@unstoppabledomains/ud-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +344 -0
  2. package/dist/commands/api-commands.d.ts +9 -0
  3. package/dist/commands/api-commands.d.ts.map +1 -0
  4. package/dist/commands/api-commands.js +303 -0
  5. package/dist/commands/api-commands.js.map +1 -0
  6. package/dist/commands/auth.d.ts +3 -0
  7. package/dist/commands/auth.d.ts.map +1 -0
  8. package/dist/commands/auth.js +97 -0
  9. package/dist/commands/auth.js.map +1 -0
  10. package/dist/commands/cart.d.ts +10 -0
  11. package/dist/commands/cart.d.ts.map +1 -0
  12. package/dist/commands/cart.js +125 -0
  13. package/dist/commands/cart.js.map +1 -0
  14. package/dist/commands/config.d.ts +3 -0
  15. package/dist/commands/config.d.ts.map +1 -0
  16. package/dist/commands/config.js +90 -0
  17. package/dist/commands/config.js.map +1 -0
  18. package/dist/commands/env.d.ts +3 -0
  19. package/dist/commands/env.d.ts.map +1 -0
  20. package/dist/commands/env.js +29 -0
  21. package/dist/commands/env.js.map +1 -0
  22. package/dist/generated/openapi-spec.json +5903 -0
  23. package/dist/index.d.ts +2 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +3 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/lib/api.d.ts +7 -0
  28. package/dist/lib/api.d.ts.map +1 -0
  29. package/dist/lib/api.js +162 -0
  30. package/dist/lib/api.js.map +1 -0
  31. package/dist/lib/command-hooks.d.ts +49 -0
  32. package/dist/lib/command-hooks.d.ts.map +1 -0
  33. package/dist/lib/command-hooks.js +150 -0
  34. package/dist/lib/command-hooks.js.map +1 -0
  35. package/dist/lib/command-registry.d.ts +30 -0
  36. package/dist/lib/command-registry.d.ts.map +1 -0
  37. package/dist/lib/command-registry.js +322 -0
  38. package/dist/lib/command-registry.js.map +1 -0
  39. package/dist/lib/config.d.ts +19 -0
  40. package/dist/lib/config.d.ts.map +1 -0
  41. package/dist/lib/config.js +95 -0
  42. package/dist/lib/config.js.map +1 -0
  43. package/dist/lib/credentials.d.ts +16 -0
  44. package/dist/lib/credentials.d.ts.map +1 -0
  45. package/dist/lib/credentials.js +126 -0
  46. package/dist/lib/credentials.js.map +1 -0
  47. package/dist/lib/formatter.d.ts +34 -0
  48. package/dist/lib/formatter.d.ts.map +1 -0
  49. package/dist/lib/formatter.js +691 -0
  50. package/dist/lib/formatter.js.map +1 -0
  51. package/dist/lib/oauth.d.ts +8 -0
  52. package/dist/lib/oauth.d.ts.map +1 -0
  53. package/dist/lib/oauth.js +212 -0
  54. package/dist/lib/oauth.js.map +1 -0
  55. package/dist/lib/param-builder.d.ts +28 -0
  56. package/dist/lib/param-builder.d.ts.map +1 -0
  57. package/dist/lib/param-builder.js +178 -0
  58. package/dist/lib/param-builder.js.map +1 -0
  59. package/dist/lib/prompt.d.ts +17 -0
  60. package/dist/lib/prompt.d.ts.map +1 -0
  61. package/dist/lib/prompt.js +53 -0
  62. package/dist/lib/prompt.js.map +1 -0
  63. package/dist/lib/spec-parser.d.ts +76 -0
  64. package/dist/lib/spec-parser.d.ts.map +1 -0
  65. package/dist/lib/spec-parser.js +201 -0
  66. package/dist/lib/spec-parser.js.map +1 -0
  67. package/dist/lib/spinner.d.ts +16 -0
  68. package/dist/lib/spinner.d.ts.map +1 -0
  69. package/dist/lib/spinner.js +23 -0
  70. package/dist/lib/spinner.js.map +1 -0
  71. package/dist/lib/types.d.ts +63 -0
  72. package/dist/lib/types.d.ts.map +1 -0
  73. package/dist/lib/types.js +11 -0
  74. package/dist/lib/types.js.map +1 -0
  75. package/dist/program.d.ts +3 -0
  76. package/dist/program.d.ts.map +1 -0
  77. package/dist/program.js +47 -0
  78. package/dist/program.js.map +1 -0
  79. package/package.json +70 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ import { program } from './program.js';
