@kb-labs/cli-commands 2.93.0 → 2.96.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.
@@ -1,4 +1,6 @@
1
- import { ManifestV3, PluginContextV3 } from '@kb-labs/plugin-contracts';
1
+ import { ILogger } from '@kb-labs/core-platform';
2
+ import { Command, CommandGroup } from '@kb-labs/shared-command-kit';
3
+ import { ManifestV3 } from '@kb-labs/plugin-contracts';
2
4
 
3
5
  /**
4
6
  * @kb-labs/cli-commands/registry
@@ -7,10 +9,17 @@ import { ManifestV3, PluginContextV3 } from '@kb-labs/plugin-contracts';
7
9
 
8
10
  interface CommandManifest {
9
11
  manifestVersion: '1.0';
12
+ /** Canonical routing key — full path segments, e.g. ['clickup', 'task', 'search'] */
13
+ segments: readonly string[];
14
+ /** Last segment — e.g. 'search' */
10
15
  id: string;
11
- aliases?: string[];
16
+ /** First segment — e.g. 'clickup' */
12
17
  group: string;
18
+ /** Second segment when depth >= 3 — e.g. 'task' */
13
19
  subgroup?: string;
20
+ aliases?: string[];
21
+ category?: string;
22
+ /** One-line description shown in group help (under 50 chars, no trailing period). */
14
23
  describe: string;
15
24
  longDescription?: string;
16
25
  requires?: string[];
