swytchcode 2.6.0 → 2.6.2
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/bin/swytchcode.js +90 -43
- package/package.json +7 -7
package/bin/swytchcode.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
process.on('SIGINT', () => {
|
|
5
|
+
try { process.stdin.setRawMode(false); } catch (_) {} // prevent stuck raw mode on Windows CMD
|
|
6
|
+
process.stdout.write('\x1b[?25h'); // restore cursor
|
|
7
|
+
process.exit(130);
|
|
8
|
+
});
|
|
9
|
+
|
|
4
10
|
const { spawnSync, execSync } = require('child_process');
|
|
5
11
|
const fs = require('fs');
|
|
6
12
|
const path = require('path');
|
|
@@ -45,7 +51,20 @@ function stripAnsi(str) {
|
|
|
45
51
|
function ask(prompt) {
|
|
46
52
|
return new Promise(resolve => {
|
|
47
53
|
const iface = rl.createInterface({ input: process.stdin, output: process.stdout });
|
|
48
|
-
|
|
54
|
+
|
|
55
|
+
function onClose() {
|
|
56
|
+
try { process.stdin.setRawMode(false); } catch (_) {}
|
|
57
|
+
process.stdout.write('\x1b[?25h');
|
|
58
|
+
process.exit(130);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
iface.on('close', onClose);
|
|
62
|
+
|
|
63
|
+
iface.question(prompt, answer => {
|
|
64
|
+
iface.removeListener('close', onClose); // only removes this specific listener
|
|
65
|
+
iface.close();
|
|
66
|
+
resolve(answer.trim());
|
|
67
|
+
});
|
|
49
68
|
});
|
|
50
69
|
}
|
|
51
70
|
|
|
@@ -188,17 +207,27 @@ function apiPost(urlStr, body) {
|
|
|
188
207
|
// ─── Binary resolution (shared by normal pass-through AND onboarding) ────────
|
|
189
208
|
function spawnBin(binPath, args, extraEnv = {}) {
|
|
190
209
|
const env = { ...process.env, ...extraEnv };
|
|
210
|
+
let result;
|
|
191
211
|
if (process.stdin.isTTY) {
|
|
192
|
-
|
|
212
|
+
result = spawnSync(binPath, args, { stdio: 'inherit', env });
|
|
213
|
+
} else {
|
|
214
|
+
let stdinData;
|
|
215
|
+
try { stdinData = fs.readFileSync(0); }
|
|
216
|
+
catch (_) { stdinData = Buffer.alloc(0); }
|
|
217
|
+
result = spawnSync(binPath, args, {
|
|
218
|
+
stdio: ['pipe', 'inherit', 'inherit'],
|
|
219
|
+
input: stdinData,
|
|
220
|
+
env,
|
|
221
|
+
});
|
|
193
222
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
223
|
+
|
|
224
|
+
if (result.signal === 'SIGINT') {
|
|
225
|
+
try { process.stdin.setRawMode(false); } catch (_) {}
|
|
226
|
+
process.stdout.write('\x1b[?25h');
|
|
227
|
+
process.exit(130);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return result;
|
|
202
231
|
}
|
|
203
232
|
|
|
204
233
|
function exitCode(result) {
|
|
@@ -271,6 +300,8 @@ const userArgs = process.argv.slice(2);
|
|
|
271
300
|
// Capture original arg BEFORE mutation
|
|
272
301
|
const originalArg = process.argv[2] || '';
|
|
273
302
|
const isCanonicalDemoArg = /^[\w]+\.[\w.]+$/.test(originalArg) && !originalArg.startsWith('-');
|
|
303
|
+
// A single bare word under npx is a potential (invalid) demo lookup — don't pass through to cobra
|
|
304
|
+
const isNpxBareWordArg = isNpx && userArgs.length === 1 && /^[\w]+$/.test(originalArg) && !originalArg.startsWith('-');
|
|
274
305
|
// Legacy support: npx swytchcode <canonical_id> → npx swytchcode exec <canonical_id>
|
|
275
306
|
if (userArgs.length > 0 && /^[\w]+\.[\w.]+$/.test(userArgs[0]) && !userArgs[0].startsWith('-')) {
|
|
276
307
|
userArgs.unshift('exec');
|
|
@@ -293,28 +324,9 @@ async function runOnboardingDirectDemo(canonicalId) {
|
|
|
293
324
|
await runOnboardingSteps2to4();
|
|
294
325
|
}
|
|
295
326
|
|
|
296
|
-
// ───
|
|
297
|
-
if (!isNpx || (userArgs.length > 0 && !isCanonicalDemoArg)) {
|
|
298
|
-
const result = spawnBin(binPath, userArgs);
|
|
299
|
-
if (result.error) {
|
|
300
|
-
err(`swytchcode: failed to launch binary: ${result.error.message}`);
|
|
301
|
-
}
|
|
302
|
-
process.exit(exitCode(result));
|
|
303
|
-
}
|
|
304
|
-
// ─── NPX with canonical ID: run demo directly then show onboarding ───────────
|
|
305
|
-
if (isNpx && isCanonicalDemoArg) {
|
|
306
|
-
runOnboardingDirectDemo(originalArg).catch(e => {
|
|
307
|
-
err(`\nswytchcode: onboarding error (${e.message}) — falling back to CLI.\n`);
|
|
308
|
-
const result = spawnBin(binPath, userArgs);
|
|
309
|
-
process.exit(exitCode(result));
|
|
310
|
-
});
|
|
311
|
-
} else {
|
|
312
|
-
// ─── NPX ONBOARDING FLOW ─────────────────────────────────────────────────────
|
|
313
|
-
// Only reached when: isNpx === true AND no args passed (bare `npx swytchcode`)
|
|
314
|
-
|
|
327
|
+
// ─── HTTP helpers (used by both canonical-demo and bare-npx onboarding paths) ─
|
|
315
328
|
const API_BASE = 'https://api-v2.swytchcode.com/v2/cli';
|
|
316
329
|
|
|
317
|
-
// Helper to perform HTTP GET (declared inside so it doesn't conflict)
|
|
318
330
|
function apiGet(urlStr) {
|
|
319
331
|
return new Promise((resolve, reject) => {
|
|
320
332
|
const parsed = new URL(urlStr);
|
|
@@ -339,6 +351,43 @@ function apiGet(urlStr) {
|
|
|
339
351
|
});
|
|
340
352
|
}
|
|
341
353
|
|
|
354
|
+
// ─── Normal pass-through (not npx, or npx with non-demo args) ───────────────
|
|
355
|
+
if (!isNpx || (userArgs.length > 0 && !isCanonicalDemoArg && !isNpxBareWordArg)) {
|
|
356
|
+
const result = spawnBin(binPath, userArgs);
|
|
357
|
+
if (result.error) {
|
|
358
|
+
err(`swytchcode: failed to launch binary: ${result.error.message}`);
|
|
359
|
+
}
|
|
360
|
+
process.exit(exitCode(result));
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// ─── NPX routing: three mutually exclusive paths ─────────────────────────────
|
|
364
|
+
if (isNpx && isCanonicalDemoArg) {
|
|
365
|
+
// Dotted canonical ID (e.g. stripe.create_payment) — run demo then onboard
|
|
366
|
+
runOnboardingDirectDemo(originalArg).catch(e => {
|
|
367
|
+
err(`\nswytchcode: onboarding error (${e.message}) — falling back to CLI.\n`);
|
|
368
|
+
const result = spawnBin(binPath, userArgs);
|
|
369
|
+
process.exit(exitCode(result));
|
|
370
|
+
});
|
|
371
|
+
} else if (isNpxBareWordArg) {
|
|
372
|
+
// Single bare word (e.g. "abcd") — not a valid canonical ID; show message then onboard
|
|
373
|
+
writeln();
|
|
374
|
+
writeln(` ${c.yellow}⚠ ${c.bold}${originalArg}${c.reset}${c.yellow} isn't a valid demo tool — canonical IDs look like ${c.bold}provider.method${c.reset}`);
|
|
375
|
+
writeln(` ${c.dim}Let's run a working demo instead.${c.reset}`);
|
|
376
|
+
writeln();
|
|
377
|
+
Promise.resolve()
|
|
378
|
+
.then(() => runDemoSelection())
|
|
379
|
+
.then(() => runOnboardingSteps2to4())
|
|
380
|
+
.catch(e => {
|
|
381
|
+
err(`\nswytchcode: onboarding error (${e.message}) — falling back to CLI.\n`);
|
|
382
|
+
process.exit(1);
|
|
383
|
+
});
|
|
384
|
+
} else {
|
|
385
|
+
// Bare npx swytchcode (no args) — full onboarding with welcome banner
|
|
386
|
+
runOnboarding().catch(e => {
|
|
387
|
+
err(`\nswytchcode: onboarding error (${e.message}) — falling back to CLI.\n`);
|
|
388
|
+
const result = spawnBin(binPath, userArgs);
|
|
389
|
+
process.exit(exitCode(result));
|
|
390
|
+
});
|
|
342
391
|
}
|
|
343
392
|
|
|
344
393
|
async function runDemoSelection() {
|
|
@@ -371,10 +420,7 @@ async function runDemoSelection() {
|
|
|
371
420
|
if (chosen !== '__skip__') {
|
|
372
421
|
writeln();
|
|
373
422
|
writeln(` ${c.gray}$ swytchcode demo stripe${c.reset}`);
|
|
374
|
-
|
|
375
|
-
stdio: 'inherit',
|
|
376
|
-
env: { ...process.env, SWYTCHCODE_ONBOARDING: '1' }
|
|
377
|
-
});
|
|
423
|
+
spawnBin(binPath, ['demo', 'stripe'], { SWYTCHCODE_ONBOARDING: '1' });
|
|
378
424
|
writeln();
|
|
379
425
|
writeln(` ${c.dim}That was a real API call. No credentials, no setup.${c.reset}`);
|
|
380
426
|
writeln(` ${c.dim}With Swytchcode, every API integration works exactly like this.${c.reset}`);
|
|
@@ -445,6 +491,12 @@ async function runOnboardingSteps2to4() {
|
|
|
445
491
|
execSync('npm install swytchcode', { stdio: 'pipe' });
|
|
446
492
|
installSpin.stop('Installed successfully');
|
|
447
493
|
} catch (e) {
|
|
494
|
+
if (e.signal === 'SIGINT') {
|
|
495
|
+
installSpin.stop('Cancelled');
|
|
496
|
+
try { process.stdin.setRawMode(false); } catch (_) {}
|
|
497
|
+
process.stdout.write('\x1b[?25h');
|
|
498
|
+
process.exit(130);
|
|
499
|
+
}
|
|
448
500
|
installSpin.fail('Installation failed.');
|
|
449
501
|
}
|
|
450
502
|
|
|
@@ -472,7 +524,7 @@ async function runOnboardingSteps2to4() {
|
|
|
472
524
|
if (authChoice === 'login') {
|
|
473
525
|
writeln(` ${c.dim}Opening browser for login ...${c.reset}`);
|
|
474
526
|
writeln();
|
|
475
|
-
const result =
|
|
527
|
+
const result = spawnBin(binPath, ['login']);
|
|
476
528
|
if (result.error || result.status !== 0) {
|
|
477
529
|
writeln(` ${c.yellow}Login window closed or failed.${c.reset}`);
|
|
478
530
|
writeln(` ${c.dim}You can log in later with:${c.reset} ${c.cyan}swytchcode login${c.reset}`);
|
|
@@ -483,7 +535,7 @@ async function runOnboardingSteps2to4() {
|
|
|
483
535
|
writeln(` ${c.dim}Opening browser to create your account ...${c.reset}`);
|
|
484
536
|
writeln();
|
|
485
537
|
// login command handles both login and registration via the browser flow
|
|
486
|
-
const result =
|
|
538
|
+
const result = spawnBin(binPath, ['login']);
|
|
487
539
|
if (result.error || result.status !== 0) {
|
|
488
540
|
writeln(` ${c.yellow}Browser window closed or failed.${c.reset}`);
|
|
489
541
|
writeln(` ${c.dim}Create your account at:${c.reset} ${c.cyan}https://swytchcode.com/signup${c.reset}`);
|
|
@@ -513,14 +565,14 @@ async function runOnboardingSteps2to4() {
|
|
|
513
565
|
if (nextAction === 'init') {
|
|
514
566
|
writeln(` ${c.dim}Starting project setup ...${c.reset}`);
|
|
515
567
|
writeln();
|
|
516
|
-
const result =
|
|
568
|
+
const result = spawnBin(binPath, ['init']);
|
|
517
569
|
if (result.error) {
|
|
518
570
|
writeln(` ${c.red}Could not launch swytchcode init: ${result.error.message}${c.reset}`);
|
|
519
571
|
}
|
|
520
572
|
} else if (nextAction === 'examples') {
|
|
521
573
|
writeln(` ${c.dim}Loading examples ...${c.reset}`);
|
|
522
574
|
writeln();
|
|
523
|
-
const result =
|
|
575
|
+
const result = spawnBin(binPath, ['examples']);
|
|
524
576
|
if (result.error) {
|
|
525
577
|
writeln(` ${c.red}Could not launch swytchcode examples: ${result.error.message}${c.reset}`);
|
|
526
578
|
}
|
|
@@ -540,8 +592,3 @@ async function runOnboardingSteps2to4() {
|
|
|
540
592
|
writeln();
|
|
541
593
|
}
|
|
542
594
|
|
|
543
|
-
runOnboarding().catch(e => {
|
|
544
|
-
err(`\nswytchcode: onboarding error (${e.message}) — falling back to CLI.\n`);
|
|
545
|
-
const result = spawnBin(binPath, userArgs);
|
|
546
|
-
process.exit(exitCode(result));
|
|
547
|
-
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swytchcode",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.2",
|
|
4
4
|
"description": "Execution authority layer for API integrations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api",
|
|
@@ -23,11 +23,11 @@
|
|
|
23
23
|
"README.md"
|
|
24
24
|
],
|
|
25
25
|
"optionalDependencies": {
|
|
26
|
-
"swytchcode-cli-darwin-arm64": "2.6.
|
|
27
|
-
"swytchcode-cli-darwin-x64": "2.6.
|
|
28
|
-
"swytchcode-cli-linux-arm64": "2.6.
|
|
29
|
-
"swytchcode-cli-linux-x64": "2.6.
|
|
30
|
-
"swytchcode-cli-win32-arm64": "2.6.
|
|
31
|
-
"swytchcode-cli-win32-x64": "2.6.
|
|
26
|
+
"swytchcode-cli-darwin-arm64": "2.6.2",
|
|
27
|
+
"swytchcode-cli-darwin-x64": "2.6.2",
|
|
28
|
+
"swytchcode-cli-linux-arm64": "2.6.2",
|
|
29
|
+
"swytchcode-cli-linux-x64": "2.6.2",
|
|
30
|
+
"swytchcode-cli-win32-arm64": "2.6.2",
|
|
31
|
+
"swytchcode-cli-win32-x64": "2.6.2"
|
|
32
32
|
}
|
|
33
33
|
}
|