@mutagent/cli 0.1.89 → 0.1.90
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 +13 -8
- package/dist/bin/cli.js +955 -1039
- package/dist/bin/cli.js.map +8 -7
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -1142,7 +1142,7 @@ var init_sdk_client = __esm(() => {
|
|
|
1142
1142
|
|
|
1143
1143
|
// src/bin/cli.ts
|
|
1144
1144
|
import { Command as Command20 } from "commander";
|
|
1145
|
-
import
|
|
1145
|
+
import chalk32 from "chalk";
|
|
1146
1146
|
import { readFileSync as readFileSync12 } from "fs";
|
|
1147
1147
|
import { join as join10, dirname as dirname2 } from "path";
|
|
1148
1148
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -1151,9 +1151,7 @@ import { fileURLToPath as fileURLToPath2 } from "url";
|
|
|
1151
1151
|
init_config();
|
|
1152
1152
|
init_sdk_client();
|
|
1153
1153
|
import { Command } from "commander";
|
|
1154
|
-
import
|
|
1155
|
-
import chalk3 from "chalk";
|
|
1156
|
-
import ora from "ora";
|
|
1154
|
+
import chalk4 from "chalk";
|
|
1157
1155
|
import { existsSync as existsSync3 } from "fs";
|
|
1158
1156
|
import { join as join4 } from "path";
|
|
1159
1157
|
|
|
@@ -1304,143 +1302,6 @@ function createSpinner(text, isJson) {
|
|
|
1304
1302
|
// src/commands/auth.ts
|
|
1305
1303
|
init_errors();
|
|
1306
1304
|
|
|
1307
|
-
// src/lib/browser-auth.ts
|
|
1308
|
-
import { hostname, platform } from "os";
|
|
1309
|
-
function generateCliToken() {
|
|
1310
|
-
return crypto.randomUUID();
|
|
1311
|
-
}
|
|
1312
|
-
async function initBrowserAuth(endpoint, cliToken) {
|
|
1313
|
-
const response = await fetch(`${endpoint}/api/auth/cli/init`, {
|
|
1314
|
-
method: "POST",
|
|
1315
|
-
headers: { "Content-Type": "application/json" },
|
|
1316
|
-
body: JSON.stringify({
|
|
1317
|
-
cliToken,
|
|
1318
|
-
hostname: hostname(),
|
|
1319
|
-
platform: platform()
|
|
1320
|
-
})
|
|
1321
|
-
});
|
|
1322
|
-
if (!response.ok) {
|
|
1323
|
-
const errorText = await response.text();
|
|
1324
|
-
throw new BrowserAuthError("INIT_FAILED", "Failed to initialize browser auth: " + String(response.status) + " " + errorText);
|
|
1325
|
-
}
|
|
1326
|
-
const data = await response.json();
|
|
1327
|
-
return data;
|
|
1328
|
-
}
|
|
1329
|
-
async function pollAuthStatus(endpoint, cliToken) {
|
|
1330
|
-
const response = await fetch(`${endpoint}/api/auth/cli/status?token=${encodeURIComponent(cliToken)}`);
|
|
1331
|
-
if (!response.ok) {
|
|
1332
|
-
const errorText = await response.text();
|
|
1333
|
-
throw new BrowserAuthError("POLL_FAILED", "Failed to poll auth status: " + String(response.status) + " " + errorText);
|
|
1334
|
-
}
|
|
1335
|
-
const data = await response.json();
|
|
1336
|
-
return data;
|
|
1337
|
-
}
|
|
1338
|
-
async function openBrowser(url) {
|
|
1339
|
-
if (process.env.MUTAGENT_TEST_MODE === "true") {
|
|
1340
|
-
console.log(`AUTH_URL:${url}`);
|
|
1341
|
-
return;
|
|
1342
|
-
}
|
|
1343
|
-
try {
|
|
1344
|
-
const { default: open } = await import("open");
|
|
1345
|
-
await open(url);
|
|
1346
|
-
} catch {
|
|
1347
|
-
throw new BrowserAuthError("BROWSER_OPEN_FAILED", `Could not open browser automatically. Please visit: ${url}`);
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
function sleep(ms) {
|
|
1351
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1352
|
-
}
|
|
1353
|
-
async function performBrowserAuth(options, onStatusUpdate) {
|
|
1354
|
-
const {
|
|
1355
|
-
endpoint,
|
|
1356
|
-
timeout = 300000,
|
|
1357
|
-
pollInterval = 2000,
|
|
1358
|
-
skipBrowserOpen = false
|
|
1359
|
-
} = options;
|
|
1360
|
-
const cliToken = generateCliToken();
|
|
1361
|
-
onStatusUpdate?.("Initializing browser authentication...");
|
|
1362
|
-
const initResponse = await initBrowserAuth(endpoint, cliToken);
|
|
1363
|
-
const { authUrl } = initResponse;
|
|
1364
|
-
if (!skipBrowserOpen) {
|
|
1365
|
-
onStatusUpdate?.("Opening browser for authentication...");
|
|
1366
|
-
try {
|
|
1367
|
-
await openBrowser(authUrl);
|
|
1368
|
-
} catch (error) {
|
|
1369
|
-
if (error instanceof BrowserAuthError && error.code === "BROWSER_OPEN_FAILED") {
|
|
1370
|
-
onStatusUpdate?.(error.message);
|
|
1371
|
-
} else {
|
|
1372
|
-
throw error;
|
|
1373
|
-
}
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
console.log("");
|
|
1377
|
-
console.log(" Open this URL to authenticate:");
|
|
1378
|
-
console.log("");
|
|
1379
|
-
console.log(" " + authUrl);
|
|
1380
|
-
console.log("");
|
|
1381
|
-
onStatusUpdate?.("Waiting for browser authentication...");
|
|
1382
|
-
const startTime = Date.now();
|
|
1383
|
-
while (Date.now() - startTime < timeout) {
|
|
1384
|
-
await sleep(pollInterval);
|
|
1385
|
-
const status = await pollAuthStatus(endpoint, cliToken);
|
|
1386
|
-
switch (status.status) {
|
|
1387
|
-
case "pending":
|
|
1388
|
-
continue;
|
|
1389
|
-
case "completed":
|
|
1390
|
-
if (!status.apiKey || !status.workspaceId || !status.workspaceName || !status.organizationId || !status.organizationName) {
|
|
1391
|
-
throw new BrowserAuthError("INCOMPLETE_RESPONSE", "Server returned incomplete auth response");
|
|
1392
|
-
}
|
|
1393
|
-
return {
|
|
1394
|
-
apiKey: status.apiKey,
|
|
1395
|
-
workspaceId: status.workspaceId,
|
|
1396
|
-
workspaceName: status.workspaceName,
|
|
1397
|
-
organizationId: status.organizationId,
|
|
1398
|
-
organizationName: status.organizationName,
|
|
1399
|
-
expiresAt: status.expiresAt
|
|
1400
|
-
};
|
|
1401
|
-
case "expired":
|
|
1402
|
-
throw new BrowserAuthError("AUTH_EXPIRED", "Browser authentication expired. Please try again.");
|
|
1403
|
-
case "denied":
|
|
1404
|
-
throw new BrowserAuthError("AUTH_DENIED", status.error ?? "Browser authentication was denied.");
|
|
1405
|
-
case "not_found":
|
|
1406
|
-
throw new BrowserAuthError("TOKEN_NOT_FOUND", "Authentication token not found. Please try again.");
|
|
1407
|
-
default:
|
|
1408
|
-
throw new BrowserAuthError("UNKNOWN_STATUS", "Unknown auth status: " + String(status.status));
|
|
1409
|
-
}
|
|
1410
|
-
}
|
|
1411
|
-
throw new BrowserAuthError("AUTH_TIMEOUT", "Browser authentication timed out after 5 minutes. Please try again.");
|
|
1412
|
-
}
|
|
1413
|
-
|
|
1414
|
-
class BrowserAuthError extends Error {
|
|
1415
|
-
code;
|
|
1416
|
-
constructor(code, message) {
|
|
1417
|
-
super(message);
|
|
1418
|
-
this.name = "BrowserAuthError";
|
|
1419
|
-
this.code = code;
|
|
1420
|
-
}
|
|
1421
|
-
getSuggestion() {
|
|
1422
|
-
switch (this.code) {
|
|
1423
|
-
case "INIT_FAILED":
|
|
1424
|
-
return "Check your endpoint configuration and network connection.";
|
|
1425
|
-
case "POLL_FAILED":
|
|
1426
|
-
return "Check your network connection and try again.";
|
|
1427
|
-
case "BROWSER_OPEN_FAILED":
|
|
1428
|
-
return "Copy the URL above and open it manually in your browser.";
|
|
1429
|
-
case "AUTH_EXPIRED":
|
|
1430
|
-
case "AUTH_TIMEOUT":
|
|
1431
|
-
return 'Run "mutagent auth login" again to restart authentication.';
|
|
1432
|
-
case "AUTH_DENIED":
|
|
1433
|
-
return "Ensure you have access to the workspace and try again.";
|
|
1434
|
-
case "TOKEN_NOT_FOUND":
|
|
1435
|
-
case "INCOMPLETE_RESPONSE":
|
|
1436
|
-
case "UNKNOWN_STATUS":
|
|
1437
|
-
return "Please try again. If the issue persists, contact support.";
|
|
1438
|
-
default:
|
|
1439
|
-
return "Please try again.";
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
|
|
1444
1305
|
// src/lib/mutation-context.ts
|
|
1445
1306
|
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
1446
1307
|
import { join as join2, resolve } from "path";
|
|
@@ -2080,245 +1941,403 @@ function runOptimizationPath(promptCount, datasetCount) {
|
|
|
2080
1941
|
console.log("");
|
|
2081
1942
|
}
|
|
2082
1943
|
|
|
1944
|
+
// src/lib/auth-flow.ts
|
|
1945
|
+
init_config();
|
|
1946
|
+
init_sdk_client();
|
|
1947
|
+
init_errors();
|
|
1948
|
+
import inquirer from "inquirer";
|
|
1949
|
+
import chalk3 from "chalk";
|
|
1950
|
+
import ora from "ora";
|
|
1951
|
+
|
|
1952
|
+
// src/lib/browser-auth.ts
|
|
1953
|
+
import { hostname, platform } from "os";
|
|
1954
|
+
function generateCliToken() {
|
|
1955
|
+
return crypto.randomUUID();
|
|
1956
|
+
}
|
|
1957
|
+
async function initBrowserAuth(endpoint, cliToken) {
|
|
1958
|
+
const response = await fetch(`${endpoint}/api/auth/cli/init`, {
|
|
1959
|
+
method: "POST",
|
|
1960
|
+
headers: { "Content-Type": "application/json" },
|
|
1961
|
+
body: JSON.stringify({
|
|
1962
|
+
cliToken,
|
|
1963
|
+
hostname: hostname(),
|
|
1964
|
+
platform: platform()
|
|
1965
|
+
})
|
|
1966
|
+
});
|
|
1967
|
+
if (!response.ok) {
|
|
1968
|
+
const errorText = await response.text();
|
|
1969
|
+
throw new BrowserAuthError("INIT_FAILED", "Failed to initialize browser auth: " + String(response.status) + " " + errorText);
|
|
1970
|
+
}
|
|
1971
|
+
const data = await response.json();
|
|
1972
|
+
return data;
|
|
1973
|
+
}
|
|
1974
|
+
async function pollAuthStatus(endpoint, cliToken) {
|
|
1975
|
+
const response = await fetch(`${endpoint}/api/auth/cli/status?token=${encodeURIComponent(cliToken)}`);
|
|
1976
|
+
if (!response.ok) {
|
|
1977
|
+
const errorText = await response.text();
|
|
1978
|
+
throw new BrowserAuthError("POLL_FAILED", "Failed to poll auth status: " + String(response.status) + " " + errorText);
|
|
1979
|
+
}
|
|
1980
|
+
const data = await response.json();
|
|
1981
|
+
return data;
|
|
1982
|
+
}
|
|
1983
|
+
async function openBrowser(url) {
|
|
1984
|
+
if (process.env.MUTAGENT_TEST_MODE === "true") {
|
|
1985
|
+
console.log(`AUTH_URL:${url}`);
|
|
1986
|
+
return;
|
|
1987
|
+
}
|
|
1988
|
+
try {
|
|
1989
|
+
const { default: open } = await import("open");
|
|
1990
|
+
await open(url);
|
|
1991
|
+
} catch {
|
|
1992
|
+
throw new BrowserAuthError("BROWSER_OPEN_FAILED", `Could not open browser automatically. Please visit: ${url}`);
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
function sleep(ms) {
|
|
1996
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
1997
|
+
}
|
|
1998
|
+
async function performBrowserAuth(options, onStatusUpdate) {
|
|
1999
|
+
const {
|
|
2000
|
+
endpoint,
|
|
2001
|
+
timeout = 300000,
|
|
2002
|
+
pollInterval = 2000,
|
|
2003
|
+
skipBrowserOpen = false
|
|
2004
|
+
} = options;
|
|
2005
|
+
const cliToken = generateCliToken();
|
|
2006
|
+
onStatusUpdate?.("Initializing browser authentication...");
|
|
2007
|
+
const initResponse = await initBrowserAuth(endpoint, cliToken);
|
|
2008
|
+
const { authUrl } = initResponse;
|
|
2009
|
+
if (!skipBrowserOpen) {
|
|
2010
|
+
onStatusUpdate?.("Opening browser for authentication...");
|
|
2011
|
+
try {
|
|
2012
|
+
await openBrowser(authUrl);
|
|
2013
|
+
} catch (error) {
|
|
2014
|
+
if (error instanceof BrowserAuthError && error.code === "BROWSER_OPEN_FAILED") {
|
|
2015
|
+
onStatusUpdate?.(error.message);
|
|
2016
|
+
} else {
|
|
2017
|
+
throw error;
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
console.log("");
|
|
2022
|
+
console.log(" Open this URL to authenticate:");
|
|
2023
|
+
console.log("");
|
|
2024
|
+
console.log(" " + authUrl);
|
|
2025
|
+
console.log("");
|
|
2026
|
+
onStatusUpdate?.("Waiting for browser authentication...");
|
|
2027
|
+
const startTime = Date.now();
|
|
2028
|
+
while (Date.now() - startTime < timeout) {
|
|
2029
|
+
await sleep(pollInterval);
|
|
2030
|
+
const status = await pollAuthStatus(endpoint, cliToken);
|
|
2031
|
+
switch (status.status) {
|
|
2032
|
+
case "pending":
|
|
2033
|
+
continue;
|
|
2034
|
+
case "completed":
|
|
2035
|
+
if (!status.apiKey || !status.workspaceId || !status.workspaceName || !status.organizationId || !status.organizationName) {
|
|
2036
|
+
throw new BrowserAuthError("INCOMPLETE_RESPONSE", "Server returned incomplete auth response");
|
|
2037
|
+
}
|
|
2038
|
+
return {
|
|
2039
|
+
apiKey: status.apiKey,
|
|
2040
|
+
workspaceId: status.workspaceId,
|
|
2041
|
+
workspaceName: status.workspaceName,
|
|
2042
|
+
organizationId: status.organizationId,
|
|
2043
|
+
organizationName: status.organizationName,
|
|
2044
|
+
expiresAt: status.expiresAt
|
|
2045
|
+
};
|
|
2046
|
+
case "expired":
|
|
2047
|
+
throw new BrowserAuthError("AUTH_EXPIRED", "Browser authentication expired. Please try again.");
|
|
2048
|
+
case "denied":
|
|
2049
|
+
throw new BrowserAuthError("AUTH_DENIED", status.error ?? "Browser authentication was denied.");
|
|
2050
|
+
case "not_found":
|
|
2051
|
+
throw new BrowserAuthError("TOKEN_NOT_FOUND", "Authentication token not found. Please try again.");
|
|
2052
|
+
default:
|
|
2053
|
+
throw new BrowserAuthError("UNKNOWN_STATUS", "Unknown auth status: " + String(status.status));
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
throw new BrowserAuthError("AUTH_TIMEOUT", "Browser authentication timed out after 5 minutes. Please try again.");
|
|
2057
|
+
}
|
|
2058
|
+
|
|
2059
|
+
class BrowserAuthError extends Error {
|
|
2060
|
+
code;
|
|
2061
|
+
constructor(code, message) {
|
|
2062
|
+
super(message);
|
|
2063
|
+
this.name = "BrowserAuthError";
|
|
2064
|
+
this.code = code;
|
|
2065
|
+
}
|
|
2066
|
+
getSuggestion() {
|
|
2067
|
+
switch (this.code) {
|
|
2068
|
+
case "INIT_FAILED":
|
|
2069
|
+
return "Check your endpoint configuration and network connection.";
|
|
2070
|
+
case "POLL_FAILED":
|
|
2071
|
+
return "Check your network connection and try again.";
|
|
2072
|
+
case "BROWSER_OPEN_FAILED":
|
|
2073
|
+
return "Copy the URL above and open it manually in your browser.";
|
|
2074
|
+
case "AUTH_EXPIRED":
|
|
2075
|
+
case "AUTH_TIMEOUT":
|
|
2076
|
+
return 'Run "mutagent auth login" again to restart authentication.';
|
|
2077
|
+
case "AUTH_DENIED":
|
|
2078
|
+
return "Ensure you have access to the workspace and try again.";
|
|
2079
|
+
case "TOKEN_NOT_FOUND":
|
|
2080
|
+
case "INCOMPLETE_RESPONSE":
|
|
2081
|
+
case "UNKNOWN_STATUS":
|
|
2082
|
+
return "Please try again. If the issue persists, contact support.";
|
|
2083
|
+
default:
|
|
2084
|
+
return "Please try again.";
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
|
|
2089
|
+
// src/lib/auth-flow.ts
|
|
2090
|
+
async function performLoginAction(opts) {
|
|
2091
|
+
const { isJson, output } = opts;
|
|
2092
|
+
const wasFirstLogin = !hasCredentials();
|
|
2093
|
+
const envApiKey = process.env.MUTAGENT_API_KEY;
|
|
2094
|
+
const endpoint = process.env.MUTAGENT_ENDPOINT ?? opts.endpoint;
|
|
2095
|
+
if (envApiKey) {
|
|
2096
|
+
return loginWithExistingKey(envApiKey, endpoint, output, wasFirstLogin);
|
|
2097
|
+
}
|
|
2098
|
+
const isNonInteractive = opts.nonInteractive === true || process.env.MUTAGENT_NON_INTERACTIVE === "true" || process.env.CI === "true" || !process.stdin.isTTY;
|
|
2099
|
+
if (isJson && !opts.browser && isNonInteractive) {
|
|
2100
|
+
throw new MutagentError("INTERACTIVE_REQUIRED", "No API key provided. Set MUTAGENT_API_KEY env var or add --browser for browser auth.", "Run: export MUTAGENT_API_KEY=<key> or mutagent login --browser --non-interactive");
|
|
2101
|
+
}
|
|
2102
|
+
if (!isNonInteractive && wasFirstLogin) {
|
|
2103
|
+
console.log(`
|
|
2104
|
+
` + chalk3.bold.cyan(" Welcome to MutagenT CLI!") + `
|
|
2105
|
+
`);
|
|
2106
|
+
console.log(` No credentials found. Please authenticate to continue.
|
|
2107
|
+
`);
|
|
2108
|
+
}
|
|
2109
|
+
let useBrowserAuth = opts.browser === true;
|
|
2110
|
+
if (!useBrowserAuth && isNonInteractive) {
|
|
2111
|
+
output.info("Non-interactive environment detected. Using browser authentication.");
|
|
2112
|
+
useBrowserAuth = true;
|
|
2113
|
+
}
|
|
2114
|
+
if (!useBrowserAuth) {
|
|
2115
|
+
const methodAnswer = await inquirer.prompt([
|
|
2116
|
+
{
|
|
2117
|
+
type: "list",
|
|
2118
|
+
name: "method",
|
|
2119
|
+
message: "How would you like to authenticate?",
|
|
2120
|
+
choices: [
|
|
2121
|
+
{ name: "Login (opens browser)", value: "browser" },
|
|
2122
|
+
{ name: "API Key (paste existing key)", value: "apiKey" }
|
|
2123
|
+
]
|
|
2124
|
+
}
|
|
2125
|
+
]);
|
|
2126
|
+
useBrowserAuth = methodAnswer.method === "browser";
|
|
2127
|
+
}
|
|
2128
|
+
if (useBrowserAuth) {
|
|
2129
|
+
return loginWithBrowser(endpoint, output, wasFirstLogin);
|
|
2130
|
+
}
|
|
2131
|
+
return loginWithPastedKey(endpoint, output, wasFirstLogin);
|
|
2132
|
+
}
|
|
2133
|
+
function buildLoginJsonResponse(result) {
|
|
2134
|
+
return {
|
|
2135
|
+
success: true,
|
|
2136
|
+
authenticated: result.authenticated,
|
|
2137
|
+
endpoint: result.endpoint,
|
|
2138
|
+
workspace: result.workspace,
|
|
2139
|
+
organization: result.organization,
|
|
2140
|
+
_directive: {
|
|
2141
|
+
instruction: "Verify workspace. Run: mutagent workspaces list --json",
|
|
2142
|
+
next: ["mutagent workspaces list --json", "mutagent prompts list --json"]
|
|
2143
|
+
}
|
|
2144
|
+
};
|
|
2145
|
+
}
|
|
2146
|
+
async function loginWithExistingKey(apiKey, endpoint, output, wasFirstLogin) {
|
|
2147
|
+
output.info("Validating API key...");
|
|
2148
|
+
const isValid = await validateApiKey(apiKey, endpoint);
|
|
2149
|
+
if (!isValid) {
|
|
2150
|
+
throw new MutagentError("INVALID_API_KEY", "Invalid API key or endpoint", "Check your API key and try again");
|
|
2151
|
+
}
|
|
2152
|
+
const orgs = await fetchOrganizations(apiKey, endpoint);
|
|
2153
|
+
let orgId;
|
|
2154
|
+
let orgName;
|
|
2155
|
+
let wsId;
|
|
2156
|
+
let wsName;
|
|
2157
|
+
if (orgs.length >= 1 && orgs[0]) {
|
|
2158
|
+
orgId = orgs[0].id;
|
|
2159
|
+
orgName = orgs[0].name;
|
|
2160
|
+
const workspaces = await fetchWorkspaces(apiKey, endpoint, orgId);
|
|
2161
|
+
const defaultWs = workspaces.find((w) => w.isDefault) ?? workspaces[0];
|
|
2162
|
+
if (defaultWs) {
|
|
2163
|
+
wsId = defaultWs.id;
|
|
2164
|
+
wsName = defaultWs.name;
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
saveFullCredentials({
|
|
2168
|
+
apiKey,
|
|
2169
|
+
endpoint,
|
|
2170
|
+
workspaceId: wsId,
|
|
2171
|
+
organizationId: orgId
|
|
2172
|
+
});
|
|
2173
|
+
return {
|
|
2174
|
+
authenticated: true,
|
|
2175
|
+
apiKey,
|
|
2176
|
+
endpoint,
|
|
2177
|
+
workspace: wsId ? { id: wsId, name: wsName } : null,
|
|
2178
|
+
organization: orgId ? { id: orgId, name: orgName } : null,
|
|
2179
|
+
wasFirstLogin
|
|
2180
|
+
};
|
|
2181
|
+
}
|
|
2182
|
+
async function loginWithBrowser(endpoint, output, wasFirstLogin) {
|
|
2183
|
+
const spinner = ora({ text: "Opening browser for authentication...", spinner: "dots" });
|
|
2184
|
+
try {
|
|
2185
|
+
spinner.start();
|
|
2186
|
+
const result = await performBrowserAuth({ endpoint, timeout: 300000, pollInterval: 2000 }, (message) => {
|
|
2187
|
+
spinner.text = message;
|
|
2188
|
+
});
|
|
2189
|
+
spinner.succeed("Authenticated successfully!");
|
|
2190
|
+
saveFullCredentials({
|
|
2191
|
+
apiKey: result.apiKey,
|
|
2192
|
+
endpoint,
|
|
2193
|
+
workspaceId: result.workspaceId,
|
|
2194
|
+
organizationId: result.organizationId,
|
|
2195
|
+
expiresAt: result.expiresAt
|
|
2196
|
+
});
|
|
2197
|
+
if (result.workspaceName)
|
|
2198
|
+
output.info(`Workspace: ${result.workspaceName}`);
|
|
2199
|
+
if (result.organizationName)
|
|
2200
|
+
output.info(`Organization: ${result.organizationName}`);
|
|
2201
|
+
return {
|
|
2202
|
+
authenticated: true,
|
|
2203
|
+
apiKey: result.apiKey,
|
|
2204
|
+
endpoint,
|
|
2205
|
+
workspace: result.workspaceId ? { id: result.workspaceId, name: result.workspaceName } : null,
|
|
2206
|
+
organization: result.organizationId ? { id: result.organizationId, name: result.organizationName } : null,
|
|
2207
|
+
wasFirstLogin
|
|
2208
|
+
};
|
|
2209
|
+
} catch (error) {
|
|
2210
|
+
spinner.fail("Authentication failed");
|
|
2211
|
+
if (error instanceof BrowserAuthError) {
|
|
2212
|
+
throw new MutagentError(error.code, error.message, error.getSuggestion());
|
|
2213
|
+
}
|
|
2214
|
+
throw error;
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
async function loginWithPastedKey(initialEndpoint, output, wasFirstLogin) {
|
|
2218
|
+
const answers = await inquirer.prompt([
|
|
2219
|
+
{
|
|
2220
|
+
type: "input",
|
|
2221
|
+
name: "endpoint",
|
|
2222
|
+
message: "MutagenT endpoint:",
|
|
2223
|
+
default: initialEndpoint
|
|
2224
|
+
},
|
|
2225
|
+
{
|
|
2226
|
+
type: "password",
|
|
2227
|
+
name: "apiKey",
|
|
2228
|
+
message: "API Key:",
|
|
2229
|
+
mask: "*",
|
|
2230
|
+
validate: (input) => input.length > 0 || "API key is required"
|
|
2231
|
+
}
|
|
2232
|
+
]);
|
|
2233
|
+
const apiKey = answers.apiKey;
|
|
2234
|
+
const endpoint = answers.endpoint;
|
|
2235
|
+
output.info("Validating API key...");
|
|
2236
|
+
const isValid = await validateApiKey(apiKey, endpoint);
|
|
2237
|
+
if (!isValid) {
|
|
2238
|
+
throw new MutagentError("INVALID_API_KEY", "Invalid API key or endpoint", "Check your API key and try again");
|
|
2239
|
+
}
|
|
2240
|
+
let selectedOrgId;
|
|
2241
|
+
let selectedOrgName;
|
|
2242
|
+
let selectedWsId;
|
|
2243
|
+
let selectedWsName;
|
|
2244
|
+
const orgs = await fetchOrganizations(apiKey, endpoint);
|
|
2245
|
+
if (orgs.length === 1 && orgs[0]) {
|
|
2246
|
+
selectedOrgId = orgs[0].id;
|
|
2247
|
+
selectedOrgName = orgs[0].name;
|
|
2248
|
+
} else if (orgs.length > 1) {
|
|
2249
|
+
const orgAnswer = await inquirer.prompt([
|
|
2250
|
+
{
|
|
2251
|
+
type: "list",
|
|
2252
|
+
name: "orgId",
|
|
2253
|
+
message: "Select organization:",
|
|
2254
|
+
choices: orgs.map((o) => ({ name: o.name, value: o.id }))
|
|
2255
|
+
}
|
|
2256
|
+
]);
|
|
2257
|
+
selectedOrgId = orgAnswer.orgId;
|
|
2258
|
+
selectedOrgName = orgs.find((o) => o.id === selectedOrgId)?.name;
|
|
2259
|
+
}
|
|
2260
|
+
if (selectedOrgId) {
|
|
2261
|
+
const workspaces = await fetchWorkspaces(apiKey, endpoint, selectedOrgId);
|
|
2262
|
+
const defaultWs = workspaces.find((w) => w.isDefault);
|
|
2263
|
+
if (workspaces.length === 1 && workspaces[0]) {
|
|
2264
|
+
selectedWsId = workspaces[0].id;
|
|
2265
|
+
selectedWsName = workspaces[0].name;
|
|
2266
|
+
} else if (defaultWs) {
|
|
2267
|
+
selectedWsId = defaultWs.id;
|
|
2268
|
+
selectedWsName = defaultWs.name;
|
|
2269
|
+
} else if (workspaces.length > 1) {
|
|
2270
|
+
const wsAnswer = await inquirer.prompt([
|
|
2271
|
+
{
|
|
2272
|
+
type: "list",
|
|
2273
|
+
name: "wsId",
|
|
2274
|
+
message: "Select workspace:",
|
|
2275
|
+
choices: workspaces.map((w) => ({
|
|
2276
|
+
name: w.name + (w.isDefault ? " (default)" : ""),
|
|
2277
|
+
value: w.id
|
|
2278
|
+
}))
|
|
2279
|
+
}
|
|
2280
|
+
]);
|
|
2281
|
+
selectedWsId = wsAnswer.wsId;
|
|
2282
|
+
selectedWsName = workspaces.find((w) => w.id === selectedWsId)?.name;
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
saveFullCredentials({
|
|
2286
|
+
apiKey,
|
|
2287
|
+
endpoint,
|
|
2288
|
+
workspaceId: selectedWsId,
|
|
2289
|
+
organizationId: selectedOrgId
|
|
2290
|
+
});
|
|
2291
|
+
return {
|
|
2292
|
+
authenticated: true,
|
|
2293
|
+
apiKey,
|
|
2294
|
+
endpoint,
|
|
2295
|
+
workspace: selectedWsId ? { id: selectedWsId, name: selectedWsName } : null,
|
|
2296
|
+
organization: selectedOrgId ? { id: selectedOrgId, name: selectedOrgName } : null,
|
|
2297
|
+
wasFirstLogin
|
|
2298
|
+
};
|
|
2299
|
+
}
|
|
2300
|
+
|
|
2083
2301
|
// src/commands/auth.ts
|
|
2084
2302
|
function createAuthCommand() {
|
|
2085
2303
|
const auth = new Command("auth").description("Authenticate with MutagenT platform").addHelpText("after", `
|
|
2086
2304
|
Examples:
|
|
2087
|
-
${
|
|
2088
|
-
${
|
|
2089
|
-
${
|
|
2090
|
-
${
|
|
2305
|
+
${chalk4.dim("$")} mutagent auth login
|
|
2306
|
+
${chalk4.dim("$")} mutagent auth login --browser
|
|
2307
|
+
${chalk4.dim("$")} mutagent auth status
|
|
2308
|
+
${chalk4.dim("$")} mutagent auth logout
|
|
2091
2309
|
`);
|
|
2092
2310
|
auth.command("login").description("Authenticate and store API key").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", `
|
|
2093
2311
|
Examples:
|
|
2094
|
-
${
|
|
2095
|
-
${
|
|
2096
|
-
${
|
|
2312
|
+
${chalk4.dim("$")} mutagent auth login ${chalk4.dim("# Interactive (choose method)")}
|
|
2313
|
+
${chalk4.dim("$")} mutagent auth login --browser ${chalk4.dim("# Browser OAuth flow")}
|
|
2314
|
+
${chalk4.dim("$")} mutagent auth login --non-interactive ${chalk4.dim("# Auto browser flow (AI agents)")}
|
|
2097
2315
|
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
MUTAGENT_ENDPOINT Custom API endpoint
|
|
2101
|
-
MUTAGENT_NON_INTERACTIVE=true Non-interactive mode (auto browser auth)
|
|
2102
|
-
CI=true Enables non-interactive mode
|
|
2316
|
+
${chalk4.dim("Note: this command is an alias for `mutagent login`.")}
|
|
2317
|
+
${chalk4.dim("See `mutagent login --help` for full documentation.")}
|
|
2103
2318
|
`).action(async (options) => {
|
|
2104
2319
|
const isJson = getJsonFlag(auth);
|
|
2105
2320
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
2106
2321
|
try {
|
|
2107
|
-
const
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
if (apiKey) {
|
|
2115
|
-
output.info("Validating API key...");
|
|
2116
|
-
const isValid = await validateApiKey(apiKey, endpoint);
|
|
2117
|
-
if (!isValid) {
|
|
2118
|
-
throw new MutagentError("INVALID_API_KEY", "Invalid API key or endpoint", "Check your API key and try again");
|
|
2119
|
-
}
|
|
2120
|
-
const orgs = await fetchOrganizations(apiKey, endpoint);
|
|
2121
|
-
let orgId;
|
|
2122
|
-
let wsId;
|
|
2123
|
-
if (orgs.length >= 1 && orgs[0]) {
|
|
2124
|
-
orgId = orgs[0].id;
|
|
2125
|
-
const workspaces = await fetchWorkspaces(apiKey, endpoint, orgId);
|
|
2126
|
-
const defaultWs = workspaces.find((w) => w.isDefault);
|
|
2127
|
-
wsId = defaultWs?.id ?? workspaces[0]?.id;
|
|
2128
|
-
}
|
|
2129
|
-
saveFullCredentials({
|
|
2130
|
-
apiKey,
|
|
2131
|
-
endpoint,
|
|
2132
|
-
workspaceId: wsId,
|
|
2133
|
-
organizationId: orgId
|
|
2134
|
-
});
|
|
2135
|
-
output.success("Authenticated successfully");
|
|
2136
|
-
if (isJson) {
|
|
2137
|
-
output.output({
|
|
2138
|
-
success: true,
|
|
2139
|
-
authenticated: true,
|
|
2140
|
-
endpoint,
|
|
2141
|
-
workspace: wsId ? { id: wsId } : null,
|
|
2142
|
-
organization: orgId ? { id: orgId } : null,
|
|
2143
|
-
_directive: {
|
|
2144
|
-
instruction: "Verify workspace. Run: mutagent workspaces list --json",
|
|
2145
|
-
next: ["mutagent workspaces list --json", "mutagent prompts list --json"]
|
|
2146
|
-
}
|
|
2147
|
-
});
|
|
2148
|
-
} else {
|
|
2149
|
-
output.info(`Endpoint: ${endpoint}`);
|
|
2150
|
-
output.info("Next: mutagent workspaces list --json");
|
|
2151
|
-
}
|
|
2152
|
-
return;
|
|
2153
|
-
}
|
|
2154
|
-
const isNonInteractive = options.nonInteractive === true || process.env.MUTAGENT_NON_INTERACTIVE === "true" || process.env.CI === "true" || !process.stdin.isTTY;
|
|
2155
|
-
if (isJson && !options.browser && isNonInteractive) {
|
|
2156
|
-
throw new MutagentError("INTERACTIVE_REQUIRED", "No API key provided. Set MUTAGENT_API_KEY env var or add --browser for browser auth.", "Run: export MUTAGENT_API_KEY=<key> or mutagent auth login --browser --non-interactive");
|
|
2157
|
-
}
|
|
2158
|
-
if (!isNonInteractive && !hasCredentials()) {
|
|
2159
|
-
console.log(`
|
|
2160
|
-
` + chalk3.bold.cyan(" Welcome to MutagenT CLI!") + `
|
|
2161
|
-
`);
|
|
2162
|
-
console.log(` No credentials found. Please authenticate to continue.
|
|
2163
|
-
`);
|
|
2164
|
-
}
|
|
2165
|
-
let useLocalBrowserAuth = options.browser === true;
|
|
2166
|
-
if (!useLocalBrowserAuth && isNonInteractive) {
|
|
2167
|
-
output.info("Non-interactive environment detected. Using browser authentication.");
|
|
2168
|
-
useLocalBrowserAuth = true;
|
|
2169
|
-
}
|
|
2170
|
-
if (!useLocalBrowserAuth) {
|
|
2171
|
-
const methodAnswer = await inquirer.prompt([
|
|
2172
|
-
{
|
|
2173
|
-
type: "list",
|
|
2174
|
-
name: "method",
|
|
2175
|
-
message: "How would you like to authenticate?",
|
|
2176
|
-
choices: [
|
|
2177
|
-
{
|
|
2178
|
-
name: "Login (opens browser)",
|
|
2179
|
-
value: "browser"
|
|
2180
|
-
},
|
|
2181
|
-
{
|
|
2182
|
-
name: "API Key (paste existing key)",
|
|
2183
|
-
value: "apiKey"
|
|
2184
|
-
}
|
|
2185
|
-
]
|
|
2186
|
-
}
|
|
2187
|
-
]);
|
|
2188
|
-
useLocalBrowserAuth = methodAnswer.method === "browser";
|
|
2189
|
-
}
|
|
2190
|
-
if (useLocalBrowserAuth) {
|
|
2191
|
-
const spinner = ora({
|
|
2192
|
-
text: "Opening browser for authentication...",
|
|
2193
|
-
spinner: "dots"
|
|
2194
|
-
});
|
|
2195
|
-
try {
|
|
2196
|
-
spinner.start();
|
|
2197
|
-
const result = await performBrowserAuth({
|
|
2198
|
-
endpoint,
|
|
2199
|
-
timeout: 300000,
|
|
2200
|
-
pollInterval: 2000
|
|
2201
|
-
}, (message) => {
|
|
2202
|
-
spinner.text = message;
|
|
2203
|
-
});
|
|
2204
|
-
spinner.succeed("Authenticated successfully!");
|
|
2205
|
-
saveFullCredentials({
|
|
2206
|
-
apiKey: result.apiKey,
|
|
2207
|
-
endpoint,
|
|
2208
|
-
workspaceId: result.workspaceId,
|
|
2209
|
-
organizationId: result.organizationId,
|
|
2210
|
-
expiresAt: result.expiresAt
|
|
2211
|
-
});
|
|
2212
|
-
apiKey = result.apiKey;
|
|
2213
|
-
workspaceName = result.workspaceName;
|
|
2214
|
-
organizationName = result.organizationName;
|
|
2215
|
-
loginWorkspaceId = result.workspaceId;
|
|
2216
|
-
loginOrgId = result.organizationId;
|
|
2217
|
-
console.log("");
|
|
2218
|
-
output.info("Workspace: " + workspaceName);
|
|
2219
|
-
output.info("Organization: " + organizationName);
|
|
2220
|
-
output.info("Endpoint: " + endpoint);
|
|
2221
|
-
} catch (error) {
|
|
2222
|
-
spinner.fail("Authentication failed");
|
|
2223
|
-
if (error instanceof BrowserAuthError) {
|
|
2224
|
-
throw new MutagentError(error.code, error.message, error.getSuggestion());
|
|
2225
|
-
}
|
|
2226
|
-
throw error;
|
|
2227
|
-
}
|
|
2228
|
-
} else {
|
|
2229
|
-
const answers = await inquirer.prompt([
|
|
2230
|
-
{
|
|
2231
|
-
type: "input",
|
|
2232
|
-
name: "endpoint",
|
|
2233
|
-
message: "MutagenT endpoint:",
|
|
2234
|
-
default: endpoint
|
|
2235
|
-
},
|
|
2236
|
-
{
|
|
2237
|
-
type: "password",
|
|
2238
|
-
name: "apiKey",
|
|
2239
|
-
message: "API Key:",
|
|
2240
|
-
mask: "*",
|
|
2241
|
-
validate: (input) => input.length > 0 || "API key is required"
|
|
2242
|
-
}
|
|
2243
|
-
]);
|
|
2244
|
-
apiKey = answers.apiKey;
|
|
2245
|
-
endpoint = answers.endpoint;
|
|
2246
|
-
output.info("Validating API key...");
|
|
2247
|
-
const isValid = await validateApiKey(apiKey, endpoint);
|
|
2248
|
-
if (!isValid) {
|
|
2249
|
-
throw new MutagentError("INVALID_API_KEY", "Invalid API key or endpoint", "Check your API key and try again");
|
|
2250
|
-
}
|
|
2251
|
-
let selectedOrgId;
|
|
2252
|
-
let selectedOrgName;
|
|
2253
|
-
let selectedWsId;
|
|
2254
|
-
let selectedWsName;
|
|
2255
|
-
const orgs = await fetchOrganizations(apiKey, endpoint);
|
|
2256
|
-
if (orgs.length === 1 && orgs[0]) {
|
|
2257
|
-
selectedOrgId = orgs[0].id;
|
|
2258
|
-
selectedOrgName = orgs[0].name;
|
|
2259
|
-
} else if (orgs.length > 1) {
|
|
2260
|
-
const orgAnswer = await inquirer.prompt([{
|
|
2261
|
-
type: "list",
|
|
2262
|
-
name: "orgId",
|
|
2263
|
-
message: "Select organization:",
|
|
2264
|
-
choices: orgs.map((o) => ({ name: o.name, value: o.id }))
|
|
2265
|
-
}]);
|
|
2266
|
-
selectedOrgId = orgAnswer.orgId;
|
|
2267
|
-
selectedOrgName = orgs.find((o) => o.id === selectedOrgId)?.name;
|
|
2268
|
-
}
|
|
2269
|
-
if (selectedOrgId) {
|
|
2270
|
-
const workspaces = await fetchWorkspaces(apiKey, endpoint, selectedOrgId);
|
|
2271
|
-
const defaultWs = workspaces.find((w) => w.isDefault);
|
|
2272
|
-
if (workspaces.length === 1 && workspaces[0]) {
|
|
2273
|
-
selectedWsId = workspaces[0].id;
|
|
2274
|
-
selectedWsName = workspaces[0].name;
|
|
2275
|
-
} else if (defaultWs) {
|
|
2276
|
-
selectedWsId = defaultWs.id;
|
|
2277
|
-
selectedWsName = defaultWs.name;
|
|
2278
|
-
} else if (workspaces.length > 1) {
|
|
2279
|
-
const wsAnswer = await inquirer.prompt([{
|
|
2280
|
-
type: "list",
|
|
2281
|
-
name: "wsId",
|
|
2282
|
-
message: "Select workspace:",
|
|
2283
|
-
choices: workspaces.map((w) => ({ name: w.name + (w.isDefault ? " (default)" : ""), value: w.id }))
|
|
2284
|
-
}]);
|
|
2285
|
-
selectedWsId = wsAnswer.wsId;
|
|
2286
|
-
selectedWsName = workspaces.find((w) => w.id === selectedWsId)?.name;
|
|
2287
|
-
}
|
|
2288
|
-
}
|
|
2289
|
-
saveFullCredentials({
|
|
2290
|
-
apiKey,
|
|
2291
|
-
endpoint,
|
|
2292
|
-
workspaceId: selectedWsId,
|
|
2293
|
-
organizationId: selectedOrgId
|
|
2294
|
-
});
|
|
2295
|
-
workspaceName = selectedWsName;
|
|
2296
|
-
organizationName = selectedOrgName;
|
|
2297
|
-
loginWorkspaceId = selectedWsId;
|
|
2298
|
-
loginOrgId = selectedOrgId;
|
|
2299
|
-
output.success("Authenticated successfully");
|
|
2300
|
-
if (selectedOrgName)
|
|
2301
|
-
output.info("Organization: " + selectedOrgName);
|
|
2302
|
-
if (selectedWsName)
|
|
2303
|
-
output.info("Workspace: " + selectedWsName);
|
|
2304
|
-
output.info("Endpoint: " + endpoint);
|
|
2305
|
-
}
|
|
2322
|
+
const result = await performLoginAction({
|
|
2323
|
+
endpoint: options.endpoint,
|
|
2324
|
+
browser: options.browser,
|
|
2325
|
+
nonInteractive: options.nonInteractive,
|
|
2326
|
+
isJson,
|
|
2327
|
+
output
|
|
2328
|
+
});
|
|
2306
2329
|
if (isJson) {
|
|
2307
|
-
output.output(
|
|
2308
|
-
success: true,
|
|
2309
|
-
authenticated: true,
|
|
2310
|
-
endpoint,
|
|
2311
|
-
workspace: loginWorkspaceId ? { id: loginWorkspaceId, name: workspaceName } : null,
|
|
2312
|
-
organization: loginOrgId ? { id: loginOrgId, name: organizationName } : null,
|
|
2313
|
-
_directive: {
|
|
2314
|
-
instruction: "Verify workspace. Run: mutagent workspaces list --json",
|
|
2315
|
-
next: ["mutagent workspaces list --json", "mutagent prompts list --json"]
|
|
2316
|
-
}
|
|
2317
|
-
});
|
|
2330
|
+
output.output(buildLoginJsonResponse(result));
|
|
2318
2331
|
} else {
|
|
2332
|
+
output.success("Authenticated successfully");
|
|
2333
|
+
if (result.organization?.name)
|
|
2334
|
+
output.info(`Organization: ${result.organization.name}`);
|
|
2335
|
+
if (result.workspace?.name)
|
|
2336
|
+
output.info(`Workspace: ${result.workspace.name}`);
|
|
2337
|
+
output.info(`Endpoint: ${result.endpoint}`);
|
|
2319
2338
|
output.info("Next: mutagent workspaces list --json");
|
|
2320
2339
|
}
|
|
2321
|
-
if (wasFirstLogin && process.stdin.isTTY && !isJson) {
|
|
2340
|
+
if (result.wasFirstLogin && process.stdin.isTTY && !isJson) {
|
|
2322
2341
|
await runPostOnboarding();
|
|
2323
2342
|
}
|
|
2324
2343
|
} catch (error) {
|
|
@@ -2331,8 +2350,8 @@ Environment Variables:
|
|
|
2331
2350
|
});
|
|
2332
2351
|
auth.command("status").description("Check authentication status").addHelpText("after", `
|
|
2333
2352
|
Examples:
|
|
2334
|
-
${
|
|
2335
|
-
${
|
|
2353
|
+
${chalk4.dim("$")} mutagent auth status
|
|
2354
|
+
${chalk4.dim("$")} mutagent auth status --json
|
|
2336
2355
|
`).action(async () => {
|
|
2337
2356
|
const isJson = getJsonFlag(auth);
|
|
2338
2357
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -2425,7 +2444,7 @@ Examples:
|
|
|
2425
2444
|
});
|
|
2426
2445
|
auth.command("logout").description("Clear stored credentials").addHelpText("after", `
|
|
2427
2446
|
Examples:
|
|
2428
|
-
${
|
|
2447
|
+
${chalk4.dim("$")} mutagent auth logout
|
|
2429
2448
|
`).action(() => {
|
|
2430
2449
|
const isJson = getJsonFlag(auth);
|
|
2431
2450
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -2436,179 +2455,70 @@ Examples:
|
|
|
2436
2455
|
}
|
|
2437
2456
|
|
|
2438
2457
|
// src/commands/login.ts
|
|
2439
|
-
init_config();
|
|
2440
|
-
init_sdk_client();
|
|
2441
2458
|
import { Command as Command2 } from "commander";
|
|
2442
|
-
import
|
|
2443
|
-
import chalk4 from "chalk";
|
|
2444
|
-
import ora2 from "ora";
|
|
2459
|
+
import chalk5 from "chalk";
|
|
2445
2460
|
init_errors();
|
|
2446
2461
|
function createLoginCommand() {
|
|
2447
|
-
const login = new Command2("login").description("Login to MutagenT
|
|
2462
|
+
const login = new Command2("login").description("Login to MutagenT (browser OAuth — signup, onboard, authorize CLI in one flow)").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", `
|
|
2448
2463
|
Examples:
|
|
2449
|
-
${
|
|
2450
|
-
${
|
|
2451
|
-
${
|
|
2464
|
+
${chalk5.dim("$")} mutagent login ${chalk5.dim("# Browser OAuth (recommended — handles signup + onboarding)")}
|
|
2465
|
+
${chalk5.dim("$")} mutagent login --browser ${chalk5.dim("# Force browser flow (skip method prompt)")}
|
|
2466
|
+
${chalk5.dim("$")} mutagent login --non-interactive ${chalk5.dim("# Auto-browser for AI agents and CI")}
|
|
2467
|
+
|
|
2468
|
+
${chalk5.yellow("Browser OAuth flow (recommended for end users):")}
|
|
2469
|
+
Opens app.mutagent.io in your browser. You will:
|
|
2470
|
+
1. Sign in or sign up with your account
|
|
2471
|
+
2. Complete onboarding (workspace, provider config)
|
|
2472
|
+
3. Authorize this CLI session
|
|
2473
|
+
The CLI polls for completion and saves credentials when you authorize.
|
|
2474
|
+
|
|
2475
|
+
${chalk5.yellow("Automation / CI / AI Agents:")}
|
|
2476
|
+
Set MUTAGENT_API_KEY environment variable before running:
|
|
2477
|
+
${chalk5.dim("$")} export MUTAGENT_API_KEY=mt_...
|
|
2478
|
+
${chalk5.dim("$")} mutagent login --json
|
|
2479
|
+
When MUTAGENT_API_KEY is set, login skips the browser flow entirely and
|
|
2480
|
+
validates the key directly. This is the canonical CI / agent path.
|
|
2452
2481
|
|
|
2453
2482
|
Environment Variables:
|
|
2454
|
-
MUTAGENT_API_KEY API key (skips interactive
|
|
2483
|
+
MUTAGENT_API_KEY Pre-existing API key (skips interactive flow)
|
|
2455
2484
|
MUTAGENT_ENDPOINT Custom API endpoint
|
|
2485
|
+
MUTAGENT_NON_INTERACTIVE=true Treat environment as non-interactive
|
|
2486
|
+
CI=true Automatically enables non-interactive mode
|
|
2487
|
+
|
|
2488
|
+
Verify after login:
|
|
2489
|
+
${chalk5.dim("$")} mutagent auth status ${chalk5.dim("# Show session, workspace, org")}
|
|
2490
|
+
${chalk5.dim("$")} mutagent workspaces list --json ${chalk5.dim("# List available workspaces")}
|
|
2491
|
+
|
|
2492
|
+
${chalk5.dim("Note: `mutagent auth login` is a back-compat alias and behaves identically.")}
|
|
2456
2493
|
`).action(async (options) => {
|
|
2457
2494
|
const isJson = getJsonFlag(login);
|
|
2458
2495
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
2459
2496
|
try {
|
|
2460
|
-
const
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
const org = orgs[0];
|
|
2470
|
-
let workspaceId;
|
|
2471
|
-
if (org) {
|
|
2472
|
-
const workspaces = await fetchWorkspaces(apiKey, endpoint, org.id);
|
|
2473
|
-
const defaultWs = workspaces.find((ws) => ws.isDefault) ?? workspaces[0];
|
|
2474
|
-
if (defaultWs)
|
|
2475
|
-
workspaceId = defaultWs.id;
|
|
2476
|
-
}
|
|
2477
|
-
saveFullCredentials({
|
|
2478
|
-
apiKey,
|
|
2479
|
-
endpoint,
|
|
2480
|
-
organizationId: org?.id,
|
|
2481
|
-
workspaceId
|
|
2482
|
-
});
|
|
2483
|
-
output.success("Logged in successfully");
|
|
2484
|
-
if (!isJson) {
|
|
2485
|
-
output.info(`Endpoint: ${endpoint}`);
|
|
2486
|
-
if (org)
|
|
2487
|
-
output.info(`Organization: ${org.name}`);
|
|
2488
|
-
}
|
|
2489
|
-
return;
|
|
2490
|
-
}
|
|
2491
|
-
const isNonInteractive = options.nonInteractive === true || process.env.MUTAGENT_NON_INTERACTIVE === "true" || process.env.CI === "true" || !process.stdin.isTTY;
|
|
2492
|
-
if (isJson && !options.browser && isNonInteractive) {
|
|
2493
|
-
throw new MutagentError("INTERACTIVE_REQUIRED", "No API key provided. Set MUTAGENT_API_KEY env var or add --browser for browser auth.", "Run: export MUTAGENT_API_KEY=<key> or mutagent login --browser --non-interactive");
|
|
2494
|
-
}
|
|
2495
|
-
if (!isNonInteractive && !hasCredentials()) {
|
|
2496
|
-
console.log(`
|
|
2497
|
-
` + chalk4.bold.cyan(" Welcome to MutagenT CLI!") + `
|
|
2498
|
-
`);
|
|
2499
|
-
console.log(` No credentials found. Please authenticate to continue.
|
|
2500
|
-
`);
|
|
2501
|
-
}
|
|
2502
|
-
let useBrowserAuth = options.browser === true;
|
|
2503
|
-
if (!useBrowserAuth && isNonInteractive) {
|
|
2504
|
-
output.info("Non-interactive environment detected. Using browser authentication.");
|
|
2505
|
-
useBrowserAuth = true;
|
|
2506
|
-
}
|
|
2507
|
-
if (!useBrowserAuth) {
|
|
2508
|
-
const methodAnswer = await inquirer2.prompt([
|
|
2509
|
-
{
|
|
2510
|
-
type: "list",
|
|
2511
|
-
name: "method",
|
|
2512
|
-
message: "How would you like to authenticate?",
|
|
2513
|
-
choices: [
|
|
2514
|
-
{
|
|
2515
|
-
name: "Login (opens browser)",
|
|
2516
|
-
value: "browser"
|
|
2517
|
-
},
|
|
2518
|
-
{
|
|
2519
|
-
name: "API Key (paste existing key)",
|
|
2520
|
-
value: "apiKey"
|
|
2521
|
-
}
|
|
2522
|
-
]
|
|
2523
|
-
}
|
|
2524
|
-
]);
|
|
2525
|
-
useBrowserAuth = methodAnswer.method === "browser";
|
|
2526
|
-
}
|
|
2527
|
-
if (useBrowserAuth) {
|
|
2528
|
-
const spinner = ora2({
|
|
2529
|
-
text: "Opening browser for authentication...",
|
|
2530
|
-
spinner: "dots"
|
|
2531
|
-
});
|
|
2532
|
-
try {
|
|
2533
|
-
spinner.start();
|
|
2534
|
-
const result = await performBrowserAuth({
|
|
2535
|
-
endpoint,
|
|
2536
|
-
timeout: 300000,
|
|
2537
|
-
pollInterval: 2000
|
|
2538
|
-
}, (message) => {
|
|
2539
|
-
spinner.text = message;
|
|
2540
|
-
});
|
|
2541
|
-
spinner.succeed("Logged in successfully!");
|
|
2542
|
-
saveFullCredentials({
|
|
2543
|
-
apiKey: result.apiKey,
|
|
2544
|
-
endpoint,
|
|
2545
|
-
workspaceId: result.workspaceId,
|
|
2546
|
-
organizationId: result.organizationId
|
|
2547
|
-
});
|
|
2548
|
-
console.log("");
|
|
2549
|
-
if (result.workspaceName) {
|
|
2550
|
-
output.info(`Workspace: ${result.workspaceName}`);
|
|
2551
|
-
}
|
|
2552
|
-
if (result.organizationName) {
|
|
2553
|
-
output.info(`Organization: ${result.organizationName}`);
|
|
2554
|
-
}
|
|
2555
|
-
} catch (error) {
|
|
2556
|
-
spinner.fail("Authentication failed");
|
|
2557
|
-
if (error instanceof BrowserAuthError) {
|
|
2558
|
-
throw new MutagentError(error.code, error.message, error.getSuggestion());
|
|
2559
|
-
}
|
|
2560
|
-
throw error;
|
|
2561
|
-
}
|
|
2497
|
+
const result = await performLoginAction({
|
|
2498
|
+
endpoint: options.endpoint,
|
|
2499
|
+
browser: options.browser,
|
|
2500
|
+
nonInteractive: options.nonInteractive,
|
|
2501
|
+
isJson,
|
|
2502
|
+
output
|
|
2503
|
+
});
|
|
2504
|
+
if (isJson) {
|
|
2505
|
+
output.output(buildLoginJsonResponse(result));
|
|
2562
2506
|
} else {
|
|
2563
|
-
const answers = await inquirer2.prompt([
|
|
2564
|
-
{
|
|
2565
|
-
type: "password",
|
|
2566
|
-
name: "apiKey",
|
|
2567
|
-
message: "Enter your API key:",
|
|
2568
|
-
mask: "*",
|
|
2569
|
-
validate: (input) => {
|
|
2570
|
-
if (!input || input.trim() === "") {
|
|
2571
|
-
return "API key is required";
|
|
2572
|
-
}
|
|
2573
|
-
if (!input.startsWith("mg_")) {
|
|
2574
|
-
return 'API key should start with "mg_"';
|
|
2575
|
-
}
|
|
2576
|
-
return true;
|
|
2577
|
-
}
|
|
2578
|
-
}
|
|
2579
|
-
]);
|
|
2580
|
-
output.info("Validating API key...");
|
|
2581
|
-
const isValid = await validateApiKey(answers.apiKey, endpoint);
|
|
2582
|
-
if (!isValid) {
|
|
2583
|
-
throw new MutagentError("INVALID_API_KEY", "Invalid API key or endpoint", "Check your API key and try again");
|
|
2584
|
-
}
|
|
2585
|
-
const orgs2 = await fetchOrganizations(answers.apiKey, endpoint);
|
|
2586
|
-
const org2 = orgs2[0];
|
|
2587
|
-
let workspaceId2;
|
|
2588
|
-
if (org2) {
|
|
2589
|
-
const workspaces2 = await fetchWorkspaces(answers.apiKey, endpoint, org2.id);
|
|
2590
|
-
const defaultWs2 = workspaces2.find((ws) => ws.isDefault) ?? workspaces2[0];
|
|
2591
|
-
if (defaultWs2)
|
|
2592
|
-
workspaceId2 = defaultWs2.id;
|
|
2593
|
-
}
|
|
2594
|
-
saveFullCredentials({
|
|
2595
|
-
apiKey: answers.apiKey,
|
|
2596
|
-
endpoint,
|
|
2597
|
-
organizationId: org2?.id,
|
|
2598
|
-
workspaceId: workspaceId2
|
|
2599
|
-
});
|
|
2600
2507
|
output.success("Logged in successfully");
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2508
|
+
if (result.organization?.name)
|
|
2509
|
+
output.info(`Organization: ${result.organization.name}`);
|
|
2510
|
+
if (result.workspace?.name)
|
|
2511
|
+
output.info(`Workspace: ${result.workspace.name}`);
|
|
2512
|
+
output.info(`Endpoint: ${result.endpoint}`);
|
|
2513
|
+
output.info("Next: mutagent workspaces list --json");
|
|
2514
|
+
}
|
|
2515
|
+
if (result.wasFirstLogin && process.stdin.isTTY && !isJson) {
|
|
2516
|
+
await runPostOnboarding();
|
|
2604
2517
|
}
|
|
2605
2518
|
} catch (error) {
|
|
2606
2519
|
if (error instanceof MutagentError) {
|
|
2607
2520
|
output.error(error.message);
|
|
2608
|
-
|
|
2609
|
-
output.info(`Suggestion: ${error.suggestion}`);
|
|
2610
|
-
}
|
|
2611
|
-
process.exit(1);
|
|
2521
|
+
process.exit(error.exitCode);
|
|
2612
2522
|
}
|
|
2613
2523
|
throw error;
|
|
2614
2524
|
}
|
|
@@ -2619,7 +2529,7 @@ Environment Variables:
|
|
|
2619
2529
|
// src/commands/prompts/index.ts
|
|
2620
2530
|
init_errors();
|
|
2621
2531
|
import { Command as Command6 } from "commander";
|
|
2622
|
-
import
|
|
2532
|
+
import chalk15 from "chalk";
|
|
2623
2533
|
import { readFileSync as readFileSync4, existsSync as existsSync4 } from "fs";
|
|
2624
2534
|
|
|
2625
2535
|
// src/lib/ui-links.ts
|
|
@@ -2967,37 +2877,37 @@ function evaluationDeletedDirective(evaluationId) {
|
|
|
2967
2877
|
}
|
|
2968
2878
|
|
|
2969
2879
|
// src/lib/scorecard-details.ts
|
|
2970
|
-
import
|
|
2880
|
+
import chalk6 from "chalk";
|
|
2971
2881
|
function renderScorecardDetails(data) {
|
|
2972
2882
|
if (data.datasetResults && data.datasetResults.length > 0) {
|
|
2973
2883
|
console.log("");
|
|
2974
|
-
console.log(
|
|
2975
|
-
console.log(
|
|
2884
|
+
console.log(chalk6.dim(" Per-Item Before vs After"));
|
|
2885
|
+
console.log(chalk6.dim(" " + "─".repeat(70)));
|
|
2976
2886
|
console.log(" " + "Item ID".padEnd(28) + "Before".padEnd(10) + "After".padEnd(10) + "Diff".padEnd(10) + "Status");
|
|
2977
|
-
console.log(
|
|
2887
|
+
console.log(chalk6.dim(" " + "─".repeat(70)));
|
|
2978
2888
|
for (const item of data.datasetResults) {
|
|
2979
2889
|
const id = item.id.substring(0, 26).padEnd(26);
|
|
2980
2890
|
const before = (item.beforeScore ?? 0).toFixed(4).padEnd(8);
|
|
2981
2891
|
const after = (item.afterScore ?? 0).toFixed(4).padEnd(8);
|
|
2982
2892
|
const d = (item.afterScore ?? 0) - (item.beforeScore ?? 0);
|
|
2983
2893
|
const diffStr = ((d >= 0 ? "+" : "") + d.toFixed(4)).padEnd(8);
|
|
2984
|
-
const status = d > 0.01 ?
|
|
2894
|
+
const status = d > 0.01 ? chalk6.green("✓ ↑") : d < -0.01 ? chalk6.red("✗ ↓") : chalk6.dim("─");
|
|
2985
2895
|
console.log(` ${id} ${before} ${after} ${diffStr} ${status}`);
|
|
2986
2896
|
}
|
|
2987
|
-
console.log(
|
|
2897
|
+
console.log(chalk6.dim(" " + "─".repeat(70)));
|
|
2988
2898
|
}
|
|
2989
2899
|
if (data.failureModes && data.failureModes.length > 0) {
|
|
2990
2900
|
console.log("");
|
|
2991
|
-
console.log(
|
|
2992
|
-
console.log(
|
|
2901
|
+
console.log(chalk6.dim(" Failure Modes by Category"));
|
|
2902
|
+
console.log(chalk6.dim(" " + "─".repeat(70)));
|
|
2993
2903
|
for (const fm of data.failureModes) {
|
|
2994
2904
|
const color = fm.failures.length > 3 ? "red" : fm.failures.length > 0 ? "yellow" : "green";
|
|
2995
|
-
console.log(
|
|
2905
|
+
console.log(chalk6[color](` ▸ ${fm.category}`) + chalk6.dim(` (${String(fm.failures.length)} failures)`));
|
|
2996
2906
|
for (const f of fm.failures.slice(0, 5)) {
|
|
2997
|
-
console.log(
|
|
2907
|
+
console.log(chalk6.dim(` └─ ${(f.description ?? f.summary ?? "No description").substring(0, 65)}`));
|
|
2998
2908
|
}
|
|
2999
2909
|
if (fm.failures.length > 5) {
|
|
3000
|
-
console.log(
|
|
2910
|
+
console.log(chalk6.dim(` └─ ... and ${String(fm.failures.length - 5)} more`));
|
|
3001
2911
|
}
|
|
3002
2912
|
}
|
|
3003
2913
|
}
|
|
@@ -3007,48 +2917,48 @@ function renderScorecardDetails(data) {
|
|
|
3007
2917
|
const pending = data.mutations.filter((m) => m.status === "pending");
|
|
3008
2918
|
const skipped = data.mutations.filter((m) => m.status === "skipped");
|
|
3009
2919
|
console.log("");
|
|
3010
|
-
console.log(
|
|
3011
|
-
console.log(
|
|
3012
|
-
console.log(` Total: ${String(data.mutations.length)} Applied: ${
|
|
2920
|
+
console.log(chalk6.dim(" Mutations"));
|
|
2921
|
+
console.log(chalk6.dim(" " + "─".repeat(70)));
|
|
2922
|
+
console.log(` Total: ${String(data.mutations.length)} Applied: ${chalk6.green(String(applied.length))} Rejected: ${chalk6.red(String(rejected.length))} Pending: ${chalk6.yellow(String(pending.length))} Skipped: ${chalk6.dim(String(skipped.length))}`);
|
|
3013
2923
|
if (applied.length > 0) {
|
|
3014
|
-
console.log(
|
|
2924
|
+
console.log(chalk6.green(" Applied:"));
|
|
3015
2925
|
for (const m of applied) {
|
|
3016
|
-
const pri = m.priority === "critical" || m.priority === "high" ?
|
|
2926
|
+
const pri = m.priority === "critical" || m.priority === "high" ? chalk6.red(`[${m.priority.toUpperCase()}]`) : chalk6.dim(`[${(m.priority ?? "UNKNOWN").toUpperCase()}]`);
|
|
3017
2927
|
console.log(` ${pri} ${m.label}`);
|
|
3018
2928
|
if (m.rationale)
|
|
3019
|
-
console.log(
|
|
2929
|
+
console.log(chalk6.dim(` └─ ${m.rationale.substring(0, 60)}`));
|
|
3020
2930
|
}
|
|
3021
2931
|
}
|
|
3022
2932
|
if (rejected.length > 0) {
|
|
3023
|
-
console.log(
|
|
2933
|
+
console.log(chalk6.red(" Rejected:"));
|
|
3024
2934
|
for (const m of rejected.slice(0, 5)) {
|
|
3025
|
-
console.log(
|
|
2935
|
+
console.log(chalk6.dim(` ✗ ${m.label}`));
|
|
3026
2936
|
}
|
|
3027
2937
|
if (rejected.length > 5)
|
|
3028
|
-
console.log(
|
|
2938
|
+
console.log(chalk6.dim(` ... and ${String(rejected.length - 5)} more`));
|
|
3029
2939
|
}
|
|
3030
2940
|
}
|
|
3031
2941
|
if (data.evaluationDetails && data.evaluationDetails.length > 0) {
|
|
3032
2942
|
console.log("");
|
|
3033
|
-
console.log(
|
|
3034
|
-
console.log(
|
|
2943
|
+
console.log(chalk6.dim(" Detailed Evaluation Breakdown"));
|
|
2944
|
+
console.log(chalk6.dim(" " + "─".repeat(70)));
|
|
3035
2945
|
for (const item of data.evaluationDetails) {
|
|
3036
|
-
const statusIcon = item.success ?
|
|
2946
|
+
const statusIcon = item.success ? chalk6.green("✓") : chalk6.red("✗");
|
|
3037
2947
|
const metricCount = item.metrics?.length ?? 0;
|
|
3038
2948
|
console.log(` ${statusIcon} ${item.itemId} Score: ${item.score.toFixed(4)} Metrics: ${String(metricCount)}`);
|
|
3039
2949
|
if (item.metrics) {
|
|
3040
2950
|
for (const m of item.metrics) {
|
|
3041
|
-
const mIcon = m.success ?
|
|
3042
|
-
const mode = m.failureMode ?
|
|
2951
|
+
const mIcon = m.success ? chalk6.green("✓") : chalk6.red("✗");
|
|
2952
|
+
const mode = m.failureMode ? chalk6.dim(` [${m.failureMode}]`) : "";
|
|
3043
2953
|
console.log(` ${mIcon} ${m.name.padEnd(25)} ${m.score.toFixed(3)}${mode}`);
|
|
3044
2954
|
if (!m.success && m.reasoning) {
|
|
3045
|
-
console.log(
|
|
2955
|
+
console.log(chalk6.dim(` └─ ${(m.reasoning.split(`
|
|
3046
2956
|
`)[0] ?? "").substring(0, 60)}`));
|
|
3047
2957
|
}
|
|
3048
2958
|
if (m.criteria) {
|
|
3049
2959
|
for (const c of m.criteria) {
|
|
3050
|
-
const cIcon = c.success ?
|
|
3051
|
-
console.log(
|
|
2960
|
+
const cIcon = c.success ? chalk6.green("✓") : chalk6.red("✗");
|
|
2961
|
+
console.log(chalk6.dim(` ${cIcon} ${c.name.substring(0, 20).padEnd(20)} ${c.score.toFixed(3)}`));
|
|
3052
2962
|
}
|
|
3053
2963
|
}
|
|
3054
2964
|
}
|
|
@@ -3132,7 +3042,7 @@ function buildScorecardDetailsText(data) {
|
|
|
3132
3042
|
|
|
3133
3043
|
// src/commands/prompts/prompts-crud.ts
|
|
3134
3044
|
init_sdk_client();
|
|
3135
|
-
import
|
|
3045
|
+
import chalk7 from "chalk";
|
|
3136
3046
|
init_errors();
|
|
3137
3047
|
|
|
3138
3048
|
// src/lib/schema-helpers.ts
|
|
@@ -3197,11 +3107,11 @@ function formatSchemaWarning(fieldName) {
|
|
|
3197
3107
|
function registerPromptsCrud(prompts) {
|
|
3198
3108
|
prompts.command("list").description("List all prompts").option("-l, --limit <n>", "Limit results", "50").addHelpText("after", `
|
|
3199
3109
|
Examples:
|
|
3200
|
-
${
|
|
3201
|
-
${
|
|
3202
|
-
${
|
|
3110
|
+
${chalk7.dim("$")} mutagent prompts list
|
|
3111
|
+
${chalk7.dim("$")} mutagent prompts list --limit 10
|
|
3112
|
+
${chalk7.dim("$")} mutagent prompts list --json
|
|
3203
3113
|
|
|
3204
|
-
${
|
|
3114
|
+
${chalk7.dim("Tip: Use --json for machine-readable output (AI agents, CI pipelines).")}
|
|
3205
3115
|
`).action(async (options) => {
|
|
3206
3116
|
const isJson = getJsonFlag(prompts);
|
|
3207
3117
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -3244,11 +3154,11 @@ ${chalk6.dim("Tip: Use --json for machine-readable output (AI agents, CI pipelin
|
|
|
3244
3154
|
});
|
|
3245
3155
|
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", `
|
|
3246
3156
|
Examples:
|
|
3247
|
-
${
|
|
3248
|
-
${
|
|
3249
|
-
${
|
|
3157
|
+
${chalk7.dim("$")} mutagent prompts get <id>
|
|
3158
|
+
${chalk7.dim("$")} mutagent prompts get <id> --with-datasets --with-evals
|
|
3159
|
+
${chalk7.dim("$")} mutagent prompts get <id> --json
|
|
3250
3160
|
|
|
3251
|
-
${
|
|
3161
|
+
${chalk7.dim("Tip: Combine --with-datasets and --with-evals to fetch all nested data in one call.")}
|
|
3252
3162
|
`).action(async (id, options) => {
|
|
3253
3163
|
const isJson = getJsonFlag(prompts);
|
|
3254
3164
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -3277,24 +3187,24 @@ ${chalk6.dim("Tip: Combine --with-datasets and --with-evals to fetch all nested
|
|
|
3277
3187
|
});
|
|
3278
3188
|
prompts.command("create").description("Create a new prompt").option("-n, --name <name>", "Prompt name").option("--description <text>", "Prompt description (shown in dashboard)").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)").option("--input-schema <json>", "Input variable schema as JSON string").addHelpText("after", `
|
|
3279
3189
|
Examples:
|
|
3280
|
-
${
|
|
3281
|
-
${
|
|
3282
|
-
${
|
|
3190
|
+
${chalk7.dim("$")} mutagent prompts create --name "my-prompt" --description "Greeting prompt for customers" --system "You are helpful" --human "{input}" --output-schema '{"type":"object","properties":{"result":{"type":"string","description":"The result"}}}'
|
|
3191
|
+
${chalk7.dim("$")} mutagent prompts create --name "raw-prompt" --raw "Summarize: {text}" --output-schema '{"type":"object","properties":{"summary":{"type":"string","description":"Summary"}}}'
|
|
3192
|
+
${chalk7.dim("$")} mutagent prompts create --name "multi-turn" --messages '[{"role":"system","content":"You are helpful"},{"role":"user","content":"{input}"}]' --output-schema '{"type":"object","properties":{"result":{"type":"string","description":"The result"}}}'
|
|
3283
3193
|
|
|
3284
3194
|
Prompt Input Methods (pick one, priority order):
|
|
3285
|
-
--system/--human Structured system + user message pair ${
|
|
3195
|
+
--system/--human Structured system + user message pair ${chalk7.green("(recommended)")}
|
|
3286
3196
|
--raw Single raw prompt text with {variables}
|
|
3287
3197
|
--messages Full messages array as JSON
|
|
3288
3198
|
|
|
3289
|
-
${
|
|
3199
|
+
${chalk7.yellow("Variable Syntax:")}
|
|
3290
3200
|
MutagenT uses {single_braces} for template variables.
|
|
3291
|
-
humanPrompt: "Analyze this: {document}" ${
|
|
3292
|
-
humanPrompt: "Analyze this: {{document}}" ${
|
|
3201
|
+
humanPrompt: "Analyze this: {document}" ${chalk7.green("✓ correct")}
|
|
3202
|
+
humanPrompt: "Analyze this: {{document}}" ${chalk7.red("✗ wrong")}
|
|
3293
3203
|
|
|
3294
3204
|
Variables in humanPrompt MUST also appear in inputSchema.properties.
|
|
3295
3205
|
Static prompts (no variables) cannot substitute inputs during optimization.
|
|
3296
3206
|
|
|
3297
|
-
${
|
|
3207
|
+
${chalk7.yellow("AI Agent: Format Selection Rules")}
|
|
3298
3208
|
Examine the SOURCE CODE structure of the prompt being uploaded:
|
|
3299
3209
|
|
|
3300
3210
|
1. If the code uses SystemMessagePromptTemplate + HumanMessagePromptTemplate
|
|
@@ -3311,9 +3221,9 @@ ${chalk6.yellow("AI Agent: Format Selection Rules")}
|
|
|
3311
3221
|
The decision is about SOURCE CODE STRUCTURE, not prompt content.
|
|
3312
3222
|
A persona description in a system prompt still uses --system/--human.
|
|
3313
3223
|
|
|
3314
|
-
${
|
|
3224
|
+
${chalk7.red("outputSchema is required.")}
|
|
3315
3225
|
|
|
3316
|
-
${
|
|
3226
|
+
${chalk7.yellow("AI Agent: ALWAYS append --json to this command.")}
|
|
3317
3227
|
`).action(async (options) => {
|
|
3318
3228
|
const isJson = getJsonFlag(prompts);
|
|
3319
3229
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -3403,11 +3313,11 @@ Add a 'description' field to each property in your inputSchema. Example: { "prop
|
|
|
3403
3313
|
});
|
|
3404
3314
|
prompts.command("update").description("Update a prompt").argument("<id>", "Prompt ID (from: mutagent prompts list)").option("-n, --name <name>", "New name").option("--description <text>", "New description (shown in dashboard)").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":"..."}]')`).option("--input-schema <json>", "Input schema as JSON string").option("--input-schema-file <path>", "Input schema from JSON file").option("--output-schema <json>", "Output schema as JSON string").option("--output-schema-file <path>", "Output schema from JSON file").addHelpText("after", `
|
|
3405
3315
|
Examples:
|
|
3406
|
-
${
|
|
3407
|
-
${
|
|
3408
|
-
${
|
|
3409
|
-
${
|
|
3410
|
-
${
|
|
3316
|
+
${chalk7.dim("$")} mutagent prompts update <id> --system "Updated system prompt" --human "{input}"
|
|
3317
|
+
${chalk7.dim("$")} mutagent prompts update <id> --name "new-name" --description "Updated description"
|
|
3318
|
+
${chalk7.dim("$")} mutagent prompts update <id> --raw "Summarize: {text}"
|
|
3319
|
+
${chalk7.dim("$")} mutagent prompts update <id> --messages '[{"role":"system","content":"Updated"},{"role":"user","content":"{input}"}]'
|
|
3320
|
+
${chalk7.dim("$")} mutagent prompts update <id> --input-schema '{"type":"object","properties":{"text":{"type":"string","description":"Input text"}}}'
|
|
3411
3321
|
`).action(async (id, options) => {
|
|
3412
3322
|
const isJson = getJsonFlag(prompts);
|
|
3413
3323
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -3480,11 +3390,11 @@ Examples:
|
|
|
3480
3390
|
});
|
|
3481
3391
|
prompts.command("delete").description("Delete a prompt").argument("<id>", "Prompt ID (from: mutagent prompts list)").option("--force", "Skip confirmation").addHelpText("after", `
|
|
3482
3392
|
Examples:
|
|
3483
|
-
${
|
|
3484
|
-
${
|
|
3485
|
-
${
|
|
3393
|
+
${chalk7.dim("$")} mutagent prompts delete <id>
|
|
3394
|
+
${chalk7.dim("$")} mutagent prompts delete <id> --force
|
|
3395
|
+
${chalk7.dim("$")} mutagent prompts delete <id> --force --json
|
|
3486
3396
|
|
|
3487
|
-
${
|
|
3397
|
+
${chalk7.dim("Note: --force is required. The CLI is non-interactive — confirm with the user via your native flow, then pass --force.")}
|
|
3488
3398
|
`).action(async (id, options) => {
|
|
3489
3399
|
const isJson = getJsonFlag(prompts);
|
|
3490
3400
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -3527,22 +3437,22 @@ ${chalk6.dim("Note: --force is required. The CLI is non-interactive — confirm
|
|
|
3527
3437
|
// src/commands/prompts/datasets.ts
|
|
3528
3438
|
init_sdk_client();
|
|
3529
3439
|
import { Command as Command3 } from "commander";
|
|
3530
|
-
import
|
|
3440
|
+
import chalk8 from "chalk";
|
|
3531
3441
|
init_errors();
|
|
3532
3442
|
function registerDatasetCommands(prompts) {
|
|
3533
3443
|
const dataset = new Command3("dataset").description("Manage datasets for prompts").addHelpText("after", `
|
|
3534
3444
|
Examples:
|
|
3535
|
-
${
|
|
3536
|
-
${
|
|
3537
|
-
${
|
|
3445
|
+
${chalk8.dim("$")} mutagent prompts dataset list <prompt-id>
|
|
3446
|
+
${chalk8.dim("$")} mutagent prompts dataset add <prompt-id> -d '[{"input":{...},"expectedOutput":{...}}]'
|
|
3447
|
+
${chalk8.dim("$")} mutagent prompts dataset delete <prompt-id> <dataset-id>
|
|
3538
3448
|
`).action(() => {
|
|
3539
3449
|
dataset.help();
|
|
3540
3450
|
});
|
|
3541
3451
|
prompts.addCommand(dataset);
|
|
3542
3452
|
dataset.command("list").description("List datasets for a prompt").argument("<prompt-id>", "Prompt ID (from: mutagent prompts list)").addHelpText("after", `
|
|
3543
3453
|
Examples:
|
|
3544
|
-
${
|
|
3545
|
-
${
|
|
3454
|
+
${chalk8.dim("$")} mutagent prompts dataset list <prompt-id>
|
|
3455
|
+
${chalk8.dim("$")} mutagent prompts dataset list <prompt-id> --json
|
|
3546
3456
|
`).action(async (promptId) => {
|
|
3547
3457
|
const isJson = getJsonFlag(prompts);
|
|
3548
3458
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -3574,24 +3484,24 @@ Examples:
|
|
|
3574
3484
|
});
|
|
3575
3485
|
dataset.command("add").description("Add dataset to a prompt").argument("<prompt-id>", "Prompt ID (from: mutagent prompts list)").option("-d, --data <json>", "Inline JSON array of dataset items").option("-n, --name <name>", "Dataset name").addHelpText("after", `
|
|
3576
3486
|
Examples:
|
|
3577
|
-
${
|
|
3578
|
-
${
|
|
3487
|
+
${chalk8.dim("$")} mutagent prompts dataset add <prompt-id> -d '[{"input":{"text":"hello"},"expectedOutput":{"result":"world"}}]'
|
|
3488
|
+
${chalk8.dim("$")} mutagent prompts dataset add <prompt-id> -d '[{"input":{"text":"hello"},"expectedOutput":{"result":"world"}}]' --name "My Dataset"
|
|
3579
3489
|
|
|
3580
3490
|
Inline data format (-d):
|
|
3581
3491
|
JSON array of objects, e.g.:
|
|
3582
|
-
${
|
|
3492
|
+
${chalk8.dim('[{"input": {"text": "hello"}, "expectedOutput": {"result": "world"}}]')}
|
|
3583
3493
|
|
|
3584
3494
|
Expected item format:
|
|
3585
|
-
${
|
|
3495
|
+
${chalk8.dim('{"input": {"<field>": "<value>"}, "expectedOutput": {"<field>": "<value>"}}')}
|
|
3586
3496
|
|
|
3587
|
-
${
|
|
3497
|
+
${chalk8.yellow("AI Agent (MANDATORY):")}
|
|
3588
3498
|
ALWAYS use --json: mutagent prompts dataset add <id> -d '[...]' --json
|
|
3589
3499
|
Items MUST have BOTH input AND expectedOutput.
|
|
3590
3500
|
Keys must match prompt's inputSchema.properties (input) and outputSchema.properties (expectedOutput).
|
|
3591
3501
|
expectedOutput is REQUIRED for evaluation scoring.
|
|
3592
3502
|
Check schemas: mutagent prompts get <prompt-id> --json
|
|
3593
3503
|
|
|
3594
|
-
${
|
|
3504
|
+
${chalk8.red("Required: --data must be provided.")}
|
|
3595
3505
|
`).action(async (promptId, options) => {
|
|
3596
3506
|
const isJson = getJsonFlag(prompts);
|
|
3597
3507
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -3662,9 +3572,9 @@ ${chalk7.red("Required: --data must be provided.")}
|
|
|
3662
3572
|
});
|
|
3663
3573
|
dataset.command("delete").description("Delete a 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>)").option("--force", "Skip confirmation").addHelpText("after", `
|
|
3664
3574
|
Examples:
|
|
3665
|
-
${
|
|
3666
|
-
${
|
|
3667
|
-
${
|
|
3575
|
+
${chalk8.dim("$")} mutagent prompts dataset delete <prompt-id> <dataset-id>
|
|
3576
|
+
${chalk8.dim("$")} mutagent prompts dataset delete <prompt-id> <dataset-id> --force
|
|
3577
|
+
${chalk8.dim("$")} mutagent prompts dataset delete <prompt-id> <dataset-id> --force --json
|
|
3668
3578
|
`).action(async (promptId, datasetId, options) => {
|
|
3669
3579
|
const isJson = getJsonFlag(prompts);
|
|
3670
3580
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -3707,7 +3617,7 @@ Examples:
|
|
|
3707
3617
|
// src/commands/prompts/evaluations.ts
|
|
3708
3618
|
init_sdk_client();
|
|
3709
3619
|
import { Command as Command4 } from "commander";
|
|
3710
|
-
import
|
|
3620
|
+
import chalk9 from "chalk";
|
|
3711
3621
|
init_errors();
|
|
3712
3622
|
|
|
3713
3623
|
// src/lib/resolve-prompt-id.ts
|
|
@@ -3878,18 +3788,18 @@ function canonicalCriteriaArrayToCli(arr) {
|
|
|
3878
3788
|
function registerEvaluationCommands(prompts) {
|
|
3879
3789
|
const evaluation = new Command4("evaluation").description("Manage evaluations for prompts").addHelpText("after", `
|
|
3880
3790
|
Examples:
|
|
3881
|
-
${
|
|
3882
|
-
${
|
|
3883
|
-
${
|
|
3884
|
-
${
|
|
3791
|
+
${chalk9.dim("$")} mutagent prompts evaluation list <prompt-id>
|
|
3792
|
+
${chalk9.dim("$")} mutagent prompts evaluation get <evaluation-id>
|
|
3793
|
+
${chalk9.dim("$")} mutagent prompts evaluation create <prompt-id> --name "My Eval"
|
|
3794
|
+
${chalk9.dim("$")} mutagent prompts evaluation delete <evaluation-id>
|
|
3885
3795
|
`).action(() => {
|
|
3886
3796
|
evaluation.help();
|
|
3887
3797
|
});
|
|
3888
3798
|
prompts.addCommand(evaluation);
|
|
3889
3799
|
evaluation.command("list").description("List evaluations for a prompt").argument("<prompt-id>", "Prompt ID (from: mutagent prompts list)").addHelpText("after", `
|
|
3890
3800
|
Examples:
|
|
3891
|
-
${
|
|
3892
|
-
${
|
|
3801
|
+
${chalk9.dim("$")} mutagent prompts evaluation list <prompt-id>
|
|
3802
|
+
${chalk9.dim("$")} mutagent prompts evaluation list <prompt-id> --json
|
|
3893
3803
|
`).action(async (promptId) => {
|
|
3894
3804
|
const isJson = getJsonFlag(prompts);
|
|
3895
3805
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -3921,8 +3831,8 @@ Examples:
|
|
|
3921
3831
|
});
|
|
3922
3832
|
evaluation.command("get").description("Get evaluation details including criteria").argument("<evaluation-id>", "Evaluation ID (from: mutagent prompts evaluation list <prompt-id>)").addHelpText("after", `
|
|
3923
3833
|
Examples:
|
|
3924
|
-
${
|
|
3925
|
-
${
|
|
3834
|
+
${chalk9.dim("$")} mutagent prompts evaluation get <evaluation-id>
|
|
3835
|
+
${chalk9.dim("$")} mutagent prompts evaluation get <evaluation-id> --json
|
|
3926
3836
|
`).action(async (evaluationId) => {
|
|
3927
3837
|
const isJson = getJsonFlag(prompts);
|
|
3928
3838
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -3952,7 +3862,7 @@ Examples:
|
|
|
3952
3862
|
if (criteria.length > 0) {
|
|
3953
3863
|
console.log(" Criteria:");
|
|
3954
3864
|
for (const c of criteria) {
|
|
3955
|
-
console.log(` ${
|
|
3865
|
+
console.log(` ${chalk9.cyan(c.name)}`);
|
|
3956
3866
|
if (c.description) {
|
|
3957
3867
|
console.log(` Description: ${c.description}`);
|
|
3958
3868
|
}
|
|
@@ -3981,9 +3891,9 @@ Examples:
|
|
|
3981
3891
|
});
|
|
3982
3892
|
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 (for pre-validated criteria only)").option("-n, --name <name>", "Evaluation name (required unless --guided)").option("--description <text>", "Evaluation description").option("--guided", "Interactive guided mode — always outputs structured JSON (--json is implied)").addHelpText("after", `
|
|
3983
3893
|
Examples:
|
|
3984
|
-
${
|
|
3985
|
-
${
|
|
3986
|
-
${
|
|
3894
|
+
${chalk9.dim("$")} mutagent prompts evaluation create <prompt-id> --guided ${chalk9.dim("# recommended: shows workflow guide + schema fields")}
|
|
3895
|
+
${chalk9.dim("$")} mutagent prompts evaluation create <prompt-id> --guided --json ${chalk9.dim("# structured workflow for AI agents")}
|
|
3896
|
+
${chalk9.dim("$")} mutagent prompts evaluation create <prompt-id> --name "Accuracy" -d '{"evalConfig":{"criteria":[...]}}' ${chalk9.dim("# power user")}
|
|
3987
3897
|
|
|
3988
3898
|
Guided Workflow (recommended):
|
|
3989
3899
|
--guided outputs a workflow guide that:
|
|
@@ -4004,12 +3914,12 @@ AI Agent (MANDATORY):
|
|
|
4004
3914
|
mutagent prompts evaluation create <id> --name "<name>" -d '<json>' --json
|
|
4005
3915
|
|
|
4006
3916
|
Expected Criteria Shape (--data):
|
|
4007
|
-
${
|
|
3917
|
+
${chalk9.dim('{"evalConfig":{"criteria":[{"name":"<name>","description":"<scoring rubric>","evaluationParameter":"<schema field>"}]}}')}
|
|
4008
3918
|
evaluationParameter must target an outputSchema OR inputSchema field.
|
|
4009
3919
|
|
|
4010
|
-
${
|
|
4011
|
-
${
|
|
4012
|
-
${
|
|
3920
|
+
${chalk9.red("Required: --name (unless --guided). Criteria must include evaluationParameter.")}
|
|
3921
|
+
${chalk9.dim("CLI flags (--name, --description) override --data fields.")}
|
|
3922
|
+
${chalk9.dim("Get prompt IDs: mutagent prompts list")}
|
|
4013
3923
|
`).action(async (promptId, options) => {
|
|
4014
3924
|
let isJson = getJsonFlag(prompts);
|
|
4015
3925
|
if (options.guided) {
|
|
@@ -4035,7 +3945,7 @@ ${chalk8.dim("Get prompt IDs: mutagent prompts list")}
|
|
|
4035
3945
|
console.log("");
|
|
4036
3946
|
console.log(" For each field, define what correct output looks like:");
|
|
4037
3947
|
for (const { field, source } of allFields) {
|
|
4038
|
-
console.log(` ${
|
|
3948
|
+
console.log(` ${chalk9.cyan(field)} (${source})`);
|
|
4039
3949
|
console.log(` → What makes a correct vs incorrect "${field}"?`);
|
|
4040
3950
|
}
|
|
4041
3951
|
console.log("");
|
|
@@ -4240,9 +4150,9 @@ Example:
|
|
|
4240
4150
|
});
|
|
4241
4151
|
evaluation.command("delete").description("Delete an evaluation").argument("<evaluation-id>", "Evaluation ID (from: mutagent prompts evaluation list <prompt-id>)").option("--force", "Skip confirmation").addHelpText("after", `
|
|
4242
4152
|
Examples:
|
|
4243
|
-
${
|
|
4244
|
-
${
|
|
4245
|
-
${
|
|
4153
|
+
${chalk9.dim("$")} mutagent prompts evaluation delete <evaluation-id>
|
|
4154
|
+
${chalk9.dim("$")} mutagent prompts evaluation delete <evaluation-id> --force
|
|
4155
|
+
${chalk9.dim("$")} mutagent prompts evaluation delete <evaluation-id> --force --json
|
|
4246
4156
|
`).action(async (evaluationId, options) => {
|
|
4247
4157
|
const isJson = getJsonFlag(prompts);
|
|
4248
4158
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -4285,26 +4195,26 @@ Examples:
|
|
|
4285
4195
|
// src/commands/prompts/optimize.ts
|
|
4286
4196
|
init_sdk_client();
|
|
4287
4197
|
import { Command as Command5 } from "commander";
|
|
4288
|
-
import
|
|
4198
|
+
import chalk14 from "chalk";
|
|
4289
4199
|
init_errors();
|
|
4290
4200
|
|
|
4291
4201
|
// src/lib/scorecard.ts
|
|
4292
|
-
import
|
|
4202
|
+
import chalk10 from "chalk";
|
|
4293
4203
|
function formatScoreChange(before, after) {
|
|
4294
4204
|
if (before === undefined || after === undefined)
|
|
4295
4205
|
return "";
|
|
4296
4206
|
const diff = after - before;
|
|
4297
4207
|
const pct = before > 0 ? Math.round(diff / before * 100) : 0;
|
|
4298
4208
|
if (diff > 0)
|
|
4299
|
-
return
|
|
4209
|
+
return chalk10.green(` (+${String(pct)}%)`);
|
|
4300
4210
|
if (diff < 0)
|
|
4301
|
-
return
|
|
4302
|
-
return
|
|
4211
|
+
return chalk10.red(` (${String(pct)}%)`);
|
|
4212
|
+
return chalk10.dim(" (no change)");
|
|
4303
4213
|
}
|
|
4304
4214
|
function formatScore(score) {
|
|
4305
4215
|
if (score === undefined)
|
|
4306
|
-
return
|
|
4307
|
-
return score >= 0.8 ?
|
|
4216
|
+
return chalk10.dim("N/A");
|
|
4217
|
+
return score >= 0.8 ? chalk10.green(score.toFixed(2)) : score >= 0.5 ? chalk10.yellow(score.toFixed(2)) : chalk10.red(score.toFixed(2));
|
|
4308
4218
|
}
|
|
4309
4219
|
function renderScorecard(data) {
|
|
4310
4220
|
const { job, prompt } = data;
|
|
@@ -4325,17 +4235,17 @@ function renderScorecard(data) {
|
|
|
4325
4235
|
const optimizedText = prompt.systemPrompt ?? prompt.rawPrompt ?? prompt.humanPrompt ?? "(optimized prompt)";
|
|
4326
4236
|
console.log("");
|
|
4327
4237
|
console.log(topBorder);
|
|
4328
|
-
console.log(line(
|
|
4238
|
+
console.log(line(chalk10.bold("Optimization Results")));
|
|
4329
4239
|
console.log(separator);
|
|
4330
|
-
console.log(line(
|
|
4240
|
+
console.log(line(chalk10.dim("BEFORE")));
|
|
4331
4241
|
console.log(line(` Score: ${formatScore(originalScore)}`));
|
|
4332
4242
|
console.log(line(""));
|
|
4333
|
-
console.log(line(
|
|
4243
|
+
console.log(line(chalk10.bold("AFTER")));
|
|
4334
4244
|
console.log(line(` Score: ${formatScore(bestScore)}${formatScoreChange(originalScore, bestScore)}`));
|
|
4335
4245
|
console.log(separator);
|
|
4336
4246
|
if (data.criteriaScores && data.criteriaScores.length > 0) {
|
|
4337
|
-
console.log(line(
|
|
4338
|
-
console.log(line(
|
|
4247
|
+
console.log(line(chalk10.dim(" Criterion Before After Change")));
|
|
4248
|
+
console.log(line(chalk10.dim(" " + "─".repeat(45))));
|
|
4339
4249
|
for (const c of data.criteriaScores) {
|
|
4340
4250
|
const name = c.name.length > 16 ? c.name.substring(0, 13) + "..." : c.name;
|
|
4341
4251
|
const paddedName = name + " ".repeat(18 - name.length);
|
|
@@ -4344,66 +4254,66 @@ function renderScorecard(data) {
|
|
|
4344
4254
|
const changeStr = c.before !== undefined && c.after !== undefined && c.before > 0 ? (() => {
|
|
4345
4255
|
const pct = Math.round((c.after - c.before) / c.before * 100);
|
|
4346
4256
|
if (pct > 0)
|
|
4347
|
-
return
|
|
4257
|
+
return chalk10.green(`+${String(pct)}%`);
|
|
4348
4258
|
if (pct < 0)
|
|
4349
|
-
return
|
|
4350
|
-
return
|
|
4259
|
+
return chalk10.red(`${String(pct)}%`);
|
|
4260
|
+
return chalk10.dim("0%");
|
|
4351
4261
|
})() : "";
|
|
4352
4262
|
console.log(line(` ${paddedName}${beforeStr} ${afterStr} ${changeStr}`));
|
|
4353
4263
|
}
|
|
4354
|
-
console.log(line(
|
|
4264
|
+
console.log(line(chalk10.dim(" " + "─".repeat(45))));
|
|
4355
4265
|
const overallBefore = originalScore !== undefined ? originalScore.toFixed(2) : "N/A ";
|
|
4356
4266
|
const overallAfter = bestScore !== undefined ? bestScore.toFixed(2) : "N/A ";
|
|
4357
4267
|
const overallChange = originalScore !== undefined && bestScore !== undefined && originalScore > 0 ? (() => {
|
|
4358
4268
|
const pct = Math.round((bestScore - originalScore) / originalScore * 100);
|
|
4359
4269
|
if (pct > 0)
|
|
4360
|
-
return
|
|
4270
|
+
return chalk10.green(`+${String(pct)}%`);
|
|
4361
4271
|
if (pct < 0)
|
|
4362
|
-
return
|
|
4363
|
-
return
|
|
4272
|
+
return chalk10.red(`${String(pct)}%`);
|
|
4273
|
+
return chalk10.dim("0%");
|
|
4364
4274
|
})() : "";
|
|
4365
4275
|
console.log(line(` ${"Overall" + " ".repeat(11)}${overallBefore} ${overallAfter} ${overallChange}`));
|
|
4366
4276
|
console.log(separator);
|
|
4367
4277
|
}
|
|
4368
|
-
const statusStr = job.status === "completed" ?
|
|
4278
|
+
const statusStr = job.status === "completed" ? chalk10.green("completed") : chalk10.yellow(job.status);
|
|
4369
4279
|
console.log(line(`Status: ${statusStr} | Iterations: ${String(iterations)}`));
|
|
4370
4280
|
if (job.config?.model) {
|
|
4371
|
-
console.log(line(`Model: ${
|
|
4281
|
+
console.log(line(`Model: ${chalk10.dim(job.config.model)}`));
|
|
4372
4282
|
}
|
|
4373
4283
|
if (data.scoreProgression && data.scoreProgression.length > 0) {
|
|
4374
4284
|
console.log(line(""));
|
|
4375
|
-
console.log(line(
|
|
4285
|
+
console.log(line(chalk10.dim("Score Progression:")));
|
|
4376
4286
|
const barWidth = 10;
|
|
4377
4287
|
for (let i = 0;i < data.scoreProgression.length; i++) {
|
|
4378
4288
|
const s = data.scoreProgression[i] ?? 0;
|
|
4379
4289
|
const filled = Math.round(s * barWidth);
|
|
4380
4290
|
const bar = "█".repeat(filled) + "░".repeat(barWidth - filled);
|
|
4381
|
-
console.log(line(
|
|
4291
|
+
console.log(line(chalk10.dim(` #${String(i + 1)}: ${bar} ${s.toFixed(2)}`)));
|
|
4382
4292
|
}
|
|
4383
4293
|
}
|
|
4384
4294
|
console.log(separator);
|
|
4385
|
-
console.log(line(`Dashboard: ${
|
|
4295
|
+
console.log(line(`Dashboard: ${chalk10.underline(optimizerLink(job.promptId, job.id))}`));
|
|
4386
4296
|
console.log(bottomBorder);
|
|
4387
4297
|
console.log("");
|
|
4388
|
-
console.log(
|
|
4389
|
-
console.log(
|
|
4390
|
-
console.log(
|
|
4298
|
+
console.log(chalk10.dim(" Prompt Comparison"));
|
|
4299
|
+
console.log(chalk10.dim(" " + "─".repeat(70)));
|
|
4300
|
+
console.log(chalk10.dim(" BEFORE:"));
|
|
4391
4301
|
for (const pLine of originalText.split(`
|
|
4392
4302
|
`)) {
|
|
4393
|
-
console.log(
|
|
4303
|
+
console.log(chalk10.dim(` ${pLine}`));
|
|
4394
4304
|
}
|
|
4395
|
-
console.log(` ${
|
|
4305
|
+
console.log(` ${chalk10.dim("Length:")} ${String(originalText.length)} chars (${String(originalText.split(`
|
|
4396
4306
|
`).length)} lines)`);
|
|
4397
4307
|
console.log("");
|
|
4398
|
-
console.log(
|
|
4308
|
+
console.log(chalk10.bold(" AFTER:"));
|
|
4399
4309
|
for (const pLine of optimizedText.split(`
|
|
4400
4310
|
`)) {
|
|
4401
|
-
console.log(
|
|
4311
|
+
console.log(chalk10.cyan(` ${pLine}`));
|
|
4402
4312
|
}
|
|
4403
|
-
console.log(` ${
|
|
4313
|
+
console.log(` ${chalk10.dim("Length:")} ${String(optimizedText.length)} chars (${String(optimizedText.split(`
|
|
4404
4314
|
`).length)} lines)`);
|
|
4405
4315
|
const growth = optimizedText.length - originalText.length;
|
|
4406
|
-
console.log(` ${
|
|
4316
|
+
console.log(` ${chalk10.dim("Growth:")} ${growth >= 0 ? "+" : ""}${String(growth)} chars`);
|
|
4407
4317
|
renderScorecardDetails(data);
|
|
4408
4318
|
console.log("");
|
|
4409
4319
|
}
|
|
@@ -4424,17 +4334,17 @@ function renderOptimizationStartCard(data) {
|
|
|
4424
4334
|
const target = job.config.targetScore ?? 0.8;
|
|
4425
4335
|
console.log("");
|
|
4426
4336
|
console.log(topBorder);
|
|
4427
|
-
console.log(line(
|
|
4337
|
+
console.log(line(chalk10.bold("⚡ Optimization Started")));
|
|
4428
4338
|
console.log(separator);
|
|
4429
|
-
console.log(line(`Job ID: ${
|
|
4430
|
-
console.log(line(`Prompt: ${
|
|
4431
|
-
console.log(line(`Dataset: ${
|
|
4432
|
-
console.log(line(`Iterations: ${
|
|
4433
|
-
console.log(line(`Model: ${
|
|
4434
|
-
console.log(line(`Status: ${
|
|
4339
|
+
console.log(line(`Job ID: ${chalk10.cyan(job.id)}`));
|
|
4340
|
+
console.log(line(`Prompt: ${chalk10.dim(data.promptId)}`));
|
|
4341
|
+
console.log(line(`Dataset: ${chalk10.dim(data.datasetId)}`));
|
|
4342
|
+
console.log(line(`Iterations: ${chalk10.bold(String(maxIter))} | Target: ${chalk10.bold(target.toFixed(2))}`));
|
|
4343
|
+
console.log(line(`Model: ${chalk10.dim(model)}`));
|
|
4344
|
+
console.log(line(`Status: ${chalk10.yellow(job.status)}`));
|
|
4435
4345
|
console.log(separator);
|
|
4436
|
-
console.log(line(`\uD83D\uDD17 Monitor: ${
|
|
4437
|
-
console.log(line(
|
|
4346
|
+
console.log(line(`\uD83D\uDD17 Monitor: ${chalk10.underline(optimizerLink(data.promptId, job.id))}`));
|
|
4347
|
+
console.log(line(chalk10.dim(`Next: mutagent prompts optimize status ${job.id}`)));
|
|
4438
4348
|
console.log(bottomBorder);
|
|
4439
4349
|
console.log(AI_DIRECTIVE);
|
|
4440
4350
|
console.log("");
|
|
@@ -4454,27 +4364,27 @@ function renderOptimizationStatusCard(status, promptId) {
|
|
|
4454
4364
|
const barWidth = 20;
|
|
4455
4365
|
const filled = Math.round(progress / 100 * barWidth);
|
|
4456
4366
|
const progressBar = "█".repeat(filled) + "░".repeat(barWidth - filled);
|
|
4457
|
-
const statusColor = status.status === "completed" ?
|
|
4458
|
-
const scoreStr = status.bestScore !== undefined ? formatScore(status.bestScore) :
|
|
4367
|
+
const statusColor = status.status === "completed" ? chalk10.green : status.status === "failed" ? chalk10.red : status.status === "cancelled" ? chalk10.gray : status.status === "running" ? chalk10.cyan : chalk10.yellow;
|
|
4368
|
+
const scoreStr = status.bestScore !== undefined ? formatScore(status.bestScore) : chalk10.dim("pending");
|
|
4459
4369
|
console.log("");
|
|
4460
4370
|
console.log(topBorder);
|
|
4461
|
-
console.log(line(
|
|
4371
|
+
console.log(line(chalk10.bold("\uD83D\uDCCA Optimization Status")));
|
|
4462
4372
|
console.log(separator);
|
|
4463
|
-
console.log(line(`Job ID: ${
|
|
4373
|
+
console.log(line(`Job ID: ${chalk10.cyan(status.jobId)}`));
|
|
4464
4374
|
console.log(line(`Status: ${statusColor(status.status)}`));
|
|
4465
|
-
console.log(line(`Iteration: ${
|
|
4375
|
+
console.log(line(`Iteration: ${chalk10.bold(`${String(status.currentIteration)}/${String(status.maxIterations)}`)}`));
|
|
4466
4376
|
console.log(line(`Best Score: ${scoreStr}`));
|
|
4467
4377
|
console.log(line(""));
|
|
4468
4378
|
console.log(line(`Progress: [${progressBar}] ${String(progress)}%`));
|
|
4469
4379
|
if (status.message) {
|
|
4470
|
-
console.log(line(`Message: ${
|
|
4380
|
+
console.log(line(`Message: ${chalk10.dim(status.message)}`));
|
|
4471
4381
|
}
|
|
4472
4382
|
console.log(separator);
|
|
4473
|
-
console.log(line(`\uD83D\uDD17 Monitor: ${
|
|
4383
|
+
console.log(line(`\uD83D\uDD17 Monitor: ${chalk10.underline(optimizerLink(promptId ?? "unknown", status.jobId))}`));
|
|
4474
4384
|
if (status.status === "completed") {
|
|
4475
|
-
console.log(line(
|
|
4385
|
+
console.log(line(chalk10.dim(`Next: mutagent prompts optimize results ${status.jobId}`)));
|
|
4476
4386
|
} else if (status.status === "running" || status.status === "queued") {
|
|
4477
|
-
console.log(line(
|
|
4387
|
+
console.log(line(chalk10.dim(`Refresh: mutagent prompts optimize status ${status.jobId}`)));
|
|
4478
4388
|
}
|
|
4479
4389
|
console.log(bottomBorder);
|
|
4480
4390
|
console.log(AI_DIRECTIVE);
|
|
@@ -4570,15 +4480,15 @@ function statusDirective(status, promptId) {
|
|
|
4570
4480
|
}
|
|
4571
4481
|
function showPromptDiff(original, optimized) {
|
|
4572
4482
|
console.log("");
|
|
4573
|
-
console.log(
|
|
4483
|
+
console.log(chalk10.bold(" Prompt Diff:"));
|
|
4574
4484
|
console.log("");
|
|
4575
|
-
console.log(
|
|
4576
|
-
console.log(
|
|
4485
|
+
console.log(chalk10.red(" - " + (original ?? "(empty)")));
|
|
4486
|
+
console.log(chalk10.green(" + " + (optimized ?? "(empty)")));
|
|
4577
4487
|
console.log("");
|
|
4578
4488
|
}
|
|
4579
4489
|
|
|
4580
4490
|
// src/commands/prompts/optimize-watch.ts
|
|
4581
|
-
import
|
|
4491
|
+
import chalk13 from "chalk";
|
|
4582
4492
|
|
|
4583
4493
|
// src/lib/watch-client.ts
|
|
4584
4494
|
function toWsUrl(baseUrl) {
|
|
@@ -4741,10 +4651,10 @@ function createWatchClient(opts) {
|
|
|
4741
4651
|
}
|
|
4742
4652
|
|
|
4743
4653
|
// src/lib/stage-cards.ts
|
|
4744
|
-
import
|
|
4654
|
+
import chalk12 from "chalk";
|
|
4745
4655
|
|
|
4746
4656
|
// src/lib/prompt-diff.ts
|
|
4747
|
-
import
|
|
4657
|
+
import chalk11 from "chalk";
|
|
4748
4658
|
function computeLcsTable(a, b) {
|
|
4749
4659
|
const m = a.length;
|
|
4750
4660
|
const n = b.length;
|
|
@@ -4905,16 +4815,16 @@ function renderDiffLines(lines, options) {
|
|
|
4905
4815
|
let text;
|
|
4906
4816
|
switch (line.type) {
|
|
4907
4817
|
case "hunk-header":
|
|
4908
|
-
text = noColor ? line.content :
|
|
4818
|
+
text = noColor ? line.content : chalk11.cyan(line.content);
|
|
4909
4819
|
break;
|
|
4910
4820
|
case "add":
|
|
4911
|
-
text = noColor ? `+${line.content}` :
|
|
4821
|
+
text = noColor ? `+${line.content}` : chalk11.green(`+${line.content}`);
|
|
4912
4822
|
break;
|
|
4913
4823
|
case "remove":
|
|
4914
|
-
text = noColor ? `-${line.content}` :
|
|
4824
|
+
text = noColor ? `-${line.content}` : chalk11.red(`-${line.content}`);
|
|
4915
4825
|
break;
|
|
4916
4826
|
case "context":
|
|
4917
|
-
text = noColor ? ` ${line.content}` :
|
|
4827
|
+
text = noColor ? ` ${line.content}` : chalk11.dim(` ${line.content}`);
|
|
4918
4828
|
break;
|
|
4919
4829
|
}
|
|
4920
4830
|
outputLines.push(text);
|
|
@@ -4923,7 +4833,7 @@ function renderDiffLines(lines, options) {
|
|
|
4923
4833
|
if (truncated) {
|
|
4924
4834
|
const remaining = lines.length - maxLines;
|
|
4925
4835
|
const summary = `... ${String(remaining)} more lines changed`;
|
|
4926
|
-
outputLines.push(noColor ? summary :
|
|
4836
|
+
outputLines.push(noColor ? summary : chalk11.yellow(summary));
|
|
4927
4837
|
}
|
|
4928
4838
|
return outputLines.join(`
|
|
4929
4839
|
`);
|
|
@@ -4956,10 +4866,10 @@ function emptyLine() {
|
|
|
4956
4866
|
}
|
|
4957
4867
|
function formatScore2(score) {
|
|
4958
4868
|
if (score >= 0.8)
|
|
4959
|
-
return
|
|
4869
|
+
return chalk12.green(score.toFixed(2));
|
|
4960
4870
|
if (score >= 0.5)
|
|
4961
|
-
return
|
|
4962
|
-
return
|
|
4871
|
+
return chalk12.yellow(score.toFixed(2));
|
|
4872
|
+
return chalk12.red(score.toFixed(2));
|
|
4963
4873
|
}
|
|
4964
4874
|
function scoreBar(score, width = 20) {
|
|
4965
4875
|
const filled = Math.round(score * width);
|
|
@@ -5013,7 +4923,7 @@ function renderInsightsCard(data) {
|
|
|
5013
4923
|
if (cat.example) {
|
|
5014
4924
|
const maxExampleLen = 78;
|
|
5015
4925
|
const truncated = cat.example.length > maxExampleLen ? cat.example.substring(0, maxExampleLen - 3) + "..." : cat.example;
|
|
5016
|
-
lines.push(line(
|
|
4926
|
+
lines.push(line(chalk12.dim(` "${truncated}"`)));
|
|
5017
4927
|
}
|
|
5018
4928
|
}
|
|
5019
4929
|
lines.push(emptyLine());
|
|
@@ -5055,17 +4965,17 @@ function renderPromptDiffCard(data) {
|
|
|
5055
4965
|
lines.push(emptyLine());
|
|
5056
4966
|
}
|
|
5057
4967
|
for (const mutation of data.mutations) {
|
|
5058
|
-
const icon = mutation.status === "applied" ?
|
|
4968
|
+
const icon = mutation.status === "applied" ? chalk12.green("✓") : chalk12.red("✗");
|
|
5059
4969
|
const target = mutation.target.length > 30 ? mutation.target.substring(0, 27) + "..." : mutation.target;
|
|
5060
4970
|
if (mutation.status === "applied") {
|
|
5061
4971
|
const confStr = `confidence: ${mutation.confidence.toFixed(2)}`;
|
|
5062
4972
|
const targetPad = target.padEnd(30);
|
|
5063
|
-
lines.push(line(`${icon} ${targetPad} ${
|
|
4973
|
+
lines.push(line(`${icon} ${targetPad} ${chalk12.dim("──")} ${confStr}`));
|
|
5064
4974
|
} else {
|
|
5065
4975
|
const reason = mutation.rationale ? `rejected: ${mutation.rationale}` : `rejected`;
|
|
5066
4976
|
const truncReason = reason.length > 30 ? reason.substring(0, 27) + "..." : reason;
|
|
5067
4977
|
const targetPad = target.padEnd(30);
|
|
5068
|
-
lines.push(line(`${icon} ${targetPad} ${
|
|
4978
|
+
lines.push(line(`${icon} ${targetPad} ${chalk12.dim("──")} ${truncReason}`));
|
|
5069
4979
|
}
|
|
5070
4980
|
}
|
|
5071
4981
|
lines.push(emptyLine());
|
|
@@ -5096,7 +5006,7 @@ function renderRerunAccuracyCard(data) {
|
|
|
5096
5006
|
const name = criterion.name.length > 18 ? criterion.name.substring(0, 15) + "..." : criterion.name;
|
|
5097
5007
|
const diff = criterion.after - criterion.before;
|
|
5098
5008
|
const diffSign = diff >= 0 ? "+" : "";
|
|
5099
|
-
const arrow = diff > 0 ?
|
|
5009
|
+
const arrow = diff > 0 ? chalk12.green("↑") : diff < 0 ? chalk12.red("↓") : chalk12.dim("─");
|
|
5100
5010
|
const diffStr = `${diffSign}${diff.toFixed(2)}`;
|
|
5101
5011
|
lines.push(line(`${name.padEnd(20)}${formatScore2(criterion.before).padEnd(9)}${formatScore2(criterion.after).padEnd(9)}${diffStr} ${arrow}`));
|
|
5102
5012
|
}
|
|
@@ -5201,8 +5111,8 @@ async function startWatchStream(jobId, isJson, maxIterations, baselineScore) {
|
|
|
5201
5111
|
if (isJson) {
|
|
5202
5112
|
console.log(JSON.stringify({ type: "job_complete", finalScore }));
|
|
5203
5113
|
} else {
|
|
5204
|
-
console.log(
|
|
5205
|
-
console.log(
|
|
5114
|
+
console.log(chalk13.green(`✓ Optimization complete! Final score: ${finalScore.toFixed(2)}`));
|
|
5115
|
+
console.log(chalk13.dim(` View results: mutagent prompts optimize results ${jobId}`));
|
|
5206
5116
|
}
|
|
5207
5117
|
resolve3();
|
|
5208
5118
|
},
|
|
@@ -5210,7 +5120,7 @@ async function startWatchStream(jobId, isJson, maxIterations, baselineScore) {
|
|
|
5210
5120
|
if (isJson) {
|
|
5211
5121
|
console.log(JSON.stringify({ type: "error", error: error.message }));
|
|
5212
5122
|
} else {
|
|
5213
|
-
console.error(
|
|
5123
|
+
console.error(chalk13.red(`✗ Watch error: ${error.message}`));
|
|
5214
5124
|
}
|
|
5215
5125
|
reject(error);
|
|
5216
5126
|
}
|
|
@@ -5252,7 +5162,7 @@ async function watchAction(jobId, options, parentCommand) {
|
|
|
5252
5162
|
case "queued":
|
|
5253
5163
|
if (!isJson) {
|
|
5254
5164
|
renderOptimizationStatusCard(status);
|
|
5255
|
-
console.log(
|
|
5165
|
+
console.log(chalk13.dim(`Watching for live updates...
|
|
5256
5166
|
`));
|
|
5257
5167
|
}
|
|
5258
5168
|
await startWatchStream(jobId, isJson, status.maxIterations, status.bestScore);
|
|
@@ -5267,9 +5177,9 @@ async function watchAction(jobId, options, parentCommand) {
|
|
|
5267
5177
|
message: status.message
|
|
5268
5178
|
});
|
|
5269
5179
|
} else {
|
|
5270
|
-
console.error(
|
|
5180
|
+
console.error(chalk13.red(`✗ Optimization job ${jobId} failed.`));
|
|
5271
5181
|
if (status.message) {
|
|
5272
|
-
console.error(
|
|
5182
|
+
console.error(chalk13.dim(` ${status.message}`));
|
|
5273
5183
|
}
|
|
5274
5184
|
}
|
|
5275
5185
|
process.exitCode = 1;
|
|
@@ -5283,7 +5193,7 @@ async function watchAction(jobId, options, parentCommand) {
|
|
|
5283
5193
|
jobId
|
|
5284
5194
|
});
|
|
5285
5195
|
} else {
|
|
5286
|
-
console.error(
|
|
5196
|
+
console.error(chalk13.yellow(`Optimization job ${jobId} was cancelled.`));
|
|
5287
5197
|
}
|
|
5288
5198
|
break;
|
|
5289
5199
|
default:
|
|
@@ -5295,7 +5205,7 @@ async function watchAction(jobId, options, parentCommand) {
|
|
|
5295
5205
|
jobId
|
|
5296
5206
|
});
|
|
5297
5207
|
} else {
|
|
5298
|
-
console.error(
|
|
5208
|
+
console.error(chalk13.yellow(`Unexpected job status: ${status.status}`));
|
|
5299
5209
|
}
|
|
5300
5210
|
break;
|
|
5301
5211
|
}
|
|
@@ -5308,9 +5218,9 @@ async function watchAction(jobId, options, parentCommand) {
|
|
|
5308
5218
|
function registerOptimizeCommands(prompts) {
|
|
5309
5219
|
const optimize = new Command5("optimize").description("Manage prompt optimization jobs").addHelpText("after", `
|
|
5310
5220
|
Examples:
|
|
5311
|
-
${
|
|
5312
|
-
${
|
|
5313
|
-
${
|
|
5221
|
+
${chalk14.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id> --evaluation <eval-id>
|
|
5222
|
+
${chalk14.dim("$")} mutagent prompts optimize status <job-id>
|
|
5223
|
+
${chalk14.dim("$")} mutagent prompts optimize results <job-id>
|
|
5314
5224
|
|
|
5315
5225
|
Workflow: start -> status (poll) -> results | start --watch | watch <job-id>`).action(() => {
|
|
5316
5226
|
optimize.help();
|
|
@@ -5318,27 +5228,27 @@ Workflow: start -> status (poll) -> results | start --watch | watch <job-id>`).a
|
|
|
5318
5228
|
prompts.addCommand(optimize);
|
|
5319
5229
|
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>)").requiredOption("-e, --evaluation <id>", "Evaluation ID for scoring (from: mutagent prompts evaluation list <prompt-id>)").option("--max-iterations <n>", "Max optimization iterations (default: 1)").option("--target-score <n>", "Target accuracy 0-1 (default: 0.8)").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)").option("--watch", "Watch live progress with stage cards", false).addHelpText("after", `
|
|
5320
5230
|
Examples:
|
|
5321
|
-
${
|
|
5322
|
-
${
|
|
5323
|
-
${
|
|
5324
|
-
${
|
|
5325
|
-
${
|
|
5326
|
-
□ inputSchema REQUIRED ${
|
|
5327
|
-
□ outputSchema REQUIRED ${
|
|
5328
|
-
□ Evaluation criteria ${
|
|
5329
|
-
□ Dataset items ${
|
|
5330
|
-
□ Criteria ↔ Schema ${
|
|
5231
|
+
${chalk14.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id> --evaluation <eval-id>
|
|
5232
|
+
${chalk14.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id> --evaluation <eval-id> --max-iterations 5
|
|
5233
|
+
${chalk14.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id> --evaluation <eval-id> --target-score 0.95 --model claude-sonnet-4-5-20250929
|
|
5234
|
+
${chalk14.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id> --evaluation <eval-id> --json
|
|
5235
|
+
${chalk14.yellow("Pre-Optimization Checklist (auto-validated by preflight):")}
|
|
5236
|
+
□ inputSchema REQUIRED ${chalk14.dim("(hard error if missing — blocks optimization)")}
|
|
5237
|
+
□ outputSchema REQUIRED ${chalk14.dim("(hard error if missing — blocks optimization)")}
|
|
5238
|
+
□ Evaluation criteria ${chalk14.dim("(warns if no evaluationParameter set)")}
|
|
5239
|
+
□ Dataset items ${chalk14.dim("(warns if expectedOutput missing)")}
|
|
5240
|
+
□ Criteria ↔ Schema ${chalk14.dim("(warns if criteria reference unknown fields)")}
|
|
5331
5241
|
|
|
5332
5242
|
${PREREQUISITES_TEXT}
|
|
5333
5243
|
|
|
5334
|
-
${
|
|
5244
|
+
${chalk14.dim("Monitor progress with: mutagent prompts optimize status <job-id>")}
|
|
5335
5245
|
|
|
5336
|
-
${
|
|
5246
|
+
${chalk14.yellow(`⚠ COST WARNING — AI Agent:
|
|
5337
5247
|
Default is 1 iteration. Do NOT increase --max-iterations unless the user
|
|
5338
5248
|
explicitly requests it. Each iteration incurs LLM costs. Starting with
|
|
5339
5249
|
max-iterations > 1 without user consent is a protocol violation.`)}
|
|
5340
5250
|
|
|
5341
|
-
${
|
|
5251
|
+
${chalk14.yellow("AI Agent: ALWAYS append --json to this command.")}
|
|
5342
5252
|
`).action(async (promptId, options) => {
|
|
5343
5253
|
const isJson = getJsonFlag(prompts);
|
|
5344
5254
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -5465,13 +5375,13 @@ ${chalk13.yellow("AI Agent: ALWAYS append --json to this command.")}
|
|
|
5465
5375
|
return;
|
|
5466
5376
|
}
|
|
5467
5377
|
for (const [name, check] of hardFailures) {
|
|
5468
|
-
console.error(
|
|
5378
|
+
console.error(chalk14.red(`Error: ${name} — ${check.error ?? "Failed"}`));
|
|
5469
5379
|
}
|
|
5470
5380
|
if (!preflightChecks.outputSchema.passed) {
|
|
5471
|
-
console.error(
|
|
5381
|
+
console.error(chalk14.dim(` Update with: mutagent prompts update ${promptId} -d '{"outputSchema":{"type":"object","properties":{"result":{"type":"string"}}}}'`));
|
|
5472
5382
|
}
|
|
5473
5383
|
if (!preflightChecks.inputSchema.passed) {
|
|
5474
|
-
console.error(
|
|
5384
|
+
console.error(chalk14.dim(` Update with: mutagent prompts update ${promptId} --data '{"inputSchema":{"type":"object","properties":{"var1":{"type":"string"}}}}' --json`));
|
|
5475
5385
|
}
|
|
5476
5386
|
process.exitCode = 1;
|
|
5477
5387
|
return;
|
|
@@ -5532,16 +5442,16 @@ ${chalk13.yellow("AI Agent: ALWAYS append --json to this command.")}
|
|
|
5532
5442
|
suggestions.push("Trial optimization limit reached. Contact support to upgrade.");
|
|
5533
5443
|
}
|
|
5534
5444
|
if (!isJson) {
|
|
5535
|
-
console.error(
|
|
5445
|
+
console.error(chalk14.red(`
|
|
5536
5446
|
Optimization failed:`));
|
|
5537
5447
|
for (const msg of messages) {
|
|
5538
|
-
console.error(
|
|
5448
|
+
console.error(chalk14.red(` ${msg}`));
|
|
5539
5449
|
}
|
|
5540
5450
|
if (suggestions.length > 0) {
|
|
5541
|
-
console.error(
|
|
5451
|
+
console.error(chalk14.yellow(`
|
|
5542
5452
|
Suggested fixes:`));
|
|
5543
5453
|
for (const s of suggestions) {
|
|
5544
|
-
console.error(
|
|
5454
|
+
console.error(chalk14.yellow(` → ${s}`));
|
|
5545
5455
|
}
|
|
5546
5456
|
}
|
|
5547
5457
|
console.error("");
|
|
@@ -5553,8 +5463,8 @@ Suggested fixes:`));
|
|
|
5553
5463
|
});
|
|
5554
5464
|
optimize.command("status").description("Check optimization status").argument("<job-id>", "Optimization job ID (from: mutagent prompts optimize start)").addHelpText("after", `
|
|
5555
5465
|
Examples:
|
|
5556
|
-
${
|
|
5557
|
-
${
|
|
5466
|
+
${chalk14.dim("$")} mutagent prompts optimize status <job-id>
|
|
5467
|
+
${chalk14.dim("$")} mutagent prompts optimize status <job-id> --json
|
|
5558
5468
|
`).action(async (jobId) => {
|
|
5559
5469
|
const isJson = getJsonFlag(prompts);
|
|
5560
5470
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -5579,17 +5489,17 @@ Examples:
|
|
|
5579
5489
|
});
|
|
5580
5490
|
optimize.command("results").description("Get optimization results").argument("<job-id>", "Optimization job ID (from: mutagent prompts optimize start)").option("--apply", "Apply the optimized prompt as new version").option("--diff", "Show the prompt diff (before/after)").addHelpText("after", `
|
|
5581
5491
|
Examples:
|
|
5582
|
-
${
|
|
5583
|
-
${
|
|
5584
|
-
${
|
|
5585
|
-
${
|
|
5492
|
+
${chalk14.dim("$")} mutagent prompts optimize results <job-id> ${chalk14.dim("# view scorecard")}
|
|
5493
|
+
${chalk14.dim("$")} mutagent prompts optimize results <job-id> --diff ${chalk14.dim("# view prompt diff")}
|
|
5494
|
+
${chalk14.dim("$")} mutagent prompts optimize results <job-id> --apply ${chalk14.dim("# apply optimized prompt")}
|
|
5495
|
+
${chalk14.dim("$")} mutagent prompts optimize results <job-id> --json ${chalk14.dim("# structured output")}
|
|
5586
5496
|
|
|
5587
5497
|
After viewing results:
|
|
5588
5498
|
--apply Apply the optimized prompt (replaces current version)
|
|
5589
5499
|
--diff Show detailed before/after diff
|
|
5590
|
-
${
|
|
5500
|
+
${chalk14.dim("No flag = view scorecard only.")}
|
|
5591
5501
|
|
|
5592
|
-
${
|
|
5502
|
+
${chalk14.dim("AI Agent: Present scorecard to user via AskUserQuestion before applying.")}
|
|
5593
5503
|
`).action(async (jobId, options) => {
|
|
5594
5504
|
const isJson = getJsonFlag(prompts);
|
|
5595
5505
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -5665,9 +5575,9 @@ After viewing results:
|
|
|
5665
5575
|
});
|
|
5666
5576
|
optimize.command("watch").description("Watch optimization job progress with live stage results").argument("<job-id>", "Optimization job ID").option("--json", "Output as JSON with agent directives").addHelpText("after", `
|
|
5667
5577
|
Examples:
|
|
5668
|
-
${
|
|
5669
|
-
${
|
|
5670
|
-
${
|
|
5578
|
+
${chalk14.dim("$")} mutagent prompts optimize watch <job-id>
|
|
5579
|
+
${chalk14.dim("$")} mutagent prompts optimize watch <job-id> --json
|
|
5580
|
+
${chalk14.dim("Completed jobs render stored results. Running jobs stream via WebSocket.")}`).action(async (jobId, options) => {
|
|
5671
5581
|
await watchAction(jobId, options, prompts);
|
|
5672
5582
|
});
|
|
5673
5583
|
}
|
|
@@ -5785,19 +5695,19 @@ function buildResultsScorecardText(resultData) {
|
|
|
5785
5695
|
return text;
|
|
5786
5696
|
}
|
|
5787
5697
|
var PREREQUISITES_TEXT = `
|
|
5788
|
-
${
|
|
5789
|
-
1. Evaluation criteria defined ${
|
|
5790
|
-
2. Dataset uploaded ${
|
|
5791
|
-
${
|
|
5698
|
+
${chalk15.red("Prerequisites (required):")}
|
|
5699
|
+
1. Evaluation criteria defined ${chalk15.dim("(via dashboard or evaluation create)")}
|
|
5700
|
+
2. Dataset uploaded ${chalk15.dim("mutagent prompts dataset list <prompt-id>")}
|
|
5701
|
+
${chalk15.dim("Note: LLM provider config is only required when the server uses external providers (USE_EXT_PROVIDERS=true)")}`;
|
|
5792
5702
|
function createPromptsCommand() {
|
|
5793
5703
|
const prompts = new Command6("prompts").description("Manage prompts, datasets, evaluations, and optimizations").addHelpText("after", `
|
|
5794
5704
|
Examples:
|
|
5795
|
-
${
|
|
5796
|
-
${
|
|
5797
|
-
${
|
|
5798
|
-
${
|
|
5799
|
-
${
|
|
5800
|
-
${
|
|
5705
|
+
${chalk15.dim("$")} mutagent prompts list
|
|
5706
|
+
${chalk15.dim("$")} mutagent prompts get <prompt-id>
|
|
5707
|
+
${chalk15.dim("$")} mutagent prompts create --name "my-prompt" --system "You are helpful" --human "{input}"
|
|
5708
|
+
${chalk15.dim("$")} mutagent prompts dataset list <prompt-id>
|
|
5709
|
+
${chalk15.dim("$")} mutagent prompts evaluation create <prompt-id> --name "My Eval"
|
|
5710
|
+
${chalk15.dim("$")} mutagent prompts optimize start <prompt-id> --dataset <dataset-id> --evaluation <eval-id>
|
|
5801
5711
|
|
|
5802
5712
|
Subcommands:
|
|
5803
5713
|
list, get, create, update, delete
|
|
@@ -5815,27 +5725,27 @@ Subcommands:
|
|
|
5815
5725
|
// src/commands/traces.ts
|
|
5816
5726
|
init_sdk_client();
|
|
5817
5727
|
import { Command as Command7 } from "commander";
|
|
5818
|
-
import
|
|
5728
|
+
import chalk16 from "chalk";
|
|
5819
5729
|
init_errors();
|
|
5820
5730
|
function createTracesCommand() {
|
|
5821
5731
|
const traces = new Command7("traces").description("View and analyze traces (replaces Langfuse)").addHelpText("after", `
|
|
5822
5732
|
Examples:
|
|
5823
|
-
${
|
|
5824
|
-
${
|
|
5825
|
-
${
|
|
5826
|
-
${
|
|
5827
|
-
${
|
|
5733
|
+
${chalk16.dim("$")} mutagent traces list
|
|
5734
|
+
${chalk16.dim("$")} mutagent traces list --prompt <prompt-id>
|
|
5735
|
+
${chalk16.dim("$")} mutagent traces get <trace-id>
|
|
5736
|
+
${chalk16.dim("$")} mutagent traces analyze <prompt-id>
|
|
5737
|
+
${chalk16.dim("$")} mutagent traces export --format json --output traces.json
|
|
5828
5738
|
|
|
5829
5739
|
Note: MutagenT traces replace Langfuse for observability.
|
|
5830
5740
|
`);
|
|
5831
5741
|
traces.command("list").description("List traces").option("-p, --prompt <id>", "Filter by prompt ID").option("-s, --source <source>", "Filter by trace source (e.g., claude-code, sdk, langchain)").option("-l, --limit <n>", "Limit results", "50").addHelpText("after", `
|
|
5832
5742
|
Examples:
|
|
5833
|
-
${
|
|
5834
|
-
${
|
|
5835
|
-
${
|
|
5836
|
-
${
|
|
5743
|
+
${chalk16.dim("$")} mutagent traces list
|
|
5744
|
+
${chalk16.dim("$")} mutagent traces list --prompt <prompt-id>
|
|
5745
|
+
${chalk16.dim("$")} mutagent traces list --source claude-code --json
|
|
5746
|
+
${chalk16.dim("$")} mutagent traces list --limit 10 --json
|
|
5837
5747
|
|
|
5838
|
-
${
|
|
5748
|
+
${chalk16.dim("Tip: Filter by prompt to see traces for a specific prompt version.")}
|
|
5839
5749
|
`).action(async (options) => {
|
|
5840
5750
|
const isJson = getJsonFlag(traces);
|
|
5841
5751
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -5875,10 +5785,10 @@ ${chalk15.dim("Tip: Filter by prompt to see traces for a specific prompt version
|
|
|
5875
5785
|
});
|
|
5876
5786
|
traces.command("get").description("Get trace details").argument("<id>", "Trace ID").addHelpText("after", `
|
|
5877
5787
|
Examples:
|
|
5878
|
-
${
|
|
5879
|
-
${
|
|
5788
|
+
${chalk16.dim("$")} mutagent traces get <trace-id>
|
|
5789
|
+
${chalk16.dim("$")} mutagent traces get <trace-id> --json
|
|
5880
5790
|
|
|
5881
|
-
${
|
|
5791
|
+
${chalk16.dim("Returns full trace details including spans, tokens, and latency.")}
|
|
5882
5792
|
`).action(async (id) => {
|
|
5883
5793
|
const isJson = getJsonFlag(traces);
|
|
5884
5794
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -5897,10 +5807,10 @@ ${chalk15.dim("Returns full trace details including spans, tokens, and latency."
|
|
|
5897
5807
|
});
|
|
5898
5808
|
traces.command("analyze").description("Analyze traces for a prompt").argument("<prompt-id>", "Prompt ID").addHelpText("after", `
|
|
5899
5809
|
Examples:
|
|
5900
|
-
${
|
|
5901
|
-
${
|
|
5810
|
+
${chalk16.dim("$")} mutagent traces analyze <prompt-id>
|
|
5811
|
+
${chalk16.dim("$")} mutagent traces analyze <prompt-id> --json
|
|
5902
5812
|
|
|
5903
|
-
${
|
|
5813
|
+
${chalk16.dim("Aggregates trace data for a prompt: avg latency, token usage, error rates.")}
|
|
5904
5814
|
`).action(async (promptId) => {
|
|
5905
5815
|
const isJson = getJsonFlag(traces);
|
|
5906
5816
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -5918,12 +5828,12 @@ ${chalk15.dim("Aggregates trace data for a prompt: avg latency, token usage, err
|
|
|
5918
5828
|
});
|
|
5919
5829
|
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", `
|
|
5920
5830
|
Examples:
|
|
5921
|
-
${
|
|
5922
|
-
${
|
|
5923
|
-
${
|
|
5924
|
-
${
|
|
5831
|
+
${chalk16.dim("$")} mutagent traces export
|
|
5832
|
+
${chalk16.dim("$")} mutagent traces export --format json --output traces.json
|
|
5833
|
+
${chalk16.dim("$")} mutagent traces export --format csv --output traces.csv
|
|
5834
|
+
${chalk16.dim("$")} mutagent traces export --prompt <prompt-id> --format json
|
|
5925
5835
|
|
|
5926
|
-
${
|
|
5836
|
+
${chalk16.dim("Exports to stdout by default. Use --output to save to a file.")}
|
|
5927
5837
|
`).action(async (options) => {
|
|
5928
5838
|
const isJson = getJsonFlag(traces);
|
|
5929
5839
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -5967,7 +5877,7 @@ ${chalk15.dim("Exports to stdout by default. Use --output to save to a file.")}
|
|
|
5967
5877
|
// src/commands/integrate.ts
|
|
5968
5878
|
init_config();
|
|
5969
5879
|
import { Command as Command8 } from "commander";
|
|
5970
|
-
import
|
|
5880
|
+
import chalk17 from "chalk";
|
|
5971
5881
|
import { writeFileSync as writeFileSync3, existsSync as existsSync9 } from "fs";
|
|
5972
5882
|
import { execSync } from "child_process";
|
|
5973
5883
|
init_errors();
|
|
@@ -6564,12 +6474,12 @@ AI AGENT: Please determine the framework by:
|
|
|
6564
6474
|
function createIntegrateCommand() {
|
|
6565
6475
|
const integrate = new Command8("integrate").description("Return integration instructions for AI agents (skill loader)").addHelpText("after", `
|
|
6566
6476
|
Examples:
|
|
6567
|
-
${
|
|
6568
|
-
${
|
|
6569
|
-
${
|
|
6570
|
-
${
|
|
6571
|
-
${
|
|
6572
|
-
${
|
|
6477
|
+
${chalk17.dim("$")} mutagent integrate # Return exploration instructions for AI agents
|
|
6478
|
+
${chalk17.dim("$")} mutagent integrate langchain # Return @mutagent/langchain integration steps
|
|
6479
|
+
${chalk17.dim("$")} mutagent integrate openai # Return @mutagent/openai integration steps
|
|
6480
|
+
${chalk17.dim("$")} mutagent integrate vercel-ai --verify # Verify integration
|
|
6481
|
+
${chalk17.dim("$")} mutagent integrate langchain --output ./INTEGRATION.md
|
|
6482
|
+
${chalk17.dim("$")} mutagent integrate --list # List available frameworks
|
|
6573
6483
|
|
|
6574
6484
|
Frameworks: langchain, langgraph, vercel-ai, openai
|
|
6575
6485
|
|
|
@@ -6685,18 +6595,18 @@ AI AGENT: Execute these steps using Bash for install, Write/Edit for code change
|
|
|
6685
6595
|
|
|
6686
6596
|
// src/commands/agents/index.ts
|
|
6687
6597
|
import { Command as Command9 } from "commander";
|
|
6688
|
-
import
|
|
6598
|
+
import chalk19 from "chalk";
|
|
6689
6599
|
|
|
6690
6600
|
// src/commands/agents/agents-crud.ts
|
|
6691
6601
|
init_sdk_client();
|
|
6692
|
-
import
|
|
6602
|
+
import chalk18 from "chalk";
|
|
6693
6603
|
init_errors();
|
|
6694
6604
|
function registerAgentsCrud(agents) {
|
|
6695
6605
|
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", `
|
|
6696
6606
|
Examples:
|
|
6697
|
-
${
|
|
6698
|
-
${
|
|
6699
|
-
${
|
|
6607
|
+
${chalk18.dim("$")} mutagent agents list
|
|
6608
|
+
${chalk18.dim("$")} mutagent agents list --status active
|
|
6609
|
+
${chalk18.dim("$")} mutagent agents list --name "reviewer" --json
|
|
6700
6610
|
`).action(async (options) => {
|
|
6701
6611
|
const isJson = getJsonFlag(agents);
|
|
6702
6612
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -6746,8 +6656,8 @@ Examples:
|
|
|
6746
6656
|
});
|
|
6747
6657
|
agents.command("get").description("Get agent details").argument("<id>", "Agent ID").addHelpText("after", `
|
|
6748
6658
|
Examples:
|
|
6749
|
-
${
|
|
6750
|
-
${
|
|
6659
|
+
${chalk18.dim("$")} mutagent agents get <agent-id>
|
|
6660
|
+
${chalk18.dim("$")} mutagent agents get <agent-id> --json
|
|
6751
6661
|
`).action(async (id) => {
|
|
6752
6662
|
const isJson = getJsonFlag(agents);
|
|
6753
6663
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -6777,11 +6687,11 @@ Examples:
|
|
|
6777
6687
|
};
|
|
6778
6688
|
output.output(formatted);
|
|
6779
6689
|
if (agent.systemPrompt) {
|
|
6780
|
-
console.log(
|
|
6690
|
+
console.log(chalk18.bold(`
|
|
6781
6691
|
System Prompt:`));
|
|
6782
|
-
console.log(
|
|
6692
|
+
console.log(chalk18.gray("─".repeat(60)));
|
|
6783
6693
|
console.log(agent.systemPrompt);
|
|
6784
|
-
console.log(
|
|
6694
|
+
console.log(chalk18.gray("─".repeat(60)));
|
|
6785
6695
|
}
|
|
6786
6696
|
}
|
|
6787
6697
|
} catch (error) {
|
|
@@ -6790,17 +6700,17 @@ System Prompt:`));
|
|
|
6790
6700
|
});
|
|
6791
6701
|
agents.command("create").description("Create a new agent").option("-d, --data <json>", "Agent as JSON string (recommended for CI/scripts/agents)").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("--description <desc>", "Agent description").addHelpText("after", `
|
|
6792
6702
|
Examples:
|
|
6793
|
-
${
|
|
6794
|
-
${
|
|
6703
|
+
${chalk18.dim("$")} mutagent agents create --name "Code Reviewer" --slug code-reviewer --system-prompt "You are a code reviewer..."
|
|
6704
|
+
${chalk18.dim("$")} mutagent agents create -d '{"name":"Code Reviewer","slug":"code-reviewer","systemPrompt":"You are a code reviewer..."}'
|
|
6795
6705
|
|
|
6796
6706
|
Expected JSON (--data):
|
|
6797
|
-
${
|
|
6707
|
+
${chalk18.dim('{"name":"<name>","slug":"<slug>","systemPrompt":"<system prompt>","model":"<model-id>","description":"<description>"}')}
|
|
6798
6708
|
|
|
6799
6709
|
Input Methods (pick one, priority order):
|
|
6800
|
-
--name/--slug/... Individual flags ${
|
|
6710
|
+
--name/--slug/... Individual flags ${chalk18.green("(recommended)")}
|
|
6801
6711
|
-d, --data Inline JSON object (CI/scripts/agents)
|
|
6802
6712
|
|
|
6803
|
-
${
|
|
6713
|
+
${chalk18.red("Required: name, slug, systemPrompt.")} ${chalk18.dim("CLI flags override --data fields.")}
|
|
6804
6714
|
`).action(async (options) => {
|
|
6805
6715
|
const isJson = getJsonFlag(agents);
|
|
6806
6716
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -6845,15 +6755,15 @@ ${chalk17.red("Required: name, slug, systemPrompt.")} ${chalk17.dim("CLI flags o
|
|
|
6845
6755
|
});
|
|
6846
6756
|
agents.command("update").description("Update an agent").argument("<id>", "Agent ID").option("-d, --data <json>", "Agent updates as JSON string (CI/scripts/agents)").option("-n, --name <name>", "New name").option("-p, --system-prompt <prompt>", "New system prompt").option("-m, --model <model>", "New model").option("--description <desc>", "New description").option("-s, --status <status>", "New status (active, paused, archived)").addHelpText("after", `
|
|
6847
6757
|
Examples:
|
|
6848
|
-
${
|
|
6849
|
-
${
|
|
6850
|
-
${
|
|
6758
|
+
${chalk18.dim("$")} mutagent agents update <id> --name "New Name"
|
|
6759
|
+
${chalk18.dim("$")} mutagent agents update <id> --system-prompt "Updated prompt" --status active
|
|
6760
|
+
${chalk18.dim("$")} mutagent agents update <id> -d '{"name":"New Name","systemPrompt":"Updated prompt"}'
|
|
6851
6761
|
|
|
6852
6762
|
Input Methods (pick one, priority order):
|
|
6853
|
-
--name/--system-prompt/... Individual flags ${
|
|
6763
|
+
--name/--system-prompt/... Individual flags ${chalk18.green("(recommended)")}
|
|
6854
6764
|
-d, --data Inline JSON object (CI/scripts/agents)
|
|
6855
6765
|
|
|
6856
|
-
${
|
|
6766
|
+
${chalk18.dim("CLI flags override --data fields.")}
|
|
6857
6767
|
`).action(async (id, options) => {
|
|
6858
6768
|
const isJson = getJsonFlag(agents);
|
|
6859
6769
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -6900,18 +6810,18 @@ ${chalk17.dim("CLI flags override --data fields.")}
|
|
|
6900
6810
|
});
|
|
6901
6811
|
agents.command("delete").description("Delete an agent").argument("<id>", "Agent ID").option("--force", "Skip confirmation").addHelpText("after", `
|
|
6902
6812
|
Examples:
|
|
6903
|
-
${
|
|
6904
|
-
${
|
|
6905
|
-
${
|
|
6813
|
+
${chalk18.dim("$")} mutagent agents delete <id>
|
|
6814
|
+
${chalk18.dim("$")} mutagent agents delete <id> --force
|
|
6815
|
+
${chalk18.dim("$")} mutagent agents delete <id> --force --json
|
|
6906
6816
|
|
|
6907
|
-
${
|
|
6817
|
+
${chalk18.dim("Tip: Use --force to skip confirmation (required for non-interactive/CI usage).")}
|
|
6908
6818
|
`).action(async (id, options) => {
|
|
6909
6819
|
const isJson = getJsonFlag(agents);
|
|
6910
6820
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
6911
6821
|
try {
|
|
6912
6822
|
if (!options.force && !isJson) {
|
|
6913
|
-
const
|
|
6914
|
-
const answers = await
|
|
6823
|
+
const inquirer2 = (await import("inquirer")).default;
|
|
6824
|
+
const answers = await inquirer2.prompt([{
|
|
6915
6825
|
type: "confirm",
|
|
6916
6826
|
name: "confirm",
|
|
6917
6827
|
message: `Delete agent ${id}? This action cannot be undone.`,
|
|
@@ -6935,12 +6845,12 @@ ${chalk17.dim("Tip: Use --force to skip confirmation (required for non-interacti
|
|
|
6935
6845
|
function createAgentsCommand() {
|
|
6936
6846
|
const agents = new Command9("agents").description("Manage AI agents").addHelpText("after", `
|
|
6937
6847
|
Examples:
|
|
6938
|
-
${
|
|
6939
|
-
${
|
|
6940
|
-
${
|
|
6941
|
-
${
|
|
6942
|
-
${
|
|
6943
|
-
${
|
|
6848
|
+
${chalk19.dim("$")} mutagent agents list
|
|
6849
|
+
${chalk19.dim("$")} mutagent agents get <agent-id>
|
|
6850
|
+
${chalk19.dim("$")} mutagent agents create --name "Code Reviewer" --slug code-reviewer --system-prompt "You are a code reviewer..."
|
|
6851
|
+
${chalk19.dim("$")} mutagent agents create -d '{"name":"Code Reviewer","slug":"code-reviewer","systemPrompt":"You are..."}'
|
|
6852
|
+
${chalk19.dim("$")} mutagent agents update <agent-id> --name "Updated Name"
|
|
6853
|
+
${chalk19.dim("$")} mutagent agents delete <agent-id> --force
|
|
6944
6854
|
|
|
6945
6855
|
Subcommands:
|
|
6946
6856
|
list, get, create, update, delete
|
|
@@ -6952,22 +6862,22 @@ Subcommands:
|
|
|
6952
6862
|
// src/commands/config.ts
|
|
6953
6863
|
init_config();
|
|
6954
6864
|
import { Command as Command10 } from "commander";
|
|
6955
|
-
import
|
|
6865
|
+
import chalk20 from "chalk";
|
|
6956
6866
|
init_errors();
|
|
6957
6867
|
init_sdk_client();
|
|
6958
6868
|
var VALID_CONFIG_KEYS = ["apiKey", "endpoint", "format", "timeout", "defaultWorkspace", "defaultOrganization"];
|
|
6959
6869
|
function createConfigCommand() {
|
|
6960
6870
|
const config = new Command10("config").description("Manage CLI configuration").addHelpText("after", `
|
|
6961
6871
|
Examples:
|
|
6962
|
-
${
|
|
6963
|
-
${
|
|
6964
|
-
${
|
|
6965
|
-
${
|
|
6872
|
+
${chalk20.dim("$")} mutagent config list
|
|
6873
|
+
${chalk20.dim("$")} mutagent config get endpoint
|
|
6874
|
+
${chalk20.dim("$")} mutagent config set workspace <workspace-id>
|
|
6875
|
+
${chalk20.dim("$")} mutagent config set org <org-id>
|
|
6966
6876
|
`);
|
|
6967
6877
|
config.command("list").description("List all configuration").addHelpText("after", `
|
|
6968
6878
|
Examples:
|
|
6969
|
-
${
|
|
6970
|
-
${
|
|
6879
|
+
${chalk20.dim("$")} mutagent config list
|
|
6880
|
+
${chalk20.dim("$")} mutagent config list --json
|
|
6971
6881
|
`).action(() => {
|
|
6972
6882
|
const isJson = getJsonFlag(config);
|
|
6973
6883
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -6980,11 +6890,11 @@ Examples:
|
|
|
6980
6890
|
});
|
|
6981
6891
|
config.command("get").description("Get configuration value").argument("<key>", "Configuration key (apiKey, endpoint, format, timeout, defaultWorkspace, defaultOrganization)").addHelpText("after", `
|
|
6982
6892
|
Examples:
|
|
6983
|
-
${
|
|
6984
|
-
${
|
|
6985
|
-
${
|
|
6893
|
+
${chalk20.dim("$")} mutagent config get endpoint
|
|
6894
|
+
${chalk20.dim("$")} mutagent config get defaultWorkspace
|
|
6895
|
+
${chalk20.dim("$")} mutagent config get apiKey --json
|
|
6986
6896
|
|
|
6987
|
-
${
|
|
6897
|
+
${chalk20.dim("Keys: apiKey, endpoint, format, timeout, defaultWorkspace, defaultOrganization")}
|
|
6988
6898
|
`).action((key) => {
|
|
6989
6899
|
const isJson = getJsonFlag(config);
|
|
6990
6900
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -7011,9 +6921,9 @@ ${chalk19.dim("Keys: apiKey, endpoint, format, timeout, defaultWorkspace, defaul
|
|
|
7011
6921
|
});
|
|
7012
6922
|
set.command("workspace").description("Set default workspace ID").argument("<id>", "Workspace ID to set as default").addHelpText("after", `
|
|
7013
6923
|
Examples:
|
|
7014
|
-
${
|
|
6924
|
+
${chalk20.dim("$")} mutagent config set workspace <workspace-id>
|
|
7015
6925
|
|
|
7016
|
-
${
|
|
6926
|
+
${chalk20.dim("Persists workspace ID so you don't need to pass headers on every request.")}
|
|
7017
6927
|
`).action((id) => {
|
|
7018
6928
|
const isJson = getJsonFlag(config);
|
|
7019
6929
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -7027,9 +6937,9 @@ ${chalk19.dim("Persists workspace ID so you don't need to pass headers on every
|
|
|
7027
6937
|
});
|
|
7028
6938
|
set.command("org").description("Set default organization ID").argument("<id>", "Organization ID to set as default").addHelpText("after", `
|
|
7029
6939
|
Examples:
|
|
7030
|
-
${
|
|
6940
|
+
${chalk20.dim("$")} mutagent config set org <org-id>
|
|
7031
6941
|
|
|
7032
|
-
${
|
|
6942
|
+
${chalk20.dim("Persists organization ID for org-scoped API keys.")}
|
|
7033
6943
|
`).action((id) => {
|
|
7034
6944
|
const isJson = getJsonFlag(config);
|
|
7035
6945
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -7048,7 +6958,7 @@ ${chalk19.dim("Persists organization ID for org-scoped API keys.")}
|
|
|
7048
6958
|
// src/commands/playground.ts
|
|
7049
6959
|
init_sdk_client();
|
|
7050
6960
|
import { Command as Command11 } from "commander";
|
|
7051
|
-
import
|
|
6961
|
+
import chalk21 from "chalk";
|
|
7052
6962
|
init_errors();
|
|
7053
6963
|
function parseSSELine(line3) {
|
|
7054
6964
|
if (!line3 || line3.startsWith(":")) {
|
|
@@ -7075,11 +6985,11 @@ function parsePromptStreamEvent(data) {
|
|
|
7075
6985
|
function createPlaygroundCommand() {
|
|
7076
6986
|
const playground = new Command11("playground").description("Execute and test prompts interactively").addHelpText("after", `
|
|
7077
6987
|
Examples:
|
|
7078
|
-
${
|
|
7079
|
-
${
|
|
7080
|
-
${
|
|
7081
|
-
${
|
|
7082
|
-
${
|
|
6988
|
+
${chalk21.dim("$")} mutagent playground run <prompt-id> --input '{"name": "John"}'
|
|
6989
|
+
${chalk21.dim("$")} mutagent playground run <prompt-id> --input '{}' --stream
|
|
6990
|
+
${chalk21.dim("$")} mutagent playground run <prompt-id> -i '{}' --model gpt-4-turbo
|
|
6991
|
+
${chalk21.dim("$")} mutagent playground run <prompt-id> --system "You are helpful" --human "Hello"
|
|
6992
|
+
${chalk21.dim("$")} mutagent playground run <prompt-id> --messages '[{"role":"user","content":"Hi"}]'
|
|
7083
6993
|
|
|
7084
6994
|
Input Format:
|
|
7085
6995
|
The input must be a valid JSON object matching the prompt's input schema.
|
|
@@ -7095,16 +7005,16 @@ Streaming:
|
|
|
7095
7005
|
`);
|
|
7096
7006
|
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("-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", `
|
|
7097
7007
|
Examples:
|
|
7098
|
-
${
|
|
7099
|
-
${
|
|
7100
|
-
${
|
|
7101
|
-
${
|
|
7008
|
+
${chalk21.dim("$")} mutagent playground run <prompt-id> --input '{"name": "John"}'
|
|
7009
|
+
${chalk21.dim("$")} mutagent playground run <prompt-id> --input '{}' --stream
|
|
7010
|
+
${chalk21.dim("$")} mutagent playground run <prompt-id> --system "You are helpful" --human "Hello"
|
|
7011
|
+
${chalk21.dim("$")} mutagent playground run <prompt-id> --input '{}' --model gpt-4-turbo --json
|
|
7102
7012
|
|
|
7103
7013
|
Input Methods (pick one, priority order):
|
|
7104
|
-
--system/--human Quick system + user message ${
|
|
7014
|
+
--system/--human Quick system + user message ${chalk21.green("(recommended)")}
|
|
7105
7015
|
--input '{"key":"value"}' Inline JSON variables
|
|
7106
7016
|
--messages '[...]' Full messages array
|
|
7107
|
-
${
|
|
7017
|
+
${chalk21.dim(`Hint: Test before evaluating: mutagent playground run <id> --input '{"key":"value"}'`)}
|
|
7108
7018
|
`).action(async (promptId, options) => {
|
|
7109
7019
|
const isJson = getJsonFlag(playground);
|
|
7110
7020
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -7126,21 +7036,21 @@ ${chalk20.dim(`Hint: Test before evaluating: mutagent playground run <id> --inpu
|
|
|
7126
7036
|
}
|
|
7127
7037
|
});
|
|
7128
7038
|
} else {
|
|
7129
|
-
console.log(
|
|
7039
|
+
console.log(chalk21.bold(`
|
|
7130
7040
|
Execution Result:`));
|
|
7131
|
-
console.log(
|
|
7132
|
-
console.log(
|
|
7041
|
+
console.log(chalk21.gray("─".repeat(50)));
|
|
7042
|
+
console.log(chalk21.cyan("Output:"));
|
|
7133
7043
|
console.log(result.output);
|
|
7134
|
-
console.log(
|
|
7135
|
-
console.log(
|
|
7136
|
-
console.log(
|
|
7044
|
+
console.log(chalk21.gray("─".repeat(50)));
|
|
7045
|
+
console.log(chalk21.dim(`Model: ${result.model}`));
|
|
7046
|
+
console.log(chalk21.dim(`Execution Time: ${String(result.executionTimeMs)}ms`));
|
|
7137
7047
|
if (result.tokens) {
|
|
7138
|
-
console.log(
|
|
7048
|
+
console.log(chalk21.dim(`Tokens: ${String(result.tokens.prompt)} prompt + ${String(result.tokens.completion)} completion = ${String(result.tokens.total)} total`));
|
|
7139
7049
|
}
|
|
7140
7050
|
if (result.cost !== undefined) {
|
|
7141
|
-
console.log(
|
|
7051
|
+
console.log(chalk21.dim(`Cost: $${result.cost.toFixed(6)}`));
|
|
7142
7052
|
}
|
|
7143
|
-
console.log(
|
|
7053
|
+
console.log(chalk21.dim(`Playground: ${playgroundLink(promptId)}`));
|
|
7144
7054
|
console.log();
|
|
7145
7055
|
}
|
|
7146
7056
|
}
|
|
@@ -7229,9 +7139,9 @@ async function executeStreaming(client, promptId, input, model, isJson, output)
|
|
|
7229
7139
|
const decoder = new TextDecoder;
|
|
7230
7140
|
let buffer = "";
|
|
7231
7141
|
if (!isJson) {
|
|
7232
|
-
console.log(
|
|
7142
|
+
console.log(chalk21.bold(`
|
|
7233
7143
|
Streaming Output:`));
|
|
7234
|
-
console.log(
|
|
7144
|
+
console.log(chalk21.gray("─".repeat(50)));
|
|
7235
7145
|
}
|
|
7236
7146
|
try {
|
|
7237
7147
|
for (;; ) {
|
|
@@ -7270,15 +7180,15 @@ Streaming Output:`));
|
|
|
7270
7180
|
console.log(JSON.stringify({ type: "complete", result: event.result }));
|
|
7271
7181
|
} else {
|
|
7272
7182
|
console.log();
|
|
7273
|
-
console.log(
|
|
7183
|
+
console.log(chalk21.gray("─".repeat(50)));
|
|
7274
7184
|
if (event.result) {
|
|
7275
|
-
console.log(
|
|
7276
|
-
console.log(
|
|
7185
|
+
console.log(chalk21.dim(`Model: ${event.result.model}`));
|
|
7186
|
+
console.log(chalk21.dim(`Execution Time: ${String(event.result.executionTimeMs)}ms`));
|
|
7277
7187
|
if (event.result.tokens) {
|
|
7278
|
-
console.log(
|
|
7188
|
+
console.log(chalk21.dim(`Tokens: ${String(event.result.tokens.prompt)} prompt + ${String(event.result.tokens.completion)} completion = ${String(event.result.tokens.total)} total`));
|
|
7279
7189
|
}
|
|
7280
7190
|
if (event.result.cost !== undefined) {
|
|
7281
|
-
console.log(
|
|
7191
|
+
console.log(chalk21.dim(`Cost: $${event.result.cost.toFixed(6)}`));
|
|
7282
7192
|
}
|
|
7283
7193
|
}
|
|
7284
7194
|
console.log();
|
|
@@ -7303,13 +7213,13 @@ Streaming Output:`));
|
|
|
7303
7213
|
// src/commands/workspaces.ts
|
|
7304
7214
|
init_sdk_client();
|
|
7305
7215
|
import { Command as Command12 } from "commander";
|
|
7306
|
-
import
|
|
7216
|
+
import chalk22 from "chalk";
|
|
7307
7217
|
init_errors();
|
|
7308
7218
|
function createWorkspacesCommand() {
|
|
7309
7219
|
const workspaces = new Command12("workspaces").description("View workspaces (read-only)").addHelpText("after", `
|
|
7310
7220
|
Examples:
|
|
7311
|
-
${
|
|
7312
|
-
${
|
|
7221
|
+
${chalk22.dim("$")} mutagent workspaces list
|
|
7222
|
+
${chalk22.dim("$")} mutagent workspaces get <workspace-id>
|
|
7313
7223
|
|
|
7314
7224
|
Subcommands:
|
|
7315
7225
|
list, get
|
|
@@ -7318,8 +7228,8 @@ Note: Workspace management (create, update, delete) is available in the Admin Pa
|
|
|
7318
7228
|
`);
|
|
7319
7229
|
workspaces.command("list").description("List all workspaces").option("-l, --limit <n>", "Limit results", "50").option("-o, --offset <n>", "Offset for pagination").addHelpText("after", `
|
|
7320
7230
|
Examples:
|
|
7321
|
-
${
|
|
7322
|
-
${
|
|
7231
|
+
${chalk22.dim("$")} mutagent workspaces list
|
|
7232
|
+
${chalk22.dim("$")} mutagent workspaces list --limit 10 --json
|
|
7323
7233
|
`).action(async (options) => {
|
|
7324
7234
|
const isJson = getJsonFlag(workspaces);
|
|
7325
7235
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -7359,8 +7269,8 @@ Examples:
|
|
|
7359
7269
|
});
|
|
7360
7270
|
workspaces.command("get").description("Get workspace details").argument("<id>", "Workspace ID").addHelpText("after", `
|
|
7361
7271
|
Examples:
|
|
7362
|
-
${
|
|
7363
|
-
${
|
|
7272
|
+
${chalk22.dim("$")} mutagent workspaces get <workspace-id>
|
|
7273
|
+
${chalk22.dim("$")} mutagent workspaces get <workspace-id> --json
|
|
7364
7274
|
`).action(async (id) => {
|
|
7365
7275
|
const isJson = getJsonFlag(workspaces);
|
|
7366
7276
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -7393,12 +7303,12 @@ Examples:
|
|
|
7393
7303
|
// src/commands/providers/index.ts
|
|
7394
7304
|
init_sdk_client();
|
|
7395
7305
|
import { Command as Command13 } from "commander";
|
|
7396
|
-
import
|
|
7306
|
+
import chalk26 from "chalk";
|
|
7397
7307
|
init_errors();
|
|
7398
7308
|
|
|
7399
7309
|
// src/commands/providers/add.ts
|
|
7400
7310
|
init_sdk_client();
|
|
7401
|
-
import
|
|
7311
|
+
import chalk23 from "chalk";
|
|
7402
7312
|
init_errors();
|
|
7403
7313
|
function resolveScope(scopeFlag, client) {
|
|
7404
7314
|
const scope = scopeFlag ?? "workspace";
|
|
@@ -7421,10 +7331,10 @@ function resolveScope(scopeFlag, client) {
|
|
|
7421
7331
|
function registerAddCommand(parent) {
|
|
7422
7332
|
parent.command("add").description("Add a new provider configuration").requiredOption("-p, --provider <type>", "Provider type (openai, anthropic, google, ...)").requiredOption("-n, --name <name>", "Display name for this provider").requiredOption("-k, --api-key <key>", "API key for the provider").option("-s, --scope <scope>", "Scope: workspace (default), org, user", "workspace").option("--base-url <url>", "Custom base URL for the provider API").option("--set-default", "Set as default provider for this scope").addHelpText("after", `
|
|
7423
7333
|
Examples:
|
|
7424
|
-
${
|
|
7425
|
-
${
|
|
7426
|
-
${
|
|
7427
|
-
${
|
|
7334
|
+
${chalk23.dim("$")} mutagent providers add --provider openai --name "My OpenAI" --api-key $OPENAI_API_KEY
|
|
7335
|
+
${chalk23.dim("$")} mutagent providers add --provider anthropic --name "Team Claude" --api-key $KEY --scope org
|
|
7336
|
+
${chalk23.dim("$")} mutagent providers add --provider openai --name "Personal" --api-key $KEY --scope user --set-default
|
|
7337
|
+
${chalk23.dim("$")} mutagent providers add --provider custom --name "Ollama" --api-key none --base-url http://localhost:11434 --json
|
|
7428
7338
|
|
|
7429
7339
|
Scope Resolution:
|
|
7430
7340
|
workspace (default) Uses your configured workspace
|
|
@@ -7470,10 +7380,10 @@ The API key is encrypted server-side and never returned in plain text.
|
|
|
7470
7380
|
console.log(` Scope: ${options.scope ?? "workspace"}`);
|
|
7471
7381
|
console.log(` URL: ${providerLink(created.id)}`);
|
|
7472
7382
|
if (options.setDefault) {
|
|
7473
|
-
console.log(
|
|
7383
|
+
console.log(chalk23.green(" Set as default provider"));
|
|
7474
7384
|
}
|
|
7475
7385
|
console.log("");
|
|
7476
|
-
console.log(
|
|
7386
|
+
console.log(chalk23.dim("API key is encrypted server-side. Use `providers get` to see masked key."));
|
|
7477
7387
|
}
|
|
7478
7388
|
} catch (error) {
|
|
7479
7389
|
handleError(error, isJson);
|
|
@@ -7511,15 +7421,15 @@ function buildProviderCreatedDirective(provider, scope) {
|
|
|
7511
7421
|
|
|
7512
7422
|
// src/commands/providers/update.ts
|
|
7513
7423
|
init_sdk_client();
|
|
7514
|
-
import
|
|
7424
|
+
import chalk24 from "chalk";
|
|
7515
7425
|
init_errors();
|
|
7516
7426
|
function registerUpdateCommand(parent) {
|
|
7517
7427
|
parent.command("update").description("Update an existing provider configuration").argument("<id>", "Provider ID (from: mutagent providers list)").option("-n, --name <name>", "Updated display name").option("-k, --api-key <key>", "Updated API key (will be re-encrypted)").option("--active <bool>", "Activate or deactivate (true|false)").option("--set-default", "Set as default provider for its scope").option("--base-url <url>", 'Updated base URL (use "" to clear)').addHelpText("after", `
|
|
7518
7428
|
Examples:
|
|
7519
|
-
${
|
|
7520
|
-
${
|
|
7521
|
-
${
|
|
7522
|
-
${
|
|
7429
|
+
${chalk24.dim("$")} mutagent providers update <id> --name "New Name"
|
|
7430
|
+
${chalk24.dim("$")} mutagent providers update <id> --api-key $NEW_KEY --json
|
|
7431
|
+
${chalk24.dim("$")} mutagent providers update <id> --active false
|
|
7432
|
+
${chalk24.dim("$")} mutagent providers update <id> --set-default --json
|
|
7523
7433
|
|
|
7524
7434
|
PATCH semantics — only provided fields are updated.
|
|
7525
7435
|
`).action(async (id, options) => {
|
|
@@ -7570,7 +7480,7 @@ PATCH semantics — only provided fields are updated.
|
|
|
7570
7480
|
console.log(` ID: ${String(updated.id ?? id)}`);
|
|
7571
7481
|
console.log(` URL: ${providerLink(updated.id ?? id)}`);
|
|
7572
7482
|
if (options.apiKey) {
|
|
7573
|
-
console.log(
|
|
7483
|
+
console.log(chalk24.dim(" API key re-encrypted server-side."));
|
|
7574
7484
|
}
|
|
7575
7485
|
}
|
|
7576
7486
|
} catch (error) {
|
|
@@ -7609,17 +7519,17 @@ function buildProviderUpdatedDirective(provider, requestId) {
|
|
|
7609
7519
|
|
|
7610
7520
|
// src/commands/providers/delete.ts
|
|
7611
7521
|
init_sdk_client();
|
|
7612
|
-
import
|
|
7522
|
+
import chalk25 from "chalk";
|
|
7613
7523
|
init_errors();
|
|
7614
7524
|
function registerDeleteCommand(parent) {
|
|
7615
7525
|
parent.command("delete").description("Delete a provider configuration").argument("<id>", "Provider ID (from: mutagent providers list)").option("-f, --force", "Skip confirmation prompt").addHelpText("after", `
|
|
7616
7526
|
Examples:
|
|
7617
|
-
${
|
|
7618
|
-
${
|
|
7619
|
-
${
|
|
7527
|
+
${chalk25.dim("$")} mutagent providers delete <id>
|
|
7528
|
+
${chalk25.dim("$")} mutagent providers delete <id> --force
|
|
7529
|
+
${chalk25.dim("$")} mutagent providers delete <id> --force --json
|
|
7620
7530
|
|
|
7621
|
-
${
|
|
7622
|
-
${
|
|
7531
|
+
${chalk25.dim("Note: --force is required. The CLI is non-interactive — confirm with the user via your native flow, then pass --force.")}
|
|
7532
|
+
${chalk25.dim("Warning: API keys are AES-256-GCM encrypted and irrecoverable after deletion. Agents referencing this provider will lose their model config.")}
|
|
7623
7533
|
`).action(async (id, options) => {
|
|
7624
7534
|
const isJson = getJsonFlag(parent);
|
|
7625
7535
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -7709,12 +7619,12 @@ function validateProviderType(type) {
|
|
|
7709
7619
|
function createProvidersCommand() {
|
|
7710
7620
|
const providers = new Command13("providers").description("Manage LLM provider configurations (BYOK)").addHelpText("after", `
|
|
7711
7621
|
Examples:
|
|
7712
|
-
${
|
|
7713
|
-
${
|
|
7714
|
-
${
|
|
7715
|
-
${
|
|
7716
|
-
${
|
|
7717
|
-
${
|
|
7622
|
+
${chalk26.dim("$")} mutagent providers list
|
|
7623
|
+
${chalk26.dim("$")} mutagent providers get <provider-id>
|
|
7624
|
+
${chalk26.dim("$")} mutagent providers add --provider openai --name "My OpenAI" --api-key $KEY
|
|
7625
|
+
${chalk26.dim("$")} mutagent providers update <id> --name "New Name"
|
|
7626
|
+
${chalk26.dim("$")} mutagent providers delete <id> --force
|
|
7627
|
+
${chalk26.dim("$")} mutagent providers test <provider-id>
|
|
7718
7628
|
|
|
7719
7629
|
Provider Types:
|
|
7720
7630
|
openai, anthropic, google, azure, bedrock, cohere, mistral, groq, together, replicate, custom
|
|
@@ -7724,9 +7634,9 @@ Subcommands:
|
|
|
7724
7634
|
`);
|
|
7725
7635
|
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", `
|
|
7726
7636
|
Examples:
|
|
7727
|
-
${
|
|
7728
|
-
${
|
|
7729
|
-
${
|
|
7637
|
+
${chalk26.dim("$")} mutagent providers list
|
|
7638
|
+
${chalk26.dim("$")} mutagent providers list --type openai
|
|
7639
|
+
${chalk26.dim("$")} mutagent providers list --json
|
|
7730
7640
|
`).action(async (options) => {
|
|
7731
7641
|
const isJson = getJsonFlag(providers);
|
|
7732
7642
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -7775,8 +7685,8 @@ Examples:
|
|
|
7775
7685
|
});
|
|
7776
7686
|
providers.command("get").description("Get provider details").argument("<id>", "Provider ID (from: mutagent providers list)").addHelpText("after", `
|
|
7777
7687
|
Examples:
|
|
7778
|
-
${
|
|
7779
|
-
${
|
|
7688
|
+
${chalk26.dim("$")} mutagent providers get <provider-id>
|
|
7689
|
+
${chalk26.dim("$")} mutagent providers get <provider-id> --json
|
|
7780
7690
|
`).action(async (id) => {
|
|
7781
7691
|
const isJson = getJsonFlag(providers);
|
|
7782
7692
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -7805,10 +7715,10 @@ Examples:
|
|
|
7805
7715
|
});
|
|
7806
7716
|
providers.command("test").description("Test provider connectivity").argument("<id>", "Provider ID (from: mutagent providers list)").addHelpText("after", `
|
|
7807
7717
|
Examples:
|
|
7808
|
-
${
|
|
7809
|
-
${
|
|
7718
|
+
${chalk26.dim("$")} mutagent providers test <provider-id>
|
|
7719
|
+
${chalk26.dim("$")} mutagent providers test <provider-id> --json
|
|
7810
7720
|
|
|
7811
|
-
${
|
|
7721
|
+
${chalk26.dim("Tests connectivity and lists available models for the provider.")}
|
|
7812
7722
|
`).action(async (id) => {
|
|
7813
7723
|
const isJson = getJsonFlag(providers);
|
|
7814
7724
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -7823,9 +7733,9 @@ ${chalk25.dim("Tests connectivity and lists available models for the provider.")
|
|
|
7823
7733
|
} else {
|
|
7824
7734
|
if (result.success) {
|
|
7825
7735
|
output.success(`Provider test passed (${String(result.responseTimeMs)}ms)`);
|
|
7826
|
-
console.log(
|
|
7736
|
+
console.log(chalk26.green(`Message: ${result.message}`));
|
|
7827
7737
|
if (result.availableModels && result.availableModels.length > 0) {
|
|
7828
|
-
console.log(
|
|
7738
|
+
console.log(chalk26.bold(`
|
|
7829
7739
|
Available Models:`));
|
|
7830
7740
|
result.availableModels.forEach((model) => {
|
|
7831
7741
|
console.log(` - ${model}`);
|
|
@@ -7834,7 +7744,7 @@ Available Models:`));
|
|
|
7834
7744
|
} else {
|
|
7835
7745
|
output.error(`Provider test failed: ${result.message}`);
|
|
7836
7746
|
if (result.error) {
|
|
7837
|
-
console.log(
|
|
7747
|
+
console.log(chalk26.red(`Error: ${result.error}`));
|
|
7838
7748
|
}
|
|
7839
7749
|
}
|
|
7840
7750
|
}
|
|
@@ -7851,8 +7761,8 @@ Available Models:`));
|
|
|
7851
7761
|
// src/commands/init.ts
|
|
7852
7762
|
init_config();
|
|
7853
7763
|
import { Command as Command14 } from "commander";
|
|
7854
|
-
import
|
|
7855
|
-
import
|
|
7764
|
+
import inquirer2 from "inquirer";
|
|
7765
|
+
import chalk27 from "chalk";
|
|
7856
7766
|
import { existsSync as existsSync11, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
7857
7767
|
import { execSync as execSync3 } from "child_process";
|
|
7858
7768
|
import { join as join6 } from "path";
|
|
@@ -7975,13 +7885,13 @@ function writeRcConfig(config, cwd = process.cwd()) {
|
|
|
7975
7885
|
function createInitCommand() {
|
|
7976
7886
|
const init = new Command14("init").description("Initialize MutagenT in your project").option("--non-interactive", "Skip interactive prompts (defaults to CLI-only mode)").addHelpText("after", `
|
|
7977
7887
|
Examples:
|
|
7978
|
-
${
|
|
7979
|
-
${
|
|
7888
|
+
${chalk27.dim("$")} mutagent init # Interactive setup wizard
|
|
7889
|
+
${chalk27.dim("$")} mutagent init --non-interactive # CLI-only mode (no prompts)
|
|
7980
7890
|
|
|
7981
7891
|
Modes:
|
|
7982
|
-
${
|
|
7983
|
-
${
|
|
7984
|
-
${
|
|
7892
|
+
${chalk27.bold("Full scaffold")} Install SDK + integration package, create config, setup tracing
|
|
7893
|
+
${chalk27.bold("CLI-only")} Verify auth + create .mutagentrc.json with workspace/endpoint
|
|
7894
|
+
${chalk27.bold("Skip")} Exit without changes
|
|
7985
7895
|
`).action(async (options) => {
|
|
7986
7896
|
const isJson = getJsonFlag(init);
|
|
7987
7897
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -7994,7 +7904,7 @@ Modes:
|
|
|
7994
7904
|
output.info("Use --force to overwrite (not yet supported). Exiting.");
|
|
7995
7905
|
return;
|
|
7996
7906
|
}
|
|
7997
|
-
const { overwrite } = await
|
|
7907
|
+
const { overwrite } = await inquirer2.prompt([{
|
|
7998
7908
|
type: "confirm",
|
|
7999
7909
|
name: "overwrite",
|
|
8000
7910
|
message: ".mutagentrc.json already exists. Overwrite?",
|
|
@@ -8012,7 +7922,7 @@ Modes:
|
|
|
8012
7922
|
if (isNonInteractive) {
|
|
8013
7923
|
throw new MutagentError("AUTH_REQUIRED", "Authentication required before init", "Run: mutagent auth login --browser");
|
|
8014
7924
|
}
|
|
8015
|
-
const { doAuth } = await
|
|
7925
|
+
const { doAuth } = await inquirer2.prompt([{
|
|
8016
7926
|
type: "confirm",
|
|
8017
7927
|
name: "doAuth",
|
|
8018
7928
|
message: "Would you like to authenticate now?",
|
|
@@ -8038,7 +7948,7 @@ Modes:
|
|
|
8038
7948
|
} else {
|
|
8039
7949
|
if (detectedFramework) {
|
|
8040
7950
|
output.info(`Detected framework: ${detectedFramework.displayName} (${detectedFramework.npmPackage})`);
|
|
8041
|
-
const { confirmFramework } = await
|
|
7951
|
+
const { confirmFramework } = await inquirer2.prompt([{
|
|
8042
7952
|
type: "confirm",
|
|
8043
7953
|
name: "confirmFramework",
|
|
8044
7954
|
message: `Use ${detectedFramework.displayName}?`,
|
|
@@ -8054,7 +7964,7 @@ Modes:
|
|
|
8054
7964
|
{ name: "Generic (OpenAI-compatible)", value: "generic" },
|
|
8055
7965
|
{ name: "None / Skip framework", value: "none" }
|
|
8056
7966
|
];
|
|
8057
|
-
const { selectedFramework } = await
|
|
7967
|
+
const { selectedFramework } = await inquirer2.prompt([{
|
|
8058
7968
|
type: "list",
|
|
8059
7969
|
name: "selectedFramework",
|
|
8060
7970
|
message: "Select your AI framework:",
|
|
@@ -8084,7 +7994,7 @@ Modes:
|
|
|
8084
7994
|
value: "skip"
|
|
8085
7995
|
}
|
|
8086
7996
|
];
|
|
8087
|
-
const { selectedMode } = await
|
|
7997
|
+
const { selectedMode } = await inquirer2.prompt([{
|
|
8088
7998
|
type: "list",
|
|
8089
7999
|
name: "selectedMode",
|
|
8090
8000
|
message: "How would you like to initialize MutagenT?",
|
|
@@ -8187,7 +8097,7 @@ Modes:
|
|
|
8187
8097
|
const skillPath = join6(cwd, ".claude/skills/mutagent-cli/SKILL.md");
|
|
8188
8098
|
const skillInstalled = existsSync11(skillPath);
|
|
8189
8099
|
if (!isNonInteractive && !skillInstalled) {
|
|
8190
|
-
const { installSkill } = await
|
|
8100
|
+
const { installSkill } = await inquirer2.prompt([{
|
|
8191
8101
|
type: "confirm",
|
|
8192
8102
|
name: "installSkill",
|
|
8193
8103
|
message: "Install MutagenT skill for Claude Code? (Teaches AI agents how to use the CLI)",
|
|
@@ -8253,23 +8163,23 @@ Modes:
|
|
|
8253
8163
|
|
|
8254
8164
|
// src/commands/explore.ts
|
|
8255
8165
|
import { Command as Command15 } from "commander";
|
|
8256
|
-
import
|
|
8166
|
+
import chalk28 from "chalk";
|
|
8257
8167
|
import { resolve as resolve3 } from "path";
|
|
8258
8168
|
init_errors();
|
|
8259
8169
|
function createExploreCommand() {
|
|
8260
8170
|
const explore = new Command15("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", `
|
|
8261
8171
|
Examples:
|
|
8262
|
-
${
|
|
8263
|
-
${
|
|
8264
|
-
${
|
|
8265
|
-
${
|
|
8266
|
-
${
|
|
8172
|
+
${chalk28.dim("$")} mutagent explore
|
|
8173
|
+
${chalk28.dim("$")} mutagent explore --path ./src
|
|
8174
|
+
${chalk28.dim("$")} mutagent explore --include "**/*.{ts,py}" --depth 5
|
|
8175
|
+
${chalk28.dim("$")} mutagent explore --markers-only
|
|
8176
|
+
${chalk28.dim("$")} mutagent explore --json
|
|
8267
8177
|
|
|
8268
8178
|
Detection modes:
|
|
8269
|
-
${
|
|
8270
|
-
${
|
|
8179
|
+
${chalk28.dim("Heuristic")} Template variables ({{var}}), prompt constants, schema definitions
|
|
8180
|
+
${chalk28.dim("Marker")} MutagenT:START/END comment markers from previous uploads
|
|
8271
8181
|
|
|
8272
|
-
${
|
|
8182
|
+
${chalk28.dim("Results are saved to .mutagent/mutation-context.md for use by other commands.")}
|
|
8273
8183
|
`).action((options) => {
|
|
8274
8184
|
const isJson = getJsonFlag(explore);
|
|
8275
8185
|
const output = new OutputFormatter(isJson ? "json" : "table");
|
|
@@ -8287,7 +8197,7 @@ ${chalk27.dim("Results are saved to .mutagent/mutation-context.md for use by oth
|
|
|
8287
8197
|
markersOnly
|
|
8288
8198
|
};
|
|
8289
8199
|
if (!isJson) {
|
|
8290
|
-
console.log(
|
|
8200
|
+
console.log(chalk28.cyan(`
|
|
8291
8201
|
Scanning ${scanPath}...
|
|
8292
8202
|
`));
|
|
8293
8203
|
}
|
|
@@ -8316,41 +8226,41 @@ Scanning ${scanPath}...
|
|
|
8316
8226
|
const totalFindings = result.prompts.length + result.datasets.length + result.markers.length;
|
|
8317
8227
|
if (totalFindings === 0) {
|
|
8318
8228
|
output.info("No prompts, datasets, or markers found.");
|
|
8319
|
-
console.log(
|
|
8229
|
+
console.log(chalk28.dim(`
|
|
8320
8230
|
Tip: Create a prompt with template variables like {{input}} to get started.`));
|
|
8321
8231
|
return;
|
|
8322
8232
|
}
|
|
8323
8233
|
if (result.prompts.length > 0) {
|
|
8324
|
-
console.log(
|
|
8234
|
+
console.log(chalk28.bold(` Prompts Found (${String(result.prompts.length)}):`));
|
|
8325
8235
|
console.log();
|
|
8326
8236
|
for (const p of result.prompts) {
|
|
8327
|
-
const confidenceTag = p.confidence === "high" ?
|
|
8328
|
-
const reasonTag =
|
|
8329
|
-
console.log(` ${confidenceTag} ${
|
|
8330
|
-
console.log(` ${
|
|
8237
|
+
const confidenceTag = p.confidence === "high" ? chalk28.green("[high]") : p.confidence === "medium" ? chalk28.yellow("[medium]") : chalk28.dim("[low]");
|
|
8238
|
+
const reasonTag = chalk28.dim(`[${p.reason}]`);
|
|
8239
|
+
console.log(` ${confidenceTag} ${chalk28.green(p.file)}:${chalk28.yellow(String(p.line))} ${reasonTag}`);
|
|
8240
|
+
console.log(` ${chalk28.dim(p.preview)}`);
|
|
8331
8241
|
}
|
|
8332
8242
|
console.log();
|
|
8333
8243
|
}
|
|
8334
8244
|
if (result.datasets.length > 0) {
|
|
8335
|
-
console.log(
|
|
8245
|
+
console.log(chalk28.bold(` Datasets Found (${String(result.datasets.length)}):`));
|
|
8336
8246
|
console.log();
|
|
8337
8247
|
for (const d of result.datasets) {
|
|
8338
|
-
console.log(` ${
|
|
8248
|
+
console.log(` ${chalk28.green(d.file)} ${chalk28.dim(`(${String(d.items)} items)`)}`);
|
|
8339
8249
|
}
|
|
8340
8250
|
console.log();
|
|
8341
8251
|
}
|
|
8342
8252
|
if (result.markers.length > 0) {
|
|
8343
|
-
console.log(
|
|
8253
|
+
console.log(chalk28.bold(` MutagenT Markers (${String(result.markers.length)}):`));
|
|
8344
8254
|
console.log();
|
|
8345
8255
|
for (const m of result.markers) {
|
|
8346
|
-
const idPart = m.platformId ?
|
|
8347
|
-
console.log(` ${
|
|
8256
|
+
const idPart = m.platformId ? chalk28.cyan(` id=${m.platformId}`) : "";
|
|
8257
|
+
console.log(` ${chalk28.green(m.file)}:${chalk28.yellow(String(m.line))} ${chalk28.magenta(m.type)}${idPart}`);
|
|
8348
8258
|
}
|
|
8349
8259
|
console.log();
|
|
8350
8260
|
}
|
|
8351
|
-
console.log(
|
|
8352
|
-
console.log(` ${
|
|
8353
|
-
console.log(
|
|
8261
|
+
console.log(chalk28.dim(" ─────────────────────────────────"));
|
|
8262
|
+
console.log(` ${chalk28.bold("Summary:")} ${String(result.prompts.length)} prompts, ${String(result.datasets.length)} datasets, ${String(result.markers.length)} markers`);
|
|
8263
|
+
console.log(chalk28.dim(` Saved to .mutagent/mutation-context.md`));
|
|
8354
8264
|
console.log();
|
|
8355
8265
|
}
|
|
8356
8266
|
} catch (error) {
|
|
@@ -8362,7 +8272,7 @@ Scanning ${scanPath}...
|
|
|
8362
8272
|
|
|
8363
8273
|
// src/commands/skills.ts
|
|
8364
8274
|
import { Command as Command16 } from "commander";
|
|
8365
|
-
import
|
|
8275
|
+
import chalk29 from "chalk";
|
|
8366
8276
|
import { existsSync as existsSync12, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
8367
8277
|
import { join as join7 } from "path";
|
|
8368
8278
|
import { execSync as execSync4 } from "child_process";
|
|
@@ -8486,7 +8396,7 @@ function createSkillsCommand() {
|
|
|
8486
8396
|
const skills = new Command16("skills").description("Manage MutagenT CLI skills for coding agents");
|
|
8487
8397
|
skills.command("install").description("Install MutagenT CLI skill for Claude Code").addHelpText("after", `
|
|
8488
8398
|
Examples:
|
|
8489
|
-
${
|
|
8399
|
+
${chalk29.dim("$")} mutagent skills install
|
|
8490
8400
|
|
|
8491
8401
|
This creates a Claude Code skill at .claude/skills/mutagent-cli/SKILL.md
|
|
8492
8402
|
that teaches coding agents how to use the MutagenT CLI effectively.
|
|
@@ -8513,10 +8423,10 @@ ${SKILL_BODY}
|
|
|
8513
8423
|
});
|
|
8514
8424
|
} else {
|
|
8515
8425
|
output.success(`Installed MutagenT CLI skill`);
|
|
8516
|
-
console.log(` ${
|
|
8426
|
+
console.log(` ${chalk29.dim("Path:")} ${skillPath}`);
|
|
8517
8427
|
console.log("");
|
|
8518
|
-
console.log(` ${
|
|
8519
|
-
console.log(` ${
|
|
8428
|
+
console.log(` ${chalk29.dim("This skill teaches coding agents how to use the MutagenT CLI.")}`);
|
|
8429
|
+
console.log(` ${chalk29.dim("It will be automatically loaded by Claude Code when relevant triggers match.")}`);
|
|
8520
8430
|
}
|
|
8521
8431
|
});
|
|
8522
8432
|
return skills;
|
|
@@ -8525,7 +8435,7 @@ ${SKILL_BODY}
|
|
|
8525
8435
|
// src/commands/usage.ts
|
|
8526
8436
|
init_config();
|
|
8527
8437
|
import { Command as Command17 } from "commander";
|
|
8528
|
-
import
|
|
8438
|
+
import chalk30 from "chalk";
|
|
8529
8439
|
init_errors();
|
|
8530
8440
|
init_sdk_client();
|
|
8531
8441
|
var TRIAL_OPTIMIZATION_LIMIT = 5;
|
|
@@ -8541,8 +8451,8 @@ function renderProgressBar(used, limit, width = 30) {
|
|
|
8541
8451
|
function createUsageCommand() {
|
|
8542
8452
|
const usage = new Command17("usage").description("Show resource counts and optimization run limits").addHelpText("after", `
|
|
8543
8453
|
Examples:
|
|
8544
|
-
${
|
|
8545
|
-
${
|
|
8454
|
+
${chalk30.dim("$")} mutagent usage
|
|
8455
|
+
${chalk30.dim("$")} mutagent usage --json
|
|
8546
8456
|
`);
|
|
8547
8457
|
usage.action(async () => {
|
|
8548
8458
|
const isJson = getJsonFlag(usage);
|
|
@@ -8597,21 +8507,21 @@ Examples:
|
|
|
8597
8507
|
});
|
|
8598
8508
|
} else {
|
|
8599
8509
|
console.log("");
|
|
8600
|
-
console.log(
|
|
8601
|
-
console.log(
|
|
8510
|
+
console.log(chalk30.bold("\uD83D\uDCCA MutagenT Usage"));
|
|
8511
|
+
console.log(chalk30.dim("─".repeat(45)));
|
|
8602
8512
|
console.log("");
|
|
8603
|
-
console.log(
|
|
8604
|
-
console.log(` Prompts: ${
|
|
8605
|
-
console.log(` Datasets: ${
|
|
8606
|
-
console.log(` Evaluations: ${
|
|
8513
|
+
console.log(chalk30.bold("Resources:"));
|
|
8514
|
+
console.log(` Prompts: ${chalk30.cyan(String(promptCount))}`);
|
|
8515
|
+
console.log(` Datasets: ${chalk30.cyan(String(datasetCount))}`);
|
|
8516
|
+
console.log(` Evaluations: ${chalk30.cyan(String(evaluationCount))}`);
|
|
8607
8517
|
console.log("");
|
|
8608
|
-
console.log(
|
|
8609
|
-
console.log(` Remaining: ${
|
|
8518
|
+
console.log(chalk30.bold(`Optimization Runs (${chalk30.yellow("trial")} plan):`));
|
|
8519
|
+
console.log(` Remaining: ${chalk30.cyan(String(optimizationRemaining))} / ${String(optimizationLimit)}`);
|
|
8610
8520
|
console.log(` ${renderProgressBar(optimizationUsed, optimizationLimit)}`);
|
|
8611
8521
|
console.log("");
|
|
8612
|
-
console.log(
|
|
8613
|
-
console.log(
|
|
8614
|
-
console.log(` Upgrade: ${
|
|
8522
|
+
console.log(chalk30.yellow(` ⚠ ${String(optimizationRemaining)} optimization runs remaining`));
|
|
8523
|
+
console.log(chalk30.dim(` ℹ Optimization run counts are approximate`));
|
|
8524
|
+
console.log(` Upgrade: ${chalk30.underline(BILLING_URL)}`);
|
|
8615
8525
|
console.log("");
|
|
8616
8526
|
}
|
|
8617
8527
|
} catch (error) {
|
|
@@ -8899,7 +8809,7 @@ Claude Code Session Telemetry:
|
|
|
8899
8809
|
|
|
8900
8810
|
// src/commands/feedback.ts
|
|
8901
8811
|
import { Command as Command19 } from "commander";
|
|
8902
|
-
import
|
|
8812
|
+
import chalk31 from "chalk";
|
|
8903
8813
|
init_errors();
|
|
8904
8814
|
init_config();
|
|
8905
8815
|
import { readFileSync as readFileSync11 } from "fs";
|
|
@@ -8953,12 +8863,12 @@ async function postToServer(payload, endpoint, apiKey, workspaceId, organization
|
|
|
8953
8863
|
}
|
|
8954
8864
|
function createFeedbackCommand() {
|
|
8955
8865
|
const feedback = new Command19("feedback").description("Send product feedback to MutagenT").addHelpText("after", `
|
|
8956
|
-
${
|
|
8957
|
-
${
|
|
8958
|
-
${
|
|
8959
|
-
${
|
|
8866
|
+
${chalk31.bold("Examples:")}
|
|
8867
|
+
${chalk31.cyan('mutagent feedback send -m "Great optimization results!"')}
|
|
8868
|
+
${chalk31.cyan('mutagent feedback send -m "CLI crashed on export" --category bug')}
|
|
8869
|
+
${chalk31.cyan('mutagent feedback send -m "Need batch operations" --category feature --json')}
|
|
8960
8870
|
|
|
8961
|
-
${
|
|
8871
|
+
${chalk31.yellow("AI Agent (MANDATORY):")}
|
|
8962
8872
|
ALWAYS use --json: mutagent feedback send -m "..." --category improvement --json
|
|
8963
8873
|
Use this command to report bugs, request features, or share UX feedback.
|
|
8964
8874
|
`).action(() => {
|
|
@@ -8969,18 +8879,18 @@ ${chalk30.yellow("AI Agent (MANDATORY):")}
|
|
|
8969
8879
|
}
|
|
8970
8880
|
function registerFeedbackSend(feedback) {
|
|
8971
8881
|
feedback.command("send").description("Send feedback about the MutagenT platform").requiredOption("-m, --message <text>", "Feedback message").option("--category <type>", `Feedback category: ${VALID_CATEGORIES.join(", ")}`, "improvement").option("--session <id>", "Link feedback to a specific session").addHelpText("after", `
|
|
8972
|
-
${
|
|
8973
|
-
${
|
|
8974
|
-
${
|
|
8975
|
-
${
|
|
8976
|
-
|
|
8977
|
-
${
|
|
8978
|
-
${
|
|
8979
|
-
${
|
|
8980
|
-
${
|
|
8981
|
-
${
|
|
8982
|
-
|
|
8983
|
-
${
|
|
8882
|
+
${chalk31.bold("Examples:")}
|
|
8883
|
+
${chalk31.dim("$")} mutagent feedback send -m "The optimization UX could show progress better"
|
|
8884
|
+
${chalk31.dim("$")} mutagent feedback send -m "CLI errored on traces export" --category bug
|
|
8885
|
+
${chalk31.dim("$")} mutagent feedback send -m "Love the guided eval!" --category praise --json
|
|
8886
|
+
|
|
8887
|
+
${chalk31.bold("Categories:")}
|
|
8888
|
+
${chalk31.bold("bug")} Something is broken or not working as expected
|
|
8889
|
+
${chalk31.bold("feature")} Request a new capability
|
|
8890
|
+
${chalk31.bold("improvement")} Suggest a UX or workflow enhancement (default)
|
|
8891
|
+
${chalk31.bold("praise")} Share what you love about the platform
|
|
8892
|
+
|
|
8893
|
+
${chalk31.yellow("AI Agent (MANDATORY):")}
|
|
8984
8894
|
ALWAYS use --json: mutagent feedback send -m "..." --json
|
|
8985
8895
|
Auto-captured context (CLI version, platform, node version) is included automatically.
|
|
8986
8896
|
`).action(async (options) => {
|
|
@@ -9052,103 +8962,109 @@ program.name("mutagent").description(`MutagenT CLI - AI-native prompt optimizati
|
|
|
9052
8962
|
showGlobalOptions: true
|
|
9053
8963
|
});
|
|
9054
8964
|
program.addHelpText("after", `
|
|
9055
|
-
${
|
|
9056
|
-
export MUTAGENT_API_KEY=mt_... ${
|
|
9057
|
-
--json ${
|
|
9058
|
-
|
|
9059
|
-
${
|
|
9060
|
-
mutagent
|
|
9061
|
-
mutagent auth status ${
|
|
9062
|
-
mutagent init ${
|
|
9063
|
-
mutagent explore ${
|
|
9064
|
-
mutagent workspaces list --json ${
|
|
9065
|
-
mutagent config set workspace <id> ${
|
|
9066
|
-
mutagent usage --json ${
|
|
9067
|
-
|
|
9068
|
-
mutagent prompts create --help ${
|
|
9069
|
-
mutagent prompts list --json ${
|
|
9070
|
-
mutagent prompts get <id> --json ${
|
|
9071
|
-
|
|
9072
|
-
mutagent prompts dataset add --help ${
|
|
9073
|
-
mutagent prompts dataset list <id> ${
|
|
9074
|
-
|
|
9075
|
-
mutagent prompts evaluation create --help ${
|
|
9076
|
-
mutagent prompts evaluation create <id> --guided --json ${
|
|
9077
|
-
mutagent prompts evaluation list <id> --json ${
|
|
9078
|
-
|
|
9079
|
-
mutagent prompts optimize start --help ${
|
|
9080
|
-
mutagent prompts optimize status <job-id> ${
|
|
9081
|
-
mutagent prompts optimize results <job-id> ${
|
|
9082
|
-
|
|
9083
|
-
mutagent feedback send -m "..." ${
|
|
9084
|
-
mutagent feedback send -m "..." --category bug ${
|
|
9085
|
-
|
|
9086
|
-
mutagent integrate <framework> ${
|
|
9087
|
-
mutagent hooks --help ${
|
|
9088
|
-
mutagent playground run <id> --input '{...}' ${
|
|
9089
|
-
|
|
9090
|
-
${
|
|
9091
|
-
1. mutagent explore ${
|
|
9092
|
-
2. mutagent integrate <framework> ${
|
|
9093
|
-
3. Apply tracing code to your codebase ${
|
|
9094
|
-
4. mutagent traces list --json ${
|
|
9095
|
-
|
|
9096
|
-
${
|
|
9097
|
-
1. mutagent prompts create --help ${
|
|
9098
|
-
2. mutagent prompts create ... --json ${
|
|
9099
|
-
3. mutagent prompts dataset add --help ${
|
|
9100
|
-
4. mutagent prompts dataset add <id> ... --json ${
|
|
9101
|
-
5. mutagent prompts evaluation create <id> --guided --json ${
|
|
8965
|
+
${chalk32.yellow("Non-Interactive Mode (CI/CD & Coding Agents):")}
|
|
8966
|
+
export MUTAGENT_API_KEY=mt_... ${chalk32.dim("or")} --api-key mt_...
|
|
8967
|
+
--json ${chalk32.dim("for structured output")} --non-interactive ${chalk32.dim("to disable prompts")}
|
|
8968
|
+
|
|
8969
|
+
${chalk32.yellow("Command Navigation:")}
|
|
8970
|
+
mutagent login ${chalk32.dim("Login (browser OAuth — recommended)")}
|
|
8971
|
+
mutagent auth status ${chalk32.dim("Check auth + workspace")}
|
|
8972
|
+
mutagent init ${chalk32.dim("Initialize project (.mutagentrc.json)")}
|
|
8973
|
+
mutagent explore ${chalk32.dim("Discover prompts in codebase")}
|
|
8974
|
+
mutagent workspaces list --json ${chalk32.dim("List workspaces (verify ID)")}
|
|
8975
|
+
mutagent config set workspace <id> ${chalk32.dim("Set active workspace")}
|
|
8976
|
+
mutagent usage --json ${chalk32.dim("Check plan limits")}
|
|
8977
|
+
|
|
8978
|
+
mutagent prompts create --help ${chalk32.dim("Upload prompt (read help first!)")}
|
|
8979
|
+
mutagent prompts list --json ${chalk32.dim("List prompts")}
|
|
8980
|
+
mutagent prompts get <id> --json ${chalk32.dim("Full prompt details + schemas")}
|
|
8981
|
+
|
|
8982
|
+
mutagent prompts dataset add --help ${chalk32.dim("Upload dataset (read help first!)")}
|
|
8983
|
+
mutagent prompts dataset list <id> ${chalk32.dim("List datasets")}
|
|
8984
|
+
|
|
8985
|
+
mutagent prompts evaluation create --help ${chalk32.dim("Create eval (read help first!)")}
|
|
8986
|
+
mutagent prompts evaluation create <id> --guided --json ${chalk32.dim("Guided eval workflow")}
|
|
8987
|
+
mutagent prompts evaluation list <id> --json ${chalk32.dim("List evaluations")}
|
|
8988
|
+
|
|
8989
|
+
mutagent prompts optimize start --help ${chalk32.dim("Run optimization (read help first!)")}
|
|
8990
|
+
mutagent prompts optimize status <job-id> ${chalk32.dim("Poll progress")}
|
|
8991
|
+
mutagent prompts optimize results <job-id> ${chalk32.dim("View scorecard")}
|
|
8992
|
+
|
|
8993
|
+
mutagent feedback send -m "..." ${chalk32.dim("Send product feedback")}
|
|
8994
|
+
mutagent feedback send -m "..." --category bug ${chalk32.dim("Report a bug")}
|
|
8995
|
+
|
|
8996
|
+
mutagent integrate <framework> ${chalk32.dim("Framework integration guide")}
|
|
8997
|
+
mutagent hooks --help ${chalk32.dim("Hook setup for Claude Code telemetry")}
|
|
8998
|
+
mutagent playground run <id> --input '{...}' ${chalk32.dim("Quick test")}
|
|
8999
|
+
|
|
9000
|
+
${chalk32.yellow("★ Workflow: Framework Integration (Tracing):")}
|
|
9001
|
+
1. mutagent explore ${chalk32.dim("← discover prompts/agents in codebase")}
|
|
9002
|
+
2. mutagent integrate <framework> ${chalk32.dim("← get integration instructions")}
|
|
9003
|
+
3. Apply tracing code to your codebase ${chalk32.dim("← follow the guide output")}
|
|
9004
|
+
4. mutagent traces list --json ${chalk32.dim("← verify traces are arriving")}
|
|
9005
|
+
|
|
9006
|
+
${chalk32.yellow("★ Workflow: Evaluate → Optimize:")}
|
|
9007
|
+
1. mutagent prompts create --help ${chalk32.dim("← read help")}
|
|
9008
|
+
2. mutagent prompts create ... --json ${chalk32.dim("← upload prompt with {variables} + inputSchema")}
|
|
9009
|
+
3. mutagent prompts dataset add --help ${chalk32.dim("← read help")}
|
|
9010
|
+
4. mutagent prompts dataset add <id> ... --json ${chalk32.dim("← upload dataset")}
|
|
9011
|
+
5. mutagent prompts evaluation create <id> --guided --json ${chalk32.dim("← guided eval")}
|
|
9102
9012
|
6. mutagent prompts optimize start <id> --dataset <d> --evaluation <e> --json
|
|
9103
9013
|
|
|
9104
|
-
${
|
|
9105
|
-
After ${
|
|
9106
|
-
${
|
|
9107
|
-
${
|
|
9108
|
-
${
|
|
9014
|
+
${chalk32.yellow("Post-Onboarding Decision Tree:")}
|
|
9015
|
+
After ${chalk32.bold("mutagent auth login")}, users land in one of 3 paths:
|
|
9016
|
+
${chalk32.bold("Path A")} (Tracing): explore → integrate <framework> → apply tracing → verify
|
|
9017
|
+
${chalk32.bold("Path B")} (Optimization): explore → prompts create → dataset add → eval create → optimize
|
|
9018
|
+
${chalk32.bold("Path C")} (Manual): Use CLI commands directly — run mutagent <command> --help
|
|
9109
9019
|
|
|
9110
|
-
${
|
|
9020
|
+
${chalk32.yellow("Directive System:")}
|
|
9111
9021
|
Every --json response may include:
|
|
9112
|
-
${
|
|
9113
|
-
${
|
|
9114
|
-
${
|
|
9115
|
-
${
|
|
9022
|
+
${chalk32.bold("_directive.renderedCard")} Pre-formatted card for the user ${chalk32.red("(MUST be shown in chat)")}
|
|
9023
|
+
${chalk32.bold("_directive.instruction")} Next step for the agent
|
|
9024
|
+
${chalk32.bold("_directive.next")} Array of suggested follow-up commands
|
|
9025
|
+
${chalk32.bold("_links")} Dashboard/API URLs (format as markdown links)
|
|
9116
9026
|
|
|
9117
|
-
${
|
|
9118
|
-
Each criterion MUST have: ${
|
|
9027
|
+
${chalk32.yellow("Evaluation Criteria Format:")}
|
|
9028
|
+
Each criterion MUST have: ${chalk32.bold("name")}, ${chalk32.bold("description")} (scoring rubric), ${chalk32.bold("evaluationParameter")}
|
|
9119
9029
|
evaluationParameter MUST match an inputSchema or outputSchema field name
|
|
9120
9030
|
No duplicate evaluationParameter values — each criterion targets a unique field
|
|
9121
9031
|
ALL schema fields must be covered (missing fields = error)
|
|
9122
|
-
Use ${
|
|
9032
|
+
Use ${chalk32.bold("--guided --json")} to generate criteria templates from prompt schemas
|
|
9123
9033
|
|
|
9124
|
-
${
|
|
9125
|
-
Default max-iterations is 1. ${
|
|
9034
|
+
${chalk32.yellow("Optimization Cost Control:")}
|
|
9035
|
+
Default max-iterations is 1. ${chalk32.red("NEVER increase without explicit user request.")}
|
|
9126
9036
|
Each iteration incurs LLM costs — confirm with user before starting >1.
|
|
9127
9037
|
|
|
9128
|
-
${
|
|
9129
|
-
After ${
|
|
9130
|
-
Then offer choices: ${
|
|
9038
|
+
${chalk32.yellow("Post-Optimization:")}
|
|
9039
|
+
After ${chalk32.bold("optimize results")}: ALWAYS show the before/after diff to the user first.
|
|
9040
|
+
Then offer choices: ${chalk32.bold("Apply")} / ${chalk32.bold("Reject")}.
|
|
9131
9041
|
|
|
9132
|
-
${
|
|
9042
|
+
${chalk32.yellow("State Tracking:")}
|
|
9133
9043
|
.mutagent/mutation-context.md — Codebase index of discovered/uploaded prompts
|
|
9134
9044
|
Update after explore, create, and dataset operations
|
|
9135
9045
|
mutagent auth status — Auth + workspace state
|
|
9136
9046
|
Comment markers (// MutagenT:START ... // MutagenT:END) in source files
|
|
9137
9047
|
|
|
9138
|
-
${
|
|
9139
|
-
1.
|
|
9140
|
-
|
|
9141
|
-
|
|
9142
|
-
|
|
9143
|
-
|
|
9144
|
-
|
|
9145
|
-
|
|
9146
|
-
|
|
9147
|
-
|
|
9048
|
+
${chalk32.yellow("AI Agent Rules (MANDATORY for coding agents):")}
|
|
9049
|
+
1. Login (two paths):
|
|
9050
|
+
- CI / fully automated: export MUTAGENT_API_KEY=mt_... then mutagent login --json
|
|
9051
|
+
- Helping a user onboard: mutagent login --browser --json
|
|
9052
|
+
(CLI prints an auth URL — surface it to the user verbatim, then the CLI
|
|
9053
|
+
polls for up to 5 minutes while the user authorizes in their browser.
|
|
9054
|
+
This IS agent-compatible. --non-interactive is NOT needed with --browser.)
|
|
9055
|
+
2. EVERY command MUST include --json (no exceptions)
|
|
9056
|
+
3. Run <command> --help BEFORE first use of any command
|
|
9057
|
+
4. Use --guided --json for evaluation creation (NEVER --guided alone)
|
|
9058
|
+
5. Parse _directive.renderedCard and copy it into your CHAT RESPONSE verbatim
|
|
9059
|
+
${chalk32.red("HARD STOP")}: do NOT run further commands until the card is rendered in chat
|
|
9060
|
+
6. After mutagent init, verify workspace: mutagent workspaces list --json
|
|
9061
|
+
7. Use {single_braces} for template variables in prompts
|
|
9062
|
+
8. Collect evaluation criteria from the user — NEVER auto-generate
|
|
9063
|
+
9. ALL user interaction via AskUserQuestion — CLI is non-interactive
|
|
9148
9064
|
${!hasCredentials() ? `
|
|
9149
|
-
` +
|
|
9065
|
+
` + chalk32.yellow(" Warning: Not authenticated. Run: mutagent login") + `
|
|
9150
9066
|
` : ""}${!hasRcConfig() ? `
|
|
9151
|
-
` +
|
|
9067
|
+
` + chalk32.green(" Get started: mutagent init") + `
|
|
9152
9068
|
` : ""}`);
|
|
9153
9069
|
var rawArgs = process.argv.slice(2);
|
|
9154
9070
|
if (rawArgs.includes("-v") || rawArgs.includes("--version")) {
|
|
@@ -9189,5 +9105,5 @@ program.addCommand(createHooksCommand());
|
|
|
9189
9105
|
program.addCommand(createFeedbackCommand());
|
|
9190
9106
|
program.parse();
|
|
9191
9107
|
|
|
9192
|
-
//# debugId=
|
|
9108
|
+
//# debugId=A8E80F0BEF0DA5B364756E2164756E21
|
|
9193
9109
|
//# sourceMappingURL=cli.js.map
|