swytchcode 2.14.0-beta.6 → 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.
Files changed (2) hide show
  1. package/bin/swytchcode.js +72 -53
  2. 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 — enter a number between 1 and ${options.length}${c.reset}`);
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 — don't pass through to cobra
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 — ran through Swytchcode.${c.reset}`);
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 — running a sample instead.${c.reset}`);
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 — auth, retries, idempotency, and schema validation, handled. Run a command below, or swytchcode --help for the full list.';
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) — run demo then onboard
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}) — falling back to CLI.\n`);
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") — not a valid canonical ID; show message then onboard
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 — IDs look like ${c.reset}${c.bold}provider.method${c.reset}`);
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}) — falling back to CLI.\n`);
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) — full onboarding with welcome banner
405
+ // Bare npx swytchcode (no args) - full onboarding with welcome banner
406
406
  runOnboarding().catch(e => {
407
- err(`\nswytchcode: onboarding error (${e.message}) — falling back to CLI.\n`);
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 — skipping to setup.${c.reset}`);
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 — Create a payment ($20.00)',
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 — ran through Swytchcode's demo account.${c.reset}`);
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 — no
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 description, sign-in line, cwd, and get-started hints.
518
- function cardBelow({ orange, dim, green }) {
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
- writeln(`${orange('●')} ${dim('not signed in — run ')}${orange('swytchcode login')}`);
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 — Run a live call${c.reset}`);
562
- writeln(`${c.dim} Run a real API call through Swytchcode.${c.reset}`);
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 — as opposed to the transient npx cache binary this script is
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' : 'command -v 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 (!out) return false;
577
- // Any resolved path that isn't inside the npx cache means a global install exists.
578
- return out.split(/\r?\n/).some(line => line && !line.toLowerCase().includes('_npx'));
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 — Install Swytchcode${c.reset}`);
631
+ writeln(`${c.bold} Step 2 of 4 - Install Swytchcode${c.reset}`);
615
632
 
616
633
  if (isGloballyInstalled()) {
617
- // Already installed — don't re-offer the install step.
618
- writeln(` ${c.green}›${c.reset} ${c.dim}swytchcode is already installed globally — skipping.${c.reset}`);
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 — Connect your account${c.reset}`);
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 — never re-prompt for login.
661
- writeln(` ${c.green}›${c.reset} ${c.dim}Already ${auth.label} — skipping.${c.reset}`);
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
- const result = spawnBin(binPath, ['login']);
678
- if (result.error || result.status !== 0) {
679
- writeln(` ${c.yellow}Login window closed or failed.${c.reset}`);
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
- // login command handles both login and registration via the browser flow
688
- const result = spawnBin(binPath, ['login']);
689
- if (result.error || result.status !== 0) {
690
- writeln(` ${c.yellow}Browser window closed or failed.${c.reset}`);
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 — you can connect your account any time with:${c.reset}`);
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 — What would you like to do next?${c.reset}`);
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}— run swytchcode init in your project${c.reset}`, value: 'init' },
710
- { label: `${c.bold}Explore examples${c.reset} ${c.dim}— download a working example project${c.reset}`, value: 'examples' },
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.14.0-beta.6",
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.14.0-beta.6",
32
- "swytchcode-cli-darwin-x64": "2.14.0-beta.6",
33
- "swytchcode-cli-linux-arm64": "2.14.0-beta.6",
34
- "swytchcode-cli-linux-x64": "2.14.0-beta.6",
35
- "swytchcode-cli-win32-arm64": "2.14.0-beta.6",
36
- "swytchcode-cli-win32-x64": "2.14.0-beta.6"
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
  }