@kb-labs/cli-commands 2.4.0 → 2.5.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.
@@ -0,0 +1,234 @@
1
+ import { ManifestV3 } from '@kb-labs/plugin-contracts';
2
+
3
+ /**
4
+ * @kb-labs/cli-commands/registry
5
+ * Type definitions for the plugin system
6
+ */
7
+
8
+ interface CommandManifest {
9
+ manifestVersion: '1.0';
10
+ id: string;
11
+ aliases?: string[];
12
+ group: string;
13
+ subgroup?: string;
14
+ describe: string;
15
+ longDescription?: string;
16
+ requires?: string[];
17
+ flags?: FlagDefinition[];
18
+ examples?: string[];
19
+ loader?: () => Promise<CommandModule>;
20
+ package?: string;
21
+ namespace?: string;
22
+ engine?: {
23
+ node?: string;
24
+ kbCli?: string;
25
+ module?: 'esm' | 'cjs';
26
+ };
27
+ permissions?: string[];
28
+ telemetry?: 'opt-in' | 'off';
29
+ manifestV2?: ManifestV3;
30
+ }
31
+ interface FlagDefinition {
32
+ name: string;
33
+ type: "string" | "boolean" | "number" | "array";
34
+ alias?: string;
35
+ default?: any;
36
+ description?: string;
37
+ describe?: string;
38
+ choices?: string[];
39
+ required?: boolean;
40
+ examples?: string[];
41
+ }
42
+ interface RegisteredCommand {
43
+ manifest: CommandManifest;
44
+ v3Manifest?: ManifestV3;
45
+ available: boolean;
46
+ unavailableReason?: string;
47
+ hint?: string;
48
+ source: 'workspace' | 'node_modules' | 'linked' | 'builtin';
49
+ shadowed: boolean;
50
+ pkgRoot?: string;
51
+ packageName?: string;
52
+ }
53
+ interface CommandModule {
54
+ run: (ctx: any, argv: string[], flags: Record<string, any>) => Promise<number | void>;
55
+ }
56
+ interface DiscoveryResult {
57
+ source: 'workspace' | 'node_modules' | 'linked' | 'builtin';
58
+ packageName: string;
59
+ manifestPath: string;
60
+ pkgRoot: string;
61
+ manifests: CommandManifest[];
62
+ }
63
+ interface GlobalFlags {
64
+ json?: boolean;
65
+ onlyAvailable?: boolean;
66
+ noCache?: boolean;
67
+ verbose?: boolean;
68
+ quiet?: boolean;
69
+ help?: boolean;
70
+ version?: boolean;
71
+ dryRun?: boolean;
72
+ }
73
+ interface PackageCacheEntry {
74
+ version: string;
75
+ manifestHash: string;
76
+ manifestPath: string;
77
+ pkgJsonMtime: number;
78
+ manifestMtime: number;
79
+ cachedAt: number;
80
+ result: DiscoveryResult;
81
+ }
82
+ interface CacheFile {
83
+ version: string;
84
+ cliVersion: string;
85
+ timestamp: number;
86
+ ttlMs?: number;
87
+ stateHash?: string;
88
+ lockfileHash?: string;
89
+ configHash?: string;
90
+ pluginsStateHash?: string;
91
+ packages: Record<string, PackageCacheEntry>;
92
+ }
93
+ type AvailabilityCheck = {
94
+ available: true;
95
+ } | {
96
+ available: false;
97
+ reason: string;
98
+ hint?: string;
99
+ };
100
+
101
+ /**
102
+ * Legacy V2 types for backward compatibility
103
+ * These types were removed from cli-contracts but are still needed
104
+ * for the adapter layer in service.ts
105
+ */
106
+
107
+ interface CommandRun {
108
+ (ctx: any, argv: string[], flags: Record<string, any>): Promise<number | void>;
109
+ }
110
+ interface Command {
111
+ name: string;
112
+ category?: string;
113
+ describe: string;
114
+ longDescription?: string;
115
+ aliases?: string[];
116
+ flags?: FlagDefinition[];
117
+ examples?: string[];
118
+ run: CommandRun;
119
+ }
120
+ interface CommandGroup {
121
+ name: string;
122
+ describe?: string;
123
+ commands: Command[];
124
+ subgroups?: CommandGroup[];
125
+ }
126
+ interface CommandRegistry {
127
+ register(cmd: Command): void;
128
+ registerGroup(group: CommandGroup): void;
129
+ registerManifest(cmd: any): void;
130
+ list(): Command[];
131
+ listGroups(): CommandGroup[];
132
+ listManifests(): any[];
133
+ markPartial(isPartial: boolean): void;
134
+ isPartial(): boolean;
135
+ }
136
+
137
+ interface ProductGroup {
138
+ name: string;
139
+ describe?: string;
140
+ commands: RegisteredCommand[];
141
+ }
142
+ type CommandType = 'system' | 'plugin';
143
+ interface CommandLookupResult {
144
+ cmd: Command | CommandGroup;
145
+ type: CommandType;
146
+ }
147
+ declare class InMemoryRegistry implements CommandRegistry {
148
+ private systemCommands;
149
+ private pluginCommands;
150
+ private byName;
151
+ private groups;
152
+ private manifests;
153
+ private partial;
154
+ register(cmd: Command): void;
155
+ registerGroup(group: CommandGroup): void;
156
+ registerManifest(cmd: RegisteredCommand): void;
157
+ markPartial(partial: boolean): void;
158
+ isPartial(): boolean;
159
+ getManifest(id: string): RegisteredCommand | undefined;
160
+ listManifests(): RegisteredCommand[];
161
+ has(name: string): boolean;
162
+ /**
163
+ * Get command with type information for secure routing
164
+ *
165
+ * Returns type='system' for commands from registerGroup() - execute in-process
166
+ * Returns type='plugin' for commands from registerManifest() - execute in subprocess
167
+ *
168
+ * This separation prevents malicious plugins from escaping the sandbox.
169
+ */
170
+ getWithType(nameOrPath: string | string[]): CommandLookupResult | undefined;
171
+ get(nameOrPath: string | string[]): Command | CommandGroup | undefined;
172
+ list(): Command[];
173
+ listGroups(): CommandGroup[];
174
+ getGroupsByPrefix(prefix: string): CommandGroup[];
175
+ getCommandsByGroupPrefix(prefix: string): Command[];
176
+ listProductGroups(): ProductGroup[];
177
+ getCommandsByGroup(group: string): RegisteredCommand[];
178
+ getManifestCommand(idOrAlias: string): RegisteredCommand | undefined;
179
+ }
180
+ declare const registry: InMemoryRegistry;
181
+ declare function findCommand(nameOrPath: string | string[]): Command | CommandGroup | undefined;
182
+ /**
183
+ * Find command with type information for secure routing
184
+ *
185
+ * Use this in bootstrap.ts to determine execution path:
186
+ * - type='system' → execute via cmd.run() in-process
187
+ * - type='plugin' → execute via executePlugin() in plugin-executor
188
+ */
189
+ declare function findCommandWithType(nameOrPath: string | string[]): CommandLookupResult | undefined;
190
+
191
+ /**
192
+ * @kb-labs/cli-commands/registry
193
+ * Command manifest discovery - workspace, node_modules, current package
194
+ */
195
+
196
+ /**
197
+ * Create loader stub for ManifestV3 commands.
198
+ * Loader should never be executed directly – CLI adapters must handle execution.
199
+ */
200
+ declare function createManifestV3Loader(commandId: string): () => Promise<{
201
+ run: any;
202
+ }>;
203
+ /**
204
+ * Ensure manifest has loader function (rehydrate after JSON serialization).
205
+ */
206
+ declare function ensureManifestLoader(manifest: CommandManifest): void;
207
+ declare const __test: {
208
+ ensureManifestLoader: typeof ensureManifestLoader;
209
+ createManifestV3Loader: typeof createManifestV3Loader;
210
+ };
211
+ /**
212
+ * Main discovery function — discovers command manifests from workspace,
213
+ * current package, and `node_modules`.
214
+ *
215
+ * @param cwd Project cwd. Used for workspace discovery (monorepo dev mode)
216
+ * and for the disk cache location.
217
+ * @param noCache Bypass both the in-process and disk caches.
218
+ * @param options Extra options:
219
+ * - `platformRoot`: When provided, `discoverNodeModules` scans
220
+ * `<platformRoot>/node_modules` instead of `<cwd>/node_modules`. This is
221
+ * required in installed mode, where the KB Labs platform lives in a
222
+ * different directory from the user's project. In dev mode `platformRoot`
223
+ * typically equals `cwd` and the two paths coincide.
224
+ */
225
+ declare function discoverManifests(cwd: string, noCache?: boolean, options?: {
226
+ platformRoot?: string;
227
+ }): Promise<DiscoveryResult[]>;
228
+ /**
229
+ * Lazy load manifests for a specific namespace
230
+ * Only loads manifests from packages matching the namespace
231
+ */
232
+ declare function discoverManifestsByNamespace(cwd: string, namespace: string, noCache?: boolean): Promise<DiscoveryResult[]>;
233
+
234
+ export { type AvailabilityCheck as A, type CommandGroup as C, type DiscoveryResult as D, type FlagDefinition as F, type GlobalFlags as G, type ProductGroup as P, type RegisteredCommand as R, __test as _, type Command as a, findCommandWithType as b, type CommandType as c, type CommandLookupResult as d, discoverManifestsByNamespace as e, findCommand as f, discoverManifests as g, type CommandManifest as h, type CommandModule as i, type PackageCacheEntry as j, type CacheFile as k, registry as r };
package/dist/index.d.ts CHANGED
@@ -1,200 +1,22 @@
1
- import { ManifestV3 } from '@kb-labs/plugin-contracts';
1
+ import { C as CommandGroup, P as ProductGroup, a as Command, R as RegisteredCommand } from './discover-8_R7njIS.js';
2
+ export { A as AvailabilityCheck, k as CacheFile, d as CommandLookupResult, h as CommandManifest, i as CommandModule, c as CommandType, D as DiscoveryResult, F as FlagDefinition, G as GlobalFlags, j as PackageCacheEntry, g as discoverManifests, e as discoverManifestsByNamespace, f as findCommand, b as findCommandWithType, r as registry } from './discover-8_R7njIS.js';
2
3
  import { ILogger } from '@kb-labs/core-platform';
