@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/AGENTS.md +4 -4
- package/CHANGELOG.md +29 -0
- package/README.md +40 -3
- package/dist/cli.cjs +801 -391
- package/dist/cli.mjs +805 -395
- package/dist/experimental.cjs +798 -386
- package/dist/experimental.d.mts +1 -1
- package/dist/experimental.d.ts +1 -1
- package/dist/experimental.mjs +801 -389
- package/dist/{extensions-OFaHmWVC.d.mts → extensions-CrfC6xjA.d.mts} +23 -2
- package/dist/{extensions-OFaHmWVC.d.ts → extensions-CrfC6xjA.d.ts} +23 -2
- package/dist/index.cjs +798 -388
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +802 -392
- package/package.json +3 -3
package/dist/experimental.cjs
CHANGED
|
@@ -31,6 +31,7 @@ var packageJsonLib = require('package-json');
|
|
|
31
31
|
var semver = require('semver');
|
|
32
32
|
var crossSpawn = require('cross-spawn');
|
|
33
33
|
var wrapAnsi = require('wrap-ansi');
|
|
34
|
+
var module$1 = require('module');
|
|
34
35
|
var Table = require('cli-table3');
|
|
35
36
|
|
|
36
37
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
@@ -1035,6 +1036,7 @@ var SENSITIVE_FLAGS = [
|
|
|
1035
1036
|
"--credentials-client-id",
|
|
1036
1037
|
"--credentials-base-url",
|
|
1037
1038
|
"--callback-url",
|
|
1039
|
+
"--answer",
|
|
1038
1040
|
"--user",
|
|
1039
1041
|
"--header",
|
|
1040
1042
|
"-H",
|
|
@@ -1271,6 +1273,7 @@ var searchSelect = core.createPrompt(
|
|
|
1271
1273
|
);
|
|
1272
1274
|
|
|
1273
1275
|
// src/utils/auth/credentials-picker.ts
|
|
1276
|
+
var CREDENTIALS_PICKER_QUESTION = "Select credentials or add a new account:";
|
|
1274
1277
|
function isSameCredentials(left, right) {
|
|
1275
1278
|
return left.name === right.name && left.baseUrl === right.baseUrl;
|
|
1276
1279
|
}
|
|
@@ -1376,7 +1379,7 @@ async function promptForCredentials({
|
|
|
1376
1379
|
activeCredentials
|
|
1377
1380
|
}) {
|
|
1378
1381
|
return searchSelect({
|
|
1379
|
-
message:
|
|
1382
|
+
message: CREDENTIALS_PICKER_QUESTION,
|
|
1380
1383
|
source: (term) => buildCredentialsChoices({
|
|
1381
1384
|
credentials,
|
|
1382
1385
|
activeCredentials,
|
|
@@ -1439,14 +1442,15 @@ async function switchCredentials({
|
|
|
1439
1442
|
async function chooseStoredLoginCredentialsAtBaseUrl({
|
|
1440
1443
|
baseUrl,
|
|
1441
1444
|
options,
|
|
1442
|
-
resolvedCredentials
|
|
1445
|
+
resolvedCredentials,
|
|
1446
|
+
prompt = promptForCredentials
|
|
1443
1447
|
}) {
|
|
1444
1448
|
if (resolvedCredentials !== void 0 || authFlowOnlyOptions(options).length > 0) {
|
|
1445
1449
|
return "none";
|
|
1446
1450
|
}
|
|
1447
1451
|
const storedCredentials = listStoredCredentials({ baseUrl });
|
|
1448
1452
|
if (storedCredentials.length === 0) return "none";
|
|
1449
|
-
const selection = await
|
|
1453
|
+
const selection = await prompt({
|
|
1450
1454
|
credentials: storedCredentials,
|
|
1451
1455
|
activeCredentials: getActiveCredentials({ baseUrl })
|
|
1452
1456
|
});
|
|
@@ -1460,7 +1464,8 @@ async function chooseStoredLoginCredentialsAtBaseUrl({
|
|
|
1460
1464
|
}
|
|
1461
1465
|
async function chooseStoredLoginCredentials({
|
|
1462
1466
|
imports,
|
|
1463
|
-
options
|
|
1467
|
+
options,
|
|
1468
|
+
prompt
|
|
1464
1469
|
}) {
|
|
1465
1470
|
const resolvedCredentials = await imports.resolveCredentials();
|
|
1466
1471
|
const credentialsBaseUrl = await resolveCredentialsBaseUrl({
|
|
@@ -1470,7 +1475,8 @@ async function chooseStoredLoginCredentials({
|
|
|
1470
1475
|
return chooseStoredLoginCredentialsAtBaseUrl({
|
|
1471
1476
|
baseUrl: credentialsBaseUrl,
|
|
1472
1477
|
options,
|
|
1473
|
-
resolvedCredentials
|
|
1478
|
+
resolvedCredentials,
|
|
1479
|
+
prompt
|
|
1474
1480
|
});
|
|
1475
1481
|
}
|
|
1476
1482
|
async function confirmNewCredentialsName(name) {
|
|
@@ -1841,6 +1847,7 @@ var PendingOauthTransactionSchema = zod.z.object({
|
|
|
1841
1847
|
credentialName: zod.z.string().optional(),
|
|
1842
1848
|
useApprovals: zod.z.boolean(),
|
|
1843
1849
|
headless: zod.z.boolean().default(false),
|
|
1850
|
+
preserveExistingCredentials: zod.z.boolean().default(false),
|
|
1844
1851
|
transaction: OauthTransactionSchema
|
|
1845
1852
|
});
|
|
1846
1853
|
function savePendingOauthTransaction({
|
|
@@ -1850,7 +1857,8 @@ function savePendingOauthTransaction({
|
|
|
1850
1857
|
credentialsBaseUrl,
|
|
1851
1858
|
credentialName,
|
|
1852
1859
|
useApprovals,
|
|
1853
|
-
headless
|
|
1860
|
+
headless,
|
|
1861
|
+
preserveExistingCredentials = false
|
|
1854
1862
|
}) {
|
|
1855
1863
|
const pendingTransaction = {
|
|
1856
1864
|
version: 1,
|
|
@@ -1858,6 +1866,7 @@ function savePendingOauthTransaction({
|
|
|
1858
1866
|
expiresAt,
|
|
1859
1867
|
useApprovals,
|
|
1860
1868
|
headless,
|
|
1869
|
+
preserveExistingCredentials,
|
|
1861
1870
|
transaction,
|
|
1862
1871
|
...credentialsBaseUrl !== void 0 && { credentialsBaseUrl },
|
|
1863
1872
|
...credentialName !== void 0 && { credentialName }
|
|
@@ -1876,6 +1885,7 @@ function clearPendingOauthTransaction() {
|
|
|
1876
1885
|
}
|
|
1877
1886
|
|
|
1878
1887
|
// src/utils/auth/oauth-flow.ts
|
|
1888
|
+
var OAUTH_CALLBACK_QUESTION = "Paste the final OAuth callback URL:";
|
|
1879
1889
|
var PENDING_OAUTH_RECOVERY_MESSAGE = "Start a new non-interactive login or signup flow to generate a fresh URL.";
|
|
1880
1890
|
var LOGIN_OAUTH_COPY = {
|
|
1881
1891
|
flowName: "Login",
|
|
@@ -1939,7 +1949,9 @@ async function startPendingOauthFlow({
|
|
|
1939
1949
|
entryPoint,
|
|
1940
1950
|
credentialName,
|
|
1941
1951
|
useApprovals,
|
|
1942
|
-
headless
|
|
1952
|
+
headless,
|
|
1953
|
+
preserveExistingCredentials = false,
|
|
1954
|
+
silent = false
|
|
1943
1955
|
}) {
|
|
1944
1956
|
const copy = entryPoint === "signup" ? SIGNUP_OAUTH_COPY : LOGIN_OAUTH_COPY;
|
|
1945
1957
|
const port = LOGIN_PORTS[0];
|
|
@@ -1956,8 +1968,10 @@ async function startPendingOauthFlow({
|
|
|
1956
1968
|
credentialsBaseUrl: baseUrl,
|
|
1957
1969
|
credentialName,
|
|
1958
1970
|
useApprovals,
|
|
1959
|
-
headless
|
|
1971
|
+
headless,
|
|
1972
|
+
preserveExistingCredentials
|
|
1960
1973
|
});
|
|
1974
|
+
if (silent) return pending;
|
|
1961
1975
|
process.stderr.write(
|
|
1962
1976
|
`Open this ${copy.urlLabel} in a browser to continue:
|
|
1963
1977
|
`
|
|
@@ -1983,23 +1997,24 @@ async function startPendingOauthFlow({
|
|
|
1983
1997
|
return pending;
|
|
1984
1998
|
}
|
|
1985
1999
|
function getPendingOauthFlow({
|
|
1986
|
-
entryPoint
|
|
2000
|
+
entryPoint,
|
|
2001
|
+
recoveryMessage = PENDING_OAUTH_RECOVERY_MESSAGE
|
|
1987
2002
|
}) {
|
|
1988
2003
|
const pending = getPendingOauthTransaction();
|
|
1989
2004
|
if (!pending) {
|
|
1990
2005
|
throw new ZapierCliValidationError(
|
|
1991
|
-
`No pending ${entryPoint} OAuth flow found. ${
|
|
2006
|
+
`No pending ${entryPoint} OAuth flow found. ${recoveryMessage}`
|
|
1992
2007
|
);
|
|
1993
2008
|
}
|
|
1994
2009
|
if (Date.now() > pending.expiresAt) {
|
|
1995
2010
|
clearPendingOauthTransaction();
|
|
1996
2011
|
throw new ZapierCliValidationError(
|
|
1997
|
-
`Pending ${pending.entryPoint} OAuth flow has expired. ${
|
|
2012
|
+
`Pending ${pending.entryPoint} OAuth flow has expired. ${recoveryMessage}`
|
|
1998
2013
|
);
|
|
1999
2014
|
}
|
|
2000
2015
|
if (pending.entryPoint !== entryPoint) {
|
|
2001
2016
|
throw new ZapierCliValidationError(
|
|
2002
|
-
`Pending OAuth flow is for ${pending.entryPoint}, not ${entryPoint}. ${
|
|
2017
|
+
`Pending OAuth flow is for ${pending.entryPoint}, not ${entryPoint}. ${recoveryMessage}`
|
|
2003
2018
|
);
|
|
2004
2019
|
}
|
|
2005
2020
|
return pending;
|
|
@@ -2162,7 +2177,7 @@ async function readHeadlessCallbackUrl({
|
|
|
2162
2177
|
process.once("SIGINT", handleCancellation);
|
|
2163
2178
|
process.once("SIGTERM", handleCancellation);
|
|
2164
2179
|
if (interactive) {
|
|
2165
|
-
void rl.question(
|
|
2180
|
+
void rl.question(`${OAUTH_CALLBACK_QUESTION} `, {
|
|
2166
2181
|
signal: abortController.signal
|
|
2167
2182
|
}).then(settleResolve).catch((error) => {
|
|
2168
2183
|
if (error instanceof Error && error.name === "AbortError") {
|
|
@@ -2649,7 +2664,7 @@ async function runOauthForEntryPoint({
|
|
|
2649
2664
|
if (event.type === "callback_accepted") {
|
|
2650
2665
|
emitSignupSuccess({
|
|
2651
2666
|
imports,
|
|
2652
|
-
isNonInteractive:
|
|
2667
|
+
isNonInteractive: !interactive,
|
|
2653
2668
|
isHeadless: headless === true
|
|
2654
2669
|
});
|
|
2655
2670
|
}
|
|
@@ -2731,7 +2746,9 @@ async function runAccountAuth({
|
|
|
2731
2746
|
options,
|
|
2732
2747
|
entryPoint,
|
|
2733
2748
|
storedCredentialsMode = "choose",
|
|
2734
|
-
preserveExistingCredentials = false
|
|
2749
|
+
preserveExistingCredentials = false,
|
|
2750
|
+
useBrowserCallback = false,
|
|
2751
|
+
silent = false
|
|
2735
2752
|
}) {
|
|
2736
2753
|
if (options.callbackUrl !== void 0) {
|
|
2737
2754
|
const { callbackUrl } = options;
|
|
@@ -2764,7 +2781,8 @@ async function runAccountAuth({
|
|
|
2764
2781
|
imports,
|
|
2765
2782
|
baseUrl: pending.credentialsBaseUrl,
|
|
2766
2783
|
interactive: false,
|
|
2767
|
-
entryPoint
|
|
2784
|
+
entryPoint,
|
|
2785
|
+
preserveExistingCredentials: pending.preserveExistingCredentials
|
|
2768
2786
|
})) {
|
|
2769
2787
|
return;
|
|
2770
2788
|
}
|
|
@@ -2841,7 +2859,7 @@ async function runAccountAuth({
|
|
|
2841
2859
|
);
|
|
2842
2860
|
}
|
|
2843
2861
|
}
|
|
2844
|
-
if (entryPoint === "login" && !interactive && providedName === void 0) {
|
|
2862
|
+
if (entryPoint === "login" && !interactive && providedName === void 0 && !preserveExistingCredentials) {
|
|
2845
2863
|
const activeCredentials = getActiveCredentials({
|
|
2846
2864
|
baseUrl: credentialsBaseUrl
|
|
2847
2865
|
});
|
|
@@ -2858,7 +2876,7 @@ async function runAccountAuth({
|
|
|
2858
2876
|
}
|
|
2859
2877
|
const timeoutSeconds = parseTimeoutSeconds(options.timeout);
|
|
2860
2878
|
const useApprovals = options.useApprovals === true;
|
|
2861
|
-
if (!interactive) {
|
|
2879
|
+
if (!interactive && (headless || !useBrowserCallback)) {
|
|
2862
2880
|
await startPendingOauthFlow({
|
|
2863
2881
|
entryPoint,
|
|
2864
2882
|
timeoutMs: timeoutSeconds * 1e3,
|
|
@@ -2866,7 +2884,9 @@ async function runAccountAuth({
|
|
|
2866
2884
|
baseUrl: credentialsBaseUrl,
|
|
2867
2885
|
credentialName: providedName,
|
|
2868
2886
|
useApprovals,
|
|
2869
|
-
headless
|
|
2887
|
+
headless,
|
|
2888
|
+
preserveExistingCredentials,
|
|
2889
|
+
silent
|
|
2870
2890
|
});
|
|
2871
2891
|
return;
|
|
2872
2892
|
}
|
|
@@ -2887,7 +2907,7 @@ async function runAccountAuth({
|
|
|
2887
2907
|
credentialName: providedName,
|
|
2888
2908
|
interactive,
|
|
2889
2909
|
useApprovals,
|
|
2890
|
-
isNonInteractive:
|
|
2910
|
+
isNonInteractive: !interactive,
|
|
2891
2911
|
isHeadless: headless
|
|
2892
2912
|
});
|
|
2893
2913
|
}
|
|
@@ -4778,6 +4798,7 @@ function createProjectDir({
|
|
|
4778
4798
|
var TEMPLATES_DIR = url.fileURLToPath(
|
|
4779
4799
|
new URL("../templates", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('experimental.cjs', document.baseURI).href)))
|
|
4780
4800
|
);
|
|
4801
|
+
var SOURCE_CLI_PATH = (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('experimental.cjs', document.baseURI).href)).endsWith(".ts") ? url.fileURLToPath(new URL("./cli.ts", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('experimental.cjs', document.baseURI).href)))) : void 0;
|
|
4781
4802
|
|
|
4782
4803
|
// src/plugins/init/steps.ts
|
|
4783
4804
|
var DEFAULT_TEMPLATE = "basic";
|
|
@@ -5488,84 +5509,6 @@ async function checkForUpdates({
|
|
|
5488
5509
|
};
|
|
5489
5510
|
}
|
|
5490
5511
|
}
|
|
5491
|
-
var BRAILLE_BLANK = "\u2800";
|
|
5492
|
-
var LIGHTNING_INTERVAL_MILLISECONDS = 140;
|
|
5493
|
-
var boltRows = [
|
|
5494
|
-
"\u2800\u2800\u2880\u28FE\u2800\u2800\u2800\u2800",
|
|
5495
|
-
"\u2800\u2800\u28E0\u28FF\u28FF\u2800\u2800\u2800",
|
|
5496
|
-
"\u2800\u28FC\u28FF\u28FF\u28FF\u28C0\u28C0\u2840",
|
|
5497
|
-
"\u2808\u2809\u2809\u28FF\u28FF\u28FF\u285F\u2800",
|
|
5498
|
-
"\u2800\u2800\u2800\u28FF\u28FF\u280B\u2800\u2800",
|
|
5499
|
-
"\u2800\u2800\u2800\u287F\u2801\u2800\u2800\u2800"
|
|
5500
|
-
];
|
|
5501
|
-
var boltFillOrder = boltRows.flatMap(
|
|
5502
|
-
(row, rowIndex) => [...row].flatMap(
|
|
5503
|
-
(cell, columnIndex) => cell === BRAILLE_BLANK ? [] : rowIndex * row.length + columnIndex
|
|
5504
|
-
)
|
|
5505
|
-
);
|
|
5506
|
-
var fillStages = [
|
|
5507
|
-
...Array.from({ length: boltFillOrder.length + 1 }, (_, index) => index),
|
|
5508
|
-
boltFillOrder.length,
|
|
5509
|
-
0
|
|
5510
|
-
];
|
|
5511
|
-
var boltFillRanks = new Map(
|
|
5512
|
-
boltFillOrder.map((cellIndex, fillIndex) => [cellIndex, fillIndex])
|
|
5513
|
-
);
|
|
5514
|
-
var STATUS_ROW_INDEX = Math.floor(boltRows.length / 2);
|
|
5515
|
-
function formatPhase({ label, detail }) {
|
|
5516
|
-
return detail ? `${chalk5__default.default.bold(label)} ${chalk5__default.default.dim(detail)}` : chalk5__default.default.bold(label);
|
|
5517
|
-
}
|
|
5518
|
-
function formatLoaderFrame({
|
|
5519
|
-
phase,
|
|
5520
|
-
fillStage
|
|
5521
|
-
}) {
|
|
5522
|
-
return boltRows.map((row, rowIndex) => {
|
|
5523
|
-
const bolt = [...row].map((cell, columnIndex) => {
|
|
5524
|
-
if (cell === BRAILLE_BLANK) return cell;
|
|
5525
|
-
const cellIndex = rowIndex * row.length + columnIndex;
|
|
5526
|
-
const fillRank = boltFillRanks.get(cellIndex);
|
|
5527
|
-
const isFilled = fillRank !== void 0 && fillRank < fillStage;
|
|
5528
|
-
return isFilled ? chalk5__default.default.bold.yellow(cell) : chalk5__default.default.dim.yellow(cell);
|
|
5529
|
-
}).join("");
|
|
5530
|
-
const status = rowIndex === STATUS_ROW_INDEX ? ` ${formatPhase(phase)}` : "";
|
|
5531
|
-
return `${bolt}${status}`;
|
|
5532
|
-
}).join("\n");
|
|
5533
|
-
}
|
|
5534
|
-
async function runWithSetupLoader({
|
|
5535
|
-
promise,
|
|
5536
|
-
...phase
|
|
5537
|
-
}) {
|
|
5538
|
-
const startedAt = Date.now();
|
|
5539
|
-
let fillFrameIndex = 0;
|
|
5540
|
-
const loader = ora__default.default({
|
|
5541
|
-
isEnabled: process.stderr.isTTY === true,
|
|
5542
|
-
spinner: { interval: 80, frames: [""] },
|
|
5543
|
-
text: formatLoaderFrame({
|
|
5544
|
-
phase,
|
|
5545
|
-
fillStage: fillStages[fillFrameIndex]
|
|
5546
|
-
})
|
|
5547
|
-
}).start();
|
|
5548
|
-
const animationTimer = setInterval(() => {
|
|
5549
|
-
fillFrameIndex = (fillFrameIndex + 1) % fillStages.length;
|
|
5550
|
-
loader.text = formatLoaderFrame({
|
|
5551
|
-
phase,
|
|
5552
|
-
fillStage: fillStages[fillFrameIndex]
|
|
5553
|
-
});
|
|
5554
|
-
}, LIGHTNING_INTERVAL_MILLISECONDS);
|
|
5555
|
-
animationTimer.unref?.();
|
|
5556
|
-
try {
|
|
5557
|
-
const result = await promise;
|
|
5558
|
-
clearInterval(animationTimer);
|
|
5559
|
-
const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
|
|
5560
|
-
loader.succeed(`${formatPhase(phase)} ${chalk5__default.default.dim(`${elapsedSeconds}s`)}`);
|
|
5561
|
-
return result;
|
|
5562
|
-
} catch (error) {
|
|
5563
|
-
clearInterval(animationTimer);
|
|
5564
|
-
const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
|
|
5565
|
-
loader.fail(`${formatPhase(phase)} ${chalk5__default.default.dim(`${elapsedSeconds}s`)}`);
|
|
5566
|
-
throw error;
|
|
5567
|
-
}
|
|
5568
|
-
}
|
|
5569
5512
|
function isRecord(value) {
|
|
5570
5513
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5571
5514
|
}
|
|
@@ -5851,7 +5794,7 @@ async function offerPackageUpdate({
|
|
|
5851
5794
|
}) {
|
|
5852
5795
|
const { currentVersion, dependency } = packageState;
|
|
5853
5796
|
if (!currentVersion || !dependency.checkForUpdates) return;
|
|
5854
|
-
const update = await
|
|
5797
|
+
const update = await context.load({
|
|
5855
5798
|
promise: context.checkForUpdates({
|
|
5856
5799
|
packageName: dependency.name,
|
|
5857
5800
|
currentVersion
|
|
@@ -5876,28 +5819,108 @@ async function offerPackageUpdate({
|
|
|
5876
5819
|
})
|
|
5877
5820
|
);
|
|
5878
5821
|
}
|
|
5879
|
-
|
|
5822
|
+
function getPackageStates(context) {
|
|
5880
5823
|
const declaredPackageNames = getDeclaredPackageNames(context.cwd);
|
|
5881
5824
|
const requiredPackages = REQUIRED_PACKAGES.filter(
|
|
5882
5825
|
({ typescriptOnly }) => !typescriptOnly || context.projectLanguage === "typescript"
|
|
5883
5826
|
);
|
|
5884
|
-
|
|
5827
|
+
return requiredPackages.map((dependency) => ({
|
|
5885
5828
|
dependency,
|
|
5829
|
+
declared: declaredPackageNames.has(dependency.name),
|
|
5886
5830
|
currentVersion: declaredPackageNames.has(dependency.name) ? getInstalledPackageVersion({
|
|
5887
5831
|
cwd: context.cwd,
|
|
5888
5832
|
packageName: dependency.name
|
|
5889
5833
|
}) : void 0
|
|
5890
5834
|
}));
|
|
5835
|
+
}
|
|
5836
|
+
async function prepareDependencies(context) {
|
|
5837
|
+
const packages = getPackageStates(context);
|
|
5891
5838
|
await offerMissingPackageInstall({
|
|
5892
5839
|
context,
|
|
5893
|
-
packages: packages.filter(
|
|
5894
|
-
({ dependency }) => !declaredPackageNames.has(dependency.name)
|
|
5895
|
-
)
|
|
5840
|
+
packages: packages.filter(({ declared }) => !declared)
|
|
5896
5841
|
});
|
|
5897
5842
|
for (const packageState of packages) {
|
|
5898
5843
|
await offerPackageUpdate({ context, packageState });
|
|
5899
5844
|
}
|
|
5900
5845
|
}
|
|
5846
|
+
var BRAILLE_BLANK = "\u2800";
|
|
5847
|
+
var LIGHTNING_INTERVAL_MILLISECONDS = 140;
|
|
5848
|
+
var boltRows = [
|
|
5849
|
+
"\u2800\u2800\u2880\u28FE\u2800\u2800\u2800\u2800",
|
|
5850
|
+
"\u2800\u2800\u28E0\u28FF\u28FF\u2800\u2800\u2800",
|
|
5851
|
+
"\u2800\u28FC\u28FF\u28FF\u28FF\u28C0\u28C0\u2840",
|
|
5852
|
+
"\u2808\u2809\u2809\u28FF\u28FF\u28FF\u285F\u2800",
|
|
5853
|
+
"\u2800\u2800\u2800\u28FF\u28FF\u280B\u2800\u2800",
|
|
5854
|
+
"\u2800\u2800\u2800\u287F\u2801\u2800\u2800\u2800"
|
|
5855
|
+
];
|
|
5856
|
+
var boltFillOrder = boltRows.flatMap(
|
|
5857
|
+
(row, rowIndex) => [...row].flatMap(
|
|
5858
|
+
(cell, columnIndex) => cell === BRAILLE_BLANK ? [] : rowIndex * row.length + columnIndex
|
|
5859
|
+
)
|
|
5860
|
+
);
|
|
5861
|
+
var fillStages = [
|
|
5862
|
+
...Array.from({ length: boltFillOrder.length + 1 }, (_, index) => index),
|
|
5863
|
+
boltFillOrder.length,
|
|
5864
|
+
0
|
|
5865
|
+
];
|
|
5866
|
+
var boltFillRanks = new Map(
|
|
5867
|
+
boltFillOrder.map((cellIndex, fillIndex) => [cellIndex, fillIndex])
|
|
5868
|
+
);
|
|
5869
|
+
var STATUS_ROW_INDEX = Math.floor(boltRows.length / 2);
|
|
5870
|
+
function formatPhase({ label, detail }) {
|
|
5871
|
+
return detail ? `${chalk5__default.default.bold(label)} ${chalk5__default.default.dim(detail)}` : chalk5__default.default.bold(label);
|
|
5872
|
+
}
|
|
5873
|
+
function formatLoaderFrame({
|
|
5874
|
+
phase,
|
|
5875
|
+
fillStage
|
|
5876
|
+
}) {
|
|
5877
|
+
return boltRows.map((row, rowIndex) => {
|
|
5878
|
+
const bolt = [...row].map((cell, columnIndex) => {
|
|
5879
|
+
if (cell === BRAILLE_BLANK) return cell;
|
|
5880
|
+
const cellIndex = rowIndex * row.length + columnIndex;
|
|
5881
|
+
const fillRank = boltFillRanks.get(cellIndex);
|
|
5882
|
+
const isFilled = fillRank !== void 0 && fillRank < fillStage;
|
|
5883
|
+
return isFilled ? chalk5__default.default.bold.yellow(cell) : chalk5__default.default.dim.yellow(cell);
|
|
5884
|
+
}).join("");
|
|
5885
|
+
const status = rowIndex === STATUS_ROW_INDEX ? ` ${formatPhase(phase)}` : "";
|
|
5886
|
+
return `${bolt}${status}`;
|
|
5887
|
+
}).join("\n");
|
|
5888
|
+
}
|
|
5889
|
+
async function runWithSetupLoader({
|
|
5890
|
+
promise,
|
|
5891
|
+
...phase
|
|
5892
|
+
}) {
|
|
5893
|
+
const startedAt = Date.now();
|
|
5894
|
+
let fillFrameIndex = 0;
|
|
5895
|
+
const loader = ora__default.default({
|
|
5896
|
+
isEnabled: process.stderr.isTTY === true,
|
|
5897
|
+
spinner: { interval: 80, frames: [""] },
|
|
5898
|
+
text: formatLoaderFrame({
|
|
5899
|
+
phase,
|
|
5900
|
+
fillStage: fillStages[fillFrameIndex]
|
|
5901
|
+
})
|
|
5902
|
+
}).start();
|
|
5903
|
+
const animationTimer = setInterval(() => {
|
|
5904
|
+
fillFrameIndex = (fillFrameIndex + 1) % fillStages.length;
|
|
5905
|
+
loader.text = formatLoaderFrame({
|
|
5906
|
+
phase,
|
|
5907
|
+
fillStage: fillStages[fillFrameIndex]
|
|
5908
|
+
});
|
|
5909
|
+
}, LIGHTNING_INTERVAL_MILLISECONDS);
|
|
5910
|
+
animationTimer.unref?.();
|
|
5911
|
+
try {
|
|
5912
|
+
const result = await promise;
|
|
5913
|
+
clearInterval(animationTimer);
|
|
5914
|
+
const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
|
|
5915
|
+
loader.succeed(`${formatPhase(phase)} ${chalk5__default.default.dim(`${elapsedSeconds}s`)}`);
|
|
5916
|
+
return result;
|
|
5917
|
+
} catch (error) {
|
|
5918
|
+
clearInterval(animationTimer);
|
|
5919
|
+
const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
|
|
5920
|
+
loader.fail(`${formatPhase(phase)} ${chalk5__default.default.dim(`${elapsedSeconds}s`)}`);
|
|
5921
|
+
throw error;
|
|
5922
|
+
}
|
|
5923
|
+
}
|
|
5901
5924
|
|
|
5902
5925
|
// src/plugins/setup/package-commands.ts
|
|
5903
5926
|
function createLocalPackageCommand({
|
|
@@ -5936,7 +5959,10 @@ function formatPackageCommand({
|
|
|
5936
5959
|
command,
|
|
5937
5960
|
args
|
|
5938
5961
|
}) {
|
|
5939
|
-
return [command, ...args].join(" ");
|
|
5962
|
+
return [command, ...args].map(quoteShellArgument).join(" ");
|
|
5963
|
+
}
|
|
5964
|
+
function quoteShellArgument(value) {
|
|
5965
|
+
return /^[a-zA-Z0-9_@%+=:,./-]+$/.test(value) ? value : `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
5940
5966
|
}
|
|
5941
5967
|
|
|
5942
5968
|
// src/plugins/setup/project.ts
|
|
@@ -6041,13 +6067,14 @@ async function runCommand({
|
|
|
6041
6067
|
args = [],
|
|
6042
6068
|
cwd,
|
|
6043
6069
|
capture = true,
|
|
6044
|
-
input
|
|
6070
|
+
input,
|
|
6071
|
+
load = runWithSetupLoader
|
|
6045
6072
|
}) {
|
|
6046
6073
|
const commandLabel = `$ ${command} ${args.join(" ")}`.trim();
|
|
6047
6074
|
const execute = capture ? executeCapturedCommand({ command, args, cwd, input }) : executeStreamingCommand({ command, args, cwd, input });
|
|
6048
6075
|
try {
|
|
6049
6076
|
if (capture) {
|
|
6050
|
-
return await
|
|
6077
|
+
return await load({
|
|
6051
6078
|
promise: execute,
|
|
6052
6079
|
label: "Running command",
|
|
6053
6080
|
detail: commandLabel
|
|
@@ -6131,7 +6158,7 @@ function detectProjectLanguage({
|
|
|
6131
6158
|
);
|
|
6132
6159
|
return hasTypeScript ? "typescript" : "javascript";
|
|
6133
6160
|
}
|
|
6134
|
-
async function
|
|
6161
|
+
async function initializeProject(context) {
|
|
6135
6162
|
context.packageManager = detectPackageManager(context.cwd).name;
|
|
6136
6163
|
console.log(`Using ${context.packageManager} for dependency installs.`);
|
|
6137
6164
|
const hasExistingProject = fs.existsSync(path.join(context.cwd, "package.json"));
|
|
@@ -6147,182 +6174,161 @@ async function prepareProject(context) {
|
|
|
6147
6174
|
cwd: context.cwd
|
|
6148
6175
|
});
|
|
6149
6176
|
}
|
|
6177
|
+
}
|
|
6178
|
+
async function prepareProject(context) {
|
|
6179
|
+
await initializeProject(context);
|
|
6150
6180
|
await prepareDependencies(context);
|
|
6151
6181
|
}
|
|
6152
6182
|
|
|
6153
6183
|
// src/plugins/setup/context.ts
|
|
6154
6184
|
function createWizardContext({
|
|
6155
|
-
imports
|
|
6185
|
+
imports,
|
|
6186
|
+
agent = false
|
|
6156
6187
|
}) {
|
|
6157
|
-
|
|
6188
|
+
const context = {
|
|
6158
6189
|
cwd: process.cwd(),
|
|
6190
|
+
load: agent ? ({ promise }) => promise : runWithSetupLoader,
|
|
6159
6191
|
imports,
|
|
6160
6192
|
createAnswer: () => createCliAnswer({ mode: "closed-list" }),
|
|
6161
6193
|
setupController: createSetupController(),
|
|
6162
|
-
selectStoredLoginCredentials: () => chooseStoredLoginCredentials({
|
|
6163
|
-
|
|
6194
|
+
selectStoredLoginCredentials: () => chooseStoredLoginCredentials({
|
|
6195
|
+
imports,
|
|
6196
|
+
options: {},
|
|
6197
|
+
...agent ? {
|
|
6198
|
+
prompt: async (options) => {
|
|
6199
|
+
const credentialChoices = buildCredentialsChoices(options);
|
|
6200
|
+
const choices = credentialChoices.map(({ name, value }) => ({
|
|
6201
|
+
label: name,
|
|
6202
|
+
value: value.action === "create" ? "create" : `account:${value.credentials.name}`,
|
|
6203
|
+
result: value
|
|
6204
|
+
}));
|
|
6205
|
+
const selected = await resolveSetupSelect({
|
|
6206
|
+
answer: context.createAnswer(),
|
|
6207
|
+
controller: context.setupController,
|
|
6208
|
+
message: CREDENTIALS_PICKER_QUESTION,
|
|
6209
|
+
choices
|
|
6210
|
+
});
|
|
6211
|
+
const selectedIndex = choices.findIndex(
|
|
6212
|
+
({ value }) => value === selected
|
|
6213
|
+
);
|
|
6214
|
+
return choices[selectedIndex].result;
|
|
6215
|
+
}
|
|
6216
|
+
} : {}
|
|
6217
|
+
}),
|
|
6218
|
+
authenticateNewAccount: ({ entryPoint, ...options }) => runAccountAuth({
|
|
6164
6219
|
imports,
|
|
6165
|
-
options
|
|
6220
|
+
options,
|
|
6166
6221
|
entryPoint,
|
|
6167
6222
|
storedCredentialsMode: "fresh",
|
|
6168
|
-
preserveExistingCredentials: true
|
|
6223
|
+
preserveExistingCredentials: true,
|
|
6224
|
+
useBrowserCallback: agent && options.headless === false,
|
|
6225
|
+
silent: agent && options.headless
|
|
6169
6226
|
}),
|
|
6170
6227
|
checkForUpdates,
|
|
6171
6228
|
openUrl: async (url) => {
|
|
6172
6229
|
await open__default.default(url);
|
|
6173
6230
|
},
|
|
6174
|
-
runCommand
|
|
6231
|
+
runCommand: agent ? (options) => runCommand({
|
|
6232
|
+
...options,
|
|
6233
|
+
capture: true,
|
|
6234
|
+
load: ({ promise, detail }) => {
|
|
6235
|
+
console.log(detail);
|
|
6236
|
+
return promise;
|
|
6237
|
+
}
|
|
6238
|
+
}) : runCommand,
|
|
6175
6239
|
packageManager: detectPackageManager(process.cwd()).name,
|
|
6176
6240
|
projectLanguage: "typescript"
|
|
6177
6241
|
};
|
|
6242
|
+
return context;
|
|
6243
|
+
}
|
|
6244
|
+
var SetupStepSchema = zod.z.enum([
|
|
6245
|
+
"directory",
|
|
6246
|
+
"project",
|
|
6247
|
+
"install",
|
|
6248
|
+
"sdk-update",
|
|
6249
|
+
"cli-update",
|
|
6250
|
+
"skill",
|
|
6251
|
+
"account",
|
|
6252
|
+
"account-flow",
|
|
6253
|
+
"account-environment",
|
|
6254
|
+
"authorize",
|
|
6255
|
+
"confirm-account",
|
|
6256
|
+
"connections",
|
|
6257
|
+
"slack",
|
|
6258
|
+
"slack-overwrite",
|
|
6259
|
+
"slack-existing",
|
|
6260
|
+
"slack-retry",
|
|
6261
|
+
"handoff"
|
|
6262
|
+
]);
|
|
6263
|
+
var SetupSchema = zod.z.object({
|
|
6264
|
+
agent: zod.z.boolean().optional().describe(
|
|
6265
|
+
"For AI agents and callers without a terminal: print the next setup question and the exact command to run for each answer."
|
|
6266
|
+
),
|
|
6267
|
+
step: SetupStepSchema.optional().describe(
|
|
6268
|
+
"Setup operation to inspect or execute."
|
|
6269
|
+
),
|
|
6270
|
+
nonInteractive: zod.z.boolean().optional().describe("Execute the named setup step without terminal prompts."),
|
|
6271
|
+
answer: zod.z.string().optional().describe(
|
|
6272
|
+
"User selection or input for a non-interactive setup step. Omitted confirmations use the terminal wizard's default."
|
|
6273
|
+
),
|
|
6274
|
+
flow: zod.z.enum(["login", "signup"]).optional().describe(
|
|
6275
|
+
"Account flow selected for the environment and OAuth callback steps."
|
|
6276
|
+
),
|
|
6277
|
+
language: zod.z.enum(["javascript", "typescript"]).optional().describe(
|
|
6278
|
+
"Project language for dependency installation and the Slack demo."
|
|
6279
|
+
)
|
|
6280
|
+
}).describe(
|
|
6281
|
+
"Set up the Zapier SDK in an existing or new project. Runs an interactive terminal wizard; AI agents should use --agent instead."
|
|
6282
|
+
);
|
|
6283
|
+
|
|
6284
|
+
// package.json
|
|
6285
|
+
var package_default = {
|
|
6286
|
+
version: "0.87.2"};
|
|
6287
|
+
var agentLabels = {
|
|
6288
|
+
claude: "Claude Code",
|
|
6289
|
+
codex: "Codex",
|
|
6290
|
+
cursor: "Cursor",
|
|
6291
|
+
"vscode-copilot": "VS Code Copilot"
|
|
6292
|
+
};
|
|
6293
|
+
function buildAgentPrompt({
|
|
6294
|
+
context
|
|
6295
|
+
}) {
|
|
6296
|
+
const listConnectionsCommand = formatPackageCommand(
|
|
6297
|
+
createLocalPackageCommand({
|
|
6298
|
+
packageManager: context.packageManager,
|
|
6299
|
+
binary: "zapier-sdk",
|
|
6300
|
+
args: ["list-connections", "--owner", "me", "--json"]
|
|
6301
|
+
})
|
|
6302
|
+
);
|
|
6303
|
+
const listActionsCommand = formatPackageCommand(
|
|
6304
|
+
createLocalPackageCommand({
|
|
6305
|
+
packageManager: context.packageManager,
|
|
6306
|
+
binary: "zapier-sdk",
|
|
6307
|
+
args: ["list-actions", "APP_KEY"]
|
|
6308
|
+
})
|
|
6309
|
+
);
|
|
6310
|
+
return `Start by running this command to discover my active connected apps outside of your sandbox:
|
|
6311
|
+
|
|
6312
|
+
${listConnectionsCommand}
|
|
6313
|
+
|
|
6314
|
+
Using the connected apps returned by that command:
|
|
6315
|
+
|
|
6316
|
+
- Pick 1-3 apps and show commands I can use to explore their actions, such as: ${listActionsCommand}
|
|
6317
|
+
- Do not run those list-actions commands.
|
|
6318
|
+
- Suggest 3 specific ideas based on my connected apps. Each idea should read from one app, optionally process data, and write to another.
|
|
6319
|
+
- Do not suggest event-driven workflows.
|
|
6320
|
+
- Keep each idea to one sentence. Example: "pull in-progress Jira issues and DM yourself a summary on Slack".
|
|
6321
|
+
|
|
6322
|
+
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.`;
|
|
6178
6323
|
}
|
|
6179
|
-
|
|
6180
|
-
function printAuthCommand({
|
|
6324
|
+
function printAgentPrompt({
|
|
6181
6325
|
context,
|
|
6182
|
-
|
|
6183
|
-
headless
|
|
6326
|
+
message
|
|
6184
6327
|
}) {
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
});
|
|
6190
|
-
console.log(`$ ${formatPackageCommand(command)}`);
|
|
6191
|
-
if (headless) {
|
|
6192
|
-
console.log(
|
|
6193
|
-
"Open the printed URL in another browser, then paste the final OAuth callback URL when prompted."
|
|
6194
|
-
);
|
|
6195
|
-
}
|
|
6196
|
-
}
|
|
6197
|
-
function isCredentialWriteError(error) {
|
|
6198
|
-
const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "";
|
|
6199
|
-
if (/^(eacces|eperm)$/i.test(code)) return true;
|
|
6200
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
6201
|
-
return /permission|sandbox|eacces|eperm/i.test(message);
|
|
6202
|
-
}
|
|
6203
|
-
async function confirmAuthentication(context) {
|
|
6204
|
-
const { data: profile } = await runWithSetupLoader({
|
|
6205
|
-
promise: context.imports.getProfile({}),
|
|
6206
|
-
label: "Confirming Zapier account"
|
|
6207
|
-
});
|
|
6208
|
-
context.accountEmail = profile.email;
|
|
6209
|
-
console.log(`Authenticated as ${profile.email}.`);
|
|
6210
|
-
}
|
|
6211
|
-
async function authenticate(context) {
|
|
6212
|
-
const activeProfile = await runWithSetupLoader({
|
|
6213
|
-
promise: context.imports.getProfile({}).then(({ data }) => data).catch((error) => {
|
|
6214
|
-
if (zapierSdk.isZapierAuthenticationError(error)) return void 0;
|
|
6215
|
-
throw error;
|
|
6216
|
-
}),
|
|
6217
|
-
label: "Checking Zapier authentication"
|
|
6218
|
-
});
|
|
6219
|
-
const storedCredentialsSelection = await context.selectStoredLoginCredentials();
|
|
6220
|
-
if (storedCredentialsSelection === "switch") {
|
|
6221
|
-
await confirmAuthentication(context);
|
|
6222
|
-
return;
|
|
6223
|
-
}
|
|
6224
|
-
if (storedCredentialsSelection === "none" && activeProfile) {
|
|
6225
|
-
const shouldLogout = await resolveSetupConfirm({
|
|
6226
|
-
answer: context.createAnswer(),
|
|
6227
|
-
controller: context.setupController,
|
|
6228
|
-
message: `You are already logged in as "${activeProfile.email}".
|
|
6229
|
-
Logging out will delete these credentials and may interrupt other Zapier SDK or CLI sessions using them.
|
|
6230
|
-
Log out and use a different account?`,
|
|
6231
|
-
defaultValue: false
|
|
6232
|
-
});
|
|
6233
|
-
if (!shouldLogout) {
|
|
6234
|
-
context.accountEmail = activeProfile.email;
|
|
6235
|
-
console.log(`Continuing as ${activeProfile.email}.`);
|
|
6236
|
-
return;
|
|
6237
|
-
}
|
|
6238
|
-
const logoutCommand = createLocalPackageCommand({
|
|
6239
|
-
packageManager: context.packageManager,
|
|
6240
|
-
binary: "zapier-sdk",
|
|
6241
|
-
args: ["logout"]
|
|
6242
|
-
});
|
|
6243
|
-
console.log(`$ ${formatPackageCommand(logoutCommand)}`);
|
|
6244
|
-
await context.imports.logout({});
|
|
6245
|
-
}
|
|
6246
|
-
const flow = await resolveSetupSelect({
|
|
6247
|
-
answer: context.createAnswer(),
|
|
6248
|
-
controller: context.setupController,
|
|
6249
|
-
message: "Zapier account:",
|
|
6250
|
-
choices: [
|
|
6251
|
-
{ label: "Log in to an existing account", value: "login" },
|
|
6252
|
-
{ label: "Create a new Zapier account", value: "signup" }
|
|
6253
|
-
]
|
|
6254
|
-
});
|
|
6255
|
-
const environment = await resolveSetupSelect({
|
|
6256
|
-
answer: context.createAnswer(),
|
|
6257
|
-
controller: context.setupController,
|
|
6258
|
-
message: "Environment:",
|
|
6259
|
-
choices: [
|
|
6260
|
-
{ label: "Local machine with a browser", value: "local" },
|
|
6261
|
-
{ label: "Remote or headless", value: "headless" }
|
|
6262
|
-
]
|
|
6263
|
-
});
|
|
6264
|
-
const headless = environment === "headless";
|
|
6265
|
-
printAuthCommand({ context, flow, headless });
|
|
6266
|
-
try {
|
|
6267
|
-
if (storedCredentialsSelection === "create") {
|
|
6268
|
-
await context.authenticateNewAccount({ entryPoint: flow, headless });
|
|
6269
|
-
} else {
|
|
6270
|
-
const runAuth = flow === "login" ? context.imports.login : context.imports.signup;
|
|
6271
|
-
await runAuth({ headless });
|
|
6272
|
-
}
|
|
6273
|
-
} catch (error) {
|
|
6274
|
-
if (isCredentialWriteError(error)) {
|
|
6275
|
-
console.error(
|
|
6276
|
-
"Authentication could not write credentials. A permissions or sandbox restriction may be blocking disk access."
|
|
6277
|
-
);
|
|
6278
|
-
}
|
|
6279
|
-
throw error;
|
|
6280
|
-
}
|
|
6281
|
-
await confirmAuthentication(context);
|
|
6282
|
-
}
|
|
6283
|
-
var agentLabels = {
|
|
6284
|
-
claude: "Claude Code",
|
|
6285
|
-
codex: "Codex",
|
|
6286
|
-
cursor: "Cursor",
|
|
6287
|
-
"vscode-copilot": "VS Code Copilot"
|
|
6288
|
-
};
|
|
6289
|
-
function buildAgentPrompt({ context }) {
|
|
6290
|
-
const listConnectionsCommand = formatPackageCommand(
|
|
6291
|
-
createLocalPackageCommand({
|
|
6292
|
-
packageManager: context.packageManager,
|
|
6293
|
-
binary: "zapier-sdk",
|
|
6294
|
-
args: ["list-connections", "--owner", "me", "--json"]
|
|
6295
|
-
})
|
|
6296
|
-
);
|
|
6297
|
-
const listActionsCommand = formatPackageCommand(
|
|
6298
|
-
createLocalPackageCommand({
|
|
6299
|
-
packageManager: context.packageManager,
|
|
6300
|
-
binary: "zapier-sdk",
|
|
6301
|
-
args: ["list-actions", "APP_KEY"]
|
|
6302
|
-
})
|
|
6303
|
-
);
|
|
6304
|
-
return `Start by running this command to discover my active connected apps outside of your sandbox:
|
|
6305
|
-
|
|
6306
|
-
${listConnectionsCommand}
|
|
6307
|
-
|
|
6308
|
-
Using the connected apps returned by that command:
|
|
6309
|
-
|
|
6310
|
-
- Pick 1-3 apps and show commands I can use to explore their actions, such as: ${listActionsCommand}
|
|
6311
|
-
- Do not run those list-actions commands.
|
|
6312
|
-
- Suggest 3 specific ideas based on my connected apps. Each idea should read from one app, optionally process data, and write to another.
|
|
6313
|
-
- Do not suggest event-driven workflows.
|
|
6314
|
-
- Keep each idea to one sentence. Example: "pull in-progress Jira issues and DM yourself a summary on Slack".
|
|
6315
|
-
|
|
6316
|
-
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.`;
|
|
6317
|
-
}
|
|
6318
|
-
function printAgentPrompt({
|
|
6319
|
-
context,
|
|
6320
|
-
message
|
|
6321
|
-
}) {
|
|
6322
|
-
console.log();
|
|
6323
|
-
console.log(chalk5__default.default.bgYellow.black.bold(message));
|
|
6324
|
-
console.log();
|
|
6325
|
-
console.log(buildAgentPrompt({ context }));
|
|
6328
|
+
console.log();
|
|
6329
|
+
console.log(chalk5__default.default.bgYellow.black.bold(message));
|
|
6330
|
+
console.log();
|
|
6331
|
+
console.log(buildAgentPrompt({ context }));
|
|
6326
6332
|
}
|
|
6327
6333
|
async function openAgentHandoff(context) {
|
|
6328
6334
|
const agent = await resolveSetupSelect({
|
|
@@ -6393,27 +6399,291 @@ async function openAgentHandoff(context) {
|
|
|
6393
6399
|
message: "If it didn't load correctly, paste this prompt into your agent:"
|
|
6394
6400
|
});
|
|
6395
6401
|
}
|
|
6402
|
+
|
|
6403
|
+
// src/plugins/setup/agent-output.ts
|
|
6404
|
+
var REQUIRED_STEPS = [
|
|
6405
|
+
"directory",
|
|
6406
|
+
"install"
|
|
6407
|
+
];
|
|
6408
|
+
function formatSetupCommand({
|
|
6409
|
+
context,
|
|
6410
|
+
target,
|
|
6411
|
+
answer
|
|
6412
|
+
}) {
|
|
6413
|
+
const args = [
|
|
6414
|
+
"setup",
|
|
6415
|
+
"--step",
|
|
6416
|
+
target.step,
|
|
6417
|
+
"--non-interactive",
|
|
6418
|
+
...target.flow ? ["--flow", target.flow] : [],
|
|
6419
|
+
"--language",
|
|
6420
|
+
context.projectLanguage,
|
|
6421
|
+
...answer !== void 0 ? ["--answer", answer] : []
|
|
6422
|
+
];
|
|
6423
|
+
return formatPackageCommand(
|
|
6424
|
+
SOURCE_CLI_PATH ? {
|
|
6425
|
+
command: process.execPath,
|
|
6426
|
+
args: [
|
|
6427
|
+
"--import",
|
|
6428
|
+
module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('experimental.cjs', document.baseURI).href))).resolve("tsx"),
|
|
6429
|
+
"--conditions",
|
|
6430
|
+
"source",
|
|
6431
|
+
SOURCE_CLI_PATH,
|
|
6432
|
+
...args
|
|
6433
|
+
]
|
|
6434
|
+
} : createPackageRunnerCommand({
|
|
6435
|
+
packageManager: context.packageManager,
|
|
6436
|
+
packageName: `@zapier/zapier-sdk-cli@${package_default.version}`,
|
|
6437
|
+
args
|
|
6438
|
+
})
|
|
6439
|
+
);
|
|
6440
|
+
}
|
|
6441
|
+
function printAgentStep({
|
|
6442
|
+
context,
|
|
6443
|
+
target,
|
|
6444
|
+
question
|
|
6445
|
+
}) {
|
|
6446
|
+
console.log(
|
|
6447
|
+
`Step: ${target.step}
|
|
6448
|
+
Working directory: ${context.cwd}
|
|
6449
|
+
Detected package manager: ${context.packageManager}
|
|
6450
|
+
Project language: ${context.projectLanguage}`
|
|
6451
|
+
);
|
|
6452
|
+
if (!question) {
|
|
6453
|
+
console.log(
|
|
6454
|
+
`Run this exact command:
|
|
6455
|
+
${formatSetupCommand({ context, target })}`
|
|
6456
|
+
);
|
|
6457
|
+
} else {
|
|
6458
|
+
if (target.step === "authorize" && context.authorizationUrl)
|
|
6459
|
+
console.log(
|
|
6460
|
+
`Give the user this URL to open in a browser where they can sign in to Zapier:
|
|
6461
|
+
${context.authorizationUrl}
|
|
6462
|
+
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.`
|
|
6463
|
+
);
|
|
6464
|
+
console.log(`Ask the user this question verbatim: "${question.message}"`);
|
|
6465
|
+
if (question.type === "select") {
|
|
6466
|
+
for (const { value, label } of question.choices)
|
|
6467
|
+
console.log(`${JSON.stringify(value)}: ${label}`);
|
|
6468
|
+
for (const { value } of question.choices) {
|
|
6469
|
+
const decision = value === "true" ? "agrees" : value === "false" ? "declines" : `chooses ${JSON.stringify(value)}`;
|
|
6470
|
+
if (value === "false" && REQUIRED_STEPS.includes(target.step))
|
|
6471
|
+
console.log("If the user declines, stop setup.");
|
|
6472
|
+
else
|
|
6473
|
+
console.log(
|
|
6474
|
+
`If the user ${decision}, run this exact command:
|
|
6475
|
+
${formatSetupCommand({ context, target, answer: value })}`
|
|
6476
|
+
);
|
|
6477
|
+
}
|
|
6478
|
+
} else {
|
|
6479
|
+
console.log(
|
|
6480
|
+
`Run this exact command with their answer as one shell-quoted argument (an empty answer is ''):
|
|
6481
|
+
${formatSetupCommand({ context, target, answer: "<answer>" })}`
|
|
6482
|
+
);
|
|
6483
|
+
}
|
|
6484
|
+
if (target.step === "account-environment")
|
|
6485
|
+
console.log(
|
|
6486
|
+
`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.`
|
|
6487
|
+
);
|
|
6488
|
+
console.log(
|
|
6489
|
+
"Use your tool for asking the user questions if you have one. Do not answer on the user's behalf."
|
|
6490
|
+
);
|
|
6491
|
+
}
|
|
6492
|
+
console.log(
|
|
6493
|
+
"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."
|
|
6494
|
+
);
|
|
6495
|
+
}
|
|
6496
|
+
function printAgentCompletion({
|
|
6497
|
+
context,
|
|
6498
|
+
cancelled = false
|
|
6499
|
+
}) {
|
|
6500
|
+
console.log(
|
|
6501
|
+
cancelled ? "Setup cancelled." : `Setup walkthrough finished. Report which operations succeeded, failed, or were skipped based on their command results.
|
|
6502
|
+
Learn more: https://docs.zapier.com/sdk
|
|
6503
|
+
|
|
6504
|
+
Continue in this agent. Do not open another agent or ask the user to choose one.
|
|
6505
|
+
${buildAgentPrompt({ context })}`
|
|
6506
|
+
);
|
|
6507
|
+
}
|
|
6508
|
+
|
|
6509
|
+
// src/plugins/setup/authentication.ts
|
|
6510
|
+
function printAuthCommand({
|
|
6511
|
+
context,
|
|
6512
|
+
flow,
|
|
6513
|
+
headless = false
|
|
6514
|
+
}) {
|
|
6515
|
+
const command = createLocalPackageCommand({
|
|
6516
|
+
packageManager: context.packageManager,
|
|
6517
|
+
binary: "zapier-sdk",
|
|
6518
|
+
args: [flow, ...headless ? ["--headless"] : []]
|
|
6519
|
+
});
|
|
6520
|
+
console.log(`$ ${formatPackageCommand(command)}`);
|
|
6521
|
+
if (headless) {
|
|
6522
|
+
console.log(
|
|
6523
|
+
"Open the printed URL in another browser, then paste the final OAuth callback URL when prompted."
|
|
6524
|
+
);
|
|
6525
|
+
}
|
|
6526
|
+
}
|
|
6527
|
+
function isCredentialWriteError(error) {
|
|
6528
|
+
const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "";
|
|
6529
|
+
if (/^(eacces|eperm)$/i.test(code)) return true;
|
|
6530
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6531
|
+
return /permission|sandbox|eacces|eperm/i.test(message);
|
|
6532
|
+
}
|
|
6533
|
+
async function confirmAuthentication(context) {
|
|
6534
|
+
const { data: profile } = await context.load({
|
|
6535
|
+
promise: context.imports.getProfile({}),
|
|
6536
|
+
label: "Confirming Zapier account"
|
|
6537
|
+
});
|
|
6538
|
+
context.accountEmail = profile.email;
|
|
6539
|
+
console.log(`Authenticated as ${profile.email}.`);
|
|
6540
|
+
}
|
|
6541
|
+
function selectAccountFlow(context) {
|
|
6542
|
+
return resolveSetupSelect({
|
|
6543
|
+
answer: context.createAnswer(),
|
|
6544
|
+
controller: context.setupController,
|
|
6545
|
+
message: "Zapier account:",
|
|
6546
|
+
choices: [
|
|
6547
|
+
{ label: "Log in to an existing account", value: "login" },
|
|
6548
|
+
{ label: "Create a new Zapier account", value: "signup" }
|
|
6549
|
+
]
|
|
6550
|
+
});
|
|
6551
|
+
}
|
|
6552
|
+
function selectAuthenticationEnvironment(context) {
|
|
6553
|
+
return resolveSetupSelect({
|
|
6554
|
+
answer: context.createAnswer(),
|
|
6555
|
+
controller: context.setupController,
|
|
6556
|
+
message: "Environment:",
|
|
6557
|
+
choices: [
|
|
6558
|
+
{ label: "Local machine with a browser", value: "local" },
|
|
6559
|
+
{ label: "Remote or headless", value: "headless" }
|
|
6560
|
+
]
|
|
6561
|
+
});
|
|
6562
|
+
}
|
|
6563
|
+
async function selectAccount(context) {
|
|
6564
|
+
const activeProfile = await context.load({
|
|
6565
|
+
promise: context.imports.getProfile({}).then(({ data }) => data).catch((error) => {
|
|
6566
|
+
if (zapierSdk.isZapierAuthenticationError(error)) return void 0;
|
|
6567
|
+
throw error;
|
|
6568
|
+
}),
|
|
6569
|
+
label: "Checking Zapier authentication"
|
|
6570
|
+
});
|
|
6571
|
+
const storedCredentialsSelection = await context.selectStoredLoginCredentials();
|
|
6572
|
+
if (storedCredentialsSelection === "none" && activeProfile) {
|
|
6573
|
+
const shouldLogout = await resolveSetupConfirm({
|
|
6574
|
+
answer: context.createAnswer(),
|
|
6575
|
+
controller: context.setupController,
|
|
6576
|
+
message: `You are already logged in as "${activeProfile.email}".
|
|
6577
|
+
Logging out will delete these credentials and may interrupt other Zapier SDK or CLI sessions using them.
|
|
6578
|
+
Log out and use a different account?`,
|
|
6579
|
+
defaultValue: false
|
|
6580
|
+
});
|
|
6581
|
+
if (!shouldLogout) {
|
|
6582
|
+
context.accountEmail = activeProfile.email;
|
|
6583
|
+
console.log(`Continuing as ${activeProfile.email}.`);
|
|
6584
|
+
return "continue";
|
|
6585
|
+
}
|
|
6586
|
+
printAuthCommand({ context, flow: "logout" });
|
|
6587
|
+
await context.imports.logout({});
|
|
6588
|
+
}
|
|
6589
|
+
return storedCredentialsSelection;
|
|
6590
|
+
}
|
|
6591
|
+
async function authenticate(context) {
|
|
6592
|
+
const next = await runAuthenticationStep({ context, options: {} });
|
|
6593
|
+
if (next.step === "confirm-account") await confirmAuthentication(context);
|
|
6594
|
+
}
|
|
6595
|
+
async function runAuthenticationStep({
|
|
6596
|
+
context,
|
|
6597
|
+
options
|
|
6598
|
+
}) {
|
|
6599
|
+
const { step } = options;
|
|
6600
|
+
let newAccount = step === "account-environment";
|
|
6601
|
+
if (!step || step === "account") {
|
|
6602
|
+
const selection = await selectAccount(context);
|
|
6603
|
+
if (selection === "switch") return { step: "confirm-account" };
|
|
6604
|
+
if (selection === "continue")
|
|
6605
|
+
return { step: step ? "confirm-account" : "connections" };
|
|
6606
|
+
if (step) return { step: "account-flow" };
|
|
6607
|
+
newAccount = selection === "create";
|
|
6608
|
+
}
|
|
6609
|
+
if (step === "confirm-account") {
|
|
6610
|
+
await confirmAuthentication(context);
|
|
6611
|
+
return { step: "connections" };
|
|
6612
|
+
}
|
|
6613
|
+
const flow = !step || step === "account-flow" ? await selectAccountFlow(context) : options.flow;
|
|
6614
|
+
if (step === "account-flow")
|
|
6615
|
+
return {
|
|
6616
|
+
step: "account-environment",
|
|
6617
|
+
flow
|
|
6618
|
+
};
|
|
6619
|
+
if (!flow)
|
|
6620
|
+
throw new ZapierCliValidationError(
|
|
6621
|
+
"This setup step requires --flow login or --flow signup."
|
|
6622
|
+
);
|
|
6623
|
+
let headless = true;
|
|
6624
|
+
let callbackUrl;
|
|
6625
|
+
let recoveryMessage;
|
|
6626
|
+
if (step === "authorize") {
|
|
6627
|
+
recoveryMessage = `Generate a fresh authorization URL with \`${formatSetupCommand(
|
|
6628
|
+
{
|
|
6629
|
+
context,
|
|
6630
|
+
target: { step: "account-environment", flow },
|
|
6631
|
+
answer: "headless"
|
|
6632
|
+
}
|
|
6633
|
+
)}\`.`;
|
|
6634
|
+
const pending = getPendingOauthFlow({ entryPoint: flow, recoveryMessage });
|
|
6635
|
+
context.authorizationUrl = pending.transaction.browserAuthUrl;
|
|
6636
|
+
callbackUrl = await resolveSetupInput({
|
|
6637
|
+
answer: context.createAnswer(),
|
|
6638
|
+
controller: context.setupController,
|
|
6639
|
+
message: OAUTH_CALLBACK_QUESTION
|
|
6640
|
+
});
|
|
6641
|
+
} else {
|
|
6642
|
+
headless = await selectAuthenticationEnvironment(context) === "headless";
|
|
6643
|
+
if (!step) printAuthCommand({ context, flow, headless });
|
|
6644
|
+
}
|
|
6645
|
+
const authOptions = {
|
|
6646
|
+
headless,
|
|
6647
|
+
...step ? { nonInteractive: true } : {},
|
|
6648
|
+
...callbackUrl !== void 0 ? { callbackUrl } : {}
|
|
6649
|
+
};
|
|
6650
|
+
try {
|
|
6651
|
+
if (newAccount) {
|
|
6652
|
+
await context.authenticateNewAccount({
|
|
6653
|
+
entryPoint: flow,
|
|
6654
|
+
...authOptions
|
|
6655
|
+
});
|
|
6656
|
+
} else {
|
|
6657
|
+
await context.imports[flow](authOptions);
|
|
6658
|
+
}
|
|
6659
|
+
} catch (error) {
|
|
6660
|
+
if (recoveryMessage) console.error(recoveryMessage);
|
|
6661
|
+
if (isCredentialWriteError(error)) {
|
|
6662
|
+
console.error(
|
|
6663
|
+
"Authentication could not write credentials. A permissions or sandbox restriction may be blocking disk access."
|
|
6664
|
+
);
|
|
6665
|
+
}
|
|
6666
|
+
throw error;
|
|
6667
|
+
}
|
|
6668
|
+
return step === "account-environment" && headless ? { step: "authorize", flow } : { step: "confirm-account" };
|
|
6669
|
+
}
|
|
6396
6670
|
var CONNECTIONS_URL = "https://zapier.com/app/assets/connections";
|
|
6397
6671
|
var CONNECTION_DISPLAY_LIMIT = 10;
|
|
6398
|
-
async function
|
|
6399
|
-
const page = await
|
|
6672
|
+
async function showActiveConnections(context) {
|
|
6673
|
+
const page = await context.load({
|
|
6400
6674
|
promise: context.imports.listConnections({
|
|
6401
6675
|
owner: "me",
|
|
6402
6676
|
maxItems: CONNECTION_DISPLAY_LIMIT
|
|
6403
6677
|
}),
|
|
6404
6678
|
label: "Loading app connections"
|
|
6405
6679
|
});
|
|
6406
|
-
if (page.data.length === 0)
|
|
6407
|
-
console.log(
|
|
6408
|
-
`No active connections found. Connect or reconnect an app at ${CONNECTIONS_URL}, then come back and run setup again.`
|
|
6409
|
-
);
|
|
6410
|
-
throw new ZapierCliExitError(
|
|
6411
|
-
"Setup stopped before completion because no active connections are available."
|
|
6412
|
-
);
|
|
6413
|
-
}
|
|
6680
|
+
if (page.data.length === 0) return false;
|
|
6414
6681
|
const table = new Table__default.default({
|
|
6415
6682
|
head: ["App", "Connection"],
|
|
6416
|
-
style: {
|
|
6683
|
+
style: {
|
|
6684
|
+
compact: true,
|
|
6685
|
+
...process.stdout.isTTY ? {} : { head: [], border: [] }
|
|
6686
|
+
}
|
|
6417
6687
|
});
|
|
6418
6688
|
table.push(
|
|
6419
6689
|
...page.data.map((connection) => [
|
|
@@ -6425,11 +6695,22 @@ async function ensureConnectionsAvailable(context) {
|
|
|
6425
6695
|
`Active Zapier connections (showing up to ${CONNECTION_DISPLAY_LIMIT}):`
|
|
6426
6696
|
);
|
|
6427
6697
|
console.log(table.toString());
|
|
6698
|
+
return true;
|
|
6699
|
+
}
|
|
6700
|
+
async function ensureConnectionsAvailable(context) {
|
|
6701
|
+
if (await showActiveConnections(context)) return;
|
|
6702
|
+
console.log(
|
|
6703
|
+
`No active connections found. Connect or reconnect an app at ${CONNECTIONS_URL}, then come back and run setup again.`
|
|
6704
|
+
);
|
|
6705
|
+
throw new ZapierCliExitError(
|
|
6706
|
+
"Setup stopped before completion because no active connections are available."
|
|
6707
|
+
);
|
|
6428
6708
|
}
|
|
6429
6709
|
var CONNECTION_PLACEHOLDER = "__ZAPIER_SDK_SLACK_CONNECTION__";
|
|
6430
6710
|
var EMAIL_PLACEHOLDER = "__ZAPIER_SDK_ACCOUNT_EMAIL__";
|
|
6431
6711
|
var APP_PLACEHOLDER = "__ZAPIER_SDK_SLACK_APP__";
|
|
6432
6712
|
var SLACK_SLUG = "slack";
|
|
6713
|
+
var SLACK_RETRY_QUESTION = "Slack email for one retry after the failed test:";
|
|
6433
6714
|
function getSlackTestPath(context) {
|
|
6434
6715
|
const extension = context.projectLanguage === "typescript" ? "ts" : "mjs";
|
|
6435
6716
|
return path.join("src", "sdk-demo", `zapier-slack-test.${extension}`);
|
|
@@ -6439,7 +6720,7 @@ function getSlackTestTemplatePath(context) {
|
|
|
6439
6720
|
return path.join(TEMPLATES_DIR, "setup", `zapier-slack-test.${extension}`);
|
|
6440
6721
|
}
|
|
6441
6722
|
async function findSlackConnection(context) {
|
|
6442
|
-
const page = await
|
|
6723
|
+
const page = await context.load({
|
|
6443
6724
|
promise: context.imports.listConnections({
|
|
6444
6725
|
owner: "me",
|
|
6445
6726
|
app: SLACK_SLUG,
|
|
@@ -6460,17 +6741,22 @@ function renderSlackTest({
|
|
|
6460
6741
|
}) {
|
|
6461
6742
|
return fs.readFileSync(getSlackTestTemplatePath(context), "utf8").replace(APP_PLACEHOLDER, () => toTemplateString(app)).replace(CONNECTION_PLACEHOLDER, () => toTemplateString(connection)).replace(EMAIL_PLACEHOLDER, () => toTemplateString(email));
|
|
6462
6743
|
}
|
|
6463
|
-
function
|
|
6744
|
+
async function createAndRunSlackTest({
|
|
6464
6745
|
context,
|
|
6465
|
-
app,
|
|
6466
6746
|
connection,
|
|
6467
|
-
email
|
|
6747
|
+
email,
|
|
6748
|
+
overwrite = true
|
|
6468
6749
|
}) {
|
|
6469
6750
|
const slackTestPath = getSlackTestPath(context);
|
|
6470
6751
|
const path2 = path.join(context.cwd, slackTestPath);
|
|
6471
6752
|
if (!fs.existsSync(path.dirname(path2))) fs.mkdirSync(path.dirname(path2), { recursive: true });
|
|
6472
|
-
fs.writeFileSync(
|
|
6753
|
+
fs.writeFileSync(
|
|
6754
|
+
path2,
|
|
6755
|
+
renderSlackTest({ context, app: SLACK_SLUG, connection, email }),
|
|
6756
|
+
{ flag: overwrite ? "w" : "wx" }
|
|
6757
|
+
);
|
|
6473
6758
|
console.log(`Created ${slackTestPath}.`);
|
|
6759
|
+
return trySlackTest(context);
|
|
6474
6760
|
}
|
|
6475
6761
|
async function executeSlackTest(context) {
|
|
6476
6762
|
const slackTestPath = getSlackTestPath(context);
|
|
@@ -6498,75 +6784,76 @@ async function executeSlackTest(context) {
|
|
|
6498
6784
|
async function trySlackTest(context) {
|
|
6499
6785
|
try {
|
|
6500
6786
|
await executeSlackTest(context);
|
|
6787
|
+
(context.outcomes ?? (context.outcomes = {})).slack = "succeeded";
|
|
6501
6788
|
return true;
|
|
6502
6789
|
} catch (error) {
|
|
6790
|
+
(context.outcomes ?? (context.outcomes = {})).slack = "failed";
|
|
6503
6791
|
const message = error instanceof Error ? error.message : String(error);
|
|
6504
6792
|
console.warn(`Slack demo failed: ${message}. Setup will continue.`);
|
|
6505
6793
|
return false;
|
|
6506
6794
|
}
|
|
6507
6795
|
}
|
|
6508
|
-
async function
|
|
6796
|
+
async function runSlackStep({
|
|
6797
|
+
context,
|
|
6798
|
+
step,
|
|
6799
|
+
connection
|
|
6800
|
+
}) {
|
|
6509
6801
|
if (!context.accountEmail) {
|
|
6510
6802
|
console.log("No account email found; skipping the Slack demo.");
|
|
6511
|
-
return;
|
|
6803
|
+
return "handoff";
|
|
6512
6804
|
}
|
|
6513
|
-
|
|
6514
|
-
if (!slackConnection) {
|
|
6805
|
+
if (!connection) {
|
|
6515
6806
|
console.log("No active Slack connection found; skipping the Slack demo.");
|
|
6516
|
-
return;
|
|
6807
|
+
return "handoff";
|
|
6517
6808
|
}
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
answer: context.createAnswer(),
|
|
6521
|
-
controller: context.setupController,
|
|
6522
|
-
message: `Run the Slack self-DM test using ${context.accountEmail}?`,
|
|
6523
|
-
defaultValue: true
|
|
6524
|
-
});
|
|
6525
|
-
if (!shouldRun) return;
|
|
6526
|
-
const path2 = path.join(context.cwd, slackTestPath);
|
|
6527
|
-
if (fs.existsSync(path2)) {
|
|
6528
|
-
const shouldOverwrite = await resolveSetupConfirm({
|
|
6809
|
+
if (step === "slack-retry") {
|
|
6810
|
+
const email = await resolveSetupInput({
|
|
6529
6811
|
answer: context.createAnswer(),
|
|
6530
6812
|
controller: context.setupController,
|
|
6531
|
-
message:
|
|
6532
|
-
defaultValue: false
|
|
6813
|
+
message: SLACK_RETRY_QUESTION
|
|
6533
6814
|
});
|
|
6534
|
-
if (
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
message: `Run the existing ${slackTestPath}?`,
|
|
6540
|
-
defaultValue: false
|
|
6815
|
+
if (email)
|
|
6816
|
+
await createAndRunSlackTest({
|
|
6817
|
+
context,
|
|
6818
|
+
connection: connection.id,
|
|
6819
|
+
email
|
|
6541
6820
|
});
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
}
|
|
6821
|
+
else console.log("Skipping the Slack test.");
|
|
6822
|
+
return "handoff";
|
|
6545
6823
|
}
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
context,
|
|
6549
|
-
app: SLACK_SLUG,
|
|
6550
|
-
connection: slackConnection.id,
|
|
6551
|
-
email
|
|
6552
|
-
});
|
|
6553
|
-
if (await trySlackTest(context)) return;
|
|
6554
|
-
email = await resolveSetupInput({
|
|
6824
|
+
const slackTestPath = getSlackTestPath(context);
|
|
6825
|
+
const shouldRun = await resolveSetupConfirm({
|
|
6555
6826
|
answer: context.createAnswer(),
|
|
6556
6827
|
controller: context.setupController,
|
|
6557
|
-
message: "Slack
|
|
6828
|
+
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}?`,
|
|
6829
|
+
defaultValue: step === "slack"
|
|
6558
6830
|
});
|
|
6559
|
-
if (!
|
|
6560
|
-
|
|
6561
|
-
|
|
6831
|
+
if (!shouldRun) {
|
|
6832
|
+
if (step === "slack-overwrite") {
|
|
6833
|
+
console.log("Keeping the existing Slack test file.");
|
|
6834
|
+
return "slack-existing";
|
|
6835
|
+
}
|
|
6836
|
+
return "handoff";
|
|
6837
|
+
}
|
|
6838
|
+
if (step === "slack" && fs.existsSync(path.join(context.cwd, slackTestPath)))
|
|
6839
|
+
return "slack-overwrite";
|
|
6840
|
+
if (step === "slack-existing") {
|
|
6841
|
+
await trySlackTest(context);
|
|
6842
|
+
return "handoff";
|
|
6562
6843
|
}
|
|
6563
|
-
|
|
6844
|
+
const succeeded = await createAndRunSlackTest({
|
|
6564
6845
|
context,
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6846
|
+
connection: connection.id,
|
|
6847
|
+
email: context.accountEmail,
|
|
6848
|
+
overwrite: step === "slack-overwrite"
|
|
6568
6849
|
});
|
|
6569
|
-
|
|
6850
|
+
return succeeded ? "handoff" : "slack-retry";
|
|
6851
|
+
}
|
|
6852
|
+
async function offerSlackTest(context) {
|
|
6853
|
+
const connection = context.accountEmail ? await findSlackConnection(context) : void 0;
|
|
6854
|
+
let step = "slack";
|
|
6855
|
+
while (step !== "handoff")
|
|
6856
|
+
step = await runSlackStep({ context, step, connection });
|
|
6570
6857
|
}
|
|
6571
6858
|
|
|
6572
6859
|
// src/plugins/setup/skill.ts
|
|
@@ -6592,7 +6879,9 @@ async function installOptionalSkill(context) {
|
|
|
6592
6879
|
cwd: context.cwd,
|
|
6593
6880
|
capture: true
|
|
6594
6881
|
});
|
|
6882
|
+
(context.outcomes ?? (context.outcomes = {})).skill = "succeeded";
|
|
6595
6883
|
} catch {
|
|
6884
|
+
(context.outcomes ?? (context.outcomes = {})).skill = "failed";
|
|
6596
6885
|
console.warn(
|
|
6597
6886
|
`Could not install the optional Zapier SDK skill. To install it manually, run: ${formatPackageCommand(command)}`
|
|
6598
6887
|
);
|
|
@@ -6649,6 +6938,177 @@ async function runWizard(context) {
|
|
|
6649
6938
|
console.log(chalk5__default.default.bgCyan.black.bold(" Next steps "));
|
|
6650
6939
|
await openAgentHandoff(context);
|
|
6651
6940
|
}
|
|
6941
|
+
var UNPROMPTED_STEPS = [
|
|
6942
|
+
"project",
|
|
6943
|
+
"confirm-account",
|
|
6944
|
+
"connections"
|
|
6945
|
+
];
|
|
6946
|
+
var ZapierSetupQuestionSignal = class extends zapierSdk.ZapierSignal {
|
|
6947
|
+
constructor(question) {
|
|
6948
|
+
super(question.message);
|
|
6949
|
+
this.question = question;
|
|
6950
|
+
this.name = "ZapierSetupQuestionSignal";
|
|
6951
|
+
this.code = "ZAPIER_SETUP_QUESTION";
|
|
6952
|
+
}
|
|
6953
|
+
};
|
|
6954
|
+
function isZapierSetupQuestionSignal(error) {
|
|
6955
|
+
return zapierSdk.isZapierSignal(error) && error.code === "ZAPIER_SETUP_QUESTION";
|
|
6956
|
+
}
|
|
6957
|
+
function createSetupAnswer({
|
|
6958
|
+
answer,
|
|
6959
|
+
execute
|
|
6960
|
+
}) {
|
|
6961
|
+
let answered = false;
|
|
6962
|
+
return async ({ result: { question } }) => {
|
|
6963
|
+
if (question.type === "collection")
|
|
6964
|
+
throw new ZapierCliValidationError(
|
|
6965
|
+
"Setup expects a selection or text input."
|
|
6966
|
+
);
|
|
6967
|
+
if (!execute) throw new ZapierSetupQuestionSignal(question);
|
|
6968
|
+
if (answered)
|
|
6969
|
+
throw new ZapierCliValidationError(
|
|
6970
|
+
"Each setup step can answer only one question. Inspect the next question with --agent and run it in a separate command."
|
|
6971
|
+
);
|
|
6972
|
+
answered = true;
|
|
6973
|
+
const confirmation = question.type === "select" && question.choices.some(({ value }) => value === "true") && question.choices.some(({ value }) => value === "false");
|
|
6974
|
+
if (answer === void 0 && !confirmation)
|
|
6975
|
+
throw new ZapierCliValidationError(
|
|
6976
|
+
"This setup step requires --answer. Inspect it with --agent and pass the user's selection or input."
|
|
6977
|
+
);
|
|
6978
|
+
if (question.type === "input")
|
|
6979
|
+
return { type: "custom", value: answer?.trim() ?? "" };
|
|
6980
|
+
const selected = answer?.trim() ?? question.choices[0].value;
|
|
6981
|
+
if (!question.choices.some(({ value }) => value === selected))
|
|
6982
|
+
throw new ZapierCliValidationError(
|
|
6983
|
+
`Answer must be one of: ${question.choices.map(({ value }) => value).join(", ")}.`
|
|
6984
|
+
);
|
|
6985
|
+
return { type: "choose", value: selected };
|
|
6986
|
+
};
|
|
6987
|
+
}
|
|
6988
|
+
async function runSetupStep({
|
|
6989
|
+
context,
|
|
6990
|
+
target
|
|
6991
|
+
}) {
|
|
6992
|
+
switch (target.step) {
|
|
6993
|
+
case "directory":
|
|
6994
|
+
await chooseDirectory(context);
|
|
6995
|
+
return { step: "project" };
|
|
6996
|
+
case "project":
|
|
6997
|
+
await ensureSupportedNode(context);
|
|
6998
|
+
await initializeProject(context);
|
|
6999
|
+
return { step: "install" };
|
|
7000
|
+
case "install":
|
|
7001
|
+
await offerMissingPackageInstall({
|
|
7002
|
+
context,
|
|
7003
|
+
packages: getPackageStates(context).filter(({ declared }) => !declared)
|
|
7004
|
+
});
|
|
7005
|
+
return { step: "sdk-update" };
|
|
7006
|
+
case "sdk-update":
|
|
7007
|
+
case "cli-update": {
|
|
7008
|
+
const name = target.step === "sdk-update" ? "@zapier/zapier-sdk" : "@zapier/zapier-sdk-cli";
|
|
7009
|
+
const packageState = getPackageStates(context).find(
|
|
7010
|
+
({ dependency }) => dependency.name === name
|
|
7011
|
+
);
|
|
7012
|
+
if (packageState) await offerPackageUpdate({ context, packageState });
|
|
7013
|
+
return { step: target.step === "sdk-update" ? "cli-update" : "skill" };
|
|
7014
|
+
}
|
|
7015
|
+
case "skill":
|
|
7016
|
+
await installOptionalSkill(context);
|
|
7017
|
+
return { step: "account" };
|
|
7018
|
+
case "account":
|
|
7019
|
+
case "account-flow":
|
|
7020
|
+
case "account-environment":
|
|
7021
|
+
case "authorize":
|
|
7022
|
+
case "confirm-account":
|
|
7023
|
+
return runAuthenticationStep({ context, options: target });
|
|
7024
|
+
case "connections":
|
|
7025
|
+
if (!await showActiveConnections(context)) {
|
|
7026
|
+
console.log(
|
|
7027
|
+
`No active connections found. Ask the user to connect or reconnect an app at ${CONNECTIONS_URL}. After they confirm, run this exact command:
|
|
7028
|
+
${formatSetupCommand({ context, target })}
|
|
7029
|
+
Success means it prints the active connections table.`
|
|
7030
|
+
);
|
|
7031
|
+
throw new ZapierCliExitError(
|
|
7032
|
+
"Setup stopped until an app connection is active."
|
|
7033
|
+
);
|
|
7034
|
+
}
|
|
7035
|
+
console.log(
|
|
7036
|
+
"Show the user every app and connection title in the table above before continuing. Do not just report that connections were found."
|
|
7037
|
+
);
|
|
7038
|
+
return { step: "slack" };
|
|
7039
|
+
case "slack":
|
|
7040
|
+
case "slack-overwrite":
|
|
7041
|
+
case "slack-existing":
|
|
7042
|
+
case "slack-retry": {
|
|
7043
|
+
const { data: profile } = await context.imports.getProfile({});
|
|
7044
|
+
context.accountEmail = profile.email;
|
|
7045
|
+
return {
|
|
7046
|
+
step: await runSlackStep({
|
|
7047
|
+
context,
|
|
7048
|
+
step: target.step,
|
|
7049
|
+
connection: await findSlackConnection(context)
|
|
7050
|
+
})
|
|
7051
|
+
};
|
|
7052
|
+
}
|
|
7053
|
+
}
|
|
7054
|
+
}
|
|
7055
|
+
async function runAgentSetup({
|
|
7056
|
+
context,
|
|
7057
|
+
options
|
|
7058
|
+
}) {
|
|
7059
|
+
if (options.agent && options.nonInteractive)
|
|
7060
|
+
throw new ZapierCliValidationError(
|
|
7061
|
+
"Use --agent to inspect a step or --non-interactive to execute it, not both."
|
|
7062
|
+
);
|
|
7063
|
+
if (!options.agent && !options.nonInteractive)
|
|
7064
|
+
throw new ZapierCliValidationError(
|
|
7065
|
+
options.step ? "Use --agent to inspect the named step or --non-interactive to execute it." : "--answer, --flow, and --language require a setup step."
|
|
7066
|
+
);
|
|
7067
|
+
if (options.nonInteractive && !options.step)
|
|
7068
|
+
throw new ZapierCliValidationError(
|
|
7069
|
+
"--non-interactive requires --step. Start with setup --agent and follow its printed commands."
|
|
7070
|
+
);
|
|
7071
|
+
if (options.answer !== void 0 && !options.nonInteractive)
|
|
7072
|
+
throw new ZapierCliValidationError("--answer requires --non-interactive.");
|
|
7073
|
+
context.cwd = fs.realpathSync(context.cwd);
|
|
7074
|
+
context.projectLanguage = options.language ?? detectProjectLanguage({
|
|
7075
|
+
cwd: context.cwd,
|
|
7076
|
+
hasExistingProject: fs.existsSync(path.join(context.cwd, "package.json"))
|
|
7077
|
+
});
|
|
7078
|
+
let target = {
|
|
7079
|
+
step: options.step ?? "directory",
|
|
7080
|
+
flow: options.flow
|
|
7081
|
+
};
|
|
7082
|
+
let execute = options.nonInteractive === true;
|
|
7083
|
+
while (true) {
|
|
7084
|
+
const { step, flow } = target;
|
|
7085
|
+
if (step === "handoff") return printAgentCompletion({ context });
|
|
7086
|
+
if (!execute && UNPROMPTED_STEPS.includes(step))
|
|
7087
|
+
return printAgentStep({ context, target });
|
|
7088
|
+
const answer = createSetupAnswer({
|
|
7089
|
+
answer: execute ? options.answer : void 0,
|
|
7090
|
+
execute
|
|
7091
|
+
});
|
|
7092
|
+
context.createAnswer = () => answer;
|
|
7093
|
+
try {
|
|
7094
|
+
const next = await runSetupStep({ context, target: { step, flow } });
|
|
7095
|
+
if (options.language) context.projectLanguage = options.language;
|
|
7096
|
+
if (execute)
|
|
7097
|
+
for (const [operation, outcome] of Object.entries(
|
|
7098
|
+
context.outcomes ?? {}
|
|
7099
|
+
))
|
|
7100
|
+
console.log(`${operation}: ${outcome}`);
|
|
7101
|
+
target = next;
|
|
7102
|
+
execute = false;
|
|
7103
|
+
} catch (error) {
|
|
7104
|
+
if (isZapierSetupQuestionSignal(error))
|
|
7105
|
+
return printAgentStep({ context, target, question: error.question });
|
|
7106
|
+
if (error instanceof ZapierCliUserCancellationError)
|
|
7107
|
+
return printAgentCompletion({ context, cancelled: true });
|
|
7108
|
+
throw error;
|
|
7109
|
+
}
|
|
7110
|
+
}
|
|
7111
|
+
}
|
|
6652
7112
|
|
|
6653
7113
|
// src/plugins/setup/index.ts
|
|
6654
7114
|
var getProfileRef = zapierSdk.declareMethod({ id: "getProfile" });
|
|
@@ -6673,10 +7133,19 @@ var setupPlugin = zapierSdk.defineMethod({
|
|
|
6673
7133
|
supportsJsonOutput: false,
|
|
6674
7134
|
inputSchema: SetupSchema,
|
|
6675
7135
|
output: "raw",
|
|
6676
|
-
run: async ({ imports }) => {
|
|
7136
|
+
run: async ({ imports, input }) => {
|
|
7137
|
+
if (input.agent || input.nonInteractive || [input.step, input.answer, input.flow, input.language].some(
|
|
7138
|
+
(value) => value !== void 0
|
|
7139
|
+
)) {
|
|
7140
|
+
await runAgentSetup({
|
|
7141
|
+
context: createWizardContext({ imports, agent: true }),
|
|
7142
|
+
options: input
|
|
7143
|
+
});
|
|
7144
|
+
return;
|
|
7145
|
+
}
|
|
6677
7146
|
if (process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
|
|
6678
|
-
throw new
|
|
6679
|
-
"`zapier-sdk setup` requires an interactive terminal."
|
|
7147
|
+
throw new ZapierCliValidationError(
|
|
7148
|
+
"`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."
|
|
6680
7149
|
);
|
|
6681
7150
|
}
|
|
6682
7151
|
await runWizard(createWizardContext({ imports }));
|
|
@@ -7171,59 +7640,6 @@ var watchTriggerInboxCliPlugin = zapierSdk.defineMethod({
|
|
|
7171
7640
|
return doWatch();
|
|
7172
7641
|
}
|
|
7173
7642
|
});
|
|
7174
|
-
var createWorkflowRef = experimental.declareMethod({ id: "createWorkflow" });
|
|
7175
|
-
function createPublicInputSchema(schema) {
|
|
7176
|
-
const publicSchema = zod.z.object(
|
|
7177
|
-
Object.fromEntries(
|
|
7178
|
-
Object.entries(schema.shape).filter(
|
|
7179
|
-
([name]) => !experimental.INTERNAL_CREATE_WORKFLOW_FIELDS.includes(
|
|
7180
|
-
name
|
|
7181
|
-
)
|
|
7182
|
-
)
|
|
7183
|
-
)
|
|
7184
|
-
);
|
|
7185
|
-
return schema.description === void 0 ? publicSchema : publicSchema.describe(schema.description);
|
|
7186
|
-
}
|
|
7187
|
-
var CreateWorkflowCliOptionsSchema = createPublicInputSchema(
|
|
7188
|
-
experimental.CreateWorkflowOptionsSchema
|
|
7189
|
-
);
|
|
7190
|
-
var createWorkflowCliPlugin = experimental.defineMethod({
|
|
7191
|
-
namespace: "cli",
|
|
7192
|
-
name: "createWorkflow",
|
|
7193
|
-
imports: [createWorkflowRef],
|
|
7194
|
-
type: "create",
|
|
7195
|
-
itemType: "Workflow",
|
|
7196
|
-
categories: ["code-workflow"],
|
|
7197
|
-
stability: "experimental",
|
|
7198
|
-
inputSchema: CreateWorkflowCliOptionsSchema,
|
|
7199
|
-
outputSchema: experimental.CreateWorkflowResponseSchema,
|
|
7200
|
-
skipOutputValidation: true,
|
|
7201
|
-
output: "raw",
|
|
7202
|
-
run: ({ imports, input }) => imports.createWorkflow({
|
|
7203
|
-
...input,
|
|
7204
|
-
creationHarness: experimental.getAgent(),
|
|
7205
|
-
creationAccessMethod: "sdk_cli"
|
|
7206
|
-
})
|
|
7207
|
-
});
|
|
7208
|
-
var importWorkflowRef = experimental.declareMethod({ id: "importWorkflow" });
|
|
7209
|
-
var importWorkflowCliPlugin = experimental.defineMethod({
|
|
7210
|
-
namespace: "cli",
|
|
7211
|
-
name: "importWorkflow",
|
|
7212
|
-
imports: [importWorkflowRef],
|
|
7213
|
-
type: "create",
|
|
7214
|
-
itemType: "Workflow",
|
|
7215
|
-
categories: ["code-workflow"],
|
|
7216
|
-
stability: "experimental",
|
|
7217
|
-
inputSchema: createPublicInputSchema(experimental.ImportWorkflowOptionsSchema),
|
|
7218
|
-
outputSchema: experimental.ImportWorkflowResponseSchema,
|
|
7219
|
-
skipOutputValidation: true,
|
|
7220
|
-
output: "raw",
|
|
7221
|
-
run: ({ imports, input }) => imports.importWorkflow({
|
|
7222
|
-
...input,
|
|
7223
|
-
creationHarness: experimental.getAgent(),
|
|
7224
|
-
creationAccessMethod: "sdk_cli"
|
|
7225
|
-
})
|
|
7226
|
-
});
|
|
7227
7643
|
function warningBlock({
|
|
7228
7644
|
banner,
|
|
7229
7645
|
message,
|
|
@@ -7249,9 +7665,9 @@ function collectDeprecationNoticeAndForward(event, onEvent) {
|
|
|
7249
7665
|
}
|
|
7250
7666
|
|
|
7251
7667
|
// package.json with { type: 'json' }
|
|
7252
|
-
var
|
|
7668
|
+
var package_default2 = {
|
|
7253
7669
|
name: "@zapier/zapier-sdk-cli",
|
|
7254
|
-
version: "0.
|
|
7670
|
+
version: "0.87.2"};
|
|
7255
7671
|
|
|
7256
7672
|
// src/sdk.ts
|
|
7257
7673
|
var warnedDeprecatedMethods = /* @__PURE__ */ new Set();
|
|
@@ -7320,7 +7736,7 @@ function createZapierCliSdk(options = {}) {
|
|
|
7320
7736
|
const stackOptions = {
|
|
7321
7737
|
...sdkOptions,
|
|
7322
7738
|
eventEmission: { ...sdkOptions.eventEmission, callContext: "cli" },
|
|
7323
|
-
callerPackage: { name:
|
|
7739
|
+
callerPackage: { name: package_default2.name, version: package_default2.version },
|
|
7324
7740
|
// Collected for the boxed stderr warning rendered in the exit path. The
|
|
7325
7741
|
// box is additive: the SDK's own inline warn still fires, so the notice
|
|
7326
7742
|
// cannot be hidden by any rendering path.
|
|
@@ -7332,14 +7748,10 @@ function createZapierCliSdk(options = {}) {
|
|
|
7332
7748
|
exports: [
|
|
7333
7749
|
experimental.omitExports(experimental.zapierExperimentalSdkPlugin, [
|
|
7334
7750
|
"drainTriggerInbox",
|
|
7335
|
-
"watchTriggerInbox"
|
|
7336
|
-
"createWorkflow",
|
|
7337
|
-
"importWorkflow"
|
|
7751
|
+
"watchTriggerInbox"
|
|
7338
7752
|
]),
|
|
7339
7753
|
drainTriggerInboxCliPlugin,
|
|
7340
7754
|
watchTriggerInboxCliPlugin,
|
|
7341
|
-
createWorkflowCliPlugin,
|
|
7342
|
-
importWorkflowCliPlugin,
|
|
7343
7755
|
loginPlugin,
|
|
7344
7756
|
signupPlugin,
|
|
7345
7757
|
logoutPlugin,
|