@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,316 @@
1
+ /**
2
+ * @module @kb-labs/shared-command-kit/helpers/use-llm
3
+ * Global LLM access helper with tier-based model selection.
4
+ *
5
+ * Provides clean access to LLM with adaptive tier routing.
6
+ * Plugins specify tiers (small/medium/large), platform resolves to actual models.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { useLLM } from '@kb-labs/shared-command-kit';
11
+ *
12
+ * async handler(ctx, argv, flags) {
13
+ * // Simple usage (uses configured default tier)
14
+ * const llm = useLLM();
15
+ *
16
+ * // Request specific tier (platform adapts if needed)
17
+ * const llm = useLLM({ tier: 'small' }); // Simple tasks
18
+ * const llm = useLLM({ tier: 'large' }); // Complex tasks
19
+ *
20
+ * // Request capabilities
21
+ * const llm = useLLM({ tier: 'medium', capabilities: ['coding'] });
22
+ *
23
+ * if (llm) {
24
+ * const result = await llm.complete('Explain this code');
25
+ * console.log(result.content);
26
+ * }
27
+ * }
28
+ * ```
29
+ */
30
+
31
+ import { usePlatform } from './use-platform.js';
32
+ import type {
33
+ ILLM,
34
+ LLMTier,
35
+ LLMOptions,
36
+ LLMResponse,
37
+ LLMMessage,
38
+ LLMToolCallOptions,
39
+ LLMToolCallResponse,
40
+ UseLLMOptions,
41
+ ILLMRouter,
42
+ LLMAdapterBinding,
43
+ LLMExecutionPolicy,
44
+ LLMProtocolCapabilities,
45
+ LLMCacheDecisionTrace,
46
+ } from '@kb-labs/core-platform';
47
+
48
+ /**
49
+ * Access global LLM adapter with tier-based selection.
50
+ *
51
+ * Platform automatically adapts to available models:
52
+ * - If plugin requests 'small' but 'medium' configured → uses 'medium' (escalation)
53
+ * - If plugin requests 'large' but 'medium' configured → uses 'medium' with warning (degradation)
54
+ *
55
+ * **Tiers are user-defined slots:**
56
+ * - `small` - Plugin says: "This task is simple"
57
+ * - `medium` - Plugin says: "Standard task"
58
+ * - `large` - Plugin says: "Complex task, need maximum quality"
59
+ *
60
+ * User decides what model maps to each tier in their config.
61
+ *
62
+ * @param options - Optional tier and capability requirements
63
+ * @returns LLM adapter or undefined if not configured
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * // Simple usage (uses configured default)
68
+ * const llm = useLLM();
69
+ *
70
+ * // Request specific tier
71
+ * const llm = useLLM({ tier: 'small' }); // Simple tasks
72
+ * const llm = useLLM({ tier: 'large' }); // Complex tasks
73
+ *
74
+ * // Request capabilities
75
+ * const llm = useLLM({ tier: 'medium', capabilities: ['coding'] });
76
+ * const llm = useLLM({ capabilities: ['vision'] });
77
+ *
78
+ * if (llm) {
79
+ * const result = await llm.complete('Generate commit message');
80
+ * console.log(result.content);
81
+ * }
82
+ * ```
83
+ */
84
+ export function useLLM(options?: UseLLMOptions): ILLM | undefined {
85
+ const platform = usePlatform();
86
+ const llm = platform.llm;
87
+
88
+ if (!llm) {
89
+ return undefined;
90
+ }
91
+
92
+ // If router and options given → return immutable LazyBoundLLM (no state mutation)
93
+ if (options && isLLMRouter(llm)) {
94
+ return new LazyBoundLLM(llm, options);
95
+ }
96
+
97
+ return llm;
98
+ }
99
+
100
+ /**
101
+ * Lazy adapter binding that resolves tier on first use.
102
+ * Immutable — does NOT mutate the global LLMRouter state.
103
+ * This fixes the race condition where useLLM({ tier: 'large' }) was immediately
104
+ * overwritten by useLLM({ tier: 'small' }) from SmartSummarizer.
105
+ */
106
+ class LazyBoundLLM implements ILLM {
107
+ private _resolved: Promise<LLMAdapterBinding> | null = null;
108
+
109
+ constructor(
110
+ private readonly router: ILLM & ILLMRouter,
111
+ private readonly options: UseLLMOptions,
112
+ ) {}
113
+
114
+ private resolve(): Promise<LLMAdapterBinding> {
115
+ if (!this._resolved) {
116
+ this._resolved = this.router.resolveAdapter(this.options);
117
+ }
118
+ return this._resolved;
119
+ }
120
+
121
+ private mergeExecutionPolicy(callOptions?: LLMOptions): LLMExecutionPolicy | undefined {
122
+ const globalPolicy = this.options.execution;
123
+ const localPolicy = callOptions?.execution;
124
+ if (!globalPolicy && !localPolicy) {
125
+ return undefined;
126
+ }
127
+ return {
128
+ ...globalPolicy,
129
+ ...localPolicy,
130
+ cache: { ...globalPolicy?.cache, ...localPolicy?.cache },
131
+ stream: { ...globalPolicy?.stream, ...localPolicy?.stream },
132
+ };
133
+ }
134
+
135
+ private async resolveProtocolCapabilities(adapter: ILLM): Promise<LLMProtocolCapabilities> {
136
+ if (!adapter.getProtocolCapabilities) {
137
+ return {
138
+ cache: { supported: false },
139
+ stream: { supported: true },
140
+ };
141
+ }
142
+ return adapter.getProtocolCapabilities();
143
+ }
144
+
145
+ private enforceCachePolicy(caps: LLMProtocolCapabilities, execution?: LLMExecutionPolicy): void {
146
+ if (execution?.cache?.mode === 'require' && !caps.cache.supported) {
147
+ throw new Error('CACHE_NOT_SUPPORTED: adapter does not support required cache policy');
148
+ }
149
+ }
150
+
151
+ private buildDecisionTrace(
152
+ caps: LLMProtocolCapabilities,
153
+ execution: LLMExecutionPolicy | undefined,
154
+ streamAppliedMode: 'prefer' | 'require' | 'off',
155
+ streamFallback?: 'complete',
156
+ reason?: string,
157
+ ): LLMCacheDecisionTrace {
158
+ const requestedCacheMode = execution?.cache?.mode ?? 'prefer';
159
+ const requestedStreamMode = execution?.stream?.mode ?? 'prefer';
160
+
161
+ return {
162
+ cacheRequestedMode: requestedCacheMode,
163
+ cacheSupported: caps.cache.supported,
164
+ cacheAppliedMode:
165
+ requestedCacheMode === 'require' || requestedCacheMode === 'bypass'
166
+ ? requestedCacheMode
167
+ : caps.cache.supported
168
+ ? 'prefer'
169
+ : 'bypass',
170
+ streamRequestedMode: requestedStreamMode,
171
+ streamSupported: caps.stream.supported,
172
+ streamAppliedMode,
173
+ streamFallback,
174
+ reason,
175
+ };
176
+ }
177
+
178
+ private withDecisionMetadata(
179
+ options: LLMOptions | undefined,
180
+ trace: LLMCacheDecisionTrace,
181
+ ): LLMOptions | undefined {
182
+ if (!options) {
183
+ return { metadata: { cacheDecisionTrace: trace } };
184
+ }
185
+
186
+ return {
187
+ ...options,
188
+ metadata: {
189
+ ...options.metadata,
190
+ cacheDecisionTrace: trace,
191
+ },
192
+ };
193
+ }
194
+
195
+ async complete(prompt: string, options?: LLMOptions): Promise<LLMResponse> {
196
+ const { adapter, model } = await this.resolve();
197
+ const execution = this.mergeExecutionPolicy(options);
198
+ const caps = await this.resolveProtocolCapabilities(adapter);
199
+ this.enforceCachePolicy(caps, execution);
200
+ const trace = this.buildDecisionTrace(caps, execution, 'off');
201
+ const optionsWithTrace = this.withDecisionMetadata(options, trace);
202
+ return adapter.complete(prompt, { ...optionsWithTrace, model, execution });
203
+ }
204
+
205
+ async *stream(prompt: string, options?: LLMOptions): AsyncIterable<string> {
206
+ const { adapter, model } = await this.resolve();
207
+ const execution = this.mergeExecutionPolicy(options);
208
+ const caps = await this.resolveProtocolCapabilities(adapter);
209
+ this.enforceCachePolicy(caps, execution);
210
+
211
+ const streamMode = execution?.stream?.mode ?? 'prefer';
212
+ const canStream = caps.stream.supported;
213
+ const allowFallback = execution?.stream?.fallbackToComplete ?? true;
214
+
215
+ if (streamMode === 'off' || (!canStream && streamMode === 'prefer' && allowFallback)) {
216
+ const fallbackReason =
217
+ streamMode === 'off'
218
+ ? 'STREAM_OFF'
219
+ : 'STREAM_UNSUPPORTED_FALLBACK_TO_COMPLETE';
220
+ const trace = this.buildDecisionTrace(caps, execution, 'off', 'complete', fallbackReason);
221
+ const optionsWithTrace = this.withDecisionMetadata(options, trace);
222
+ const response = await adapter.complete(prompt, { ...optionsWithTrace, model, execution });
223
+ if (response.content) {
224
+ yield response.content;
225
+ }
226
+ return;
227
+ }
228
+
229
+ if (!canStream && streamMode === 'require') {
230
+ throw new Error('STREAM_NOT_SUPPORTED: adapter does not support required streaming');
231
+ }
232
+
233
+ const trace = this.buildDecisionTrace(caps, execution, streamMode);
234
+ const optionsWithTrace = this.withDecisionMetadata(options, trace);
235
+ yield* adapter.stream(prompt, { ...optionsWithTrace, model, execution });
236
+ }
237
+
238
+ async chatWithTools(
239
+ messages: LLMMessage[],
240
+ options: LLMToolCallOptions,
241
+ ): Promise<LLMToolCallResponse> {
242
+ const { adapter, model, tier } = await this.resolve();
243
+ const execution = this.mergeExecutionPolicy(options);
244
+ const caps = await this.resolveProtocolCapabilities(adapter);
245
+ this.enforceCachePolicy(caps, execution);
246
+ if (!adapter.chatWithTools) {
247
+ throw new Error('Current adapter does not support chatWithTools');
248
+ }
249
+ const trace = this.buildDecisionTrace(caps, execution, 'off');
250
+ const optionsWithTrace = this.withDecisionMetadata(options, trace) as LLMToolCallOptions;
251
+ return adapter.chatWithTools(messages, {
252
+ ...optionsWithTrace,
253
+ model,
254
+ execution,
255
+ metadata: { ...optionsWithTrace.metadata, tier },
256
+ });
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Check if LLM is available.
262
+ *
263
+ * Useful for conditional logic (LLM-powered vs deterministic fallback).
264
+ *
265
+ * @returns true if LLM is configured and ready
266
+ *
267
+ * @example
268
+ * ```typescript
269
+ * if (isLLMAvailable()) {
270
+ * const summary = await generateWithLLM(data);
271
+ * } else {
272
+ * const summary = generateDeterministic(data);
273
+ * }
274
+ * ```
275
+ */
276
+ export function isLLMAvailable(): boolean {
277
+ const llm = useLLM();
278
+ return !!llm;
279
+ }
280
+
281
+ /**
282
+ * Get configured LLM tier.
283
+ *
284
+ * Useful for diagnostics and logging.
285
+ *
286
+ * @returns Configured tier or undefined if LLM not available/not a router
287
+ *
288
+ * @example
289
+ * ```typescript
290
+ * const tier = getLLMTier();
291
+ * console.log(`Using LLM tier: ${tier ?? 'default'}`);
292
+ * ```
293
+ */
294
+ export function getLLMTier(): LLMTier | undefined {
295
+ const platform = usePlatform();
296
+ const llm = platform.llm;
297
+
298
+ if (llm && isLLMRouter(llm)) {
299
+ return llm.getConfiguredTier();
300
+ }
301
+
302
+ return undefined;
303
+ }
304
+
305
+ /**
306
+ * Type guard for ILLMRouter.
307
+ */
308
+ function isLLMRouter(llm: ILLM): llm is ILLM & ILLMRouter {
309
+ return (
310
+ typeof (llm as unknown as ILLMRouter).getConfiguredTier === 'function' &&
311
+ typeof (llm as unknown as ILLMRouter).resolve === 'function'
312
+ );
313
+ }
314
+
315
+ // Re-export types for convenience
316
+ export type { LLMTier, UseLLMOptions } from '@kb-labs/core-platform';
@@ -0,0 +1,77 @@
1
+ /**
2
+ * @module @kb-labs/shared-command-kit/helpers/use-logger
3
+ * Global logger access helper
4
+ *
5
+ * Provides clean access to structured logging without context drilling.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { useLogger } from '@kb-labs/shared-command-kit';
10
+ *
11
+ * async handler(ctx, argv, flags) {
12
+ * const logger = useLogger();
13
+ *
14
+ * await logger.info('Processing started');
15
+ * await logger.debug('Details', { userId: 123 });
16
+ * await logger.error('Failed', { error: err });
17
+ * }
18
+ * ```
19
+ */
20
+
21
+ import { usePlatform } from './use-platform';
22
+ import type { ILogger } from '@kb-labs/core-platform';
23
+
24
+ /**
25
+ * Access global logger
26
+ *
27
+ * Returns the platform logger with structured logging capabilities.
28
+ * Supports child loggers with additional context.
29
+ *
30
+ * **Methods:**
31
+ * - `logger.trace(message, meta?)` - Trace-level logs (most verbose)
32
+ * - `logger.debug(message, meta?)` - Debug-level logs
33
+ * - `logger.info(message, meta?)` - Info-level logs
34
+ * - `logger.warn(message, meta?)` - Warning-level logs
35
+ * - `logger.error(message, meta?)` - Error-level logs
36
+ * - `logger.child(meta)` - Create child logger with additional context
37
+ *
38
+ * @returns Platform logger instance
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const logger = useLogger();
43
+ *
44
+ * await logger.info('Task started', { taskId: '123' });
45
+ * await logger.error('Task failed', { taskId: '123', error: err.message });
46
+ *
47
+ * // Child logger with persistent context
48
+ * const taskLogger = logger.child({ taskId: '123', userId: 'user-1' });
49
+ * await taskLogger.info('Step 1 completed');
50
+ * await taskLogger.info('Step 2 completed');
51
+ * ```
52
+ */
53
+ export function useLogger(): ILogger {
54
+ const platform = usePlatform();
55
+ return platform.logger;
56
+ }
57
+
58
+ /**
59
+ * Create child logger with additional context
60
+ *
61
+ * Useful for scoped logging within a specific operation.
62
+ *
63
+ * @param context - Additional context to attach to all log entries
64
+ * @returns Child logger with persistent context
65
+ *
66
+ * @example
67
+ * ```typescript
68
+ * const logger = useLoggerWithContext({ operation: 'release', version: '1.0.0' });
69
+ *
70
+ * await logger.info('Started'); // Automatically includes operation + version
71
+ * await logger.info('Completed');
72
+ * ```
73
+ */
74
+ export function useLoggerWithContext(context: Record<string, unknown>): ILogger {
75
+ const logger = useLogger();
76
+ return logger.child(context);
77
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @module @kb-labs/shared-command-kit/helpers/use-platform
3
+ * Global platform singleton access helper
4
+ *
5
+ * Provides clean access to platform services without context drilling.
6
+ * Similar to React hooks pattern, but for KB Labs platform.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { usePlatform } from '@kb-labs/shared-command-kit';
11
+ *
12
+ * // In any command handler
13
+ * async handler(ctx, argv, flags) {
14
+ * const platform = usePlatform();
15
+ *
16
+ * if (platform.llm) {
17
+ * const result = await platform.llm.complete('prompt');
18
+ * }
19
+ *
20
+ * await platform.logger.info('Task completed');
21
+ * }
22
+ * ```
23
+ */
24
+
25
+ import { platform as globalPlatform } from '@kb-labs/core-runtime';
26
+
27
+ /**
28
+ * Access global platform singleton
29
+ *
30
+ * Returns the initialized platform object with all registered adapters.
31
+ * This is the single source of truth for platform services.
32
+ *
33
+ * **What's available:**
34
+ * - `platform.llm` - LLM adapter (OpenAI, Anthropic, etc.)
35
+ * - `platform.embeddings` - Embeddings adapter
36
+ * - `platform.vectorStore` - Vector storage (Qdrant, local, etc.)
37
+ * - `platform.storage` - File/blob storage
38
+ * - `platform.cache` - Caching layer
39
+ * - `platform.analytics` - Analytics/telemetry
40
+ * - `platform.logger` - Structured logging
41
+ * - `platform.eventBus` - Event system
42
+ * - `platform.workflows` - Workflow engine
43
+ * - `platform.jobs` - Background jobs
44
+ * - `platform.cron` - Scheduled tasks
45
+ * - `platform.resources` - Resource management
46
+ * - `platform.invoke` - Plugin invocation
47
+ * - `platform.artifacts` - Build artifacts
48
+ *
49
+ * **Graceful degradation:**
50
+ * Always check if adapter is available before using:
51
+ * ```typescript
52
+ * const platform = usePlatform();
53
+ * if (platform.llm) {
54
+ * // Use LLM
55
+ * } else {
56
+ * // Fallback logic
57
+ * }
58
+ * ```
59
+ *
60
+ * **Multi-tenancy:**
61
+ * Currently returns global singleton (single-tenant).
62
+ * Future: Will support tenant-scoped platform via AsyncLocalStorage.
63
+ *
64
+ * @returns Global platform singleton
65
+ */
66
+ export function usePlatform(): typeof globalPlatform {
67
+ return globalPlatform;
68
+ }
69
+
70
+ /**
71
+ * Check if specific platform adapter is configured
72
+ *
73
+ * Useful for conditional logic based on available services.
74
+ *
75
+ * @param adapterName - Name of the adapter to check
76
+ * @returns true if adapter is configured and available
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * if (isPlatformConfigured('llm')) {
81
+ * // Use LLM-powered feature
82
+ * } else {
83
+ * // Use deterministic fallback
84
+ * }
85
+ * ```
86
+ */
87
+ export function isPlatformConfigured(adapterName: keyof typeof globalPlatform): boolean {
88
+ const platform = usePlatform();
89
+
90
+ // Check if adapter exists and is not a noop/fallback
91
+ const adapter = platform[adapterName];
92
+
93
+ if (!adapter) {
94
+ return false;
95
+ }
96
+
97
+ // For adapters with hasAdapter method (like platform itself)
98
+ if ('hasAdapter' in platform && typeof platform.hasAdapter === 'function') {
99
+ return platform.hasAdapter(adapterName as any);
100
+ }
101
+
102
+ // Fallback: check if adapter is not noop
103
+ // Noop adapters usually have a specific constructor name or are simple objects
104
+ if (typeof adapter === 'object' && adapter.constructor) {
105
+ const constructorName = adapter.constructor.name;
106
+ return !constructorName.toLowerCase().includes('noop') &&
107
+ !constructorName.toLowerCase().includes('fallback');
108
+ }
109
+
110
+ return true;
111
+ }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * @module @kb-labs/shared-command-kit/helpers/use-resource-broker
3
+ * Global ResourceBroker access helper
4
+ *
5
+ * Provides clean access to ResourceBroker for queue and rate limiting.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { useResourceBroker } from '@kb-labs/shared-command-kit';
10
+ *
11
+ * async handler(ctx, argv, flags) {
12
+ * const broker = useResourceBroker();
13
+ *
14
+ * // Get statistics
15
+ * const stats = broker.getStats();
16
+ * console.log(`Queue size: ${stats.queueSize}`);
17
+ * }
18
+ * ```
19
+ */
20
+
21
+ import { usePlatform } from './use-platform.js';
22
+ import type { IResourceBroker } from '@kb-labs/core-resource-broker';
23
+
24
+ /**
25
+ * Access global ResourceBroker
26
+ *
27
+ * Returns the platform ResourceBroker for queue management, rate limiting,
28
+ * and retry logic for heavy operations (LLM, embeddings, vector store).
29
+ *
30
+ * **Features:**
31
+ * - Priority queue (high/normal/low)
32
+ * - Rate limiting with configurable backend
33
+ * - Automatic retry with exponential backoff
34
+ * - Per-resource statistics
35
+ *
36
+ * **Note:** Most plugins don't need this directly.
37
+ * Use `useLLM()`, `useEmbeddings()`, etc. which automatically
38
+ * route through the ResourceBroker.
39
+ *
40
+ * @returns ResourceBroker instance
41
+ * @throws Error if ResourceBroker not initialized
42
+ *
43
+ * @example
44
+ * ```typescript
45
+ * const broker = useResourceBroker();
46
+ *
47
+ * // Get queue statistics
48
+ * const stats = broker.getStats();
49
+ * console.log(`Total requests: ${stats.totalRequests}`);
50
+ * console.log(`Queue size: ${stats.queueSize}`);
51
+ *
52
+ * // Check if resource is registered
53
+ * if (broker.hasResource('llm')) {
54
+ * console.log('LLM is available for queueing');
55
+ * }
56
+ * ```
57
+ */
58
+ export function useResourceBroker(): IResourceBroker {
59
+ const platform = usePlatform();
60
+ return platform.resourceBroker;
61
+ }
62
+
63
+ /**
64
+ * Check if ResourceBroker is available
65
+ *
66
+ * Useful for conditional logic when ResourceBroker may not be initialized.
67
+ *
68
+ * @returns true if ResourceBroker is initialized and ready
69
+ *
70
+ * @example
71
+ * ```typescript
72
+ * if (isResourceBrokerAvailable()) {
73
+ * const broker = useResourceBroker();
74
+ * const stats = broker.getStats();
75
+ * } else {
76
+ * console.log('ResourceBroker not initialized');
77
+ * }
78
+ * ```
79
+ */
80
+ export function isResourceBrokerAvailable(): boolean {
81
+ const platform = usePlatform();
82
+ return platform.hasResourceBroker;
83
+ }
84
+
85
+ /**
86
+ * Get ResourceBroker statistics
87
+ *
88
+ * Convenience helper to get statistics without handling the broker directly.
89
+ *
90
+ * @returns ResourceBroker statistics or undefined if not available
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * const stats = getResourceBrokerStats();
95
+ * if (stats) {
96
+ * console.log(`LLM requests: ${stats.resources.llm?.totalRequests ?? 0}`);
97
+ * console.log(`Queue size: ${stats.queueSize}`);
98
+ * }
99
+ * ```
100
+ */
101
+ export function getResourceBrokerStats() {
102
+ if (!isResourceBrokerAvailable()) {
103
+ return undefined;
104
+ }
105
+ return useResourceBroker().getStats();
106
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @module @kb-labs/shared-command-kit/helpers/use-storage
3
+ * Global storage access helper
4
+ *
5
+ * Provides clean access to file/blob storage adapter.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { useStorage } from '@kb-labs/shared-command-kit';
10
+ *
11
+ * async handler(ctx, argv, flags) {
12
+ * const storage = useStorage();
13
+ *
14
+ * if (storage) {
15
+ * await storage.write('path/to/file.txt', 'content');
16
+ * const content = await storage.read('path/to/file.txt');
17
+ * }
18
+ * }
19
+ * ```
20
+ */
21
+
22
+ import { usePlatform } from './use-platform';
23
+ import type { IStorage } from '@kb-labs/core-platform';
24
+
25
+ /**
26
+ * Access global storage adapter
27
+ *
28
+ * Returns the platform storage adapter for file/blob operations.
29
+ * Returns undefined if storage is not configured (graceful degradation).
30
+ *
31
+ * **Methods:**
32
+ * - `storage.read(path)` - Read file content
33
+ * - `storage.write(path, content)` - Write file content
34
+ * - `storage.exists(path)` - Check if file exists
35
+ * - `storage.delete(path)` - Delete file
36
+ * - `storage.list(prefix?)` - List files
37
+ *
38
+ * **Always check availability:**
39
+ * ```typescript
40
+ * const storage = useStorage();
41
+ * if (storage) {
42
+ * await storage.write('file.txt', 'content');
43
+ * }
44
+ * ```
45
+ *
46
+ * @returns Storage adapter or undefined if not configured
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const storage = useStorage();
51
+ *
52
+ * if (storage) {
53
+ * // Write file
54
+ * await storage.write('releases/v1.0.0.json', JSON.stringify(data));
55
+ *
56
+ * // Read file
57
+ * const content = await storage.read('releases/v1.0.0.json');
58
+ * const data = JSON.parse(content);
59
+ *
60
+ * // Check existence
61
+ * const exists = await storage.exists('releases/v1.0.0.json');
62
+ *
63
+ * // List files
64
+ * const files = await storage.list('releases/');
65
+ * }
66
+ * ```
67
+ */
68
+ export function useStorage(): IStorage | undefined {
69
+ const platform = usePlatform();
70
+ return platform.storage;
71
+ }