@brew.new/cli 0.5.0 → 0.8.0

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/dist/bin.js CHANGED
@@ -31,6 +31,14 @@ var CliApiError = class extends Error {
31
31
  suggestion;
32
32
  docs;
33
33
  requestId;
34
+ /**
35
+ * The envelope's `details` object when the API sent one — for a
36
+ * trigger-fire `payload_mismatch` that is `{ errors[], warnings[],
37
+ * payloadSchema, … }`, naming every field the payload got wrong.
38
+ */
39
+ details;
40
+ /** The parsed response body exactly as received (`undefined` if not JSON). */
41
+ body;
34
42
  constructor(input) {
35
43
  super(input.message);
36
44
  this.status = input.status;
@@ -40,8 +48,38 @@ var CliApiError = class extends Error {
40
48
  this.suggestion = input.suggestion;
41
49
  this.docs = input.docs;
42
50
  this.requestId = input.requestId;
51
+ this.details = input.details;
52
+ this.body = input.body;
43
53
  }
44
54
  };
55
+ function errorTypeForStatus(status) {
56
+ switch (status) {
57
+ case 401:
58
+ return "authentication_error";
59
+ case 402:
60
+ return "payment_required";
61
+ case 403:
62
+ return "authorization_error";
63
+ case 404:
64
+ return "not_found";
65
+ case 409:
66
+ return "conflict";
67
+ case 429:
68
+ return "rate_limit";
69
+ case 501:
70
+ return "not_implemented";
71
+ case 503:
72
+ return "service_unavailable";
73
+ default:
74
+ return status >= 400 && status < 500 ? "invalid_request" : "internal_error";
75
+ }
76
+ }
77
+ function suggestionForStatus(status) {
78
+ if (status === 408 || status === 429 || status >= 500) {
79
+ return "Retry the request. If it keeps failing, contact support.";
80
+ }
81
+ return "Fix the request before sending it again \u2014 the same request fails the same way. See `details` for the specifics when present.";
82
+ }
45
83
  var ConfirmationRequiredError = class extends Error {
46
84
  envelope;
47
85
  constructor(envelope) {
@@ -67,6 +105,7 @@ function toExitCode(error) {
67
105
  }
68
106
  function toErrorEnvelope(error) {
69
107
  if (error instanceof BrewApiError || error instanceof CliApiError) {
108
+ const details = readErrorDetails(error);
70
109
  return {
71
110
  code: error.code,
72
111
  type: error.type,
@@ -75,6 +114,7 @@ function toErrorEnvelope(error) {
75
114
  ...error.suggestion ? { suggestion: error.suggestion } : {},
76
115
  ...error.docs ? { docs: error.docs } : {},
77
116
  ...error.requestId ? { requestId: error.requestId } : {},
117
+ ...details === void 0 ? {} : { details },
78
118
  status: error.status
79
119
  };
80
120
  }
@@ -134,7 +174,10 @@ function printError(ctx, error) {
134
174
  `);
135
175
  return;
136
176
  }
137
- const lines = [`brew-cli: ${envelope.message}`];
177
+ const lines = [
178
+ `brew-cli: ${envelope.message}`,
179
+ ...formatDetailLines(envelope.details)
180
+ ];
138
181
  if (envelope.suggestion) {
139
182
  lines.push(envelope.suggestion);
140
183
  }
@@ -147,6 +190,29 @@ function printError(ctx, error) {
147
190
  ctx.io.stderr.write(`${lines.join("\n")}
148
191
  `);
149
192
  }
193
+ function readErrorDetails(error) {
194
+ const details = error.details;
195
+ return isRecord(details) ? details : void 0;
196
+ }
197
+ function formatDetailLines(details) {
198
+ if (details === void 0) {
199
+ return [];
200
+ }
201
+ const issues = details.errors;
202
+ if (Array.isArray(issues) && issues.length > 0 && issues.every(isIssue)) {
203
+ return issues.map((issue) => {
204
+ const types = typeof issue.expectedType === "string" ? typeof issue.actualType === "string" ? ` (expected ${issue.expectedType}, got ${issue.actualType})` : ` (expected ${issue.expectedType})` : "";
205
+ return ` - ${issue.field}: ${issue.message}${types}`;
206
+ });
207
+ }
208
+ return [`Details: ${JSON.stringify(details)}`];
209
+ }
210
+ function isIssue(value) {
211
+ return isRecord(value) && typeof value.field === "string" && typeof value.message === "string";
212
+ }
213
+ function isRecord(value) {
214
+ return typeof value === "object" && value !== null && !Array.isArray(value);
215
+ }
150
216
  function apiErrorStatus(error) {
151
217
  if (error instanceof BrewApiError || error instanceof CliApiError) {
152
218
  return error.status;
@@ -215,7 +281,7 @@ function shellQuote(token) {
215
281
 
216
282
  // src/version.ts
217
283
  var CLI_NAME = "brew-cli";
218
- var CLI_VERSION = "0.5.0" ;
284
+ var CLI_VERSION = "0.8.0" ;
219
285
  var CONFIG_KEYS = ["apiKey", "brandId", "apiUrl"];
220
286
  function isConfigKey(value) {
221
287
  return CONFIG_KEYS.includes(value);
@@ -286,6 +352,7 @@ var ORG_LEVEL_PATH_PREFIXES = [
286
352
  "/v1/brands",
287
353
  "/v1/usage",
288
354
  "/v1/templates",
355
+ "/v1/flows",
289
356
  "/v1/health",
290
357
  "/v1/help",
291
358
  "/v1/llms.txt",
@@ -668,58 +735,128 @@ function renderAutomationRows(rows) {
668
735
  ]);
669
736
  }
670
737
 
671
- // src/commands/analytics/campaigns.ts
672
- var analyticsCampaignsCommand = defineCommand({
673
- path: ["analytics", "campaigns"],
674
- summary: "Lifetime per-campaign KPIs (sent, opened, clicked, bounced)",
675
- sdkMethod: "analytics.campaigns",
676
- route: { method: "GET", path: "/v1/analytics/campaigns" },
738
+ // src/commands/sends/list.ts
739
+ var SEND_STATUS_SUMMARY = "scheduled | queued | running | paused | completed | partially_completed | failed | canceled";
740
+ var sendsListCommand = defineCommand({
741
+ path: ["sends", "list"],
742
+ summary: "List sends (the unit of delivery and analytics) with lifetime stats",
743
+ sdkMethod: "sends.list",
744
+ route: { method: "GET", path: "/v1/sends" },
677
745
  commandClass: "read",
678
- flags: [LIMIT_FLAG, CURSOR_FLAG, ALL_FLAG, INPUT_FLAG],
746
+ flags: [
747
+ { flag: "--email <emailId>", summary: "Only sends of this design" },
748
+ { flag: "--kind <kind>", summary: "campaign | automation" },
749
+ { flag: "--automation <automationId>", summary: "Filter by automation" },
750
+ {
751
+ flag: "--automation-run <automationRunId>",
752
+ summary: "Deliveries of one automation run"
753
+ },
754
+ {
755
+ flag: "--audience-run <audienceRunId>",
756
+ summary: "Deliveries of one manual-audience run"
757
+ },
758
+ {
759
+ flag: "--trigger-instance <triggerInstanceId>",
760
+ summary: "Deliveries started by one fired trigger instance"
761
+ },
762
+ { flag: "--status <status>", summary: SEND_STATUS_SUMMARY },
763
+ {
764
+ flag: "--message-class <class>",
765
+ summary: "marketing | transactional"
766
+ },
767
+ {
768
+ flag: "--since <datetime>",
769
+ summary: "Inclusive lower bound on updatedAt (ISO-8601)"
770
+ },
771
+ {
772
+ flag: "--until <datetime>",
773
+ summary: "Inclusive upper bound on updatedAt (ISO-8601)"
774
+ },
775
+ LIMIT_FLAG,
776
+ CURSOR_FLAG,
777
+ ALL_FLAG,
778
+ INPUT_FLAG
779
+ ],
679
780
  examples: [
680
- "brew-cli analytics campaigns",
681
- "brew-cli analytics campaigns --all --json"
781
+ "brew-cli sends list --status completed",
782
+ "brew-cli sends list --email eml_1 --all --json",
783
+ "brew-cli sends list --automation-run arun_9f2kX"
682
784
  ],
683
785
  run: async ({ ctx, flags }) => {
684
786
  const base = await readJsonFlag(ctx, flags.input, "--input");
685
787
  const input = mergeInput(base, {
788
+ emailId: flagString(flags.email),
789
+ kind: flagString(flags.kind),
790
+ automationId: flagString(flags.automation),
791
+ automationRunId: flagString(flags.automationRun),
792
+ audienceRunId: flagString(flags.audienceRun),
793
+ triggerInstanceId: flagString(flags.triggerInstance),
794
+ status: flagString(flags.status),
795
+ messageClass: flagString(flags.messageClass),
796
+ from: flagString(flags.since),
797
+ to: flagString(flags.until),
686
798
  limit: flagInt(flags.limit, "--limit"),
687
799
  cursor: flagString(flags.cursor)
688
800
  });
689
- const analytics = ctx.client().analytics;
690
- if (flags.all === true) {
691
- const rows = await collectAll(
692
- ctx,
693
- (cursor) => analytics.campaigns(
694
- asSdkInput({
695
- ...input,
696
- ...cursor === void 0 ? {} : { cursor }
697
- })
698
- )
699
- );
700
- return {
701
- data: { data: rows, pagination: { cursor: null, hasMore: false } },
702
- human: renderCampaigns(rows)
703
- };
704
- }
705
- const result = await analytics.campaigns(
706
- asSdkInput(input)
707
- );
708
- return { data: result, human: renderCampaigns(result.data) };
801
+ return await listSends(ctx, input, flags.all === true);
709
802
  }
710
803
  });
711
- function renderCampaigns(rows) {
804
+ async function listSends(ctx, input, followCursor) {
805
+ const sends = ctx.client().sends;
806
+ if (followCursor) {
807
+ const rows = await collectAll(
808
+ ctx,
809
+ (cursor) => sends.list(
810
+ asSdkInput({
811
+ ...input,
812
+ ...cursor === void 0 ? {} : { cursor }
813
+ })
814
+ )
815
+ );
816
+ return {
817
+ data: { data: rows, pagination: { cursor: null, hasMore: false } },
818
+ human: renderSends(rows)
819
+ };
820
+ }
821
+ const result = await sends.list(asSdkInput(input));
822
+ return { data: result, human: renderSends(result.data) };
823
+ }
824
+ function renderSends(rows) {
712
825
  if (rows.length === 0) {
713
- return "No campaign analytics rows.";
826
+ return "No sends found.";
714
827
  }
715
828
  return renderTable(rows, [
716
829
  { key: "sendId", header: "SEND" },
717
- { key: "title", header: "TITLE" },
830
+ { key: "kind", header: "KIND" },
718
831
  { key: "status", header: "STATUS" },
719
- { key: "sentAt", header: "SENT AT" }
832
+ { key: "subject", header: "SUBJECT" }
720
833
  ]);
721
834
  }
722
835
 
836
+ // src/commands/analytics/campaigns.ts
837
+ var analyticsCampaignsCommand = defineCommand({
838
+ path: ["analytics", "campaigns"],
839
+ summary: "Lifetime per-campaign KPIs (`sends list --kind campaign`; stats ride each row)",
840
+ sdkMethod: null,
841
+ derivedFrom: "sends.list",
842
+ route: { method: "GET", path: "/v1/sends" },
843
+ commandClass: "read",
844
+ flags: [LIMIT_FLAG, CURSOR_FLAG, ALL_FLAG, INPUT_FLAG],
845
+ examples: [
846
+ "brew-cli analytics campaigns",
847
+ "brew-cli analytics campaigns --all --json"
848
+ ],
849
+ run: async ({ ctx, flags }) => {
850
+ const base = await readJsonFlag(ctx, flags.input, "--input");
851
+ const input = mergeInput(base, {
852
+ kind: "campaign",
853
+ limit: flagInt(flags.limit, "--limit"),
854
+ cursor: flagString(flags.cursor)
855
+ });
856
+ return await listSends(ctx, input, flags.all === true);
857
+ }
858
+ });
859
+
723
860
  // src/commands/analytics/events.ts
724
861
  var analyticsEventsCommand = defineCommand({
725
862
  path: ["analytics", "events"],
@@ -730,7 +867,10 @@ var analyticsEventsCommand = defineCommand({
730
867
  flags: [
731
868
  { flag: "--since <datetime>", summary: "Window start (ISO-8601)" },
732
869
  { flag: "--until <datetime>", summary: "Window end (ISO-8601)" },
733
- { flag: "--recipient <email>", summary: "Filter by recipient email" },
870
+ {
871
+ flag: "--recipient <rules>",
872
+ summary: "CSV of recipient rules (max 10): an address, @domain, or substring; prefix ! to exclude"
873
+ },
734
874
  {
735
875
  flag: "--event-type <type>",
736
876
  summary: "Filter by event type (e.g. opened, clicked)"
@@ -751,7 +891,7 @@ var analyticsEventsCommand = defineCommand({
751
891
  const input = mergeInput(base, {
752
892
  from: flagString(flags.since),
753
893
  to: flagString(flags.until),
754
- recipientEmail: flagString(flags.recipient),
894
+ recipient: flagString(flags.recipient),
755
895
  eventType: flagString(flags.eventType),
756
896
  automationId: flagString(flags.automation),
757
897
  sendId: flagString(flags.send),
@@ -852,10 +992,10 @@ var analyticsOverviewCommand = defineCommand({
852
992
  // src/commands/analytics/sends/get.ts
853
993
  var analyticsSendsGetCommand = defineCommand({
854
994
  path: ["analytics", "sends", "get"],
855
- summary: "Fetch one send by id",
995
+ summary: "Fetch one send by id \u2014 the bare row (`sends get`)",
856
996
  sdkMethod: null,
857
- derivedFrom: "analytics.sends.list",
858
- route: { method: "GET", path: "/v1/analytics/sends" },
997
+ derivedFrom: "sends.get",
998
+ route: { method: "GET", path: "/v1/sends/{sendId}" },
859
999
  commandClass: "read",
860
1000
  args: [
861
1001
  {
@@ -875,46 +1015,54 @@ var analyticsSendsGetCommand = defineCommand({
875
1015
  "brew-cli analytics sends get snd_123 --include events"
876
1016
  ],
877
1017
  run: async ({ ctx, args, flags }) => {
878
- const sendId = args.sendId ?? "";
879
1018
  const include = flagString(flags.include);
880
- const result = await ctx.client().analytics.sends.list(
881
- asSdkInput({
882
- sendId,
883
- ...include === void 0 ? {} : { include }
884
- })
885
- );
886
- const send = result.data[0];
887
- if (send === void 0) {
888
- throw new CliApiError({
889
- status: 404,
890
- code: "SEND_NOT_FOUND",
891
- type: "not_found",
892
- message: `No send found for ${sendId}`,
893
- suggestion: "List sends with `brew-cli analytics sends list`."
894
- });
895
- }
896
- return { data: send };
1019
+ return {
1020
+ data: await ctx.client().sends.get(
1021
+ args.sendId ?? "",
1022
+ include === void 0 ? void 0 : { include }
1023
+ )
1024
+ };
897
1025
  }
898
1026
  });
899
1027
 
1028
+ // src/lib/compat.ts
1029
+ function singleRowPage(row) {
1030
+ return { data: [row], pagination: { cursor: null, hasMore: false } };
1031
+ }
1032
+ function inputField(base, key) {
1033
+ if (base === null || typeof base !== "object") {
1034
+ return void 0;
1035
+ }
1036
+ const value = base[key];
1037
+ return typeof value === "string" && value !== "" ? value : void 0;
1038
+ }
1039
+ function includeRidesDetailRead(getCommand, idFlag) {
1040
+ const pairing = idFlag === void 0 ? "" : `, or pair it with ${idFlag}`;
1041
+ return new CliUsageError(
1042
+ `--include rides the detail read: use \`brew-cli ${getCommand} <id> --include \u2026\`${pairing}.`
1043
+ );
1044
+ }
1045
+
900
1046
  // src/commands/analytics/sends/list.ts
901
1047
  var analyticsSendsListCommand = defineCommand({
902
1048
  path: ["analytics", "sends", "list"],
903
- summary: "List campaign/automation sends with delivery stats",
904
- sdkMethod: "analytics.sends.list",
905
- route: { method: "GET", path: "/v1/analytics/sends" },
1049
+ summary: "List campaign/automation sends with delivery stats (`sends list`)",
1050
+ sdkMethod: null,
1051
+ derivedFrom: "sends.list",
1052
+ route: { method: "GET", path: "/v1/sends" },
906
1053
  commandClass: "read",
907
1054
  flags: [
908
- { flag: "--send <sendId>", summary: "Fetch one send (single-row page)" },
909
- { flag: "--email <emailId>", summary: "Filter by email design" },
910
1055
  {
911
- flag: "--include <tokens>",
912
- summary: "Comma-separated expansions: events"
1056
+ flag: "--send <sendId>",
1057
+ summary: "0.6 shim: read ONE send as a single-row page (`sends get` is the real read)"
913
1058
  },
914
1059
  {
915
- flag: "--status <status>",
916
- summary: "scheduled | queued | sending | sent | failed | canceled"
1060
+ flag: "--include <tokens>",
1061
+ summary: "With --send only: detail includes (`events`)"
917
1062
  },
1063
+ { flag: "--email <emailId>", summary: "Filter by email design" },
1064
+ { flag: "--kind <kind>", summary: "campaign | automation" },
1065
+ { flag: "--status <status>", summary: SEND_STATUS_SUMMARY },
918
1066
  { flag: "--since <datetime>", summary: "Window start (ISO-8601)" },
919
1067
  { flag: "--until <datetime>", summary: "Window end (ISO-8601)" },
920
1068
  LIMIT_FLAG,
@@ -923,59 +1071,105 @@ var analyticsSendsListCommand = defineCommand({
923
1071
  INPUT_FLAG
924
1072
  ],
925
1073
  examples: [
926
- "brew-cli analytics sends list --status sent",
927
- "brew-cli analytics sends list --email em_123 --all --json"
1074
+ "brew-cli analytics sends list --status completed",
1075
+ "brew-cli analytics sends list --email eml_1 --all --json"
928
1076
  ],
929
1077
  run: async ({ ctx, flags }) => {
930
1078
  const base = await readJsonFlag(ctx, flags.input, "--input");
1079
+ const sendId = flagString(flags.send) ?? inputField(base, "sendId");
1080
+ const include = flagString(flags.include) ?? inputField(base, "include");
1081
+ if (sendId !== void 0) {
1082
+ const row = await ctx.client().sends.get(sendId, include === void 0 ? void 0 : { include });
1083
+ return { data: singleRowPage(row), human: renderSends([row]) };
1084
+ }
1085
+ if (include !== void 0) {
1086
+ throw includeRidesDetailRead("sends get", "--send");
1087
+ }
931
1088
  const input = mergeInput(base, {
932
- sendId: flagString(flags.send),
933
1089
  emailId: flagString(flags.email),
934
- include: flagString(flags.include),
1090
+ kind: flagString(flags.kind),
935
1091
  status: flagString(flags.status),
936
1092
  from: flagString(flags.since),
937
1093
  to: flagString(flags.until),
938
1094
  limit: flagInt(flags.limit, "--limit"),
939
1095
  cursor: flagString(flags.cursor)
940
1096
  });
941
- const sends = ctx.client().analytics.sends;
942
- if (flags.all === true) {
943
- const rows = await collectAll(
944
- ctx,
945
- (cursor) => sends.list(
946
- asSdkInput({
947
- ...input,
948
- ...cursor === void 0 ? {} : { cursor }
949
- })
950
- )
951
- );
952
- return {
953
- data: { data: rows, pagination: { cursor: null, hasMore: false } },
954
- human: renderSends(rows)
955
- };
956
- }
957
- const result = await sends.list(asSdkInput(input));
958
- return { data: result, human: renderSends(result.data) };
1097
+ return await listSends(ctx, input, flags.all === true);
959
1098
  }
960
1099
  });
961
- function renderSends(rows) {
1100
+
1101
+ // src/commands/automations/trigger-instances/list.ts
1102
+ var automationsTriggerInstancesListCommand = defineCommand({
1103
+ path: ["automations", "trigger-instances", "list"],
1104
+ summary: "List fired-trigger instances (the inbound-fire audit log); each row carries a lifecycle `state`",
1105
+ sdkMethod: "automations.triggerInstances.list",
1106
+ route: { method: "GET", path: "/v1/automations/trigger-instances" },
1107
+ commandClass: "read",
1108
+ flags: [
1109
+ {
1110
+ flag: "--trigger <triggerEventId>",
1111
+ summary: "Filter by trigger event"
1112
+ },
1113
+ LIMIT_FLAG,
1114
+ CURSOR_FLAG,
1115
+ ALL_FLAG,
1116
+ INPUT_FLAG
1117
+ ],
1118
+ examples: [
1119
+ "brew-cli automations trigger-instances list --trigger tri_signup",
1120
+ "brew-cli automations trigger-instances list --all --json"
1121
+ ],
1122
+ run: async ({ ctx, flags }) => {
1123
+ const base = await readJsonFlag(ctx, flags.input, "--input");
1124
+ const input = mergeInput(base, {
1125
+ triggerEventId: flagString(flags.trigger),
1126
+ limit: flagInt(flags.limit, "--limit"),
1127
+ cursor: flagString(flags.cursor)
1128
+ });
1129
+ return await listTriggerInstances(ctx, input, flags.all === true);
1130
+ }
1131
+ });
1132
+ async function listTriggerInstances(ctx, input, followCursor) {
1133
+ const triggerInstances = ctx.client().automations.triggerInstances;
1134
+ if (followCursor) {
1135
+ const rows = await collectAll(
1136
+ ctx,
1137
+ (cursor) => triggerInstances.list(
1138
+ asSdkInput({
1139
+ ...input,
1140
+ ...cursor === void 0 ? {} : { cursor }
1141
+ })
1142
+ )
1143
+ );
1144
+ return {
1145
+ data: { data: rows, pagination: { cursor: null, hasMore: false } },
1146
+ human: renderInstances(rows)
1147
+ };
1148
+ }
1149
+ const result = await triggerInstances.list(
1150
+ asSdkInput(input)
1151
+ );
1152
+ return { data: result, human: renderInstances(result.data) };
1153
+ }
1154
+ function renderInstances(rows) {
962
1155
  if (rows.length === 0) {
963
- return "No sends found.";
1156
+ return "No trigger instances found.";
964
1157
  }
965
1158
  return renderTable(rows, [
966
- { key: "sendId", header: "SEND" },
967
- { key: "kind", header: "KIND" },
968
- { key: "status", header: "STATUS" },
969
- { key: "subject", header: "SUBJECT" }
1159
+ { key: "triggerInstanceId", header: "INSTANCE" },
1160
+ { key: "source", header: "SOURCE" },
1161
+ { key: "state", header: "STATE" },
1162
+ { key: "receivedAt", header: "RECEIVED" }
970
1163
  ]);
971
1164
  }
972
1165
 
973
1166
  // src/commands/analytics/trigger-instances/list.ts
974
1167
  var analyticsTriggerInstancesListCommand = defineCommand({
975
1168
  path: ["analytics", "trigger-instances", "list"],
976
- summary: "List fired-trigger instances (ingest + match history)",
977
- sdkMethod: "analytics.triggerInstances.list",
978
- route: { method: "GET", path: "/v1/analytics/trigger-instances" },
1169
+ summary: "List fired-trigger instances with their lifecycle `state` (`automations trigger-instances list`)",
1170
+ sdkMethod: null,
1171
+ derivedFrom: "automations.triggerInstances.list",
1172
+ route: { method: "GET", path: "/v1/automations/trigger-instances" },
979
1173
  commandClass: "read",
980
1174
  flags: [
981
1175
  {
@@ -984,7 +1178,7 @@ var analyticsTriggerInstancesListCommand = defineCommand({
984
1178
  },
985
1179
  {
986
1180
  flag: "--trigger-instance <triggerInstanceId>",
987
- summary: "Fetch one instance (single-row page)"
1181
+ summary: "0.6 shim: read ONE instance as a single-row page (`automations trigger-instances get` is the real read)"
988
1182
  },
989
1183
  LIMIT_FLAG,
990
1184
  CURSOR_FLAG,
@@ -992,50 +1186,24 @@ var analyticsTriggerInstancesListCommand = defineCommand({
992
1186
  INPUT_FLAG
993
1187
  ],
994
1188
  examples: [
995
- "brew-cli analytics trigger-instances list --trigger tev_123",
1189
+ "brew-cli analytics trigger-instances list --trigger tri_signup",
996
1190
  "brew-cli analytics trigger-instances list --all --json"
997
1191
  ],
998
1192
  run: async ({ ctx, flags }) => {
999
1193
  const base = await readJsonFlag(ctx, flags.input, "--input");
1194
+ const triggerInstanceId = flagString(flags.triggerInstance) ?? inputField(base, "triggerInstanceId");
1195
+ if (triggerInstanceId !== void 0) {
1196
+ const row = await ctx.client().automations.triggerInstances.get(triggerInstanceId);
1197
+ return { data: singleRowPage(row), human: renderInstances([row]) };
1198
+ }
1000
1199
  const input = mergeInput(base, {
1001
1200
  triggerEventId: flagString(flags.trigger),
1002
- triggerInstanceId: flagString(flags.triggerInstance),
1003
1201
  limit: flagInt(flags.limit, "--limit"),
1004
1202
  cursor: flagString(flags.cursor)
1005
1203
  });
1006
- const triggerInstances = ctx.client().analytics.triggerInstances;
1007
- if (flags.all === true) {
1008
- const rows = await collectAll(
1009
- ctx,
1010
- (cursor) => triggerInstances.list(
1011
- asSdkInput({
1012
- ...input,
1013
- ...cursor === void 0 ? {} : { cursor }
1014
- })
1015
- )
1016
- );
1017
- return {
1018
- data: { data: rows, pagination: { cursor: null, hasMore: false } },
1019
- human: renderInstances(rows)
1020
- };
1021
- }
1022
- const result = await triggerInstances.list(
1023
- asSdkInput(input)
1024
- );
1025
- return { data: result, human: renderInstances(result.data) };
1204
+ return await listTriggerInstances(ctx, input, flags.all === true);
1026
1205
  }
1027
1206
  });
1028
- function renderInstances(rows) {
1029
- if (rows.length === 0) {
1030
- return "No trigger instances found.";
1031
- }
1032
- return renderTable(rows, [
1033
- { key: "triggerInstanceId", header: "INSTANCE" },
1034
- { key: "source", header: "SOURCE" },
1035
- { key: "state", header: "STATE" },
1036
- { key: "receivedAt", header: "RECEIVED" }
1037
- ]);
1038
- }
1039
1207
 
1040
1208
  // src/lib/raw-request.ts
1041
1209
  async function rawRequest(ctx, request) {
@@ -1107,26 +1275,33 @@ function buildRawHeaders(input) {
1107
1275
  }
1108
1276
  function responseToApiError(response, parsed) {
1109
1277
  const requestId = response.headers.get("x-request-id") ?? void 0;
1110
- const record = parsed !== null && typeof parsed === "object" ? parsed : void 0;
1111
- const envelope = record !== void 0 && record.error !== null && typeof record.error === "object" ? record.error : record;
1278
+ const record = isRecord2(parsed) ? parsed : void 0;
1279
+ const standard = record !== void 0 && isRecord2(record.error) ? record.error : void 0;
1280
+ const envelope = standard ?? record;
1112
1281
  const readField = (key) => {
1113
1282
  const value = envelope?.[key];
1114
1283
  return typeof value === "string" ? value : void 0;
1115
1284
  };
1116
1285
  const param = readField("param");
1117
- const suggestion = readField("suggestion");
1286
+ const suggestion = readField("suggestion") ?? (envelope === void 0 ? void 0 : suggestionForStatus(response.status));
1118
1287
  const docs = readField("docs");
1288
+ const details = isRecord2(envelope?.details) ? envelope.details : void 0;
1119
1289
  return new CliApiError({
1120
1290
  status: response.status,
1121
1291
  code: readField("code") ?? "HTTP_ERROR",
1122
- type: readField("type") ?? "internal_error",
1292
+ type: readField("type") ?? errorTypeForStatus(response.status),
1123
1293
  message: readField("message") ?? `Request failed with status ${response.status}`,
1124
1294
  ...param === void 0 ? {} : { param },
1125
1295
  ...suggestion === void 0 ? {} : { suggestion },
1126
1296
  ...docs === void 0 ? {} : { docs },
1127
- ...requestId === void 0 ? {} : { requestId }
1297
+ ...requestId === void 0 ? {} : { requestId },
1298
+ ...details === void 0 ? {} : { details },
1299
+ ...parsed === void 0 ? {} : { body: parsed }
1128
1300
  });
1129
1301
  }
1302
+ function isRecord2(value) {
1303
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1304
+ }
1130
1305
  function tryParseJson(text) {
1131
1306
  try {
1132
1307
  return JSON.parse(text);
@@ -1479,10 +1654,9 @@ var audiencesFromEventsCommand = defineCommand({
1479
1654
  // src/commands/audiences/get.ts
1480
1655
  var audiencesGetCommand = defineCommand({
1481
1656
  path: ["audiences", "get"],
1482
- summary: "Fetch one audience segment by id",
1483
- sdkMethod: null,
1484
- derivedFrom: "audiences.list",
1485
- route: { method: "GET", path: "/v1/audiences" },
1657
+ summary: "Fetch one audience segment by id \u2014 the bare row",
1658
+ sdkMethod: "audiences.get",
1659
+ route: { method: "GET", path: "/v1/audiences/{audienceId}" },
1486
1660
  commandClass: "read",
1487
1661
  args: [
1488
1662
  { name: "audienceId", summary: "Audience id to fetch", isRequired: true }
@@ -1490,42 +1664,35 @@ var audiencesGetCommand = defineCommand({
1490
1664
  flags: [
1491
1665
  {
1492
1666
  flag: "--include <tokens>",
1493
- summary: "Comma-separated expansions: count"
1667
+ summary: "Comma-separated expansions: count, build"
1494
1668
  }
1495
1669
  ],
1496
- examples: ["brew-cli audiences get aud_3k9sQ"],
1670
+ examples: [
1671
+ "brew-cli audiences get aud_3k9sQ",
1672
+ "brew-cli audiences get aud_3k9sQ --include count,build"
1673
+ ],
1497
1674
  run: async ({ ctx, args, flags }) => {
1498
- const audienceId = args.audienceId ?? "";
1499
1675
  const include = flagString(flags.include);
1500
- const result = await ctx.client().audiences.list({
1501
- audienceId,
1502
- ...include === void 0 ? {} : { include }
1503
- });
1504
- const audience = result.data[0];
1505
- if (audience === void 0) {
1506
- throw new CliApiError({
1507
- status: 404,
1508
- code: "AUDIENCE_NOT_FOUND",
1509
- type: "not_found",
1510
- message: `No audience found for ${audienceId}`,
1511
- suggestion: "List audiences with `brew-cli audiences list`."
1512
- });
1513
- }
1514
- return { data: audience };
1676
+ return {
1677
+ data: await ctx.client().audiences.get(
1678
+ args.audienceId ?? "",
1679
+ include === void 0 ? void 0 : { include }
1680
+ )
1681
+ };
1515
1682
  }
1516
1683
  });
1517
1684
 
1518
1685
  // src/commands/audiences/list.ts
1519
1686
  var audiencesListCommand = defineCommand({
1520
1687
  path: ["audiences", "list"],
1521
- summary: "List audience segments",
1688
+ summary: "List audience segments; one segment is `audiences get`",
1522
1689
  sdkMethod: "audiences.list",
1523
1690
  route: { method: "GET", path: "/v1/audiences" },
1524
1691
  commandClass: "read",
1525
1692
  flags: [
1526
1693
  {
1527
1694
  flag: "--include <tokens>",
1528
- summary: "Comma-separated expansions: count"
1695
+ summary: "0.6 flag: includes ride the detail read now (`audiences get --include count,build`)"
1529
1696
  },
1530
1697
  LIMIT_FLAG,
1531
1698
  CURSOR_FLAG,
@@ -1534,13 +1701,15 @@ var audiencesListCommand = defineCommand({
1534
1701
  ],
1535
1702
  examples: [
1536
1703
  "brew-cli audiences list",
1537
- "brew-cli audiences list --include count --limit 10",
1704
+ "brew-cli audiences list --limit 10",
1538
1705
  "brew-cli audiences list --all --json"
1539
1706
  ],
1540
1707
  run: async ({ ctx, flags }) => {
1541
1708
  const base = await readJsonFlag(ctx, flags.input, "--input");
1709
+ if ((flagString(flags.include) ?? inputField(base, "include")) !== void 0) {
1710
+ throw includeRidesDetailRead("audiences get");
1711
+ }
1542
1712
  const input = mergeInput(base, {
1543
- include: flagString(flags.include),
1544
1713
  limit: flagInt(flags.limit, "--limit"),
1545
1714
  cursor: flagString(flags.cursor)
1546
1715
  });
@@ -1607,16 +1776,45 @@ var audiencesUpdateCommand = defineCommand({
1607
1776
  }
1608
1777
  });
1609
1778
 
1610
- // src/commands/automations/audience-runs/control.ts
1611
- var automationsAudienceRunsControlCommand = defineCommand({
1612
- path: ["automations", "audience-runs", "control"],
1613
- summary: "Pause, resume, or cancel an in-flight manual-audience run",
1614
- sdkMethod: "automations.audienceRuns.control",
1779
+ // src/commands/automations/audience-runs/cancel.ts
1780
+ var automationsAudienceRunsCancelCommand = defineCommand({
1781
+ path: ["automations", "audience-runs", "cancel"],
1782
+ summary: "Cancel a manual-audience run for good \u2014 it can never be resumed",
1783
+ sdkMethod: "automations.audienceRuns.cancel",
1615
1784
  route: {
1616
1785
  method: "POST",
1617
- path: "/v1/automations/audience-runs/{audienceRunId}/control"
1786
+ path: "/v1/automations/audience-runs/{audienceRunId}/cancel"
1618
1787
  },
1619
1788
  commandClass: "destructive",
1789
+ args: [
1790
+ {
1791
+ name: "audienceRunId",
1792
+ summary: "Audience run id to cancel",
1793
+ isRequired: true
1794
+ }
1795
+ ],
1796
+ flags: [IDEMPOTENCY_FLAG],
1797
+ examples: ["brew-cli automations audience-runs cancel arun_01HZ --yes"],
1798
+ confirmSummary: ({ args }) => `Cancel audience run ${args.audienceRunId ?? ""} for good. Emails already sent are not recalled, and a canceled run cannot be resumed.`,
1799
+ run: async ({ ctx, args, flags }) => ({
1800
+ data: await ctx.client().automations.audienceRuns.cancel(
1801
+ args.audienceRunId ?? "",
1802
+ requestOptions(flags)
1803
+ )
1804
+ })
1805
+ });
1806
+
1807
+ // src/commands/automations/audience-runs/control.ts
1808
+ var automationsAudienceRunsControlCommand = defineCommand({
1809
+ path: ["automations", "audience-runs", "control"],
1810
+ summary: "Pause, resume, or cancel an in-flight manual-audience run (0.6 form of `audience-runs pause|resume|cancel`)",
1811
+ sdkMethod: null,
1812
+ derivedFrom: [
1813
+ "automations.audienceRuns.pause",
1814
+ "automations.audienceRuns.resume",
1815
+ "automations.audienceRuns.cancel"
1816
+ ],
1817
+ commandClass: "destructive",
1620
1818
  args: [
1621
1819
  {
1622
1820
  name: "audienceRunId",
@@ -1628,7 +1826,8 @@ var automationsAudienceRunsControlCommand = defineCommand({
1628
1826
  {
1629
1827
  flag: "--action <action>",
1630
1828
  summary: "pause (resumable) | resume | cancel (final)"
1631
- }
1829
+ },
1830
+ IDEMPOTENCY_FLAG
1632
1831
  ],
1633
1832
  examples: [
1634
1833
  "brew-cli automations audience-runs control arun_01HZ --action pause",
@@ -1637,57 +1836,181 @@ var automationsAudienceRunsControlCommand = defineCommand({
1637
1836
  // Only cancel is irreversible; pause and resume proceed ungated.
1638
1837
  confirmSummary: ({ args, flags }) => flagString(flags.action) === "cancel" ? `Cancel audience run ${args.audienceRunId ?? ""} for good. Emails already sent are not recalled, and a canceled run cannot be resumed.` : void 0,
1639
1838
  run: async ({ ctx, args, flags }) => {
1640
- const action = flagString(flags.action);
1641
- if (action === void 0) {
1642
- throw new CliUsageError("--action is required: pause, resume, or cancel.");
1839
+ const audienceRuns = ctx.client().automations.audienceRuns;
1840
+ const audienceRunId = args.audienceRunId ?? "";
1841
+ const options = requestOptions(flags);
1842
+ switch (flagString(flags.action)) {
1843
+ case "pause":
1844
+ return { data: await audienceRuns.pause(audienceRunId, options) };
1845
+ case "resume":
1846
+ return { data: await audienceRuns.resume(audienceRunId, options) };
1847
+ case "cancel":
1848
+ return { data: await audienceRuns.cancel(audienceRunId, options) };
1849
+ default:
1850
+ throw new CliUsageError(
1851
+ "--action is required: pause, resume, or cancel."
1852
+ );
1643
1853
  }
1644
- return {
1645
- data: await ctx.client().automations.audienceRuns.control(
1646
- asSdkInput({
1647
- audienceRunId: args.audienceRunId ?? "",
1648
- action
1649
- })
1650
- )
1651
- };
1652
1854
  }
1653
1855
  });
1654
1856
 
1857
+ // src/commands/automations/audience-runs/get.ts
1858
+ var automationsAudienceRunsGetCommand = defineCommand({
1859
+ path: ["automations", "audience-runs", "get"],
1860
+ summary: "Fetch one manual-audience run by id \u2014 the bare row",
1861
+ sdkMethod: "automations.audienceRuns.get",
1862
+ route: {
1863
+ method: "GET",
1864
+ path: "/v1/automations/audience-runs/{audienceRunId}"
1865
+ },
1866
+ commandClass: "read",
1867
+ args: [
1868
+ {
1869
+ name: "audienceRunId",
1870
+ summary: "Audience run id to fetch",
1871
+ isRequired: true
1872
+ }
1873
+ ],
1874
+ examples: ["brew-cli automations audience-runs get arun_01HZ"],
1875
+ run: async ({ ctx, args }) => ({
1876
+ data: await ctx.client().automations.audienceRuns.get(args.audienceRunId ?? "")
1877
+ })
1878
+ });
1879
+
1655
1880
  // src/commands/automations/audience-runs/list.ts
1656
1881
  var automationsAudienceRunsListCommand = defineCommand({
1657
1882
  path: ["automations", "audience-runs", "list"],
1658
- summary: "List manual-audience runs (newest first)",
1883
+ summary: "List manual-audience runs, newest first; one run is `automations audience-runs get`",
1659
1884
  sdkMethod: "automations.audienceRuns.list",
1660
1885
  route: { method: "GET", path: "/v1/automations/audience-runs" },
1661
1886
  commandClass: "read",
1662
- // The spec paginates by --limit only: no cursor, and the response carries
1663
- // no pagination envelope, so there is no --all here.
1664
1887
  flags: [
1665
1888
  {
1666
- flag: "--audience-run-id <id>",
1667
- summary: "Fetch a single audience run by id"
1889
+ flag: "--automation <automationId>",
1890
+ summary: "Only runs of this automation"
1891
+ },
1892
+ {
1893
+ flag: "--automation-id <automationId>",
1894
+ summary: "0.6 alias of --automation"
1895
+ },
1896
+ {
1897
+ flag: "--audience-run-id <audienceRunId>",
1898
+ summary: "0.6 shim: read ONE run as a single-row page (`automations audience-runs get` is the real read)"
1668
1899
  },
1669
1900
  {
1670
- flag: "--automation-id <id>",
1671
- summary: "Filter runs to a single automation"
1901
+ flag: "--status <status>",
1902
+ summary: "queued | scheduled | running | paused | completed | failed | canceled"
1672
1903
  },
1673
- { flag: "--limit <n>", summary: "Max rows, 1-200 (default 50)" }
1904
+ LIMIT_FLAG,
1905
+ CURSOR_FLAG,
1906
+ ALL_FLAG,
1907
+ INPUT_FLAG
1674
1908
  ],
1675
1909
  examples: [
1676
1910
  "brew-cli automations audience-runs list",
1677
- "brew-cli automations audience-runs list --automation-id auto_abc --limit 20"
1911
+ "brew-cli automations audience-runs list --automation am_123 --status running"
1678
1912
  ],
1679
1913
  run: async ({ ctx, flags }) => {
1680
- const limit = flagInt(flags.limit, "--limit");
1681
- return {
1682
- data: await ctx.client().automations.audienceRuns.list(
1683
- asSdkInput({
1684
- audienceRunId: flagString(flags.audienceRunId),
1685
- automationId: flagString(flags.automationId),
1686
- limit
1687
- })
1688
- )
1689
- };
1914
+ const audienceRuns = ctx.client().automations.audienceRuns;
1915
+ const base = await readJsonFlag(ctx, flags.input, "--input");
1916
+ const audienceRunId = flagString(flags.audienceRunId) ?? inputField(base, "audienceRunId");
1917
+ if (audienceRunId !== void 0) {
1918
+ const row = await audienceRuns.get(audienceRunId);
1919
+ return { data: singleRowPage(row), human: renderAudienceRuns([row]) };
1920
+ }
1921
+ const input = mergeInput(base, {
1922
+ automationId: flagString(flags.automation) ?? flagString(flags.automationId),
1923
+ status: flagString(flags.status),
1924
+ limit: flagInt(flags.limit, "--limit"),
1925
+ cursor: flagString(flags.cursor)
1926
+ });
1927
+ if (flags.all === true) {
1928
+ const rows = await collectAll(
1929
+ ctx,
1930
+ (cursor) => audienceRuns.list(
1931
+ asSdkInput({
1932
+ ...input,
1933
+ ...cursor === void 0 ? {} : { cursor }
1934
+ })
1935
+ )
1936
+ );
1937
+ return {
1938
+ data: { data: rows, pagination: { cursor: null, hasMore: false } },
1939
+ human: renderAudienceRuns(rows)
1940
+ };
1941
+ }
1942
+ const result = await audienceRuns.list(
1943
+ asSdkInput(input)
1944
+ );
1945
+ return { data: result, human: renderAudienceRuns(result.data) };
1946
+ }
1947
+ });
1948
+ function renderAudienceRuns(rows) {
1949
+ if (rows.length === 0) {
1950
+ return "No audience runs found.";
1690
1951
  }
1952
+ return renderTable(rows, [
1953
+ { key: "audienceRunId", header: "AUDIENCE RUN" },
1954
+ { key: "automationId", header: "AUTOMATION" },
1955
+ { key: "status", header: "STATUS" },
1956
+ { key: "totalRecipients", header: "RECIPIENTS" }
1957
+ ]);
1958
+ }
1959
+
1960
+ // src/commands/automations/audience-runs/pause.ts
1961
+ var automationsAudienceRunsPauseCommand = defineCommand({
1962
+ path: ["automations", "audience-runs", "pause"],
1963
+ summary: "Pause a running manual-audience run at its next step boundary (resumable)",
1964
+ sdkMethod: "automations.audienceRuns.pause",
1965
+ route: {
1966
+ method: "POST",
1967
+ path: "/v1/automations/audience-runs/{audienceRunId}/pause"
1968
+ },
1969
+ commandClass: "write",
1970
+ args: [
1971
+ {
1972
+ name: "audienceRunId",
1973
+ summary: "Audience run id to pause",
1974
+ isRequired: true
1975
+ }
1976
+ ],
1977
+ flags: [IDEMPOTENCY_FLAG],
1978
+ examples: ["brew-cli automations audience-runs pause arun_01HZ"],
1979
+ run: async ({ ctx, args, flags }) => ({
1980
+ data: await ctx.client().automations.audienceRuns.pause(
1981
+ args.audienceRunId ?? "",
1982
+ requestOptions(flags)
1983
+ )
1984
+ })
1985
+ });
1986
+
1987
+ // src/commands/automations/audience-runs/resume.ts
1988
+ var automationsAudienceRunsResumeCommand = defineCommand({
1989
+ path: ["automations", "audience-runs", "resume"],
1990
+ summary: "Resume a paused manual-audience run, or restart a failed one from its first undelivered send",
1991
+ sdkMethod: "automations.audienceRuns.resume",
1992
+ route: {
1993
+ method: "POST",
1994
+ path: "/v1/automations/audience-runs/{audienceRunId}/resume"
1995
+ },
1996
+ commandClass: "write",
1997
+ args: [
1998
+ {
1999
+ name: "audienceRunId",
2000
+ summary: "Audience run id to resume",
2001
+ isRequired: true
2002
+ }
2003
+ ],
2004
+ flags: [IDEMPOTENCY_FLAG],
2005
+ // `resumedFrom` on the response reports which case ran: `paused` or
2006
+ // `failed`. A failed restart never resends a step the failed run finished.
2007
+ examples: ["brew-cli automations audience-runs resume arun_01HZ"],
2008
+ run: async ({ ctx, args, flags }) => ({
2009
+ data: await ctx.client().automations.audienceRuns.resume(
2010
+ args.audienceRunId ?? "",
2011
+ requestOptions(flags)
2012
+ )
2013
+ })
1691
2014
  });
1692
2015
 
1693
2016
  // src/commands/automations/create.ts
@@ -1755,10 +2078,9 @@ var automationsDeleteCommand = defineCommand({
1755
2078
  // src/commands/automations/get.ts
1756
2079
  var automationsGetCommand = defineCommand({
1757
2080
  path: ["automations", "get"],
1758
- summary: "Fetch one automation by id",
1759
- sdkMethod: null,
1760
- derivedFrom: "automations.list",
1761
- route: { method: "GET", path: "/v1/automations" },
2081
+ summary: "Fetch one automation by id \u2014 the bare row, lean by default",
2082
+ sdkMethod: "automations.get",
2083
+ route: { method: "GET", path: "/v1/automations/{automationId}" },
1762
2084
  commandClass: "read",
1763
2085
  args: [
1764
2086
  {
@@ -1770,7 +2092,7 @@ var automationsGetCommand = defineCommand({
1770
2092
  flags: [
1771
2093
  {
1772
2094
  flag: "--include <tokens>",
1773
- summary: "Comma-separated expansions: graph | versions"
2095
+ summary: "Comma-separated expansions: graph, versions"
1774
2096
  }
1775
2097
  ],
1776
2098
  examples: [
@@ -1778,23 +2100,13 @@ var automationsGetCommand = defineCommand({
1778
2100
  "brew-cli automations get am_123 --include graph,versions"
1779
2101
  ],
1780
2102
  run: async ({ ctx, args, flags }) => {
1781
- const automationId = args.automationId ?? "";
1782
2103
  const include = flagString(flags.include);
1783
- const result = await ctx.client().automations.list({
1784
- automationId,
1785
- ...include === void 0 ? {} : { include }
1786
- });
1787
- const automation = result.data[0];
1788
- if (automation === void 0) {
1789
- throw new CliApiError({
1790
- status: 404,
1791
- code: "AUTOMATION_NOT_FOUND",
1792
- type: "not_found",
1793
- message: `No automation found for ${automationId}`,
1794
- suggestion: "List automations with `brew-cli automations list`."
1795
- });
1796
- }
1797
- return { data: automation };
2104
+ return {
2105
+ data: await ctx.client().automations.get(
2106
+ args.automationId ?? "",
2107
+ include === void 0 ? void 0 : { include }
2108
+ )
2109
+ };
1798
2110
  }
1799
2111
  });
1800
2112
 
@@ -1918,7 +2230,7 @@ var automationsRunCommand = defineCommand({
1918
2230
  ],
1919
2231
  confirmSummary: ({ args, flags }) => {
1920
2232
  const inline = parseInlineInput(flags.input);
1921
- if (flags.dryRun === true || inline?.dry_run === true) {
2233
+ if (flags.dryRun === true || inline?.dryRun === true) {
1922
2234
  return;
1923
2235
  }
1924
2236
  const scheduleAt = flagString(flags.scheduleAt) ?? asString(inline?.scheduledAt);
@@ -1928,8 +2240,7 @@ var automationsRunCommand = defineCommand({
1928
2240
  run: async ({ ctx, args, flags }) => {
1929
2241
  const base = await readJsonFlag(ctx, flags.input, "--input");
1930
2242
  const input = mergeInput(base, {
1931
- // The spec field is snake_case, unlike the rest of the API surface.
1932
- dry_run: flags.dryRun === true ? true : void 0,
2243
+ dryRun: flags.dryRun === true ? true : void 0,
1933
2244
  scheduledAt: flagString(flags.scheduleAt)
1934
2245
  });
1935
2246
  return {
@@ -1957,22 +2268,89 @@ function asString(value) {
1957
2268
  return typeof value === "string" && value !== "" ? value : void 0;
1958
2269
  }
1959
2270
 
2271
+ // src/commands/automations/runs/cancel.ts
2272
+ var automationsRunsCancelCommand = defineCommand({
2273
+ path: ["automations", "runs", "cancel"],
2274
+ summary: "Cancel one in-flight automation run (event execution or test run) \u2014 nothing further is sent, and it can never be resumed",
2275
+ sdkMethod: "automations.runs.cancel",
2276
+ route: {
2277
+ method: "POST",
2278
+ path: "/v1/automations/runs/{automationRunId}/cancel"
2279
+ },
2280
+ commandClass: "destructive",
2281
+ args: [
2282
+ {
2283
+ name: "automationRunId",
2284
+ summary: "Run id to cancel (from `automations runs list`, a test start, or a fire response)",
2285
+ isRequired: true
2286
+ }
2287
+ ],
2288
+ flags: [
2289
+ { flag: "--reason <text>", summary: "Operator note stored on the run" },
2290
+ IDEMPOTENCY_FLAG
2291
+ ],
2292
+ examples: [
2293
+ 'brew-cli automations runs cancel run_9f2kX --reason "wrong audience" --yes'
2294
+ ],
2295
+ confirmSummary: ({ args }) => `Cancel automation run ${args.automationRunId ?? ""}. Nothing further is sent; emails already delivered are not recalled, and a canceled run can never be resumed.`,
2296
+ run: async ({ ctx, args, flags }) => {
2297
+ const reason = flagString(flags.reason);
2298
+ const options = {
2299
+ ...requestOptions(flags),
2300
+ ...reason === void 0 ? {} : { reason }
2301
+ };
2302
+ return {
2303
+ data: await ctx.client().automations.runs.cancel(
2304
+ args.automationRunId ?? "",
2305
+ Object.keys(options).length === 0 ? void 0 : options
2306
+ )
2307
+ };
2308
+ }
2309
+ });
2310
+
2311
+ // src/commands/automations/runs/get.ts
2312
+ var automationsRunsGetCommand = defineCommand({
2313
+ path: ["automations", "runs", "get"],
2314
+ summary: "Fetch one automation run by id \u2014 the bare row",
2315
+ sdkMethod: "automations.runs.get",
2316
+ route: { method: "GET", path: "/v1/automations/runs/{automationRunId}" },
2317
+ commandClass: "read",
2318
+ args: [
2319
+ {
2320
+ name: "automationRunId",
2321
+ summary: "Run id (from `automations runs list`, a test start, or a fire)",
2322
+ isRequired: true
2323
+ }
2324
+ ],
2325
+ flags: [
2326
+ {
2327
+ flag: "--include <tokens>",
2328
+ summary: "Expansions: logs (newest 100 per-node execution logs)"
2329
+ }
2330
+ ],
2331
+ examples: [
2332
+ "brew-cli automations runs get run_9f2kX",
2333
+ "brew-cli automations runs get run_9f2kX --include logs"
2334
+ ],
2335
+ run: async ({ ctx, args, flags }) => {
2336
+ const include = flagString(flags.include);
2337
+ return {
2338
+ data: await ctx.client().automations.runs.get(
2339
+ args.automationRunId ?? "",
2340
+ include === void 0 ? void 0 : { include }
2341
+ )
2342
+ };
2343
+ }
2344
+ });
2345
+
1960
2346
  // src/commands/automations/runs/list.ts
1961
2347
  var automationsRunsListCommand = defineCommand({
1962
2348
  path: ["automations", "runs", "list"],
1963
- summary: "List automation runs (live + test history)",
2349
+ summary: "List automation runs (live + test history); one run is `automations runs get`",
1964
2350
  sdkMethod: "automations.runs.list",
1965
2351
  route: { method: "GET", path: "/v1/automations/runs" },
1966
2352
  commandClass: "read",
1967
2353
  flags: [
1968
- {
1969
- flag: "--run <automationRunId>",
1970
- summary: "Fetch one run (single-row page)"
1971
- },
1972
- {
1973
- flag: "--include <tokens>",
1974
- summary: "Comma-separated expansions: logs"
1975
- },
1976
2354
  { flag: "--automation <automationId>", summary: "Filter by automation" },
1977
2355
  {
1978
2356
  flag: "--trigger <triggerEventId>",
@@ -1982,12 +2360,23 @@ var automationsRunsListCommand = defineCommand({
1982
2360
  flag: "--trigger-instance <triggerInstanceId>",
1983
2361
  summary: "Filter by fired trigger instance"
1984
2362
  },
1985
- { flag: "--recipient <email>", summary: "Filter by recipient email" },
1986
2363
  {
1987
2364
  flag: "--status <status>",
1988
- summary: "pending | running | completed | failed | cancelled"
2365
+ summary: "queued | running | completed | failed | canceled"
1989
2366
  },
1990
2367
  { flag: "--mode <mode>", summary: "live | test" },
2368
+ {
2369
+ flag: "--recipient <email>",
2370
+ summary: "Only runs for this recipient (case-insensitive match on the run row's recipientEmail)"
2371
+ },
2372
+ {
2373
+ flag: "--run <automationRunId>",
2374
+ summary: "0.6 shim: read ONE run as a single-row page (`automations runs get` is the real read)"
2375
+ },
2376
+ {
2377
+ flag: "--include <tokens>",
2378
+ summary: "With --run only: detail includes (`logs`)"
2379
+ },
1991
2380
  { flag: "--since <datetime>", summary: "Runs started at/after (ISO-8601)" },
1992
2381
  {
1993
2382
  flag: "--until <datetime>",
@@ -2000,13 +2389,24 @@ var automationsRunsListCommand = defineCommand({
2000
2389
  ],
2001
2390
  examples: [
2002
2391
  "brew-cli automations runs list --automation am_123 --status failed",
2003
- "brew-cli automations runs list --run arun_123 --include logs"
2392
+ "brew-cli automations runs list --trigger-instance tin_2f1c9d8a"
2004
2393
  ],
2005
2394
  run: async ({ ctx, flags }) => {
2395
+ const runs = ctx.client().automations.runs;
2006
2396
  const base = await readJsonFlag(ctx, flags.input, "--input");
2397
+ const runId = flagString(flags.run) ?? inputField(base, "automationRunId");
2398
+ const include = flagString(flags.include) ?? inputField(base, "include");
2399
+ if (runId !== void 0) {
2400
+ const row = await runs.get(
2401
+ runId,
2402
+ include === void 0 ? void 0 : { include }
2403
+ );
2404
+ return { data: singleRowPage(row), human: renderRuns([row]) };
2405
+ }
2406
+ if (include !== void 0) {
2407
+ throw includeRidesDetailRead("automations runs get", "--run");
2408
+ }
2007
2409
  const input = mergeInput(base, {
2008
- automationRunId: flagString(flags.run),
2009
- include: flagString(flags.include),
2010
2410
  automationId: flagString(flags.automation),
2011
2411
  triggerEventId: flagString(flags.trigger),
2012
2412
  triggerInstanceId: flagString(flags.triggerInstance),
@@ -2018,7 +2418,6 @@ var automationsRunsListCommand = defineCommand({
2018
2418
  limit: flagInt(flags.limit, "--limit"),
2019
2419
  cursor: flagString(flags.cursor)
2020
2420
  });
2021
- const runs = ctx.client().automations.runs;
2022
2421
  if (flags.all === true) {
2023
2422
  const rows = await collectAll(
2024
2423
  ctx,
@@ -2083,6 +2482,29 @@ var automationsTestCommand = defineCommand({
2083
2482
  }
2084
2483
  });
2085
2484
 
2485
+ // src/commands/automations/trigger-instances/get.ts
2486
+ var automationsTriggerInstancesGetCommand = defineCommand({
2487
+ path: ["automations", "trigger-instances", "get"],
2488
+ summary: "Fetch one fired-trigger instance by id \u2014 the bare row, with its lifecycle `state` and the runs it started",
2489
+ sdkMethod: "automations.triggerInstances.get",
2490
+ route: {
2491
+ method: "GET",
2492
+ path: "/v1/automations/trigger-instances/{triggerInstanceId}"
2493
+ },
2494
+ commandClass: "read",
2495
+ args: [
2496
+ {
2497
+ name: "triggerInstanceId",
2498
+ summary: "Instance id returned by a fire, or by the instances list",
2499
+ isRequired: true
2500
+ }
2501
+ ],
2502
+ examples: ["brew-cli automations trigger-instances get tin_2f1c9d8a"],
2503
+ run: async ({ ctx, args }) => ({
2504
+ data: await ctx.client().automations.triggerInstances.get(args.triggerInstanceId ?? "")
2505
+ })
2506
+ });
2507
+
2086
2508
  // src/commands/automations/triggers/contract.ts
2087
2509
  var FORMAT_FLAG = {
2088
2510
  flag: "--format <format>",
@@ -2355,17 +2777,52 @@ var automationsTriggersFireCommand = defineCommand({
2355
2777
  }
2356
2778
  });
2357
2779
 
2780
+ // src/commands/automations/triggers/get.ts
2781
+ var automationsTriggersGetCommand = defineCommand({
2782
+ path: ["automations", "triggers", "get"],
2783
+ summary: "Fetch one trigger by id \u2014 the bare row with its payload schema",
2784
+ sdkMethod: "automations.triggers.get",
2785
+ route: { method: "GET", path: "/v1/automations/triggers/{triggerEventId}" },
2786
+ commandClass: "read",
2787
+ args: [
2788
+ {
2789
+ name: "triggerEventId",
2790
+ summary: "Trigger id (tri_\u2026, or an integration composite id)",
2791
+ isRequired: true
2792
+ }
2793
+ ],
2794
+ flags: [
2795
+ {
2796
+ flag: "--include <tokens>",
2797
+ summary: "Expansions: skill (a SKILL.md-shaped wiring brief)"
2798
+ }
2799
+ ],
2800
+ examples: [
2801
+ "brew-cli automations triggers get tri_signup",
2802
+ "brew-cli automations triggers get tri_signup --include skill"
2803
+ ],
2804
+ run: async ({ ctx, args, flags }) => {
2805
+ const include = flagString(flags.include);
2806
+ return {
2807
+ data: await ctx.client().automations.triggers.get(
2808
+ args.triggerEventId ?? "",
2809
+ include === void 0 ? void 0 : { include }
2810
+ )
2811
+ };
2812
+ }
2813
+ });
2814
+
2358
2815
  // src/commands/automations/triggers/list.ts
2359
2816
  var automationsTriggersListCommand = defineCommand({
2360
2817
  path: ["automations", "triggers", "list"],
2361
- summary: "List trigger events (their payload schemas drive fires)",
2818
+ summary: "List trigger events (their payload schemas drive fires); one trigger is `automations triggers get`",
2362
2819
  sdkMethod: "automations.triggers.list",
2363
2820
  route: { method: "GET", path: "/v1/automations/triggers" },
2364
2821
  commandClass: "read",
2365
2822
  flags: [
2366
2823
  {
2367
2824
  flag: "--trigger <triggerEventId>",
2368
- summary: "Fetch one trigger event (single-row page)"
2825
+ summary: "0.6 shim: read ONE trigger as a single-row page (`automations triggers get` is the real read)"
2369
2826
  },
2370
2827
  LIMIT_FLAG,
2371
2828
  CURSOR_FLAG,
@@ -2374,16 +2831,20 @@ var automationsTriggersListCommand = defineCommand({
2374
2831
  ],
2375
2832
  examples: [
2376
2833
  "brew-cli automations triggers list",
2377
- "brew-cli automations triggers list --trigger tev_123"
2834
+ "brew-cli automations triggers list --all --json"
2378
2835
  ],
2379
2836
  run: async ({ ctx, flags }) => {
2837
+ const triggers = ctx.client().automations.triggers;
2380
2838
  const base = await readJsonFlag(ctx, flags.input, "--input");
2839
+ const triggerEventId = flagString(flags.trigger) ?? inputField(base, "triggerEventId");
2840
+ if (triggerEventId !== void 0) {
2841
+ const row = await triggers.get(triggerEventId);
2842
+ return { data: singleRowPage(row), human: renderTriggers([row]) };
2843
+ }
2381
2844
  const input = mergeInput(base, {
2382
- triggerEventId: flagString(flags.trigger),
2383
2845
  limit: flagInt(flags.limit, "--limit"),
2384
2846
  cursor: flagString(flags.cursor)
2385
2847
  });
2386
- const triggers = ctx.client().automations.triggers;
2387
2848
  if (flags.all === true) {
2388
2849
  const rows = await collectAll(
2389
2850
  ctx,
@@ -2418,10 +2879,10 @@ function renderTriggers(rows) {
2418
2879
  var automationsTriggersReadyCommand = defineCommand({
2419
2880
  path: ["automations", "triggers", "ready"],
2420
2881
  summary: "Preflight a trigger without firing: key + scope + permissions pass/fail, the payload contract, and what a fire would start",
2421
- sdkMethod: "automations.triggers.ready",
2882
+ sdkMethod: "automations.triggers.readiness",
2422
2883
  route: {
2423
2884
  method: "GET",
2424
- path: "/v1/automations/triggers/{triggerEventId}/fire"
2885
+ path: "/v1/automations/triggers/{triggerEventId}/readiness"
2425
2886
  },
2426
2887
  commandClass: "read",
2427
2888
  args: [
@@ -2432,17 +2893,13 @@ var automationsTriggersReadyCommand = defineCommand({
2432
2893
  }
2433
2894
  ],
2434
2895
  examples: ["brew-cli automations triggers ready tri_signup"],
2435
- // 200 `status: "ready"` means the exact credential in use can fire this
2436
- // trigger; `details.counts.automations: 0` means fires are accepted and
2437
- // logged but start no runs until a wired automation is published.
2438
- run: async ({ ctx, args }) => {
2439
- const result = await ctx.client().automations.triggers.ready(
2440
- asSdkInput({
2441
- triggerEventId: args.triggerEventId ?? ""
2442
- })
2443
- );
2444
- return { data: result };
2445
- }
2896
+ // 200 `ready: true` means the exact credential in use can fire this
2897
+ // trigger. A `NO_PUBLISHED_AUTOMATION` blocker with `ready: false` means
2898
+ // fires are accepted and logged but start no runs until a wired
2899
+ // automation is published — still a 200, because a probe has to say why.
2900
+ run: async ({ ctx, args }) => ({
2901
+ data: await ctx.client().automations.triggers.readiness(args.triggerEventId ?? "")
2902
+ })
2446
2903
  });
2447
2904
 
2448
2905
  // src/commands/automations/triggers/update.ts
@@ -2962,37 +3419,21 @@ function inlineEmailCount(input) {
2962
3419
  // src/commands/contacts/get.ts
2963
3420
  var contactsGetCommand = defineCommand({
2964
3421
  path: ["contacts", "get"],
2965
- summary: "Fetch one contact by email",
2966
- sdkMethod: null,
2967
- derivedFrom: "contacts.search",
2968
- route: { method: "POST", path: "/v1/contacts/search" },
3422
+ summary: "Fetch one contact by email \u2014 the bare row",
3423
+ sdkMethod: "contacts.get",
3424
+ route: { method: "GET", path: "/v1/contacts/{email}" },
2969
3425
  commandClass: "read",
2970
3426
  args: [
2971
3427
  {
2972
3428
  name: "email",
2973
- summary: "Email address of the contact",
3429
+ summary: "Email address of the contact (the contact primary key)",
2974
3430
  isRequired: true
2975
3431
  }
2976
3432
  ],
2977
3433
  examples: ["brew-cli contacts get jane@example.com"],
2978
- run: async ({ ctx, args }) => {
2979
- const email = args.email ?? "";
2980
- const result = await ctx.client().contacts.search({
2981
- filters: [{ field: "email", operator: "equals", value: email }],
2982
- limit: 1
2983
- });
2984
- const contact = result.data[0];
2985
- if (contact === void 0) {
2986
- throw new CliApiError({
2987
- status: 404,
2988
- code: "CONTACT_NOT_FOUND",
2989
- type: "not_found",
2990
- message: `No contact found for ${email}`,
2991
- suggestion: "Check the address, or create the contact with `brew-cli contacts upsert`."
2992
- });
2993
- }
2994
- return { data: contact };
2995
- }
3434
+ run: async ({ ctx, args }) => ({
3435
+ data: await ctx.client().contacts.get(args.email ?? "")
3436
+ })
2996
3437
  });
2997
3438
 
2998
3439
  // src/commands/contacts/import-csv.ts
@@ -3033,22 +3474,23 @@ var contactsImportCsvCommand = defineCommand({
3033
3474
  }
3034
3475
  });
3035
3476
 
3036
- // src/commands/contacts/search.ts
3037
- var contactsSearchCommand = defineCommand({
3038
- path: ["contacts", "search"],
3039
- summary: "Search contacts with structured filters (the contacts read)",
3040
- sdkMethod: "contacts.search",
3041
- route: { method: "POST", path: "/v1/contacts/search" },
3477
+ // src/commands/contacts/list.ts
3478
+ var contactsListCommand = defineCommand({
3479
+ path: ["contacts", "list"],
3480
+ summary: "List contacts, newest first \u2014 free-text search and one audience; typed clauses are `contacts search`",
3481
+ sdkMethod: "contacts.list",
3482
+ route: { method: "GET", path: "/v1/contacts" },
3042
3483
  commandClass: "read",
3043
3484
  flags: [
3044
3485
  { flag: "--search <text>", summary: "Free-text search" },
3045
3486
  {
3046
- flag: "--filter <filters...>",
3047
- summary: "Structured filter field:operator[:value], repeatable"
3487
+ flag: "--audience <audienceId>",
3488
+ summary: "Only members of this saved audience"
3489
+ },
3490
+ {
3491
+ flag: "--sort <field>",
3492
+ summary: "Any core column or custom field (default createdAt)"
3048
3493
  },
3049
- { flag: "--audience <audienceId>", summary: "Scope to one audience" },
3050
- { flag: "--logic <logic>", summary: "Filter combinator: and | or" },
3051
- { flag: "--sort <field>", summary: "Sort field" },
3052
3494
  { flag: "--order <order>", summary: "Sort order: asc | desc" },
3053
3495
  LIMIT_FLAG,
3054
3496
  CURSOR_FLAG,
@@ -3056,17 +3498,15 @@ var contactsSearchCommand = defineCommand({
3056
3498
  INPUT_FLAG
3057
3499
  ],
3058
3500
  examples: [
3059
- "brew-cli contacts search --filter email:equals:jane@example.com",
3060
- "brew-cli contacts search --search jane --limit 10",
3061
- "brew-cli contacts search --all --json"
3501
+ "brew-cli contacts list --limit 20",
3502
+ "brew-cli contacts list --audience aud_3k9sQ --all --json",
3503
+ "brew-cli contacts list --search acme --sort email --order asc"
3062
3504
  ],
3063
3505
  run: async ({ ctx, flags }) => {
3064
3506
  const base = await readJsonFlag(ctx, flags.input, "--input");
3065
3507
  const input = mergeInput(base, {
3066
3508
  search: flagString(flags.search),
3067
- filters: parseFilterFlags(flags.filter),
3068
3509
  audienceId: flagString(flags.audience),
3069
- logic: flagString(flags.logic),
3070
3510
  sort: flagString(flags.sort),
3071
3511
  order: flagString(flags.order),
3072
3512
  limit: flagInt(flags.limit, "--limit"),
@@ -3076,7 +3516,7 @@ var contactsSearchCommand = defineCommand({
3076
3516
  if (flags.all === true) {
3077
3517
  const rows = await collectAll(
3078
3518
  ctx,
3079
- (cursor) => contacts.search(
3519
+ (cursor) => contacts.list(
3080
3520
  asSdkInput({
3081
3521
  ...input,
3082
3522
  ...cursor === void 0 ? {} : { cursor }
@@ -3088,13 +3528,13 @@ var contactsSearchCommand = defineCommand({
3088
3528
  human: renderContacts(rows)
3089
3529
  };
3090
3530
  }
3091
- const result = await contacts.search(asSdkInput(input));
3531
+ const result = await contacts.list(asSdkInput(input));
3092
3532
  return { data: result, human: renderContacts(result.data) };
3093
3533
  }
3094
3534
  });
3095
3535
  function renderContacts(rows) {
3096
3536
  if (rows.length === 0) {
3097
- return "No contacts matched.";
3537
+ return "No contacts found.";
3098
3538
  }
3099
3539
  return renderTable(rows, [
3100
3540
  { key: "email", header: "EMAIL" },
@@ -3104,15 +3544,86 @@ function renderContacts(rows) {
3104
3544
  ]);
3105
3545
  }
3106
3546
 
3107
- // src/commands/contacts/update.ts
3108
- var contactsUpdateCommand = defineCommand({
3109
- path: ["contacts", "update"],
3110
- summary: "Partially update one contact (PATCH; never retried)",
3111
- sdkMethod: "contacts.patch",
3112
- route: { method: "PATCH", path: "/v1/contacts/{email}" },
3113
- commandClass: "write",
3114
- args: [
3115
- {
3547
+ // src/commands/contacts/search.ts
3548
+ var contactsSearchCommand = defineCommand({
3549
+ path: ["contacts", "search"],
3550
+ summary: "Search contacts with structured filters (the contacts read)",
3551
+ sdkMethod: "contacts.search",
3552
+ route: { method: "POST", path: "/v1/contacts/search" },
3553
+ commandClass: "read",
3554
+ flags: [
3555
+ { flag: "--search <text>", summary: "Free-text search" },
3556
+ {
3557
+ flag: "--filter <filters...>",
3558
+ summary: "Structured filter field:operator[:value], repeatable"
3559
+ },
3560
+ { flag: "--audience <audienceId>", summary: "Scope to one audience" },
3561
+ { flag: "--logic <logic>", summary: "Filter combinator: and | or" },
3562
+ { flag: "--sort <field>", summary: "Sort field" },
3563
+ { flag: "--order <order>", summary: "Sort order: asc | desc" },
3564
+ LIMIT_FLAG,
3565
+ CURSOR_FLAG,
3566
+ ALL_FLAG,
3567
+ INPUT_FLAG
3568
+ ],
3569
+ examples: [
3570
+ "brew-cli contacts search --filter email:equals:jane@example.com",
3571
+ "brew-cli contacts search --search jane --limit 10",
3572
+ "brew-cli contacts search --all --json"
3573
+ ],
3574
+ run: async ({ ctx, flags }) => {
3575
+ const base = await readJsonFlag(ctx, flags.input, "--input");
3576
+ const input = mergeInput(base, {
3577
+ search: flagString(flags.search),
3578
+ filters: parseFilterFlags(flags.filter),
3579
+ audienceId: flagString(flags.audience),
3580
+ logic: flagString(flags.logic),
3581
+ sort: flagString(flags.sort),
3582
+ order: flagString(flags.order),
3583
+ limit: flagInt(flags.limit, "--limit"),
3584
+ cursor: flagString(flags.cursor)
3585
+ });
3586
+ const contacts = ctx.client().contacts;
3587
+ if (flags.all === true) {
3588
+ const rows = await collectAll(
3589
+ ctx,
3590
+ (cursor) => contacts.search(
3591
+ asSdkInput({
3592
+ ...input,
3593
+ ...cursor === void 0 ? {} : { cursor }
3594
+ })
3595
+ )
3596
+ );
3597
+ return {
3598
+ data: { data: rows, pagination: { cursor: null, hasMore: false } },
3599
+ human: renderContacts2(rows)
3600
+ };
3601
+ }
3602
+ const result = await contacts.search(asSdkInput(input));
3603
+ return { data: result, human: renderContacts2(result.data) };
3604
+ }
3605
+ });
3606
+ function renderContacts2(rows) {
3607
+ if (rows.length === 0) {
3608
+ return "No contacts matched.";
3609
+ }
3610
+ return renderTable(rows, [
3611
+ { key: "email", header: "EMAIL" },
3612
+ { key: "firstName", header: "FIRST" },
3613
+ { key: "lastName", header: "LAST" },
3614
+ { key: "subscribed", header: "SUBSCRIBED" }
3615
+ ]);
3616
+ }
3617
+
3618
+ // src/commands/contacts/update.ts
3619
+ var contactsUpdateCommand = defineCommand({
3620
+ path: ["contacts", "update"],
3621
+ summary: "Partially update one contact (PATCH; never retried)",
3622
+ sdkMethod: "contacts.patch",
3623
+ route: { method: "PATCH", path: "/v1/contacts/{email}" },
3624
+ commandClass: "write",
3625
+ args: [
3626
+ {
3116
3627
  name: "email",
3117
3628
  summary: "Email address of the contact",
3118
3629
  isRequired: true
@@ -3582,8 +4093,56 @@ var contractsInferCommand = defineCommand({
3582
4093
  }
3583
4094
  });
3584
4095
 
4096
+ // src/commands/data/run.ts
4097
+ var dataRunCommand = defineCommand({
4098
+ path: ["data", "run"],
4099
+ summary: "Run a `db \u2026` command over the brand's data",
4100
+ sdkMethod: "data.run",
4101
+ route: { method: "POST", path: "/v1/data" },
4102
+ commandClass: "read",
4103
+ args: [
4104
+ {
4105
+ name: "command",
4106
+ summary: "The db command line, e.g. 'db find audiences --fields name'",
4107
+ isRequired: true
4108
+ }
4109
+ ],
4110
+ flags: [],
4111
+ examples: [
4112
+ "brew-cli data run 'db ls'",
4113
+ "brew-cli data run 'db find contacts --since 30d --fields email --limit 20'",
4114
+ "brew-cli data run 'db agg analyticsEvents --since 7d --group-by eventType --bucket day'"
4115
+ ],
4116
+ run: async ({ ctx, args }) => {
4117
+ const result = await ctx.client().data.run({
4118
+ command: args.command ?? ""
4119
+ });
4120
+ return {
4121
+ data: result,
4122
+ human: result.output,
4123
+ exitCode: result.exitCode === 0 ? 0 : 1
4124
+ };
4125
+ }
4126
+ });
4127
+
3585
4128
  // src/skip-list.ts
3586
4129
  var SDK_SKIP_LIST = [
4130
+ {
4131
+ sdkPath: "automations.triggers.getContract",
4132
+ reason: "covered by `automations triggers contract get` (raw route, bound pre-SDK-v9; SDK-method migration tracked separately)"
4133
+ },
4134
+ {
4135
+ sdkPath: "automations.triggers.putContract",
4136
+ reason: "covered by `automations triggers contract put` (raw route, bound pre-SDK-v9)"
4137
+ },
4138
+ {
4139
+ sdkPath: "automations.triggers.validatePayload",
4140
+ reason: "covered by `automations triggers contract validate` (raw route, bound pre-SDK-v9)"
4141
+ },
4142
+ {
4143
+ sdkPath: "payloadContracts.infer",
4144
+ reason: "covered by `contracts infer` (raw route, bound pre-SDK-v9)"
4145
+ },
3587
4146
  {
3588
4147
  sdkPath: "contacts.searchAll",
3589
4148
  reason: "auto-pager covered by `contacts search --all`"
@@ -3593,12 +4152,12 @@ var SDK_SKIP_LIST = [
3593
4152
  reason: "auto-pager covered by `analytics events --all`"
3594
4153
  },
3595
4154
  {
3596
- sdkPath: "analytics.sends.listAll",
3597
- reason: "auto-pager covered by `analytics sends list --all`"
4155
+ sdkPath: "sends.listAll",
4156
+ reason: "auto-pager covered by `sends list --all`"
3598
4157
  },
3599
4158
  {
3600
- sdkPath: "analytics.triggerInstances.listAll",
3601
- reason: "auto-pager covered by `analytics trigger-instances list --all`"
4159
+ sdkPath: "automations.triggerInstances.listAll",
4160
+ reason: "auto-pager covered by `automations trigger-instances list --all`"
3602
4161
  },
3603
4162
  {
3604
4163
  sdkPath: "brand.update",
@@ -3674,7 +4233,7 @@ function buildManifest() {
3674
4233
 
3675
4234
  // src/commands/docs.ts
3676
4235
  var DOCS_POINTERS = {
3677
- documentation: "https://docs.getbrew.io",
4236
+ documentation: "https://docs.brew.new",
3678
4237
  openapiSpec: "https://brew.new/openapi/public-api-v1.yaml",
3679
4238
  agentGuide: "https://brew.new/api/v1/llms.txt",
3680
4239
  apiCatalog: "https://brew.new/api/v1/help",
@@ -3865,28 +4424,15 @@ var domainsDeleteCommand = defineCommand({
3865
4424
  // src/commands/domains/get.ts
3866
4425
  var domainsGetCommand = defineCommand({
3867
4426
  path: ["domains", "get"],
3868
- summary: "Fetch one sending domain by id",
3869
- sdkMethod: null,
3870
- derivedFrom: "domains.list",
3871
- route: { method: "GET", path: "/v1/domains" },
4427
+ summary: "Fetch one sending domain by id \u2014 the bare row",
4428
+ sdkMethod: "domains.get",
4429
+ route: { method: "GET", path: "/v1/domains/{domainId}" },
3872
4430
  commandClass: "read",
3873
4431
  args: [{ name: "domainId", summary: "Domain id to fetch", isRequired: true }],
3874
4432
  examples: ["brew-cli domains get dom_3k9sQ"],
3875
- run: async ({ ctx, args }) => {
3876
- const domainId = args.domainId ?? "";
3877
- const result = await ctx.client().domains.list({ domainId });
3878
- const domain = result.data[0];
3879
- if (domain === void 0) {
3880
- throw new CliApiError({
3881
- status: 404,
3882
- code: "DOMAIN_NOT_FOUND",
3883
- type: "not_found",
3884
- message: `No domain found for ${domainId}`,
3885
- suggestion: "List domains with `brew-cli domains list`."
3886
- });
3887
- }
3888
- return { data: domain };
3889
- }
4433
+ run: async ({ ctx, args }) => ({
4434
+ data: await ctx.client().domains.get(args.domainId ?? "")
4435
+ })
3890
4436
  });
3891
4437
 
3892
4438
  // src/commands/domains/health.ts
@@ -4136,7 +4682,7 @@ var emailsCloneCommand = defineCommand({
4136
4682
  var emailsCreateInboxPlacementTestCommand = defineCommand({
4137
4683
  path: ["emails", "create-inbox-placement-test"],
4138
4684
  summary: "Seed-test where the design lands (inbox vs spam) via a real small send (10 credits)",
4139
- sdkMethod: "emails.createInboxPlacementTest",
4685
+ sdkMethod: "emails.inboxPlacementTests.create",
4140
4686
  route: { method: "POST", path: "/v1/emails/{emailId}/inbox-placement-tests" },
4141
4687
  commandClass: "write",
4142
4688
  isCredited: true,
@@ -4180,9 +4726,9 @@ var emailsCreateInboxPlacementTestCommand = defineCommand({
4180
4726
  const emailVersionId = flagString(flags.emailVersionId);
4181
4727
  const providers = toStringArray(flags.providers);
4182
4728
  return {
4183
- // The API answers 202 with a pending test (status: "collecting");
4184
- // poll `emails get-inbox-placement-results --test-id` for the outcome.
4185
- data: await ctx.client().emails.createInboxPlacementTest(
4729
+ // The API answers 202 with a pending test (status: "queued"); poll
4730
+ // `emails get-inbox-placement-results --test-id` for the outcome.
4731
+ data: await ctx.client().emails.inboxPlacementTests.create(
4186
4732
  asSdkInput({
4187
4733
  emailId: args.emailId ?? "",
4188
4734
  domainId,
@@ -4213,9 +4759,13 @@ var emailsDeleteCommand = defineCommand({
4213
4759
  });
4214
4760
 
4215
4761
  // src/commands/emails/edit.ts
4762
+ var ENVELOPE_FIELDS = ["title", "subjectLine", "groupId"];
4763
+ function isText(value) {
4764
+ return typeof value === "string" && value !== "";
4765
+ }
4216
4766
  var emailsEditCommand = defineCommand({
4217
4767
  path: ["emails", "edit"],
4218
- summary: "AI-edit an email design, and/or set its subject line (subject-only is free)",
4768
+ summary: "AI-edit an email design, and/or set its subject line, title or group (free without a prompt)",
4219
4769
  sdkMethod: "emails.edit",
4220
4770
  route: { method: "PATCH", path: "/v1/emails/{emailId}" },
4221
4771
  commandClass: "write",
@@ -4235,30 +4785,54 @@ var emailsEditCommand = defineCommand({
4235
4785
  flag: "--subject-line <text>",
4236
4786
  summary: "The design's default inbox subject line; alone it skips the AI run"
4237
4787
  },
4788
+ {
4789
+ flag: "--title <text>",
4790
+ summary: "Rename the design (its canvas name); alone it skips the AI run"
4791
+ },
4792
+ {
4793
+ flag: "--group-id <groupId>",
4794
+ summary: "Move the design into this existing group; alone it skips the AI run"
4795
+ },
4796
+ {
4797
+ flag: "--ungroup",
4798
+ summary: "Move the design to Ungrouped (groupId: null)"
4799
+ },
4238
4800
  INPUT_FLAG
4239
4801
  ],
4240
4802
  examples: [
4241
4803
  'brew-cli emails edit eml_2SmZOWV3ZQ7W5x6g3m4p --prompt "Tighten the hero copy"',
4242
- 'brew-cli emails edit eml_2SmZOWV3ZQ7W5x6g3m4p --subject-line "Your September roundup"'
4804
+ 'brew-cli emails edit eml_2SmZOWV3ZQ7W5x6g3m4p --subject-line "Your September roundup"',
4805
+ 'brew-cli emails edit eml_2SmZOWV3ZQ7W5x6g3m4p --title "Fall sale v2" --group-id grp_7Hq2',
4806
+ "brew-cli emails edit eml_2SmZOWV3ZQ7W5x6g3m4p --ungroup"
4243
4807
  ],
4244
4808
  run: async ({ ctx, args, flags }) => {
4809
+ const groupId = flagString(flags.groupId);
4810
+ if (groupId !== void 0 && flags.ungroup === true) {
4811
+ throw new CliUsageError(
4812
+ "--group-id and --ungroup conflict: pick one group move."
4813
+ );
4814
+ }
4245
4815
  const base = await readJsonFlag(ctx, flags.input, "--input");
4246
4816
  const input = mergeInput(base, {
4247
4817
  prompt: flagString(flags.prompt),
4248
4818
  emailVersionId: flagString(flags.emailVersionId),
4249
4819
  contentUrls: toStringArray(flags.contentUrls),
4250
- subjectLine: flagString(flags.subjectLine)
4820
+ subjectLine: flagString(flags.subjectLine),
4821
+ title: flagString(flags.title),
4822
+ groupId: flags.ungroup === true ? null : groupId
4251
4823
  });
4252
- const isPromptEdit = typeof input.prompt === "string" && input.prompt !== "";
4253
- const hasSubjectLine = typeof input.subjectLine === "string" && input.subjectLine !== "";
4254
- if (!(isPromptEdit || hasSubjectLine)) {
4824
+ const isPromptEdit = isText(input.prompt);
4825
+ const envelope = ENVELOPE_FIELDS.filter(
4826
+ (field) => isText(input[field]) || field === "groupId" && input[field] === null
4827
+ );
4828
+ if (!isPromptEdit && envelope.length === 0) {
4255
4829
  throw new CliUsageError(
4256
- "--prompt or --subject-line is required (or provide either via --input)."
4830
+ "Pass --prompt, or at least one of --subject-line, --title, --group-id or --ungroup (or those fields via --input)."
4257
4831
  );
4258
4832
  }
4259
4833
  progress(
4260
4834
  ctx,
4261
- isPromptEdit ? "Editing email\u2026 (typically 30-90s)" : "Setting the subject line\u2026"
4835
+ isPromptEdit ? "Editing email\u2026 (typically 30-90s)" : envelope.length === 1 && envelope[0] === "subjectLine" ? "Setting the subject line\u2026" : "Updating the design (no AI run)\u2026"
4262
4836
  );
4263
4837
  const result = await ctx.client().emails.edit(
4264
4838
  asSdkInput({ ...input, emailId: args.emailId ?? "" }),
@@ -4310,7 +4884,7 @@ var emailsExportCommand = defineCommand({
4310
4884
  provider,
4311
4885
  ...templateName === void 0 ? {} : { templateName },
4312
4886
  // The spec field is snake_case, unlike the rest of the API surface.
4313
- ...flags.dryRun === true ? { dry_run: true } : {}
4887
+ ...flags.dryRun === true ? { dryRun: true } : {}
4314
4888
  }),
4315
4889
  requestOptions(flags)
4316
4890
  )
@@ -4379,10 +4953,9 @@ var emailsGenerateCommand = defineCommand({
4379
4953
  // src/commands/emails/get.ts
4380
4954
  var emailsGetCommand = defineCommand({
4381
4955
  path: ["emails", "get"],
4382
- summary: "Fetch one email design by id",
4383
- sdkMethod: null,
4384
- derivedFrom: "emails.list",
4385
- route: { method: "GET", path: "/v1/emails" },
4956
+ summary: "Fetch one email design by id \u2014 the bare row",
4957
+ sdkMethod: "emails.get",
4958
+ route: { method: "GET", path: "/v1/emails/{emailId}" },
4386
4959
  commandClass: "read",
4387
4960
  args: [
4388
4961
  {
@@ -4394,7 +4967,7 @@ var emailsGetCommand = defineCommand({
4394
4967
  flags: [
4395
4968
  {
4396
4969
  flag: "--include <tokens>",
4397
- summary: "Comma-separated expansions: html,versions"
4970
+ summary: "Comma-separated expansions: html, versions"
4398
4971
  }
4399
4972
  ],
4400
4973
  examples: [
@@ -4402,31 +4975,89 @@ var emailsGetCommand = defineCommand({
4402
4975
  "brew-cli emails get eml_2SmZOWV3ZQ7W5x6g3m4p --include html,versions"
4403
4976
  ],
4404
4977
  run: async ({ ctx, args, flags }) => {
4405
- const emailId = args.emailId ?? "";
4406
4978
  const include = flagString(flags.include);
4407
- const result = await ctx.client().emails.list({
4408
- emailId,
4409
- ...include === void 0 ? {} : { include }
4979
+ return {
4980
+ data: await ctx.client().emails.get(
4981
+ args.emailId ?? "",
4982
+ include === void 0 ? void 0 : { include }
4983
+ )
4984
+ };
4985
+ }
4986
+ });
4987
+
4988
+ // src/commands/emails/get-audit.ts
4989
+ var emailsGetAuditCommand = defineCommand({
4990
+ path: ["emails", "get-audit"],
4991
+ summary: "Read a saved email audit: one page of its findings (free; never reruns the audit)",
4992
+ sdkMethod: null,
4993
+ isRawTransport: true,
4994
+ route: { method: "GET", path: "/v1/emails/audits/{auditId}" },
4995
+ commandClass: "read",
4996
+ args: [
4997
+ {
4998
+ name: "auditId",
4999
+ summary: "The auditId `emails audit` returned (reports are kept 7 days)",
5000
+ isRequired: true
5001
+ }
5002
+ ],
5003
+ flags: [LIMIT_FLAG, CURSOR_FLAG],
5004
+ examples: [
5005
+ "brew-cli emails get-audit 6f1e2d3c-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
5006
+ "brew-cli emails get-audit 6f1e2d3c-4b5a-4c7d-8e9f-0a1b2c3d4e5f --limit 20"
5007
+ ],
5008
+ // The next page is `--cursor <pagination.cursor>`; `pagination.hasMore`
5009
+ // says whether one exists.
5010
+ run: async ({ ctx, args, flags }) => {
5011
+ const limit = flagInt(flags.limit, "--limit");
5012
+ const body = await rawRequest(ctx, {
5013
+ method: "GET",
5014
+ path: `/v1/emails/audits/${encodeURIComponent(args.auditId ?? "")}`,
5015
+ query: {
5016
+ cursor: flagString(flags.cursor),
5017
+ limit: limit === void 0 ? void 0 : String(limit)
5018
+ }
4410
5019
  });
4411
- const email = result.data[0];
4412
- if (email === void 0) {
4413
- throw new CliApiError({
4414
- status: 404,
4415
- code: "EMAIL_NOT_FOUND",
4416
- type: "not_found",
4417
- message: `No email design found for ${emailId}`,
4418
- suggestion: "List designs with `brew-cli emails list`."
4419
- });
5020
+ return { data: body };
5021
+ }
5022
+ });
5023
+
5024
+ // src/commands/emails/get-client-preview.ts
5025
+ var emailsGetClientPreviewCommand = defineCommand({
5026
+ path: ["emails", "get-client-preview"],
5027
+ summary: "Poll a client-preview rendering job: per-client screenshot links once it settles (free; never re-renders)",
5028
+ sdkMethod: null,
5029
+ isRawTransport: true,
5030
+ route: { method: "GET", path: "/v1/emails/client-previews/{previewId}" },
5031
+ commandClass: "read",
5032
+ args: [
5033
+ {
5034
+ name: "previewId",
5035
+ summary: "The previewId `emails preview-clients` returned",
5036
+ isRequired: true
4420
5037
  }
4421
- return { data: email };
5038
+ ],
5039
+ examples: [
5040
+ "brew-cli emails get-client-preview prv_0b7f3c1e-9a2d-4e8b-b6c5-3d1f2a9e8c47",
5041
+ "brew-cli emails get-client-preview prv_0b7f3c1e-9a2d-4e8b-b6c5-3d1f2a9e8c47 --json | jq '.previews[] | {label, status, imageUrl}'"
5042
+ ],
5043
+ // While `status` is `queued` or `running`, poll again after
5044
+ // `nextPollAfterMs`. It settles as `completed`, `partially_completed` or
5045
+ // `failed`; each client then carries its `imageUrl`, or a `reason` and
5046
+ // whether it is `retryable`.
5047
+ run: async ({ ctx, args }) => {
5048
+ const body = await rawRequest(ctx, {
5049
+ method: "GET",
5050
+ path: `/v1/emails/client-previews/${encodeURIComponent(args.previewId ?? "")}`
5051
+ });
5052
+ return { data: body };
4422
5053
  }
4423
5054
  });
4424
5055
 
4425
5056
  // src/commands/emails/get-inbox-placement-results.ts
4426
5057
  var emailsGetInboxPlacementResultsCommand = defineCommand({
4427
5058
  path: ["emails", "get-inbox-placement-results"],
4428
- summary: "Inbox placement results: one test with --test-id, else the recent tests",
4429
- sdkMethod: "emails.getInboxPlacementResults",
5059
+ summary: "Inbox placement results: the recent tests, or one test with --test-id",
5060
+ sdkMethod: "emails.inboxPlacementTests.list",
4430
5061
  route: { method: "GET", path: "/v1/emails/{emailId}/inbox-placement-tests" },
4431
5062
  commandClass: "read",
4432
5063
  args: [
@@ -4438,22 +5069,38 @@ var emailsGetInboxPlacementResultsCommand = defineCommand({
4438
5069
  ],
4439
5070
  flags: [
4440
5071
  {
5072
+ // The list no longer filters by test id: --test-id reads the real
5073
+ // detail route, the same one `emails inbox-placement-tests get` binds.
4441
5074
  flag: "--test-id <id>",
4442
5075
  summary: "One test: live status + per-provider placement (re-poll ~30s until completed)"
4443
- }
5076
+ },
5077
+ LIMIT_FLAG,
5078
+ CURSOR_FLAG,
5079
+ INPUT_FLAG
4444
5080
  ],
4445
5081
  examples: [
4446
5082
  "brew-cli emails get-inbox-placement-results eml_2SmZOWV3ZQ7W5x6g3m4p",
4447
5083
  "brew-cli emails get-inbox-placement-results eml_2SmZOWV3ZQ7W5x6g3m4p --test-id ibp_2f1c9d8a"
4448
5084
  ],
4449
- run: async ({ ctx, args, flags }) => ({
4450
- data: await ctx.client().emails.getInboxPlacementResults(
4451
- asSdkInput({
4452
- emailId: args.emailId ?? "",
4453
- testId: flagString(flags.testId)
4454
- })
4455
- )
4456
- })
5085
+ run: async ({ ctx, args, flags }) => {
5086
+ const emailId = args.emailId ?? "";
5087
+ const testId = flagString(flags.testId);
5088
+ const inboxPlacementTests = ctx.client().emails.inboxPlacementTests;
5089
+ if (testId !== void 0) {
5090
+ return { data: await inboxPlacementTests.get(emailId, testId) };
5091
+ }
5092
+ const base = await readJsonFlag(ctx, flags.input, "--input");
5093
+ const input = mergeInput(base, {
5094
+ emailId,
5095
+ limit: flagInt(flags.limit, "--limit"),
5096
+ cursor: flagString(flags.cursor)
5097
+ });
5098
+ return {
5099
+ data: await inboxPlacementTests.list(
5100
+ asSdkInput(input)
5101
+ )
5102
+ };
5103
+ }
4457
5104
  });
4458
5105
 
4459
5106
  // src/commands/emails/groups/create.ts
@@ -4510,6 +5157,29 @@ var emailsGroupsDeleteCommand = defineCommand({
4510
5157
  })
4511
5158
  });
4512
5159
 
5160
+ // src/commands/emails/groups/get.ts
5161
+ var emailsGroupsGetCommand = defineCommand({
5162
+ path: ["emails", "groups", "get"],
5163
+ summary: "Fetch one email group by id \u2014 the bare row",
5164
+ sdkMethod: "emailGroups.get",
5165
+ route: { method: "GET", path: "/v1/email-groups/{groupId}" },
5166
+ commandClass: "read",
5167
+ args: [
5168
+ {
5169
+ name: "groupId",
5170
+ summary: "Group id (`grp_\u2026`, or the literal `ungrouped`)",
5171
+ isRequired: true
5172
+ }
5173
+ ],
5174
+ examples: [
5175
+ "brew-cli emails groups get grp_2f1c9d8a",
5176
+ "brew-cli emails groups get ungrouped"
5177
+ ],
5178
+ run: async ({ ctx, args }) => ({
5179
+ data: await ctx.client().emailGroups.get(args.groupId ?? "")
5180
+ })
5181
+ });
5182
+
4513
5183
  // src/commands/emails/groups/list.ts
4514
5184
  var emailsGroupsListCommand = defineCommand({
4515
5185
  path: ["emails", "groups", "list"],
@@ -4700,53 +5370,108 @@ var emailsImportFigmaCommand = defineCommand({
4700
5370
  }
4701
5371
  });
4702
5372
 
5373
+ // src/commands/emails/inbox-placement-tests/get.ts
5374
+ var emailsInboxPlacementTestsGetCommand = defineCommand({
5375
+ path: ["emails", "inbox-placement-tests", "get"],
5376
+ summary: "Fetch one inbox-placement (seed) test \u2014 the bare row, re-poll ~30s until completed",
5377
+ sdkMethod: "emails.inboxPlacementTests.get",
5378
+ route: {
5379
+ method: "GET",
5380
+ path: "/v1/emails/{emailId}/inbox-placement-tests/{testId}"
5381
+ },
5382
+ commandClass: "read",
5383
+ args: [
5384
+ {
5385
+ name: "emailId",
5386
+ summary: "Design id the test ran on",
5387
+ isRequired: true
5388
+ },
5389
+ {
5390
+ name: "testId",
5391
+ summary: "Test id returned by `emails create-inbox-placement-test`",
5392
+ isRequired: true
5393
+ }
5394
+ ],
5395
+ examples: [
5396
+ "brew-cli emails inbox-placement-tests get eml_2SmZOWV3ZQ7W5x6g3m4p ibp_2f1c9d8a"
5397
+ ],
5398
+ run: async ({ ctx, args }) => ({
5399
+ data: await ctx.client().emails.inboxPlacementTests.get(args.emailId ?? "", args.testId ?? "")
5400
+ })
5401
+ });
5402
+
4703
5403
  // src/commands/emails/list.ts
4704
5404
  var emailsListCommand = defineCommand({
4705
5405
  path: ["emails", "list"],
4706
- summary: "List email designs (the single email read)",
5406
+ summary: "List email designs; one design is `emails get`",
4707
5407
  sdkMethod: "emails.list",
4708
5408
  route: { method: "GET", path: "/v1/emails" },
4709
5409
  commandClass: "read",
4710
5410
  flags: [
4711
5411
  {
4712
5412
  flag: "--status <status>",
4713
- summary: "Filter by status: streaming | complete | error"
5413
+ summary: "Filter by status: generating | ready | failed"
4714
5414
  },
4715
5415
  {
4716
5416
  flag: "--group-id <groupId>",
4717
5417
  summary: "Filter by one group id; use ungrouped for no saved group"
4718
5418
  },
4719
5419
  {
4720
- flag: "--sort <field>",
4721
- summary: "Sort by updatedAt | createdAt | title"
5420
+ flag: "--sort-by <field>",
5421
+ summary: "Timestamp the page is ordered by and that --since/--until bound: updatedAt (default) | createdAt"
5422
+ },
5423
+ {
5424
+ flag: "--since <iso>",
5425
+ summary: "Inclusive lower bound on the --sort-by timestamp (ISO-8601)"
5426
+ },
5427
+ {
5428
+ flag: "--until <iso>",
5429
+ summary: "Inclusive upper bound on the --sort-by timestamp (ISO-8601)"
5430
+ },
5431
+ { flag: "--sort <field>", summary: "0.6 alias of --sort-by" },
5432
+ {
5433
+ flag: "--order <order>",
5434
+ summary: "0.6 flag: pages are newest first; only desc is accepted"
5435
+ },
5436
+ {
5437
+ flag: "--created-at-from <iso>",
5438
+ summary: "0.6 alias of --sort-by createdAt --since <iso>"
5439
+ },
5440
+ {
5441
+ flag: "--created-at-to <iso>",
5442
+ summary: "0.6 alias of --sort-by createdAt --until <iso>"
5443
+ },
5444
+ {
5445
+ flag: "--updated-at-from <iso>",
5446
+ summary: "0.6 alias of --sort-by updatedAt --since <iso>"
5447
+ },
5448
+ {
5449
+ flag: "--updated-at-to <iso>",
5450
+ summary: "0.6 alias of --sort-by updatedAt --until <iso>"
4722
5451
  },
4723
- { flag: "--order <order>", summary: "Sort order: asc | desc" },
4724
- { flag: "--created-at-from <iso>", summary: "Created at or after (ISO)" },
4725
- { flag: "--created-at-to <iso>", summary: "Created at or before (ISO)" },
4726
- { flag: "--updated-at-from <iso>", summary: "Updated at or after (ISO)" },
4727
- { flag: "--updated-at-to <iso>", summary: "Updated at or before (ISO)" },
4728
5452
  LIMIT_FLAG,
4729
5453
  CURSOR_FLAG,
4730
5454
  ALL_FLAG,
4731
5455
  INPUT_FLAG
4732
5456
  ],
4733
5457
  examples: [
4734
- "brew-cli emails list --status complete --limit 10",
4735
- "brew-cli emails list --group-id ungrouped --sort title --order asc",
4736
- "brew-cli emails list --updated-at-from 2026-08-01T00:00:00Z",
5458
+ "brew-cli emails list --status ready --limit 10",
5459
+ "brew-cli emails list --group-id ungrouped",
5460
+ "brew-cli emails list --sort-by createdAt --since 2026-08-01T00:00:00Z",
4737
5461
  "brew-cli emails list --all --json"
4738
5462
  ],
4739
5463
  run: async ({ ctx, flags }) => {
5464
+ const legacy = legacyWindow(
5465
+ flags,
5466
+ flagString(flags.sortBy) ?? flagString(flags.sort)
5467
+ );
4740
5468
  const base = await readJsonFlag(ctx, flags.input, "--input");
4741
5469
  const input = mergeInput(base, {
4742
5470
  status: flagString(flags.status),
4743
5471
  groupId: flagString(flags.groupId),
4744
- sort: flagString(flags.sort),
4745
- order: flagString(flags.order),
4746
- createdAtFrom: flagString(flags.createdAtFrom),
4747
- createdAtTo: flagString(flags.createdAtTo),
4748
- updatedAtFrom: flagString(flags.updatedAtFrom),
4749
- updatedAtTo: flagString(flags.updatedAtTo),
5472
+ sortBy: flagString(flags.sortBy) ?? flagString(flags.sort) ?? legacy.sortBy,
5473
+ from: flagString(flags.since) ?? legacy.from,
5474
+ to: flagString(flags.until) ?? legacy.to,
4750
5475
  limit: flagInt(flags.limit, "--limit"),
4751
5476
  cursor: flagString(flags.cursor)
4752
5477
  });
@@ -4770,6 +5495,40 @@ var emailsListCommand = defineCommand({
4770
5495
  return { data: result, human: renderEmails(result.data) };
4771
5496
  }
4772
5497
  });
5498
+ function legacyWindow(flags, explicitSortBy) {
5499
+ const order = flagString(flags.order);
5500
+ if (order !== void 0 && order !== "desc") {
5501
+ throw new CliUsageError(
5502
+ "GET /v1/emails pages newest first only; --order asc has no equivalent."
5503
+ );
5504
+ }
5505
+ const created = {
5506
+ from: flagString(flags.createdAtFrom),
5507
+ to: flagString(flags.createdAtTo)
5508
+ };
5509
+ const updated = {
5510
+ from: flagString(flags.updatedAtFrom),
5511
+ to: flagString(flags.updatedAtTo)
5512
+ };
5513
+ const hasCreated = created.from !== void 0 || created.to !== void 0;
5514
+ const hasUpdated = updated.from !== void 0 || updated.to !== void 0;
5515
+ if (hasCreated && hasUpdated) {
5516
+ throw new CliUsageError(
5517
+ "The API bounds one timestamp per page: pass --created-at-* or --updated-at-*, not both (or --sort-by with --since/--until)."
5518
+ );
5519
+ }
5520
+ if (!(hasCreated || hasUpdated)) {
5521
+ return { sortBy: void 0, from: void 0, to: void 0 };
5522
+ }
5523
+ const column = hasCreated ? "createdAt" : "updatedAt";
5524
+ if (explicitSortBy !== void 0 && explicitSortBy !== column) {
5525
+ const prefix = hasCreated ? "--created-at-*" : "--updated-at-*";
5526
+ throw new CliUsageError(
5527
+ `${prefix} bounds ${column}, but the page is ordered by ${explicitSortBy}; the API bounds the --sort-by timestamp only.`
5528
+ );
5529
+ }
5530
+ return { sortBy: column, ...hasCreated ? created : updated };
5531
+ }
4773
5532
  function renderEmails(rows) {
4774
5533
  if (rows.length === 0) {
4775
5534
  return "No email designs found.";
@@ -4786,7 +5545,7 @@ function renderEmails(rows) {
4786
5545
  // src/commands/emails/preview-clients.ts
4787
5546
  var emailsPreviewClientsCommand = defineCommand({
4788
5547
  path: ["emails", "preview-clients"],
4789
- summary: "Render the design across real email clients (10 credits)",
5548
+ summary: "Start a rendering job across real email clients (10 credits); poll it with `emails get-client-preview`",
4790
5549
  sdkMethod: "emails.previewClients",
4791
5550
  route: { method: "POST", path: "/v1/emails/{emailId}/client-previews" },
4792
5551
  commandClass: "write",
@@ -4799,25 +5558,49 @@ var emailsPreviewClientsCommand = defineCommand({
4799
5558
  flag: "--clients <ids...>",
4800
5559
  summary: "Client id(s) to render, repeatable (e.g. applemail16 iphone16_18); default: a popular spread"
4801
5560
  },
5561
+ {
5562
+ flag: "--email-version-id <id>",
5563
+ summary: "Render this saved version (default: the latest)"
5564
+ },
4802
5565
  IDEMPOTENCY_FLAG
4803
5566
  ],
4804
5567
  examples: [
4805
5568
  "brew-cli emails preview-clients eml_2SmZOWV3ZQ7W5x6g3m4p",
4806
- "brew-cli emails preview-clients eml_2SmZOWV3ZQ7W5x6g3m4p --clients applemail16 outlook2021_win11_lm_dt"
5569
+ "brew-cli emails preview-clients eml_2SmZOWV3ZQ7W5x6g3m4p --clients applemail16 outlook2021_win11_lm_dt",
5570
+ 'PREVIEW_ID=$(brew-cli emails preview-clients eml_2SmZOWV3ZQ7W5x6g3m4p --json | jq -r .previewId) && brew-cli emails get-client-preview "$PREVIEW_ID"'
4807
5571
  ],
5572
+ // The API answers 202 with the admitted job (or 200 with the existing job
5573
+ // for the same version and clients): `previewId`, its `status` and
5574
+ // per-client progress. Screenshots arrive on the job once it settles, so
5575
+ // `emails get-client-preview <previewId>` is how they are read.
4808
5576
  run: async ({ ctx, args, flags }) => {
4809
5577
  const clients = toStringArray(flags.clients);
4810
- return {
4811
- data: await ctx.client().emails.previewClients(
4812
- asSdkInput({
4813
- emailId: args.emailId ?? "",
4814
- ...clients === void 0 ? {} : { clients }
4815
- }),
4816
- requestOptions(flags)
4817
- )
4818
- };
5578
+ const emailVersionId = flagString(flags.emailVersionId);
5579
+ const job = await ctx.client().emails.previewClients(
5580
+ asSdkInput({
5581
+ emailId: args.emailId ?? "",
5582
+ ...clients === void 0 ? {} : { clients },
5583
+ ...emailVersionId === void 0 ? {} : { emailVersionId }
5584
+ }),
5585
+ requestOptions(flags)
5586
+ );
5587
+ const hint = pollHint(job);
5588
+ if (hint !== void 0) {
5589
+ progress(ctx, hint);
5590
+ }
5591
+ return { data: job };
4819
5592
  }
4820
5593
  });
5594
+ function pollHint(job) {
5595
+ if (typeof job !== "object" || job === null || !("previewId" in job) || !("status" in job)) {
5596
+ return;
5597
+ }
5598
+ const { previewId, status } = job;
5599
+ if (typeof previewId !== "string" || status !== "queued" && status !== "running") {
5600
+ return;
5601
+ }
5602
+ return `Rendering job ${previewId} is ${status}. Poll it with: brew-cli emails get-client-preview ${previewId}`;
5603
+ }
4821
5604
 
4822
5605
  // src/commands/emails/restore.ts
4823
5606
  var emailsRestoreCommand = defineCommand({
@@ -4831,19 +5614,24 @@ var emailsRestoreCommand = defineCommand({
4831
5614
  ],
4832
5615
  // --version is taken by the CLI itself, hence --to-version.
4833
5616
  flags: [
4834
- { flag: "--to-version <n>", summary: "Version number to restore" },
5617
+ {
5618
+ flag: "--to-version <emailVersionId>",
5619
+ summary: "Version id to restore (from `emails get <emailId> --include versions`)"
5620
+ },
4835
5621
  IDEMPOTENCY_FLAG
4836
5622
  ],
4837
- examples: ["brew-cli emails restore eml_2SmZOWV3ZQ7W5x6g3m4p --to-version 2"],
5623
+ examples: [
5624
+ "brew-cli emails restore eml_2SmZOWV3ZQ7W5x6g3m4p --to-version emv_7Hq2"
5625
+ ],
4838
5626
  run: async ({ ctx, args, flags }) => {
4839
- const version = flagInt(flags.toVersion, "--to-version");
4840
- if (version === void 0) {
5627
+ const emailVersionId = flagString(flags.toVersion);
5628
+ if (emailVersionId === void 0) {
4841
5629
  throw new CliUsageError(
4842
- "--to-version is required (see `brew-cli emails get <emailId> --include versions`)."
5630
+ "--to-version is required (a version id; see `brew-cli emails get <emailId> --include versions`)."
4843
5631
  );
4844
5632
  }
4845
5633
  const result = await ctx.client().emails.restore(
4846
- { emailId: args.emailId ?? "", version },
5634
+ { emailId: args.emailId ?? "", emailVersionId },
4847
5635
  requestOptions(flags)
4848
5636
  );
4849
5637
  return { data: result };
@@ -5013,6 +5801,26 @@ var fieldsDeleteCommand = defineCommand({
5013
5801
  })
5014
5802
  });
5015
5803
 
5804
+ // src/commands/fields/get.ts
5805
+ var fieldsGetCommand = defineCommand({
5806
+ path: ["fields", "get"],
5807
+ summary: "Fetch one contact field definition by name \u2014 the bare row",
5808
+ sdkMethod: "fields.get",
5809
+ route: { method: "GET", path: "/v1/fields/{fieldName}" },
5810
+ commandClass: "read",
5811
+ args: [
5812
+ {
5813
+ name: "fieldName",
5814
+ summary: "Field name (a core column or a custom field)",
5815
+ isRequired: true
5816
+ }
5817
+ ],
5818
+ examples: ["brew-cli fields get loyalty_tier"],
5819
+ run: async ({ ctx, args }) => ({
5820
+ data: await ctx.client().fields.get(args.fieldName ?? "")
5821
+ })
5822
+ });
5823
+
5016
5824
  // src/commands/fields/list.ts
5017
5825
  var fieldsListCommand = defineCommand({
5018
5826
  path: ["fields", "list"],
@@ -5024,6 +5832,178 @@ var fieldsListCommand = defineCommand({
5024
5832
  run: async ({ ctx }) => ({ data: await ctx.client().fields.list() })
5025
5833
  });
5026
5834
 
5835
+ // src/commands/flows/get.ts
5836
+ var flowsGetCommand = defineCommand({
5837
+ path: ["flows", "get"],
5838
+ summary: "Fetch one public email flow by brand domain, with every step (day offset, wait, subject, template id)",
5839
+ sdkMethod: "flows.get",
5840
+ route: { method: "GET", path: "/v1/flows/{slug}" },
5841
+ commandClass: "read",
5842
+ args: [
5843
+ {
5844
+ name: "slug",
5845
+ summary: "The brand domain a `flows list` card carries (e.g. brew.new)",
5846
+ isRequired: true
5847
+ }
5848
+ ],
5849
+ flags: [
5850
+ {
5851
+ flag: "--include <keys>",
5852
+ summary: "Comma-separated expansions: html (each step\u2019s rendered HTML, best-effort per step)"
5853
+ }
5854
+ ],
5855
+ examples: [
5856
+ "brew-cli flows get brew.new",
5857
+ "brew-cli flows get brew.new --include html --json"
5858
+ ],
5859
+ run: async ({ ctx, args, flags }) => {
5860
+ const include = flagString(flags.include);
5861
+ const flow = await ctx.client().flows.get(
5862
+ args.slug ?? "",
5863
+ include === void 0 ? void 0 : { include }
5864
+ );
5865
+ return { data: flow, human: renderSteps(flow) };
5866
+ }
5867
+ });
5868
+ function renderSteps(flow) {
5869
+ const header = `${flow.title} \u2014 ${flow.brand.name} (${flow.slug}), ${flow.emailCount} emails over ${flow.spanDays} days${flow.anchor === void 0 ? "" : `, day 0 = ${flow.anchor}`}`;
5870
+ const table = renderTable(
5871
+ (flow.steps ?? []).map((step) => ({
5872
+ order: step.order,
5873
+ day: step.dayOffset,
5874
+ wait: step.delayDays,
5875
+ subject: step.subject,
5876
+ category: step.category,
5877
+ emailId: step.emailId
5878
+ })),
5879
+ [
5880
+ { key: "order", header: "#" },
5881
+ { key: "day", header: "DAY" },
5882
+ { key: "wait", header: "WAIT" },
5883
+ { key: "subject", header: "SUBJECT" },
5884
+ { key: "category", header: "CATEGORY" },
5885
+ { key: "emailId", header: "TEMPLATE" }
5886
+ ]
5887
+ );
5888
+ return `${header}
5889
+
5890
+ ${table}`;
5891
+ }
5892
+
5893
+ // src/commands/flows/list.ts
5894
+ var flowsListCommand = defineCommand({
5895
+ path: ["flows", "list"],
5896
+ summary: "List public email flows (real multi-step sequences by brand) as cards; `flows get <slug>` reads one",
5897
+ sdkMethod: "flows.list",
5898
+ route: { method: "GET", path: "/v1/flows" },
5899
+ commandClass: "read",
5900
+ flags: [
5901
+ {
5902
+ // --brand is taken by the global brand-selection flag.
5903
+ flag: "--brand-domain <domain>",
5904
+ summary: "Filter the list by brand domain"
5905
+ },
5906
+ {
5907
+ flag: "--category <category>",
5908
+ summary: "Filter by dominant step category (welcome, newsletter, \u2026)"
5909
+ },
5910
+ {
5911
+ flag: "--type <type>",
5912
+ summary: "Filter by how the sequence starts: signup | newsletter"
5913
+ },
5914
+ {
5915
+ flag: "--semantic <text>",
5916
+ summary: "Semantic search over the sequences (relevance order)"
5917
+ },
5918
+ {
5919
+ flag: "--sort <order>",
5920
+ summary: "List order: newest (default) | emails | span | remixes"
5921
+ },
5922
+ {
5923
+ flag: "--slug <domain>",
5924
+ summary: "0.6 shim: read ONE flow with its steps as a single-row page (`flows get <slug>` is the real read)"
5925
+ },
5926
+ {
5927
+ flag: "--include <keys>",
5928
+ summary: "With --slug only: `html` adds each step's rendered HTML"
5929
+ },
5930
+ LIMIT_FLAG,
5931
+ CURSOR_FLAG,
5932
+ ALL_FLAG,
5933
+ INPUT_FLAG
5934
+ ],
5935
+ examples: [
5936
+ "brew-cli flows list --type signup --sort emails",
5937
+ "brew-cli flows list --brand-domain brew.new --json",
5938
+ 'brew-cli flows list --semantic "developer onboarding drip"'
5939
+ ],
5940
+ run: async ({ ctx, flags }) => {
5941
+ const flows = ctx.client().flows;
5942
+ const base = await readJsonFlag(ctx, flags.input, "--input");
5943
+ const slug = flagString(flags.slug) ?? inputField(base, "slug");
5944
+ const include = flagString(flags.include) ?? inputField(base, "include");
5945
+ if (slug !== void 0) {
5946
+ const flow = await flows.get(
5947
+ slug,
5948
+ include === void 0 ? void 0 : { include }
5949
+ );
5950
+ return { data: singleRowPage(flow), human: renderFlows([flow]) };
5951
+ }
5952
+ if (include !== void 0) {
5953
+ throw includeRidesDetailRead("flows get", "--slug");
5954
+ }
5955
+ const input = mergeInput(base, {
5956
+ brand: flagString(flags.brandDomain),
5957
+ category: flagString(flags.category),
5958
+ type: flagString(flags.type),
5959
+ semantic: flagString(flags.semantic),
5960
+ sort: flagString(flags.sort),
5961
+ limit: flagInt(flags.limit, "--limit"),
5962
+ cursor: flagString(flags.cursor)
5963
+ });
5964
+ if (flags.all === true) {
5965
+ const rows = await collectAll(
5966
+ ctx,
5967
+ (cursor) => flows.list(
5968
+ asSdkInput({
5969
+ ...input,
5970
+ ...cursor === void 0 ? {} : { cursor }
5971
+ })
5972
+ )
5973
+ );
5974
+ return {
5975
+ data: { data: rows, pagination: { cursor: null, hasMore: false } },
5976
+ human: renderFlows(rows)
5977
+ };
5978
+ }
5979
+ const result = await flows.list(asSdkInput(input));
5980
+ return { data: result, human: renderFlows(result.data) };
5981
+ }
5982
+ });
5983
+ function renderFlows(rows) {
5984
+ if (rows.length === 0) {
5985
+ return "No flows found.";
5986
+ }
5987
+ return renderTable(
5988
+ rows.map((row) => ({
5989
+ slug: row.slug,
5990
+ brand: row.brand.name,
5991
+ type: row.type,
5992
+ category: row.category,
5993
+ emails: row.emailCount,
5994
+ spanDays: row.spanDays
5995
+ })),
5996
+ [
5997
+ { key: "slug", header: "SLUG" },
5998
+ { key: "brand", header: "BRAND" },
5999
+ { key: "type", header: "TYPE" },
6000
+ { key: "category", header: "CATEGORY" },
6001
+ { key: "emails", header: "EMAILS" },
6002
+ { key: "spanDays", header: "SPAN (DAYS)" }
6003
+ ]
6004
+ );
6005
+ }
6006
+
5027
6007
  // src/commands/health.ts
5028
6008
  var healthCommand = defineCommand({
5029
6009
  path: ["health"],
@@ -5150,6 +6130,35 @@ var sendsCancelCommand = defineCommand({
5150
6130
  })
5151
6131
  });
5152
6132
 
6133
+ // src/commands/sends/get.ts
6134
+ var sendsGetCommand = defineCommand({
6135
+ path: ["sends", "get"],
6136
+ summary: "Fetch one send by id \u2014 the bare row with its lifetime stats",
6137
+ sdkMethod: "sends.get",
6138
+ route: { method: "GET", path: "/v1/sends/{sendId}" },
6139
+ commandClass: "read",
6140
+ args: [{ name: "sendId", summary: "Send id to fetch", isRequired: true }],
6141
+ flags: [
6142
+ {
6143
+ flag: "--include <tokens>",
6144
+ summary: "Comma-separated expansions: events"
6145
+ }
6146
+ ],
6147
+ examples: [
6148
+ "brew-cli sends get snd_9f2kX",
6149
+ "brew-cli sends get snd_9f2kX --include events"
6150
+ ],
6151
+ run: async ({ ctx, args, flags }) => {
6152
+ const include = flagString(flags.include);
6153
+ return {
6154
+ data: await ctx.client().sends.get(
6155
+ args.sendId ?? "",
6156
+ include === void 0 ? void 0 : { include }
6157
+ )
6158
+ };
6159
+ }
6160
+ });
6161
+
5153
6162
  // src/commands/sends/pause.ts
5154
6163
  var sendsPauseCommand = defineCommand({
5155
6164
  path: ["sends", "pause"],
@@ -5168,7 +6177,7 @@ var sendsPauseCommand = defineCommand({
5168
6177
  // src/commands/sends/resume.ts
5169
6178
  var sendsResumeCommand = defineCommand({
5170
6179
  path: ["sends", "resume"],
5171
- summary: "Resume a paused gradual send (the unsent tail is re-spread)",
6180
+ summary: "Resume a paused gradual send (the unsent tail is re-spread); the send reports `running` again",
5172
6181
  sdkMethod: "sends.resume",
5173
6182
  route: { method: "POST", path: "/v1/sends/{sendId}/resume" },
5174
6183
  commandClass: "write",
@@ -5180,6 +6189,41 @@ var sendsResumeCommand = defineCommand({
5180
6189
  })
5181
6190
  });
5182
6191
 
6192
+ // src/commands/templates/get.ts
6193
+ var templatesGetCommand = defineCommand({
6194
+ path: ["templates", "get"],
6195
+ summary: "Fetch one public template: its links and the referenceEmailId to remix; --include html adds its HTML",
6196
+ sdkMethod: null,
6197
+ isRawTransport: true,
6198
+ route: { method: "GET", path: "/v1/templates/{templateId}" },
6199
+ commandClass: "read",
6200
+ args: [
6201
+ {
6202
+ name: "templateId",
6203
+ summary: "Template id: the TEMPLATE column (emailId) of `templates list`",
6204
+ isRequired: true
6205
+ }
6206
+ ],
6207
+ flags: [
6208
+ {
6209
+ flag: "--include <tokens>",
6210
+ summary: "Expansions: html (the rendered HTML; a large page arrives as a content.url download link instead)"
6211
+ }
6212
+ ],
6213
+ examples: [
6214
+ "brew-cli templates get seed-vercel-newsletter",
6215
+ "brew-cli templates get seed-vercel-newsletter --include html --json"
6216
+ ],
6217
+ run: async ({ ctx, args, flags }) => {
6218
+ const body = await rawRequest(ctx, {
6219
+ method: "GET",
6220
+ path: `/v1/templates/${encodeURIComponent(args.templateId ?? "")}`,
6221
+ query: { include: flagString(flags.include) }
6222
+ });
6223
+ return { data: body };
6224
+ }
6225
+ });
6226
+
5183
6227
  // src/commands/templates/list.ts
5184
6228
  var templatesListCommand = defineCommand({
5185
6229
  path: ["templates", "list"],
@@ -5487,6 +6531,7 @@ var ALL_COMMANDS = [
5487
6531
  configGetCommand,
5488
6532
  configSetCommand,
5489
6533
  configUnsetCommand,
6534
+ contactsListCommand,
5490
6535
  contactsSearchCommand,
5491
6536
  contactsGetCommand,
5492
6537
  contactsCountCommand,
@@ -5498,10 +6543,12 @@ var ALL_COMMANDS = [
5498
6543
  contactsValidateCommand,
5499
6544
  contactsImportCsvCommand,
5500
6545
  fieldsListCommand,
6546
+ fieldsGetCommand,
5501
6547
  fieldsCreateCommand,
5502
6548
  fieldsDeleteCommand,
5503
6549
  emailsListCommand,
5504
6550
  emailsGroupsListCommand,
6551
+ emailsGroupsGetCommand,
5505
6552
  emailsGroupsCreateCommand,
5506
6553
  emailsGroupsUpdateCommand,
5507
6554
  emailsGroupsDeleteCommand,
@@ -5515,10 +6562,15 @@ var ALL_COMMANDS = [
5515
6562
  emailsDeleteCommand,
5516
6563
  emailsExportCommand,
5517
6564
  emailsAuditCommand,
6565
+ emailsGetAuditCommand,
5518
6566
  emailsPreviewClientsCommand,
6567
+ emailsGetClientPreviewCommand,
5519
6568
  emailsCreateInboxPlacementTestCommand,
5520
6569
  emailsGetInboxPlacementResultsCommand,
6570
+ emailsInboxPlacementTestsGetCommand,
5521
6571
  emailsSendCommand,
6572
+ sendsListCommand,
6573
+ sendsGetCommand,
5522
6574
  sendsCancelCommand,
5523
6575
  sendsPauseCommand,
5524
6576
  sendsResumeCommand,
@@ -5540,18 +6592,28 @@ var ALL_COMMANDS = [
5540
6592
  automationsTestCommand,
5541
6593
  automationsRunCommand,
5542
6594
  automationsTriggersListCommand,
6595
+ automationsTriggersGetCommand,
5543
6596
  automationsTriggersReadyCommand,
5544
6597
  automationsTriggersContractGetCommand,
5545
6598
  automationsTriggersContractPutCommand,
5546
6599
  automationsTriggersContractValidateCommand,
5547
6600
  contractsInferCommand,
6601
+ dataRunCommand,
5548
6602
  automationsTriggersCreateCommand,
5549
6603
  automationsTriggersUpdateCommand,
5550
6604
  automationsTriggersDeleteCommand,
5551
6605
  automationsTriggersFireCommand,
5552
6606
  automationsRunsListCommand,
6607
+ automationsRunsGetCommand,
6608
+ automationsRunsCancelCommand,
5553
6609
  automationsAudienceRunsListCommand,
6610
+ automationsAudienceRunsGetCommand,
6611
+ automationsAudienceRunsPauseCommand,
6612
+ automationsAudienceRunsResumeCommand,
6613
+ automationsAudienceRunsCancelCommand,
5554
6614
  automationsAudienceRunsControlCommand,
6615
+ automationsTriggerInstancesListCommand,
6616
+ automationsTriggerInstancesGetCommand,
5555
6617
  analyticsOverviewCommand,
5556
6618
  analyticsCampaignsCommand,
5557
6619
  analyticsAutomationsCommand,
@@ -5581,6 +6643,9 @@ var ALL_COMMANDS = [
5581
6643
  contentHtmlToPngCommand,
5582
6644
  contentAddImageCommand,
5583
6645
  templatesListCommand,
6646
+ templatesGetCommand,
6647
+ flowsListCommand,
6648
+ flowsGetCommand,
5584
6649
  integrationsListCommand,
5585
6650
  chatsGetCommand,
5586
6651
  healthCommand,
@@ -5593,7 +6658,8 @@ var ALL_COMMANDS = [
5593
6658
 
5594
6659
  // src/cli.ts
5595
6660
  var GROUP_SUMMARIES = {
5596
- analytics: "Read campaign, automation, send, and event analytics",
6661
+ analytics: "Reports: overview, events, and automation analytics",
6662
+ "audience-runs": "Manual-audience launches: read, pause, resume, cancel",
5597
6663
  "api-keys": "Manage organization API keys",
5598
6664
  audiences: "Manage audience segments",
5599
6665
  automations: "Manage automation graphs, triggers, and runs",
@@ -5607,15 +6673,17 @@ var GROUP_SUMMARIES = {
5607
6673
  domains: "Manage sending domains",
5608
6674
  emails: "Manage email designs and send campaigns",
5609
6675
  fields: "Manage custom contact fields",
6676
+ flows: "Browse public email flows (real multi-step sequences by brand)",
5610
6677
  groups: "Manage email folders (groups)",
5611
6678
  integrations: "Read the connected-integration catalog",
5612
- sends: "Control in-flight or scheduled sends",
6679
+ "inbox-placement-tests": "Inbox placement (seed) test results",
6680
+ sends: "Read sends, and control one in flight or scheduled",
5613
6681
  templates: "Browse the template gallery",
5614
6682
  contract: "Stored payload contracts (get, put, validate)",
5615
6683
  contracts: "Payload-contract helpers",
5616
6684
  triggers: "Manage trigger events",
5617
- runs: "Automation run history",
5618
- "trigger-instances": "Fired trigger instances"
6685
+ runs: "Automation run history, and cancel one in-flight run",
6686
+ "trigger-instances": "Fired trigger instances (the inbound-fire audit log)"
5619
6687
  };
5620
6688
  var AGENT_HELP_FOOTER = `
5621
6689
  Environment: