prompt-lock 0.2.0

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 (80) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/LICENSE +21 -0
  3. package/README.md +351 -0
  4. package/dist/assertions/builtin.d.ts +5 -0
  5. package/dist/assertions/builtin.d.ts.map +1 -0
  6. package/dist/assertions/builtin.js +172 -0
  7. package/dist/assertions/builtin.js.map +1 -0
  8. package/dist/assertions/custom.d.ts +3 -0
  9. package/dist/assertions/custom.d.ts.map +1 -0
  10. package/dist/assertions/custom.js +26 -0
  11. package/dist/assertions/custom.js.map +1 -0
  12. package/dist/assertions/index.d.ts +3 -0
  13. package/dist/assertions/index.d.ts.map +1 -0
  14. package/dist/assertions/index.js +32 -0
  15. package/dist/assertions/index.js.map +1 -0
  16. package/dist/assertions/json-schema.d.ts +3 -0
  17. package/dist/assertions/json-schema.d.ts.map +1 -0
  18. package/dist/assertions/json-schema.js +35 -0
  19. package/dist/assertions/json-schema.js.map +1 -0
  20. package/dist/cache.d.ts +14 -0
  21. package/dist/cache.d.ts.map +1 -0
  22. package/dist/cache.js +114 -0
  23. package/dist/cache.js.map +1 -0
  24. package/dist/cli.d.ts +3 -0
  25. package/dist/cli.d.ts.map +1 -0
  26. package/dist/cli.js +434 -0
  27. package/dist/cli.js.map +1 -0
  28. package/dist/config-validation.d.ts +6 -0
  29. package/dist/config-validation.d.ts.map +1 -0
  30. package/dist/config-validation.js +133 -0
  31. package/dist/config-validation.js.map +1 -0
  32. package/dist/github.d.ts +11 -0
  33. package/dist/github.d.ts.map +1 -0
  34. package/dist/github.js +138 -0
  35. package/dist/github.js.map +1 -0
  36. package/dist/index.d.ts +40 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +119 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/providers/anthropic.d.ts +3 -0
  41. package/dist/providers/anthropic.d.ts.map +1 -0
  42. package/dist/providers/anthropic.js +46 -0
  43. package/dist/providers/anthropic.js.map +1 -0
  44. package/dist/providers/custom.d.ts +3 -0
  45. package/dist/providers/custom.d.ts.map +1 -0
  46. package/dist/providers/custom.js +178 -0
  47. package/dist/providers/custom.js.map +1 -0
  48. package/dist/providers/index.d.ts +3 -0
  49. package/dist/providers/index.d.ts.map +1 -0
  50. package/dist/providers/index.js +34 -0
  51. package/dist/providers/index.js.map +1 -0
  52. package/dist/providers/openai.d.ts +3 -0
  53. package/dist/providers/openai.d.ts.map +1 -0
  54. package/dist/providers/openai.js +45 -0
  55. package/dist/providers/openai.js.map +1 -0
  56. package/dist/reporter.d.ts +6 -0
  57. package/dist/reporter.d.ts.map +1 -0
  58. package/dist/reporter.js +251 -0
  59. package/dist/reporter.js.map +1 -0
  60. package/dist/retry.d.ts +8 -0
  61. package/dist/retry.d.ts.map +1 -0
  62. package/dist/retry.js +51 -0
  63. package/dist/retry.js.map +1 -0
  64. package/dist/runner.d.ts +16 -0
  65. package/dist/runner.d.ts.map +1 -0
  66. package/dist/runner.js +203 -0
  67. package/dist/runner.js.map +1 -0
  68. package/dist/snapshot.d.ts +7 -0
  69. package/dist/snapshot.d.ts.map +1 -0
  70. package/dist/snapshot.js +146 -0
  71. package/dist/snapshot.js.map +1 -0
  72. package/dist/types.d.ts +138 -0
  73. package/dist/types.d.ts.map +1 -0
  74. package/dist/types.js +4 -0
  75. package/dist/types.js.map +1 -0
  76. package/dist/utils.d.ts +9 -0
  77. package/dist/utils.d.ts.map +1 -0
  78. package/dist/utils.js +83 -0
  79. package/dist/utils.js.map +1 -0
  80. package/package.json +82 -0
