@getmagical/cli 0.2.5 → 0.2.6

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,20 +13866,20 @@ 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;
13882
13885
  var repoPathSchema = z21.string().min(1).transform(normalizeRepoPath).refine(isNormalizedRepoPath, {
@@ -13897,7 +13900,7 @@ var memoryConfigSchema = z21.object({
13897
13900
  }).strict().describe("Configuration for the memory runtime plugin.");
13898
13901
  var skillsConfigSchema = z21.object({
13899
13902
  enabled: z21.boolean().default(false).describe("Explicit rollout switch for the skills runtime plugin."),
13900
- registeredSkills: z21.array(repoPathSchema.refine((path8) => skillPathPattern.test(path8), {
13903
+ registeredSkills: z21.array(repoPathSchema.refine((path9) => skillPathPattern.test(path9), {
13901
13904
  message: "Skill paths must be under root, automation, or automation-agent skills."
13902
13905
  })).default(() => []).describe("Repository skill root paths available to the skills plugin."),
13903
13906
  canEdit: z21.boolean().default(false).describe("Allows the skills runtime plugin to edit repo skills under the root skills folder.")
@@ -13921,6 +13924,7 @@ var baseAgentConfigFieldsSchema = z21.object({
13921
13924
  environmentOptions: environmentOptionsSchema.optional().default(DEFAULT_ENVIRONMENT_OPTION).describe("Environment configuration for the agent. Default is browser with SOM."),
13922
13925
  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
13926
  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."),
13927
+ 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
13928
  limitations: agentRunLimitationSchema.describe("Resource limits for this agent, including maximum duration and tool call limits."),
13925
13929
  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
13930
  idempotencySettings: z21.object({
@@ -14327,13 +14331,13 @@ function getMentionedStandardCommand(instructions) {
14327
14331
  const normalizedInstructions = instructions.toLowerCase();
14328
14332
  return STANDARD_COMMAND_NAMES.find((commandName) => normalizedInstructions.includes(commandName.toLowerCase())) ?? null;
14329
14333
  }
14330
- function assertCustomInstructionsCommand({ commands, path: path8 }) {
14331
- const customCommands = commands.flatMap((command, commandIndex) => command["commandName"] === "custom" ? [{ command, path: `${path8}[${commandIndex.toString()}]` }] : []);
14334
+ function assertCustomInstructionsCommand({ commands, path: path9 }) {
14335
+ const customCommands = commands.flatMap((command, commandIndex) => command["commandName"] === "custom" ? [{ command, path: `${path9}[${commandIndex.toString()}]` }] : []);
14332
14336
  if (customCommands.length === 0) {
14333
14337
  return;
14334
14338
  }
14335
14339
  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.`);
14340
+ 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
14341
  }
14338
14342
  const [customCommand] = customCommands;
14339
14343
  if (!customCommand) {
@@ -14388,26 +14392,32 @@ function createOperationSpec(spec) {
14388
14392
 
14389
14393
  // ../mcp-registry/src/operation-specs.ts
14390
14394
  function stringOption({
14395
+ clientOnly = false,
14391
14396
  description,
14392
14397
  flagName,
14393
14398
  inputKey,
14394
- required = false
14399
+ required = false,
14400
+ valueHint
14395
14401
  }) {
14396
14402
  return {
14403
+ ...clientOnly ? { clientOnly: true } : {},
14397
14404
  description,
14398
14405
  flagName,
14399
14406
  inputKey,
14400
14407
  required,
14408
+ ...valueHint ? { valueHint } : {},
14401
14409
  valueType: "string"
14402
14410
  };
14403
14411
  }
14404
14412
  function numberOption({
14413
+ clientOnly = false,
14405
14414
  description,
14406
14415
  flagName,
14407
14416
  inputKey,
14408
14417
  required = false
14409
14418
  }) {
14410
14419
  return {
14420
+ ...clientOnly ? { clientOnly: true } : {},
14411
14421
  description,
14412
14422
  flagName,
14413
14423
  inputKey,
@@ -14416,11 +14426,13 @@ function numberOption({
14416
14426
  };
14417
14427
  }
14418
14428
  function booleanOption({
14429
+ clientOnly = false,
14419
14430
  description,
14420
14431
  flagName,
14421
14432
  inputKey
14422
14433
  }) {
14423
14434
  return {
14435
+ ...clientOnly ? { clientOnly: true } : {},
14424
14436
  description,
14425
14437
  flagName,
14426
14438
  inputKey,
@@ -14458,13 +14470,79 @@ function jsonOption({
14458
14470
  };
14459
14471
  }
14460
14472
  var jsonObjectSchema = z25.record(z25.string(), z25.unknown());
14473
+ var evalRunStatusSchema = z25.enum([
14474
+ "QUEUED",
14475
+ "RUNNING",
14476
+ "COMPLETE",
14477
+ "FAILED",
14478
+ "CANCELLED"
14479
+ ]);
14480
+ var evalInputChoicesSchema = z25.record(
14481
+ z25.string(),
14482
+ z25.array(z25.unknown()).min(1)
14483
+ );
14484
+ var registeredEvalRunInputSchema = z25.object({
14485
+ description: z25.string().min(1).optional(),
14486
+ input: evalInputChoicesSchema,
14487
+ maxConcurrency: z25.number().int().positive().default(1),
14488
+ name: z25.string().min(1).optional(),
14489
+ repeatCount: z25.number().int().positive().default(1),
14490
+ slug: z25.string().min(1),
14491
+ tags: z25.array(z25.string().min(1)).default([])
14492
+ });
14493
+ var registeredEvalSelection = ` slug
14494
+ name
14495
+ description
14496
+ tags
14497
+ version
14498
+ inputSchema`;
14499
+ var evalRunSelection = ` id
14500
+ createdAt
14501
+ updatedAt
14502
+ userId
14503
+ slug
14504
+ evalName
14505
+ evalDescription
14506
+ evalTags
14507
+ evalVersion
14508
+ input
14509
+ name
14510
+ description
14511
+ tags
14512
+ scorerSlugs
14513
+ maxConcurrency
14514
+ repeatCount
14515
+ acknowledgedTrialCount
14516
+ idempotencyKey
14517
+ dashboardUrl
14518
+ workflowId
14519
+ workflowRunId
14520
+ status
14521
+ startedAt
14522
+ finishedAt
14523
+ trialStatusCounts {
14524
+ queued
14525
+ running
14526
+ complete
14527
+ failed
14528
+ cancelled
14529
+ }`;
14530
+ var evalRunExportSelection = ` exportId
14531
+ evalRunId
14532
+ status
14533
+ workflowId
14534
+ workflowRunId
14535
+ fileName
14536
+ trialCount
14537
+ downloadUrl
14538
+ error`;
14461
14539
  function isRecord3(value) {
14462
14540
  return typeof value === "object" && value !== null && !Array.isArray(value);
14463
14541
  }
14464
14542
  function validateCustomInstructionsCommands({
14465
14543
  commands,
14466
14544
  ctx,
14467
- path: path8
14545
+ path: path9
14468
14546
  }) {
14469
14547
  if (!Array.isArray(commands)) {
14470
14548
  return;
@@ -14472,14 +14550,14 @@ function validateCustomInstructionsCommands({
14472
14550
  const validationResult = fromThrowable(() => {
14473
14551
  assertCustomInstructionsCommand({
14474
14552
  commands: commands.map((command) => isRecord3(command) ? command : {}),
14475
- path: path8.join(".").replaceAll(/\.(?<index>\d+)/gu, "[$<index>]")
14553
+ path: path9.join(".").replaceAll(/\.(?<index>\d+)/gu, "[$<index>]")
14476
14554
  });
14477
14555
  }, "invalid-custom-instructions-command");
14478
14556
  if (isErr(validationResult)) {
14479
14557
  ctx.addIssue({
14480
14558
  code: "custom",
14481
14559
  message: `${getErrorMessage2(validationResult.error.cause)} Run mgcl catalog commands to find the standard command for this work.`,
14482
- path: path8
14560
+ path: path9
14483
14561
  });
14484
14562
  }
14485
14563
  }
@@ -14715,6 +14793,7 @@ ${agentLimitationsSelection}
14715
14793
  systemPrompt
14716
14794
  additionalSystemPrompt
14717
14795
  ignoreUnstableSessionState
14796
+ stepFollowingVerification
14718
14797
  resourcePools {
14719
14798
  id
14720
14799
  type
@@ -14784,6 +14863,7 @@ ${agentLimitationsSelection}
14784
14863
  systemPrompt
14785
14864
  additionalSystemPrompt
14786
14865
  ignoreUnstableSessionState
14866
+ stepFollowingVerification
14787
14867
  }
14788
14868
  isCurrent
14789
14869
  }
@@ -16980,140 +17060,770 @@ mutation UpdateAutomationById($id: ID!, $input: UpdateAutomationInput!) {
16980
17060
  lastSavedAt
16981
17061
  }
16982
17062
  }`
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) {
17073
- return parsedResponse.data.message;
17063
+ }),
17064
+ createOperationSpec({
17065
+ operationName: "ListRegisteredEvals",
17066
+ kind: "query",
17067
+ inputSchema: z25.object({}),
17068
+ cli: {
17069
+ name: "list-registered-evals",
17070
+ path: ["evals", "list"],
17071
+ description: "List globally registered eval definitions.",
17072
+ resultKey: "registeredEvals",
17073
+ options: []
17074
+ },
17075
+ mcp: { fileName: "registeredEvals.graphql" },
17076
+ scope: "global",
17077
+ document: `# List globally registered eval definitions available to the authenticated caller
17078
+ query ListRegisteredEvals {
17079
+ registeredEvals {
17080
+ ${registeredEvalSelection}
17074
17081
  }
17075
- if (!parsedResponse.data.errors || parsedResponse.data.errors.length === 0) {
17076
- return null;
17082
+ }`
17083
+ }),
17084
+ createOperationSpec({
17085
+ operationName: "GetRegisteredEval",
17086
+ kind: "query",
17087
+ inputSchema: z25.object({ slug: z25.string().min(1) }),
17088
+ cli: {
17089
+ name: "get-registered-eval",
17090
+ path: ["evals", "get"],
17091
+ description: "Get one globally registered eval definition.",
17092
+ resultKey: "registeredEval",
17093
+ options: [
17094
+ stringOption({
17095
+ description: "Registered eval slug.",
17096
+ flagName: "slug",
17097
+ inputKey: "slug",
17098
+ required: true
17099
+ })
17100
+ ]
17101
+ },
17102
+ mcp: { fileName: "registeredEval.graphql" },
17103
+ scope: "global",
17104
+ document: `# Get one globally registered eval definition by slug
17105
+ query GetRegisteredEval($slug: String!) {
17106
+ registeredEval(slug: $slug) {
17107
+ ${registeredEvalSelection}
17077
17108
  }
17078
- return parsedResponse.data.errors.map((error) => error.message).join("\n");
17079
- }
17080
- function trimTrailingSlash(value) {
17081
- return value.replace(/\/+$/u, "");
17082
- }
17083
- function isRecord4(value) {
17084
- return typeof value === "object" && value !== null && !Array.isArray(value);
17085
- }
17086
- function decodeJwtPayload(token) {
17087
- const [, payloadSegment] = token.split(".");
17088
- if (!payloadSegment) {
17089
- return null;
17109
+ }`
17110
+ }),
17111
+ createOperationSpec({
17112
+ operationName: "TestRegisteredEval",
17113
+ kind: "mutation",
17114
+ inputSchema: z25.object({
17115
+ input: jsonObjectSchema,
17116
+ slug: z25.string().min(1)
17117
+ }),
17118
+ cli: {
17119
+ name: "test-registered-eval",
17120
+ path: ["evals", "test-run"],
17121
+ description: "Execute one registered eval input and its scorers without persistence.",
17122
+ resultKey: "testRegisteredEval",
17123
+ options: [
17124
+ stringOption({
17125
+ description: "Registered eval slug.",
17126
+ flagName: "slug",
17127
+ inputKey: "slug",
17128
+ required: true
17129
+ }),
17130
+ jsonOption({
17131
+ description: "Concrete eval input object.",
17132
+ flagName: "input-json",
17133
+ inputKey: "input"
17134
+ }),
17135
+ stringOption({
17136
+ clientOnly: true,
17137
+ description: "Path to a JSON file containing the concrete input.",
17138
+ flagName: "input-file",
17139
+ inputKey: "inputFile"
17140
+ })
17141
+ ]
17142
+ },
17143
+ mcp: { fileName: "testRegisteredEval.graphql" },
17144
+ scope: "global",
17145
+ document: `# Execute exactly one registered eval input and its scorers without persistence or automatic retries
17146
+ # COMPLETE and FAILED execution outcomes are returned in the result body
17147
+ mutation TestRegisteredEval($slug: String!, $input: JSON!) {
17148
+ testRegisteredEval(input: { slug: $slug, input: $input }) {
17149
+ status
17150
+ input
17151
+ output
17152
+ scores
17153
+ error {
17154
+ type
17155
+ message
17156
+ }
17090
17157
  }
17091
- const payloadResult = safeJsonParse(
17092
- Buffer.from(payloadSegment, "base64url").toString("utf8")
17093
- );
17094
- if (isErr(payloadResult)) {
17095
- return null;
17158
+ }`
17159
+ }),
17160
+ createOperationSpec({
17161
+ operationName: "PlanRegisteredEvalRun",
17162
+ kind: "query",
17163
+ inputSchema: registeredEvalRunInputSchema,
17164
+ cli: {
17165
+ name: "plan-registered-eval-run",
17166
+ path: ["evals", "plan-run"],
17167
+ description: "Validate a registered eval run and calculate its exact trial count.",
17168
+ resultKey: "planRegisteredEvalRun",
17169
+ options: [
17170
+ stringOption({
17171
+ description: "Registered eval slug.",
17172
+ flagName: "slug",
17173
+ inputKey: "slug",
17174
+ required: true
17175
+ }),
17176
+ jsonOption({
17177
+ description: "Eval input choices keyed by registered input name.",
17178
+ flagName: "input-json",
17179
+ inputKey: "input"
17180
+ }),
17181
+ stringOption({
17182
+ clientOnly: true,
17183
+ description: "Path to a JSON file containing eval input choices.",
17184
+ flagName: "input-file",
17185
+ inputKey: "inputFile"
17186
+ }),
17187
+ stringOption({
17188
+ description: "Optional persisted run name.",
17189
+ flagName: "name",
17190
+ inputKey: "name"
17191
+ }),
17192
+ stringOption({
17193
+ description: "Optional persisted run description.",
17194
+ flagName: "description",
17195
+ inputKey: "description"
17196
+ }),
17197
+ stringArrayOption({
17198
+ description: "Persisted run tags.",
17199
+ flagName: "tags",
17200
+ inputKey: "tags"
17201
+ }),
17202
+ numberOption({
17203
+ description: "Maximum simultaneously executing trials.",
17204
+ flagName: "max-concurrency",
17205
+ inputKey: "maxConcurrency"
17206
+ }),
17207
+ numberOption({
17208
+ description: "Number of times to repeat each input combination.",
17209
+ flagName: "repeat-count",
17210
+ inputKey: "repeatCount"
17211
+ })
17212
+ ]
17213
+ },
17214
+ mcp: { fileName: "planRegisteredEvalRun.graphql" },
17215
+ scope: "global",
17216
+ document: `# Validate the complete proposed run and return the exact trial count without persistence
17217
+ query PlanRegisteredEvalRun(
17218
+ $slug: String!
17219
+ $input: JSON!
17220
+ $name: String
17221
+ $description: String
17222
+ $tags: [String!]
17223
+ $maxConcurrency: Int
17224
+ $repeatCount: Int
17225
+ ) {
17226
+ planRegisteredEvalRun(
17227
+ input: {
17228
+ slug: $slug
17229
+ input: $input
17230
+ name: $name
17231
+ description: $description
17232
+ tags: $tags
17233
+ maxConcurrency: $maxConcurrency
17234
+ repeatCount: $repeatCount
17235
+ }
17236
+ ) {
17237
+ combinationCount
17238
+ repeatCount
17239
+ trialCount
17096
17240
  }
17097
- return isRecord4(payloadResult.value) ? payloadResult.value : null;
17098
- }
17099
- function isOttoAuthorizationToken(token) {
17100
- return decodeJwtPayload(token)?.["iss"] === OTTO_AUTHORIZATION_ISSUER;
17101
- }
17102
- function applyAuthenticationHeaders({
17103
- accessToken,
17104
- allowOttoAuthorization,
17105
- headers,
17106
- impersonatedOrganizationId,
17107
- organizationId
17108
- }) {
17109
- if (!isOttoAuthorizationToken(accessToken)) {
17110
- headers.set("authorization", `Bearer ${accessToken}`);
17111
- if (impersonatedOrganizationId) {
17112
- headers.set("x-organization-id", impersonatedOrganizationId);
17241
+ }`
17242
+ }),
17243
+ createOperationSpec({
17244
+ operationName: "StartRegisteredEvalRun",
17245
+ kind: "mutation",
17246
+ inputSchema: registeredEvalRunInputSchema.extend({
17247
+ expectedTrialCount: z25.number().int().positive(),
17248
+ idempotencyKey: z25.string().trim().min(1)
17249
+ }),
17250
+ cli: {
17251
+ name: "start-registered-eval-run",
17252
+ path: ["evals", "run"],
17253
+ description: "Plan, confirm, and asynchronously start a registered eval run.",
17254
+ resultKey: "startRegisteredEvalRun",
17255
+ options: [
17256
+ stringOption({
17257
+ description: "Registered eval slug.",
17258
+ flagName: "slug",
17259
+ inputKey: "slug",
17260
+ required: true
17261
+ }),
17262
+ jsonOption({
17263
+ description: "Eval input choices keyed by registered input name.",
17264
+ flagName: "input-json",
17265
+ inputKey: "input"
17266
+ }),
17267
+ stringOption({
17268
+ clientOnly: true,
17269
+ description: "Path to a JSON file containing eval input choices.",
17270
+ flagName: "input-file",
17271
+ inputKey: "inputFile"
17272
+ }),
17273
+ stringOption({
17274
+ description: "Optional persisted run name.",
17275
+ flagName: "name",
17276
+ inputKey: "name"
17277
+ }),
17278
+ stringOption({
17279
+ description: "Optional persisted run description.",
17280
+ flagName: "description",
17281
+ inputKey: "description"
17282
+ }),
17283
+ stringArrayOption({
17284
+ description: "Persisted run tags.",
17285
+ flagName: "tags",
17286
+ inputKey: "tags"
17287
+ }),
17288
+ numberOption({
17289
+ description: "Maximum simultaneously executing trials.",
17290
+ flagName: "max-concurrency",
17291
+ inputKey: "maxConcurrency"
17292
+ }),
17293
+ numberOption({
17294
+ description: "Number of times to repeat each input combination.",
17295
+ flagName: "repeat-count",
17296
+ inputKey: "repeatCount"
17297
+ }),
17298
+ stringOption({
17299
+ description: "Idempotency key; generated by mgcl when omitted.",
17300
+ flagName: "idempotency-key",
17301
+ inputKey: "idempotencyKey"
17302
+ }),
17303
+ numberOption({
17304
+ clientOnly: true,
17305
+ description: "Explicitly acknowledge the planned trial count.",
17306
+ flagName: "confirm-trials",
17307
+ inputKey: "confirmTrials"
17308
+ }),
17309
+ booleanOption({
17310
+ clientOnly: true,
17311
+ description: "Wait until the persisted run reaches a terminal state.",
17312
+ flagName: "wait",
17313
+ inputKey: "wait"
17314
+ })
17315
+ ]
17316
+ },
17317
+ mcp: { fileName: "startRegisteredEvalRun.graphql" },
17318
+ scope: "global",
17319
+ document: `# Start a registered eval run after PlanRegisteredEvalRun has returned an exact count
17320
+ # MCP callers must provide a unique idempotencyKey and the planned expectedTrialCount
17321
+ mutation StartRegisteredEvalRun(
17322
+ $slug: String!
17323
+ $input: JSON!
17324
+ $name: String
17325
+ $description: String
17326
+ $tags: [String!]
17327
+ $maxConcurrency: Int
17328
+ $repeatCount: Int
17329
+ $idempotencyKey: String!
17330
+ $expectedTrialCount: Int!
17331
+ ) {
17332
+ startRegisteredEvalRun(
17333
+ input: {
17334
+ slug: $slug
17335
+ input: $input
17336
+ name: $name
17337
+ description: $description
17338
+ tags: $tags
17339
+ maxConcurrency: $maxConcurrency
17340
+ repeatCount: $repeatCount
17341
+ idempotencyKey: $idempotencyKey
17342
+ expectedTrialCount: $expectedTrialCount
17113
17343
  }
17114
- return;
17344
+ ) {
17345
+ idempotencyKey
17346
+ evalRunId
17347
+ workflowId
17348
+ workflowRunId
17115
17349
  }
17116
- if (!allowOttoAuthorization) {
17350
+ }`
17351
+ }),
17352
+ createOperationSpec({
17353
+ operationName: "ListEvalRuns",
17354
+ kind: "query",
17355
+ inputSchema: z25.object({
17356
+ page: z25.number().int().nonnegative().default(0),
17357
+ pageSize: z25.number().int().min(1).max(100).default(20),
17358
+ slug: z25.string().min(1).optional(),
17359
+ status: evalRunStatusSchema.optional()
17360
+ }),
17361
+ cli: {
17362
+ name: "list-eval-runs",
17363
+ path: ["evals", "runs", "list"],
17364
+ description: "List persisted eval runs with optional filters.",
17365
+ resultKey: "evalRuns",
17366
+ options: [
17367
+ stringOption({
17368
+ description: "Filter by registered eval slug.",
17369
+ flagName: "slug",
17370
+ inputKey: "slug"
17371
+ }),
17372
+ stringOption({
17373
+ description: "Filter by eval run status.",
17374
+ flagName: "status",
17375
+ inputKey: "status"
17376
+ }),
17377
+ numberOption({
17378
+ description: "Zero-based page number.",
17379
+ flagName: "page",
17380
+ inputKey: "page"
17381
+ }),
17382
+ numberOption({
17383
+ description: "Page size from 1 to 100.",
17384
+ flagName: "page-size",
17385
+ inputKey: "pageSize"
17386
+ })
17387
+ ]
17388
+ },
17389
+ mcp: { fileName: "evalRuns.graphql" },
17390
+ scope: "global",
17391
+ document: `# List globally persisted eval runs with status counts and offset pagination
17392
+ query ListEvalRuns(
17393
+ $slug: String
17394
+ $status: EvalRunStatus
17395
+ $page: Int
17396
+ $pageSize: Int
17397
+ ) {
17398
+ evalRuns(slug: $slug, status: $status, page: $page, pageSize: $pageSize) {
17399
+ items {
17400
+ ${evalRunSelection}
17401
+ }
17402
+ total
17403
+ page
17404
+ pageSize
17405
+ }
17406
+ }`
17407
+ }),
17408
+ createOperationSpec({
17409
+ operationName: "GetEvalRun",
17410
+ kind: "query",
17411
+ inputSchema: z25.object({ id: z25.string().min(1) }),
17412
+ cli: {
17413
+ name: "get-eval-run",
17414
+ path: ["evals", "runs", "get"],
17415
+ description: "Get one persisted eval run with current status counts.",
17416
+ resultKey: "evalRun",
17417
+ options: [
17418
+ stringOption({
17419
+ description: "Eval run ID.",
17420
+ flagName: "id",
17421
+ inputKey: "id",
17422
+ required: true
17423
+ })
17424
+ ]
17425
+ },
17426
+ mcp: { fileName: "evalRun.graphql" },
17427
+ scope: "global",
17428
+ document: `# Get one globally persisted eval run by ID
17429
+ query GetEvalRun($id: String!) {
17430
+ evalRun(id: $id) {
17431
+ ${evalRunSelection}
17432
+ }
17433
+ }`
17434
+ }),
17435
+ createOperationSpec({
17436
+ operationName: "AwaitEvalRun",
17437
+ kind: "query",
17438
+ inputSchema: z25.object({
17439
+ id: z25.string().min(1),
17440
+ timeoutMs: z25.number().int().min(1e3).max(6e4).default(3e4)
17441
+ }),
17442
+ cli: {
17443
+ name: "await-eval-run",
17444
+ path: ["evals", "runs", "await"],
17445
+ description: "Wait for an eval run by repeating bounded server long-polls.",
17446
+ resultKey: "evalRunAwait",
17447
+ options: [
17448
+ stringOption({
17449
+ description: "Eval run ID.",
17450
+ flagName: "id",
17451
+ inputKey: "id",
17452
+ required: true
17453
+ }),
17454
+ stringOption({
17455
+ clientOnly: true,
17456
+ description: "Overall client wait timeout.",
17457
+ flagName: "timeout",
17458
+ inputKey: "timeout",
17459
+ valueHint: "duration, for example 30s or 5m"
17460
+ })
17461
+ ]
17462
+ },
17463
+ mcp: { fileName: "evalRunAwait.graphql" },
17464
+ scope: "global",
17465
+ document: `# Wait up to 60 seconds for an eval run to reach COMPLETE, FAILED, or CANCELLED
17466
+ # Call again when reachedTerminal is false and a longer overall wait is needed
17467
+ query AwaitEvalRun($id: String!, $timeoutMs: Int) {
17468
+ evalRunAwait(id: $id, timeoutMs: $timeoutMs) {
17469
+ reachedTerminal
17470
+ pollCount
17471
+ elapsedMs
17472
+ evalRun {
17473
+ ${evalRunSelection}
17474
+ }
17475
+ }
17476
+ }`
17477
+ }),
17478
+ createOperationSpec({
17479
+ operationName: "ListEvalRunTrials",
17480
+ kind: "query",
17481
+ inputSchema: z25.object({
17482
+ cursor: z25.string().min(1).optional(),
17483
+ id: z25.string().min(1),
17484
+ limit: z25.number().int().min(1).max(1e3).default(100)
17485
+ }),
17486
+ cli: {
17487
+ name: "list-eval-run-trials",
17488
+ path: ["evals", "runs", "trials"],
17489
+ description: "List eval trials in deterministic cursor order.",
17490
+ resultKey: "evalRunTrials",
17491
+ options: [
17492
+ stringOption({
17493
+ description: "Eval run ID.",
17494
+ flagName: "id",
17495
+ inputKey: "id",
17496
+ required: true
17497
+ }),
17498
+ numberOption({
17499
+ description: "Maximum trials to return, from 1 to 1000.",
17500
+ flagName: "limit",
17501
+ inputKey: "limit"
17502
+ }),
17503
+ stringOption({
17504
+ description: "Opaque cursor returned by the previous page.",
17505
+ flagName: "cursor",
17506
+ inputKey: "cursor"
17507
+ })
17508
+ ]
17509
+ },
17510
+ mcp: { fileName: "evalRunTrials.graphql" },
17511
+ scope: "global",
17512
+ document: `# List eval trials in ascending deterministic order with an opaque continuation cursor
17513
+ query ListEvalRunTrials($id: String!, $limit: Int, $cursor: String) {
17514
+ evalRunTrials(id: $id, limit: $limit, cursor: $cursor) {
17515
+ trials {
17516
+ id
17517
+ createdAt
17518
+ updatedAt
17519
+ evalRunId
17520
+ repeatIndex
17521
+ input
17522
+ status
17523
+ startedAt
17524
+ finishedAt
17525
+ scores
17526
+ output
17527
+ workflowId
17528
+ workflowRunId
17529
+ }
17530
+ nextCursor
17531
+ }
17532
+ }`
17533
+ }),
17534
+ createOperationSpec({
17535
+ operationName: "CancelEvalRun",
17536
+ kind: "mutation",
17537
+ inputSchema: z25.object({ id: z25.string().min(1) }),
17538
+ cli: {
17539
+ name: "cancel-eval-run",
17540
+ path: ["evals", "runs", "cancel"],
17541
+ description: "Request cancellation for a queued or running eval run.",
17542
+ resultKey: "cancelEvalRun",
17543
+ options: [
17544
+ stringOption({
17545
+ description: "Eval run ID.",
17546
+ flagName: "id",
17547
+ inputKey: "id",
17548
+ required: true
17549
+ })
17550
+ ]
17551
+ },
17552
+ mcp: { fileName: "cancelEvalRun.graphql" },
17553
+ scope: "global",
17554
+ document: `# Request cancellation without claiming the run has already reached CANCELLED
17555
+ mutation CancelEvalRun($id: String!) {
17556
+ cancelEvalRun(id: $id) {
17557
+ evalRunId
17558
+ cancellationRequested
17559
+ status
17560
+ }
17561
+ }`
17562
+ }),
17563
+ createOperationSpec({
17564
+ operationName: "RequestEvalRunExport",
17565
+ kind: "mutation",
17566
+ inputSchema: z25.object({ id: z25.string().min(1) }),
17567
+ cli: {
17568
+ name: "request-eval-run-export",
17569
+ path: ["evals", "runs", "export"],
17570
+ description: "Request an asynchronous raw-results export.",
17571
+ resultKey: "requestEvalRunExport",
17572
+ options: [
17573
+ stringOption({
17574
+ description: "Eval run ID.",
17575
+ flagName: "id",
17576
+ inputKey: "id",
17577
+ required: true
17578
+ }),
17579
+ stringOption({
17580
+ clientOnly: true,
17581
+ description: "Destination path for the completed export.",
17582
+ flagName: "output",
17583
+ inputKey: "output",
17584
+ required: true
17585
+ }),
17586
+ booleanOption({
17587
+ clientOnly: true,
17588
+ description: "Wait for export completion and download the file.",
17589
+ flagName: "wait",
17590
+ inputKey: "wait"
17591
+ }),
17592
+ booleanOption({
17593
+ clientOnly: true,
17594
+ description: "Authorize replacement of an existing output file.",
17595
+ flagName: "force",
17596
+ inputKey: "force"
17597
+ })
17598
+ ]
17599
+ },
17600
+ mcp: { fileName: "requestEvalRunExport.graphql" },
17601
+ scope: "global",
17602
+ document: `# Request or reuse an asynchronous raw-results export for a terminal eval run
17603
+ mutation RequestEvalRunExport($id: String!) {
17604
+ requestEvalRunExport(id: $id) {
17605
+ ${evalRunExportSelection}
17606
+ }
17607
+ }`
17608
+ }),
17609
+ createOperationSpec({
17610
+ operationName: "GetEvalRunExport",
17611
+ kind: "query",
17612
+ inputSchema: z25.object({ exportId: z25.string().min(1) }),
17613
+ cli: {
17614
+ hidden: true,
17615
+ name: "get-eval-run-export",
17616
+ path: ["evals", "runs", "export-status"],
17617
+ description: "Get asynchronous eval export status by export ID.",
17618
+ resultKey: "evalRunExport",
17619
+ options: [
17620
+ stringOption({
17621
+ description: "Eval export ID.",
17622
+ flagName: "export-id",
17623
+ inputKey: "exportId",
17624
+ required: true
17625
+ })
17626
+ ]
17627
+ },
17628
+ mcp: { fileName: "evalRunExport.graphql" },
17629
+ scope: "global",
17630
+ document: `# Get asynchronous eval export status; downloadUrl is signed and only present when COMPLETE
17631
+ query GetEvalRunExport($exportId: String!) {
17632
+ evalRunExport(exportId: $exportId) {
17633
+ ${evalRunExportSelection}
17634
+ }
17635
+ }`
17636
+ })
17637
+ ];
17638
+
17639
+ // src/program.ts
17640
+ import { Command as Command2, InvalidArgumentError as InvalidArgumentError2, Option as Option2 } from "commander";
17641
+
17642
+ // src/api.ts
17643
+ import { randomUUID } from "node:crypto";
17644
+ import { createWriteStream } from "node:fs";
17645
+ import { access, link, rename, rm } from "node:fs/promises";
17646
+ import nodePath from "node:path";
17647
+ import { Readable } from "node:stream";
17648
+ import { pipeline } from "node:stream/promises";
17649
+ import { z as z26 } from "zod";
17650
+
17651
+ // src/version.ts
17652
+ import fs from "node:fs";
17653
+ import path from "node:path";
17654
+ import { fileURLToPath } from "node:url";
17655
+ var packageManifestPath = path.resolve(
17656
+ path.dirname(fileURLToPath(import.meta.url)),
17657
+ "../package.json"
17658
+ );
17659
+ var packageManifestResult = safeJsonParse(
17660
+ fs.readFileSync(packageManifestPath, "utf8")
17661
+ );
17662
+ if (isErr(packageManifestResult)) {
17663
+ throw new Error(`Failed to parse ${packageManifestPath}.`, {
17664
+ cause: packageManifestResult.error.cause
17665
+ });
17666
+ }
17667
+ var cliPackageVersion = packageManifestResult.value.version;
17668
+ if (typeof cliPackageVersion !== "string" || cliPackageVersion.length === 0) {
17669
+ throw new Error(`Expected a version in ${packageManifestPath}.`);
17670
+ }
17671
+ var CLI_VERSION = cliPackageVersion;
17672
+
17673
+ // src/api.ts
17674
+ var OTTO_AUTHORIZATION_HEADER_NAME = "X-Otto-Authorization";
17675
+ var OTTO_AUTHORIZATION_ISSUER = "magical:otto";
17676
+ var workosOrganizationsResponseSchema = z26.object({
17677
+ organizations: z26.array(
17678
+ z26.object({
17679
+ id: z26.string().min(1),
17680
+ name: z26.string().min(1),
17681
+ primaryDomain: z26.string().nullable().optional()
17682
+ })
17683
+ ),
17684
+ success: z26.boolean()
17685
+ });
17686
+ var workosUserSchema = z26.object({
17687
+ email: z26.string().nullable(),
17688
+ id: z26.string().min(1)
17689
+ });
17690
+ var nangoIntegrationWireSchema = z26.object({
17691
+ // eslint-disable-next-line @typescript-eslint/naming-convention -- mirrors Nango REST payload
17692
+ unique_key: z26.string().min(1)
17693
+ }).passthrough().transform((data) => ({
17694
+ ...data,
17695
+ uniqueKey: data.unique_key
17696
+ }));
17697
+ var nangoIntegrationsResponseSchema = z26.array(nangoIntegrationWireSchema);
17698
+ var organizationAuthenticationSchema = z26.object({
17699
+ id: z26.string().min(1),
17700
+ type: z26.string().min(1),
17701
+ connectionId: z26.string().nullable().optional(),
17702
+ providerConfigKey: z26.string().nullable().optional(),
17703
+ description: z26.string().nullable().optional(),
17704
+ hostname: z26.string().nullable().optional()
17705
+ }).passthrough();
17706
+ var organizationAuthenticationsResponseSchema = z26.object({
17707
+ authentications: z26.array(organizationAuthenticationSchema),
17708
+ success: z26.boolean()
17709
+ });
17710
+ var graphQlResponseSchema = z26.object({
17711
+ data: z26.record(z26.string(), z26.unknown()).nullable().optional(),
17712
+ errors: z26.array(
17713
+ z26.object({
17714
+ extensions: z26.object({
17715
+ code: z26.string().min(1).optional()
17716
+ }).passthrough().optional(),
17717
+ message: z26.string().min(1)
17718
+ })
17719
+ ).optional()
17720
+ });
17721
+ var apiErrorResponseSchema = z26.object({
17722
+ errors: z26.array(
17723
+ z26.object({
17724
+ message: z26.string().min(1)
17725
+ })
17726
+ ).optional(),
17727
+ message: z26.string().min(1).optional()
17728
+ });
17729
+ function getApiErrorDetail(responseBody) {
17730
+ const parsedResponse = apiErrorResponseSchema.safeParse(responseBody);
17731
+ if (!parsedResponse.success) {
17732
+ return null;
17733
+ }
17734
+ if (parsedResponse.data.message) {
17735
+ return parsedResponse.data.message;
17736
+ }
17737
+ if (!parsedResponse.data.errors || parsedResponse.data.errors.length === 0) {
17738
+ return null;
17739
+ }
17740
+ return parsedResponse.data.errors.map((error) => error.message).join("\n");
17741
+ }
17742
+ var DEFINITIVE_GRAPHQL_APPLICATION_ERROR_CODES = /* @__PURE__ */ new Set([
17743
+ "BAD_REQUEST",
17744
+ "BAD_USER_INPUT",
17745
+ "FORBIDDEN",
17746
+ "GRAPHQL_PARSE_FAILED",
17747
+ "GRAPHQL_VALIDATION_FAILED",
17748
+ "NOT_FOUND",
17749
+ "OPERATION_RESOLUTION_FAILURE",
17750
+ "PERSISTED_QUERY_NOT_FOUND",
17751
+ "PERSISTED_QUERY_NOT_SUPPORTED",
17752
+ "UNAUTHORIZED"
17753
+ ]);
17754
+ var GraphQlResponseError = class extends CliError {
17755
+ graphQlCodes;
17756
+ hasUnclassifiedGraphQlErrors;
17757
+ constructor(message, {
17758
+ graphQlCodes,
17759
+ hasUnclassifiedGraphQlErrors = false
17760
+ }) {
17761
+ super(message);
17762
+ this.name = "GraphQlResponseError";
17763
+ this.graphQlCodes = [...graphQlCodes];
17764
+ this.hasUnclassifiedGraphQlErrors = hasUnclassifiedGraphQlErrors;
17765
+ }
17766
+ };
17767
+ function isDefinitiveGraphQlApplicationError(error) {
17768
+ return error instanceof GraphQlResponseError && !error.hasUnclassifiedGraphQlErrors && error.graphQlCodes.length > 0 && error.graphQlCodes.every(
17769
+ (code) => DEFINITIVE_GRAPHQL_APPLICATION_ERROR_CODES.has(code)
17770
+ );
17771
+ }
17772
+ function trimTrailingSlash(value) {
17773
+ return value.replace(/\/+$/u, "");
17774
+ }
17775
+ function isFileAlreadyExistsError(error) {
17776
+ return error instanceof Error && "code" in error && error.code === "EEXIST";
17777
+ }
17778
+ async function assertOutputDoesNotExist(outputPath) {
17779
+ const outputExists = await access(outputPath).then(() => true).catch((error) => {
17780
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
17781
+ return false;
17782
+ }
17783
+ throw new CliError(`Failed to inspect export path "${outputPath}".`, {
17784
+ cause: error
17785
+ });
17786
+ });
17787
+ if (outputExists) {
17788
+ throw new CliError(
17789
+ `Refusing to overwrite existing file "${outputPath}". Pass --force to authorize replacement.`
17790
+ );
17791
+ }
17792
+ }
17793
+ function isRecord4(value) {
17794
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17795
+ }
17796
+ function decodeJwtPayload(token) {
17797
+ const [, payloadSegment] = token.split(".");
17798
+ if (!payloadSegment) {
17799
+ return null;
17800
+ }
17801
+ const payloadResult = safeJsonParse(
17802
+ Buffer.from(payloadSegment, "base64url").toString("utf8")
17803
+ );
17804
+ if (isErr(payloadResult)) {
17805
+ return null;
17806
+ }
17807
+ return isRecord4(payloadResult.value) ? payloadResult.value : null;
17808
+ }
17809
+ function isOttoAuthorizationToken(token) {
17810
+ return decodeJwtPayload(token)?.["iss"] === OTTO_AUTHORIZATION_ISSUER;
17811
+ }
17812
+ function applyAuthenticationHeaders({
17813
+ accessToken,
17814
+ allowOttoAuthorization,
17815
+ headers,
17816
+ impersonatedOrganizationId,
17817
+ organizationId
17818
+ }) {
17819
+ if (!isOttoAuthorizationToken(accessToken)) {
17820
+ headers.set("authorization", `Bearer ${accessToken}`);
17821
+ if (impersonatedOrganizationId) {
17822
+ headers.set("x-organization-id", impersonatedOrganizationId);
17823
+ }
17824
+ return;
17825
+ }
17826
+ if (!allowOttoAuthorization) {
17117
17827
  throw new CliError(
17118
17828
  "Otto authorization is only supported for GraphQL requests."
17119
17829
  );
@@ -17133,11 +17843,11 @@ function createMagicalApiClient({
17133
17843
  accessToken,
17134
17844
  impersonatedOrganizationId,
17135
17845
  allowOttoAuthorization,
17136
- path: path8,
17846
+ path: path9,
17137
17847
  init,
17138
17848
  organizationId
17139
17849
  }) {
17140
- const url = `${trimTrailingSlash(await resolveApiBaseUrl())}${path8}`;
17850
+ const url = `${trimTrailingSlash(await resolveApiBaseUrl())}${path9}`;
17141
17851
  const headers = new Headers(init?.headers);
17142
17852
  applyAuthenticationHeaders({
17143
17853
  accessToken,
@@ -17182,6 +17892,51 @@ function createMagicalApiClient({
17182
17892
  return responseBody;
17183
17893
  }
17184
17894
  return {
17895
+ async downloadFile({ outputPath, overwrite = false, url }) {
17896
+ if (!overwrite) {
17897
+ await assertOutputDoesNotExist(outputPath);
17898
+ }
17899
+ const temporaryPath = nodePath.join(
17900
+ nodePath.dirname(outputPath),
17901
+ `.${nodePath.basename(outputPath)}.${randomUUID()}.tmp`
17902
+ );
17903
+ await (async () => {
17904
+ const response = await fetchFn(url).catch((error) => {
17905
+ throw new CliError("Failed to download eval export.", {
17906
+ cause: error
17907
+ });
17908
+ });
17909
+ if (!response.ok) {
17910
+ throw new CliError(
17911
+ `Eval export download failed with status ${response.status}.`
17912
+ );
17913
+ }
17914
+ if (!response.body) {
17915
+ throw new CliError("Eval export download returned an empty body.");
17916
+ }
17917
+ await pipeline(
17918
+ Readable.fromWeb(response.body),
17919
+ createWriteStream(temporaryPath, { flags: "wx" })
17920
+ );
17921
+ if (overwrite) {
17922
+ await rename(temporaryPath, outputPath);
17923
+ return;
17924
+ }
17925
+ await link(temporaryPath, outputPath).catch((error) => {
17926
+ if (isFileAlreadyExistsError(error)) {
17927
+ throw new CliError(
17928
+ `Refusing to overwrite existing file "${outputPath}". Pass --force to authorize replacement.`,
17929
+ { cause: error }
17930
+ );
17931
+ }
17932
+ throw error;
17933
+ });
17934
+ await rm(temporaryPath, { force: true });
17935
+ })().catch(async (error) => {
17936
+ await rm(temporaryPath, { force: true });
17937
+ throw error;
17938
+ });
17939
+ },
17185
17940
  async executeGraphQl({
17186
17941
  accessToken,
17187
17942
  impersonatedOrganizationId,
@@ -17213,8 +17968,15 @@ function createMagicalApiClient({
17213
17968
  throw new CliError("GraphQL response payload was invalid.");
17214
17969
  }
17215
17970
  if (parsedResponse.data.errors && parsedResponse.data.errors.length > 0) {
17216
- throw new CliError(
17217
- parsedResponse.data.errors.map((error) => error.message).join("\n")
17971
+ const graphQlCodes = parsedResponse.data.errors.flatMap(
17972
+ (error) => error.extensions?.code ? [error.extensions.code] : []
17973
+ );
17974
+ throw new GraphQlResponseError(
17975
+ parsedResponse.data.errors.map((error) => error.message).join("\n"),
17976
+ {
17977
+ graphQlCodes,
17978
+ hasUnclassifiedGraphQlErrors: graphQlCodes.length !== parsedResponse.data.errors.length
17979
+ }
17218
17980
  );
17219
17981
  }
17220
17982
  return parsedResponse.data.data?.[resultKey] ?? null;
@@ -17372,7 +18134,7 @@ function requireWorkosClientId(config) {
17372
18134
  }
17373
18135
 
17374
18136
  // src/settings.ts
17375
- import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
18137
+ import { mkdir, readFile, rm as rm2, writeFile } from "node:fs/promises";
17376
18138
  import path3 from "node:path";
17377
18139
  import { z as z27 } from "zod";
17378
18140
  var cliSettingsSchema = z27.object({
@@ -17431,7 +18193,7 @@ function createFileSettingsStore(stateFilePath) {
17431
18193
  },
17432
18194
  async save(settings) {
17433
18195
  if (!hasCliSettingsOverrides(settings)) {
17434
- await rm(settingsFilePath, { force: true });
18196
+ await rm2(settingsFilePath, { force: true });
17435
18197
  return;
17436
18198
  }
17437
18199
  await mkdir(path3.dirname(settingsFilePath), { recursive: true });
@@ -17520,6 +18282,7 @@ var rootOperationalGroupDescriptions = /* @__PURE__ */ new Map([
17520
18282
  ["automations", "Manage automations."],
17521
18283
  ["automation-runs", "Inspect and control automation runs."],
17522
18284
  ["catalog", "Inspect available commands, models, and tools."],
18285
+ ["evals", "Discover registered evals and manage eval runs."],
17523
18286
  ["graphql", "Inspect GraphQL metadata."],
17524
18287
  ["skills", "Inspect and update root-level Workplace skills."]
17525
18288
  ]);
@@ -17549,11 +18312,498 @@ function createOperationHelpExamples(operationSpec) {
17549
18312
  const baseInvocation = [baseCommand, ...requiredOptions].join(" ");
17550
18313
  return [
17551
18314
  baseInvocation,
17552
- `${baseInvocation} --org <org>`,
18315
+ ...operationSpec.scope === "global" ? [] : [`${baseInvocation} --org <org>`],
17553
18316
  `${baseInvocation} --json`
17554
18317
  ];
17555
18318
  }
17556
18319
 
18320
+ // src/eval-commands.ts
18321
+ import { randomUUID as randomUUID2 } from "node:crypto";
18322
+ import { access as access2, readFile as readFile2 } from "node:fs/promises";
18323
+ import path4 from "node:path";
18324
+ import { createInterface } from "node:readline/promises";
18325
+ import { z as z28 } from "zod";
18326
+ var MAX_AWAIT_REQUEST_MS = 6e4;
18327
+ var MIN_AWAIT_REQUEST_MS = 1e3;
18328
+ var EXPORT_POLL_INTERVAL_MS = 1e3;
18329
+ var evalRunStatusSchema2 = z28.enum([
18330
+ "QUEUED",
18331
+ "RUNNING",
18332
+ "COMPLETE",
18333
+ "FAILED",
18334
+ "CANCELLED"
18335
+ ]);
18336
+ var awaitResultSchema = z28.object({
18337
+ elapsedMs: z28.number().nonnegative(),
18338
+ evalRun: z28.object({
18339
+ id: z28.string().min(1),
18340
+ status: evalRunStatusSchema2
18341
+ }).passthrough(),
18342
+ pollCount: z28.number().int().nonnegative(),
18343
+ reachedTerminal: z28.boolean()
18344
+ }).passthrough();
18345
+ var planResultSchema = z28.object({ trialCount: z28.number().int().nonnegative() }).passthrough();
18346
+ var startResultSchema = z28.object({
18347
+ evalRunId: z28.string().min(1),
18348
+ idempotencyKey: z28.string().min(1),
18349
+ workflowId: z28.string().min(1),
18350
+ workflowRunId: z28.string().min(1)
18351
+ }).passthrough();
18352
+ var exportResultSchema = z28.object({
18353
+ downloadUrl: z28.string().min(1).nullable().optional(),
18354
+ evalRunId: z28.string().min(1),
18355
+ exportId: z28.string().min(1),
18356
+ status: z28.enum(["QUEUED", "RUNNING", "COMPLETE", "FAILED"])
18357
+ }).passthrough();
18358
+ var inputOptionsSchema = z28.object({
18359
+ inputFile: z28.string().min(1).optional(),
18360
+ inputJson: z28.unknown().optional()
18361
+ });
18362
+ var commonRunOptionsSchema = inputOptionsSchema.extend({
18363
+ description: z28.string().min(1).optional(),
18364
+ maxConcurrency: z28.number().int().positive().optional(),
18365
+ name: z28.string().min(1).optional(),
18366
+ repeatCount: z28.number().int().positive().optional(),
18367
+ slug: z28.string().min(1),
18368
+ tags: z28.array(z28.string().min(1)).optional()
18369
+ });
18370
+ function parseApiResult(value, schema, label) {
18371
+ const parsedResult = schema.safeParse(value);
18372
+ if (!parsedResult.success) {
18373
+ throw new CliError(`${label} returned an invalid response.`);
18374
+ }
18375
+ return parsedResult.data;
18376
+ }
18377
+ async function parseInputFile({
18378
+ inputFile,
18379
+ workingDirectory
18380
+ }) {
18381
+ const inputPath = path4.resolve(workingDirectory, inputFile);
18382
+ const contents = await readFile2(inputPath, "utf8").catch(
18383
+ (error) => {
18384
+ throw new CliError(`Failed to read eval input file "${inputPath}".`, {
18385
+ cause: error
18386
+ });
18387
+ }
18388
+ );
18389
+ const parsedJson = safeJsonParseWithoutLogging(contents);
18390
+ if (isErr(parsedJson)) {
18391
+ throw new CliError(
18392
+ `Eval input file "${inputPath}" must contain valid JSON.`,
18393
+ { cause: parsedJson.error }
18394
+ );
18395
+ }
18396
+ return parsedJson.value;
18397
+ }
18398
+ async function resolveEvalInput({
18399
+ inputFile,
18400
+ inputJson,
18401
+ workingDirectory
18402
+ }) {
18403
+ const inputSourceCount = Number(inputFile !== void 0) + Number(inputJson !== void 0);
18404
+ if (inputSourceCount !== 1) {
18405
+ throw new CliError(
18406
+ "Pass exactly one of --input-file or --input-json for eval input."
18407
+ );
18408
+ }
18409
+ const input = inputFile === void 0 ? inputJson : await parseInputFile({ inputFile, workingDirectory });
18410
+ const parsedInput = z28.record(z28.string(), z28.unknown()).safeParse(input);
18411
+ if (!parsedInput.success) {
18412
+ throw new CliError("Eval input must be a JSON object.");
18413
+ }
18414
+ return parsedInput.data;
18415
+ }
18416
+ async function resolveEvalInputFromOptions({
18417
+ inputFile,
18418
+ inputJson,
18419
+ workingDirectory
18420
+ }) {
18421
+ return await resolveEvalInput({
18422
+ ...inputFile === void 0 ? {} : { inputFile },
18423
+ ...inputJson === void 0 ? {} : { inputJson },
18424
+ workingDirectory
18425
+ });
18426
+ }
18427
+ function buildCommonRunVariables({
18428
+ input,
18429
+ options
18430
+ }) {
18431
+ return {
18432
+ input,
18433
+ slug: options.slug,
18434
+ ...options.description === void 0 ? {} : { description: options.description },
18435
+ ...options.maxConcurrency === void 0 ? {} : { maxConcurrency: options.maxConcurrency },
18436
+ ...options.name === void 0 ? {} : { name: options.name },
18437
+ ...options.repeatCount === void 0 ? {} : { repeatCount: options.repeatCount },
18438
+ ...options.tags === void 0 ? {} : { tags: options.tags }
18439
+ };
18440
+ }
18441
+ function parseDurationMs(value) {
18442
+ const match = /^(?<amount>\d+(?:\.\d+)?)(?<unit>ms|s|m|h)$/iu.exec(
18443
+ value.trim()
18444
+ );
18445
+ const amount = Number(match?.groups?.["amount"]);
18446
+ const multiplierByUnit = { h: 36e5, m: 6e4, ms: 1, s: 1e3 };
18447
+ const parsedUnit = z28.enum(["h", "m", "ms", "s"]).safeParse(match?.groups?.["unit"]?.toLowerCase());
18448
+ const durationMs = parsedUnit.success ? amount * multiplierByUnit[parsedUnit.data] : Number.NaN;
18449
+ if (!Number.isSafeInteger(durationMs) || durationMs < MIN_AWAIT_REQUEST_MS) {
18450
+ throw new CliError(
18451
+ "Expected --timeout to be a duration of at least 1s, such as 30s, 5m, or 1h."
18452
+ );
18453
+ }
18454
+ return durationMs;
18455
+ }
18456
+ function quotePosixShellArgument(value) {
18457
+ return `'${value.replaceAll("'", `'"'"'`)}'`;
18458
+ }
18459
+ async function defaultConfirm(question) {
18460
+ const prompt = createInterface({
18461
+ input: process.stdin,
18462
+ output: process.stdout
18463
+ });
18464
+ const answer = await prompt.question(`${question} [y/N] `).finally(() => {
18465
+ prompt.close();
18466
+ });
18467
+ return answer.trim().toLowerCase() === "y" || answer.trim().toLowerCase() === "yes";
18468
+ }
18469
+ function terminalExitError(result) {
18470
+ const { id, status } = result.evalRun;
18471
+ if (status === "FAILED" || status === "CANCELLED") {
18472
+ return new CliError(`Eval run "${id}" finished with status ${status}.`);
18473
+ }
18474
+ return void 0;
18475
+ }
18476
+ async function awaitEvalRun({
18477
+ evalRunId,
18478
+ executeOperation,
18479
+ now: now2,
18480
+ timeoutMs
18481
+ }) {
18482
+ const deadline = timeoutMs === void 0 ? void 0 : now2() + timeoutMs;
18483
+ let previousResult = void 0;
18484
+ for (; ; ) {
18485
+ const remainingMs = deadline === void 0 ? void 0 : deadline - now2();
18486
+ if (remainingMs !== void 0 && remainingMs < MIN_AWAIT_REQUEST_MS) {
18487
+ return {
18488
+ exitError: new CliError(
18489
+ `Timed out waiting for eval run "${evalRunId}".`
18490
+ ),
18491
+ result: previousResult ?? {
18492
+ elapsedMs: timeoutMs ?? 0,
18493
+ evalRun: { id: evalRunId, status: "QUEUED" },
18494
+ pollCount: 0,
18495
+ reachedTerminal: false
18496
+ }
18497
+ };
18498
+ }
18499
+ const requestTimeoutMs = Math.min(
18500
+ MAX_AWAIT_REQUEST_MS,
18501
+ remainingMs ?? MAX_AWAIT_REQUEST_MS
18502
+ );
18503
+ const result = parseApiResult(
18504
+ // eslint-disable-next-line no-await-in-loop -- each long-poll must finish before the next bounded request begins
18505
+ await executeOperation("AwaitEvalRun", {
18506
+ id: evalRunId,
18507
+ timeoutMs: requestTimeoutMs
18508
+ }),
18509
+ awaitResultSchema,
18510
+ "Eval run await"
18511
+ );
18512
+ if (result.reachedTerminal) {
18513
+ const exitError = terminalExitError(result);
18514
+ return { ...exitError ? { exitError } : {}, result };
18515
+ }
18516
+ previousResult = result;
18517
+ }
18518
+ }
18519
+ async function assertExportOutputAvailable({
18520
+ force,
18521
+ outputPath
18522
+ }) {
18523
+ if (force) {
18524
+ return;
18525
+ }
18526
+ const exists = await access2(outputPath).then(() => true).catch((error) => {
18527
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
18528
+ return false;
18529
+ }
18530
+ throw new CliError(`Failed to inspect export path "${outputPath}".`, {
18531
+ cause: error
18532
+ });
18533
+ });
18534
+ if (exists) {
18535
+ throw new CliError(
18536
+ `Refusing to overwrite existing file "${outputPath}". Pass --force to authorize replacement.`
18537
+ );
18538
+ }
18539
+ }
18540
+ async function finishExport({
18541
+ downloadFile,
18542
+ exportResult,
18543
+ force,
18544
+ outputPath
18545
+ }) {
18546
+ if (exportResult.status === "FAILED") {
18547
+ return {
18548
+ exitError: new CliError(`Eval export "${exportResult.exportId}" failed.`),
18549
+ result: exportResult
18550
+ };
18551
+ }
18552
+ if (exportResult.status !== "COMPLETE") {
18553
+ return { result: exportResult };
18554
+ }
18555
+ if (!exportResult.downloadUrl) {
18556
+ throw new CliError(
18557
+ `Completed eval export "${exportResult.exportId}" did not include a download URL.`
18558
+ );
18559
+ }
18560
+ if (!downloadFile) {
18561
+ throw new CliError("Eval export download is not configured.");
18562
+ }
18563
+ await downloadFile({
18564
+ outputPath,
18565
+ overwrite: force,
18566
+ url: exportResult.downloadUrl
18567
+ });
18568
+ const { downloadUrl: _downloadUrl, ...downloadedExport } = exportResult;
18569
+ return { result: { ...downloadedExport, outputPath } };
18570
+ }
18571
+ async function pollExport({
18572
+ executeOperation,
18573
+ exportId,
18574
+ sleep
18575
+ }) {
18576
+ for (; ; ) {
18577
+ await sleep(EXPORT_POLL_INTERVAL_MS);
18578
+ const result = parseApiResult(
18579
+ // eslint-disable-next-line no-await-in-loop -- do not overlap signed-export status requests
18580
+ await executeOperation("GetEvalRunExport", { exportId }),
18581
+ exportResultSchema,
18582
+ "Eval export status"
18583
+ );
18584
+ if (result.status !== "QUEUED" && result.status !== "RUNNING") {
18585
+ return result;
18586
+ }
18587
+ }
18588
+ }
18589
+ async function executeTestRegisteredEval({
18590
+ executeOperation,
18591
+ options,
18592
+ workingDirectory
18593
+ }) {
18594
+ const parsedOptions = commonRunOptionsSchema.pick({ slug: true }).merge(inputOptionsSchema).parse(options);
18595
+ const input = await resolveEvalInputFromOptions({
18596
+ ...parsedOptions,
18597
+ workingDirectory
18598
+ });
18599
+ return {
18600
+ result: await executeOperation("TestRegisteredEval", {
18601
+ input,
18602
+ slug: parsedOptions.slug
18603
+ })
18604
+ };
18605
+ }
18606
+ async function executePlanRegisteredEvalRun({
18607
+ executeOperation,
18608
+ options,
18609
+ workingDirectory
18610
+ }) {
18611
+ const parsedOptions = commonRunOptionsSchema.parse(options);
18612
+ const input = await resolveEvalInputFromOptions({
18613
+ ...parsedOptions,
18614
+ workingDirectory
18615
+ });
18616
+ return {
18617
+ result: await executeOperation(
18618
+ "PlanRegisteredEvalRun",
18619
+ buildCommonRunVariables({ input, options: parsedOptions })
18620
+ )
18621
+ };
18622
+ }
18623
+ async function confirmPlannedTrialCount({
18624
+ confirm,
18625
+ confirmedTrialCount,
18626
+ isInteractive,
18627
+ json,
18628
+ trialCount
18629
+ }) {
18630
+ if (confirmedTrialCount !== void 0) {
18631
+ if (confirmedTrialCount !== trialCount) {
18632
+ throw new CliError(
18633
+ `Planned ${trialCount} trials, but --confirm-trials was ${confirmedTrialCount}.`
18634
+ );
18635
+ }
18636
+ return;
18637
+ }
18638
+ if (json || !isInteractive) {
18639
+ throw new CliError(
18640
+ `This run will start ${trialCount} trials. Pass --confirm-trials ${trialCount} in non-interactive mode.`
18641
+ );
18642
+ }
18643
+ const confirmed = await confirm(`Start ${trialCount} eval trials?`);
18644
+ if (confirmed) {
18645
+ return;
18646
+ }
18647
+ throw new CliError("Eval run cancelled before starting.");
18648
+ }
18649
+ async function executeStartRegisteredEvalRun({
18650
+ executeOperation,
18651
+ options,
18652
+ runtime,
18653
+ workingDirectory
18654
+ }) {
18655
+ const parsedOptions = commonRunOptionsSchema.extend({
18656
+ confirmTrials: z28.number().int().positive().optional(),
18657
+ idempotencyKey: z28.string().trim().min(1).optional(),
18658
+ json: z28.boolean().optional(),
18659
+ wait: z28.boolean().optional()
18660
+ }).parse(options);
18661
+ const input = await resolveEvalInputFromOptions({
18662
+ ...parsedOptions,
18663
+ workingDirectory
18664
+ });
18665
+ const commonVariables = buildCommonRunVariables({
18666
+ input,
18667
+ options: parsedOptions
18668
+ });
18669
+ const plan = parseApiResult(
18670
+ await executeOperation("PlanRegisteredEvalRun", commonVariables),
18671
+ planResultSchema,
18672
+ "Eval run plan"
18673
+ );
18674
+ await confirmPlannedTrialCount({
18675
+ confirm: runtime.confirm ?? defaultConfirm,
18676
+ ...parsedOptions.confirmTrials === void 0 ? {} : { confirmedTrialCount: parsedOptions.confirmTrials },
18677
+ isInteractive: runtime.isInteractive?.() ?? (process.stdin.isTTY && process.stdout.isTTY),
18678
+ json: parsedOptions.json === true,
18679
+ trialCount: plan.trialCount
18680
+ });
18681
+ const idempotencyKey = parsedOptions.idempotencyKey ?? `mgcl-eval-${(runtime.randomUuid ?? randomUUID2)()}`;
18682
+ const start = await executeOperation("StartRegisteredEvalRun", {
18683
+ ...commonVariables,
18684
+ expectedTrialCount: plan.trialCount,
18685
+ idempotencyKey
18686
+ }).catch((error) => {
18687
+ if (isDefinitiveGraphQlApplicationError(error)) {
18688
+ throw error;
18689
+ }
18690
+ throw new CliError(
18691
+ `${getErrorMessage(error)}
18692
+ If execution was accepted, retry with --idempotency-key ${quotePosixShellArgument(idempotencyKey)} to resolve the request safely.`,
18693
+ { cause: error }
18694
+ );
18695
+ });
18696
+ const parsedStart = parseApiResult(
18697
+ start,
18698
+ startResultSchema,
18699
+ "Eval run start"
18700
+ );
18701
+ if (parsedOptions.wait !== true) {
18702
+ return { result: parsedStart };
18703
+ }
18704
+ const awaited = await awaitEvalRun({
18705
+ evalRunId: parsedStart.evalRunId,
18706
+ executeOperation,
18707
+ now: runtime.now ?? Date.now
18708
+ });
18709
+ return {
18710
+ ...awaited.exitError ? { exitError: awaited.exitError } : {},
18711
+ result: { ...parsedStart, await: awaited.result }
18712
+ };
18713
+ }
18714
+ async function executeAwaitEvalRun({
18715
+ executeOperation,
18716
+ options,
18717
+ runtime
18718
+ }) {
18719
+ const parsedOptions = z28.object({ id: z28.string().min(1), timeout: z28.string().optional() }).parse(options);
18720
+ return await awaitEvalRun({
18721
+ evalRunId: parsedOptions.id,
18722
+ executeOperation,
18723
+ now: runtime.now ?? Date.now,
18724
+ ...parsedOptions.timeout ? { timeoutMs: parseDurationMs(parsedOptions.timeout) } : {}
18725
+ });
18726
+ }
18727
+ async function defaultSleep(milliseconds) {
18728
+ await new Promise((resolve) => {
18729
+ setTimeout(resolve, milliseconds);
18730
+ });
18731
+ }
18732
+ async function executeRequestEvalRunExport({
18733
+ executeOperation,
18734
+ options,
18735
+ runtime,
18736
+ workingDirectory
18737
+ }) {
18738
+ const parsedOptions = z28.object({
18739
+ force: z28.boolean().optional(),
18740
+ id: z28.string().min(1),
18741
+ output: z28.string().min(1),
18742
+ wait: z28.boolean().optional()
18743
+ }).parse(options);
18744
+ const outputPath = path4.resolve(workingDirectory, parsedOptions.output);
18745
+ const force = parsedOptions.force === true;
18746
+ const shouldWait = parsedOptions.wait === true;
18747
+ if (shouldWait) {
18748
+ await assertExportOutputAvailable({ force, outputPath });
18749
+ }
18750
+ const requestedExport = parseApiResult(
18751
+ await executeOperation("RequestEvalRunExport", { id: parsedOptions.id }),
18752
+ exportResultSchema,
18753
+ "Eval export request"
18754
+ );
18755
+ if (!shouldWait) {
18756
+ return { result: requestedExport };
18757
+ }
18758
+ const exportResult = requestedExport.status === "QUEUED" || requestedExport.status === "RUNNING" ? await pollExport({
18759
+ executeOperation,
18760
+ exportId: requestedExport.exportId,
18761
+ sleep: runtime.sleep ?? defaultSleep
18762
+ }) : requestedExport;
18763
+ if (exportResult.status === "QUEUED" || exportResult.status === "RUNNING") {
18764
+ return { result: exportResult };
18765
+ }
18766
+ return await finishExport({
18767
+ ...runtime.downloadFile ? { downloadFile: runtime.downloadFile } : {},
18768
+ exportResult,
18769
+ force,
18770
+ outputPath
18771
+ });
18772
+ }
18773
+ async function executeEvalCliOperation({
18774
+ executeOperation,
18775
+ operationName,
18776
+ options,
18777
+ runtime = {}
18778
+ }) {
18779
+ const handlerInput = {
18780
+ executeOperation,
18781
+ options,
18782
+ runtime,
18783
+ workingDirectory: runtime.workingDirectory ?? process.cwd()
18784
+ };
18785
+ switch (operationName) {
18786
+ case "TestRegisteredEval": {
18787
+ return await executeTestRegisteredEval(handlerInput);
18788
+ }
18789
+ case "PlanRegisteredEvalRun": {
18790
+ return await executePlanRegisteredEvalRun(handlerInput);
18791
+ }
18792
+ case "StartRegisteredEvalRun": {
18793
+ return await executeStartRegisteredEvalRun(handlerInput);
18794
+ }
18795
+ case "AwaitEvalRun": {
18796
+ return await executeAwaitEvalRun(handlerInput);
18797
+ }
18798
+ case "RequestEvalRunExport": {
18799
+ return await executeRequestEvalRunExport(handlerInput);
18800
+ }
18801
+ default: {
18802
+ return null;
18803
+ }
18804
+ }
18805
+ }
18806
+
17557
18807
  // src/keychain.ts
17558
18808
  function buildKeychainAccountName(account) {
17559
18809
  return `${account.clientId}:${account.userId}`;
@@ -17620,7 +18870,7 @@ function resolveOpenCommand(url) {
17620
18870
  }
17621
18871
 
17622
18872
  // src/program-session.ts
17623
- import { readFile as readFile2, rm as rm2 } from "node:fs/promises";
18873
+ import { readFile as readFile3, rm as rm3 } from "node:fs/promises";
17624
18874
  async function withOrgScopedAccessToken({
17625
18875
  dependencies,
17626
18876
  organizationId,
@@ -17633,6 +18883,35 @@ async function withOrgScopedAccessToken({
17633
18883
  if (directAccessToken) {
17634
18884
  return { accessToken: directAccessToken };
17635
18885
  }
18886
+ return await refreshAccessToken({
18887
+ dependencies,
18888
+ organizationId,
18889
+ state
18890
+ });
18891
+ }
18892
+ async function withGlobalAccessToken({
18893
+ authenticationOrganizationId,
18894
+ dependencies,
18895
+ state
18896
+ }) {
18897
+ const directAccessToken = await loadDirectAccessToken({
18898
+ dependencies,
18899
+ organizationId: authenticationOrganizationId
18900
+ });
18901
+ if (directAccessToken) {
18902
+ return { accessToken: directAccessToken };
18903
+ }
18904
+ return await refreshAccessToken({
18905
+ dependencies,
18906
+ organizationId: authenticationOrganizationId,
18907
+ state
18908
+ });
18909
+ }
18910
+ async function refreshAccessToken({
18911
+ dependencies,
18912
+ organizationId,
18913
+ state
18914
+ }) {
17636
18915
  const refreshToken = await dependencies.refreshTokenStore.load(state.account);
17637
18916
  if (!refreshToken) {
17638
18917
  throw new CliError(
@@ -17664,7 +18943,7 @@ async function clearDirectAccessToken(runtimeConfig) {
17664
18943
  if (!runtimeConfig.accessTokenFilePath) {
17665
18944
  return;
17666
18945
  }
17667
- await rm2(runtimeConfig.accessTokenFilePath, { force: true });
18946
+ await rm3(runtimeConfig.accessTokenFilePath, { force: true });
17668
18947
  }
17669
18948
  async function loadDirectAccessToken({
17670
18949
  dependencies,
@@ -17674,7 +18953,7 @@ async function loadDirectAccessToken({
17674
18953
  if (!accessTokenFilePath) {
17675
18954
  return null;
17676
18955
  }
17677
- const accessTokenFileContents = await readFile2(accessTokenFilePath, "utf8").then((value) => value.trim()).catch((error) => {
18956
+ const accessTokenFileContents = await readFile3(accessTokenFilePath, "utf8").then((value) => value.trim()).catch((error) => {
17678
18957
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
17679
18958
  return null;
17680
18959
  }
@@ -17701,7 +18980,7 @@ async function loadDirectAccessToken({
17701
18980
  }
17702
18981
  return null;
17703
18982
  }
17704
- if (claims.org_id && claims.org_id !== organizationId) {
18983
+ if (organizationId !== void 0 && claims.org_id && claims.org_id !== organizationId) {
17705
18984
  throw new CliError(
17706
18985
  `The current Otto session is authenticated for organization "${claims.org_id}", not "${organizationId}". Start a new Otto session from the desired organization.`
17707
18986
  );
@@ -17718,7 +18997,7 @@ function isExpiredAccessTokenClaims(claims) {
17718
18997
  // src/self-update.ts
17719
18998
  import { spawn as spawn2 } from "node:child_process";
17720
18999
  import fs2 from "node:fs";
17721
- import path4 from "node:path";
19000
+ import path5 from "node:path";
17722
19001
  import { fileURLToPath as fileURLToPath2 } from "node:url";
17723
19002
  var CLI_PACKAGE_NAME = "@getmagical/cli";
17724
19003
  var DEFAULT_CLI_DIST_TAG2 = "latest";
@@ -17729,9 +19008,9 @@ function resolveInstalledPackageRoot({
17729
19008
  packageName
17730
19009
  }) {
17731
19010
  const packagePathSegments = packageName.split("/");
17732
- let currentPath = path4.dirname(entryFilePath);
19011
+ let currentPath = path5.dirname(entryFilePath);
17733
19012
  for (; ; ) {
17734
- const currentPathSegments = currentPath.split(path4.sep).filter(Boolean);
19013
+ const currentPathSegments = currentPath.split(path5.sep).filter(Boolean);
17735
19014
  const currentPackageSegments = currentPathSegments.slice(
17736
19015
  -packagePathSegments.length
17737
19016
  );
@@ -17740,7 +19019,7 @@ function resolveInstalledPackageRoot({
17740
19019
  )) {
17741
19020
  return currentPath;
17742
19021
  }
17743
- const parentPath = path4.dirname(currentPath);
19022
+ const parentPath = path5.dirname(currentPath);
17744
19023
  if (parentPath === currentPath) {
17745
19024
  return null;
17746
19025
  }
@@ -17750,14 +19029,14 @@ function resolveInstalledPackageRoot({
17750
19029
  function resolveInstallPrefixFromPackageRoot(packageRootPath) {
17751
19030
  let currentPath = packageRootPath;
17752
19031
  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);
19032
+ if (path5.basename(currentPath) === "node_modules") {
19033
+ const nodeModulesParentPath = path5.dirname(currentPath);
19034
+ if (path5.basename(nodeModulesParentPath) === "lib") {
19035
+ return path5.dirname(nodeModulesParentPath);
17757
19036
  }
17758
19037
  return nodeModulesParentPath;
17759
19038
  }
17760
- const parentPath = path4.dirname(currentPath);
19039
+ const parentPath = path5.dirname(currentPath);
17761
19040
  if (parentPath === currentPath) {
17762
19041
  return null;
17763
19042
  }
@@ -17774,13 +19053,13 @@ function resolveManagedNpmCommand(installPrefix) {
17774
19053
  if (process.platform === "win32") {
17775
19054
  return null;
17776
19055
  }
17777
- const managedNodeExecutable = path4.join(
19056
+ const managedNodeExecutable = path5.join(
17778
19057
  installPrefix,
17779
19058
  MANAGED_NODE_SUBPATH,
17780
19059
  "bin",
17781
19060
  "node"
17782
19061
  );
17783
- const managedNpmCli = path4.join(
19062
+ const managedNpmCli = path5.join(
17784
19063
  installPrefix,
17785
19064
  MANAGED_NODE_SUBPATH,
17786
19065
  "lib",
@@ -17979,20 +19258,20 @@ ${formatExamples("Examples", [
17979
19258
 
17980
19259
  // src/skills-working-copy.ts
17981
19260
  import { execFile } from "node:child_process";
17982
- import { createHash, randomUUID } from "node:crypto";
19261
+ import { createHash, randomUUID as randomUUID3 } from "node:crypto";
17983
19262
  import {
17984
19263
  lstat,
17985
19264
  mkdir as mkdir2,
17986
19265
  mkdtemp,
17987
- readFile as readFile3,
19266
+ readFile as readFile4,
17988
19267
  readdir,
17989
- rename,
17990
- rm as rm3,
19268
+ rename as rename2,
19269
+ rm as rm4,
17991
19270
  writeFile as writeFile2
17992
19271
  } from "node:fs/promises";
17993
19272
  import os2 from "node:os";
17994
- import path5 from "node:path";
17995
- import { z as z28 } from "zod";
19273
+ import path6 from "node:path";
19274
+ import { z as z29 } from "zod";
17996
19275
  var SKILLS_ROOT_PATH = "skills";
17997
19276
  var METADATA_DIRECTORY_NAME = "skill-working-copies";
17998
19277
  var MAX_GIT_OUTPUT_BYTES = 10 * 1024 * 1024;
@@ -18001,40 +19280,40 @@ var FULL_COMMIT_SHA_PATTERN = /^[\dA-Fa-f]{40}$/u;
18001
19280
  var UTF8_ENCODER = new TextEncoder();
18002
19281
  var WINDOWS_RESERVED_PATH_CHARACTER_PATTERN = /[<>:"|?*]/u;
18003
19282
  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()
19283
+ var skillBundleSchema = z29.object({
19284
+ files: z29.array(
19285
+ z29.object({
19286
+ content: z29.string(),
19287
+ encoding: z29.literal("base64"),
19288
+ path: z29.string().min(1),
19289
+ size: z29.number().int().nonnegative()
18011
19290
  })
18012
19291
  ),
18013
- path: z28.string().min(1),
18014
- ref: z28.string().regex(FULL_COMMIT_SHA_PATTERN)
19292
+ path: z29.string().min(1),
19293
+ ref: z29.string().regex(FULL_COMMIT_SHA_PATTERN)
18015
19294
  });
18016
- var skillsApplyPatchResultSchema = z28.object({
18017
- changedFiles: z28.array(
18018
- z28.object({ path: z28.string().min(1), status: z28.string().min(1) })
19295
+ var skillsApplyPatchResultSchema = z29.object({
19296
+ changedFiles: z29.array(
19297
+ z29.object({ path: z29.string().min(1), status: z29.string().min(1) })
18019
19298
  ),
18020
- commit: z28.string().regex(FULL_COMMIT_SHA_PATTERN),
18021
- ok: z28.boolean(),
18022
- ref: z28.string().min(1)
19299
+ commit: z29.string().regex(FULL_COMMIT_SHA_PATTERN),
19300
+ ok: z29.boolean(),
19301
+ ref: z29.string().min(1)
18023
19302
  }).refine((result) => result.ok, {
18024
19303
  message: "Skills patch result was not successful."
18025
19304
  });
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)
19305
+ var workingCopyMetadataSchema = z29.object({
19306
+ version: z29.literal(1),
19307
+ files: z29.array(
19308
+ z29.object({
19309
+ content: z29.string(),
19310
+ path: z29.string().min(1)
18032
19311
  })
18033
19312
  ),
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)
19313
+ organizationId: z29.string().min(1),
19314
+ requestedRef: z29.string().min(1).nullable(),
19315
+ skillPath: z29.string().min(1),
19316
+ workingCopyPath: z29.string().min(1)
18038
19317
  });
18039
19318
  function hasControlCharacter2(value) {
18040
19319
  return UTF8_ENCODER.encode(value).some((byte) => byte <= 31 || byte === 127);
@@ -18062,12 +19341,12 @@ function normalizeRootSkillPath(skill) {
18062
19341
  return `${SKILLS_ROOT_PATH}/${skillName}`;
18063
19342
  }
18064
19343
  function resolveWorkingCopyPath(workingDirectory, skillPath) {
18065
- return path5.resolve(workingDirectory, ...skillPath.split("/"));
19344
+ return path6.resolve(workingDirectory, ...skillPath.split("/"));
18066
19345
  }
18067
19346
  function resolveMetadataPath(stateFilePath, workingCopyPath) {
18068
19347
  const key = createHash("sha256").update(workingCopyPath).digest("hex");
18069
- return path5.join(
18070
- path5.dirname(stateFilePath),
19348
+ return path6.join(
19349
+ path6.dirname(stateFilePath),
18071
19350
  METADATA_DIRECTORY_NAME,
18072
19351
  `${key}.json`
18073
19352
  );
@@ -18095,7 +19374,7 @@ function metadataFilesToSnapshot(files) {
18095
19374
  );
18096
19375
  }
18097
19376
  async function loadMetadata(metadataPath) {
18098
- const fileContents = await readFile3(metadataPath, "utf8").catch(
19377
+ const fileContents = await readFile4(metadataPath, "utf8").catch(
18099
19378
  (error) => {
18100
19379
  if (isMissingFileError(error)) {
18101
19380
  return null;
@@ -18119,13 +19398,13 @@ async function loadMetadata(metadataPath) {
18119
19398
  return parsed.data;
18120
19399
  }
18121
19400
  async function saveMetadata(metadataPath, metadata) {
18122
- await mkdir2(path5.dirname(metadataPath), { recursive: true });
18123
- const temporaryPath = `${metadataPath}.${randomUUID()}.tmp`;
19401
+ await mkdir2(path6.dirname(metadataPath), { recursive: true });
19402
+ const temporaryPath = `${metadataPath}.${randomUUID3()}.tmp`;
18124
19403
  await writeFile2(temporaryPath, `${JSON.stringify(metadata, null, 2)}
18125
19404
  `, {
18126
19405
  mode: 384
18127
19406
  });
18128
- await rename(temporaryPath, metadataPath);
19407
+ await rename2(temporaryPath, metadataPath);
18129
19408
  }
18130
19409
  function assertSafeRelativeFilePath(relativePath) {
18131
19410
  const segments = relativePath.split("/");
@@ -18196,7 +19475,7 @@ async function readDirectorySnapshot({
18196
19475
  const nextSegments = [...segments, entry.name];
18197
19476
  const relativePath = nextSegments.join("/");
18198
19477
  assertSafeRelativeFilePath(relativePath);
18199
- const filePath = path5.join(currentDirectory, entry.name);
19478
+ const filePath = path6.join(currentDirectory, entry.name);
18200
19479
  if (entry.isDirectory()) {
18201
19480
  return await visit(filePath, nextSegments);
18202
19481
  }
@@ -18205,7 +19484,7 @@ async function readDirectorySnapshot({
18205
19484
  `Skill working copy contains unsupported entry "${filePath}". Only regular files and directories are allowed.`
18206
19485
  );
18207
19486
  }
18208
- return [[`${skillPath}/${relativePath}`, await readFile3(filePath)]];
19487
+ return [[`${skillPath}/${relativePath}`, await readFile4(filePath)]];
18209
19488
  })
18210
19489
  );
18211
19490
  return nestedEntries.flat();
@@ -18231,8 +19510,8 @@ async function writeSnapshotContents(rootPath, snapshot, prefix) {
18231
19510
  [...snapshot.entries()].map(async ([filePath, content]) => {
18232
19511
  const relativePath = prefix === null ? filePath : filePath.slice(`${prefix}/`.length);
18233
19512
  assertSafeRelativeFilePath(relativePath);
18234
- const targetPath = path5.join(rootPath, ...relativePath.split("/"));
18235
- await mkdir2(path5.dirname(targetPath), { recursive: true });
19513
+ const targetPath = path6.join(rootPath, ...relativePath.split("/"));
19514
+ await mkdir2(path6.dirname(targetPath), { recursive: true });
18236
19515
  await writeFile2(targetPath, content);
18237
19516
  })
18238
19517
  );
@@ -18242,42 +19521,42 @@ async function replaceWorkingCopy({
18242
19521
  skillPath,
18243
19522
  workingCopyPath
18244
19523
  }) {
18245
- const parentPath = path5.dirname(workingCopyPath);
19524
+ const parentPath = path6.dirname(workingCopyPath);
18246
19525
  await mkdir2(parentPath, { recursive: true });
18247
- const temporaryPath = path5.join(
19526
+ const temporaryPath = path6.join(
18248
19527
  parentPath,
18249
- `.mgcl-${path5.basename(workingCopyPath)}-${randomUUID()}.tmp`
19528
+ `.mgcl-${path6.basename(workingCopyPath)}-${randomUUID3()}.tmp`
18250
19529
  );
18251
- const backupPath = `${workingCopyPath}.${randomUUID()}.bak`;
19530
+ const backupPath = `${workingCopyPath}.${randomUUID3()}.bak`;
18252
19531
  await mkdir2(temporaryPath);
18253
19532
  const prepareResult = await fromThrowable(async () => {
18254
19533
  await writeSnapshotContents(temporaryPath, snapshot, skillPath);
18255
19534
  const hadExistingWorkingCopy = await pathExists(workingCopyPath);
18256
19535
  if (hadExistingWorkingCopy) {
18257
- await rename(workingCopyPath, backupPath);
19536
+ await rename2(workingCopyPath, backupPath);
18258
19537
  }
18259
19538
  return hadExistingWorkingCopy;
18260
19539
  }, "skills-working-copy-replace-failed");
18261
19540
  if (isErr(prepareResult)) {
18262
- await rm3(temporaryPath, { force: true, recursive: true });
19541
+ await rm4(temporaryPath, { force: true, recursive: true });
18263
19542
  throw new CliError("Failed to replace the skill working copy.", {
18264
19543
  cause: prepareResult.error.cause
18265
19544
  });
18266
19545
  }
18267
19546
  const activationResult = await fromThrowable(async () => {
18268
- await rename(temporaryPath, workingCopyPath);
19547
+ await rename2(temporaryPath, workingCopyPath);
18269
19548
  }, "skills-working-copy-activation-failed");
18270
19549
  if (isErr(activationResult)) {
18271
19550
  if (prepareResult.value) {
18272
- await rename(backupPath, workingCopyPath);
19551
+ await rename2(backupPath, workingCopyPath);
18273
19552
  }
18274
- await rm3(temporaryPath, { force: true, recursive: true });
19553
+ await rm4(temporaryPath, { force: true, recursive: true });
18275
19554
  throw new CliError("Failed to activate the new skill working copy.", {
18276
19555
  cause: activationResult.error.cause
18277
19556
  });
18278
19557
  }
18279
19558
  if (prepareResult.value) {
18280
- await rm3(backupPath, { force: true, recursive: true });
19559
+ await rm4(backupPath, { force: true, recursive: true });
18281
19560
  }
18282
19561
  }
18283
19562
  async function runGit(arguments_, cwd, allowedExitCodes = [0]) {
@@ -18317,7 +19596,7 @@ async function clearDirectoryExceptGit(directoryPath) {
18317
19596
  const entries = await readdir(directoryPath);
18318
19597
  await Promise.all(
18319
19598
  entries.filter((entry) => entry !== ".git").map(async (entry) => {
18320
- await rm3(path5.join(directoryPath, entry), {
19599
+ await rm4(path6.join(directoryPath, entry), {
18321
19600
  force: true,
18322
19601
  recursive: true
18323
19602
  });
@@ -18329,7 +19608,7 @@ async function createPatch(before, after) {
18329
19608
  return "";
18330
19609
  }
18331
19610
  const repositoryPath = await mkdtemp(
18332
- path5.join(os2.tmpdir(), "mgcl-skills-diff-")
19611
+ path6.join(os2.tmpdir(), "mgcl-skills-diff-")
18333
19612
  );
18334
19613
  const patchResult = await fromThrowable(async () => {
18335
19614
  await runGit(["init", "--quiet"], repositoryPath);
@@ -18372,7 +19651,7 @@ async function createPatch(before, after) {
18372
19651
  );
18373
19652
  return result.stdout.toString("utf8");
18374
19653
  }, "skills-patch-generation-failed");
18375
- await rm3(repositoryPath, { force: true, recursive: true });
19654
+ await rm4(repositoryPath, { force: true, recursive: true });
18376
19655
  if (isErr(patchResult)) {
18377
19656
  throw patchResult.error.cause;
18378
19657
  }
@@ -18580,7 +19859,7 @@ async function pushSkillWorkingCopy({
18580
19859
  assertTextPatch(patchContents);
18581
19860
  const applyResult = await fromThrowable(
18582
19861
  async () => await context.api.applyPatch({
18583
- idempotencyKey: `mgcl-skills-${randomUUID()}`,
19862
+ idempotencyKey: `mgcl-skills-${randomUUID3()}`,
18584
19863
  message: message ?? `Update ${workingCopy.skillPath} via mgcl`,
18585
19864
  patch: patchContents
18586
19865
  }),
@@ -18651,34 +19930,34 @@ async function pushSkillWorkingCopy({
18651
19930
  }
18652
19931
 
18653
19932
  // 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)
19933
+ import { mkdir as mkdir3, readFile as readFile5, rm as rm5, writeFile as writeFile3 } from "node:fs/promises";
19934
+ import path7 from "node:path";
19935
+ import { z as z30 } from "zod";
19936
+ var cliAccountSchema = z30.object({
19937
+ clientId: z30.string().min(1),
19938
+ email: z30.string().nullable(),
19939
+ userId: z30.string().min(1)
18661
19940
  });
18662
- var cliOrganizationSchema = z29.object({
18663
- id: z29.string().min(1),
18664
- name: z29.string().min(1),
18665
- primaryDomain: z29.string().nullable().default(null)
19941
+ var cliOrganizationSchema = z30.object({
19942
+ id: z30.string().min(1),
19943
+ name: z30.string().min(1),
19944
+ primaryDomain: z30.string().nullable().default(null)
18666
19945
  });
18667
- var cliStateSchema = z29.object({
19946
+ var cliStateSchema = z30.object({
18668
19947
  account: cliAccountSchema,
18669
- defaultOrgId: z29.string().nullable(),
18670
- lastUsedOrgId: z29.string().nullable(),
18671
- organizations: z29.array(cliOrganizationSchema)
19948
+ defaultOrgId: z30.string().nullable(),
19949
+ lastUsedOrgId: z30.string().nullable(),
19950
+ organizations: z30.array(cliOrganizationSchema)
18672
19951
  });
18673
- var refreshTokenFileSchema = z29.record(z29.string(), z29.string());
19952
+ var refreshTokenFileSchema = z30.record(z30.string(), z30.string());
18674
19953
  function createFileStateStore(stateFilePath) {
18675
19954
  return {
18676
19955
  async clear() {
18677
- await rm4(stateFilePath, { force: true });
19956
+ await rm5(stateFilePath, { force: true });
18678
19957
  },
18679
19958
  async load() {
18680
19959
  try {
18681
- const fileContents = await readFile4(stateFilePath, "utf8");
19960
+ const fileContents = await readFile5(stateFilePath, "utf8");
18682
19961
  const parsed = cliStateSchema.safeParse(JSON.parse(fileContents));
18683
19962
  if (!parsed.success) {
18684
19963
  throw new CliError("Stored CLI state is invalid.");
@@ -18695,7 +19974,7 @@ function createFileStateStore(stateFilePath) {
18695
19974
  }
18696
19975
  },
18697
19976
  async save(state) {
18698
- await mkdir3(path6.dirname(stateFilePath), { recursive: true });
19977
+ await mkdir3(path7.dirname(stateFilePath), { recursive: true });
18699
19978
  await writeFile3(stateFilePath, `${JSON.stringify(state, null, 2)}
18700
19979
  `);
18701
19980
  }
@@ -18704,7 +19983,7 @@ function createFileStateStore(stateFilePath) {
18704
19983
  function createFileRefreshTokenStore(refreshTokenFilePath) {
18705
19984
  async function loadRefreshTokens() {
18706
19985
  try {
18707
- const fileContents = await readFile4(refreshTokenFilePath, "utf8");
19986
+ const fileContents = await readFile5(refreshTokenFilePath, "utf8");
18708
19987
  const parsed = refreshTokenFileSchema.safeParse(JSON.parse(fileContents));
18709
19988
  if (!parsed.success) {
18710
19989
  throw new CliError("Stored refresh tokens are invalid.");
@@ -18723,7 +20002,7 @@ function createFileRefreshTokenStore(refreshTokenFilePath) {
18723
20002
  }
18724
20003
  }
18725
20004
  async function saveRefreshTokens(refreshTokens) {
18726
- await mkdir3(path6.dirname(refreshTokenFilePath), { recursive: true });
20005
+ await mkdir3(path7.dirname(refreshTokenFilePath), { recursive: true });
18727
20006
  await writeFile3(
18728
20007
  refreshTokenFilePath,
18729
20008
  `${JSON.stringify(refreshTokens, null, 2)}
@@ -18740,7 +20019,7 @@ function createFileRefreshTokenStore(refreshTokenFilePath) {
18740
20019
  )
18741
20020
  );
18742
20021
  if (Object.keys(nextRefreshTokens).length === 0) {
18743
- await rm4(refreshTokenFilePath, { force: true });
20022
+ await rm5(refreshTokenFilePath, { force: true });
18744
20023
  return;
18745
20024
  }
18746
20025
  await saveRefreshTokens(nextRefreshTokens);
@@ -18761,37 +20040,37 @@ function buildRefreshTokenKey(account) {
18761
20040
  }
18762
20041
 
18763
20042
  // src/workos-auth.ts
18764
- import { z as z30 } from "zod";
20043
+ import { z as z31 } from "zod";
18765
20044
  var DEFAULT_DEVICE_POLL_INTERVAL_SECONDS = 5;
18766
20045
  function buildFormHeaders() {
18767
20046
  const headers = new Headers();
18768
20047
  headers.set("content-type", "application/x-www-form-urlencoded");
18769
20048
  return headers;
18770
20049
  }
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()
20050
+ var deviceAuthorizationSchema = z31.object({
20051
+ device_code: z31.string().min(1),
20052
+ expires_in: z31.number().int().positive().optional(),
20053
+ interval: z31.number().int().positive().optional(),
20054
+ user_code: z31.string().min(1),
20055
+ verification_uri: z31.url(),
20056
+ verification_uri_complete: z31.url().optional()
18778
20057
  });
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()
20058
+ var tokenResponseSchema = z31.object({
20059
+ access_token: z31.string().min(1),
20060
+ expires_in: z31.number().int().positive().optional(),
20061
+ refresh_token: z31.string().min(1),
20062
+ token_type: z31.string().optional()
18784
20063
  });
18785
- var tokenErrorSchema = z30.object({
18786
- error: z30.string().min(1),
18787
- error_description: z30.string().optional()
20064
+ var tokenErrorSchema = z31.object({
20065
+ error: z31.string().min(1),
20066
+ error_description: z31.string().optional()
18788
20067
  });
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)
20068
+ var accessTokenClaimsSchema = z31.object({
20069
+ exp: z31.number().int().positive().optional(),
20070
+ iss: z31.string().min(1).optional(),
20071
+ org_id: z31.string().min(1).optional(),
20072
+ sid: z31.string().min(1).optional(),
20073
+ sub: z31.string().min(1)
18795
20074
  });
18796
20075
  function createWorkosAuthClient({
18797
20076
  fetchFn = fetch,
@@ -19044,6 +20323,9 @@ function requireApiClientMethod(apiClient, key) {
19044
20323
  function collectOperationVariables(operationSpec, options) {
19045
20324
  const variables = Object.fromEntries(
19046
20325
  operationSpec.cli.options.flatMap((optionSpec) => {
20326
+ if (optionSpec.clientOnly) {
20327
+ return [];
20328
+ }
19047
20329
  const optionValue = options[buildCommandOptionProperty(optionSpec.flagName)];
19048
20330
  if (optionValue === void 0) {
19049
20331
  return [];
@@ -19051,6 +20333,9 @@ function collectOperationVariables(operationSpec, options) {
19051
20333
  return [[optionSpec.inputKey, optionValue]];
19052
20334
  })
19053
20335
  );
20336
+ return parseOperationVariables(operationSpec, variables);
20337
+ }
20338
+ function parseOperationVariables(operationSpec, variables) {
19054
20339
  const parsedVariables = operationSpec.inputSchema.safeParse(variables);
19055
20340
  if (!parsedVariables.success) {
19056
20341
  throw new CliError(
@@ -19130,6 +20415,14 @@ async function handleSelfUpdate(dependencies, options) {
19130
20415
  );
19131
20416
  }
19132
20417
  async function handleOperationCommand(dependencies, operationSpec, commandOptions) {
20418
+ if (operationSpec.scope === "global") {
20419
+ await handleGlobalOperationCommand(
20420
+ dependencies,
20421
+ operationSpec,
20422
+ commandOptions
20423
+ );
20424
+ return;
20425
+ }
19133
20426
  const { accessToken, impersonatedOrganizationId, organization, state } = await withSelectedOrganizationAndAccessToken({
19134
20427
  dependencies,
19135
20428
  options: commandOptions
@@ -19153,16 +20446,89 @@ async function handleOperationCommand(dependencies, operationSpec, commandOption
19153
20446
  }
19154
20447
  dependencies.io.info(formatHumanReadableOutput(result));
19155
20448
  }
19156
- function getSkillsOperation(operationName) {
20449
+ function getOperation(operationName) {
19157
20450
  const operationSpec = operationSpecs.find(
19158
20451
  (candidate) => candidate.operationName === operationName
19159
20452
  );
19160
20453
  if (!operationSpec) {
20454
+ throw new CliError(`Operation "${operationName}" is not registered.`);
20455
+ }
20456
+ return operationSpec;
20457
+ }
20458
+ async function withGlobalOperationAccessToken({
20459
+ dependencies
20460
+ }) {
20461
+ const state = requireLoggedInState(await dependencies.stateStore.load());
20462
+ const directAccessTokenOrganizationId = await resolveDirectAccessTokenOrganizationId({ dependencies });
20463
+ const authenticationOrganizationId = directAccessTokenOrganizationId ?? state.defaultOrgId ?? state.lastUsedOrgId ?? state.organizations[0]?.id;
20464
+ if (!authenticationOrganizationId) {
19161
20465
  throw new CliError(
19162
- `Skills operation "${operationName}" is not registered.`
20466
+ 'No organization is available for authentication. Run "mgcl auth login" again.'
19163
20467
  );
19164
20468
  }
19165
- return operationSpec;
20469
+ const { accessToken } = await withGlobalAccessToken({
20470
+ authenticationOrganizationId,
20471
+ dependencies,
20472
+ state
20473
+ });
20474
+ const usesOttoAuthorization = (() => {
20475
+ try {
20476
+ return dependencies.authClient.decodeAccessTokenClaims(accessToken).iss === "magical:otto";
20477
+ } catch {
20478
+ return false;
20479
+ }
20480
+ })();
20481
+ return {
20482
+ accessToken,
20483
+ ...usesOttoAuthorization ? { organizationId: authenticationOrganizationId } : {}
20484
+ };
20485
+ }
20486
+ async function handleGlobalOperationCommand(dependencies, operationSpec, commandOptions) {
20487
+ const { accessToken, organizationId } = await withGlobalOperationAccessToken({
20488
+ dependencies
20489
+ });
20490
+ const executeOperation = async (operationName, variables) => {
20491
+ const nextOperationSpec = getOperation(operationName);
20492
+ if (nextOperationSpec.scope !== "global") {
20493
+ throw new CliError(
20494
+ `Global operation "${operationName}" cannot execute an organization-scoped operation.`
20495
+ );
20496
+ }
20497
+ return await dependencies.apiClient.executeGraphQl({
20498
+ accessToken,
20499
+ ...organizationId ? { organizationId } : {},
20500
+ query: nextOperationSpec.document,
20501
+ resultKey: nextOperationSpec.cli.resultKey,
20502
+ variables: parseOperationVariables(nextOperationSpec, variables)
20503
+ });
20504
+ };
20505
+ const customResult = await executeEvalCliOperation({
20506
+ executeOperation,
20507
+ operationName: operationSpec.operationName,
20508
+ options: commandOptions,
20509
+ runtime: {
20510
+ ...dependencies.evalCommandRuntime,
20511
+ ...dependencies.apiClient.downloadFile ? { downloadFile: dependencies.apiClient.downloadFile } : {},
20512
+ workingDirectory: dependencies.evalCommandRuntime?.workingDirectory ?? dependencies.workingDirectory ?? process.cwd()
20513
+ }
20514
+ });
20515
+ const commandResult = customResult ?? {
20516
+ result: await executeOperation(
20517
+ operationSpec.operationName,
20518
+ collectOperationVariables(operationSpec, commandOptions)
20519
+ )
20520
+ };
20521
+ writeCommandOutput({
20522
+ dependencies,
20523
+ json: commandOptions.json,
20524
+ result: commandResult.result
20525
+ });
20526
+ if (commandResult.exitError) {
20527
+ throw commandResult.exitError;
20528
+ }
20529
+ }
20530
+ function getSkillsOperation(operationName) {
20531
+ return getOperation(operationName);
19166
20532
  }
19167
20533
  async function withSkillsWorkingCopyContext(dependencies, options) {
19168
20534
  const { accessToken, impersonatedOrganizationId, organization, state } = await withSelectedOrganizationAndAccessToken({ dependencies, options });
@@ -19420,7 +20786,7 @@ async function resolveDirectAccessTokenOrganizationId({
19420
20786
  if (!accessTokenFilePath) {
19421
20787
  return null;
19422
20788
  }
19423
- const accessToken = await readFile5(accessTokenFilePath, "utf8").then((value) => value.trim()).catch((error) => {
20789
+ const accessToken = await readFile6(accessTokenFilePath, "utf8").then((value) => value.trim()).catch((error) => {
19424
20790
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
19425
20791
  return null;
19426
20792
  }
@@ -19452,6 +20818,9 @@ function addRegistryOperationCommand({
19452
20818
  dependencies,
19453
20819
  operationSpec
19454
20820
  }) {
20821
+ if (operationSpec.cli.hidden) {
20822
+ return;
20823
+ }
19455
20824
  const commandPath = [...operationSpec.cli.path];
19456
20825
  const leafCommandName = commandPath.pop();
19457
20826
  if (!leafCommandName) {
@@ -19488,12 +20857,16 @@ function addRegistryOperationCommand({
19488
20857
  configureOperationalCommand(legacyAliasCommand, dependencies, operationSpec);
19489
20858
  }
19490
20859
  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(
20860
+ command.description(operationSpec.cli.description);
20861
+ if (operationSpec.scope !== "global") {
20862
+ command.addOption(
20863
+ new Option2(
20864
+ "--org <org>",
20865
+ "Organization ID or exact organization name to use."
20866
+ ).helpGroup("Shared options:")
20867
+ );
20868
+ }
20869
+ command.addHelpText(
19497
20870
  "after",
19498
20871
  `
19499
20872
  ${formatExamples(
@@ -19532,12 +20905,12 @@ function createConsoleIo() {
19532
20905
  function createDefaultDependencies() {
19533
20906
  const runtimeConfig = getRuntimeConfig();
19534
20907
  const settingsStore = createFileSettingsStore(runtimeConfig.stateFilePath);
19535
- const accessTokenFilePath = runtimeConfig.accessTokenFilePath ?? path7.join(
19536
- path7.dirname(runtimeConfig.stateFilePath),
20908
+ const accessTokenFilePath = runtimeConfig.accessTokenFilePath ?? path8.join(
20909
+ path8.dirname(runtimeConfig.stateFilePath),
19537
20910
  CLI_ACCESS_TOKEN_FILE_NAME
19538
20911
  );
19539
- const refreshTokenFilePath = runtimeConfig.refreshTokenFilePath ?? path7.join(
19540
- path7.dirname(runtimeConfig.stateFilePath),
20912
+ const refreshTokenFilePath = runtimeConfig.refreshTokenFilePath ?? path8.join(
20913
+ path8.dirname(runtimeConfig.stateFilePath),
19541
20914
  CLI_REFRESH_TOKEN_FILE_NAME
19542
20915
  );
19543
20916
  const selfUpdateOptions = {