@tangle-network/agent-runtime 0.36.0 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/agent.d.ts +3 -3
  2. package/dist/analyst-loop.d.ts +2 -2
  3. package/dist/analyst-loop.js +3 -257
  4. package/dist/analyst-loop.js.map +1 -1
  5. package/dist/{chunk-NYGEI3NV.js → chunk-M65QJD35.js} +5 -211
  6. package/dist/chunk-M65QJD35.js.map +1 -0
  7. package/dist/{chunk-HSX6PFZR.js → chunk-V6GURW4W.js} +209 -1
  8. package/dist/chunk-V6GURW4W.js.map +1 -0
  9. package/dist/chunk-VOX6Z3II.js +90 -0
  10. package/dist/chunk-VOX6Z3II.js.map +1 -0
  11. package/dist/chunk-XBUG326M.js +261 -0
  12. package/dist/chunk-XBUG326M.js.map +1 -0
  13. package/dist/{chunk-7ZECSZ3C.js → chunk-Z523NPJK.js} +59 -2
  14. package/dist/chunk-Z523NPJK.js.map +1 -0
  15. package/dist/dynamic-DeOPeeAw.d.ts +106 -0
  16. package/dist/{improvement-adapter-CaZxFxTd.d.ts → improvement-adapter-BC4HhuAR.d.ts} +1 -1
  17. package/dist/improvement.d.ts +6 -130
  18. package/dist/improvement.js +4 -85
  19. package/dist/improvement.js.map +1 -1
  20. package/dist/index.d.ts +148 -3
  21. package/dist/index.js +109 -2
  22. package/dist/index.js.map +1 -1
  23. package/dist/loops.d.ts +5 -107
  24. package/dist/mcp/bin.js +4 -3
  25. package/dist/mcp/bin.js.map +1 -1
  26. package/dist/mcp/index.d.ts +6 -440
  27. package/dist/mcp/index.js +7 -62
  28. package/dist/mcp/index.js.map +1 -1
  29. package/dist/optimize-prompt-cmH9wZdH.d.ts +129 -0
  30. package/dist/otel-export-CNmeg_7B.d.ts +627 -0
  31. package/dist/profiles.d.ts +1 -2
  32. package/dist/{types-DrXVR2Fu.d.ts → types-CmkQl8qE.d.ts} +137 -3
  33. package/dist/{types-D_MXrmJP.d.ts → types-p8dWBIXL.d.ts} +1 -1
  34. package/package.json +1 -1
  35. package/dist/chunk-7ZECSZ3C.js.map +0 -1
  36. package/dist/chunk-HSX6PFZR.js.map +0 -1
  37. package/dist/chunk-NYGEI3NV.js.map +0 -1
  38. package/dist/otel-export-xgf4J6bo.d.ts +0 -191
  39. package/dist/runtime-run-B8VIiOhI.d.ts +0 -137
@@ -1,100 +1,14 @@
1
- import { L as LoopSandboxClient, j as LoopSandboxPlacement, m as LoopTraceEmitter } from '../types-DrXVR2Fu.js';
2
- import { SandboxInstance } from '@tangle-network/sandbox';
3
- import { CoderOutput, CoderTask } from '../profiles.js';
1
+ import { L as LoopSandboxClient, j as LoopSandboxPlacement, m as LoopTraceEmitter } from '../types-CmkQl8qE.js';
2
+ import { F as FleetHandle, D as DelegationExecutor, a as DelegateFeedbackArgs, b as DelegationFeedbackSnapshot, c as DelegationProfile, d as DelegateCodeArgs, e as DelegateResearchArgs, f as DelegationStatus, g as DelegationProgress, h as DelegationResultPayload, i as DelegationError, j as DelegationStatusResult, k as DelegationHistoryArgs, l as DelegationHistoryEntry, C as CoderDelegate, R as ResearcherDelegate, m as DelegateCodeResult, n as DelegateFeedbackResult, o as ResearchSource, p as DelegateResearchResult, q as DelegationHistoryResult, r as DelegationStatusArgs, O as OtelExporter } from '../otel-export-CNmeg_7B.js';
3
+ export { s as CoderReview, t as CoderReviewer, u as CoderWinnerSelection, v as CreateDefaultCoderDelegateOptions, w as CreateKbGateOptions, x as DelegateCodeConfig, y as DelegateResearchConfig, z as DelegateRunCtx, A as FactCandidate, B as FactJudge, E as FactJudgeVerdict, G as FeedbackRating, H as FeedbackRefersTo, I as FleetWorkspaceExecutorOptions, K as KbGateResult, J as ResearchOutputShape, S as SiblingSandboxExecutorOptions, L as createDefaultCoderDelegate, M as createFleetWorkspaceExecutor, N as createKbGate, P as createSiblingSandboxExecutor, Q as mcpToolsForRuntimeMcp, T as mcpToolsForRuntimeMcpSubset } from '../otel-export-CNmeg_7B.js';
4
4
  import { L as LocalHarness, r as runLocalHarness } from '../local-harness-KrdFTY5R.js';
5
5
  export { a as LocalHarnessResult, R as RunLocalHarnessOptions } from '../local-harness-KrdFTY5R.js';
6
- import { O as OtelExporter } from '../otel-export-xgf4J6bo.js';
7
- export { m as mcpToolsForRuntimeMcp, a as mcpToolsForRuntimeMcpSubset } from '../otel-export-xgf4J6bo.js';
8
6
  import '@tangle-network/agent-eval';
9
- import '../runtime-run-B8VIiOhI.js';
7
+ import '@tangle-network/sandbox';
10
8
  import '../types-CsCCryln.js';
9
+ import '../profiles.js';
11
10
  import 'node:child_process';
12
11
 
