@prompts-gpt/client 0.2.5 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +617 -101
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -3
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +46 -22
- package/dist/runtime.js.map +1 -1
- package/dist/sweep.d.ts.map +1 -1
- package/dist/sweep.js +133 -7
- package/dist/sweep.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -27,15 +27,32 @@ class CliError extends Error {
|
|
|
27
27
|
async function main() {
|
|
28
28
|
const argv = process.argv.slice(2);
|
|
29
29
|
if (argv.length === 0) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
prompts-gpt sweep — run a
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
const assets = await discoverWorkspaceAssets(process.cwd()).catch(() => null);
|
|
31
|
+
const hasSetup = assets && (assets.credentialsFound || assets.configFound || assets.prompts.length > 0 || assets.sweeps.length > 0);
|
|
32
|
+
if (hasSetup && assets) {
|
|
33
|
+
console.log(`Prompts-GPT CLI — ${assets.prompts.length} prompts, ${assets.sweeps.length} sweeps available\n`);
|
|
34
|
+
if (assets.sweeps.length > 0) {
|
|
35
|
+
console.log(" prompts-gpt sweep — run a sweep (interactive picker)");
|
|
36
|
+
}
|
|
37
|
+
if (assets.prompts.length > 0) {
|
|
38
|
+
console.log(" prompts-gpt run — run a prompt");
|
|
39
|
+
}
|
|
40
|
+
console.log(" prompts-gpt list — see all available assets");
|
|
41
|
+
console.log(" prompts-gpt sync — refresh prompts from studio");
|
|
42
|
+
console.log(" prompts-gpt status — check workspace readiness");
|
|
43
|
+
console.log(`\nRun \`prompts-gpt help\` for the full command list.\n`);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
console.log(`Prompts-GPT CLI — sync and run AI prompt packs locally\n`);
|
|
47
|
+
console.log("Get started:");
|
|
48
|
+
console.log(" prompts-gpt quickstart — setup credentials, config, and first run");
|
|
49
|
+
console.log(" prompts-gpt init --token-prompt — save your project token");
|
|
50
|
+
console.log("");
|
|
51
|
+
console.log("Already have sweep files?");
|
|
52
|
+
console.log(" prompts-gpt sweep — auto-detect and run local sweeps");
|
|
53
|
+
console.log(" prompts-gpt list — see available prompts and sweeps");
|
|
54
|
+
console.log(`\nRun \`prompts-gpt help\` for the full command list.\n`);
|
|
55
|
+
}
|
|
39
56
|
return;
|
|
40
57
|
}
|
|
41
58
|
const first = argv[0];
|
|
@@ -84,14 +101,21 @@ async function runCommand(command, flags) {
|
|
|
84
101
|
console.log(JSON.stringify({ cwd, providers }, null, 2));
|
|
85
102
|
return;
|
|
86
103
|
}
|
|
87
|
-
console.log(`Workspace: ${cwd}`);
|
|
104
|
+
console.log(`Workspace: ${cwd}\n`);
|
|
88
105
|
for (const provider of providers) {
|
|
89
|
-
const
|
|
90
|
-
console.log(`${provider.provider}: ${
|
|
106
|
+
const icon = provider.available ? "✓" : "✗";
|
|
107
|
+
console.log(`${icon} ${provider.provider}: ${provider.available ? "available" : "missing"} | bin=${provider.bin} | model=${provider.modelDefault}${provider.version ? ` | ${provider.version}` : ""}`);
|
|
91
108
|
if (!provider.available) {
|
|
92
|
-
console.log(`
|
|
109
|
+
console.log(` → ${provider.installHint}`);
|
|
93
110
|
}
|
|
94
111
|
}
|
|
112
|
+
const noneAvailable = providers.every((p) => !p.available);
|
|
113
|
+
if (noneAvailable) {
|
|
114
|
+
console.log("\nNo providers installed. Quick install:");
|
|
115
|
+
console.log(" npm install -g @openai/codex # OpenAI Codex");
|
|
116
|
+
console.log(" npm install -g @anthropic-ai/claude-code # Claude Code");
|
|
117
|
+
console.log(" # Cursor: install Cursor IDE");
|
|
118
|
+
}
|
|
95
119
|
return;
|
|
96
120
|
}
|
|
97
121
|
if (command === "setup") {
|
|
@@ -141,13 +165,42 @@ async function runCommand(command, flags) {
|
|
|
141
165
|
console.log("⚠ No provider CLIs detected. Install codex, cursor agent, claude, or copilot.");
|
|
142
166
|
}
|
|
143
167
|
const setupAssets = await discoverWorkspaceAssets(cwd);
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
168
|
+
if (isTTYInteractive() && (setupAssets.sweeps.length > 0 || setupAssets.prompts.length > 0)) {
|
|
169
|
+
const setupOptions = [];
|
|
170
|
+
for (const s of setupAssets.sweeps) {
|
|
171
|
+
setupOptions.push({ label: `sweep: ${s.name}`, value: `sweep:${s.file}` });
|
|
172
|
+
}
|
|
173
|
+
for (const p of setupAssets.prompts.slice(0, 3)) {
|
|
174
|
+
setupOptions.push({ label: `run: ${p.title}`, value: `run:.prompts-gpt/${p.file}` });
|
|
175
|
+
}
|
|
176
|
+
setupOptions.push({ label: "prompts-gpt list", value: "list" });
|
|
177
|
+
setupOptions.push({ label: "(done)", value: "done" });
|
|
178
|
+
console.log("");
|
|
179
|
+
const setupPicked = await interactiveSelect("What next?", setupOptions);
|
|
180
|
+
if (setupPicked === "list") {
|
|
181
|
+
const { spawnSync: spSync } = await import("node:child_process");
|
|
182
|
+
const cliEntry = process.argv[1] || require.resolve("./cli.js");
|
|
183
|
+
spSync(process.execPath, [cliEntry, "list"], { stdio: "inherit", cwd });
|
|
184
|
+
}
|
|
185
|
+
else if (setupPicked !== "done") {
|
|
186
|
+
const [action, file] = setupPicked.split(":", 2);
|
|
187
|
+
const cmd = action === "sweep" ? "sweep" : "run";
|
|
188
|
+
console.log(`\nRunning: prompts-gpt ${cmd} -f ${file}\n`);
|
|
189
|
+
const { spawnSync: spSync } = await import("node:child_process");
|
|
190
|
+
const cliEntry = process.argv[1] || require.resolve("./cli.js");
|
|
191
|
+
const setupResult = spSync(process.execPath, [cliEntry, cmd, "-f", file], { stdio: "inherit", cwd });
|
|
192
|
+
process.exitCode = setupResult.status ?? 1;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
console.log("Next steps:");
|
|
197
|
+
console.log(` prompts-gpt run${result.sourceSummary.defaultPromptFile ? "" : " --prompt-file <path>"}`);
|
|
198
|
+
if (setupAssets.sweeps.length > 0) {
|
|
199
|
+
console.log(` prompts-gpt sweep — run a multi-iteration sweep (${setupAssets.sweeps.length} found)`);
|
|
200
|
+
}
|
|
201
|
+
console.log(" prompts-gpt list — see all runnable assets");
|
|
202
|
+
console.log(" prompts-gpt status — check workspace readiness");
|
|
148
203
|
}
|
|
149
|
-
console.log(" prompts-gpt list — see all runnable assets");
|
|
150
|
-
console.log(" prompts-gpt status — check workspace readiness");
|
|
151
204
|
return;
|
|
152
205
|
}
|
|
153
206
|
if (command === "doctor") {
|
|
@@ -157,17 +210,38 @@ async function runCommand(command, flags) {
|
|
|
157
210
|
console.log(JSON.stringify(report, null, 2));
|
|
158
211
|
return;
|
|
159
212
|
}
|
|
160
|
-
console.log(
|
|
161
|
-
console.log(
|
|
162
|
-
console.log(
|
|
213
|
+
console.log("Prompts-GPT Doctor");
|
|
214
|
+
console.log("==================\n");
|
|
215
|
+
console.log("System:");
|
|
216
|
+
console.log(` ${report.nodeVersion.startsWith("v18") || report.nodeVersion.startsWith("v2") ? "✓" : "⚠"} Node: ${report.nodeVersion}`);
|
|
217
|
+
console.log(` ✓ OS: ${report.osPlatform}/${report.osArch} | CPUs: ${report.cpuCount}`);
|
|
218
|
+
console.log(` ${report.configFound ? "✓" : "✗"} Config: ${report.configFound ? report.configPath : "not found — run \`prompts-gpt setup\`"}`);
|
|
219
|
+
console.log(`\n Workspace: ${report.cwd}\n`);
|
|
220
|
+
console.log("Providers:");
|
|
163
221
|
for (const provider of report.providers) {
|
|
164
|
-
|
|
222
|
+
const icon = provider.available ? "✓" : "✗";
|
|
223
|
+
console.log(` ${icon} ${provider.provider}: ${provider.available ? `${provider.bin}` : "not found"}${provider.version ? ` (${provider.version})` : ""}`);
|
|
165
224
|
if (!provider.available) {
|
|
166
|
-
console.log(`
|
|
225
|
+
console.log(` → ${provider.installHint}`);
|
|
167
226
|
}
|
|
168
227
|
}
|
|
169
|
-
|
|
170
|
-
|
|
228
|
+
const configNotes = report.notes.filter((n) => n.includes("config") || n.includes("Config") || n.includes("provider order") || n.includes("Router"));
|
|
229
|
+
const sweepNotes = report.notes.filter((n) => n.includes("weep") || n.includes("lock"));
|
|
230
|
+
const otherNotes = report.notes.filter((n) => !configNotes.includes(n) && !sweepNotes.includes(n));
|
|
231
|
+
if (configNotes.length > 0) {
|
|
232
|
+
console.log("\nConfiguration:");
|
|
233
|
+
for (const n of configNotes)
|
|
234
|
+
console.log(` ℹ ${n}`);
|
|
235
|
+
}
|
|
236
|
+
if (sweepNotes.length > 0) {
|
|
237
|
+
console.log("\nSweep:");
|
|
238
|
+
for (const n of sweepNotes)
|
|
239
|
+
console.log(` ℹ ${n}`);
|
|
240
|
+
}
|
|
241
|
+
if (otherNotes.length > 0) {
|
|
242
|
+
console.log("\nNotes:");
|
|
243
|
+
for (const n of otherNotes)
|
|
244
|
+
console.log(` ℹ ${n}`);
|
|
171
245
|
}
|
|
172
246
|
return;
|
|
173
247
|
}
|
|
@@ -205,9 +279,23 @@ async function runCommand(command, flags) {
|
|
|
205
279
|
const iterCount = await readSweepIterationsFromFrontmatter(path.resolve(cwd, s.file));
|
|
206
280
|
const iterHint = iterCount ? ` (${iterCount} iterations)` : "";
|
|
207
281
|
const iterFlag = iterCount ? ` --iterations ${iterCount}` : "";
|
|
208
|
-
|
|
282
|
+
let lastRun = "";
|
|
283
|
+
try {
|
|
284
|
+
const artifactsDir = path.resolve(cwd, ".prompts-gpt-runs");
|
|
285
|
+
if (existsSync(artifactsDir)) {
|
|
286
|
+
const { readdir: rd, stat: fsStat } = await import("node:fs/promises");
|
|
287
|
+
const dirs = await rd(artifactsDir);
|
|
288
|
+
const sweepDirs = dirs.filter((d) => d.includes("sweep")).sort().reverse();
|
|
289
|
+
if (sweepDirs[0]) {
|
|
290
|
+
const s2 = await fsStat(path.join(artifactsDir, sweepDirs[0]));
|
|
291
|
+
lastRun = ` | last run: ${s2.mtime.toLocaleDateString()}`;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
catch { /* skip */ }
|
|
296
|
+
console.log(` ${s.name}${iterHint}${lastRun}`);
|
|
209
297
|
console.log(` file: ${s.file}`);
|
|
210
|
-
console.log(` sweep: prompts-gpt sweep
|
|
298
|
+
console.log(` sweep: prompts-gpt sweep -f ${s.file}${iterFlag}`);
|
|
211
299
|
}
|
|
212
300
|
console.log("");
|
|
213
301
|
}
|
|
@@ -250,7 +338,8 @@ async function runCommand(command, flags) {
|
|
|
250
338
|
const cmd = action === "sweep" ? "sweep" : "run";
|
|
251
339
|
console.log(`\nRunning: prompts-gpt ${cmd} -f ${file}\n`);
|
|
252
340
|
const { spawnSync: spSync } = await import("node:child_process");
|
|
253
|
-
const
|
|
341
|
+
const cliEntry = process.argv[1] || require.resolve("./cli.js");
|
|
342
|
+
const result = spSync(process.execPath, [cliEntry, cmd, "-f", file], { stdio: "inherit", cwd });
|
|
254
343
|
process.exitCode = result.status ?? 1;
|
|
255
344
|
}
|
|
256
345
|
}
|
|
@@ -287,7 +376,22 @@ async function runCommand(command, flags) {
|
|
|
287
376
|
}
|
|
288
377
|
}
|
|
289
378
|
else {
|
|
290
|
-
console.log(" Providers: ✗ — no CLI found");
|
|
379
|
+
console.log(" Providers: ✗ — no CLI found. Install one:");
|
|
380
|
+
console.log(" npm install -g @openai/codex # Codex");
|
|
381
|
+
console.log(" npm install -g @anthropic-ai/claude-code # Claude Code");
|
|
382
|
+
console.log(" # Cursor: install Cursor IDE (includes agent CLI)");
|
|
383
|
+
}
|
|
384
|
+
console.log("");
|
|
385
|
+
const lockFile = path.resolve(cwd, ".sweep.lock");
|
|
386
|
+
if (existsSync(lockFile)) {
|
|
387
|
+
try {
|
|
388
|
+
const { readFile: fsRead } = await import("node:fs/promises");
|
|
389
|
+
const lockData = JSON.parse(await fsRead(lockFile, "utf8"));
|
|
390
|
+
console.log(` Sweep lock: ⚠ active (PID ${lockData.pid}, started ${lockData.startedAt})`);
|
|
391
|
+
}
|
|
392
|
+
catch {
|
|
393
|
+
console.log(" Sweep lock: ⚠ found but unreadable");
|
|
394
|
+
}
|
|
291
395
|
}
|
|
292
396
|
console.log("");
|
|
293
397
|
if (assets.prompts.length > 0 && availableProviders.length > 0) {
|
|
@@ -331,6 +435,20 @@ async function runCommand(command, flags) {
|
|
|
331
435
|
for (const w of result.warnings) {
|
|
332
436
|
console.log(` warning: ${w}`);
|
|
333
437
|
}
|
|
438
|
+
const validAssets = await discoverWorkspaceAssets(cwd);
|
|
439
|
+
if (validAssets.sweeps.length > 0) {
|
|
440
|
+
console.log(`\nSweep files (${validAssets.sweeps.length}):`);
|
|
441
|
+
for (const s of validAssets.sweeps) {
|
|
442
|
+
const fm = await readSweepFrontmatter(path.resolve(cwd, s.file));
|
|
443
|
+
const issues = [];
|
|
444
|
+
if (!fm.iterations)
|
|
445
|
+
issues.push("no iterations in frontmatter");
|
|
446
|
+
if (!fm.title)
|
|
447
|
+
issues.push("no title heading");
|
|
448
|
+
const icon = issues.length === 0 ? "✓" : "⚠";
|
|
449
|
+
console.log(` ${icon} ${s.name}${issues.length > 0 ? ` — ${issues.join(", ")}` : ""}`);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
334
452
|
if (result.valid && result.errors.length === 0 && result.warnings.length === 0) {
|
|
335
453
|
console.log(" No issues found.");
|
|
336
454
|
}
|
|
@@ -374,12 +492,32 @@ async function runCommand(command, flags) {
|
|
|
374
492
|
const runProviders = await detectProviders(cwd);
|
|
375
493
|
const runAvailable = runProviders.filter((p) => p.available);
|
|
376
494
|
if (!getStringFlag(flags, "agent") && isTTYInteractive(flags) && !Boolean(flags.json) && runAvailable.length > 1) {
|
|
495
|
+
const lastRunProvider = await getLastUsedProvider(cwd);
|
|
377
496
|
const providerOpts = runAvailable.map((p) => ({
|
|
378
|
-
label: `${p.provider} (${p.modelDefault}${p.version ? `, ${p.version}` : ""})`,
|
|
497
|
+
label: `${p.provider} (${p.modelDefault}${p.version ? `, ${p.version}` : ""})${p.provider === lastRunProvider ? " ★" : ""}`,
|
|
379
498
|
value: p.provider,
|
|
380
499
|
}));
|
|
381
500
|
providerOpts.push({ label: "router (auto-select)", value: "router" });
|
|
501
|
+
if (lastRunProvider) {
|
|
502
|
+
const idx = providerOpts.findIndex((o) => o.value === lastRunProvider);
|
|
503
|
+
if (idx > 0) {
|
|
504
|
+
const [item] = providerOpts.splice(idx, 1);
|
|
505
|
+
providerOpts.unshift(item);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
382
508
|
flags.agent = await interactiveSelect("Select a provider:", providerOpts);
|
|
509
|
+
if (flags.agent !== "router") {
|
|
510
|
+
await saveLastUsedProvider(cwd, flags.agent);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
if (!getStringFlag(flags, "model") && isTTYInteractive(flags) && !Boolean(flags.json)) {
|
|
514
|
+
const currentAgent = resolveRunAgent(flags, config.defaultAgent);
|
|
515
|
+
if (currentAgent !== "router") {
|
|
516
|
+
const modelChoices = getModelChoicesForProvider(currentAgent, config);
|
|
517
|
+
if (modelChoices.length > 0) {
|
|
518
|
+
flags.model = await interactiveSelect("Select a model:", modelChoices);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
383
521
|
}
|
|
384
522
|
const agent = resolveRunAgent(flags, config.defaultAgent);
|
|
385
523
|
if (Boolean(flags["dry-run"])) {
|
|
@@ -405,6 +543,23 @@ async function runCommand(command, flags) {
|
|
|
405
543
|
console.log(` Timeout: ${getStringFlag(flags, "timeout") || config.timeoutSeconds}s`);
|
|
406
544
|
return;
|
|
407
545
|
}
|
|
546
|
+
if (isTTYInteractive(flags) && !Boolean(flags.json) && !Boolean(flags["dry-run"])) {
|
|
547
|
+
const previewFile = getStringFlag(flags, "prompt-file");
|
|
548
|
+
if (previewFile && existsSync(path.resolve(cwd, previewFile))) {
|
|
549
|
+
try {
|
|
550
|
+
const { readFile: fsRead } = await import("node:fs/promises");
|
|
551
|
+
const previewContent = await fsRead(path.resolve(cwd, previewFile), "utf8");
|
|
552
|
+
const previewLines = previewContent.split("\n").slice(0, 5);
|
|
553
|
+
console.log(`\nPrompt preview (${path.basename(previewFile)}):`);
|
|
554
|
+
for (const line of previewLines)
|
|
555
|
+
console.log(` ${line}`);
|
|
556
|
+
if (previewContent.split("\n").length > 5)
|
|
557
|
+
console.log(` ... (${previewContent.split("\n").length - 5} more lines)`);
|
|
558
|
+
console.log("");
|
|
559
|
+
}
|
|
560
|
+
catch { /* skip preview */ }
|
|
561
|
+
}
|
|
562
|
+
}
|
|
408
563
|
const modelFlag = getStringFlag(flags, "model");
|
|
409
564
|
if (modelFlag && !Boolean(flags.json) && agent !== "router") {
|
|
410
565
|
const providers = await detectProviders(cwd);
|
|
@@ -443,9 +598,29 @@ async function runCommand(command, flags) {
|
|
|
443
598
|
console.log(`Summary: ${result.summaryFile}`);
|
|
444
599
|
console.log(`Log: ${result.logFile}`);
|
|
445
600
|
if (result.exitCode === 0) {
|
|
601
|
+
try {
|
|
602
|
+
const { readFile: fsRead } = await import("node:fs/promises");
|
|
603
|
+
const deltaContent = await fsRead(result.worktreeDeltaFile, "utf8");
|
|
604
|
+
if (!deltaContent.includes("No worktree delta")) {
|
|
605
|
+
const afterLines = deltaContent.split("\n").filter((l) => l.startsWith("=== AFTER ===") ? false : true);
|
|
606
|
+
const changedFiles = afterLines.filter((l) => /^\s*[MADRCU?!]/.test(l)).length;
|
|
607
|
+
if (changedFiles > 0) {
|
|
608
|
+
console.log(`Files changed: ${changedFiles}`);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
catch { /* skip */ }
|
|
446
613
|
console.log("");
|
|
447
614
|
console.log(`View results: cat ${result.summaryFile}`);
|
|
448
615
|
}
|
|
616
|
+
if (Boolean(flags.open) && result.summaryFile) {
|
|
617
|
+
try {
|
|
618
|
+
const { spawn: openSpawn } = await import("node:child_process");
|
|
619
|
+
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "notepad" : "xdg-open";
|
|
620
|
+
openSpawn(openCmd, [result.summaryFile], { detached: true, stdio: "ignore" }).unref();
|
|
621
|
+
}
|
|
622
|
+
catch { /* ignore */ }
|
|
623
|
+
}
|
|
449
624
|
if (result.exitCode !== 0) {
|
|
450
625
|
const diagnostics = await extractRunDiagnostics(result.logFile, result.provider, result.model);
|
|
451
626
|
if (diagnostics.length > 0) {
|
|
@@ -563,35 +738,55 @@ async function runCommand(command, flags) {
|
|
|
563
738
|
const providers = await detectProviders(cwd);
|
|
564
739
|
const availableProviders = providers.filter((p) => p.available);
|
|
565
740
|
if (!getStringFlag(flags, "agent") && isTTYInteractive(flags) && !Boolean(flags.json) && availableProviders.length > 1) {
|
|
741
|
+
const lastProvider = await getLastUsedProvider(cwd);
|
|
566
742
|
const providerOptions = availableProviders.map((p) => ({
|
|
567
|
-
label: `${p.provider} (${p.modelDefault}${p.version ? `, ${p.version}` : ""})`,
|
|
743
|
+
label: `${p.provider} (${p.modelDefault}${p.version ? `, ${p.version}` : ""})${p.provider === lastProvider ? " ★" : ""}`,
|
|
568
744
|
value: p.provider,
|
|
569
745
|
}));
|
|
570
746
|
providerOptions.push({ label: "router (auto-select best available)", value: "router" });
|
|
747
|
+
if (lastProvider) {
|
|
748
|
+
const idx = providerOptions.findIndex((o) => o.value === lastProvider);
|
|
749
|
+
if (idx > 0) {
|
|
750
|
+
const [item] = providerOptions.splice(idx, 1);
|
|
751
|
+
providerOptions.unshift(item);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
571
754
|
const picked = await interactiveSelect("Select a provider:", providerOptions);
|
|
572
755
|
flags.agent = picked;
|
|
756
|
+
if (picked !== "router") {
|
|
757
|
+
await saveLastUsedProvider(cwd, picked);
|
|
758
|
+
}
|
|
573
759
|
}
|
|
574
760
|
if (!getStringFlag(flags, "model") && isTTYInteractive(flags) && !Boolean(flags.json)) {
|
|
575
761
|
const currentAgent = resolveRunAgent(flags, config.defaultAgent);
|
|
576
762
|
if (currentAgent !== "router") {
|
|
577
|
-
const
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
const modelInput = await interactiveInput("Model", hint);
|
|
581
|
-
if (modelInput && modelInput !== hint) {
|
|
582
|
-
flags.model = modelInput;
|
|
763
|
+
const modelChoices = getModelChoicesForProvider(currentAgent, config);
|
|
764
|
+
if (modelChoices.length > 0) {
|
|
765
|
+
flags.model = await interactiveSelect("Select a model:", modelChoices);
|
|
583
766
|
}
|
|
584
767
|
}
|
|
585
768
|
}
|
|
586
769
|
if (!getStringFlag(flags, "iterations") && isTTYInteractive(flags) && !Boolean(flags.json)) {
|
|
587
770
|
const fmIter = await readSweepIterationsFromFrontmatter(path.resolve(cwd, getStringFlag(flags, "prompt-file")));
|
|
588
771
|
const defaultIter = fmIter ? String(fmIter) : "1";
|
|
589
|
-
const
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
772
|
+
const iterOptions = [
|
|
773
|
+
{ label: `${defaultIter} (default)`, value: defaultIter },
|
|
774
|
+
...(defaultIter !== "1" ? [{ label: "1", value: "1" }] : []),
|
|
775
|
+
...(defaultIter !== "2" ? [{ label: "2", value: "2" }] : []),
|
|
776
|
+
...(defaultIter !== "3" ? [{ label: "3", value: "3" }] : []),
|
|
777
|
+
...(defaultIter !== "5" ? [{ label: "5", value: "5" }] : []),
|
|
778
|
+
];
|
|
779
|
+
flags.iterations = await interactiveSelect("Select iterations:", iterOptions);
|
|
593
780
|
}
|
|
594
781
|
const agent = resolveRunAgent(flags, config.defaultAgent);
|
|
782
|
+
const sweepModelFlag = getStringFlag(flags, "model");
|
|
783
|
+
if (sweepModelFlag && agent !== "router" && !Boolean(flags.json)) {
|
|
784
|
+
const resolvedP = resolveRunProvider(agent, providers, config.providerOrder);
|
|
785
|
+
const check = validateModelForProvider(sweepModelFlag, resolvedP);
|
|
786
|
+
if (!check.valid) {
|
|
787
|
+
console.log(`⚠ Model "${sweepModelFlag}" may not be available for ${resolvedP}.${check.suggestion ? ` Did you mean "${check.suggestion}"?` : ""}`);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
595
790
|
if (isTTYInteractive(flags) && !Boolean(flags.json) && !Boolean(flags["dry-run"])) {
|
|
596
791
|
const resolvedProvider = resolveRunProvider(agent, providers, config.providerOrder);
|
|
597
792
|
const resolvedModel = getStringFlag(flags, "model")?.trim() || config.modelOverrides[resolvedProvider]?.trim() || availableProviders.find((p) => p.provider === resolvedProvider)?.modelDefault || "auto";
|
|
@@ -599,19 +794,32 @@ async function runCommand(command, flags) {
|
|
|
599
794
|
const sweepFile = getStringFlag(flags, "prompt-file") || "(default)";
|
|
600
795
|
const iterTimeout = parsePositiveIntFlag(getStringFlag(flags, "iteration-timeout"), "iteration-timeout") ?? 5400;
|
|
601
796
|
const estMaxMs = parseInt(resolvedIter, 10) * iterTimeout * 1000;
|
|
797
|
+
const maxRetries = parseNonNegativeIntFlag(getStringFlag(flags, "max-retries"), "max-retries") ?? 2;
|
|
602
798
|
console.log("");
|
|
603
|
-
console.log(
|
|
604
|
-
console.log(
|
|
605
|
-
console.log(
|
|
606
|
-
console.log(
|
|
607
|
-
console.log(
|
|
799
|
+
console.log(colorize("╔══════════════════════════════════════════════════════════════╗", "\x1b[36m"));
|
|
800
|
+
console.log(colorize("║ Prompts-GPT Sweep ║", "\x1b[36m"));
|
|
801
|
+
console.log(colorize("╠══════════════════════════════════════════════════════════════╣", "\x1b[36m"));
|
|
802
|
+
console.log(`${colorize("║", "\x1b[36m")} Sweep: ${path.basename(sweepFile).padEnd(46)} ${colorize("║", "\x1b[36m")}`);
|
|
803
|
+
console.log(`${colorize("║", "\x1b[36m")} Provider: ${resolvedProvider.padEnd(46)} ${colorize("║", "\x1b[36m")}`);
|
|
804
|
+
console.log(`${colorize("║", "\x1b[36m")} Model: ${resolvedModel.padEnd(46)} ${colorize("║", "\x1b[36m")}`);
|
|
805
|
+
console.log(`${colorize("║", "\x1b[36m")} Iterations: ${resolvedIter.padEnd(46)} ${colorize("║", "\x1b[36m")}`);
|
|
806
|
+
console.log(`${colorize("║", "\x1b[36m")} Timeout: ${`${formatDuration(iterTimeout * 1000)} per iteration`.padEnd(46)} ${colorize("║", "\x1b[36m")}`);
|
|
807
|
+
console.log(`${colorize("║", "\x1b[36m")} Max time: ${`~${formatDuration(estMaxMs)}`.padEnd(46)} ${colorize("║", "\x1b[36m")}`);
|
|
808
|
+
console.log(`${colorize("║", "\x1b[36m")} Retries: ${String(maxRetries).padEnd(46)} ${colorize("║", "\x1b[36m")}`);
|
|
809
|
+
console.log(colorize("╚══════════════════════════════════════════════════════════════╝", "\x1b[36m"));
|
|
608
810
|
console.log("");
|
|
609
|
-
const
|
|
610
|
-
|
|
811
|
+
const confirmOpts = [
|
|
812
|
+
{ label: "Yes, run this sweep", value: "y" },
|
|
813
|
+
{ label: "Cancel", value: "n" },
|
|
814
|
+
];
|
|
815
|
+
const confirm = await interactiveSelect("Run this sweep?", confirmOpts);
|
|
816
|
+
if (confirm === "n") {
|
|
611
817
|
console.log("Cancelled.");
|
|
612
818
|
return;
|
|
613
819
|
}
|
|
614
820
|
}
|
|
821
|
+
const quiet = Boolean(flags.quiet);
|
|
822
|
+
const summaryLineCount = parsePositiveIntFlag(getStringFlag(flags, "summary-lines"), "summary-lines") ?? 40;
|
|
615
823
|
const onProgress = Boolean(flags.json)
|
|
616
824
|
? undefined
|
|
617
825
|
: (event) => {
|
|
@@ -620,43 +828,107 @@ async function runCommand(command, flags) {
|
|
|
620
828
|
console.log(`Provider: ${report.provider} | Model: ${report.model} | Iterations: ${report.iterations}`);
|
|
621
829
|
console.log(`Branch: ${report.gitBranch} | Dirty files: ${report.gitDirtyFiles} | Free disk: ${report.diskFreeMb}MB`);
|
|
622
830
|
console.log(`Prompt: ${path.basename(report.promptFile)}`);
|
|
831
|
+
try {
|
|
832
|
+
const fs = require("node:fs");
|
|
833
|
+
const skillDir = path.resolve(cwd, ".agents", "skills");
|
|
834
|
+
const ruleDir = path.resolve(cwd, ".cursor", "rules");
|
|
835
|
+
const skillCount = fs.existsSync(skillDir) ? fs.readdirSync(skillDir, { recursive: true }).filter((f) => String(f).endsWith("SKILL.md")).length : 0;
|
|
836
|
+
const ruleCount = fs.existsSync(ruleDir) ? fs.readdirSync(ruleDir).filter((f) => String(f).endsWith(".mdc")).length : 0;
|
|
837
|
+
const mcpConfig = fs.existsSync(path.resolve(cwd, ".cursor", "mcp.json")) ? "found" : "none";
|
|
838
|
+
console.log(`Skills: ${skillCount} | Rules: ${ruleCount} | MCP config: ${mcpConfig}`);
|
|
839
|
+
}
|
|
840
|
+
catch { /* skip */ }
|
|
841
|
+
const maxRunDirs = parsePositiveIntFlag(getStringFlag(flags, "max-run-dirs"), "max-run-dirs") ?? 20;
|
|
842
|
+
console.log(`Log rotation: keep ${maxRunDirs} runs`);
|
|
623
843
|
for (const w of report.warnings)
|
|
624
844
|
console.log(`⚠ ${w}`);
|
|
625
845
|
}
|
|
626
846
|
else if (event.type === "iteration_start") {
|
|
627
|
-
console.log(`\n
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
process.stdout.write(`\r${frames[fi++ % frames.length]} Running ${event.provider}... ${elapsed} `);
|
|
635
|
-
}, 120);
|
|
636
|
-
spinner.unref?.();
|
|
637
|
-
const clearSpinner = () => { clearInterval(spinner); process.stdout.write("\r\x1b[K"); };
|
|
638
|
-
globalThis.__sweepSpinner = clearSpinner;
|
|
847
|
+
console.log(`\n${colorize("══════════════════════════════════════════════════════════════", "\x1b[35m")}`);
|
|
848
|
+
console.log(colorize(`[${new Date().toLocaleTimeString()}] Iteration ${event.iteration}/${event.total}: ${event.provider} (${event.model})`, "\x1b[1;35m"));
|
|
849
|
+
console.log(colorize("══════════════════════════════════════════════════════════════", "\x1b[35m"));
|
|
850
|
+
}
|
|
851
|
+
else if (event.type === "message") {
|
|
852
|
+
if (!quiet) {
|
|
853
|
+
console.log(` ${colorize(`[${event.elapsed}]`, "\x1b[36m")} 💬 ${event.text.slice(0, 120)}`);
|
|
639
854
|
}
|
|
640
855
|
}
|
|
641
|
-
else if (event.type === "
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
856
|
+
else if (event.type === "tool") {
|
|
857
|
+
if (!quiet) {
|
|
858
|
+
const c = event.counts;
|
|
859
|
+
let icon = "🔧";
|
|
860
|
+
if (event.action.includes("read"))
|
|
861
|
+
icon = "📖";
|
|
862
|
+
else if (event.action.includes("write") || event.action.includes("edit"))
|
|
863
|
+
icon = "✏️ ";
|
|
864
|
+
else if (event.action.includes("shell") || event.action === "bash")
|
|
865
|
+
icon = "⚡";
|
|
866
|
+
else if (event.action.includes("search") || event.action.includes("grep") || event.action.includes("glob"))
|
|
867
|
+
icon = "🔍";
|
|
868
|
+
else if (event.action.includes("todo"))
|
|
869
|
+
icon = "📋";
|
|
870
|
+
const fileStr = event.file ? ` ${colorize(event.file, "\x1b[90m")}` : "";
|
|
871
|
+
const countStr = colorize(`(R:${c.reads} W:${c.writes} S:${c.shells} 🔍:${c.searches})`, "\x1b[90m");
|
|
872
|
+
console.log(` ${icon} ${event.action}${fileStr} ${countStr}`);
|
|
646
873
|
}
|
|
874
|
+
}
|
|
875
|
+
else if (event.type === "iteration_end") {
|
|
647
876
|
const elapsed = formatDuration(event.durationMs);
|
|
648
|
-
const icon = event.status === "success" ? "✓" : "✗";
|
|
649
|
-
|
|
877
|
+
const icon = event.status === "success" ? colorize("✓", "\x1b[32m") : colorize("✗", "\x1b[31m");
|
|
878
|
+
const durations = globalThis.__sweepDurations || [];
|
|
879
|
+
durations.push(event.durationMs);
|
|
880
|
+
globalThis.__sweepDurations = durations;
|
|
881
|
+
const remaining = ((parseInt(String(getStringFlag(flags, "iterations"))) || 1) - event.iteration);
|
|
882
|
+
let etaStr = "";
|
|
883
|
+
if (remaining > 0 && durations.length > 0) {
|
|
884
|
+
const avgMs = durations.reduce((a, b) => a + b, 0) / durations.length;
|
|
885
|
+
etaStr = ` | ETA: ~${formatDuration(avgMs * remaining)}`;
|
|
886
|
+
}
|
|
887
|
+
console.log(`${icon} Iteration ${event.iteration} ${event.status} (${elapsed})${etaStr}`);
|
|
650
888
|
}
|
|
651
889
|
else if (event.type === "attempt_retry") {
|
|
652
|
-
console.log(`
|
|
890
|
+
console.log(colorize(` ⟳ Retry ${event.attempt}/${event.maxAttempts} for iteration ${event.iteration}, backoff ${event.backoffMs}ms`, "\x1b[33m"));
|
|
653
891
|
}
|
|
654
892
|
else if (event.type === "summary") {
|
|
655
|
-
|
|
656
|
-
|
|
893
|
+
if (summaryLineCount > 0) {
|
|
894
|
+
const preview = event.lines.slice(0, summaryLineCount);
|
|
895
|
+
console.log(`\n── Summary (iteration ${event.iteration}, ${preview.length}/${event.lines.length} lines) ──`);
|
|
896
|
+
for (const line of preview)
|
|
897
|
+
console.log(` ${line}`);
|
|
898
|
+
if (event.lines.length > summaryLineCount) {
|
|
899
|
+
console.log(` ... (${event.lines.length - summaryLineCount} more lines)`);
|
|
900
|
+
}
|
|
901
|
+
console.log("── End summary ──");
|
|
902
|
+
}
|
|
657
903
|
}
|
|
658
904
|
else if (event.type === "sweep_end") {
|
|
659
|
-
|
|
905
|
+
const r = event.result;
|
|
906
|
+
console.log("");
|
|
907
|
+
console.log(colorize("╔══════════════════════════════════════════════════════════════╗", "\x1b[36m"));
|
|
908
|
+
console.log(colorize("║ Sweep Complete ║", "\x1b[36m"));
|
|
909
|
+
console.log(colorize("╠══════════════════════════════════════════════════════════════╣", "\x1b[36m"));
|
|
910
|
+
console.log(`${colorize("║", "\x1b[36m")} Model: ${r.model.padEnd(45)} ${colorize("║", "\x1b[36m")}`);
|
|
911
|
+
console.log(`${colorize("║", "\x1b[36m")} Duration: ${formatDuration(r.totalDurationMs).padEnd(45)} ${colorize("║", "\x1b[36m")}`);
|
|
912
|
+
console.log(`${colorize("║", "\x1b[36m")} Iterations: ${String(r.totalIterations).padEnd(45)} ${colorize("║", "\x1b[36m")}`);
|
|
913
|
+
console.log(`${colorize("║", "\x1b[36m")} Succeeded: ${colorize(String(r.succeeded), "\x1b[32m").padEnd(54)} ${colorize("║", "\x1b[36m")}`);
|
|
914
|
+
if (r.failed > 0) {
|
|
915
|
+
console.log(`${colorize("║", "\x1b[36m")} Failed: ${colorize(String(r.failed), "\x1b[31m").padEnd(54)} ${colorize("║", "\x1b[36m")}`);
|
|
916
|
+
}
|
|
917
|
+
console.log(colorize("╠══════════════════════════════════════════════════════════════╣", "\x1b[36m"));
|
|
918
|
+
for (const iter of r.iterations) {
|
|
919
|
+
const statusColor = iter.status === "success" ? "\x1b[32m" : "\x1b[31m";
|
|
920
|
+
const iterLine = ` Iter ${iter.iteration}: ${colorize(iter.status.padEnd(16), statusColor)} ${formatDuration(iter.durationMs)}`;
|
|
921
|
+
console.log(`${colorize("║", "\x1b[36m")}${iterLine.padEnd(60)} ${colorize("║", "\x1b[36m")}`);
|
|
922
|
+
}
|
|
923
|
+
console.log(colorize("╚══════════════════════════════════════════════════════════════╝", "\x1b[36m"));
|
|
924
|
+
if (hasTokenUsage(r.tokenUsage)) {
|
|
925
|
+
const tu = r.tokenUsage;
|
|
926
|
+
console.log(`Tokens: ${formatTokenUsage(tu)}`);
|
|
927
|
+
const estCost = ((tu.inputTokens || 0) * 0.003 + (tu.outputTokens || 0) * 0.015) / 1000;
|
|
928
|
+
if (estCost > 0.001) {
|
|
929
|
+
console.log(`Estimated cost: ~$${estCost.toFixed(2)}`);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
660
932
|
}
|
|
661
933
|
};
|
|
662
934
|
const result = await sweepPrompt({
|
|
@@ -737,9 +1009,37 @@ async function runCommand(command, flags) {
|
|
|
737
1009
|
console.log("Inspect results:");
|
|
738
1010
|
console.log(` cat ${result.manifestFile}`);
|
|
739
1011
|
console.log(` ls ${result.runDir}`);
|
|
1012
|
+
if (Boolean(flags.open) && result.manifestFile) {
|
|
1013
|
+
try {
|
|
1014
|
+
const { spawn: openSpawn } = await import("node:child_process");
|
|
1015
|
+
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "notepad" : "xdg-open";
|
|
1016
|
+
openSpawn(openCmd, [result.manifestFile], { detached: true, stdio: "ignore" }).unref();
|
|
1017
|
+
}
|
|
1018
|
+
catch { /* ignore */ }
|
|
1019
|
+
}
|
|
740
1020
|
if (result.failed > 0) {
|
|
1021
|
+
const failedIters = result.iterations.filter((it) => it.status !== "success");
|
|
1022
|
+
for (const fi of failedIters) {
|
|
1023
|
+
try {
|
|
1024
|
+
const { readFile: fsRead } = await import("node:fs/promises");
|
|
1025
|
+
const logText = await fsRead(fi.logFile, "utf8");
|
|
1026
|
+
const tailLines = logText.split("\n").slice(-80);
|
|
1027
|
+
if (tailLines.length > 0) {
|
|
1028
|
+
console.log(`\n── Last 80 lines of iteration ${fi.iteration} log ──`);
|
|
1029
|
+
for (const line of tailLines)
|
|
1030
|
+
console.log(` ${line}`);
|
|
1031
|
+
console.log("── End log tail ──");
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
catch { /* skip */ }
|
|
1035
|
+
}
|
|
741
1036
|
process.exitCode = 1;
|
|
742
1037
|
}
|
|
1038
|
+
console.log("\nNext steps:");
|
|
1039
|
+
console.log(" 1. Review iteration summaries in the run directory");
|
|
1040
|
+
if (result.failed > 0) {
|
|
1041
|
+
console.log(` 2. Re-run failed: prompts-gpt sweep -f ${getStringFlag(flags, "prompt-file")} -n ${result.failed}`);
|
|
1042
|
+
}
|
|
743
1043
|
return;
|
|
744
1044
|
}
|
|
745
1045
|
if (command === "quickstart") {
|
|
@@ -750,7 +1050,32 @@ async function runCommand(command, flags) {
|
|
|
750
1050
|
console.log("Prompts-GPT Quickstart");
|
|
751
1051
|
console.log("======================");
|
|
752
1052
|
console.log("");
|
|
1053
|
+
const { spawnSync: gitCheck } = await import("node:child_process");
|
|
1054
|
+
const gitResult = gitCheck("git", ["rev-parse", "--is-inside-work-tree"], { cwd, encoding: "utf8", timeout: 5000, windowsHide: true });
|
|
1055
|
+
if (gitResult.status !== 0) {
|
|
1056
|
+
console.log("⚠ Not inside a git repository. Prompts-GPT works best in a git repo for worktree tracking.");
|
|
1057
|
+
console.log(" Run: git init\n");
|
|
1058
|
+
}
|
|
753
1059
|
if (!assets.credentialsFound) {
|
|
1060
|
+
let networkOk = true;
|
|
1061
|
+
try {
|
|
1062
|
+
const netCheck = await Promise.race([
|
|
1063
|
+
fetch("https://prompts-gpt.com/api/health", { method: "HEAD" }),
|
|
1064
|
+
new Promise((_, rej) => setTimeout(() => rej(new Error("timeout")), 5000)),
|
|
1065
|
+
]);
|
|
1066
|
+
networkOk = netCheck instanceof Response;
|
|
1067
|
+
}
|
|
1068
|
+
catch {
|
|
1069
|
+
networkOk = false;
|
|
1070
|
+
}
|
|
1071
|
+
if (!networkOk) {
|
|
1072
|
+
console.log("⚠ Network unavailable. Quickstart requires internet for token validation.\n");
|
|
1073
|
+
console.log("You can still use local sweep files without a network connection:");
|
|
1074
|
+
console.log(" 1. Create .prompts-gpt/sweeps/<name>.md with your sweep prompt");
|
|
1075
|
+
console.log(" 2. Run: prompts-gpt sweep");
|
|
1076
|
+
console.log("\nWhen online, run `prompts-gpt quickstart` again.");
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
754
1079
|
console.log("Step 1: Save your project token");
|
|
755
1080
|
console.log(" prompts-gpt init --token-prompt");
|
|
756
1081
|
console.log("");
|
|
@@ -812,8 +1137,21 @@ async function runCommand(command, flags) {
|
|
|
812
1137
|
}
|
|
813
1138
|
}
|
|
814
1139
|
catch (syncErr) {
|
|
815
|
-
|
|
816
|
-
|
|
1140
|
+
const syncMsg = syncErr instanceof Error ? syncErr.message : String(syncErr);
|
|
1141
|
+
if (syncErr instanceof PromptsGptApiError && (syncErr.status === 401 || syncErr.status === 403)) {
|
|
1142
|
+
console.log(`✗ Authentication failed: ${syncMsg}`);
|
|
1143
|
+
console.log(" Your token may be invalid or expired. Re-run:");
|
|
1144
|
+
console.log(" prompts-gpt init --token-prompt");
|
|
1145
|
+
}
|
|
1146
|
+
else if (syncMsg.includes("ENOTFOUND") || syncMsg.includes("ECONNREFUSED") || syncMsg.includes("fetch") || syncMsg.includes("network")) {
|
|
1147
|
+
console.log(`✗ Network error: ${syncMsg}`);
|
|
1148
|
+
console.log(" Check your internet connection and try again.");
|
|
1149
|
+
console.log(" You can still use local sweep files without network access.");
|
|
1150
|
+
}
|
|
1151
|
+
else {
|
|
1152
|
+
console.log(`✗ Sync failed: ${syncMsg}`);
|
|
1153
|
+
console.log(" Run manually: prompts-gpt sync");
|
|
1154
|
+
}
|
|
817
1155
|
return;
|
|
818
1156
|
}
|
|
819
1157
|
const refreshedAssets = await discoverWorkspaceAssets(cwd);
|
|
@@ -840,7 +1178,8 @@ async function runCommand(command, flags) {
|
|
|
840
1178
|
const cmd = action === "sweep" ? "sweep" : "run";
|
|
841
1179
|
console.log(`\nRunning: prompts-gpt ${cmd} -f ${file}\n`);
|
|
842
1180
|
const { spawnSync: spSync } = await import("node:child_process");
|
|
843
|
-
const
|
|
1181
|
+
const cliEntry = process.argv[1] || require.resolve("./cli.js");
|
|
1182
|
+
const result = spSync(process.execPath, [cliEntry, cmd, "-f", file], { stdio: "inherit", cwd });
|
|
844
1183
|
process.exitCode = result.status ?? 1;
|
|
845
1184
|
return;
|
|
846
1185
|
}
|
|
@@ -877,13 +1216,21 @@ async function runCommand(command, flags) {
|
|
|
877
1216
|
const providers = await detectProviders(cwd);
|
|
878
1217
|
const availableProviders = providers.filter((p) => p.available);
|
|
879
1218
|
let configError = null;
|
|
880
|
-
|
|
1219
|
+
let doOverwrite = true;
|
|
1220
|
+
const existingConfig = existsSync(path.resolve(cwd, DEFAULT_RUN_CONFIG_PATH));
|
|
1221
|
+
if (existingConfig && isTTYInteractive() && !Boolean(flags.json)) {
|
|
1222
|
+
const confirmOverwrite = await interactiveInput("Existing run config found. Overwrite? [Y/n]", "Y");
|
|
1223
|
+
if (confirmOverwrite.toLowerCase() === "n" || confirmOverwrite.toLowerCase() === "no") {
|
|
1224
|
+
doOverwrite = false;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
const configResult = doOverwrite ? await initRunConfig({
|
|
881
1228
|
cwd,
|
|
882
1229
|
overwrite: true,
|
|
883
1230
|
}).catch((err) => {
|
|
884
1231
|
configError = err.message;
|
|
885
1232
|
return null;
|
|
886
|
-
});
|
|
1233
|
+
}) : null;
|
|
887
1234
|
if (Boolean(flags.json)) {
|
|
888
1235
|
console.log(JSON.stringify({
|
|
889
1236
|
project: { brandName: project.brandName, websiteUrl: project.websiteUrl },
|
|
@@ -923,7 +1270,8 @@ async function runCommand(command, flags) {
|
|
|
923
1270
|
let token = await resolveTokenInput(flags, { command });
|
|
924
1271
|
if (!token && process.stdin.isTTY && process.stdout.isTTY) {
|
|
925
1272
|
console.log("No token flag provided — prompting interactively.");
|
|
926
|
-
console.log("Get your token from: https://prompts-gpt.com/studio/projects
|
|
1273
|
+
console.log("Get your token from: https://prompts-gpt.com/studio/projects");
|
|
1274
|
+
console.log("Token format: pgpt_xxxxxxxxxxxxxxxx (starts with 'pgpt_')\n");
|
|
927
1275
|
token = await readTokenFromPrompt(command);
|
|
928
1276
|
}
|
|
929
1277
|
if (!token) {
|
|
@@ -963,6 +1311,17 @@ async function runCommand(command, flags) {
|
|
|
963
1311
|
});
|
|
964
1312
|
console.log(`Saved Prompts-GPT credentials to ${result.credentialsPath}`);
|
|
965
1313
|
console.log("The credentials file is added to .gitignore.");
|
|
1314
|
+
if (isTTYInteractive()) {
|
|
1315
|
+
console.log("");
|
|
1316
|
+
const runQs = await interactiveInput("Run quickstart now? [Y/n]", "Y");
|
|
1317
|
+
if (runQs.toLowerCase() !== "n" && runQs.toLowerCase() !== "no") {
|
|
1318
|
+
const { spawnSync: spSync } = await import("node:child_process");
|
|
1319
|
+
const cliEntry = process.argv[1] || require.resolve("./cli.js");
|
|
1320
|
+
const qsResult = spSync(process.execPath, [cliEntry, "quickstart", "--cwd", cwd], { stdio: "inherit", cwd });
|
|
1321
|
+
process.exitCode = qsResult.status ?? 1;
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
966
1325
|
console.log("");
|
|
967
1326
|
console.log("Next steps:");
|
|
968
1327
|
console.log(" prompts-gpt quickstart — interactive setup (recommended)");
|
|
@@ -977,19 +1336,29 @@ async function runCommand(command, flags) {
|
|
|
977
1336
|
console.log("No prompts matched the query. Try different filters or check the project prompt library.");
|
|
978
1337
|
return;
|
|
979
1338
|
}
|
|
1339
|
+
const pullCwd = getResolvedCwd(flags);
|
|
1340
|
+
const pullOutDir = getStringFlag(flags, "out") || DEFAULT_PROMPTS_GPT_OUT_DIR;
|
|
980
1341
|
const result = await writePromptMarkdownFiles(prompts, {
|
|
981
|
-
cwd:
|
|
982
|
-
outDir:
|
|
1342
|
+
cwd: pullCwd,
|
|
1343
|
+
outDir: pullOutDir,
|
|
983
1344
|
overwrite: Boolean(flags.overwrite),
|
|
984
1345
|
});
|
|
1346
|
+
const pullManifest = await writePromptManifest(prompts, { cwd: pullCwd, outDir: pullOutDir });
|
|
985
1347
|
console.log(`Wrote ${result.written.length} prompt file(s) to ${result.outDir}.`);
|
|
1348
|
+
console.log(`Updated manifest: ${pullManifest.manifestPath}`);
|
|
1349
|
+
if (Boolean(flags.overwrite)) {
|
|
1350
|
+
const agentResult = await writeAgentFiles(prompts, { cwd: pullCwd, agent: "all", overwriteAgentFiles: true });
|
|
1351
|
+
if (agentResult.written.length > 0) {
|
|
1352
|
+
console.log(`Updated ${agentResult.written.length} agent file(s): ${agentResult.targets.join(", ")}`);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
986
1355
|
if (result.skipped.length) {
|
|
987
1356
|
console.log(`Skipped ${result.skipped.length} existing file(s). Use --overwrite to replace them.`);
|
|
988
1357
|
}
|
|
989
1358
|
if (result.written.length > 0) {
|
|
990
1359
|
console.log("");
|
|
991
1360
|
console.log("Run a pulled prompt:");
|
|
992
|
-
console.log(` prompts-gpt run
|
|
1361
|
+
console.log(` prompts-gpt run -f ${result.written[0]}`);
|
|
993
1362
|
console.log(" prompts-gpt list — see all available prompts");
|
|
994
1363
|
}
|
|
995
1364
|
return;
|
|
@@ -1021,7 +1390,9 @@ async function runCommand(command, flags) {
|
|
|
1021
1390
|
const target = getStringFlag(flags, "agent") || "all";
|
|
1022
1391
|
const pulled = await client.pullPrompts().catch((err) => {
|
|
1023
1392
|
if (!Boolean(flags.json)) {
|
|
1024
|
-
console.error(
|
|
1393
|
+
console.error(`⚠ Could not pull existing prompts for agent sync: ${err.message}`);
|
|
1394
|
+
console.error(" Agent files will only include the newly generated prompt.");
|
|
1395
|
+
console.error(" Run \`prompts-gpt sync\` afterward to include all library prompts.");
|
|
1025
1396
|
}
|
|
1026
1397
|
return [];
|
|
1027
1398
|
});
|
|
@@ -1043,6 +1414,21 @@ async function runCommand(command, flags) {
|
|
|
1043
1414
|
if (result.skipped.length) {
|
|
1044
1415
|
console.log("Skipped existing generated prompt. Use --overwrite to replace it.");
|
|
1045
1416
|
}
|
|
1417
|
+
const genFile = result.written[0];
|
|
1418
|
+
if (genFile && isTTYInteractive()) {
|
|
1419
|
+
const genProviders = await detectProviders(cwd);
|
|
1420
|
+
if (genProviders.some((p) => p.available)) {
|
|
1421
|
+
console.log("");
|
|
1422
|
+
const runNow = await interactiveInput("Run this prompt now? [Y/n]", "Y");
|
|
1423
|
+
if (runNow.toLowerCase() !== "n" && runNow.toLowerCase() !== "no") {
|
|
1424
|
+
console.log(`\nRunning: prompts-gpt run -f ${genFile}\n`);
|
|
1425
|
+
const { spawnSync: spSync } = await import("node:child_process");
|
|
1426
|
+
const cliEntry = process.argv[1] || require.resolve("./cli.js");
|
|
1427
|
+
const genResult = spSync(process.execPath, [cliEntry, "run", "-f", genFile], { stdio: "inherit", cwd });
|
|
1428
|
+
process.exitCode = genResult.status ?? 1;
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1046
1432
|
return;
|
|
1047
1433
|
}
|
|
1048
1434
|
if (command === "sync") {
|
|
@@ -1052,7 +1438,18 @@ async function runCommand(command, flags) {
|
|
|
1052
1438
|
const prompts = [];
|
|
1053
1439
|
const goal = getStringFlag(flags, "goal");
|
|
1054
1440
|
const generatedOnly = Boolean(flags["generated-only"]);
|
|
1055
|
-
|
|
1441
|
+
let client;
|
|
1442
|
+
try {
|
|
1443
|
+
client = await createClientForCommand(command, flags);
|
|
1444
|
+
}
|
|
1445
|
+
catch (clientErr) {
|
|
1446
|
+
if (clientErr instanceof CliError && clientErr.exitCode === CLI_EXIT_CODES.auth) {
|
|
1447
|
+
throw new CliError(`Authentication failed. Your token may be invalid, expired, or lack the required scope.\n\n` +
|
|
1448
|
+
`Re-run: prompts-gpt init --token-prompt\n` +
|
|
1449
|
+
`Get a new token: https://prompts-gpt.com/studio/projects`, CLI_EXIT_CODES.auth, { helpCommand: "sync" });
|
|
1450
|
+
}
|
|
1451
|
+
throw clientErr;
|
|
1452
|
+
}
|
|
1056
1453
|
if (goal && !Boolean(flags.json)) {
|
|
1057
1454
|
printDataTransmissionNotice("sync", { goal, context: getStringFlag(flags, "context"), constraints: getStringFlag(flags, "constraints") });
|
|
1058
1455
|
}
|
|
@@ -1068,9 +1465,13 @@ async function runCommand(command, flags) {
|
|
|
1068
1465
|
});
|
|
1069
1466
|
}
|
|
1070
1467
|
if (Boolean(flags["dry-run"])) {
|
|
1071
|
-
|
|
1468
|
+
const agentTarget = getStringFlag(flags, "agent") || "all";
|
|
1469
|
+
console.log(`[dry-run] Would sync ${prompts.length} prompt(s) for agent target: ${agentTarget}`);
|
|
1072
1470
|
for (const p of prompts)
|
|
1073
1471
|
console.log(` - ${p.title} (${p.source})`);
|
|
1472
|
+
const targetList = agentTarget === "all" ? SUPPORTED_AGENT_TARGETS.join(", ") : agentTarget;
|
|
1473
|
+
console.log(`\n Agent file targets: ${targetList}`);
|
|
1474
|
+
console.log(` Output dir: ${getStringFlag(flags, "out") || DEFAULT_PROMPTS_GPT_OUT_DIR}`);
|
|
1074
1475
|
return;
|
|
1075
1476
|
}
|
|
1076
1477
|
const result = await syncPrompts(prompts, {
|
|
@@ -1124,6 +1525,18 @@ async function runCommand(command, flags) {
|
|
|
1124
1525
|
console.log(`Personas: ${formatList(project.targetPersonas)}`);
|
|
1125
1526
|
console.log(`Competitors: ${formatCompetitors(project.competitors)}`);
|
|
1126
1527
|
console.log(`API URL: ${apiUrl}`);
|
|
1528
|
+
if (isTTYInteractive()) {
|
|
1529
|
+
console.log("");
|
|
1530
|
+
const syncNow = await interactiveInput("Sync prompts from this project? [Y/n]", "Y");
|
|
1531
|
+
if (syncNow.toLowerCase() !== "n" && syncNow.toLowerCase() !== "no") {
|
|
1532
|
+
console.log("\nSyncing...");
|
|
1533
|
+
const { spawnSync: spSync } = await import("node:child_process");
|
|
1534
|
+
const cliEntry = process.argv[1] || require.resolve("./cli.js");
|
|
1535
|
+
const projCwd = getResolvedCwd(flags);
|
|
1536
|
+
const syncResult = spSync(process.execPath, [cliEntry, "sync", "--cwd", projCwd], { stdio: "inherit", cwd: projCwd });
|
|
1537
|
+
process.exitCode = syncResult.status ?? 1;
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1127
1540
|
return;
|
|
1128
1541
|
}
|
|
1129
1542
|
}
|
|
@@ -1145,6 +1558,9 @@ async function resolveClientOptions(command, flags) {
|
|
|
1145
1558
|
// CI fallback — never read process.env in the importable SDK, only in the CLI entrypoint
|
|
1146
1559
|
const envToken = process.env.PROMPTS_GPT_TOKEN?.trim();
|
|
1147
1560
|
if (envToken) {
|
|
1561
|
+
if (!envToken.startsWith("pgpt_")) {
|
|
1562
|
+
throw new CliError("PROMPTS_GPT_TOKEN env var must start with 'pgpt_'. Check the value.", CLI_EXIT_CODES.auth);
|
|
1563
|
+
}
|
|
1148
1564
|
return {
|
|
1149
1565
|
token: envToken,
|
|
1150
1566
|
apiUrl: explicitApiUrl || credentials?.apiUrl || DEFAULT_PROMPTS_GPT_API_URL,
|
|
@@ -1336,6 +1752,8 @@ function getCommandOptions(command) {
|
|
|
1336
1752
|
"permission-mode": { type: "string" },
|
|
1337
1753
|
"dry-run": { type: "boolean" },
|
|
1338
1754
|
"non-interactive": { type: "boolean" },
|
|
1755
|
+
verbose: { type: "boolean", short: "v" },
|
|
1756
|
+
open: { type: "boolean" },
|
|
1339
1757
|
};
|
|
1340
1758
|
}
|
|
1341
1759
|
if (command === "sweep") {
|
|
@@ -1360,6 +1778,9 @@ function getCommandOptions(command) {
|
|
|
1360
1778
|
background: { type: "boolean" },
|
|
1361
1779
|
"permission-mode": { type: "string" },
|
|
1362
1780
|
"non-interactive": { type: "boolean" },
|
|
1781
|
+
verbose: { type: "boolean", short: "v" },
|
|
1782
|
+
open: { type: "boolean" },
|
|
1783
|
+
quiet: { type: "boolean", short: "q" },
|
|
1363
1784
|
};
|
|
1364
1785
|
}
|
|
1365
1786
|
if (command === "run-batch") {
|
|
@@ -1373,6 +1794,7 @@ function getCommandOptions(command) {
|
|
|
1373
1794
|
model: { type: "string" },
|
|
1374
1795
|
timeout: { type: "string" },
|
|
1375
1796
|
"artifacts-dir": { type: "string" },
|
|
1797
|
+
"non-interactive": { type: "boolean" },
|
|
1376
1798
|
};
|
|
1377
1799
|
}
|
|
1378
1800
|
if (command === "load-config") {
|
|
@@ -1512,7 +1934,12 @@ async function readTokenFromStdin() {
|
|
|
1512
1934
|
}
|
|
1513
1935
|
chunks.push(buffer);
|
|
1514
1936
|
}
|
|
1515
|
-
|
|
1937
|
+
const combined = Buffer.concat(chunks);
|
|
1938
|
+
const result = combined.toString("utf8").trim();
|
|
1939
|
+
combined.fill(0);
|
|
1940
|
+
for (const chunk of chunks)
|
|
1941
|
+
chunk.fill(0);
|
|
1942
|
+
return result;
|
|
1516
1943
|
}
|
|
1517
1944
|
function readTokenFromPrompt(command) {
|
|
1518
1945
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
@@ -1588,6 +2015,7 @@ function readTokenFromPrompt(command) {
|
|
|
1588
2015
|
}
|
|
1589
2016
|
buf.write(char, bufLen, "utf8");
|
|
1590
2017
|
bufLen += charBytes;
|
|
2018
|
+
stdout.write("*");
|
|
1591
2019
|
}
|
|
1592
2020
|
}
|
|
1593
2021
|
};
|
|
@@ -1783,17 +2211,86 @@ function parseNonNegativeIntFlag(raw, flagName) {
|
|
|
1783
2211
|
}
|
|
1784
2212
|
return value;
|
|
1785
2213
|
}
|
|
2214
|
+
async function getLastUsedProvider(cwd) {
|
|
2215
|
+
try {
|
|
2216
|
+
const { readFile: fsRead } = await import("node:fs/promises");
|
|
2217
|
+
const data = JSON.parse(await fsRead(path.resolve(cwd, DEFAULT_PROMPTS_GPT_OUT_DIR, ".last-provider"), "utf8"));
|
|
2218
|
+
return data.provider ?? null;
|
|
2219
|
+
}
|
|
2220
|
+
catch {
|
|
2221
|
+
return null;
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
async function saveLastUsedProvider(cwd, provider) {
|
|
2225
|
+
try {
|
|
2226
|
+
const { writeFile: fsWrite, mkdir: fsMkdir } = await import("node:fs/promises");
|
|
2227
|
+
const dir = path.resolve(cwd, DEFAULT_PROMPTS_GPT_OUT_DIR);
|
|
2228
|
+
await fsMkdir(dir, { recursive: true });
|
|
2229
|
+
await fsWrite(path.resolve(dir, ".last-provider"), JSON.stringify({ provider, updatedAt: new Date().toISOString() }));
|
|
2230
|
+
}
|
|
2231
|
+
catch { /* ignore */ }
|
|
2232
|
+
}
|
|
2233
|
+
function validateModelForProvider(model, provider) {
|
|
2234
|
+
const allKnown = {
|
|
2235
|
+
codex: ["gpt-5.4-mini", "o4-mini", "o3", "gpt-5.1-codex", "gpt-4.1"],
|
|
2236
|
+
claude: ["claude-sonnet-4-6", "claude-4.5-opus", "claude-4.6-sonnet", "claude-haiku-3.5", "claude-4.6-opus-high", "claude-4.6-sonnet-high"],
|
|
2237
|
+
cursor: ["auto", "claude-4.6-sonnet", "gpt-5.4-mini", "claude-4.5-opus", "claude-4.6-opus-high", "claude-4.6-sonnet-high", "composer-2", "composer-2-fast", "gpt-5.3-codex"],
|
|
2238
|
+
copilot: ["auto", "gpt-5.4-mini", "claude-4.6-sonnet"],
|
|
2239
|
+
};
|
|
2240
|
+
const known = allKnown[provider] ?? [];
|
|
2241
|
+
if (known.length === 0)
|
|
2242
|
+
return { valid: true, suggestion: "" };
|
|
2243
|
+
if (known.includes(model))
|
|
2244
|
+
return { valid: true, suggestion: "" };
|
|
2245
|
+
const close = known.find((k) => k.startsWith(model.slice(0, 5)));
|
|
2246
|
+
return { valid: false, suggestion: close ?? known[0] ?? "" };
|
|
2247
|
+
}
|
|
2248
|
+
function getModelChoicesForProvider(provider, config) {
|
|
2249
|
+
const KNOWN_MODELS = {
|
|
2250
|
+
codex: [
|
|
2251
|
+
{ label: "gpt-5.4-mini (default)", value: "gpt-5.4-mini" },
|
|
2252
|
+
{ label: "o4-mini", value: "o4-mini" },
|
|
2253
|
+
{ label: "o3", value: "o3" },
|
|
2254
|
+
{ label: "gpt-5.1-codex", value: "gpt-5.1-codex" },
|
|
2255
|
+
{ label: "gpt-4.1", value: "gpt-4.1" },
|
|
2256
|
+
],
|
|
2257
|
+
claude: [
|
|
2258
|
+
{ label: "claude-sonnet-4-6 (default)", value: "claude-sonnet-4-6" },
|
|
2259
|
+
{ label: "claude-4.5-opus", value: "claude-4.5-opus" },
|
|
2260
|
+
{ label: "claude-4.6-sonnet", value: "claude-4.6-sonnet" },
|
|
2261
|
+
{ label: "claude-haiku-3.5", value: "claude-haiku-3.5" },
|
|
2262
|
+
],
|
|
2263
|
+
cursor: [
|
|
2264
|
+
{ label: "auto (default)", value: "auto" },
|
|
2265
|
+
{ label: "claude-4.6-sonnet", value: "claude-4.6-sonnet" },
|
|
2266
|
+
{ label: "gpt-5.4-mini", value: "gpt-5.4-mini" },
|
|
2267
|
+
{ label: "claude-4.5-opus", value: "claude-4.5-opus" },
|
|
2268
|
+
],
|
|
2269
|
+
copilot: [
|
|
2270
|
+
{ label: "auto (default)", value: "auto" },
|
|
2271
|
+
{ label: "gpt-5.4-mini", value: "gpt-5.4-mini" },
|
|
2272
|
+
{ label: "claude-4.6-sonnet", value: "claude-4.6-sonnet" },
|
|
2273
|
+
],
|
|
2274
|
+
};
|
|
2275
|
+
const choices = KNOWN_MODELS[provider] ?? [];
|
|
2276
|
+
const override = config.modelOverrides[provider]?.trim();
|
|
2277
|
+
if (override && !choices.some((c) => c.value === override)) {
|
|
2278
|
+
choices.unshift({ label: `${override} (configured)`, value: override });
|
|
2279
|
+
}
|
|
2280
|
+
return choices;
|
|
2281
|
+
}
|
|
1786
2282
|
function resolveRunAgent(flags, fallback) {
|
|
1787
2283
|
const raw = getStringFlag(flags, "agent");
|
|
1788
2284
|
if (!raw)
|
|
1789
2285
|
return fallback;
|
|
1790
|
-
const
|
|
1791
|
-
const
|
|
2286
|
+
const sanitized = raw.replace(/[;&|`$(){}!<>]/g, "").trim();
|
|
2287
|
+
const normalizedRaw = sanitized.toLowerCase();
|
|
2288
|
+
const normalized = normalizeOrchestrationAgent(sanitized);
|
|
1792
2289
|
if (normalized === "router" && normalizedRaw !== "router") {
|
|
1793
2290
|
const profiles = ORCHESTRATION_AGENT_PROFILES.join(", ");
|
|
1794
2291
|
const hint = ORCHESTRATION_AGENT_PROFILES.find((p) => p.startsWith(normalizedRaw.slice(0, 3)));
|
|
1795
2292
|
const suggestion = hint ? ` Did you mean "${hint}"?` : "";
|
|
1796
|
-
throw new CliError(`Invalid --agent target: ${
|
|
2293
|
+
throw new CliError(`Invalid --agent target: ${sanitized}. Use ${profiles}.${suggestion}`, CLI_EXIT_CODES.validation);
|
|
1797
2294
|
}
|
|
1798
2295
|
return normalized;
|
|
1799
2296
|
}
|
|
@@ -2270,9 +2767,11 @@ function interactiveSelect(prompt, options) {
|
|
|
2270
2767
|
let cursor = 0;
|
|
2271
2768
|
let escBuf = "";
|
|
2272
2769
|
const maxVisible = Math.min(options.length, (process.stdout.rows ?? 24) - 3);
|
|
2770
|
+
const useUnicode = supportsColor();
|
|
2771
|
+
const pointer = useUnicode ? "❯" : ">";
|
|
2273
2772
|
const formatLine = (i, selected) => {
|
|
2274
2773
|
const num = i < 9 ? `${i + 1}` : " ";
|
|
2275
|
-
const prefix = selected ? colorize(
|
|
2774
|
+
const prefix = selected ? colorize(pointer, "\x1b[36m") : " ";
|
|
2276
2775
|
const label = selected ? colorize(options[i].label, "\x1b[1m") : options[i].label;
|
|
2277
2776
|
return ` ${prefix} ${num}. ${label}`;
|
|
2278
2777
|
};
|
|
@@ -2293,7 +2792,8 @@ function interactiveSelect(prompt, options) {
|
|
|
2293
2792
|
else {
|
|
2294
2793
|
stdout.write("\n".repeat(2));
|
|
2295
2794
|
}
|
|
2296
|
-
|
|
2795
|
+
const posLabel = options.length > 1 ? ` (${cursor + 1}/${options.length})` : "";
|
|
2796
|
+
stdout.write(`${prompt}${posLabel}\n`);
|
|
2297
2797
|
const scrollStart = Math.max(0, Math.min(cursor - Math.floor(maxVisible / 2), options.length - maxVisible));
|
|
2298
2798
|
for (let vi = 0; vi < maxVisible; vi++) {
|
|
2299
2799
|
const i = scrollStart + vi;
|
|
@@ -2315,13 +2815,20 @@ function interactiveSelect(prompt, options) {
|
|
|
2315
2815
|
}
|
|
2316
2816
|
stdin.resume();
|
|
2317
2817
|
const cleanup = () => {
|
|
2318
|
-
|
|
2818
|
+
try {
|
|
2819
|
+
stdin.removeListener("data", onData);
|
|
2820
|
+
}
|
|
2821
|
+
catch { /* already destroyed */ }
|
|
2319
2822
|
try {
|
|
2320
2823
|
if (typeof stdin.setRawMode === "function")
|
|
2321
2824
|
stdin.setRawMode(false);
|
|
2322
2825
|
}
|
|
2323
2826
|
catch { /* ignore */ }
|
|
2324
|
-
|
|
2827
|
+
try {
|
|
2828
|
+
if (!stdin.destroyed)
|
|
2829
|
+
stdin.pause();
|
|
2830
|
+
}
|
|
2831
|
+
catch { /* ignore */ }
|
|
2325
2832
|
};
|
|
2326
2833
|
const onData = (data) => {
|
|
2327
2834
|
for (let ci = 0; ci < data.length; ci++) {
|
|
@@ -2389,13 +2896,12 @@ function interactiveSelect(prompt, options) {
|
|
|
2389
2896
|
stdin.on("data", onData);
|
|
2390
2897
|
});
|
|
2391
2898
|
}
|
|
2392
|
-
function interactiveInput(prompt, defaultValue) {
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
const { createInterface } = await import("node:readline");
|
|
2899
|
+
async function interactiveInput(prompt, defaultValue) {
|
|
2900
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
2901
|
+
throw new CliError("Interactive input requires a TTY.", CLI_EXIT_CODES.usage);
|
|
2902
|
+
}
|
|
2903
|
+
const { createInterface } = await import("node:readline");
|
|
2904
|
+
return new Promise((resolve) => {
|
|
2399
2905
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
2400
2906
|
const suffix = defaultValue ? ` (${defaultValue})` : "";
|
|
2401
2907
|
rl.question(`${prompt}${suffix}: `, (answer) => {
|
|
@@ -2416,7 +2922,9 @@ async function readSweepFrontmatter(filePath) {
|
|
|
2416
2922
|
if (val > 0 && val <= 50)
|
|
2417
2923
|
iterations = val;
|
|
2418
2924
|
}
|
|
2419
|
-
const
|
|
2925
|
+
const fmEnd = content.indexOf("---", content.indexOf("---") + 3);
|
|
2926
|
+
const bodyStart = fmEnd > 0 ? fmEnd + 3 : 0;
|
|
2927
|
+
const titleMatch = content.slice(bodyStart).match(/^#\s+(.+)/m);
|
|
2420
2928
|
if (titleMatch) {
|
|
2421
2929
|
title = titleMatch[1].trim();
|
|
2422
2930
|
}
|
|
@@ -2441,7 +2949,15 @@ function buildGenerateInput(flags) {
|
|
|
2441
2949
|
};
|
|
2442
2950
|
}
|
|
2443
2951
|
function sanitizeGenerateInput(value) {
|
|
2444
|
-
return value
|
|
2952
|
+
return value
|
|
2953
|
+
.replace(/pgpt_[a-zA-Z0-9]{4,}/g, "pgpt_***")
|
|
2954
|
+
.replace(/sk-[a-zA-Z0-9]{20,}/g, "sk-***")
|
|
2955
|
+
.replace(/ghp_[a-zA-Z0-9]{36,}/g, "ghp_***")
|
|
2956
|
+
.replace(/ghu_[a-zA-Z0-9]{36,}/g, "ghu_***")
|
|
2957
|
+
.replace(/Bearer\s+[a-zA-Z0-9_.-]{20,}/gi, "Bearer ***")
|
|
2958
|
+
.replace(/xai-[a-zA-Z0-9]{20,}/g, "xai-***")
|
|
2959
|
+
.replace(/ANTHROPIC_API_KEY=[^\s]+/gi, "ANTHROPIC_API_KEY=***")
|
|
2960
|
+
.replace(/OPENAI_API_KEY=[^\s]+/gi, "OPENAI_API_KEY=***");
|
|
2445
2961
|
}
|
|
2446
2962
|
function printDataTransmissionNotice(command, input) {
|
|
2447
2963
|
console.log(`[notice] The --goal text${input.context ? ", --context" : ""}${input.constraints ? ", --constraints" : ""} you provided will be sent to prompts-gpt.com to generate a prompt.`);
|