@zapier/zapier-sdk-cli 0.52.10 → 0.52.12

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.
Files changed (51) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +19 -1
  3. package/dist/cli.cjs +80 -82
  4. package/dist/cli.mjs +81 -83
  5. package/dist/experimental.cjs +17 -26
  6. package/dist/experimental.d.mts +1 -1
  7. package/dist/experimental.d.ts +1 -1
  8. package/dist/experimental.mjs +16 -25
  9. package/dist/index.cjs +18 -27
  10. package/dist/index.d.mts +1 -1
  11. package/dist/index.d.ts +1 -1
  12. package/dist/index.mjs +16 -25
  13. package/dist/login.cjs +8 -10
  14. package/dist/login.d.mts +2 -10
  15. package/dist/login.d.ts +2 -10
  16. package/dist/login.mjs +5 -9
  17. package/dist/package.json +1 -1
  18. package/dist/{sdk-B3nKAZdN.d.mts → sdk-Sa1HjzUj.d.mts} +14 -14
  19. package/dist/{sdk-B3nKAZdN.d.ts → sdk-Sa1HjzUj.d.ts} +14 -14
  20. package/dist/src/experimental.js +29 -27
  21. package/dist/src/login/index.d.ts +1 -9
  22. package/dist/src/login/index.js +12 -14
  23. package/dist/src/plugins/add/index.d.ts +15 -15
  24. package/dist/src/plugins/add/index.js +1 -1
  25. package/dist/src/plugins/buildManifest/index.d.ts +2 -2
  26. package/dist/src/plugins/bundleCode/index.d.ts +1 -1
  27. package/dist/src/plugins/bundleCode/index.js +2 -1
  28. package/dist/src/plugins/cliOverrides/index.d.ts +5 -10
  29. package/dist/src/plugins/cliOverrides/index.js +2 -6
  30. package/dist/src/plugins/curl/index.d.ts +2 -2
  31. package/dist/src/plugins/curl/schemas.d.ts +2 -2
  32. package/dist/src/plugins/feedback/index.d.ts +1 -1
  33. package/dist/src/plugins/generateAppTypes/index.d.ts +11 -11
  34. package/dist/src/plugins/getLoginConfigPath/index.d.ts +1 -1
  35. package/dist/src/plugins/index.d.ts +1 -1
  36. package/dist/src/plugins/index.js +1 -1
  37. package/dist/src/plugins/init/index.d.ts +1 -1
  38. package/dist/src/plugins/login/index.d.ts +1 -1
  39. package/dist/src/plugins/logout/index.d.ts +1 -1
  40. package/dist/src/plugins/mcp/index.d.ts +1 -1
  41. package/dist/src/sdk.js +31 -20
  42. package/dist/src/utils/cli-generator.js +14 -7
  43. package/dist/src/utils/cli-renderer.d.ts +13 -3
  44. package/dist/src/utils/cli-renderer.js +27 -20
  45. package/dist/src/utils/log.js +9 -4
  46. package/dist/src/utils/parameter-resolver.js +3 -1
  47. package/dist/src/utils/schema-formatter.d.ts +2 -2
  48. package/dist/src/utils/schema-formatter.js +4 -30
  49. package/dist/src/utils/version-checker.js +8 -3
  50. package/dist/tsconfig.tsbuildinfo +1 -1
  51. package/package.json +3 -3
