@zapier/zapier-sdk-cli 0.86.7 → 0.87.2

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,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command, CommanderError, Option, InvalidArgumentError } from 'commander';
3
- import { STABILITY_LEVELS, getConnectionPlugin, definePlugin, apiPlugin, defineMethod, apiPluginRef, resolveCredentialsPluginRef, eventEmissionPluginRef, sdkOptionsPluginRef, declareOptionalProperty, OutputPropertySchema, ZapierBundleError, isZapierBundleError, DEFAULT_CONFIG_PATH, declareMethod, ZapierValidationError, isZapierValidationError, ZapierUnknownError, manifestPluginRef, defineResolver, isPermanentHttpError, isZapierAuthenticationError, ZapierApiError, defineOverride, fetchPlugin, zapierCoreOptions, injectCliLogin, omitExports, zapierSdkPlugin, BaseSdkOptionsSchema, disposeSdk, invalidateCachedToken, batch, toSnakeCase, ZapierError, isZapierReleaseTriggerMessageSignal, createSdk as createSdk$2, CORE_OPTIONS_ID as CORE_OPTIONS_ID$2, SDK_OPTIONS_ID as SDK_OPTIONS_ID$2, addPlugin as addPlugin$2, formatExtensionPluginFailure as formatExtensionPluginFailure$2, resolvePlugin, isCredentialsObject, getRegistryPlugin, createController, ZapierAbortDrainSignal, ZapierReleaseTriggerMessageSignal, STABILITY_DEFINITIONS, getRegistry, getCoreErrorCode, CoreErrorCode, applyStabilityLabel, buildApplicationLifecycleEvent, AuthMechanism, DEPRECATION_NOTICE_EVENT, runWithCallerContext, isCoreCancelledSignal, getNegatable, isPositional, descriptionFor, isZapierError, formatErrorMessage, getOsInfo, getPlatformVersions, getAgent as getAgent$1, getTtyContext, getCiPlatform, isCi, isZapierConflictError, getReleaseId, getCurrentTimestamp, generateEventId, isZapierApprovalError, ZapierAuthenticationError } from '@zapier/zapier-sdk';
3
+ import { STABILITY_LEVELS, getConnectionPlugin, definePlugin, apiPlugin, defineMethod, apiPluginRef, resolveCredentialsPluginRef, eventEmissionPluginRef, sdkOptionsPluginRef, declareOptionalProperty, OutputPropertySchema, ZapierBundleError, isZapierBundleError, DEFAULT_CONFIG_PATH, declareMethod, ZapierValidationError, isZapierValidationError, ZapierUnknownError, manifestPluginRef, defineResolver, isPermanentHttpError, isZapierAuthenticationError, ZapierApiError, defineOverride, fetchPlugin, zapierCoreOptions, injectCliLogin, omitExports, zapierSdkPlugin, BaseSdkOptionsSchema, disposeSdk, invalidateCachedToken, batch, toSnakeCase, ZapierError, isZapierReleaseTriggerMessageSignal, createSdk as createSdk$2, CORE_OPTIONS_ID as CORE_OPTIONS_ID$2, SDK_OPTIONS_ID as SDK_OPTIONS_ID$2, addPlugin as addPlugin$2, formatExtensionPluginFailure as formatExtensionPluginFailure$2, resolvePlugin, isCredentialsObject, isZapierSignal, getRegistryPlugin, createController, ZapierAbortDrainSignal, ZapierReleaseTriggerMessageSignal, STABILITY_DEFINITIONS, getRegistry, getCoreErrorCode, CoreErrorCode, applyStabilityLabel, buildApplicationLifecycleEvent, AuthMechanism, ZapierSignal, DEPRECATION_NOTICE_EVENT, runWithCallerContext, getNegatable, isInternalField, isPositional, descriptionFor, isCoreCancelledSignal, 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 chalk10 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
9
  import * as fs from 'fs';
10
- import { promises, createWriteStream, existsSync, readdirSync, readFileSync, rmSync, mkdirSync, writeFileSync, copyFileSync } from 'fs';
10
+ import { promises, createWriteStream, existsSync, readdirSync, realpathSync, readFileSync, rmSync, mkdirSync, writeFileSync, copyFileSync } from 'fs';
11
11
  import * as path from 'path';
12
12
  import { resolve, join, dirname, basename, relative, extname } from 'path';
13
13
  import isInstalledGlobally from 'is-installed-globally';
@@ -33,8 +33,9 @@ import { fileURLToPath } from 'url';
33
33
  import packageJsonLib, { VersionNotFoundError } from 'package-json';
34
34
  import semver from 'semver';
35
35
  import crossSpawn from 'cross-spawn';
36
+ import { createRequire } from 'module';
36
37
  import Table from 'cli-table3';
37
- import { triggerInboxResolver, DrainTriggerInboxSchema, WatchTriggerInboxSchema, declareMethod as declareMethod$1, defineMethod as defineMethod$1, CreateWorkflowResponseSchema, getAgent, ImportWorkflowResponseSchema, injectCliLogin as injectCliLogin$2, INTERNAL_CREATE_WORKFLOW_FIELDS, CreateWorkflowOptionsSchema, definePlugin as definePlugin$1, omitExports as omitExports$1, zapierExperimentalSdkPlugin, createSdk, CORE_OPTIONS_ID, SDK_OPTIONS_ID, addPlugin, formatExtensionPluginFailure, ImportWorkflowOptionsSchema } from '@zapier/zapier-sdk/experimental';
38
+ import { triggerInboxResolver, DrainTriggerInboxSchema, WatchTriggerInboxSchema, injectCliLogin as injectCliLogin$2, definePlugin as definePlugin$1, omitExports as omitExports$1, zapierExperimentalSdkPlugin, createSdk, CORE_OPTIONS_ID, SDK_OPTIONS_ID, addPlugin, formatExtensionPluginFailure } from '@zapier/zapier-sdk/experimental';
38
39
  import { injectCliLogin as injectCliLogin$1, definePlugin as definePlugin$2, omitExports as omitExports$2, zapierBetaSdkPlugin, createSdk as createSdk$1, CORE_OPTIONS_ID as CORE_OPTIONS_ID$1, SDK_OPTIONS_ID as SDK_OPTIONS_ID$1, addPlugin as addPlugin$1, formatExtensionPluginFailure as formatExtensionPluginFailure$1 } from '@zapier/zapier-sdk/beta';
39
40
  import * as readline from 'readline';
40
41
 
@@ -562,7 +563,7 @@ var SHARED_COMMAND_CLI_OPTIONS = [
562
563
 
563
564
  // package.json
564
565
  var package_default = {
565
- version: "0.86.7"};
566
+ version: "0.87.2"};
566
567
  var PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
567
568
  var LOCKFILES = [
568
569
  ["pnpm-lock.yaml", "pnpm"],
@@ -688,7 +689,7 @@ function buildCliCommandExecutedEvent({
688
689
  is_ci_environment: isCi(),
689
690
  ci_platform: getCiPlatform(),
690
691
  ...getTtyContext(),
691
- agent: getAgent$1(),
692
+ agent: getAgent(),
692
693
  package_manager: data.package_manager ?? detectPackageManager(process.cwd()).name,
693
694
  made_network_requests: data.made_network_requests ?? null,
694
695
  files_modified_count: data.files_modified_count ?? null,
@@ -1080,6 +1081,7 @@ var SENSITIVE_FLAGS = [
1080
1081
  "--credentials-client-id",
1081
1082
  "--credentials-base-url",
1082
1083
  "--callback-url",
1084
+ "--answer",
1083
1085
  "--user",
1084
1086
  "--header",
1085
1087
  "-H",
@@ -1295,11 +1297,11 @@ function analyzeZodField(name, schema) {
1295
1297
  let deprecationMessage;
1296
1298
  let nullable = false;
1297
1299
  while (true) {
1298
- const meta = baseSchema.meta?.();
1300
+ const meta = z.globalRegistry.get(baseSchema);
1299
1301
  if (meta?.deprecated) {
1300
1302
  isDeprecated = true;
1301
1303
  }
1302
- if (meta?.deprecationMessage && !deprecationMessage) {
1304
+ if (typeof meta?.deprecationMessage === "string" && !deprecationMessage) {
1303
1305
  deprecationMessage = meta.deprecationMessage;
1304
1306
  }
1305
1307
  if (baseSchema instanceof z.ZodOptional) {
@@ -1360,6 +1362,7 @@ function analyzeZodField(name, schema) {
1360
1362
  elementType,
1361
1363
  deprecationMessage,
1362
1364
  isDeprecated,
1365
+ isInternal: isInternalField(schema),
1363
1366
  negatable: getNegatable(schema),
1364
1367
  nullable
1365
1368
  };
@@ -1818,6 +1821,7 @@ function addCommand(program2, commandName, config2) {
1818
1821
  param.description || `${kebabName} parameter`
1819
1822
  );
1820
1823
  } else {
1824
+ const hideFromHelp = param.isDeprecated || param.isInternal;
1821
1825
  const flags = [];
1822
1826
  const alias = config2.aliases?.[param.name];
1823
1827
  if (alias && alias.length === 1) {
@@ -1826,7 +1830,7 @@ function addCommand(program2, commandName, config2) {
1826
1830
  flags.push(`--${kebabName}`);
1827
1831
  if (param.type === "boolean") {
1828
1832
  const opt = new Option(flags.join(", "), param.description);
1829
- if (param.isDeprecated) opt.hideHelp();
1833
+ if (hideFromHelp) opt.hideHelp();
1830
1834
  command.addOption(opt);
1831
1835
  const negationKebab = negationKebabName(param);
1832
1836
  if (negationKebab !== void 0) {
@@ -1837,7 +1841,7 @@ function addCommand(program2, commandName, config2) {
1837
1841
  if (!negationKebab.startsWith("no-")) {
1838
1842
  negation.conflicts(param.name);
1839
1843
  }
1840
- if (param.isDeprecated) negation.hideHelp();
1844
+ if (hideFromHelp) negation.hideHelp();
1841
1845
  command.addOption(negation);
1842
1846
  }
1843
1847
  booleanFlags2.push({
@@ -1853,7 +1857,7 @@ function addCommand(program2, commandName, config2) {
1853
1857
  opt.argParser(
1854
1858
  (value, previous) => (previous || []).concat([value])
1855
1859
  );
1856
- if (param.isDeprecated) opt.hideHelp();
1860
+ if (hideFromHelp) opt.hideHelp();
1857
1861
  command.addOption(opt);
1858
1862
  } else {
1859
1863
  const flagSignature = flags.join(", ") + ` <${param.type}>`;
@@ -1861,7 +1865,7 @@ function addCommand(program2, commandName, config2) {
1861
1865
  if (param.default !== void 0) {
1862
1866
  opt.default(param.default);
1863
1867
  }
1864
- if (param.isDeprecated) opt.hideHelp();
1868
+ if (hideFromHelp) opt.hideHelp();
1865
1869
  command.addOption(opt);
1866
1870
  }
1867
1871
  }
@@ -3065,6 +3069,7 @@ async function setupClientCredentials({
3065
3069
  }
3066
3070
  return { clientId };
3067
3071
  }
3072
+ var CREDENTIALS_PICKER_QUESTION = "Select credentials or add a new account:";
3068
3073
  function isSameCredentials(left, right) {
3069
3074
  return left.name === right.name && left.baseUrl === right.baseUrl;
3070
3075
  }
@@ -3170,7 +3175,7 @@ async function promptForCredentials({
3170
3175
  activeCredentials
3171
3176
  }) {
3172
3177
  return searchSelect({
3173
- message: "Select credentials or add a new account:",
3178
+ message: CREDENTIALS_PICKER_QUESTION,
3174
3179
  source: (term) => buildCredentialsChoices({
3175
3180
  credentials: credentials2,
3176
3181
  activeCredentials,
@@ -3233,14 +3238,15 @@ async function switchCredentials({
3233
3238
  async function chooseStoredLoginCredentialsAtBaseUrl({
3234
3239
  baseUrl: baseUrl2,
3235
3240
  options,
3236
- resolvedCredentials
3241
+ resolvedCredentials,
3242
+ prompt = promptForCredentials
3237
3243
  }) {
3238
3244
  if (resolvedCredentials !== void 0 || authFlowOnlyOptions(options).length > 0) {
3239
3245
  return "none";
3240
3246
  }
3241
3247
  const storedCredentials = listStoredCredentials({ baseUrl: baseUrl2 });
3242
3248
  if (storedCredentials.length === 0) return "none";
3243
- const selection = await promptForCredentials({
3249
+ const selection = await prompt({
3244
3250
  credentials: storedCredentials,
3245
3251
  activeCredentials: getActiveCredentials({ baseUrl: baseUrl2 })
3246
3252
  });
@@ -3254,7 +3260,8 @@ async function chooseStoredLoginCredentialsAtBaseUrl({
3254
3260
  }
3255
3261
  async function chooseStoredLoginCredentials({
3256
3262
  imports,
3257
- options
3263
+ options,
3264
+ prompt
3258
3265
  }) {
3259
3266
  const resolvedCredentials = await imports.resolveCredentials();
3260
3267
  const credentialsBaseUrl2 = await resolveCredentialsBaseUrl({
@@ -3264,7 +3271,8 @@ async function chooseStoredLoginCredentials({
3264
3271
  return chooseStoredLoginCredentialsAtBaseUrl({
3265
3272
  baseUrl: credentialsBaseUrl2,
3266
3273
  options,
3267
- resolvedCredentials
3274
+ resolvedCredentials,
3275
+ prompt
3268
3276
  });
3269
3277
  }
3270
3278
  async function confirmNewCredentialsName(name) {
@@ -3635,6 +3643,7 @@ var PendingOauthTransactionSchema = z.object({
3635
3643
  credentialName: z.string().optional(),
3636
3644
  useApprovals: z.boolean(),
3637
3645
  headless: z.boolean().default(false),
3646
+ preserveExistingCredentials: z.boolean().default(false),
3638
3647
  transaction: OauthTransactionSchema
3639
3648
  });
3640
3649
  function savePendingOauthTransaction({
@@ -3644,7 +3653,8 @@ function savePendingOauthTransaction({
3644
3653
  credentialsBaseUrl: credentialsBaseUrl2,
3645
3654
  credentialName,
3646
3655
  useApprovals,
3647
- headless
3656
+ headless,
3657
+ preserveExistingCredentials = false
3648
3658
  }) {
3649
3659
  const pendingTransaction = {
3650
3660
  version: 1,
@@ -3652,6 +3662,7 @@ function savePendingOauthTransaction({
3652
3662
  expiresAt,
3653
3663
  useApprovals,
3654
3664
  headless,
3665
+ preserveExistingCredentials,
3655
3666
  transaction,
3656
3667
  ...credentialsBaseUrl2 !== void 0 && { credentialsBaseUrl: credentialsBaseUrl2 },
3657
3668
  ...credentialName !== void 0 && { credentialName }
@@ -3670,6 +3681,7 @@ function clearPendingOauthTransaction() {
3670
3681
  }
3671
3682
 
3672
3683
  // src/utils/auth/oauth-flow.ts
3684
+ var OAUTH_CALLBACK_QUESTION = "Paste the final OAuth callback URL:";
3673
3685
  var PENDING_OAUTH_RECOVERY_MESSAGE = "Start a new non-interactive login or signup flow to generate a fresh URL.";
3674
3686
  var LOGIN_OAUTH_COPY = {
3675
3687
  flowName: "Login",
@@ -3733,7 +3745,9 @@ async function startPendingOauthFlow({
3733
3745
  entryPoint,
3734
3746
  credentialName,
3735
3747
  useApprovals,
3736
- headless
3748
+ headless,
3749
+ preserveExistingCredentials = false,
3750
+ silent = false
3737
3751
  }) {
3738
3752
  const copy = entryPoint === "signup" ? SIGNUP_OAUTH_COPY : LOGIN_OAUTH_COPY;
3739
3753
  const port = LOGIN_PORTS[0];
@@ -3750,8 +3764,10 @@ async function startPendingOauthFlow({
3750
3764
  credentialsBaseUrl: baseUrl2,
3751
3765
  credentialName,
3752
3766
  useApprovals,
3753
- headless
3767
+ headless,
3768
+ preserveExistingCredentials
3754
3769
  });
3770
+ if (silent) return pending;
3755
3771
  process.stderr.write(
3756
3772
  `Open this ${copy.urlLabel} in a browser to continue:
3757
3773
  `
@@ -3777,23 +3793,24 @@ async function startPendingOauthFlow({
3777
3793
  return pending;
3778
3794
  }
3779
3795
  function getPendingOauthFlow({
3780
- entryPoint
3796
+ entryPoint,
3797
+ recoveryMessage = PENDING_OAUTH_RECOVERY_MESSAGE
3781
3798
  }) {
3782
3799
  const pending = getPendingOauthTransaction();
3783
3800
  if (!pending) {
3784
3801
  throw new ZapierCliValidationError(
3785
- `No pending ${entryPoint} OAuth flow found. ${PENDING_OAUTH_RECOVERY_MESSAGE}`
3802
+ `No pending ${entryPoint} OAuth flow found. ${recoveryMessage}`
3786
3803
  );
3787
3804
  }
3788
3805
  if (Date.now() > pending.expiresAt) {
3789
3806
  clearPendingOauthTransaction();
3790
3807
  throw new ZapierCliValidationError(
3791
- `Pending ${pending.entryPoint} OAuth flow has expired. ${PENDING_OAUTH_RECOVERY_MESSAGE}`
3808
+ `Pending ${pending.entryPoint} OAuth flow has expired. ${recoveryMessage}`
3792
3809
  );
3793
3810
  }
3794
3811
  if (pending.entryPoint !== entryPoint) {
3795
3812
  throw new ZapierCliValidationError(
3796
- `Pending OAuth flow is for ${pending.entryPoint}, not ${entryPoint}. ${PENDING_OAUTH_RECOVERY_MESSAGE}`
3813
+ `Pending OAuth flow is for ${pending.entryPoint}, not ${entryPoint}. ${recoveryMessage}`
3797
3814
  );
3798
3815
  }
3799
3816
  return pending;
@@ -3956,7 +3973,7 @@ async function readHeadlessCallbackUrl({
3956
3973
  process.once("SIGINT", handleCancellation);
3957
3974
  process.once("SIGTERM", handleCancellation);
3958
3975
  if (interactive) {
3959
- void rl.question("Paste the final OAuth callback URL: ", {
3976
+ void rl.question(`${OAUTH_CALLBACK_QUESTION} `, {
3960
3977
  signal: abortController.signal
3961
3978
  }).then(settleResolve).catch((error) => {
3962
3979
  if (error instanceof Error && error.name === "AbortError") {
@@ -4443,7 +4460,7 @@ async function runOauthForEntryPoint({
4443
4460
  if (event.type === "callback_accepted") {
4444
4461
  emitSignupSuccess({
4445
4462
  imports,
4446
- isNonInteractive: false,
4463
+ isNonInteractive: !interactive,
4447
4464
  isHeadless: headless === true
4448
4465
  });
4449
4466
  }
@@ -4525,7 +4542,9 @@ async function runAccountAuth({
4525
4542
  options,
4526
4543
  entryPoint,
4527
4544
  storedCredentialsMode = "choose",
4528
- preserveExistingCredentials = false
4545
+ preserveExistingCredentials = false,
4546
+ useBrowserCallback = false,
4547
+ silent = false
4529
4548
  }) {
4530
4549
  if (options.callbackUrl !== void 0) {
4531
4550
  const { callbackUrl } = options;
@@ -4558,7 +4577,8 @@ async function runAccountAuth({
4558
4577
  imports,
4559
4578
  baseUrl: pending.credentialsBaseUrl,
4560
4579
  interactive: false,
4561
- entryPoint
4580
+ entryPoint,
4581
+ preserveExistingCredentials: pending.preserveExistingCredentials
4562
4582
  })) {
4563
4583
  return;
4564
4584
  }
@@ -4635,7 +4655,7 @@ async function runAccountAuth({
4635
4655
  );
4636
4656
  }
4637
4657
  }
4638
- if (entryPoint === "login" && !interactive && providedName === void 0) {
4658
+ if (entryPoint === "login" && !interactive && providedName === void 0 && !preserveExistingCredentials) {
4639
4659
  const activeCredentials = getActiveCredentials({
4640
4660
  baseUrl: credentialsBaseUrl2
4641
4661
  });
@@ -4652,7 +4672,7 @@ async function runAccountAuth({
4652
4672
  }
4653
4673
  const timeoutSeconds = parseTimeoutSeconds(options.timeout);
4654
4674
  const useApprovals = options.useApprovals === true;
4655
- if (!interactive) {
4675
+ if (!interactive && (headless || !useBrowserCallback)) {
4656
4676
  await startPendingOauthFlow({
4657
4677
  entryPoint,
4658
4678
  timeoutMs: timeoutSeconds * 1e3,
@@ -4660,7 +4680,9 @@ async function runAccountAuth({
4660
4680
  baseUrl: credentialsBaseUrl2,
4661
4681
  credentialName: providedName,
4662
4682
  useApprovals,
4663
- headless
4683
+ headless,
4684
+ preserveExistingCredentials,
4685
+ silent
4664
4686
  });
4665
4687
  return;
4666
4688
  }
@@ -4681,7 +4703,7 @@ async function runAccountAuth({
4681
4703
  credentialName: providedName,
4682
4704
  interactive,
4683
4705
  useApprovals,
4684
- isNonInteractive: false,
4706
+ isNonInteractive: !interactive,
4685
4707
  isHeadless: headless
4686
4708
  });
4687
4709
  }
@@ -6521,6 +6543,7 @@ function createProjectDir({
6521
6543
  var TEMPLATES_DIR = fileURLToPath(
6522
6544
  new URL("../templates", import.meta.url)
6523
6545
  );
6546
+ var SOURCE_CLI_PATH = import.meta.url.endsWith(".ts") ? fileURLToPath(new URL("./cli.ts", import.meta.url)) : void 0;
6524
6547
 
6525
6548
  // src/plugins/init/steps.ts
6526
6549
  var DEFAULT_TEMPLATE = "basic";
@@ -6981,84 +7004,6 @@ async function checkAndNotifyUpdates({
6981
7004
  const versionInfo = await checkForUpdates({ packageName, currentVersion });
6982
7005
  displayUpdateNotification(versionInfo, packageName);
6983
7006
  }
6984
- var BRAILLE_BLANK = "\u2800";
6985
- var LIGHTNING_INTERVAL_MILLISECONDS = 140;
6986
- var boltRows = [
6987
- "\u2800\u2800\u2880\u28FE\u2800\u2800\u2800\u2800",
6988
- "\u2800\u2800\u28E0\u28FF\u28FF\u2800\u2800\u2800",
6989
- "\u2800\u28FC\u28FF\u28FF\u28FF\u28C0\u28C0\u2840",
6990
- "\u2808\u2809\u2809\u28FF\u28FF\u28FF\u285F\u2800",
6991
- "\u2800\u2800\u2800\u28FF\u28FF\u280B\u2800\u2800",
6992
- "\u2800\u2800\u2800\u287F\u2801\u2800\u2800\u2800"
6993
- ];
6994
- var boltFillOrder = boltRows.flatMap(
6995
- (row, rowIndex) => [...row].flatMap(
6996
- (cell, columnIndex) => cell === BRAILLE_BLANK ? [] : rowIndex * row.length + columnIndex
6997
- )
6998
- );
6999
- var fillStages = [
7000
- ...Array.from({ length: boltFillOrder.length + 1 }, (_, index) => index),
7001
- boltFillOrder.length,
7002
- 0
7003
- ];
7004
- var boltFillRanks = new Map(
7005
- boltFillOrder.map((cellIndex, fillIndex) => [cellIndex, fillIndex])
7006
- );
7007
- var STATUS_ROW_INDEX = Math.floor(boltRows.length / 2);
7008
- function formatPhase({ label, detail }) {
7009
- return detail ? `${chalk10.bold(label)} ${chalk10.dim(detail)}` : chalk10.bold(label);
7010
- }
7011
- function formatLoaderFrame({
7012
- phase,
7013
- fillStage
7014
- }) {
7015
- return boltRows.map((row, rowIndex) => {
7016
- const bolt = [...row].map((cell, columnIndex) => {
7017
- if (cell === BRAILLE_BLANK) return cell;
7018
- const cellIndex = rowIndex * row.length + columnIndex;
7019
- const fillRank = boltFillRanks.get(cellIndex);
7020
- const isFilled = fillRank !== void 0 && fillRank < fillStage;
7021
- return isFilled ? chalk10.bold.yellow(cell) : chalk10.dim.yellow(cell);
7022
- }).join("");
7023
- const status = rowIndex === STATUS_ROW_INDEX ? ` ${formatPhase(phase)}` : "";
7024
- return `${bolt}${status}`;
7025
- }).join("\n");
7026
- }
7027
- async function runWithSetupLoader({
7028
- promise,
7029
- ...phase
7030
- }) {
7031
- const startedAt = Date.now();
7032
- let fillFrameIndex = 0;
7033
- const loader = ora({
7034
- isEnabled: process.stderr.isTTY === true,
7035
- spinner: { interval: 80, frames: [""] },
7036
- text: formatLoaderFrame({
7037
- phase,
7038
- fillStage: fillStages[fillFrameIndex]
7039
- })
7040
- }).start();
7041
- const animationTimer = setInterval(() => {
7042
- fillFrameIndex = (fillFrameIndex + 1) % fillStages.length;
7043
- loader.text = formatLoaderFrame({
7044
- phase,
7045
- fillStage: fillStages[fillFrameIndex]
7046
- });
7047
- }, LIGHTNING_INTERVAL_MILLISECONDS);
7048
- animationTimer.unref?.();
7049
- try {
7050
- const result = await promise;
7051
- clearInterval(animationTimer);
7052
- const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
7053
- loader.succeed(`${formatPhase(phase)} ${chalk10.dim(`${elapsedSeconds}s`)}`);
7054
- return result;
7055
- } catch (error) {
7056
- clearInterval(animationTimer);
7057
- const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
7058
- loader.fail(`${formatPhase(phase)} ${chalk10.dim(`${elapsedSeconds}s`)}`);
7059
- throw error;
7060
- }
7061
- }
7062
7007
  function isRecord(value) {
7063
7008
  return typeof value === "object" && value !== null && !Array.isArray(value);
7064
7009
  }
@@ -7344,7 +7289,7 @@ async function offerPackageUpdate({
7344
7289
  }) {
7345
7290
  const { currentVersion, dependency } = packageState;
7346
7291
  if (!currentVersion || !dependency.checkForUpdates) return;
7347
- const update = await runWithSetupLoader({
7292
+ const update = await context.load({
7348
7293
  promise: context.checkForUpdates({
7349
7294
  packageName: dependency.name,
7350
7295
  currentVersion
@@ -7369,28 +7314,108 @@ async function offerPackageUpdate({
7369
7314
  })
7370
7315
  );
7371
7316
  }
7372
- async function prepareDependencies(context) {
7317
+ function getPackageStates(context) {
7373
7318
  const declaredPackageNames = getDeclaredPackageNames(context.cwd);
7374
7319
  const requiredPackages = REQUIRED_PACKAGES.filter(
7375
7320
  ({ typescriptOnly }) => !typescriptOnly || context.projectLanguage === "typescript"
7376
7321
  );
7377
- const packages = requiredPackages.map((dependency) => ({
7322
+ return requiredPackages.map((dependency) => ({
7378
7323
  dependency,
7324
+ declared: declaredPackageNames.has(dependency.name),
7379
7325
  currentVersion: declaredPackageNames.has(dependency.name) ? getInstalledPackageVersion({
7380
7326
  cwd: context.cwd,
7381
7327
  packageName: dependency.name
7382
7328
  }) : void 0
7383
7329
  }));
7330
+ }
7331
+ async function prepareDependencies(context) {
7332
+ const packages = getPackageStates(context);
7384
7333
  await offerMissingPackageInstall({
7385
7334
  context,
7386
- packages: packages.filter(
7387
- ({ dependency }) => !declaredPackageNames.has(dependency.name)
7388
- )
7335
+ packages: packages.filter(({ declared }) => !declared)
7389
7336
  });
7390
7337
  for (const packageState of packages) {
7391
7338
  await offerPackageUpdate({ context, packageState });
7392
7339
  }
7393
7340
  }
7341
+ var BRAILLE_BLANK = "\u2800";
7342
+ var LIGHTNING_INTERVAL_MILLISECONDS = 140;
7343
+ var boltRows = [
7344
+ "\u2800\u2800\u2880\u28FE\u2800\u2800\u2800\u2800",
7345
+ "\u2800\u2800\u28E0\u28FF\u28FF\u2800\u2800\u2800",
7346
+ "\u2800\u28FC\u28FF\u28FF\u28FF\u28C0\u28C0\u2840",
7347
+ "\u2808\u2809\u2809\u28FF\u28FF\u28FF\u285F\u2800",
7348
+ "\u2800\u2800\u2800\u28FF\u28FF\u280B\u2800\u2800",
7349
+ "\u2800\u2800\u2800\u287F\u2801\u2800\u2800\u2800"
7350
+ ];
7351
+ var boltFillOrder = boltRows.flatMap(
7352
+ (row, rowIndex) => [...row].flatMap(
7353
+ (cell, columnIndex) => cell === BRAILLE_BLANK ? [] : rowIndex * row.length + columnIndex
7354
+ )
7355
+ );
7356
+ var fillStages = [
7357
+ ...Array.from({ length: boltFillOrder.length + 1 }, (_, index) => index),
7358
+ boltFillOrder.length,
7359
+ 0
7360
+ ];
7361
+ var boltFillRanks = new Map(
7362
+ boltFillOrder.map((cellIndex, fillIndex) => [cellIndex, fillIndex])
7363
+ );
7364
+ var STATUS_ROW_INDEX = Math.floor(boltRows.length / 2);
7365
+ function formatPhase({ label, detail }) {
7366
+ return detail ? `${chalk10.bold(label)} ${chalk10.dim(detail)}` : chalk10.bold(label);
7367
+ }
7368
+ function formatLoaderFrame({
7369
+ phase,
7370
+ fillStage
7371
+ }) {
7372
+ return boltRows.map((row, rowIndex) => {
7373
+ const bolt = [...row].map((cell, columnIndex) => {
7374
+ if (cell === BRAILLE_BLANK) return cell;
7375
+ const cellIndex = rowIndex * row.length + columnIndex;
7376
+ const fillRank = boltFillRanks.get(cellIndex);
7377
+ const isFilled = fillRank !== void 0 && fillRank < fillStage;
7378
+ return isFilled ? chalk10.bold.yellow(cell) : chalk10.dim.yellow(cell);
7379
+ }).join("");
7380
+ const status = rowIndex === STATUS_ROW_INDEX ? ` ${formatPhase(phase)}` : "";
7381
+ return `${bolt}${status}`;
7382
+ }).join("\n");
7383
+ }
7384
+ async function runWithSetupLoader({
7385
+ promise,
7386
+ ...phase
7387
+ }) {
7388
+ const startedAt = Date.now();
7389
+ let fillFrameIndex = 0;
7390
+ const loader = ora({
7391
+ isEnabled: process.stderr.isTTY === true,
7392
+ spinner: { interval: 80, frames: [""] },
7393
+ text: formatLoaderFrame({
7394
+ phase,
7395
+ fillStage: fillStages[fillFrameIndex]
7396
+ })
7397
+ }).start();
7398
+ const animationTimer = setInterval(() => {
7399
+ fillFrameIndex = (fillFrameIndex + 1) % fillStages.length;
7400
+ loader.text = formatLoaderFrame({
7401
+ phase,
7402
+ fillStage: fillStages[fillFrameIndex]
7403
+ });
7404
+ }, LIGHTNING_INTERVAL_MILLISECONDS);
7405
+ animationTimer.unref?.();
7406
+ try {
7407
+ const result = await promise;
7408
+ clearInterval(animationTimer);
7409
+ const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
7410
+ loader.succeed(`${formatPhase(phase)} ${chalk10.dim(`${elapsedSeconds}s`)}`);
7411
+ return result;
7412
+ } catch (error) {
7413
+ clearInterval(animationTimer);
7414
+ const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
7415
+ loader.fail(`${formatPhase(phase)} ${chalk10.dim(`${elapsedSeconds}s`)}`);
7416
+ throw error;
7417
+ }
7418
+ }
7394
7419
 
7395
7420
  // src/plugins/setup/package-commands.ts
7396
7421
  function createLocalPackageCommand({
@@ -7429,7 +7454,10 @@ function formatPackageCommand({
7429
7454
  command,
7430
7455
  args
7431
7456
  }) {
7432
- return [command, ...args].join(" ");
7457
+ return [command, ...args].map(quoteShellArgument).join(" ");
7458
+ }
7459
+ function quoteShellArgument(value) {
7460
+ return /^[a-zA-Z0-9_@%+=:,./-]+$/.test(value) ? value : `'${value.replace(/'/g, `'"'"'`)}'`;
7433
7461
  }
7434
7462
 
7435
7463
  // src/plugins/setup/project.ts
@@ -7534,13 +7562,14 @@ async function runCommand({
7534
7562
  args = [],
7535
7563
  cwd,
7536
7564
  capture = true,
7537
- input
7565
+ input,
7566
+ load = runWithSetupLoader
7538
7567
  }) {
7539
7568
  const commandLabel = `$ ${command} ${args.join(" ")}`.trim();
7540
7569
  const execute = capture ? executeCapturedCommand({ command, args, cwd, input }) : executeStreamingCommand({ command, args, cwd, input });
7541
7570
  try {
7542
7571
  if (capture) {
7543
- return await runWithSetupLoader({
7572
+ return await load({
7544
7573
  promise: execute,
7545
7574
  label: "Running command",
7546
7575
  detail: commandLabel
@@ -7624,7 +7653,7 @@ function detectProjectLanguage({
7624
7653
  );
7625
7654
  return hasTypeScript ? "typescript" : "javascript";
7626
7655
  }
7627
- async function prepareProject(context) {
7656
+ async function initializeProject(context) {
7628
7657
  context.packageManager = detectPackageManager(context.cwd).name;
7629
7658
  console.log(`Using ${context.packageManager} for dependency installs.`);
7630
7659
  const hasExistingProject = existsSync(join(context.cwd, "package.json"));
@@ -7640,182 +7669,157 @@ async function prepareProject(context) {
7640
7669
  cwd: context.cwd
7641
7670
  });
7642
7671
  }
7672
+ }
7673
+ async function prepareProject(context) {
7674
+ await initializeProject(context);
7643
7675
  await prepareDependencies(context);
7644
7676
  }
7645
7677
 
7646
7678
  // src/plugins/setup/context.ts
7647
7679
  function createWizardContext({
7648
- imports
7680
+ imports,
7681
+ agent = false
7649
7682
  }) {
7650
- return {
7683
+ const context = {
7651
7684
  cwd: process.cwd(),
7685
+ load: agent ? ({ promise }) => promise : runWithSetupLoader,
7652
7686
  imports,
7653
7687
  createAnswer: () => createCliAnswer({ mode: "closed-list" }),
7654
7688
  setupController: createSetupController(),
7655
- selectStoredLoginCredentials: () => chooseStoredLoginCredentials({ imports, options: {} }),
7656
- authenticateNewAccount: ({ entryPoint, headless }) => runAccountAuth({
7689
+ selectStoredLoginCredentials: () => chooseStoredLoginCredentials({
7690
+ imports,
7691
+ options: {},
7692
+ ...agent ? {
7693
+ prompt: async (options) => {
7694
+ const credentialChoices = buildCredentialsChoices(options);
7695
+ const choices = credentialChoices.map(({ name, value }) => ({
7696
+ label: name,
7697
+ value: value.action === "create" ? "create" : `account:${value.credentials.name}`,
7698
+ result: value
7699
+ }));
7700
+ const selected = await resolveSetupSelect({
7701
+ answer: context.createAnswer(),
7702
+ controller: context.setupController,
7703
+ message: CREDENTIALS_PICKER_QUESTION,
7704
+ choices
7705
+ });
7706
+ const selectedIndex = choices.findIndex(
7707
+ ({ value }) => value === selected
7708
+ );
7709
+ return choices[selectedIndex].result;
7710
+ }
7711
+ } : {}
7712
+ }),
7713
+ authenticateNewAccount: ({ entryPoint, ...options }) => runAccountAuth({
7657
7714
  imports,
7658
- options: { headless },
7715
+ options,
7659
7716
  entryPoint,
7660
7717
  storedCredentialsMode: "fresh",
7661
- preserveExistingCredentials: true
7718
+ preserveExistingCredentials: true,
7719
+ useBrowserCallback: agent && options.headless === false,
7720
+ silent: agent && options.headless
7662
7721
  }),
7663
7722
  checkForUpdates,
7664
7723
  openUrl: async (url) => {
7665
7724
  await open(url);
7666
7725
  },
7667
- runCommand,
7726
+ runCommand: agent ? (options) => runCommand({
7727
+ ...options,
7728
+ capture: true,
7729
+ load: ({ promise, detail }) => {
7730
+ console.log(detail);
7731
+ return promise;
7732
+ }
7733
+ }) : runCommand,
7668
7734
  packageManager: detectPackageManager(process.cwd()).name,
7669
7735
  projectLanguage: "typescript"
7670
7736
  };
7737
+ return context;
7738
+ }
7739
+ var SetupStepSchema = z.enum([
7740
+ "directory",
7741
+ "project",
7742
+ "install",
7743
+ "sdk-update",
7744
+ "cli-update",
7745
+ "skill",
7746
+ "account",
7747
+ "account-flow",
7748
+ "account-environment",
7749
+ "authorize",
7750
+ "confirm-account",
7751
+ "connections",
7752
+ "slack",
7753
+ "slack-overwrite",
7754
+ "slack-existing",
7755
+ "slack-retry",
7756
+ "handoff"
7757
+ ]);
7758
+ var SetupSchema = z.object({
7759
+ agent: z.boolean().optional().describe(
7760
+ "For AI agents and callers without a terminal: print the next setup question and the exact command to run for each answer."
7761
+ ),
7762
+ step: SetupStepSchema.optional().describe(
7763
+ "Setup operation to inspect or execute."
7764
+ ),
7765
+ nonInteractive: z.boolean().optional().describe("Execute the named setup step without terminal prompts."),
7766
+ answer: z.string().optional().describe(
7767
+ "User selection or input for a non-interactive setup step. Omitted confirmations use the terminal wizard's default."
7768
+ ),
7769
+ flow: z.enum(["login", "signup"]).optional().describe(
7770
+ "Account flow selected for the environment and OAuth callback steps."
7771
+ ),
7772
+ language: z.enum(["javascript", "typescript"]).optional().describe(
7773
+ "Project language for dependency installation and the Slack demo."
7774
+ )
7775
+ }).describe(
7776
+ "Set up the Zapier SDK in an existing or new project. Runs an interactive terminal wizard; AI agents should use --agent instead."
7777
+ );
7778
+ var agentLabels = {
7779
+ claude: "Claude Code",
7780
+ codex: "Codex",
7781
+ cursor: "Cursor",
7782
+ "vscode-copilot": "VS Code Copilot"
7783
+ };
7784
+ function buildAgentPrompt({
7785
+ context
7786
+ }) {
7787
+ const listConnectionsCommand = formatPackageCommand(
7788
+ createLocalPackageCommand({
7789
+ packageManager: context.packageManager,
7790
+ binary: "zapier-sdk",
7791
+ args: ["list-connections", "--owner", "me", "--json"]
7792
+ })
7793
+ );
7794
+ const listActionsCommand = formatPackageCommand(
7795
+ createLocalPackageCommand({
7796
+ packageManager: context.packageManager,
7797
+ binary: "zapier-sdk",
7798
+ args: ["list-actions", "APP_KEY"]
7799
+ })
7800
+ );
7801
+ return `Start by running this command to discover my active connected apps outside of your sandbox:
7802
+
7803
+ ${listConnectionsCommand}
7804
+
7805
+ Using the connected apps returned by that command:
7806
+
7807
+ - Pick 1-3 apps and show commands I can use to explore their actions, such as: ${listActionsCommand}
7808
+ - Do not run those list-actions commands.
7809
+ - Suggest 3 specific ideas based on my connected apps. Each idea should read from one app, optionally process data, and write to another.
7810
+ - Do not suggest event-driven workflows.
7811
+ - Keep each idea to one sentence. Example: "pull in-progress Jira issues and DM yourself a summary on Slack".
7812
+
7813
+ 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.`;
7671
7814
  }
7672
- var SetupSchema = z.object({}).describe("Set up the Zapier SDK in an existing or new project");
7673
- function printAuthCommand({
7815
+ function printAgentPrompt({
7674
7816
  context,
7675
- flow,
7676
- headless
7817
+ message
7677
7818
  }) {
7678
- const command = createLocalPackageCommand({
7679
- packageManager: context.packageManager,
7680
- binary: "zapier-sdk",
7681
- args: [flow, ...headless ? ["--headless"] : []]
7682
- });
7683
- console.log(`$ ${formatPackageCommand(command)}`);
7684
- if (headless) {
7685
- console.log(
7686
- "Open the printed URL in another browser, then paste the final OAuth callback URL when prompted."
7687
- );
7688
- }
7689
- }
7690
- function isCredentialWriteError(error) {
7691
- const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "";
7692
- if (/^(eacces|eperm)$/i.test(code)) return true;
7693
- const message = error instanceof Error ? error.message : String(error);
7694
- return /permission|sandbox|eacces|eperm/i.test(message);
7695
- }
7696
- async function confirmAuthentication(context) {
7697
- const { data: profile } = await runWithSetupLoader({
7698
- promise: context.imports.getProfile({}),
7699
- label: "Confirming Zapier account"
7700
- });
7701
- context.accountEmail = profile.email;
7702
- console.log(`Authenticated as ${profile.email}.`);
7703
- }
7704
- async function authenticate(context) {
7705
- const activeProfile = await runWithSetupLoader({
7706
- promise: context.imports.getProfile({}).then(({ data }) => data).catch((error) => {
7707
- if (isZapierAuthenticationError(error)) return void 0;
7708
- throw error;
7709
- }),
7710
- label: "Checking Zapier authentication"
7711
- });
7712
- const storedCredentialsSelection = await context.selectStoredLoginCredentials();
7713
- if (storedCredentialsSelection === "switch") {
7714
- await confirmAuthentication(context);
7715
- return;
7716
- }
7717
- if (storedCredentialsSelection === "none" && activeProfile) {
7718
- const shouldLogout = await resolveSetupConfirm({
7719
- answer: context.createAnswer(),
7720
- controller: context.setupController,
7721
- message: `You are already logged in as "${activeProfile.email}".
7722
- Logging out will delete these credentials and may interrupt other Zapier SDK or CLI sessions using them.
7723
- Log out and use a different account?`,
7724
- defaultValue: false
7725
- });
7726
- if (!shouldLogout) {
7727
- context.accountEmail = activeProfile.email;
7728
- console.log(`Continuing as ${activeProfile.email}.`);
7729
- return;
7730
- }
7731
- const logoutCommand = createLocalPackageCommand({
7732
- packageManager: context.packageManager,
7733
- binary: "zapier-sdk",
7734
- args: ["logout"]
7735
- });
7736
- console.log(`$ ${formatPackageCommand(logoutCommand)}`);
7737
- await context.imports.logout({});
7738
- }
7739
- const flow = await resolveSetupSelect({
7740
- answer: context.createAnswer(),
7741
- controller: context.setupController,
7742
- message: "Zapier account:",
7743
- choices: [
7744
- { label: "Log in to an existing account", value: "login" },
7745
- { label: "Create a new Zapier account", value: "signup" }
7746
- ]
7747
- });
7748
- const environment = await resolveSetupSelect({
7749
- answer: context.createAnswer(),
7750
- controller: context.setupController,
7751
- message: "Environment:",
7752
- choices: [
7753
- { label: "Local machine with a browser", value: "local" },
7754
- { label: "Remote or headless", value: "headless" }
7755
- ]
7756
- });
7757
- const headless = environment === "headless";
7758
- printAuthCommand({ context, flow, headless });
7759
- try {
7760
- if (storedCredentialsSelection === "create") {
7761
- await context.authenticateNewAccount({ entryPoint: flow, headless });
7762
- } else {
7763
- const runAuth = flow === "login" ? context.imports.login : context.imports.signup;
7764
- await runAuth({ headless });
7765
- }
7766
- } catch (error) {
7767
- if (isCredentialWriteError(error)) {
7768
- console.error(
7769
- "Authentication could not write credentials. A permissions or sandbox restriction may be blocking disk access."
7770
- );
7771
- }
7772
- throw error;
7773
- }
7774
- await confirmAuthentication(context);
7775
- }
7776
- var agentLabels = {
7777
- claude: "Claude Code",
7778
- codex: "Codex",
7779
- cursor: "Cursor",
7780
- "vscode-copilot": "VS Code Copilot"
7781
- };
7782
- function buildAgentPrompt({ context }) {
7783
- const listConnectionsCommand = formatPackageCommand(
7784
- createLocalPackageCommand({
7785
- packageManager: context.packageManager,
7786
- binary: "zapier-sdk",
7787
- args: ["list-connections", "--owner", "me", "--json"]
7788
- })
7789
- );
7790
- const listActionsCommand = formatPackageCommand(
7791
- createLocalPackageCommand({
7792
- packageManager: context.packageManager,
7793
- binary: "zapier-sdk",
7794
- args: ["list-actions", "APP_KEY"]
7795
- })
7796
- );
7797
- return `Start by running this command to discover my active connected apps outside of your sandbox:
7798
-
7799
- ${listConnectionsCommand}
7800
-
7801
- Using the connected apps returned by that command:
7802
-
7803
- - Pick 1-3 apps and show commands I can use to explore their actions, such as: ${listActionsCommand}
7804
- - Do not run those list-actions commands.
7805
- - Suggest 3 specific ideas based on my connected apps. Each idea should read from one app, optionally process data, and write to another.
7806
- - Do not suggest event-driven workflows.
7807
- - Keep each idea to one sentence. Example: "pull in-progress Jira issues and DM yourself a summary on Slack".
7808
-
7809
- 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.`;
7810
- }
7811
- function printAgentPrompt({
7812
- context,
7813
- message
7814
- }) {
7815
- console.log();
7816
- console.log(chalk10.bgYellow.black.bold(message));
7817
- console.log();
7818
- console.log(buildAgentPrompt({ context }));
7819
+ console.log();
7820
+ console.log(chalk10.bgYellow.black.bold(message));
7821
+ console.log();
7822
+ console.log(buildAgentPrompt({ context }));
7819
7823
  }
7820
7824
  async function openAgentHandoff(context) {
7821
7825
  const agent = await resolveSetupSelect({
@@ -7886,27 +7890,291 @@ async function openAgentHandoff(context) {
7886
7890
  message: "If it didn't load correctly, paste this prompt into your agent:"
7887
7891
  });
7888
7892
  }
7893
+
7894
+ // src/plugins/setup/agent-output.ts
7895
+ var REQUIRED_STEPS = [
7896
+ "directory",
7897
+ "install"
7898
+ ];
7899
+ function formatSetupCommand({
7900
+ context,
7901
+ target,
7902
+ answer
7903
+ }) {
7904
+ const args = [
7905
+ "setup",
7906
+ "--step",
7907
+ target.step,
7908
+ "--non-interactive",
7909
+ ...target.flow ? ["--flow", target.flow] : [],
7910
+ "--language",
7911
+ context.projectLanguage,
7912
+ ...answer !== void 0 ? ["--answer", answer] : []
7913
+ ];
7914
+ return formatPackageCommand(
7915
+ SOURCE_CLI_PATH ? {
7916
+ command: process.execPath,
7917
+ args: [
7918
+ "--import",
7919
+ createRequire(import.meta.url).resolve("tsx"),
7920
+ "--conditions",
7921
+ "source",
7922
+ SOURCE_CLI_PATH,
7923
+ ...args
7924
+ ]
7925
+ } : createPackageRunnerCommand({
7926
+ packageManager: context.packageManager,
7927
+ packageName: `@zapier/zapier-sdk-cli@${package_default.version}`,
7928
+ args
7929
+ })
7930
+ );
7931
+ }
7932
+ function printAgentStep({
7933
+ context,
7934
+ target,
7935
+ question
7936
+ }) {
7937
+ console.log(
7938
+ `Step: ${target.step}
7939
+ Working directory: ${context.cwd}
7940
+ Detected package manager: ${context.packageManager}
7941
+ Project language: ${context.projectLanguage}`
7942
+ );
7943
+ if (!question) {
7944
+ console.log(
7945
+ `Run this exact command:
7946
+ ${formatSetupCommand({ context, target })}`
7947
+ );
7948
+ } else {
7949
+ if (target.step === "authorize" && context.authorizationUrl)
7950
+ console.log(
7951
+ `Give the user this URL to open in a browser where they can sign in to Zapier:
7952
+ ${context.authorizationUrl}
7953
+ After they approve, the browser opens a localhost page that may fail to load. That is expected: ask them to copy the full address from the browser's address bar. Pass that address only to the command below; do not save it or repeat it elsewhere.`
7954
+ );
7955
+ console.log(`Ask the user this question verbatim: "${question.message}"`);
7956
+ if (question.type === "select") {
7957
+ for (const { value, label } of question.choices)
7958
+ console.log(`${JSON.stringify(value)}: ${label}`);
7959
+ for (const { value } of question.choices) {
7960
+ const decision = value === "true" ? "agrees" : value === "false" ? "declines" : `chooses ${JSON.stringify(value)}`;
7961
+ if (value === "false" && REQUIRED_STEPS.includes(target.step))
7962
+ console.log("If the user declines, stop setup.");
7963
+ else
7964
+ console.log(
7965
+ `If the user ${decision}, run this exact command:
7966
+ ${formatSetupCommand({ context, target, answer: value })}`
7967
+ );
7968
+ }
7969
+ } else {
7970
+ console.log(
7971
+ `Run this exact command with their answer as one shell-quoted argument (an empty answer is ''):
7972
+ ${formatSetupCommand({ context, target, answer: "<answer>" })}`
7973
+ );
7974
+ }
7975
+ if (target.step === "account-environment")
7976
+ console.log(
7977
+ `The local command opens a browser and waits up to ${LOGIN_TIMEOUT_MILLISECONDS / 1e3} seconds for authorization, using the terminal login flow. Keep the process running until it completes and allow extra time for credential creation. If the browser does not open, use its printed fallback URL or choose headless instead.`
7978
+ );
7979
+ console.log(
7980
+ "Use your tool for asking the user questions if you have one. Do not answer on the user's behalf."
7981
+ );
7982
+ }
7983
+ console.log(
7984
+ "On success, follow the next step's guidance printed by that operation. On failure, stop and report the error; do not proceed or retry automatically. Ignore CLI update notices; setup offers package updates as their own steps."
7985
+ );
7986
+ }
7987
+ function printAgentCompletion({
7988
+ context,
7989
+ cancelled = false
7990
+ }) {
7991
+ console.log(
7992
+ cancelled ? "Setup cancelled." : `Setup walkthrough finished. Report which operations succeeded, failed, or were skipped based on their command results.
7993
+ Learn more: https://docs.zapier.com/sdk
7994
+
7995
+ Continue in this agent. Do not open another agent or ask the user to choose one.
7996
+ ${buildAgentPrompt({ context })}`
7997
+ );
7998
+ }
7999
+
8000
+ // src/plugins/setup/authentication.ts
8001
+ function printAuthCommand({
8002
+ context,
8003
+ flow,
8004
+ headless = false
8005
+ }) {
8006
+ const command = createLocalPackageCommand({
8007
+ packageManager: context.packageManager,
8008
+ binary: "zapier-sdk",
8009
+ args: [flow, ...headless ? ["--headless"] : []]
8010
+ });
8011
+ console.log(`$ ${formatPackageCommand(command)}`);
8012
+ if (headless) {
8013
+ console.log(
8014
+ "Open the printed URL in another browser, then paste the final OAuth callback URL when prompted."
8015
+ );
8016
+ }
8017
+ }
8018
+ function isCredentialWriteError(error) {
8019
+ const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "";
8020
+ if (/^(eacces|eperm)$/i.test(code)) return true;
8021
+ const message = error instanceof Error ? error.message : String(error);
8022
+ return /permission|sandbox|eacces|eperm/i.test(message);
8023
+ }
8024
+ async function confirmAuthentication(context) {
8025
+ const { data: profile } = await context.load({
8026
+ promise: context.imports.getProfile({}),
8027
+ label: "Confirming Zapier account"
8028
+ });
8029
+ context.accountEmail = profile.email;
8030
+ console.log(`Authenticated as ${profile.email}.`);
8031
+ }
8032
+ function selectAccountFlow(context) {
8033
+ return resolveSetupSelect({
8034
+ answer: context.createAnswer(),
8035
+ controller: context.setupController,
8036
+ message: "Zapier account:",
8037
+ choices: [
8038
+ { label: "Log in to an existing account", value: "login" },
8039
+ { label: "Create a new Zapier account", value: "signup" }
8040
+ ]
8041
+ });
8042
+ }
8043
+ function selectAuthenticationEnvironment(context) {
8044
+ return resolveSetupSelect({
8045
+ answer: context.createAnswer(),
8046
+ controller: context.setupController,
8047
+ message: "Environment:",
8048
+ choices: [
8049
+ { label: "Local machine with a browser", value: "local" },
8050
+ { label: "Remote or headless", value: "headless" }
8051
+ ]
8052
+ });
8053
+ }
8054
+ async function selectAccount(context) {
8055
+ const activeProfile = await context.load({
8056
+ promise: context.imports.getProfile({}).then(({ data }) => data).catch((error) => {
8057
+ if (isZapierAuthenticationError(error)) return void 0;
8058
+ throw error;
8059
+ }),
8060
+ label: "Checking Zapier authentication"
8061
+ });
8062
+ const storedCredentialsSelection = await context.selectStoredLoginCredentials();
8063
+ if (storedCredentialsSelection === "none" && activeProfile) {
8064
+ const shouldLogout = await resolveSetupConfirm({
8065
+ answer: context.createAnswer(),
8066
+ controller: context.setupController,
8067
+ message: `You are already logged in as "${activeProfile.email}".
8068
+ Logging out will delete these credentials and may interrupt other Zapier SDK or CLI sessions using them.
8069
+ Log out and use a different account?`,
8070
+ defaultValue: false
8071
+ });
8072
+ if (!shouldLogout) {
8073
+ context.accountEmail = activeProfile.email;
8074
+ console.log(`Continuing as ${activeProfile.email}.`);
8075
+ return "continue";
8076
+ }
8077
+ printAuthCommand({ context, flow: "logout" });
8078
+ await context.imports.logout({});
8079
+ }
8080
+ return storedCredentialsSelection;
8081
+ }
8082
+ async function authenticate(context) {
8083
+ const next = await runAuthenticationStep({ context, options: {} });
8084
+ if (next.step === "confirm-account") await confirmAuthentication(context);
8085
+ }
8086
+ async function runAuthenticationStep({
8087
+ context,
8088
+ options
8089
+ }) {
8090
+ const { step } = options;
8091
+ let newAccount = step === "account-environment";
8092
+ if (!step || step === "account") {
8093
+ const selection = await selectAccount(context);
8094
+ if (selection === "switch") return { step: "confirm-account" };
8095
+ if (selection === "continue")
8096
+ return { step: step ? "confirm-account" : "connections" };
8097
+ if (step) return { step: "account-flow" };
8098
+ newAccount = selection === "create";
8099
+ }
8100
+ if (step === "confirm-account") {
8101
+ await confirmAuthentication(context);
8102
+ return { step: "connections" };
8103
+ }
8104
+ const flow = !step || step === "account-flow" ? await selectAccountFlow(context) : options.flow;
8105
+ if (step === "account-flow")
8106
+ return {
8107
+ step: "account-environment",
8108
+ flow
8109
+ };
8110
+ if (!flow)
8111
+ throw new ZapierCliValidationError(
8112
+ "This setup step requires --flow login or --flow signup."
8113
+ );
8114
+ let headless = true;
8115
+ let callbackUrl;
8116
+ let recoveryMessage;
8117
+ if (step === "authorize") {
8118
+ recoveryMessage = `Generate a fresh authorization URL with \`${formatSetupCommand(
8119
+ {
8120
+ context,
8121
+ target: { step: "account-environment", flow },
8122
+ answer: "headless"
8123
+ }
8124
+ )}\`.`;
8125
+ const pending = getPendingOauthFlow({ entryPoint: flow, recoveryMessage });
8126
+ context.authorizationUrl = pending.transaction.browserAuthUrl;
8127
+ callbackUrl = await resolveSetupInput({
8128
+ answer: context.createAnswer(),
8129
+ controller: context.setupController,
8130
+ message: OAUTH_CALLBACK_QUESTION
8131
+ });
8132
+ } else {
8133
+ headless = await selectAuthenticationEnvironment(context) === "headless";
8134
+ if (!step) printAuthCommand({ context, flow, headless });
8135
+ }
8136
+ const authOptions = {
8137
+ headless,
8138
+ ...step ? { nonInteractive: true } : {},
8139
+ ...callbackUrl !== void 0 ? { callbackUrl } : {}
8140
+ };
8141
+ try {
8142
+ if (newAccount) {
8143
+ await context.authenticateNewAccount({
8144
+ entryPoint: flow,
8145
+ ...authOptions
8146
+ });
8147
+ } else {
8148
+ await context.imports[flow](authOptions);
8149
+ }
8150
+ } catch (error) {
8151
+ if (recoveryMessage) console.error(recoveryMessage);
8152
+ if (isCredentialWriteError(error)) {
8153
+ console.error(
8154
+ "Authentication could not write credentials. A permissions or sandbox restriction may be blocking disk access."
8155
+ );
8156
+ }
8157
+ throw error;
8158
+ }
8159
+ return step === "account-environment" && headless ? { step: "authorize", flow } : { step: "confirm-account" };
8160
+ }
7889
8161
  var CONNECTIONS_URL = "https://zapier.com/app/assets/connections";
7890
8162
  var CONNECTION_DISPLAY_LIMIT = 10;
7891
- async function ensureConnectionsAvailable(context) {
7892
- const page = await runWithSetupLoader({
8163
+ async function showActiveConnections(context) {
8164
+ const page = await context.load({
7893
8165
  promise: context.imports.listConnections({
7894
8166
  owner: "me",
7895
8167
  maxItems: CONNECTION_DISPLAY_LIMIT
7896
8168
  }),
7897
8169
  label: "Loading app connections"
7898
8170
  });
7899
- if (page.data.length === 0) {
7900
- console.log(
7901
- `No active connections found. Connect or reconnect an app at ${CONNECTIONS_URL}, then come back and run setup again.`
7902
- );
7903
- throw new ZapierCliExitError(
7904
- "Setup stopped before completion because no active connections are available."
7905
- );
7906
- }
8171
+ if (page.data.length === 0) return false;
7907
8172
  const table = new Table({
7908
8173
  head: ["App", "Connection"],
7909
- style: { compact: true }
8174
+ style: {
8175
+ compact: true,
8176
+ ...process.stdout.isTTY ? {} : { head: [], border: [] }
8177
+ }
7910
8178
  });
7911
8179
  table.push(
7912
8180
  ...page.data.map((connection) => [
@@ -7918,11 +8186,22 @@ async function ensureConnectionsAvailable(context) {
7918
8186
  `Active Zapier connections (showing up to ${CONNECTION_DISPLAY_LIMIT}):`
7919
8187
  );
7920
8188
  console.log(table.toString());
8189
+ return true;
8190
+ }
8191
+ async function ensureConnectionsAvailable(context) {
8192
+ if (await showActiveConnections(context)) return;
8193
+ console.log(
8194
+ `No active connections found. Connect or reconnect an app at ${CONNECTIONS_URL}, then come back and run setup again.`
8195
+ );
8196
+ throw new ZapierCliExitError(
8197
+ "Setup stopped before completion because no active connections are available."
8198
+ );
7921
8199
  }
7922
8200
  var CONNECTION_PLACEHOLDER = "__ZAPIER_SDK_SLACK_CONNECTION__";
7923
8201
  var EMAIL_PLACEHOLDER = "__ZAPIER_SDK_ACCOUNT_EMAIL__";
7924
8202
  var APP_PLACEHOLDER = "__ZAPIER_SDK_SLACK_APP__";
7925
8203
  var SLACK_SLUG = "slack";
8204
+ var SLACK_RETRY_QUESTION = "Slack email for one retry after the failed test:";
7926
8205
  function getSlackTestPath(context) {
7927
8206
  const extension = context.projectLanguage === "typescript" ? "ts" : "mjs";
7928
8207
  return join("src", "sdk-demo", `zapier-slack-test.${extension}`);
@@ -7932,7 +8211,7 @@ function getSlackTestTemplatePath(context) {
7932
8211
  return join(TEMPLATES_DIR, "setup", `zapier-slack-test.${extension}`);
7933
8212
  }
7934
8213
  async function findSlackConnection(context) {
7935
- const page = await runWithSetupLoader({
8214
+ const page = await context.load({
7936
8215
  promise: context.imports.listConnections({
7937
8216
  owner: "me",
7938
8217
  app: SLACK_SLUG,
@@ -7953,17 +8232,22 @@ function renderSlackTest({
7953
8232
  }) {
7954
8233
  return readFileSync(getSlackTestTemplatePath(context), "utf8").replace(APP_PLACEHOLDER, () => toTemplateString(app)).replace(CONNECTION_PLACEHOLDER, () => toTemplateString(connection)).replace(EMAIL_PLACEHOLDER, () => toTemplateString(email));
7955
8234
  }
7956
- function writeSlackTest({
8235
+ async function createAndRunSlackTest({
7957
8236
  context,
7958
- app,
7959
8237
  connection,
7960
- email
8238
+ email,
8239
+ overwrite = true
7961
8240
  }) {
7962
8241
  const slackTestPath = getSlackTestPath(context);
7963
8242
  const path2 = join(context.cwd, slackTestPath);
7964
8243
  if (!existsSync(dirname(path2))) mkdirSync(dirname(path2), { recursive: true });
7965
- writeFileSync(path2, renderSlackTest({ context, app, connection, email }));
8244
+ writeFileSync(
8245
+ path2,
8246
+ renderSlackTest({ context, app: SLACK_SLUG, connection, email }),
8247
+ { flag: overwrite ? "w" : "wx" }
8248
+ );
7966
8249
  console.log(`Created ${slackTestPath}.`);
8250
+ return trySlackTest(context);
7967
8251
  }
7968
8252
  async function executeSlackTest(context) {
7969
8253
  const slackTestPath = getSlackTestPath(context);
@@ -7991,75 +8275,76 @@ async function executeSlackTest(context) {
7991
8275
  async function trySlackTest(context) {
7992
8276
  try {
7993
8277
  await executeSlackTest(context);
8278
+ (context.outcomes ?? (context.outcomes = {})).slack = "succeeded";
7994
8279
  return true;
7995
8280
  } catch (error) {
8281
+ (context.outcomes ?? (context.outcomes = {})).slack = "failed";
7996
8282
  const message = error instanceof Error ? error.message : String(error);
7997
8283
  console.warn(`Slack demo failed: ${message}. Setup will continue.`);
7998
8284
  return false;
7999
8285
  }
8000
8286
  }
8001
- async function offerSlackTest(context) {
8287
+ async function runSlackStep({
8288
+ context,
8289
+ step,
8290
+ connection
8291
+ }) {
8002
8292
  if (!context.accountEmail) {
8003
8293
  console.log("No account email found; skipping the Slack demo.");
8004
- return;
8294
+ return "handoff";
8005
8295
  }
8006
- const slackConnection = await findSlackConnection(context);
8007
- if (!slackConnection) {
8296
+ if (!connection) {
8008
8297
  console.log("No active Slack connection found; skipping the Slack demo.");
8009
- return;
8298
+ return "handoff";
8010
8299
  }
8011
- const slackTestPath = getSlackTestPath(context);
8012
- const shouldRun = await resolveSetupConfirm({
8013
- answer: context.createAnswer(),
8014
- controller: context.setupController,
8015
- message: `Run the Slack self-DM test using ${context.accountEmail}?`,
8016
- defaultValue: true
8017
- });
8018
- if (!shouldRun) return;
8019
- const path2 = join(context.cwd, slackTestPath);
8020
- if (existsSync(path2)) {
8021
- const shouldOverwrite = await resolveSetupConfirm({
8300
+ if (step === "slack-retry") {
8301
+ const email = await resolveSetupInput({
8022
8302
  answer: context.createAnswer(),
8023
8303
  controller: context.setupController,
8024
- message: `${slackTestPath} already exists. Is it okay to overwrite it?`,
8025
- defaultValue: false
8304
+ message: SLACK_RETRY_QUESTION
8026
8305
  });
8027
- if (!shouldOverwrite) {
8028
- console.log("Keeping the existing Slack test file.");
8029
- const shouldRunExisting = await resolveSetupConfirm({
8030
- answer: context.createAnswer(),
8031
- controller: context.setupController,
8032
- message: `Run the existing ${slackTestPath}?`,
8033
- defaultValue: false
8306
+ if (email)
8307
+ await createAndRunSlackTest({
8308
+ context,
8309
+ connection: connection.id,
8310
+ email
8034
8311
  });
8035
- if (shouldRunExisting) await trySlackTest(context);
8036
- return;
8037
- }
8312
+ else console.log("Skipping the Slack test.");
8313
+ return "handoff";
8038
8314
  }
8039
- let email = context.accountEmail;
8040
- writeSlackTest({
8041
- context,
8042
- app: SLACK_SLUG,
8043
- connection: slackConnection.id,
8044
- email
8045
- });
8046
- if (await trySlackTest(context)) return;
8047
- email = await resolveSetupInput({
8315
+ const slackTestPath = getSlackTestPath(context);
8316
+ const shouldRun = await resolveSetupConfirm({
8048
8317
  answer: context.createAnswer(),
8049
8318
  controller: context.setupController,
8050
- message: "Slack email for one retry after the failed test:"
8319
+ message: step === "slack" ? `Run the Slack self-DM test using ${context.accountEmail}?` : step === "slack-overwrite" ? `${slackTestPath} already exists. Is it okay to overwrite it?` : `Run the existing ${slackTestPath}?`,
8320
+ defaultValue: step === "slack"
8051
8321
  });
8052
- if (!email) {
8053
- console.log("Skipping the Slack test.");
8054
- return;
8322
+ if (!shouldRun) {
8323
+ if (step === "slack-overwrite") {
8324
+ console.log("Keeping the existing Slack test file.");
8325
+ return "slack-existing";
8326
+ }
8327
+ return "handoff";
8328
+ }
8329
+ if (step === "slack" && existsSync(join(context.cwd, slackTestPath)))
8330
+ return "slack-overwrite";
8331
+ if (step === "slack-existing") {
8332
+ await trySlackTest(context);
8333
+ return "handoff";
8055
8334
  }
8056
- writeSlackTest({
8335
+ const succeeded = await createAndRunSlackTest({
8057
8336
  context,
8058
- app: SLACK_SLUG,
8059
- connection: slackConnection.id,
8060
- email
8337
+ connection: connection.id,
8338
+ email: context.accountEmail,
8339
+ overwrite: step === "slack-overwrite"
8061
8340
  });
8062
- await trySlackTest(context);
8341
+ return succeeded ? "handoff" : "slack-retry";
8342
+ }
8343
+ async function offerSlackTest(context) {
8344
+ const connection = context.accountEmail ? await findSlackConnection(context) : void 0;
8345
+ let step = "slack";
8346
+ while (step !== "handoff")
8347
+ step = await runSlackStep({ context, step, connection });
8063
8348
  }
8064
8349
 
8065
8350
  // src/plugins/setup/skill.ts
@@ -8085,7 +8370,9 @@ async function installOptionalSkill(context) {
8085
8370
  cwd: context.cwd,
8086
8371
  capture: true
8087
8372
  });
8373
+ (context.outcomes ?? (context.outcomes = {})).skill = "succeeded";
8088
8374
  } catch {
8375
+ (context.outcomes ?? (context.outcomes = {})).skill = "failed";
8089
8376
  console.warn(
8090
8377
  `Could not install the optional Zapier SDK skill. To install it manually, run: ${formatPackageCommand(command)}`
8091
8378
  );
@@ -8142,6 +8429,177 @@ async function runWizard(context) {
8142
8429
  console.log(chalk10.bgCyan.black.bold(" Next steps "));
8143
8430
  await openAgentHandoff(context);
8144
8431
  }
8432
+ var UNPROMPTED_STEPS = [
8433
+ "project",
8434
+ "confirm-account",
8435
+ "connections"
8436
+ ];
8437
+ var ZapierSetupQuestionSignal = class extends ZapierSignal {
8438
+ constructor(question) {
8439
+ super(question.message);
8440
+ this.question = question;
8441
+ this.name = "ZapierSetupQuestionSignal";
8442
+ this.code = "ZAPIER_SETUP_QUESTION";
8443
+ }
8444
+ };
8445
+ function isZapierSetupQuestionSignal(error) {
8446
+ return isZapierSignal(error) && error.code === "ZAPIER_SETUP_QUESTION";
8447
+ }
8448
+ function createSetupAnswer({
8449
+ answer,
8450
+ execute
8451
+ }) {
8452
+ let answered = false;
8453
+ return async ({ result: { question } }) => {
8454
+ if (question.type === "collection")
8455
+ throw new ZapierCliValidationError(
8456
+ "Setup expects a selection or text input."
8457
+ );
8458
+ if (!execute) throw new ZapierSetupQuestionSignal(question);
8459
+ if (answered)
8460
+ throw new ZapierCliValidationError(
8461
+ "Each setup step can answer only one question. Inspect the next question with --agent and run it in a separate command."
8462
+ );
8463
+ answered = true;
8464
+ const confirmation = question.type === "select" && question.choices.some(({ value }) => value === "true") && question.choices.some(({ value }) => value === "false");
8465
+ if (answer === void 0 && !confirmation)
8466
+ throw new ZapierCliValidationError(
8467
+ "This setup step requires --answer. Inspect it with --agent and pass the user's selection or input."
8468
+ );
8469
+ if (question.type === "input")
8470
+ return { type: "custom", value: answer?.trim() ?? "" };
8471
+ const selected = answer?.trim() ?? question.choices[0].value;
8472
+ if (!question.choices.some(({ value }) => value === selected))
8473
+ throw new ZapierCliValidationError(
8474
+ `Answer must be one of: ${question.choices.map(({ value }) => value).join(", ")}.`
8475
+ );
8476
+ return { type: "choose", value: selected };
8477
+ };
8478
+ }
8479
+ async function runSetupStep({
8480
+ context,
8481
+ target
8482
+ }) {
8483
+ switch (target.step) {
8484
+ case "directory":
8485
+ await chooseDirectory(context);
8486
+ return { step: "project" };
8487
+ case "project":
8488
+ await ensureSupportedNode(context);
8489
+ await initializeProject(context);
8490
+ return { step: "install" };
8491
+ case "install":
8492
+ await offerMissingPackageInstall({
8493
+ context,
8494
+ packages: getPackageStates(context).filter(({ declared }) => !declared)
8495
+ });
8496
+ return { step: "sdk-update" };
8497
+ case "sdk-update":
8498
+ case "cli-update": {
8499
+ const name = target.step === "sdk-update" ? "@zapier/zapier-sdk" : "@zapier/zapier-sdk-cli";
8500
+ const packageState = getPackageStates(context).find(
8501
+ ({ dependency }) => dependency.name === name
8502
+ );
8503
+ if (packageState) await offerPackageUpdate({ context, packageState });
8504
+ return { step: target.step === "sdk-update" ? "cli-update" : "skill" };
8505
+ }
8506
+ case "skill":
8507
+ await installOptionalSkill(context);
8508
+ return { step: "account" };
8509
+ case "account":
8510
+ case "account-flow":
8511
+ case "account-environment":
8512
+ case "authorize":
8513
+ case "confirm-account":
8514
+ return runAuthenticationStep({ context, options: target });
8515
+ case "connections":
8516
+ if (!await showActiveConnections(context)) {
8517
+ console.log(
8518
+ `No active connections found. Ask the user to connect or reconnect an app at ${CONNECTIONS_URL}. After they confirm, run this exact command:
8519
+ ${formatSetupCommand({ context, target })}
8520
+ Success means it prints the active connections table.`
8521
+ );
8522
+ throw new ZapierCliExitError(
8523
+ "Setup stopped until an app connection is active."
8524
+ );
8525
+ }
8526
+ console.log(
8527
+ "Show the user every app and connection title in the table above before continuing. Do not just report that connections were found."
8528
+ );
8529
+ return { step: "slack" };
8530
+ case "slack":
8531
+ case "slack-overwrite":
8532
+ case "slack-existing":
8533
+ case "slack-retry": {
8534
+ const { data: profile } = await context.imports.getProfile({});
8535
+ context.accountEmail = profile.email;
8536
+ return {
8537
+ step: await runSlackStep({
8538
+ context,
8539
+ step: target.step,
8540
+ connection: await findSlackConnection(context)
8541
+ })
8542
+ };
8543
+ }
8544
+ }
8545
+ }
8546
+ async function runAgentSetup({
8547
+ context,
8548
+ options
8549
+ }) {
8550
+ if (options.agent && options.nonInteractive)
8551
+ throw new ZapierCliValidationError(
8552
+ "Use --agent to inspect a step or --non-interactive to execute it, not both."
8553
+ );
8554
+ if (!options.agent && !options.nonInteractive)
8555
+ throw new ZapierCliValidationError(
8556
+ options.step ? "Use --agent to inspect the named step or --non-interactive to execute it." : "--answer, --flow, and --language require a setup step."
8557
+ );
8558
+ if (options.nonInteractive && !options.step)
8559
+ throw new ZapierCliValidationError(
8560
+ "--non-interactive requires --step. Start with setup --agent and follow its printed commands."
8561
+ );
8562
+ if (options.answer !== void 0 && !options.nonInteractive)
8563
+ throw new ZapierCliValidationError("--answer requires --non-interactive.");
8564
+ context.cwd = realpathSync(context.cwd);
8565
+ context.projectLanguage = options.language ?? detectProjectLanguage({
8566
+ cwd: context.cwd,
8567
+ hasExistingProject: existsSync(join(context.cwd, "package.json"))
8568
+ });
8569
+ let target = {
8570
+ step: options.step ?? "directory",
8571
+ flow: options.flow
8572
+ };
8573
+ let execute = options.nonInteractive === true;
8574
+ while (true) {
8575
+ const { step, flow } = target;
8576
+ if (step === "handoff") return printAgentCompletion({ context });
8577
+ if (!execute && UNPROMPTED_STEPS.includes(step))
8578
+ return printAgentStep({ context, target });
8579
+ const answer = createSetupAnswer({
8580
+ answer: execute ? options.answer : void 0,
8581
+ execute
8582
+ });
8583
+ context.createAnswer = () => answer;
8584
+ try {
8585
+ const next = await runSetupStep({ context, target: { step, flow } });
8586
+ if (options.language) context.projectLanguage = options.language;
8587
+ if (execute)
8588
+ for (const [operation, outcome] of Object.entries(
8589
+ context.outcomes ?? {}
8590
+ ))
8591
+ console.log(`${operation}: ${outcome}`);
8592
+ target = next;
8593
+ execute = false;
8594
+ } catch (error) {
8595
+ if (isZapierSetupQuestionSignal(error))
8596
+ return printAgentStep({ context, target, question: error.question });
8597
+ if (error instanceof ZapierCliUserCancellationError)
8598
+ return printAgentCompletion({ context, cancelled: true });
8599
+ throw error;
8600
+ }
8601
+ }
8602
+ }
8145
8603
 
8146
8604
  // src/plugins/setup/index.ts
8147
8605
  var getProfileRef = declareMethod({ id: "getProfile" });
@@ -8166,10 +8624,19 @@ var setupPlugin = defineMethod({
8166
8624
  supportsJsonOutput: false,
8167
8625
  inputSchema: SetupSchema,
8168
8626
  output: "raw",
8169
- run: async ({ imports }) => {
8627
+ run: async ({ imports, input }) => {
8628
+ if (input.agent || input.nonInteractive || [input.step, input.answer, input.flow, input.language].some(
8629
+ (value) => value !== void 0
8630
+ )) {
8631
+ await runAgentSetup({
8632
+ context: createWizardContext({ imports, agent: true }),
8633
+ options: input
8634
+ });
8635
+ return;
8636
+ }
8170
8637
  if (process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
8171
- throw new ZapierCliExitError(
8172
- "`zapier-sdk setup` requires an interactive terminal."
8638
+ throw new ZapierCliValidationError(
8639
+ "`zapier-sdk setup` requires an interactive terminal. AI agents and other callers without a terminal should run `zapier-sdk setup --agent` and follow its printed steps."
8173
8640
  );
8174
8641
  }
8175
8642
  await runWizard(createWizardContext({ imports }));
@@ -8649,59 +9116,6 @@ var watchTriggerInboxCliPlugin = defineMethod({
8649
9116
  return doWatch();
8650
9117
  }
8651
9118
  });
8652
- var createWorkflowRef = declareMethod$1({ id: "createWorkflow" });
8653
- function createPublicInputSchema(schema) {
8654
- const publicSchema = z.object(
8655
- Object.fromEntries(
8656
- Object.entries(schema.shape).filter(
8657
- ([name]) => !INTERNAL_CREATE_WORKFLOW_FIELDS.includes(
8658
- name
8659
- )
8660
- )
8661
- )
8662
- );
8663
- return schema.description === void 0 ? publicSchema : publicSchema.describe(schema.description);
8664
- }
8665
- var CreateWorkflowCliOptionsSchema = createPublicInputSchema(
8666
- CreateWorkflowOptionsSchema
8667
- );
8668
- var createWorkflowCliPlugin = defineMethod$1({
8669
- namespace: "cli",
8670
- name: "createWorkflow",
8671
- imports: [createWorkflowRef],
8672
- type: "create",
8673
- itemType: "Workflow",
8674
- categories: ["code-workflow"],
8675
- stability: "experimental",
8676
- inputSchema: CreateWorkflowCliOptionsSchema,
8677
- outputSchema: CreateWorkflowResponseSchema,
8678
- skipOutputValidation: true,
8679
- output: "raw",
8680
- run: ({ imports, input }) => imports.createWorkflow({
8681
- ...input,
8682
- creationHarness: getAgent(),
8683
- creationAccessMethod: "sdk_cli"
8684
- })
8685
- });
8686
- var importWorkflowRef = declareMethod$1({ id: "importWorkflow" });
8687
- var importWorkflowCliPlugin = defineMethod$1({
8688
- namespace: "cli",
8689
- name: "importWorkflow",
8690
- imports: [importWorkflowRef],
8691
- type: "create",
8692
- itemType: "Workflow",
8693
- categories: ["code-workflow"],
8694
- stability: "experimental",
8695
- inputSchema: createPublicInputSchema(ImportWorkflowOptionsSchema),
8696
- outputSchema: ImportWorkflowResponseSchema,
8697
- skipOutputValidation: true,
8698
- output: "raw",
8699
- run: ({ imports, input }) => imports.importWorkflow({
8700
- ...input,
8701
- creationHarness: getAgent(),
8702
- creationAccessMethod: "sdk_cli"
8703
- })
8704
- });
8705
9119
  var BOX_WIDTH = 72;
8706
9120
  var BOX_TITLE = "ZAPIER SDK DEPRECATION NOTICE";
8707
9121
  var activeNotices = /* @__PURE__ */ new Map();
@@ -8744,7 +9158,7 @@ function buildBoxLines(message) {
8744
9158
  // package.json with { type: 'json' }
8745
9159
  var package_default2 = {
8746
9160
  name: "@zapier/zapier-sdk-cli",
8747
- version: "0.86.7"};
9161
+ version: "0.87.2"};
8748
9162
 
8749
9163
  // src/sdk.ts
8750
9164
  var warnedDeprecatedMethods = /* @__PURE__ */ new Set();
@@ -8910,14 +9324,10 @@ function createZapierCliSdk3(options = {}) {
8910
9324
  exports: [
8911
9325
  omitExports$1(zapierExperimentalSdkPlugin, [
8912
9326
  "drainTriggerInbox",
8913
- "watchTriggerInbox",
8914
- "createWorkflow",
8915
- "importWorkflow"
9327
+ "watchTriggerInbox"
8916
9328
  ]),
8917
9329
  drainTriggerInboxCliPlugin,
8918
9330
  watchTriggerInboxCliPlugin,
8919
- createWorkflowCliPlugin,
8920
- importWorkflowCliPlugin,
8921
9331
  loginPlugin,
8922
9332
  signupPlugin,
8923
9333
  logoutPlugin,