@zapier/zapier-sdk-cli 0.86.7 → 0.87.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -4
- package/CHANGELOG.md +21 -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 +4 -4
package/dist/index.mjs
CHANGED
|
@@ -2,12 +2,12 @@ import * as jwt from 'jsonwebtoken';
|
|
|
2
2
|
import { deletePassword, getPassword, getKeyring, setPassword } from 'cross-keychain';
|
|
3
3
|
import Conf from 'conf';
|
|
4
4
|
import * as fs from 'fs';
|
|
5
|
-
import { promises, createWriteStream, existsSync, readdirSync, readFileSync, rmSync, mkdirSync, writeFileSync, copyFileSync } from 'fs';
|
|
5
|
+
import { promises, createWriteStream, existsSync, readdirSync, realpathSync, readFileSync, rmSync, mkdirSync, writeFileSync, copyFileSync } from 'fs';
|
|
6
6
|
import crypto, { createHash } from 'crypto';
|
|
7
7
|
import * as path from 'path';
|
|
8
8
|
import { resolve, join, dirname, basename, relative, extname } from 'path';
|
|
9
9
|
import * as lockfile from 'proper-lockfile';
|
|
10
|
-
import { definePlugin, apiPlugin, defineMethod, apiPluginRef, resolveCredentialsPluginRef, eventEmissionPluginRef, sdkOptionsPluginRef, declareOptionalProperty, OutputPropertySchema, ZapierBundleError, isZapierBundleError, DEFAULT_CONFIG_PATH, declareMethod, ZapierValidationError, isZapierValidationError, ZapierUnknownError, manifestPluginRef, defineResolver, isPermanentHttpError, isZapierAuthenticationError, ZapierApiError, defineOverride, fetchPlugin, zapierCoreOptions, injectCliLogin, omitExports, zapierSdkPlugin, STABILITY_LEVELS, getConnectionPlugin, invalidateCachedToken, batch, toSnakeCase, ZapierError, isZapierReleaseTriggerMessageSignal, createSdk, SDK_OPTIONS_ID, resolvePlugin, isCredentialsObject, getRegistryPlugin, createController, ZapierAbortDrainSignal, ZapierReleaseTriggerMessageSignal, buildApplicationLifecycleEvent, AuthMechanism, isCoreCancelledSignal, ZapierAuthenticationError, CORE_OPTIONS_ID, addPlugin, formatExtensionPluginFailure, getOsInfo, getPlatformVersions, getAgent
|
|
10
|
+
import { definePlugin, apiPlugin, defineMethod, apiPluginRef, resolveCredentialsPluginRef, eventEmissionPluginRef, sdkOptionsPluginRef, declareOptionalProperty, OutputPropertySchema, ZapierBundleError, isZapierBundleError, DEFAULT_CONFIG_PATH, declareMethod, ZapierValidationError, isZapierValidationError, ZapierUnknownError, manifestPluginRef, defineResolver, isPermanentHttpError, isZapierAuthenticationError, ZapierApiError, defineOverride, fetchPlugin, zapierCoreOptions, injectCliLogin, omitExports, zapierSdkPlugin, STABILITY_LEVELS, getConnectionPlugin, invalidateCachedToken, batch, toSnakeCase, ZapierError, isZapierReleaseTriggerMessageSignal, createSdk, SDK_OPTIONS_ID, resolvePlugin, isCredentialsObject, isZapierSignal, getRegistryPlugin, createController, ZapierAbortDrainSignal, ZapierReleaseTriggerMessageSignal, buildApplicationLifecycleEvent, AuthMechanism, ZapierSignal, isCoreCancelledSignal, ZapierAuthenticationError, CORE_OPTIONS_ID, addPlugin, formatExtensionPluginFailure, getOsInfo, getPlatformVersions, getAgent, getTtyContext, getCiPlatform, isCi, STABILITY_DEFINITIONS, getReleaseId, getCurrentTimestamp, generateEventId, DEPRECATION_NOTICE_EVENT } from '@zapier/zapier-sdk';
|
|
11
11
|
import { z } from 'zod';
|
|
12
12
|
import chalk6 from 'chalk';
|
|
13
13
|
import { hostname } from 'os';
|
|
@@ -30,8 +30,9 @@ import packageJsonLib, { VersionNotFoundError } from 'package-json';
|
|
|
30
30
|
import semver from 'semver';
|
|
31
31
|
import crossSpawn from 'cross-spawn';
|
|
32
32
|
import wrapAnsi from 'wrap-ansi';
|
|
33
|
+
import { createRequire } from 'module';
|
|
33
34
|
import Table from 'cli-table3';
|
|
34
|
-
import { triggerInboxResolver, DrainTriggerInboxSchema, WatchTriggerInboxSchema
|
|
35
|
+
import { triggerInboxResolver, DrainTriggerInboxSchema, WatchTriggerInboxSchema } from '@zapier/zapier-sdk/experimental';
|
|
35
36
|
import 'commander';
|
|
36
37
|
|
|
37
38
|
var __defProp = Object.defineProperty;
|
|
@@ -1011,6 +1012,7 @@ var SENSITIVE_FLAGS = [
|
|
|
1011
1012
|
"--credentials-client-id",
|
|
1012
1013
|
"--credentials-base-url",
|
|
1013
1014
|
"--callback-url",
|
|
1015
|
+
"--answer",
|
|
1014
1016
|
"--user",
|
|
1015
1017
|
"--header",
|
|
1016
1018
|
"-H",
|
|
@@ -1247,6 +1249,7 @@ var searchSelect = createPrompt(
|
|
|
1247
1249
|
);
|
|
1248
1250
|
|
|
1249
1251
|
// src/utils/auth/credentials-picker.ts
|
|
1252
|
+
var CREDENTIALS_PICKER_QUESTION = "Select credentials or add a new account:";
|
|
1250
1253
|
function isSameCredentials(left, right) {
|
|
1251
1254
|
return left.name === right.name && left.baseUrl === right.baseUrl;
|
|
1252
1255
|
}
|
|
@@ -1352,7 +1355,7 @@ async function promptForCredentials({
|
|
|
1352
1355
|
activeCredentials
|
|
1353
1356
|
}) {
|
|
1354
1357
|
return searchSelect({
|
|
1355
|
-
message:
|
|
1358
|
+
message: CREDENTIALS_PICKER_QUESTION,
|
|
1356
1359
|
source: (term) => buildCredentialsChoices({
|
|
1357
1360
|
credentials,
|
|
1358
1361
|
activeCredentials,
|
|
@@ -1415,14 +1418,15 @@ async function switchCredentials({
|
|
|
1415
1418
|
async function chooseStoredLoginCredentialsAtBaseUrl({
|
|
1416
1419
|
baseUrl,
|
|
1417
1420
|
options,
|
|
1418
|
-
resolvedCredentials
|
|
1421
|
+
resolvedCredentials,
|
|
1422
|
+
prompt = promptForCredentials
|
|
1419
1423
|
}) {
|
|
1420
1424
|
if (resolvedCredentials !== void 0 || authFlowOnlyOptions(options).length > 0) {
|
|
1421
1425
|
return "none";
|
|
1422
1426
|
}
|
|
1423
1427
|
const storedCredentials = listStoredCredentials({ baseUrl });
|
|
1424
1428
|
if (storedCredentials.length === 0) return "none";
|
|
1425
|
-
const selection = await
|
|
1429
|
+
const selection = await prompt({
|
|
1426
1430
|
credentials: storedCredentials,
|
|
1427
1431
|
activeCredentials: getActiveCredentials({ baseUrl })
|
|
1428
1432
|
});
|
|
@@ -1436,7 +1440,8 @@ async function chooseStoredLoginCredentialsAtBaseUrl({
|
|
|
1436
1440
|
}
|
|
1437
1441
|
async function chooseStoredLoginCredentials({
|
|
1438
1442
|
imports,
|
|
1439
|
-
options
|
|
1443
|
+
options,
|
|
1444
|
+
prompt
|
|
1440
1445
|
}) {
|
|
1441
1446
|
const resolvedCredentials = await imports.resolveCredentials();
|
|
1442
1447
|
const credentialsBaseUrl = await resolveCredentialsBaseUrl({
|
|
@@ -1446,7 +1451,8 @@ async function chooseStoredLoginCredentials({
|
|
|
1446
1451
|
return chooseStoredLoginCredentialsAtBaseUrl({
|
|
1447
1452
|
baseUrl: credentialsBaseUrl,
|
|
1448
1453
|
options,
|
|
1449
|
-
resolvedCredentials
|
|
1454
|
+
resolvedCredentials,
|
|
1455
|
+
prompt
|
|
1450
1456
|
});
|
|
1451
1457
|
}
|
|
1452
1458
|
async function confirmNewCredentialsName(name) {
|
|
@@ -1817,6 +1823,7 @@ var PendingOauthTransactionSchema = z.object({
|
|
|
1817
1823
|
credentialName: z.string().optional(),
|
|
1818
1824
|
useApprovals: z.boolean(),
|
|
1819
1825
|
headless: z.boolean().default(false),
|
|
1826
|
+
preserveExistingCredentials: z.boolean().default(false),
|
|
1820
1827
|
transaction: OauthTransactionSchema
|
|
1821
1828
|
});
|
|
1822
1829
|
function savePendingOauthTransaction({
|
|
@@ -1826,7 +1833,8 @@ function savePendingOauthTransaction({
|
|
|
1826
1833
|
credentialsBaseUrl,
|
|
1827
1834
|
credentialName,
|
|
1828
1835
|
useApprovals,
|
|
1829
|
-
headless
|
|
1836
|
+
headless,
|
|
1837
|
+
preserveExistingCredentials = false
|
|
1830
1838
|
}) {
|
|
1831
1839
|
const pendingTransaction = {
|
|
1832
1840
|
version: 1,
|
|
@@ -1834,6 +1842,7 @@ function savePendingOauthTransaction({
|
|
|
1834
1842
|
expiresAt,
|
|
1835
1843
|
useApprovals,
|
|
1836
1844
|
headless,
|
|
1845
|
+
preserveExistingCredentials,
|
|
1837
1846
|
transaction,
|
|
1838
1847
|
...credentialsBaseUrl !== void 0 && { credentialsBaseUrl },
|
|
1839
1848
|
...credentialName !== void 0 && { credentialName }
|
|
@@ -1852,6 +1861,7 @@ function clearPendingOauthTransaction() {
|
|
|
1852
1861
|
}
|
|
1853
1862
|
|
|
1854
1863
|
// src/utils/auth/oauth-flow.ts
|
|
1864
|
+
var OAUTH_CALLBACK_QUESTION = "Paste the final OAuth callback URL:";
|
|
1855
1865
|
var PENDING_OAUTH_RECOVERY_MESSAGE = "Start a new non-interactive login or signup flow to generate a fresh URL.";
|
|
1856
1866
|
var LOGIN_OAUTH_COPY = {
|
|
1857
1867
|
flowName: "Login",
|
|
@@ -1915,7 +1925,9 @@ async function startPendingOauthFlow({
|
|
|
1915
1925
|
entryPoint,
|
|
1916
1926
|
credentialName,
|
|
1917
1927
|
useApprovals,
|
|
1918
|
-
headless
|
|
1928
|
+
headless,
|
|
1929
|
+
preserveExistingCredentials = false,
|
|
1930
|
+
silent = false
|
|
1919
1931
|
}) {
|
|
1920
1932
|
const copy = entryPoint === "signup" ? SIGNUP_OAUTH_COPY : LOGIN_OAUTH_COPY;
|
|
1921
1933
|
const port = LOGIN_PORTS[0];
|
|
@@ -1932,8 +1944,10 @@ async function startPendingOauthFlow({
|
|
|
1932
1944
|
credentialsBaseUrl: baseUrl,
|
|
1933
1945
|
credentialName,
|
|
1934
1946
|
useApprovals,
|
|
1935
|
-
headless
|
|
1947
|
+
headless,
|
|
1948
|
+
preserveExistingCredentials
|
|
1936
1949
|
});
|
|
1950
|
+
if (silent) return pending;
|
|
1937
1951
|
process.stderr.write(
|
|
1938
1952
|
`Open this ${copy.urlLabel} in a browser to continue:
|
|
1939
1953
|
`
|
|
@@ -1959,23 +1973,24 @@ async function startPendingOauthFlow({
|
|
|
1959
1973
|
return pending;
|
|
1960
1974
|
}
|
|
1961
1975
|
function getPendingOauthFlow({
|
|
1962
|
-
entryPoint
|
|
1976
|
+
entryPoint,
|
|
1977
|
+
recoveryMessage = PENDING_OAUTH_RECOVERY_MESSAGE
|
|
1963
1978
|
}) {
|
|
1964
1979
|
const pending = getPendingOauthTransaction();
|
|
1965
1980
|
if (!pending) {
|
|
1966
1981
|
throw new ZapierCliValidationError(
|
|
1967
|
-
`No pending ${entryPoint} OAuth flow found. ${
|
|
1982
|
+
`No pending ${entryPoint} OAuth flow found. ${recoveryMessage}`
|
|
1968
1983
|
);
|
|
1969
1984
|
}
|
|
1970
1985
|
if (Date.now() > pending.expiresAt) {
|
|
1971
1986
|
clearPendingOauthTransaction();
|
|
1972
1987
|
throw new ZapierCliValidationError(
|
|
1973
|
-
`Pending ${pending.entryPoint} OAuth flow has expired. ${
|
|
1988
|
+
`Pending ${pending.entryPoint} OAuth flow has expired. ${recoveryMessage}`
|
|
1974
1989
|
);
|
|
1975
1990
|
}
|
|
1976
1991
|
if (pending.entryPoint !== entryPoint) {
|
|
1977
1992
|
throw new ZapierCliValidationError(
|
|
1978
|
-
`Pending OAuth flow is for ${pending.entryPoint}, not ${entryPoint}. ${
|
|
1993
|
+
`Pending OAuth flow is for ${pending.entryPoint}, not ${entryPoint}. ${recoveryMessage}`
|
|
1979
1994
|
);
|
|
1980
1995
|
}
|
|
1981
1996
|
return pending;
|
|
@@ -2138,7 +2153,7 @@ async function readHeadlessCallbackUrl({
|
|
|
2138
2153
|
process.once("SIGINT", handleCancellation);
|
|
2139
2154
|
process.once("SIGTERM", handleCancellation);
|
|
2140
2155
|
if (interactive) {
|
|
2141
|
-
void rl.question(
|
|
2156
|
+
void rl.question(`${OAUTH_CALLBACK_QUESTION} `, {
|
|
2142
2157
|
signal: abortController.signal
|
|
2143
2158
|
}).then(settleResolve).catch((error) => {
|
|
2144
2159
|
if (error instanceof Error && error.name === "AbortError") {
|
|
@@ -2625,7 +2640,7 @@ async function runOauthForEntryPoint({
|
|
|
2625
2640
|
if (event.type === "callback_accepted") {
|
|
2626
2641
|
emitSignupSuccess({
|
|
2627
2642
|
imports,
|
|
2628
|
-
isNonInteractive:
|
|
2643
|
+
isNonInteractive: !interactive,
|
|
2629
2644
|
isHeadless: headless === true
|
|
2630
2645
|
});
|
|
2631
2646
|
}
|
|
@@ -2707,7 +2722,9 @@ async function runAccountAuth({
|
|
|
2707
2722
|
options,
|
|
2708
2723
|
entryPoint,
|
|
2709
2724
|
storedCredentialsMode = "choose",
|
|
2710
|
-
preserveExistingCredentials = false
|
|
2725
|
+
preserveExistingCredentials = false,
|
|
2726
|
+
useBrowserCallback = false,
|
|
2727
|
+
silent = false
|
|
2711
2728
|
}) {
|
|
2712
2729
|
if (options.callbackUrl !== void 0) {
|
|
2713
2730
|
const { callbackUrl } = options;
|
|
@@ -2740,7 +2757,8 @@ async function runAccountAuth({
|
|
|
2740
2757
|
imports,
|
|
2741
2758
|
baseUrl: pending.credentialsBaseUrl,
|
|
2742
2759
|
interactive: false,
|
|
2743
|
-
entryPoint
|
|
2760
|
+
entryPoint,
|
|
2761
|
+
preserveExistingCredentials: pending.preserveExistingCredentials
|
|
2744
2762
|
})) {
|
|
2745
2763
|
return;
|
|
2746
2764
|
}
|
|
@@ -2817,7 +2835,7 @@ async function runAccountAuth({
|
|
|
2817
2835
|
);
|
|
2818
2836
|
}
|
|
2819
2837
|
}
|
|
2820
|
-
if (entryPoint === "login" && !interactive && providedName === void 0) {
|
|
2838
|
+
if (entryPoint === "login" && !interactive && providedName === void 0 && !preserveExistingCredentials) {
|
|
2821
2839
|
const activeCredentials = getActiveCredentials({
|
|
2822
2840
|
baseUrl: credentialsBaseUrl
|
|
2823
2841
|
});
|
|
@@ -2834,7 +2852,7 @@ async function runAccountAuth({
|
|
|
2834
2852
|
}
|
|
2835
2853
|
const timeoutSeconds = parseTimeoutSeconds(options.timeout);
|
|
2836
2854
|
const useApprovals = options.useApprovals === true;
|
|
2837
|
-
if (!interactive) {
|
|
2855
|
+
if (!interactive && (headless || !useBrowserCallback)) {
|
|
2838
2856
|
await startPendingOauthFlow({
|
|
2839
2857
|
entryPoint,
|
|
2840
2858
|
timeoutMs: timeoutSeconds * 1e3,
|
|
@@ -2842,7 +2860,9 @@ async function runAccountAuth({
|
|
|
2842
2860
|
baseUrl: credentialsBaseUrl,
|
|
2843
2861
|
credentialName: providedName,
|
|
2844
2862
|
useApprovals,
|
|
2845
|
-
headless
|
|
2863
|
+
headless,
|
|
2864
|
+
preserveExistingCredentials,
|
|
2865
|
+
silent
|
|
2846
2866
|
});
|
|
2847
2867
|
return;
|
|
2848
2868
|
}
|
|
@@ -2863,7 +2883,7 @@ async function runAccountAuth({
|
|
|
2863
2883
|
credentialName: providedName,
|
|
2864
2884
|
interactive,
|
|
2865
2885
|
useApprovals,
|
|
2866
|
-
isNonInteractive:
|
|
2886
|
+
isNonInteractive: !interactive,
|
|
2867
2887
|
isHeadless: headless
|
|
2868
2888
|
});
|
|
2869
2889
|
}
|
|
@@ -4754,6 +4774,7 @@ function createProjectDir({
|
|
|
4754
4774
|
var TEMPLATES_DIR = fileURLToPath(
|
|
4755
4775
|
new URL("../templates", import.meta.url)
|
|
4756
4776
|
);
|
|
4777
|
+
var SOURCE_CLI_PATH = import.meta.url.endsWith(".ts") ? fileURLToPath(new URL("./cli.ts", import.meta.url)) : void 0;
|
|
4757
4778
|
|
|
4758
4779
|
// src/plugins/init/steps.ts
|
|
4759
4780
|
var DEFAULT_TEMPLATE = "basic";
|
|
@@ -5464,84 +5485,6 @@ async function checkForUpdates({
|
|
|
5464
5485
|
};
|
|
5465
5486
|
}
|
|
5466
5487
|
}
|
|
5467
|
-
var BRAILLE_BLANK = "\u2800";
|
|
5468
|
-
var LIGHTNING_INTERVAL_MILLISECONDS = 140;
|
|
5469
|
-
var boltRows = [
|
|
5470
|
-
"\u2800\u2800\u2880\u28FE\u2800\u2800\u2800\u2800",
|
|
5471
|
-
"\u2800\u2800\u28E0\u28FF\u28FF\u2800\u2800\u2800",
|
|
5472
|
-
"\u2800\u28FC\u28FF\u28FF\u28FF\u28C0\u28C0\u2840",
|
|
5473
|
-
"\u2808\u2809\u2809\u28FF\u28FF\u28FF\u285F\u2800",
|
|
5474
|
-
"\u2800\u2800\u2800\u28FF\u28FF\u280B\u2800\u2800",
|
|
5475
|
-
"\u2800\u2800\u2800\u287F\u2801\u2800\u2800\u2800"
|
|
5476
|
-
];
|
|
5477
|
-
var boltFillOrder = boltRows.flatMap(
|
|
5478
|
-
(row, rowIndex) => [...row].flatMap(
|
|
5479
|
-
(cell, columnIndex) => cell === BRAILLE_BLANK ? [] : rowIndex * row.length + columnIndex
|
|
5480
|
-
)
|
|
5481
|
-
);
|
|
5482
|
-
var fillStages = [
|
|
5483
|
-
...Array.from({ length: boltFillOrder.length + 1 }, (_, index) => index),
|
|
5484
|
-
boltFillOrder.length,
|
|
5485
|
-
0
|
|
5486
|
-
];
|
|
5487
|
-
var boltFillRanks = new Map(
|
|
5488
|
-
boltFillOrder.map((cellIndex, fillIndex) => [cellIndex, fillIndex])
|
|
5489
|
-
);
|
|
5490
|
-
var STATUS_ROW_INDEX = Math.floor(boltRows.length / 2);
|
|
5491
|
-
function formatPhase({ label, detail }) {
|
|
5492
|
-
return detail ? `${chalk6.bold(label)} ${chalk6.dim(detail)}` : chalk6.bold(label);
|
|
5493
|
-
}
|
|
5494
|
-
function formatLoaderFrame({
|
|
5495
|
-
phase,
|
|
5496
|
-
fillStage
|
|
5497
|
-
}) {
|
|
5498
|
-
return boltRows.map((row, rowIndex) => {
|
|
5499
|
-
const bolt = [...row].map((cell, columnIndex) => {
|
|
5500
|
-
if (cell === BRAILLE_BLANK) return cell;
|
|
5501
|
-
const cellIndex = rowIndex * row.length + columnIndex;
|
|
5502
|
-
const fillRank = boltFillRanks.get(cellIndex);
|
|
5503
|
-
const isFilled = fillRank !== void 0 && fillRank < fillStage;
|
|
5504
|
-
return isFilled ? chalk6.bold.yellow(cell) : chalk6.dim.yellow(cell);
|
|
5505
|
-
}).join("");
|
|
5506
|
-
const status = rowIndex === STATUS_ROW_INDEX ? ` ${formatPhase(phase)}` : "";
|
|
5507
|
-
return `${bolt}${status}`;
|
|
5508
|
-
}).join("\n");
|
|
5509
|
-
}
|
|
5510
|
-
async function runWithSetupLoader({
|
|
5511
|
-
promise,
|
|
5512
|
-
...phase
|
|
5513
|
-
}) {
|
|
5514
|
-
const startedAt = Date.now();
|
|
5515
|
-
let fillFrameIndex = 0;
|
|
5516
|
-
const loader = ora({
|
|
5517
|
-
isEnabled: process.stderr.isTTY === true,
|
|
5518
|
-
spinner: { interval: 80, frames: [""] },
|
|
5519
|
-
text: formatLoaderFrame({
|
|
5520
|
-
phase,
|
|
5521
|
-
fillStage: fillStages[fillFrameIndex]
|
|
5522
|
-
})
|
|
5523
|
-
}).start();
|
|
5524
|
-
const animationTimer = setInterval(() => {
|
|
5525
|
-
fillFrameIndex = (fillFrameIndex + 1) % fillStages.length;
|
|
5526
|
-
loader.text = formatLoaderFrame({
|
|
5527
|
-
phase,
|
|
5528
|
-
fillStage: fillStages[fillFrameIndex]
|
|
5529
|
-
});
|
|
5530
|
-
}, LIGHTNING_INTERVAL_MILLISECONDS);
|
|
5531
|
-
animationTimer.unref?.();
|
|
5532
|
-
try {
|
|
5533
|
-
const result = await promise;
|
|
5534
|
-
clearInterval(animationTimer);
|
|
5535
|
-
const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
|
|
5536
|
-
loader.succeed(`${formatPhase(phase)} ${chalk6.dim(`${elapsedSeconds}s`)}`);
|
|
5537
|
-
return result;
|
|
5538
|
-
} catch (error) {
|
|
5539
|
-
clearInterval(animationTimer);
|
|
5540
|
-
const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
|
|
5541
|
-
loader.fail(`${formatPhase(phase)} ${chalk6.dim(`${elapsedSeconds}s`)}`);
|
|
5542
|
-
throw error;
|
|
5543
|
-
}
|
|
5544
|
-
}
|
|
5545
5488
|
function isRecord(value) {
|
|
5546
5489
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5547
5490
|
}
|
|
@@ -5827,7 +5770,7 @@ async function offerPackageUpdate({
|
|
|
5827
5770
|
}) {
|
|
5828
5771
|
const { currentVersion, dependency } = packageState;
|
|
5829
5772
|
if (!currentVersion || !dependency.checkForUpdates) return;
|
|
5830
|
-
const update = await
|
|
5773
|
+
const update = await context.load({
|
|
5831
5774
|
promise: context.checkForUpdates({
|
|
5832
5775
|
packageName: dependency.name,
|
|
5833
5776
|
currentVersion
|
|
@@ -5852,28 +5795,108 @@ async function offerPackageUpdate({
|
|
|
5852
5795
|
})
|
|
5853
5796
|
);
|
|
5854
5797
|
}
|
|
5855
|
-
|
|
5798
|
+
function getPackageStates(context) {
|
|
5856
5799
|
const declaredPackageNames = getDeclaredPackageNames(context.cwd);
|
|
5857
5800
|
const requiredPackages = REQUIRED_PACKAGES.filter(
|
|
5858
5801
|
({ typescriptOnly }) => !typescriptOnly || context.projectLanguage === "typescript"
|
|
5859
5802
|
);
|
|
5860
|
-
|
|
5803
|
+
return requiredPackages.map((dependency) => ({
|
|
5861
5804
|
dependency,
|
|
5805
|
+
declared: declaredPackageNames.has(dependency.name),
|
|
5862
5806
|
currentVersion: declaredPackageNames.has(dependency.name) ? getInstalledPackageVersion({
|
|
5863
5807
|
cwd: context.cwd,
|
|
5864
5808
|
packageName: dependency.name
|
|
5865
5809
|
}) : void 0
|
|
5866
5810
|
}));
|
|
5811
|
+
}
|
|
5812
|
+
async function prepareDependencies(context) {
|
|
5813
|
+
const packages = getPackageStates(context);
|
|
5867
5814
|
await offerMissingPackageInstall({
|
|
5868
5815
|
context,
|
|
5869
|
-
packages: packages.filter(
|
|
5870
|
-
({ dependency }) => !declaredPackageNames.has(dependency.name)
|
|
5871
|
-
)
|
|
5816
|
+
packages: packages.filter(({ declared }) => !declared)
|
|
5872
5817
|
});
|
|
5873
5818
|
for (const packageState of packages) {
|
|
5874
5819
|
await offerPackageUpdate({ context, packageState });
|
|
5875
5820
|
}
|
|
5876
5821
|
}
|
|
5822
|
+
var BRAILLE_BLANK = "\u2800";
|
|
5823
|
+
var LIGHTNING_INTERVAL_MILLISECONDS = 140;
|
|
5824
|
+
var boltRows = [
|
|
5825
|
+
"\u2800\u2800\u2880\u28FE\u2800\u2800\u2800\u2800",
|
|
5826
|
+
"\u2800\u2800\u28E0\u28FF\u28FF\u2800\u2800\u2800",
|
|
5827
|
+
"\u2800\u28FC\u28FF\u28FF\u28FF\u28C0\u28C0\u2840",
|
|
5828
|
+
"\u2808\u2809\u2809\u28FF\u28FF\u28FF\u285F\u2800",
|
|
5829
|
+
"\u2800\u2800\u2800\u28FF\u28FF\u280B\u2800\u2800",
|
|
5830
|
+
"\u2800\u2800\u2800\u287F\u2801\u2800\u2800\u2800"
|
|
5831
|
+
];
|
|
5832
|
+
var boltFillOrder = boltRows.flatMap(
|
|
5833
|
+
(row, rowIndex) => [...row].flatMap(
|
|
5834
|
+
(cell, columnIndex) => cell === BRAILLE_BLANK ? [] : rowIndex * row.length + columnIndex
|
|
5835
|
+
)
|
|
5836
|
+
);
|
|
5837
|
+
var fillStages = [
|
|
5838
|
+
...Array.from({ length: boltFillOrder.length + 1 }, (_, index) => index),
|
|
5839
|
+
boltFillOrder.length,
|
|
5840
|
+
0
|
|
5841
|
+
];
|
|
5842
|
+
var boltFillRanks = new Map(
|
|
5843
|
+
boltFillOrder.map((cellIndex, fillIndex) => [cellIndex, fillIndex])
|
|
5844
|
+
);
|
|
5845
|
+
var STATUS_ROW_INDEX = Math.floor(boltRows.length / 2);
|
|
5846
|
+
function formatPhase({ label, detail }) {
|
|
5847
|
+
return detail ? `${chalk6.bold(label)} ${chalk6.dim(detail)}` : chalk6.bold(label);
|
|
5848
|
+
}
|
|
5849
|
+
function formatLoaderFrame({
|
|
5850
|
+
phase,
|
|
5851
|
+
fillStage
|
|
5852
|
+
}) {
|
|
5853
|
+
return boltRows.map((row, rowIndex) => {
|
|
5854
|
+
const bolt = [...row].map((cell, columnIndex) => {
|
|
5855
|
+
if (cell === BRAILLE_BLANK) return cell;
|
|
5856
|
+
const cellIndex = rowIndex * row.length + columnIndex;
|
|
5857
|
+
const fillRank = boltFillRanks.get(cellIndex);
|
|
5858
|
+
const isFilled = fillRank !== void 0 && fillRank < fillStage;
|
|
5859
|
+
return isFilled ? chalk6.bold.yellow(cell) : chalk6.dim.yellow(cell);
|
|
5860
|
+
}).join("");
|
|
5861
|
+
const status = rowIndex === STATUS_ROW_INDEX ? ` ${formatPhase(phase)}` : "";
|
|
5862
|
+
return `${bolt}${status}`;
|
|
5863
|
+
}).join("\n");
|
|
5864
|
+
}
|
|
5865
|
+
async function runWithSetupLoader({
|
|
5866
|
+
promise,
|
|
5867
|
+
...phase
|
|
5868
|
+
}) {
|
|
5869
|
+
const startedAt = Date.now();
|
|
5870
|
+
let fillFrameIndex = 0;
|
|
5871
|
+
const loader = ora({
|
|
5872
|
+
isEnabled: process.stderr.isTTY === true,
|
|
5873
|
+
spinner: { interval: 80, frames: [""] },
|
|
5874
|
+
text: formatLoaderFrame({
|
|
5875
|
+
phase,
|
|
5876
|
+
fillStage: fillStages[fillFrameIndex]
|
|
5877
|
+
})
|
|
5878
|
+
}).start();
|
|
5879
|
+
const animationTimer = setInterval(() => {
|
|
5880
|
+
fillFrameIndex = (fillFrameIndex + 1) % fillStages.length;
|
|
5881
|
+
loader.text = formatLoaderFrame({
|
|
5882
|
+
phase,
|
|
5883
|
+
fillStage: fillStages[fillFrameIndex]
|
|
5884
|
+
});
|
|
5885
|
+
}, LIGHTNING_INTERVAL_MILLISECONDS);
|
|
5886
|
+
animationTimer.unref?.();
|
|
5887
|
+
try {
|
|
5888
|
+
const result = await promise;
|
|
5889
|
+
clearInterval(animationTimer);
|
|
5890
|
+
const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
|
|
5891
|
+
loader.succeed(`${formatPhase(phase)} ${chalk6.dim(`${elapsedSeconds}s`)}`);
|
|
5892
|
+
return result;
|
|
5893
|
+
} catch (error) {
|
|
5894
|
+
clearInterval(animationTimer);
|
|
5895
|
+
const elapsedSeconds = ((Date.now() - startedAt) / 1e3).toFixed(1);
|
|
5896
|
+
loader.fail(`${formatPhase(phase)} ${chalk6.dim(`${elapsedSeconds}s`)}`);
|
|
5897
|
+
throw error;
|
|
5898
|
+
}
|
|
5899
|
+
}
|
|
5877
5900
|
|
|
5878
5901
|
// src/plugins/setup/package-commands.ts
|
|
5879
5902
|
function createLocalPackageCommand({
|
|
@@ -5912,7 +5935,10 @@ function formatPackageCommand({
|
|
|
5912
5935
|
command,
|
|
5913
5936
|
args
|
|
5914
5937
|
}) {
|
|
5915
|
-
return [command, ...args].join(" ");
|
|
5938
|
+
return [command, ...args].map(quoteShellArgument).join(" ");
|
|
5939
|
+
}
|
|
5940
|
+
function quoteShellArgument(value) {
|
|
5941
|
+
return /^[a-zA-Z0-9_@%+=:,./-]+$/.test(value) ? value : `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
5916
5942
|
}
|
|
5917
5943
|
|
|
5918
5944
|
// src/plugins/setup/project.ts
|
|
@@ -6017,13 +6043,14 @@ async function runCommand({
|
|
|
6017
6043
|
args = [],
|
|
6018
6044
|
cwd,
|
|
6019
6045
|
capture = true,
|
|
6020
|
-
input
|
|
6046
|
+
input,
|
|
6047
|
+
load = runWithSetupLoader
|
|
6021
6048
|
}) {
|
|
6022
6049
|
const commandLabel = `$ ${command} ${args.join(" ")}`.trim();
|
|
6023
6050
|
const execute = capture ? executeCapturedCommand({ command, args, cwd, input }) : executeStreamingCommand({ command, args, cwd, input });
|
|
6024
6051
|
try {
|
|
6025
6052
|
if (capture) {
|
|
6026
|
-
return await
|
|
6053
|
+
return await load({
|
|
6027
6054
|
promise: execute,
|
|
6028
6055
|
label: "Running command",
|
|
6029
6056
|
detail: commandLabel
|
|
@@ -6107,7 +6134,7 @@ function detectProjectLanguage({
|
|
|
6107
6134
|
);
|
|
6108
6135
|
return hasTypeScript ? "typescript" : "javascript";
|
|
6109
6136
|
}
|
|
6110
|
-
async function
|
|
6137
|
+
async function initializeProject(context) {
|
|
6111
6138
|
context.packageManager = detectPackageManager(context.cwd).name;
|
|
6112
6139
|
console.log(`Using ${context.packageManager} for dependency installs.`);
|
|
6113
6140
|
const hasExistingProject = existsSync(join(context.cwd, "package.json"));
|
|
@@ -6123,182 +6150,161 @@ async function prepareProject(context) {
|
|
|
6123
6150
|
cwd: context.cwd
|
|
6124
6151
|
});
|
|
6125
6152
|
}
|
|
6153
|
+
}
|
|
6154
|
+
async function prepareProject(context) {
|
|
6155
|
+
await initializeProject(context);
|
|
6126
6156
|
await prepareDependencies(context);
|
|
6127
6157
|
}
|
|
6128
6158
|
|
|
6129
6159
|
// src/plugins/setup/context.ts
|
|
6130
6160
|
function createWizardContext({
|
|
6131
|
-
imports
|
|
6161
|
+
imports,
|
|
6162
|
+
agent = false
|
|
6132
6163
|
}) {
|
|
6133
|
-
|
|
6164
|
+
const context = {
|
|
6134
6165
|
cwd: process.cwd(),
|
|
6166
|
+
load: agent ? ({ promise }) => promise : runWithSetupLoader,
|
|
6135
6167
|
imports,
|
|
6136
6168
|
createAnswer: () => createCliAnswer({ mode: "closed-list" }),
|
|
6137
6169
|
setupController: createSetupController(),
|
|
6138
|
-
selectStoredLoginCredentials: () => chooseStoredLoginCredentials({
|
|
6139
|
-
|
|
6170
|
+
selectStoredLoginCredentials: () => chooseStoredLoginCredentials({
|
|
6171
|
+
imports,
|
|
6172
|
+
options: {},
|
|
6173
|
+
...agent ? {
|
|
6174
|
+
prompt: async (options) => {
|
|
6175
|
+
const credentialChoices = buildCredentialsChoices(options);
|
|
6176
|
+
const choices = credentialChoices.map(({ name, value }) => ({
|
|
6177
|
+
label: name,
|
|
6178
|
+
value: value.action === "create" ? "create" : `account:${value.credentials.name}`,
|
|
6179
|
+
result: value
|
|
6180
|
+
}));
|
|
6181
|
+
const selected = await resolveSetupSelect({
|
|
6182
|
+
answer: context.createAnswer(),
|
|
6183
|
+
controller: context.setupController,
|
|
6184
|
+
message: CREDENTIALS_PICKER_QUESTION,
|
|
6185
|
+
choices
|
|
6186
|
+
});
|
|
6187
|
+
const selectedIndex = choices.findIndex(
|
|
6188
|
+
({ value }) => value === selected
|
|
6189
|
+
);
|
|
6190
|
+
return choices[selectedIndex].result;
|
|
6191
|
+
}
|
|
6192
|
+
} : {}
|
|
6193
|
+
}),
|
|
6194
|
+
authenticateNewAccount: ({ entryPoint, ...options }) => runAccountAuth({
|
|
6140
6195
|
imports,
|
|
6141
|
-
options
|
|
6196
|
+
options,
|
|
6142
6197
|
entryPoint,
|
|
6143
6198
|
storedCredentialsMode: "fresh",
|
|
6144
|
-
preserveExistingCredentials: true
|
|
6199
|
+
preserveExistingCredentials: true,
|
|
6200
|
+
useBrowserCallback: agent && options.headless === false,
|
|
6201
|
+
silent: agent && options.headless
|
|
6145
6202
|
}),
|
|
6146
6203
|
checkForUpdates,
|
|
6147
6204
|
openUrl: async (url) => {
|
|
6148
6205
|
await open(url);
|
|
6149
6206
|
},
|
|
6150
|
-
runCommand
|
|
6207
|
+
runCommand: agent ? (options) => runCommand({
|
|
6208
|
+
...options,
|
|
6209
|
+
capture: true,
|
|
6210
|
+
load: ({ promise, detail }) => {
|
|
6211
|
+
console.log(detail);
|
|
6212
|
+
return promise;
|
|
6213
|
+
}
|
|
6214
|
+
}) : runCommand,
|
|
6151
6215
|
packageManager: detectPackageManager(process.cwd()).name,
|
|
6152
6216
|
projectLanguage: "typescript"
|
|
6153
6217
|
};
|
|
6218
|
+
return context;
|
|
6219
|
+
}
|
|
6220
|
+
var SetupStepSchema = z.enum([
|
|
6221
|
+
"directory",
|
|
6222
|
+
"project",
|
|
6223
|
+
"install",
|
|
6224
|
+
"sdk-update",
|
|
6225
|
+
"cli-update",
|
|
6226
|
+
"skill",
|
|
6227
|
+
"account",
|
|
6228
|
+
"account-flow",
|
|
6229
|
+
"account-environment",
|
|
6230
|
+
"authorize",
|
|
6231
|
+
"confirm-account",
|
|
6232
|
+
"connections",
|
|
6233
|
+
"slack",
|
|
6234
|
+
"slack-overwrite",
|
|
6235
|
+
"slack-existing",
|
|
6236
|
+
"slack-retry",
|
|
6237
|
+
"handoff"
|
|
6238
|
+
]);
|
|
6239
|
+
var SetupSchema = z.object({
|
|
6240
|
+
agent: z.boolean().optional().describe(
|
|
6241
|
+
"For AI agents and callers without a terminal: print the next setup question and the exact command to run for each answer."
|
|
6242
|
+
),
|
|
6243
|
+
step: SetupStepSchema.optional().describe(
|
|
6244
|
+
"Setup operation to inspect or execute."
|
|
6245
|
+
),
|
|
6246
|
+
nonInteractive: z.boolean().optional().describe("Execute the named setup step without terminal prompts."),
|
|
6247
|
+
answer: z.string().optional().describe(
|
|
6248
|
+
"User selection or input for a non-interactive setup step. Omitted confirmations use the terminal wizard's default."
|
|
6249
|
+
),
|
|
6250
|
+
flow: z.enum(["login", "signup"]).optional().describe(
|
|
6251
|
+
"Account flow selected for the environment and OAuth callback steps."
|
|
6252
|
+
),
|
|
6253
|
+
language: z.enum(["javascript", "typescript"]).optional().describe(
|
|
6254
|
+
"Project language for dependency installation and the Slack demo."
|
|
6255
|
+
)
|
|
6256
|
+
}).describe(
|
|
6257
|
+
"Set up the Zapier SDK in an existing or new project. Runs an interactive terminal wizard; AI agents should use --agent instead."
|
|
6258
|
+
);
|
|
6259
|
+
|
|
6260
|
+
// package.json
|
|
6261
|
+
var package_default = {
|
|
6262
|
+
version: "0.87.1"};
|
|
6263
|
+
var agentLabels = {
|
|
6264
|
+
claude: "Claude Code",
|
|
6265
|
+
codex: "Codex",
|
|
6266
|
+
cursor: "Cursor",
|
|
6267
|
+
"vscode-copilot": "VS Code Copilot"
|
|
6268
|
+
};
|
|
6269
|
+
function buildAgentPrompt({
|
|
6270
|
+
context
|
|
6271
|
+
}) {
|
|
6272
|
+
const listConnectionsCommand = formatPackageCommand(
|
|
6273
|
+
createLocalPackageCommand({
|
|
6274
|
+
packageManager: context.packageManager,
|
|
6275
|
+
binary: "zapier-sdk",
|
|
6276
|
+
args: ["list-connections", "--owner", "me", "--json"]
|
|
6277
|
+
})
|
|
6278
|
+
);
|
|
6279
|
+
const listActionsCommand = formatPackageCommand(
|
|
6280
|
+
createLocalPackageCommand({
|
|
6281
|
+
packageManager: context.packageManager,
|
|
6282
|
+
binary: "zapier-sdk",
|
|
6283
|
+
args: ["list-actions", "APP_KEY"]
|
|
6284
|
+
})
|
|
6285
|
+
);
|
|
6286
|
+
return `Start by running this command to discover my active connected apps outside of your sandbox:
|
|
6287
|
+
|
|
6288
|
+
${listConnectionsCommand}
|
|
6289
|
+
|
|
6290
|
+
Using the connected apps returned by that command:
|
|
6291
|
+
|
|
6292
|
+
- Pick 1-3 apps and show commands I can use to explore their actions, such as: ${listActionsCommand}
|
|
6293
|
+
- Do not run those list-actions commands.
|
|
6294
|
+
- Suggest 3 specific ideas based on my connected apps. Each idea should read from one app, optionally process data, and write to another.
|
|
6295
|
+
- Do not suggest event-driven workflows.
|
|
6296
|
+
- Keep each idea to one sentence. Example: "pull in-progress Jira issues and DM yourself a summary on Slack".
|
|
6297
|
+
|
|
6298
|
+
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.`;
|
|
6154
6299
|
}
|
|
6155
|
-
|
|
6156
|
-
function printAuthCommand({
|
|
6300
|
+
function printAgentPrompt({
|
|
6157
6301
|
context,
|
|
6158
|
-
|
|
6159
|
-
headless
|
|
6302
|
+
message
|
|
6160
6303
|
}) {
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
});
|
|
6166
|
-
console.log(`$ ${formatPackageCommand(command)}`);
|
|
6167
|
-
if (headless) {
|
|
6168
|
-
console.log(
|
|
6169
|
-
"Open the printed URL in another browser, then paste the final OAuth callback URL when prompted."
|
|
6170
|
-
);
|
|
6171
|
-
}
|
|
6172
|
-
}
|
|
6173
|
-
function isCredentialWriteError(error) {
|
|
6174
|
-
const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "";
|
|
6175
|
-
if (/^(eacces|eperm)$/i.test(code)) return true;
|
|
6176
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
6177
|
-
return /permission|sandbox|eacces|eperm/i.test(message);
|
|
6178
|
-
}
|
|
6179
|
-
async function confirmAuthentication(context) {
|
|
6180
|
-
const { data: profile } = await runWithSetupLoader({
|
|
6181
|
-
promise: context.imports.getProfile({}),
|
|
6182
|
-
label: "Confirming Zapier account"
|
|
6183
|
-
});
|
|
6184
|
-
context.accountEmail = profile.email;
|
|
6185
|
-
console.log(`Authenticated as ${profile.email}.`);
|
|
6186
|
-
}
|
|
6187
|
-
async function authenticate(context) {
|
|
6188
|
-
const activeProfile = await runWithSetupLoader({
|
|
6189
|
-
promise: context.imports.getProfile({}).then(({ data }) => data).catch((error) => {
|
|
6190
|
-
if (isZapierAuthenticationError(error)) return void 0;
|
|
6191
|
-
throw error;
|
|
6192
|
-
}),
|
|
6193
|
-
label: "Checking Zapier authentication"
|
|
6194
|
-
});
|
|
6195
|
-
const storedCredentialsSelection = await context.selectStoredLoginCredentials();
|
|
6196
|
-
if (storedCredentialsSelection === "switch") {
|
|
6197
|
-
await confirmAuthentication(context);
|
|
6198
|
-
return;
|
|
6199
|
-
}
|
|
6200
|
-
if (storedCredentialsSelection === "none" && activeProfile) {
|
|
6201
|
-
const shouldLogout = await resolveSetupConfirm({
|
|
6202
|
-
answer: context.createAnswer(),
|
|
6203
|
-
controller: context.setupController,
|
|
6204
|
-
message: `You are already logged in as "${activeProfile.email}".
|
|
6205
|
-
Logging out will delete these credentials and may interrupt other Zapier SDK or CLI sessions using them.
|
|
6206
|
-
Log out and use a different account?`,
|
|
6207
|
-
defaultValue: false
|
|
6208
|
-
});
|
|
6209
|
-
if (!shouldLogout) {
|
|
6210
|
-
context.accountEmail = activeProfile.email;
|
|
6211
|
-
console.log(`Continuing as ${activeProfile.email}.`);
|
|
6212
|
-
return;
|
|
6213
|
-
}
|
|
6214
|
-
const logoutCommand = createLocalPackageCommand({
|
|
6215
|
-
packageManager: context.packageManager,
|
|
6216
|
-
binary: "zapier-sdk",
|
|
6217
|
-
args: ["logout"]
|
|
6218
|
-
});
|
|
6219
|
-
console.log(`$ ${formatPackageCommand(logoutCommand)}`);
|
|
6220
|
-
await context.imports.logout({});
|
|
6221
|
-
}
|
|
6222
|
-
const flow = await resolveSetupSelect({
|
|
6223
|
-
answer: context.createAnswer(),
|
|
6224
|
-
controller: context.setupController,
|
|
6225
|
-
message: "Zapier account:",
|
|
6226
|
-
choices: [
|
|
6227
|
-
{ label: "Log in to an existing account", value: "login" },
|
|
6228
|
-
{ label: "Create a new Zapier account", value: "signup" }
|
|
6229
|
-
]
|
|
6230
|
-
});
|
|
6231
|
-
const environment = await resolveSetupSelect({
|
|
6232
|
-
answer: context.createAnswer(),
|
|
6233
|
-
controller: context.setupController,
|
|
6234
|
-
message: "Environment:",
|
|
6235
|
-
choices: [
|
|
6236
|
-
{ label: "Local machine with a browser", value: "local" },
|
|
6237
|
-
{ label: "Remote or headless", value: "headless" }
|
|
6238
|
-
]
|
|
6239
|
-
});
|
|
6240
|
-
const headless = environment === "headless";
|
|
6241
|
-
printAuthCommand({ context, flow, headless });
|
|
6242
|
-
try {
|
|
6243
|
-
if (storedCredentialsSelection === "create") {
|
|
6244
|
-
await context.authenticateNewAccount({ entryPoint: flow, headless });
|
|
6245
|
-
} else {
|
|
6246
|
-
const runAuth = flow === "login" ? context.imports.login : context.imports.signup;
|
|
6247
|
-
await runAuth({ headless });
|
|
6248
|
-
}
|
|
6249
|
-
} catch (error) {
|
|
6250
|
-
if (isCredentialWriteError(error)) {
|
|
6251
|
-
console.error(
|
|
6252
|
-
"Authentication could not write credentials. A permissions or sandbox restriction may be blocking disk access."
|
|
6253
|
-
);
|
|
6254
|
-
}
|
|
6255
|
-
throw error;
|
|
6256
|
-
}
|
|
6257
|
-
await confirmAuthentication(context);
|
|
6258
|
-
}
|
|
6259
|
-
var agentLabels = {
|
|
6260
|
-
claude: "Claude Code",
|
|
6261
|
-
codex: "Codex",
|
|
6262
|
-
cursor: "Cursor",
|
|
6263
|
-
"vscode-copilot": "VS Code Copilot"
|
|
6264
|
-
};
|
|
6265
|
-
function buildAgentPrompt({ context }) {
|
|
6266
|
-
const listConnectionsCommand = formatPackageCommand(
|
|
6267
|
-
createLocalPackageCommand({
|
|
6268
|
-
packageManager: context.packageManager,
|
|
6269
|
-
binary: "zapier-sdk",
|
|
6270
|
-
args: ["list-connections", "--owner", "me", "--json"]
|
|
6271
|
-
})
|
|
6272
|
-
);
|
|
6273
|
-
const listActionsCommand = formatPackageCommand(
|
|
6274
|
-
createLocalPackageCommand({
|
|
6275
|
-
packageManager: context.packageManager,
|
|
6276
|
-
binary: "zapier-sdk",
|
|
6277
|
-
args: ["list-actions", "APP_KEY"]
|
|
6278
|
-
})
|
|
6279
|
-
);
|
|
6280
|
-
return `Start by running this command to discover my active connected apps outside of your sandbox:
|
|
6281
|
-
|
|
6282
|
-
${listConnectionsCommand}
|
|
6283
|
-
|
|
6284
|
-
Using the connected apps returned by that command:
|
|
6285
|
-
|
|
6286
|
-
- Pick 1-3 apps and show commands I can use to explore their actions, such as: ${listActionsCommand}
|
|
6287
|
-
- Do not run those list-actions commands.
|
|
6288
|
-
- Suggest 3 specific ideas based on my connected apps. Each idea should read from one app, optionally process data, and write to another.
|
|
6289
|
-
- Do not suggest event-driven workflows.
|
|
6290
|
-
- Keep each idea to one sentence. Example: "pull in-progress Jira issues and DM yourself a summary on Slack".
|
|
6291
|
-
|
|
6292
|
-
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.`;
|
|
6293
|
-
}
|
|
6294
|
-
function printAgentPrompt({
|
|
6295
|
-
context,
|
|
6296
|
-
message
|
|
6297
|
-
}) {
|
|
6298
|
-
console.log();
|
|
6299
|
-
console.log(chalk6.bgYellow.black.bold(message));
|
|
6300
|
-
console.log();
|
|
6301
|
-
console.log(buildAgentPrompt({ context }));
|
|
6304
|
+
console.log();
|
|
6305
|
+
console.log(chalk6.bgYellow.black.bold(message));
|
|
6306
|
+
console.log();
|
|
6307
|
+
console.log(buildAgentPrompt({ context }));
|
|
6302
6308
|
}
|
|
6303
6309
|
async function openAgentHandoff(context) {
|
|
6304
6310
|
const agent = await resolveSetupSelect({
|
|
@@ -6369,27 +6375,291 @@ async function openAgentHandoff(context) {
|
|
|
6369
6375
|
message: "If it didn't load correctly, paste this prompt into your agent:"
|
|
6370
6376
|
});
|
|
6371
6377
|
}
|
|
6378
|
+
|
|
6379
|
+
// src/plugins/setup/agent-output.ts
|
|
6380
|
+
var REQUIRED_STEPS = [
|
|
6381
|
+
"directory",
|
|
6382
|
+
"install"
|
|
6383
|
+
];
|
|
6384
|
+
function formatSetupCommand({
|
|
6385
|
+
context,
|
|
6386
|
+
target,
|
|
6387
|
+
answer
|
|
6388
|
+
}) {
|
|
6389
|
+
const args = [
|
|
6390
|
+
"setup",
|
|
6391
|
+
"--step",
|
|
6392
|
+
target.step,
|
|
6393
|
+
"--non-interactive",
|
|
6394
|
+
...target.flow ? ["--flow", target.flow] : [],
|
|
6395
|
+
"--language",
|
|
6396
|
+
context.projectLanguage,
|
|
6397
|
+
...answer !== void 0 ? ["--answer", answer] : []
|
|
6398
|
+
];
|
|
6399
|
+
return formatPackageCommand(
|
|
6400
|
+
SOURCE_CLI_PATH ? {
|
|
6401
|
+
command: process.execPath,
|
|
6402
|
+
args: [
|
|
6403
|
+
"--import",
|
|
6404
|
+
createRequire(import.meta.url).resolve("tsx"),
|
|
6405
|
+
"--conditions",
|
|
6406
|
+
"source",
|
|
6407
|
+
SOURCE_CLI_PATH,
|
|
6408
|
+
...args
|
|
6409
|
+
]
|
|
6410
|
+
} : createPackageRunnerCommand({
|
|
6411
|
+
packageManager: context.packageManager,
|
|
6412
|
+
packageName: `@zapier/zapier-sdk-cli@${package_default.version}`,
|
|
6413
|
+
args
|
|
6414
|
+
})
|
|
6415
|
+
);
|
|
6416
|
+
}
|
|
6417
|
+
function printAgentStep({
|
|
6418
|
+
context,
|
|
6419
|
+
target,
|
|
6420
|
+
question
|
|
6421
|
+
}) {
|
|
6422
|
+
console.log(
|
|
6423
|
+
`Step: ${target.step}
|
|
6424
|
+
Working directory: ${context.cwd}
|
|
6425
|
+
Detected package manager: ${context.packageManager}
|
|
6426
|
+
Project language: ${context.projectLanguage}`
|
|
6427
|
+
);
|
|
6428
|
+
if (!question) {
|
|
6429
|
+
console.log(
|
|
6430
|
+
`Run this exact command:
|
|
6431
|
+
${formatSetupCommand({ context, target })}`
|
|
6432
|
+
);
|
|
6433
|
+
} else {
|
|
6434
|
+
if (target.step === "authorize" && context.authorizationUrl)
|
|
6435
|
+
console.log(
|
|
6436
|
+
`Give the user this URL to open in a browser where they can sign in to Zapier:
|
|
6437
|
+
${context.authorizationUrl}
|
|
6438
|
+
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.`
|
|
6439
|
+
);
|
|
6440
|
+
console.log(`Ask the user this question verbatim: "${question.message}"`);
|
|
6441
|
+
if (question.type === "select") {
|
|
6442
|
+
for (const { value, label } of question.choices)
|
|
6443
|
+
console.log(`${JSON.stringify(value)}: ${label}`);
|
|
6444
|
+
for (const { value } of question.choices) {
|
|
6445
|
+
const decision = value === "true" ? "agrees" : value === "false" ? "declines" : `chooses ${JSON.stringify(value)}`;
|
|
6446
|
+
if (value === "false" && REQUIRED_STEPS.includes(target.step))
|
|
6447
|
+
console.log("If the user declines, stop setup.");
|
|
6448
|
+
else
|
|
6449
|
+
console.log(
|
|
6450
|
+
`If the user ${decision}, run this exact command:
|
|
6451
|
+
${formatSetupCommand({ context, target, answer: value })}`
|
|
6452
|
+
);
|
|
6453
|
+
}
|
|
6454
|
+
} else {
|
|
6455
|
+
console.log(
|
|
6456
|
+
`Run this exact command with their answer as one shell-quoted argument (an empty answer is ''):
|
|
6457
|
+
${formatSetupCommand({ context, target, answer: "<answer>" })}`
|
|
6458
|
+
);
|
|
6459
|
+
}
|
|
6460
|
+
if (target.step === "account-environment")
|
|
6461
|
+
console.log(
|
|
6462
|
+
`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.`
|
|
6463
|
+
);
|
|
6464
|
+
console.log(
|
|
6465
|
+
"Use your tool for asking the user questions if you have one. Do not answer on the user's behalf."
|
|
6466
|
+
);
|
|
6467
|
+
}
|
|
6468
|
+
console.log(
|
|
6469
|
+
"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."
|
|
6470
|
+
);
|
|
6471
|
+
}
|
|
6472
|
+
function printAgentCompletion({
|
|
6473
|
+
context,
|
|
6474
|
+
cancelled = false
|
|
6475
|
+
}) {
|
|
6476
|
+
console.log(
|
|
6477
|
+
cancelled ? "Setup cancelled." : `Setup walkthrough finished. Report which operations succeeded, failed, or were skipped based on their command results.
|
|
6478
|
+
Learn more: https://docs.zapier.com/sdk
|
|
6479
|
+
|
|
6480
|
+
Continue in this agent. Do not open another agent or ask the user to choose one.
|
|
6481
|
+
${buildAgentPrompt({ context })}`
|
|
6482
|
+
);
|
|
6483
|
+
}
|
|
6484
|
+
|
|
6485
|
+
// src/plugins/setup/authentication.ts
|
|
6486
|
+
function printAuthCommand({
|
|
6487
|
+
context,
|
|
6488
|
+
flow,
|
|
6489
|
+
headless = false
|
|
6490
|
+
}) {
|
|
6491
|
+
const command = createLocalPackageCommand({
|
|
6492
|
+
packageManager: context.packageManager,
|
|
6493
|
+
binary: "zapier-sdk",
|
|
6494
|
+
args: [flow, ...headless ? ["--headless"] : []]
|
|
6495
|
+
});
|
|
6496
|
+
console.log(`$ ${formatPackageCommand(command)}`);
|
|
6497
|
+
if (headless) {
|
|
6498
|
+
console.log(
|
|
6499
|
+
"Open the printed URL in another browser, then paste the final OAuth callback URL when prompted."
|
|
6500
|
+
);
|
|
6501
|
+
}
|
|
6502
|
+
}
|
|
6503
|
+
function isCredentialWriteError(error) {
|
|
6504
|
+
const code = typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "";
|
|
6505
|
+
if (/^(eacces|eperm)$/i.test(code)) return true;
|
|
6506
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6507
|
+
return /permission|sandbox|eacces|eperm/i.test(message);
|
|
6508
|
+
}
|
|
6509
|
+
async function confirmAuthentication(context) {
|
|
6510
|
+
const { data: profile } = await context.load({
|
|
6511
|
+
promise: context.imports.getProfile({}),
|
|
6512
|
+
label: "Confirming Zapier account"
|
|
6513
|
+
});
|
|
6514
|
+
context.accountEmail = profile.email;
|
|
6515
|
+
console.log(`Authenticated as ${profile.email}.`);
|
|
6516
|
+
}
|
|
6517
|
+
function selectAccountFlow(context) {
|
|
6518
|
+
return resolveSetupSelect({
|
|
6519
|
+
answer: context.createAnswer(),
|
|
6520
|
+
controller: context.setupController,
|
|
6521
|
+
message: "Zapier account:",
|
|
6522
|
+
choices: [
|
|
6523
|
+
{ label: "Log in to an existing account", value: "login" },
|
|
6524
|
+
{ label: "Create a new Zapier account", value: "signup" }
|
|
6525
|
+
]
|
|
6526
|
+
});
|
|
6527
|
+
}
|
|
6528
|
+
function selectAuthenticationEnvironment(context) {
|
|
6529
|
+
return resolveSetupSelect({
|
|
6530
|
+
answer: context.createAnswer(),
|
|
6531
|
+
controller: context.setupController,
|
|
6532
|
+
message: "Environment:",
|
|
6533
|
+
choices: [
|
|
6534
|
+
{ label: "Local machine with a browser", value: "local" },
|
|
6535
|
+
{ label: "Remote or headless", value: "headless" }
|
|
6536
|
+
]
|
|
6537
|
+
});
|
|
6538
|
+
}
|
|
6539
|
+
async function selectAccount(context) {
|
|
6540
|
+
const activeProfile = await context.load({
|
|
6541
|
+
promise: context.imports.getProfile({}).then(({ data }) => data).catch((error) => {
|
|
6542
|
+
if (isZapierAuthenticationError(error)) return void 0;
|
|
6543
|
+
throw error;
|
|
6544
|
+
}),
|
|
6545
|
+
label: "Checking Zapier authentication"
|
|
6546
|
+
});
|
|
6547
|
+
const storedCredentialsSelection = await context.selectStoredLoginCredentials();
|
|
6548
|
+
if (storedCredentialsSelection === "none" && activeProfile) {
|
|
6549
|
+
const shouldLogout = await resolveSetupConfirm({
|
|
6550
|
+
answer: context.createAnswer(),
|
|
6551
|
+
controller: context.setupController,
|
|
6552
|
+
message: `You are already logged in as "${activeProfile.email}".
|
|
6553
|
+
Logging out will delete these credentials and may interrupt other Zapier SDK or CLI sessions using them.
|
|
6554
|
+
Log out and use a different account?`,
|
|
6555
|
+
defaultValue: false
|
|
6556
|
+
});
|
|
6557
|
+
if (!shouldLogout) {
|
|
6558
|
+
context.accountEmail = activeProfile.email;
|
|
6559
|
+
console.log(`Continuing as ${activeProfile.email}.`);
|
|
6560
|
+
return "continue";
|
|
6561
|
+
}
|
|
6562
|
+
printAuthCommand({ context, flow: "logout" });
|
|
6563
|
+
await context.imports.logout({});
|
|
6564
|
+
}
|
|
6565
|
+
return storedCredentialsSelection;
|
|
6566
|
+
}
|
|
6567
|
+
async function authenticate(context) {
|
|
6568
|
+
const next = await runAuthenticationStep({ context, options: {} });
|
|
6569
|
+
if (next.step === "confirm-account") await confirmAuthentication(context);
|
|
6570
|
+
}
|
|
6571
|
+
async function runAuthenticationStep({
|
|
6572
|
+
context,
|
|
6573
|
+
options
|
|
6574
|
+
}) {
|
|
6575
|
+
const { step } = options;
|
|
6576
|
+
let newAccount = step === "account-environment";
|
|
6577
|
+
if (!step || step === "account") {
|
|
6578
|
+
const selection = await selectAccount(context);
|
|
6579
|
+
if (selection === "switch") return { step: "confirm-account" };
|
|
6580
|
+
if (selection === "continue")
|
|
6581
|
+
return { step: step ? "confirm-account" : "connections" };
|
|
6582
|
+
if (step) return { step: "account-flow" };
|
|
6583
|
+
newAccount = selection === "create";
|
|
6584
|
+
}
|
|
6585
|
+
if (step === "confirm-account") {
|
|
6586
|
+
await confirmAuthentication(context);
|
|
6587
|
+
return { step: "connections" };
|
|
6588
|
+
}
|
|
6589
|
+
const flow = !step || step === "account-flow" ? await selectAccountFlow(context) : options.flow;
|
|
6590
|
+
if (step === "account-flow")
|
|
6591
|
+
return {
|
|
6592
|
+
step: "account-environment",
|
|
6593
|
+
flow
|
|
6594
|
+
};
|
|
6595
|
+
if (!flow)
|
|
6596
|
+
throw new ZapierCliValidationError(
|
|
6597
|
+
"This setup step requires --flow login or --flow signup."
|
|
6598
|
+
);
|
|
6599
|
+
let headless = true;
|
|
6600
|
+
let callbackUrl;
|
|
6601
|
+
let recoveryMessage;
|
|
6602
|
+
if (step === "authorize") {
|
|
6603
|
+
recoveryMessage = `Generate a fresh authorization URL with \`${formatSetupCommand(
|
|
6604
|
+
{
|
|
6605
|
+
context,
|
|
6606
|
+
target: { step: "account-environment", flow },
|
|
6607
|
+
answer: "headless"
|
|
6608
|
+
}
|
|
6609
|
+
)}\`.`;
|
|
6610
|
+
const pending = getPendingOauthFlow({ entryPoint: flow, recoveryMessage });
|
|
6611
|
+
context.authorizationUrl = pending.transaction.browserAuthUrl;
|
|
6612
|
+
callbackUrl = await resolveSetupInput({
|
|
6613
|
+
answer: context.createAnswer(),
|
|
6614
|
+
controller: context.setupController,
|
|
6615
|
+
message: OAUTH_CALLBACK_QUESTION
|
|
6616
|
+
});
|
|
6617
|
+
} else {
|
|
6618
|
+
headless = await selectAuthenticationEnvironment(context) === "headless";
|
|
6619
|
+
if (!step) printAuthCommand({ context, flow, headless });
|
|
6620
|
+
}
|
|
6621
|
+
const authOptions = {
|
|
6622
|
+
headless,
|
|
6623
|
+
...step ? { nonInteractive: true } : {},
|
|
6624
|
+
...callbackUrl !== void 0 ? { callbackUrl } : {}
|
|
6625
|
+
};
|
|
6626
|
+
try {
|
|
6627
|
+
if (newAccount) {
|
|
6628
|
+
await context.authenticateNewAccount({
|
|
6629
|
+
entryPoint: flow,
|
|
6630
|
+
...authOptions
|
|
6631
|
+
});
|
|
6632
|
+
} else {
|
|
6633
|
+
await context.imports[flow](authOptions);
|
|
6634
|
+
}
|
|
6635
|
+
} catch (error) {
|
|
6636
|
+
if (recoveryMessage) console.error(recoveryMessage);
|
|
6637
|
+
if (isCredentialWriteError(error)) {
|
|
6638
|
+
console.error(
|
|
6639
|
+
"Authentication could not write credentials. A permissions or sandbox restriction may be blocking disk access."
|
|
6640
|
+
);
|
|
6641
|
+
}
|
|
6642
|
+
throw error;
|
|
6643
|
+
}
|
|
6644
|
+
return step === "account-environment" && headless ? { step: "authorize", flow } : { step: "confirm-account" };
|
|
6645
|
+
}
|
|
6372
6646
|
var CONNECTIONS_URL = "https://zapier.com/app/assets/connections";
|
|
6373
6647
|
var CONNECTION_DISPLAY_LIMIT = 10;
|
|
6374
|
-
async function
|
|
6375
|
-
const page = await
|
|
6648
|
+
async function showActiveConnections(context) {
|
|
6649
|
+
const page = await context.load({
|
|
6376
6650
|
promise: context.imports.listConnections({
|
|
6377
6651
|
owner: "me",
|
|
6378
6652
|
maxItems: CONNECTION_DISPLAY_LIMIT
|
|
6379
6653
|
}),
|
|
6380
6654
|
label: "Loading app connections"
|
|
6381
6655
|
});
|
|
6382
|
-
if (page.data.length === 0)
|
|
6383
|
-
console.log(
|
|
6384
|
-
`No active connections found. Connect or reconnect an app at ${CONNECTIONS_URL}, then come back and run setup again.`
|
|
6385
|
-
);
|
|
6386
|
-
throw new ZapierCliExitError(
|
|
6387
|
-
"Setup stopped before completion because no active connections are available."
|
|
6388
|
-
);
|
|
6389
|
-
}
|
|
6656
|
+
if (page.data.length === 0) return false;
|
|
6390
6657
|
const table = new Table({
|
|
6391
6658
|
head: ["App", "Connection"],
|
|
6392
|
-
style: {
|
|
6659
|
+
style: {
|
|
6660
|
+
compact: true,
|
|
6661
|
+
...process.stdout.isTTY ? {} : { head: [], border: [] }
|
|
6662
|
+
}
|
|
6393
6663
|
});
|
|
6394
6664
|
table.push(
|
|
6395
6665
|
...page.data.map((connection) => [
|
|
@@ -6401,11 +6671,22 @@ async function ensureConnectionsAvailable(context) {
|
|
|
6401
6671
|
`Active Zapier connections (showing up to ${CONNECTION_DISPLAY_LIMIT}):`
|
|
6402
6672
|
);
|
|
6403
6673
|
console.log(table.toString());
|
|
6674
|
+
return true;
|
|
6675
|
+
}
|
|
6676
|
+
async function ensureConnectionsAvailable(context) {
|
|
6677
|
+
if (await showActiveConnections(context)) return;
|
|
6678
|
+
console.log(
|
|
6679
|
+
`No active connections found. Connect or reconnect an app at ${CONNECTIONS_URL}, then come back and run setup again.`
|
|
6680
|
+
);
|
|
6681
|
+
throw new ZapierCliExitError(
|
|
6682
|
+
"Setup stopped before completion because no active connections are available."
|
|
6683
|
+
);
|
|
6404
6684
|
}
|
|
6405
6685
|
var CONNECTION_PLACEHOLDER = "__ZAPIER_SDK_SLACK_CONNECTION__";
|
|
6406
6686
|
var EMAIL_PLACEHOLDER = "__ZAPIER_SDK_ACCOUNT_EMAIL__";
|
|
6407
6687
|
var APP_PLACEHOLDER = "__ZAPIER_SDK_SLACK_APP__";
|
|
6408
6688
|
var SLACK_SLUG = "slack";
|
|
6689
|
+
var SLACK_RETRY_QUESTION = "Slack email for one retry after the failed test:";
|
|
6409
6690
|
function getSlackTestPath(context) {
|
|
6410
6691
|
const extension = context.projectLanguage === "typescript" ? "ts" : "mjs";
|
|
6411
6692
|
return join("src", "sdk-demo", `zapier-slack-test.${extension}`);
|
|
@@ -6415,7 +6696,7 @@ function getSlackTestTemplatePath(context) {
|
|
|
6415
6696
|
return join(TEMPLATES_DIR, "setup", `zapier-slack-test.${extension}`);
|
|
6416
6697
|
}
|
|
6417
6698
|
async function findSlackConnection(context) {
|
|
6418
|
-
const page = await
|
|
6699
|
+
const page = await context.load({
|
|
6419
6700
|
promise: context.imports.listConnections({
|
|
6420
6701
|
owner: "me",
|
|
6421
6702
|
app: SLACK_SLUG,
|
|
@@ -6436,17 +6717,22 @@ function renderSlackTest({
|
|
|
6436
6717
|
}) {
|
|
6437
6718
|
return readFileSync(getSlackTestTemplatePath(context), "utf8").replace(APP_PLACEHOLDER, () => toTemplateString(app)).replace(CONNECTION_PLACEHOLDER, () => toTemplateString(connection)).replace(EMAIL_PLACEHOLDER, () => toTemplateString(email));
|
|
6438
6719
|
}
|
|
6439
|
-
function
|
|
6720
|
+
async function createAndRunSlackTest({
|
|
6440
6721
|
context,
|
|
6441
|
-
app,
|
|
6442
6722
|
connection,
|
|
6443
|
-
email
|
|
6723
|
+
email,
|
|
6724
|
+
overwrite = true
|
|
6444
6725
|
}) {
|
|
6445
6726
|
const slackTestPath = getSlackTestPath(context);
|
|
6446
6727
|
const path2 = join(context.cwd, slackTestPath);
|
|
6447
6728
|
if (!existsSync(dirname(path2))) mkdirSync(dirname(path2), { recursive: true });
|
|
6448
|
-
writeFileSync(
|
|
6729
|
+
writeFileSync(
|
|
6730
|
+
path2,
|
|
6731
|
+
renderSlackTest({ context, app: SLACK_SLUG, connection, email }),
|
|
6732
|
+
{ flag: overwrite ? "w" : "wx" }
|
|
6733
|
+
);
|
|
6449
6734
|
console.log(`Created ${slackTestPath}.`);
|
|
6735
|
+
return trySlackTest(context);
|
|
6450
6736
|
}
|
|
6451
6737
|
async function executeSlackTest(context) {
|
|
6452
6738
|
const slackTestPath = getSlackTestPath(context);
|
|
@@ -6474,75 +6760,76 @@ async function executeSlackTest(context) {
|
|
|
6474
6760
|
async function trySlackTest(context) {
|
|
6475
6761
|
try {
|
|
6476
6762
|
await executeSlackTest(context);
|
|
6763
|
+
(context.outcomes ?? (context.outcomes = {})).slack = "succeeded";
|
|
6477
6764
|
return true;
|
|
6478
6765
|
} catch (error) {
|
|
6766
|
+
(context.outcomes ?? (context.outcomes = {})).slack = "failed";
|
|
6479
6767
|
const message = error instanceof Error ? error.message : String(error);
|
|
6480
6768
|
console.warn(`Slack demo failed: ${message}. Setup will continue.`);
|
|
6481
6769
|
return false;
|
|
6482
6770
|
}
|
|
6483
6771
|
}
|
|
6484
|
-
async function
|
|
6772
|
+
async function runSlackStep({
|
|
6773
|
+
context,
|
|
6774
|
+
step,
|
|
6775
|
+
connection
|
|
6776
|
+
}) {
|
|
6485
6777
|
if (!context.accountEmail) {
|
|
6486
6778
|
console.log("No account email found; skipping the Slack demo.");
|
|
6487
|
-
return;
|
|
6779
|
+
return "handoff";
|
|
6488
6780
|
}
|
|
6489
|
-
|
|
6490
|
-
if (!slackConnection) {
|
|
6781
|
+
if (!connection) {
|
|
6491
6782
|
console.log("No active Slack connection found; skipping the Slack demo.");
|
|
6492
|
-
return;
|
|
6783
|
+
return "handoff";
|
|
6493
6784
|
}
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
answer: context.createAnswer(),
|
|
6497
|
-
controller: context.setupController,
|
|
6498
|
-
message: `Run the Slack self-DM test using ${context.accountEmail}?`,
|
|
6499
|
-
defaultValue: true
|
|
6500
|
-
});
|
|
6501
|
-
if (!shouldRun) return;
|
|
6502
|
-
const path2 = join(context.cwd, slackTestPath);
|
|
6503
|
-
if (existsSync(path2)) {
|
|
6504
|
-
const shouldOverwrite = await resolveSetupConfirm({
|
|
6785
|
+
if (step === "slack-retry") {
|
|
6786
|
+
const email = await resolveSetupInput({
|
|
6505
6787
|
answer: context.createAnswer(),
|
|
6506
6788
|
controller: context.setupController,
|
|
6507
|
-
message:
|
|
6508
|
-
defaultValue: false
|
|
6789
|
+
message: SLACK_RETRY_QUESTION
|
|
6509
6790
|
});
|
|
6510
|
-
if (
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
message: `Run the existing ${slackTestPath}?`,
|
|
6516
|
-
defaultValue: false
|
|
6791
|
+
if (email)
|
|
6792
|
+
await createAndRunSlackTest({
|
|
6793
|
+
context,
|
|
6794
|
+
connection: connection.id,
|
|
6795
|
+
email
|
|
6517
6796
|
});
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
}
|
|
6797
|
+
else console.log("Skipping the Slack test.");
|
|
6798
|
+
return "handoff";
|
|
6521
6799
|
}
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
context,
|
|
6525
|
-
app: SLACK_SLUG,
|
|
6526
|
-
connection: slackConnection.id,
|
|
6527
|
-
email
|
|
6528
|
-
});
|
|
6529
|
-
if (await trySlackTest(context)) return;
|
|
6530
|
-
email = await resolveSetupInput({
|
|
6800
|
+
const slackTestPath = getSlackTestPath(context);
|
|
6801
|
+
const shouldRun = await resolveSetupConfirm({
|
|
6531
6802
|
answer: context.createAnswer(),
|
|
6532
6803
|
controller: context.setupController,
|
|
6533
|
-
message: "Slack
|
|
6804
|
+
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}?`,
|
|
6805
|
+
defaultValue: step === "slack"
|
|
6534
6806
|
});
|
|
6535
|
-
if (!
|
|
6536
|
-
|
|
6537
|
-
|
|
6807
|
+
if (!shouldRun) {
|
|
6808
|
+
if (step === "slack-overwrite") {
|
|
6809
|
+
console.log("Keeping the existing Slack test file.");
|
|
6810
|
+
return "slack-existing";
|
|
6811
|
+
}
|
|
6812
|
+
return "handoff";
|
|
6813
|
+
}
|
|
6814
|
+
if (step === "slack" && existsSync(join(context.cwd, slackTestPath)))
|
|
6815
|
+
return "slack-overwrite";
|
|
6816
|
+
if (step === "slack-existing") {
|
|
6817
|
+
await trySlackTest(context);
|
|
6818
|
+
return "handoff";
|
|
6538
6819
|
}
|
|
6539
|
-
|
|
6820
|
+
const succeeded = await createAndRunSlackTest({
|
|
6540
6821
|
context,
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6822
|
+
connection: connection.id,
|
|
6823
|
+
email: context.accountEmail,
|
|
6824
|
+
overwrite: step === "slack-overwrite"
|
|
6544
6825
|
});
|
|
6545
|
-
|
|
6826
|
+
return succeeded ? "handoff" : "slack-retry";
|
|
6827
|
+
}
|
|
6828
|
+
async function offerSlackTest(context) {
|
|
6829
|
+
const connection = context.accountEmail ? await findSlackConnection(context) : void 0;
|
|
6830
|
+
let step = "slack";
|
|
6831
|
+
while (step !== "handoff")
|
|
6832
|
+
step = await runSlackStep({ context, step, connection });
|
|
6546
6833
|
}
|
|
6547
6834
|
|
|
6548
6835
|
// src/plugins/setup/skill.ts
|
|
@@ -6568,7 +6855,9 @@ async function installOptionalSkill(context) {
|
|
|
6568
6855
|
cwd: context.cwd,
|
|
6569
6856
|
capture: true
|
|
6570
6857
|
});
|
|
6858
|
+
(context.outcomes ?? (context.outcomes = {})).skill = "succeeded";
|
|
6571
6859
|
} catch {
|
|
6860
|
+
(context.outcomes ?? (context.outcomes = {})).skill = "failed";
|
|
6572
6861
|
console.warn(
|
|
6573
6862
|
`Could not install the optional Zapier SDK skill. To install it manually, run: ${formatPackageCommand(command)}`
|
|
6574
6863
|
);
|
|
@@ -6625,6 +6914,177 @@ async function runWizard(context) {
|
|
|
6625
6914
|
console.log(chalk6.bgCyan.black.bold(" Next steps "));
|
|
6626
6915
|
await openAgentHandoff(context);
|
|
6627
6916
|
}
|
|
6917
|
+
var UNPROMPTED_STEPS = [
|
|
6918
|
+
"project",
|
|
6919
|
+
"confirm-account",
|
|
6920
|
+
"connections"
|
|
6921
|
+
];
|
|
6922
|
+
var ZapierSetupQuestionSignal = class extends ZapierSignal {
|
|
6923
|
+
constructor(question) {
|
|
6924
|
+
super(question.message);
|
|
6925
|
+
this.question = question;
|
|
6926
|
+
this.name = "ZapierSetupQuestionSignal";
|
|
6927
|
+
this.code = "ZAPIER_SETUP_QUESTION";
|
|
6928
|
+
}
|
|
6929
|
+
};
|
|
6930
|
+
function isZapierSetupQuestionSignal(error) {
|
|
6931
|
+
return isZapierSignal(error) && error.code === "ZAPIER_SETUP_QUESTION";
|
|
6932
|
+
}
|
|
6933
|
+
function createSetupAnswer({
|
|
6934
|
+
answer,
|
|
6935
|
+
execute
|
|
6936
|
+
}) {
|
|
6937
|
+
let answered = false;
|
|
6938
|
+
return async ({ result: { question } }) => {
|
|
6939
|
+
if (question.type === "collection")
|
|
6940
|
+
throw new ZapierCliValidationError(
|
|
6941
|
+
"Setup expects a selection or text input."
|
|
6942
|
+
);
|
|
6943
|
+
if (!execute) throw new ZapierSetupQuestionSignal(question);
|
|
6944
|
+
if (answered)
|
|
6945
|
+
throw new ZapierCliValidationError(
|
|
6946
|
+
"Each setup step can answer only one question. Inspect the next question with --agent and run it in a separate command."
|
|
6947
|
+
);
|
|
6948
|
+
answered = true;
|
|
6949
|
+
const confirmation = question.type === "select" && question.choices.some(({ value }) => value === "true") && question.choices.some(({ value }) => value === "false");
|
|
6950
|
+
if (answer === void 0 && !confirmation)
|
|
6951
|
+
throw new ZapierCliValidationError(
|
|
6952
|
+
"This setup step requires --answer. Inspect it with --agent and pass the user's selection or input."
|
|
6953
|
+
);
|
|
6954
|
+
if (question.type === "input")
|
|
6955
|
+
return { type: "custom", value: answer?.trim() ?? "" };
|
|
6956
|
+
const selected = answer?.trim() ?? question.choices[0].value;
|
|
6957
|
+
if (!question.choices.some(({ value }) => value === selected))
|
|
6958
|
+
throw new ZapierCliValidationError(
|
|
6959
|
+
`Answer must be one of: ${question.choices.map(({ value }) => value).join(", ")}.`
|
|
6960
|
+
);
|
|
6961
|
+
return { type: "choose", value: selected };
|
|
6962
|
+
};
|
|
6963
|
+
}
|
|
6964
|
+
async function runSetupStep({
|
|
6965
|
+
context,
|
|
6966
|
+
target
|
|
6967
|
+
}) {
|
|
6968
|
+
switch (target.step) {
|
|
6969
|
+
case "directory":
|
|
6970
|
+
await chooseDirectory(context);
|
|
6971
|
+
return { step: "project" };
|
|
6972
|
+
case "project":
|
|
6973
|
+
await ensureSupportedNode(context);
|
|
6974
|
+
await initializeProject(context);
|
|
6975
|
+
return { step: "install" };
|
|
6976
|
+
case "install":
|
|
6977
|
+
await offerMissingPackageInstall({
|
|
6978
|
+
context,
|
|
6979
|
+
packages: getPackageStates(context).filter(({ declared }) => !declared)
|
|
6980
|
+
});
|
|
6981
|
+
return { step: "sdk-update" };
|
|
6982
|
+
case "sdk-update":
|
|
6983
|
+
case "cli-update": {
|
|
6984
|
+
const name = target.step === "sdk-update" ? "@zapier/zapier-sdk" : "@zapier/zapier-sdk-cli";
|
|
6985
|
+
const packageState = getPackageStates(context).find(
|
|
6986
|
+
({ dependency }) => dependency.name === name
|
|
6987
|
+
);
|
|
6988
|
+
if (packageState) await offerPackageUpdate({ context, packageState });
|
|
6989
|
+
return { step: target.step === "sdk-update" ? "cli-update" : "skill" };
|
|
6990
|
+
}
|
|
6991
|
+
case "skill":
|
|
6992
|
+
await installOptionalSkill(context);
|
|
6993
|
+
return { step: "account" };
|
|
6994
|
+
case "account":
|
|
6995
|
+
case "account-flow":
|
|
6996
|
+
case "account-environment":
|
|
6997
|
+
case "authorize":
|
|
6998
|
+
case "confirm-account":
|
|
6999
|
+
return runAuthenticationStep({ context, options: target });
|
|
7000
|
+
case "connections":
|
|
7001
|
+
if (!await showActiveConnections(context)) {
|
|
7002
|
+
console.log(
|
|
7003
|
+
`No active connections found. Ask the user to connect or reconnect an app at ${CONNECTIONS_URL}. After they confirm, run this exact command:
|
|
7004
|
+
${formatSetupCommand({ context, target })}
|
|
7005
|
+
Success means it prints the active connections table.`
|
|
7006
|
+
);
|
|
7007
|
+
throw new ZapierCliExitError(
|
|
7008
|
+
"Setup stopped until an app connection is active."
|
|
7009
|
+
);
|
|
7010
|
+
}
|
|
7011
|
+
console.log(
|
|
7012
|
+
"Show the user every app and connection title in the table above before continuing. Do not just report that connections were found."
|
|
7013
|
+
);
|
|
7014
|
+
return { step: "slack" };
|
|
7015
|
+
case "slack":
|
|
7016
|
+
case "slack-overwrite":
|
|
7017
|
+
case "slack-existing":
|
|
7018
|
+
case "slack-retry": {
|
|
7019
|
+
const { data: profile } = await context.imports.getProfile({});
|
|
7020
|
+
context.accountEmail = profile.email;
|
|
7021
|
+
return {
|
|
7022
|
+
step: await runSlackStep({
|
|
7023
|
+
context,
|
|
7024
|
+
step: target.step,
|
|
7025
|
+
connection: await findSlackConnection(context)
|
|
7026
|
+
})
|
|
7027
|
+
};
|
|
7028
|
+
}
|
|
7029
|
+
}
|
|
7030
|
+
}
|
|
7031
|
+
async function runAgentSetup({
|
|
7032
|
+
context,
|
|
7033
|
+
options
|
|
7034
|
+
}) {
|
|
7035
|
+
if (options.agent && options.nonInteractive)
|
|
7036
|
+
throw new ZapierCliValidationError(
|
|
7037
|
+
"Use --agent to inspect a step or --non-interactive to execute it, not both."
|
|
7038
|
+
);
|
|
7039
|
+
if (!options.agent && !options.nonInteractive)
|
|
7040
|
+
throw new ZapierCliValidationError(
|
|
7041
|
+
options.step ? "Use --agent to inspect the named step or --non-interactive to execute it." : "--answer, --flow, and --language require a setup step."
|
|
7042
|
+
);
|
|
7043
|
+
if (options.nonInteractive && !options.step)
|
|
7044
|
+
throw new ZapierCliValidationError(
|
|
7045
|
+
"--non-interactive requires --step. Start with setup --agent and follow its printed commands."
|
|
7046
|
+
);
|
|
7047
|
+
if (options.answer !== void 0 && !options.nonInteractive)
|
|
7048
|
+
throw new ZapierCliValidationError("--answer requires --non-interactive.");
|
|
7049
|
+
context.cwd = realpathSync(context.cwd);
|
|
7050
|
+
context.projectLanguage = options.language ?? detectProjectLanguage({
|
|
7051
|
+
cwd: context.cwd,
|
|
7052
|
+
hasExistingProject: existsSync(join(context.cwd, "package.json"))
|
|
7053
|
+
});
|
|
7054
|
+
let target = {
|
|
7055
|
+
step: options.step ?? "directory",
|
|
7056
|
+
flow: options.flow
|
|
7057
|
+
};
|
|
7058
|
+
let execute = options.nonInteractive === true;
|
|
7059
|
+
while (true) {
|
|
7060
|
+
const { step, flow } = target;
|
|
7061
|
+
if (step === "handoff") return printAgentCompletion({ context });
|
|
7062
|
+
if (!execute && UNPROMPTED_STEPS.includes(step))
|
|
7063
|
+
return printAgentStep({ context, target });
|
|
7064
|
+
const answer = createSetupAnswer({
|
|
7065
|
+
answer: execute ? options.answer : void 0,
|
|
7066
|
+
execute
|
|
7067
|
+
});
|
|
7068
|
+
context.createAnswer = () => answer;
|
|
7069
|
+
try {
|
|
7070
|
+
const next = await runSetupStep({ context, target: { step, flow } });
|
|
7071
|
+
if (options.language) context.projectLanguage = options.language;
|
|
7072
|
+
if (execute)
|
|
7073
|
+
for (const [operation, outcome] of Object.entries(
|
|
7074
|
+
context.outcomes ?? {}
|
|
7075
|
+
))
|
|
7076
|
+
console.log(`${operation}: ${outcome}`);
|
|
7077
|
+
target = next;
|
|
7078
|
+
execute = false;
|
|
7079
|
+
} catch (error) {
|
|
7080
|
+
if (isZapierSetupQuestionSignal(error))
|
|
7081
|
+
return printAgentStep({ context, target, question: error.question });
|
|
7082
|
+
if (error instanceof ZapierCliUserCancellationError)
|
|
7083
|
+
return printAgentCompletion({ context, cancelled: true });
|
|
7084
|
+
throw error;
|
|
7085
|
+
}
|
|
7086
|
+
}
|
|
7087
|
+
}
|
|
6628
7088
|
|
|
6629
7089
|
// src/plugins/setup/index.ts
|
|
6630
7090
|
var getProfileRef = declareMethod({ id: "getProfile" });
|
|
@@ -6649,10 +7109,19 @@ var setupPlugin = defineMethod({
|
|
|
6649
7109
|
supportsJsonOutput: false,
|
|
6650
7110
|
inputSchema: SetupSchema,
|
|
6651
7111
|
output: "raw",
|
|
6652
|
-
run: async ({ imports }) => {
|
|
7112
|
+
run: async ({ imports, input }) => {
|
|
7113
|
+
if (input.agent || input.nonInteractive || [input.step, input.answer, input.flow, input.language].some(
|
|
7114
|
+
(value) => value !== void 0
|
|
7115
|
+
)) {
|
|
7116
|
+
await runAgentSetup({
|
|
7117
|
+
context: createWizardContext({ imports, agent: true }),
|
|
7118
|
+
options: input
|
|
7119
|
+
});
|
|
7120
|
+
return;
|
|
7121
|
+
}
|
|
6653
7122
|
if (process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
|
|
6654
|
-
throw new
|
|
6655
|
-
"`zapier-sdk setup` requires an interactive terminal."
|
|
7123
|
+
throw new ZapierCliValidationError(
|
|
7124
|
+
"`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."
|
|
6656
7125
|
);
|
|
6657
7126
|
}
|
|
6658
7127
|
await runWizard(createWizardContext({ imports }));
|
|
@@ -7142,59 +7611,6 @@ var watchTriggerInboxCliPlugin = defineMethod({
|
|
|
7142
7611
|
return doWatch();
|
|
7143
7612
|
}
|
|
7144
7613
|
});
|
|
7145
|
-
var createWorkflowRef = declareMethod$1({ id: "createWorkflow" });
|
|
7146
|
-
function createPublicInputSchema(schema) {
|
|
7147
|
-
const publicSchema = z.object(
|
|
7148
|
-
Object.fromEntries(
|
|
7149
|
-
Object.entries(schema.shape).filter(
|
|
7150
|
-
([name]) => !INTERNAL_CREATE_WORKFLOW_FIELDS.includes(
|
|
7151
|
-
name
|
|
7152
|
-
)
|
|
7153
|
-
)
|
|
7154
|
-
)
|
|
7155
|
-
);
|
|
7156
|
-
return schema.description === void 0 ? publicSchema : publicSchema.describe(schema.description);
|
|
7157
|
-
}
|
|
7158
|
-
var CreateWorkflowCliOptionsSchema = createPublicInputSchema(
|
|
7159
|
-
CreateWorkflowOptionsSchema
|
|
7160
|
-
);
|
|
7161
|
-
defineMethod$1({
|
|
7162
|
-
namespace: "cli",
|
|
7163
|
-
name: "createWorkflow",
|
|
7164
|
-
imports: [createWorkflowRef],
|
|
7165
|
-
type: "create",
|
|
7166
|
-
itemType: "Workflow",
|
|
7167
|
-
categories: ["code-workflow"],
|
|
7168
|
-
stability: "experimental",
|
|
7169
|
-
inputSchema: CreateWorkflowCliOptionsSchema,
|
|
7170
|
-
outputSchema: CreateWorkflowResponseSchema,
|
|
7171
|
-
skipOutputValidation: true,
|
|
7172
|
-
output: "raw",
|
|
7173
|
-
run: ({ imports, input }) => imports.createWorkflow({
|
|
7174
|
-
...input,
|
|
7175
|
-
creationHarness: getAgent(),
|
|
7176
|
-
creationAccessMethod: "sdk_cli"
|
|
7177
|
-
})
|
|
7178
|
-
});
|
|
7179
|
-
var importWorkflowRef = declareMethod$1({ id: "importWorkflow" });
|
|
7180
|
-
defineMethod$1({
|
|
7181
|
-
namespace: "cli",
|
|
7182
|
-
name: "importWorkflow",
|
|
7183
|
-
imports: [importWorkflowRef],
|
|
7184
|
-
type: "create",
|
|
7185
|
-
itemType: "Workflow",
|
|
7186
|
-
categories: ["code-workflow"],
|
|
7187
|
-
stability: "experimental",
|
|
7188
|
-
inputSchema: createPublicInputSchema(ImportWorkflowOptionsSchema),
|
|
7189
|
-
outputSchema: ImportWorkflowResponseSchema,
|
|
7190
|
-
skipOutputValidation: true,
|
|
7191
|
-
output: "raw",
|
|
7192
|
-
run: ({ imports, input }) => imports.importWorkflow({
|
|
7193
|
-
...input,
|
|
7194
|
-
creationHarness: getAgent(),
|
|
7195
|
-
creationAccessMethod: "sdk_cli"
|
|
7196
|
-
})
|
|
7197
|
-
});
|
|
7198
7614
|
var activeNotices = /* @__PURE__ */ new Map();
|
|
7199
7615
|
function collectDeprecationNotice(event) {
|
|
7200
7616
|
if (event.type !== DEPRECATION_NOTICE_EVENT) return;
|
|
@@ -7209,9 +7625,9 @@ function collectDeprecationNoticeAndForward(event, onEvent) {
|
|
|
7209
7625
|
}
|
|
7210
7626
|
|
|
7211
7627
|
// package.json with { type: 'json' }
|
|
7212
|
-
var
|
|
7628
|
+
var package_default2 = {
|
|
7213
7629
|
name: "@zapier/zapier-sdk-cli",
|
|
7214
|
-
version: "0.
|
|
7630
|
+
version: "0.87.1"};
|
|
7215
7631
|
|
|
7216
7632
|
// src/sdk.ts
|
|
7217
7633
|
var warnedDeprecatedMethods = /* @__PURE__ */ new Set();
|
|
@@ -7277,7 +7693,7 @@ function createZapierCliSdk(options = {}) {
|
|
|
7277
7693
|
const stackOptions = {
|
|
7278
7694
|
...sdkOptions,
|
|
7279
7695
|
eventEmission: { ...sdkOptions.eventEmission, callContext: "cli" },
|
|
7280
|
-
callerPackage: { name:
|
|
7696
|
+
callerPackage: { name: package_default2.name, version: package_default2.version },
|
|
7281
7697
|
// Collected for the boxed stderr warning rendered in the exit path. The
|
|
7282
7698
|
// box is additive: the SDK's own inline warn still fires, so the notice
|
|
7283
7699
|
// cannot be hidden by any rendering path.
|
|
@@ -7302,12 +7718,6 @@ function createZapierCliSdk(options = {}) {
|
|
|
7302
7718
|
}
|
|
7303
7719
|
return sdk;
|
|
7304
7720
|
}
|
|
7305
|
-
|
|
7306
|
-
// package.json
|
|
7307
|
-
var package_default2 = {
|
|
7308
|
-
version: "0.86.7"};
|
|
7309
|
-
|
|
7310
|
-
// src/telemetry/builders.ts
|
|
7311
7721
|
function createCliBaseEvent(context = {}) {
|
|
7312
7722
|
return {
|
|
7313
7723
|
event_id: generateEventId(),
|
|
@@ -7325,7 +7735,7 @@ function createCliBaseEvent(context = {}) {
|
|
|
7325
7735
|
function buildCliCommandExecutedEvent({
|
|
7326
7736
|
data,
|
|
7327
7737
|
context = {},
|
|
7328
|
-
cliVersion =
|
|
7738
|
+
cliVersion = package_default.version
|
|
7329
7739
|
}) {
|
|
7330
7740
|
const osInfo = getOsInfo();
|
|
7331
7741
|
const platformVersions = getPlatformVersions();
|
|
@@ -7352,7 +7762,7 @@ function buildCliCommandExecutedEvent({
|
|
|
7352
7762
|
is_ci_environment: isCi(),
|
|
7353
7763
|
ci_platform: getCiPlatform(),
|
|
7354
7764
|
...getTtyContext(),
|
|
7355
|
-
agent: getAgent
|
|
7765
|
+
agent: getAgent(),
|
|
7356
7766
|
package_manager: data.package_manager ?? detectPackageManager(process.cwd()).name,
|
|
7357
7767
|
made_network_requests: data.made_network_requests ?? null,
|
|
7358
7768
|
files_modified_count: data.files_modified_count ?? null,
|