@signal9/era-ui 4.15.5 → 4.16.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.
@@ -1,4 +1,4 @@
1
- import type { SwarmAgent } from './swarm.js';
1
+ import type { SwarmAgent, SwarmContentRenderers } from './swarm.js';
2
2
  /**
3
3
  * What `Swarm.Root` shares with every part below it.
4
4
  *
@@ -21,6 +21,12 @@ export interface SwarmContext {
21
21
  readonly onOpen?: (agent: SwarmAgent) => void;
22
22
  /** Cancel an agent (the host decides whether that means its subtree too). */
23
23
  readonly onCancel?: (agent: SwarmAgent) => void;
24
+ /**
25
+ * Inline renderers for artifact payloads, one per content kind — see
26
+ * `SwarmContentRenderers`. Registered once here so every artifact in the
27
+ * tree resolves the same registry without prop drilling.
28
+ */
29
+ readonly renderers?: SwarmContentRenderers;
24
30
  }
25
31
  export declare function setSwarmContext(ctx: SwarmContext): void;
26
32
  export declare function getSwarmContext(): SwarmContext;
@@ -13,5 +13,5 @@ export { default as Footer } from './swarm-footer.svelte';
13
13
  export { default as Dot, SWARM_DOT } from './swarm-dot.svelte';
14
14
  export { default as Role, SWARM_ROLE } from './swarm-role.svelte';
15
15
  export { SwarmController } from './swarm.svelte.js';
16
- export { buildSwarmTree, isSwarmAgentActive, flattenSwarmTree, summarizeSwarm, summarizeBarrier, swarmElapsed, formatSwarmAge, formatSwarmDuration, type SwarmAgent, type SwarmAgentStatus, type SwarmArtifact, type SwarmBarrier, type SwarmBarrierStatus, type SwarmConnection, type SwarmCounts, type SwarmEvent, type SwarmNode, type SwarmPlan, type SwarmPlanStatus, type SwarmRole, type SwarmSandbox, type SwarmSnapshot } from './swarm.js';
16
+ export { buildSwarmTree, isSwarmAgentActive, isSwarmAgentRetrying, isSwarmSandboxFork, flattenSwarmTree, parseSwarmContent, summarizeSwarm, summarizeBarrier, summarizeSwarmRoots, swarmArtifactContent, swarmElapsed, swarmSandboxForkOf, swarmSubtree, formatSwarmAge, formatSwarmDuration, formatSwarmRetry, type SwarmAgent, type SwarmAgentProgress, type SwarmAgentStatus, type SwarmArtifact, type SwarmBarrier, type SwarmBarrierStatus, type SwarmChartContent, type SwarmComponentContent, type SwarmConnection, type SwarmContentKind, type SwarmContentOf, type SwarmContentRenderers, type SwarmCounts, type SwarmEvent, type SwarmEventKind, type SwarmExecContent, type SwarmExecEvent, type SwarmExecSegment, type SwarmJsonContent, type SwarmMarkdownContent, type SwarmNode, type SwarmPlan, type SwarmPlanStatus, type SwarmRichContent, type SwarmRole, type SwarmRootSummary, type SwarmSandbox, type SwarmSandboxForkId, type SwarmSandboxStatus, type SwarmSnapshot } from './swarm.js';
17
17
  export type { SwarmContext } from './context.js';
@@ -13,4 +13,4 @@ export { default as Footer } from './swarm-footer.svelte';
13
13
  export { default as Dot, SWARM_DOT } from './swarm-dot.svelte';
14
14
  export { default as Role, SWARM_ROLE } from './swarm-role.svelte';
15
15
  export { SwarmController } from './swarm.svelte.js';
16
- export { buildSwarmTree, isSwarmAgentActive, flattenSwarmTree, summarizeSwarm, summarizeBarrier, swarmElapsed, formatSwarmAge, formatSwarmDuration } from './swarm.js';
16
+ export { buildSwarmTree, isSwarmAgentActive, isSwarmAgentRetrying, isSwarmSandboxFork, flattenSwarmTree, parseSwarmContent, summarizeSwarm, summarizeBarrier, summarizeSwarmRoots, swarmArtifactContent, swarmElapsed, swarmSandboxForkOf, swarmSubtree, formatSwarmAge, formatSwarmDuration, formatSwarmRetry } from './swarm.js';
@@ -3,7 +3,13 @@
3
3
  import { Card } from '../../ui/card/index.js';
