@prompts-gpt/client 0.2.2 → 0.2.4
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/LICENSE +75 -21
- package/README.md +106 -279
- package/dist/cli.js +1513 -144
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +276 -47
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts +223 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +1444 -0
- package/dist/runtime.js.map +1 -0
- package/dist/sweep.d.ts +180 -0
- package/dist/sweep.d.ts.map +1 -0
- package/dist/sweep.js +606 -0
- package/dist/sweep.js.map +1 -0
- package/package.json +4 -5
- package/CHANGELOG.md +0 -110
package/dist/index.js
CHANGED
|
@@ -1,11 +1,26 @@
|
|
|
1
1
|
import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { ensureGitignoreEntry } from "./runtime.js";
|
|
5
|
+
export { DEFAULT_RUN_ARTIFACTS_DIR, DEFAULT_RUN_CONFIG_PATH, ORCHESTRATION_AGENT_PROFILES, DEFAULT_MODELS, normalizeOrchestrationAgent, normalizeConcreteProvider, loadRunConfig, detectProviders, doctor, initRunConfig, runBatch, runPrompt, resolveRunProvider, resolveTimeoutSeconds, resolveDefaultPromptFile, assertPromptFitsLaunch, warnModelProviderMismatch, executeProviderCommandWithRetries, executeProviderCommand, captureWorktreeStatus, buildWorktreeDelta, buildProviderCommand, formatCombinedOutput, appendFileSafe, aggregateTokenUsage, validateRunConfig, discoverWorkspaceAssets, emptyTokenUsage, extractTokenUsageFromLog, hasTokenUsage, isCI, readTokenUsageFromLog, } from "./runtime.js";
|
|
6
|
+
export { sweepPrompt, acquireSweepLock, releaseSweepLock, parseStreamJsonToolCounts, streamJsonHasResult, extractIterationSummary, buildIterationPrompt, runPreFlight, writeSweepManifest, } from "./sweep.js";
|
|
4
7
|
export const DEFAULT_PROMPTS_GPT_API_URL = "https://prompts-gpt.com";
|
|
5
8
|
export const DEFAULT_PROMPTS_GPT_OUT_DIR = ".prompts-gpt";
|
|
6
9
|
export const PROMPTS_GPT_CREDENTIALS_FILE = ".credentials.json";
|
|
7
10
|
export const PROMPTS_GPT_MANIFEST_FILE = "manifest.json";
|
|
8
|
-
export const SUPPORTED_AGENT_TARGETS = [
|
|
11
|
+
export const SUPPORTED_AGENT_TARGETS = [
|
|
12
|
+
"codex",
|
|
13
|
+
"claude-code",
|
|
14
|
+
"cursor",
|
|
15
|
+
"vscode",
|
|
16
|
+
"copilot",
|
|
17
|
+
"continue",
|
|
18
|
+
"gemini-cli",
|
|
19
|
+
"windsurf",
|
|
20
|
+
"cline",
|
|
21
|
+
"junie",
|
|
22
|
+
"amp",
|
|
23
|
+
];
|
|
9
24
|
export class PromptsGptApiError extends Error {
|
|
10
25
|
status;
|
|
11
26
|
code;
|
|
@@ -20,7 +35,7 @@ export class PromptsGptApiError extends Error {
|
|
|
20
35
|
this.code = options?.code ?? "UNKNOWN_ERROR";
|
|
21
36
|
this.recovery = options?.recovery ?? "Retry the request or create a fresh project token.";
|
|
22
37
|
this.requestId = options?.requestId ?? null;
|
|
23
|
-
this.fieldErrors = options?.fieldErrors;
|
|
38
|
+
this.fieldErrors = options?.fieldErrors ? Object.freeze({ ...options.fieldErrors }) : undefined;
|
|
24
39
|
this.retryAfterMs = options?.retryAfterMs ?? null;
|
|
25
40
|
}
|
|
26
41
|
}
|
|
@@ -33,11 +48,16 @@ export class PromptsGptClient {
|
|
|
33
48
|
token;
|
|
34
49
|
fetchImpl;
|
|
35
50
|
timeoutMs;
|
|
51
|
+
accountId;
|
|
36
52
|
constructor(options) {
|
|
37
53
|
this.apiUrl = safeNormalizeApiUrl(options.apiUrl);
|
|
38
54
|
this.token = options.token?.trim() || null;
|
|
39
55
|
this.fetchImpl = options.fetch;
|
|
40
56
|
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
57
|
+
this.accountId = options.accountId?.trim() || null;
|
|
58
|
+
if (this.token && this.apiUrl.startsWith("http://") && !this.apiUrl.includes("localhost") && !this.apiUrl.includes("127.0.0.1")) {
|
|
59
|
+
throw new PromptsGptApiError("Refusing to send credentials over unencrypted HTTP. Use HTTPS or localhost.", { code: "INSECURE_TRANSPORT", recovery: "Change the API URL to use https://." });
|
|
60
|
+
}
|
|
41
61
|
}
|
|
42
62
|
async getProject(options = {}) {
|
|
43
63
|
const data = await this.request("/api/sdk/v1/project", options);
|
|
@@ -121,7 +141,11 @@ export class PromptsGptClient {
|
|
|
121
141
|
authorization: `Bearer ${this.token}`,
|
|
122
142
|
accept: "application/json",
|
|
123
143
|
"x-prompts-gpt-client": `@prompts-gpt/client/${getClientVersion()}`,
|
|
144
|
+
"x-prompts-gpt-build": getBuildFingerprint(),
|
|
124
145
|
};
|
|
146
|
+
if (this.accountId) {
|
|
147
|
+
headers["x-prompts-gpt-account"] = this.accountId;
|
|
148
|
+
}
|
|
125
149
|
if (!options.omitUserAgent) {
|
|
126
150
|
headers["user-agent"] = `prompts-gpt-client/${getClientVersion()}`;
|
|
127
151
|
}
|
|
@@ -245,7 +269,9 @@ function normalizeTimeoutMs(value) {
|
|
|
245
269
|
recovery: "Provide a timeout greater than 0.",
|
|
246
270
|
});
|
|
247
271
|
}
|
|
248
|
-
|
|
272
|
+
const MAX_API_TIMEOUT_MS = 600_000;
|
|
273
|
+
const capped = Math.min(Math.trunc(value), MAX_API_TIMEOUT_MS);
|
|
274
|
+
return capped;
|
|
249
275
|
}
|
|
250
276
|
function serializePromptQuery(query) {
|
|
251
277
|
const params = new URLSearchParams();
|
|
@@ -340,11 +366,37 @@ function parseRetryAfterHeader(value) {
|
|
|
340
366
|
return Math.min(Math.max(retryAt - Date.now(), 0), 600_000);
|
|
341
367
|
}
|
|
342
368
|
function sleep(ms) {
|
|
343
|
-
return new Promise((resolve) =>
|
|
369
|
+
return new Promise((resolve) => {
|
|
370
|
+
setTimeout(resolve, ms);
|
|
371
|
+
});
|
|
344
372
|
}
|
|
345
373
|
function generateRequestId() {
|
|
346
|
-
|
|
347
|
-
|
|
374
|
+
try {
|
|
375
|
+
const crypto = globalThis.crypto;
|
|
376
|
+
const bytes = new Uint8Array(8);
|
|
377
|
+
crypto.getRandomValues(bytes);
|
|
378
|
+
return `pgcli_${Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("")}`;
|
|
379
|
+
}
|
|
380
|
+
catch {
|
|
381
|
+
const hex = Array.from({ length: 8 }, () => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")).join("");
|
|
382
|
+
return `pgcli_${hex}`;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
const BUILD_TS = "dev";
|
|
386
|
+
const BUILD_ACCOUNT_ID = "unattributed";
|
|
387
|
+
let cachedBuildFingerprint = null;
|
|
388
|
+
function getBuildFingerprint() {
|
|
389
|
+
if (cachedBuildFingerprint)
|
|
390
|
+
return cachedBuildFingerprint;
|
|
391
|
+
cachedBuildFingerprint = `${getClientVersion()}/${BUILD_TS}/${BUILD_ACCOUNT_ID}`;
|
|
392
|
+
return cachedBuildFingerprint;
|
|
393
|
+
}
|
|
394
|
+
export function getAttribution() {
|
|
395
|
+
return {
|
|
396
|
+
version: getClientVersion(),
|
|
397
|
+
buildTs: BUILD_TS,
|
|
398
|
+
accountId: BUILD_ACCOUNT_ID,
|
|
399
|
+
};
|
|
348
400
|
}
|
|
349
401
|
let cachedVersion = null;
|
|
350
402
|
function getClientVersion() {
|
|
@@ -381,16 +433,24 @@ export async function loadLocalCredentials(cwd = process.cwd()) {
|
|
|
381
433
|
if (!existsSync(credentialsPath))
|
|
382
434
|
return null;
|
|
383
435
|
try {
|
|
384
|
-
const
|
|
436
|
+
const raw = await readFile(credentialsPath, "utf8");
|
|
437
|
+
const parsed = JSON.parse(raw);
|
|
438
|
+
if (!parsed || typeof parsed !== "object")
|
|
439
|
+
return null;
|
|
385
440
|
let apiUrl = DEFAULT_PROMPTS_GPT_API_URL;
|
|
386
441
|
if (typeof parsed.apiUrl === "string") {
|
|
387
442
|
try {
|
|
388
|
-
new URL(parsed.apiUrl);
|
|
389
|
-
|
|
443
|
+
const url = new URL(parsed.apiUrl);
|
|
444
|
+
if (url.protocol === "https:" || url.protocol === "http:") {
|
|
445
|
+
apiUrl = parsed.apiUrl;
|
|
446
|
+
}
|
|
390
447
|
}
|
|
391
|
-
catch { }
|
|
448
|
+
catch { /* invalid URL — use default */ }
|
|
392
449
|
}
|
|
393
450
|
const rawToken = typeof parsed.token === "string" ? parsed.token.trim() : null;
|
|
451
|
+
if (rawToken && !rawToken.startsWith("pgpt_")) {
|
|
452
|
+
return { token: null, apiUrl };
|
|
453
|
+
}
|
|
394
454
|
return {
|
|
395
455
|
token: rawToken || null,
|
|
396
456
|
apiUrl,
|
|
@@ -446,6 +506,9 @@ export async function writePromptMarkdownFiles(prompts, options = {}) {
|
|
|
446
506
|
}
|
|
447
507
|
export async function writeAgentFiles(prompts, options = {}) {
|
|
448
508
|
const cwd = options.cwd ?? process.cwd();
|
|
509
|
+
if (!existsSync(cwd)) {
|
|
510
|
+
throw new Error(`Working directory does not exist: ${cwd}`);
|
|
511
|
+
}
|
|
449
512
|
const targets = normalizeAgentTargets(options.agent ?? options.agents ?? "all");
|
|
450
513
|
const overwrite = Boolean(options.overwriteAgentFiles);
|
|
451
514
|
const written = [];
|
|
@@ -494,9 +557,13 @@ export async function writePromptManifest(prompts, options = {}) {
|
|
|
494
557
|
const normalizedPrompts = assertUniquePromptFileStems(prompts);
|
|
495
558
|
await mkdir(outDir, { recursive: true });
|
|
496
559
|
const manifestPath = path.join(outDir, PROMPTS_GPT_MANIFEST_FILE);
|
|
560
|
+
const attribution = getAttribution();
|
|
497
561
|
const payload = {
|
|
498
562
|
version: 1,
|
|
499
563
|
generatedAt: new Date().toISOString(),
|
|
564
|
+
generatedBy: `@prompts-gpt/client@${attribution.version}`,
|
|
565
|
+
accountId: attribution.accountId,
|
|
566
|
+
buildFingerprint: `${attribution.version}/${attribution.buildTs}/${attribution.accountId}`,
|
|
500
567
|
count: normalizedPrompts.length,
|
|
501
568
|
prompts: normalizedPrompts.map(({ prompt, stem }) => ({
|
|
502
569
|
slug: stem,
|
|
@@ -567,24 +634,47 @@ function buildAgentFiles(target, prompts) {
|
|
|
567
634
|
].join("\n"),
|
|
568
635
|
}];
|
|
569
636
|
}
|
|
637
|
+
if (target === "claude-code") {
|
|
638
|
+
return [{
|
|
639
|
+
path: "CLAUDE.md",
|
|
640
|
+
managedBlock: true,
|
|
641
|
+
content: [
|
|
642
|
+
"# Prompts-GPT Claude Code Instructions",
|
|
643
|
+
"",
|
|
644
|
+
"Prompts synced by `prompts-gpt sync` live in `.prompts-gpt/`. Start with [.prompts-gpt/manifest.json](.prompts-gpt/manifest.json), then open the prompt packs linked below before starting related work.",
|
|
645
|
+
"",
|
|
646
|
+
"## Available Prompt Packs",
|
|
647
|
+
...prompts.map(({ prompt, stem }) => `- [${prompt.title}](.prompts-gpt/${stem}.md)`),
|
|
648
|
+
"",
|
|
649
|
+
"When a prompt pack is relevant, load it, adapt variables to the current task, and keep verification tied to the prompt's acceptance criteria.",
|
|
650
|
+
"",
|
|
651
|
+
].join("\n"),
|
|
652
|
+
}];
|
|
653
|
+
}
|
|
570
654
|
if (target === "cursor") {
|
|
571
|
-
return prompts.
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
655
|
+
return prompts.flatMap(({ prompt, stem }) => ([
|
|
656
|
+
{
|
|
657
|
+
path: `.cursor/rules/prompts-gpt-${stem}.mdc`,
|
|
658
|
+
content: [
|
|
659
|
+
"---",
|
|
660
|
+
`description: ${yamlScalar(prompt.summary || prompt.title)}`,
|
|
661
|
+
"globs: []",
|
|
662
|
+
"alwaysApply: false",
|
|
663
|
+
"---",
|
|
664
|
+
"",
|
|
665
|
+
`# ${prompt.title}`,
|
|
666
|
+
"",
|
|
667
|
+
prompt.promptText,
|
|
668
|
+
"",
|
|
669
|
+
prompt.usageNotes ? `Usage notes: ${prompt.usageNotes}` : "",
|
|
670
|
+
"",
|
|
671
|
+
].filter(Boolean).join("\n"),
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
path: `.cursor/commands/prompts-gpt-${stem}.md`,
|
|
675
|
+
content: formatCursorCommandMarkdown(prompt, stem),
|
|
676
|
+
},
|
|
677
|
+
]));
|
|
588
678
|
}
|
|
589
679
|
if (target === "vscode") {
|
|
590
680
|
return [
|
|
@@ -604,12 +694,12 @@ function buildAgentFiles(target, prompts) {
|
|
|
604
694
|
path: ".github/instructions/prompts-gpt.instructions.md",
|
|
605
695
|
content: [
|
|
606
696
|
"---",
|
|
607
|
-
'applyTo: "AGENTS.md,.prompts-gpt/**/*.md,.github/copilot-instructions.md,.github/prompts/**/*.prompt.md,.cursor/rules/**/*.mdc,.vscode/prompts-gpt.code-snippets"',
|
|
697
|
+
'applyTo: "AGENTS.md,.prompts-gpt/**/*.md,.github/copilot-instructions.md,.github/prompts/**/*.prompt.md,.cursor/rules/**/*.mdc,.cursor/commands/**/*.md,.vscode/prompts-gpt.code-snippets"',
|
|
608
698
|
"---",
|
|
609
699
|
"",
|
|
610
700
|
"# Prompts-GPT managed artifacts",
|
|
611
701
|
"",
|
|
612
|
-
"These files are generated or refreshed by `prompts-gpt sync
|
|
702
|
+
"These files are generated or refreshed by `prompts-gpt sync`.",
|
|
613
703
|
"",
|
|
614
704
|
"- Treat `.prompts-gpt/manifest.json` as the source of truth for discoverable prompt packs and generated agent files.",
|
|
615
705
|
"- Prefer updating the upstream prompt pack or rerunning sync instead of manually editing generated agent artifacts.",
|
|
@@ -629,6 +719,110 @@ function buildAgentFiles(target, prompts) {
|
|
|
629
719
|
content: formatCopilotPromptMarkdown(prompt, stem),
|
|
630
720
|
}));
|
|
631
721
|
}
|
|
722
|
+
if (target === "continue") {
|
|
723
|
+
return prompts.map(({ prompt, stem }) => ({
|
|
724
|
+
path: `.continue/rules/prompts-gpt-${stem}.md`,
|
|
725
|
+
content: [
|
|
726
|
+
`# ${prompt.title}`,
|
|
727
|
+
"",
|
|
728
|
+
`[Canonical prompt pack](../../.prompts-gpt/${stem}.md)`,
|
|
729
|
+
"",
|
|
730
|
+
prompt.summary ?? "",
|
|
731
|
+
"",
|
|
732
|
+
prompt.promptText ?? "",
|
|
733
|
+
"",
|
|
734
|
+
prompt.usageNotes ? `Usage notes: ${prompt.usageNotes}` : "",
|
|
735
|
+
"",
|
|
736
|
+
].filter(Boolean).join("\n"),
|
|
737
|
+
}));
|
|
738
|
+
}
|
|
739
|
+
if (target === "gemini-cli") {
|
|
740
|
+
return [{
|
|
741
|
+
path: "GEMINI.md",
|
|
742
|
+
managedBlock: true,
|
|
743
|
+
content: [
|
|
744
|
+
"# Prompts-GPT Gemini CLI Instructions",
|
|
745
|
+
"",
|
|
746
|
+
"Prompts synced by `prompts-gpt sync` live in `.prompts-gpt/`. Start with [.prompts-gpt/manifest.json](.prompts-gpt/manifest.json), then open the prompt packs linked below before starting related work.",
|
|
747
|
+
"",
|
|
748
|
+
"## Available Prompt Packs",
|
|
749
|
+
...prompts.map(({ prompt, stem }) => `- [${prompt.title}](.prompts-gpt/${stem}.md)`),
|
|
750
|
+
"",
|
|
751
|
+
"When a prompt pack is relevant, load it, adapt variables to the current task, and keep verification tied to the prompt's acceptance criteria.",
|
|
752
|
+
"",
|
|
753
|
+
].join("\n"),
|
|
754
|
+
}];
|
|
755
|
+
}
|
|
756
|
+
if (target === "windsurf") {
|
|
757
|
+
return prompts.map(({ prompt, stem }) => ({
|
|
758
|
+
path: `.windsurf/rules/prompts-gpt-${stem}.md`,
|
|
759
|
+
content: [
|
|
760
|
+
`# ${prompt.title}`,
|
|
761
|
+
"",
|
|
762
|
+
`[Canonical prompt pack](../../.prompts-gpt/${stem}.md)`,
|
|
763
|
+
"",
|
|
764
|
+
prompt.summary ?? "",
|
|
765
|
+
"",
|
|
766
|
+
prompt.promptText ?? "",
|
|
767
|
+
"",
|
|
768
|
+
"Use this as a workspace rule for Cascade or Devin Local when the prompt pack matches the task.",
|
|
769
|
+
prompt.usageNotes ? `Usage notes: ${prompt.usageNotes}` : "",
|
|
770
|
+
"",
|
|
771
|
+
].filter(Boolean).join("\n"),
|
|
772
|
+
}));
|
|
773
|
+
}
|
|
774
|
+
if (target === "cline") {
|
|
775
|
+
return prompts.map(({ prompt, stem }) => ({
|
|
776
|
+
path: `.clinerules/prompts-gpt-${stem}.md`,
|
|
777
|
+
content: [
|
|
778
|
+
`# ${prompt.title}`,
|
|
779
|
+
"",
|
|
780
|
+
`[Canonical prompt pack](../.prompts-gpt/${stem}.md)`,
|
|
781
|
+
"",
|
|
782
|
+
prompt.summary ?? "",
|
|
783
|
+
"",
|
|
784
|
+
prompt.promptText ?? "",
|
|
785
|
+
"",
|
|
786
|
+
"Enable this rule when the current Cline task matches the linked prompt pack.",
|
|
787
|
+
prompt.usageNotes ? `Usage notes: ${prompt.usageNotes}` : "",
|
|
788
|
+
"",
|
|
789
|
+
].filter(Boolean).join("\n"),
|
|
790
|
+
}));
|
|
791
|
+
}
|
|
792
|
+
if (target === "junie") {
|
|
793
|
+
return [{
|
|
794
|
+
path: ".junie/guidelines.md",
|
|
795
|
+
managedBlock: true,
|
|
796
|
+
content: [
|
|
797
|
+
"# Prompts-GPT Junie Guidelines",
|
|
798
|
+
"",
|
|
799
|
+
"Prompts synced by `prompts-gpt sync` live in `.prompts-gpt/`. Start with [.prompts-gpt/manifest.json](.prompts-gpt/manifest.json), then open the prompt packs linked below before starting related work.",
|
|
800
|
+
"",
|
|
801
|
+
"## Available Prompt Packs",
|
|
802
|
+
...prompts.map(({ prompt, stem }) => `- [${prompt.title}](../.prompts-gpt/${stem}.md)`),
|
|
803
|
+
"",
|
|
804
|
+
"When a prompt pack is relevant, load it, adapt variables to the current task, and keep verification tied to the prompt's acceptance criteria.",
|
|
805
|
+
"",
|
|
806
|
+
].join("\n"),
|
|
807
|
+
}];
|
|
808
|
+
}
|
|
809
|
+
if (target === "amp") {
|
|
810
|
+
return [{
|
|
811
|
+
path: "AGENT.md",
|
|
812
|
+
managedBlock: true,
|
|
813
|
+
content: [
|
|
814
|
+
"# Prompts-GPT Amp Instructions",
|
|
815
|
+
"",
|
|
816
|
+
"Prompts synced by `prompts-gpt sync` live in `.prompts-gpt/`. Start with [.prompts-gpt/manifest.json](.prompts-gpt/manifest.json), then open the prompt packs linked below before starting related work.",
|
|
817
|
+
"",
|
|
818
|
+
"## Available Prompt Packs",
|
|
819
|
+
...prompts.map(({ prompt, stem }) => `- [${prompt.title}](.prompts-gpt/${stem}.md)`),
|
|
820
|
+
"",
|
|
821
|
+
"When a prompt pack is relevant, load it, adapt variables to the current task, and keep verification tied to the prompt's acceptance criteria.",
|
|
822
|
+
"",
|
|
823
|
+
].join("\n"),
|
|
824
|
+
}];
|
|
825
|
+
}
|
|
632
826
|
return [];
|
|
633
827
|
}
|
|
634
828
|
function buildVsCodeSnippets(prompts) {
|
|
@@ -689,13 +883,52 @@ function buildDiscoverablePromptFiles(stem, prompt) {
|
|
|
689
883
|
return {
|
|
690
884
|
markdown: `.prompts-gpt/${stem}.md`,
|
|
691
885
|
codexInstructions: supports("codex") ? "AGENTS.md" : null,
|
|
886
|
+
claudeCodeInstructions: supports("claude-code") ? "CLAUDE.md" : null,
|
|
692
887
|
cursorRule: supports("cursor") ? `.cursor/rules/prompts-gpt-${stem}.mdc` : null,
|
|
888
|
+
cursorCommand: supports("cursor") ? `.cursor/commands/prompts-gpt-${stem}.md` : null,
|
|
693
889
|
vscodeInstructions: supports("vscode") ? ".github/copilot-instructions.md" : null,
|
|
694
890
|
copilotPathInstructions: supports("vscode") ? ".github/instructions/prompts-gpt.instructions.md" : null,
|
|
695
891
|
vscodeSnippets: supports("vscode") ? ".vscode/prompts-gpt.code-snippets" : null,
|
|
696
892
|
copilotPrompt: supports("copilot") ? `.github/prompts/prompts-gpt-${stem}.prompt.md` : null,
|
|
893
|
+
continueRule: supports("continue") ? `.continue/rules/prompts-gpt-${stem}.md` : null,
|
|
894
|
+
geminiInstructions: supports("gemini-cli") ? "GEMINI.md" : null,
|
|
895
|
+
windsurfRule: supports("windsurf") ? `.windsurf/rules/prompts-gpt-${stem}.md` : null,
|
|
896
|
+
clineRule: supports("cline") ? `.clinerules/prompts-gpt-${stem}.md` : null,
|
|
897
|
+
junieGuidelines: supports("junie") ? ".junie/guidelines.md" : null,
|
|
898
|
+
ampInstructions: supports("amp") ? "AGENT.md" : null,
|
|
697
899
|
};
|
|
698
900
|
}
|
|
901
|
+
function formatCursorCommandMarkdown(prompt, stem) {
|
|
902
|
+
const lines = [
|
|
903
|
+
`# ${prompt.title}`,
|
|
904
|
+
"",
|
|
905
|
+
`[Canonical prompt pack](../../.prompts-gpt/${stem}.md)`,
|
|
906
|
+
"",
|
|
907
|
+
prompt.summary ?? "",
|
|
908
|
+
"",
|
|
909
|
+
"## Task",
|
|
910
|
+
"",
|
|
911
|
+
prompt.promptText ?? "",
|
|
912
|
+
];
|
|
913
|
+
if (prompt.variables?.length) {
|
|
914
|
+
lines.push("", "## Inputs", "");
|
|
915
|
+
for (const variable of prompt.variables) {
|
|
916
|
+
lines.push(`- ${String(variable).replace(/[{}$]/g, "")}`);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
if (prompt.usageNotes) {
|
|
920
|
+
lines.push("", "## Usage Notes", "", prompt.usageNotes);
|
|
921
|
+
}
|
|
922
|
+
lines.push("", "Verify the output against `.prompts-gpt/manifest.json` and the linked canonical prompt pack.", "");
|
|
923
|
+
return lines
|
|
924
|
+
.reduce((acc, line, index, list) => {
|
|
925
|
+
if (line === "" && index > 0 && list[index - 1] === "" && (index < 2 || list[index - 2] === ""))
|
|
926
|
+
return acc;
|
|
927
|
+
acc.push(line);
|
|
928
|
+
return acc;
|
|
929
|
+
}, [])
|
|
930
|
+
.join("\n");
|
|
931
|
+
}
|
|
699
932
|
function formatCopilotPromptMarkdown(prompt, stem) {
|
|
700
933
|
const sections = [
|
|
701
934
|
"---",
|
|
@@ -755,8 +988,9 @@ function escapeMarkdownLinkText(value) {
|
|
|
755
988
|
return value.replace(/[[\]]/g, "\\$&");
|
|
756
989
|
}
|
|
757
990
|
async function writePromptIndex(prompts, { outDir }) {
|
|
758
|
-
const indexPath = path.
|
|
759
|
-
|
|
991
|
+
const indexPath = path.resolve(outDir, "README.md");
|
|
992
|
+
assertInside(indexPath, path.resolve(outDir));
|
|
993
|
+
const managedContent = [
|
|
760
994
|
"# Prompts-GPT Prompt Packs",
|
|
761
995
|
"",
|
|
762
996
|
"These prompts were synced by `prompts-gpt`. Re-run `prompts-gpt sync` to refresh Markdown and agent files.",
|
|
@@ -770,8 +1004,12 @@ async function writePromptIndex(prompts, { outDir }) {
|
|
|
770
1004
|
}),
|
|
771
1005
|
"",
|
|
772
1006
|
].join("\n");
|
|
773
|
-
|
|
774
|
-
|
|
1007
|
+
let existing = "";
|
|
1008
|
+
try {
|
|
1009
|
+
existing = await readFile(indexPath, "utf8");
|
|
1010
|
+
}
|
|
1011
|
+
catch { }
|
|
1012
|
+
await writeFile(indexPath, upsertManagedBlock(existing, managedContent));
|
|
775
1013
|
}
|
|
776
1014
|
function normalizeAgentTargets(value) {
|
|
777
1015
|
const raw = Array.isArray(value) ? value.join(",") : String(value ?? "all");
|
|
@@ -834,8 +1072,8 @@ function assertInside(filePath, directory) {
|
|
|
834
1072
|
}
|
|
835
1073
|
}
|
|
836
1074
|
function safeSlug(value) {
|
|
837
|
-
const raw = String(value ?? "");
|
|
838
|
-
if (!raw
|
|
1075
|
+
const raw = String(value ?? "").trim();
|
|
1076
|
+
if (!raw)
|
|
839
1077
|
return "prompt";
|
|
840
1078
|
const slug = raw
|
|
841
1079
|
.toLowerCase()
|
|
@@ -844,7 +1082,9 @@ function safeSlug(value) {
|
|
|
844
1082
|
.replace(/[^a-z0-9]+/g, "-")
|
|
845
1083
|
.replace(/^-+|-+$/g, "")
|
|
846
1084
|
.slice(0, 90);
|
|
847
|
-
|
|
1085
|
+
if (!slug || slug === "-")
|
|
1086
|
+
return "prompt";
|
|
1087
|
+
return slug;
|
|
848
1088
|
}
|
|
849
1089
|
function yamlScalar(value) {
|
|
850
1090
|
const s = String(value ?? "");
|
|
@@ -853,15 +1093,4 @@ function yamlScalar(value) {
|
|
|
853
1093
|
}
|
|
854
1094
|
return JSON.stringify(s);
|
|
855
1095
|
}
|
|
856
|
-
async function ensureGitignoreEntry(cwd, entry) {
|
|
857
|
-
const gitignorePath = path.resolve(cwd, ".gitignore");
|
|
858
|
-
const existing = existsSync(gitignorePath) ? await readFile(gitignorePath, "utf8") : "";
|
|
859
|
-
const eol = existing.includes("\r\n") ? "\r\n" : "\n";
|
|
860
|
-
const lines = existing.split(/\r?\n/).map((line) => line.trim());
|
|
861
|
-
if (lines.includes(entry))
|
|
862
|
-
return;
|
|
863
|
-
const needsLeadingNewline = existing.length > 0 && !existing.endsWith("\n") && !existing.endsWith("\r\n");
|
|
864
|
-
const prefix = needsLeadingNewline ? eol : "";
|
|
865
|
-
await writeFile(gitignorePath, `${existing}${prefix}${entry}${eol}`);
|
|
866
|
-
}
|
|
867
1096
|
//# sourceMappingURL=index.js.map
|