@getmagical/cli 0.4.0 → 0.6.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/index.js CHANGED
@@ -6954,6 +6954,130 @@ function renderKeyValueBlock(entries) {
6954
6954
  function renderSection(title, bodyLines) {
6955
6955
  return [formatHeading(title), "", ...bodyLines].join("\n");
6956
6956
  }
6957
+ function getRecordArray(value) {
6958
+ return Array.isArray(value) && value.every(isRecord) ? value : null;
6959
+ }
6960
+ function getRecordScalar(record, key) {
6961
+ const value = record[key];
6962
+ return isPrimitiveLike(value) ? formatScalar(value) : EMPTY_VALUE;
6963
+ }
6964
+ function getMergeChangeExplanation(change) {
6965
+ const explanation = change["statusDescription"] ?? change["conflictDescription"];
6966
+ return typeof explanation === "string" ? formatScalar(explanation) : EMPTY_VALUE;
6967
+ }
6968
+ function formatMergeChanges(changes, includeStatus) {
6969
+ return formatTable({
6970
+ columns: includeStatus ? ["Change", "Status", "Discardable", "Explanation", "Change ID"] : ["Change", "Explanation", "Change ID"],
6971
+ rows: changes.map((change) => {
6972
+ const cells = [getRecordScalar(change, "label")];
6973
+ if (includeStatus) {
6974
+ cells.push(
6975
+ getRecordScalar(change, "status"),
6976
+ change["discardable"] === true ? "yes" : "no"
6977
+ );
6978
+ }
6979
+ cells.push(
6980
+ getMergeChangeExplanation(change),
6981
+ getRecordScalar(change, "id")
6982
+ );
6983
+ return cells;
6984
+ })
6985
+ });
6986
+ }
6987
+ function renderMergePreviewSection(title, preview, changes) {
6988
+ return renderSection(title, [
6989
+ renderKeyValueBlock([
6990
+ ["Base version", getRecordScalar(preview, "baseVersionId")],
6991
+ ["Source version", getRecordScalar(preview, "sourceVersionId")],
6992
+ ["Target version", getRecordScalar(preview, "targetVersionId")]
6993
+ ]),
6994
+ "",
6995
+ changes.length > 0 ? formatMergeChanges(changes, true) : "No changes to merge."
6996
+ ]);
6997
+ }
6998
+ function renderDiscardHint(preview, changes) {
6999
+ const hasDiscardable = changes.some(
7000
+ (change) => change["discardable"] === true
7001
+ );
7002
+ if (!hasDiscardable) {
7003
+ return null;
7004
+ }
7005
+ return renderSection("Resolve conflicts", [
7006
+ "Discards revert a change on the branch so main keeps its value; conflicts must be discarded or edited to match main before merging.",
7007
+ formatCommandSnippet(
7008
+ `mgcl --branch-id <branch-id> automations branches discard-changes --automation-id <automation-id> --change-ids <change-id,...> --source-version-id ${getRecordScalar(preview, "sourceVersionId")} --target-version-id ${getRecordScalar(preview, "targetVersionId")}`
7009
+ )
7010
+ ]);
7011
+ }
7012
+ function formatAutomationBranchMergePreviewOutput(value) {
7013
+ const changes = isRecord(value) ? getRecordArray(value["changes"]) : null;
7014
+ if (!isRecord(value) || !changes) {
7015
+ return formatHumanReadableOutput(value);
7016
+ }
7017
+ const hint = renderDiscardHint(value, changes);
7018
+ return [
7019
+ renderMergePreviewSection("Merge Preview", value, changes),
7020
+ ...hint ? [hint] : []
7021
+ ].join("\n\n");
7022
+ }
7023
+ function formatAutomationBranchDiscardOutput(value) {
7024
+ const preview = isRecord(value) ? value["preview"] : null;
7025
+ const changes = isRecord(preview) ? getRecordArray(preview["changes"]) : null;
7026
+ if (!isRecord(value) || !isRecord(preview) || !changes) {
7027
+ return formatHumanReadableOutput(value);
7028
+ }
7029
+ const discardedChangeIds = Array.isArray(value["discardedChangeIds"]) ? value["discardedChangeIds"].map(formatScalar).join(", ") : EMPTY_VALUE;
7030
+ return [
7031
+ renderSection("Branch Discard", [
7032
+ renderKeyValueBlock([
7033
+ ["Branch ID", getRecordScalar(value, "branchId")],
7034
+ ["Previous head", getRecordScalar(value, "previousHeadVersionId")],
7035
+ ["New head", getRecordScalar(value, "headVersionId")],
7036
+ ["Discarded changes", discardedChangeIds]
7037
+ ])
7038
+ ]),
7039
+ renderMergePreviewSection("Refreshed Merge Preview", preview, changes)
7040
+ ].join("\n\n");
7041
+ }
7042
+ function formatAutomationBranchMergeOutput(value) {
7043
+ if (!isRecord(value) || value["status"] !== "conflict") {
7044
+ return formatHumanReadableOutput(value);
7045
+ }
7046
+ const { preview } = value;
7047
+ const conflicts = getRecordArray(value["conflicts"]);
7048
+ if (!isRecord(preview) || !conflicts || conflicts.length === 0) {
7049
+ return formatHumanReadableOutput(value);
7050
+ }
7051
+ const changes = getRecordArray(preview["changes"]);
7052
+ if (!changes) {
7053
+ return formatHumanReadableOutput(value);
7054
+ }
7055
+ const hint = renderDiscardHint(preview, changes);
7056
+ return [
7057
+ renderSection("Branch Merge", [
7058
+ renderKeyValueBlock([
7059
+ ["Status", getRecordScalar(value, "status")],
7060
+ ["Automation ID", getRecordScalar(value, "automationId")],
7061
+ ["Branch ID", getRecordScalar(value, "branchId")],
7062
+ [
7063
+ "Source branch deleted",
7064
+ getRecordScalar(value, "sourceBranchDeleted")
7065
+ ]
7066
+ ])
7067
+ ]),
7068
+ renderSection("Merge Conflicts", [formatMergeChanges(conflicts, false)]),
7069
+ renderMergePreviewSection("Merge Preview", preview, changes),
7070
+ ...hint ? [hint] : []
7071
+ ].join("\n\n");
7072
+ }
7073
+ var BRANCH_MERGE_FORMATTERS = /* @__PURE__ */ new Map([
7074
+ ["DiscardAutomationBranchChanges", formatAutomationBranchDiscardOutput],
7075
+ ["MergeAutomationBranch", formatAutomationBranchMergeOutput],
7076
+ ["PreviewAutomationBranchMerge", formatAutomationBranchMergePreviewOutput]
7077
+ ]);
7078
+ function getBranchMergeFormatter(operationName) {
7079
+ return BRANCH_MERGE_FORMATTERS.get(operationName);
7080
+ }
6957
7081
  var MagicalHelp = class extends Help {
6958
7082
  outputHasColors = process.stdout.isTTY;
6959
7083
  constructor() {
@@ -7073,12 +7197,14 @@ function formatOutputModesNote() {
7073
7197
 
7074
7198
  // src/errors.ts
7075
7199
  var CliError = class extends Error {
7200
+ apiErrorCode;
7076
7201
  retryAfterMs;
7077
7202
  retryable;
7078
7203
  statusCode;
7079
7204
  constructor(message, options) {
7080
7205
  super(message, options);
7081
7206
  this.name = "CliError";
7207
+ this.apiErrorCode = options?.apiErrorCode;
7082
7208
  this.retryAfterMs = options?.retryAfterMs;
7083
7209
  this.retryable = options?.retryable;
7084
7210
  this.statusCode = options?.statusCode;
@@ -7095,7 +7221,7 @@ function getErrorMessage(error) {
7095
7221
  import { randomUUID as randomUUID4 } from "node:crypto";
7096
7222
  import { readFile as readFile6 } from "node:fs/promises";
7097
7223
  import path8 from "node:path";
7098
- import { setTimeout as sleep } from "node:timers/promises";
7224
+ import { setTimeout as sleep2 } from "node:timers/promises";
7099
7225
 
7100
7226
  // ../common/dist/src/stdlib/json.util.js
7101
7227
  var import_ts_essentials = __toESM(require_dist(), 1);
@@ -7767,6 +7893,8 @@ function safeJsonParseWithoutLogging(json) {
7767
7893
  // ../common/dist/src/constants/automation.js
7768
7894
  var AUTOMATION_BRANCH_NAME_MAX_LENGTH = 100;
7769
7895
  var AUTOMATION_BRANCH_NAME_MAX_LENGTH_MESSAGE = `Branch name must be ${AUTOMATION_BRANCH_NAME_MAX_LENGTH} characters or fewer.`;
7896
+ var AUTOMATION_BRANCH_DISCARD_MAX_CHANGE_IDS = 50;
7897
+ var AUTOMATION_BRANCH_CHANGE_ID_MAX_LENGTH = 256;
7770
7898
 
7771
7899
  // ../common/dist/src/constants/tool-declarations.js
7772
7900
  import { z as z15 } from "zod";
@@ -12365,6 +12493,27 @@ var clickComparisonSchema = z9.union([
12365
12493
  [COMMON_PARAMETERS_KEY]: DEFAULT_COMMON_PARAMETERS
12366
12494
  })
12367
12495
  ]);
12496
+ var holdClickMarkerInputSchema = z9.object({
12497
+ marker: markerSchema("The marker of the element to press and hold.")
12498
+ });
12499
+ var holdClickCoordinateInputSchema = z9.object({
12500
+ coordinates: coordinateSchema({
12501
+ xDescription: "The x coordinate of the element to press and hold.",
12502
+ yDescription: "The y coordinate of the element to press and hold."
12503
+ })
12504
+ });
12505
+ var holdClickComparisonSchema = z9.union([
12506
+ holdClickMarkerInputSchema.extend({
12507
+ [COMMON_PARAMETERS_KEY]: DEFAULT_COMMON_PARAMETERS
12508
+ }),
12509
+ holdClickCoordinateInputSchema.extend({
12510
+ [COMMON_PARAMETERS_KEY]: DEFAULT_COMMON_PARAMETERS
12511
+ })
12512
+ ]);
12513
+ var releaseClickInputSchema = z9.object({});
12514
+ var releaseClickComparisonSchema = releaseClickInputSchema.extend({
12515
+ [COMMON_PARAMETERS_KEY]: DEFAULT_COMMON_PARAMETERS
12516
+ });
12368
12517
  var moveMarkerInputSchema = z9.object({
12369
12518
  marker: markerSchema("The marker to move the mouse to")
12370
12519
  });
@@ -12735,7 +12884,8 @@ var PressEvent;
12735
12884
  Response2.create = create;
12736
12885
  })(Response = PressEvent2.Response || (PressEvent2.Response = {}));
12737
12886
  })(PressEvent || (PressEvent = {}));
12738
- var Keys = [
12887
+ var ModifierKeys = ["Alt", "Control", "Meta", "Shift"];
12888
+ var PhysicalKeys = [
12739
12889
  // Modifiers
12740
12890
  "Alt",
12741
12891
  "CapsLock",
@@ -12837,16 +12987,16 @@ var Keys = [
12837
12987
  "y",
12838
12988
  "Z",
12839
12989
  "z",
12840
- "0",
12841
- "1",
12842
- "2",
12843
- "3",
12844
- "4",
12845
- "5",
12846
- "6",
12847
- "7",
12848
- "8",
12849
- "9",
12990
+ "Digit0",
12991
+ "Digit1",
12992
+ "Digit2",
12993
+ "Digit3",
12994
+ "Digit4",
12995
+ "Digit5",
12996
+ "Digit6",
12997
+ "Digit7",
12998
+ "Digit8",
12999
+ "Digit9",
12850
13000
  // Punctuation
12851
13001
  "Minus",
12852
13002
  "Equal",
@@ -12863,8 +13013,106 @@ var Keys = [
12863
13013
  "Insert",
12864
13014
  "PrintScreen"
12865
13015
  ];
13016
+ var KeyAliases = [
13017
+ "0",
13018
+ "1",
13019
+ "2",
13020
+ "3",
13021
+ "4",
13022
+ "5",
13023
+ "6",
13024
+ "7",
13025
+ "8",
13026
+ "9",
13027
+ "`",
13028
+ "~",
13029
+ "-",
13030
+ "_",
13031
+ "=",
13032
+ "+",
13033
+ "[",
13034
+ "{",
13035
+ "]",
13036
+ "}",
13037
+ "\\",
13038
+ "|",
13039
+ ";",
13040
+ ":",
13041
+ "'",
13042
+ '"',
13043
+ ",",
13044
+ "<",
13045
+ ".",
13046
+ ">",
13047
+ "/",
13048
+ "?",
13049
+ "!",
13050
+ "@",
13051
+ "#",
13052
+ "$",
13053
+ "%",
13054
+ "^",
13055
+ "&",
13056
+ "*",
13057
+ "(",
13058
+ ")"
13059
+ ];
13060
+ var Keys = [...PhysicalKeys, ...KeyAliases];
13061
+ var KeyAliasMappings = [
13062
+ ["0", ["Digit0"]],
13063
+ ["1", ["Digit1"]],
13064
+ ["2", ["Digit2"]],
13065
+ ["3", ["Digit3"]],
13066
+ ["4", ["Digit4"]],
13067
+ ["5", ["Digit5"]],
13068
+ ["6", ["Digit6"]],
13069
+ ["7", ["Digit7"]],
13070
+ ["8", ["Digit8"]],
13071
+ ["9", ["Digit9"]],
13072
+ ["`", ["Backquote"]],
13073
+ ["~", ["Shift", "Backquote"]],
13074
+ ["-", ["Minus"]],
13075
+ ["_", ["Shift", "Minus"]],
13076
+ ["=", ["Equal"]],
13077
+ ["+", ["Shift", "Equal"]],
13078
+ ["[", ["BracketLeft"]],
13079
+ ["{", ["Shift", "BracketLeft"]],
13080
+ ["]", ["BracketRight"]],
13081
+ ["}", ["Shift", "BracketRight"]],
13082
+ ["\\", ["Backslash"]],
13083
+ ["|", ["Shift", "Backslash"]],
13084
+ [";", ["Semicolon"]],
13085
+ [":", ["Shift", "Semicolon"]],
13086
+ ["'", ["Quote"]],
13087
+ ['"', ["Shift", "Quote"]],
13088
+ [",", ["Comma"]],
13089
+ ["<", ["Shift", "Comma"]],
13090
+ [".", ["Period"]],
13091
+ [">", ["Shift", "Period"]],
13092
+ ["/", ["Slash"]],
13093
+ ["?", ["Shift", "Slash"]],
13094
+ ["!", ["Shift", "Digit1"]],
13095
+ ["@", ["Shift", "Digit2"]],
13096
+ ["#", ["Shift", "Digit3"]],
13097
+ ["$", ["Shift", "Digit4"]],
13098
+ ["%", ["Shift", "Digit5"]],
13099
+ ["^", ["Shift", "Digit6"]],
13100
+ ["&", ["Shift", "Digit7"]],
13101
+ ["*", ["Shift", "Digit8"]],
13102
+ ["(", ["Shift", "Digit9"]],
13103
+ [")", ["Shift", "Digit0"]]
13104
+ ];
13105
+ var KeyMappings = [
13106
+ ...PhysicalKeys.map((key) => [
13107
+ key,
13108
+ [key]
13109
+ ]),
13110
+ ...KeyAliasMappings
13111
+ ];
13112
+ var KeyMapping = new Map(KeyMappings);
13113
+ var ModifierKeySet = new Set(ModifierKeys);
12866
13114
  var pressDataSchema = z12.object({
12867
- keys: z12.array(z12.enum(Keys))
13115
+ keys: z12.array(z12.enum(Keys)).describe("Keys in one simultaneous keyboard chord. Use type for a sequence of characters. US keyboard characters and physical key codes such as Digit4 are supported.")
12868
13116
  });
12869
13117
 
12870
13118
  // ../common/dist/src/models/websocket/actions/report-stop.js
@@ -13190,6 +13438,16 @@ var baseToolDeclarations = {
13190
13438
  description: 'ONLY USE FOR CLICKING WITHOUT ENTERING TEXT. This tool clicks on an element but DOES NOT allow entering text. Use for buttons, links, checkboxes, dropdown toggles, tabs, and other clickable elements. NEVER use this when you need to enter text into a field - for text entry, use "clickFill" instead, this tool automatically moves the cursor to the element, no need to use the move tool first.',
13191
13439
  parameters: clickComparisonSchema
13192
13440
  },
13441
+ holdClick: {
13442
+ id: "holdClick",
13443
+ description: "Press and hold the left mouse button on an element that reveals content only while pressed. The hold remains active during non-browser work and is released automatically before the next browser interaction.",
13444
+ parameters: holdClickComparisonSchema
13445
+ },
13446
+ releaseClick: {
13447
+ id: "releaseClick",
13448
+ description: "Release the left mouse button after holdClick. This is safe to call again when the mouse is already released.",
13449
+ parameters: releaseClickComparisonSchema
13450
+ },
13193
13451
  multiClick: {
13194
13452
  id: "multiClick",
13195
13453
  description: "This object is deprecated, only adding here to satisfy the DB type check",
@@ -13798,12 +14056,109 @@ var apiAgentEmbeddedFilesSchema = z16.array(apiAgentEmbeddedFileSchema).superRef
13798
14056
  // ../common/dist/src/zod-schemas/api-agent-request-file-encoding.schema.js
13799
14057
  import { z as z17 } from "zod";
13800
14058
  var API_REQUEST_FILE_PATH_PATTERN = /^[A-Za-z_$][\w$-]*(?:\.[A-Za-z_$][\w$-]*)*$/u;
14059
+ var API_REQUEST_BASE64_FILE_HELPER_PATTERN = /^\s*\{\{\s*base64File\s+(?<sourceInput>[^{}\s]+)\s*\}\}\s*$/u;
14060
+ var API_REQUEST_BASE64_FILE_HELPER_USAGE_PATTERN = /\{\{\s*base64File\b/u;
14061
+ var API_REQUEST_BASE64_FILE_HELPER_EXAMPLE = "{{base64File fileInput}}";
13801
14062
  function parseApiRequestFilePath(path9) {
13802
14063
  if (!API_REQUEST_FILE_PATH_PATTERN.test(path9)) {
13803
14064
  return void 0;
13804
14065
  }
13805
14066
  return path9.split(".");
13806
14067
  }
14068
+ function inspectApiRequestBase64FileHelperValue({ path: path9, value }) {
14069
+ const match = API_REQUEST_BASE64_FILE_HELPER_PATTERN.exec(value);
14070
+ if (match === null) {
14071
+ return API_REQUEST_BASE64_FILE_HELPER_USAGE_PATTERN.test(value) ? {
14072
+ helpers: [],
14073
+ issues: [
14074
+ {
14075
+ message: `Use ${API_REQUEST_BASE64_FILE_HELPER_EXAMPLE} as the entire JSON field value.`,
14076
+ path: path9
14077
+ }
14078
+ ]
14079
+ } : { helpers: [], issues: [] };
14080
+ }
14081
+ const { sourceInput } = match.groups ?? {};
14082
+ if (sourceInput === void 0 || parseApiRequestFilePath(sourceInput) === void 0) {
14083
+ return {
14084
+ helpers: [],
14085
+ issues: [
14086
+ {
14087
+ message: "Base64 file helper input must use an object property path.",
14088
+ path: path9
14089
+ }
14090
+ ]
14091
+ };
14092
+ }
14093
+ return {
14094
+ helpers: [{ destinationPath: path9, sourceInput }],
14095
+ issues: []
14096
+ };
14097
+ }
14098
+ function inspectApiRequestBase64FileHelpers(body, path9 = []) {
14099
+ if (typeof body === "string") {
14100
+ return inspectApiRequestBase64FileHelperValue({ path: path9, value: body });
14101
+ }
14102
+ if (Array.isArray(body)) {
14103
+ return body.reduce((inspection, value, index) => {
14104
+ const nestedInspection = inspectApiRequestBase64FileHelpers(value, [
14105
+ ...path9,
14106
+ index
14107
+ ]);
14108
+ return {
14109
+ helpers: [...inspection.helpers, ...nestedInspection.helpers],
14110
+ issues: [...inspection.issues, ...nestedInspection.issues]
14111
+ };
14112
+ }, { helpers: [], issues: [] });
14113
+ }
14114
+ if (body === null || typeof body !== "object") {
14115
+ return { helpers: [], issues: [] };
14116
+ }
14117
+ return Object.entries(body).reduce((inspection, [key, value]) => {
14118
+ const nestedInspection = inspectApiRequestBase64FileHelpers(value, [
14119
+ ...path9,
14120
+ key
14121
+ ]);
14122
+ return {
14123
+ helpers: [...inspection.helpers, ...nestedInspection.helpers],
14124
+ issues: [...inspection.issues, ...nestedInspection.issues]
14125
+ };
14126
+ }, { helpers: [], issues: [] });
14127
+ }
14128
+ function validateApiRequestBase64FileHelpers({ body, bodyType, context, supportsRequestBody }) {
14129
+ const inspection = inspectApiRequestBase64FileHelpers(body);
14130
+ for (const issue of inspection.issues) {
14131
+ context.addIssue({
14132
+ code: z17.ZodIssueCode.custom,
14133
+ message: issue.message,
14134
+ path: ["body", ...issue.path]
14135
+ });
14136
+ }
14137
+ if (inspection.helpers.length === 0) {
14138
+ return;
14139
+ }
14140
+ if (!supportsRequestBody) {
14141
+ context.addIssue({
14142
+ code: z17.ZodIssueCode.custom,
14143
+ message: "Base64 file helpers are not supported for this method",
14144
+ path: ["body"]
14145
+ });
14146
+ }
14147
+ if ((bodyType ?? "json") !== "json") {
14148
+ context.addIssue({
14149
+ code: z17.ZodIssueCode.custom,
14150
+ message: "Base64 file helpers are only supported for JSON bodies",
14151
+ path: ["body"]
14152
+ });
14153
+ }
14154
+ if (body === null || typeof body !== "object" || Array.isArray(body)) {
14155
+ context.addIssue({
14156
+ code: z17.ZodIssueCode.custom,
14157
+ message: "Base64 file helpers require a JSON object body",
14158
+ path: ["body"]
14159
+ });
14160
+ }
14161
+ }
13807
14162
  var apiAgentRequestFileEncodingSchema = z17.object({
13808
14163
  sourceInput: z17.string().trim().min(1, "File input is required.").refine((path9) => parseApiRequestFilePath(path9) !== void 0, {
13809
14164
  message: "File input must use an object property path."
@@ -13978,6 +14333,13 @@ var apiToolSchema = z20.object({
13978
14333
  }).refine((data) => !data.requestFileEncodings?.length || data.body !== null && typeof data.body === "object" && !Array.isArray(data.body), {
13979
14334
  message: "Request file encoding requires a JSON object body",
13980
14335
  path: ["body"]
14336
+ }).superRefine((data, context) => {
14337
+ validateApiRequestBase64FileHelpers({
14338
+ body: data.body,
14339
+ bodyType: data.bodyType,
14340
+ context,
14341
+ supportsRequestBody: methodsWithBody.has(data.type)
14342
+ });
13981
14343
  }).refine((data) => isValidApiMultipartFormDataBody({
13982
14344
  bodyType: data.bodyType,
13983
14345
  body: data.body
@@ -14385,6 +14747,13 @@ var apiAgentConfigSchema = baseAgentConfigFieldsSchema.safeExtend({
14385
14747
  }).refine((data) => !data.requestFileEncodings?.length || data.body !== null && typeof data.body === "object" && !Array.isArray(data.body), {
14386
14748
  message: "Request file encoding requires a JSON object body",
14387
14749
  path: ["body"]
14750
+ }).superRefine((data, context) => {
14751
+ validateApiRequestBase64FileHelpers({
14752
+ body: data.body,
14753
+ bodyType: data.bodyType,
14754
+ context,
14755
+ supportsRequestBody: METHODS_WITH_BODY.has(data.method)
14756
+ });
14388
14757
  }).refine((data) => isValidApiMultipartFormDataBody({
14389
14758
  bodyType: data.bodyType,
14390
14759
  body: data.body
@@ -15161,6 +15530,7 @@ ${agentLimitationsSelection}
15161
15530
  operationName: "GetAgentVersion",
15162
15531
  kind: "query",
15163
15532
  inputSchema: z27.object({
15533
+ draftAutomationId: z27.string().min(1),
15164
15534
  agentId: z27.string().min(1),
15165
15535
  versionId: z27.string().min(1)
15166
15536
  }),
@@ -15170,6 +15540,12 @@ ${agentLimitationsSelection}
15170
15540
  description: "Fetch one saved version for an agent.",
15171
15541
  resultKey: "agentVersion",
15172
15542
  options: [
15543
+ stringOption({
15544
+ inputKey: "draftAutomationId",
15545
+ flagName: "automation-id",
15546
+ description: "Automation ID whose main draft lineage scopes the agent's history.",
15547
+ required: true
15548
+ }),
15173
15549
  stringOption({
15174
15550
  inputKey: "agentId",
15175
15551
  flagName: "agent-id",
@@ -15186,8 +15562,12 @@ ${agentLimitationsSelection}
15186
15562
  },
15187
15563
  mcp: { fileName: "agentVersion.graphql" },
15188
15564
  document: `# Query to fetch a specific saved version for an agent
15189
- query GetAgentVersion($agentId: ID!, $versionId: ID!) {
15190
- agentVersion(agentId: $agentId, versionId: $versionId) {
15565
+ query GetAgentVersion($draftAutomationId: ID!, $agentId: ID!, $versionId: ID!) {
15566
+ agentVersion(
15567
+ draftAutomationId: $draftAutomationId
15568
+ agentId: $agentId
15569
+ versionId: $versionId
15570
+ ) {
15191
15571
  id
15192
15572
  agentId
15193
15573
  sequence
@@ -15227,6 +15607,7 @@ ${agentLimitationsSelection}
15227
15607
  operationName: "GetAgentVersions",
15228
15608
  kind: "query",
15229
15609
  inputSchema: z27.object({
15610
+ draftAutomationId: z27.string().min(1),
15230
15611
  agentId: z27.string().min(1)
15231
15612
  }),
15232
15613
  cli: {
@@ -15235,6 +15616,12 @@ ${agentLimitationsSelection}
15235
15616
  description: "Fetch version history for an agent.",
15236
15617
  resultKey: "agentVersions",
15237
15618
  options: [
15619
+ stringOption({
15620
+ inputKey: "draftAutomationId",
15621
+ flagName: "automation-id",
15622
+ description: "Automation ID whose main draft lineage scopes the agent's history.",
15623
+ required: true
15624
+ }),
15238
15625
  stringOption({
15239
15626
  inputKey: "agentId",
15240
15627
  flagName: "agent-id",
@@ -15245,8 +15632,8 @@ ${agentLimitationsSelection}
15245
15632
  },
15246
15633
  mcp: { fileName: "agentVersions.graphql" },
15247
15634
  document: `# Query to fetch version history metadata for an agent
15248
- query GetAgentVersions($agentId: ID!) {
15249
- agentVersions(agentId: $agentId) {
15635
+ query GetAgentVersions($draftAutomationId: ID!, $agentId: ID!) {
15636
+ agentVersions(draftAutomationId: $draftAutomationId, agentId: $agentId) {
15250
15637
  id
15251
15638
  sequence
15252
15639
  name
@@ -15262,6 +15649,7 @@ query GetAgentVersions($agentId: ID!) {
15262
15649
  operationName: "DiffAgentVersion",
15263
15650
  kind: "query",
15264
15651
  inputSchema: z27.object({
15652
+ draftAutomationId: z27.string().min(1),
15265
15653
  agentId: z27.string().min(1),
15266
15654
  versionId: z27.string().min(1),
15267
15655
  compareVersionId: z27.string().min(1).optional()
@@ -15269,9 +15657,15 @@ query GetAgentVersions($agentId: ID!) {
15269
15657
  cli: {
15270
15658
  name: "diff-agent-version",
15271
15659
  path: ["agents", "versions", "diff"],
15272
- description: "Diff one agent version against another version or the current latest version.",
15660
+ description: "Diff one agent version against another version or the automation's current draft version.",
15273
15661
  resultKey: "agentVersionDiff",
15274
15662
  options: [
15663
+ stringOption({
15664
+ inputKey: "draftAutomationId",
15665
+ flagName: "automation-id",
15666
+ description: "Automation ID whose main draft lineage scopes the agent's history.",
15667
+ required: true
15668
+ }),
15275
15669
  stringOption({
15276
15670
  inputKey: "agentId",
15277
15671
  flagName: "agent-id",
@@ -15287,18 +15681,20 @@ query GetAgentVersions($agentId: ID!) {
15287
15681
  stringOption({
15288
15682
  inputKey: "compareVersionId",
15289
15683
  flagName: "compare-version-id",
15290
- description: "Optional target version ID. Defaults to the current latest version."
15684
+ description: "Optional target version ID. Defaults to the automation's current draft version."
15291
15685
  })
15292
15686
  ]
15293
15687
  },
15294
15688
  mcp: { fileName: "agentVersionDiff.graphql" },
15295
- document: `# Query to diff one agent version against another or the current latest version
15689
+ document: `# Query to diff one agent version against another or the automation's current draft version
15296
15690
  query DiffAgentVersion(
15691
+ $draftAutomationId: ID!
15297
15692
  $agentId: ID!
15298
15693
  $versionId: ID!
15299
15694
  $compareVersionId: ID
15300
15695
  ) {
15301
15696
  agentVersionDiff(
15697
+ draftAutomationId: $draftAutomationId
15302
15698
  agentId: $agentId
15303
15699
  versionId: $versionId
15304
15700
  compareVersionId: $compareVersionId
@@ -16175,7 +16571,7 @@ query GetAutomationBranch($automationId: ID!, $branchId: ID!) {
16175
16571
  branchContext: "required",
16176
16572
  name: "merge-automation-branch",
16177
16573
  path: ["automations", "branches", "merge"],
16178
- description: "Preview and merge a branch into main when every change is conflict-free. Exits nonzero when conflicts block the merge.",
16574
+ description: "Preview and merge a branch into main when every change is conflict-free. Exits nonzero when conflicts block the merge; use `automations branches discard-changes` to resolve them.",
16179
16575
  resultKey: "mergeAutomationBranch",
16180
16576
  options: [
16181
16577
  stringOption({
@@ -16200,16 +16596,36 @@ mutation MergeAutomationBranch($automationId: ID!, $branchId: ID!) {
16200
16596
  targetVersionId
16201
16597
  changes {
16202
16598
  id
16599
+ kind
16203
16600
  group
16204
- label
16205
16601
  status
16602
+ label
16603
+ discardable
16604
+ agentId
16605
+ agentName
16606
+ field
16607
+ configKey
16608
+ fromAgentId
16609
+ toAgentId
16610
+ conflictDescription
16611
+ statusDescription
16206
16612
  }
16207
16613
  }
16208
16614
  conflicts {
16209
16615
  id
16616
+ kind
16210
16617
  group
16211
- label
16212
16618
  status
16619
+ label
16620
+ discardable
16621
+ agentId
16622
+ agentName
16623
+ field
16624
+ configKey
16625
+ fromAgentId
16626
+ toAgentId
16627
+ conflictDescription
16628
+ statusDescription
16213
16629
  }
16214
16630
  applyResult {
16215
16631
  draftVersionId
@@ -16218,6 +16634,150 @@ mutation MergeAutomationBranch($automationId: ID!, $branchId: ID!) {
16218
16634
  wasRebased
16219
16635
  }
16220
16636
  }
16637
+ }`
16638
+ }),
16639
+ createOperationSpec({
16640
+ operationName: "PreviewAutomationBranchMerge",
16641
+ kind: "query",
16642
+ inputSchema: z27.object({
16643
+ automationId: z27.uuid("--automation-id must be a UUID."),
16644
+ branchId: z27.uuid("--branch-id must be a UUID.")
16645
+ }),
16646
+ cli: {
16647
+ branchContext: "required",
16648
+ name: "preview-automation-branch-merge",
16649
+ path: ["automations", "branches", "merge-preview"],
16650
+ description: "Explain how a branch would merge into main: one change per agent field with its status and, for conflicts, why it conflicts. Writes nothing.",
16651
+ resultKey: "automationBranchMergePreview",
16652
+ options: [
16653
+ stringOption({
16654
+ inputKey: "automationId",
16655
+ flagName: "automation-id",
16656
+ description: "Automation ID.",
16657
+ required: true
16658
+ })
16659
+ ]
16660
+ },
16661
+ mcp: { fileName: "automationBranchMergePreview.graphql" },
16662
+ document: `# Explain how a branch would merge into main without writing anything.
16663
+ query PreviewAutomationBranchMerge($automationId: ID!, $branchId: ID!) {
16664
+ automationBranchMergePreview(automationId: $automationId, branchId: $branchId) {
16665
+ baseVersionId
16666
+ sourceVersionId
16667
+ targetVersionId
16668
+ changes {
16669
+ id
16670
+ kind
16671
+ group
16672
+ status
16673
+ label
16674
+ discardable
16675
+ agentId
16676
+ agentName
16677
+ field
16678
+ configKey
16679
+ fromAgentId
16680
+ toAgentId
16681
+ conflictDescription
16682
+ statusDescription
16683
+ }
16684
+ }
16685
+ }`
16686
+ }),
16687
+ createOperationSpec({
16688
+ operationName: "DiscardAutomationBranchChanges",
16689
+ kind: "mutation",
16690
+ inputSchema: z27.object({
16691
+ automationId: z27.uuid("--automation-id must be a UUID."),
16692
+ branchId: z27.uuid("--branch-id must be a UUID."),
16693
+ changeIds: z27.array(
16694
+ z27.string().min(1).max(
16695
+ AUTOMATION_BRANCH_CHANGE_ID_MAX_LENGTH,
16696
+ `--change-ids entries must be at most ${AUTOMATION_BRANCH_CHANGE_ID_MAX_LENGTH} characters.`
16697
+ )
16698
+ ).min(1, "--change-ids must name at least one preview change id.").max(
16699
+ AUTOMATION_BRANCH_DISCARD_MAX_CHANGE_IDS,
16700
+ `--change-ids can name at most ${AUTOMATION_BRANCH_DISCARD_MAX_CHANGE_IDS} preview change ids per run.`
16701
+ ),
16702
+ sourceVersionId: z27.uuid("--source-version-id must be a UUID."),
16703
+ targetVersionId: z27.uuid("--target-version-id must be a UUID.")
16704
+ }),
16705
+ cli: {
16706
+ branchContext: "required",
16707
+ name: "discard-automation-branch-changes",
16708
+ path: ["automations", "branches", "discard-changes"],
16709
+ description: "Revert preview changes on the branch so main keeps its values. Pass the change ids plus the source and target version ids from the preview you are acting on.",
16710
+ resultKey: "discardAutomationBranchChanges",
16711
+ options: [
16712
+ stringOption({
16713
+ inputKey: "automationId",
16714
+ flagName: "automation-id",
16715
+ description: "Automation ID.",
16716
+ required: true
16717
+ }),
16718
+ stringArrayOption({
16719
+ inputKey: "changeIds",
16720
+ flagName: "change-ids",
16721
+ description: "Preview change ids to revert on the branch, for example agent:update:<agent-id>:instructions.",
16722
+ required: true
16723
+ }),
16724
+ stringOption({
16725
+ inputKey: "sourceVersionId",
16726
+ flagName: "source-version-id",
16727
+ description: "sourceVersionId from the preview being acted on.",
16728
+ required: true
16729
+ }),
16730
+ stringOption({
16731
+ inputKey: "targetVersionId",
16732
+ flagName: "target-version-id",
16733
+ description: "targetVersionId from the preview being acted on.",
16734
+ required: true
16735
+ })
16736
+ ]
16737
+ },
16738
+ mcp: { fileName: "discardAutomationBranchChanges.graphql" },
16739
+ document: `# Revert preview changes on a branch and return the refreshed merge preview.
16740
+ mutation DiscardAutomationBranchChanges(
16741
+ $automationId: ID!
16742
+ $branchId: ID!
16743
+ $changeIds: [String!]!
16744
+ $sourceVersionId: ID!
16745
+ $targetVersionId: ID!
16746
+ ) {
16747
+ discardAutomationBranchChanges(
16748
+ automationId: $automationId
16749
+ branchId: $branchId
16750
+ changeIds: $changeIds
16751
+ sourceVersionId: $sourceVersionId
16752
+ targetVersionId: $targetVersionId
16753
+ ) {
16754
+ automationId
16755
+ branchId
16756
+ previousHeadVersionId
16757
+ headVersionId
16758
+ discardedChangeIds
16759
+ preview {
16760
+ baseVersionId
16761
+ sourceVersionId
16762
+ targetVersionId
16763
+ changes {
16764
+ id
16765
+ kind
16766
+ group
16767
+ status
16768
+ label
16769
+ discardable
16770
+ agentId
16771
+ agentName
16772
+ field
16773
+ configKey
16774
+ fromAgentId
16775
+ toAgentId
16776
+ conflictDescription
16777
+ statusDescription
16778
+ }
16779
+ }
16780
+ }
16221
16781
  }`
16222
16782
  }),
16223
16783
  createOperationSpec({
@@ -16328,7 +16888,8 @@ query GetAvailableCommands($env: AvailableCommandsEnv!) {
16328
16888
  operationName: "GetAvailableModels",
16329
16889
  kind: "query",
16330
16890
  inputSchema: z27.object({
16331
- agentId: z27.string().min(1)
16891
+ agentId: z27.string().min(1),
16892
+ automationId: z27.string().min(1)
16332
16893
  }),
16333
16894
  cli: {
16334
16895
  name: "get-available-models",
@@ -16341,13 +16902,20 @@ query GetAvailableCommands($env: AvailableCommandsEnv!) {
16341
16902
  flagName: "agent-id",
16342
16903
  description: "Agent ID.",
16343
16904
  required: true
16905
+ }),
16906
+ stringOption({
16907
+ inputKey: "automationId",
16908
+ flagName: "automation-id",
16909
+ description: "Automation whose head pins the agent (required with agent-id).",
16910
+ required: true
16344
16911
  })
16345
16912
  ]
16346
16913
  },
16347
16914
  mcp: { fileName: "availableModels.graphql" },
16348
16915
  document: `# Query to fetch available model definitions and pools for a specific agent
16349
- query GetAvailableModels($agentId: String!) {
16350
- availableModels(agentId: $agentId) {
16916
+ # from that automation's head (agent model config resolves branch-safely).
16917
+ query GetAvailableModels($agentId: String!, $automationId: String!) {
16918
+ availableModels(agentId: $agentId, automationId: $automationId) {
16351
16919
  availableModelPools {
16352
16920
  name
16353
16921
  poolId
@@ -18400,7 +18968,7 @@ ${evalRunExportSelection}
18400
18968
  ];
18401
18969
 
18402
18970
  // src/program.ts
18403
- import { Command as Command3, InvalidArgumentError as InvalidArgumentError2, Option as Option3 } from "commander";
18971
+ import { Command as Command4, InvalidArgumentError as InvalidArgumentError2, Option as Option4 } from "commander";
18404
18972
 
18405
18973
  // src/api.ts
18406
18974
  import { randomUUID } from "node:crypto";
@@ -18734,6 +19302,108 @@ var pathwayRegressionRunResultResponseSchema = z28.object({
18734
19302
  workflowId: z28.string().min(1)
18735
19303
  })
18736
19304
  });
19305
+ var regressionTestPathwayStatusSchema = z28.enum([
19306
+ "new_pathway",
19307
+ "missing_after_change",
19308
+ "historical_path_missing_after_change",
19309
+ "no_matching_runs",
19310
+ "queued",
19311
+ "running",
19312
+ "passed",
19313
+ "failed",
19314
+ "inconclusive",
19315
+ "errored"
19316
+ ]);
19317
+ var regressionTestStatusSchema = z28.enum([
19318
+ "queued",
19319
+ "running",
19320
+ "passed",
19321
+ "failed",
19322
+ "inconclusive",
19323
+ "errored"
19324
+ ]);
19325
+ var regressionTestKickoffPathwaySchema = z28.object({
19326
+ baselineContractPathId: z28.string().min(1).nullable(),
19327
+ baselineLabel: z28.string().nullable(),
19328
+ candidateContractPathId: z28.string().min(1).nullable(),
19329
+ candidateLabel: z28.string().nullable(),
19330
+ id: z28.string().min(1),
19331
+ pathwayKey: z28.string().min(1),
19332
+ status: regressionTestPathwayStatusSchema
19333
+ });
19334
+ var regressionTestKickoffResponseSchema = z28.object({
19335
+ pathways: z28.array(regressionTestKickoffPathwaySchema),
19336
+ regressionTestId: z28.string().min(1),
19337
+ status: regressionTestStatusSchema
19338
+ });
19339
+ var regressionTestIterationCountsSchema = z28.object({
19340
+ errored: z28.number(),
19341
+ failed: z28.number(),
19342
+ passed: z28.number(),
19343
+ total: z28.number()
19344
+ });
19345
+ var regressionTestBaselineRunSummarySchema = z28.object({
19346
+ id: z28.string().min(1),
19347
+ iterationCounts: regressionTestIterationCountsSchema
19348
+ });
19349
+ var regressionTestPathwaySummarySchema = z28.object({
19350
+ baselineLabel: z28.string().nullable(),
19351
+ baselineRuns: z28.array(regressionTestBaselineRunSummarySchema),
19352
+ candidateLabel: z28.string().nullable(),
19353
+ id: z28.string().min(1),
19354
+ pathwayKey: z28.string().min(1),
19355
+ status: regressionTestPathwayStatusSchema
19356
+ });
19357
+ var regressionTestResultResponseSchema = z28.object({
19358
+ pathways: z28.array(regressionTestPathwaySummarySchema),
19359
+ regressionTest: z28.object({
19360
+ finishedAt: z28.string().nullable(),
19361
+ id: z28.string().min(1),
19362
+ startedAt: z28.string().nullable(),
19363
+ status: regressionTestStatusSchema
19364
+ })
19365
+ });
19366
+ var regressionTestBaselineStepSchema = z28.object({
19367
+ expectedToolCall: z28.unknown().nullable(),
19368
+ id: z28.string().min(1),
19369
+ iterationIndex: z28.number()
19370
+ });
19371
+ var regressionTestFailedToolCallSchema = z28.object({
19372
+ count: z28.number(),
19373
+ observedToolCall: z28.unknown()
19374
+ });
19375
+ var regressionTestFailedIterationSchema = z28.object({
19376
+ baselineIterationId: z28.string().min(1),
19377
+ failedToolCalls: z28.array(regressionTestFailedToolCallSchema)
19378
+ });
19379
+ var regressionTestReplayCountsSchema = z28.object({
19380
+ errored: z28.number(),
19381
+ failed: z28.number(),
19382
+ passed: z28.number()
19383
+ });
19384
+ var regressionTestBaselineRunSchema = z28.object({
19385
+ baselineAgentRunId: z28.string().min(1),
19386
+ baselineIterations: z28.array(regressionTestBaselineStepSchema),
19387
+ failedIterations: z28.array(regressionTestFailedIterationSchema),
19388
+ replayCounts: regressionTestReplayCountsSchema
19389
+ });
19390
+ var regressionTestPathwayDetailSchema = z28.object({
19391
+ baselineLabel: z28.string().nullable(),
19392
+ baselineRuns: z28.array(regressionTestBaselineRunSchema),
19393
+ candidateLabel: z28.string().nullable(),
19394
+ id: z28.string().min(1),
19395
+ pathwayKey: z28.string().min(1),
19396
+ status: regressionTestPathwayStatusSchema
19397
+ });
19398
+ var regressionTestPathwayResultResponseSchema = z28.object({
19399
+ pathway: regressionTestPathwayDetailSchema,
19400
+ regressionTest: z28.object({
19401
+ finishedAt: z28.string().nullable(),
19402
+ id: z28.string().min(1),
19403
+ startedAt: z28.string().nullable(),
19404
+ status: regressionTestStatusSchema
19405
+ })
19406
+ });
18737
19407
  var graphQlResponseSchema = z28.object({
18738
19408
  data: z28.record(z28.string(), z28.unknown()).nullable().optional(),
18739
19409
  errors: z28.array(
@@ -18775,6 +19445,7 @@ function getGraphQlErrorStatus(error) {
18775
19445
  return error.extensions?.appErrorType?.includes("not-found") ? 404 : void 0;
18776
19446
  }
18777
19447
  var apiErrorResponseSchema = z28.object({
19448
+ code: z28.string().min(1).optional(),
18778
19449
  errors: z28.array(
18779
19450
  z28.object({
18780
19451
  message: z28.string().min(1)
@@ -18795,6 +19466,13 @@ function getApiErrorDetail(responseBody) {
18795
19466
  }
18796
19467
  return parsedResponse.data.errors.map((error) => error.message).join("\n");
18797
19468
  }
19469
+ function getApiErrorCode(responseBody) {
19470
+ const parsedResponse = apiErrorResponseSchema.safeParse(responseBody);
19471
+ if (!parsedResponse.success) {
19472
+ return null;
19473
+ }
19474
+ return parsedResponse.data.code ?? null;
19475
+ }
18798
19476
  function getRetryAfterMs(response) {
18799
19477
  const retryAfter = response.headers.get("retry-after");
18800
19478
  if (!retryAfter) {
@@ -18924,12 +19602,12 @@ function applyAuthenticationHeaders({
18924
19602
  headers.set(OTTO_AUTHORIZATION_HEADER_NAME, `Bearer ${accessToken}`);
18925
19603
  headers.set("x-organization-id", organizationId);
18926
19604
  }
18927
- function createMagicalApiClient({
19605
+ function createFetchJson({
18928
19606
  apiBaseUrl,
18929
- fetchFn = fetch
19607
+ fetchFn
18930
19608
  }) {
18931
19609
  const resolveApiBaseUrl = typeof apiBaseUrl === "string" ? () => apiBaseUrl : apiBaseUrl;
18932
- async function fetchJson({
19610
+ return async function fetchJson({
18933
19611
  accessToken,
18934
19612
  impersonatedOrganizationId,
18935
19613
  allowOttoAuthorization,
@@ -18981,13 +19659,23 @@ function createMagicalApiClient({
18981
19659
  });
18982
19660
  if (!response.ok) {
18983
19661
  const errorDetail = getApiErrorDetail(responseBody);
19662
+ const apiErrorCode = getApiErrorCode(responseBody);
18984
19663
  throw new CliError(
18985
19664
  `Magical API request to ${url} failed with status ${response.status}${errorDetail ? `: ${errorDetail}` : "."}`,
18986
- errorOptions
19665
+ {
19666
+ ...errorOptions,
19667
+ ...apiErrorCode === null ? {} : { apiErrorCode }
19668
+ }
18987
19669
  );
18988
19670
  }
18989
19671
  return responseBody;
18990
- }
19672
+ };
19673
+ }
19674
+ function createMagicalApiClient({
19675
+ apiBaseUrl,
19676
+ fetchFn = fetch
19677
+ }) {
19678
+ const fetchJson = createFetchJson({ apiBaseUrl, fetchFn });
18991
19679
  return {
18992
19680
  async downloadFile({ outputPath, overwrite = false, url }) {
18993
19681
  if (!overwrite) {
@@ -19280,6 +19968,77 @@ function createMagicalApiClient({
19280
19968
  );
19281
19969
  }
19282
19970
  return parsedResponse.data;
19971
+ },
19972
+ async startAgentVersionRegressionTest({
19973
+ accessToken,
19974
+ agentVersionId,
19975
+ automationVersionId,
19976
+ impersonatedOrganizationId,
19977
+ organizationId
19978
+ }) {
19979
+ const parsedResponse = regressionTestKickoffResponseSchema.safeParse(
19980
+ await fetchJson({
19981
+ accessToken,
19982
+ allowOttoAuthorization: true,
19983
+ ...impersonatedOrganizationId ? { impersonatedOrganizationId } : {},
19984
+ ...organizationId ? { organizationId } : {},
19985
+ path: `/pathway-regression/tests/automation-versions/${encodeURIComponent(
19986
+ automationVersionId
19987
+ )}/agent-versions/${encodeURIComponent(agentVersionId)}/run`,
19988
+ init: {
19989
+ method: "POST"
19990
+ }
19991
+ })
19992
+ );
19993
+ if (!parsedResponse.success) {
19994
+ throw new CliError("Regression test kickoff payload was invalid.");
19995
+ }
19996
+ return parsedResponse.data;
19997
+ },
19998
+ async getAgentVersionRegressionTestResult({
19999
+ accessToken,
20000
+ impersonatedOrganizationId,
20001
+ organizationId,
20002
+ regressionTestId
20003
+ }) {
20004
+ const parsedResponse = regressionTestResultResponseSchema.safeParse(
20005
+ await fetchJson({
20006
+ accessToken,
20007
+ allowOttoAuthorization: true,
20008
+ ...impersonatedOrganizationId ? { impersonatedOrganizationId } : {},
20009
+ ...organizationId ? { organizationId } : {},
20010
+ path: `/pathway-regression/tests/${encodeURIComponent(
20011
+ regressionTestId
20012
+ )}`
20013
+ })
20014
+ );
20015
+ if (!parsedResponse.success) {
20016
+ throw new CliError("Regression test result payload was invalid.");
20017
+ }
20018
+ return parsedResponse.data;
20019
+ },
20020
+ async getAgentVersionRegressionTestPathway({
20021
+ accessToken,
20022
+ impersonatedOrganizationId,
20023
+ organizationId,
20024
+ regressionTestId,
20025
+ testPathwayId
20026
+ }) {
20027
+ const parsedResponse = regressionTestPathwayResultResponseSchema.safeParse(
20028
+ await fetchJson({
20029
+ accessToken,
20030
+ allowOttoAuthorization: true,
20031
+ ...impersonatedOrganizationId ? { impersonatedOrganizationId } : {},
20032
+ ...organizationId ? { organizationId } : {},
20033
+ path: `/pathway-regression/tests/${encodeURIComponent(
20034
+ regressionTestId
20035
+ )}/pathways/${encodeURIComponent(testPathwayId)}`
20036
+ })
20037
+ );
20038
+ if (!parsedResponse.success) {
20039
+ throw new CliError("Regression test pathway payload was invalid.");
20040
+ }
20041
+ return parsedResponse.data;
19283
20042
  }
19284
20043
  };
19285
20044
  }
@@ -19506,6 +20265,18 @@ async function handleAuthLogin(dependencies, options) {
19506
20265
  );
19507
20266
  }
19508
20267
 
20268
+ // src/branch-merge.ts
20269
+ function isRecord5(value) {
20270
+ return typeof value === "object" && value !== null && !Array.isArray(value);
20271
+ }
20272
+ function assertBranchMergeApplied(operationSpec, result) {
20273
+ if (operationSpec.operationName === "MergeAutomationBranch" && (!isRecord5(result) || result["status"] !== "merged")) {
20274
+ throw new CliError(
20275
+ isRecord5(result) && result["status"] === "conflict" ? "Merge not applied. Discard the conflicting changes with `mgcl automations branches discard-changes` (main keeps its values) or edit the branch to match main, then rerun this merge command." : "Merge not applied. Review the merge output, resolve any conflicts, then merge again."
20276
+ );
20277
+ }
20278
+ }
20279
+
19509
20280
  // src/capture-commands.ts
19510
20281
  import { Command, Option } from "commander";
19511
20282
 
@@ -19798,7 +20569,7 @@ async function pollCaptureRecording({
19798
20569
  onStatus,
19799
20570
  recordingId,
19800
20571
  signal,
19801
- sleep: sleep2 = async (delayMs) => {
20572
+ sleep: sleep3 = async (delayMs) => {
19802
20573
  await defaultSleep(delayMs, signal);
19803
20574
  }
19804
20575
  }) {
@@ -19824,7 +20595,7 @@ async function pollCaptureRecording({
19824
20595
  throw error;
19825
20596
  }
19826
20597
  onRetry?.(error, retryDelay);
19827
- await sleep2(retryDelay);
20598
+ await sleep3(retryDelay);
19828
20599
  return await pollNext(state);
19829
20600
  }
19830
20601
  const status = statusResult.value;
@@ -19839,7 +20610,7 @@ async function pollCaptureRecording({
19839
20610
  if (TERMINAL_STATUSES.has(status.status)) {
19840
20611
  return status;
19841
20612
  }
19842
- await sleep2(DEFAULT_POLL_INTERVAL_MS);
20613
+ await sleep3(DEFAULT_POLL_INTERVAL_MS);
19843
20614
  return await pollNext({
19844
20615
  effectiveDeadlineMs,
19845
20616
  hasObservedRecording: true
@@ -20105,10 +20876,10 @@ async function finishExport({
20105
20876
  async function pollExport({
20106
20877
  executeOperation,
20107
20878
  exportId,
20108
- sleep: sleep2
20879
+ sleep: sleep3
20109
20880
  }) {
20110
20881
  for (; ; ) {
20111
- await sleep2(EXPORT_POLL_INTERVAL_MS);
20882
+ await sleep3(EXPORT_POLL_INTERVAL_MS);
20112
20883
  const result = parseApiResult(
20113
20884
  // eslint-disable-next-line no-await-in-loop -- do not overlap signed-export status requests
20114
20885
  await executeOperation("GetEvalRunExport", { exportId }),
@@ -20528,6 +21299,267 @@ function isExpiredAccessTokenClaims(claims) {
20528
21299
  return claims.exp * 1e3 <= Date.now();
20529
21300
  }
20530
21301
 
21302
+ // src/regression-commands.ts
21303
+ import { setTimeout as sleep } from "node:timers/promises";
21304
+ import { Command as Command2, Option as Option2 } from "commander";
21305
+ var REGRESSION_TEST_TERMINAL_STATUSES = /* @__PURE__ */ new Set([
21306
+ "passed",
21307
+ "failed",
21308
+ "inconclusive",
21309
+ "errored"
21310
+ ]);
21311
+ var REGRESSION_TEST_POLL_INTERVAL_MS = 5e3;
21312
+ var REGRESSION_TEST_KICKOFF_RETRY_DELAY_MS = 5e3;
21313
+ var REGRESSION_TEST_RETRYABLE_KICKOFF_ERROR_CODE = "PATHWAY_CONTRACT_NOT_READY";
21314
+ function isRetryableRegressionTestKickoffError(error) {
21315
+ return error instanceof CliError && error.statusCode === 409 && error.apiErrorCode === REGRESSION_TEST_RETRYABLE_KICKOFF_ERROR_CODE;
21316
+ }
21317
+ function summarizeRegressionTestResult(result) {
21318
+ return {
21319
+ regressionTestId: result.regressionTest.id,
21320
+ status: result.regressionTest.status,
21321
+ startedAt: result.regressionTest.startedAt,
21322
+ finishedAt: result.regressionTest.finishedAt,
21323
+ pathways: result.pathways.map((pathway) => ({
21324
+ id: pathway.id,
21325
+ pathwayKey: pathway.pathwayKey,
21326
+ baselineLabel: pathway.baselineLabel,
21327
+ candidateLabel: pathway.candidateLabel,
21328
+ status: pathway.status,
21329
+ baselineRuns: pathway.baselineRuns.map((run) => ({
21330
+ id: run.id,
21331
+ iterationCounts: run.iterationCounts
21332
+ }))
21333
+ }))
21334
+ };
21335
+ }
21336
+ function summarizeRegressionTestPathway(result) {
21337
+ return {
21338
+ regressionTestId: result.regressionTest.id,
21339
+ status: result.regressionTest.status,
21340
+ pathway: {
21341
+ id: result.pathway.id,
21342
+ pathwayKey: result.pathway.pathwayKey,
21343
+ baselineLabel: result.pathway.baselineLabel,
21344
+ candidateLabel: result.pathway.candidateLabel,
21345
+ status: result.pathway.status,
21346
+ baselineRuns: result.pathway.baselineRuns.map((run) => ({
21347
+ baselineAgentRunId: run.baselineAgentRunId,
21348
+ replayCounts: run.replayCounts,
21349
+ baselineIterationCount: run.baselineIterations.length,
21350
+ failedIterations: run.failedIterations.map((fi) => ({
21351
+ baselineIterationId: fi.baselineIterationId,
21352
+ failedToolCalls: fi.failedToolCalls.map((ftc) => ({
21353
+ observedToolCall: ftc.observedToolCall,
21354
+ count: ftc.count
21355
+ }))
21356
+ }))
21357
+ }))
21358
+ }
21359
+ };
21360
+ }
21361
+ async function startRegressionTestWithRetry({
21362
+ dependencies,
21363
+ input,
21364
+ startRegressionTest
21365
+ }) {
21366
+ for (; ; ) {
21367
+ const result = await fromThrowable(
21368
+ startRegressionTest.bind(void 0, input),
21369
+ "regression-test-kickoff-failed"
21370
+ );
21371
+ if (!isErr(result)) {
21372
+ return result.value;
21373
+ }
21374
+ if (!isRetryableRegressionTestKickoffError(result.error.cause)) {
21375
+ throw result.error.cause;
21376
+ }
21377
+ dependencies.io.info("Contract generation in progress, retrying...");
21378
+ await sleep(REGRESSION_TEST_KICKOFF_RETRY_DELAY_MS);
21379
+ }
21380
+ }
21381
+ async function pollRegressionTestResult({
21382
+ dependencies,
21383
+ getRegressionTestResult,
21384
+ input,
21385
+ regressionTestId
21386
+ }) {
21387
+ for (; ; ) {
21388
+ await sleep(REGRESSION_TEST_POLL_INTERVAL_MS);
21389
+ const result = await getRegressionTestResult({
21390
+ ...input,
21391
+ regressionTestId
21392
+ });
21393
+ if (REGRESSION_TEST_TERMINAL_STATUSES.has(result.regressionTest.status)) {
21394
+ return result;
21395
+ }
21396
+ dependencies.io.info(
21397
+ `Regression test ${regressionTestId}: ${result.regressionTest.status}...`
21398
+ );
21399
+ }
21400
+ }
21401
+ async function handleRegressionRunCommand({
21402
+ dependencies,
21403
+ helpers,
21404
+ options
21405
+ }) {
21406
+ const { accessToken, impersonatedOrganizationId, organization, state } = await helpers.withSelectedOrganizationAndAccessToken({
21407
+ dependencies,
21408
+ options
21409
+ });
21410
+ const startAgentVersionRegressionTest = helpers.requireApiClientMethod(
21411
+ dependencies.apiClient,
21412
+ "startAgentVersionRegressionTest"
21413
+ );
21414
+ const getAgentVersionRegressionTestResult = helpers.requireApiClientMethod(
21415
+ dependencies.apiClient,
21416
+ "getAgentVersionRegressionTestResult"
21417
+ );
21418
+ const authParams = {
21419
+ accessToken,
21420
+ ...impersonatedOrganizationId ? { impersonatedOrganizationId } : {},
21421
+ organizationId: organization.id
21422
+ };
21423
+ const kickoffResult = await startRegressionTestWithRetry({
21424
+ dependencies,
21425
+ input: {
21426
+ ...authParams,
21427
+ agentVersionId: options.agentVersion,
21428
+ automationVersionId: options.automationVersion
21429
+ },
21430
+ startRegressionTest: startAgentVersionRegressionTest
21431
+ });
21432
+ const { regressionTestId } = kickoffResult;
21433
+ dependencies.io.info(`Regression test started: ${regressionTestId}`);
21434
+ const result = await pollRegressionTestResult({
21435
+ dependencies,
21436
+ getRegressionTestResult: getAgentVersionRegressionTestResult,
21437
+ input: authParams,
21438
+ regressionTestId
21439
+ });
21440
+ await helpers.saveLastUsedOrganization({
21441
+ dependencies,
21442
+ organizationId: organization.id,
21443
+ state
21444
+ });
21445
+ helpers.writeCommandOutput({
21446
+ dependencies,
21447
+ json: options.json,
21448
+ result: options.json ? result : summarizeRegressionTestResult(result)
21449
+ });
21450
+ }
21451
+ async function handleRegressionShowCommand({
21452
+ dependencies,
21453
+ helpers,
21454
+ options
21455
+ }) {
21456
+ const { accessToken, impersonatedOrganizationId, organization, state } = await helpers.withSelectedOrganizationAndAccessToken({
21457
+ dependencies,
21458
+ options
21459
+ });
21460
+ const authParams = {
21461
+ accessToken,
21462
+ ...impersonatedOrganizationId ? { impersonatedOrganizationId } : {},
21463
+ organizationId: organization.id
21464
+ };
21465
+ await helpers.saveLastUsedOrganization({
21466
+ dependencies,
21467
+ organizationId: organization.id,
21468
+ state
21469
+ });
21470
+ if (options.pathway) {
21471
+ const getAgentVersionRegressionTestPathway = helpers.requireApiClientMethod(
21472
+ dependencies.apiClient,
21473
+ "getAgentVersionRegressionTestPathway"
21474
+ );
21475
+ const result2 = await getAgentVersionRegressionTestPathway({
21476
+ ...authParams,
21477
+ regressionTestId: options.testId,
21478
+ testPathwayId: options.pathway
21479
+ });
21480
+ helpers.writeCommandOutput({
21481
+ dependencies,
21482
+ json: options.json,
21483
+ result: options.json ? result2 : summarizeRegressionTestPathway(result2)
21484
+ });
21485
+ return;
21486
+ }
21487
+ const getAgentVersionRegressionTestResult = helpers.requireApiClientMethod(
21488
+ dependencies.apiClient,
21489
+ "getAgentVersionRegressionTestResult"
21490
+ );
21491
+ const result = await getAgentVersionRegressionTestResult({
21492
+ ...authParams,
21493
+ regressionTestId: options.testId
21494
+ });
21495
+ helpers.writeCommandOutput({
21496
+ dependencies,
21497
+ json: options.json,
21498
+ result: options.json ? result : summarizeRegressionTestResult(result)
21499
+ });
21500
+ }
21501
+ function addRegressionCommands({
21502
+ dependencies,
21503
+ helpers,
21504
+ program: program2
21505
+ }) {
21506
+ const regressionCommand = configureCommandPresentation(
21507
+ new Command2("regression").description(
21508
+ "Run and inspect agent version regression tests."
21509
+ )
21510
+ ).helpGroup("Workspace:").addHelpText(
21511
+ "after",
21512
+ `
21513
+ ${formatExamples("Examples", [
21514
+ "mgcl regression run --automation-version <id> --agent-version <id>",
21515
+ "mgcl regression show <testId>",
21516
+ "mgcl regression show <testId> --pathway <pathwayId>"
21517
+ ])}`
21518
+ );
21519
+ regressionCommand.command("run").description(
21520
+ "Start a regression test, poll until complete, and return the summary."
21521
+ ).addOption(
21522
+ new Option2(
21523
+ "--org <org>",
21524
+ "Organization ID or exact organization name to use."
21525
+ ).helpGroup("Shared options:")
21526
+ ).addOption(
21527
+ new Option2(
21528
+ "--automation-version <id>",
21529
+ "Automation version to test against."
21530
+ ).helpGroup("Regression options:").makeOptionMandatory(true)
21531
+ ).addOption(
21532
+ new Option2("--agent-version <id>", "Agent version to test.").helpGroup("Regression options:").makeOptionMandatory(true)
21533
+ ).action(async function() {
21534
+ await handleRegressionRunCommand({
21535
+ dependencies,
21536
+ helpers,
21537
+ options: this.optsWithGlobals()
21538
+ });
21539
+ });
21540
+ regressionCommand.command("show <testId>").description("Show regression test results.").addOption(
21541
+ new Option2(
21542
+ "--org <org>",
21543
+ "Organization ID or exact organization name to use."
21544
+ ).helpGroup("Shared options:")
21545
+ ).addOption(
21546
+ new Option2(
21547
+ "--pathway <pathwayId>",
21548
+ "Show detail for a specific pathway."
21549
+ ).helpGroup("Regression options:")
21550
+ ).action(async function(testId) {
21551
+ await handleRegressionShowCommand({
21552
+ dependencies,
21553
+ helpers,
21554
+ options: {
21555
+ ...this.optsWithGlobals(),
21556
+ testId
21557
+ }
21558
+ });
21559
+ });
21560
+ program2.addCommand(regressionCommand);
21561
+ }
21562
+
20531
21563
  // src/self-update.ts
20532
21564
  import { spawn as spawn2 } from "node:child_process";
20533
21565
  import fs2 from "node:fs";
@@ -20692,7 +21724,7 @@ async function selfUpdateInstalledCli({
20692
21724
  }
20693
21725
 
20694
21726
  // src/settings-command.ts
20695
- import { Command as Command2, InvalidArgumentError, Option as Option2 } from "commander";
21727
+ import { Command as Command3, InvalidArgumentError, Option as Option3 } from "commander";
20696
21728
  function writeJsonOutput2(io, value) {
20697
21729
  io.info(JSON.stringify(value, null, 2));
20698
21730
  }
@@ -20770,7 +21802,7 @@ async function handleSettingsEnvBaseUrl(dependencies, rawBaseUrl, options) {
20770
21802
  }
20771
21803
  function createSettingsCommand(dependencies) {
20772
21804
  const settingsCommand = configureCommandPresentation(
20773
- new Command2("settings").description("Manage persisted CLI settings.")
21805
+ new Command3("settings").description("Manage persisted CLI settings.")
20774
21806
  ).helpGroup("Workspace:").addHelpText(
20775
21807
  "after",
20776
21808
  `
@@ -20780,7 +21812,7 @@ ${formatExamples("Examples", [
20780
21812
  ])}`
20781
21813
  );
20782
21814
  const settingsEnvCommand = settingsCommand.command("env").description("Manage persisted environment overrides.");
20783
- settingsEnvCommand.command("base-url [url]").description("Set or clear the persisted Magical API base URL override.").addOption(new Option2("--reset", "Clear the persisted base URL override.")).action(async function(baseUrl) {
21815
+ settingsEnvCommand.command("base-url [url]").description("Set or clear the persisted Magical API base URL override.").addOption(new Option3("--reset", "Clear the persisted base URL override.")).action(async function(baseUrl) {
20784
21816
  await handleSettingsEnvBaseUrl(
20785
21817
  dependencies,
20786
21818
  baseUrl,
@@ -21608,7 +22640,7 @@ var accessTokenClaimsSchema = z34.object({
21608
22640
  });
21609
22641
  function createWorkosAuthClient({
21610
22642
  fetchFn = fetch,
21611
- sleep: sleep2 = async (milliseconds) => {
22643
+ sleep: sleep3 = async (milliseconds) => {
21612
22644
  await new Promise((resolve) => {
21613
22645
  setTimeout(resolve, milliseconds);
21614
22646
  });
@@ -21702,12 +22734,12 @@ function createWorkosAuthClient({
21702
22734
  );
21703
22735
  }
21704
22736
  if (parsedError.data.error === "authorization_pending") {
21705
- await sleep2(nextIntervalMilliseconds);
22737
+ await sleep3(nextIntervalMilliseconds);
21706
22738
  return poll(nextIntervalMilliseconds);
21707
22739
  }
21708
22740
  if (parsedError.data.error === "slow_down") {
21709
22741
  const slowedIntervalMilliseconds = nextIntervalMilliseconds + 5e3;
21710
- await sleep2(slowedIntervalMilliseconds);
22742
+ await sleep3(slowedIntervalMilliseconds);
21711
22743
  return poll(slowedIntervalMilliseconds);
21712
22744
  }
21713
22745
  throw new CliError(
@@ -21791,7 +22823,7 @@ function parseCommandOptionValue(rawValue, optionSpec) {
21791
22823
  function createCliCommanderOption(optionSpec, helpGroup) {
21792
22824
  const optionFlags = optionSpec.valueType === "boolean" ? `--${optionSpec.flagName}` : `--${optionSpec.flagName} <value>`;
21793
22825
  const optionDescription = optionSpec.valueHint ? `${optionSpec.description} (${optionSpec.valueHint})` : optionSpec.description;
21794
- const nextOption = new Option3(optionFlags, optionDescription).helpGroup(
22826
+ const nextOption = new Option4(optionFlags, optionDescription).helpGroup(
21795
22827
  helpGroup
21796
22828
  );
21797
22829
  if (optionSpec.valueType === "boolean") {
@@ -21811,7 +22843,7 @@ function parsePositiveIntegerOption(rawValue) {
21811
22843
  }
21812
22844
  return parsedValue;
21813
22845
  }
21814
- function isRecord5(value) {
22846
+ function isRecord6(value) {
21815
22847
  return typeof value === "object" && value !== null && !Array.isArray(value);
21816
22848
  }
21817
22849
  function resolveOrganizationBySelector({
@@ -21888,7 +22920,7 @@ function parseOperationVariables(operationSpec, variables) {
21888
22920
  parsedVariables.error.issues[0]?.message ?? "Invalid command input."
21889
22921
  );
21890
22922
  }
21891
- if (!isRecord5(parsedVariables.data)) {
22923
+ if (!isRecord6(parsedVariables.data)) {
21892
22924
  throw new CliError("Invalid command input.");
21893
22925
  }
21894
22926
  return parsedVariables.data;
@@ -21986,13 +23018,17 @@ async function handleOperationCommand(dependencies, operationSpec, commandOption
21986
23018
  ...state,
21987
23019
  lastUsedOrgId: organization.id
21988
23020
  });
23021
+ const humanReadableFormatter = getBranchMergeFormatter(
23022
+ operationSpec.operationName
23023
+ );
21989
23024
  writeCommandOutput({
21990
23025
  dependencies,
23026
+ ...humanReadableFormatter ? { humanReadableFormatter } : {},
21991
23027
  json: commandOptions.json,
21992
23028
  result
21993
23029
  });
21994
23030
  assertBranchMergeApplied(operationSpec, result);
21995
- if (operationSpec.operationName === "ViewAutomationReview" && commandOptions["open"] && isRecord5(result) && typeof result["reportUrl"] === "string") {
23031
+ if (operationSpec.operationName === "ViewAutomationReview" && commandOptions["open"] && isRecord6(result) && typeof result["reportUrl"] === "string") {
21996
23032
  await dependencies.openExternalUrl(result["reportUrl"]).catch((error) => {
21997
23033
  dependencies.io.error(
21998
23034
  `Warning: Failed to open the automation review in the default browser: ${getErrorMessage(error)}`
@@ -22000,13 +23036,6 @@ async function handleOperationCommand(dependencies, operationSpec, commandOption
22000
23036
  });
22001
23037
  }
22002
23038
  }
22003
- function assertBranchMergeApplied(operationSpec, result) {
22004
- if (operationSpec.operationName === "MergeAutomationBranch" && (!isRecord5(result) || result["status"] !== "merged")) {
22005
- throw new CliError(
22006
- "Merge not applied. Review the merge output, resolve any conflicts, then merge again."
22007
- );
22008
- }
22009
- }
22010
23039
  function getOperation(operationName) {
22011
23040
  const operationSpec = operationSpecs.find(
22012
23041
  (candidate) => candidate.operationName === operationName
@@ -22179,12 +23208,12 @@ function addSkillsWorkingCopyCommands({
22179
23208
  skillsCommand
22180
23209
  }) {
22181
23210
  skillsCommand.command("pull <skill>").description("Download a root-level skill into ./skills/<skill-name>.").addOption(
22182
- new Option3(
23211
+ new Option4(
22183
23212
  "--org <org>",
22184
23213
  "Organization ID or exact organization name to use."
22185
23214
  ).helpGroup("Shared options:")
22186
23215
  ).addOption(
22187
- new Option3(
23216
+ new Option4(
22188
23217
  "--force",
22189
23218
  "Replace existing files or local edits with the remote bundle."
22190
23219
  )
@@ -22203,7 +23232,7 @@ ${formatExamples("Examples", [
22203
23232
  );
22204
23233
  });
22205
23234
  skillsCommand.command("diff <skill>").description("Preview local skill changes against the pulled bundle.").addOption(
22206
- new Option3(
23235
+ new Option4(
22207
23236
  "--org <org>",
22208
23237
  "Organization ID or exact organization name to use."
22209
23238
  ).helpGroup("Shared options:")
@@ -22222,12 +23251,12 @@ ${formatExamples("Examples", [
22222
23251
  );
22223
23252
  });
22224
23253
  skillsCommand.command("push <skill>").description("Atomically push local changes for one root-level skill.").addOption(
22225
- new Option3(
23254
+ new Option4(
22226
23255
  "--org <org>",
22227
23256
  "Organization ID or exact organization name to use."
22228
23257
  ).helpGroup("Shared options:")
22229
23258
  ).addOption(
22230
- new Option3("--message <message>", "Commit message for the skill update.")
23259
+ new Option4("--message <message>", "Commit message for the skill update.")
22231
23260
  ).addHelpText(
22232
23261
  "after",
22233
23262
  `
@@ -22268,6 +23297,7 @@ async function withSelectedOrganizationAndAccessToken({
22268
23297
  }
22269
23298
  function writeCommandOutput({
22270
23299
  dependencies,
23300
+ humanReadableFormatter = formatHumanReadableOutput,
22271
23301
  json,
22272
23302
  result
22273
23303
  }) {
@@ -22275,7 +23305,7 @@ function writeCommandOutput({
22275
23305
  writeJsonOutput3(dependencies.io, result);
22276
23306
  return;
22277
23307
  }
22278
- dependencies.io.info(formatHumanReadableOutput(result));
23308
+ dependencies.io.info(humanReadableFormatter(result));
22279
23309
  }
22280
23310
  async function handleNangoIntegrationsListCommand(dependencies, options) {
22281
23311
  const { accessToken, impersonatedOrganizationId, organization, state } = await withSelectedOrganizationAndAccessToken({ dependencies, options });
@@ -22659,7 +23689,7 @@ async function retryCaptureRequest({
22659
23689
  throw error;
22660
23690
  }
22661
23691
  onRetry(error, retryDelay);
22662
- await sleep(retryDelay, void 0, { signal }).catch(
23692
+ await sleep2(retryDelay, void 0, { signal }).catch(
22663
23693
  (sleepError) => {
22664
23694
  throw new CliError("Capture wait interrupted.", { cause: sleepError });
22665
23695
  }
@@ -22909,7 +23939,7 @@ function configureOperationalCommand(command, dependencies, operationSpec) {
22909
23939
  command.description(operationSpec.cli.description);
22910
23940
  if (operationSpec.scope !== "global") {
22911
23941
  command.addOption(
22912
- new Option3(
23942
+ new Option4(
22913
23943
  "--org <org>",
22914
23944
  "Organization ID or exact organization name to use."
22915
23945
  ).helpGroup("Shared options:")
@@ -22990,14 +24020,14 @@ function createDefaultDependencies() {
22990
24020
  }
22991
24021
  function buildProgram(dependencies) {
22992
24022
  const program2 = configureCommandPresentation(
22993
- new Command3().name("mgcl").description("Run Magical operations from the command line.")
22994
- ).addOption(new Option3("--json", "Render JSON output.")).addOption(
22995
- new Option3(
24023
+ new Command4().name("mgcl").description("Run Magical operations from the command line.")
24024
+ ).addOption(new Option4("--json", "Render JSON output.")).addOption(
24025
+ new Option4(
22996
24026
  "--branch-id <id>",
22997
24027
  'Target a supported automation command at one branch; omit it to target main. "Branch-aware commands" below lists the commands that accept it.'
22998
24028
  )
22999
24029
  ).version(CLI_VERSION, "--version", `Display mgcl version (${CLI_VERSION}).`).addOption(
23000
- new Option3(
24030
+ new Option4(
23001
24031
  "--update",
23002
24032
  "Update mgcl to the latest published npm release."
23003
24033
  )
@@ -23023,7 +24053,7 @@ function buildProgram(dependencies) {
23023
24053
  this.outputHelp();
23024
24054
  });
23025
24055
  const authCommand = configureCommandPresentation(
23026
- new Command3("auth").description("Manage CLI authentication.")
24056
+ new Command4("auth").description("Manage CLI authentication.")
23027
24057
  ).helpGroup("Workspace:").addHelpText(
23028
24058
  "after",
23029
24059
  `
@@ -23038,7 +24068,7 @@ ${formatExamples("Examples", ["mgcl auth login", "mgcl auth logout"])}`
23038
24068
  program2.addCommand(authCommand);
23039
24069
  program2.addCommand(createSettingsCommand(dependencies));
23040
24070
  const orgCommand = configureCommandPresentation(
23041
- new Command3("org").description("Manage organization selection.")
24071
+ new Command4("org").description("Manage organization selection.")
23042
24072
  ).helpGroup("Workspace:").addHelpText(
23043
24073
  "after",
23044
24074
  `
@@ -23059,7 +24089,7 @@ ${formatExamples("Examples", [
23059
24089
  });
23060
24090
  program2.addCommand(orgCommand);
23061
24091
  const pathwayRegressionCommand = configureCommandPresentation(
23062
- new Command3("pathway-regression").description(
24092
+ new Command4("pathway-regression").description(
23063
24093
  "Preview, start, and inspect pathway regression runs."
23064
24094
  )
23065
24095
  ).helpGroup("Workspace:").addHelpText(
@@ -23073,20 +24103,20 @@ ${formatExamples("Examples", [
23073
24103
  ])}`
23074
24104
  );
23075
24105
  const addPathwayRegressionAgentVersionOptions = (command) => command.addOption(
23076
- new Option3(
24106
+ new Option4(
23077
24107
  "--org <org>",
23078
24108
  "Organization ID or exact organization name to use."
23079
24109
  ).helpGroup("Shared options:")
23080
24110
  ).addOption(
23081
- new Option3(
24111
+ new Option4(
23082
24112
  "--automation-version-id <id>",
23083
24113
  "Automation version to test against."
23084
24114
  ).helpGroup("Pathway regression options:").makeOptionMandatory(true)
23085
24115
  ).addOption(
23086
- new Option3("--agent-version-id <id>", "Agent version to test.").helpGroup("Pathway regression options:").makeOptionMandatory(true)
24116
+ new Option4("--agent-version-id <id>", "Agent version to test.").helpGroup("Pathway regression options:").makeOptionMandatory(true)
23087
24117
  );
23088
24118
  const addPathwayRegressionPreviewOptions = (command) => addPathwayRegressionAgentVersionOptions(command).addOption(
23089
- new Option3(
24119
+ new Option4(
23090
24120
  "--runs-per-path <count>",
23091
24121
  "Number of historical runs to use per pathway. Defaults to the service value."
23092
24122
  ).helpGroup("Pathway regression options:").argParser(parsePositiveIntegerOption)
@@ -23108,12 +24138,12 @@ ${formatExamples("Examples", [
23108
24138
  );
23109
24139
  });
23110
24140
  pathwayRegressionCommand.command("results").description("Read a pathway regression run result.").addOption(
23111
- new Option3(
24141
+ new Option4(
23112
24142
  "--org <org>",
23113
24143
  "Organization ID or exact organization name to use."
23114
24144
  ).helpGroup("Shared options:")
23115
24145
  ).addOption(
23116
- new Option3(
24146
+ new Option4(
23117
24147
  "--regression-run-id <id>",
23118
24148
  "Pathway regression run ID to inspect."
23119
24149
  ).helpGroup("Pathway regression options:").makeOptionMandatory(true)
@@ -23124,12 +24154,12 @@ ${formatExamples("Examples", [
23124
24154
  );
23125
24155
  });
23126
24156
  pathwayRegressionCommand.command("check-results").description("Read detailed check attempts for one replay iteration.").addOption(
23127
- new Option3(
24157
+ new Option4(
23128
24158
  "--org <org>",
23129
24159
  "Organization ID or exact organization name to use."
23130
24160
  ).helpGroup("Shared options:")
23131
24161
  ).addOption(
23132
- new Option3(
24162
+ new Option4(
23133
24163
  "--regression-replay-iteration-id <id>",
23134
24164
  "Pathway regression replay iteration ID to inspect."
23135
24165
  ).helpGroup("Pathway regression options:").makeOptionMandatory(true)
@@ -23140,19 +24170,29 @@ ${formatExamples("Examples", [
23140
24170
  );
23141
24171
  });
23142
24172
  program2.addCommand(pathwayRegressionCommand);
24173
+ addRegressionCommands({
24174
+ dependencies,
24175
+ helpers: {
24176
+ requireApiClientMethod,
24177
+ saveLastUsedOrganization,
24178
+ withSelectedOrganizationAndAccessToken,
24179
+ writeCommandOutput
24180
+ },
24181
+ program: program2
24182
+ });
23143
24183
  const pathwaysCommand = configureCommandPresentation(
23144
- new Command3("pathways").description("Inspect pathways.")
24184
+ new Command4("pathways").description("Inspect pathways.")
23145
24185
  ).helpGroup("Workspace:");
23146
24186
  const pathwaySignaturesCommand = configureCommandPresentation(
23147
- new Command3("signatures").description("Inspect agent-run signatures.")
24187
+ new Command4("signatures").description("Inspect agent-run signatures.")
23148
24188
  );
23149
24189
  pathwaySignaturesCommand.command("get").description("Read an agent-run pathway signature.").addOption(
23150
- new Option3(
24190
+ new Option4(
23151
24191
  "--org <org>",
23152
24192
  "Organization ID or exact organization name to use."
23153
24193
  ).helpGroup("Shared options:")
23154
24194
  ).addOption(
23155
- new Option3("--agent-run-id <id>", "Agent run ID to inspect.").helpGroup("Pathway signature options:").makeOptionMandatory(true)
24195
+ new Option4("--agent-run-id <id>", "Agent run ID to inspect.").helpGroup("Pathway signature options:").makeOptionMandatory(true)
23156
24196
  ).action(async function() {
23157
24197
  await handlePathwaySignatureGetCommand(
23158
24198
  dependencies,
@@ -23162,7 +24202,7 @@ ${formatExamples("Examples", [
23162
24202
  pathwaysCommand.addCommand(pathwaySignaturesCommand);
23163
24203
  program2.addCommand(pathwaysCommand);
23164
24204
  const nangoCommand = configureCommandPresentation(
23165
- new Command3("nango").description(
24205
+ new Command4("nango").description(
23166
24206
  "Inspect Nango integrations and org-scoped authentications."
23167
24207
  )
23168
24208
  ).helpGroup("Workspace:").addHelpText(
@@ -23174,10 +24214,10 @@ ${formatExamples("Examples", [
23174
24214
  ])}`
23175
24215
  );
23176
24216
  const nangoIntegrationsCommand = configureCommandPresentation(
23177
- new Command3("integrations").description("Work with Nango integrations.")
24217
+ new Command4("integrations").description("Work with Nango integrations.")
23178
24218
  );
23179
24219
  nangoIntegrationsCommand.command("list").description("List Nango integrations available in the current workspace.").addOption(
23180
- new Option3(
24220
+ new Option4(
23181
24221
  "--org <org>",
23182
24222
  "Organization ID or exact organization name to use."
23183
24223
  ).helpGroup("Shared options:")
@@ -23189,22 +24229,22 @@ ${formatExamples("Examples", [
23189
24229
  });
23190
24230
  nangoCommand.addCommand(nangoIntegrationsCommand);
23191
24231
  const nangoAuthsCommand = configureCommandPresentation(
23192
- new Command3("auths").alias("authentications").description("Work with org-scoped Nango authentications.")
24232
+ new Command4("auths").alias("authentications").description("Work with org-scoped Nango authentications.")
23193
24233
  );
23194
24234
  nangoAuthsCommand.command("list").description(
23195
24235
  "List org-scoped Nango authentications and their connection IDs."
23196
24236
  ).addOption(
23197
- new Option3(
24237
+ new Option4(
23198
24238
  "--org <org>",
23199
24239
  "Organization ID or exact organization name to use."
23200
24240
  ).helpGroup("Shared options:")
23201
24241
  ).addOption(
23202
- new Option3(
24242
+ new Option4(
23203
24243
  "--integration <integration>",
23204
24244
  "Optional integration key to filter Nango authentications."
23205
24245
  )
23206
24246
  ).addOption(
23207
- new Option3(
24247
+ new Option4(
23208
24248
  "--connection-id <connectionId>",
23209
24249
  "Optional connection ID to filter Nango authentications."
23210
24250
  )
@@ -23222,7 +24262,7 @@ ${formatExamples("Examples", [
23222
24262
  nangoCommand.addCommand(nangoAuthsCommand);
23223
24263
  program2.addCommand(nangoCommand);
23224
24264
  const updateCommand = configureCommandPresentation(
23225
- new Command3("update").description(
24265
+ new Command4("update").description(
23226
24266
  "Update mgcl to the latest published npm release."
23227
24267
  )
23228
24268
  ).helpGroup("Workspace:").addHelpText(