@mutagent/cli 0.1.192 → 0.1.194

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/cli.js CHANGED
@@ -546,6 +546,31 @@ class SDKClientWrapper {
546
546
  }
547
547
  return response.json();
548
548
  }
549
+ async requestRaw(path, options) {
550
+ const optHeaders = options?.headers;
551
+ let extraHeaders = {};
552
+ if (optHeaders instanceof Headers) {
553
+ optHeaders.forEach((value, key) => {
554
+ extraHeaders[key] = value;
555
+ });
556
+ } else if (optHeaders) {
557
+ extraHeaders = optHeaders;
558
+ }
559
+ const tenancyHeaders = {};
560
+ if (this.workspaceId)
561
+ tenancyHeaders["x-workspace-id"] = this.workspaceId;
562
+ if (this.organizationId)
563
+ tenancyHeaders["x-organization-id"] = this.organizationId;
564
+ return fetch(`${this.endpoint}${path}`, {
565
+ ...options,
566
+ headers: {
567
+ "x-api-key": this.apiKey,
568
+ "Content-Type": "application/json",
569
+ ...tenancyHeaders,
570
+ ...extraHeaders
571
+ }
572
+ });
573
+ }
549
574
  async listPrompts() {
550
575
  try {
551
576
  const response = await this.sdk.prompt.listPrompts();
@@ -675,10 +700,24 @@ class SDKClientWrapper {
675
700
  metadata: item.metadata
676
701
  }));
677
702
  const missingExpectedOutputCount = mappedItems.filter((item) => item.expectedOutput === undefined).length;
