@swirls/looms 0.0.1

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 (270) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +9 -0
  3. package/dist/actor/cell.d.ts +27 -0
  4. package/dist/actor/cell.js +41 -0
  5. package/dist/actor/host.d.ts +27 -0
  6. package/dist/actor/host.js +82 -0
  7. package/dist/actor/index.d.ts +3 -0
  8. package/dist/actor/index.js +3 -0
  9. package/dist/actor/routing.d.ts +15 -0
  10. package/dist/actor/routing.js +80 -0
  11. package/dist/agent/definitions-store.d.ts +11 -0
  12. package/dist/agent/definitions-store.js +10 -0
  13. package/dist/agent/definitions.d.ts +152 -0
  14. package/dist/agent/definitions.js +74 -0
  15. package/dist/agent/effects.d.ts +425 -0
  16. package/dist/agent/effects.js +318 -0
  17. package/dist/agent/events.d.ts +170 -0
  18. package/dist/agent/events.js +61 -0
  19. package/dist/agent/index.d.ts +13 -0
  20. package/dist/agent/index.js +13 -0
  21. package/dist/agent/llm.d.ts +35 -0
  22. package/dist/agent/llm.js +48 -0
  23. package/dist/agent/module.d.ts +1037 -0
  24. package/dist/agent/module.js +27 -0
  25. package/dist/agent/projections.d.ts +17 -0
  26. package/dist/agent/projections.js +81 -0
  27. package/dist/agent/scope.d.ts +171 -0
  28. package/dist/agent/scope.js +7 -0
  29. package/dist/agent/signals.d.ts +17 -0
  30. package/dist/agent/signals.js +19 -0
  31. package/dist/agent/stop-when.d.ts +12 -0
  32. package/dist/agent/stop-when.js +6 -0
  33. package/dist/agent/threads.d.ts +34 -0
  34. package/dist/agent/threads.js +407 -0
  35. package/dist/agent/tool-schema.d.ts +21 -0
  36. package/dist/agent/tool-schema.js +67 -0
  37. package/dist/agent/types.d.ts +87 -0
  38. package/dist/agent/types.js +32 -0
  39. package/dist/ai-vercel/index.d.ts +2 -0
  40. package/dist/ai-vercel/index.js +2 -0
  41. package/dist/ai-vercel/messages.d.ts +9 -0
  42. package/dist/ai-vercel/messages.js +68 -0
  43. package/dist/ai-vercel/vercel-llm.d.ts +8 -0
  44. package/dist/ai-vercel/vercel-llm.js +98 -0
  45. package/dist/approval/effects.d.ts +133 -0
  46. package/dist/approval/effects.js +13 -0
  47. package/dist/approval/events.d.ts +52 -0
  48. package/dist/approval/events.js +28 -0
  49. package/dist/approval/index.d.ts +6 -0
  50. package/dist/approval/index.js +6 -0
  51. package/dist/approval/module.d.ts +342 -0
  52. package/dist/approval/module.js +10 -0
  53. package/dist/approval/projections.d.ts +42 -0
  54. package/dist/approval/projections.js +57 -0
  55. package/dist/approval/scope.d.ts +45 -0
  56. package/dist/approval/scope.js +7 -0
  57. package/dist/approval/signals.d.ts +19 -0
  58. package/dist/approval/signals.js +34 -0
  59. package/dist/cli/cli.d.ts +2 -0
  60. package/dist/cli/cli.js +6 -0
  61. package/dist/cli/commands.d.ts +13 -0
  62. package/dist/cli/commands.js +133 -0
  63. package/dist/cli/index.d.ts +1 -0
  64. package/dist/cli/index.js +1 -0
  65. package/dist/client/client.d.ts +69 -0
  66. package/dist/client/client.js +179 -0
  67. package/dist/client/index.d.ts +2 -0
  68. package/dist/client/index.js +2 -0
  69. package/dist/client/sse.d.ts +10 -0
  70. package/dist/client/sse.js +103 -0
  71. package/dist/cloudflare/alarm-scheduler.d.ts +9 -0
  72. package/dist/cloudflare/alarm-scheduler.js +13 -0
  73. package/dist/cloudflare/durable-object.d.ts +24 -0
  74. package/dist/cloudflare/durable-object.js +43 -0
  75. package/dist/cloudflare/event-store.d.ts +10 -0
  76. package/dist/cloudflare/event-store.js +18 -0
  77. package/dist/cloudflare/index.d.ts +4 -0
  78. package/dist/cloudflare/index.js +4 -0
  79. package/dist/cloudflare/router.d.ts +12 -0
  80. package/dist/cloudflare/router.js +26 -0
  81. package/dist/core/bun-sqlite.d.ts +13 -0
  82. package/dist/core/bun-sqlite.js +19 -0
  83. package/dist/core/catalog.d.ts +49 -0
  84. package/dist/core/catalog.js +39 -0
  85. package/dist/core/coalesce.d.ts +21 -0
  86. package/dist/core/coalesce.js +178 -0
  87. package/dist/core/compose.d.ts +59 -0
  88. package/dist/core/compose.js +97 -0
  89. package/dist/core/cursor.d.ts +16 -0
  90. package/dist/core/cursor.js +46 -0
  91. package/dist/core/effects.d.ts +110 -0
  92. package/dist/core/effects.js +99 -0
  93. package/dist/core/envelope.d.ts +79 -0
  94. package/dist/core/envelope.js +68 -0
  95. package/dist/core/event-codec.d.ts +8 -0
  96. package/dist/core/event-codec.js +82 -0
  97. package/dist/core/event-index.d.ts +28 -0
  98. package/dist/core/event-index.js +86 -0
  99. package/dist/core/fold.d.ts +19 -0
  100. package/dist/core/fold.js +362 -0
  101. package/dist/core/ids.d.ts +11 -0
  102. package/dist/core/ids.js +47 -0
  103. package/dist/core/index.d.ts +26 -0
  104. package/dist/core/index.js +25 -0
  105. package/dist/core/match.d.ts +8 -0
  106. package/dist/core/match.js +58 -0
  107. package/dist/core/module-scope.d.ts +99 -0
  108. package/dist/core/module-scope.js +72 -0
  109. package/dist/core/module.d.ts +74 -0
  110. package/dist/core/module.js +3 -0
  111. package/dist/core/projection.d.ts +83 -0
  112. package/dist/core/projection.js +241 -0
  113. package/dist/core/protocol.d.ts +99 -0
  114. package/dist/core/protocol.js +101 -0
  115. package/dist/core/replay.d.ts +13 -0
  116. package/dist/core/replay.js +34 -0
  117. package/dist/core/schema.d.ts +35 -0
  118. package/dist/core/schema.js +130 -0
  119. package/dist/core/serialize.d.ts +14 -0
  120. package/dist/core/serialize.js +42 -0
  121. package/dist/core/snapshot-store.d.ts +39 -0
  122. package/dist/core/snapshot-store.js +53 -0
  123. package/dist/core/snapshots.d.ts +26 -0
  124. package/dist/core/snapshots.js +100 -0
  125. package/dist/core/sqlite-store.d.ts +31 -0
  126. package/dist/core/sqlite-store.js +328 -0
  127. package/dist/core/state.d.ts +43 -0
  128. package/dist/core/state.js +31 -0
  129. package/dist/core/store.d.ts +146 -0
  130. package/dist/core/store.js +229 -0
  131. package/dist/core/thread.d.ts +41 -0
  132. package/dist/core/thread.js +13 -0
  133. package/dist/core/types.d.ts +27 -0
  134. package/dist/core/types.js +42 -0
  135. package/dist/core/validate-event.d.ts +19 -0
  136. package/dist/core/validate-event.js +42 -0
  137. package/dist/debugger/components/debugger-split.d.ts +23 -0
  138. package/dist/debugger/components/debugger-split.js +25 -0
  139. package/dist/debugger/components/event-inspector.d.ts +5 -0
  140. package/dist/debugger/components/event-inspector.js +38 -0
  141. package/dist/debugger/components/event-stream.d.ts +13 -0
  142. package/dist/debugger/components/event-stream.js +119 -0
  143. package/dist/debugger/components/json-view.d.ts +5 -0
  144. package/dist/debugger/components/json-view.js +5 -0
  145. package/dist/debugger/components/run-tree.d.ts +14 -0
  146. package/dist/debugger/components/run-tree.js +38 -0
  147. package/dist/debugger/components/status-dot.d.ts +3 -0
  148. package/dist/debugger/components/status-dot.js +5 -0
  149. package/dist/debugger/contracts.d.ts +22 -0
  150. package/dist/debugger/contracts.js +1 -0
  151. package/dist/debugger/events/catalog.d.ts +6 -0
  152. package/dist/debugger/events/catalog.js +27 -0
  153. package/dist/debugger/events/domain-summarize.d.ts +3 -0
  154. package/dist/debugger/events/domain-summarize.js +107 -0
  155. package/dist/debugger/events/family.d.ts +8 -0
  156. package/dist/debugger/events/family.js +44 -0
  157. package/dist/debugger/events/protocol-summarize.d.ts +3 -0
  158. package/dist/debugger/events/protocol-summarize.js +70 -0
  159. package/dist/debugger/index.d.ts +17 -0
  160. package/dist/debugger/index.js +16 -0
  161. package/dist/debugger/lib/cn.d.ts +5 -0
  162. package/dist/debugger/lib/cn.js +17 -0
  163. package/dist/debugger/lib/event-counts.d.ts +5 -0
  164. package/dist/debugger/lib/event-counts.js +23 -0
  165. package/dist/debugger/lib/event-meta.d.ts +8 -0
  166. package/dist/debugger/lib/event-meta.js +20 -0
  167. package/dist/debugger/lib/project-run.d.ts +9 -0
  168. package/dist/debugger/lib/project-run.js +14 -0
  169. package/dist/debugger/lib/status.d.ts +3 -0
  170. package/dist/debugger/lib/status.js +31 -0
  171. package/dist/debugger/lib/visible-events.d.ts +8 -0
  172. package/dist/debugger/lib/visible-events.js +21 -0
  173. package/dist/debugger/styles.css +71 -0
  174. package/dist/debugger/ui/checkbox.d.ts +4 -0
  175. package/dist/debugger/ui/checkbox.js +9 -0
  176. package/dist/debugger/ui/input.d.ts +3 -0
  177. package/dist/debugger/ui/input.js +7 -0
  178. package/dist/debugger/ui/scroll-area.d.ts +9 -0
  179. package/dist/debugger/ui/scroll-area.js +10 -0
  180. package/dist/debugger/ui/tabs.d.ts +7 -0
  181. package/dist/debugger/ui/tabs.js +17 -0
  182. package/dist/index.d.ts +2 -0
  183. package/dist/index.js +2 -0
  184. package/dist/projectors/index-model.d.ts +56 -0
  185. package/dist/projectors/index-model.js +117 -0
  186. package/dist/projectors/index.d.ts +4 -0
  187. package/dist/projectors/index.js +3 -0
  188. package/dist/projectors/memory.d.ts +5 -0
  189. package/dist/projectors/memory.js +77 -0
  190. package/dist/projectors/postgres.d.ts +9 -0
  191. package/dist/projectors/postgres.js +108 -0
  192. package/dist/projectors/projector.d.ts +11 -0
  193. package/dist/projectors/projector.js +1 -0
  194. package/dist/projectors/schema.d.ts +5 -0
  195. package/dist/projectors/schema.js +43 -0
  196. package/dist/projectors/sqlite.d.ts +9 -0
  197. package/dist/projectors/sqlite.js +103 -0
  198. package/dist/projectors/with-projectors.d.ts +17 -0
  199. package/dist/projectors/with-projectors.js +55 -0
  200. package/dist/react/derived.d.ts +19 -0
  201. package/dist/react/derived.js +50 -0
  202. package/dist/react/index.d.ts +6 -0
  203. package/dist/react/index.js +5 -0
  204. package/dist/react/materialize.d.ts +3 -0
  205. package/dist/react/materialize.js +86 -0
  206. package/dist/react/notify.d.ts +18 -0
  207. package/dist/react/notify.js +80 -0
  208. package/dist/react/react.d.ts +61 -0
  209. package/dist/react/react.js +187 -0
  210. package/dist/react/register.d.ts +31 -0
  211. package/dist/react/register.js +1 -0
  212. package/dist/react/sse.d.ts +1 -0
  213. package/dist/react/sse.js +1 -0
  214. package/dist/react/store.d.ts +56 -0
  215. package/dist/react/store.js +340 -0
  216. package/dist/react/tables.d.ts +21 -0
  217. package/dist/react/tables.js +6 -0
  218. package/dist/runtime/dispatch-effect.d.ts +3 -0
  219. package/dist/runtime/dispatch-effect.js +113 -0
  220. package/dist/runtime/events-api.d.ts +4 -0
  221. package/dist/runtime/events-api.js +84 -0
  222. package/dist/runtime/index.d.ts +5 -0
  223. package/dist/runtime/index.js +5 -0
  224. package/dist/runtime/looms.d.ts +74 -0
  225. package/dist/runtime/looms.js +109 -0
  226. package/dist/runtime/runtime-helpers.d.ts +51 -0
  227. package/dist/runtime/runtime-helpers.js +230 -0
  228. package/dist/runtime/runtime.d.ts +91 -0
  229. package/dist/runtime/runtime.js +531 -0
  230. package/dist/runtime/server.d.ts +17 -0
  231. package/dist/runtime/server.js +226 -0
  232. package/dist/runtime/sse.d.ts +15 -0
  233. package/dist/runtime/sse.js +96 -0
  234. package/dist/runtime/wake-scheduler.d.ts +8 -0
  235. package/dist/runtime/wake-scheduler.js +38 -0
  236. package/dist/s2/config.d.ts +27 -0
  237. package/dist/s2/config.js +54 -0
  238. package/dist/s2/index.d.ts +6 -0
  239. package/dist/s2/index.js +6 -0
  240. package/dist/s2/lite.d.ts +26 -0
  241. package/dist/s2/lite.js +150 -0
  242. package/dist/s2/projector.d.ts +8 -0
  243. package/dist/s2/projector.js +28 -0
  244. package/dist/s2/serialize.d.ts +1 -0
  245. package/dist/s2/serialize.js +1 -0
  246. package/dist/s2/snapshot-store.d.ts +17 -0
  247. package/dist/s2/snapshot-store.js +320 -0
  248. package/dist/s2/store.d.ts +35 -0
  249. package/dist/s2/store.js +337 -0
  250. package/dist/testing/index.d.ts +11 -0
  251. package/dist/testing/index.js +63 -0
  252. package/dist/workflow/definitions-store.d.ts +11 -0
  253. package/dist/workflow/definitions-store.js +8 -0
  254. package/dist/workflow/definitions.d.ts +82 -0
  255. package/dist/workflow/definitions.js +32 -0
  256. package/dist/workflow/effects.d.ts +305 -0
  257. package/dist/workflow/effects.js +208 -0
  258. package/dist/workflow/events.d.ts +60 -0
  259. package/dist/workflow/events.js +39 -0
  260. package/dist/workflow/index.d.ts +8 -0
  261. package/dist/workflow/index.js +8 -0
  262. package/dist/workflow/module.d.ts +926 -0
  263. package/dist/workflow/module.js +19 -0
  264. package/dist/workflow/projections.d.ts +30 -0
  265. package/dist/workflow/projections.js +43 -0
  266. package/dist/workflow/scope.d.ts +61 -0
  267. package/dist/workflow/scope.js +7 -0
  268. package/dist/workflow/threads.d.ts +171 -0
  269. package/dist/workflow/threads.js +287 -0
  270. package/package.json +183 -0