13
- /**
14
- * @experimental
15
- *
16
- * Delegation executors — the layer between MCP delegates and the sandbox
17
- * substrate. Each executor exposes a {@link LoopSandboxClient} the kernel
18
- * consumes plus a placement tag so the trace pipeline can correlate workers
19
- * with their physical placement.
20
- *
21
- * Two implementations ship in-box:
22
- *
23
- * - {@link createSiblingSandboxExecutor} — every delegation spawns a fresh
24
- * sandbox sibling to the caller. Default when the MCP server runs as a
25
- * standalone CLI mounted outside a fleet.
26
- *
27
- * - {@link createFleetWorkspaceExecutor} — delegations dispatch onto machines
28
- * in the caller's existing fleet so worker diffs land directly on the
29
- * caller's filesystem (the fleet's shared workspace). Selected when the
30
- * parent sandbox passes `TANGLE_FLEET_ID` into the MCP server's env.
31
- */
32
-
33
- /** @experimental */
34
- interface DelegationExecutor {
35
- /** Sandbox client the kernel calls. Returned with `describePlacement` set. */
36
- readonly client: LoopSandboxClient;
37
- /** Best-effort one-liner used in stderr boot logs and diagnostics. */
38
- describe(): string;
39
- }
40
- /** @experimental */
41
- interface SiblingSandboxExecutorOptions {
42
- client: LoopSandboxClient;
43
- }
44
- /**
45
- * Wrap a raw sandbox SDK client so the kernel emits
46
- * `loop.iteration.dispatch` events with `{ placement: 'sibling', sandboxId }`.
47
- *
48
- * The returned client `.create()` delegates to the underlying client; the
49
- * only added behavior is a `describePlacement` tag the kernel reads.
50
- *
51
- * @experimental
52
- */
53
- declare function createSiblingSandboxExecutor(options: SiblingSandboxExecutorOptions): DelegationExecutor;
54
- /**
55
- * Minimal `SandboxFleet` surface the fleet executor calls. Declared
56
- * structurally so tests can pass an in-memory stub without instantiating the
57
- * sandbox SDK.
58
- *
59
- * @experimental
60
- */
61
- interface FleetHandle {
62
- readonly fleetId: string;
63
- /** Machine ids in dispatch-eligible order. The executor round-robins. */
64
- readonly ids: ReadonlyArray<string>;
65
- /** Resolve a machine id to its `SandboxInstance` — that machine is mounted
66
- * on the fleet's shared workspace, so any diff the worker writes lands on
67
- * every other fleet machine's filesystem too. */
68
- sandbox(machineId: string): Promise<SandboxInstance>;
69
- }
70
- /** @experimental */
71
- interface FleetWorkspaceExecutorOptions {
72
- fleet: FleetHandle;
73
- /**
74
- * Override the machine-selection policy. Default = round-robin across
75
- * `fleet.ids`, skipping the optional `excludeMachineIds` set (typically the
76
- * coordinator machine the MCP server is running on).
77
- */
78
- selectMachine?: (call: {
79
- callIndex: number;
80
- ids: ReadonlyArray<string>;
81
- }) => string;
82
- /**
83
- * Machine ids to skip during default round-robin. Set to the caller's own
84
- * machineId so workers don't compete with the orchestrator on the same VM.
85
- */
86
- excludeMachineIds?: ReadonlyArray<string>;
87
- }
88
- /**
89
- * Build an executor that resolves each delegated iteration to an existing
90
- * machine in `fleet`. The fleet's shared-workspace policy means the worker
91
- * machine sees the caller's filesystem — diffs land in-place with no
92
- * cross-sandbox copy step.
93
- *
94
- * @experimental
95
- */
96
- declare function createFleetWorkspaceExecutor(options: FleetWorkspaceExecutorOptions): DelegationExecutor;
97
-
98
12
  /**
99
13
  * @experimental
100
14
  *
@@ -131,279 +45,6 @@ interface DetectExecutorArgs {
131
45
  */
132
46
  declare function detectExecutor(args: DetectExecutorArgs): Promise<DelegationExecutor>;
133
47
 
