@vibe-agent-toolkit/agent-skills 0.1.40 → 0.1.41-rc.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/dist/skill-test/eval-executor.d.ts +50 -0
- package/dist/skill-test/eval-executor.d.ts.map +1 -0
- package/dist/skill-test/eval-executor.js +85 -0
- package/dist/skill-test/eval-executor.js.map +1 -0
- package/dist/skill-test/eval-fragment.d.ts +278 -0
- package/dist/skill-test/eval-fragment.d.ts.map +1 -0
- package/dist/skill-test/eval-fragment.js +128 -0
- package/dist/skill-test/eval-fragment.js.map +1 -0
- package/dist/skill-test/eval-grader.d.ts +54 -0
- package/dist/skill-test/eval-grader.d.ts.map +1 -0
- package/dist/skill-test/eval-grader.js +184 -0
- package/dist/skill-test/eval-grader.js.map +1 -0
- package/dist/skill-test/eval-inputs.d.ts +355 -0
- package/dist/skill-test/eval-inputs.d.ts.map +1 -1
- package/dist/skill-test/eval-inputs.js +36 -8
- package/dist/skill-test/eval-inputs.js.map +1 -1
- package/dist/skill-test/eval-lint.d.ts +51 -0
- package/dist/skill-test/eval-lint.d.ts.map +1 -0
- package/dist/skill-test/eval-lint.js +157 -0
- package/dist/skill-test/eval-lint.js.map +1 -0
- package/dist/skill-test/evals-template.d.ts.map +1 -1
- package/dist/skill-test/evals-template.js +7 -0
- package/dist/skill-test/evals-template.js.map +1 -1
- package/dist/skill-test/executor-prompt.d.ts +41 -0
- package/dist/skill-test/executor-prompt.d.ts.map +1 -0
- package/dist/skill-test/executor-prompt.js +63 -0
- package/dist/skill-test/executor-prompt.js.map +1 -0
- package/dist/skill-test/exit-codes.d.ts +8 -5
- package/dist/skill-test/exit-codes.d.ts.map +1 -1
- package/dist/skill-test/exit-codes.js +12 -7
- package/dist/skill-test/exit-codes.js.map +1 -1
- package/dist/skill-test/fragment-merge.d.ts +46 -0
- package/dist/skill-test/fragment-merge.d.ts.map +1 -0
- package/dist/skill-test/fragment-merge.js +77 -0
- package/dist/skill-test/fragment-merge.js.map +1 -0
- package/dist/skill-test/friction-schema.d.ts +10 -10
- package/dist/skill-test/friction-schema.d.ts.map +1 -1
- package/dist/skill-test/friction-schema.js +6 -1
- package/dist/skill-test/friction-schema.js.map +1 -1
- package/dist/skill-test/grader-model.d.ts +6 -0
- package/dist/skill-test/grader-model.d.ts.map +1 -0
- package/dist/skill-test/grader-model.js +6 -0
- package/dist/skill-test/grader-model.js.map +1 -0
- package/dist/skill-test/grader-prompt.d.ts +74 -0
- package/dist/skill-test/grader-prompt.d.ts.map +1 -0
- package/dist/skill-test/grader-prompt.js +173 -0
- package/dist/skill-test/grader-prompt.js.map +1 -0
- package/dist/skill-test/grading-adapter.d.ts +5 -11
- package/dist/skill-test/grading-adapter.d.ts.map +1 -1
- package/dist/skill-test/grading-adapter.js +9 -22
- package/dist/skill-test/grading-adapter.js.map +1 -1
- package/dist/skill-test/grading-schema.d.ts +18 -15
- package/dist/skill-test/grading-schema.d.ts.map +1 -1
- package/dist/skill-test/grading-schema.js +6 -5
- package/dist/skill-test/grading-schema.js.map +1 -1
- package/dist/skill-test/index.d.ts +13 -3
- package/dist/skill-test/index.d.ts.map +1 -1
- package/dist/skill-test/index.js +13 -3
- package/dist/skill-test/index.js.map +1 -1
- package/dist/skill-test/pipeline.d.ts +29 -0
- package/dist/skill-test/pipeline.d.ts.map +1 -0
- package/dist/skill-test/pipeline.js +77 -0
- package/dist/skill-test/pipeline.js.map +1 -0
- package/dist/skill-test/prompt-invariants.d.ts +27 -0
- package/dist/skill-test/prompt-invariants.d.ts.map +1 -0
- package/dist/skill-test/prompt-invariants.js +38 -0
- package/dist/skill-test/prompt-invariants.js.map +1 -0
- package/dist/skill-test/run-harness.d.ts +187 -55
- package/dist/skill-test/run-harness.d.ts.map +1 -1
- package/dist/skill-test/run-harness.js +539 -189
- package/dist/skill-test/run-harness.js.map +1 -1
- package/dist/skill-test/tier-plan.d.ts +89 -0
- package/dist/skill-test/tier-plan.d.ts.map +1 -0
- package/dist/skill-test/tier-plan.js +96 -0
- package/dist/skill-test/tier-plan.js.map +1 -0
- package/dist/skill-test/tool-eval-schema.d.ts +412 -0
- package/dist/skill-test/tool-eval-schema.d.ts.map +1 -0
- package/dist/skill-test/tool-eval-schema.js +83 -0
- package/dist/skill-test/tool-eval-schema.js.map +1 -0
- package/dist/validators/packaging-validator.d.ts +8 -1
- package/dist/validators/packaging-validator.d.ts.map +1 -1
- package/dist/validators/packaging-validator.js.map +1 -1
- package/package.json +5 -5
- package/schemas/friction-report.json +2 -1
- package/dist/skill-test/experimenter-prompt.d.ts +0 -42
- package/dist/skill-test/experimenter-prompt.d.ts.map +0 -1
- package/dist/skill-test/experimenter-prompt.js +0 -104
- package/dist/skill-test/experimenter-prompt.js.map +0 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { spawnHeadlessClaude, type ParsedTranscript, type SpawnResult } from '@vibe-agent-toolkit/utils';
|
|
2
|
+
export interface RunExecutorInput {
|
|
3
|
+
evalId: string;
|
|
4
|
+
task: string;
|
|
5
|
+
subjectStagedDir: string;
|
|
6
|
+
/** `<workspacesRoot>/<id>` when the eval declares input `files`. */
|
|
7
|
+
workspaceDir?: string;
|
|
8
|
+
pluginDirs: string[];
|
|
9
|
+
env: NodeJS.ProcessEnv;
|
|
10
|
+
model?: string;
|
|
11
|
+
maxTurns: number;
|
|
12
|
+
maxBudgetUsd: number;
|
|
13
|
+
timeoutMs: number;
|
|
14
|
+
stallMs?: number;
|
|
15
|
+
/** Injectable seam for tests; defaults to the real {@link spawnHeadlessClaude}. */
|
|
16
|
+
spawn?: typeof spawnHeadlessClaude;
|
|
17
|
+
/** Called with each stdout chunk as it streams (for progress echo). */
|
|
18
|
+
onProgress?: (chunk: string) => void;
|
|
19
|
+
}
|
|
20
|
+
export interface ExecutorOutcome {
|
|
21
|
+
/** Full captured stdout (stream-json), held IN MEMORY only — never written to disk. */
|
|
22
|
+
transcript: string;
|
|
23
|
+
parsed: ParsedTranscript;
|
|
24
|
+
spawnResult: SpawnResult;
|
|
25
|
+
/** true = the executor exited non-zero WITHIN budget — a valid eval failure, not a harness break. */
|
|
26
|
+
cleanFailure: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Run ONE eval's executor: a blind `claude -p` spawn that performs `task`
|
|
30
|
+
* against the staged subject (issue #145). The executor's entire stream-json
|
|
31
|
+
* stdout is accumulated in memory (never written to a skill-writable disk
|
|
32
|
+
* path — the "stop discarding stdout" fix) and echoed to `onProgress` chunk
|
|
33
|
+
* by chunk for visibility.
|
|
34
|
+
*
|
|
35
|
+
* Encodes the R1 exit bifurcation at the executor boundary:
|
|
36
|
+
* - A spawn error (the promise rejects), or our own watchdog firing
|
|
37
|
+
* (`timedOut`/`stalled`), is HARNESS breakage → thrown as
|
|
38
|
+
* {@link InternalHarnessError} (exit 1).
|
|
39
|
+
* - A mid-stream rate-limit that cuts the run off before it completes (status
|
|
40
|
+
* !== 0) is NOT a harness failure but also not gradeable → thrown as
|
|
41
|
+
* {@link RateLimitSignal} so the caller's pool can back off and retry this
|
|
42
|
+
* eval. A rate-limit event that the run still completed past (status 0) is
|
|
43
|
+
* kept and returned normally.
|
|
44
|
+
* - Anything else — including a clean non-zero exit within budget — is a
|
|
45
|
+
* valid eval OUTCOME, not a harness break: returned with `cleanFailure`
|
|
46
|
+
* reflecting whether the executor exited non-zero. Never laundered into a
|
|
47
|
+
* thrown error; the grader decides whether the transcript passes.
|
|
48
|
+
*/
|
|
49
|
+
export declare function runExecutorForEval(input: RunExecutorInput): Promise<ExecutorOutcome>;
|
|
50
|
+
//# sourceMappingURL=eval-executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eval-executor.d.ts","sourceRoot":"","sources":["../../src/skill-test/eval-executor.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EACjB,MAAM,2BAA2B,CAAC;AAMnC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,MAAM,CAAC;IACzB,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mFAAmF;IACnF,KAAK,CAAC,EAAE,OAAO,mBAAmB,CAAC;IACnC,uEAAuE;IACvE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,eAAe;IAC9B,uFAAuF;IACvF,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,gBAAgB,CAAC;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,qGAAqG;IACrG,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC,CAsE1F"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { parseStreamJsonTranscript, spawnHeadlessClaude, } from '@vibe-agent-toolkit/utils';
|
|
2
|
+
import { assertExecutorPromptInvariants, buildExecutorPrompt } from './executor-prompt.js';
|
|
3
|
+
import { InternalHarnessError } from './exit-codes.js';
|
|
4
|
+
import { RateLimitSignal } from './pipeline.js';
|
|
5
|
+
/**
|
|
6
|
+
* Run ONE eval's executor: a blind `claude -p` spawn that performs `task`
|
|
7
|
+
* against the staged subject (issue #145). The executor's entire stream-json
|
|
8
|
+
* stdout is accumulated in memory (never written to a skill-writable disk
|
|
9
|
+
* path — the "stop discarding stdout" fix) and echoed to `onProgress` chunk
|
|
10
|
+
* by chunk for visibility.
|
|
11
|
+
*
|
|
12
|
+
* Encodes the R1 exit bifurcation at the executor boundary:
|
|
13
|
+
* - A spawn error (the promise rejects), or our own watchdog firing
|
|
14
|
+
* (`timedOut`/`stalled`), is HARNESS breakage → thrown as
|
|
15
|
+
* {@link InternalHarnessError} (exit 1).
|
|
16
|
+
* - A mid-stream rate-limit that cuts the run off before it completes (status
|
|
17
|
+
* !== 0) is NOT a harness failure but also not gradeable → thrown as
|
|
18
|
+
* {@link RateLimitSignal} so the caller's pool can back off and retry this
|
|
19
|
+
* eval. A rate-limit event that the run still completed past (status 0) is
|
|
20
|
+
* kept and returned normally.
|
|
21
|
+
* - Anything else — including a clean non-zero exit within budget — is a
|
|
22
|
+
* valid eval OUTCOME, not a harness break: returned with `cleanFailure`
|
|
23
|
+
* reflecting whether the executor exited non-zero. Never laundered into a
|
|
24
|
+
* thrown error; the grader decides whether the transcript passes.
|
|
25
|
+
*/
|
|
26
|
+
export async function runExecutorForEval(input) {
|
|
27
|
+
const workDir = input.workspaceDir ?? input.subjectStagedDir;
|
|
28
|
+
const prompt = buildExecutorPrompt({
|
|
29
|
+
task: input.task,
|
|
30
|
+
subjectPath: input.subjectStagedDir,
|
|
31
|
+
...(input.workspaceDir === undefined ? {} : { workspaceDir: input.workspaceDir }),
|
|
32
|
+
});
|
|
33
|
+
// Defense-in-depth (parity with run-harness's build→assert→use pattern):
|
|
34
|
+
// re-verify the built prompt didn't accidentally blind-break the executor
|
|
35
|
+
// before spawning. Only OUR scaffolding is policed — the adopter task is
|
|
36
|
+
// excluded, so a legit task containing denylist words does not trip this.
|
|
37
|
+
assertExecutorPromptInvariants(prompt, input.task);
|
|
38
|
+
const spawn = input.spawn ?? spawnHeadlessClaude;
|
|
39
|
+
let transcript = '';
|
|
40
|
+
const onStdout = (chunk) => {
|
|
41
|
+
transcript += chunk;
|
|
42
|
+
input.onProgress?.(chunk);
|
|
43
|
+
};
|
|
44
|
+
let spawnResult;
|
|
45
|
+
try {
|
|
46
|
+
spawnResult = await spawn({
|
|
47
|
+
prompt,
|
|
48
|
+
pluginDirs: input.pluginDirs,
|
|
49
|
+
sandboxDir: workDir,
|
|
50
|
+
cwd: workDir,
|
|
51
|
+
env: input.env,
|
|
52
|
+
timeoutMs: input.timeoutMs,
|
|
53
|
+
onStdout,
|
|
54
|
+
maxTurns: input.maxTurns,
|
|
55
|
+
maxBudgetUsd: input.maxBudgetUsd,
|
|
56
|
+
...(input.model === undefined ? {} : { model: input.model }),
|
|
57
|
+
...(input.stallMs === undefined ? {} : { stallMs: input.stallMs }),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
throw new InternalHarnessError(`Executor spawn failed for eval "${input.evalId}": ${err instanceof Error ? err.message : String(err)}`);
|
|
62
|
+
}
|
|
63
|
+
// Watchdog kills (our own harness code, not the executor) are harness
|
|
64
|
+
// breakage regardless of what the executor produced before being killed.
|
|
65
|
+
if (spawnResult.stalled) {
|
|
66
|
+
throw new InternalHarnessError(`Executor stalled for eval "${input.evalId}" (no output for ${input.stallMs ?? 0}ms).`);
|
|
67
|
+
}
|
|
68
|
+
if (spawnResult.timedOut) {
|
|
69
|
+
throw new InternalHarnessError(`Executor timed out for eval "${input.evalId}" (limit ${input.timeoutMs}ms).`);
|
|
70
|
+
}
|
|
71
|
+
const parsed = parseStreamJsonTranscript(transcript);
|
|
72
|
+
// A rate-limit that cut the run off before completion (non-zero status) is
|
|
73
|
+
// not gradeable — signal the pool to back off and retry. A rate-limit event
|
|
74
|
+
// the run otherwise completed past (status 0) is kept as-is.
|
|
75
|
+
if (parsed.rateLimited && spawnResult.status !== 0) {
|
|
76
|
+
throw new RateLimitSignal(`Executor rate-limited for eval "${input.evalId}".`);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
transcript,
|
|
80
|
+
parsed,
|
|
81
|
+
spawnResult,
|
|
82
|
+
cleanFailure: spawnResult.status !== 0,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=eval-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eval-executor.js","sourceRoot":"","sources":["../../src/skill-test/eval-executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** One graded expectation inside a per-eval grader fragment. */
|
|
3
|
+
export declare const EvalFragmentExpectationSchema: z.ZodObject<{
|
|
4
|
+
text: z.ZodString;
|
|
5
|
+
passed: z.ZodBoolean;
|
|
6
|
+
evidence: z.ZodOptional<z.ZodString>;
|
|
7
|
+
}, "strict", z.ZodTypeAny, {
|
|
8
|
+
passed: boolean;
|
|
9
|
+
text: string;
|
|
10
|
+
evidence?: string | undefined;
|
|
11
|
+
}, {
|
|
12
|
+
passed: boolean;
|
|
13
|
+
text: string;
|
|
14
|
+
evidence?: string | undefined;
|
|
15
|
+
}>;
|
|
16
|
+
export type EvalFragmentExpectation = z.infer<typeof EvalFragmentExpectationSchema>;
|
|
17
|
+
/**
|
|
18
|
+
* Strict shape of a single grader subagent's output (issue #145 Task 4). One
|
|
19
|
+
* GRADER spawn grades ONE eval's expectations from that eval's captured
|
|
20
|
+
* transcript and writes exactly one fragment matching this schema; vat reads
|
|
21
|
+
* every eval's fragment back and merges them into the run's aggregate grading
|
|
22
|
+
* result (skill-creator's flat `grading.json` shape — see grading-adapter.ts).
|
|
23
|
+
*
|
|
24
|
+
* `.strict()`: this is vat's OWN output artifact contract, not external data
|
|
25
|
+
* we're auditing (see CLAUDE.md Postel's Law) — an unrecognized field is a
|
|
26
|
+
* grader bug we want surfaced immediately, not silently dropped.
|
|
27
|
+
*
|
|
28
|
+
* `arm` distinguishes a WITH/WITHOUT baseline run's fragment; absent means the
|
|
29
|
+
* default 'with' (skill present) arm.
|
|
30
|
+
*
|
|
31
|
+
* `tool` (issue #145 Phase T) carries this eval's tool-expectation verdict —
|
|
32
|
+
* a SEPARATE channel from `expectations[]` and from `friction` (see
|
|
33
|
+
* tool-eval-schema.ts). It is {@link ToolVerdictBodySchema}, i.e. a
|
|
34
|
+
* {@link import('./tool-eval-schema.js').ToolVerdict} WITHOUT `evalId`: the
|
|
35
|
+
* fragment already carries `evalId` at its top level, so the merge step
|
|
36
|
+
* (`mergeFragmentsToToolEval` in fragment-merge.ts) re-attaches it from the
|
|
37
|
+
* fragment when assembling vat's `tool-eval.json`.
|
|
38
|
+
*/
|
|
39
|
+
export declare const EvalFragmentSchema: z.ZodObject<{
|
|
40
|
+
runNonce: z.ZodString;
|
|
41
|
+
evalId: z.ZodString;
|
|
42
|
+
arm: z.ZodOptional<z.ZodEnum<["with", "without"]>>;
|
|
43
|
+
expectations: z.ZodArray<z.ZodObject<{
|
|
44
|
+
text: z.ZodString;
|
|
45
|
+
passed: z.ZodBoolean;
|
|
46
|
+
evidence: z.ZodOptional<z.ZodString>;
|
|
47
|
+
}, "strict", z.ZodTypeAny, {
|
|
48
|
+
passed: boolean;
|
|
49
|
+
text: string;
|
|
50
|
+
evidence?: string | undefined;
|
|
51
|
+
}, {
|
|
52
|
+
passed: boolean;
|
|
53
|
+
text: string;
|
|
54
|
+
evidence?: string | undefined;
|
|
55
|
+
}>, "many">;
|
|
56
|
+
friction: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
57
|
+
severity: z.ZodEnum<["high", "medium", "low"]>;
|
|
58
|
+
category: z.ZodEnum<["path-assumption", "undeclared-dependency", "ambient-propping", "doc-engine-drift", "missing-bundled-file", "tool-expectation"]>;
|
|
59
|
+
message: z.ZodString;
|
|
60
|
+
subjectFile: z.ZodOptional<z.ZodString>;
|
|
61
|
+
evidence: z.ZodOptional<z.ZodString>;
|
|
62
|
+
}, "strict", z.ZodTypeAny, {
|
|
63
|
+
message: string;
|
|
64
|
+
severity: "high" | "medium" | "low";
|
|
65
|
+
category: "path-assumption" | "undeclared-dependency" | "ambient-propping" | "doc-engine-drift" | "missing-bundled-file" | "tool-expectation";
|
|
66
|
+
evidence?: string | undefined;
|
|
67
|
+
subjectFile?: string | undefined;
|
|
68
|
+
}, {
|
|
69
|
+
message: string;
|
|
70
|
+
severity: "high" | "medium" | "low";
|
|
71
|
+
category: "path-assumption" | "undeclared-dependency" | "ambient-propping" | "doc-engine-drift" | "missing-bundled-file" | "tool-expectation";
|
|
72
|
+
evidence?: string | undefined;
|
|
73
|
+
subjectFile?: string | undefined;
|
|
74
|
+
}>, "many">>;
|
|
75
|
+
tool: z.ZodOptional<z.ZodObject<{
|
|
76
|
+
mustRun: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
77
|
+
name: z.ZodString;
|
|
78
|
+
ran: z.ZodBoolean;
|
|
79
|
+
evidence: z.ZodOptional<z.ZodString>;
|
|
80
|
+
}, "strict", z.ZodTypeAny, {
|
|
81
|
+
name: string;
|
|
82
|
+
ran: boolean;
|
|
83
|
+
evidence?: string | undefined;
|
|
84
|
+
}, {
|
|
85
|
+
name: string;
|
|
86
|
+
ran: boolean;
|
|
87
|
+
evidence?: string | undefined;
|
|
88
|
+
}>, "many">>;
|
|
89
|
+
mustNotRun: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
90
|
+
name: z.ZodString;
|
|
91
|
+
ran: z.ZodBoolean;
|
|
92
|
+
evidence: z.ZodOptional<z.ZodString>;
|
|
93
|
+
}, "strict", z.ZodTypeAny, {
|
|
94
|
+
name: string;
|
|
95
|
+
ran: boolean;
|
|
96
|
+
evidence?: string | undefined;
|
|
97
|
+
}, {
|
|
98
|
+
name: string;
|
|
99
|
+
ran: boolean;
|
|
100
|
+
evidence?: string | undefined;
|
|
101
|
+
}>, "many">>;
|
|
102
|
+
mustSucceed: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
103
|
+
name: z.ZodString;
|
|
104
|
+
succeeded: z.ZodBoolean;
|
|
105
|
+
evidence: z.ZodOptional<z.ZodString>;
|
|
106
|
+
}, "strict", z.ZodTypeAny, {
|
|
107
|
+
name: string;
|
|
108
|
+
succeeded: boolean;
|
|
109
|
+
evidence?: string | undefined;
|
|
110
|
+
}, {
|
|
111
|
+
name: string;
|
|
112
|
+
succeeded: boolean;
|
|
113
|
+
evidence?: string | undefined;
|
|
114
|
+
}>, "many">>;
|
|
115
|
+
sequence: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
116
|
+
steps: z.ZodArray<z.ZodString, "many">;
|
|
117
|
+
satisfied: z.ZodBoolean;
|
|
118
|
+
evidence: z.ZodOptional<z.ZodString>;
|
|
119
|
+
}, "strict", z.ZodTypeAny, {
|
|
120
|
+
steps: string[];
|
|
121
|
+
satisfied: boolean;
|
|
122
|
+
evidence?: string | undefined;
|
|
123
|
+
}, {
|
|
124
|
+
steps: string[];
|
|
125
|
+
satisfied: boolean;
|
|
126
|
+
evidence?: string | undefined;
|
|
127
|
+
}>, "many">>;
|
|
128
|
+
passed: z.ZodBoolean;
|
|
129
|
+
}, "strict", z.ZodTypeAny, {
|
|
130
|
+
passed: boolean;
|
|
131
|
+
mustRun?: {
|
|
132
|
+
name: string;
|
|
133
|
+
ran: boolean;
|
|
134
|
+
evidence?: string | undefined;
|
|
135
|
+
}[] | undefined;
|
|
136
|
+
mustNotRun?: {
|
|
137
|
+
name: string;
|
|
138
|
+
ran: boolean;
|
|
139
|
+
evidence?: string | undefined;
|
|
140
|
+
}[] | undefined;
|
|
141
|
+
mustSucceed?: {
|
|
142
|
+
name: string;
|
|
143
|
+
succeeded: boolean;
|
|
144
|
+
evidence?: string | undefined;
|
|
145
|
+
}[] | undefined;
|
|
146
|
+
sequence?: {
|
|
147
|
+
steps: string[];
|
|
148
|
+
satisfied: boolean;
|
|
149
|
+
evidence?: string | undefined;
|
|
150
|
+
}[] | undefined;
|
|
151
|
+
}, {
|
|
152
|
+
passed: boolean;
|
|
153
|
+
mustRun?: {
|
|
154
|
+
name: string;
|
|
155
|
+
ran: boolean;
|
|
156
|
+
evidence?: string | undefined;
|
|
157
|
+
}[] | undefined;
|
|
158
|
+
mustNotRun?: {
|
|
159
|
+
name: string;
|
|
160
|
+
ran: boolean;
|
|
161
|
+
evidence?: string | undefined;
|
|
162
|
+
}[] | undefined;
|
|
163
|
+
mustSucceed?: {
|
|
164
|
+
name: string;
|
|
165
|
+
succeeded: boolean;
|
|
166
|
+
evidence?: string | undefined;
|
|
167
|
+
}[] | undefined;
|
|
168
|
+
sequence?: {
|
|
169
|
+
steps: string[];
|
|
170
|
+
satisfied: boolean;
|
|
171
|
+
evidence?: string | undefined;
|
|
172
|
+
}[] | undefined;
|
|
173
|
+
}>>;
|
|
174
|
+
}, "strict", z.ZodTypeAny, {
|
|
175
|
+
expectations: {
|
|
176
|
+
passed: boolean;
|
|
177
|
+
text: string;
|
|
178
|
+
evidence?: string | undefined;
|
|
179
|
+
}[];
|
|
180
|
+
evalId: string;
|
|
181
|
+
runNonce: string;
|
|
182
|
+
arm?: "with" | "without" | undefined;
|
|
183
|
+
friction?: {
|
|
184
|
+
message: string;
|
|
185
|
+
severity: "high" | "medium" | "low";
|
|
186
|
+
category: "path-assumption" | "undeclared-dependency" | "ambient-propping" | "doc-engine-drift" | "missing-bundled-file" | "tool-expectation";
|
|
187
|
+
evidence?: string | undefined;
|
|
188
|
+
subjectFile?: string | undefined;
|
|
189
|
+
}[] | undefined;
|
|
190
|
+
tool?: {
|
|
191
|
+
passed: boolean;
|
|
192
|
+
mustRun?: {
|
|
193
|
+
name: string;
|
|
194
|
+
ran: boolean;
|
|
195
|
+
evidence?: string | undefined;
|
|
196
|
+
}[] | undefined;
|
|
197
|
+
mustNotRun?: {
|
|
198
|
+
name: string;
|
|
199
|
+
ran: boolean;
|
|
200
|
+
evidence?: string | undefined;
|
|
201
|
+
}[] | undefined;
|
|
202
|
+
mustSucceed?: {
|
|
203
|
+
name: string;
|
|
204
|
+
succeeded: boolean;
|
|
205
|
+
evidence?: string | undefined;
|
|
206
|
+
}[] | undefined;
|
|
207
|
+
sequence?: {
|
|
208
|
+
steps: string[];
|
|
209
|
+
satisfied: boolean;
|
|
210
|
+
evidence?: string | undefined;
|
|
211
|
+
}[] | undefined;
|
|
212
|
+
} | undefined;
|
|
213
|
+
}, {
|
|
214
|
+
expectations: {
|
|
215
|
+
passed: boolean;
|
|
216
|
+
text: string;
|
|
217
|
+
evidence?: string | undefined;
|
|
218
|
+
}[];
|
|
219
|
+
evalId: string;
|
|
220
|
+
runNonce: string;
|
|
221
|
+
arm?: "with" | "without" | undefined;
|
|
222
|
+
friction?: {
|
|
223
|
+
message: string;
|
|
224
|
+
severity: "high" | "medium" | "low";
|
|
225
|
+
category: "path-assumption" | "undeclared-dependency" | "ambient-propping" | "doc-engine-drift" | "missing-bundled-file" | "tool-expectation";
|
|
226
|
+
evidence?: string | undefined;
|
|
227
|
+
subjectFile?: string | undefined;
|
|
228
|
+
}[] | undefined;
|
|
229
|
+
tool?: {
|
|
230
|
+
passed: boolean;
|
|
231
|
+
mustRun?: {
|
|
232
|
+
name: string;
|
|
233
|
+
ran: boolean;
|
|
234
|
+
evidence?: string | undefined;
|
|
235
|
+
}[] | undefined;
|
|
236
|
+
mustNotRun?: {
|
|
237
|
+
name: string;
|
|
238
|
+
ran: boolean;
|
|
239
|
+
evidence?: string | undefined;
|
|
240
|
+
}[] | undefined;
|
|
241
|
+
mustSucceed?: {
|
|
242
|
+
name: string;
|
|
243
|
+
succeeded: boolean;
|
|
244
|
+
evidence?: string | undefined;
|
|
245
|
+
}[] | undefined;
|
|
246
|
+
sequence?: {
|
|
247
|
+
steps: string[];
|
|
248
|
+
satisfied: boolean;
|
|
249
|
+
evidence?: string | undefined;
|
|
250
|
+
}[] | undefined;
|
|
251
|
+
} | undefined;
|
|
252
|
+
}>;
|
|
253
|
+
export type EvalFragment = z.infer<typeof EvalFragmentSchema>;
|
|
254
|
+
/**
|
|
255
|
+
* Thrown when a single grader subagent's fragment output does not match
|
|
256
|
+
* {@link EvalFragmentSchema}. Deliberately distinct from `GradingSkewError`
|
|
257
|
+
* (grading-adapter.ts): that error's message is specific to the AGGREGATE
|
|
258
|
+
* `grading.json` shape (skill-creator's flat report) and is wrong when the
|
|
259
|
+
* thing that failed to parse is one grader's per-eval fragment — a fragment
|
|
260
|
+
* shape bug is a GRADER bug, not an aggregate-assembly bug, and the message
|
|
261
|
+
* should point at the offending eval, not at "Re-sync the vendored
|
|
262
|
+
* skill-creator".
|
|
263
|
+
*/
|
|
264
|
+
export declare class EvalFragmentError extends Error {
|
|
265
|
+
constructor(message: string);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Parse + validate one grader's fragment output. Throws {@link EvalFragmentError}
|
|
269
|
+
* — never {@link GradingSkewError} — because this is a per-eval fragment, not
|
|
270
|
+
* the assembled aggregate `grading.json`.
|
|
271
|
+
*
|
|
272
|
+
* The verdict channels are strict. The auxiliary `friction` field is sanitized
|
|
273
|
+
* leniently first (see {@link sanitizeFrictionField}); when items are dropped,
|
|
274
|
+
* `onWarn` (if given) is called so the operator sees that friction was partial —
|
|
275
|
+
* grading itself is never affected.
|
|
276
|
+
*/
|
|
277
|
+
export declare function parseEvalFragment(raw: unknown, onWarn?: (message: string) => void): EvalFragment;
|
|
278
|
+
//# sourceMappingURL=eval-fragment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eval-fragment.d.ts","sourceRoot":"","sources":["../../src/skill-test/eval-fragment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,gEAAgE;AAChE,eAAO,MAAM,6BAA6B;;;;;;;;;;;;EAI/B,CAAC;AAEZ,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,6BAA6B,CAAC,CAAC;AAEpF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAOpB,CAAC;AAEZ,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE9D;;;;;;;;;GASG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAI5B;AA+CD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,YAAY,CAkBhG"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { FrictionItemSchema } from './friction-schema.js';
|
|
3
|
+
import { ToolVerdictBodySchema } from './tool-eval-schema.js';
|
|
4
|
+
/** One graded expectation inside a per-eval grader fragment. */
|
|
5
|
+
export const EvalFragmentExpectationSchema = z.object({
|
|
6
|
+
text: z.string(),
|
|
7
|
+
passed: z.boolean(),
|
|
8
|
+
evidence: z.string().optional(),
|
|
9
|
+
}).strict();
|
|
10
|
+
/**
|
|
11
|
+
* Strict shape of a single grader subagent's output (issue #145 Task 4). One
|
|
12
|
+
* GRADER spawn grades ONE eval's expectations from that eval's captured
|
|
13
|
+
* transcript and writes exactly one fragment matching this schema; vat reads
|
|
14
|
+
* every eval's fragment back and merges them into the run's aggregate grading
|
|
15
|
+
* result (skill-creator's flat `grading.json` shape — see grading-adapter.ts).
|
|
16
|
+
*
|
|
17
|
+
* `.strict()`: this is vat's OWN output artifact contract, not external data
|
|
18
|
+
* we're auditing (see CLAUDE.md Postel's Law) — an unrecognized field is a
|
|
19
|
+
* grader bug we want surfaced immediately, not silently dropped.
|
|
20
|
+
*
|
|
21
|
+
* `arm` distinguishes a WITH/WITHOUT baseline run's fragment; absent means the
|
|
22
|
+
* default 'with' (skill present) arm.
|
|
23
|
+
*
|
|
24
|
+
* `tool` (issue #145 Phase T) carries this eval's tool-expectation verdict —
|
|
25
|
+
* a SEPARATE channel from `expectations[]` and from `friction` (see
|
|
26
|
+
* tool-eval-schema.ts). It is {@link ToolVerdictBodySchema}, i.e. a
|
|
27
|
+
* {@link import('./tool-eval-schema.js').ToolVerdict} WITHOUT `evalId`: the
|
|
28
|
+
* fragment already carries `evalId` at its top level, so the merge step
|
|
29
|
+
* (`mergeFragmentsToToolEval` in fragment-merge.ts) re-attaches it from the
|
|
30
|
+
* fragment when assembling vat's `tool-eval.json`.
|
|
31
|
+
*/
|
|
32
|
+
export const EvalFragmentSchema = z.object({
|
|
33
|
+
runNonce: z.string().min(1),
|
|
34
|
+
evalId: z.string().min(1),
|
|
35
|
+
arm: z.enum(['with', 'without']).optional(),
|
|
36
|
+
expectations: z.array(EvalFragmentExpectationSchema).min(1),
|
|
37
|
+
friction: z.array(FrictionItemSchema).optional(),
|
|
38
|
+
tool: ToolVerdictBodySchema.optional(),
|
|
39
|
+
}).strict();
|
|
40
|
+
/**
|
|
41
|
+
* Thrown when a single grader subagent's fragment output does not match
|
|
42
|
+
* {@link EvalFragmentSchema}. Deliberately distinct from `GradingSkewError`
|
|
43
|
+
* (grading-adapter.ts): that error's message is specific to the AGGREGATE
|
|
44
|
+
* `grading.json` shape (skill-creator's flat report) and is wrong when the
|
|
45
|
+
* thing that failed to parse is one grader's per-eval fragment — a fragment
|
|
46
|
+
* shape bug is a GRADER bug, not an aggregate-assembly bug, and the message
|
|
47
|
+
* should point at the offending eval, not at "Re-sync the vendored
|
|
48
|
+
* skill-creator".
|
|
49
|
+
*/
|
|
50
|
+
export class EvalFragmentError extends Error {
|
|
51
|
+
constructor(message) {
|
|
52
|
+
super(message);
|
|
53
|
+
this.name = 'EvalFragmentError';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** Best-effort extraction of `evalId` from raw input for error messages, tolerating any shape. */
|
|
57
|
+
function extractRawEvalId(raw) {
|
|
58
|
+
if (typeof raw === 'object' && raw !== null && 'evalId' in raw) {
|
|
59
|
+
const value = raw['evalId'];
|
|
60
|
+
if (typeof value === 'string' && value.length > 0)
|
|
61
|
+
return `"${value}"`;
|
|
62
|
+
}
|
|
63
|
+
return '(unknown)';
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Sanitize ONLY the (non-verdict-bearing) `friction` field before the strict
|
|
67
|
+
* fragment parse. Friction is auxiliary advisory data, not a verdict channel —
|
|
68
|
+
* so a grader that wobbles on the friction shape (e.g. emits bare strings, the
|
|
69
|
+
* common failure mode — PR #147) must NOT be allowed to discard the
|
|
70
|
+
* verdict-bearing grading for the whole run. We drop friction items that don't
|
|
71
|
+
* match {@link FrictionItemSchema} (and a `friction` that isn't an array at
|
|
72
|
+
* all), then hand the rest to the STRICT fragment parse — so the verdict
|
|
73
|
+
* channels (`runNonce`/`evalId`/`expectations`/`tool`) stay fully fail-closed
|
|
74
|
+
* and an unknown field elsewhere still surfaces as a grader bug.
|
|
75
|
+
*
|
|
76
|
+
* Returns the possibly-rewritten raw value and how many friction items were
|
|
77
|
+
* dropped (0 when friction is absent or already well-shaped — the input is then
|
|
78
|
+
* returned untouched).
|
|
79
|
+
*/
|
|
80
|
+
function sanitizeFrictionField(raw) {
|
|
81
|
+
if (typeof raw !== 'object' || raw === null || !('friction' in raw)) {
|
|
82
|
+
return { value: raw, dropped: 0 };
|
|
83
|
+
}
|
|
84
|
+
const obj = raw;
|
|
85
|
+
const friction = obj['friction'];
|
|
86
|
+
if (friction === undefined)
|
|
87
|
+
return { value: raw, dropped: 0 };
|
|
88
|
+
if (!Array.isArray(friction)) {
|
|
89
|
+
// A non-array `friction` (e.g. a bare string) is unusable auxiliary noise —
|
|
90
|
+
// drop the whole field rather than fail the run over it.
|
|
91
|
+
const rest = {};
|
|
92
|
+
for (const [key, val] of Object.entries(obj)) {
|
|
93
|
+
if (key !== 'friction')
|
|
94
|
+
rest[key] = val;
|
|
95
|
+
}
|
|
96
|
+
return { value: rest, dropped: 1 };
|
|
97
|
+
}
|
|
98
|
+
const kept = friction.filter((item) => FrictionItemSchema.safeParse(item).success);
|
|
99
|
+
if (kept.length === friction.length)
|
|
100
|
+
return { value: raw, dropped: 0 };
|
|
101
|
+
return { value: { ...obj, friction: kept }, dropped: friction.length - kept.length };
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Parse + validate one grader's fragment output. Throws {@link EvalFragmentError}
|
|
105
|
+
* — never {@link GradingSkewError} — because this is a per-eval fragment, not
|
|
106
|
+
* the assembled aggregate `grading.json`.
|
|
107
|
+
*
|
|
108
|
+
* The verdict channels are strict. The auxiliary `friction` field is sanitized
|
|
109
|
+
* leniently first (see {@link sanitizeFrictionField}); when items are dropped,
|
|
110
|
+
* `onWarn` (if given) is called so the operator sees that friction was partial —
|
|
111
|
+
* grading itself is never affected.
|
|
112
|
+
*/
|
|
113
|
+
export function parseEvalFragment(raw, onWarn) {
|
|
114
|
+
const { value, dropped } = sanitizeFrictionField(raw);
|
|
115
|
+
if (dropped > 0) {
|
|
116
|
+
onWarn?.(`grader fragment for eval ${extractRawEvalId(raw)} had ${dropped} malformed friction item(s) — ` +
|
|
117
|
+
`dropped them (friction is advisory; grading is unaffected).`);
|
|
118
|
+
}
|
|
119
|
+
const result = EvalFragmentSchema.safeParse(value);
|
|
120
|
+
if (!result.success) {
|
|
121
|
+
const firstIssue = result.error.issues[0];
|
|
122
|
+
const path = firstIssue?.path.join('.') ?? '(root)';
|
|
123
|
+
const evalId = extractRawEvalId(raw);
|
|
124
|
+
throw new EvalFragmentError(`grader fragment for eval ${evalId} has an invalid shape: invalid field at "${path}" (${firstIssue?.message ?? 'unknown'})`);
|
|
125
|
+
}
|
|
126
|
+
return result.data;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=eval-fragment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eval-fragment.js","sourceRoot":"","sources":["../../src/skill-test/eval-fragment.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { spawnHeadlessClaude } from '@vibe-agent-toolkit/utils';
|
|
2
|
+
import { type EvalFragment } from './eval-fragment.js';
|
|
3
|
+
import type { ToolExpectations } from './eval-inputs.js';
|
|
4
|
+
export interface RunGraderInput {
|
|
5
|
+
evalId: string;
|
|
6
|
+
/** The FULL captured transcript (stream-json) for this eval's executor run. */
|
|
7
|
+
transcript: string;
|
|
8
|
+
expectations: string[];
|
|
9
|
+
expectedOutput?: string;
|
|
10
|
+
/** Path to the vendored skill-creator grader rubric (references/grader.md). */
|
|
11
|
+
rubricPath: string;
|
|
12
|
+
/**
|
|
13
|
+
* The eval's declared tool expectations (issue #145 Phase T). Optional — when
|
|
14
|
+
* absent, `buildGraderPrompt` emits no tool-verdict instruction and the
|
|
15
|
+
* returned fragment omits `tool`. See `grader-prompt.ts`'s
|
|
16
|
+
* `BuildGraderPromptOptions.toolExpectations`.
|
|
17
|
+
*/
|
|
18
|
+
toolExpectations?: ToolExpectations;
|
|
19
|
+
/** Name → invocation hint for declared executables, a recognition aid alongside `toolExpectations`. */
|
|
20
|
+
declaredExecutables?: Array<{
|
|
21
|
+
name: string;
|
|
22
|
+
howInvoked: string;
|
|
23
|
+
kind: string;
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* VAT-ONLY directory the grader fragment is written to — deliberately
|
|
27
|
+
* OUTSIDE the skill-writable sandbox (never the executor's staged/workspace
|
|
28
|
+
* dir) so untrusted skill code from Task 7's executor run cannot forge or
|
|
29
|
+
* delete the fragment this run relies on.
|
|
30
|
+
*/
|
|
31
|
+
graderOutDir: string;
|
|
32
|
+
graderModel: string;
|
|
33
|
+
/** Per-run integrity nonce the grader must echo back in the fragment. */
|
|
34
|
+
nonce: string;
|
|
35
|
+
maxTurns: number;
|
|
36
|
+
maxBudgetUsd: number;
|
|
37
|
+
timeoutMs: number;
|
|
38
|
+
stallMs?: number;
|
|
39
|
+
/** Grader auth env — no skill secrets are needed beyond auth. */
|
|
40
|
+
env: NodeJS.ProcessEnv;
|
|
41
|
+
/** Injectable seam for tests; defaults to the real {@link spawnHeadlessClaude}. */
|
|
42
|
+
spawn?: typeof spawnHeadlessClaude;
|
|
43
|
+
/** Called with each stdout chunk as it streams (for progress echo). */
|
|
44
|
+
onProgress?: (chunk: string) => void;
|
|
45
|
+
/**
|
|
46
|
+
* Reports this grader session's `total_cost_usd` (parsed from its stream-json
|
|
47
|
+
* transcript's terminal result; `undefined` when the transcript carried none,
|
|
48
|
+
* e.g. a mock spawn). Called once after a successful grader spawn so the run can
|
|
49
|
+
* aggregate total spend across all executor+grader sessions (adopter follow-up).
|
|
50
|
+
*/
|
|
51
|
+
costSink?: (totalCostUsd: number | undefined) => void;
|
|
52
|
+
}
|
|
53
|
+
export declare function runGraderForEval(input: RunGraderInput): Promise<EvalFragment>;
|
|
54
|
+
//# sourceMappingURL=eval-grader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eval-grader.d.ts","sourceRoot":"","sources":["../../src/skill-test/eval-grader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsD,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAEpH,OAAO,EAAwC,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAMzD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,uGAAuG;IACvG,mBAAmB,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChF;;;;;OAKG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,mFAAmF;IACnF,KAAK,CAAC,EAAE,OAAO,mBAAmB,CAAC;IACnC,uEAAuE;IACvE,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;CACvD;AAsCD,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CAoGnF"}
|