reygent-code 1.0.0 → 1.1.0
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 +16 -5
- package/dist/cli.js +969 -708
- package/dist/cli.js.map +1 -1
- package/package.json +8 -2
package/dist/cli.js
CHANGED
|
@@ -5,7 +5,7 @@ import { Command } from "commander";
|
|
|
5
5
|
import { readFileSync as readFileSync12 } from "fs";
|
|
6
6
|
import { dirname as dirname7, join as join14 } from "path";
|
|
7
7
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8
|
-
import
|
|
8
|
+
import chalk30 from "chalk";
|
|
9
9
|
|
|
10
10
|
// src/child-registry.ts
|
|
11
11
|
var activeChildProcesses = /* @__PURE__ */ new Set();
|
|
@@ -52,6 +52,9 @@ function isDebug() {
|
|
|
52
52
|
return debugEnabled || process.env.REYGENT_DEBUG === "1";
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
// src/model.ts
|
|
56
|
+
import chalk6 from "chalk";
|
|
57
|
+
|
|
55
58
|
// src/config.ts
|
|
56
59
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
57
60
|
import { join as join2 } from "path";
|
|
@@ -524,6 +527,7 @@ var SHORT_ALIASES = {
|
|
|
524
527
|
"claude-3-opus": "claude-3-opus-20240229"
|
|
525
528
|
};
|
|
526
529
|
var DEFAULT_MODEL = "claude-sonnet-4-5-20250929";
|
|
530
|
+
var vertexAiLoggedForClaude = false;
|
|
527
531
|
function extractTokenUsage(msg) {
|
|
528
532
|
const usageData = msg.usage;
|
|
529
533
|
const hasInput = usageData?.input_tokens !== void 0 || usageData?.cache_creation_input_tokens !== void 0 || usageData?.cache_read_input_tokens !== void 0 || msg.input_tokens !== void 0;
|
|
@@ -576,6 +580,18 @@ var claudeAdapter = {
|
|
|
576
580
|
if (options.autoApprove) {
|
|
577
581
|
args.push("--allowedTools", "Bash", "Edit", "Write", "Read", "Glob", "Grep");
|
|
578
582
|
}
|
|
583
|
+
const name = options.agentName;
|
|
584
|
+
const vertexProject = process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT;
|
|
585
|
+
const vertexRegion = process.env.GOOGLE_CLOUD_REGION;
|
|
586
|
+
const hasVertexConfig = !!vertexProject;
|
|
587
|
+
if (hasVertexConfig && !options.quiet && !vertexAiLoggedForClaude) {
|
|
588
|
+
const region = vertexRegion ?? "(using CLI default)";
|
|
589
|
+
process.stderr.write(
|
|
590
|
+
chalk2.gray(`[${name}] Vertex AI detected: project=${vertexProject}, region=${region}
|
|
591
|
+
`)
|
|
592
|
+
);
|
|
593
|
+
vertexAiLoggedForClaude = true;
|
|
594
|
+
}
|
|
579
595
|
const stdinMode = options.autoApprove === false ? "inherit" : "ignore";
|
|
580
596
|
const child = spawn("claude", args, {
|
|
581
597
|
stdio: [stdinMode, "pipe", "pipe"],
|
|
@@ -584,9 +600,10 @@ var claudeAdapter = {
|
|
|
584
600
|
});
|
|
585
601
|
registerChildProcess(child);
|
|
586
602
|
let resultText = "";
|
|
603
|
+
let resultErrorMessage;
|
|
604
|
+
let resultApiErrorStatus;
|
|
587
605
|
let resultUsage;
|
|
588
606
|
const textChunks = [];
|
|
589
|
-
const name = options.agentName;
|
|
590
607
|
const timeout = setTimeout(() => {
|
|
591
608
|
if (child.pid && process.platform !== "win32") {
|
|
592
609
|
try {
|
|
@@ -606,7 +623,13 @@ var claudeAdapter = {
|
|
|
606
623
|
if (stdoutEnded && stderrEnded && processExitCode !== null) {
|
|
607
624
|
clearTimeout(timeout);
|
|
608
625
|
const stdout = resultText || textChunks.join("\n");
|
|
609
|
-
resolve5({
|
|
626
|
+
resolve5({
|
|
627
|
+
stdout,
|
|
628
|
+
exitCode: processExitCode,
|
|
629
|
+
usage: resultUsage,
|
|
630
|
+
errorMessage: resultErrorMessage,
|
|
631
|
+
apiErrorStatus: resultApiErrorStatus
|
|
632
|
+
});
|
|
610
633
|
}
|
|
611
634
|
};
|
|
612
635
|
const stdoutRL = createInterface({ input: child.stdout });
|
|
@@ -641,6 +664,10 @@ var claudeAdapter = {
|
|
|
641
664
|
} else if (event.type === "result") {
|
|
642
665
|
const msg = event;
|
|
643
666
|
resultText = msg.result;
|
|
667
|
+
if (msg.is_error) {
|
|
668
|
+
resultErrorMessage = msg.result;
|
|
669
|
+
resultApiErrorStatus = msg.api_error_status;
|
|
670
|
+
}
|
|
644
671
|
const { inputTokens, outputTokens, cachedTokens, cacheWriteTokens } = extractTokenUsage(msg);
|
|
645
672
|
const hasUsage = msg.total_cost_usd !== void 0 || msg.duration_ms !== void 0 || msg.num_turns !== void 0 || inputTokens !== void 0 || outputTokens !== void 0;
|
|
646
673
|
if (hasUsage) {
|
|
@@ -730,6 +757,7 @@ var SUPPORTED_MODELS2 = [
|
|
|
730
757
|
];
|
|
731
758
|
var SHORT_ALIASES2 = {};
|
|
732
759
|
var DEFAULT_MODEL2 = "gemini-2.5-pro";
|
|
760
|
+
var vertexAiLoggedForGemini = false;
|
|
733
761
|
var availabilityCache2 = null;
|
|
734
762
|
var geminiAdapter = {
|
|
735
763
|
name: "gemini",
|
|
@@ -764,6 +792,17 @@ var geminiAdapter = {
|
|
|
764
792
|
}
|
|
765
793
|
const name = options.agentName;
|
|
766
794
|
const stdinMode = options.autoApprove === false ? "inherit" : "ignore";
|
|
795
|
+
const vertexProject = process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT;
|
|
796
|
+
const vertexRegion = process.env.GOOGLE_CLOUD_REGION;
|
|
797
|
+
const hasVertexConfig = !!vertexProject;
|
|
798
|
+
if (hasVertexConfig && !options.quiet && !vertexAiLoggedForGemini) {
|
|
799
|
+
const region = vertexRegion ?? "(using CLI default)";
|
|
800
|
+
process.stderr.write(
|
|
801
|
+
chalk3.gray(`[${name}] Vertex AI detected: project=${vertexProject}, region=${region}
|
|
802
|
+
`)
|
|
803
|
+
);
|
|
804
|
+
vertexAiLoggedForGemini = true;
|
|
805
|
+
}
|
|
767
806
|
const child = spawn2("gemini", args, {
|
|
768
807
|
stdio: [stdinMode, "pipe", "pipe"],
|
|
769
808
|
env: { ...process.env, GEMINI_CLI_TRUST_WORKSPACE: "true" },
|
|
@@ -809,14 +848,47 @@ var geminiAdapter = {
|
|
|
809
848
|
let inputTokens;
|
|
810
849
|
let outputTokens;
|
|
811
850
|
let cachedTokens;
|
|
851
|
+
let errorMessage;
|
|
852
|
+
let apiErrorStatus;
|
|
812
853
|
try {
|
|
813
854
|
const parsed = JSON.parse(stdout);
|
|
814
855
|
resultText = parsed.response ?? parsed.text ?? stdout;
|
|
815
856
|
inputTokens = parsed.usage_metadata?.prompt_token_count ?? parsed.input_tokens;
|
|
816
857
|
outputTokens = parsed.usage_metadata?.candidates_token_count ?? parsed.output_tokens;
|
|
817
858
|
cachedTokens = parsed.usage_metadata?.cached_content_token_count;
|
|
859
|
+
if (parsed.error) {
|
|
860
|
+
errorMessage = parsed.error.message;
|
|
861
|
+
let statusCode = parsed.error.status;
|
|
862
|
+
if (parsed.error.code) {
|
|
863
|
+
if (typeof parsed.error.code === "number") {
|
|
864
|
+
statusCode = parsed.error.code;
|
|
865
|
+
} else if (typeof parsed.error.code === "string") {
|
|
866
|
+
const code2 = parsed.error.code.toLowerCase();
|
|
867
|
+
if (code2 === "not_found" || code2 === "model_not_found") {
|
|
868
|
+
statusCode = 404;
|
|
869
|
+
} else if (code2 === "permission_denied" || code2 === "unauthenticated") {
|
|
870
|
+
statusCode = 403;
|
|
871
|
+
} else if (code2 === "invalid_api_key" || code2 === "invalid_authentication") {
|
|
872
|
+
statusCode = 401;
|
|
873
|
+
} else if (code2 === "resource_exhausted" || code2 === "rate_limit_exceeded") {
|
|
874
|
+
statusCode = 429;
|
|
875
|
+
} else if (code2 === "internal" || code2 === "server_error") {
|
|
876
|
+
statusCode = 500;
|
|
877
|
+
} else if (code2 === "invalid_argument") {
|
|
878
|
+
statusCode = 400;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
apiErrorStatus = statusCode;
|
|
883
|
+
}
|
|
818
884
|
} catch {
|
|
819
885
|
}
|
|
886
|
+
if (code !== 0 && !errorMessage && stderrChunks.length > 0) {
|
|
887
|
+
const stderr = stderrChunks.join("").trim();
|
|
888
|
+
if (stderr) {
|
|
889
|
+
errorMessage = stderr;
|
|
890
|
+
}
|
|
891
|
+
}
|
|
820
892
|
resolve5({
|
|
821
893
|
stdout: resultText,
|
|
822
894
|
exitCode: code ?? 1,
|
|
@@ -826,7 +898,9 @@ var geminiAdapter = {
|
|
|
826
898
|
outputTokens,
|
|
827
899
|
cachedTokens,
|
|
828
900
|
provider: "gemini"
|
|
829
|
-
}
|
|
901
|
+
},
|
|
902
|
+
errorMessage,
|
|
903
|
+
apiErrorStatus
|
|
830
904
|
});
|
|
831
905
|
});
|
|
832
906
|
});
|
|
@@ -922,8 +996,10 @@ var codexAdapter = {
|
|
|
922
996
|
child.stdout.on("data", (chunk) => {
|
|
923
997
|
stdout += chunk.toString();
|
|
924
998
|
});
|
|
999
|
+
const stderrChunks = [];
|
|
925
1000
|
child.stderr.on("data", (chunk) => {
|
|
926
1001
|
const text = chunk.toString();
|
|
1002
|
+
stderrChunks.push(text);
|
|
927
1003
|
if (options.onActivity) {
|
|
928
1004
|
const line = text.trim();
|
|
929
1005
|
if (line) options.onActivity({ agent: name, detail: line.slice(0, 80) });
|
|
@@ -942,14 +1018,44 @@ var codexAdapter = {
|
|
|
942
1018
|
let inputTokens;
|
|
943
1019
|
let outputTokens;
|
|
944
1020
|
let cachedTokens;
|
|
1021
|
+
let errorMessage;
|
|
1022
|
+
let apiErrorStatus;
|
|
945
1023
|
try {
|
|
946
1024
|
const parsed = JSON.parse(stdout);
|
|
947
1025
|
resultText = parsed.response ?? parsed.text ?? stdout;
|
|
948
1026
|
inputTokens = parsed.usage?.prompt_tokens ?? parsed.input_tokens;
|
|
949
1027
|
outputTokens = parsed.usage?.completion_tokens ?? parsed.output_tokens;
|
|
950
1028
|
cachedTokens = parsed.usage?.prompt_tokens_details?.cached_tokens ?? parsed.cached_tokens;
|
|
1029
|
+
if (parsed.error) {
|
|
1030
|
+
errorMessage = parsed.error.message;
|
|
1031
|
+
if (typeof parsed.error.code === "string") {
|
|
1032
|
+
const code2 = parsed.error.code;
|
|
1033
|
+
if (code2 === "model_not_found" || code2 === "invalid_model") {
|
|
1034
|
+
apiErrorStatus = 404;
|
|
1035
|
+
} else if (code2 === "invalid_api_key" || code2 === "invalid_request_error") {
|
|
1036
|
+
apiErrorStatus = 401;
|
|
1037
|
+
} else if (code2 === "rate_limit_exceeded") {
|
|
1038
|
+
apiErrorStatus = 429;
|
|
1039
|
+
} else if (code2 === "insufficient_quota") {
|
|
1040
|
+
apiErrorStatus = 402;
|
|
1041
|
+
} else if (code2 === "server_error") {
|
|
1042
|
+
apiErrorStatus = 500;
|
|
1043
|
+
} else if (code2.includes("not_found")) {
|
|
1044
|
+
apiErrorStatus = 404;
|
|
1045
|
+
} else if (code2.includes("auth") || code2.includes("unauthorized")) {
|
|
1046
|
+
apiErrorStatus = 401;
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
apiErrorStatus = apiErrorStatus ?? parsed.error.status;
|
|
1050
|
+
}
|
|
951
1051
|
} catch {
|
|
952
1052
|
}
|
|
1053
|
+
if (code !== 0 && !errorMessage && stderrChunks.length > 0) {
|
|
1054
|
+
const stderr = stderrChunks.join("").trim();
|
|
1055
|
+
if (stderr) {
|
|
1056
|
+
errorMessage = stderr;
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
953
1059
|
resolve5({
|
|
954
1060
|
stdout: resultText,
|
|
955
1061
|
exitCode: code ?? 1,
|
|
@@ -960,7 +1066,9 @@ var codexAdapter = {
|
|
|
960
1066
|
cachedTokens,
|
|
961
1067
|
// Note: cacheWriteTokens not extracted — OpenAI doesn't currently expose this field
|
|
962
1068
|
provider: "codex"
|
|
963
|
-
}
|
|
1069
|
+
},
|
|
1070
|
+
errorMessage,
|
|
1071
|
+
apiErrorStatus
|
|
964
1072
|
});
|
|
965
1073
|
});
|
|
966
1074
|
});
|
|
@@ -1113,6 +1221,7 @@ var SUPPORTED_MODELS5 = getProvider("claude").supportedModels;
|
|
|
1113
1221
|
var DEFAULT_MODEL5 = getProvider("claude").defaultModel;
|
|
1114
1222
|
var modelOverride = null;
|
|
1115
1223
|
var providerOverride = null;
|
|
1224
|
+
var warnedCustomModels = /* @__PURE__ */ new Set();
|
|
1116
1225
|
function setModelOverride(id) {
|
|
1117
1226
|
modelOverride = id;
|
|
1118
1227
|
}
|
|
@@ -1126,17 +1235,20 @@ function validateModel(id, providerName) {
|
|
|
1126
1235
|
if (name === "openrouter") return resolved;
|
|
1127
1236
|
const valid = provider.supportedModels.some((m) => m.id === resolved);
|
|
1128
1237
|
if (!valid) {
|
|
1129
|
-
const
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1238
|
+
const warningKey = `${name}:${resolved}`;
|
|
1239
|
+
if (!warnedCustomModels.has(warningKey)) {
|
|
1240
|
+
const list = provider.supportedModels.map((m) => ` ${m.id} \u2014 ${m.label}`).join("\n");
|
|
1241
|
+
const aliases = Object.entries(provider.shortAliases).map(([alias, full]) => ` ${alias} \u2192 ${full}`).join("\n");
|
|
1242
|
+
console.log(chalk6.yellow("Warning:"), `"${id}" not in ${name} supported models list. Using custom model.`);
|
|
1243
|
+
console.log(chalk6.gray("Supported models for"), chalk6.cyan(name) + chalk6.gray(":"));
|
|
1244
|
+
console.log(list);
|
|
1245
|
+
if (aliases) {
|
|
1246
|
+
console.log(chalk6.gray("\nShort aliases:"));
|
|
1247
|
+
console.log(aliases);
|
|
1248
|
+
}
|
|
1249
|
+
console.log("");
|
|
1250
|
+
warnedCustomModels.add(warningKey);
|
|
1251
|
+
}
|
|
1140
1252
|
}
|
|
1141
1253
|
return resolved;
|
|
1142
1254
|
}
|
|
@@ -1184,12 +1296,12 @@ function resolveTelemetryEnabled(override, config) {
|
|
|
1184
1296
|
|
|
1185
1297
|
// src/commands/agent.ts
|
|
1186
1298
|
import { select } from "@inquirer/prompts";
|
|
1187
|
-
import
|
|
1299
|
+
import chalk9 from "chalk";
|
|
1188
1300
|
|
|
1189
1301
|
// src/spec.ts
|
|
1190
1302
|
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
|
|
1191
1303
|
import { basename as basename2, extname, resolve as resolve3 } from "path";
|
|
1192
|
-
import
|
|
1304
|
+
import chalk8 from "chalk";
|
|
1193
1305
|
|
|
1194
1306
|
// src/linear.ts
|
|
1195
1307
|
var LINEAR_URL_PATTERN = /^https:\/\/linear\.app\/[^/]+\/issue\/([A-Z]+-\d+)/;
|
|
@@ -1407,7 +1519,7 @@ function loadEnvFile() {
|
|
|
1407
1519
|
|
|
1408
1520
|
// src/chesstrace/index.ts
|
|
1409
1521
|
import { randomUUID } from "crypto";
|
|
1410
|
-
import
|
|
1522
|
+
import chalk7 from "chalk";
|
|
1411
1523
|
|
|
1412
1524
|
// src/chesstrace/events.ts
|
|
1413
1525
|
var TelemetryLevel = /* @__PURE__ */ ((TelemetryLevel2) => {
|
|
@@ -1598,7 +1710,7 @@ var Chesstrace = class {
|
|
|
1598
1710
|
try {
|
|
1599
1711
|
const deleted = await backend.prune(olderThan);
|
|
1600
1712
|
if (deleted > 0) {
|
|
1601
|
-
console.log(
|
|
1713
|
+
console.log(chalk7.gray(`Pruned ${deleted} event(s) older than ${retentionDays} days`));
|
|
1602
1714
|
}
|
|
1603
1715
|
} catch (err) {
|
|
1604
1716
|
this.config.onError?.(err, "auto-prune");
|
|
@@ -1778,7 +1890,7 @@ function readSpec(filePath) {
|
|
|
1778
1890
|
}
|
|
1779
1891
|
const ext = extname(resolved).toLowerCase();
|
|
1780
1892
|
if (ext !== ".md" && ext !== ".markdown") {
|
|
1781
|
-
console.log(
|
|
1893
|
+
console.log(chalk8.yellow("Warning:"), `${basename2(resolved)} is not a .md file`);
|
|
1782
1894
|
}
|
|
1783
1895
|
const content = readFileSync4(resolved, "utf-8");
|
|
1784
1896
|
if (!content.trim()) {
|
|
@@ -2337,7 +2449,7 @@ async function agentCommand(name, options) {
|
|
|
2337
2449
|
const found = agents.find((a) => a.name === name);
|
|
2338
2450
|
if (!found) {
|
|
2339
2451
|
const validNames = agents.map((a) => a.name).join(", ");
|
|
2340
|
-
console.log(
|
|
2452
|
+
console.log(chalk9.red.bold("Error:"), `Unknown agent "${name}". Valid agents: ${validNames}`);
|
|
2341
2453
|
process.exit(1);
|
|
2342
2454
|
}
|
|
2343
2455
|
agent = found;
|
|
@@ -2348,9 +2460,9 @@ async function agentCommand(name, options) {
|
|
|
2348
2460
|
if (!process.stdin.isTTY) {
|
|
2349
2461
|
const validNames = agents.map((a) => a.name);
|
|
2350
2462
|
const displayNames = validNames.length > 5 ? `${validNames.slice(0, 5).join(", ")}, ... (${validNames.length - 5} more)` : validNames.join(", ");
|
|
2351
|
-
console.log(
|
|
2463
|
+
console.log(chalk9.red.bold("Error:"), `Agent name required in non-interactive mode. Valid agents: ${displayNames}`);
|
|
2352
2464
|
if (validNames.length > 5) {
|
|
2353
|
-
console.log(
|
|
2465
|
+
console.log(chalk9.gray(" Run 'reygent list' to see all agents."));
|
|
2354
2466
|
}
|
|
2355
2467
|
process.exit(1);
|
|
2356
2468
|
}
|
|
@@ -2380,19 +2492,19 @@ ${spec.content}`;
|
|
|
2380
2492
|
const provider = getProvider(providerName);
|
|
2381
2493
|
const modelId = agent.model ? validateModel(agent.model, providerName) : await resolveModel(providerName);
|
|
2382
2494
|
console.log(
|
|
2383
|
-
|
|
2384
|
-
Starting session with ${agent.name} agent`) +
|
|
2495
|
+
chalk9.bold.cyan(`
|
|
2496
|
+
Starting session with ${agent.name} agent`) + chalk9.gray(` (${providerName}/${modelId})`) + "\n"
|
|
2385
2497
|
);
|
|
2386
2498
|
const exitCode = await provider.spawnInteractive(systemPrompt, modelId);
|
|
2387
2499
|
process.exit(exitCode);
|
|
2388
2500
|
} catch (err) {
|
|
2389
2501
|
if (err instanceof SpecError || err instanceof TaskError) {
|
|
2390
|
-
console.log(
|
|
2502
|
+
console.log(chalk9.red.bold("Error:"), err.message);
|
|
2391
2503
|
if (isDebug()) console.error(err.stack);
|
|
2392
2504
|
process.exit(1);
|
|
2393
2505
|
}
|
|
2394
2506
|
const message = err instanceof Error ? err.message : String(err);
|
|
2395
|
-
console.log(
|
|
2507
|
+
console.log(chalk9.red.bold("Internal error:"), message);
|
|
2396
2508
|
if (isDebug()) console.error(err instanceof Error ? err.stack : err);
|
|
2397
2509
|
process.exit(2);
|
|
2398
2510
|
}
|
|
@@ -2403,12 +2515,12 @@ Starting session with ${agent.name} agent`) + chalk8.gray(` (${providerName}/${m
|
|
|
2403
2515
|
import { createInterface as createInterface2 } from "readline";
|
|
2404
2516
|
import { writeFileSync } from "fs";
|
|
2405
2517
|
import { resolve as resolve4 } from "path";
|
|
2406
|
-
import
|
|
2518
|
+
import chalk12 from "chalk";
|
|
2407
2519
|
|
|
2408
2520
|
// src/knowledge/loader.ts
|
|
2409
2521
|
import { existsSync as existsSync7, readFileSync as readFileSync5, readdirSync as readdirSync2, statSync as statSync3 } from "fs";
|
|
2410
2522
|
import { join as join5 } from "path";
|
|
2411
|
-
import
|
|
2523
|
+
import chalk10 from "chalk";
|
|
2412
2524
|
import { marked } from "marked";
|
|
2413
2525
|
|
|
2414
2526
|
// src/test-env.ts
|
|
@@ -2436,7 +2548,7 @@ function readMarkdown(filePath) {
|
|
|
2436
2548
|
const content = readFileSync5(filePath, "utf-8");
|
|
2437
2549
|
if (!content || content.trim().length === 0) return "";
|
|
2438
2550
|
if (!validateMarkdown(content)) {
|
|
2439
|
-
console.warn(
|
|
2551
|
+
console.warn(chalk10.yellow(`\u26A0 Suspicious content detected in ${filePath}, skipping`));
|
|
2440
2552
|
return null;
|
|
2441
2553
|
}
|
|
2442
2554
|
return sanitizeMarkdown(content);
|
|
@@ -2517,7 +2629,7 @@ async function loadKnowledge(agentName, stage) {
|
|
|
2517
2629
|
const knowledgeDir = findKnowledgeDir();
|
|
2518
2630
|
if (!knowledgeDir) {
|
|
2519
2631
|
if (!isTestEnvironment() && process.env.REYGENT_DEBUG !== "knowledge") {
|
|
2520
|
-
console.warn(
|
|
2632
|
+
console.warn(chalk10.yellow("\u26A0 No knowledge directory found. Run 'reygent init' to create .reygent/knowledge/"));
|
|
2521
2633
|
}
|
|
2522
2634
|
return {
|
|
2523
2635
|
agentTips: "",
|
|
@@ -2616,7 +2728,56 @@ function searchKnowledge(query) {
|
|
|
2616
2728
|
return results;
|
|
2617
2729
|
}
|
|
2618
2730
|
|
|
2731
|
+
// src/telemetry-helpers.ts
|
|
2732
|
+
function emitErrorTask(message, stage, options) {
|
|
2733
|
+
const chesstrace = getChesstrace();
|
|
2734
|
+
if (chesstrace) {
|
|
2735
|
+
try {
|
|
2736
|
+
chesstrace.emit(Events.ERROR_TASK, {
|
|
2737
|
+
type: "TaskError",
|
|
2738
|
+
message,
|
|
2739
|
+
stage,
|
|
2740
|
+
...options?.agent && { agent: options.agent },
|
|
2741
|
+
...options?.errorMessage && { errorMessage: options.errorMessage },
|
|
2742
|
+
...options?.apiErrorStatus && { apiErrorStatus: options.apiErrorStatus }
|
|
2743
|
+
});
|
|
2744
|
+
} catch (err) {
|
|
2745
|
+
if (isDebug()) {
|
|
2746
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
2747
|
+
console.error(`[DEBUG] Telemetry emit failed (ERROR_TASK): ${errMsg}`);
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
}
|
|
2752
|
+
|
|
2619
2753
|
// src/spawn.ts
|
|
2754
|
+
function looksLikeMalformedModel(model) {
|
|
2755
|
+
if (!model) return false;
|
|
2756
|
+
const trimmed = model.trim();
|
|
2757
|
+
if (trimmed.length === 0) return true;
|
|
2758
|
+
if (/\s/.test(trimmed)) return true;
|
|
2759
|
+
if (/^[^a-zA-Z0-9]|[^a-zA-Z0-9]$/.test(trimmed)) return true;
|
|
2760
|
+
if (trimmed.length < 3) return true;
|
|
2761
|
+
return false;
|
|
2762
|
+
}
|
|
2763
|
+
function formatExitDetail(result, model) {
|
|
2764
|
+
if (result.errorMessage) {
|
|
2765
|
+
const status = result.apiErrorStatus ? ` (HTTP ${result.apiErrorStatus})` : "";
|
|
2766
|
+
let detail = `
|
|
2767
|
+
${result.errorMessage}${status}`;
|
|
2768
|
+
if (result.apiErrorStatus === 404 && /not available/i.test(result.errorMessage) && looksLikeMalformedModel(model)) {
|
|
2769
|
+
detail += `
|
|
2770
|
+
Tip: edit .reygent/config.json "model" field, or run \`reygent config\` to pick a supported model.`;
|
|
2771
|
+
}
|
|
2772
|
+
return detail;
|
|
2773
|
+
}
|
|
2774
|
+
const trimmed = result.stdout.trim();
|
|
2775
|
+
if (!trimmed) return "";
|
|
2776
|
+
const truncated = trimmed.slice(0, 500);
|
|
2777
|
+
const suffix = trimmed.length > 500 ? "..." : "";
|
|
2778
|
+
return `
|
|
2779
|
+
${truncated}${suffix}`;
|
|
2780
|
+
}
|
|
2620
2781
|
async function spawnAgentStream(name, prompt2, timeoutMs, options) {
|
|
2621
2782
|
const providerName = options?.provider ?? resolveProvider();
|
|
2622
2783
|
const adapter = getProvider(providerName);
|
|
@@ -2628,13 +2789,12 @@ async function spawnAgentStream(name, prompt2, timeoutMs, options) {
|
|
|
2628
2789
|
provider: providerName,
|
|
2629
2790
|
reason
|
|
2630
2791
|
});
|
|
2631
|
-
chesstrace.emit(Events.ERROR_TASK, {
|
|
2632
|
-
type: "TaskError",
|
|
2633
|
-
message: `Provider "${providerName}" is not available: ${reason}`,
|
|
2634
|
-
stage: options?.stage ?? "spawn",
|
|
2635
|
-
agent: name
|
|
2636
|
-
});
|
|
2637
2792
|
}
|
|
2793
|
+
emitErrorTask(
|
|
2794
|
+
`Provider "${providerName}" is not available: ${reason}`,
|
|
2795
|
+
options?.stage ?? "spawn",
|
|
2796
|
+
{ agent: name }
|
|
2797
|
+
);
|
|
2638
2798
|
throw new TaskError(`Provider "${providerName}" is not available: ${reason}`);
|
|
2639
2799
|
}
|
|
2640
2800
|
const modelId = options?.model ?? await resolveModel(providerName);
|
|
@@ -2818,18 +2978,16 @@ async function runPlanner(spec, previousAnswers, options) {
|
|
|
2818
2978
|
const agents = getAgents();
|
|
2819
2979
|
const plannerAgent = agents.find((a) => a.name === "planner");
|
|
2820
2980
|
const prompt2 = buildPrompt(spec, previousAnswers, options);
|
|
2821
|
-
const
|
|
2981
|
+
const spawnResult = await spawnAgentStream("planner", prompt2, 3e5, { quiet: true, onActivity: options?.onActivity, provider: plannerAgent?.provider, model: plannerAgent?.model });
|
|
2982
|
+
const { stdout: raw, exitCode, usage, errorMessage, apiErrorStatus } = spawnResult;
|
|
2822
2983
|
if (exitCode !== 0) {
|
|
2823
|
-
const
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
});
|
|
2831
|
-
}
|
|
2832
|
-
throw new TaskError(`Planner: agent exited with code ${exitCode}`);
|
|
2984
|
+
const detail = formatExitDetail(spawnResult, plannerAgent?.model);
|
|
2985
|
+
emitErrorTask(
|
|
2986
|
+
`Planner: agent exited with code ${exitCode}${detail}`,
|
|
2987
|
+
"plan",
|
|
2988
|
+
{ agent: "planner", errorMessage, apiErrorStatus }
|
|
2989
|
+
);
|
|
2990
|
+
throw new TaskError(`Planner: agent exited with code ${exitCode}${detail}`);
|
|
2833
2991
|
}
|
|
2834
2992
|
let parsed;
|
|
2835
2993
|
try {
|
|
@@ -2857,31 +3015,23 @@ async function runPlanner(spec, previousAnswers, options) {
|
|
|
2857
3015
|
}
|
|
2858
3016
|
}
|
|
2859
3017
|
const errors = Array.isArray(obj.errors) ? obj.errors.join("\n - ") : "unknown validation error";
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
chesstrace2.emit(Events.ERROR_TASK, {
|
|
2863
|
-
type: "TaskError",
|
|
2864
|
-
message: `Planner: spec validation failed:
|
|
3018
|
+
emitErrorTask(
|
|
3019
|
+
`Planner: spec validation failed:
|
|
2865
3020
|
- ${errors}`,
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
}
|
|
3021
|
+
"plan",
|
|
3022
|
+
{ agent: "planner" }
|
|
3023
|
+
);
|
|
2870
3024
|
throw new TaskError(
|
|
2871
3025
|
`Planner: spec validation failed:
|
|
2872
3026
|
- ${errors}`
|
|
2873
3027
|
);
|
|
2874
3028
|
}
|
|
2875
3029
|
if (obj.valid !== true) {
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
stage: "plan",
|
|
2882
|
-
agent: "planner"
|
|
2883
|
-
});
|
|
2884
|
-
}
|
|
3030
|
+
emitErrorTask(
|
|
3031
|
+
"Planner: unexpected response \u2014 missing 'valid' field",
|
|
3032
|
+
"plan",
|
|
3033
|
+
{ agent: "planner" }
|
|
3034
|
+
);
|
|
2885
3035
|
throw new TaskError(
|
|
2886
3036
|
"Planner: unexpected response \u2014 missing 'valid' field"
|
|
2887
3037
|
);
|
|
@@ -2889,49 +3039,37 @@ async function runPlanner(spec, previousAnswers, options) {
|
|
|
2889
3039
|
const { goals, tasks, constraints, dod } = obj;
|
|
2890
3040
|
const chesstrace = getChesstrace();
|
|
2891
3041
|
if (!isNonEmptyStringArray(goals)) {
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
agent: "planner"
|
|
2898
|
-
});
|
|
2899
|
-
}
|
|
3042
|
+
emitErrorTask(
|
|
3043
|
+
"Planner: 'goals' must be a non-empty string array",
|
|
3044
|
+
"plan",
|
|
3045
|
+
{ agent: "planner" }
|
|
3046
|
+
);
|
|
2900
3047
|
throw new TaskError("Planner: 'goals' must be a non-empty string array");
|
|
2901
3048
|
}
|
|
2902
3049
|
if (!isNonEmptyStringArray(tasks)) {
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
agent: "planner"
|
|
2909
|
-
});
|
|
2910
|
-
}
|
|
3050
|
+
emitErrorTask(
|
|
3051
|
+
"Planner: 'tasks' must be a non-empty string array",
|
|
3052
|
+
"plan",
|
|
3053
|
+
{ agent: "planner" }
|
|
3054
|
+
);
|
|
2911
3055
|
throw new TaskError("Planner: 'tasks' must be a non-empty string array");
|
|
2912
3056
|
}
|
|
2913
3057
|
if (!isNonEmptyStringArray(constraints)) {
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
agent: "planner"
|
|
2920
|
-
});
|
|
2921
|
-
}
|
|
3058
|
+
emitErrorTask(
|
|
3059
|
+
"Planner: 'constraints' must be a non-empty string array",
|
|
3060
|
+
"plan",
|
|
3061
|
+
{ agent: "planner" }
|
|
3062
|
+
);
|
|
2922
3063
|
throw new TaskError(
|
|
2923
3064
|
"Planner: 'constraints' must be a non-empty string array"
|
|
2924
3065
|
);
|
|
2925
3066
|
}
|
|
2926
3067
|
if (!isNonEmptyStringArray(dod)) {
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
agent: "planner"
|
|
2933
|
-
});
|
|
2934
|
-
}
|
|
3068
|
+
emitErrorTask(
|
|
3069
|
+
"Planner: 'dod' must be a non-empty string array",
|
|
3070
|
+
"plan",
|
|
3071
|
+
{ agent: "planner" }
|
|
3072
|
+
);
|
|
2935
3073
|
throw new TaskError("Planner: 'dod' must be a non-empty string array");
|
|
2936
3074
|
}
|
|
2937
3075
|
return { result: { goals, tasks, constraints, dod }, usage };
|
|
@@ -3017,10 +3155,19 @@ Be specific and actionable. Expand the description into concrete requirements th
|
|
|
3017
3155
|
**Description:** ${description}${answersContext}`;
|
|
3018
3156
|
}
|
|
3019
3157
|
async function runClarification(description, previousAnswers, onActivity) {
|
|
3158
|
+
const agents = getAgents();
|
|
3159
|
+
const plannerAgent = agents.find((a) => a.name === "planner");
|
|
3020
3160
|
const prompt2 = buildClarificationPrompt(description, previousAnswers);
|
|
3021
|
-
const
|
|
3161
|
+
const clarifyResult = await spawnAgentStream("generate-spec", prompt2, 12e4, { quiet: true, onActivity });
|
|
3162
|
+
const { stdout: raw, exitCode, errorMessage, apiErrorStatus } = clarifyResult;
|
|
3022
3163
|
if (exitCode !== 0) {
|
|
3023
|
-
|
|
3164
|
+
const detail = formatExitDetail(clarifyResult, plannerAgent?.model);
|
|
3165
|
+
emitErrorTask(
|
|
3166
|
+
`generate-spec: agent exited with code ${exitCode}${detail}`,
|
|
3167
|
+
"clarification",
|
|
3168
|
+
{ agent: "generate-spec", errorMessage, apiErrorStatus }
|
|
3169
|
+
);
|
|
3170
|
+
throw new TaskError(`generate-spec: agent exited with code ${exitCode}${detail}`);
|
|
3024
3171
|
}
|
|
3025
3172
|
let parsed;
|
|
3026
3173
|
try {
|
|
@@ -3052,10 +3199,19 @@ async function runClarification(description, previousAnswers, onActivity) {
|
|
|
3052
3199
|
return { ready: true };
|
|
3053
3200
|
}
|
|
3054
3201
|
async function generateSpec(description, clarificationAnswers, onActivity) {
|
|
3202
|
+
const agents = getAgents();
|
|
3203
|
+
const plannerAgent = agents.find((a) => a.name === "planner");
|
|
3055
3204
|
const prompt2 = buildGeneratePrompt(description, clarificationAnswers);
|
|
3056
|
-
const
|
|
3205
|
+
const specResult = await spawnAgentStream("generate-spec", prompt2, 12e4, { onActivity });
|
|
3206
|
+
const { stdout, exitCode, errorMessage, apiErrorStatus } = specResult;
|
|
3057
3207
|
if (exitCode !== 0) {
|
|
3058
|
-
|
|
3208
|
+
const detail = formatExitDetail(specResult, plannerAgent?.model);
|
|
3209
|
+
emitErrorTask(
|
|
3210
|
+
`generate-spec: agent exited with code ${exitCode}${detail}`,
|
|
3211
|
+
"generate",
|
|
3212
|
+
{ agent: "generate-spec", errorMessage, apiErrorStatus }
|
|
3213
|
+
);
|
|
3214
|
+
throw new TaskError(`generate-spec: agent exited with code ${exitCode}${detail}`);
|
|
3059
3215
|
}
|
|
3060
3216
|
if (!stdout) {
|
|
3061
3217
|
throw new TaskError("generate-spec: empty result from agent");
|
|
@@ -3064,7 +3220,7 @@ async function generateSpec(description, clarificationAnswers, onActivity) {
|
|
|
3064
3220
|
}
|
|
3065
3221
|
|
|
3066
3222
|
// src/live-status.ts
|
|
3067
|
-
import
|
|
3223
|
+
import chalk11 from "chalk";
|
|
3068
3224
|
import ora from "ora";
|
|
3069
3225
|
var TRACK_LENGTH = 4;
|
|
3070
3226
|
var PAW_POSITIONS = [0, 1, 2, 3, 2, 1];
|
|
@@ -3096,16 +3252,16 @@ function truncateToWidth(text, maxWidth) {
|
|
|
3096
3252
|
function buildAnimationFrame(position, label, elapsed, lastActivity) {
|
|
3097
3253
|
const track = Array.from(
|
|
3098
3254
|
{ length: TRACK_LENGTH },
|
|
3099
|
-
(_, i) => i === position ?
|
|
3255
|
+
(_, i) => i === position ? chalk11.yellowBright("\u{1F43E}") : chalk11.gray("\xB7")
|
|
3100
3256
|
).join(" ");
|
|
3101
|
-
const mainLine = `${track} ${
|
|
3257
|
+
const mainLine = `${track} ${chalk11.blue(label)} ${chalk11.gray(elapsed)}`;
|
|
3102
3258
|
if (lastActivity) {
|
|
3103
3259
|
const parts = [lastActivity.agent];
|
|
3104
3260
|
if (lastActivity.tool) parts.push(lastActivity.tool);
|
|
3105
3261
|
if (lastActivity.detail) parts.push(lastActivity.detail.replace(/[\r\n]+/g, " "));
|
|
3106
|
-
const activityText =
|
|
3262
|
+
const activityText = chalk11.cyan(parts.join(" \u2192 "));
|
|
3107
3263
|
const terminalWidth = process.stdout.columns || 120;
|
|
3108
|
-
const separator =
|
|
3264
|
+
const separator = chalk11.gray(" | ");
|
|
3109
3265
|
const combined = `${mainLine}${separator}${activityText}`;
|
|
3110
3266
|
return truncateToWidth(combined, terminalWidth - 2);
|
|
3111
3267
|
}
|
|
@@ -3224,6 +3380,35 @@ function createLiveStatus(label) {
|
|
|
3224
3380
|
};
|
|
3225
3381
|
}
|
|
3226
3382
|
|
|
3383
|
+
// src/format.ts
|
|
3384
|
+
function stripAnsi2(str) {
|
|
3385
|
+
return str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
3386
|
+
}
|
|
3387
|
+
function wrapText(text, indent, maxWidth, continuationPrefix) {
|
|
3388
|
+
if (!text || text.trim().length === 0) return text || "";
|
|
3389
|
+
if (maxWidth <= 0) return text;
|
|
3390
|
+
if (indent < 0) indent = 0;
|
|
3391
|
+
const available = maxWidth - indent;
|
|
3392
|
+
if (available > 20 && stripAnsi2(text).length <= available) return text;
|
|
3393
|
+
const minAvailable = Math.max(available, 10);
|
|
3394
|
+
const words = text.split(" ");
|
|
3395
|
+
const wrappedLines = [];
|
|
3396
|
+
let currentLine = "";
|
|
3397
|
+
for (const word of words) {
|
|
3398
|
+
if (currentLine.length === 0) {
|
|
3399
|
+
currentLine = word;
|
|
3400
|
+
} else if (stripAnsi2(currentLine).length + 1 + stripAnsi2(word).length <= minAvailable) {
|
|
3401
|
+
currentLine += " " + word;
|
|
3402
|
+
} else {
|
|
3403
|
+
wrappedLines.push(currentLine);
|
|
3404
|
+
currentLine = word;
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
if (currentLine) wrappedLines.push(currentLine);
|
|
3408
|
+
const pad = continuationPrefix ?? " ".repeat(indent);
|
|
3409
|
+
return wrappedLines.join("\n" + pad);
|
|
3410
|
+
}
|
|
3411
|
+
|
|
3227
3412
|
// src/commands/generate-spec.ts
|
|
3228
3413
|
async function prompt(question, fallback) {
|
|
3229
3414
|
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
@@ -3239,7 +3424,7 @@ async function generateSpecCommand(description, options) {
|
|
|
3239
3424
|
if (!description) {
|
|
3240
3425
|
description = await prompt("Feature description: ");
|
|
3241
3426
|
if (!description) {
|
|
3242
|
-
console.log(
|
|
3427
|
+
console.log(chalk12.red.bold("Error:"), "Description is required.");
|
|
3243
3428
|
process.exit(1);
|
|
3244
3429
|
}
|
|
3245
3430
|
}
|
|
@@ -3259,7 +3444,7 @@ async function generateSpecCommand(description, options) {
|
|
|
3259
3444
|
try {
|
|
3260
3445
|
result = await runClarification(description, clarificationAnswers, clarifyStatus.onActivity);
|
|
3261
3446
|
} catch (err) {
|
|
3262
|
-
clarifyStatus.fail(
|
|
3447
|
+
clarifyStatus.fail(chalk12.red("Failed to check clarification needs"));
|
|
3263
3448
|
if (err instanceof TaskError) {
|
|
3264
3449
|
throw err;
|
|
3265
3450
|
}
|
|
@@ -3267,66 +3452,76 @@ async function generateSpecCommand(description, options) {
|
|
|
3267
3452
|
throw new TaskError(`Clarification check failed: ${message}`);
|
|
3268
3453
|
}
|
|
3269
3454
|
if ("ready" in result && result.ready) {
|
|
3270
|
-
clarifyStatus.succeed(
|
|
3455
|
+
clarifyStatus.succeed(chalk12.green("No clarification needed"));
|
|
3271
3456
|
ready = true;
|
|
3272
3457
|
break;
|
|
3273
3458
|
}
|
|
3274
3459
|
if ("needsClarification" in result && result.needsClarification) {
|
|
3275
3460
|
clarifyStatus.stop();
|
|
3276
3461
|
resetTerminalForInput();
|
|
3277
|
-
console.log(
|
|
3462
|
+
console.log(chalk12.yellow("\n\u2501\u2501\u2501 Clarifying Questions \u2501\u2501\u2501\n"));
|
|
3278
3463
|
const answers = [];
|
|
3279
3464
|
const rl = createInterface2({
|
|
3280
3465
|
input: process.stdin,
|
|
3281
3466
|
output: process.stdout
|
|
3282
3467
|
});
|
|
3468
|
+
const termWidth = Math.max(process.stdout.columns || 80, 40);
|
|
3283
3469
|
try {
|
|
3284
3470
|
for (let i = 0; i < result.questions.length; i++) {
|
|
3285
3471
|
const question = result.questions[i];
|
|
3472
|
+
if (i === 0) {
|
|
3473
|
+
console.log();
|
|
3474
|
+
}
|
|
3475
|
+
const counter = chalk12.cyan(`Question ${i + 1} of ${result.questions.length}`);
|
|
3476
|
+
console.log(counter);
|
|
3477
|
+
const wrapped = wrapText(question, 2, termWidth, " ");
|
|
3478
|
+
console.log(` ${wrapped}`);
|
|
3286
3479
|
const answer = await new Promise((resolve5) => {
|
|
3287
|
-
rl.question(
|
|
3288
|
-
> `, resolve5);
|
|
3480
|
+
rl.question(chalk12.gray("> "), resolve5);
|
|
3289
3481
|
});
|
|
3290
3482
|
if (answer.trim().toLowerCase() === "abort" || answer.trim().toLowerCase() === "cancel") {
|
|
3291
|
-
console.log(
|
|
3483
|
+
console.log(chalk12.red("\nAborted."));
|
|
3292
3484
|
process.exit(0);
|
|
3293
3485
|
}
|
|
3294
3486
|
answers.push(`Q: ${question}
|
|
3295
3487
|
A: ${answer}`);
|
|
3488
|
+
if (i < result.questions.length - 1) {
|
|
3489
|
+
console.log();
|
|
3490
|
+
}
|
|
3296
3491
|
}
|
|
3297
3492
|
} finally {
|
|
3298
3493
|
rl.close();
|
|
3299
3494
|
}
|
|
3300
3495
|
clarificationAnswers = answers.join("\n\n");
|
|
3301
3496
|
if (attempts < maxAttempts) {
|
|
3302
|
-
console.log(
|
|
3497
|
+
console.log(chalk12.blue("\n\u2501\u2501\u2501 Re-checking with your answers \u2501\u2501\u2501\n"));
|
|
3303
3498
|
}
|
|
3304
3499
|
}
|
|
3305
3500
|
}
|
|
3306
3501
|
if (!ready && attempts >= maxAttempts) {
|
|
3307
|
-
console.log(
|
|
3502
|
+
console.log(chalk12.yellow("Max clarification rounds reached, generating spec with answers so far..."));
|
|
3308
3503
|
}
|
|
3309
3504
|
}
|
|
3310
3505
|
const genStatus = createLiveStatus("Generating spec...");
|
|
3311
3506
|
let markdown;
|
|
3312
3507
|
try {
|
|
3313
3508
|
markdown = await generateSpec(description, clarificationAnswers, genStatus.onActivity);
|
|
3314
|
-
genStatus.succeed(
|
|
3509
|
+
genStatus.succeed(chalk12.green("Spec generated"));
|
|
3315
3510
|
} catch (err) {
|
|
3316
|
-
genStatus.fail(
|
|
3511
|
+
genStatus.fail(chalk12.red("Failed to generate spec"));
|
|
3317
3512
|
throw err;
|
|
3318
3513
|
}
|
|
3319
3514
|
const outPath = resolve4(process.cwd(), output);
|
|
3320
3515
|
writeFileSync(outPath, markdown, "utf-8");
|
|
3321
|
-
console.log(
|
|
3516
|
+
console.log(chalk12.gray("Spec written to"), chalk12.cyan(outPath));
|
|
3322
3517
|
} catch (err) {
|
|
3323
3518
|
if (err instanceof TaskError) {
|
|
3324
|
-
console.log(
|
|
3519
|
+
console.log(chalk12.red.bold("Error:"), err.message);
|
|
3325
3520
|
if (isDebug()) console.error(err.stack);
|
|
3326
3521
|
process.exit(1);
|
|
3327
3522
|
}
|
|
3328
3523
|
const message = err instanceof Error ? err.message : String(err);
|
|
3329
|
-
console.log(
|
|
3524
|
+
console.log(chalk12.red.bold("Internal error:"), message);
|
|
3330
3525
|
if (isDebug()) console.error(err instanceof Error ? err.stack : err);
|
|
3331
3526
|
process.exit(2);
|
|
3332
3527
|
}
|
|
@@ -3334,7 +3529,7 @@ A: ${answer}`);
|
|
|
3334
3529
|
}
|
|
3335
3530
|
|
|
3336
3531
|
// src/commands/spec.ts
|
|
3337
|
-
import
|
|
3532
|
+
import chalk13 from "chalk";
|
|
3338
3533
|
import { select as select2 } from "@inquirer/prompts";
|
|
3339
3534
|
|
|
3340
3535
|
// src/cursor-aware-input.ts
|
|
@@ -3535,33 +3730,6 @@ async function pasteableInput(config, context) {
|
|
|
3535
3730
|
|
|
3536
3731
|
// src/commands/spec.ts
|
|
3537
3732
|
import { ExitPromptError } from "@inquirer/core";
|
|
3538
|
-
|
|
3539
|
-
// src/format.ts
|
|
3540
|
-
function stripAnsi2(str) {
|
|
3541
|
-
return str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
3542
|
-
}
|
|
3543
|
-
function wrapText(text, indent, maxWidth, continuationPrefix) {
|
|
3544
|
-
const available = maxWidth - indent;
|
|
3545
|
-
if (available <= 20 || stripAnsi2(text).length <= available) return text;
|
|
3546
|
-
const words = text.split(" ");
|
|
3547
|
-
const wrappedLines = [];
|
|
3548
|
-
let currentLine = "";
|
|
3549
|
-
for (const word of words) {
|
|
3550
|
-
if (currentLine.length === 0) {
|
|
3551
|
-
currentLine = word;
|
|
3552
|
-
} else if (stripAnsi2(currentLine).length + 1 + stripAnsi2(word).length <= available) {
|
|
3553
|
-
currentLine += " " + word;
|
|
3554
|
-
} else {
|
|
3555
|
-
wrappedLines.push(currentLine);
|
|
3556
|
-
currentLine = word;
|
|
3557
|
-
}
|
|
3558
|
-
}
|
|
3559
|
-
if (currentLine) wrappedLines.push(currentLine);
|
|
3560
|
-
const pad = continuationPrefix ?? " ".repeat(indent);
|
|
3561
|
-
return wrappedLines.join("\n" + pad);
|
|
3562
|
-
}
|
|
3563
|
-
|
|
3564
|
-
// src/commands/spec.ts
|
|
3565
3733
|
var VALID_PROVIDERS = ["jira", "linear", "local"];
|
|
3566
3734
|
function inferProvider(source) {
|
|
3567
3735
|
if (/^https:\/\/linear\.app\//.test(source)) {
|
|
@@ -3578,7 +3746,7 @@ async function specCommand(source, options) {
|
|
|
3578
3746
|
if (options.source !== void 0) {
|
|
3579
3747
|
if (!VALID_PROVIDERS.includes(options.source)) {
|
|
3580
3748
|
console.log(
|
|
3581
|
-
|
|
3749
|
+
chalk13.red.bold("Error:"),
|
|
3582
3750
|
`Invalid source provider "${options.source}". Must be one of: ${VALID_PROVIDERS.join(", ")}`
|
|
3583
3751
|
);
|
|
3584
3752
|
process.exit(1);
|
|
@@ -3591,17 +3759,17 @@ async function specCommand(source, options) {
|
|
|
3591
3759
|
const isIssueKey = ISSUE_KEY_PATTERN.test(source);
|
|
3592
3760
|
if (provider === "local" && isLinearUrl2) {
|
|
3593
3761
|
console.log(
|
|
3594
|
-
|
|
3762
|
+
chalk13.yellow("Warning:"),
|
|
3595
3763
|
`Source "${source}" is a Linear URL, but --source=local treats it as a file path.`
|
|
3596
3764
|
);
|
|
3597
3765
|
} else if (provider === "linear" && hasMdExt) {
|
|
3598
3766
|
console.log(
|
|
3599
|
-
|
|
3767
|
+
chalk13.yellow("Warning:"),
|
|
3600
3768
|
`Source "${source}" ends in .md/.markdown, but --source=linear treats it as a Linear issue ID.`
|
|
3601
3769
|
);
|
|
3602
3770
|
} else if (provider === "jira" && hasMdExt) {
|
|
3603
3771
|
console.log(
|
|
3604
|
-
|
|
3772
|
+
chalk13.yellow("Warning:"),
|
|
3605
3773
|
`Source "${source}" ends in .md/.markdown, but --source=jira treats it as a Jira issue key.`
|
|
3606
3774
|
);
|
|
3607
3775
|
}
|
|
@@ -3612,7 +3780,7 @@ async function specCommand(source, options) {
|
|
|
3612
3780
|
if (!provider) {
|
|
3613
3781
|
if (!process.stdin.isTTY) {
|
|
3614
3782
|
console.log(
|
|
3615
|
-
|
|
3783
|
+
chalk13.red.bold("Error:"),
|
|
3616
3784
|
`Cannot determine provider for "${source}" in non-interactive mode. Use --source <jira|linear|local>.`
|
|
3617
3785
|
);
|
|
3618
3786
|
process.exit(1);
|
|
@@ -3643,7 +3811,7 @@ async function specCommand(source, options) {
|
|
|
3643
3811
|
if ("needsClarification" in result && result.needsClarification) {
|
|
3644
3812
|
status.stop();
|
|
3645
3813
|
resetTerminalForInput();
|
|
3646
|
-
console.log(
|
|
3814
|
+
console.log(chalk13.yellow("\nPlanner needs clarification:\n"));
|
|
3647
3815
|
const answers = [];
|
|
3648
3816
|
for (let i = 0; i < result.questions.length; i++) {
|
|
3649
3817
|
const question = result.questions[i];
|
|
@@ -3657,37 +3825,37 @@ async function specCommand(source, options) {
|
|
|
3657
3825
|
A: ${answer}`);
|
|
3658
3826
|
}
|
|
3659
3827
|
clarificationAnswers = answers.join("\n\n");
|
|
3660
|
-
console.log(
|
|
3828
|
+
console.log(chalk13.blue("\nRe-running planner with clarifications...\n"));
|
|
3661
3829
|
status.start();
|
|
3662
3830
|
} else {
|
|
3663
3831
|
plan = result;
|
|
3664
3832
|
}
|
|
3665
3833
|
}
|
|
3666
3834
|
if (!plan) {
|
|
3667
|
-
status.fail(
|
|
3835
|
+
status.fail(chalk13.red("Planner failed"));
|
|
3668
3836
|
throw new TaskError(`Planner: failed to create valid plan after ${maxAttempts} attempts`);
|
|
3669
3837
|
}
|
|
3670
|
-
status.succeed(
|
|
3838
|
+
status.succeed(chalk13.green("Plan created"));
|
|
3671
3839
|
const cols = process.stdout.columns || 80;
|
|
3672
|
-
console.log(
|
|
3673
|
-
for (const g of plan.goals) console.log(` ${
|
|
3674
|
-
console.log(
|
|
3675
|
-
for (const t of plan.tasks) console.log(` ${
|
|
3676
|
-
console.log(
|
|
3677
|
-
for (const c of plan.constraints) console.log(` ${
|
|
3678
|
-
console.log(
|
|
3679
|
-
for (const d of plan.dod) console.log(` ${
|
|
3840
|
+
console.log(chalk13.cyan("\nGoals:"));
|
|
3841
|
+
for (const g of plan.goals) console.log(` ${chalk13.gray("-")} ${wrapText(g, 4, cols)}`);
|
|
3842
|
+
console.log(chalk13.cyan("\nTasks:"));
|
|
3843
|
+
for (const t of plan.tasks) console.log(` ${chalk13.gray("-")} ${wrapText(t, 4, cols)}`);
|
|
3844
|
+
console.log(chalk13.cyan("\nConstraints:"));
|
|
3845
|
+
for (const c of plan.constraints) console.log(` ${chalk13.gray("-")} ${wrapText(c, 4, cols)}`);
|
|
3846
|
+
console.log(chalk13.cyan("\nDefinition of Done:"));
|
|
3847
|
+
for (const d of plan.dod) console.log(` ${chalk13.gray("-")} ${wrapText(d, 4, cols)}`);
|
|
3680
3848
|
} catch (err) {
|
|
3681
3849
|
if (err instanceof ExitPromptError) {
|
|
3682
3850
|
process.exit(0);
|
|
3683
3851
|
}
|
|
3684
3852
|
if (err instanceof SpecError || err instanceof TaskError) {
|
|
3685
|
-
console.log(
|
|
3853
|
+
console.log(chalk13.red.bold("Error:"), err.message);
|
|
3686
3854
|
if (isDebug()) console.error(err.stack);
|
|
3687
3855
|
process.exit(1);
|
|
3688
3856
|
}
|
|
3689
3857
|
const message = err instanceof Error ? err.message : String(err);
|
|
3690
|
-
console.log(
|
|
3858
|
+
console.log(chalk13.red.bold("Internal error:"), message);
|
|
3691
3859
|
if (isDebug()) console.error(err instanceof Error ? err.stack : err);
|
|
3692
3860
|
process.exit(2);
|
|
3693
3861
|
}
|
|
@@ -3697,12 +3865,12 @@ A: ${answer}`);
|
|
|
3697
3865
|
// src/commands/run.ts
|
|
3698
3866
|
import { createInterface as createInterface4 } from "readline";
|
|
3699
3867
|
import { join as join6 } from "path";
|
|
3700
|
-
import
|
|
3868
|
+
import chalk19 from "chalk";
|
|
3701
3869
|
import ora2 from "ora";
|
|
3702
3870
|
import { select as select3 } from "@inquirer/prompts";
|
|
3703
3871
|
|
|
3704
3872
|
// src/implement.ts
|
|
3705
|
-
import
|
|
3873
|
+
import chalk14 from "chalk";
|
|
3706
3874
|
function getFailureSummary(stdout, maxLen = 300) {
|
|
3707
3875
|
const trimmed = stdout.trim();
|
|
3708
3876
|
if (!trimmed) return "";
|
|
@@ -3861,15 +4029,11 @@ async function runImplement(spec, plan, options, retryOptions) {
|
|
|
3861
4029
|
const devAgent = agents.find((a) => a.name === "dev");
|
|
3862
4030
|
const qeAgent = agents.find((a) => a.name === "qe");
|
|
3863
4031
|
if (!devAgent || !qeAgent) {
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
stage: options?.stage ?? "implement",
|
|
3870
|
-
agent: "implement"
|
|
3871
|
-
});
|
|
3872
|
-
}
|
|
4032
|
+
emitErrorTask(
|
|
4033
|
+
"Implement: missing dev or qe agent config",
|
|
4034
|
+
options?.stage ?? "implement",
|
|
4035
|
+
{ agent: "implement" }
|
|
4036
|
+
);
|
|
3873
4037
|
throw new TaskError("Implement: missing dev or qe agent config");
|
|
3874
4038
|
}
|
|
3875
4039
|
const agentsToRun = retryOptions?.agentsToRun ?? ["dev", "qe"];
|
|
@@ -3908,12 +4072,15 @@ async function runImplement(spec, plan, options, retryOptions) {
|
|
|
3908
4072
|
if (devResult.value.exitCode === 0) {
|
|
3909
4073
|
dev = extractDevOutput(devResult.value.stdout);
|
|
3910
4074
|
} else {
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
if (
|
|
4075
|
+
const detail = formatExitDetail(devResult.value, devAgent.model);
|
|
4076
|
+
console.log(chalk14.red("dev agent failed:"), `exit code ${devResult.value.exitCode}${detail}`);
|
|
4077
|
+
if (!devResult.value.errorMessage || devResult.value.errorMessage.length < 50) {
|
|
4078
|
+
const summary = getFailureSummary(devResult.value.stdout);
|
|
4079
|
+
if (summary) console.log(chalk14.gray(" \u21B3"), chalk14.gray(summary));
|
|
4080
|
+
}
|
|
3914
4081
|
}
|
|
3915
4082
|
} else {
|
|
3916
|
-
console.log(
|
|
4083
|
+
console.log(chalk14.red("dev agent failed:"), devResult.reason);
|
|
3917
4084
|
}
|
|
3918
4085
|
}
|
|
3919
4086
|
if (runQE) {
|
|
@@ -3923,17 +4090,20 @@ async function runImplement(spec, plan, options, retryOptions) {
|
|
|
3923
4090
|
if (qeResult.value.exitCode === 0) {
|
|
3924
4091
|
qe = extractQEOutput(qeResult.value.stdout);
|
|
3925
4092
|
} else {
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
if (
|
|
4093
|
+
const detail = formatExitDetail(qeResult.value, qeAgent.model);
|
|
4094
|
+
console.log(chalk14.red("qe agent failed:"), `exit code ${qeResult.value.exitCode}${detail}`);
|
|
4095
|
+
if (!qeResult.value.errorMessage || qeResult.value.errorMessage.length < 50) {
|
|
4096
|
+
const summary = getFailureSummary(qeResult.value.stdout);
|
|
4097
|
+
if (summary) console.log(chalk14.gray(" \u21B3"), chalk14.gray(summary));
|
|
4098
|
+
}
|
|
3929
4099
|
}
|
|
3930
4100
|
} else {
|
|
3931
|
-
console.log(
|
|
4101
|
+
console.log(chalk14.red("qe agent failed:"), qeResult.reason);
|
|
3932
4102
|
}
|
|
3933
4103
|
}
|
|
3934
4104
|
} else {
|
|
3935
4105
|
if (runDev) {
|
|
3936
|
-
console.log(
|
|
4106
|
+
console.log(chalk14.blue("Running dev agent (approve edits as prompted)..."));
|
|
3937
4107
|
try {
|
|
3938
4108
|
const devResult = await spawnAgent("dev", devPrompt, { ...options, provider: devAgent.provider, model: devAgent.model, stage: "implement" });
|
|
3939
4109
|
if (devResult.exitCode === 0) {
|
|
@@ -3941,16 +4111,19 @@ async function runImplement(spec, plan, options, retryOptions) {
|
|
|
3941
4111
|
}
|
|
3942
4112
|
usages.push({ agent: "dev", usage: devResult.usage });
|
|
3943
4113
|
if (devResult.exitCode !== 0) {
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
if (
|
|
4114
|
+
const detail = formatExitDetail(devResult);
|
|
4115
|
+
console.log(chalk14.red("dev agent failed:"), `exit code ${devResult.exitCode}${detail}`);
|
|
4116
|
+
if (!devResult.errorMessage) {
|
|
4117
|
+
const summary = getFailureSummary(devResult.stdout);
|
|
4118
|
+
if (summary) console.log(chalk14.gray(" \u21B3"), chalk14.gray(summary));
|
|
4119
|
+
}
|
|
3947
4120
|
}
|
|
3948
4121
|
} catch (err) {
|
|
3949
|
-
console.log(
|
|
4122
|
+
console.log(chalk14.red("dev agent failed:"), err);
|
|
3950
4123
|
}
|
|
3951
4124
|
}
|
|
3952
4125
|
if (runQE) {
|
|
3953
|
-
console.log(
|
|
4126
|
+
console.log(chalk14.blue("Running qe agent (approve edits as prompted)..."));
|
|
3954
4127
|
try {
|
|
3955
4128
|
const qeResult = await spawnAgent("qe", qePrompt, { ...options, provider: qeAgent.provider, model: qeAgent.model, stage: "implement" });
|
|
3956
4129
|
if (qeResult.exitCode === 0) {
|
|
@@ -3958,47 +4131,41 @@ async function runImplement(spec, plan, options, retryOptions) {
|
|
|
3958
4131
|
}
|
|
3959
4132
|
usages.push({ agent: "qe", usage: qeResult.usage });
|
|
3960
4133
|
if (qeResult.exitCode !== 0) {
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
if (
|
|
4134
|
+
const detail = formatExitDetail(qeResult);
|
|
4135
|
+
console.log(chalk14.red("qe agent failed:"), `exit code ${qeResult.exitCode}${detail}`);
|
|
4136
|
+
if (!qeResult.errorMessage) {
|
|
4137
|
+
const summary = getFailureSummary(qeResult.stdout);
|
|
4138
|
+
if (summary) console.log(chalk14.gray(" \u21B3"), chalk14.gray(summary));
|
|
4139
|
+
}
|
|
3964
4140
|
}
|
|
3965
4141
|
} catch (err) {
|
|
3966
|
-
console.log(
|
|
4142
|
+
console.log(chalk14.red("qe agent failed:"), err);
|
|
3967
4143
|
}
|
|
3968
4144
|
}
|
|
3969
4145
|
}
|
|
3970
4146
|
const chesstrace = getChesstrace();
|
|
3971
4147
|
if (runDev && dev === null && (runQE && qe === null)) {
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
agent: "implement"
|
|
3978
|
-
});
|
|
3979
|
-
}
|
|
4148
|
+
emitErrorTask(
|
|
4149
|
+
"Implement: all requested agents failed",
|
|
4150
|
+
options?.stage ?? "implement",
|
|
4151
|
+
{ agent: "implement" }
|
|
4152
|
+
);
|
|
3980
4153
|
throw new TaskError("Implement: all requested agents failed");
|
|
3981
4154
|
}
|
|
3982
4155
|
if (runDev && !runQE && dev === null) {
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
agent: "dev"
|
|
3989
|
-
});
|
|
3990
|
-
}
|
|
4156
|
+
emitErrorTask(
|
|
4157
|
+
"Implement: dev agent failed",
|
|
4158
|
+
options?.stage ?? "implement",
|
|
4159
|
+
{ agent: "dev" }
|
|
4160
|
+
);
|
|
3991
4161
|
throw new TaskError("Implement: dev agent failed");
|
|
3992
4162
|
}
|
|
3993
4163
|
if (!runDev && runQE && qe === null) {
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
agent: "qe"
|
|
4000
|
-
});
|
|
4001
|
-
}
|
|
4164
|
+
emitErrorTask(
|
|
4165
|
+
"Implement: qe agent failed",
|
|
4166
|
+
options?.stage ?? "implement",
|
|
4167
|
+
{ agent: "qe" }
|
|
4168
|
+
);
|
|
4002
4169
|
throw new TaskError("Implement: qe agent failed");
|
|
4003
4170
|
}
|
|
4004
4171
|
return { implement: { dev, qe }, usages };
|
|
@@ -4624,7 +4791,7 @@ function detectTypeFromLinearLabels(labels) {
|
|
|
4624
4791
|
|
|
4625
4792
|
// src/pr-review.ts
|
|
4626
4793
|
import { execFile as execFile2 } from "child_process";
|
|
4627
|
-
import
|
|
4794
|
+
import chalk15 from "chalk";
|
|
4628
4795
|
|
|
4629
4796
|
// src/diff-split.ts
|
|
4630
4797
|
function estimateTokens(text) {
|
|
@@ -4850,11 +5017,11 @@ function formatPRReviewTerminal(output) {
|
|
|
4850
5017
|
const lines = [];
|
|
4851
5018
|
const cols = process.stdout.columns || 80;
|
|
4852
5019
|
lines.push("");
|
|
4853
|
-
lines.push(
|
|
5020
|
+
lines.push(chalk15.cyan.bold("Summary"));
|
|
4854
5021
|
lines.push(` ${wrapText(output.summary, 2, cols)}`);
|
|
4855
5022
|
lines.push("");
|
|
4856
5023
|
if (output.comments.length > 0) {
|
|
4857
|
-
lines.push(
|
|
5024
|
+
lines.push(chalk15.cyan.bold(`Comments (${output.comments.length}):`));
|
|
4858
5025
|
const byFile = /* @__PURE__ */ new Map();
|
|
4859
5026
|
for (const c of output.comments) {
|
|
4860
5027
|
const group = byFile.get(c.file) ?? [];
|
|
@@ -4864,22 +5031,22 @@ function formatPRReviewTerminal(output) {
|
|
|
4864
5031
|
const commentIndent = 6;
|
|
4865
5032
|
for (const [file, comments] of byFile) {
|
|
4866
5033
|
lines.push("");
|
|
4867
|
-
lines.push(` ${
|
|
5034
|
+
lines.push(` ${chalk15.bold(file)}`);
|
|
4868
5035
|
for (const c of comments) {
|
|
4869
5036
|
const lineRef = c.line !== null ? `:${c.line}` : "";
|
|
4870
5037
|
const prefix = lineRef ? `${lineRef} ` : "";
|
|
4871
5038
|
const wrapped = wrapText(prefix + c.comment, commentIndent, cols);
|
|
4872
|
-
const display = c.line !== null ?
|
|
4873
|
-
lines.push(` ${
|
|
5039
|
+
const display = c.line !== null ? chalk15.gray(`:${c.line}`) + " " + wrapped.slice(prefix.length) : wrapped;
|
|
5040
|
+
lines.push(` ${chalk15.yellow("\u2022")} ${display}`);
|
|
4874
5041
|
}
|
|
4875
5042
|
}
|
|
4876
5043
|
lines.push("");
|
|
4877
5044
|
}
|
|
4878
5045
|
if (output.recommendedActions.length > 0) {
|
|
4879
|
-
lines.push(
|
|
5046
|
+
lines.push(chalk15.cyan.bold("Recommended Actions:"));
|
|
4880
5047
|
lines.push("");
|
|
4881
5048
|
for (const action of output.recommendedActions) {
|
|
4882
|
-
lines.push(` ${
|
|
5049
|
+
lines.push(` ${chalk15.gray("-")} ${wrapText(action, 4, cols)}`);
|
|
4883
5050
|
}
|
|
4884
5051
|
}
|
|
4885
5052
|
return lines.join("\n");
|
|
@@ -4973,9 +5140,9 @@ async function resolvePRNumber(context) {
|
|
|
4973
5140
|
if (context.prCreate) {
|
|
4974
5141
|
return context.prCreate.prNumber;
|
|
4975
5142
|
}
|
|
4976
|
-
console.log(
|
|
5143
|
+
console.log(chalk15.blue("No PR number provided \u2014 detecting from current branch..."));
|
|
4977
5144
|
const detected = await detectPRFromBranch();
|
|
4978
|
-
console.log(
|
|
5145
|
+
console.log(chalk15.green(`Found PR #${detected.prNumber} on branch "${detected.branch}"`));
|
|
4979
5146
|
return detected.prNumber;
|
|
4980
5147
|
}
|
|
4981
5148
|
async function runPRReview(context, options) {
|
|
@@ -5014,7 +5181,7 @@ async function postPRReviewComment(context, review) {
|
|
|
5014
5181
|
}
|
|
5015
5182
|
|
|
5016
5183
|
// src/security-review.ts
|
|
5017
|
-
import
|
|
5184
|
+
import chalk16 from "chalk";
|
|
5018
5185
|
var SEVERITY_ORDER = {
|
|
5019
5186
|
LOW: 0,
|
|
5020
5187
|
MEDIUM: 1,
|
|
@@ -5134,27 +5301,27 @@ function extractSecurityReviewOutput(stdout) {
|
|
|
5134
5301
|
}
|
|
5135
5302
|
function formatFindings(findings, threshold) {
|
|
5136
5303
|
if (findings.length === 0) {
|
|
5137
|
-
return
|
|
5304
|
+
return chalk16.gray(" No findings.");
|
|
5138
5305
|
}
|
|
5139
5306
|
return findings.map((f) => {
|
|
5140
5307
|
const isBlocking = severityAtOrAbove(f.severity, threshold);
|
|
5141
|
-
const marker = isBlocking ?
|
|
5308
|
+
const marker = isBlocking ? chalk16.red.bold("!! ") : " ";
|
|
5142
5309
|
let severityLabel;
|
|
5143
5310
|
switch (f.severity) {
|
|
5144
5311
|
case "CRITICAL":
|
|
5145
|
-
severityLabel =
|
|
5312
|
+
severityLabel = chalk16.red.bold(`[${f.severity}]`);
|
|
5146
5313
|
break;
|
|
5147
5314
|
case "HIGH":
|
|
5148
|
-
severityLabel =
|
|
5315
|
+
severityLabel = chalk16.red(`[${f.severity}]`);
|
|
5149
5316
|
break;
|
|
5150
5317
|
case "MEDIUM":
|
|
5151
|
-
severityLabel =
|
|
5318
|
+
severityLabel = chalk16.yellow(`[${f.severity}]`);
|
|
5152
5319
|
break;
|
|
5153
5320
|
case "LOW":
|
|
5154
|
-
severityLabel =
|
|
5321
|
+
severityLabel = chalk16.blue(`[${f.severity}]`);
|
|
5155
5322
|
break;
|
|
5156
5323
|
}
|
|
5157
|
-
const loc = f.location ?
|
|
5324
|
+
const loc = f.location ? chalk16.gray(
|
|
5158
5325
|
` (${f.location.file}${f.location.line ? `:${f.location.line}` : ""})`
|
|
5159
5326
|
) : "";
|
|
5160
5327
|
const cols = process.stdout.columns || 80;
|
|
@@ -5183,7 +5350,7 @@ async function runSecurityReview(context, threshold, options) {
|
|
|
5183
5350
|
}
|
|
5184
5351
|
|
|
5185
5352
|
// src/usage.ts
|
|
5186
|
-
import
|
|
5353
|
+
import chalk17 from "chalk";
|
|
5187
5354
|
|
|
5188
5355
|
// src/pricing.ts
|
|
5189
5356
|
var PROVIDER_PRICING = {
|
|
@@ -5315,7 +5482,7 @@ function printCacheWarnings(tracker) {
|
|
|
5315
5482
|
const noCacheHit = (usage.cachedTokens ?? 0) === 0;
|
|
5316
5483
|
if (hasInput && noCacheHit) {
|
|
5317
5484
|
console.error(
|
|
5318
|
-
|
|
5485
|
+
chalk17.yellow("\u26A0") + chalk17.yellow(` [${agent}] Prompt caching appears inactive for ${provider} provider. `) + chalk17.yellow("Repeated context is not being cached \u2014 costs may be higher than expected.")
|
|
5319
5486
|
);
|
|
5320
5487
|
warned.add(agent);
|
|
5321
5488
|
}
|
|
@@ -5332,21 +5499,21 @@ function printUsageSummary(tracker) {
|
|
|
5332
5499
|
const totalSavings = entries.reduce((sum, e) => sum + calculateCacheSavings(e.usage), 0);
|
|
5333
5500
|
const byAgent = tracker.getByAgent();
|
|
5334
5501
|
console.log("");
|
|
5335
|
-
console.log(
|
|
5336
|
-
console.log(
|
|
5337
|
-
console.log(
|
|
5502
|
+
console.log(chalk17.bold.cyan("\u250C\u2500 Usage Summary"));
|
|
5503
|
+
console.log(chalk17.cyan("\u2502") + ` Total cost: ${chalk17.bold(formatCost(totalCost))}`);
|
|
5504
|
+
console.log(chalk17.cyan("\u2502") + ` Duration: ${formatDuration(totalDuration)}`);
|
|
5338
5505
|
if (totalInput > 0 || totalOutput > 0) {
|
|
5339
5506
|
const cachedSuffix = totalCached > 0 ? ` / ${formatTokenCount(totalCached)} cached` : "";
|
|
5340
|
-
console.log(
|
|
5507
|
+
console.log(chalk17.cyan("\u2502") + ` Tokens: ${formatTokenCount(totalInput)} in / ${formatTokenCount(totalOutput)} out${cachedSuffix}`);
|
|
5341
5508
|
}
|
|
5342
5509
|
if (totalSavings > 0 && Math.round(totalSavings * 100) >= 1) {
|
|
5343
|
-
console.log(
|
|
5510
|
+
console.log(chalk17.cyan("\u2502") + ` Cache saves: ${chalk17.green(formatCost(totalSavings))}`);
|
|
5344
5511
|
}
|
|
5345
|
-
console.log(
|
|
5346
|
-
console.log(
|
|
5512
|
+
console.log(chalk17.cyan("\u2502"));
|
|
5513
|
+
console.log(chalk17.cyan("\u2502") + ` By agent:`);
|
|
5347
5514
|
for (const [agent, stats] of byAgent) {
|
|
5348
5515
|
const callLabel = stats.calls === 1 ? "1 call" : `${stats.calls} calls`;
|
|
5349
|
-
const prefix =
|
|
5516
|
+
const prefix = chalk17.cyan("\u2502") + " ";
|
|
5350
5517
|
console.log(prefix + `${agent.padEnd(12)} ${formatCost(stats.cost).padStart(7)} (${callLabel})`);
|
|
5351
5518
|
if (stats.inputTokens > 0 || stats.outputTokens > 0) {
|
|
5352
5519
|
const tokenParts = [];
|
|
@@ -5355,30 +5522,30 @@ function printUsageSummary(tracker) {
|
|
|
5355
5522
|
if (stats.cachedTokens > 0) {
|
|
5356
5523
|
tokenParts.push(`${formatTokenCount(stats.cachedTokens)} cached`);
|
|
5357
5524
|
}
|
|
5358
|
-
console.log(prefix +
|
|
5525
|
+
console.log(prefix + chalk17.gray(` ${tokenParts.join(" / ")}`));
|
|
5359
5526
|
}
|
|
5360
5527
|
const agentSavings = stats.cachedTokens > 0 && stats.provider ? calculateCacheSavings({ cachedTokens: stats.cachedTokens, provider: stats.provider }) : 0;
|
|
5361
5528
|
const hitRate = stats.inputTokens > 0 && stats.cachedTokens > 0 ? Math.round(stats.cachedTokens / stats.inputTokens * 100) : 0;
|
|
5362
5529
|
if (agentSavings > 0 || hitRate > 0) {
|
|
5363
5530
|
const parts = [];
|
|
5364
|
-
if (agentSavings > 0) parts.push(
|
|
5365
|
-
if (hitRate > 0) parts.push(
|
|
5531
|
+
if (agentSavings > 0) parts.push(chalk17.green(formatCost(agentSavings) + " saved"));
|
|
5532
|
+
if (hitRate > 0) parts.push(chalk17.green(hitRate + "% hit"));
|
|
5366
5533
|
console.log(prefix + ` ${parts.join(" ")}`);
|
|
5367
5534
|
}
|
|
5368
5535
|
}
|
|
5369
|
-
console.log(
|
|
5536
|
+
console.log(chalk17.cyan("\u2514\u2500"));
|
|
5370
5537
|
printCacheWarnings(tracker);
|
|
5371
5538
|
}
|
|
5372
5539
|
function printVerboseUsage(tracker) {
|
|
5373
5540
|
const entries = tracker.getEntries();
|
|
5374
5541
|
if (entries.length === 0) return;
|
|
5375
5542
|
console.log("");
|
|
5376
|
-
console.log(
|
|
5543
|
+
console.log(chalk17.bold.cyan("\u250C\u2500 Detailed Usage") + chalk17.gray(" (--verbose)"));
|
|
5377
5544
|
for (const entry of entries) {
|
|
5378
5545
|
const { agent, stage, usage } = entry;
|
|
5379
5546
|
const tokens = usage.inputTokens || usage.outputTokens ? ` ${formatTokenCount(usage.inputTokens ?? 0)} in / ${formatTokenCount(usage.outputTokens ?? 0)} out` : "";
|
|
5380
5547
|
console.log(
|
|
5381
|
-
|
|
5548
|
+
chalk17.cyan("\u2502") + ` ${chalk17.bold(agent)} ${chalk17.gray(`(${stage})`)} ${formatCost(usage.costUsd ?? 0)} ${formatDuration(usage.durationMs ?? 0)} ${usage.numTurns ?? 0} turns${tokens}`
|
|
5382
5549
|
);
|
|
5383
5550
|
const hasCacheData = (usage.cachedTokens ?? 0) > 0 || (usage.cacheWriteTokens ?? 0) > 0 || (usage.cacheDiscount ?? 0) > 0;
|
|
5384
5551
|
if (hasCacheData) {
|
|
@@ -5390,11 +5557,11 @@ function printVerboseUsage(tracker) {
|
|
|
5390
5557
|
if (savings > 0) parts.push(`saved: ${formatCost(savings)}`);
|
|
5391
5558
|
if (usage.provider) parts.push(`provider: ${usage.provider}`);
|
|
5392
5559
|
console.log(
|
|
5393
|
-
|
|
5560
|
+
chalk17.cyan("\u2502") + ` ${chalk17.gray("cache: { " + parts.join(", ") + " }")}`
|
|
5394
5561
|
);
|
|
5395
5562
|
}
|
|
5396
5563
|
}
|
|
5397
|
-
console.log(
|
|
5564
|
+
console.log(chalk17.cyan("\u2514\u2500"));
|
|
5398
5565
|
}
|
|
5399
5566
|
|
|
5400
5567
|
// src/knowledge/analyzer.ts
|
|
@@ -5848,7 +6015,7 @@ import { existsSync as existsSync8, mkdirSync as mkdirSync2 } from "fs";
|
|
|
5848
6015
|
|
|
5849
6016
|
// src/retry-prompt.ts
|
|
5850
6017
|
import { createInterface as createInterface3 } from "readline";
|
|
5851
|
-
import
|
|
6018
|
+
import chalk18 from "chalk";
|
|
5852
6019
|
async function promptForRetry(options) {
|
|
5853
6020
|
const { taskName, attempt, maxRetries, autoApprove = false, telemetry } = options;
|
|
5854
6021
|
if (maxRetries === 0) {
|
|
@@ -5891,7 +6058,7 @@ async function promptForRetry(options) {
|
|
|
5891
6058
|
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
5892
6059
|
const answer = await new Promise((resolve5) => {
|
|
5893
6060
|
rl.question(
|
|
5894
|
-
|
|
6061
|
+
chalk18.yellow(`
|
|
5895
6062
|
${taskName} failed after ${maxRetries} retries. Continue retrying? (y/n) `),
|
|
5896
6063
|
resolve5
|
|
5897
6064
|
);
|
|
@@ -5914,7 +6081,7 @@ ${taskName} failed after ${maxRetries} retries. Continue retrying? (y/n) `),
|
|
|
5914
6081
|
}
|
|
5915
6082
|
throw new TaskError(`${taskName} failed - user declined to retry after ${maxRetries} attempts`);
|
|
5916
6083
|
}
|
|
5917
|
-
console.log(
|
|
6084
|
+
console.log(chalk18.blue("\nContinuing retries...\n"));
|
|
5918
6085
|
return true;
|
|
5919
6086
|
}
|
|
5920
6087
|
if (!autoApprove) {
|
|
@@ -5923,14 +6090,14 @@ ${taskName} failed after ${maxRetries} retries. Continue retrying? (y/n) `),
|
|
|
5923
6090
|
const attemptInfo = maxRetries > 0 ? `(attempt ${attempt}/${maxRetries})` : `(attempt ${attempt})`;
|
|
5924
6091
|
const answer = await new Promise((resolve5) => {
|
|
5925
6092
|
rl.question(
|
|
5926
|
-
|
|
6093
|
+
chalk18.yellow(`
|
|
5927
6094
|
${taskName} failed. Retry? ${attemptInfo} (y/n) `),
|
|
5928
6095
|
resolve5
|
|
5929
6096
|
);
|
|
5930
6097
|
});
|
|
5931
6098
|
rl.close();
|
|
5932
6099
|
if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
|
|
5933
|
-
console.log(
|
|
6100
|
+
console.log(chalk18.red("Aborted by user."));
|
|
5934
6101
|
process.exit(1);
|
|
5935
6102
|
}
|
|
5936
6103
|
}
|
|
@@ -6094,7 +6261,7 @@ async function retryGate(opts) {
|
|
|
6094
6261
|
}
|
|
6095
6262
|
}
|
|
6096
6263
|
const attemptDisplay = maxRetries > 0 ? `${attempt}/${maxRetries}` : `${attempt}`;
|
|
6097
|
-
console.log(
|
|
6264
|
+
console.log(chalk19.yellow(`
|
|
6098
6265
|
Retrying ${gateName} (attempt ${attemptDisplay})...`));
|
|
6099
6266
|
const failureContext = {
|
|
6100
6267
|
gateName,
|
|
@@ -6118,7 +6285,7 @@ Retrying ${gateName} (attempt ${attemptDisplay})...`));
|
|
|
6118
6285
|
if (retryResult.qe && context.implement) {
|
|
6119
6286
|
context.implement.qe = retryResult.qe;
|
|
6120
6287
|
}
|
|
6121
|
-
status.succeed(
|
|
6288
|
+
status.succeed(chalk19.green("Retry implementation complete"));
|
|
6122
6289
|
const retryStatus = createLiveStatus(`re-running ${gateName}...`);
|
|
6123
6290
|
const { gate: gateResult, usage: gateUsage } = await gateRunner(attempt + 1);
|
|
6124
6291
|
const gateAgentName = gateName === "unit tests" ? "gate:unit-tests" : "gate:functional-tests";
|
|
@@ -6130,17 +6297,17 @@ Retrying ${gateName} (attempt ${attemptDisplay})...`));
|
|
|
6130
6297
|
context.gates.functionalTests = gateResult;
|
|
6131
6298
|
}
|
|
6132
6299
|
if (gateResult.passed) {
|
|
6133
|
-
retryStatus.succeed(
|
|
6300
|
+
retryStatus.succeed(chalk19.green(`${gateName} PASSED on retry ${attempt}`));
|
|
6134
6301
|
return gateResult;
|
|
6135
6302
|
}
|
|
6136
6303
|
const attemptDisplayFail = maxRetries > 0 ? `${attempt}/${maxRetries}` : `${attempt}`;
|
|
6137
|
-
retryStatus.fail(
|
|
6304
|
+
retryStatus.fail(chalk19.red(`${gateName} FAILED (retry ${attemptDisplayFail})`));
|
|
6138
6305
|
}
|
|
6139
6306
|
}
|
|
6140
6307
|
async function promptLinearSpec() {
|
|
6141
6308
|
loadEnvFile();
|
|
6142
6309
|
if (!process.env.LINEAR_API_KEY) {
|
|
6143
|
-
console.log(
|
|
6310
|
+
console.log(chalk19.red.bold("Error:"), "LINEAR_API_KEY not set. Add it to your .env file.");
|
|
6144
6311
|
process.exit(1);
|
|
6145
6312
|
}
|
|
6146
6313
|
resetTerminalForInput();
|
|
@@ -6163,7 +6330,7 @@ async function promptJiraSpec() {
|
|
|
6163
6330
|
if (!process.env.JIRA_EMAIL) missing.push("JIRA_EMAIL");
|
|
6164
6331
|
if (!process.env.JIRA_API_TOKEN) missing.push("JIRA_API_TOKEN");
|
|
6165
6332
|
if (missing.length > 0) {
|
|
6166
|
-
console.log(
|
|
6333
|
+
console.log(chalk19.red.bold("Error:"), `Missing env vars: ${missing.join(", ")}. Add them to your .env file.`);
|
|
6167
6334
|
process.exit(1);
|
|
6168
6335
|
}
|
|
6169
6336
|
resetTerminalForInput();
|
|
@@ -6228,7 +6395,7 @@ async function runCommand(options) {
|
|
|
6228
6395
|
createdReygentDir = true;
|
|
6229
6396
|
} catch (err) {
|
|
6230
6397
|
if (isDebug()) {
|
|
6231
|
-
console.error(
|
|
6398
|
+
console.error(chalk19.gray("Failed to create .reygent:"), err);
|
|
6232
6399
|
}
|
|
6233
6400
|
}
|
|
6234
6401
|
}
|
|
@@ -6241,12 +6408,12 @@ async function runCommand(options) {
|
|
|
6241
6408
|
await chesstrace.init(backend);
|
|
6242
6409
|
await chesstrace.startRun();
|
|
6243
6410
|
if (createdReygentDir) {
|
|
6244
|
-
console.log(
|
|
6411
|
+
console.log(chalk19.green("\u2713"), chalk19.gray("Created .reygent/ for local knowledge learning"));
|
|
6245
6412
|
console.log("");
|
|
6246
6413
|
}
|
|
6247
6414
|
} catch (err) {
|
|
6248
6415
|
if (isDebug()) {
|
|
6249
|
-
console.error(
|
|
6416
|
+
console.error(chalk19.gray("Telemetry init failed:"), err);
|
|
6250
6417
|
}
|
|
6251
6418
|
chesstrace = null;
|
|
6252
6419
|
}
|
|
@@ -6256,7 +6423,7 @@ async function runCommand(options) {
|
|
|
6256
6423
|
let specSource = options.spec;
|
|
6257
6424
|
if (!specSource) {
|
|
6258
6425
|
if (!process.stdin.isTTY) {
|
|
6259
|
-
console.log(
|
|
6426
|
+
console.log(chalk19.red.bold("Error:"), "--spec is required in non-interactive environments.");
|
|
6260
6427
|
await chesstrace?.close();
|
|
6261
6428
|
process.exit(1);
|
|
6262
6429
|
}
|
|
@@ -6264,32 +6431,32 @@ async function runCommand(options) {
|
|
|
6264
6431
|
}
|
|
6265
6432
|
const spec = await loadSpec(specSource);
|
|
6266
6433
|
if (options.dryRun) {
|
|
6267
|
-
console.log(
|
|
6434
|
+
console.log(chalk19.yellow.bold("[dry-run]"), "No changes will be made.\n");
|
|
6268
6435
|
console.log("");
|
|
6269
|
-
console.log(
|
|
6270
|
-
console.log(
|
|
6271
|
-
console.log(
|
|
6272
|
-
console.log(
|
|
6436
|
+
console.log(chalk19.bold.cyan("\u250C\u2500 Specification"));
|
|
6437
|
+
console.log(chalk19.cyan("\u2502"), chalk19.bold(spec.title));
|
|
6438
|
+
console.log(chalk19.cyan("\u2502"), chalk19.gray(`source: ${spec.source}`));
|
|
6439
|
+
console.log(chalk19.cyan("\u2514\u2500"));
|
|
6273
6440
|
console.log("");
|
|
6274
|
-
console.log(
|
|
6441
|
+
console.log(chalk19.bold.cyan("\u250C\u2500 Workflow Stages"));
|
|
6275
6442
|
for (let i = 0; i < PIPELINE.length; i++) {
|
|
6276
6443
|
const stage = PIPELINE[i];
|
|
6277
6444
|
const isLast = i === PIPELINE.length - 1;
|
|
6278
6445
|
const prefix = isLast ? "\u2514\u2500" : "\u251C\u2500";
|
|
6279
6446
|
const continuation = isLast ? " " : "\u2502 ";
|
|
6280
|
-
console.log(
|
|
6281
|
-
console.log(
|
|
6447
|
+
console.log(chalk19.cyan(prefix), chalk19.bold.white(stage.name));
|
|
6448
|
+
console.log(chalk19.cyan(continuation), chalk19.gray(stage.description));
|
|
6282
6449
|
let execInfo = "";
|
|
6283
6450
|
if (stage.execution.kind === "agent") {
|
|
6284
|
-
execInfo =
|
|
6451
|
+
execInfo = chalk19.blue(`agent: ${stage.execution.agent}`);
|
|
6285
6452
|
} else if (stage.execution.kind === "parallel") {
|
|
6286
|
-
execInfo =
|
|
6453
|
+
execInfo = chalk19.magenta(`parallel: ${stage.execution.agents.join(", ")}`);
|
|
6287
6454
|
} else if (stage.execution.kind === "gate") {
|
|
6288
|
-
execInfo =
|
|
6455
|
+
execInfo = chalk19.yellow(`gate: ${stage.execution.condition} (${stage.execution.agent})`);
|
|
6289
6456
|
}
|
|
6290
|
-
console.log(
|
|
6457
|
+
console.log(chalk19.cyan(continuation), execInfo);
|
|
6291
6458
|
if (!isLast) {
|
|
6292
|
-
console.log(
|
|
6459
|
+
console.log(chalk19.cyan("\u2502"));
|
|
6293
6460
|
}
|
|
6294
6461
|
}
|
|
6295
6462
|
console.log("");
|
|
@@ -6304,7 +6471,7 @@ async function runCommand(options) {
|
|
|
6304
6471
|
context = { spec, results: [] };
|
|
6305
6472
|
const threshold = options.securityThreshold.toUpperCase();
|
|
6306
6473
|
if (!VALID_SEVERITIES.has(threshold)) {
|
|
6307
|
-
console.log(
|
|
6474
|
+
console.log(chalk19.red.bold("Error:"), `Invalid --security-threshold "${options.securityThreshold}". Must be one of: CRITICAL, HIGH, MEDIUM, LOW`);
|
|
6308
6475
|
process.exit(1);
|
|
6309
6476
|
}
|
|
6310
6477
|
let autoApprove = options.autoApprove;
|
|
@@ -6383,7 +6550,7 @@ async function runCommand(options) {
|
|
|
6383
6550
|
{ makeAssumptions: true, ...withActivity(agentOptions, status, toolTracker) }
|
|
6384
6551
|
);
|
|
6385
6552
|
if ("needsClarification" in result2 && result2.needsClarification) {
|
|
6386
|
-
status.fail(
|
|
6553
|
+
status.fail(chalk19.red("Planner asked questions despite skip flag"));
|
|
6387
6554
|
const chesstrace2 = getChesstrace();
|
|
6388
6555
|
if (chesstrace2) {
|
|
6389
6556
|
try {
|
|
@@ -6415,7 +6582,7 @@ async function runCommand(options) {
|
|
|
6415
6582
|
if ("needsClarification" in result2 && result2.needsClarification) {
|
|
6416
6583
|
status.stop();
|
|
6417
6584
|
resetTerminalForInput();
|
|
6418
|
-
console.log(
|
|
6585
|
+
console.log(chalk19.yellow("\nPlanner needs clarification:\n"));
|
|
6419
6586
|
const answers = [];
|
|
6420
6587
|
for (let i = 0; i < result2.questions.length; i++) {
|
|
6421
6588
|
const question = result2.questions[i];
|
|
@@ -6441,14 +6608,14 @@ async function runCommand(options) {
|
|
|
6441
6608
|
A: ${answer}`);
|
|
6442
6609
|
}
|
|
6443
6610
|
clarificationAnswers = answers.join("\n\n");
|
|
6444
|
-
console.log(
|
|
6611
|
+
console.log(chalk19.blue("\nRe-running planner with clarifications...\n"));
|
|
6445
6612
|
status.start();
|
|
6446
6613
|
} else {
|
|
6447
6614
|
plan = result2;
|
|
6448
6615
|
}
|
|
6449
6616
|
}
|
|
6450
6617
|
if (!plan) {
|
|
6451
|
-
status.fail(
|
|
6618
|
+
status.fail(chalk19.red("Planner failed"));
|
|
6452
6619
|
const chesstrace2 = getChesstrace();
|
|
6453
6620
|
if (chesstrace2) {
|
|
6454
6621
|
try {
|
|
@@ -6466,17 +6633,17 @@ A: ${answer}`);
|
|
|
6466
6633
|
);
|
|
6467
6634
|
}
|
|
6468
6635
|
}
|
|
6469
|
-
status.succeed(
|
|
6636
|
+
status.succeed(chalk19.green("Plan created"));
|
|
6470
6637
|
context.plan = plan;
|
|
6471
6638
|
const cols = process.stdout.columns || 80;
|
|
6472
|
-
console.log(
|
|
6473
|
-
for (const g of plan.goals) console.log(` ${
|
|
6474
|
-
console.log(
|
|
6475
|
-
for (const t of plan.tasks) console.log(` ${
|
|
6476
|
-
console.log(
|
|
6477
|
-
for (const c of plan.constraints) console.log(` ${
|
|
6478
|
-
console.log(
|
|
6479
|
-
for (const d of plan.dod) console.log(` ${
|
|
6639
|
+
console.log(chalk19.cyan("\nGoals:"));
|
|
6640
|
+
for (const g of plan.goals) console.log(` ${chalk19.gray("-")} ${wrapText(g, 4, cols)}`);
|
|
6641
|
+
console.log(chalk19.cyan("\nTasks:"));
|
|
6642
|
+
for (const t of plan.tasks) console.log(` ${chalk19.gray("-")} ${wrapText(t, 4, cols)}`);
|
|
6643
|
+
console.log(chalk19.cyan("\nConstraints:"));
|
|
6644
|
+
for (const c of plan.constraints) console.log(` ${chalk19.gray("-")} ${wrapText(c, 4, cols)}`);
|
|
6645
|
+
console.log(chalk19.cyan("\nDefinition of Done:"));
|
|
6646
|
+
for (const d of plan.dod) console.log(` ${chalk19.gray("-")} ${wrapText(d, 4, cols)}`);
|
|
6480
6647
|
console.log();
|
|
6481
6648
|
context.results.push({
|
|
6482
6649
|
stage: stage.name,
|
|
@@ -6514,15 +6681,15 @@ A: ${answer}`);
|
|
|
6514
6681
|
let devSuccess = impl.dev !== null;
|
|
6515
6682
|
let qeSuccess = impl.qe !== null;
|
|
6516
6683
|
if (devSuccess && qeSuccess) {
|
|
6517
|
-
implStatus.succeed(
|
|
6684
|
+
implStatus.succeed(chalk19.green("Implementation complete"));
|
|
6518
6685
|
} else {
|
|
6519
|
-
implStatus.warn(
|
|
6686
|
+
implStatus.warn(chalk19.yellow("Implementation partially failed"));
|
|
6520
6687
|
}
|
|
6521
6688
|
if (impl.dev) {
|
|
6522
|
-
console.log(
|
|
6689
|
+
console.log(chalk19.gray("dev files:"), impl.dev.files.join(", ") || chalk19.gray("(none)"));
|
|
6523
6690
|
}
|
|
6524
6691
|
if (impl.qe) {
|
|
6525
|
-
console.log(
|
|
6692
|
+
console.log(chalk19.gray("qe test files:"), impl.qe.testFiles.join(", ") || chalk19.gray("(none)"));
|
|
6526
6693
|
}
|
|
6527
6694
|
let attempt = 0;
|
|
6528
6695
|
while (!devSuccess || !qeSuccess) {
|
|
@@ -6545,7 +6712,7 @@ A: ${answer}`);
|
|
|
6545
6712
|
if (!devSuccess) agentsToRetry.push("dev");
|
|
6546
6713
|
if (!qeSuccess) agentsToRetry.push("qe");
|
|
6547
6714
|
const attemptDisplay = maxRetries > 0 ? `${attempt}/${maxRetries}` : `${attempt}`;
|
|
6548
|
-
console.log(
|
|
6715
|
+
console.log(chalk19.yellow(`
|
|
6549
6716
|
Retrying ${agentsToRetry.join(" + ")} agent(s) (attempt ${attemptDisplay})...`));
|
|
6550
6717
|
const retryStatus = createLiveStatus(`re-running ${agentsToRetry.join(" + ")} agent(s)...`);
|
|
6551
6718
|
try {
|
|
@@ -6567,18 +6734,18 @@ Retrying ${agentsToRetry.join(" + ")} agent(s) (attempt ${attemptDisplay})...`))
|
|
|
6567
6734
|
qeSuccess = true;
|
|
6568
6735
|
}
|
|
6569
6736
|
if (devSuccess && qeSuccess) {
|
|
6570
|
-
retryStatus.succeed(
|
|
6737
|
+
retryStatus.succeed(chalk19.green("Implementation complete on retry"));
|
|
6571
6738
|
if (context.implement.dev) {
|
|
6572
|
-
console.log(
|
|
6739
|
+
console.log(chalk19.gray("dev files:"), context.implement.dev.files.join(", ") || chalk19.gray("(none)"));
|
|
6573
6740
|
}
|
|
6574
6741
|
if (context.implement.qe) {
|
|
6575
|
-
console.log(
|
|
6742
|
+
console.log(chalk19.gray("qe test files:"), context.implement.qe.testFiles.join(", ") || chalk19.gray("(none)"));
|
|
6576
6743
|
}
|
|
6577
6744
|
} else {
|
|
6578
|
-
retryStatus.warn(
|
|
6745
|
+
retryStatus.warn(chalk19.yellow(`Retry ${attempt} partially failed`));
|
|
6579
6746
|
}
|
|
6580
6747
|
} catch {
|
|
6581
|
-
retryStatus.fail(
|
|
6748
|
+
retryStatus.fail(chalk19.red(`Retry ${attempt} failed`));
|
|
6582
6749
|
}
|
|
6583
6750
|
}
|
|
6584
6751
|
context.results.push({
|
|
@@ -6614,7 +6781,7 @@ Retrying ${agentsToRetry.join(" + ")} agent(s) (attempt ${attemptDisplay})...`))
|
|
|
6614
6781
|
if (!context.gates) context.gates = {};
|
|
6615
6782
|
context.gates.unitTests = gateResult;
|
|
6616
6783
|
if (gateResult.passed) {
|
|
6617
|
-
unitStatus.succeed(
|
|
6784
|
+
unitStatus.succeed(chalk19.green("Unit tests PASSED"));
|
|
6618
6785
|
context.results.push({
|
|
6619
6786
|
stage: stage.name,
|
|
6620
6787
|
success: true,
|
|
@@ -6623,7 +6790,7 @@ Retrying ${agentsToRetry.join(" + ")} agent(s) (attempt ${attemptDisplay})...`))
|
|
|
6623
6790
|
emitStageEnd(chesstrace, stage.name, stageStartTime, true, void 0, toolTracker);
|
|
6624
6791
|
continue;
|
|
6625
6792
|
}
|
|
6626
|
-
unitStatus.fail(
|
|
6793
|
+
unitStatus.fail(chalk19.red("Unit tests FAILED"));
|
|
6627
6794
|
try {
|
|
6628
6795
|
gateResult = await retryGate({
|
|
6629
6796
|
gateName: "unit tests",
|
|
@@ -6675,7 +6842,7 @@ Retrying ${agentsToRetry.join(" + ")} agent(s) (attempt ${attemptDisplay})...`))
|
|
|
6675
6842
|
if (!context.gates) context.gates = {};
|
|
6676
6843
|
context.gates.functionalTests = gateResult;
|
|
6677
6844
|
if (gateResult.passed) {
|
|
6678
|
-
funcStatus.succeed(
|
|
6845
|
+
funcStatus.succeed(chalk19.green("Functional tests PASSED"));
|
|
6679
6846
|
context.results.push({
|
|
6680
6847
|
stage: stage.name,
|
|
6681
6848
|
success: true,
|
|
@@ -6684,7 +6851,7 @@ Retrying ${agentsToRetry.join(" + ")} agent(s) (attempt ${attemptDisplay})...`))
|
|
|
6684
6851
|
emitStageEnd(chesstrace, stage.name, stageStartTime, true, void 0, toolTracker);
|
|
6685
6852
|
continue;
|
|
6686
6853
|
}
|
|
6687
|
-
funcStatus.fail(
|
|
6854
|
+
funcStatus.fail(chalk19.red("Functional tests FAILED"));
|
|
6688
6855
|
console.log(gateResult.output);
|
|
6689
6856
|
try {
|
|
6690
6857
|
gateResult = await retryGate({
|
|
@@ -6736,12 +6903,12 @@ Retrying ${agentsToRetry.join(" + ")} agent(s) (attempt ${attemptDisplay})...`))
|
|
|
6736
6903
|
if (secUsage) tracker.record("security-review", stage.name, secUsage);
|
|
6737
6904
|
context.securityReview = output;
|
|
6738
6905
|
if (passed) {
|
|
6739
|
-
secStatus.succeed(
|
|
6906
|
+
secStatus.succeed(chalk19.green("Security review PASSED"));
|
|
6740
6907
|
} else {
|
|
6741
|
-
secStatus.fail(
|
|
6908
|
+
secStatus.fail(chalk19.red("Security review FAILED"));
|
|
6742
6909
|
}
|
|
6743
6910
|
console.log("");
|
|
6744
|
-
console.log(
|
|
6911
|
+
console.log(chalk19.cyan.bold(`Security Findings (${output.findings.length}):`));
|
|
6745
6912
|
console.log(formatFindings(output.findings, threshold));
|
|
6746
6913
|
console.log("");
|
|
6747
6914
|
if (passed) {
|
|
@@ -6753,7 +6920,7 @@ Retrying ${agentsToRetry.join(" + ")} agent(s) (attempt ${attemptDisplay})...`))
|
|
|
6753
6920
|
emitStageEnd(chesstrace, stage.name, stageStartTime, true, void 0, toolTracker);
|
|
6754
6921
|
continue;
|
|
6755
6922
|
}
|
|
6756
|
-
console.log(
|
|
6923
|
+
console.log(chalk19.yellow(`Findings at or above ${threshold} threshold`));
|
|
6757
6924
|
context.results.push({
|
|
6758
6925
|
stage: stage.name,
|
|
6759
6926
|
success: false,
|
|
@@ -6761,7 +6928,7 @@ Retrying ${agentsToRetry.join(" + ")} agent(s) (attempt ${attemptDisplay})...`))
|
|
|
6761
6928
|
});
|
|
6762
6929
|
emitStageEnd(chesstrace, stage.name, stageStartTime, false, void 0, toolTracker);
|
|
6763
6930
|
if (autoApprove) {
|
|
6764
|
-
console.log(
|
|
6931
|
+
console.log(chalk19.yellow("Auto-approved \u2014 bypassing security gate..."));
|
|
6765
6932
|
} else {
|
|
6766
6933
|
resetTerminalForInput();
|
|
6767
6934
|
const rl = createInterface4({
|
|
@@ -6770,16 +6937,16 @@ Retrying ${agentsToRetry.join(" + ")} agent(s) (attempt ${attemptDisplay})...`))
|
|
|
6770
6937
|
});
|
|
6771
6938
|
const answer = await new Promise((resolve5) => {
|
|
6772
6939
|
rl.question(
|
|
6773
|
-
|
|
6940
|
+
chalk19.yellow("\nSecurity review failed. Continue with PR creation anyway? (y/n) "),
|
|
6774
6941
|
resolve5
|
|
6775
6942
|
);
|
|
6776
6943
|
});
|
|
6777
6944
|
rl.close();
|
|
6778
6945
|
if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
|
|
6779
|
-
console.log(
|
|
6946
|
+
console.log(chalk19.red("Aborted by user."));
|
|
6780
6947
|
process.exit(1);
|
|
6781
6948
|
}
|
|
6782
|
-
console.log(
|
|
6949
|
+
console.log(chalk19.yellow("Bypassed by user \u2014 continuing..."));
|
|
6783
6950
|
}
|
|
6784
6951
|
continue;
|
|
6785
6952
|
}
|
|
@@ -6818,12 +6985,12 @@ Retrying ${agentsToRetry.join(" + ")} agent(s) (attempt ${attemptDisplay})...`))
|
|
|
6818
6985
|
});
|
|
6819
6986
|
}
|
|
6820
6987
|
}
|
|
6821
|
-
const spinner = ora2(
|
|
6988
|
+
const spinner = ora2(chalk19.blue("creating pull request...")).start();
|
|
6822
6989
|
const prResult = await runPRCreate(context, { insecure: options.insecure, branchType });
|
|
6823
6990
|
context.prCreate = prResult;
|
|
6824
|
-
spinner.succeed(
|
|
6825
|
-
console.log(
|
|
6826
|
-
console.log(
|
|
6991
|
+
spinner.succeed(chalk19.green("PR created"));
|
|
6992
|
+
console.log(chalk19.gray("branch:"), chalk19.cyan(prResult.branch));
|
|
6993
|
+
console.log(chalk19.gray("PR:"), chalk19.blue(prResult.prUrl));
|
|
6827
6994
|
context.results.push({
|
|
6828
6995
|
stage: stage.name,
|
|
6829
6996
|
success: true,
|
|
@@ -6840,15 +7007,15 @@ Retrying ${agentsToRetry.join(" + ")} agent(s) (attempt ${attemptDisplay})...`))
|
|
|
6840
7007
|
);
|
|
6841
7008
|
context.prReview = reviewOutput;
|
|
6842
7009
|
if (prUsage) tracker.record("pr-review", stage.name, prUsage);
|
|
6843
|
-
prStatus.succeed(
|
|
7010
|
+
prStatus.succeed(chalk19.green("PR review complete"));
|
|
6844
7011
|
console.log(formatPRReviewTerminal(reviewOutput));
|
|
6845
|
-
const commentSpinner = ora2(
|
|
7012
|
+
const commentSpinner = ora2(chalk19.blue("posting review comment to PR...")).start();
|
|
6846
7013
|
try {
|
|
6847
7014
|
await postPRReviewComment(context, reviewOutput);
|
|
6848
|
-
commentSpinner.succeed(
|
|
7015
|
+
commentSpinner.succeed(chalk19.green("Review posted to PR"));
|
|
6849
7016
|
} catch (err) {
|
|
6850
7017
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6851
|
-
commentSpinner.fail(
|
|
7018
|
+
commentSpinner.fail(chalk19.yellow(`Could not post review to PR: ${msg}`));
|
|
6852
7019
|
}
|
|
6853
7020
|
context.results.push({
|
|
6854
7021
|
stage: stage.name,
|
|
@@ -6863,7 +7030,7 @@ Retrying ${agentsToRetry.join(" + ")} agent(s) (attempt ${attemptDisplay})...`))
|
|
|
6863
7030
|
success: true,
|
|
6864
7031
|
output: "skipped"
|
|
6865
7032
|
};
|
|
6866
|
-
console.log(
|
|
7033
|
+
console.log(chalk19.gray(`[${stage.name}] skipped`));
|
|
6867
7034
|
context.results.push(result);
|
|
6868
7035
|
emitStageEnd(chesstrace, stage.name, stageStartTime, true, void 0, toolTracker);
|
|
6869
7036
|
}
|
|
@@ -6947,13 +7114,13 @@ Retrying ${agentsToRetry.join(" + ")} agent(s) (attempt ${attemptDisplay})...`))
|
|
|
6947
7114
|
process.exit(0);
|
|
6948
7115
|
}
|
|
6949
7116
|
if (err instanceof SpecError || err instanceof TaskError) {
|
|
6950
|
-
console.log(
|
|
7117
|
+
console.log(chalk19.red.bold("Error:"), err.message);
|
|
6951
7118
|
if (isDebug()) console.error(err.stack);
|
|
6952
7119
|
if (isTest) throw err;
|
|
6953
7120
|
process.exit(1);
|
|
6954
7121
|
}
|
|
6955
7122
|
const message = err instanceof Error ? err.message : String(err);
|
|
6956
|
-
console.log(
|
|
7123
|
+
console.log(chalk19.red.bold("Internal error:"), message);
|
|
6957
7124
|
if (isDebug()) console.error(err instanceof Error ? err.stack : err);
|
|
6958
7125
|
if (isTest) throw err;
|
|
6959
7126
|
process.exit(2);
|
|
@@ -6965,7 +7132,7 @@ import { existsSync as existsSync9, mkdirSync as mkdirSync3, writeFileSync as wr
|
|
|
6965
7132
|
import { join as join7 } from "path";
|
|
6966
7133
|
import { ExitPromptError as ExitPromptError2 } from "@inquirer/core";
|
|
6967
7134
|
import { select as select4 } from "@inquirer/prompts";
|
|
6968
|
-
import
|
|
7135
|
+
import chalk20 from "chalk";
|
|
6969
7136
|
import ora3 from "ora";
|
|
6970
7137
|
async function initCommand(options = { dryRun: false }) {
|
|
6971
7138
|
const targetDir = join7(process.cwd(), ".reygent");
|
|
@@ -6977,25 +7144,25 @@ async function initCommand(options = { dryRun: false }) {
|
|
|
6977
7144
|
model: DEFAULT_MODEL5
|
|
6978
7145
|
};
|
|
6979
7146
|
if (options.dryRun) {
|
|
6980
|
-
console.log(
|
|
6981
|
-
console.log(
|
|
6982
|
-
console.log(
|
|
6983
|
-
console.log(
|
|
6984
|
-
console.log(
|
|
7147
|
+
console.log(chalk20.yellow.bold("[dry-run]"), "No changes will be made.\n");
|
|
7148
|
+
console.log(chalk20.bold("Would create:"));
|
|
7149
|
+
console.log(chalk20.gray(" dir: "), chalk20.cyan(targetDir));
|
|
7150
|
+
console.log(chalk20.gray(" dir: "), chalk20.cyan(skillsDir));
|
|
7151
|
+
console.log(chalk20.gray(" file: "), chalk20.cyan(configPath));
|
|
6985
7152
|
console.log("");
|
|
6986
|
-
console.log(
|
|
6987
|
-
console.log(
|
|
7153
|
+
console.log(chalk20.bold("Config preview:"));
|
|
7154
|
+
console.log(chalk20.gray(JSON.stringify(defaultConfig, null, 2)));
|
|
6988
7155
|
console.log("");
|
|
6989
7156
|
return;
|
|
6990
7157
|
}
|
|
6991
7158
|
try {
|
|
6992
7159
|
if (existsSync9(targetDir)) {
|
|
6993
|
-
console.log(
|
|
6994
|
-
console.log(
|
|
7160
|
+
console.log(chalk20.yellow.bold("Warning:"), `.reygent folder already exists`);
|
|
7161
|
+
console.log(chalk20.gray(` Path: ${targetDir}
|
|
6995
7162
|
`));
|
|
6996
7163
|
if (existsSync9(configPath)) {
|
|
6997
7164
|
if (!process.stdin.isTTY) {
|
|
6998
|
-
console.log(
|
|
7165
|
+
console.log(chalk20.red.bold("Error:"), "Cannot prompt in non-interactive mode. Use --dry-run to preview or remove existing .reygent/ first.");
|
|
6999
7166
|
process.exit(1);
|
|
7000
7167
|
}
|
|
7001
7168
|
resetTerminalForInput();
|
|
@@ -7008,16 +7175,16 @@ async function initCommand(options = { dryRun: false }) {
|
|
|
7008
7175
|
]
|
|
7009
7176
|
});
|
|
7010
7177
|
if (action === "cancel") {
|
|
7011
|
-
console.log(
|
|
7178
|
+
console.log(chalk20.gray("No changes made.\n"));
|
|
7012
7179
|
return;
|
|
7013
7180
|
}
|
|
7014
7181
|
if (action === "edit") {
|
|
7015
|
-
console.log(
|
|
7182
|
+
console.log(chalk20.cyan("Run"), chalk20.bold("reygent config"), chalk20.cyan("to edit your configuration.\n"));
|
|
7016
7183
|
return;
|
|
7017
7184
|
}
|
|
7018
|
-
console.log(
|
|
7185
|
+
console.log(chalk20.cyan("Resetting config to defaults...\n"));
|
|
7019
7186
|
} else {
|
|
7020
|
-
console.log(
|
|
7187
|
+
console.log(chalk20.cyan("No config.json found. Creating default config...\n"));
|
|
7021
7188
|
}
|
|
7022
7189
|
}
|
|
7023
7190
|
const spinnerText = existsSync9(targetDir) ? "Writing config" : "Creating .reygent folder";
|
|
@@ -7044,24 +7211,24 @@ knowledge/success-patterns.md
|
|
|
7044
7211
|
# - knowledge/agents/*.md (curated agent tips)
|
|
7045
7212
|
`;
|
|
7046
7213
|
writeFileSync2(gitignorePath, gitignoreContent, "utf-8");
|
|
7047
|
-
spinner.succeed(
|
|
7214
|
+
spinner.succeed(chalk20.green("Initialized .reygent folder"));
|
|
7048
7215
|
console.log("");
|
|
7049
|
-
console.log(
|
|
7050
|
-
console.log(
|
|
7051
|
-
console.log(
|
|
7052
|
-
console.log(
|
|
7053
|
-
console.log(
|
|
7054
|
-
console.log(
|
|
7216
|
+
console.log(chalk20.bold("Next steps:"));
|
|
7217
|
+
console.log(chalk20.gray(" \u2022 Edit"), chalk20.cyan(".reygent/config.json"), chalk20.gray("to customize agents"));
|
|
7218
|
+
console.log(chalk20.gray(" \u2022 Add custom agents to the"), chalk20.cyan("agents"), chalk20.gray("array"));
|
|
7219
|
+
console.log(chalk20.gray(" \u2022 Add skills to"), chalk20.cyan(".reygent/skills/"), chalk20.gray("(each in its own folder with SKILL.md)"));
|
|
7220
|
+
console.log(chalk20.gray(" \u2022 Populate"), chalk20.cyan(".reygent/knowledge/"), chalk20.gray("with project conventions"));
|
|
7221
|
+
console.log(chalk20.gray(" \u2022 Run"), chalk20.cyan("reygent agent <name>"), chalk20.gray("to use your local config"));
|
|
7055
7222
|
console.log("");
|
|
7056
7223
|
} catch (err) {
|
|
7057
7224
|
const message = err instanceof Error ? err.message : String(err);
|
|
7058
|
-
spinner.fail(
|
|
7225
|
+
spinner.fail(chalk20.red(`Failed: ${message}`));
|
|
7059
7226
|
if (isDebug()) console.error(err instanceof Error ? err.stack : err);
|
|
7060
7227
|
process.exit(2);
|
|
7061
7228
|
}
|
|
7062
7229
|
} catch (err) {
|
|
7063
7230
|
if (err instanceof ExitPromptError2) {
|
|
7064
|
-
console.log(
|
|
7231
|
+
console.log(chalk20.yellow("\nInitialization cancelled."));
|
|
7065
7232
|
process.exit(0);
|
|
7066
7233
|
}
|
|
7067
7234
|
throw err;
|
|
@@ -7072,7 +7239,7 @@ knowledge/success-patterns.md
|
|
|
7072
7239
|
import { existsSync as existsSync11, mkdirSync as mkdirSync5, writeFileSync as writeFileSync3, rmSync, readdirSync as readdirSync4, statSync as statSync5, readFileSync as readFileSync8 } from "fs";
|
|
7073
7240
|
import { join as join9, dirname as dirname4 } from "path";
|
|
7074
7241
|
import { fileURLToPath } from "url";
|
|
7075
|
-
import
|
|
7242
|
+
import chalk21 from "chalk";
|
|
7076
7243
|
import ora4 from "ora";
|
|
7077
7244
|
|
|
7078
7245
|
// src/registry.ts
|
|
@@ -7228,33 +7395,33 @@ async function listAction() {
|
|
|
7228
7395
|
try {
|
|
7229
7396
|
const skills = await listRemoteSkills();
|
|
7230
7397
|
const installed = getInstalledSkillNames();
|
|
7231
|
-
spinner.succeed(
|
|
7398
|
+
spinner.succeed(chalk21.green(`Found ${skills.length} skill${skills.length !== 1 ? "s" : ""}`));
|
|
7232
7399
|
console.log("");
|
|
7233
7400
|
if (skills.length === 0) {
|
|
7234
|
-
console.log(
|
|
7401
|
+
console.log(chalk21.gray(" No skills available in registry."));
|
|
7235
7402
|
console.log("");
|
|
7236
7403
|
return;
|
|
7237
7404
|
}
|
|
7238
7405
|
for (const skill of skills) {
|
|
7239
|
-
const badge = installed.has(skill.name) ?
|
|
7240
|
-
const version = skill.version ?
|
|
7241
|
-
console.log(` ${
|
|
7406
|
+
const badge = installed.has(skill.name) ? chalk21.green(" [installed]") : "";
|
|
7407
|
+
const version = skill.version ? chalk21.gray(` v${skill.version}`) : "";
|
|
7408
|
+
console.log(` ${chalk21.bold.cyan(skill.name)}${version}${badge}`);
|
|
7242
7409
|
console.log(` ${skill.description}`);
|
|
7243
7410
|
if (skill.license) {
|
|
7244
|
-
console.log(` ${
|
|
7411
|
+
console.log(` ${chalk21.gray(`License: ${skill.license}`)}`);
|
|
7245
7412
|
}
|
|
7246
7413
|
console.log("");
|
|
7247
7414
|
}
|
|
7248
7415
|
} catch (err) {
|
|
7249
7416
|
const message = err instanceof Error ? err.message : String(err);
|
|
7250
|
-
spinner.fail(
|
|
7417
|
+
spinner.fail(chalk21.red(`Failed to fetch skills: ${message}`));
|
|
7251
7418
|
if (isDebug()) console.error(err instanceof Error ? err.stack : err);
|
|
7252
7419
|
process.exit(2);
|
|
7253
7420
|
}
|
|
7254
7421
|
}
|
|
7255
7422
|
async function addAction(name, options) {
|
|
7256
7423
|
if (!validateSkillName(name)) {
|
|
7257
|
-
console.log(
|
|
7424
|
+
console.log(chalk21.red.bold("Error:"), `Invalid skill name "${name}"`);
|
|
7258
7425
|
process.exit(1);
|
|
7259
7426
|
}
|
|
7260
7427
|
let targetBase;
|
|
@@ -7263,15 +7430,15 @@ async function addAction(name, options) {
|
|
|
7263
7430
|
} else {
|
|
7264
7431
|
const localSkillsDir = resolveSkillsDir("local");
|
|
7265
7432
|
if (!localSkillsDir) {
|
|
7266
|
-
console.log(
|
|
7267
|
-
console.log(
|
|
7433
|
+
console.log(chalk21.red.bold("Error:"), "No .reygent/ directory found.");
|
|
7434
|
+
console.log(chalk21.gray(" Run"), chalk21.cyan("reygent init"), chalk21.gray("first, or use"), chalk21.cyan("--global"));
|
|
7268
7435
|
process.exit(1);
|
|
7269
7436
|
}
|
|
7270
7437
|
targetBase = localSkillsDir;
|
|
7271
7438
|
}
|
|
7272
7439
|
const targetDir = join9(targetBase, name);
|
|
7273
7440
|
if (existsSync11(targetDir)) {
|
|
7274
|
-
console.log(
|
|
7441
|
+
console.log(chalk21.red.bold("Error:"), `Skill "${name}" already installed at ${targetDir}`);
|
|
7275
7442
|
process.exit(1);
|
|
7276
7443
|
}
|
|
7277
7444
|
const spinner = ora4(`Installing ${name}...`).start();
|
|
@@ -7282,9 +7449,9 @@ async function addAction(name, options) {
|
|
|
7282
7449
|
const compatible = checkCompatibility(manifest.compatibility, version);
|
|
7283
7450
|
if (!compatible) {
|
|
7284
7451
|
spinner.warn(
|
|
7285
|
-
|
|
7452
|
+
chalk21.yellow(`Skill "${name}" requires ${manifest.compatibility}, you have v${version}`)
|
|
7286
7453
|
);
|
|
7287
|
-
console.log(
|
|
7454
|
+
console.log(chalk21.yellow(" Installing anyway \u2014 some features may not work.\n"));
|
|
7288
7455
|
spinner.start(`Downloading ${name}...`);
|
|
7289
7456
|
}
|
|
7290
7457
|
spinner.text = `Downloading ${name}...`;
|
|
@@ -7296,21 +7463,21 @@ async function addAction(name, options) {
|
|
|
7296
7463
|
mkdirSync5(fileDir, { recursive: true });
|
|
7297
7464
|
writeFileSync3(filePath, file.content, "utf-8");
|
|
7298
7465
|
}
|
|
7299
|
-
spinner.succeed(
|
|
7466
|
+
spinner.succeed(chalk21.green(`Installed "${name}" (${files.length} files)`));
|
|
7300
7467
|
console.log("");
|
|
7301
|
-
console.log(
|
|
7302
|
-
console.log(
|
|
7468
|
+
console.log(chalk21.gray(" Location:"), chalk21.cyan(targetDir));
|
|
7469
|
+
console.log(chalk21.gray(" Usage: "), chalk21.cyan(`reygent agent ${name}`));
|
|
7303
7470
|
console.log("");
|
|
7304
7471
|
} catch (err) {
|
|
7305
7472
|
const message = err instanceof Error ? err.message : String(err);
|
|
7306
|
-
spinner.fail(
|
|
7473
|
+
spinner.fail(chalk21.red(`Failed to install "${name}": ${message}`));
|
|
7307
7474
|
if (isDebug()) console.error(err instanceof Error ? err.stack : err);
|
|
7308
7475
|
process.exit(2);
|
|
7309
7476
|
}
|
|
7310
7477
|
}
|
|
7311
7478
|
async function removeAction(name, options) {
|
|
7312
7479
|
if (!validateSkillName(name)) {
|
|
7313
|
-
console.log(
|
|
7480
|
+
console.log(chalk21.red.bold("Error:"), `Invalid skill name "${name}"`);
|
|
7314
7481
|
process.exit(1);
|
|
7315
7482
|
}
|
|
7316
7483
|
let targetBase;
|
|
@@ -7319,22 +7486,22 @@ async function removeAction(name, options) {
|
|
|
7319
7486
|
} else {
|
|
7320
7487
|
const localSkillsDir = resolveSkillsDir("local");
|
|
7321
7488
|
if (!localSkillsDir) {
|
|
7322
|
-
console.log(
|
|
7489
|
+
console.log(chalk21.red.bold("Error:"), "No .reygent/ directory found.");
|
|
7323
7490
|
process.exit(1);
|
|
7324
7491
|
}
|
|
7325
7492
|
targetBase = localSkillsDir;
|
|
7326
7493
|
}
|
|
7327
7494
|
const targetDir = join9(targetBase, name);
|
|
7328
7495
|
if (!existsSync11(targetDir)) {
|
|
7329
|
-
console.log(
|
|
7496
|
+
console.log(chalk21.red.bold("Error:"), `Skill "${name}" not found at ${targetDir}`);
|
|
7330
7497
|
process.exit(1);
|
|
7331
7498
|
}
|
|
7332
7499
|
try {
|
|
7333
7500
|
rmSync(targetDir, { recursive: true, force: true });
|
|
7334
|
-
console.log(
|
|
7501
|
+
console.log(chalk21.green(`Removed "${name}" from ${targetDir}`));
|
|
7335
7502
|
} catch (err) {
|
|
7336
7503
|
const message = err instanceof Error ? err.message : String(err);
|
|
7337
|
-
console.log(
|
|
7504
|
+
console.log(chalk21.red.bold("Error:"), `Failed to remove "${name}": ${message}`);
|
|
7338
7505
|
if (isDebug()) console.error(err instanceof Error ? err.stack : err);
|
|
7339
7506
|
process.exit(1);
|
|
7340
7507
|
}
|
|
@@ -7349,7 +7516,7 @@ function registerSkillsCommand(program2) {
|
|
|
7349
7516
|
// src/commands/review-work.ts
|
|
7350
7517
|
import { execFile as execFile3 } from "child_process";
|
|
7351
7518
|
import { request as httpsRequest2 } from "https";
|
|
7352
|
-
import
|
|
7519
|
+
import chalk22 from "chalk";
|
|
7353
7520
|
import ora5 from "ora";
|
|
7354
7521
|
|
|
7355
7522
|
// src/spec-prefix.ts
|
|
@@ -7702,7 +7869,7 @@ async function reviewWorkCommand(options) {
|
|
|
7702
7869
|
try {
|
|
7703
7870
|
await exec3("git", ["rev-parse", "--is-inside-work-tree"]);
|
|
7704
7871
|
} catch {
|
|
7705
|
-
console.log(
|
|
7872
|
+
console.log(chalk22.red.bold("Error:"), "Not inside a git repository.");
|
|
7706
7873
|
process.exit(1);
|
|
7707
7874
|
}
|
|
7708
7875
|
loadEnvFile();
|
|
@@ -7713,9 +7880,9 @@ async function reviewWorkCommand(options) {
|
|
|
7713
7880
|
const parsed = parseSpecWithPrefix(options.spec);
|
|
7714
7881
|
const loaded = await loadSpec(parsed.identifier, parsed.provider);
|
|
7715
7882
|
spec = { title: loaded.title, content: loaded.content };
|
|
7716
|
-
spinner.succeed(
|
|
7883
|
+
spinner.succeed(chalk22.green(`Spec loaded: ${loaded.title}`));
|
|
7717
7884
|
} catch (err) {
|
|
7718
|
-
spinner.fail(
|
|
7885
|
+
spinner.fail(chalk22.red("Failed to load spec"));
|
|
7719
7886
|
throw err;
|
|
7720
7887
|
}
|
|
7721
7888
|
}
|
|
@@ -7724,14 +7891,14 @@ async function reviewWorkCommand(options) {
|
|
|
7724
7891
|
const branch = await getCurrentBranch();
|
|
7725
7892
|
const defaultBranch = await getDefaultBranch();
|
|
7726
7893
|
console.log(
|
|
7727
|
-
|
|
7894
|
+
chalk22.gray(` Platform: ${remote.platform}`) + chalk22.gray(` | Branch: ${branch}`) + chalk22.gray(` | Base: ${defaultBranch}`)
|
|
7728
7895
|
);
|
|
7729
7896
|
console.log();
|
|
7730
7897
|
if (remote.platform === "github") {
|
|
7731
7898
|
const spinner = ora5("Checking for open PR...").start();
|
|
7732
7899
|
const prNumber = await detectGitHubPR();
|
|
7733
7900
|
if (prNumber !== null) {
|
|
7734
|
-
spinner.succeed(
|
|
7901
|
+
spinner.succeed(chalk22.green(`Found PR #${prNumber}`));
|
|
7735
7902
|
const context = {
|
|
7736
7903
|
spec: spec ? { source: "markdown", title: spec.title, content: spec.content } : { source: "markdown", title: "Review", content: "" },
|
|
7737
7904
|
prCreate: {
|
|
@@ -7745,19 +7912,19 @@ async function reviewWorkCommand(options) {
|
|
|
7745
7912
|
console.log();
|
|
7746
7913
|
const prReviewStatus = createLiveStatus("Running PR review...");
|
|
7747
7914
|
const { output } = await runPRReview(context, { quiet: true, onActivity: prReviewStatus.onActivity });
|
|
7748
|
-
prReviewStatus.succeed(
|
|
7915
|
+
prReviewStatus.succeed(chalk22.green("Review complete"));
|
|
7749
7916
|
console.log(formatPRReviewTerminal(output));
|
|
7750
7917
|
console.log();
|
|
7751
7918
|
const postSpinner = ora5("Posting review comment to PR...").start();
|
|
7752
7919
|
try {
|
|
7753
7920
|
await postPRReviewComment(context, output);
|
|
7754
|
-
postSpinner.succeed(
|
|
7921
|
+
postSpinner.succeed(chalk22.green(`Review posted to PR #${prNumber}`));
|
|
7755
7922
|
} catch (err) {
|
|
7756
7923
|
const msg = err instanceof Error ? err.message : String(err);
|
|
7757
|
-
postSpinner.fail(
|
|
7924
|
+
postSpinner.fail(chalk22.red(`Failed to post comment: ${msg}`));
|
|
7758
7925
|
}
|
|
7759
7926
|
} else {
|
|
7760
|
-
spinner.info(
|
|
7927
|
+
spinner.info(chalk22.yellow("No open PR found for this branch"));
|
|
7761
7928
|
console.log();
|
|
7762
7929
|
const reviewStatus = createLiveStatus("Running review...");
|
|
7763
7930
|
let output;
|
|
@@ -7766,15 +7933,15 @@ async function reviewWorkCommand(options) {
|
|
|
7766
7933
|
} catch (err) {
|
|
7767
7934
|
if (err instanceof TaskError && err.message.includes("no changes found")) {
|
|
7768
7935
|
reviewStatus.stop();
|
|
7769
|
-
console.log(
|
|
7936
|
+
console.log(chalk22.yellow("No changes found against"), chalk22.bold(defaultBranch));
|
|
7770
7937
|
return;
|
|
7771
7938
|
}
|
|
7772
7939
|
throw err;
|
|
7773
7940
|
}
|
|
7774
|
-
reviewStatus.succeed(
|
|
7941
|
+
reviewStatus.succeed(chalk22.green("Review complete"));
|
|
7775
7942
|
console.log(formatPRReviewTerminal(output));
|
|
7776
7943
|
console.log();
|
|
7777
|
-
console.log(
|
|
7944
|
+
console.log(chalk22.gray("No PR found \u2014 review printed to console only."));
|
|
7778
7945
|
}
|
|
7779
7946
|
} else {
|
|
7780
7947
|
const spinner = ora5("Checking for open MR...").start();
|
|
@@ -7784,16 +7951,16 @@ async function reviewWorkCommand(options) {
|
|
|
7784
7951
|
} catch (err) {
|
|
7785
7952
|
if (isDebug()) {
|
|
7786
7953
|
const msg = err instanceof Error ? err.message : String(err);
|
|
7787
|
-
console.error(
|
|
7954
|
+
console.error(chalk22.gray(`[debug] Token resolution failed: ${msg}`));
|
|
7788
7955
|
}
|
|
7789
|
-
spinner.info(
|
|
7956
|
+
spinner.info(chalk22.yellow("Could not resolve GitLab token \u2014 skipping MR detection"));
|
|
7790
7957
|
token = "";
|
|
7791
7958
|
}
|
|
7792
7959
|
const mrIid = token ? await detectGitLabMR(remote, token, branch, options.insecure) : null;
|
|
7793
7960
|
if (mrIid !== null) {
|
|
7794
|
-
spinner.succeed(
|
|
7961
|
+
spinner.succeed(chalk22.green(`Found MR !${mrIid}`));
|
|
7795
7962
|
} else {
|
|
7796
|
-
spinner.info(
|
|
7963
|
+
spinner.info(chalk22.yellow("No open MR found for this branch"));
|
|
7797
7964
|
}
|
|
7798
7965
|
console.log();
|
|
7799
7966
|
const glReviewStatus = createLiveStatus("Running review...");
|
|
@@ -7803,12 +7970,12 @@ async function reviewWorkCommand(options) {
|
|
|
7803
7970
|
} catch (err) {
|
|
7804
7971
|
if (err instanceof TaskError && err.message.includes("no changes found")) {
|
|
7805
7972
|
glReviewStatus.stop();
|
|
7806
|
-
console.log(
|
|
7973
|
+
console.log(chalk22.yellow("No changes found against"), chalk22.bold(defaultBranch));
|
|
7807
7974
|
return;
|
|
7808
7975
|
}
|
|
7809
7976
|
throw err;
|
|
7810
7977
|
}
|
|
7811
|
-
glReviewStatus.succeed(
|
|
7978
|
+
glReviewStatus.succeed(chalk22.green("Review complete"));
|
|
7812
7979
|
console.log(formatPRReviewTerminal(output));
|
|
7813
7980
|
console.log();
|
|
7814
7981
|
if (mrIid !== null && token) {
|
|
@@ -7816,13 +7983,13 @@ async function reviewWorkCommand(options) {
|
|
|
7816
7983
|
try {
|
|
7817
7984
|
const body = formatPRReviewOutput(output) + "\n\n---\n*Review by [reygent](https://github.com/andrewevans0102/reygent)*";
|
|
7818
7985
|
await postGitLabComment(remote, token, mrIid, body, options.insecure);
|
|
7819
|
-
postSpinner.succeed(
|
|
7986
|
+
postSpinner.succeed(chalk22.green(`Review posted to MR !${mrIid}`));
|
|
7820
7987
|
} catch (err) {
|
|
7821
7988
|
const msg = err instanceof Error ? err.message : String(err);
|
|
7822
|
-
postSpinner.fail(
|
|
7989
|
+
postSpinner.fail(chalk22.red(`Failed to post comment: ${msg}`));
|
|
7823
7990
|
}
|
|
7824
7991
|
} else {
|
|
7825
|
-
console.log(
|
|
7992
|
+
console.log(chalk22.gray("No MR found \u2014 review printed to console only."));
|
|
7826
7993
|
}
|
|
7827
7994
|
}
|
|
7828
7995
|
} catch (err) {
|
|
@@ -7830,12 +7997,12 @@ async function reviewWorkCommand(options) {
|
|
|
7830
7997
|
process.exit(0);
|
|
7831
7998
|
}
|
|
7832
7999
|
if (err instanceof SpecError || err instanceof SpecPrefixError || err instanceof TaskError) {
|
|
7833
|
-
console.log(
|
|
8000
|
+
console.log(chalk22.red.bold("Error:"), err.message);
|
|
7834
8001
|
if (isDebug()) console.error(err.stack);
|
|
7835
8002
|
process.exit(1);
|
|
7836
8003
|
}
|
|
7837
8004
|
const message = err instanceof Error ? err.message : String(err);
|
|
7838
|
-
console.log(
|
|
8005
|
+
console.log(chalk22.red.bold("Internal error:"), message);
|
|
7839
8006
|
if (isDebug()) console.error(err instanceof Error ? err.stack : err);
|
|
7840
8007
|
process.exit(2);
|
|
7841
8008
|
}
|
|
@@ -7844,7 +8011,7 @@ async function reviewWorkCommand(options) {
|
|
|
7844
8011
|
// src/commands/review-comments.ts
|
|
7845
8012
|
import { execFile as execFile4 } from "child_process";
|
|
7846
8013
|
import { request as httpsRequest3 } from "https";
|
|
7847
|
-
import
|
|
8014
|
+
import chalk23 from "chalk";
|
|
7848
8015
|
import { select as select5 } from "@inquirer/prompts";
|
|
7849
8016
|
var PRIMARY_SECURITY_KEYWORDS = [
|
|
7850
8017
|
"xss",
|
|
@@ -8113,21 +8280,21 @@ async function fetchGitLabComments(remote, token, mrIid, insecure) {
|
|
|
8113
8280
|
function displayCommentSummary(comments) {
|
|
8114
8281
|
const securityCount = comments.filter((c) => c.isSecurity).length;
|
|
8115
8282
|
const generalCount = comments.length - securityCount;
|
|
8116
|
-
console.log(
|
|
8283
|
+
console.log(chalk23.bold(` ${comments.length} review comment(s) found`));
|
|
8117
8284
|
if (securityCount > 0) {
|
|
8118
8285
|
console.log(
|
|
8119
|
-
|
|
8286
|
+
chalk23.yellow(` \u26A0 ${securityCount} security-related`) + chalk23.gray(` | ${generalCount} general`)
|
|
8120
8287
|
);
|
|
8121
8288
|
}
|
|
8122
8289
|
console.log();
|
|
8123
8290
|
for (const c of comments) {
|
|
8124
|
-
const location = c.path ?
|
|
8125
|
-
const tag = c.isSecurity ?
|
|
8126
|
-
console.log(` ${tag}${
|
|
8291
|
+
const location = c.path ? chalk23.cyan(` ${c.path}${c.line ? `:${c.line}` : ""}`) : chalk23.gray(" (general)");
|
|
8292
|
+
const tag = c.isSecurity ? chalk23.bgYellow.black(" SEC ") + " " : "";
|
|
8293
|
+
console.log(` ${tag}${chalk23.bold(c.author)} ${location}`);
|
|
8127
8294
|
const cols = process.stdout.columns || 80;
|
|
8128
8295
|
const preview = c.body.length > 200 ? c.body.slice(0, 200) + "..." : c.body;
|
|
8129
8296
|
for (const line of preview.split("\n")) {
|
|
8130
|
-
console.log(
|
|
8297
|
+
console.log(chalk23.gray(` ${wrapText(line, 4, cols)}`));
|
|
8131
8298
|
}
|
|
8132
8299
|
console.log();
|
|
8133
8300
|
}
|
|
@@ -8253,23 +8420,23 @@ async function generatePlan(comments, includedDiffs, excludedFiles, feedback) {
|
|
|
8253
8420
|
}
|
|
8254
8421
|
function displayPlan(plan) {
|
|
8255
8422
|
const cols = process.stdout.columns || 80;
|
|
8256
|
-
console.log(
|
|
8257
|
-
console.log(
|
|
8423
|
+
console.log(chalk23.bold("\n Plan to Address Review Comments\n"));
|
|
8424
|
+
console.log(chalk23.bold.blue(" Goals:"));
|
|
8258
8425
|
for (const g of plan.goals) {
|
|
8259
8426
|
console.log(` - ${wrapText(g, 6, cols)}`);
|
|
8260
8427
|
}
|
|
8261
8428
|
console.log();
|
|
8262
|
-
console.log(
|
|
8429
|
+
console.log(chalk23.bold.blue(" Tasks:"));
|
|
8263
8430
|
for (const t of plan.tasks) {
|
|
8264
8431
|
console.log(` - ${wrapText(t, 6, cols)}`);
|
|
8265
8432
|
}
|
|
8266
8433
|
console.log();
|
|
8267
|
-
console.log(
|
|
8434
|
+
console.log(chalk23.bold.blue(" Constraints:"));
|
|
8268
8435
|
for (const c of plan.constraints) {
|
|
8269
8436
|
console.log(` - ${wrapText(c, 6, cols)}`);
|
|
8270
8437
|
}
|
|
8271
8438
|
console.log();
|
|
8272
|
-
console.log(
|
|
8439
|
+
console.log(chalk23.bold.blue(" Definition of Done:"));
|
|
8273
8440
|
for (const d of plan.dod) {
|
|
8274
8441
|
console.log(` - ${wrapText(d, 6, cols)}`);
|
|
8275
8442
|
}
|
|
@@ -8336,9 +8503,9 @@ async function executeWithDevAgent(comments, plan, autoApprove, onActivity, user
|
|
|
8336
8503
|
const parsed = JSON.parse(extractJSON(result.stdout));
|
|
8337
8504
|
if (parsed.files && parsed.files.length > 0) {
|
|
8338
8505
|
console.log();
|
|
8339
|
-
console.log(
|
|
8506
|
+
console.log(chalk23.bold(" Files modified:"));
|
|
8340
8507
|
for (const f of parsed.files) {
|
|
8341
|
-
console.log(` - ${
|
|
8508
|
+
console.log(` - ${chalk23.cyan(f)}`);
|
|
8342
8509
|
}
|
|
8343
8510
|
}
|
|
8344
8511
|
} catch {
|
|
@@ -8350,7 +8517,7 @@ async function reviewCommentsCommand(options) {
|
|
|
8350
8517
|
try {
|
|
8351
8518
|
await exec4("git", ["rev-parse", "--is-inside-work-tree"]);
|
|
8352
8519
|
} catch {
|
|
8353
|
-
console.log(
|
|
8520
|
+
console.log(chalk23.red.bold("Error:"), "Not inside a git repository.");
|
|
8354
8521
|
process.exit(1);
|
|
8355
8522
|
}
|
|
8356
8523
|
loadEnvFile();
|
|
@@ -8359,7 +8526,7 @@ async function reviewCommentsCommand(options) {
|
|
|
8359
8526
|
const branch = await getCurrentBranch2();
|
|
8360
8527
|
const defaultBranch = await getDefaultBranch2();
|
|
8361
8528
|
console.log(
|
|
8362
|
-
|
|
8529
|
+
chalk23.gray(` Platform: ${remote.platform}`) + chalk23.gray(` | Branch: ${branch}`) + chalk23.gray(` | Base: ${defaultBranch}`)
|
|
8363
8530
|
);
|
|
8364
8531
|
console.log();
|
|
8365
8532
|
let comments = [];
|
|
@@ -8367,20 +8534,20 @@ async function reviewCommentsCommand(options) {
|
|
|
8367
8534
|
const spinner = createLiveStatus("checking for open PR...");
|
|
8368
8535
|
const prNumber = await detectGitHubPR2();
|
|
8369
8536
|
if (prNumber === null) {
|
|
8370
|
-
spinner.fail(
|
|
8537
|
+
spinner.fail(chalk23.red("No open PR found for this branch"));
|
|
8371
8538
|
console.log();
|
|
8372
|
-
console.log(
|
|
8539
|
+
console.log(chalk23.yellow("Cannot pull review comments without a PR or MR."));
|
|
8373
8540
|
process.exit(1);
|
|
8374
8541
|
}
|
|
8375
|
-
spinner.succeed(
|
|
8542
|
+
spinner.succeed(chalk23.green(`Found PR #${prNumber}`));
|
|
8376
8543
|
console.log();
|
|
8377
8544
|
const commentSpinner = createLiveStatus("fetching review comments...");
|
|
8378
8545
|
comments = await fetchGitHubComments();
|
|
8379
8546
|
if (comments.length === 0) {
|
|
8380
|
-
commentSpinner.info(
|
|
8547
|
+
commentSpinner.info(chalk23.yellow("No review comments found on this PR"));
|
|
8381
8548
|
return;
|
|
8382
8549
|
}
|
|
8383
|
-
commentSpinner.succeed(
|
|
8550
|
+
commentSpinner.succeed(chalk23.green(`Fetched ${comments.length} comment(s)`));
|
|
8384
8551
|
} else {
|
|
8385
8552
|
const spinner = createLiveStatus("checking for open MR...");
|
|
8386
8553
|
let token;
|
|
@@ -8389,29 +8556,29 @@ async function reviewCommentsCommand(options) {
|
|
|
8389
8556
|
} catch (err) {
|
|
8390
8557
|
if (isDebug()) {
|
|
8391
8558
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8392
|
-
console.error(
|
|
8559
|
+
console.error(chalk23.gray(`[debug] Token resolution failed: ${msg}`));
|
|
8393
8560
|
}
|
|
8394
|
-
spinner.fail(
|
|
8561
|
+
spinner.fail(chalk23.red("Could not resolve GitLab token"));
|
|
8395
8562
|
console.log();
|
|
8396
|
-
console.log(
|
|
8563
|
+
console.log(chalk23.yellow("Cannot pull review comments without a PR or MR."));
|
|
8397
8564
|
process.exit(1);
|
|
8398
8565
|
}
|
|
8399
8566
|
const mrIid = await detectGitLabMR2(remote, token, branch, options.insecure);
|
|
8400
8567
|
if (mrIid === null) {
|
|
8401
|
-
spinner.fail(
|
|
8568
|
+
spinner.fail(chalk23.red("No open MR found for this branch"));
|
|
8402
8569
|
console.log();
|
|
8403
|
-
console.log(
|
|
8570
|
+
console.log(chalk23.yellow("Cannot pull review comments without a PR or MR."));
|
|
8404
8571
|
process.exit(1);
|
|
8405
8572
|
}
|
|
8406
|
-
spinner.succeed(
|
|
8573
|
+
spinner.succeed(chalk23.green(`Found MR !${mrIid}`));
|
|
8407
8574
|
console.log();
|
|
8408
8575
|
const commentSpinner = createLiveStatus("fetching review comments...");
|
|
8409
8576
|
comments = await fetchGitLabComments(remote, token, mrIid, options.insecure);
|
|
8410
8577
|
if (comments.length === 0) {
|
|
8411
|
-
commentSpinner.info(
|
|
8578
|
+
commentSpinner.info(chalk23.yellow("No review comments found on this MR"));
|
|
8412
8579
|
return;
|
|
8413
8580
|
}
|
|
8414
|
-
commentSpinner.succeed(
|
|
8581
|
+
commentSpinner.succeed(chalk23.green(`Fetched ${comments.length} comment(s)`));
|
|
8415
8582
|
}
|
|
8416
8583
|
const classified = classifyComments(comments);
|
|
8417
8584
|
console.log();
|
|
@@ -8421,7 +8588,7 @@ async function reviewCommentsCommand(options) {
|
|
|
8421
8588
|
let includedDiffs = [];
|
|
8422
8589
|
let excludedFiles = [];
|
|
8423
8590
|
if (!rawDiff.trim()) {
|
|
8424
|
-
diffSpinner.warn(
|
|
8591
|
+
diffSpinner.warn(chalk23.yellow("No diff found against base branch"));
|
|
8425
8592
|
} else {
|
|
8426
8593
|
const fileDiffs = splitDiffByFile(rawDiff);
|
|
8427
8594
|
const reservedTokens = estimateTokens(formatCommentBlock(classified)) + RESERVED_PROMPT_TOKENS;
|
|
@@ -8451,16 +8618,16 @@ async function reviewCommentsCommand(options) {
|
|
|
8451
8618
|
}
|
|
8452
8619
|
}
|
|
8453
8620
|
if (excludedFiles.length > 0) {
|
|
8454
|
-
diffSpinner.succeed(
|
|
8621
|
+
diffSpinner.succeed(chalk23.green(`Diff loaded (${includedDiffs.length} files included, ${excludedFiles.length} excluded for size)`));
|
|
8455
8622
|
} else {
|
|
8456
|
-
diffSpinner.succeed(
|
|
8623
|
+
diffSpinner.succeed(chalk23.green("Diff loaded"));
|
|
8457
8624
|
}
|
|
8458
8625
|
}
|
|
8459
8626
|
let plan;
|
|
8460
8627
|
{
|
|
8461
8628
|
const planSpinner = createLiveStatus("generating plan...");
|
|
8462
8629
|
plan = await generatePlan(classified, includedDiffs, excludedFiles);
|
|
8463
|
-
planSpinner.succeed(
|
|
8630
|
+
planSpinner.succeed(chalk23.green("Plan generated"));
|
|
8464
8631
|
}
|
|
8465
8632
|
displayPlan(plan);
|
|
8466
8633
|
let userInstructions;
|
|
@@ -8487,7 +8654,7 @@ async function reviewCommentsCommand(options) {
|
|
|
8487
8654
|
if (feedback.trim()) {
|
|
8488
8655
|
const planSpinner = createLiveStatus("regenerating plan...");
|
|
8489
8656
|
plan = await generatePlan(classified, includedDiffs, excludedFiles, feedback);
|
|
8490
|
-
planSpinner.succeed(
|
|
8657
|
+
planSpinner.succeed(chalk23.green("Plan regenerated"));
|
|
8491
8658
|
displayPlan(plan);
|
|
8492
8659
|
}
|
|
8493
8660
|
} else if (action === "instructions") {
|
|
@@ -8499,14 +8666,14 @@ async function reviewCommentsCommand(options) {
|
|
|
8499
8666
|
userInstructions = userInstructions ? `${userInstructions}
|
|
8500
8667
|
|
|
8501
8668
|
${extra.trim()}` : extra.trim();
|
|
8502
|
-
console.log(
|
|
8669
|
+
console.log(chalk23.green(" Instructions saved. They will be included when executing."));
|
|
8503
8670
|
const displayText = userInstructions.length > 200 ? userInstructions.slice(0, 200) + "..." : userInstructions;
|
|
8504
|
-
console.log(
|
|
8671
|
+
console.log(chalk23.gray(` Current instructions:
|
|
8505
8672
|
${displayText.split("\n").join("\n ")}`));
|
|
8506
8673
|
console.log();
|
|
8507
8674
|
}
|
|
8508
8675
|
} else {
|
|
8509
|
-
console.log(
|
|
8676
|
+
console.log(chalk23.yellow("\n Rejected. No changes made.\n"));
|
|
8510
8677
|
return;
|
|
8511
8678
|
}
|
|
8512
8679
|
}
|
|
@@ -8514,25 +8681,19 @@ ${extra.trim()}` : extra.trim();
|
|
|
8514
8681
|
console.log();
|
|
8515
8682
|
const execStatus = createLiveStatus("addressing review comments...");
|
|
8516
8683
|
await executeWithDevAgent(classified, plan, true, execStatus.onActivity, userInstructions);
|
|
8517
|
-
execStatus.succeed(
|
|
8684
|
+
execStatus.succeed(chalk23.green("Dev agent finished"));
|
|
8518
8685
|
console.log();
|
|
8519
8686
|
const pushSpinner = createLiveStatus("committing and pushing...");
|
|
8520
8687
|
const trace = getChesstrace();
|
|
8688
|
+
const commitMessage = "fix: address PR review comments";
|
|
8689
|
+
const maxRetries = options.retryCommits ?? 3;
|
|
8690
|
+
let committed = false;
|
|
8521
8691
|
try {
|
|
8522
8692
|
await exec4("git", ["add", "-A"]);
|
|
8523
|
-
await exec4("git", ["commit", "-m",
|
|
8524
|
-
|
|
8525
|
-
|
|
8526
|
-
|
|
8527
|
-
}
|
|
8528
|
-
await exec4("git", ["push", "origin", branch]);
|
|
8529
|
-
try {
|
|
8530
|
-
trace.emit(Events.GIT_PUSH, { branch });
|
|
8531
|
-
} catch {
|
|
8532
|
-
}
|
|
8533
|
-
pushSpinner.succeed(chalk22.green("Changes committed and pushed."));
|
|
8534
|
-
} catch (pushErr) {
|
|
8535
|
-
const msg = pushErr instanceof Error ? pushErr.message : String(pushErr);
|
|
8693
|
+
await exec4("git", ["commit", "-m", commitMessage]);
|
|
8694
|
+
committed = true;
|
|
8695
|
+
} catch (commitErr) {
|
|
8696
|
+
const msg = commitErr instanceof Error ? commitErr.message : String(commitErr);
|
|
8536
8697
|
if (msg.includes("nothing to commit")) {
|
|
8537
8698
|
try {
|
|
8538
8699
|
const ahead = await exec4("git", [
|
|
@@ -8546,35 +8707,71 @@ ${extra.trim()}` : extra.trim();
|
|
|
8546
8707
|
trace.emit(Events.GIT_PUSH, { branch });
|
|
8547
8708
|
} catch {
|
|
8548
8709
|
}
|
|
8549
|
-
pushSpinner.succeed(
|
|
8710
|
+
pushSpinner.succeed(chalk23.green("Changes pushed."));
|
|
8550
8711
|
} else {
|
|
8551
|
-
pushSpinner.warn(
|
|
8712
|
+
pushSpinner.warn(chalk23.yellow("No changes were made by the dev agent."));
|
|
8552
8713
|
}
|
|
8553
8714
|
} catch {
|
|
8554
|
-
pushSpinner.warn(
|
|
8715
|
+
pushSpinner.warn(chalk23.yellow("Nothing to commit or push."));
|
|
8555
8716
|
}
|
|
8556
8717
|
} else {
|
|
8718
|
+
let retryCount = 0;
|
|
8719
|
+
while (retryCount < maxRetries) {
|
|
8720
|
+
retryCount++;
|
|
8721
|
+
pushSpinner.text = `pre-commit hook failed, re-staging and retrying (${retryCount}/${maxRetries})...`;
|
|
8722
|
+
try {
|
|
8723
|
+
await exec4("git", ["add", "-A"]);
|
|
8724
|
+
await exec4("git", ["commit", "-m", commitMessage]);
|
|
8725
|
+
committed = true;
|
|
8726
|
+
break;
|
|
8727
|
+
} catch (retryErr) {
|
|
8728
|
+
const retryMsg = retryErr instanceof Error ? retryErr.message : String(retryErr);
|
|
8729
|
+
if (retryCount >= maxRetries) {
|
|
8730
|
+
try {
|
|
8731
|
+
trace.emit(Events.GIT_ERROR, { operation: "commit", error: retryMsg, retriesExhausted: maxRetries });
|
|
8732
|
+
} catch {
|
|
8733
|
+
}
|
|
8734
|
+
pushSpinner.fail(chalk23.red(`Commit failed after ${maxRetries} retries: ${retryMsg}`));
|
|
8735
|
+
}
|
|
8736
|
+
}
|
|
8737
|
+
}
|
|
8738
|
+
}
|
|
8739
|
+
}
|
|
8740
|
+
if (committed) {
|
|
8741
|
+
try {
|
|
8742
|
+
trace.emit(Events.GIT_COMMIT, { branch, messageSubject: commitMessage });
|
|
8743
|
+
} catch {
|
|
8744
|
+
}
|
|
8745
|
+
try {
|
|
8746
|
+
await exec4("git", ["push", "origin", branch]);
|
|
8747
|
+
try {
|
|
8748
|
+
trace.emit(Events.GIT_PUSH, { branch });
|
|
8749
|
+
} catch {
|
|
8750
|
+
}
|
|
8751
|
+
pushSpinner.succeed(chalk23.green("Changes committed and pushed."));
|
|
8752
|
+
} catch (pushErr) {
|
|
8753
|
+
const pushMsg = pushErr instanceof Error ? pushErr.message : String(pushErr);
|
|
8557
8754
|
try {
|
|
8558
|
-
trace.emit(Events.GIT_ERROR, { operation: "
|
|
8755
|
+
trace.emit(Events.GIT_ERROR, { operation: "push", error: pushMsg });
|
|
8559
8756
|
} catch {
|
|
8560
8757
|
}
|
|
8561
|
-
pushSpinner.fail(
|
|
8758
|
+
pushSpinner.fail(chalk23.red(`Push failed: ${pushMsg}`));
|
|
8562
8759
|
}
|
|
8563
8760
|
}
|
|
8564
8761
|
console.log();
|
|
8565
|
-
console.log(
|
|
8762
|
+
console.log(chalk23.green.bold(" Done!"), chalk23.gray("Review comments addressed."));
|
|
8566
8763
|
console.log();
|
|
8567
8764
|
} catch (err) {
|
|
8568
8765
|
if (err instanceof Error && err.name === "ExitPromptError") {
|
|
8569
8766
|
process.exit(0);
|
|
8570
8767
|
}
|
|
8571
8768
|
if (err instanceof TaskError) {
|
|
8572
|
-
console.log(
|
|
8769
|
+
console.log(chalk23.red.bold("Error:"), err.message);
|
|
8573
8770
|
if (isDebug()) console.error(err.stack);
|
|
8574
8771
|
process.exit(1);
|
|
8575
8772
|
}
|
|
8576
8773
|
const message = err instanceof Error ? err.message : String(err);
|
|
8577
|
-
console.log(
|
|
8774
|
+
console.log(chalk23.red.bold("Internal error:"), message);
|
|
8578
8775
|
if (isDebug()) console.error(err instanceof Error ? err.stack : err);
|
|
8579
8776
|
process.exit(2);
|
|
8580
8777
|
}
|
|
@@ -8585,22 +8782,22 @@ ${extra.trim()}` : extra.trim();
|
|
|
8585
8782
|
import { existsSync as existsSync12, readFileSync as readFileSync9, writeFileSync as writeFileSync4, mkdirSync as mkdirSync6, lstatSync, renameSync, unlinkSync } from "fs";
|
|
8586
8783
|
import { join as join10, dirname as dirname5 } from "path";
|
|
8587
8784
|
import { randomBytes } from "crypto";
|
|
8588
|
-
import
|
|
8785
|
+
import chalk24 from "chalk";
|
|
8589
8786
|
import { select as select6, confirm } from "@inquirer/prompts";
|
|
8590
8787
|
var AGENT_CATEGORIES = [
|
|
8591
8788
|
{
|
|
8592
8789
|
label: "Development",
|
|
8593
|
-
color:
|
|
8790
|
+
color: chalk24.blue,
|
|
8594
8791
|
roles: ["developer", "general"]
|
|
8595
8792
|
},
|
|
8596
8793
|
{
|
|
8597
8794
|
label: "Testing & Review",
|
|
8598
|
-
color:
|
|
8795
|
+
color: chalk24.magenta,
|
|
8599
8796
|
roles: ["quality-engineer", "security-reviewer", "reviewer"]
|
|
8600
8797
|
},
|
|
8601
8798
|
{
|
|
8602
8799
|
label: "Planning",
|
|
8603
|
-
color:
|
|
8800
|
+
color: chalk24.yellow,
|
|
8604
8801
|
roles: ["planner"]
|
|
8605
8802
|
}
|
|
8606
8803
|
];
|
|
@@ -8631,7 +8828,7 @@ function categorizeAgents(agents) {
|
|
|
8631
8828
|
if (remaining.length > 0) {
|
|
8632
8829
|
groups.push({
|
|
8633
8830
|
label: "Other",
|
|
8634
|
-
color:
|
|
8831
|
+
color: chalk24.gray,
|
|
8635
8832
|
agentIndices: remaining
|
|
8636
8833
|
});
|
|
8637
8834
|
}
|
|
@@ -8639,14 +8836,14 @@ function categorizeAgents(agents) {
|
|
|
8639
8836
|
}
|
|
8640
8837
|
function roleBadge(role) {
|
|
8641
8838
|
const badges = {
|
|
8642
|
-
"developer":
|
|
8643
|
-
"general":
|
|
8644
|
-
"quality-engineer":
|
|
8645
|
-
"security-reviewer":
|
|
8646
|
-
"reviewer":
|
|
8647
|
-
"planner":
|
|
8839
|
+
"developer": chalk24.bgBlue.white,
|
|
8840
|
+
"general": chalk24.bgBlue.white,
|
|
8841
|
+
"quality-engineer": chalk24.bgMagenta.white,
|
|
8842
|
+
"security-reviewer": chalk24.bgRed.white,
|
|
8843
|
+
"reviewer": chalk24.bgMagenta.white,
|
|
8844
|
+
"planner": chalk24.bgYellow.black
|
|
8648
8845
|
};
|
|
8649
|
-
const colorFn = badges[role] ??
|
|
8846
|
+
const colorFn = badges[role] ?? chalk24.bgGray.white;
|
|
8650
8847
|
return colorFn(` ${role} `);
|
|
8651
8848
|
}
|
|
8652
8849
|
async function configCommand() {
|
|
@@ -8654,7 +8851,7 @@ async function configCommand() {
|
|
|
8654
8851
|
await runConfig();
|
|
8655
8852
|
} catch (err) {
|
|
8656
8853
|
if (err && typeof err === "object" && "name" in err && err.name === "ExitPromptError") {
|
|
8657
|
-
console.log(
|
|
8854
|
+
console.log(chalk24.yellow("\nConfiguration cancelled."));
|
|
8658
8855
|
process.exit(0);
|
|
8659
8856
|
}
|
|
8660
8857
|
throw err;
|
|
@@ -8662,23 +8859,23 @@ async function configCommand() {
|
|
|
8662
8859
|
}
|
|
8663
8860
|
async function runConfig() {
|
|
8664
8861
|
if (!process.stdin.isTTY) {
|
|
8665
|
-
console.log(
|
|
8666
|
-
console.log(
|
|
8862
|
+
console.log(chalk24.red.bold("Error:"), "config command requires interactive mode.");
|
|
8863
|
+
console.log(chalk24.gray(" Edit"), chalk24.cyan(".reygent/config.json"), chalk24.gray("or"), chalk24.cyan("~/.reygent/config.json"), chalk24.gray("directly."));
|
|
8667
8864
|
process.exit(1);
|
|
8668
8865
|
}
|
|
8669
8866
|
const scope = await select6({
|
|
8670
8867
|
message: "Configuration scope:",
|
|
8671
8868
|
choices: [
|
|
8672
|
-
{ name: `Local ${
|
|
8673
|
-
{ name: `Global ${
|
|
8869
|
+
{ name: `Local ${chalk24.gray("\u2014 .reygent/config.json (this project)")}`, value: "local" },
|
|
8870
|
+
{ name: `Global ${chalk24.gray("\u2014 ~/.reygent/config.json (all projects)")}`, value: "global" }
|
|
8674
8871
|
]
|
|
8675
8872
|
});
|
|
8676
8873
|
let configPath;
|
|
8677
8874
|
if (scope === "local") {
|
|
8678
8875
|
const configDir = findLocalConfigDir(process.cwd());
|
|
8679
8876
|
if (!configDir) {
|
|
8680
|
-
console.log(
|
|
8681
|
-
console.log(
|
|
8877
|
+
console.log(chalk24.red.bold("Error:"), "No .reygent/ directory found.");
|
|
8878
|
+
console.log(chalk24.gray(" Run"), chalk24.cyan("reygent init"), chalk24.gray("first."));
|
|
8682
8879
|
console.log("");
|
|
8683
8880
|
process.exit(1);
|
|
8684
8881
|
}
|
|
@@ -8696,15 +8893,15 @@ async function runConfig() {
|
|
|
8696
8893
|
rawConfig = JSON.parse(content);
|
|
8697
8894
|
} catch (err) {
|
|
8698
8895
|
if (err instanceof SyntaxError) {
|
|
8699
|
-
console.log(
|
|
8700
|
-
console.log(
|
|
8896
|
+
console.log(chalk24.red.bold("Error:"), `Invalid JSON in ${configPath}`);
|
|
8897
|
+
console.log(chalk24.gray(" Parse error:"), err.message);
|
|
8701
8898
|
process.exit(2);
|
|
8702
8899
|
}
|
|
8703
8900
|
if (err && typeof err === "object" && "code" in err && err.code === "EACCES") {
|
|
8704
|
-
console.log(
|
|
8901
|
+
console.log(chalk24.red.bold("Error:"), `Permission denied: ${configPath}`);
|
|
8705
8902
|
process.exit(2);
|
|
8706
8903
|
}
|
|
8707
|
-
console.log(
|
|
8904
|
+
console.log(chalk24.red.bold("Error:"), `Failed to read ${configPath}`);
|
|
8708
8905
|
if (isDebug()) console.error(err);
|
|
8709
8906
|
process.exit(2);
|
|
8710
8907
|
}
|
|
@@ -8723,15 +8920,15 @@ async function runConfig() {
|
|
|
8723
8920
|
}
|
|
8724
8921
|
const currentProvider = rawConfig.provider ?? "(not set)";
|
|
8725
8922
|
const currentModel = rawConfig.model ?? "(not set)";
|
|
8726
|
-
console.log(
|
|
8727
|
-
console.log(
|
|
8728
|
-
console.log(
|
|
8729
|
-
console.log(
|
|
8923
|
+
console.log(chalk24.bold("Current config:"));
|
|
8924
|
+
console.log(chalk24.gray(" Scope: "), chalk24.cyan(scope));
|
|
8925
|
+
console.log(chalk24.gray(" Provider:"), chalk24.cyan(currentProvider));
|
|
8926
|
+
console.log(chalk24.gray(" Model: "), chalk24.cyan(currentModel));
|
|
8730
8927
|
console.log("");
|
|
8731
8928
|
const providerChoices = PROVIDER_NAMES.map((name) => {
|
|
8732
8929
|
const status = availability[name];
|
|
8733
|
-
const badge = status?.available ?
|
|
8734
|
-
const hint = !status?.available && status?.reason ?
|
|
8930
|
+
const badge = status?.available ? chalk24.green("\u2713") : chalk24.red("\u2717");
|
|
8931
|
+
const hint = !status?.available && status?.reason ? chalk24.gray(` \u2014 ${status.reason}`) : "";
|
|
8735
8932
|
return {
|
|
8736
8933
|
name: `${badge} ${name}${hint}`,
|
|
8737
8934
|
value: name
|
|
@@ -8745,14 +8942,14 @@ async function runConfig() {
|
|
|
8745
8942
|
});
|
|
8746
8943
|
if (!availability[selectedProvider]?.available) {
|
|
8747
8944
|
const reason = availability[selectedProvider]?.reason ?? "unknown reason";
|
|
8748
|
-
console.log(
|
|
8945
|
+
console.log(chalk24.yellow("\u26A0"), chalk24.yellow(`Provider ${selectedProvider} is unavailable (${reason})`));
|
|
8749
8946
|
resetTerminalForInput();
|
|
8750
8947
|
const proceed = await confirm({
|
|
8751
8948
|
message: "Continue with this provider anyway?",
|
|
8752
8949
|
default: false
|
|
8753
8950
|
});
|
|
8754
8951
|
if (!proceed) {
|
|
8755
|
-
console.log(
|
|
8952
|
+
console.log(chalk24.yellow("\nConfiguration cancelled."));
|
|
8756
8953
|
process.exit(0);
|
|
8757
8954
|
}
|
|
8758
8955
|
}
|
|
@@ -8770,30 +8967,59 @@ async function runConfig() {
|
|
|
8770
8967
|
name: `${m.id} \u2014 ${m.label}`,
|
|
8771
8968
|
value: m.id
|
|
8772
8969
|
}));
|
|
8773
|
-
|
|
8970
|
+
modelChoices.push({
|
|
8971
|
+
name: chalk24.gray("Custom model (enter manually)"),
|
|
8972
|
+
value: "__custom__"
|
|
8973
|
+
});
|
|
8974
|
+
const modelSelection = await select6({
|
|
8774
8975
|
message: "Default model:",
|
|
8775
8976
|
choices: modelChoices,
|
|
8776
8977
|
default: rawConfig.model ?? provider.defaultModel
|
|
8777
8978
|
});
|
|
8979
|
+
if (modelSelection === "__custom__") {
|
|
8980
|
+
resetTerminalForInput();
|
|
8981
|
+
selectedModel = await pasteableInput({
|
|
8982
|
+
message: "Enter model ID:",
|
|
8983
|
+
default: rawConfig.model ?? provider.defaultModel
|
|
8984
|
+
});
|
|
8985
|
+
if (selectedProvider === "claude") {
|
|
8986
|
+
if (!selectedModel.startsWith("claude-") && !selectedModel.includes("projects/")) {
|
|
8987
|
+
console.log(chalk24.yellow("\u26A0"), chalk24.yellow("Model ID doesn't look like Claude format. Expected: claude-{family}-{version} or Vertex AI full resource name."));
|
|
8988
|
+
console.log(chalk24.gray(" Examples: claude-opus-4-6, projects/PROJECT/locations/REGION/publishers/anthropic/models/MODEL"));
|
|
8989
|
+
}
|
|
8990
|
+
} else if (selectedProvider === "gemini") {
|
|
8991
|
+
if (!selectedModel.startsWith("gemini-") && !selectedModel.includes("projects/")) {
|
|
8992
|
+
console.log(chalk24.yellow("\u26A0"), chalk24.yellow("Model ID doesn't look like Gemini format. Expected: gemini-{version}-{variant} or Vertex AI full resource name."));
|
|
8993
|
+
console.log(chalk24.gray(" Examples: gemini-2.5-pro, projects/PROJECT/locations/REGION/publishers/google/models/MODEL"));
|
|
8994
|
+
}
|
|
8995
|
+
} else if (selectedProvider === "codex") {
|
|
8996
|
+
if (!selectedModel.startsWith("gpt-")) {
|
|
8997
|
+
console.log(chalk24.yellow("\u26A0"), chalk24.yellow("Model ID doesn't look like Codex format. Expected: gpt-{version}"));
|
|
8998
|
+
console.log(chalk24.gray(" Examples: gpt-5.4, gpt-6.0"));
|
|
8999
|
+
}
|
|
9000
|
+
}
|
|
9001
|
+
} else {
|
|
9002
|
+
selectedModel = modelSelection;
|
|
9003
|
+
}
|
|
8778
9004
|
}
|
|
8779
9005
|
const updatedAgents = [...agents];
|
|
8780
9006
|
const categorized = categorizeAgents(agents);
|
|
8781
9007
|
for (const group of categorized) {
|
|
8782
9008
|
console.log("");
|
|
8783
|
-
console.log(group.color(
|
|
9009
|
+
console.log(group.color(chalk24.bold(`\u2500\u2500 ${group.label} \u2500\u2500`)));
|
|
8784
9010
|
for (const agentIndex of group.agentIndices) {
|
|
8785
9011
|
const agent = updatedAgents[agentIndex];
|
|
8786
9012
|
const agentProvider = agent.provider ?? selectedProvider;
|
|
8787
9013
|
const agentModel = agent.model ?? selectedModel;
|
|
8788
9014
|
console.log("");
|
|
8789
|
-
console.log(
|
|
8790
|
-
console.log(
|
|
9015
|
+
console.log(chalk24.bold(agent.name), roleBadge(agent.role));
|
|
9016
|
+
console.log(chalk24.gray(` ${agent.description}`));
|
|
8791
9017
|
console.log(
|
|
8792
|
-
|
|
8793
|
-
agent.tools.map((t) =>
|
|
9018
|
+
chalk24.gray(" Tools:"),
|
|
9019
|
+
agent.tools.map((t) => chalk24.cyan(t)).join(chalk24.gray(", "))
|
|
8794
9020
|
);
|
|
8795
|
-
console.log(
|
|
8796
|
-
console.log(
|
|
9021
|
+
console.log(chalk24.gray(" Provider:"), chalk24.cyan(agentProvider));
|
|
9022
|
+
console.log(chalk24.gray(" Model: "), chalk24.cyan(agentModel));
|
|
8797
9023
|
const hasOverride = agent.provider !== void 0 || agent.model !== void 0;
|
|
8798
9024
|
resetTerminalForInput();
|
|
8799
9025
|
const action = await select6({
|
|
@@ -8820,7 +9046,7 @@ async function runConfig() {
|
|
|
8820
9046
|
});
|
|
8821
9047
|
if (!availability[agentProviderChoice]?.available) {
|
|
8822
9048
|
const reason = availability[agentProviderChoice]?.reason ?? "unknown reason";
|
|
8823
|
-
console.log(
|
|
9049
|
+
console.log(chalk24.yellow("\u26A0"), chalk24.yellow(`Provider ${agentProviderChoice} is unavailable (${reason})`));
|
|
8824
9050
|
resetTerminalForInput();
|
|
8825
9051
|
const proceed = await confirm({
|
|
8826
9052
|
message: "Continue with this provider anyway?",
|
|
@@ -8844,11 +9070,40 @@ async function runConfig() {
|
|
|
8844
9070
|
name: `${m.id} \u2014 ${m.label}`,
|
|
8845
9071
|
value: m.id
|
|
8846
9072
|
}));
|
|
8847
|
-
|
|
9073
|
+
agentModelChoices.push({
|
|
9074
|
+
name: chalk24.gray("Custom model (enter manually)"),
|
|
9075
|
+
value: "__custom__"
|
|
9076
|
+
});
|
|
9077
|
+
const agentModelSelection = await select6({
|
|
8848
9078
|
message: `Model for ${agent.name}:`,
|
|
8849
9079
|
choices: agentModelChoices,
|
|
8850
9080
|
default: agent.model ?? agentProviderAdapter.defaultModel
|
|
8851
9081
|
});
|
|
9082
|
+
if (agentModelSelection === "__custom__") {
|
|
9083
|
+
resetTerminalForInput();
|
|
9084
|
+
agentModelChoice = await pasteableInput({
|
|
9085
|
+
message: `Enter model ID for ${agent.name}:`,
|
|
9086
|
+
default: agent.model ?? agentProviderAdapter.defaultModel
|
|
9087
|
+
});
|
|
9088
|
+
if (agentProviderChoice === "claude") {
|
|
9089
|
+
if (!agentModelChoice.startsWith("claude-") && !agentModelChoice.includes("projects/")) {
|
|
9090
|
+
console.log(chalk24.yellow("\u26A0"), chalk24.yellow("Model ID doesn't look like Claude format. Expected: claude-{family}-{version} or Vertex AI full resource name."));
|
|
9091
|
+
console.log(chalk24.gray(" Examples: claude-opus-4-6, projects/PROJECT/locations/REGION/publishers/anthropic/models/MODEL"));
|
|
9092
|
+
}
|
|
9093
|
+
} else if (agentProviderChoice === "gemini") {
|
|
9094
|
+
if (!agentModelChoice.startsWith("gemini-") && !agentModelChoice.includes("projects/")) {
|
|
9095
|
+
console.log(chalk24.yellow("\u26A0"), chalk24.yellow("Model ID doesn't look like Gemini format. Expected: gemini-{version}-{variant} or Vertex AI full resource name."));
|
|
9096
|
+
console.log(chalk24.gray(" Examples: gemini-2.5-pro, projects/PROJECT/locations/REGION/publishers/google/models/MODEL"));
|
|
9097
|
+
}
|
|
9098
|
+
} else if (agentProviderChoice === "codex") {
|
|
9099
|
+
if (!agentModelChoice.startsWith("gpt-")) {
|
|
9100
|
+
console.log(chalk24.yellow("\u26A0"), chalk24.yellow("Model ID doesn't look like Codex format. Expected: gpt-{version}"));
|
|
9101
|
+
console.log(chalk24.gray(" Examples: gpt-5.4, gpt-6.0"));
|
|
9102
|
+
}
|
|
9103
|
+
}
|
|
9104
|
+
} else {
|
|
9105
|
+
agentModelChoice = agentModelSelection;
|
|
9106
|
+
}
|
|
8852
9107
|
}
|
|
8853
9108
|
updatedAgents[agentIndex] = { ...agent, provider: agentProviderChoice, model: agentModelChoice };
|
|
8854
9109
|
}
|
|
@@ -8890,24 +9145,24 @@ async function runConfig() {
|
|
|
8890
9145
|
}
|
|
8891
9146
|
} catch (err) {
|
|
8892
9147
|
const message = err instanceof Error ? err.message : String(err);
|
|
8893
|
-
console.log(
|
|
9148
|
+
console.log(chalk24.red.bold("Error:"), `Failed to write config: ${message}`);
|
|
8894
9149
|
if (isDebug()) console.error(err instanceof Error ? err.stack : err);
|
|
8895
9150
|
process.exit(2);
|
|
8896
9151
|
}
|
|
8897
9152
|
console.log("");
|
|
8898
|
-
console.log(
|
|
8899
|
-
console.log(
|
|
8900
|
-
console.log(
|
|
8901
|
-
console.log(
|
|
8902
|
-
console.log(
|
|
9153
|
+
console.log(chalk24.green.bold("\u2713"), chalk24.bold("Config updated"));
|
|
9154
|
+
console.log(chalk24.gray(" Scope: "), chalk24.cyan(scope));
|
|
9155
|
+
console.log(chalk24.gray(" File: "), chalk24.gray(configPath));
|
|
9156
|
+
console.log(chalk24.gray(" Provider:"), chalk24.cyan(selectedProvider));
|
|
9157
|
+
console.log(chalk24.gray(" Model: "), chalk24.cyan(selectedModel));
|
|
8903
9158
|
const overriddenAgents = updatedAgents.filter((a) => a.provider || a.model);
|
|
8904
9159
|
if (overriddenAgents.length > 0) {
|
|
8905
|
-
console.log(
|
|
9160
|
+
console.log(chalk24.gray(" Agent overrides:"));
|
|
8906
9161
|
for (const a of overriddenAgents) {
|
|
8907
9162
|
const parts = [];
|
|
8908
9163
|
if (a.provider) parts.push(`provider=${a.provider}`);
|
|
8909
9164
|
if (a.model) parts.push(`model=${a.model}`);
|
|
8910
|
-
console.log(
|
|
9165
|
+
console.log(chalk24.gray(` ${a.name}:`), chalk24.cyan(parts.join(", ")));
|
|
8911
9166
|
}
|
|
8912
9167
|
}
|
|
8913
9168
|
console.log("");
|
|
@@ -8916,7 +9171,7 @@ async function runConfig() {
|
|
|
8916
9171
|
// src/commands/telemetry.ts
|
|
8917
9172
|
import { statSync as statSync6 } from "fs";
|
|
8918
9173
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
8919
|
-
import
|
|
9174
|
+
import chalk25 from "chalk";
|
|
8920
9175
|
import ora6 from "ora";
|
|
8921
9176
|
import Table from "cli-table3";
|
|
8922
9177
|
import { join as join11 } from "path";
|
|
@@ -8967,7 +9222,7 @@ async function statusCommand() {
|
|
|
8967
9222
|
const config = loadConfig();
|
|
8968
9223
|
const telemetryConfig = config.telemetry;
|
|
8969
9224
|
if (!telemetryConfig) {
|
|
8970
|
-
spinner.fail(
|
|
9225
|
+
spinner.fail(chalk25.red("Telemetry configuration not found"));
|
|
8971
9226
|
return;
|
|
8972
9227
|
}
|
|
8973
9228
|
const backendType = telemetryConfig.backend === "sqlite" ? "local" : "local";
|
|
@@ -8977,20 +9232,20 @@ async function statusCommand() {
|
|
|
8977
9232
|
const dbPath = backend.getDbPath();
|
|
8978
9233
|
const dbSize = getDbSize(dbPath);
|
|
8979
9234
|
await backend.close();
|
|
8980
|
-
spinner.succeed(
|
|
9235
|
+
spinner.succeed(chalk25.green("Telemetry status loaded"));
|
|
8981
9236
|
console.log();
|
|
8982
|
-
console.log(
|
|
8983
|
-
console.log(` Enabled: ${telemetryConfig.enabled === void 0 ?
|
|
8984
|
-
console.log(` Level: ${
|
|
8985
|
-
console.log(` Backend: ${
|
|
8986
|
-
console.log(` Retention: ${
|
|
9237
|
+
console.log(chalk25.bold("Telemetry Configuration"));
|
|
9238
|
+
console.log(` Enabled: ${telemetryConfig.enabled === void 0 ? chalk25.yellow("unset (will prompt)") : telemetryConfig.enabled ? chalk25.green("yes") : chalk25.red("no")}`);
|
|
9239
|
+
console.log(` Level: ${chalk25.cyan(telemetryConfig.level)}`);
|
|
9240
|
+
console.log(` Backend: ${chalk25.cyan(telemetryConfig.backend)}`);
|
|
9241
|
+
console.log(` Retention: ${chalk25.cyan(`${telemetryConfig.retention} days`)}`);
|
|
8987
9242
|
console.log();
|
|
8988
|
-
console.log(
|
|
8989
|
-
console.log(` Database: ${
|
|
8990
|
-
console.log(` Size: ${
|
|
8991
|
-
console.log(` Runs: ${
|
|
9243
|
+
console.log(chalk25.bold("Storage"));
|
|
9244
|
+
console.log(` Database: ${chalk25.gray(dbPath)}`);
|
|
9245
|
+
console.log(` Size: ${chalk25.cyan(formatBytes(dbSize))}`);
|
|
9246
|
+
console.log(` Runs: ${chalk25.cyan(runs.length.toString())}`);
|
|
8992
9247
|
} catch (err) {
|
|
8993
|
-
spinner.fail(
|
|
9248
|
+
spinner.fail(chalk25.red(`Failed to load telemetry status: ${err.message}`));
|
|
8994
9249
|
process.exit(1);
|
|
8995
9250
|
}
|
|
8996
9251
|
}
|
|
@@ -9007,25 +9262,25 @@ async function runsCommand(options) {
|
|
|
9007
9262
|
if (options.limit) {
|
|
9008
9263
|
const parsed = Number.parseInt(options.limit, 10);
|
|
9009
9264
|
if (isNaN(parsed) || parsed < 1) {
|
|
9010
|
-
spinner.fail(
|
|
9265
|
+
spinner.fail(chalk25.red(`Invalid limit: ${options.limit}. Must be positive integer.`));
|
|
9011
9266
|
process.exit(1);
|
|
9012
9267
|
}
|
|
9013
9268
|
limit = parsed;
|
|
9014
9269
|
}
|
|
9015
9270
|
const runs = allRuns.slice(0, limit);
|
|
9016
|
-
spinner.succeed(
|
|
9271
|
+
spinner.succeed(chalk25.green(`Loaded ${runs.length} run(s)`));
|
|
9017
9272
|
if (runs.length === 0) {
|
|
9018
|
-
console.log(
|
|
9273
|
+
console.log(chalk25.yellow("\nNo telemetry runs found"));
|
|
9019
9274
|
return;
|
|
9020
9275
|
}
|
|
9021
9276
|
console.log();
|
|
9022
9277
|
const table = new Table({
|
|
9023
9278
|
head: [
|
|
9024
|
-
|
|
9025
|
-
|
|
9026
|
-
|
|
9027
|
-
|
|
9028
|
-
|
|
9279
|
+
chalk25.cyan("Run ID"),
|
|
9280
|
+
chalk25.cyan("Start Time"),
|
|
9281
|
+
chalk25.cyan("Duration"),
|
|
9282
|
+
chalk25.cyan("Events"),
|
|
9283
|
+
chalk25.cyan("Categories")
|
|
9029
9284
|
],
|
|
9030
9285
|
colWidths: [38, 20, 12, 10, 30]
|
|
9031
9286
|
});
|
|
@@ -9041,13 +9296,13 @@ async function runsCommand(options) {
|
|
|
9041
9296
|
}
|
|
9042
9297
|
console.log(table.toString());
|
|
9043
9298
|
} catch (err) {
|
|
9044
|
-
spinner.fail(
|
|
9299
|
+
spinner.fail(chalk25.red(`Failed to load runs: ${err.message}`));
|
|
9045
9300
|
process.exit(1);
|
|
9046
9301
|
}
|
|
9047
9302
|
}
|
|
9048
9303
|
async function showCommand(runId) {
|
|
9049
9304
|
if (!isValidUuid(runId)) {
|
|
9050
|
-
console.error(
|
|
9305
|
+
console.error(chalk25.red(`Invalid run ID format: ${runId}. Must be valid UUID.`));
|
|
9051
9306
|
process.exit(1);
|
|
9052
9307
|
}
|
|
9053
9308
|
const spinner = ora6(`Loading events for run ${runId}...`).start();
|
|
@@ -9059,28 +9314,28 @@ async function showCommand(runId) {
|
|
|
9059
9314
|
const events = await backend.query({ runId });
|
|
9060
9315
|
await backend.close();
|
|
9061
9316
|
if (events.length === 0) {
|
|
9062
|
-
spinner.fail(
|
|
9317
|
+
spinner.fail(chalk25.yellow(`No events found for run ${runId}`));
|
|
9063
9318
|
return;
|
|
9064
9319
|
}
|
|
9065
|
-
spinner.succeed(
|
|
9320
|
+
spinner.succeed(chalk25.green(`Loaded ${events.length} event(s) for run ${runId}`));
|
|
9066
9321
|
console.log();
|
|
9067
|
-
console.log(
|
|
9068
|
-
console.log(
|
|
9322
|
+
console.log(chalk25.bold(`Events for run ${runId}`));
|
|
9323
|
+
console.log(chalk25.gray(`Total events: ${events.length}`));
|
|
9069
9324
|
console.log();
|
|
9070
9325
|
for (const event of events) {
|
|
9071
9326
|
const timestamp = formatTimestamp(event.timestamp);
|
|
9072
|
-
const category =
|
|
9073
|
-
const eventName =
|
|
9327
|
+
const category = chalk25.cyan(`[${event.category}]`);
|
|
9328
|
+
const eventName = chalk25.bold(event.event);
|
|
9074
9329
|
const dataStr = Object.keys(event.data).length > 0 ? JSON.stringify(event.data, null, 2) : "";
|
|
9075
|
-
console.log(`${
|
|
9330
|
+
console.log(`${chalk25.gray(timestamp)} ${category} ${eventName}`);
|
|
9076
9331
|
if (dataStr) {
|
|
9077
|
-
const grayData = dataStr.split("\n").map((line) =>
|
|
9332
|
+
const grayData = dataStr.split("\n").map((line) => chalk25.gray(line)).join("\n");
|
|
9078
9333
|
console.log(grayData);
|
|
9079
9334
|
}
|
|
9080
9335
|
console.log();
|
|
9081
9336
|
}
|
|
9082
9337
|
} catch (err) {
|
|
9083
|
-
spinner.fail(
|
|
9338
|
+
spinner.fail(chalk25.red(`Failed to load events: ${err.message}`));
|
|
9084
9339
|
process.exit(1);
|
|
9085
9340
|
}
|
|
9086
9341
|
}
|
|
@@ -9100,7 +9355,7 @@ function exportCsv(events) {
|
|
|
9100
9355
|
}
|
|
9101
9356
|
async function exportCommand(runId, options) {
|
|
9102
9357
|
if (!isValidUuid(runId)) {
|
|
9103
|
-
console.error(
|
|
9358
|
+
console.error(chalk25.red(`Invalid run ID format: ${runId}. Must be valid UUID.`));
|
|
9104
9359
|
process.exit(1);
|
|
9105
9360
|
}
|
|
9106
9361
|
const format = options.format ?? "json";
|
|
@@ -9113,20 +9368,20 @@ async function exportCommand(runId, options) {
|
|
|
9113
9368
|
const events = await backend.query({ runId });
|
|
9114
9369
|
await backend.close();
|
|
9115
9370
|
if (events.length === 0) {
|
|
9116
|
-
spinner.fail(
|
|
9371
|
+
spinner.fail(chalk25.yellow(`No events found for run ${runId}`));
|
|
9117
9372
|
return;
|
|
9118
9373
|
}
|
|
9119
9374
|
const data = format === "json" ? exportJson(events) : exportCsv(events);
|
|
9120
9375
|
if (options.output) {
|
|
9121
9376
|
writeFileSync5(options.output, data, "utf-8");
|
|
9122
|
-
spinner.succeed(
|
|
9377
|
+
spinner.succeed(chalk25.green(`Exported ${events.length} events to ${options.output}`));
|
|
9123
9378
|
} else {
|
|
9124
|
-
spinner.succeed(
|
|
9379
|
+
spinner.succeed(chalk25.green(`Exported ${events.length} events`));
|
|
9125
9380
|
console.log();
|
|
9126
9381
|
console.log(data);
|
|
9127
9382
|
}
|
|
9128
9383
|
} catch (err) {
|
|
9129
|
-
spinner.fail(
|
|
9384
|
+
spinner.fail(chalk25.red(`Failed to export run: ${err.message}`));
|
|
9130
9385
|
process.exit(1);
|
|
9131
9386
|
}
|
|
9132
9387
|
}
|
|
@@ -9142,9 +9397,9 @@ async function pruneCommand(options) {
|
|
|
9142
9397
|
const olderThan = Date.now() - days * 24 * 60 * 60 * 1e3;
|
|
9143
9398
|
const deleted = await backend.prune(olderThan);
|
|
9144
9399
|
await backend.close();
|
|
9145
|
-
spinner.succeed(
|
|
9400
|
+
spinner.succeed(chalk25.green(`Pruned ${deleted} event(s) older than ${days} days`));
|
|
9146
9401
|
} catch (err) {
|
|
9147
|
-
spinner.fail(
|
|
9402
|
+
spinner.fail(chalk25.red(`Failed to prune events: ${err.message}`));
|
|
9148
9403
|
process.exit(1);
|
|
9149
9404
|
}
|
|
9150
9405
|
}
|
|
@@ -9162,9 +9417,9 @@ async function enableCommand() {
|
|
|
9162
9417
|
config.telemetry.enabled = true;
|
|
9163
9418
|
writeFileSync5(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
9164
9419
|
const scope = localConfigDir ? "local" : "global";
|
|
9165
|
-
spinner.succeed(
|
|
9420
|
+
spinner.succeed(chalk25.green(`Telemetry enabled (${scope} config)`));
|
|
9166
9421
|
} catch (err) {
|
|
9167
|
-
spinner.fail(
|
|
9422
|
+
spinner.fail(chalk25.red(`Failed to enable telemetry: ${err.message}`));
|
|
9168
9423
|
process.exit(1);
|
|
9169
9424
|
}
|
|
9170
9425
|
}
|
|
@@ -9182,9 +9437,9 @@ async function disableCommand() {
|
|
|
9182
9437
|
config.telemetry.enabled = false;
|
|
9183
9438
|
writeFileSync5(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
9184
9439
|
const scope = localConfigDir ? "local" : "global";
|
|
9185
|
-
spinner.succeed(
|
|
9440
|
+
spinner.succeed(chalk25.green(`Telemetry disabled (${scope} config)`));
|
|
9186
9441
|
} catch (err) {
|
|
9187
|
-
spinner.fail(
|
|
9442
|
+
spinner.fail(chalk25.red(`Failed to disable telemetry: ${err.message}`));
|
|
9188
9443
|
process.exit(1);
|
|
9189
9444
|
}
|
|
9190
9445
|
}
|
|
@@ -9202,7 +9457,7 @@ function registerTelemetryCommand(program2) {
|
|
|
9202
9457
|
}
|
|
9203
9458
|
|
|
9204
9459
|
// src/commands/analyze.ts
|
|
9205
|
-
import
|
|
9460
|
+
import chalk26 from "chalk";
|
|
9206
9461
|
import ora7 from "ora";
|
|
9207
9462
|
|
|
9208
9463
|
// src/telemetry-path.ts
|
|
@@ -9268,8 +9523,8 @@ async function getBackend() {
|
|
|
9268
9523
|
}
|
|
9269
9524
|
function checkTelemetryEnabled(config) {
|
|
9270
9525
|
if (!config.telemetry?.enabled) {
|
|
9271
|
-
console.log(
|
|
9272
|
-
console.log(
|
|
9526
|
+
console.log(chalk26.yellow("\nTelemetry is disabled. Enable with:"));
|
|
9527
|
+
console.log(chalk26.cyan(" reygent telemetry enable\n"));
|
|
9273
9528
|
process.exit(1);
|
|
9274
9529
|
}
|
|
9275
9530
|
}
|
|
@@ -9285,27 +9540,27 @@ async function analyzeFailures(options) {
|
|
|
9285
9540
|
const pipelineEvents = filterEvents(allEvents, { event: Events.PIPELINE_END });
|
|
9286
9541
|
await backend.close();
|
|
9287
9542
|
if (errorEvents.length === 0) {
|
|
9288
|
-
spinner.succeed(
|
|
9289
|
-
console.log(
|
|
9543
|
+
spinner.succeed(chalk26.green("No failures found"));
|
|
9544
|
+
console.log(chalk26.yellow("\nNo error events in telemetry data"));
|
|
9290
9545
|
return;
|
|
9291
9546
|
}
|
|
9292
9547
|
const totalRuns = new Set(pipelineEvents.map((e) => e.runId)).size;
|
|
9293
9548
|
const days = Math.floor((Date.now() - since) / (24 * 60 * 60 * 1e3));
|
|
9294
|
-
spinner.succeed(
|
|
9549
|
+
spinner.succeed(chalk26.green(`Analyzed ${errorEvents.length} error(s) from ${totalRuns} run(s)`));
|
|
9295
9550
|
console.log();
|
|
9296
|
-
console.log(
|
|
9551
|
+
console.log(chalk26.bold(`Failure Analysis (last ${days} days, ${totalRuns} runs)`));
|
|
9297
9552
|
console.log();
|
|
9298
9553
|
const patternGroups = groupBy(errorEvents, (e) => e.event);
|
|
9299
9554
|
const sortedPatterns = Array.from(patternGroups.entries()).sort((a, b) => b[1].length - a[1].length);
|
|
9300
9555
|
const limit = options.limit ? Number.parseInt(options.limit, 10) : sortedPatterns.length;
|
|
9301
9556
|
const topPatterns = sortedPatterns.slice(0, limit);
|
|
9302
|
-
console.log(
|
|
9557
|
+
console.log(chalk26.bold("Top Failure Patterns:"));
|
|
9303
9558
|
console.log();
|
|
9304
9559
|
for (let i = 0; i < topPatterns.length; i++) {
|
|
9305
9560
|
const [eventName, events] = topPatterns[i];
|
|
9306
9561
|
const agentGroups = groupBy(events, (e) => e.data.agent || "unknown");
|
|
9307
9562
|
const mostRecent = events.reduce((a, b) => a.timestamp > b.timestamp ? a : b);
|
|
9308
|
-
console.log(
|
|
9563
|
+
console.log(chalk26.cyan(`${i + 1}. ${eventName}`) + chalk26.gray(` (${events.length} occurrences)`));
|
|
9309
9564
|
const agentSummary = Array.from(agentGroups.entries()).map(([agent, events2]) => `${agent} (${events2.length})`).join(", ");
|
|
9310
9565
|
console.log(` Agents: ${agentSummary}`);
|
|
9311
9566
|
const messages = events.map((e) => e.data.message).filter(Boolean);
|
|
@@ -9316,7 +9571,7 @@ async function analyzeFailures(options) {
|
|
|
9316
9571
|
console.log(` Most recent: run ${mostRecent.runId.substring(0, 8)} (${formatRelativeTime(mostRecent.timestamp)})`);
|
|
9317
9572
|
console.log();
|
|
9318
9573
|
}
|
|
9319
|
-
console.log(
|
|
9574
|
+
console.log(chalk26.bold("Recommendations:"));
|
|
9320
9575
|
const recommendations = [];
|
|
9321
9576
|
const parseErrors = errorEvents.filter((e) => e.event === Events.ERROR_PARSE);
|
|
9322
9577
|
if (parseErrors.length > 0) {
|
|
@@ -9342,7 +9597,7 @@ async function analyzeFailures(options) {
|
|
|
9342
9597
|
}
|
|
9343
9598
|
}
|
|
9344
9599
|
if (recommendations.length === 0) {
|
|
9345
|
-
console.log(
|
|
9600
|
+
console.log(chalk26.gray(" No specific recommendations"));
|
|
9346
9601
|
} else {
|
|
9347
9602
|
for (const rec of recommendations) {
|
|
9348
9603
|
console.log(rec);
|
|
@@ -9356,7 +9611,7 @@ async function analyzeFailures(options) {
|
|
|
9356
9611
|
const patterns = analyzeFailurePatterns(analysisBackend, since);
|
|
9357
9612
|
await analysisBackend.close();
|
|
9358
9613
|
if (patterns.length === 0) {
|
|
9359
|
-
updateSpinner.info(
|
|
9614
|
+
updateSpinner.info(chalk26.yellow("No recurring patterns to add"));
|
|
9360
9615
|
} else {
|
|
9361
9616
|
let addedCount = 0;
|
|
9362
9617
|
const limit2 = options.limit ? Number.parseInt(options.limit, 10) : 5;
|
|
@@ -9370,13 +9625,13 @@ async function analyzeFailures(options) {
|
|
|
9370
9625
|
addedCount++;
|
|
9371
9626
|
}
|
|
9372
9627
|
}
|
|
9373
|
-
updateSpinner.succeed(
|
|
9374
|
-
console.log(
|
|
9628
|
+
updateSpinner.succeed(chalk26.green(`Added ${addedCount} failure pattern(s) to knowledge base`));
|
|
9629
|
+
console.log(chalk26.gray(` See .reygent/knowledge/common-failures.md`));
|
|
9375
9630
|
console.log();
|
|
9376
9631
|
}
|
|
9377
9632
|
} catch (err) {
|
|
9378
9633
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
9379
|
-
updateSpinner.fail(
|
|
9634
|
+
updateSpinner.fail(chalk26.red(`Failed to update knowledge: ${errMsg}`));
|
|
9380
9635
|
if (process.env.REYGENT_DEBUG === "1" || process.env.REYGENT_DEBUG === "telemetry") {
|
|
9381
9636
|
console.error("[debug:telemetry] analyzeFailures knowledge update error:", err);
|
|
9382
9637
|
}
|
|
@@ -9384,7 +9639,7 @@ async function analyzeFailures(options) {
|
|
|
9384
9639
|
}
|
|
9385
9640
|
} catch (err) {
|
|
9386
9641
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
9387
|
-
spinner.fail(
|
|
9642
|
+
spinner.fail(chalk26.red(`Failed to analyze failures: ${errMsg}`));
|
|
9388
9643
|
if (process.env.REYGENT_DEBUG === "1" || process.env.REYGENT_DEBUG === "telemetry") {
|
|
9389
9644
|
console.error("[debug:telemetry] analyzeFailures error:", err);
|
|
9390
9645
|
}
|
|
@@ -9406,14 +9661,14 @@ async function analyzeSuccess(options) {
|
|
|
9406
9661
|
const successfulRuns = pipelineEvents.filter((e) => e.data.success === true);
|
|
9407
9662
|
const days = Math.floor((Date.now() - since) / (24 * 60 * 60 * 1e3));
|
|
9408
9663
|
if (successfulRuns.length === 0) {
|
|
9409
|
-
spinner.succeed(
|
|
9664
|
+
spinner.succeed(chalk26.yellow("No successful runs found"));
|
|
9410
9665
|
return;
|
|
9411
9666
|
}
|
|
9412
|
-
spinner.succeed(
|
|
9667
|
+
spinner.succeed(chalk26.green(`Analyzed ${successfulRuns.length} successful run(s)`));
|
|
9413
9668
|
console.log();
|
|
9414
|
-
console.log(
|
|
9669
|
+
console.log(chalk26.bold(`Success Analysis (last ${days} days, ${successfulRuns.length} successful runs)`));
|
|
9415
9670
|
console.log();
|
|
9416
|
-
console.log(
|
|
9671
|
+
console.log(chalk26.bold("Agent Performance:"));
|
|
9417
9672
|
console.log();
|
|
9418
9673
|
const agentStats = /* @__PURE__ */ new Map();
|
|
9419
9674
|
for (const spawn4 of agentSpawnEvents) {
|
|
@@ -9455,7 +9710,7 @@ async function analyzeSuccess(options) {
|
|
|
9455
9710
|
const stageAgents = new Set(stageEvents.map((e) => e.data.agent));
|
|
9456
9711
|
if (!stageAgents.has(agent)) continue;
|
|
9457
9712
|
}
|
|
9458
|
-
console.log(
|
|
9713
|
+
console.log(chalk26.cyan(`${agent}:`));
|
|
9459
9714
|
console.log(` Runs: ${stats.completions}`);
|
|
9460
9715
|
console.log(` Success rate: ${formatPercent(successRate)} (${stats.successes} success, ${stats.completions - stats.successes} failures)`);
|
|
9461
9716
|
console.log(` Avg duration: ${formatDuration3(avgDuration)}`);
|
|
@@ -9463,7 +9718,7 @@ async function analyzeSuccess(options) {
|
|
|
9463
9718
|
console.log(` Model distribution: ${modelDist}`);
|
|
9464
9719
|
console.log();
|
|
9465
9720
|
}
|
|
9466
|
-
console.log(
|
|
9721
|
+
console.log(chalk26.bold("Recommendations:"));
|
|
9467
9722
|
const recommendations = [];
|
|
9468
9723
|
const sortedAgents = Array.from(agentStats.entries()).filter(([_, stats]) => stats.completions > 0).map(([agent, stats]) => ({
|
|
9469
9724
|
agent,
|
|
@@ -9477,7 +9732,7 @@ async function analyzeSuccess(options) {
|
|
|
9477
9732
|
}
|
|
9478
9733
|
}
|
|
9479
9734
|
if (recommendations.length === 0) {
|
|
9480
|
-
console.log(
|
|
9735
|
+
console.log(chalk26.gray(" No specific recommendations"));
|
|
9481
9736
|
} else {
|
|
9482
9737
|
for (const rec of recommendations) {
|
|
9483
9738
|
console.log(rec);
|
|
@@ -9492,7 +9747,7 @@ async function analyzeSuccess(options) {
|
|
|
9492
9747
|
const patterns = analyzeSuccessPatterns(analysisBackend, since, minRate);
|
|
9493
9748
|
await analysisBackend.close();
|
|
9494
9749
|
if (patterns.length === 0) {
|
|
9495
|
-
updateSpinner.info(
|
|
9750
|
+
updateSpinner.info(chalk26.yellow("No high-success patterns to add"));
|
|
9496
9751
|
} else {
|
|
9497
9752
|
let addedCount = 0;
|
|
9498
9753
|
const limit = 5;
|
|
@@ -9503,13 +9758,13 @@ async function analyzeSuccess(options) {
|
|
|
9503
9758
|
});
|
|
9504
9759
|
addedCount++;
|
|
9505
9760
|
}
|
|
9506
|
-
updateSpinner.succeed(
|
|
9507
|
-
console.log(
|
|
9761
|
+
updateSpinner.succeed(chalk26.green(`Added ${addedCount} success pattern(s) to knowledge base`));
|
|
9762
|
+
console.log(chalk26.gray(` See .reygent/knowledge/success-patterns.md`));
|
|
9508
9763
|
console.log();
|
|
9509
9764
|
}
|
|
9510
9765
|
} catch (err) {
|
|
9511
9766
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
9512
|
-
updateSpinner.fail(
|
|
9767
|
+
updateSpinner.fail(chalk26.red(`Failed to update knowledge: ${errMsg}`));
|
|
9513
9768
|
if (process.env.REYGENT_DEBUG === "1" || process.env.REYGENT_DEBUG === "telemetry") {
|
|
9514
9769
|
console.error("[debug:telemetry] analyzeSuccess knowledge update error:", err);
|
|
9515
9770
|
}
|
|
@@ -9517,7 +9772,7 @@ async function analyzeSuccess(options) {
|
|
|
9517
9772
|
}
|
|
9518
9773
|
} catch (err) {
|
|
9519
9774
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
9520
|
-
spinner.fail(
|
|
9775
|
+
spinner.fail(chalk26.red(`Failed to analyze success: ${errMsg}`));
|
|
9521
9776
|
if (process.env.REYGENT_DEBUG === "1" || process.env.REYGENT_DEBUG === "telemetry") {
|
|
9522
9777
|
console.error("[debug:telemetry] analyzeSuccess error:", err);
|
|
9523
9778
|
}
|
|
@@ -9536,18 +9791,18 @@ async function analyzeCosts(options) {
|
|
|
9536
9791
|
const pipelineEvents = filterEvents(allEvents, { event: Events.PIPELINE_END });
|
|
9537
9792
|
await backend.close();
|
|
9538
9793
|
if (costEvents.length === 0) {
|
|
9539
|
-
spinner.succeed(
|
|
9540
|
-
console.log(
|
|
9541
|
-
console.log(
|
|
9794
|
+
spinner.succeed(chalk26.yellow("No cost data found"));
|
|
9795
|
+
console.log(chalk26.gray("\nEnable verbose telemetry to track costs:"));
|
|
9796
|
+
console.log(chalk26.cyan(" reygent run --telemetry-level verbose\n"));
|
|
9542
9797
|
return;
|
|
9543
9798
|
}
|
|
9544
9799
|
const totalRuns = new Set(pipelineEvents.map((e) => e.runId)).size;
|
|
9545
9800
|
const successfulRuns = pipelineEvents.filter((e) => e.data.success === true).length;
|
|
9546
9801
|
const failedRuns = totalRuns - successfulRuns;
|
|
9547
9802
|
const days = Math.floor((Date.now() - since) / (24 * 60 * 60 * 1e3));
|
|
9548
|
-
spinner.succeed(
|
|
9803
|
+
spinner.succeed(chalk26.green(`Analyzed ${costEvents.length} cost event(s)`));
|
|
9549
9804
|
console.log();
|
|
9550
|
-
console.log(
|
|
9805
|
+
console.log(chalk26.bold(`Cost Analysis (last ${days} days, ${totalRuns} runs)`));
|
|
9551
9806
|
console.log();
|
|
9552
9807
|
const totalCost = costEvents.reduce((sum, e) => sum + e.data.costUsd, 0);
|
|
9553
9808
|
const successRunIds = new Set(
|
|
@@ -9555,12 +9810,12 @@ async function analyzeCosts(options) {
|
|
|
9555
9810
|
);
|
|
9556
9811
|
const successCost = costEvents.filter((e) => successRunIds.has(e.runId)).reduce((sum, e) => sum + e.data.costUsd, 0);
|
|
9557
9812
|
const failedCost = totalCost - successCost;
|
|
9558
|
-
console.log(
|
|
9813
|
+
console.log(chalk26.bold("Total Spend:"), chalk26.cyan(formatCost2(totalCost)));
|
|
9559
9814
|
console.log(`Successful runs: ${formatCost2(successCost)} (${formatPercent(successCost / totalCost)})`);
|
|
9560
9815
|
console.log(`Failed runs: ${formatCost2(failedCost)} (${formatPercent(failedCost / totalCost)} - wasted)`);
|
|
9561
9816
|
console.log();
|
|
9562
9817
|
if (options.byAgent) {
|
|
9563
|
-
console.log(
|
|
9818
|
+
console.log(chalk26.bold("Cost by Agent:"));
|
|
9564
9819
|
const agentCosts = /* @__PURE__ */ new Map();
|
|
9565
9820
|
for (const event of costEvents) {
|
|
9566
9821
|
const agent = event.data.agent || "unknown";
|
|
@@ -9578,7 +9833,7 @@ async function analyzeCosts(options) {
|
|
|
9578
9833
|
}
|
|
9579
9834
|
console.log();
|
|
9580
9835
|
} else {
|
|
9581
|
-
console.log(
|
|
9836
|
+
console.log(chalk26.bold("Cost by Stage:"));
|
|
9582
9837
|
const stageCosts = /* @__PURE__ */ new Map();
|
|
9583
9838
|
for (const event of costEvents) {
|
|
9584
9839
|
const stage = event.data.stage ?? "unknown";
|
|
@@ -9597,7 +9852,7 @@ async function analyzeCosts(options) {
|
|
|
9597
9852
|
console.log();
|
|
9598
9853
|
}
|
|
9599
9854
|
if (failedRuns > 0 && options.showRuns) {
|
|
9600
|
-
console.log(
|
|
9855
|
+
console.log(chalk26.bold("Expensive Failures (top 3):"));
|
|
9601
9856
|
const failedRunIds = new Set(
|
|
9602
9857
|
pipelineEvents.filter((e) => e.data.success !== true).map((e) => e.runId)
|
|
9603
9858
|
);
|
|
@@ -9622,7 +9877,7 @@ async function analyzeCosts(options) {
|
|
|
9622
9877
|
}
|
|
9623
9878
|
console.log();
|
|
9624
9879
|
}
|
|
9625
|
-
console.log(
|
|
9880
|
+
console.log(chalk26.bold("Optimization Opportunities:"));
|
|
9626
9881
|
const recommendations = [];
|
|
9627
9882
|
if (failedCost > 0) {
|
|
9628
9883
|
const wastePercent = failedCost / totalCost * 100;
|
|
@@ -9641,7 +9896,7 @@ async function analyzeCosts(options) {
|
|
|
9641
9896
|
Potential Savings: ${formatCost2(monthlySavings)}/month (${formatPercent(potentialSavings / totalCost)})`);
|
|
9642
9897
|
}
|
|
9643
9898
|
if (recommendations.length === 0) {
|
|
9644
|
-
console.log(
|
|
9899
|
+
console.log(chalk26.gray(" No specific recommendations"));
|
|
9645
9900
|
} else {
|
|
9646
9901
|
for (const rec of recommendations) {
|
|
9647
9902
|
console.log(rec);
|
|
@@ -9649,7 +9904,7 @@ Potential Savings: ${formatCost2(monthlySavings)}/month (${formatPercent(potenti
|
|
|
9649
9904
|
}
|
|
9650
9905
|
console.log();
|
|
9651
9906
|
} catch (err) {
|
|
9652
|
-
spinner.fail(
|
|
9907
|
+
spinner.fail(chalk26.red(`Failed to analyze costs: ${err.message}`));
|
|
9653
9908
|
process.exit(1);
|
|
9654
9909
|
}
|
|
9655
9910
|
}
|
|
@@ -9667,13 +9922,13 @@ async function analyzeAgents(options) {
|
|
|
9667
9922
|
const costEvents = filterEvents(allEvents, { event: Events.USAGE_COST });
|
|
9668
9923
|
await backend.close();
|
|
9669
9924
|
if (agentSpawnEvents.length === 0) {
|
|
9670
|
-
spinner.succeed(
|
|
9925
|
+
spinner.succeed(chalk26.yellow("No agent data found"));
|
|
9671
9926
|
return;
|
|
9672
9927
|
}
|
|
9673
9928
|
const days = Math.floor((Date.now() - since) / (24 * 60 * 60 * 1e3));
|
|
9674
|
-
spinner.succeed(
|
|
9929
|
+
spinner.succeed(chalk26.green(`Analyzed ${agentSpawnEvents.length} agent spawn(s)`));
|
|
9675
9930
|
console.log();
|
|
9676
|
-
console.log(
|
|
9931
|
+
console.log(chalk26.bold(`Agent Performance Analysis (last ${days} days)`));
|
|
9677
9932
|
console.log();
|
|
9678
9933
|
const agentStats = /* @__PURE__ */ new Map();
|
|
9679
9934
|
for (const spawn4 of agentSpawnEvents) {
|
|
@@ -9727,8 +9982,8 @@ async function analyzeAgents(options) {
|
|
|
9727
9982
|
if (options.agent) {
|
|
9728
9983
|
const requestedStats = agentStats.get(options.agent);
|
|
9729
9984
|
if (!requestedStats) {
|
|
9730
|
-
spinner.warn(
|
|
9731
|
-
console.log(
|
|
9985
|
+
spinner.warn(chalk26.yellow(`Agent "${options.agent}" not found in telemetry data`));
|
|
9986
|
+
console.log(chalk26.gray(`
|
|
9732
9987
|
Available agents: ${Array.from(agentStats.keys()).join(", ")}`));
|
|
9733
9988
|
return;
|
|
9734
9989
|
}
|
|
@@ -9740,7 +9995,7 @@ Available agents: ${Array.from(agentStats.keys()).join(", ")}`));
|
|
|
9740
9995
|
const successRate = stats.completions > 0 ? stats.successes / stats.completions : 0;
|
|
9741
9996
|
const avgDuration = stats.completions > 0 ? stats.totalDuration / stats.completions : 0;
|
|
9742
9997
|
const avgCost = stats.completions > 0 ? stats.totalCost / stats.completions : 0;
|
|
9743
|
-
console.log(
|
|
9998
|
+
console.log(chalk26.bold.cyan(agent + ":"));
|
|
9744
9999
|
console.log(` Runs: ${stats.completions}`);
|
|
9745
10000
|
console.log(` Success rate: ${formatPercent(successRate)} (${stats.successes} success, ${stats.failures} failures)`);
|
|
9746
10001
|
console.log(` Avg duration: ${formatDuration3(avgDuration)}`);
|
|
@@ -9790,7 +10045,7 @@ Available agents: ${Array.from(agentStats.keys()).join(", ")}`));
|
|
|
9790
10045
|
}
|
|
9791
10046
|
console.log();
|
|
9792
10047
|
}
|
|
9793
|
-
console.log(
|
|
10048
|
+
console.log(chalk26.bold("Recommendations:"));
|
|
9794
10049
|
const recommendations = [];
|
|
9795
10050
|
for (const [agent, stats] of agentStats) {
|
|
9796
10051
|
if (stats.completions > 0) {
|
|
@@ -9809,7 +10064,7 @@ Available agents: ${Array.from(agentStats.keys()).join(", ")}`));
|
|
|
9809
10064
|
recommendations.push(`\u2022 ${sortedBySuccess[0].agent}: Best performer (${formatPercent(sortedBySuccess[0].successRate)} success)`);
|
|
9810
10065
|
}
|
|
9811
10066
|
if (recommendations.length === 0) {
|
|
9812
|
-
console.log(
|
|
10067
|
+
console.log(chalk26.gray(" No specific recommendations"));
|
|
9813
10068
|
} else {
|
|
9814
10069
|
for (const rec of recommendations) {
|
|
9815
10070
|
console.log(rec);
|
|
@@ -9817,7 +10072,7 @@ Available agents: ${Array.from(agentStats.keys()).join(", ")}`));
|
|
|
9817
10072
|
}
|
|
9818
10073
|
console.log();
|
|
9819
10074
|
} catch (err) {
|
|
9820
|
-
spinner.fail(
|
|
10075
|
+
spinner.fail(chalk26.red(`Failed to analyze agents: ${err.message}`));
|
|
9821
10076
|
process.exit(1);
|
|
9822
10077
|
}
|
|
9823
10078
|
}
|
|
@@ -9830,7 +10085,7 @@ function registerAnalyzeCommand(program2) {
|
|
|
9830
10085
|
}
|
|
9831
10086
|
|
|
9832
10087
|
// src/commands/last.ts
|
|
9833
|
-
import
|
|
10088
|
+
import chalk27 from "chalk";
|
|
9834
10089
|
import ora8 from "ora";
|
|
9835
10090
|
import Table2 from "cli-table3";
|
|
9836
10091
|
function formatTimestamp2(timestamp) {
|
|
@@ -9853,8 +10108,8 @@ function formatCost3(usd) {
|
|
|
9853
10108
|
}
|
|
9854
10109
|
function checkTelemetryEnabled2(config) {
|
|
9855
10110
|
if (!config.telemetry?.enabled) {
|
|
9856
|
-
console.log(
|
|
9857
|
-
console.log(
|
|
10111
|
+
console.log(chalk27.yellow("\nTelemetry disabled. Enable with:"));
|
|
10112
|
+
console.log(chalk27.cyan(" reygent telemetry enable\n"));
|
|
9858
10113
|
process.exit(1);
|
|
9859
10114
|
}
|
|
9860
10115
|
}
|
|
@@ -9871,11 +10126,11 @@ function displaySummary(runId, events) {
|
|
|
9871
10126
|
const totalCost = costEvents.reduce((sum, e) => sum + e.data.costUsd, 0);
|
|
9872
10127
|
const agents = [...new Set(agentSpawns.map((e) => e.data.agent))];
|
|
9873
10128
|
console.log();
|
|
9874
|
-
console.log(
|
|
10129
|
+
console.log(chalk27.bold("Latest Run Summary"));
|
|
9875
10130
|
console.log();
|
|
9876
|
-
console.log(` Run ID: ${
|
|
9877
|
-
console.log(` Status: ${success ?
|
|
9878
|
-
console.log(` Started: ${
|
|
10131
|
+
console.log(` Run ID: ${chalk27.cyan(runId.substring(0, 8))}`);
|
|
10132
|
+
console.log(` Status: ${success ? chalk27.green("Success") : chalk27.red("Failed")}`);
|
|
10133
|
+
console.log(` Started: ${chalk27.gray(formatTimestamp2(startTime))}`);
|
|
9879
10134
|
console.log(` Duration: ${formatDuration4(duration)}`);
|
|
9880
10135
|
console.log(` Agents: ${agents.join(", ") || "none"}`);
|
|
9881
10136
|
if (totalCost > 0) {
|
|
@@ -9883,7 +10138,7 @@ function displaySummary(runId, events) {
|
|
|
9883
10138
|
}
|
|
9884
10139
|
if (errorEvents.length > 0) {
|
|
9885
10140
|
console.log();
|
|
9886
|
-
console.log(
|
|
10141
|
+
console.log(chalk27.red(` Errors: ${errorEvents.length} error(s)`));
|
|
9887
10142
|
const errorSummary = errorEvents.slice(0, 3).map((e) => {
|
|
9888
10143
|
const msg = e.data.message || e.event;
|
|
9889
10144
|
return ` \u2022 ${msg}`;
|
|
@@ -9897,14 +10152,14 @@ function displaySummary(runId, events) {
|
|
|
9897
10152
|
}
|
|
9898
10153
|
function displayVerbose(runId, events) {
|
|
9899
10154
|
console.log();
|
|
9900
|
-
console.log(
|
|
10155
|
+
console.log(chalk27.bold(`Detailed Event Log (${events.length} events)`));
|
|
9901
10156
|
console.log();
|
|
9902
10157
|
const table = new Table2({
|
|
9903
10158
|
head: [
|
|
9904
|
-
|
|
9905
|
-
|
|
9906
|
-
|
|
9907
|
-
|
|
10159
|
+
chalk27.cyan("Time"),
|
|
10160
|
+
chalk27.cyan("Category"),
|
|
10161
|
+
chalk27.cyan("Event"),
|
|
10162
|
+
chalk27.cyan("Details")
|
|
9908
10163
|
],
|
|
9909
10164
|
colWidths: [20, 15, 30, 50],
|
|
9910
10165
|
wordWrap: true
|
|
@@ -9913,10 +10168,10 @@ function displayVerbose(runId, events) {
|
|
|
9913
10168
|
const timestamp = formatTimestamp2(event.timestamp);
|
|
9914
10169
|
const details = Object.keys(event.data).length > 0 ? JSON.stringify(event.data).substring(0, 100) : "";
|
|
9915
10170
|
table.push([
|
|
9916
|
-
|
|
10171
|
+
chalk27.gray(timestamp),
|
|
9917
10172
|
event.category,
|
|
9918
10173
|
event.event,
|
|
9919
|
-
|
|
10174
|
+
chalk27.gray(details)
|
|
9920
10175
|
]);
|
|
9921
10176
|
}
|
|
9922
10177
|
console.log(table.toString());
|
|
@@ -9926,7 +10181,7 @@ function displayOutput(events) {
|
|
|
9926
10181
|
const pipelineEnd = events.find((e) => e.event === Events.PIPELINE_END);
|
|
9927
10182
|
const agentCompletes = events.filter((e) => e.event === Events.AGENT_COMPLETE);
|
|
9928
10183
|
console.log();
|
|
9929
|
-
console.log(
|
|
10184
|
+
console.log(chalk27.bold("Run Output"));
|
|
9930
10185
|
console.log();
|
|
9931
10186
|
if (pipelineEnd?.data.output) {
|
|
9932
10187
|
console.log(pipelineEnd.data.output);
|
|
@@ -9935,23 +10190,23 @@ function displayOutput(events) {
|
|
|
9935
10190
|
const agent = complete.data.agent;
|
|
9936
10191
|
const output = complete.data.output;
|
|
9937
10192
|
if (output) {
|
|
9938
|
-
console.log(
|
|
10193
|
+
console.log(chalk27.cyan(`[${agent}]`));
|
|
9939
10194
|
console.log(output);
|
|
9940
10195
|
console.log();
|
|
9941
10196
|
}
|
|
9942
10197
|
}
|
|
9943
10198
|
} else {
|
|
9944
|
-
console.log(
|
|
10199
|
+
console.log(chalk27.yellow("No output captured"));
|
|
9945
10200
|
}
|
|
9946
10201
|
console.log();
|
|
9947
10202
|
}
|
|
9948
10203
|
function displayErrors(events) {
|
|
9949
10204
|
const errorEvents = events.filter((e) => e.category === "error");
|
|
9950
10205
|
console.log();
|
|
9951
|
-
console.log(
|
|
10206
|
+
console.log(chalk27.bold(`Errors (${errorEvents.length})`));
|
|
9952
10207
|
console.log();
|
|
9953
10208
|
if (errorEvents.length === 0) {
|
|
9954
|
-
console.log(
|
|
10209
|
+
console.log(chalk27.green("No errors in this run"));
|
|
9955
10210
|
console.log();
|
|
9956
10211
|
return;
|
|
9957
10212
|
}
|
|
@@ -9959,10 +10214,10 @@ function displayErrors(events) {
|
|
|
9959
10214
|
const timestamp = formatTimestamp2(error.timestamp);
|
|
9960
10215
|
const message = error.data.message || "Unknown error";
|
|
9961
10216
|
const agent = error.data.agent || "unknown";
|
|
9962
|
-
console.log(
|
|
10217
|
+
console.log(chalk27.gray(timestamp) + chalk27.red(` [${error.event}]`) + ` ${agent}`);
|
|
9963
10218
|
console.log(` ${message}`);
|
|
9964
10219
|
if (error.data.stack) {
|
|
9965
|
-
console.log(
|
|
10220
|
+
console.log(chalk27.gray(` ${error.data.stack}`));
|
|
9966
10221
|
}
|
|
9967
10222
|
console.log();
|
|
9968
10223
|
}
|
|
@@ -9986,8 +10241,8 @@ async function lastCommandImpl(options, testBackend) {
|
|
|
9986
10241
|
}
|
|
9987
10242
|
const runs = await backend.listRuns();
|
|
9988
10243
|
if (runs.length === 0) {
|
|
9989
|
-
spinner.fail(
|
|
9990
|
-
console.log(
|
|
10244
|
+
spinner.fail(chalk27.yellow("No telemetry runs found"));
|
|
10245
|
+
console.log(chalk27.gray("\nRun a reygent command to generate telemetry data"));
|
|
9991
10246
|
if (!testBackend) {
|
|
9992
10247
|
await backend.close();
|
|
9993
10248
|
}
|
|
@@ -9998,7 +10253,7 @@ async function lastCommandImpl(options, testBackend) {
|
|
|
9998
10253
|
if (!testBackend) {
|
|
9999
10254
|
await backend.close();
|
|
10000
10255
|
}
|
|
10001
|
-
spinner.succeed(
|
|
10256
|
+
spinner.succeed(chalk27.green(`Loaded latest run: ${latestRun.runId.substring(0, 8)}`));
|
|
10002
10257
|
if (options.json) {
|
|
10003
10258
|
displayJson(latestRun.runId, events);
|
|
10004
10259
|
} else if (options.output) {
|
|
@@ -10011,7 +10266,7 @@ async function lastCommandImpl(options, testBackend) {
|
|
|
10011
10266
|
displaySummary(latestRun.runId, events);
|
|
10012
10267
|
}
|
|
10013
10268
|
} catch (err) {
|
|
10014
|
-
spinner.fail(
|
|
10269
|
+
spinner.fail(chalk27.red(`Failed to load latest run: ${err.message}`));
|
|
10015
10270
|
process.exit(1);
|
|
10016
10271
|
}
|
|
10017
10272
|
}
|
|
@@ -10025,7 +10280,7 @@ function registerLastCommand(program2) {
|
|
|
10025
10280
|
// src/commands/knowledge.ts
|
|
10026
10281
|
import { join as join12 } from "path";
|
|
10027
10282
|
import { execSync } from "child_process";
|
|
10028
|
-
import
|
|
10283
|
+
import chalk28 from "chalk";
|
|
10029
10284
|
import ora9 from "ora";
|
|
10030
10285
|
import Table3 from "cli-table3";
|
|
10031
10286
|
import { select as select7, confirm as confirm2 } from "@inquirer/prompts";
|
|
@@ -10068,22 +10323,22 @@ function registerKnowledgeCommand(program2) {
|
|
|
10068
10323
|
async function listCommand() {
|
|
10069
10324
|
const knowledgeDir = findKnowledgeDir();
|
|
10070
10325
|
if (!knowledgeDir) {
|
|
10071
|
-
console.log(
|
|
10326
|
+
console.log(chalk28.yellow("No .reygent/knowledge/ directory found."));
|
|
10072
10327
|
console.log(
|
|
10073
|
-
|
|
10328
|
+
chalk28.gray("Run from a project with .reygent/ or create one with:")
|
|
10074
10329
|
);
|
|
10075
|
-
console.log(
|
|
10330
|
+
console.log(chalk28.cyan(" reygent init"));
|
|
10076
10331
|
return;
|
|
10077
10332
|
}
|
|
10078
10333
|
const files = listKnowledgeFiles();
|
|
10079
10334
|
if (files.length === 0) {
|
|
10080
|
-
console.log(
|
|
10335
|
+
console.log(chalk28.yellow("No knowledge files found."));
|
|
10081
10336
|
return;
|
|
10082
10337
|
}
|
|
10083
|
-
console.log(
|
|
10338
|
+
console.log(chalk28.bold("\nKnowledge Files:"));
|
|
10084
10339
|
console.log();
|
|
10085
10340
|
const table = new Table3({
|
|
10086
|
-
head: [
|
|
10341
|
+
head: [chalk28.cyan("File"), chalk28.cyan("Type")],
|
|
10087
10342
|
colWidths: [40, 30]
|
|
10088
10343
|
});
|
|
10089
10344
|
for (const file of files) {
|
|
@@ -10092,13 +10347,13 @@ async function listCommand() {
|
|
|
10092
10347
|
}
|
|
10093
10348
|
console.log(table.toString());
|
|
10094
10349
|
console.log();
|
|
10095
|
-
console.log(
|
|
10096
|
-
console.log(
|
|
10350
|
+
console.log(chalk28.gray(`View file: ${chalk28.white("reygent knowledge show <file>")}`));
|
|
10351
|
+
console.log(chalk28.gray(`Search: ${chalk28.white("reygent knowledge search <query>")}`));
|
|
10097
10352
|
}
|
|
10098
10353
|
async function showCommand2(file) {
|
|
10099
10354
|
const knowledgeDir = findKnowledgeDir();
|
|
10100
10355
|
if (!knowledgeDir) {
|
|
10101
|
-
console.log(
|
|
10356
|
+
console.log(chalk28.red("No .reygent/knowledge/ directory found."));
|
|
10102
10357
|
process.exit(1);
|
|
10103
10358
|
}
|
|
10104
10359
|
const normalizedFile = file.endsWith(".md") ? file : `${file}.md`;
|
|
@@ -10106,24 +10361,24 @@ async function showCommand2(file) {
|
|
|
10106
10361
|
try {
|
|
10107
10362
|
const content = readMarkdown(filePath);
|
|
10108
10363
|
if (content === null) {
|
|
10109
|
-
console.log(
|
|
10110
|
-
console.log(
|
|
10364
|
+
console.log(chalk28.red(`Knowledge file validation failed: ${normalizedFile}`));
|
|
10365
|
+
console.log(chalk28.gray("File may contain suspicious content or be malformed."));
|
|
10111
10366
|
process.exit(1);
|
|
10112
10367
|
}
|
|
10113
10368
|
if (content === "") {
|
|
10114
|
-
console.log(
|
|
10115
|
-
console.log(
|
|
10369
|
+
console.log(chalk28.yellow(`Knowledge file is empty or not found: ${normalizedFile}`));
|
|
10370
|
+
console.log(chalk28.gray("Available files:"));
|
|
10116
10371
|
const files = listKnowledgeFiles();
|
|
10117
|
-
files.forEach((f) => console.log(
|
|
10372
|
+
files.forEach((f) => console.log(chalk28.gray(` - ${f}`)));
|
|
10118
10373
|
process.exit(1);
|
|
10119
10374
|
}
|
|
10120
|
-
console.log(
|
|
10375
|
+
console.log(chalk28.bold(`
|
|
10121
10376
|
${normalizedFile}
|
|
10122
10377
|
`));
|
|
10123
10378
|
console.log(content);
|
|
10124
10379
|
console.log();
|
|
10125
10380
|
} catch (err) {
|
|
10126
|
-
console.log(
|
|
10381
|
+
console.log(chalk28.red(`Failed to read ${normalizedFile}: ${err.message}`));
|
|
10127
10382
|
process.exit(1);
|
|
10128
10383
|
}
|
|
10129
10384
|
}
|
|
@@ -10132,45 +10387,45 @@ async function searchCommand(query) {
|
|
|
10132
10387
|
try {
|
|
10133
10388
|
const results = searchKnowledge(query);
|
|
10134
10389
|
if (results.length === 0) {
|
|
10135
|
-
spinner.fail(
|
|
10390
|
+
spinner.fail(chalk28.yellow("No matches found."));
|
|
10136
10391
|
return;
|
|
10137
10392
|
}
|
|
10138
|
-
spinner.succeed(
|
|
10393
|
+
spinner.succeed(chalk28.green(`Found ${results.length} match(es)`));
|
|
10139
10394
|
console.log();
|
|
10140
10395
|
for (const result of results) {
|
|
10141
|
-
console.log(
|
|
10142
|
-
console.log(
|
|
10143
|
-
console.log(
|
|
10396
|
+
console.log(chalk28.bold.cyan(`${result.file}`));
|
|
10397
|
+
console.log(chalk28.bold(` ${result.entry.title}`));
|
|
10398
|
+
console.log(chalk28.gray(` ${result.excerpt}`));
|
|
10144
10399
|
console.log();
|
|
10145
10400
|
}
|
|
10146
10401
|
} catch (err) {
|
|
10147
|
-
spinner.fail(
|
|
10402
|
+
spinner.fail(chalk28.red(`Search failed: ${err.message}`));
|
|
10148
10403
|
process.exit(1);
|
|
10149
10404
|
}
|
|
10150
10405
|
}
|
|
10151
10406
|
async function editCommand(file) {
|
|
10152
10407
|
const knowledgeDir = findKnowledgeDir();
|
|
10153
10408
|
if (!knowledgeDir) {
|
|
10154
|
-
console.log(
|
|
10409
|
+
console.log(chalk28.red("No .reygent/knowledge/ directory found."));
|
|
10155
10410
|
process.exit(1);
|
|
10156
10411
|
}
|
|
10157
10412
|
const normalizedFile = file.endsWith(".md") ? file : `${file}.md`;
|
|
10158
10413
|
const filePath = join12(knowledgeDir, normalizedFile);
|
|
10159
10414
|
const editor = process.env.EDITOR || "vi";
|
|
10160
|
-
console.log(
|
|
10415
|
+
console.log(chalk28.cyan(`Opening ${normalizedFile} in ${editor}...`));
|
|
10161
10416
|
try {
|
|
10162
10417
|
execSync(`${editor} "${filePath}"`, { stdio: "inherit" });
|
|
10163
|
-
console.log(
|
|
10418
|
+
console.log(chalk28.green("File saved."));
|
|
10164
10419
|
} catch (err) {
|
|
10165
|
-
console.log(
|
|
10420
|
+
console.log(chalk28.red(`Failed to open editor: ${err.message}`));
|
|
10166
10421
|
process.exit(1);
|
|
10167
10422
|
}
|
|
10168
10423
|
}
|
|
10169
10424
|
async function addFailureCommand(options) {
|
|
10170
10425
|
const knowledgeDir = findKnowledgeDir();
|
|
10171
10426
|
if (!knowledgeDir) {
|
|
10172
|
-
console.log(
|
|
10173
|
-
console.log(
|
|
10427
|
+
console.log(chalk28.red("No .reygent/knowledge/ directory found."));
|
|
10428
|
+
console.log(chalk28.gray("Run 'reygent init' to create knowledge directory."));
|
|
10174
10429
|
process.exit(1);
|
|
10175
10430
|
}
|
|
10176
10431
|
let issue = options.issue;
|
|
@@ -10185,7 +10440,7 @@ async function addFailureCommand(options) {
|
|
|
10185
10440
|
});
|
|
10186
10441
|
} catch (err) {
|
|
10187
10442
|
if (err instanceof InputTimeoutError) {
|
|
10188
|
-
console.log(
|
|
10443
|
+
console.log(chalk28.red("\n\u2717 Input timed out"));
|
|
10189
10444
|
process.exit(1);
|
|
10190
10445
|
}
|
|
10191
10446
|
throw err;
|
|
@@ -10199,7 +10454,7 @@ async function addFailureCommand(options) {
|
|
|
10199
10454
|
});
|
|
10200
10455
|
} catch (err) {
|
|
10201
10456
|
if (err instanceof InputTimeoutError) {
|
|
10202
|
-
console.log(
|
|
10457
|
+
console.log(chalk28.red("\n\u2717 Input timed out"));
|
|
10203
10458
|
process.exit(1);
|
|
10204
10459
|
}
|
|
10205
10460
|
throw err;
|
|
@@ -10224,7 +10479,7 @@ async function addFailureCommand(options) {
|
|
|
10224
10479
|
});
|
|
10225
10480
|
} catch (err) {
|
|
10226
10481
|
if (err instanceof InputTimeoutError) {
|
|
10227
|
-
console.log(
|
|
10482
|
+
console.log(chalk28.red("\n\u2717 Input timed out"));
|
|
10228
10483
|
process.exit(1);
|
|
10229
10484
|
}
|
|
10230
10485
|
throw err;
|
|
@@ -10238,15 +10493,15 @@ async function addFailureCommand(options) {
|
|
|
10238
10493
|
agent,
|
|
10239
10494
|
example
|
|
10240
10495
|
});
|
|
10241
|
-
console.log(
|
|
10242
|
-
console.log(
|
|
10243
|
-
console.log(
|
|
10496
|
+
console.log(chalk28.green("\u2713 Failure documented"));
|
|
10497
|
+
console.log(chalk28.gray(` File: common-failures.md`));
|
|
10498
|
+
console.log(chalk28.gray(` Agent: ${agent}`));
|
|
10244
10499
|
}
|
|
10245
10500
|
async function addPatternCommand(options) {
|
|
10246
10501
|
const knowledgeDir = findKnowledgeDir();
|
|
10247
10502
|
if (!knowledgeDir) {
|
|
10248
|
-
console.log(
|
|
10249
|
-
console.log(
|
|
10503
|
+
console.log(chalk28.red("No .reygent/knowledge/ directory found."));
|
|
10504
|
+
console.log(chalk28.gray("Run 'reygent init' to create knowledge directory."));
|
|
10250
10505
|
process.exit(1);
|
|
10251
10506
|
}
|
|
10252
10507
|
let description = options.description;
|
|
@@ -10260,7 +10515,7 @@ async function addPatternCommand(options) {
|
|
|
10260
10515
|
});
|
|
10261
10516
|
} catch (err) {
|
|
10262
10517
|
if (err instanceof InputTimeoutError) {
|
|
10263
|
-
console.log(
|
|
10518
|
+
console.log(chalk28.red("\n\u2717 Input timed out"));
|
|
10264
10519
|
process.exit(1);
|
|
10265
10520
|
}
|
|
10266
10521
|
throw err;
|
|
@@ -10278,7 +10533,7 @@ async function addPatternCommand(options) {
|
|
|
10278
10533
|
});
|
|
10279
10534
|
} catch (err) {
|
|
10280
10535
|
if (err instanceof InputTimeoutError) {
|
|
10281
|
-
console.log(
|
|
10536
|
+
console.log(chalk28.red("\n\u2717 Input timed out"));
|
|
10282
10537
|
process.exit(1);
|
|
10283
10538
|
}
|
|
10284
10539
|
throw err;
|
|
@@ -10302,7 +10557,7 @@ async function addPatternCommand(options) {
|
|
|
10302
10557
|
successRate = parseFloat(rateStr);
|
|
10303
10558
|
} catch (err) {
|
|
10304
10559
|
if (err instanceof InputTimeoutError) {
|
|
10305
|
-
console.log(
|
|
10560
|
+
console.log(chalk28.red("\n\u2717 Input timed out"));
|
|
10306
10561
|
process.exit(1);
|
|
10307
10562
|
}
|
|
10308
10563
|
throw err;
|
|
@@ -10315,13 +10570,13 @@ async function addPatternCommand(options) {
|
|
|
10315
10570
|
approach,
|
|
10316
10571
|
successRate
|
|
10317
10572
|
});
|
|
10318
|
-
console.log(
|
|
10319
|
-
console.log(
|
|
10573
|
+
console.log(chalk28.green("\u2713 Pattern documented"));
|
|
10574
|
+
console.log(chalk28.gray(` File: success-patterns.md`));
|
|
10320
10575
|
}
|
|
10321
10576
|
async function statsCommand(options) {
|
|
10322
10577
|
const knowledgeDir = findKnowledgeDir();
|
|
10323
10578
|
if (!knowledgeDir) {
|
|
10324
|
-
console.log(
|
|
10579
|
+
console.log(chalk28.red("No .reygent/knowledge/ directory found."));
|
|
10325
10580
|
process.exit(1);
|
|
10326
10581
|
}
|
|
10327
10582
|
const spinner = ora9("Calculating knowledge base stats...").start();
|
|
@@ -10329,7 +10584,7 @@ async function statsCommand(options) {
|
|
|
10329
10584
|
const since = options.since || "30d";
|
|
10330
10585
|
const match = since.match(/^(\d+)d$/);
|
|
10331
10586
|
if (!match) {
|
|
10332
|
-
spinner.fail(
|
|
10587
|
+
spinner.fail(chalk28.red(`Invalid --since format: ${since}. Use format like "30d".`));
|
|
10333
10588
|
process.exit(1);
|
|
10334
10589
|
}
|
|
10335
10590
|
const days = Number.parseInt(match[1], 10);
|
|
@@ -10343,9 +10598,9 @@ async function statsCommand(options) {
|
|
|
10343
10598
|
}, 0);
|
|
10344
10599
|
const chesstrace = getChesstrace();
|
|
10345
10600
|
if (!chesstrace) {
|
|
10346
|
-
spinner.fail(
|
|
10601
|
+
spinner.fail(chalk28.yellow("Telemetry not available. Cannot calculate effectiveness."));
|
|
10347
10602
|
console.log();
|
|
10348
|
-
console.log(
|
|
10603
|
+
console.log(chalk28.bold("Knowledge Base Stats"));
|
|
10349
10604
|
console.log();
|
|
10350
10605
|
console.log(`Files: ${files.length}`);
|
|
10351
10606
|
console.log(`Total entries: ${totalEntries}`);
|
|
@@ -10353,32 +10608,32 @@ async function statsCommand(options) {
|
|
|
10353
10608
|
}
|
|
10354
10609
|
const backend = chesstrace.getBackend();
|
|
10355
10610
|
const effectiveness = measureKnowledgeEffectiveness(backend, sinceMs);
|
|
10356
|
-
spinner.succeed(
|
|
10611
|
+
spinner.succeed(chalk28.green("Stats calculated"));
|
|
10357
10612
|
console.log();
|
|
10358
|
-
console.log(
|
|
10613
|
+
console.log(chalk28.bold("Knowledge Base Stats"));
|
|
10359
10614
|
console.log();
|
|
10360
|
-
console.log(
|
|
10361
|
-
console.log(
|
|
10615
|
+
console.log(chalk28.cyan("Files:"), files.length);
|
|
10616
|
+
console.log(chalk28.cyan("Total entries:"), totalEntries);
|
|
10362
10617
|
console.log();
|
|
10363
|
-
console.log(
|
|
10364
|
-
console.log(
|
|
10365
|
-
console.log(
|
|
10618
|
+
console.log(chalk28.bold(`Usage (last ${days} days):`));
|
|
10619
|
+
console.log(chalk28.cyan(" Consulted runs:"), effectiveness.consultedRuns);
|
|
10620
|
+
console.log(chalk28.cyan(" Baseline runs:"), effectiveness.baselineRuns);
|
|
10366
10621
|
console.log();
|
|
10367
10622
|
if (effectiveness.consultedRuns > 0 || effectiveness.baselineRuns > 0) {
|
|
10368
10623
|
const withKnowledgePct = Math.round(effectiveness.withKnowledge * 100);
|
|
10369
10624
|
const baselinePct = Math.round(effectiveness.baseline * 100);
|
|
10370
10625
|
const improvementPct = Math.round(effectiveness.improvement * 100);
|
|
10371
|
-
console.log(
|
|
10372
|
-
console.log(
|
|
10373
|
-
console.log(
|
|
10374
|
-
const improvementColor = effectiveness.improvement > 0 ?
|
|
10375
|
-
console.log(
|
|
10626
|
+
console.log(chalk28.bold("Effectiveness:"));
|
|
10627
|
+
console.log(chalk28.cyan(" Success rate with knowledge:"), `${withKnowledgePct}%`);
|
|
10628
|
+
console.log(chalk28.cyan(" Baseline success rate:"), `${baselinePct}%`);
|
|
10629
|
+
const improvementColor = effectiveness.improvement > 0 ? chalk28.green : effectiveness.improvement < 0 ? chalk28.red : chalk28.gray;
|
|
10630
|
+
console.log(chalk28.cyan(" Improvement:"), improvementColor(`${improvementPct > 0 ? "+" : ""}${improvementPct}%`));
|
|
10376
10631
|
} else {
|
|
10377
|
-
console.log(
|
|
10632
|
+
console.log(chalk28.gray("No runs found in time window to measure effectiveness."));
|
|
10378
10633
|
}
|
|
10379
10634
|
console.log();
|
|
10380
10635
|
} catch (err) {
|
|
10381
|
-
spinner.fail(
|
|
10636
|
+
spinner.fail(chalk28.red(`Failed to calculate stats: ${err.message}`));
|
|
10382
10637
|
process.exit(1);
|
|
10383
10638
|
}
|
|
10384
10639
|
}
|
|
@@ -10388,7 +10643,7 @@ import { existsSync as existsSync13, readFileSync as readFileSync11, writeFileSy
|
|
|
10388
10643
|
import { join as join13, dirname as dirname6 } from "path";
|
|
10389
10644
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
10390
10645
|
import { confirm as confirm3 } from "@inquirer/prompts";
|
|
10391
|
-
import
|
|
10646
|
+
import chalk29 from "chalk";
|
|
10392
10647
|
function shouldPromptForTelemetry() {
|
|
10393
10648
|
if (!process.stdin.isTTY) {
|
|
10394
10649
|
return false;
|
|
@@ -10419,16 +10674,16 @@ function shouldPromptForTelemetry() {
|
|
|
10419
10674
|
return false;
|
|
10420
10675
|
} catch (err) {
|
|
10421
10676
|
if (isDebug()) {
|
|
10422
|
-
console.error(
|
|
10677
|
+
console.error(chalk29.gray(`Failed to read config at ${configPath}:`), err);
|
|
10423
10678
|
}
|
|
10424
10679
|
return true;
|
|
10425
10680
|
}
|
|
10426
10681
|
}
|
|
10427
10682
|
async function promptForTelemetryOptIn() {
|
|
10428
10683
|
console.log("");
|
|
10429
|
-
console.log(
|
|
10430
|
-
console.log(
|
|
10431
|
-
console.log(
|
|
10684
|
+
console.log(chalk29.bold("First-run telemetry setup"));
|
|
10685
|
+
console.log(chalk29.gray("Reygent can collect local usage data to help diagnose issues."));
|
|
10686
|
+
console.log(chalk29.gray("Data is stored locally in SQLite and never sent to external servers."));
|
|
10432
10687
|
console.log("");
|
|
10433
10688
|
const enabled = await confirm3({
|
|
10434
10689
|
message: "Enable local telemetry?",
|
|
@@ -10437,9 +10692,9 @@ async function promptForTelemetryOptIn() {
|
|
|
10437
10692
|
await saveTelemetryChoice(enabled);
|
|
10438
10693
|
console.log("");
|
|
10439
10694
|
if (enabled) {
|
|
10440
|
-
console.log(
|
|
10695
|
+
console.log(chalk29.green("\u2713"), "Local telemetry enabled");
|
|
10441
10696
|
} else {
|
|
10442
|
-
console.log(
|
|
10697
|
+
console.log(chalk29.gray("\u2713"), "Local telemetry disabled");
|
|
10443
10698
|
}
|
|
10444
10699
|
console.log("");
|
|
10445
10700
|
}
|
|
@@ -10462,7 +10717,7 @@ async function saveTelemetryChoice(enabled) {
|
|
|
10462
10717
|
rawConfig = JSON.parse(content);
|
|
10463
10718
|
} catch (err) {
|
|
10464
10719
|
if (isDebug()) {
|
|
10465
|
-
console.error(
|
|
10720
|
+
console.error(chalk29.gray(`Failed to parse config at ${configPath}:`), err);
|
|
10466
10721
|
}
|
|
10467
10722
|
}
|
|
10468
10723
|
}
|
|
@@ -10491,9 +10746,9 @@ async function saveTelemetryChoice(enabled) {
|
|
|
10491
10746
|
}
|
|
10492
10747
|
} catch (err) {
|
|
10493
10748
|
const message = err instanceof Error ? err.message : String(err);
|
|
10494
|
-
console.log(
|
|
10749
|
+
console.log(chalk29.yellow("Warning:"), `Failed to save telemetry config: ${message}`);
|
|
10495
10750
|
if (isDebug()) console.error(err instanceof Error ? err.stack : err);
|
|
10496
|
-
console.log(
|
|
10751
|
+
console.log(chalk29.gray("Command will continue without saving telemetry preference."));
|
|
10497
10752
|
}
|
|
10498
10753
|
}
|
|
10499
10754
|
|
|
@@ -10504,7 +10759,7 @@ var pkg = JSON.parse(
|
|
|
10504
10759
|
);
|
|
10505
10760
|
var program = new Command();
|
|
10506
10761
|
program.name("reygent").description("Reygent CLI tool").version(pkg.version).option("--debug", "Show full stack traces on errors (or set REYGENT_DEBUG=1)").option("--model <id>", "Model ID (e.g. claude-sonnet-4-5, gemini-2.5-pro, gpt-5.4)").option("--provider <name>", `AI provider (${PROVIDER_NAMES.join(", ")})`).option("--no-telemetry", "Disable telemetry for this run").option("--telemetry-level <level>", "Override telemetry level (minimal, standard, verbose)").option("--telemetry-verbose", "Shorthand for --telemetry-level verbose").addHelpText("after", `
|
|
10507
|
-
${
|
|
10762
|
+
${chalk30.yellow("Disclaimer:")} This software is provided "as is" with no warranty. AI-generated output should be reviewed by a human. See LICENSE for full terms.`);
|
|
10508
10763
|
program.command("init").description("Initialize .reygent folder with default agent and skill config").option("--dry-run", "Preview what files would be created without writing anything", false).action(initCommand);
|
|
10509
10764
|
program.command("generate-spec").description("Generate a full markdown spec from a short description").argument("[description]", "Short description of the feature to spec out").option("--output <file>", "Output file path").option("--skip-clarification", "Skip clarifying questions and generate spec directly", false).action(generateSpecCommand);
|
|
10510
10765
|
program.command("spec").description("Load a spec from a markdown file, Jira issue, or Linear issue").argument("<source>", "Path to a markdown file, issue key (e.g. PROJ-123), or Linear URL").option("--clarify", "Run planner with clarification loop to evaluate spec", false).option("--source <name>", "Issue source provider (jira, linear, local) \u2014 skips interactive prompt").action(specCommand);
|
|
@@ -10512,12 +10767,18 @@ program.command("agent").description("Start an interactive agent session").argum
|
|
|
10512
10767
|
program.command("run").description("Run the reygent workflow from spec to reviewed PR").option("--spec <source>", "Path to a markdown file, issue key, or Linear URL (prompts if omitted in interactive mode)").option("--type <type>", "Branch type (feat, fix, chore, refactor, docs, test, style, perf) \u2014 skips interactive prompt").option("--dry-run", "Preview workflow stages without executing", false).option("--security-threshold <level>", "Minimum severity to fail security review (CRITICAL, HIGH, MEDIUM, LOW)", "HIGH").option("--auto-approve", "Auto-approve all file edits and actions without prompting", false).option("--insecure", "Skip SSL certificate verification for API calls", false).option("--skip-clarification", "Skip planner clarification and make assumptions", false).option("--max-retries <count>", "Max retry attempts when gate tests fail", "2").option("--verbose", "Show detailed per-agent token and cost breakdown", false).hook("preAction", (thisCommand) => {
|
|
10513
10768
|
const opts = thisCommand.opts();
|
|
10514
10769
|
if (opts.type && !isValidType(opts.type)) {
|
|
10515
|
-
console.error(
|
|
10770
|
+
console.error(chalk30.red(`Error: Invalid --type "${opts.type}". Must be one of: ${VALID_BRANCH_TYPES.join(", ")} (or feature/bugfix aliases)`));
|
|
10516
10771
|
process.exit(1);
|
|
10517
10772
|
}
|
|
10518
10773
|
}).action(runCommand);
|
|
10519
10774
|
program.command("review-work").description("Review current branch and post summary to PR/MR").option("--spec <source>", "Spec source with provider prefix (jira:KEY, linear:ID, markdown:FILE) \u2014 file paths auto-infer markdown:").option("--insecure", "Skip SSL certificate verification for API calls", false).action(reviewWorkCommand);
|
|
10520
|
-
program.command("review-comments").description("Fetch PR/MR review comments and address them with an agent").option("--insecure", "Skip SSL certificate verification for API calls", false).option("--auto-approve", "Auto-approve plan and execute without prompting", false).
|
|
10775
|
+
program.command("review-comments").description("Fetch PR/MR review comments and address them with an agent").option("--insecure", "Skip SSL certificate verification for API calls", false).option("--auto-approve", "Auto-approve plan and execute without prompting", false).option("--retry-commits <count>", "Max retries for pre-commit hook failures (default: 3)", (val) => {
|
|
10776
|
+
const num = parseInt(val, 10);
|
|
10777
|
+
if (isNaN(num) || num < 0 || num > 10) {
|
|
10778
|
+
throw new Error("--retry-commits must be between 0 and 10");
|
|
10779
|
+
}
|
|
10780
|
+
return num;
|
|
10781
|
+
}).action(reviewCommentsCommand);
|
|
10521
10782
|
program.command("config").description("Configure default provider, model, and per-agent overrides").action(configCommand);
|
|
10522
10783
|
registerTelemetryCommand(program);
|
|
10523
10784
|
registerAnalyzeCommand(program);
|
|
@@ -10526,8 +10787,8 @@ registerSkillsCommand(program);
|
|
|
10526
10787
|
registerKnowledgeCommand(program);
|
|
10527
10788
|
var isHelpOrVersion = process.argv.includes("--help") || process.argv.includes("-h") || process.argv.includes("--version") || process.argv.includes("-V") || process.argv.length <= 2;
|
|
10528
10789
|
if (!isHelpOrVersion) {
|
|
10529
|
-
console.log(
|
|
10530
|
-
reygent`) +
|
|
10790
|
+
console.log(chalk30.bold.cyan(`
|
|
10791
|
+
reygent`) + chalk30.gray(` v${pkg.version}`) + "\n");
|
|
10531
10792
|
}
|
|
10532
10793
|
program.hook("preAction", async () => {
|
|
10533
10794
|
if (program.opts().debug) {
|
|
@@ -10571,7 +10832,7 @@ program.hook("preAction", async () => {
|
|
|
10571
10832
|
}
|
|
10572
10833
|
} catch (err) {
|
|
10573
10834
|
if (program.opts().debug) {
|
|
10574
|
-
console.error(
|
|
10835
|
+
console.error(chalk30.gray("Validation error:"), err);
|
|
10575
10836
|
}
|
|
10576
10837
|
}
|
|
10577
10838
|
const noTelemetry = program.opts().telemetry === false;
|
|
@@ -10580,11 +10841,11 @@ program.hook("preAction", async () => {
|
|
|
10580
10841
|
await promptForTelemetryOptIn();
|
|
10581
10842
|
} catch (err) {
|
|
10582
10843
|
if (err && typeof err === "object" && "name" in err && err.name === "ExitPromptError") {
|
|
10583
|
-
console.log(
|
|
10844
|
+
console.log(chalk30.yellow("\nTelemetry setup cancelled."));
|
|
10584
10845
|
process.exit(0);
|
|
10585
10846
|
}
|
|
10586
10847
|
if (program.opts().debug) {
|
|
10587
|
-
console.error(
|
|
10848
|
+
console.error(chalk30.gray("Telemetry prompt failed:"), err);
|
|
10588
10849
|
}
|
|
10589
10850
|
}
|
|
10590
10851
|
}
|