swytchcode 2.14.0-beta.5 → 2.15.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/bin/swytchcode.js +72 -53
- package/package.json +7 -7
package/bin/swytchcode.js
CHANGED
|
@@ -88,7 +88,7 @@ function menuArrow(prompt, options) {
|
|
|
88
88
|
resolve(options[n - 1].value);
|
|
89
89
|
return;
|
|
90
90
|
}
|
|
91
|
-
writeln(`${c.red} invalid choice
|
|
91
|
+
writeln(`${c.red} invalid choice - enter a number between 1 and ${options.length}${c.reset}`);
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
|
|
@@ -306,7 +306,7 @@ const userArgs = process.argv.slice(2);
|
|
|
306
306
|
// Capture original arg BEFORE mutation
|
|
307
307
|
const originalArg = process.argv[2] || '';
|
|
308
308
|
const isCanonicalDemoArg = /^[\w]+\.[\w.]+$/.test(originalArg) && !originalArg.startsWith('-');
|
|
309
|
-
// A single bare word under npx is a potential (invalid) demo lookup
|
|
309
|
+
// A single bare word under npx is a potential (invalid) demo lookup - don't pass through to cobra
|
|
310
310
|
const isNpxBareWordArg = isNpx && userArgs.length === 1 && /^[\w]+$/.test(originalArg) && !originalArg.startsWith('-');
|
|
311
311
|
// Legacy support: npx swytchcode <canonical_id> → npx swytchcode exec <canonical_id>
|
|
312
312
|
if (userArgs.length > 0 && /^[\w]+\.[\w.]+$/.test(userArgs[0]) && !userArgs[0].startsWith('-')) {
|
|
@@ -319,10 +319,10 @@ async function runOnboardingDirectDemo(canonicalId) {
|
|
|
319
319
|
const demoResult = spawnBin(binPath, ['exec', canonicalId], { SWYTCHCODE_ONBOARDING: '1' });
|
|
320
320
|
writeln();
|
|
321
321
|
if (demoResult.status === 0) {
|
|
322
|
-
writeln(` ${c.dim}Done
|
|
322
|
+
writeln(` ${c.dim}Done - ran through Swytchcode.${c.reset}`);
|
|
323
323
|
writeln();
|
|
324
324
|
} else {
|
|
325
|
-
writeln(` ${c.dim}${c.bold}${canonicalId}${c.reset}${c.dim} isn't a demo tool
|
|
325
|
+
writeln(` ${c.dim}${c.bold}${canonicalId}${c.reset}${c.dim} isn't a demo tool - running a sample instead.${c.reset}`);
|
|
326
326
|
writeln(` ${c.dim}Let's run a working demo instead.${c.reset}`);
|
|
327
327
|
writeln();
|
|
328
328
|
await runDemoSelection();
|
|
@@ -369,7 +369,7 @@ const CARD_WORDMARK = [
|
|
|
369
369
|
'╚══════╝ ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝',
|
|
370
370
|
];
|
|
371
371
|
const CARD_TAGLINE = 'Your agent calls an API. We make sure it goes through.';
|
|
372
|
-
const CARD_DESCRIPTION = 'Swytchcode sits between your agent and any API
|
|
372
|
+
const CARD_DESCRIPTION = 'Swytchcode sits between your agent and any API - auth, retries, idempotency, and schema validation, handled. Run a command below, or swytchcode --help for the full list.';
|
|
373
373
|
|
|
374
374
|
// ─── Normal pass-through (not npx, or npx with non-demo args) ───────────────
|
|
375
375
|
if (!isNpx || (userArgs.length > 0 && !isCanonicalDemoArg && !isNpxBareWordArg)) {
|
|
@@ -382,29 +382,29 @@ if (!isNpx || (userArgs.length > 0 && !isCanonicalDemoArg && !isNpxBareWordArg))
|
|
|
382
382
|
|
|
383
383
|
// ─── NPX routing: three mutually exclusive paths ─────────────────────────────
|
|
384
384
|
if (isNpx && isCanonicalDemoArg) {
|
|
385
|
-
// Dotted canonical ID (e.g. stripe.create_payment)
|
|
385
|
+
// Dotted canonical ID (e.g. stripe.create_payment) - run demo then onboard
|
|
386
386
|
runOnboardingDirectDemo(originalArg).catch(e => {
|
|
387
|
-
err(`\nswytchcode: onboarding error (${e.message})
|
|
387
|
+
err(`\nswytchcode: onboarding error (${e.message}) - falling back to CLI.\n`);
|
|
388
388
|
const result = spawnBin(binPath, userArgs);
|
|
389
389
|
process.exit(exitCode(result));
|
|
390
390
|
});
|
|
391
391
|
} else if (isNpxBareWordArg) {
|
|
392
|
-
// Single bare word (e.g. "abcd")
|
|
392
|
+
// Single bare word (e.g. "abcd") - not a valid canonical ID; show message then onboard
|
|
393
393
|
writeln();
|
|
394
|
-
writeln(` ${c.dim}${c.bold}${originalArg}${c.reset}${c.dim} isn't a demo tool
|
|
394
|
+
writeln(` ${c.dim}${c.bold}${originalArg}${c.reset}${c.dim} isn't a demo tool - IDs look like ${c.reset}${c.bold}provider.method${c.reset}`);
|
|
395
395
|
writeln(` ${c.dim}Let's run a working demo instead.${c.reset}`);
|
|
396
396
|
writeln();
|
|
397
397
|
Promise.resolve()
|
|
398
398
|
.then(() => runDemoSelection())
|
|
399
399
|
.then(() => runOnboardingSteps2to4())
|
|
400
400
|
.catch(e => {
|
|
401
|
-
err(`\nswytchcode: onboarding error (${e.message})
|
|
401
|
+
err(`\nswytchcode: onboarding error (${e.message}) - falling back to CLI.\n`);
|
|
402
402
|
process.exit(1);
|
|
403
403
|
});
|
|
404
404
|
} else {
|
|
405
|
-
// Bare npx swytchcode (no args)
|
|
405
|
+
// Bare npx swytchcode (no args) - full onboarding with welcome banner
|
|
406
406
|
runOnboarding().catch(e => {
|
|
407
|
-
err(`\nswytchcode: onboarding error (${e.message})
|
|
407
|
+
err(`\nswytchcode: onboarding error (${e.message}) - falling back to CLI.\n`);
|
|
408
408
|
const result = spawnBin(binPath, userArgs);
|
|
409
409
|
process.exit(exitCode(result));
|
|
410
410
|
});
|
|
@@ -420,13 +420,13 @@ async function runDemoSelection() {
|
|
|
420
420
|
} catch (_) {}
|
|
421
421
|
|
|
422
422
|
if (demoTools.length === 0) {
|
|
423
|
-
writeln(`${c.yellow} Demo unavailable right now
|
|
423
|
+
writeln(`${c.yellow} Demo unavailable right now - skipping to setup.${c.reset}`);
|
|
424
424
|
writeln();
|
|
425
425
|
return;
|
|
426
426
|
}
|
|
427
427
|
|
|
428
428
|
const friendlyName = {
|
|
429
|
-
'stripe.create_payment': 'Stripe
|
|
429
|
+
'stripe.create_payment': 'Stripe - Create a payment ($20.00)',
|
|
430
430
|
};
|
|
431
431
|
|
|
432
432
|
const demoOptions = demoTools.map(t => ({
|
|
@@ -442,7 +442,7 @@ async function runDemoSelection() {
|
|
|
442
442
|
writeln(` ${c.gray}$ swytchcode demo stripe${c.reset}`);
|
|
443
443
|
spawnBin(binPath, ['demo', 'stripe'], { SWYTCHCODE_ONBOARDING: '1' });
|
|
444
444
|
writeln();
|
|
445
|
-
writeln(` ${c.dim}Done
|
|
445
|
+
writeln(` ${c.dim}Done - ran through Swytchcode's demo account.${c.reset}`);
|
|
446
446
|
writeln(` ${c.dim}Every integration runs the same way.${c.reset}`);
|
|
447
447
|
}
|
|
448
448
|
}
|
|
@@ -478,10 +478,10 @@ function writeDescRows(boxRow, orange, contentW, margin) {
|
|
|
478
478
|
}
|
|
479
479
|
|
|
480
480
|
// welcomeCard renders the universal welcome banner: the "swytchcode" figlet
|
|
481
|
-
// wordmark, version, tagline, and wrapped description inside a framed box
|
|
481
|
+
// wordmark, version, tagline, and wrapped description inside a framed box - no
|
|
482
482
|
// bolt logo. Mirrors wordmarkBanner in internal/output/banner.go so npx
|
|
483
483
|
// onboarding and the installed CLI look identical (single form, no tiering).
|
|
484
|
-
function welcomeCard(cliVersion) {
|
|
484
|
+
function welcomeCard(cliVersion, auth) {
|
|
485
485
|
const isTTY = !!process.stdout.isTTY;
|
|
486
486
|
const ct = process.env.COLORTERM || '';
|
|
487
487
|
const truecolor = ct === 'truecolor' || ct === '24bit';
|
|
@@ -511,13 +511,19 @@ function welcomeCard(cliVersion) {
|
|
|
511
511
|
writeDescRows(boxRow, orange, innerW - 2 * margin, margin);
|
|
512
512
|
writeln(boxRow('', 0));
|
|
513
513
|
writeln(frame('└' + rep('─', innerW) + '┘'));
|
|
514
|
-
cardBelow({ orange, dim, green });
|
|
514
|
+
cardBelow({ orange, dim, green, auth });
|
|
515
515
|
}
|
|
516
516
|
|
|
517
|
-
// cardBelow prints the
|
|
518
|
-
|
|
517
|
+
// cardBelow prints the sign-in line, cwd, and get-started hints. The sign-in
|
|
518
|
+
// line reflects the real auth state so it stays consistent with the Step 3
|
|
519
|
+
// skip-login logic (no "not signed in" when the user is actually authenticated).
|
|
520
|
+
function cardBelow({ orange, dim, green, auth }) {
|
|
519
521
|
writeln();
|
|
520
|
-
|
|
522
|
+
if (auth && auth.authed) {
|
|
523
|
+
writeln(`${orange('●')} ${dim(auth.label)}`);
|
|
524
|
+
} else {
|
|
525
|
+
writeln(`${orange('●')} ${dim('not signed in - run ')}${orange('swytchcode login')}`);
|
|
526
|
+
}
|
|
521
527
|
const cwd = process.cwd().replace(/\\/g, '/');
|
|
522
528
|
const home = (require('os').homedir() || '').replace(/\\/g, '/');
|
|
523
529
|
writeln(dim(home && cwd.startsWith(home) ? '~' + cwd.slice(home.length) : cwd));
|
|
@@ -549,7 +555,7 @@ async function runOnboarding() {
|
|
|
549
555
|
// Clear screen for a clean experience
|
|
550
556
|
process.stdout.write('\x1Bc');
|
|
551
557
|
|
|
552
|
-
welcomeCard(cliVersion);
|
|
558
|
+
welcomeCard(cliVersion, authStatus());
|
|
553
559
|
|
|
554
560
|
// Divider between the welcome card/info and the interactive walkthrough,
|
|
555
561
|
// matching the rules drawn between steps below.
|
|
@@ -558,27 +564,38 @@ async function runOnboarding() {
|
|
|
558
564
|
writeln();
|
|
559
565
|
|
|
560
566
|
// ── Step 1: Demo ──────────────────────────────────────────────────────────
|
|
561
|
-
writeln(`${c.bold} Step 1 of 4
|
|
562
|
-
writeln(`${c.dim} Run
|
|
567
|
+
writeln(`${c.bold} Step 1 of 4 - Try it${c.reset}`);
|
|
568
|
+
writeln(`${c.dim} Run an API call through Swytchcode.${c.reset}`);
|
|
563
569
|
writeln();
|
|
564
570
|
await runDemoSelection();
|
|
565
571
|
await runOnboardingSteps2to4();
|
|
566
572
|
}
|
|
567
573
|
|
|
568
574
|
// isGloballyInstalled reports whether a real, persistent global `swytchcode`
|
|
569
|
-
// exists on PATH
|
|
575
|
+
// exists on PATH - as opposed to the transient npx cache binary this script is
|
|
570
576
|
// currently running from. Used to skip the "install globally" onboarding step
|
|
571
577
|
// when it's already installed.
|
|
572
578
|
function isGloballyInstalled() {
|
|
579
|
+
// Primary: look for the binary under npm's global prefix. This is independent
|
|
580
|
+
// of PATH ordering - under npx the transient cache binary is first on PATH, so
|
|
581
|
+
// a `command -v` first-match check would miss a real global install.
|
|
582
|
+
try {
|
|
583
|
+
const prefix = execSync('npm prefix -g', { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8' }).trim();
|
|
584
|
+
if (prefix) {
|
|
585
|
+
const candidates = process.platform === 'win32'
|
|
586
|
+
? ['swytchcode.cmd', 'swytchcode.ps1', 'swytchcode'].map(n => path.join(prefix, n))
|
|
587
|
+
: [path.join(prefix, 'bin', 'swytchcode')];
|
|
588
|
+
if (candidates.some(p => fs.existsSync(p))) return true;
|
|
589
|
+
}
|
|
590
|
+
} catch (_) {}
|
|
591
|
+
// Fallback: inspect EVERY PATH match (not just the first), excluding the npx
|
|
592
|
+
// cache. `where` (Windows) and `which -a` (POSIX) both list all matches.
|
|
573
593
|
try {
|
|
574
|
-
const probe = process.platform === 'win32' ? 'where swytchcode' : '
|
|
594
|
+
const probe = process.platform === 'win32' ? 'where swytchcode' : 'which -a swytchcode';
|
|
575
595
|
const out = execSync(probe, { stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8' }).trim();
|
|
576
|
-
if (
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
} catch (_) {
|
|
580
|
-
return false; // not found on PATH
|
|
581
|
-
}
|
|
596
|
+
if (out) return out.split(/\r?\n/).some(line => line && !line.toLowerCase().includes('_npx'));
|
|
597
|
+
} catch (_) {}
|
|
598
|
+
return false;
|
|
582
599
|
}
|
|
583
600
|
|
|
584
601
|
// authStatus reports whether the user is already authenticated, so onboarding
|
|
@@ -611,11 +628,11 @@ async function runOnboardingSteps2to4() {
|
|
|
611
628
|
writeln();
|
|
612
629
|
writeln(' ' + '─'.repeat(45));
|
|
613
630
|
writeln();
|
|
614
|
-
writeln(`${c.bold} Step 2 of 4
|
|
631
|
+
writeln(`${c.bold} Step 2 of 4 - Install Swytchcode${c.reset}`);
|
|
615
632
|
|
|
616
633
|
if (isGloballyInstalled()) {
|
|
617
|
-
// Already installed
|
|
618
|
-
writeln(` ${c.green}›${c.reset} ${c.dim}swytchcode is already installed globally
|
|
634
|
+
// Already installed - don't re-offer the install step.
|
|
635
|
+
writeln(` ${c.green}›${c.reset} ${c.dim}swytchcode is already installed globally - skipping.${c.reset}`);
|
|
619
636
|
} else {
|
|
620
637
|
writeln(`${c.dim} Install the ${c.reset}${c.orange}swytchcode${c.reset}${c.dim} command globally.${c.reset}`);
|
|
621
638
|
writeln();
|
|
@@ -653,12 +670,12 @@ async function runOnboardingSteps2to4() {
|
|
|
653
670
|
writeln();
|
|
654
671
|
writeln(' ' + '─'.repeat(45));
|
|
655
672
|
writeln();
|
|
656
|
-
writeln(`${c.bold} Step 3 of 4
|
|
673
|
+
writeln(`${c.bold} Step 3 of 4 - Connect your account${c.reset}`);
|
|
657
674
|
|
|
658
675
|
const auth = authStatus();
|
|
659
676
|
if (auth.authed) {
|
|
660
|
-
// Already authenticated
|
|
661
|
-
writeln(` ${c.green}›${c.reset} ${c.dim}Already ${auth.label}
|
|
677
|
+
// Already authenticated - never re-prompt for login.
|
|
678
|
+
writeln(` ${c.green}›${c.reset} ${c.dim}Already ${auth.label} - skipping.${c.reset}`);
|
|
662
679
|
} else {
|
|
663
680
|
writeln(`${c.dim} See your usage analytics, execution history, and saved projects.${c.reset}`);
|
|
664
681
|
writeln();
|
|
@@ -674,26 +691,28 @@ async function runOnboardingSteps2to4() {
|
|
|
674
691
|
if (authChoice === 'login') {
|
|
675
692
|
writeln(` ${c.dim}Opening browser for login ...${c.reset}`);
|
|
676
693
|
writeln();
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
writeln(` ${c.dim}You can log in later with:${c.reset} ${c.orange}swytchcode login${c.reset}`);
|
|
681
|
-
} else {
|
|
694
|
+
spawnBin(binPath, ['login']);
|
|
695
|
+
// A zero exit doesn't guarantee a session was created - confirm the token.
|
|
696
|
+
if (authStatus().authed) {
|
|
682
697
|
writeln(` ${c.green}›${c.reset} logged in`);
|
|
698
|
+
} else {
|
|
699
|
+
writeln(` ${c.yellow}Login didn't complete.${c.reset}`);
|
|
700
|
+
writeln(` ${c.dim}You can log in later with:${c.reset} ${c.orange}swytchcode login${c.reset}`);
|
|
683
701
|
}
|
|
684
702
|
} else if (authChoice === 'register') {
|
|
685
703
|
writeln(` ${c.dim}Opening browser to create your account ...${c.reset}`);
|
|
686
704
|
writeln();
|
|
687
|
-
//
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
writeln(` ${c.dim}Create your account at:${c.reset} ${c.orange}https://swytchcode.com/signup${c.reset}`);
|
|
692
|
-
} else {
|
|
705
|
+
// The browser flow handles both signup and login; verify a session
|
|
706
|
+
// actually exists before claiming the account is connected.
|
|
707
|
+
spawnBin(binPath, ['login']);
|
|
708
|
+
if (authStatus().authed) {
|
|
693
709
|
writeln(` ${c.green}›${c.reset} account connected`);
|
|
710
|
+
} else {
|
|
711
|
+
writeln(` ${c.yellow}Account not connected yet.${c.reset}`);
|
|
712
|
+
writeln(` ${c.dim}Create your account at:${c.reset} ${c.orange}https://swytchcode.com/signup${c.reset}`);
|
|
694
713
|
}
|
|
695
714
|
} else {
|
|
696
|
-
writeln(` ${c.dim}No problem
|
|
715
|
+
writeln(` ${c.dim}No problem - you can connect your account any time with:${c.reset}`);
|
|
697
716
|
writeln(` ${c.orange}swytchcode login${c.reset}`);
|
|
698
717
|
}
|
|
699
718
|
}
|
|
@@ -702,12 +721,12 @@ async function runOnboardingSteps2to4() {
|
|
|
702
721
|
writeln();
|
|
703
722
|
writeln(' ' + '─'.repeat(45));
|
|
704
723
|
writeln();
|
|
705
|
-
writeln(`${c.bold} Step 4 of 4
|
|
724
|
+
writeln(`${c.bold} Step 4 of 4 - What would you like to do next?${c.reset}`);
|
|
706
725
|
writeln();
|
|
707
726
|
|
|
708
727
|
const nextAction = await menuArrow('Choose an action:', [
|
|
709
|
-
{ label: `${c.bold}Build a new integration${c.reset} ${c.dim}
|
|
710
|
-
{ label: `${c.bold}Explore examples${c.reset} ${c.dim}
|
|
728
|
+
{ label: `${c.bold}Build a new integration${c.reset} ${c.dim}- run swytchcode init in your project${c.reset}`, value: 'init' },
|
|
729
|
+
{ label: `${c.bold}Explore examples${c.reset} ${c.dim}- download a working example project${c.reset}`, value: 'examples' },
|
|
711
730
|
{ label: `${c.bold}Exit${c.reset}`, value: 'exit' },
|
|
712
731
|
]);
|
|
713
732
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swytchcode",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.15.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://gitlab.com/swytchcode/cli.git"
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
"README.md"
|
|
29
29
|
],
|
|
30
30
|
"optionalDependencies": {
|
|
31
|
-
"swytchcode-cli-darwin-arm64": "2.
|
|
32
|
-
"swytchcode-cli-darwin-x64": "2.
|
|
33
|
-
"swytchcode-cli-linux-arm64": "2.
|
|
34
|
-
"swytchcode-cli-linux-x64": "2.
|
|
35
|
-
"swytchcode-cli-win32-arm64": "2.
|
|
36
|
-
"swytchcode-cli-win32-x64": "2.
|
|
31
|
+
"swytchcode-cli-darwin-arm64": "2.15.0",
|
|
32
|
+
"swytchcode-cli-darwin-x64": "2.15.0",
|
|
33
|
+
"swytchcode-cli-linux-arm64": "2.15.0",
|
|
34
|
+
"swytchcode-cli-linux-x64": "2.15.0",
|
|
35
|
+
"swytchcode-cli-win32-arm64": "2.15.0",
|
|
36
|
+
"swytchcode-cli-win32-x64": "2.15.0"
|
|
37
37
|
}
|
|
38
38
|
}
|