Skip to content

Commit 9ce84d4

Browse files
CHANGE: Changed the default compile output folder defaults and updated documentation
1 parent ef812da commit 9ce84d4

11 files changed

Lines changed: 148 additions & 38 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ Direct adapter rendering also accepts `environment` and `tier` selectors. This i
187187
```typescript
188188
import type { ResolvedPromptAsset } from 'promptopskit';
189189
import { openaiAdapter } from 'promptopskit/openai';
190-
import compiledPrompt from './dist/prompts/summarizePullRequest.mjs';
190+
import compiledPrompt from './.generated-prompts/esm/summarizePullRequest.mjs';
191191

192192
const prompt = compiledPrompt as ResolvedPromptAsset;
193193

@@ -217,7 +217,7 @@ const request = await openaiAdapter.renderPrompt(
217217
{
218218
path: 'summarizePullRequest',
219219
sourceDir: path.join(process.cwd(), 'prompts'),
220-
compiledDir: path.join(process.cwd(), 'output-json'),
220+
compiledDir: path.join(process.cwd(), '.generated-prompts', 'json'),
221221
},
222222
{
223223
environment: 'dev',
@@ -386,7 +386,7 @@ promptopskit skill
386386
promptopskit validate <dir> [--strict]
387387

388388
# Compile .md → JSON/ESM artifacts
389-
promptopskit compile <src> <out> [--dry-run] [--format json|esm] [--no-clean]
389+
promptopskit compile [src] [out] [--dry-run] [--format json|esm] [--no-clean]
390390

391391
# Render a prompt preview (auto-loads .test.yaml sidecar)
392392
promptopskit render <file> [--env <name>] [--tier <name>] [--vars <file>] [--json]

SKILL.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ import { createPromptOpsKit } from 'promptopskit';
258258
259259
const kit = createPromptOpsKit({
260260
sourceDir: './prompts',
261-
compiledDir: './dist/prompts',
261+
compiledDir: './.generated-prompts/json',
262262
warnings: {
263263
contextSize: process.env.NODE_ENV === 'production' ? 'off' : 'console-and-result',
264264
},
@@ -289,7 +289,7 @@ const request = await openaiAdapter.renderPrompt(
289289
{
290290
path: 'support/reply',
291291
sourceDir: path.join(process.cwd(), 'prompts'),
292-
compiledDir: path.join(process.cwd(), 'dist/prompts'),
292+
compiledDir: path.join(process.cwd(), '.generated-prompts', 'json'),
293293
},
294294
{
295295
environment: 'production',
@@ -311,7 +311,7 @@ const request = await openaiAdapter.renderPrompt(
311311
```typescript
312312
import type { ResolvedPromptAsset } from 'promptopskit';
313313
import { openaiAdapter } from 'promptopskit/openai';
314-
import compiledPrompt from './dist/prompts/support/reply.mjs';
314+
import compiledPrompt from './.generated-prompts/esm/support/reply.mjs';
315315
316316
const prompt = compiledPrompt as ResolvedPromptAsset;
317317
@@ -344,13 +344,13 @@ Prompts should usually be validated and compiled as part of the normal build pip
344344
{
345345
"scripts": {
346346
"validate:prompts": "promptopskit validate ./prompts --strict",
347-
"build:prompts": "promptopskit compile ./prompts ./dist/prompts --format json",
347+
"build:prompts": "promptopskit compile",
348348
"build": "npm run validate:prompts && npm run build:prompts && tsup"
349349
}
350350
}
351351
```
352352

353-
Use `--format json` for server-side Node usage where prompts are loaded from disk. Use `--format esm` when prompts need to be imported into a bundle.
353+
`promptopskit compile` defaults to JSON output in `./.generated-prompts/json`, which matches runtime `compiledDir` loading. Use `promptopskit compile --format esm` when prompts need to be imported into a bundle; those artifacts default to `./.generated-prompts/esm`.
354354

355355
### Build strategy by environment
356356

@@ -362,7 +362,7 @@ Use `--format json` for server-side Node usage where prompts are loaded from dis
362362

363363
- Add `validate:prompts` before `build:prompts` so schema or variable mistakes fail fast
364364
- Treat compiled artifacts as build outputs, not the source of truth
365-
- Keep prompt source in `./prompts` and compiled output in a generated directory such as `./dist/prompts` or `./src/generated/prompts`
365+
- Keep prompt source in `./prompts`; use `./.generated-prompts/json` as the default server output and `./.generated-prompts/esm` for imported client artifacts unless a project-specific build layout needs something else
366366
- If using `createPromptOpsKit` in `auto` mode, point both `sourceDir` and `compiledDir` at those directories so local development can fall back to source when artifacts are stale or missing
367367

368368
### Typical server-side setup
@@ -372,7 +372,7 @@ import { createPromptOpsKit } from 'promptopskit';
372372
373373
export const prompts = createPromptOpsKit({
374374
sourceDir: './prompts',
375-
compiledDir: './dist/prompts',
375+
compiledDir: './.generated-prompts/json',
376376
mode: 'auto',
377377
});
378378
```
@@ -432,7 +432,7 @@ Hello {{ name }}
432432
|---------|-------------|
433433
| `promptopskit init [dir]` | Scaffold a prompts directory with starter files (including `defaults.md`) |
434434
| `promptopskit validate <dir>` | Validate all prompt files in a directory |
435-
| `promptopskit compile <src> <out>` | Compile `.md` prompts to JSON or ESM artifacts |
435+
| `promptopskit compile [src] [out]` | Compile `.md` prompts to JSON or ESM artifacts |
436436
| `promptopskit render <file>` | Render a prompt preview |
437437
| `promptopskit inspect <file>` | Print the normalized prompt asset |
438438

