@getmagical/cli 0.2.5 → 0.2.7

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
@@ -2056,13 +2056,13 @@ var require_ast = __commonJS({
2056
2056
  helperExpression: function helperExpression(node) {
2057
2057
  return node.type === "SubExpression" || (node.type === "MustacheStatement" || node.type === "BlockStatement") && !!(node.params && node.params.length || node.hash);
2058
2058
  },
2059
- scopedId: function scopedId(path8) {
2060
- return /^\.|this\b/.test(path8.original);
2059
+ scopedId: function scopedId(path9) {
2060
+ return /^\.|this\b/.test(path9.original);
2061
2061
  },
2062
2062
  // an ID is simple if it only has one part, and that part is not
2063
2063
  // `..` or `this`.
2064
- simpleId: function simpleId(path8) {
2065
- return path8.parts.length === 1 && !AST.helpers.scopedId(path8) && !path8.depth;
2064
+ simpleId: function simpleId(path9) {
2065
+ return path9.parts.length === 1 && !AST.helpers.scopedId(path9) && !path9.depth;
2066
2066
  }
2067
2067
  }
2068
2068
  };
@@ -3132,12 +3132,12 @@ var require_helpers2 = __commonJS({
3132
3132
  loc
3133
3133
  };
3134
3134
  }
3135
- function prepareMustache(path8, params, hash, open, strip, locInfo) {
3135
+ function prepareMustache(path9, params, hash, open, strip, locInfo) {
3136
3136
  var escapeFlag = open.charAt(3) || open.charAt(2), escaped = escapeFlag !== "{" && escapeFlag !== "&";
3137
3137
  var decorator = /\*/.test(open);
3138
3138
  return {
3139
3139
  type: decorator ? "Decorator" : "MustacheStatement",
3140
- path: path8,
3140
+ path: path9,
3141
3141
  params,
3142
3142
  hash,
3143
3143
  escaped,
@@ -3455,9 +3455,9 @@ var require_compiler = __commonJS({
3455
3455
  },
3456
3456
  DecoratorBlock: function DecoratorBlock(decorator) {
3457
3457
  var program2 = decorator.program && this.compileProgram(decorator.program);
3458
- var params = this.setupFullMustacheParams(decorator, program2, void 0), path8 = decorator.path;
3458
+ var params = this.setupFullMustacheParams(decorator, program2, void 0), path9 = decorator.path;
3459
3459
  this.useDecorators = true;
3460
- this.opcode("registerDecorator", params.length, path8.original);
3460
+ this.opcode("registerDecorator", params.length, path9.original);
3461
3461
  },
3462
3462
  PartialStatement: function PartialStatement(partial) {
3463
3463
  this.usePartial = true;
@@ -3521,46 +3521,46 @@ var require_compiler = __commonJS({
3521
3521
  }
3522
3522
  },
3523
3523
  ambiguousSexpr: function ambiguousSexpr(sexpr, program2, inverse) {
3524
- var path8 = sexpr.path, name = path8.parts[0], isBlock = program2 != null || inverse != null;
3525
- this.opcode("getContext", path8.depth);
3524
+ var path9 = sexpr.path, name = path9.parts[0], isBlock = program2 != null || inverse != null;
3525
+ this.opcode("getContext", path9.depth);
3526
3526
  this.opcode("pushProgram", program2);
3527
3527
  this.opcode("pushProgram", inverse);
3528
- path8.strict = true;
3529
- this.accept(path8);
3528
+ path9.strict = true;
3529
+ this.accept(path9);
3530
3530
  this.opcode("invokeAmbiguous", name, isBlock);
3531
3531
  },
3532
3532
  simpleSexpr: function simpleSexpr(sexpr) {
3533
- var path8 = sexpr.path;
3534
- path8.strict = true;
3535
- this.accept(path8);
3533
+ var path9 = sexpr.path;
3534
+ path9.strict = true;
3535
+ this.accept(path9);
3536
3536
  this.opcode("resolvePossibleLambda");
3537
3537
  },
3538
3538
  helperSexpr: function helperSexpr(sexpr, program2, inverse) {
3539
- var params = this.setupFullMustacheParams(sexpr, program2, inverse), path8 = sexpr.path, name = path8.parts[0];
3539
+ var params = this.setupFullMustacheParams(sexpr, program2, inverse), path9 = sexpr.path, name = path9.parts[0];
3540
3540
  if (this.options.knownHelpers[name]) {
3541
3541
  this.opcode("invokeKnownHelper", params.length, name);
3542
3542
  } else if (this.options.knownHelpersOnly) {
3543
3543
  throw new _exception2["default"]("You specified knownHelpersOnly, but used the unknown helper " + name, sexpr);
3544
3544
  } else {
3545
- path8.strict = true;
3546
- path8.falsy = true;
3547
- this.accept(path8);
3548
- this.opcode("invokeHelper", params.length, path8.original, _ast2["default"].helpers.simpleId(path8));
3545
+ path9.strict = true;
3546
+ path9.falsy = true;
3547
+ this.accept(path9);
3548
+ this.opcode("invokeHelper", params.length, path9.original, _ast2["default"].helpers.simpleId(path9));
3549
3549
  }
3550
3550
  },
3551
- PathExpression: function PathExpression(path8) {
3552
- this.addDepth(path8.depth);
3553
- this.opcode("getContext", path8.depth);
3554
- var name = path8.parts[0], scoped = _ast2["default"].helpers.scopedId(path8), blockParamId = !path8.depth && !scoped && this.blockParamIndex(name);
3551
+ PathExpression: function PathExpression(path9) {
3552
+ this.addDepth(path9.depth);
3553
+ this.opcode("getContext", path9.depth);
3554
+ var name = path9.parts[0], scoped = _ast2["default"].helpers.scopedId(path9), blockParamId = !path9.depth && !scoped && this.blockParamIndex(name);
3555
3555
  if (blockParamId) {
3556
- this.opcode("lookupBlockParam", blockParamId, path8.parts);
3556
+ this.opcode("lookupBlockParam", blockParamId, path9.parts);
3557
3557
  } else if (!name) {
3558
3558
  this.opcode("pushContext");
3559
- } else if (path8.data) {
3559
+ } else if (path9.data) {
3560
3560
  this.options.data = true;
3561
- this.opcode("lookupData", path8.depth, path8.parts, path8.strict);
3561
+ this.opcode("lookupData", path9.depth, path9.parts, path9.strict);
3562
3562
  } else {
3563
- this.opcode("lookupOnContext", path8.parts, path8.falsy, path8.strict, scoped);
3563
+ this.opcode("lookupOnContext", path9.parts, path9.falsy, path9.strict, scoped);
3564
3564
  }
3565
3565
  },
3566
3566
  StringLiteral: function StringLiteral(string) {
@@ -3910,16 +3910,16 @@ var require_util2 = __commonJS({
3910
3910
  }
3911
3911
  exports.urlGenerate = urlGenerate;
3912
3912
  function normalize(aPath) {
3913
- var path8 = aPath;
3913
+ var path9 = aPath;
3914
3914
  var url = urlParse(aPath);
3915
3915
  if (url) {
3916
3916
  if (!url.path) {
3917
3917
  return aPath;
3918
3918
  }
3919
- path8 = url.path;
3919
+ path9 = url.path;
3920
3920
  }
3921
- var isAbsolute = exports.isAbsolute(path8);
3922
- var parts = path8.split(/\/+/);
3921
+ var isAbsolute = exports.isAbsolute(path9);
3922
+ var parts = path9.split(/\/+/);
3923
3923
  for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
3924
3924
  part = parts[i];
3925
3925
  if (part === ".") {
@@ -3936,15 +3936,15 @@ var require_util2 = __commonJS({
3936
3936
  }
3937
3937
  }
3938
3938
  }
3939
- path8 = parts.join("/");
3940
- if (path8 === "") {
3941
- path8 = isAbsolute ? "/" : ".";
3939
+ path9 = parts.join("/");
3940
+ if (path9 === "") {
3941
+ path9 = isAbsolute ? "/" : ".";
3942
3942
  }
3943
3943
  if (url) {
3944
- url.path = path8;
3944
+ url.path = path9;
3945
3945
  return urlGenerate(url);
3946
3946
  }
3947
- return path8;
3947
+ return path9;
3948
3948
  }
3949
3949
  exports.normalize = normalize;
3950
3950
  function join(aRoot, aPath) {
@@ -6727,8 +6727,8 @@ var require_printer = __commonJS({
6727
6727
  return this.accept(sexpr.path) + " " + params + hash;
6728
6728
  };
6729
6729
  PrintVisitor.prototype.PathExpression = function(id) {
6730
- var path8 = id.parts.join("/");
6731
- return (id.data ? "@" : "") + "PATH:" + path8;
6730
+ var path9 = id.parts.join("/");
6731
+ return (id.data ? "@" : "") + "PATH:" + path9;
6732
6732
  };
6733
6733
  PrintVisitor.prototype.StringLiteral = function(string) {
6734
6734
  return '"' + string.value + '"';
@@ -7079,8 +7079,8 @@ function getErrorMessage(error) {
7079
7079
  }
7080
7080
 
7081
7081
  // src/program.ts
7082
- import { readFile as readFile5 } from "node:fs/promises";
7083
- import path7 from "node:path";
7082
+ import { readFile as readFile6 } from "node:fs/promises";
7083
+ import path8 from "node:path";
7084
7084
 
7085
7085
  // ../common/dist/src/stdlib/json.util.js
7086
7086
  var import_ts_essentials = __toESM(require_dist(), 1);
@@ -11818,6 +11818,7 @@ var fieldMetadataSchema = z7.object({
11818
11818
  description: z7.string().describe("A description of the input parameter.").nullable(),
11819
11819
  typeOverride: z7.string().describe("The override for the input parameter.").nullable(),
11820
11820
  enumLabels: z7.record(z7.string(), z7.string()).describe("Optional map of enum values to their display labels.").optional(),
11821
+ displayDefaultValue: z7.unknown().describe("Optional value to display when input is omitted without changing the parsed value.").optional(),
11821
11822
  label: z7.string().describe("Optional label override for the field.").optional(),
11822
11823
  allowLineBreaks: z7.boolean().describe("Whether the field should allow line breaks when supported by the input component.").optional(),
11823
11824
  hideEmptyInCollapsed: z7.boolean().describe("Whether to hide this field in collapsed view when empty.").optional(),
@@ -11850,6 +11851,7 @@ var clickTypeEnumSchema = z7.enum([
11850
11851
  "DOUBLE",
11851
11852
  "TRIPLE"
11852
11853
  ]);
11854
+ var updateModeSchema = z7.enum(["append", "prepend", "replace"]);
11853
11855
  var clickTypeSchema = withMetadata(clickTypeEnumSchema.optional(), {
11854
11856
  description: "The type of click to perform",
11855
11857
  typeOverride: null
@@ -11922,8 +11924,8 @@ var RENDER_TEMPLATE_ERROR_REASON_CATALOG = defineErrorReasonCatalog()([
11922
11924
  ]);
11923
11925
  var storeReferencePathPattern = String.raw`store(?:\.[$A-Z_a-z][\w$]*)*`;
11924
11926
  var storeReferenceMarkdownLinkTemplateRegex = new RegExp(String.raw`(?<open>\{\{\{?)\s*\[(?<path>${storeReferencePathPattern})\]\(\s*<?https?:\/\/\k<path>>?\s*\)\s*(?<close>\}\}\}?)`, "gu");
11925
- function normalizeAutomationStoreTemplateLinkMatch([_match, open, path8]) {
11926
- return open === "{{{" ? `{{{${path8}}}}` : `{{${path8}}}`;
11927
+ function normalizeAutomationStoreTemplateLinkMatch([_match, open, path9]) {
11928
+ return open === "{{{" ? `{{{${path9}}}}` : `{{${path9}}}`;
11927
11929
  }
11928
11930
  function normalizeAutomationStoreTemplateLinks(template) {
11929
11931
  return template.replaceAll(storeReferenceMarkdownLinkTemplateRegex, (...args) => normalizeAutomationStoreTemplateLinkMatch(args));
@@ -12491,18 +12493,18 @@ var reportStopDataSchema = z11.object({
12491
12493
  // ../common/dist/src/utils/automation-store-path.util.js
12492
12494
  var AUTOMATION_STORE_ROOT_PATH = "store";
12493
12495
  var relativeStorePathRegex = /^[$A-Z_a-z][\w$]*(?:\.[$A-Z_a-z][\w$]*)*$/u;
12494
- function normalizeStoreMutationPath(path8) {
12495
- const trimmedPath = path8.trim();
12496
+ function normalizeStoreMutationPath(path9) {
12497
+ const trimmedPath = path9.trim();
12496
12498
  const rootPrefix = `${AUTOMATION_STORE_ROOT_PATH}.`;
12497
12499
  const relativePath = trimmedPath.startsWith(rootPrefix) ? trimmedPath.slice(rootPrefix.length) : trimmedPath;
12498
12500
  if (!relativeStorePathRegex.test(relativePath)) {
12499
12501
  return Err({
12500
12502
  type: "invalid-automation-store-path",
12501
- path: path8,
12503
+ path: path9,
12502
12504
  categories: ["customer_usage"],
12503
12505
  statusCode: 400,
12504
12506
  nonRetryable: true,
12505
- message: `Automation store path "${path8}" is invalid.`,
12507
+ message: `Automation store path "${path9}" is invalid.`,
12506
12508
  suggestedAction: "Use a dot path relative to the automation store, such as patient.name or provider.clinic."
12507
12509
  });
12508
12510
  }
@@ -12515,16 +12517,16 @@ function findAutomationStorePathOverlap(paths) {
12515
12517
  ...new Set(paths.map(getCanonicalAutomationStoreMutationPath))
12516
12518
  ].toSorted((left, right) => (left === AUTOMATION_STORE_ROOT_PATH ? 0 : left.split(".").length) - (right === AUTOMATION_STORE_ROOT_PATH ? 0 : right.split(".").length));
12517
12519
  for (const [index, ancestorPath] of canonicalPaths.entries()) {
12518
- const descendantPath = canonicalPaths.slice(index + 1).find((path8) => ancestorPath === AUTOMATION_STORE_ROOT_PATH || path8.startsWith(`${ancestorPath}.`));
12520
+ const descendantPath = canonicalPaths.slice(index + 1).find((path9) => ancestorPath === AUTOMATION_STORE_ROOT_PATH || path9.startsWith(`${ancestorPath}.`));
12519
12521
  if (descendantPath !== void 0) {
12520
12522
  return { ancestorPath, descendantPath };
12521
12523
  }
12522
12524
  }
12523
12525
  return void 0;
12524
12526
  }
12525
- function getCanonicalAutomationStoreMutationPath(path8) {
12526
- const normalizedPath = normalizeStoreMutationPath(path8);
12527
- return normalizedPath._tag === "Ok" ? normalizedPath.value : path8.trim();
12527
+ function getCanonicalAutomationStoreMutationPath(path9) {
12528
+ const normalizedPath = normalizeStoreMutationPath(path9);
12529
+ return normalizedPath._tag === "Ok" ? normalizedPath.value : path9.trim();
12528
12530
  }
12529
12531
 
12530
12532
  // ../common/dist/src/constants/tool-declarations.js
@@ -12748,9 +12750,9 @@ var baseToolDeclarations = {
12748
12750
  path: []
12749
12751
  });
12750
12752
  }
12751
- const canonicalUpdatePaths = updates.map(({ path: path8 }) => getCanonicalAutomationStoreMutationPath(path8));
12753
+ const canonicalUpdatePaths = updates.map(({ path: path9 }) => getCanonicalAutomationStoreMutationPath(path9));
12752
12754
  const canonicalClearPathSet = new Set(clears.map(getCanonicalAutomationStoreMutationPath));
12753
- const conflictedUpdatePath = canonicalUpdatePaths.find((path8) => canonicalClearPathSet.has(path8));
12755
+ const conflictedUpdatePath = canonicalUpdatePaths.find((path9) => canonicalClearPathSet.has(path9));
12754
12756
  if (conflictedUpdatePath !== void 0) {
12755
12757
  context.addIssue({
12756
12758
  code: "custom",
@@ -12826,10 +12828,11 @@ var baseToolDeclarations = {
12826
12828
  },
12827
12829
  type: {
12828
12830
  id: "type",
12829
- description: "Type in the currently focused element with the given text",
12831
+ description: "Type in the currently focused element. By default, this replaces the complete current value; updateMode can instead append or prepend the text.",
12830
12832
  parameters: z12.object({
12831
12833
  [COMMON_PARAMETERS_KEY]: DEFAULT_COMMON_PARAMETERS,
12832
- text: z12.string().describe("The text to type")
12834
+ text: z12.string().describe("The text to type"),
12835
+ updateMode: updateModeSchema.optional().describe("How to combine the text with the current value. Defaults to replace.")
12833
12836
  })
12834
12837
  },
12835
12838
  getNDCFromMedication: {
@@ -13429,9 +13432,9 @@ var specialCommands = {
13429
13432
  };
13430
13433
 
13431
13434
  // ../common/dist/src/utils/agent-knowledge-base-assets.util.js
13432
- function getIsKnowledgeBaseAssetPathAllowed(path8) {
13433
- const pathSegments = path8.split("/");
13434
- if (path8.length === 0 || pathSegments.some((segment) => segment.length === 0)) {
13435
+ function getIsKnowledgeBaseAssetPathAllowed(path9) {
13436
+ const pathSegments = path9.split("/");
13437
+ if (path9.length === 0 || pathSegments.some((segment) => segment.length === 0)) {
13435
13438
  return false;
13436
13439
  }
13437
13440
  const isTopLevelAssetPath = pathSegments[0] === "assets";
@@ -13473,46 +13476,46 @@ var API_FILE_TYPE_REGISTRY = {
13473
13476
  var ApiAgentOutputModes = ["inline", "file"];
13474
13477
  var API_EMBEDDED_FILE_PATH_PATTERN = /^(?:\[\*\]|[A-Za-z_$][\w$-]*)(?:\[\*\]|\.[A-Za-z_$][\w$-]*)*$/u;
13475
13478
  var API_EMBEDDED_FILE_PATH_SEGMENT_PATTERN = /\[\*\]|[A-Za-z_$][\w$-]*/gu;
13476
- function parseApiEmbeddedFilePath(path8) {
13477
- if (!API_EMBEDDED_FILE_PATH_PATTERN.test(path8)) {
13479
+ function parseApiEmbeddedFilePath(path9) {
13480
+ if (!API_EMBEDDED_FILE_PATH_PATTERN.test(path9)) {
13478
13481
  return void 0;
13479
13482
  }
13480
- return [...path8.matchAll(API_EMBEDDED_FILE_PATH_SEGMENT_PATTERN)].map(([segment]) => segment === "[*]" ? { type: "arrayWildcard" } : { key: segment, type: "property" });
13483
+ return [...path9.matchAll(API_EMBEDDED_FILE_PATH_SEGMENT_PATTERN)].map(([segment]) => segment === "[*]" ? { type: "arrayWildcard" } : { key: segment, type: "property" });
13481
13484
  }
13482
13485
  var apiAgentEmbeddedFileSchema = z14.object({
13483
- path: z14.string().trim().min(1, "Embedded file path is required.").refine((path8) => parseApiEmbeddedFilePath(path8) !== void 0, {
13486
+ path: z14.string().trim().min(1, "Embedded file path is required.").refine((path9) => parseApiEmbeddedFilePath(path9) !== void 0, {
13484
13487
  message: "Embedded file path must use object properties and [*] array wildcards."
13485
13488
  }).describe("Path to a Base64 value relative to the projected API response. Supports object properties and [*] array wildcards."),
13486
13489
  contentType: z14.enum(ApiFileContentTypes).describe("File type of the decoded Base64 value.")
13487
13490
  }).strict();
13488
13491
  var apiAgentEmbeddedFilesSchema = z14.array(apiAgentEmbeddedFileSchema).superRefine((embeddedFiles, context) => {
13489
13492
  const paths = /* @__PURE__ */ new Set();
13490
- for (const [index, { path: path8 }] of embeddedFiles.entries()) {
13491
- if (paths.has(path8)) {
13493
+ for (const [index, { path: path9 }] of embeddedFiles.entries()) {
13494
+ if (paths.has(path9)) {
13492
13495
  context.addIssue({
13493
13496
  code: z14.ZodIssueCode.custom,
13494
- message: `Embedded file path "${path8}" can only be configured once.`,
13497
+ message: `Embedded file path "${path9}" can only be configured once.`,
13495
13498
  path: [index, "path"]
13496
13499
  });
13497
13500
  }
13498
- paths.add(path8);
13501
+ paths.add(path9);
13499
13502
  }
13500
13503
  }).describe("Base64 values to decode, upload as permanent files, and replace with file references in the projected API response.");
13501
13504
 
13502
13505
  // ../common/dist/src/zod-schemas/api-agent-request-file-encoding.schema.js
13503
13506
  import { z as z15 } from "zod";
13504
13507
  var API_REQUEST_FILE_PATH_PATTERN = /^[A-Za-z_$][\w$-]*(?:\.[A-Za-z_$][\w$-]*)*$/u;
13505
- function parseApiRequestFilePath(path8) {
13506
- if (!API_REQUEST_FILE_PATH_PATTERN.test(path8)) {
13508
+ function parseApiRequestFilePath(path9) {
13509
+ if (!API_REQUEST_FILE_PATH_PATTERN.test(path9)) {
13507
13510
  return void 0;
13508
13511
  }
13509
- return path8.split(".");
13512
+ return path9.split(".");
13510
13513
  }
13511
13514
  var apiAgentRequestFileEncodingSchema = z15.object({
13512
- sourceInput: z15.string().trim().min(1, "File input is required.").refine((path8) => parseApiRequestFilePath(path8) !== void 0, {
13515
+ sourceInput: z15.string().trim().min(1, "File input is required.").refine((path9) => parseApiRequestFilePath(path9) !== void 0, {
13513
13516
  message: "File input must use an object property path."
13514
13517
  }).describe("API Agent input containing the file reference to encode."),
13515
- destinationPath: z15.string().trim().min(1, "Request field is required.").refine((path8) => parseApiRequestFilePath(path8) !== void 0, {
13518
+ destinationPath: z15.string().trim().min(1, "Request field is required.").refine((path9) => parseApiRequestFilePath(path9) !== void 0, {
13516
13519
  message: "Request field must use an object property path."
13517
13520
  }).describe("JSON request body path where the encoded value is inserted."),
13518
13521
  encoding: z15.literal("base64").describe("Encoding applied to the source file before insertion.")
@@ -13863,25 +13866,32 @@ function hasControlCharacter(value) {
13863
13866
  }
13864
13867
  return false;
13865
13868
  }
13866
- function isNormalizedRepoPath(path8) {
13867
- if (path8 === "/") {
13869
+ function isNormalizedRepoPath(path9) {
13870
+ if (path9 === "/") {
13868
13871
  return true;
13869
13872
  }
13870
- if (path8.length === 0 || path8.startsWith("/") || path8.startsWith("\\") || path8.includes("\\") || hasControlCharacter(path8) || windowsAbsolutePathPattern.test(path8)) {
13873
+ if (path9.length === 0 || path9.startsWith("/") || path9.startsWith("\\") || path9.includes("\\") || hasControlCharacter(path9) || windowsAbsolutePathPattern.test(path9)) {
13871
13874
  return false;
13872
13875
  }
13873
- return path8.split("/").every((segment) => segment.length > 0 && segment !== "." && segment !== ".." && segment !== ".git");
13876
+ return path9.split("/").every((segment) => segment.length > 0 && segment !== "." && segment !== ".." && segment !== ".git");
13874
13877
  }
13875
- function normalizeRepoPath(path8) {
13876
- if (path8 === "/") {
13877
- return path8;
13878
+ function normalizeRepoPath(path9) {
13879
+ if (path9 === "/") {
13880
+ return path9;
13878
13881
  }
13879
- return path8.replaceAll(/\/+$/gu, "");
13882
+ return path9.replaceAll(/\/+$/gu, "");
13880
13883
  }
13881
13884
  var skillPathPattern = /^(?:skills\/.+|automations\/[^/]+\/skills\/.+|automations\/[^/]+\/agents\/[^/]+\/skills\/.+)$/u;
13885
+ var skillRootPathPattern = /^(?:skills\/[^/]+|automations\/[^/]+\/skills\/[^/]+|automations\/[^/]+\/agents\/[^/]+\/skills\/[^/]+)$/u;
13882
13886
  var repoPathSchema = z21.string().min(1).transform(normalizeRepoPath).refine(isNormalizedRepoPath, {
13883
13887
  message: "Path must be a normalized repository-relative path."
13884
13888
  });
13889
+ var registeredSkillPathSchema = repoPathSchema.refine((path9) => skillPathPattern.test(path9), {
13890
+ message: "Skill paths must be under root, automation, or automation-agent skills."
13891
+ });
13892
+ var registeredSkillRootPathSchema = registeredSkillPathSchema.refine((path9) => skillRootPathPattern.test(path9) && !path9.endsWith("/SKILL.md"), {
13893
+ message: "Registered skill paths must identify a skill root directory."
13894
+ });
13885
13895
  var knowledgeBasePluginPermissionSchema = z21.object({
13886
13896
  path: repoPathSchema.refine(getIsKnowledgeBaseAssetPathAllowed, {
13887
13897
  message: "Knowledge Base paths must be under org, automation, or automation-agent assets."
@@ -13897,9 +13907,7 @@ var memoryConfigSchema = z21.object({
13897
13907
  }).strict().describe("Configuration for the memory runtime plugin.");
13898
13908
  var skillsConfigSchema = z21.object({
13899
13909
  enabled: z21.boolean().default(false).describe("Explicit rollout switch for the skills runtime plugin."),
13900
- registeredSkills: z21.array(repoPathSchema.refine((path8) => skillPathPattern.test(path8), {
13901
- message: "Skill paths must be under root, automation, or automation-agent skills."
13902
- })).default(() => []).describe("Repository skill root paths available to the skills plugin."),
13910
+ registeredSkills: z21.array(registeredSkillPathSchema).default(() => []).describe("Repository skill root paths available to the skills plugin."),
13903
13911
  canEdit: z21.boolean().default(false).describe("Allows the skills runtime plugin to edit repo skills under the root skills folder.")
13904
13912
  }).describe("Configuration for the skills runtime plugin.");
13905
13913
  var agentPluginsConfigSchema = z21.object({
@@ -13921,6 +13929,7 @@ var baseAgentConfigFieldsSchema = z21.object({
13921
13929
  environmentOptions: environmentOptionsSchema.optional().default(DEFAULT_ENVIRONMENT_OPTION).describe("Environment configuration for the agent. Default is browser with SOM."),
13922
13930
  runSettings: agentRunSettingsSchema.optional().describe("Run settings persisted on the agent and used when this agent is selected as the settings source for a run while the run-settings rollout is enabled. This is the canonical runtime source for resource pools during the migration. It intentionally mirrors a subset of agent config so settings survive topology changes and can be stored on any agent regardless of that agent's own execution environment. Writers may populate this before the rollout flag is enabled, but runtime snapshotting must keep using legacy fields while the flag is disabled."),
13923
13931
  skipBrowserDebuggerPauses: z21.boolean().optional().describe("Legacy agent-local browser session startup setting. Used only when a run is in legacy config mode; canonical run settings mode reads runSettings.skipBrowserDebuggerPauses instead."),
13932
+ stepFollowingVerification: z21.enum(["default", "enabled", "disabled"]).optional().describe("Controls step-following verification for this agent. Default runs verification unless skills are enabled; enabled forces it on past the skills rule; disabled forces it off. Automation and system feature gates still take precedence."),
13924
13933
  limitations: agentRunLimitationSchema.describe("Resource limits for this agent, including maximum duration and tool call limits."),
13925
13934
  commonParametersSchema: z21.custom().optional().describe("Custom schema defining metadata the agent must provide with every tool call. By default, agents provide reasoning and step information. If specified, this schema replaces the default metadata schema entirely."),
13926
13935
  idempotencySettings: z21.object({
@@ -14266,7 +14275,8 @@ var automationRunConfigBaseSchema = z24.object({
14266
14275
  resolvedRunSettings: automationRunResolvedRunSettingsSchema.optional().describe("Canonical run settings snapshotted onto the automation run at creation time. Present only for runSettings mode; legacyConfig mode intentionally resolves runtime settings from each current agent config instead of storing a misleading snapshot."),
14267
14276
  queueResourcePools: resourcePoolsSchema.optional().describe("Canonical deduped resource-pool requirements snapshotted for queue and slot assignment. Present on new runs so assignment does not recompute requirements from mutable agent config."),
14268
14277
  credentialVariableResourcePools: resourcePoolsSchema.optional().describe("Additional resource pools selected through credential-valued automation variables. These are additive queue requirements and do not change whether the run uses runSettings or legacyConfig as its runtime settings source."),
14269
- resolvedRunSettingsSource: z24.enum(["runSettings", "legacyConfig"]).optional().describe("Runtime mode decided at run creation. runSettings means resolvedRunSettings is canonical for browser/session/resource-pool behaviour; legacyConfig means runtime consumers must use current agent legacy config fields.")
14278
+ resolvedRunSettingsSource: z24.enum(["runSettings", "legacyConfig"]).optional().describe("Runtime mode decided at run creation. runSettings means resolvedRunSettings is canonical for browser/session/resource-pool behaviour; legacyConfig means runtime consumers must use current agent legacy config fields."),
14279
+ automationVersionPinned: z24.literal(true).optional().describe("Infrastructure-owned marker set when the run was explicitly pinned to an automation version (e.g. a branch head draft run). Draft-scoped prompt rendering must keep the pinned agent version instead of re-resolving the latest draft instructions.")
14270
14280
  });
14271
14281
  var automationRunConfigSchema = automationRunConfigBaseSchema.superRefine((config, ctx) => {
14272
14282
  if (config.networkTrafficCaptureExplicitlyDisabled === true && config.networkTrafficCapture !== void 0) {
@@ -14279,6 +14289,7 @@ var automationRunConfigSchema = automationRunConfigBaseSchema.superRefine((confi
14279
14289
  });
14280
14290
  var automationRunStartConfigSchema = automationRunConfigBaseSchema.omit({
14281
14291
  allowPointOfNoReturnOverride: true,
14292
+ automationVersionPinned: true,
14282
14293
  credentialVariableResourcePools: true,
14283
14294
  implicitNetworkTrafficRecordingDecision: true,
14284
14295
  networkTrafficCapture: true,
@@ -14327,13 +14338,13 @@ function getMentionedStandardCommand(instructions) {
14327
14338
  const normalizedInstructions = instructions.toLowerCase();
14328
14339
  return STANDARD_COMMAND_NAMES.find((commandName) => normalizedInstructions.includes(commandName.toLowerCase())) ?? null;
14329
14340
  }
14330
- function assertCustomInstructionsCommand({ commands, path: path8 }) {
14331
- const customCommands = commands.flatMap((command, commandIndex) => command["commandName"] === "custom" ? [{ command, path: `${path8}[${commandIndex.toString()}]` }] : []);
14341
+ function assertCustomInstructionsCommand({ commands, path: path9 }) {
14342
+ const customCommands = commands.flatMap((command, commandIndex) => command["commandName"] === "custom" ? [{ command, path: `${path9}[${commandIndex.toString()}]` }] : []);
14332
14343
  if (customCommands.length === 0) {
14333
14344
  return;
14334
14345
  }
14335
14346
  if (customCommands.length > MAX_CUSTOM_COMMAND_COUNT) {
14336
- throw createInvalidValueError(`${path8} contains ${customCommands.length.toString()} custom commands. Use at most one short custom command per agent. Split policy, decision, outreach, and multi-step work into catalog commands or child agents instead.`);
14347
+ throw createInvalidValueError(`${path9} contains ${customCommands.length.toString()} custom commands. Use at most one short custom command per agent. Split policy, decision, outreach, and multi-step work into catalog commands or child agents instead.`);
14337
14348
  }
14338
14349
  const [customCommand] = customCommands;
14339
14350
  if (!customCommand) {
@@ -14387,27 +14398,35 @@ function createOperationSpec(spec) {
14387
14398
  }
14388
14399
 
14389
14400
  // ../mcp-registry/src/operation-specs.ts
14401
+ var AUTOMATION_BRANCH_NAME_PATTERN = /^[\da-z]+(?:-[\da-z]+)*$/u;
14402
+ var AUTOMATION_BRANCH_NAME_MESSAGE = 'Branch name must use lowercase letters or numbers separated by single dashes (for example, "release-2").';
14390
14403
  function stringOption({
14404
+ clientOnly = false,
14391
14405
  description,
14392
14406
  flagName,
14393
14407
  inputKey,
14394
- required = false
14408
+ required = false,
14409
+ valueHint
14395
14410
  }) {
14396
14411
  return {
14412
+ ...clientOnly ? { clientOnly: true } : {},
14397
14413
  description,
14398
14414
  flagName,
14399
14415
  inputKey,
14400
14416
  required,
14417
+ ...valueHint ? { valueHint } : {},
14401
14418
  valueType: "string"
14402
14419
  };
14403
14420
  }
14404
14421
  function numberOption({
14422
+ clientOnly = false,
14405
14423
  description,
14406
14424
  flagName,
14407
14425
  inputKey,
14408
14426
  required = false
14409
14427
  }) {
14410
14428
  return {
14429
+ ...clientOnly ? { clientOnly: true } : {},
14411
14430
  description,
14412
14431
  flagName,
14413
14432
  inputKey,
@@ -14416,11 +14435,13 @@ function numberOption({
14416
14435
  };
14417
14436
  }
14418
14437
  function booleanOption({
14438
+ clientOnly = false,
14419
14439
  description,
14420
14440
  flagName,
14421
14441
  inputKey
14422
14442
  }) {
14423
14443
  return {
14444
+ ...clientOnly ? { clientOnly: true } : {},
14424
14445
  description,
14425
14446
  flagName,
14426
14447
  inputKey,
@@ -14458,13 +14479,79 @@ function jsonOption({
14458
14479
  };
14459
14480
  }
14460
14481
  var jsonObjectSchema = z25.record(z25.string(), z25.unknown());
14482
+ var evalRunStatusSchema = z25.enum([
14483
+ "QUEUED",
14484
+ "RUNNING",
14485
+ "COMPLETE",
14486
+ "FAILED",
14487
+ "CANCELLED"
14488
+ ]);
14489
+ var evalInputChoicesSchema = z25.record(
14490
+ z25.string(),
14491
+ z25.array(z25.unknown()).min(1)
14492
+ );
14493
+ var registeredEvalRunInputSchema = z25.object({
14494
+ description: z25.string().min(1).optional(),
14495
+ input: evalInputChoicesSchema,
14496
+ maxConcurrency: z25.number().int().positive().default(1),
14497
+ name: z25.string().min(1).optional(),
14498
+ repeatCount: z25.number().int().positive().default(1),
14499
+ slug: z25.string().min(1),
14500
+ tags: z25.array(z25.string().min(1)).default([])
14501
+ });
14502
+ var registeredEvalSelection = ` slug
14503
+ name
14504
+ description
14505
+ tags
14506
+ version
14507
+ inputSchema`;
14508
+ var evalRunSelection = ` id
14509
+ createdAt
14510
+ updatedAt
14511
+ userId
14512
+ slug
14513
+ evalName
14514
+ evalDescription
14515
+ evalTags
14516
+ evalVersion
14517
+ input
14518
+ name
14519
+ description
14520
+ tags
14521
+ scorerSlugs
14522
+ maxConcurrency
14523
+ repeatCount
14524
+ acknowledgedTrialCount
14525
+ idempotencyKey
14526
+ dashboardUrl
14527
+ workflowId
14528
+ workflowRunId
14529
+ status
14530
+ startedAt
14531
+ finishedAt
14532
+ trialStatusCounts {
14533
+ queued
14534
+ running
14535
+ complete
14536
+ failed
14537
+ cancelled
14538
+ }`;
14539
+ var evalRunExportSelection = ` exportId
14540
+ evalRunId
14541
+ status
14542
+ workflowId
14543
+ workflowRunId
14544
+ fileName
14545
+ trialCount
14546
+ downloadUrl
14547
+ error`;
14461
14548
  function isRecord3(value) {
14462
14549
  return typeof value === "object" && value !== null && !Array.isArray(value);
14463
14550
  }
14464
14551
  function validateCustomInstructionsCommands({
14465
14552
  commands,
14466
14553
  ctx,
14467
- path: path8
14554
+ path: path9
14468
14555
  }) {
14469
14556
  if (!Array.isArray(commands)) {
14470
14557
  return;
@@ -14472,14 +14559,14 @@ function validateCustomInstructionsCommands({
14472
14559
  const validationResult = fromThrowable(() => {
14473
14560
  assertCustomInstructionsCommand({
14474
14561
  commands: commands.map((command) => isRecord3(command) ? command : {}),
14475
- path: path8.join(".").replaceAll(/\.(?<index>\d+)/gu, "[$<index>]")
14562
+ path: path9.join(".").replaceAll(/\.(?<index>\d+)/gu, "[$<index>]")
14476
14563
  });
14477
14564
  }, "invalid-custom-instructions-command");
14478
14565
  if (isErr(validationResult)) {
14479
14566
  ctx.addIssue({
14480
14567
  code: "custom",
14481
14568
  message: `${getErrorMessage2(validationResult.error.cause)} Run mgcl catalog commands to find the standard command for this work.`,
14482
- path: path8
14569
+ path: path9
14483
14570
  });
14484
14571
  }
14485
14572
  }
@@ -14715,6 +14802,7 @@ ${agentLimitationsSelection}
14715
14802
  systemPrompt
14716
14803
  additionalSystemPrompt
14717
14804
  ignoreUnstableSessionState
14805
+ stepFollowingVerification
14718
14806
  resourcePools {
14719
14807
  id
14720
14808
  type
@@ -14784,6 +14872,7 @@ ${agentLimitationsSelection}
14784
14872
  systemPrompt
14785
14873
  additionalSystemPrompt
14786
14874
  ignoreUnstableSessionState
14875
+ stepFollowingVerification
14787
14876
  }
14788
14877
  isCurrent
14789
14878
  }
@@ -15493,6 +15582,193 @@ query GetAutomations($ids: [ID!]!) {
15493
15582
  }
15494
15583
  }
15495
15584
  }
15585
+ }`
15586
+ }),
15587
+ createOperationSpec({
15588
+ operationName: "ListAutomationBranches",
15589
+ kind: "query",
15590
+ inputSchema: z25.object({
15591
+ automationId: z25.string().min(1)
15592
+ }),
15593
+ cli: {
15594
+ name: "list-automation-branches",
15595
+ path: ["automations", "branches", "list"],
15596
+ description: "List active branches for an automation.",
15597
+ resultKey: "automationBranches",
15598
+ options: [
15599
+ stringOption({
15600
+ inputKey: "automationId",
15601
+ flagName: "automation-id",
15602
+ description: "Automation ID.",
15603
+ required: true
15604
+ })
15605
+ ]
15606
+ },
15607
+ mcp: { fileName: "automationBranches.graphql" },
15608
+ document: `# List active automation branches. Deleted branches are excluded.
15609
+ query ListAutomationBranches($automationId: ID!) {
15610
+ automationBranches(automationId: $automationId) {
15611
+ branchId
15612
+ automationId
15613
+ name
15614
+ headVersionId
15615
+ forkedFromBranchId
15616
+ forkedFromVersionId
15617
+ createdAt
15618
+ updatedAt
15619
+ }
15620
+ }`
15621
+ }),
15622
+ createOperationSpec({
15623
+ operationName: "CreateAutomationBranch",
15624
+ kind: "mutation",
15625
+ inputSchema: z25.object({
15626
+ automationId: z25.string().min(1),
15627
+ name: z25.string().regex(AUTOMATION_BRANCH_NAME_PATTERN, AUTOMATION_BRANCH_NAME_MESSAGE),
15628
+ sourceBranchId: z25.string().min(1).optional(),
15629
+ sourceVersionId: z25.string().min(1).optional()
15630
+ }),
15631
+ cli: {
15632
+ name: "create-automation-branch",
15633
+ path: ["automations", "branches", "create"],
15634
+ description: "Create an automation branch. The source defaults to the current main head.",
15635
+ resultKey: "createAutomationBranch",
15636
+ options: [
15637
+ stringOption({
15638
+ inputKey: "automationId",
15639
+ flagName: "automation-id",
15640
+ description: "Automation ID.",
15641
+ required: true
15642
+ }),
15643
+ stringOption({
15644
+ inputKey: "name",
15645
+ flagName: "name",
15646
+ description: 'Lowercase branch name with single dashes between words or numbers (for example, "release-2").',
15647
+ required: true
15648
+ }),
15649
+ stringOption({
15650
+ inputKey: "sourceBranchId",
15651
+ flagName: "source-branch-id",
15652
+ description: "Optional source branch ID. Omit to branch from main."
15653
+ }),
15654
+ stringOption({
15655
+ inputKey: "sourceVersionId",
15656
+ flagName: "source-version-id",
15657
+ description: "Optional version in the selected source history. Omit to use its head."
15658
+ })
15659
+ ]
15660
+ },
15661
+ mcp: { fileName: "createAutomationBranch.graphql" },
15662
+ document: `# Create an automation branch from main or another branch.
15663
+ mutation CreateAutomationBranch(
15664
+ $automationId: ID!
15665
+ $name: String!
15666
+ $sourceBranchId: ID
15667
+ $sourceVersionId: ID
15668
+ ) {
15669
+ createAutomationBranch(
15670
+ automationId: $automationId
15671
+ name: $name
15672
+ sourceBranchId: $sourceBranchId
15673
+ sourceVersionId: $sourceVersionId
15674
+ ) {
15675
+ branchId
15676
+ automationId
15677
+ name
15678
+ headVersionId
15679
+ forkedFromBranchId
15680
+ forkedFromVersionId
15681
+ createdAt
15682
+ updatedAt
15683
+ }
15684
+ }`
15685
+ }),
15686
+ createOperationSpec({
15687
+ operationName: "GetAutomationBranch",
15688
+ kind: "query",
15689
+ inputSchema: z25.object({
15690
+ automationId: z25.string().min(1),
15691
+ branchId: z25.string().min(1)
15692
+ }),
15693
+ cli: {
15694
+ branchContext: "required",
15695
+ name: "get-automation-branch",
15696
+ path: ["automations", "branches", "get"],
15697
+ description: "Get the hydrated snapshot at an automation branch head without authentication secrets.",
15698
+ resultKey: "automationBranchHead",
15699
+ options: [
15700
+ stringOption({
15701
+ inputKey: "automationId",
15702
+ flagName: "automation-id",
15703
+ description: "Automation ID.",
15704
+ required: true
15705
+ })
15706
+ ]
15707
+ },
15708
+ mcp: { fileName: "automationBranchHead.graphql" },
15709
+ document: `# Get the hydrated snapshot at an active branch head. Authentication secrets are excluded.
15710
+ query GetAutomationBranch($automationId: ID!, $branchId: ID!) {
15711
+ automationBranchHead(automationId: $automationId, branchId: $branchId) {
15712
+ branchId
15713
+ headVersionId
15714
+ automation
15715
+ }
15716
+ }`
15717
+ }),
15718
+ createOperationSpec({
15719
+ operationName: "MergeAutomationBranch",
15720
+ kind: "mutation",
15721
+ inputSchema: z25.object({
15722
+ automationId: z25.string().min(1),
15723
+ branchId: z25.string().min(1)
15724
+ }),
15725
+ cli: {
15726
+ branchContext: "required",
15727
+ name: "merge-automation-branch",
15728
+ path: ["automations", "branches", "merge"],
15729
+ description: "Preview and merge a branch into main when every change is conflict-free.",
15730
+ resultKey: "mergeAutomationBranch",
15731
+ options: [
15732
+ stringOption({
15733
+ inputKey: "automationId",
15734
+ flagName: "automation-id",
15735
+ description: "Automation ID.",
15736
+ required: true
15737
+ })
15738
+ ]
15739
+ },
15740
+ mcp: { fileName: "mergeAutomationBranch.graphql" },
15741
+ document: `# Preview a branch merge and apply it only when there are no conflicts.
15742
+ mutation MergeAutomationBranch($automationId: ID!, $branchId: ID!) {
15743
+ mergeAutomationBranch(automationId: $automationId, branchId: $branchId) {
15744
+ automationId
15745
+ branchId
15746
+ status
15747
+ sourceBranchDeleted
15748
+ preview {
15749
+ baseVersionId
15750
+ sourceVersionId
15751
+ targetVersionId
15752
+ changes {
15753
+ id
15754
+ group
15755
+ label
15756
+ status
15757
+ }
15758
+ }
15759
+ conflicts {
15760
+ id
15761
+ group
15762
+ label
15763
+ status
15764
+ }
15765
+ applyResult {
15766
+ draftVersionId
15767
+ lastSavedAt
15768
+ publishedVersionId
15769
+ wasRebased
15770
+ }
15771
+ }
15496
15772
  }`
15497
15773
  }),
15498
15774
  createOperationSpec({
@@ -15747,9 +16023,11 @@ query GetAutomationWorkbenchCredentials {
15747
16023
  operationName: "GetAutomationWorkbenchDiagnostics",
15748
16024
  kind: "query",
15749
16025
  inputSchema: z25.object({
15750
- draftAutomationId: z25.string().min(1)
16026
+ draftAutomationId: z25.string().min(1),
16027
+ branchId: z25.string().min(1).optional()
15751
16028
  }),
15752
16029
  cli: {
16030
+ branchContext: "optional",
15753
16031
  name: "get-automation-workbench-diagnostics",
15754
16032
  path: ["workbench", "diagnostics"],
15755
16033
  description: "Fetch a compact draft automation graph plus workbench diagnostics.",
@@ -15765,8 +16043,10 @@ query GetAutomationWorkbenchCredentials {
15765
16043
  },
15766
16044
  mcp: { fileName: "automationWorkbenchDiagnostics.graphql" },
15767
16045
  document: `# Query automation workbench diagnostics for a draft automation.
15768
- query GetAutomationWorkbenchDiagnostics($draftAutomationId: ID!) {
15769
- automationWorkbenchDiagnostics(draftAutomationId: $draftAutomationId) {
16046
+ query GetAutomationWorkbenchDiagnostics($draftAutomationId: ID!, $branchId: ID) {
16047
+ automationWorkbenchDiagnostics(draftAutomationId: $draftAutomationId, branchId: $branchId) {
16048
+ branchId
16049
+ headVersionId
15770
16050
  summary {
15771
16051
  draftAutomationId
15772
16052
  name
@@ -16111,10 +16391,19 @@ query GetAutomationWorkbenchAwaitRunCompletion(
16111
16391
  inputSchema: z25.object({
16112
16392
  automationRunId: z25.string().min(1),
16113
16393
  draftAutomationId: z25.string().min(1).optional(),
16394
+ branchId: z25.string().min(1).optional(),
16114
16395
  minConfidence: z25.number().min(0).max(1).optional(),
16115
16396
  includeSensitive: z25.boolean().optional()
16397
+ }).superRefine((input, ctx) => {
16398
+ if (input.branchId && !input.draftAutomationId) {
16399
+ ctx.addIssue({
16400
+ code: z25.ZodIssueCode.custom,
16401
+ message: "--branch-id requires --draft-automation-id."
16402
+ });
16403
+ }
16116
16404
  }),
16117
16405
  cli: {
16406
+ branchContext: "optional",
16118
16407
  name: "get-automation-workbench-schema-suggestions",
16119
16408
  path: ["workbench", "schema-suggestions"],
16120
16409
  description: "Heuristic suggestions for schema fields the agent observed on browser pages but were not declared in the input schema.",
@@ -16149,15 +16438,19 @@ query GetAutomationWorkbenchAwaitRunCompletion(
16149
16438
  query GetAutomationWorkbenchSchemaSuggestions(
16150
16439
  $automationRunId: ID!
16151
16440
  $draftAutomationId: ID
16441
+ $branchId: ID
16152
16442
  $minConfidence: Float
16153
16443
  $includeSensitive: Boolean
16154
16444
  ) {
16155
16445
  automationWorkbenchSchemaSuggestions(
16156
16446
  automationRunId: $automationRunId
16157
16447
  draftAutomationId: $draftAutomationId
16448
+ branchId: $branchId
16158
16449
  minConfidence: $minConfidence
16159
16450
  includeSensitive: $includeSensitive
16160
16451
  ) {
16452
+ branchId
16453
+ headVersionId
16161
16454
  kind
16162
16455
  fieldName
16163
16456
  fieldLabel
@@ -16596,6 +16889,7 @@ mutation ResumeAutomationRun($automationRunId: ID!, $message: String) {
16596
16889
  kind: "mutation",
16597
16890
  inputSchema: z25.object({
16598
16891
  draftAutomationId: z25.string().min(1),
16892
+ branchId: z25.string().min(1).optional(),
16599
16893
  agentId: z25.string().min(1),
16600
16894
  idempotencyKey: z25.string().min(1),
16601
16895
  input: z25.unknown().optional(),
@@ -16605,6 +16899,7 @@ mutation ResumeAutomationRun($automationRunId: ID!, $message: String) {
16605
16899
  consistencyCheckCount: z25.number().int().optional()
16606
16900
  }),
16607
16901
  cli: {
16902
+ branchContext: "optional",
16608
16903
  name: "run-draft-automation",
16609
16904
  path: ["automations", "run-draft"],
16610
16905
  description: "Run a draft automation with an explicit trigger agent.",
@@ -16660,6 +16955,7 @@ mutation ResumeAutomationRun($automationRunId: ID!, $message: String) {
16660
16955
  # \`draftAutomationId\` is the draft automation entity ID (\`Automation.id\`), not \`draftVersionId\`.
16661
16956
  mutation RunDraftAutomation(
16662
16957
  $draftAutomationId: ID!
16958
+ $branchId: ID
16663
16959
  $agentId: ID!
16664
16960
  $idempotencyKey: String!
16665
16961
  $input: JSON
@@ -16670,6 +16966,7 @@ mutation RunDraftAutomation(
16670
16966
  ) {
16671
16967
  runDraftAutomation(
16672
16968
  draftAutomationId: $draftAutomationId
16969
+ branchId: $branchId
16673
16970
  agentId: $agentId
16674
16971
  idempotencyKey: $idempotencyKey
16675
16972
  input: $input
@@ -16679,6 +16976,9 @@ mutation RunDraftAutomation(
16679
16976
  consistencyCheckCount: $consistencyCheckCount
16680
16977
  ) {
16681
16978
  automationRunId
16979
+ automationVersionId
16980
+ branchId
16981
+ headVersionId
16682
16982
  workflowId
16683
16983
  workflowRunId
16684
16984
  }
@@ -16715,10 +17015,12 @@ mutation StopAutomationRun($automationRunId: ID!) {
16715
17015
  kind: "mutation",
16716
17016
  inputSchema: z25.object({
16717
17017
  draftAutomationId: z25.string().min(1),
17018
+ branchId: z25.string().min(1).optional(),
16718
17019
  expectedLastSavedAt: z25.string().optional(),
16719
17020
  operations: automationPatchOperationsSchema
16720
17021
  }),
16721
17022
  cli: {
17023
+ branchContext: "optional",
16722
17024
  name: "preview-automation-patch",
16723
17025
  path: ["workbench", "patch", "preview"],
16724
17026
  description: "Preview semantic workbench patch operations without saving the draft.",
@@ -16742,13 +17044,17 @@ mutation StopAutomationRun($automationRunId: ID!) {
16742
17044
  document: `# Preview semantic automation patch operations without writing.
16743
17045
  mutation PreviewAutomationPatch(
16744
17046
  $draftAutomationId: ID!
17047
+ $branchId: ID
16745
17048
  $operations: [AutomationWorkbenchPatchOperationInput!]!
16746
17049
  ) {
16747
17050
  previewAutomationPatch(
16748
17051
  draftAutomationId: $draftAutomationId
17052
+ branchId: $branchId
16749
17053
  operations: $operations
16750
17054
  ) {
16751
17055
  draftAutomationId
17056
+ branchId
17057
+ headVersionId
16752
17058
  applied
16753
17059
  updateInput
16754
17060
  before {
@@ -16820,6 +17126,83 @@ mutation PreviewAutomationPatch(
16820
17126
  name
16821
17127
  }
16822
17128
  }
17129
+ }`
17130
+ }),
17131
+ createOperationSpec({
17132
+ operationName: "ValidateAutomationPatchReadiness",
17133
+ kind: "mutation",
17134
+ inputSchema: z25.object({
17135
+ targetDraftAutomationId: z25.string().min(1).optional(),
17136
+ newAutomationName: z25.string().min(1).optional(),
17137
+ branchId: z25.string().min(1).optional(),
17138
+ operations: automationPatchOperationsSchema
17139
+ }).superRefine((input, ctx) => {
17140
+ if (input.branchId && !input.targetDraftAutomationId) {
17141
+ ctx.addIssue({
17142
+ code: z25.ZodIssueCode.custom,
17143
+ message: "--branch-id requires --target-draft-automation-id."
17144
+ });
17145
+ }
17146
+ }),
17147
+ cli: {
17148
+ branchContext: "optional",
17149
+ name: "validate-automation-patch-readiness",
17150
+ path: ["workbench", "patch", "readiness"],
17151
+ description: "Validate workbench patch readiness without changing an automation.",
17152
+ resultKey: "validateAutomationPatchReadiness",
17153
+ options: [
17154
+ stringOption({
17155
+ inputKey: "targetDraftAutomationId",
17156
+ flagName: "target-draft-automation-id",
17157
+ description: "Existing draft automation ID to validate."
17158
+ }),
17159
+ stringOption({
17160
+ inputKey: "newAutomationName",
17161
+ flagName: "new-automation-name",
17162
+ description: "New automation name when validating without an existing target."
17163
+ }),
17164
+ jsonOption({
17165
+ inputKey: "operations",
17166
+ flagName: "operations-json",
17167
+ description: `Automation patch operations array. ${COMMAND_CATALOG_HELP}`,
17168
+ required: true
17169
+ })
17170
+ ]
17171
+ },
17172
+ mcp: { fileName: "validateAutomationPatchReadiness.graphql" },
17173
+ document: `# Validate automation patch readiness without writing.
17174
+ mutation ValidateAutomationPatchReadiness(
17175
+ $targetDraftAutomationId: ID
17176
+ $newAutomationName: String
17177
+ $branchId: ID
17178
+ $operations: [AutomationWorkbenchPatchOperationInput!]!
17179
+ ) {
17180
+ validateAutomationPatchReadiness(
17181
+ targetDraftAutomationId: $targetDraftAutomationId
17182
+ newAutomationName: $newAutomationName
17183
+ branchId: $branchId
17184
+ operations: $operations
17185
+ ) {
17186
+ targetDraftAutomationId
17187
+ branchId
17188
+ headVersionId
17189
+ issues {
17190
+ severity
17191
+ code
17192
+ message
17193
+ agentId
17194
+ localId
17195
+ path
17196
+ repair
17197
+ relatedAgentIds
17198
+ relatedLocalIds
17199
+ }
17200
+ createdAgents {
17201
+ localId
17202
+ id
17203
+ name
17204
+ }
17205
+ }
16823
17206
  }`
16824
17207
  }),
16825
17208
  createOperationSpec({
@@ -16827,9 +17210,12 @@ mutation PreviewAutomationPatch(
16827
17210
  kind: "mutation",
16828
17211
  inputSchema: z25.object({
16829
17212
  draftAutomationId: z25.string().min(1),
17213
+ branchId: z25.string().min(1).optional(),
17214
+ expectedLastSavedAt: z25.string().optional(),
16830
17215
  operations: automationPatchOperationsSchema
16831
17216
  }),
16832
17217
  cli: {
17218
+ branchContext: "optional",
16833
17219
  name: "apply-automation-patch",
16834
17220
  path: ["workbench", "patch", "apply"],
16835
17221
  description: "Apply semantic workbench patch operations through the versioned save path.",
@@ -16858,15 +17244,19 @@ mutation PreviewAutomationPatch(
16858
17244
  document: `# Apply semantic automation patch operations through the versioned save path.
16859
17245
  mutation ApplyAutomationPatch(
16860
17246
  $draftAutomationId: ID!
17247
+ $branchId: ID
16861
17248
  $operations: [AutomationWorkbenchPatchOperationInput!]!
16862
17249
  $expectedLastSavedAt: String
16863
17250
  ) {
16864
17251
  applyAutomationPatch(
16865
17252
  draftAutomationId: $draftAutomationId
17253
+ branchId: $branchId
16866
17254
  operations: $operations
16867
17255
  expectedLastSavedAt: $expectedLastSavedAt
16868
17256
  ) {
16869
17257
  draftAutomationId
17258
+ branchId
17259
+ headVersionId
16870
17260
  applied
16871
17261
  updateInput
16872
17262
  before {
@@ -16945,9 +17335,11 @@ mutation ApplyAutomationPatch(
16945
17335
  kind: "mutation",
16946
17336
  inputSchema: z25.object({
16947
17337
  id: z25.string().min(1),
17338
+ branchId: z25.string().min(1).optional(),
16948
17339
  input: updateAutomationInputSchema
16949
17340
  }),
16950
17341
  cli: {
17342
+ branchContext: "optional",
16951
17343
  name: "update-automation-by-id",
16952
17344
  path: ["automations", "update"],
16953
17345
  description: "Update an automation.",
@@ -16974,102 +17366,865 @@ mutation ApplyAutomationPatch(
16974
17366
  # config.storeSchema remains additive. Use removeStoreSchemaPaths to delete named properties (and combine it with config.storeSchema for an atomic rename), or replaceStoreSchema for an exact replacement. replaceStoreSchema cannot be combined with either of those fields.
16975
17367
  # Destructive Store schema changes are rejected when the final agent set still references a removed property. Rewrite those agent references in the same update or leave the property in place.
16976
17368
  # Returns only id and lastSavedAt for MCP tool simplicity
16977
- mutation UpdateAutomationById($id: ID!, $input: UpdateAutomationInput!) {
16978
- updateAutomation(id: $id, input: $input) {
17369
+ mutation UpdateAutomationById($id: ID!, $branchId: ID, $input: UpdateAutomationInput!) {
17370
+ updateAutomation(id: $id, branchId: $branchId, input: $input) {
16979
17371
  id
17372
+ branchId
17373
+ headVersionId
16980
17374
  lastSavedAt
16981
17375
  }
16982
17376
  }`
16983
- })
16984
- ];
16985
-
16986
- // src/program.ts
16987
- import { Command as Command2, InvalidArgumentError as InvalidArgumentError2, Option as Option2 } from "commander";
16988
-
16989
- // src/api.ts
16990
- import { z as z26 } from "zod";
16991
-
16992
- // src/version.ts
16993
- import fs from "node:fs";
16994
- import path from "node:path";
16995
- import { fileURLToPath } from "node:url";
16996
- var packageManifestPath = path.resolve(
16997
- path.dirname(fileURLToPath(import.meta.url)),
16998
- "../package.json"
16999
- );
17000
- var packageManifestResult = safeJsonParse(
17001
- fs.readFileSync(packageManifestPath, "utf8")
17002
- );
17003
- if (isErr(packageManifestResult)) {
17004
- throw new Error(`Failed to parse ${packageManifestPath}.`, {
17005
- cause: packageManifestResult.error.cause
17006
- });
17007
- }
17008
- var cliPackageVersion = packageManifestResult.value.version;
17009
- if (typeof cliPackageVersion !== "string" || cliPackageVersion.length === 0) {
17010
- throw new Error(`Expected a version in ${packageManifestPath}.`);
17011
- }
17012
- var CLI_VERSION = cliPackageVersion;
17013
-
17014
- // src/api.ts
17015
- var OTTO_AUTHORIZATION_HEADER_NAME = "X-Otto-Authorization";
17016
- var OTTO_AUTHORIZATION_ISSUER = "magical:otto";
17017
- var workosOrganizationsResponseSchema = z26.object({
17018
- organizations: z26.array(
17019
- z26.object({
17020
- id: z26.string().min(1),
17021
- name: z26.string().min(1),
17022
- primaryDomain: z26.string().nullable().optional()
17023
- })
17024
- ),
17025
- success: z26.boolean()
17026
- });
17027
- var workosUserSchema = z26.object({
17028
- email: z26.string().nullable(),
17029
- id: z26.string().min(1)
17030
- });
17031
- var nangoIntegrationWireSchema = z26.object({
17032
- // eslint-disable-next-line @typescript-eslint/naming-convention -- mirrors Nango REST payload
17033
- unique_key: z26.string().min(1)
17034
- }).passthrough().transform((data) => ({
17035
- ...data,
17036
- uniqueKey: data.unique_key
17037
- }));
17038
- var nangoIntegrationsResponseSchema = z26.array(nangoIntegrationWireSchema);
17039
- var organizationAuthenticationSchema = z26.object({
17040
- id: z26.string().min(1),
17041
- type: z26.string().min(1),
17042
- connectionId: z26.string().nullable().optional(),
17043
- providerConfigKey: z26.string().nullable().optional(),
17044
- description: z26.string().nullable().optional(),
17045
- hostname: z26.string().nullable().optional()
17046
- }).passthrough();
17047
- var organizationAuthenticationsResponseSchema = z26.object({
17048
- authentications: z26.array(organizationAuthenticationSchema),
17049
- success: z26.boolean()
17050
- });
17051
- var graphQlResponseSchema = z26.object({
17052
- data: z26.record(z26.string(), z26.unknown()).optional(),
17053
- errors: z26.array(
17054
- z26.object({
17055
- message: z26.string().min(1)
17056
- })
17057
- ).optional()
17058
- });
17059
- var apiErrorResponseSchema = z26.object({
17060
- errors: z26.array(
17061
- z26.object({
17062
- message: z26.string().min(1)
17063
- })
17064
- ).optional(),
17065
- message: z26.string().min(1).optional()
17066
- });
17067
- function getApiErrorDetail(responseBody) {
17068
- const parsedResponse = apiErrorResponseSchema.safeParse(responseBody);
17069
- if (!parsedResponse.success) {
17070
- return null;
17071
- }
17072
- if (parsedResponse.data.message) {
17377
+ }),
17378
+ createOperationSpec({
17379
+ operationName: "ListRegisteredEvals",
17380
+ kind: "query",
17381
+ inputSchema: z25.object({}),
17382
+ cli: {
17383
+ name: "list-registered-evals",
17384
+ path: ["evals", "list"],
17385
+ description: "List globally registered eval definitions.",
17386
+ resultKey: "registeredEvals",
17387
+ options: []
17388
+ },
17389
+ mcp: { fileName: "registeredEvals.graphql" },
17390
+ scope: "global",
17391
+ document: `# List globally registered eval definitions available to the authenticated caller
17392
+ query ListRegisteredEvals {
17393
+ registeredEvals {
17394
+ ${registeredEvalSelection}
17395
+ }
17396
+ }`
17397
+ }),
17398
+ createOperationSpec({
17399
+ operationName: "GetRegisteredEval",
17400
+ kind: "query",
17401
+ inputSchema: z25.object({ slug: z25.string().min(1) }),
17402
+ cli: {
17403
+ name: "get-registered-eval",
17404
+ path: ["evals", "get"],
17405
+ description: "Get one globally registered eval definition.",
17406
+ resultKey: "registeredEval",
17407
+ options: [
17408
+ stringOption({
17409
+ description: "Registered eval slug.",
17410
+ flagName: "slug",
17411
+ inputKey: "slug",
17412
+ required: true
17413
+ })
17414
+ ]
17415
+ },
17416
+ mcp: { fileName: "registeredEval.graphql" },
17417
+ scope: "global",
17418
+ document: `# Get one globally registered eval definition by slug
17419
+ query GetRegisteredEval($slug: String!) {
17420
+ registeredEval(slug: $slug) {
17421
+ ${registeredEvalSelection}
17422
+ }
17423
+ }`
17424
+ }),
17425
+ createOperationSpec({
17426
+ operationName: "TestRegisteredEval",
17427
+ kind: "mutation",
17428
+ inputSchema: z25.object({
17429
+ input: jsonObjectSchema,
17430
+ slug: z25.string().min(1)
17431
+ }),
17432
+ cli: {
17433
+ name: "test-registered-eval",
17434
+ path: ["evals", "test-run"],
17435
+ description: "Execute one registered eval input and its scorers without persistence.",
17436
+ resultKey: "testRegisteredEval",
17437
+ options: [
17438
+ stringOption({
17439
+ description: "Registered eval slug.",
17440
+ flagName: "slug",
17441
+ inputKey: "slug",
17442
+ required: true
17443
+ }),
17444
+ jsonOption({
17445
+ description: "Concrete eval input object.",
17446
+ flagName: "input-json",
17447
+ inputKey: "input"
17448
+ }),
17449
+ stringOption({
17450
+ clientOnly: true,
17451
+ description: "Path to a JSON file containing the concrete input.",
17452
+ flagName: "input-file",
17453
+ inputKey: "inputFile"
17454
+ })
17455
+ ]
17456
+ },
17457
+ mcp: { fileName: "testRegisteredEval.graphql" },
17458
+ scope: "global",
17459
+ document: `# Execute exactly one registered eval input and its scorers without persistence or automatic retries
17460
+ # COMPLETE and FAILED execution outcomes are returned in the result body
17461
+ mutation TestRegisteredEval($slug: String!, $input: JSON!) {
17462
+ testRegisteredEval(input: { slug: $slug, input: $input }) {
17463
+ status
17464
+ input
17465
+ output
17466
+ scores
17467
+ error {
17468
+ type
17469
+ message
17470
+ }
17471
+ }
17472
+ }`
17473
+ }),
17474
+ createOperationSpec({
17475
+ operationName: "PlanRegisteredEvalRun",
17476
+ kind: "query",
17477
+ inputSchema: registeredEvalRunInputSchema,
17478
+ cli: {
17479
+ name: "plan-registered-eval-run",
17480
+ path: ["evals", "plan-run"],
17481
+ description: "Validate a registered eval run and calculate its exact trial count.",
17482
+ resultKey: "planRegisteredEvalRun",
17483
+ options: [
17484
+ stringOption({
17485
+ description: "Registered eval slug.",
17486
+ flagName: "slug",
17487
+ inputKey: "slug",
17488
+ required: true
17489
+ }),
17490
+ jsonOption({
17491
+ description: "Eval input choices keyed by registered input name.",
17492
+ flagName: "input-json",
17493
+ inputKey: "input"
17494
+ }),
17495
+ stringOption({
17496
+ clientOnly: true,
17497
+ description: "Path to a JSON file containing eval input choices.",
17498
+ flagName: "input-file",
17499
+ inputKey: "inputFile"
17500
+ }),
17501
+ stringOption({
17502
+ description: "Optional persisted run name.",
17503
+ flagName: "name",
17504
+ inputKey: "name"
17505
+ }),
17506
+ stringOption({
17507
+ description: "Optional persisted run description.",
17508
+ flagName: "description",
17509
+ inputKey: "description"
17510
+ }),
17511
+ stringArrayOption({
17512
+ description: "Persisted run tags.",
17513
+ flagName: "tags",
17514
+ inputKey: "tags"
17515
+ }),
17516
+ numberOption({
17517
+ description: "Maximum simultaneously executing trials.",
17518
+ flagName: "max-concurrency",
17519
+ inputKey: "maxConcurrency"
17520
+ }),
17521
+ numberOption({
17522
+ description: "Number of times to repeat each input combination.",
17523
+ flagName: "repeat-count",
17524
+ inputKey: "repeatCount"
17525
+ })
17526
+ ]
17527
+ },
17528
+ mcp: { fileName: "planRegisteredEvalRun.graphql" },
17529
+ scope: "global",
17530
+ document: `# Validate the complete proposed run and return the exact trial count without persistence
17531
+ query PlanRegisteredEvalRun(
17532
+ $slug: String!
17533
+ $input: JSON!
17534
+ $name: String
17535
+ $description: String
17536
+ $tags: [String!]
17537
+ $maxConcurrency: Int
17538
+ $repeatCount: Int
17539
+ ) {
17540
+ planRegisteredEvalRun(
17541
+ input: {
17542
+ slug: $slug
17543
+ input: $input
17544
+ name: $name
17545
+ description: $description
17546
+ tags: $tags
17547
+ maxConcurrency: $maxConcurrency
17548
+ repeatCount: $repeatCount
17549
+ }
17550
+ ) {
17551
+ combinationCount
17552
+ repeatCount
17553
+ trialCount
17554
+ }
17555
+ }`
17556
+ }),
17557
+ createOperationSpec({
17558
+ operationName: "StartRegisteredEvalRun",
17559
+ kind: "mutation",
17560
+ inputSchema: registeredEvalRunInputSchema.extend({
17561
+ expectedTrialCount: z25.number().int().positive(),
17562
+ idempotencyKey: z25.string().trim().min(1)
17563
+ }),
17564
+ cli: {
17565
+ name: "start-registered-eval-run",
17566
+ path: ["evals", "run"],
17567
+ description: "Plan, confirm, and asynchronously start a registered eval run.",
17568
+ resultKey: "startRegisteredEvalRun",
17569
+ options: [
17570
+ stringOption({
17571
+ description: "Registered eval slug.",
17572
+ flagName: "slug",
17573
+ inputKey: "slug",
17574
+ required: true
17575
+ }),
17576
+ jsonOption({
17577
+ description: "Eval input choices keyed by registered input name.",
17578
+ flagName: "input-json",
17579
+ inputKey: "input"
17580
+ }),
17581
+ stringOption({
17582
+ clientOnly: true,
17583
+ description: "Path to a JSON file containing eval input choices.",
17584
+ flagName: "input-file",
17585
+ inputKey: "inputFile"
17586
+ }),
17587
+ stringOption({
17588
+ description: "Optional persisted run name.",
17589
+ flagName: "name",
17590
+ inputKey: "name"
17591
+ }),
17592
+ stringOption({
17593
+ description: "Optional persisted run description.",
17594
+ flagName: "description",
17595
+ inputKey: "description"
17596
+ }),
17597
+ stringArrayOption({
17598
+ description: "Persisted run tags.",
17599
+ flagName: "tags",
17600
+ inputKey: "tags"
17601
+ }),
17602
+ numberOption({
17603
+ description: "Maximum simultaneously executing trials.",
17604
+ flagName: "max-concurrency",
17605
+ inputKey: "maxConcurrency"
17606
+ }),
17607
+ numberOption({
17608
+ description: "Number of times to repeat each input combination.",
17609
+ flagName: "repeat-count",
17610
+ inputKey: "repeatCount"
17611
+ }),
17612
+ stringOption({
17613
+ description: "Idempotency key; generated by mgcl when omitted.",
17614
+ flagName: "idempotency-key",
17615
+ inputKey: "idempotencyKey"
17616
+ }),
17617
+ numberOption({
17618
+ clientOnly: true,
17619
+ description: "Explicitly acknowledge the planned trial count.",
17620
+ flagName: "confirm-trials",
17621
+ inputKey: "confirmTrials"
17622
+ }),
17623
+ booleanOption({
17624
+ clientOnly: true,
17625
+ description: "Wait until the persisted run reaches a terminal state.",
17626
+ flagName: "wait",
17627
+ inputKey: "wait"
17628
+ })
17629
+ ]
17630
+ },
17631
+ mcp: { fileName: "startRegisteredEvalRun.graphql" },
17632
+ scope: "global",
17633
+ document: `# Start a registered eval run after PlanRegisteredEvalRun has returned an exact count
17634
+ # MCP callers must provide a unique idempotencyKey and the planned expectedTrialCount
17635
+ mutation StartRegisteredEvalRun(
17636
+ $slug: String!
17637
+ $input: JSON!
17638
+ $name: String
17639
+ $description: String
17640
+ $tags: [String!]
17641
+ $maxConcurrency: Int
17642
+ $repeatCount: Int
17643
+ $idempotencyKey: String!
17644
+ $expectedTrialCount: Int!
17645
+ ) {
17646
+ startRegisteredEvalRun(
17647
+ input: {
17648
+ slug: $slug
17649
+ input: $input
17650
+ name: $name
17651
+ description: $description
17652
+ tags: $tags
17653
+ maxConcurrency: $maxConcurrency
17654
+ repeatCount: $repeatCount
17655
+ idempotencyKey: $idempotencyKey
17656
+ expectedTrialCount: $expectedTrialCount
17657
+ }
17658
+ ) {
17659
+ idempotencyKey
17660
+ evalRunId
17661
+ workflowId
17662
+ workflowRunId
17663
+ }
17664
+ }`
17665
+ }),
17666
+ createOperationSpec({
17667
+ operationName: "ListEvalRuns",
17668
+ kind: "query",
17669
+ inputSchema: z25.object({
17670
+ page: z25.number().int().nonnegative().default(0),
17671
+ pageSize: z25.number().int().min(1).max(100).default(20),
17672
+ slug: z25.string().min(1).optional(),
17673
+ status: evalRunStatusSchema.optional()
17674
+ }),
17675
+ cli: {
17676
+ name: "list-eval-runs",
17677
+ path: ["evals", "runs", "list"],
17678
+ description: "List persisted eval runs with optional filters.",
17679
+ resultKey: "evalRuns",
17680
+ options: [
17681
+ stringOption({
17682
+ description: "Filter by registered eval slug.",
17683
+ flagName: "slug",
17684
+ inputKey: "slug"
17685
+ }),
17686
+ stringOption({
17687
+ description: "Filter by eval run status.",
17688
+ flagName: "status",
17689
+ inputKey: "status"
17690
+ }),
17691
+ numberOption({
17692
+ description: "Zero-based page number.",
17693
+ flagName: "page",
17694
+ inputKey: "page"
17695
+ }),
17696
+ numberOption({
17697
+ description: "Page size from 1 to 100.",
17698
+ flagName: "page-size",
17699
+ inputKey: "pageSize"
17700
+ })
17701
+ ]
17702
+ },
17703
+ mcp: { fileName: "evalRuns.graphql" },
17704
+ scope: "global",
17705
+ document: `# List globally persisted eval runs with status counts and offset pagination
17706
+ query ListEvalRuns(
17707
+ $slug: String
17708
+ $status: EvalRunStatus
17709
+ $page: Int
17710
+ $pageSize: Int
17711
+ ) {
17712
+ evalRuns(slug: $slug, status: $status, page: $page, pageSize: $pageSize) {
17713
+ items {
17714
+ ${evalRunSelection}
17715
+ }
17716
+ total
17717
+ page
17718
+ pageSize
17719
+ }
17720
+ }`
17721
+ }),
17722
+ createOperationSpec({
17723
+ operationName: "GetEvalRun",
17724
+ kind: "query",
17725
+ inputSchema: z25.object({ id: z25.string().min(1) }),
17726
+ cli: {
17727
+ name: "get-eval-run",
17728
+ path: ["evals", "runs", "get"],
17729
+ description: "Get one persisted eval run with current status counts.",
17730
+ resultKey: "evalRun",
17731
+ options: [
17732
+ stringOption({
17733
+ description: "Eval run ID.",
17734
+ flagName: "id",
17735
+ inputKey: "id",
17736
+ required: true
17737
+ })
17738
+ ]
17739
+ },
17740
+ mcp: { fileName: "evalRun.graphql" },
17741
+ scope: "global",
17742
+ document: `# Get one globally persisted eval run by ID
17743
+ query GetEvalRun($id: String!) {
17744
+ evalRun(id: $id) {
17745
+ ${evalRunSelection}
17746
+ }
17747
+ }`
17748
+ }),
17749
+ createOperationSpec({
17750
+ operationName: "AwaitEvalRun",
17751
+ kind: "query",
17752
+ inputSchema: z25.object({
17753
+ id: z25.string().min(1),
17754
+ timeoutMs: z25.number().int().min(1e3).max(6e4).default(3e4)
17755
+ }),
17756
+ cli: {
17757
+ name: "await-eval-run",
17758
+ path: ["evals", "runs", "await"],
17759
+ description: "Wait for an eval run by repeating bounded server long-polls.",
17760
+ resultKey: "evalRunAwait",
17761
+ options: [
17762
+ stringOption({
17763
+ description: "Eval run ID.",
17764
+ flagName: "id",
17765
+ inputKey: "id",
17766
+ required: true
17767
+ }),
17768
+ stringOption({
17769
+ clientOnly: true,
17770
+ description: "Overall client wait timeout.",
17771
+ flagName: "timeout",
17772
+ inputKey: "timeout",
17773
+ valueHint: "duration, for example 30s or 5m"
17774
+ })
17775
+ ]
17776
+ },
17777
+ mcp: { fileName: "evalRunAwait.graphql" },
17778
+ scope: "global",
17779
+ document: `# Wait up to 60 seconds for an eval run to reach COMPLETE, FAILED, or CANCELLED
17780
+ # Call again when reachedTerminal is false and a longer overall wait is needed
17781
+ query AwaitEvalRun($id: String!, $timeoutMs: Int) {
17782
+ evalRunAwait(id: $id, timeoutMs: $timeoutMs) {
17783
+ reachedTerminal
17784
+ pollCount
17785
+ elapsedMs
17786
+ evalRun {
17787
+ ${evalRunSelection}
17788
+ }
17789
+ }
17790
+ }`
17791
+ }),
17792
+ createOperationSpec({
17793
+ operationName: "ListEvalRunTrials",
17794
+ kind: "query",
17795
+ inputSchema: z25.object({
17796
+ cursor: z25.string().min(1).optional(),
17797
+ id: z25.string().min(1),
17798
+ limit: z25.number().int().min(1).max(1e3).default(100)
17799
+ }),
17800
+ cli: {
17801
+ name: "list-eval-run-trials",
17802
+ path: ["evals", "runs", "trials"],
17803
+ description: "List eval trials in deterministic cursor order.",
17804
+ resultKey: "evalRunTrials",
17805
+ options: [
17806
+ stringOption({
17807
+ description: "Eval run ID.",
17808
+ flagName: "id",
17809
+ inputKey: "id",
17810
+ required: true
17811
+ }),
17812
+ numberOption({
17813
+ description: "Maximum trials to return, from 1 to 1000.",
17814
+ flagName: "limit",
17815
+ inputKey: "limit"
17816
+ }),
17817
+ stringOption({
17818
+ description: "Opaque cursor returned by the previous page.",
17819
+ flagName: "cursor",
17820
+ inputKey: "cursor"
17821
+ })
17822
+ ]
17823
+ },
17824
+ mcp: { fileName: "evalRunTrials.graphql" },
17825
+ scope: "global",
17826
+ document: `# List eval trials in ascending deterministic order with an opaque continuation cursor
17827
+ query ListEvalRunTrials($id: String!, $limit: Int, $cursor: String) {
17828
+ evalRunTrials(id: $id, limit: $limit, cursor: $cursor) {
17829
+ trials {
17830
+ id
17831
+ createdAt
17832
+ updatedAt
17833
+ evalRunId
17834
+ repeatIndex
17835
+ input
17836
+ status
17837
+ startedAt
17838
+ finishedAt
17839
+ scores
17840
+ output
17841
+ workflowId
17842
+ workflowRunId
17843
+ }
17844
+ nextCursor
17845
+ }
17846
+ }`
17847
+ }),
17848
+ createOperationSpec({
17849
+ operationName: "CancelEvalRun",
17850
+ kind: "mutation",
17851
+ inputSchema: z25.object({ id: z25.string().min(1) }),
17852
+ cli: {
17853
+ name: "cancel-eval-run",
17854
+ path: ["evals", "runs", "cancel"],
17855
+ description: "Request cancellation for a queued or running eval run.",
17856
+ resultKey: "cancelEvalRun",
17857
+ options: [
17858
+ stringOption({
17859
+ description: "Eval run ID.",
17860
+ flagName: "id",
17861
+ inputKey: "id",
17862
+ required: true
17863
+ })
17864
+ ]
17865
+ },
17866
+ mcp: { fileName: "cancelEvalRun.graphql" },
17867
+ scope: "global",
17868
+ document: `# Request cancellation without claiming the run has already reached CANCELLED
17869
+ mutation CancelEvalRun($id: String!) {
17870
+ cancelEvalRun(id: $id) {
17871
+ evalRunId
17872
+ cancellationRequested
17873
+ status
17874
+ }
17875
+ }`
17876
+ }),
17877
+ createOperationSpec({
17878
+ operationName: "RequestEvalRunExport",
17879
+ kind: "mutation",
17880
+ inputSchema: z25.object({ id: z25.string().min(1) }),
17881
+ cli: {
17882
+ name: "request-eval-run-export",
17883
+ path: ["evals", "runs", "export"],
17884
+ description: "Request an asynchronous raw-results export.",
17885
+ resultKey: "requestEvalRunExport",
17886
+ options: [
17887
+ stringOption({
17888
+ description: "Eval run ID.",
17889
+ flagName: "id",
17890
+ inputKey: "id",
17891
+ required: true
17892
+ }),
17893
+ stringOption({
17894
+ clientOnly: true,
17895
+ description: "Destination path for the completed export.",
17896
+ flagName: "output",
17897
+ inputKey: "output",
17898
+ required: true
17899
+ }),
17900
+ booleanOption({
17901
+ clientOnly: true,
17902
+ description: "Wait for export completion and download the file.",
17903
+ flagName: "wait",
17904
+ inputKey: "wait"
17905
+ }),
17906
+ booleanOption({
17907
+ clientOnly: true,
17908
+ description: "Authorize replacement of an existing output file.",
17909
+ flagName: "force",
17910
+ inputKey: "force"
17911
+ })
17912
+ ]
17913
+ },
17914
+ mcp: { fileName: "requestEvalRunExport.graphql" },
17915
+ scope: "global",
17916
+ document: `# Request or reuse an asynchronous raw-results export for a terminal eval run
17917
+ mutation RequestEvalRunExport($id: String!) {
17918
+ requestEvalRunExport(id: $id) {
17919
+ ${evalRunExportSelection}
17920
+ }
17921
+ }`
17922
+ }),
17923
+ createOperationSpec({
17924
+ operationName: "GetEvalRunExport",
17925
+ kind: "query",
17926
+ inputSchema: z25.object({ exportId: z25.string().min(1) }),
17927
+ cli: {
17928
+ hidden: true,
17929
+ name: "get-eval-run-export",
17930
+ path: ["evals", "runs", "export-status"],
17931
+ description: "Get asynchronous eval export status by export ID.",
17932
+ resultKey: "evalRunExport",
17933
+ options: [
17934
+ stringOption({
17935
+ description: "Eval export ID.",
17936
+ flagName: "export-id",
17937
+ inputKey: "exportId",
17938
+ required: true
17939
+ })
17940
+ ]
17941
+ },
17942
+ mcp: { fileName: "evalRunExport.graphql" },
17943
+ scope: "global",
17944
+ document: `# Get asynchronous eval export status; downloadUrl is signed and only present when COMPLETE
17945
+ query GetEvalRunExport($exportId: String!) {
17946
+ evalRunExport(exportId: $exportId) {
17947
+ ${evalRunExportSelection}
17948
+ }
17949
+ }`
17950
+ })
17951
+ ];
17952
+
17953
+ // src/program.ts
17954
+ import { Command as Command2, InvalidArgumentError as InvalidArgumentError2, Option as Option2 } from "commander";
17955
+
17956
+ // src/api.ts
17957
+ import { randomUUID } from "node:crypto";
17958
+ import { createWriteStream } from "node:fs";
17959
+ import { access, link, rename, rm } from "node:fs/promises";
17960
+ import nodePath from "node:path";
17961
+ import { Readable } from "node:stream";
17962
+ import { pipeline } from "node:stream/promises";
17963
+ import { z as z26 } from "zod";
17964
+
17965
+ // src/version.ts
17966
+ import fs from "node:fs";
17967
+ import path from "node:path";
17968
+ import { fileURLToPath } from "node:url";
17969
+ var packageManifestPath = path.resolve(
17970
+ path.dirname(fileURLToPath(import.meta.url)),
17971
+ "../package.json"
17972
+ );
17973
+ var packageManifestResult = safeJsonParse(
17974
+ fs.readFileSync(packageManifestPath, "utf8")
17975
+ );
17976
+ if (isErr(packageManifestResult)) {
17977
+ throw new Error(`Failed to parse ${packageManifestPath}.`, {
17978
+ cause: packageManifestResult.error.cause
17979
+ });
17980
+ }
17981
+ var cliPackageVersion = packageManifestResult.value.version;
17982
+ if (typeof cliPackageVersion !== "string" || cliPackageVersion.length === 0) {
17983
+ throw new Error(`Expected a version in ${packageManifestPath}.`);
17984
+ }
17985
+ var CLI_VERSION = cliPackageVersion;
17986
+
17987
+ // src/api.ts
17988
+ var OTTO_AUTHORIZATION_HEADER_NAME = "X-Otto-Authorization";
17989
+ var OTTO_AUTHORIZATION_ISSUER = "magical:otto";
17990
+ var workosOrganizationsResponseSchema = z26.object({
17991
+ organizations: z26.array(
17992
+ z26.object({
17993
+ id: z26.string().min(1),
17994
+ name: z26.string().min(1),
17995
+ primaryDomain: z26.string().nullable().optional()
17996
+ })
17997
+ ),
17998
+ success: z26.boolean()
17999
+ });
18000
+ var workosUserSchema = z26.object({
18001
+ email: z26.string().nullable(),
18002
+ id: z26.string().min(1)
18003
+ });
18004
+ var nangoIntegrationWireSchema = z26.object({
18005
+ // eslint-disable-next-line @typescript-eslint/naming-convention -- mirrors Nango REST payload
18006
+ unique_key: z26.string().min(1)
18007
+ }).passthrough().transform((data) => ({
18008
+ ...data,
18009
+ uniqueKey: data.unique_key
18010
+ }));
18011
+ var nangoIntegrationsResponseSchema = z26.array(nangoIntegrationWireSchema);
18012
+ var organizationAuthenticationSchema = z26.object({
18013
+ id: z26.string().min(1),
18014
+ type: z26.string().min(1),
18015
+ connectionId: z26.string().nullable().optional(),
18016
+ providerConfigKey: z26.string().nullable().optional(),
18017
+ description: z26.string().nullable().optional(),
18018
+ hostname: z26.string().nullable().optional()
18019
+ }).passthrough();
18020
+ var organizationAuthenticationsResponseSchema = z26.object({
18021
+ authentications: z26.array(organizationAuthenticationSchema),
18022
+ success: z26.boolean()
18023
+ });
18024
+ var pathwayRegressionRunStatusSchema = z26.enum([
18025
+ "queued",
18026
+ "running",
18027
+ "passed",
18028
+ "failed",
18029
+ "inconclusive",
18030
+ "errored"
18031
+ ]);
18032
+ var pathwayRegressionReplayIterationStatusSchema = z26.enum([
18033
+ "running",
18034
+ "passed",
18035
+ "failed",
18036
+ "inconclusive",
18037
+ "errored"
18038
+ ]);
18039
+ var pathwayRegressionMatchingRunSchema = z26.object({
18040
+ agentRunId: z26.string().min(1),
18041
+ agentVersionId: z26.string().min(1),
18042
+ automationRunId: z26.string().min(1),
18043
+ contractPathHash: z26.string().min(1),
18044
+ finishedAt: z26.string().min(1),
18045
+ signatureId: z26.string().min(1),
18046
+ stepCount: z26.number().nullable()
18047
+ });
18048
+ var pathwayRegressionMatchingRunsPathSchema = z26.object({
18049
+ contractPathId: z26.string().min(1),
18050
+ executablePathHash: z26.string().min(1),
18051
+ label: z26.string().min(1),
18052
+ pathwayKey: z26.string().min(1),
18053
+ runs: z26.array(pathwayRegressionMatchingRunSchema),
18054
+ sortOrder: z26.number()
18055
+ });
18056
+ var pathwayRegressionMatchingRunsResponseSchema = z26.object({
18057
+ agentVersionId: z26.string().min(1),
18058
+ automationId: z26.string().min(1),
18059
+ automationVersionId: z26.string().min(1),
18060
+ contractId: z26.string().min(1),
18061
+ paths: z26.array(pathwayRegressionMatchingRunsPathSchema)
18062
+ });
18063
+ var pathwayRegressionAgentVersionRunPathStatusSchema = z26.enum([
18064
+ "historical_path_missing_after_change",
18065
+ "missing_after_change",
18066
+ "new_pathway",
18067
+ "no_matching_runs",
18068
+ "queued"
18069
+ ]);
18070
+ var pathwayRegressionAgentVersionRunStatusSchema = z26.enum([
18071
+ "queued",
18072
+ "running",
18073
+ "passed",
18074
+ "failed",
18075
+ "inconclusive",
18076
+ "errored",
18077
+ "contract_generation_queued",
18078
+ "not_started"
18079
+ ]);
18080
+ var pathwayRegressionAgentVersionRunPathSideSchema = z26.object({
18081
+ contractPathId: z26.string().min(1),
18082
+ executablePathHash: z26.string().min(1),
18083
+ label: z26.string().min(1),
18084
+ sortOrder: z26.number()
18085
+ });
18086
+ var pathwayRegressionAgentVersionRunPathSchema = z26.object({
18087
+ baseline: pathwayRegressionAgentVersionRunPathSideSchema.nullable(),
18088
+ candidate: pathwayRegressionAgentVersionRunPathSideSchema.nullable(),
18089
+ isInLatestPublishedBaseline: z26.boolean().optional(),
18090
+ lastSeenPublishedAgentVersionId: z26.string().min(1).optional(),
18091
+ lastSeenPublishedAt: z26.string().min(1).nullable().optional(),
18092
+ lastSeenPublishedAutomationVersionId: z26.string().min(1).optional(),
18093
+ lastSeenPublishedSequence: z26.number().optional(),
18094
+ pathwayKey: z26.string().min(1),
18095
+ selectedRunCount: z26.number(),
18096
+ status: pathwayRegressionAgentVersionRunPathStatusSchema
18097
+ });
18098
+ var pathwayRegressionContractGenerationStatusSchema = z26.enum([
18099
+ "failed",
18100
+ "queued",
18101
+ "running",
18102
+ "succeeded"
18103
+ ]);
18104
+ var pathwayRegressionAgentVersionContractQueuedResponseSchema = z26.object({
18105
+ agentVersionId: z26.string().min(1),
18106
+ automationId: z26.string().min(1),
18107
+ automationVersionId: z26.string().min(1),
18108
+ contractGenerationStatus: pathwayRegressionContractGenerationStatusSchema,
18109
+ contractWorkflowId: z26.string().min(1),
18110
+ regressionRunId: z26.null(),
18111
+ selectedReplayCount: z26.literal(0),
18112
+ status: z26.literal("contract_generation_queued"),
18113
+ workflowId: z26.null()
18114
+ });
18115
+ var pathwayRegressionAgentVersionRegressionRunResponseSchema = z26.object({
18116
+ agentVersionId: z26.string().min(1),
18117
+ automationId: z26.string().min(1),
18118
+ automationVersionId: z26.string().min(1),
18119
+ baselineAgentVersionId: z26.string().min(1),
18120
+ baselineAutomationVersionId: z26.string().min(1),
18121
+ baselineContractId: z26.string().min(1),
18122
+ candidateContractId: z26.string().min(1),
18123
+ contractId: z26.string().min(1),
18124
+ paths: z26.array(pathwayRegressionAgentVersionRunPathSchema),
18125
+ regressionRunId: z26.string().min(1).nullable(),
18126
+ selectedReplayCount: z26.number(),
18127
+ status: pathwayRegressionAgentVersionRunStatusSchema,
18128
+ workflowId: z26.string().min(1).nullable()
18129
+ });
18130
+ var pathwayRegressionAgentVersionRunResponseSchema = z26.union([
18131
+ pathwayRegressionAgentVersionContractQueuedResponseSchema,
18132
+ pathwayRegressionAgentVersionRegressionRunResponseSchema
18133
+ ]);
18134
+ var pathwayRegressionCheckSummarySchema = z26.object({
18135
+ errored: z26.number(),
18136
+ failed: z26.number(),
18137
+ inconclusive: z26.number(),
18138
+ passed: z26.number(),
18139
+ total: z26.number()
18140
+ });
18141
+ var pathwayRegressionRunResultIterationSchema = z26.object({
18142
+ baselineIterationId: z26.string().min(1),
18143
+ createdAt: z26.string().min(1),
18144
+ expectedToolName: z26.string().min(1),
18145
+ id: z26.string().min(1),
18146
+ observedToolName: z26.string().min(1).nullable(),
18147
+ outputResult: z26.unknown().nullable(),
18148
+ sequence: z26.number(),
18149
+ status: pathwayRegressionReplayIterationStatusSchema,
18150
+ updatedAt: z26.string().min(1)
18151
+ });
18152
+ var pathwayRegressionReplayCheckResultSchema = z26.object({
18153
+ actualToolName: z26.string().min(1).nullable(),
18154
+ attemptIndex: z26.number(),
18155
+ createdAt: z26.string().min(1),
18156
+ expectedActionAssessment: z26.unknown().nullable(),
18157
+ expectedToolName: z26.string().min(1),
18158
+ id: z26.string().min(1),
18159
+ llmRequestId: z26.string().min(1).nullable(),
18160
+ modelId: z26.string().min(1).nullable(),
18161
+ outputResult: z26.unknown().nullable(),
18162
+ status: z26.enum(["passed", "failed", "errored"]),
18163
+ strictExactMatch: z26.boolean().nullable()
18164
+ });
18165
+ var pathwayRegressionReplayIterationCheckResultsResponseSchema = z26.object({
18166
+ regressionReplayIteration: pathwayRegressionRunResultIterationSchema.extend({
18167
+ checkResults: z26.array(pathwayRegressionReplayCheckResultSchema),
18168
+ regressionReplayId: z26.string().min(1)
18169
+ })
18170
+ });
18171
+ var pathwayRegressionRunResultReplaySchema = z26.object({
18172
+ baselineAgentRunId: z26.string().min(1),
18173
+ baselineAutomationRunId: z26.string().min(1),
18174
+ checks: pathwayRegressionCheckSummarySchema,
18175
+ createdAt: z26.string().min(1),
18176
+ finishedAt: z26.string().min(1).nullable(),
18177
+ id: z26.string().min(1),
18178
+ iterations: z26.array(pathwayRegressionRunResultIterationSchema),
18179
+ status: pathwayRegressionRunStatusSchema
18180
+ });
18181
+ var pathwayRegressionRunResultPathwaySchema = z26.object({
18182
+ contractId: z26.string().min(1),
18183
+ contractPathId: z26.string().min(1).nullable(),
18184
+ label: z26.string().min(1).nullable(),
18185
+ pathwayKey: z26.string().min(1),
18186
+ replays: z26.array(pathwayRegressionRunResultReplaySchema),
18187
+ sortOrder: z26.number().nullable()
18188
+ });
18189
+ var pathwayRegressionRunResultResponseSchema = z26.object({
18190
+ pathways: z26.array(pathwayRegressionRunResultPathwaySchema),
18191
+ regressionRun: z26.object({
18192
+ automationId: z26.string().min(1),
18193
+ candidateAgentVersionId: z26.string().min(1).nullable(),
18194
+ candidateAutomationVersionId: z26.string().min(1),
18195
+ createdAt: z26.string().min(1),
18196
+ finishedAt: z26.string().min(1).nullable(),
18197
+ id: z26.string().min(1),
18198
+ scope: z26.enum(["single_run", "contract_batch", "automation_version"]),
18199
+ status: pathwayRegressionRunStatusSchema,
18200
+ workflowId: z26.string().min(1)
18201
+ })
18202
+ });
18203
+ var graphQlResponseSchema = z26.object({
18204
+ data: z26.record(z26.string(), z26.unknown()).nullable().optional(),
18205
+ errors: z26.array(
18206
+ z26.object({
18207
+ extensions: z26.object({
18208
+ code: z26.string().min(1).optional()
18209
+ }).passthrough().optional(),
18210
+ message: z26.string().min(1)
18211
+ })
18212
+ ).optional()
18213
+ });
18214
+ var apiErrorResponseSchema = z26.object({
18215
+ errors: z26.array(
18216
+ z26.object({
18217
+ message: z26.string().min(1)
18218
+ })
18219
+ ).optional(),
18220
+ message: z26.string().min(1).optional()
18221
+ });
18222
+ function getApiErrorDetail(responseBody) {
18223
+ const parsedResponse = apiErrorResponseSchema.safeParse(responseBody);
18224
+ if (!parsedResponse.success) {
18225
+ return null;
18226
+ }
18227
+ if (parsedResponse.data.message) {
17073
18228
  return parsedResponse.data.message;
17074
18229
  }
17075
18230
  if (!parsedResponse.data.errors || parsedResponse.data.errors.length === 0) {
@@ -17077,9 +18232,57 @@ function getApiErrorDetail(responseBody) {
17077
18232
  }
17078
18233
  return parsedResponse.data.errors.map((error) => error.message).join("\n");
17079
18234
  }
18235
+ var DEFINITIVE_GRAPHQL_APPLICATION_ERROR_CODES = /* @__PURE__ */ new Set([
18236
+ "BAD_REQUEST",
18237
+ "BAD_USER_INPUT",
18238
+ "FORBIDDEN",
18239
+ "GRAPHQL_PARSE_FAILED",
18240
+ "GRAPHQL_VALIDATION_FAILED",
18241
+ "NOT_FOUND",
18242
+ "OPERATION_RESOLUTION_FAILURE",
18243
+ "PERSISTED_QUERY_NOT_FOUND",
18244
+ "PERSISTED_QUERY_NOT_SUPPORTED",
18245
+ "UNAUTHORIZED"
18246
+ ]);
18247
+ var GraphQlResponseError = class extends CliError {
18248
+ graphQlCodes;
18249
+ hasUnclassifiedGraphQlErrors;
18250
+ constructor(message, {
18251
+ graphQlCodes,
18252
+ hasUnclassifiedGraphQlErrors = false
18253
+ }) {
18254
+ super(message);
18255
+ this.name = "GraphQlResponseError";
18256
+ this.graphQlCodes = [...graphQlCodes];
18257
+ this.hasUnclassifiedGraphQlErrors = hasUnclassifiedGraphQlErrors;
18258
+ }
18259
+ };
18260
+ function isDefinitiveGraphQlApplicationError(error) {
18261
+ return error instanceof GraphQlResponseError && !error.hasUnclassifiedGraphQlErrors && error.graphQlCodes.length > 0 && error.graphQlCodes.every(
18262
+ (code) => DEFINITIVE_GRAPHQL_APPLICATION_ERROR_CODES.has(code)
18263
+ );
18264
+ }
17080
18265
  function trimTrailingSlash(value) {
17081
18266
  return value.replace(/\/+$/u, "");
17082
18267
  }
18268
+ function isFileAlreadyExistsError(error) {
18269
+ return error instanceof Error && "code" in error && error.code === "EEXIST";
18270
+ }
18271
+ async function assertOutputDoesNotExist(outputPath) {
18272
+ const outputExists = await access(outputPath).then(() => true).catch((error) => {
18273
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
18274
+ return false;
18275
+ }
18276
+ throw new CliError(`Failed to inspect export path "${outputPath}".`, {
18277
+ cause: error
18278
+ });
18279
+ });
18280
+ if (outputExists) {
18281
+ throw new CliError(
18282
+ `Refusing to overwrite existing file "${outputPath}". Pass --force to authorize replacement.`
18283
+ );
18284
+ }
18285
+ }
17083
18286
  function isRecord4(value) {
17084
18287
  return typeof value === "object" && value !== null && !Array.isArray(value);
17085
18288
  }
@@ -17099,6 +18302,23 @@ function decodeJwtPayload(token) {
17099
18302
  function isOttoAuthorizationToken(token) {
17100
18303
  return decodeJwtPayload(token)?.["iss"] === OTTO_AUTHORIZATION_ISSUER;
17101
18304
  }
18305
+ function buildPathwayRegressionAgentVersionPath({
18306
+ agentVersionId,
18307
+ automationVersionId,
18308
+ leafPath,
18309
+ runsPerPath
18310
+ }) {
18311
+ const path9 = `/pathway-regression/automation-versions/${encodeURIComponent(
18312
+ automationVersionId
18313
+ )}/agent-versions/${encodeURIComponent(agentVersionId)}/${leafPath}`;
18314
+ if (runsPerPath === void 0) {
18315
+ return path9;
18316
+ }
18317
+ const queryParams = new URLSearchParams({
18318
+ runsPerPath: String(runsPerPath)
18319
+ });
18320
+ return `${path9}?${queryParams.toString()}`;
18321
+ }
17102
18322
  function applyAuthenticationHeaders({
17103
18323
  accessToken,
17104
18324
  allowOttoAuthorization,
@@ -17133,11 +18353,11 @@ function createMagicalApiClient({
17133
18353
  accessToken,
17134
18354
  impersonatedOrganizationId,
17135
18355
  allowOttoAuthorization,
17136
- path: path8,
18356
+ path: path9,
17137
18357
  init,
17138
18358
  organizationId
17139
18359
  }) {
17140
- const url = `${trimTrailingSlash(await resolveApiBaseUrl())}${path8}`;
18360
+ const url = `${trimTrailingSlash(await resolveApiBaseUrl())}${path9}`;
17141
18361
  const headers = new Headers(init?.headers);
17142
18362
  applyAuthenticationHeaders({
17143
18363
  accessToken,
@@ -17182,6 +18402,51 @@ function createMagicalApiClient({
17182
18402
  return responseBody;
17183
18403
  }
17184
18404
  return {
18405
+ async downloadFile({ outputPath, overwrite = false, url }) {
18406
+ if (!overwrite) {
18407
+ await assertOutputDoesNotExist(outputPath);
18408
+ }
18409
+ const temporaryPath = nodePath.join(
18410
+ nodePath.dirname(outputPath),
18411
+ `.${nodePath.basename(outputPath)}.${randomUUID()}.tmp`
18412
+ );
18413
+ await (async () => {
18414
+ const response = await fetchFn(url).catch((error) => {
18415
+ throw new CliError("Failed to download eval export.", {
18416
+ cause: error
18417
+ });
18418
+ });
18419
+ if (!response.ok) {
18420
+ throw new CliError(
18421
+ `Eval export download failed with status ${response.status}.`
18422
+ );
18423
+ }
18424
+ if (!response.body) {
18425
+ throw new CliError("Eval export download returned an empty body.");
18426
+ }
18427
+ await pipeline(
18428
+ Readable.fromWeb(response.body),
18429
+ createWriteStream(temporaryPath, { flags: "wx" })
18430
+ );
18431
+ if (overwrite) {
18432
+ await rename(temporaryPath, outputPath);
18433
+ return;
18434
+ }
18435
+ await link(temporaryPath, outputPath).catch((error) => {
18436
+ if (isFileAlreadyExistsError(error)) {
18437
+ throw new CliError(
18438
+ `Refusing to overwrite existing file "${outputPath}". Pass --force to authorize replacement.`,
18439
+ { cause: error }
18440
+ );
18441
+ }
18442
+ throw error;
18443
+ });
18444
+ await rm(temporaryPath, { force: true });
18445
+ })().catch(async (error) => {
18446
+ await rm(temporaryPath, { force: true });
18447
+ throw error;
18448
+ });
18449
+ },
17185
18450
  async executeGraphQl({
17186
18451
  accessToken,
17187
18452
  impersonatedOrganizationId,
@@ -17213,8 +18478,15 @@ function createMagicalApiClient({
17213
18478
  throw new CliError("GraphQL response payload was invalid.");
17214
18479
  }
17215
18480
  if (parsedResponse.data.errors && parsedResponse.data.errors.length > 0) {
17216
- throw new CliError(
17217
- parsedResponse.data.errors.map((error) => error.message).join("\n")
18481
+ const graphQlCodes = parsedResponse.data.errors.flatMap(
18482
+ (error) => error.extensions?.code ? [error.extensions.code] : []
18483
+ );
18484
+ throw new GraphQlResponseError(
18485
+ parsedResponse.data.errors.map((error) => error.message).join("\n"),
18486
+ {
18487
+ graphQlCodes,
18488
+ hasUnclassifiedGraphQlErrors: graphQlCodes.length !== parsedResponse.data.errors.length
18489
+ }
17218
18490
  );
17219
18491
  }
17220
18492
  return parsedResponse.data.data?.[resultKey] ?? null;
@@ -17287,6 +18559,111 @@ function createMagicalApiClient({
17287
18559
  throw new CliError("Organization authentications payload was invalid.");
17288
18560
  }
17289
18561
  return parsedResponse.data.authentications;
18562
+ },
18563
+ async previewPathwayRegressionMatchingRuns({
18564
+ accessToken,
18565
+ agentVersionId,
18566
+ automationVersionId,
18567
+ impersonatedOrganizationId,
18568
+ organizationId,
18569
+ runsPerPath
18570
+ }) {
18571
+ const parsedResponse = pathwayRegressionMatchingRunsResponseSchema.safeParse(
18572
+ await fetchJson({
18573
+ accessToken,
18574
+ allowOttoAuthorization: true,
18575
+ ...impersonatedOrganizationId ? { impersonatedOrganizationId } : {},
18576
+ ...organizationId ? { organizationId } : {},
18577
+ path: buildPathwayRegressionAgentVersionPath({
18578
+ agentVersionId,
18579
+ automationVersionId,
18580
+ leafPath: "matching-runs",
18581
+ ...runsPerPath === void 0 ? {} : { runsPerPath }
18582
+ })
18583
+ })
18584
+ );
18585
+ if (!parsedResponse.success) {
18586
+ throw new CliError(
18587
+ "Pathway regression matching-runs payload was invalid."
18588
+ );
18589
+ }
18590
+ return parsedResponse.data;
18591
+ },
18592
+ async startPathwayRegressionAgentVersionRun({
18593
+ accessToken,
18594
+ agentVersionId,
18595
+ automationVersionId,
18596
+ impersonatedOrganizationId,
18597
+ organizationId,
18598
+ runsPerPath
18599
+ }) {
18600
+ const parsedResponse = pathwayRegressionAgentVersionRunResponseSchema.safeParse(
18601
+ await fetchJson({
18602
+ accessToken,
18603
+ allowOttoAuthorization: true,
18604
+ ...impersonatedOrganizationId ? { impersonatedOrganizationId } : {},
18605
+ ...organizationId ? { organizationId } : {},
18606
+ path: buildPathwayRegressionAgentVersionPath({
18607
+ agentVersionId,
18608
+ automationVersionId,
18609
+ leafPath: "run",
18610
+ ...runsPerPath === void 0 ? {} : { runsPerPath }
18611
+ }),
18612
+ init: {
18613
+ method: "POST"
18614
+ }
18615
+ })
18616
+ );
18617
+ if (!parsedResponse.success) {
18618
+ throw new CliError("Pathway regression kickoff payload was invalid.");
18619
+ }
18620
+ return parsedResponse.data;
18621
+ },
18622
+ async getPathwayRegressionRunResult({
18623
+ accessToken,
18624
+ impersonatedOrganizationId,
18625
+ organizationId,
18626
+ regressionRunId
18627
+ }) {
18628
+ const parsedResponse = pathwayRegressionRunResultResponseSchema.safeParse(
18629
+ await fetchJson({
18630
+ accessToken,
18631
+ allowOttoAuthorization: true,
18632
+ ...impersonatedOrganizationId ? { impersonatedOrganizationId } : {},
18633
+ ...organizationId ? { organizationId } : {},
18634
+ path: `/pathway-regression/runs/${encodeURIComponent(
18635
+ regressionRunId
18636
+ )}`
18637
+ })
18638
+ );
18639
+ if (!parsedResponse.success) {
18640
+ throw new CliError("Pathway regression run payload was invalid.");
18641
+ }
18642
+ return parsedResponse.data;
18643
+ },
18644
+ async getPathwayRegressionReplayIterationCheckResults({
18645
+ accessToken,
18646
+ impersonatedOrganizationId,
18647
+ organizationId,
18648
+ regressionReplayIterationId
18649
+ }) {
18650
+ const parsedResponse = pathwayRegressionReplayIterationCheckResultsResponseSchema.safeParse(
18651
+ await fetchJson({
18652
+ accessToken,
18653
+ allowOttoAuthorization: true,
18654
+ ...impersonatedOrganizationId ? { impersonatedOrganizationId } : {},
18655
+ ...organizationId ? { organizationId } : {},
18656
+ path: `/pathway-regression/replay-iterations/${encodeURIComponent(
18657
+ regressionReplayIterationId
18658
+ )}/check-results`
18659
+ })
18660
+ );
18661
+ if (!parsedResponse.success) {
18662
+ throw new CliError(
18663
+ "Pathway regression replay iteration check-results payload was invalid."
18664
+ );
18665
+ }
18666
+ return parsedResponse.data;
17290
18667
  }
17291
18668
  };
17292
18669
  }
@@ -17372,7 +18749,7 @@ function requireWorkosClientId(config) {
17372
18749
  }
17373
18750
 
17374
18751
  // src/settings.ts
17375
- import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
18752
+ import { mkdir, readFile, rm as rm2, writeFile } from "node:fs/promises";
17376
18753
  import path3 from "node:path";
17377
18754
  import { z as z27 } from "zod";
17378
18755
  var cliSettingsSchema = z27.object({
@@ -17431,7 +18808,7 @@ function createFileSettingsStore(stateFilePath) {
17431
18808
  },
17432
18809
  async save(settings) {
17433
18810
  if (!hasCliSettingsOverrides(settings)) {
17434
- await rm(settingsFilePath, { force: true });
18811
+ await rm2(settingsFilePath, { force: true });
17435
18812
  return;
17436
18813
  }
17437
18814
  await mkdir(path3.dirname(settingsFilePath), { recursive: true });
@@ -17520,6 +18897,7 @@ var rootOperationalGroupDescriptions = /* @__PURE__ */ new Map([
17520
18897
  ["automations", "Manage automations."],
17521
18898
  ["automation-runs", "Inspect and control automation runs."],
17522
18899
  ["catalog", "Inspect available commands, models, and tools."],
18900
+ ["evals", "Discover registered evals and manage eval runs."],
17523
18901
  ["graphql", "Inspect GraphQL metadata."],
17524
18902
  ["skills", "Inspect and update root-level Workplace skills."]
17525
18903
  ]);
@@ -17529,29 +18907,525 @@ function configureCommandPresentation(command) {
17529
18907
  command.createHelp = () => new MagicalHelp();
17530
18908
  return command;
17531
18909
  }
17532
- function createOperationHelpExamples(operationSpec) {
17533
- const baseCommand = `mgcl ${operationSpec.cli.path.join(" ")}`;
17534
- const requiredOptions = operationSpec.cli.options.filter((optionSpec) => optionSpec.required).map((optionSpec) => {
17535
- if (optionSpec.valueType === "boolean") {
17536
- return `--${optionSpec.flagName}`;
18910
+ function createOperationHelpExamples(operationSpec) {
18911
+ const commandPath = operationSpec.cli.path.join(" ");
18912
+ const baseCommand = operationSpec.cli.branchContext === "required" ? `mgcl --branch-id <branch-id> ${commandPath}` : `mgcl ${commandPath}`;
18913
+ const requiredOptions = operationSpec.cli.options.filter((optionSpec) => optionSpec.required).map((optionSpec) => {
18914
+ if (optionSpec.valueType === "boolean") {
18915
+ return `--${optionSpec.flagName}`;
18916
+ }
18917
+ if (optionSpec.valueType === "number") {
18918
+ return `--${optionSpec.flagName} 10`;
18919
+ }
18920
+ if (optionSpec.valueType === "json") {
18921
+ return `--${optionSpec.flagName} '{...}'`;
18922
+ }
18923
+ if (optionSpec.valueType === "string-array") {
18924
+ return `--${optionSpec.flagName} value-a,value-b`;
18925
+ }
18926
+ return `--${optionSpec.flagName} <${optionSpec.flagName}>`;
18927
+ });
18928
+ const baseInvocation = [baseCommand, ...requiredOptions].join(" ");
18929
+ return [
18930
+ baseInvocation,
18931
+ ...operationSpec.scope === "global" ? [] : [`${baseInvocation} --org <org>`],
18932
+ `${baseInvocation} --json`,
18933
+ ...operationSpec.cli.branchContext === "optional" ? [
18934
+ [
18935
+ "mgcl --branch-id <branch-id>",
18936
+ commandPath,
18937
+ ...requiredOptions,
18938
+ "--json"
18939
+ ].join(" ")
18940
+ ] : []
18941
+ ];
18942
+ }
18943
+
18944
+ // src/eval-commands.ts
18945
+ import { randomUUID as randomUUID2 } from "node:crypto";
18946
+ import { access as access2, readFile as readFile2 } from "node:fs/promises";
18947
+ import path4 from "node:path";
18948
+ import { createInterface } from "node:readline/promises";
18949
+ import { z as z28 } from "zod";
18950
+ var MAX_AWAIT_REQUEST_MS = 6e4;
18951
+ var MIN_AWAIT_REQUEST_MS = 1e3;
18952
+ var EXPORT_POLL_INTERVAL_MS = 1e3;
18953
+ var evalRunStatusSchema2 = z28.enum([
18954
+ "QUEUED",
18955
+ "RUNNING",
18956
+ "COMPLETE",
18957
+ "FAILED",
18958
+ "CANCELLED"
18959
+ ]);
18960
+ var awaitResultSchema = z28.object({
18961
+ elapsedMs: z28.number().nonnegative(),
18962
+ evalRun: z28.object({
18963
+ id: z28.string().min(1),
18964
+ status: evalRunStatusSchema2
18965
+ }).passthrough(),
18966
+ pollCount: z28.number().int().nonnegative(),
18967
+ reachedTerminal: z28.boolean()
18968
+ }).passthrough();
18969
+ var planResultSchema = z28.object({ trialCount: z28.number().int().nonnegative() }).passthrough();
18970
+ var startResultSchema = z28.object({
18971
+ evalRunId: z28.string().min(1),
18972
+ idempotencyKey: z28.string().min(1),
18973
+ workflowId: z28.string().min(1),
18974
+ workflowRunId: z28.string().min(1)
18975
+ }).passthrough();
18976
+ var exportResultSchema = z28.object({
18977
+ downloadUrl: z28.string().min(1).nullable().optional(),
18978
+ evalRunId: z28.string().min(1),
18979
+ exportId: z28.string().min(1),
18980
+ status: z28.enum(["QUEUED", "RUNNING", "COMPLETE", "FAILED"])
18981
+ }).passthrough();
18982
+ var inputOptionsSchema = z28.object({
18983
+ inputFile: z28.string().min(1).optional(),
18984
+ inputJson: z28.unknown().optional()
18985
+ });
18986
+ var commonRunOptionsSchema = inputOptionsSchema.extend({
18987
+ description: z28.string().min(1).optional(),
18988
+ maxConcurrency: z28.number().int().positive().optional(),
18989
+ name: z28.string().min(1).optional(),
18990
+ repeatCount: z28.number().int().positive().optional(),
18991
+ slug: z28.string().min(1),
18992
+ tags: z28.array(z28.string().min(1)).optional()
18993
+ });
18994
+ function parseApiResult(value, schema, label) {
18995
+ const parsedResult = schema.safeParse(value);
18996
+ if (!parsedResult.success) {
18997
+ throw new CliError(`${label} returned an invalid response.`);
18998
+ }
18999
+ return parsedResult.data;
19000
+ }
19001
+ async function parseInputFile({
19002
+ inputFile,
19003
+ workingDirectory
19004
+ }) {
19005
+ const inputPath = path4.resolve(workingDirectory, inputFile);
19006
+ const contents = await readFile2(inputPath, "utf8").catch(
19007
+ (error) => {
19008
+ throw new CliError(`Failed to read eval input file "${inputPath}".`, {
19009
+ cause: error
19010
+ });
19011
+ }
19012
+ );
19013
+ const parsedJson = safeJsonParseWithoutLogging(contents);
19014
+ if (isErr(parsedJson)) {
19015
+ throw new CliError(
19016
+ `Eval input file "${inputPath}" must contain valid JSON.`,
19017
+ { cause: parsedJson.error }
19018
+ );
19019
+ }
19020
+ return parsedJson.value;
19021
+ }
19022
+ async function resolveEvalInput({
19023
+ inputFile,
19024
+ inputJson,
19025
+ workingDirectory
19026
+ }) {
19027
+ const inputSourceCount = Number(inputFile !== void 0) + Number(inputJson !== void 0);
19028
+ if (inputSourceCount !== 1) {
19029
+ throw new CliError(
19030
+ "Pass exactly one of --input-file or --input-json for eval input."
19031
+ );
19032
+ }
19033
+ const input = inputFile === void 0 ? inputJson : await parseInputFile({ inputFile, workingDirectory });
19034
+ const parsedInput = z28.record(z28.string(), z28.unknown()).safeParse(input);
19035
+ if (!parsedInput.success) {
19036
+ throw new CliError("Eval input must be a JSON object.");
19037
+ }
19038
+ return parsedInput.data;
19039
+ }
19040
+ async function resolveEvalInputFromOptions({
19041
+ inputFile,
19042
+ inputJson,
19043
+ workingDirectory
19044
+ }) {
19045
+ return await resolveEvalInput({
19046
+ ...inputFile === void 0 ? {} : { inputFile },
19047
+ ...inputJson === void 0 ? {} : { inputJson },
19048
+ workingDirectory
19049
+ });
19050
+ }
19051
+ function buildCommonRunVariables({
19052
+ input,
19053
+ options
19054
+ }) {
19055
+ return {
19056
+ input,
19057
+ slug: options.slug,
19058
+ ...options.description === void 0 ? {} : { description: options.description },
19059
+ ...options.maxConcurrency === void 0 ? {} : { maxConcurrency: options.maxConcurrency },
19060
+ ...options.name === void 0 ? {} : { name: options.name },
19061
+ ...options.repeatCount === void 0 ? {} : { repeatCount: options.repeatCount },
19062
+ ...options.tags === void 0 ? {} : { tags: options.tags }
19063
+ };
19064
+ }
19065
+ function parseDurationMs(value) {
19066
+ const match = /^(?<amount>\d+(?:\.\d+)?)(?<unit>ms|s|m|h)$/iu.exec(
19067
+ value.trim()
19068
+ );
19069
+ const amount = Number(match?.groups?.["amount"]);
19070
+ const multiplierByUnit = { h: 36e5, m: 6e4, ms: 1, s: 1e3 };
19071
+ const parsedUnit = z28.enum(["h", "m", "ms", "s"]).safeParse(match?.groups?.["unit"]?.toLowerCase());
19072
+ const durationMs = parsedUnit.success ? amount * multiplierByUnit[parsedUnit.data] : Number.NaN;
19073
+ if (!Number.isSafeInteger(durationMs) || durationMs < MIN_AWAIT_REQUEST_MS) {
19074
+ throw new CliError(
19075
+ "Expected --timeout to be a duration of at least 1s, such as 30s, 5m, or 1h."
19076
+ );
19077
+ }
19078
+ return durationMs;
19079
+ }
19080
+ function quotePosixShellArgument(value) {
19081
+ return `'${value.replaceAll("'", `'"'"'`)}'`;
19082
+ }
19083
+ async function defaultConfirm(question) {
19084
+ const prompt = createInterface({
19085
+ input: process.stdin,
19086
+ output: process.stdout
19087
+ });
19088
+ const answer = await prompt.question(`${question} [y/N] `).finally(() => {
19089
+ prompt.close();
19090
+ });
19091
+ return answer.trim().toLowerCase() === "y" || answer.trim().toLowerCase() === "yes";
19092
+ }
19093
+ function terminalExitError(result) {
19094
+ const { id, status } = result.evalRun;
19095
+ if (status === "FAILED" || status === "CANCELLED") {
19096
+ return new CliError(`Eval run "${id}" finished with status ${status}.`);
19097
+ }
19098
+ return void 0;
19099
+ }
19100
+ async function awaitEvalRun({
19101
+ evalRunId,
19102
+ executeOperation,
19103
+ now: now2,
19104
+ timeoutMs
19105
+ }) {
19106
+ const deadline = timeoutMs === void 0 ? void 0 : now2() + timeoutMs;
19107
+ let previousResult = void 0;
19108
+ for (; ; ) {
19109
+ const remainingMs = deadline === void 0 ? void 0 : deadline - now2();
19110
+ if (remainingMs !== void 0 && remainingMs < MIN_AWAIT_REQUEST_MS) {
19111
+ return {
19112
+ exitError: new CliError(
19113
+ `Timed out waiting for eval run "${evalRunId}".`
19114
+ ),
19115
+ result: previousResult ?? {
19116
+ elapsedMs: timeoutMs ?? 0,
19117
+ evalRun: { id: evalRunId, status: "QUEUED" },
19118
+ pollCount: 0,
19119
+ reachedTerminal: false
19120
+ }
19121
+ };
19122
+ }
19123
+ const requestTimeoutMs = Math.min(
19124
+ MAX_AWAIT_REQUEST_MS,
19125
+ remainingMs ?? MAX_AWAIT_REQUEST_MS
19126
+ );
19127
+ const result = parseApiResult(
19128
+ // eslint-disable-next-line no-await-in-loop -- each long-poll must finish before the next bounded request begins
19129
+ await executeOperation("AwaitEvalRun", {
19130
+ id: evalRunId,
19131
+ timeoutMs: requestTimeoutMs
19132
+ }),
19133
+ awaitResultSchema,
19134
+ "Eval run await"
19135
+ );
19136
+ if (result.reachedTerminal) {
19137
+ const exitError = terminalExitError(result);
19138
+ return { ...exitError ? { exitError } : {}, result };
19139
+ }
19140
+ previousResult = result;
19141
+ }
19142
+ }
19143
+ async function assertExportOutputAvailable({
19144
+ force,
19145
+ outputPath
19146
+ }) {
19147
+ if (force) {
19148
+ return;
19149
+ }
19150
+ const exists = await access2(outputPath).then(() => true).catch((error) => {
19151
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
19152
+ return false;
19153
+ }
19154
+ throw new CliError(`Failed to inspect export path "${outputPath}".`, {
19155
+ cause: error
19156
+ });
19157
+ });
19158
+ if (exists) {
19159
+ throw new CliError(
19160
+ `Refusing to overwrite existing file "${outputPath}". Pass --force to authorize replacement.`
19161
+ );
19162
+ }
19163
+ }
19164
+ async function finishExport({
19165
+ downloadFile,
19166
+ exportResult,
19167
+ force,
19168
+ outputPath
19169
+ }) {
19170
+ if (exportResult.status === "FAILED") {
19171
+ return {
19172
+ exitError: new CliError(`Eval export "${exportResult.exportId}" failed.`),
19173
+ result: exportResult
19174
+ };
19175
+ }
19176
+ if (exportResult.status !== "COMPLETE") {
19177
+ return { result: exportResult };
19178
+ }
19179
+ if (!exportResult.downloadUrl) {
19180
+ throw new CliError(
19181
+ `Completed eval export "${exportResult.exportId}" did not include a download URL.`
19182
+ );
19183
+ }
19184
+ if (!downloadFile) {
19185
+ throw new CliError("Eval export download is not configured.");
19186
+ }
19187
+ await downloadFile({
19188
+ outputPath,
19189
+ overwrite: force,
19190
+ url: exportResult.downloadUrl
19191
+ });
19192
+ const { downloadUrl: _downloadUrl, ...downloadedExport } = exportResult;
19193
+ return { result: { ...downloadedExport, outputPath } };
19194
+ }
19195
+ async function pollExport({
19196
+ executeOperation,
19197
+ exportId,
19198
+ sleep
19199
+ }) {
19200
+ for (; ; ) {
19201
+ await sleep(EXPORT_POLL_INTERVAL_MS);
19202
+ const result = parseApiResult(
19203
+ // eslint-disable-next-line no-await-in-loop -- do not overlap signed-export status requests
19204
+ await executeOperation("GetEvalRunExport", { exportId }),
19205
+ exportResultSchema,
19206
+ "Eval export status"
19207
+ );
19208
+ if (result.status !== "QUEUED" && result.status !== "RUNNING") {
19209
+ return result;
19210
+ }
19211
+ }
19212
+ }
19213
+ async function executeTestRegisteredEval({
19214
+ executeOperation,
19215
+ options,
19216
+ workingDirectory
19217
+ }) {
19218
+ const parsedOptions = commonRunOptionsSchema.pick({ slug: true }).merge(inputOptionsSchema).parse(options);
19219
+ const input = await resolveEvalInputFromOptions({
19220
+ ...parsedOptions,
19221
+ workingDirectory
19222
+ });
19223
+ return {
19224
+ result: await executeOperation("TestRegisteredEval", {
19225
+ input,
19226
+ slug: parsedOptions.slug
19227
+ })
19228
+ };
19229
+ }
19230
+ async function executePlanRegisteredEvalRun({
19231
+ executeOperation,
19232
+ options,
19233
+ workingDirectory
19234
+ }) {
19235
+ const parsedOptions = commonRunOptionsSchema.parse(options);
19236
+ const input = await resolveEvalInputFromOptions({
19237
+ ...parsedOptions,
19238
+ workingDirectory
19239
+ });
19240
+ return {
19241
+ result: await executeOperation(
19242
+ "PlanRegisteredEvalRun",
19243
+ buildCommonRunVariables({ input, options: parsedOptions })
19244
+ )
19245
+ };
19246
+ }
19247
+ async function confirmPlannedTrialCount({
19248
+ confirm,
19249
+ confirmedTrialCount,
19250
+ isInteractive,
19251
+ json,
19252
+ trialCount
19253
+ }) {
19254
+ if (confirmedTrialCount !== void 0) {
19255
+ if (confirmedTrialCount !== trialCount) {
19256
+ throw new CliError(
19257
+ `Planned ${trialCount} trials, but --confirm-trials was ${confirmedTrialCount}.`
19258
+ );
19259
+ }
19260
+ return;
19261
+ }
19262
+ if (json || !isInteractive) {
19263
+ throw new CliError(
19264
+ `This run will start ${trialCount} trials. Pass --confirm-trials ${trialCount} in non-interactive mode.`
19265
+ );
19266
+ }
19267
+ const confirmed = await confirm(`Start ${trialCount} eval trials?`);
19268
+ if (confirmed) {
19269
+ return;
19270
+ }
19271
+ throw new CliError("Eval run cancelled before starting.");
19272
+ }
19273
+ async function executeStartRegisteredEvalRun({
19274
+ executeOperation,
19275
+ options,
19276
+ runtime,
19277
+ workingDirectory
19278
+ }) {
19279
+ const parsedOptions = commonRunOptionsSchema.extend({
19280
+ confirmTrials: z28.number().int().positive().optional(),
19281
+ idempotencyKey: z28.string().trim().min(1).optional(),
19282
+ json: z28.boolean().optional(),
19283
+ wait: z28.boolean().optional()
19284
+ }).parse(options);
19285
+ const input = await resolveEvalInputFromOptions({
19286
+ ...parsedOptions,
19287
+ workingDirectory
19288
+ });
19289
+ const commonVariables = buildCommonRunVariables({
19290
+ input,
19291
+ options: parsedOptions
19292
+ });
19293
+ const plan = parseApiResult(
19294
+ await executeOperation("PlanRegisteredEvalRun", commonVariables),
19295
+ planResultSchema,
19296
+ "Eval run plan"
19297
+ );
19298
+ await confirmPlannedTrialCount({
19299
+ confirm: runtime.confirm ?? defaultConfirm,
19300
+ ...parsedOptions.confirmTrials === void 0 ? {} : { confirmedTrialCount: parsedOptions.confirmTrials },
19301
+ isInteractive: runtime.isInteractive?.() ?? (process.stdin.isTTY && process.stdout.isTTY),
19302
+ json: parsedOptions.json === true,
19303
+ trialCount: plan.trialCount
19304
+ });
19305
+ const idempotencyKey = parsedOptions.idempotencyKey ?? `mgcl-eval-${(runtime.randomUuid ?? randomUUID2)()}`;
19306
+ const start = await executeOperation("StartRegisteredEvalRun", {
19307
+ ...commonVariables,
19308
+ expectedTrialCount: plan.trialCount,
19309
+ idempotencyKey
19310
+ }).catch((error) => {
19311
+ if (isDefinitiveGraphQlApplicationError(error)) {
19312
+ throw error;
19313
+ }
19314
+ throw new CliError(
19315
+ `${getErrorMessage(error)}
19316
+ If execution was accepted, retry with --idempotency-key ${quotePosixShellArgument(idempotencyKey)} to resolve the request safely.`,
19317
+ { cause: error }
19318
+ );
19319
+ });
19320
+ const parsedStart = parseApiResult(
19321
+ start,
19322
+ startResultSchema,
19323
+ "Eval run start"
19324
+ );
19325
+ if (parsedOptions.wait !== true) {
19326
+ return { result: parsedStart };
19327
+ }
19328
+ const awaited = await awaitEvalRun({
19329
+ evalRunId: parsedStart.evalRunId,
19330
+ executeOperation,
19331
+ now: runtime.now ?? Date.now
19332
+ });
19333
+ return {
19334
+ ...awaited.exitError ? { exitError: awaited.exitError } : {},
19335
+ result: { ...parsedStart, await: awaited.result }
19336
+ };
19337
+ }
19338
+ async function executeAwaitEvalRun({
19339
+ executeOperation,
19340
+ options,
19341
+ runtime
19342
+ }) {
19343
+ const parsedOptions = z28.object({ id: z28.string().min(1), timeout: z28.string().optional() }).parse(options);
19344
+ return await awaitEvalRun({
19345
+ evalRunId: parsedOptions.id,
19346
+ executeOperation,
19347
+ now: runtime.now ?? Date.now,
19348
+ ...parsedOptions.timeout ? { timeoutMs: parseDurationMs(parsedOptions.timeout) } : {}
19349
+ });
19350
+ }
19351
+ async function defaultSleep(milliseconds) {
19352
+ await new Promise((resolve) => {
19353
+ setTimeout(resolve, milliseconds);
19354
+ });
19355
+ }
19356
+ async function executeRequestEvalRunExport({
19357
+ executeOperation,
19358
+ options,
19359
+ runtime,
19360
+ workingDirectory
19361
+ }) {
19362
+ const parsedOptions = z28.object({
19363
+ force: z28.boolean().optional(),
19364
+ id: z28.string().min(1),
19365
+ output: z28.string().min(1),
19366
+ wait: z28.boolean().optional()
19367
+ }).parse(options);
19368
+ const outputPath = path4.resolve(workingDirectory, parsedOptions.output);
19369
+ const force = parsedOptions.force === true;
19370
+ const shouldWait = parsedOptions.wait === true;
19371
+ if (shouldWait) {
19372
+ await assertExportOutputAvailable({ force, outputPath });
19373
+ }
19374
+ const requestedExport = parseApiResult(
19375
+ await executeOperation("RequestEvalRunExport", { id: parsedOptions.id }),
19376
+ exportResultSchema,
19377
+ "Eval export request"
19378
+ );
19379
+ if (!shouldWait) {
19380
+ return { result: requestedExport };
19381
+ }
19382
+ const exportResult = requestedExport.status === "QUEUED" || requestedExport.status === "RUNNING" ? await pollExport({
19383
+ executeOperation,
19384
+ exportId: requestedExport.exportId,
19385
+ sleep: runtime.sleep ?? defaultSleep
19386
+ }) : requestedExport;
19387
+ if (exportResult.status === "QUEUED" || exportResult.status === "RUNNING") {
19388
+ return { result: exportResult };
19389
+ }
19390
+ return await finishExport({
19391
+ ...runtime.downloadFile ? { downloadFile: runtime.downloadFile } : {},
19392
+ exportResult,
19393
+ force,
19394
+ outputPath
19395
+ });
19396
+ }
19397
+ async function executeEvalCliOperation({
19398
+ executeOperation,
19399
+ operationName,
19400
+ options,
19401
+ runtime = {}
19402
+ }) {
19403
+ const handlerInput = {
19404
+ executeOperation,
19405
+ options,
19406
+ runtime,
19407
+ workingDirectory: runtime.workingDirectory ?? process.cwd()
19408
+ };
19409
+ switch (operationName) {
19410
+ case "TestRegisteredEval": {
19411
+ return await executeTestRegisteredEval(handlerInput);
17537
19412
  }
17538
- if (optionSpec.valueType === "number") {
17539
- return `--${optionSpec.flagName} 10`;
19413
+ case "PlanRegisteredEvalRun": {
19414
+ return await executePlanRegisteredEvalRun(handlerInput);
17540
19415
  }
17541
- if (optionSpec.valueType === "json") {
17542
- return `--${optionSpec.flagName} '{...}'`;
19416
+ case "StartRegisteredEvalRun": {
19417
+ return await executeStartRegisteredEvalRun(handlerInput);
17543
19418
  }
17544
- if (optionSpec.valueType === "string-array") {
17545
- return `--${optionSpec.flagName} value-a,value-b`;
19419
+ case "AwaitEvalRun": {
19420
+ return await executeAwaitEvalRun(handlerInput);
17546
19421
  }
17547
- return `--${optionSpec.flagName} <${optionSpec.flagName}>`;
17548
- });
17549
- const baseInvocation = [baseCommand, ...requiredOptions].join(" ");
17550
- return [
17551
- baseInvocation,
17552
- `${baseInvocation} --org <org>`,
17553
- `${baseInvocation} --json`
17554
- ];
19422
+ case "RequestEvalRunExport": {
19423
+ return await executeRequestEvalRunExport(handlerInput);
19424
+ }
19425
+ default: {
19426
+ return null;
19427
+ }
19428
+ }
17555
19429
  }
17556
19430
 
17557
19431
  // src/keychain.ts
@@ -17620,7 +19494,7 @@ function resolveOpenCommand(url) {
17620
19494
  }
17621
19495
 
17622
19496
  // src/program-session.ts
17623
- import { readFile as readFile2, rm as rm2 } from "node:fs/promises";
19497
+ import { readFile as readFile3, rm as rm3 } from "node:fs/promises";
17624
19498
  async function withOrgScopedAccessToken({
17625
19499
  dependencies,
17626
19500
  organizationId,
@@ -17633,6 +19507,35 @@ async function withOrgScopedAccessToken({
17633
19507
  if (directAccessToken) {
17634
19508
  return { accessToken: directAccessToken };
17635
19509
  }
19510
+ return await refreshAccessToken({
19511
+ dependencies,
19512
+ organizationId,
19513
+ state
19514
+ });
19515
+ }
19516
+ async function withGlobalAccessToken({
19517
+ authenticationOrganizationId,
19518
+ dependencies,
19519
+ state
19520
+ }) {
19521
+ const directAccessToken = await loadDirectAccessToken({
19522
+ dependencies,
19523
+ organizationId: authenticationOrganizationId
19524
+ });
19525
+ if (directAccessToken) {
19526
+ return { accessToken: directAccessToken };
19527
+ }
19528
+ return await refreshAccessToken({
19529
+ dependencies,
19530
+ organizationId: authenticationOrganizationId,
19531
+ state
19532
+ });
19533
+ }
19534
+ async function refreshAccessToken({
19535
+ dependencies,
19536
+ organizationId,
19537
+ state
19538
+ }) {
17636
19539
  const refreshToken = await dependencies.refreshTokenStore.load(state.account);
17637
19540
  if (!refreshToken) {
17638
19541
  throw new CliError(
@@ -17664,7 +19567,7 @@ async function clearDirectAccessToken(runtimeConfig) {
17664
19567
  if (!runtimeConfig.accessTokenFilePath) {
17665
19568
  return;
17666
19569
  }
17667
- await rm2(runtimeConfig.accessTokenFilePath, { force: true });
19570
+ await rm3(runtimeConfig.accessTokenFilePath, { force: true });
17668
19571
  }
17669
19572
  async function loadDirectAccessToken({
17670
19573
  dependencies,
@@ -17674,7 +19577,7 @@ async function loadDirectAccessToken({
17674
19577
  if (!accessTokenFilePath) {
17675
19578
  return null;
17676
19579
  }
17677
- const accessTokenFileContents = await readFile2(accessTokenFilePath, "utf8").then((value) => value.trim()).catch((error) => {
19580
+ const accessTokenFileContents = await readFile3(accessTokenFilePath, "utf8").then((value) => value.trim()).catch((error) => {
17678
19581
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
17679
19582
  return null;
17680
19583
  }
@@ -17701,7 +19604,7 @@ async function loadDirectAccessToken({
17701
19604
  }
17702
19605
  return null;
17703
19606
  }
17704
- if (claims.org_id && claims.org_id !== organizationId) {
19607
+ if (organizationId !== void 0 && claims.org_id && claims.org_id !== organizationId) {
17705
19608
  throw new CliError(
17706
19609
  `The current Otto session is authenticated for organization "${claims.org_id}", not "${organizationId}". Start a new Otto session from the desired organization.`
17707
19610
  );
@@ -17718,7 +19621,7 @@ function isExpiredAccessTokenClaims(claims) {
17718
19621
  // src/self-update.ts
17719
19622
  import { spawn as spawn2 } from "node:child_process";
17720
19623
  import fs2 from "node:fs";
17721
- import path4 from "node:path";
19624
+ import path5 from "node:path";
17722
19625
  import { fileURLToPath as fileURLToPath2 } from "node:url";
17723
19626
  var CLI_PACKAGE_NAME = "@getmagical/cli";
17724
19627
  var DEFAULT_CLI_DIST_TAG2 = "latest";
@@ -17729,9 +19632,9 @@ function resolveInstalledPackageRoot({
17729
19632
  packageName
17730
19633
  }) {
17731
19634
  const packagePathSegments = packageName.split("/");
17732
- let currentPath = path4.dirname(entryFilePath);
19635
+ let currentPath = path5.dirname(entryFilePath);
17733
19636
  for (; ; ) {
17734
- const currentPathSegments = currentPath.split(path4.sep).filter(Boolean);
19637
+ const currentPathSegments = currentPath.split(path5.sep).filter(Boolean);
17735
19638
  const currentPackageSegments = currentPathSegments.slice(
17736
19639
  -packagePathSegments.length
17737
19640
  );
@@ -17740,7 +19643,7 @@ function resolveInstalledPackageRoot({
17740
19643
  )) {
17741
19644
  return currentPath;
17742
19645
  }
17743
- const parentPath = path4.dirname(currentPath);
19646
+ const parentPath = path5.dirname(currentPath);
17744
19647
  if (parentPath === currentPath) {
17745
19648
  return null;
17746
19649
  }
@@ -17750,14 +19653,14 @@ function resolveInstalledPackageRoot({
17750
19653
  function resolveInstallPrefixFromPackageRoot(packageRootPath) {
17751
19654
  let currentPath = packageRootPath;
17752
19655
  for (; ; ) {
17753
- if (path4.basename(currentPath) === "node_modules") {
17754
- const nodeModulesParentPath = path4.dirname(currentPath);
17755
- if (path4.basename(nodeModulesParentPath) === "lib") {
17756
- return path4.dirname(nodeModulesParentPath);
19656
+ if (path5.basename(currentPath) === "node_modules") {
19657
+ const nodeModulesParentPath = path5.dirname(currentPath);
19658
+ if (path5.basename(nodeModulesParentPath) === "lib") {
19659
+ return path5.dirname(nodeModulesParentPath);
17757
19660
  }
17758
19661
  return nodeModulesParentPath;
17759
19662
  }
17760
- const parentPath = path4.dirname(currentPath);
19663
+ const parentPath = path5.dirname(currentPath);
17761
19664
  if (parentPath === currentPath) {
17762
19665
  return null;
17763
19666
  }
@@ -17774,13 +19677,13 @@ function resolveManagedNpmCommand(installPrefix) {
17774
19677
  if (process.platform === "win32") {
17775
19678
  return null;
17776
19679
  }
17777
- const managedNodeExecutable = path4.join(
19680
+ const managedNodeExecutable = path5.join(
17778
19681
  installPrefix,
17779
19682
  MANAGED_NODE_SUBPATH,
17780
19683
  "bin",
17781
19684
  "node"
17782
19685
  );
17783
- const managedNpmCli = path4.join(
19686
+ const managedNpmCli = path5.join(
17784
19687
  installPrefix,
17785
19688
  MANAGED_NODE_SUBPATH,
17786
19689
  "lib",
@@ -17979,20 +19882,20 @@ ${formatExamples("Examples", [
17979
19882
 
17980
19883
  // src/skills-working-copy.ts
17981
19884
  import { execFile } from "node:child_process";
17982
- import { createHash, randomUUID } from "node:crypto";
19885
+ import { createHash, randomUUID as randomUUID3 } from "node:crypto";
17983
19886
  import {
17984
19887
  lstat,
17985
19888
  mkdir as mkdir2,
17986
19889
  mkdtemp,
17987
- readFile as readFile3,
19890
+ readFile as readFile4,
17988
19891
  readdir,
17989
- rename,
17990
- rm as rm3,
19892
+ rename as rename2,
19893
+ rm as rm4,
17991
19894
  writeFile as writeFile2
17992
19895
  } from "node:fs/promises";
17993
19896
  import os2 from "node:os";
17994
- import path5 from "node:path";
17995
- import { z as z28 } from "zod";
19897
+ import path6 from "node:path";
19898
+ import { z as z29 } from "zod";
17996
19899
  var SKILLS_ROOT_PATH = "skills";
17997
19900
  var METADATA_DIRECTORY_NAME = "skill-working-copies";
17998
19901
  var MAX_GIT_OUTPUT_BYTES = 10 * 1024 * 1024;
@@ -18001,40 +19904,40 @@ var FULL_COMMIT_SHA_PATTERN = /^[\dA-Fa-f]{40}$/u;
18001
19904
  var UTF8_ENCODER = new TextEncoder();
18002
19905
  var WINDOWS_RESERVED_PATH_CHARACTER_PATTERN = /[<>:"|?*]/u;
18003
19906
  var WINDOWS_RESERVED_PATH_NAME_PATTERN = /^(?:AUX|CON|NUL|PRN|COM[1-9]|LPT[1-9])(?:\..*)?$/iu;
18004
- var skillBundleSchema = z28.object({
18005
- files: z28.array(
18006
- z28.object({
18007
- content: z28.string(),
18008
- encoding: z28.literal("base64"),
18009
- path: z28.string().min(1),
18010
- size: z28.number().int().nonnegative()
19907
+ var skillBundleSchema = z29.object({
19908
+ files: z29.array(
19909
+ z29.object({
19910
+ content: z29.string(),
19911
+ encoding: z29.literal("base64"),
19912
+ path: z29.string().min(1),
19913
+ size: z29.number().int().nonnegative()
18011
19914
  })
18012
19915
  ),
18013
- path: z28.string().min(1),
18014
- ref: z28.string().regex(FULL_COMMIT_SHA_PATTERN)
19916
+ path: z29.string().min(1),
19917
+ ref: z29.string().regex(FULL_COMMIT_SHA_PATTERN)
18015
19918
  });
18016
- var skillsApplyPatchResultSchema = z28.object({
18017
- changedFiles: z28.array(
18018
- z28.object({ path: z28.string().min(1), status: z28.string().min(1) })
19919
+ var skillsApplyPatchResultSchema = z29.object({
19920
+ changedFiles: z29.array(
19921
+ z29.object({ path: z29.string().min(1), status: z29.string().min(1) })
18019
19922
  ),
18020
- commit: z28.string().regex(FULL_COMMIT_SHA_PATTERN),
18021
- ok: z28.boolean(),
18022
- ref: z28.string().min(1)
19923
+ commit: z29.string().regex(FULL_COMMIT_SHA_PATTERN),
19924
+ ok: z29.boolean(),
19925
+ ref: z29.string().min(1)
18023
19926
  }).refine((result) => result.ok, {
18024
19927
  message: "Skills patch result was not successful."
18025
19928
  });
18026
- var workingCopyMetadataSchema = z28.object({
18027
- version: z28.literal(1),
18028
- files: z28.array(
18029
- z28.object({
18030
- content: z28.string(),
18031
- path: z28.string().min(1)
19929
+ var workingCopyMetadataSchema = z29.object({
19930
+ version: z29.literal(1),
19931
+ files: z29.array(
19932
+ z29.object({
19933
+ content: z29.string(),
19934
+ path: z29.string().min(1)
18032
19935
  })
18033
19936
  ),
18034
- organizationId: z28.string().min(1),
18035
- requestedRef: z28.string().min(1).nullable(),
18036
- skillPath: z28.string().min(1),
18037
- workingCopyPath: z28.string().min(1)
19937
+ organizationId: z29.string().min(1),
19938
+ requestedRef: z29.string().min(1).nullable(),
19939
+ skillPath: z29.string().min(1),
19940
+ workingCopyPath: z29.string().min(1)
18038
19941
  });
18039
19942
  function hasControlCharacter2(value) {
18040
19943
  return UTF8_ENCODER.encode(value).some((byte) => byte <= 31 || byte === 127);
@@ -18062,12 +19965,12 @@ function normalizeRootSkillPath(skill) {
18062
19965
  return `${SKILLS_ROOT_PATH}/${skillName}`;
18063
19966
  }
18064
19967
  function resolveWorkingCopyPath(workingDirectory, skillPath) {
18065
- return path5.resolve(workingDirectory, ...skillPath.split("/"));
19968
+ return path6.resolve(workingDirectory, ...skillPath.split("/"));
18066
19969
  }
18067
19970
  function resolveMetadataPath(stateFilePath, workingCopyPath) {
18068
19971
  const key = createHash("sha256").update(workingCopyPath).digest("hex");
18069
- return path5.join(
18070
- path5.dirname(stateFilePath),
19972
+ return path6.join(
19973
+ path6.dirname(stateFilePath),
18071
19974
  METADATA_DIRECTORY_NAME,
18072
19975
  `${key}.json`
18073
19976
  );
@@ -18095,7 +19998,7 @@ function metadataFilesToSnapshot(files) {
18095
19998
  );
18096
19999
  }
18097
20000
  async function loadMetadata(metadataPath) {
18098
- const fileContents = await readFile3(metadataPath, "utf8").catch(
20001
+ const fileContents = await readFile4(metadataPath, "utf8").catch(
18099
20002
  (error) => {
18100
20003
  if (isMissingFileError(error)) {
18101
20004
  return null;
@@ -18119,13 +20022,13 @@ async function loadMetadata(metadataPath) {
18119
20022
  return parsed.data;
18120
20023
  }
18121
20024
  async function saveMetadata(metadataPath, metadata) {
18122
- await mkdir2(path5.dirname(metadataPath), { recursive: true });
18123
- const temporaryPath = `${metadataPath}.${randomUUID()}.tmp`;
20025
+ await mkdir2(path6.dirname(metadataPath), { recursive: true });
20026
+ const temporaryPath = `${metadataPath}.${randomUUID3()}.tmp`;
18124
20027
  await writeFile2(temporaryPath, `${JSON.stringify(metadata, null, 2)}
18125
20028
  `, {
18126
20029
  mode: 384
18127
20030
  });
18128
- await rename(temporaryPath, metadataPath);
20031
+ await rename2(temporaryPath, metadataPath);
18129
20032
  }
18130
20033
  function assertSafeRelativeFilePath(relativePath) {
18131
20034
  const segments = relativePath.split("/");
@@ -18196,7 +20099,7 @@ async function readDirectorySnapshot({
18196
20099
  const nextSegments = [...segments, entry.name];
18197
20100
  const relativePath = nextSegments.join("/");
18198
20101
  assertSafeRelativeFilePath(relativePath);
18199
- const filePath = path5.join(currentDirectory, entry.name);
20102
+ const filePath = path6.join(currentDirectory, entry.name);
18200
20103
  if (entry.isDirectory()) {
18201
20104
  return await visit(filePath, nextSegments);
18202
20105
  }
@@ -18205,7 +20108,7 @@ async function readDirectorySnapshot({
18205
20108
  `Skill working copy contains unsupported entry "${filePath}". Only regular files and directories are allowed.`
18206
20109
  );
18207
20110
  }
18208
- return [[`${skillPath}/${relativePath}`, await readFile3(filePath)]];
20111
+ return [[`${skillPath}/${relativePath}`, await readFile4(filePath)]];
18209
20112
  })
18210
20113
  );
18211
20114
  return nestedEntries.flat();
@@ -18231,8 +20134,8 @@ async function writeSnapshotContents(rootPath, snapshot, prefix) {
18231
20134
  [...snapshot.entries()].map(async ([filePath, content]) => {
18232
20135
  const relativePath = prefix === null ? filePath : filePath.slice(`${prefix}/`.length);
18233
20136
  assertSafeRelativeFilePath(relativePath);
18234
- const targetPath = path5.join(rootPath, ...relativePath.split("/"));
18235
- await mkdir2(path5.dirname(targetPath), { recursive: true });
20137
+ const targetPath = path6.join(rootPath, ...relativePath.split("/"));
20138
+ await mkdir2(path6.dirname(targetPath), { recursive: true });
18236
20139
  await writeFile2(targetPath, content);
18237
20140
  })
18238
20141
  );
@@ -18242,42 +20145,42 @@ async function replaceWorkingCopy({
18242
20145
  skillPath,
18243
20146
  workingCopyPath
18244
20147
  }) {
18245
- const parentPath = path5.dirname(workingCopyPath);
20148
+ const parentPath = path6.dirname(workingCopyPath);
18246
20149
  await mkdir2(parentPath, { recursive: true });
18247
- const temporaryPath = path5.join(
20150
+ const temporaryPath = path6.join(
18248
20151
  parentPath,
18249
- `.mgcl-${path5.basename(workingCopyPath)}-${randomUUID()}.tmp`
20152
+ `.mgcl-${path6.basename(workingCopyPath)}-${randomUUID3()}.tmp`
18250
20153
  );
18251
- const backupPath = `${workingCopyPath}.${randomUUID()}.bak`;
20154
+ const backupPath = `${workingCopyPath}.${randomUUID3()}.bak`;
18252
20155
  await mkdir2(temporaryPath);
18253
20156
  const prepareResult = await fromThrowable(async () => {
18254
20157
  await writeSnapshotContents(temporaryPath, snapshot, skillPath);
18255
20158
  const hadExistingWorkingCopy = await pathExists(workingCopyPath);
18256
20159
  if (hadExistingWorkingCopy) {
18257
- await rename(workingCopyPath, backupPath);
20160
+ await rename2(workingCopyPath, backupPath);
18258
20161
  }
18259
20162
  return hadExistingWorkingCopy;
18260
20163
  }, "skills-working-copy-replace-failed");
18261
20164
  if (isErr(prepareResult)) {
18262
- await rm3(temporaryPath, { force: true, recursive: true });
20165
+ await rm4(temporaryPath, { force: true, recursive: true });
18263
20166
  throw new CliError("Failed to replace the skill working copy.", {
18264
20167
  cause: prepareResult.error.cause
18265
20168
  });
18266
20169
  }
18267
20170
  const activationResult = await fromThrowable(async () => {
18268
- await rename(temporaryPath, workingCopyPath);
20171
+ await rename2(temporaryPath, workingCopyPath);
18269
20172
  }, "skills-working-copy-activation-failed");
18270
20173
  if (isErr(activationResult)) {
18271
20174
  if (prepareResult.value) {
18272
- await rename(backupPath, workingCopyPath);
20175
+ await rename2(backupPath, workingCopyPath);
18273
20176
  }
18274
- await rm3(temporaryPath, { force: true, recursive: true });
20177
+ await rm4(temporaryPath, { force: true, recursive: true });
18275
20178
  throw new CliError("Failed to activate the new skill working copy.", {
18276
20179
  cause: activationResult.error.cause
18277
20180
  });
18278
20181
  }
18279
20182
  if (prepareResult.value) {
18280
- await rm3(backupPath, { force: true, recursive: true });
20183
+ await rm4(backupPath, { force: true, recursive: true });
18281
20184
  }
18282
20185
  }
18283
20186
  async function runGit(arguments_, cwd, allowedExitCodes = [0]) {
@@ -18317,7 +20220,7 @@ async function clearDirectoryExceptGit(directoryPath) {
18317
20220
  const entries = await readdir(directoryPath);
18318
20221
  await Promise.all(
18319
20222
  entries.filter((entry) => entry !== ".git").map(async (entry) => {
18320
- await rm3(path5.join(directoryPath, entry), {
20223
+ await rm4(path6.join(directoryPath, entry), {
18321
20224
  force: true,
18322
20225
  recursive: true
18323
20226
  });
@@ -18329,7 +20232,7 @@ async function createPatch(before, after) {
18329
20232
  return "";
18330
20233
  }
18331
20234
  const repositoryPath = await mkdtemp(
18332
- path5.join(os2.tmpdir(), "mgcl-skills-diff-")
20235
+ path6.join(os2.tmpdir(), "mgcl-skills-diff-")
18333
20236
  );
18334
20237
  const patchResult = await fromThrowable(async () => {
18335
20238
  await runGit(["init", "--quiet"], repositoryPath);
@@ -18372,7 +20275,7 @@ async function createPatch(before, after) {
18372
20275
  );
18373
20276
  return result.stdout.toString("utf8");
18374
20277
  }, "skills-patch-generation-failed");
18375
- await rm3(repositoryPath, { force: true, recursive: true });
20278
+ await rm4(repositoryPath, { force: true, recursive: true });
18376
20279
  if (isErr(patchResult)) {
18377
20280
  throw patchResult.error.cause;
18378
20281
  }
@@ -18580,7 +20483,7 @@ async function pushSkillWorkingCopy({
18580
20483
  assertTextPatch(patchContents);
18581
20484
  const applyResult = await fromThrowable(
18582
20485
  async () => await context.api.applyPatch({
18583
- idempotencyKey: `mgcl-skills-${randomUUID()}`,
20486
+ idempotencyKey: `mgcl-skills-${randomUUID3()}`,
18584
20487
  message: message ?? `Update ${workingCopy.skillPath} via mgcl`,
18585
20488
  patch: patchContents
18586
20489
  }),
@@ -18651,34 +20554,34 @@ async function pushSkillWorkingCopy({
18651
20554
  }
18652
20555
 
18653
20556
  // src/state.ts
18654
- import { mkdir as mkdir3, readFile as readFile4, rm as rm4, writeFile as writeFile3 } from "node:fs/promises";
18655
- import path6 from "node:path";
18656
- import { z as z29 } from "zod";
18657
- var cliAccountSchema = z29.object({
18658
- clientId: z29.string().min(1),
18659
- email: z29.string().nullable(),
18660
- userId: z29.string().min(1)
20557
+ import { mkdir as mkdir3, readFile as readFile5, rm as rm5, writeFile as writeFile3 } from "node:fs/promises";
20558
+ import path7 from "node:path";
20559
+ import { z as z30 } from "zod";
20560
+ var cliAccountSchema = z30.object({
20561
+ clientId: z30.string().min(1),
20562
+ email: z30.string().nullable(),
20563
+ userId: z30.string().min(1)
18661
20564
  });
18662
- var cliOrganizationSchema = z29.object({
18663
- id: z29.string().min(1),
18664
- name: z29.string().min(1),
18665
- primaryDomain: z29.string().nullable().default(null)
20565
+ var cliOrganizationSchema = z30.object({
20566
+ id: z30.string().min(1),
20567
+ name: z30.string().min(1),
20568
+ primaryDomain: z30.string().nullable().default(null)
18666
20569
  });
18667
- var cliStateSchema = z29.object({
20570
+ var cliStateSchema = z30.object({
18668
20571
  account: cliAccountSchema,
18669
- defaultOrgId: z29.string().nullable(),
18670
- lastUsedOrgId: z29.string().nullable(),
18671
- organizations: z29.array(cliOrganizationSchema)
20572
+ defaultOrgId: z30.string().nullable(),
20573
+ lastUsedOrgId: z30.string().nullable(),
20574
+ organizations: z30.array(cliOrganizationSchema)
18672
20575
  });
18673
- var refreshTokenFileSchema = z29.record(z29.string(), z29.string());
20576
+ var refreshTokenFileSchema = z30.record(z30.string(), z30.string());
18674
20577
  function createFileStateStore(stateFilePath) {
18675
20578
  return {
18676
20579
  async clear() {
18677
- await rm4(stateFilePath, { force: true });
20580
+ await rm5(stateFilePath, { force: true });
18678
20581
  },
18679
20582
  async load() {
18680
20583
  try {
18681
- const fileContents = await readFile4(stateFilePath, "utf8");
20584
+ const fileContents = await readFile5(stateFilePath, "utf8");
18682
20585
  const parsed = cliStateSchema.safeParse(JSON.parse(fileContents));
18683
20586
  if (!parsed.success) {
18684
20587
  throw new CliError("Stored CLI state is invalid.");
@@ -18695,7 +20598,7 @@ function createFileStateStore(stateFilePath) {
18695
20598
  }
18696
20599
  },
18697
20600
  async save(state) {
18698
- await mkdir3(path6.dirname(stateFilePath), { recursive: true });
20601
+ await mkdir3(path7.dirname(stateFilePath), { recursive: true });
18699
20602
  await writeFile3(stateFilePath, `${JSON.stringify(state, null, 2)}
18700
20603
  `);
18701
20604
  }
@@ -18704,7 +20607,7 @@ function createFileStateStore(stateFilePath) {
18704
20607
  function createFileRefreshTokenStore(refreshTokenFilePath) {
18705
20608
  async function loadRefreshTokens() {
18706
20609
  try {
18707
- const fileContents = await readFile4(refreshTokenFilePath, "utf8");
20610
+ const fileContents = await readFile5(refreshTokenFilePath, "utf8");
18708
20611
  const parsed = refreshTokenFileSchema.safeParse(JSON.parse(fileContents));
18709
20612
  if (!parsed.success) {
18710
20613
  throw new CliError("Stored refresh tokens are invalid.");
@@ -18723,7 +20626,7 @@ function createFileRefreshTokenStore(refreshTokenFilePath) {
18723
20626
  }
18724
20627
  }
18725
20628
  async function saveRefreshTokens(refreshTokens) {
18726
- await mkdir3(path6.dirname(refreshTokenFilePath), { recursive: true });
20629
+ await mkdir3(path7.dirname(refreshTokenFilePath), { recursive: true });
18727
20630
  await writeFile3(
18728
20631
  refreshTokenFilePath,
18729
20632
  `${JSON.stringify(refreshTokens, null, 2)}
@@ -18740,7 +20643,7 @@ function createFileRefreshTokenStore(refreshTokenFilePath) {
18740
20643
  )
18741
20644
  );
18742
20645
  if (Object.keys(nextRefreshTokens).length === 0) {
18743
- await rm4(refreshTokenFilePath, { force: true });
20646
+ await rm5(refreshTokenFilePath, { force: true });
18744
20647
  return;
18745
20648
  }
18746
20649
  await saveRefreshTokens(nextRefreshTokens);
@@ -18761,37 +20664,37 @@ function buildRefreshTokenKey(account) {
18761
20664
  }
18762
20665
 
18763
20666
  // src/workos-auth.ts
18764
- import { z as z30 } from "zod";
20667
+ import { z as z31 } from "zod";
18765
20668
  var DEFAULT_DEVICE_POLL_INTERVAL_SECONDS = 5;
18766
20669
  function buildFormHeaders() {
18767
20670
  const headers = new Headers();
18768
20671
  headers.set("content-type", "application/x-www-form-urlencoded");
18769
20672
  return headers;
18770
20673
  }
18771
- var deviceAuthorizationSchema = z30.object({
18772
- device_code: z30.string().min(1),
18773
- expires_in: z30.number().int().positive().optional(),
18774
- interval: z30.number().int().positive().optional(),
18775
- user_code: z30.string().min(1),
18776
- verification_uri: z30.url(),
18777
- verification_uri_complete: z30.url().optional()
20674
+ var deviceAuthorizationSchema = z31.object({
20675
+ device_code: z31.string().min(1),
20676
+ expires_in: z31.number().int().positive().optional(),
20677
+ interval: z31.number().int().positive().optional(),
20678
+ user_code: z31.string().min(1),
20679
+ verification_uri: z31.url(),
20680
+ verification_uri_complete: z31.url().optional()
18778
20681
  });
18779
- var tokenResponseSchema = z30.object({
18780
- access_token: z30.string().min(1),
18781
- expires_in: z30.number().int().positive().optional(),
18782
- refresh_token: z30.string().min(1),
18783
- token_type: z30.string().optional()
20682
+ var tokenResponseSchema = z31.object({
20683
+ access_token: z31.string().min(1),
20684
+ expires_in: z31.number().int().positive().optional(),
20685
+ refresh_token: z31.string().min(1),
20686
+ token_type: z31.string().optional()
18784
20687
  });
18785
- var tokenErrorSchema = z30.object({
18786
- error: z30.string().min(1),
18787
- error_description: z30.string().optional()
20688
+ var tokenErrorSchema = z31.object({
20689
+ error: z31.string().min(1),
20690
+ error_description: z31.string().optional()
18788
20691
  });
18789
- var accessTokenClaimsSchema = z30.object({
18790
- exp: z30.number().int().positive().optional(),
18791
- iss: z30.string().min(1).optional(),
18792
- org_id: z30.string().min(1).optional(),
18793
- sid: z30.string().min(1).optional(),
18794
- sub: z30.string().min(1)
20692
+ var accessTokenClaimsSchema = z31.object({
20693
+ exp: z31.number().int().positive().optional(),
20694
+ iss: z31.string().min(1).optional(),
20695
+ org_id: z31.string().min(1).optional(),
20696
+ sid: z31.string().min(1).optional(),
20697
+ sub: z31.string().min(1)
18795
20698
  });
18796
20699
  function createWorkosAuthClient({
18797
20700
  fetchFn = fetch,
@@ -18934,6 +20837,7 @@ function createWorkosAuthClient({
18934
20837
  }
18935
20838
 
18936
20839
  // src/program.ts
20840
+ var commandBranchContexts = /* @__PURE__ */ new WeakMap();
18937
20841
  function buildCommandOptionProperty(flagName) {
18938
20842
  const [firstSegment, ...remainingSegments] = flagName.split("-");
18939
20843
  return [
@@ -18990,6 +20894,13 @@ function createCliCommanderOption(optionSpec, helpGroup) {
18990
20894
  }
18991
20895
  return nextOption;
18992
20896
  }
20897
+ function parsePositiveIntegerOption(rawValue) {
20898
+ const parsedValue = Number(rawValue);
20899
+ if (!Number.isInteger(parsedValue) || parsedValue < 1) {
20900
+ throw new InvalidArgumentError2("Expected a positive integer.");
20901
+ }
20902
+ return parsedValue;
20903
+ }
18993
20904
  function isRecord5(value) {
18994
20905
  return typeof value === "object" && value !== null && !Array.isArray(value);
18995
20906
  }
@@ -19044,6 +20955,9 @@ function requireApiClientMethod(apiClient, key) {
19044
20955
  function collectOperationVariables(operationSpec, options) {
19045
20956
  const variables = Object.fromEntries(
19046
20957
  operationSpec.cli.options.flatMap((optionSpec) => {
20958
+ if (optionSpec.clientOnly) {
20959
+ return [];
20960
+ }
19047
20961
  const optionValue = options[buildCommandOptionProperty(optionSpec.flagName)];
19048
20962
  if (optionValue === void 0) {
19049
20963
  return [];
@@ -19051,6 +20965,13 @@ function collectOperationVariables(operationSpec, options) {
19051
20965
  return [[optionSpec.inputKey, optionValue]];
19052
20966
  })
19053
20967
  );
20968
+ const { branchId } = options;
20969
+ if (operationSpec.cli.branchContext !== void 0 && typeof branchId === "string") {
20970
+ variables["branchId"] = branchId;
20971
+ }
20972
+ return parseOperationVariables(operationSpec, variables);
20973
+ }
20974
+ function parseOperationVariables(operationSpec, variables) {
19054
20975
  const parsedVariables = operationSpec.inputSchema.safeParse(variables);
19055
20976
  if (!parsedVariables.success) {
19056
20977
  throw new CliError(
@@ -19130,6 +21051,14 @@ async function handleSelfUpdate(dependencies, options) {
19130
21051
  );
19131
21052
  }
19132
21053
  async function handleOperationCommand(dependencies, operationSpec, commandOptions) {
21054
+ if (operationSpec.scope === "global") {
21055
+ await handleGlobalOperationCommand(
21056
+ dependencies,
21057
+ operationSpec,
21058
+ commandOptions
21059
+ );
21060
+ return;
21061
+ }
19133
21062
  const { accessToken, impersonatedOrganizationId, organization, state } = await withSelectedOrganizationAndAccessToken({
19134
21063
  dependencies,
19135
21064
  options: commandOptions
@@ -19153,16 +21082,89 @@ async function handleOperationCommand(dependencies, operationSpec, commandOption
19153
21082
  }
19154
21083
  dependencies.io.info(formatHumanReadableOutput(result));
19155
21084
  }
19156
- function getSkillsOperation(operationName) {
21085
+ function getOperation(operationName) {
19157
21086
  const operationSpec = operationSpecs.find(
19158
21087
  (candidate) => candidate.operationName === operationName
19159
21088
  );
19160
21089
  if (!operationSpec) {
21090
+ throw new CliError(`Operation "${operationName}" is not registered.`);
21091
+ }
21092
+ return operationSpec;
21093
+ }
21094
+ async function withGlobalOperationAccessToken({
21095
+ dependencies
21096
+ }) {
21097
+ const state = requireLoggedInState(await dependencies.stateStore.load());
21098
+ const directAccessTokenOrganizationId = await resolveDirectAccessTokenOrganizationId({ dependencies });
21099
+ const authenticationOrganizationId = directAccessTokenOrganizationId ?? state.defaultOrgId ?? state.lastUsedOrgId ?? state.organizations[0]?.id;
21100
+ if (!authenticationOrganizationId) {
19161
21101
  throw new CliError(
19162
- `Skills operation "${operationName}" is not registered.`
21102
+ 'No organization is available for authentication. Run "mgcl auth login" again.'
19163
21103
  );
19164
21104
  }
19165
- return operationSpec;
21105
+ const { accessToken } = await withGlobalAccessToken({
21106
+ authenticationOrganizationId,
21107
+ dependencies,
21108
+ state
21109
+ });
21110
+ const usesOttoAuthorization = (() => {
21111
+ try {
21112
+ return dependencies.authClient.decodeAccessTokenClaims(accessToken).iss === "magical:otto";
21113
+ } catch {
21114
+ return false;
21115
+ }
21116
+ })();
21117
+ return {
21118
+ accessToken,
21119
+ ...usesOttoAuthorization ? { organizationId: authenticationOrganizationId } : {}
21120
+ };
21121
+ }
21122
+ async function handleGlobalOperationCommand(dependencies, operationSpec, commandOptions) {
21123
+ const { accessToken, organizationId } = await withGlobalOperationAccessToken({
21124
+ dependencies
21125
+ });
21126
+ const executeOperation = async (operationName, variables) => {
21127
+ const nextOperationSpec = getOperation(operationName);
21128
+ if (nextOperationSpec.scope !== "global") {
21129
+ throw new CliError(
21130
+ `Global operation "${operationName}" cannot execute an organization-scoped operation.`
21131
+ );
21132
+ }
21133
+ return await dependencies.apiClient.executeGraphQl({
21134
+ accessToken,
21135
+ ...organizationId ? { organizationId } : {},
21136
+ query: nextOperationSpec.document,
21137
+ resultKey: nextOperationSpec.cli.resultKey,
21138
+ variables: parseOperationVariables(nextOperationSpec, variables)
21139
+ });
21140
+ };
21141
+ const customResult = await executeEvalCliOperation({
21142
+ executeOperation,
21143
+ operationName: operationSpec.operationName,
21144
+ options: commandOptions,
21145
+ runtime: {
21146
+ ...dependencies.evalCommandRuntime,
21147
+ ...dependencies.apiClient.downloadFile ? { downloadFile: dependencies.apiClient.downloadFile } : {},
21148
+ workingDirectory: dependencies.evalCommandRuntime?.workingDirectory ?? dependencies.workingDirectory ?? process.cwd()
21149
+ }
21150
+ });
21151
+ const commandResult = customResult ?? {
21152
+ result: await executeOperation(
21153
+ operationSpec.operationName,
21154
+ collectOperationVariables(operationSpec, commandOptions)
21155
+ )
21156
+ };
21157
+ writeCommandOutput({
21158
+ dependencies,
21159
+ json: commandOptions.json,
21160
+ result: commandResult.result
21161
+ });
21162
+ if (commandResult.exitError) {
21163
+ throw commandResult.exitError;
21164
+ }
21165
+ }
21166
+ function getSkillsOperation(operationName) {
21167
+ return getOperation(operationName);
19166
21168
  }
19167
21169
  async function withSkillsWorkingCopyContext(dependencies, options) {
19168
21170
  const { accessToken, impersonatedOrganizationId, organization, state } = await withSelectedOrganizationAndAccessToken({ dependencies, options });
@@ -19413,6 +21415,217 @@ async function handleNangoAuthsListCommand(dependencies, options) {
19413
21415
  result: authentications
19414
21416
  });
19415
21417
  }
21418
+ function summarizePathwayRegressionPreview(result) {
21419
+ return {
21420
+ automationVersionId: result.automationVersionId,
21421
+ agentVersionId: result.agentVersionId,
21422
+ contractId: result.contractId,
21423
+ pathwayCount: result.paths.length,
21424
+ selectedReplayCount: result.paths.reduce(
21425
+ (sum, pathway) => sum + pathway.runs.length,
21426
+ 0
21427
+ ),
21428
+ paths: result.paths.map((pathway) => ({
21429
+ sortOrder: pathway.sortOrder,
21430
+ label: pathway.label,
21431
+ pathwayKey: pathway.pathwayKey,
21432
+ matchingRunCount: pathway.runs.length,
21433
+ runs: pathway.runs.map((run) => ({
21434
+ agentRunId: run.agentRunId,
21435
+ automationRunId: run.automationRunId,
21436
+ finishedAt: run.finishedAt,
21437
+ stepCount: run.stepCount
21438
+ }))
21439
+ }))
21440
+ };
21441
+ }
21442
+ function summarizePathwayRegressionKickoff(result) {
21443
+ if ("contractWorkflowId" in result) {
21444
+ return {
21445
+ status: result.status,
21446
+ contractGenerationStatus: result.contractGenerationStatus,
21447
+ contractWorkflowId: result.contractWorkflowId,
21448
+ regressionRunId: result.regressionRunId,
21449
+ workflowId: result.workflowId,
21450
+ selectedReplayCount: result.selectedReplayCount,
21451
+ automationVersionId: result.automationVersionId,
21452
+ agentVersionId: result.agentVersionId
21453
+ };
21454
+ }
21455
+ return {
21456
+ regressionRunId: result.regressionRunId,
21457
+ workflowId: result.workflowId,
21458
+ status: result.status,
21459
+ selectedReplayCount: result.selectedReplayCount,
21460
+ automationVersionId: result.automationVersionId,
21461
+ agentVersionId: result.agentVersionId,
21462
+ contractId: result.contractId,
21463
+ baselineAutomationVersionId: result.baselineAutomationVersionId,
21464
+ baselineAgentVersionId: result.baselineAgentVersionId,
21465
+ baselineContractId: result.baselineContractId,
21466
+ candidateContractId: result.candidateContractId,
21467
+ paths: result.paths.map((pathway) => ({
21468
+ sortOrder: pathway.candidate?.sortOrder ?? pathway.baseline?.sortOrder ?? null,
21469
+ baselineLabel: pathway.baseline?.label ?? null,
21470
+ candidateLabel: pathway.candidate?.label ?? null,
21471
+ pathwayKey: pathway.pathwayKey,
21472
+ selectedRunCount: pathway.selectedRunCount,
21473
+ status: pathway.status,
21474
+ isInLatestPublishedBaseline: pathway.isInLatestPublishedBaseline ?? null,
21475
+ lastSeenPublishedAutomationVersionId: pathway.lastSeenPublishedAutomationVersionId ?? null,
21476
+ lastSeenPublishedAgentVersionId: pathway.lastSeenPublishedAgentVersionId ?? null,
21477
+ lastSeenPublishedSequence: pathway.lastSeenPublishedSequence ?? null
21478
+ }))
21479
+ };
21480
+ }
21481
+ function summarizePathwayRegressionResult(result) {
21482
+ const replayCount = result.pathways.reduce(
21483
+ (sum, pathway) => sum + pathway.replays.length,
21484
+ 0
21485
+ );
21486
+ return {
21487
+ regressionRunId: result.regressionRun.id,
21488
+ workflowId: result.regressionRun.workflowId,
21489
+ scope: result.regressionRun.scope,
21490
+ status: result.regressionRun.status,
21491
+ finishedAt: result.regressionRun.finishedAt,
21492
+ pathwayCount: result.pathways.length,
21493
+ replayCount,
21494
+ pathways: result.pathways.map((pathway) => ({
21495
+ sortOrder: pathway.sortOrder,
21496
+ label: pathway.label ?? pathway.pathwayKey,
21497
+ pathwayKey: pathway.pathwayKey,
21498
+ replays: pathway.replays.map((replay) => ({
21499
+ regressionReplayId: replay.id,
21500
+ baselineAgentRunId: replay.baselineAgentRunId,
21501
+ baselineAutomationRunId: replay.baselineAutomationRunId,
21502
+ status: replay.status,
21503
+ checks: replay.checks,
21504
+ nonPassingIterations: replay.iterations.filter((iteration) => iteration.status !== "passed").map((iteration) => ({
21505
+ regressionReplayIterationId: iteration.id,
21506
+ sequence: iteration.sequence,
21507
+ status: iteration.status,
21508
+ expectedToolName: iteration.expectedToolName,
21509
+ observedToolName: iteration.observedToolName
21510
+ }))
21511
+ }))
21512
+ }))
21513
+ };
21514
+ }
21515
+ function summarizePathwayRegressionReplayIterationCheckResults(result) {
21516
+ const { regressionReplayIteration } = result;
21517
+ return {
21518
+ regressionReplayId: regressionReplayIteration.regressionReplayId,
21519
+ regressionReplayIterationId: regressionReplayIteration.id,
21520
+ sequence: regressionReplayIteration.sequence,
21521
+ status: regressionReplayIteration.status,
21522
+ expectedToolName: regressionReplayIteration.expectedToolName,
21523
+ observedToolName: regressionReplayIteration.observedToolName,
21524
+ checkCount: regressionReplayIteration.checkResults.length,
21525
+ checks: regressionReplayIteration.checkResults.map((checkResult) => ({
21526
+ attemptIndex: checkResult.attemptIndex,
21527
+ status: checkResult.status,
21528
+ expectedToolName: checkResult.expectedToolName,
21529
+ actualToolName: checkResult.actualToolName,
21530
+ outputResult: checkResult.outputResult
21531
+ }))
21532
+ };
21533
+ }
21534
+ async function handlePathwayRegressionPreviewCommand(dependencies, options) {
21535
+ const { accessToken, impersonatedOrganizationId, organization, state } = await withSelectedOrganizationAndAccessToken({ dependencies, options });
21536
+ const previewPathwayRegressionMatchingRuns = requireApiClientMethod(
21537
+ dependencies.apiClient,
21538
+ "previewPathwayRegressionMatchingRuns"
21539
+ );
21540
+ const result = await previewPathwayRegressionMatchingRuns({
21541
+ accessToken,
21542
+ agentVersionId: options.agentVersionId,
21543
+ automationVersionId: options.automationVersionId,
21544
+ ...impersonatedOrganizationId ? { impersonatedOrganizationId } : {},
21545
+ organizationId: organization.id,
21546
+ ...options.runsPerPath === void 0 ? {} : { runsPerPath: options.runsPerPath }
21547
+ });
21548
+ await saveLastUsedOrganization({
21549
+ dependencies,
21550
+ organizationId: organization.id,
21551
+ state
21552
+ });
21553
+ writeCommandOutput({
21554
+ dependencies,
21555
+ json: options.json,
21556
+ result: options.json ? result : summarizePathwayRegressionPreview(result)
21557
+ });
21558
+ }
21559
+ async function handlePathwayRegressionRunCommand(dependencies, options) {
21560
+ const { accessToken, impersonatedOrganizationId, organization, state } = await withSelectedOrganizationAndAccessToken({ dependencies, options });
21561
+ const startPathwayRegressionAgentVersionRun = requireApiClientMethod(
21562
+ dependencies.apiClient,
21563
+ "startPathwayRegressionAgentVersionRun"
21564
+ );
21565
+ const result = await startPathwayRegressionAgentVersionRun({
21566
+ accessToken,
21567
+ agentVersionId: options.agentVersionId,
21568
+ automationVersionId: options.automationVersionId,
21569
+ ...impersonatedOrganizationId ? { impersonatedOrganizationId } : {},
21570
+ organizationId: organization.id
21571
+ });
21572
+ await saveLastUsedOrganization({
21573
+ dependencies,
21574
+ organizationId: organization.id,
21575
+ state
21576
+ });
21577
+ writeCommandOutput({
21578
+ dependencies,
21579
+ json: options.json,
21580
+ result: options.json ? result : summarizePathwayRegressionKickoff(result)
21581
+ });
21582
+ }
21583
+ async function handlePathwayRegressionResultsCommand(dependencies, options) {
21584
+ const { accessToken, impersonatedOrganizationId, organization, state } = await withSelectedOrganizationAndAccessToken({ dependencies, options });
21585
+ const getPathwayRegressionRunResult = requireApiClientMethod(
21586
+ dependencies.apiClient,
21587
+ "getPathwayRegressionRunResult"
21588
+ );
21589
+ const result = await getPathwayRegressionRunResult({
21590
+ accessToken,
21591
+ regressionRunId: options.regressionRunId,
21592
+ ...impersonatedOrganizationId ? { impersonatedOrganizationId } : {},
21593
+ organizationId: organization.id
21594
+ });
21595
+ await saveLastUsedOrganization({
21596
+ dependencies,
21597
+ organizationId: organization.id,
21598
+ state
21599
+ });
21600
+ writeCommandOutput({
21601
+ dependencies,
21602
+ json: options.json,
21603
+ result: options.json ? result : summarizePathwayRegressionResult(result)
21604
+ });
21605
+ }
21606
+ async function handlePathwayRegressionCheckResultsCommand(dependencies, options) {
21607
+ const { accessToken, impersonatedOrganizationId, organization, state } = await withSelectedOrganizationAndAccessToken({ dependencies, options });
21608
+ const getPathwayRegressionReplayIterationCheckResults = requireApiClientMethod(
21609
+ dependencies.apiClient,
21610
+ "getPathwayRegressionReplayIterationCheckResults"
21611
+ );
21612
+ const result = await getPathwayRegressionReplayIterationCheckResults({
21613
+ accessToken,
21614
+ regressionReplayIterationId: options.regressionReplayIterationId,
21615
+ ...impersonatedOrganizationId ? { impersonatedOrganizationId } : {},
21616
+ organizationId: organization.id
21617
+ });
21618
+ await saveLastUsedOrganization({
21619
+ dependencies,
21620
+ organizationId: organization.id,
21621
+ state
21622
+ });
21623
+ writeCommandOutput({
21624
+ dependencies,
21625
+ json: options.json,
21626
+ result: options.json ? result : summarizePathwayRegressionReplayIterationCheckResults(result)
21627
+ });
21628
+ }
19416
21629
  async function resolveDirectAccessTokenOrganizationId({
19417
21630
  dependencies
19418
21631
  }) {
@@ -19420,7 +21633,7 @@ async function resolveDirectAccessTokenOrganizationId({
19420
21633
  if (!accessTokenFilePath) {
19421
21634
  return null;
19422
21635
  }
19423
- const accessToken = await readFile5(accessTokenFilePath, "utf8").then((value) => value.trim()).catch((error) => {
21636
+ const accessToken = await readFile6(accessTokenFilePath, "utf8").then((value) => value.trim()).catch((error) => {
19424
21637
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
19425
21638
  return null;
19426
21639
  }
@@ -19452,6 +21665,9 @@ function addRegistryOperationCommand({
19452
21665
  dependencies,
19453
21666
  operationSpec
19454
21667
  }) {
21668
+ if (operationSpec.cli.hidden) {
21669
+ return;
21670
+ }
19455
21671
  const commandPath = [...operationSpec.cli.path];
19456
21672
  const leafCommandName = commandPath.pop();
19457
21673
  if (!leafCommandName) {
@@ -19488,12 +21704,17 @@ function addRegistryOperationCommand({
19488
21704
  configureOperationalCommand(legacyAliasCommand, dependencies, operationSpec);
19489
21705
  }
19490
21706
  function configureOperationalCommand(command, dependencies, operationSpec) {
19491
- command.description(operationSpec.cli.description).addOption(
19492
- new Option2(
19493
- "--org <org>",
19494
- "Organization ID or exact organization name to use."
19495
- ).helpGroup("Shared options:")
19496
- ).addHelpText(
21707
+ commandBranchContexts.set(command, operationSpec.cli.branchContext);
21708
+ command.description(operationSpec.cli.description);
21709
+ if (operationSpec.scope !== "global") {
21710
+ command.addOption(
21711
+ new Option2(
21712
+ "--org <org>",
21713
+ "Organization ID or exact organization name to use."
21714
+ ).helpGroup("Shared options:")
21715
+ );
21716
+ }
21717
+ command.addHelpText(
19497
21718
  "after",
19498
21719
  `
19499
21720
  ${formatExamples(
@@ -19532,12 +21753,12 @@ function createConsoleIo() {
19532
21753
  function createDefaultDependencies() {
19533
21754
  const runtimeConfig = getRuntimeConfig();
19534
21755
  const settingsStore = createFileSettingsStore(runtimeConfig.stateFilePath);
19535
- const accessTokenFilePath = runtimeConfig.accessTokenFilePath ?? path7.join(
19536
- path7.dirname(runtimeConfig.stateFilePath),
21756
+ const accessTokenFilePath = runtimeConfig.accessTokenFilePath ?? path8.join(
21757
+ path8.dirname(runtimeConfig.stateFilePath),
19537
21758
  CLI_ACCESS_TOKEN_FILE_NAME
19538
21759
  );
19539
- const refreshTokenFilePath = runtimeConfig.refreshTokenFilePath ?? path7.join(
19540
- path7.dirname(runtimeConfig.stateFilePath),
21760
+ const refreshTokenFilePath = runtimeConfig.refreshTokenFilePath ?? path8.join(
21761
+ path8.dirname(runtimeConfig.stateFilePath),
19541
21762
  CLI_REFRESH_TOKEN_FILE_NAME
19542
21763
  );
19543
21764
  const selfUpdateOptions = {
@@ -19569,7 +21790,12 @@ function createDefaultDependencies() {
19569
21790
  function buildProgram(dependencies) {
19570
21791
  const program2 = configureCommandPresentation(
19571
21792
  new Command2().name("mgcl").description("Run Magical operations from the command line.")
19572
- ).addOption(new Option2("--json", "Render JSON output.")).version(CLI_VERSION, "--version", `Display mgcl version (${CLI_VERSION}).`).addOption(
21793
+ ).addOption(new Option2("--json", "Render JSON output.")).addOption(
21794
+ new Option2(
21795
+ "--branch-id <id>",
21796
+ "Target a supported automation command at one branch; omit it to target main."
21797
+ )
21798
+ ).version(CLI_VERSION, "--version", `Display mgcl version (${CLI_VERSION}).`).addOption(
19573
21799
  new Option2(
19574
21800
  "--update",
19575
21801
  "Update mgcl to the latest published npm release."
@@ -19587,6 +21813,18 @@ ${formatExamples("Quick start", [
19587
21813
 
19588
21814
  ${formatOutputModesNote()}`
19589
21815
  );
21816
+ program2.hook("preAction", (_thisCommand, actionCommand) => {
21817
+ const options = actionCommand.optsWithGlobals();
21818
+ const branchContext = commandBranchContexts.get(actionCommand);
21819
+ if (options.branchId && branchContext === void 0) {
21820
+ throw new CliError(
21821
+ `Command "${actionCommand.name()}" does not support --branch-id.`
21822
+ );
21823
+ }
21824
+ if (!options.branchId && branchContext === "required") {
21825
+ throw new CliError("--branch-id is required for this command.");
21826
+ }
21827
+ });
19590
21828
  program2.action(async function() {
19591
21829
  const options = this.optsWithGlobals();
19592
21830
  if (options.update) {
@@ -19631,6 +21869,88 @@ ${formatExamples("Examples", [
19631
21869
  );
19632
21870
  });
19633
21871
  program2.addCommand(orgCommand);
21872
+ const pathwayRegressionCommand = configureCommandPresentation(
21873
+ new Command2("pathway-regression").description(
21874
+ "Preview, start, and inspect pathway regression runs."
21875
+ )
21876
+ ).helpGroup("Workspace:").addHelpText(
21877
+ "after",
21878
+ `
21879
+ ${formatExamples("Examples", [
21880
+ "mgcl pathway-regression preview --automation-version-id <id> --agent-version-id <id>",
21881
+ "mgcl pathway-regression run --automation-version-id <id> --agent-version-id <id>",
21882
+ "mgcl pathway-regression results --regression-run-id <id>",
21883
+ "mgcl pathway-regression check-results --regression-replay-iteration-id <id>"
21884
+ ])}`
21885
+ );
21886
+ const addPathwayRegressionAgentVersionOptions = (command) => command.addOption(
21887
+ new Option2(
21888
+ "--org <org>",
21889
+ "Organization ID or exact organization name to use."
21890
+ ).helpGroup("Shared options:")
21891
+ ).addOption(
21892
+ new Option2(
21893
+ "--automation-version-id <id>",
21894
+ "Automation version to test against."
21895
+ ).helpGroup("Pathway regression options:").makeOptionMandatory(true)
21896
+ ).addOption(
21897
+ new Option2("--agent-version-id <id>", "Agent version to test.").helpGroup("Pathway regression options:").makeOptionMandatory(true)
21898
+ );
21899
+ const addPathwayRegressionPreviewOptions = (command) => addPathwayRegressionAgentVersionOptions(command).addOption(
21900
+ new Option2(
21901
+ "--runs-per-path <count>",
21902
+ "Number of historical runs to use per pathway. Defaults to the service value."
21903
+ ).helpGroup("Pathway regression options:").argParser(parsePositiveIntegerOption)
21904
+ );
21905
+ addPathwayRegressionPreviewOptions(
21906
+ pathwayRegressionCommand.command("preview").description("Show which historical runs are available per pathway.")
21907
+ ).action(async function() {
21908
+ await handlePathwayRegressionPreviewCommand(
21909
+ dependencies,
21910
+ this.optsWithGlobals()
21911
+ );
21912
+ });
21913
+ addPathwayRegressionAgentVersionOptions(
21914
+ pathwayRegressionCommand.command("run").description("Start regression replay for an agent version.")
21915
+ ).action(async function() {
21916
+ await handlePathwayRegressionRunCommand(
21917
+ dependencies,
21918
+ this.optsWithGlobals()
21919
+ );
21920
+ });
21921
+ pathwayRegressionCommand.command("results").description("Read a pathway regression run result.").addOption(
21922
+ new Option2(
21923
+ "--org <org>",
21924
+ "Organization ID or exact organization name to use."
21925
+ ).helpGroup("Shared options:")
21926
+ ).addOption(
21927
+ new Option2(
21928
+ "--regression-run-id <id>",
21929
+ "Pathway regression run ID to inspect."
21930
+ ).helpGroup("Pathway regression options:").makeOptionMandatory(true)
21931
+ ).action(async function() {
21932
+ await handlePathwayRegressionResultsCommand(
21933
+ dependencies,
21934
+ this.optsWithGlobals()
21935
+ );
21936
+ });
21937
+ pathwayRegressionCommand.command("check-results").description("Read detailed check attempts for one replay iteration.").addOption(
21938
+ new Option2(
21939
+ "--org <org>",
21940
+ "Organization ID or exact organization name to use."
21941
+ ).helpGroup("Shared options:")
21942
+ ).addOption(
21943
+ new Option2(
21944
+ "--regression-replay-iteration-id <id>",
21945
+ "Pathway regression replay iteration ID to inspect."
21946
+ ).helpGroup("Pathway regression options:").makeOptionMandatory(true)
21947
+ ).action(async function() {
21948
+ await handlePathwayRegressionCheckResultsCommand(
21949
+ dependencies,
21950
+ this.optsWithGlobals()
21951
+ );
21952
+ });
21953
+ program2.addCommand(pathwayRegressionCommand);
19634
21954
  const nangoCommand = configureCommandPresentation(
19635
21955
  new Command2("nango").description(
19636
21956
  "Inspect Nango integrations and org-scoped authentications."