3
4
  export { TimingTracker } from '@kb-labs/shared-cli-ui';
4
5
  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
- subgroup?: string;
17
- describe: string;
18
- longDescription?: string;
19
- requires?: string[];
20
- flags?: FlagDefinition[];
21
- examples?: string[];
22
- loader?: () => Promise<CommandModule>;
23
- package?: string;
24
- namespace?: string;
25
- engine?: {
26
- node?: string;
27
- kbCli?: string;
28
- module?: 'esm' | 'cjs';
29
- };
30
- permissions?: string[];
31
- telemetry?: 'opt-in' | 'off';
32
- manifestV2?: ManifestV3;
33
- }
34
- interface FlagDefinition {
35
- name: string;
36
- type: "string" | "boolean" | "number" | "array";
37
- alias?: string;
38
- default?: any;
39
- description?: string;
40
- describe?: string;
41
- choices?: string[];
42
- required?: boolean;
43
- examples?: string[];
44
- }
45
- interface RegisteredCommand {
46
- manifest: CommandManifest;
47
- v3Manifest?: ManifestV3;
48
- available: boolean;
49
- unavailableReason?: string;
50
- hint?: string;
51
- source: 'workspace' | 'node_modules' | 'linked' | 'builtin';
52
- shadowed: boolean;
53
- pkgRoot?: string;
54
- packageName?: string;
55
- }
56
- interface CommandModule {
57
- run: (ctx: any, argv: string[], flags: Record<string, any>) => Promise<number | void>;
58
- }
59
- interface DiscoveryResult {
60
- source: 'workspace' | 'node_modules' | 'linked' | 'builtin';
61
- packageName: string;
62
- manifestPath: string;
63
- pkgRoot: string;
64
- manifests: CommandManifest[];
65
- }
66
- interface GlobalFlags {
67
- json?: boolean;
68
- onlyAvailable?: boolean;
69
- noCache?: boolean;
70
- verbose?: boolean;
71
- quiet?: boolean;
72
- help?: boolean;
73
- version?: boolean;
74
- dryRun?: boolean;
75
- }
76
- interface PackageCacheEntry {
77
- version: string;
78
- manifestHash: string;
79
- manifestPath: string;
80
- pkgJsonMtime: number;
81
- manifestMtime: number;
82
- cachedAt: number;
83
- result: DiscoveryResult;
84
- }
85
- interface CacheFile {
86
- version: string;
87
- cliVersion: string;
88
- timestamp: number;
89
- ttlMs?: number;
90
- stateHash?: string;
91
- lockfileHash?: string;
92
- configHash?: string;
93
- pluginsStateHash?: string;
94
- packages: Record<string, PackageCacheEntry>;
95
- }
96
- type AvailabilityCheck = {
97
- available: true;
98
- } | {
99
- available: false;
100
- reason: string;
101
- hint?: string;
102
- };
103
-
104
- /**
105
- * Legacy V2 types for backward compatibility
106
- * These types were removed from cli-contracts but are still needed
107
- * for the adapter layer in service.ts
108
- */
109
-
110
- interface CommandRun {
111
- (ctx: any, argv: string[], flags: Record<string, any>): Promise<number | void>;
112
- }
113
- interface Command {
114
- name: string;
115
- category?: string;
116
- describe: string;
117
- longDescription?: string;
118
- aliases?: string[];
119
- flags?: FlagDefinition[];
120
- examples?: string[];
121
- run: CommandRun;
122
- }
123
- interface CommandGroup {
124
- name: string;
125
- describe?: string;
126
- commands: Command[];
127
- subgroups?: CommandGroup[];
128
- }
129
- interface CommandRegistry {
130
- register(cmd: Command): void;
131
- registerGroup(group: CommandGroup): void;
132
- registerManifest(cmd: any): void;
133
- list(): Command[];
134
- listGroups(): CommandGroup[];
135
- listManifests(): any[];
136
- markPartial(isPartial: boolean): void;
137
- isPartial(): boolean;
138
- }
139
-
140
- interface ProductGroup {
141
- name: string;
142
- describe?: string;
143
- commands: RegisteredCommand[];
144
- }
145
- type CommandType = 'system' | 'plugin';
146
- interface CommandLookupResult {
147
- cmd: Command | CommandGroup;
148
- type: CommandType;
149
- }
150
- declare class InMemoryRegistry implements CommandRegistry {
151
- private systemCommands;
152
- private pluginCommands;
153
- private byName;
154
- private groups;
155
- private manifests;
156
- private partial;
157
- register(cmd: Command): void;
158
- registerGroup(group: CommandGroup): void;
159
- registerManifest(cmd: RegisteredCommand): void;
160
- markPartial(partial: boolean): void;
161
- isPartial(): boolean;
162
- getManifest(id: string): RegisteredCommand | undefined;
163
- listManifests(): RegisteredCommand[];
164
- has(name: string): boolean;
165
- /**
166
- * Get command with type information for secure routing
167
- *
168
- * Returns type='system' for commands from registerGroup() - execute in-process
169
- * Returns type='plugin' for commands from registerManifest() - execute in subprocess
170
- *
171
- * This separation prevents malicious plugins from escaping the sandbox.
172
- */
173
- getWithType(nameOrPath: string | string[]): CommandLookupResult | undefined;
174
- get(nameOrPath: string | string[]): Command | CommandGroup | undefined;
175
- list(): Command[];
176
- listGroups(): CommandGroup[];
177
- getGroupsByPrefix(prefix: string): CommandGroup[];
178
- getCommandsByGroupPrefix(prefix: string): Command[];
179
- listProductGroups(): ProductGroup[];
180
- getCommandsByGroup(group: string): RegisteredCommand[];
181
- getManifestCommand(idOrAlias: string): RegisteredCommand | undefined;
182
- }
183
- declare const registry: InMemoryRegistry;
184
- declare function findCommand(nameOrPath: string | string[]): Command | CommandGroup | undefined;
185
- /**
186
- * Find command with type information for secure routing
187
- *
188
- * Use this in bootstrap.ts to determine execution path:
189
- * - type='system' → execute via cmd.run() in-process
190
- * - type='plugin' → execute via executePlugin() in plugin-executor
191
- */
192
- declare function findCommandWithType(nameOrPath: string | string[]): CommandLookupResult | undefined;
6
+ import '@kb-labs/plugin-contracts';
193
7
 
