@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,6 @@
1
+ /**
2
+ * @module @kb-labs/shared-command-kit/validation
3
+ * Validation schema builders
4
+ */
5
+
6
+ export * from './schema-builders';
@@ -0,0 +1,409 @@
1
+ /**
2
+ * Schema Builders for KB Labs Plugins
3
+ *
4
+ * Optional helpers for common Zod validation patterns.
5
+ * You can always use plain Zod - these are just conveniences for repetitive patterns.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { schema } from '@kb-labs/shared-command-kit';
10
+ *
11
+ * const RequestSchema = schema.object({
12
+ * cwd: schema.cwd(),
13
+ * scope: schema.scopeId(),
14
+ * text: schema.text({ min: 1, max: 10000 }),
15
+ * mode: schema.enum(['instant', 'auto', 'thinking'], { default: 'auto' }),
16
+ * limit: schema.positiveInt({ max: 100, default: 10 }),
17
+ * });
18
+ * ```
19
+ */
20
+
21
+ import { z } from 'zod';
22
+
23
+ /**
24
+ * Current working directory path (optional string)
25
+ * Commonly used in CLI and REST handlers
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const schema = z.object({
30
+ * cwd: schema.cwd(),
31
+ * });
32
+ * // Equivalent to: cwd: z.string().optional()
33
+ * ```
34
+ */
35
+ export function cwd() {
36
+ return z.string().optional().describe('Current working directory path');
37
+ }
38
+
39
+ /**
40
+ * Scope identifier (required non-empty string)
41
+ * Used for Mind RAG scopes, workflow scopes, etc.
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * const schema = z.object({
46
+ * scope: schema.scopeId(),
47
+ * });
48
+ * // Equivalent to: scope: z.string().min(1)
49
+ * ```
50
+ */
51
+ export function scopeId() {
52
+ return z.string().min(1).describe('Scope identifier');
53
+ }
54
+
55
+ /**
56
+ * Text string with optional length constraints
57
+ *
58
+ * @example
59
+ * ```typescript
60
+ * schema.text({ min: 1, max: 10000 })
61
+ * // Equivalent to: z.string().min(1).max(10000)
62
+ * ```
63
+ */
64
+ export function text(options?: { min?: number; max?: number; default?: string }): z.ZodString | z.ZodDefault<z.ZodString> {
65
+ let schema = z.string();
66
+
67
+ if (options?.min !== undefined) {
68
+ schema = schema.min(options.min);
69
+ }
70
+
71
+ if (options?.max !== undefined) {
72
+ schema = schema.max(options.max);
73
+ }
74
+
75
+ if (options?.default !== undefined) {
76
+ return schema.default(options.default).describe('Text string');
77
+ }
78
+
79
+ return schema.describe('Text string');
80
+ }
81
+
82
+ /**
83
+ * Positive integer with optional constraints
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * schema.positiveInt({ max: 100, default: 10 })
88
+ * // Equivalent to: z.number().int().positive().max(100).default(10)
89
+ * ```
90
+ */
91
+ export function positiveInt(options?: { min?: number; max?: number; default?: number }): z.ZodNumber | z.ZodDefault<z.ZodNumber> {
92
+ let schema = z.number().int().positive();
93
+
94
+ if (options?.min !== undefined) {
95
+ schema = schema.min(options.min);
96
+ }
97
+
98
+ if (options?.max !== undefined) {
99
+ schema = schema.max(options.max);
100
+ }
101
+
102
+ if (options?.default !== undefined) {
103
+ return schema.default(options.default).describe('Positive integer');
104
+ }
105
+
106
+ return schema.describe('Positive integer');
107
+ }
108
+
109
+ /**
110
+ * Non-negative integer (0 or positive)
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * schema.nonNegativeInt({ max: 100 })
115
+ * // Equivalent to: z.number().int().min(0).max(100)
116
+ * ```
117
+ */
118
+ export function nonNegativeInt(options?: { max?: number; default?: number }): z.ZodNumber | z.ZodDefault<z.ZodNumber> {
119
+ let schema = z.number().int().min(0);
120
+
121
+ if (options?.max !== undefined) {
122
+ schema = schema.max(options.max);
123
+ }
124
+
125
+ if (options?.default !== undefined) {
126
+ return schema.default(options.default).describe('Non-negative integer');
127
+ }
128
+
129
+ return schema.describe('Non-negative integer');
130
+ }
131
+
132
+ /**
133
+ * Enum with optional default value
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * schema.enum(['instant', 'auto', 'thinking'], { default: 'auto' })
138
+ * // Equivalent to: z.enum(['instant', 'auto', 'thinking']).default('auto')
139
+ * ```
140
+ */
141
+ export function enumSchema<T extends [string, ...string[]]>(
142
+ values: T,
143
+ options?: { default?: T[number] }
144
+ ): z.ZodDefault<z.ZodEnum<T>> | z.ZodEnum<T> {
145
+ const schema = z.enum(values);
146
+
147
+ if (options?.default !== undefined) {
148
+ return schema.default(options.default as T[number]);
149
+ }
150
+
151
+ return schema;
152
+ }
153
+
154
+ /**
155
+ * Plugin ID (@kb-labs/package-name format)
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * schema.pluginId()
160
+ * // Matches: @kb-labs/mind, @kb-labs/workflow, etc.
161
+ * ```
162
+ */
163
+ export function pluginId() {
164
+ return z
165
+ .string()
166
+ .regex(/^@kb-labs\/[a-z][a-z0-9-]*$/, 'Must be in format @kb-labs/package-name')
167
+ .describe('Plugin ID');
168
+ }
169
+
170
+ /**
171
+ * Command ID (plugin:command format)
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * schema.commandId()
176
+ * // Matches: mind:query, workflow:run, etc.
177
+ * ```
178
+ */
179
+ export function commandId() {
180
+ return z
181
+ .string()
182
+ .regex(/^[a-z][a-z0-9-]*:[a-z][a-z0-9-]*$/, 'Must be in format plugin:command')
183
+ .describe('Command ID');
184
+ }
185
+
186
+ /**
187
+ * Artifact ID (plugin.artifact.id format)
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * schema.artifactId()
192
+ * // Matches: mind.index.vector, workflow.run.result, etc.
193
+ * ```
194
+ */
195
+ export function artifactId() {
196
+ return z
197
+ .string()
198
+ .regex(/^[a-z][a-z0-9-]*\.[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)*$/, 'Must be in format plugin.artifact.id')
199
+ .describe('Artifact ID');
200
+ }
201
+
202
+ /**
203
+ * File path (string)
204
+ * Optional with default to undefined
205
+ *
206
+ * @example
207
+ * ```typescript
208
+ * schema.filePath()
209
+ * // Equivalent to: z.string()
210
+ * ```
211
+ */
212
+ export function filePath(options?: { optional?: boolean }) {
213
+ const schema = z.string().describe('File path');
214
+
215
+ if (options?.optional) {
216
+ return schema.optional();
217
+ }
218
+
219
+ return schema;
220
+ }
221
+
222
+ /**
223
+ * URL string
224
+ *
225
+ * @example
226
+ * ```typescript
227
+ * schema.url()
228
+ * // Equivalent to: z.string().url()
229
+ * ```
230
+ */
231
+ export function url(options?: { optional?: boolean }) {
232
+ const schema = z.string().url().describe('URL');
233
+
234
+ if (options?.optional) {
235
+ return schema.optional();
236
+ }
237
+
238
+ return schema;
239
+ }
240
+
241
+ /**
242
+ * Email string
243
+ *
244
+ * @example
245
+ * ```typescript
246
+ * schema.email()
247
+ * // Equivalent to: z.string().email()
248
+ * ```
249
+ */
250
+ export function email(options?: { optional?: boolean }) {
251
+ const schema = z.string().email().describe('Email address');
252
+
253
+ if (options?.optional) {
254
+ return schema.optional();
255
+ }
256
+
257
+ return schema;
258
+ }
259
+
260
+ /**
261
+ * UUID string
262
+ *
263
+ * @example
264
+ * ```typescript
265
+ * schema.uuid()
266
+ * // Equivalent to: z.string().uuid()
267
+ * ```
268
+ */
269
+ export function uuid(options?: { optional?: boolean }) {
270
+ const schema = z.string().uuid().describe('UUID');
271
+
272
+ if (options?.optional) {
273
+ return schema.optional();
274
+ }
275
+
276
+ return schema;
277
+ }
278
+
279
+ /**
280
+ * ISO datetime string
281
+ *
282
+ * @example
283
+ * ```typescript
284
+ * schema.datetime()
285
+ * // Equivalent to: z.string().datetime()
286
+ * ```
287
+ */
288
+ export function datetime(options?: { optional?: boolean }) {
289
+ const schema = z.string().datetime().describe('ISO datetime');
290
+
291
+ if (options?.optional) {
292
+ return schema.optional();
293
+ }
294
+
295
+ return schema;
296
+ }
297
+
298
+ /**
299
+ * JSON object (any valid JSON object)
300
+ *
301
+ * @example
302
+ * ```typescript
303
+ * schema.json()
304
+ * // Equivalent to: z.record(z.unknown())
305
+ * ```
306
+ */
307
+ export function json() {
308
+ return z.record(z.unknown()).describe('JSON object');
309
+ }
310
+
311
+ /**
312
+ * Boolean with optional default
313
+ *
314
+ * @example
315
+ * ```typescript
316
+ * schema.boolean({ default: false })
317
+ * // Equivalent to: z.boolean().default(false)
318
+ * ```
319
+ */
320
+ export function boolean(options?: { default?: boolean }) {
321
+ const schema = z.boolean();
322
+
323
+ if (options?.default !== undefined) {
324
+ return schema.default(options.default);
325
+ }
326
+
327
+ return schema;
328
+ }
329
+
330
+ /**
331
+ * Array of items with optional length constraints
332
+ *
333
+ * @example
334
+ * ```typescript
335
+ * schema.array(z.string(), { min: 1, max: 10 })
336
+ * // Equivalent to: z.array(z.string()).min(1).max(10)
337
+ * ```
338
+ */
339
+ export function array<T extends z.ZodTypeAny>(
340
+ itemSchema: T,
341
+ options?: { min?: number; max?: number }
342
+ ) {
343
+ let schema = z.array(itemSchema);
344
+
345
+ if (options?.min !== undefined) {
346
+ schema = schema.min(options.min);
347
+ }
348
+
349
+ if (options?.max !== undefined) {
350
+ schema = schema.max(options.max);
351
+ }
352
+
353
+ return schema;
354
+ }
355
+
356
+ /**
357
+ * Object schema builder (alias for z.object)
358
+ *
359
+ * @example
360
+ * ```typescript
361
+ * schema.object({ name: z.string() })
362
+ * // Equivalent to: z.object({ name: z.string() })
363
+ * ```
364
+ */
365
+ export function object<T extends z.ZodRawShape>(shape: T) {
366
+ return z.object(shape);
367
+ }
368
+
369
+ /**
370
+ * Export schema builders namespace
371
+ *
372
+ * @example
373
+ * ```typescript
374
+ * import { schema } from '@kb-labs/shared-command-kit';
375
+ *
376
+ * const MySchema = schema.object({
377
+ * cwd: schema.cwd(),
378
+ * scope: schema.scopeId(),
379
+ * text: schema.text({ min: 1, max: 10000 }),
380
+ * });
381
+ * ```
382
+ */
383
+ export const schema = {
384
+ // Path and ID builders
385
+ cwd,
386
+ scopeId,
387
+ pluginId,
388
+ commandId,
389
+ artifactId,
390
+ filePath,
391
+
392
+ // String builders
393
+ text,
394
+ url,
395
+ email,
396
+ uuid,
397
+ datetime,
398
+
399
+ // Number builders
400
+ positiveInt,
401
+ nonNegativeInt,
402
+
403
+ // Other builders
404
+ enum: enumSchema,
405
+ boolean,
406
+ json,
407
+ array,
408
+ object,
409
+ };
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Enhanced WebSocket types for better DX
3
+ *
4
+ * Provides type-safe message builders and pattern matching utilities.
5
+ */
6
+
7
+ import type { PluginContextV3 } from '@kb-labs/plugin-contracts';
8
+ import type { WSSender, WSMessage } from '@kb-labs/plugin-contracts';
9
+
10
+ /**
11
+ * Type-safe message builder
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const Progress = defineMessage<{ phase: string; progress: number }>('progress');
16
+ * const msg = Progress.create({ phase: 'analyzing', progress: 50 });
17
+ * // msg: { type: 'progress', payload: { phase: 'analyzing', progress: 50 }, timestamp: number }
18
+ * ```
19
+ */
20
+ export class MessageBuilder<TPayload = unknown> {
21
+ constructor(private type: string) {}
22
+
23
+ /**
24
+ * Create message with payload
25
+ */
26
+ create(payload: TPayload, messageId?: string): WSMessage {
27
+ return {
28
+ type: this.type,
29
+ payload,
30
+ messageId,
31
+ timestamp: Date.now(),
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Match against incoming message type (type guard)
37
+ */
38
+ is(message: WSMessage): message is WSMessage & { payload: TPayload } {
39
+ return message.type === this.type;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Helper to define typed messages
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * const StartMsg = defineMessage<{ scope?: string }>('start');
49
+ * const ProgressMsg = defineMessage<{ phase: string; progress: number }>('progress');
50
+ * ```
51
+ */
52
+ export function defineMessage<TPayload = unknown>(type: string) {
53
+ return new MessageBuilder<TPayload>(type);
54
+ }
55
+
56
+ /**
57
+ * Message router for pattern matching
58
+ *
59
+ * Provides elegant routing of incoming WebSocket messages to typed handlers.
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * const router = new MessageRouter()
64
+ * .on(StartMsg, async (ctx, payload, sender) => {
65
+ * // payload is typed as { scope?: string }
66
+ * console.log('Starting with scope:', payload.scope);
67
+ * })
68
+ * .on(StopMsg, async (ctx, payload, sender) => {
69
+ * // Different message type, different payload type
70
+ * sender.close(1000, 'Stopped by user');
71
+ * });
72
+ *
73
+ * await router.handle(ctx, message, sender);
74
+ * ```
75
+ */
76
+ export class MessageRouter<TConfig = unknown> {
77
+ private handlers = new Map<
78
+ string,
79
+ (ctx: PluginContextV3<TConfig>, payload: any, sender: WSSender) => Promise<void> | void
80
+ >();
81
+
82
+ /**
83
+ * Register message handler
84
+ */
85
+ on<TPayload>(
86
+ message: MessageBuilder<TPayload>,
87
+ handler: (ctx: PluginContextV3<TConfig>, payload: TPayload, sender: WSSender) => Promise<void> | void
88
+ ): this {
89
+ this.handlers.set(message['type'], handler);
90
+ return this;
91
+ }
92
+
93
+ /**
94
+ * Handle incoming message
95
+ *
96
+ * @returns true if message was handled, false otherwise
97
+ */
98
+ async handle(ctx: PluginContextV3<TConfig>, message: WSMessage, sender: WSSender): Promise<boolean> {
99
+ const handler = this.handlers.get(message.type);
100
+ if (handler) {
101
+ await handler(ctx, message.payload, sender);
102
+ return true;
103
+ }
104
+ return false;
105
+ }
106
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "baseUrl": ".",
6
+ "paths": {}
7
+ },
8
+ "include": [
9
+ "src/**/*"
10
+ ],
11
+ "exclude": [
12
+ "dist",
13
+ "node_modules"
14
+ ]
15
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "extends": "@kb-labs/devkit/tsconfig/node.json",
4
+ "compilerOptions": {
5
+ "rootDir": "src",
6
+ "outDir": "dist"
7
+ },
8
+ "include": ["src"]
9
+ }
@@ -0,0 +1,30 @@
1
+ import { defineConfig } from 'tsup';
2
+ import nodePreset from '@kb-labs/devkit/tsup/node';
3
+
4
+ export default defineConfig({
5
+ ...nodePreset,
6
+ entry: {
7
+ index: 'src/index.ts',
8
+ 'flags/index': 'src/flags/index.ts',
9
+ 'analytics/index': 'src/analytics/index.ts',
10
+ 'errors/index': 'src/errors/index.ts',
11
+ 'helpers/index': 'src/helpers/index.ts',
12
+ 'studio/index': 'src/studio/index.ts',
13
+ },
14
+ tsconfig: 'tsconfig.build.json', // Use build-specific tsconfig without paths
15
+ dts: {
16
+ resolve: true, // Resolve external type declarations
17
+ entry: {
18
+ // Skip studio types due to dependency issues
19
+ index: 'src/index.ts',
20
+ 'flags/index': 'src/flags/index.ts',
21
+ 'analytics/index': 'src/analytics/index.ts',
22
+ 'errors/index': 'src/errors/index.ts',
23
+ 'helpers/index': 'src/helpers/index.ts',
24
+ },
25
+ },
26
+ external: [
27
+ /^@kb-labs\/.*/, // All workspace packages - let runtime resolve them
28
+ ],
29
+ });
30
+
@@ -0,0 +1,4 @@
1
+ import preset from '@kb-labs/devkit/vitest/node';
2
+
3
+ export default preset;
4
+
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@kb-labs/shared-http",
3
+ "version": "1.1.0",
4
+ "type": "module",
5
+ "description": "Shared Fastify/OpenAPI utilities for KB Labs HTTP services",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "sideEffects": false,
19
+ "scripts": {
20
+ "clean": "rimraf dist",
21
+ "build": "tsup --config tsup.config.ts",
22
+ "dev": "tsup --config tsup.config.ts --watch",
23
+ "lint": "eslint src",
24
+ "lint:fix": "eslint src --fix",
25
+ "type-check": "tsc --noEmit",
26
+ "test": "vitest run --passWithNoTests",
27
+ "test:watch": "vitest"
28
+ },
29
+ "dependencies": {
30
+ "@kb-labs/core-contracts": "link:../../../kb-labs-core/packages/core-contracts",
31
+ "zod": "^4.0.0",
32
+ "zod-to-json-schema": "^3.25.0"
33
+ },
34
+ "peerDependencies": {
35
+ "@fastify/swagger": ">=9.5.1",
36
+ "@fastify/swagger-ui": "^5.2.0",
37
+ "fastify": "^5.5.0",
38
+ "fastify-type-provider-zod": "^6.0.0"
39
+ },
40
+ "peerDependenciesMeta": {
41
+ "@fastify/swagger": {
42
+ "optional": false
43
+ },
44
+ "@fastify/swagger-ui": {
45
+ "optional": false
46
+ },
47
+ "fastify-type-provider-zod": {
48
+ "optional": false
49
+ }
50
+ },
51
+ "devDependencies": {
52
+ "@kb-labs/devkit": "link:../../../../infra/kb-labs-devkit",
53
+ "@types/node": "^24.3.3",
54
+ "rimraf": "^6.0.1",
55
+ "tsup": "^8.5.0",
56
+ "typescript": "^5.6.3",
57
+ "vitest": "^3.2.4"
58
+ },
59
+ "engines": {
60
+ "node": ">=20.0.0",
61
+ "pnpm": ">=9.0.0"
62
+ },
63
+ "packageManager": "pnpm@9.11.0",
64
+ "publishConfig": {
65
+ "access": "public"
66
+ }
67
+ }