134
- /**
135
- * @experimental
136
- *
137
- * MCP delegation tool surface — the typed inputs/outputs the product agent
138
- * sees over the wire. These types are the contract; the JSON schemas under
139
- * `tools/*` mirror them for the MCP `tools/list` advertisement.
140
- *
141
- * Async semantics: `delegate_code` + `delegate_research` return a `taskId`
142
- * immediately. The product agent polls `delegation_status` until the task
143
- * transitions to `completed` | `failed` | `cancelled`. `delegate_feedback`
144
- * + `delegation_history` are synchronous reads / writes against the local
145
- * task queue + feedback store.
146
- */
147
-
148
- /** @experimental */
149
- type DelegationProfile = 'coder' | 'researcher';
150
- /** @experimental */
151
- type DelegationStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
152
- /**
153
- * Minimal `CoderTask` overrides exposed over the MCP wire. The full
154
- * `CoderTask` carries fields the kernel synthesizes from `goal` +
155
- * `repoRoot` — the agent only edits the few that materially gate
156
- * validator behavior.
157
- *
158
- * @experimental
159
- */
160
- interface DelegateCodeConfig {
161
- testCmd?: string;
162
- typecheckCmd?: string;
163
- forbiddenPaths?: string[];
164
- maxDiffLines?: number;
165
- }
166
- /** @experimental */
167
- interface DelegateCodeArgs {
168
- /** Natural-language description of what the coder must accomplish. */
169
- goal: string;
170
- /** Absolute path inside the sandbox where the repo lives. */
171
- repoRoot: string;
172
- /** Optional free-form context the agent surfaces in the prompt prelude. */
173
- contextHint?: string;
174
- /**
175
- * When > 1, dispatches `multiHarnessCoderFanout` across N harnesses
176
- * (claude-code, codex, opencode-glm) and picks the highest-scoring
177
- * passing patch. Default 1.
178
- */
179
- variants?: number;
180
- /** Validator + prompt overrides the agent knows for this repo. */
181
- config?: DelegateCodeConfig;
182
- /** Multi-tenant scope (customer-id, workspace-id). */
183
- namespace?: string;
184
- }
185
- /** @experimental */
186
- interface DelegateCodeResult {
187
- taskId: string;
188
- /** Best-effort hint — coder loops can take minutes-to-hours. */
189
- estimatedDurationMs?: number;
190
- }
191
- /** @experimental */
192
- type ResearchSource = 'web' | 'corpus' | 'twitter' | 'github' | 'docs';
193
- /** @experimental */
194
- interface DelegateResearchConfig {
195
- recencyWindow?: {
196
- since?: string;
197
- until?: string;
198
- };
199
- maxItems?: number;
200
- minConfidence?: number;
201
- }
202
- /** @experimental */
203
- interface DelegateResearchArgs {
204
- question: string;
205
- namespace: string;
206
- scope?: string;
207
- sources?: ResearchSource[];
208
- variants?: number;
209
- config?: DelegateResearchConfig;
210
- }
211
- /** @experimental */
212
- interface DelegateResearchResult {
213
- taskId: string;
214
- estimatedDurationMs?: number;
215
- }
216
- /** @experimental */
217
- interface FeedbackRefersTo {
218
- kind: 'delegation' | 'artifact' | 'outcome';
219
- /** For `'delegation'`, this is the taskId. */
220
- ref: string;
221
- }
222
- /** @experimental */
223
- interface FeedbackRating {
224
- /** [0, 1]. */
225
- score: number;
226
- label?: 'good' | 'bad' | 'neutral' | 'mixed';
227
- notes: string;
228
- }
229
- /** @experimental */
230
- interface DelegateFeedbackArgs {
231
- refersTo: FeedbackRefersTo;
232
- rating: FeedbackRating;
233
- by: 'agent' | 'user' | 'downstream-judge';
234
- /** ISO timestamp; defaults to server clock when omitted. */
235
- capturedAt?: string;
236
- namespace?: string;
237
- }
238
- /** @experimental */
239
- interface DelegateFeedbackResult {
240
- recorded: true;
241
- id: string;
242
- }
243
- /** @experimental */
244
- interface DelegationStatusArgs {
245
- taskId: string;
246
- }
247
- /** @experimental */
248
- interface DelegationProgress {
249
- iteration: number;
250
- phase: string;
251
- }
252
- /** @experimental */
253
- interface DelegationError {
254
- message: string;
255
- kind: string;
256
- }
257
- /**
258
- * Polymorphic `result` field: `CoderOutput` when the underlying profile
259
- * is `'coder'`, a structurally-typed research output when `'researcher'`.
260
- * The MCP wire carries it as JSON either way.
261
- *
262
- * @experimental
263
- */
264
- type DelegationResultPayload = {
265
- profile: 'coder';
266
- output: CoderOutput;
267
- } | {
268
- profile: 'researcher';
269
- output: ResearchOutputShape;
270
- };
271
- /**
272
- * Loose shape of a research output over the wire — the substrate cannot
273
- * import the `ResearchOutput` type from agent-knowledge without inducing
274
- * a dependency cycle, so the MCP layer treats it structurally.
275
- *
276
- * @experimental
277
- */
278
- interface ResearchOutputShape {
279
- items: unknown[];
280
- citations: unknown[];
281
- proposedWrites: unknown[];
282
- gaps?: string[];
283
- notes?: string;
284
- [key: string]: unknown;
285
- }
286
- /** @experimental */
287
- interface DelegationStatusResult {
288
- taskId: string;
289
- profile: DelegationProfile;
290
- status: DelegationStatus;
291
- progress?: DelegationProgress;
292
- result?: DelegationResultPayload;
293
- error?: DelegationError;
294
- costUsd?: number;
295
- startedAt: string;
296
- completedAt?: string;
297
- }
298
- /** @experimental */
299
- interface DelegationHistoryArgs {
300
- namespace?: string;
301
- profile?: DelegationProfile;
302
- /** ISO date — only delegations started at-or-after `since` are returned. */
303
- since?: string;
304
- /** Default 50. Hard cap 500. */
305
- limit?: number;
306
- }
307
- /** @experimental */
308
- interface DelegationFeedbackSnapshot {
309
- id: string;
310
- score: number;
311
- label?: FeedbackRating['label'];
312
- by: DelegateFeedbackArgs['by'];
313
- notes: string;
314
- capturedAt: string;
315
- }
316
- /** @experimental */
317
- interface DelegationHistoryEntry {
318
- taskId: string;
319
- profile: DelegationProfile;
320
- namespace?: string;
321
- args: DelegateCodeArgs | DelegateResearchArgs;
322
- status: DelegationStatus;
323
- feedback?: DelegationFeedbackSnapshot[];
324
- costUsd?: number;
325
- startedAt: string;
326
- completedAt?: string;
327
- }
328
- /** @experimental */
329
- interface DelegationHistoryResult {
330
- delegations: DelegationHistoryEntry[];
331
- }
332
-
333
- /** @experimental */
334
- interface DelegateRunCtx {
335
- signal: AbortSignal;
336
- report(progress: DelegationProgress): void;
337
- }
338
- /** @experimental */
339
- type CoderDelegate = (args: DelegateCodeArgs, ctx: DelegateRunCtx) => Promise<CoderOutput>;
340
- /** @experimental */
341
- type ResearcherDelegate = (args: DelegateResearchArgs, ctx: DelegateRunCtx) => Promise<ResearchOutputShape>;
342
- /** @experimental Structured review verdict over a coder candidate. */
343
- interface CoderReview {
344
- /** Gate: only approved candidates are eligible to win. */
345
- approved: boolean;
346
- /** Reviewer's recommendation — surfaced in traces. */
347
- recommendation: 'ship' | 'approve-with-nits' | 'changes-requested' | 'reject';
348
- /** Readiness 0..1, used by the `highest-readiness` winner-selection strategy. */
349
- readiness: number;
350
- notes?: string;
351
- }
352
- /**
353
- * @experimental
354
- *
355
- * Optional adversarial reviewer over a coder candidate that already passed
356
- * mechanical validation (tests/typecheck/forbidden/diff/no-op/secrets). Folded
357
- * from the ai-trading-blueprint delegation MCP: a candidate is only eligible to
358
- * win if the reviewer approves it. The reviewer is the consumer's seam — an LLM
359
- * judge, a `pnpm review` command, anything returning a `CoderReview`.
360
- */
361
- type CoderReviewer = (output: CoderOutput, task: CoderTask, ctx: {
362
- signal: AbortSignal;
363
- }) => Promise<CoderReview> | CoderReview;
364
- /**
365
- * @experimental Winner-selection strategy among validated (+ reviewed)
366
- * candidates. `highest-readiness` requires a `reviewer`. Default `highest-score`
367
- * (the kernel's behavior — preserves backward compatibility).
368
- */
369
- type CoderWinnerSelection = 'highest-score' | 'smallest-diff' | 'highest-readiness' | 'first-approved';
370
- /** @experimental */
371
- interface CreateDefaultCoderDelegateOptions {
372
- /**
373
- * Execution placement. Pass a {@link DelegationExecutor} (sibling or fleet)
374
- * to control where worker iterations land. `sandboxClient` is a
375
- * convenience shorthand that wraps the client in a sibling executor — pass
376
- * one or the other, not both.
377
- */
378
- executor?: DelegationExecutor;
379
- /**
380
- * Convenience shorthand for sibling placement. Equivalent to
381
- * `executor: createSiblingSandboxExecutor({ client: sandboxClient })`.
382
- */
383
- sandboxClient?: LoopSandboxClient;
384
- /** Default `['claude-code', 'codex', 'opencode/zai-coding-plan/glm-5.1']` when variants > 1. */
385
- fanoutHarnesses?: string[];
386
- /** Hard cap on the kernel's per-batch concurrency. Default 4. */
387
- maxConcurrency?: number;
388
- /**
389
- * Optional adversarial reviewer. When set, a candidate must pass mechanical
390
- * validation AND `reviewer.approved` to be eligible to win — empty/secret/
391
- * test-failing patches are already gone; this catches the "compiles + passes
392
- * but wrong/unsafe" class the deterministic validator can't see.
393
- */
394
- reviewer?: CoderReviewer;
395
- /** Winner-selection strategy among eligible candidates. Default `highest-score`. */
396
- winnerSelection?: CoderWinnerSelection;
397
- }
398
- /**
399
- * Build a coder delegate that drives `runLoop` against the project's
400
- * sandbox client + coder profile. When `args.variants > 1` it switches
401
- * to the multi-harness fanout topology.
402
- *
403
- * @experimental
404
- */
405
- declare function createDefaultCoderDelegate(options: CreateDefaultCoderDelegateOptions): CoderDelegate;
406
-
407
48
  /**
408
49
  * @experimental
409
50
  *
@@ -644,81 +285,6 @@ interface InProcessExecutorDescribePlacement extends LoopSandboxPlacement {
644
285
  */
