sdk-pilot-cli 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/README.md ADDED
@@ -0,0 +1,161 @@
1
+ # sdk-pilot-cli
2
+
3
+ > CLI tool for SDK Pilot — generate SDKs & API docs, publish packages, and create MCP servers from API specs
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm i -g sdk-pilot-cli
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```bash
14
+ # 1. Authenticate
15
+ sdk-pilot auth <your-api-key>
16
+
17
+ # 2. Generate a TypeScript SDK
18
+ sdk-pilot generate https://petstore3.swagger.io/api/v3/openapi.json --lang typescript
19
+
20
+ # 3. Generate API docs
21
+ sdk-pilot docs https://petstore3.swagger.io/api/v3/openapi.json
22
+
23
+ # 4. Publish to npm
24
+ sdk-pilot publish ./my-sdk --registry npm
25
+ ```
26
+
27
+ ## Commands
28
+
29
+ ### `sdk-pilot auth <api-key>`
30
+
31
+ Save your SDK Pilot API key to `~/.sdk-pilot/config.json`.
32
+
33
+ ```bash
34
+ sdk-pilot auth sk-abc123...
35
+ ```
36
+
37
+ ### `sdk-pilot generate <spec-url-or-file>`
38
+
39
+ Generate an SDK from an OpenAPI/Swagger/GraphQL/gRPC/Postman spec.
40
+
41
+ ```bash
42
+ sdk-pilot generate https://example.com/openapi.json --lang typescript
43
+ sdk-pilot generate ./openapi.yaml --lang python --output ./my-sdk
44
+ ```
45
+
46
+ **Options:**
47
+
48
+ | Flag | Description | Default |
49
+ |------|-------------|---------|
50
+ | `--lang <language>` | Target language (`typescript\|python\|go\|java\|csharp\|swift\|kotlin\|terraform`) | **required** |
51
+ | `--format <format>` | Spec format (`auto\|openapi\|graphql\|grpc\|postman`) | `auto` |
52
+ | `--model <model>` | LLM model to use (e.g. `gpt-4o`, `claude-3.5-sonnet`) | server default |
53
+ | `--zod` | Include Zod runtime validation schemas (TypeScript only) | off |
54
+ | `--output <dir>` | Output directory | `.` (current directory) |
55
+
56
+ **Examples:**
57
+
58
+ ```bash
59
+ # Auto-detect format, generate Go SDK
60
+ sdk-pilot generate https://api.example.com/spec.yaml --lang go
61
+
62
+ # Force GraphQL format, use Claude model
63
+ sdk-pilot generate ./schema.graphql --lang typescript --format graphql --model claude-3.5-sonnet
64
+
65
+ # TypeScript SDK with Zod schemas
66
+ sdk-pilot generate https://api.example.com/openapi.json --lang typescript --zod --output ./sdk
67
+ ```
68
+
69
+ ### `sdk-pilot docs <spec-url-or-file>`
70
+
71
+ Generate API documentation from a spec.
72
+
73
+ ```bash
74
+ sdk-pilot docs https://petstore3.swagger.io/api/v3/openapi.json
75
+ sdk-pilot docs ./openapi.yaml --output ./docs
76
+ ```
77
+
78
+ **Options:**
79
+
80
+ | Flag | Description | Default |
81
+ |------|-------------|---------|
82
+ | `--format <format>` | Spec format (`auto\|openapi\|graphql\|grpc\|postman`) | `auto` |
83
+ | `--model <model>` | LLM model to use | server default |
84
+ | `--output <dir>` | Output directory | `.` (current directory) |
85
+
86
+ ### `sdk-pilot publish <dir>`
87
+
88
+ Publish an SDK directory to a package registry.
89
+
90
+ ```bash
91
+ sdk-pilot publish ./my-sdk --registry npm
92
+ sdk-pilot publish ./my-python-sdk --registry pypi
93
+ ```
94
+
95
+ **Options:**
96
+
97
+ | Flag | Description | Default |
98
+ |------|-------------|---------|
99
+ | `--registry <registry>` | Package registry (`npm\|pypi`) | `npm` |
100
+
101
+ ### `sdk-pilot mcp <spec-url>`
102
+
103
+ Generate an MCP (Model Context Protocol) server from an OpenAPI spec.
104
+
105
+ ```bash
106
+ sdk-pilot mcp https://petstore3.swagger.io/api/v3/openapi.json --name petstore-mcp
107
+ sdk-pilot mcp https://api.example.com/openapi.json --lang python --name my-api-mcp
108
+ ```
109
+
110
+ **Options:**
111
+
112
+ | Flag | Description | Default |
113
+ |------|-------------|---------|
114
+ | `--name <name>` | MCP server name | `my-mcp-server` |
115
+ | `--lang <language>` | Language (`typescript\|python`) | `typescript` |
116
+
117
+ ### `sdk-pilot config`
118
+
119
+ Show current configuration.
120
+
121
+ ```bash
122
+ sdk-pilot config
123
+ sdk-pilot config get apiKey
124
+ sdk-pilot config set defaultLang typescript
125
+ ```
126
+
127
+ ## Supported Languages
128
+
129
+ - TypeScript
130
+ - Python
131
+ - Go
132
+ - Java
133
+ - C#
134
+ - Swift
135
+ - Kotlin
136
+ - Terraform
137
+
138
+ ## Supported Spec Formats
139
+
140
+ - **OpenAPI / Swagger** (JSON & YAML)
141
+ - **GraphQL** (schema files)
142
+ - **gRPC** (proto files)
143
+ - **Postman** (collection JSON)
144
+
145
+ ## Configuration
146
+
147
+ Config is stored at `~/.sdk-pilot/config.json`:
148
+
149
+ ```json
150
+ {
151
+ "apiKey": "sk-...",
152
+ "defaultLang": "typescript",
153
+ "defaultOutput": ".",
154
+ "defaultFormat": "auto",
155
+ "defaultModel": "gpt-4o"
156
+ }
157
+ ```
158
+
159
+ ## License
160
+
161
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# 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,514 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const ora_1 = __importDefault(require("ora"));
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const path_1 = __importDefault(require("path"));
12
+ const os_1 = __importDefault(require("os"));
13
+ // ── Config helpers ──────────────────────────────────────────────────────
14
+ const CONFIG_DIR = path_1.default.join(os_1.default.homedir(), '.sdk-pilot');
15
+ const CONFIG_FILE = path_1.default.join(CONFIG_DIR, 'config.json');
16
+ function loadConfig() {
17
+ try {
18
+ if (fs_1.default.existsSync(CONFIG_FILE)) {
19
+ return JSON.parse(fs_1.default.readFileSync(CONFIG_FILE, 'utf-8'));
20
+ }
21
+ }
22
+ catch { /* ignore */ }
23
+ return {};
24
+ }
25
+ function saveConfig(cfg) {
26
+ if (!fs_1.default.existsSync(CONFIG_DIR)) {
27
+ fs_1.default.mkdirSync(CONFIG_DIR, { recursive: true });
28
+ }
29
+ fs_1.default.writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2), 'utf-8');
30
+ }
31
+ function getApiKey() {
32
+ const cfg = loadConfig();
33
+ if (!cfg.apiKey) {
34
+ console.error(chalk_1.default.red('Error: API key not set. Run `sdk-pilot auth <api-key>` first.'));
35
+ process.exit(1);
36
+ }
37
+ return cfg.apiKey;
38
+ }
39
+ // ── Constants ───────────────────────────────────────────────────────────
40
+ const BASE_URL = 'https://us-central1-mage-ai-601b3.cloudfunctions.net';
41
+ const SUPPORTED_LANGS = ['typescript', 'python', 'go', 'java', 'csharp', 'swift', 'kotlin', 'terraform'];
42
+ const SPEC_FORMATS = ['auto', 'openapi', 'graphql', 'grpc', 'postman'];
43
+ // ── SSE stream reader ──────────────────────────────────────────────────
44
+ async function* readSSE(response) {
45
+ const reader = response.body?.getReader();
46
+ if (!reader)
47
+ throw new Error('No response body');
48
+ const decoder = new TextDecoder();
49
+ let buffer = '';
50
+ while (true) {
51
+ const { done, value } = await reader.read();
52
+ if (done)
53
+ break;
54
+ buffer += decoder.decode(value, { stream: true });
55
+ const lines = buffer.split('\n');
56
+ buffer = lines.pop() || '';
57
+ let currentEvent;
58
+ let currentData = '';
59
+ for (const line of lines) {
60
+ if (line.startsWith('event:')) {
61
+ currentEvent = line.slice(6).trim();
62
+ }
63
+ else if (line.startsWith('data:')) {
64
+ currentData += line.slice(5).trim();
65
+ }
66
+ else if (line === '') {
67
+ if (currentData) {
68
+ yield { event: currentEvent, data: currentData };
69
+ currentEvent = undefined;
70
+ currentData = '';
71
+ }
72
+ }
73
+ }
74
+ }
75
+ if (buffer.trim()) {
76
+ const m = buffer.match(/^data:\s*(.+)$/s);
77
+ if (m)
78
+ yield { data: m[1] };
79
+ }
80
+ }
81
+ async function generateCommand(specUrlOrFile, options) {
82
+ const apiKey = getApiKey();
83
+ if (!SUPPORTED_LANGS.includes(options.lang)) {
84
+ console.error(chalk_1.default.red(`Unsupported language: ${options.lang}`));
85
+ console.error(chalk_1.default.yellow(`Supported: ${SUPPORTED_LANGS.join(', ')}`));
86
+ process.exit(1);
87
+ }
88
+ if (!SPEC_FORMATS.includes(options.format)) {
89
+ console.error(chalk_1.default.red(`Unsupported format: ${options.format}`));
90
+ console.error(chalk_1.default.yellow(`Supported: ${SPEC_FORMATS.join(', ')}`));
91
+ process.exit(1);
92
+ }
93
+ const lang = options.lang;
94
+ const format = options.format;
95
+ const outputDir = path_1.default.resolve(options.output || '.');
96
+ // Determine if specUrlOrFile is a file path or URL
97
+ let specUrl = specUrlOrFile;
98
+ let specContent = null;
99
+ if (fs_1.default.existsSync(specUrlOrFile)) {
100
+ specContent = fs_1.default.readFileSync(specUrlOrFile, 'utf-8');
101
+ specUrl = '';
102
+ }
103
+ else if (!specUrlOrFile.startsWith('http://') && !specUrlOrFile.startsWith('https://')) {
104
+ console.error(chalk_1.default.red('Error: spec-url-or-file must be a URL or a path to an existing file.'));
105
+ process.exit(1);
106
+ }
107
+ const spinner = (0, ora_1.default)('Generating SDK...').start();
108
+ try {
109
+ const body = { language: lang };
110
+ if (specUrl)
111
+ body.specUrl = specUrl;
112
+ if (specContent)
113
+ body.specContent = specContent;
114
+ if (format !== 'auto')
115
+ body.specFormat = format;
116
+ if (options.model)
117
+ body.model = options.model;
118
+ if (options.zod)
119
+ body.includeZodSchemas = true;
120
+ const response = await fetch(`${BASE_URL}/generateSdk`, {
121
+ method: 'POST',
122
+ headers: {
123
+ 'Content-Type': 'application/json',
124
+ 'Authorization': `Bearer ${apiKey}`,
125
+ },
126
+ body: JSON.stringify(body),
127
+ });
128
+ if (!response.ok) {
129
+ const errText = await response.text();
130
+ spinner.fail(`API error: ${response.status} ${response.statusText}`);
131
+ console.error(chalk_1.default.red(errText));
132
+ process.exit(1);
133
+ }
134
+ const contentType = response.headers.get('content-type') || '';
135
+ if (contentType.includes('text/event-stream')) {
136
+ // SSE stream
137
+ for await (const evt of readSSE(response)) {
138
+ try {
139
+ const parsed = JSON.parse(evt.data);
140
+ if (parsed.progress !== undefined) {
141
+ spinner.text = `Generating SDK... ${parsed.progress}%${parsed.message ? ' — ' + parsed.message : ''}`;
142
+ }
143
+ if (parsed.status === 'complete' || parsed.files) {
144
+ spinner.succeed('SDK generated successfully!');
145
+ writeFiles(parsed.files || {}, outputDir);
146
+ return;
147
+ }
148
+ if (parsed.error) {
149
+ spinner.fail(`Error: ${parsed.error}`);
150
+ process.exit(1);
151
+ }
152
+ }
153
+ catch {
154
+ // Non-JSON SSE data — skip
155
+ }
156
+ }
157
+ spinner.warn('Stream ended without completion signal.');
158
+ }
159
+ else {
160
+ // Regular JSON response
161
+ const result = await response.json();
162
+ if (result.error) {
163
+ spinner.fail(`Error: ${result.error}`);
164
+ process.exit(1);
165
+ }
166
+ spinner.succeed('SDK generated successfully!');
167
+ if (result.files) {
168
+ writeFiles(result.files, outputDir);
169
+ }
170
+ else {
171
+ console.log(chalk_1.default.green(JSON.stringify(result, null, 2)));
172
+ }
173
+ }
174
+ }
175
+ catch (err) {
176
+ spinner.fail('Generation failed');
177
+ console.error(chalk_1.default.red(err.message || err));
178
+ process.exit(1);
179
+ }
180
+ }
181
+ async function docsCommand(specUrlOrFile, options) {
182
+ const apiKey = getApiKey();
183
+ if (!SPEC_FORMATS.includes(options.format)) {
184
+ console.error(chalk_1.default.red(`Unsupported format: ${options.format}`));
185
+ console.error(chalk_1.default.yellow(`Supported: ${SPEC_FORMATS.join(', ')}`));
186
+ process.exit(1);
187
+ }
188
+ const format = options.format;
189
+ const outputDir = path_1.default.resolve(options.output || '.');
190
+ // Determine if specUrlOrFile is a file path or URL
191
+ let specUrl = specUrlOrFile;
192
+ let specContent = null;
193
+ if (fs_1.default.existsSync(specUrlOrFile)) {
194
+ specContent = fs_1.default.readFileSync(specUrlOrFile, 'utf-8');
195
+ specUrl = '';
196
+ }
197
+ else if (!specUrlOrFile.startsWith('http://') && !specUrlOrFile.startsWith('https://')) {
198
+ console.error(chalk_1.default.red('Error: spec-url-or-file must be a URL or a path to an existing file.'));
199
+ process.exit(1);
200
+ }
201
+ const spinner = (0, ora_1.default)('Generating API docs...').start();
202
+ try {
203
+ const body = {};
204
+ if (specUrl)
205
+ body.specUrl = specUrl;
206
+ if (specContent)
207
+ body.specContent = specContent;
208
+ if (format !== 'auto')
209
+ body.specFormat = format;
210
+ if (options.model)
211
+ body.model = options.model;
212
+ const response = await fetch(`${BASE_URL}/generateDocs`, {
213
+ method: 'POST',
214
+ headers: {
215
+ 'Content-Type': 'application/json',
216
+ 'Authorization': `Bearer ${apiKey}`,
217
+ },
218
+ body: JSON.stringify(body),
219
+ });
220
+ if (!response.ok) {
221
+ const errText = await response.text();
222
+ spinner.fail(`API error: ${response.status} ${response.statusText}`);
223
+ console.error(chalk_1.default.red(errText));
224
+ process.exit(1);
225
+ }
226
+ const contentType = response.headers.get('content-type') || '';
227
+ if (contentType.includes('text/event-stream')) {
228
+ for await (const evt of readSSE(response)) {
229
+ try {
230
+ const parsed = JSON.parse(evt.data);
231
+ if (parsed.progress !== undefined) {
232
+ spinner.text = `Generating docs... ${parsed.progress}%${parsed.message ? ' — ' + parsed.message : ''}`;
233
+ }
234
+ if (parsed.status === 'complete' || parsed.files) {
235
+ spinner.succeed('API docs generated successfully!');
236
+ writeFiles(parsed.files || {}, outputDir);
237
+ return;
238
+ }
239
+ if (parsed.error) {
240
+ spinner.fail(`Error: ${parsed.error}`);
241
+ process.exit(1);
242
+ }
243
+ }
244
+ catch { /* skip */ }
245
+ }
246
+ spinner.warn('Stream ended without completion signal.');
247
+ }
248
+ else {
249
+ const result = await response.json();
250
+ if (result.error) {
251
+ spinner.fail(`Error: ${result.error}`);
252
+ process.exit(1);
253
+ }
254
+ spinner.succeed('API docs generated successfully!');
255
+ if (result.files) {
256
+ writeFiles(result.files, outputDir);
257
+ }
258
+ else if (result.html || result.markdown) {
259
+ // Write single-file output
260
+ if (!fs_1.default.existsSync(outputDir)) {
261
+ fs_1.default.mkdirSync(outputDir, { recursive: true });
262
+ }
263
+ if (result.html) {
264
+ const outPath = path_1.default.join(outputDir, 'api-docs.html');
265
+ fs_1.default.writeFileSync(outPath, result.html, 'utf-8');
266
+ console.log(chalk_1.default.cyan(' Created: ') + 'api-docs.html');
267
+ console.log(chalk_1.default.green(`\n✅ API docs written to ${outPath}`));
268
+ }
269
+ if (result.markdown) {
270
+ const outPath = path_1.default.join(outputDir, 'api-docs.md');
271
+ fs_1.default.writeFileSync(outPath, result.markdown, 'utf-8');
272
+ console.log(chalk_1.default.cyan(' Created: ') + 'api-docs.md');
273
+ console.log(chalk_1.default.green(`\n✅ API docs written to ${outPath}`));
274
+ }
275
+ }
276
+ else {
277
+ console.log(chalk_1.default.green(JSON.stringify(result, null, 2)));
278
+ }
279
+ }
280
+ }
281
+ catch (err) {
282
+ spinner.fail('Docs generation failed');
283
+ console.error(chalk_1.default.red(err.message || err));
284
+ process.exit(1);
285
+ }
286
+ }
287
+ // ── File writer ─────────────────────────────────────────────────────────
288
+ function writeFiles(files, outputDir) {
289
+ if (!fs_1.default.existsSync(outputDir)) {
290
+ fs_1.default.mkdirSync(outputDir, { recursive: true });
291
+ }
292
+ for (const [filePath, content] of Object.entries(files)) {
293
+ const fullPath = path_1.default.join(outputDir, filePath);
294
+ const dir = path_1.default.dirname(fullPath);
295
+ if (!fs_1.default.existsSync(dir)) {
296
+ fs_1.default.mkdirSync(dir, { recursive: true });
297
+ }
298
+ fs_1.default.writeFileSync(fullPath, content, 'utf-8');
299
+ console.log(chalk_1.default.cyan(' Created: ') + filePath);
300
+ }
301
+ console.log(chalk_1.default.green(`\n✅ ${Object.keys(files).length} file(s) written to ${outputDir}`));
302
+ }
303
+ // ── Publish command ────────────────────────────────────────────────────
304
+ async function publishCommand(dir, options) {
305
+ const apiKey = getApiKey();
306
+ const registry = options.registry || 'npm';
307
+ if (!['npm', 'pypi'].includes(registry)) {
308
+ console.error(chalk_1.default.red(`Unsupported registry: ${registry}. Use 'npm' or 'pypi'.`));
309
+ process.exit(1);
310
+ }
311
+ const absDir = path_1.default.resolve(dir);
312
+ if (!fs_1.default.existsSync(absDir)) {
313
+ console.error(chalk_1.default.red(`Directory not found: ${absDir}`));
314
+ process.exit(1);
315
+ }
316
+ const spinner = (0, ora_1.default)(`Publishing to ${registry}...`).start();
317
+ try {
318
+ const response = await fetch(`${BASE_URL}/publishToRegistry`, {
319
+ method: 'POST',
320
+ headers: {
321
+ 'Content-Type': 'application/json',
322
+ 'Authorization': `Bearer ${apiKey}`,
323
+ },
324
+ body: JSON.stringify({
325
+ directory: absDir,
326
+ registry,
327
+ }),
328
+ });
329
+ if (!response.ok) {
330
+ const errText = await response.text();
331
+ spinner.fail(`API error: ${response.status}`);
332
+ console.error(chalk_1.default.red(errText));
333
+ process.exit(1);
334
+ }
335
+ const result = await response.json();
336
+ if (result.error) {
337
+ spinner.fail(`Error: ${result.error}`);
338
+ process.exit(1);
339
+ }
340
+ spinner.succeed(`Published to ${registry} successfully!`);
341
+ console.log(chalk_1.default.green(JSON.stringify(result, null, 2)));
342
+ }
343
+ catch (err) {
344
+ spinner.fail('Publish failed');
345
+ console.error(chalk_1.default.red(err.message || err));
346
+ process.exit(1);
347
+ }
348
+ }
349
+ // ── MCP command ─────────────────────────────────────────────────────────
350
+ async function mcpCommand(specUrl, options) {
351
+ const apiKey = getApiKey();
352
+ const lang = (options.lang || 'typescript');
353
+ if (!['typescript', 'python'].includes(lang)) {
354
+ console.error(chalk_1.default.red(`MCP server only supports: typescript, python`));
355
+ process.exit(1);
356
+ }
357
+ const name = options.name || 'my-mcp-server';
358
+ const spinner = (0, ora_1.default)(`Generating MCP server "${name}"...`).start();
359
+ try {
360
+ const response = await fetch(`${BASE_URL}/generateMcpServer`, {
361
+ method: 'POST',
362
+ headers: {
363
+ 'Content-Type': 'application/json',
364
+ 'Authorization': `Bearer ${apiKey}`,
365
+ },
366
+ body: JSON.stringify({
367
+ specUrl,
368
+ name,
369
+ language: lang,
370
+ }),
371
+ });
372
+ if (!response.ok) {
373
+ const errText = await response.text();
374
+ spinner.fail(`API error: ${response.status}`);
375
+ console.error(chalk_1.default.red(errText));
376
+ process.exit(1);
377
+ }
378
+ const contentType = response.headers.get('content-type') || '';
379
+ if (contentType.includes('text/event-stream')) {
380
+ for await (const evt of readSSE(response)) {
381
+ try {
382
+ const parsed = JSON.parse(evt.data);
383
+ if (parsed.progress !== undefined) {
384
+ spinner.text = `Generating MCP server... ${parsed.progress}%${parsed.message ? ' — ' + parsed.message : ''}`;
385
+ }
386
+ if (parsed.status === 'complete' || parsed.files) {
387
+ spinner.succeed('MCP server generated successfully!');
388
+ writeFiles(parsed.files || {}, `./${name}`);
389
+ return;
390
+ }
391
+ if (parsed.error) {
392
+ spinner.fail(`Error: ${parsed.error}`);
393
+ process.exit(1);
394
+ }
395
+ }
396
+ catch { /* skip */ }
397
+ }
398
+ }
399
+ else {
400
+ const result = await response.json();
401
+ if (result.error) {
402
+ spinner.fail(`Error: ${result.error}`);
403
+ process.exit(1);
404
+ }
405
+ spinner.succeed('MCP server generated successfully!');
406
+ if (result.files) {
407
+ writeFiles(result.files, `./${name}`);
408
+ }
409
+ else {
410
+ console.log(chalk_1.default.green(JSON.stringify(result, null, 2)));
411
+ }
412
+ }
413
+ }
414
+ catch (err) {
415
+ spinner.fail('MCP generation failed');
416
+ console.error(chalk_1.default.red(err.message || err));
417
+ process.exit(1);
418
+ }
419
+ }
420
+ // ── Auth command ────────────────────────────────────────────────────────
421
+ function authCommand(apiKey) {
422
+ const cfg = loadConfig();
423
+ cfg.apiKey = apiKey;
424
+ saveConfig(cfg);
425
+ console.log(chalk_1.default.green('✅ API key saved to ' + CONFIG_FILE));
426
+ }
427
+ // ── Config command ──────────────────────────────────────────────────────
428
+ function configCommand(action, key, value) {
429
+ const cfg = loadConfig();
430
+ // Handle get/set subcommands
431
+ if (action === 'get' && key) {
432
+ if (cfg[key] !== undefined) {
433
+ const val = cfg[key];
434
+ if (key === 'apiKey' && typeof val === 'string') {
435
+ console.log(`${key}: ${val.slice(0, 8)}${'*'.repeat(Math.max(0, val.length - 8))}`);
436
+ }
437
+ else {
438
+ console.log(`${key}: ${val}`);
439
+ }
440
+ }
441
+ else {
442
+ console.log(chalk_1.default.yellow(`Key '${key}' not set.`));
443
+ }
444
+ return;
445
+ }
446
+ if (action === 'set' && key && value !== undefined) {
447
+ cfg[key] = value;
448
+ saveConfig(cfg);
449
+ console.log(chalk_1.default.green(`✅ Set ${key}`));
450
+ return;
451
+ }
452
+ if (Object.keys(cfg).length === 0) {
453
+ console.log(chalk_1.default.yellow('No configuration found.'));
454
+ console.log(chalk_1.default.gray(`Config file: ${CONFIG_FILE}`));
455
+ console.log(chalk_1.default.gray('Run `sdk-pilot auth <api-key>` to set your API key.'));
456
+ return;
457
+ }
458
+ console.log(chalk_1.default.bold('SDK Pilot Configuration'));
459
+ console.log(chalk_1.default.gray(`Config file: ${CONFIG_FILE}\n`));
460
+ for (const [key, value] of Object.entries(cfg)) {
461
+ if (key === 'apiKey' && typeof value === 'string') {
462
+ console.log(` ${chalk_1.default.cyan(key)}: ${value.slice(0, 8)}${'*'.repeat(Math.max(0, value.length - 8))}`);
463
+ }
464
+ else {
465
+ console.log(` ${chalk_1.default.cyan(key)}: ${value}`);
466
+ }
467
+ }
468
+ }
469
+ // ── Main program ───────────────────────────────────────────────────────
470
+ const program = new commander_1.Command();
471
+ program
472
+ .name('sdk-pilot')
473
+ .description('SDK Pilot CLI — Generate SDKs, API docs, publish packages, and create MCP servers from API specs')
474
+ .version('1.1.0');
475
+ program
476
+ .command('generate <spec-url-or-file>')
477
+ .description('Generate an SDK from an API spec URL or local file')
478
+ .requiredOption('--lang <language>', `Target language (${SUPPORTED_LANGS.join('|')})`)
479
+ .option('--format <spec-format>', `Spec format (${SPEC_FORMATS.join('|')})`, 'auto')
480
+ .option('--model <llm-model>', 'LLM model to use (e.g. gpt-4o, claude-3.5-sonnet)')
481
+ .option('--zod', 'Include Zod runtime validation schemas (TypeScript only)')
482
+ .option('--output <dir>', 'Output directory', '.')
483
+ .action(generateCommand);
484
+ program
485
+ .command('docs <spec-url-or-file>')
486
+ .description('Generate API documentation from an API spec URL or local file')
487
+ .option('--format <spec-format>', `Spec format (${SPEC_FORMATS.join('|')})`, 'auto')
488
+ .option('--model <llm-model>', 'LLM model to use (e.g. gpt-4o, claude-3.5-sonnet)')
489
+ .option('--output <dir>', 'Output directory', '.')
490
+ .action(docsCommand);
491
+ program
492
+ .command('publish <dir>')
493
+ .description('Publish an SDK to a package registry')
494
+ .option('--registry <registry>', 'Package registry (npm|pypi)', 'npm')
495
+ .action(publishCommand);
496
+ program
497
+ .command('mcp <spec-url>')
498
+ .description('Generate an MCP server from an OpenAPI spec')
499
+ .option('--name <server-name>', 'MCP server name', 'my-mcp-server')
500
+ .option('--lang <language>', 'Language (typescript|python)', 'typescript')
501
+ .action(mcpCommand);
502
+ program
503
+ .command('auth <api-key>')
504
+ .description('Save your SDK Pilot API key')
505
+ .action(authCommand);
506
+ program
507
+ .command('config')
508
+ .description('Show current configuration, or get/set individual values')
509
+ .argument('[action]', 'get or set')
510
+ .argument('[key]', 'config key')
511
+ .argument('[value]', 'config value (for set)')
512
+ .action(configCommand);
513
+ program.parse(process.argv);
514
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "sdk-pilot-cli",
3
+ "version": "1.1.0",
4
+ "description": "CLI tool for SDK Pilot \u2014 generate SDKs & API docs, publish packages, and create MCP servers from API specs",
5
+ "bin": {
6
+ "sdk-pilot": "./dist/index.js"
7
+ },
8
+ "main": "dist/index.js",
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "start": "node dist/index.js"
12
+ },
13
+ "dependencies": {
14
+ "commander": "^12.1.0",
15
+ "chalk": "^4.1.2",
16
+ "ora": "^5.4.1",
17
+ "node-fetch": "^2.7.0"
18
+ },
19
+ "devDependencies": {
20
+ "typescript": "^5.4.5",
21
+ "@types/node": "^20.14.2"
22
+ },
23
+ "keywords": [
24
+ "sdk",
25
+ "openapi",
26
+ "swagger",
27
+ "cli",
28
+ "generator",
29
+ "mcp"
30
+ ],
31
+ "license": "MIT"
32
+ }
package/src/index.ts ADDED
@@ -0,0 +1,584 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import chalk from 'chalk';
5
+ import ora from 'ora';
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import os from 'os';
9
+ import { execSync } from 'child_process';
10
+
11
+ // ── Config helpers ──────────────────────────────────────────────────────
12
+ const CONFIG_DIR = path.join(os.homedir(), '.sdk-pilot');
13
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
14
+
15
+ interface Config {
16
+ apiKey?: string;
17
+ defaultLang?: string;
18
+ defaultOutput?: string;
19
+ defaultFormat?: string;
20
+ defaultModel?: string;
21
+ }
22
+
23
+ function loadConfig(): Config {
24
+ try {
25
+ if (fs.existsSync(CONFIG_FILE)) {
26
+ return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
27
+ }
28
+ } catch { /* ignore */ }
29
+ return {};
30
+ }
31
+
32
+ function saveConfig(cfg: Config): void {
33
+ if (!fs.existsSync(CONFIG_DIR)) {
34
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
35
+ }
36
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(cfg, null, 2), 'utf-8');
37
+ }
38
+
39
+ function getApiKey(): string {
40
+ const cfg = loadConfig();
41
+ if (!cfg.apiKey) {
42
+ console.error(chalk.red('Error: API key not set. Run `sdk-pilot auth <api-key>` first.'));
43
+ process.exit(1);
44
+ }
45
+ return cfg.apiKey;
46
+ }
47
+
48
+ // ── Constants ───────────────────────────────────────────────────────────
49
+ const BASE_URL = 'https://us-central1-mage-ai-601b3.cloudfunctions.net';
50
+
51
+ const SUPPORTED_LANGS = ['typescript', 'python', 'go', 'java', 'csharp', 'swift', 'kotlin', 'terraform'] as const;
52
+ type Lang = typeof SUPPORTED_LANGS[number];
53
+
54
+ const SPEC_FORMATS = ['auto', 'openapi', 'graphql', 'grpc', 'postman'] as const;
55
+ type SpecFormat = typeof SPEC_FORMATS[number];
56
+
57
+ // ── SSE stream reader ──────────────────────────────────────────────────
58
+ async function* readSSE(response: Response): AsyncGenerator<{ event?: string; data: string }> {
59
+ const reader = response.body?.getReader();
60
+ if (!reader) throw new Error('No response body');
61
+
62
+ const decoder = new TextDecoder();
63
+ let buffer = '';
64
+
65
+ while (true) {
66
+ const { done, value } = await reader.read();
67
+ if (done) break;
68
+
69
+ buffer += decoder.decode(value, { stream: true });
70
+ const lines = buffer.split('\n');
71
+ buffer = lines.pop() || '';
72
+
73
+ let currentEvent: string | undefined;
74
+ let currentData = '';
75
+
76
+ for (const line of lines) {
77
+ if (line.startsWith('event:')) {
78
+ currentEvent = line.slice(6).trim();
79
+ } else if (line.startsWith('data:')) {
80
+ currentData += line.slice(5).trim();
81
+ } else if (line === '') {
82
+ if (currentData) {
83
+ yield { event: currentEvent, data: currentData };
84
+ currentEvent = undefined;
85
+ currentData = '';
86
+ }
87
+ }
88
+ }
89
+ }
90
+
91
+ if (buffer.trim()) {
92
+ const m = buffer.match(/^data:\s*(.+)$/s);
93
+ if (m) yield { data: m[1] };
94
+ }
95
+ }
96
+
97
+ // ── Generate command ───────────────────────────────────────────────────
98
+ interface GenerateOptions {
99
+ lang: string;
100
+ output: string;
101
+ format: string;
102
+ model: string;
103
+ zod: boolean;
104
+ }
105
+
106
+ async function generateCommand(specUrlOrFile: string, options: GenerateOptions) {
107
+ const apiKey = getApiKey();
108
+
109
+ if (!SUPPORTED_LANGS.includes(options.lang as Lang)) {
110
+ console.error(chalk.red(`Unsupported language: ${options.lang}`));
111
+ console.error(chalk.yellow(`Supported: ${SUPPORTED_LANGS.join(', ')}`));
112
+ process.exit(1);
113
+ }
114
+
115
+ if (!SPEC_FORMATS.includes(options.format as SpecFormat)) {
116
+ console.error(chalk.red(`Unsupported format: ${options.format}`));
117
+ console.error(chalk.yellow(`Supported: ${SPEC_FORMATS.join(', ')}`));
118
+ process.exit(1);
119
+ }
120
+
121
+ const lang = options.lang as Lang;
122
+ const format = options.format as SpecFormat;
123
+ const outputDir = path.resolve(options.output || '.');
124
+
125
+ // Determine if specUrlOrFile is a file path or URL
126
+ let specUrl = specUrlOrFile;
127
+ let specContent: string | null = null;
128
+
129
+ if (fs.existsSync(specUrlOrFile)) {
130
+ specContent = fs.readFileSync(specUrlOrFile, 'utf-8');
131
+ specUrl = '';
132
+ } else if (!specUrlOrFile.startsWith('http://') && !specUrlOrFile.startsWith('https://')) {
133
+ console.error(chalk.red('Error: spec-url-or-file must be a URL or a path to an existing file.'));
134
+ process.exit(1);
135
+ }
136
+
137
+ const spinner = ora('Generating SDK...').start();
138
+
139
+ try {
140
+ const body: Record<string, unknown> = { language: lang };
141
+ if (specUrl) body.specUrl = specUrl;
142
+ if (specContent) body.specContent = specContent;
143
+ if (format !== 'auto') body.specFormat = format;
144
+ if (options.model) body.model = options.model;
145
+ if (options.zod) body.includeZodSchemas = true;
146
+
147
+ const response = await fetch(`${BASE_URL}/generateSdk`, {
148
+ method: 'POST',
149
+ headers: {
150
+ 'Content-Type': 'application/json',
151
+ 'Authorization': `Bearer ${apiKey}`,
152
+ },
153
+ body: JSON.stringify(body),
154
+ });
155
+
156
+ if (!response.ok) {
157
+ const errText = await response.text();
158
+ spinner.fail(`API error: ${response.status} ${response.statusText}`);
159
+ console.error(chalk.red(errText));
160
+ process.exit(1);
161
+ }
162
+
163
+ const contentType = response.headers.get('content-type') || '';
164
+
165
+ if (contentType.includes('text/event-stream')) {
166
+ // SSE stream
167
+ for await (const evt of readSSE(response)) {
168
+ try {
169
+ const parsed = JSON.parse(evt.data);
170
+
171
+ if (parsed.progress !== undefined) {
172
+ spinner.text = `Generating SDK... ${parsed.progress}%${parsed.message ? ' — ' + parsed.message : ''}`;
173
+ }
174
+ if (parsed.status === 'complete' || parsed.files) {
175
+ spinner.succeed('SDK generated successfully!');
176
+ writeFiles(parsed.files || {}, outputDir);
177
+ return;
178
+ }
179
+ if (parsed.error) {
180
+ spinner.fail(`Error: ${parsed.error}`);
181
+ process.exit(1);
182
+ }
183
+ } catch {
184
+ // Non-JSON SSE data — skip
185
+ }
186
+ }
187
+ spinner.warn('Stream ended without completion signal.');
188
+ } else {
189
+ // Regular JSON response
190
+ const result = await response.json() as Record<string, any>;
191
+
192
+ if (result.error) {
193
+ spinner.fail(`Error: ${result.error}`);
194
+ process.exit(1);
195
+ }
196
+
197
+ spinner.succeed('SDK generated successfully!');
198
+
199
+ if (result.files) {
200
+ writeFiles(result.files, outputDir);
201
+ } else {
202
+ console.log(chalk.green(JSON.stringify(result, null, 2)));
203
+ }
204
+ }
205
+ } catch (err: any) {
206
+ spinner.fail('Generation failed');
207
+ console.error(chalk.red(err.message || err));
208
+ process.exit(1);
209
+ }
210
+ }
211
+
212
+ // ── Docs command ────────────────────────────────────────────────────────
213
+ interface DocsOptions {
214
+ format: string;
215
+ model: string;
216
+ output: string;
217
+ }
218
+
219
+ async function docsCommand(specUrlOrFile: string, options: DocsOptions) {
220
+ const apiKey = getApiKey();
221
+
222
+ if (!SPEC_FORMATS.includes(options.format as SpecFormat)) {
223
+ console.error(chalk.red(`Unsupported format: ${options.format}`));
224
+ console.error(chalk.yellow(`Supported: ${SPEC_FORMATS.join(', ')}`));
225
+ process.exit(1);
226
+ }
227
+
228
+ const format = options.format as SpecFormat;
229
+ const outputDir = path.resolve(options.output || '.');
230
+
231
+ // Determine if specUrlOrFile is a file path or URL
232
+ let specUrl = specUrlOrFile;
233
+ let specContent: string | null = null;
234
+
235
+ if (fs.existsSync(specUrlOrFile)) {
236
+ specContent = fs.readFileSync(specUrlOrFile, 'utf-8');
237
+ specUrl = '';
238
+ } else if (!specUrlOrFile.startsWith('http://') && !specUrlOrFile.startsWith('https://')) {
239
+ console.error(chalk.red('Error: spec-url-or-file must be a URL or a path to an existing file.'));
240
+ process.exit(1);
241
+ }
242
+
243
+ const spinner = ora('Generating API docs...').start();
244
+
245
+ try {
246
+ const body: Record<string, unknown> = {};
247
+ if (specUrl) body.specUrl = specUrl;
248
+ if (specContent) body.specContent = specContent;
249
+ if (format !== 'auto') body.specFormat = format;
250
+ if (options.model) body.model = options.model;
251
+
252
+ const response = await fetch(`${BASE_URL}/generateDocs`, {
253
+ method: 'POST',
254
+ headers: {
255
+ 'Content-Type': 'application/json',
256
+ 'Authorization': `Bearer ${apiKey}`,
257
+ },
258
+ body: JSON.stringify(body),
259
+ });
260
+
261
+ if (!response.ok) {
262
+ const errText = await response.text();
263
+ spinner.fail(`API error: ${response.status} ${response.statusText}`);
264
+ console.error(chalk.red(errText));
265
+ process.exit(1);
266
+ }
267
+
268
+ const contentType = response.headers.get('content-type') || '';
269
+
270
+ if (contentType.includes('text/event-stream')) {
271
+ for await (const evt of readSSE(response)) {
272
+ try {
273
+ const parsed = JSON.parse(evt.data);
274
+ if (parsed.progress !== undefined) {
275
+ spinner.text = `Generating docs... ${parsed.progress}%${parsed.message ? ' — ' + parsed.message : ''}`;
276
+ }
277
+ if (parsed.status === 'complete' || parsed.files) {
278
+ spinner.succeed('API docs generated successfully!');
279
+ writeFiles(parsed.files || {}, outputDir);
280
+ return;
281
+ }
282
+ if (parsed.error) {
283
+ spinner.fail(`Error: ${parsed.error}`);
284
+ process.exit(1);
285
+ }
286
+ } catch { /* skip */ }
287
+ }
288
+ spinner.warn('Stream ended without completion signal.');
289
+ } else {
290
+ const result = await response.json() as Record<string, any>;
291
+
292
+ if (result.error) {
293
+ spinner.fail(`Error: ${result.error}`);
294
+ process.exit(1);
295
+ }
296
+
297
+ spinner.succeed('API docs generated successfully!');
298
+
299
+ if (result.files) {
300
+ writeFiles(result.files, outputDir);
301
+ } else if (result.html || result.markdown) {
302
+ // Write single-file output
303
+ if (!fs.existsSync(outputDir)) {
304
+ fs.mkdirSync(outputDir, { recursive: true });
305
+ }
306
+ if (result.html) {
307
+ const outPath = path.join(outputDir, 'api-docs.html');
308
+ fs.writeFileSync(outPath, result.html, 'utf-8');
309
+ console.log(chalk.cyan(' Created: ') + 'api-docs.html');
310
+ console.log(chalk.green(`\n✅ API docs written to ${outPath}`));
311
+ }
312
+ if (result.markdown) {
313
+ const outPath = path.join(outputDir, 'api-docs.md');
314
+ fs.writeFileSync(outPath, result.markdown, 'utf-8');
315
+ console.log(chalk.cyan(' Created: ') + 'api-docs.md');
316
+ console.log(chalk.green(`\n✅ API docs written to ${outPath}`));
317
+ }
318
+ } else {
319
+ console.log(chalk.green(JSON.stringify(result, null, 2)));
320
+ }
321
+ }
322
+ } catch (err: any) {
323
+ spinner.fail('Docs generation failed');
324
+ console.error(chalk.red(err.message || err));
325
+ process.exit(1);
326
+ }
327
+ }
328
+
329
+ // ── File writer ─────────────────────────────────────────────────────────
330
+ function writeFiles(files: Record<string, string>, outputDir: string): void {
331
+ if (!fs.existsSync(outputDir)) {
332
+ fs.mkdirSync(outputDir, { recursive: true });
333
+ }
334
+
335
+ for (const [filePath, content] of Object.entries(files)) {
336
+ const fullPath = path.join(outputDir, filePath);
337
+ const dir = path.dirname(fullPath);
338
+ if (!fs.existsSync(dir)) {
339
+ fs.mkdirSync(dir, { recursive: true });
340
+ }
341
+ fs.writeFileSync(fullPath, content, 'utf-8');
342
+ console.log(chalk.cyan(' Created: ') + filePath);
343
+ }
344
+
345
+ console.log(chalk.green(`\n✅ ${Object.keys(files).length} file(s) written to ${outputDir}`));
346
+ }
347
+
348
+ // ── Publish command ────────────────────────────────────────────────────
349
+ async function publishCommand(dir: string, options: { registry: string }) {
350
+ const apiKey = getApiKey();
351
+ const registry = options.registry || 'npm';
352
+
353
+ if (!['npm', 'pypi'].includes(registry)) {
354
+ console.error(chalk.red(`Unsupported registry: ${registry}. Use 'npm' or 'pypi'.`));
355
+ process.exit(1);
356
+ }
357
+
358
+ const absDir = path.resolve(dir);
359
+ if (!fs.existsSync(absDir)) {
360
+ console.error(chalk.red(`Directory not found: ${absDir}`));
361
+ process.exit(1);
362
+ }
363
+
364
+ const spinner = ora(`Publishing to ${registry}...`).start();
365
+
366
+ try {
367
+ const response = await fetch(`${BASE_URL}/publishToRegistry`, {
368
+ method: 'POST',
369
+ headers: {
370
+ 'Content-Type': 'application/json',
371
+ 'Authorization': `Bearer ${apiKey}`,
372
+ },
373
+ body: JSON.stringify({
374
+ directory: absDir,
375
+ registry,
376
+ }),
377
+ });
378
+
379
+ if (!response.ok) {
380
+ const errText = await response.text();
381
+ spinner.fail(`API error: ${response.status}`);
382
+ console.error(chalk.red(errText));
383
+ process.exit(1);
384
+ }
385
+
386
+ const result = await response.json() as Record<string, any>;
387
+
388
+ if (result.error) {
389
+ spinner.fail(`Error: ${result.error}`);
390
+ process.exit(1);
391
+ }
392
+
393
+ spinner.succeed(`Published to ${registry} successfully!`);
394
+ console.log(chalk.green(JSON.stringify(result, null, 2)));
395
+ } catch (err: any) {
396
+ spinner.fail('Publish failed');
397
+ console.error(chalk.red(err.message || err));
398
+ process.exit(1);
399
+ }
400
+ }
401
+
402
+ // ── MCP command ─────────────────────────────────────────────────────────
403
+ async function mcpCommand(specUrl: string, options: { name: string; lang: string }) {
404
+ const apiKey = getApiKey();
405
+ const lang = (options.lang || 'typescript') as string;
406
+
407
+ if (!['typescript', 'python'].includes(lang)) {
408
+ console.error(chalk.red(`MCP server only supports: typescript, python`));
409
+ process.exit(1);
410
+ }
411
+
412
+ const name = options.name || 'my-mcp-server';
413
+ const spinner = ora(`Generating MCP server "${name}"...`).start();
414
+
415
+ try {
416
+ const response = await fetch(`${BASE_URL}/generateMcpServer`, {
417
+ method: 'POST',
418
+ headers: {
419
+ 'Content-Type': 'application/json',
420
+ 'Authorization': `Bearer ${apiKey}`,
421
+ },
422
+ body: JSON.stringify({
423
+ specUrl,
424
+ name,
425
+ language: lang,
426
+ }),
427
+ });
428
+
429
+ if (!response.ok) {
430
+ const errText = await response.text();
431
+ spinner.fail(`API error: ${response.status}`);
432
+ console.error(chalk.red(errText));
433
+ process.exit(1);
434
+ }
435
+
436
+ const contentType = response.headers.get('content-type') || '';
437
+
438
+ if (contentType.includes('text/event-stream')) {
439
+ for await (const evt of readSSE(response)) {
440
+ try {
441
+ const parsed = JSON.parse(evt.data);
442
+ if (parsed.progress !== undefined) {
443
+ spinner.text = `Generating MCP server... ${parsed.progress}%${parsed.message ? ' — ' + parsed.message : ''}`;
444
+ }
445
+ if (parsed.status === 'complete' || parsed.files) {
446
+ spinner.succeed('MCP server generated successfully!');
447
+ writeFiles(parsed.files || {}, `./${name}`);
448
+ return;
449
+ }
450
+ if (parsed.error) {
451
+ spinner.fail(`Error: ${parsed.error}`);
452
+ process.exit(1);
453
+ }
454
+ } catch { /* skip */ }
455
+ }
456
+ } else {
457
+ const result = await response.json() as Record<string, any>;
458
+
459
+ if (result.error) {
460
+ spinner.fail(`Error: ${result.error}`);
461
+ process.exit(1);
462
+ }
463
+
464
+ spinner.succeed('MCP server generated successfully!');
465
+
466
+ if (result.files) {
467
+ writeFiles(result.files, `./${name}`);
468
+ } else {
469
+ console.log(chalk.green(JSON.stringify(result, null, 2)));
470
+ }
471
+ }
472
+ } catch (err: any) {
473
+ spinner.fail('MCP generation failed');
474
+ console.error(chalk.red(err.message || err));
475
+ process.exit(1);
476
+ }
477
+ }
478
+
479
+ // ── Auth command ────────────────────────────────────────────────────────
480
+ function authCommand(apiKey: string) {
481
+ const cfg = loadConfig();
482
+ cfg.apiKey = apiKey;
483
+ saveConfig(cfg);
484
+ console.log(chalk.green('✅ API key saved to ' + CONFIG_FILE));
485
+ }
486
+
487
+ // ── Config command ──────────────────────────────────────────────────────
488
+ function configCommand(action?: string, key?: string, value?: string) {
489
+ const cfg = loadConfig();
490
+
491
+ // Handle get/set subcommands
492
+ if (action === 'get' && key) {
493
+ if (cfg[key as keyof Config] !== undefined) {
494
+ const val = cfg[key as keyof Config];
495
+ if (key === 'apiKey' && typeof val === 'string') {
496
+ console.log(`${key}: ${val.slice(0, 8)}${'*'.repeat(Math.max(0, val.length - 8))}`);
497
+ } else {
498
+ console.log(`${key}: ${val}`);
499
+ }
500
+ } else {
501
+ console.log(chalk.yellow(`Key '${key}' not set.`));
502
+ }
503
+ return;
504
+ }
505
+
506
+ if (action === 'set' && key && value !== undefined) {
507
+ (cfg as any)[key] = value;
508
+ saveConfig(cfg);
509
+ console.log(chalk.green(`✅ Set ${key}`));
510
+ return;
511
+ }
512
+
513
+ if (Object.keys(cfg).length === 0) {
514
+ console.log(chalk.yellow('No configuration found.'));
515
+ console.log(chalk.gray(`Config file: ${CONFIG_FILE}`));
516
+ console.log(chalk.gray('Run `sdk-pilot auth <api-key>` to set your API key.'));
517
+ return;
518
+ }
519
+
520
+ console.log(chalk.bold('SDK Pilot Configuration'));
521
+ console.log(chalk.gray(`Config file: ${CONFIG_FILE}\n`));
522
+
523
+ for (const [key, value] of Object.entries(cfg)) {
524
+ if (key === 'apiKey' && typeof value === 'string') {
525
+ console.log(` ${chalk.cyan(key)}: ${value.slice(0, 8)}${'*'.repeat(Math.max(0, value.length - 8))}`);
526
+ } else {
527
+ console.log(` ${chalk.cyan(key)}: ${value}`);
528
+ }
529
+ }
530
+ }
531
+
532
+ // ── Main program ───────────────────────────────────────────────────────
533
+ const program = new Command();
534
+
535
+ program
536
+ .name('sdk-pilot')
537
+ .description('SDK Pilot CLI — Generate SDKs, API docs, publish packages, and create MCP servers from API specs')
538
+ .version('1.1.0');
539
+
540
+ program
541
+ .command('generate <spec-url-or-file>')
542
+ .description('Generate an SDK from an API spec URL or local file')
543
+ .requiredOption('--lang <language>', `Target language (${SUPPORTED_LANGS.join('|')})`)
544
+ .option('--format <spec-format>', `Spec format (${SPEC_FORMATS.join('|')})`, 'auto')
545
+ .option('--model <llm-model>', 'LLM model to use (e.g. gpt-4o, claude-3.5-sonnet)')
546
+ .option('--zod', 'Include Zod runtime validation schemas (TypeScript only)')
547
+ .option('--output <dir>', 'Output directory', '.')
548
+ .action(generateCommand);
549
+
550
+ program
551
+ .command('docs <spec-url-or-file>')
552
+ .description('Generate API documentation from an API spec URL or local file')
553
+ .option('--format <spec-format>', `Spec format (${SPEC_FORMATS.join('|')})`, 'auto')
554
+ .option('--model <llm-model>', 'LLM model to use (e.g. gpt-4o, claude-3.5-sonnet)')
555
+ .option('--output <dir>', 'Output directory', '.')
556
+ .action(docsCommand);
557
+
558
+ program
559
+ .command('publish <dir>')
560
+ .description('Publish an SDK to a package registry')
561
+ .option('--registry <registry>', 'Package registry (npm|pypi)', 'npm')
562
+ .action(publishCommand);
563
+
564
+ program
565
+ .command('mcp <spec-url>')
566
+ .description('Generate an MCP server from an OpenAPI spec')
567
+ .option('--name <server-name>', 'MCP server name', 'my-mcp-server')
568
+ .option('--lang <language>', 'Language (typescript|python)', 'typescript')
569
+ .action(mcpCommand);
570
+
571
+ program
572
+ .command('auth <api-key>')
573
+ .description('Save your SDK Pilot API key')
574
+ .action(authCommand);
575
+
576
+ program
577
+ .command('config')
578
+ .description('Show current configuration, or get/set individual values')
579
+ .argument('[action]', 'get or set')
580
+ .argument('[key]', 'config key')
581
+ .argument('[value]', 'config value (for set)')
582
+ .action(configCommand);
583
+
584
+ program.parse(process.argv);
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "commonjs",
5
+ "lib": ["ES2020"],
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "resolveJsonModule": true,
13
+ "declaration": true,
14
+ "declarationMap": true,
15
+ "sourceMap": true
16
+ },
17
+ "include": ["src/**/*"],
18
+ "exclude": ["node_modules", "dist"]
19
+ }