@@ -0,0 +1,5 @@
1
+ import type { JsonValue } from '@swirls/looms/core';
2
+ export declare function JsonView({ value, className }: {
3
+ value: JsonValue;
4
+ className?: string;
5
+ }): import("react").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from '../lib/cn.js';
3
+ export function JsonView({ value, className }) {
4
+ return (_jsx("pre", { className: cn('text-muted-foreground overflow-auto font-mono text-[11px] leading-relaxed wrap-break-word whitespace-pre-wrap', className), children: JSON.stringify(value, null, 2) }));
5
+ }
@@ -0,0 +1,14 @@
1
+ import type { ThreadNode } from '@swirls/looms/core';
2
+ export declare function RunTree({ runId, runStatus, tree, eventCounts, totalEventCount, selectedThread, onSelectThread, formatRunLabel, showHeading, }: {
3
+ runId: string;
4
+ runStatus: string;
5
+ tree: {
6
+ root: ThreadNode | null;
7
+ };
8
+ eventCounts: ReadonlyMap<string, number> | Map<string, number>;
9
+ totalEventCount?: number;
10
+ selectedThread?: string;
11
+ onSelectThread: (threadId: string | undefined) => void;
12
+ formatRunLabel?: (runId: string) => string;
13
+ showHeading?: boolean;
14
+ }): import("react").JSX.Element;
@@ -0,0 +1,38 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ChevronDown, ChevronRight } from 'lucide-react';
3
+ import { memo, useCallback, useState } from 'react';
4
+ import { cn, shortId } from '../lib/cn.js';
5
+ import { statusClass } from '../lib/status.js';
6
+ import { StatusDot } from './status-dot.js';
7
+ const NodeRow = memo(function NodeRow({ node, depth, selected, counts, collapsed, onToggle, onSelect, }) {
8
+ const hasChildren = node.children.length > 0;
9
+ const isCollapsed = collapsed.has(node.threadId);
10
+ const count = counts.get(node.threadId) ?? 0;
11
+ const handleToggle = useCallback(() => {
12
+ onToggle(node.threadId);
13
+ }, [onToggle, node.threadId]);
14
+ const handleSelect = useCallback(() => {
15
+ onSelect(node.threadId);
16
+ }, [onSelect, node.threadId]);
17
+ return (_jsxs("li", { className: "relative", children: [_jsxs("div", { className: cn('flex items-center gap-1 rounded-md py-0.5 pr-1 text-xs transition-colors', selected === node.threadId ? 'bg-accent font-medium' : 'hover:bg-accent/50'), style: { paddingLeft: 8 + depth * 14 }, children: [hasChildren ? (_jsx("button", { type: "button", className: "text-muted-foreground hover:text-foreground size-4 shrink-0", onClick: handleToggle, "aria-label": isCollapsed ? 'Expand thread' : 'Collapse thread', children: isCollapsed ? _jsx(ChevronRight, { className: "size-3" }) : _jsx(ChevronDown, { className: "size-3" }) })) : (_jsx("span", { className: "size-4 shrink-0" })), _jsxs("button", { type: "button", className: "flex min-w-0 flex-1 items-center gap-1.5 text-left", onClick: handleSelect, children: [_jsx(StatusDot, { status: node.status }), _jsxs("span", { className: "truncate", children: [_jsx("span", { className: "text-foreground font-medium", children: node.definitionName }), _jsxs("span", { className: "text-muted-foreground ml-1 font-mono text-[10px]", children: ["(", node.kind, ")"] })] }), _jsx("span", { className: cn('shrink-0 text-[10px]', statusClass(node.status)), children: node.status }), _jsx("span", { className: "text-muted-foreground ml-auto shrink-0 font-mono text-[10px]", children: count })] })] }), hasChildren && !isCollapsed ? (_jsx("ul", { className: "relative", children: node.children.map((child) => (_jsx(NodeRow, { node: child, depth: depth + 1, selected: selected, counts: counts, collapsed: collapsed, onToggle: onToggle, onSelect: onSelect }, child.threadId))) })) : null] }));
18
+ });
19
+ export function RunTree({ runId, runStatus, tree, eventCounts, totalEventCount, selectedThread, onSelectThread, formatRunLabel = shortId, showHeading = true, }) {
20
+ const [collapsed, setCollapsed] = useState(new Set());
21
+ const runCount = totalEventCount ?? eventCounts.get('run') ?? 0;
22
+ const toggle = useCallback((id) => {
23
+ setCollapsed((prev) => {
24
+ const next = new Set(prev);
25
+ if (next.has(id)) {
26
+ next.delete(id);
27
+ }
28
+ else {
29
+ next.add(id);
30
+ }
31
+ return next;
32
+ });
33
+ }, []);
34
+ const handleSelectRoot = useCallback(() => {
35
+ onSelectThread(undefined);
36
+ }, [onSelectThread]);
37
+ return (_jsxs("div", { children: [showHeading && (_jsx("h2", { className: "text-muted-foreground px-2 pb-1 text-[11px] font-medium tracking-wide uppercase", children: "Run tree" })), _jsxs("button", { type: "button", onClick: handleSelectRoot, className: cn('mb-0.5 flex w-full items-center gap-1.5 rounded-md px-2 py-1 text-left text-xs', !selectedThread ? 'bg-accent' : 'hover:bg-accent/50'), children: [_jsx(StatusDot, { status: runStatus }), _jsx("span", { className: "truncate font-mono", children: formatRunLabel(runId) }), _jsx("span", { className: cn('ml-auto', statusClass(runStatus)), children: runStatus }), _jsx("span", { className: "text-muted-foreground font-mono text-[10px]", children: runCount })] }), tree.root ? (_jsx("ul", { children: _jsx(NodeRow, { node: tree.root, depth: 0, selected: selectedThread, counts: eventCounts, collapsed: collapsed, onToggle: toggle, onSelect: onSelectThread }) })) : (_jsx("p", { className: "text-muted-foreground px-2 text-xs", children: "Waiting for threads\u2026" }))] }));
38
+ }
@@ -0,0 +1,3 @@
1
+ export declare function StatusDot({ status }: {
2
+ status: string;
3
+ }): import("react").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { statusDotClass } from '../lib/status.js';
3
+ export function StatusDot({ status }) {
4
+ return _jsx("span", { className: statusDotClass(status), "aria-hidden": true });
5
+ }
@@ -0,0 +1,22 @@
1
+ import type { EventEnvelope, JsonValue, ReplayStep, ThreadTree } from '@swirls/looms/core';
2
+ import type { EventFamily, EventSummary } from './events/family';
3
+ export type DebuggerEvent<TType extends string = string> = Pick<EventEnvelope<TType>, 'id' | 'runId' | 'seq' | 'ts' | 'type' | 'payload' | 'threadId' | 'causationId' | 'ephemeral'> & Partial<Pick<EventEnvelope<TType>, 'parentThreadId' | 'correlationId' | 'effectId' | 'origin'>>;
4
+ export type EventStreamCatalog<TEvent extends DebuggerEvent = DebuggerEvent> = {
5
+ families: readonly string[];
6
+ familyOf: (type: string) => string;
7
+ familyClass: (family: string) => string;
8
+ summarize: (event: TEvent) => EventSummary;
9
+ searchText?: (event: TEvent) => string;
10
+ };
11
+ export type ReplayLoader = (input: {
12
+ runId: string;
13
+ seq: number;
14
+ }) => Promise<ReplayStep | null>;
15
+ export type RunTreeModel = {
16
+ runId: string;
17
+ runStatus: string;
18
+ tree: ThreadTree;
19
+ eventCounts: Map<string, number>;
20
+ totalEventCount?: number;
21
+ };
22
+ export type { EventFamily, EventSummary, JsonValue, ReplayStep, ThreadTree };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ import type { DebuggerEvent, EventStreamCatalog } from '../contracts';
2
+ import { type EventSummary } from './family';
3
+ export declare function summarizeEvent(event: DebuggerEvent): EventSummary;
4
+ export declare function searchText<TEvent extends DebuggerEvent>(event: TEvent, summarize?: (event: TEvent) => EventSummary): string;
5
+ export declare function createDefaultCatalog<TEvent extends DebuggerEvent = DebuggerEvent>(): EventStreamCatalog<TEvent>;
6
+ export declare const defaultEventCatalog: EventStreamCatalog;
@@ -0,0 +1,27 @@
1
+ import { compactJson } from '../lib/cn.js';
2
+ import { summarizeDomainEvent } from './domain-summarize.js';
3
+ import { DEFAULT_FAMILIES, familyClass, familyFromPrefix } from './family.js';
4
+ import { summarizeProtocolEvent } from './protocol-summarize.js';
5
+ export function summarizeEvent(event) {
6
+ return (summarizeProtocolEvent(event) ??
7
+ summarizeDomainEvent(event) ?? {
8
+ title: event.type,
9
+ detail: compactJson(event.payload),
10
+ });
11
+ }
12
+ export function searchText(event, summarize = summarizeEvent) {
13
+ const summary = summarize(event);
14
+ return [event.type, event.threadId ?? '', summary.title, summary.detail ?? '', event.id]
15
+ .join(' ')
16
+ .toLowerCase();
17
+ }
18
+ export function createDefaultCatalog() {
19
+ return {
20
+ families: DEFAULT_FAMILIES,
21
+ familyOf: familyFromPrefix,
22
+ familyClass,
23
+ summarize: (event) => summarizeEvent(event),
24
+ searchText: (event) => searchText(event),
25
+ };
26
+ }
27
+ export const defaultEventCatalog = createDefaultCatalog();
@@ -0,0 +1,3 @@
1
+ import type { DebuggerEvent } from '../contracts';
2
+ import type { EventSummary } from './family';
3
+ export declare function summarizeDomainEvent(event: DebuggerEvent): EventSummary | undefined;
@@ -0,0 +1,107 @@
1
+ import { isJsonNumber, isJsonObject, isJsonString } from '@swirls/looms/core';
2
+ import { compactJson } from '../lib/cn.js';
3
+ function obj(value) {
4
+ return isJsonObject(value) ? value : {};
5
+ }
6
+ function text(value) {
7
+ return isJsonString(value) ? value : undefined;
8
+ }
9
+ function numeric(value) {
10
+ return isJsonNumber(value) ? String(value) : undefined;
11
+ }
12
+ function messageContent(payload) {
13
+ const message = obj(payload ?? null).message;
14
+ return isJsonObject(message) && isJsonString(message.content) ? message.content : undefined;
15
+ }
16
+ function toolCallSummary(payload) {
17
+ const call = obj(payload ?? null).toolCall;
18
+ if (!isJsonObject(call)) {
19
+ return { name: 'tool', args: null };
20
+ }
21
+ const summary = {
22
+ name: isJsonString(call.name) ? call.name : 'tool',
23
+ args: call.arguments ?? null,
24
+ };
25
+ return summary;
26
+ }
27
+ export function summarizeDomainEvent(event) {
28
+ const payload = obj(event.payload);
29
+ switch (event.type) {
30
+ case 'agent.message.received':
31
+ return { title: 'user message', detail: messageContent(event.payload) };
32
+ case 'agent.turn.started':
33
+ return { title: 'turn started', detail: `turn ${numeric(payload.turn) ?? ''}` };
34
+ case 'agent.turn.text_delta':
35
+ return { title: 'text delta', detail: text(payload.delta) };
36
+ case 'agent.message':
37
+ return { title: 'agent message', detail: messageContent(event.payload) };
38
+ case 'agent.tool_call.requested': {
39
+ const call = toolCallSummary(event.payload);
40
+ return { title: `tool ${call.name}`, detail: compactJson(call.args) };
41
+ }
42
+ case 'agent.tool.result':
43
+ return {
44
+ title: text(payload.error)
45
+ ? `tool error ${text(payload.name)}`
46
+ : `tool result ${text(payload.name)}`,
47
+ detail: text(payload.error) ?? compactJson(payload.result ?? null),
48
+ };
49
+ case 'agent.steered':
50
+ return { title: 'steered', detail: messageContent(event.payload) };
51
+ case 'agent.spawn.requested':
52
+ return {
53
+ title: 'agent spawn',
54
+ detail: `${text(payload.kind) ?? 'agent'}:${text(payload.definitionName) ?? 'unknown'}`,
55
+ };
56
+ case 'agent.effects.requested':
57
+ return { title: 'agent effects', detail: text(payload.toolCallId) };
58
+ case 'workflow.node.started':
59
+ return { title: 'node started', detail: text(payload.nodeId) };
60
+ case 'workflow.node.finished':
61
+ return {
62
+ title: text(payload.error) ? 'node failed' : 'node finished',
63
+ detail: text(payload.error) ??
64
+ `${text(payload.nodeId) ?? ''} ${compactJson(payload.result ?? null)}`,
65
+ };
66
+ case 'workflow.node.skipped':
67
+ return {
68
+ title: 'node skipped',
69
+ detail: `${text(payload.nodeId) ?? ''} · ${text(payload.reason) ?? ''}`,
70
+ };
71
+ case 'workflow.spawn.requested':
72
+ return {
73
+ title: 'workflow spawn',
74
+ detail: `${text(payload.definitionName) ?? 'unknown'} from ${text(payload.nodeId) ?? ''}`,
75
+ };
76
+ case 'workflow.sleep.requested':
77
+ return { title: 'sleep', detail: text(payload.nodeId) };
78
+ case 'workflow.effects.requested':
79
+ return { title: 'workflow effects', detail: text(payload.nodeId) };
80
+ case 'approval.requested':
81
+ return { title: 'approval requested', detail: text(payload.title) };
82
+ case 'approval.decided':
83
+ return {
84
+ title: `approval ${text(payload.outcome) ?? 'decided'}`,
85
+ detail: text(payload.approvalId),
86
+ };
87
+ case 'approval.timed_out':
88
+ return { title: 'approval timed out', detail: text(payload.approvalId) };
89
+ case 'payments.charge.requested':
90
+ return {
91
+ title: 'charge requested',
92
+ detail: `${numeric(payload.amount) ?? ''} ${text(payload.currency) ?? ''}`.trim(),
93
+ };
94
+ case 'payments.charge.authorized':
95
+ return {
96
+ title: 'charge authorized',
97
+ detail: `${numeric(payload.amount) ?? ''} ${text(payload.currency) ?? ''}`.trim(),
98
+ };
99
+ case 'payments.charge.declined':
100
+ return {
101
+ title: 'charge declined',
102
+ detail: `${numeric(payload.amount) ?? ''} ${text(payload.currency) ?? ''} · ${text(payload.reason) ?? ''}`.trim(),
103
+ };
104
+ default:
105
+ return undefined;
106
+ }
107
+ }
@@ -0,0 +1,8 @@
1
+ export declare const DEFAULT_FAMILIES: readonly ['runtime', 'agent', 'workflow', 'approval', 'payments', 'wait'];
2
+ export type EventFamily = (typeof DEFAULT_FAMILIES)[number];
3
+ export type EventSummary = {
4
+ title: string;
5
+ detail?: string;
6
+ };
7
+ export declare function familyFromPrefix(type: string): EventFamily;
8
+ export declare function familyClass(family: string): string;
@@ -0,0 +1,44 @@
1
+ export const DEFAULT_FAMILIES = [
2
+ 'runtime',
3
+ 'agent',
4
+ 'workflow',
5
+ 'approval',
6
+ 'payments',
7
+ 'wait',
8
+ ];
9
+ export function familyFromPrefix(type) {
10
+ if (type.startsWith('agent.')) {
11
+ return 'agent';
12
+ }
13
+ if (type.startsWith('workflow.')) {
14
+ return 'workflow';
15
+ }
16
+ if (type.startsWith('approval.')) {
17
+ return 'approval';
18
+ }
19
+ if (type.startsWith('payments.')) {
20
+ return 'payments';
21
+ }
22
+ if (type.startsWith('runtime.wait')) {
23
+ return 'wait';
24
+ }
25
+ return 'runtime';
26
+ }
27
+ export function familyClass(family) {
28
+ switch (family) {
29
+ case 'agent':
30
+ return 'bg-family-agent';
31
+ case 'workflow':
32
+ return 'bg-family-workflow';
33
+ case 'approval':
34
+ return 'bg-family-approval';
35
+ case 'payments':
36
+ return 'bg-family-payments';
37
+ case 'wait':
38
+ return 'bg-family-wait';
39
+ case 'runtime':
40
+ return 'bg-family-runtime';
41
+ default:
42
+ return 'bg-family-runtime';
43
+ }
44
+ }
@@ -0,0 +1,3 @@
1
+ import type { DebuggerEvent } from '../contracts';
2
+ import type { EventSummary } from './family';
3
+ export declare function summarizeProtocolEvent(event: DebuggerEvent): EventSummary | undefined;
@@ -0,0 +1,70 @@
1
+ import { isJsonNumber, isJsonObject, isJsonString, isProtocolType, } from '@swirls/looms/core';
2
+ import { compactJson } from '../lib/cn.js';
3
+ function obj(value) {
4
+ return isJsonObject(value) ? value : {};
5
+ }
6
+ function text(value) {
7
+ return isJsonString(value) ? value : undefined;
8
+ }
9
+ function numeric(value) {
10
+ return isJsonNumber(value) ? String(value) : undefined;
11
+ }
12
+ export function summarizeProtocolEvent(event) {
13
+ if (!isProtocolType(event.type)) {
14
+ return undefined;
15
+ }
16
+ const payload = obj(event.payload);
17
+ switch (event.type) {
18
+ case 'runtime.run.started':
19
+ return {
20
+ title: 'run started',
21
+ detail: `${text(payload.kind) ?? 'run'}:${text(payload.definitionName) ?? 'unknown'}`,
22
+ };
23
+ case 'runtime.run.completed':
24
+ return {
25
+ title: text(payload.error) ? 'run failed' : 'run completed',
26
+ detail: text(payload.error) ?? compactJson(payload.output ?? null),
27
+ };
28
+ case 'runtime.thread.started':
29
+ return {
30
+ title: 'thread started',
31
+ detail: `${text(payload.kind) ?? 'thread'}:${text(payload.definitionName) ?? 'unknown'}`,
32
+ };
33
+ case 'runtime.thread.completed':
34
+ return { title: 'thread completed', detail: compactJson(payload.output ?? null) };
35
+ case 'runtime.thread.failed':
36
+ return { title: 'thread failed', detail: text(payload.error) };
37
+ case 'runtime.thread.cancelled':
38
+ return { title: 'thread cancelled', detail: text(payload.reason) };
39
+ case 'runtime.wait.registered': {
40
+ const on = obj(payload.on ?? null);
41
+ const type = on.type;
42
+ const detail = isJsonString(type)
43
+ ? type
44
+ : Array.isArray(type)
45
+ ? type.filter(isJsonString).join(', ')
46
+ : isJsonNumber(on.timerAt)
47
+ ? `timer ${on.timerAt}`
48
+ : undefined;
49
+ return { title: 'wait registered', detail };
50
+ }
51
+ case 'runtime.wait.satisfied': {
52
+ const waited = obj(payload.event ?? null);
53
+ return { title: 'wait satisfied', detail: text(waited.type) };
54
+ }
55
+ case 'runtime.timer.set':
56
+ return { title: 'timer set', detail: numeric(payload.wakeAt) };
57
+ case 'runtime.timer.fired':
58
+ return { title: 'timer fired' };
59
+ case 'runtime.effect.failed':
60
+ return { title: 'effect failed', detail: text(payload.error) };
61
+ case 'runtime.snapshot.taken':
62
+ return { title: 'snapshot', detail: `seq ${numeric(payload.seq) ?? ''}` };
63
+ case 'runtime.signal.received':
64
+ return { title: 'signal', detail: compactJson(event.payload) };
65
+ default: {
66
+ const exhaustiveType = event.type;
67
+ return { title: 'event', detail: compactJson(obj(exhaustiveType)) };
68
+ }
69
+ }
70
+ }
@@ -0,0 +1,17 @@
1
+ export type { DebuggerEvent, EventFamily, EventStreamCatalog, EventSummary, ReplayLoader, ReplayStep, RunTreeModel, ThreadTree, } from './contracts';
2
+ export { DEFAULT_FAMILIES, familyClass, familyFromPrefix } from './events/family';
3
+ export { summarizeProtocolEvent } from './events/protocol-summarize';
4
+ export { summarizeDomainEvent } from './events/domain-summarize';
5
+ export { createDefaultCatalog, defaultEventCatalog, searchText, summarizeEvent, } from './events/catalog';
6
+ export { cn, compactJson, shortId } from './lib/cn';
7
+ export { statusClass, statusDotClass, type StatusKind } from './lib/status';
8
+ export { countEventsByThread, runStatusFromEvents, startedAtFromEvents } from './lib/event-counts';
9
+ export { projectRunView, type ProjectedRunView } from './lib/project-run';
10
+ export { StatusDot } from './components/status-dot';
11
+ export { JsonView } from './components/json-view';
12
+ export { RunTree } from './components/run-tree';
13
+ export { EventStream } from './components/event-stream';
14
+ export { EventInspector } from './components/event-inspector';
15
+ export { DebuggerSplit } from './components/debugger-split';
16
+ export { Checkbox } from './ui/checkbox';
17
+ export { ScrollArea, ScrollBar } from './ui/scroll-area';
@@ -0,0 +1,16 @@
1
+ export { DEFAULT_FAMILIES, familyClass, familyFromPrefix } from './events/family.js';
2
+ export { summarizeProtocolEvent } from './events/protocol-summarize.js';
3
+ export { summarizeDomainEvent } from './events/domain-summarize.js';
4
+ export { createDefaultCatalog, defaultEventCatalog, searchText, summarizeEvent, } from './events/catalog.js';
5
+ export { cn, compactJson, shortId } from './lib/cn.js';
6
+ export { statusClass, statusDotClass } from './lib/status.js';
7
+ export { countEventsByThread, runStatusFromEvents, startedAtFromEvents } from './lib/event-counts.js';
8
+ export { projectRunView } from './lib/project-run.js';
9
+ export { StatusDot } from './components/status-dot.js';
10
+ export { JsonView } from './components/json-view.js';
11
+ export { RunTree } from './components/run-tree.js';
12
+ export { EventStream } from './components/event-stream.js';
13
+ export { EventInspector } from './components/event-inspector.js';
14
+ export { DebuggerSplit } from './components/debugger-split.js';
15
+ export { Checkbox } from './ui/checkbox.js';
16
+ export { ScrollArea, ScrollBar } from './ui/scroll-area.js';
@@ -0,0 +1,5 @@
1
+ import { type ClassValue } from 'clsx';
2
+ import type { JsonValue } from '@swirls/looms/core';
3
+ export declare function cn(...inputs: ClassValue[]): string;
4
+ export declare function shortId(id: string): string;
5
+ export declare function compactJson(value: JsonValue): string;
@@ -0,0 +1,17 @@
1
+ import { clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+ export function cn(...inputs) {
4
+ return twMerge(clsx(inputs));
5
+ }
6
+ export function shortId(id) {
7
+ const cut = id.lastIndexOf('_');
8
+ const tail = cut >= 0 ? id.slice(cut + 1) : id;
9
+ return tail.length > 8 ? tail.slice(0, 8) : tail;
10
+ }
11
+ export function compactJson(value) {
12
+ const text = JSON.stringify(value);
13
+ if (text === undefined) {
14
+ return '';
15
+ }
16
+ return text.length > 96 ? `${text.slice(0, 93)}…` : text;
17
+ }
@@ -0,0 +1,5 @@
1
+ import { type EventEnvelope } from '@swirls/looms/core';
2
+ /** Build thread→count map via the shared EventIndex. */
3
+ export declare function countEventsByThread(events: readonly EventEnvelope[]): Map<string, number>;
4
+ export declare function runStatusFromEvents(events: readonly EventEnvelope[]): string;
5
+ export declare function startedAtFromEvents(events: readonly EventEnvelope[]): number | undefined;
@@ -0,0 +1,23 @@
1
+ import { EventIndex, isJsonObject, isJsonString } from '@swirls/looms/core';
2
+ /** Build thread→count map via the shared EventIndex. */
3
+ export function countEventsByThread(events) {
4
+ const index = new EventIndex();
5
+ index.append(events);
6
+ return new Map(index.getCounts());
7
+ }
8
+ export function runStatusFromEvents(events) {
9
+ for (let index = events.length - 1; index >= 0; index -= 1) {
10
+ const event = events[index];
11
+ if (!event || event.type !== 'runtime.run.completed') {
12
+ continue;
13
+ }
14
+ const payload = isJsonObject(event.payload) ? event.payload : {};
15
+ return isJsonString(payload.error) && payload.error.length > 0 ? 'failed' : 'completed';
16
+ }
17
+ return 'running';
18
+ }
19
+ export function startedAtFromEvents(events) {
20
+ const index = new EventIndex();
21
+ index.append(events);
22
+ return index.getStartedAt();
23
+ }
@@ -0,0 +1,8 @@
1
+ import type { DebuggerEvent, EventStreamCatalog } from '../contracts';
2
+ import type { EventSummary } from '../events/family';
3
+ export interface CachedEventMeta {
4
+ summary: EventSummary;
5
+ searchText: string;
6
+ family: string;
7
+ }
8
+ export declare function getEventMeta<TEvent extends DebuggerEvent>(event: TEvent, catalog?: EventStreamCatalog<TEvent>): CachedEventMeta;
@@ -0,0 +1,20 @@
1
+ import { searchText, summarizeEvent } from '../events/catalog.js';
2
+ const metaCache = new WeakMap();
3
+ export function getEventMeta(event, catalog) {
4
+ const existing = metaCache.get(event);
5
+ if (existing && existing.catalog === catalog) {
6
+ return existing.meta;
7
+ }
8
+ const family = catalog ? catalog.familyOf(event.type) : 'runtime';
9
+ const summary = catalog ? catalog.summarize(event) : summarizeEvent(event);
10
+ const text = catalog?.searchText
11
+ ? catalog.searchText(event)
12
+ : searchText(event, catalog ? catalog.summarize : summarizeEvent);
13
+ const meta = { summary, searchText: text, family };
14
+ metaCache.set(event, {
15
+ // SAFETY: EventStreamCatalog is covariant over event for cache identity compares.
16
+ catalog: catalog,
17
+ meta,
18
+ });
19
+ return meta;
20
+ }
@@ -0,0 +1,9 @@
1
+ import { type EventEnvelope, type ThreadTree } from '@swirls/looms/core';
2
+ export type ProjectedRunView = {
3
+ runId: string;
4
+ tree: ThreadTree;
5
+ eventCounts: Map<string, number>;
6
+ runStatus: string;
7
+ startedAt?: number;
8
+ };
9
+ export declare function projectRunView(events: readonly EventEnvelope[]): ProjectedRunView;
@@ -0,0 +1,14 @@
1
+ import { EventIndex, project, threadTree, toThreadTree, } from '@swirls/looms/core';
2
+ import { runStatusFromEvents } from './event-counts.js';
3
+ export function projectRunView(events) {
4
+ const index = new EventIndex();
5
+ index.append(events);
6
+ const tree = toThreadTree(project(threadTree, events));
7
+ return {
8
+ runId: events[0]?.runId ?? tree.runId,
9
+ tree,
10
+ eventCounts: new Map(index.getCounts()),
11
+ runStatus: runStatusFromEvents(events),
12
+ startedAt: index.getStartedAt(),
13
+ };
14
+ }
@@ -0,0 +1,3 @@
1
+ export type StatusKind = 'running' | 'waiting' | 'completed' | 'failed' | 'cancelled';
2
+ export declare function statusClass(status: string): string;
3
+ export declare function statusDotClass(status: string): string;
@@ -0,0 +1,31 @@
1
+ import { cn } from './cn.js';
2
+ export function statusClass(status) {
3
+ switch (status) {
4
+ case 'running':
5
+ return 'text-status-running';
6
+ case 'waiting':
7
+ return 'text-status-waiting';
8
+ case 'completed':
9
+ case 'approved':
10
+ case 'authorized':
11
+ return 'text-status-completed';
12
+ case 'failed':
13
+ case 'rejected':
14
+ case 'declined':
15
+ return 'text-status-failed';
16
+ default:
17
+ return 'text-status-cancelled';
18
+ }
19
+ }
20
+ export function statusDotClass(status) {
21
+ return cn('inline-block size-1.5 shrink-0 rounded-full', status === 'running' && 'bg-status-running animate-pulse', status === 'waiting' && 'bg-status-waiting', (status === 'completed' || status === 'approved' || status === 'authorized') &&
22
+ 'bg-status-completed', (status === 'failed' || status === 'rejected' || status === 'declined') && 'bg-status-failed', status !== 'running' &&
23
+ status !== 'waiting' &&
24
+ status !== 'completed' &&
25
+ status !== 'approved' &&
26
+ status !== 'authorized' &&
27
+ status !== 'failed' &&
28
+ status !== 'rejected' &&
29
+ status !== 'declined' &&
30
+ 'bg-status-cancelled');
31
+ }
@@ -0,0 +1,8 @@
1
+ import type { DebuggerEvent, EventStreamCatalog } from '../contracts';
2
+ export declare function useVisibleEvents<TEvent extends DebuggerEvent>({ events, query, families, threadId, catalog, }: {
3
+ events: readonly TEvent[];
4
+ query: string;
5
+ families: ReadonlySet<string>;
6
+ threadId?: string;
7
+ catalog: EventStreamCatalog<TEvent>;
8
+ }): readonly TEvent[];
@@ -0,0 +1,21 @@
1
+ import { useDeferredValue, useMemo } from 'react';
2
+ import { getEventMeta } from './event-meta.js';
3
+ export function useVisibleEvents({ events, query, families, threadId, catalog, }) {
4
+ const deferredQuery = useDeferredValue(query);
5
+ const q = deferredQuery.trim().toLowerCase();
6
+ return useMemo(() => {
7
+ return events.filter((event) => {
8
+ if (threadId && event.threadId !== threadId) {
9
+ return false;
10
+ }
11
+ const meta = getEventMeta(event, catalog);
12
+ if (!families.has(meta.family)) {
13
+ return false;
14
+ }
15
+ if (q && !meta.searchText.includes(q)) {
16
+ return false;
17
+ }
18
+ return true;
19
+ });
20
+ }, [events, q, families, threadId, catalog]);
21
+ }