promptopskit 0.3.5 → 0.3.7

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.
Files changed (56) hide show
  1. package/README.md +12 -5
  2. package/SKILL.md +8 -1
  3. package/dist/{chunk-7RWTFGMS.js → chunk-5TLHYSP7.js} +2 -2
  4. package/dist/{chunk-M5VKRDIY.js → chunk-6XKV4YVK.js} +256 -3
  5. package/dist/chunk-6XKV4YVK.js.map +1 -0
  6. package/dist/{chunk-ROBYCHAW.js → chunk-DGLLQ3FR.js} +3 -3
  7. package/dist/{chunk-2LK6IILW.js → chunk-IXPIBZXT.js} +14 -2
  8. package/dist/chunk-IXPIBZXT.js.map +1 -0
  9. package/dist/{chunk-4QW4BSGE.js → chunk-KFSP5KN4.js} +2 -2
  10. package/dist/{chunk-2X5HFPSD.js → chunk-QPOHKVY5.js} +2 -2
  11. package/dist/cli/index.js +256 -93
  12. package/dist/cli/index.js.map +1 -1
  13. package/dist/index.cjs +295 -46
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.cts +7 -5
  16. package/dist/index.d.ts +7 -5
  17. package/dist/index.js +44 -50
  18. package/dist/index.js.map +1 -1
  19. package/dist/providers/anthropic.cjs +238 -2
  20. package/dist/providers/anthropic.cjs.map +1 -1
  21. package/dist/providers/anthropic.d.cts +2 -2
  22. package/dist/providers/anthropic.d.ts +2 -2
  23. package/dist/providers/anthropic.js +3 -3
  24. package/dist/providers/gemini.cjs +238 -2
  25. package/dist/providers/gemini.cjs.map +1 -1
  26. package/dist/providers/gemini.d.cts +2 -2
  27. package/dist/providers/gemini.d.ts +2 -2
  28. package/dist/providers/gemini.js +3 -3
  29. package/dist/providers/openai.cjs +238 -2
  30. package/dist/providers/openai.cjs.map +1 -1
  31. package/dist/providers/openai.d.cts +2 -2
  32. package/dist/providers/openai.d.ts +2 -2
  33. package/dist/providers/openai.js +3 -3
  34. package/dist/providers/openrouter.cjs +238 -2
  35. package/dist/providers/openrouter.cjs.map +1 -1
  36. package/dist/providers/openrouter.d.cts +2 -2
  37. package/dist/providers/openrouter.d.ts +2 -2
  38. package/dist/providers/openrouter.js +4 -4
  39. package/dist/{schema-Dq0jKest.d.cts → schema-Bgoff-CN.d.cts} +89 -0
  40. package/dist/{schema-Dq0jKest.d.ts → schema-Bgoff-CN.d.ts} +89 -0
  41. package/dist/testing.cjs +13 -1
  42. package/dist/testing.cjs.map +1 -1
  43. package/dist/testing.d.cts +1 -1
  44. package/dist/testing.d.ts +1 -1
  45. package/dist/testing.js +1 -1
  46. package/dist/{types-ClXTFaX-.d.cts → types-7U58bgVW.d.cts} +8 -1
  47. package/dist/{types-lLD7m02V.d.ts → types-HnZ46u5Q.d.ts} +8 -1
  48. package/dist/usagetap/index.d.cts +2 -2
  49. package/dist/usagetap/index.d.ts +2 -2
  50. package/package.json +1 -1
  51. package/dist/chunk-2LK6IILW.js.map +0 -1
  52. package/dist/chunk-M5VKRDIY.js.map +0 -1
  53. /package/dist/{chunk-7RWTFGMS.js.map → chunk-5TLHYSP7.js.map} +0 -0
  54. /package/dist/{chunk-ROBYCHAW.js.map → chunk-DGLLQ3FR.js.map} +0 -0
  55. /package/dist/{chunk-4QW4BSGE.js.map → chunk-KFSP5KN4.js.map} +0 -0
  56. /package/dist/{chunk-2X5HFPSD.js.map → chunk-QPOHKVY5.js.map} +0 -0
package/dist/index.d.cts CHANGED
@@ -1,7 +1,7 @@
1
- import { P as PromptAsset, a as PromptAssetOverrides, R as ResolvedPromptAsset } from './schema-Dq0jKest.cjs';
2
- export { b as PromptAssetOverridesSchema, c as PromptAssetSchema } from './schema-Dq0jKest.cjs';
3
- import { P as ProviderAdapter, a as ProviderRequest } from './types-ClXTFaX-.cjs';
4
- export { b as ProviderInlinePromptSource, c as ProviderPromptInput, d as ProviderPromptLookup, R as RuntimeRenderOptions, V as ValidationResult } from './types-ClXTFaX-.cjs';
1
+ import { P as PromptAsset, a as PromptAssetOverrides, R as ResolvedPromptAsset } from './schema-Bgoff-CN.cjs';
2
+ export { b as PromptAssetOverridesSchema, c as PromptAssetSchema } from './schema-Bgoff-CN.cjs';
3
+ import { P as ProviderAdapter, R as RuntimeRenderOptions, a as ProviderRequest } from './types-7U58bgVW.cjs';
4
+ export { b as ProviderInlinePromptSource, c as ProviderPromptInput, d as ProviderPromptLookup, V as ValidationResult } from './types-7U58bgVW.cjs';
5
5
  export { UsageTapAllowed, UsageTapAllowedCapability, UsageTapBeginRequest, UsageTapBeginResponse, UsageTapCallOptions, UsageTapCallResult, UsageTapClient, UsageTapClientConfig, UsageTapEndRequest, UsageTapEndResponse, UsageTapEndUsage, UsageTapEntitlementMode, UsageTapEntitlementOptions, UsageTapErrorPayload, UsageTapInvokeContext, UsageTapInvokeResult, UsageTapProviderRunOptions, UsageTapProviderRunResult, UsageTapReasoningLevel, applyUsageTapEntitlements, beginUsageTapCall, createUsageTapClient, defaultUsageTapErrorMapper, endUsageTapCall, extractAnthropicUsage, extractGeminiUsage, extractOpenAIUsage, runAnthropicWithUsageTap, runGeminiWithUsageTap, runOpenAIWithUsageTap, runOpenRouterWithUsageTap, withUsageTapCall } from './usagetap/index.cjs';
6
6
  export { anthropicAdapter } from './providers/anthropic.cjs';
7
7
  export { geminiAdapter } from './providers/gemini.cjs';