4
4
  import { cn } from '../../utils/index.js';
5
5
  import { getSwarmContext } from './context.js';
6
- import { formatSwarmAge, type SwarmArtifact } from './swarm.js';
6
+ import {
7
+ formatSwarmAge,
8
+ swarmArtifactContent,
9
+ type SwarmArtifact,
10
+ type SwarmRichContent
11
+ } from './swarm.js';
12
+ import type { Snippet } from 'svelte';
7
13
 
8
14
  let {
9
15
  artifact,
@@ -17,6 +23,15 @@
17
23
  const age = $derived(
18
24
  artifact.createdAt != null ? formatSwarmAge(artifact.createdAt, ctx.now) : null
19
25
  );
26
+
27
+ // The payload's classified body, and the host's renderer for it, if both
28
+ // exist. The cast erases the per-kind narrowing the registry's mapped type
29
+ // enforces at REGISTRATION — the lookup pairs each snippet with content of
30
+ // its own kind by construction, TS just can't see across the indexed access.
31
+ const content = $derived(swarmArtifactContent(artifact));
32
+ const render = $derived(
33
+ content ? (ctx.renderers?.[content.kind] as Snippet<[SwarmRichContent]> | undefined) : undefined
34
+ );
20
35
  </script>
21
36
 
22
37
  <!-- What a branch actually produced: the merged finding, the report, the diff.
@@ -37,5 +52,12 @@
37
52
  <span class="shrink-0 font-mono text-body text-muted tabular-nums">{age}</span>
38
53
  {/if}
39
54
  </div>
40
- <p class="text-body leading-body text-muted">{artifact.summary}</p>
55
+ {#if content && render}
56
+ <!-- The host's inline renderer for this payload kind — a chart, a terminal,
57
+ an embedded component. The summary stays out of the way: the rich body
58
+ IS the artifact, and the one-liner under it would say it twice. -->
59
+ {@render render(content)}
60
+ {:else}
61
+ <p class="text-body leading-body text-muted">{artifact.summary}</p>
62
+ {/if}
41
63
  </Card>
@@ -8,7 +8,13 @@
8
8
  import Role from './swarm-role.svelte';
9
9
  import Sandbox from './swarm-sandbox.svelte';
10
10
  import Actions, { swarmActions } from './swarm-actions.svelte';
11
- import { formatSwarmDuration, swarmElapsed, type SwarmAgent } from './swarm.js';
11
+ import {
12
+ formatSwarmDuration,
13
+ formatSwarmRetry,
14
+ isSwarmAgentRetrying,
15
+ swarmElapsed,
16
+ type SwarmAgent
17
+ } from './swarm.js';
12
18
 
13
19
  let {
14
20
  agent,
@@ -160,12 +166,26 @@
160
166
  active
161
167
  ? 'bg-hover text-bright'
162
168
  : 'text-fg hover:bg-(--era-highlight) hover:shadow-(--era-highlight-shadow)',
163
- 'group-focus-visible/node:outline group-focus-visible/node:-outline-offset-1 group-focus-visible/node:outline-primary'
169
+ // Scoped to the DIRECT parent, not the group: every node in the tree is
170
+ // a group/node, and a named group matches ANY ancestor — focusing a
171
+ // parent row was outlining every visible child row. `:focus-visible > &`
172
+ // can only mean this row's own treeitem.
173
+ '[:focus-visible>&]:outline [:focus-visible>&]:-outline-offset-1 [:focus-visible>&]:outline-primary'
164
174
  )}
165
175
  >
166
176
  {#if hasChildren}
177
+ <!-- Rotation keys off the component's own bound `open`, NOT the
178
+ group-data-[state=open]/node selector it used to ride: nested nodes
179
+ all share the group name, and a named group matches ANY ancestor —
180
+ so the moment a parent expanded (which it must, for a child to be
181
+ visible at all), every child chevron rotated and stayed rotated.
182
+ `open` is bind:open on this node's own Collapsible.Root — the same
183
+ single source of truth, without the ancestry. -->
167
184
  <ChevronRight
168
- class="size-(--era-h-xs) shrink-0 text-muted transition-transform duration-(--era-duration) ease-(--era-ease) group-data-[state=open]/node:rotate-90"
185
+ class={cn(
186
+ 'size-(--era-h-xs) shrink-0 text-muted transition-transform duration-(--era-duration) ease-(--era-ease)',
187
+ open && 'rotate-90'
188
+ )}
169
189
  aria-hidden="true"
170
190
  />
171
191
  {:else}
@@ -215,6 +235,18 @@
215
235
  <Sandbox sandbox={agent.sandbox} />
216
236
  {/if}
217
237
 
238
+ {#if isSwarmAgentRetrying(agent.progress)}
239
+ <!-- The retry ladder, visible: the runtime is waiting out a provider
240
+ outage, and a live countdown is the difference between "stuck" and
241
+ "resuming in 8s". Warning ink — it is a degraded state, not an
242
+ error. Ticks with ctx.now like every clock here. -->
243
+ <span class="shrink-0 font-mono text-body text-warning tabular-nums">
244
+ {formatSwarmRetry(agent.progress, ctx.now)}
245
+ </span>
246
+ {:else if agent.progress?.phase === 'waiting'}
247
+ <span class="shrink-0 font-mono text-body text-muted">{agent.progress.label}</span>
248
+ {/if}
249
+
218
250
  {#if elapsed != null}
219
251
  <span class="shrink-0 font-mono text-body text-muted tabular-nums">
220
252
  {formatSwarmDuration(elapsed)}
@@ -3,13 +3,14 @@
3
3
  import type { HTMLAttributes } from 'svelte/elements';
4
4
  import { cn } from '../../utils/index.js';
5
5
  import { setSwarmContext } from './context.js';
6
- import type { SwarmAgent } from './swarm.js';
6
+ import type { SwarmAgent, SwarmContentRenderers } from './swarm.js';
7
7
 
8
8
  let {
9
9
  ref = $bindable(null),
10
10
  now = Date.now(),
11
11
  onOpen,
12
12
  onCancel,
13
+ renderers,
13
14
  children,
14
15
  class: className,
15
16
  ...restProps
@@ -21,6 +22,8 @@
21
22
  onOpen?: (agent: SwarmAgent) => void;
22
23
  /** Cancel an agent. Nodes show the affordance only while one is still active. */
23
24
  onCancel?: (agent: SwarmAgent) => void;
25
+ /** Inline renderers for artifact payloads (charts, exec output, components). */
26
+ renderers?: SwarmContentRenderers;
24
27
  children?: Snippet;
25
28
  } = $props();
26
29
 
@@ -35,6 +38,9 @@
35
38
  },
36
39
  get onCancel() {
37
40
  return onCancel;
41
+ },
42
+ get renderers() {
43
+ return renderers;
38
44
  }
39
45
  });
40
46
  </script>
@@ -1,6 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
- import type { SwarmAgent } from './swarm.js';
3
+ import type { SwarmAgent, SwarmContentRenderers } from './swarm.js';
4
4
  type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
5
5
  ref?: HTMLDivElement | null;
6
6
  /** Epoch ms for every elapsed readout. Tick it in `$state` for live counters. */
@@ -9,6 +9,8 @@ type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
9
9
  onOpen?: (agent: SwarmAgent) => void;
10
10
  /** Cancel an agent. Nodes show the affordance only while one is still active. */
11
11
  onCancel?: (agent: SwarmAgent) => void;
12
+ /** Inline renderers for artifact payloads (charts, exec output, components). */
13
+ renderers?: SwarmContentRenderers;
12
14
  children?: Snippet;
13
15
  };
