@mutagent/cli 0.1.13 → 0.1.15

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
@@ -16,44 +16,24 @@ var __toESM = (mod, isNodeMode, target) => {
16
16
  });
17
17
  return to;
18
18
  };
19
+ var __export = (target, all) => {
20
+ for (var name in all)
21
+ __defProp(target, name, {
22
+ get: all[name],
23
+ enumerable: true,
24
+ configurable: true,
25
+ set: (newValue) => all[name] = () => newValue
26
+ });
27
+ };
28
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
19
29
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
20
30
 
21
- // src/bin/cli.ts
22
- import { Command as Command12 } from "commander";
23
- import chalk13 from "chalk";
24
- import { readFileSync as readFileSync12 } from "fs";
25
- import { join as join3, dirname } from "path";
26
- import { fileURLToPath } from "url";
27
-
28
- // src/commands/auth.ts
29
- import { Command } from "commander";
30
- import inquirer from "inquirer";
31
- import chalk2 from "chalk";
32
- import ora from "ora";
33
-
34
31
  // src/lib/config.ts
35
32
  import { cosmiconfigSync } from "cosmiconfig";
36
33
  import { z } from "zod";
37
34
  import { homedir } from "os";
38
35
  import { join } from "path";
39
36
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
40
- var configSchema = z.object({
41
- apiKey: z.string().optional(),
42
- endpoint: z.string().default("https://api.mutagent.io"),
43
- format: z.enum(["table", "json"]).default("table"),
44
- timeout: z.number().default(30000),
45
- defaultWorkspace: z.string().optional(),
46
- defaultOrganization: z.string().optional()
47
- });
48
- var credentialsSchema = z.object({
49
- apiKey: z.string().optional(),
50
- endpoint: z.string().optional(),
51
- defaultWorkspace: z.string().optional(),
52
- defaultOrganization: z.string().optional(),
53
- expiresAt: z.string().optional()
54
- }).loose();
55
- var CREDENTIALS_DIR = join(homedir(), ".config", "mutagent");
56
- var CREDENTIALS_FILE = join(CREDENTIALS_DIR, "credentials.json");
57
37
  function parseJsonSafe(content, schema) {
58
38
  try {
59
39
  const parsed = JSON.parse(content);
@@ -161,80 +141,28 @@ function setDefaultOrganization(organizationId) {
161
141
  };
162
142
  writeFileSync(CREDENTIALS_FILE, JSON.stringify(updated, null, 2));
163
143
  }
164
-
165
- // src/lib/sdk-client.ts
166
- import { Mutagent, HTTPClient } from "@mutagent/sdk";
144
+ var configSchema, credentialsSchema, CREDENTIALS_DIR, CREDENTIALS_FILE;
145
+ var init_config = __esm(() => {
146
+ configSchema = z.object({
147
+ apiKey: z.string().optional(),
148
+ endpoint: z.string().default("https://api.mutagent.io"),
149
+ format: z.enum(["table", "json"]).default("table"),
150
+ timeout: z.number().default(30000),
151
+ defaultWorkspace: z.string().optional(),
152
+ defaultOrganization: z.string().optional()
153
+ });
154
+ credentialsSchema = z.object({
155
+ apiKey: z.string().optional(),
156
+ endpoint: z.string().optional(),
157
+ defaultWorkspace: z.string().optional(),
158
+ defaultOrganization: z.string().optional(),
159
+ expiresAt: z.string().optional()
160
+ }).loose();
161
+ CREDENTIALS_DIR = join(homedir(), ".config", "mutagent");
162
+ CREDENTIALS_FILE = join(CREDENTIALS_DIR, "credentials.json");
163
+ });
167
164
 
168
165
  // src/lib/errors.ts
169
- class MutagentError extends Error {
170
- code;
171
- suggestion;
172
- exitCode;
173
- constructor(code, message, suggestion, exitCode = 1) {
174
- super(message);
175
- this.code = code;
176
- this.suggestion = suggestion;
177
- this.exitCode = exitCode;
178
- this.name = "MutagentError";
179
- }
180
- toJSON() {
181
- return {
182
- error: {
183
- code: this.code,
184
- message: this.message,
185
- suggestion: this.suggestion
186
- }
187
- };
188
- }
189
- }
190
- var AUTH_REMEDIATION_MESSAGE = [
191
- "Authentication required. Options:",
192
- " Interactive: mutagent auth login --browser",
193
- " Non-interactive: export MUTAGENT_API_KEY=<your-key>",
194
- " CI/CD: mutagent auth login --api-key <key>"
195
- ].join(`
196
- `);
197
-
198
- class AuthenticationError extends MutagentError {
199
- suggestions;
200
- cause;
201
- constructor(message, options = {}) {
202
- super("AUTH_REQUIRED", message ?? 'Authentication required. Please run "mutagent auth login"', options.suggestions ? options.suggestions[0] : "Run: mutagent auth login --browser", 2);
203
- this.suggestions = options.suggestions ?? [
204
- "mutagent auth login --browser",
205
- "export MUTAGENT_API_KEY=<your-key>",
206
- "mutagent auth login --api-key <key>"
207
- ];
208
- this.suggestion = options.suggestions ? options.suggestions[0] : "Run: mutagent auth login --browser";
209
- this.cause = options.cause;
210
- }
211
- }
212
-
213
- class ApiError extends MutagentError {
214
- statusCode;
215
- constructor(status, message) {
216
- super(`API_${status}`, message, status === 401 ? "Check your API key with: mutagent auth status" : undefined, 1);
217
- this.statusCode = status;
218
- }
219
- }
220
- var WORKSPACE_REMEDIATION_MESSAGE = [
221
- "Workspace context missing. To fix:",
222
- " mutagent config set workspace <workspace-id> # Set default workspace",
223
- " mutagent workspaces list # List available workspaces"
224
- ].join(`
225
- `);
226
-
227
- class WorkspaceContextError extends MutagentError {
228
- constructor(message) {
229
- super("WORKSPACE_CONTEXT_MISSING", message ?? "Workspace context is required but not configured", "Run: mutagent config set workspace <workspace-id>", 3);
230
- }
231
- }
232
-
233
- class ValidationError extends MutagentError {
234
- constructor(message) {
235
- super("VALIDATION_ERROR", message, "Check the command syntax with: mutagent <command> --help", 1);
236
- }
237
- }
238
166
  function handleError(error, isJson) {
239
167
  if (error instanceof MutagentError) {
240
168
  if (isJson) {
@@ -313,8 +241,87 @@ function handleError(error, isJson) {
313
241
  }
314
242
  process.exit(1);
315
243
  }
244
+ var MutagentError, AUTH_REMEDIATION_MESSAGE, AuthenticationError, ApiError, WORKSPACE_REMEDIATION_MESSAGE, WorkspaceContextError, ValidationError;
245
+ var init_errors = __esm(() => {
246
+ MutagentError = class MutagentError extends Error {
247
+ code;
248
+ suggestion;
249
+ exitCode;
250
+ constructor(code, message, suggestion, exitCode = 1) {
251
+ super(message);
252
+ this.code = code;
253
+ this.suggestion = suggestion;
254
+ this.exitCode = exitCode;
255
+ this.name = "MutagentError";
256
+ }
257
+ toJSON() {
258
+ return {
259
+ error: {
260
+ code: this.code,
261
+ message: this.message,
262
+ suggestion: this.suggestion
263
+ }
264
+ };
265
+ }
266
+ };
267
+ AUTH_REMEDIATION_MESSAGE = [
268
+ "Authentication required. Options:",
269
+ " Interactive: mutagent auth login --browser",
270
+ " Non-interactive: export MUTAGENT_API_KEY=<your-key>",
271
+ " CI/CD: mutagent auth login --api-key <key>"
272
+ ].join(`
273
+ `);
274
+ AuthenticationError = class AuthenticationError extends MutagentError {
275
+ suggestions;
276
+ cause;
277
+ constructor(message, options = {}) {
278
+ super("AUTH_REQUIRED", message ?? 'Authentication required. Please run "mutagent auth login"', options.suggestions ? options.suggestions[0] : "Run: mutagent auth login --browser", 2);
279
+ this.suggestions = options.suggestions ?? [
280
+ "mutagent auth login --browser",
281
+ "export MUTAGENT_API_KEY=<your-key>",
282
+ "mutagent auth login --api-key <key>"
283
+ ];
284
+ this.suggestion = options.suggestions ? options.suggestions[0] : "Run: mutagent auth login --browser";
285
+ this.cause = options.cause;
286
+ }
287
+ };
288
+ ApiError = class ApiError extends MutagentError {
289
+ statusCode;
290
+ constructor(status, message) {
291
+ super(`API_${String(status)}`, message, status === 401 ? "Check your API key with: mutagent auth status" : undefined, 1);
292
+ this.statusCode = status;
293
+ }
294
+ };
295
+ WORKSPACE_REMEDIATION_MESSAGE = [
296
+ "Workspace context missing. To fix:",
297
+ " mutagent config set workspace <workspace-id> # Set default workspace",
298
+ " mutagent workspaces list # List available workspaces"
299
+ ].join(`
300
+ `);
301
+ WorkspaceContextError = class WorkspaceContextError extends MutagentError {
302
+ constructor(message) {
303
+ super("WORKSPACE_CONTEXT_MISSING", message ?? "Workspace context is required but not configured", "Run: mutagent config set workspace <workspace-id>", 3);
304
+ }
305
+ };
306
+ ValidationError = class ValidationError extends MutagentError {
307
+ constructor(message) {
308
+ super("VALIDATION_ERROR", message, "Check the command syntax with: mutagent <command> --help", 1);
309
+ }
310
+ };
311
+ });
316
312
 
317
313
  // src/lib/sdk-client.ts
314
+ var exports_sdk_client = {};
315
+ __export(exports_sdk_client, {
316
+ validateApiKey: () => validateApiKey,
317
+ resetSDKClient: () => resetSDKClient,
318
+ getSDKClient: () => getSDKClient,
319
+ fetchWorkspaces: () => fetchWorkspaces,
320
+ fetchOrganizations: () => fetchOrganizations,
321
+ MutagentSDK: () => SDKClientWrapper
322
+ });
323
+ import { Mutagent, HTTPClient } from "@mutagent/sdk";
324
+
318
325
  class SDKClientWrapper {
319
326
  sdk;
320
327
  apiKey;
@@ -853,7 +860,6 @@ class SDKClientWrapper {
853
860
  }
854
861
  }
855
862
  }
856
- var sdkClient = null;
857
863
  function getSDKClient() {
858
864
  if (!sdkClient) {
859
865
  const apiKey = getApiKey();
@@ -870,6 +876,9 @@ function getSDKClient() {
870
876
  }
871
877
  return sdkClient;
872
878
  }
879
+ function resetSDKClient() {
880
+ sdkClient = null;
881
+ }
873
882
  async function validateApiKey(apiKey, endpoint) {
874
883
  try {
875
884
  const response = await fetch(`${endpoint}/api/organizations`, {
@@ -906,6 +915,28 @@ async function fetchWorkspaces(apiKey, endpoint, orgId) {
906
915
  return [];
907
916
  }
908
917
  }
918
+ var sdkClient = null;
919
+ var init_sdk_client = __esm(() => {
920
+ init_errors();
921
+ init_config();
922
+ });
923
+
924
+ // src/bin/cli.ts
925
+ import { Command as Command14 } from "commander";
926
+ import chalk18 from "chalk";
927
+ import { readFileSync as readFileSync14 } from "fs";
928
+ import { join as join7, dirname } from "path";
929
+ import { fileURLToPath } from "url";
930
+
931
+ // src/commands/auth.ts
932
+ init_config();
933
+ init_sdk_client();
934
+ import { Command } from "commander";
935
+ import inquirer from "inquirer";
936
+ import chalk3 from "chalk";
937
+ import ora from "ora";
938
+ import { existsSync as existsSync3 } from "fs";
939
+ import { join as join4 } from "path";
909
940
 
910
941
  // src/lib/output.ts
911
942
  import chalk from "chalk";
@@ -1028,6 +1059,9 @@ ${String(data.length)} result(s)`));
1028
1059
  }
1029
1060
  }
1030
1061
 
1062
+ // src/commands/auth.ts
1063
+ init_errors();
1064
+
1031
1065
  // src/lib/browser-auth.ts
1032
1066
  import { hostname, platform } from "os";
1033
1067
  function generateCliToken() {
@@ -1165,22 +1199,658 @@ class BrowserAuthError extends Error {
1165
1199
  }
1166
1200
  }
1167
1201
 
1202
+ // src/lib/mutation-context.ts
1203
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
1204
+ import { join as join2, resolve } from "path";
1205
+ function parseTableRows(lines) {
1206
+ const rows = [];
1207
+ for (const line of lines) {
1208
+ const trimmed = line.trim();
1209
+ if (!trimmed.startsWith("|") || !trimmed.endsWith("|"))
1210
+ continue;
1211
+ if (/^\|[\s-:|]+\|$/.test(trimmed))
1212
+ continue;
1213
+ const cells = trimmed.slice(1, -1).split("|").map((c) => c.trim());
1214
+ rows.push(cells);
1215
+ }
1216
+ return rows;
1217
+ }
1218
+ function emptyToUndefined(value) {
1219
+ return value && value.length > 0 ? value : undefined;
1220
+ }
1221
+ function renderTable(headers, rows) {
1222
+ const separator = headers.map((h) => "-".repeat(Math.max(h.length, 3)));
1223
+ const lines = [
1224
+ `| ${headers.join(" | ")} |`,
1225
+ `| ${separator.join(" | ")} |`,
1226
+ ...rows.map((r) => `| ${r.join(" | ")} |`)
1227
+ ];
1228
+ return lines.join(`
1229
+ `);
1230
+ }
1231
+ var CONTEXT_DIR = ".mutagent";
1232
+ var CONTEXT_FILE = "mutation-context.md";
1233
+
1234
+ class MutationContext {
1235
+ prompts = [];
1236
+ datasets = [];
1237
+ evaluations = [];
1238
+ integrations = [];
1239
+ filePath;
1240
+ constructor(filePath) {
1241
+ this.filePath = filePath;
1242
+ }
1243
+ static load(projectRoot) {
1244
+ const root = projectRoot ?? process.cwd();
1245
+ const dirPath = join2(resolve(root), CONTEXT_DIR);
1246
+ const filePath = join2(dirPath, CONTEXT_FILE);
1247
+ const ctx = new MutationContext(filePath);
1248
+ if (existsSync2(filePath)) {
1249
+ const content = readFileSync2(filePath, "utf-8");
1250
+ ctx.parse(content);
1251
+ }
1252
+ return ctx;
1253
+ }
1254
+ save() {
1255
+ const dirPath = join2(this.filePath, "..");
1256
+ if (!existsSync2(dirPath)) {
1257
+ mkdirSync2(dirPath, { recursive: true });
1258
+ }
1259
+ writeFileSync2(this.filePath, this.render(), "utf-8");
1260
+ }
1261
+ addDiscoveredPrompt(file, line, preview) {
1262
+ const existing = this.prompts.find((p) => p.file === file && p.line === line);
1263
+ if (existing) {
1264
+ existing.preview = preview;
1265
+ return;
1266
+ }
1267
+ this.prompts.push({ file, line, preview, status: "discovered" });
1268
+ }
1269
+ markPromptUploaded(file, platformId, version) {
1270
+ const entry = this.prompts.find((p) => p.file === file);
1271
+ if (entry) {
1272
+ entry.platformId = platformId;
1273
+ entry.version = version;
1274
+ entry.status = "uploaded";
1275
+ }
1276
+ }
1277
+ getDiscoveredPrompts() {
1278
+ return this.prompts.filter((p) => p.status === "discovered");
1279
+ }
1280
+ getUploadedPrompts() {
1281
+ return this.prompts.filter((p) => p.status === "uploaded");
1282
+ }
1283
+ addDiscoveredDataset(file, name, items) {
1284
+ const existing = this.datasets.find((d) => d.file === file && d.name === name);
1285
+ if (existing) {
1286
+ existing.items = items;
1287
+ return;
1288
+ }
1289
+ this.datasets.push({ file, name, items, status: "discovered" });
1290
+ }
1291
+ markDatasetUploaded(file, platformId, promptId) {
1292
+ const entry = this.datasets.find((d) => d.file === file);
1293
+ if (entry) {
1294
+ entry.platformId = platformId;
1295
+ entry.promptId = promptId;
1296
+ entry.status = "uploaded";
1297
+ }
1298
+ }
1299
+ addEvaluation(name, criteriaCount, platformId, promptId) {
1300
+ const existing = this.evaluations.find((e) => e.name === name);
1301
+ if (existing) {
1302
+ existing.criteriaCount = criteriaCount;
1303
+ existing.platformId = platformId;
1304
+ existing.promptId = promptId;
1305
+ existing.status = "uploaded";
1306
+ return;
1307
+ }
1308
+ this.evaluations.push({ name, criteriaCount, platformId, promptId, status: "uploaded" });
1309
+ }
1310
+ setIntegrationStatus(framework, pkg, status) {
1311
+ const existing = this.integrations.find((i) => i.framework === framework);
1312
+ if (existing) {
1313
+ existing.pkg = pkg;
1314
+ existing.status = status;
1315
+ return;
1316
+ }
1317
+ this.integrations.push({ framework, pkg, status });
1318
+ }
1319
+ getSummary() {
1320
+ return {
1321
+ prompts: this.prompts.length,
1322
+ datasets: this.datasets.length,
1323
+ evaluations: this.evaluations.length,
1324
+ integrated: this.integrations.map((i) => i.framework)
1325
+ };
1326
+ }
1327
+ render() {
1328
+ const now = new Date().toISOString();
1329
+ const sections = [
1330
+ "# MutagenT Mutation Context",
1331
+ `<!-- MutagenT:AUTO-GENERATED - Do not edit manually -->`,
1332
+ `<!-- Last updated: ${now} -->`,
1333
+ "",
1334
+ "## Discovered Resources",
1335
+ "",
1336
+ "### Prompts",
1337
+ renderTable(["File", "Line", "Content Preview", "Platform ID", "Version", "Status"], this.prompts.map((p) => [
1338
+ p.file,
1339
+ String(p.line),
1340
+ p.preview,
1341
+ p.platformId ?? "",
1342
+ p.version ?? "",
1343
+ p.status
1344
+ ])),
1345
+ "",
1346
+ "### Datasets",
1347
+ renderTable(["File", "Name", "Items", "Platform ID", "Prompt ID", "Status"], this.datasets.map((d) => [
1348
+ d.file,
1349
+ d.name,
1350
+ String(d.items),
1351
+ d.platformId ?? "",
1352
+ d.promptId ?? "",
1353
+ d.status
1354
+ ])),
1355
+ "",
1356
+ "### Evaluations",
1357
+ renderTable(["Name", "Criteria Count", "Platform ID", "Prompt ID", "Status"], this.evaluations.map((e) => [
1358
+ e.name,
1359
+ String(e.criteriaCount),
1360
+ e.platformId ?? "",
1361
+ e.promptId ?? "",
1362
+ e.status
1363
+ ])),
1364
+ "",
1365
+ "## Integration Status",
1366
+ renderTable(["Framework", "Package", "Status"], this.integrations.map((i) => [
1367
+ i.framework,
1368
+ i.pkg,
1369
+ i.status
1370
+ ])),
1371
+ ""
1372
+ ];
1373
+ return sections.join(`
1374
+ `);
1375
+ }
1376
+ parse(content) {
1377
+ const lines = content.split(`
1378
+ `);
1379
+ let currentSection = null;
1380
+ let sectionLines = [];
1381
+ const flushSection = () => {
1382
+ if (!currentSection || sectionLines.length === 0)
1383
+ return;
1384
+ const rows = parseTableRows(sectionLines);
1385
+ const dataRows = rows.slice(1);
1386
+ switch (currentSection) {
1387
+ case "prompts":
1388
+ for (const row of dataRows) {
1389
+ const [file, lineStr, preview, pid, ver, st] = row;
1390
+ if (file !== undefined && lineStr !== undefined && preview !== undefined) {
1391
+ this.prompts.push({
1392
+ file,
1393
+ line: parseInt(lineStr, 10) || 0,
1394
+ preview,
1395
+ platformId: emptyToUndefined(pid),
1396
+ version: emptyToUndefined(ver),
1397
+ status: emptyToUndefined(st) ?? "discovered"
1398
+ });
1399
+ }
1400
+ }
1401
+ break;
1402
+ case "datasets":
1403
+ for (const row of dataRows) {
1404
+ const [file, name, itemsStr, pid, prid, st] = row;
1405
+ if (file !== undefined && name !== undefined && itemsStr !== undefined) {
1406
+ this.datasets.push({
1407
+ file,
1408
+ name,
1409
+ items: parseInt(itemsStr, 10) || 0,
1410
+ platformId: emptyToUndefined(pid),
1411
+ promptId: emptyToUndefined(prid),
1412
+ status: emptyToUndefined(st) ?? "discovered"
1413
+ });
1414
+ }
1415
+ }
1416
+ break;
1417
+ case "evaluations":
1418
+ for (const row of dataRows) {
1419
+ const [name, ccStr, pid, prid, st] = row;
1420
+ if (name !== undefined && ccStr !== undefined) {
1421
+ this.evaluations.push({
1422
+ name,
1423
+ criteriaCount: parseInt(ccStr, 10) || 0,
1424
+ platformId: emptyToUndefined(pid),
1425
+ promptId: emptyToUndefined(prid),
1426
+ status: emptyToUndefined(st) ?? "discovered"
1427
+ });
1428
+ }
1429
+ }
1430
+ break;
1431
+ case "integrations":
1432
+ for (const row of dataRows) {
1433
+ const [framework, pkg, status] = row;
1434
+ if (framework !== undefined && pkg !== undefined && status !== undefined) {
1435
+ this.integrations.push({ framework, pkg, status });
1436
+ }
1437
+ }
1438
+ break;
1439
+ }
1440
+ sectionLines = [];
1441
+ };
1442
+ for (const line of lines) {
1443
+ const trimmed = line.trim();
1444
+ if (trimmed === "### Prompts") {
1445
+ flushSection();
1446
+ currentSection = "prompts";
1447
+ continue;
1448
+ }
1449
+ if (trimmed === "### Datasets") {
1450
+ flushSection();
1451
+ currentSection = "datasets";
1452
+ continue;
1453
+ }
1454
+ if (trimmed === "### Evaluations") {
1455
+ flushSection();
1456
+ currentSection = "evaluations";
1457
+ continue;
1458
+ }
1459
+ if (trimmed === "## Integration Status") {
1460
+ flushSection();
1461
+ currentSection = "integrations";
1462
+ continue;
1463
+ }
1464
+ if (trimmed.startsWith("## ") && currentSection !== null && trimmed !== "## Integration Status") {
1465
+ flushSection();
1466
+ currentSection = null;
1467
+ continue;
1468
+ }
1469
+ if (currentSection && trimmed.startsWith("|")) {
1470
+ sectionLines.push(trimmed);
1471
+ }
1472
+ }
1473
+ flushSection();
1474
+ }
1475
+ }
1476
+
1477
+ // src/commands/onboarding.ts
1478
+ import chalk2 from "chalk";
1479
+ import { resolve as resolve2 } from "path";
1480
+
1481
+ // src/lib/explorer.ts
1482
+ import { readdirSync, readFileSync as readFileSync3, statSync } from "fs";
1483
+ import { join as join3, relative, extname, basename } from "path";
1484
+ var TEMPLATE_VAR_PATTERN = /\{\{[a-zA-Z_][a-zA-Z0-9_]*\}\}/;
1485
+ var PROMPT_NAME_PATTERN = /(?:const|let|var|export)\s+\w*(?:prompt|system|agent|instruction|template)\w*\s*=/i;
1486
+ var SCHEMA_PATTERN = /["']?(?:inputSchema|outputSchema|properties|required)["']?\s*[=:]/;
1487
+ var ZOD_SCHEMA_PATTERN = /z\.object\s*\(/;
1488
+ var PYDANTIC_PATTERN = /class\s+\w+\s*\(\s*(?:BaseModel|BaseSettings)\s*\)/;
1489
+ var MARKER_START_PATTERN = /MutagenT:START\s+(\w+)(?:\s+id=(\S+))?/;
1490
+ function walkDir(dir, extensions, excludeDirs, maxDepth, currentDepth = 0) {
1491
+ if (currentDepth >= maxDepth)
1492
+ return [];
1493
+ const files = [];
1494
+ let entries;
1495
+ try {
1496
+ entries = readdirSync(dir);
1497
+ } catch {
1498
+ return files;
1499
+ }
1500
+ for (const entry of entries) {
1501
+ const fullPath = join3(dir, entry);
1502
+ let stat;
1503
+ try {
1504
+ stat = statSync(fullPath);
1505
+ } catch {
1506
+ continue;
1507
+ }
1508
+ if (stat.isDirectory()) {
1509
+ if (excludeDirs.includes(entry))
1510
+ continue;
1511
+ files.push(...walkDir(fullPath, extensions, excludeDirs, maxDepth, currentDepth + 1));
1512
+ } else if (stat.isFile()) {
1513
+ const ext = extname(entry).toLowerCase();
1514
+ if (extensions.includes(ext)) {
1515
+ files.push(fullPath);
1516
+ }
1517
+ }
1518
+ }
1519
+ return files;
1520
+ }
1521
+ function scanForPrompts(filePath, relativePath) {
1522
+ const results = [];
1523
+ let content;
1524
+ try {
1525
+ content = readFileSync3(filePath, "utf-8");
1526
+ } catch {
1527
+ return results;
1528
+ }
1529
+ const lines = content.split(`
1530
+ `);
1531
+ for (let i = 0;i < lines.length; i++) {
1532
+ const line = lines[i];
1533
+ if (!line)
1534
+ continue;
1535
+ if (TEMPLATE_VAR_PATTERN.test(line)) {
1536
+ const preview = line.trim().substring(0, 80);
1537
+ results.push({
1538
+ file: relativePath,
1539
+ line: i + 1,
1540
+ preview,
1541
+ reason: "template-variable"
1542
+ });
1543
+ }
1544
+ if (PROMPT_NAME_PATTERN.test(line)) {
1545
+ const preview = line.trim().substring(0, 80);
1546
+ if (!results.some((r) => r.file === relativePath && r.line === i + 1)) {
1547
+ results.push({
1548
+ file: relativePath,
1549
+ line: i + 1,
1550
+ preview,
1551
+ reason: "prompt-constant"
1552
+ });
1553
+ }
1554
+ }
1555
+ if (ZOD_SCHEMA_PATTERN.test(line)) {
1556
+ const preview = line.trim().substring(0, 80);
1557
+ if (!results.some((r) => r.file === relativePath && r.line === i + 1)) {
1558
+ results.push({
1559
+ file: relativePath,
1560
+ line: i + 1,
1561
+ preview,
1562
+ reason: "zod-schema"
1563
+ });
1564
+ }
1565
+ }
1566
+ if (PYDANTIC_PATTERN.test(line)) {
1567
+ const preview = line.trim().substring(0, 80);
1568
+ if (!results.some((r) => r.file === relativePath && r.line === i + 1)) {
1569
+ results.push({
1570
+ file: relativePath,
1571
+ line: i + 1,
1572
+ preview,
1573
+ reason: "pydantic-model"
1574
+ });
1575
+ }
1576
+ }
1577
+ }
1578
+ return results;
1579
+ }
1580
+ function scanForMarkers(filePath, relativePath) {
1581
+ const results = [];
1582
+ let content;
1583
+ try {
1584
+ content = readFileSync3(filePath, "utf-8");
1585
+ } catch {
1586
+ return results;
1587
+ }
1588
+ const lines = content.split(`
1589
+ `);
1590
+ for (let i = 0;i < lines.length; i++) {
1591
+ const line = lines[i];
1592
+ if (!line)
1593
+ continue;
1594
+ const match = MARKER_START_PATTERN.exec(line);
1595
+ if (match) {
1596
+ const rawType = match[1]?.toLowerCase();
1597
+ const platformId = match[2];
1598
+ const validTypes = new Set(["prompt", "dataset", "evaluation"]);
1599
+ if (rawType && validTypes.has(rawType)) {
1600
+ results.push({
1601
+ file: relativePath,
1602
+ line: i + 1,
1603
+ type: rawType,
1604
+ platformId
1605
+ });
1606
+ }
1607
+ }
1608
+ }
1609
+ return results;
1610
+ }
1611
+ function scanJsonForSchemas(filePath, relativePath) {
1612
+ const results = [];
1613
+ const ext = extname(filePath).toLowerCase();
1614
+ if (ext !== ".json")
1615
+ return results;
1616
+ let content;
1617
+ try {
1618
+ content = readFileSync3(filePath, "utf-8");
1619
+ } catch {
1620
+ return results;
1621
+ }
1622
+ if (!SCHEMA_PATTERN.test(content))
1623
+ return results;
1624
+ const preview = `JSON with schema definitions: ${basename(filePath)}`;
1625
+ results.push({
1626
+ file: relativePath,
1627
+ line: 1,
1628
+ preview: preview.substring(0, 80),
1629
+ reason: "json-schema"
1630
+ });
1631
+ return results;
1632
+ }
1633
+ function scanForDatasets(dir, rootPath, excludeDirs, maxDepth) {
1634
+ const results = [];
1635
+ const dataExtensions = [".json", ".jsonl", ".csv"];
1636
+ const files = walkDir(dir, dataExtensions, excludeDirs, maxDepth);
1637
+ for (const filePath of files) {
1638
+ const relativePath = relative(rootPath, filePath);
1639
+ const ext = extname(filePath).toLowerCase();
1640
+ const name = basename(filePath, ext);
1641
+ let content;
1642
+ try {
1643
+ content = readFileSync3(filePath, "utf-8");
1644
+ } catch {
1645
+ continue;
1646
+ }
1647
+ if (ext === ".csv") {
1648
+ const lines = content.trim().split(`
1649
+ `);
1650
+ if (lines.length > 1) {
1651
+ const header = lines[0]?.toLowerCase() ?? "";
1652
+ if (header.includes("input") || header.includes("output") || header.includes("expected")) {
1653
+ results.push({ file: relativePath, name, items: lines.length - 1 });
1654
+ }
1655
+ }
1656
+ } else if (ext === ".jsonl") {
1657
+ const lines = content.trim().split(`
1658
+ `).filter((l) => l.trim().length > 0);
1659
+ if (lines.length > 0) {
1660
+ try {
1661
+ const first = JSON.parse(lines[0] ?? "{}");
1662
+ if ("input" in first || "expectedOutput" in first) {
1663
+ results.push({ file: relativePath, name, items: lines.length });
1664
+ }
1665
+ } catch {}
1666
+ }
1667
+ } else if (ext === ".json") {
1668
+ try {
1669
+ const parsed = JSON.parse(content);
1670
+ if (Array.isArray(parsed) && parsed.length > 0) {
1671
+ const first = parsed[0];
1672
+ if ("input" in first || "expectedOutput" in first) {
1673
+ results.push({ file: relativePath, name, items: parsed.length });
1674
+ }
1675
+ }
1676
+ } catch {}
1677
+ }
1678
+ }
1679
+ return results;
1680
+ }
1681
+ function exploreCodebase(options) {
1682
+ const rootPath = options.path;
1683
+ const prompts = [];
1684
+ const datasets = [];
1685
+ const markers = [];
1686
+ const sourceFiles = walkDir(rootPath, options.extensions, options.excludeDirs, options.depth);
1687
+ for (const filePath of sourceFiles) {
1688
+ const relativePath = relative(rootPath, filePath);
1689
+ markers.push(...scanForMarkers(filePath, relativePath));
1690
+ if (!options.markersOnly) {
1691
+ prompts.push(...scanForPrompts(filePath, relativePath));
1692
+ }
1693
+ }
1694
+ if (!options.markersOnly) {
1695
+ const jsonFiles = walkDir(rootPath, [".json"], options.excludeDirs, options.depth);
1696
+ for (const filePath of jsonFiles) {
1697
+ const relativePath = relative(rootPath, filePath);
1698
+ prompts.push(...scanJsonForSchemas(filePath, relativePath));
1699
+ }
1700
+ datasets.push(...scanForDatasets(rootPath, rootPath, options.excludeDirs, options.depth));
1701
+ }
1702
+ return { prompts, datasets, markers };
1703
+ }
1704
+ function parseExtensions(includeGlob) {
1705
+ const braceMatch = /\{([^}]+)\}/.exec(includeGlob);
1706
+ if (braceMatch?.[1]) {
1707
+ return braceMatch[1].split(",").map((ext) => `.${ext.trim()}`);
1708
+ }
1709
+ const extMatch = /\*\.(\w+)$/.exec(includeGlob);
1710
+ if (extMatch?.[1]) {
1711
+ return [`.${extMatch[1]}`];
1712
+ }
1713
+ return [".ts", ".js", ".py", ".tsx", ".jsx"];
1714
+ }
1715
+ function parseExcludeDirs(excludePattern) {
1716
+ return excludePattern.split(",").map((d) => d.trim()).filter(Boolean);
1717
+ }
1718
+
1719
+ // src/commands/onboarding.ts
1720
+ async function runPostOnboarding() {
1721
+ const inquirer = (await import("inquirer")).default;
1722
+ console.log("");
1723
+ console.log(chalk2.bold.cyan(" What would you like to do next?"));
1724
+ console.log("");
1725
+ const { path: selectedPath } = await inquirer.prompt([{
1726
+ type: "list",
1727
+ name: "path",
1728
+ message: "Choose your path:",
1729
+ choices: [
1730
+ {
1731
+ name: `${chalk2.green("A")} Guided Integration — connect your AI framework`,
1732
+ value: "integrate"
1733
+ },
1734
+ {
1735
+ name: `${chalk2.green("B")} Quick Optimization — upload a prompt and optimize it`,
1736
+ value: "optimize"
1737
+ },
1738
+ {
1739
+ name: `${chalk2.green("C")} Exit — explore on your own`,
1740
+ value: "exit"
1741
+ }
1742
+ ]
1743
+ }]);
1744
+ if (selectedPath === "exit") {
1745
+ console.log("");
1746
+ console.log(chalk2.dim(" You can run `mutagent --help` anytime to see available commands."));
1747
+ console.log(chalk2.dim(" Try `mutagent explore` to scan your codebase for prompts."));
1748
+ console.log("");
1749
+ return;
1750
+ }
1751
+ console.log("");
1752
+ console.log(chalk2.cyan(" Scanning your codebase..."));
1753
+ console.log("");
1754
+ const scanPath = resolve2(".");
1755
+ const result = exploreCodebase({
1756
+ path: scanPath,
1757
+ depth: 10,
1758
+ extensions: parseExtensions("**/*.{ts,js,py,tsx,jsx}"),
1759
+ excludeDirs: parseExcludeDirs("node_modules,dist,.git,build,.next,__pycache__,venv,.venv"),
1760
+ markersOnly: false
1761
+ });
1762
+ const totalFindings = result.prompts.length + result.datasets.length;
1763
+ if (totalFindings > 0) {
1764
+ console.log(chalk2.green(` Found ${String(result.prompts.length)} prompt(s) and ${String(result.datasets.length)} dataset(s)`));
1765
+ } else {
1766
+ console.log(chalk2.dim(" No prompts or datasets detected yet."));
1767
+ }
1768
+ console.log("");
1769
+ if (selectedPath === "integrate") {
1770
+ await runIntegrationPath();
1771
+ } else {
1772
+ runOptimizationPath(result.prompts.length, result.datasets.length);
1773
+ }
1774
+ }
1775
+ async function runIntegrationPath() {
1776
+ const inquirerMod = (await import("inquirer")).default;
1777
+ const { framework } = await inquirerMod.prompt([{
1778
+ type: "list",
1779
+ name: "framework",
1780
+ message: "Which AI framework are you using?",
1781
+ choices: [
1782
+ { name: "Mastra", value: "mastra" },
1783
+ { name: "LangChain", value: "langchain" },
1784
+ { name: "LangGraph", value: "langgraph" },
1785
+ { name: "Vercel AI SDK", value: "vercel-ai" },
1786
+ { name: "Claude Code", value: "claude-code" },
1787
+ { name: "Other / Generic", value: "generic" }
1788
+ ]
1789
+ }]);
1790
+ console.log("");
1791
+ console.log(chalk2.bold(" Next steps:"));
1792
+ console.log("");
1793
+ console.log(` 1. ${chalk2.green(`mutagent integrate ${framework}`)}`);
1794
+ console.log(` Get the integration guide for ${framework}`);
1795
+ console.log("");
1796
+ console.log(` 2. ${chalk2.green(`mutagent integrate ${framework} --verify`)}`);
1797
+ console.log(" Verify your integration is working");
1798
+ console.log("");
1799
+ console.log(` 3. ${chalk2.green("mutagent explore")}`);
1800
+ console.log(" Re-scan to confirm markers are in place");
1801
+ console.log("");
1802
+ }
1803
+ function runOptimizationPath(promptCount, datasetCount) {
1804
+ console.log(chalk2.bold(" Quick Optimization Workflow:"));
1805
+ console.log("");
1806
+ let step = 1;
1807
+ if (promptCount === 0) {
1808
+ console.log(` ${String(step)}. ${chalk2.green('mutagent prompts create --name "my-prompt" --raw "Your prompt with {{variables}}"')}`);
1809
+ console.log(" Create a prompt with template variables");
1810
+ console.log("");
1811
+ step++;
1812
+ } else {
1813
+ console.log(chalk2.dim(` ${chalk2.green("✓")} Prompts detected in codebase (${String(promptCount)} found)`));
1814
+ console.log(chalk2.dim(` Upload one: mutagent prompts create --name "my-prompt" --raw-file <path>`));
1815
+ console.log("");
1816
+ }
1817
+ if (datasetCount === 0) {
1818
+ console.log(` ${String(step)}. ${chalk2.green("mutagent prompts dataset add <prompt-id> --file dataset.json")}`);
1819
+ console.log(" Upload a dataset with input/output pairs");
1820
+ console.log("");
1821
+ step++;
1822
+ } else {
1823
+ console.log(chalk2.dim(` ${chalk2.green("✓")} Datasets detected in codebase (${String(datasetCount)} found)`));
1824
+ console.log(chalk2.dim(` Upload one: mutagent prompts dataset add <prompt-id> --file <path>`));
1825
+ console.log("");
1826
+ }
1827
+ console.log(` ${String(step)}. ${chalk2.green('mutagent prompts evaluation create <prompt-id> --name "My Eval" --file criteria.json')}`);
1828
+ console.log(" Define evaluation criteria");
1829
+ console.log("");
1830
+ step++;
1831
+ console.log(` ${String(step)}. ${chalk2.green("mutagent prompts optimize start <prompt-id> --dataset <dataset-id>")}`);
1832
+ console.log(" Start the optimization loop");
1833
+ console.log("");
1834
+ console.log(chalk2.dim(" Tip: Use `mutagent prompts list` to see your prompt IDs."));
1835
+ console.log("");
1836
+ }
1837
+
1168
1838
  // src/commands/auth.ts
1169
1839
  function createAuthCommand() {
1170
1840
  const auth = new Command("auth").description("Authenticate with MutagenT platform").addHelpText("after", `
1171
1841
  Examples:
1172
- ${chalk2.dim("$")} mutagent auth login
1173
- ${chalk2.dim("$")} mutagent auth login --browser
1174
- ${chalk2.dim("$")} mutagent auth login --api-key <key>
1175
- ${chalk2.dim("$")} mutagent auth status
1176
- ${chalk2.dim("$")} mutagent auth logout
1842
+ ${chalk3.dim("$")} mutagent auth login
1843
+ ${chalk3.dim("$")} mutagent auth login --browser
1844
+ ${chalk3.dim("$")} mutagent auth login --api-key <key>
1845
+ ${chalk3.dim("$")} mutagent auth status
1846
+ ${chalk3.dim("$")} mutagent auth logout
1177
1847
  `);
1178
1848
  auth.command("login").description("Authenticate and store API key").option("--api-key <key>", "API key (non-interactive)").option("--browser", "Force browser-based authentication").option("--non-interactive", "Disable interactive prompts (auto-selects browser auth)").option("--endpoint <url>", "API endpoint", "https://api.mutagent.io").addHelpText("after", `
1179
1849
  Examples:
1180
- ${chalk2.dim("$")} mutagent auth login ${chalk2.dim("# Interactive (choose method)")}
1181
- ${chalk2.dim("$")} mutagent auth login --browser ${chalk2.dim("# Browser OAuth flow")}
1182
- ${chalk2.dim("$")} mutagent auth login --api-key mg_live_xxx ${chalk2.dim("# Direct API key (CI/CD)")}
1183
- ${chalk2.dim("$")} mutagent auth login --non-interactive ${chalk2.dim("# Auto browser flow (AI agents)")}
1850
+ ${chalk3.dim("$")} mutagent auth login ${chalk3.dim("# Interactive (choose method)")}
1851
+ ${chalk3.dim("$")} mutagent auth login --browser ${chalk3.dim("# Browser OAuth flow")}
1852
+ ${chalk3.dim("$")} mutagent auth login --api-key mg_live_xxx ${chalk3.dim("# Direct API key (CI/CD)")}
1853
+ ${chalk3.dim("$")} mutagent auth login --non-interactive ${chalk3.dim("# Auto browser flow (AI agents)")}
1184
1854
 
1185
1855
  Environment Variables:
1186
1856
  MUTAGENT_API_KEY API key (skips login entirely)
@@ -1191,6 +1861,7 @@ Environment Variables:
1191
1861
  const isJson = getJsonFlag(auth);
1192
1862
  const output = new OutputFormatter(isJson ? "json" : "table");
1193
1863
  try {
1864
+ const wasFirstLogin = !hasCredentials();
1194
1865
  let apiKey = options.apiKey ?? process.env.MUTAGENT_API_KEY;
1195
1866
  let endpoint = process.env.MUTAGENT_ENDPOINT ?? options.endpoint;
1196
1867
  let workspaceName;
@@ -1228,7 +1899,7 @@ Environment Variables:
1228
1899
  }
1229
1900
  if (!isNonInteractive && !hasCredentials()) {
1230
1901
  console.log(`
1231
- ` + chalk2.bold.cyan(" Welcome to MutagenT CLI!") + `
1902
+ ` + chalk3.bold.cyan(" Welcome to MutagenT CLI!") + `
1232
1903
  `);
1233
1904
  console.log(` No credentials found. Please authenticate to continue.
1234
1905
  `);
@@ -1368,6 +2039,9 @@ Environment Variables:
1368
2039
  output.info("Workspace: " + selectedWsName);
1369
2040
  output.info("Endpoint: " + endpoint);
1370
2041
  }
2042
+ if (wasFirstLogin && process.stdin.isTTY && !isJson) {
2043
+ await runPostOnboarding();
2044
+ }
1371
2045
  } catch (error) {
1372
2046
  if (error instanceof MutagentError) {
1373
2047
  output.error(error.message);
@@ -1378,8 +2052,8 @@ Environment Variables:
1378
2052
  });
1379
2053
  auth.command("status").description("Check authentication status").addHelpText("after", `
1380
2054
  Examples:
1381
- ${chalk2.dim("$")} mutagent auth status
1382
- ${chalk2.dim("$")} mutagent auth status --json
2055
+ ${chalk3.dim("$")} mutagent auth status
2056
+ ${chalk3.dim("$")} mutagent auth status --json
1383
2057
  `).action(async () => {
1384
2058
  const isJson = getJsonFlag(auth);
1385
2059
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -1396,13 +2070,26 @@ Examples:
1396
2070
  process.exit(0);
1397
2071
  }
1398
2072
  const isValid = await validateApiKey(apiKey, endpoint);
2073
+ const cwd = process.cwd();
2074
+ const hasOnboarding = existsSync3(join4(cwd, ".mutagentrc.json"));
2075
+ const hasContextFile = existsSync3(join4(cwd, ".mutagent", "mutation-context.md"));
2076
+ let contextSummary;
2077
+ if (hasContextFile) {
2078
+ try {
2079
+ const ctx = MutationContext.load(cwd);
2080
+ contextSummary = ctx.getSummary();
2081
+ } catch {}
2082
+ }
1399
2083
  if (isJson) {
1400
2084
  const statusResult = {
1401
2085
  authenticated: isValid,
1402
2086
  endpoint,
1403
2087
  keyPrefix: `${apiKey.slice(0, 8)}...`,
1404
2088
  defaultWorkspace: config.defaultWorkspace,
1405
- defaultOrganization: config.defaultOrganization
2089
+ defaultOrganization: config.defaultOrganization,
2090
+ onboarding: hasOnboarding,
2091
+ contextFile: hasContextFile,
2092
+ context: contextSummary ?? null
1406
2093
  };
1407
2094
  if (!isValid) {
1408
2095
  statusResult.message = "Authentication invalid — run `mutagent auth login --browser`";
@@ -1415,7 +2102,7 @@ Examples:
1415
2102
  output.output(statusResult);
1416
2103
  } else {
1417
2104
  if (isValid) {
1418
- output.success("Authenticated");
2105
+ output.success("Authentication: Authenticated");
1419
2106
  output.info(`Endpoint: ${endpoint}`);
1420
2107
  output.info(`Key: ${apiKey.slice(0, 8)}...`);
1421
2108
  if (config.defaultWorkspace) {
@@ -1425,18 +2112,38 @@ Examples:
1425
2112
  output.info(`Organization: ${config.defaultOrganization}`);
1426
2113
  }
1427
2114
  } else {
1428
- output.error("Authentication invalid — run `mutagent auth login --browser`");
2115
+ output.error("Authentication: Invalid — run `mutagent auth login --browser`");
1429
2116
  console.error("");
1430
2117
  console.error("Authentication required. Options:");
1431
2118
  console.error(" Interactive: mutagent auth login --browser");
1432
2119
  console.error(" Non-interactive: export MUTAGENT_API_KEY=<your-key>");
1433
2120
  console.error(" CI/CD: mutagent auth login --api-key <key>");
1434
2121
  }
2122
+ if (hasOnboarding) {
2123
+ output.success("Onboarding: Complete (.mutagentrc.json found)");
2124
+ } else {
2125
+ output.warn("Onboarding: Not initialized (run `mutagent init`)");
2126
+ }
2127
+ if (hasContextFile && contextSummary) {
2128
+ const parts = [
2129
+ `${String(contextSummary.prompts)} prompts`,
2130
+ `${String(contextSummary.datasets)} datasets`,
2131
+ `${String(contextSummary.evaluations)} evaluations`
2132
+ ];
2133
+ output.success(`Context File: .mutagent/mutation-context.md (${parts.join(", ")})`);
2134
+ } else if (hasContextFile) {
2135
+ output.success("Context File: .mutagent/mutation-context.md");
2136
+ } else {
2137
+ output.warn("Context File: Not found (run `mutagent explore`)");
2138
+ }
2139
+ if (contextSummary && contextSummary.integrated.length > 0) {
2140
+ output.success(`Integration: ${contextSummary.integrated.join(", ")} (active)`);
2141
+ }
1435
2142
  }
1436
2143
  });
1437
2144
  auth.command("logout").description("Clear stored credentials").addHelpText("after", `
1438
2145
  Examples:
1439
- ${chalk2.dim("$")} mutagent auth logout
2146
+ ${chalk3.dim("$")} mutagent auth logout
1440
2147
  `).action(() => {
1441
2148
  const isJson = getJsonFlag(auth);
1442
2149
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -1447,17 +2154,20 @@ Examples:
1447
2154
  }
1448
2155
 
1449
2156
  // src/commands/login.ts
2157
+ init_config();
2158
+ init_sdk_client();
1450
2159
  import { Command as Command2 } from "commander";
1451
2160
  import inquirer2 from "inquirer";
1452
- import chalk3 from "chalk";
2161
+ import chalk4 from "chalk";
1453
2162
  import ora2 from "ora";
2163
+ init_errors();
1454
2164
  function createLoginCommand() {
1455
2165
  const login = new Command2("login").description("Login to MutagenT platform").option("--api-key <key>", "API key (non-interactive)").option("--browser", "Force browser-based authentication").option("--non-interactive", "Disable interactive prompts (auto-selects browser auth)").option("--endpoint <url>", "API endpoint", "https://api.mutagent.io").addHelpText("after", `
1456
2166
  Examples:
1457
- ${chalk3.dim("$")} mutagent login
1458
- ${chalk3.dim("$")} mutagent login --browser
1459
- ${chalk3.dim("$")} mutagent login --api-key <key>
1460
- ${chalk3.dim("$")} mutagent login --non-interactive ${chalk3.dim("# Auto browser flow (AI agents)")}
2167
+ ${chalk4.dim("$")} mutagent login
2168
+ ${chalk4.dim("$")} mutagent login --browser
2169
+ ${chalk4.dim("$")} mutagent login --api-key <key>
2170
+ ${chalk4.dim("$")} mutagent login --non-interactive ${chalk4.dim("# Auto browser flow (AI agents)")}
1461
2171
  `).action(async (options) => {
1462
2172
  const isJson = getJsonFlag(login);
1463
2173
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -1483,7 +2193,7 @@ Examples:
1483
2193
  }
1484
2194
  if (!isNonInteractive && !hasCredentials()) {
1485
2195
  console.log(`
1486
- ` + chalk3.bold.cyan(" Welcome to MutagenT CLI!") + `
2196
+ ` + chalk4.bold.cyan(" Welcome to MutagenT CLI!") + `
1487
2197
  `);
1488
2198
  console.log(` No credentials found. Please authenticate to continue.
1489
2199
  `);
@@ -1590,9 +2300,11 @@ Examples:
1590
2300
  }
1591
2301
 
1592
2302
  // src/commands/prompts.ts
2303
+ init_sdk_client();
1593
2304
  import { Command as Command3 } from "commander";
1594
- import chalk4 from "chalk";
1595
- import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
2305
+ import chalk7 from "chalk";
2306
+ import { readFileSync as readFileSync4, existsSync as existsSync4 } from "fs";
2307
+ init_errors();
1596
2308
 
1597
2309
  // src/lib/ui-links.ts
1598
2310
  function getAppBaseUrl() {
@@ -1626,6 +2338,33 @@ function playgroundLink() {
1626
2338
  function providerSettingsLink() {
1627
2339
  return `${getAppBaseUrl()}/settings/providers`;
1628
2340
  }
2341
+ function workspaceLink(id) {
2342
+ return `${getAppBaseUrl()}/settings/workspaces/${String(id)}`;
2343
+ }
2344
+ function workspaceLinks(id) {
2345
+ return {
2346
+ settings: workspaceLink(id),
2347
+ api: `/api/workspaces/${String(id)}`
2348
+ };
2349
+ }
2350
+ function providerLink(id) {
2351
+ return `${getAppBaseUrl()}/settings/providers/${String(id)}`;
2352
+ }
2353
+ function providerLinks(id) {
2354
+ return {
2355
+ settings: providerLink(id),
2356
+ api: `/api/providers/${String(id)}`
2357
+ };
2358
+ }
2359
+ function agentLink(id) {
2360
+ return `${getAppBaseUrl()}/agents/${String(id)}`;
2361
+ }
2362
+ function agentLinks(id) {
2363
+ return {
2364
+ dashboard: agentLink(id),
2365
+ api: `/api/agents/${String(id)}`
2366
+ };
2367
+ }
1629
2368
  function promptLinks(promptId) {
1630
2369
  return {
1631
2370
  dashboard: promptLink(promptId),
@@ -1674,46 +2413,344 @@ function isValidJsonSchema(schema) {
1674
2413
  if (!("properties" in obj) || typeof obj.properties !== "object" || obj.properties === null) {
1675
2414
  return false;
1676
2415
  }
1677
- }
1678
- return true;
1679
- }
1680
- function buildSchemaFromVariables(variables) {
1681
- const properties = {};
1682
- for (const variable of variables) {
1683
- const prop = { type: variable.type };
1684
- if (variable.description) {
1685
- prop.description = variable.description;
2416
+ }
2417
+ return true;
2418
+ }
2419
+ function buildSchemaFromVariables(variables) {
2420
+ const properties = {};
2421
+ for (const variable of variables) {
2422
+ const prop = { type: variable.type };
2423
+ if (variable.description) {
2424
+ prop.description = variable.description;
2425
+ }
2426
+ properties[variable.name] = prop;
2427
+ }
2428
+ return {
2429
+ type: "object",
2430
+ properties
2431
+ };
2432
+ }
2433
+ function formatSchemaWarning(fieldName) {
2434
+ return [
2435
+ `${fieldName} doesn't appear to be a valid JSON Schema.`,
2436
+ "",
2437
+ " Expected format:",
2438
+ " {",
2439
+ ' "type": "object",',
2440
+ ' "properties": {',
2441
+ ' "variable_name": { "type": "string", "description": "Description here" }',
2442
+ " }",
2443
+ " }",
2444
+ "",
2445
+ " You can also provide a schema file: mutagent prompts create --file schema.json"
2446
+ ].join(`
2447
+ `);
2448
+ }
2449
+
2450
+ // src/lib/eval-creator.ts
2451
+ import chalk5 from "chalk";
2452
+ var RUBRIC_TEMPLATES = {
2453
+ "Exact Match": "Score 1.0 if the output exactly matches the expected value, 0.0 otherwise.",
2454
+ "Semantic Similarity": "Score 0.0-1.0 based on semantic similarity to the expected output. 1.0 = identical meaning, 0.5 = partially related, 0.0 = unrelated.",
2455
+ "Contains Key Info": "Score 1.0 if all key information from expected output is present, 0.5 if partially present, 0.0 if missing.",
2456
+ "Format Compliance": "Score 1.0 if the output follows the expected format/structure, 0.5 for minor deviations, 0.0 for wrong format.",
2457
+ "Factual Accuracy": "Score 1.0 if all facts are correct, 0.5 if mostly correct with minor errors, 0.0 if incorrect."
2458
+ };
2459
+ var EVAL_TYPE_DESCRIPTIONS = {
2460
+ accuracy: "Check if outputs match expected results (exact or semantic)",
2461
+ quality: "Assess output quality, clarity, and helpfulness",
2462
+ custom: "Define your own evaluation criteria"
2463
+ };
2464
+ function extractSchemaFields(schema, prefix) {
2465
+ if (!schema || typeof schema !== "object")
2466
+ return [];
2467
+ const obj = schema;
2468
+ const properties = obj.properties;
2469
+ if (properties) {
2470
+ return Object.keys(properties).map((key) => `${prefix}.${key}`);
2471
+ }
2472
+ const keys = Object.keys(obj).filter((k) => k !== "type" && k !== "required" && k !== "description");
2473
+ if (keys.length > 0) {
2474
+ return keys.map((key) => `${prefix}.${key}`);
2475
+ }
2476
+ return [];
2477
+ }
2478
+ async function runGuidedEvalCreator(promptId) {
2479
+ const inquirer3 = (await import("inquirer")).default;
2480
+ console.log("");
2481
+ console.log(chalk5.cyan(" Fetching prompt details..."));
2482
+ let inputFields = [];
2483
+ let outputFields = [];
2484
+ try {
2485
+ const { getSDKClient: getSDKClient2 } = await Promise.resolve().then(() => (init_sdk_client(), exports_sdk_client));
2486
+ const client = getSDKClient2();
2487
+ const prompt = await client.getPrompt(promptId);
2488
+ inputFields = extractSchemaFields(prompt.inputSchema, "input");
2489
+ outputFields = extractSchemaFields(prompt.outputSchema, "output");
2490
+ if (inputFields.length > 0 || outputFields.length > 0) {
2491
+ console.log(chalk5.green(` Found ${String(inputFields.length)} input field(s) and ${String(outputFields.length)} output field(s)`));
2492
+ } else {
2493
+ console.log(chalk5.yellow(" No schema fields detected. You can still define criteria manually."));
2494
+ }
2495
+ } catch {
2496
+ console.log(chalk5.yellow(" Could not fetch prompt. You can still define criteria manually."));
2497
+ }
2498
+ console.log("");
2499
+ const { evalType } = await inquirer3.prompt([{
2500
+ type: "list",
2501
+ name: "evalType",
2502
+ message: "What type of evaluation?",
2503
+ choices: Object.entries(EVAL_TYPE_DESCRIPTIONS).map(([value, description]) => ({
2504
+ name: `${value} — ${description}`,
2505
+ value
2506
+ }))
2507
+ }]);
2508
+ const defaultName = evalType.charAt(0).toUpperCase() + evalType.slice(1) + " Evaluation";
2509
+ const { evalName } = await inquirer3.prompt([{
2510
+ type: "input",
2511
+ name: "evalName",
2512
+ message: "Evaluation name:",
2513
+ default: defaultName,
2514
+ validate: (input) => {
2515
+ if (!input.trim())
2516
+ return "Evaluation name is required";
2517
+ return true;
2518
+ }
2519
+ }]);
2520
+ const allFields = [...inputFields, ...outputFields];
2521
+ const criteria = [];
2522
+ let addMore = true;
2523
+ while (addMore) {
2524
+ console.log("");
2525
+ console.log(chalk5.bold(` Criterion #${String(criteria.length + 1)}`));
2526
+ const { criterionName } = await inquirer3.prompt([{
2527
+ type: "input",
2528
+ name: "criterionName",
2529
+ message: "Name this criterion:",
2530
+ validate: (input) => {
2531
+ if (!input.trim())
2532
+ return "Criterion name is required";
2533
+ return true;
2534
+ }
2535
+ }]);
2536
+ let targetField;
2537
+ if (allFields.length > 0) {
2538
+ const fieldChoices = [
2539
+ ...allFields.map((f) => ({ name: f, value: f })),
2540
+ { name: "(custom field name)", value: "__custom__" }
2541
+ ];
2542
+ const { field } = await inquirer3.prompt([{
2543
+ type: "list",
2544
+ name: "field",
2545
+ message: "Target field:",
2546
+ choices: fieldChoices
2547
+ }]);
2548
+ if (field === "__custom__") {
2549
+ const { customField } = await inquirer3.prompt([{
2550
+ type: "input",
2551
+ name: "customField",
2552
+ message: "Custom field name (e.g., output.summary):"
2553
+ }]);
2554
+ targetField = customField.trim();
2555
+ } else {
2556
+ targetField = field;
2557
+ }
2558
+ } else {
2559
+ const { customField } = await inquirer3.prompt([{
2560
+ type: "input",
2561
+ name: "customField",
2562
+ message: "Target field (e.g., output.result):",
2563
+ default: "output"
2564
+ }]);
2565
+ targetField = customField.trim();
2566
+ }
2567
+ const rubricChoices = [
2568
+ ...Object.entries(RUBRIC_TEMPLATES).map(([name, value]) => ({
2569
+ name: `${name} — ${chalk5.dim(value.substring(0, 50))}...`,
2570
+ value
2571
+ })),
2572
+ { name: "(write custom rubric)", value: "__custom__" }
2573
+ ];
2574
+ const { rubric } = await inquirer3.prompt([{
2575
+ type: "list",
2576
+ name: "rubric",
2577
+ message: "Scoring rubric:",
2578
+ choices: rubricChoices
2579
+ }]);
2580
+ let scoringRubric;
2581
+ if (rubric === "__custom__") {
2582
+ const { customRubric } = await inquirer3.prompt([{
2583
+ type: "input",
2584
+ name: "customRubric",
2585
+ message: "Describe the scoring rubric:",
2586
+ validate: (input) => {
2587
+ if (!input.trim())
2588
+ return "Rubric is required";
2589
+ return true;
2590
+ }
2591
+ }]);
2592
+ scoringRubric = customRubric.trim();
2593
+ } else {
2594
+ scoringRubric = rubric;
1686
2595
  }
1687
- properties[variable.name] = prop;
2596
+ criteria.push({
2597
+ name: criterionName.trim(),
2598
+ targetField,
2599
+ scoringRubric,
2600
+ weight: 1
2601
+ });
2602
+ const { continueAdding } = await inquirer3.prompt([{
2603
+ type: "confirm",
2604
+ name: "continueAdding",
2605
+ message: "Add another criterion?",
2606
+ default: false
2607
+ }]);
2608
+ addMore = continueAdding;
2609
+ }
2610
+ if (criteria.length === 0) {
2611
+ console.log(chalk5.yellow(`
2612
+ No criteria defined. Aborting guided eval creation.`));
2613
+ return;
2614
+ }
2615
+ console.log("");
2616
+ console.log(chalk5.bold(" Evaluation Summary:"));
2617
+ console.log(` Name: ${chalk5.green(evalName)}`);
2618
+ console.log(` Type: ${evalType}`);
2619
+ console.log(` Criteria: ${String(criteria.length)}`);
2620
+ for (const c of criteria) {
2621
+ console.log(` - ${chalk5.cyan(c.name)} → ${c.targetField}`);
2622
+ }
2623
+ console.log("");
2624
+ const { confirmed } = await inquirer3.prompt([{
2625
+ type: "confirm",
2626
+ name: "confirmed",
2627
+ message: "Create this evaluation?",
2628
+ default: true
2629
+ }]);
2630
+ if (!confirmed) {
2631
+ console.log(chalk5.dim(`
2632
+ Cancelled.`));
2633
+ return;
1688
2634
  }
1689
2635
  return {
1690
- type: "object",
1691
- properties
2636
+ name: evalName.trim(),
2637
+ description: `${evalType} evaluation with ${String(criteria.length)} criteria`,
2638
+ evalConfig: { criteria }
1692
2639
  };
1693
2640
  }
1694
- function formatSchemaWarning(fieldName) {
1695
- return [
1696
- `${fieldName} doesn't appear to be a valid JSON Schema.`,
1697
- "",
1698
- " Expected format:",
1699
- " {",
1700
- ' "type": "object",',
1701
- ' "properties": {',
1702
- ' "variable_name": { "type": "string", "description": "Description here" }',
1703
- " }",
1704
- " }",
1705
- "",
1706
- " You can also provide a schema file: mutagent prompts create --file schema.json"
1707
- ].join(`
1708
- `);
2641
+
2642
+ // src/lib/scorecard.ts
2643
+ import chalk6 from "chalk";
2644
+ function truncateText(text, maxLen) {
2645
+ if (text.length <= maxLen)
2646
+ return text;
2647
+ return text.substring(0, maxLen - 3) + "...";
2648
+ }
2649
+ function formatScoreChange(before, after) {
2650
+ if (before === undefined || after === undefined)
2651
+ return "";
2652
+ const diff = after - before;
2653
+ const pct = before > 0 ? Math.round(diff / before * 100) : 0;
2654
+ if (diff > 0)
2655
+ return chalk6.green(` (+${String(pct)}%)`);
2656
+ if (diff < 0)
2657
+ return chalk6.red(` (${String(pct)}%)`);
2658
+ return chalk6.dim(" (no change)");
2659
+ }
2660
+ function formatScore(score) {
2661
+ if (score === undefined)
2662
+ return chalk6.dim("N/A");
2663
+ return score >= 0.8 ? chalk6.green(score.toFixed(2)) : score >= 0.5 ? chalk6.yellow(score.toFixed(2)) : chalk6.red(score.toFixed(2));
2664
+ }
2665
+ function renderScorecard(data) {
2666
+ const { job, prompt } = data;
2667
+ const boxWidth = 55;
2668
+ const topBorder = `┌${"─".repeat(boxWidth)}┐`;
2669
+ const bottomBorder = `└${"─".repeat(boxWidth)}┘`;
2670
+ const separator = `│ ${"─".repeat(boxWidth - 2)} │`;
2671
+ const pad = (text, width) => {
2672
+ const stripped = text.replace(/\u001B\[[0-9;]*m/g, "");
2673
+ const remaining = width - stripped.length;
2674
+ return remaining > 0 ? text + " ".repeat(remaining) : text;
2675
+ };
2676
+ const line = (text) => `│ ${pad(text, boxWidth - 2)} │`;
2677
+ const originalScore = data.originalScore;
2678
+ const bestScore = data.bestScore;
2679
+ const iterations = data.iterationsCompleted ?? job.config?.maxIterations ?? 0;
2680
+ const originalText = data.originalPrompt?.systemPrompt ?? data.originalPrompt?.rawPrompt ?? "(original prompt)";
2681
+ const optimizedText = prompt.systemPrompt ?? prompt.rawPrompt ?? prompt.humanPrompt ?? "(optimized prompt)";
2682
+ console.log("");
2683
+ console.log(topBorder);
2684
+ console.log(line(chalk6.bold("Optimization Results")));
2685
+ console.log(separator);
2686
+ console.log(line(chalk6.dim("BEFORE")));
2687
+ console.log(line(` Prompt: ${chalk6.dim(truncateText(originalText, 38))}`));
2688
+ console.log(line(` Score: ${formatScore(originalScore)}`));
2689
+ console.log(line(""));
2690
+ console.log(line(chalk6.bold("AFTER")));
2691
+ console.log(line(` Prompt: ${chalk6.cyan(truncateText(optimizedText, 38))}`));
2692
+ console.log(line(` Score: ${formatScore(bestScore)}${formatScoreChange(originalScore, bestScore)}`));
2693
+ console.log(separator);
2694
+ const statusStr = job.status === "completed" ? chalk6.green("completed") : chalk6.yellow(job.status);
2695
+ console.log(line(`Status: ${statusStr} | Iterations: ${String(iterations)}`));
2696
+ if (job.config?.model) {
2697
+ console.log(line(`Model: ${chalk6.dim(job.config.model)}`));
2698
+ }
2699
+ if (data.scoreProgression && data.scoreProgression.length > 0) {
2700
+ console.log(line(""));
2701
+ console.log(line(chalk6.dim("Score Progression:")));
2702
+ const progression = data.scoreProgression.map((s, i) => `#${String(i + 1)}: ${s.toFixed(2)}`).join(" ");
2703
+ if (progression.length > boxWidth - 4) {
2704
+ const mid = Math.ceil(data.scoreProgression.length / 2);
2705
+ const line1 = data.scoreProgression.slice(0, mid).map((s, i) => `#${String(i + 1)}: ${s.toFixed(2)}`).join(" ");
2706
+ const line2 = data.scoreProgression.slice(mid).map((s, i) => `#${String(i + mid + 1)}: ${s.toFixed(2)}`).join(" ");
2707
+ console.log(line(chalk6.dim(line1)));
2708
+ console.log(line(chalk6.dim(line2)));
2709
+ } else {
2710
+ console.log(line(chalk6.dim(progression)));
2711
+ }
2712
+ }
2713
+ console.log(separator);
2714
+ console.log(line(`Dashboard: ${chalk6.underline(optimizerLink(job.jobId))}`));
2715
+ console.log(bottomBorder);
2716
+ console.log("");
2717
+ }
2718
+ async function promptScorecardAction() {
2719
+ const inquirer3 = (await import("inquirer")).default;
2720
+ const { action } = await inquirer3.prompt([{
2721
+ type: "list",
2722
+ name: "action",
2723
+ message: "What would you like to do?",
2724
+ choices: [
2725
+ { name: chalk6.green("Apply") + " — Update prompt to optimized version", value: "apply" },
2726
+ { name: chalk6.red("Reject") + " — Keep original prompt", value: "reject" },
2727
+ { name: chalk6.dim("View Details") + " — Show full diff", value: "details" }
2728
+ ]
2729
+ }]);
2730
+ return { action };
2731
+ }
2732
+ function showPromptDiff(original, optimized) {
2733
+ console.log("");
2734
+ console.log(chalk6.bold(" Prompt Diff:"));
2735
+ console.log("");
2736
+ console.log(chalk6.red(" - " + (original ?? "(empty)")));
2737
+ console.log(chalk6.green(" + " + (optimized ?? "(empty)")));
2738
+ console.log("");
1709
2739
  }
1710
2740
 
1711
2741
  // src/commands/prompts.ts
2742
+ function updateMutationContext(updater) {
2743
+ try {
2744
+ const ctx = MutationContext.load();
2745
+ updater(ctx);
2746
+ ctx.save();
2747
+ } catch {}
2748
+ }
1712
2749
  var PREREQUISITES_TEXT = `
1713
- ${chalk4.yellow("Prerequisites:")}
1714
- 1. Evaluation criteria defined ${chalk4.dim("(via dashboard or evaluation create)")}
1715
- 2. Dataset uploaded ${chalk4.dim("mutagent prompts dataset list <prompt-id>")}
1716
- ${chalk4.dim("Note: LLM provider config is only required when the server uses external providers (USE_EXT_PROVIDERS=true)")}`;
2750
+ ${chalk7.yellow("Prerequisites:")}
2751
+ 1. Evaluation criteria defined ${chalk7.dim("(via dashboard or evaluation create)")}
2752
+ 2. Dataset uploaded ${chalk7.dim("mutagent prompts dataset list <prompt-id>")}
2753
+ ${chalk7.dim("Note: LLM provider config is only required when the server uses external providers (USE_EXT_PROVIDERS=true)")}`;
1717
2754
  function parseValidationErrors(error) {
1718
2755
  if (error instanceof ApiError) {
1719
2756
  try {
@@ -1824,16 +2861,16 @@ async function promptForInputSchema() {
1824
2861
  validate: (input) => {
1825
2862
  if (!input.trim())
1826
2863
  return "File path is required";
1827
- if (!existsSync2(input.trim()))
2864
+ if (!existsSync4(input.trim()))
1828
2865
  return `File not found: ${input.trim()}`;
1829
2866
  return true;
1830
2867
  }
1831
2868
  }]);
1832
- const content = readFileSync2(fileAnswer.path.trim(), "utf-8");
2869
+ const content = readFileSync4(fileAnswer.path.trim(), "utf-8");
1833
2870
  try {
1834
2871
  const parsed = JSON.parse(content);
1835
2872
  if (!isValidJsonSchema(parsed)) {
1836
- console.log(chalk4.yellow(`
2873
+ console.log(chalk7.yellow(`
1837
2874
  Warning: ${formatSchemaWarning("inputSchema")}
1838
2875
  `));
1839
2876
  }
@@ -1891,12 +2928,12 @@ function parseDatasetFile(rawContent, filePath) {
1891
2928
  function createPromptsCommand() {
1892
2929
  const prompts = new Command3("prompts").description("Manage prompts, datasets, evaluations, and optimizations").addHelpText("after", `
1893
2930
  Examples:
1894
- ${chalk4.dim("$")} mutagent prompts list
1895
- ${chalk4.dim("$")} mutagent prompts get <prompt-id>
1896
- ${chalk4.dim("$")} mutagent prompts create --file prompt.json
1897
- ${chalk4.dim("$")} mutagent prompts dataset list <prompt-id>
1898
- ${chalk4.dim("$")} mutagent prompts evaluation create <prompt-id> --name "My Eval"
1899
- ${chalk4.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id>
2931
+ ${chalk7.dim("$")} mutagent prompts list
2932
+ ${chalk7.dim("$")} mutagent prompts get <prompt-id>
2933
+ ${chalk7.dim("$")} mutagent prompts create --file prompt.json
2934
+ ${chalk7.dim("$")} mutagent prompts dataset list <prompt-id>
2935
+ ${chalk7.dim("$")} mutagent prompts evaluation create <prompt-id> --name "My Eval"
2936
+ ${chalk7.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id>
1900
2937
 
1901
2938
  Subcommands:
1902
2939
  list, get, create, update, delete
@@ -1906,11 +2943,11 @@ Subcommands:
1906
2943
  `);
1907
2944
  prompts.command("list").description("List all prompts").option("-l, --limit <n>", "Limit results", "50").addHelpText("after", `
1908
2945
  Examples:
1909
- ${chalk4.dim("$")} mutagent prompts list
1910
- ${chalk4.dim("$")} mutagent prompts list --limit 10
1911
- ${chalk4.dim("$")} mutagent prompts list --json
2946
+ ${chalk7.dim("$")} mutagent prompts list
2947
+ ${chalk7.dim("$")} mutagent prompts list --limit 10
2948
+ ${chalk7.dim("$")} mutagent prompts list --json
1912
2949
 
1913
- ${chalk4.dim("Tip: Use --json for machine-readable output (AI agents, CI pipelines).")}
2950
+ ${chalk7.dim("Tip: Use --json for machine-readable output (AI agents, CI pipelines).")}
1914
2951
  `).action(async (options) => {
1915
2952
  const isJson = getJsonFlag(prompts);
1916
2953
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -1941,11 +2978,11 @@ ${chalk4.dim("Tip: Use --json for machine-readable output (AI agents, CI pipelin
1941
2978
  });
1942
2979
  prompts.command("get").description("Get prompt details with nested data").argument("<id>", "Prompt ID (from: mutagent prompts list)").option("--with-datasets", "Include datasets").option("--with-evals", "Include evaluations").addHelpText("after", `
1943
2980
  Examples:
1944
- ${chalk4.dim("$")} mutagent prompts get <id>
1945
- ${chalk4.dim("$")} mutagent prompts get <id> --with-datasets --with-evals
1946
- ${chalk4.dim("$")} mutagent prompts get <id> --json
2981
+ ${chalk7.dim("$")} mutagent prompts get <id>
2982
+ ${chalk7.dim("$")} mutagent prompts get <id> --with-datasets --with-evals
2983
+ ${chalk7.dim("$")} mutagent prompts get <id> --json
1947
2984
 
1948
- ${chalk4.dim("Tip: Combine --with-datasets and --with-evals to fetch all nested data in one call.")}
2985
+ ${chalk7.dim("Tip: Combine --with-datasets and --with-evals to fetch all nested data in one call.")}
1949
2986
  `).action(async (id, options) => {
1950
2987
  const isJson = getJsonFlag(prompts);
1951
2988
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -1969,35 +3006,46 @@ ${chalk4.dim("Tip: Combine --with-datasets and --with-evals to fetch all nested
1969
3006
  handleError(error, isJson);
1970
3007
  }
1971
3008
  });
1972
- prompts.command("create").description("Create a new prompt").option("-f, --file <path>", "Create from JSON file").option("--raw-file <path>", "Create from plain text file (used as rawPrompt)").option("-n, --name <name>", "Prompt name").option("-c, --content <content>", "Prompt content (rawPrompt) [DEPRECATED: use --raw]").option("-r, --raw <text>", "Raw prompt text (single prompt)").option("--system <text>", "System prompt (use with --human)").option("--human <text>", "Human prompt (use with --system)").option("--messages <json>", `Messages array as JSON (e.g., '[{"role":"system","content":"..."}]')`).addHelpText("after", `
3009
+ prompts.command("create").description("Create a new prompt").option("-d, --data <json>", "Prompt as JSON string (recommended — curl-style inline)").option("-f, --file <path>", "Create from JSON file").option("--raw-file <path>", "Create from plain text file (used as rawPrompt)").option("-n, --name <name>", "Prompt name").option("-c, --content <content>", "Prompt content (rawPrompt) [DEPRECATED: use --raw]").option("-r, --raw <text>", "Raw prompt text (single prompt)").option("--system <text>", "System prompt (use with --human)").option("--human <text>", "Human prompt (use with --system)").option("--messages <json>", `Messages array as JSON (e.g., '[{"role":"system","content":"..."}]')`).option("--output-schema <json>", "Output schema as JSON string (required for optimization)").addHelpText("after", `
1973
3010
  Examples:
1974
- ${chalk4.dim("$")} mutagent prompts create --name "my-prompt" --system "You are helpful" --human "Hello"
1975
- ${chalk4.dim("$")} mutagent prompts create --name "raw-prompt" --raw "Summarize: {{text}}"
1976
- ${chalk4.dim("$")} mutagent prompts create --file prompt.json
1977
- ${chalk4.dim("$")} mutagent prompts create --name "chat" --messages '[{"role":"system","content":"..."}]'
1978
- ${chalk4.dim("$")} mutagent prompts create --name "from-file" --raw-file prompt.txt
3011
+ ${chalk7.dim("$")} mutagent prompts create -d '{"name":"summarizer","systemPrompt":"Summarize","humanPrompt":"{{text}}","outputSchema":{"type":"object","properties":{"summary":{"type":"string"}}}}'
3012
+ ${chalk7.dim("$")} mutagent prompts create --name "my-prompt" --system "You are helpful" --human "Hello" --output-schema '{"type":"object","properties":{"result":{"type":"string"}}}'
3013
+ ${chalk7.dim("$")} mutagent prompts create --file prompt.json
3014
+ ${chalk7.dim("$")} mutagent prompts create --name "raw-prompt" --raw "Summarize: {{text}}"
1979
3015
 
1980
- Prompt Input Methods (pick one):
3016
+ Prompt Input Methods (pick one, priority order):
3017
+ -d, --data Inline JSON object (recommended for CI/scripts)
3018
+ --file Load from JSON file (full prompt object)
3019
+ --raw-file Load plain text file as raw prompt
1981
3020
  --system/--human Structured system + user message pair
1982
3021
  --raw Single raw prompt text with {{variables}}
1983
- --raw-file Load plain text file as raw prompt
1984
3022
  --messages Full messages array as JSON
1985
- --file Load from JSON file (full prompt object)
1986
3023
 
1987
- ${chalk4.dim("Hint: Use --file with JSON or --raw-file for plain text. Get prompt IDs: mutagent prompts list")}
3024
+ ${chalk7.dim("Note: --data and --file are mutually exclusive. outputSchema is required (include in --data/--file or use --output-schema).")}
1988
3025
  `).action(async (options) => {
1989
3026
  const isJson = getJsonFlag(prompts);
1990
3027
  const output = new OutputFormatter(isJson ? "json" : "table");
1991
3028
  try {
1992
3029
  let data;
1993
- if (options.file) {
1994
- const content = readFileSync2(options.file, "utf-8");
3030
+ if (options.data && options.file) {
3031
+ throw new MutagentError("INVALID_ARGUMENTS", "Cannot use --data and --file together", "Use --data for inline JSON or --file for file-based input, not both");
3032
+ }
3033
+ if (options.data) {
3034
+ try {
3035
+ data = JSON.parse(options.data);
3036
+ } catch {
3037
+ throw new MutagentError("INVALID_JSON", "Invalid JSON in --data flag", `Provide a valid JSON object, e.g., '{"name":"my-prompt","systemPrompt":"You are helpful"}'`);
3038
+ }
3039
+ if (options.name)
3040
+ data.name = options.name;
3041
+ } else if (options.file) {
3042
+ const content = readFileSync4(options.file, "utf-8");
1995
3043
  data = JSON.parse(content);
1996
3044
  } else if (options.rawFile) {
1997
- if (!existsSync2(options.rawFile)) {
3045
+ if (!existsSync4(options.rawFile)) {
1998
3046
  throw new MutagentError("FILE_NOT_FOUND", `File not found: ${options.rawFile}`, "Check the file path and try again");
1999
3047
  }
2000
- const textContent = readFileSync2(options.rawFile, "utf-8");
3048
+ const textContent = readFileSync4(options.rawFile, "utf-8");
2001
3049
  data = {
2002
3050
  name: options.name ?? options.rawFile.replace(/^.*[\\/]/, "").replace(/\.[^.]+$/, ""),
2003
3051
  rawPrompt: textContent
@@ -2026,15 +3074,46 @@ ${chalk4.dim("Hint: Use --file with JSON or --raw-file for plain text. Get promp
2026
3074
  } else if (options.content) {
2027
3075
  data.rawPrompt = options.content;
2028
3076
  } else {
2029
- throw new MutagentError("MISSING_ARGUMENTS", "Prompt content required", "Use --raw, --raw-file, --system/--human, or --messages to specify prompt content");
3077
+ throw new MutagentError("MISSING_ARGUMENTS", "Prompt content required", "Use --data, --raw, --raw-file, --system/--human, or --messages to specify prompt content");
2030
3078
  }
2031
3079
  } else {
2032
- throw new MutagentError("MISSING_ARGUMENTS", "Either --file, --raw-file, or --name with prompt content is required", "Use --file to load from JSON, --raw-file for plain text, or provide --name with --raw, --system/--human, or --messages");
3080
+ throw new MutagentError("MISSING_ARGUMENTS", "Either --data, --file, --raw-file, or --name with prompt content is required", "Use --data for inline JSON, --file to load from JSON, --raw-file for plain text, or provide --name with --raw, --system/--human, or --messages");
2033
3081
  }
2034
3082
  const promptContent = data.rawPrompt ?? data.systemPrompt ?? data.humanPrompt ?? "";
2035
3083
  if (promptContent && !isJson) {
2036
3084
  warnSingleBraceVariables(promptContent, output);
2037
3085
  }
3086
+ if (options.outputSchema) {
3087
+ try {
3088
+ data.outputSchema = JSON.parse(options.outputSchema);
3089
+ } catch {
3090
+ throw new MutagentError("INVALID_JSON", "Invalid JSON in --output-schema flag", `Provide a valid JSON Schema, e.g., '{"type":"object","properties":{"result":{"type":"string"}}}'`);
3091
+ }
3092
+ }
3093
+ if (isSchemaEmpty(data.outputSchema)) {
3094
+ if (!isJson && process.stdin.isTTY) {
3095
+ const inquirer3 = (await import("inquirer")).default;
3096
+ output.warn("outputSchema is required for optimization. Define the expected output structure.");
3097
+ const schemaAnswer = await inquirer3.prompt([{
3098
+ type: "input",
3099
+ name: "schema",
3100
+ message: "Output schema (JSON):",
3101
+ validate: (input) => {
3102
+ if (!input.trim())
3103
+ return "outputSchema is required";
3104
+ try {
3105
+ JSON.parse(input);
3106
+ return true;
3107
+ } catch {
3108
+ return 'Invalid JSON. Example: {"type":"object","properties":{"result":{"type":"string"}}}';
3109
+ }
3110
+ }
3111
+ }]);
3112
+ data.outputSchema = JSON.parse(schemaAnswer.schema);
3113
+ } else {
3114
+ throw new MutagentError("MISSING_ARGUMENTS", "outputSchema is required for prompt creation", `Use --output-schema '{"type":"object","properties":{...}}' or include outputSchema in --data/--file`);
3115
+ }
3116
+ }
2038
3117
  if (!isJson && isSchemaEmpty(data.inputSchema)) {
2039
3118
  if (process.stdin.isTTY) {
2040
3119
  const schema = await promptForInputSchema();
@@ -2061,30 +3140,51 @@ ${chalk4.dim("Hint: Use --file with JSON or --raw-file for plain text. Get promp
2061
3140
  });
2062
3141
  console.log(hints);
2063
3142
  }
3143
+ const sourceFile = options.file ?? options.rawFile;
3144
+ if (sourceFile) {
3145
+ updateMutationContext((ctx) => {
3146
+ const preview = (data.rawPrompt ?? data.systemPrompt ?? data.name ?? "").slice(0, 50);
3147
+ ctx.addDiscoveredPrompt(sourceFile, 1, preview);
3148
+ ctx.markPromptUploaded(sourceFile, String(prompt.id), prompt.version);
3149
+ });
3150
+ }
2064
3151
  } catch (error) {
2065
3152
  handleError(error, isJson);
2066
3153
  }
2067
3154
  });
2068
- prompts.command("update").description("Update a prompt").argument("<id>", "Prompt ID (from: mutagent prompts list)").option("-f, --file <path>", "Update from JSON file").option("--raw-file <path>", "Update from plain text file (used as rawPrompt)").option("-n, --name <name>", "New name").option("-c, --content <content>", "New content (rawPrompt) [DEPRECATED: use --raw]").option("-r, --raw <text>", "Raw prompt text (single prompt)").option("--system <text>", "System prompt (use with --human)").option("--human <text>", "Human prompt (use with --system)").option("--messages <json>", `Messages array as JSON (e.g., '[{"role":"system","content":"..."}]')`).addHelpText("after", `
3155
+ prompts.command("update").description("Update a prompt").argument("<id>", "Prompt ID (from: mutagent prompts list)").option("-d, --data <json>", "Update fields as JSON string (recommended — curl-style inline)").option("-f, --file <path>", "Update from JSON file").option("--raw-file <path>", "Update from plain text file (used as rawPrompt)").option("-n, --name <name>", "New name").option("-c, --content <content>", "New content (rawPrompt) [DEPRECATED: use --raw]").option("-r, --raw <text>", "Raw prompt text (single prompt)").option("--system <text>", "System prompt (use with --human)").option("--human <text>", "Human prompt (use with --system)").option("--messages <json>", `Messages array as JSON (e.g., '[{"role":"system","content":"..."}]')`).addHelpText("after", `
2069
3156
  Examples:
2070
- ${chalk4.dim("$")} mutagent prompts update <id> --name "new-name"
2071
- ${chalk4.dim("$")} mutagent prompts update <id> --system "Updated system prompt"
2072
- ${chalk4.dim("$")} mutagent prompts update <id> --raw-file updated-prompt.txt
2073
- ${chalk4.dim("$")} mutagent prompts update <id> --file updated-prompt.json
2074
- ${chalk4.dim("$")} mutagent prompts update <id> --json
3157
+ ${chalk7.dim("$")} mutagent prompts update <id> -d '{"name":"new-name","systemPrompt":"Updated prompt"}'
3158
+ ${chalk7.dim("$")} mutagent prompts update <id> --name "new-name"
3159
+ ${chalk7.dim("$")} mutagent prompts update <id> --system "Updated system prompt"
3160
+ ${chalk7.dim("$")} mutagent prompts update <id> --raw-file updated-prompt.txt
3161
+ ${chalk7.dim("$")} mutagent prompts update <id> --file updated-prompt.json
3162
+
3163
+ ${chalk7.dim("Note: --data and --file are mutually exclusive. CLI flags (--name) override --data fields.")}
2075
3164
  `).action(async (id, options) => {
2076
3165
  const isJson = getJsonFlag(prompts);
2077
3166
  const output = new OutputFormatter(isJson ? "json" : "table");
2078
3167
  try {
2079
3168
  let data = {};
2080
- if (options.file) {
2081
- const content = readFileSync2(options.file, "utf-8");
3169
+ if (options.data && options.file) {
3170
+ throw new MutagentError("INVALID_ARGUMENTS", "Cannot use --data and --file together", "Use --data for inline JSON or --file for file-based input, not both");
3171
+ }
3172
+ if (options.data) {
3173
+ try {
3174
+ data = JSON.parse(options.data);
3175
+ } catch {
3176
+ throw new MutagentError("INVALID_JSON", "Invalid JSON in --data flag", `Provide a valid JSON object, e.g., '{"name":"new-name","systemPrompt":"Updated prompt"}'`);
3177
+ }
3178
+ if (options.name)
3179
+ data.name = options.name;
3180
+ } else if (options.file) {
3181
+ const content = readFileSync4(options.file, "utf-8");
2082
3182
  data = JSON.parse(content);
2083
3183
  } else if (options.rawFile) {
2084
- if (!existsSync2(options.rawFile)) {
3184
+ if (!existsSync4(options.rawFile)) {
2085
3185
  throw new MutagentError("FILE_NOT_FOUND", `File not found: ${options.rawFile}`, "Check the file path and try again");
2086
3186
  }
2087
- const textContent = readFileSync2(options.rawFile, "utf-8");
3187
+ const textContent = readFileSync4(options.rawFile, "utf-8");
2088
3188
  data.rawPrompt = textContent;
2089
3189
  if (options.name)
2090
3190
  data.name = options.name;
@@ -2115,7 +3215,7 @@ Examples:
2115
3215
  }
2116
3216
  }
2117
3217
  if (Object.keys(data).length === 0) {
2118
- throw new MutagentError("MISSING_ARGUMENTS", "No update data provided", "Use --file, --raw-file, --name, --raw, --system/--human, or --messages");
3218
+ throw new MutagentError("MISSING_ARGUMENTS", "No update data provided", "Use --data, --file, --raw-file, --name, --raw, --system/--human, or --messages");
2119
3219
  }
2120
3220
  const promptContent = data.rawPrompt ?? data.systemPrompt ?? data.humanPrompt ?? "";
2121
3221
  if (promptContent && !isJson) {
@@ -2136,17 +3236,23 @@ Examples:
2136
3236
  });
2137
3237
  console.log(hints);
2138
3238
  }
3239
+ const sourceFile = options.file ?? options.rawFile;
3240
+ if (sourceFile) {
3241
+ updateMutationContext((ctx) => {
3242
+ ctx.markPromptUploaded(sourceFile, String(prompt.id), prompt.version);
3243
+ });
3244
+ }
2139
3245
  } catch (error) {
2140
3246
  handleError(error, isJson);
2141
3247
  }
2142
3248
  });
2143
3249
  prompts.command("delete").description("Delete a prompt").argument("<id>", "Prompt ID (from: mutagent prompts list)").option("--force", "Skip confirmation").addHelpText("after", `
2144
3250
  Examples:
2145
- ${chalk4.dim("$")} mutagent prompts delete <id>
2146
- ${chalk4.dim("$")} mutagent prompts delete <id> --force
2147
- ${chalk4.dim("$")} mutagent prompts delete <id> --force --json
3251
+ ${chalk7.dim("$")} mutagent prompts delete <id>
3252
+ ${chalk7.dim("$")} mutagent prompts delete <id> --force
3253
+ ${chalk7.dim("$")} mutagent prompts delete <id> --force --json
2148
3254
 
2149
- ${chalk4.dim("Tip: Use --force to skip confirmation (required for non-interactive/CI usage).")}
3255
+ ${chalk7.dim("Tip: Use --force to skip confirmation (required for non-interactive/CI usage).")}
2150
3256
  `).action(async (id, options) => {
2151
3257
  const isJson = getJsonFlag(prompts);
2152
3258
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -2173,14 +3279,14 @@ ${chalk4.dim("Tip: Use --force to skip confirmation (required for non-interactiv
2173
3279
  });
2174
3280
  const dataset = prompts.command("dataset").description("Manage datasets for prompts").addHelpText("after", `
2175
3281
  Examples:
2176
- ${chalk4.dim("$")} mutagent prompts dataset list <prompt-id>
2177
- ${chalk4.dim("$")} mutagent prompts dataset add <prompt-id> --file dataset.jsonl
2178
- ${chalk4.dim("$")} mutagent prompts dataset remove <prompt-id> <dataset-id>
3282
+ ${chalk7.dim("$")} mutagent prompts dataset list <prompt-id>
3283
+ ${chalk7.dim("$")} mutagent prompts dataset add <prompt-id> --file dataset.jsonl
3284
+ ${chalk7.dim("$")} mutagent prompts dataset remove <prompt-id> <dataset-id>
2179
3285
  `);
2180
3286
  dataset.command("list").description("List datasets for a prompt").argument("<prompt-id>", "Prompt ID (from: mutagent prompts list)").addHelpText("after", `
2181
3287
  Examples:
2182
- ${chalk4.dim("$")} mutagent prompts dataset list <prompt-id>
2183
- ${chalk4.dim("$")} mutagent prompts dataset list <prompt-id> --json
3288
+ ${chalk7.dim("$")} mutagent prompts dataset list <prompt-id>
3289
+ ${chalk7.dim("$")} mutagent prompts dataset list <prompt-id> --json
2184
3290
  `).action(async (promptId) => {
2185
3291
  const isJson = getJsonFlag(prompts);
2186
3292
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -2206,21 +3312,21 @@ Examples:
2206
3312
  });
2207
3313
  dataset.command("add").description("Add dataset to a prompt").argument("<prompt-id>", "Prompt ID (from: mutagent prompts list)").option("-f, --file <path>", "Dataset file (JSON array, JSONL, or CSV)").option("-d, --data <json>", "Inline JSON array of dataset items").option("-n, --name <name>", "Dataset name (default: timestamped)").addHelpText("after", `
2208
3314
  Examples:
2209
- ${chalk4.dim("$")} mutagent prompts dataset add <prompt-id> --file dataset.json
2210
- ${chalk4.dim("$")} mutagent prompts dataset add <prompt-id> --file dataset.jsonl --name "My Dataset"
2211
- ${chalk4.dim("$")} mutagent prompts dataset add <prompt-id> --file dataset.csv
2212
- ${chalk4.dim("$")} mutagent prompts dataset add <prompt-id> -d '[{"input":{"text":"hello"},"expectedOutput":{"result":"world"}}]'
3315
+ ${chalk7.dim("$")} mutagent prompts dataset add <prompt-id> --file dataset.json
3316
+ ${chalk7.dim("$")} mutagent prompts dataset add <prompt-id> --file dataset.jsonl --name "My Dataset"
3317
+ ${chalk7.dim("$")} mutagent prompts dataset add <prompt-id> --file dataset.csv
3318
+ ${chalk7.dim("$")} mutagent prompts dataset add <prompt-id> -d '[{"input":{"text":"hello"},"expectedOutput":{"result":"world"}}]'
2213
3319
 
2214
3320
  Supported file formats:
2215
- ${chalk4.dim(".json")} JSON array of objects: [{"input": {...}, "expectedOutput": {...}}, ...]
2216
- ${chalk4.dim(".jsonl")} One JSON object per line (newline-delimited JSON)
2217
- ${chalk4.dim(".csv")} Comma-separated values with header row
3321
+ ${chalk7.dim(".json")} JSON array of objects: [{"input": {...}, "expectedOutput": {...}}, ...]
3322
+ ${chalk7.dim(".jsonl")} One JSON object per line (newline-delimited JSON)
3323
+ ${chalk7.dim(".csv")} Comma-separated values with header row
2218
3324
 
2219
3325
  Inline data format (-d):
2220
3326
  JSON array of objects, e.g.:
2221
- ${chalk4.dim('[{"input": {"text": "hello"}, "expectedOutput": {"result": "world"}}]')}
3327
+ ${chalk7.dim('[{"input": {"text": "hello"}, "expectedOutput": {"result": "world"}}]')}
2222
3328
 
2223
- ${chalk4.dim("Note: --file and -d are mutually exclusive. Provide one or the other.")}
3329
+ ${chalk7.dim("Note: --file and -d are mutually exclusive. Provide one or the other.")}
2224
3330
  `).action(async (promptId, options) => {
2225
3331
  const isJson = getJsonFlag(prompts);
2226
3332
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -2246,11 +3352,30 @@ ${chalk4.dim("Note: --file and -d are mutually exclusive. Provide one or the oth
2246
3352
  }
2247
3353
  } else {
2248
3354
  const filePath = options.file;
2249
- const rawContent = readFileSync2(filePath, "utf-8");
3355
+ const rawContent = readFileSync4(filePath, "utf-8");
2250
3356
  content = parseDatasetFile(rawContent, filePath);
2251
3357
  }
3358
+ let datasetName = options.name;
3359
+ if (!datasetName && !isJson && process.stdin.isTTY) {
3360
+ const inquirer3 = (await import("inquirer")).default;
3361
+ const defaultName = options.file ? options.file.replace(/^.*[\\/]/, "").replace(/\.[^.]+$/, "") : undefined;
3362
+ const nameAnswer = await inquirer3.prompt([{
3363
+ type: "input",
3364
+ name: "name",
3365
+ message: "Name this dataset:",
3366
+ default: defaultName,
3367
+ validate: (input) => {
3368
+ if (!input.trim())
3369
+ return "Dataset name is required";
3370
+ if (input.trim().length < 2)
3371
+ return "Dataset name must be at least 2 characters";
3372
+ return true;
3373
+ }
3374
+ }]);
3375
+ datasetName = nameAnswer.name.trim();
3376
+ }
2252
3377
  const client = getSDKClient();
2253
- const datasetResult = await client.addDataset(promptId, content, options.name);
3378
+ const datasetResult = await client.addDataset(promptId, content, datasetName);
2254
3379
  if (isJson) {
2255
3380
  output.output({
2256
3381
  ...datasetResult,
@@ -2270,14 +3395,19 @@ ${chalk4.dim("Note: --file and -d are mutually exclusive. Provide one or the oth
2270
3395
  });
2271
3396
  console.log(hints);
2272
3397
  }
3398
+ const datasetFile = options.file ?? "inline-data";
3399
+ updateMutationContext((ctx) => {
3400
+ ctx.addDiscoveredDataset(datasetFile, datasetResult.name, datasetResult.itemCount ?? 0);
3401
+ ctx.markDatasetUploaded(datasetFile, String(datasetResult.id), promptId);
3402
+ });
2273
3403
  } catch (error) {
2274
3404
  handleError(error, isJson);
2275
3405
  }
2276
3406
  });
2277
3407
  dataset.command("remove").description("Remove dataset from a prompt").argument("<prompt-id>", "Prompt ID (from: mutagent prompts list)").argument("<dataset-id>", "Dataset ID (from: mutagent prompts dataset list <prompt-id>)").addHelpText("after", `
2278
3408
  Examples:
2279
- ${chalk4.dim("$")} mutagent prompts dataset remove <prompt-id> <dataset-id>
2280
- ${chalk4.dim("$")} mutagent prompts dataset remove <prompt-id> <dataset-id> --json
3409
+ ${chalk7.dim("$")} mutagent prompts dataset remove <prompt-id> <dataset-id>
3410
+ ${chalk7.dim("$")} mutagent prompts dataset remove <prompt-id> <dataset-id> --json
2281
3411
  `).action(async (promptId, datasetId) => {
2282
3412
  const isJson = getJsonFlag(prompts);
2283
3413
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -2291,14 +3421,14 @@ Examples:
2291
3421
  });
2292
3422
  const evaluation = prompts.command("evaluation").description("Manage evaluations for prompts").addHelpText("after", `
2293
3423
  Examples:
2294
- ${chalk4.dim("$")} mutagent prompts evaluation list <prompt-id>
2295
- ${chalk4.dim("$")} mutagent prompts evaluation create <prompt-id> --name "My Eval"
2296
- ${chalk4.dim("$")} mutagent prompts evaluation results <run-id>
3424
+ ${chalk7.dim("$")} mutagent prompts evaluation list <prompt-id>
3425
+ ${chalk7.dim("$")} mutagent prompts evaluation create <prompt-id> --name "My Eval"
3426
+ ${chalk7.dim("$")} mutagent prompts evaluation results <run-id>
2297
3427
  `);
2298
3428
  evaluation.command("list").description("List evaluations for a prompt").argument("<prompt-id>", "Prompt ID (from: mutagent prompts list)").addHelpText("after", `
2299
3429
  Examples:
2300
- ${chalk4.dim("$")} mutagent prompts evaluation list <prompt-id>
2301
- ${chalk4.dim("$")} mutagent prompts evaluation list <prompt-id> --json
3430
+ ${chalk7.dim("$")} mutagent prompts evaluation list <prompt-id>
3431
+ ${chalk7.dim("$")} mutagent prompts evaluation list <prompt-id> --json
2302
3432
  `).action(async (promptId) => {
2303
3433
  const isJson = getJsonFlag(prompts);
2304
3434
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -2322,30 +3452,85 @@ Examples:
2322
3452
  handleError(error, isJson);
2323
3453
  }
2324
3454
  });
2325
- evaluation.command("create").description("Create an evaluation configuration for a prompt").argument("<prompt-id>", "Prompt ID (from: mutagent prompts list)").requiredOption("-n, --name <name>", "Evaluation name").option("-f, --file <path>", "Load evaluation criteria from JSON file").option("--description <text>", "Evaluation description").option("-d, --dataset <id>", "Dataset ID to associate (from: mutagent prompts dataset list)").addHelpText("after", `
3455
+ evaluation.command("create").description("Create an evaluation configuration for a prompt").argument("<prompt-id>", "Prompt ID (from: mutagent prompts list)").option("-d, --data <json>", "Evaluation as JSON string (recommended — curl-style inline)").option("-n, --name <name>", "Evaluation name (required unless --guided)").option("-f, --file <path>", "Load evaluation criteria from JSON file").option("--description <text>", "Evaluation description").option("--dataset <id>", "Dataset ID to associate (from: mutagent prompts dataset list)").option("--guided", "Interactive guided mode — build criteria step by step").addHelpText("after", `
2326
3456
  Examples:
2327
- ${chalk4.dim("$")} mutagent prompts evaluation create <prompt-id> --name "Accuracy Check"
2328
- ${chalk4.dim("$")} mutagent prompts evaluation create <prompt-id> --name "Full Eval" --file criteria.json --dataset <dataset-id>
2329
- ${chalk4.dim("$")} mutagent prompts evaluation create <prompt-id> --name "QA" --description "Quality assurance eval" --json
2330
-
2331
- Criteria file format (--file):
2332
- ${chalk4.dim('{ "evalConfig": { "criteria": [...] }, "llmConfig": { "model": "gpt-4" } }')}
2333
-
2334
- ${chalk4.dim("AI Agent Hint: Create an evaluation before running it. Use --file to load criteria from JSON.")}
2335
- ${chalk4.dim("Get prompt IDs: mutagent prompts list | Get dataset IDs: mutagent prompts dataset list <prompt-id>")}
3457
+ ${chalk7.dim("$")} mutagent prompts evaluation create <prompt-id> --guided
3458
+ ${chalk7.dim("$")} mutagent prompts evaluation create <prompt-id> --data '{"name":"Accuracy","evalConfig":{"criteria":[...]}}' --name "Accuracy"
3459
+ ${chalk7.dim("$")} mutagent prompts evaluation create <prompt-id> --name "Accuracy Check"
3460
+ ${chalk7.dim("$")} mutagent prompts evaluation create <prompt-id> --name "Full Eval" --file criteria.json --dataset <dataset-id>
3461
+ ${chalk7.dim("$")} mutagent prompts evaluation create <prompt-id> --name "QA" --description "Quality assurance eval" --json
3462
+
3463
+ Criteria file format (--file or --data):
3464
+ ${chalk7.dim('{ "name": "...", "evalConfig": { "criteria": [...] }, "llmConfig": { "model": "gpt-4" } }')}
3465
+
3466
+ ${chalk7.dim("Note: --data and --file are mutually exclusive. CLI flags (--name, --description) override --data fields.")}
3467
+ ${chalk7.dim("Tip: Use --guided for an interactive walkthrough of criteria creation.")}
3468
+ ${chalk7.dim("Get prompt IDs: mutagent prompts list | Get dataset IDs: mutagent prompts dataset list <prompt-id>")}
2336
3469
  `).action(async (promptId, options) => {
2337
3470
  const isJson = getJsonFlag(prompts);
2338
3471
  const output = new OutputFormatter(isJson ? "json" : "table");
2339
3472
  try {
3473
+ if (options.guided) {
3474
+ if (!process.stdin.isTTY || isJson) {
3475
+ throw new MutagentError("INTERACTIVE_REQUIRED", "--guided requires an interactive terminal", "Remove --guided for non-interactive usage, or use --data/--file to provide criteria");
3476
+ }
3477
+ const guidedResult = await runGuidedEvalCreator(promptId);
3478
+ if (!guidedResult) {
3479
+ return;
3480
+ }
3481
+ const client2 = getSDKClient();
3482
+ const evalResult2 = await client2.createEvaluation(promptId, {
3483
+ name: guidedResult.name,
3484
+ description: guidedResult.description,
3485
+ evalConfig: guidedResult.evalConfig,
3486
+ datasetId: options.dataset ? parseInt(options.dataset, 10) : undefined
3487
+ });
3488
+ output.success(`Created evaluation: ${evalResult2.name} (id: ${String(evalResult2.id)})`);
3489
+ const hints = formatCreationHints({
3490
+ resourceType: "Evaluation",
3491
+ id: evalResult2.id,
3492
+ name: evalResult2.name,
3493
+ dashboardUrl: evaluationLink(promptId, evalResult2.id),
3494
+ apiPath: `/api/prompts/${promptId}/evaluations/${String(evalResult2.id)}`
3495
+ });
3496
+ console.log(hints);
3497
+ const criteriaCount2 = guidedResult.evalConfig.criteria.length;
3498
+ updateMutationContext((ctx) => {
3499
+ ctx.addEvaluation(evalResult2.name, criteriaCount2, String(evalResult2.id), promptId);
3500
+ });
3501
+ return;
3502
+ }
3503
+ if (!options.name) {
3504
+ throw new MutagentError("MISSING_ARGUMENTS", "Evaluation name is required", "Use --name <name> or --guided for interactive mode");
3505
+ }
3506
+ if (options.data && options.file) {
3507
+ throw new MutagentError("INVALID_ARGUMENTS", "Cannot use --data and --file together", "Use --data for inline JSON or --file for file-based input, not both");
3508
+ }
2340
3509
  const evalData = {
2341
3510
  name: options.name,
2342
3511
  description: options.description
2343
3512
  };
2344
- if (options.file) {
2345
- if (!existsSync2(options.file)) {
3513
+ if (options.data) {
3514
+ try {
3515
+ const parsed = JSON.parse(options.data);
3516
+ if (parsed.evalConfig)
3517
+ evalData.evalConfig = parsed.evalConfig;
3518
+ if (parsed.llmConfig)
3519
+ evalData.llmConfig = parsed.llmConfig;
3520
+ if (parsed.tags)
3521
+ evalData.tags = parsed.tags;
3522
+ if (parsed.metadata)
3523
+ evalData.metadata = parsed.metadata;
3524
+ if (parsed.datasetId)
3525
+ evalData.datasetId = parsed.datasetId;
3526
+ } catch {
3527
+ throw new MutagentError("INVALID_JSON", "Invalid JSON in --data flag", `Provide a valid JSON object, e.g., '{"evalConfig":{"criteria":[...]},"llmConfig":{"model":"gpt-4"}}'`);
3528
+ }
3529
+ } else if (options.file) {
3530
+ if (!existsSync4(options.file)) {
2346
3531
  throw new MutagentError("FILE_NOT_FOUND", `File not found: ${options.file}`, "Check the file path and try again");
2347
3532
  }
2348
- const fileContent = readFileSync2(options.file, "utf-8");
3533
+ const fileContent = readFileSync4(options.file, "utf-8");
2349
3534
  try {
2350
3535
  const parsed = JSON.parse(fileContent);
2351
3536
  if (parsed.evalConfig)
@@ -2360,6 +3545,10 @@ ${chalk4.dim("Get prompt IDs: mutagent prompts list | Get dataset IDs: mutagent
2360
3545
  throw new MutagentError("INVALID_JSON", `Failed to parse criteria file: ${options.file}`, "Ensure the file contains valid JSON with evalConfig and/or llmConfig");
2361
3546
  }
2362
3547
  }
3548
+ if (options.name)
3549
+ evalData.name = options.name;
3550
+ if (options.description)
3551
+ evalData.description = options.description;
2363
3552
  if (options.dataset) {
2364
3553
  evalData.datasetId = parseInt(options.dataset, 10);
2365
3554
  if (isNaN(evalData.datasetId)) {
@@ -2384,14 +3573,18 @@ ${chalk4.dim("Get prompt IDs: mutagent prompts list | Get dataset IDs: mutagent
2384
3573
  });
2385
3574
  console.log(hints);
2386
3575
  }
3576
+ const criteriaCount = evalData.evalConfig?.criteria?.length ?? 0;
3577
+ updateMutationContext((ctx) => {
3578
+ ctx.addEvaluation(evalResult.name, criteriaCount, String(evalResult.id), promptId);
3579
+ });
2387
3580
  } catch (error) {
2388
3581
  handleError(error, isJson);
2389
3582
  }
2390
3583
  });
2391
3584
  evaluation.command("results").description("Get evaluation results").argument("<run-id>", "Evaluation run ID (from: mutagent prompts evaluation list <prompt-id>)").addHelpText("after", `
2392
3585
  Examples:
2393
- ${chalk4.dim("$")} mutagent prompts evaluation results <run-id>
2394
- ${chalk4.dim("$")} mutagent prompts evaluation results <run-id> --json
3586
+ ${chalk7.dim("$")} mutagent prompts evaluation results <run-id>
3587
+ ${chalk7.dim("$")} mutagent prompts evaluation results <run-id> --json
2395
3588
  `).action(async (runId) => {
2396
3589
  const isJson = getJsonFlag(prompts);
2397
3590
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -2405,21 +3598,21 @@ Examples:
2405
3598
  });
2406
3599
  const optimize = prompts.command("optimize").description("Manage prompt optimization jobs").addHelpText("after", `
2407
3600
  Examples:
2408
- ${chalk4.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id>
2409
- ${chalk4.dim("$")} mutagent prompts optimize status <job-id>
2410
- ${chalk4.dim("$")} mutagent prompts optimize results <job-id>
3601
+ ${chalk7.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id>
3602
+ ${chalk7.dim("$")} mutagent prompts optimize status <job-id>
3603
+ ${chalk7.dim("$")} mutagent prompts optimize results <job-id>
2411
3604
 
2412
3605
  Workflow: start -> status (poll) -> results
2413
3606
  `);
2414
3607
  optimize.command("start").description("Start prompt optimization").argument("<prompt-id>", "Prompt ID (from: mutagent prompts list)").requiredOption("-d, --dataset <id>", "Dataset ID for optimization (from: mutagent prompts dataset list <prompt-id>)").option("--max-iterations <n>", "Max optimization iterations (default: 3)").option("--target-score <n>", "Target accuracy 0-1 (e.g., 0.9)").option("--patience <n>", "Iterations without improvement before stopping").option("--model <model-id>", 'Target LLM model (e.g., "claude-sonnet-4-5-20250929")').option("--eval-model <model-id>", "Evaluation model (defaults to target model)").addHelpText("after", `
2415
3608
  Examples:
2416
- ${chalk4.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id>
2417
- ${chalk4.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id> --max-iterations 5
2418
- ${chalk4.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id> --target-score 0.95 --model claude-sonnet-4-5-20250929
2419
- ${chalk4.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id> --json
3609
+ ${chalk7.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id>
3610
+ ${chalk7.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id> --max-iterations 5
3611
+ ${chalk7.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id> --target-score 0.95 --model claude-sonnet-4-5-20250929
3612
+ ${chalk7.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id> --json
2420
3613
  ${PREREQUISITES_TEXT}
2421
3614
 
2422
- ${chalk4.dim("Monitor progress with: mutagent prompts optimize status <job-id>")}
3615
+ ${chalk7.dim("Monitor progress with: mutagent prompts optimize status <job-id>")}
2423
3616
  `).action(async (promptId, options) => {
2424
3617
  const isJson = getJsonFlag(prompts);
2425
3618
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -2454,9 +3647,9 @@ ${chalk4.dim("Monitor progress with: mutagent prompts optimize status <job-id>")
2454
3647
  if (error instanceof ApiError) {
2455
3648
  const messages = parseValidationErrors(error);
2456
3649
  if (!isJson) {
2457
- console.error(chalk4.red("Optimization failed. Missing requirements:"));
3650
+ console.error(chalk7.red("Optimization failed. Missing requirements:"));
2458
3651
  for (const msg of messages) {
2459
- console.error(chalk4.red(` - ${msg}`));
3652
+ console.error(chalk7.red(` - ${msg}`));
2460
3653
  }
2461
3654
  console.error("");
2462
3655
  console.error(PREREQUISITES_TEXT);
@@ -2467,8 +3660,8 @@ ${chalk4.dim("Monitor progress with: mutagent prompts optimize status <job-id>")
2467
3660
  });
2468
3661
  optimize.command("status").description("Check optimization status").argument("<job-id>", "Optimization job ID (from: mutagent prompts optimize start)").addHelpText("after", `
2469
3662
  Examples:
2470
- ${chalk4.dim("$")} mutagent prompts optimize status <job-id>
2471
- ${chalk4.dim("$")} mutagent prompts optimize status <job-id> --json
3663
+ ${chalk7.dim("$")} mutagent prompts optimize status <job-id>
3664
+ ${chalk7.dim("$")} mutagent prompts optimize status <job-id> --json
2472
3665
  `).action(async (jobId) => {
2473
3666
  const isJson = getJsonFlag(prompts);
2474
3667
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -2491,19 +3684,59 @@ Examples:
2491
3684
  });
2492
3685
  optimize.command("results").description("Get optimization results").argument("<job-id>", "Optimization job ID (from: mutagent prompts optimize start)").addHelpText("after", `
2493
3686
  Examples:
2494
- ${chalk4.dim("$")} mutagent prompts optimize results <job-id>
2495
- ${chalk4.dim("$")} mutagent prompts optimize results <job-id> --json
3687
+ ${chalk7.dim("$")} mutagent prompts optimize results <job-id>
3688
+ ${chalk7.dim("$")} mutagent prompts optimize results <job-id> --json
2496
3689
  `).action(async (jobId) => {
2497
3690
  const isJson = getJsonFlag(prompts);
2498
3691
  const output = new OutputFormatter(isJson ? "json" : "table");
2499
3692
  try {
2500
3693
  const client = getSDKClient();
2501
3694
  const results = await client.getOptimizationResults(jobId);
3695
+ const resultData = results;
2502
3696
  if (isJson) {
2503
- output.output({ ...results, _links: { optimizer: optimizerLink(jobId) } });
3697
+ output.output({ ...resultData, _links: { optimizer: optimizerLink(jobId) } });
2504
3698
  } else {
2505
- output.output(results);
2506
- output.info(`View: ${optimizerLink(jobId)}`);
3699
+ renderScorecard(resultData);
3700
+ const jobData = resultData.job;
3701
+ const isCompleted = jobData?.status === "completed";
3702
+ if (isCompleted && process.stdin.isTTY) {
3703
+ let showDetails = true;
3704
+ while (showDetails) {
3705
+ const { action } = await promptScorecardAction();
3706
+ if (action === "details") {
3707
+ const original = resultData.originalPrompt;
3708
+ const optimized = resultData.prompt;
3709
+ showPromptDiff(original?.systemPrompt ?? original?.rawPrompt ?? null, optimized?.systemPrompt ?? optimized?.rawPrompt ?? null);
3710
+ continue;
3711
+ }
3712
+ if (action === "apply") {
3713
+ const optimizedPrompt = resultData.prompt;
3714
+ const promptIdStr = String(jobData.promptId);
3715
+ if (optimizedPrompt && promptIdStr) {
3716
+ output.info("Applying optimized prompt...");
3717
+ const updateData = {};
3718
+ if (optimizedPrompt.systemPrompt)
3719
+ updateData.systemPrompt = optimizedPrompt.systemPrompt;
3720
+ if (optimizedPrompt.humanPrompt)
3721
+ updateData.humanPrompt = optimizedPrompt.humanPrompt;
3722
+ if (optimizedPrompt.rawPrompt)
3723
+ updateData.rawPrompt = optimizedPrompt.rawPrompt;
3724
+ await client.updatePrompt(promptIdStr, updateData);
3725
+ output.success("Optimized prompt applied as new version!");
3726
+ updateMutationContext((ctx) => {
3727
+ ctx.markPromptUploaded(`optimization:${jobId}`, promptIdStr, "optimized");
3728
+ });
3729
+ }
3730
+ } else {
3731
+ output.info("Kept original prompt. No changes applied.");
3732
+ }
3733
+ showDetails = false;
3734
+ }
3735
+ } else if (!isCompleted) {
3736
+ const statusStr = jobData?.status ?? "unknown";
3737
+ output.info(`Job status: ${statusStr}. Results may be partial.`);
3738
+ output.info(`View: ${optimizerLink(jobId)}`);
3739
+ }
2507
3740
  }
2508
3741
  } catch (error) {
2509
3742
  handleError(error, isJson);
@@ -2513,26 +3746,28 @@ Examples:
2513
3746
  }
2514
3747
 
2515
3748
  // src/commands/traces.ts
3749
+ init_sdk_client();
2516
3750
  import { Command as Command4 } from "commander";
2517
- import chalk5 from "chalk";
3751
+ import chalk8 from "chalk";
3752
+ init_errors();
2518
3753
  function createTracesCommand() {
2519
3754
  const traces = new Command4("traces").description("View and analyze traces (replaces Langfuse)").addHelpText("after", `
2520
3755
  Examples:
2521
- ${chalk5.dim("$")} mutagent traces list
2522
- ${chalk5.dim("$")} mutagent traces list --prompt <prompt-id>
2523
- ${chalk5.dim("$")} mutagent traces get <trace-id>
2524
- ${chalk5.dim("$")} mutagent traces analyze <prompt-id>
2525
- ${chalk5.dim("$")} mutagent traces export --format json --output traces.json
3756
+ ${chalk8.dim("$")} mutagent traces list
3757
+ ${chalk8.dim("$")} mutagent traces list --prompt <prompt-id>
3758
+ ${chalk8.dim("$")} mutagent traces get <trace-id>
3759
+ ${chalk8.dim("$")} mutagent traces analyze <prompt-id>
3760
+ ${chalk8.dim("$")} mutagent traces export --format json --output traces.json
2526
3761
 
2527
3762
  Note: MutagenT traces replace Langfuse for observability.
2528
3763
  `);
2529
3764
  traces.command("list").description("List traces").option("-p, --prompt <id>", "Filter by prompt ID").option("-l, --limit <n>", "Limit results", "50").addHelpText("after", `
2530
3765
  Examples:
2531
- ${chalk5.dim("$")} mutagent traces list
2532
- ${chalk5.dim("$")} mutagent traces list --prompt <prompt-id>
2533
- ${chalk5.dim("$")} mutagent traces list --limit 10 --json
3766
+ ${chalk8.dim("$")} mutagent traces list
3767
+ ${chalk8.dim("$")} mutagent traces list --prompt <prompt-id>
3768
+ ${chalk8.dim("$")} mutagent traces list --limit 10 --json
2534
3769
 
2535
- ${chalk5.dim("Tip: Filter by prompt to see traces for a specific prompt version.")}
3770
+ ${chalk8.dim("Tip: Filter by prompt to see traces for a specific prompt version.")}
2536
3771
  `).action(async (options) => {
2537
3772
  const isJson = getJsonFlag(traces);
2538
3773
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -2566,10 +3801,10 @@ ${chalk5.dim("Tip: Filter by prompt to see traces for a specific prompt version.
2566
3801
  });
2567
3802
  traces.command("get").description("Get trace details").argument("<id>", "Trace ID").addHelpText("after", `
2568
3803
  Examples:
2569
- ${chalk5.dim("$")} mutagent traces get <trace-id>
2570
- ${chalk5.dim("$")} mutagent traces get <trace-id> --json
3804
+ ${chalk8.dim("$")} mutagent traces get <trace-id>
3805
+ ${chalk8.dim("$")} mutagent traces get <trace-id> --json
2571
3806
 
2572
- ${chalk5.dim("Returns full trace details including spans, tokens, and latency.")}
3807
+ ${chalk8.dim("Returns full trace details including spans, tokens, and latency.")}
2573
3808
  `).action(async (id) => {
2574
3809
  const isJson = getJsonFlag(traces);
2575
3810
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -2588,10 +3823,10 @@ ${chalk5.dim("Returns full trace details including spans, tokens, and latency.")
2588
3823
  });
2589
3824
  traces.command("analyze").description("Analyze traces for a prompt").argument("<prompt-id>", "Prompt ID").addHelpText("after", `
2590
3825
  Examples:
2591
- ${chalk5.dim("$")} mutagent traces analyze <prompt-id>
2592
- ${chalk5.dim("$")} mutagent traces analyze <prompt-id> --json
3826
+ ${chalk8.dim("$")} mutagent traces analyze <prompt-id>
3827
+ ${chalk8.dim("$")} mutagent traces analyze <prompt-id> --json
2593
3828
 
2594
- ${chalk5.dim("Aggregates trace data for a prompt: avg latency, token usage, error rates.")}
3829
+ ${chalk8.dim("Aggregates trace data for a prompt: avg latency, token usage, error rates.")}
2595
3830
  `).action(async (promptId) => {
2596
3831
  const isJson = getJsonFlag(traces);
2597
3832
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -2609,12 +3844,12 @@ ${chalk5.dim("Aggregates trace data for a prompt: avg latency, token usage, erro
2609
3844
  });
2610
3845
  traces.command("export").description("Export traces").option("-p, --prompt <id>", "Filter by prompt ID").option("-f, --format <format>", "Export format (json, csv)", "json").option("-o, --output <path>", "Output file path").addHelpText("after", `
2611
3846
  Examples:
2612
- ${chalk5.dim("$")} mutagent traces export
2613
- ${chalk5.dim("$")} mutagent traces export --format json --output traces.json
2614
- ${chalk5.dim("$")} mutagent traces export --format csv --output traces.csv
2615
- ${chalk5.dim("$")} mutagent traces export --prompt <prompt-id> --format json
3847
+ ${chalk8.dim("$")} mutagent traces export
3848
+ ${chalk8.dim("$")} mutagent traces export --format json --output traces.json
3849
+ ${chalk8.dim("$")} mutagent traces export --format csv --output traces.csv
3850
+ ${chalk8.dim("$")} mutagent traces export --prompt <prompt-id> --format json
2616
3851
 
2617
- ${chalk5.dim("Exports to stdout by default. Use --output to save to a file.")}
3852
+ ${chalk8.dim("Exports to stdout by default. Use --output to save to a file.")}
2618
3853
  `).action(async (options) => {
2619
3854
  const isJson = getJsonFlag(traces);
2620
3855
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -2642,8 +3877,8 @@ ${chalk5.dim("Exports to stdout by default. Use --output to save to a file.")}
2642
3877
  throw new Error(`Unsupported format: ${options.format}`);
2643
3878
  }
2644
3879
  if (options.output) {
2645
- const { writeFileSync: writeFileSync2 } = await import("fs");
2646
- writeFileSync2(options.output, content);
3880
+ const { writeFileSync: writeFileSync3 } = await import("fs");
3881
+ writeFileSync3(options.output, content);
2647
3882
  output.success(`Exported ${String(tracesList.length)} traces to ${options.output}`);
2648
3883
  } else {
2649
3884
  process.stdout.write(content);
@@ -2656,13 +3891,15 @@ ${chalk5.dim("Exports to stdout by default. Use --output to save to a file.")}
2656
3891
  }
2657
3892
 
2658
3893
  // src/commands/integrate.ts
3894
+ init_config();
2659
3895
  import { Command as Command5 } from "commander";
2660
- import chalk6 from "chalk";
2661
- import { writeFileSync as writeFileSync2, existsSync as existsSync9 } from "fs";
3896
+ import chalk9 from "chalk";
3897
+ import { writeFileSync as writeFileSync3, existsSync as existsSync11 } from "fs";
2662
3898
  import { execSync } from "child_process";
3899
+ init_errors();
2663
3900
 
2664
3901
  // src/lib/integrations/mastra.ts
2665
- import { readFileSync as readFileSync3, existsSync as existsSync3 } from "fs";
3902
+ import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
2666
3903
  function renderPrerequisites(config) {
2667
3904
  const keyPreview = config.apiKey.slice(0, 8) + "..." + config.apiKey.slice(-4);
2668
3905
  return `✓ MUTAGENT_API_KEY: ${keyPreview}
@@ -2676,14 +3913,14 @@ var mastraIntegration = {
2676
3913
  const files = ["mastra.config.ts", "mastra.config.js"];
2677
3914
  const found = [];
2678
3915
  for (const file of files) {
2679
- if (existsSync3(file)) {
3916
+ if (existsSync5(file)) {
2680
3917
  found.push(file);
2681
3918
  }
2682
3919
  }
2683
3920
  let hasMastraDep = false;
2684
- if (existsSync3("package.json")) {
3921
+ if (existsSync5("package.json")) {
2685
3922
  try {
2686
- const pkg = JSON.parse(readFileSync3("package.json", "utf-8"));
3923
+ const pkg = JSON.parse(readFileSync5("package.json", "utf-8"));
2687
3924
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
2688
3925
  hasMastraDep = "@mastra/core" in deps;
2689
3926
  } catch {}
@@ -2858,15 +4095,15 @@ mutagent traces analyze <prompt-id>
2858
4095
  };
2859
4096
 
2860
4097
  // src/lib/integrations/langchain.ts
2861
- import { readFileSync as readFileSync4, existsSync as existsSync4 } from "fs";
4098
+ import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
2862
4099
  var langchainIntegration = {
2863
4100
  name: "langchain",
2864
4101
  description: "LangChain framework",
2865
4102
  async detect() {
2866
4103
  let hasLangchain = false;
2867
- if (existsSync4("package.json")) {
4104
+ if (existsSync6("package.json")) {
2868
4105
  try {
2869
- const pkg = JSON.parse(readFileSync4("package.json", "utf-8"));
4106
+ const pkg = JSON.parse(readFileSync6("package.json", "utf-8"));
2870
4107
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
2871
4108
  hasLangchain = "langchain" in deps || "@langchain/core" in deps;
2872
4109
  } catch {}
@@ -2998,15 +4235,15 @@ mutagent traces analyze <prompt-id>
2998
4235
  };
2999
4236
 
3000
4237
  // src/lib/integrations/langgraph.ts
3001
- import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
4238
+ import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
3002
4239
  var langgraphIntegration = {
3003
4240
  name: "langgraph",
3004
4241
  description: "LangGraph agent workflow framework",
3005
4242
  async detect() {
3006
4243
  let hasLanggraph = false;
3007
- if (existsSync5("package.json")) {
4244
+ if (existsSync7("package.json")) {
3008
4245
  try {
3009
- const pkg = JSON.parse(readFileSync5("package.json", "utf-8"));
4246
+ const pkg = JSON.parse(readFileSync7("package.json", "utf-8"));
3010
4247
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
3011
4248
  hasLanggraph = "@langchain/langgraph" in deps;
3012
4249
  } catch {}
@@ -3124,15 +4361,15 @@ mutagent traces analyze <node-prompt-id>
3124
4361
  };
3125
4362
 
3126
4363
  // src/lib/integrations/vercel-ai.ts
3127
- import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
4364
+ import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
3128
4365
  var vercelAiIntegration = {
3129
4366
  name: "vercel-ai",
3130
4367
  description: "Vercel AI SDK",
3131
4368
  async detect() {
3132
4369
  let hasAiSdk = false;
3133
- if (existsSync6("package.json")) {
4370
+ if (existsSync8("package.json")) {
3134
4371
  try {
3135
- const pkg = JSON.parse(readFileSync6("package.json", "utf-8"));
4372
+ const pkg = JSON.parse(readFileSync8("package.json", "utf-8"));
3136
4373
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
3137
4374
  hasAiSdk = "ai" in deps;
3138
4375
  } catch {}
@@ -3245,15 +4482,15 @@ mutagent traces export --prompt <prompt-id> --format json
3245
4482
  };
3246
4483
 
3247
4484
  // src/lib/integrations/openai.ts
3248
- import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
4485
+ import { readFileSync as readFileSync9, existsSync as existsSync9 } from "fs";
3249
4486
  var openaiIntegration = {
3250
4487
  name: "openai",
3251
4488
  description: "OpenAI SDK integration with automatic tracing",
3252
4489
  async detect() {
3253
4490
  let hasOpenAI = false;
3254
- if (existsSync7("package.json")) {
4491
+ if (existsSync9("package.json")) {
3255
4492
  try {
3256
- const pkg = JSON.parse(readFileSync7("package.json", "utf-8"));
4493
+ const pkg = JSON.parse(readFileSync9("package.json", "utf-8"));
3257
4494
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
3258
4495
  hasOpenAI = "openai" in deps;
3259
4496
  } catch {}
@@ -3383,15 +4620,15 @@ mutagent traces export --format json
3383
4620
  };
3384
4621
 
3385
4622
  // src/lib/integrations/claude-code.ts
3386
- import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
4623
+ import { readFileSync as readFileSync10, existsSync as existsSync10 } from "fs";
3387
4624
  var claudeCodeIntegration = {
3388
4625
  name: "claude-code",
3389
4626
  description: "Claude Code SDK",
3390
4627
  async detect() {
3391
4628
  let hasClaudeCode = false;
3392
- if (existsSync8("package.json")) {
4629
+ if (existsSync10("package.json")) {
3393
4630
  try {
3394
- const pkg = JSON.parse(readFileSync8("package.json", "utf-8"));
4631
+ const pkg = JSON.parse(readFileSync10("package.json", "utf-8"));
3395
4632
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
3396
4633
  hasClaudeCode = "@anthropic-ai/claude-code" in deps || "@anthropic-ai/sdk" in deps;
3397
4634
  } catch {}
@@ -3703,16 +4940,16 @@ function getFrameworkMetadata(name) {
3703
4940
 
3704
4941
  // src/commands/integrate.ts
3705
4942
  function detectPackageManager() {
3706
- if (existsSync9("bun.lockb") || existsSync9("bun.lock")) {
4943
+ if (existsSync11("bun.lockb") || existsSync11("bun.lock")) {
3707
4944
  return "bun";
3708
4945
  }
3709
- if (existsSync9("pnpm-lock.yaml")) {
4946
+ if (existsSync11("pnpm-lock.yaml")) {
3710
4947
  return "pnpm";
3711
4948
  }
3712
- if (existsSync9("yarn.lock")) {
4949
+ if (existsSync11("yarn.lock")) {
3713
4950
  return "yarn";
3714
4951
  }
3715
- if (existsSync9("package-lock.json")) {
4952
+ if (existsSync11("package-lock.json")) {
3716
4953
  return "npm";
3717
4954
  }
3718
4955
  try {
@@ -3762,12 +4999,12 @@ AI AGENT: Please determine the framework by:
3762
4999
  function createIntegrateCommand() {
3763
5000
  const integrate = new Command5("integrate").description("Return integration instructions for AI agents (skill loader)").addHelpText("after", `
3764
5001
  Examples:
3765
- ${chalk6.dim("$")} mutagent integrate # Return exploration instructions for AI agents
3766
- ${chalk6.dim("$")} mutagent integrate langchain # Return @mutagent/langchain integration steps
3767
- ${chalk6.dim("$")} mutagent integrate openai # Return @mutagent/openai integration steps
3768
- ${chalk6.dim("$")} mutagent integrate vercel-ai --verify # Verify integration
3769
- ${chalk6.dim("$")} mutagent integrate langchain --output ./INTEGRATION.md
3770
- ${chalk6.dim("$")} mutagent integrate --list # List available frameworks
5002
+ ${chalk9.dim("$")} mutagent integrate # Return exploration instructions for AI agents
5003
+ ${chalk9.dim("$")} mutagent integrate langchain # Return @mutagent/langchain integration steps
5004
+ ${chalk9.dim("$")} mutagent integrate openai # Return @mutagent/openai integration steps
5005
+ ${chalk9.dim("$")} mutagent integrate vercel-ai --verify # Verify integration
5006
+ ${chalk9.dim("$")} mutagent integrate langchain --output ./INTEGRATION.md
5007
+ ${chalk9.dim("$")} mutagent integrate --list # List available frameworks
3771
5008
 
3772
5009
  Frameworks: mastra, langchain, langgraph, vercel-ai, openai, claude-code, generic
3773
5010
 
@@ -3786,7 +5023,7 @@ It returns INSTRUCTIONS that AI agents execute - it does NOT auto-install packag
3786
5023
  if (!frameworkArg) {
3787
5024
  const explorationInstructions = generateExplorationInstructions();
3788
5025
  if (options.output) {
3789
- writeFileSync2(options.output, explorationInstructions);
5026
+ writeFileSync3(options.output, explorationInstructions);
3790
5027
  output.success(`Exploration instructions saved to ${options.output}`);
3791
5028
  } else if (options.raw === true || isJson) {
3792
5029
  process.stdout.write(explorationInstructions);
@@ -3834,7 +5071,7 @@ export MUTAGENT_API_KEY=${apiKey.substring(0, 12)}...
3834
5071
  AI AGENT: Execute these steps using Bash for install, Write/Edit for code changes.
3835
5072
  `;
3836
5073
  if (options.output) {
3837
- writeFileSync2(options.output, instructions);
5074
+ writeFileSync3(options.output, instructions);
3838
5075
  output.success(`Integration instructions saved to ${options.output}`);
3839
5076
  } else if (options.raw === true || isJson) {
3840
5077
  process.stdout.write(instructions);
@@ -3869,23 +5106,25 @@ AI AGENT: Execute these steps using Bash for install, Write/Edit for code change
3869
5106
  }
3870
5107
 
3871
5108
  // src/commands/agents.ts
5109
+ init_sdk_client();
3872
5110
  import { Command as Command6 } from "commander";
3873
- import chalk7 from "chalk";
3874
- import { readFileSync as readFileSync9 } from "fs";
5111
+ import chalk10 from "chalk";
5112
+ import { readFileSync as readFileSync11 } from "fs";
5113
+ init_errors();
3875
5114
  function createAgentsCommand() {
3876
5115
  const agents = new Command6("agents").description("Manage AI agents").addHelpText("after", `
3877
5116
  Examples:
3878
- ${chalk7.dim("$")} mutagent agents list
3879
- ${chalk7.dim("$")} mutagent agents get <agent-id>
3880
- ${chalk7.dim("$")} mutagent agents create --file agent.json
3881
- ${chalk7.dim("$")} mutagent agents create --name "Code Reviewer" --slug code-reviewer --system-prompt "You are a code reviewer..."
3882
- ${chalk7.dim("$")} mutagent agents update <agent-id> --name "Updated Name"
3883
- ${chalk7.dim("$")} mutagent agents delete <agent-id> --force
3884
- ${chalk7.dim("$")} mutagent agents conversations list <agent-id>
3885
- ${chalk7.dim("$")} mutagent agents conversations get <agent-id> <conversation-id>
3886
- ${chalk7.dim("$")} mutagent agents conversations create <agent-id>
3887
- ${chalk7.dim("$")} mutagent agents conversations delete <agent-id> <conversation-id>
3888
- ${chalk7.dim("$")} mutagent agents conversations messages <agent-id> <conversation-id>
5117
+ ${chalk10.dim("$")} mutagent agents list
5118
+ ${chalk10.dim("$")} mutagent agents get <agent-id>
5119
+ ${chalk10.dim("$")} mutagent agents create --file agent.json
5120
+ ${chalk10.dim("$")} mutagent agents create --name "Code Reviewer" --slug code-reviewer --system-prompt "You are a code reviewer..."
5121
+ ${chalk10.dim("$")} mutagent agents update <agent-id> --name "Updated Name"
5122
+ ${chalk10.dim("$")} mutagent agents delete <agent-id> --force
5123
+ ${chalk10.dim("$")} mutagent agents conversations list <agent-id>
5124
+ ${chalk10.dim("$")} mutagent agents conversations get <agent-id> <conversation-id>
5125
+ ${chalk10.dim("$")} mutagent agents conversations create <agent-id>
5126
+ ${chalk10.dim("$")} mutagent agents conversations delete <agent-id> <conversation-id>
5127
+ ${chalk10.dim("$")} mutagent agents conversations messages <agent-id> <conversation-id>
3889
5128
 
3890
5129
  Subcommands:
3891
5130
  list, get, create, update, delete
@@ -3893,9 +5132,9 @@ Subcommands:
3893
5132
  `);
3894
5133
  agents.command("list").description("List all agents").option("-l, --limit <n>", "Limit results", "50").option("-o, --offset <n>", "Offset for pagination").option("-n, --name <name>", "Filter by name").option("-s, --status <status>", "Filter by status (active, paused, archived)").addHelpText("after", `
3895
5134
  Examples:
3896
- ${chalk7.dim("$")} mutagent agents list
3897
- ${chalk7.dim("$")} mutagent agents list --status active
3898
- ${chalk7.dim("$")} mutagent agents list --name "reviewer" --json
5135
+ ${chalk10.dim("$")} mutagent agents list
5136
+ ${chalk10.dim("$")} mutagent agents list --status active
5137
+ ${chalk10.dim("$")} mutagent agents list --name "reviewer" --json
3899
5138
  `).action(async (options) => {
3900
5139
  const isJson = getJsonFlag(agents);
3901
5140
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -3915,7 +5154,11 @@ Examples:
3915
5154
  }
3916
5155
  const result = await client.listAgents(filters);
3917
5156
  if (isJson) {
3918
- output.output(result);
5157
+ const withLinks = result.data.map((a) => ({
5158
+ ...a,
5159
+ _links: agentLinks(a.id)
5160
+ }));
5161
+ output.output({ ...result, data: withLinks });
3919
5162
  } else {
3920
5163
  const formatted = result.data.map((a) => ({
3921
5164
  id: a.id,
@@ -3924,7 +5167,8 @@ Examples:
3924
5167
  model: a.model,
3925
5168
  status: a.status,
3926
5169
  isPublic: a.isPublic ? "Yes" : "No",
3927
- updated: a.updatedAt ? new Date(a.updatedAt).toLocaleDateString() : "N/A"
5170
+ updated: a.updatedAt ? new Date(a.updatedAt).toLocaleDateString() : "N/A",
5171
+ url: agentLink(a.id)
3928
5172
  }));
3929
5173
  output.output(formatted);
3930
5174
  }
@@ -3934,8 +5178,8 @@ Examples:
3934
5178
  });
3935
5179
  agents.command("get").description("Get agent details").argument("<id>", "Agent ID").addHelpText("after", `
3936
5180
  Examples:
3937
- ${chalk7.dim("$")} mutagent agents get <agent-id>
3938
- ${chalk7.dim("$")} mutagent agents get <agent-id> --json
5181
+ ${chalk10.dim("$")} mutagent agents get <agent-id>
5182
+ ${chalk10.dim("$")} mutagent agents get <agent-id> --json
3939
5183
  `).action(async (id) => {
3940
5184
  const isJson = getJsonFlag(agents);
3941
5185
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -3943,7 +5187,7 @@ Examples:
3943
5187
  const client = getSDKClient();
3944
5188
  const agent = await client.getAgent(id);
3945
5189
  if (isJson) {
3946
- output.output(agent);
5190
+ output.output({ ...agent, _links: agentLinks(agent.id) });
3947
5191
  } else {
3948
5192
  const formatted = {
3949
5193
  id: agent.id,
@@ -3960,15 +5204,16 @@ Examples:
3960
5204
  tags: agent.tags?.join(", ") ?? "None",
3961
5205
  createdBy: agent.createdBy ?? "N/A",
3962
5206
  createdAt: agent.createdAt ? new Date(agent.createdAt).toLocaleString() : "N/A",
3963
- updatedAt: agent.updatedAt ? new Date(agent.updatedAt).toLocaleString() : "N/A"
5207
+ updatedAt: agent.updatedAt ? new Date(agent.updatedAt).toLocaleString() : "N/A",
5208
+ url: agentLink(agent.id)
3964
5209
  };
3965
5210
  output.output(formatted);
3966
5211
  if (agent.systemPrompt) {
3967
- console.log(chalk7.bold(`
5212
+ console.log(chalk10.bold(`
3968
5213
  System Prompt:`));
3969
- console.log(chalk7.gray("─".repeat(60)));
5214
+ console.log(chalk10.gray("─".repeat(60)));
3970
5215
  console.log(agent.systemPrompt);
3971
- console.log(chalk7.gray("─".repeat(60)));
5216
+ console.log(chalk10.gray("─".repeat(60)));
3972
5217
  }
3973
5218
  }
3974
5219
  } catch (error) {
@@ -3977,18 +5222,18 @@ System Prompt:`));
3977
5222
  });
3978
5223
  agents.command("create").description("Create a new agent").option("-f, --file <path>", "Create from JSON file").option("-n, --name <name>", "Agent name").option("-s, --slug <slug>", "Agent slug (URL-friendly identifier)").option("-p, --system-prompt <prompt>", "System prompt").option("-m, --model <model>", "Model (claude-sonnet-4-5, claude-opus-4-5, claude-haiku-4-5)").option("-d, --description <description>", "Agent description").addHelpText("after", `
3979
5224
  Examples:
3980
- ${chalk7.dim("$")} mutagent agents create --name "Code Reviewer" --slug code-reviewer --system-prompt "Review code for bugs"
3981
- ${chalk7.dim("$")} mutagent agents create --file agent.json
3982
- ${chalk7.dim("$")} mutagent agents create --name "Helper" --slug helper --system-prompt "..." --model claude-sonnet-4-5 --json
5225
+ ${chalk10.dim("$")} mutagent agents create --name "Code Reviewer" --slug code-reviewer --system-prompt "Review code for bugs"
5226
+ ${chalk10.dim("$")} mutagent agents create --file agent.json
5227
+ ${chalk10.dim("$")} mutagent agents create --name "Helper" --slug helper --system-prompt "..." --model claude-sonnet-4-5 --json
3983
5228
 
3984
- ${chalk7.dim("Required: --name, --slug, and --system-prompt (or --file).")}
5229
+ ${chalk10.dim("Required: --name, --slug, and --system-prompt (or --file).")}
3985
5230
  `).action(async (options) => {
3986
5231
  const isJson = getJsonFlag(agents);
3987
5232
  const output = new OutputFormatter(isJson ? "json" : "table");
3988
5233
  try {
3989
5234
  let data;
3990
5235
  if (options.file) {
3991
- const content = readFileSync9(options.file, "utf-8");
5236
+ const content = readFileSync11(options.file, "utf-8");
3992
5237
  data = JSON.parse(content);
3993
5238
  } else if (options.name && options.slug && options.systemPrompt) {
3994
5239
  data = {
@@ -4013,16 +5258,16 @@ ${chalk7.dim("Required: --name, --slug, and --system-prompt (or --file).")}
4013
5258
  });
4014
5259
  agents.command("update").description("Update an agent").argument("<id>", "Agent ID").option("-f, --file <path>", "Update from JSON file").option("-n, --name <name>", "New name").option("-p, --system-prompt <prompt>", "New system prompt").option("-m, --model <model>", "New model").option("-d, --description <description>", "New description").option("-s, --status <status>", "New status (active, paused, archived)").addHelpText("after", `
4015
5260
  Examples:
4016
- ${chalk7.dim("$")} mutagent agents update <id> --name "New Name"
4017
- ${chalk7.dim("$")} mutagent agents update <id> --status paused
4018
- ${chalk7.dim("$")} mutagent agents update <id> --file updated-agent.json --json
5261
+ ${chalk10.dim("$")} mutagent agents update <id> --name "New Name"
5262
+ ${chalk10.dim("$")} mutagent agents update <id> --status paused
5263
+ ${chalk10.dim("$")} mutagent agents update <id> --file updated-agent.json --json
4019
5264
  `).action(async (id, options) => {
4020
5265
  const isJson = getJsonFlag(agents);
4021
5266
  const output = new OutputFormatter(isJson ? "json" : "table");
4022
5267
  try {
4023
5268
  let data = {};
4024
5269
  if (options.file) {
4025
- const content = readFileSync9(options.file, "utf-8");
5270
+ const content = readFileSync11(options.file, "utf-8");
4026
5271
  data = JSON.parse(content);
4027
5272
  } else {
4028
5273
  if (options.name)
@@ -4049,11 +5294,11 @@ Examples:
4049
5294
  });
4050
5295
  agents.command("delete").description("Delete an agent").argument("<id>", "Agent ID").option("--force", "Skip confirmation").addHelpText("after", `
4051
5296
  Examples:
4052
- ${chalk7.dim("$")} mutagent agents delete <id>
4053
- ${chalk7.dim("$")} mutagent agents delete <id> --force
4054
- ${chalk7.dim("$")} mutagent agents delete <id> --force --json
5297
+ ${chalk10.dim("$")} mutagent agents delete <id>
5298
+ ${chalk10.dim("$")} mutagent agents delete <id> --force
5299
+ ${chalk10.dim("$")} mutagent agents delete <id> --force --json
4055
5300
 
4056
- ${chalk7.dim("Tip: Use --force to skip confirmation (required for non-interactive/CI usage).")}
5301
+ ${chalk10.dim("Tip: Use --force to skip confirmation (required for non-interactive/CI usage).")}
4057
5302
  `).action(async (id, options) => {
4058
5303
  const isJson = getJsonFlag(agents);
4059
5304
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4080,14 +5325,14 @@ ${chalk7.dim("Tip: Use --force to skip confirmation (required for non-interactiv
4080
5325
  });
4081
5326
  const conversations = agents.command("conversations").description("Manage conversations for agents").addHelpText("after", `
4082
5327
  Examples:
4083
- ${chalk7.dim("$")} mutagent agents conversations list <agent-id>
4084
- ${chalk7.dim("$")} mutagent agents conversations create <agent-id>
4085
- ${chalk7.dim("$")} mutagent agents conversations messages <agent-id> <conversation-id>
5328
+ ${chalk10.dim("$")} mutagent agents conversations list <agent-id>
5329
+ ${chalk10.dim("$")} mutagent agents conversations create <agent-id>
5330
+ ${chalk10.dim("$")} mutagent agents conversations messages <agent-id> <conversation-id>
4086
5331
  `);
4087
5332
  conversations.command("list").description("List conversations for an agent").argument("<agent-id>", "Agent ID").option("-l, --limit <n>", "Limit results", "50").option("-o, --offset <n>", "Offset for pagination").addHelpText("after", `
4088
5333
  Examples:
4089
- ${chalk7.dim("$")} mutagent agents conversations list <agent-id>
4090
- ${chalk7.dim("$")} mutagent agents conversations list <agent-id> --limit 10 --json
5334
+ ${chalk10.dim("$")} mutagent agents conversations list <agent-id>
5335
+ ${chalk10.dim("$")} mutagent agents conversations list <agent-id> --limit 10 --json
4091
5336
  `).action(async (agentId, options) => {
4092
5337
  const isJson = getJsonFlag(agents);
4093
5338
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4119,8 +5364,8 @@ Examples:
4119
5364
  });
4120
5365
  conversations.command("get").description("Get conversation details").argument("<agent-id>", "Agent ID").argument("<conversation-id>", "Conversation ID").addHelpText("after", `
4121
5366
  Examples:
4122
- ${chalk7.dim("$")} mutagent agents conversations get <agent-id> <conversation-id>
4123
- ${chalk7.dim("$")} mutagent agents conversations get <agent-id> <conversation-id> --json
5367
+ ${chalk10.dim("$")} mutagent agents conversations get <agent-id> <conversation-id>
5368
+ ${chalk10.dim("$")} mutagent agents conversations get <agent-id> <conversation-id> --json
4124
5369
  `).action(async (agentId, conversationId) => {
4125
5370
  const isJson = getJsonFlag(agents);
4126
5371
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4147,8 +5392,8 @@ Examples:
4147
5392
  });
4148
5393
  conversations.command("create").description("Start a new conversation with an agent").argument("<agent-id>", "Agent ID").option("-t, --title <title>", "Conversation title").addHelpText("after", `
4149
5394
  Examples:
4150
- ${chalk7.dim("$")} mutagent agents conversations create <agent-id>
4151
- ${chalk7.dim("$")} mutagent agents conversations create <agent-id> --title "Debug session" --json
5395
+ ${chalk10.dim("$")} mutagent agents conversations create <agent-id>
5396
+ ${chalk10.dim("$")} mutagent agents conversations create <agent-id> --title "Debug session" --json
4152
5397
  `).action(async (agentId, options) => {
4153
5398
  const isJson = getJsonFlag(agents);
4154
5399
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4167,8 +5412,8 @@ Examples:
4167
5412
  });
4168
5413
  conversations.command("delete").description("Delete a conversation").argument("<agent-id>", "Agent ID").argument("<conversation-id>", "Conversation ID").option("--force", "Skip confirmation").addHelpText("after", `
4169
5414
  Examples:
4170
- ${chalk7.dim("$")} mutagent agents conversations delete <agent-id> <conversation-id>
4171
- ${chalk7.dim("$")} mutagent agents conversations delete <agent-id> <conversation-id> --force --json
5415
+ ${chalk10.dim("$")} mutagent agents conversations delete <agent-id> <conversation-id>
5416
+ ${chalk10.dim("$")} mutagent agents conversations delete <agent-id> <conversation-id> --force --json
4172
5417
  `).action(async (agentId, conversationId, options) => {
4173
5418
  const isJson = getJsonFlag(agents);
4174
5419
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4195,8 +5440,8 @@ Examples:
4195
5440
  });
4196
5441
  conversations.command("messages").description("List messages in a conversation").argument("<agent-id>", "Agent ID").argument("<conversation-id>", "Conversation ID").option("-l, --limit <n>", "Limit results", "50").option("-o, --offset <n>", "Offset for pagination").addHelpText("after", `
4197
5442
  Examples:
4198
- ${chalk7.dim("$")} mutagent agents conversations messages <agent-id> <conversation-id>
4199
- ${chalk7.dim("$")} mutagent agents conversations messages <agent-id> <conversation-id> --limit 20 --json
5443
+ ${chalk10.dim("$")} mutagent agents conversations messages <agent-id> <conversation-id>
5444
+ ${chalk10.dim("$")} mutagent agents conversations messages <agent-id> <conversation-id> --limit 20 --json
4200
5445
  `).action(async (agentId, conversationId, options) => {
4201
5446
  const isJson = getJsonFlag(agents);
4202
5447
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4229,20 +5474,21 @@ Examples:
4229
5474
  }
4230
5475
 
4231
5476
  // src/commands/config.ts
5477
+ init_config();
4232
5478
  import { Command as Command7 } from "commander";
4233
- import chalk8 from "chalk";
5479
+ import chalk11 from "chalk";
4234
5480
  function createConfigCommand() {
4235
5481
  const config = new Command7("config").description("Manage CLI configuration").addHelpText("after", `
4236
5482
  Examples:
4237
- ${chalk8.dim("$")} mutagent config list
4238
- ${chalk8.dim("$")} mutagent config get endpoint
4239
- ${chalk8.dim("$")} mutagent config set workspace <workspace-id>
4240
- ${chalk8.dim("$")} mutagent config set org <org-id>
5483
+ ${chalk11.dim("$")} mutagent config list
5484
+ ${chalk11.dim("$")} mutagent config get endpoint
5485
+ ${chalk11.dim("$")} mutagent config set workspace <workspace-id>
5486
+ ${chalk11.dim("$")} mutagent config set org <org-id>
4241
5487
  `);
4242
5488
  config.command("list").description("List all configuration").addHelpText("after", `
4243
5489
  Examples:
4244
- ${chalk8.dim("$")} mutagent config list
4245
- ${chalk8.dim("$")} mutagent config list --json
5490
+ ${chalk11.dim("$")} mutagent config list
5491
+ ${chalk11.dim("$")} mutagent config list --json
4246
5492
  `).action(() => {
4247
5493
  const isJson = getJsonFlag(config);
4248
5494
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4255,11 +5501,11 @@ Examples:
4255
5501
  });
4256
5502
  config.command("get").description("Get configuration value").argument("<key>", "Configuration key (apiKey, endpoint, format, timeout, defaultWorkspace, defaultOrganization)").addHelpText("after", `
4257
5503
  Examples:
4258
- ${chalk8.dim("$")} mutagent config get endpoint
4259
- ${chalk8.dim("$")} mutagent config get defaultWorkspace
4260
- ${chalk8.dim("$")} mutagent config get apiKey --json
5504
+ ${chalk11.dim("$")} mutagent config get endpoint
5505
+ ${chalk11.dim("$")} mutagent config get defaultWorkspace
5506
+ ${chalk11.dim("$")} mutagent config get apiKey --json
4261
5507
 
4262
- ${chalk8.dim("Keys: apiKey, endpoint, format, timeout, defaultWorkspace, defaultOrganization")}
5508
+ ${chalk11.dim("Keys: apiKey, endpoint, format, timeout, defaultWorkspace, defaultOrganization")}
4263
5509
  `).action((key) => {
4264
5510
  const isJson = getJsonFlag(config);
4265
5511
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4280,9 +5526,9 @@ ${chalk8.dim("Keys: apiKey, endpoint, format, timeout, defaultWorkspace, default
4280
5526
  const set = new Command7("set").description("Set configuration value");
4281
5527
  set.command("workspace").description("Set default workspace ID").argument("<id>", "Workspace ID to set as default").addHelpText("after", `
4282
5528
  Examples:
4283
- ${chalk8.dim("$")} mutagent config set workspace <workspace-id>
5529
+ ${chalk11.dim("$")} mutagent config set workspace <workspace-id>
4284
5530
 
4285
- ${chalk8.dim("Persists workspace ID so you don't need to pass headers on every request.")}
5531
+ ${chalk11.dim("Persists workspace ID so you don't need to pass headers on every request.")}
4286
5532
  `).action((id) => {
4287
5533
  const isJson = getJsonFlag(config);
4288
5534
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4295,9 +5541,9 @@ ${chalk8.dim("Persists workspace ID so you don't need to pass headers on every r
4295
5541
  });
4296
5542
  set.command("org").description("Set default organization ID").argument("<id>", "Organization ID to set as default").addHelpText("after", `
4297
5543
  Examples:
4298
- ${chalk8.dim("$")} mutagent config set org <org-id>
5544
+ ${chalk11.dim("$")} mutagent config set org <org-id>
4299
5545
 
4300
- ${chalk8.dim("Persists organization ID for org-scoped API keys.")}
5546
+ ${chalk11.dim("Persists organization ID for org-scoped API keys.")}
4301
5547
  `).action((id) => {
4302
5548
  const isJson = getJsonFlag(config);
4303
5549
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4313,9 +5559,11 @@ ${chalk8.dim("Persists organization ID for org-scoped API keys.")}
4313
5559
  }
4314
5560
 
4315
5561
  // src/commands/playground.ts
5562
+ init_sdk_client();
4316
5563
  import { Command as Command8 } from "commander";
4317
- import chalk9 from "chalk";
4318
- import { readFileSync as readFileSync10 } from "fs";
5564
+ import chalk12 from "chalk";
5565
+ import { readFileSync as readFileSync12 } from "fs";
5566
+ init_errors();
4319
5567
  function parseSSELine(line) {
4320
5568
  if (!line || line.startsWith(":")) {
4321
5569
  return null;
@@ -4341,12 +5589,12 @@ function parsePromptStreamEvent(data) {
4341
5589
  function createPlaygroundCommand() {
4342
5590
  const playground = new Command8("playground").description("Execute and test prompts interactively").addHelpText("after", `
4343
5591
  Examples:
4344
- ${chalk9.dim("$")} mutagent playground run <prompt-id> --input '{"name": "John"}'
4345
- ${chalk9.dim("$")} mutagent playground run <prompt-id> --file input.json
4346
- ${chalk9.dim("$")} mutagent playground run <prompt-id> --input '{}' --stream
4347
- ${chalk9.dim("$")} mutagent playground run <prompt-id> -i '{}' --model gpt-4-turbo
4348
- ${chalk9.dim("$")} mutagent playground run <prompt-id> --system "You are helpful" --human "Hello"
4349
- ${chalk9.dim("$")} mutagent playground run <prompt-id> --messages '[{"role":"user","content":"Hi"}]'
5592
+ ${chalk12.dim("$")} mutagent playground run <prompt-id> --input '{"name": "John"}'
5593
+ ${chalk12.dim("$")} mutagent playground run <prompt-id> --file input.json
5594
+ ${chalk12.dim("$")} mutagent playground run <prompt-id> --input '{}' --stream
5595
+ ${chalk12.dim("$")} mutagent playground run <prompt-id> -i '{}' --model gpt-4-turbo
5596
+ ${chalk12.dim("$")} mutagent playground run <prompt-id> --system "You are helpful" --human "Hello"
5597
+ ${chalk12.dim("$")} mutagent playground run <prompt-id> --messages '[{"role":"user","content":"Hi"}]'
4350
5598
 
4351
5599
  Input Format:
4352
5600
  The input must be a valid JSON object matching the prompt's input schema.
@@ -4362,10 +5610,10 @@ Streaming:
4362
5610
  `);
4363
5611
  playground.command("run").description("Execute a prompt with input variables").argument("<prompt-id>", "Prompt ID to execute (from: mutagent prompts list)").option("-i, --input <json>", "Input variables as JSON").option("-f, --file <path>", "Input from JSON file").option("-s, --stream", "Stream the response").option("-m, --model <model>", "Override model").option("--system <text>", "Set system prompt text").option("--human <text>", "Set human/user message text").option("--messages <json>", "Pass full messages array as JSON string").addHelpText("after", `
4364
5612
  Examples:
4365
- ${chalk9.dim("$")} mutagent playground run <prompt-id> --input '{"name": "John"}'
4366
- ${chalk9.dim("$")} mutagent playground run <prompt-id> --file input.json --stream
4367
- ${chalk9.dim("$")} mutagent playground run <prompt-id> --system "You are helpful" --human "Hello"
4368
- ${chalk9.dim("$")} mutagent playground run <prompt-id> --input '{}' --model gpt-4-turbo --json
5613
+ ${chalk12.dim("$")} mutagent playground run <prompt-id> --input '{"name": "John"}'
5614
+ ${chalk12.dim("$")} mutagent playground run <prompt-id> --file input.json --stream
5615
+ ${chalk12.dim("$")} mutagent playground run <prompt-id> --system "You are helpful" --human "Hello"
5616
+ ${chalk12.dim("$")} mutagent playground run <prompt-id> --input '{}' --model gpt-4-turbo --json
4369
5617
 
4370
5618
  Input Methods (pick one):
4371
5619
  --input '{"key":"value"}' Inline JSON variables
@@ -4373,7 +5621,7 @@ Input Methods (pick one):
4373
5621
  --system/--human Quick system + user message
4374
5622
  --messages '[...]' Full messages array
4375
5623
 
4376
- ${chalk9.dim(`Hint: Test before evaluating: mutagent playground run <id> --input '{"key":"value"}'`)}
5624
+ ${chalk12.dim(`Hint: Test before evaluating: mutagent playground run <id> --input '{"key":"value"}'`)}
4377
5625
  `).action(async (promptId, options) => {
4378
5626
  const isJson = getJsonFlag(playground);
4379
5627
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4395,21 +5643,21 @@ ${chalk9.dim(`Hint: Test before evaluating: mutagent playground run <id> --input
4395
5643
  }
4396
5644
  });
4397
5645
  } else {
4398
- console.log(chalk9.bold(`
5646
+ console.log(chalk12.bold(`
4399
5647
  Execution Result:`));
4400
- console.log(chalk9.gray("─".repeat(50)));
4401
- console.log(chalk9.cyan("Output:"));
5648
+ console.log(chalk12.gray("─".repeat(50)));
5649
+ console.log(chalk12.cyan("Output:"));
4402
5650
  console.log(result.output);
4403
- console.log(chalk9.gray("─".repeat(50)));
4404
- console.log(chalk9.dim(`Model: ${result.model}`));
4405
- console.log(chalk9.dim(`Execution Time: ${String(result.executionTimeMs)}ms`));
5651
+ console.log(chalk12.gray("─".repeat(50)));
5652
+ console.log(chalk12.dim(`Model: ${result.model}`));
5653
+ console.log(chalk12.dim(`Execution Time: ${String(result.executionTimeMs)}ms`));
4406
5654
  if (result.tokens) {
4407
- console.log(chalk9.dim(`Tokens: ${String(result.tokens.prompt)} prompt + ${String(result.tokens.completion)} completion = ${String(result.tokens.total)} total`));
5655
+ console.log(chalk12.dim(`Tokens: ${String(result.tokens.prompt)} prompt + ${String(result.tokens.completion)} completion = ${String(result.tokens.total)} total`));
4408
5656
  }
4409
5657
  if (result.cost !== undefined) {
4410
- console.log(chalk9.dim(`Cost: $${result.cost.toFixed(6)}`));
5658
+ console.log(chalk12.dim(`Cost: $${result.cost.toFixed(6)}`));
4411
5659
  }
4412
- console.log(chalk9.dim(`Playground: ${playgroundLink()}`));
5660
+ console.log(chalk12.dim(`Playground: ${playgroundLink()}`));
4413
5661
  console.log();
4414
5662
  }
4415
5663
  }
@@ -4476,7 +5724,7 @@ function parsePromptStyleInput(options) {
4476
5724
  function getInputJson(options) {
4477
5725
  if (options.file) {
4478
5726
  try {
4479
- return readFileSync10(options.file, "utf-8");
5727
+ return readFileSync12(options.file, "utf-8");
4480
5728
  } catch (err) {
4481
5729
  throw new MutagentError("FILE_READ_ERROR", `Failed to read input file: ${options.file}`, err instanceof Error ? err.message : "Check the file path and permissions");
4482
5730
  }
@@ -4509,9 +5757,9 @@ async function executeStreaming(client, promptId, input, model, isJson, output)
4509
5757
  const decoder = new TextDecoder;
4510
5758
  let buffer = "";
4511
5759
  if (!isJson) {
4512
- console.log(chalk9.bold(`
5760
+ console.log(chalk12.bold(`
4513
5761
  Streaming Output:`));
4514
- console.log(chalk9.gray("─".repeat(50)));
5762
+ console.log(chalk12.gray("─".repeat(50)));
4515
5763
  }
4516
5764
  try {
4517
5765
  for (;; ) {
@@ -4550,15 +5798,15 @@ Streaming Output:`));
4550
5798
  console.log(JSON.stringify({ type: "complete", result: event.result }));
4551
5799
  } else {
4552
5800
  console.log();
4553
- console.log(chalk9.gray("─".repeat(50)));
5801
+ console.log(chalk12.gray("─".repeat(50)));
4554
5802
  if (event.result) {
4555
- console.log(chalk9.dim(`Model: ${event.result.model}`));
4556
- console.log(chalk9.dim(`Execution Time: ${String(event.result.executionTimeMs)}ms`));
5803
+ console.log(chalk12.dim(`Model: ${event.result.model}`));
5804
+ console.log(chalk12.dim(`Execution Time: ${String(event.result.executionTimeMs)}ms`));
4557
5805
  if (event.result.tokens) {
4558
- console.log(chalk9.dim(`Tokens: ${String(event.result.tokens.prompt)} prompt + ${String(event.result.tokens.completion)} completion = ${String(event.result.tokens.total)} total`));
5806
+ console.log(chalk12.dim(`Tokens: ${String(event.result.tokens.prompt)} prompt + ${String(event.result.tokens.completion)} completion = ${String(event.result.tokens.total)} total`));
4559
5807
  }
4560
5808
  if (event.result.cost !== undefined) {
4561
- console.log(chalk9.dim(`Cost: $${event.result.cost.toFixed(6)}`));
5809
+ console.log(chalk12.dim(`Cost: $${event.result.cost.toFixed(6)}`));
4562
5810
  }
4563
5811
  }
4564
5812
  console.log();
@@ -4581,13 +5829,15 @@ Streaming Output:`));
4581
5829
  }
4582
5830
 
4583
5831
  // src/commands/workspaces.ts
5832
+ init_sdk_client();
4584
5833
  import { Command as Command9 } from "commander";
4585
- import chalk10 from "chalk";
5834
+ import chalk13 from "chalk";
5835
+ init_errors();
4586
5836
  function createWorkspacesCommand() {
4587
5837
  const workspaces = new Command9("workspaces").description("View workspaces (read-only)").addHelpText("after", `
4588
5838
  Examples:
4589
- ${chalk10.dim("$")} mutagent workspaces list
4590
- ${chalk10.dim("$")} mutagent workspaces get <workspace-id>
5839
+ ${chalk13.dim("$")} mutagent workspaces list
5840
+ ${chalk13.dim("$")} mutagent workspaces get <workspace-id>
4591
5841
 
4592
5842
  Subcommands:
4593
5843
  list, get
@@ -4596,8 +5846,8 @@ Note: Workspace management (create, update, delete) is available in the Admin Pa
4596
5846
  `);
4597
5847
  workspaces.command("list").description("List all workspaces").option("-l, --limit <n>", "Limit results", "50").option("-o, --offset <n>", "Offset for pagination").addHelpText("after", `
4598
5848
  Examples:
4599
- ${chalk10.dim("$")} mutagent workspaces list
4600
- ${chalk10.dim("$")} mutagent workspaces list --limit 10 --json
5849
+ ${chalk13.dim("$")} mutagent workspaces list
5850
+ ${chalk13.dim("$")} mutagent workspaces list --limit 10 --json
4601
5851
  `).action(async (options) => {
4602
5852
  const isJson = getJsonFlag(workspaces);
4603
5853
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4611,14 +5861,19 @@ Examples:
4611
5861
  }
4612
5862
  const result = await client.listWorkspaces(filters);
4613
5863
  if (isJson) {
4614
- output.output(result);
5864
+ const withLinks = result.data.map((w) => ({
5865
+ ...w,
5866
+ _links: workspaceLinks(w.id)
5867
+ }));
5868
+ output.output({ ...result, data: withLinks });
4615
5869
  } else {
4616
5870
  const formatted = result.data.map((w) => ({
4617
5871
  id: w.id,
4618
5872
  name: w.name,
4619
5873
  slug: w.slug,
4620
5874
  isDefault: w.isDefault ? "Yes" : "No",
4621
- updated: w.updatedAt ? new Date(w.updatedAt).toLocaleDateString() : "N/A"
5875
+ updated: w.updatedAt ? new Date(w.updatedAt).toLocaleDateString() : "N/A",
5876
+ url: workspaceLink(w.id)
4622
5877
  }));
4623
5878
  output.output(formatted);
4624
5879
  }
@@ -4628,8 +5883,8 @@ Examples:
4628
5883
  });
4629
5884
  workspaces.command("get").description("Get workspace details").argument("<id>", "Workspace ID").addHelpText("after", `
4630
5885
  Examples:
4631
- ${chalk10.dim("$")} mutagent workspaces get <workspace-id>
4632
- ${chalk10.dim("$")} mutagent workspaces get <workspace-id> --json
5886
+ ${chalk13.dim("$")} mutagent workspaces get <workspace-id>
5887
+ ${chalk13.dim("$")} mutagent workspaces get <workspace-id> --json
4633
5888
  `).action(async (id) => {
4634
5889
  const isJson = getJsonFlag(workspaces);
4635
5890
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4637,7 +5892,7 @@ Examples:
4637
5892
  const client = getSDKClient();
4638
5893
  const workspace = await client.getWorkspace(id);
4639
5894
  if (isJson) {
4640
- output.output(workspace);
5895
+ output.output({ ...workspace, _links: workspaceLinks(workspace.id) });
4641
5896
  } else {
4642
5897
  const formatted = {
4643
5898
  id: workspace.id,
@@ -4647,7 +5902,8 @@ Examples:
4647
5902
  isDefault: workspace.isDefault ? "Yes" : "No",
4648
5903
  createdBy: workspace.createdBy ?? "N/A",
4649
5904
  createdAt: workspace.createdAt ? new Date(workspace.createdAt).toLocaleString() : "N/A",
4650
- updatedAt: workspace.updatedAt ? new Date(workspace.updatedAt).toLocaleString() : "N/A"
5905
+ updatedAt: workspace.updatedAt ? new Date(workspace.updatedAt).toLocaleString() : "N/A",
5906
+ url: workspaceLink(workspace.id)
4651
5907
  };
4652
5908
  output.output(formatted);
4653
5909
  }
@@ -4659,8 +5915,10 @@ Examples:
4659
5915
  }
4660
5916
 
4661
5917
  // src/commands/providers.ts
5918
+ init_sdk_client();
4662
5919
  import { Command as Command10 } from "commander";
4663
- import chalk11 from "chalk";
5920
+ import chalk14 from "chalk";
5921
+ init_errors();
4664
5922
  var VALID_PROVIDER_TYPES = [
4665
5923
  "openai",
4666
5924
  "anthropic",
@@ -4683,9 +5941,9 @@ function validateProviderType(type) {
4683
5941
  function createProvidersCommand() {
4684
5942
  const providers = new Command10("providers").description("View LLM providers (read-only)").addHelpText("after", `
4685
5943
  Examples:
4686
- ${chalk11.dim("$")} mutagent providers list
4687
- ${chalk11.dim("$")} mutagent providers get <provider-id>
4688
- ${chalk11.dim("$")} mutagent providers test <provider-id>
5944
+ ${chalk14.dim("$")} mutagent providers list
5945
+ ${chalk14.dim("$")} mutagent providers get <provider-id>
5946
+ ${chalk14.dim("$")} mutagent providers test <provider-id>
4689
5947
 
4690
5948
  Provider Types:
4691
5949
  openai, anthropic, google, azure, bedrock, cohere, mistral, groq, together, replicate, custom
@@ -4697,9 +5955,9 @@ Note: Provider management (create, update, delete) is available in the Admin Pan
4697
5955
  `);
4698
5956
  providers.command("list").description("List all providers").option("-l, --limit <n>", "Limit results", "50").option("-o, --offset <n>", "Offset for pagination").option("-t, --type <type>", "Filter by provider type").addHelpText("after", `
4699
5957
  Examples:
4700
- ${chalk11.dim("$")} mutagent providers list
4701
- ${chalk11.dim("$")} mutagent providers list --type openai
4702
- ${chalk11.dim("$")} mutagent providers list --json
5958
+ ${chalk14.dim("$")} mutagent providers list
5959
+ ${chalk14.dim("$")} mutagent providers list --type openai
5960
+ ${chalk14.dim("$")} mutagent providers list --json
4703
5961
  `).action(async (options) => {
4704
5962
  const isJson = getJsonFlag(providers);
4705
5963
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4716,7 +5974,11 @@ Examples:
4716
5974
  }
4717
5975
  const result = await client.listProviders(filters);
4718
5976
  if (isJson) {
4719
- output.output(result);
5977
+ const withLinks = result.data.map((p) => ({
5978
+ ...p,
5979
+ _links: providerLinks(p.id)
5980
+ }));
5981
+ output.output({ ...result, data: withLinks });
4720
5982
  } else {
4721
5983
  if (result.data.length === 0) {
4722
5984
  output.info("No providers configured.");
@@ -4728,7 +5990,8 @@ Examples:
4728
5990
  type: p.type,
4729
5991
  baseUrl: p.baseUrl ?? "default",
4730
5992
  active: p.isActive ? "Yes" : "No",
4731
- updated: p.updatedAt ? new Date(p.updatedAt).toLocaleDateString() : "N/A"
5993
+ updated: p.updatedAt ? new Date(p.updatedAt).toLocaleDateString() : "N/A",
5994
+ url: providerLink(p.id)
4732
5995
  }));
4733
5996
  output.output(formatted);
4734
5997
  }
@@ -4739,8 +6002,8 @@ Examples:
4739
6002
  });
4740
6003
  providers.command("get").description("Get provider details").argument("<id>", "Provider ID (from: mutagent providers list)").addHelpText("after", `
4741
6004
  Examples:
4742
- ${chalk11.dim("$")} mutagent providers get <provider-id>
4743
- ${chalk11.dim("$")} mutagent providers get <provider-id> --json
6005
+ ${chalk14.dim("$")} mutagent providers get <provider-id>
6006
+ ${chalk14.dim("$")} mutagent providers get <provider-id> --json
4744
6007
  `).action(async (id) => {
4745
6008
  const isJson = getJsonFlag(providers);
4746
6009
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4748,7 +6011,7 @@ Examples:
4748
6011
  const client = getSDKClient();
4749
6012
  const provider = await client.getProvider(id);
4750
6013
  if (isJson) {
4751
- output.output(provider);
6014
+ output.output({ ...provider, _links: providerLinks(provider.id) });
4752
6015
  } else {
4753
6016
  const formatted = {
4754
6017
  id: provider.id,
@@ -4758,7 +6021,8 @@ Examples:
4758
6021
  isActive: provider.isActive ? "Yes" : "No",
4759
6022
  createdBy: provider.createdBy ?? "N/A",
4760
6023
  createdAt: provider.createdAt ? new Date(provider.createdAt).toLocaleString() : "N/A",
4761
- updatedAt: provider.updatedAt ? new Date(provider.updatedAt).toLocaleString() : "N/A"
6024
+ updatedAt: provider.updatedAt ? new Date(provider.updatedAt).toLocaleString() : "N/A",
6025
+ url: providerLink(provider.id)
4762
6026
  };
4763
6027
  output.output(formatted);
4764
6028
  }
@@ -4768,10 +6032,10 @@ Examples:
4768
6032
  });
4769
6033
  providers.command("test").description("Test provider connectivity").argument("<id>", "Provider ID (from: mutagent providers list)").addHelpText("after", `
4770
6034
  Examples:
4771
- ${chalk11.dim("$")} mutagent providers test <provider-id>
4772
- ${chalk11.dim("$")} mutagent providers test <provider-id> --json
6035
+ ${chalk14.dim("$")} mutagent providers test <provider-id>
6036
+ ${chalk14.dim("$")} mutagent providers test <provider-id> --json
4773
6037
 
4774
- ${chalk11.dim("Tests connectivity and lists available models for the provider.")}
6038
+ ${chalk14.dim("Tests connectivity and lists available models for the provider.")}
4775
6039
  `).action(async (id) => {
4776
6040
  const isJson = getJsonFlag(providers);
4777
6041
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -4782,13 +6046,13 @@ ${chalk11.dim("Tests connectivity and lists available models for the provider.")
4782
6046
  }
4783
6047
  const result = await client.testProvider(id);
4784
6048
  if (isJson) {
4785
- output.output(result);
6049
+ output.output({ ...result, _links: providerLinks(id) });
4786
6050
  } else {
4787
6051
  if (result.success) {
4788
6052
  output.success(`Provider test passed (${String(result.responseTimeMs)}ms)`);
4789
- console.log(chalk11.green(`Message: ${result.message}`));
6053
+ console.log(chalk14.green(`Message: ${result.message}`));
4790
6054
  if (result.availableModels && result.availableModels.length > 0) {
4791
- console.log(chalk11.bold(`
6055
+ console.log(chalk14.bold(`
4792
6056
  Available Models:`));
4793
6057
  result.availableModels.forEach((model) => {
4794
6058
  console.log(` - ${model}`);
@@ -4797,7 +6061,7 @@ Available Models:`));
4797
6061
  } else {
4798
6062
  output.error(`Provider test failed: ${result.message}`);
4799
6063
  if (result.error) {
4800
- console.log(chalk11.red(`Error: ${result.error}`));
6064
+ console.log(chalk14.red(`Error: ${result.error}`));
4801
6065
  }
4802
6066
  }
4803
6067
  }
@@ -4809,12 +6073,14 @@ Available Models:`));
4809
6073
  }
4810
6074
 
4811
6075
  // src/commands/init.ts
6076
+ init_config();
4812
6077
  import { Command as Command11 } from "commander";
4813
6078
  import inquirer3 from "inquirer";
4814
- import chalk12 from "chalk";
4815
- import { existsSync as existsSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync3 } from "fs";
6079
+ import chalk15 from "chalk";
6080
+ import { existsSync as existsSync12, readFileSync as readFileSync13, writeFileSync as writeFileSync4 } from "fs";
4816
6081
  import { execSync as execSync2 } from "child_process";
4817
- import { join as join2 } from "path";
6082
+ import { join as join5 } from "path";
6083
+ init_errors();
4818
6084
  var FRAMEWORK_DETECTION_MAP = {
4819
6085
  "@mastra/core": {
4820
6086
  name: "mastra",
@@ -4864,16 +6130,16 @@ var FRAMEWORK_DETECTION_MAP = {
4864
6130
  }
4865
6131
  };
4866
6132
  function detectPackageManager2(cwd = process.cwd()) {
4867
- if (existsSync10(join2(cwd, "bun.lockb")) || existsSync10(join2(cwd, "bun.lock"))) {
6133
+ if (existsSync12(join5(cwd, "bun.lockb")) || existsSync12(join5(cwd, "bun.lock"))) {
4868
6134
  return "bun";
4869
6135
  }
4870
- if (existsSync10(join2(cwd, "pnpm-lock.yaml"))) {
6136
+ if (existsSync12(join5(cwd, "pnpm-lock.yaml"))) {
4871
6137
  return "pnpm";
4872
6138
  }
4873
- if (existsSync10(join2(cwd, "yarn.lock"))) {
6139
+ if (existsSync12(join5(cwd, "yarn.lock"))) {
4874
6140
  return "yarn";
4875
6141
  }
4876
- if (existsSync10(join2(cwd, "package-lock.json"))) {
6142
+ if (existsSync12(join5(cwd, "package-lock.json"))) {
4877
6143
  return "npm";
4878
6144
  }
4879
6145
  try {
@@ -4894,13 +6160,13 @@ function getInstallCommand2(pm, packages) {
4894
6160
  return commands[pm];
4895
6161
  }
4896
6162
  function detectFrameworkFromPackageJson(cwd = process.cwd()) {
4897
- const pkgPath = join2(cwd, "package.json");
4898
- if (!existsSync10(pkgPath)) {
6163
+ const pkgPath = join5(cwd, "package.json");
6164
+ if (!existsSync12(pkgPath)) {
4899
6165
  return null;
4900
6166
  }
4901
6167
  let pkg;
4902
6168
  try {
4903
- pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
6169
+ pkg = JSON.parse(readFileSync13(pkgPath, "utf-8"));
4904
6170
  } catch {
4905
6171
  return null;
4906
6172
  }
@@ -4916,23 +6182,23 @@ function detectFrameworkFromPackageJson(cwd = process.cwd()) {
4916
6182
  return null;
4917
6183
  }
4918
6184
  function hasRcConfig(cwd = process.cwd()) {
4919
- return existsSync10(join2(cwd, ".mutagentrc.json"));
6185
+ return existsSync12(join5(cwd, ".mutagentrc.json"));
4920
6186
  }
4921
6187
  function writeRcConfig(config, cwd = process.cwd()) {
4922
- const rcPath = join2(cwd, ".mutagentrc.json");
4923
- writeFileSync3(rcPath, JSON.stringify(config, null, 2) + `
6188
+ const rcPath = join5(cwd, ".mutagentrc.json");
6189
+ writeFileSync4(rcPath, JSON.stringify(config, null, 2) + `
4924
6190
  `);
4925
6191
  }
4926
6192
  function createInitCommand() {
4927
6193
  const init = new Command11("init").description("Initialize MutagenT in your project").option("--non-interactive", "Skip interactive prompts (defaults to CLI-only mode)").addHelpText("after", `
4928
6194
  Examples:
4929
- ${chalk12.dim("$")} mutagent init # Interactive setup wizard
4930
- ${chalk12.dim("$")} mutagent init --non-interactive # CLI-only mode (no prompts)
6195
+ ${chalk15.dim("$")} mutagent init # Interactive setup wizard
6196
+ ${chalk15.dim("$")} mutagent init --non-interactive # CLI-only mode (no prompts)
4931
6197
 
4932
6198
  Modes:
4933
- ${chalk12.bold("Full scaffold")} Install SDK + integration package, create config, setup tracing
4934
- ${chalk12.bold("CLI-only")} Verify auth + create .mutagentrc.json with workspace/endpoint
4935
- ${chalk12.bold("Skip")} Exit without changes
6199
+ ${chalk15.bold("Full scaffold")} Install SDK + integration package, create config, setup tracing
6200
+ ${chalk15.bold("CLI-only")} Verify auth + create .mutagentrc.json with workspace/endpoint
6201
+ ${chalk15.bold("Skip")} Exit without changes
4936
6202
  `).action(async (options) => {
4937
6203
  const isJson = getJsonFlag(init);
4938
6204
  const output = new OutputFormatter(isJson ? "json" : "table");
@@ -5101,15 +6367,259 @@ Modes:
5101
6367
  return init;
5102
6368
  }
5103
6369
 
6370
+ // src/commands/explore.ts
6371
+ import { Command as Command12 } from "commander";
6372
+ import chalk16 from "chalk";
6373
+ import { resolve as resolve3 } from "path";
6374
+ init_errors();
6375
+ function createExploreCommand() {
6376
+ const explore = new Command12("explore").description("Scan codebase for prompts, datasets, and MutagenT markers").option("-p, --path <dir>", "Directory to scan", ".").option("--depth <n>", "Max directory depth", "10").option("--include <glob>", "Include file pattern", "**/*.{ts,js,py,tsx,jsx}").option("--exclude <dirs>", "Comma-separated directories to exclude", "node_modules,dist,.git,build,.next,__pycache__,venv,.venv").option("--markers-only", "Only find existing MutagenT markers").addHelpText("after", `
6377
+ Examples:
6378
+ ${chalk16.dim("$")} mutagent explore
6379
+ ${chalk16.dim("$")} mutagent explore --path ./src
6380
+ ${chalk16.dim("$")} mutagent explore --include "**/*.{ts,py}" --depth 5
6381
+ ${chalk16.dim("$")} mutagent explore --markers-only
6382
+ ${chalk16.dim("$")} mutagent explore --json
6383
+
6384
+ Detection modes:
6385
+ ${chalk16.dim("Heuristic")} Template variables ({{var}}), prompt constants, schema definitions
6386
+ ${chalk16.dim("Marker")} MutagenT:START/END comment markers from previous uploads
6387
+
6388
+ ${chalk16.dim("Results are saved to .mutagent/mutation-context.md for use by other commands.")}
6389
+ `).action((options) => {
6390
+ const isJson = getJsonFlag(explore);
6391
+ const output = new OutputFormatter(isJson ? "json" : "table");
6392
+ try {
6393
+ const scanPath = resolve3(options.path ?? ".");
6394
+ const depth = parseInt(options.depth ?? "10", 10);
6395
+ const extensions = parseExtensions(options.include ?? "**/*.{ts,js,py,tsx,jsx}");
6396
+ const excludeDirs = parseExcludeDirs(options.exclude ?? "node_modules,dist,.git,build,.next,__pycache__,venv,.venv");
6397
+ const markersOnly = options.markersOnly ?? false;
6398
+ const exploreOpts = {
6399
+ path: scanPath,
6400
+ depth,
6401
+ extensions,
6402
+ excludeDirs,
6403
+ markersOnly
6404
+ };
6405
+ if (!isJson) {
6406
+ console.log(chalk16.cyan(`
6407
+ Scanning ${scanPath}...
6408
+ `));
6409
+ }
6410
+ const result = exploreCodebase(exploreOpts);
6411
+ const ctx = MutationContext.load(scanPath);
6412
+ for (const prompt of result.prompts) {
6413
+ ctx.addDiscoveredPrompt(prompt.file, prompt.line, prompt.preview);
6414
+ }
6415
+ for (const dataset of result.datasets) {
6416
+ ctx.addDiscoveredDataset(dataset.file, dataset.name, dataset.items);
6417
+ }
6418
+ ctx.save();
6419
+ if (isJson) {
6420
+ output.output({
6421
+ prompts: result.prompts,
6422
+ datasets: result.datasets,
6423
+ markers: result.markers,
6424
+ summary: {
6425
+ totalPrompts: result.prompts.length,
6426
+ totalDatasets: result.datasets.length,
6427
+ totalMarkers: result.markers.length
6428
+ },
6429
+ contextFile: ".mutagent/mutation-context.md"
6430
+ });
6431
+ } else {
6432
+ const totalFindings = result.prompts.length + result.datasets.length + result.markers.length;
6433
+ if (totalFindings === 0) {
6434
+ output.info("No prompts, datasets, or markers found.");
6435
+ console.log(chalk16.dim(`
6436
+ Tip: Create a prompt with template variables like {{input}} to get started.`));
6437
+ return;
6438
+ }
6439
+ if (result.prompts.length > 0) {
6440
+ console.log(chalk16.bold(` Prompts Found (${String(result.prompts.length)}):`));
6441
+ console.log();
6442
+ for (const p of result.prompts) {
6443
+ const reasonTag = chalk16.dim(`[${p.reason}]`);
6444
+ console.log(` ${chalk16.green(p.file)}:${chalk16.yellow(String(p.line))} ${reasonTag}`);
6445
+ console.log(` ${chalk16.dim(p.preview)}`);
6446
+ }
6447
+ console.log();
6448
+ }
6449
+ if (result.datasets.length > 0) {
6450
+ console.log(chalk16.bold(` Datasets Found (${String(result.datasets.length)}):`));
6451
+ console.log();
6452
+ for (const d of result.datasets) {
6453
+ console.log(` ${chalk16.green(d.file)} ${chalk16.dim(`(${String(d.items)} items)`)}`);
6454
+ }
6455
+ console.log();
6456
+ }
6457
+ if (result.markers.length > 0) {
6458
+ console.log(chalk16.bold(` MutagenT Markers (${String(result.markers.length)}):`));
6459
+ console.log();
6460
+ for (const m of result.markers) {
6461
+ const idPart = m.platformId ? chalk16.cyan(` id=${m.platformId}`) : "";
6462
+ console.log(` ${chalk16.green(m.file)}:${chalk16.yellow(String(m.line))} ${chalk16.magenta(m.type)}${idPart}`);
6463
+ }
6464
+ console.log();
6465
+ }
6466
+ console.log(chalk16.dim(" ─────────────────────────────────"));
6467
+ console.log(` ${chalk16.bold("Summary:")} ${String(result.prompts.length)} prompts, ${String(result.datasets.length)} datasets, ${String(result.markers.length)} markers`);
6468
+ console.log(chalk16.dim(` Saved to .mutagent/mutation-context.md`));
6469
+ console.log();
6470
+ }
6471
+ } catch (error) {
6472
+ handleError(error, isJson);
6473
+ }
6474
+ });
6475
+ return explore;
6476
+ }
6477
+
6478
+ // src/commands/skills.ts
6479
+ import { Command as Command13 } from "commander";
6480
+ import chalk17 from "chalk";
6481
+ import { existsSync as existsSync13, mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "fs";
6482
+ import { join as join6 } from "path";
6483
+ var SKILL_FRONTMATTER = `---
6484
+ name: mutagent-cli
6485
+ description: |
6486
+ MutagenT CLI - AI Prompt Optimization Platform CLI.
6487
+ Guides coding agents through prompt upload, evaluation creation,
6488
+ dataset curation, optimization, and framework integration.
6489
+ Triggers: "mutagent", "optimize prompt", "upload prompt", "integrate tracing",
6490
+ "create evaluation", "upload dataset", "mutagent cli".
6491
+ ---`;
6492
+ var SKILL_BODY = `# MutagenT CLI Skill
6493
+
6494
+ ## Quick Reference
6495
+ Run \`mutagent --help\` for full command list and examples.
6496
+
6497
+ ## Post-Onboarding Decision Tree
6498
+
6499
+ After \`mutagent auth login\`, the user lands in one of 3 paths:
6500
+
6501
+ ### Path A: Guided Integration (Tracing)
6502
+ 1. \`mutagent explore\` — Map codebase, discover prompts/agents
6503
+ 2. User selects framework from detected or asks
6504
+ 3. \`mutagent integrate <framework>\` — Get integration instructions
6505
+ 4. Apply tracing code to user's codebase
6506
+ 5. Verify with test run
6507
+
6508
+ ### Path B: Free-flow Optimization
6509
+ 1. \`mutagent explore\` — Map codebase, discover prompts
6510
+ 2. User selects prompts to upload
6511
+ 3. \`mutagent prompts create --data '{...}'\` — Upload with REQUIRED outputSchema
6512
+ 4. Guided eval creator OR \`mutagent prompts evaluation create\`
6513
+ 5. \`mutagent prompts dataset add\` — Upload/curate datasets (named)
6514
+ 6. \`mutagent prompts optimize start\` — Run optimization
6515
+ 7. Review scorecard → Apply/Reject optimized prompt
6516
+
6517
+ ### Path C: Manual
6518
+ User uses CLI commands directly. Run \`mutagent --help\`.
6519
+
6520
+ ## State Tracking
6521
+ - \`.mutagent/mutation-context.md\` — Local context file tracking all uploads
6522
+ - \`mutagent auth status\` — Shows onboarding completion + integration state
6523
+ - Comment markers (\`// MutagenT:START ... // MutagenT:END\`) in source files
6524
+
6525
+ ## Wireframe Templates
6526
+
6527
+ ### Active Operation Status Card
6528
+ \`\`\`
6529
+ ┌─────────────────────────────────────────┐
6530
+ │ ⚡ MutagenT: Optimizing │
6531
+ │ ─────────────────────────────────────── │
6532
+ │ Prompt: "email-summarizer" (ID: 42) │
6533
+ │ Dataset: "customer-emails" (150 items) │
6534
+ │ Status: Running — Iteration 3/10 │
6535
+ │ Score: 0.72 → 0.85 (+18%) │
6536
+ │ ████████████░░░░░░░░ 60% │
6537
+ │ │
6538
+ │ \uD83D\uDD17 View: https://app.mutagent.io/... │
6539
+ └─────────────────────────────────────────┘
6540
+ \`\`\`
6541
+
6542
+ ### Optimization Scorecard
6543
+ \`\`\`
6544
+ ┌─────────────────────────────────────────┐
6545
+ │ \uD83D\uDCCA Optimization Results │
6546
+ │ ─────────────────────────────────────── │
6547
+ │ BEFORE │
6548
+ │ System: "You are a helpful..." │
6549
+ │ Score: 0.62 │
6550
+ │ │
6551
+ │ AFTER │
6552
+ │ System: "You are an expert..." │
6553
+ │ Score: 0.91 (+47%) │
6554
+ │ │
6555
+ │ Iterations: 5 | Best: #4 │
6556
+ │ ─────────────────────────────────────── │
6557
+ │ Score Progression: │
6558
+ │ #1: 0.62 #2: 0.71 #3: 0.78 │
6559
+ │ #4: 0.91 #5: 0.89 │
6560
+ │ │
6561
+ │ [Apply] [Reject] [View Details] │
6562
+ │ │
6563
+ │ \uD83D\uDD17 Dashboard: https://app.mutagent... │
6564
+ │ \uD83D\uDD17 Optimizer: https://app.mutagent... │
6565
+ └─────────────────────────────────────────┘
6566
+ \`\`\`
6567
+
6568
+ ## Evaluation Criteria Reminder
6569
+ Every evaluation MUST specify criteria targeting either:
6570
+ - Input variable fields (from inputSchema)
6571
+ - Output fields (from outputSchema / structured output)`;
6572
+ var SKILL_DIR = ".claude/skills/mutagent-cli";
6573
+ var SKILL_FILE = "SKILL.md";
6574
+ function createSkillsCommand() {
6575
+ const skills = new Command13("skills").description("Manage MutagenT CLI skills for coding agents");
6576
+ skills.command("install").description("Install MutagenT CLI skill for Claude Code").addHelpText("after", `
6577
+ Examples:
6578
+ ${chalk17.dim("$")} mutagent skills install
6579
+
6580
+ This creates a Claude Code skill at .claude/skills/mutagent-cli/SKILL.md
6581
+ that teaches coding agents how to use the MutagenT CLI effectively.
6582
+ `).action((_options, cmd) => {
6583
+ const parentCmd = cmd.parent?.parent;
6584
+ const isJson = parentCmd ? getJsonFlag(parentCmd) : false;
6585
+ const output = new OutputFormatter(isJson ? "json" : "table");
6586
+ const skillDir = join6(process.cwd(), SKILL_DIR);
6587
+ const skillPath = join6(skillDir, SKILL_FILE);
6588
+ if (!existsSync13(skillDir)) {
6589
+ mkdirSync3(skillDir, { recursive: true });
6590
+ }
6591
+ const content = `${SKILL_FRONTMATTER}
6592
+
6593
+ ${SKILL_BODY}
6594
+ `;
6595
+ writeFileSync5(skillPath, content, "utf-8");
6596
+ if (isJson) {
6597
+ output.output({
6598
+ installed: true,
6599
+ path: skillPath,
6600
+ name: "mutagent-cli"
6601
+ });
6602
+ } else {
6603
+ output.success(`Installed MutagenT CLI skill`);
6604
+ console.log(` ${chalk17.dim("Path:")} ${skillPath}`);
6605
+ console.log("");
6606
+ console.log(` ${chalk17.dim("This skill teaches coding agents how to use the MutagenT CLI.")}`);
6607
+ console.log(` ${chalk17.dim("It will be automatically loaded by Claude Code when relevant triggers match.")}`);
6608
+ }
6609
+ });
6610
+ return skills;
6611
+ }
6612
+
5104
6613
  // src/bin/cli.ts
6614
+ init_config();
5105
6615
  var cliVersion = "0.1.1";
5106
6616
  try {
5107
6617
  const __dirname2 = dirname(fileURLToPath(import.meta.url));
5108
- const pkgPath = join3(__dirname2, "..", "..", "package.json");
5109
- const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
6618
+ const pkgPath = join7(__dirname2, "..", "..", "package.json");
6619
+ const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
5110
6620
  cliVersion = pkg.version ?? cliVersion;
5111
6621
  } catch {}
5112
- var program = new Command12;
6622
+ var program = new Command14;
5113
6623
  program.name("mutagent").description(`MutagenT CLI - AI-native prompt optimization platform
5114
6624
 
5115
6625
  Documentation: https://docs.mutagent.io/cli
@@ -5118,44 +6628,44 @@ program.name("mutagent").description(`MutagenT CLI - AI-native prompt optimizati
5118
6628
  showGlobalOptions: true
5119
6629
  });
5120
6630
  program.addHelpText("after", `
5121
- ${chalk13.yellow("Non-Interactive Mode (CI/CD & Coding Agents):")}
5122
- Export your API key: ${chalk13.green("export MUTAGENT_API_KEY=mt_your_key_here")}
5123
- Or pass inline: ${chalk13.green("mutagent prompts list --api-key mt_your_key")}
5124
- Machine-readable output: ${chalk13.green("mutagent prompts list --json")}
5125
- Disable prompts: ${chalk13.green("mutagent prompts list --non-interactive")}
5126
- Set default workspace: ${chalk13.green("mutagent config set workspace <workspace-id>")}
5127
- Set default org: ${chalk13.green("mutagent config set org <org-id>")}
6631
+ ${chalk18.yellow("Non-Interactive Mode (CI/CD & Coding Agents):")}
6632
+ Export your API key: ${chalk18.green("export MUTAGENT_API_KEY=mt_your_key_here")}
6633
+ Or pass inline: ${chalk18.green("mutagent prompts list --api-key mt_your_key")}
6634
+ Machine-readable output: ${chalk18.green("mutagent prompts list --json")}
6635
+ Disable prompts: ${chalk18.green("mutagent prompts list --non-interactive")}
6636
+ Set default workspace: ${chalk18.green("mutagent config set workspace <workspace-id>")}
6637
+ Set default org: ${chalk18.green("mutagent config set org <org-id>")}
5128
6638
  `);
5129
6639
  program.addHelpText("after", `
5130
- ${chalk13.yellow("Workflows:")}
5131
- ${chalk13.bold("Evaluate → Optimize Loop:")}
6640
+ ${chalk18.yellow("Workflows:")}
6641
+ ${chalk18.bold("Evaluate → Optimize Loop:")}
5132
6642
  1. mutagent prompts create --name "..." --raw-file prompt.txt
5133
6643
  2. mutagent prompts dataset add <prompt-id> --name "..." --file data.json
5134
6644
  3. mutagent prompts evaluation create <prompt-id> --name "..." --file criteria.json
5135
6645
  4. mutagent prompts optimize start <prompt-id> --dataset <id> --max-iterations 3
5136
6646
 
5137
- ${chalk13.bold("Quick Test:")}
6647
+ ${chalk18.bold("Quick Test:")}
5138
6648
  mutagent playground run <prompt-id> --input '{"key":"value"}'
5139
6649
 
5140
- ${chalk13.bold("Prerequisites for Optimization:")}
5141
- ${chalk13.green("✓")} Prompt with input/output parameters
5142
- ${chalk13.green("✓")} Dataset with items (input + expectedOutput pairs)
5143
- ${chalk13.green("✓")} Evaluation with criteria (field-level, input/output focused)
5144
- ${chalk13.dim("•")} LLM provider ${chalk13.dim("(only when server uses external providers)")}
6650
+ ${chalk18.bold("Prerequisites for Optimization:")}
6651
+ ${chalk18.green("✓")} Prompt with input/output parameters
6652
+ ${chalk18.green("✓")} Dataset with items (input + expectedOutput pairs)
6653
+ ${chalk18.green("✓")} Evaluation with criteria (field-level, input/output focused)
6654
+ ${chalk18.dim("•")} LLM provider ${chalk18.dim("(only when server uses external providers)")}
5145
6655
  `);
5146
6656
  program.addHelpText("after", `
5147
- ${chalk13.cyan("┌─ AI AGENT INTEGRATION HINT ────────────────────────────────────────────────┐")}
5148
- ${chalk13.cyan("│")} ${chalk13.cyan("│")}
5149
- ${chalk13.cyan("│")} Frameworks: mastra, langchain, langgraph, vercel-ai, claude-code, generic ${chalk13.cyan("│")}
5150
- ${chalk13.cyan("│")} ${chalk13.cyan("│")}
5151
- ${chalk13.cyan("│")} Get integration guide: mutagent integrate <framework> ${chalk13.cyan("│")}
5152
- ${chalk13.cyan("│")} Verify setup: mutagent integrate <framework> --verify ${chalk13.cyan("│")}
5153
- ${chalk13.cyan("│")} Use --json for AI parsing: mutagent <command> --json ${chalk13.cyan("│")}
5154
- ${chalk13.cyan("│")} ${chalk13.cyan("│")}
5155
- ${chalk13.cyan("└────────────────────────────────────────────────────────────────────────────┘")}
5156
- ${!hasCredentials() ? chalk13.yellow(`
6657
+ ${chalk18.cyan("┌─ AI AGENT INTEGRATION HINT ────────────────────────────────────────────────┐")}
6658
+ ${chalk18.cyan("│")} ${chalk18.cyan("│")}
6659
+ ${chalk18.cyan("│")} Frameworks: mastra, langchain, langgraph, vercel-ai, claude-code, generic ${chalk18.cyan("│")}
6660
+ ${chalk18.cyan("│")} ${chalk18.cyan("│")}
6661
+ ${chalk18.cyan("│")} Get integration guide: mutagent integrate <framework> ${chalk18.cyan("│")}
6662
+ ${chalk18.cyan("│")} Verify setup: mutagent integrate <framework> --verify ${chalk18.cyan("│")}
6663
+ ${chalk18.cyan("│")} Use --json for AI parsing: mutagent <command> --json ${chalk18.cyan("│")}
6664
+ ${chalk18.cyan("│")} ${chalk18.cyan("│")}
6665
+ ${chalk18.cyan("└────────────────────────────────────────────────────────────────────────────┘")}
6666
+ ${!hasCredentials() ? chalk18.yellow(`
5157
6667
  Warning: Not authenticated. Run: mutagent auth login --browser
5158
- `) : ""}${!hasRcConfig() ? chalk13.green(`
6668
+ `) : ""}${!hasRcConfig() ? chalk18.green(`
5159
6669
  Get started: mutagent init
5160
6670
  `) : ""}`);
5161
6671
  program.hook("preAction", (thisCommand) => {
@@ -5181,7 +6691,9 @@ program.addCommand(createAgentsCommand());
5181
6691
  program.addCommand(createPlaygroundCommand());
5182
6692
  program.addCommand(createWorkspacesCommand());
5183
6693
  program.addCommand(createProvidersCommand());
6694
+ program.addCommand(createExploreCommand());
6695
+ program.addCommand(createSkillsCommand());
5184
6696
  program.parse();
5185
6697
 
5186
- //# debugId=EDFE2E68EFA4B20A64756E2164756E21
6698
+ //# debugId=A683D38662CECE3C64756E2164756E21
5187
6699
  //# sourceMappingURL=cli.js.map