@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/index.cjs
CHANGED
|
@@ -30,6 +30,7 @@ var packageJsonLib = require('package-json');
|
|
|
30
30
|
var semver = require('semver');
|
|
31
31
|
var crossSpawn = require('cross-spawn');
|
|
32
32
|
var wrapAnsi = require('wrap-ansi');
|
|
33
|
+
var module$1 = require('module');
|
|
33
34
|
var Table = require('cli-table3');
|
|
34
35
|
var experimental = require('@zapier/zapier-sdk/experimental');
|
|
35
36
|
require('commander');
|
|
@@ -1052,6 +1053,7 @@ var SENSITIVE_FLAGS = [
|
|
|
1052
1053
|
"--credentials-client-id",
|
|
1053
1054
|
"--credentials-base-url",
|
|
1054
1055
|
"--callback-url",
|
|
1056
|
+
"--answer",
|
|
1055
1057
|
"--user",
|
|
1056
1058
|
"--header",
|
|
1057
1059
|
"-H",
|
|
@@ -1288,6 +1290,7 @@ var searchSelect = core.createPrompt(
|
|
|
1288
1290
|
);
|
|
1289
1291
|
|
|
1290
1292
|
// src/utils/auth/credentials-picker.ts
|
|
1293
|
+
var CREDENTIALS_PICKER_QUESTION = "Select credentials or add a new account:";
|
|
1291
1294
|
function isSameCredentials(left, right) {
|
|
1292
1295
|
return left.name === right.name && left.baseUrl === right.baseUrl;
|
|
1293
1296
|
}
|
|
@@ -1393,7 +1396,7 @@ async function promptForCredentials({
|
|
|
1393
1396
|
activeCredentials
|
|
1394
1397
|
}) {
|
|
1395
1398
|
return searchSelect({
|
|
1396
|
-
message:
|
|
1399
|
+
message: CREDENTIALS_PICKER_QUESTION,
|
|
1397
1400
|
source: (term) => buildCredentialsChoices({
|
|
1398
1401
|
credentials,
|
|
1399
1402
|
activeCredentials,
|
|
@@ -1456,14 +1459,15 @@ async function switchCredentials({
|
|
|
1456
1459
|
async function chooseStoredLoginCredentialsAtBaseUrl({
|
|
1457
1460
|
baseUrl,
|
|
1458
1461
|
options,
|
|
1459
|
-
resolvedCredentials
|
|
1462
|
+
resolvedCredentials,
|
|
1463
|
+
prompt = promptForCredentials
|
|
1460
1464
|
}) {
|
|
1461
1465
|
if (resolvedCredentials !== void 0 || authFlowOnlyOptions(options).length > 0) {
|
|
1462
1466
|
return "none";
|
|
1463
1467
|
}
|
|
1464
1468
|
const storedCredentials = listStoredCredentials({ baseUrl });
|
|
1465
1469
|
if (storedCredentials.length === 0) return "none";
|
|
1466
|
-
const selection = await
|
|
1470
|
+
const selection = await prompt({
|
|
1467
1471
|
credentials: storedCredentials,
|
|
1468
1472
|
activeCredentials: getActiveCredentials({ baseUrl })
|
|
1469
1473
|
});
|
|
@@ -1477,7 +1481,8 @@ async function chooseStoredLoginCredentialsAtBaseUrl({
|
|
|
1477
1481
|
}
|
|
1478
1482
|
async function chooseStoredLoginCredentials({
|
|
1479
1483
|
imports,
|
|
1480
|
-
options
|
|
1484
|
+
options,
|
|
1485
|
+
prompt
|
|
1481
1486
|
}) {
|
|
1482
1487
|
const resolvedCredentials = await imports.resolveCredentials();
|
|
1483
1488
|
const credentialsBaseUrl = await resolveCredentialsBaseUrl({
|
|
@@ -1487,7 +1492,8 @@ async function chooseStoredLoginCredentials({
|
|
|
1487
1492
|
return chooseStoredLoginCredentialsAtBaseUrl({
|
|
1488
1493
|
baseUrl: credentialsBaseUrl,
|
|
1489
1494
|
options,
|
|
1490
|
-
resolvedCredentials
|
|
1495
|
+
resolvedCredentials,
|
|
1496
|
+
prompt
|
|
1491
1497
|
});
|
|
1492
1498
|
}
|
|
1493
1499
|
async function confirmNewCredentialsName(name) {
|
|
@@ -1858,6 +1864,7 @@ var PendingOauthTransactionSchema = zod.z.object({
|
|
|
1858
1864
|
credentialName: zod.z.string().optional(),
|
|
1859
1865
|
useApprovals: zod.z.boolean(),
|
|
1860
1866
|
headless: zod.z.boolean().default(false),
|
|
1867
|
+
preserveExistingCredentials: zod.z.boolean().default(false),
|
|
1861
1868
|
transaction: OauthTransactionSchema
|
|
1862
1869
|
});
|
|
1863
1870
|
function savePendingOauthTransaction({
|
|
@@ -1867,7 +1874,8 @@ function savePendingOauthTransaction({
|
|
|
1867
1874
|
credentialsBaseUrl,
|
|
1868
1875
|
credentialName,
|
|
1869
1876
|
useApprovals,
|
|
1870
|
-
headless
|
|
1877
|
+
headless,
|
|
1878
|
+
preserveExistingCredentials = false
|
|
1871
1879
|
}) {
|
|
1872
1880
|
const pendingTransaction = {
|
|
1873
1881
|
version: 1,
|
|
@@ -1875,6 +1883,7 @@ function savePendingOauthTransaction({
|
|
|
1875
1883
|
expiresAt,
|
|
1876
1884
|
useApprovals,
|
|
1877
1885
|
headless,
|
|
1886
|
+
preserveExistingCredentials,
|
|
1878
1887
|
transaction,
|
|
1879
1888
|
...credentialsBaseUrl !== void 0 && { credentialsBaseUrl },
|
|
1880
1889
|
...credentialName !== void 0 && { credentialName }
|
|
@@ -1893,6 +1902,7 @@ function clearPendingOauthTransaction() {
|
|
|
1893
1902
|
}
|
|
1894
1903
|
|
|
1895
1904
|
// src/utils/auth/oauth-flow.ts
|
|
1905
|
+
var OAUTH_CALLBACK_QUESTION = "Paste the final OAuth callback URL:";
|
|
1896
1906
|
var PENDING_OAUTH_RECOVERY_MESSAGE = "Start a new non-interactive login or signup flow to generate a fresh URL.";
|
|
1897
1907
|
var LOGIN_OAUTH_COPY = {
|
|
1898
1908
|
flowName: "Login",
|
|
@@ -1956,7 +1966,9 @@ async function startPendingOauthFlow({
|
|
|
1956
1966
|
entryPoint,
|
|
1957
1967
|
credentialName,
|
|
1958
1968
|
useApprovals,
|
|
1959
|
-
headless
|
|
1969
|
+
headless,
|
|
1970
|
+
preserveExistingCredentials = false,
|
|
1971
|
+
silent = false
|
|
1960
1972
|
}) {
|
|
1961
1973
|
const copy = entryPoint === "signup" ? SIGNUP_OAUTH_COPY : LOGIN_OAUTH_COPY;
|
|
1962
1974
|
const port = LOGIN_PORTS[0];
|
|
@@ -1973,8 +1985,10 @@ async function startPendingOauthFlow({
|
|
|
1973
1985
|
credentialsBaseUrl: baseUrl,
|
|
1974
1986
|
credentialName,
|
|
1975
1987
|
useApprovals,
|
|
1976
|
-
headless
|
|
1988
|
+
headless,
|
|
1989
|
+
preserveExistingCredentials
|
|
1977
1990
|
});
|
|
1991
|
+
if (silent) return pending;
|
|
1978
1992
|
process.stderr.write(
|
|
1979
1993
|
`Open this ${copy.urlLabel} in a browser to continue:
|
|
1980
1994
|
`
|
|
@@ -2000,23 +2014,24 @@ async function startPendingOauthFlow({
|
|
|
2000
2014
|
return pending;
|
|
2001
2015
|
}
|
|
2002
2016
|
function getPendingOauthFlow({
|
|
2003
|
-
entryPoint
|
|
2017
|
+
entryPoint,
|
|
2018
|
+
recoveryMessage = PENDING_OAUTH_RECOVERY_MESSAGE
|
|
2004
2019
|
}) {
|
|
2005
2020
|
const pending = getPendingOauthTransaction();
|
|
2006
2021
|
if (!pending) {
|
|
2007
2022
|
throw new ZapierCliValidationError(
|
|
2008
|
-
`No pending ${entryPoint} OAuth flow found. ${
|
|
2023
|
+
`No pending ${entryPoint} OAuth flow found. ${recoveryMessage}`
|
|
2009
2024
|
);
|
|
2010
2025
|
}
|
|
2011
2026
|
if (Date.now() > pending.expiresAt) {
|
|
2012
2027
|
clearPendingOauthTransaction();
|
|
2013
2028
|
throw new ZapierCliValidationError(
|
|
2014
|
-
`Pending ${pending.entryPoint} OAuth flow has expired. ${
|
|
2029
|
+
`Pending ${pending.entryPoint} OAuth flow has expired. ${recoveryMessage}`
|
|
2015
2030
|
);
|
|
2016
2031
|
}
|
|
2017
2032
|
if (pending.entryPoint !== entryPoint) {
|
|
2018
2033
|
throw new ZapierCliValidationError(
|
|
2019
|
-
`Pending OAuth flow is for ${pending.entryPoint}, not ${entryPoint}. ${
|
|
2034
|
+
`Pending OAuth flow is for ${pending.entryPoint}, not ${entryPoint}. ${recoveryMessage}`
|
|
2020
2035
|
);
|
|
2021
2036
|
}
|
|
2022
2037
|
return pending;
|
|
@@ -2179,7 +2194,7 @@ async function readHeadlessCallbackUrl({
|
|
|
2179
2194
|
process.once("SIGINT", handleCancellation);
|
|
2180
2195
|
process.once("SIGTERM", handleCancellation);
|
|
2181
2196
|
if (interactive) {
|
|
2182
|
-
void rl.question(
|
|
2197
|
+
void rl.question(`${OAUTH_CALLBACK_QUESTION} `, {
|
|
2183
2198
|
signal: abortController.signal
|
|
2184
2199
|
}).then(settleResolve).catch((error) => {
|
|
2185
2200
|
if (error instanceof Error && error.name === "AbortError") {
|
|
@@ -2666,7 +2681,7 @@ async function runOauthForEntryPoint({
|
|
|
2666
2681
|
if (event.type === "callback_accepted") {
|
|
2667
2682
|
emitSignupSuccess({
|
|
2668
2683
|
imports,
|
|
2669
|
-
isNonInteractive:
|
|
2684
|
+
isNonInteractive: !interactive,
|
|
2670
2685
|
isHeadless: headless === true
|
|
2671
2686
|
});
|
|
2672
2687
|
}
|
|
@@ -2748,7 +2763,9 @@ async function runAccountAuth({
|
|
|
2748
2763
|
options,
|
|
2749
2764
|
entryPoint,
|
|
2750
2765
|
storedCredentialsMode = "choose",
|
|
2751
|
-
preserveExistingCredentials = false
|
|
2766
|
+
preserveExistingCredentials = false,
|
|
2767
|
+
useBrowserCallback = false,
|
|
2768
|
+
silent = false
|
|
2752
2769
|
}) {
|
|
2753
2770
|
if (options.callbackUrl !== void 0) {
|
|
2754
2771
|
const { callbackUrl } = options;
|
|
@@ -2781,7 +2798,8 @@ async function runAccountAuth({
|
|
|
2781
2798
|
imports,
|
|
2782
2799
|
baseUrl: pending.credentialsBaseUrl,
|
|
2783
2800
|
interactive: false,
|
|
2784
|
-
entryPoint
|
|
2801
|
+
entryPoint,
|
|
2802
|
+
preserveExistingCredentials: pending.preserveExistingCredentials
|
|
2785
2803
|
})) {
|
|
2786
2804
|
return;
|
|
2787
2805
|
}
|
|
@@ -2858,7 +2876,7 @@ async function runAccountAuth({
|
|
|
2858
2876
|
);
|
|
2859
2877
|
}
|
|
2860
2878
|
}
|
|
2861
|
-
if (entryPoint === "login" && !interactive && providedName === void 0) {
|
|
2879
|
+
if (entryPoint === "login" && !interactive && providedName === void 0 && !preserveExistingCredentials) {
|
|
2862
2880
|
const activeCredentials = getActiveCredentials({
|
|
2863
2881
|
baseUrl: credentialsBaseUrl
|
|
2864
2882
|
});
|
|
@@ -2875,7 +2893,7 @@ async function runAccountAuth({
|
|
|
2875
2893
|
}
|
|
2876
2894
|
const timeoutSeconds = parseTimeoutSeconds(options.timeout);
|
|
2877
2895
|
const useApprovals = options.useApprovals === true;
|
|
2878
|
-
if (!interactive) {
|
|
2896
|
+
if (!interactive && (headless || !useBrowserCallback)) {
|
|
2879
2897
|
await startPendingOauthFlow({
|
|
2880
2898
|
entryPoint,
|
|
2881
2899
|
timeoutMs: timeoutSeconds * 1e3,
|
|
@@ -2883,7 +2901,9 @@ async function runAccountAuth({
|
|
|
2883
2901
|
baseUrl: credentialsBaseUrl,
|
|
2884
2902
|
credentialName: providedName,
|
|
2885
2903
|
useApprovals,
|
|
2886
|
-
headless
|
|
2904
|
+
headless,
|
|
2905
|
+
preserveExistingCredentials,
|
|
2906
|
+
silent
|
|
2887
2907
|
});
|
|
2888
2908
|
return;
|
|
2889
2909
|
}
|
|
@@ -2904,7 +2924,7 @@ async function runAccountAuth({
|
|
|
2904
2924
|
credentialName: providedName,
|
|
2905
2925
|
interactive,
|
|
2906
2926
|
useApprovals,
|
|
2907
|
-
isNonInteractive:
|
|
2927
|
+
isNonInteractive: !interactive,
|
|
2908
2928
|
isHeadless: headless
|
|
2909
2929
|
});
|
|
2910
2930
|
}
|
|
@@ -4795,6 +4815,7 @@ function createProjectDir({
|
|
|
4795
4815
|
var TEMPLATES_DIR = url.fileURLToPath(
|
|
4796
4816
|
new URL("../templates", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)))
|
|
4797
4817
|
);
|
|
4818
|
+
var SOURCE_CLI_PATH = (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.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('index.cjs', document.baseURI).href)))) : void 0;
|
|
4798
4819
|
|
|
4799
4820
|
// src/plugins/init/steps.ts
|
|
4800
4821
|
var DEFAULT_TEMPLATE = "basic";
|
|
@@ -5505,84 +5526,6 @@ async function checkForUpdates({
|
|
|
5505
5526
|
};
|
|
5506
5527
|
}
|
|
5507
5528
|
}
|
|
5508
|
-
var BRAILLE_BLANK = "\u2800";
|
|
5509
|
-
var LIGHTNING_INTERVAL_MILLISECONDS = 140;
|
|
5510
|
-
var boltRows = [
|
|
5511
|
-
"\u2800\u2800\u2880\u28FE\u2800\u2800\u2800\u2800",
|
|
5512
|
-
"\u2800\u2800\u28E0\u28FF\u28FF\u2800\u2800\u2800",
|
|
5513
|
-
"\u2800\u28FC\u28FF\u28FF\u28FF\u28C0\u28C0\u2840",
|
|
5514
|
-
"\u2808\u2809\u2809\u28FF\u28FF\u28FF\u285F\u2800",
|
|
5515
|
-
"\u2800\u2800\u2800\u28FF\u28FF\u280B\u2800\u2800",
|
|
5516
|
-
"\u2800\u2800\u2800\u287F\u2801\u2800\u2800\u2800"
|
|
5517
|
-
];
|
|
5518
|
-
var boltFillOrder = boltRows.flatMap(
|
|
5519
|
-
(row, rowIndex) => [...row].flatMap(
|
|
5520
|
-
(cell, columnIndex) => cell === BRAILLE_BLANK ? [] : rowIndex * row.length + columnIndex
|
|
5521
|
-
)
|
|
5522
|
-
);
|
|
5523
|
-
var fillStages = [
|
|
5524
|
-
...Array.from({ length: boltFillOrder.length + 1 }, (_, index) => index),
|
|
5525
|
-
boltFillOrder.length,
|
|
5526
|
-
0
|
|
5527
|
-
];
|
|
5528
|
-
var boltFillRanks = new Map(
|
|
5529
|
-
boltFillOrder.map((cellIndex, fillIndex) => [cellIndex, fillIndex])
|
|
5530
|
-
);
|
|
5531
|
-
var STATUS_ROW_INDEX = Math.floor(boltRows.length / 2);
|
|
5532
|
-
function formatPhase({ label, detail }) {
|
|
5533
|
-
return detail ? `${chalk6__default.default.bold(label)} ${chalk6__default.default.dim(detail)}` : chalk6__default.default.bold(label);
|
|
5534
|
-
}
|
|
5535
|
-
function formatLoaderFrame({
|
|
5536
|
-
phase,
|
|
5537
|
-
fillStage
|
|
5538
|
-
}) {
|
|
5539
|
-
return boltRows.map((row, rowIndex) => {
|
|
5540
|
-
const bolt = [...row].map((cell, columnIndex) => {
|
|
5541
|
-
if (cell === BRAILLE_BLANK) return cell;
|
|
5542
|
-
const cellIndex = rowIndex * row.length + columnIndex;
|
|
5543
|
-
const fillRank = boltFillRanks.get(cellIndex);
|
|
5544
|
-
const isFilled = fillRank !== void 0 && fillRank < fillStage;
|
|
5545
|
-
return isFilled ? chalk6__default.default.bold.yellow(cell) : chalk6__default.default.dim.yellow(cell);
|
|
5546
|
-
}).join("");
|
|
5547
|
-
const status = rowIndex === STATUS_ROW_INDEX ? ` ${formatPhase(phase)}` : "";
|
|
5548
|
-
return `${bolt}${status}`;
|
|
5549
|
-
}).join("\n");
|
|
5550
|
-
}
|
|
5551
|
-
async function runWithSetupLoader({
|
|
5552
|
-
promise,
|
|
5553
|
-
...phase
|
|
5554
|
-
}) {
|
|
5555
|
-
const startedAt = Date.now();
|
|
5556
|
-
let fillFrameIndex = 0;
|
|
5557
|
-
const loader = ora__default.default({
|
|
5558
|
-
isEnabled: process.stderr.isTTY === true,
|
|
5559
|
-
spinner: { interval: 80, frames: [""] },
|
|
5560
|
-
text: formatLoaderFrame({
|
|
5561
|
-
phase,
|
|
5562
|
-
fillStage: fillStages[fillFrameIndex]
|
|
5563
|
-
})
|
|
5564
|
-
}).start();
|
|
5565
|
-
const animationTimer = setInterval(() => {
|
|
5566
|
-
fillFrameIndex = (fillFrameIndex + 1) % fillStages.length;
|
|
5567
|
-
loader.text = formatLoaderFrame({
|
|
5568
|
-
phase,
|
|
5569
|
-
fillStage: fillStages[fillFrameIndex]
|
|
5570
|
-
});
|
|
5571
|
-
}, LIGHTNING_INTERVAL_MILLISECONDS);
|
|
5572
|
-
animationTimer.unref?.();
|
|
5573
|
-
try {
|
|
5574
|
-
const result = await promise;
|
|
5575
|
-
clearInterval(animationTimer);
|
|
5576
|
-
const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
|
|
5577
|
-
loader.succeed(`${formatPhase(phase)} ${chalk6__default.default.dim(`${elapsedSeconds}s`)}`);
|
|
5578
|
-
return result;
|
|
5579
|
-
} catch (error) {
|
|
5580
|
-
clearInterval(animationTimer);
|
|
5581
|
-
const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
|
|
5582
|
-
loader.fail(`${formatPhase(phase)} ${chalk6__default.default.dim(`${elapsedSeconds}s`)}`);
|
|
5583
|
-
throw error;
|
|
5584
|
-
}
|
|
5585
|
-
}
|
|
5586
5529
|
function isRecord(value) {
|
|
5587
5530
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5588
5531
|
}
|
|
@@ -5868,7 +5811,7 @@ async function offerPackageUpdate({
|
|
|
5868
5811
|
}) {
|
|
5869
5812
|
const { currentVersion, dependency } = packageState;
|
|
5870
5813
|
if (!currentVersion || !dependency.checkForUpdates) return;
|
|
5871
|
-
const update = await
|
|
5814
|
+
const update = await context.load({
|
|
5872
5815
|
promise: context.checkForUpdates({
|
|
5873
5816
|
packageName: dependency.name,
|
|
5874
5817
|
currentVersion
|
|
@@ -5893,28 +5836,108 @@ async function offerPackageUpdate({
|
|
|
5893
5836
|
})
|
|
5894
5837
|
);
|
|
5895
5838
|
}
|
|
5896
|
-
|
|
5839
|
+
function getPackageStates(context) {
|
|
5897
5840
|
const declaredPackageNames = getDeclaredPackageNames(context.cwd);
|
|
5898
5841
|
const requiredPackages = REQUIRED_PACKAGES.filter(
|
|
5899
5842
|
({ typescriptOnly }) => !typescriptOnly || context.projectLanguage === "typescript"
|
|
5900
5843
|
);
|
|
5901
|
-
|
|
5844
|
+
return requiredPackages.map((dependency) => ({
|
|
5902
5845
|
dependency,
|
|
5846
|
+
declared: declaredPackageNames.has(dependency.name),
|
|
5903
5847
|
currentVersion: declaredPackageNames.has(dependency.name) ? getInstalledPackageVersion({
|
|
5904
5848
|
cwd: context.cwd,
|
|
5905
5849
|
packageName: dependency.name
|
|
5906
5850
|
}) : void 0
|
|
5907
5851
|
}));
|
|
5852
|
+
}
|
|
5853
|
+
async function prepareDependencies(context) {
|
|
5854
|
+
const packages = getPackageStates(context);
|
|
5908
5855
|
await offerMissingPackageInstall({
|
|
5909
5856
|
context,
|
|
5910
|
-
packages: packages.filter(
|
|
5911
|
-
({ dependency }) => !declaredPackageNames.has(dependency.name)
|
|
5912
|
-
)
|
|
5857
|
+
packages: packages.filter(({ declared }) => !declared)
|
|
5913
5858
|
});
|
|
5914
5859
|
for (const packageState of packages) {
|
|
5915
5860
|
await offerPackageUpdate({ context, packageState });
|
|
5916
5861
|
}
|
|
5917
5862
|
}
|
|
5863
|
+
var BRAILLE_BLANK = "\u2800";
|
|
5864
|
+
var LIGHTNING_INTERVAL_MILLISECONDS = 140;
|
|
5865
|
+
var boltRows = [
|
|
5866
|
+
"\u2800\u2800\u2880\u28FE\u2800\u2800\u2800\u2800",
|
|
5867
|
+
"\u2800\u2800\u28E0\u28FF\u28FF\u2800\u2800\u2800",
|
|
5868
|
+
"\u2800\u28FC\u28FF\u28FF\u28FF\u28C0\u28C0\u2840",
|
|
5869
|
+
"\u2808\u2809\u2809\u28FF\u28FF\u28FF\u285F\u2800",
|
|
5870
|
+
"\u2800\u2800\u2800\u28FF\u28FF\u280B\u2800\u2800",
|
|
5871
|
+
"\u2800\u2800\u2800\u287F\u2801\u2800\u2800\u2800"
|
|
5872
|
+
];
|
|
5873
|
+
var boltFillOrder = boltRows.flatMap(
|
|
5874
|
+
(row, rowIndex) => [...row].flatMap(
|
|
5875
|
+
(cell, columnIndex) => cell === BRAILLE_BLANK ? [] : rowIndex * row.length + columnIndex
|
|
5876
|
+
)
|
|
5877
|
+
);
|
|
5878
|
+
var fillStages = [
|
|
5879
|
+
...Array.from({ length: boltFillOrder.length + 1 }, (_, index) => index),
|
|
5880
|
+
boltFillOrder.length,
|
|
5881
|
+
0
|
|
5882
|
+
];
|
|
5883
|
+
var boltFillRanks = new Map(
|
|
5884
|
+
boltFillOrder.map((cellIndex, fillIndex) => [cellIndex, fillIndex])
|
|
5885
|
+
);
|
|
5886
|
+
var STATUS_ROW_INDEX = Math.floor(boltRows.length / 2);
|
|
5887
|
+
function formatPhase({ label, detail }) {
|
|
5888
|
+
return detail ? `${chalk6__default.default.bold(label)} ${chalk6__default.default.dim(detail)}` : chalk6__default.default.bold(label);
|
|
5889
|
+
}
|
|
5890
|
+
function formatLoaderFrame({
|
|
5891
|
+
phase,
|
|
5892
|
+
fillStage
|
|
5893
|
+
}) {
|
|
5894
|
+
return boltRows.map((row, rowIndex) => {
|
|
5895
|
+
const bolt = [...row].map((cell, columnIndex) => {
|
|
5896
|
+
if (cell === BRAILLE_BLANK) return cell;
|
|
5897
|
+
const cellIndex = rowIndex * row.length + columnIndex;
|
|
5898
|
+
const fillRank = boltFillRanks.get(cellIndex);
|
|
5899
|
+
const isFilled = fillRank !== void 0 && fillRank < fillStage;
|
|
5900
|
+
return isFilled ? chalk6__default.default.bold.yellow(cell) : chalk6__default.default.dim.yellow(cell);
|
|
5901
|
+
}).join("");
|
|
5902
|
+
const status = rowIndex === STATUS_ROW_INDEX ? ` ${formatPhase(phase)}` : "";
|
|
5903
|
+
return `${bolt}${status}`;
|
|
5904
|
+
}).join("\n");
|
|
5905
|
+
}
|
|
5906
|
+
async function runWithSetupLoader({
|
|
5907
|
+
promise,
|
|
5908
|
+
...phase
|
|
5909
|
+
}) {
|
|
5910
|
+
const startedAt = Date.now();
|
|
5911
|
+
let fillFrameIndex = 0;
|
|
5912
|
+
const loader = ora__default.default({
|
|
5913
|
+
isEnabled: process.stderr.isTTY === true,
|
|
5914
|
+
spinner: { interval: 80, frames: [""] },
|
|
5915
|
+
text: formatLoaderFrame({
|
|
5916
|
+
phase,
|
|
5917
|
+
fillStage: fillStages[fillFrameIndex]
|
|
5918
|
+
})
|
|
5919
|
+
}).start();
|
|
5920
|
+
const animationTimer = setInterval(() => {
|
|
5921
|
+
fillFrameIndex = (fillFrameIndex + 1) % fillStages.length;
|
|
5922
|
+
loader.text = formatLoaderFrame({
|
|
5923
|
+
phase,
|
|
5924
|
+
fillStage: fillStages[fillFrameIndex]
|
|
5925
|
+
});
|
|
5926
|
+
}, LIGHTNING_INTERVAL_MILLISECONDS);
|
|
5927
|
+
animationTimer.unref?.();
|
|
5928
|
+
try {
|
|
5929
|
+
const result = await promise;
|
|
5930
|
+
clearInterval(animationTimer);
|
|
5931
|
+
const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
|
|
5932
|
+
loader.succeed(`${formatPhase(phase)} ${chalk6__default.default.dim(`${elapsedSeconds}s`)}`);
|
|
5933
|
+
return result;
|
|
5934
|
+
} catch (error) {
|
|
5935
|
+
clearInterval(animationTimer);
|
|
5936
|
+
const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
|
|
5937
|
+
loader.fail(`${formatPhase(phase)} ${chalk6__default.default.dim(`${elapsedSeconds}s`)}`);
|
|
5938
|
+
throw error;
|
|
5939
|
+
}
|
|
5940
|
+
}
|
|
5918
5941
|
|
|
5919
5942
|
// src/plugins/setup/package-commands.ts
|
|
5920
5943
|
function createLocalPackageCommand({
|
|
@@ -5953,7 +5976,10 @@ function formatPackageCommand({
|
|
|
5953
5976
|
command,
|
|
5954
5977
|
args
|
|
5955
5978
|
}) {
|
|
5956
|
-
return [command, ...args].join(" ");
|
|
5979
|
+
return [command, ...args].map(quoteShellArgument).join(" ");
|
|
5980
|
+
}
|
|
5981
|
+
function quoteShellArgument(value) {
|
|
5982
|
+
return /^[a-zA-Z0-9_@%+=:,./-]+$/.test(value) ? value : `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
5957
5983
|
}
|
|
5958
5984
|
|
|
5959
5985
|
// src/plugins/setup/project.ts
|
|
@@ -6058,13 +6084,14 @@ async function runCommand({
|
|
|
6058
6084
|
args = [],
|
|
6059
6085
|
cwd,
|
|
6060
6086
|
capture = true,
|
|
6061
|
-
input
|
|
6087
|
+
input,
|
|
6088
|
+
load = runWithSetupLoader
|
|
6062
6089
|
}) {
|
|
6063
6090
|
const commandLabel = `$ ${command} ${args.join(" ")}`.trim();
|
|
6064
6091
|
const execute = capture ? executeCapturedCommand({ command, args, cwd, input }) : executeStreamingCommand({ command, args, cwd, input });
|
|
6065
6092
|
try {
|
|
6066
6093
|
if (capture) {
|
|
6067
|
-
return await
|
|
6094
|
+
return await load({
|
|
6068
6095
|
promise: execute,
|
|
6069
6096
|
label: "Running command",
|
|
6070
6097
|
detail: commandLabel
|
|
@@ -6148,7 +6175,7 @@ function detectProjectLanguage({
|
|
|
6148
6175
|
);
|
|
6149
6176
|
return hasTypeScript ? "typescript" : "javascript";
|
|
6150
6177
|
}
|
|
6151
|
-
async function
|
|
6178
|
+
async function initializeProject(context) {
|
|
6152
6179
|
context.packageManager = detectPackageManager(context.cwd).name;
|
|
6153
6180
|
console.log(`Using ${context.packageManager} for dependency installs.`);
|
|
6154
6181
|
const hasExistingProject = fs.existsSync(path.join(context.cwd, "package.json"));
|
|
@@ -6164,182 +6191,161 @@ async function prepareProject(context) {
|
|
|
6164
6191
|
cwd: context.cwd
|
|
6165
6192
|
});
|
|
6166
6193
|
}
|
|
6194
|
+
}
|
|
6195
|
+
async function prepareProject(context) {
|
|
6196
|
+
await initializeProject(context);
|
|
6167
6197
|
await prepareDependencies(context);
|
|
6168
6198
|
}
|
|
6169
6199
|
|
|
6170
6200
|
// src/plugins/setup/context.ts
|
|
6171
6201
|
function createWizardContext({
|
|
6172
|
-
imports
|
|
6202
|
+
imports,
|
|
6203
|
+
agent = false
|
|
6173
6204
|
}) {
|
|
6174
|
-
|
|
6205
|
+
const context = {
|
|
6175
6206
|
cwd: process.cwd(),
|
|
6207
|
+
load: agent ? ({ promise }) => promise : runWithSetupLoader,
|
|
6176
6208
|
imports,
|
|
6177
6209
|
createAnswer: () => createCliAnswer({ mode: "closed-list" }),
|
|
6178
6210
|
setupController: createSetupController(),
|
|
6179
|
-
selectStoredLoginCredentials: () => chooseStoredLoginCredentials({
|
|
6180
|
-
|
|
6211
|
+
selectStoredLoginCredentials: () => chooseStoredLoginCredentials({
|
|
6212
|
+
imports,
|
|
6213
|
+
options: {},
|
|
6214
|
+
...agent ? {
|
|
6215
|
+
prompt: async (options) => {
|
|
6216
|
+
const credentialChoices = buildCredentialsChoices(options);
|
|
6217
|
+
const choices = credentialChoices.map(({ name, value }) => ({
|
|
6218
|
+
label: name,
|
|
6219
|
+
value: value.action === "create" ? "create" : `account:${value.credentials.name}`,
|
|
6220
|
+
result: value
|
|
6221
|
+
}));
|
|
6222
|
+
const selected = await resolveSetupSelect({
|
|
6223
|
+
answer: context.createAnswer(),
|
|
6224
|
+
controller: context.setupController,
|
|
6225
|
+
message: CREDENTIALS_PICKER_QUESTION,
|
|
6226
|
+
choices
|
|
6227
|
+
});
|
|
6228
|
+
const selectedIndex = choices.findIndex(
|
|
6229
|
+
({ value }) => value === selected
|
|
6230
|
+
);
|
|
6231
|
+
return choices[selectedIndex].result;
|
|
6232
|
+
}
|
|
6233
|
+
} : {}
|
|
6234
|
+
}),
|
|
6235
|
+
authenticateNewAccount: ({ entryPoint, ...options }) => runAccountAuth({
|
|
6181
6236
|
imports,
|
|
6182
|
-
options
|
|
6237
|
+
options,
|
|
6183
6238
|
entryPoint,
|
|
6184
6239
|
storedCredentialsMode: "fresh",
|
|
6185
|
-
preserveExistingCredentials: true
|
|
6240
|
+
preserveExistingCredentials: true,
|
|
6241
|
+
useBrowserCallback: agent && options.headless === false,
|
|
6242
|
+
silent: agent && options.headless
|
|
6186
6243
|
}),
|
|
6187
6244
|
checkForUpdates,
|
|
6188
6245
|
openUrl: async (url) => {
|
|
6189
6246
|
await open__default.default(url);
|
|
6190
6247
|
},
|
|
6191
|
-
runCommand
|
|
6248
|
+
runCommand: agent ? (options) => runCommand({
|
|
6249
|
+
...options,
|
|
6250
|
+
capture: true,
|
|
6251
|
+
load: ({ promise, detail }) => {
|
|
6252
|
+
console.log(detail);
|
|
6253
|
+
return promise;
|
|
6254
|
+
}
|
|
6255
|
+
}) : runCommand,
|
|
6192
6256
|
packageManager: detectPackageManager(process.cwd()).name,
|
|
6193
6257
|
projectLanguage: "typescript"
|
|
6194
6258
|
};
|
|
6259
|
+
return context;
|
|
6260
|
+
}
|
|
6261
|
+
var SetupStepSchema = zod.z.enum([
|
|
6262
|
+
"directory",
|
|
6263
|
+
"project",
|
|
6264
|
+
"install",
|
|
6265
|
+
"sdk-update",
|
|
6266
|
+
"cli-update",
|
|
6267
|
+
"skill",
|
|
6268
|
+
"account",
|
|
6269
|
+
"account-flow",
|
|
6270
|
+
"account-environment",
|
|
6271
|
+
"authorize",
|
|
6272
|
+
"confirm-account",
|
|
6273
|
+
"connections",
|
|
6274
|
+
"slack",
|
|
6275
|
+
"slack-overwrite",
|
|
6276
|
+
"slack-existing",
|
|
6277
|
+
"slack-retry",
|
|
6278
|
+
"handoff"
|
|
6279
|
+
]);
|
|
6280
|
+
var SetupSchema = zod.z.object({
|
|
6281
|
+
agent: zod.z.boolean().optional().describe(
|
|
6282
|
+
"For AI agents and callers without a terminal: print the next setup question and the exact command to run for each answer."
|
|
6283
|
+
),
|
|
6284
|
+
step: SetupStepSchema.optional().describe(
|
|
6285
|
+
"Setup operation to inspect or execute."
|
|
6286
|
+
),
|
|
6287
|
+
nonInteractive: zod.z.boolean().optional().describe("Execute the named setup step without terminal prompts."),
|
|
6288
|
+
answer: zod.z.string().optional().describe(
|
|
6289
|
+
"User selection or input for a non-interactive setup step. Omitted confirmations use the terminal wizard's default."
|
|
6290
|
+
),
|
|
6291
|
+
flow: zod.z.enum(["login", "signup"]).optional().describe(
|
|
6292
|
+
"Account flow selected for the environment and OAuth callback steps."
|
|
6293
|
+
),
|
|
6294
|
+
language: zod.z.enum(["javascript", "typescript"]).optional().describe(
|
|
6295
|
+
"Project language for dependency installation and the Slack demo."
|
|
6296
|
+
)
|
|
6297
|
+
}).describe(
|
|
6298
|
+
"Set up the Zapier SDK in an existing or new project. Runs an interactive terminal wizard; AI agents should use --agent instead."
|
|
6299
|
+
);
|
|
6300
|
+
|
|
6301
|
+
// package.json
|
|
6302
|
+
var package_default = {
|
|
6303
|
+
version: "0.87.2"};
|
|
6304
|
+
var agentLabels = {
|
|
6305
|
+
claude: "Claude Code",
|
|
6306
|
+
codex: "Codex",
|
|
6307
|
+
cursor: "Cursor",
|
|
6308
|
+
"vscode-copilot": "VS Code Copilot"
|
|
6309
|
+
};
|
|
6310
|
+
function buildAgentPrompt({
|
|
6311
|
+
context
|
|
6312
|
+
}) {
|
|
6313
|
+
const listConnectionsCommand = formatPackageCommand(
|
|
6314
|
+
createLocalPackageCommand({
|
|
6315
|
+
packageManager: context.packageManager,
|
|
6316
|
+
binary: "zapier-sdk",
|
|
6317
|
+
args: ["list-connections", "--owner", "me", "--json"]
|
|
6318
|
+
})
|
|
6319
|
+
);
|
|
6320
|
+
const listActionsCommand = formatPackageCommand(
|
|
6321
|
+
createLocalPackageCommand({
|
|
6322
|
+
packageManager: context.packageManager,
|
|
6323
|
+
binary: "zapier-sdk",
|
|
6324
|
+
args: ["list-actions", "APP_KEY"]
|
|
6325
|
+
})
|
|
6326
|
+
);
|
|
6327
|
+
return `Start by running this command to discover my active connected apps outside of your sandbox:
|
|
6328
|
+
|
|
6329
|
+
${listConnectionsCommand}
|
|
6330
|
+
|
|
6331
|
+
Using the connected apps returned by that command:
|
|
6332
|
+
|
|
6333
|
+
- Pick 1-3 apps and show commands I can use to explore their actions, such as: ${listActionsCommand}
|
|
6334
|
+
- Do not run those list-actions commands.
|
|
6335
|
+
- Suggest 3 specific ideas based on my connected apps. Each idea should read from one app, optionally process data, and write to another.
|
|
6336
|
+
- Do not suggest event-driven workflows.
|
|
6337
|
+
- Keep each idea to one sentence. Example: "pull in-progress Jira issues and DM yourself a summary on Slack".
|
|
6338
|
+
|
|
6339
|
+
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.`;
|
|
6195
6340
|
}
|
|
6196
|
-
|
|
6197
|
-
function printAuthCommand({
|
|
6341
|
+
function printAgentPrompt({
|
|
6198
6342
|
context,
|
|
6199
|
-
|
|
6200
|
-
headless
|
|
6343
|
+
message
|
|
6201
6344
|
}) {
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
});
|
|
6207
|
-
console.log(`$ ${formatPackageCommand(command)}`);
|
|
6208
|
-
if (headless) {
|
|
6209
|
-
console.log(
|
|
6210
|
-
"Open the printed URL in another browser, then paste the final OAuth callback URL when prompted."
|
|
6211
|
-
);
|
|
6212
|
-
}
|
|
6213
|
-
}
|
|
6214
|
-
function isCredentialWriteError(error) {
|
|
6215
|
-
const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "";
|
|
6216
|
-
if (/^(eacces|eperm)$/i.test(code)) return true;
|
|
6217
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
6218
|
-
return /permission|sandbox|eacces|eperm/i.test(message);
|
|
6219
|
-
}
|
|
6220
|
-
async function confirmAuthentication(context) {
|
|
6221
|
-
const { data: profile } = await runWithSetupLoader({
|
|
6222
|
-
promise: context.imports.getProfile({}),
|
|
6223
|
-
label: "Confirming Zapier account"
|
|
6224
|
-
});
|
|
6225
|
-
context.accountEmail = profile.email;
|
|
6226
|
-
console.log(`Authenticated as ${profile.email}.`);
|
|
6227
|
-
}
|
|
6228
|
-
async function authenticate(context) {
|
|
6229
|
-
const activeProfile = await runWithSetupLoader({
|
|
6230
|
-
promise: context.imports.getProfile({}).then(({ data }) => data).catch((error) => {
|
|
6231
|
-
if (zapierSdk.isZapierAuthenticationError(error)) return void 0;
|
|
6232
|
-
throw error;
|
|
6233
|
-
}),
|
|
6234
|
-
label: "Checking Zapier authentication"
|
|
6235
|
-
});
|
|
6236
|
-
const storedCredentialsSelection = await context.selectStoredLoginCredentials();
|
|
6237
|
-
if (storedCredentialsSelection === "switch") {
|
|
6238
|
-
await confirmAuthentication(context);
|
|
6239
|
-
return;
|
|
6240
|
-
}
|
|
6241
|
-
if (storedCredentialsSelection === "none" && activeProfile) {
|
|
6242
|
-
const shouldLogout = await resolveSetupConfirm({
|
|
6243
|
-
answer: context.createAnswer(),
|
|
6244
|
-
controller: context.setupController,
|
|
6245
|
-
message: `You are already logged in as "${activeProfile.email}".
|
|
6246
|
-
Logging out will delete these credentials and may interrupt other Zapier SDK or CLI sessions using them.
|
|
6247
|
-
Log out and use a different account?`,
|
|
6248
|
-
defaultValue: false
|
|
6249
|
-
});
|
|
6250
|
-
if (!shouldLogout) {
|
|
6251
|
-
context.accountEmail = activeProfile.email;
|
|
6252
|
-
console.log(`Continuing as ${activeProfile.email}.`);
|
|
6253
|
-
return;
|
|
6254
|
-
}
|
|
6255
|
-
const logoutCommand = createLocalPackageCommand({
|
|
6256
|
-
packageManager: context.packageManager,
|
|
6257
|
-
binary: "zapier-sdk",
|
|
6258
|
-
args: ["logout"]
|
|
6259
|
-
});
|
|
6260
|
-
console.log(`$ ${formatPackageCommand(logoutCommand)}`);
|
|
6261
|
-
await context.imports.logout({});
|
|
6262
|
-
}
|
|
6263
|
-
const flow = await resolveSetupSelect({
|
|
6264
|
-
answer: context.createAnswer(),
|
|
6265
|
-
controller: context.setupController,
|
|
6266
|
-
message: "Zapier account:",
|
|
6267
|
-
choices: [
|
|
6268
|
-
{ label: "Log in to an existing account", value: "login" },
|
|
6269
|
-
{ label: "Create a new Zapier account", value: "signup" }
|
|
6270
|
-
]
|
|
6271
|
-
});
|
|
6272
|
-
const environment = await resolveSetupSelect({
|
|
6273
|
-
answer: context.createAnswer(),
|
|
6274
|
-
controller: context.setupController,
|
|
6275
|
-
message: "Environment:",
|
|
6276
|
-
choices: [
|
|
6277
|
-
{ label: "Local machine with a browser", value: "local" },
|
|
6278
|
-
{ label: "Remote or headless", value: "headless" }
|
|
6279
|
-
]
|
|
6280
|
-
});
|
|
6281
|
-
const headless = environment === "headless";
|
|
6282
|
-
printAuthCommand({ context, flow, headless });
|
|
6283
|
-
try {
|
|
6284
|
-
if (storedCredentialsSelection === "create") {
|
|
6285
|
-
await context.authenticateNewAccount({ entryPoint: flow, headless });
|
|
6286
|
-
} else {
|
|
6287
|
-
const runAuth = flow === "login" ? context.imports.login : context.imports.signup;
|
|
6288
|
-
await runAuth({ headless });
|
|
6289
|
-
}
|
|
6290
|
-
} catch (error) {
|
|
6291
|
-
if (isCredentialWriteError(error)) {
|
|
6292
|
-
console.error(
|
|
6293
|
-
"Authentication could not write credentials. A permissions or sandbox restriction may be blocking disk access."
|
|
6294
|
-
);
|
|
6295
|
-
}
|
|
6296
|
-
throw error;
|
|
6297
|
-
}
|
|
6298
|
-
await confirmAuthentication(context);
|
|
6299
|
-
}
|
|
6300
|
-
var agentLabels = {
|
|
6301
|
-
claude: "Claude Code",
|
|
6302
|
-
codex: "Codex",
|
|
6303
|
-
cursor: "Cursor",
|
|
6304
|
-
"vscode-copilot": "VS Code Copilot"
|
|
6305
|
-
};
|
|
6306
|
-
function buildAgentPrompt({ context }) {
|
|
6307
|
-
const listConnectionsCommand = formatPackageCommand(
|
|
6308
|
-
createLocalPackageCommand({
|
|
6309
|
-
packageManager: context.packageManager,
|
|
6310
|
-
binary: "zapier-sdk",
|
|
6311
|
-
args: ["list-connections", "--owner", "me", "--json"]
|
|
6312
|
-
})
|
|
6313
|
-
);
|
|
6314
|
-
const listActionsCommand = formatPackageCommand(
|
|
6315
|
-
createLocalPackageCommand({
|
|
6316
|
-
packageManager: context.packageManager,
|
|
6317
|
-
binary: "zapier-sdk",
|
|
6318
|
-
args: ["list-actions", "APP_KEY"]
|
|
6319
|
-
})
|
|
6320
|
-
);
|
|
6321
|
-
return `Start by running this command to discover my active connected apps outside of your sandbox:
|
|
6322
|
-
|
|
6323
|
-
${listConnectionsCommand}
|
|
6324
|
-
|
|
6325
|
-
Using the connected apps returned by that command:
|
|
6326
|
-
|
|
6327
|
-
- Pick 1-3 apps and show commands I can use to explore their actions, such as: ${listActionsCommand}
|
|
6328
|
-
- Do not run those list-actions commands.
|
|
6329
|
-
- Suggest 3 specific ideas based on my connected apps. Each idea should read from one app, optionally process data, and write to another.
|
|
6330
|
-
- Do not suggest event-driven workflows.
|
|
6331
|
-
- Keep each idea to one sentence. Example: "pull in-progress Jira issues and DM yourself a summary on Slack".
|
|
6332
|
-
|
|
6333
|
-
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.`;
|
|
6334
|
-
}
|
|
6335
|
-
function printAgentPrompt({
|
|
6336
|
-
context,
|
|
6337
|
-
message
|
|
6338
|
-
}) {
|
|
6339
|
-
console.log();
|
|
6340
|
-
console.log(chalk6__default.default.bgYellow.black.bold(message));
|
|
6341
|
-
console.log();
|
|
6342
|
-
console.log(buildAgentPrompt({ context }));
|
|
6345
|
+
console.log();
|
|
6346
|
+
console.log(chalk6__default.default.bgYellow.black.bold(message));
|
|
6347
|
+
console.log();
|
|
6348
|
+
console.log(buildAgentPrompt({ context }));
|
|
6343
6349
|
}
|
|
6344
6350
|
async function openAgentHandoff(context) {
|
|
6345
6351
|
const agent = await resolveSetupSelect({
|
|
@@ -6410,27 +6416,291 @@ async function openAgentHandoff(context) {
|
|
|
6410
6416
|
message: "If it didn't load correctly, paste this prompt into your agent:"
|
|
6411
6417
|
});
|
|
6412
6418
|
}
|
|
6419
|
+
|
|
6420
|
+
// src/plugins/setup/agent-output.ts
|
|
6421
|
+
var REQUIRED_STEPS = [
|
|
6422
|
+
"directory",
|
|
6423
|
+
"install"
|
|
6424
|
+
];
|
|
6425
|
+
function formatSetupCommand({
|
|
6426
|
+
context,
|
|
6427
|
+
target,
|
|
6428
|
+
answer
|
|
6429
|
+
}) {
|
|
6430
|
+
const args = [
|
|
6431
|
+
"setup",
|
|
6432
|
+
"--step",
|
|
6433
|
+
target.step,
|
|
6434
|
+
"--non-interactive",
|
|
6435
|
+
...target.flow ? ["--flow", target.flow] : [],
|
|
6436
|
+
"--language",
|
|
6437
|
+
context.projectLanguage,
|
|
6438
|
+
...answer !== void 0 ? ["--answer", answer] : []
|
|
6439
|
+
];
|
|
6440
|
+
return formatPackageCommand(
|
|
6441
|
+
SOURCE_CLI_PATH ? {
|
|
6442
|
+
command: process.execPath,
|
|
6443
|
+
args: [
|
|
6444
|
+
"--import",
|
|
6445
|
+
module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))).resolve("tsx"),
|
|
6446
|
+
"--conditions",
|
|
6447
|
+
"source",
|
|
6448
|
+
SOURCE_CLI_PATH,
|
|
6449
|
+
...args
|
|
6450
|
+
]
|
|
6451
|
+
} : createPackageRunnerCommand({
|
|
6452
|
+
packageManager: context.packageManager,
|
|
6453
|
+
packageName: `@zapier/zapier-sdk-cli@${package_default.version}`,
|
|
6454
|
+
args
|
|
6455
|
+
})
|
|
6456
|
+
);
|
|
6457
|
+
}
|
|
6458
|
+
function printAgentStep({
|
|
6459
|
+
context,
|
|
6460
|
+
target,
|
|
6461
|
+
question
|
|
6462
|
+
}) {
|
|
6463
|
+
console.log(
|
|
6464
|
+
`Step: ${target.step}
|
|
6465
|
+
Working directory: ${context.cwd}
|
|
6466
|
+
Detected package manager: ${context.packageManager}
|
|
6467
|
+
Project language: ${context.projectLanguage}`
|
|
6468
|
+
);
|
|
6469
|
+
if (!question) {
|
|
6470
|
+
console.log(
|
|
6471
|
+
`Run this exact command:
|
|
6472
|
+
${formatSetupCommand({ context, target })}`
|
|
6473
|
+
);
|
|
6474
|
+
} else {
|
|
6475
|
+
if (target.step === "authorize" && context.authorizationUrl)
|
|
6476
|
+
console.log(
|
|
6477
|
+
`Give the user this URL to open in a browser where they can sign in to Zapier:
|
|
6478
|
+
${context.authorizationUrl}
|
|
6479
|
+
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.`
|
|
6480
|
+
);
|
|
6481
|
+
console.log(`Ask the user this question verbatim: "${question.message}"`);
|
|
6482
|
+
if (question.type === "select") {
|
|
6483
|
+
for (const { value, label } of question.choices)
|
|
6484
|
+
console.log(`${JSON.stringify(value)}: ${label}`);
|
|
6485
|
+
for (const { value } of question.choices) {
|
|
6486
|
+
const decision = value === "true" ? "agrees" : value === "false" ? "declines" : `chooses ${JSON.stringify(value)}`;
|
|
6487
|
+
if (value === "false" && REQUIRED_STEPS.includes(target.step))
|
|
6488
|
+
console.log("If the user declines, stop setup.");
|
|
6489
|
+
else
|
|
6490
|
+
console.log(
|
|
6491
|
+
`If the user ${decision}, run this exact command:
|
|
6492
|
+
${formatSetupCommand({ context, target, answer: value })}`
|
|
6493
|
+
);
|
|
6494
|
+
}
|
|
6495
|
+
} else {
|
|
6496
|
+
console.log(
|
|
6497
|
+
`Run this exact command with their answer as one shell-quoted argument (an empty answer is ''):
|
|
6498
|
+
${formatSetupCommand({ context, target, answer: "<answer>" })}`
|
|
6499
|
+
);
|
|
6500
|
+
}
|
|
6501
|
+
if (target.step === "account-environment")
|
|
6502
|
+
console.log(
|
|
6503
|
+
`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.`
|
|
6504
|
+
);
|
|
6505
|
+
console.log(
|
|
6506
|
+
"Use your tool for asking the user questions if you have one. Do not answer on the user's behalf."
|
|
6507
|
+
);
|
|
6508
|
+
}
|
|
6509
|
+
console.log(
|
|
6510
|
+
"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."
|
|
6511
|
+
);
|
|
6512
|
+
}
|
|
6513
|
+
function printAgentCompletion({
|
|
6514
|
+
context,
|
|
6515
|
+
cancelled = false
|
|
6516
|
+
}) {
|
|
6517
|
+
console.log(
|
|
6518
|
+
cancelled ? "Setup cancelled." : `Setup walkthrough finished. Report which operations succeeded, failed, or were skipped based on their command results.
|
|
6519
|
+
Learn more: https://docs.zapier.com/sdk
|
|
6520
|
+
|
|
6521
|
+
Continue in this agent. Do not open another agent or ask the user to choose one.
|
|
6522
|
+
${buildAgentPrompt({ context })}`
|
|
6523
|
+
);
|
|
6524
|
+
}
|
|
6525
|
+
|
|
6526
|
+
// src/plugins/setup/authentication.ts
|
|
6527
|
+
function printAuthCommand({
|
|
6528
|
+
context,
|
|
6529
|
+
flow,
|
|
6530
|
+
headless = false
|
|
6531
|
+
}) {
|
|
6532
|
+
const command = createLocalPackageCommand({
|
|
6533
|
+
packageManager: context.packageManager,
|
|
6534
|
+
binary: "zapier-sdk",
|
|
6535
|
+
args: [flow, ...headless ? ["--headless"] : []]
|
|
6536
|
+
});
|
|
6537
|
+
console.log(`$ ${formatPackageCommand(command)}`);
|
|
6538
|
+
if (headless) {
|
|
6539
|
+
console.log(
|
|
6540
|
+
"Open the printed URL in another browser, then paste the final OAuth callback URL when prompted."
|
|
6541
|
+
);
|
|
6542
|
+
}
|
|
6543
|
+
}
|
|
6544
|
+
function isCredentialWriteError(error) {
|
|
6545
|
+
const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "";
|
|
6546
|
+
if (/^(eacces|eperm)$/i.test(code)) return true;
|
|
6547
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6548
|
+
return /permission|sandbox|eacces|eperm/i.test(message);
|
|
6549
|
+
}
|
|
6550
|
+
async function confirmAuthentication(context) {
|
|
6551
|
+
const { data: profile } = await context.load({
|
|
6552
|
+
promise: context.imports.getProfile({}),
|
|
6553
|
+
label: "Confirming Zapier account"
|
|
6554
|
+
});
|
|
6555
|
+
context.accountEmail = profile.email;
|
|
6556
|
+
console.log(`Authenticated as ${profile.email}.`);
|
|
6557
|
+
}
|
|
6558
|
+
function selectAccountFlow(context) {
|
|
6559
|
+
return resolveSetupSelect({
|
|
6560
|
+
answer: context.createAnswer(),
|
|
6561
|
+
controller: context.setupController,
|
|
6562
|
+
message: "Zapier account:",
|
|
6563
|
+
choices: [
|
|
6564
|
+
{ label: "Log in to an existing account", value: "login" },
|
|
6565
|
+
{ label: "Create a new Zapier account", value: "signup" }
|
|
6566
|
+
]
|
|
6567
|
+
});
|
|
6568
|
+
}
|
|
6569
|
+
function selectAuthenticationEnvironment(context) {
|
|
6570
|
+
return resolveSetupSelect({
|
|
6571
|
+
answer: context.createAnswer(),
|
|
6572
|
+
controller: context.setupController,
|
|
6573
|
+
message: "Environment:",
|
|
6574
|
+
choices: [
|
|
6575
|
+
{ label: "Local machine with a browser", value: "local" },
|
|
6576
|
+
{ label: "Remote or headless", value: "headless" }
|
|
6577
|
+
]
|
|
6578
|
+
});
|
|
6579
|
+
}
|
|
6580
|
+
async function selectAccount(context) {
|
|
6581
|
+
const activeProfile = await context.load({
|
|
6582
|
+
promise: context.imports.getProfile({}).then(({ data }) => data).catch((error) => {
|
|
6583
|
+
if (zapierSdk.isZapierAuthenticationError(error)) return void 0;
|
|
6584
|
+
throw error;
|
|
6585
|
+
}),
|
|
6586
|
+
label: "Checking Zapier authentication"
|
|
6587
|
+
});
|
|
6588
|
+
const storedCredentialsSelection = await context.selectStoredLoginCredentials();
|
|
6589
|
+
if (storedCredentialsSelection === "none" && activeProfile) {
|
|
6590
|
+
const shouldLogout = await resolveSetupConfirm({
|
|
6591
|
+
answer: context.createAnswer(),
|
|
6592
|
+
controller: context.setupController,
|
|
6593
|
+
message: `You are already logged in as "${activeProfile.email}".
|
|
6594
|
+
Logging out will delete these credentials and may interrupt other Zapier SDK or CLI sessions using them.
|
|
6595
|
+
Log out and use a different account?`,
|
|
6596
|
+
defaultValue: false
|
|
6597
|
+
});
|
|
6598
|
+
if (!shouldLogout) {
|
|
6599
|
+
context.accountEmail = activeProfile.email;
|
|
6600
|
+
console.log(`Continuing as ${activeProfile.email}.`);
|
|
6601
|
+
return "continue";
|
|
6602
|
+
}
|
|
6603
|
+
printAuthCommand({ context, flow: "logout" });
|
|
6604
|
+
await context.imports.logout({});
|
|
6605
|
+
}
|
|
6606
|
+
return storedCredentialsSelection;
|
|
6607
|
+
}
|
|
6608
|
+
async function authenticate(context) {
|
|
6609
|
+
const next = await runAuthenticationStep({ context, options: {} });
|
|
6610
|
+
if (next.step === "confirm-account") await confirmAuthentication(context);
|
|
6611
|
+
}
|
|
6612
|
+
async function runAuthenticationStep({
|
|
6613
|
+
context,
|
|
6614
|
+
options
|
|
6615
|
+
}) {
|
|
6616
|
+
const { step } = options;
|
|
6617
|
+
let newAccount = step === "account-environment";
|
|
6618
|
+
if (!step || step === "account") {
|
|
6619
|
+
const selection = await selectAccount(context);
|
|
6620
|
+
if (selection === "switch") return { step: "confirm-account" };
|
|
6621
|
+
if (selection === "continue")
|
|
6622
|
+
return { step: step ? "confirm-account" : "connections" };
|
|
6623
|
+
if (step) return { step: "account-flow" };
|
|
6624
|
+
newAccount = selection === "create";
|
|
6625
|
+
}
|
|
6626
|
+
if (step === "confirm-account") {
|
|
6627
|
+
await confirmAuthentication(context);
|
|
6628
|
+
return { step: "connections" };
|
|
6629
|
+
}
|
|
6630
|
+
const flow = !step || step === "account-flow" ? await selectAccountFlow(context) : options.flow;
|
|
6631
|
+
if (step === "account-flow")
|
|
6632
|
+
return {
|
|
6633
|
+
step: "account-environment",
|
|
6634
|
+
flow
|
|
6635
|
+
};
|
|
6636
|
+
if (!flow)
|
|
6637
|
+
throw new ZapierCliValidationError(
|
|
6638
|
+
"This setup step requires --flow login or --flow signup."
|
|
6639
|
+
);
|
|
6640
|
+
let headless = true;
|
|
6641
|
+
let callbackUrl;
|
|
6642
|
+
let recoveryMessage;
|
|
6643
|
+
if (step === "authorize") {
|
|
6644
|
+
recoveryMessage = `Generate a fresh authorization URL with \`${formatSetupCommand(
|
|
6645
|
+
{
|
|
6646
|
+
context,
|
|
6647
|
+
target: { step: "account-environment", flow },
|
|
6648
|
+
answer: "headless"
|
|
6649
|
+
}
|
|
6650
|
+
)}\`.`;
|
|
6651
|
+
const pending = getPendingOauthFlow({ entryPoint: flow, recoveryMessage });
|
|
6652
|
+
context.authorizationUrl = pending.transaction.browserAuthUrl;
|
|
6653
|
+
callbackUrl = await resolveSetupInput({
|
|
6654
|
+
answer: context.createAnswer(),
|
|
6655
|
+
controller: context.setupController,
|
|
6656
|
+
message: OAUTH_CALLBACK_QUESTION
|
|
6657
|
+
});
|
|
6658
|
+
} else {
|
|
6659
|
+
headless = await selectAuthenticationEnvironment(context) === "headless";
|
|
6660
|
+
if (!step) printAuthCommand({ context, flow, headless });
|
|
6661
|
+
}
|
|
6662
|
+
const authOptions = {
|
|
6663
|
+
headless,
|
|
6664
|
+
...step ? { nonInteractive: true } : {},
|
|
6665
|
+
...callbackUrl !== void 0 ? { callbackUrl } : {}
|
|
6666
|
+
};
|
|
6667
|
+
try {
|
|
6668
|
+
if (newAccount) {
|
|
6669
|
+
await context.authenticateNewAccount({
|
|
6670
|
+
entryPoint: flow,
|
|
6671
|
+
...authOptions
|
|
6672
|
+
});
|
|
6673
|
+
} else {
|
|
6674
|
+
await context.imports[flow](authOptions);
|
|
6675
|
+
}
|
|
6676
|
+
} catch (error) {
|
|
6677
|
+
if (recoveryMessage) console.error(recoveryMessage);
|
|
6678
|
+
if (isCredentialWriteError(error)) {
|
|
6679
|
+
console.error(
|
|
6680
|
+
"Authentication could not write credentials. A permissions or sandbox restriction may be blocking disk access."
|
|
6681
|
+
);
|
|
6682
|
+
}
|
|
6683
|
+
throw error;
|
|
6684
|
+
}
|
|
6685
|
+
return step === "account-environment" && headless ? { step: "authorize", flow } : { step: "confirm-account" };
|
|
6686
|
+
}
|
|
6413
6687
|
var CONNECTIONS_URL = "https://zapier.com/app/assets/connections";
|
|
6414
6688
|
var CONNECTION_DISPLAY_LIMIT = 10;
|
|
6415
|
-
async function
|
|
6416
|
-
const page = await
|
|
6689
|
+
async function showActiveConnections(context) {
|
|
6690
|
+
const page = await context.load({
|
|
6417
6691
|
promise: context.imports.listConnections({
|
|
6418
6692
|
owner: "me",
|
|
6419
6693
|
maxItems: CONNECTION_DISPLAY_LIMIT
|
|
6420
6694
|
}),
|
|
6421
6695
|
label: "Loading app connections"
|
|
6422
6696
|
});
|
|
6423
|
-
if (page.data.length === 0)
|
|
6424
|
-
console.log(
|
|
6425
|
-
`No active connections found. Connect or reconnect an app at ${CONNECTIONS_URL}, then come back and run setup again.`
|
|
6426
|
-
);
|
|
6427
|
-
throw new ZapierCliExitError(
|
|
6428
|
-
"Setup stopped before completion because no active connections are available."
|
|
6429
|
-
);
|
|
6430
|
-
}
|
|
6697
|
+
if (page.data.length === 0) return false;
|
|
6431
6698
|
const table = new Table__default.default({
|
|
6432
6699
|
head: ["App", "Connection"],
|
|
6433
|
-
style: {
|
|
6700
|
+
style: {
|
|
6701
|
+
compact: true,
|
|
6702
|
+
...process.stdout.isTTY ? {} : { head: [], border: [] }
|
|
6703
|
+
}
|
|
6434
6704
|
});
|
|
6435
6705
|
table.push(
|
|
6436
6706
|
...page.data.map((connection) => [
|
|
@@ -6442,11 +6712,22 @@ async function ensureConnectionsAvailable(context) {
|
|
|
6442
6712
|
`Active Zapier connections (showing up to ${CONNECTION_DISPLAY_LIMIT}):`
|
|
6443
6713
|
);
|
|
6444
6714
|
console.log(table.toString());
|
|
6715
|
+
return true;
|
|
6716
|
+
}
|
|
6717
|
+
async function ensureConnectionsAvailable(context) {
|
|
6718
|
+
if (await showActiveConnections(context)) return;
|
|
6719
|
+
console.log(
|
|
6720
|
+
`No active connections found. Connect or reconnect an app at ${CONNECTIONS_URL}, then come back and run setup again.`
|
|
6721
|
+
);
|
|
6722
|
+
throw new ZapierCliExitError(
|
|
6723
|
+
"Setup stopped before completion because no active connections are available."
|
|
6724
|
+
);
|
|
6445
6725
|
}
|
|
6446
6726
|
var CONNECTION_PLACEHOLDER = "__ZAPIER_SDK_SLACK_CONNECTION__";
|
|
6447
6727
|
var EMAIL_PLACEHOLDER = "__ZAPIER_SDK_ACCOUNT_EMAIL__";
|
|
6448
6728
|
var APP_PLACEHOLDER = "__ZAPIER_SDK_SLACK_APP__";
|
|
6449
6729
|
var SLACK_SLUG = "slack";
|
|
6730
|
+
var SLACK_RETRY_QUESTION = "Slack email for one retry after the failed test:";
|
|
6450
6731
|
function getSlackTestPath(context) {
|
|
6451
6732
|
const extension = context.projectLanguage === "typescript" ? "ts" : "mjs";
|
|
6452
6733
|
return path.join("src", "sdk-demo", `zapier-slack-test.${extension}`);
|
|
@@ -6456,7 +6737,7 @@ function getSlackTestTemplatePath(context) {
|
|
|
6456
6737
|
return path.join(TEMPLATES_DIR, "setup", `zapier-slack-test.${extension}`);
|
|
6457
6738
|
}
|
|
6458
6739
|
async function findSlackConnection(context) {
|
|
6459
|
-
const page = await
|
|
6740
|
+
const page = await context.load({
|
|
6460
6741
|
promise: context.imports.listConnections({
|
|
6461
6742
|
owner: "me",
|
|
6462
6743
|
app: SLACK_SLUG,
|
|
@@ -6477,17 +6758,22 @@ function renderSlackTest({
|
|
|
6477
6758
|
}) {
|
|
6478
6759
|
return fs.readFileSync(getSlackTestTemplatePath(context), "utf8").replace(APP_PLACEHOLDER, () => toTemplateString(app)).replace(CONNECTION_PLACEHOLDER, () => toTemplateString(connection)).replace(EMAIL_PLACEHOLDER, () => toTemplateString(email));
|
|
6479
6760
|
}
|
|
6480
|
-
function
|
|
6761
|
+
async function createAndRunSlackTest({
|
|
6481
6762
|
context,
|
|
6482
|
-
app,
|
|
6483
6763
|
connection,
|
|
6484
|
-
email
|
|
6764
|
+
email,
|
|
6765
|
+
overwrite = true
|
|
6485
6766
|
}) {
|
|
6486
6767
|
const slackTestPath = getSlackTestPath(context);
|
|
6487
6768
|
const path2 = path.join(context.cwd, slackTestPath);
|
|
6488
6769
|
if (!fs.existsSync(path.dirname(path2))) fs.mkdirSync(path.dirname(path2), { recursive: true });
|
|
6489
|
-
fs.writeFileSync(
|
|
6770
|
+
fs.writeFileSync(
|
|
6771
|
+
path2,
|
|
6772
|
+
renderSlackTest({ context, app: SLACK_SLUG, connection, email }),
|
|
6773
|
+
{ flag: overwrite ? "w" : "wx" }
|
|
6774
|
+
);
|
|
6490
6775
|
console.log(`Created ${slackTestPath}.`);
|
|
6776
|
+
return trySlackTest(context);
|
|
6491
6777
|
}
|
|
6492
6778
|
async function executeSlackTest(context) {
|
|
6493
6779
|
const slackTestPath = getSlackTestPath(context);
|
|
@@ -6515,75 +6801,76 @@ async function executeSlackTest(context) {
|
|
|
6515
6801
|
async function trySlackTest(context) {
|
|
6516
6802
|
try {
|
|
6517
6803
|
await executeSlackTest(context);
|
|
6804
|
+
(context.outcomes ?? (context.outcomes = {})).slack = "succeeded";
|
|
6518
6805
|
return true;
|
|
6519
6806
|
} catch (error) {
|
|
6807
|
+
(context.outcomes ?? (context.outcomes = {})).slack = "failed";
|
|
6520
6808
|
const message = error instanceof Error ? error.message : String(error);
|
|
6521
6809
|
console.warn(`Slack demo failed: ${message}. Setup will continue.`);
|
|
6522
6810
|
return false;
|
|
6523
6811
|
}
|
|
6524
6812
|
}
|
|
6525
|
-
async function
|
|
6813
|
+
async function runSlackStep({
|
|
6814
|
+
context,
|
|
6815
|
+
step,
|
|
6816
|
+
connection
|
|
6817
|
+
}) {
|
|
6526
6818
|
if (!context.accountEmail) {
|
|
6527
6819
|
console.log("No account email found; skipping the Slack demo.");
|
|
6528
|
-
return;
|
|
6820
|
+
return "handoff";
|
|
6529
6821
|
}
|
|
6530
|
-
|
|
6531
|
-
if (!slackConnection) {
|
|
6822
|
+
if (!connection) {
|
|
6532
6823
|
console.log("No active Slack connection found; skipping the Slack demo.");
|
|
6533
|
-
return;
|
|
6824
|
+
return "handoff";
|
|
6534
6825
|
}
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
answer: context.createAnswer(),
|
|
6538
|
-
controller: context.setupController,
|
|
6539
|
-
message: `Run the Slack self-DM test using ${context.accountEmail}?`,
|
|
6540
|
-
defaultValue: true
|
|
6541
|
-
});
|
|
6542
|
-
if (!shouldRun) return;
|
|
6543
|
-
const path2 = path.join(context.cwd, slackTestPath);
|
|
6544
|
-
if (fs.existsSync(path2)) {
|
|
6545
|
-
const shouldOverwrite = await resolveSetupConfirm({
|
|
6826
|
+
if (step === "slack-retry") {
|
|
6827
|
+
const email = await resolveSetupInput({
|
|
6546
6828
|
answer: context.createAnswer(),
|
|
6547
6829
|
controller: context.setupController,
|
|
6548
|
-
message:
|
|
6549
|
-
defaultValue: false
|
|
6830
|
+
message: SLACK_RETRY_QUESTION
|
|
6550
6831
|
});
|
|
6551
|
-
if (
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
message: `Run the existing ${slackTestPath}?`,
|
|
6557
|
-
defaultValue: false
|
|
6832
|
+
if (email)
|
|
6833
|
+
await createAndRunSlackTest({
|
|
6834
|
+
context,
|
|
6835
|
+
connection: connection.id,
|
|
6836
|
+
email
|
|
6558
6837
|
});
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
}
|
|
6838
|
+
else console.log("Skipping the Slack test.");
|
|
6839
|
+
return "handoff";
|
|
6562
6840
|
}
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
context,
|
|
6566
|
-
app: SLACK_SLUG,
|
|
6567
|
-
connection: slackConnection.id,
|
|
6568
|
-
email
|
|
6569
|
-
});
|
|
6570
|
-
if (await trySlackTest(context)) return;
|
|
6571
|
-
email = await resolveSetupInput({
|
|
6841
|
+
const slackTestPath = getSlackTestPath(context);
|
|
6842
|
+
const shouldRun = await resolveSetupConfirm({
|
|
6572
6843
|
answer: context.createAnswer(),
|
|
6573
6844
|
controller: context.setupController,
|
|
6574
|
-
message: "Slack
|
|
6845
|
+
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}?`,
|
|
6846
|
+
defaultValue: step === "slack"
|
|
6575
6847
|
});
|
|
6576
|
-
if (!
|
|
6577
|
-
|
|
6578
|
-
|
|
6848
|
+
if (!shouldRun) {
|
|
6849
|
+
if (step === "slack-overwrite") {
|
|
6850
|
+
console.log("Keeping the existing Slack test file.");
|
|
6851
|
+
return "slack-existing";
|
|
6852
|
+
}
|
|
6853
|
+
return "handoff";
|
|
6854
|
+
}
|
|
6855
|
+
if (step === "slack" && fs.existsSync(path.join(context.cwd, slackTestPath)))
|
|
6856
|
+
return "slack-overwrite";
|
|
6857
|
+
if (step === "slack-existing") {
|
|
6858
|
+
await trySlackTest(context);
|
|
6859
|
+
return "handoff";
|
|
6579
6860
|
}
|
|
6580
|
-
|
|
6861
|
+
const succeeded = await createAndRunSlackTest({
|
|
6581
6862
|
context,
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6863
|
+
connection: connection.id,
|
|
6864
|
+
email: context.accountEmail,
|
|
6865
|
+
overwrite: step === "slack-overwrite"
|
|
6585
6866
|
});
|
|
6586
|
-
|
|
6867
|
+
return succeeded ? "handoff" : "slack-retry";
|
|
6868
|
+
}
|
|
6869
|
+
async function offerSlackTest(context) {
|
|
6870
|
+
const connection = context.accountEmail ? await findSlackConnection(context) : void 0;
|
|
6871
|
+
let step = "slack";
|
|
6872
|
+
while (step !== "handoff")
|
|
6873
|
+
step = await runSlackStep({ context, step, connection });
|
|
6587
6874
|
}
|
|
6588
6875
|
|
|
6589
6876
|
// src/plugins/setup/skill.ts
|
|
@@ -6609,7 +6896,9 @@ async function installOptionalSkill(context) {
|
|
|
6609
6896
|
cwd: context.cwd,
|
|
6610
6897
|
capture: true
|
|
6611
6898
|
});
|
|
6899
|
+
(context.outcomes ?? (context.outcomes = {})).skill = "succeeded";
|
|
6612
6900
|
} catch {
|
|
6901
|
+
(context.outcomes ?? (context.outcomes = {})).skill = "failed";
|
|
6613
6902
|
console.warn(
|
|
6614
6903
|
`Could not install the optional Zapier SDK skill. To install it manually, run: ${formatPackageCommand(command)}`
|
|
6615
6904
|
);
|
|
@@ -6666,6 +6955,177 @@ async function runWizard(context) {
|
|
|
6666
6955
|
console.log(chalk6__default.default.bgCyan.black.bold(" Next steps "));
|
|
6667
6956
|
await openAgentHandoff(context);
|
|
6668
6957
|
}
|
|
6958
|
+
var UNPROMPTED_STEPS = [
|
|
6959
|
+
"project",
|
|
6960
|
+
"confirm-account",
|
|
6961
|
+
"connections"
|
|
6962
|
+
];
|
|
6963
|
+
var ZapierSetupQuestionSignal = class extends zapierSdk.ZapierSignal {
|
|
6964
|
+
constructor(question) {
|
|
6965
|
+
super(question.message);
|
|
6966
|
+
this.question = question;
|
|
6967
|
+
this.name = "ZapierSetupQuestionSignal";
|
|
6968
|
+
this.code = "ZAPIER_SETUP_QUESTION";
|
|
6969
|
+
}
|
|
6970
|
+
};
|
|
6971
|
+
function isZapierSetupQuestionSignal(error) {
|
|
6972
|
+
return zapierSdk.isZapierSignal(error) && error.code === "ZAPIER_SETUP_QUESTION";
|
|
6973
|
+
}
|
|
6974
|
+
function createSetupAnswer({
|
|
6975
|
+
answer,
|
|
6976
|
+
execute
|
|
6977
|
+
}) {
|
|
6978
|
+
let answered = false;
|
|
6979
|
+
return async ({ result: { question } }) => {
|
|
6980
|
+
if (question.type === "collection")
|
|
6981
|
+
throw new ZapierCliValidationError(
|
|
6982
|
+
"Setup expects a selection or text input."
|
|
6983
|
+
);
|
|
6984
|
+
if (!execute) throw new ZapierSetupQuestionSignal(question);
|
|
6985
|
+
if (answered)
|
|
6986
|
+
throw new ZapierCliValidationError(
|
|
6987
|
+
"Each setup step can answer only one question. Inspect the next question with --agent and run it in a separate command."
|
|
6988
|
+
);
|
|
6989
|
+
answered = true;
|
|
6990
|
+
const confirmation = question.type === "select" && question.choices.some(({ value }) => value === "true") && question.choices.some(({ value }) => value === "false");
|
|
6991
|
+
if (answer === void 0 && !confirmation)
|
|
6992
|
+
throw new ZapierCliValidationError(
|
|
6993
|
+
"This setup step requires --answer. Inspect it with --agent and pass the user's selection or input."
|
|
6994
|
+
);
|
|
6995
|
+
if (question.type === "input")
|
|
6996
|
+
return { type: "custom", value: answer?.trim() ?? "" };
|
|
6997
|
+
const selected = answer?.trim() ?? question.choices[0].value;
|
|
6998
|
+
if (!question.choices.some(({ value }) => value === selected))
|
|
6999
|
+
throw new ZapierCliValidationError(
|
|
7000
|
+
`Answer must be one of: ${question.choices.map(({ value }) => value).join(", ")}.`
|
|
7001
|
+
);
|
|
7002
|
+
return { type: "choose", value: selected };
|
|
7003
|
+
};
|
|
7004
|
+
}
|
|
7005
|
+
async function runSetupStep({
|
|
7006
|
+
context,
|
|
7007
|
+
target
|
|
7008
|
+
}) {
|
|
7009
|
+
switch (target.step) {
|
|
7010
|
+
case "directory":
|
|
7011
|
+
await chooseDirectory(context);
|
|
7012
|
+
return { step: "project" };
|
|
7013
|
+
case "project":
|
|
7014
|
+
await ensureSupportedNode(context);
|
|
7015
|
+
await initializeProject(context);
|
|
7016
|
+
return { step: "install" };
|
|
7017
|
+
case "install":
|
|
7018
|
+
await offerMissingPackageInstall({
|
|
7019
|
+
context,
|
|
7020
|
+
packages: getPackageStates(context).filter(({ declared }) => !declared)
|
|
7021
|
+
});
|
|
7022
|
+
return { step: "sdk-update" };
|
|
7023
|
+
case "sdk-update":
|
|
7024
|
+
case "cli-update": {
|
|
7025
|
+
const name = target.step === "sdk-update" ? "@zapier/zapier-sdk" : "@zapier/zapier-sdk-cli";
|
|
7026
|
+
const packageState = getPackageStates(context).find(
|
|
7027
|
+
({ dependency }) => dependency.name === name
|
|
7028
|
+
);
|
|
7029
|
+
if (packageState) await offerPackageUpdate({ context, packageState });
|
|
7030
|
+
return { step: target.step === "sdk-update" ? "cli-update" : "skill" };
|
|
7031
|
+
}
|
|
7032
|
+
case "skill":
|
|
7033
|
+
await installOptionalSkill(context);
|
|
7034
|
+
return { step: "account" };
|
|
7035
|
+
case "account":
|
|
7036
|
+
case "account-flow":
|
|
7037
|
+
case "account-environment":
|
|
7038
|
+
case "authorize":
|
|
7039
|
+
case "confirm-account":
|
|
7040
|
+
return runAuthenticationStep({ context, options: target });
|
|
7041
|
+
case "connections":
|
|
7042
|
+
if (!await showActiveConnections(context)) {
|
|
7043
|
+
console.log(
|
|
7044
|
+
`No active connections found. Ask the user to connect or reconnect an app at ${CONNECTIONS_URL}. After they confirm, run this exact command:
|
|
7045
|
+
${formatSetupCommand({ context, target })}
|
|
7046
|
+
Success means it prints the active connections table.`
|
|
7047
|
+
);
|
|
7048
|
+
throw new ZapierCliExitError(
|
|
7049
|
+
"Setup stopped until an app connection is active."
|
|
7050
|
+
);
|
|
7051
|
+
}
|
|
7052
|
+
console.log(
|
|
7053
|
+
"Show the user every app and connection title in the table above before continuing. Do not just report that connections were found."
|
|
7054
|
+
);
|
|
7055
|
+
return { step: "slack" };
|
|
7056
|
+
case "slack":
|
|
7057
|
+
case "slack-overwrite":
|
|
7058
|
+
case "slack-existing":
|
|
7059
|
+
case "slack-retry": {
|
|
7060
|
+
const { data: profile } = await context.imports.getProfile({});
|
|
7061
|
+
context.accountEmail = profile.email;
|
|
7062
|
+
return {
|
|
7063
|
+
step: await runSlackStep({
|
|
7064
|
+
context,
|
|
7065
|
+
step: target.step,
|
|
7066
|
+
connection: await findSlackConnection(context)
|
|
7067
|
+
})
|
|
7068
|
+
};
|
|
7069
|
+
}
|
|
7070
|
+
}
|
|
7071
|
+
}
|
|
7072
|
+
async function runAgentSetup({
|
|
7073
|
+
context,
|
|
7074
|
+
options
|
|
7075
|
+
}) {
|
|
7076
|
+
if (options.agent && options.nonInteractive)
|
|
7077
|
+
throw new ZapierCliValidationError(
|
|
7078
|
+
"Use --agent to inspect a step or --non-interactive to execute it, not both."
|
|
7079
|
+
);
|
|
7080
|
+
if (!options.agent && !options.nonInteractive)
|
|
7081
|
+
throw new ZapierCliValidationError(
|
|
7082
|
+
options.step ? "Use --agent to inspect the named step or --non-interactive to execute it." : "--answer, --flow, and --language require a setup step."
|
|
7083
|
+
);
|
|
7084
|
+
if (options.nonInteractive && !options.step)
|
|
7085
|
+
throw new ZapierCliValidationError(
|
|
7086
|
+
"--non-interactive requires --step. Start with setup --agent and follow its printed commands."
|
|
7087
|
+
);
|
|
7088
|
+
if (options.answer !== void 0 && !options.nonInteractive)
|
|
7089
|
+
throw new ZapierCliValidationError("--answer requires --non-interactive.");
|
|
7090
|
+
context.cwd = fs.realpathSync(context.cwd);
|
|
7091
|
+
context.projectLanguage = options.language ?? detectProjectLanguage({
|
|
7092
|
+
cwd: context.cwd,
|
|
7093
|
+
hasExistingProject: fs.existsSync(path.join(context.cwd, "package.json"))
|
|
7094
|
+
});
|
|
7095
|
+
let target = {
|
|
7096
|
+
step: options.step ?? "directory",
|
|
7097
|
+
flow: options.flow
|
|
7098
|
+
};
|
|
7099
|
+
let execute = options.nonInteractive === true;
|
|
7100
|
+
while (true) {
|
|
7101
|
+
const { step, flow } = target;
|
|
7102
|
+
if (step === "handoff") return printAgentCompletion({ context });
|
|
7103
|
+
if (!execute && UNPROMPTED_STEPS.includes(step))
|
|
7104
|
+
return printAgentStep({ context, target });
|
|
7105
|
+
const answer = createSetupAnswer({
|
|
7106
|
+
answer: execute ? options.answer : void 0,
|
|
7107
|
+
execute
|
|
7108
|
+
});
|
|
7109
|
+
context.createAnswer = () => answer;
|
|
7110
|
+
try {
|
|
7111
|
+
const next = await runSetupStep({ context, target: { step, flow } });
|
|
7112
|
+
if (options.language) context.projectLanguage = options.language;
|
|
7113
|
+
if (execute)
|
|
7114
|
+
for (const [operation, outcome] of Object.entries(
|
|
7115
|
+
context.outcomes ?? {}
|
|
7116
|
+
))
|
|
7117
|
+
console.log(`${operation}: ${outcome}`);
|
|
7118
|
+
target = next;
|
|
7119
|
+
execute = false;
|
|
7120
|
+
} catch (error) {
|
|
7121
|
+
if (isZapierSetupQuestionSignal(error))
|
|
7122
|
+
return printAgentStep({ context, target, question: error.question });
|
|
7123
|
+
if (error instanceof ZapierCliUserCancellationError)
|
|
7124
|
+
return printAgentCompletion({ context, cancelled: true });
|
|
7125
|
+
throw error;
|
|
7126
|
+
}
|
|
7127
|
+
}
|
|
7128
|
+
}
|
|
6669
7129
|
|
|
6670
7130
|
// src/plugins/setup/index.ts
|
|
6671
7131
|
var getProfileRef = zapierSdk.declareMethod({ id: "getProfile" });
|
|
@@ -6690,10 +7150,19 @@ var setupPlugin = zapierSdk.defineMethod({
|
|
|
6690
7150
|
supportsJsonOutput: false,
|
|
6691
7151
|
inputSchema: SetupSchema,
|
|
6692
7152
|
output: "raw",
|
|
6693
|
-
run: async ({ imports }) => {
|
|
7153
|
+
run: async ({ imports, input }) => {
|
|
7154
|
+
if (input.agent || input.nonInteractive || [input.step, input.answer, input.flow, input.language].some(
|
|
7155
|
+
(value) => value !== void 0
|
|
7156
|
+
)) {
|
|
7157
|
+
await runAgentSetup({
|
|
7158
|
+
context: createWizardContext({ imports, agent: true }),
|
|
7159
|
+
options: input
|
|
7160
|
+
});
|
|
7161
|
+
return;
|
|
7162
|
+
}
|
|
6694
7163
|
if (process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
|
|
6695
|
-
throw new
|
|
6696
|
-
"`zapier-sdk setup` requires an interactive terminal."
|
|
7164
|
+
throw new ZapierCliValidationError(
|
|
7165
|
+
"`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."
|
|
6697
7166
|
);
|
|
6698
7167
|
}
|
|
6699
7168
|
await runWizard(createWizardContext({ imports }));
|
|
@@ -7183,59 +7652,6 @@ var watchTriggerInboxCliPlugin = zapierSdk.defineMethod({
|
|
|
7183
7652
|
return doWatch();
|
|
7184
7653
|
}
|
|
7185
7654
|
});
|
|
7186
|
-
var createWorkflowRef = experimental.declareMethod({ id: "createWorkflow" });
|
|
7187
|
-
function createPublicInputSchema(schema) {
|
|
7188
|
-
const publicSchema = zod.z.object(
|
|
7189
|
-
Object.fromEntries(
|
|
7190
|
-
Object.entries(schema.shape).filter(
|
|
7191
|
-
([name]) => !experimental.INTERNAL_CREATE_WORKFLOW_FIELDS.includes(
|
|
7192
|
-
name
|
|
7193
|
-
)
|
|
7194
|
-
)
|
|
7195
|
-
)
|
|
7196
|
-
);
|
|
7197
|
-
return schema.description === void 0 ? publicSchema : publicSchema.describe(schema.description);
|
|
7198
|
-
}
|
|
7199
|
-
var CreateWorkflowCliOptionsSchema = createPublicInputSchema(
|
|
7200
|
-
experimental.CreateWorkflowOptionsSchema
|
|
7201
|
-
);
|
|
7202
|
-
experimental.defineMethod({
|
|
7203
|
-
namespace: "cli",
|
|
7204
|
-
name: "createWorkflow",
|
|
7205
|
-
imports: [createWorkflowRef],
|
|
7206
|
-
type: "create",
|
|
7207
|
-
itemType: "Workflow",
|
|
7208
|
-
categories: ["code-workflow"],
|
|
7209
|
-
stability: "experimental",
|
|
7210
|
-
inputSchema: CreateWorkflowCliOptionsSchema,
|
|
7211
|
-
outputSchema: experimental.CreateWorkflowResponseSchema,
|
|
7212
|
-
skipOutputValidation: true,
|
|
7213
|
-
output: "raw",
|
|
7214
|
-
run: ({ imports, input }) => imports.createWorkflow({
|
|
7215
|
-
...input,
|
|
7216
|
-
creationHarness: experimental.getAgent(),
|
|
7217
|
-
creationAccessMethod: "sdk_cli"
|
|
7218
|
-
})
|
|
7219
|
-
});
|
|
7220
|
-
var importWorkflowRef = experimental.declareMethod({ id: "importWorkflow" });
|
|
7221
|
-
experimental.defineMethod({
|
|
7222
|
-
namespace: "cli",
|
|
7223
|
-
name: "importWorkflow",
|
|
7224
|
-
imports: [importWorkflowRef],
|
|
7225
|
-
type: "create",
|
|
7226
|
-
itemType: "Workflow",
|
|
7227
|
-
categories: ["code-workflow"],
|
|
7228
|
-
stability: "experimental",
|
|
7229
|
-
inputSchema: createPublicInputSchema(experimental.ImportWorkflowOptionsSchema),
|
|
7230
|
-
outputSchema: experimental.ImportWorkflowResponseSchema,
|
|
7231
|
-
skipOutputValidation: true,
|
|
7232
|
-
output: "raw",
|
|
7233
|
-
run: ({ imports, input }) => imports.importWorkflow({
|
|
7234
|
-
...input,
|
|
7235
|
-
creationHarness: experimental.getAgent(),
|
|
7236
|
-
creationAccessMethod: "sdk_cli"
|
|
7237
|
-
})
|
|
7238
|
-
});
|
|
7239
7655
|
var activeNotices = /* @__PURE__ */ new Map();
|
|
7240
7656
|
function collectDeprecationNotice(event) {
|
|
7241
7657
|
if (event.type !== zapierSdk.DEPRECATION_NOTICE_EVENT) return;
|
|
@@ -7250,9 +7666,9 @@ function collectDeprecationNoticeAndForward(event, onEvent) {
|
|
|
7250
7666
|
}
|
|
7251
7667
|
|
|
7252
7668
|
// package.json with { type: 'json' }
|
|
7253
|
-
var
|
|
7669
|
+
var package_default2 = {
|
|
7254
7670
|
name: "@zapier/zapier-sdk-cli",
|
|
7255
|
-
version: "0.
|
|
7671
|
+
version: "0.87.2"};
|
|
7256
7672
|
|
|
7257
7673
|
// src/sdk.ts
|
|
7258
7674
|
var warnedDeprecatedMethods = /* @__PURE__ */ new Set();
|
|
@@ -7318,7 +7734,7 @@ function createZapierCliSdk(options = {}) {
|
|
|
7318
7734
|
const stackOptions = {
|
|
7319
7735
|
...sdkOptions,
|
|
7320
7736
|
eventEmission: { ...sdkOptions.eventEmission, callContext: "cli" },
|
|
7321
|
-
callerPackage: { name:
|
|
7737
|
+
callerPackage: { name: package_default2.name, version: package_default2.version },
|
|
7322
7738
|
// Collected for the boxed stderr warning rendered in the exit path. The
|
|
7323
7739
|
// box is additive: the SDK's own inline warn still fires, so the notice
|
|
7324
7740
|
// cannot be hidden by any rendering path.
|
|
@@ -7343,12 +7759,6 @@ function createZapierCliSdk(options = {}) {
|
|
|
7343
7759
|
}
|
|
7344
7760
|
return sdk;
|
|
7345
7761
|
}
|
|
7346
|
-
|
|
7347
|
-
// package.json
|
|
7348
|
-
var package_default2 = {
|
|
7349
|
-
version: "0.86.7"};
|
|
7350
|
-
|
|
7351
|
-
// src/telemetry/builders.ts
|
|
7352
7762
|
function createCliBaseEvent(context = {}) {
|
|
7353
7763
|
return {
|
|
7354
7764
|
event_id: zapierSdk.generateEventId(),
|
|
@@ -7366,7 +7776,7 @@ function createCliBaseEvent(context = {}) {
|
|
|
7366
7776
|
function buildCliCommandExecutedEvent({
|
|
7367
7777
|
data,
|
|
7368
7778
|
context = {},
|
|
7369
|
-
cliVersion =
|
|
7779
|
+
cliVersion = package_default.version
|
|
7370
7780
|
}) {
|
|
7371
7781
|
const osInfo = zapierSdk.getOsInfo();
|
|
7372
7782
|
const platformVersions = zapierSdk.getPlatformVersions();
|