@zelari/core 1.29.0 → 1.30.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/dist/kraken/graph.d.ts +5 -2
- package/dist/kraken/graph.d.ts.map +1 -1
- package/dist/kraken/graph.js.map +1 -1
- package/dist/kraken/index.d.ts +10 -2
- package/dist/kraken/index.d.ts.map +1 -1
- package/dist/kraken/index.js +10 -2
- package/dist/kraken/index.js.map +1 -1
- package/dist/kraken/personas/conformance.d.ts +25 -0
- package/dist/kraken/personas/conformance.d.ts.map +1 -0
- package/dist/kraken/personas/conformance.js +89 -0
- package/dist/kraken/personas/conformance.js.map +1 -0
- package/dist/kraken/personas/index.d.ts +12 -0
- package/dist/kraken/personas/index.d.ts.map +1 -0
- package/dist/kraken/personas/index.js +12 -0
- package/dist/kraken/personas/index.js.map +1 -0
- package/dist/kraken/personas/registry.d.ts +62 -0
- package/dist/kraken/personas/registry.d.ts.map +1 -0
- package/dist/kraken/personas/registry.js +49 -0
- package/dist/kraken/personas/registry.js.map +1 -0
- package/dist/kraken/personas/specReviewer.d.ts +21 -0
- package/dist/kraken/personas/specReviewer.d.ts.map +1 -0
- package/dist/kraken/personas/specReviewer.js +74 -0
- package/dist/kraken/personas/specReviewer.js.map +1 -0
- package/dist/kraken/runtime/index.d.ts +13 -0
- package/dist/kraken/runtime/index.d.ts.map +1 -0
- package/dist/kraken/runtime/index.js +16 -0
- package/dist/kraken/runtime/index.js.map +1 -0
- package/dist/kraken/runtime/runner.d.ts +80 -0
- package/dist/kraken/runtime/runner.d.ts.map +1 -0
- package/dist/kraken/runtime/runner.js +253 -0
- package/dist/kraken/runtime/runner.js.map +1 -0
- package/dist/kraken/runtime/sandbox.d.ts +65 -0
- package/dist/kraken/runtime/sandbox.d.ts.map +1 -0
- package/dist/kraken/runtime/sandbox.js +158 -0
- package/dist/kraken/runtime/sandbox.js.map +1 -0
- package/dist/kraken/runtime/sdk.d.ts +32 -0
- package/dist/kraken/runtime/sdk.d.ts.map +1 -0
- package/dist/kraken/runtime/sdk.js +61 -0
- package/dist/kraken/runtime/sdk.js.map +1 -0
- package/dist/kraken/runtime/types.d.ts +220 -0
- package/dist/kraken/runtime/types.d.ts.map +1 -0
- package/dist/kraken/runtime/types.js +35 -0
- package/dist/kraken/runtime/types.js.map +1 -0
- package/dist/kraken/verdict.d.ts +53 -0
- package/dist/kraken/verdict.d.ts.map +1 -1
- package/dist/kraken/verdict.js +75 -0
- package/dist/kraken/verdict.js.map +1 -1
- package/dist/kraken/weakness.d.ts +160 -0
- package/dist/kraken/weakness.d.ts.map +1 -0
- package/dist/kraken/weakness.js +305 -0
- package/dist/kraken/weakness.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kraken script runtime — public types.
|
|
3
|
+
*
|
|
4
|
+
* A Kraken "script plan" is a TypeScript module the planner emits (or a user
|
|
5
|
+
* hands in) that imports the SDK from `@zelari/kraken-runtime` and calls
|
|
6
|
+
* `tentacle()`, `merge()`, `checkpoint()`, etc. The runtime compiles the
|
|
7
|
+
* module with esbuild (CLI side), loads it in a Node `vm` context with a
|
|
8
|
+
* capability-based sandbox, and runs it. Every call into the SDK is a
|
|
9
|
+
* bridge from the sandboxed script to the parent process — there is no
|
|
10
|
+
* direct filesystem, process, or network access in the script.
|
|
11
|
+
*
|
|
12
|
+
* Safety invariants (see F1.1 in `.zelari/docs/kraken-best-in-class-roadmap.md`):
|
|
13
|
+
* - The script cannot read `process.env` or `fs` outside the SDK.
|
|
14
|
+
* - Every `tentacle()` call increments a counter; the run aborts past
|
|
15
|
+
* `MAX_TENTACLES` (default 200) regardless of what the script does.
|
|
16
|
+
* - The script runs under a wall-clock budget (`ZELARI_KRAKEN_PLAN_TIMEOUT_MS`,
|
|
17
|
+
* default 30 minutes) enforced by the `vm` timeout.
|
|
18
|
+
* - `merge()` is one-shot per plan: a second call throws `PlanError` and
|
|
19
|
+
* the run is settled.
|
|
20
|
+
*
|
|
21
|
+
* @since Kraken v1.30.x — workflow script runtime (F1.1)
|
|
22
|
+
*/
|
|
23
|
+
import type { z } from 'zod';
|
|
24
|
+
import type { TaskNodeKind, TaskNodeStatus } from '../graph.js';
|
|
25
|
+
/** A node the script plans to spawn. Mirrors the JSON-DAG shape for parity. */
|
|
26
|
+
export interface TentacleOptions<T = unknown> {
|
|
27
|
+
/** What kind of subagent this is. */
|
|
28
|
+
kind: TaskNodeKind;
|
|
29
|
+
/** Short label for status / radio (max 200 chars). */
|
|
30
|
+
label: string;
|
|
31
|
+
/** Full self-contained prompt handed to the subagent. */
|
|
32
|
+
prompt: string;
|
|
33
|
+
/** Path/glob allowlist. Required for parallel writers. */
|
|
34
|
+
scope?: string[];
|
|
35
|
+
/** Acceptance checklist enforced by the verify tentacle. */
|
|
36
|
+
acceptance?: string[];
|
|
37
|
+
/** Upstream tentacle refs whose results are injected as context. */
|
|
38
|
+
deps?: TentacleRef[];
|
|
39
|
+
/**
|
|
40
|
+
* Optional Zod schema. If set, the subagent is asked to emit JSON matching
|
|
41
|
+
* the schema as its final message; the parsed result is exposed as
|
|
42
|
+
* `TentacleRef.result`. Use for structured hand-offs between tentacles.
|
|
43
|
+
*/
|
|
44
|
+
outputSchema?: z.ZodType<T>;
|
|
45
|
+
/** Tool-call budget. Default: `deep` for writers, `medium` for readers. */
|
|
46
|
+
thoroughness?: 'quick' | 'medium' | 'deep';
|
|
47
|
+
/** Model override. Default: routed by `krakenModel` per kind. */
|
|
48
|
+
model?: string;
|
|
49
|
+
/** Max retries before the node is left `error` (no fix-node spawn). */
|
|
50
|
+
maxRetries?: number;
|
|
51
|
+
/** Wall-clock cap (ms) for this single tentacle. 0 disables. */
|
|
52
|
+
maxRuntimeMs?: number;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* A reference to a tentacle the script spawned. The `result` is populated
|
|
56
|
+
* only when the subagent emitted a parseable JSON matching `outputSchema`;
|
|
57
|
+
* otherwise the raw `findings` text is the fallback.
|
|
58
|
+
*/
|
|
59
|
+
export interface TentacleRef<T = unknown> {
|
|
60
|
+
id: string;
|
|
61
|
+
kind: TaskNodeKind;
|
|
62
|
+
label: string;
|
|
63
|
+
status: TaskNodeStatus;
|
|
64
|
+
/** Parsed JSON if `outputSchema` was set and the subagent emitted it. */
|
|
65
|
+
result?: T;
|
|
66
|
+
/** Raw text conclusion (always populated, capped to `MAX_FINDINGS_CHARS`). */
|
|
67
|
+
findings: string;
|
|
68
|
+
/** Verdict trailer for `verify` / `spec` / `conformance` tentacles. */
|
|
69
|
+
verdict?: 'pass' | 'fail' | 'unknown';
|
|
70
|
+
scope?: string[];
|
|
71
|
+
durationMs?: number;
|
|
72
|
+
worktree?: string | null;
|
|
73
|
+
}
|
|
74
|
+
/** How a `merge()` call should land the worktrees in the parent HEAD. */
|
|
75
|
+
export type MergeStrategy = 'squash' | 'squash-sequential' | 'rebase' | 'manual';
|
|
76
|
+
export interface MergeOptions {
|
|
77
|
+
strategy?: MergeStrategy;
|
|
78
|
+
message?: string;
|
|
79
|
+
/** Delete the worktrees after a successful merge. Default: true. */
|
|
80
|
+
cleanup?: boolean;
|
|
81
|
+
}
|
|
82
|
+
/** Per-tentacle outcome from the runtime's perspective. */
|
|
83
|
+
export interface MergeResult {
|
|
84
|
+
merged: string[];
|
|
85
|
+
conflicts: {
|
|
86
|
+
nodeId: string;
|
|
87
|
+
reason: string;
|
|
88
|
+
}[];
|
|
89
|
+
/** True when every input tentacle was merged without conflict. */
|
|
90
|
+
ok: boolean;
|
|
91
|
+
}
|
|
92
|
+
/** Snapshot of the running plan, persisted as JSON. */
|
|
93
|
+
export interface PlanSnapshot {
|
|
94
|
+
graphId: string;
|
|
95
|
+
goal: string;
|
|
96
|
+
takenAt: string;
|
|
97
|
+
completed: TentacleRef[];
|
|
98
|
+
inFlight: TentacleRef[];
|
|
99
|
+
failed: TentacleRef[];
|
|
100
|
+
/** Tentacles the script already declared but not yet started. */
|
|
101
|
+
pending: TentacleRef[];
|
|
102
|
+
}
|
|
103
|
+
/** What the user (or a hook) can emit to the radio / workbench. */
|
|
104
|
+
export interface EmitPayload {
|
|
105
|
+
kind: string;
|
|
106
|
+
detail?: string;
|
|
107
|
+
data?: Record<string, unknown>;
|
|
108
|
+
}
|
|
109
|
+
/** Error categories the script runtime can raise. */
|
|
110
|
+
export type PlanErrorKind = 'budget_exceeded' | 'merge_already_done' | 'merge_conflict' | 'compile_error' | 'runtime_error' | 'sandbox_breach' | 'cancelled';
|
|
111
|
+
/** Structured error from the runtime; scripts should not throw raw values. */
|
|
112
|
+
export declare class PlanError extends Error {
|
|
113
|
+
readonly name = "PlanError";
|
|
114
|
+
readonly kind: PlanErrorKind;
|
|
115
|
+
readonly cause?: unknown;
|
|
116
|
+
constructor(kind: PlanErrorKind, message: string, cause?: unknown);
|
|
117
|
+
}
|
|
118
|
+
/** Capabilities injected into the script sandbox. Pure values + functions. */
|
|
119
|
+
export interface PlanCapabilities {
|
|
120
|
+
tentacle<T = unknown>(opts: TentacleOptions<T>): Promise<TentacleRef<T>>;
|
|
121
|
+
/** Wait for N tentacles to complete (parallel); returns the same refs typed. */
|
|
122
|
+
barrier<T extends readonly TentacleRef[]>(refs: T): Promise<{
|
|
123
|
+
-readonly [K in keyof T]: T[K];
|
|
124
|
+
}>;
|
|
125
|
+
/** Race N tentacles; first to complete wins, others are cancelled. */
|
|
126
|
+
race<T extends readonly TentacleRef[]>(refs: T): Promise<T[number]>;
|
|
127
|
+
/** Bounded loop helper. Throws PlanError('budget_exceeded') past `maxIter`. */
|
|
128
|
+
while_<T>(cond: () => boolean | Promise<boolean>, body: () => Promise<T>, maxIter: number): Promise<T[]>;
|
|
129
|
+
until<T>(cond: () => boolean | Promise<boolean>, body: () => Promise<T>, maxIter: number): Promise<T[]>;
|
|
130
|
+
/** Sequential merge of N worktrees into the parent HEAD. */
|
|
131
|
+
merge(refs: readonly TentacleRef[], opts?: MergeOptions): Promise<MergeResult>;
|
|
132
|
+
/** Snapshot the current plan state to `.zelari/kraken/snapshots/<id>.json`. */
|
|
133
|
+
checkpoint(label?: string): Promise<PlanSnapshot>;
|
|
134
|
+
/** Structured log line to the radio + workbench. */
|
|
135
|
+
log(msg: string, data?: Record<string, unknown>): void;
|
|
136
|
+
/** Emit a custom radio event for downstream tools. */
|
|
137
|
+
emit(payload: EmitPayload): void;
|
|
138
|
+
/** Read-only access to the plan-level context (graph id, goal, etc.). */
|
|
139
|
+
getContext(): PlanContext;
|
|
140
|
+
/** Cross-session message: enqueue a message for `peerId` (a TentacleRef). */
|
|
141
|
+
sendTo(peerId: string, payload: EmitPayload): void;
|
|
142
|
+
}
|
|
143
|
+
/** Read-only metadata exposed to the script via `getContext()`. */
|
|
144
|
+
export interface PlanContext {
|
|
145
|
+
graphId: string;
|
|
146
|
+
goal: string;
|
|
147
|
+
parentCwd: string;
|
|
148
|
+
sessionId: string;
|
|
149
|
+
/** Tentacles emitted so far, by id. */
|
|
150
|
+
tentacles: ReadonlyMap<string, TentacleRef>;
|
|
151
|
+
/** Tentacle cap (`ZELARI_KRAKEN_MAX_TENTACLES`, default 200). */
|
|
152
|
+
maxTentacles: number;
|
|
153
|
+
/** Wall-clock budget for the whole plan (ms). */
|
|
154
|
+
planTimeoutMs: number;
|
|
155
|
+
}
|
|
156
|
+
/** Bridge between the host (executor) and the script runtime. */
|
|
157
|
+
export interface PlanHostBridge {
|
|
158
|
+
/**
|
|
159
|
+
* Run one tentacle, returning the raw host result. The runner turns this
|
|
160
|
+
* into a `TentacleRef` and parses verdicts where appropriate.
|
|
161
|
+
*
|
|
162
|
+
* `worktree` is the worktree path the host created for this tentacle, or
|
|
163
|
+
* `null` if none (read-only kinds). The script runtime uses it to drive
|
|
164
|
+
* `merge()` later.
|
|
165
|
+
*/
|
|
166
|
+
runTentacle(args: {
|
|
167
|
+
node: TentacleOptions;
|
|
168
|
+
parentCwd: string;
|
|
169
|
+
sessionId: string;
|
|
170
|
+
}): Promise<HostTentacleResult>;
|
|
171
|
+
/** Merge N worktrees into the parent HEAD, sequentially. */
|
|
172
|
+
mergeWorktrees(args: {
|
|
173
|
+
refs: readonly TentacleRef[];
|
|
174
|
+
parentCwd: string;
|
|
175
|
+
strategy: MergeStrategy;
|
|
176
|
+
message?: string;
|
|
177
|
+
cleanup?: boolean;
|
|
178
|
+
}): Promise<MergeResult>;
|
|
179
|
+
/** Append a structured log line to the radio + workbench. */
|
|
180
|
+
log(line: string): void;
|
|
181
|
+
/** Persist a snapshot JSON to disk. */
|
|
182
|
+
saveSnapshot(snapshot: PlanSnapshot, dir: string): Promise<string>;
|
|
183
|
+
/** Read the abort signal; the script should respect it between awaits. */
|
|
184
|
+
signal(): AbortSignal | undefined;
|
|
185
|
+
}
|
|
186
|
+
/** Raw tentacle outcome from the host. The runner wraps this in a
|
|
187
|
+
* `TentacleRef` and stashes it for snapshot / merge. */
|
|
188
|
+
export interface HostTentacleResult {
|
|
189
|
+
ok: boolean;
|
|
190
|
+
/** Subagent's final text conclusion. Undefined on failure. */
|
|
191
|
+
result?: string;
|
|
192
|
+
/** Error message. Undefined on success. */
|
|
193
|
+
error?: string;
|
|
194
|
+
/** Wall-clock duration (ms). Optional; the host may not measure this. */
|
|
195
|
+
durationMs?: number;
|
|
196
|
+
/** Worktree path the host created, or null. */
|
|
197
|
+
worktree?: string | null;
|
|
198
|
+
}
|
|
199
|
+
/** What `runScriptPlan` returns to the executor — the same shape the JSON
|
|
200
|
+
* DAG path returns, so the executor doesn't need to special-case the two. */
|
|
201
|
+
export interface ScriptRunResult {
|
|
202
|
+
/** All tentacles that ran, keyed by id. */
|
|
203
|
+
tentacles: ReadonlyMap<string, TentacleRef>;
|
|
204
|
+
/** Number of `merge()` calls made. 0 = never merged, ≥1 = merged at least once. */
|
|
205
|
+
mergeCount: number;
|
|
206
|
+
/** Aggregate verdict surfaced to the workbench / digest. */
|
|
207
|
+
converged: boolean;
|
|
208
|
+
/** When the run stopped because the abort signal fired. */
|
|
209
|
+
cancelled: boolean;
|
|
210
|
+
/** Wall-clock duration of the whole plan (ms). */
|
|
211
|
+
durationMs: number;
|
|
212
|
+
/** Any unresolved findings (verify FAIL with rework budget spent, etc.). */
|
|
213
|
+
unresolvedFindings: {
|
|
214
|
+
nodeId: string;
|
|
215
|
+
label: string;
|
|
216
|
+
reason: string;
|
|
217
|
+
findings: string;
|
|
218
|
+
}[];
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/kraken/runtime/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kraken script runtime — public types.
|
|
3
|
+
*
|
|
4
|
+
* A Kraken "script plan" is a TypeScript module the planner emits (or a user
|
|
5
|
+
* hands in) that imports the SDK from `@zelari/kraken-runtime` and calls
|
|
6
|
+
* `tentacle()`, `merge()`, `checkpoint()`, etc. The runtime compiles the
|
|
7
|
+
* module with esbuild (CLI side), loads it in a Node `vm` context with a
|
|
8
|
+
* capability-based sandbox, and runs it. Every call into the SDK is a
|
|
9
|
+
* bridge from the sandboxed script to the parent process — there is no
|
|
10
|
+
* direct filesystem, process, or network access in the script.
|
|
11
|
+
*
|
|
12
|
+
* Safety invariants (see F1.1 in `.zelari/docs/kraken-best-in-class-roadmap.md`):
|
|
13
|
+
* - The script cannot read `process.env` or `fs` outside the SDK.
|
|
14
|
+
* - Every `tentacle()` call increments a counter; the run aborts past
|
|
15
|
+
* `MAX_TENTACLES` (default 200) regardless of what the script does.
|
|
16
|
+
* - The script runs under a wall-clock budget (`ZELARI_KRAKEN_PLAN_TIMEOUT_MS`,
|
|
17
|
+
* default 30 minutes) enforced by the `vm` timeout.
|
|
18
|
+
* - `merge()` is one-shot per plan: a second call throws `PlanError` and
|
|
19
|
+
* the run is settled.
|
|
20
|
+
*
|
|
21
|
+
* @since Kraken v1.30.x — workflow script runtime (F1.1)
|
|
22
|
+
*/
|
|
23
|
+
/** Structured error from the runtime; scripts should not throw raw values. */
|
|
24
|
+
export class PlanError extends Error {
|
|
25
|
+
name = 'PlanError';
|
|
26
|
+
kind;
|
|
27
|
+
cause;
|
|
28
|
+
constructor(kind, message, cause) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.kind = kind;
|
|
31
|
+
if (cause !== undefined)
|
|
32
|
+
this.cause = cause;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/kraken/runtime/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAuGH,8EAA8E;AAC9E,MAAM,OAAO,SAAU,SAAQ,KAAK;IAChB,IAAI,GAAG,WAAW,CAAC;IAC5B,IAAI,CAAgB;IACpB,KAAK,CAAW;IACzB,YAAY,IAAmB,EAAE,OAAe,EAAE,KAAe;QAC/D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IAC9C,CAAC;CACF"}
|
package/dist/kraken/verdict.d.ts
CHANGED
|
@@ -12,9 +12,25 @@
|
|
|
12
12
|
* a `VERDICT: PASS` / `VERDICT: FAIL` trailer; the executor parses it and, on
|
|
13
13
|
* FAIL, spawns a bounded rework round.
|
|
14
14
|
*
|
|
15
|
+
* **Pillar 2 extension (v1.30.x)**: `spec` and `conformance` personas emit
|
|
16
|
+
* the same trailer PLUS a per-requirement table in a JSON code block. The
|
|
17
|
+
* parser extracts both: the trailer is the gate, the table is the
|
|
18
|
+
* structured findings the executor can surface in the digest and feed
|
|
19
|
+
* into a follow-up `fix` node.
|
|
20
|
+
*
|
|
21
|
+
* **v1.31.x (Bennett's Razor)**: each parsed verdict now also carries a
|
|
22
|
+
* `weaknessScore` in `[0, 1]`, computed from the persona's free text via
|
|
23
|
+
* `weaknessFromVerdict` (see `./weakness.js`). 1.0 = "maximally general
|
|
24
|
+
* claim" (weak), 0.0 = "maximally specific claim" (strong). The gate
|
|
25
|
+
* (PASS/FAIL) is unchanged — weakness is metadata, surfaced in the
|
|
26
|
+
* workbench digest so the user can see whether a PASS was earned by a
|
|
27
|
+
* tightly-asserted reviewer or a loosely-claimed one.
|
|
28
|
+
*
|
|
15
29
|
* No CLI dependencies (see CORREZIONE-1 in the engine plan).
|
|
16
30
|
*
|
|
17
31
|
* @since v1.28.x — verify quality gate
|
|
32
|
+
* @since v1.30.x — spec / conformance persona verdicts
|
|
33
|
+
* @since v1.31.x — weakness score on persona verdicts
|
|
18
34
|
*/
|
|
19
35
|
/**
|
|
20
36
|
* What a verify node concluded.
|
|
@@ -62,4 +78,41 @@ export interface UnresolvedFinding {
|
|
|
62
78
|
reason: 'fail' | 'unknown';
|
|
63
79
|
findings: string;
|
|
64
80
|
}
|
|
81
|
+
/** One row of the spec / conformance per-requirement table. */
|
|
82
|
+
export interface RequirementVerdict {
|
|
83
|
+
requirement: string;
|
|
84
|
+
/** pass = satisfied, fail = violated, unknown = not assessed. */
|
|
85
|
+
met: 'pass' | 'fail' | 'unknown';
|
|
86
|
+
/** Path / line / output the reviewer cites as evidence. */
|
|
87
|
+
evidence?: string;
|
|
88
|
+
}
|
|
89
|
+
/** Structured verdict for `spec` and `conformance` personas.
|
|
90
|
+
*
|
|
91
|
+
* The trailer (`VERDICT: PASS|FAIL`) is the gate; the `requirements` table
|
|
92
|
+
* is the per-row reasoning the executor can surface and feed forward.
|
|
93
|
+
* `weaknessScore` (Bennett 2023) is metadata: 1.0 = the reviewer asserted
|
|
94
|
+
* very little (maximally weak / general), 0.0 = the reviewer pinned
|
|
95
|
+
* specific paths, versions, or invariants. It does NOT change the gate,
|
|
96
|
+
* but is surfaced in the workbench digest so a user can tell a tightly
|
|
97
|
+
* earned PASS from a loosely claimed one. */
|
|
98
|
+
export interface PersonaVerdict {
|
|
99
|
+
verdict: VerifyVerdict;
|
|
100
|
+
findings: string;
|
|
101
|
+
requirements: RequirementVerdict[];
|
|
102
|
+
/**
|
|
103
|
+
* Bennett-style weakness score in `[0, 1]`, computed from the persona's
|
|
104
|
+
* free text by `weaknessFromVerdict`. Higher = weaker = more general.
|
|
105
|
+
* `1` for the no-trailer case (a missing verdict asserts nothing) and
|
|
106
|
+
* for the all-empty case.
|
|
107
|
+
*
|
|
108
|
+
* @since v1.31.x
|
|
109
|
+
*/
|
|
110
|
+
weaknessScore: number;
|
|
111
|
+
}
|
|
112
|
+
/** Extract the per-requirement JSON block (if any) from a `spec` or
|
|
113
|
+
* `conformance` reply. The block is a ```json ... ``` fenced object
|
|
114
|
+
* with a `requirements: [...]` array. */
|
|
115
|
+
export declare function extractRequirementsBlock(text: string | undefined | null): RequirementVerdict[];
|
|
116
|
+
/** Full parser for a `spec` or `conformance` reply: trailer + table. */
|
|
117
|
+
export declare function parsePersonaVerdict(text: string | undefined | null): PersonaVerdict;
|
|
65
118
|
//# sourceMappingURL=verdict.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verdict.d.ts","sourceRoot":"","sources":["../../src/kraken/verdict.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"verdict.d.ts","sourceRoot":"","sources":["../../src/kraken/verdict.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAIH;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,aAAa,CAAC;IACvB;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,OAAO,CAAC;AAUvC;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,aAAa,CAsBjF;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,+DAA+D;AAC/D,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACjC,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;8CAQ8C;AAC9C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,kBAAkB,EAAE,CAAC;IACnC;;;;;;;OAOG;IACH,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;0CAE0C;AAC1C,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,kBAAkB,EAAE,CAgC9F;AAED,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,cAAc,CAcnF"}
|
package/dist/kraken/verdict.js
CHANGED
|
@@ -12,10 +12,27 @@
|
|
|
12
12
|
* a `VERDICT: PASS` / `VERDICT: FAIL` trailer; the executor parses it and, on
|
|
13
13
|
* FAIL, spawns a bounded rework round.
|
|
14
14
|
*
|
|
15
|
+
* **Pillar 2 extension (v1.30.x)**: `spec` and `conformance` personas emit
|
|
16
|
+
* the same trailer PLUS a per-requirement table in a JSON code block. The
|
|
17
|
+
* parser extracts both: the trailer is the gate, the table is the
|
|
18
|
+
* structured findings the executor can surface in the digest and feed
|
|
19
|
+
* into a follow-up `fix` node.
|
|
20
|
+
*
|
|
21
|
+
* **v1.31.x (Bennett's Razor)**: each parsed verdict now also carries a
|
|
22
|
+
* `weaknessScore` in `[0, 1]`, computed from the persona's free text via
|
|
23
|
+
* `weaknessFromVerdict` (see `./weakness.js`). 1.0 = "maximally general
|
|
24
|
+
* claim" (weak), 0.0 = "maximally specific claim" (strong). The gate
|
|
25
|
+
* (PASS/FAIL) is unchanged — weakness is metadata, surfaced in the
|
|
26
|
+
* workbench digest so the user can see whether a PASS was earned by a
|
|
27
|
+
* tightly-asserted reviewer or a loosely-claimed one.
|
|
28
|
+
*
|
|
15
29
|
* No CLI dependencies (see CORREZIONE-1 in the engine plan).
|
|
16
30
|
*
|
|
17
31
|
* @since v1.28.x — verify quality gate
|
|
32
|
+
* @since v1.30.x — spec / conformance persona verdicts
|
|
33
|
+
* @since v1.31.x — weakness score on persona verdicts
|
|
18
34
|
*/
|
|
35
|
+
import { weaknessScoreFromText } from './weakness.js';
|
|
19
36
|
/**
|
|
20
37
|
* Cap on retained findings text. Mirrors `MAX_UPSTREAM_CHARS_PER_DEP` in the
|
|
21
38
|
* CLI executor, since findings travel the same route (into a sub-agent prompt).
|
|
@@ -58,6 +75,64 @@ export function parseVerifyVerdict(text) {
|
|
|
58
75
|
const findings = capFindings(source.slice(0, last.index));
|
|
59
76
|
return { verdict, findings };
|
|
60
77
|
}
|
|
78
|
+
/** Extract the per-requirement JSON block (if any) from a `spec` or
|
|
79
|
+
* `conformance` reply. The block is a ```json ... ``` fenced object
|
|
80
|
+
* with a `requirements: [...]` array. */
|
|
81
|
+
export function extractRequirementsBlock(text) {
|
|
82
|
+
if (typeof text !== 'string' || text.trim() === '')
|
|
83
|
+
return [];
|
|
84
|
+
// Find the LAST ```json ... ``` block (LLMs sometimes emit the spec first,
|
|
85
|
+
// then the actual answer; we want the final one).
|
|
86
|
+
const re = /```json\s*([\s\S]*?)```/gi;
|
|
87
|
+
let m;
|
|
88
|
+
let last = null;
|
|
89
|
+
while ((m = re.exec(text)) !== null) {
|
|
90
|
+
last = m[1];
|
|
91
|
+
if (m.index === re.lastIndex)
|
|
92
|
+
re.lastIndex += 1;
|
|
93
|
+
}
|
|
94
|
+
if (!last)
|
|
95
|
+
return [];
|
|
96
|
+
try {
|
|
97
|
+
const obj = JSON.parse(last);
|
|
98
|
+
if (!obj || !Array.isArray(obj.requirements))
|
|
99
|
+
return [];
|
|
100
|
+
const out = [];
|
|
101
|
+
for (const r of obj.requirements) {
|
|
102
|
+
if (!r || typeof r !== 'object')
|
|
103
|
+
continue;
|
|
104
|
+
const row = r;
|
|
105
|
+
const req = typeof row.requirement === 'string' ? row.requirement : '';
|
|
106
|
+
const metRaw = typeof row.met === 'string' ? row.met.toLowerCase() : '';
|
|
107
|
+
const met = metRaw === 'pass' || metRaw === 'true' ? 'pass'
|
|
108
|
+
: metRaw === 'fail' || metRaw === 'false' ? 'fail'
|
|
109
|
+
: 'unknown';
|
|
110
|
+
const evidence = typeof row.evidence === 'string' ? row.evidence : undefined;
|
|
111
|
+
if (req)
|
|
112
|
+
out.push({ requirement: req, met, ...(evidence ? { evidence } : {}) });
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** Full parser for a `spec` or `conformance` reply: trailer + table. */
|
|
121
|
+
export function parsePersonaVerdict(text) {
|
|
122
|
+
const base = parseVerifyVerdict(text);
|
|
123
|
+
return {
|
|
124
|
+
verdict: base.verdict,
|
|
125
|
+
findings: base.findings,
|
|
126
|
+
requirements: extractRequirementsBlock(text),
|
|
127
|
+
// Bennett's weakness = "how little the reviewer's free text asserts"
|
|
128
|
+
// (arXiv:2301.12987). `weaknessScoreFromText` is the weakness form
|
|
129
|
+
// (1.0 = maximally general / no claims; 0.0 = maximally specific).
|
|
130
|
+
// The verdict gate is the trailer; weakness is metadata surfaced in
|
|
131
|
+
// the workbench so a user can see whether a PASS was earned by a
|
|
132
|
+
// tightly-asserted or loosely-claimed reviewer.
|
|
133
|
+
weaknessScore: weaknessScoreFromText(text),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
61
136
|
/** Trim and cap findings text, marking the cut so a reader knows it happened. */
|
|
62
137
|
function capFindings(raw) {
|
|
63
138
|
const trimmed = raw.trim();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verdict.js","sourceRoot":"","sources":["../../src/kraken/verdict.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"verdict.js","sourceRoot":"","sources":["../../src/kraken/verdict.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kraken graph engine — weakness-based hypothesis ranking (Bennett 2023).
|
|
3
|
+
*
|
|
4
|
+
* "The Optimal Choice of Hypothesis Is the Weakest, Not the Shortest"
|
|
5
|
+
* Michael Timothy Bennett, AGI 2023 — arXiv:2301.12987v4.
|
|
6
|
+
*
|
|
7
|
+
* Bennett's formal result, restated for a coding-agent context:
|
|
8
|
+
*
|
|
9
|
+
* In a lattice of declarative programs, the **weakness** of a statement
|
|
10
|
+
* `l` is the cardinality of its extension `|Z_l|` — the number of
|
|
11
|
+
* statements `l` is a sub-statement of. For an unknown parent task
|
|
12
|
+
* `ω` of a known child `α`, the probability of a model `h ∈ M_α`
|
|
13
|
+
* generalising to `ω` is
|
|
14
|
+
*
|
|
15
|
+
* p(h ∈ M_ω | h ∈ M_α, α ⊏ ω) = 2^|Z_{S_α} ∩ Z_h| / 2^|Z_{S_α}|
|
|
16
|
+
*
|
|
17
|
+
* which is monotonically increasing in `|Z_h|`. The weakest sufficient
|
|
18
|
+
* hypothesis maximises the probability of generalisation — and in
|
|
19
|
+
* Bennett's experiments (binary 8-bit add / mult) weakness generalised
|
|
20
|
+
* at 1.1×–5× the rate of MDL (Occam's Razor as length).
|
|
21
|
+
*
|
|
22
|
+
* "Explanations should be no more specific than necessary."
|
|
23
|
+
* — Bennett's Razor
|
|
24
|
+
*
|
|
25
|
+
* For a natural-language plan we can't compute `|Z_h|` exactly. This
|
|
26
|
+
* module provides three usable approximations, cheapest first:
|
|
27
|
+
*
|
|
28
|
+
* 1. `weaknessFromVerdict(text)` — heuristic string scan for
|
|
29
|
+
* "specificity markers" (e.g. "exactly", "must", "always",
|
|
30
|
+
* "guaranteed", "line N"). Catches gross over-claiming, free.
|
|
31
|
+
* 2. `measureSpecificity(text)` — caller-agnostic shape of an LLM
|
|
32
|
+
* meter prompt; the CLI uses {@link WEAKNESS_METER_PROMPT} plus a
|
|
33
|
+
* model call to get a principled specificity score.
|
|
34
|
+
* 3. `extensionSize` (if a caller computes it themselves) — feeds
|
|
35
|
+
* `rankByWeakness` directly.
|
|
36
|
+
*
|
|
37
|
+
* `rankByWeakness(candidates)` is the single ranking entry point; it
|
|
38
|
+
* combines the three into a normalised weakness score in `[0, 1]`.
|
|
39
|
+
*
|
|
40
|
+
* No CLI dependencies (see CORREZIONE-1 in the engine plan).
|
|
41
|
+
*
|
|
42
|
+
* @since v1.31.x — weakness-based hypothesis selection
|
|
43
|
+
*/
|
|
44
|
+
import { z } from 'zod';
|
|
45
|
+
/**
|
|
46
|
+
* Bennett's Razor in one sentence, suitable for inclusion in system prompts.
|
|
47
|
+
*
|
|
48
|
+
* "Explanations should be no more specific than necessary." — Bennett 2023.
|
|
49
|
+
*
|
|
50
|
+
* The expanded form below spells out the operational meaning: when two
|
|
51
|
+
* solutions both satisfy a task, prefer the one that makes fewer specific
|
|
52
|
+
* claims about the world. It is deliberately phrased as a *tie-breaker*,
|
|
53
|
+
* not a goal in itself — a plan that is too weak to act on is still useless.
|
|
54
|
+
*/
|
|
55
|
+
export declare const BENNETTS_RAZOR: string;
|
|
56
|
+
/**
|
|
57
|
+
* Short form — a single sentence, for inclusion in compact prompts.
|
|
58
|
+
*/
|
|
59
|
+
export declare const BENNETTS_RAZOR_SHORT = "Prefer the solution that is no more specific than necessary.";
|
|
60
|
+
/**
|
|
61
|
+
* Compute a heuristic `specificity` score in `[0, 1]` for `text`.
|
|
62
|
+
*
|
|
63
|
+
* Returns `0` for an empty / whitespace-only string (a maximally weak claim).
|
|
64
|
+
* A score of `1` means "highly specific — many marker hits and/or many
|
|
65
|
+
* clauses"; a score of `0` means "no specificity signals at all".
|
|
66
|
+
*/
|
|
67
|
+
export declare function weaknessFromVerdict(text: string | undefined | null): number;
|
|
68
|
+
/**
|
|
69
|
+
* Weakness = `1 - specificity`, in `[0, 1]`. The default tie-breaker
|
|
70
|
+
* when no `extensionSize` or LLM meter is available.
|
|
71
|
+
*/
|
|
72
|
+
export declare function weaknessScoreFromText(text: string | undefined | null): number;
|
|
73
|
+
/**
|
|
74
|
+
* The meter prompt. A caller wraps this with their own model invocation
|
|
75
|
+
* (see `src/cli/kraken/weaknessMeter.ts`) and parses the JSON response.
|
|
76
|
+
*
|
|
77
|
+
* Kept as a string here (not a function) so it can be snapshotted in
|
|
78
|
+
* tests and re-used across providers without re-importing the CLI.
|
|
79
|
+
*/
|
|
80
|
+
export declare const WEAKNESS_METER_PROMPT = "You are measuring the SPECIFICITY of a candidate solution to a software task.\n\nSpecificity means: how many specific commitments does this solution make that a more general plan would not have to make? Examples of specific commitments: exact file paths, exact line numbers, exact semver versions, exact function signatures, guarantees about runtime behaviour, assertions about what other agents/users will do.\n\nA maximally general solution is one that asserts nothing beyond the task itself (\"just do the task\"). A maximally specific solution is one that pins every possible value, path, and invariant.\n\nOutput ONLY a JSON object of the form:\n{\"specificity\": <float in [0,1]>, \"assumptions\": [<short string>, ...]}\n\nwhere\n- specificity = 0.0 \u2192 solution asserts nothing beyond the task\n- specificity = 1.0 \u2192 solution pins every value, path, version, and invariant\n- assumptions = the list of specific commitments you identified, each \u2264 12 words, deduped, sorted by strength (most specific first). Cap the list at 12.\n\nDo not add prose, do not add a code fence, do not explain your reasoning. JSON only.";
|
|
81
|
+
/**
|
|
82
|
+
* Zod schema for the meter response. Use this in the CLI to parse the
|
|
83
|
+
* model's output — gives type safety + a clear error path for malformed
|
|
84
|
+
* JSON, which is the most common failure mode of meter calls.
|
|
85
|
+
*/
|
|
86
|
+
export declare const WeaknessMeterResponseSchema: z.ZodObject<{
|
|
87
|
+
specificity: z.ZodNumber;
|
|
88
|
+
assumptions: z.ZodArray<z.ZodString>;
|
|
89
|
+
}, z.core.$strip>;
|
|
90
|
+
export type WeaknessMeterResponse = z.infer<typeof WeaknessMeterResponseSchema>;
|
|
91
|
+
/**
|
|
92
|
+
* Convenience: turn a meter response into a weakness score in `[0, 1]`.
|
|
93
|
+
* Pure: no I/O. The meter itself is the only thing that costs.
|
|
94
|
+
*/
|
|
95
|
+
export declare function weaknessFromMeter(meter: WeaknessMeterResponse): number;
|
|
96
|
+
/**
|
|
97
|
+
* Convenience: turn an `assumptions` list (from a meter response) into a
|
|
98
|
+
* heuristic *specificity* score. Used as a fallback when the meter returns
|
|
99
|
+
* a `specificity` outside `[0,1]` or one of the JSON fields is missing
|
|
100
|
+
* after parsing. Each assumption is treated as one specificity hit.
|
|
101
|
+
*/
|
|
102
|
+
export declare function specificityFromAssumptions(assumptions: readonly string[]): number;
|
|
103
|
+
/**
|
|
104
|
+
* A hypothesis / plan / skill candidate. At least one of the weakness
|
|
105
|
+
* signals should be populated; `rankByWeakness` will use the strongest
|
|
106
|
+
* signal available.
|
|
107
|
+
*/
|
|
108
|
+
export interface HypothesisCandidate {
|
|
109
|
+
/** Stable id (writer node id, skill name, plan hash, …). */
|
|
110
|
+
id: string;
|
|
111
|
+
/** The text we may scan heuristically if no other signal is set. */
|
|
112
|
+
text?: string;
|
|
113
|
+
/**
|
|
114
|
+
* Optional: caller's pre-computed extension size `|Z_h|`. When set,
|
|
115
|
+
* overrides everything else. Use this if you have a real lattice
|
|
116
|
+
* representation (Kraken's Spec Council does not, today).
|
|
117
|
+
*/
|
|
118
|
+
extensionSize?: number;
|
|
119
|
+
/**
|
|
120
|
+
* Optional: result of {@link WeaknessMeterResponseSchema}.parsed.
|
|
121
|
+
* Overrides the heuristic scan.
|
|
122
|
+
*/
|
|
123
|
+
meter?: WeaknessMeterResponse;
|
|
124
|
+
}
|
|
125
|
+
/** A candidate plus the score it received. */
|
|
126
|
+
export interface RankedHypothesis<T extends HypothesisCandidate = HypothesisCandidate> {
|
|
127
|
+
candidate: T;
|
|
128
|
+
/** Normalised weakness score in `[0, 1]`. Higher = weaker = more general. */
|
|
129
|
+
weaknessScore: number;
|
|
130
|
+
/** 1-based rank, weakest first. Ties get the same rank. */
|
|
131
|
+
rank: number;
|
|
132
|
+
/** Which signal drove the score (for debugging / auditing). */
|
|
133
|
+
source: 'extensionSize' | 'meter' | 'heuristic';
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Rank candidates by weakness, weakest first. Stable: equal scores keep
|
|
137
|
+
* input order. The function is pure and synchronous; no LLM, no I/O.
|
|
138
|
+
*
|
|
139
|
+
* Strategy per candidate:
|
|
140
|
+
* 1. `extensionSize` (raw count) → normalised across the candidate set
|
|
141
|
+
* to `[0, 1]` by dividing by the max within the set.
|
|
142
|
+
* 2. `meter.specificity` → `1 - specificity` if present and valid.
|
|
143
|
+
* 3. `weaknessScoreFromText(candidate.text)` → heuristic.
|
|
144
|
+
* 4. `0` if nothing is set (the candidate is "as general as the empty claim").
|
|
145
|
+
*/
|
|
146
|
+
export declare function rankByWeakness<T extends HypothesisCandidate>(candidates: readonly T[]): RankedHypothesis<T>[];
|
|
147
|
+
/**
|
|
148
|
+
* Pick the weakest candidate (rank 1) from a list. Convenience for the
|
|
149
|
+
* Spec Council's "all PASS, pick one" branch. Returns `undefined` if the
|
|
150
|
+
* input is empty.
|
|
151
|
+
*/
|
|
152
|
+
export declare function pickWeakest<T extends HypothesisCandidate>(candidates: readonly T[]): T | undefined;
|
|
153
|
+
/**
|
|
154
|
+
* Filter candidates to those with weakness ≥ `threshold` (in `[0, 1]`).
|
|
155
|
+
* Useful for "among all PASS solutions, keep only the ones that are
|
|
156
|
+
* *enough* general" — e.g. drop a solution whose heuristic scan flags
|
|
157
|
+
* ≥ 4 specific markers.
|
|
158
|
+
*/
|
|
159
|
+
export declare function filterByWeakness<T extends HypothesisCandidate>(candidates: readonly T[], threshold: number): T[];
|
|
160
|
+
//# sourceMappingURL=weakness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"weakness.d.ts","sourceRoot":"","sources":["../../src/kraken/weakness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAMxB;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,QAMhB,CAAC;AAEZ;;GAEG;AACH,eAAO,MAAM,oBAAoB,iEAC+B,CAAC;AAkDjE;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAmB3E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAE7E;AAMD;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,snCAcmD,CAAC;AAEtF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B;;;iBAGtC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,qBAAqB,GAAG,MAAM,CAEtE;AAED;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAOjF;AAMD;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,4DAA4D;IAC5D,EAAE,EAAE,MAAM,CAAC;IACX,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,KAAK,CAAC,EAAE,qBAAqB,CAAC;CAC/B;AAED,8CAA8C;AAC9C,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,mBAAmB,GAAG,mBAAmB;IACnF,SAAS,EAAE,CAAC,CAAC;IACb,6EAA6E;IAC7E,aAAa,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,MAAM,EAAE,eAAe,GAAG,OAAO,GAAG,WAAW,CAAC;CACjD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,mBAAmB,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,GAAG,gBAAgB,CAAC,CAAC,CAAC,EAAE,CA+D7G;AAyBD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,mBAAmB,EAAE,UAAU,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,GAAG,SAAS,CAGlG;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,mBAAmB,EAC5D,UAAU,EAAE,SAAS,CAAC,EAAE,EACxB,SAAS,EAAE,MAAM,GAChB,CAAC,EAAE,CAGL"}
|