@zapier/zapier-sdk-cli 0.68.0 → 0.69.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/dist/cli.mjs CHANGED
@@ -1,21 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command, CommanderError, Option } from 'commander';
3
- import { getConnectionPlugin, defineMethod, apiPluginRef, resolveCredentialsPluginRef, eventEmissionPluginRef, sdkOptionsPluginRef, declareOptionalProperty, OutputPropertySchema, ZapierBundleError, isZapierBundleError, DEFAULT_CONFIG_PATH, declareMethod, ZapierValidationError, isZapierValidationError, ZapierUnknownError, manifestPluginRef, defineResolver, isPermanentHttpError, isZapierAuthenticationError, ZapierApiError, defineMethodOverride, zapierCoreOptions, injectCliLogin, definePlugin, omitExports, zapierSdkPlugin, BaseSdkOptionsSchema, disposeSdk, invalidateCachedToken, batch, toSnakeCase, ZapierError, isZapierReleaseTriggerMessageSignal, createSdk as createSdk$1, CORE_OPTIONS_ID as CORE_OPTIONS_ID$1, SDK_OPTIONS_ID as SDK_OPTIONS_ID$1, addPlugin as addPlugin$1, getOrCreateApiClient, isCredentialsObject, ZapierAbortDrainSignal, ZapierReleaseTriggerMessageSignal, buildApplicationLifecycleEvent, AuthMechanism, DEPRECATION_NOTICE_EVENT, runWithCallerContext, isPositional, createController, isCoreCancelledSignal, resolvePlugin, isZapierError, formatErrorMessage, getOsInfo, getPlatformVersions, getAgent, getTtyContext, getCiPlatform, isCi, isZapierConflictError, getReleaseId, getCurrentTimestamp, generateEventId, isZapierApprovalError, ZapierAuthenticationError } from '@zapier/zapier-sdk';
3
+ import { getConnectionPlugin, defineMethod, apiPluginRef, resolveCredentialsPluginRef, eventEmissionPluginRef, sdkOptionsPluginRef, declareOptionalProperty, OutputPropertySchema, ZapierBundleError, isZapierBundleError, DEFAULT_CONFIG_PATH, declareMethod, ZapierValidationError, isZapierValidationError, ZapierUnknownError, manifestPluginRef, defineResolver, isPermanentHttpError, isZapierAuthenticationError, ZapierApiError, defineMethodOverride, zapierCoreOptions, injectCliLogin, definePlugin, omitExports, zapierSdkPlugin, BaseSdkOptionsSchema, disposeSdk, invalidateCachedToken, batch, toSnakeCase, ZapierError, isZapierReleaseTriggerMessageSignal, createSdk as createSdk$1, CORE_OPTIONS_ID as CORE_OPTIONS_ID$1, SDK_OPTIONS_ID as SDK_OPTIONS_ID$1, addPlugin as addPlugin$1, getOrCreateApiClient, isCredentialsObject, getRegistryPlugin, createController, ZapierAbortDrainSignal, ZapierReleaseTriggerMessageSignal, buildApplicationLifecycleEvent, AuthMechanism, DEPRECATION_NOTICE_EVENT, runWithCallerContext, isCoreCancelledSignal, isPositional, resolvePlugin, isZapierError, formatErrorMessage, getOsInfo, getPlatformVersions, getAgent, getTtyContext, getCiPlatform, isCi, isZapierConflictError, getReleaseId, getCurrentTimestamp, generateEventId, isZapierApprovalError, ZapierAuthenticationError } from '@zapier/zapier-sdk';
4
4
  import { z } from 'zod';
5
5
  import inquirer from 'inquirer';
6
6
  import chalk8 from 'chalk';
7
7
  import { makeTheme, createPrompt, useState, usePrefix, useMemo, useEffect, useKeypress, isEnterKey, isTabKey, isUpKey, isDownKey, usePagination, Separator } from '@inquirer/core';
8
8
  import ora from 'ora';
9
+ import * as fs from 'fs';
10
+ import { promises, createWriteStream, existsSync, readdirSync, readFileSync, rmSync, mkdirSync, writeFileSync, copyFileSync } from 'fs';
11
+ import * as path from 'path';
12
+ import { resolve, join, dirname, basename, relative, extname } from 'path';
13
+ import isInstalledGlobally from 'is-installed-globally';
9
14
  import util, { stripVTControlCharacters } from 'util';
10
- import wrapAnsi3 from 'wrap-ansi';
15
+ import wrapAnsi4 from 'wrap-ansi';
11
16
  import * as jwt from 'jsonwebtoken';
12
17
  import { deletePassword, getKeyring, setPassword, getPassword } from 'cross-keychain';
13
18
  import Conf from 'conf';
14
- import * as fs from 'fs';
15
- import { promises, createWriteStream, existsSync, readdirSync, rmSync, mkdirSync, writeFileSync, copyFileSync, readFileSync } from 'fs';
16
19
  import crypto, { createHash } from 'crypto';
17
- import * as path from 'path';
18
- import { resolve, join, dirname, basename, relative, extname } from 'path';
19
20
  import * as lockfile from 'proper-lockfile';
20
21
  import { hostname } from 'os';
21
22
  import express from 'express';
@@ -26,13 +27,14 @@ import { startMcpServer } from '@zapier/zapier-sdk-mcp';
26
27
  import { buildSync } from 'esbuild';
27
28
  import { mkdir, writeFile, access } from 'fs/promises';
28
29
  import * as ts from 'typescript';
29
- import isInstalledGlobally from 'is-installed-globally';
30
30
  import { execSync, spawn } from 'child_process';
31
31
  import Handlebars from 'handlebars';
32
32
  import { fileURLToPath } from 'url';
33
- import { triggerInboxResolver, DrainTriggerInboxSchema, WatchTriggerInboxSchema, injectCliLogin as injectCliLogin$1, definePlugin as definePlugin$1, omitExports as omitExports$1, zapierExperimentalSdkPlugin, createSdk, CORE_OPTIONS_ID, SDK_OPTIONS_ID, addPlugin } from '@zapier/zapier-sdk/experimental';
34
33
  import packageJsonLib, { VersionNotFoundError } from 'package-json';
35
34
  import semver from 'semver';
35
+ import crossSpawn from 'cross-spawn';
36
+ import Table from 'cli-table3';
37
+ import { triggerInboxResolver, DrainTriggerInboxSchema, WatchTriggerInboxSchema, injectCliLogin as injectCliLogin$1, definePlugin as definePlugin$1, omitExports as omitExports$1, zapierExperimentalSdkPlugin, createSdk, CORE_OPTIONS_ID, SDK_OPTIONS_ID, addPlugin } from '@zapier/zapier-sdk/experimental';
36
38
  import * as readline from 'readline';
37
39
 
38
40
  var __defProp = Object.defineProperty;
@@ -194,11 +196,21 @@ async function promptText({
194
196
  password
195
197
  }) {
196
198
  const { value } = await inquirer.prompt([
197
- { type: password ? "password" : "input", name: "value", message }
199
+ {
200
+ type: password ? "password" : "input",
201
+ name: "value",
202
+ message,
203
+ theme: HIGH_CONTRAST_PROMPT_THEME
204
+ }
198
205
  ]);
199
206
  return value;
200
207
  }
201
208
  var display = (c) => c.hint ? `${c.label} ${chalk8.dim(`(${c.hint})`)}` : c.label;
209
+ var HIGH_CONTRAST_PROMPT_THEME = {
210
+ style: {
211
+ answer: (text) => chalk8.inverse.bold(` ${text} `)
212
+ }
213
+ };
202
214
  function buildSelectRows(question, term) {
203
215
  const row = (name, action) => ({
204
216
  name,
@@ -265,9 +277,39 @@ function foldPage(acc, question, field) {
265
277
  checked: []
266
278
  };
267
279
  }
268
- async function answerSelect(question, field, box, failed = false) {
280
+ async function answerSelect(question, field, box, failed, mode) {
269
281
  const acc = failed ? void 0 : box.acc = foldPage(box.acc, question, field);
270
282
  const view = acc ? { ...question, choices: acc.choices } : question;
283
+ const isClosedListPrompt = mode === "closed-list" && !failed && !view.multiple;
284
+ const booleanValues = view.choices.map(({ value: value2 }) => value2);
285
+ if (isClosedListPrompt && booleanValues.length === 2 && booleanValues.includes("true") && booleanValues.includes("false")) {
286
+ const { value: value2 } = await inquirer.prompt([
287
+ {
288
+ type: "confirm",
289
+ name: "value",
290
+ message: view.message,
291
+ default: booleanValues[0] === "true",
292
+ theme: HIGH_CONTRAST_PROMPT_THEME
293
+ }
294
+ ]);
295
+ return { type: "choose", value: String(value2) };
296
+ }
297
+ if (isClosedListPrompt && view.choices.length > 0 && !offers(view, "search") && !offers(view, "next_page") && !offers(view, "retry")) {
298
+ const choices = view.choices.map((choice) => ({
299
+ name: display(choice),
300
+ value: choice.value
301
+ }));
302
+ const { value: value2 } = await inquirer.prompt([
303
+ {
304
+ type: "list",
305
+ name: "value",
306
+ message: view.message,
307
+ choices,
308
+ theme: HIGH_CONTRAST_PROMPT_THEME
309
+ }
310
+ ]);
311
+ return { type: "choose", value: value2 };
312
+ }
271
313
  if (question.multiple && acc) {
272
314
  if (acc.newStart > 0 && process.stdout.isTTY) {
273
315
  process.stdout.write("\x1B[1A\x1B[2K");
@@ -291,7 +333,13 @@ async function answerSelect(question, field, box, failed = false) {
291
333
  }))
292
334
  ];
293
335
  const { values } = await inquirer.prompt([
294
- { type: "checkbox", name: "values", message: question.message, choices }
336
+ {
337
+ type: "checkbox",
338
+ name: "values",
339
+ message: question.message,
340
+ choices,
341
+ theme: HIGH_CONTRAST_PROMPT_THEME
342
+ }
295
343
  ]);
296
344
  const selected = values;
297
345
  const picked = selected.filter((v) => !isActionRow(v));
@@ -386,7 +434,8 @@ async function answerCollection(question) {
386
434
  type: "confirm",
387
435
  name: "again",
388
436
  message: question.message,
389
- default: false
437
+ default: false,
438
+ theme: HIGH_CONTRAST_PROMPT_THEME
390
439
  }
391
440
  ]);
392
441
  return again ? { type: "add" } : { type: "done" };
@@ -401,22 +450,37 @@ function withEngineSpinner(answer, spinner) {
401
450
  }
402
451
  };
403
452
  }