@@ -0,0 +1,16 @@
1
+ import { PromptLockConfig, RunResult } from './types';
2
+ import { RetryOptions } from './retry';
3
+ export interface RunOptions {
4
+ dryRun?: boolean;
5
+ verbose?: boolean;
6
+ parallel?: boolean;
7
+ concurrency?: number;
8
+ cache?: boolean;
9
+ cacheDir?: string;
10
+ retry?: Partial<RetryOptions>;
11
+ onResult?: (result: RunResult) => void;
12
+ onProgress?: (id: string, status: string) => void;
13
+ }
14
+ export declare function runPrompt(config: PromptLockConfig, opts?: RunOptions): Promise<RunResult>;
15
+ export declare function runAll(configs: PromptLockConfig[], opts?: RunOptions): Promise<RunResult[]>;
16
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAqC,MAAM,SAAS,CAAC;AAMzF,OAAO,EAAa,YAAY,EAAE,MAAM,SAAS,CAAC;AAElD,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,IAAI,CAAC;IACvC,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACnD;AA8CD,wBAAsB,SAAS,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,SAAS,CAAC,CA4G/F;AAED,wBAAsB,MAAM,CAC1B,OAAO,EAAE,gBAAgB,EAAE,EAC3B,IAAI,CAAC,EAAE,UAAU,GAChB,OAAO,CAAC,SAAS,EAAE,CAAC,CAetB"}
package/dist/runner.js ADDED
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runPrompt = runPrompt;
4
+ exports.runAll = runAll;
5
+ const providers_1 = require("./providers");
6
+ const assertions_1 = require("./assertions");
7
+ const utils_1 = require("./utils");
8
+ const config_validation_1 = require("./config-validation");
9
+ const cache_1 = require("./cache");
10
+ const retry_1 = require("./retry");
11
+ function getCache(opts) {
12
+ if (!opts?.cache)
13
+ return null;
14
+ return new cache_1.OutputCache(opts.cacheDir);
15
+ }
16
+ async function callWithCacheAndRetry(provider, prompt, model, opts, providerOpts) {
17
+ const cache = getCache(opts);
18
+ // Check cache
19
+ if (cache) {
20
+ const cached = await cache.get(prompt, model);
21
+ if (cached !== null) {
22
+ if (opts?.verbose) {
23
+ process.stderr.write(` [cache] HIT for ${model}:${prompt.slice(0, 50)}...\n`);
24
+ }
25
+ return { output: cached, cached: true };
26
+ }
27
+ }
28
+ // Call with retry
29
+ const output = await (0, retry_1.withRetry)(() => provider.call(prompt, providerOpts), opts?.retry, opts?.verbose
30
+ ? (attempt, error, delay) => {
31
+ process.stderr.write(` [retry] attempt ${attempt}: ${error.message} — retrying in ${delay}ms\n`);
32
+ }
33
+ : undefined);
34
+ // Save to cache
35
+ if (cache) {
36
+ await cache.set(prompt, model, output);
37
+ }
38
+ return { output, cached: false };
39
+ }
40
+ async function runPrompt(config, opts) {
41
+ const startTime = Date.now();
42
+ // Validate config before running
43
+ const validation = (0, config_validation_1.validateConfig)(config);
44
+ if (!validation.valid) {
45
+ return {
46
+ id: config.id ?? 'unknown',
47
+ version: config.version,
48
+ provider: providerName(config),
49
+ model: config.model ?? 'unknown',
50
+ prompt: config.prompt ?? '',
51
+ promptHash: '',
52
+ output: '',
53
+ assertions: [{
54
+ type: 'error',
55
+ name: 'config-validation',
56
+ passed: false,
57
+ message: `Invalid config: ${validation.errors.join('; ')}`,
58
+ }],
59
+ passed: false,
60
+ duration: 0,
61
+ timestamp: new Date().toISOString(),
62
+ };
63
+ }
64
+ // Render template with variables
65
+ const renderedPrompt = config.defaultVars
66
+ ? (0, utils_1.renderTemplate)(config.prompt, config.defaultVars)
67
+ : config.prompt;
68
+ if (opts?.dryRun) {
69
+ const output = '[DRY RUN — no LLM call made]';
70
+ const assertionResults = await runAssertionsWithLatency(output, config.assertions, 0);
71
+ return {
72
+ id: config.id,
73
+ version: config.version,
74
+ provider: providerName(config),
75
+ model: config.model,
76
+ prompt: renderedPrompt,
77
+ promptHash: `sha256:${(0, utils_1.hashString)(renderedPrompt)}`,
78
+ output,
79
+ defaultVars: config.defaultVars,
80
+ assertions: assertionResults,
81
+ passed: assertionResults.every(r => r.passed),
82
+ duration: 0,
83
+ timestamp: new Date().toISOString(),
84
+ };
85
+ }
86
+ // Get provider and call LLM (with cache + retry)
87
+ opts?.onProgress?.(config.id, 'calling LLM...');
88
+ const provider = (0, providers_1.getProvider)(config.provider, config.model);
89
+ const callStart = Date.now();
90
+ const { output, cached } = await callWithCacheAndRetry(provider, renderedPrompt, config.model, opts, config.options);
91
+ const callDuration = Date.now() - callStart;
92
+ if (opts?.verbose) {
93
+ const src = cached ? 'cached' : 'live';
94
+ process.stderr.write(` [verbose] ${config.id}: ${src} response in ${callDuration}ms (${output.length} chars)\n`);
95
+ }
96
+ // Run assertions (inject latency for max-latency)
97
+ const assertionResults = await runAssertionsWithLatency(output, config.assertions, callDuration);
98
+ const allPassed = assertionResults.every(r => r.passed);
99
+ const totalDuration = Date.now() - startTime;
100
+ // Dataset runs
101
+ let datasetResults;
102
+ if (config.dataset && config.dataset.length > 0) {
103
+ opts?.onProgress?.(config.id, `running dataset (${config.dataset.length} inputs)...`);
104
+ datasetResults = [];
105
+ for (const vars of config.dataset) {
106
+ const dsPrompt = (0, utils_1.renderTemplate)(config.prompt, vars);
107
+ const dsStart = Date.now();
108
+ const dsResult = await callWithCacheAndRetry(provider, dsPrompt, config.model, opts, config.options);
109
+ const dsDuration = Date.now() - dsStart;
110
+ const dsAssertions = await runAssertionsWithLatency(dsResult.output, config.assertions, dsDuration);
111
+ datasetResults.push({
112
+ vars,
113
+ output: dsResult.output,
114
+ assertions: dsAssertions,
115
+ passed: dsAssertions.every(r => r.passed),
116
+ duration: dsDuration,
117
+ });
118
+ }
119
+ }
120
+ const datasetAllPassed = datasetResults
121
+ ? datasetResults.every(d => d.passed)
122
+ : true;
123
+ return {
124
+ id: config.id,
125
+ version: config.version,
126
+ provider: providerName(config),
127
+ model: config.model,
128
+ prompt: renderedPrompt,
129
+ promptHash: `sha256:${(0, utils_1.hashString)(renderedPrompt)}`,
130
+ output,
131
+ defaultVars: config.defaultVars,
132
+ assertions: assertionResults,
133
+ passed: allPassed && datasetAllPassed,
134
+ duration: totalDuration,
135
+ timestamp: new Date().toISOString(),
136
+ datasetResults,
137
+ };
138
+ }
139
+ async function runAll(configs, opts) {
140
+ const parallel = opts?.parallel ?? configs[0]?.options?.parallel ?? false;
141
+ const concurrency = opts?.concurrency ?? configs[0]?.options?.concurrency ?? 5;
142
+ if (parallel && configs.length > 1) {
143
+ return runParallel(configs, concurrency, opts);
144
+ }
145
+ const results = [];
146
+ for (const config of configs) {
147
+ const result = await runSafe(config, opts);
148
+ results.push(result);
149
+ opts?.onResult?.(result);
150
+ }
151
+ return results;
152
+ }
153
+ async function runParallel(configs, concurrency, opts) {
154
+ const results = new Array(configs.length);
155
+ const queue = [...configs.keys()]; // [0, 1, 2, ...]
156
+ async function worker() {
157
+ while (queue.length > 0) {
158
+ const i = queue.shift();
159
+ results[i] = await runSafe(configs[i], opts);
160
+ opts?.onResult?.(results[i]);
161
+ }
162
+ }
163
+ const workers = Array.from({ length: Math.min(concurrency, configs.length) }, () => worker());
164
+ await Promise.all(workers);
165
+ return results;
166
+ }
167
+ async function runSafe(config, opts) {
168
+ try {
169
+ return await runPrompt(config, opts);
170
+ }
171
+ catch (error) {
172
+ return {
173
+ id: config.id,
174
+ version: config.version,
175
+ provider: providerName(config),
176
+ model: config.model,
177
+ prompt: config.prompt,
178
+ promptHash: `sha256:${(0, utils_1.hashString)(config.prompt)}`,
179
+ output: '',
180
+ assertions: [{
181
+ type: 'error',
182
+ name: 'execution-error',
183
+ passed: false,
184
+ message: `Error running prompt: ${error.message}`,
185
+ }],
186
+ passed: false,
187
+ duration: 0,
188
+ timestamp: new Date().toISOString(),
189
+ };
190
+ }
191
+ }
192
+ async function runAssertionsWithLatency(output, assertions, durationMs) {
193
+ const enriched = assertions.map(a => a.type === 'max-latency'
194
+ ? { ...a, __duration: durationMs }
195
+ : a);
196
+ return (0, assertions_1.runAssertions)(output, enriched);
197
+ }
198
+ function providerName(config) {
199
+ if (typeof config.provider === 'string')
200
+ return config.provider;
201
+ return `custom:${config.provider.url}`;
202
+ }
203
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { SnapshotData, RunResult, DiffResult } from './types';
2
+ export declare function saveSnapshot(result: RunResult, baseDir?: string): Promise<string>;
3
+ export declare function loadSnapshot(id: string, baseDir?: string): Promise<SnapshotData | null>;
4
+ export declare function loadSnapshotHistory(id: string, baseDir?: string): Promise<SnapshotData[]>;
5
+ export declare function listSnapshots(baseDir?: string): Promise<string[]>;
6
+ export declare function diffSnapshots(previous: SnapshotData, currentOutput: string): DiffResult;
7
+ //# sourceMappingURL=snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,UAAU,EAAc,MAAM,SAAS,CAAC;AAS1E,wBAAsB,YAAY,CAChC,MAAM,EAAE,SAAS,EACjB,OAAO,GAAE,MAA6B,GACrC,OAAO,CAAC,MAAM,CAAC,CA0BjB;AAED,wBAAsB,YAAY,CAChC,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,MAA6B,GACrC,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAkB9B;AAED,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,MAA6B,GACrC,OAAO,CAAC,YAAY,EAAE,CAAC,CAkBzB;AAED,wBAAsB,aAAa,CACjC,OAAO,GAAE,MAA6B,GACrC,OAAO,CAAC,MAAM,EAAE,CAAC,CAenB;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,YAAY,EACtB,aAAa,EAAE,MAAM,GACpB,UAAU,CAgBZ"}
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.saveSnapshot = saveSnapshot;
37
+ exports.loadSnapshot = loadSnapshot;
38
+ exports.loadSnapshotHistory = loadSnapshotHistory;
39
+ exports.listSnapshots = listSnapshots;
40
+ exports.diffSnapshots = diffSnapshots;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const diff_1 = require("diff");
44
+ const utils_1 = require("./utils");
45
+ const DEFAULT_SNAPSHOT_DIR = '.promptlock/snapshots';
46
+ function sanitizeId(id) {
47
+ return id.replace(/[^a-zA-Z0-9_\-]/g, '_');
48
+ }
49
+ async function saveSnapshot(result, baseDir = DEFAULT_SNAPSHOT_DIR) {
50
+ const snapshot = {
51
+ id: result.id,
52
+ version: result.version,
53
+ promptHash: result.promptHash,
54
+ capturedAt: result.timestamp,
55
+ model: result.model,
56
+ defaultVars: result.defaultVars,
57
+ output: result.output,
58
+ assertionResults: result.assertions,
59
+ };
60
+ const safeId = sanitizeId(result.id);
61
+ const promptDir = path.join(baseDir, safeId);
62
+ await (0, utils_1.ensureDir)(promptDir);
63
+ // Save timestamped version for history
64
+ const ts = new Date().toISOString().replace(/[:.]/g, '-');
65
+ const historyPath = path.join(promptDir, `${ts}.json`);
66
+ await (0, utils_1.writeJsonFile)(historyPath, snapshot);
67
+ // Also save as "latest.json" for easy access
68
+ const latestPath = path.join(promptDir, 'latest.json');
69
+ await (0, utils_1.writeJsonFile)(latestPath, snapshot);
70
+ return latestPath;
71
+ }
72
+ async function loadSnapshot(id, baseDir = DEFAULT_SNAPSHOT_DIR) {
73
+ const safeId = sanitizeId(id);
74
+ // Try new format: {id}/latest.json
75
+ const latestPath = path.join(baseDir, safeId, 'latest.json');
76
+ try {
77
+ const content = await fs.promises.readFile(latestPath, 'utf-8');
78
+ return JSON.parse(content);
79
+ }
80
+ catch {
81
+ // Fall back to old format: {id}.json
82
+ const legacyPath = path.join(baseDir, `${safeId}.json`);
83
+ try {
84
+ const content = await fs.promises.readFile(legacyPath, 'utf-8');
85
+ return JSON.parse(content);
86
+ }
87
+ catch {
88
+ return null;
89
+ }
90
+ }
91
+ }
92
+ async function loadSnapshotHistory(id, baseDir = DEFAULT_SNAPSHOT_DIR) {
93
+ const safeId = sanitizeId(id);
94
+ const promptDir = path.join(baseDir, safeId);
95
+ try {
96
+ const files = await fs.promises.readdir(promptDir);
97
+ const snapshots = [];
98
+ for (const file of files.filter(f => f.endsWith('.json') && f !== 'latest.json').sort()) {
99
+ try {
100
+ const content = await fs.promises.readFile(path.join(promptDir, file), 'utf-8');
101
+ snapshots.push(JSON.parse(content));
102
+ }
103
+ catch {
104
+ // skip corrupt files
105
+ }
106
+ }
107
+ return snapshots;
108
+ }
109
+ catch {
110
+ return [];
111
+ }
112
+ }
113
+ async function listSnapshots(baseDir = DEFAULT_SNAPSHOT_DIR) {
114
+ try {
115
+ const entries = await fs.promises.readdir(baseDir, { withFileTypes: true });
116
+ const ids = [];
117
+ for (const entry of entries) {
118
+ if (entry.isDirectory()) {
119
+ ids.push(entry.name);
120
+ }
121
+ else if (entry.isFile() && entry.name.endsWith('.json')) {
122
+ ids.push(entry.name.replace('.json', ''));
123
+ }
124
+ }
125
+ return ids;
126
+ }
127
+ catch {
128
+ return [];
129
+ }
130
+ }
131
+ function diffSnapshots(previous, currentOutput) {
132
+ const changes = (0, diff_1.diffLines)(previous.output, currentOutput);
133
+ const diffChanges = changes.map(change => ({
134
+ added: change.added,
135
+ removed: change.removed,
136
+ value: change.value,
137
+ }));
138
+ return {
139
+ id: previous.id,
140
+ previousOutput: previous.output,
141
+ currentOutput,
142
+ changes: diffChanges,
143
+ snapshotTimestamp: previous.capturedAt,
144
+ };
145
+ }
146
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,138 @@
1
+ export type ProviderConfig = 'openai' | 'anthropic' | CustomProviderConfig;
2
+ export interface CustomProviderConfig {
3
+ type: 'custom';
4
+ url: string;
5
+ headers?: Record<string, string>;
6
+ bodyTemplate?: Record<string, unknown>;
7
+ responsePath?: string;
8
+ }
9
+ export interface PromptLockConfig {
10
+ id: string;
11
+ version?: string;
12
+ provider: ProviderConfig;
13
+ model: string;
14
+ prompt: string;
15
+ defaultVars?: Record<string, string>;
16
+ dataset?: Record<string, string>[];
17
+ assertions: AssertionConfig[];
18
+ options?: PromptLockOptions;
19
+ }
20
+ export interface PromptLockOptions {
21
+ temperature?: number;
22
+ maxTokens?: number;
23
+ timeout?: number;
24
+ parallel?: boolean;
25
+ concurrency?: number;
26
+ }
27
+ export type AssertionConfig = {
28
+ type: 'contains';
29
+ value: string;
30
+ } | {
31
+ type: 'not-contains';
32
+ value: string;
33
+ } | {
34
+ type: 'contains-all';
35
+ values: string[];
36
+ } | {
37
+ type: 'starts-with';
38
+ value: string;
39
+ } | {
40
+ type: 'ends-with';
41
+ value: string;
42
+ } | {
43
+ type: 'matches-regex';
44
+ pattern: string;
45
+ } | {
46
+ type: 'max-length';
47
+ chars: number;
48
+ } | {
49
+ type: 'min-length';
50
+ chars: number;
51
+ } | {
52
+ type: 'json-valid';
53
+ } | {
54
+ type: 'json-schema';
55
+ schema: Record<string, unknown>;
56
+ } | {
57
+ type: 'no-hallucination-words';
58
+ words?: string[];
59
+ } | {
60
+ type: 'no-duplicates';
61
+ separator?: string;
62
+ } | {
63
+ type: 'max-latency';
64
+ ms: number;
65
+ } | {
66
+ type: 'custom';
67
+ name: string;
68
+ fn: (output: string) => boolean | Promise<boolean>;
69
+ };
70
+ export interface AssertionResult {
71
+ type: string;
72
+ name: string;
73
+ passed: boolean;
74
+ expected?: string;
75
+ actual?: string;
76
+ message?: string;
77
+ }
78
+ export interface RunResult {
79
+ id: string;
80
+ version?: string;
81
+ provider: string;
82
+ model: string;
83
+ prompt: string;
84
+ promptHash: string;
85
+ output: string;
86
+ defaultVars?: Record<string, string>;
87
+ assertions: AssertionResult[];
88
+ passed: boolean;
89
+ duration: number;
90
+ timestamp: string;
91
+ datasetResults?: DatasetRunResult[];
92
+ }
93
+ export interface DatasetRunResult {
94
+ vars: Record<string, string>;
95
+ output: string;
96
+ assertions: AssertionResult[];
97
+ passed: boolean;
98
+ duration: number;
99
+ }
100
+ export interface SnapshotData {
101
+ id: string;
102
+ version?: string;
103
+ promptHash: string;
104
+ capturedAt: string;
105
+ model: string;
106
+ defaultVars?: Record<string, string>;
107
+ output: string;
108
+ assertionResults: AssertionResult[];
109
+ }
110
+ export interface DiffResult {
111
+ id: string;
112
+ previousOutput: string;
113
+ currentOutput: string;
114
+ changes: DiffChange[];
115
+ snapshotTimestamp: string;
116
+ }
117
+ export interface DiffChange {
118
+ added?: boolean;
119
+ removed?: boolean;
120
+ value: string;
121
+ }
122
+ export interface PromptLockProjectConfig {
123
+ promptsDir: string;
124
+ snapshotDir: string;
125
+ reportDir: string;
126
+ defaultProvider: string;
127
+ defaultModel?: string;
128
+ ci: {
129
+ failOnRegression: boolean;
130
+ reportFormat: ('json' | 'html')[];
131
+ };
132
+ }
133
+ export interface LLMProvider {
134
+ call(prompt: string, options?: PromptLockOptions & {
135
+ model?: string;
136
+ }): Promise<string>;
137
+ }
138
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,cAAc,GACtB,QAAQ,GACR,WAAW,GACX,oBAAoB,CAAC;AAEzB,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAID,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,cAAc,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IACnC,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC7B;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,wBAAwB,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,CAAC;AAEzF,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,eAAe,EAAE,CAAC;CACrC;AAID,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAID,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,EAAE,EAAE;QACF,gBAAgB,EAAE,OAAO,CAAC;QAC1B,YAAY,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;KACnC,CAAC;CACH;AAID,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACzF"}
package/dist/types.js ADDED
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ // ── Provider Config ──────────────────────────────────────────────────────────
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA,gFAAgF"}
@@ -0,0 +1,9 @@
1
+ export declare function renderTemplate(template: string, variables: Record<string, string>): string;
2
+ export declare function hashString(s: string): string;
3
+ export declare function ensureDir(dir: string): Promise<void>;
4
+ export declare function readJsonFile<T>(filePath: string): T | null;
5
+ export declare function writeJsonFile(filePath: string, data: unknown): Promise<void>;
6
+ export declare function spinner(message: string): {
7
+ stop: (finalMessage?: string) => void;
8
+ };
9
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAI1F;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE1D;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAO1D;AAED,wBAAsB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAGlF;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,CAAC,YAAY,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAclF"}
package/dist/utils.js ADDED
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.renderTemplate = renderTemplate;
37
+ exports.hashString = hashString;
38
+ exports.ensureDir = ensureDir;
39
+ exports.readJsonFile = readJsonFile;
40
+ exports.writeJsonFile = writeJsonFile;
41
+ exports.spinner = spinner;
42
+ const crypto = __importStar(require("crypto"));
43
+ const fs = __importStar(require("fs"));
44
+ const path = __importStar(require("path"));
45
+ function renderTemplate(template, variables) {
46
+ return template.replace(/\{\{([\w.\-]+)\}\}/g, (match, key) => {
47
+ return variables[key] !== undefined ? variables[key] : match;
48
+ });
49
+ }
50
+ function hashString(s) {
51
+ return crypto.createHash('sha256').update(s).digest('hex');
52
+ }
53
+ async function ensureDir(dir) {
54
+ await fs.promises.mkdir(dir, { recursive: true });
55
+ }
56
+ function readJsonFile(filePath) {
57
+ try {
58
+ const content = fs.readFileSync(filePath, 'utf-8');
59
+ return JSON.parse(content);
60
+ }
61
+ catch {
62
+ return null;
63
+ }
64
+ }
65
+ async function writeJsonFile(filePath, data) {
66
+ await ensureDir(path.dirname(filePath));
67
+ await fs.promises.writeFile(filePath, JSON.stringify(data, null, 2) + '\n', 'utf-8');
68
+ }
69
+ function spinner(message) {
70
+ const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
71
+ let i = 0;
72
+ const interval = setInterval(() => {
73
+ process.stderr.write(`\r${frames[i % frames.length]} ${message}`);
74
+ i++;
75
+ }, 80);
76
+ return {
77
+ stop(finalMessage) {
78
+ clearInterval(interval);
79
+ process.stderr.write(`\r${finalMessage ?? message}${''.padEnd(10)}\n`);
80
+ },
81
+ };
82
+ }
83
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,wCAIC;AAED,gCAEC;AAED,8BAEC;AAED,oCAOC;AAED,sCAGC;AAED,0BAcC;AA9CD,+CAAiC;AACjC,uCAAyB;AACzB,2CAA6B;AAE7B,SAAgB,cAAc,CAAC,QAAgB,EAAE,SAAiC;IAChF,OAAO,QAAQ,CAAC,OAAO,CAAC,qBAAqB,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC5D,OAAO,SAAS,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,UAAU,CAAC,CAAS;IAClC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC7D,CAAC;AAEM,KAAK,UAAU,SAAS,CAAC,GAAW;IACzC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,SAAgB,YAAY,CAAI,QAAgB;IAC9C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAM,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,aAAa,CAAC,QAAgB,EAAE,IAAa;IACjE,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACxC,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AACvF,CAAC;AAED,SAAgB,OAAO,CAAC,OAAe;IACrC,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAClE,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC;QAClE,CAAC,EAAE,CAAC;IACN,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO;QACL,IAAI,CAAC,YAAqB;YACxB,aAAa,CAAC,QAAQ,CAAC,CAAC;YACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,YAAY,IAAI,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;QACzE,CAAC;KACF,CAAC;AACJ,CAAC"}