645
286
  declare function createInProcessExecutor(options: InProcessExecutorOptions): DelegationExecutor;
646
287
 
647
- /**
648
- * @experimental
649
- *
650
- * `createKbGate` — the valid-only knowledge-base growth gate, distilled from
651
- * physim's KB-research subsystem. A research-in-a-loop delegate (or any KB
652
- * writer) runs candidate facts through this before persisting, so the KB grows
653
- * with ONLY grounded facts — hallucinated, unsourced, or laundered claims are
654
- * vetoed at the gate.
655
- *
656
- * Fail-closed by construction: every judge must `accept`; the FIRST veto wins
657
- * and the fact is rejected. The non-negotiable floor (always on, can't be
658
- * disabled) is the **passage-present guard** — a fact's `verbatimPassage` MUST
659
- * literally appear in its `sourceText`. That single check kills the dominant
660
- * failure mode (a confident claim decoupled from any real source).
661
- *
662
- * Pure + dependency-free: it operates on fact candidates, not on a store, so it
663
- * composes with `@tangle-network/agent-knowledge` or any persistence layer
664
- * without importing it. The remediation policy (correct-on-veto vs
665
- * escalate-as-unverified) is the caller's — this returns the verdict; it never
666
- * drops a fact silently.
667
- */
668
- /** @experimental A fact proposed for the KB, with its grounding. */
669
- interface FactCandidate {
670
- /** The atomic claim text. */
671
- claim: string;
672
- /** Optional extracted value (number or string) the claim asserts. */
673
- value?: string | number;
674
- /** Verbatim span lifted from the source that backs the claim. */
675
- verbatimPassage: string;
676
- /** The raw source text the passage must be grounded in. */
677
- sourceText: string;
678
- /** Where the fact claims to come from — checked for circular/self citations. */
679
- citation?: string;
680
- }
681
- /** @experimental */
682
- interface FactJudgeVerdict {
683
- accept: boolean;
684
- reason?: string;
685
- }
686
- /** @experimental A pluggable fact validator. Throw is NOT allowed — return a
687
- * verdict; a thrown judge is a programmer error, not a veto. */
688
- interface FactJudge {
689
- name: string;
690
- judge(candidate: FactCandidate): FactJudgeVerdict | Promise<FactJudgeVerdict>;
691
- }
692
- /** @experimental */
693
- interface KbGateResult {
694
- accepted: boolean;
695
- /** Name of the judge that vetoed; undefined when accepted. */
696
- vetoedBy?: string;
697
- reason?: string;
698
- }
699
- /** @experimental */
700
- interface CreateKbGateOptions {
701
- /** Extra judges appended after the built-in floor (e.g. an LLM judge). */
702
- judges?: FactJudge[];
703
- /** Minimum verbatim-passage length. Default 12 — kills empty/stub passages. */
704
- minPassageChars?: number;
705
- /**
706
- * Citation tokens that denote a SELF-generated artifact (e.g. `'spec'`,
707
- * `'cad_params'`, `'requirements'`). A citation naming one is circular
708
- * (laundering) — the fact cites a derived artifact, not a real source.
709
- * Default `[]` (no circular check unless the consumer declares its kinds).
710
- */
711
- selfArtifactKinds?: string[];
712
- }
713
- /**
714
- * @experimental
715
- *
716
- * Build a fail-closed KB gate. The returned function runs the built-in floor
717
- * (passage-non-empty → passage-present → value-in-passage → no-circular-citation)
718
- * then any consumer judges, returning on the first veto.
719
- */
720
- declare function createKbGate(options?: CreateKbGateOptions): (candidate: FactCandidate) => Promise<KbGateResult>;
721
-
722
288
  /**
723
289
  * @experimental
724
290
  *
@@ -1306,4 +872,4 @@ declare function createPropagatingTraceEmitter(ctx: TraceContext): {
1306
872
  */
1307
873
  declare function traceContextToEnv(ctx: TraceContext): Record<string, string>;
1308
874
 