194
8
  interface RegisterBuiltinCommandsInput {
195
9
  cwd?: string;
196
10
  env?: NodeJS.ProcessEnv;
197
11
  logger?: ILogger;
12
+ /**
13
+ * Where the KB Labs platform is installed (parent of
14
+ * `node_modules/@kb-labs/*`). Forwarded to `discoverManifests` so that
15
+ * plugin discovery scans the platform `node_modules` regardless of where
16
+ * the CLI is invoked from. When omitted, falls back to `cwd` — this keeps
17
+ * dev-mode behavior unchanged.
18
+ */
19
+ platformRoot?: string;
198
20
  }
199
21
  declare function registerBuiltinCommands(input?: RegisterBuiltinCommandsInput): Promise<void>;
200
22
 
@@ -231,22 +53,6 @@ interface ExampleCase {
231
53
  }
232
54
  declare function generateExamples(commandName: string, productName: string, cases: ExampleCase[]): string[];
233
55
 
234
- /**
235
- * @kb-labs/cli-commands/registry
236
- * Command manifest discovery - workspace, node_modules, current package
237
- */
238
-
239
- /**
240
- * Main discovery function
241
- * Discovers command manifests from workspace, current package, and node_modules
242
- */
243
- declare function discoverManifests(cwd: string, noCache?: boolean): Promise<DiscoveryResult[]>;
244
- /**
245
- * Lazy load manifests for a specific namespace
246
- * Only loads manifests from packages matching the namespace
247
- */
248
- declare function discoverManifestsByNamespace(cwd: string, namespace: string, noCache?: boolean): Promise<DiscoveryResult[]>;
249
-
250
56
  declare const hello: _kb_labs_shared_command_kit.Command;