678
- await this.request(`/api/prompts/datasets/${String(dataset.id)}/items/bulk`, {
703
+ const bulkResult = await this.requestRaw(`/api/prompts/datasets/${String(dataset.id)}/items/bulk`, {
679
704
  method: "POST",
680
705
  body: JSON.stringify({ items: mappedItems })
681
706
  });
707
+ if (!bulkResult.ok) {
708
+ const bodyText = await bulkResult.text();
709
+ let parsed2;
710
+ try {
711
+ parsed2 = JSON.parse(bodyText);
712
+ } catch {}
713
+ const typed = parsed2;
714
+ if (typed && typed.kind === "bulk_insert_rollback") {
715
+ const constraint = typeof typed.failingConstraint === "string" ? typed.failingConstraint : "unknown";
716
+ const rowIndex = typeof typed.failingRowIndex === "number" ? typed.failingRowIndex : null;
717
+ throw new ApiError(bulkResult.status, `Bulk insert rolled back — constraint: ${constraint}` + (rowIndex !== null ? `, first failing row: ${String(rowIndex)}` : ""));
718
+ }
719
+ throw new ApiError(bulkResult.status, bodyText || "Bulk insert failed");
720
+ }
682
721
  itemCount = mappedItems.length;
683
722
  return { ...dataset, itemCount, missingExpectedOutputCount };
684
723
  }
@@ -839,10 +878,9 @@ class SDKClientWrapper {
839
878
  maxIterations: config?.maxIterations ?? 1,
840
879
  targetScore: config?.targetScore ?? 0.8,
841
880
  patience: config?.patience,
842
- ...config?.execModel ? { executionModel: config.execModel } : {},
843
- ...config?.model ? { model: config.model } : {},
844
- ...config?.evalModel ? { evaluationModel: config.evalModel } : {},
845
- ...config?.optModel ? { optimizationModel: config.optModel } : {},
881
+ ...config?.executionModel ? { executionModel: config.executionModel } : {},
882
+ ...config?.evaluationModel ? { evaluationModel: config.evaluationModel } : {},
883
+ ...config?.optimizationModel ? { optimizationModel: config.optimizationModel } : {},
846
884
  ...config?.providerId ? { executionProviderId: config.providerId } : {},
847
885
  ...config?.evalProviderId ? { evaluationProviderId: config.evalProviderId } : {},
848
886
  ...config?.optProviderId ? { optimizationProviderId: config.optProviderId } : {}
@@ -1271,7 +1309,7 @@ var init_sdk_client = __esm(() => {
1271
1309
  // src/bin/cli.ts
1272
1310
  import { Command as Command21 } from "commander";
1273
1311
  import chalk39 from "chalk";
1274
- import { readFileSync as readFileSync14, existsSync as existsSync17 } from "fs";
1312
+ import { readFileSync as readFileSync15, existsSync as existsSync18 } from "fs";
1275
1313
  import { join as join12, dirname as dirname3 } from "path";
1276
1314
  import { fileURLToPath as fileURLToPath2 } from "url";
1277
1315
 
@@ -2847,7 +2885,7 @@ init_errors();
2847
2885
  init_sdk_client();
2848
2886
  import { Command as Command7 } from "commander";
2849
2887
  import chalk18 from "chalk";
2850
- import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
2888
+ import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
2851
2889
 
2852
2890
  // src/lib/ui-links.ts
2853
2891
  function getAppBaseUrl() {
@@ -3617,10 +3655,14 @@ inputSchema must be provided. Pass it via the API or dashboard.`);
3617
3655
  Add a 'description' field to each property in your inputSchema. Example: { "properties": { "field": { "type": "string", "description": "What this field contains" } } }`);
3618
3656
  }
3619
3657
  }
3620
- if (isSchemaEmpty(data.outputSchema)) {
3621
- output.warn("No outputSchema provided. This may limit optimization effectiveness.");
3622
- } else if (!isValidJsonSchema(data.outputSchema)) {
3658
+ if (!isValidJsonSchema(data.outputSchema)) {
3623
3659
  output.warn(formatSchemaWarning("outputSchema"));
3660
+ } else {
3661
+ const missingOutputDescs = validateSchemaDescriptions(data.outputSchema);
3662
+ if (missingOutputDescs.length > 0) {
3663
+ throw new MutagentError("VALIDATION_ERROR", `outputSchema properties missing descriptions: ${missingOutputDescs.join(", ")}`, `Run: mutagent prompts create --help
3664
+ Add a 'description' field to each property in your outputSchema. Example: { "properties": { "field": { "type": "string", "description": "What this field contains" } } }`);
3665
+ }
3624
3666
  }
3625
3667
  const client = await getSDKClient();
3626
3668
  const prompt = await client.createPrompt(data);
@@ -3696,6 +3738,13 @@ Examples:
3696
3738
  ` + `Add a 'description' field to each property in your inputSchema. Example: { "properties": { "field": { "type": "string", "description": "What this field contains" } } }`);
3697
3739
  }
3698
3740
  }
3741
+ if (data.outputSchema && isValidJsonSchema(data.outputSchema)) {
3742
+ const missingOutputDescs = validateSchemaDescriptions(data.outputSchema);
3743
+ if (missingOutputDescs.length > 0) {
3744
+ throw new MutagentError("VALIDATION_ERROR", `outputSchema properties missing descriptions: ${missingOutputDescs.join(", ")}`, `Run: mutagent prompts update --help
3745
+ ` + `Add a 'description' field to each property in your outputSchema. Example: { "properties": { "field": { "type": "string", "description": "What this field contains" } } }`);
3746
+ }
3747
+ }
3699
3748
  if (Object.keys(data).length === 0) {
3700
3749
  throw new MutagentError("MISSING_ARGUMENTS", "No update data provided", `Run: mutagent prompts update --help
3701
3750
  ` + "Use --name, --raw, --system/--human, --messages, --input-schema, or --output-schema");
@@ -4117,7 +4166,76 @@ async function fetchAndBuildGuidedDatasetWorkflow(promptId) {
4117
4166
  return result;
4118
4167
  }
4119
4168
 
4169
+ // src/commands/prompts/dataset-file-utils.ts
4170
+ init_errors();
4171
+ import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
4172
+ function parseDatasetFile(rawContent, filePath) {
4173
+ const trimmed = rawContent.trim();
4174
+ if (filePath.endsWith(".csv")) {
4175
+ return rawContent;
4176
+ }
4177
+ if (trimmed.startsWith("[")) {
4178
+ try {
4179
+ const parsed = JSON.parse(trimmed);
4180
+ if (!Array.isArray(parsed)) {
4181
+ throw new MutagentError("INVALID_JSON", "Expected a JSON array in dataset file", `Run: mutagent prompts dataset add --help
4182
+ Dataset JSON files should contain an array of objects: [{...}, {...}]`);
4183
+ }
4184
+ return trimmed;
4185
+ } catch (e) {
4186
+ if (e instanceof MutagentError)
4187
+ throw e;
4188
+ throw new MutagentError("INVALID_JSON", `Failed to parse JSON array from ${filePath}`, `Run: mutagent prompts dataset add --help
4189
+ Ensure the file contains valid JSON. For line-delimited JSON, use .jsonl extension or put one object per line.`);
4190
+ }
4191
+ }
4192
+ const lines = trimmed.split(`
4193
+ `).filter((line) => line.trim().length > 0);
4194
+ const items = [];
4195
+ for (let i = 0;i < lines.length; i++) {
4196
+ const line = lines[i];
4197
+ if (!line)
4198
+ continue;
4199
+ const trimmedLine = line.trim();
4200
+ try {
4201
+ items.push(JSON.parse(trimmedLine));
4202
+ } catch {
4203
+ throw new MutagentError("INVALID_JSONL", `Invalid JSON on line ${String(i + 1)} of ${filePath}`, `Run: mutagent prompts dataset add --help
4204
+ Each line must be valid JSON. Problem line: "${trimmedLine.substring(0, 80)}${trimmedLine.length > 80 ? "..." : ""}"`);
4205
+ }
4206
+ }
4207
+ return JSON.stringify(items);
4208
+ }
4209
+ function readDatasetFile(filePath) {
4210
+ if (!existsSync5(filePath)) {
4211
+ throw new MutagentError("FILE_NOT_FOUND", `File not found: ${filePath}`, `Run: mutagent prompts dataset add --help
4212
+ Verify the file path exists and is readable.`);
4213
+ }
4214
+ const rawContent = readFileSync5(filePath, "utf-8");
4215
+ const content = parseDatasetFile(rawContent, filePath);
4216
+ if (filePath.endsWith(".csv")) {
4217
+ return { content, expectedItemCount: null };
4218
+ }
4219
+ const expectedItemCount = JSON.parse(content).length;
4220
+ return { content, expectedItemCount };
4221
+ }
4222
+
4120
4223
  // src/commands/prompts/datasets.ts
4224
+ async function verifyItemCount(client, datasetId, expectedItemCount, isJson, output, uploadHint) {
4225
+ try {
4226
+ const fetched = await client.getDataset(datasetId);
4227
+ const serverCount = fetched.itemCount;
4228
+ if (serverCount !== undefined && serverCount !== expectedItemCount) {
4229
+ throw new MutagentError("ITEM_COUNT_MISMATCH", `Dataset created but itemCount mismatch: expected ${String(expectedItemCount)}, server reports ${String(serverCount)}`, `The server may have rolled back part of the bulk insert. Re-upload with:
4230
+ ${uploadHint}`);
4231
+ }
4232
+ } catch (err) {
4233
+ if (err instanceof MutagentError)
4234
+ throw err;
4235
+ if (!isJson)
4236
+ output.warn("Could not verify itemCount after upload (re-fetch failed)");
4237
+ }
4238
+ }
4121
4239
  function registerDatasetCommands(prompts) {
4122
4240
  const dataset = new Command3("dataset").description("Manage datasets for prompts").addHelpText("after", `
4123
4241
  Examples:
@@ -4217,12 +4335,21 @@ Verify the dataset ID exists, or list datasets for a prompt to find valid IDs.`)
4217
4335
  }
4218
4336
  }
4219
4337
  });
4220
- dataset.command("add").description("Add dataset to a prompt").argument("[prompt-id]", "Prompt ID (from: mutagent prompts list) — optional when --guided is set").option("-d, --data <json>", "Inline JSON array of dataset items").option("-n, --name <name>", "Dataset name").option("--guided", "Guided mode — analyze prompt schema and suggest dataset categories. prompt-id is optional when --guided is set.").addHelpText("after", `
4338
+ dataset.command("add").description("Add dataset to a prompt").argument("[prompt-id]", "Prompt ID (from: mutagent prompts list) — optional when --guided is set").option("-d, --data <json>", "Inline JSON array of dataset items").option("-f, --file <path>", "Path to a JSONL or JSON file. JSONL: one JSON object per line. JSON: array of objects. Avoids shell ARG_MAX limits for large datasets.").option("-n, --name <name>", "Dataset name").option("--guided", "Guided mode — analyze prompt schema and suggest dataset categories. prompt-id is optional when --guided is set.").option("--allow-missing-expected", "Skip the expectedOutput requirement (backwards-compat escape hatch). Items missing expectedOutput are uploaded but evaluation scoring will be broken.").addHelpText("after", `
4221
4339
  Examples:
4222
4340
  ${chalk8.dim("$")} mutagent prompts dataset add --guided --json # no prompt-id: returns generic workflow + upload instructions
4223
4341
  ${chalk8.dim("$")} mutagent prompts dataset add <prompt-id> --guided --json # recommended: schema-aware category suggestions
4224
4342
  ${chalk8.dim("$")} mutagent prompts dataset add <prompt-id> -d '[{"input":{"text":"hello"},"expectedOutput":{"result":"world"}}]'
4225
4343
  ${chalk8.dim("$")} mutagent prompts dataset add <prompt-id> -d '[{"input":{"text":"hello"},"expectedOutput":{"result":"world"}}]' --name "My Dataset"
4344
+ ${chalk8.dim("$")} mutagent prompts dataset add <prompt-id> -f ./items.jsonl --name "My Dataset" # recommended for large datasets (avoids ARG_MAX)
4345
+ ${chalk8.dim("$")} mutagent prompts dataset add <prompt-id> -f ./items.json --name "My Dataset" # JSON array file
4346
+ ${chalk8.dim("$")} mutagent prompts dataset add <prompt-id> -d '[{"input":{"text":"hello"}}]' --name "legacy" --allow-missing-expected
4347
+
4348
+ File mode (-f / --file):
4349
+ Streams the file line-by-line (JSONL) or parses it as a JSON array, then submits as a
4350
+ single bulk request. Throws with the line number on any malformed line.
4351
+ Avoids the macOS ARG_MAX limit that truncates large -d payloads.
4352
+ After upload, re-fetches the created dataset and verifies itemCount matches the file.
4226
4353
 
4227
4354
  Guided mode (--guided):
4228
4355
  Fetches the prompt's inputSchema + outputSchema and returns structured JSON
@@ -4244,7 +4371,8 @@ ${chalk8.yellow("AI Agent (MANDATORY):")}
4244
4371
  expectedOutput is REQUIRED for evaluation scoring.
4245
4372
  Check schemas: mutagent prompts get <prompt-id> --json
4246
4373
 
4247
- ${chalk8.red("Required: --data or --guided must be provided.")}
4374
+ ${chalk8.red("Required: --data, --file, or --guided must be provided.")}
4375
+ ${chalk8.yellow("--allow-missing-expected: Use ONLY for legacy datasets where expectedOutput cannot be provided. Evaluation will not work without it.")}
4248
4376
  `).action(async (promptId, options) => {
4249
4377
  const isJson = options.guided ? true : getJsonFlag(prompts);
4250
4378
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4264,23 +4392,30 @@ ${chalk8.red("Required: --data or --guided must be provided.")}
4264
4392
  ` + `Usage: mutagent prompts dataset add <prompt-id> [options]
4265
4393
  ` + "With --guided: mutagent prompts dataset add --guided --json (returns generic workflow)");
4266
4394
  }
4267
- if (!options.data) {
4268
- throw new MutagentError("MISSING_ARGUMENTS", "-d/--data is required", `Run: mutagent prompts dataset add --help
4269
- ` + "Use -d '[{...}]' to provide inline JSON data");
4395
+ if (!options.data && !options.file) {
4396
+ throw new MutagentError("MISSING_ARGUMENTS", "-d/--data or -f/--file is required", `Run: mutagent prompts dataset add --help
4397
+ ` + "Use -d '[{...}]' for inline JSON, or -f ./items.jsonl for file upload (recommended for large datasets)");
4270
4398
  }
4271
4399
  let content;
4272
- try {
4273
- const parsed = JSON.parse(options.data);
4274
- if (!Array.isArray(parsed)) {
4275
- throw new MutagentError("INVALID_JSON", "Inline data must be a JSON array", `Run: mutagent prompts dataset add --help
4400
+ let expectedItemCount = null;
4401
+ if (options.file) {
4402
+ const result = readDatasetFile(options.file);
4403
+ content = result.content;
4404
+ expectedItemCount = result.expectedItemCount;
4405
+ } else {
4406
+ try {
4407
+ const parsed = JSON.parse(options.data);
4408
+ if (!Array.isArray(parsed)) {
4409
+ throw new MutagentError("INVALID_JSON", "Inline data must be a JSON array", `Run: mutagent prompts dataset add --help
4276
4410
  ` + `Provide a JSON array, e.g., '[{"input": {...}, "expectedOutput": {...}}]'`);
4277
- }
4278
- content = options.data;
4279
- } catch (e) {
4280
- if (e instanceof MutagentError)
4281
- throw e;
4282
- throw new MutagentError("INVALID_JSON", "Invalid JSON in -d/--data flag", `Run: mutagent prompts dataset add --help
4411
+ }
4412
+ content = options.data;
4413
+ } catch (e) {
4414
+ if (e instanceof MutagentError)
4415
+ throw e;
4416
+ throw new MutagentError("INVALID_JSON", "Invalid JSON in -d/--data flag", `Run: mutagent prompts dataset add --help
4283
4417
  ` + `Provide a valid JSON array, e.g., '[{"input": {...}, "expectedOutput": {...}}]'`);
4418
+ }
4284
4419
  }
4285
4420
  const parsedItems = JSON.parse(content);
4286
4421
  if (parsedItems.length === 0) {
@@ -4288,6 +4423,7 @@ ${chalk8.red("Required: --data or --guided must be provided.")}
4288
4423
  Provide at least one item in the array.`);
4289
4424
  }
4290
4425
  const warnings = [];
4426
+ const missingExpectedIndices = [];
4291
4427
  for (let i = 0;i < parsedItems.length; i++) {
4292
4428
  const item = parsedItems[i];
4293
4429
  if (!("input" in item)) {
@@ -4299,9 +4435,18 @@ Each item must have: {"input": {...}, "expectedOutput": {...}}`);
4299
4435
  "input" must be a JSON object: {"input": {"field": "value"}}`);
4300
4436
  }
4301
4437
  if (!("expectedOutput" in item)) {
4302
- warnings.push(`Item at index ${i} is missing "expectedOutput" (recommended for evaluation scoring)`);
4438
+ missingExpectedIndices.push(i);
4303
4439
  }
4304
4440
  }
4441
+ if (missingExpectedIndices.length > 0) {
4442
+ if (!options.allowMissingExpected) {
4443
+ throw new MutagentError("VALIDATION_ERROR", `${missingExpectedIndices.length} dataset item(s) are missing "expectedOutput" at indices: ${missingExpectedIndices.join(", ")}`, `Run: mutagent prompts dataset add --help
4444
+ ` + `Each item must have: {"input": {...}, "expectedOutput": {...}}
4445
+ ` + `"expectedOutput" is required for evaluation scoring.
4446
+ ` + "If you intentionally want to upload items without expectedOutput, use: --allow-missing-expected");
4447
+ }
4448
+ warnings.push(`${missingExpectedIndices.length} item(s) missing "expectedOutput" at indices: ${missingExpectedIndices.join(", ")}. Evaluation scoring will not work.`);
4449
+ }
4305
4450
  const datasetName = options.name;
4306
4451
  if (!datasetName) {
4307
4452
  throw new MutagentError("MISSING_ARGUMENTS", "Dataset name is required", `Run: mutagent prompts dataset add --help
@@ -4311,6 +4456,10 @@ Each item must have: {"input": {...}, "expectedOutput": {...}}`);
4311
4456
  const resolvedPromptId = promptId;
4312
4457
  const client = await getSDKClient();
4313
4458
  const datasetResult = await client.addDataset(resolvedPromptId, content, datasetName);
4459
+ if (expectedItemCount !== null && datasetResult.id !== undefined) {
4460
+ const hint = `mutagent prompts dataset add ${resolvedPromptId} -f ${options.file ?? "<file>"} --name "${datasetName}"`;
4461
+ await verifyItemCount(client, datasetResult.id, expectedItemCount, isJson, output, hint);
4462
+ }
4314
4463
  if (isJson) {
4315
4464
  let rsState;
4316
4465
  try {
@@ -4344,9 +4493,10 @@ Each item must have: {"input": {...}, "expectedOutput": {...}}`);
4344
4493
  });
4345
4494
  console.log(hints);
4346
4495
  }
4496
+ const dataSource = options.file ? `file:${options.file}` : "inline-data";
4347
4497
  updateMutationContext((ctx) => {
4348
- ctx.addDiscoveredDataset("inline-data", datasetResult.name, datasetResult.itemCount ?? 0);
4349
- ctx.markDatasetUploaded("inline-data", String(datasetResult.id), resolvedPromptId);
4498
+ ctx.addDiscoveredDataset(dataSource, datasetResult.name, datasetResult.itemCount ?? 0);
4499
+ ctx.markDatasetUploaded(dataSource, String(datasetResult.id), resolvedPromptId);
4350
4500
  });
4351
4501
  } catch (error) {
4352
4502
  handleError(error, isJson);
@@ -6319,14 +6469,21 @@ ${chalk16.bold("Hit a bug or unexpected result?")}
6319
6469
  output.warn("--optimizer-model is deprecated, use --opt-model");
6320
6470
  options.optModel = options.optModel ?? options.optimizerModel;
6321
6471
  }
6322
- if (options.optModel) {
6323
- validateOptimizerModel(options.optModel);
6472
+ const resolvedExecModel = options.execModel ?? options.model;
6473
+ const resolvedEvalModel = options.evalModel ?? options.model;
6474
+ const resolvedOptModel = options.optModel ?? options.model;
6475
+ if (resolvedOptModel) {
6476
+ validateOptimizerModel(resolvedOptModel);
6324
6477
  }
6325
- const execModel = options.execModel ?? options.model;
6326
- if (!execModel && !isJson) {
6327
- output.warn("No --model specified. Server will use default. Pass --model <id> to control costs.");
6478
+ if (!resolvedExecModel && !isJson) {
6479
+ output.warn("No --model specified. Server will use workspace defaults. Pass --model <id> to control costs.");
6328
6480
  }
6329
- if (execModel) {
6481
+ const modelsToValidate = [
6482
+ ...resolvedExecModel ? [{ slot: "exec", model: resolvedExecModel }] : [],
6483
+ ...resolvedEvalModel && resolvedEvalModel !== resolvedExecModel ? [{ slot: "eval", model: resolvedEvalModel }] : [],
6484
+ ...resolvedOptModel && resolvedOptModel !== resolvedExecModel && resolvedOptModel !== resolvedEvalModel ? [{ slot: "opt", model: resolvedOptModel }] : []
6485
+ ];
6486
+ if (modelsToValidate.length > 0) {
6330
6487
  try {
6331
6488
  const providers = await client.listProviders();
6332
6489
  if (providers.data && providers.data.length > 0) {
@@ -6339,18 +6496,20 @@ ${chalk16.bold("Hit a bug or unexpected result?")}
6339
6496
  }
6340
6497
  } else {
6341
6498
  const modelFamilies = getModelFamiliesForProviderTypes(configuredTypes);
6342
- const modelLower = execModel.toLowerCase();
6343
- const matchedFamily = modelFamilies.find(({ prefixes }) => prefixes.some((prefix) => modelLower.startsWith(prefix)));
6344
- if (!matchedFamily) {
6345
- const supportedModels = modelFamilies.flatMap((f) => f.examples).join(", ");
6346
- const errorMsg = `Model '${execModel}' is not supported by any configured provider. ` + `Your providers: [${configuredTypes.join(", ")}]. ` + `Supported models: ${supportedModels || "(unknown — check mutagent providers list --json)"}. ` + `Run: mutagent providers list --json`;
6347
- if (isJson) {
6348
- output.output({ success: false, error: errorMsg, code: "MODEL_NOT_SUPPORTED" });
6499
+ for (const { slot, model } of modelsToValidate) {
6500
+ const modelLower = model.toLowerCase();
6501
+ const matchedFamily = modelFamilies.find(({ prefixes }) => prefixes.some((prefix) => modelLower.startsWith(prefix)));
6502
+ if (!matchedFamily) {
6503
+ const supportedModels = modelFamilies.flatMap((f) => f.examples).join(", ");
6504
+ const errorMsg = `${slot} model '${model}' is not supported by any configured provider. ` + `Your providers: [${configuredTypes.join(", ")}]. ` + `Supported models: ${supportedModels || "(unknown — check mutagent providers list --json)"}. ` + `Run: mutagent providers list --json`;
6505
+ if (isJson) {
6506
+ output.output({ success: false, error: errorMsg, code: "MODEL_NOT_SUPPORTED" });
6507
+ return;
6508
+ }
6509
+ output.error(errorMsg);
6510
+ process.exitCode = 1;
6349
6511
  return;
6350
6512
  }
6351
- output.error(errorMsg);
6352
- process.exitCode = 1;
6353
- return;
6354
6513
  }
6355
6514
  }
6356
6515
  }
@@ -6507,10 +6666,9 @@ ${chalk16.bold("Hit a bug or unexpected result?")}
6507
6666
  maxIterations: options.maxIterations ? parseInt(options.maxIterations, 10) : 1,
6508
6667
  targetScore: options.targetScore ? parseFloat(options.targetScore) : undefined,
6509
6668
  patience: options.patience ? parseInt(options.patience, 10) : undefined,
6510
- model: options.execModel ? undefined : options.model,
6511
- execModel: options.execModel,
6512
- evalModel: options.evalModel,
6513
- optModel: options.optModel,
6669
+ executionModel: resolvedExecModel,
6670
+ evaluationModel: resolvedEvalModel,
6671
+ optimizationModel: resolvedOptModel,
6514
6672
  providerId: options.providerId,
6515
6673
  evalProviderId: options.evalProviderId,
6516
6674
  optProviderId: options.optProviderId
@@ -6959,12 +7117,12 @@ Provide a valid JSON Schema, e.g., '{"type":"object","properties":{"field":{"typ
6959
7117
  }
6960
7118
  }
6961
7119
  if (filePath) {
6962
- if (!existsSync5(filePath)) {
7120
+ if (!existsSync6(filePath)) {
6963
7121
  throw new MutagentError("FILE_NOT_FOUND", `File not found: ${filePath}`, `Run: ${helpCommand}
6964
7122
  Check the file path and try again`);
6965
7123
  }
6966
7124
  try {
6967
- return JSON.parse(readFileSync5(filePath, "utf-8"));
7125
+ return JSON.parse(readFileSync6(filePath, "utf-8"));
6968
7126
  } catch {
6969
7127
  throw new MutagentError("INVALID_JSON", `Failed to parse JSON from ${filePath}`, `Run: ${helpCommand}
6970
7128
  Ensure the file contains valid JSON Schema`);
@@ -7262,20 +7420,20 @@ ${chalk22.dim("Returns full trace details including spans, tokens, and latency."
7262
7420
  init_config();
7263
7421
  import { Command as Command9 } from "commander";
7264
7422
  import chalk23 from "chalk";
7265
- import { writeFileSync as writeFileSync3, existsSync as existsSync10 } from "fs";
7423
+ import { writeFileSync as writeFileSync3, existsSync as existsSync11 } from "fs";
7266
7424
  import { execSync } from "child_process";
7267
7425
  init_errors();
7268
7426
 
7269
7427
  // src/lib/integrations/langchain.ts
7270
- import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
7428
+ import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
7271
7429
  var langchainIntegration = {
7272
7430
  name: "langchain",
7273
7431
  description: "LangChain framework",
7274
7432
  detect() {
7275
7433
  let hasLangchain = false;
7276
- if (existsSync6("package.json")) {
7434
+ if (existsSync7("package.json")) {
7277
7435
  try {
7278
- const pkg = JSON.parse(readFileSync6("package.json", "utf-8"));
7436
+ const pkg = JSON.parse(readFileSync7("package.json", "utf-8"));
7279
7437
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
7280
7438
  hasLangchain = "langchain" in deps || "@langchain/core" in deps;
7281
7439
  } catch {}
@@ -7407,15 +7565,15 @@ mutagent traces analyze <prompt-id>
7407
7565
  };
7408
7566
 
7409
7567
  // src/lib/integrations/langgraph.ts
7410
- import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
7568
+ import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
7411
7569
  var langgraphIntegration = {
7412
7570
  name: "langgraph",
7413
7571
  description: "LangGraph agent workflow framework",
7414
7572
  detect() {
7415
7573
  let hasLanggraph = false;
7416
- if (existsSync7("package.json")) {
7574
+ if (existsSync8("package.json")) {
7417
7575
  try {
7418
- const pkg = JSON.parse(readFileSync7("package.json", "utf-8"));
7576
+ const pkg = JSON.parse(readFileSync8("package.json", "utf-8"));
7419
7577
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
7420
7578
  hasLanggraph = "@langchain/langgraph" in deps;
7421
7579
  } catch {}
@@ -7497,15 +7655,15 @@ mutagent integrate langgraph --verify
7497
7655
  };
7498
7656
 
7499
7657
  // src/lib/integrations/vercel-ai.ts
7500
- import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
7658
+ import { readFileSync as readFileSync9, existsSync as existsSync9 } from "fs";
7501
7659
  var vercelAiIntegration = {
7502
7660
  name: "vercel-ai",
7503
7661
  description: "Vercel AI SDK",
7504
7662
  detect() {
7505
7663
  let hasAiSdk = false;
7506
- if (existsSync8("package.json")) {
7664
+ if (existsSync9("package.json")) {
7507
7665
  try {
7508
- const pkg = JSON.parse(readFileSync8("package.json", "utf-8"));
7666
+ const pkg = JSON.parse(readFileSync9("package.json", "utf-8"));
7509
7667
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
7510
7668
  hasAiSdk = "ai" in deps;
7511
7669
  } catch {}
@@ -7647,15 +7805,15 @@ mutagent integrate vercel-ai --verify
7647
7805
  };
7648
7806
 
7649
7807
  // src/lib/integrations/openai.ts
7650
- import { readFileSync as readFileSync9, existsSync as existsSync9 } from "fs";
7808
+ import { readFileSync as readFileSync10, existsSync as existsSync10 } from "fs";
7651
7809
  var openaiIntegration = {
7652
7810
  name: "openai",
7653
7811
  description: "OpenAI SDK integration with automatic tracing",
7654
7812
  detect() {
7655
7813
  let hasOpenAI = false;
7656
- if (existsSync9("package.json")) {
7814
+ if (existsSync10("package.json")) {
7657
7815
  try {
7658
- const pkg = JSON.parse(readFileSync9("package.json", "utf-8"));
7816
+ const pkg = JSON.parse(readFileSync10("package.json", "utf-8"));
7659
7817
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
7660
7818
  hasOpenAI = "openai" in deps;
7661
7819
  } catch {}
@@ -7804,16 +7962,16 @@ function getFrameworkMetadata(name) {
7804
7962
 
7805
7963
  // src/commands/integrate.ts
7806
7964
  function detectPackageManager() {
7807
- if (existsSync10("bun.lockb") || existsSync10("bun.lock")) {
7965
+ if (existsSync11("bun.lockb") || existsSync11("bun.lock")) {
7808
7966
  return "bun";
7809
7967
  }
7810
- if (existsSync10("pnpm-lock.yaml")) {
7968
+ if (existsSync11("pnpm-lock.yaml")) {
7811
7969
  return "pnpm";
7812
7970
  }
7813
- if (existsSync10("yarn.lock")) {
7971
+ if (existsSync11("yarn.lock")) {
7814
7972
  return "yarn";
7815
7973
  }
7816
- if (existsSync10("package-lock.json")) {
7974
+ if (existsSync11("package-lock.json")) {
7817
7975
  return "npm";
7818
7976
  }
7819
7977
  try {
@@ -9199,13 +9357,13 @@ init_config();
9199
9357
  import { Command as Command15 } from "commander";
9200
9358
  import inquirer2 from "inquirer";
9201
9359
  import chalk34 from "chalk";
9202
- import { existsSync as existsSync12, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
9360
+ import { existsSync as existsSync13, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
9203
9361
  import { execSync as execSync3 } from "child_process";
9204
9362
  import { join as join7 } from "path";
9205
9363
  init_errors();
9206
9364
 
9207
9365
  // src/lib/framework-detection.ts
9208
- import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
9366
+ import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
9209
9367
  import { execSync as execSync2 } from "child_process";
9210
9368
  import { join as join6 } from "path";
9211
9369
  var FRAMEWORK_DETECTION_MAP = {
@@ -9257,16 +9415,16 @@ var FRAMEWORK_DETECTION_MAP = {
9257
9415
  }
9258
9416
  };
9259
9417
  function detectPackageManager2(cwd = process.cwd()) {
9260
- if (existsSync11(join6(cwd, "bun.lockb")) || existsSync11(join6(cwd, "bun.lock"))) {
9418
+ if (existsSync12(join6(cwd, "bun.lockb")) || existsSync12(join6(cwd, "bun.lock"))) {
9261
9419
  return "bun";
9262
9420
  }
9263
- if (existsSync11(join6(cwd, "pnpm-lock.yaml"))) {
9421
+ if (existsSync12(join6(cwd, "pnpm-lock.yaml"))) {
9264
9422
  return "pnpm";
9265
9423
  }
9266
- if (existsSync11(join6(cwd, "yarn.lock"))) {
9424
+ if (existsSync12(join6(cwd, "yarn.lock"))) {
9267
9425
  return "yarn";
9268
9426
  }
9269
- if (existsSync11(join6(cwd, "package-lock.json"))) {
9427
+ if (existsSync12(join6(cwd, "package-lock.json"))) {
9270
9428
  return "npm";
9271
9429
  }
9272
9430
  try {
@@ -9288,12 +9446,12 @@ function getInstallCommand2(pm, packages) {
9288
9446
  }
9289
9447
  function detectFrameworkFromPackageJson(cwd = process.cwd()) {
9290
9448
  const pkgPath = join6(cwd, "package.json");
9291
- if (!existsSync11(pkgPath)) {
9449
+ if (!existsSync12(pkgPath)) {
9292
9450
  return null;
9293
9451
  }
9294
9452
  let pkg;
9295
9453
  try {
9296
- pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
9454
+ pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
9297
9455
  } catch {
9298
9456
  return null;
9299
9457
  }
@@ -9309,7 +9467,7 @@ function detectFrameworkFromPackageJson(cwd = process.cwd()) {
9309
9467
  return null;
9310
9468
  }
9311
9469
  function hasRcConfig(cwd = process.cwd()) {
9312
- return existsSync11(join6(cwd, ".mutagentrc.json"));
9470
+ return existsSync12(join6(cwd, ".mutagentrc.json"));
9313
9471
  }
9314
9472
 
9315
9473
  // src/commands/init.ts
@@ -9531,7 +9689,7 @@ Modes:
9531
9689
  }
9532
9690
  }
9533
9691
  const skillPath = join7(cwd, ".claude/skills/mutagent-cli/SKILL.md");
9534
- const skillInstalled = existsSync12(skillPath);
9692
+ const skillInstalled = existsSync13(skillPath);
9535
9693
  if (!isNonInteractive && !skillInstalled) {
9536
9694
  const { installSkill } = await inquirer2.prompt([{
9537
9695
  type: "confirm",
@@ -9542,7 +9700,7 @@ Modes:
9542
9700
  if (installSkill) {
9543
9701
  try {
9544
9702
  const skillDir = join7(cwd, ".claude/skills/mutagent-cli");
9545
- if (!existsSync12(skillDir)) {
9703
+ if (!existsSync13(skillDir)) {
9546
9704
  mkdirSync3(skillDir, { recursive: true });
9547
9705
  }
9548
9706
  execSync3("node " + join7(cwd, "node_modules/.bin/mutagent") + " skills install", {
@@ -9593,7 +9751,7 @@ Modes:
9593
9751
  framework: confirmedFramework?.name ?? null,
9594
9752
  authenticated,
9595
9753
  workspaceValidation: workspaceValidation ?? null,
9596
- skillInstalled: skillInstalled || existsSync12(skillPath),
9754
+ skillInstalled: skillInstalled || existsSync13(skillPath),
9597
9755
  _directive: initDirective
9598
9756
  };
9599
9757
  output.output(summary);
@@ -9767,7 +9925,7 @@ Scanning ${scanPath}...
9767
9925
  // src/commands/skills.ts
9768
9926
  import { Command as Command17 } from "commander";
9769
9927
  import chalk36 from "chalk";
9770
- import { existsSync as existsSync13, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
9928
+ import { existsSync as existsSync14, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
9771
9929
  import { dirname, join as join8 } from "path";
9772
9930
  import { execSync as execSync4 } from "child_process";
9773
9931
 
@@ -10035,7 +10193,7 @@ After every CLI command:
10035
10193
  - **CI / automated**: \`export MUTAGENT_API_KEY=mt_... && mutagent login --json\` -- no browser, no prompts.
10036
10194
  - **Onboarding a user**: \`mutagent login --browser --json\` -- CLI prints auth URL to stdout, polls 5 min. **Surface the URL verbatim to the user.** \`--non-interactive\` is NOT needed when \`--browser\` is set.
10037
10195
 
10038
- \`mutagent login\` is canonical. \`mutagent auth login\` is a back-compat alias. Both delegate to \`lib/auth-flow.ts\`. Decision record: [cli-design-principles.md](../../docs/cli-design-principles.md) -> Login Unification.
10196
+ \`mutagent login\` is canonical. \`mutagent auth login\` is a back-compat alias. Both delegate to a single shared implementation; they are thin wrappers and stay that way by design.
10039
10197
 
10040
10198
  ---
10041
10199
 
@@ -12294,7 +12452,7 @@ that teaches coding agents how to use the MutagenT CLI effectively.
12294
12452
  for (const relPath of sortedKeys) {
12295
12453
  const destPath = join8(skillDir, relPath);
12296
12454
  const parentDir = dirname(destPath);
12297
- if (!existsSync13(parentDir)) {
12455
+ if (!existsSync14(parentDir)) {
12298
12456
  mkdirSync4(parentDir, { recursive: true });
12299
12457
  }
12300
12458
  const raw = files[relPath] ?? "";
@@ -12428,7 +12586,7 @@ import { Command as Command19 } from "commander";
12428
12586
  import { randomUUID } from "crypto";
12429
12587
 
12430
12588
  // src/commands/hooks/state.ts
12431
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync6, renameSync, unlinkSync, existsSync as existsSync14 } from "fs";
12589
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync6, renameSync, unlinkSync, existsSync as existsSync15 } from "fs";
12432
12590
  import { join as join9 } from "path";
12433
12591
  import { tmpdir } from "os";
12434
12592
  function stateFilePath(sessionId) {
@@ -12436,10 +12594,10 @@ function stateFilePath(sessionId) {
12436
12594
  }
12437
12595
  function readState(sessionId) {
12438
12596
  const path = stateFilePath(sessionId);
12439
- if (!existsSync14(path))
12597
+ if (!existsSync15(path))
12440
12598
  return null;
12441
12599
  try {
12442
- const raw = JSON.parse(readFileSync11(path, "utf-8"));
12600
+ const raw = JSON.parse(readFileSync12(path, "utf-8"));
12443
12601
  if (!Array.isArray(raw.parentStack)) {
12444
12602
  raw.parentStack = [];
12445
12603
  }
@@ -12459,7 +12617,7 @@ function writeState(sessionId, state) {
12459
12617
  }
12460
12618
  function deleteState(sessionId) {
12461
12619
  const path = stateFilePath(sessionId);
12462
- if (existsSync14(path)) {
12620
+ if (existsSync15(path)) {
12463
12621
  try {
12464
12622
  unlinkSync(path);
12465
12623
  } catch {}
@@ -13106,7 +13264,7 @@ async function handlePostToolUseFailure() {
13106
13264
  }
13107
13265
 
13108
13266
  // src/commands/hooks/install.ts
13109
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync7, existsSync as existsSync15, mkdirSync as mkdirSync5 } from "fs";
13267
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync7, existsSync as existsSync16, mkdirSync as mkdirSync5 } from "fs";
13110
13268
  import { join as join10 } from "path";
13111
13269
 
13112
13270
  class SettingsParseError extends Error {
@@ -13171,10 +13329,10 @@ function migrateV1Hooks(settings) {
13171
13329
  function installHooks(cwd) {
13172
13330
  const claudeDir = join10(cwd, ".claude");
13173
13331
  const settingsPath = join10(claudeDir, "settings.local.json");
13174
- const existed = existsSync15(settingsPath);
13332
+ const existed = existsSync16(settingsPath);
13175
13333
  let settings = {};
13176
13334
  if (existed) {
13177
- const raw = readFileSync12(settingsPath, "utf-8");
13335
+ const raw = readFileSync13(settingsPath, "utf-8");
13178
13336
  try {
13179
13337
  settings = JSON.parse(raw);
13180
13338
  } catch (err) {
@@ -13209,7 +13367,7 @@ function installHooks(cwd) {
13209
13367
  }
13210
13368
  let userWarning;
13211
13369
  if (added.length > 0 || migrated.length > 0) {
13212
- if (!existsSync15(claudeDir)) {
13370
+ if (!existsSync16(claudeDir)) {
13213
13371
  mkdirSync5(claudeDir, { recursive: true });
13214
13372
  }
13215
13373
  writeFileSync7(settingsPath, JSON.stringify(settings, null, 2) + `
@@ -13359,7 +13517,7 @@ import { Command as Command20 } from "commander";
13359
13517
  import chalk38 from "chalk";
13360
13518
  init_errors();
13361
13519
  init_config();
13362
- import { readFileSync as readFileSync13, existsSync as existsSync16 } from "fs";
13520
+ import { readFileSync as readFileSync14, existsSync as existsSync17 } from "fs";
13363
13521
  import { join as join11, dirname as dirname2 } from "path";
13364
13522
  import { fileURLToPath } from "url";
13365
13523
  var VALID_CATEGORIES = ["bug", "feature", "improvement", "praise"];
@@ -13370,7 +13528,7 @@ function getCliVersion() {
13370
13528
  try {
13371
13529
  const __dirname2 = dirname2(fileURLToPath(import.meta.url));
13372
13530
  const pkgPath = join11(__dirname2, "..", "..", "package.json");
13373
- const pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
13531
+ const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
13374
13532
  return pkg.version ?? "0.1.1";
13375
13533
  } catch {
13376
13534
  return "0.1.1";
@@ -13401,12 +13559,12 @@ async function resolveContextSource(source, _readStdinOverride) {
13401
13559
  raw = await (_readStdinOverride ?? readStdin2)();
13402
13560
  } else if (source.startsWith("@")) {
13403
13561
  const filePath = source.slice(1);
13404
- if (!existsSync16(filePath)) {
13562
+ if (!existsSync17(filePath)) {
13405
13563
  throw new MutagentError("INVALID_ARGUMENTS", `Context file not found: ${filePath}`, `Verify the path exists: ls -la "${filePath}"
13406
13564
  Or use inline JSON: --context '{"key":"value"}'`);
13407
13565
  }
13408
13566
  try {
13409
- raw = readFileSync13(filePath, "utf-8").trim();
13567
+ raw = readFileSync14(filePath, "utf-8").trim();
13410
13568
  } catch (err) {
13411
13569
  const msg = err instanceof Error ? err.message : String(err);
13412
13570
  throw new MutagentError("INVALID_ARGUMENTS", `Cannot read context file "${filePath}": ${msg}`, `Check file permissions: ls -la "${filePath}"`);
@@ -13559,7 +13717,7 @@ if (process.env.CLI_VERSION) {
13559
13717
  try {
13560
13718
  const __dirname2 = dirname3(fileURLToPath2(import.meta.url));
13561
13719
  const pkgPath = join12(__dirname2, "..", "..", "package.json");
13562
- const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
13720
+ const pkg = JSON.parse(readFileSync15(pkgPath, "utf-8"));
13563
13721
  cliVersion = pkg.version ?? cliVersion;
13564
13722
  } catch {}
13565
13723
  }
@@ -13754,11 +13912,11 @@ var isInteractive = process.stdin.isTTY && !rawArgs.includes("--json") && proces
13754
13912
  var isSkillCommand = rawArgs[0] === "skills" || rawArgs[0] === "hooks";
13755
13913
  if (isInteractive && !isSkillCommand) {
13756
13914
  const skillPath = join12(process.cwd(), ".claude/skills/mutagent-cli/SKILL.md");
13757
- if (!existsSync17(skillPath)) {
13915
+ if (!existsSync18(skillPath)) {
13758
13916
  console.log(chalk39.dim("MutagenT SKILL not installed. Install it for AI agent support? Run:"), chalk39.cyan("mutagent skills install"));
13759
13917
  }
13760
13918
  }
13761
13919
  program.parse();
13762
13920
 
13763
- //# debugId=6F6C59E53DD7DB6E64756E2164756E21
13921
+ //# debugId=62DF92692E0B964164756E2164756E21
13764
13922
  //# sourceMappingURL=cli.js.map