@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,52 @@
1
+ # ADR-XXXX: [Brief Decision Title]
2
+
3
+ **Date:** YYYY-MM-DD
4
+ **Status:** Proposed | Accepted | Deprecated | Superseded
5
+ **Deciders:** KB Labs Team
6
+ **Last Reviewed:** YYYY-MM-DD
7
+ **Reviewers:** [Optional list of reviewers]
8
+ **Tags:** [tag1, tag2, tag3]
9
+
10
+ > **Note:** Tags are mandatory. Minimum 1 tag, maximum 5 tags. See approved tags list in [DOCUMENTATION.md](../DOCUMENTATION.md#adr-tags).
11
+
12
+ ## Context
13
+
14
+ _Describe the problem or situation that necessitated this decision._
15
+ _What alternatives were considered? What constraints exist?_
16
+
17
+ ## Decision
18
+
19
+ _Describe the decision that was made. Key aspects: structure, tools, practices._
20
+ _Include diagrams or schemas if applicable._
21
+
22
+ ## Consequences
23
+
24
+ ### Positive
25
+
26
+ - Benefits of the chosen solution
27
+
28
+ ### Negative
29
+
30
+ - Drawbacks and risks
31
+
32
+ ### Alternatives Considered
33
+
34
+ - Why other options were rejected
35
+
36
+ ## Implementation
37
+
38
+ _What changes after this decision is made? What processes or code need to be updated?_
39
+ _Will this decision be revisited in the future?_
40
+
41
+ ## References
42
+
43
+ - [Discussion / Pull Request](url)
44
+ - [Related ADRs](./0000-other-decision.md)
45
+
46
+ ---
47
+
48
+ **Last Updated:** YYYY-MM-DD
49
+ **Next Review:** YYYY-MM-DD (if scheduled)
50
+
51
+
52
+
@@ -0,0 +1,31 @@
1
+ # ADR-0001: Architecture and Repository Layout
2
+
3
+ **Date:** 2025-09-13
4
+ **Status:** Accepted
5
+ **Deciders:** KB Labs Team
6
+ **Last Reviewed:** 2025-11-03
7
+ **Tags:** [architecture, tooling]
8
+
9
+ ## Context
10
+
11
+ KB Labs products must be consistent across repositories. Each repository should follow the same monorepo-style layout to support apps, packages, and fixtures.
12
+
13
+ ## Decision
14
+
15
+ - Use PNPM workspaces for package management
16
+ - Repository root must contain:
17
+ - `/apps` — example/demo apps or product UI
18
+ - `/packages` — core logic, reusable libraries, domain modules
19
+ - `/fixtures` — sample diffs, test inputs, reference data
20
+ - `/docs` — ADRs, handbook, guides
21
+ - Shared configs (tsconfig, eslint, prettier, vitest) live in root
22
+
23
+ ## Consequences
24
+
25
+ **Positive:**
26
+ - Consistent developer experience across products
27
+ - Easy onboarding: all repositories look alike
28
+ - Enables cross-product reuse of tools/scripts
29
+
30
+ **Negative:**
31
+ - Initial setup complexity for new repositories
@@ -0,0 +1,44 @@
1
+ # ADR-0002: Plugins and Extensibility
2
+
3
+ **Date:** 2025-09-13
4
+ **Status:** Accepted
5
+ **Deciders:** KB Labs Team
6
+ **Last Reviewed:** 2025-11-03
7
+ **Tags:** [architecture, api]
8
+
9
+ ## Context
10
+
11
+ KB Labs products are designed to be reusable across different stacks, domains, and teams. To ensure long-term scalability, all products (AI Review, AI Docs, AI Tests, etc.) must support a flexible plugin & extension system. Without this, every new feature would require hardcoding into the core, increasing maintenance burden and reducing adaptability.
12
+
13
+ ## Decision
14
+
15
+ - Each KB Labs product must expose a plugin API that allows third-party developers (or other KB Labs packages) to extend behavior without modifying the core
16
+ - The plugin system must be:
17
+ 1. **Isolated** — Plugins run in a sandboxed scope and cannot break the core
18
+ 2. **Composable** — Multiple plugins can be combined in one pipeline
19
+ 3. **Discoverable** — Plugins are registered via a central registry (`plugins/index.ts`) or a configuration file (`.kblabsrc.json`)
20
+ 4. **Typed** — All plugin interfaces must be defined in `@kb-labs/core` using TypeScript types and Zod schemas
21
+ 5. **Cross-product** — The same plugin (e.g., a Slack notifier) can be reused in AI Review, AI Docs, and AI Tests without rewriting
22
+
23
+ ## Examples
24
+
25
+ - **AI Review** — rule providers, LLM strategies, custom output formatters
26
+ - **AI Docs** — content generators, format exporters (Markdown, HTML, Confluence)
27
+ - **AI Tests** — test strategy plugins, snapshot comparators
28
+ - **Shared** — analytics/logging, secret providers, budget control
29
+
30
+ ## Consequences
31
+
32
+ **Positive:**
33
+ - Easier to onboard contributors: they extend via plugins instead of modifying the core
34
+ - Ensures product consistency: every KB Labs product has the same extensibility model
35
+ - Avoids long-term lock-in
36
+
37
+ **Negative:**
38
+ - Core complexity increases slightly
39
+ - Additional abstraction layer to maintain
40
+
41
+ ## Alternatives Considered
42
+
43
+ - **Hardcoded integrations** — rejected (not scalable, not reusable)
44
+ - **Separate extension repositories** — rejected (too fragmented, harder to maintain)
@@ -0,0 +1,35 @@
1
+ # ADR-0003: Package and Module Boundaries
2
+
3
+ **Date:** 2025-09-13
4
+ **Status:** Accepted
5
+ **Deciders:** KB Labs Team
6
+ **Last Reviewed:** 2025-11-03
7
+ **Tags:** [architecture, process]
8
+
9
+ ## Context
10
+
11
+ Products in KB Labs often require multiple internal packages. Without strict boundaries, cross-dependencies can grow messy and unmaintainable.
12
+
13
+ ## Decision
14
+
15
+ - Every package under `/packages` must define:
16
+ - `src/` — implementation
17
+ - `index.ts` — public entry point
18
+ - `types/` — exported types & schemas
19
+ - Packages must only depend on public exports of other packages
20
+ - Cross-package imports must use workspace aliases (`@kb-labs/<pkg>`)
21
+ - Domain rules:
22
+ - Core logic in `@kb-labs/core`
23
+ - Product-specific code in `@kb-labs/<product>`
24
+ - Experimental code → feature packages, not core
25
+
26
+ ## Consequences
27
+
28
+ **Positive:**
29
+ - Prevents tight coupling
30
+ - Core remains minimal and reusable
31
+ - Easier to extract packages as standalone OSS later
32
+
33
+ **Negative:**
34
+ - Requires discipline to maintain boundaries
35
+ - More complex dependency management
@@ -0,0 +1,36 @@
1
+ # ADR-0004: Versioning and Release Policy
2
+
3
+ **Date:** 2025-09-13
4
+ **Status:** Accepted
5
+ **Deciders:** KB Labs Team
6
+ **Last Reviewed:** 2025-11-03
7
+ **Tags:** [process, deployment]
8
+
9
+ ## Context
10
+
11
+ The KB Labs ecosystem must stay consistent, while still allowing individual products to evolve.
12
+
13
+ ## Decision
14
+
15
+ - Use Semantic Versioning (SemVer) for all published packages
16
+ - Core (`@kb-labs/core`) follows stricter rules:
17
+ - **MAJOR:** breaking changes in APIs/schemas
18
+ - **MINOR:** new features, backward-compatible
19
+ - **PATCH:** bugfixes
20
+ - Products (`ai-review`, `ai-docs`, `ai-tests`, etc.) can release independently, but must pin to compatible core versions
21
+ - Changelog generation automated via changesets or `@kb-labs/changelog-generator`
22
+ - Release flow:
23
+ 1. Pull request → CI check (lint, type-check, test)
24
+ 2. Merge → changeset entry created
25
+ 3. Release pipeline tags version, publishes to npm, updates changelog
26
+
27
+ ## Consequences
28
+
29
+ **Positive:**
30
+ - Predictable updates across ecosystem
31
+ - Users know when breaking changes occur
32
+ - Easy adoption of multiple products without fear of hidden breakage
33
+
34
+ **Negative:**
35
+ - Requires careful coordination for major releases
36
+ - More complex release automation setup
@@ -0,0 +1,179 @@
1
+ # ADR-0005: Reactive Loader Pattern for CLI Spinners
2
+
3
+ **Date:** 2025-12-13
4
+ **Status:** Accepted
5
+ **Deciders:** KB Labs Team
6
+ **Last Reviewed:** 2025-12-13
7
+ **Tags:** [ui, architecture, performance, simplicity]
8
+
9
+ ## Context
10
+
11
+ CLI loaders (spinners) need to update text dynamically while maintaining a single-line animation. The original implementation had issues:
12
+
13
+ 1. **Animation duplication** - When updating text, multiple lines appeared instead of a single updating line
14
+ 2. **Complex control flow** - Stopping and restarting `setInterval` on each update added unnecessary complexity
15
+ 3. **Performance overhead** - Clearing intervals and creating new ones every 200ms was wasteful
16
+ 4. **Child process stdout buffering** - In forked child processes, frequent interval restarts could cause buffering issues
17
+
18
+ ### Initial Approach (Problematic)
19
+
20
+ ```typescript
21
+ update(options: Partial<LoaderOptions>): void {
22
+ // Stop current interval
23
+ if (this.intervalId) {
24
+ clearInterval(this.intervalId);
25
+ this.intervalId = undefined;
26
+ }
27
+
28
+ // Update options
29
+ this.options = { ...this.options, ...options };
30
+
31
+ // Restart interval with new text
32
+ this.intervalId = setInterval(() => {
33
+ const text = this.options.text ?? 'Loading...';
34
+ process.stdout.write(`\r${SPINNER_CHARS[frame]} ${text}`);
35
+ }, 200);
36
+ }
37
+ ```
38
+
39
+ **Problems:**
40
+ - ❌ Animation flickers on updates
41
+ - ❌ Interval restart overhead every update
42
+ - ❌ Race conditions between stop/start
43
+ - ❌ Line duplication in child processes
44
+
45
+ ## Decision
46
+
47
+ Implement a **reactive variable pattern** (Vue-style) where `setInterval` runs continuously and reads a mutable text variable:
48
+
49
+ ```typescript
50
+ class Loader {
51
+ private currentText: string; // ← Reactive variable
52
+ private intervalId?: NodeJS.Timeout;
53
+
54
+ start(): void {
55
+ this.isActive = true;
56
+
57
+ // Start interval once - reads currentText continuously
58
+ this.intervalId = setInterval(() => {
59
+ if (!this.isActive) {
60
+ this.clearInterval();
61
+ return;
62
+ }
63
+
64
+ const char = SPINNER_CHARS[this.frameIndex % SPINNER_CHARS.length];
65
+ process.stdout.write(`\r${char} ${this.currentText}`); // ← Read reactive text
66
+ this.frameIndex++;
67
+ }, 200);
68
+ }
69
+
70
+ update(options: Partial<LoaderOptions>): void {
71
+ this.options = { ...this.options, ...options };
72
+
73
+ // Just update the variable - setInterval picks it up on next tick!
74
+ if (options.text !== undefined) {
75
+ this.currentText = options.text; // ← Simple variable assignment
76
+ }
77
+ }
78
+ }
79
+ ```
80
+
81
+ **Key insight:** `setInterval` callback has closure access to `this.currentText`. When we update the variable, the next interval tick automatically reads the new value - **no restart needed**.
82
+
83
+ ## Consequences
84
+
85
+ ### Positive
86
+
87
+ - ✅ **Single-line animation** - No more line duplication
88
+ - ✅ **Zero overhead updates** - Just variable assignment (O(1) vs interval restart overhead)
89
+ - ✅ **Simple mental model** - "Text is reactive, interval reads it" (Vue-style)
90
+ - ✅ **No race conditions** - No concurrent interval management
91
+ - ✅ **Child process friendly** - Continuous stdout writes work with piping
92
+ - ✅ **Performance** - Eliminates ~50% of interval operations (no stop/start)
93
+
94
+ ### Negative
95
+
96
+ - ⚠️ **Requires understanding closures** - Developers must understand how setInterval captures `this`
97
+ - ⚠️ **Not obvious from API** - `update()` looks like it does nothing, but it's reactive
98
+
99
+ ### Alternatives Considered
100
+
101
+ **1. Message Queue Pattern**
102
+ ```typescript
103
+ private textQueue: string[] = [];
104
+ update(text: string) { this.textQueue.push(text); }
105
+ ```
106
+ ❌ Rejected: Adds complexity, doesn't solve fundamental issue
107
+
108
+ **2. requestAnimationFrame (browser-style)**
109
+ ❌ Rejected: Not available in Node.js
110
+
111
+ **3. Observable/RxJS**
112
+ ❌ Rejected: Overkill dependency for simple text updates
113
+
114
+ **4. Event Emitter**
115
+ ```typescript
116
+ private emitter = new EventEmitter();
117
+ update(text: string) { this.emitter.emit('text', text); }
118
+ ```
119
+ ❌ Rejected: More complex than needed, adds event listener overhead
120
+
121
+ ## Implementation
122
+
123
+ ### Files Changed
124
+
125
+ 1. **`kb-labs-shared/packages/shared-cli-ui/src/loader.ts`**
126
+ - Added `private currentText: string` reactive variable
127
+ - Modified `start()` to read `currentText` in interval callback
128
+ - Simplified `update()` to just assign `currentText`
129
+
130
+ 2. **`kb-labs-sdk/packages/sdk/src/ui.ts`**
131
+ - Exported `useLoader` hook for plugin consumption
132
+
133
+ 3. **`kb-labs-plugin/packages/plugin-runtime/src/presenter/presenter-facade.ts`**
134
+ - Removed `spinner()` method from UIFacade interface
135
+
136
+ ### Migration Guide
137
+
138
+ **Before (deprecated):**
139
+ ```typescript
140
+ const spinner = ctx.ui.spinner('Loading...');
141
+ spinner.start();
142
+ spinner.update({ text: 'Processing...' }); // ❌ Stop/restart interval
143
+ spinner.succeed('Done!');
144
+ ```
145
+
146
+ **After (recommended):**
147
+ ```typescript
148
+ import { useLoader } from '@kb-labs/sdk';
149
+
150
+ const loader = useLoader('Loading...');
151
+ loader.start();
152
+ loader.update({ text: 'Processing...' }); // ✅ Just update reactive variable
153
+ loader.succeed('Done!');
154
+ ```
155
+
156
+ ### Testing
157
+
158
+ Verified with `plugin-template:test-loader` command:
159
+ - ✅ Single continuous loader (4 updates in 2s) - single line, no duplication
160
+ - ✅ Multi-stage progress (3 stages × 4 updates) - clean stage transitions
161
+ - ✅ Rapid updates (10 updates in 100ms) - smooth animation
162
+ - ✅ Child process execution (verified via PID logging)
163
+
164
+ ### Future Considerations
165
+
166
+ - Consider TypeScript `readonly` modifier to document reactive variables
167
+ - Add JSDoc comment explaining reactive pattern
168
+ - Benchmark memory usage vs previous implementation (expected: identical)
169
+
170
+ ## References
171
+
172
+ - [Vue.js Reactivity Fundamentals](https://vuejs.org/guide/essentials/reactivity-fundamentals.html) - Inspiration for pattern
173
+ - Implementation: `kb-labs-shared/packages/shared-cli-ui/src/loader.ts`
174
+ - Test: `kb-labs-plugin-template/packages/plugin-template-core/src/cli/commands/test-loader.ts`
175
+
176
+ ---
177
+
178
+ **Last Updated:** 2025-12-13
179
+ **Next Review:** 2026-01-13 (1 month - verify no regressions)