@@ -67,19 +67,19 @@ export declare const generateAppTypesPlugin: (sdk: {
67
67
  } & {
68
68
  context: {
69
69
  meta: {
70
- listApps: import("@zapier/zapier-sdk").PluginMeta;
70
+ listApps: import("@zapier/zapier-sdk").PluginMeta<unknown>;
71
71
  };
72
72
  };
73
73
  } & {
74
74
  listActions: (options?: (({
75
75
  app: string;
76
- actionType?: "filter" | "read" | "read_bulk" | "run" | "search" | "search_and_write" | "search_or_write" | "write" | undefined;
76
+ actionType?: "read" | "read_bulk" | "write" | "search" | "search_or_write" | "search_and_write" | "filter" | "run" | undefined;
77
77
  pageSize?: number | undefined;
78
78
  maxItems?: number | undefined;
79
79
  cursor?: string | undefined;
80
80
  } | {
81
81
  appKey: string;
82
- actionType?: "filter" | "read" | "read_bulk" | "run" | "search" | "search_and_write" | "search_or_write" | "write" | undefined;
82
+ actionType?: "read" | "read_bulk" | "write" | "search" | "search_or_write" | "search_and_write" | "filter" | "run" | undefined;
83
83
  pageSize?: number | undefined;
84
84
  maxItems?: number | undefined;
85
85
  cursor?: string | undefined;
@@ -91,24 +91,24 @@ export declare const generateAppTypesPlugin: (sdk: {
91
91
  description: string;
92
92
  key: string;
93
93
  app_key: string;
94
- action_type: "filter" | "read" | "read_bulk" | "run" | "search" | "search_and_write" | "search_or_write" | "write";
94
+ action_type: "read" | "read_bulk" | "write" | "search" | "search_or_write" | "search_and_write" | "filter" | "run";
95
95
  title: string;
96
96
  type: "action";
97
+ is_hidden?: boolean | undefined;
97
98
  id?: string | undefined;
98
99
  is_important?: boolean | undefined;
99
- is_hidden?: boolean | undefined;
100
100
  app_version?: string | undefined;
101
101
  }>;
102
102
  } & {
103
103
  context: {
104
104
  meta: {
105
- listActions: import("@zapier/zapier-sdk").PluginMeta;
105
+ listActions: import("@zapier/zapier-sdk").PluginMeta<unknown>;
106
106
  };
107
107
  };
108
108
  } & {
109
109
  listActionInputFields: (options?: (({
110
110
  app: string;
111
- actionType: "filter" | "read" | "read_bulk" | "run" | "search" | "search_and_write" | "search_or_write" | "write";
111
+ actionType: "read" | "read_bulk" | "write" | "search" | "search_or_write" | "search_and_write" | "filter" | "run";
112
112
  action: string;
113
113
  connection?: string | number | undefined;
114
114
  connectionId?: string | number | null | undefined;
@@ -119,7 +119,7 @@ export declare const generateAppTypesPlugin: (sdk: {
119
119
  cursor?: string | undefined;
120
120
  } | {
121
121
  appKey: string;
122
- actionType: "filter" | "read" | "read_bulk" | "run" | "search" | "search_and_write" | "search_or_write" | "write";
122
+ actionType: "read" | "read_bulk" | "write" | "search" | "search_or_write" | "search_and_write" | "filter" | "run";
123
123
  actionKey: string;
124
124
  connection?: string | number | undefined;
125
125
  connectionId?: string | number | null | undefined;
@@ -156,7 +156,7 @@ export declare const generateAppTypesPlugin: (sdk: {
156
156
  } & {
157
157
  context: {
158
158
  meta: {
159
- listActionInputFields: import("@zapier/zapier-sdk").PluginMeta;
159
+ listActionInputFields: import("@zapier/zapier-sdk").PluginMeta<unknown>;
160
160
  };
161
161
  };
162
162
  } & {
@@ -213,7 +213,7 @@ export declare const generateAppTypesPlugin: (sdk: {
213
213
  } & {
214
214
  context: {
215
215
  meta: {
216
- listConnections: import("@zapier/zapier-sdk").PluginMeta;
216
+ listConnections: import("@zapier/zapier-sdk").PluginMeta<unknown>;
217
217
  };
218
218
  };
219
219
  } & {
@@ -258,7 +258,7 @@ export declare const generateAppTypesPlugin: (sdk: {
258
258
  } & {
259
259
  context: {
260
260
  meta: {
261
- generateAppTypes: import("@zapier/zapier-sdk").PluginMeta;
261
+ generateAppTypes: import("@zapier/zapier-sdk").PluginMeta<unknown>;
262
262
  };
263
263
  };
264
264
  };
@@ -9,7 +9,7 @@ export declare const getLoginConfigPathPlugin: (sdk: {
9
9
  } & {
10
10
  context: {
11
11
  meta: {
12
- getLoginConfigPath: import("@zapier/zapier-sdk").PluginMeta;
12
+ getLoginConfigPath: import("@zapier/zapier-sdk").PluginMeta<unknown>;
13
13
  };
14
14
  };
15
15
  };
@@ -3,7 +3,7 @@ export { logoutPlugin } from "./logout";
3
3
  export { mcpPlugin } from "./mcp";
4
4
  export { bundleCodePlugin } from "./bundleCode";
5
5
  export { getLoginConfigPathPlugin } from "./getLoginConfigPath";
6
- export { addPlugin } from "./add";
6
+ export { addAppsPlugin } from "./add";
7
7
  export { generateAppTypesPlugin } from "./generateAppTypes";
8
8
  export { buildManifestPlugin } from "./buildManifest";
9
9
  export { feedbackPlugin } from "./feedback";
@@ -3,7 +3,7 @@ export { logoutPlugin } from "./logout";
3
3
  export { mcpPlugin } from "./mcp";
4
4
  export { bundleCodePlugin } from "./bundleCode";
5
5
  export { getLoginConfigPathPlugin } from "./getLoginConfigPath";
6
- export { addPlugin } from "./add";
6
+ export { addAppsPlugin } from "./add";
7
7
  export { generateAppTypesPlugin } from "./generateAppTypes";
8
8
  export { buildManifestPlugin } from "./buildManifest";
9
9
  export { feedbackPlugin } from "./feedback";
@@ -14,7 +14,7 @@ export declare const initPlugin: (sdk: {
14
14
  } & {
15
15
  context: {
16
16
  meta: {
17
- init: import("@zapier/zapier-sdk").PluginMeta;
17
+ init: import("@zapier/zapier-sdk").PluginMeta<unknown>;
18
18
  };
19
19
  };
20
20
  };
@@ -29,7 +29,7 @@ export declare const loginPlugin: (sdk: {
29
29
  } & {
30
30
  context: {
31
31
  meta: {
32
- login: import("@zapier/zapier-sdk").PluginMeta;
32
+ login: import("@zapier/zapier-sdk").PluginMeta<unknown>;
33
33
  };
34
34
  };
35
35
  };
@@ -22,7 +22,7 @@ export declare const logoutPlugin: (sdk: {
22
22
  } & {
23
23
  context: {
24
24
  meta: {
25
- logout: import("@zapier/zapier-sdk").PluginMeta;
25
+ logout: import("@zapier/zapier-sdk").PluginMeta<unknown>;
26
26
  };
27
27
  };
28
28
  };
@@ -21,7 +21,7 @@ export declare const mcpPlugin: (sdk: {
21
21
  } & {
22
22
  context: {
23
23
  meta: {
24
- mcp: import("@zapier/zapier-sdk").PluginMeta;
24
+ mcp: import("@zapier/zapier-sdk").PluginMeta<unknown>;
25
25
  };
26
26
  };
27
27
  };
package/dist/src/sdk.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as cliLogin from "./login";
2
- import { createZapierSdk, injectCliLogin, } from "@zapier/zapier-sdk";
3
- import { loginPlugin, logoutPlugin, mcpPlugin, bundleCodePlugin, getLoginConfigPathPlugin, addPlugin, generateAppTypesPlugin, buildManifestPlugin, feedbackPlugin, curlPlugin, cliOverridesPlugin, initPlugin,
2
+ import { addPlugin, createZapierSdkStack, injectCliLogin, } from "@zapier/zapier-sdk";
3
+ import { loginPlugin, logoutPlugin, mcpPlugin, bundleCodePlugin, getLoginConfigPathPlugin, addAppsPlugin, generateAppTypesPlugin, buildManifestPlugin, feedbackPlugin, curlPlugin, cliOverridesPlugin, initPlugin,
4
4
  // drainTriggerInboxForeverCliPlugin is experimental — registered only
5
5
  // in `./experimental.ts`. See the "Experimental gating" section in
6
6
  // `docs/design/2026-05-01-triggers-in-sdk.md`.
@@ -19,37 +19,48 @@ export function createZapierCliSdk(options = {}) {
19
19
  const extensionsContextPlugin = () => ({
20
20
  context: { extensions },
21
21
  });
22
- let chain = createZapierSdk({
22
+ const sdk = createZapierSdkStack({
23
23
  ...sdkOptions,
24
24
  eventEmission: { ...sdkOptions.eventEmission, callContext: "cli" },
25
25
  callerPackage: { name: packageJson.name, version: packageJson.version },
26
26
  })
27
- .addPlugin(extensionsContextPlugin)
28
- .addPlugin(generateAppTypesPlugin)
29
- .addPlugin(buildManifestPlugin)
30
- .addPlugin(bundleCodePlugin)
31
- .addPlugin(getLoginConfigPathPlugin)
32
- .addPlugin(addPlugin)
33
- .addPlugin(feedbackPlugin)
34
- .addPlugin(curlPlugin)
35
- .addPlugin(initPlugin)
36
- .addPlugin(mcpPlugin)
37
- .addPlugin(loginPlugin)
38
- .addPlugin(logoutPlugin)
39
- .addPlugin(cliOverridesPlugin);
27
+ .use(extensionsContextPlugin)
28
+ .use(generateAppTypesPlugin)
29
+ .use(buildManifestPlugin)
30
+ .use(bundleCodePlugin)
31
+ .use(getLoginConfigPathPlugin)
32
+ .use(addAppsPlugin)
33
+ .use(feedbackPlugin)
34
+ .use(curlPlugin)
35
+ .use(initPlugin)
36
+ .use(mcpPlugin)
37
+ .use(loginPlugin)
38
+ .use(logoutPlugin)
39
+ // cliOverridesPlugin patches existing meta entries (e.g. flags `fetch`
40
+ // as deprecated) without re-registering the method. `.use` throws on
41
+ // meta-key collisions by default, so the intent has to be explicit.
42
+ .use(cliOverridesPlugin, { override: true })
43
+ .toSdk();
40
44
  // Construct extensions defensively. The loader (`utils/extensions.ts`)
41
45
  // already isolates *load*-time failures (failed dynamic imports);
42
46
  // here we cover the second failure mode — a successfully-imported
43
47
  // plugin that throws during construction (bad context lookup, schema
44
- // build error, composePlugins collision, etc.). Honors the
45
- // design-doc promise that "a broken extension does not kill the CLI."
48
+ // build error, plugin collision, etc.). Honors the design-doc promise
49
+ // that "a broken extension does not kill the CLI."
50
+ //
51
+ // `addPlugin` mutates `sdk` in place and `mergeContribution` is
52
+ // atomic (validate-all-then-apply), so a failed extension leaves
53
+ // the sdk in its prior consistent state. Base plugins run exactly
54
+ // once regardless of how many extensions are installed, so the
55
+ // `eventEmission` startup payload reaches the wire once per
56
+ // process.
46
57
  for (const ext of extensions) {
47
58
  try {
48
- chain = chain.addPlugin(ext);
59
+ addPlugin(sdk, ext);
49
60
  }
50
61
  catch (err) {
51
62
  console.warn(`Extension plugin failed to construct: ${err.message}; skipping.`);
52
63
  }
53
64
  }
54
- return chain;
65
+ return sdk;
55
66
  }
@@ -472,14 +472,20 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
472
472
  const startTime = Date.now();
473
473
  let success = true;
474
474
  let errorMessage = null;
475
- let resolvedParams = {};
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 = {};
476
482
  // The last argument is always the command object with parsed options
477
483
  const commandObj = args[args.length - 1];
478
484
  const options = commandObj.opts();
479
485
  // interactiveMode is true by default; --json disables it
480
486
  const interactiveMode = !options.json;
481
487
  const renderer = interactiveMode
482
- ? createInteractiveRenderer()
488
+ ? createInteractiveRenderer({ sdk, params: resolvedParams })
483
489
  : createJsonRenderer();
484
490
  try {
485
491
  emitDeprecationWarning({
@@ -509,15 +515,16 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
509
515
  }
510
516
  if (schema && !usesInputParameters) {
511
517
  const resolver = new SchemaParameterResolver();
512
- resolvedParams = (await resolver.resolveParameters(schema, rawParams, sdk, functionInfo.name, {
518
+ const resolved = (await resolver.resolveParameters(schema, rawParams, sdk, functionInfo.name, {
513
519
  interactiveMode,
514
520
  debug: !!options.debug ||
515
521
  process.env.DEBUG === "true" ||
516
522
  process.argv.includes("--debug"),
517
523
  }));
524
+ Object.assign(resolvedParams, resolved);
518
525
  }
519
526
  else {
520
- resolvedParams = rawParams;
527
+ Object.assign(resolvedParams, rawParams);
521
528
  }
522
529
  const confirm = functionInfo.confirm;
523
530
  let confirmMessageAfter;
@@ -543,7 +550,7 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
543
550
  sdkResult,
544
551
  maxItems,
545
552
  });
546
- renderer.renderCollectedList(allItems, {
553
+ await renderer.renderCollectedList(allItems, {
547
554
  maxItems,
548
555
  userSpecifiedMaxItems: hasUserSpecifiedMaxItems,
549
556
  functionInfo,
@@ -575,7 +582,7 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
575
582
  await renderer.renderResponse(normalizedResult.value);
576
583
  }
577
584
  else if (normalizedResult.kind === "list") {
578
- renderer.renderCollectedList(normalizedResult.data, {
585
+ await renderer.renderCollectedList(normalizedResult.data, {
579
586
  maxItems: resolvedParams.maxItems,
580
587
  userSpecifiedMaxItems: hasUserSpecifiedMaxItems,
581
588
  functionInfo,
@@ -635,7 +642,7 @@ function createCommandConfig(cliCommandName, functionInfo, sdk) {
635
642
  description,
636
643
  parameters,
637
644
  handler,
638
- hidden: functionInfo.categories?.includes("deprecated") ?? false,
645
+ hidden: !!functionInfo.deprecation,
639
646
  aliases: functionInfo.aliases,
640
647
  supportsJsonOutput: functionInfo.supportsJsonOutput,
641
648
  };
@@ -1,4 +1,4 @@
1
- import type { FunctionRegistryEntry, SdkPage } from "@zapier/zapier-sdk";
1
+ import type { FunctionRegistryEntry, SdkPage, ZapierSdk } from "@zapier/zapier-sdk";
2
2
  export interface JsonErrorEntry {
3
3
  code: string;
4
4
  message: string;
@@ -15,7 +15,7 @@ export interface CliRenderer {
15
15
  maxItems?: number;
16
16
  userSpecifiedMaxItems?: boolean;
17
17
  functionInfo?: FunctionRegistryEntry;
18
- }): void;
18
+ }): Promise<void>;
19
19
  renderItem(value: unknown, options?: {
20
20
  outputFile?: unknown;
21
21
  commandName?: string;
@@ -24,6 +24,16 @@ export interface CliRenderer {
24
24
  renderResponse(response: Response): Promise<void>;
25
25
  renderError(error: unknown): never;
26
26
  }
27
+ /**
28
+ * Per-invocation context the interactive renderer threads into the registry
29
+ * formatter. `sdk` and `params` are passed to `formatter.fetch(...)` so a
30
+ * formatter can enrich items by calling back into the SDK (for example, the
31
+ * table-record formatter resolves field IDs to human-readable names).
32
+ */
33
+ export interface RendererContext {
34
+ sdk?: ZapierSdk;
35
+ params?: Record<string, unknown>;
36
+ }
27
37
  export declare function buildJsonErrors(error: unknown): JsonErrorEntry[];
28
38
  /**
29
39
  * Replacer for JSON.stringify that coerces Error instances to a plain
@@ -38,5 +48,5 @@ export declare function buildJsonErrors(error: unknown): JsonErrorEntry[];
38
48
  */
39
49
  export declare function jsonReplacer(_key: string, value: unknown): unknown;
40
50
  export declare function createJsonRenderer(): CliRenderer;
41
- export declare function createInteractiveRenderer(): CliRenderer;
51
+ export declare function createInteractiveRenderer(context?: RendererContext): CliRenderer;
42
52
  export {};
@@ -93,7 +93,7 @@ export function createJsonRenderer() {
93
93
  errors: [],
94
94
  });
95
95
  },
96
- renderCollectedList(items, _options) {
96
+ async renderCollectedList(items, _options) {
97
97
  outputJson({ data: items, errors: [] });
98
98
  },
99
99
  renderItem(value, options) {
@@ -131,22 +131,29 @@ function getListTitle(functionInfo) {
131
131
  return `Available ${functionInfo.itemType} items`;
132
132
  return "items";
133
133
  }
134
- function renderItemsForDisplay(items, functionInfo, startingNumber = 0) {
135
- if (functionInfo?.inputSchema) {
136
- formatItemsFromSchema(functionInfo, items, startingNumber);
137
- }
138
- else {
139
- items.forEach((item, index) => {
140
- const obj = item;
141
- const name = obj?.name || obj?.key || obj?.id || "Item";
142
- console.log(`${chalk.gray(`${startingNumber + index + 1}.`)} ${chalk.cyan(String(name))}`);
143
- if (obj?.description)
144
- console.log(` ${chalk.dim(String(obj.description))}`);
145
- console.log();
146
- });
134
+ export function createInteractiveRenderer(context = {}) {
135
+ async function renderItemsForDisplay(items, functionInfo, startingNumber = 0) {
136
+ if (functionInfo?.inputSchema) {
137
+ // `formatter` on the registry entry is typed `unknown` so the registry
138
+ // layer stays SDK-agnostic; cast back to the CLI-side shape here at the
139
+ // boundary where we actually use it.
140
+ await formatItemsFromSchema(functionInfo, items, startingNumber, {
141
+ formatter: functionInfo.formatter,
142
+ sdk: context.sdk,
143
+ params: context.params,
144
+ });
145
+ }
146
+ else {
147
+ items.forEach((item, index) => {
148
+ const obj = item;
149
+ const name = obj?.name || obj?.key || obj?.id || "Item";
150
+ console.log(`${chalk.gray(`${startingNumber + index + 1}.`)} ${chalk.cyan(String(name))}`);
151
+ if (obj?.description)
152
+ console.log(` ${chalk.dim(String(obj.description))}`);
153
+ console.log();
154
+ });
155
+ }
147
156
  }
148
- }
149
- export function createInteractiveRenderer() {
150
157
  return {
151
158
  async renderPaginatedList(source, functionInfo) {
152
159
  const itemName = getItemName(functionInfo);
@@ -156,7 +163,7 @@ export function createInteractiveRenderer() {
156
163
  console.log(chalk.yellow(`No ${itemName} found.`));
157
164
  return;
158
165
  }
159
- renderItemsForDisplay(items, functionInfo, 0);
166
+ await renderItemsForDisplay(items, functionInfo, 0);
160
167
  console.log(chalk.green(`\n✅ Showing ${items.length} ${itemName}`));
161
168
  return;
162
169
  }
@@ -176,7 +183,7 @@ export function createInteractiveRenderer() {
176
183
  console.clear();
177
184
  console.log(chalk.blue(`📋 ${getListTitle(functionInfo)}\n`));
178
185
  }
179
- renderItemsForDisplay(items, functionInfo, totalShown);
186
+ await renderItemsForDisplay(items, functionInfo, totalShown);
180
187
  totalShown += items.length;
181
188
  console.log(chalk.green(`\n✅ Showing ${totalShown} ${itemName} (page ${pageCount})`));
182
189
  if (page.nextCursor) {
@@ -197,7 +204,7 @@ export function createInteractiveRenderer() {
197
204
  }
198
205
  console.log(chalk.gray(`\n📄 Finished browsing ${itemName}`));
199
206
  },
200
- renderCollectedList(items, { maxItems, userSpecifiedMaxItems, functionInfo } = {}) {
207
+ async renderCollectedList(items, { maxItems, userSpecifiedMaxItems, functionInfo } = {}) {
201
208
  if (!Array.isArray(items)) {
202
209
  formatJsonOutput(items);
203
210
  return;
@@ -208,7 +215,7 @@ export function createInteractiveRenderer() {
208
215
  return;
209
216
  }
210
217
  console.log(chalk.green(`\n✅ Found ${items.length} ${itemName}:\n`));
211
- renderItemsForDisplay(items, functionInfo);
218
+ await renderItemsForDisplay(items, functionInfo);
212
219
  if (userSpecifiedMaxItems && maxItems) {
213
220
  console.log(chalk.gray(`\n📄 Showing up to ${maxItems} ${itemName} (--max-items ${maxItems})`));
214
221
  }
@@ -1,20 +1,25 @@
1
1
  import chalk from "chalk";
2
+ // Every method here writes to stderr. The CLI reserves stdout for the
3
+ // program's data payload (command output, JSON, response bodies); status,
4
+ // info, warnings, errors, and debug all belong on stderr so they don't
5
+ // break callers piping CLI output through jq, > redirect, or JSON.parse.
6
+ // In a TTY both streams interleave, so interactive users see no change.
2
7
  const log = {
3
8
  info: (message, ...args) => {
4
- console.log(chalk.blue("ℹ"), message, ...args);
9
+ console.error(chalk.blue("ℹ"), message, ...args);
5
10
  },
6
11
  error: (message, ...args) => {
7
12
  console.error(chalk.red("✖"), message, ...args);
8
13
  },
9
14
  success: (message, ...args) => {
10
- console.log(chalk.green("✓"), message, ...args);
15
+ console.error(chalk.green("✓"), message, ...args);
11
16
  },
12
17
  warn: (message, ...args) => {
13
- console.log(chalk.yellow("⚠"), message, ...args);
18
+ console.error(chalk.yellow("⚠"), message, ...args);
14
19
  },
15
20
  debug: (message, ...args) => {
16
21
  if (process.env.DEBUG === "true" || process.argv.includes("--debug")) {
17
- console.log(chalk.gray("🐛"), message, ...args);
22
+ console.error(chalk.gray("🐛"), message, ...args);
18
23
  }
19
24
  },
20
25
  };
@@ -129,7 +129,9 @@ export class SchemaParameterResolver {
129
129
  debugLog(message) {
130
130
  if (this.debug) {
131
131
  this.stopSpinner();
132
- console.log(chalk.gray(`[Zapier CLI] ${message}`));
132
+ // stderr so debug output never pollutes stdout (jq, > redirect,
133
+ // JSON.parse all consume stdout).
134
+ console.error(chalk.gray(`[Zapier CLI] ${message}`));
133
135
  }
134
136
  }
135
137
  startSpinner() {
@@ -1,11 +1,11 @@
1
1
  import type { z } from "zod";
2
2
  import type { OutputFormatter, ZapierSdk } from "@zapier/zapier-sdk";
3
3
  export declare function formatJsonOutput(data: unknown): void;
4
- export declare function formatItemsFromSchema(functionInfo: {
4
+ export declare function formatItemsFromSchema(_functionInfo: {
5
5
  inputSchema: z.ZodType;
6
6
  outputSchema?: z.ZodType;
7
7
  }, items: unknown[], startingNumber?: number, options?: {
8
- formatter?: OutputFormatter;
8
+ formatter?: OutputFormatter<ZapierSdk>;
9
9
  sdk?: ZapierSdk;
10
10
  params?: Record<string, unknown>;
11
11
  }): Promise<void>;
@@ -1,16 +1,6 @@
1
1
  import chalk from "chalk";
2
2
  import util from "util";
3
3
  import wrapAnsi from "wrap-ansi";
4
- // These functions are internal to SDK, implementing basic formatting fallback
5
- // TODO: Consider exposing these utilities or implementing proper CLI formatting
6
- function getFormatMetadata(schema) {
7
- return schema?._zod
8
- ?.def?.formatMeta;
9
- }
10
- function getOutputSchema(schema) {
11
- return schema?._zod?.def
12
- ?.outputSchema;
13
- }
14
4
  // ============================================================================
15
5
  // JSON Formatting
16
6
  // ============================================================================
@@ -25,8 +15,8 @@ export function formatJsonOutput(data) {
25
15
  // ============================================================================
26
16
  // Generic Schema-Driven Formatter
27
17
  // ============================================================================
28
- export async function formatItemsFromSchema(functionInfo, items, startingNumber = 0, options) {
29
- // If a registry-level OutputFormatter is provided, use it
18
+ export async function formatItemsFromSchema(_functionInfo, items, startingNumber = 0, options) {
19
+ // Use the registry-level formatter when the plugin declared one.
30
20
  if (options?.formatter) {
31
21
  let context;
32
22
  if (options.formatter.fetch && options.sdk && options.params) {
@@ -40,24 +30,8 @@ export async function formatItemsFromSchema(functionInfo, items, startingNumber
40
30
  });
41
31
  return;
42
32
  }
43
- // Get the output schema from function info or fall back to input schema output schema
44
- const outputSchema = functionInfo.outputSchema || getOutputSchema(functionInfo.inputSchema);
45
- if (!outputSchema) {
46
- // Fallback to generic formatting if no output schema
47
- formatItemsGeneric(items, startingNumber);
48
- return;
49
- }
50
- const formatMeta = getFormatMetadata(outputSchema);
51
- if (!formatMeta) {
52
- // Fallback to generic formatting if no format metadata
53
- formatItemsGeneric(items, startingNumber);
54
- return;
55
- }
56
- // Format each item using the schema metadata
57
- items.forEach((item, index) => {
58
- const formatted = formatMeta.format(item);
59
- formatSingleItem(formatted, startingNumber + index);
60
- });
33
+ // No formatter declared; fall back to generic field-sniffing.
34
+ formatItemsGeneric(items, startingNumber);
61
35
  }
62
36
  function formatSingleItem(formatted, itemNumber) {
63
37
  // Build the main title line with optional subtitle
@@ -1,4 +1,4 @@
1
- import packageJsonLib from "package-json";
1
+ import packageJsonLib, { VersionNotFoundError } from "package-json";
2
2
  import chalk from "chalk";
3
3
  import log from "./log";
4
4
  import { getConfig } from "../login";
@@ -94,8 +94,13 @@ export async function checkForUpdates({ packageName, currentVersion, }) {
94
94
  currentPackageInfo = await fetchCachedPackageInfo(packageName, currentVersion);
95
95
  }
96
96
  catch (error) {
97
- // If we can't fetch the current version info, use the latest version info
98
- log.debug(`Failed to check deprecation for current version: ${error}`);
97
+ // A `VersionNotFoundError` is the normal state during a publish
98
+ // pipeline: the running CLI is the very build about to be published,
99
+ // so npm doesn't have it yet. Silently fall back to the latest info
100
+ // and only log unexpected errors.
101
+ if (!(error instanceof VersionNotFoundError)) {
102
+ log.debug(`Failed to check deprecation for current version: ${error}`);
103
+ }
99
104
  currentPackageInfo = latestPackageInfo;
100
105
  }
101
106
  const isDeprecated = Boolean(currentPackageInfo.deprecated);