@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/README.md +461 -222
- package/dist/bin/cli.js +2004 -492
- package/dist/bin/cli.js.map +20 -13
- package/dist/index.js +124 -90
- package/dist/index.js.map +7 -7
- package/package.json +3 -8
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
|
-
|
|
166
|
-
|
|
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
|
-
${
|
|
1173
|
-
${
|
|
1174
|
-
${
|
|
1175
|
-
${
|
|
1176
|
-
${
|
|
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
|
-
${
|
|
1181
|
-
${
|
|
1182
|
-
${
|
|
1183
|
-
${
|
|
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
|
-
` +
|
|
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
|
-
${
|
|
1382
|
-
${
|
|
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
|
|
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
|
-
${
|
|
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
|
|
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
|
-
${
|
|
1458
|
-
${
|
|
1459
|
-
${
|
|
1460
|
-
${
|
|
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
|
-
` +
|
|
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
|
|
1595
|
-
import { readFileSync as
|
|
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
|
-
|
|
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
|
-
|
|
1691
|
-
|
|
2636
|
+
name: evalName.trim(),
|
|
2637
|
+
description: `${evalType} evaluation with ${String(criteria.length)} criteria`,
|
|
2638
|
+
evalConfig: { criteria }
|
|
1692
2639
|
};
|
|
1693
2640
|
}
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
"
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
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
|
-
${
|
|
1714
|
-
1. Evaluation criteria defined ${
|
|
1715
|
-
2. Dataset uploaded ${
|
|
1716
|
-
${
|
|
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 (!
|
|
2864
|
+
if (!existsSync4(input.trim()))
|
|
1828
2865
|
return `File not found: ${input.trim()}`;
|
|
1829
2866
|
return true;
|
|
1830
2867
|
}
|
|
1831
2868
|
}]);
|
|
1832
|
-
const content =
|
|
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(
|
|
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
|
-
${
|
|
1895
|
-
${
|
|
1896
|
-
${
|
|
1897
|
-
${
|
|
1898
|
-
${
|
|
1899
|
-
${
|
|
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
|
-
${
|
|
1910
|
-
${
|
|
1911
|
-
${
|
|
2946
|
+
${chalk7.dim("$")} mutagent prompts list
|
|
2947
|
+
${chalk7.dim("$")} mutagent prompts list --limit 10
|
|
2948
|
+
${chalk7.dim("$")} mutagent prompts list --json
|
|
1912
2949
|
|
|
1913
|
-
${
|
|
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
|
-
${
|
|
1945
|
-
${
|
|
1946
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
1975
|
-
${
|
|
1976
|
-
${
|
|
1977
|
-
${
|
|
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
|
-
${
|
|
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
|
-
|
|
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 (!
|
|
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 =
|
|
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
|
-
${
|
|
2071
|
-
${
|
|
2072
|
-
${
|
|
2073
|
-
${
|
|
2074
|
-
${
|
|
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
|
-
|
|
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 (!
|
|
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 =
|
|
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
|
-
${
|
|
2146
|
-
${
|
|
2147
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
2177
|
-
${
|
|
2178
|
-
${
|
|
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
|
-
${
|
|
2183
|
-
${
|
|
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
|
-
${
|
|
2210
|
-
${
|
|
2211
|
-
${
|
|
2212
|
-
${
|
|
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
|
-
${
|
|
2216
|
-
${
|
|
2217
|
-
${
|
|
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
|
-
${
|
|
3327
|
+
${chalk7.dim('[{"input": {"text": "hello"}, "expectedOutput": {"result": "world"}}]')}
|
|
2222
3328
|
|
|
2223
|
-
${
|
|
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 =
|
|
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,
|
|
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
|
-
${
|
|
2280
|
-
${
|
|
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
|
-
${
|
|
2295
|
-
${
|
|
2296
|
-
${
|
|
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
|
-
${
|
|
2301
|
-
${
|
|
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)").
|
|
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
|
-
${
|
|
2328
|
-
${
|
|
2329
|
-
${
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
${
|
|
2335
|
-
|
|
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.
|
|
2345
|
-
|
|
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 =
|
|
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
|
-
${
|
|
2394
|
-
${
|
|
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
|
-
${
|
|
2409
|
-
${
|
|
2410
|
-
${
|
|
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
|
-
${
|
|
2417
|
-
${
|
|
2418
|
-
${
|
|
2419
|
-
${
|
|
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
|
-
${
|
|
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(
|
|
3650
|
+
console.error(chalk7.red("Optimization failed. Missing requirements:"));
|
|
2458
3651
|
for (const msg of messages) {
|
|
2459
|
-
console.error(
|
|
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
|
-
${
|
|
2471
|
-
${
|
|
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
|
-
${
|
|
2495
|
-
${
|
|
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({ ...
|
|
3697
|
+
output.output({ ...resultData, _links: { optimizer: optimizerLink(jobId) } });
|
|
2504
3698
|
} else {
|
|
2505
|
-
|
|
2506
|
-
|
|
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
|
|
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
|
-
${
|
|
2522
|
-
${
|
|
2523
|
-
${
|
|
2524
|
-
${
|
|
2525
|
-
${
|
|
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
|
-
${
|
|
2532
|
-
${
|
|
2533
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
2570
|
-
${
|
|
3804
|
+
${chalk8.dim("$")} mutagent traces get <trace-id>
|
|
3805
|
+
${chalk8.dim("$")} mutagent traces get <trace-id> --json
|
|
2571
3806
|
|
|
2572
|
-
${
|
|
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
|
-
${
|
|
2592
|
-
${
|
|
3826
|
+
${chalk8.dim("$")} mutagent traces analyze <prompt-id>
|
|
3827
|
+
${chalk8.dim("$")} mutagent traces analyze <prompt-id> --json
|
|
2593
3828
|
|
|
2594
|
-
${
|
|
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
|
-
${
|
|
2613
|
-
${
|
|
2614
|
-
${
|
|
2615
|
-
${
|
|
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
|
-
${
|
|
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:
|
|
2646
|
-
|
|
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
|
|
2661
|
-
import { writeFileSync as
|
|
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
|
|
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 (
|
|
3916
|
+
if (existsSync5(file)) {
|
|
2680
3917
|
found.push(file);
|
|
2681
3918
|
}
|
|
2682
3919
|
}
|
|
2683
3920
|
let hasMastraDep = false;
|
|
2684
|
-
if (
|
|
3921
|
+
if (existsSync5("package.json")) {
|
|
2685
3922
|
try {
|
|
2686
|
-
const pkg = JSON.parse(
|
|
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
|
|
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 (
|
|
4104
|
+
if (existsSync6("package.json")) {
|
|
2868
4105
|
try {
|
|
2869
|
-
const pkg = JSON.parse(
|
|
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
|
|
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 (
|
|
4244
|
+
if (existsSync7("package.json")) {
|
|
3008
4245
|
try {
|
|
3009
|
-
const pkg = JSON.parse(
|
|
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
|
|
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 (
|
|
4370
|
+
if (existsSync8("package.json")) {
|
|
3134
4371
|
try {
|
|
3135
|
-
const pkg = JSON.parse(
|
|
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
|
|
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 (
|
|
4491
|
+
if (existsSync9("package.json")) {
|
|
3255
4492
|
try {
|
|
3256
|
-
const pkg = JSON.parse(
|
|
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
|
|
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 (
|
|
4629
|
+
if (existsSync10("package.json")) {
|
|
3393
4630
|
try {
|
|
3394
|
-
const pkg = JSON.parse(
|
|
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 (
|
|
4943
|
+
if (existsSync11("bun.lockb") || existsSync11("bun.lock")) {
|
|
3707
4944
|
return "bun";
|
|
3708
4945
|
}
|
|
3709
|
-
if (
|
|
4946
|
+
if (existsSync11("pnpm-lock.yaml")) {
|
|
3710
4947
|
return "pnpm";
|
|
3711
4948
|
}
|
|
3712
|
-
if (
|
|
4949
|
+
if (existsSync11("yarn.lock")) {
|
|
3713
4950
|
return "yarn";
|
|
3714
4951
|
}
|
|
3715
|
-
if (
|
|
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
|
-
${
|
|
3766
|
-
${
|
|
3767
|
-
${
|
|
3768
|
-
${
|
|
3769
|
-
${
|
|
3770
|
-
${
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
3874
|
-
import { readFileSync as
|
|
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
|
-
${
|
|
3879
|
-
${
|
|
3880
|
-
${
|
|
3881
|
-
${
|
|
3882
|
-
${
|
|
3883
|
-
${
|
|
3884
|
-
${
|
|
3885
|
-
${
|
|
3886
|
-
${
|
|
3887
|
-
${
|
|
3888
|
-
${
|
|
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
|
-
${
|
|
3897
|
-
${
|
|
3898
|
-
${
|
|
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
|
-
|
|
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
|
-
${
|
|
3938
|
-
${
|
|
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(
|
|
5212
|
+
console.log(chalk10.bold(`
|
|
3968
5213
|
System Prompt:`));
|
|
3969
|
-
console.log(
|
|
5214
|
+
console.log(chalk10.gray("─".repeat(60)));
|
|
3970
5215
|
console.log(agent.systemPrompt);
|
|
3971
|
-
console.log(
|
|
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
|
-
${
|
|
3981
|
-
${
|
|
3982
|
-
${
|
|
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
|
-
${
|
|
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 =
|
|
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
|
-
${
|
|
4017
|
-
${
|
|
4018
|
-
${
|
|
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 =
|
|
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
|
-
${
|
|
4053
|
-
${
|
|
4054
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
4084
|
-
${
|
|
4085
|
-
${
|
|
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
|
-
${
|
|
4090
|
-
${
|
|
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
|
-
${
|
|
4123
|
-
${
|
|
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
|
-
${
|
|
4151
|
-
${
|
|
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
|
-
${
|
|
4171
|
-
${
|
|
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
|
-
${
|
|
4199
|
-
${
|
|
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
|
|
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
|
-
${
|
|
4238
|
-
${
|
|
4239
|
-
${
|
|
4240
|
-
${
|
|
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
|
-
${
|
|
4245
|
-
${
|
|
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
|
-
${
|
|
4259
|
-
${
|
|
4260
|
-
${
|
|
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
|
-
${
|
|
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
|
-
${
|
|
5529
|
+
${chalk11.dim("$")} mutagent config set workspace <workspace-id>
|
|
4284
5530
|
|
|
4285
|
-
${
|
|
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
|
-
${
|
|
5544
|
+
${chalk11.dim("$")} mutagent config set org <org-id>
|
|
4299
5545
|
|
|
4300
|
-
${
|
|
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
|
|
4318
|
-
import { readFileSync as
|
|
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
|
-
${
|
|
4345
|
-
${
|
|
4346
|
-
${
|
|
4347
|
-
${
|
|
4348
|
-
${
|
|
4349
|
-
${
|
|
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
|
-
${
|
|
4366
|
-
${
|
|
4367
|
-
${
|
|
4368
|
-
${
|
|
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
|
-
${
|
|
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(
|
|
5646
|
+
console.log(chalk12.bold(`
|
|
4399
5647
|
Execution Result:`));
|
|
4400
|
-
console.log(
|
|
4401
|
-
console.log(
|
|
5648
|
+
console.log(chalk12.gray("─".repeat(50)));
|
|
5649
|
+
console.log(chalk12.cyan("Output:"));
|
|
4402
5650
|
console.log(result.output);
|
|
4403
|
-
console.log(
|
|
4404
|
-
console.log(
|
|
4405
|
-
console.log(
|
|
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(
|
|
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(
|
|
5658
|
+
console.log(chalk12.dim(`Cost: $${result.cost.toFixed(6)}`));
|
|
4411
5659
|
}
|
|
4412
|
-
console.log(
|
|
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
|
|
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(
|
|
5760
|
+
console.log(chalk12.bold(`
|
|
4513
5761
|
Streaming Output:`));
|
|
4514
|
-
console.log(
|
|
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(
|
|
5801
|
+
console.log(chalk12.gray("─".repeat(50)));
|
|
4554
5802
|
if (event.result) {
|
|
4555
|
-
console.log(
|
|
4556
|
-
console.log(
|
|
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(
|
|
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(
|
|
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
|
|
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
|
-
${
|
|
4590
|
-
${
|
|
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
|
-
${
|
|
4600
|
-
${
|
|
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
|
-
|
|
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
|
-
${
|
|
4632
|
-
${
|
|
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
|
|
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
|
-
${
|
|
4687
|
-
${
|
|
4688
|
-
${
|
|
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
|
-
${
|
|
4701
|
-
${
|
|
4702
|
-
${
|
|
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
|
-
|
|
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
|
-
${
|
|
4743
|
-
${
|
|
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
|
-
${
|
|
4772
|
-
${
|
|
6035
|
+
${chalk14.dim("$")} mutagent providers test <provider-id>
|
|
6036
|
+
${chalk14.dim("$")} mutagent providers test <provider-id> --json
|
|
4773
6037
|
|
|
4774
|
-
${
|
|
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(
|
|
6053
|
+
console.log(chalk14.green(`Message: ${result.message}`));
|
|
4790
6054
|
if (result.availableModels && result.availableModels.length > 0) {
|
|
4791
|
-
console.log(
|
|
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(
|
|
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
|
|
4815
|
-
import { existsSync as
|
|
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
|
|
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 (
|
|
6133
|
+
if (existsSync12(join5(cwd, "bun.lockb")) || existsSync12(join5(cwd, "bun.lock"))) {
|
|
4868
6134
|
return "bun";
|
|
4869
6135
|
}
|
|
4870
|
-
if (
|
|
6136
|
+
if (existsSync12(join5(cwd, "pnpm-lock.yaml"))) {
|
|
4871
6137
|
return "pnpm";
|
|
4872
6138
|
}
|
|
4873
|
-
if (
|
|
6139
|
+
if (existsSync12(join5(cwd, "yarn.lock"))) {
|
|
4874
6140
|
return "yarn";
|
|
4875
6141
|
}
|
|
4876
|
-
if (
|
|
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 =
|
|
4898
|
-
if (!
|
|
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(
|
|
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
|
|
6185
|
+
return existsSync12(join5(cwd, ".mutagentrc.json"));
|
|
4920
6186
|
}
|
|
4921
6187
|
function writeRcConfig(config, cwd = process.cwd()) {
|
|
4922
|
-
const rcPath =
|
|
4923
|
-
|
|
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
|
-
${
|
|
4930
|
-
${
|
|
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
|
-
${
|
|
4934
|
-
${
|
|
4935
|
-
${
|
|
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 =
|
|
5109
|
-
const pkg = JSON.parse(
|
|
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
|
|
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
|
-
${
|
|
5122
|
-
Export your API key: ${
|
|
5123
|
-
Or pass inline: ${
|
|
5124
|
-
Machine-readable output: ${
|
|
5125
|
-
Disable prompts: ${
|
|
5126
|
-
Set default workspace: ${
|
|
5127
|
-
Set default org: ${
|
|
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
|
-
${
|
|
5131
|
-
${
|
|
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
|
-
${
|
|
6647
|
+
${chalk18.bold("Quick Test:")}
|
|
5138
6648
|
mutagent playground run <prompt-id> --input '{"key":"value"}'
|
|
5139
6649
|
|
|
5140
|
-
${
|
|
5141
|
-
${
|
|
5142
|
-
${
|
|
5143
|
-
${
|
|
5144
|
-
${
|
|
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
|
-
${
|
|
5148
|
-
${
|
|
5149
|
-
${
|
|
5150
|
-
${
|
|
5151
|
-
${
|
|
5152
|
-
${
|
|
5153
|
-
${
|
|
5154
|
-
${
|
|
5155
|
-
${
|
|
5156
|
-
${!hasCredentials() ?
|
|
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() ?
|
|
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=
|
|
6698
|
+
//# debugId=A683D38662CECE3C64756E2164756E21
|
|
5187
6699
|
//# sourceMappingURL=cli.js.map
|