@stackmemoryai/stackmemory 1.6.0 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/cli/commands/orchestrate.js +334 -4
- package/dist/src/cli/commands/orchestrator.js +283 -24
- package/package.json +1 -2
- package/scripts/gepa/.before-optimize.md +0 -112
- package/scripts/gepa/README.md +0 -275
- package/scripts/gepa/config.json +0 -59
- package/scripts/gepa/evals/coding-tasks.jsonl +0 -5
- package/scripts/gepa/evals/fixtures/api-endpoint.ts +0 -31
- package/scripts/gepa/evals/fixtures/brittle-integration.ts +0 -38
- package/scripts/gepa/evals/fixtures/buggy-loop.js +0 -18
- package/scripts/gepa/evals/fixtures/callback-hell.js +0 -53
- package/scripts/gepa/evals/fixtures/fts5-triggers.sql +0 -23
- package/scripts/gepa/evals/fixtures/leaky-service.ts +0 -70
- package/scripts/gepa/evals/fixtures/mcp-dispatch-stub.ts +0 -39
- package/scripts/gepa/evals/fixtures/pr-diff.txt +0 -24
- package/scripts/gepa/evals/fixtures/unsafe-webhook.ts +0 -34
- package/scripts/gepa/evals/fixtures/unwrapped-db-op.ts +0 -42
- package/scripts/gepa/evals/stackmemory-tasks.jsonl +0 -8
- package/scripts/gepa/generations/gen-000/baseline.md +0 -112
- package/scripts/gepa/generations/gen-001/baseline.md +0 -112
- package/scripts/gepa/generations/gen-001/variant-a.md +0 -107
- package/scripts/gepa/generations/gen-001/variant-b.md +0 -216
- package/scripts/gepa/generations/gen-001/variant-c.md +0 -83
- package/scripts/gepa/generations/gen-001/variant-d.md +0 -90
- package/scripts/gepa/hooks/auto-optimize.js +0 -494
- package/scripts/gepa/hooks/eval-tracker.js +0 -203
- package/scripts/gepa/hooks/reflect.js +0 -350
- package/scripts/gepa/optimize.js +0 -853
- package/scripts/gepa/results/eval-1-baseline.json +0 -218
- package/scripts/gepa/results/eval-1-variant-a.json +0 -218
- package/scripts/gepa/results/eval-1-variant-b.json +0 -218
- package/scripts/gepa/results/eval-1-variant-c.json +0 -218
- package/scripts/gepa/results/eval-1-variant-d.json +0 -218
- package/scripts/gepa/state.json +0 -49
|
@@ -275,6 +275,94 @@ function ensureDefaultPromptTemplate() {
|
|
|
275
275
|
}
|
|
276
276
|
return templatePath;
|
|
277
277
|
}
|
|
278
|
+
function predictDifficulty(labels, description, priority, outcomes) {
|
|
279
|
+
let difficulty = "medium";
|
|
280
|
+
let confidence = 0.5;
|
|
281
|
+
const reasons = [];
|
|
282
|
+
const lowerLabels = labels.map((l) => l.toLowerCase());
|
|
283
|
+
if (outcomes.length > 0 && labels.length > 0) {
|
|
284
|
+
const matching = outcomes.filter(
|
|
285
|
+
(o) => o.labels && o.labels.some((ol) => lowerLabels.includes(ol.toLowerCase()))
|
|
286
|
+
);
|
|
287
|
+
if (matching.length >= 3) {
|
|
288
|
+
const failRate = matching.filter((o) => o.outcome === "failure").length / matching.length;
|
|
289
|
+
if (failRate > 0.6) {
|
|
290
|
+
difficulty = "hard";
|
|
291
|
+
confidence = Math.min(confidence + 0.1, 0.9);
|
|
292
|
+
reasons.push(
|
|
293
|
+
`Historical failure rate ${Math.round(failRate * 100)}% for similar labels`
|
|
294
|
+
);
|
|
295
|
+
} else if (failRate < 0.2) {
|
|
296
|
+
difficulty = "easy";
|
|
297
|
+
confidence = Math.min(confidence + 0.1, 0.9);
|
|
298
|
+
reasons.push(
|
|
299
|
+
`Historical failure rate ${Math.round(failRate * 100)}% for similar labels`
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
const hasBugOrFix = lowerLabels.some(
|
|
305
|
+
(l) => l === "bug" || l === "fix" || l.includes("bugfix")
|
|
306
|
+
);
|
|
307
|
+
if (description.length < 100 && hasBugOrFix) {
|
|
308
|
+
if (difficulty !== "easy") difficulty = "easy";
|
|
309
|
+
confidence = Math.min(confidence + 0.1, 0.9);
|
|
310
|
+
reasons.push("Short description with bug/fix label suggests simple fix");
|
|
311
|
+
}
|
|
312
|
+
const hasComplexLabel = lowerLabels.some(
|
|
313
|
+
(l) => l === "feature" || l === "refactor" || l === "refactoring" || l === "architecture"
|
|
314
|
+
);
|
|
315
|
+
if (description.length > 500 || hasComplexLabel) {
|
|
316
|
+
if (difficulty !== "hard") {
|
|
317
|
+
difficulty = description.length > 500 && hasComplexLabel ? "hard" : difficulty === "easy" ? "medium" : "hard";
|
|
318
|
+
}
|
|
319
|
+
confidence = Math.min(confidence + 0.1, 0.9);
|
|
320
|
+
if (description.length > 500) {
|
|
321
|
+
reasons.push(
|
|
322
|
+
`Long description (${description.length} chars) suggests complexity`
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
if (hasComplexLabel) {
|
|
326
|
+
reasons.push("Feature/refactor label suggests higher complexity");
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
if (priority === 1 || priority === 2) {
|
|
330
|
+
if (difficulty === "easy") difficulty = "medium";
|
|
331
|
+
else if (difficulty === "medium") difficulty = "hard";
|
|
332
|
+
confidence = Math.min(confidence + 0.1, 0.9);
|
|
333
|
+
reasons.push(
|
|
334
|
+
`Priority ${priority} (${priority === 1 ? "urgent" : "high"}) \u2014 higher difficulty expected`
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
if (outcomes.length > 0 && labels.length > 0) {
|
|
338
|
+
const matching = outcomes.filter(
|
|
339
|
+
(o) => o.labels && o.labels.some((ol) => lowerLabels.includes(ol.toLowerCase()))
|
|
340
|
+
);
|
|
341
|
+
if (matching.length >= 3) {
|
|
342
|
+
const avgToolCalls = matching.reduce((s, o) => s + o.toolCalls, 0) / matching.length;
|
|
343
|
+
if (avgToolCalls > 80) {
|
|
344
|
+
difficulty = "hard";
|
|
345
|
+
confidence = Math.min(confidence + 0.1, 0.9);
|
|
346
|
+
reasons.push(
|
|
347
|
+
`Historical avg tool calls ${Math.round(avgToolCalls)} for similar labels (>80)`
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
if (reasons.length === 0) {
|
|
353
|
+
reasons.push("No strong signals \u2014 defaulting to medium");
|
|
354
|
+
}
|
|
355
|
+
return { difficulty, confidence, reasons };
|
|
356
|
+
}
|
|
357
|
+
function loadOutcomes() {
|
|
358
|
+
const logPath = getOutcomesLogPath();
|
|
359
|
+
if (!existsSync(logPath)) return [];
|
|
360
|
+
try {
|
|
361
|
+
return readFileSync(logPath, "utf-8").trim().split("\n").filter(Boolean).map((l) => JSON.parse(l));
|
|
362
|
+
} catch {
|
|
363
|
+
return [];
|
|
364
|
+
}
|
|
365
|
+
}
|
|
278
366
|
function spawnClaudePrint(prompt, timeoutMs = 12e4) {
|
|
279
367
|
return new Promise((resolve, reject) => {
|
|
280
368
|
const child = cpSpawn("claude", ["--print"], {
|
|
@@ -306,6 +394,68 @@ function spawnClaudePrint(prompt, timeoutMs = 12e4) {
|
|
|
306
394
|
child.stdin.end();
|
|
307
395
|
});
|
|
308
396
|
}
|
|
397
|
+
function printSimpleDiff(oldText, newText) {
|
|
398
|
+
const oldLines = oldText.split("\n");
|
|
399
|
+
const newLines = newText.split("\n");
|
|
400
|
+
const oldSet = new Set(oldLines);
|
|
401
|
+
const newSet = new Set(newLines);
|
|
402
|
+
const removed = oldLines.filter((l) => !newSet.has(l));
|
|
403
|
+
const added = newLines.filter((l) => !oldSet.has(l));
|
|
404
|
+
const removedSet = new Set(removed);
|
|
405
|
+
const addedSet = new Set(added);
|
|
406
|
+
const CONTEXT = 2;
|
|
407
|
+
const changedOld = /* @__PURE__ */ new Set();
|
|
408
|
+
for (let i = 0; i < oldLines.length; i++) {
|
|
409
|
+
if (removedSet.has(oldLines[i])) changedOld.add(i);
|
|
410
|
+
}
|
|
411
|
+
const changedNew = /* @__PURE__ */ new Set();
|
|
412
|
+
for (let i = 0; i < newLines.length; i++) {
|
|
413
|
+
if (addedSet.has(newLines[i])) changedNew.add(i);
|
|
414
|
+
}
|
|
415
|
+
let lastPrinted = -1;
|
|
416
|
+
for (let i = 0; i < oldLines.length; i++) {
|
|
417
|
+
let nearChange = false;
|
|
418
|
+
for (let j = Math.max(0, i - CONTEXT); j <= Math.min(oldLines.length - 1, i + CONTEXT); j++) {
|
|
419
|
+
if (changedOld.has(j)) {
|
|
420
|
+
nearChange = true;
|
|
421
|
+
break;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
if (!nearChange) continue;
|
|
425
|
+
if (lastPrinted >= 0 && i > lastPrinted + 1) {
|
|
426
|
+
console.log(` ${c.d}...${c.r}`);
|
|
427
|
+
}
|
|
428
|
+
if (removedSet.has(oldLines[i])) {
|
|
429
|
+
console.log(` ${c.red}- ${oldLines[i]}${c.r}`);
|
|
430
|
+
} else {
|
|
431
|
+
console.log(` ${oldLines[i]}`);
|
|
432
|
+
}
|
|
433
|
+
lastPrinted = i;
|
|
434
|
+
}
|
|
435
|
+
if (removed.length > 0 && added.length > 0) {
|
|
436
|
+
console.log(` ${c.d}---${c.r}`);
|
|
437
|
+
}
|
|
438
|
+
lastPrinted = -1;
|
|
439
|
+
for (let i = 0; i < newLines.length; i++) {
|
|
440
|
+
let nearChange = false;
|
|
441
|
+
for (let j = Math.max(0, i - CONTEXT); j <= Math.min(newLines.length - 1, i + CONTEXT); j++) {
|
|
442
|
+
if (changedNew.has(j)) {
|
|
443
|
+
nearChange = true;
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (!nearChange) continue;
|
|
448
|
+
if (lastPrinted >= 0 && i > lastPrinted + 1) {
|
|
449
|
+
console.log(` ${c.d}...${c.r}`);
|
|
450
|
+
}
|
|
451
|
+
if (addedSet.has(newLines[i])) {
|
|
452
|
+
console.log(` ${c.green}+ ${newLines[i]}${c.r}`);
|
|
453
|
+
} else {
|
|
454
|
+
console.log(` ${newLines[i]}`);
|
|
455
|
+
}
|
|
456
|
+
lastPrinted = i;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
309
459
|
async function evolvePromptTemplate(input) {
|
|
310
460
|
const {
|
|
311
461
|
templatePath,
|
|
@@ -314,7 +464,8 @@ async function evolvePromptTemplate(input) {
|
|
|
314
464
|
failPhases,
|
|
315
465
|
errorPatterns,
|
|
316
466
|
recs,
|
|
317
|
-
outcomes
|
|
467
|
+
outcomes,
|
|
468
|
+
dryRun
|
|
318
469
|
} = input;
|
|
319
470
|
let currentTemplate;
|
|
320
471
|
if (existsSync(templatePath)) {
|
|
@@ -387,6 +538,17 @@ OUTPUT THE IMPROVED TEMPLATE:`;
|
|
|
387
538
|
);
|
|
388
539
|
return;
|
|
389
540
|
}
|
|
541
|
+
if (dryRun) {
|
|
542
|
+
console.log(`
|
|
543
|
+
${c.b}${c.cyan}Dry-run diff:${c.r}
|
|
544
|
+
`);
|
|
545
|
+
printSimpleDiff(currentTemplate, evolved.trim());
|
|
546
|
+
console.log(
|
|
547
|
+
`
|
|
548
|
+
${c.d}Dry run \u2014 no files modified. Run without --dry-run to apply.${c.r}`
|
|
549
|
+
);
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
390
552
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
391
553
|
const backupPath = templatePath.replace(".md", `.backup-${timestamp}.md`);
|
|
392
554
|
copyFileSync(templatePath, backupPath);
|
|
@@ -825,6 +987,14 @@ function createConductorCommands() {
|
|
|
825
987
|
"--evolve",
|
|
826
988
|
"Auto-mutate prompt template using GEPA-style evolution from failure data",
|
|
827
989
|
false
|
|
990
|
+
).option(
|
|
991
|
+
"--dry-run",
|
|
992
|
+
"Show evolved template without writing (use with --evolve)",
|
|
993
|
+
false
|
|
994
|
+
).option(
|
|
995
|
+
"--predict",
|
|
996
|
+
"Show difficulty predictions alongside actual outcomes",
|
|
997
|
+
false
|
|
828
998
|
).action(async (options) => {
|
|
829
999
|
const logPath = getOutcomesLogPath();
|
|
830
1000
|
if (!existsSync(logPath)) {
|
|
@@ -1015,11 +1185,161 @@ function createConductorCommands() {
|
|
|
1015
1185
|
failPhases,
|
|
1016
1186
|
errorPatterns,
|
|
1017
1187
|
recs,
|
|
1018
|
-
outcomes
|
|
1188
|
+
outcomes,
|
|
1189
|
+
dryRun: options.dryRun
|
|
1019
1190
|
});
|
|
1020
1191
|
}
|
|
1192
|
+
if (options.predict) {
|
|
1193
|
+
console.log(
|
|
1194
|
+
`
|
|
1195
|
+
${c.b}${c.purple}Difficulty Predictions vs Actual${c.r}
|
|
1196
|
+
`
|
|
1197
|
+
);
|
|
1198
|
+
const byIssue = /* @__PURE__ */ new Map();
|
|
1199
|
+
for (const o of outcomes) {
|
|
1200
|
+
byIssue.set(o.issue, o);
|
|
1201
|
+
}
|
|
1202
|
+
const difficultyColor = {
|
|
1203
|
+
easy: c.green,
|
|
1204
|
+
medium: c.yellow,
|
|
1205
|
+
hard: c.red
|
|
1206
|
+
};
|
|
1207
|
+
for (const [issue, outcome] of byIssue) {
|
|
1208
|
+
const issueLabels = outcome.labels || [];
|
|
1209
|
+
const otherOutcomes = outcomes.filter((o) => o.issue !== issue);
|
|
1210
|
+
const pred = predictDifficulty(
|
|
1211
|
+
issueLabels,
|
|
1212
|
+
"",
|
|
1213
|
+
// no description in outcome data
|
|
1214
|
+
0,
|
|
1215
|
+
// no priority in outcome data
|
|
1216
|
+
otherOutcomes
|
|
1217
|
+
);
|
|
1218
|
+
const actualDifficulty = outcome.outcome === "success" && outcome.toolCalls < 40 ? "easy" : outcome.outcome === "failure" || outcome.toolCalls > 80 ? "hard" : "medium";
|
|
1219
|
+
const match = pred.difficulty === actualDifficulty;
|
|
1220
|
+
const matchIcon = match ? `${c.green}\u2713${c.r}` : `${c.red}\u2717${c.r}`;
|
|
1221
|
+
console.log(
|
|
1222
|
+
` ${matchIcon} ${c.white}${issue.padEnd(12)}${c.r} predicted: ${difficultyColor[pred.difficulty]}${pred.difficulty.padEnd(6)}${c.r} actual: ${difficultyColor[actualDifficulty]}${actualDifficulty.padEnd(6)}${c.r} ${c.gray}(${Math.round(pred.confidence * 100)}% conf)${c.r}`
|
|
1223
|
+
);
|
|
1224
|
+
}
|
|
1225
|
+
const issueList = [...byIssue.values()];
|
|
1226
|
+
const correct = issueList.filter((o) => {
|
|
1227
|
+
const otherOutcomes = outcomes.filter((oo) => oo.issue !== o.issue);
|
|
1228
|
+
const pred = predictDifficulty(o.labels || [], "", 0, otherOutcomes);
|
|
1229
|
+
const actual = o.outcome === "success" && o.toolCalls < 40 ? "easy" : o.outcome === "failure" || o.toolCalls > 80 ? "hard" : "medium";
|
|
1230
|
+
return pred.difficulty === actual;
|
|
1231
|
+
}).length;
|
|
1232
|
+
const accuracy = Math.round(correct / issueList.length * 100);
|
|
1233
|
+
console.log(
|
|
1234
|
+
`
|
|
1235
|
+
${c.b}Accuracy${c.r}: ${accuracy}% (${correct}/${issueList.length})`
|
|
1236
|
+
);
|
|
1237
|
+
}
|
|
1021
1238
|
console.log("");
|
|
1022
1239
|
});
|
|
1240
|
+
cmd.command("predict [issue-id]").description("Predict difficulty for an issue based on historical outcomes").option("--title <title>", "Issue title (for testing without Linear)").option(
|
|
1241
|
+
"--labels <labels>",
|
|
1242
|
+
"Comma-separated labels (for testing without Linear)"
|
|
1243
|
+
).option("--priority <n>", "Priority 0-4 (for testing without Linear)", "0").option("--json", "Output as JSON", false).action(async (issueId, options) => {
|
|
1244
|
+
let title = options.title || "";
|
|
1245
|
+
let labels = options.labels ? options.labels.split(",").map((l) => l.trim()) : [];
|
|
1246
|
+
let description = "";
|
|
1247
|
+
let priority = parseInt(options.priority, 10) || 0;
|
|
1248
|
+
if (issueId && !options.title && !options.labels) {
|
|
1249
|
+
try {
|
|
1250
|
+
const { LinearClient } = await import("../../integrations/linear/client.js");
|
|
1251
|
+
const { LinearAuthManager } = await import("../../integrations/linear/auth.js");
|
|
1252
|
+
let client;
|
|
1253
|
+
try {
|
|
1254
|
+
const authManager = new LinearAuthManager(process.cwd());
|
|
1255
|
+
const token = await authManager.getValidToken();
|
|
1256
|
+
client = new LinearClient({ apiKey: token, useBearer: true });
|
|
1257
|
+
} catch {
|
|
1258
|
+
const apiKey = process.env.LINEAR_API_KEY;
|
|
1259
|
+
if (!apiKey) {
|
|
1260
|
+
console.log(
|
|
1261
|
+
`${c.red}No Linear auth found.${c.r} Use --title/--labels/--priority for testing.`
|
|
1262
|
+
);
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1265
|
+
client = new LinearClient({ apiKey });
|
|
1266
|
+
}
|
|
1267
|
+
const issue = await client.getIssue(issueId);
|
|
1268
|
+
if (!issue) {
|
|
1269
|
+
console.log(`${c.red}Issue ${issueId} not found.${c.r}`);
|
|
1270
|
+
return;
|
|
1271
|
+
}
|
|
1272
|
+
title = issue.title;
|
|
1273
|
+
description = issue.description || "";
|
|
1274
|
+
labels = issue.labels.map((l) => l.name);
|
|
1275
|
+
priority = issue.priority;
|
|
1276
|
+
} catch (err) {
|
|
1277
|
+
console.log(
|
|
1278
|
+
`${c.red}Failed to fetch issue:${c.r} ${err.message}`
|
|
1279
|
+
);
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
if (!issueId && !options.title) {
|
|
1284
|
+
console.log(
|
|
1285
|
+
`${c.yellow}Provide an issue ID or --title/--labels for testing.${c.r}`
|
|
1286
|
+
);
|
|
1287
|
+
return;
|
|
1288
|
+
}
|
|
1289
|
+
const outcomes = loadOutcomes();
|
|
1290
|
+
const pred = predictDifficulty(labels, description, priority, outcomes);
|
|
1291
|
+
if (options.json) {
|
|
1292
|
+
console.log(
|
|
1293
|
+
JSON.stringify(
|
|
1294
|
+
{
|
|
1295
|
+
issueId: issueId || "inline",
|
|
1296
|
+
title,
|
|
1297
|
+
labels,
|
|
1298
|
+
priority,
|
|
1299
|
+
...pred
|
|
1300
|
+
},
|
|
1301
|
+
null,
|
|
1302
|
+
2
|
|
1303
|
+
)
|
|
1304
|
+
);
|
|
1305
|
+
return;
|
|
1306
|
+
}
|
|
1307
|
+
const difficultyColor = {
|
|
1308
|
+
easy: c.green,
|
|
1309
|
+
medium: c.yellow,
|
|
1310
|
+
hard: c.red
|
|
1311
|
+
};
|
|
1312
|
+
console.log(`
|
|
1313
|
+
${c.b}${c.purple}Difficulty Prediction${c.r}
|
|
1314
|
+
`);
|
|
1315
|
+
if (title) {
|
|
1316
|
+
console.log(` ${c.b}Issue${c.r} ${issueId || "inline"}`);
|
|
1317
|
+
console.log(` ${c.b}Title${c.r} ${title}`);
|
|
1318
|
+
}
|
|
1319
|
+
if (labels.length > 0) {
|
|
1320
|
+
console.log(` ${c.b}Labels${c.r} ${labels.join(", ")}`);
|
|
1321
|
+
}
|
|
1322
|
+
if (priority > 0) {
|
|
1323
|
+
console.log(` ${c.b}Priority${c.r} ${priority}`);
|
|
1324
|
+
}
|
|
1325
|
+
console.log(
|
|
1326
|
+
`
|
|
1327
|
+
${c.b}Difficulty${c.r} ${difficultyColor[pred.difficulty]}${pred.difficulty.toUpperCase()}${c.r}`
|
|
1328
|
+
);
|
|
1329
|
+
console.log(
|
|
1330
|
+
` ${c.b}Confidence${c.r} ${Math.round(pred.confidence * 100)}%`
|
|
1331
|
+
);
|
|
1332
|
+
console.log(`
|
|
1333
|
+
${c.b}Signals${c.r}`);
|
|
1334
|
+
for (const reason of pred.reasons) {
|
|
1335
|
+
console.log(` ${c.cyan}\u2192${c.r} ${reason}`);
|
|
1336
|
+
}
|
|
1337
|
+
console.log(
|
|
1338
|
+
`
|
|
1339
|
+
${c.d}Based on ${outcomes.length} historical outcomes${c.r}
|
|
1340
|
+
`
|
|
1341
|
+
);
|
|
1342
|
+
});
|
|
1023
1343
|
cmd.command("usage").description("Show token usage, budget, and time-to-exhaustion").option("--json", "Output as JSON", false).option("--scan", "Scan Claude Code JSONL logs for historical data", false).action(async (options) => {
|
|
1024
1344
|
const statusPath = join(
|
|
1025
1345
|
process.cwd(),
|
|
@@ -1084,6 +1404,13 @@ function createConductorCommands() {
|
|
|
1084
1404
|
"--mode <mode>",
|
|
1085
1405
|
'Agent mode: "cli" (claude -p, session auth) or "adapter" (JSON-RPC, API key)',
|
|
1086
1406
|
"cli"
|
|
1407
|
+
).option(
|
|
1408
|
+
"--model <model>",
|
|
1409
|
+
'Model routing: "auto" (complexity-based) or a specific model ID',
|
|
1410
|
+
"auto"
|
|
1411
|
+
).option(
|
|
1412
|
+
"--no-pr",
|
|
1413
|
+
"Disable automatic GitHub PR creation after agent success"
|
|
1087
1414
|
).action(async (options) => {
|
|
1088
1415
|
ensureDefaultPromptTemplate();
|
|
1089
1416
|
const conductor = new Conductor({
|
|
@@ -1098,7 +1425,9 @@ function createConductorCommands() {
|
|
|
1098
1425
|
baseBranch: options.branch,
|
|
1099
1426
|
maxRetries: parseInt(options.retries, 10),
|
|
1100
1427
|
turnTimeoutMs: parseInt(options.turnTimeout, 10),
|
|
1101
|
-
agentMode: options.mode === "adapter" ? "adapter" : "cli"
|
|
1428
|
+
agentMode: options.mode === "adapter" ? "adapter" : "cli",
|
|
1429
|
+
model: options.model,
|
|
1430
|
+
autoPR: options.pr
|
|
1102
1431
|
});
|
|
1103
1432
|
await conductor.start();
|
|
1104
1433
|
});
|
|
@@ -1379,5 +1708,6 @@ function createConductorCommands() {
|
|
|
1379
1708
|
}
|
|
1380
1709
|
export {
|
|
1381
1710
|
createConductorCommands,
|
|
1382
|
-
formatElapsed
|
|
1711
|
+
formatElapsed,
|
|
1712
|
+
predictDifficulty
|
|
1383
1713
|
};
|