promptopskit 0.2.4 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -2
- package/SKILL.md +70 -7
- package/dist/{chunk-CX6KVBW4.js → chunk-2LK6IILW.js} +10 -2
- package/dist/chunk-2LK6IILW.js.map +1 -0
- package/dist/cli/index.js +29 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +85 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -4
- package/dist/index.d.ts +8 -4
- package/dist/index.js +77 -5
- package/dist/index.js.map +1 -1
- package/dist/providers/anthropic.d.cts +2 -2
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/gemini.d.cts +2 -2
- package/dist/providers/gemini.d.ts +2 -2
- package/dist/providers/openai.d.cts +2 -2
- package/dist/providers/openai.d.ts +2 -2
- package/dist/providers/openrouter.d.cts +2 -2
- package/dist/providers/openrouter.d.ts +2 -2
- package/dist/{schema-C6smABrt.d.cts → schema-DJ7C8Q6y.d.cts} +34 -13
- package/dist/{schema-C6smABrt.d.ts → schema-DJ7C8Q6y.d.ts} +34 -13
- package/dist/testing.cjs +9 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/dist/{types-S_c-ZEfK.d.cts → types-BUzJB5p_.d.cts} +1 -1
- package/dist/{types-D7lW5IYT.d.ts → types-DM0-tThJ.d.ts} +1 -1
- package/package.json +1 -1
- package/dist/chunk-CX6KVBW4.js.map +0 -1
package/README.md
CHANGED
|
@@ -63,7 +63,8 @@ sampling:
|
|
|
63
63
|
context:
|
|
64
64
|
inputs:
|
|
65
65
|
- user_message
|
|
66
|
-
- app_context
|
|
66
|
+
- name: app_context
|
|
67
|
+
max_size: 2000
|
|
67
68
|
includes:
|
|
68
69
|
- ./shared/tone.md
|
|
69
70
|
---
|
|
@@ -104,6 +105,19 @@ const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
|
104
105
|
});
|
|
105
106
|
```
|
|
106
107
|
|
|
108
|
+
You can control context size warning behavior at the kit level:
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
const kit = createPromptOpsKit({
|
|
112
|
+
sourceDir: './prompts',
|
|
113
|
+
warnings: {
|
|
114
|
+
contextSize: process.env.NODE_ENV === 'production' ? 'off' : 'console-and-result',
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Supported values for `warnings.contextSize` are `auto`, `off`, `result-only`, `console`, and `console-and-result`.
|
|
120
|
+
|
|
107
121
|
## Features
|
|
108
122
|
|
|
109
123
|
- **Prompts as Markdown** — YAML front matter for settings, H1 headings for sections (`# System instructions`, `# Prompt template`, `# Notes`)
|
|
@@ -113,6 +127,8 @@ const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
|
113
127
|
- **Overrides** — Environment and tier-based overrides (base → env → tier → runtime)
|
|
114
128
|
- **4 provider adapters** — OpenAI, Anthropic, Gemini, OpenRouter — body-only output
|
|
115
129
|
- **Validation** — Zod schema validation, Levenshtein-based "did you mean?" for typos, variable usage checks
|
|
130
|
+
- **Context size guardrails** — optional per-input `max_size` metadata with non-blocking render-time warnings
|
|
131
|
+
- **Warning controls** — top-level config can suppress or emit context size warnings differently in dev and prod
|
|
116
132
|
- **Caching** — LRU cache with mtime-based invalidation
|
|
117
133
|
- **CLI** — init, validate, compile, render, inspect, skill
|
|
118
134
|
- **Compiled artifacts** — Pre-compile `.md` → JSON or ESM for production
|
|
@@ -333,6 +349,7 @@ Creates a `PromptOpsKit` instance.
|
|
|
333
349
|
| `compiledDir` | `string` | — | Path to compiled artifacts |
|
|
334
350
|
| `mode` | `'auto' \| 'compiled-only' \| 'source-only'` | `'auto'` | Resolution strategy |
|
|
335
351
|
| `cache` | `boolean` | `true` | Enable LRU cache with mtime invalidation |
|
|
352
|
+
| `warnings.contextSize` | `'auto' \| 'off' \| 'result-only' \| 'console' \| 'console-and-result'` | `'auto'` | Control whether render-time context size warnings are returned, logged, both, or suppressed |
|
|
336
353
|
|
|
337
354
|
### `kit.renderPrompt(options)`
|
|
338
355
|
|
|
@@ -347,6 +364,7 @@ Renders a prompt for a specific provider. Returns `{ resolved, request, warnings
|
|
|
347
364
|
| `environment` | `string` | Environment override name |
|
|
348
365
|
| `tier` | `string` | Tier override name |
|
|
349
366
|
| `history` | `Array<{ role, content }>` | Conversation history |
|
|
367
|
+
| `toolRegistry` | `Record<string, unknown>` | Tool definitions for resolving string tool references |
|
|
350
368
|
| `strict` | `boolean` | Fail on missing variables |
|
|
351
369
|
|
|
352
370
|
### `kit.loadPrompt(path)` / `kit.resolvePrompt(path, options)` / `kit.validatePrompt(path)`
|
|
@@ -375,7 +393,7 @@ Prompt files use YAML front matter with these fields:
|
|
|
375
393
|
| `response` | `object` | `{ format, stream }` |
|
|
376
394
|
| `tools` | `array` | Tool references (string names or inline definitions) |
|
|
377
395
|
| `mcp` | `object` | MCP server references |
|
|
378
|
-
| `context` | `object` | `{ inputs, history }` — declare expected variables |
|
|
396
|
+
| `context` | `object` | `{ inputs, history }` — declare expected variables, with optional per-input `max_size` budgets |
|
|
379
397
|
| `includes` | `string[]` | Paths to included prompt files |
|
|
380
398
|
| `environments` | `object` | Named environment overrides |
|
|
381
399
|
| `tiers` | `object` | Named tier overrides |
|
package/SKILL.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: promptopskit
|
|
3
|
+
description: Guidance for creating and editing promptopskit prompt files, defaults, variables, and validation-safe templates.
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# promptopskit — Prompt Engineering Skill
|
|
2
7
|
|
|
3
8
|
This project uses **promptopskit** to manage LLM prompts as code.
|
|
@@ -24,7 +29,8 @@ provider: openai
|
|
|
24
29
|
model: gpt-5.4
|
|
25
30
|
context:
|
|
26
31
|
inputs:
|
|
27
|
-
- name
|
|
32
|
+
- name: name
|
|
33
|
+
max_size: 2000
|
|
28
34
|
---
|
|
29
35
|
|
|
30
36
|
# System instructions
|
|
@@ -36,6 +42,13 @@ You are a helpful assistant.
|
|
|
36
42
|
Hello {{ name }}, how can I help you?
|
|
37
43
|
```
|
|
38
44
|
|
|
45
|
+
When creating a new prompt file with "just the necessary fields", include only
|
|
46
|
+
the fields required by that specific file:
|
|
47
|
+
- Always include `id` and `schema_version: 1`
|
|
48
|
+
- Include `provider` and `model` only if they are not inherited from `defaults.md`
|
|
49
|
+
- Include `context.inputs` whenever the body contains `{{ variable }}` placeholders
|
|
50
|
+
- Omit `context` entirely only when the body has no placeholders
|
|
51
|
+
|
|
39
52
|
---
|
|
40
53
|
|
|
41
54
|
## Front matter reference
|
|
@@ -53,7 +66,7 @@ Hello {{ name }}, how can I help you?
|
|
|
53
66
|
| `response` | object | no | `{ format: text|json|markdown, stream: boolean }` |
|
|
54
67
|
| `tools` | array | no | Tool names (strings) or inline definitions with `{ name, description, input_schema }` |
|
|
55
68
|
| `mcp` | object | no | `{ servers: [string | { name, config }] }` |
|
|
56
|
-
| `context.inputs` | string
|
|
69
|
+
| `context.inputs` | `Array<string | { name, max_size? }>` | no | Declared variable names used in templates, with optional size budgets |
|
|
57
70
|
| `context.history` | object | no | `{ max_items: number }` |
|
|
58
71
|
| `includes` | string[] | no | Relative paths to other prompt files to include |
|
|
59
72
|
| `environments` | object | no | Per-environment overrides (see Overrides) |
|
|
@@ -84,10 +97,44 @@ sections. Variables are replaced at render time.
|
|
|
84
97
|
|
|
85
98
|
Rules:
|
|
86
99
|
- Declare all variables in `context.inputs` — validation warns on undeclared usage
|
|
100
|
+
- Before finishing a new prompt file, scan the body for every `{{ variable }}` and
|
|
101
|
+
ensure each exact variable name appears in `context.inputs`
|
|
102
|
+
- Use object-form inputs with `max_size` when a variable is likely to grow large and should trigger early warnings
|
|
87
103
|
- Escape literal braces with `\{{` and `\}}`
|
|
88
104
|
- In strict mode, missing variables throw an error
|
|
89
105
|
- In permissive mode, unresolved placeholders are left intact
|
|
90
106
|
|
|
107
|
+
Example with a size budget:
|
|
108
|
+
|
|
109
|
+
```yaml
|
|
110
|
+
context:
|
|
111
|
+
inputs:
|
|
112
|
+
- user_message
|
|
113
|
+
- name: account_summary
|
|
114
|
+
max_size: 4096
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
If a rendered value exceeds `max_size`, `renderPrompt()` emits a non-blocking `POK030` warning.
|
|
118
|
+
|
|
119
|
+
Example: this is the minimal valid shape for a prompt that references
|
|
120
|
+
`{{ pull_request }}` even when provider/model are inherited from defaults:
|
|
121
|
+
|
|
122
|
+
```markdown
|
|
123
|
+
---
|
|
124
|
+
id: summarizePullRequest
|
|
125
|
+
schema_version: 1
|
|
126
|
+
context:
|
|
127
|
+
inputs:
|
|
128
|
+
- pull_request
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
# Prompt template
|
|
132
|
+
|
|
133
|
+
Summarize the following pull request:
|
|
134
|
+
|
|
135
|
+
{{ pull_request }}
|
|
136
|
+
```
|
|
137
|
+
|
|
91
138
|
---
|
|
92
139
|
|
|
93
140
|
## Includes (composition)
|
|
@@ -131,6 +178,9 @@ Supported default fields:
|
|
|
131
178
|
This lets you configure app-wide settings like `provider` and `model`
|
|
132
179
|
in a single root `defaults.md`, so individual prompts only declare what's unique to them.
|
|
133
180
|
|
|
181
|
+
Important: `defaults.md` does not declare or infer `context.inputs` for a prompt.
|
|
182
|
+
If a prompt body uses placeholders, the prompt file itself must declare them.
|
|
183
|
+
|
|
134
184
|
Rules:
|
|
135
185
|
- Nearest subfolder `defaults.md` overrides parent defaults
|
|
136
186
|
- Prompt-local values always take precedence over defaults
|
|
@@ -202,19 +252,32 @@ import { createPromptOpsKit } from 'promptopskit';
|
|
|
202
252
|
const kit = createPromptOpsKit({ sourceDir: './prompts' });
|
|
203
253
|
|
|
204
254
|
// Load → resolve includes → apply overrides → render
|
|
205
|
-
const
|
|
255
|
+
const result = await kit.renderPrompt({
|
|
256
|
+
path: 'greeting',
|
|
257
|
+
provider: 'openai',
|
|
206
258
|
variables: { name: 'Alice' },
|
|
207
259
|
environment: 'production',
|
|
208
260
|
});
|
|
209
261
|
|
|
210
|
-
// request.body is ready for the provider's API
|
|
262
|
+
// result.request.body is ready for the provider's API
|
|
211
263
|
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
212
264
|
method: 'POST',
|
|
213
265
|
headers: {
|
|
214
266
|
'Content-Type': 'application/json',
|
|
215
267
|
Authorization: `Bearer ${apiKey}`,
|
|
216
268
|
},
|
|
217
|
-
body: JSON.stringify(request.body),
|
|
269
|
+
body: JSON.stringify(result.request.body),
|
|
270
|
+
});
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
You can control render-time context size warnings at the top level:
|
|
274
|
+
|
|
275
|
+
```typescript
|
|
276
|
+
const kit = createPromptOpsKit({
|
|
277
|
+
sourceDir: './prompts',
|
|
278
|
+
warnings: {
|
|
279
|
+
contextSize: process.env.NODE_ENV === 'production' ? 'off' : 'console-and-result',
|
|
280
|
+
},
|
|
218
281
|
});
|
|
219
282
|
```
|
|
220
283
|
|
|
@@ -271,7 +334,7 @@ const asset = parsePrompt(source);
|
|
|
271
334
|
const result = validateAsset(asset);
|
|
272
335
|
|
|
273
336
|
if (!result.valid) {
|
|
274
|
-
console.error(result.errors); //
|
|
337
|
+
console.error(result.errors); // Validation error codes: POK001-POK021
|
|
275
338
|
}
|
|
276
339
|
```
|
|
277
340
|
|
|
@@ -316,7 +379,7 @@ Hello {{ name }}
|
|
|
316
379
|
|
|
317
380
|
1. **One prompt per file** — each `.md` file is a single prompt asset
|
|
318
381
|
2. **Always set `id` and `schema_version: 1`** in front matter (or inherit `schema_version` from `defaults.md`)
|
|
319
|
-
3. **Declare all variables** in `context.inputs` that appear in templates
|
|
382
|
+
3. **Declare all variables** in `context.inputs` that appear in templates; do not leave placeholders undeclared just because other settings come from `defaults.md`
|
|
320
383
|
4. **Use includes** for shared system instructions (tone, safety, formatting)
|
|
321
384
|
5. **Keep prompt templates focused** — compose behavior via includes, not duplication
|
|
322
385
|
6. **Use environment overrides** for dev/staging/prod model differences
|
|
@@ -32,8 +32,16 @@ var ResponseSchema = z.object({
|
|
|
32
32
|
var HistorySchema = z.object({
|
|
33
33
|
max_items: z.number().int().positive().optional()
|
|
34
34
|
});
|
|
35
|
+
var ContextInputDefinitionObjectSchema = z.object({
|
|
36
|
+
name: z.string(),
|
|
37
|
+
max_size: z.number().int().positive().optional()
|
|
38
|
+
});
|
|
39
|
+
var ContextInputDefinitionSchema = z.union([
|
|
40
|
+
z.string(),
|
|
41
|
+
ContextInputDefinitionObjectSchema
|
|
42
|
+
]);
|
|
35
43
|
var ContextSchema = z.object({
|
|
36
|
-
inputs: z.array(
|
|
44
|
+
inputs: z.array(ContextInputDefinitionSchema).optional(),
|
|
37
45
|
history: HistorySchema.optional()
|
|
38
46
|
});
|
|
39
47
|
var MetadataSchema = z.object({
|
|
@@ -250,4 +258,4 @@ export {
|
|
|
250
258
|
parsePrompt,
|
|
251
259
|
loadPromptFile
|
|
252
260
|
};
|
|
253
|
-
//# sourceMappingURL=chunk-
|
|
261
|
+
//# sourceMappingURL=chunk-2LK6IILW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/schema/schema.ts","../src/parser/sections.ts","../src/parser/parser.ts","../src/parser/loader.ts"],"sourcesContent":["import { z } from 'zod';\n\n// --- Tool definitions ---\n\nexport const InlineToolDefSchema = z.object({\n name: z.string(),\n description: z.string().optional(),\n input_schema: z.record(z.unknown()).optional(),\n});\n\nexport type InlineToolDef = z.infer<typeof InlineToolDefSchema>;\n\nexport const ToolRefSchema = z.union([z.string(), InlineToolDefSchema]);\n\n// --- MCP ---\n\nexport const MCPServerRefSchema = z.union([\n z.string(),\n z.object({\n name: z.string(),\n config: z.record(z.unknown()).optional(),\n }),\n]);\n\nexport type MCPServerRef = z.infer<typeof MCPServerRefSchema>;\n\n// --- Reasoning ---\n\nexport const ReasoningSchema = z.object({\n effort: z.enum(['low', 'medium', 'high']).optional(),\n budget_tokens: z.number().int().positive().optional(),\n});\n\n// --- Sampling ---\n\nexport const SamplingSchema = z.object({\n temperature: z.number().min(0).max(2).optional(),\n top_p: z.number().min(0).max(1).optional(),\n frequency_penalty: z.number().optional(),\n presence_penalty: z.number().optional(),\n stop: z.array(z.string()).optional(),\n max_output_tokens: z.number().int().positive().optional(),\n});\n\n// --- Response ---\n\nexport const ResponseSchema = z.object({\n format: z.enum(['text', 'json', 'markdown']).optional(),\n stream: z.boolean().optional(),\n});\n\n// --- Context ---\n\nexport const HistorySchema = z.object({\n max_items: z.number().int().positive().optional(),\n});\n\nexport const ContextInputDefinitionObjectSchema = z.object({\n name: z.string(),\n max_size: z.number().int().positive().optional(),\n});\n\nexport const ContextInputDefinitionSchema = z.union([\n z.string(),\n ContextInputDefinitionObjectSchema,\n]);\n\nexport type ContextInputDefinition = z.infer<typeof ContextInputDefinitionSchema>;\n\nexport const ContextSchema = z.object({\n inputs: z.array(ContextInputDefinitionSchema).optional(),\n history: HistorySchema.optional(),\n});\n\n// --- Metadata ---\n\nexport const MetadataSchema = z.object({\n owner: z.string().optional(),\n tags: z.array(z.string()).optional(),\n review_required: z.boolean().optional(),\n stable: z.boolean().optional(),\n});\n\n// --- MCP block ---\n\nexport const MCPSchema = z.object({\n servers: z.array(MCPServerRefSchema).optional(),\n});\n\n// --- Overrides (subset allowed in environments/tiers) ---\n\nexport const PromptAssetOverridesSchema = z.object({\n model: z.string().optional(),\n fallback_models: z.array(z.string()).optional(),\n reasoning: ReasoningSchema.optional(),\n sampling: SamplingSchema.optional(),\n response: ResponseSchema.optional(),\n tools: z.array(ToolRefSchema).optional(),\n});\n\nexport type PromptAssetOverrides = z.infer<typeof PromptAssetOverridesSchema>;\n\n// --- Source tracking ---\n\nexport const SourceSchema = z.object({\n file_path: z.string().optional(),\n checksum: z.string().optional(),\n});\n\n// --- Sections (populated by parser) ---\n\nexport const SectionsSchema = z.object({\n system_instructions: z.string().optional(),\n prompt_template: z.string().optional(),\n notes: z.string().optional(),\n});\n\n// --- Defaults files (folder-level inheritance) ---\n\nexport const PromptDefaultsSchema = z.object({\n provider: z.enum(['openai', 'anthropic', 'google', 'gemini', 'openrouter', 'any']).optional(),\n model: z.string().optional(),\n metadata: MetadataSchema.optional(),\n sections: z.object({\n system_instructions: z.string().optional(),\n }).optional(),\n});\n\nexport type PromptDefaults = z.infer<typeof PromptDefaultsSchema>;\n\n// --- Top-level PromptAsset ---\n\nexport const PromptAssetSchema = z.object({\n id: z.string(),\n schema_version: z.number().int().positive().default(1),\n description: z.string().optional(),\n\n provider: z.enum(['openai', 'anthropic', 'google', 'gemini', 'openrouter', 'any']).optional(),\n model: z.string().optional(),\n fallback_models: z.array(z.string()).optional(),\n\n reasoning: ReasoningSchema.optional(),\n sampling: SamplingSchema.optional(),\n response: ResponseSchema.optional(),\n\n tools: z.array(ToolRefSchema).optional(),\n mcp: MCPSchema.optional(),\n\n context: ContextSchema.optional(),\n\n includes: z.array(z.string()).optional(),\n\n environments: z.record(PromptAssetOverridesSchema).optional(),\n tiers: z.record(PromptAssetOverridesSchema).optional(),\n\n metadata: MetadataSchema.optional(),\n\n // Populated by parser, not authored in YAML\n sections: SectionsSchema.optional(),\n source: SourceSchema.optional(),\n});\n\nexport type PromptAsset = z.infer<typeof PromptAssetSchema>;\n\n// --- Resolved asset (after includes, overrides applied) ---\n\nexport interface ResolvedPromptAsset extends PromptAsset {\n sections: {\n system_instructions?: string;\n prompt_template?: string;\n notes?: string;\n };\n source: {\n file_path?: string;\n checksum?: string;\n };\n}\n","export interface Sections {\n system_instructions?: string;\n prompt_template?: string;\n notes?: string;\n}\n\nconst SECTION_MAP: Record<string, keyof Sections> = {\n 'system instructions': 'system_instructions',\n 'prompt template': 'prompt_template',\n 'notes': 'notes',\n};\n\n/**\n * Extract named sections from the markdown body using H1 headings.\n * Case-insensitive. H2+ within a section is treated as content.\n * If no H1 headings are found, the entire body is treated as prompt_template.\n */\nexport function extractSections(body: string): Sections {\n const lines = body.split(/\\r?\\n/);\n const sections: Sections = {};\n\n let currentKey: keyof Sections | null = null;\n let currentLines: string[] = [];\n let foundAnyH1 = false;\n\n for (const line of lines) {\n const h1Match = line.match(/^#\\s+(.+)$/);\n if (h1Match) {\n // Flush previous section\n if (currentKey) {\n sections[currentKey] = currentLines.join('\\n').trim();\n }\n\n foundAnyH1 = true;\n const heading = h1Match[1].trim().toLowerCase();\n currentKey = SECTION_MAP[heading] ?? null;\n currentLines = [];\n } else {\n currentLines.push(line);\n }\n }\n\n // Flush last section\n if (currentKey) {\n sections[currentKey] = currentLines.join('\\n').trim();\n }\n\n // If no H1 headings found, treat entire body as prompt_template\n if (!foundAnyH1) {\n const trimmed = body.trim();\n if (trimmed) {\n sections.prompt_template = trimmed;\n }\n }\n\n return sections;\n}\n","import matter from 'gray-matter';\nimport { PromptAssetSchema } from '../schema/index.js';\nimport type { PromptAsset } from '../schema/index.js';\nimport { extractSections } from './sections.js';\n\nexport interface ParseResult {\n asset: PromptAsset;\n raw: {\n frontMatter: Record<string, unknown>;\n body: string;\n };\n}\n\n/**\n * Parse a prompt markdown string (YAML front matter + markdown body)\n * into a validated PromptAsset.\n */\nexport function parsePrompt(content: string, filePath?: string): ParseResult {\n const { data: frontMatter, content: body } = matter(content);\n\n const sections = extractSections(body);\n\n const raw = {\n ...frontMatter,\n sections,\n source: filePath ? { file_path: filePath } : undefined,\n };\n\n const asset = PromptAssetSchema.parse(raw);\n\n return {\n asset,\n raw: {\n frontMatter: frontMatter as Record<string, unknown>,\n body,\n },\n };\n}\n","import { readFile } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport matter from 'gray-matter';\nimport { parsePrompt } from './parser.js';\nimport type { ParseResult } from './parser.js';\nimport { extractSections } from './sections.js';\nimport { PromptDefaultsSchema } from '../schema/index.js';\nimport type { PromptDefaults } from '../schema/index.js';\n\nconst DEFAULTS_FILE_NAME = 'defaults.md';\n\nexport interface LoadPromptOptions {\n /**\n * Optional boundary directory for defaults discovery.\n * If provided, defaults are loaded from this directory down to the prompt directory.\n */\n defaultsRoot?: string;\n}\n\n/**\n * Load and parse a prompt file from disk.\n */\nexport async function loadPromptFile(filePath: string, options: LoadPromptOptions = {}): Promise<ParseResult> {\n const content = await readFile(filePath, 'utf-8');\n const parsed = parsePrompt(content, filePath);\n // Default the boundary to the file's own directory so traversal never\n // walks above the prompt tree when no explicit root is provided.\n const root = options.defaultsRoot ?? dirname(filePath);\n const defaults = await loadDefaultsForPath(filePath, root);\n const asset = applyDefaults(parsed.asset, defaults);\n\n return {\n ...parsed,\n asset,\n };\n}\n\nasync function loadDefaultsForPath(filePath: string, defaultsRoot?: string): Promise<PromptDefaults> {\n const directories = getDirectoriesToCheck(filePath, defaultsRoot);\n let merged: PromptDefaults = {};\n\n for (const dir of directories) {\n const defaultsPath = join(dir, DEFAULTS_FILE_NAME);\n try {\n const defaultsContent = await readFile(defaultsPath, 'utf-8');\n const defaults = parseDefaults(defaultsContent);\n merged = mergeDefaults(merged, defaults);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw error;\n }\n }\n }\n\n return merged;\n}\n\nfunction getDirectoriesToCheck(filePath: string, defaultsRoot?: string): string[] {\n const dirs: string[] = [];\n let current = resolve(dirname(filePath));\n const boundary = defaultsRoot ? resolve(defaultsRoot) : undefined;\n\n while (true) {\n dirs.unshift(current);\n if ((boundary && current === boundary) || current === dirname(current)) {\n break;\n }\n current = dirname(current);\n }\n\n return dirs;\n}\n\nfunction parseDefaults(content: string): PromptDefaults {\n const { data: frontMatter, content: body } = matter(content);\n const sections = extractSections(body);\n\n return PromptDefaultsSchema.parse({\n ...frontMatter,\n sections: {\n system_instructions: sections.system_instructions,\n },\n });\n}\n\nfunction mergeDefaults(base: PromptDefaults, local: PromptDefaults): PromptDefaults {\n return {\n provider: local.provider ?? base.provider,\n model: local.model ?? base.model,\n metadata: {\n ...(base.metadata ?? {}),\n ...(local.metadata ?? {}),\n },\n sections: {\n ...(base.sections ?? {}),\n ...(local.sections ?? {}),\n },\n };\n}\n\nfunction applyDefaults(asset: ParseResult['asset'], defaults: PromptDefaults): ParseResult['asset'] {\n const hasDefaultMetadata = defaults.metadata && Object.keys(defaults.metadata).length > 0;\n const hasDefaultSystem = !!defaults.sections?.system_instructions;\n const hasDefaultScalars = defaults.provider !== undefined\n || defaults.model !== undefined;\n\n // Short-circuit: nothing to merge\n if (!hasDefaultMetadata && !hasDefaultSystem && !hasDefaultScalars) {\n return asset;\n }\n\n const mergedMetadata = {\n ...(defaults.metadata ?? {}),\n ...(asset.metadata ?? {}),\n };\n const metadata = Object.keys(mergedMetadata).length > 0 ? mergedMetadata : undefined;\n\n const systemInstructions = asset.sections?.system_instructions ?? defaults.sections?.system_instructions;\n\n const sections = asset.sections\n ? { ...asset.sections, system_instructions: systemInstructions }\n : systemInstructions\n ? { system_instructions: systemInstructions }\n : undefined;\n\n return {\n ...asset,\n provider: asset.provider ?? defaults.provider,\n model: asset.model ?? defaults.model,\n metadata,\n sections,\n };\n}\n"],"mappings":"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","names":["matter","matter"]}
|
package/dist/cli/index.js
CHANGED
|
@@ -41,8 +41,16 @@ var ResponseSchema = z.object({
|
|
|
41
41
|
var HistorySchema = z.object({
|
|
42
42
|
max_items: z.number().int().positive().optional()
|
|
43
43
|
});
|
|
44
|
+
var ContextInputDefinitionObjectSchema = z.object({
|
|
45
|
+
name: z.string(),
|
|
46
|
+
max_size: z.number().int().positive().optional()
|
|
47
|
+
});
|
|
48
|
+
var ContextInputDefinitionSchema = z.union([
|
|
49
|
+
z.string(),
|
|
50
|
+
ContextInputDefinitionObjectSchema
|
|
51
|
+
]);
|
|
44
52
|
var ContextSchema = z.object({
|
|
45
|
-
inputs: z.array(
|
|
53
|
+
inputs: z.array(ContextInputDefinitionSchema).optional(),
|
|
46
54
|
history: HistorySchema.optional()
|
|
47
55
|
});
|
|
48
56
|
var MetadataSchema = z.object({
|
|
@@ -319,6 +327,24 @@ async function resolveIncludes(asset, basePath, visited = /* @__PURE__ */ new Se
|
|
|
319
327
|
};
|
|
320
328
|
}
|
|
321
329
|
|
|
330
|
+
// src/context.ts
|
|
331
|
+
var textEncoder = new TextEncoder();
|
|
332
|
+
function getContextInputs(asset) {
|
|
333
|
+
return (asset.context?.inputs ?? []).map(normalizeContextInput);
|
|
334
|
+
}
|
|
335
|
+
function getContextInputNames(asset) {
|
|
336
|
+
return getContextInputs(asset).map((input) => input.name);
|
|
337
|
+
}
|
|
338
|
+
function normalizeContextInput(input) {
|
|
339
|
+
if (typeof input === "string") {
|
|
340
|
+
return { name: input };
|
|
341
|
+
}
|
|
342
|
+
return {
|
|
343
|
+
name: input.name,
|
|
344
|
+
max_size: input.max_size
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
322
348
|
// src/validation/levenshtein.ts
|
|
323
349
|
function levenshtein(a, b) {
|
|
324
350
|
const m = a.length;
|
|
@@ -400,7 +426,7 @@ function validateAsset(asset, frontMatterKeys, filePath) {
|
|
|
400
426
|
}
|
|
401
427
|
}
|
|
402
428
|
}
|
|
403
|
-
const declaredInputs = new Set(asset
|
|
429
|
+
const declaredInputs = new Set(getContextInputNames(asset));
|
|
404
430
|
const usedVars = /* @__PURE__ */ new Set();
|
|
405
431
|
if (asset.sections?.system_instructions) {
|
|
406
432
|
for (const v of extractVariables(asset.sections.system_instructions)) {
|
|
@@ -413,7 +439,7 @@ function validateAsset(asset, frontMatterKeys, filePath) {
|
|
|
413
439
|
}
|
|
414
440
|
}
|
|
415
441
|
for (const v of usedVars) {
|
|
416
|
-
if (
|
|
442
|
+
if (!declaredInputs.has(v)) {
|
|
417
443
|
warnings.push({
|
|
418
444
|
code: "POK011",
|
|
419
445
|
message: `Variable "{{ ${v} }}" is used but not declared in context.inputs`,
|