@kb-labs/cli-commands 1.0.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/README.md ADDED
@@ -0,0 +1,253 @@
1
+ # @kb-labs/cli-commands
2
+
3
+ > **Command implementations for KB Labs CLI.** Contains command implementations and registry system for KB Labs CLI with plugin-based architecture, command discovery, execution, and help generation.
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+ [![Node.js](https://img.shields.io/badge/Node.js-18.18.0+-green.svg)](https://nodejs.org/)
7
+ [![pnpm](https://img.shields.io/badge/pnpm-9.0.0+-orange.svg)](https://pnpm.io/)
8
+
9
+ ## 🎯 Vision & Purpose
10
+
11
+ **@kb-labs/cli-commands** provides command implementations and registry system for KB Labs CLI. It includes plugin-based command architecture, command discovery, execution, help generation, and built-in system commands.
12
+
13
+ ## 🏗️ Architecture
14
+
15
+ ### Core Components
16
+
17
+ #### Command Registry
18
+
19
+ - **Purpose**: Discover and register commands
20
+ - **Responsibilities**: Plugin discovery, manifest validation, command registration
21
+ - **Dependencies**: cli-core, plugin-manifest
22
+
23
+ #### Command Execution
24
+
25
+ - **Purpose**: Execute commands
26
+ - **Responsibilities**: Command routing, handler execution, error handling
27
+ - **Dependencies**: Registry, cli-core
28
+
29
+ #### Help Generation
30
+
31
+ - **Purpose**: Generate help output
32
+ - **Responsibilities**: Global help, group help, manifest help
33
+ - **Dependencies**: Registry
34
+
35
+ ### Design Patterns
36
+
37
+ - **Registry Pattern**: Command registry
38
+ - **Plugin Pattern**: Plugin-based commands
39
+ - **Strategy Pattern**: Multiple discovery strategies
40
+ - **Command Pattern**: Command execution
41
+
42
+ ### Data Flow
43
+
44
+ ```
45
+ CLI Entry Point
46
+
47
+ ├──► Discover plugins
48
+ ├──► Register commands
49
+ ├──► Parse arguments
50
+ ├──► Find command
51
+ ├──► Execute command
52
+ └──► Return result
53
+ ```
54
+
55
+ ## 🚀 Quick Start
56
+
57
+ ### Installation
58
+
59
+ ```bash
60
+ pnpm add @kb-labs/cli-commands
61
+ ```
62
+
63
+ ### Basic Usage
64
+
65
+ ```typescript
66
+ import { discoverManifests, registerCommands } from '@kb-labs/cli-commands';
67
+
68
+ const manifests = await discoverManifests(process.cwd());
69
+ const registry = await registerCommands(manifests);
70
+ ```
71
+
72
+ ## ✨ Features
73
+
74
+ ```
75
+ kb-labs-cli/packages/commands/src/
76
+ ├── registry/ # Plugin discovery and registration
77
+ │ ├── types.ts # All interfaces
78
+ │ ├── availability.ts # ESM-safe dependency resolution
79
+ │ ├── discover.ts # Workspace + node_modules discovery
80
+ │ ├── register.ts # Manifest validation and shadowing
81
+ │ ├── run.ts # Command execution
82
+ │ └── __tests__/ # Comprehensive test suite
83
+ ├── builtins/ # Built-in commands (legacy)
84
+ └── utils/ # Utilities (logger, path helpers)
85
+ ```
86
+
87
+ ### Plugin Manifest v2
88
+
89
+ Commands ship as part of plugin manifests declared via ManifestV2:
90
+
91
+ ```typescript
92
+ // packages/my-plugin/src/kb/manifest.ts
93
+ import type { ManifestV2 } from '@kb-labs/plugin-manifest';
94
+
95
+ export const manifest: ManifestV2 = {
96
+ schema: 'kb.plugin/2',
97
+ id: '@kb-labs/my-plugin',
98
+ version: '0.1.0',
99
+ display: {
100
+ name: 'My Plugin',
101
+ description: 'Example plugin command set',
102
+ },
103
+ permissions: {
104
+ fs: { mode: 'read', allow: ['.'] },
105
+ },
106
+ cli: {
107
+ commands: [
108
+ {
109
+ id: 'my:command',
110
+ group: 'my',
111
+ describe: 'My command description',
112
+ handler: './commands/command#run',
113
+ flags: [],
114
+ },
115
+ ],
116
+ },
117
+ };
118
+ ```
119
+
120
+ The CLI registry converts these declarations into internal command manifests during discovery.
121
+
122
+ ### Package.json Configuration
123
+
124
+ ```json
125
+ {
126
+ "name": "@kb-labs/my-plugin",
127
+ "exports": {
128
+ "./kb/manifest": "./dist/kb/manifest.js"
129
+ },
130
+ "kb": {
131
+ "plugin": true,
132
+ "manifest": "./dist/kb/manifest.js"
133
+ }
134
+ }
135
+ ```
136
+
137
+ ## Global Flags
138
+
139
+ All commands receive these global flags regardless of their own flag definitions:
140
+
141
+ - `--json` - JSON output mode
142
+ - `--only-available` - Filter unavailable commands (help only)
143
+ - `--no-cache` - Force discovery refresh
144
+ - `--verbose` - Detailed output
145
+ - `--quiet` - Minimal output
146
+ - `--help` - Show help
147
+ - `--version` - Show version
148
+
149
+ These flags are guaranteed to be passed through to all commands.
150
+
151
+ ## Exit Codes
152
+
153
+ - **0** - Success
154
+ - **1** - Command error / invalid module
155
+ - **2** - Command unavailable (missing dependencies)
156
+
157
+ In `--json` mode with exit code 2:
158
+ ```json
159
+ {
160
+ "ok": false,
161
+ "available": false,
162
+ "command": "my:command",
163
+ "reason": "Missing dependency: @kb-labs/some-dependency",
164
+ "hint": "Run: kb devlink apply"
165
+ }
166
+ ```
167
+
168
+ ## Logging
169
+
170
+ The CLI respects the `KB_LOG_LEVEL` environment variable:
171
+
172
+ - `silent` - No output
173
+ - `error` - Error messages only
174
+ - `warn` - Warnings and errors (default)
175
+ - `info` - Informational messages
176
+ - `debug` - Debug information
177
+
178
+ All diagnostic output goes to `stderr`, leaving `stdout` free for command output.
179
+
180
+ ## Discovery Process
181
+
182
+ 1. **Workspace Discovery**: Scans `pnpm-workspace.yaml` for packages exposing `./kb/manifest` via exports or `kb.manifest`.
183
+ 2. **Node Modules Discovery**: Looks through installed packages for ManifestV2 files.
184
+ 3. **Explicit Paths**: Follows linked directories and CLI-provided manifest paths.
185
+ 4. **Shadowing**: Workspace packages shadow node_modules packages.
186
+ 5. **Caching**: Results are cached in memory (and optional adapters) for fast startup.
187
+
188
+ ## Command Execution
189
+
190
+ Commands execute inside the plugin sandbox:
191
+
192
+ 1. Validate ManifestV2 metadata and permissions.
193
+ 2. Check availability and granted permissions.
194
+ 3. Execute via `@kb-labs/plugin-adapter-cli` (sandbox runtime).
195
+ 4. Record telemetry and return the exit code.
196
+
197
+ ## Diagnostics
198
+
199
+ Use `kb plugins list` to see all discovered commands with their status:
200
+
201
+ - Available/unavailable status
202
+ - Source (workspace/node_modules/builtin)
203
+ - Shadowing information
204
+ - Missing dependency reasons and hints
205
+
206
+ ## Development
207
+
208
+ ### Running Tests
209
+
210
+ ```bash
211
+ pnpm test
212
+ ```
213
+
214
+ ### Building
215
+
216
+ ```bash
217
+ pnpm build
218
+ ```
219
+
220
+ ### Adding New Commands
221
+
222
+ 1. Run `kb plugins scaffold my-plugin` to generate a manifest v2 skeleton.
223
+ 2. Implement your command handler in `src/commands/<name>.ts`.
224
+ 3. Update manifest permissions and metadata as needed.
225
+ 4. Build your package and test with `kb plugins list`.
226
+
227
+ ## Migration from Legacy Commands
228
+
229
+ Legacy command groups are being converted to manifest format:
230
+
231
+ 1. **Built-in Commands**: Converted to manifest format in `builtins/`
232
+ 2. **Product Commands**: Moved to their respective packages
233
+ 3. **System Commands**: Available as standalone commands
234
+
235
+ The registry system maintains backward compatibility during the transition.
236
+
237
+ ## 🔧 Configuration
238
+
239
+ ### Configuration Options
240
+
241
+ No global configuration needed. Commands are discovered automatically.
242
+
243
+ ### Environment Variables
244
+
245
+ - `KB_LOG_LEVEL`: Logging level (`silent`, `error`, `warn`, `info`, `debug`)
246
+
247
+ ## 🤝 Contributing
248
+
249
+ See [CONTRIBUTING.md](../../CONTRIBUTING.md) for development guidelines.
250
+
251
+ ## 📄 License
252
+
253
+ KB Public License v1.1 © KB Labs
@@ -0,0 +1,292 @@
1
+ import { ManifestV3 } from '@kb-labs/plugin-contracts';
2
+ import { Logger } from '@kb-labs/cli-core';
3
+ export { TimingTracker } from '@kb-labs/shared-cli-ui';
4
+ import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
5
+
6
+ /**
7
+ * @kb-labs/cli-commands/registry
8
+ * Type definitions for the plugin system
9
+ */
10
+
11
+ interface CommandManifest {
12
+ manifestVersion: '1.0';
13
+ id: string;
14
+ aliases?: string[];
15
+ group: string;
16
+ describe: string;
17
+ longDescription?: string;
18
+ requires?: string[];
19
+ flags?: FlagDefinition[];
20
+ examples?: string[];
21
+ loader?: () => Promise<CommandModule>;
22
+ package?: string;
23
+ namespace?: string;
24
+ engine?: {
25
+ node?: string;
26
+ kbCli?: string;
27
+ module?: 'esm' | 'cjs';
28
+ };
29
+ permissions?: string[];
30
+ telemetry?: 'opt-in' | 'off';
31
+ manifestV2?: ManifestV3;
32
+ }
33
+ interface FlagDefinition {
34
+ name: string;
35
+ type: "string" | "boolean" | "number" | "array";
36
+ alias?: string;
37
+ default?: any;
38
+ description?: string;
39
+ describe?: string;
40
+ choices?: string[];
41
+ required?: boolean;
42
+ examples?: string[];
43
+ }
44
+ interface RegisteredCommand {
45
+ manifest: CommandManifest;
46
+ v3Manifest?: ManifestV3;
47
+ available: boolean;
48
+ unavailableReason?: string;
49
+ hint?: string;
50
+ source: 'workspace' | 'node_modules' | 'linked' | 'builtin';
51
+ shadowed: boolean;
52
+ pkgRoot?: string;
53
+ packageName?: string;
54
+ }
55
+ interface CommandModule {
56
+ run: (ctx: any, argv: string[], flags: Record<string, any>) => Promise<number | void>;
57
+ }
58
+ interface DiscoveryResult {
59
+ source: 'workspace' | 'node_modules' | 'linked' | 'builtin';
60
+ packageName: string;
61
+ manifestPath: string;
62
+ pkgRoot: string;
63
+ manifests: CommandManifest[];
64
+ }
65
+ interface GlobalFlags {
66
+ json?: boolean;
67
+ onlyAvailable?: boolean;
68
+ noCache?: boolean;
69
+ verbose?: boolean;
70
+ quiet?: boolean;
71
+ help?: boolean;
72
+ version?: boolean;
73
+ dryRun?: boolean;
74
+ }
75
+ interface PackageCacheEntry {
76
+ version: string;
77
+ manifestHash: string;
78
+ manifestPath: string;
79
+ pkgJsonMtime: number;
80
+ manifestMtime: number;
81
+ cachedAt: number;
82
+ result: DiscoveryResult;
83
+ }
84
+ interface CacheFile {
85
+ version: string;
86
+ cliVersion: string;
87
+ timestamp: number;
88
+ ttlMs?: number;
89
+ stateHash?: string;
90
+ lockfileHash?: string;
91
+ configHash?: string;
92
+ pluginsStateHash?: string;
93
+ packages: Record<string, PackageCacheEntry>;
94
+ }
95
+ type AvailabilityCheck = {
96
+ available: true;
97
+ } | {
98
+ available: false;
99
+ reason: string;
100
+ hint?: string;
101
+ };
102
+
103
+ /**
104
+ * Legacy V2 types for backward compatibility
105
+ * These types were removed from cli-contracts but are still needed
106
+ * for the adapter layer in service.ts
107
+ */
108
+
109
+ interface CommandRun {
110
+ (ctx: any, argv: string[], flags: Record<string, any>): Promise<number | void>;
111
+ }
112
+ interface Command {
113
+ name: string;
114
+ category?: string;
115
+ describe: string;
116
+ longDescription?: string;
117
+ aliases?: string[];
118
+ flags?: FlagDefinition[];
119
+ examples?: string[];
120
+ run: CommandRun;
121
+ }
122
+ interface CommandGroup {
123
+ name: string;
124
+ describe?: string;
125
+ commands: Command[];
126
+ }
127
+ interface CommandRegistry {
128
+ register(cmd: Command): void;
129
+ registerGroup(group: CommandGroup): void;
130
+ registerManifest(cmd: any): void;
131
+ list(): Command[];
132
+ listGroups(): CommandGroup[];
133
+ listManifests(): any[];
134
+ markPartial(isPartial: boolean): void;
135
+ isPartial(): boolean;
136
+ }
137
+
138
+ interface ProductGroup {
139
+ name: string;
140
+ describe?: string;
141
+ commands: RegisteredCommand[];
142
+ }
143
+ type CommandType = 'system' | 'plugin';
144
+ interface CommandLookupResult {
145
+ cmd: Command | CommandGroup;
146
+ type: CommandType;
147
+ }
148
+ declare class InMemoryRegistry implements CommandRegistry {
149
+ private systemCommands;
150
+ private pluginCommands;
151
+ private byName;
152
+ private groups;
153
+ private manifests;
154
+ private partial;
155
+ register(cmd: Command): void;
156
+ registerGroup(group: CommandGroup): void;
157
+ registerManifest(cmd: RegisteredCommand): void;
158
+ markPartial(partial: boolean): void;
159
+ isPartial(): boolean;
160
+ getManifest(id: string): RegisteredCommand | undefined;
161
+ listManifests(): RegisteredCommand[];
162
+ has(name: string): boolean;
163
+ /**
164
+ * Get command with type information for secure routing
165
+ *
166
+ * Returns type='system' for commands from registerGroup() - execute in-process
167
+ * Returns type='plugin' for commands from registerManifest() - execute in subprocess
168
+ *
169
+ * This separation prevents malicious plugins from escaping the sandbox.
170
+ */
171
+ getWithType(nameOrPath: string | string[]): CommandLookupResult | undefined;
172
+ get(nameOrPath: string | string[]): Command | CommandGroup | undefined;
173
+ list(): Command[];
174
+ listGroups(): CommandGroup[];
175
+ getGroupsByPrefix(prefix: string): CommandGroup[];
176
+ getCommandsByGroupPrefix(prefix: string): Command[];
177
+ listProductGroups(): ProductGroup[];
178
+ getCommandsByGroup(group: string): RegisteredCommand[];
179
+ getManifestCommand(idOrAlias: string): RegisteredCommand | undefined;
180
+ }
181
+ declare const registry: InMemoryRegistry;
182
+ declare function findCommand(nameOrPath: string | string[]): Command | CommandGroup | undefined;
183
+ /**
184
+ * Find command with type information for secure routing
185
+ *
186
+ * Use this in bootstrap.ts to determine execution path:
187
+ * - type='system' → execute via cmd.run() in-process
188
+ * - type='plugin' → execute via tryExecuteV3() in subprocess
189
+ */
190
+ declare function findCommandWithType(nameOrPath: string | string[]): CommandLookupResult | undefined;
191
+
192
+ interface RegisterBuiltinCommandsInput {
193
+ cwd?: string;
194
+ env?: NodeJS.ProcessEnv;
195
+ logger?: Logger;
196
+ }
197
+ declare function registerBuiltinCommands(input?: RegisterBuiltinCommandsInput): Promise<void>;
198
+
199
+ declare function renderGroupHelp(group: CommandGroup): string;
200
+
201
+ declare function renderGlobalHelp(groups: ProductGroup[], standalone: Command[]): string;
202
+ declare function renderGlobalHelpNew(registry: {
203
+ listProductGroups(): ProductGroup[];
204
+ list(): Command[];
205
+ listGroups?(): CommandGroup[];
206
+ }): string;
207
+ declare function renderPluginsHelp(registry: {
208
+ list(): Command[];
209
+ }): string;
210
+
211
+ declare function renderProductHelp(groupName: string, commands: RegisteredCommand[]): string;
212
+
213
+ declare function renderManifestCommandHelp(registered: RegisteredCommand): string;
214
+
215
+ interface RenderHelpOptions {
216
+ json: boolean;
217
+ onlyAvailable: boolean;
218
+ version?: string;
219
+ }
220
+ declare function renderHelp(commands: RegisteredCommand[], options: RenderHelpOptions): string | Record<string, unknown>;
221
+
222
+ /**
223
+ * Generate command examples
224
+ * Simple helper to format command examples for CLI commands
225
+ */
226
+ interface ExampleCase {
227
+ flags: Record<string, unknown>;
228
+ description?: string;
229
+ }
230
+ declare function generateExamples(commandName: string, productName: string, cases: ExampleCase[]): string[];
231
+
232
+ /**
233
+ * @kb-labs/cli-commands/registry
234
+ * Command manifest discovery - workspace, node_modules, current package
235
+ */
236
+
237
+ /**
238
+ * Main discovery function
239
+ * Discovers command manifests from workspace, current package, and node_modules
240
+ */
241
+ declare function discoverManifests(cwd: string, noCache?: boolean): Promise<DiscoveryResult[]>;
242
+ /**
243
+ * Lazy load manifests for a specific namespace
244
+ * Only loads manifests from packages matching the namespace
245
+ */
246
+ declare function discoverManifestsByNamespace(cwd: string, namespace: string, noCache?: boolean): Promise<DiscoveryResult[]>;
247
+
248
+ declare const hello: _kb_labs_shared_command_kit.Command;
249
+
250
+ declare const health: _kb_labs_shared_command_kit.Command;
251
+
252
+ declare const version: _kb_labs_shared_command_kit.Command;
253
+
254
+ /**
255
+ * logs diagnose — "What went wrong?" Automated error analysis.
256
+ * Agent-first command: single call gives a full diagnostic report.
257
+ */
258
+ declare const logsDiagnose: _kb_labs_shared_command_kit.Command;
259
+
260
+ /**
261
+ * logs context — Show full timeline for an execution/trace/request.
262
+ * Agent-first: "What happened in this workflow run?"
263
+ */
264
+ declare const logsContext: _kb_labs_shared_command_kit.Command;
265
+
266
+ /**
267
+ * logs summarize — AI-powered log analysis.
268
+ * Agent-first: ask a natural-language question about logs.
269
+ */
270
+ declare const logsSummarize: _kb_labs_shared_command_kit.Command;
271
+
272
+ /**
273
+ * logs query — Query logs with filters and pagination
274
+ */
275
+ declare const logsQuery: _kb_labs_shared_command_kit.Command;
276
+
277
+ /**
278
+ * logs search — Full-text search across logs (FTS5)
279
+ */
280
+ declare const logsSearch: _kb_labs_shared_command_kit.Command;
281
+
282
+ /**
283
+ * logs get — Get single log by ID with optional related logs
284
+ */
285
+ declare const logsGet: _kb_labs_shared_command_kit.Command;
286
+
287
+ /**
288
+ * logs stats — Show log storage statistics and capabilities
289
+ */
290
+ declare const logsStats: _kb_labs_shared_command_kit.Command;
291
+
292
+ export { type AvailabilityCheck, type CacheFile, type CommandLookupResult, type CommandManifest, type CommandModule, type CommandType, type DiscoveryResult, type ExampleCase, type FlagDefinition, type GlobalFlags, type PackageCacheEntry, type ProductGroup, type RegisteredCommand, discoverManifests, discoverManifestsByNamespace, findCommand, findCommandWithType, generateExamples, health, hello, logsContext, logsDiagnose, logsGet, logsQuery, logsSearch, logsStats, logsSummarize, registerBuiltinCommands, registry, renderGlobalHelp, renderGlobalHelpNew, renderGroupHelp, renderHelp, renderManifestCommandHelp, renderPluginsHelp, renderProductHelp, version };