docs/api-reference.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { createPromptOpsKit } from 'promptopskit';
99

1010
const kit = createPromptOpsKit({
1111
sourceDir: './prompts',
12-
compiledDir: './dist/prompts',
12+
compiledDir: './.generated-prompts/json',
1313
mode: 'auto',
1414
cache: true,
1515
warnings: {

docs/cli.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,23 @@ Output per file:
6565
Compile `.md` prompt files to JSON or ESM artifacts.
6666

6767
```bash
68-
promptopskit compile <src> <out> [--dry-run] [--format json|esm] [--no-clean]
68+
promptopskit compile [src] [out] [--dry-run] [--format json|esm] [--no-clean]
6969
```
7070

7171
| Option | Default | Description |
7272
|--------|---------|-------------|
73-
| `<src>` || Source directory (required) |
74-
| `<out>` || Output directory (required) |
73+
| `<src>` | `./prompts` | Source directory |
74+
| `<out>` | `./.generated-prompts/json` | Output directory |
75+
| `--source`, `-s` || Explicit source directory override |
76+
| `--output`, `-o` || Explicit output directory override |
7577
| `--format` | `json` | Output format: `json` or `esm` |
7678
| `--dry-run` || Show what would be compiled without writing |
7779
| `--no-clean` || Don't clear the output directory before compiling |
7880

7981
Includes are resolved during compilation so compiled artifacts are self-sufficient. The output directory is cleared by default before compiling (unless `--no-clean` is set).
8082

83+
If you omit `<out>`, the CLI chooses `./.generated-prompts/json` for `json` and `./.generated-prompts/esm` for `esm`.
84+
8185
`defaults.md` files are treated as configuration inputs and are not compiled as standalone prompts.
8286

8387
JSON format produces `.json` files:

docs/getting-started.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,15 @@ This checks all `.md` files for schema errors, unknown front matter keys (with "
119119
## Compile for production
120120

121121
```bash
122-
npx promptopskit compile ./prompts ./dist/prompts
122+
npx promptopskit compile
123123
```
124124

125125
Pre-compiles `.md` files to JSON (or ESM) artifacts so deployments skip parsing entirely. Add to your build scripts:
126126

127127
```json
128128
{
129129
"scripts": {
130-
"build:prompts": "promptopskit compile ./prompts ./dist/prompts"
130+
"build:prompts": "promptopskit compile"
131131
}
132132
}
133133
```

docs/providers.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ const request = await openaiAdapter.renderPrompt(
6868
{
6969
path: 'summarizePullRequest',
7070
sourceDir: path.join(process.cwd(), 'prompts'),
71-
compiledDir: path.join(process.cwd(), 'output-json'),
71+
compiledDir: path.join(process.cwd(), '.generated-prompts', 'json'),
7272
},
7373
{
7474
environment: 'dev',
@@ -86,7 +86,7 @@ The top-level `promptopskit` runtime is Node-oriented. It supports prompt loadin
8686

8787
For browser or client-side code:
8888

89-
- Precompile prompts to ESM with `promptopskit compile ./prompts ./dist/prompts --format esm` and import the generated artifact, or inline a small `ResolvedPromptAsset`.
89+
- Precompile prompts to ESM with `promptopskit compile --format esm` and import the generated artifact from `./.generated-prompts/esm`, or inline a small `ResolvedPromptAsset`.
9090
- Pass `environment` and `tier` directly to `adapter.validate()` and `adapter.render()` when you need overrides on the client side.
9191
- Avoid `renderPrompt()` in browser-only code because resolving prompt files from disk is Node-oriented.
9292
- Keep provider credentials on the server. In production, use the rendered request body with a server endpoint, server action, or edge function that owns the API key.

src/cli/commands/compile.ts

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ import { loadPromptFile } from '../../parser/index.js';
44
import { resolveIncludes } from '../../composition/index.js';
55

66
const HELP = `
7-
promptopskit compile <sourceDir> <outputDir> [options]
7+
promptopskit compile [sourceDir] [outputDir] [options]
88
9-
Compile .md prompt files to JSON artifacts.
9+
Compile .md prompt files to JSON or ESM artifacts.
1010
1111
Options:
12+
--source, -s Source directory (default: ./prompts)
13+
--output, -o Output directory (default: ./.generated-prompts/<format>)
1214
--no-clean Don't clear the output directory before compiling
1315
--dry-run Show what would be compiled without writing files
1416
--format Output format: json (default) or esm
@@ -21,16 +23,7 @@ export async function compile(args: string[]): Promise<void> {
2123
return;
2224
}
2325

24-
const positional = args.filter((a) => !a.startsWith('--'));
25-
const sourceDir = positional[0];
26-
const outputDir = positional[1];
27-
28-
if (!sourceDir || !outputDir) {
29-
console.error('Error: Please provide source and output directories.');
30-
console.error('Usage: promptopskit compile <sourceDir> <outputDir>');
31-
process.exit(1);
32-
}
33-
26+
const positional = getPositionalArgs(args, new Set(['--format', '--source', '--output', '-s', '-o']));
3427
const dryRun = args.includes('--dry-run');
3528
const noClean = args.includes('--no-clean');
3629
const format = getFlag(args, '--format') ?? 'json';
@@ -40,6 +33,9 @@ export async function compile(args: string[]): Promise<void> {
4033
process.exit(1);
4134
}
4235

36+
const sourceDir = getFlag(args, '--source', '-s') ?? positional[0] ?? './prompts';
37+
const outputDir = getFlag(args, '--output', '-o') ?? positional[1] ?? defaultOutputDirForFormat(format);
38+
4339
// Collect prompt files
4440
const files = await collectPromptFiles(sourceDir);
4541

@@ -103,10 +99,36 @@ export async function compile(args: string[]): Promise<void> {
10399
}
104100
}
105101

106-
function getFlag(args: string[], flag: string): string | undefined {
107-
const idx = args.indexOf(flag);
108-
if (idx >= 0 && idx + 1 < args.length) {
109-
return args[idx + 1];
102+
function defaultOutputDirForFormat(format: 'json' | 'esm'): string {
103+
return format === 'esm' ? './.generated-prompts/esm' : './.generated-prompts/json';
104+
}
105+
106+
function getPositionalArgs(args: string[], flagsWithValues: Set<string>): string[] {
107+
const positional: string[] = [];
108+
109+
for (let index = 0; index < args.length; index++) {
110+
const arg = args[index];
111+
if (flagsWithValues.has(arg)) {
112+
index++;
113+
continue;
114+
}
115+
116+
if (arg.startsWith('-')) {
117+
continue;
118+
}
119+
120+
positional.push(arg);
121+
}
122+
123+
return positional;
124+
}
125+
126+
function getFlag(args: string[], ...flags: string[]): string | undefined {
127+
for (const flag of flags) {
128+
const idx = args.indexOf(flag);
129+
if (idx >= 0 && idx + 1 < args.length) {
130+
return args[idx + 1];
131+
}
110132
}
111133
return undefined;
112134
}

src/cli/commands/init.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ promptopskit init [dir]
77
88
Scaffold a prompts directory with starter files.
99
10+
Arguments:
11+
dir Target directory (default: ./prompts)
12+
1013
Options:
1114
--help, -h Show this help
1215
`.trim();
@@ -180,7 +183,7 @@ export async function init(args: string[]): Promise<void> {
180183
if (!pkg.scripts?.['build:prompts']) {
181184
console.log();
182185
console.log(`Tip: Add to your package.json scripts:`);
183-
console.log(` "build:prompts": "promptopskit compile ${dir} ./dist/prompts"`);
186+
console.log(` "build:prompts": "promptopskit compile ${dir}"`);
184187
}
185188
} catch {
186189
// Ignore parse errors

src/cli/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Usage:
1414
Commands:
1515
init [dir] Scaffold a prompts directory with starter files
1616
validate <dir> Validate prompt files
17-
compile <src> <out> [options] Compile .md prompts to JSON/ESM artifacts
17+
compile [src] [out] [options] Compile .md prompts to JSON/ESM artifacts
1818
render <file> [options] Render a prompt preview
1919
inspect <file> Print normalized prompt asset
2020
skill [options] Deploy AI agent instructions into your project

tests/composition.test.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,4 +355,85 @@ Hello.
355355
const compiled = JSON.parse(await readFile(join(outDir, 'simple.json'), 'utf-8'));
356356
expect(compiled.sections.prompt_template).toBe('Hello.');
357357
});
358+
359+
it('defaults to ./prompts and ./.generated-prompts/json', async () => {
360+
const cwd = process.cwd();
361+
const srcDir = join(tmpDir, 'prompts');
362+
const outDir = join(tmpDir, '.generated-prompts', 'json');
363+
await mkdir(srcDir, { recursive: true });
364+
365+
await writeFile(join(srcDir, 'defaulted.md'), `---
366+
id: defaulted
367+
schema_version: 1
368+
---
369+
370+
# Prompt template
371+
372+
Hello.
373+
`);
374+
375+
process.chdir(tmpDir);
376+
377+
try {
378+
const { compile } = await import('../src/cli/commands/compile.js');
379+
await compile([]);
380+
} finally {
381+
process.chdir(cwd);
382+
}
383+
384+
const compiled = JSON.parse(await readFile(join(outDir, 'defaulted.json'), 'utf-8'));
385+
expect(compiled.id).toBe('defaulted');
386+
});
387+
388+
it('defaults ESM output to ./.generated-prompts/esm', async () => {
389+
const cwd = process.cwd();
390+
const srcDir = join(tmpDir, 'prompts');
391+
const outDir = join(tmpDir, '.generated-prompts', 'esm');
392+
await mkdir(srcDir, { recursive: true });
393+
394+
await writeFile(join(srcDir, 'esm-default.md'), `---
395+
id: esm-default
396+
schema_version: 1
397+
---
398+
399+
# Prompt template
400+
401+
Hello.
402+
`);
403+
404+
process.chdir(tmpDir);
405+
406+
try {
407+
const { compile } = await import('../src/cli/commands/compile.js');
408+
await compile(['--format', 'esm']);
409+
} finally {
410+
process.chdir(cwd);
411+
}
412+
413+
const compiled = await readFile(join(outDir, 'esm-default.mjs'), 'utf-8');
414+
expect(compiled).toContain('export default');
415+
expect(compiled).toContain('"id": "esm-default"');
416+
});
417+
418+
it('accepts -s and -o aliases for source and output', async () => {
419+
const srcDir = join(tmpDir, 'source-prompts');
420+
const outDir = join(tmpDir, 'custom-output');
421+
await mkdir(srcDir, { recursive: true });
422+
423+
await writeFile(join(srcDir, 'aliased.md'), `---
424+
id: aliased
425+
schema_version: 1
426+
---
427+
428+
# Prompt template
429+
430+
Hello.
431+
`);
432+
433+
const { compile } = await import('../src/cli/commands/compile.js');
434+
await compile(['-s', srcDir, '-o', outDir]);
435+
436+
const compiled = JSON.parse(await readFile(join(outDir, 'aliased.json'), 'utf-8'));
437+
expect(compiled.id).toBe('aliased');
438+
});
358439
});

0 commit comments

Comments
 (0)