14
16
  declare const SwarmRoot: import("svelte").Component<$$ComponentProps, {}, "ref">;
@@ -15,7 +15,10 @@
15
15
 
16
16
  <script lang="ts">
17
17
  import Box from '@lucide/svelte/icons/box';
18
+ import Camera from '@lucide/svelte/icons/camera';
19
+ import GitBranch from '@lucide/svelte/icons/git-branch';
18
20
  import { cn } from '../../utils/index.js';
21
+ import { swarmSandboxForkOf } from './swarm.js';
19
22
 
20
23
  let {
21
24
  sandbox,
@@ -27,6 +30,18 @@
27
30
  label?: boolean;
28
31
  class?: string;
29
32
  } = $props();
33
+
34
+ const forkOf = $derived(swarmSandboxForkOf(sandbox));
35
+ const title = $derived(
36
+ [
37
+ `sandbox ${sandbox.id ?? ''} (${sandbox.status})`,
38
+ forkOf && `forked from ${forkOf}`,
39
+ sandbox.checkpoint && 'checkpoint',
40
+ sandbox.busy && 'command running'
41
+ ]
42
+ .filter(Boolean)
43
+ .join(' — ')
44
+ );
30
45
  </script>
31
46
 
32
47
  <!-- Deliberately a signal of its own, never folded into the status dot: an agent
