praxis-agent 0.46.4 → 0.47.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.
- package/README.md +4 -0
- package/dist/cli-runtime.d.ts +2 -0
- package/dist/cli-runtime.js +29 -2
- package/dist/evals/eval-contract.d.ts +102 -0
- package/dist/evals/eval-contract.js +57 -0
- package/dist/evals/eval-graders.d.ts +6 -0
- package/dist/evals/eval-graders.js +94 -0
- package/dist/evals/project-eval-runner.d.ts +59 -0
- package/dist/evals/project-eval-runner.js +359 -0
- package/dist/evals/project-eval-schema.d.ts +35 -0
- package/dist/evals/project-eval-schema.js +395 -0
- package/dist/evals/project-eval-workspace.d.ts +30 -0
- package/dist/evals/project-eval-workspace.js +108 -0
- package/dist/evals/project-eval.d.ts +77 -0
- package/dist/evals/project-eval.js +214 -0
- package/dist/platform/bounded-process-runner.d.ts +2 -0
- package/dist/platform/bounded-process-runner.js +4 -2
- package/dist/plugins/claude-plugin-eval-graders.d.ts +2 -33
- package/dist/plugins/claude-plugin-eval-graders.js +7 -66
- package/dist/plugins/claude-plugin-eval-runner.d.ts +4 -29
- package/dist/plugins/claude-plugin-eval-runner.js +3 -58
- package/dist/plugins/claude-plugin-eval-schema.d.ts +9 -34
- package/dist/tools/local-tools.js +16 -1
- package/package.json +1 -1
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import { writeFileAtomically } from '../platform/atomic-write.js';
|
|
2
|
+
import { BoundedProcessRunner } from '../platform/bounded-process-runner.js';
|
|
3
|
+
import { redactSensitiveValue, redactSensitiveText, sensitiveEnvironmentValues, } from '../platform/sensitive-data.js';
|
|
4
|
+
import { gradeDeterministicEvalRun } from './eval-graders.js';
|
|
5
|
+
import { normalizeEvalTraceEvent, resolveEvalAllowedTools, } from './eval-contract.js';
|
|
6
|
+
import { cleanupProjectEvalWorkspace, createProjectEvalWorkspace, diffProjectEvalWorkspace, } from './project-eval-workspace.js';
|
|
7
|
+
import { minimatch } from 'minimatch';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
function check(name, passed, explanation, evidence) {
|
|
10
|
+
return {
|
|
11
|
+
name,
|
|
12
|
+
passed,
|
|
13
|
+
weight: 1,
|
|
14
|
+
explanation,
|
|
15
|
+
...(evidence === undefined ? {} : { evidence }),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const MAX_TRACE_EVENTS = 10_000;
|
|
19
|
+
const MAX_TRACE_BYTES = 8 * 1024 * 1024;
|
|
20
|
+
function serializeTrace(value) {
|
|
21
|
+
try {
|
|
22
|
+
const seen = new WeakSet();
|
|
23
|
+
return (JSON.stringify(value, (_key, item) => {
|
|
24
|
+
if (typeof item === 'bigint')
|
|
25
|
+
return String(item);
|
|
26
|
+
if (item && typeof item === 'object') {
|
|
27
|
+
if (seen.has(item))
|
|
28
|
+
return '[Circular]';
|
|
29
|
+
seen.add(item);
|
|
30
|
+
}
|
|
31
|
+
return item;
|
|
32
|
+
}) ?? 'null');
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return '"[Unserializable]"';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function verifierEnvironment(evalEnvironment, home, temporaryDirectory) {
|
|
39
|
+
const environment = {
|
|
40
|
+
...evalEnvironment,
|
|
41
|
+
HOME: home,
|
|
42
|
+
USERPROFILE: home,
|
|
43
|
+
TMPDIR: temporaryDirectory,
|
|
44
|
+
TEMP: temporaryDirectory,
|
|
45
|
+
TMP: temporaryDirectory,
|
|
46
|
+
};
|
|
47
|
+
for (const name of [
|
|
48
|
+
'PATH',
|
|
49
|
+
'SystemRoot',
|
|
50
|
+
'WINDIR',
|
|
51
|
+
'COMSPEC',
|
|
52
|
+
'PATHEXT',
|
|
53
|
+
]) {
|
|
54
|
+
const value = process.env[name];
|
|
55
|
+
if (value !== undefined)
|
|
56
|
+
environment[name] = value;
|
|
57
|
+
}
|
|
58
|
+
return environment;
|
|
59
|
+
}
|
|
60
|
+
export async function runProjectEvalCase(options) {
|
|
61
|
+
if (!Number.isSafeInteger(options.run) || options.run < 1)
|
|
62
|
+
throw new Error('Project eval run index must be a positive integer');
|
|
63
|
+
if (options.case.verification.length && !options.runVerification)
|
|
64
|
+
throw new Error('Verification requires --run-verification');
|
|
65
|
+
const allowedTools = resolveEvalAllowedTools(options.case.execution.allowedTools, options.allowTools ?? []);
|
|
66
|
+
const sensitiveValues = sensitiveEnvironmentValues(process.env, options.case.execution.env);
|
|
67
|
+
const errorText = (error) => redactSensitiveText(error instanceof Error ? error.message : String(error), sensitiveValues);
|
|
68
|
+
const workspace = await createProjectEvalWorkspace(options.case.fixture);
|
|
69
|
+
const trace = [];
|
|
70
|
+
const traceRecords = [];
|
|
71
|
+
let traceBytes = 0;
|
|
72
|
+
let traceOverflow = false;
|
|
73
|
+
const verifications = [];
|
|
74
|
+
const verifierChecks = [];
|
|
75
|
+
const cleanupErrors = [];
|
|
76
|
+
const started = Date.now();
|
|
77
|
+
let runtime;
|
|
78
|
+
let runtimeCompleted = false;
|
|
79
|
+
let runtimeError = null;
|
|
80
|
+
let runtimeCloseError = null;
|
|
81
|
+
let termination = null;
|
|
82
|
+
let turns = 0;
|
|
83
|
+
let usage = null;
|
|
84
|
+
let costUsd = null;
|
|
85
|
+
let lastMessage = '';
|
|
86
|
+
let graderError = null;
|
|
87
|
+
let graders = [];
|
|
88
|
+
const runtimeController = new AbortController();
|
|
89
|
+
let deadlineReached = false;
|
|
90
|
+
const forwardAbort = () => runtimeController.abort(options.signal?.reason);
|
|
91
|
+
options.signal?.addEventListener('abort', forwardAbort, { once: true });
|
|
92
|
+
if (options.signal?.aborted)
|
|
93
|
+
forwardAbort();
|
|
94
|
+
const runtimeTimer = setTimeout(() => {
|
|
95
|
+
deadlineReached = true;
|
|
96
|
+
runtimeController.abort(new DOMException('Eval run timed out', 'AbortError'));
|
|
97
|
+
}, options.case.execution.timeoutSeconds * 1000);
|
|
98
|
+
try {
|
|
99
|
+
runtime = await options.factory.create({
|
|
100
|
+
dataPlane: 'native',
|
|
101
|
+
cwd: workspace.cwd,
|
|
102
|
+
configRoot: workspace.config,
|
|
103
|
+
home: workspace.home,
|
|
104
|
+
maxTurns: options.case.execution.maxTurns,
|
|
105
|
+
pluginDirectories: [],
|
|
106
|
+
allowedTools,
|
|
107
|
+
...((options.model ?? options.case.execution.model)
|
|
108
|
+
? { model: options.model ?? options.case.execution.model }
|
|
109
|
+
: {}),
|
|
110
|
+
...(options.case.execution.appendSystemPrompt
|
|
111
|
+
? { appendSystemPrompt: options.case.execution.appendSystemPrompt }
|
|
112
|
+
: {}),
|
|
113
|
+
addDirs: [],
|
|
114
|
+
env: options.case.execution.env,
|
|
115
|
+
eventSink: (event) => {
|
|
116
|
+
if (traceOverflow)
|
|
117
|
+
return;
|
|
118
|
+
try {
|
|
119
|
+
const normalized = normalizeEvalTraceEvent(event);
|
|
120
|
+
const redacted = redactSensitiveValue(normalized, sensitiveValues);
|
|
121
|
+
const encoded = serializeTrace(redacted);
|
|
122
|
+
const bytes = Buffer.byteLength(encoded);
|
|
123
|
+
const nextBytes = traceBytes + bytes + (trace.length ? 1 : 0);
|
|
124
|
+
if (trace.length >= MAX_TRACE_EVENTS || nextBytes > MAX_TRACE_BYTES) {
|
|
125
|
+
traceOverflow = true;
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
trace.push(JSON.parse(encoded));
|
|
129
|
+
traceRecords.push(encoded);
|
|
130
|
+
traceBytes = nextBytes;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
traceOverflow = true;
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
const result = await runtime.run(options.case.execution.prompt, runtimeController.signal);
|
|
138
|
+
lastMessage = result.text;
|
|
139
|
+
turns = result.turns;
|
|
140
|
+
usage = result.usage ?? null;
|
|
141
|
+
costUsd = result.costUsd ?? null;
|
|
142
|
+
if (options.signal?.aborted) {
|
|
143
|
+
termination = 'interrupted';
|
|
144
|
+
runtimeError = 'Eval run interrupted';
|
|
145
|
+
}
|
|
146
|
+
else if (deadlineReached || runtimeController.signal.aborted) {
|
|
147
|
+
termination = 'timeout';
|
|
148
|
+
runtimeError = 'Eval run timed out';
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
runtimeCompleted = true;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
runtimeError = errorText(error);
|
|
156
|
+
if (options.signal?.aborted) {
|
|
157
|
+
termination = 'interrupted';
|
|
158
|
+
runtimeError = 'Eval run interrupted';
|
|
159
|
+
}
|
|
160
|
+
else if (deadlineReached || runtimeController.signal.aborted) {
|
|
161
|
+
termination = 'timeout';
|
|
162
|
+
runtimeError = 'Eval run timed out';
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
clearTimeout(runtimeTimer);
|
|
167
|
+
options.signal?.removeEventListener('abort', forwardAbort);
|
|
168
|
+
try {
|
|
169
|
+
await runtime?.close?.();
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
runtimeCloseError = errorText(error);
|
|
173
|
+
cleanupErrors.push(`Runtime cleanup failed: ${runtimeCloseError}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (runtimeCompleted && !runtimeCloseError && !termination) {
|
|
177
|
+
for (const verifier of options.case.verification) {
|
|
178
|
+
const verifierStarted = Date.now();
|
|
179
|
+
try {
|
|
180
|
+
const result = await new BoundedProcessRunner({
|
|
181
|
+
cwd: workspace.cwd,
|
|
182
|
+
maxOutputBytes: 64 * 1024,
|
|
183
|
+
}).run({
|
|
184
|
+
command: verifier.command,
|
|
185
|
+
args: [...verifier.args],
|
|
186
|
+
cwd: workspace.cwd,
|
|
187
|
+
timeoutMs: verifier.timeoutSeconds * 1000,
|
|
188
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
189
|
+
env: verifierEnvironment(options.case.execution.env, workspace.home, workspace.root),
|
|
190
|
+
inheritEnvironment: false,
|
|
191
|
+
redactExplicitEnvironment: true,
|
|
192
|
+
});
|
|
193
|
+
const passed = result.code === 0 && !result.timedOut;
|
|
194
|
+
const verifierError = result.timedOut
|
|
195
|
+
? 'Verifier timed out'
|
|
196
|
+
: result.code === 0
|
|
197
|
+
? null
|
|
198
|
+
: `Verifier exited with code ${result.code}`;
|
|
199
|
+
verifications.push({
|
|
200
|
+
schema_version: '1.0',
|
|
201
|
+
name: verifier.name,
|
|
202
|
+
command: verifier.command,
|
|
203
|
+
argv: [...verifier.args],
|
|
204
|
+
exit_code: result.code,
|
|
205
|
+
timed_out: result.timedOut,
|
|
206
|
+
stdout: result.stdout,
|
|
207
|
+
stderr: result.stderr,
|
|
208
|
+
truncated: result.truncated,
|
|
209
|
+
duration_ms: Date.now() - verifierStarted,
|
|
210
|
+
passed,
|
|
211
|
+
error: verifierError,
|
|
212
|
+
});
|
|
213
|
+
verifierChecks.push(check(`verifier:${verifier.name}`, passed, passed ? 'Verifier passed' : (verifierError ?? 'Verifier failed')));
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
const message = errorText(error);
|
|
217
|
+
if (options.signal?.aborted)
|
|
218
|
+
termination = 'interrupted';
|
|
219
|
+
verifications.push({
|
|
220
|
+
schema_version: '1.0',
|
|
221
|
+
name: verifier.name,
|
|
222
|
+
command: verifier.command,
|
|
223
|
+
argv: [...verifier.args],
|
|
224
|
+
exit_code: null,
|
|
225
|
+
timed_out: false,
|
|
226
|
+
stdout: '',
|
|
227
|
+
stderr: '',
|
|
228
|
+
truncated: false,
|
|
229
|
+
duration_ms: Date.now() - verifierStarted,
|
|
230
|
+
passed: false,
|
|
231
|
+
error: message,
|
|
232
|
+
});
|
|
233
|
+
verifierChecks.push(check(`verifier:${verifier.name}`, false, message));
|
|
234
|
+
if (termination === 'interrupted')
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
const verifiersPassed = verifierChecks.every((item) => item.passed);
|
|
240
|
+
if (runtimeCompleted &&
|
|
241
|
+
!runtimeCloseError &&
|
|
242
|
+
!termination &&
|
|
243
|
+
verifiersPassed &&
|
|
244
|
+
options.case.graders.length > 0) {
|
|
245
|
+
try {
|
|
246
|
+
graders = await gradeDeterministicEvalRun({
|
|
247
|
+
graders: options.case.graders,
|
|
248
|
+
artifacts: { lastMessage, trace, cwd: workspace.cwd },
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
graderError = errorText(error);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
let manifestError = null;
|
|
256
|
+
let after;
|
|
257
|
+
let sourceAfter;
|
|
258
|
+
try {
|
|
259
|
+
after = await workspace.manifest(workspace.cwd);
|
|
260
|
+
sourceAfter = await workspace.manifest(options.case.fixture);
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
manifestError = errorText(error);
|
|
264
|
+
}
|
|
265
|
+
const workspaceDiff = after
|
|
266
|
+
? await diffProjectEvalWorkspace(workspace.before, after)
|
|
267
|
+
: { added: [], modified: [], deleted: [], changed: [] };
|
|
268
|
+
const sourceUnchanged = sourceAfter !== undefined &&
|
|
269
|
+
JSON.stringify(sourceAfter) === JSON.stringify(workspace.sourceBefore);
|
|
270
|
+
const allowedPaths = workspaceDiff.changed.every((path) => options.case.expect.allowedChangedPaths.some((pattern) => minimatch(path, pattern)));
|
|
271
|
+
const expectedPaths = options.case.expect.expectedChangedPaths.every((pattern) => workspaceDiff.changed.some((path) => minimatch(path, pattern)));
|
|
272
|
+
const forbiddenPaths = !workspaceDiff.changed.some((path) => options.case.expect.forbiddenChangedPaths.some((pattern) => minimatch(path, pattern)));
|
|
273
|
+
const checks = [
|
|
274
|
+
check('runtime', runtimeCompleted && runtimeError === null, runtimeCompleted
|
|
275
|
+
? 'Runtime completed'
|
|
276
|
+
: (runtimeError ?? 'Runtime failed')),
|
|
277
|
+
check('termination', termination === null, termination === null ? 'Run completed' : `Run ${termination}`),
|
|
278
|
+
check('trace-bounds', !traceOverflow, traceOverflow ? 'Trace exceeded artifact bounds' : 'Trace within bounds'),
|
|
279
|
+
check('runtime-close', runtimeCloseError === null, runtimeCloseError === null
|
|
280
|
+
? runtime
|
|
281
|
+
? 'Runtime closed'
|
|
282
|
+
: 'Runtime was not created'
|
|
283
|
+
: `Runtime cleanup failed: ${runtimeCloseError}`),
|
|
284
|
+
...verifierChecks,
|
|
285
|
+
...graders.map((grader) => check(`grader:${grader.name}`, grader.passed, grader.explanation, grader.evidence)),
|
|
286
|
+
...(graderError
|
|
287
|
+
? [check('graders', false, `Project graders failed: ${graderError}`)]
|
|
288
|
+
: []),
|
|
289
|
+
check('workspace-manifest', manifestError === null && after !== undefined, manifestError ?? 'Workspace manifest completed'),
|
|
290
|
+
check('source-unchanged', sourceUnchanged, sourceUnchanged ? 'Source fixture unchanged' : 'Source fixture changed'),
|
|
291
|
+
check('allowed-paths', allowedPaths, allowedPaths ? 'All changes are allowed' : 'Unexpected path mutation', workspaceDiff.changed.join('\n')),
|
|
292
|
+
check('expected-paths', expectedPaths, expectedPaths
|
|
293
|
+
? 'Expected changes are present'
|
|
294
|
+
: 'Expected change missing', workspaceDiff.changed.join('\n')),
|
|
295
|
+
check('forbidden-paths', forbiddenPaths, forbiddenPaths ? 'No forbidden changes' : 'Forbidden path changed', workspaceDiff.changed.join('\n')),
|
|
296
|
+
];
|
|
297
|
+
const runDirectory = join(options.outputDir, options.case.name, `run-${options.run}`);
|
|
298
|
+
let artifactError = null;
|
|
299
|
+
try {
|
|
300
|
+
await writeFileAtomically(join(runDirectory, 'trace.jsonl'), traceRecords.join('\n'));
|
|
301
|
+
await writeFileAtomically(join(runDirectory, 'workspace-diff.json'), JSON.stringify({ schema_version: '1.0', ...workspaceDiff }, null, 2));
|
|
302
|
+
await writeFileAtomically(join(runDirectory, 'verification.json'), JSON.stringify(verifications, null, 2));
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
artifactError = errorText(error);
|
|
306
|
+
}
|
|
307
|
+
checks.push(check('artifact-write', artifactError === null, artifactError ?? 'Run artifacts written'));
|
|
308
|
+
let tempCleanupError = null;
|
|
309
|
+
if (!options.keepTemp) {
|
|
310
|
+
try {
|
|
311
|
+
await cleanupProjectEvalWorkspace(workspace.root);
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
tempCleanupError = errorText(error);
|
|
315
|
+
cleanupErrors.push(`Temp cleanup failed: ${tempCleanupError}`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
checks.push(check('temp-cleanup', tempCleanupError === null, options.keepTemp
|
|
319
|
+
? 'Temporary workspace kept by request'
|
|
320
|
+
: tempCleanupError === null
|
|
321
|
+
? 'Temporary workspace removed'
|
|
322
|
+
: `Temporary workspace cleanup failed: ${tempCleanupError}`));
|
|
323
|
+
const passed = checks.every((item) => item.passed);
|
|
324
|
+
const primaryError = runtimeError ??
|
|
325
|
+
graderError ??
|
|
326
|
+
verifications.find((verification) => verification.error)?.error ??
|
|
327
|
+
manifestError ??
|
|
328
|
+
checks.find((item) => !item.passed)?.explanation ??
|
|
329
|
+
null;
|
|
330
|
+
const result = {
|
|
331
|
+
schema_version: '1.0',
|
|
332
|
+
case: options.case.name,
|
|
333
|
+
run: options.run,
|
|
334
|
+
version: options.version,
|
|
335
|
+
model: options.model ?? options.case.execution.model ?? null,
|
|
336
|
+
passed,
|
|
337
|
+
score: passed ? 1 : 0,
|
|
338
|
+
turns,
|
|
339
|
+
usage,
|
|
340
|
+
cost_usd: costUsd,
|
|
341
|
+
cost_known: costUsd !== null,
|
|
342
|
+
duration_ms: Date.now() - started,
|
|
343
|
+
termination,
|
|
344
|
+
graders,
|
|
345
|
+
checks,
|
|
346
|
+
artifacts: {
|
|
347
|
+
trace: 'trace.jsonl',
|
|
348
|
+
workspace_diff: 'workspace-diff.json',
|
|
349
|
+
verification: 'verification.json',
|
|
350
|
+
result: 'result.json',
|
|
351
|
+
},
|
|
352
|
+
error: primaryError,
|
|
353
|
+
cleanup_errors: cleanupErrors,
|
|
354
|
+
temp_root: options.keepTemp ? workspace.root : null,
|
|
355
|
+
};
|
|
356
|
+
await writeFileAtomically(join(runDirectory, 'result.json'), JSON.stringify(result, null, 2));
|
|
357
|
+
return result;
|
|
358
|
+
}
|
|
359
|
+
//# sourceMappingURL=project-eval-runner.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { EvalDeterministicGrader } from './eval-contract.js';
|
|
2
|
+
export declare const PROJECT_EVAL_SCHEMA_VERSION = "1.0";
|
|
3
|
+
export interface ProjectEvalCase {
|
|
4
|
+
schemaVersion: '1.0';
|
|
5
|
+
name: string;
|
|
6
|
+
dir: string;
|
|
7
|
+
fixture: string;
|
|
8
|
+
tags: readonly string[];
|
|
9
|
+
runs: number;
|
|
10
|
+
execution: {
|
|
11
|
+
prompt: string;
|
|
12
|
+
maxTurns: number;
|
|
13
|
+
timeoutSeconds: number;
|
|
14
|
+
allowedTools: readonly string[];
|
|
15
|
+
model?: string;
|
|
16
|
+
appendSystemPrompt?: string;
|
|
17
|
+
env: Readonly<Record<string, string>>;
|
|
18
|
+
};
|
|
19
|
+
verification: readonly {
|
|
20
|
+
name: string;
|
|
21
|
+
command: string;
|
|
22
|
+
args: readonly string[];
|
|
23
|
+
timeoutSeconds: number;
|
|
24
|
+
}[];
|
|
25
|
+
graders: readonly EvalDeterministicGrader[];
|
|
26
|
+
expect: {
|
|
27
|
+
allowedChangedPaths: readonly string[];
|
|
28
|
+
expectedChangedPaths: readonly string[];
|
|
29
|
+
forbiddenChangedPaths: readonly string[];
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export declare function parseProjectEvalCase(raw: unknown, dir: string): ProjectEvalCase;
|
|
33
|
+
export declare function loadProjectEvalCase(dir: string): Promise<ProjectEvalCase>;
|
|
34
|
+
export declare function discoverProjectEvalCases(target: string, filter?: string, tags?: readonly string[]): Promise<ProjectEvalCase[]>;
|
|
35
|
+
//# sourceMappingURL=project-eval-schema.d.ts.map
|