@@ -142,6 +142,8 @@ interface RenderPromptOptions {
142
142
  runtime?: Partial<PromptAssetOverrides>;
143
143
  /** Variables for interpolation */
144
144
  variables?: Record<string, string>;
145
+ /** Optional callback to transform oversized context values before warnings/rendering */
146
+ onContextOverflow?: RuntimeRenderOptions['onContextOverflow'];
145
147
  /** Conversation history */
146
148
  history?: Array<{
147
149
  role: string;
@@ -196,4 +198,4 @@ declare function renderPrompt(options: RenderPromptOptions & {
196
198
  warnings?: PromptOpsKitConfig['warnings'];
197
199
  }): Promise<RenderResult>;
198
200
 
199
- export { type OverrideOptions, type ParseResult, PromptAsset, PromptOpsKit, type PromptOpsKitConfig, type PromptValidationResult, ProviderAdapter, ProviderRequest, type RenderOptions, type RenderPromptOptions, type RenderResult, type RenderedSections, ResolvedPromptAsset, type ValidationError, applyOverrides, createPromptOpsKit, extractSections, extractVariables, getAdapter, interpolate, loadPromptFile, parsePrompt, renderPrompt, resolveIncludes, validateAsset, validateAssetWithIncludes };
201
+ export { type OverrideOptions, type ParseResult, PromptAsset, PromptOpsKit, type PromptOpsKitConfig, type PromptValidationResult, ProviderAdapter, ProviderRequest, type RenderOptions, type RenderPromptOptions, type RenderResult, type RenderedSections, ResolvedPromptAsset, RuntimeRenderOptions, type ValidationError, applyOverrides, createPromptOpsKit, extractSections, extractVariables, getAdapter, interpolate, loadPromptFile, parsePrompt, renderPrompt, resolveIncludes, validateAsset, validateAssetWithIncludes };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { P as PromptAsset, a as PromptAssetOverrides, R as ResolvedPromptAsset } from './schema-Dq0jKest.js';
2
- export { b as PromptAssetOverridesSchema, c as PromptAssetSchema } from './schema-Dq0jKest.js';
3
- import { P as ProviderAdapter, a as ProviderRequest } from './types-lLD7m02V.js';
4
- export { b as ProviderInlinePromptSource, c as ProviderPromptInput, d as ProviderPromptLookup, R as RuntimeRenderOptions, V as ValidationResult } from './types-lLD7m02V.js';
1
+ import { P as PromptAsset, a as PromptAssetOverrides, R as ResolvedPromptAsset } from './schema-Bgoff-CN.js';
2
+ export { b as PromptAssetOverridesSchema, c as PromptAssetSchema } from './schema-Bgoff-CN.js';
3
+ import { P as ProviderAdapter, R as RuntimeRenderOptions, a as ProviderRequest } from './types-HnZ46u5Q.js';
4
+ export { b as ProviderInlinePromptSource, c as ProviderPromptInput, d as ProviderPromptLookup, V as ValidationResult } from './types-HnZ46u5Q.js';
5
5
  export { UsageTapAllowed, UsageTapAllowedCapability, UsageTapBeginRequest, UsageTapBeginResponse, UsageTapCallOptions, UsageTapCallResult, UsageTapClient, UsageTapClientConfig, UsageTapEndRequest, UsageTapEndResponse, UsageTapEndUsage, UsageTapEntitlementMode, UsageTapEntitlementOptions, UsageTapErrorPayload, UsageTapInvokeContext, UsageTapInvokeResult, UsageTapProviderRunOptions, UsageTapProviderRunResult, UsageTapReasoningLevel, applyUsageTapEntitlements, beginUsageTapCall, createUsageTapClient, defaultUsageTapErrorMapper, endUsageTapCall, extractAnthropicUsage, extractGeminiUsage, extractOpenAIUsage, runAnthropicWithUsageTap, runGeminiWithUsageTap, runOpenAIWithUsageTap, runOpenRouterWithUsageTap, withUsageTapCall } from './usagetap/index.js';
6
6
  export { anthropicAdapter } from './providers/anthropic.js';
7
7
  export { geminiAdapter } from './providers/gemini.js';
@@ -142,6 +142,8 @@ interface RenderPromptOptions {
142
142
  runtime?: Partial<PromptAssetOverrides>;
143
143
  /** Variables for interpolation */
144
144
  variables?: Record<string, string>;
145
+ /** Optional callback to transform oversized context values before warnings/rendering */
146
+ onContextOverflow?: RuntimeRenderOptions['onContextOverflow'];
145
147
  /** Conversation history */
146
148
  history?: Array<{
147
149
  role: string;
@@ -196,4 +198,4 @@ declare function renderPrompt(options: RenderPromptOptions & {
196
198
  warnings?: PromptOpsKitConfig['warnings'];
197
199
  }): Promise<RenderResult>;
198
200
 
199
- export { type OverrideOptions, type ParseResult, PromptAsset, PromptOpsKit, type PromptOpsKitConfig, type PromptValidationResult, ProviderAdapter, ProviderRequest, type RenderOptions, type RenderPromptOptions, type RenderResult, type RenderedSections, ResolvedPromptAsset, type ValidationError, applyOverrides, createPromptOpsKit, extractSections, extractVariables, getAdapter, interpolate, loadPromptFile, parsePrompt, renderPrompt, resolveIncludes, validateAsset, validateAssetWithIncludes };
201
+ export { type OverrideOptions, type ParseResult, PromptAsset, PromptOpsKit, type PromptOpsKitConfig, type PromptValidationResult, ProviderAdapter, ProviderRequest, type RenderOptions, type RenderPromptOptions, type RenderResult, type RenderedSections, ResolvedPromptAsset, RuntimeRenderOptions, type ValidationError, applyOverrides, createPromptOpsKit, extractSections, extractVariables, getAdapter, interpolate, loadPromptFile, parsePrompt, renderPrompt, resolveIncludes, validateAsset, validateAssetWithIncludes };
package/dist/index.js CHANGED
@@ -15,35 +15,40 @@ import {
15
15
  } from "./chunk-HWEVRBKZ.js";
16
16
  import {
17
17
  anthropicAdapter
18
- } from "./chunk-4QW4BSGE.js";
18
+ } from "./chunk-KFSP5KN4.js";
19
19
  import {
20
20
  geminiAdapter
21
- } from "./chunk-7RWTFGMS.js";
21
+ } from "./chunk-5TLHYSP7.js";
22
22
  import {
23
23
  openrouterAdapter
24
- } from "./chunk-ROBYCHAW.js";
24
+ } from "./chunk-DGLLQ3FR.js";
25
25
  import {
26
26
  openaiAdapter
27
- } from "./chunk-2X5HFPSD.js";
27
+ } from "./chunk-QPOHKVY5.js";
28
28
  import {
29
29
  DEFAULT_PROMPTS_DIR,
30
30
  PromptCache,
31
31
  applyOverrides,
32
+ collectContextSizeWarnings,
33
+ compileContextRegex,
32
34
  extractVariables,
35
+ getContextInputNames,
36
+ getContextInputs,
33
37
  interpolate,
34
38
  loadPromptAsset,
35
39
  resolveIncludes,
36
40
  resolveInlinePromptSource,
37
41
  resolvePromptAsset,
42
+ sanitizeContextVariables,
38
43
  withPromptResolutionDefaults
39
- } from "./chunk-M5VKRDIY.js";
44
+ } from "./chunk-6XKV4YVK.js";
40
45
  import {
41
46
  PromptAssetOverridesSchema,
42
47
  PromptAssetSchema,
43
48
  extractSections,
44
49
  loadPromptFile,
45
50
  parsePrompt
46
- } from "./chunk-2LK6IILW.js";
51
+ } from "./chunk-IXPIBZXT.js";
47
52
 
48
53
  // src/index.ts
49
54
  import { resolve } from "path";
@@ -66,48 +71,6 @@ function getAdapter(provider) {
66
71
  return adapter;
67
72
  }
68
73
 
69
- // src/context.ts
70
- var textEncoder = new TextEncoder();
71
- function getContextInputs(asset) {
72
- return (asset.context?.inputs ?? []).map(normalizeContextInput);
73
- }
74
- function getContextInputNames(asset) {
75
- return getContextInputs(asset).map((input) => input.name);
76
- }
77
- function normalizeContextInput(input) {
78
- if (typeof input === "string") {
79
- return { name: input };
80
- }
81
- return {
82
- name: input.name,
83
- max_size: input.max_size
84
- };
85
- }
86
- function measureContextValueSize(value) {
87
- return textEncoder.encode(value).length;
88
- }
89
- function collectContextSizeWarnings(asset, variables = {}) {
90
- const warnings = [];
91
- for (const input of getContextInputs(asset)) {
92
- if (input.max_size === void 0) {
93
- continue;
94
- }
95
- const value = variables[input.name];
96
- if (value === void 0) {
97
- continue;
98
- }
99
- const actualSize = measureContextValueSize(value);
100
- if (actualSize > input.max_size) {
101
- warnings.push({
102
- variable: input.name,
103
- maxSize: input.max_size,
104
- actualSize
105
- });
106
- }
107
- }
108
- return warnings;
109
- }
110
-
111
74
  // src/validation/levenshtein.ts
112
75
  function levenshtein(a, b) {
113
76
  const m = a.length;
@@ -219,6 +182,34 @@ function validateAsset(asset, frontMatterKeys, filePath) {
219
182
  });
220
183
  }
221
184
  }
