swytchcode 2.20.5 → 2.20.7
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 +109 -40
- package/package.json +7 -7
package/bin/swytchcode.js
CHANGED
|
@@ -205,6 +205,34 @@ function apiPost(urlStr, body) {
|
|
|
205
205
|
});
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
// describeSpawnError turns a failed spawnSync's `error` into an actionable
|
|
209
|
+
// message. On Windows, antivirus/EDR software quarantining or blocking an
|
|
210
|
+
// unsigned downloaded .exe is by far the most common cause of a launch
|
|
211
|
+
// failure here, and it surfaces through Node as a generic, unhelpful error:
|
|
212
|
+
// EPERM, or - most often - a bare "UNKNOWN" with no further detail, because
|
|
213
|
+
// the OS refused the spawn rather than reporting why. Node's own message for
|
|
214
|
+
// that case ("spawnSync ... UNKNOWN") gives the user nothing to act on, so we
|
|
215
|
+
// add the likely cause and a concrete next step instead of just relaying it.
|
|
216
|
+
function describeSpawnError(binPath, error) {
|
|
217
|
+
const base = `${error.message} (path: ${binPath})`;
|
|
218
|
+
if (process.platform !== 'win32') return base;
|
|
219
|
+
|
|
220
|
+
const fileIsGone = !fs.existsSync(binPath);
|
|
221
|
+
if (fileIsGone) {
|
|
222
|
+
return `${base}\n` +
|
|
223
|
+
` The binary is missing from disk - antivirus software may have quarantined it after install.\n` +
|
|
224
|
+
` Check your antivirus quarantine, then reinstall: npm install -g swytchcode`;
|
|
225
|
+
}
|
|
226
|
+
if (error.code === 'UNKNOWN' || error.code === 'EPERM' || error.code === 'EACCES') {
|
|
227
|
+
return `${base}\n` +
|
|
228
|
+
` Windows refused to run this binary without saying why (code: ${error.code}) - this almost\n` +
|
|
229
|
+
` always means antivirus or Windows Defender is blocking it, not a problem with swytchcode.\n` +
|
|
230
|
+
` Check your antivirus/Defender quarantine and allow "${binPath}", then try again.\n` +
|
|
231
|
+
` Details: https://docs.swytchcode.com/docs/`;
|
|
232
|
+
}
|
|
233
|
+
return base;
|
|
234
|
+
}
|
|
235
|
+
|
|
208
236
|
// ─── Binary resolution (shared by normal pass-through AND onboarding) ────────
|
|
209
237
|
function spawnBin(binPath, args, extraEnv = {}) {
|
|
210
238
|
const env = { ...process.env, ...extraEnv };
|
|
@@ -255,7 +283,7 @@ const bareNpxLaunch =
|
|
|
255
283
|
if (explicitBin && !bareNpxLaunch) {
|
|
256
284
|
const result = spawnBin(explicitBin, process.argv.slice(2));
|
|
257
285
|
if (result.error) {
|
|
258
|
-
err(`swytchcode: failed to launch SWYTCHCODE_BIN="${explicitBin}": ${result.error
|
|
286
|
+
err(`swytchcode: failed to launch SWYTCHCODE_BIN="${explicitBin}": ${describeSpawnError(explicitBin, result.error)}`);
|
|
259
287
|
process.exit(1);
|
|
260
288
|
}
|
|
261
289
|
process.exit(exitCode(result));
|
|
@@ -367,12 +395,30 @@ const isNpx =
|
|
|
367
395
|
binPath.includes('_npx') ||
|
|
368
396
|
(process.env.npm_execpath || '').includes('npx');
|
|
369
397
|
|
|
398
|
+
// Top-level subcommands the Go CLI actually registers - see internal/cli/root.go's
|
|
399
|
+
// rootCmd.AddCommand calls (plus cobra's built-in "help"). Keep this in sync with
|
|
400
|
+
// that file: anything NOT in this set is treated below as a mistyped/invalid demo
|
|
401
|
+
// lookup rather than passed through, so a real subcommand missing from this list
|
|
402
|
+
// would silently stop working under npx (e.g. `npx swytchcode examples` would be
|
|
403
|
+
// swallowed into "isn't a demo tool" instead of running the actual command).
|
|
404
|
+
const KNOWN_SUBCOMMANDS = new Set([
|
|
405
|
+
'init', 'get', 'add', 'bootstrap', 'sync', 'workflow', 'policy',
|
|
406
|
+
'search', 'list', 'info', 'discover', 'plan',
|
|
407
|
+
'exec', 'demo', 'examples',
|
|
408
|
+
'login', 'logout', 'whoami', 'auth',
|
|
409
|
+
'mcp', 'doctor', 'audit', 'config',
|
|
410
|
+
'help',
|
|
411
|
+
]);
|
|
412
|
+
|
|
370
413
|
const userArgs = process.argv.slice(2);
|
|
371
414
|
// Capture original arg BEFORE mutation
|
|
372
415
|
const originalArg = process.argv[2] || '';
|
|
373
416
|
const isCanonicalDemoArg = /^[\w]+\.[\w.]+$/.test(originalArg) && !originalArg.startsWith('-');
|
|
374
|
-
// A single bare word under npx is a potential (invalid) demo lookup - don't pass
|
|
375
|
-
|
|
417
|
+
// A single bare word under npx is a potential (invalid) demo lookup - don't pass
|
|
418
|
+
// through to cobra - UNLESS it's a real subcommand, in which case it must reach
|
|
419
|
+
// the actual CLI like any other argument does.
|
|
420
|
+
const isNpxBareWordArg = isNpx && userArgs.length === 1 && /^[\w]+$/.test(originalArg) &&
|
|
421
|
+
!originalArg.startsWith('-') && !KNOWN_SUBCOMMANDS.has(originalArg);
|
|
376
422
|
// Legacy support: npx swytchcode <canonical_id> → npx swytchcode exec <canonical_id>
|
|
377
423
|
if (userArgs.length > 0 && /^[\w]+\.[\w.]+$/.test(userArgs[0]) && !userArgs[0].startsWith('-')) {
|
|
378
424
|
userArgs.unshift('exec');
|
|
@@ -383,7 +429,15 @@ async function runOnboardingDirectDemo(canonicalId) {
|
|
|
383
429
|
writeln();
|
|
384
430
|
const demoResult = spawnBin(binPath, ['exec', canonicalId], { SWYTCHCODE_ONBOARDING: '1' });
|
|
385
431
|
writeln();
|
|
386
|
-
if (demoResult.
|
|
432
|
+
if (demoResult.error) {
|
|
433
|
+
// The binary itself failed to launch (e.g. antivirus quarantine) - this is
|
|
434
|
+
// not the same as "not a demo tool" and must not be reported as that.
|
|
435
|
+
writeln(` ${c.red}Could not launch swytchcode: ${describeSpawnError(binPath, demoResult.error)}${c.reset}`);
|
|
436
|
+
writeln();
|
|
437
|
+
writeln(` ${c.dim}Let's run a working demo instead.${c.reset}`);
|
|
438
|
+
writeln();
|
|
439
|
+
await runDemoSelection();
|
|
440
|
+
} else if (demoResult.status === 0) {
|
|
387
441
|
writeln(` ${c.dim}Done - ran through Swytchcode.${c.reset}`);
|
|
388
442
|
writeln();
|
|
389
443
|
} else {
|
|
@@ -392,7 +446,7 @@ async function runOnboardingDirectDemo(canonicalId) {
|
|
|
392
446
|
writeln();
|
|
393
447
|
await runDemoSelection();
|
|
394
448
|
}
|
|
395
|
-
await
|
|
449
|
+
await runOnboardingSteps1to3();
|
|
396
450
|
}
|
|
397
451
|
|
|
398
452
|
// ─── HTTP helpers (used by both canonical-demo and bare-npx onboarding paths) ─
|
|
@@ -440,7 +494,7 @@ const CARD_DESCRIPTION = 'Swytchcode sits between your agent and any API - auth,
|
|
|
440
494
|
if (!isNpx || (userArgs.length > 0 && !isCanonicalDemoArg && !isNpxBareWordArg)) {
|
|
441
495
|
const result = spawnBin(binPath, userArgs);
|
|
442
496
|
if (result.error) {
|
|
443
|
-
err(`swytchcode: failed to launch binary: ${result.error
|
|
497
|
+
err(`swytchcode: failed to launch binary: ${describeSpawnError(binPath, result.error)}`);
|
|
444
498
|
}
|
|
445
499
|
process.exit(exitCode(result));
|
|
446
500
|
}
|
|
@@ -461,7 +515,7 @@ if (isNpx && isCanonicalDemoArg) {
|
|
|
461
515
|
writeln();
|
|
462
516
|
Promise.resolve()
|
|
463
517
|
.then(() => runDemoSelection())
|
|
464
|
-
.then(() =>
|
|
518
|
+
.then(() => runOnboardingSteps1to3())
|
|
465
519
|
.catch(e => {
|
|
466
520
|
err(`\nswytchcode: onboarding error (${e.message}) - falling back to CLI.\n`);
|
|
467
521
|
process.exit(1);
|
|
@@ -475,6 +529,16 @@ if (isNpx && isCanonicalDemoArg) {
|
|
|
475
529
|
});
|
|
476
530
|
}
|
|
477
531
|
|
|
532
|
+
// Maps a canonical demo tool ID (as returned by GET /demo/tools) to the short
|
|
533
|
+
// `swytchcode demo <name>` subcommand alias that actually runs it - see
|
|
534
|
+
// internal/cli/demo_commands.go's registered aliases. A tool with no entry
|
|
535
|
+
// here has no runnable `demo <name>` subcommand yet, so it's skipped in
|
|
536
|
+
// runDemoSelection below rather than launching a different demo by mistake.
|
|
537
|
+
const DEMO_TOOL_TO_SUBCOMMAND = {
|
|
538
|
+
'stripe.create_payment': 'stripe',
|
|
539
|
+
'fintech.compliance': 'fintech-compliance',
|
|
540
|
+
};
|
|
541
|
+
|
|
478
542
|
async function runDemoSelection() {
|
|
479
543
|
let demoTools = [];
|
|
480
544
|
try {
|
|
@@ -503,12 +567,26 @@ async function runDemoSelection() {
|
|
|
503
567
|
const chosen = await menuArrow('Choose a demo to run:', demoOptions);
|
|
504
568
|
|
|
505
569
|
if (chosen !== '__skip__') {
|
|
570
|
+
const demoSubcommand = DEMO_TOOL_TO_SUBCOMMAND[chosen];
|
|
571
|
+
if (!demoSubcommand) {
|
|
572
|
+
// Backend added a demo tool with no matching `demo <name>` subcommand
|
|
573
|
+
// yet - skip rather than silently running a different demo instead.
|
|
574
|
+
writeln();
|
|
575
|
+
writeln(` ${c.yellow}${chosen} isn't runnable via this onboarding flow yet - skipping.${c.reset}`);
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
506
578
|
writeln();
|
|
507
|
-
writeln(` ${c.gray}$ swytchcode demo
|
|
508
|
-
spawnBin(binPath, ['demo',
|
|
579
|
+
writeln(` ${c.gray}$ swytchcode demo ${demoSubcommand}${c.reset}`);
|
|
580
|
+
const demoResult = spawnBin(binPath, ['demo', demoSubcommand], { SWYTCHCODE_ONBOARDING: '1' });
|
|
509
581
|
writeln();
|
|
510
|
-
|
|
511
|
-
|
|
582
|
+
if (demoResult.error) {
|
|
583
|
+
writeln(` ${c.red}Could not launch swytchcode demo: ${describeSpawnError(binPath, demoResult.error)}${c.reset}`);
|
|
584
|
+
} else if (demoResult.status === 0) {
|
|
585
|
+
writeln(` ${c.dim}Done - ran through Swytchcode's demo account.${c.reset}`);
|
|
586
|
+
writeln(` ${c.dim}Every integration runs the same way.${c.reset}`);
|
|
587
|
+
} else {
|
|
588
|
+
writeln(` ${c.red}Demo exited with an error (status ${demoResult.status}).${c.reset}`);
|
|
589
|
+
}
|
|
512
590
|
}
|
|
513
591
|
}
|
|
514
592
|
|
|
@@ -580,7 +658,7 @@ function welcomeCard(cliVersion, auth) {
|
|
|
580
658
|
}
|
|
581
659
|
|
|
582
660
|
// cardBelow prints the sign-in line, cwd, and get-started hints. The sign-in
|
|
583
|
-
// line reflects the real auth state so it stays consistent with the Step
|
|
661
|
+
// line reflects the real auth state so it stays consistent with the Step 2
|
|
584
662
|
// skip-login logic (no "not signed in" when the user is actually authenticated).
|
|
585
663
|
function cardBelow({ orange, dim, green, auth }) {
|
|
586
664
|
writeln();
|
|
@@ -596,7 +674,6 @@ function cardBelow({ orange, dim, green, auth }) {
|
|
|
596
674
|
const rows = [
|
|
597
675
|
['swytchcode init', 'set up this project'],
|
|
598
676
|
['swytchcode get <project>', 'fetch integration bundles'],
|
|
599
|
-
['swytchcode exec <canonical_id>', 'run a tool'],
|
|
600
677
|
];
|
|
601
678
|
for (const [cmd, desc] of rows) writeln(` ${green('›')} ${cmd.padEnd(32)} ${dim(desc)}`);
|
|
602
679
|
writeln();
|
|
@@ -622,18 +699,7 @@ async function runOnboarding() {
|
|
|
622
699
|
|
|
623
700
|
welcomeCard(cliVersion, authStatus());
|
|
624
701
|
|
|
625
|
-
|
|
626
|
-
// matching the rules drawn between steps below.
|
|
627
|
-
writeln();
|
|
628
|
-
writeln(' ' + '─'.repeat(45));
|
|
629
|
-
writeln();
|
|
630
|
-
|
|
631
|
-
// ── Step 1: Demo ──────────────────────────────────────────────────────────
|
|
632
|
-
writeln(`${c.bold} Step 1 of 4 - Try it${c.reset}`);
|
|
633
|
-
writeln(`${c.dim} Run an API call through Swytchcode.${c.reset}`);
|
|
634
|
-
writeln();
|
|
635
|
-
await runDemoSelection();
|
|
636
|
-
await runOnboardingSteps2to4();
|
|
702
|
+
await runOnboardingSteps1to3();
|
|
637
703
|
}
|
|
638
704
|
|
|
639
705
|
// isGloballyInstalled reports whether a real, persistent global `swytchcode`
|
|
@@ -688,12 +754,12 @@ function authStatus() {
|
|
|
688
754
|
return { authed: false, label: '' };
|
|
689
755
|
}
|
|
690
756
|
|
|
691
|
-
async function
|
|
692
|
-
// ── Step
|
|
757
|
+
async function runOnboardingSteps1to3() {
|
|
758
|
+
// ── Step 1: Install ───────────────────────────────────────────────────────
|
|
693
759
|
writeln();
|
|
694
760
|
writeln(' ' + '─'.repeat(45));
|
|
695
761
|
writeln();
|
|
696
|
-
writeln(`${c.bold} Step
|
|
762
|
+
writeln(`${c.bold} Step 1 of 3 - Install Swytchcode${c.reset}`);
|
|
697
763
|
|
|
698
764
|
if (isGloballyInstalled()) {
|
|
699
765
|
// Already installed - don't re-offer the install step.
|
|
@@ -731,11 +797,11 @@ async function runOnboardingSteps2to4() {
|
|
|
731
797
|
}
|
|
732
798
|
}
|
|
733
799
|
|
|
734
|
-
// ── Step
|
|
800
|
+
// ── Step 2: Account sync ──────────────────────────────────────────────────
|
|
735
801
|
writeln();
|
|
736
802
|
writeln(' ' + '─'.repeat(45));
|
|
737
803
|
writeln();
|
|
738
|
-
writeln(`${c.bold} Step
|
|
804
|
+
writeln(`${c.bold} Step 2 of 3 - Connect your account${c.reset}`);
|
|
739
805
|
|
|
740
806
|
const auth = authStatus();
|
|
741
807
|
if (auth.authed) {
|
|
@@ -756,9 +822,11 @@ async function runOnboardingSteps2to4() {
|
|
|
756
822
|
if (authChoice === 'login') {
|
|
757
823
|
writeln(` ${c.dim}Opening browser for login ...${c.reset}`);
|
|
758
824
|
writeln();
|
|
759
|
-
spawnBin(binPath, ['login']);
|
|
760
|
-
|
|
761
|
-
|
|
825
|
+
const loginResult = spawnBin(binPath, ['login']);
|
|
826
|
+
if (loginResult.error) {
|
|
827
|
+
writeln(` ${c.red}Could not launch swytchcode login: ${describeSpawnError(binPath, loginResult.error)}${c.reset}`);
|
|
828
|
+
} else if (authStatus().authed) {
|
|
829
|
+
// A zero exit doesn't guarantee a session was created - confirm the token.
|
|
762
830
|
writeln(` ${c.green}›${c.reset} logged in`);
|
|
763
831
|
} else {
|
|
764
832
|
writeln(` ${c.yellow}Login didn't complete.${c.reset}`);
|
|
@@ -769,8 +837,10 @@ async function runOnboardingSteps2to4() {
|
|
|
769
837
|
writeln();
|
|
770
838
|
// The browser flow handles both signup and login; verify a session
|
|
771
839
|
// actually exists before claiming the account is connected.
|
|
772
|
-
spawnBin(binPath, ['login']);
|
|
773
|
-
if (
|
|
840
|
+
const registerResult = spawnBin(binPath, ['login']);
|
|
841
|
+
if (registerResult.error) {
|
|
842
|
+
writeln(` ${c.red}Could not launch swytchcode login: ${describeSpawnError(binPath, registerResult.error)}${c.reset}`);
|
|
843
|
+
} else if (authStatus().authed) {
|
|
774
844
|
writeln(` ${c.green}›${c.reset} account connected`);
|
|
775
845
|
} else {
|
|
776
846
|
writeln(` ${c.yellow}Account not connected yet.${c.reset}`);
|
|
@@ -782,11 +852,11 @@ async function runOnboardingSteps2to4() {
|
|
|
782
852
|
}
|
|
783
853
|
}
|
|
784
854
|
|
|
785
|
-
// ── Step
|
|
855
|
+
// ── Step 3: Next action ───────────────────────────────────────────────────
|
|
786
856
|
writeln();
|
|
787
857
|
writeln(' ' + '─'.repeat(45));
|
|
788
858
|
writeln();
|
|
789
|
-
writeln(`${c.bold} Step
|
|
859
|
+
writeln(`${c.bold} Step 3 of 3 - What would you like to do next?${c.reset}`);
|
|
790
860
|
writeln();
|
|
791
861
|
|
|
792
862
|
const nextAction = await menuArrow('Choose an action:', [
|
|
@@ -802,14 +872,14 @@ async function runOnboardingSteps2to4() {
|
|
|
802
872
|
writeln();
|
|
803
873
|
const result = spawnBin(binPath, ['init']);
|
|
804
874
|
if (result.error) {
|
|
805
|
-
writeln(` ${c.red}Could not launch swytchcode init: ${result.error
|
|
875
|
+
writeln(` ${c.red}Could not launch swytchcode init: ${describeSpawnError(binPath, result.error)}${c.reset}`);
|
|
806
876
|
}
|
|
807
877
|
} else if (nextAction === 'examples') {
|
|
808
878
|
writeln(` ${c.dim}Loading examples ...${c.reset}`);
|
|
809
879
|
writeln();
|
|
810
880
|
const result = spawnBin(binPath, ['examples']);
|
|
811
881
|
if (result.error) {
|
|
812
|
-
writeln(` ${c.red}Could not launch swytchcode examples: ${result.error
|
|
882
|
+
writeln(` ${c.red}Could not launch swytchcode examples: ${describeSpawnError(binPath, result.error)}${c.reset}`);
|
|
813
883
|
}
|
|
814
884
|
} else {
|
|
815
885
|
writeln(` ${c.bold}You're all set.${c.reset}`);
|
|
@@ -818,7 +888,6 @@ async function runOnboardingSteps2to4() {
|
|
|
818
888
|
writeln(` ${c.orange}swytchcode init${c.reset} ${c.dim}Set up a new project${c.reset}`);
|
|
819
889
|
writeln(` ${c.orange}swytchcode examples${c.reset} ${c.dim}Browse example integrations${c.reset}`);
|
|
820
890
|
writeln(` ${c.orange}swytchcode get <api>${c.reset} ${c.dim}Install an API integration${c.reset}`);
|
|
821
|
-
writeln(` ${c.orange}swytchcode exec <id>${c.reset} ${c.dim}Execute an API method${c.reset}`);
|
|
822
891
|
writeln(` ${c.orange}swytchcode --help${c.reset} ${c.dim}Full command reference${c.reset}`);
|
|
823
892
|
}
|
|
824
893
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swytchcode",
|
|
3
|
-
"version": "2.20.
|
|
3
|
+
"version": "2.20.7",
|
|
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.20.
|
|
32
|
-
"swytchcode-cli-darwin-x64": "2.20.
|
|
33
|
-
"swytchcode-cli-linux-arm64": "2.20.
|
|
34
|
-
"swytchcode-cli-linux-x64": "2.20.
|
|
35
|
-
"swytchcode-cli-win32-arm64": "2.20.
|
|
36
|
-
"swytchcode-cli-win32-x64": "2.20.
|
|
31
|
+
"swytchcode-cli-darwin-arm64": "2.20.7",
|
|
32
|
+
"swytchcode-cli-darwin-x64": "2.20.7",
|
|
33
|
+
"swytchcode-cli-linux-arm64": "2.20.7",
|
|
34
|
+
"swytchcode-cli-linux-x64": "2.20.7",
|
|
35
|
+
"swytchcode-cli-win32-arm64": "2.20.7",
|
|
36
|
+
"swytchcode-cli-win32-x64": "2.20.7"
|
|
37
37
|
}
|
|
38
38
|
}
|