1309
- export { type CoderDelegate, type CoderReview, type CoderReviewer, type CoderWinnerSelection, type CreateDefaultCoderDelegateOptions, type CreateKbGateOptions, type CreateWorktreeOptions, DELEGATE_CODE_DESCRIPTION, DELEGATE_CODE_INPUT_SCHEMA, DELEGATE_CODE_TOOL_NAME, DELEGATE_FEEDBACK_DESCRIPTION, DELEGATE_FEEDBACK_INPUT_SCHEMA, DELEGATE_FEEDBACK_TOOL_NAME, DELEGATE_RESEARCH_DESCRIPTION, DELEGATE_RESEARCH_INPUT_SCHEMA, DELEGATE_RESEARCH_TOOL_NAME, DELEGATION_HISTORY_DESCRIPTION, DELEGATION_HISTORY_INPUT_SCHEMA, DELEGATION_HISTORY_TOOL_NAME, DELEGATION_STATUS_DESCRIPTION, DELEGATION_STATUS_INPUT_SCHEMA, DELEGATION_STATUS_TOOL_NAME, type DelegateCodeArgs, type DelegateCodeConfig, type DelegateCodeResult, type DelegateFeedbackArgs, type DelegateFeedbackResult, type DelegateResearchArgs, type DelegateResearchConfig, type DelegateResearchResult, type DelegateRunCtx, type DelegationError, type DelegationExecutor, type DelegationFeedbackSnapshot, type DelegationHistoryArgs, type DelegationHistoryEntry, type DelegationHistoryResult, type DelegationProfile, type DelegationProgress, type DelegationRecord, type DelegationResultPayload, type DelegationStatus, type DelegationStatusArgs, type DelegationStatusResult, DelegationTaskQueue, type DelegationTaskQueueOptions, type DetectExecutorArgs, type DiffOptions, type DiffResult, type FactCandidate, type FactJudge, type FactJudgeVerdict, type FeedbackEvent, type FeedbackRating, type FeedbackRefersTo, type FeedbackStore, type FleetHandle, type FleetWorkspaceExecutorOptions, type GitRunner, InMemoryFeedbackStore, type InProcessExecutorDescribePlacement, type InProcessExecutorOptions, type JsonRpcMessage, type JsonRpcResponse, type KbGateResult, LocalHarness, type McpServer, type McpServerOptions, type McpToolDescriptor, type McpTransport, type RemoveWorktreeOptions, type ResearchOutputShape, type ResearchSource, type ResearcherDelegate, type SiblingSandboxExecutorOptions, type SubmitInput, type SubmitOutput, type TraceContext, type WorktreeHandle, captureWorktreeDiff, createDefaultCoderDelegate, createDelegateCodeHandler, createDelegateFeedbackHandler, createDelegateResearchHandler, createDelegationHistoryHandler, createDelegationStatusHandler, createFleetWorkspaceExecutor, createInProcessExecutor, createInProcessTransport, createKbGate, createMcpServer, createPropagatingTraceEmitter, createSiblingSandboxExecutor, createWorktree, detectExecutor, eventToSnapshot, hashIdempotencyInput, readTraceContextFromEnv, removeWorktree, runLocalHarness, traceContextToEnv, validateDelegateCodeArgs, validateDelegateFeedbackArgs, validateDelegateResearchArgs, validateDelegationHistoryArgs, validateDelegationStatusArgs };
875
+ export { CoderDelegate, type CreateWorktreeOptions, DELEGATE_CODE_DESCRIPTION, DELEGATE_CODE_INPUT_SCHEMA, DELEGATE_CODE_TOOL_NAME, DELEGATE_FEEDBACK_DESCRIPTION, DELEGATE_FEEDBACK_INPUT_SCHEMA, DELEGATE_FEEDBACK_TOOL_NAME, DELEGATE_RESEARCH_DESCRIPTION, DELEGATE_RESEARCH_INPUT_SCHEMA, DELEGATE_RESEARCH_TOOL_NAME, DELEGATION_HISTORY_DESCRIPTION, DELEGATION_HISTORY_INPUT_SCHEMA, DELEGATION_HISTORY_TOOL_NAME, DELEGATION_STATUS_DESCRIPTION, DELEGATION_STATUS_INPUT_SCHEMA, DELEGATION_STATUS_TOOL_NAME, DelegateCodeArgs, DelegateCodeResult, DelegateFeedbackArgs, DelegateFeedbackResult, DelegateResearchArgs, DelegateResearchResult, DelegationError, DelegationExecutor, DelegationFeedbackSnapshot, DelegationHistoryArgs, DelegationHistoryEntry, DelegationHistoryResult, DelegationProfile, DelegationProgress, type DelegationRecord, DelegationResultPayload, DelegationStatus, DelegationStatusArgs, DelegationStatusResult, DelegationTaskQueue, type DelegationTaskQueueOptions, type DetectExecutorArgs, type DiffOptions, type DiffResult, type FeedbackEvent, type FeedbackStore, FleetHandle, type GitRunner, InMemoryFeedbackStore, type InProcessExecutorDescribePlacement, type InProcessExecutorOptions, type JsonRpcMessage, type JsonRpcResponse, LocalHarness, type McpServer, type McpServerOptions, type McpToolDescriptor, type McpTransport, type RemoveWorktreeOptions, ResearchSource, ResearcherDelegate, type SubmitInput, type SubmitOutput, type TraceContext, type WorktreeHandle, captureWorktreeDiff, createDelegateCodeHandler, createDelegateFeedbackHandler, createDelegateResearchHandler, createDelegationHistoryHandler, createDelegationStatusHandler, createInProcessExecutor, createInProcessTransport, createMcpServer, createPropagatingTraceEmitter, createWorktree, detectExecutor, eventToSnapshot, hashIdempotencyInput, readTraceContextFromEnv, removeWorktree, runLocalHarness, traceContextToEnv, validateDelegateCodeArgs, validateDelegateFeedbackArgs, validateDelegateResearchArgs, validateDelegationHistoryArgs, validateDelegationStatusArgs };
package/dist/mcp/index.js CHANGED
@@ -1,21 +1,19 @@
1
1
  import {
2
2
  captureWorktreeDiff,
3
- createDefaultCoderDelegate,
4
- createFleetWorkspaceExecutor,
5
3
  createInProcessExecutor,
6
4
  createInProcessTransport,
7
5
  createMcpServer,
8
- createSiblingSandboxExecutor,
9
6
  createWorktree,
10
7
  detectExecutor,
11
8
  removeWorktree
12
- } from "../chunk-NYGEI3NV.js";
9
+ } from "../chunk-M65QJD35.js";
13
10
  import {
14
11
  buildLoopOtelSpans,
12
+ createKbGate,
15
13
  createOtelExporter,
16
14
  mcpToolsForRuntimeMcp,
17
15
  mcpToolsForRuntimeMcpSubset
18
- } from "../chunk-7ZECSZ3C.js";
16
+ } from "../chunk-Z523NPJK.js";
19
17
  import {
20
18
  DELEGATE_CODE_DESCRIPTION,
21
19
  DELEGATE_CODE_INPUT_SCHEMA,
@@ -34,11 +32,14 @@ import {
34
32
  DELEGATION_STATUS_TOOL_NAME,
35
33
  DelegationTaskQueue,
36
34
  InMemoryFeedbackStore,
35
+ createDefaultCoderDelegate,
37
36
  createDelegateCodeHandler,
38
37
  createDelegateFeedbackHandler,
39
38
  createDelegateResearchHandler,
40
39
  createDelegationHistoryHandler,
41
40
  createDelegationStatusHandler,
41
+ createFleetWorkspaceExecutor,
42
+ createSiblingSandboxExecutor,
42
43
  eventToSnapshot,
43
44
  hashIdempotencyInput,
44
45
  validateDelegateCodeArgs,
@@ -46,7 +47,7 @@ import {
46
47
  validateDelegateResearchArgs,
47
48
  validateDelegationHistoryArgs,
48
49
  validateDelegationStatusArgs
49
- } from "../chunk-HSX6PFZR.js";
50
+ } from "../chunk-V6GURW4W.js";
50
51
  import {
51
52
  runLocalHarness
52
53
  } from "../chunk-GLR25NG7.js";
@@ -56,62 +57,6 @@ import "../chunk-PY6NMZYX.js";
56
57
  import "../chunk-SQSCRJ7U.js";
57
58
  import "../chunk-DGUM43GV.js";
58
59
 
59
- // src/mcp/kb-gate.ts
60
- var norm = (s) => s.toLowerCase().replace(/\s+/g, " ").trim();
61
- function valueAppears(value, passageNorm) {
62
- if (passageNorm.includes(norm(String(value)))) return true;
63
- if (typeof value !== "number" || !Number.isFinite(value)) return false;
64
- const forms = [value.toLocaleString("en-US")];
65
- if (Math.abs(value) >= 1e9) forms.push(`${trimZero(value / 1e9)} billion`);
66
- if (Math.abs(value) >= 1e6) forms.push(`${trimZero(value / 1e6)} million`);
67
- return forms.some((f) => passageNorm.includes(norm(f)));
68
- }
69
- function trimZero(n) {
70
- return Number.isInteger(n) ? String(n) : String(Number(n.toFixed(2)));
71
- }
72
- function builtinJudges(minPassageChars, selfArtifactKinds) {
73
- const kinds = selfArtifactKinds.map((k) => k.toLowerCase());
74
- return [
75
- {
76
- name: "passage-non-empty",
77
- judge: (c) => c.verbatimPassage.trim().length >= minPassageChars ? { accept: true } : { accept: false, reason: `passage shorter than ${minPassageChars} chars` }
78
- },
79
- {
80
- // THE anti-hallucination floor — the passage must literally be in the source.
81
- name: "passage-present",
82
- judge: (c) => norm(c.sourceText).includes(norm(c.verbatimPassage)) ? { accept: true } : { accept: false, reason: "verbatim passage not found in source (unbacked fact)" }
83
- },
84
- {
85
- name: "value-in-passage",
86
- judge: (c) => c.value === void 0 || valueAppears(c.value, norm(c.verbatimPassage)) ? { accept: true } : { accept: false, reason: `value ${JSON.stringify(c.value)} not present in passage` }
87
- },
88
- {
89
- name: "no-circular-citation",
90
- judge: (c) => {
91
- if (!c.citation || kinds.length === 0) return { accept: true };
92
- const cite = c.citation.toLowerCase();
93
- const hit = kinds.find((k) => cite.includes(k));
94
- return hit ? { accept: false, reason: `circular citation to self-generated artifact "${hit}"` } : { accept: true };
95
- }
96
- }
97
- ];
98
- }
99
- function createKbGate(options = {}) {
100
- const judges = [
101
- ...builtinJudges(options.minPassageChars ?? 12, options.selfArtifactKinds ?? []),
102
- ...options.judges ?? []
103
- ];
104
- return async (candidate) => {
105
- for (const j of judges) {
106
- const verdict = await j.judge(candidate);
107
- if (!verdict.accept) {
108
- return { accepted: false, vetoedBy: j.name, reason: verdict.reason };
109
- }
110
- }
111
- return { accepted: true };
112
- };
113
- }
114
-
115
60
  // src/mcp/trace-propagation.ts
116
61
  function readTraceContextFromEnv() {
117
62
  const traceId = process.env.TRACE_ID || generateTraceId();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/mcp/kb-gate.ts","../../src/mcp/trace-propagation.ts"],"sourcesContent":["/**\n * @experimental\n *\n * `createKbGate` — the valid-only knowledge-base growth gate, distilled from\n * physim's KB-research subsystem. A research-in-a-loop delegate (or any KB\n * writer) runs candidate facts through this before persisting, so the KB grows\n * with ONLY grounded facts — hallucinated, unsourced, or laundered claims are\n * vetoed at the gate.\n *\n * Fail-closed by construction: every judge must `accept`; the FIRST veto wins\n * and the fact is rejected. The non-negotiable floor (always on, can't be\n * disabled) is the **passage-present guard** — a fact's `verbatimPassage` MUST\n * literally appear in its `sourceText`. That single check kills the dominant\n * failure mode (a confident claim decoupled from any real source).\n *\n * Pure + dependency-free: it operates on fact candidates, not on a store, so it\n * composes with `@tangle-network/agent-knowledge` or any persistence layer\n * without importing it. The remediation policy (correct-on-veto vs\n * escalate-as-unverified) is the caller's — this returns the verdict; it never\n * drops a fact silently.\n */\n\n/** @experimental A fact proposed for the KB, with its grounding. */\nexport interface FactCandidate {\n /** The atomic claim text. */\n claim: string\n /** Optional extracted value (number or string) the claim asserts. */\n value?: string | number\n /** Verbatim span lifted from the source that backs the claim. */\n verbatimPassage: string\n /** The raw source text the passage must be grounded in. */\n sourceText: string\n /** Where the fact claims to come from — checked for circular/self citations. */\n citation?: string\n}\n\n/** @experimental */\nexport interface FactJudgeVerdict {\n accept: boolean\n reason?: string\n}\n\n/** @experimental A pluggable fact validator. Throw is NOT allowed — return a\n * verdict; a thrown judge is a programmer error, not a veto. */\nexport interface FactJudge {\n name: string\n judge(candidate: FactCandidate): FactJudgeVerdict | Promise<FactJudgeVerdict>\n}\n\n/** @experimental */\nexport interface KbGateResult {\n accepted: boolean\n /** Name of the judge that vetoed; undefined when accepted. */\n vetoedBy?: string\n reason?: string\n}\n\n/** @experimental */\nexport interface CreateKbGateOptions {\n /** Extra judges appended after the built-in floor (e.g. an LLM judge). */\n judges?: FactJudge[]\n /** Minimum verbatim-passage length. Default 12 — kills empty/stub passages. */\n minPassageChars?: number\n /**\n * Citation tokens that denote a SELF-generated artifact (e.g. `'spec'`,\n * `'cad_params'`, `'requirements'`). A citation naming one is circular\n * (laundering) — the fact cites a derived artifact, not a real source.\n * Default `[]` (no circular check unless the consumer declares its kinds).\n */\n selfArtifactKinds?: string[]\n}\n\nconst norm = (s: string): string => s.toLowerCase().replace(/\\s+/g, ' ').trim()\n\n/** Does `value` appear in the (normalized) passage — literally, comma-grouped,\n * or in billion/million shorthand (the forms a source actually writes). */\nfunction valueAppears(value: string | number, passageNorm: string): boolean {\n if (passageNorm.includes(norm(String(value)))) return true\n if (typeof value !== 'number' || !Number.isFinite(value)) return false\n const forms = [value.toLocaleString('en-US')]\n if (Math.abs(value) >= 1e9) forms.push(`${trimZero(value / 1e9)} billion`)\n if (Math.abs(value) >= 1e6) forms.push(`${trimZero(value / 1e6)} million`)\n return forms.some((f) => passageNorm.includes(norm(f)))\n}\n\nfunction trimZero(n: number): string {\n return Number.isInteger(n) ? String(n) : String(Number(n.toFixed(2)))\n}\n\n/** The always-on floor judges. Order matters: cheapest / most-fundamental first. */\nfunction builtinJudges(minPassageChars: number, selfArtifactKinds: string[]): FactJudge[] {\n const kinds = selfArtifactKinds.map((k) => k.toLowerCase())\n return [\n {\n name: 'passage-non-empty',\n judge: (c) =>\n c.verbatimPassage.trim().length >= minPassageChars\n ? { accept: true }\n : { accept: false, reason: `passage shorter than ${minPassageChars} chars` },\n },\n {\n // THE anti-hallucination floor — the passage must literally be in the source.\n name: 'passage-present',\n judge: (c) =>\n norm(c.sourceText).includes(norm(c.verbatimPassage))\n ? { accept: true }\n : { accept: false, reason: 'verbatim passage not found in source (unbacked fact)' },\n },\n {\n name: 'value-in-passage',\n judge: (c) =>\n c.value === undefined || valueAppears(c.value, norm(c.verbatimPassage))\n ? { accept: true }\n : { accept: false, reason: `value ${JSON.stringify(c.value)} not present in passage` },\n },\n {\n name: 'no-circular-citation',\n judge: (c) => {\n if (!c.citation || kinds.length === 0) return { accept: true }\n const cite = c.citation.toLowerCase()\n const hit = kinds.find((k) => cite.includes(k))\n return hit\n ? { accept: false, reason: `circular citation to self-generated artifact \"${hit}\"` }\n : { accept: true }\n },\n },\n ]\n}\n\n/**\n * @experimental\n *\n * Build a fail-closed KB gate. The returned function runs the built-in floor\n * (passage-non-empty → passage-present → value-in-passage → no-circular-citation)\n * then any consumer judges, returning on the first veto.\n */\nexport function createKbGate(\n options: CreateKbGateOptions = {},\n): (candidate: FactCandidate) => Promise<KbGateResult> {\n const judges = [\n ...builtinJudges(options.minPassageChars ?? 12, options.selfArtifactKinds ?? []),\n ...(options.judges ?? []),\n ]\n return async (candidate) => {\n for (const j of judges) {\n const verdict = await j.judge(candidate)\n if (!verdict.accept) {\n return { accepted: false, vetoedBy: j.name, reason: verdict.reason }\n }\n }\n return { accepted: true }\n }\n}\n","/**\n * @experimental\n *\n * Trace context propagation for MCP subprocess.\n *\n * When the MCP server is launched as a child process by a sandbox harness,\n * the parent passes trace context via environment variables:\n *\n * TRACE_ID=<current-run-trace-id>\n * PARENT_SPAN_ID=<span-that-dispatched-the-delegation>\n *\n * The MCP server reads these at startup and uses them as the root of its\n * internal trace tree. All spans emitted by `runLoop` invocations inside\n * the MCP are children of the parent's delegation span.\n *\n * When these env vars are absent, the MCP generates a fresh trace root —\n * the server operates standalone without trace joining.\n */\n\nimport type { LoopTraceEmitter, LoopTraceEvent } from '../loops/types'\nimport type { OtelExporter } from '../otel-export'\nimport { buildLoopOtelSpans, createOtelExporter } from '../otel-export'\n\nexport interface TraceContext {\n /** Trace id inherited from the parent process, or a fresh one. */\n traceId: string\n /** Parent span id from the delegation that launched this MCP server. */\n parentSpanId?: string\n}\n\n/**\n * Read trace context from the process environment.\n * Returns a context with inherited ids or a freshly generated root.\n */\nexport function readTraceContextFromEnv(): TraceContext {\n const traceId = process.env.TRACE_ID || generateTraceId()\n const parentSpanId = process.env.PARENT_SPAN_ID || undefined\n return { traceId, parentSpanId }\n}\n\n/**\n * Create a LoopTraceEmitter that:\n * 1. Parents all spans under the inherited PARENT_SPAN_ID.\n * 2. Exports spans to OTEL when OTEL_EXPORTER_OTLP_ENDPOINT is set.\n *\n * Returns both the emitter and the optional exporter handle for shutdown.\n */\nexport function createPropagatingTraceEmitter(ctx: TraceContext): {\n emitter: LoopTraceEmitter\n exporter: OtelExporter | undefined\n context: TraceContext\n} {\n const exporter = createOtelExporter()\n\n // Buffer events per loop run, then emit the full nested span tree on\n // `loop.ended` so the topology hierarchy (loop → round → branch) reaches the\n // OTLP collector — not a flat list of zero-duration point spans. A run that\n // never reaches `loop.ended` (hard abort) drops its buffer; acceptable for\n // the short-lived MCP subprocess.\n const buffers = new Map<string, LoopTraceEvent[]>()\n\n const emitter: LoopTraceEmitter = {\n emit(event: LoopTraceEvent) {\n if (!exporter) return\n const buf = buffers.get(event.runId)\n if (buf) buf.push(event)\n else buffers.set(event.runId, [event])\n if (event.kind === 'loop.ended') {\n const events = buffers.get(event.runId) ?? [event]\n buffers.delete(event.runId)\n for (const span of buildLoopOtelSpans(events, ctx.traceId, ctx.parentSpanId)) {\n exporter.exportSpan(span)\n }\n }\n },\n }\n\n return { emitter, exporter, context: ctx }\n}\n\n/**\n * Build env vars to pass to a child MCP subprocess so it inherits the\n * current trace context.\n */\nexport function traceContextToEnv(ctx: TraceContext): Record<string, string> {\n const env: Record<string, string> = { TRACE_ID: ctx.traceId }\n if (ctx.parentSpanId) env.PARENT_SPAN_ID = ctx.parentSpanId\n return env\n}\n\nfunction generateTraceId(): string {\n const bytes = new Uint8Array(16)\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n globalThis.crypto.getRandomValues(bytes)\n } else {\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256)\n }\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/mcp/trace-propagation.ts"],"sourcesContent":["/**\n * @experimental\n *\n * Trace context propagation for MCP subprocess.\n *\n * When the MCP server is launched as a child process by a sandbox harness,\n * the parent passes trace context via environment variables:\n *\n * TRACE_ID=<current-run-trace-id>\n * PARENT_SPAN_ID=<span-that-dispatched-the-delegation>\n *\n * The MCP server reads these at startup and uses them as the root of its\n * internal trace tree. All spans emitted by `runLoop` invocations inside\n * the MCP are children of the parent's delegation span.\n *\n * When these env vars are absent, the MCP generates a fresh trace root —\n * the server operates standalone without trace joining.\n */\n\nimport type { LoopTraceEmitter, LoopTraceEvent } from '../loops/types'\nimport type { OtelExporter } from '../otel-export'\nimport { buildLoopOtelSpans, createOtelExporter } from '../otel-export'\n\nexport interface TraceContext {\n /** Trace id inherited from the parent process, or a fresh one. */\n traceId: string\n /** Parent span id from the delegation that launched this MCP server. */\n parentSpanId?: string\n}\n\n/**\n * Read trace context from the process environment.\n * Returns a context with inherited ids or a freshly generated root.\n */\nexport function readTraceContextFromEnv(): TraceContext {\n const traceId = process.env.TRACE_ID || generateTraceId()\n const parentSpanId = process.env.PARENT_SPAN_ID || undefined\n return { traceId, parentSpanId }\n}\n\n/**\n * Create a LoopTraceEmitter that:\n * 1. Parents all spans under the inherited PARENT_SPAN_ID.\n * 2. Exports spans to OTEL when OTEL_EXPORTER_OTLP_ENDPOINT is set.\n *\n * Returns both the emitter and the optional exporter handle for shutdown.\n */\nexport function createPropagatingTraceEmitter(ctx: TraceContext): {\n emitter: LoopTraceEmitter\n exporter: OtelExporter | undefined\n context: TraceContext\n} {\n const exporter = createOtelExporter()\n\n // Buffer events per loop run, then emit the full nested span tree on\n // `loop.ended` so the topology hierarchy (loop → round → branch) reaches the\n // OTLP collector — not a flat list of zero-duration point spans. A run that\n // never reaches `loop.ended` (hard abort) drops its buffer; acceptable for\n // the short-lived MCP subprocess.\n const buffers = new Map<string, LoopTraceEvent[]>()\n\n const emitter: LoopTraceEmitter = {\n emit(event: LoopTraceEvent) {\n if (!exporter) return\n const buf = buffers.get(event.runId)\n if (buf) buf.push(event)\n else buffers.set(event.runId, [event])\n if (event.kind === 'loop.ended') {\n const events = buffers.get(event.runId) ?? [event]\n buffers.delete(event.runId)\n for (const span of buildLoopOtelSpans(events, ctx.traceId, ctx.parentSpanId)) {\n exporter.exportSpan(span)\n }\n }\n },\n }\n\n return { emitter, exporter, context: ctx }\n}\n\n/**\n * Build env vars to pass to a child MCP subprocess so it inherits the\n * current trace context.\n */\nexport function traceContextToEnv(ctx: TraceContext): Record<string, string> {\n const env: Record<string, string> = { TRACE_ID: ctx.traceId }\n if (ctx.parentSpanId) env.PARENT_SPAN_ID = ctx.parentSpanId\n return env\n}\n\nfunction generateTraceId(): string {\n const bytes = new Uint8Array(16)\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n globalThis.crypto.getRandomValues(bytes)\n } else {\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256)\n }\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCO,SAAS,0BAAwC;AACtD,QAAM,UAAU,QAAQ,IAAI,YAAY,gBAAgB;AACxD,QAAM,eAAe,QAAQ,IAAI,kBAAkB;AACnD,SAAO,EAAE,SAAS,aAAa;AACjC;AASO,SAAS,8BAA8B,KAI5C;AACA,QAAM,WAAW,mBAAmB;AAOpC,QAAM,UAAU,oBAAI,IAA8B;AAElD,QAAM,UAA4B;AAAA,IAChC,KAAK,OAAuB;AAC1B,UAAI,CAAC,SAAU;AACf,YAAM,MAAM,QAAQ,IAAI,MAAM,KAAK;AACnC,UAAI,IAAK,KAAI,KAAK,KAAK;AAAA,UAClB,SAAQ,IAAI,MAAM,OAAO,CAAC,KAAK,CAAC;AACrC,UAAI,MAAM,SAAS,cAAc;AAC/B,cAAM,SAAS,QAAQ,IAAI,MAAM,KAAK,KAAK,CAAC,KAAK;AACjD,gBAAQ,OAAO,MAAM,KAAK;AAC1B,mBAAW,QAAQ,mBAAmB,QAAQ,IAAI,SAAS,IAAI,YAAY,GAAG;AAC5E,mBAAS,WAAW,IAAI;AAAA,QAC1B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,UAAU,SAAS,IAAI;AAC3C;AAMO,SAAS,kBAAkB,KAA2C;AAC3E,QAAM,MAA8B,EAAE,UAAU,IAAI,QAAQ;AAC5D,MAAI,IAAI,aAAc,KAAI,iBAAiB,IAAI;AAC/C,SAAO;AACT;AAEA,SAAS,kBAA0B;AACjC,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,MAAI,OAAO,WAAW,QAAQ,oBAAoB,YAAY;AAC5D,eAAW,OAAO,gBAAgB,KAAK;AAAA,EACzC,OAAO;AACL,aAAS,IAAI,GAAG,IAAI,IAAI,IAAK,OAAM,CAAC,IAAI,KAAK,MAAM,KAAK,OAAO,IAAI,GAAG;AAAA,EACxE;AACA,SAAO,MAAM,KAAK,KAAK,EACpB,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAC1C,KAAK,EAAE;AACZ;","names":[]}