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