404
- function createCliAnswer() {
453
+ function createCliAnswer({
454
+ mode = "search"
455
+ } = {}) {
405
456
  const box = {};
406
- return ({ result }) => {
407
- if (result.error !== void 0) {
408
- const message = typeof result.error === "string" ? result.error : result.error.message;
409
- console.log(chalk8.yellow(`! ${message}`));
410
- }
411
- const question = result.question;
412
- const field = question.path.length ? question.path.join(".") : "value";
413
- switch (question.type) {
414
- case "select":
415
- return answerSelect(question, field, box, result.status === "failed");
416
- case "input":
417
- return answerInput(question);
418
- case "collection":
419
- return answerCollection(question);
457
+ return async ({ result }) => {
458
+ try {
459
+ if (result.error !== void 0) {
460
+ const message = typeof result.error === "string" ? result.error : result.error.message;
461
+ console.log(chalk8.yellow(`! ${message}`));
462
+ }
463
+ const question = result.question;
464
+ const field = question.path.length ? question.path.join(".") : "value";
465
+ switch (question.type) {
466
+ case "select":
467
+ return await answerSelect(
468
+ question,
469
+ field,
470
+ box,
471
+ result.status === "failed",
472
+ mode
473
+ );
474
+ case "input":
475
+ return await answerInput(question);
476
+ case "collection":
477
+ return await answerCollection(question);
478
+ }
479
+ } catch (error) {
480
+ if (error instanceof Error && error.name === "ExitPromptError") {
481
+ return { type: "cancel" };
482
+ }
483
+ throw error;
420
484
  }
421
485
  };
422
486
  }
@@ -494,7 +558,86 @@ var SHARED_COMMAND_CLI_OPTIONS = [
494
558
 
495
559
  // package.json
496
560
  var package_default = {
497
- version: "0.68.0"};
561
+ version: "0.69.0"};
562
+ var PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
563
+ var LOCKFILES = [
564
+ ["pnpm-lock.yaml", "pnpm"],
565
+ ["yarn.lock", "yarn"],
566
+ ["bun.lock", "bun"],
567
+ ["bun.lockb", "bun"],
568
+ ["package-lock.json", "npm"]
569
+ ];
570
+ function readDeclaredPackageManager(cwd) {
571
+ try {
572
+ const manifest = JSON.parse(
573
+ readFileSync(join(cwd, "package.json"), "utf8")
574
+ );
575
+ if (typeof manifest !== "object" || manifest === null || !("packageManager" in manifest) || typeof manifest.packageManager !== "string") {
576
+ return void 0;
577
+ }
578
+ const [name] = manifest.packageManager.split("@", 1);
579
+ return PACKAGE_MANAGERS.find((packageManager) => packageManager === name);
580
+ } catch {
581
+ return void 0;
582
+ }
583
+ }
584
+ function detectPackageManager(cwd = process.cwd()) {
585
+ const lockfileManagers = new Set(
586
+ LOCKFILES.filter(([file]) => existsSync(join(cwd, file))).map(
587
+ ([, packageManager]) => packageManager
588
+ )
589
+ );
590
+ if (lockfileManagers.size === 1) {
591
+ return { name: [...lockfileManagers][0], source: "lockfile" };
592
+ }
593
+ const declaredPackageManager = readDeclaredPackageManager(cwd);
594
+ if (declaredPackageManager) {
595
+ return { name: declaredPackageManager, source: "package-json" };
596
+ }
597
+ const userAgent = process.env.npm_config_user_agent;
598
+ if (userAgent) {
599
+ if (userAgent.includes("yarn")) {
600
+ return { name: "yarn", source: "runtime" };
601
+ }
602
+ if (userAgent.includes("pnpm")) {
603
+ return { name: "pnpm", source: "runtime" };
604
+ }
605
+ if (userAgent.includes("bun")) {
606
+ return { name: "bun", source: "runtime" };
607
+ }
608
+ if (userAgent.includes("npm")) {
609
+ return { name: "npm", source: "runtime" };
610
+ }
611
+ }
612
+ return { name: "npm", source: "fallback" };
613
+ }
614
+ function getUpdateCommand(packageName) {
615
+ const pm = detectPackageManager();
616
+ const isGlobal = isInstalledGlobally;
617
+ if (isGlobal) {
618
+ switch (pm.name) {
619
+ case "yarn":
620
+ return `yarn global upgrade ${packageName}@latest`;
621
+ case "pnpm":
622
+ return `pnpm update -g ${packageName}@latest`;
623
+ case "bun":
624
+ return `bun update -g ${packageName}@latest`;
625
+ default:
626
+ return `npm install -g ${packageName}@latest`;
627
+ }
628
+ } else {
629
+ switch (pm.name) {
630
+ case "yarn":
631
+ return `yarn upgrade ${packageName}@latest`;
632
+ case "pnpm":
633
+ return `pnpm update ${packageName}@latest`;
634
+ case "bun":
635
+ return `bun update ${packageName}@latest`;
636
+ default:
637
+ return `npm install ${packageName}@latest`;
638
+ }
639
+ }
640
+ }
498
641
 
499
642
  // src/telemetry/builders.ts
500
643
  function createCliBaseEvent(context = {}) {
@@ -542,8 +685,7 @@ function buildCliCommandExecutedEvent({
542
685
  ci_platform: getCiPlatform(),
543
686
  ...getTtyContext(),
544
687
  agent: getAgent(),
545
- package_manager: data.package_manager ?? "pnpm",
546
- // Default based on project setup
688
+ package_manager: data.package_manager ?? detectPackageManager(process.cwd()).name,
547
689
  made_network_requests: data.made_network_requests ?? null,
548
690
  files_modified_count: data.files_modified_count ?? null,
549
691
  files_created_count: data.files_created_count ?? null,
@@ -637,7 +779,7 @@ var DETAIL_INDENT = " ";
637
779
  var DETAIL_MAX_LINES = 5;
638
780
  function formatDetailText(text, indent = DETAIL_INDENT) {
639
781
  const columns = Math.max((process.stdout.columns || 80) - indent.length, 40);
640
- const wrapped = wrapAnsi3(text, columns, { hard: true, trim: false });
782
+ const wrapped = wrapAnsi4(text, columns, { hard: true, trim: false });
641
783
  const lines = wrapped.split("\n");
642
784
  if (lines.length <= DETAIL_MAX_LINES) {
643
785
  return lines.join("\n" + indent);
@@ -5715,54 +5857,6 @@ var InitSchema = z.object({
5715
5857
  }).describe(
5716
5858
  "Create a new Zapier SDK project in a new directory with starter files"
5717
5859
  );
5718
- function detectPackageManager(cwd = process.cwd()) {
5719
- const ua = process.env.npm_config_user_agent;
5720
- if (ua) {
5721
- if (ua.includes("yarn")) return { name: "yarn", source: "runtime" };
5722
- if (ua.includes("pnpm")) return { name: "pnpm", source: "runtime" };
5723
- if (ua.includes("bun")) return { name: "bun", source: "runtime" };
5724
- if (ua.includes("npm")) return { name: "npm", source: "runtime" };
5725
- }
5726
- const files = [
5727
- ["pnpm-lock.yaml", "pnpm"],
5728
- ["yarn.lock", "yarn"],
5729
- ["bun.lockb", "bun"],
5730
- ["package-lock.json", "npm"]
5731
- ];
5732
- for (const [file, name] of files) {
5733
- if (existsSync(join(cwd, file))) {
5734
- return { name, source: "lockfile" };
5735
- }
5736
- }
5737
- return { name: "unknown", source: "fallback" };
5738
- }
5739
- function getUpdateCommand(packageName) {
5740
- const pm = detectPackageManager();
5741
- const isGlobal = isInstalledGlobally;
5742
- if (isGlobal) {
5743
- switch (pm.name) {
5744
- case "yarn":
5745
- return `yarn global upgrade ${packageName}@latest`;
5746
- case "pnpm":
5747
- return `pnpm update -g ${packageName}@latest`;
5748
- case "bun":
5749
- return `bun update -g ${packageName}@latest`;
5750
- default:
5751
- return `npm install -g ${packageName}@latest`;
5752
- }
5753
- } else {
5754
- switch (pm.name) {
5755
- case "yarn":
5756
- return `yarn upgrade ${packageName}@latest`;
5757
- case "pnpm":
5758
- return `pnpm update ${packageName}@latest`;
5759
- case "bun":
5760
- return `bun update ${packageName}@latest`;
5761
- default:
5762
- return `npm install ${packageName}@latest`;
5763
- }
5764
- }
5765
- }
5766
5860
  function getDirentParentPath(entry) {
5767
5861
  const e = entry;
5768
5862
  const parent = e.parentPath ?? e.path;
@@ -6159,17 +6253,16 @@ var initPlugin = defineMethod({
6159
6253
  const cwd = process.cwd();
6160
6254
  const { projectName, projectDir } = validateInitOptions({ rawName, cwd });
6161
6255
  const displayHooks = createConsoleDisplayHooks();
6162
- const packageManagerInfo = detectPackageManager(cwd);
6163
- if (packageManagerInfo.name === "unknown") {
6256
+ const packageManager = detectPackageManager(cwd);
6257
+ if (packageManager.source === "fallback") {
6164
6258
  displayHooks.onWarn(
6165
6259
  "Could not detect package manager, defaulting to npm."
6166
6260
  );
6167
6261
  }
6168
- const packageManager = packageManagerInfo.name === "unknown" ? "npm" : packageManagerInfo.name;
6169
6262
  const steps = getInitSteps({
6170
6263
  projectDir,
6171
6264
  projectName,
6172
- packageManager,
6265
+ packageManager: packageManager.name,
6173
6266
  displayHooks
6174
6267
  });
6175
6268
  const completedSetupStepIds = [];
@@ -6197,99 +6290,1427 @@ var initPlugin = defineMethod({
6197
6290
  projectName,
6198
6291
  steps,
6199
6292
  completedSetupStepIds,
6200
- packageManager
6293
+ packageManager: packageManager.name
6201
6294
  });
6202
6295
  }
6203
6296
  });
6204
- var CliSkipLeaseExpireError = class extends Error {
6205
- constructor() {
6206
- super("user skipped (let lease expire)");
6207
- this.name = "CliSkipLeaseExpireError";
6297
+ var ONE_DAY_MILLISECONDS = 24 * 60 * 60 * 1e3;
6298
+ var CACHE_RESET_INTERVAL_MILLISECONDS = (() => {
6299
+ const {
6300
+ ZAPIER_SDK_UPDATE_CHECK_INTERVAL_SECONDS,
6301
+ ZAPIER_SDK_UPDATE_CHECK_INTERVAL_MS
6302
+ } = process.env;
6303
+ let intervalMs;
6304
+ if (ZAPIER_SDK_UPDATE_CHECK_INTERVAL_SECONDS !== void 0) {
6305
+ const seconds = parseInt(ZAPIER_SDK_UPDATE_CHECK_INTERVAL_SECONDS);
6306
+ intervalMs = isNaN(seconds) ? NaN : seconds * 1e3;
6307
+ } else if (ZAPIER_SDK_UPDATE_CHECK_INTERVAL_MS !== void 0) {
6308
+ intervalMs = parseInt(ZAPIER_SDK_UPDATE_CHECK_INTERVAL_MS);
6309
+ } else {
6310
+ intervalMs = ONE_DAY_MILLISECONDS;
6208
6311
  }
6209
- };
6210
- function createInteractiveCallback() {
6211
- let messageNumber = 0;
6212
- return async (message) => {
6213
- messageNumber++;
6214
- const attrs = message.message_attributes;
6215
- console.log(
6216
- `
6217
- ${chalk8.bold(`Message #${messageNumber}`)} ${chalk8.dim(message.id)} ${chalk8.dim(`(lease #${attrs.lease_count})`)}`
6218
- );
6219
- if (attrs.error_message) {
6220
- console.log(chalk8.yellow(` upstream error: ${attrs.error_message}`));
6221
- }
6222
- if (attrs.possible_duplicate_data) {
6223
- console.log(chalk8.yellow(" possible duplicate data"));
6312
+ if (isNaN(intervalMs) || intervalMs < 0) {
6313
+ return -1;
6314
+ }
6315
+ return intervalMs;
6316
+ })();
6317
+ function getVersionCache() {
6318
+ try {
6319
+ const cache = getConfig().get("version_cache");
6320
+ const now = Date.now();
6321
+ if (!cache || !cache.last_reset_timestamp || now - cache.last_reset_timestamp >= CACHE_RESET_INTERVAL_MILLISECONDS) {
6322
+ const newCache = {
6323
+ last_reset_timestamp: now,
6324
+ packages: {}
6325
+ };
6326
+ getConfig().set("version_cache", newCache);
6327
+ return newCache;
6224
6328
  }
6225
- while (true) {
6226
- let action;
6227
- try {
6228
- const answer = await inquirer.prompt([
6229
- {
6230
- type: "list",
6231
- name: "action",
6232
- message: "Action?",
6233
- choices: [
6234
- { name: "Ack (remove from inbox)", value: "ack" },
6235
- {
6236
- name: "Skip (release after draining)",
6237
- value: "skip-release"
6238
- },
6239
- { name: "Skip (let lease expire)", value: "skip-expire" },
6240
- { name: "View payload", value: "view" },
6241
- { name: "Quit", value: "quit" }
6242
- ]
6243
- }
6244
- ]);
6245
- action = answer.action;
6246
- } catch (error) {
6247
- if (error instanceof Error && error.name === "ExitPromptError") {
6248
- throw new ZapierAbortDrainSignal("user pressed Ctrl-C");
6249
- }
6250
- throw error;
6251
- }
6252
- if (action === "view") {
6253
- console.log(chalk8.dim(JSON.stringify(message.payload, null, 2)));
6254
- continue;
6255
- }
6256
- if (action === "ack") {
6257
- return;
6258
- }
6259
- if (action === "skip-release") {
6260
- throw new ZapierReleaseTriggerMessageSignal("user skipped (release)");
6261
- }
6262
- if (action === "skip-expire") {
6263
- throw new CliSkipLeaseExpireError();
6264
- }
6265
- if (action === "quit") {
6266
- throw new ZapierAbortDrainSignal("user requested quit");
6267
- }
6329
+ return cache;
6330
+ } catch (error) {
6331
+ log_default.debug(`Failed to read version cache: ${error}`);
6332
+ return {
6333
+ last_reset_timestamp: Date.now(),
6334
+ packages: {}
6335
+ };
6336
+ }
6337
+ }
6338
+ function setCachedPackageInfo(packageName, version, info) {
6339
+ try {
6340
+ const cache = getVersionCache();
6341
+ if (!cache.packages[packageName]) {
6342
+ cache.packages[packageName] = {};
6268
6343
  }
6269
- };
6344
+ cache.packages[packageName][version] = info;
6345
+ getConfig().set("version_cache", cache);
6346
+ } catch (error) {
6347
+ log_default.debug(`Failed to cache package info: ${error}`);
6348
+ }
6270
6349
  }
6271
- function createNdjsonCallback() {
6272
- return (message) => new Promise((resolve4, reject) => {
6273
- process.stdout.write(JSON.stringify(message) + "\n", (err) => {
6274
- if (err) reject(err);
6275
- else resolve4();
6276
- });
6277
- });
6350
+ function getCachedPackageInfo(packageName, version) {
6351
+ try {
6352
+ const cache = getVersionCache();
6353
+ return cache.packages[packageName]?.[version];
6354
+ } catch (error) {
6355
+ log_default.debug(`Failed to get cached package info: ${error}`);
6356
+ return void 0;
6357
+ }
6278
6358
  }
6279
- function runSubprocess(options) {
6280
- const { command, args, shell, label, message, signal } = options;
6281
- return new Promise((resolve4, reject) => {
6282
- const child = spawn(command, args, {
6283
- shell,
6284
- stdio: ["pipe", "inherit", "inherit"]
6285
- });
6286
- let abortListener;
6287
- if (signal) {
6288
- if (signal.aborted) {
6289
- child.kill();
6290
- } else {
6291
- abortListener = () => {
6292
- child.kill();
6359
+ async function fetchCachedPackageInfo(packageName, version) {
6360
+ const cacheKey = version || "latest";
6361
+ let cachedInfo = getCachedPackageInfo(packageName, cacheKey);
6362
+ if (cachedInfo) {
6363
+ return cachedInfo;
6364
+ }
6365
+ const packageInfo = await packageJsonLib(packageName, {
6366
+ version,
6367
+ fullMetadata: true
6368
+ });
6369
+ const info = {
6370
+ version: packageInfo.version,
6371
+ deprecated: packageInfo.deprecated,
6372
+ fetched_at: (/* @__PURE__ */ new Date()).toISOString()
6373
+ };
6374
+ setCachedPackageInfo(packageName, cacheKey, info);
6375
+ return info;
6376
+ }
6377
+ async function checkForUpdates({
6378
+ packageName,
6379
+ currentVersion
6380
+ }) {
6381
+ try {
6382
+ const latestPackageInfo = await fetchCachedPackageInfo(packageName);
6383
+ const latestVersion = latestPackageInfo.version;
6384
+ const hasUpdate = semver.gt(latestVersion, currentVersion);
6385
+ let currentPackageInfo;
6386
+ try {
6387
+ currentPackageInfo = await fetchCachedPackageInfo(
6388
+ packageName,
6389
+ currentVersion
6390
+ );
6391
+ } catch (error) {
6392
+ if (!(error instanceof VersionNotFoundError)) {
6393
+ log_default.debug(`Failed to check deprecation for current version: ${error}`);
6394
+ }
6395
+ currentPackageInfo = latestPackageInfo;
6396
+ }
6397
+ const isDeprecated = Boolean(currentPackageInfo.deprecated);
6398
+ const deprecationMessage = isDeprecated ? String(currentPackageInfo.deprecated) : void 0;
6399
+ return {
6400
+ hasUpdate,
6401
+ latestVersion,
6402
+ currentVersion,
6403
+ isDeprecated,
6404
+ deprecationMessage
6405
+ };
6406
+ } catch (error) {
6407
+ log_default.debug(`Failed to check for updates: ${error}`);
6408
+ return {
6409
+ hasUpdate: false,
6410
+ currentVersion,
6411
+ isDeprecated: false
6412
+ };
6413
+ }
6414
+ }
6415
+ function displayUpdateNotification(versionInfo, packageName) {
6416
+ if (versionInfo.isDeprecated) {
6417
+ console.error();
6418
+ console.error(
6419
+ chalk8.red.bold("\u26A0\uFE0F DEPRECATION WARNING") + chalk8.red(
6420
+ ` - ${packageName} v${versionInfo.currentVersion} is deprecated.`
6421
+ )
6422
+ );
6423
+ if (versionInfo.deprecationMessage) {
6424
+ console.error(chalk8.red(` ${versionInfo.deprecationMessage}`));
6425
+ }
6426
+ console.error(chalk8.red(` Please update to the latest version.`));
6427
+ console.error();
6428
+ }
6429
+ if (versionInfo.hasUpdate) {
6430
+ console.error();
6431
+ console.error(
6432
+ chalk8.yellow.bold("\u{1F4E6} Update available!") + chalk8.yellow(
6433
+ ` ${packageName} v${versionInfo.currentVersion} \u2192 v${versionInfo.latestVersion}`
6434
+ )
6435
+ );
6436
+ console.error(
6437
+ chalk8.yellow(
6438
+ ` Run ${chalk8.bold(getUpdateCommand(packageName))} to update.`
6439
+ )
6440
+ );
6441
+ console.error();
6442
+ }
6443
+ }
6444
+ async function checkAndNotifyUpdates({
6445
+ packageName,
6446
+ currentVersion
6447
+ }) {
6448
+ if (CACHE_RESET_INTERVAL_MILLISECONDS < 0) {
6449
+ return;
6450
+ }
6451
+ const versionInfo = await checkForUpdates({ packageName, currentVersion });
6452
+ displayUpdateNotification(versionInfo, packageName);
6453
+ }
6454
+ var BRAILLE_BLANK = "\u2800";
6455
+ var LIGHTNING_INTERVAL_MILLISECONDS = 140;
6456
+ var boltRows = [
6457
+ "\u2800\u2800\u2880\u28FE\u2800\u2800\u2800\u2800",
6458
+ "\u2800\u2800\u28E0\u28FF\u28FF\u2800\u2800\u2800",
6459
+ "\u2800\u28FC\u28FF\u28FF\u28FF\u28C0\u28C0\u2840",
6460
+ "\u2808\u2809\u2809\u28FF\u28FF\u28FF\u285F\u2800",
6461
+ "\u2800\u2800\u2800\u28FF\u28FF\u280B\u2800\u2800",
6462
+ "\u2800\u2800\u2800\u287F\u2801\u2800\u2800\u2800"
6463
+ ];
6464
+ var boltFillOrder = boltRows.flatMap(
6465
+ (row, rowIndex) => [...row].flatMap(
6466
+ (cell, columnIndex) => cell === BRAILLE_BLANK ? [] : rowIndex * row.length + columnIndex
6467
+ )
6468
+ );
6469
+ var fillStages = [
6470
+ ...Array.from({ length: boltFillOrder.length + 1 }, (_, index) => index),
6471
+ boltFillOrder.length,
6472
+ 0
6473
+ ];
6474
+ var boltFillRanks = new Map(
6475
+ boltFillOrder.map((cellIndex, fillIndex) => [cellIndex, fillIndex])
6476
+ );
6477
+ var STATUS_ROW_INDEX = Math.floor(boltRows.length / 2);
6478
+ function formatPhase({ label, detail }) {
6479
+ return detail ? `${chalk8.bold(label)} ${chalk8.dim(detail)}` : chalk8.bold(label);
6480
+ }
6481
+ function formatLoaderFrame({
6482
+ phase,
6483
+ fillStage
6484
+ }) {
6485
+ return boltRows.map((row, rowIndex) => {
6486
+ const bolt = [...row].map((cell, columnIndex) => {
6487
+ if (cell === BRAILLE_BLANK) return cell;
6488
+ const cellIndex = rowIndex * row.length + columnIndex;
6489
+ const fillRank = boltFillRanks.get(cellIndex);
6490
+ const isFilled = fillRank !== void 0 && fillRank < fillStage;
6491
+ return isFilled ? chalk8.bold.yellow(cell) : chalk8.dim.yellow(cell);
6492
+ }).join("");
6493
+ const status = rowIndex === STATUS_ROW_INDEX ? ` ${formatPhase(phase)}` : "";
6494
+ return `${bolt}${status}`;
6495
+ }).join("\n");
6496
+ }
6497
+ async function runWithSetupLoader({
6498
+ promise,
6499
+ ...phase
6500
+ }) {
6501
+ const startedAt = Date.now();
6502
+ let fillFrameIndex = 0;
6503
+ const loader = ora({
6504
+ isEnabled: process.stderr.isTTY === true,
6505
+ spinner: { interval: 80, frames: [""] },
6506
+ text: formatLoaderFrame({
6507
+ phase,
6508
+ fillStage: fillStages[fillFrameIndex]
6509
+ })
6510
+ }).start();
6511
+ const animationTimer = setInterval(() => {
6512
+ fillFrameIndex = (fillFrameIndex + 1) % fillStages.length;
6513
+ loader.text = formatLoaderFrame({
6514
+ phase,
6515
+ fillStage: fillStages[fillFrameIndex]
6516
+ });
6517
+ }, LIGHTNING_INTERVAL_MILLISECONDS);
6518
+ animationTimer.unref?.();
6519
+ try {
6520
+ const result = await promise;
6521
+ clearInterval(animationTimer);
6522
+ const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
6523
+ loader.succeed(`${formatPhase(phase)} ${chalk8.dim(`${elapsedSeconds}s`)}`);
6524
+ return result;
6525
+ } catch (error) {
6526
+ clearInterval(animationTimer);
6527
+ const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
6528
+ loader.fail(`${formatPhase(phase)} ${chalk8.dim(`${elapsedSeconds}s`)}`);
6529
+ throw error;
6530
+ }
6531
+ }
6532
+ function isRecord(value) {
6533
+ return typeof value === "object" && value !== null && !Array.isArray(value);
6534
+ }
6535
+ function readPackageJson({
6536
+ directory
6537
+ }) {
6538
+ try {
6539
+ const manifest = JSON.parse(
6540
+ readFileSync(join(directory, "package.json"), "utf8")
6541
+ );
6542
+ return isRecord(manifest) ? manifest : void 0;
6543
+ } catch {
6544
+ return void 0;
6545
+ }
6546
+ }
6547
+ var SetupOptionSchema = z.object({
6548
+ label: z.string(),
6549
+ value: z.string()
6550
+ });
6551
+ var SetupOptionsSchema = z.array(SetupOptionSchema).min(1);
6552
+ var SetupDecisionSchema = z.object({
6553
+ message: z.string(),
6554
+ options: SetupOptionsSchema,
6555
+ answer: z.string()
6556
+ });
6557
+ var SetupInputSchema = z.object({
6558
+ message: z.string(),
6559
+ answer: z.string()
6560
+ });
6561
+ var setupDecisionResolver = defineResolver({
6562
+ requireParameters: ["message", "options"],
6563
+ listItems: ({ input }) => ({ data: input.options }),
6564
+ prompt: ({ items, input }) => ({
6565
+ type: "list",
6566
+ message: input.message,
6567
+ choices: items
6568
+ }),
6569
+ validate: ({ input, value }) => {
6570
+ if (typeof value !== "string") return "Choose an available option.";
6571
+ return input.options.some((option) => option.value === value) || "Choose one of the available options.";
6572
+ }
6573
+ });
6574
+ var setupInputResolver = defineResolver({
6575
+ type: "static",
6576
+ inputType: "text",
6577
+ requireParameters: ["message"]
6578
+ });
6579
+ var resolveSetupDecisionPlugin = defineMethod({
6580
+ name: "resolveSetupDecision",
6581
+ description: "Resolve one setup wizard decision.",
6582
+ inputSchema: SetupDecisionSchema,
6583
+ resolvers: { answer: setupDecisionResolver },
6584
+ run: ({ input }) => input
6585
+ });
6586
+ var resolveSetupInputPlugin = defineMethod({
6587
+ name: "resolveSetupInput",
6588
+ description: "Resolve one setup wizard text input.",
6589
+ inputSchema: SetupInputSchema,
6590
+ resolvers: { answer: setupInputResolver },
6591
+ run: ({ input }) => input
6592
+ });
6593
+ function createSetupController() {
6594
+ const setupResolutionSdk = createSdk$1(
6595
+ definePlugin({
6596
+ name: "setup-resolution",
6597
+ exports: [
6598
+ resolveSetupDecisionPlugin,
6599
+ resolveSetupInputPlugin,
6600
+ getRegistryPlugin
6601
+ ]
6602
+ })
6603
+ );
6604
+ return createController(setupResolutionSdk);
6605
+ }
6606
+ async function resolveWithCancellation({
6607
+ run
6608
+ }) {
6609
+ try {
6610
+ return await run();
6611
+ } catch (error) {
6612
+ if (isCoreCancelledSignal(error)) {
6613
+ throw new ZapierCliUserCancellationError();
6614
+ }
6615
+ throw error;
6616
+ }
6617
+ }
6618
+ async function resolveSetupDecision({
6619
+ answer,
6620
+ controller,
6621
+ message,
6622
+ options
6623
+ }) {
6624
+ const parsedOptions = SetupOptionsSchema.parse(options);
6625
+ const resolved = await resolveWithCancellation({
6626
+ run: () => controller.resolve({
6627
+ method: "resolveSetupDecision",
6628
+ input: { message, options: parsedOptions },
6629
+ answer,
6630
+ interactive: true
6631
+ })
6632
+ });
6633
+ return SetupDecisionSchema.parse(resolved).answer;
6634
+ }
6635
+ async function resolveSetupConfirm({
6636
+ answer,
6637
+ controller,
6638
+ defaultValue,
6639
+ message
6640
+ }) {
6641
+ const values = defaultValue ? [true, false] : [false, true];
6642
+ const resolved = await resolveSetupDecision({
6643
+ answer,
6644
+ controller,
6645
+ message,
6646
+ options: values.map((value) => ({
6647
+ label: value ? "Yes" : "No",
6648
+ value: String(value)
6649
+ }))
6650
+ });
6651
+ return resolved === "true";
6652
+ }
6653
+ async function resolveSetupInput({
6654
+ answer,
6655
+ controller,
6656
+ message
6657
+ }) {
6658
+ const resolved = await resolveWithCancellation({
6659
+ run: () => controller.resolve({
6660
+ method: "resolveSetupInput",
6661
+ input: { message },
6662
+ answer: ({ result, state }) => answer({
6663
+ state,
6664
+ result: {
6665
+ ...result,
6666
+ question: { ...result.question, message }
6667
+ }
6668
+ }),
6669
+ interactive: true
6670
+ })
6671
+ });
6672
+ return SetupInputSchema.parse(resolved).answer.trim();
6673
+ }
6674
+ async function resolveSetupSelect({
6675
+ answer,
6676
+ controller,
6677
+ choices,
6678
+ message
6679
+ }) {
6680
+ const resolved = await resolveSetupDecision({
6681
+ answer,
6682
+ controller,
6683
+ message,
6684
+ options: choices
6685
+ });
6686
+ const selected = choices.find(({ value }) => value === resolved);
6687
+ if (!selected) {
6688
+ throw new Error("Resolved setup selection is not an available choice.");
6689
+ }
6690
+ return selected.value;
6691
+ }
6692
+
6693
+ // src/plugins/setup/dependencies.ts
6694
+ var REQUIRED_PACKAGES = [
6695
+ { name: "@zapier/zapier-sdk", dev: false, checkForUpdates: true },
6696
+ { name: "@zapier/zapier-sdk-cli", dev: true, checkForUpdates: true },
6697
+ {
6698
+ name: "@types/node",
6699
+ dev: true,
6700
+ checkForUpdates: false,
6701
+ typescriptOnly: true
6702
+ },
6703
+ {
6704
+ name: "typescript",
6705
+ dev: true,
6706
+ checkForUpdates: false,
6707
+ typescriptOnly: true
6708
+ },
6709
+ { name: "tsx", dev: true, checkForUpdates: false, typescriptOnly: true }
6710
+ ];
6711
+ function getInstallCommand({
6712
+ packageManager,
6713
+ packages,
6714
+ dev = false
6715
+ }) {
6716
+ const verb = packageManager === "npm" ? "install" : "add";
6717
+ const devFlag = packageManager === "bun" ? "-d" : "-D";
6718
+ return {
6719
+ command: packageManager,
6720
+ args: [verb, ...dev ? [devFlag] : [], ...packages]
6721
+ };
6722
+ }
6723
+ async function executeInstall(context, command) {
6724
+ try {
6725
+ await context.runCommand({ ...command, cwd: context.cwd });
6726
+ } catch (error) {
6727
+ const message = error instanceof Error ? error.message : String(error);
6728
+ if (message.includes("EPERM") && message.includes(".npm/_cacache")) {
6729
+ console.error(
6730
+ "This EPERM usually means the command sandbox blocked npm cache writes; it does not usually mean your file permissions are broken."
6731
+ );
6732
+ }
6733
+ throw error;
6734
+ }
6735
+ }
6736
+ function getDeclaredPackageNames(cwd) {
6737
+ const manifest = readPackageJson({ directory: cwd });
6738
+ if (!manifest) return /* @__PURE__ */ new Set();
6739
+ const names = /* @__PURE__ */ new Set();
6740
+ for (const section of ["dependencies", "devDependencies"]) {
6741
+ const dependencies = manifest[section];
6742
+ if (!isRecord(dependencies)) continue;
6743
+ for (const name of Object.keys(dependencies)) names.add(name);
6744
+ }
6745
+ return names;
6746
+ }
6747
+ function getInstalledPackageVersion({
6748
+ cwd,
6749
+ packageName
6750
+ }) {
6751
+ let directory = cwd;
6752
+ while (true) {
6753
+ const manifest = readPackageJson({
6754
+ directory: join(directory, "node_modules", ...packageName.split("/"))
6755
+ });
6756
+ if (manifest?.name === packageName && typeof manifest.version === "string") {
6757
+ return manifest.version;
6758
+ }
6759
+ const parent = dirname(directory);
6760
+ if (parent === directory) return void 0;
6761
+ directory = parent;
6762
+ }
6763
+ }
6764
+ async function installPackages({
6765
+ context,
6766
+ packages
6767
+ }) {
6768
+ const runtimePackages = packages.filter(({ dependency }) => !dependency.dev).map(({ dependency }) => dependency.name);
6769
+ if (runtimePackages.length > 0) {
6770
+ await executeInstall(
6771
+ context,
6772
+ getInstallCommand({
6773
+ packageManager: context.packageManager,
6774
+ packages: runtimePackages
6775
+ })
6776
+ );
6777
+ }
6778
+ const developmentPackages = packages.filter(({ dependency }) => dependency.dev).map(({ dependency }) => dependency.name);
6779
+ if (developmentPackages.length > 0) {
6780
+ await executeInstall(
6781
+ context,
6782
+ getInstallCommand({
6783
+ packageManager: context.packageManager,
6784
+ packages: developmentPackages,
6785
+ dev: true
6786
+ })
6787
+ );
6788
+ }
6789
+ }
6790
+ async function offerMissingPackageInstall({
6791
+ context,
6792
+ packages
6793
+ }) {
6794
+ if (packages.length === 0) return;
6795
+ const shouldInstall = await resolveSetupConfirm({
6796
+ answer: context.createAnswer(),
6797
+ controller: context.setupController,
6798
+ message: `These packages are required to continue. Install them now: ${packages.map(({ dependency }) => dependency.name).join(", ")}?`,
6799
+ defaultValue: true
6800
+ });
6801
+ if (!shouldInstall) {
6802
+ console.log(
6803
+ "The Zapier SDK packages are required to continue. Setup cancelled without installing dependencies."
6804
+ );
6805
+ throw new ZapierCliUserCancellationError(
6806
+ "Required Zapier SDK packages were not installed"
6807
+ );
6808
+ }
6809
+ await installPackages({ context, packages });
6810
+ }
6811
+ async function offerPackageUpdate({
6812
+ context,
6813
+ packageState
6814
+ }) {
6815
+ const { currentVersion, dependency } = packageState;
6816
+ if (!currentVersion || !dependency.checkForUpdates) return;
6817
+ const update = await runWithSetupLoader({
6818
+ promise: context.checkForUpdates({
6819
+ packageName: dependency.name,
6820
+ currentVersion
6821
+ }),
6822
+ label: "Checking for updates",
6823
+ detail: dependency.name
6824
+ });
6825
+ if (!update.hasUpdate || !update.latestVersion) return;
6826
+ const shouldUpdate = await resolveSetupConfirm({
6827
+ answer: context.createAnswer(),
6828
+ controller: context.setupController,
6829
+ message: `Update ${dependency.name} from ${currentVersion} to ${update.latestVersion}?`,
6830
+ defaultValue: true
6831
+ });
6832
+ if (!shouldUpdate) return;
6833
+ await executeInstall(
6834
+ context,
6835
+ getInstallCommand({
6836
+ packageManager: context.packageManager,
6837
+ packages: [`${dependency.name}@${update.latestVersion}`],
6838
+ dev: dependency.dev
6839
+ })
6840
+ );
6841
+ }
6842
+ async function prepareDependencies(context) {
6843
+ const declaredPackageNames = getDeclaredPackageNames(context.cwd);
6844
+ const requiredPackages = REQUIRED_PACKAGES.filter(
6845
+ ({ typescriptOnly }) => !typescriptOnly || context.projectLanguage === "typescript"
6846
+ );
6847
+ const packages = requiredPackages.map((dependency) => ({
6848
+ dependency,
6849
+ currentVersion: declaredPackageNames.has(dependency.name) ? getInstalledPackageVersion({
6850
+ cwd: context.cwd,
6851
+ packageName: dependency.name
6852
+ }) : void 0
6853
+ }));
6854
+ await offerMissingPackageInstall({
6855
+ context,
6856
+ packages: packages.filter(
6857
+ ({ dependency }) => !declaredPackageNames.has(dependency.name)
6858
+ )
6859
+ });
6860
+ for (const packageState of packages) {
6861
+ await offerPackageUpdate({ context, packageState });
6862
+ }
6863
+ }
6864
+
6865
+ // src/plugins/setup/package-commands.ts
6866
+ function createLocalPackageCommand({
6867
+ packageManager,
6868
+ binary,
6869
+ args = []
6870
+ }) {
6871
+ const runner = {
6872
+ npm: { command: "npx", args: ["--no-install"] },
6873
+ pnpm: { command: "pnpm", args: ["exec"] },
6874
+ yarn: { command: "yarn", args: ["exec"] },
6875
+ bun: { command: "bunx", args: ["--no-install"] }
6876
+ };
6877
+ return {
6878
+ command: runner[packageManager].command,
6879
+ args: [...runner[packageManager].args, binary, ...args]
6880
+ };
6881
+ }
6882
+ function createPackageRunnerCommand({
6883
+ packageManager,
6884
+ packageName,
6885
+ args = []
6886
+ }) {
6887
+ const runner = {
6888
+ npm: { command: "npx", args: ["--yes"] },
6889
+ pnpm: { command: "pnpm", args: ["dlx"] },
6890
+ yarn: { command: "yarn", args: ["dlx"] },
6891
+ bun: { command: "bunx", args: [] }
6892
+ };
6893
+ return {
6894
+ command: runner[packageManager].command,
6895
+ args: [...runner[packageManager].args, packageName, ...args]
6896
+ };
6897
+ }
6898
+ function formatPackageCommand({
6899
+ command,
6900
+ args
6901
+ }) {
6902
+ return [command, ...args].join(" ");
6903
+ }
6904
+
6905
+ // src/plugins/setup/project.ts
6906
+ var COMMAND_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
6907
+ var PROJECT_INIT_COMMANDS = {
6908
+ npm: { command: "npm", args: ["init", "-y"] },
6909
+ pnpm: { command: "pnpm", args: ["init"] },
6910
+ yarn: { command: "yarn", args: ["init", "-y"] },
6911
+ bun: { command: "bun", args: ["init", "-y"] }
6912
+ };
6913
+ var CapturedCommandError = class extends Error {
6914
+ constructor(error, stdout, stderr) {
6915
+ super(error.message);
6916
+ this.stdout = stdout;
6917
+ this.stderr = stderr;
6918
+ }
6919
+ };
6920
+ function commandError({
6921
+ command,
6922
+ code,
6923
+ signal
6924
+ }) {
6925
+ return new Error(
6926
+ signal ? `${command} was terminated by ${signal}` : `${command} exited with code ${code ?? "unknown"}`
6927
+ );
6928
+ }
6929
+ function executeCapturedCommand({
6930
+ command,
6931
+ args,
6932
+ cwd,
6933
+ input
6934
+ }) {
6935
+ return new Promise((resolve4, reject) => {
6936
+ const child = crossSpawn(command, args, {
6937
+ cwd,
6938
+ shell: false,
6939
+ stdio: ["pipe", "pipe", "pipe"]
6940
+ });
6941
+ let stdout = "";
6942
+ let stderr = "";
6943
+ const append = ({
6944
+ chunk,
6945
+ stream
6946
+ }) => {
6947
+ if (stream === "stdout") stdout += chunk.toString();
6948
+ else stderr += chunk.toString();
6949
+ if (Buffer.byteLength(stdout) + Buffer.byteLength(stderr) > COMMAND_MAX_BUFFER_BYTES) {
6950
+ child.kill();
6951
+ reject(new Error("Command output exceeded the capture limit."));
6952
+ }
6953
+ };
6954
+ child.stdout?.on(
6955
+ "data",
6956
+ (chunk) => append({ chunk, stream: "stdout" })
6957
+ );
6958
+ child.stderr?.on(
6959
+ "data",
6960
+ (chunk) => append({ chunk, stream: "stderr" })
6961
+ );
6962
+ child.once("error", reject);
6963
+ child.once("close", (code, signal) => {
6964
+ if (code === 0) {
6965
+ resolve4(stdout.trim());
6966
+ return;
6967
+ }
6968
+ reject(
6969
+ new CapturedCommandError(
6970
+ commandError({ command, code, signal }),
6971
+ stdout,
6972
+ stderr
6973
+ )
6974
+ );
6975
+ });
6976
+ child.stdin?.end(input);
6977
+ });
6978
+ }
6979
+ function executeStreamingCommand({
6980
+ command,
6981
+ args,
6982
+ cwd,
6983
+ input
6984
+ }) {
6985
+ return new Promise((resolve4, reject) => {
6986
+ const child = crossSpawn(command, args, {
6987
+ cwd,
6988
+ shell: false,
6989
+ stdio: [input === void 0 ? "inherit" : "pipe", "inherit", "inherit"]
6990
+ });
6991
+ child.once("error", reject);
6992
+ child.once("close", (code, signal) => {
6993
+ if (code === 0) {
6994
+ resolve4("");
6995
+ return;
6996
+ }
6997
+ reject(commandError({ command, code, signal }));
6998
+ });
6999
+ if (input !== void 0) child.stdin?.end(input);
7000
+ });
7001
+ }
7002
+ async function runCommand({
7003
+ command,
7004
+ args = [],
7005
+ cwd,
7006
+ capture = true,
7007
+ input
7008
+ }) {
7009
+ const commandLabel = `$ ${command} ${args.join(" ")}`.trim();
7010
+ const execute = capture ? executeCapturedCommand({ command, args, cwd, input }) : executeStreamingCommand({ command, args, cwd, input });
7011
+ try {
7012
+ if (capture) {
7013
+ return await runWithSetupLoader({
7014
+ promise: execute,
7015
+ label: "Running command",
7016
+ detail: commandLabel
7017
+ });
7018
+ }
7019
+ console.log(chalk8.dim(commandLabel));
7020
+ return await execute;
7021
+ } catch (error) {
7022
+ const message = error instanceof Error ? error.message : String(error);
7023
+ if (error instanceof CapturedCommandError) {
7024
+ if (error.stdout) process.stdout.write(error.stdout);
7025
+ if (error.stderr) process.stderr.write(error.stderr);
7026
+ if (!error.stdout && !error.stderr) console.error(message);
7027
+ } else {
7028
+ console.error(message);
7029
+ }
7030
+ throw new ZapierCliExitError(message);
7031
+ }
7032
+ }
7033
+ async function chooseDirectory(context) {
7034
+ const useCurrentDirectory = await resolveSetupConfirm({
7035
+ answer: context.createAnswer(),
7036
+ controller: context.setupController,
7037
+ message: `Set up the Zapier SDK in ${context.cwd}?`,
7038
+ defaultValue: true
7039
+ });
7040
+ if (useCurrentDirectory) return;
7041
+ const setupCommand = formatPackageCommand(
7042
+ createLocalPackageCommand({
7043
+ packageManager: context.packageManager,
7044
+ binary: "zapier-sdk",
7045
+ args: ["setup"]
7046
+ })
7047
+ );
7048
+ console.log(
7049
+ `Setup cancelled. Navigate to the intended directory and run \`${setupCommand}\` again.`
7050
+ );
7051
+ throw new ZapierCliUserCancellationError("Setup cancelled by user");
7052
+ }
7053
+ async function ensureSupportedNode(context) {
7054
+ let version;
7055
+ try {
7056
+ version = await context.runCommand({
7057
+ command: "node",
7058
+ args: ["-v"],
7059
+ cwd: context.cwd,
7060
+ capture: true
7061
+ });
7062
+ } catch {
7063
+ console.error(
7064
+ "Node.js 20 or higher is required. Install it from https://nodejs.org, then run setup again."
7065
+ );
7066
+ throw new ZapierCliExitError(
7067
+ "Setup could not continue without Node.js 20 or higher."
7068
+ );
7069
+ }
7070
+ const major = Number(version.replace(/^v/, "").split(".")[0]);
7071
+ if (!Number.isFinite(major) || major < 20) {
7072
+ console.error(
7073
+ `Node.js 20 or higher is required; found ${version}. Upgrade Node.js, then run setup again.`
7074
+ );
7075
+ throw new ZapierCliExitError(
7076
+ "Setup could not continue without Node.js 20 or higher."
7077
+ );
7078
+ }
7079
+ console.log(`Node.js ${version} is ready.`);
7080
+ }
7081
+ function detectProjectLanguage({
7082
+ cwd,
7083
+ hasExistingProject
7084
+ }) {
7085
+ if (!hasExistingProject || existsSync(join(cwd, "tsconfig.json"))) {
7086
+ return "typescript";
7087
+ }
7088
+ const manifest = readPackageJson({ directory: cwd });
7089
+ const hasTypeScript = [
7090
+ manifest?.dependencies,
7091
+ manifest?.devDependencies
7092
+ ].some(
7093
+ (dependencies) => isRecord(dependencies) && "typescript" in dependencies
7094
+ );
7095
+ return hasTypeScript ? "typescript" : "javascript";
7096
+ }
7097
+ async function prepareProject(context) {
7098
+ context.packageManager = detectPackageManager(context.cwd).name;
7099
+ console.log(`Using ${context.packageManager} for dependency installs.`);
7100
+ const hasExistingProject = existsSync(join(context.cwd, "package.json"));
7101
+ context.projectLanguage = detectProjectLanguage({
7102
+ cwd: context.cwd,
7103
+ hasExistingProject
7104
+ });
7105
+ if (hasExistingProject) {
7106
+ console.log("Found package.json; using this project as-is.");
7107
+ } else {
7108
+ await context.runCommand({
7109
+ ...PROJECT_INIT_COMMANDS[context.packageManager],
7110
+ cwd: context.cwd
7111
+ });
7112
+ }
7113
+ await prepareDependencies(context);
7114
+ }
7115
+
7116
+ // src/plugins/setup/context.ts
7117
+ function createWizardContext({
7118
+ imports
7119
+ }) {
7120
+ return {
7121
+ cwd: process.cwd(),
7122
+ imports,
7123
+ createAnswer: () => createCliAnswer({ mode: "closed-list" }),
7124
+ setupController: createSetupController(),
7125
+ checkForUpdates,
7126
+ openUrl: async (url) => {
7127
+ await open(url);
7128
+ },
7129
+ runCommand,
7130
+ packageManager: detectPackageManager(process.cwd()).name,
7131
+ projectLanguage: "typescript"
7132
+ };
7133
+ }
7134
+ var SetupSchema = z.object({}).describe("Set up the Zapier SDK in an existing or new project");
7135
+ function printAuthCommand({
7136
+ context,
7137
+ flow,
7138
+ headless
7139
+ }) {
7140
+ const command = createLocalPackageCommand({
7141
+ packageManager: context.packageManager,
7142
+ binary: "zapier-sdk",
7143
+ args: [flow, ...headless ? ["--headless"] : []]
7144
+ });
7145
+ console.log(`$ ${formatPackageCommand(command)}`);
7146
+ if (headless) {
7147
+ console.log(
7148
+ "Open the printed URL in another browser, then paste the final OAuth callback URL when prompted."
7149
+ );
7150
+ }
7151
+ }
7152
+ function isCredentialWriteError(error) {
7153
+ const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "";
7154
+ if (/^(eacces|eperm)$/i.test(code)) return true;
7155
+ const message = error instanceof Error ? error.message : String(error);
7156
+ return /permission|sandbox|eacces|eperm/i.test(message);
7157
+ }
7158
+ async function authenticate(context) {
7159
+ const activeProfile = await runWithSetupLoader({
7160
+ promise: context.imports.getProfile({}).then(({ data }) => data).catch((error) => {
7161
+ if (isZapierAuthenticationError(error)) return void 0;
7162
+ throw error;
7163
+ }),
7164
+ label: "Checking Zapier authentication"
7165
+ });
7166
+ if (activeProfile) {
7167
+ const shouldLogout = await resolveSetupConfirm({
7168
+ answer: context.createAnswer(),
7169
+ controller: context.setupController,
7170
+ message: `You are already logged in as "${activeProfile.email}".
7171
+ Logging out will delete these credentials and may interrupt other Zapier SDK or CLI sessions using them.
7172
+ Log out and use a different account?`,
7173
+ defaultValue: false
7174
+ });
7175
+ if (!shouldLogout) {
7176
+ context.accountEmail = activeProfile.email;
7177
+ console.log(`Continuing as ${activeProfile.email}.`);
7178
+ return;
7179
+ }
7180
+ const logoutCommand = createLocalPackageCommand({
7181
+ packageManager: context.packageManager,
7182
+ binary: "zapier-sdk",
7183
+ args: ["logout"]
7184
+ });
7185
+ console.log(`$ ${formatPackageCommand(logoutCommand)}`);
7186
+ await context.imports.logout({});
7187
+ }
7188
+ const flow = await resolveSetupSelect({
7189
+ answer: context.createAnswer(),
7190
+ controller: context.setupController,
7191
+ message: "Zapier account:",
7192
+ choices: [
7193
+ { label: "Log in to an existing account", value: "login" },
7194
+ { label: "Create a new Zapier account", value: "signup" }
7195
+ ]
7196
+ });
7197
+ const environment = await resolveSetupSelect({
7198
+ answer: context.createAnswer(),
7199
+ controller: context.setupController,
7200
+ message: "Environment:",
7201
+ choices: [
7202
+ { label: "Local machine with a browser", value: "local" },
7203
+ { label: "Remote or headless", value: "headless" }
7204
+ ]
7205
+ });
7206
+ const headless = environment === "headless";
7207
+ const runAuth = flow === "login" ? context.imports.login : context.imports.signup;
7208
+ printAuthCommand({ context, flow, headless });
7209
+ try {
7210
+ await runAuth({ headless });
7211
+ } catch (error) {
7212
+ if (isCredentialWriteError(error)) {
7213
+ console.error(
7214
+ "Authentication could not write credentials. A permissions or sandbox restriction may be blocking disk access."
7215
+ );
7216
+ }
7217
+ throw error;
7218
+ }
7219
+ const { data: profile } = await runWithSetupLoader({
7220
+ promise: context.imports.getProfile({}),
7221
+ label: "Confirming Zapier account"
7222
+ });
7223
+ context.accountEmail = profile.email;
7224
+ console.log(`Authenticated as ${profile.email}.`);
7225
+ }
7226
+ var agentLabels = {
7227
+ claude: "Claude Code",
7228
+ codex: "Codex",
7229
+ cursor: "Cursor",
7230
+ "vscode-copilot": "VS Code Copilot"
7231
+ };
7232
+ function buildAgentPrompt({ context }) {
7233
+ const listConnectionsCommand = formatPackageCommand(
7234
+ createLocalPackageCommand({
7235
+ packageManager: context.packageManager,
7236
+ binary: "zapier-sdk",
7237
+ args: ["list-connections", "--owner", "me", "--json"]
7238
+ })
7239
+ );
7240
+ const listActionsCommand = formatPackageCommand(
7241
+ createLocalPackageCommand({
7242
+ packageManager: context.packageManager,
7243
+ binary: "zapier-sdk",
7244
+ args: ["list-actions", "APP_KEY"]
7245
+ })
7246
+ );
7247
+ return `Start by running this command to discover my active connected apps outside of your sandbox:
7248
+
7249
+ ${listConnectionsCommand}
7250
+
7251
+ Using the connected apps returned by that command:
7252
+
7253
+ - Pick 1-3 apps and show commands I can use to explore their actions, such as: ${listActionsCommand}
7254
+ - Do not run those list-actions commands.
7255
+ - Suggest 3 specific ideas based on my connected apps. Each idea should read from one app, optionally process data, and write to another.
7256
+ - Do not suggest event-driven workflows.
7257
+ - Keep each idea to one sentence. Example: "pull in-progress Jira issues and DM yourself a summary on Slack".
7258
+
7259
+ Do not inspect files or modify the project. If fewer than two distinct apps are listed, explain that cross-app ideas require another active connection instead of inventing apps.`;
7260
+ }
7261
+ function printAgentPrompt({
7262
+ context,
7263
+ message
7264
+ }) {
7265
+ console.log();
7266
+ console.log(chalk8.bgYellow.black.bold(message));
7267
+ console.log();
7268
+ console.log(buildAgentPrompt({ context }));
7269
+ }
7270
+ async function openAgentHandoff(context) {
7271
+ const agent = await resolveSetupSelect({
7272
+ answer: context.createAnswer(),
7273
+ controller: context.setupController,
7274
+ message: "Want to open your agent and have it give you suggestions to start?",
7275
+ choices: [
7276
+ { label: "No", value: "none" },
7277
+ { label: "Claude Code", value: "claude" },
7278
+ { label: "Cursor", value: "cursor" },
7279
+ { label: "Codex", value: "codex" },
7280
+ { label: "VS Code Copilot", value: "vscode-copilot" },
7281
+ { label: "Other", value: "other" }
7282
+ ]
7283
+ });
7284
+ if (agent === "none") return;
7285
+ if (agent === "other") {
7286
+ printAgentPrompt({
7287
+ context,
7288
+ message: "Paste this prompt into your AI agent:"
7289
+ });
7290
+ return;
7291
+ }
7292
+ const prompt = buildAgentPrompt({ context });
7293
+ const encodedPrompt = encodeURIComponent(prompt);
7294
+ const encodedPath = encodeURIComponent(context.cwd);
7295
+ try {
7296
+ switch (agent) {
7297
+ case "claude":
7298
+ await context.openUrl(
7299
+ `claude://code/new?q=${encodedPrompt}&folder=${encodedPath}`
7300
+ );
7301
+ break;
7302
+ case "codex":
7303
+ await context.openUrl(
7304
+ `codex://threads/new?prompt=${encodedPrompt}&path=${encodedPath}`
7305
+ );
7306
+ break;
7307
+ case "cursor":
7308
+ await context.runCommand({
7309
+ command: "cursor",
7310
+ args: ["."],
7311
+ cwd: context.cwd,
7312
+ capture: true
7313
+ });
7314
+ console.log(`Cursor opened in ${context.cwd}.`);
7315
+ break;
7316
+ case "vscode-copilot":
7317
+ await context.runCommand({
7318
+ command: "code",
7319
+ args: ["chat", "--mode", "agent", "-"],
7320
+ cwd: context.cwd,
7321
+ input: prompt
7322
+ });
7323
+ break;
7324
+ default: {
7325
+ const unsupportedAgent = agent;
7326
+ throw new Error(`Unsupported agent: ${unsupportedAgent}`);
7327
+ }
7328
+ }
7329
+ } catch {
7330
+ console.warn(
7331
+ `Could not open ${agentLabels[agent]}. Open it manually to continue.`
7332
+ );
7333
+ }
7334
+ printAgentPrompt({
7335
+ context,
7336
+ message: "If it didn't load correctly, paste this prompt into your agent:"
7337
+ });
7338
+ }
7339
+ var CONNECTIONS_URL = "https://zapier.com/app/assets/connections";
7340
+ var CONNECTION_DISPLAY_LIMIT = 10;
7341
+ async function ensureConnectionsAvailable(context) {
7342
+ const page = await runWithSetupLoader({
7343
+ promise: context.imports.listConnections({
7344
+ owner: "me",
7345
+ maxItems: CONNECTION_DISPLAY_LIMIT
7346
+ }),
7347
+ label: "Loading app connections"
7348
+ });
7349
+ if (page.data.length === 0) {
7350
+ console.log(
7351
+ `No active connections found. Connect or reconnect an app at ${CONNECTIONS_URL}, then come back and run setup again.`
7352
+ );
7353
+ throw new ZapierCliExitError(
7354
+ "Setup stopped before completion because no active connections are available."
7355
+ );
7356
+ }
7357
+ const table = new Table({
7358
+ head: ["App", "Connection"],
7359
+ style: { compact: true }
7360
+ });
7361
+ table.push(
7362
+ ...page.data.map((connection) => [
7363
+ connection.slug || connection.app_key,
7364
+ connection.title
7365
+ ])
7366
+ );
7367
+ console.log(
7368
+ `Active Zapier connections (showing up to ${CONNECTION_DISPLAY_LIMIT}):`
7369
+ );
7370
+ console.log(table.toString());
7371
+ }
7372
+ var CONNECTION_PLACEHOLDER = "__ZAPIER_SDK_SLACK_CONNECTION__";
7373
+ var EMAIL_PLACEHOLDER = "__ZAPIER_SDK_ACCOUNT_EMAIL__";
7374
+ var APP_PLACEHOLDER = "__ZAPIER_SDK_SLACK_APP__";
7375
+ var SLACK_SLUG = "slack";
7376
+ function getSlackTestPath(context) {
7377
+ const extension = context.projectLanguage === "typescript" ? "ts" : "mjs";
7378
+ return join("src", "sdk-demo", `zapier-slack-test.${extension}`);
7379
+ }
7380
+ function getSlackTestTemplatePath(context) {
7381
+ const extension = context.projectLanguage === "typescript" ? "ts" : "mjs";
7382
+ return join(TEMPLATES_DIR, "setup", `zapier-slack-test.${extension}`);
7383
+ }
7384
+ async function findSlackConnection(context) {
7385
+ const page = await runWithSetupLoader({
7386
+ promise: context.imports.listConnections({
7387
+ owner: "me",
7388
+ app: SLACK_SLUG,
7389
+ maxItems: 1
7390
+ }),
7391
+ label: "Looking for a Slack connection"
7392
+ });
7393
+ return page.data.find(({ slug }) => slug === SLACK_SLUG);
7394
+ }
7395
+ function toTemplateString(value) {
7396
+ return JSON.stringify(value).slice(1, -1);
7397
+ }
7398
+ function renderSlackTest({
7399
+ context,
7400
+ app,
7401
+ connection,
7402
+ email
7403
+ }) {
7404
+ return readFileSync(getSlackTestTemplatePath(context), "utf8").replace(APP_PLACEHOLDER, () => toTemplateString(app)).replace(CONNECTION_PLACEHOLDER, () => toTemplateString(connection)).replace(EMAIL_PLACEHOLDER, () => toTemplateString(email));
7405
+ }
7406
+ function writeSlackTest({
7407
+ context,
7408
+ app,
7409
+ connection,
7410
+ email
7411
+ }) {
7412
+ const slackTestPath = getSlackTestPath(context);
7413
+ const path2 = join(context.cwd, slackTestPath);
7414
+ if (!existsSync(dirname(path2))) mkdirSync(dirname(path2), { recursive: true });
7415
+ writeFileSync(path2, renderSlackTest({ context, app, connection, email }));
7416
+ console.log(`Created ${slackTestPath}.`);
7417
+ }
7418
+ async function executeSlackTest(context) {
7419
+ const slackTestPath = getSlackTestPath(context);
7420
+ if (context.projectLanguage === "javascript") {
7421
+ await context.runCommand({
7422
+ command: "node",
7423
+ args: [slackTestPath],
7424
+ cwd: context.cwd,
7425
+ capture: false
7426
+ });
7427
+ return;
7428
+ }
7429
+ const command = context.packageManager === "bun" ? { command: "bun", args: [] } : createLocalPackageCommand({
7430
+ packageManager: context.packageManager,
7431
+ binary: "tsx"
7432
+ });
7433
+ const args = [...command.args, slackTestPath];
7434
+ await context.runCommand({
7435
+ command: command.command,
7436
+ args,
7437
+ cwd: context.cwd,
7438
+ capture: false
7439
+ });
7440
+ }
7441
+ async function trySlackTest(context) {
7442
+ try {
7443
+ await executeSlackTest(context);
7444
+ return true;
7445
+ } catch (error) {
7446
+ const message = error instanceof Error ? error.message : String(error);
7447
+ console.warn(`Slack demo failed: ${message}. Setup will continue.`);
7448
+ return false;
7449
+ }
7450
+ }
7451
+ async function offerSlackTest(context) {
7452
+ if (!context.accountEmail) {
7453
+ console.log("No account email found; skipping the Slack demo.");
7454
+ return;
7455
+ }
7456
+ const slackConnection = await findSlackConnection(context);
7457
+ if (!slackConnection) {
7458
+ console.log("No active Slack connection found; skipping the Slack demo.");
7459
+ return;
7460
+ }
7461
+ const slackTestPath = getSlackTestPath(context);
7462
+ const shouldRun = await resolveSetupConfirm({
7463
+ answer: context.createAnswer(),
7464
+ controller: context.setupController,
7465
+ message: `Run the Slack self-DM test using ${context.accountEmail}?`,
7466
+ defaultValue: true
7467
+ });
7468
+ if (!shouldRun) return;
7469
+ const path2 = join(context.cwd, slackTestPath);
7470
+ if (existsSync(path2)) {
7471
+ const shouldOverwrite = await resolveSetupConfirm({
7472
+ answer: context.createAnswer(),
7473
+ controller: context.setupController,
7474
+ message: `${slackTestPath} already exists. Is it okay to overwrite it?`,
7475
+ defaultValue: false
7476
+ });
7477
+ if (!shouldOverwrite) {
7478
+ console.log("Keeping the existing Slack test file.");
7479
+ const shouldRunExisting = await resolveSetupConfirm({
7480
+ answer: context.createAnswer(),
7481
+ controller: context.setupController,
7482
+ message: `Run the existing ${slackTestPath}?`,
7483
+ defaultValue: false
7484
+ });
7485
+ if (shouldRunExisting) await trySlackTest(context);
7486
+ return;
7487
+ }
7488
+ }
7489
+ let email = context.accountEmail;
7490
+ writeSlackTest({
7491
+ context,
7492
+ app: SLACK_SLUG,
7493
+ connection: slackConnection.id,
7494
+ email
7495
+ });
7496
+ if (await trySlackTest(context)) return;
7497
+ email = await resolveSetupInput({
7498
+ answer: context.createAnswer(),
7499
+ controller: context.setupController,
7500
+ message: "Slack email for one retry after the failed test:"
7501
+ });
7502
+ if (!email) {
7503
+ console.log("Skipping the Slack test.");
7504
+ return;
7505
+ }
7506
+ writeSlackTest({
7507
+ context,
7508
+ app: SLACK_SLUG,
7509
+ connection: slackConnection.id,
7510
+ email
7511
+ });
7512
+ await trySlackTest(context);
7513
+ }
7514
+
7515
+ // src/plugins/setup/skill.ts
7516
+ async function installOptionalSkill(context) {
7517
+ const shouldInstall = await resolveSetupConfirm({
7518
+ answer: context.createAnswer(),
7519
+ controller: context.setupController,
7520
+ message: "Install the optional Zapier SDK skill for extra agent context? This is not required for SDK setup.",
7521
+ defaultValue: true
7522
+ });
7523
+ if (!shouldInstall) {
7524
+ console.log("Skipping the optional Zapier SDK skill.");
7525
+ return;
7526
+ }
7527
+ const command = createPackageRunnerCommand({
7528
+ packageManager: context.packageManager,
7529
+ packageName: "skills",
7530
+ args: ["add", "zapier/sdk", "-y"]
7531
+ });
7532
+ try {
7533
+ await context.runCommand({
7534
+ ...command,
7535
+ cwd: context.cwd,
7536
+ capture: true
7537
+ });
7538
+ } catch {
7539
+ console.warn(
7540
+ `Could not install the optional Zapier SDK skill. To install it manually, run: ${formatPackageCommand(command)}`
7541
+ );
7542
+ }
7543
+ }
7544
+
7545
+ // src/plugins/setup/wizard.ts
7546
+ var PHASE_COUNT = 6;
7547
+ var MINIMUM_MESSAGE_WIDTH = 20;
7548
+ var MAXIMUM_MESSAGE_WIDTH = 88;
7549
+ function showPhase({ number, title }) {
7550
+ console.log();
7551
+ console.log(chalk8.bgCyan.black.bold(` ${number}/${PHASE_COUNT} ${title} `));
7552
+ }
7553
+ function printWrapped(text) {
7554
+ const width = Math.max(
7555
+ MINIMUM_MESSAGE_WIDTH,
7556
+ Math.min(
7557
+ process.stdout.columns ?? MAXIMUM_MESSAGE_WIDTH,
7558
+ MAXIMUM_MESSAGE_WIDTH
7559
+ )
7560
+ );
7561
+ console.log(wrapAnsi4(text, width));
7562
+ }
7563
+ function showReadyMessage() {
7564
+ console.log();
7565
+ console.log(chalk8.bgGreen.black.bold(" \u2713 Zapier SDK setup complete "));
7566
+ console.log();
7567
+ printWrapped(
7568
+ "Use active Zapier connections to access 9,000+ app connectors without managing each app's OAuth, token refresh, or retries."
7569
+ );
7570
+ console.log();
7571
+ printWrapped(
7572
+ "To learn more about the Zapier SDK, visit https://docs.zapier.com/sdk"
7573
+ );
7574
+ console.log();
7575
+ }
7576
+ async function runWizard(context) {
7577
+ console.log(chalk8.bold("Zapier SDK setup"));
7578
+ showPhase({ number: 1, title: "Project directory" });
7579
+ await chooseDirectory(context);
7580
+ showPhase({ number: 2, title: "Node.js" });
7581
+ await ensureSupportedNode(context);
7582
+ showPhase({ number: 3, title: "Dependencies" });
7583
+ await prepareProject(context);
7584
+ await installOptionalSkill(context);
7585
+ showPhase({ number: 4, title: "Zapier account" });
7586
+ await authenticate(context);
7587
+ showPhase({ number: 5, title: "App connections" });
7588
+ await ensureConnectionsAvailable(context);
7589
+ showPhase({ number: 6, title: "Slack demo" });
7590
+ await offerSlackTest(context);
7591
+ showReadyMessage();
7592
+ console.log(chalk8.bgCyan.black.bold(" Next steps "));
7593
+ await openAgentHandoff(context);
7594
+ }
7595
+
7596
+ // src/plugins/setup/index.ts
7597
+ var getProfileRef = declareMethod({ id: "getProfile" });
7598
+ var listConnectionsRef2 = declareMethod({ id: "listConnections" });
7599
+ var loginRef = declareMethod({ id: "login" });
7600
+ var logoutRef = declareMethod({ id: "logout" });
7601
+ var signupRef = declareMethod({ id: "signup" });
7602
+ var setupImports = [
7603
+ getProfileRef,
7604
+ listConnectionsRef2,
7605
+ loginRef,
7606
+ logoutRef,
7607
+ signupRef
7608
+ ];
7609
+ var setupPlugin = defineMethod({
7610
+ name: "setup",
7611
+ imports: setupImports,
7612
+ categories: ["utility"],
7613
+ supportsJsonOutput: false,
7614
+ inputSchema: SetupSchema,
7615
+ output: "raw",
7616
+ run: async ({ imports }) => {
7617
+ if (process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
7618
+ throw new ZapierCliExitError(
7619
+ "`zapier-sdk setup` requires an interactive terminal."
7620
+ );
7621
+ }
7622
+ await runWizard(createWizardContext({ imports }));
7623
+ }
7624
+ });
7625
+ var CliSkipLeaseExpireError = class extends Error {
7626
+ constructor() {
7627
+ super("user skipped (let lease expire)");
7628
+ this.name = "CliSkipLeaseExpireError";
7629
+ }
7630
+ };
7631
+ function createInteractiveCallback() {
7632
+ let messageNumber = 0;
7633
+ return async (message) => {
7634
+ messageNumber++;
7635
+ const attrs = message.message_attributes;
7636
+ console.log(
7637
+ `
7638
+ ${chalk8.bold(`Message #${messageNumber}`)} ${chalk8.dim(message.id)} ${chalk8.dim(`(lease #${attrs.lease_count})`)}`
7639
+ );
7640
+ if (attrs.error_message) {
7641
+ console.log(chalk8.yellow(` upstream error: ${attrs.error_message}`));
7642
+ }
7643
+ if (attrs.possible_duplicate_data) {
7644
+ console.log(chalk8.yellow(" possible duplicate data"));
7645
+ }
7646
+ while (true) {
7647
+ let action;
7648
+ try {
7649
+ const answer = await inquirer.prompt([
7650
+ {
7651
+ type: "list",
7652
+ name: "action",
7653
+ message: "Action?",
7654
+ choices: [
7655
+ { name: "Ack (remove from inbox)", value: "ack" },
7656
+ {
7657
+ name: "Skip (release after draining)",
7658
+ value: "skip-release"
7659
+ },
7660
+ { name: "Skip (let lease expire)", value: "skip-expire" },
7661
+ { name: "View payload", value: "view" },
7662
+ { name: "Quit", value: "quit" }
7663
+ ]
7664
+ }
7665
+ ]);
7666
+ action = answer.action;
7667
+ } catch (error) {
7668
+ if (error instanceof Error && error.name === "ExitPromptError") {
7669
+ throw new ZapierAbortDrainSignal("user pressed Ctrl-C");
7670
+ }
7671
+ throw error;
7672
+ }
7673
+ if (action === "view") {
7674
+ console.log(chalk8.dim(JSON.stringify(message.payload, null, 2)));
7675
+ continue;
7676
+ }
7677
+ if (action === "ack") {
7678
+ return;
7679
+ }
7680
+ if (action === "skip-release") {
7681
+ throw new ZapierReleaseTriggerMessageSignal("user skipped (release)");
7682
+ }
7683
+ if (action === "skip-expire") {
7684
+ throw new CliSkipLeaseExpireError();
7685
+ }
7686
+ if (action === "quit") {
7687
+ throw new ZapierAbortDrainSignal("user requested quit");
7688
+ }
7689
+ }
7690
+ };
7691
+ }
7692
+ function createNdjsonCallback() {
7693
+ return (message) => new Promise((resolve4, reject) => {
7694
+ process.stdout.write(JSON.stringify(message) + "\n", (err) => {
7695
+ if (err) reject(err);
7696
+ else resolve4();
7697
+ });
7698
+ });
7699
+ }
7700
+ function runSubprocess(options) {
7701
+ const { command, args, shell, label, message, signal } = options;
7702
+ return new Promise((resolve4, reject) => {
7703
+ const child = spawn(command, args, {
7704
+ shell,
7705
+ stdio: ["pipe", "inherit", "inherit"]
7706
+ });
7707
+ let abortListener;
7708
+ if (signal) {
7709
+ if (signal.aborted) {
7710
+ child.kill();
7711
+ } else {
7712
+ abortListener = () => {
7713
+ child.kill();
6293
7714
  };
6294
7715
  signal.addEventListener("abort", abortListener, { once: true });
6295
7716
  }
@@ -6705,7 +8126,7 @@ function renderDeprecationNotices() {
6705
8126
  function buildBoxLines(message) {
6706
8127
  const innerWidth = BOX_WIDTH - 4;
6707
8128
  const pad = (line) => `\u2502 ${line.padEnd(innerWidth)} \u2502`;
6708
- const wrapped = wrapAnsi3(message, innerWidth, { hard: true }).split("\n");
8129
+ const wrapped = wrapAnsi4(message, innerWidth, { hard: true }).split("\n");
6709
8130
  return [
6710
8131
  `\u256D${"\u2500".repeat(BOX_WIDTH - 2)}\u256E`,
6711
8132
  pad(BOX_TITLE),
@@ -6718,7 +8139,7 @@ function buildBoxLines(message) {
6718
8139
  // package.json with { type: 'json' }
6719
8140
  var package_default2 = {
6720
8141
  name: "@zapier/zapier-sdk-cli",
6721
- version: "0.68.0"};
8142
+ version: "0.69.0"};
6722
8143
 
6723
8144
  // src/sdk.ts
6724
8145
  var warnedDeprecatedMethods = /* @__PURE__ */ new Set();
@@ -6758,6 +8179,7 @@ var cliSdkPlugin = definePlugin({
6758
8179
  mcpPlugin,
6759
8180
  getLoginConfigPathPlugin,
6760
8181
  initPlugin,
8182
+ setupPlugin,
6761
8183
  bundleCodePlugin,
6762
8184
  feedbackPlugin,
6763
8185
  curlPlugin,
@@ -6826,6 +8248,7 @@ function createZapierCliSdk2(options = {}) {
6826
8248
  mcpPlugin,
6827
8249
  getLoginConfigPathPlugin,
6828
8250
  initPlugin,
8251
+ setupPlugin,
6829
8252
  bundleCodePlugin,
6830
8253
  feedbackPlugin,
6831
8254
  curlPlugin,
@@ -6910,163 +8333,6 @@ function readEnvSpecs() {
6910
8333
  if (!raw) return [];
6911
8334
  return raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
6912
8335
  }
6913
- var ONE_DAY_MILLISECONDS = 24 * 60 * 60 * 1e3;
6914
- var CACHE_RESET_INTERVAL_MILLISECONDS = (() => {
6915
- const {
6916
- ZAPIER_SDK_UPDATE_CHECK_INTERVAL_SECONDS,
6917
- ZAPIER_SDK_UPDATE_CHECK_INTERVAL_MS
6918
- } = process.env;
6919
- let intervalMs;
6920
- if (ZAPIER_SDK_UPDATE_CHECK_INTERVAL_SECONDS !== void 0) {
6921
- const seconds = parseInt(ZAPIER_SDK_UPDATE_CHECK_INTERVAL_SECONDS);
6922
- intervalMs = isNaN(seconds) ? NaN : seconds * 1e3;
6923
- } else if (ZAPIER_SDK_UPDATE_CHECK_INTERVAL_MS !== void 0) {
6924
- intervalMs = parseInt(ZAPIER_SDK_UPDATE_CHECK_INTERVAL_MS);
6925
- } else {
6926
- intervalMs = ONE_DAY_MILLISECONDS;
6927
- }
6928
- if (isNaN(intervalMs) || intervalMs < 0) {
6929
- return -1;
6930
- }
6931
- return intervalMs;
6932
- })();
6933
- function getVersionCache() {
6934
- try {
6935
- const cache = getConfig().get("version_cache");
6936
- const now = Date.now();
6937
- if (!cache || !cache.last_reset_timestamp || now - cache.last_reset_timestamp >= CACHE_RESET_INTERVAL_MILLISECONDS) {
6938
- const newCache = {
6939
- last_reset_timestamp: now,
6940
- packages: {}
6941
- };
6942
- getConfig().set("version_cache", newCache);
6943
- return newCache;
6944
- }
6945
- return cache;
6946
- } catch (error) {
6947
- log_default.debug(`Failed to read version cache: ${error}`);
6948
- return {
6949
- last_reset_timestamp: Date.now(),
6950
- packages: {}
6951
- };
6952
- }
6953
- }
6954
- function setCachedPackageInfo(packageName, version, info) {
6955
- try {
6956
- const cache = getVersionCache();
6957
- if (!cache.packages[packageName]) {
6958
- cache.packages[packageName] = {};
6959
- }
6960
- cache.packages[packageName][version] = info;
6961
- getConfig().set("version_cache", cache);
6962
- } catch (error) {
6963
- log_default.debug(`Failed to cache package info: ${error}`);
6964
- }
6965
- }
6966
- function getCachedPackageInfo(packageName, version) {
6967
- try {
6968
- const cache = getVersionCache();
6969
- return cache.packages[packageName]?.[version];
6970
- } catch (error) {
6971
- log_default.debug(`Failed to get cached package info: ${error}`);
6972
- return void 0;
6973
- }
6974
- }
6975
- async function fetchCachedPackageInfo(packageName, version) {
6976
- const cacheKey = version || "latest";
6977
- let cachedInfo = getCachedPackageInfo(packageName, cacheKey);
6978
- if (cachedInfo) {
6979
- return cachedInfo;
6980
- }
6981
- const packageInfo = await packageJsonLib(packageName, {
6982
- version,
6983
- fullMetadata: true
6984
- });
6985
- const info = {
6986
- version: packageInfo.version,
6987
- deprecated: packageInfo.deprecated,
6988
- fetched_at: (/* @__PURE__ */ new Date()).toISOString()
6989
- };
6990
- setCachedPackageInfo(packageName, cacheKey, info);
6991
- return info;
6992
- }
6993
- async function checkForUpdates({
6994
- packageName,
6995
- currentVersion
6996
- }) {
6997
- try {
6998
- const latestPackageInfo = await fetchCachedPackageInfo(packageName);
6999
- const latestVersion = latestPackageInfo.version;
7000
- const hasUpdate = semver.gt(latestVersion, currentVersion);
7001
- let currentPackageInfo;
7002
- try {
7003
- currentPackageInfo = await fetchCachedPackageInfo(
7004
- packageName,
7005
- currentVersion
7006
- );
7007
- } catch (error) {
7008
- if (!(error instanceof VersionNotFoundError)) {
7009
- log_default.debug(`Failed to check deprecation for current version: ${error}`);
7010
- }
7011
- currentPackageInfo = latestPackageInfo;
7012
- }
7013
- const isDeprecated = Boolean(currentPackageInfo.deprecated);
7014
- const deprecationMessage = isDeprecated ? String(currentPackageInfo.deprecated) : void 0;
7015
- return {
7016
- hasUpdate,
7017
- latestVersion,
7018
- currentVersion,
7019
- isDeprecated,
7020
- deprecationMessage
7021
- };
7022
- } catch (error) {
7023
- log_default.debug(`Failed to check for updates: ${error}`);
7024
- return {
7025
- hasUpdate: false,
7026
- currentVersion,
7027
- isDeprecated: false
7028
- };
7029
- }
7030
- }
7031
- function displayUpdateNotification(versionInfo, packageName) {
7032
- if (versionInfo.isDeprecated) {
7033
- console.error();
7034
- console.error(
7035
- chalk8.red.bold("\u26A0\uFE0F DEPRECATION WARNING") + chalk8.red(
7036
- ` - ${packageName} v${versionInfo.currentVersion} is deprecated.`
7037
- )
7038
- );
7039
- if (versionInfo.deprecationMessage) {
7040
- console.error(chalk8.red(` ${versionInfo.deprecationMessage}`));
7041
- }
7042
- console.error(chalk8.red(` Please update to the latest version.`));
7043
- console.error();
7044
- }
7045
- if (versionInfo.hasUpdate) {
7046
- console.error();
7047
- console.error(
7048
- chalk8.yellow.bold("\u{1F4E6} Update available!") + chalk8.yellow(
7049
- ` ${packageName} v${versionInfo.currentVersion} \u2192 v${versionInfo.latestVersion}`
7050
- )
7051
- );
7052
- console.error(
7053
- chalk8.yellow(
7054
- ` Run ${chalk8.bold(getUpdateCommand(packageName))} to update.`
7055
- )
7056
- );
7057
- console.error();
7058
- }
7059
- }
7060
- async function checkAndNotifyUpdates({
7061
- packageName,
7062
- currentVersion
7063
- }) {
7064
- if (CACHE_RESET_INTERVAL_MILLISECONDS < 0) {
7065
- return;
7066
- }
7067
- const versionInfo = await checkForUpdates({ packageName, currentVersion });
7068
- displayUpdateNotification(versionInfo, packageName);
7069
- }
7070
8336
  var EMOJI_PRESENTATION_PATTERN = /\p{Emoji_Presentation}/u;
7071
8337
  var WIDE_CODE_POINT_RANGES = [
7072
8338
  [4352, 4447],
@@ -7170,7 +8436,7 @@ function buildFrameLines(state, frameIndex) {
7170
8436
  const hasMessages = recentMessages.length > 0;
7171
8437
  recentMessages.forEach((message, index) => {
7172
8438
  const dimmed = Boolean(state.verdict) || index < recentMessages.length - 1;
7173
- const segments = wrapAnsi3(message, bodyTextWidth, { hard: true }).split(
8439
+ const segments = wrapAnsi4(message, bodyTextWidth, { hard: true }).split(
7174
8440
  "\n"
7175
8441
  );
7176
8442
  segments.forEach((segment, segmentIndex) => {
@@ -7181,7 +8447,7 @@ function buildFrameLines(state, frameIndex) {
7181
8447
  if (state.streamError) {
7182
8448
  if (hasMessages || !state.verdict) content.push("");
7183
8449
  content.push(chalk8.bold.red("Approval stream error"));
7184
- for (const segment of wrapAnsi3(state.streamError, bodyTextWidth, {
8450
+ for (const segment of wrapAnsi4(state.streamError, bodyTextWidth, {
7185
8451
  hard: true
7186
8452
  }).split("\n")) {
7187
8453
  content.push(` ${segment}`);
@@ -7193,7 +8459,7 @@ function buildFrameLines(state, frameIndex) {
7193
8459
  chalk8.bold.green(`${state.verdict.icon} ${state.verdict.label}`)
7194
8460
  );
7195
8461
  if (state.verdict.reason) {
7196
- for (const segment of wrapAnsi3(state.verdict.reason, bodyTextWidth, {
8462
+ for (const segment of wrapAnsi4(state.verdict.reason, bodyTextWidth, {
7197
8463
  hard: true
7198
8464
  }).split("\n")) {
7199
8465
  content.push(` ${segment}`);