prompts-gpt 0.2.9 → 0.2.11
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 +3 -1
- package/dist/cli.js +59 -55
- package/dist/cli.js.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +0 -11
- package/dist/runtime.js.map +1 -1
- package/dist/sweep.d.ts +1 -1
- package/dist/sweep.d.ts.map +1 -1
- package/dist/sweep.js +8 -88
- package/dist/sweep.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -115,8 +115,10 @@ prompts-gpt models --provider codex
|
|
|
115
115
|
prompts-gpt sync-models
|
|
116
116
|
|
|
117
117
|
# Use model aliases for shorter commands
|
|
118
|
-
prompts-gpt run --model opus # resolves to claude-4
|
|
118
|
+
prompts-gpt run --model opus # resolves to claude-opus-4-7
|
|
119
119
|
prompts-gpt run --model mini # resolves to gpt-5.4-mini
|
|
120
|
+
prompts-gpt run --model pro # resolves to gpt-5.5-pro
|
|
121
|
+
prompts-gpt run --model o3 # resolves to o3
|
|
120
122
|
|
|
121
123
|
# Sync from cloud
|
|
122
124
|
prompts-gpt sync --agent all
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { existsSync, readFileSync, statSync, readdirSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { parseArgs } from "node:util";
|
|
5
5
|
import { hasTokenUsage, DEFAULT_PROMPTS_GPT_API_URL, DEFAULT_PROMPTS_GPT_OUT_DIR, DEFAULT_RUN_CONFIG_PATH, PROMPTS_GPT_CREDENTIALS_FILE, PromptsGptApiError, PromptsGptClient, doctor, initRunConfig, loadRunConfig, normalizeOrchestrationAgent, ORCHESTRATION_AGENT_PROFILES, runBatch, runPrompt, resolveRunProvider, warnModelProviderMismatch, sweepPrompt, validateRunConfig, discoverWorkspaceAssets, SUPPORTED_AGENT_TARGETS, detectProviders, loadLocalCredentials, saveLocalCredentials, syncPrompts, writeAgentFiles, writePromptManifest, writePromptMarkdownFiles, ensureGitignoreEntry, } from "./index.js";
|
|
@@ -79,7 +79,10 @@ async function main() {
|
|
|
79
79
|
}
|
|
80
80
|
const command = asCommandName(first);
|
|
81
81
|
if (!command) {
|
|
82
|
-
|
|
82
|
+
const suggestion = COMMANDS.find((c) => c.startsWith(first.slice(0, 3)));
|
|
83
|
+
const hint = suggestion ? ` Did you mean \`prompts-gpt ${suggestion}\`?` : "";
|
|
84
|
+
const installHint = "\nIf you installed from npm, ensure you have the latest version: npm install -g prompts-gpt@latest";
|
|
85
|
+
throw new CliError(`Unknown command: ${first}.${hint}${installHint}`, CLI_EXIT_CODES.usage);
|
|
83
86
|
}
|
|
84
87
|
if (!isRunnableCommand(command)) {
|
|
85
88
|
throw new CliError(`Unknown command: ${first}.`, CLI_EXIT_CODES.usage, {
|
|
@@ -617,8 +620,7 @@ async function runCommand(command, flags) {
|
|
|
617
620
|
const statusModelCache = path.resolve(cwd, DEFAULT_PROMPTS_GPT_OUT_DIR, ".models.json");
|
|
618
621
|
if (existsSync(statusModelCache)) {
|
|
619
622
|
try {
|
|
620
|
-
const
|
|
621
|
-
const mStat = fs.statSync(statusModelCache);
|
|
623
|
+
const mStat = statSync(statusModelCache);
|
|
622
624
|
const ageMs = Date.now() - mStat.mtimeMs;
|
|
623
625
|
const ageDays = Math.floor(ageMs / (1000 * 60 * 60 * 24));
|
|
624
626
|
console.log(` Models: ${ageDays <= 7 ? "✓" : "⚠"} synced ${ageDays === 0 ? "today" : `${ageDays}d ago`}${ageDays > 7 ? " — run 'prompts-gpt sync-models'" : ""}`);
|
|
@@ -629,18 +631,6 @@ async function runCommand(command, flags) {
|
|
|
629
631
|
console.log(" Models: — not synced. Run 'prompts-gpt sync-models'");
|
|
630
632
|
}
|
|
631
633
|
console.log("");
|
|
632
|
-
const lockFile = path.resolve(cwd, ".sweep.lock");
|
|
633
|
-
if (existsSync(lockFile)) {
|
|
634
|
-
try {
|
|
635
|
-
const { readFile: fsRead } = await import("node:fs/promises");
|
|
636
|
-
const lockData = JSON.parse(await fsRead(lockFile, "utf8"));
|
|
637
|
-
console.log(` Sweep lock: ⚠ active (PID ${lockData.pid}, started ${lockData.startedAt})`);
|
|
638
|
-
}
|
|
639
|
-
catch {
|
|
640
|
-
console.log(" Sweep lock: ⚠ found but unreadable");
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
console.log("");
|
|
644
634
|
if (assets.prompts.length > 0 && availableProviders.length > 0) {
|
|
645
635
|
console.log("Ready to run:");
|
|
646
636
|
console.log(` prompts-gpt run --prompt-file .prompts-gpt/${assets.prompts[0].file}`);
|
|
@@ -997,7 +987,7 @@ async function runCommand(command, flags) {
|
|
|
997
987
|
const iterFromFm = await readSweepIterationsFromFrontmatter(path.resolve(cwd, autoFile));
|
|
998
988
|
console.log(`Auto-selected sweep: ${path.basename(autoFile)}${iterFromFm ? ` (${iterFromFm} iterations from frontmatter)` : ""}`);
|
|
999
989
|
flags["prompt-file"] = autoFile;
|
|
1000
|
-
if (iterFromFm && !getStringFlag(flags, "iterations")) {
|
|
990
|
+
if (iterFromFm && !getStringFlag(flags, "iterations") && !isTTYInteractive(flags)) {
|
|
1001
991
|
flags.iterations = String(iterFromFm);
|
|
1002
992
|
}
|
|
1003
993
|
}
|
|
@@ -1005,16 +995,11 @@ async function runCommand(command, flags) {
|
|
|
1005
995
|
if (isTTYInteractive(flags)) {
|
|
1006
996
|
const sweepOptions = await Promise.all(assets.sweeps.map(async (s) => {
|
|
1007
997
|
const fm = await readSweepFrontmatter(path.resolve(cwd, s.file));
|
|
1008
|
-
const iterLabel = fm.iterations ? ` (${fm.iterations} iterations)` : "";
|
|
1009
998
|
const titleLabel = fm.title ? ` — ${fm.title}` : "";
|
|
1010
|
-
return { label: `${path.basename(s.file, ".md")}${titleLabel}
|
|
999
|
+
return { label: `${path.basename(s.file, ".md")}${titleLabel}`, value: s.file };
|
|
1011
1000
|
}));
|
|
1012
1001
|
const picked = await interactiveSelect("Select a sweep file:", sweepOptions);
|
|
1013
1002
|
flags["prompt-file"] = picked;
|
|
1014
|
-
const iterFromFm = await readSweepIterationsFromFrontmatter(path.resolve(cwd, picked));
|
|
1015
|
-
if (iterFromFm && !getStringFlag(flags, "iterations")) {
|
|
1016
|
-
flags.iterations = String(iterFromFm);
|
|
1017
|
-
}
|
|
1018
1003
|
}
|
|
1019
1004
|
else {
|
|
1020
1005
|
console.log(`${assets.sweeps.length} sweep files found. Pick one with --prompt-file:\n`);
|
|
@@ -1033,7 +1018,7 @@ async function runCommand(command, flags) {
|
|
|
1033
1018
|
return;
|
|
1034
1019
|
}
|
|
1035
1020
|
}
|
|
1036
|
-
if (!getStringFlag(flags, "iterations") && getStringFlag(flags, "prompt-file")) {
|
|
1021
|
+
if (!getStringFlag(flags, "iterations") && getStringFlag(flags, "prompt-file") && !isTTYInteractive(flags)) {
|
|
1037
1022
|
const iterFromFm = await readSweepIterationsFromFrontmatter(path.resolve(cwd, getStringFlag(flags, "prompt-file")));
|
|
1038
1023
|
if (iterFromFm) {
|
|
1039
1024
|
flags.iterations = String(iterFromFm);
|
|
@@ -1098,14 +1083,16 @@ async function runCommand(command, flags) {
|
|
|
1098
1083
|
}
|
|
1099
1084
|
if (!getStringFlag(flags, "iterations") && isTTYInteractive(flags) && !Boolean(flags.json) && getStringFlag(flags, "prompt-file")) {
|
|
1100
1085
|
const fmIter = await readSweepIterationsFromFrontmatter(path.resolve(cwd, getStringFlag(flags, "prompt-file")));
|
|
1101
|
-
const defaultIter =
|
|
1086
|
+
const defaultIter = "1";
|
|
1102
1087
|
const iterOptions = [
|
|
1103
1088
|
{ label: `${defaultIter} (default)`, value: defaultIter },
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
...(defaultIter !== "5" ? [{ label: "5", value: "5" }] : []),
|
|
1089
|
+
{ label: "2", value: "2" },
|
|
1090
|
+
{ label: "3", value: "3" },
|
|
1091
|
+
{ label: "5", value: "5" },
|
|
1108
1092
|
];
|
|
1093
|
+
if (fmIter && !iterOptions.some((option) => option.value === String(fmIter))) {
|
|
1094
|
+
iterOptions.push({ label: String(fmIter), value: String(fmIter) });
|
|
1095
|
+
}
|
|
1109
1096
|
flags.iterations = await interactiveSelect("Select iterations:", iterOptions);
|
|
1110
1097
|
}
|
|
1111
1098
|
const agent = resolveRunAgent(flags, config.defaultAgent);
|
|
@@ -1114,7 +1101,7 @@ async function runCommand(command, flags) {
|
|
|
1114
1101
|
const resolvedP = resolveRunProvider(agent, providers, config.providerOrder);
|
|
1115
1102
|
const check = validateModelForProvider(sweepModelFlag, resolvedP);
|
|
1116
1103
|
if (!check.valid) {
|
|
1117
|
-
console.log(`⚠ Model "${sweepModelFlag}" may not be available for ${resolvedP}.${check.suggestion ? ` Did you mean "${check.suggestion}"?` : ""}
|
|
1104
|
+
console.log(`⚠ Model "${sweepModelFlag}" may not be available for ${resolvedP}.${check.suggestion ? ` Did you mean "${check.suggestion}"?` : ""}\n Run \`prompts-gpt sweep --list-models --agent ${resolvedP}\` to see available models.`);
|
|
1118
1105
|
}
|
|
1119
1106
|
}
|
|
1120
1107
|
if (isTTYInteractive(flags) && !Boolean(flags.json) && !Boolean(flags["dry-run"])) {
|
|
@@ -1135,14 +1122,16 @@ async function runCommand(command, flags) {
|
|
|
1135
1122
|
];
|
|
1136
1123
|
const longestVal = Math.max(...boxValues.map((v) => v.length), 30);
|
|
1137
1124
|
const innerW = longestVal + 16;
|
|
1138
|
-
const
|
|
1125
|
+
const uc = supportsColor();
|
|
1126
|
+
const [TL, H, TR, V, ML, MR, BL, BR] = uc ? ["╔", "═", "╗", "║", "╠", "╣", "╚", "╝"] : ["+", "-", "+", "|", "+", "+", "+", "+"];
|
|
1127
|
+
const bar = H.repeat(innerW);
|
|
1139
1128
|
const pad = (v) => v.padEnd(longestVal);
|
|
1140
|
-
const row = (label, val) => `${colorize(
|
|
1129
|
+
const row = (label, val) => `${colorize(V, "\x1b[36m")} ${label.padEnd(12)} ${pad(val)} ${colorize(V, "\x1b[36m")}`;
|
|
1141
1130
|
const titleText = "Prompts-GPT Sweep";
|
|
1142
1131
|
const titlePad = Math.max(0, Math.floor((innerW - titleText.length) / 2));
|
|
1143
|
-
console.log(colorize(
|
|
1144
|
-
console.log(colorize(
|
|
1145
|
-
console.log(colorize(
|
|
1132
|
+
console.log(colorize(`${TL}${bar}${TR}`, "\x1b[36m"));
|
|
1133
|
+
console.log(colorize(`${V}${" ".repeat(titlePad)}${titleText}${" ".repeat(innerW - titlePad - titleText.length)}${V}`, "\x1b[36m"));
|
|
1134
|
+
console.log(colorize(`${ML}${bar}${MR}`, "\x1b[36m"));
|
|
1146
1135
|
console.log(row("Sweep:", path.basename(sweepFile)));
|
|
1147
1136
|
console.log(row("Provider:", resolvedProvider));
|
|
1148
1137
|
console.log(row("Model:", resolvedModel));
|
|
@@ -1152,9 +1141,9 @@ async function runCommand(command, flags) {
|
|
|
1152
1141
|
console.log(row("Retries:", String(maxRetries)));
|
|
1153
1142
|
console.log(row("Tier:", tierBadge));
|
|
1154
1143
|
if (modelTier === "frontier") {
|
|
1155
|
-
console.log(`${colorize(
|
|
1144
|
+
console.log(`${colorize(V, "\x1b[36m")} ${colorize(uc ? "⚠ Frontier model — higher cost per token" : "! Frontier model -- higher cost per token", "\x1b[33m")}${" ".repeat(Math.max(0, innerW - 43))} ${colorize(V, "\x1b[36m")}`);
|
|
1156
1145
|
}
|
|
1157
|
-
console.log(colorize(
|
|
1146
|
+
console.log(colorize(`${BL}${bar}${BR}`, "\x1b[36m"));
|
|
1158
1147
|
console.log("");
|
|
1159
1148
|
const confirmOpts = [
|
|
1160
1149
|
{ label: "Yes, run this sweep", value: "y" },
|
|
@@ -1178,12 +1167,11 @@ async function runCommand(command, flags) {
|
|
|
1178
1167
|
console.log(`Branch: ${report.gitBranch} | Dirty files: ${report.gitDirtyFiles} | Free disk: ${report.diskFreeMb}MB`);
|
|
1179
1168
|
console.log(`Prompt: ${path.basename(report.promptFile)}`);
|
|
1180
1169
|
try {
|
|
1181
|
-
const fs = require("node:fs");
|
|
1182
1170
|
const skillDir = path.resolve(cwd, ".agents", "skills");
|
|
1183
1171
|
const ruleDir = path.resolve(cwd, ".cursor", "rules");
|
|
1184
|
-
const skillCount =
|
|
1185
|
-
const ruleCount =
|
|
1186
|
-
const mcpConfig =
|
|
1172
|
+
const skillCount = existsSync(skillDir) ? readdirSync(skillDir, { recursive: true }).filter((f) => String(f).endsWith("SKILL.md")).length : 0;
|
|
1173
|
+
const ruleCount = existsSync(ruleDir) ? readdirSync(ruleDir).filter((f) => String(f).endsWith(".mdc")).length : 0;
|
|
1174
|
+
const mcpConfig = existsSync(path.resolve(cwd, ".cursor", "mcp.json")) ? "found" : "none";
|
|
1187
1175
|
console.log(`Skills: ${skillCount} | Rules: ${ruleCount} | MCP config: ${mcpConfig}`);
|
|
1188
1176
|
}
|
|
1189
1177
|
catch { /* skip */ }
|
|
@@ -2486,6 +2474,8 @@ function getStringFlag(flags, name) {
|
|
|
2486
2474
|
return typeof value === "string" ? value : undefined;
|
|
2487
2475
|
}
|
|
2488
2476
|
function formatDuration(ms) {
|
|
2477
|
+
if (!Number.isFinite(ms) || ms < 0)
|
|
2478
|
+
return "unknown";
|
|
2489
2479
|
if (ms < 1000)
|
|
2490
2480
|
return ms < 1 ? "<1ms" : `${Math.round(ms)}ms`;
|
|
2491
2481
|
const totalSeconds = Math.round(ms / 1000);
|
|
@@ -2696,16 +2686,15 @@ const PROVIDER_MODELS = Object.freeze({
|
|
|
2696
2686
|
{ value: "gpt-4.1", label: "gpt-4.1 — legacy", tier: "budget" },
|
|
2697
2687
|
],
|
|
2698
2688
|
claude: [
|
|
2699
|
-
{ value: "claude-opus-4-7", label: "claude-opus-4-7 — most capable
|
|
2689
|
+
{ value: "claude-opus-4-7", label: "claude-opus-4-7 — latest, most capable", tier: "frontier" },
|
|
2690
|
+
{ value: "claude-opus-4-6", label: "claude-opus-4-6 — previous gen opus", tier: "frontier" },
|
|
2700
2691
|
{ value: "claude-sonnet-4-6", label: "claude-sonnet-4-6 — speed + intelligence", tier: "standard" },
|
|
2701
2692
|
{ value: "claude-haiku-4-5", label: "claude-haiku-4-5 — fastest near-frontier", tier: "fast" },
|
|
2702
|
-
{ value: "claude-4.6-opus-high", label: "claude-4.6-opus-high — high-thinking opus", tier: "frontier" },
|
|
2703
|
-
{ value: "claude-4.6-sonnet-high", label: "claude-4.6-sonnet-high — high-thinking sonnet", tier: "standard" },
|
|
2704
|
-
{ value: "claude-4.5-opus", label: "claude-4.5-opus — previous gen opus", tier: "standard" },
|
|
2705
2693
|
],
|
|
2706
2694
|
cursor: [
|
|
2707
2695
|
{ value: "auto", label: "auto — Cursor auto-selects best", tier: "standard" },
|
|
2708
2696
|
{ value: "claude-4.6-opus-high", label: "claude-4.6-opus-high — frontier reasoning", tier: "frontier" },
|
|
2697
|
+
{ value: "claude-4.6-opus-high-thinking", label: "claude-4.6-opus-high-thinking — reasoning + thinking", tier: "frontier" },
|
|
2709
2698
|
{ value: "claude-4.6-sonnet-high", label: "claude-4.6-sonnet-high — fast + smart", tier: "standard" },
|
|
2710
2699
|
{ value: "gpt-5.5-medium", label: "gpt-5.5-medium — GPT frontier", tier: "frontier" },
|
|
2711
2700
|
{ value: "composer-2", label: "composer-2 — balanced multi-file", tier: "standard" },
|
|
@@ -2724,7 +2713,7 @@ const PROVIDER_MODELS = Object.freeze({
|
|
|
2724
2713
|
],
|
|
2725
2714
|
});
|
|
2726
2715
|
const MODEL_ALIASES = {
|
|
2727
|
-
opus: "claude-4
|
|
2716
|
+
opus: "claude-opus-4-7",
|
|
2728
2717
|
sonnet: "claude-sonnet-4-6",
|
|
2729
2718
|
haiku: "claude-haiku-4-5",
|
|
2730
2719
|
codex: "gpt-5.3-codex",
|
|
@@ -2734,6 +2723,8 @@ const MODEL_ALIASES = {
|
|
|
2734
2723
|
composer: "composer-2",
|
|
2735
2724
|
fast: "composer-2-fast",
|
|
2736
2725
|
gemini: "gemini-3.1-pro",
|
|
2726
|
+
o3: "o3",
|
|
2727
|
+
pro: "gpt-5.5-pro",
|
|
2737
2728
|
};
|
|
2738
2729
|
function resolveModelAlias(model) {
|
|
2739
2730
|
return MODEL_ALIASES[model.toLowerCase().trim()] ?? model;
|
|
@@ -3062,13 +3053,12 @@ Why use it:
|
|
|
3062
3053
|
Runs the same prompt N times, feeding each iteration's summary into the next.
|
|
3063
3054
|
Includes pre-flight checks, safety guards, SIGTERM handling, and progress monitoring.
|
|
3064
3055
|
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
in the sweep file's YAML frontmatter (or 1 if not specified).
|
|
3056
|
+
Interactive runs always ask for the iteration count. Non-interactive runs use
|
|
3057
|
+
the \`iterations:\` value in the sweep file's YAML frontmatter when present.
|
|
3068
3058
|
|
|
3069
3059
|
Options:
|
|
3070
3060
|
-f, --prompt-file <path> Prompt file to sweep. Auto-detects local sweeps if omitted.
|
|
3071
|
-
-n, --iterations <n> Number of iterations.
|
|
3061
|
+
-n, --iterations <n> Number of iterations. Interactive default: 1.
|
|
3072
3062
|
--agent <name> Orchestration profile. Default from config or router.
|
|
3073
3063
|
--model <name> Model override for the selected provider.
|
|
3074
3064
|
--iteration-timeout <secs> Timeout per iteration in seconds. Default: 5400 (90 min)
|
|
@@ -3401,10 +3391,14 @@ function interactiveSelect(prompt, options) {
|
|
|
3401
3391
|
const onData = (data) => {
|
|
3402
3392
|
for (let ci = 0; ci < data.length; ci++) {
|
|
3403
3393
|
const ch = data[ci];
|
|
3404
|
-
if (escBuf.length > 0) {
|
|
3394
|
+
if (escBuf.length > 0 && escBuf[0] === "\x1b") {
|
|
3405
3395
|
escBuf += ch;
|
|
3406
3396
|
if (escBuf.length === 2 && ch === "[")
|
|
3407
3397
|
continue;
|
|
3398
|
+
if (escBuf.length === 2 && ch !== "[") {
|
|
3399
|
+
escBuf = "";
|
|
3400
|
+
continue;
|
|
3401
|
+
}
|
|
3408
3402
|
if (escBuf.length >= 3) {
|
|
3409
3403
|
if (escBuf === "\x1b[A" || escBuf === "\x1b[k") {
|
|
3410
3404
|
cursor = cursor > 0 ? cursor - 1 : options.length - 1;
|
|
@@ -3426,6 +3420,8 @@ function interactiveSelect(prompt, options) {
|
|
|
3426
3420
|
}
|
|
3427
3421
|
escBuf = "";
|
|
3428
3422
|
}
|
|
3423
|
+
if (escBuf.length > 8)
|
|
3424
|
+
escBuf = "";
|
|
3429
3425
|
continue;
|
|
3430
3426
|
}
|
|
3431
3427
|
if (ch === "\x1b") {
|
|
@@ -3593,7 +3589,12 @@ main().catch((error) => {
|
|
|
3593
3589
|
return;
|
|
3594
3590
|
}
|
|
3595
3591
|
if (error instanceof PromptsGptApiError) {
|
|
3596
|
-
|
|
3592
|
+
try {
|
|
3593
|
+
console.error(formatApiError(error));
|
|
3594
|
+
}
|
|
3595
|
+
catch {
|
|
3596
|
+
console.error(`API error: ${error.message} (${error.status})`);
|
|
3597
|
+
}
|
|
3597
3598
|
process.exitCode = error.status === 401 || error.status === 403
|
|
3598
3599
|
? CLI_EXIT_CODES.auth
|
|
3599
3600
|
: error.status === 429
|
|
@@ -3604,10 +3605,13 @@ main().catch((error) => {
|
|
|
3604
3605
|
return;
|
|
3605
3606
|
}
|
|
3606
3607
|
const msg = error instanceof Error ? error.message : String(error);
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3608
|
+
try {
|
|
3609
|
+
console.error(msg.replace(/pgpt_[a-zA-Z0-9]{4,}/g, "pgpt_***"));
|
|
3610
|
+
if (process.env.PROMPTS_GPT_DEBUG === "1" && error instanceof Error && error.stack) {
|
|
3611
|
+
console.error(error.stack.replace(/pgpt_[a-zA-Z0-9]{4,}/g, "pgpt_***"));
|
|
3612
|
+
}
|
|
3610
3613
|
}
|
|
3614
|
+
catch { /* stderr closed or broken pipe */ }
|
|
3611
3615
|
process.exitCode = CLI_EXIT_CODES.general;
|
|
3612
3616
|
});
|
|
3613
3617
|
async function extractRunDiagnostics(logFile, provider, model) {
|