@prompts-gpt/client 0.2.0 → 0.2.3

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 CHANGED
@@ -1,186 +1,1248 @@
1
1
  #!/usr/bin/env node
2
- import { DEFAULT_PROMPTS_GPT_API_URL, DEFAULT_PROMPTS_GPT_OUT_DIR, PromptsGptApiError, PromptsGptClient, SUPPORTED_AGENT_TARGETS, loadLocalCredentials, saveLocalCredentials, syncPrompts, writeAgentFiles, writePromptMarkdownFiles, } from "./index.js";
3
- const CLI_EXIT_CODES = { success: 0, general: 1, auth: 2, validation: 3 };
2
+ import { existsSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { parseArgs } from "node:util";
5
+ import { 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, sweepPrompt, validateRunConfig, discoverWorkspaceAssets, SUPPORTED_AGENT_TARGETS, detectProviders, loadLocalCredentials, saveLocalCredentials, syncPrompts, writeAgentFiles, writePromptManifest, writePromptMarkdownFiles, } from "./index.js";
6
+ const CLI_EXIT_CODES = {
7
+ success: 0,
8
+ general: 1,
9
+ auth: 2,
10
+ validation: 3,
11
+ rateLimit: 4,
12
+ usage: 64,
13
+ };
4
14
  const VALID_TOOLS = ["Codex", "Claude Code", "Cursor", "GitHub Copilot", "ChatGPT", "Gemini", "Perplexity", "Grok", "DeepSeek", "Claude"];
15
+ const COMMANDS = ["setup", "init", "project", "pull", "generate", "sync", "run", "run-batch", "sweep", "list", "status", "validate", "providers", "doctor", "load-config", "version", "help"];
16
+ const MAX_STDIN_TOKEN_LENGTH = 4_096;
17
+ class CliError extends Error {
18
+ exitCode;
19
+ helpCommand;
20
+ constructor(message, exitCode, options) {
21
+ super(message);
22
+ this.name = "CliError";
23
+ this.exitCode = exitCode;
24
+ this.helpCommand = options?.helpCommand;
25
+ }
26
+ }
5
27
  async function main() {
6
- const [command, ...args] = process.argv.slice(2);
7
- const flags = parseFlags(args);
8
- if (!command || command === "help" || flags.help) {
28
+ const argv = process.argv.slice(2);
29
+ if (argv.length === 0) {
30
+ printHelp();
31
+ console.log("Quick start:");
32
+ console.log(" prompts-gpt status — check workspace readiness");
33
+ console.log(" prompts-gpt list — see available prompts, sweeps, agents");
34
+ console.log(" prompts-gpt help <cmd> — detailed help for a command");
35
+ console.log("");
36
+ return;
37
+ }
38
+ const first = argv[0];
39
+ if (first === "--help") {
9
40
  printHelp();
10
41
  return;
11
42
  }
12
- if (command === "version" || command === "--version" || flags.version) {
13
- const version = await getCliVersion();
14
- console.log(`@prompts-gpt/client v${version}`);
43
+ if (first === "--version") {
44
+ await printVersion();
45
+ return;
46
+ }
47
+ if (first === "help") {
48
+ handleHelpCommand(argv.slice(1));
49
+ return;
50
+ }
51
+ if (first === "version") {
52
+ if (argv.length > 1) {
53
+ throw new CliError("The `version` command does not accept additional arguments.", CLI_EXIT_CODES.usage, {
54
+ helpCommand: "version",
55
+ });
56
+ }
57
+ await printVersion();
58
+ return;
59
+ }
60
+ const command = asCommandName(first);
61
+ if (!command) {
62
+ throw new CliError(`Unknown command: ${first}.`, CLI_EXIT_CODES.usage);
63
+ }
64
+ if (!isRunnableCommand(command)) {
65
+ throw new CliError(`Unknown command: ${first}.`, CLI_EXIT_CODES.usage, {
66
+ helpCommand: "help",
67
+ });
68
+ }
69
+ const flags = parseCommandFlags(command, argv.slice(1));
70
+ if (Boolean(flags.help)) {
71
+ printHelp(command);
72
+ return;
73
+ }
74
+ await runCommand(command, flags);
75
+ }
76
+ async function runCommand(command, flags) {
77
+ if (command === "providers") {
78
+ const cwd = getResolvedCwd(flags);
79
+ const providers = await detectProviders(cwd);
80
+ if (Boolean(flags.json)) {
81
+ console.log(JSON.stringify({ cwd, providers }, null, 2));
82
+ return;
83
+ }
84
+ console.log(`Workspace: ${cwd}`);
85
+ for (const provider of providers) {
86
+ console.log(`${provider.provider}: ${provider.available ? "available" : "missing"} | bin=${provider.bin} | model=${provider.modelDefault}${provider.version ? ` | version=${provider.version}` : ""}`);
87
+ }
88
+ return;
89
+ }
90
+ if (command === "setup") {
91
+ const cwd = getResolvedCwd(flags);
92
+ const providerOrder = getStringFlag(flags, "provider-order")
93
+ ?.split(",")
94
+ .map((item) => item.trim())
95
+ .filter(Boolean);
96
+ validateProviderOrderFlag(providerOrder);
97
+ const promptFile = getStringFlag(flags, "prompt-file");
98
+ const promptFiles = getStringFlag(flags, "prompt-files")
99
+ ?.split(",")
100
+ .map((item) => item.trim())
101
+ .filter(Boolean);
102
+ const result = await initRunConfig({
103
+ cwd,
104
+ promptFile,
105
+ manifestPath: getStringFlag(flags, "manifest"),
106
+ promptFiles,
107
+ promptDir: getStringFlag(flags, "prompt-dir"),
108
+ defaultAgent: resolveRunAgent(flags, "router"),
109
+ providerOrder,
110
+ artifactsDir: getStringFlag(flags, "artifacts-dir"),
111
+ timeoutSeconds: parsePositiveIntFlag(getStringFlag(flags, "timeout"), "timeout"),
112
+ retryCount: parseNonNegativeIntFlag(getStringFlag(flags, "retry-count"), "retry-count"),
113
+ disallowDestructiveGit: Boolean(flags["allow-destructive-git"]) ? false : true,
114
+ modelOverrides: {
115
+ codex: getStringFlag(flags, "codex-model"),
116
+ cursor: getStringFlag(flags, "cursor-model"),
117
+ claude: getStringFlag(flags, "claude-model"),
118
+ copilot: getStringFlag(flags, "copilot-model"),
119
+ },
120
+ overwrite: Boolean(flags.overwrite),
121
+ });
122
+ if (Boolean(flags.json)) {
123
+ console.log(JSON.stringify(result, null, 2));
124
+ return;
125
+ }
126
+ console.log(`Created run config: ${result.configPath}`);
127
+ console.log(`Default agent: ${result.config.defaultAgent ?? "router"}`);
128
+ console.log(`Provider order: ${(result.config.providerOrder ?? []).join(", ")}`);
129
+ if (result.sourceSummary.defaultPromptFile) {
130
+ console.log(`Default prompt file: ${result.sourceSummary.defaultPromptFile}`);
131
+ }
132
+ if (result.sourceSummary.manifestPath) {
133
+ console.log(`Batch default manifest: ${result.sourceSummary.manifestPath}`);
134
+ }
135
+ else if (result.sourceSummary.promptFiles.length > 0) {
136
+ console.log(`Batch default prompt files: ${result.sourceSummary.promptFiles.length}`);
137
+ }
138
+ else {
139
+ console.log("Batch default prompt sources: none detected");
140
+ }
141
+ console.log("Detected providers:");
142
+ for (const provider of result.providerSummary) {
143
+ console.log(`- ${provider.provider}: ${provider.available ? "available" : "missing"} | bin=${provider.bin}`);
144
+ }
145
+ console.log("Next steps:");
146
+ console.log(` prompts-gpt run${result.sourceSummary.defaultPromptFile ? "" : " --prompt-file <path>"}`);
147
+ console.log(" prompts-gpt run-batch");
148
+ console.log(" prompts-gpt list — see all runnable assets");
149
+ console.log(" prompts-gpt status — check workspace readiness");
150
+ console.log(" prompts-gpt validate — validate your config");
151
+ return;
152
+ }
153
+ if (command === "doctor") {
154
+ const cwd = getResolvedCwd(flags);
155
+ const report = await doctor(cwd);
156
+ if (Boolean(flags.json)) {
157
+ console.log(JSON.stringify(report, null, 2));
158
+ return;
159
+ }
160
+ console.log(`Workspace: ${report.cwd}`);
161
+ console.log(`Node: ${report.nodeVersion} | OS: ${report.osPlatform}/${report.osArch} | CPUs: ${report.cpuCount}`);
162
+ console.log(`Config: ${report.configFound ? "found" : "not found"} (${report.configPath})`);
163
+ for (const provider of report.providers) {
164
+ console.log(`${provider.provider}: ${provider.available ? "available" : "missing"} | bin=${provider.bin}${provider.version ? ` | version=${provider.version}` : ""}`);
165
+ if (!provider.available) {
166
+ console.log(` hint: ${provider.installHint}`);
167
+ }
168
+ }
169
+ for (const note of report.notes) {
170
+ console.log(`note: ${note}`);
171
+ }
172
+ return;
173
+ }
174
+ if (command === "list") {
175
+ const cwd = getResolvedCwd(flags);
176
+ const assets = await discoverWorkspaceAssets(cwd);
177
+ if (Boolean(flags.json)) {
178
+ console.log(JSON.stringify(assets, null, 2));
179
+ return;
180
+ }
181
+ console.log(`Workspace: ${cwd}`);
182
+ console.log("");
183
+ if (assets.prompts.length > 0) {
184
+ console.log(`Prompt packs (${assets.prompts.length}):`);
185
+ for (const p of assets.prompts) {
186
+ console.log(` ${p.slug} — ${p.title} [${p.source}]`);
187
+ console.log(` file: .prompts-gpt/${p.file}`);
188
+ console.log(` run: prompts-gpt run --prompt-file .prompts-gpt/${p.file}`);
189
+ }
190
+ console.log("");
191
+ }
192
+ else {
193
+ console.log("Prompt packs: none found");
194
+ console.log(" Run `prompts-gpt sync` to pull prompt packs, or `prompts-gpt pull` to download them.");
195
+ console.log("");
196
+ }
197
+ if (assets.sweeps.length > 0) {
198
+ console.log(`Sweep prompts (${assets.sweeps.length}):`);
199
+ for (const s of assets.sweeps) {
200
+ console.log(` ${s.name}`);
201
+ console.log(` file: ${s.file}`);
202
+ console.log(` sweep: prompts-gpt sweep --prompt-file ${s.file}`);
203
+ }
204
+ console.log("");
205
+ }
206
+ else {
207
+ console.log("Sweep prompts: none found");
208
+ console.log(" Create .prompts-gpt/sweeps/<name>.md to add sweep prompts.");
209
+ console.log("");
210
+ }
211
+ if (assets.agents.length > 0) {
212
+ console.log(`Agent integrations (${assets.agents.length}):`);
213
+ for (const a of assets.agents) {
214
+ console.log(` ${a.target} — ${a.file}`);
215
+ }
216
+ console.log("");
217
+ }
218
+ else {
219
+ console.log("Agent integrations: none synced");
220
+ console.log(" Run `prompts-gpt sync` to generate agent files.");
221
+ console.log("");
222
+ }
223
+ console.log(`Config: ${assets.configFound ? "found" : "not found — run `prompts-gpt setup`"}`);
224
+ console.log(`Manifest: ${assets.manifestFound ? "found" : "not found — run `prompts-gpt sync`"}`);
225
+ console.log(`Credentials: ${assets.credentialsFound ? "found" : "not found — run `prompts-gpt init --token <token>`"}`);
226
+ return;
227
+ }
228
+ if (command === "status") {
229
+ const cwd = getResolvedCwd(flags);
230
+ const assets = await discoverWorkspaceAssets(cwd);
231
+ const providers = await detectProviders(cwd);
232
+ const availableProviders = providers.filter((p) => p.available);
233
+ if (Boolean(flags.json)) {
234
+ console.log(JSON.stringify({ cwd, assets, providers }, null, 2));
235
+ return;
236
+ }
237
+ console.log(`Workspace: ${cwd}`);
238
+ console.log("");
239
+ console.log("Readiness:");
240
+ console.log(` Credentials: ${assets.credentialsFound ? "✓" : "✗ — run \`prompts-gpt init --token <token>\`"}`);
241
+ console.log(` Config: ${assets.configFound ? "✓" : "✗ — run \`prompts-gpt setup\`"}`);
242
+ console.log(` Manifest: ${assets.manifestFound ? "✓" : "✗ — run \`prompts-gpt sync\`"}`);
243
+ console.log(` Prompts: ${assets.prompts.length > 0 ? `✓ (${assets.prompts.length})` : "✗ — none found"}`);
244
+ console.log(` Sweeps: ${assets.sweeps.length > 0 ? `✓ (${assets.sweeps.length})` : "— none found"}`);
245
+ console.log(` Agents: ${assets.agents.length > 0 ? `✓ (${assets.agents.length} targets)` : "✗ — run \`prompts-gpt sync\`"}`);
246
+ console.log(` Providers: ${availableProviders.length > 0 ? `✓ (${availableProviders.map((p) => p.provider).join(", ")})` : "✗ — no CLI found"}`);
247
+ console.log("");
248
+ if (assets.prompts.length > 0 && availableProviders.length > 0) {
249
+ console.log("Ready to run:");
250
+ console.log(` prompts-gpt run --prompt-file .prompts-gpt/${assets.prompts[0].file}`);
251
+ if (assets.sweeps.length > 0) {
252
+ console.log(` prompts-gpt sweep --prompt-file ${assets.sweeps[0].file}`);
253
+ }
254
+ }
255
+ else {
256
+ console.log("Next steps:");
257
+ let step = 1;
258
+ if (!assets.credentialsFound)
259
+ console.log(` ${step++}. prompts-gpt init --token <project-token>`);
260
+ if (assets.prompts.length === 0)
261
+ console.log(` ${step++}. prompts-gpt sync`);
262
+ if (availableProviders.length === 0)
263
+ console.log(` ${step++}. Install a provider CLI (codex, cursor agent, claude, copilot)`);
264
+ if (!assets.configFound)
265
+ console.log(` ${step++}. prompts-gpt setup`);
266
+ }
267
+ return;
268
+ }
269
+ if (command === "validate") {
270
+ const cwd = getResolvedCwd(flags);
271
+ const result = await validateRunConfig(cwd);
272
+ if (Boolean(flags.json)) {
273
+ console.log(JSON.stringify(result, null, 2));
274
+ return;
275
+ }
276
+ console.log(`Config: ${result.configPath}`);
277
+ console.log(`Valid: ${result.valid ? "yes" : "no"}`);
278
+ for (const e of result.errors) {
279
+ console.log(` error: ${e}`);
280
+ }
281
+ for (const w of result.warnings) {
282
+ console.log(` warning: ${w}`);
283
+ }
284
+ if (result.valid && result.errors.length === 0 && result.warnings.length === 0) {
285
+ console.log(" No issues found.");
286
+ }
287
+ return;
288
+ }
289
+ if (command === "run") {
290
+ const cwd = getResolvedCwd(flags);
291
+ const promptFile = getStringFlag(flags, "prompt-file");
292
+ const config = await loadRunConfig(cwd);
293
+ warnOnConfigIssues(config);
294
+ if (!promptFile && !Boolean(flags.json)) {
295
+ if (!config.defaultPromptFile && config.batchDefaults.promptFiles.length === 0 && !config.batchDefaults.manifestPath) {
296
+ const assets = await discoverWorkspaceAssets(cwd);
297
+ if (assets.prompts.length > 0 || assets.sweeps.length > 0) {
298
+ console.log("No default prompt file configured. Available options:\n");
299
+ if (assets.prompts.length > 0) {
300
+ console.log("Prompt packs:");
301
+ for (const p of assets.prompts) {
302
+ console.log(` prompts-gpt run --prompt-file .prompts-gpt/${p.file}`);
303
+ }
304
+ }
305
+ if (assets.sweeps.length > 0) {
306
+ console.log("\nSweep prompts:");
307
+ for (const s of assets.sweeps) {
308
+ console.log(` prompts-gpt sweep --prompt-file ${s.file}`);
309
+ }
310
+ }
311
+ console.log("\nOr set a default: prompts-gpt setup --prompt-file <path>");
312
+ return;
313
+ }
314
+ }
315
+ }
316
+ const agent = resolveRunAgent(flags, config.defaultAgent);
317
+ const result = await runPrompt({
318
+ cwd,
319
+ promptFile,
320
+ agent,
321
+ model: getStringFlag(flags, "model"),
322
+ timeoutSeconds: parsePositiveIntFlag(getStringFlag(flags, "timeout"), "timeout"),
323
+ artifactsDir: getStringFlag(flags, "artifacts-dir"),
324
+ runId: getStringFlag(flags, "run-id"),
325
+ approveMcps: !Boolean(flags["no-approve-mcps"]),
326
+ sandboxMode: getStringFlag(flags, "sandbox"),
327
+ background: Boolean(flags.background),
328
+ permissionMode: getStringFlag(flags, "permission-mode"),
329
+ });
330
+ if (Boolean(flags.json)) {
331
+ console.log(JSON.stringify(result, null, 2));
332
+ return;
333
+ }
334
+ const agentLabel = getStringFlag(flags, "agent") ? result.provider : `${result.provider} (auto-selected)`;
335
+ console.log(`Run ID: ${result.runId}`);
336
+ console.log(`Provider: ${agentLabel} | Model: ${result.model}`);
337
+ console.log(`Exit code: ${result.exitCode}`);
338
+ console.log(`Duration: ${formatDuration(result.durationMs)}`);
339
+ console.log(`Run dir: ${result.runDir}`);
340
+ console.log(`Summary: ${result.summaryFile}`);
341
+ console.log(`Log: ${result.logFile}`);
342
+ return;
343
+ }
344
+ if (command === "run-batch") {
345
+ const cwd = getResolvedCwd(flags);
346
+ const promptFiles = getStringFlag(flags, "prompt-files")
347
+ ?.split(",")
348
+ .map((item) => item.trim())
349
+ .filter(Boolean);
350
+ const config = await loadRunConfig(cwd);
351
+ warnOnConfigIssues(config);
352
+ if (!promptFiles && !getStringFlag(flags, "manifest") && !Boolean(flags.json)) {
353
+ if (!config.batchDefaults.manifestPath && config.batchDefaults.promptFiles.length === 0) {
354
+ const assets = await discoverWorkspaceAssets(cwd);
355
+ if (assets.prompts.length > 0) {
356
+ console.log("No batch source configured. Available prompt packs:\n");
357
+ const fileList = assets.prompts.map((p) => `.prompts-gpt/${p.file}`).join(",");
358
+ console.log(` prompts-gpt run-batch --prompt-files ${fileList}`);
359
+ if (assets.manifestFound) {
360
+ console.log(` prompts-gpt run-batch --manifest .prompts-gpt/manifest.json`);
361
+ }
362
+ console.log("\nOr configure batch defaults: prompts-gpt setup");
363
+ return;
364
+ }
365
+ }
366
+ }
367
+ const agent = resolveRunAgent(flags, config.defaultAgent);
368
+ const result = await runBatch({
369
+ cwd,
370
+ manifestPath: getStringFlag(flags, "manifest"),
371
+ promptFiles,
372
+ agent,
373
+ model: getStringFlag(flags, "model"),
374
+ timeoutSeconds: parsePositiveIntFlag(getStringFlag(flags, "timeout"), "timeout"),
375
+ artifactsDir: getStringFlag(flags, "artifacts-dir"),
376
+ });
377
+ if (Boolean(flags.json)) {
378
+ console.log(JSON.stringify(result, null, 2));
379
+ return;
380
+ }
381
+ console.log(`Batch complete: total=${result.total} success=${result.success} failed=${result.failed}`);
382
+ for (const [idx, run] of result.results.entries()) {
383
+ const status = run.exitCode === 0 ? "ok" : "FAIL";
384
+ console.log(` [${idx + 1}/${result.total}] ${status} ${path.basename(run.promptFile)} -> ${run.provider} (exit=${run.exitCode}, ${formatDuration(run.durationMs)})`);
385
+ }
386
+ return;
387
+ }
388
+ if (command === "sweep") {
389
+ const cwd = getResolvedCwd(flags);
390
+ const sweepPromptFile = getStringFlag(flags, "prompt-file");
391
+ const config = await loadRunConfig(cwd);
392
+ warnOnConfigIssues(config);
393
+ if (!sweepPromptFile && !Boolean(flags.json)) {
394
+ if (!config.defaultPromptFile) {
395
+ const assets = await discoverWorkspaceAssets(cwd);
396
+ if (assets.sweeps.length > 0) {
397
+ console.log("No default prompt file configured. Available sweep prompts:\n");
398
+ for (const s of assets.sweeps) {
399
+ console.log(` prompts-gpt sweep --prompt-file ${s.file}`);
400
+ }
401
+ if (assets.prompts.length > 0) {
402
+ console.log("\nOr run a prompt pack instead:");
403
+ for (const p of assets.prompts.slice(0, 3)) {
404
+ console.log(` prompts-gpt run --prompt-file .prompts-gpt/${p.file}`);
405
+ }
406
+ }
407
+ console.log("\nOr set a default: prompts-gpt setup --prompt-file <path>");
408
+ return;
409
+ }
410
+ }
411
+ }
412
+ const agent = resolveRunAgent(flags, config.defaultAgent);
413
+ const onProgress = Boolean(flags.json)
414
+ ? undefined
415
+ : (event) => {
416
+ if (event.type === "preflight") {
417
+ const report = JSON.parse(event.message);
418
+ console.log(`[preflight] provider=${report.provider} model=${report.model} branch=${report.gitBranch} dirty=${report.gitDirtyFiles} disk=${report.diskFreeMb}MB iterations=${report.iterations}`);
419
+ console.log(`[preflight] prompt=${report.promptFile}`);
420
+ for (const w of report.warnings)
421
+ console.log(`[preflight] warning: ${w}`);
422
+ }
423
+ else if (event.type === "iteration_start") {
424
+ console.log(`\n--- Iteration ${event.iteration}/${event.total} ---`);
425
+ }
426
+ else if (event.type === "iteration_end") {
427
+ const elapsed = formatDuration(event.durationMs);
428
+ console.log(`--- Iteration ${event.iteration} ${event.status} (${elapsed}) ---`);
429
+ }
430
+ else if (event.type === "attempt_retry") {
431
+ console.log(`[retry] iteration ${event.iteration}, attempt ${event.attempt}/${event.maxAttempts}, backoff ${event.backoffMs}ms`);
432
+ }
433
+ else if (event.type === "summary") {
434
+ const preview = event.lines.slice(0, 5).join("\n");
435
+ console.log(`[summary] iteration ${event.iteration}:\n${preview}${event.lines.length > 5 ? `\n ... (${event.lines.length - 5} more lines)` : ""}`);
436
+ }
437
+ else if (event.type === "sweep_end") {
438
+ console.log(`\nSweep complete: ${event.result.succeeded}/${event.result.totalIterations} succeeded in ${formatDuration(event.result.totalDurationMs)}`);
439
+ }
440
+ };
441
+ const result = await sweepPrompt({
442
+ cwd,
443
+ promptFile: getStringFlag(flags, "prompt-file"),
444
+ agent,
445
+ model: getStringFlag(flags, "model"),
446
+ iterations: parsePositiveIntFlag(getStringFlag(flags, "iterations"), "iterations"),
447
+ iterationTimeoutSeconds: parsePositiveIntFlag(getStringFlag(flags, "iteration-timeout"), "iteration-timeout"),
448
+ maxRetries: parseNonNegativeIntFlag(getStringFlag(flags, "max-retries"), "max-retries"),
449
+ artifactsDir: getStringFlag(flags, "artifacts-dir"),
450
+ runId: getStringFlag(flags, "run-id"),
451
+ approveMcps: !Boolean(flags["no-approve-mcps"]),
452
+ sandboxMode: getStringFlag(flags, "sandbox"),
453
+ phase: getStringFlag(flags, "phase"),
454
+ dryRun: Boolean(flags["dry-run"]),
455
+ maxRunDirs: parsePositiveIntFlag(getStringFlag(flags, "max-run-dirs"), "max-run-dirs"),
456
+ summaryLines: parsePositiveIntFlag(getStringFlag(flags, "summary-lines"), "summary-lines"),
457
+ onProgress,
458
+ });
459
+ if (Boolean(flags.json)) {
460
+ console.log(JSON.stringify(result, null, 2));
461
+ return;
462
+ }
463
+ if (result.dryRun) {
464
+ console.log("[dry-run] Would execute sweep with:");
465
+ console.log(` Provider: ${result.provider}`);
466
+ console.log(` Model: ${result.model}`);
467
+ console.log(` Iterations: ${result.totalIterations}`);
468
+ console.log(` Prompt: ${result.promptFile}`);
469
+ return;
470
+ }
471
+ console.log(`Run ID: ${result.runId}`);
472
+ console.log(`Provider: ${result.provider} | Model: ${result.model}`);
473
+ console.log(`Prompt: ${result.promptFile}`);
474
+ console.log(`Iterations: ${result.succeeded}/${result.totalIterations} succeeded`);
475
+ console.log(`Duration: ${formatDuration(result.totalDurationMs)}`);
476
+ console.log(`Run dir: ${result.runDir}`);
477
+ console.log(`Manifest: ${result.manifestFile}`);
478
+ if (result.failed > 0) {
479
+ process.exitCode = 1;
480
+ }
481
+ return;
482
+ }
483
+ if (command === "load-config") {
484
+ const cwd = getResolvedCwd(flags);
485
+ const client = await createClientForCommand(command, flags);
486
+ const project = await client.getProject();
487
+ const prompts = await client.pullPrompts();
488
+ if (prompts.length === 0) {
489
+ console.log("No prompt packs found in the project library. Configure prompts in Prompts Studio first.");
490
+ console.log(` Open: https://prompts-gpt.com/studio/projects`);
491
+ return;
492
+ }
493
+ const result = await syncPrompts(prompts, {
494
+ cwd,
495
+ outDir: getStringFlag(flags, "out") || DEFAULT_PROMPTS_GPT_OUT_DIR,
496
+ overwrite: true,
497
+ agent: getStringFlag(flags, "agent") || "all",
498
+ });
499
+ const providers = await detectProviders(cwd);
500
+ const availableProviders = providers.filter((p) => p.available);
501
+ let configError = null;
502
+ const configResult = await initRunConfig({
503
+ cwd,
504
+ overwrite: true,
505
+ }).catch((err) => {
506
+ configError = err.message;
507
+ return null;
508
+ });
509
+ if (Boolean(flags.json)) {
510
+ console.log(JSON.stringify({
511
+ project: { brandName: project.brandName, websiteUrl: project.websiteUrl },
512
+ synced: { prompts: result.markdown.written.length, agents: result.agents.written.length },
513
+ providers: availableProviders.map((p) => p.provider),
514
+ config: configResult ? "created" : "skipped",
515
+ }, null, 2));
516
+ return;
517
+ }
518
+ console.log(`Loaded configuration from Prompts Studio for: ${project.brandName}`);
519
+ console.log(`Synced ${result.markdown.written.length} prompt pack(s) to ${result.markdown.outDir}`);
520
+ console.log(`Synced ${result.agents.written.length} agent file(s): ${result.agents.targets.join(", ")}`);
521
+ console.log(`Manifest: ${result.manifest.manifestPath}`);
522
+ if (configResult) {
523
+ console.log(`Config: ${configResult.configPath}`);
524
+ }
525
+ else if (configError) {
526
+ console.error(`[config] Skipped: ${configError}`);
527
+ }
528
+ if (availableProviders.length > 0 && result.manifest.manifest.prompts.length > 0) {
529
+ const firstFile = result.manifest.manifest.prompts[0]?.file;
530
+ if (firstFile) {
531
+ console.log(`\nReady to run:`);
532
+ console.log(` prompts-gpt run --prompt-file .prompts-gpt/${firstFile}`);
533
+ }
534
+ }
15
535
  return;
16
536
  }
17
537
  if (command === "init") {
18
- const token = flags.token;
19
- if (!token)
20
- throw new Error("Run `prompts-gpt init --token <project-token>`.");
21
- if (typeof token !== "string" || token.length > 256)
22
- throw new Error("Token value is invalid or too long.");
23
- if (!token.startsWith("pgpt_"))
24
- throw new Error("Token must start with 'pgpt_'. Copy the full token from the Prompts-GPT dashboard.");
538
+ const token = await resolveTokenInput(flags, { command });
539
+ if (!token) {
540
+ throw new CliError("Run `prompts-gpt init --token <project-token>`, `--token-stdin`, or `--token-prompt`.", CLI_EXIT_CODES.validation, {
541
+ helpCommand: "init",
542
+ });
543
+ }
544
+ if (token.length > 256) {
545
+ throw new CliError("Token value is invalid or too long.", CLI_EXIT_CODES.validation, {
546
+ helpCommand: "init",
547
+ });
548
+ }
549
+ if (!token.startsWith("pgpt_")) {
550
+ throw new CliError("Token must start with `pgpt_`. Copy the full token from the Prompts-GPT dashboard.", CLI_EXIT_CODES.validation, {
551
+ helpCommand: "init",
552
+ });
553
+ }
554
+ const cwd = getResolvedCwd(flags);
555
+ const apiUrlFlag = getStringFlag(flags, "api-url");
556
+ if (apiUrlFlag) {
557
+ try {
558
+ const parsed = new URL(apiUrlFlag);
559
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
560
+ throw new CliError("--api-url must use https or http.", CLI_EXIT_CODES.validation, { helpCommand: "init" });
561
+ }
562
+ }
563
+ catch (e) {
564
+ if (e instanceof CliError)
565
+ throw e;
566
+ throw new CliError(`--api-url is not a valid URL: ${apiUrlFlag}`, CLI_EXIT_CODES.validation, { helpCommand: "init" });
567
+ }
568
+ }
25
569
  const result = await saveLocalCredentials({
26
570
  token,
27
- apiUrl: flags.apiUrl || DEFAULT_PROMPTS_GPT_API_URL,
28
- cwd: flags.cwd || process.cwd(),
571
+ apiUrl: apiUrlFlag || DEFAULT_PROMPTS_GPT_API_URL,
572
+ cwd,
29
573
  });
30
574
  console.log(`Saved Prompts-GPT credentials to ${result.credentialsPath}`);
31
575
  console.log("The credentials file is added to .gitignore.");
32
- return;
33
- }
34
- const cwd = flags.cwd || process.cwd();
35
- const credentials = await loadLocalCredentials(cwd);
36
- const client = new PromptsGptClient({
37
- token: flags.token || credentials?.token || "",
38
- apiUrl: flags.apiUrl || credentials?.apiUrl || DEFAULT_PROMPTS_GPT_API_URL,
39
- fetch,
40
- });
41
- if (command === "project") {
42
- const project = await client.getProject();
43
- console.log(`${project.brandName} (${project.websiteUrl})`);
576
+ console.log("Next: prompts-gpt sync");
44
577
  return;
45
578
  }
46
579
  if (command === "pull") {
47
- const prompts = await client.pullPrompts(buildPullQuery(flags));
580
+ const parsedLimit = parseLimitFlag(getStringFlag(flags, "limit"));
581
+ const client = await createClientForCommand(command, flags);
582
+ const prompts = await client.pullPrompts(buildPullQuery(flags, parsedLimit));
48
583
  if (prompts.length === 0) {
49
584
  console.log("No prompts matched the query. Try different filters or check the project prompt library.");
50
585
  return;
51
586
  }
52
587
  const result = await writePromptMarkdownFiles(prompts, {
53
- cwd,
54
- outDir: flags.out || DEFAULT_PROMPTS_GPT_OUT_DIR,
588
+ cwd: getResolvedCwd(flags),
589
+ outDir: getStringFlag(flags, "out") || DEFAULT_PROMPTS_GPT_OUT_DIR,
55
590
  overwrite: Boolean(flags.overwrite),
56
591
  });
57
592
  console.log(`Wrote ${result.written.length} prompt file(s) to ${result.outDir}.`);
58
- if (result.skipped.length)
593
+ if (result.skipped.length) {
59
594
  console.log(`Skipped ${result.skipped.length} existing file(s). Use --overwrite to replace them.`);
595
+ }
60
596
  return;
61
597
  }
62
598
  if (command === "generate") {
63
- validateToolFlag(flags.tool);
64
- const prompt = await generatePromptFromFlags(client, flags);
599
+ validateToolFlag(getStringFlag(flags, "tool"));
600
+ const goal = getStringFlag(flags, "goal");
601
+ if (!goal) {
602
+ throw new CliError("Prompt generation requires `--goal`.", CLI_EXIT_CODES.validation, {
603
+ helpCommand: "generate",
604
+ });
605
+ }
606
+ validateAgentFlag(getStringFlag(flags, "agent"));
607
+ const client = await createClientForCommand(command, flags);
608
+ const prompt = await client.generatePrompt({
609
+ goal,
610
+ context: getStringFlag(flags, "context") || "",
611
+ constraints: getStringFlag(flags, "constraints") || "",
612
+ desiredOutput: getStringFlag(flags, "desired-output") || "A reusable prompt pack saved as Markdown.",
613
+ tool: getStringFlag(flags, "tool") || "Codex",
614
+ mode: getStringFlag(flags, "mode") || "implement",
615
+ artifactType: getStringFlag(flags, "artifact-type") || "prompt-file",
616
+ includeWebSearch: Boolean(flags["web-search"]),
617
+ });
618
+ const cwd = getResolvedCwd(flags);
65
619
  const result = await writePromptMarkdownFiles([prompt], {
66
620
  cwd,
67
- outDir: flags.out || DEFAULT_PROMPTS_GPT_OUT_DIR,
621
+ outDir: getStringFlag(flags, "out") || DEFAULT_PROMPTS_GPT_OUT_DIR,
68
622
  overwrite: Boolean(flags.overwrite),
69
623
  });
70
- const agentFlag = (flags.agent || flags.agents || flags.syncAgents);
71
- if (agentFlag) {
72
- const agentResult = await writeAgentFiles([prompt], {
624
+ const shouldSyncAgents = Boolean(flags["sync-agents"]) || typeof getStringFlag(flags, "agent") === "string";
625
+ if (shouldSyncAgents) {
626
+ const target = getStringFlag(flags, "agent") || "all";
627
+ const pulled = await client.pullPrompts().catch(() => []);
628
+ const syncedPrompts = mergePromptPacks([prompt, ...pulled]);
629
+ const agentResult = await writeAgentFiles(syncedPrompts, {
73
630
  cwd,
74
- agent: typeof agentFlag === "string" ? agentFlag : "all",
631
+ agent: target,
75
632
  overwriteAgentFiles: true,
76
633
  });
634
+ const manifestResult = await writePromptManifest(syncedPrompts, {
635
+ cwd,
636
+ outDir: getStringFlag(flags, "out") || DEFAULT_PROMPTS_GPT_OUT_DIR,
637
+ });
77
638
  console.log(`Synced ${agentResult.written.length} agent file(s) for ${agentResult.targets.join(", ")}.`);
639
+ console.log(`Updated manifest: ${manifestResult.manifestPath}`);
78
640
  }
79
641
  console.log(`Generated: ${prompt.title}`);
80
642
  console.log(`Wrote to ${result.written[0] ?? result.outDir}.`);
81
- if (result.skipped.length)
643
+ if (result.skipped.length) {
82
644
  console.log("Skipped existing generated prompt. Use --overwrite to replace it.");
645
+ }
83
646
  return;
84
647
  }
85
648
  if (command === "sync") {
86
- validateToolFlag(flags.tool);
649
+ validateToolFlag(getStringFlag(flags, "tool"));
650
+ validateAgentFlag(getStringFlag(flags, "agent"));
651
+ const parsedLimit = parseLimitFlag(getStringFlag(flags, "limit"));
87
652
  const prompts = [];
88
- if (flags.goal) {
89
- prompts.push(await generatePromptFromFlags(client, flags));
653
+ const goal = getStringFlag(flags, "goal");
654
+ const generatedOnly = Boolean(flags["generated-only"]);
655
+ const client = await createClientForCommand(command, flags);
656
+ if (goal) {
657
+ prompts.push(await client.generatePrompt({
658
+ goal,
659
+ context: getStringFlag(flags, "context") || "",
660
+ constraints: getStringFlag(flags, "constraints") || "",
661
+ desiredOutput: getStringFlag(flags, "desired-output") || "A reusable prompt pack saved as Markdown.",
662
+ tool: getStringFlag(flags, "tool") || "Codex",
663
+ mode: getStringFlag(flags, "mode") || "implement",
664
+ artifactType: getStringFlag(flags, "artifact-type") || "prompt-file",
665
+ includeWebSearch: Boolean(flags["web-search"]),
666
+ }));
90
667
  }
91
- if (!flags.generatedOnly) {
92
- prompts.push(...await client.pullPrompts(buildPullQuery(flags)));
668
+ if (!generatedOnly) {
669
+ prompts.push(...await client.pullPrompts(buildPullQuery(flags, parsedLimit)));
670
+ }
671
+ if (prompts.length === 0) {
672
+ throw new CliError("No prompts to sync. Provide `--goal` or remove `--generated-only`.", CLI_EXIT_CODES.validation, {
673
+ helpCommand: "sync",
674
+ });
675
+ }
676
+ if (Boolean(flags["dry-run"])) {
677
+ console.log(`[dry-run] Would sync ${prompts.length} prompt(s) for agent target: ${getStringFlag(flags, "agent") || "all"}.`);
678
+ for (const p of prompts)
679
+ console.log(` - ${p.title} (${p.source})`);
680
+ return;
93
681
  }
94
- if (prompts.length === 0)
95
- throw new Error("No prompts to sync. Provide --goal or remove --generated-only.");
96
682
  const result = await syncPrompts(prompts, {
97
- cwd,
98
- outDir: flags.out || DEFAULT_PROMPTS_GPT_OUT_DIR,
683
+ cwd: getResolvedCwd(flags),
684
+ outDir: getStringFlag(flags, "out") || DEFAULT_PROMPTS_GPT_OUT_DIR,
99
685
  overwrite: Boolean(flags.overwrite),
100
- agent: flags.agent || flags.agents || "all",
686
+ agent: getStringFlag(flags, "agent") || "all",
101
687
  });
102
- console.log(`Synced ${result.markdown.written.length} Markdown prompt file(s) to ${result.markdown.outDir}.`);
103
- console.log(`Synced ${result.agents.written.length} agent integration file(s): ${result.agents.targets.join(", ")}.`);
104
- console.log(`Updated manifest: ${result.manifest.manifestPath}`);
105
- if (result.markdown.skipped.length)
106
- console.log(`Skipped ${result.markdown.skipped.length} existing Markdown file(s). Use --overwrite to replace them.`);
688
+ console.log(`Synced ${result.markdown.written.length} new prompt file(s) to ${result.markdown.outDir}.`);
689
+ if (result.markdown.skipped.length) {
690
+ console.log(`Kept ${result.markdown.skipped.length} existing file(s) unchanged. Use --overwrite to replace.`);
691
+ }
692
+ console.log(`Synced ${result.agents.written.length} agent file(s): ${result.agents.targets.join(", ")}.`);
693
+ console.log(`Manifest: ${result.manifest.manifestPath}`);
107
694
  return;
108
695
  }
109
- if (command === "install-agents") {
110
- const prompts = await client.pullPrompts(buildPullQuery(flags));
111
- const result = await writeAgentFiles(prompts, {
112
- cwd,
113
- agent: flags.agent || flags.agents || "all",
114
- overwriteAgentFiles: true,
115
- });
116
- console.log(`Synced ${result.written.length} agent integration file(s): ${result.targets.join(", ")}.`);
696
+ if (command === "project") {
697
+ const clientOptions = await resolveClientOptions(command, flags);
698
+ const client = new PromptsGptClient(clientOptions);
699
+ const project = await client.getProject();
700
+ const apiUrl = clientOptions.apiUrl;
701
+ if (Boolean(flags.json)) {
702
+ console.log(JSON.stringify({
703
+ project,
704
+ apiUrl,
705
+ }, null, 2));
706
+ return;
707
+ }
708
+ console.log(`Project: ${project.brandName}`);
709
+ console.log(`Website: ${project.websiteUrl}`);
710
+ console.log(`Industry: ${project.industryCategory}`);
711
+ console.log(`Language: ${project.targetLanguage}`);
712
+ console.log(`Countries: ${formatList(project.targetCountries)}`);
713
+ console.log(`Aliases: ${formatList(project.brandAliases)}`);
714
+ console.log(`Keywords: ${formatList(project.productKeywords)}`);
715
+ console.log(`Personas: ${formatList(project.targetPersonas)}`);
716
+ console.log(`Competitors: ${formatCompetitors(project.competitors)}`);
717
+ console.log(`API URL: ${apiUrl}`);
117
718
  return;
118
719
  }
119
- throw new Error(`Unknown command: ${command}. Run \`prompts-gpt help\` for usage.`);
120
720
  }
121
- function buildPullQuery(flags) {
721
+ async function createClientForCommand(command, flags) {
722
+ return new PromptsGptClient(await resolveClientOptions(command, flags));
723
+ }
724
+ async function resolveClientOptions(command, flags) {
725
+ const cwd = getResolvedCwd(flags);
726
+ const explicitToken = await resolveTokenInput(flags, { command });
727
+ const explicitApiUrl = getStringFlag(flags, "api-url");
728
+ const credentialsPath = path.resolve(cwd, DEFAULT_PROMPTS_GPT_OUT_DIR, PROMPTS_GPT_CREDENTIALS_FILE);
729
+ const hasCredentialsFile = existsSync(credentialsPath);
730
+ const credentials = await loadLocalCredentials(cwd);
731
+ if (hasCredentialsFile && !credentials && !explicitToken) {
732
+ throw new CliError(`Could not read local credentials at ${credentialsPath}. Re-run \`prompts-gpt init --token <project-token>\` to replace the file.`, CLI_EXIT_CODES.auth, { helpCommand: command });
733
+ }
734
+ const token = explicitToken || credentials?.token || "";
735
+ if (!token && !process.stdin.isTTY) {
736
+ // CI fallback — never read process.env in the importable SDK, only in the CLI entrypoint
737
+ const envToken = process.env.PROMPTS_GPT_TOKEN?.trim();
738
+ if (envToken) {
739
+ return {
740
+ token: envToken,
741
+ apiUrl: explicitApiUrl || credentials?.apiUrl || DEFAULT_PROMPTS_GPT_API_URL,
742
+ fetch,
743
+ };
744
+ }
745
+ }
746
+ if (!token) {
747
+ throw new CliError("Project token is missing. Run `prompts-gpt init --token <project-token>` or pass `--token`, `--token-stdin`, or `--token-prompt` for this command.", CLI_EXIT_CODES.auth, { helpCommand: command });
748
+ }
122
749
  return {
123
- q: (flags.query || flags.q),
124
- category: flags.category,
125
- tool: flags.tool,
126
- outputType: flags.outputType,
127
- limit: flags.limit,
750
+ token,
751
+ apiUrl: explicitApiUrl || credentials?.apiUrl || DEFAULT_PROMPTS_GPT_API_URL,
752
+ fetch,
753
+ };
754
+ }
755
+ function buildPullQuery(flags, limit) {
756
+ return {
757
+ q: getStringFlag(flags, "query") || getStringFlag(flags, "q"),
758
+ category: getStringFlag(flags, "category"),
759
+ tool: getStringFlag(flags, "tool"),
760
+ outputType: getStringFlag(flags, "output-type"),
761
+ limit,
762
+ };
763
+ }
764
+ function parseCommandFlags(command, argv) {
765
+ const options = getCommandOptions(command);
766
+ try {
767
+ const result = parseArgs({
768
+ args: argv,
769
+ options,
770
+ allowPositionals: false,
771
+ strict: true,
772
+ });
773
+ const values = result.values;
774
+ validateFlagConflicts(command, values);
775
+ return values;
776
+ }
777
+ catch (error) {
778
+ throw toCliParseError(error, command);
779
+ }
780
+ }
781
+ function handleHelpCommand(argv) {
782
+ try {
783
+ const { positionals, values } = parseArgs({
784
+ args: argv,
785
+ options: { help: { type: "boolean" } },
786
+ allowPositionals: true,
787
+ strict: true,
788
+ });
789
+ if (values.help) {
790
+ printHelp();
791
+ return;
792
+ }
793
+ if (positionals.length > 1) {
794
+ throw new CliError("The `help` command accepts at most one command name.", CLI_EXIT_CODES.usage, {
795
+ helpCommand: "help",
796
+ });
797
+ }
798
+ if (positionals.length === 0) {
799
+ printHelp();
800
+ return;
801
+ }
802
+ const topic = asCommandName(positionals[0]);
803
+ if (!topic) {
804
+ throw new CliError(`Unknown help topic: ${positionals[0]}.`, CLI_EXIT_CODES.usage, {
805
+ helpCommand: "help",
806
+ });
807
+ }
808
+ printHelp(topic);
809
+ }
810
+ catch (error) {
811
+ if (error instanceof CliError)
812
+ throw error;
813
+ throw toCliParseError(error, "help");
814
+ }
815
+ }
816
+ function getCommandOptions(command) {
817
+ const common = {
818
+ help: { type: "boolean" },
819
+ token: { type: "string" },
820
+ "token-stdin": { type: "boolean" },
821
+ "token-prompt": { type: "boolean" },
822
+ "api-url": { type: "string" },
823
+ cwd: { type: "string" },
128
824
  };
825
+ if (command === "init") {
826
+ return common;
827
+ }
828
+ if (command === "setup") {
829
+ return {
830
+ help: { type: "boolean" },
831
+ cwd: { type: "string" },
832
+ json: { type: "boolean" },
833
+ overwrite: { type: "boolean" },
834
+ "prompt-file": { type: "string" },
835
+ "prompt-dir": { type: "string" },
836
+ manifest: { type: "string" },
837
+ "prompt-files": { type: "string" },
838
+ agent: { type: "string" },
839
+ "provider-order": { type: "string" },
840
+ timeout: { type: "string" },
841
+ "retry-count": { type: "string" },
842
+ "artifacts-dir": { type: "string" },
843
+ "allow-destructive-git": { type: "boolean" },
844
+ "codex-model": { type: "string" },
845
+ "cursor-model": { type: "string" },
846
+ "claude-model": { type: "string" },
847
+ "copilot-model": { type: "string" },
848
+ };
849
+ }
850
+ if (command === "project") {
851
+ return {
852
+ ...common,
853
+ json: { type: "boolean" },
854
+ };
855
+ }
856
+ if (command === "pull") {
857
+ return {
858
+ ...common,
859
+ query: { type: "string" },
860
+ q: { type: "string" },
861
+ category: { type: "string" },
862
+ tool: { type: "string" },
863
+ "output-type": { type: "string" },
864
+ limit: { type: "string" },
865
+ out: { type: "string" },
866
+ overwrite: { type: "boolean" },
867
+ };
868
+ }
869
+ if (command === "generate") {
870
+ return {
871
+ ...common,
872
+ goal: { type: "string" },
873
+ context: { type: "string" },
874
+ constraints: { type: "string" },
875
+ "desired-output": { type: "string" },
876
+ tool: { type: "string" },
877
+ mode: { type: "string" },
878
+ "artifact-type": { type: "string" },
879
+ "web-search": { type: "boolean" },
880
+ out: { type: "string" },
881
+ overwrite: { type: "boolean" },
882
+ agent: { type: "string" },
883
+ "sync-agents": { type: "boolean" },
884
+ };
885
+ }
886
+ if (command === "sync") {
887
+ return {
888
+ ...common,
889
+ goal: { type: "string" },
890
+ context: { type: "string" },
891
+ constraints: { type: "string" },
892
+ "desired-output": { type: "string" },
893
+ tool: { type: "string" },
894
+ mode: { type: "string" },
895
+ "artifact-type": { type: "string" },
896
+ "web-search": { type: "boolean" },
897
+ query: { type: "string" },
898
+ q: { type: "string" },
899
+ category: { type: "string" },
900
+ "output-type": { type: "string" },
901
+ limit: { type: "string" },
902
+ out: { type: "string" },
903
+ overwrite: { type: "boolean" },
904
+ agent: { type: "string" },
905
+ "generated-only": { type: "boolean" },
906
+ "dry-run": { type: "boolean" },
907
+ };
908
+ }
909
+ if (command === "run") {
910
+ return {
911
+ help: { type: "boolean" },
912
+ cwd: { type: "string" },
913
+ json: { type: "boolean" },
914
+ "prompt-file": { type: "string" },
915
+ agent: { type: "string" },
916
+ model: { type: "string" },
917
+ timeout: { type: "string" },
918
+ "artifacts-dir": { type: "string" },
919
+ "run-id": { type: "string" },
920
+ sandbox: { type: "string" },
921
+ "no-approve-mcps": { type: "boolean" },
922
+ background: { type: "boolean" },
923
+ "permission-mode": { type: "string" },
924
+ };
925
+ }
926
+ if (command === "sweep") {
927
+ return {
928
+ help: { type: "boolean" },
929
+ cwd: { type: "string" },
930
+ json: { type: "boolean" },
931
+ "prompt-file": { type: "string" },
932
+ agent: { type: "string" },
933
+ model: { type: "string" },
934
+ iterations: { type: "string" },
935
+ "iteration-timeout": { type: "string" },
936
+ "max-retries": { type: "string" },
937
+ "artifacts-dir": { type: "string" },
938
+ "run-id": { type: "string" },
939
+ sandbox: { type: "string" },
940
+ "no-approve-mcps": { type: "boolean" },
941
+ phase: { type: "string" },
942
+ "dry-run": { type: "boolean" },
943
+ "max-run-dirs": { type: "string" },
944
+ "summary-lines": { type: "string" },
945
+ background: { type: "boolean" },
946
+ "permission-mode": { type: "string" },
947
+ };
948
+ }
949
+ if (command === "run-batch") {
950
+ return {
951
+ help: { type: "boolean" },
952
+ cwd: { type: "string" },
953
+ json: { type: "boolean" },
954
+ manifest: { type: "string" },
955
+ "prompt-files": { type: "string" },
956
+ agent: { type: "string" },
957
+ model: { type: "string" },
958
+ timeout: { type: "string" },
959
+ "artifacts-dir": { type: "string" },
960
+ };
961
+ }
962
+ if (command === "load-config") {
963
+ return {
964
+ ...common,
965
+ json: { type: "boolean" },
966
+ out: { type: "string" },
967
+ agent: { type: "string" },
968
+ };
969
+ }
970
+ if (command === "list" || command === "status" || command === "validate" || command === "providers" || command === "doctor") {
971
+ return {
972
+ help: { type: "boolean" },
973
+ cwd: { type: "string" },
974
+ json: { type: "boolean" },
975
+ };
976
+ }
977
+ throw new CliError(`Unsupported command: ${command}.`, CLI_EXIT_CODES.usage, {
978
+ helpCommand: "help",
979
+ });
980
+ }
981
+ function toCliParseError(error, command) {
982
+ const message = normalizeParseErrorMessage(error instanceof Error ? error.message : String(error));
983
+ return new CliError(message, CLI_EXIT_CODES.usage, {
984
+ helpCommand: command,
985
+ });
986
+ }
987
+ function normalizeParseErrorMessage(message) {
988
+ const trimmed = message.trim();
989
+ if (trimmed.startsWith("Unknown option")) {
990
+ return `${trimmed}.`;
991
+ }
992
+ return trimmed;
993
+ }
994
+ function validateFlagConflicts(command, flags) {
995
+ const tokenSourceCount = [Boolean(flags.token), Boolean(flags["token-stdin"]), Boolean(flags["token-prompt"])].filter(Boolean).length;
996
+ if (tokenSourceCount > 1) {
997
+ throw new CliError("Use only one token source: `--token`, `--token-stdin`, or `--token-prompt`.", CLI_EXIT_CODES.usage, {
998
+ helpCommand: command,
999
+ });
1000
+ }
1001
+ if (flags.query && flags.q) {
1002
+ throw new CliError("Use either `--query` or `--q`, not both.", CLI_EXIT_CODES.usage, {
1003
+ helpCommand: command,
1004
+ });
1005
+ }
1006
+ const promptSourceCount = [
1007
+ Boolean(flags["prompt-file"]),
1008
+ Boolean(flags["prompt-files"]),
1009
+ Boolean(flags.manifest),
1010
+ Boolean(flags["prompt-dir"]),
1011
+ ].filter(Boolean).length;
1012
+ if (command === "setup" && promptSourceCount > 1) {
1013
+ throw new CliError("Use only one prompt source for `setup`: `--prompt-file`, `--prompt-files`, `--manifest`, or `--prompt-dir`.", CLI_EXIT_CODES.usage, {
1014
+ helpCommand: command,
1015
+ });
1016
+ }
1017
+ if (command === "run-batch" && Boolean(flags["prompt-files"]) && Boolean(flags.manifest)) {
1018
+ throw new CliError("Use either `--prompt-files` or `--manifest`, not both.", CLI_EXIT_CODES.usage, {
1019
+ helpCommand: command,
1020
+ });
1021
+ }
1022
+ }
1023
+ async function resolveTokenInput(flags, options) {
1024
+ const explicitToken = getStringFlag(flags, "token")?.trim();
1025
+ if (explicitToken) {
1026
+ return explicitToken;
1027
+ }
1028
+ if (flags["token-stdin"]) {
1029
+ const token = await readTokenFromStdin();
1030
+ if (!token) {
1031
+ throw new CliError("No token was received on stdin. Pipe a project token into `--token-stdin`.", CLI_EXIT_CODES.validation, {
1032
+ helpCommand: options.command,
1033
+ });
1034
+ }
1035
+ return token;
1036
+ }
1037
+ if (flags["token-prompt"]) {
1038
+ return readTokenFromPrompt(options.command);
1039
+ }
1040
+ return undefined;
1041
+ }
1042
+ async function readTokenFromStdin() {
1043
+ if (process.stdin.isTTY) {
1044
+ throw new CliError("`--token-stdin` expects piped input. Use `--token-prompt` for an interactive terminal.", CLI_EXIT_CODES.usage);
1045
+ }
1046
+ const chunks = [];
1047
+ let totalLength = 0;
1048
+ for await (const chunk of process.stdin) {
1049
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
1050
+ totalLength += buffer.length;
1051
+ if (totalLength > MAX_STDIN_TOKEN_LENGTH) {
1052
+ throw new CliError("Token input from stdin is too long.", CLI_EXIT_CODES.validation);
1053
+ }
1054
+ chunks.push(buffer);
1055
+ }
1056
+ return Buffer.concat(chunks).toString("utf8").trim();
1057
+ }
1058
+ function readTokenFromPrompt(command) {
1059
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
1060
+ throw new CliError("`--token-prompt` requires an interactive terminal. Use `--token-stdin` for CI or piped input.", CLI_EXIT_CODES.usage, {
1061
+ helpCommand: command,
1062
+ });
1063
+ }
1064
+ return new Promise((resolve, reject) => {
1065
+ const stdin = process.stdin;
1066
+ const stdout = process.stdout;
1067
+ const buf = Buffer.alloc(MAX_STDIN_TOKEN_LENGTH);
1068
+ let bufLen = 0;
1069
+ const cleanup = () => {
1070
+ stdin.removeListener("data", onData);
1071
+ process.removeListener("SIGTERM", onSigterm);
1072
+ process.removeListener("SIGINT", onSigint);
1073
+ stdin.setRawMode?.(false);
1074
+ stdin.pause();
1075
+ };
1076
+ const extractAndWipe = () => {
1077
+ const result = buf.toString("utf8", 0, bufLen).trim();
1078
+ buf.fill(0, 0, bufLen);
1079
+ bufLen = 0;
1080
+ return result;
1081
+ };
1082
+ const finish = (callback) => {
1083
+ stdout.write("\n");
1084
+ cleanup();
1085
+ callback();
1086
+ };
1087
+ const onSigterm = () => {
1088
+ buf.fill(0, 0, bufLen);
1089
+ cleanup();
1090
+ process.exit(130);
1091
+ };
1092
+ const onSigint = () => {
1093
+ buf.fill(0, 0, bufLen);
1094
+ cleanup();
1095
+ process.exit(130);
1096
+ };
1097
+ process.on("SIGTERM", onSigterm);
1098
+ process.on("SIGINT", onSigint);
1099
+ const onData = (chunk) => {
1100
+ const value = typeof chunk === "string" ? chunk : chunk.toString("utf8");
1101
+ for (const char of value) {
1102
+ if (char === "\u0003") {
1103
+ buf.fill(0, 0, bufLen);
1104
+ finish(() => reject(new CliError("Token entry cancelled.", CLI_EXIT_CODES.general, { helpCommand: command })));
1105
+ return;
1106
+ }
1107
+ if (char === "\r" || char === "\n") {
1108
+ const trimmed = extractAndWipe();
1109
+ if (!trimmed) {
1110
+ finish(() => reject(new CliError("Project token is required.", CLI_EXIT_CODES.validation, { helpCommand: command })));
1111
+ return;
1112
+ }
1113
+ finish(() => resolve(trimmed));
1114
+ return;
1115
+ }
1116
+ if (char === "\u007f" || char === "\b") {
1117
+ if (bufLen > 0) {
1118
+ bufLen--;
1119
+ buf[bufLen] = 0;
1120
+ }
1121
+ continue;
1122
+ }
1123
+ if (char >= " ") {
1124
+ const charBytes = Buffer.byteLength(char, "utf8");
1125
+ if (bufLen + charBytes > MAX_STDIN_TOKEN_LENGTH) {
1126
+ buf.fill(0, 0, bufLen);
1127
+ finish(() => reject(new CliError("Token input is too long.", CLI_EXIT_CODES.validation, { helpCommand: command })));
1128
+ return;
1129
+ }
1130
+ buf.write(char, bufLen, "utf8");
1131
+ bufLen += charBytes;
1132
+ }
1133
+ }
1134
+ };
1135
+ stdout.write("Project token: ");
1136
+ stdin.setEncoding("utf8");
1137
+ try {
1138
+ stdin.setRawMode?.(true);
1139
+ }
1140
+ catch {
1141
+ reject(new CliError("Cannot enable raw mode for token prompt. Use --token-stdin instead.", CLI_EXIT_CODES.usage, { helpCommand: command }));
1142
+ return;
1143
+ }
1144
+ stdin.resume();
1145
+ stdin.on("data", onData);
1146
+ });
1147
+ }
1148
+ function parseLimitFlag(raw) {
1149
+ if (raw === undefined)
1150
+ return undefined;
1151
+ if (!/^\d+$/.test(raw)) {
1152
+ throw new CliError("`--limit` must be a positive integer between 1 and 100.", CLI_EXIT_CODES.validation);
1153
+ }
1154
+ const value = Number.parseInt(raw, 10);
1155
+ if (!Number.isSafeInteger(value) || value < 1 || value > 100) {
1156
+ throw new CliError("`--limit` must be a positive integer between 1 and 100.", CLI_EXIT_CODES.validation);
1157
+ }
1158
+ return value;
129
1159
  }
130
1160
  function validateToolFlag(tool) {
131
1161
  if (!tool)
132
1162
  return;
133
1163
  const validSet = new Set(VALID_TOOLS);
134
1164
  if (!validSet.has(tool)) {
135
- throw new Error(`Invalid --tool "${tool}". Valid tools: ${VALID_TOOLS.join(", ")}.`);
136
- }
137
- }
138
- async function generatePromptFromFlags(client, flags) {
139
- const goal = flags.goal;
140
- if (!goal)
141
- throw new Error("Prompt generation requires --goal.");
142
- return client.generatePrompt({
143
- goal,
144
- context: flags.context || "",
145
- constraints: flags.constraints || "",
146
- desiredOutput: flags.desiredOutput || "A reusable prompt pack saved as Markdown.",
147
- tool: flags.tool || "Codex",
148
- mode: flags.mode || "implement",
149
- artifactType: flags.artifactType || "prompt-file",
150
- includeWebSearch: Boolean(flags.webSearch),
1165
+ throw new CliError(`Invalid --tool "${tool}". Valid tools: ${VALID_TOOLS.join(", ")}.`, CLI_EXIT_CODES.validation);
1166
+ }
1167
+ }
1168
+ function validateAgentFlag(agent) {
1169
+ if (!agent)
1170
+ return;
1171
+ const targets = agent.split(",").map((item) => item.trim().toLowerCase()).filter(Boolean);
1172
+ const validSet = new Set([...SUPPORTED_AGENT_TARGETS, "all"]);
1173
+ const invalid = [...new Set(targets.filter((target) => !validSet.has(target)))];
1174
+ if (invalid.length) {
1175
+ throw new CliError(`Invalid --agent target: ${invalid.join(", ")}. Use ${SUPPORTED_AGENT_TARGETS.join(", ")}, or all.`, CLI_EXIT_CODES.validation);
1176
+ }
1177
+ }
1178
+ function validateProviderOrderFlag(values) {
1179
+ if (!values?.length)
1180
+ return;
1181
+ const invalid = values.filter((value) => {
1182
+ const raw = value.trim().toLowerCase();
1183
+ const normalized = normalizeOrchestrationAgent(raw);
1184
+ return !raw || normalized === "router";
151
1185
  });
1186
+ if (invalid.length > 0) {
1187
+ throw new CliError(`Invalid --provider-order value: ${invalid.join(", ")}. Use codex, cursor, claude, or copilot.`, CLI_EXIT_CODES.validation);
1188
+ }
152
1189
  }
153
- const MAX_FLAG_VALUE_LENGTH = 2000;
154
- function parseFlags(args) {
155
- const flags = {};
156
- for (let index = 0; index < args.length; index += 1) {
157
- const arg = args[index];
158
- if (!arg.startsWith("--"))
159
- continue;
160
- const eqIndex = arg.indexOf("=");
161
- if (eqIndex !== -1) {
162
- const key = normalizeFlag(arg.slice(2, eqIndex));
163
- if (!key || key.length > 64)
164
- continue;
165
- flags[key] = arg.slice(eqIndex + 1).slice(0, MAX_FLAG_VALUE_LENGTH);
166
- continue;
167
- }
168
- const key = normalizeFlag(arg.slice(2));
169
- if (!key || key.length > 64)
170
- continue;
171
- const next = args[index + 1];
172
- if (!next || next.startsWith("--")) {
173
- flags[key] = true;
174
- }
175
- else {
176
- flags[key] = String(next).slice(0, MAX_FLAG_VALUE_LENGTH);
177
- index += 1;
178
- }
1190
+ function getResolvedCwd(flags) {
1191
+ return path.resolve(getStringFlag(flags, "cwd") || process.cwd());
1192
+ }
1193
+ function getStringFlag(flags, name) {
1194
+ const value = flags[name];
1195
+ return typeof value === "string" ? value : undefined;
1196
+ }
1197
+ function formatDuration(ms) {
1198
+ if (ms < 1000)
1199
+ return `${ms}ms`;
1200
+ const totalSeconds = Math.round(ms / 1000);
1201
+ const hours = Math.floor(totalSeconds / 3600);
1202
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
1203
+ const seconds = totalSeconds % 60;
1204
+ if (hours > 0)
1205
+ return `${hours}h ${minutes}m ${seconds}s`;
1206
+ if (minutes > 0)
1207
+ return `${minutes}m ${seconds}s`;
1208
+ return `${seconds}s`;
1209
+ }
1210
+ function formatList(values) {
1211
+ if (!Array.isArray(values) || values.length === 0)
1212
+ return "None";
1213
+ return values.join(", ");
1214
+ }
1215
+ function formatCompetitors(values) {
1216
+ if (!Array.isArray(values) || values.length === 0)
1217
+ return "None";
1218
+ return values.map((competitor) => {
1219
+ const aliases = competitor.aliases?.length ? ` [aliases: ${competitor.aliases.join(", ")}]` : "";
1220
+ return competitor.websiteUrl ? `${competitor.name} (${competitor.websiteUrl})${aliases}` : `${competitor.name}${aliases}`;
1221
+ }).join("; ");
1222
+ }
1223
+ function mergePromptPacks(prompts) {
1224
+ const deduped = new Map();
1225
+ for (const prompt of prompts) {
1226
+ deduped.set(normalizePromptKey(prompt), prompt);
179
1227
  }
180
- return flags;
1228
+ return [...deduped.values()];
1229
+ }
1230
+ function normalizePromptKey(prompt) {
1231
+ const raw = String(prompt.slug || prompt.title || "prompt").trim().toLowerCase();
1232
+ const normalized = raw.replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1233
+ return normalized || "prompt";
181
1234
  }
182
- function normalizeFlag(raw) {
183
- return raw.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
1235
+ function asCommandName(value) {
1236
+ if (!value)
1237
+ return undefined;
1238
+ return COMMANDS.find((command) => command === value);
1239
+ }
1240
+ function isRunnableCommand(command) {
1241
+ return command !== "help" && command !== "version";
1242
+ }
1243
+ async function printVersion() {
1244
+ const version = await getCliVersion();
1245
+ console.log(`@prompts-gpt/client v${version}`);
184
1246
  }
185
1247
  async function getCliVersion() {
186
1248
  try {
@@ -192,47 +1254,478 @@ async function getCliVersion() {
192
1254
  return "0.0.0";
193
1255
  }
194
1256
  }
195
- function printHelp() {
1257
+ function printHelp(command) {
1258
+ if (command) {
1259
+ console.log(getCommandHelp(command));
1260
+ return;
1261
+ }
196
1262
  console.log(`Prompts-GPT CLI
197
1263
 
198
- Commands:
199
- prompts-gpt init --token <token> [--api-url https://prompts-gpt.com] [--cwd /path/to/repo]
1264
+ Usage:
1265
+ prompts-gpt <command> [options]
1266
+ prompts-gpt help [command]
200
1267
  prompts-gpt version
201
- prompts-gpt project
202
- prompts-gpt pull [--query "repo audit"] [--category coding] [--tool Codex] [--limit 25] [--out .prompts-gpt] [--overwrite]
203
- prompts-gpt generate --goal "Review this diff" [--context "Next.js app"] [--agent codex,cursor,vscode]
204
- prompts-gpt sync [--goal "Review this diff"] [--limit 25] [--agent all] [--out .prompts-gpt] [--cwd /path/to/repo]
205
- prompts-gpt install-agents [--agent codex,cursor,vscode,copilot]
206
1268
 
207
- Options:
208
- --token <token> Project API token
209
- --api-url <url> Custom API base URL for self-hosted instances
210
- --cwd <path> Target local project directory for config and generated files
211
- --agent <targets> Comma-separated agent targets: codex,cursor,vscode,copilot or all
212
- --help Show this help message
213
- --version Show the current CLI version
214
-
215
- Agent targets:
216
- codex writes AGENTS.md with prompt-pack links
217
- cursor writes .cursor/rules/prompts-gpt-*.mdc
218
- vscode writes .github/copilot-instructions.md and .vscode snippets
219
- copilot writes .github/prompts/*.prompt.md
1269
+ Commands:
1270
+ init Save a project token in .prompts-gpt/.credentials.json
1271
+ setup Scaffold .prompts-gpt/config.json for local orchestration
1272
+ load-config Pull configuration and prompts directly from Prompts Studio
1273
+ pull Download prompt packs as Markdown files
1274
+ generate Generate one prompt pack from a goal
1275
+ sync Generate and/or pull prompt packs, then sync agent files
1276
+ list Show available prompts, sweeps, and agent integrations
1277
+ status Show workspace readiness and next steps
1278
+ validate Validate .prompts-gpt/config.json and report issues
1279
+ run Execute a prompt file with local agent orchestration
1280
+ run-batch Execute multiple prompt files from config, manifest, or list
1281
+ sweep Multi-iteration prompt execution with progress and summaries
1282
+ providers Show detected local provider CLIs
1283
+ doctor Validate local run prerequisites and config
1284
+ project Show the current project linked to the token
1285
+ version Show the current CLI version
1286
+ help Show global or command-specific help
1287
+
1288
+ Global options:
1289
+ --help Show help
1290
+ --version Show the current CLI version
220
1291
 
221
1292
  Supported tools: ${VALID_TOOLS.join(", ")}
222
1293
  Supported agent targets: ${SUPPORTED_AGENT_TARGETS.join(", ")}
1294
+ Run agent profiles: ${ORCHESTRATION_AGENT_PROFILES.join(", ")}
223
1295
  `);
224
1296
  }
1297
+ function parsePositiveIntFlag(raw, flagName) {
1298
+ if (raw === undefined)
1299
+ return undefined;
1300
+ const label = flagName ? `--${flagName}` : "Value";
1301
+ if (!/^\d+$/.test(raw)) {
1302
+ throw new CliError(`${label} must be a positive integer, got "${raw}".`, CLI_EXIT_CODES.validation);
1303
+ }
1304
+ const value = Number.parseInt(raw, 10);
1305
+ if (!Number.isSafeInteger(value) || value < 1) {
1306
+ throw new CliError(`${label} must be a positive integer, got "${raw}".`, CLI_EXIT_CODES.validation);
1307
+ }
1308
+ return value;
1309
+ }
1310
+ function parseNonNegativeIntFlag(raw, flagName) {
1311
+ if (raw === undefined)
1312
+ return undefined;
1313
+ const label = flagName ? `--${flagName}` : "Value";
1314
+ if (!/^\d+$/.test(raw)) {
1315
+ throw new CliError(`${label} must be a non-negative integer, got "${raw}".`, CLI_EXIT_CODES.validation);
1316
+ }
1317
+ const value = Number.parseInt(raw, 10);
1318
+ if (!Number.isSafeInteger(value) || value < 0) {
1319
+ throw new CliError(`${label} must be a non-negative integer, got "${raw}".`, CLI_EXIT_CODES.validation);
1320
+ }
1321
+ return value;
1322
+ }
1323
+ function resolveRunAgent(flags, fallback) {
1324
+ const raw = getStringFlag(flags, "agent");
1325
+ if (!raw)
1326
+ return fallback;
1327
+ const normalizedRaw = raw.trim().toLowerCase();
1328
+ const normalized = normalizeOrchestrationAgent(raw);
1329
+ if (normalized === "router" && normalizedRaw !== "router") {
1330
+ const profiles = ORCHESTRATION_AGENT_PROFILES.join(", ");
1331
+ const hint = ORCHESTRATION_AGENT_PROFILES.find((p) => p.startsWith(normalizedRaw.slice(0, 3)));
1332
+ const suggestion = hint ? ` Did you mean "${hint}"?` : "";
1333
+ throw new CliError(`Invalid --agent target: ${raw}. Use ${profiles}.${suggestion}`, CLI_EXIT_CODES.validation);
1334
+ }
1335
+ return normalized;
1336
+ }
1337
+ function getCommandHelp(command) {
1338
+ if (command === "init") {
1339
+ return `prompts-gpt init
1340
+
1341
+ Usage:
1342
+ prompts-gpt init (--token <project-token> | --token-stdin | --token-prompt) [--api-url <url>] [--cwd <path>]
1343
+
1344
+ Why use it:
1345
+ Stores a project token in a local credentials file so day-one CLI usage does not require re-pasting secrets on every command.
1346
+
1347
+ Options:
1348
+ --token <token> Project API token. Must start with pgpt_.
1349
+ --token-stdin Read the project token from stdin so it does not end up in shell history.
1350
+ --token-prompt Prompt for the project token without echoing it.
1351
+ --api-url <url> Custom API base URL for self-hosted instances.
1352
+ --cwd <path> Target project directory that will receive .prompts-gpt/.credentials.json.
1353
+ --help Show this command help.
1354
+ `;
1355
+ }
1356
+ if (command === "setup") {
1357
+ return `prompts-gpt setup
1358
+
1359
+ Usage:
1360
+ prompts-gpt setup [--prompt-file <path> | --prompt-files <a,b,c> | --manifest <path> | --prompt-dir <path>] [--agent codex|cursor|claude|copilot|router] [--provider-order <a,b,c>] [--timeout <seconds>] [--retry-count <n>] [--artifacts-dir <path>] [--codex-model <name>] [--cursor-model <name>] [--claude-model <name>] [--copilot-model <name>] [--allow-destructive-git] [--overwrite] [--json] [--cwd <path>]
1361
+
1362
+ Why use it:
1363
+ Scaffolds a generic local orchestration config so a repo can run prompts through Codex, Cursor, Claude Code, or Copilot with minimal repeated CLI flags.
1364
+
1365
+ Options:
1366
+ --prompt-file <path> Default single prompt file for \`prompts-gpt run\`.
1367
+ --prompt-files <list> Default batch prompt files for \`prompts-gpt run-batch\`.
1368
+ --manifest <path> Use this manifest as the batch source. Default: auto-detect .prompts-gpt/manifest.json
1369
+ --prompt-dir <path> Scan a prompt directory when you do not use .prompts-gpt.
1370
+ --agent <name> Default orchestration profile. Default: router
1371
+ --provider-order <list> Comma-separated router order such as codex,cursor,claude,copilot
1372
+ --timeout <seconds> Default timeout in seconds. Default: 900
1373
+ --retry-count <n> Retry count for spawn and timeout failures. Default: 0
1374
+ --artifacts-dir <path> Run artifact directory. Default: .scripts/runs
1375
+ --codex-model <name> Default model override for codex.
1376
+ --cursor-model <name> Default model override for cursor.
1377
+ --claude-model <name> Default model override for claude.
1378
+ --copilot-model <name> Default model override for copilot.
1379
+ --allow-destructive-git Write config with destructive git protection disabled.
1380
+ --overwrite Replace an existing config file.
1381
+ --json Print the generated config payload as JSON.
1382
+ --cwd <path> Project directory.
1383
+ --help Show this command help.
1384
+ `;
1385
+ }
1386
+ if (command === "project") {
1387
+ return `prompts-gpt project
1388
+
1389
+ Usage:
1390
+ prompts-gpt project [--json] [--token <project-token> | --token-stdin | --token-prompt] [--api-url <url>] [--cwd <path>]
1391
+
1392
+ Why use it:
1393
+ Verifies that the current local token resolves to the expected Prompts-GPT project before syncing files.
1394
+
1395
+ Options:
1396
+ --json Print the full project payload as JSON.
1397
+ --token <token> Override the saved local token for this command only.
1398
+ --token-stdin Read the override token from stdin for this command only.
1399
+ --token-prompt Prompt for the override token without echoing it.
1400
+ --api-url <url> Override the saved API base URL for this command only.
1401
+ --cwd <path> Project directory to inspect for local credentials.
1402
+ --help Show this command help.
1403
+ `;
1404
+ }
1405
+ if (command === "pull") {
1406
+ return `prompts-gpt pull
1407
+
1408
+ Usage:
1409
+ prompts-gpt pull [--query <text> | --q <text>] [--category <name>] [--tool <name>] [--output-type <name>] [--limit <n>] [--out <dir>] [--overwrite] [--token <project-token> | --token-stdin | --token-prompt] [--api-url <url>] [--cwd <path>]
1410
+
1411
+ Why use it:
1412
+ Pulls prompt packs into local Markdown files so teams can review and use the same prompt assets inside their repository.
1413
+
1414
+ Options:
1415
+ --query <text> Search query for the project prompt library.
1416
+ --q <text> Short alias for --query.
1417
+ --category <name> Filter prompts by category.
1418
+ --tool <name> Filter prompts by supported tool.
1419
+ --output-type <name> Filter prompts by output type.
1420
+ --limit <n> Positive integer limit for returned prompts.
1421
+ --out <dir> Output directory inside the current project. Default: .prompts-gpt
1422
+ --overwrite Replace existing Markdown files instead of skipping them.
1423
+ --token <token> Override the saved local token for this command only.
1424
+ --token-stdin Read the override token from stdin for this command only.
1425
+ --token-prompt Prompt for the override token without echoing it.
1426
+ --api-url <url> Override the saved API base URL for this command only.
1427
+ --cwd <path> Project directory to inspect for local credentials and output files.
1428
+ --help Show this command help.
1429
+ `;
1430
+ }
1431
+ if (command === "generate") {
1432
+ return `prompts-gpt generate
1433
+
1434
+ Usage:
1435
+ prompts-gpt generate --goal <text> [--context <text>] [--constraints <text>] [--desired-output <text>] [--tool <name>] [--mode <name>] [--artifact-type <name>] [--web-search] [--out <dir>] [--overwrite] [--agent <targets>] [--sync-agents] [--token <project-token> | --token-stdin | --token-prompt] [--api-url <url>] [--cwd <path>]
1436
+
1437
+ Why use it:
1438
+ Creates a new reusable prompt pack from a concrete developer goal, then optionally installs agent-readable files immediately.
1439
+
1440
+ Options:
1441
+ --goal <text> Required. The task to generate a prompt pack for.
1442
+ --context <text> Extra project or stack context for the generator.
1443
+ --constraints <text> Constraints that the generated prompt must honor.
1444
+ --desired-output <text> Preferred output shape for the generated prompt pack.
1445
+ --tool <name> Target tool. Default: Codex
1446
+ --mode <name> Prompt generation mode. Default: implement
1447
+ --artifact-type <name> Artifact type. Default: prompt-file
1448
+ --web-search Allow server-side web research when generating the prompt.
1449
+ --out <dir> Output directory inside the current project. Default: .prompts-gpt
1450
+ --overwrite Replace an existing generated Markdown file.
1451
+ --agent <targets> Sync agent files for specific targets after generation.
1452
+ --sync-agents Sync all agent files after generation.
1453
+ --token <token> Override the saved local token for this command only.
1454
+ --token-stdin Read the override token from stdin for this command only.
1455
+ --token-prompt Prompt for the override token without echoing it.
1456
+ --api-url <url> Override the saved API base URL for this command only.
1457
+ --cwd <path> Project directory to inspect for local credentials and output files.
1458
+ --help Show this command help.
1459
+ `;
1460
+ }
1461
+ if (command === "sync") {
1462
+ return `prompts-gpt sync
1463
+
1464
+ Usage:
1465
+ prompts-gpt sync [--goal <text>] [--generated-only] [--query <text> | --q <text>] [--category <name>] [--tool <name>] [--output-type <name>] [--limit <n>] [--context <text>] [--constraints <text>] [--desired-output <text>] [--mode <name>] [--artifact-type <name>] [--web-search] [--agent <targets>] [--out <dir>] [--overwrite] [--dry-run] [--token <project-token> | --token-stdin | --token-prompt] [--api-url <url>] [--cwd <path>]
1466
+
1467
+ Why use it:
1468
+ Gives teams a one-command path to refresh Markdown prompts, agent files, and the local manifest from the same source of truth.
1469
+
1470
+ Options:
1471
+ --goal <text> Generate one prompt pack before syncing.
1472
+ --generated-only Skip library pull and sync only the generated prompt pack from --goal.
1473
+ --query <text> Search query for pulled prompt packs.
1474
+ --q <text> Short alias for --query.
1475
+ --category <name> Filter pulled prompt packs by category.
1476
+ --tool <name> Filter pulled prompt packs and generated output by tool.
1477
+ --output-type <name> Filter pulled prompt packs by output type.
1478
+ --limit <n> Positive integer limit for pulled prompt packs.
1479
+ --context <text> Extra project or stack context for generated prompt packs.
1480
+ --constraints <text> Constraints for generated prompt packs.
1481
+ --desired-output <text> Preferred output shape for generated prompt packs.
1482
+ --mode <name> Prompt generation mode. Default: implement
1483
+ --artifact-type <name> Artifact type. Default: prompt-file
1484
+ --web-search Allow server-side web research when generating a prompt pack.
1485
+ --agent <targets> Comma-separated agent targets. Default: all
1486
+ --out <dir> Output directory inside the current project. Default: .prompts-gpt
1487
+ --overwrite Replace existing Markdown files instead of skipping them.
1488
+ --dry-run Preview what would be synced without writing any files.
1489
+ --token <token> Override the saved local token for this command only.
1490
+ --token-stdin Read the override token from stdin for this command only.
1491
+ --token-prompt Prompt for the override token without echoing it.
1492
+ --api-url <url> Override the saved API base URL for this command only.
1493
+ --cwd <path> Project directory to inspect for local credentials and output files.
1494
+ --help Show this command help.
1495
+ `;
1496
+ }
1497
+ if (command === "run") {
1498
+ return `prompts-gpt run
1499
+
1500
+ Usage:
1501
+ prompts-gpt run [--prompt-file <path>] [--agent codex|cursor|claude|copilot|router] [--model <name>] [--timeout <seconds>] [--artifacts-dir <path>] [--run-id <id>] [--sandbox <mode>] [--no-approve-mcps] [--background] [--permission-mode <mode>] [--json] [--cwd <path>]
1502
+
1503
+ Why use it:
1504
+ Executes one local prompt file with the built-in provider adapter runtime and writes run artifacts. If \`--prompt-file\` is omitted, the command uses the configured default prompt.
1505
+
1506
+ Options:
1507
+ --prompt-file <path> Optional explicit prompt Markdown or text file.
1508
+ --agent <name> Orchestration profile. Default from ${DEFAULT_RUN_CONFIG_PATH} or router.
1509
+ --model <name> Optional model override for the selected provider.
1510
+ --timeout <seconds> Execution timeout in seconds.
1511
+ --artifacts-dir <path> Override run artifacts directory.
1512
+ --run-id <id> Explicit run ID for artifact folder naming.
1513
+ --sandbox <mode> Codex sandbox mode. Default: workspace-write.
1514
+ --no-approve-mcps Disable Cursor MCP auto-approval flag.
1515
+ --background Run as a background agent (Cursor cloud agent mode).
1516
+ --permission-mode <mode> Claude Code permission mode. Default: acceptEdits.
1517
+ --json Print machine-readable JSON output.
1518
+ --cwd <path> Project directory.
1519
+ --help Show this command help.
1520
+ `;
1521
+ }
1522
+ if (command === "run-batch") {
1523
+ return `prompts-gpt run-batch
1524
+
1525
+ Usage:
1526
+ prompts-gpt run-batch [--manifest <path> | --prompt-files <a,b,c>] [--agent codex|cursor|claude|copilot|router] [--model <name>] [--timeout <seconds>] [--artifacts-dir <path>] [--json] [--cwd <path>]
1527
+
1528
+ Why use it:
1529
+ Executes multiple prompt files in sequence using the configured prompt source, a manifest, or an explicit file list.
1530
+
1531
+ Options:
1532
+ --manifest <path> Prompt manifest path. Overrides config batch defaults.
1533
+ --prompt-files <list> Comma-separated prompt files to run.
1534
+ --agent <name> Orchestration profile. Default from ${DEFAULT_RUN_CONFIG_PATH} or router.
1535
+ --model <name> Optional model override for all runs.
1536
+ --timeout <seconds> Execution timeout in seconds per prompt.
1537
+ --artifacts-dir <path> Override run artifacts directory.
1538
+ --json Print machine-readable JSON output.
1539
+ --cwd <path> Project directory.
1540
+ --help Show this command help.
1541
+ `;
1542
+ }
1543
+ if (command === "sweep") {
1544
+ return `prompts-gpt sweep
1545
+
1546
+ Usage:
1547
+ prompts-gpt sweep [--prompt-file <path>] [--agent codex|cursor|claude|copilot|router] [--model <name>] [--iterations <n>] [--iteration-timeout <seconds>] [--max-retries <n>] [--phase <name>] [--artifacts-dir <path>] [--run-id <id>] [--sandbox <mode>] [--no-approve-mcps] [--background] [--permission-mode <mode>] [--max-run-dirs <n>] [--summary-lines <n>] [--dry-run] [--json] [--cwd <path>]
1548
+
1549
+ Why use it:
1550
+ Replaces the bash sweep scripts with a generic multi-iteration execution engine.
1551
+ Runs the same prompt N times, feeding each iteration's summary into the next.
1552
+ Includes pre-flight checks, safety guards, SIGTERM handling, progress monitoring,
1553
+ and a structured sweep manifest.
1554
+
1555
+ Options:
1556
+ --prompt-file <path> Prompt file to sweep. Reads from config if omitted.
1557
+ --agent <name> Orchestration profile. Default from config or router.
1558
+ --model <name> Model override for the selected provider.
1559
+ --iterations <n> Number of sweep iterations. Default: 1
1560
+ --iteration-timeout <secs> Timeout per iteration in seconds. Default: 5400 (90 min)
1561
+ --max-retries <n> Max retries per iteration on spawn/timeout. Default: 2
1562
+ --phase <name> Optional phase label injected into the prompt.
1563
+ --artifacts-dir <path> Override run artifacts directory.
1564
+ --run-id <id> Explicit run ID for artifact folder naming.
1565
+ --sandbox <mode> Codex sandbox mode. Default: workspace-write
1566
+ --no-approve-mcps Disable Cursor MCP auto-approval flag.
1567
+ --background Run as a background agent (Cursor cloud agent mode).
1568
+ --permission-mode <mode> Claude Code permission mode. Default: acceptEdits
1569
+ --max-run-dirs <n> Max artifact directories to keep. Default: 20
1570
+ --summary-lines <n> Lines of summary to extract per iteration. Default: 40
1571
+ --dry-run Preview what the sweep would do without executing.
1572
+ --json Print machine-readable JSON output.
1573
+ --cwd <path> Project directory.
1574
+ --help Show this command help.
1575
+ `;
1576
+ }
1577
+ if (command === "list") {
1578
+ return `prompts-gpt list
1579
+
1580
+ Usage:
1581
+ prompts-gpt list [--json] [--cwd <path>]
1582
+
1583
+ Why use it:
1584
+ Shows all prompt packs, sweep files, and agent integrations available in the workspace.
1585
+ Gives runnable commands for each entry so you can copy-paste them directly.
1586
+
1587
+ Options:
1588
+ --json Print as JSON.
1589
+ --cwd <path> Project directory.
1590
+ --help Show this command help.
1591
+ `;
1592
+ }
1593
+ if (command === "status") {
1594
+ return `prompts-gpt status
1595
+
1596
+ Usage:
1597
+ prompts-gpt status [--json] [--cwd <path>]
1598
+
1599
+ Why use it:
1600
+ Shows workspace readiness at a glance: credentials, config, manifest,
1601
+ prompts, sweeps, agent integrations, and available providers.
1602
+
1603
+ Options:
1604
+ --json Print as JSON.
1605
+ --cwd <path> Project directory.
1606
+ --help Show this command help.
1607
+ `;
1608
+ }
1609
+ if (command === "validate") {
1610
+ return `prompts-gpt validate
1611
+
1612
+ Usage:
1613
+ prompts-gpt validate [--json] [--cwd <path>]
1614
+
1615
+ Why use it:
1616
+ Validates the .prompts-gpt/config.json file and reports errors and
1617
+ warnings without running any commands.
1618
+
1619
+ Options:
1620
+ --json Print as JSON.
1621
+ --cwd <path> Project directory.
1622
+ --help Show this command help.
1623
+ `;
1624
+ }
1625
+ if (command === "providers") {
1626
+ return `prompts-gpt providers
1627
+
1628
+ Usage:
1629
+ prompts-gpt providers [--json] [--cwd <path>]
1630
+
1631
+ Why use it:
1632
+ Shows provider CLI detection details for codex, cursor, claude, and copilot so you can decide the best router order before running setup.
1633
+ `;
1634
+ }
1635
+ if (command === "doctor") {
1636
+ return `prompts-gpt doctor
1637
+
1638
+ Usage:
1639
+ prompts-gpt doctor [--json] [--cwd <path>]
1640
+
1641
+ Why use it:
1642
+ Checks runtime prerequisites, provider availability, prompt-source readiness, and run config health.
1643
+ `;
1644
+ }
1645
+ if (command === "load-config") {
1646
+ return `prompts-gpt load-config
1647
+
1648
+ Usage:
1649
+ prompts-gpt load-config [--agent <targets>] [--out <dir>] [--json] [--token <project-token> | --token-stdin | --token-prompt] [--api-url <url>] [--cwd <path>]
1650
+
1651
+ Why use it:
1652
+ One command to pull all prompts, agent files, and config from Prompts Studio
1653
+ into your local workspace. Replaces the multi-step init + sync + setup flow
1654
+ for users who manage their prompt library in the Prompts Studio web app.
1655
+
1656
+ Options:
1657
+ --agent <targets> Comma-separated agent targets. Default: all
1658
+ --out <dir> Output directory. Default: .prompts-gpt
1659
+ --json Print machine-readable JSON output.
1660
+ --token <token> Override saved token.
1661
+ --token-stdin Read token from stdin.
1662
+ --token-prompt Prompt for token.
1663
+ --api-url <url> Override API URL.
1664
+ --cwd <path> Project directory.
1665
+ --help Show this command help.
1666
+ `;
1667
+ }
1668
+ if (command === "version") {
1669
+ return `prompts-gpt version
1670
+
1671
+ Usage:
1672
+ prompts-gpt version
1673
+
1674
+ Why use it:
1675
+ Confirms the installed CLI version when debugging package resolution or publish issues.
1676
+ `;
1677
+ }
1678
+ return `prompts-gpt help
1679
+
1680
+ Usage:
1681
+ prompts-gpt help [command]
1682
+
1683
+ Why use it:
1684
+ Shows focused usage for the exact command you are trying to run so shell users do not have to scan the full command list.
1685
+ `;
1686
+ }
225
1687
  main().catch((error) => {
1688
+ if (error instanceof CliError) {
1689
+ console.error(error.message);
1690
+ if (error.helpCommand) {
1691
+ console.error(`Run \`prompts-gpt help${error.helpCommand ? ` ${error.helpCommand}` : ""}\` for usage.`);
1692
+ }
1693
+ process.exitCode = error.exitCode;
1694
+ return;
1695
+ }
226
1696
  if (error instanceof PromptsGptApiError) {
227
- console.error(`${error.message}\n${error.recovery}`);
1697
+ console.error(formatApiError(error));
228
1698
  process.exitCode = error.status === 401 || error.status === 403
229
1699
  ? CLI_EXIT_CODES.auth
230
- : error.code === "VALIDATION_ERROR"
231
- ? CLI_EXIT_CODES.validation
232
- : CLI_EXIT_CODES.general;
1700
+ : error.status === 429
1701
+ ? CLI_EXIT_CODES.rateLimit
1702
+ : error.code === "VALIDATION_ERROR"
1703
+ ? CLI_EXIT_CODES.validation
1704
+ : CLI_EXIT_CODES.general;
233
1705
  return;
234
1706
  }
235
- console.error(error instanceof Error ? error.message : String(error));
1707
+ const msg = error instanceof Error ? error.message : String(error);
1708
+ console.error(msg.replace(/pgpt_[a-zA-Z0-9]{4,}/g, "pgpt_***"));
236
1709
  process.exitCode = CLI_EXIT_CODES.general;
237
1710
  });
1711
+ function warnOnConfigIssues(config) {
1712
+ for (const w of config.configWarnings) {
1713
+ console.error(`[config warning] ${w}`);
1714
+ }
1715
+ }
1716
+ function formatApiError(error) {
1717
+ const lines = [error.message];
1718
+ for (const [field, messages] of Object.entries(error.fieldErrors ?? {})) {
1719
+ for (const message of messages ?? []) {
1720
+ lines.push(`- ${field}: ${message}`);
1721
+ }
1722
+ }
1723
+ if (error.requestId) {
1724
+ lines.push(`Request ID: ${error.requestId}`);
1725
+ }
1726
+ if (error.recovery) {
1727
+ lines.push(error.recovery);
1728
+ }
1729
+ return lines.join("\n");
1730
+ }
238
1731
  //# sourceMappingURL=cli.js.map