swytchcode 2.3.22 → 2.5.1

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 +450 -34
  2. package/package.json +8 -8
package/bin/swytchcode.js CHANGED
@@ -1,37 +1,225 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- const { spawnSync } = require('child_process');
5
- const fs = require('fs');
4
+ const { spawnSync, execSync } = require('child_process');
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const rl = require('readline');
8
+ const https = require('https');
9
+ const http = require('http');
6
10
 
7
- // When stdin is piped (not a TTY), read it fully and re-pipe it explicitly to the
8
- // child. Blindly inheriting a piped stdin fd can leave the Go binary with an
9
- // already-EOF pipe, causing its HTTP context to cancel mid-response.
11
+ // ─── Colours ────────────────────────────────────────────────────────────────
12
+ const c = {
13
+ reset: '\x1b[0m',
14
+ bold: '\x1b[1m',
15
+ dim: '\x1b[2m',
16
+ green: '\x1b[32m',
17
+ yellow: '\x1b[33m',
18
+ cyan: '\x1b[36m',
19
+ white: '\x1b[37m',
20
+ gray: '\x1b[90m',
21
+ bgGreen: '\x1b[42m',
22
+ red: '\x1b[31m',
23
+ };
24
+
25
+ // ─── Helpers ────────────────────────────────────────────────────────────────
26
+ function write(msg) { process.stdout.write(msg); }
27
+ function writeln(msg = '') { process.stdout.write(msg + '\n'); }
28
+ function err(msg) { process.stderr.write(msg + '\n'); }
29
+
30
+ function box(lines, colour = c.cyan) {
31
+ const width = Math.max(...lines.map(l => stripAnsi(l).length)) + 4;
32
+ const bar = colour + '─'.repeat(width) + c.reset;
33
+ writeln(bar);
34
+ for (const line of lines) {
35
+ const pad = width - 2 - stripAnsi(line).length;
36
+ writeln(colour + ' ' + c.reset + line + ' '.repeat(pad) + colour + ' ' + c.reset);
37
+ }
38
+ writeln(bar);
39
+ }
40
+
41
+ function stripAnsi(str) {
42
+ return str.replace(/\x1b\[[0-9;]*m/g, '');
43
+ }
44
+
45
+ function ask(prompt) {
46
+ return new Promise(resolve => {
47
+ const iface = rl.createInterface({ input: process.stdin, output: process.stdout });
48
+ iface.question(prompt, answer => { iface.close(); resolve(answer.trim()); });
49
+ });
50
+ }
51
+
52
+ function menuArrow(prompt, options) {
53
+ // options: [{ label, value }]
54
+ return new Promise(async resolve => {
55
+ if (!process.stdin.isTTY) {
56
+ // TTY fallback to number input
57
+ writeln();
58
+ writeln(c.bold + prompt + c.reset);
59
+ writeln();
60
+ options.forEach((o, i) => {
61
+ writeln(` ${c.cyan}${i + 1}${c.reset} ${stripAnsi(o.label)}`);
62
+ });
63
+ writeln();
64
+ while (true) {
65
+ const raw = await ask(`${c.gray}Enter number [1-${options.length}]: ${c.reset}`);
66
+ const n = parseInt(raw, 10);
67
+ if (n >= 1 && n <= options.length) {
68
+ resolve(options[n - 1].value);
69
+ return;
70
+ }
71
+ writeln(`${c.red} Invalid choice. Please enter a number between 1 and ${options.length}.${c.reset}`);
72
+ }
73
+ }
74
+
75
+ // TTY interactive mode with arrow keys
76
+ let selectedIndex = 0;
77
+
78
+ // Hide cursor
79
+ write('\x1b[?25l');
80
+
81
+ function render() {
82
+ writeln();
83
+ writeln(c.bold + prompt + c.reset);
84
+ writeln();
85
+ options.forEach((o, i) => {
86
+ if (i === selectedIndex) {
87
+ writeln(` ${c.cyan}❯${c.reset} ${c.bold}${c.green}${stripAnsi(o.label)}${c.reset}`);
88
+ } else {
89
+ writeln(` ${c.dim}${stripAnsi(o.label)}${c.reset}`);
90
+ }
91
+ });
92
+ writeln();
93
+ }
94
+
95
+ function clean() {
96
+ const lines = options.length + 4;
97
+ rl.moveCursor(process.stdout, 0, -lines);
98
+ rl.clearScreenDown(process.stdout);
99
+ }
100
+
101
+ render();
102
+
103
+ const onKeypress = (char, key) => {
104
+ if (key) {
105
+ if (key.name === 'up') {
106
+ selectedIndex = (selectedIndex - 1 + options.length) % options.length;
107
+ clean();
108
+ render();
109
+ } else if (key.name === 'down') {
110
+ selectedIndex = (selectedIndex + 1) % options.length;
111
+ clean();
112
+ render();
113
+ } else if (key.name === 'return' || key.name === 'enter') {
114
+ cleanup();
115
+ resolve(options[selectedIndex].value);
116
+ } else if (key.ctrl && key.name === 'c') {
117
+ cleanup();
118
+ process.exit(130);
119
+ }
120
+ }
121
+ };
122
+
123
+ rl.emitKeypressEvents(process.stdin);
124
+ process.stdin.setRawMode(true);
125
+ process.stdin.resume();
126
+ process.stdin.on('keypress', onKeypress);
127
+
128
+ function cleanup() {
129
+ // Show cursor
130
+ write('\x1b[?25h');
131
+ process.stdin.removeListener('keypress', onKeypress);
132
+ try {
133
+ process.stdin.setRawMode(false);
134
+ } catch (_) {}
135
+ process.stdin.pause();
136
+ }
137
+ });
138
+ }
139
+
140
+ function spinner(msg) {
141
+ const frames = ['⠋','⠙','⠹','⠸','⠼','⠴','⠦','⠧','⠇','⠏'];
142
+ let i = 0;
143
+ const iv = setInterval(() => {
144
+ process.stdout.write(`\r${c.cyan}${frames[i++ % frames.length]}${c.reset} ${msg}`);
145
+ }, 80);
146
+ return {
147
+ stop(doneMsg) {
148
+ clearInterval(iv);
149
+ process.stdout.write(`\r${c.green}✔${c.reset} ${doneMsg}\n`);
150
+ },
151
+ fail(failMsg) {
152
+ clearInterval(iv);
153
+ process.stdout.write(`\r${c.red}✖${c.reset} ${failMsg}\n`);
154
+ },
155
+ };
156
+ }
157
+
158
+ function apiPost(urlStr, body) {
159
+ return new Promise((resolve, reject) => {
160
+ const payload = JSON.stringify(body);
161
+ const parsed = new URL(urlStr);
162
+ const lib = parsed.protocol === 'https:' ? https : http;
163
+ const req = lib.request({
164
+ hostname: parsed.hostname,
165
+ port: parsed.port || (parsed.protocol === 'https:' ? 443 : 80),
166
+ path: parsed.pathname + parsed.search,
167
+ method: 'POST',
168
+ headers: {
169
+ 'Content-Type': 'application/json',
170
+ 'Content-Length': Buffer.byteLength(payload),
171
+ 'User-Agent': 'swytchcode-npx-onboarding/1.0',
172
+ },
173
+ }, res => {
174
+ let data = '';
175
+ res.on('data', d => { data += d; });
176
+ res.on('end', () => {
177
+ try { resolve({ status: res.statusCode, body: JSON.parse(data) }); }
178
+ catch { resolve({ status: res.statusCode, body: data }); }
179
+ });
180
+ });
181
+ req.on('error', reject);
182
+ req.setTimeout(15000, () => { req.destroy(new Error('Request timed out')); });
183
+ req.write(payload);
184
+ req.end();
185
+ });
186
+ }
187
+
188
+ // ─── Binary resolution (shared by normal pass-through AND onboarding) ────────
10
189
  function spawnBin(binPath, args) {
11
190
  if (process.stdin.isTTY) {
12
191
  return spawnSync(binPath, args, { stdio: 'inherit' });
13
192
  }
14
193
  let stdinData;
15
- try {
16
- stdinData = fs.readFileSync(0); // fd 0 = stdin
17
- } catch (_) {
18
- stdinData = Buffer.alloc(0);
19
- }
194
+ try { stdinData = fs.readFileSync(0); }
195
+ catch (_) { stdinData = Buffer.alloc(0); }
20
196
  return spawnSync(binPath, args, {
21
197
  stdio: ['pipe', 'inherit', 'inherit'],
22
198
  input: stdinData,
23
199
  });
24
200
  }
25
201
 
26
- // Explicit override: set SWYTCHCODE_BIN=/path/to/binary to bypass platform package resolution.
202
+ function exitCode(result) {
203
+ if (result.status !== null && result.status !== undefined) return result.status;
204
+ const SIGNALS = {
205
+ SIGHUP:1,SIGINT:2,SIGQUIT:3,SIGILL:4,SIGTRAP:5,SIGABRT:6,
206
+ SIGBUS:7,SIGFPE:8,SIGKILL:9,SIGUSR1:10,SIGSEGV:11,SIGUSR2:12,
207
+ SIGPIPE:13,SIGALRM:14,SIGTERM:15,
208
+ };
209
+ const sig = result.signal;
210
+ if (sig && SIGNALS[sig] !== undefined) return 128 + SIGNALS[sig];
211
+ return 1;
212
+ }
213
+
214
+ // Explicit override: SWYTCHCODE_BIN=/path/to/binary bypasses platform resolution.
27
215
  const explicitBin = (process.env.SWYTCHCODE_BIN || '').trim();
28
216
  if (explicitBin) {
29
217
  const result = spawnBin(explicitBin, process.argv.slice(2));
30
218
  if (result.error) {
31
- process.stderr.write(`swytchcode: failed to launch SWYTCHCODE_BIN="${explicitBin}": ${result.error.message}\n`);
219
+ err(`swytchcode: failed to launch SWYTCHCODE_BIN="${explicitBin}": ${result.error.message}`);
32
220
  process.exit(1);
33
221
  }
34
- process.exit(result.status ?? 1);
222
+ process.exit(exitCode(result));
35
223
  }
36
224
 
37
225
  const PLATFORM_PACKAGES = {
@@ -44,53 +232,281 @@ const PLATFORM_PACKAGES = {
44
232
  };
45
233
 
46
234
  const platform = process.platform;
47
- const arch = process.arch;
48
- const key = `${platform}-${arch}`;
49
- const pkg = PLATFORM_PACKAGES[key];
235
+ const arch = process.arch;
236
+ const key = `${platform}-${arch}`;
237
+ const pkg = PLATFORM_PACKAGES[key];
50
238
 
51
239
  if (!pkg) {
52
- process.stderr.write(
240
+ err(
53
241
  `swytchcode: unsupported platform "${key}".\n` +
54
242
  `Supported: ${Object.keys(PLATFORM_PACKAGES).join(', ')}\n` +
55
- `Install via curl instead: https://cli.swytchcode.com\n`
243
+ `Install via curl instead: https://cli.swytchcode.com`
56
244
  );
57
245
  process.exit(1);
58
246
  }
59
247
 
60
248
  const isWindows = platform === 'win32';
61
- const binName = isWindows ? 'swytchcode.exe' : 'swytchcode';
62
-
249
+ const binName = isWindows ? 'swytchcode.exe' : 'swytchcode';
63
250
  let binPath;
64
251
  try {
65
252
  binPath = require.resolve(`${pkg}/bin/${binName}`);
66
253
  } catch (_) {
67
- process.stderr.write(
254
+ err(
68
255
  `swytchcode: could not find the binary for "${key}".\n` +
69
- `Try reinstalling: npm install -g swytchcode\n`
256
+ `Try reinstalling: npm install -g swytchcode`
70
257
  );
71
258
  process.exit(1);
72
259
  }
73
260
 
74
- // Detect npx: npm 7+ runs `npx` as `npm exec` (npm_command=exec),
75
- // older npm puts the binary in a _npx temp dir, and even older npm names npx in npm_execpath.
261
+ // Detect npx
76
262
  const isNpx =
77
263
  (process.env.npm_command || '') === 'exec' ||
78
264
  __filename.includes('_npx') ||
79
265
  binPath.includes('_npx') ||
80
266
  (process.env.npm_execpath || '').includes('npx');
81
267
 
82
- const result = spawnBin(binPath, process.argv.slice(2));
268
+ const userArgs = process.argv.slice(2);
83
269
 
84
- if (result.error) {
85
- process.stderr.write(`swytchcode: failed to launch binary: ${result.error.message}\n`);
86
- process.exit(1);
270
+ // Legacy support: npx swytchcode <canonical_id> → npx swytchcode exec <canonical_id>
271
+ if (userArgs.length > 0 && /^[\w]+\.[\w.]+$/.test(userArgs[0]) && !userArgs[0].startsWith('-')) {
272
+ userArgs.unshift('exec');
87
273
  }
88
274
 
89
- if (isNpx && result.status === 0) {
90
- process.stderr.write(
91
- '\n\x1b[33m★ Speed up swytchcode — install it globally:\x1b[0m\n' +
92
- ' \x1b[1m\x1b[32mnpm install -g swytchcode\x1b[0m\n\n'
93
- );
275
+ // ─── Normal pass-through (not npx, or npx with args) ────────────────────────
276
+ if (!isNpx || userArgs.length > 0) {
277
+ const result = spawnBin(binPath, userArgs);
278
+ if (result.error) {
279
+ err(`swytchcode: failed to launch binary: ${result.error.message}`);
280
+ process.exit(1);
281
+ }
282
+ process.exit(exitCode(result));
283
+ }
284
+
285
+ // ─── NPX ONBOARDING FLOW ─────────────────────────────────────────────────────
286
+ // Only reached when: isNpx === true AND no args passed (bare `npx swytchcode`)
287
+
288
+ const API_BASE = 'https://api-v2.swytchcode.com/v2/cli';
289
+
290
+ // Helper to perform HTTP GET (declared inside so it doesn't conflict)
291
+ function apiGet(urlStr) {
292
+ return new Promise((resolve, reject) => {
293
+ const parsed = new URL(urlStr);
294
+ const lib = parsed.protocol === 'https:' ? https : http;
295
+ const req = lib.request({
296
+ hostname: parsed.hostname,
297
+ port: parsed.port || (parsed.protocol === 'https:' ? 443 : 80),
298
+ path: parsed.pathname + parsed.search,
299
+ method: 'GET',
300
+ headers: { 'User-Agent': 'swytchcode-npx-onboarding/1.0' },
301
+ }, res => {
302
+ let data = '';
303
+ res.on('data', d => { data += d; });
304
+ res.on('end', () => {
305
+ try { resolve({ status: res.statusCode, body: JSON.parse(data) }); }
306
+ catch { resolve({ status: res.statusCode, body: data }); }
307
+ });
308
+ });
309
+ req.on('error', reject);
310
+ req.setTimeout(10000, () => { req.destroy(new Error('Request timed out')); });
311
+ req.end();
312
+ });
313
+ }
314
+ async function runOnboarding() {
315
+ let cliVersion = '0.0.0';
316
+ try {
317
+ const verResult = spawnSync(binPath, ['--version'], { encoding: 'utf8' });
318
+ const semverMatch = verResult.stdout && verResult.stdout.match(/[\d]+\.[\d]+\.[\d]+/);
319
+ if (semverMatch) {
320
+ cliVersion = semverMatch[0];
321
+ } else if (verResult.stdout && verResult.stdout.includes('dev')) {
322
+ cliVersion = 'dev';
323
+ } else {
324
+ const pkgJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf8'));
325
+ cliVersion = pkgJson.version || '0.0.0';
326
+ }
327
+ } catch (_) {}
328
+
329
+ // Clear screen for a clean experience
330
+ process.stdout.write('\x1Bc');
331
+
332
+ writeln();
333
+ const vPad = ' '.repeat(Math.max(0, 34 - cliVersion.length));
334
+ writeln(` ${c.yellow}==========================================${c.reset}`);
335
+ writeln(` ${c.yellow}|${c.reset} ${c.yellow}⚡ ${c.bold}Welcome to Swytchcode${c.reset} ${c.yellow}|${c.reset}`);
336
+ writeln(` ${c.yellow}|${c.reset} ${c.dim}v${cliVersion}${c.reset}${vPad}${c.yellow}|${c.reset}`);
337
+ writeln(` ${c.yellow}|${c.reset} ${c.dim}Execution authority layer${c.reset} ${c.yellow}|${c.reset}`);
338
+ writeln(` ${c.yellow}==========================================${c.reset}`);
339
+ writeln();
340
+
341
+ // ── Step 1: Demo ──────────────────────────────────────────────────────────
342
+ writeln(`${c.bold} Step 1 of 4 — See it in action${c.reset}`);
343
+ writeln(`${c.dim} Run a live API call right now, no setup required.${c.reset}`);
344
+ writeln();
345
+
346
+ // Fetch available demo tools
347
+ let demoTools = [];
348
+ try {
349
+ const res = await apiGet(`${API_BASE}/demo/tools`);
350
+ if (res.status === 200 && Array.isArray(res.body.tools)) {
351
+ demoTools = res.body.tools;
352
+ }
353
+ } catch (_) {
354
+ // silently fall through — skip demo if API is unreachable
355
+ }
356
+
357
+ if (demoTools.length === 0) {
358
+ writeln(`${c.yellow} Demo unavailable right now — skipping to setup.${c.reset}`);
359
+ writeln();
360
+ } else {
361
+ // Map tool IDs to friendly names
362
+ const friendlyName = {
363
+ 'stripe.create_payment': 'Stripe — Create a payment ($20.00)',
364
+ };
365
+
366
+ const demoOptions = demoTools.map(t => ({
367
+ label: friendlyName[t] || t,
368
+ value: t,
369
+ }));
370
+ demoOptions.push({ label: 'Skip demo', value: '__skip__' });
371
+
372
+ const chosen = await menuArrow('Choose a demo to run:', demoOptions);
373
+
374
+ if (chosen !== '__skip__') {
375
+ writeln();
376
+ writeln(` ${c.gray}$ swytchcode demo stripe${c.reset}`);
377
+ spawnSync(binPath, ['demo', 'stripe'], { stdio: 'inherit' });
378
+ writeln();
379
+ writeln(` ${c.dim}That was a real API call. No credentials, no setup.${c.reset}`);
380
+ writeln(` ${c.dim}With Swytchcode, every API integration works exactly like this.${c.reset}`);
381
+ }
382
+ }
383
+
384
+ // ── Step 2: Install ───────────────────────────────────────────────────────
385
+ writeln();
386
+ writeln(' ' + '─'.repeat(45));
387
+ writeln();
388
+ writeln(`${c.bold} Step 2 of 4 — Install Swytchcode${c.reset}`);
389
+ writeln(`${c.dim} Install once, use everywhere. Adds the ${c.reset}${c.cyan}swytchcode${c.reset}${c.dim} command to your terminal.${c.reset}`);
390
+ writeln();
391
+ writeln(` ${c.dim}Installing into: ${process.cwd()}${c.reset}`);
392
+ writeln(` ${c.dim}$ npm install swytchcode${c.reset}`);
393
+ writeln();
394
+
395
+ const installChoice = await menuArrow('Install here?', [
396
+ { label: 'Yes, install here', value: 'yes' },
397
+ { label: 'Skip for now', value: 'no' },
398
+ ]);
399
+
400
+ writeln();
401
+
402
+ if (installChoice === 'no') {
403
+ writeln(` ${c.dim}Skipped. Install manually with:${c.reset}`);
404
+ writeln(` ${c.cyan}npm install swytchcode${c.reset}`);
405
+ writeln(` ${c.dim}For global access:${c.reset} ${c.cyan}npm install -g swytchcode${c.reset}`);
406
+ } else {
407
+ const installSpin = spinner('Running npm install swytchcode ...');
408
+ try {
409
+ execSync('npm install swytchcode', { stdio: 'pipe' });
410
+ installSpin.stop('Installed successfully');
411
+ } catch (e) {
412
+ installSpin.fail('Installation failed.');
413
+ }
414
+
415
+ writeln();
416
+ writeln(` ${c.dim}To make it available globally, run:${c.reset}`);
417
+ writeln(` ${c.bold}${c.green}npm install -g swytchcode${c.reset}`);
418
+ }
419
+
420
+ // ── Step 3: Account sync ──────────────────────────────────────────────────
421
+ writeln();
422
+ writeln(' ' + '─'.repeat(45));
423
+ writeln();
424
+ writeln(`${c.bold} Step 3 of 4 — Connect your account${c.reset}`);
425
+ writeln(`${c.dim} See your usage analytics, execution history, and saved projects.${c.reset}`);
426
+ writeln();
427
+
428
+ const authChoice = await menuArrow('Do you already have an account?', [
429
+ { label: 'Login to my account', value: 'login' },
430
+ { label: 'Create a new account', value: 'register' },
431
+ { label: 'Continue anonymously', value: 'anon' },
432
+ ]);
433
+
434
+ writeln();
435
+
436
+ if (authChoice === 'login') {
437
+ writeln(` ${c.dim}Opening browser for login ...${c.reset}`);
438
+ writeln();
439
+ const result = spawnSync(binPath, ['login'], { stdio: 'inherit' });
440
+ if (result.error || result.status !== 0) {
441
+ writeln(` ${c.yellow}Login window closed or failed.${c.reset}`);
442
+ writeln(` ${c.dim}You can log in later with:${c.reset} ${c.cyan}swytchcode login${c.reset}`);
443
+ } else {
444
+ writeln(` ${c.green}✔ Logged in successfully.${c.reset}`);
445
+ }
446
+ } else if (authChoice === 'register') {
447
+ writeln(` ${c.dim}Opening browser to create your account ...${c.reset}`);
448
+ writeln();
449
+ // login command handles both login and registration via the browser flow
450
+ const result = spawnSync(binPath, ['login'], { stdio: 'inherit' });
451
+ if (result.error || result.status !== 0) {
452
+ writeln(` ${c.yellow}Browser window closed or failed.${c.reset}`);
453
+ writeln(` ${c.dim}Create your account at:${c.reset} ${c.cyan}https://swytchcode.com/signup${c.reset}`);
454
+ } else {
455
+ writeln(` ${c.green}✔ Account connected successfully.${c.reset}`);
456
+ }
457
+ } else {
458
+ writeln(` ${c.dim}No problem — you can connect your account any time with:${c.reset}`);
459
+ writeln(` ${c.cyan}swytchcode login${c.reset}`);
460
+ }
461
+
462
+ // ── Step 4: Next action ───────────────────────────────────────────────────
463
+ writeln();
464
+ writeln(' ' + '─'.repeat(45));
465
+ writeln();
466
+ writeln(`${c.bold} Step 4 of 4 — What would you like to do next?${c.reset}`);
467
+ writeln();
468
+
469
+ const nextAction = await menuArrow('Choose an action:', [
470
+ { label: `${c.bold}Build a new integration${c.reset} ${c.dim}— run swytchcode init in your project${c.reset}`, value: 'init' },
471
+ { label: `${c.bold}Explore examples${c.reset} ${c.dim}— scaffold a working example project${c.reset}`, value: 'examples' },
472
+ { label: `${c.bold}Exit${c.reset}`, value: 'exit' },
473
+ ]);
474
+
475
+ writeln();
476
+
477
+ if (nextAction === 'init') {
478
+ writeln(` ${c.dim}Starting project setup ...${c.reset}`);
479
+ writeln();
480
+ const result = spawnSync(binPath, ['init'], { stdio: 'inherit' });
481
+ if (result.error) {
482
+ writeln(` ${c.red}Could not launch swytchcode init: ${result.error.message}${c.reset}`);
483
+ }
484
+ } else if (nextAction === 'examples') {
485
+ writeln(` ${c.dim}Loading examples ...${c.reset}`);
486
+ writeln();
487
+ const result = spawnSync(binPath, ['examples'], { stdio: 'inherit' });
488
+ if (result.error) {
489
+ writeln(` ${c.red}Could not launch swytchcode examples: ${result.error.message}${c.reset}`);
490
+ }
491
+ } else {
492
+ writeln(` ${c.bold}You're all set.${c.reset}`);
493
+ writeln();
494
+ writeln(` Quick reference:`);
495
+ writeln(` ${c.cyan}swytchcode init${c.reset} ${c.dim}Set up a new project${c.reset}`);
496
+ writeln(` ${c.cyan}swytchcode examples${c.reset} ${c.dim}Browse example integrations${c.reset}`);
497
+ writeln(` ${c.cyan}swytchcode get <api>${c.reset} ${c.dim}Install an API integration${c.reset}`);
498
+ writeln(` ${c.cyan}swytchcode exec <id>${c.reset} ${c.dim}Execute an API method${c.reset}`);
499
+ writeln(` ${c.cyan}swytchcode --help${c.reset} ${c.dim}Full command reference${c.reset}`);
500
+ }
501
+
502
+ writeln();
503
+ writeln(` ${c.dim}Docs: https://cli.swytchcode.com${c.reset}`);
504
+ writeln();
94
505
  }
95
506
 
96
- process.exit(result.status ?? 1);
507
+ runOnboarding().catch(e => {
508
+ // If onboarding crashes for any reason, fall back to normal binary pass-through
509
+ err(`\nswytchcode: onboarding error (${e.message}) — falling back to CLI.\n`);
510
+ const result = spawnBin(binPath, userArgs);
511
+ process.exit(exitCode(result));
512
+ });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "swytchcode",
3
- "version": "2.3.22",
4
- "description": "Execution layer for API integrations",
3
+ "version": "2.5.1",
4
+ "description": "Execution authority layer for API integrations",
5
5
  "keywords": [
6
6
  "api",
7
7
  "integration",
@@ -23,11 +23,11 @@
23
23
  "README.md"
24
24
  ],
25
25
  "optionalDependencies": {
26
- "swytchcode-cli-darwin-arm64": "2.3.22",
27
- "swytchcode-cli-darwin-x64": "2.3.22",
28
- "swytchcode-cli-linux-arm64": "2.3.22",
29
- "swytchcode-cli-linux-x64": "2.3.22",
30
- "swytchcode-cli-win32-arm64": "2.3.22",
31
- "swytchcode-cli-win32-x64": "2.3.22"
26
+ "swytchcode-cli-darwin-arm64": "2.5.1",
27
+ "swytchcode-cli-darwin-x64": "2.5.1",
28
+ "swytchcode-cli-linux-arm64": "2.5.1",
29
+ "swytchcode-cli-linux-x64": "2.5.1",
30
+ "swytchcode-cli-win32-arm64": "2.5.1",
31
+ "swytchcode-cli-win32-x64": "2.5.1"
32
32
  }
33
33
  }