2
+ program.parse();
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { mcpBaseUrl, apiBaseUrl } from './config.js';
2
+ import type { AuthStatus } from './types.js';
3
+ export declare function callAction(toolName: string, params: Record<string, unknown>): Promise<unknown>;
4
+ export declare function healthCheck(): Promise<boolean>;
5
+ export declare function verifyAuth(): Promise<AuthStatus>;
6
+ export { apiBaseUrl, mcpBaseUrl };
7
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIjF,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,YAAY,CAAC;AA6GxD,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,OAAO,CAAC,CAalB;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAQpD;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC,CAmDtD;AAED,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC"}
@@ -0,0 +1,162 @@
1
+ import { getActiveEnv, getEnvConfig, mcpBaseUrl, apiBaseUrl } from './config.js';
2
+ import { getApiKey, getTokens, saveTokens } from './credentials.js';
3
+ import { refreshAccessToken, discoverMetadata } from './oauth.js';
4
+ import { ApiError } from './types.js';
5
+ const REFRESH_BUFFER_MS = 60_000; // Refresh 60s before expiry
6
+ async function getAuthHeader() {
7
+ const env = getActiveEnv();
8
+ const envConfig = getEnvConfig(env);
9
+ if (envConfig.authMethod === 'oauth') {
10
+ let tokens = await getTokens(env);
11
+ if (!tokens)
12
+ return null;
13
+ // Proactive refresh if token expires within buffer
14
+ if (tokens.expiresAt - Date.now() < REFRESH_BUFFER_MS) {
15
+ tokens = await tryRefreshTokens(tokens);
16
+ }
17
+ return `Bearer ${tokens.accessToken}`;
18
+ }
19
+ // Default: API key
20
+ const apiKey = await getApiKey(env);
21
+ if (!apiKey)
22
+ return null;
23
+ return `Bearer ${apiKey}`;
24
+ }
25
+ async function tryRefreshTokens(tokens) {
26
+ const envConfig = getEnvConfig();
27
+ const clientId = envConfig.oauth?.clientId;
28
+ if (!clientId)
29
+ return tokens;
30
+ try {
31
+ const metadata = await discoverMetadata();
32
+ const response = await refreshAccessToken(metadata.token_endpoint, tokens.refreshToken, clientId);
33
+ const refreshed = {
34
+ accessToken: response.access_token,
35
+ refreshToken: response.refresh_token,
36
+ expiresAt: Date.now() + response.expires_in * 1000,
37
+ scope: response.scope,
38
+ };
39
+ await saveTokens(refreshed);
40
+ return refreshed;
41
+ }
42
+ catch {
43
+ // If refresh fails, return original tokens and let the 401 retry handle it
44
+ return tokens;
45
+ }
46
+ }
47
+ async function request(url, options = {}, retry = true) {
48
+ const authHeader = await getAuthHeader();
49
+ const headers = {
50
+ 'Content-Type': 'application/json',
51
+ ...options.headers,
52
+ };
53
+ if (authHeader) {
54
+ headers['Authorization'] = authHeader;
55
+ }
56
+ const res = await fetch(url, { ...options, headers });
57
+ // Reactive refresh: retry once on 401
58
+ if (res.status === 401 && retry) {
59
+ const envConfig = getEnvConfig();
60
+ if (envConfig.authMethod === 'oauth') {
61
+ const tokens = await getTokens();
62
+ if (tokens) {
63
+ const refreshed = await tryRefreshTokens(tokens);
64
+ if (refreshed.accessToken !== tokens.accessToken) {
65
+ return request(url, options, false);
66
+ }
67
+ }
68
+ }
69
+ }
70
+ return res;
71
+ }
72
+ function parseError(status, body) {
73
+ try {
74
+ const json = JSON.parse(body);
75
+ const message = json.message ?? json.error ?? body;
76
+ switch (status) {
77
+ case 400:
78
+ return new ApiError(`Bad request: ${message}`, 400, 'BAD_REQUEST');
79
+ case 401:
80
+ return new ApiError('Authentication failed. Run `ud auth login` to authenticate.', 401, 'UNAUTHORIZED');
81
+ case 403:
82
+ return new ApiError(`Access denied: ${message}`, 403, 'FORBIDDEN');
83
+ default:
84
+ return new ApiError(`API error (${status}): ${message}`, status, 'API_ERROR');
85
+ }
86
+ }
87
+ catch {
88
+ return new ApiError(`API error (${status}): ${body}`, status, 'API_ERROR');
89
+ }
90
+ }
91
+ // --- Public API ---
92
+ export async function callAction(toolName, params) {
93
+ const url = `${mcpBaseUrl()}/actions/${toolName}`;
94
+ const res = await request(url, {
95
+ method: 'POST',
96
+ body: JSON.stringify(params),
97
+ });
98
+ if (!res.ok) {
99
+ const body = await res.text();
100
+ throw parseError(res.status, body);
101
+ }
102
+ return res.json();
103
+ }
104
+ export async function healthCheck() {
105
+ try {
106
+ const url = `${mcpBaseUrl()}/health`;
107
+ const res = await fetch(url);
108
+ return res.ok;
109
+ }
110
+ catch {
111
+ return false;
112
+ }
113
+ }
114
+ export async function verifyAuth() {
115
+ const env = getActiveEnv();
116
+ const envConfig = getEnvConfig(env);
117
+ // Check if any credentials exist
118
+ const hasApiKey = !!(await getApiKey(env));
119
+ const hasTokens = !!(await getTokens(env));
120
+ if (!hasApiKey && !hasTokens) {
121
+ return {
122
+ authenticated: false,
123
+ environment: env,
124
+ message: 'Not authenticated. Run `ud auth login` to get started.',
125
+ };
126
+ }
127
+ const method = envConfig.authMethod ?? (hasApiKey ? 'api-key' : 'oauth');
128
+ try {
129
+ // Use portfolio list as a lightweight auth check
130
+ const url = `${mcpBaseUrl()}/actions/ud_portfolio_list`;
131
+ const res = await request(url, {
132
+ method: 'POST',
133
+ body: JSON.stringify({ limit: 1 }),
134
+ });
135
+ if (res.ok) {
136
+ return {
137
+ authenticated: true,
138
+ method,
139
+ environment: env,
140
+ message: `Authenticated via ${method} to ${env}`,
141
+ };
142
+ }
143
+ const body = await res.text();
144
+ const error = parseError(res.status, body);
145
+ return {
146
+ authenticated: false,
147
+ method,
148
+ environment: env,
149
+ message: error.message,
150
+ };
151
+ }
152
+ catch (err) {
153
+ return {
154
+ authenticated: false,
155
+ method,
156
+ environment: env,
157
+ message: `Connection error: ${err instanceof Error ? err.message : String(err)}`,
158
+ };
159
+ }
160
+ }
161
+ export { apiBaseUrl, mcpBaseUrl };
162
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Declarative hook definitions for commands that need special behavior
3
+ * beyond the standard API call (confirmations, OTP prompts, operation hints).
4
+ */
5
+ export interface CommandHooks {
6
+ /** Require --confirm flag or interactive prompt before executing. */
7
+ requireConfirm?: {
8
+ /** API param name to set when confirmed (e.g., 'confirmDeleteAll'). Omit if no API param needed. */
9
+ paramName?: string;
10
+ /** Warning message shown to the user. */
11
+ message: string;
12
+ };
13
+ /** Prompt for a value interactively if the corresponding flag is not provided. */
14
+ promptInput?: {
15
+ /** CLI flag name (kebab-case, e.g., 'otp-code'). */
16
+ flagName: string;
17
+ /** API param name to set with the input value. */
18
+ paramName: string;
19
+ /** Prompt message shown to the user. */
20
+ prompt: string;
21
+ /** Regex to validate user input. */
22
+ validate?: RegExp;
23
+ };
24
+ /** Transform the request body before sending (e.g., price conversion). */
25
+ transformBody?: (body: Record<string, unknown>, opts: Record<string, unknown>) => Record<string, unknown>;
26
+ /** Register a --price <dollars> option for this command. */
27
+ priceOption?: boolean;
28
+ /** Show an operation-tracking hint after the API call completes. */
29
+ showOperationHint?: boolean;
30
+ /** Show a cart-add hint using the first available result from search. */
31
+ showCartHint?: boolean;
32
+ }
33
+ /**
34
+ * Get hooks for a given tool name. Returns undefined if no hooks defined.
35
+ */
36
+ export declare function getHooks(toolName: string): CommandHooks | undefined;
37
+ /**
38
+ * Format a hint about async DNS operations from an API response.
39
+ * Scans result.results[] for items with operationId and collects unique domains.
40
+ */
41
+ export declare function formatOperationHint(result: unknown): string;
42
+ /** Map marketplace source to the corresponding cart add subcommand. */
43
+ export declare const SOURCE_TO_CART_CMD: Record<string, string>;
44
+ /**
45
+ * Format a cart-add hint from domain search results.
46
+ * Shows one example per marketplace source type found in the results.
47
+ */
48
+ export declare function formatCartHint(result: unknown): string;
49
+ //# sourceMappingURL=command-hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-hooks.d.ts","sourceRoot":"","sources":["../../src/lib/command-hooks.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,cAAc,CAAC,EAAE;QACf,oGAAoG;QACpG,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,yCAAyC;QACzC,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,kFAAkF;IAClF,WAAW,CAAC,EAAE;QACZ,oDAAoD;QACpD,QAAQ,EAAE,MAAM,CAAC;QACjB,kDAAkD;QAClD,SAAS,EAAE,MAAM,CAAC;QAClB,wCAAwC;QACxC,MAAM,EAAE,MAAM,CAAC;QACf,oCAAoC;QACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,0EAA0E;IAC1E,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1G,4DAA4D;IAC5D,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,oEAAoE;IACpE,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,yEAAyE;IACzE,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AA0ED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEnE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CA2B3D;AAED,uEAAuE;AACvE,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKrD,CAAC;AAEF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CA2BtD"}
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Declarative hook definitions for commands that need special behavior
3
+ * beyond the standard API call (confirmations, OTP prompts, operation hints).
4
+ */
5
+ import chalk from 'chalk';
6
+ /**
7
+ * Create a transformBody hook that converts --price (dollars) to priceInCents on each item.
8
+ */
9
+ function makePriceTransformer(arrayKey) {
10
+ return (body, opts) => {
11
+ const price = opts.price;
12
+ if (price !== undefined) {
13
+ const num = Number(price);
14
+ if (Number.isNaN(num) || num < 0) {
15
+ throw new Error(`Invalid --price value: "${price}". Must be a non-negative number (e.g., 99.99).`);
16
+ }
17
+ const cents = Math.round(num * 100);
18
+ if (Array.isArray(body[arrayKey])) {
19
+ for (const item of body[arrayKey]) {
20
+ if (item.priceInCents === undefined)
21
+ item.priceInCents = cents;
22
+ }
23
+ }
24
+ }
25
+ return body;
26
+ };
27
+ }
28
+ const HOOKS = {
29
+ ud_dns_records_remove_all: {
30
+ requireConfirm: {
31
+ paramName: 'confirmDeleteAll',
32
+ message: 'This will delete ALL DNS records for the specified domain(s). Are you sure?',
33
+ },
34
+ showOperationHint: true,
35
+ },
36
+ ud_domain_remove_lander: {
37
+ requireConfirm: {
38
+ message: 'This will remove the AI lander for the specified domain(s). Are you sure?',
39
+ },
40
+ showOperationHint: true,
41
+ },
42
+ ud_domain_push: {
43
+ promptInput: {
44
+ flagName: 'otp-code',
45
+ paramName: 'otpCode',
46
+ prompt: 'Enter 6-digit OTP code: ',
47
+ validate: /^\d{6}$/,
48
+ },
49
+ },
50
+ ud_cart_checkout: {
51
+ requireConfirm: {
52
+ message: 'Are you sure you want to complete this purchase? Review your cart with: ud cart get',
53
+ },
54
+ },
55
+ ud_listing_cancel: {
56
+ requireConfirm: {
57
+ message: 'This will cancel the specified listing(s). Are you sure?',
58
+ },
59
+ },
60
+ ud_listing_create: {
61
+ priceOption: true,
62
+ transformBody: makePriceTransformer('domains'),
63
+ },
64
+ ud_listing_update: {
65
+ priceOption: true,
66
+ transformBody: makePriceTransformer('listings'),
67
+ },
68
+ ud_domains_search: { showCartHint: true },
69
+ ud_dns_record_add: { showOperationHint: true },
70
+ ud_dns_record_update: { showOperationHint: true },
71
+ ud_dns_record_remove: { showOperationHint: true },
72
+ ud_dns_nameservers_set_custom: { showOperationHint: true },
73
+ ud_dns_nameservers_set_default: { showOperationHint: true },
74
+ ud_dns_hosting_add: { showOperationHint: true },
75
+ ud_dns_hosting_remove: { showOperationHint: true },
76
+ };
77
+ /**
78
+ * Get hooks for a given tool name. Returns undefined if no hooks defined.
79
+ */
80
+ export function getHooks(toolName) {
81
+ return HOOKS[toolName];
82
+ }
83
+ /**
84
+ * Format a hint about async DNS operations from an API response.
85
+ * Scans result.results[] for items with operationId and collects unique domains.
86
+ */
87
+ export function formatOperationHint(result) {
88
+ if (!result || typeof result !== 'object')
89
+ return '';
90
+ const obj = result;
91
+ const results = obj.results;
92
+ if (!Array.isArray(results))
93
+ return '';
94
+ const domains = new Set();
95
+ let hasOps = false;
96
+ for (const item of results) {
97
+ if (item.operationId !== undefined) {
98
+ hasOps = true;
99
+ if (typeof item.domain === 'string') {
100
+ domains.add(item.domain);
101
+ }
102
+ }
103
+ }
104
+ if (!hasOps)
105
+ return '';
106
+ const domainList = [...domains].join(' ');
107
+ const trackCmd = domainList
108
+ ? `ud domains operations ${domainList}`
109
+ : 'ud domains operations <domain>';
110
+ return chalk.dim(`Tip: DNS changes are async. Track with: ${trackCmd}`);
111
+ }
112
+ /** Map marketplace source to the corresponding cart add subcommand. */
113
+ export const SOURCE_TO_CART_CMD = {
114
+ unstoppable_domains: 'registration',
115
+ aftermarket: 'listed',
116
+ afternic: 'afternic',
117
+ sedo: 'sedo',
118
+ };
119
+ /**
120
+ * Format a cart-add hint from domain search results.
121
+ * Shows one example per marketplace source type found in the results.
122
+ */
123
+ export function formatCartHint(result) {
124
+ if (!result || typeof result !== 'object')
125
+ return '';
126
+ const obj = result;
127
+ const results = (obj.results ?? obj.domains);
128
+ if (!Array.isArray(results) || results.length === 0)
129
+ return '';
130
+ // Collect one example per marketplace source type
131
+ const seenSources = new Map();
132
+ for (const item of results) {
133
+ if (item.available !== true)
134
+ continue;
135
+ const name = item.name;
136
+ if (!name)
137
+ continue;
138
+ const marketplace = item.marketplace;
139
+ const source = marketplace?.source;
140
+ const subCmd = SOURCE_TO_CART_CMD[source ?? ''] ?? 'registration';
141
+ if (!seenSources.has(subCmd)) {
142
+ seenSources.set(subCmd, { name, subCmd });
143
+ }
144
+ }
145
+ if (seenSources.size === 0)
146
+ return '';
147
+ const lines = [...seenSources.values()].map(({ name, subCmd }) => ` ud cart add ${subCmd} ${name}`);
148
+ return chalk.dim(`\nTo add to cart:\n${lines.join('\n')}`);
149
+ }
150
+ //# sourceMappingURL=command-hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-hooks.js","sourceRoot":"","sources":["../../src/lib/command-hooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Static command routing table that maps API tool names to CLI command hierarchy.
3
+ *
4
+ * Each route defines:
5
+ * - The tool name (matches the OpenAPI spec endpoint)
6
+ * - The CLI path as [group, subgroup?, command]
7
+ * - Optional positional arguments
8
+ */
9
+ export interface PositionalArg {
10
+ name: string;
11
+ description: string;
12
+ required: boolean;
13
+ variadic: boolean;
14
+ }
15
+ export interface CommandRoute {
16
+ toolName: string;
17
+ path: string[];
18
+ positionalArgs: PositionalArg[];
19
+ description?: string;
20
+ }
21
+ export declare const COMMAND_ROUTES: CommandRoute[];
22
+ /**
23
+ * Returns the set of unique top-level group names.
24
+ */
25
+ export declare function getGroups(): string[];
26
+ /**
27
+ * Builds a lookup map from toolName → CommandRoute.
28
+ */
29
+ export declare function buildRouteMap(): Map<string, CommandRoute>;
30
+ //# sourceMappingURL=command-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-registry.d.ts","sourceRoot":"","sources":["../../src/lib/command-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,cAAc,EAAE,YAAY,EA+SxC,CAAC;AAEF;;GAEG;AACH,wBAAgB,SAAS,IAAI,MAAM,EAAE,CAMpC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAMzD"}