@@ -38,8 +53,21 @@
38
53
  SANDBOX_TONE[sandbox.status],
39
54
  className
40
55
  )}
41
- title="sandbox {sandbox.id ?? ''} ({sandbox.status})"
56
+ {title}
42
57
  >
43
- <Box class="size-(--era-h-xs) shrink-0" aria-hidden="true" />
58
+ <!-- busy: the box PULSES rather than gaining a second glyph — "a command is
59
+ streaming through this VM" is motion, and motion is what says it. -->
60
+ <Box
61
+ class={cn('size-(--era-h-xs) shrink-0', sandbox.busy && 'animate-pulse')}
62
+ aria-hidden="true"
63
+ />
64
+ {#if sandbox.checkpoint}
65
+ <!-- A paused VM kept as a restore point — the camera badge, as the
66
+ reference console draws it. -->
67
+ <Camera class="size-(--era-icon-xxs) shrink-0" aria-hidden="true" />
68
+ {:else if forkOf}
69
+ <!-- Live-forked from a parent VM; the lineage is in the title. -->
70
+ <GitBranch class="size-(--era-icon-xxs) shrink-0" aria-hidden="true" />
71
+ {/if}
44
72
  {#if label}<span class="truncate">{sandbox.status}</span>{/if}
45
73
  </span>
@@ -53,12 +53,87 @@ export type SwarmBarrierStatus = 'open' | 'done' | 'failed' | 'cancelled';
53
53
  * `Swarm.Footer`) for exactly that reason.
54
54
  */
55
55
  export type SwarmConnection = 'idle' | 'loading' | 'live' | 'reconnecting' | 'error';
56
- /** The VM an agent executes in, when it has one. */
56
+ /** A sandbox VM's lifecycle. `paused` includes checkpoints see `checkpoint`. */
57
+ export type SwarmSandboxStatus = 'running' | 'paused' | 'terminated';
58
+ /**
59
+ * The id convention live-forked VMs carry: `<parent>-fk-<hex>`. A template
60
+ * literal type rather than a boolean field, because the LINEAGE is in the id —
61
+ * `swarmSandboxForkOf` recovers the parent from it with no extra data.
62
+ */
63
+ export type SwarmSandboxForkId = `${string}-fk-${string}`;
64
+ /** Whether a sandbox id names a live fork of another VM. */
65
+ export declare function isSwarmSandboxFork(id: string): id is SwarmSandboxForkId;
66
+ /** The parent VM a forked sandbox was cloned from, or null for a fresh VM. */
67
+ export declare function swarmSandboxForkOf(sandbox: SwarmSandbox): string | null;
68
+ /**
69
+ * The VM an agent executes in, when it has one.
70
+ *
71
+ * Everything beyond `status` is optional because sandbox truth is usually a
72
+ * SEPARATE, slower channel than the swarm's own event stream (the reference
73
+ * implementation snapshots it on a poll and deliberately never journals it) —
74
+ * a host reports what it knows and the parts render what is there.
75
+ */
57
76
  export interface SwarmSandbox {
58
- /** Provider id, shown on hover. */
77
+ /** Provider id, shown on hover. Fork lineage is readable from it — see `SwarmSandboxForkId`. */
59
78
  id?: string;
60
- status: 'running' | 'paused' | 'terminated';
79
+ status: SwarmSandboxStatus;
80
+ /** Parent VM this one was live-forked from. Omit to derive from the id. */
81
+ forkOf?: string | null;
82
+ /** A paused VM kept as a restore point (rendered with the checkpoint badge). */
83
+ checkpoint?: boolean;
84
+ /** A command is streaming through this VM right now. */
85
+ busy?: boolean;
86
+ /** Epoch ms the grace-window VM will be reaped, for a countdown. */
87
+ expiresAt?: number | null;
88
+ }
89
+ /** One chunk of live process output from a sandbox exec. */
90
+ export interface SwarmExecSegment {
91
+ stream: 'stdout' | 'stderr';
92
+ data: string;
61
93
  }
94
+ /**
95
+ * The exec stream's wire shape: interleaved output, then exactly one exit.
96
+ * `hint` is a sandbox-side diagnostic (timeout, missing interpreter) — NOT
97
+ * process output, which is why it is on the exit and not in the segments.
98
+ */
99
+ export type SwarmExecEvent = {
100
+ type: 'output';
101
+ segments: SwarmExecSegment[];
102
+ } | {
103
+ type: 'exit';
104
+ exitCode: number;
105
+ hint?: string;
106
+ };
107
+ /**
108
+ * A transient runtime phase on a live agent — the retry ladder made visible.
109
+ *
110
+ * Discriminated on `phase` so the retrying arm can REQUIRE its countdown
111
+ * fields: a "retrying" chip with no resume time is exactly the half-state this
112
+ * type exists to make unrepresentable.
113
+ */
114
+ export type SwarmAgentProgress = {
115
+ phase: 'retrying';
116
+ /** Retry attempt number, 1-based. */
117
+ attempt: number;
118
+ /** Epoch ms when the runtime resumes after the backoff. */
119
+ resumeAt: number;
120
+ /** What is being waited out ("provider overloaded"). */
121
+ label?: string;
122
+ } | {
123
+ phase: 'waiting';
124
+ label: string;
125
+ };
126
+ /** Narrow an agent's progress to the retrying arm (gates the countdown chip). */
127
+ export declare function isSwarmAgentRetrying(progress: SwarmAgentProgress | null | undefined): progress is Extract<SwarmAgentProgress, {
128
+ phase: 'retrying';
129
+ }>;
130
+ /**
131
+ * The countdown a retrying agent renders: `attempt 2 — resuming in 8s`.
132
+ * Same clock rule as everything here — `now` is an argument.
133
+ */
134
+ export declare function formatSwarmRetry(progress: Extract<SwarmAgentProgress, {
135
+ phase: 'retrying';
136
+ }>, now: number): string;
62
137
  /** One agent in the swarm. */
63
138
  export interface SwarmAgent {
64
139
  id: string;
@@ -76,6 +151,18 @@ export interface SwarmAgent {
76
151
  result?: string;
77
152
  /** Fan-in gate this agent reports into. */
78
153
  barrierId?: string | null;
154
+ /** The plan this agent belongs to, when the host tracks more than one. */
155
+ planId?: string | null;
156
+ /**
157
+ * The host's execution handle — what sandbox operations (exec, terminate,
158
+ * lifecycle) are keyed by in most runtimes. Opaque to era.
159
+ */
160
+ executionId?: string | null;
161
+ /**
162
+ * Transient runtime phase (a provider-retry countdown, a named wait).
163
+ * Cleared with `null`; rendered inline on the row while present.
164
+ */
165
+ progress?: SwarmAgentProgress | null;
79
166
  /**
80
167
  * The agent's own transcript, when it has one. This GATES the open
81
168
  * affordance: a row or card shows the open button only when the host has both
@@ -121,6 +208,12 @@ export interface SwarmArtifact {
121
208
  kind: string;
122
209
  title?: string;
123
210
  summary: string;
211
+ /**
212
+ * The artifact's full structured body — what `summary` is a compression of.
213
+ * Parsed structurally by `parseSwarmContent` for inline rich rendering
214
+ * (charts, exec output, embedded components); see `SwarmContentRenderers`.
215
+ */
216
+ payload?: Record<string, unknown> | null;
124
217
  /** Epoch ms. */
125
218
  createdAt?: number;
126
219
  }
@@ -142,6 +235,8 @@ export interface SwarmCounts {
142
235
  cancelled: number;
143
236
  /** blocked + queued + running — everything that has not landed yet. */
144
237
  active: number;
238
+ /** done + failed + cancelled — the determinate progress bar's value. */
239
+ settled: number;
145
240
  /** Agents holding a VM that is not terminated. */
146
241
  sandboxes: number;
147
242
  }
@@ -206,10 +301,18 @@ export declare function formatSwarmDuration(ms: number): string;
206
301
  * differ the moment an event updates an agent already in the map, which is most
207
302
  * events, and confusing the two silently re-requests or skips history.
208
303
  */
304
+ /**
305
+ * The event labels the reference journal emits, template-literal-typed so a
306
+ * status change is spelled from the same union the status field uses — and
307
+ * widened with `(string & {})`, the intersection trick that keeps arbitrary
308
+ * producer strings assignable WITHOUT collapsing the union (a bare `| string`
309
+ * would swallow the literals and take autocomplete with it).
310
+ */
311
+ export type SwarmEventKind = 'agent.spawned' | `agent.${SwarmAgentStatus}` | `plan.${'created' | 'updated'}` | `barrier.${'created' | 'updated'}` | 'artifact.published' | (string & {});
209
312
  export interface SwarmEvent {
210
313
  seq: number;
211
- /** Free-form producer label ("agent.completed"), passed through untouched. */
212
- kind?: string;
314
+ /** Producer label see `SwarmEventKind`. Passed through untouched. */
315
+ kind?: SwarmEventKind;
213
316
  agent?: SwarmAgent;
214
317
  plan?: SwarmPlan;
215
318
  barrier?: SwarmBarrier;
@@ -224,3 +327,114 @@ export interface SwarmSnapshot {
224
327
  barriers?: SwarmBarrier[];
225
328
  artifacts?: SwarmArtifact[];
226
329
  }
330
+ /**
331
+ * Tabular data with a visualization spec — the chart shape the reference
332
+ * runtime streams (`viz.type` names the mark, `data` is columnar rows).
333
+ * era ships no chart renderer; the HOST registers one (see
334
+ * `SwarmContentRenderers`) and receives this, fully typed.
335
+ */
336
+ export interface SwarmChartContent {
337
+ kind: 'chart';
338
+ viz: {
339
+ type: string;
340
+ } & Record<string, unknown>;
341
+ data: {
342
+ columns: string[];
343
+ rows: Record<string, unknown>[];
344
+ rowCount?: number;
345
+ };
346
+ title?: string;
347
+ }
348
+ /** A finished command's output — the sandbox exec result, inline. */
349
+ export interface SwarmExecContent {
350
+ kind: 'exec';
351
+ exitCode: number;
352
+ stdout: string;
353
+ stderr: string;
354
+ /** Sandbox-side diagnostic (timeout, missing interpreter) — not process output. */
355
+ hint?: string;
356
+ command?: string;
357
+ }
358
+ /**
359
+ * An embedded component by registry name — the "spawn an app inline" shape.
360
+ * Generic over its props so a host with a typed registry can narrow `props`
361
+ * per component id; the default keeps it structural.
362
+ */
363
+ export interface SwarmComponentContent<P extends Record<string, unknown> = Record<string, unknown>> {
364
+ kind: 'component';
365
+ /** Registry id the host resolves to a Svelte component. */
366
+ component: string;
367
+ props?: P;
368
+ /** Render in place (true) vs. "opens elsewhere" affordance (false). */
369
+ inline?: boolean;
370
+ }
371
+ /** Prose — rendered by the host's markdown pipeline. */
372
+ export interface SwarmMarkdownContent {
373
+ kind: 'markdown';
374
+ text: string;
375
+ }
376
+ /** The structured fallback: anything JSON-shaped the parsers above declined. */
377
+ export interface SwarmJsonContent {
378
+ kind: 'json';
379
+ data: unknown;
380
+ }
381
+ /** Everything an artifact payload can render as, discriminated on `kind`. */
382
+ export type SwarmRichContent = SwarmChartContent | SwarmExecContent | SwarmComponentContent | SwarmMarkdownContent | SwarmJsonContent;
383
+ export type SwarmContentKind = SwarmRichContent['kind'];
384
+ /** The union member for one kind — `SwarmContentOf<'chart'>` is `SwarmChartContent`. */
385
+ export type SwarmContentOf<K extends SwarmContentKind> = Extract<SwarmRichContent, {
386
+ kind: K;
387
+ }>;
388
+ /**
389
+ * The host's inline renderers, one optional snippet per content kind, each
390
+ * typed to exactly its member of the union — a mapped type over the
391
+ * discriminant, so registering a `chart` snippet that expects exec output is a
392
+ * compile error, not a runtime surprise.
393
+ *
394
+ * Registered once on `Swarm.Root` and read through context by every artifact
395
+ * in the tree — the era analogue of the reference app's component registry.
396
+ * Kinds without a renderer fall back to the artifact's summary text.
397
+ */
398
+ export type SwarmContentRenderers = {
399
+ [K in SwarmContentKind]?: import('svelte').Snippet<[SwarmContentOf<K>]>;
400
+ };
401
+ /**
402
+ * Classify a payload STRUCTURALLY — by the fields it carries, never by a tool
403
+ * name or a declared type tag (producers rename tools; shapes are the
404
+ * contract). Detection order mirrors the reference implementation: exec
405
+ * (exitCode + stdout) → chart (viz.type + data.columns[]) → component
406
+ * (component string) → markdown (a lone text/markdown field) → json.
407
+ * Returns null only for empty input, so a renderer switch is total.
408
+ */
409
+ export declare function parseSwarmContent(payload: unknown): SwarmRichContent | null;
410
+ /** An artifact's rich body, when it has one — `parseSwarmContent` over `payload`. */
411
+ export declare function swarmArtifactContent(artifact: SwarmArtifact): SwarmRichContent | null;
412
+ /**
413
+ * One swarm summarized to a list row — what a hunts/runs table renders.
414
+ * The reference app's "hunt" IS this: a swarm root plus aggregate counts,
415
+ * under a domain label.
416
+ */
417
+ export interface SwarmRootSummary {
418
+ rootId: string;
419
+ /** The root agent's task — the row's title. */
420
+ title: string;
421
+ /** The root agent's own status. */
422
+ status: SwarmAgentStatus;
423
+ counts: SwarmCounts;
424
+ /** Epoch ms of the newest agent activity, for the "updated" cell. */
425
+ updatedAt?: number;
426
+ }
427
+ /**
428
+ * Summarize each delegation tree in a flat agent list to a table row.
429
+ * Rows come back in first-seen order; the caller sorts.
430
+ */
431
+ export declare function summarizeSwarmRoots(agents: SwarmAgent[]): SwarmRootSummary[];
432
+ /**
433
+ * An agent and every transitive descendant, in tree order.
434
+ *
435
+ * The cascade selector: the reference runtime cancels SUBTREES (and cancels
436
+ * dependents when a dependency fails), so a host wiring `onCancel` calls this
437
+ * to know what a cancellation will take with it — and to filter it to
438
+ * `isSwarmAgentActive` for the confirm prompt's count.
439
+ */
440
+ export declare function swarmSubtree(agents: SwarmAgent[], agentId: string): SwarmAgent[];