@kb-labs/shared 1.1.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.
Files changed (232) hide show
  1. package/.cursorrules +32 -0
  2. package/.github/workflows/ci.yml +13 -0
  3. package/.github/workflows/deploy.yml +28 -0
  4. package/.github/workflows/docker-build.yml +25 -0
  5. package/.github/workflows/drift-check.yml +10 -0
  6. package/.github/workflows/profiles-validate.yml +16 -0
  7. package/.github/workflows/release.yml +8 -0
  8. package/.kb/devkit/agents/devkit-maintainer/context.globs +15 -0
  9. package/.kb/devkit/agents/devkit-maintainer/permissions.yml +17 -0
  10. package/.kb/devkit/agents/devkit-maintainer/prompt.md +28 -0
  11. package/.kb/devkit/agents/devkit-maintainer/runbook.md +31 -0
  12. package/.kb/devkit/agents/docs-crafter/prompt.md +24 -0
  13. package/.kb/devkit/agents/docs-crafter/runbook.md +18 -0
  14. package/.kb/devkit/agents/release-manager/context.globs +7 -0
  15. package/.kb/devkit/agents/release-manager/prompt.md +27 -0
  16. package/.kb/devkit/agents/release-manager/runbook.md +17 -0
  17. package/.kb/devkit/agents/test-generator/context.globs +7 -0
  18. package/.kb/devkit/agents/test-generator/prompt.md +27 -0
  19. package/.kb/devkit/agents/test-generator/runbook.md +18 -0
  20. package/.vscode/settings.json +23 -0
  21. package/CHANGELOG.md +33 -0
  22. package/CONTRIBUTING.md +117 -0
  23. package/LICENSE +21 -0
  24. package/README.md +306 -0
  25. package/docs/DECLARATIVE-FLAGS-AND-ENV.md +622 -0
  26. package/docs/DOCUMENTATION.md +70 -0
  27. package/docs/adr/0000-template.md +52 -0
  28. package/docs/adr/0001-architecture-and-repository-layout.md +31 -0
  29. package/docs/adr/0002-plugins-and-extensibility.md +44 -0
  30. package/docs/adr/0003-package-and-module-boundaries.md +35 -0
  31. package/docs/adr/0004-versioning-and-release-policy.md +36 -0
  32. package/docs/adr/0005-reactive-loader-pattern.md +179 -0
  33. package/docs/adr/0006-declarative-flags-and-env-systems.md +376 -0
  34. package/eslint.config.js +27 -0
  35. package/kb-labs.config.json +5 -0
  36. package/package.json +88 -0
  37. package/package.json.bin +25 -0
  38. package/package.json.lib +30 -0
  39. package/packages/shared-cli-ui/CHANGELOG.md +20 -0
  40. package/packages/shared-cli-ui/README.md +342 -0
  41. package/packages/shared-cli-ui/docs/ARCHITECTURE.md +105 -0
  42. package/packages/shared-cli-ui/eslint.config.js +27 -0
  43. package/packages/shared-cli-ui/package.json +72 -0
  44. package/packages/shared-cli-ui/src/__tests__/artifacts-display.spec.ts +89 -0
  45. package/packages/shared-cli-ui/src/__tests__/format.spec.ts +44 -0
  46. package/packages/shared-cli-ui/src/__tests__/loader-json-mode.test.ts +119 -0
  47. package/packages/shared-cli-ui/src/artifacts-display.ts +266 -0
  48. package/packages/shared-cli-ui/src/cli-auto-discovery.ts +120 -0
  49. package/packages/shared-cli-ui/src/colors.ts +142 -0
  50. package/packages/shared-cli-ui/src/command-discovery.ts +72 -0
  51. package/packages/shared-cli-ui/src/command-output.ts +153 -0
  52. package/packages/shared-cli-ui/src/command-result.ts +267 -0
  53. package/packages/shared-cli-ui/src/command-runner.ts +310 -0
  54. package/packages/shared-cli-ui/src/command-suggestions.ts +204 -0
  55. package/packages/shared-cli-ui/src/debug/components/output.ts +141 -0
  56. package/packages/shared-cli-ui/src/debug/components/trace.ts +101 -0
  57. package/packages/shared-cli-ui/src/debug/components/tree.ts +88 -0
  58. package/packages/shared-cli-ui/src/debug/formatters/ai.ts +17 -0
  59. package/packages/shared-cli-ui/src/debug/formatters/human.ts +98 -0
  60. package/packages/shared-cli-ui/src/debug/formatters/timeline.ts +94 -0
  61. package/packages/shared-cli-ui/src/debug/index.ts +56 -0
  62. package/packages/shared-cli-ui/src/debug/types.ts +57 -0
  63. package/packages/shared-cli-ui/src/debug/utilities.ts +203 -0
  64. package/packages/shared-cli-ui/src/dynamic-command-discovery.ts +131 -0
  65. package/packages/shared-cli-ui/src/format.ts +412 -0
  66. package/packages/shared-cli-ui/src/index.ts +34 -0
  67. package/packages/shared-cli-ui/src/loader.ts +196 -0
  68. package/packages/shared-cli-ui/src/manifest-parser.ts +151 -0
  69. package/packages/shared-cli-ui/src/modern-format.ts +271 -0
  70. package/packages/shared-cli-ui/src/multi-cli-suggestions.ts +159 -0
  71. package/packages/shared-cli-ui/src/table.ts +134 -0
  72. package/packages/shared-cli-ui/src/timing-tracker.ts +68 -0
  73. package/packages/shared-cli-ui/src/utils/context.ts +12 -0
  74. package/packages/shared-cli-ui/src/utils/env.ts +164 -0
  75. package/packages/shared-cli-ui/src/utils/flags.ts +269 -0
  76. package/packages/shared-cli-ui/src/utils/path.ts +8 -0
  77. package/packages/shared-cli-ui/tsconfig.build.json +15 -0
  78. package/packages/shared-cli-ui/tsconfig.json +9 -0
  79. package/packages/shared-cli-ui/tsup.config.ts +11 -0
  80. package/packages/shared-cli-ui/vitest.config.ts +15 -0
  81. package/packages/shared-command-kit/CHANGELOG.md +20 -0
  82. package/packages/shared-command-kit/LICENSE +22 -0
  83. package/packages/shared-command-kit/README.md +1030 -0
  84. package/packages/shared-command-kit/docs/HIGH-LEVEL-API.md +89 -0
  85. package/packages/shared-command-kit/docs/LOW-LEVEL-API.md +105 -0
  86. package/packages/shared-command-kit/docs/MIGRATION-GUIDE.md +135 -0
  87. package/packages/shared-command-kit/eslint.config.js +27 -0
  88. package/packages/shared-command-kit/eslint.config.ts +14 -0
  89. package/packages/shared-command-kit/package.json +76 -0
  90. package/packages/shared-command-kit/prettierrc.json +5 -0
  91. package/packages/shared-command-kit/src/__tests__/define-command.spec.ts +294 -0
  92. package/packages/shared-command-kit/src/__tests__/define-route.test.ts +285 -0
  93. package/packages/shared-command-kit/src/__tests__/define-system-command.spec.ts +508 -0
  94. package/packages/shared-command-kit/src/__tests__/define-webhook.test.ts +156 -0
  95. package/packages/shared-command-kit/src/__tests__/define-websocket.test.ts +316 -0
  96. package/packages/shared-command-kit/src/__tests__/errors.spec.ts +45 -0
  97. package/packages/shared-command-kit/src/__tests__/flags.spec.ts +353 -0
  98. package/packages/shared-command-kit/src/__tests__/platform-api.test.ts +135 -0
  99. package/packages/shared-command-kit/src/__tests__/plugin-context-v3.snapshot.spec.ts +240 -0
  100. package/packages/shared-command-kit/src/__tests__/ws-types.test.ts +359 -0
  101. package/packages/shared-command-kit/src/analytics/index.ts +6 -0
  102. package/packages/shared-command-kit/src/analytics/with-analytics.ts +195 -0
  103. package/packages/shared-command-kit/src/define-action.ts +100 -0
  104. package/packages/shared-command-kit/src/define-command.ts +113 -0
  105. package/packages/shared-command-kit/src/define-route.ts +113 -0
  106. package/packages/shared-command-kit/src/define-system-command.ts +362 -0
  107. package/packages/shared-command-kit/src/define-webhook.ts +115 -0
  108. package/packages/shared-command-kit/src/define-websocket.ts +308 -0
  109. package/packages/shared-command-kit/src/errors/factory.ts +282 -0
  110. package/packages/shared-command-kit/src/errors/format-validation.ts +144 -0
  111. package/packages/shared-command-kit/src/errors/format.ts +92 -0
  112. package/packages/shared-command-kit/src/errors/index.ts +9 -0
  113. package/packages/shared-command-kit/src/errors/types.ts +32 -0
  114. package/packages/shared-command-kit/src/flags/define.ts +92 -0
  115. package/packages/shared-command-kit/src/flags/index.ts +9 -0
  116. package/packages/shared-command-kit/src/flags/types.ts +153 -0
  117. package/packages/shared-command-kit/src/flags/validate.ts +358 -0
  118. package/packages/shared-command-kit/src/helpers/context.ts +8 -0
  119. package/packages/shared-command-kit/src/helpers/flags.ts +84 -0
  120. package/packages/shared-command-kit/src/helpers/index.ts +42 -0
  121. package/packages/shared-command-kit/src/helpers/patterns.ts +464 -0
  122. package/packages/shared-command-kit/src/helpers/platform.ts +335 -0
  123. package/packages/shared-command-kit/src/helpers/use-analytics.ts +95 -0
  124. package/packages/shared-command-kit/src/helpers/use-cache.ts +97 -0
  125. package/packages/shared-command-kit/src/helpers/use-config.ts +99 -0
  126. package/packages/shared-command-kit/src/helpers/use-embeddings.ts +49 -0
  127. package/packages/shared-command-kit/src/helpers/use-llm.ts +316 -0
  128. package/packages/shared-command-kit/src/helpers/use-logger.ts +77 -0
  129. package/packages/shared-command-kit/src/helpers/use-platform.ts +111 -0
  130. package/packages/shared-command-kit/src/helpers/use-resource-broker.ts +106 -0
  131. package/packages/shared-command-kit/src/helpers/use-storage.ts +71 -0
  132. package/packages/shared-command-kit/src/helpers/use-vector-store.ts +49 -0
  133. package/packages/shared-command-kit/src/helpers/validation.ts +398 -0
  134. package/packages/shared-command-kit/src/index.ts +410 -0
  135. package/packages/shared-command-kit/src/jobs.ts +132 -0
  136. package/packages/shared-command-kit/src/lifecycle/define-handlers.ts +366 -0
  137. package/packages/shared-command-kit/src/lifecycle/index.ts +6 -0
  138. package/packages/shared-command-kit/src/manifest.ts +127 -0
  139. package/packages/shared-command-kit/src/rest/define-handler.ts +187 -0
  140. package/packages/shared-command-kit/src/rest/index.ts +11 -0
  141. package/packages/shared-command-kit/src/studio/index.ts +12 -0
  142. package/packages/shared-command-kit/src/validation/index.ts +6 -0
  143. package/packages/shared-command-kit/src/validation/schema-builders.ts +409 -0
  144. package/packages/shared-command-kit/src/ws-types.ts +106 -0
  145. package/packages/shared-command-kit/tsconfig.build.json +15 -0
  146. package/packages/shared-command-kit/tsconfig.json +9 -0
  147. package/packages/shared-command-kit/tsup.config.ts +30 -0
  148. package/packages/shared-command-kit/vitest.config.ts +4 -0
  149. package/packages/shared-http/package.json +67 -0
  150. package/packages/shared-http/src/__tests__/log-correlation.test.ts +81 -0
  151. package/packages/shared-http/src/__tests__/operation-metrics-tracker.test.ts +55 -0
  152. package/packages/shared-http/src/http-observability-collector.ts +363 -0
  153. package/packages/shared-http/src/index.ts +36 -0
  154. package/packages/shared-http/src/log-correlation.ts +89 -0
  155. package/packages/shared-http/src/operation-metrics-tracker.ts +107 -0
  156. package/packages/shared-http/src/register-openapi.ts +108 -0
  157. package/packages/shared-http/src/resolve-schema-ref.ts +75 -0
  158. package/packages/shared-http/src/schemas.ts +29 -0
  159. package/packages/shared-http/src/service-observability.ts +63 -0
  160. package/packages/shared-http/tsconfig.build.json +15 -0
  161. package/packages/shared-http/tsconfig.json +9 -0
  162. package/packages/shared-http/tsup.config.ts +23 -0
  163. package/packages/shared-http/vitest.config.ts +13 -0
  164. package/packages/shared-perm-presets/CHANGELOG.md +20 -0
  165. package/packages/shared-perm-presets/README.md +78 -0
  166. package/packages/shared-perm-presets/eslint.config.js +27 -0
  167. package/packages/shared-perm-presets/package.json +45 -0
  168. package/packages/shared-perm-presets/src/__tests__/combine.test.ts +403 -0
  169. package/packages/shared-perm-presets/src/__tests__/presets.test.ts +205 -0
  170. package/packages/shared-perm-presets/src/combine.ts +278 -0
  171. package/packages/shared-perm-presets/src/index.ts +18 -0
  172. package/packages/shared-perm-presets/src/presets/ci-environment.ts +34 -0
  173. package/packages/shared-perm-presets/src/presets/full-env.ts +16 -0
  174. package/packages/shared-perm-presets/src/presets/git-workflow.ts +40 -0
  175. package/packages/shared-perm-presets/src/presets/index.ts +8 -0
  176. package/packages/shared-perm-presets/src/presets/kb-platform.ts +30 -0
  177. package/packages/shared-perm-presets/src/presets/llm-access.ts +29 -0
  178. package/packages/shared-perm-presets/src/presets/minimal.ts +21 -0
  179. package/packages/shared-perm-presets/src/presets/npm-publish.ts +48 -0
  180. package/packages/shared-perm-presets/src/presets/vector-store.ts +40 -0
  181. package/packages/shared-perm-presets/src/types.ts +192 -0
  182. package/packages/shared-perm-presets/tsconfig.build.json +15 -0
  183. package/packages/shared-perm-presets/tsconfig.json +9 -0
  184. package/packages/shared-perm-presets/tsup.config.ts +8 -0
  185. package/packages/shared-perm-presets/vitest.config.ts +9 -0
  186. package/packages/shared-testing/CHANGELOG.md +20 -0
  187. package/packages/shared-testing/README.md +430 -0
  188. package/packages/shared-testing/package.json +51 -0
  189. package/packages/shared-testing/src/__tests__/create-test-context.test.ts +199 -0
  190. package/packages/shared-testing/src/__tests__/mock-cache.test.ts +174 -0
  191. package/packages/shared-testing/src/__tests__/mock-llm.test.ts +212 -0
  192. package/packages/shared-testing/src/__tests__/setup-platform.test.ts +90 -0
  193. package/packages/shared-testing/src/__tests__/test-command.test.ts +557 -0
  194. package/packages/shared-testing/src/create-test-context.ts +550 -0
  195. package/packages/shared-testing/src/index.ts +77 -0
  196. package/packages/shared-testing/src/mock-cache.ts +179 -0
  197. package/packages/shared-testing/src/mock-llm.ts +319 -0
  198. package/packages/shared-testing/src/mock-logger.ts +97 -0
  199. package/packages/shared-testing/src/mock-storage.ts +108 -0
  200. package/packages/shared-testing/src/setup-platform.ts +101 -0
  201. package/packages/shared-testing/src/test-command.ts +288 -0
  202. package/packages/shared-testing/tsconfig.build.json +15 -0
  203. package/packages/shared-testing/tsconfig.json +9 -0
  204. package/packages/shared-testing/tsup.config.ts +20 -0
  205. package/packages/shared-testing/vitest.config.ts +3 -0
  206. package/packages/shared-tool-kit/CHANGELOG.md +20 -0
  207. package/packages/shared-tool-kit/package.json +47 -0
  208. package/packages/shared-tool-kit/src/__tests__/factory.test.ts +103 -0
  209. package/packages/shared-tool-kit/src/__tests__/mock-tool.test.ts +95 -0
  210. package/packages/shared-tool-kit/src/factory.ts +126 -0
  211. package/packages/shared-tool-kit/src/index.ts +32 -0
  212. package/packages/shared-tool-kit/src/testing/index.ts +84 -0
  213. package/packages/shared-tool-kit/tsconfig.build.json +15 -0
  214. package/packages/shared-tool-kit/tsconfig.json +9 -0
  215. package/packages/shared-tool-kit/tsup.config.ts +21 -0
  216. package/pnpm-workspace.yaml +11070 -0
  217. package/prettierrc.json +1 -0
  218. package/scripts/devkit-sync.mjs +37 -0
  219. package/scripts/hooks/post-push +9 -0
  220. package/scripts/hooks/pre-commit +9 -0
  221. package/scripts/hooks/pre-push +9 -0
  222. package/tsconfig.base.json +9 -0
  223. package/tsconfig.build.json +15 -0
  224. package/tsconfig.json +9 -0
  225. package/tsconfig.paths.json +50 -0
  226. package/tsconfig.tools.json +18 -0
  227. package/tsup.config.bin.ts +34 -0
  228. package/tsup.config.cli.ts +41 -0
  229. package/tsup.config.dual.ts +46 -0
  230. package/tsup.config.ts +36 -0
  231. package/tsup.external.json +104 -0
  232. package/vitest.config.ts +48 -0
