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 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.6-opus-high
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
- throw new CliError(`Unknown command: ${first}.`, CLI_EXIT_CODES.usage);
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 fs = require("node:fs");
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}${iterLabel}`, value: s.file };
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 = fmIter ? String(fmIter) : "1";
1086
+ const defaultIter = "1";
1102
1087
  const iterOptions = [
1103
1088
  { label: `${defaultIter} (default)`, value: defaultIter },
1104
- ...(defaultIter !== "1" ? [{ label: "1", value: "1" }] : []),
1105
- ...(defaultIter !== "2" ? [{ label: "2", value: "2" }] : []),
1106
- ...(defaultIter !== "3" ? [{ label: "3", value: "3" }] : []),
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 bar = "═".repeat(innerW);
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("║", "\x1b[36m")} ${label.padEnd(12)} ${pad(val)} ${colorize("║", "\x1b[36m")}`;
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(`╔${bar}╗`, "\x1b[36m"));
1144
- console.log(colorize(`║${" ".repeat(titlePad)}${titleText}${" ".repeat(innerW - titlePad - titleText.length)}║`, "\x1b[36m"));
1145
- console.log(colorize(`╠${bar}╣`, "\x1b[36m"));
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("║", "\x1b[36m")} ${colorize("⚠ Frontier model — higher cost per token", "\x1b[33m")}${" ".repeat(Math.max(0, innerW - 43))} ${colorize("║", "\x1b[36m")}`);
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(`╚${bar}╝`, "\x1b[36m"));
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 = fs.existsSync(skillDir) ? fs.readdirSync(skillDir, { recursive: true }).filter((f) => String(f).endsWith("SKILL.md")).length : 0;
1185
- const ruleCount = fs.existsSync(ruleDir) ? fs.readdirSync(ruleDir).filter((f) => String(f).endsWith(".mdc")).length : 0;
1186
- const mcpConfig = fs.existsSync(path.resolve(cwd, ".cursor", "mcp.json")) ? "found" : "none";
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, complex reasoning", tier: "frontier" },
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.6-opus-high",
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
- When --prompt-file is omitted and only one .prompts-gpt/sweeps/*.md file exists,
3066
- it is auto-selected. The iteration count defaults to the \`iterations:\` value
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. Default: from frontmatter or 1.
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
- console.error(formatApiError(error));
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
- console.error(msg.replace(/pgpt_[a-zA-Z0-9]{4,}/g, "pgpt_***"));
3608
- if (process.env.PROMPTS_GPT_DEBUG === "1" && error instanceof Error && error.stack) {
3609
- console.error(error.stack.replace(/pgpt_[a-zA-Z0-9]{4,}/g, "pgpt_***"));
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) {