251
57
 
252
58
  declare const health: _kb_labs_shared_command_kit.Command;
@@ -291,4 +97,4 @@ declare const logsGet: _kb_labs_shared_command_kit.Command;
291
97
  */
292
98
  declare const logsStats: _kb_labs_shared_command_kit.Command;
293
99
 
294
- 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 };
100
+ export { type ExampleCase, ProductGroup, RegisteredCommand, generateExamples, health, hello, logsContext, logsDiagnose, logsGet, logsQuery, logsSearch, logsStats, logsSummarize, registerBuiltinCommands, renderGlobalHelp, renderGlobalHelpNew, renderGroupHelp, renderHelp, renderManifestCommandHelp, renderPluginsHelp, renderProductHelp, version };
package/dist/index.js CHANGED
@@ -851,7 +851,7 @@ async function saveCache(cwd, results) {
851
851
  log("debug", `Failed to save cache: ${err.message}`);
852
852
  }
853
853
  }
854
- async function discoverManifests(cwd, noCache = false) {
854
+ async function discoverManifests(cwd, noCache = false, options = {}) {
855
855
  const startTime = Date.now();
856
856
  const timings = {};
857
857
  if (noCache) {
@@ -927,7 +927,8 @@ async function discoverManifests(cwd, noCache = false) {
927
927
  }
928
928
  }
929
929
  const nmStart = Date.now();
930
- const installed = await discoverNodeModules(cwd);
930
+ const nodeModulesRoot = options.platformRoot ?? cwd;
931
+ const installed = await discoverNodeModules(nodeModulesRoot);
931
932
  timings.nodeModules = Date.now() - nmStart;
932
933
  if (installed.length > 0) {
933
934
  log("info", `Discovered ${installed.length} installed packages with CLI manifests`);
@@ -1524,7 +1525,8 @@ var diag = defineSystemCommand({
1524
1525
  details: { nodeVersion, cliVersion, platform: platform11, arch }
1525
1526
  });
1526
1527
  try {
1527
- const discovered = await discoverManifests(cwd, false);
1528
+ const platformRoot = process.env.KB_PLATFORM_ROOT;
1529
+ const discovered = await discoverManifests(cwd, false, { platformRoot });
1528
1530
  const manifests = registry.listManifests();
1529
1531
  const enabled = manifests.filter((m) => m.available && !m.shadowed).length;
1530
1532
  const disabled = manifests.filter((m) => !m.available).length;
@@ -3660,7 +3662,9 @@ async function registerBuiltinCommands(input = {}) {
3660
3662
  const env = input.env ?? process.env;
3661
3663
  const noCache = process.argv.includes("--no-cache") || env.KB_PLUGIN_NO_CACHE === "1";
3662
3664
  const { discoverManifests: discoverManifests2 } = await Promise.resolve().then(() => (init_discover(), discover_exports));
3663
- const discovered = await discoverManifests2(cwd, noCache);
3665
+ const discovered = await discoverManifests2(cwd, noCache, {
3666
+ platformRoot: input.platformRoot
3667
+ });
3664
3668
  if (discovered.length > 0) {
3665
3669
  log3.info(`Discovered ${discovered.length} packages with CLI manifests`);
3666
3670
  const { valid: readyToRegister, skipped: preflightSkipped } = preflightManifests(discovered, log3);