@@ -0,0 +1,1030 @@
1
+ # @kb-labs/shared-command-kit
2
+
3
+ > **Complete toolkit for building KB Labs CLI commands and plugins**
4
+
5
+ Fast, type-safe command development with platform service access, validation helpers, and common patterns.
6
+
7
+ ---
8
+
9
+ ## Table of Contents
10
+
11
+ - [Installation](#installation)
12
+ - [Quick Start](#quick-start)
13
+ - [Command Definition](#command-definition)
14
+ - [defineCommand](#definecommand)
15
+ - [defineSystemCommand](#definesystemcommand)
16
+ - [Manifest Definition](#manifest-definition)
17
+ - [defineManifest](#definemanifest)
18
+ - [defineCommandFlags](#definecommandflags)
19
+ - [Permission Presets](#permission-presets)
20
+ - [Permission Combiners](#permission-combiners)
21
+ - [Available Presets](#available-presets)
22
+ - [Error Factory](#error-factory)
23
+ - [Basic Usage](#basic-usage)
24
+ - [Common Error Definitions](#common-error-definitions)
25
+ - [Error Type Guards](#error-type-guards)
26
+ - [Schema Builders](#schema-builders)
27
+ - [Basic Usage](#basic-usage-1)
28
+ - [Available Builders](#available-builders)
29
+ - [REST Handler Definition](#rest-handler-definition)
30
+ - [Basic Usage](#basic-usage-2)
31
+ - [Enhanced Context Helpers](#enhanced-context-helpers)
32
+ - [Error Handling](#error-handling)
33
+ - [Widget Card Helpers](#widget-card-helpers)
34
+ - [Lifecycle Helpers](#lifecycle-helpers)
35
+ - [Setup Handler](#setup-handler)
36
+ - [Destroy Handler](#destroy-handler)
37
+ - [Platform Service Helpers](#platform-service-helpers)
38
+ - [Service Access](#service-access)
39
+ - [Shortcuts](#shortcuts)
40
+ - [Configuration Checking](#configuration-checking)
41
+ - [Validation Helpers](#validation-helpers)
42
+ - [Common Schemas](#common-schemas)
43
+ - [Validation Functions](#validation-functions)
44
+ - [Type Guards](#type-guards)
45
+ - [Common Patterns](#common-patterns)
46
+ - [Spinner Pattern](#spinner-pattern)
47
+ - [Batch Processing](#batch-processing)
48
+ - [Retry Logic](#retry-logic)
49
+ - [Utilities](#utilities)
50
+ - [Full Examples](#full-examples)
51
+
52
+ ---
53
+
54
+ ## Installation
55
+
56
+ ```bash
57
+ pnpm add @kb-labs/shared-command-kit
58
+ ```
59
+
60
+ **Dependencies**:
61
+ - `@kb-labs/core-platform` - Platform service interfaces
62
+ - `@kb-labs/plugin-runtime` - Plugin context and runtime
63
+ - `zod` - Schema validation
64
+
65
+ ---
66
+
67
+ ## Quick Start
68
+
69
+ ```typescript
70
+ import { defineCommand, useLLM, withSpinner, schemas, validateSchema } from '@kb-labs/shared-command-kit';
71
+
72
+ export const myCommand = defineCommand({
73
+ name: 'my-plugin:process',
74
+ flags: {
75
+ input: { type: 'string', required: true },
76
+ format: { type: 'string', default: 'json' },
77
+ },
78
+ async handler(ctx, argv, flags) {
79
+ // Use platform services with configuration checks
80
+ const llm = useLLM(ctx);
81
+
82
+ // Validation with common schemas
83
+ const config = validateSchema(schemas.jsonString, flags.input);
84
+
85
+ // Progress feedback
86
+ const result = await withSpinner(ctx, 'Processing data', async () => {
87
+ return await llm.complete('Analyze this data: ' + config);
88
+ });
89
+
90
+ return { ok: true, result: result.content };
91
+ },
92
+ });
93
+ ```
94
+
95
+ ---
96
+
97
+ ## Command Definition
98
+
99
+ ### defineCommand
100
+
101
+ Define a plugin command with automatic flag validation, analytics, and error handling.
102
+
103
+ ```typescript
104
+ import { defineCommand, type CommandResult } from '@kb-labs/shared-command-kit';
105
+
106
+ type MyResult = CommandResult & {
107
+ processed: number;
108
+ skipped: number;
109
+ };
110
+
111
+ export const processCommand = defineCommand<MyResult>({
112
+ name: 'my-plugin:process',
113
+ flags: {
114
+ scope: { type: 'string', required: true },
115
+ 'dry-run': { type: 'boolean', default: false },
116
+ format: { type: 'string', choices: ['json', 'yaml'], default: 'json' },
117
+ },
118
+ analytics: {
119
+ startEvent: 'PROCESS_STARTED',
120
+ finishEvent: 'PROCESS_FINISHED',
121
+ includeFlags: true,
122
+ },
123
+ async handler(ctx, argv, flags) {
124
+ // flags.scope is typed as string
125
+ // flags['dry-run'] is typed as boolean
126
+ // flags.format is typed as 'json' | 'yaml'
127
+
128
+ const items = await loadItems(flags.scope);
129
+ const processed = await processItems(items, flags);
130
+
131
+ return {
132
+ ok: true,
133
+ processed: processed.length,
134
+ skipped: items.length - processed.length,
135
+ };
136
+ },
137
+ });
138
+ ```
139
+
140
+ ### defineSystemCommand
141
+
142
+ Define a system command with full privileges (for official KB Labs commands only).
143
+
144
+ ```typescript
145
+ import { defineSystemCommand, type CommandResult } from '@kb-labs/shared-command-kit';
146
+
147
+ type ListResult = CommandResult & {
148
+ items: Array<{ id: string; name: string }>;
149
+ total: number;
150
+ };
151
+
152
+ export const listCommand = defineSystemCommand<ListResult>({
153
+ name: 'list',
154
+ description: 'List all items',
155
+ category: 'system',
156
+ flags: {
157
+ filter: { type: 'string' },
158
+ json: { type: 'boolean', default: false },
159
+ },
160
+ async handler(ctx, argv, flags) {
161
+ const items = await fetchItems(flags.filter);
162
+ return { ok: true, items, total: items.length };
163
+ },
164
+ formatter(result, ctx, flags) {
165
+ if (flags.json) {
166
+ ctx.output?.json(result);
167
+ } else {
168
+ result.items.forEach(item => ctx.output?.write(`${item.id}: ${item.name}`));
169
+ }
170
+ },
171
+ });
172
+ ```
173
+
174
+ ---
175
+
176
+ ## Manifest Definition
177
+
178
+ ### defineManifest
179
+
180
+ Define a ManifestV3 for your plugin with type safety and zero runtime dependencies.
181
+
182
+ ```typescript
183
+ import { defineManifest } from '@kb-labs/shared-command-kit';
184
+
185
+ export const manifest = defineManifest({
186
+ schema: 'kb.plugin/3',
187
+ id: '@kb-labs/my-plugin',
188
+ version: '1.0.0',
189
+ commands: [
190
+ {
191
+ name: 'hello',
192
+ handler: './cli/commands/hello.js',
193
+ },
194
+ ],
195
+ permissions: {
196
+ fs: {
197
+ mode: 'read',
198
+ allow: ['.kb/my-plugin/**'],
199
+ },
200
+ },
201
+ });
202
+
203
+ export default manifest;
204
+ ```
205
+
206
+ **Why use `defineManifest` instead of plain object?**
207
+
208
+ - ✅ **Type safety** - TypeScript validates the manifest structure at compile time
209
+ - ✅ **Zero runtime dependencies** - Compiles to plain object in dist/ (no imports)
210
+ - ✅ **IDE autocomplete** - Get full IntelliSense for all manifest fields
211
+ - ✅ **Optional validation** - Can add runtime validation in development if needed
212
+
213
+ **Note:** `defineManifest` is the V3 API. Legacy `createManifestV2` from `@kb-labs/plugin-manifest` is deprecated.
214
+
215
+ ### defineCommandFlags
216
+
217
+ Convert flag schema definition (used in `defineCommand`) to manifest format:
218
+
219
+ ```typescript
220
+ import { defineManifest, defineCommandFlags } from '@kb-labs/shared-command-kit';
221
+
222
+ // Define flags once using defineCommand format
223
+ const helloFlags = {
224
+ name: { type: 'string', description: 'Name to greet', alias: 'n' },
225
+ json: { type: 'boolean', description: 'Emit JSON', default: false },
226
+ count: { type: 'number', description: 'Repeat count', default: 1 },
227
+ } as const;
228
+
229
+ // Use in manifest
230
+ export const manifest = defineManifest({
231
+ cli: {
232
+ commands: [{
233
+ id: 'hello',
234
+ flags: defineCommandFlags(helloFlags), // Converts to manifest format
235
+ handler: './cli/commands/hello#run',
236
+ }],
237
+ },
238
+ });
239
+
240
+ // Use in command handler
241
+ import { defineCommand } from '@kb-labs/shared-command-kit';
242
+
243
+ export const run = defineCommand({
244
+ name: 'hello',
245
+ flags: helloFlags, // Reuse same flag definition
246
+ async handler(ctx, argv, flags) {
247
+ // flags.name is typed as string | undefined
248
+ // flags.json is typed as boolean
249
+ // flags.count is typed as number
250
+ return { ok: true };
251
+ },
252
+ });
253
+ ```
254
+
255
+ **Benefits:**
256
+ - ✅ **DRY** - Define flags once, use in both manifest and command
257
+ - ✅ **Type consistency** - Flags in manifest match command handler types
258
+ - ✅ **Less boilerplate** - No manual conversion between formats
259
+
260
+ ---
261
+
262
+ ## Permission Presets
263
+
264
+ **Optional** helpers for defining plugin permissions without boilerplate. You can always use plain objects.
265
+
266
+ ### Permission Combiners
267
+
268
+ ```typescript
269
+ import { defineManifest, permissions } from '@kb-labs/shared-command-kit';
270
+
271
+ export const manifest = defineManifest({
272
+ permissions: permissions.combine(
273
+ // Plugin workspace access (read-write)
274
+ permissions.presets.pluginWorkspace('mind'),
275
+
276
+ // LLM API access
277
+ permissions.presets.llmApi(['openai', 'anthropic']),
278
+
279
+ // Vector database access
280
+ permissions.presets.vectorDb(['qdrant']),
281
+
282
+ // Custom additions
283
+ {
284
+ env: { allow: ['CUSTOM_VAR'] },
285
+ }
286
+ ),
287
+ });
288
+ ```
289
+
290
+ ### Available Presets
291
+
292
+ ```typescript
293
+ // Workspace access
294
+ permissions.presets.pluginWorkspaceRead('plugin-name') // Read-only
295
+ permissions.presets.pluginWorkspace('plugin-name') // Read-write
296
+
297
+ // API access
298
+ permissions.presets.llmApi(['openai', 'anthropic', 'google', 'cohere'])
299
+ permissions.presets.vectorDb(['qdrant', 'pinecone', 'weaviate'])
300
+
301
+ // State and analytics
302
+ permissions.presets.analytics()
303
+
304
+ // Development
305
+ permissions.presets.monorepo() // Full monorepo read access
306
+ permissions.presets.httpClient() // Any HTTP host
307
+ permissions.presets.localhost() // Localhost only
308
+ ```
309
+
310
+ **Benefits:**
311
+ - ✅ **DRY** - Reuse common permission patterns
312
+ - ✅ **Security** - Built-in deny patterns for secrets
313
+ - ✅ **Composable** - Mix presets with custom permissions
314
+ - ✅ **Type-safe** - Full TypeScript support
315
+
316
+ ---
317
+
318
+ ## Error Factory
319
+
320
+ **Optional** helper for defining plugin errors without boilerplate. You can always use standard Error classes.
321
+
322
+ ### Basic Usage
323
+
324
+ ```typescript
325
+ import { defineError } from '@kb-labs/shared-command-kit';
326
+
327
+ // Define error namespace
328
+ export const MindError = defineError('MIND', {
329
+ ValidationFailed: {
330
+ code: 400,
331
+ message: 'Validation failed',
332
+ },
333
+ IndexNotFound: {
334
+ code: 404,
335
+ message: (scope: string) => `Index '${scope}' not found`,
336
+ },
337
+ QueryFailed: {
338
+ code: 500,
339
+ message: 'Query execution failed',
340
+ },
341
+ });
342
+
343
+ // Usage
344
+ throw new MindError.IndexNotFound('default');
345
+ // Error: "Index 'default' not found" (HTTP 404)
346
+
347
+ throw new MindError.ValidationFailed({
348
+ details: { field: 'cwd', reason: 'missing' }
349
+ });
350
+ // Error: "Validation failed" (HTTP 400) with details
351
+ ```
352
+
353
+ ### Common Error Definitions
354
+
355
+ ```typescript
356
+ import { commonErrors } from '@kb-labs/shared-command-kit';
357
+
358
+ export const MyError = defineError('MY_PLUGIN', {
359
+ ...commonErrors, // ValidationFailed, NotFound, InternalError, etc.
360
+
361
+ CustomError: {
362
+ code: 400,
363
+ message: 'Custom error message',
364
+ },
365
+ });
366
+ ```
367
+
368
+ ### Error Type Guards
369
+
370
+ ```typescript
371
+ try {
372
+ throw new MindError.IndexNotFound('default');
373
+ } catch (error) {
374
+ if (MindError.is(error)) {
375
+ // error is PluginError from MIND namespace
376
+ console.log(error.statusCode); // 404
377
+ console.log(error.errorCode); // "MIND_INDEXNOTFOUND"
378
+ }
379
+
380
+ if (MindError.hasCode(error, 'IndexNotFound')) {
381
+ // error is specifically IndexNotFound
382
+ console.log('Index not found!');
383
+ }
384
+ }
385
+ ```
386
+
387
+ **Benefits:**
388
+ - ✅ **Centralized** - All errors defined in one place
389
+ - ✅ **Type-safe** - Full TypeScript autocomplete
390
+ - ✅ **HTTP codes** - Automatic HTTP status codes
391
+ - ✅ **Templates** - Parameterized error messages
392
+
393
+ ---
394
+
395
+ ## Schema Builders
396
+
397
+ **Optional** helpers for common Zod validation patterns. You can always use plain Zod.
398
+
399
+ ### Basic Usage
400
+
401
+ ```typescript
402
+ import { schema } from '@kb-labs/shared-command-kit';
403
+ import { z } from 'zod';
404
+
405
+ const RequestSchema = schema.object({
406
+ // Common KB Labs patterns
407
+ cwd: schema.cwd(), // Optional string
408
+ scope: schema.scopeId(), // Non-empty string
409
+ pluginId: schema.pluginId(), // @kb-labs/package-name
410
+
411
+ // String patterns
412
+ text: schema.text({ min: 1, max: 10000 }), // Length constraints
413
+ url: schema.url({ optional: true }), // URL validation
414
+ email: schema.email(), // Email validation
415
+
416
+ // Number patterns
417
+ limit: schema.positiveInt({ max: 100, default: 10 }), // Positive integer
418
+ offset: schema.nonNegativeInt({ default: 0 }), // 0 or positive
419
+
420
+ // Enum with default
421
+ mode: schema.enum(['instant', 'auto', 'thinking'], { default: 'auto' }),
422
+
423
+ // Boolean with default
424
+ json: schema.boolean({ default: false }),
425
+
426
+ // Array with constraints
427
+ tags: schema.array(z.string(), { min: 1, max: 10 }),
428
+ });
429
+
430
+ // Type inference works!
431
+ type Request = z.infer<typeof RequestSchema>;
432
+ ```
433
+
434
+ ### Available Builders
435
+
436
+ **KB Labs specific:**
437
+ - `schema.cwd()` - Current working directory (optional string)
438
+ - `schema.scopeId()` - Scope identifier (non-empty string)
439
+ - `schema.pluginId()` - Plugin ID (@kb-labs/package-name format)
440
+ - `schema.commandId()` - Command ID (plugin:command format)
441
+ - `schema.artifactId()` - Artifact ID (plugin.artifact.id format)
442
+
443
+ **String builders:**
444
+ - `schema.text({ min?, max?, default? })` - Text with length constraints
445
+ - `schema.filePath({ optional? })` - File path string
446
+ - `schema.url({ optional? })` - URL string
447
+ - `schema.email({ optional? })` - Email string
448
+ - `schema.uuid({ optional? })` - UUID string
449
+ - `schema.datetime({ optional? })` - ISO datetime string
450
+
451
+ **Number builders:**
452
+ - `schema.positiveInt({ min?, max?, default? })` - Positive integer
453
+ - `schema.nonNegativeInt({ max?, default? })` - Non-negative integer (0+)
454
+
455
+ **Other builders:**
456
+ - `schema.enum(values, { default? })` - Enum with optional default
457
+ - `schema.boolean({ default? })` - Boolean with optional default
458
+ - `schema.json()` - Any JSON object
459
+ - `schema.array(itemSchema, { min?, max? })` - Array with constraints
460
+ - `schema.object(shape)` - Alias for z.object
461
+
462
+ **Benefits:**
463
+ - ✅ **DRY** - Common patterns in one place
464
+ - ✅ **Readable** - More concise than raw Zod
465
+ - ✅ **Type-safe** - Full Zod type inference
466
+ - ✅ **Optional** - Mix with plain Zod anytime
467
+
468
+ ---
469
+
470
+ ## REST Handler Definition
471
+
472
+ **Optional** helper for defining REST handlers with automatic validation and error handling. You can always use plain functions.
473
+
474
+ ### Basic Usage
475
+
476
+ ```typescript
477
+ import { defineRestHandler, schema } from '@kb-labs/shared-command-kit';
478
+ import { z } from 'zod';
479
+
480
+ export const handleVerify = defineRestHandler({
481
+ name: 'mind:verify',
482
+
483
+ // Automatic Zod validation
484
+ input: z.object({
485
+ cwd: schema.cwd(),
486
+ }),
487
+
488
+ // Response schema (for documentation/validation in dev)
489
+ output: z.object({
490
+ ok: z.boolean(),
491
+ cards: z.array(cardDataSchema),
492
+ }),
493
+
494
+ // Error definitions with HTTP codes
495
+ errors: {
496
+ 'VERIFY_FAILED': { http: 500, message: 'Verification failed' },
497
+ },
498
+
499
+ async handler(request, ctx) {
500
+ // request is typed as { cwd?: string }
501
+ // ctx has helpers: log, env, resolveCwd
502
+
503
+ // Auto-resolve cwd (from request → env → workspace)
504
+ const cwd = await ctx.resolveCwd(request.cwd);
505
+
506
+ const result = await verifyIndexes(cwd);
507
+
508
+ // Create widget cards
509
+ const cards = createCardList([
510
+ { title: 'Status', content: result.ok ? 'OK' : 'Issues', status: result.ok ? 'ok' : 'warn' },
511
+ { title: 'Hint', content: result.hint, status: 'info' },
512
+ ]);
513
+
514
+ return { ok: true, cards };
515
+ },
516
+ });
517
+ ```
518
+
519
+ ### Enhanced Context Helpers
520
+
521
+ The handler receives an enhanced context with useful helpers:
522
+
523
+ ```typescript
524
+ async handler(request, ctx) {
525
+ // Logger (always available, falls back to console)
526
+ ctx.log('info', 'Processing request', { requestId: ctx.requestId });
527
+
528
+ // Environment getter (always available, falls back to process.env)
529
+ const apiKey = ctx.env('OPENAI_API_KEY');
530
+
531
+ // Auto-resolve cwd: request.cwd → env KB_LABS_REPO_ROOT → workspace root → '.'
532
+ const cwd = await ctx.resolveCwd(request.cwd);
533
+
534
+ // Access runtime services if available
535
+ if (ctx.runtime?.fetch) {
536
+ const response = await ctx.runtime.fetch('https://api.example.com');
537
+ }
538
+ }
539
+ ```
540
+
541
+ ### Error Handling
542
+
543
+ Automatic error handling with HTTP status codes:
544
+
545
+ ```typescript
546
+ export const handler = defineRestHandler({
547
+ name: 'my:handler',
548
+ input: z.object({ id: z.string() }),
549
+
550
+ // Define expected errors
551
+ errors: {
552
+ 'NOT_FOUND': { http: 404, message: 'Resource not found' },
553
+ 'INVALID_STATE': { http: 409, message: 'Invalid state' },
554
+ },
555
+
556
+ async handler(request, ctx) {
557
+ // Throw errors with errorCode
558
+ const MyError = defineError('MY', {
559
+ NotFound: { code: 404, message: 'Not found' },
560
+ });
561
+
562
+ throw new MyError.NotFound();
563
+ // Automatically mapped to error response with HTTP 404
564
+ },
565
+ });
566
+ ```
567
+
568
+ ### Widget Card Helpers
569
+
570
+ ```typescript
571
+ import { createCardList } from '@kb-labs/shared-command-kit';
572
+
573
+ const cards = createCardList([
574
+ { title: 'Status', content: 'OK', status: 'ok' },
575
+ { title: 'Warning', content: 'Check logs', status: 'warn' },
576
+ { title: 'Error', content: 'Failed to sync', status: 'error' },
577
+ { title: 'Info', content: 'Hint text', status: 'info' },
578
+ ]);
579
+ ```
580
+
581
+ **Benefits:**
582
+ - ✅ **Automatic validation** - Input/output validation with Zod
583
+ - ✅ **Type safety** - Full TypeScript inference
584
+ - ✅ **Error handling** - HTTP codes and structured errors
585
+ - ✅ **Context helpers** - log, env, resolveCwd always available
586
+ - ✅ **Widget support** - Easy card creation for Studio
587
+
588
+ ---
589
+
590
+ ## Lifecycle Helpers
591
+
592
+ **Optional** helpers for plugin lifecycle hooks (setup, destroy). You can always use plain functions.
593
+
594
+ ### Setup Handler
595
+
596
+ ```typescript
597
+ import { defineSetupHandler } from '@kb-labs/shared-command-kit';
598
+
599
+ export const setup = defineSetupHandler({
600
+ name: 'mind:setup',
601
+
602
+ // Declarative workspace setup
603
+ workspace: {
604
+ // Directories to create
605
+ directories: [
606
+ '.kb/mind/index',
607
+ '.kb/mind/cache',
608
+ '.kb/mind/pack',
609
+ ],
610
+ // Files to create with content
611
+ files: {
612
+ '.kb/mind/.gitignore': 'cache/\npack/\n',
613
+ },
614
+ },
615
+
616
+ // Declarative config updates (merged with existing)
617
+ config: {
618
+ 'kb.config.json': {
619
+ mind: {
620
+ enabled: true,
621
+ scopes: ['default'],
622
+ },
623
+ },
624
+ },
625
+
626
+ // Optional custom logic
627
+ async handler(ctx) {
628
+ ctx.log?.('info', 'Mind workspace initialized', {});
629
+ return { ok: true };
630
+ },
631
+ });
632
+ ```
633
+
634
+ ### Destroy Handler
635
+
636
+ ```typescript
637
+ import { defineDestroyHandler } from '@kb-labs/shared-command-kit';
638
+
639
+ export const destroy = defineDestroyHandler({
640
+ name: 'mind:destroy',
641
+
642
+ // Cleanup workspace
643
+ workspace: {
644
+ directories: ['.kb/mind'],
645
+ files: ['.kb/mind/.gitignore'],
646
+ },
647
+
648
+ // Cleanup config (remove keys)
649
+ config: {
650
+ 'kb.config.json': ['mind'], // Remove 'mind' key
651
+ },
652
+
653
+ // Optional custom cleanup
654
+ async handler(ctx) {
655
+ ctx.log?.('info', 'Mind cleanup completed', {});
656
+ return { ok: true };
657
+ },
658
+ });
659
+ ```
660
+
661
+ ### Context Available
662
+
663
+ ```typescript
664
+ interface LifecycleContext {
665
+ outdir: string; // Plugin workspace root
666
+ pluginId: string; // Plugin ID
667
+ requestId?: string;
668
+ log?: (level, msg, meta) => void;
669
+ env?: (key) => string | undefined;
670
+ }
671
+ ```
672
+
673
+ **Benefits:**
674
+ - ✅ **Declarative** - Workspace and config setup in plain objects
675
+ - ✅ **Automatic** - Directory creation, config merging handled automatically
676
+ - ✅ **Safe** - Merge configs instead of overwrite
677
+ - ✅ **Custom logic** - Optional handler for complex setup
678
+
679
+ ---
680
+
681
+ ## Platform Service Helpers
682
+
683
+ Convenient access to platform services with automatic configuration checks and helpful error messages.
684
+
685
+ ### Service Access
686
+
687
+ These functions throw `ServiceNotConfiguredError` if the service is not configured (using NoOp/fallback):
688
+
689
+ ```typescript
690
+ import { useLLM, useEmbeddings, useVectorStore, useCache, useStorage, useLogger, useAnalytics, useEventBus, useWorkflows, useJobs } from '@kb-labs/shared-command-kit/helpers';
691
+
692
+ async function handler(ctx: PluginContext) {
693
+ // LLM service (throws if not configured)
694
+ const llm = useLLM(ctx);
695
+ const response = await llm.complete('Hello!');
696
+
697
+ // Embeddings service (throws if not configured)
698
+ const embeddings = useEmbeddings(ctx);
699
+ const vector = await embeddings.embed('text to embed');
700
+
701
+ // Vector store (throws if not configured)
702
+ const vectorStore = useVectorStore(ctx);
703
+ const results = await vectorStore.search(vector, 10);
704
+
705
+ // Always available (safe fallbacks)
706
+ const cache = useCache(ctx);
707
+ const storage = useStorage(ctx);
708
+ const logger = useLogger(ctx);
709
+ const analytics = useAnalytics(ctx);
710
+ const events = useEventBus(ctx);
711
+
712
+ // Core features (always available)
713
+ const workflows = useWorkflows(ctx);
714
+ const jobs = useJobs(ctx);
715
+ }
716
+ ```
717
+
718
+ ### Shortcuts
719
+
720
+ High-level operations that combine service access with common patterns:
721
+
722
+ ```typescript
723
+ import { embedText, embedBatch, searchVectors, completeLLM, streamLLM } from '@kb-labs/shared-command-kit/helpers';
724
+
725
+ async function handler(ctx: PluginContext) {
726
+ // Generate single embedding
727
+ const vector = await embedText(ctx, 'Hello, world!');
728
+
729
+ // Generate batch embeddings
730
+ const vectors = await embedBatch(ctx, ['text 1', 'text 2', 'text 3']);
731
+
732
+ // Search vectors
733
+ const queryVector = await embedText(ctx, 'search query');
734
+ const results = await searchVectors(ctx, queryVector, 5);
735
+
736
+ // LLM completion
737
+ const response = await completeLLM(ctx, 'Explain quantum computing', {
738
+ temperature: 0.7,
739
+ maxTokens: 500,
740
+ });
741
+
742
+ // LLM streaming
743
+ for await (const chunk of streamLLM(ctx, 'Write a story')) {
744
+ ctx.ui.message(chunk);
745
+ }
746
+ }
747
+ ```
748
+
749
+ ### Configuration Checking
750
+
751
+ Check if services are configured without throwing errors:
752
+
753
+ ```typescript
754
+ import { isServiceConfigured } from '@kb-labs/shared-command-kit/helpers';
755
+
756
+ async function handler(ctx: PluginContext) {
757
+ if (isServiceConfigured(ctx, 'llm')) {
758
+ // Use LLM
759
+ const response = await completeLLM(ctx, prompt);
760
+ } else {
761
+ // Fallback behavior
762
+ ctx.ui.warning('LLM not configured, using fallback');
763
+ }
764
+ }
765
+ ```
766
+
767
+ ---
768
+
769
+ ## Validation Helpers
770
+
771
+ Ready-to-use validation schemas and Zod integration for type-safe input validation.
772
+
773
+ ### Common Schemas
774
+
775
+ ```typescript
776
+ import { schemas } from '@kb-labs/shared-command-kit/helpers';
777
+
778
+ const userSchema = z.object({
779
+ name: schemas.nonEmptyString,
780
+ email: schemas.email,
781
+ version: schemas.semver,
782
+ repo: schemas.githubUrl,
783
+ age: schemas.positiveInt,
784
+ port: schemas.port,
785
+ id: schemas.uuid,
786
+ tenantId: schemas.tenantId,
787
+ pluginId: schemas.pluginId,
788
+ packageName: schemas.packageName,
789
+ config: schemas.jsonString,
790
+ color: schemas.hexColor,
791
+ url: schemas.url,
792
+ createdAt: schemas.isoDate,
793
+ });
794
+ ```
795
+
796
+ **Available schemas**:
797
+ - `packageName` - NPM package name (scoped or unscoped)
798
+ - `scopedPackageName` - Scoped package name (must start with @)
799
+ - `semver` - Semantic version
800
+ - `email` - Email address
801
+ - `url` - HTTP/HTTPS URL
802
+ - `githubUrl` - GitHub repository URL
803
+ - `filePath` - File path (Unix-style)
804
+ - `nonEmptyString` - Non-empty string (trimmed)
805
+ - `positiveInt` - Positive integer
806
+ - `nonNegativeInt` - Non-negative integer (including 0)
807
+ - `port` - Port number (1-65535)
808
+ - `uuid` - UUID v4
809
+ - `isoDate` - ISO 8601 date string
810
+ - `jsonString` - JSON string (can be parsed)
811
+ - `hexColor` - Hexadecimal color code
812
+ - `tenantId` - Tenant ID (alphanumeric, dash, underscore)
813
+ - `pluginId` - Plugin ID (scoped package name)
814
+
815
+ ### Validation Functions
816
+
817
+ ```typescript
818
+ import { validateInput, safeValidate, validateSchema, validateArray } from '@kb-labs/shared-command-kit/helpers';
819
+ import { z } from 'zod';
820
+
821
+ // Validate input (throws ValidationError on failure)
822
+ const configSchema = z.object({
823
+ output: z.string().optional(),
824
+ force: z.boolean().default(false),
825
+ });
826
+
827
+ const config = validateInput(configSchema, rawInput);
828
+ // config is typed as { output?: string; force: boolean }
829
+
830
+ // Safe validation (returns success/failure)
831
+ const result = safeValidate(schemas.email, input);
832
+ if (result.success) {
833
+ console.log('Valid email:', result.data);
834
+ } else {
835
+ console.error('Invalid:', result.error);
836
+ console.error('Issues:', result.issues);
837
+ }
838
+
839
+ // Validate schema (convenience wrapper)
840
+ const validConfig = validateSchema(configSchema, rawConfig);
841
+
842
+ // Validate array of items
843
+ const { valid, invalid } = validateArray(schemas.email, emails);
844
+ console.log(`${valid.length} valid, ${invalid.length} invalid`);
845
+ for (const { index, error } of invalid) {
846
+ console.error(`Item ${index}: ${error}`);
847
+ }
848
+ ```
849
+
850
+ ### Type Guards
851
+
852
+ ```typescript
853
+ import { isPackageName, isSemver, isEmail, isUrl, isUUID } from '@kb-labs/shared-command-kit/helpers';
854
+
855
+ if (isPackageName(value)) {
856
+ // value is typed as string
857
+ installPackage(value);
858
+ }
859
+
860
+ if (isSemver(version)) {
861
+ compareVersions(version, '1.0.0');
862
+ }
863
+
864
+ if (isEmail(contact)) {
865
+ sendEmail(contact);
866
+ }
867
+ ```
868
+
869
+ ### Helper Functions
870
+
871
+ ```typescript
872
+ import { optionalString, optionalBoolean, optionalNumber, enumFromArray } from '@kb-labs/shared-command-kit/helpers';
873
+
874
+ const schema = z.object({
875
+ format: optionalString('json'), // defaults to 'json'
876
+ force: optionalBoolean(false), // defaults to false
877
+ timeout: optionalNumber(5000), // defaults to 5000
878
+ mode: enumFromArray(['instant', 'auto', 'thinking'] as const),
879
+ });
880
+ ```
881
+
882
+ ---
883
+
884
+ ## Common Patterns
885
+
886
+ ### Spinner Pattern
887
+
888
+ Show progress feedback for long-running operations:
889
+
890
+ ```typescript
891
+ import { withSpinner, withSteps } from '@kb-labs/shared-command-kit/helpers';
892
+
893
+ // Single operation with spinner
894
+ const result = await withSpinner(
895
+ ctx,
896
+ 'Indexing documents',
897
+ async () => {
898
+ return await indexDocuments(docs);
899
+ }
900
+ );
901
+ // Output: "Indexing documents... ✓"
902
+
903
+ // Multiple steps with progress
904
+ const [docs, vectors, stored] = await withSteps(ctx, [
905
+ { message: 'Loading documents', fn: () => loadDocuments() },
906
+ { message: 'Generating embeddings', fn: () => generateEmbeddings(docs) },
907
+ { message: 'Storing in database', fn: () => storeVectors(vectors) },
908
+ ]);
909
+ // Output:
910
+ // "Loading documents... ✓"
911
+ // "Generating embeddings... ✓"
912
+ // "Storing in database... ✓"
913
+ ```
914
+
915
+ ### Batch Processing
916
+
917
+ Process arrays with concurrency control and progress feedback:
918
+
919
+ ```typescript
920
+ import { processBatch, processBatchWithUI } from '@kb-labs/shared-command-kit/helpers';
921
+
922
+ // Batch processing with custom options
923
+ const results = await processBatch(
924
+ files,
925
+ async (file, index) => await processFile(file),
926
+ {
927
+ concurrency: 10,
928
+ onProgress: (completed, total) => {
929
+ ctx.ui.message(`Processed ${completed}/${total}`);
930
+ },
931
+ onError: (error, item) => {
932
+ ctx.ui.warning(`Failed to process ${item}: ${error.message}`);
933
+ },
934
+ stopOnError: false,
935
+ }
936
+ );
937
+
938
+ // Batch processing with automatic UI updates
939
+ const results = await processBatchWithUI(
940
+ ctx,
941
+ files,
942
+ async (file) => await processFile(file),
943
+ { concurrency: 10 }
944
+ );
945
+ // Automatically shows: "Processing 1/100... 2/100..."
946
+ ```
947
+
948
+ ### Retry Logic
949
+
950
+ Retry operations with exponential backoff:
951
+
952
+ ```typescript
953
+ import { retryWithBackoff, retryWithUI } from '@kb-labs/shared-command-kit/helpers';
954
+
955
+ // Retry with custom options
956
+ const data = await retryWithBackoff(
957
+ async () => await fetchFromAPI(),
958
+ {
959
+ maxRetries: 5,
960
+ delay: 1000,
961
+ backoff: 2,
962
+ maxDelay: 30000,
963
+ onRetry: (attempt, error) => {
964
+ console.log(`Retry ${attempt}: ${error.message}`);
965
+ },
966
+ shouldRetry: (error) => {
967
+ // Only retry on network errors
968
+ return error.message.includes('ECONNREFUSED');
969
+ },
970
+ }
971
+ );
972
+
973
+ // Retry with UI feedback
974
+ const data = await retryWithUI(
975
+ ctx,
976
+ 'Fetching data from API',
977
+ async () => await api.getData(),
978
+ { maxRetries: 3 }
979
+ );
980
+ // Output: "Retrying (1/3)...", "Retrying (2/3)..."
981
+ ```
982
+
983
+ ### Utilities
984
+
985
+ ```typescript
986
+ import { sleep, withTimeout, debounce, throttle } from '@kb-labs/shared-command-kit/helpers';
987
+
988
+ // Sleep
989
+ await sleep(1000); // Wait 1 second
990
+
991
+ // Timeout wrapper
992
+ const result = await withTimeout(
993
+ async () => await slowOperation(),
994
+ 5000 // 5 seconds timeout
995
+ );
996
+
997
+ // Debounce (wait for calls to stop)
998
+ const debouncedSave = debounce(
999
+ async (data) => await saveToDatabase(data),
1000
+ 1000
1001
+ );
1002
+ debouncedSave(data1);
1003
+ debouncedSave(data2);
1004
+ debouncedSave(data3); // Only this one executes
1005
+
1006
+ // Throttle (execute at most once per interval)
1007
+ const throttledLog = throttle(
1008
+ async (message) => await sendToAPI(message),
1009
+ 5000
1010
+ );
1011
+ throttledLog('msg1'); // Executes immediately
1012
+ throttledLog('msg2'); // Ignored (within 5s)
1013
+ // ... 5s later ...
1014
+ throttledLog('msg3'); // Executes
1015
+ ```
1016
+
1017
+ ---
1018
+
1019
+ ## Related Packages
1020
+
1021
+ - `@kb-labs/core-platform` - Platform service interfaces
1022
+ - `@kb-labs/core-runtime` - DI container and core implementations
1023
+ - `@kb-labs/plugin-runtime` - Plugin context and runtime
1024
+ - `@kb-labs/shared-cli-ui` - CLI UI components and formatters
1025
+
1026
+ ---
1027
+
1028
+ ## License
1029
+
1030
+ MIT