@@ -18,7 +27,6 @@ interface CommandManifest {
18
27
  examples?: string[];
19
28
  loader?: () => Promise<CommandModule>;
20
29
  package?: string;
21
- namespace?: string;
22
30
  engine?: {
23
31
  node?: string;
24
32
  kbCli?: string;
@@ -30,6 +38,8 @@ interface CommandManifest {
30
38
  pkgRoot?: string;
31
39
  /** Internal flag: true for synthetic "unavailable" manifests that must not be cached. */
32
40
  _synthetic?: boolean;
41
+ /** Archetype from manifest — drives automatic flag injection and --schema generation. */
42
+ operationType?: 'read' | 'mutate' | 'execute' | 'analyze';
33
43
  }
34
44
  interface FlagDefinition {
35
45
  name: string;
@@ -64,8 +74,9 @@ interface DiscoveryResult {
64
74
  /**
65
75
  * Scope this result came from. Platform-wide discovery (monorepo workspace,
66
76
  * platform node_modules) reports `platform`; discovery from
67
- * `<projectRoot>/.kb/plugins/` reports `project`. On collision (same
68
- * packageName in both scopes) the platform entry wins — see ADR-0012.
77
+ * `<projectRoot>/.kb/plugins/` or `<projectRoot>` workspace reports `project`.
78
+ * On collision (same packageName in both scopes) the project entry wins —
79
+ * project overrides platform defaults.
69
80
  */
70
81
  scope: 'platform' | 'project';
71
82
  packageName: string;
@@ -95,6 +106,7 @@ interface PackageCacheEntry {
95
106
  interface CacheFile {
96
107
  version: string;
97
108
  cliVersion: string;
109
+ discoveryVersion?: number;
98
110
  timestamp: number;
99
111
  ttlMs?: number;
100
112
  stateHash?: string;
@@ -120,124 +132,136 @@ type AvailabilityCheck = {
120
132
  };
121
133
 
122
134
  /**
123
- * Legacy V2 types for backward compatibility
124
- * These types were removed from cli-contracts but are still needed
125
- * for the adapter layer in service.ts
135
+ * @kb-labs/cli-commands/registry/trie-router
136
+ * Path-based trie router for CLI command resolution.
137
+ *
138
+ * Replaces the flat-map InMemoryRegistry + backtracking resolveCommand().
139
+ * Two trie instances: systemTrie (always first) + pluginTrie (plugins).
140
+ *
141
+ * Key guarantees:
142
+ * - O(depth) resolution — no backtracking
143
+ * - No collisions: same last-segment in different paths are distinct nodes
144
+ * - "did you mean?" via Levenshtein ≤ 2 + findDeep shorthand detection
145
+ * - Tab completion via complete()
126
146
  */
127
147
 
128
- interface CommandRun {
129
- (ctx: PluginContextV3, argv: string[], flags: Record<string, unknown>): Promise<number | void>;
130
- }
131
- interface Command {
132
- name: string;
133
- category?: string;
134
- describe: string;
135
- longDescription?: string;
136
- aliases?: string[];
137
- flags?: FlagDefinition[];
138
- examples?: string[];
139
- run: CommandRun;
140
- }
141
- interface CommandGroup {
142
- name: string;
143
- describe?: string;
144
- commands: Command[];
145
- subgroups?: CommandGroup[];
146
- }
147
- interface CommandRegistry {
148
- register(cmd: Command): void;
149
- registerGroup(group: CommandGroup): void;
150
- registerManifest(cmd: RegisteredCommand): void;
151
- list(): Command[];
152
- listGroups(): CommandGroup[];
153
- listManifests(): RegisteredCommand[];
154
- markPartial(isPartial: boolean): void;
155
- isPartial(): boolean;
156
- }
157
-
158
- interface ProductGroup {
159
- name: string;
148
+ type RouteResult = {
149
+ type: 'system-cmd';
150
+ cmd: Command;
151
+ rest: string[];
152
+ } | {
153
+ type: 'system-group';
154
+ group: CommandGroup;
155
+ rest: string[];
156
+ } | {
157
+ type: 'command';
158
+ command: RegisteredCommand;
159
+ rest: string[];
160
+ } | {
161
+ type: 'group';
162
+ segments: string[];
160
163
  describe?: string;
161
- commands: RegisteredCommand[];
162
- }
163
- type CommandType = 'system' | 'plugin';
164
- interface CommandLookupResult {
165
- cmd: Command | CommandGroup;
166
- type: CommandType;
164
+ childKeys: string[];
165
+ } | {
166
+ type: 'ambiguous';
167
+ input: string[];
168
+ candidates: string[];
169
+ } | {
170
+ type: 'not-found';
171
+ input: string[];
172
+ suggestions: string[];
173
+ };
174
+ interface RegistryDiagnostics {
175
+ systemCommandCount: number;
176
+ systemGroupCount: number;
177
+ pluginCommandCount: number;
178
+ partialLoad: boolean;
167
179
  }
168
- declare class InMemoryRegistry implements CommandRegistry {
169
- private systemCommands;
170
- private pluginByCanonical;
171
- private pluginAliases;
172
- private byName;
173
- private groups;
174
- private manifests;
175
- private partial;
176
- register(cmd: Command): void;
177
- registerGroup(group: CommandGroup): void;
178
- registerManifest(cmd: RegisteredCommand): void;
179
- /**
180
- * Check whether any system command already owns the canonical id or its parts.
181
- * Returns the colliding key if found, null otherwise.
182
- */
183
- private _findSystemCollision;
180
+ declare function levenshtein(a: string, b: string): number;
181
+ declare class TrieRouter {
182
+ private readonly root;
184
183
  /**
185
- * Register all lookup aliases for a plugin command.
184
+ * Insert a plugin command into the trie.
186
185
  *
187
- * Priority (what beats what) is handled in resolveToCanonical at query time.
188
- * Here we just build the mapping.
186
+ * Enforces 1-manifest-1-namespace: the first packageName to register any command
187
+ * under a top-level group becomes the owner. Subsequent packages with a different
188
+ * packageName are rejected (collides: true) — the caller is responsible for warning
189
+ * and marking the command as shadowed.
189
190
  *
190
- * Aliases registered:
191
- * - canonicalId itself ("marketplace:plugins:list")
192
- * - bare id ("list") ← low priority, may clash
193
- * - 2-part shorthand ("marketplace:list", "marketplace list")
194
- * - manifest.aliases[] (user-defined aliases, except collisions)
191
+ * Returns { collides: false } on success, or { collides: true, ownerPackage } on conflict.
195
192
  */
196
- private _registerPluginAliases;
193
+ insertCommand(segments: readonly string[], cmd: RegisteredCommand): {
194
+ collides: false;
195
+ } | {
196
+ collides: true;
197
+ ownerPackage: string | undefined;
198
+ };
199
+ insertSystemCommand(cmd: Command): void;
200
+ insertSystemGroup(group: CommandGroup): void;
201
+ getGroupDescribe(segments: string[]): string | undefined;
202
+ setGroupDescribe(segments: string[], describe: string): void;
203
+ resolve(tokens: string[]): RouteResult;
204
+ complete(tokens: string[]): string[];
197
205
  /**
198
- * Register synthetic subgroups for help display.
206
+ * List all leaf plugin commands under a given node path.
199
207
  */
200
- private _registerSyntheticGroups;
208
+ listUnder(segments: string[]): RegisteredCommand[];
201
209
  /**
202
- * Resolve any user input to its canonical plugin ID.
203
- *
204
- * Returns canonicalId if found in plugin aliases, undefined otherwise.
210
+ * Get exact command at path.
205
211
  */
206
- private resolveToCanonical;
207
- markPartial(partial: boolean): void;
208
- isPartial(): boolean;
209
- getManifest(id: string): RegisteredCommand | undefined;
210
- listManifests(): RegisteredCommand[];
211
- has(name: string): boolean;
212
+ getAt(segments: string[]): RegisteredCommand | null;
212
213
  /**
213
- * Get command with type information for secure routing.
214
- *
215
- * System commands ALWAYS win — checked first before any plugin lookup.
216
- * Returns type='system' for system commands (in-process execution).
217
- * Returns type='plugin' for plugin commands (subprocess execution).
214
+ * List top-level system groups and standalone system commands (depth=1 nodes).
218
215
  */
219
- getWithType(nameOrPath: string | string[]): CommandLookupResult | undefined;
220
- get(nameOrPath: string | string[]): Command | CommandGroup | undefined;
221
- list(): Command[];
222
- listGroups(): CommandGroup[];
223
- getGroupsByPrefix(prefix: string): CommandGroup[];
224
- getCommandsByGroupPrefix(prefix: string): Command[];
225
- listProductGroups(): ProductGroup[];
226
- getCommandsByGroup(group: string): RegisteredCommand[];
227
- getManifestCommand(idOrAlias: string): RegisteredCommand | undefined;
216
+ listSystemTopLevel(): Array<{
217
+ name: string;
218
+ describe: string;
219
+ isGroup: boolean;
220
+ }>;
221
+ /**
222
+ * Collect all plugin commands reachable from node.
223
+ */
224
+ listAll(): RegisteredCommand[];
225
+ private _collectCommands;
226
+ private _notFound;
228
227
  }
229
- declare const registry: InMemoryRegistry;
230
- declare function findCommand(nameOrPath: string | string[]): Command | CommandGroup | undefined;
228
+
231
229
  /**
232
- * Find command with type information for secure routing.
233
- *
234
- * Use this in bootstrap.ts to determine execution path:
235
- * - type='system' → execute via cmd.run() in-process
236
- * - type='plugin' → execute via executePlugin() in plugin-executor
230
+ * @kb-labs/cli-commands/registry/service
231
+ * TrieBackedRegistry — path-based CLI command registry (ADR-0015, ADR-0018)
237
232
  *
238
- * System commands ALWAYS take priority over plugin commands.
233
+ * Replaces InMemoryRegistry + all legacy flat-map methods.
234
+ * System commands (in-process) always take priority over plugin commands.
235
+ * Plugin namespace ownership: 1 manifest = 1 namespace (ADR-0018).
239
236
  */
240
- declare function findCommandWithType(nameOrPath: string | string[]): CommandLookupResult | undefined;
237
+
238
+ declare class TrieBackedRegistry {
239
+ private readonly systemRouter;
240
+ private readonly pluginRouter;
241
+ private partial;
242
+ private logger;
243
+ setLogger(logger: ILogger): void;
244
+ register(cmd: Command): void;
245
+ registerGroup(group: CommandGroup): void;
246
+ registerManifest(cmd: RegisteredCommand): void;
247
+ resolve(tokens: string[]): RouteResult;
248
+ complete(tokens: string[]): string[];
249
+ listSystemTopLevel(): Array<{
250
+ name: string;
251
+ describe: string;
252
+ isGroup: boolean;
253
+ }>;
254
+ getPluginGroupDescribe(segments: string[]): string | undefined;
255
+ listCommands(): RegisteredCommand[];
256
+ listCommandsUnder(segments: string[]): RegisteredCommand[];
257
+ getCommandAt(segments: string[]): RegisteredCommand | null;
258
+ markPartial(v: boolean): void;
259
+ isPartial(): boolean;
260
+ getDiagnostics(): RegistryDiagnostics;
261
+ }
262
+ declare function createRegistry(): TrieBackedRegistry;
263
+ /** Global registry singleton — populated by bootstrap before any command runs. */
264
+ declare const registry: TrieBackedRegistry;
241
265
 
242
266
  /**
243
267
  * @kb-labs/cli-commands/registry
@@ -263,6 +287,14 @@ declare const __test: {
263
287
  * in the same process performs a fresh scan rather than serving stale results.
264
288
  */
265
289
  declare function resetInProcCache(): void;
290
+ /**
291
+ * Load kb.config.json with plugins allowlist/blocklist
292
+ */
293
+ declare function loadConfig(cwd: string): Promise<{
294
+ allow?: string[];
295
+ block?: string[];
296
+ linked?: string[];
297
+ }>;
266
298
  /**
267
299
  * Main discovery function — discovers command manifests from workspace,
268
300
  * current package, and `node_modules`.
@@ -287,4 +319,4 @@ declare function discoverManifests(cwd: string, noCache?: boolean, options?: {
287
319
  */
288
320
  declare function discoverManifestsByNamespace(cwd: string, namespace: string, noCache?: boolean): Promise<DiscoveryResult[]>;
289
321
 
290
- 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, type CacheFile as b, type CommandLookupResult as c, type CommandManifest as d, type CommandModule as e, type CommandType as f, type PackageCacheEntry as g, discoverManifests as h, discoverManifestsByNamespace as i, findCommand as j, findCommandWithType as k, type CommandRegistry as l, resetInProcCache as m, registry as r };
322
+ export { type AvailabilityCheck as A, type CommandManifest as C, type DiscoveryResult as D, type FlagDefinition as F, type GlobalFlags as G, type PackageCacheEntry as P, type RegisteredCommand as R, TrieBackedRegistry as T, __test as _, type CacheFile as a, type CommandModule as b, type RegistryDiagnostics as c, type RouteResult as d, createRegistry as e, discoverManifests as f, discoverManifestsByNamespace as g, TrieRouter as h, loadConfig as i, resetInProcCache as j, levenshtein as l, registry as r };
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import { C as CommandGroup, P as ProductGroup, a as Command, R as RegisteredCommand } from './discover-D_Is1Qqq.js';
2
- export { A as AvailabilityCheck, b as CacheFile, c as CommandLookupResult, d as CommandManifest, e as CommandModule, f as CommandType, D as DiscoveryResult, F as FlagDefinition, G as GlobalFlags, g as PackageCacheEntry, h as discoverManifests, i as discoverManifestsByNamespace, j as findCommand, k as findCommandWithType, r as registry } from './discover-D_Is1Qqq.js';
1
+ import { R as RegisteredCommand, T as TrieBackedRegistry, C as CommandManifest } from './discover-DxmYCrcJ.js';
2
+ export { A as AvailabilityCheck, a as CacheFile, b as CommandModule, D as DiscoveryResult, F as FlagDefinition, G as GlobalFlags, P as PackageCacheEntry, c as RegistryDiagnostics, d as RouteResult, e as createRegistry, f as discoverManifests, g as discoverManifestsByNamespace, r as registry } from './discover-DxmYCrcJ.js';
3
3
  import { ILogger } from '@kb-labs/core-platform';
4
4
  export { TimingTracker } from '@kb-labs/shared-cli-ui';
5
5
  import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
6
+ export { Command as SystemCommand, CommandGroup as SystemGroup } from '@kb-labs/shared-command-kit';
6
7
  import '@kb-labs/plugin-contracts';
7
8
 
8
9
  interface RegisterBuiltinCommandsInput {
@@ -27,17 +28,19 @@ interface RegisterBuiltinCommandsInput {
27
28
  }
28
29
  declare function registerBuiltinCommands(input?: RegisterBuiltinCommandsInput): Promise<void>;
29
30
 
30
- declare function renderGroupHelp(group: CommandGroup): string;
31
+ interface GroupHelpOptions {
32
+ /** Full path of the group (e.g. ['marketplace', 'plugins']) */
33
+ segments: string[];
34
+ describe?: string;
35
+ /** Direct child key names shown in group listing */
36
+ childKeys: string[];
37
+ /** Full plugin commands available under this path (for detailed listing) */
38
+ commands?: RegisteredCommand[];
39
+ }
40
+ declare function renderGroupHelp(opts: GroupHelpOptions): string;
31
41
 
32
- declare function renderGlobalHelp(groups: ProductGroup[], standalone: Command[]): string;
33
- declare function renderGlobalHelpNew(registry: {
34
- listProductGroups(): ProductGroup[];
35
- list(): Command[];
36
- listGroups?(): CommandGroup[];
37
- }): string;
38
- declare function renderPluginsHelp(registry: {
39
- list(): Command[];
40
- }): string;
42
+ declare function renderGlobalHelp(registry: TrieBackedRegistry): string;
43
+ declare function renderPluginsHelp(registry: TrieBackedRegistry): string;
41
44
 
42
45
  declare function renderProductHelp(groupName: string, commands: RegisteredCommand[]): string;
43
46
 
@@ -50,6 +53,12 @@ interface RenderHelpOptions {
50
53
  }
51
54
  declare function renderHelp(commands: RegisteredCommand[], options: RenderHelpOptions): string | Record<string, unknown>;
52
55
 
56
+ /**
57
+ * Generates a JSON Schema object from a CommandManifest.
58
+ * Used by the --schema flag interception in bootstrap.
59
+ */
60
+ declare function generateCommandSchema(manifest: CommandManifest): object;
61
+
53
62
  /**
54
63
  * Generate command examples
55
64
  * Simple helper to format command examples for CLI commands
@@ -66,6 +75,8 @@ declare const health: _kb_labs_shared_command_kit.Command;
66
75
 
67
76
  declare const version: _kb_labs_shared_command_kit.Command;
68
77
 
78
+ declare function createCompletionCommand(registry: TrieBackedRegistry): _kb_labs_shared_command_kit.Command;
79
+
69
80
  /**
70
81
  * logs diagnose — "What went wrong?" Automated error analysis.
71
82
  * Agent-first command: single call gives a full diagnostic report.
@@ -104,4 +115,4 @@ declare const logsGet: _kb_labs_shared_command_kit.Command;
104
115
  */
105
116
  declare const logsStats: _kb_labs_shared_command_kit.Command;
106
117
 
107
- export { type ExampleCase, ProductGroup, RegisteredCommand, generateExamples, health, hello, logsContext, logsDiagnose, logsGet, logsQuery, logsSearch, logsStats, logsSummarize, registerBuiltinCommands, renderGlobalHelp, renderGlobalHelpNew, renderGroupHelp, renderHelp, renderManifestCommandHelp, renderPluginsHelp, renderProductHelp, version };
118
+ export { CommandManifest, type ExampleCase, RegisteredCommand, TrieBackedRegistry, createCompletionCommand, generateCommandSchema, generateExamples, health, hello, logsContext, logsDiagnose, logsGet, logsQuery, logsSearch, logsStats, logsSummarize, registerBuiltinCommands, renderGlobalHelp, renderGroupHelp, renderHelp, renderManifestCommandHelp, renderPluginsHelp, renderProductHelp, version };