@zapier/zapier-sdk-cli 0.59.1 → 0.59.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/CHANGELOG.md +24 -0
- package/dist/cli.cjs +2 -2
- package/dist/cli.mjs +2 -2
- package/dist/experimental.cjs +1 -1
- package/dist/experimental.mjs +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/package.json +3 -3
- package/dist/package.json +0 -121
- package/dist/src/cli.d.ts +0 -2
- package/dist/src/cli.js +0 -219
- package/dist/src/experimental.d.ts +0 -33
- package/dist/src/experimental.js +0 -86
- package/dist/src/generators/ast-generator.d.ts +0 -41
- package/dist/src/generators/ast-generator.js +0 -405
- package/dist/src/index.d.ts +0 -5
- package/dist/src/index.js +0 -5
- package/dist/src/login/config.d.ts +0 -4
- package/dist/src/login/config.js +0 -21
- package/dist/src/login/credentials-revoke.d.ts +0 -14
- package/dist/src/login/credentials-revoke.js +0 -95
- package/dist/src/login/credentials-store.d.ts +0 -60
- package/dist/src/login/credentials-store.js +0 -181
- package/dist/src/login/filesystem-cache.d.ts +0 -25
- package/dist/src/login/filesystem-cache.js +0 -195
- package/dist/src/login/index.d.ts +0 -110
- package/dist/src/login/index.js +0 -424
- package/dist/src/login/keychain.d.ts +0 -18
- package/dist/src/login/keychain.js +0 -74
- package/dist/src/login/legacy-jwt.d.ts +0 -4
- package/dist/src/login/legacy-jwt.js +0 -18
- package/dist/src/login.d.ts +0 -10
- package/dist/src/login.js +0 -10
- package/dist/src/paths.d.ts +0 -1
- package/dist/src/paths.js +0 -6
- package/dist/src/plugins/add/index.d.ts +0 -254
- package/dist/src/plugins/add/index.js +0 -95
- package/dist/src/plugins/add/schemas.d.ts +0 -8
- package/dist/src/plugins/add/schemas.js +0 -22
- package/dist/src/plugins/auth/credentials-base-url.d.ts +0 -11
- package/dist/src/plugins/auth/credentials-base-url.js +0 -24
- package/dist/src/plugins/buildManifest/index.d.ts +0 -120
- package/dist/src/plugins/buildManifest/index.js +0 -71
- package/dist/src/plugins/buildManifest/schemas.d.ts +0 -44
- package/dist/src/plugins/buildManifest/schemas.js +0 -17
- package/dist/src/plugins/bundleCode/index.d.ts +0 -23
- package/dist/src/plugins/bundleCode/index.js +0 -62
- package/dist/src/plugins/bundleCode/schemas.d.ts +0 -10
- package/dist/src/plugins/bundleCode/schemas.js +0 -19
- package/dist/src/plugins/cliOverrides/index.d.ts +0 -21
- package/dist/src/plugins/cliOverrides/index.js +0 -17
- package/dist/src/plugins/curl/index.d.ts +0 -76
- package/dist/src/plugins/curl/index.js +0 -236
- package/dist/src/plugins/curl/schemas.d.ts +0 -40
- package/dist/src/plugins/curl/schemas.js +0 -108
- package/dist/src/plugins/curl/utils.d.ts +0 -34
- package/dist/src/plugins/curl/utils.js +0 -150
- package/dist/src/plugins/drainTriggerInbox/index.d.ts +0 -46
- package/dist/src/plugins/drainTriggerInbox/index.js +0 -178
- package/dist/src/plugins/feedback/index.d.ts +0 -24
- package/dist/src/plugins/feedback/index.js +0 -52
- package/dist/src/plugins/feedback/schemas.d.ts +0 -5
- package/dist/src/plugins/feedback/schemas.js +0 -8
- package/dist/src/plugins/generateAppTypes/index.d.ts +0 -265
- package/dist/src/plugins/generateAppTypes/index.js +0 -129
- package/dist/src/plugins/generateAppTypes/schemas.d.ts +0 -58
- package/dist/src/plugins/generateAppTypes/schemas.js +0 -21
- package/dist/src/plugins/getLoginConfigPath/index.d.ts +0 -16
- package/dist/src/plugins/getLoginConfigPath/index.js +0 -9
- package/dist/src/plugins/getLoginConfigPath/schemas.d.ts +0 -3
- package/dist/src/plugins/getLoginConfigPath/schemas.js +0 -5
- package/dist/src/plugins/index.d.ts +0 -15
- package/dist/src/plugins/index.js +0 -15
- package/dist/src/plugins/init/display.d.ts +0 -9
- package/dist/src/plugins/init/display.js +0 -72
- package/dist/src/plugins/init/index.d.ts +0 -21
- package/dist/src/plugins/init/index.js +0 -56
- package/dist/src/plugins/init/schemas.d.ts +0 -9
- package/dist/src/plugins/init/schemas.js +0 -19
- package/dist/src/plugins/init/steps.d.ts +0 -39
- package/dist/src/plugins/init/steps.js +0 -141
- package/dist/src/plugins/init/types.d.ts +0 -31
- package/dist/src/plugins/init/types.js +0 -1
- package/dist/src/plugins/init/utils.d.ts +0 -48
- package/dist/src/plugins/init/utils.js +0 -135
- package/dist/src/plugins/login/index.d.ts +0 -25
- package/dist/src/plugins/login/index.js +0 -12
- package/dist/src/plugins/login/schemas.d.ts +0 -9
- package/dist/src/plugins/login/schemas.js +0 -27
- package/dist/src/plugins/logout/index.d.ts +0 -30
- package/dist/src/plugins/logout/index.js +0 -33
- package/dist/src/plugins/logout/schemas.d.ts +0 -2
- package/dist/src/plugins/logout/schemas.js +0 -4
- package/dist/src/plugins/mcp/index.d.ts +0 -28
- package/dist/src/plugins/mcp/index.js +0 -24
- package/dist/src/plugins/mcp/schemas.d.ts +0 -5
- package/dist/src/plugins/mcp/schemas.js +0 -10
- package/dist/src/plugins/signup/index.d.ts +0 -25
- package/dist/src/plugins/signup/index.js +0 -12
- package/dist/src/plugins/signup/schemas.d.ts +0 -9
- package/dist/src/plugins/signup/schemas.js +0 -26
- package/dist/src/plugins/signup/test-harness.d.ts +0 -34
- package/dist/src/plugins/signup/test-harness.js +0 -76
- package/dist/src/plugins/watchTriggerInbox/index.d.ts +0 -46
- package/dist/src/plugins/watchTriggerInbox/index.js +0 -166
- package/dist/src/sdk.d.ts +0 -17
- package/dist/src/sdk.js +0 -67
- package/dist/src/telemetry/builders.d.ts +0 -44
- package/dist/src/telemetry/builders.js +0 -59
- package/dist/src/telemetry/events.d.ts +0 -40
- package/dist/src/telemetry/events.js +0 -4
- package/dist/src/types/sdk.d.ts +0 -6
- package/dist/src/types/sdk.js +0 -1
- package/dist/src/utils/api/client.d.ts +0 -15
- package/dist/src/utils/api/client.js +0 -27
- package/dist/src/utils/approval-errors.d.ts +0 -1
- package/dist/src/utils/approval-errors.js +0 -9
- package/dist/src/utils/approval-progress.d.ts +0 -12
- package/dist/src/utils/approval-progress.js +0 -179
- package/dist/src/utils/auth/account-auth.d.ts +0 -33
- package/dist/src/utils/auth/account-auth.js +0 -302
- package/dist/src/utils/auth/client-credentials.d.ts +0 -26
- package/dist/src/utils/auth/client-credentials.js +0 -67
- package/dist/src/utils/auth/oauth-callback.d.ts +0 -6
- package/dist/src/utils/auth/oauth-callback.js +0 -28
- package/dist/src/utils/auth/oauth-errors.d.ts +0 -2
- package/dist/src/utils/auth/oauth-errors.js +0 -39
- package/dist/src/utils/auth/oauth-flow.d.ts +0 -37
- package/dist/src/utils/auth/oauth-flow.js +0 -313
- package/dist/src/utils/auth/oauth-transaction.d.ts +0 -35
- package/dist/src/utils/auth/oauth-transaction.js +0 -69
- package/dist/src/utils/cli-generator-utils.d.ts +0 -14
- package/dist/src/utils/cli-generator-utils.js +0 -122
- package/dist/src/utils/cli-generator.d.ts +0 -4
- package/dist/src/utils/cli-generator.js +0 -831
- package/dist/src/utils/cli-options.d.ts +0 -16
- package/dist/src/utils/cli-options.js +0 -34
- package/dist/src/utils/cli-renderer.d.ts +0 -53
- package/dist/src/utils/cli-renderer.js +0 -265
- package/dist/src/utils/constants.d.ts +0 -3
- package/dist/src/utils/constants.js +0 -5
- package/dist/src/utils/directory-detection.d.ts +0 -5
- package/dist/src/utils/directory-detection.js +0 -21
- package/dist/src/utils/errors.d.ts +0 -33
- package/dist/src/utils/errors.js +0 -36
- package/dist/src/utils/extensions.d.ts +0 -20
- package/dist/src/utils/extensions.js +0 -66
- package/dist/src/utils/getCallablePromise.d.ts +0 -6
- package/dist/src/utils/getCallablePromise.js +0 -14
- package/dist/src/utils/log.d.ts +0 -8
- package/dist/src/utils/log.js +0 -26
- package/dist/src/utils/manifest-helpers.d.ts +0 -10
- package/dist/src/utils/manifest-helpers.js +0 -19
- package/dist/src/utils/non-interactive.d.ts +0 -14
- package/dist/src/utils/non-interactive.js +0 -15
- package/dist/src/utils/package-manager-detector.d.ts +0 -18
- package/dist/src/utils/package-manager-detector.js +0 -72
- package/dist/src/utils/parameter-resolver.d.ts +0 -179
- package/dist/src/utils/parameter-resolver.js +0 -1554
- package/dist/src/utils/retry.d.ts +0 -6
- package/dist/src/utils/retry.js +0 -21
- package/dist/src/utils/schema-formatter.d.ts +0 -11
- package/dist/src/utils/schema-formatter.js +0 -131
- package/dist/src/utils/serializeAsync.d.ts +0 -2
- package/dist/src/utils/serializeAsync.js +0 -16
- package/dist/src/utils/spinner.d.ts +0 -1
- package/dist/src/utils/spinner.js +0 -21
- package/dist/src/utils/string-utils.d.ts +0 -1
- package/dist/src/utils/string-utils.js +0 -6
- package/dist/src/utils/triggerDrain.d.ts +0 -144
- package/dist/src/utils/triggerDrain.js +0 -351
- package/dist/src/utils/version-checker.d.ts +0 -17
- package/dist/src/utils/version-checker.js +0 -154
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -1,831 +0,0 @@
|
|
|
1
|
-
import { Option } from "commander";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
import { isPositional, runWithCallerContext, } from "@zapier/zapier-sdk";
|
|
4
|
-
import { SchemaParameterResolver } from "./parameter-resolver";
|
|
5
|
-
import chalk from "chalk";
|
|
6
|
-
import inquirer from "inquirer";
|
|
7
|
-
import { ZapierCliError, ZapierCliExitError, ZapierCliMissingParametersError, ZapierCliValidationError, } from "./errors";
|
|
8
|
-
import { SHARED_COMMAND_CLI_OPTIONS } from "./cli-options";
|
|
9
|
-
import { buildCliCommandExecutedEvent } from "../telemetry/builders";
|
|
10
|
-
import { createJsonRenderer, createInteractiveRenderer } from "./cli-renderer";
|
|
11
|
-
import { toKebabCase } from "./string-utils";
|
|
12
|
-
const CLI_COMMAND_EXECUTED_EVENT_SUBJECT = "platform.sdk.CliCommandExecutedEvent";
|
|
13
|
-
const PAGINATION_PARAM_NAMES = new Set(["maxItems", "pageSize", "cursor"]);
|
|
14
|
-
// Flags whose values may contain secrets and must not appear in telemetry
|
|
15
|
-
const SENSITIVE_FLAGS = [
|
|
16
|
-
"--credentials",
|
|
17
|
-
"--credentials-client-secret",
|
|
18
|
-
"--credentials-client-id",
|
|
19
|
-
"--credentials-base-url",
|
|
20
|
-
"--user",
|
|
21
|
-
"--header",
|
|
22
|
-
"-H",
|
|
23
|
-
"-u",
|
|
24
|
-
];
|
|
25
|
-
export function sanitizeCliArguments(args) {
|
|
26
|
-
const sanitized = [];
|
|
27
|
-
let skipNext = false;
|
|
28
|
-
for (const arg of args) {
|
|
29
|
-
if (skipNext) {
|
|
30
|
-
skipNext = false;
|
|
31
|
-
sanitized.push("[REDACTED]");
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
if (SENSITIVE_FLAGS.some((flag) => arg.startsWith(flag + "="))) {
|
|
35
|
-
sanitized.push(arg.split("=")[0] + "=[REDACTED]");
|
|
36
|
-
}
|
|
37
|
-
else if (SENSITIVE_FLAGS.includes(arg)) {
|
|
38
|
-
sanitized.push(arg);
|
|
39
|
-
skipNext = true;
|
|
40
|
-
}
|
|
41
|
-
else {
|
|
42
|
-
sanitized.push(arg);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return sanitized;
|
|
46
|
-
}
|
|
47
|
-
function getNormalizedResult(result, { isListCommand }) {
|
|
48
|
-
if (result instanceof Response) {
|
|
49
|
-
return { kind: "response", value: result };
|
|
50
|
-
}
|
|
51
|
-
if (isListCommand) {
|
|
52
|
-
const sdkResult = result;
|
|
53
|
-
if (!Array.isArray(sdkResult?.data)) {
|
|
54
|
-
throw new Error(`List command returned unexpected shape (expected { data: [] }): ${JSON.stringify(result).slice(0, 200)}`);
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
kind: "list",
|
|
58
|
-
data: sdkResult.data,
|
|
59
|
-
nextCursor: sdkResult.nextCursor,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
const sdkResult = result;
|
|
63
|
-
return {
|
|
64
|
-
kind: "item",
|
|
65
|
-
value: result !== null && typeof result === "object" && "data" in result
|
|
66
|
-
? sdkResult.data
|
|
67
|
-
: result,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
function hasItems(sdkResult) {
|
|
71
|
-
return (sdkResult != null &&
|
|
72
|
-
typeof sdkResult.items === "function");
|
|
73
|
-
}
|
|
74
|
-
function hasPages(sdkResult) {
|
|
75
|
-
return (sdkResult != null &&
|
|
76
|
-
typeof sdkResult[Symbol.asyncIterator] === "function");
|
|
77
|
-
}
|
|
78
|
-
async function* toItemsStream(sdkResult) {
|
|
79
|
-
if (hasItems(sdkResult)) {
|
|
80
|
-
yield* sdkResult.items();
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
if (hasPages(sdkResult)) {
|
|
84
|
-
for await (const page of sdkResult) {
|
|
85
|
-
yield* page.data ?? [];
|
|
86
|
-
}
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
throw new ZapierCliExitError(`SDK method returned a value that is not async-iterable. Got: ${typeof sdkResult}. ` +
|
|
90
|
-
`List methods must return an AsyncIterable or an object with an items() method.`, 1);
|
|
91
|
-
}
|
|
92
|
-
async function collectItemsFromResult({ sdkResult, maxItems, }) {
|
|
93
|
-
const items = [];
|
|
94
|
-
for await (const item of toItemsStream(sdkResult)) {
|
|
95
|
-
items.push(item);
|
|
96
|
-
if (maxItems !== undefined && items.length >= maxItems)
|
|
97
|
-
break;
|
|
98
|
-
}
|
|
99
|
-
return maxItems !== undefined ? items.slice(0, maxItems) : items;
|
|
100
|
-
}
|
|
101
|
-
const CONFIRM_MESSAGES = {
|
|
102
|
-
"create-secret": {
|
|
103
|
-
messageBefore: "You are about to create a sensitive secret that will be displayed as plain text.\n" +
|
|
104
|
-
"Once created, you cannot retrieve it again.",
|
|
105
|
-
messageAfter: "Please treat this secret like a password and store it securely!",
|
|
106
|
-
},
|
|
107
|
-
delete: (itemType) => ({
|
|
108
|
-
messageBefore: `You are about to delete the ${itemType || "item"}.`,
|
|
109
|
-
}),
|
|
110
|
-
};
|
|
111
|
-
async function promptConfirm(confirmType, itemType) {
|
|
112
|
-
if (!confirmType || !CONFIRM_MESSAGES[confirmType]) {
|
|
113
|
-
return { confirmed: true }; // No confirmation needed
|
|
114
|
-
}
|
|
115
|
-
const configOrFn = CONFIRM_MESSAGES[confirmType];
|
|
116
|
-
const { messageBefore, messageAfter } = typeof configOrFn === "function" ? configOrFn(itemType) : configOrFn;
|
|
117
|
-
console.log(chalk.yellow(`\n${messageBefore}\n`));
|
|
118
|
-
const { confirmed } = await inquirer.prompt([
|
|
119
|
-
{
|
|
120
|
-
type: "confirm",
|
|
121
|
-
name: "confirmed",
|
|
122
|
-
message: "Continue?",
|
|
123
|
-
default: false,
|
|
124
|
-
},
|
|
125
|
-
]);
|
|
126
|
-
return { confirmed, messageAfter };
|
|
127
|
-
}
|
|
128
|
-
function emitDeprecationWarning({ cliCommandName, deprecation, }) {
|
|
129
|
-
if (!deprecation) {
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
console.warn();
|
|
133
|
-
console.warn(chalk.yellow.bold("⚠️ DEPRECATION WARNING") +
|
|
134
|
-
chalk.yellow(` - \`${cliCommandName}\` is deprecated.`));
|
|
135
|
-
console.warn(chalk.yellow(` ${deprecation.message}`));
|
|
136
|
-
console.warn();
|
|
137
|
-
}
|
|
138
|
-
function emitParamDeprecationWarnings({ options, parameters, }) {
|
|
139
|
-
for (const param of parameters) {
|
|
140
|
-
if (!param.isDeprecated)
|
|
141
|
-
continue;
|
|
142
|
-
const value = options[param.name];
|
|
143
|
-
if (value === undefined)
|
|
144
|
-
continue;
|
|
145
|
-
if (Array.isArray(value) && value.length === 0)
|
|
146
|
-
continue;
|
|
147
|
-
console.warn();
|
|
148
|
-
console.warn(chalk.yellow.bold("⚠️ DEPRECATION WARNING") +
|
|
149
|
-
chalk.yellow(` - \`${toKebabCase(param.name)}\` is deprecated and may be removed in a future release.`));
|
|
150
|
-
if (param.deprecationMessage) {
|
|
151
|
-
console.warn(chalk.yellow(` ${param.deprecationMessage}`));
|
|
152
|
-
}
|
|
153
|
-
console.warn();
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
function resolveOutputMode({ isListCommand, hasPaginationParams, hasUserSpecifiedMaxItems, }) {
|
|
157
|
-
if (!isListCommand || !hasPaginationParams)
|
|
158
|
-
return "single";
|
|
159
|
-
if (hasUserSpecifiedMaxItems)
|
|
160
|
-
return "collect";
|
|
161
|
-
return "paginate";
|
|
162
|
-
}
|
|
163
|
-
/** Extract the aliases map from a schema's metadata (e.g., { appKey: "app" }). */
|
|
164
|
-
function getSchemaAliases(schema) {
|
|
165
|
-
return schema?.meta?.()?.aliases;
|
|
166
|
-
}
|
|
167
|
-
// ============================================================================
|
|
168
|
-
// Schema Analysis
|
|
169
|
-
// ============================================================================
|
|
170
|
-
function analyzeZodSchema(schema, functionInfo) {
|
|
171
|
-
const parameters = [];
|
|
172
|
-
// Handle ZodEffects (schemas with .refine(), .transform(), etc.)
|
|
173
|
-
// In Zod, effects have type "effect" and inner schema is accessed via innerType
|
|
174
|
-
const schemaDef = schema._zod?.def;
|
|
175
|
-
if (schemaDef?.type === "effect" && schemaDef.innerType) {
|
|
176
|
-
return analyzeZodSchema(schemaDef.innerType, functionInfo);
|
|
177
|
-
}
|
|
178
|
-
if (schema instanceof z.ZodObject) {
|
|
179
|
-
const shape = schema.shape;
|
|
180
|
-
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
181
|
-
const param = analyzeZodField(key, fieldSchema, functionInfo);
|
|
182
|
-
if (param) {
|
|
183
|
-
parameters.push(param);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
return parameters;
|
|
188
|
-
}
|
|
189
|
-
function analyzeZodField(name, schema, functionInfo) {
|
|
190
|
-
let baseSchema = schema;
|
|
191
|
-
let required = true;
|
|
192
|
-
let defaultValue = undefined;
|
|
193
|
-
let isDeprecated = false;
|
|
194
|
-
let deprecationMessage;
|
|
195
|
-
// Unwrap optional, default, and nullable wrappers - keep unwrapping until we get to the base type.
|
|
196
|
-
// Check .meta()?.deprecated at each level since it doesn't propagate through wrappers.
|
|
197
|
-
while (true) {
|
|
198
|
-
const meta = baseSchema.meta?.();
|
|
199
|
-
if (meta?.deprecated) {
|
|
200
|
-
isDeprecated = true;
|
|
201
|
-
}
|
|
202
|
-
if (meta?.deprecationMessage && !deprecationMessage) {
|
|
203
|
-
deprecationMessage = meta.deprecationMessage;
|
|
204
|
-
}
|
|
205
|
-
if (baseSchema instanceof z.ZodOptional) {
|
|
206
|
-
required = false;
|
|
207
|
-
baseSchema = baseSchema._zod.def.innerType;
|
|
208
|
-
}
|
|
209
|
-
else if (baseSchema instanceof z.ZodDefault) {
|
|
210
|
-
required = false;
|
|
211
|
-
const defValue = baseSchema._zod.def.defaultValue;
|
|
212
|
-
defaultValue = typeof defValue === "function" ? defValue() : defValue;
|
|
213
|
-
baseSchema = baseSchema._zod.def.innerType;
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
// Check for ZodNullable - nullable doesn't affect CLI required status, but we need to unwrap it to get the base type
|
|
217
|
-
// Use _zod.def.type for Zod 4 compatibility (matches patterns elsewhere in codebase)
|
|
218
|
-
const zodDef = baseSchema._zod?.def;
|
|
219
|
-
if (zodDef?.type === "nullable" && zodDef.innerType) {
|
|
220
|
-
baseSchema = zodDef.innerType;
|
|
221
|
-
continue;
|
|
222
|
-
}
|
|
223
|
-
// No more wrappers to unwrap
|
|
224
|
-
break;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
// Some schema kinds aren't expressible as CLI flags and would
|
|
228
|
-
// otherwise fall through to a bogus `--name <string>` flag:
|
|
229
|
-
// - z.function() — onMessage / onError-style callbacks
|
|
230
|
-
// - z.custom<AbortSignal>() and other custom predicates — passed
|
|
231
|
-
// programmatically by callers, or filled in by a CLI-side
|
|
232
|
-
// decorator plugin (closure-capture + override).
|
|
233
|
-
// Skip them so the auto-generated CLI surface stays clean.
|
|
234
|
-
const baseSchemaDef = baseSchema._zod?.def;
|
|
235
|
-
if (baseSchema instanceof z.ZodFunction || baseSchemaDef?.type === "custom") {
|
|
236
|
-
return null;
|
|
237
|
-
}
|
|
238
|
-
// Determine parameter type
|
|
239
|
-
let paramType = "string";
|
|
240
|
-
let elementType;
|
|
241
|
-
let choices;
|
|
242
|
-
if (baseSchema instanceof z.ZodString) {
|
|
243
|
-
paramType = "string";
|
|
244
|
-
}
|
|
245
|
-
else if (baseSchema instanceof z.ZodNumber) {
|
|
246
|
-
paramType = "number";
|
|
247
|
-
}
|
|
248
|
-
else if (baseSchema instanceof z.ZodBoolean) {
|
|
249
|
-
paramType = "boolean";
|
|
250
|
-
}
|
|
251
|
-
else if (baseSchema instanceof z.ZodArray) {
|
|
252
|
-
paramType = "array";
|
|
253
|
-
const elementSchema = baseSchema._zod.def.element;
|
|
254
|
-
if (elementSchema instanceof z.ZodObject ||
|
|
255
|
-
elementSchema instanceof z.ZodRecord) {
|
|
256
|
-
elementType = "object";
|
|
257
|
-
}
|
|
258
|
-
else if (elementSchema instanceof z.ZodNumber) {
|
|
259
|
-
elementType = "number";
|
|
260
|
-
}
|
|
261
|
-
else if (elementSchema instanceof z.ZodBoolean) {
|
|
262
|
-
elementType = "boolean";
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
else if (baseSchema instanceof z.ZodEnum) {
|
|
266
|
-
paramType = "string";
|
|
267
|
-
choices = baseSchema.options;
|
|
268
|
-
}
|
|
269
|
-
else if (baseSchema instanceof z.ZodObject ||
|
|
270
|
-
baseSchema instanceof z.ZodRecord) {
|
|
271
|
-
// User passes a JSON string; convertValue will parse it to an object
|
|
272
|
-
paramType = "object";
|
|
273
|
-
}
|
|
274
|
-
// Check if this parameter has a resolver
|
|
275
|
-
let paramHasResolver = false;
|
|
276
|
-
// Check function-specific resolvers first
|
|
277
|
-
if (functionInfo?.resolvers?.[name]) {
|
|
278
|
-
paramHasResolver = true;
|
|
279
|
-
}
|
|
280
|
-
// Extract resolver metadata
|
|
281
|
-
return {
|
|
282
|
-
name,
|
|
283
|
-
type: paramType,
|
|
284
|
-
required,
|
|
285
|
-
description: schema.description,
|
|
286
|
-
default: defaultValue,
|
|
287
|
-
choices,
|
|
288
|
-
hasResolver: paramHasResolver,
|
|
289
|
-
isPositional: isPositional(schema),
|
|
290
|
-
elementType,
|
|
291
|
-
deprecationMessage,
|
|
292
|
-
isDeprecated,
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Analyze inputParameters (used by multi-parameter functions like fetch) into flat CLI parameters.
|
|
297
|
-
* Simple-type params become positional args; object-type params have their properties flattened into flags.
|
|
298
|
-
*/
|
|
299
|
-
function analyzeInputParameters(inputParameters, functionInfo) {
|
|
300
|
-
const cliParams = [];
|
|
301
|
-
for (const param of inputParameters) {
|
|
302
|
-
let schema = param.schema;
|
|
303
|
-
let isOptional = false;
|
|
304
|
-
// Unwrap optional wrapper
|
|
305
|
-
if (schema instanceof z.ZodOptional) {
|
|
306
|
-
isOptional = true;
|
|
307
|
-
schema = schema._zod.def.innerType;
|
|
308
|
-
}
|
|
309
|
-
if (schema instanceof z.ZodObject) {
|
|
310
|
-
// Flatten object properties into individual CLI flags
|
|
311
|
-
const shape = schema.shape;
|
|
312
|
-
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
313
|
-
const analyzed = analyzeZodField(key, fieldSchema, functionInfo);
|
|
314
|
-
if (analyzed) {
|
|
315
|
-
if (isOptional) {
|
|
316
|
-
analyzed.required = false;
|
|
317
|
-
}
|
|
318
|
-
cliParams.push(analyzed);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
else {
|
|
323
|
-
// Simple type — treat as positional argument
|
|
324
|
-
const analyzed = analyzeZodField(param.name, param.schema, functionInfo);
|
|
325
|
-
if (analyzed) {
|
|
326
|
-
analyzed.required = !isOptional;
|
|
327
|
-
analyzed.isPositional = true;
|
|
328
|
-
cliParams.push(analyzed);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
return cliParams;
|
|
333
|
-
}
|
|
334
|
-
/**
|
|
335
|
-
* Reconstruct positional arguments for SDK invocation from a flat params record.
|
|
336
|
-
* Used when calling multi-parameter SDK functions (inputParameters) from the CLI.
|
|
337
|
-
*/
|
|
338
|
-
function reconstructPositionalArgs(inputParameters, flatParams) {
|
|
339
|
-
const args = [];
|
|
340
|
-
for (const param of inputParameters) {
|
|
341
|
-
let schema = param.schema;
|
|
342
|
-
if (schema instanceof z.ZodOptional) {
|
|
343
|
-
schema = schema._zod.def.innerType;
|
|
344
|
-
}
|
|
345
|
-
if (schema instanceof z.ZodObject) {
|
|
346
|
-
const shape = schema.shape;
|
|
347
|
-
const obj = {};
|
|
348
|
-
let hasValues = false;
|
|
349
|
-
for (const key of Object.keys(shape)) {
|
|
350
|
-
if (key in flatParams && flatParams[key] !== undefined) {
|
|
351
|
-
obj[key] = flatParams[key];
|
|
352
|
-
hasValues = true;
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
args.push(hasValues ? obj : undefined);
|
|
356
|
-
}
|
|
357
|
-
else {
|
|
358
|
-
args.push(flatParams[param.name]);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
return args;
|
|
362
|
-
}
|
|
363
|
-
// ============================================================================
|
|
364
|
-
// CLI Structure Derivation - Purely Generic
|
|
365
|
-
// ============================================================================
|
|
366
|
-
/**
|
|
367
|
-
* Convert SDK method name directly to CLI command
|
|
368
|
-
* e.g., listApps -> list-apps, getApp -> get-app, generateTypes -> generate-types
|
|
369
|
-
*/
|
|
370
|
-
function methodNameToCliCommand(methodName) {
|
|
371
|
-
return toKebabCase(methodName);
|
|
372
|
-
}
|
|
373
|
-
// ============================================================================
|
|
374
|
-
// CLI Command Generation - Completely Generic
|
|
375
|
-
// ============================================================================
|
|
376
|
-
export function generateCliCommands(program, sdk) {
|
|
377
|
-
// Check if SDK has registry
|
|
378
|
-
if (typeof sdk.getRegistry !== "function") {
|
|
379
|
-
console.error("SDK registry not available");
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
const registry = sdk.getRegistry({ package: "cli" });
|
|
383
|
-
// Create all commands first
|
|
384
|
-
registry.functions.forEach((fnInfo) => {
|
|
385
|
-
if (!fnInfo.inputSchema && !fnInfo.inputParameters) {
|
|
386
|
-
console.warn(`Schema not found for ${fnInfo.name}`);
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
// Convert methodName to kebab-case CLI command
|
|
390
|
-
const cliCommandName = methodNameToCliCommand(fnInfo.name);
|
|
391
|
-
const config = createCommandConfig(cliCommandName, fnInfo, sdk);
|
|
392
|
-
addCommand(program, cliCommandName, config);
|
|
393
|
-
});
|
|
394
|
-
// Override the help display to show commands grouped by category
|
|
395
|
-
program.configureHelp({
|
|
396
|
-
formatHelp: (cmd, helper) => {
|
|
397
|
-
const helpWidth = helper.helpWidth || 80;
|
|
398
|
-
let output = helper.commandUsage(cmd) + "\n";
|
|
399
|
-
if (cmd.description()) {
|
|
400
|
-
output += helper.wrap(cmd.description(), helpWidth, 0) + "\n";
|
|
401
|
-
}
|
|
402
|
-
// Add options section
|
|
403
|
-
const options = helper.visibleOptions(cmd);
|
|
404
|
-
if (options.length > 0) {
|
|
405
|
-
output += "\nOptions:\n";
|
|
406
|
-
const longestOptionLength = Math.max(...options.map((opt) => helper.optionTerm(opt).length));
|
|
407
|
-
options.forEach((option) => {
|
|
408
|
-
const term = helper.optionTerm(option);
|
|
409
|
-
const padding = " ".repeat(Math.max(2, longestOptionLength - term.length + 4));
|
|
410
|
-
output += ` ${term}${padding}${helper.optionDescription(option)}\n`;
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
// Add categorized commands section
|
|
414
|
-
const commands = helper.visibleCommands(cmd);
|
|
415
|
-
if (commands.length > 0) {
|
|
416
|
-
output += "\nCommands:\n";
|
|
417
|
-
// Collect all SDK commands that belong to categories
|
|
418
|
-
const categorizedCommands = new Set();
|
|
419
|
-
// Group SDK commands by categories
|
|
420
|
-
registry.categories.forEach((category) => {
|
|
421
|
-
const categoryCommands = commands.filter((command) => category.functions.some((functionName) => {
|
|
422
|
-
const cliCommandName = methodNameToCliCommand(functionName);
|
|
423
|
-
return command.name() === cliCommandName;
|
|
424
|
-
}));
|
|
425
|
-
if (categoryCommands.length > 0) {
|
|
426
|
-
output += `\n ${category.titlePlural}:\n`;
|
|
427
|
-
categoryCommands.forEach((command) => {
|
|
428
|
-
output += ` ${helper.subcommandTerm(command)}\n`;
|
|
429
|
-
categorizedCommands.add(command.name());
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
});
|
|
433
|
-
// Add any remaining commands that aren't part of SDK categories
|
|
434
|
-
const otherCommands = commands.filter((command) => !categorizedCommands.has(command.name()));
|
|
435
|
-
if (otherCommands.length > 0) {
|
|
436
|
-
output += `\n Other:\n`;
|
|
437
|
-
otherCommands.forEach((command) => {
|
|
438
|
-
output += ` ${helper.subcommandTerm(command)}\n`;
|
|
439
|
-
});
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
return output;
|
|
443
|
-
},
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
function createCommandConfig(cliCommandName, functionInfo, sdk) {
|
|
447
|
-
const usesInputParameters = !functionInfo.inputSchema && !!functionInfo.inputParameters;
|
|
448
|
-
const schema = functionInfo.inputSchema;
|
|
449
|
-
const parameters = usesInputParameters
|
|
450
|
-
? analyzeInputParameters(functionInfo.inputParameters, functionInfo)
|
|
451
|
-
: analyzeZodSchema(schema, functionInfo);
|
|
452
|
-
// Mark params that are aliases for other params (e.g., appKey is an alias for app).
|
|
453
|
-
const schemaAliases = getSchemaAliases(schema);
|
|
454
|
-
if (schemaAliases) {
|
|
455
|
-
const aliasedNames = new Set(Object.keys(schemaAliases));
|
|
456
|
-
for (const param of parameters) {
|
|
457
|
-
if (aliasedNames.has(param.name)) {
|
|
458
|
-
param.isAlias = true;
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
const baseDescription = functionInfo.description ||
|
|
463
|
-
schema?.description ||
|
|
464
|
-
`${cliCommandName} command`;
|
|
465
|
-
// Mark experimental commands clearly in --help so users know what they're
|
|
466
|
-
// touching. The command only reaches here at all when the experimental SDK
|
|
467
|
-
// factory is loaded, so we don't need to gate help visibility separately.
|
|
468
|
-
const description = functionInfo.experimental
|
|
469
|
-
? `${baseDescription} (experimental)`
|
|
470
|
-
: baseDescription;
|
|
471
|
-
const handler = async (...args) => {
|
|
472
|
-
const startTime = Date.now();
|
|
473
|
-
let success = true;
|
|
474
|
-
let errorMessage = null;
|
|
475
|
-
// `resolvedParams` is populated below either by `resolveParameters` or
|
|
476
|
-
// by copying `rawParams`. The renderer captures this object by
|
|
477
|
-
// reference and reads from it inside formatter callbacks, so we
|
|
478
|
-
// mutate it in place (via `Object.assign`) once params are resolved
|
|
479
|
-
// rather than reassigning the binding, which would leave the
|
|
480
|
-
// renderer holding the empty initial object.
|
|
481
|
-
const resolvedParams = {};
|
|
482
|
-
// The last argument is always the command object with parsed options
|
|
483
|
-
const commandObj = args[args.length - 1];
|
|
484
|
-
const options = commandObj.opts();
|
|
485
|
-
// interactiveMode is true by default; --json disables it
|
|
486
|
-
const interactiveMode = !options.json;
|
|
487
|
-
const renderer = interactiveMode
|
|
488
|
-
? createInteractiveRenderer({
|
|
489
|
-
sdk,
|
|
490
|
-
params: resolvedParams,
|
|
491
|
-
})
|
|
492
|
-
: createJsonRenderer();
|
|
493
|
-
try {
|
|
494
|
-
emitDeprecationWarning({
|
|
495
|
-
cliCommandName,
|
|
496
|
-
deprecation: functionInfo.deprecation,
|
|
497
|
-
});
|
|
498
|
-
emitParamDeprecationWarnings({ options, parameters });
|
|
499
|
-
// Check if this is a list command for pagination
|
|
500
|
-
const isListCommand = functionInfo.type === "list";
|
|
501
|
-
const hasPaginationParams = parameters.some((p) => PAGINATION_PARAM_NAMES.has(p.name));
|
|
502
|
-
const hasUserSpecifiedMaxItems = "maxItems" in options && options.maxItems !== undefined;
|
|
503
|
-
const outputMode = resolveOutputMode({
|
|
504
|
-
isListCommand,
|
|
505
|
-
hasPaginationParams,
|
|
506
|
-
hasUserSpecifiedMaxItems,
|
|
507
|
-
});
|
|
508
|
-
const rawParams = convertCliArgsToSdkParams(parameters, args.slice(0, -1), options);
|
|
509
|
-
// Remap aliased parameter names (e.g., authenticationId → connectionId)
|
|
510
|
-
const schemaAliases = getSchemaAliases(schema);
|
|
511
|
-
if (schemaAliases) {
|
|
512
|
-
for (const [oldName, newName] of Object.entries(schemaAliases)) {
|
|
513
|
-
if (oldName in rawParams && !(newName in rawParams)) {
|
|
514
|
-
rawParams[newName] = rawParams[oldName];
|
|
515
|
-
delete rawParams[oldName];
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
if (schema && !usesInputParameters) {
|
|
520
|
-
const resolver = new SchemaParameterResolver();
|
|
521
|
-
const resolved = (await resolver.resolveParameters(schema, rawParams, sdk, functionInfo.name, {
|
|
522
|
-
interactiveMode,
|
|
523
|
-
debug: !!options.debug ||
|
|
524
|
-
process.env.DEBUG === "true" ||
|
|
525
|
-
process.argv.includes("--debug"),
|
|
526
|
-
}));
|
|
527
|
-
Object.assign(resolvedParams, resolved);
|
|
528
|
-
}
|
|
529
|
-
else {
|
|
530
|
-
Object.assign(resolvedParams, rawParams);
|
|
531
|
-
}
|
|
532
|
-
const confirm = functionInfo.confirm;
|
|
533
|
-
let confirmMessageAfter;
|
|
534
|
-
if (confirm && interactiveMode) {
|
|
535
|
-
const confirmResult = await promptConfirm(confirm, functionInfo.itemType);
|
|
536
|
-
if (!confirmResult.confirmed) {
|
|
537
|
-
console.log(chalk.yellow("Operation cancelled."));
|
|
538
|
-
return;
|
|
539
|
-
}
|
|
540
|
-
confirmMessageAfter = confirmResult.messageAfter;
|
|
541
|
-
}
|
|
542
|
-
const sdkMethod = sdk[functionInfo.name];
|
|
543
|
-
switch (outputMode) {
|
|
544
|
-
case "paginate": {
|
|
545
|
-
const source = sdkMethod(resolvedParams);
|
|
546
|
-
await renderer.renderPaginatedList(source, functionInfo);
|
|
547
|
-
break;
|
|
548
|
-
}
|
|
549
|
-
case "collect": {
|
|
550
|
-
const maxItems = resolvedParams.maxItems;
|
|
551
|
-
const sdkResult = sdkMethod({ ...resolvedParams, maxItems });
|
|
552
|
-
const allItems = await collectItemsFromResult({
|
|
553
|
-
sdkResult,
|
|
554
|
-
maxItems,
|
|
555
|
-
});
|
|
556
|
-
await renderer.renderCollectedList(allItems, {
|
|
557
|
-
maxItems,
|
|
558
|
-
userSpecifiedMaxItems: hasUserSpecifiedMaxItems,
|
|
559
|
-
functionInfo,
|
|
560
|
-
});
|
|
561
|
-
break;
|
|
562
|
-
}
|
|
563
|
-
case "single": {
|
|
564
|
-
const callSdkMethod = () => {
|
|
565
|
-
if (usesInputParameters) {
|
|
566
|
-
const positionalArgs = reconstructPositionalArgs(functionInfo.inputParameters, resolvedParams);
|
|
567
|
-
return sdkMethod(...positionalArgs);
|
|
568
|
-
}
|
|
569
|
-
return sdkMethod(resolvedParams);
|
|
570
|
-
};
|
|
571
|
-
const outputFile = resolvedParams.output;
|
|
572
|
-
if (outputFile) {
|
|
573
|
-
await callSdkMethod();
|
|
574
|
-
renderer.renderItem(null, {
|
|
575
|
-
outputFile,
|
|
576
|
-
commandName: cliCommandName,
|
|
577
|
-
});
|
|
578
|
-
break;
|
|
579
|
-
}
|
|
580
|
-
const result = await callSdkMethod();
|
|
581
|
-
const normalizedResult = getNormalizedResult(result, {
|
|
582
|
-
isListCommand,
|
|
583
|
-
});
|
|
584
|
-
if (normalizedResult.kind === "response") {
|
|
585
|
-
await renderer.renderResponse(normalizedResult.value);
|
|
586
|
-
}
|
|
587
|
-
else if (normalizedResult.kind === "list") {
|
|
588
|
-
await renderer.renderCollectedList(normalizedResult.data, {
|
|
589
|
-
maxItems: resolvedParams.maxItems,
|
|
590
|
-
userSpecifiedMaxItems: hasUserSpecifiedMaxItems,
|
|
591
|
-
functionInfo,
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
else {
|
|
595
|
-
renderer.renderItem(normalizedResult.value);
|
|
596
|
-
}
|
|
597
|
-
if (confirmMessageAfter) {
|
|
598
|
-
console.log(chalk.yellow(`\n${confirmMessageAfter}`));
|
|
599
|
-
}
|
|
600
|
-
break;
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
catch (error) {
|
|
605
|
-
success = false;
|
|
606
|
-
errorMessage = error instanceof Error ? error.message : String(error);
|
|
607
|
-
if (error instanceof ZapierCliMissingParametersError) {
|
|
608
|
-
renderer.renderError(error);
|
|
609
|
-
}
|
|
610
|
-
else if (error instanceof ZapierCliValidationError) {
|
|
611
|
-
renderer.renderError(error);
|
|
612
|
-
}
|
|
613
|
-
else if (error instanceof ZapierCliError) {
|
|
614
|
-
throw error;
|
|
615
|
-
}
|
|
616
|
-
else {
|
|
617
|
-
renderer.renderError(error);
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
finally {
|
|
621
|
-
try {
|
|
622
|
-
const event = buildCliCommandExecutedEvent({
|
|
623
|
-
data: {
|
|
624
|
-
cli_primary_command: cliCommandName,
|
|
625
|
-
success_flag: success,
|
|
626
|
-
execution_duration_ms: Date.now() - startTime,
|
|
627
|
-
exit_code: success ? 0 : 1,
|
|
628
|
-
error_message: errorMessage,
|
|
629
|
-
command_category: functionInfo.categories?.[0] ?? null,
|
|
630
|
-
requires_auth: null,
|
|
631
|
-
cli_arguments: sanitizeCliArguments(process.argv.slice(2)),
|
|
632
|
-
},
|
|
633
|
-
context: {
|
|
634
|
-
selected_api: resolvedParams.app ?? null,
|
|
635
|
-
},
|
|
636
|
-
});
|
|
637
|
-
sdk.context.eventEmission.emit(CLI_COMMAND_EXECUTED_EVENT_SUBJECT, event);
|
|
638
|
-
}
|
|
639
|
-
catch {
|
|
640
|
-
// Never let telemetry failures affect command execution
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
};
|
|
644
|
-
const handlerWithCallerContext = async (...args) => {
|
|
645
|
-
return runWithCallerContext({ packageOperation: cliCommandName }, () => handler(...args));
|
|
646
|
-
};
|
|
647
|
-
return {
|
|
648
|
-
description,
|
|
649
|
-
parameters,
|
|
650
|
-
handler: handlerWithCallerContext,
|
|
651
|
-
hidden: !!functionInfo.deprecation,
|
|
652
|
-
aliases: functionInfo.aliases,
|
|
653
|
-
supportsJsonOutput: functionInfo.supportsJsonOutput,
|
|
654
|
-
};
|
|
655
|
-
}
|
|
656
|
-
// Collect function for repeatable options (e.g., -d foo -d bar → ['foo', 'bar'])
|
|
657
|
-
function collect(value, previous = []) {
|
|
658
|
-
previous.push(value);
|
|
659
|
-
return previous;
|
|
660
|
-
}
|
|
661
|
-
function addCommand(program, commandName, config) {
|
|
662
|
-
const command = program
|
|
663
|
-
.command(commandName, { hidden: config.hidden ?? false })
|
|
664
|
-
.description(config.description);
|
|
665
|
-
// Track whether we've already used a positional array parameter
|
|
666
|
-
let hasPositionalArray = false;
|
|
667
|
-
// Add parameters to command
|
|
668
|
-
config.parameters.forEach((param) => {
|
|
669
|
-
const kebabName = toKebabCase(param.name);
|
|
670
|
-
if (param.hasResolver && param.required) {
|
|
671
|
-
// Required parameters with resolvers become optional positional arguments (resolver handles prompting)
|
|
672
|
-
command.argument(`[${kebabName}]`, param.description || `${kebabName} parameter`);
|
|
673
|
-
}
|
|
674
|
-
else if (param.required &&
|
|
675
|
-
param.type === "array" &&
|
|
676
|
-
!hasPositionalArray) {
|
|
677
|
-
// First required array parameter becomes a variadic positional argument
|
|
678
|
-
hasPositionalArray = true;
|
|
679
|
-
command.argument(`<${kebabName}...>`, param.description || `${kebabName} parameter`);
|
|
680
|
-
}
|
|
681
|
-
else if (param.required && param.type === "array") {
|
|
682
|
-
// Subsequent required array parameters become required flags (repeatable)
|
|
683
|
-
const flags = [`--${kebabName}`];
|
|
684
|
-
const flagSignature = flags.join(", ") + ` <value>`;
|
|
685
|
-
command.requiredOption(flagSignature, param.description || `${kebabName} parameter (required, repeatable)`, collect, []);
|
|
686
|
-
}
|
|
687
|
-
else if (param.required) {
|
|
688
|
-
// Required parameters without resolvers become required positional arguments
|
|
689
|
-
command.argument(`<${kebabName}>`, param.description || `${kebabName} parameter`);
|
|
690
|
-
}
|
|
691
|
-
else if (param.isPositional && !param.isDeprecated && !param.isAlias) {
|
|
692
|
-
// Optional parameters marked as positional become optional positional arguments
|
|
693
|
-
command.argument(`[${kebabName}]`, param.description || `${kebabName} parameter`);
|
|
694
|
-
}
|
|
695
|
-
else {
|
|
696
|
-
// Optional parameters become flags (whether they have resolvers or not)
|
|
697
|
-
const flags = [];
|
|
698
|
-
// Add short alias if defined (single-letter aliases only)
|
|
699
|
-
const alias = config.aliases?.[param.name];
|
|
700
|
-
if (alias && alias.length === 1) {
|
|
701
|
-
flags.push(`-${alias}`);
|
|
702
|
-
}
|
|
703
|
-
flags.push(`--${kebabName}`);
|
|
704
|
-
if (param.type === "boolean") {
|
|
705
|
-
const opt = new Option(flags.join(", "), param.description);
|
|
706
|
-
if (param.isDeprecated)
|
|
707
|
-
opt.hideHelp();
|
|
708
|
-
command.addOption(opt);
|
|
709
|
-
}
|
|
710
|
-
else if (param.type === "array") {
|
|
711
|
-
// For arrays, use collect pattern for repeatable flags (e.g., -d foo -d bar)
|
|
712
|
-
const flagSignature = flags.join(", ") + ` <value>`;
|
|
713
|
-
const opt = new Option(flagSignature, param.description || "");
|
|
714
|
-
opt.default([]);
|
|
715
|
-
opt.argParser((value, previous) => (previous || []).concat([value]));
|
|
716
|
-
if (param.isDeprecated)
|
|
717
|
-
opt.hideHelp();
|
|
718
|
-
command.addOption(opt);
|
|
719
|
-
}
|
|
720
|
-
else {
|
|
721
|
-
const flagSignature = flags.join(", ") + ` <${param.type}>`;
|
|
722
|
-
const opt = new Option(flagSignature, param.description || "");
|
|
723
|
-
if (param.default !== undefined) {
|
|
724
|
-
opt.default(param.default);
|
|
725
|
-
}
|
|
726
|
-
if (param.isDeprecated)
|
|
727
|
-
opt.hideHelp();
|
|
728
|
-
command.addOption(opt);
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
});
|
|
732
|
-
// Add shared command options (if not already included or excluded by interactive mode)
|
|
733
|
-
const paramNames = new Set(config.parameters.map((p) => p.name));
|
|
734
|
-
SHARED_COMMAND_CLI_OPTIONS.forEach((opt) => {
|
|
735
|
-
if (paramNames.has(opt.name))
|
|
736
|
-
return;
|
|
737
|
-
if (config.supportsJsonOutput === false && opt.name === "json")
|
|
738
|
-
return;
|
|
739
|
-
command.option(opt.flag, opt.description);
|
|
740
|
-
});
|
|
741
|
-
command.action(config.handler);
|
|
742
|
-
}
|
|
743
|
-
// ============================================================================
|
|
744
|
-
// Parameter Conversion
|
|
745
|
-
// ============================================================================
|
|
746
|
-
function convertCliArgsToSdkParams(parameters, positionalArgs, options) {
|
|
747
|
-
const sdkParams = {};
|
|
748
|
-
// Handle positional arguments (required parameters or optional positional parameters)
|
|
749
|
-
let argIndex = 0;
|
|
750
|
-
parameters.forEach((param) => {
|
|
751
|
-
if ((param.required ||
|
|
752
|
-
(param.isPositional && !param.isDeprecated && !param.isAlias)) &&
|
|
753
|
-
argIndex < positionalArgs.length) {
|
|
754
|
-
// Use the original camelCase parameter name for the SDK
|
|
755
|
-
sdkParams[param.name] = convertValue(positionalArgs[argIndex], param.type, param.elementType);
|
|
756
|
-
argIndex++;
|
|
757
|
-
}
|
|
758
|
-
});
|
|
759
|
-
// Handle option flags
|
|
760
|
-
Object.entries(options).forEach(([key, value]) => {
|
|
761
|
-
// Convert kebab-case back to camelCase
|
|
762
|
-
const camelKey = key.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
|
763
|
-
const param = parameters.find((p) => p.name === camelKey);
|
|
764
|
-
if (param && value !== undefined) {
|
|
765
|
-
// Skip empty arrays — Commander initializes repeatable options with []
|
|
766
|
-
// so an empty array means the user didn't pass the flag. Omitting it
|
|
767
|
-
// lets Zod's .default() supply the intended default value.
|
|
768
|
-
if (param.type === "array" &&
|
|
769
|
-
Array.isArray(value) &&
|
|
770
|
-
value.length === 0) {
|
|
771
|
-
return;
|
|
772
|
-
}
|
|
773
|
-
sdkParams[camelKey] = convertValue(value, param.type, param.elementType);
|
|
774
|
-
}
|
|
775
|
-
});
|
|
776
|
-
return sdkParams;
|
|
777
|
-
}
|
|
778
|
-
function convertValue(value, type, elementType) {
|
|
779
|
-
// Don't convert undefined values - let the resolver system handle them
|
|
780
|
-
if (value === undefined) {
|
|
781
|
-
return undefined;
|
|
782
|
-
}
|
|
783
|
-
switch (type) {
|
|
784
|
-
case "number":
|
|
785
|
-
return Number(value);
|
|
786
|
-
case "boolean":
|
|
787
|
-
return Boolean(value);
|
|
788
|
-
case "array": {
|
|
789
|
-
const arr = Array.isArray(value) ? value : [value];
|
|
790
|
-
if (elementType !== "object")
|
|
791
|
-
return arr;
|
|
792
|
-
return arr.flatMap((item) => {
|
|
793
|
-
if (typeof item === "string" &&
|
|
794
|
-
(item.startsWith("{") || item.startsWith("["))) {
|
|
795
|
-
try {
|
|
796
|
-
return JSON.parse(item);
|
|
797
|
-
}
|
|
798
|
-
catch {
|
|
799
|
-
return item;
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
return item;
|
|
803
|
-
});
|
|
804
|
-
}
|
|
805
|
-
case "string":
|
|
806
|
-
return value;
|
|
807
|
-
case "object":
|
|
808
|
-
// Parse JSON string to object for z.record() and similar types
|
|
809
|
-
if (typeof value === "string") {
|
|
810
|
-
try {
|
|
811
|
-
return JSON.parse(value);
|
|
812
|
-
}
|
|
813
|
-
catch {
|
|
814
|
-
return value;
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
return value;
|
|
818
|
-
default:
|
|
819
|
-
// Unknown schema types - try to parse if it looks like JSON
|
|
820
|
-
if (typeof value === "string" &&
|
|
821
|
-
(value.startsWith("{") || value.startsWith("["))) {
|
|
822
|
-
try {
|
|
823
|
-
return JSON.parse(value);
|
|
824
|
-
}
|
|
825
|
-
catch {
|
|
826
|
-
return value;
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
return value;
|
|
830
|
-
}
|
|
831
|
-
}
|