promptopskit 0.5.0 → 0.6.2
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 +9 -7
- package/SKILL.md +16 -10
- package/dist/{chunk-6VLKZCNS.js → chunk-55B7QQBK.js} +2 -2
- package/dist/{chunk-6BOUQVSX.js → chunk-FNCIBZJF.js} +3 -3
- package/dist/{chunk-D75HKF64.js → chunk-GLT3YYWK.js} +2 -2
- package/dist/{chunk-IN4KT5EU.js → chunk-IPFD5Y3O.js} +3 -3
- package/dist/{chunk-KN7H4JRK.js → chunk-JR7252DG.js} +393 -386
- package/dist/chunk-JR7252DG.js.map +1 -0
- package/dist/{chunk-K6ZU3CGV.js → chunk-UY5OKMVP.js} +281 -17
- package/dist/chunk-UY5OKMVP.js.map +1 -0
- package/dist/{chunk-QK3WKE3K.js → chunk-VMLGUI4F.js} +2 -2
- package/dist/{chunk-LNGHGGJN.js → chunk-XEZJZ3IG.js} +2 -2
- package/dist/cli/index.js +410 -103
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +971 -660
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -4
- package/dist/index.d.ts +5 -4
- package/dist/index.js +55 -15
- package/dist/index.js.map +1 -1
- package/dist/providers/anthropic.cjs +675 -407
- package/dist/providers/anthropic.cjs.map +1 -1
- package/dist/providers/anthropic.d.cts +2 -2
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +3 -3
- package/dist/providers/gemini.cjs +675 -407
- package/dist/providers/gemini.cjs.map +1 -1
- package/dist/providers/gemini.d.cts +2 -2
- package/dist/providers/gemini.d.ts +2 -2
- package/dist/providers/gemini.js +3 -3
- package/dist/providers/llmasaservice.cjs +675 -407
- package/dist/providers/llmasaservice.cjs.map +1 -1
- package/dist/providers/llmasaservice.d.cts +2 -2
- package/dist/providers/llmasaservice.d.ts +2 -2
- package/dist/providers/llmasaservice.js +4 -4
- package/dist/providers/openai-responses.cjs +675 -407
- package/dist/providers/openai-responses.cjs.map +1 -1
- package/dist/providers/openai-responses.d.cts +2 -2
- package/dist/providers/openai-responses.d.ts +2 -2
- package/dist/providers/openai-responses.js +3 -3
- package/dist/providers/openai.cjs +675 -407
- package/dist/providers/openai.cjs.map +1 -1
- package/dist/providers/openai.d.cts +2 -2
- package/dist/providers/openai.d.ts +2 -2
- package/dist/providers/openai.js +3 -3
- package/dist/providers/openrouter.cjs +675 -407
- package/dist/providers/openrouter.cjs.map +1 -1
- package/dist/providers/openrouter.d.cts +2 -2
- package/dist/providers/openrouter.d.ts +2 -2
- package/dist/providers/openrouter.js +4 -4
- package/dist/{schema-D-RI4w-k.d.cts → schema-CuYsv8JA.d.cts} +540 -206
- package/dist/{schema-D-RI4w-k.d.ts → schema-CuYsv8JA.d.ts} +540 -206
- package/dist/testing.cjs +43 -5
- 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-B3dxBGu6.d.ts → types-DpK0mTHL.d.ts} +1 -1
- package/dist/{types-DbTAjlTN.d.cts → types-UA_p9uJy.d.cts} +1 -1
- package/dist/usagetap/index.d.cts +2 -2
- package/dist/usagetap/index.d.ts +2 -2
- package/package.json +9 -2
- package/dist/chunk-K6ZU3CGV.js.map +0 -1
- package/dist/chunk-KN7H4JRK.js.map +0 -1
- /package/dist/{chunk-6VLKZCNS.js.map → chunk-55B7QQBK.js.map} +0 -0
- /package/dist/{chunk-6BOUQVSX.js.map → chunk-FNCIBZJF.js.map} +0 -0
- /package/dist/{chunk-D75HKF64.js.map → chunk-GLT3YYWK.js.map} +0 -0
- /package/dist/{chunk-IN4KT5EU.js.map → chunk-IPFD5Y3O.js.map} +0 -0
- /package/dist/{chunk-QK3WKE3K.js.map → chunk-VMLGUI4F.js.map} +0 -0
- /package/dist/{chunk-LNGHGGJN.js.map → chunk-XEZJZ3IG.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadPromptFile,
|
|
3
3
|
parsePrompt
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UY5OKMVP.js";
|
|
5
5
|
|
|
6
6
|
// src/renderer/interpolate.ts
|
|
7
7
|
var VARIABLE_RE = /\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g;
|
|
@@ -9,12 +9,13 @@ var ESCAPED_OPEN = /\\\{\\\{/g;
|
|
|
9
9
|
var ESCAPE_PLACEHOLDER = "\0ESCAPED_OPEN\0";
|
|
10
10
|
function interpolate(template, variables, options = {}) {
|
|
11
11
|
const { strict = false } = options;
|
|
12
|
+
const optionalVariables = new Set(options.optionalVariables ?? []);
|
|
12
13
|
let result = template.replace(ESCAPED_OPEN, ESCAPE_PLACEHOLDER);
|
|
13
14
|
result = result.replace(VARIABLE_RE, (match, name) => {
|
|
14
15
|
if (name in variables) {
|
|
15
16
|
return variables[name];
|
|
16
17
|
}
|
|
17
|
-
if (strict) {
|
|
18
|
+
if (strict && !optionalVariables.has(name)) {
|
|
18
19
|
throw new Error(`Missing required variable: "${name}"`);
|
|
19
20
|
}
|
|
20
21
|
return match;
|
|
@@ -32,22 +33,326 @@ function extractVariables(template) {
|
|
|
32
33
|
return [...vars];
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
// src/context.ts
|
|
37
|
+
var textEncoder = new TextEncoder();
|
|
38
|
+
var REJECT_SECRETS_PATTERN = "(secret|api[_-]?key|password)";
|
|
39
|
+
var REJECT_SECRETS_FLAGS = "i";
|
|
40
|
+
function getContextInputs(asset) {
|
|
41
|
+
return (asset.context?.inputs ?? []).map(normalizeContextInput);
|
|
42
|
+
}
|
|
43
|
+
function normalizeContextInput(input) {
|
|
44
|
+
if (typeof input === "string") {
|
|
45
|
+
return { name: input };
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
name: input.name,
|
|
49
|
+
optional: input.optional,
|
|
50
|
+
warnings: input.warnings,
|
|
51
|
+
max_size: input.max_size,
|
|
52
|
+
trim: input.trim,
|
|
53
|
+
allow_regex: normalizeContextRegex(input.allow_regex),
|
|
54
|
+
deny_regex: normalizeContextRegex(input.deny_regex),
|
|
55
|
+
non_empty: normalizeBuiltInValidator(input.non_empty),
|
|
56
|
+
reject_secrets: normalizeBuiltInValidator(input.reject_secrets)
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function areContextInputWarningsEnabled(input) {
|
|
60
|
+
return input.warnings !== false;
|
|
61
|
+
}
|
|
62
|
+
function normalizeContextRegex(value) {
|
|
63
|
+
if (value === void 0) {
|
|
64
|
+
return void 0;
|
|
65
|
+
}
|
|
66
|
+
if (typeof value === "string") {
|
|
67
|
+
const literal = parseRegexLiteral(value);
|
|
68
|
+
if (value.startsWith("/") && !literal) {
|
|
69
|
+
return {
|
|
70
|
+
pattern: value,
|
|
71
|
+
flags: "",
|
|
72
|
+
raw: value,
|
|
73
|
+
invalidLiteral: true
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
pattern: literal?.pattern ?? value,
|
|
78
|
+
flags: literal?.flags ?? "",
|
|
79
|
+
raw: value
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
pattern: value.pattern,
|
|
84
|
+
flags: value.flags ?? "",
|
|
85
|
+
raw: JSON.stringify(value),
|
|
86
|
+
returnMessage: value.return_message
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function normalizeBuiltInValidator(value) {
|
|
90
|
+
if (value === void 0 || value === false) {
|
|
91
|
+
return void 0;
|
|
92
|
+
}
|
|
93
|
+
if (value === true) {
|
|
94
|
+
return {};
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
returnMessage: value.return_message
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function parseRegexLiteral(value) {
|
|
101
|
+
if (!value.startsWith("/")) {
|
|
102
|
+
return void 0;
|
|
103
|
+
}
|
|
104
|
+
for (let index = value.length - 1; index > 0; index -= 1) {
|
|
105
|
+
if (value[index] !== "/") {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
let backslashCount = 0;
|
|
109
|
+
for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
|
|
110
|
+
backslashCount += 1;
|
|
111
|
+
}
|
|
112
|
+
if (backslashCount % 2 === 1) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
pattern: value.slice(1, index),
|
|
117
|
+
flags: value.slice(index + 1)
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return void 0;
|
|
121
|
+
}
|
|
122
|
+
function formatInvalidContextRegexMessage(details) {
|
|
123
|
+
return [
|
|
124
|
+
`Invalid context regex for prompt "${details.promptId}"`,
|
|
125
|
+
`variable "${details.variable}"`,
|
|
126
|
+
`field "${details.field}"`,
|
|
127
|
+
`value ${JSON.stringify(details.raw)}: ${details.reason}`
|
|
128
|
+
].join(", ");
|
|
129
|
+
}
|
|
130
|
+
function compileContextRegex(regex, details) {
|
|
131
|
+
if (regex.invalidLiteral) {
|
|
132
|
+
throw new Error(
|
|
133
|
+
`POK013: ${formatInvalidContextRegexMessage({
|
|
134
|
+
...details,
|
|
135
|
+
raw: regex.raw,
|
|
136
|
+
reason: "Malformed regex literal. Use /pattern/flags or { pattern, flags }."
|
|
137
|
+
})}`
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
return new RegExp(regex.pattern, regex.flags);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
144
|
+
throw new Error(`POK013: ${formatInvalidContextRegexMessage({ ...details, raw: regex.raw, reason })}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function getRejectSecretsRegex() {
|
|
148
|
+
return {
|
|
149
|
+
pattern: REJECT_SECRETS_PATTERN,
|
|
150
|
+
flags: REJECT_SECRETS_FLAGS,
|
|
151
|
+
raw: JSON.stringify({ pattern: REJECT_SECRETS_PATTERN, flags: REJECT_SECRETS_FLAGS })
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function isTrimEnabled(mode) {
|
|
155
|
+
return mode === true || mode === "start" || mode === "end" || mode === "both";
|
|
156
|
+
}
|
|
157
|
+
function normalizeTrimMode(mode) {
|
|
158
|
+
if (mode === "start") {
|
|
159
|
+
return "start";
|
|
160
|
+
}
|
|
161
|
+
return "end";
|
|
162
|
+
}
|
|
163
|
+
function trimToMaxSize(value, maxSize, mode) {
|
|
164
|
+
const measured = measureContextValueSize(value);
|
|
165
|
+
if (measured <= maxSize) {
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
const characters = Array.from(value);
|
|
169
|
+
const normalizedMode = normalizeTrimMode(mode);
|
|
170
|
+
if (normalizedMode === "start") {
|
|
171
|
+
let collected2 = "";
|
|
172
|
+
let size2 = 0;
|
|
173
|
+
for (let i = characters.length - 1; i >= 0; i -= 1) {
|
|
174
|
+
const next = characters[i];
|
|
175
|
+
const charSize = measureContextValueSize(next);
|
|
176
|
+
if (size2 + charSize > maxSize) {
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
collected2 = next + collected2;
|
|
180
|
+
size2 += charSize;
|
|
181
|
+
}
|
|
182
|
+
return collected2;
|
|
183
|
+
}
|
|
184
|
+
let collected = "";
|
|
185
|
+
let size = 0;
|
|
186
|
+
for (const char of characters) {
|
|
187
|
+
const charSize = measureContextValueSize(char);
|
|
188
|
+
if (size + charSize > maxSize) {
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
collected += char;
|
|
192
|
+
size += charSize;
|
|
193
|
+
}
|
|
194
|
+
return collected;
|
|
195
|
+
}
|
|
196
|
+
function sanitizeContextVariables(asset, variables = {}, options = {}) {
|
|
197
|
+
const { onContextOverflow } = options;
|
|
198
|
+
const sanitized = { ...variables };
|
|
199
|
+
for (const input of getContextInputs(asset)) {
|
|
200
|
+
const value = sanitized[input.name];
|
|
201
|
+
if (value === void 0) {
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
let candidate = value;
|
|
205
|
+
if (input.max_size !== void 0) {
|
|
206
|
+
const actualSize = measureContextValueSize(candidate);
|
|
207
|
+
if (actualSize > input.max_size && onContextOverflow) {
|
|
208
|
+
candidate = onContextOverflow({
|
|
209
|
+
promptId: asset.id,
|
|
210
|
+
variable: input.name,
|
|
211
|
+
value: candidate,
|
|
212
|
+
maxSize: input.max_size,
|
|
213
|
+
actualSize
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (isTrimEnabled(input.trim) && input.max_size !== void 0) {
|
|
218
|
+
candidate = trimToMaxSize(candidate, input.max_size, input.trim);
|
|
219
|
+
}
|
|
220
|
+
sanitized[input.name] = candidate;
|
|
221
|
+
if (input.allow_regex) {
|
|
222
|
+
const candidate2 = sanitized[input.name];
|
|
223
|
+
const matcher = compileContextRegex(input.allow_regex, {
|
|
224
|
+
promptId: asset.id,
|
|
225
|
+
variable: input.name,
|
|
226
|
+
field: "allow_regex"
|
|
227
|
+
});
|
|
228
|
+
if (!matcher.test(candidate2)) {
|
|
229
|
+
if (input.allow_regex.returnMessage) {
|
|
230
|
+
return {
|
|
231
|
+
variables: sanitized,
|
|
232
|
+
shortCircuit: {
|
|
233
|
+
returnMessage: input.allow_regex.returnMessage,
|
|
234
|
+
code: "POK031",
|
|
235
|
+
variable: input.name,
|
|
236
|
+
field: "allow_regex"
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
throw new Error(
|
|
241
|
+
`POK031: Context variable "${input.name}" failed allow_regex validation for prompt "${asset.id}".`
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (input.deny_regex) {
|
|
246
|
+
const candidate2 = sanitized[input.name];
|
|
247
|
+
const matcher = compileContextRegex(input.deny_regex, {
|
|
248
|
+
promptId: asset.id,
|
|
249
|
+
variable: input.name,
|
|
250
|
+
field: "deny_regex"
|
|
251
|
+
});
|
|
252
|
+
if (matcher.test(candidate2)) {
|
|
253
|
+
if (input.deny_regex.returnMessage) {
|
|
254
|
+
return {
|
|
255
|
+
variables: sanitized,
|
|
256
|
+
shortCircuit: {
|
|
257
|
+
returnMessage: input.deny_regex.returnMessage,
|
|
258
|
+
code: "POK032",
|
|
259
|
+
variable: input.name,
|
|
260
|
+
field: "deny_regex"
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
throw new Error(
|
|
265
|
+
`POK032: Context variable "${input.name}" matched deny_regex for prompt "${asset.id}".`
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (input.non_empty && candidate.trim().length === 0) {
|
|
270
|
+
if (input.non_empty.returnMessage) {
|
|
271
|
+
return {
|
|
272
|
+
variables: sanitized,
|
|
273
|
+
shortCircuit: {
|
|
274
|
+
returnMessage: input.non_empty.returnMessage,
|
|
275
|
+
code: "POK033",
|
|
276
|
+
variable: input.name,
|
|
277
|
+
field: "non_empty"
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
throw new Error(
|
|
282
|
+
`POK033: Context variable "${input.name}" failed non_empty validation for prompt "${asset.id}".`
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
if (input.reject_secrets) {
|
|
286
|
+
const matcher = compileContextRegex(getRejectSecretsRegex(), {
|
|
287
|
+
promptId: asset.id,
|
|
288
|
+
variable: input.name,
|
|
289
|
+
field: "reject_secrets"
|
|
290
|
+
});
|
|
291
|
+
if (matcher.test(candidate)) {
|
|
292
|
+
if (input.reject_secrets.returnMessage) {
|
|
293
|
+
return {
|
|
294
|
+
variables: sanitized,
|
|
295
|
+
shortCircuit: {
|
|
296
|
+
returnMessage: input.reject_secrets.returnMessage,
|
|
297
|
+
code: "POK034",
|
|
298
|
+
variable: input.name,
|
|
299
|
+
field: "reject_secrets"
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
throw new Error(
|
|
304
|
+
`POK034: Context variable "${input.name}" matched reject_secrets validation for prompt "${asset.id}".`
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return { variables: sanitized };
|
|
310
|
+
}
|
|
311
|
+
function measureContextValueSize(value) {
|
|
312
|
+
return textEncoder.encode(value).length;
|
|
313
|
+
}
|
|
314
|
+
function collectContextSizeWarnings(asset, variables = {}) {
|
|
315
|
+
const warnings = [];
|
|
316
|
+
for (const input of getContextInputs(asset)) {
|
|
317
|
+
if (!areContextInputWarningsEnabled(input)) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
if (input.max_size === void 0) {
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
const value = variables[input.name];
|
|
324
|
+
if (value === void 0) {
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
const actualSize = measureContextValueSize(value);
|
|
328
|
+
if (actualSize > input.max_size) {
|
|
329
|
+
warnings.push({
|
|
330
|
+
variable: input.name,
|
|
331
|
+
maxSize: input.max_size,
|
|
332
|
+
actualSize
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return warnings;
|
|
337
|
+
}
|
|
338
|
+
|
|
35
339
|
// src/renderer/renderer.ts
|
|
36
340
|
function renderSections(asset, options = {}) {
|
|
37
341
|
const { variables = {}, strict = false } = options;
|
|
342
|
+
const optionalVariables = getContextInputs(asset).filter((input) => input.optional === true).map((input) => input.name);
|
|
38
343
|
const result = {};
|
|
39
344
|
if (asset.sections.system_instructions) {
|
|
40
345
|
result.system_instructions = interpolate(
|
|
41
346
|
asset.sections.system_instructions,
|
|
42
347
|
variables,
|
|
43
|
-
{ strict }
|
|
348
|
+
{ strict, optionalVariables }
|
|
44
349
|
);
|
|
45
350
|
}
|
|
46
351
|
if (asset.sections.prompt_template) {
|
|
47
352
|
result.prompt_template = interpolate(
|
|
48
353
|
asset.sections.prompt_template,
|
|
49
354
|
variables,
|
|
50
|
-
{ strict }
|
|
355
|
+
{ strict, optionalVariables }
|
|
51
356
|
);
|
|
52
357
|
}
|
|
53
358
|
return result;
|
|
@@ -226,400 +531,102 @@ async function resolveIncludes(asset, basePath, visited = /* @__PURE__ */ new Se
|
|
|
226
531
|
...asset.sections,
|
|
227
532
|
system_instructions: combinedSystem
|
|
228
533
|
},
|
|
229
|
-
// Drop includes from the resolved asset — they've been inlined
|
|
230
|
-
includes: void 0
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// src/prompt-resolution.ts
|
|
235
|
-
import { readFile as readFile2 } from "fs/promises";
|
|
236
|
-
import { existsSync, statSync as statSync2 } from "fs";
|
|
237
|
-
import { resolve as resolve2 } from "path";
|
|
238
|
-
var DEFAULT_PROMPTS_DIR = "./prompts";
|
|
239
|
-
var DEFAULT_COMPILED_JSON_DIR = "./.generated-prompts/json";
|
|
240
|
-
function withPromptResolutionDefaults(config) {
|
|
241
|
-
return {
|
|
242
|
-
...config,
|
|
243
|
-
sourceDir: config.sourceDir ?? DEFAULT_PROMPTS_DIR,
|
|
244
|
-
compiledDir: config.compiledDir ?? DEFAULT_COMPILED_JSON_DIR
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
var sharedPromptCache = new PromptCache();
|
|
248
|
-
async function loadPromptAsset(promptPath, config, promptCache = sharedPromptCache) {
|
|
249
|
-
const resolvedConfig = withPromptResolutionDefaults(config);
|
|
250
|
-
const mode = resolvedConfig.mode ?? "auto";
|
|
251
|
-
if (mode !== "source-only" && resolvedConfig.compiledDir) {
|
|
252
|
-
const compiledFile = resolve2(resolvedConfig.compiledDir, promptPath + ".json");
|
|
253
|
-
if (existsSync(compiledFile)) {
|
|
254
|
-
if (mode === "auto") {
|
|
255
|
-
const sourceFile = resolve2(resolvedConfig.sourceDir, promptPath + ".md");
|
|
256
|
-
if (existsSync(sourceFile)) {
|
|
257
|
-
const compiledMtime = statSync2(compiledFile).mtimeMs;
|
|
258
|
-
const sourceMtime = statSync2(sourceFile).mtimeMs;
|
|
259
|
-
if (sourceMtime > compiledMtime) {
|
|
260
|
-
console.warn(
|
|
261
|
-
`[promptopskit] Warning: compiled artifact for "${promptPath}" is older than source .md file.
|
|
262
|
-
Run "promptopskit compile" or switch to source-only mode.`
|
|
263
|
-
);
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
const content = await readFile2(compiledFile, "utf-8");
|
|
268
|
-
return JSON.parse(content);
|
|
269
|
-
}
|
|
270
|
-
if (mode === "compiled-only") {
|
|
271
|
-
throw new Error(
|
|
272
|
-
`Compiled artifact not found: ${compiledFile}
|
|
273
|
-
Run "promptopskit compile" to generate it.`
|
|
274
|
-
);
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
if (mode !== "compiled-only") {
|
|
278
|
-
const sourceFile = resolve2(resolvedConfig.sourceDir, promptPath + ".md");
|
|
279
|
-
if (resolvedConfig.cache !== false) {
|
|
280
|
-
const cached = promptCache.get(sourceFile);
|
|
281
|
-
if (cached) {
|
|
282
|
-
return cached;
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
if (!existsSync(sourceFile)) {
|
|
286
|
-
const paths = [sourceFile];
|
|
287
|
-
if (resolvedConfig.compiledDir) {
|
|
288
|
-
paths.unshift(resolve2(resolvedConfig.compiledDir, promptPath + ".json"));
|
|
289
|
-
}
|
|
290
|
-
throw new Error(
|
|
291
|
-
`Prompt not found: "${promptPath}"
|
|
292
|
-
Searched:
|
|
293
|
-
${paths.map((candidate) => ` - ${candidate}`).join("\n")}`
|
|
294
|
-
);
|
|
295
|
-
}
|
|
296
|
-
const { asset } = await loadPromptFile(sourceFile, { defaultsRoot: resolvedConfig.sourceDir });
|
|
297
|
-
if (resolvedConfig.cache !== false) {
|
|
298
|
-
promptCache.set(sourceFile, asset);
|
|
299
|
-
}
|
|
300
|
-
return asset;
|
|
301
|
-
}
|
|
302
|
-
throw new Error(`Prompt not found: "${promptPath}"`);
|
|
303
|
-
}
|
|
304
|
-
async function resolvePromptAsset(promptPath, config, options = {}, promptCache = sharedPromptCache) {
|
|
305
|
-
const resolvedConfig = withPromptResolutionDefaults(config);
|
|
306
|
-
let asset = await loadPromptAsset(promptPath, resolvedConfig, promptCache);
|
|
307
|
-
const sourceFile = resolve2(resolvedConfig.sourceDir, promptPath + ".md");
|
|
308
|
-
if (asset.includes && asset.includes.length > 0 && existsSync(sourceFile)) {
|
|
309
|
-
asset = await resolveIncludes(asset, sourceFile);
|
|
310
|
-
}
|
|
311
|
-
asset = applyOverrides(asset, {
|
|
312
|
-
environment: options.environment,
|
|
313
|
-
tier: options.tier,
|
|
314
|
-
runtime: options.runtime
|
|
315
|
-
});
|
|
316
|
-
return asset;
|
|
317
|
-
}
|
|
318
|
-
function resolveInlinePromptSource(source, options = {}) {
|
|
319
|
-
const { asset } = parsePrompt(source);
|
|
320
|
-
return applyOverrides(asset, {
|
|
321
|
-
environment: options.environment,
|
|
322
|
-
tier: options.tier,
|
|
323
|
-
runtime: options.runtime
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// src/context.ts
|
|
328
|
-
var textEncoder = new TextEncoder();
|
|
329
|
-
var REJECT_SECRETS_PATTERN = "(secret|api[_-]?key|password)";
|
|
330
|
-
var REJECT_SECRETS_FLAGS = "i";
|
|
331
|
-
function getContextInputs(asset) {
|
|
332
|
-
return (asset.context?.inputs ?? []).map(normalizeContextInput);
|
|
333
|
-
}
|
|
334
|
-
function getContextInputNames(asset) {
|
|
335
|
-
return getContextInputs(asset).map((input) => input.name);
|
|
336
|
-
}
|
|
337
|
-
function normalizeContextInput(input) {
|
|
338
|
-
if (typeof input === "string") {
|
|
339
|
-
return { name: input };
|
|
340
|
-
}
|
|
341
|
-
return {
|
|
342
|
-
name: input.name,
|
|
343
|
-
max_size: input.max_size,
|
|
344
|
-
trim: input.trim,
|
|
345
|
-
allow_regex: normalizeContextRegex(input.allow_regex),
|
|
346
|
-
deny_regex: normalizeContextRegex(input.deny_regex),
|
|
347
|
-
non_empty: normalizeBuiltInValidator(input.non_empty),
|
|
348
|
-
reject_secrets: normalizeBuiltInValidator(input.reject_secrets)
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
function normalizeContextRegex(value) {
|
|
352
|
-
if (value === void 0) {
|
|
353
|
-
return void 0;
|
|
354
|
-
}
|
|
355
|
-
if (typeof value === "string") {
|
|
356
|
-
const literal = parseRegexLiteral(value);
|
|
357
|
-
if (value.startsWith("/") && !literal) {
|
|
358
|
-
return {
|
|
359
|
-
pattern: value,
|
|
360
|
-
flags: "",
|
|
361
|
-
raw: value,
|
|
362
|
-
invalidLiteral: true
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
return {
|
|
366
|
-
pattern: literal?.pattern ?? value,
|
|
367
|
-
flags: literal?.flags ?? "",
|
|
368
|
-
raw: value
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
return {
|
|
372
|
-
pattern: value.pattern,
|
|
373
|
-
flags: value.flags ?? "",
|
|
374
|
-
raw: JSON.stringify(value),
|
|
375
|
-
returnMessage: value.return_message
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
function normalizeBuiltInValidator(value) {
|
|
379
|
-
if (value === void 0 || value === false) {
|
|
380
|
-
return void 0;
|
|
381
|
-
}
|
|
382
|
-
if (value === true) {
|
|
383
|
-
return {};
|
|
384
|
-
}
|
|
385
|
-
return {
|
|
386
|
-
returnMessage: value.return_message
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
function parseRegexLiteral(value) {
|
|
390
|
-
if (!value.startsWith("/")) {
|
|
391
|
-
return void 0;
|
|
392
|
-
}
|
|
393
|
-
for (let index = value.length - 1; index > 0; index -= 1) {
|
|
394
|
-
if (value[index] !== "/") {
|
|
395
|
-
continue;
|
|
396
|
-
}
|
|
397
|
-
let backslashCount = 0;
|
|
398
|
-
for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
|
|
399
|
-
backslashCount += 1;
|
|
400
|
-
}
|
|
401
|
-
if (backslashCount % 2 === 1) {
|
|
402
|
-
continue;
|
|
403
|
-
}
|
|
404
|
-
return {
|
|
405
|
-
pattern: value.slice(1, index),
|
|
406
|
-
flags: value.slice(index + 1)
|
|
407
|
-
};
|
|
408
|
-
}
|
|
409
|
-
return void 0;
|
|
410
|
-
}
|
|
411
|
-
function formatInvalidContextRegexMessage(details) {
|
|
412
|
-
return [
|
|
413
|
-
`Invalid context regex for prompt "${details.promptId}"`,
|
|
414
|
-
`variable "${details.variable}"`,
|
|
415
|
-
`field "${details.field}"`,
|
|
416
|
-
`value ${JSON.stringify(details.raw)}: ${details.reason}`
|
|
417
|
-
].join(", ");
|
|
418
|
-
}
|
|
419
|
-
function compileContextRegex(regex, details) {
|
|
420
|
-
if (regex.invalidLiteral) {
|
|
421
|
-
throw new Error(
|
|
422
|
-
`POK013: ${formatInvalidContextRegexMessage({
|
|
423
|
-
...details,
|
|
424
|
-
raw: regex.raw,
|
|
425
|
-
reason: "Malformed regex literal. Use /pattern/flags or { pattern, flags }."
|
|
426
|
-
})}`
|
|
427
|
-
);
|
|
428
|
-
}
|
|
429
|
-
try {
|
|
430
|
-
return new RegExp(regex.pattern, regex.flags);
|
|
431
|
-
} catch (error) {
|
|
432
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
433
|
-
throw new Error(`POK013: ${formatInvalidContextRegexMessage({ ...details, raw: regex.raw, reason })}`);
|
|
434
|
-
}
|
|
534
|
+
// Drop includes from the resolved asset — they've been inlined
|
|
535
|
+
includes: void 0
|
|
536
|
+
};
|
|
435
537
|
}
|
|
436
|
-
|
|
538
|
+
|
|
539
|
+
// src/prompt-resolution.ts
|
|
540
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
541
|
+
import { existsSync, statSync as statSync2 } from "fs";
|
|
542
|
+
import { resolve as resolve2 } from "path";
|
|
543
|
+
var DEFAULT_PROMPTS_DIR = "./prompts";
|
|
544
|
+
var DEFAULT_COMPILED_JSON_DIR = "./.generated-prompts/json";
|
|
545
|
+
function withPromptResolutionDefaults(config) {
|
|
437
546
|
return {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
547
|
+
...config,
|
|
548
|
+
sourceDir: config.sourceDir ?? DEFAULT_PROMPTS_DIR,
|
|
549
|
+
compiledDir: config.compiledDir ?? DEFAULT_COMPILED_JSON_DIR
|
|
441
550
|
};
|
|
442
551
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
if (mode
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
for (let i = characters.length - 1; i >= 0; i -= 1) {
|
|
463
|
-
const next = characters[i];
|
|
464
|
-
const charSize = measureContextValueSize(next);
|
|
465
|
-
if (size2 + charSize > maxSize) {
|
|
466
|
-
break;
|
|
552
|
+
var sharedPromptCache = new PromptCache();
|
|
553
|
+
async function loadPromptAsset(promptPath, config, promptCache = sharedPromptCache) {
|
|
554
|
+
const resolvedConfig = withPromptResolutionDefaults(config);
|
|
555
|
+
const mode = resolvedConfig.mode ?? "auto";
|
|
556
|
+
if (mode !== "source-only" && resolvedConfig.compiledDir) {
|
|
557
|
+
const compiledFile = resolve2(resolvedConfig.compiledDir, promptPath + ".json");
|
|
558
|
+
if (existsSync(compiledFile)) {
|
|
559
|
+
if (mode === "auto") {
|
|
560
|
+
const sourceFile = resolve2(resolvedConfig.sourceDir, promptPath + ".md");
|
|
561
|
+
if (existsSync(sourceFile)) {
|
|
562
|
+
const compiledMtime = statSync2(compiledFile).mtimeMs;
|
|
563
|
+
const sourceMtime = statSync2(sourceFile).mtimeMs;
|
|
564
|
+
if (sourceMtime > compiledMtime) {
|
|
565
|
+
console.warn(
|
|
566
|
+
`[promptopskit] Warning: compiled artifact for "${promptPath}" is older than source .md file.
|
|
567
|
+
Run "promptopskit compile" or switch to source-only mode.`
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
467
571
|
}
|
|
468
|
-
|
|
469
|
-
|
|
572
|
+
const content = await readFile2(compiledFile, "utf-8");
|
|
573
|
+
return JSON.parse(content);
|
|
470
574
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
const charSize = measureContextValueSize(char);
|
|
477
|
-
if (size + charSize > maxSize) {
|
|
478
|
-
break;
|
|
575
|
+
if (mode === "compiled-only") {
|
|
576
|
+
throw new Error(
|
|
577
|
+
`Compiled artifact not found: ${compiledFile}
|
|
578
|
+
Run "promptopskit compile" to generate it.`
|
|
579
|
+
);
|
|
479
580
|
}
|
|
480
|
-
collected += char;
|
|
481
|
-
size += charSize;
|
|
482
581
|
}
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
const value = sanitized[input.name];
|
|
490
|
-
if (value === void 0) {
|
|
491
|
-
continue;
|
|
492
|
-
}
|
|
493
|
-
let candidate = value;
|
|
494
|
-
if (input.max_size !== void 0) {
|
|
495
|
-
const actualSize = measureContextValueSize(candidate);
|
|
496
|
-
if (actualSize > input.max_size && onContextOverflow) {
|
|
497
|
-
candidate = onContextOverflow({
|
|
498
|
-
promptId: asset.id,
|
|
499
|
-
variable: input.name,
|
|
500
|
-
value: candidate,
|
|
501
|
-
maxSize: input.max_size,
|
|
502
|
-
actualSize
|
|
503
|
-
});
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
if (isTrimEnabled(input.trim) && input.max_size !== void 0) {
|
|
507
|
-
candidate = trimToMaxSize(candidate, input.max_size, input.trim);
|
|
508
|
-
}
|
|
509
|
-
sanitized[input.name] = candidate;
|
|
510
|
-
if (input.allow_regex) {
|
|
511
|
-
const candidate2 = sanitized[input.name];
|
|
512
|
-
const matcher = compileContextRegex(input.allow_regex, {
|
|
513
|
-
promptId: asset.id,
|
|
514
|
-
variable: input.name,
|
|
515
|
-
field: "allow_regex"
|
|
516
|
-
});
|
|
517
|
-
if (!matcher.test(candidate2)) {
|
|
518
|
-
if (input.allow_regex.returnMessage) {
|
|
519
|
-
return {
|
|
520
|
-
variables: sanitized,
|
|
521
|
-
shortCircuit: {
|
|
522
|
-
returnMessage: input.allow_regex.returnMessage,
|
|
523
|
-
code: "POK031",
|
|
524
|
-
variable: input.name,
|
|
525
|
-
field: "allow_regex"
|
|
526
|
-
}
|
|
527
|
-
};
|
|
528
|
-
}
|
|
529
|
-
throw new Error(
|
|
530
|
-
`POK031: Context variable "${input.name}" failed allow_regex validation for prompt "${asset.id}".`
|
|
531
|
-
);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
if (input.deny_regex) {
|
|
535
|
-
const candidate2 = sanitized[input.name];
|
|
536
|
-
const matcher = compileContextRegex(input.deny_regex, {
|
|
537
|
-
promptId: asset.id,
|
|
538
|
-
variable: input.name,
|
|
539
|
-
field: "deny_regex"
|
|
540
|
-
});
|
|
541
|
-
if (matcher.test(candidate2)) {
|
|
542
|
-
if (input.deny_regex.returnMessage) {
|
|
543
|
-
return {
|
|
544
|
-
variables: sanitized,
|
|
545
|
-
shortCircuit: {
|
|
546
|
-
returnMessage: input.deny_regex.returnMessage,
|
|
547
|
-
code: "POK032",
|
|
548
|
-
variable: input.name,
|
|
549
|
-
field: "deny_regex"
|
|
550
|
-
}
|
|
551
|
-
};
|
|
552
|
-
}
|
|
553
|
-
throw new Error(
|
|
554
|
-
`POK032: Context variable "${input.name}" matched deny_regex for prompt "${asset.id}".`
|
|
555
|
-
);
|
|
582
|
+
if (mode !== "compiled-only") {
|
|
583
|
+
const sourceFile = resolve2(resolvedConfig.sourceDir, promptPath + ".md");
|
|
584
|
+
if (resolvedConfig.cache !== false) {
|
|
585
|
+
const cached = promptCache.get(sourceFile);
|
|
586
|
+
if (cached) {
|
|
587
|
+
return cached;
|
|
556
588
|
}
|
|
557
589
|
}
|
|
558
|
-
if (
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
shortCircuit: {
|
|
563
|
-
returnMessage: input.non_empty.returnMessage,
|
|
564
|
-
code: "POK033",
|
|
565
|
-
variable: input.name,
|
|
566
|
-
field: "non_empty"
|
|
567
|
-
}
|
|
568
|
-
};
|
|
590
|
+
if (!existsSync(sourceFile)) {
|
|
591
|
+
const paths = [sourceFile];
|
|
592
|
+
if (resolvedConfig.compiledDir) {
|
|
593
|
+
paths.unshift(resolve2(resolvedConfig.compiledDir, promptPath + ".json"));
|
|
569
594
|
}
|
|
570
595
|
throw new Error(
|
|
571
|
-
`
|
|
596
|
+
`Prompt not found: "${promptPath}"
|
|
597
|
+
Searched:
|
|
598
|
+
${paths.map((candidate) => ` - ${candidate}`).join("\n")}`
|
|
572
599
|
);
|
|
573
600
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
variable: input.name,
|
|
578
|
-
field: "reject_secrets"
|
|
579
|
-
});
|
|
580
|
-
if (matcher.test(candidate)) {
|
|
581
|
-
if (input.reject_secrets.returnMessage) {
|
|
582
|
-
return {
|
|
583
|
-
variables: sanitized,
|
|
584
|
-
shortCircuit: {
|
|
585
|
-
returnMessage: input.reject_secrets.returnMessage,
|
|
586
|
-
code: "POK034",
|
|
587
|
-
variable: input.name,
|
|
588
|
-
field: "reject_secrets"
|
|
589
|
-
}
|
|
590
|
-
};
|
|
591
|
-
}
|
|
592
|
-
throw new Error(
|
|
593
|
-
`POK034: Context variable "${input.name}" matched reject_secrets validation for prompt "${asset.id}".`
|
|
594
|
-
);
|
|
595
|
-
}
|
|
601
|
+
const { asset } = await loadPromptFile(sourceFile, { defaultsRoot: resolvedConfig.sourceDir });
|
|
602
|
+
if (resolvedConfig.cache !== false) {
|
|
603
|
+
promptCache.set(sourceFile, asset);
|
|
596
604
|
}
|
|
605
|
+
return asset;
|
|
597
606
|
}
|
|
598
|
-
|
|
599
|
-
}
|
|
600
|
-
function measureContextValueSize(value) {
|
|
601
|
-
return textEncoder.encode(value).length;
|
|
607
|
+
throw new Error(`Prompt not found: "${promptPath}"`);
|
|
602
608
|
}
|
|
603
|
-
function
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
const value = variables[input.name];
|
|
610
|
-
if (value === void 0) {
|
|
611
|
-
continue;
|
|
612
|
-
}
|
|
613
|
-
const actualSize = measureContextValueSize(value);
|
|
614
|
-
if (actualSize > input.max_size) {
|
|
615
|
-
warnings.push({
|
|
616
|
-
variable: input.name,
|
|
617
|
-
maxSize: input.max_size,
|
|
618
|
-
actualSize
|
|
619
|
-
});
|
|
620
|
-
}
|
|
609
|
+
async function resolvePromptAsset(promptPath, config, options = {}, promptCache = sharedPromptCache) {
|
|
610
|
+
const resolvedConfig = withPromptResolutionDefaults(config);
|
|
611
|
+
let asset = await loadPromptAsset(promptPath, resolvedConfig, promptCache);
|
|
612
|
+
const sourceFile = resolve2(resolvedConfig.sourceDir, promptPath + ".md");
|
|
613
|
+
if (asset.includes && asset.includes.length > 0 && existsSync(sourceFile)) {
|
|
614
|
+
asset = await resolveIncludes(asset, sourceFile);
|
|
621
615
|
}
|
|
622
|
-
|
|
616
|
+
asset = applyOverrides(asset, {
|
|
617
|
+
environment: options.environment,
|
|
618
|
+
tier: options.tier,
|
|
619
|
+
runtime: options.runtime
|
|
620
|
+
});
|
|
621
|
+
return asset;
|
|
622
|
+
}
|
|
623
|
+
function resolveInlinePromptSource(source, options = {}) {
|
|
624
|
+
const { asset } = parsePrompt(source);
|
|
625
|
+
return applyOverrides(asset, {
|
|
626
|
+
environment: options.environment,
|
|
627
|
+
tier: options.tier,
|
|
628
|
+
runtime: options.runtime
|
|
629
|
+
});
|
|
623
630
|
}
|
|
624
631
|
|
|
625
632
|
// src/history.ts
|
|
@@ -736,6 +743,11 @@ function getRawProviderBody(asset, provider) {
|
|
|
736
743
|
export {
|
|
737
744
|
interpolate,
|
|
738
745
|
extractVariables,
|
|
746
|
+
getContextInputs,
|
|
747
|
+
areContextInputWarningsEnabled,
|
|
748
|
+
compileContextRegex,
|
|
749
|
+
sanitizeContextVariables,
|
|
750
|
+
collectContextSizeWarnings,
|
|
739
751
|
renderSections,
|
|
740
752
|
applyOverrides,
|
|
741
753
|
resolveAssetForProvider,
|
|
@@ -746,13 +758,8 @@ export {
|
|
|
746
758
|
loadPromptAsset,
|
|
747
759
|
resolvePromptAsset,
|
|
748
760
|
resolveInlinePromptSource,
|
|
749
|
-
getContextInputs,
|
|
750
|
-
getContextInputNames,
|
|
751
|
-
compileContextRegex,
|
|
752
|
-
sanitizeContextVariables,
|
|
753
|
-
collectContextSizeWarnings,
|
|
754
761
|
compactHistoryForPrompt,
|
|
755
762
|
withPromptInputSupport,
|
|
756
763
|
applyRawProviderBody
|
|
757
764
|
};
|
|
758
|
-
//# sourceMappingURL=chunk-
|
|
765
|
+
//# sourceMappingURL=chunk-JR7252DG.js.map
|