185
+ for (const input of getContextInputs(asset)) {
186
+ if (input.trim !== void 0 && input.trim !== false && input.max_size === void 0) {
187
+ warnings.push({
188
+ code: "POK014",
189
+ message: `Context input "${input.name}" sets trim but has no max_size; trim-to-budget will be skipped.`,
190
+ filePath
191
+ });
192
+ }
193
+ const checks = [];
194
+ if (input.allow_regex) checks.push({ regex: input.allow_regex, kind: "allow_regex" });
195
+ if (input.deny_regex) checks.push({ regex: input.deny_regex, kind: "deny_regex" });
196
+ for (const check of checks) {
197
+ try {
198
+ compileContextRegex(check.regex, {
199
+ promptId: asset.id,
200
+ variable: input.name,
201
+ field: check.kind
202
+ });
203
+ } catch (error) {
204
+ const reason = error instanceof Error ? error.message.replace(/^POK013:\s*/, "") : String(error);
205
+ errors.push({
206
+ code: "POK013",
207
+ message: reason,
208
+ filePath
209
+ });
210
+ }
211
+ }
212
+ }
222
213
  return {
223
214
  valid: errors.length === 0,
224
215
  errors,
@@ -329,7 +320,10 @@ var PromptOpsKit = class {
329
320
  ` + validation.errors.map((e) => ` - ${e}`).join("\n")
330
321
  );
331
322
  }
332
- const contextSizeWarnings = collectContextSizeWarnings(resolved, options.variables).map(
323
+ const sanitizedVariables = sanitizeContextVariables(resolved, options.variables, {
324
+ onContextOverflow: options.onContextOverflow
325
+ });
326
+ const contextSizeWarnings = collectContextSizeWarnings(resolved, sanitizedVariables).map(
333
327
  (warning) => formatContextSizeWarning(resolved, warning)
334
328
  );
335
329
  const contextWarningPolicy = this.config.warnings?.contextSize;
@@ -339,7 +333,7 @@ var PromptOpsKit = class {
339
333
  }
340
334
  }
341
335
  const request = adapter.render(resolved, {
342
- variables: options.variables,
336
+ variables: sanitizedVariables,
343
337
  history: options.history,
344
338
  toolRegistry: options.toolRegistry,
345
339
  strict: options.strict
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/providers/index.ts","../src/context.ts","../src/validation/levenshtein.ts","../src/validation/validate.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { resolve, join } from 'node:path';\n\nimport { parsePrompt, loadPromptFile } from './parser/index.js';\nimport { resolveIncludes } from './composition/index.js';\nimport { applyOverrides } from './overrides/index.js';\nimport { renderSections } from './renderer/index.js';\nimport { getAdapter } from './providers/index.js';\nimport { validateAsset, validateAssetWithIncludes } from './validation/index.js';\nimport { PromptCache } from './cache.js';\nimport { collectContextSizeWarnings } from './context.js';\nimport {\n DEFAULT_PROMPTS_DIR,\n loadPromptAsset,\n resolveInlinePromptSource,\n resolvePromptAsset,\n withPromptResolutionDefaults,\n} from './prompt-resolution.js';\nimport type { PromptAsset, PromptAssetOverrides, ResolvedPromptAsset } from './schema/index.js';\nimport type { ProviderRequest, RuntimeRenderOptions } from './providers/types.js';\nimport type { PromptValidationResult } from './validation/index.js';\n\n// --- Re-exports ---\nexport type { PromptAsset, ResolvedPromptAsset } from './schema/index.js';\nexport type {\n ProviderRequest,\n RuntimeRenderOptions,\n ProviderAdapter,\n ProviderInlinePromptSource,\n ProviderPromptInput,\n ProviderPromptLookup,\n ValidationResult,\n} from './providers/types.js';\nexport type { PromptValidationResult, ValidationError } from './validation/index.js';\nexport type { RenderedSections, RenderOptions } from './renderer/index.js';\nexport type { ParseResult } from './parser/index.js';\nexport type { OverrideOptions } from './overrides/index.js';\nexport type {\n UsageTapAllowed,\n UsageTapAllowedCapability,\n UsageTapBeginRequest,\n UsageTapBeginResponse,\n UsageTapCallOptions,\n UsageTapCallResult,\n UsageTapClient,\n UsageTapClientConfig,\n UsageTapEndRequest,\n UsageTapEndResponse,\n UsageTapEndUsage,\n UsageTapEntitlementMode,\n UsageTapEntitlementOptions,\n UsageTapErrorPayload,\n UsageTapInvokeContext,\n UsageTapInvokeResult,\n UsageTapProviderRunOptions,\n UsageTapProviderRunResult,\n UsageTapReasoningLevel,\n} from './usagetap/index.js';\n\nexport { parsePrompt, loadPromptFile, extractSections } from './parser/index.js';\nexport { interpolate, extractVariables } from './renderer/index.js';\nexport { resolveIncludes } from './composition/index.js';\nexport { applyOverrides } from './overrides/index.js';\nexport { validateAsset, validateAssetWithIncludes } from './validation/index.js';\nexport { getAdapter, openaiAdapter } from './providers/index.js';\nexport { anthropicAdapter } from './providers/anthropic.js';\nexport { geminiAdapter } from './providers/gemini.js';\nexport { openrouterAdapter } from './providers/openrouter.js';\nexport { PromptAssetSchema, PromptAssetOverridesSchema } from './schema/index.js';\nexport {\n applyUsageTapEntitlements,\n beginUsageTapCall,\n createUsageTapClient,\n defaultUsageTapErrorMapper,\n endUsageTapCall,\n extractAnthropicUsage,\n extractGeminiUsage,\n extractOpenAIUsage,\n runAnthropicWithUsageTap,\n runGeminiWithUsageTap,\n runOpenAIWithUsageTap,\n runOpenRouterWithUsageTap,\n withUsageTapCall,\n} from './usagetap/index.js';\n\n// --- Config ---\n\nexport interface PromptOpsKitConfig {\n sourceDir?: string;\n compiledDir?: string;\n mode?: 'auto' | 'compiled-only' | 'source-only';\n cache?: boolean;\n warnings?: {\n contextSize?: 'auto' | 'off' | 'result-only' | 'console' | 'console-and-result';\n };\n}\n\n// --- Render options ---\n\nexport interface RenderPromptOptions {\n /** Prompt path (no extension), e.g. 'support/reply' */\n path?: string;\n /** Inline prompt source string (alternative to path) */\n source?: string;\n /** Provider name */\n provider: string;\n /** Environment override */\n environment?: string;\n /** Tier override */\n tier?: string;\n /** Runtime overrides applied after environment and tier */\n runtime?: Partial<PromptAssetOverrides>;\n /** Variables for interpolation */\n variables?: Record<string, string>;\n /** Conversation history */\n history?: Array<{ role: string; content: string }>;\n /** Tool registry for resolving tool references */\n toolRegistry?: Record<string, unknown>;\n /** Strict mode — fail on missing variables */\n strict?: boolean;\n}\n\n// --- Result ---\n\nexport interface RenderResult {\n resolved: ResolvedPromptAsset;\n request: ProviderRequest;\n warnings: string[];\n}\n\nfunction shouldIncludeContextWarningsInResult(\n policy: NonNullable<PromptOpsKitConfig['warnings']>['contextSize'] | undefined,\n): boolean {\n return policy === undefined\n || policy === 'auto'\n || policy === 'result-only'\n || policy === 'console-and-result';\n}\n\nfunction shouldLogContextWarnings(\n policy: NonNullable<PromptOpsKitConfig['warnings']>['contextSize'] | undefined,\n options: Pick<RenderPromptOptions, 'source'>,\n mode: PromptOpsKitConfig['mode'],\n): boolean {\n if (policy === 'off' || policy === 'result-only') {\n return false;\n }\n\n if (policy === 'console' || policy === 'console-and-result') {\n return true;\n }\n\n return Boolean(options.source || mode !== 'compiled-only');\n}\n\nfunction formatContextSizeWarning(\n asset: ResolvedPromptAsset,\n warning: { variable: string; maxSize: number; actualSize: number },\n): string {\n return [\n 'POK030:',\n `Context variable \"${warning.variable}\" exceeded max_size`,\n `for prompt \"${asset.id}\"`,\n `(${warning.actualSize} bytes > ${warning.maxSize} bytes).`,\n ].join(' ');\n}\n\n// --- Main class ---\n\nexport class PromptOpsKit {\n private config: Required<Pick<PromptOpsKitConfig, 'sourceDir' | 'mode'>> & PromptOpsKitConfig;\n private promptCache: PromptCache<PromptAsset>;\n\n constructor(config: PromptOpsKitConfig) {\n const resolvedConfig = withPromptResolutionDefaults(config);\n this.config = {\n ...resolvedConfig,\n mode: resolvedConfig.mode ?? 'auto',\n cache: resolvedConfig.cache ?? true,\n };\n this.promptCache = new PromptCache();\n }\n\n /**\n * Load a prompt asset from compiled or source, based on mode.\n */\n async loadPrompt(promptPath: string): Promise<PromptAsset> {\n return loadPromptAsset(promptPath, this.config, this.promptCache);\n }\n\n /**\n * Resolve a prompt: load, resolve includes, apply overrides.\n */\n async resolvePrompt(\n promptPath: string,\n options: { environment?: string; tier?: string; runtime?: Partial<PromptAssetOverrides> } = {},\n ): Promise<ResolvedPromptAsset> {\n return resolvePromptAsset(promptPath, this.config, options, this.promptCache);\n }\n\n /**\n * Render a prompt for a specific provider.\n */\n async renderPrompt(options: RenderPromptOptions): Promise<RenderResult> {\n let resolved: ResolvedPromptAsset;\n\n if (options.source) {\n resolved = resolveInlinePromptSource(options.source, {\n environment: options.environment,\n tier: options.tier,\n runtime: options.runtime,\n });\n } else if (options.path) {\n resolved = await this.resolvePrompt(options.path, {\n environment: options.environment,\n tier: options.tier,\n runtime: options.runtime,\n });\n } else {\n throw new Error('Either \"path\" or \"source\" must be provided to renderPrompt()');\n }\n\n const adapter = getAdapter(options.provider);\n const validation = adapter.validate(resolved);\n\n if (!validation.valid) {\n throw new Error(\n `Provider validation failed for \"${options.provider}\":\\n` +\n validation.errors.map((e) => ` - ${e}`).join('\\n'),\n );\n }\n\n const contextSizeWarnings = collectContextSizeWarnings(resolved, options.variables).map((warning) =>\n formatContextSizeWarning(resolved, warning),\n );\n\n const contextWarningPolicy = this.config.warnings?.contextSize;\n\n if (contextSizeWarnings.length > 0 && shouldLogContextWarnings(contextWarningPolicy, options, this.config.mode)) {\n for (const warning of contextSizeWarnings) {\n console.warn(`[promptopskit] Warning: ${warning}`);\n }\n }\n\n const request = adapter.render(resolved, {\n variables: options.variables,\n history: options.history,\n toolRegistry: options.toolRegistry,\n strict: options.strict,\n });\n\n return {\n resolved,\n request,\n warnings: shouldIncludeContextWarningsInResult(contextWarningPolicy)\n ? [...validation.warnings, ...contextSizeWarnings]\n : validation.warnings,\n };\n }\n\n /**\n * Validate a prompt file.\n */\n async validatePrompt(promptPath: string): Promise<PromptValidationResult> {\n const asset = await this.loadPrompt(promptPath);\n\n const sourceFile = resolve(this.config.sourceDir, promptPath + '.md');\n return validateAssetWithIncludes(asset, sourceFile);\n }\n\n /**\n * Clear the internal cache.\n */\n clearCache(): void {\n this.promptCache.clear();\n }\n}\n\n// --- Factory ---\n\nexport function createPromptOpsKit(config: PromptOpsKitConfig = {}): PromptOpsKit {\n return new PromptOpsKit(config);\n}\n\n// --- Standalone convenience ---\n\n/**\n * Standalone renderPrompt for quick usage without creating a PromptOpsKit instance.\n * Requires either `source` (inline) or `path` + implicit sourceDir of ./prompts.\n */\nexport async function renderPrompt(\n options: RenderPromptOptions & {\n sourceDir?: string;\n warnings?: PromptOpsKitConfig['warnings'];\n },\n): Promise<RenderResult> {\n const kit = createPromptOpsKit({\n sourceDir: options.sourceDir ?? DEFAULT_PROMPTS_DIR,\n cache: false,\n warnings: options.warnings,\n });\n return kit.renderPrompt(options);\n}\n","export type {\n ProviderAdapter,\n ProviderInlinePromptSource,\n ProviderPromptInput,\n ProviderPromptLookup,\n ProviderRequest,\n ValidationResult,\n RuntimeRenderOptions,\n} from './types.js';\nexport { openaiAdapter } from './openai.js';\nexport { anthropicAdapter } from './anthropic.js';\nexport { geminiAdapter } from './gemini.js';\nexport { openrouterAdapter } from './openrouter.js';\n\nimport type { ProviderAdapter } from './types.js';\nimport { openaiAdapter } from './openai.js';\nimport { anthropicAdapter } from './anthropic.js';\nimport { geminiAdapter } from './gemini.js';\nimport { openrouterAdapter } from './openrouter.js';\n\nconst adapters: Record<string, ProviderAdapter> = {\n openai: openaiAdapter,\n anthropic: anthropicAdapter,\n google: geminiAdapter,\n gemini: geminiAdapter,\n openrouter: openrouterAdapter,\n};\n\n/**\n * Get a provider adapter by name.\n */\nexport function getAdapter(provider: string): ProviderAdapter {\n const adapter = adapters[provider];\n if (!adapter) {\n throw new Error(\n `Unknown provider: \"${provider}\". Supported: ${Object.keys(adapters).join(', ')}`,\n );\n }\n return adapter;\n}\n","import type { PromptAsset, ResolvedPromptAsset, ContextInputDefinition } from './schema/index.js';\n\nexport interface NormalizedContextInput {\n name: string;\n max_size?: number;\n}\n\nexport interface ContextSizeWarning {\n variable: string;\n maxSize: number;\n actualSize: number;\n}\n\nconst textEncoder = new TextEncoder();\n\nexport function getContextInputs(\n asset: Pick<PromptAsset | ResolvedPromptAsset, 'context'>,\n): NormalizedContextInput[] {\n return (asset.context?.inputs ?? []).map(normalizeContextInput);\n}\n\nexport function getContextInputNames(\n asset: Pick<PromptAsset | ResolvedPromptAsset, 'context'>,\n): string[] {\n return getContextInputs(asset).map((input) => input.name);\n}\n\nexport function normalizeContextInput(input: ContextInputDefinition): NormalizedContextInput {\n if (typeof input === 'string') {\n return { name: input };\n }\n\n return {\n name: input.name,\n max_size: input.max_size,\n };\n}\n\nexport function measureContextValueSize(value: string): number {\n return textEncoder.encode(value).length;\n}\n\nexport function collectContextSizeWarnings(\n asset: Pick<PromptAsset | ResolvedPromptAsset, 'context'>,\n variables: Record<string, string> = {},\n): ContextSizeWarning[] {\n const warnings: ContextSizeWarning[] = [];\n\n for (const input of getContextInputs(asset)) {\n if (input.max_size === undefined) {\n continue;\n }\n\n const value = variables[input.name];\n if (value === undefined) {\n continue;\n }\n\n const actualSize = measureContextValueSize(value);\n if (actualSize > input.max_size) {\n warnings.push({\n variable: input.name,\n maxSize: input.max_size,\n actualSize,\n });\n }\n }\n\n return warnings;\n}","/**\n * Compute the Levenshtein distance between two strings.\n * Used for \"did you mean?\" suggestions on unknown fields.\n */\nexport function levenshtein(a: string, b: string): number {\n const m = a.length;\n const n = b.length;\n\n if (m === 0) return n;\n if (n === 0) return m;\n\n const dp: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0) as number[]);\n\n for (let i = 0; i <= m; i++) dp[i][0] = i;\n for (let j = 0; j <= n; j++) dp[0][j] = j;\n\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n dp[i][j] = Math.min(\n dp[i - 1][j] + 1,\n dp[i][j - 1] + 1,\n dp[i - 1][j - 1] + cost,\n );\n }\n }\n\n return dp[m][n];\n}\n","import { PromptAssetSchema } from '../schema/index.js';\nimport type { PromptAsset } from '../schema/index.js';\nimport { extractVariables } from '../renderer/index.js';\nimport { resolveIncludes } from '../composition/index.js';\nimport { getContextInputNames } from '../context.js';\nimport { levenshtein } from './levenshtein.js';\n\nexport interface ValidationError {\n code: string;\n message: string;\n filePath?: string;\n suggestion?: string;\n}\n\nexport interface PromptValidationResult {\n valid: boolean;\n errors: ValidationError[];\n warnings: ValidationError[];\n}\n\nconst KNOWN_FRONT_MATTER_KEYS = new Set([\n 'id', 'schema_version', 'description', 'provider', 'model', 'fallback_models',\n 'reasoning', 'sampling', 'response', 'tools', 'mcp', 'context', 'includes',\n 'environments', 'tiers', 'metadata',\n]);\n\n/**\n * Validate a parsed prompt asset, returning all errors and warnings.\n */\nexport function validateAsset(\n asset: PromptAsset,\n frontMatterKeys?: string[],\n filePath?: string,\n): PromptValidationResult {\n const errors: ValidationError[] = [];\n const warnings: ValidationError[] = [];\n\n // Schema validation\n const result = PromptAssetSchema.safeParse(asset);\n if (!result.success) {\n for (const issue of result.error.issues) {\n errors.push({\n code: 'POK001',\n message: `Schema error at ${issue.path.join('.')}: ${issue.message}`,\n filePath,\n });\n }\n }\n\n // Missing id\n if (!asset.id) {\n errors.push({\n code: 'POK002',\n message: 'Missing required field: \"id\"',\n filePath,\n });\n }\n\n // Missing body sections\n if (!asset.sections?.system_instructions && !asset.sections?.prompt_template) {\n errors.push({\n code: 'POK003',\n message: 'Prompt must have at least one body section (System instructions or Prompt template)',\n filePath,\n });\n }\n\n // Unknown front matter keys with \"did you mean?\"\n if (frontMatterKeys) {\n for (const key of frontMatterKeys) {\n if (!KNOWN_FRONT_MATTER_KEYS.has(key)) {\n const suggestion = findClosestMatch(key, KNOWN_FRONT_MATTER_KEYS);\n warnings.push({\n code: 'POK010',\n message: `Unknown front matter field: \"${key}\"`,\n filePath,\n suggestion: suggestion ? `Did you mean \"${suggestion}\"?` : undefined,\n });\n }\n }\n }\n\n // Variable validation: used but not declared\n const declaredInputs = new Set(getContextInputNames(asset));\n const usedVars = new Set<string>();\n\n if (asset.sections?.system_instructions) {\n for (const v of extractVariables(asset.sections.system_instructions)) {\n usedVars.add(v);\n }\n }\n if (asset.sections?.prompt_template) {\n for (const v of extractVariables(asset.sections.prompt_template)) {\n usedVars.add(v);\n }\n }\n\n for (const v of usedVars) {\n if (!declaredInputs.has(v)) {\n warnings.push({\n code: 'POK011',\n message: `Variable \"{{ ${v} }}\" is used but not declared in context.inputs`,\n filePath,\n });\n }\n }\n\n // Declared but unused\n for (const v of declaredInputs) {\n if (!usedVars.has(v)) {\n warnings.push({\n code: 'POK012',\n message: `Variable \"${v}\" is declared in context.inputs but never used`,\n filePath,\n });\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\n/**\n * Validate a prompt asset including its include graph.\n * Catches missing include files, circular includes, and parse errors in included files.\n */\nexport async function validateAssetWithIncludes(\n asset: PromptAsset,\n filePath: string,\n frontMatterKeys?: string[],\n): Promise<PromptValidationResult> {\n // Run standard validation first\n const result = validateAsset(asset, frontMatterKeys, filePath);\n\n // Validate includes\n if (asset.includes && asset.includes.length > 0) {\n try {\n await resolveIncludes(asset, filePath);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const isCircular = message.includes('Circular include');\n result.errors.push({\n code: isCircular ? 'POK021' : 'POK020',\n message: isCircular\n ? `Circular include detected: ${message}`\n : `Include resolution failed: ${message}`,\n filePath,\n });\n result.valid = false;\n }\n }\n\n return result;\n}\n\nfunction findClosestMatch(input: string, candidates: Set<string>): string | undefined {\n let best: string | undefined;\n let bestDist = Infinity;\n\n for (const candidate of candidates) {\n const dist = levenshtein(input.toLowerCase(), candidate.toLowerCase());\n if (dist < bestDist && dist <= 3) {\n bestDist = dist;\n best = candidate;\n }\n }\n\n return best;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/providers/index.ts","../src/validation/levenshtein.ts","../src/validation/validate.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { resolve, join } from 'node:path';\n\nimport { parsePrompt, loadPromptFile } from './parser/index.js';\nimport { resolveIncludes } from './composition/index.js';\nimport { applyOverrides } from './overrides/index.js';\nimport { renderSections } from './renderer/index.js';\nimport { getAdapter } from './providers/index.js';\nimport { validateAsset, validateAssetWithIncludes } from './validation/index.js';\nimport { PromptCache } from './cache.js';\nimport { collectContextSizeWarnings, sanitizeContextVariables } from './context.js';\nimport {\n DEFAULT_PROMPTS_DIR,\n loadPromptAsset,\n resolveInlinePromptSource,\n resolvePromptAsset,\n withPromptResolutionDefaults,\n} from './prompt-resolution.js';\nimport type { PromptAsset, PromptAssetOverrides, ResolvedPromptAsset } from './schema/index.js';\nimport type { ProviderRequest, RuntimeRenderOptions } from './providers/types.js';\nimport type { PromptValidationResult } from './validation/index.js';\n\n// --- Re-exports ---\nexport type { PromptAsset, ResolvedPromptAsset } from './schema/index.js';\nexport type {\n ProviderRequest,\n RuntimeRenderOptions,\n ProviderAdapter,\n ProviderInlinePromptSource,\n ProviderPromptInput,\n ProviderPromptLookup,\n ValidationResult,\n} from './providers/types.js';\nexport type { PromptValidationResult, ValidationError } from './validation/index.js';\nexport type { RenderedSections, RenderOptions } from './renderer/index.js';\nexport type { ParseResult } from './parser/index.js';\nexport type { OverrideOptions } from './overrides/index.js';\nexport type {\n UsageTapAllowed,\n UsageTapAllowedCapability,\n UsageTapBeginRequest,\n UsageTapBeginResponse,\n UsageTapCallOptions,\n UsageTapCallResult,\n UsageTapClient,\n UsageTapClientConfig,\n UsageTapEndRequest,\n UsageTapEndResponse,\n UsageTapEndUsage,\n UsageTapEntitlementMode,\n UsageTapEntitlementOptions,\n UsageTapErrorPayload,\n UsageTapInvokeContext,\n UsageTapInvokeResult,\n UsageTapProviderRunOptions,\n UsageTapProviderRunResult,\n UsageTapReasoningLevel,\n} from './usagetap/index.js';\n\nexport { parsePrompt, loadPromptFile, extractSections } from './parser/index.js';\nexport { interpolate, extractVariables } from './renderer/index.js';\nexport { resolveIncludes } from './composition/index.js';\nexport { applyOverrides } from './overrides/index.js';\nexport { validateAsset, validateAssetWithIncludes } from './validation/index.js';\nexport { getAdapter, openaiAdapter } from './providers/index.js';\nexport { anthropicAdapter } from './providers/anthropic.js';\nexport { geminiAdapter } from './providers/gemini.js';\nexport { openrouterAdapter } from './providers/openrouter.js';\nexport { PromptAssetSchema, PromptAssetOverridesSchema } from './schema/index.js';\nexport {\n applyUsageTapEntitlements,\n beginUsageTapCall,\n createUsageTapClient,\n defaultUsageTapErrorMapper,\n endUsageTapCall,\n extractAnthropicUsage,\n extractGeminiUsage,\n extractOpenAIUsage,\n runAnthropicWithUsageTap,\n runGeminiWithUsageTap,\n runOpenAIWithUsageTap,\n runOpenRouterWithUsageTap,\n withUsageTapCall,\n} from './usagetap/index.js';\n\n// --- Config ---\n\nexport interface PromptOpsKitConfig {\n sourceDir?: string;\n compiledDir?: string;\n mode?: 'auto' | 'compiled-only' | 'source-only';\n cache?: boolean;\n warnings?: {\n contextSize?: 'auto' | 'off' | 'result-only' | 'console' | 'console-and-result';\n };\n}\n\n// --- Render options ---\n\nexport interface RenderPromptOptions {\n /** Prompt path (no extension), e.g. 'support/reply' */\n path?: string;\n /** Inline prompt source string (alternative to path) */\n source?: string;\n /** Provider name */\n provider: string;\n /** Environment override */\n environment?: string;\n /** Tier override */\n tier?: string;\n /** Runtime overrides applied after environment and tier */\n runtime?: Partial<PromptAssetOverrides>;\n /** Variables for interpolation */\n variables?: Record<string, string>;\n /** Optional callback to transform oversized context values before warnings/rendering */\n onContextOverflow?: RuntimeRenderOptions['onContextOverflow'];\n /** Conversation history */\n history?: Array<{ role: string; content: string }>;\n /** Tool registry for resolving tool references */\n toolRegistry?: Record<string, unknown>;\n /** Strict mode — fail on missing variables */\n strict?: boolean;\n}\n\n// --- Result ---\n\nexport interface RenderResult {\n resolved: ResolvedPromptAsset;\n request: ProviderRequest;\n warnings: string[];\n}\n\nfunction shouldIncludeContextWarningsInResult(\n policy: NonNullable<PromptOpsKitConfig['warnings']>['contextSize'] | undefined,\n): boolean {\n return policy === undefined\n || policy === 'auto'\n || policy === 'result-only'\n || policy === 'console-and-result';\n}\n\nfunction shouldLogContextWarnings(\n policy: NonNullable<PromptOpsKitConfig['warnings']>['contextSize'] | undefined,\n options: Pick<RenderPromptOptions, 'source'>,\n mode: PromptOpsKitConfig['mode'],\n): boolean {\n if (policy === 'off' || policy === 'result-only') {\n return false;\n }\n\n if (policy === 'console' || policy === 'console-and-result') {\n return true;\n }\n\n return Boolean(options.source || mode !== 'compiled-only');\n}\n\nfunction formatContextSizeWarning(\n asset: ResolvedPromptAsset,\n warning: { variable: string; maxSize: number; actualSize: number },\n): string {\n return [\n 'POK030:',\n `Context variable \"${warning.variable}\" exceeded max_size`,\n `for prompt \"${asset.id}\"`,\n `(${warning.actualSize} bytes > ${warning.maxSize} bytes).`,\n ].join(' ');\n}\n\n// --- Main class ---\n\nexport class PromptOpsKit {\n private config: Required<Pick<PromptOpsKitConfig, 'sourceDir' | 'mode'>> & PromptOpsKitConfig;\n private promptCache: PromptCache<PromptAsset>;\n\n constructor(config: PromptOpsKitConfig) {\n const resolvedConfig = withPromptResolutionDefaults(config);\n this.config = {\n ...resolvedConfig,\n mode: resolvedConfig.mode ?? 'auto',\n cache: resolvedConfig.cache ?? true,\n };\n this.promptCache = new PromptCache();\n }\n\n /**\n * Load a prompt asset from compiled or source, based on mode.\n */\n async loadPrompt(promptPath: string): Promise<PromptAsset> {\n return loadPromptAsset(promptPath, this.config, this.promptCache);\n }\n\n /**\n * Resolve a prompt: load, resolve includes, apply overrides.\n */\n async resolvePrompt(\n promptPath: string,\n options: { environment?: string; tier?: string; runtime?: Partial<PromptAssetOverrides> } = {},\n ): Promise<ResolvedPromptAsset> {\n return resolvePromptAsset(promptPath, this.config, options, this.promptCache);\n }\n\n /**\n * Render a prompt for a specific provider.\n */\n async renderPrompt(options: RenderPromptOptions): Promise<RenderResult> {\n let resolved: ResolvedPromptAsset;\n\n if (options.source) {\n resolved = resolveInlinePromptSource(options.source, {\n environment: options.environment,\n tier: options.tier,\n runtime: options.runtime,\n });\n } else if (options.path) {\n resolved = await this.resolvePrompt(options.path, {\n environment: options.environment,\n tier: options.tier,\n runtime: options.runtime,\n });\n } else {\n throw new Error('Either \"path\" or \"source\" must be provided to renderPrompt()');\n }\n\n const adapter = getAdapter(options.provider);\n const validation = adapter.validate(resolved);\n\n if (!validation.valid) {\n throw new Error(\n `Provider validation failed for \"${options.provider}\":\\n` +\n validation.errors.map((e) => ` - ${e}`).join('\\n'),\n );\n }\n\n const sanitizedVariables = sanitizeContextVariables(resolved, options.variables, {\n onContextOverflow: options.onContextOverflow,\n });\n\n const contextSizeWarnings = collectContextSizeWarnings(resolved, sanitizedVariables).map((warning) =>\n formatContextSizeWarning(resolved, warning),\n );\n\n const contextWarningPolicy = this.config.warnings?.contextSize;\n\n if (contextSizeWarnings.length > 0 && shouldLogContextWarnings(contextWarningPolicy, options, this.config.mode)) {\n for (const warning of contextSizeWarnings) {\n console.warn(`[promptopskit] Warning: ${warning}`);\n }\n }\n\n const request = adapter.render(resolved, {\n variables: sanitizedVariables,\n history: options.history,\n toolRegistry: options.toolRegistry,\n strict: options.strict,\n });\n\n return {\n resolved,\n request,\n warnings: shouldIncludeContextWarningsInResult(contextWarningPolicy)\n ? [...validation.warnings, ...contextSizeWarnings]\n : validation.warnings,\n };\n }\n\n /**\n * Validate a prompt file.\n */\n async validatePrompt(promptPath: string): Promise<PromptValidationResult> {\n const asset = await this.loadPrompt(promptPath);\n\n const sourceFile = resolve(this.config.sourceDir, promptPath + '.md');\n return validateAssetWithIncludes(asset, sourceFile);\n }\n\n /**\n * Clear the internal cache.\n */\n clearCache(): void {\n this.promptCache.clear();\n }\n}\n\n// --- Factory ---\n\nexport function createPromptOpsKit(config: PromptOpsKitConfig = {}): PromptOpsKit {\n return new PromptOpsKit(config);\n}\n\n// --- Standalone convenience ---\n\n/**\n * Standalone renderPrompt for quick usage without creating a PromptOpsKit instance.\n * Requires either `source` (inline) or `path` + implicit sourceDir of ./prompts.\n */\nexport async function renderPrompt(\n options: RenderPromptOptions & {\n sourceDir?: string;\n warnings?: PromptOpsKitConfig['warnings'];\n },\n): Promise<RenderResult> {\n const kit = createPromptOpsKit({\n sourceDir: options.sourceDir ?? DEFAULT_PROMPTS_DIR,\n cache: false,\n warnings: options.warnings,\n });\n return kit.renderPrompt(options);\n}\n","export type {\n ProviderAdapter,\n ProviderInlinePromptSource,\n ProviderPromptInput,\n ProviderPromptLookup,\n ProviderRequest,\n ValidationResult,\n RuntimeRenderOptions,\n} from './types.js';\nexport { openaiAdapter } from './openai.js';\nexport { anthropicAdapter } from './anthropic.js';\nexport { geminiAdapter } from './gemini.js';\nexport { openrouterAdapter } from './openrouter.js';\n\nimport type { ProviderAdapter } from './types.js';\nimport { openaiAdapter } from './openai.js';\nimport { anthropicAdapter } from './anthropic.js';\nimport { geminiAdapter } from './gemini.js';\nimport { openrouterAdapter } from './openrouter.js';\n\nconst adapters: Record<string, ProviderAdapter> = {\n openai: openaiAdapter,\n anthropic: anthropicAdapter,\n google: geminiAdapter,\n gemini: geminiAdapter,\n openrouter: openrouterAdapter,\n};\n\n/**\n * Get a provider adapter by name.\n */\nexport function getAdapter(provider: string): ProviderAdapter {\n const adapter = adapters[provider];\n if (!adapter) {\n throw new Error(\n `Unknown provider: \"${provider}\". Supported: ${Object.keys(adapters).join(', ')}`,\n );\n }\n return adapter;\n}\n","/**\n * Compute the Levenshtein distance between two strings.\n * Used for \"did you mean?\" suggestions on unknown fields.\n */\nexport function levenshtein(a: string, b: string): number {\n const m = a.length;\n const n = b.length;\n\n if (m === 0) return n;\n if (n === 0) return m;\n\n const dp: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0) as number[]);\n\n for (let i = 0; i <= m; i++) dp[i][0] = i;\n for (let j = 0; j <= n; j++) dp[0][j] = j;\n\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n dp[i][j] = Math.min(\n dp[i - 1][j] + 1,\n dp[i][j - 1] + 1,\n dp[i - 1][j - 1] + cost,\n );\n }\n }\n\n return dp[m][n];\n}\n","import { PromptAssetSchema } from '../schema/index.js';\nimport type { PromptAsset } from '../schema/index.js';\nimport { extractVariables } from '../renderer/index.js';\nimport { resolveIncludes } from '../composition/index.js';\nimport {\n compileContextRegex,\n formatInvalidContextRegexMessage,\n getContextInputs,\n getContextInputNames,\n} from '../context.js';\nimport { levenshtein } from './levenshtein.js';\n\nexport interface ValidationError {\n code: string;\n message: string;\n filePath?: string;\n suggestion?: string;\n}\n\nexport interface PromptValidationResult {\n valid: boolean;\n errors: ValidationError[];\n warnings: ValidationError[];\n}\n\nconst KNOWN_FRONT_MATTER_KEYS = new Set([\n 'id', 'schema_version', 'description', 'provider', 'model', 'fallback_models',\n 'reasoning', 'sampling', 'response', 'tools', 'mcp', 'context', 'includes',\n 'environments', 'tiers', 'metadata',\n]);\n\n/**\n * Validate a parsed prompt asset, returning all errors and warnings.\n */\nexport function validateAsset(\n asset: PromptAsset,\n frontMatterKeys?: string[],\n filePath?: string,\n): PromptValidationResult {\n const errors: ValidationError[] = [];\n const warnings: ValidationError[] = [];\n\n // Schema validation\n const result = PromptAssetSchema.safeParse(asset);\n if (!result.success) {\n for (const issue of result.error.issues) {\n errors.push({\n code: 'POK001',\n message: `Schema error at ${issue.path.join('.')}: ${issue.message}`,\n filePath,\n });\n }\n }\n\n // Missing id\n if (!asset.id) {\n errors.push({\n code: 'POK002',\n message: 'Missing required field: \"id\"',\n filePath,\n });\n }\n\n // Missing body sections\n if (!asset.sections?.system_instructions && !asset.sections?.prompt_template) {\n errors.push({\n code: 'POK003',\n message: 'Prompt must have at least one body section (System instructions or Prompt template)',\n filePath,\n });\n }\n\n // Unknown front matter keys with \"did you mean?\"\n if (frontMatterKeys) {\n for (const key of frontMatterKeys) {\n if (!KNOWN_FRONT_MATTER_KEYS.has(key)) {\n const suggestion = findClosestMatch(key, KNOWN_FRONT_MATTER_KEYS);\n warnings.push({\n code: 'POK010',\n message: `Unknown front matter field: \"${key}\"`,\n filePath,\n suggestion: suggestion ? `Did you mean \"${suggestion}\"?` : undefined,\n });\n }\n }\n }\n\n // Variable validation: used but not declared\n const declaredInputs = new Set(getContextInputNames(asset));\n const usedVars = new Set<string>();\n\n if (asset.sections?.system_instructions) {\n for (const v of extractVariables(asset.sections.system_instructions)) {\n usedVars.add(v);\n }\n }\n if (asset.sections?.prompt_template) {\n for (const v of extractVariables(asset.sections.prompt_template)) {\n usedVars.add(v);\n }\n }\n\n for (const v of usedVars) {\n if (!declaredInputs.has(v)) {\n warnings.push({\n code: 'POK011',\n message: `Variable \"{{ ${v} }}\" is used but not declared in context.inputs`,\n filePath,\n });\n }\n }\n\n // Declared but unused\n for (const v of declaredInputs) {\n if (!usedVars.has(v)) {\n warnings.push({\n code: 'POK012',\n message: `Variable \"${v}\" is declared in context.inputs but never used`,\n filePath,\n });\n }\n }\n\n // Context regex definitions compile successfully\n for (const input of getContextInputs(asset)) {\n if (input.trim !== undefined && input.trim !== false && input.max_size === undefined) {\n warnings.push({\n code: 'POK014',\n message: `Context input \"${input.name}\" sets trim but has no max_size; trim-to-budget will be skipped.`,\n filePath,\n });\n }\n\n const checks: Array<{\n regex: NonNullable<typeof input.allow_regex>;\n kind: 'allow_regex' | 'deny_regex';\n }> = [];\n\n if (input.allow_regex) checks.push({ regex: input.allow_regex, kind: 'allow_regex' });\n if (input.deny_regex) checks.push({ regex: input.deny_regex, kind: 'deny_regex' });\n\n for (const check of checks) {\n try {\n compileContextRegex(check.regex, {\n promptId: asset.id,\n variable: input.name,\n field: check.kind,\n });\n } catch (error) {\n const reason = error instanceof Error ? error.message.replace(/^POK013:\\s*/, '') : String(error);\n errors.push({\n code: 'POK013',\n message: reason,\n filePath,\n });\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\n/**\n * Validate a prompt asset including its include graph.\n * Catches missing include files, circular includes, and parse errors in included files.\n */\nexport async function validateAssetWithIncludes(\n asset: PromptAsset,\n filePath: string,\n frontMatterKeys?: string[],\n): Promise<PromptValidationResult> {\n // Run standard validation first\n const result = validateAsset(asset, frontMatterKeys, filePath);\n\n // Validate includes\n if (asset.includes && asset.includes.length > 0) {\n try {\n await resolveIncludes(asset, filePath);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n const isCircular = message.includes('Circular include');\n result.errors.push({\n code: isCircular ? 'POK021' : 'POK020',\n message: isCircular\n ? `Circular include detected: ${message}`\n : `Include resolution failed: ${message}`,\n filePath,\n });\n result.valid = false;\n }\n }\n\n return result;\n}\n\nfunction findClosestMatch(input: string, candidates: Set<string>): string | undefined {\n let best: string | undefined;\n let bestDist = Infinity;\n\n for (const candidate of candidates) {\n const dist = levenshtein(input.toLowerCase(), candidate.toLowerCase());\n if (dist < bestDist && dist <= 3) {\n bestDist = dist;\n best = candidate;\n }\n }\n\n return best;\n}\n"],"mappings":"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","names":[]}
@@ -210,9 +210,21 @@ var ResponseSchema = import_zod.z.object({
210
210
  var HistorySchema = import_zod.z.object({
211
211
  max_items: import_zod.z.number().int().positive().optional()
212
212
  });
213
+ var ContextRegexSchema = import_zod.z.union([
214
+ import_zod.z.string(),
215
+ import_zod.z.object({
216
+ pattern: import_zod.z.string(),
217
+ flags: import_zod.z.string().optional()
218
+ })
219
+ ]);
213
220
  var ContextInputDefinitionObjectSchema = import_zod.z.object({
214
221
  name: import_zod.z.string(),
215
- max_size: import_zod.z.number().int().positive().optional()
222
+ max_size: import_zod.z.number().int().positive().optional(),
223
+ trim: import_zod.z.union([import_zod.z.boolean(), import_zod.z.enum(["start", "end", "both"])]).optional(),
224
+ allow_regex: ContextRegexSchema.optional(),
225
+ deny_regex: ContextRegexSchema.optional(),
226
+ non_empty: import_zod.z.boolean().optional(),
227
+ reject_secrets: import_zod.z.boolean().optional()
216
228
  });
217
229
  var ContextInputDefinitionSchema = import_zod.z.union([
218
230
  import_zod.z.string(),
@@ -555,6 +567,224 @@ function resolveInlinePromptSource(source, options = {}) {
555
567
  });
556
568
  }
557
569
 
570
+ // src/context.ts
571
+ var textEncoder = new TextEncoder();
572
+ var REJECT_SECRETS_PATTERN = "(secret|api[_-]?key|password)";
573
+ var REJECT_SECRETS_FLAGS = "i";
574
+ function getContextInputs(asset) {
575
+ return (asset.context?.inputs ?? []).map(normalizeContextInput);
576
+ }
577
+ function normalizeContextInput(input) {
578
+ if (typeof input === "string") {
579
+ return { name: input };
580
+ }
581
+ return {
582
+ name: input.name,
583
+ max_size: input.max_size,
584
+ trim: input.trim,
585
+ allow_regex: normalizeContextRegex(input.allow_regex),
586
+ deny_regex: normalizeContextRegex(input.deny_regex),
587
+ non_empty: input.non_empty,
588
+ reject_secrets: input.reject_secrets
589
+ };
590
+ }
591
+ function normalizeContextRegex(value) {
592
+ if (value === void 0) {
593
+ return void 0;
594
+ }
595
+ if (typeof value === "string") {
596
+ const literal = parseRegexLiteral(value);
597
+ if (value.startsWith("/") && !literal) {
598
+ return {
599
+ pattern: value,
600
+ flags: "",
601
+ raw: value,
602
+ invalidLiteral: true
603
+ };
604
+ }
605
+ return {
606
+ pattern: literal?.pattern ?? value,
607
+ flags: literal?.flags ?? "",
608
+ raw: value
609
+ };
610
+ }
611
+ return {
612
+ pattern: value.pattern,
613
+ flags: value.flags ?? "",
614
+ raw: JSON.stringify(value)
615
+ };
616
+ }
617
+ function parseRegexLiteral(value) {
618
+ if (!value.startsWith("/")) {
619
+ return void 0;
620
+ }
621
+ for (let index = value.length - 1; index > 0; index -= 1) {
622
+ if (value[index] !== "/") {
623
+ continue;
624
+ }
625
+ let backslashCount = 0;
626
+ for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
627
+ backslashCount += 1;
628
+ }
629
+ if (backslashCount % 2 === 1) {
630
+ continue;
631
+ }
632
+ return {
633
+ pattern: value.slice(1, index),
634
+ flags: value.slice(index + 1)
635
+ };
636
+ }
637
+ return void 0;
638
+ }
639
+ function formatInvalidContextRegexMessage(details) {
640
+ return [
641
+ `Invalid context regex for prompt "${details.promptId}"`,
642
+ `variable "${details.variable}"`,
643
+ `field "${details.field}"`,
644
+ `value ${JSON.stringify(details.raw)}: ${details.reason}`
645
+ ].join(", ");
646
+ }
647
+ function compileContextRegex(regex, details) {
648
+ if (regex.invalidLiteral) {
649
+ throw new Error(
650
+ `POK013: ${formatInvalidContextRegexMessage({
651
+ ...details,
652
+ raw: regex.raw,
653
+ reason: "Malformed regex literal. Use /pattern/flags or { pattern, flags }."
654
+ })}`
655
+ );
656
+ }
657
+ try {
658
+ return new RegExp(regex.pattern, regex.flags);
659
+ } catch (error) {
660
+ const reason = error instanceof Error ? error.message : String(error);
661
+ throw new Error(`POK013: ${formatInvalidContextRegexMessage({ ...details, raw: regex.raw, reason })}`);
662
+ }
663
+ }
664
+ function getRejectSecretsRegex() {
665
+ return {
666
+ pattern: REJECT_SECRETS_PATTERN,
667
+ flags: REJECT_SECRETS_FLAGS,
668
+ raw: JSON.stringify({ pattern: REJECT_SECRETS_PATTERN, flags: REJECT_SECRETS_FLAGS })
669
+ };
670
+ }
671
+ function isTrimEnabled(mode) {
672
+ return mode === true || mode === "start" || mode === "end" || mode === "both";
673
+ }
674
+ function normalizeTrimMode(mode) {
675
+ if (mode === "start") {
676
+ return "start";
677
+ }
678
+ return "end";
679
+ }
680
+ function trimToMaxSize(value, maxSize, mode) {
681
+ const measured = measureContextValueSize(value);
682
+ if (measured <= maxSize) {
683
+ return value;
684
+ }
685
+ const characters = Array.from(value);
686
+ const normalizedMode = normalizeTrimMode(mode);
687
+ if (normalizedMode === "start") {
688
+ let collected2 = "";
689
+ let size2 = 0;
690
+ for (let i = characters.length - 1; i >= 0; i -= 1) {
691
+ const next = characters[i];
692
+ const charSize = measureContextValueSize(next);
693
+ if (size2 + charSize > maxSize) {
694
+ break;
695
+ }
696
+ collected2 = next + collected2;
697
+ size2 += charSize;
698
+ }
699
+ return collected2;
700
+ }
701
+ let collected = "";
702
+ let size = 0;
703
+ for (const char of characters) {
704
+ const charSize = measureContextValueSize(char);
705
+ if (size + charSize > maxSize) {
706
+ break;
707
+ }
708
+ collected += char;
709
+ size += charSize;
710
+ }
711
+ return collected;
712
+ }
713
+ function sanitizeContextVariables(asset, variables = {}, options = {}) {
714
+ const { onContextOverflow } = options;
715
+ const sanitized = { ...variables };
716
+ for (const input of getContextInputs(asset)) {
717
+ const value = sanitized[input.name];
718
+ if (value === void 0) {
719
+ continue;
720
+ }
721
+ let candidate = value;
722
+ if (input.max_size !== void 0) {
723
+ const actualSize = measureContextValueSize(candidate);
724
+ if (actualSize > input.max_size && onContextOverflow) {
725
+ candidate = onContextOverflow({
726
+ promptId: asset.id,
727
+ variable: input.name,
728
+ value: candidate,
729
+ maxSize: input.max_size,
730
+ actualSize
731
+ });
732
+ }
733
+ }
734
+ if (isTrimEnabled(input.trim) && input.max_size !== void 0) {
735
+ candidate = trimToMaxSize(candidate, input.max_size, input.trim);
736
+ }
737
+ sanitized[input.name] = candidate;
738
+ if (input.allow_regex) {
739
+ const candidate2 = sanitized[input.name];
740
+ const matcher = compileContextRegex(input.allow_regex, {
741
+ promptId: asset.id,
742
+ variable: input.name,
743
+ field: "allow_regex"
744
+ });
745
+ if (!matcher.test(candidate2)) {
746
+ throw new Error(
747
+ `POK031: Context variable "${input.name}" failed allow_regex validation for prompt "${asset.id}".`
748
+ );
749
+ }
750
+ }
751
+ if (input.deny_regex) {
752
+ const candidate2 = sanitized[input.name];
753
+ const matcher = compileContextRegex(input.deny_regex, {
754
+ promptId: asset.id,
755
+ variable: input.name,
756
+ field: "deny_regex"
757
+ });
758
+ if (matcher.test(candidate2)) {
759
+ throw new Error(
760
+ `POK032: Context variable "${input.name}" matched deny_regex for prompt "${asset.id}".`
761
+ );
762
+ }
763
+ }
764
+ if (input.non_empty && candidate.trim().length === 0) {
765
+ throw new Error(
766
+ `POK033: Context variable "${input.name}" failed non_empty validation for prompt "${asset.id}".`
767
+ );
768
+ }
769
+ if (input.reject_secrets) {
770
+ const matcher = compileContextRegex(getRejectSecretsRegex(), {
771
+ promptId: asset.id,
772
+ variable: input.name,
773
+ field: "reject_secrets"
774
+ });
775
+ if (matcher.test(candidate)) {
776
+ throw new Error(
777
+ `POK034: Context variable "${input.name}" matched reject_secrets validation for prompt "${asset.id}".`
778
+ );
779
+ }
780
+ }
781
+ }
782
+ return sanitized;
783
+ }
784
+ function measureContextValueSize(value) {
785
+ return textEncoder.encode(value).length;
786
+ }
787
+
558
788
  // src/providers/prompt-input.ts
559
789
  function isPromptLookup(input) {
560
790
  return "path" in input && typeof input.path === "string";
@@ -578,7 +808,13 @@ function withPromptInputSupport(adapter) {
578
808
  };
579
809
  const renderPrompt = async (input, runtime) => {
580
810
  const resolved = await resolveProviderPromptInput(input, runtime);
581
- return adapter.render(resolved, runtime);
811
+ const variables = sanitizeContextVariables(resolved, runtime.variables, {
812
+ onContextOverflow: runtime.onContextOverflow
813
+ });
814
+ return adapter.render(resolved, {
815
+ ...runtime,
816
+ variables
817
+ });
582
818
  };
583
819
  return {
584
820
  ...adapter,