@acpus/web 0.1.0-alpha.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 (141) hide show
  1. package/LICENSE +21 -0
  2. package/dist/.tsbuildinfo +1 -0
  3. package/dist/client/api.d.ts +398 -0
  4. package/dist/client/api.d.ts.map +1 -0
  5. package/dist/client/api.js +73 -0
  6. package/dist/client/api.js.map +1 -0
  7. package/dist/client/assets/index-Cn1qpJ2F.css +1 -0
  8. package/dist/client/assets/index-DVV3hISu.js +2 -0
  9. package/dist/client/assets/vendor-B7fc3-WT.js +69 -0
  10. package/dist/client/assets/vendor-icons-BQrCRas_.js +241 -0
  11. package/dist/client/assets/vendor-json-view-B9Z7D9kT.css +1 -0
  12. package/dist/client/assets/vendor-json-view-uYZpLE5K.js +1 -0
  13. package/dist/client/assets/vendor-query-Co8PPx4J.js +1 -0
  14. package/dist/client/assets/vendor-radix-C9JUg2bE.js +1 -0
  15. package/dist/client/assets/vendor-react-BRGuIgbw.js +49 -0
  16. package/dist/client/index.html +26 -0
  17. package/dist/client/lib/utils.d.ts +3 -0
  18. package/dist/client/lib/utils.d.ts.map +1 -0
  19. package/dist/client/lib/utils.js +6 -0
  20. package/dist/client/lib/utils.js.map +1 -0
  21. package/dist/client/main.d.ts +2 -0
  22. package/dist/client/main.d.ts.map +1 -0
  23. package/dist/client/main.js +18 -0
  24. package/dist/client/main.js.map +1 -0
  25. package/dist/client/static-viz.d.ts +8 -0
  26. package/dist/client/static-viz.d.ts.map +1 -0
  27. package/dist/client/static-viz.js +10 -0
  28. package/dist/client/static-viz.js.map +1 -0
  29. package/dist/client/ui/App.d.ts +40 -0
  30. package/dist/client/ui/App.d.ts.map +1 -0
  31. package/dist/client/ui/App.js +742 -0
  32. package/dist/client/ui/App.js.map +1 -0
  33. package/dist/client/ui/RunGraph.d.ts +9 -0
  34. package/dist/client/ui/RunGraph.d.ts.map +1 -0
  35. package/dist/client/ui/RunGraph.js +294 -0
  36. package/dist/client/ui/RunGraph.js.map +1 -0
  37. package/dist/client/ui/StaticGraphApp.d.ts +22 -0
  38. package/dist/client/ui/StaticGraphApp.d.ts.map +1 -0
  39. package/dist/client/ui/StaticGraphApp.js +102 -0
  40. package/dist/client/ui/StaticGraphApp.js.map +1 -0
  41. package/dist/client/ui/Toast.d.ts +16 -0
  42. package/dist/client/ui/Toast.d.ts.map +1 -0
  43. package/dist/client/ui/Toast.js +41 -0
  44. package/dist/client/ui/Toast.js.map +1 -0
  45. package/dist/client/ui/shadcn/alert.d.ts +3 -0
  46. package/dist/client/ui/shadcn/alert.d.ts.map +1 -0
  47. package/dist/client/ui/shadcn/alert.js +6 -0
  48. package/dist/client/ui/shadcn/alert.js.map +1 -0
  49. package/dist/client/ui/shadcn/badge.d.ts +10 -0
  50. package/dist/client/ui/shadcn/badge.d.ts.map +1 -0
  51. package/dist/client/ui/shadcn/badge.js +19 -0
  52. package/dist/client/ui/shadcn/badge.js.map +1 -0
  53. package/dist/client/ui/shadcn/breadcrumb.d.ts +9 -0
  54. package/dist/client/ui/shadcn/breadcrumb.d.ts.map +1 -0
  55. package/dist/client/ui/shadcn/breadcrumb.js +15 -0
  56. package/dist/client/ui/shadcn/breadcrumb.js.map +1 -0
  57. package/dist/client/ui/shadcn/button.d.ts +12 -0
  58. package/dist/client/ui/shadcn/button.d.ts.map +1 -0
  59. package/dist/client/ui/shadcn/button.js +37 -0
  60. package/dist/client/ui/shadcn/button.js.map +1 -0
  61. package/dist/client/ui/shadcn/card.d.ts +6 -0
  62. package/dist/client/ui/shadcn/card.d.ts.map +1 -0
  63. package/dist/client/ui/shadcn/card.js +10 -0
  64. package/dist/client/ui/shadcn/card.js.map +1 -0
  65. package/dist/client/ui/shadcn/dialog.d.ts +11 -0
  66. package/dist/client/ui/shadcn/dialog.d.ts.map +1 -0
  67. package/dist/client/ui/shadcn/dialog.js +15 -0
  68. package/dist/client/ui/shadcn/dialog.js.map +1 -0
  69. package/dist/client/ui/shadcn/input.d.ts +5 -0
  70. package/dist/client/ui/shadcn/input.d.ts.map +1 -0
  71. package/dist/client/ui/shadcn/input.js +6 -0
  72. package/dist/client/ui/shadcn/input.js.map +1 -0
  73. package/dist/client/ui/shadcn/list.d.ts +8 -0
  74. package/dist/client/ui/shadcn/list.d.ts.map +1 -0
  75. package/dist/client/ui/shadcn/list.js +8 -0
  76. package/dist/client/ui/shadcn/list.js.map +1 -0
  77. package/dist/client/ui/shadcn/popover.d.ts +8 -0
  78. package/dist/client/ui/shadcn/popover.d.ts.map +1 -0
  79. package/dist/client/ui/shadcn/popover.js +11 -0
  80. package/dist/client/ui/shadcn/popover.js.map +1 -0
  81. package/dist/client/ui/shadcn/select.d.ts +9 -0
  82. package/dist/client/ui/shadcn/select.d.ts.map +1 -0
  83. package/dist/client/ui/shadcn/select.js +17 -0
  84. package/dist/client/ui/shadcn/select.js.map +1 -0
  85. package/dist/client/ui/shadcn/tabs.d.ts +7 -0
  86. package/dist/client/ui/shadcn/tabs.d.ts.map +1 -0
  87. package/dist/client/ui/shadcn/tabs.js +12 -0
  88. package/dist/client/ui/shadcn/tabs.js.map +1 -0
  89. package/dist/client/ui/shadcn/textarea.d.ts +3 -0
  90. package/dist/client/ui/shadcn/textarea.d.ts.map +1 -0
  91. package/dist/client/ui/shadcn/textarea.js +6 -0
  92. package/dist/client/ui/shadcn/textarea.js.map +1 -0
  93. package/dist/graph-renderer.d.ts +114 -0
  94. package/dist/graph-renderer.d.ts.map +1 -0
  95. package/dist/graph-renderer.js +673 -0
  96. package/dist/graph-renderer.js.map +1 -0
  97. package/dist/index.d.ts +5 -0
  98. package/dist/index.d.ts.map +1 -0
  99. package/dist/index.js +5 -0
  100. package/dist/index.js.map +1 -0
  101. package/dist/runtime-status.d.ts +10 -0
  102. package/dist/runtime-status.d.ts.map +1 -0
  103. package/dist/runtime-status.js +45 -0
  104. package/dist/runtime-status.js.map +1 -0
  105. package/dist/server/app.d.ts +11 -0
  106. package/dist/server/app.d.ts.map +1 -0
  107. package/dist/server/app.js +244 -0
  108. package/dist/server/app.js.map +1 -0
  109. package/dist/server/assets.d.ts +3 -0
  110. package/dist/server/assets.d.ts.map +1 -0
  111. package/dist/server/assets.js +45 -0
  112. package/dist/server/assets.js.map +1 -0
  113. package/dist/server/errors.d.ts +14 -0
  114. package/dist/server/errors.d.ts.map +1 -0
  115. package/dist/server/errors.js +13 -0
  116. package/dist/server/errors.js.map +1 -0
  117. package/dist/server/graph.d.ts +137 -0
  118. package/dist/server/graph.d.ts.map +1 -0
  119. package/dist/server/graph.js +592 -0
  120. package/dist/server/graph.js.map +1 -0
  121. package/dist/server/launcher.d.ts +15 -0
  122. package/dist/server/launcher.d.ts.map +1 -0
  123. package/dist/server/launcher.js +30 -0
  124. package/dist/server/launcher.js.map +1 -0
  125. package/dist/server/node-inspection.d.ts +108 -0
  126. package/dist/server/node-inspection.d.ts.map +1 -0
  127. package/dist/server/node-inspection.js +435 -0
  128. package/dist/server/node-inspection.js.map +1 -0
  129. package/dist/server/security.d.ts +12 -0
  130. package/dist/server/security.d.ts.map +1 -0
  131. package/dist/server/security.js +43 -0
  132. package/dist/server/security.js.map +1 -0
  133. package/dist/server/static-viz-assets.generated.d.ts +3 -0
  134. package/dist/server/static-viz-assets.generated.d.ts.map +1 -0
  135. package/dist/server/static-viz-assets.generated.js +4 -0
  136. package/dist/server/static-viz-assets.generated.js.map +1 -0
  137. package/dist/server/workflows.d.ts +75 -0
  138. package/dist/server/workflows.d.ts.map +1 -0
  139. package/dist/server/workflows.js +205 -0
  140. package/dist/server/workflows.js.map +1 -0
  141. package/package.json +65 -0
@@ -0,0 +1,742 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { useEffect, useRef, useState } from "react";
4
+ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
5
+ import ReactMarkdown from "react-markdown";
6
+ import { allExpanded, defaultStyles, JsonView } from "react-json-view-lite";
7
+ import "react-json-view-lite/dist/index.css";
8
+ import remarkGfm from "remark-gfm";
9
+ import Activity from "lucide-react/dist/esm/icons/activity.js";
10
+ import Ban from "lucide-react/dist/esm/icons/ban.js";
11
+ import Boxes from "lucide-react/dist/esm/icons/boxes.js";
12
+ import CheckCircle2 from "lucide-react/dist/esm/icons/circle-check-big.js";
13
+ import ChevronRight from "lucide-react/dist/esm/icons/chevron-right.js";
14
+ import ChevronsLeft from "lucide-react/dist/esm/icons/chevrons-left.js";
15
+ import ChevronsRight from "lucide-react/dist/esm/icons/chevrons-right.js";
16
+ import CircleAlert from "lucide-react/dist/esm/icons/circle-alert.js";
17
+ import Clock from "lucide-react/dist/esm/icons/clock.js";
18
+ import Copy from "lucide-react/dist/esm/icons/copy.js";
19
+ import FileSearch from "lucide-react/dist/esm/icons/file-search.js";
20
+ import FileText from "lucide-react/dist/esm/icons/file-text.js";
21
+ import Folder from "lucide-react/dist/esm/icons/folder.js";
22
+ import LoaderCircle from "lucide-react/dist/esm/icons/loader-circle.js";
23
+ import Package from "lucide-react/dist/esm/icons/package.js";
24
+ import Pause from "lucide-react/dist/esm/icons/pause.js";
25
+ import Play from "lucide-react/dist/esm/icons/play.js";
26
+ import Radio from "lucide-react/dist/esm/icons/radio.js";
27
+ import RotateCcw from "lucide-react/dist/esm/icons/rotate-ccw.js";
28
+ import Search from "lucide-react/dist/esm/icons/search.js";
29
+ import Square from "lucide-react/dist/esm/icons/square.js";
30
+ import Workflow from "lucide-react/dist/esm/icons/workflow.js";
31
+ import XCircle from "lucide-react/dist/esm/icons/circle-x.js";
32
+ import { getConfig, getArtifactPreview, getHealth, getNodeExecutionInspection, getNodeInspection, getRunRuntimeSnapshot, listWorkflowCatalog, listWorkflowFiles, listRuns, submitRunCommand, visualizeWorkflow, } from "../api.js";
33
+ import { RunGraph } from "./RunGraph.js";
34
+ import { StaticGraphApp } from "./StaticGraphApp.js";
35
+ import { ToastViewport, useToasts } from "./Toast.js";
36
+ import { Button } from "./shadcn/button.js";
37
+ import { Alert } from "./shadcn/alert.js";
38
+ import { Badge } from "./shadcn/badge.js";
39
+ import { Breadcrumb, BreadcrumbButton, BreadcrumbItem, BreadcrumbList, BreadcrumbSeparator, } from "./shadcn/breadcrumb.js";
40
+ import { Card } from "./shadcn/card.js";
41
+ import { Dialog, DialogContent, DialogDescription, DialogTitle, } from "./shadcn/dialog.js";
42
+ import { Input } from "./shadcn/input.js";
43
+ import { List, ListRow } from "./shadcn/list.js";
44
+ import { Popover, PopoverClose, PopoverContent, PopoverTrigger, } from "./shadcn/popover.js";
45
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "./shadcn/select.js";
46
+ import { Tabs, TabsContent, TabsList, TabsTrigger, } from "./shadcn/tabs.js";
47
+ import { Textarea } from "./shadcn/textarea.js";
48
+ import { normalizeRuntimeStatus, runtimeStatusLabel } from "../../runtime-status.js";
49
+ const inspectorExitMs = 220;
50
+ const reducedMotionQuery = "(prefers-reduced-motion: reduce)";
51
+ export function App() {
52
+ const [page, setPage] = useState("runtime");
53
+ const [selectedRunId, setSelectedRunId] = useState();
54
+ const [graphTarget, setGraphTarget] = useState();
55
+ const [statusOpen, setStatusOpen] = useState(false);
56
+ const [sidebarCollapsed, setSidebarCollapsed] = useState(true);
57
+ const runs = useQuery({
58
+ queryKey: ["runs"],
59
+ queryFn: listRuns,
60
+ refetchInterval: 4_000,
61
+ });
62
+ const health = useQuery({
63
+ queryKey: ["health"],
64
+ queryFn: getHealth,
65
+ refetchInterval: 5_000,
66
+ });
67
+ const config = useQuery({
68
+ queryKey: ["config"],
69
+ queryFn: getConfig,
70
+ });
71
+ useEffect(() => {
72
+ if (!selectedRunId && runs.data?.[0])
73
+ setSelectedRunId(runs.data[0].id);
74
+ }, [runs.data, selectedRunId]);
75
+ return (_jsxs("main", { className: `app-shell ${sidebarCollapsed ? "sidebar-collapsed" : ""}`, children: [_jsxs("aside", { className: "sidebar", children: [_jsxs("div", { className: "sidebar-head", children: [_jsxs("div", { className: "brand", children: [_jsx("div", { className: "brand-mark", children: _jsx(Workflow, { size: 19 }) }), _jsx("div", { className: "brand-copy", children: _jsx("h1", { children: "Acpus" }) })] }), _jsx(Button, { type: "button", variant: "ghost", className: "sidebar-toggle", "aria-label": sidebarCollapsed ? "Expand sidebar" : "Collapse sidebar", title: sidebarCollapsed ? "Expand sidebar" : "Collapse sidebar", onClick: () => setSidebarCollapsed(current => !current), children: sidebarCollapsed ? _jsx(ChevronsRight, { size: 16 }) : _jsx(ChevronsLeft, { size: 16 }) })] }), _jsxs("nav", { className: "nav-list", children: [_jsx(NavButton, { icon: _jsx(Activity, { size: 17 }), label: "Runtime", active: page === "runtime", onClick: () => setPage("runtime") }), _jsx(NavButton, { icon: _jsx(FileSearch, { size: 17 }), label: "Workflows", active: page === "workflows", onClick: () => setPage("workflows") })] }), _jsxs(Popover, { open: statusOpen, onOpenChange: setStatusOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(SidebarStatus, { health: health.data, config: config.data }) }), _jsx(StatusInfoPopover, { health: health.data, config: config.data })] })] }), _jsxs("section", { className: "workspace", children: [page === "runtime" && (_jsx(RuntimePage, { runId: selectedRunId, runs: runs.data ?? [], selectedTarget: graphTarget, onSelectRun: id => {
76
+ setSelectedRunId(id);
77
+ setGraphTarget(undefined);
78
+ }, onSelectTarget: setGraphTarget })), page === "workflows" && _jsx(WorkflowsPage, {})] })] }));
79
+ }
80
+ function RuntimePage({ runId, runs, selectedTarget, onSelectRun, onSelectTarget, }) {
81
+ const queryClient = useQueryClient();
82
+ const { toasts, push, dismiss } = useToasts();
83
+ const { exiting, close, layoutState } = useInspectorPresence(selectedTarget, () => onSelectTarget(undefined));
84
+ const selectedNodeId = selectedTarget?.kind === "node" ? selectedTarget.id : undefined;
85
+ const selectedNodeContext = selectedTarget?.kind === "node" ? selectedTarget.context : [];
86
+ const selectedNodeDisplayStatus = selectedTarget?.kind === "node" ? selectedTarget.displayStatus : undefined;
87
+ const snapshot = useQuery({
88
+ queryKey: ["run-runtime-snapshot", runId],
89
+ queryFn: () => getRunRuntimeSnapshot(runId),
90
+ enabled: Boolean(runId),
91
+ refetchInterval: query => isTerminalRunStatus(query.state.data?.run.status) ? false : 1_000,
92
+ });
93
+ const inspection = useQuery({
94
+ queryKey: ["node-inspection", runId, selectedNodeId, selectedNodeContext],
95
+ queryFn: () => getNodeInspection(runId, selectedNodeId, selectedNodeContext),
96
+ enabled: Boolean(runId && selectedNodeId),
97
+ refetchInterval: 2_500,
98
+ });
99
+ const command = useMutation({
100
+ mutationFn: (input) => submitRunCommand(runId, input),
101
+ onSuccess: async (_data, variables) => {
102
+ push({ tone: "success", title: `${commandLabel(variables)} accepted` });
103
+ await Promise.all([
104
+ queryClient.invalidateQueries({ queryKey: ["run", runId] }),
105
+ queryClient.invalidateQueries({ queryKey: ["run-runtime-snapshot", runId] }),
106
+ queryClient.invalidateQueries({ queryKey: ["runs"] }),
107
+ ]);
108
+ },
109
+ onError: (error, variables) => {
110
+ push({ tone: "error", title: `${commandLabel(variables)} failed`, detail: error instanceof Error ? error.message : String(error) });
111
+ },
112
+ });
113
+ const runDetails = snapshot.data?.run;
114
+ const signalWait = selectedTarget?.kind === "node"
115
+ ? inspection.data?.signalWaits.find(w => w.status === "awaiting")
116
+ : undefined;
117
+ const retryTargets = retryTargetsForRun(runDetails);
118
+ const retryTargetSignature = retryTargets.map(target => target.value).join("|");
119
+ const [retryTarget, setRetryTarget] = useState();
120
+ useEffect(() => {
121
+ const values = new Set(retryTargets.map(target => target.value));
122
+ setRetryTarget(current => current && values.has(current) ? current : retryTargets[0]?.value);
123
+ }, [retryTargetSignature]);
124
+ if (!runId)
125
+ return _jsx(EmptyState, { title: "No Run Selected", detail: "Open Runs to choose a durable run." });
126
+ const headerState = runHeaderViewState(runDetails, snapshot.error);
127
+ return (_jsxs("div", { className: "runtime-grid", children: [_jsxs("header", { className: "topbar", children: [_jsx("div", { className: "run-titlebar", children: headerState.kind === "ready" ? (_jsxs(_Fragment, { children: [_jsx("h2", { children: headerState.run.name }), _jsxs("div", { className: "run-meta", children: [_jsx(RunStatusIndicator, { status: headerState.run.status }), _jsx("span", { children: runId }), headerState.run.updatedAt && _jsx("span", { children: formatDate(headerState.run.updatedAt) })] })] })) : headerState.kind === "error" ? (_jsx(RunHeaderError, { message: headerState.message })) : (_jsx(RunHeaderSkeleton, {})) }), _jsxs("div", { className: "run-header-actions", children: [_jsx(RunSelector, { runs: runs, selectedRunId: runId, onSelectRun: onSelectRun }), _jsx(RunControls, { disabled: !runDetails || command.isPending, status: runDetails?.status, selectedNodeId: selectedNodeId, retryTargets: retryTargets, selectedRetryTarget: retryTarget, onSelectRetryTarget: setRetryTarget, onCommand: input => command.mutate(input) })] })] }), _jsxs("div", { className: `graph-inspection-layout ${layoutState === "open" ? "with-inspector" : layoutState === "closing" ? "closing-inspector" : ""}`, children: [_jsx("section", { className: "graph-panel", children: _jsx(RunGraph, { graph: snapshot.data?.graph, ...(selectedNodeId === undefined ? {} : { selectedNodeId }), onSelectNode: (id, context = [], displayStatus) => onSelectTarget(id ? { kind: "node", id, context, ...(displayStatus ? { displayStatus } : {}) } : undefined), onSelectWorkflow: () => onSelectTarget({ kind: "workflow" }) }) }), selectedTarget && (_jsx("div", { className: "inspector-slot", children: _jsxs(InspectorPanel, { title: selectedTarget.kind === "workflow" ? "Workflow I/O" : inspection.data?.summary.nodeId ?? selectedNodeId ?? "Node", exiting: exiting, onClose: close, children: [selectedTarget.kind === "workflow" ? (_jsx(RuntimeWorkflowInspector, { run: runDetails })) : (_jsx(Inspector, { runId: runId, target: selectedNodeId, context: selectedNodeContext, displayStatus: selectedNodeDisplayStatus, inspection: inspection.data, loading: inspection.isLoading })), selectedTarget.kind === "node" && signalWait && (_jsx(SignalBox, { wait: signalWait, onSubmit: payload => command.mutate({ type: "signal", target: signalWait.nodeKey, payload }) }))] }) }))] }), _jsx(ToastViewport, { toasts: toasts, onDismiss: dismiss })] }));
128
+ }
129
+ export function runHeaderViewState(run, error) {
130
+ if (run)
131
+ return { kind: "ready", run };
132
+ if (error)
133
+ return { kind: "error", message: error instanceof Error ? error.message : String(error) };
134
+ return { kind: "loading" };
135
+ }
136
+ function RunHeaderSkeleton() {
137
+ return (_jsxs("div", { className: "run-header-skeleton", role: "status", "aria-label": "Loading run details", "aria-busy": "true", children: [_jsx("span", { className: "state-skeleton-line title", "aria-hidden": "true" }), _jsx("span", { className: "state-skeleton-line meta", "aria-hidden": "true" })] }));
138
+ }
139
+ function RunHeaderError({ message }) {
140
+ return (_jsxs("div", { className: "run-header-error", role: "alert", children: [_jsx("strong", { children: "Run details unavailable" }), _jsx("span", { children: message })] }));
141
+ }
142
+ function commandLabel(input) {
143
+ return typeof input.type === "string" ? input.type : "command";
144
+ }
145
+ function useInspectorPresence(target, onExited) {
146
+ const [exiting, setExiting] = useState(false);
147
+ const timerRef = useRef(undefined);
148
+ useEffect(() => {
149
+ setExiting(false);
150
+ if (timerRef.current !== undefined) {
151
+ window.clearTimeout(timerRef.current);
152
+ timerRef.current = undefined;
153
+ }
154
+ }, [target]);
155
+ useEffect(() => () => {
156
+ if (timerRef.current !== undefined)
157
+ window.clearTimeout(timerRef.current);
158
+ }, []);
159
+ const close = () => {
160
+ if (!target || exiting)
161
+ return;
162
+ if (window.matchMedia(reducedMotionQuery).matches) {
163
+ setExiting(false);
164
+ onExited();
165
+ return;
166
+ }
167
+ setExiting(true);
168
+ timerRef.current = window.setTimeout(() => {
169
+ timerRef.current = undefined;
170
+ setExiting(false);
171
+ onExited();
172
+ }, inspectorExitMs);
173
+ };
174
+ return { exiting, layoutState: target ? exiting ? "closing" : "open" : "closed", close };
175
+ }
176
+ function WorkflowsPage() {
177
+ const [dir, setDir] = useState("");
178
+ const [source, setSource] = useState();
179
+ const [result, setResult] = useState();
180
+ const catalog = useQuery({
181
+ queryKey: ["workflow-catalog"],
182
+ queryFn: listWorkflowCatalog,
183
+ });
184
+ const files = useQuery({
185
+ queryKey: ["workflow-files", dir],
186
+ queryFn: () => listWorkflowFiles(dir),
187
+ });
188
+ const visualize = useMutation({
189
+ mutationFn: (next) => visualizeWorkflow(next),
190
+ onSuccess: next => {
191
+ setResult(next);
192
+ },
193
+ });
194
+ const graph = result?.status === "ready" ? result.graph : undefined;
195
+ return (_jsxs("div", { className: "workflow-viz-grid", children: [_jsxs("section", { className: "table-panel workflow-source-panel", children: [_jsx(PageHeader, { title: "Workflows", detail: "Static Visualization" }), _jsx(WorkflowSourcePicker, { catalog: catalog.data ?? [], catalogLoading: catalog.isLoading, catalogError: catalog.error, files: files.data?.entries ?? [], filesLoading: files.isLoading, filesError: files.error, dir: files.data?.dir ?? dir, selected: source, visualizing: visualize.isPending, visualizeError: visualize.error, visualizationFailure: result?.status === "failed" ? result : undefined, onOpenDir: setDir, onSelect: next => {
196
+ setSource(next);
197
+ setResult(undefined);
198
+ }, onVisualize: () => source && visualize.mutate(source) })] }), graph && result?.status === "ready" ? (_jsx(StaticGraphApp, { data: result })) : (_jsx("section", { className: "graph-panel", children: _jsx(EmptyState, { title: "No Workflow Visualized", detail: "Choose a catalog entry or workspace workflow file, then click Visualize." }) }))] }));
199
+ }
200
+ function WorkflowSourcePicker({ catalog, catalogLoading, catalogError, files, filesLoading, filesError, dir, selected, visualizing, visualizeError, visualizationFailure, onOpenDir, onSelect, onVisualize, }) {
201
+ const [activeTab, setActiveTab] = useState("catalog");
202
+ const selectedSummary = describeWorkflowSource(selected);
203
+ return (_jsxs("div", { className: "workflow-picker", children: [_jsxs(Tabs, { value: activeTab, onValueChange: value => setActiveTab(value), className: "workflow-picker-tabs", children: [_jsxs(TabsList, { className: "workflow-picker-tabs-list", "aria-label": "Workflow source type", children: [_jsx(TabsTrigger, { value: "catalog", children: "Catalog" }), _jsx(TabsTrigger, { value: "files", children: "Files" })] }), _jsx(TabsContent, { value: "catalog", className: "workflow-picker-tab-panel", children: _jsx(WorkflowCatalogList, { entries: catalog, loading: catalogLoading, error: catalogError, selected: selected, onSelect: onSelect }) }), _jsx(TabsContent, { value: "files", className: "workflow-picker-tab-panel", children: _jsx(WorkflowFileSelector, { entries: files, loading: filesLoading, error: filesError, dir: dir, selected: selected, onOpenDir: onOpenDir, onSelect: onSelect }) })] }), _jsxs("div", { className: "workflow-picker-footer", children: [_jsxs("div", { className: `workflow-selected-source ${selected ? "selected" : ""}`, children: [_jsx("span", { children: "Selected source" }), _jsx("strong", { children: selectedSummary.title }), selectedSummary.detail && _jsx("small", { children: selectedSummary.detail })] }), _jsx(Button, { variant: "default", className: "primary-button", disabled: !selected || visualizing, onClick: onVisualize, children: visualizing ? "Visualizing..." : "Visualize" }), visualizeError ? (_jsx(StateBlock, { tone: "error", title: "Visualization failed", detail: visualizeError instanceof Error ? visualizeError.message : String(visualizeError) })) : null, visualizationFailure && (_jsx(StateBlock, { tone: "error", title: `${visualizationFailure.phase} failed`, detail: visualizationFailure.message }))] })] }));
204
+ }
205
+ function WorkflowCatalogList({ entries, loading, error, selected, onSelect, }) {
206
+ if (loading)
207
+ return _jsx(StateBlock, { tone: "loading", title: "Loading catalog" });
208
+ if (error)
209
+ return _jsx(StateBlock, { tone: "error", title: "Catalog unavailable", detail: error instanceof Error ? error.message : String(error) });
210
+ if (entries.length === 0) {
211
+ return _jsx(StateBlock, { tone: "empty", title: "No catalog workflows", detail: "Use Files to choose a workflow module from this workspace." });
212
+ }
213
+ return (_jsx(List, { className: "workflow-source-table", "aria-label": "Project catalog workflows", children: entries.map(entry => {
214
+ const active = selected?.kind === "catalog" && selected.name === entry.name;
215
+ return (_jsxs(ListRow, { className: `workflow-list-row catalog ${active ? "selected" : ""}`, "aria-pressed": active, onClick: () => onSelect({ kind: "catalog", name: entry.name }), children: [_jsx(Package, { size: 15 }), _jsxs("span", { className: "workflow-row-main", children: [_jsx("strong", { children: entry.name }), _jsx("small", { children: compactWorkflowPath(entry.entryPath) })] }), _jsx(Badge, { className: "workflow-row-badge", children: "project" })] }, entry.name));
216
+ }) }));
217
+ }
218
+ function WorkflowFileSelector({ entries, loading, error, dir, selected, onOpenDir, onSelect, }) {
219
+ const [filter, setFilter] = useState("");
220
+ const normalizedFilter = filter.trim().toLowerCase();
221
+ const visibleEntries = normalizedFilter
222
+ ? entries.filter(entry => `${entry.name} ${entry.path}`.toLowerCase().includes(normalizedFilter))
223
+ : entries;
224
+ return (_jsxs("div", { className: "workflow-file-selector", children: [_jsxs("div", { className: "workflow-file-toolbar", children: [_jsx(WorkflowBreadcrumb, { dir: dir, onOpenDir: onOpenDir }), _jsxs("label", { className: "workflow-filter", children: [_jsx(Search, { size: 14, "aria-hidden": "true" }), _jsx(Input, { value: filter, onChange: event => setFilter(event.currentTarget.value), placeholder: "Filter current directory", "aria-label": "Filter current directory" })] })] }), loading ? (_jsx(StateBlock, { tone: "loading", title: "Loading workspace files" })) : error ? (_jsx(StateBlock, { tone: "error", title: "Files unavailable", detail: error instanceof Error ? error.message : String(error) })) : visibleEntries.length === 0 ? (_jsx(StateBlock, { tone: "empty", title: "No workflow files here", detail: filter ? "Clear the filter or open another directory." : "Open a directory that contains .workflow.ts or .workflow.tsx files." })) : (_jsx(List, { className: "workflow-source-table", "aria-label": "Workspace workflow files", children: visibleEntries.map(entry => {
225
+ const active = selected?.kind === "file" && selected.path === entry.path;
226
+ const directory = entry.kind === "directory";
227
+ return (_jsxs(ListRow, { className: `workflow-list-row file ${directory ? "directory" : "workflow"} ${active ? "selected" : ""}`, "aria-pressed": active, onClick: () => directory ? onOpenDir(entry.path) : onSelect({ kind: "file", path: entry.path }), children: [directory ? _jsx(Folder, { size: 15 }) : _jsx(FileText, { size: 15 }), _jsxs("span", { className: "workflow-row-main", children: [_jsx("strong", { children: entry.name }), _jsx("small", { children: entry.path })] }), _jsx(Badge, { className: "workflow-row-badge", children: directory ? "directory" : "workflow" }), directory && _jsx(ChevronRight, { size: 14, className: "workflow-row-chevron", "aria-hidden": "true" })] }, `${entry.kind}:${entry.path}`));
228
+ }) }))] }));
229
+ }
230
+ function WorkflowBreadcrumb({ dir, onOpenDir }) {
231
+ const segments = dir.split("/").filter(Boolean);
232
+ const targets = segments.map((_segment, index) => segments.slice(0, index + 1).join("/"));
233
+ return (_jsx(Breadcrumb, { "aria-label": "Workspace path", className: "workflow-breadcrumb", children: _jsxs(BreadcrumbList, { children: [_jsx(BreadcrumbItem, { children: _jsx(BreadcrumbButton, { "aria-current": dir.length === 0 ? "page" : undefined, onClick: () => onOpenDir(""), children: "Workspace" }) }), segments.map((segment, index) => {
234
+ const target = targets[index];
235
+ return (_jsxs(React.Fragment, { children: [_jsx(BreadcrumbSeparator, { children: _jsx(ChevronRight, { size: 13 }) }), _jsx(BreadcrumbItem, { children: _jsx(BreadcrumbButton, { "aria-current": target === dir ? "page" : undefined, onClick: () => onOpenDir(target), children: segment }) })] }, target));
236
+ })] }) }));
237
+ }
238
+ function describeWorkflowSource(source) {
239
+ if (!source)
240
+ return { title: "None selected", detail: "Choose from Catalog or Files." };
241
+ if (source.kind === "catalog")
242
+ return { title: source.name, detail: "Project catalog entry" };
243
+ return { title: fileNameFromPath(source.path), detail: source.path };
244
+ }
245
+ function fileNameFromPath(path) {
246
+ return path.split("/").filter(Boolean).at(-1) ?? path;
247
+ }
248
+ function compactWorkflowPath(path) {
249
+ const workflowMarker = "/.acpus/workflows/";
250
+ const workflowIndex = path.indexOf(workflowMarker);
251
+ if (workflowIndex >= 0)
252
+ return `.acpus/workflows/${path.slice(workflowIndex + workflowMarker.length)}`;
253
+ const packageMarker = "/packages/";
254
+ const packageIndex = path.indexOf(packageMarker);
255
+ if (packageIndex >= 0)
256
+ return `packages/${path.slice(packageIndex + packageMarker.length)}`;
257
+ return path;
258
+ }
259
+ function RuntimeWorkflowInspector({ run }) {
260
+ if (!run)
261
+ return _jsx(StateBlock, { tone: "loading", title: "Loading workflow I/O" });
262
+ const hasOutput = run.output !== undefined;
263
+ const terminal = isTerminalRunStatus(run.status);
264
+ return (_jsxs("div", { className: "inspector-stack", children: [_jsxs(InspectorSection, { title: "Workflow", children: [_jsx(KeyValue, { label: "Name", value: run.name }), _jsx(KeyValue, { label: "Run ID", value: run.id }), _jsx(KeyValue, { label: "Status", value: runtimeStatusLabel(normalizeRuntimeStatus(run.status)) }), run.dynamic?.version !== undefined && _jsx(KeyValue, { label: "Runtime version", value: String(run.dynamic.version) }), _jsx(KeyValue, { label: "Started", value: formatDate(run.createdAt) }), _jsx(KeyValue, { label: "Updated", value: formatDate(run.updatedAt) }), _jsx(KeyValue, { label: "Duration", value: formatDuration(durationBetween(run.createdAt, run.updatedAt)) })] }), _jsx(JsonSection, { title: "Input", value: run.input }), hasOutput
265
+ ? _jsx(JsonSection, { title: "Output", value: run.output })
266
+ : (_jsx(InspectorSection, { title: "Output", children: _jsx(StateBlock, { tone: "empty", title: terminal ? "No workflow output recorded" : "Output pending", detail: terminal ? "The run reached a terminal state without a workflow output value." : "Workflow output is available after the run completes." }) }))] }));
267
+ }
268
+ function StaticWorkflowInspector({ result }) {
269
+ return (_jsxs("div", { className: "inspector-stack", children: [_jsxs(InspectorSection, { title: "Workflow", children: [_jsx(KeyValue, { label: "Name", value: result.workflow.name }), result.workflow.description && _jsx(KeyValue, { label: "Description", value: result.workflow.description }), _jsx(KeyValue, { label: "IR version", value: String(result.workflow.irVersion) }), _jsx(KeyValue, { label: "Node count", value: String(result.workflow.nodeCount) }), _jsx(KeyValue, { label: "IR digest", value: result.irDigest }), _jsx(KeyValue, { label: "Source digest", value: result.sourceGraphDigest })] }), result.contract.inputSchema
270
+ ? _jsx(JsonSection, { title: "Input Contract", value: result.contract.inputSchema })
271
+ : (_jsx(InspectorSection, { title: "Input Contract", children: _jsx(StateBlock, { tone: "empty", title: "No input contract", detail: "This workflow does not declare an input schema." }) })), _jsx(JsonSection, { title: "Output Mapping", value: result.contract.outputs })] }));
272
+ }
273
+ function StaticGraphInspector({ graph, target }) {
274
+ if (!graph || !target)
275
+ return _jsx(StateBlock, { tone: "empty", title: "Select a graph node", detail: "Node details appear here after selection." });
276
+ const node = graph.nodes.find(item => item.id === target);
277
+ const container = graph.containers.find(item => item.id === target);
278
+ if (!node && !container)
279
+ return _jsx(StateBlock, { tone: "empty", title: "No graph detail", detail: "The selected graph target is no longer available." });
280
+ return (_jsxs("div", { className: "inspector-stack", children: [_jsxs(InspectorSection, { title: "Identity", children: [_jsx(KeyValue, { label: "Kind", value: node?.kind ?? container?.kind ?? "unknown" }), _jsx(KeyValue, { label: "Node ID", value: node?.nodeId ?? container?.nodeId ?? target }), _jsx(KeyValue, { label: "Path", value: (node?.path ?? container?.path ?? []).join(" / ") })] }), node?.detail && (_jsx(JsonSection, { title: "Definition", value: node.detail }))] }));
281
+ }
282
+ function InspectorPanel({ title, exiting = false, onClose, children, }) {
283
+ useEffect(() => {
284
+ const onKeyDown = (event) => {
285
+ if (event.key === "Escape")
286
+ onClose();
287
+ };
288
+ window.addEventListener("keydown", onKeyDown);
289
+ return () => window.removeEventListener("keydown", onKeyDown);
290
+ }, [onClose]);
291
+ return (_jsx(Card, { asChild: true, className: `inspector-card ${exiting ? "exiting" : ""}`, children: _jsxs("aside", { role: "dialog", "aria-label": title, children: [_jsxs("div", { className: "inspector-card-head", children: [_jsxs("div", { children: [_jsx("span", { children: "Inspector" }), _jsx("strong", { children: title })] }), _jsx(Button, { variant: "ghost", className: "close-button", onClick: onClose, "aria-label": "Close inspector", children: _jsx(XCircle, { size: 16 }) })] }), _jsx("div", { className: "inspector-card-body", children: children })] }) }));
292
+ }
293
+ function RunControls({ disabled, status, selectedNodeId, retryTargets, selectedRetryTarget, onSelectRetryTarget, onCommand, }) {
294
+ const controls = controlStateForRun(status, disabled, retryTargets);
295
+ const retryTarget = retryCommandTarget(retryTargets, selectedRetryTarget);
296
+ const [pendingControl, setPendingControl] = useState();
297
+ const retryTargetLabel = retryTargets.find(target => target.value === retryTarget)?.label;
298
+ return (_jsxs("div", { className: "control-strip", children: [retryTargets.length > 1 && controls.some(control => control.id === "retry") && (_jsxs(Select, { value: selectedRetryTarget ?? retryTargets[0]?.value ?? "", disabled: disabled, onValueChange: onSelectRetryTarget, children: [_jsx(SelectTrigger, { className: "retry-target-select", "aria-label": "Retry target", title: "Retry target", children: _jsx(SelectValue, { placeholder: "Retry target" }) }), _jsx(SelectContent, { children: retryTargets.map(target => _jsx(SelectItem, { value: target.value, children: target.label }, target.value)) })] })), controls.map(control => {
299
+ const command = commandForControl(control.id, retryTarget, selectedNodeId);
300
+ const commandDisabled = control.id === "retry" && !command;
301
+ return (_jsx(IconButton, { label: control.label, title: control.title, tone: control.tone, icon: controlIcon(control.id), disabled: control.disabled || commandDisabled, onClick: () => {
302
+ if (!command)
303
+ return;
304
+ setPendingControl({
305
+ control,
306
+ command,
307
+ targetLabel: control.id === "retry" ? retryTargetLabel : selectedNodeId,
308
+ restoreFocus: document.activeElement instanceof HTMLElement ? document.activeElement : undefined,
309
+ });
310
+ } }, control.id));
311
+ }), pendingControl && (_jsx(ConfirmDialog, { confirmation: confirmationForControl(pendingControl.control.id, pendingControl.targetLabel), restoreFocus: pendingControl.restoreFocus, onCancel: () => setPendingControl(undefined), onConfirm: () => {
312
+ onCommand(pendingControl.command);
313
+ setPendingControl(undefined);
314
+ } }))] }));
315
+ }
316
+ function RunSelector({ runs, selectedRunId, onSelectRun, }) {
317
+ return (_jsxs("label", { className: "run-select-wrap", children: [_jsx("span", { children: "Run" }), _jsxs(Select, { ...(selectedRunId ? { value: selectedRunId } : {}), disabled: runs.length === 0, onValueChange: onSelectRun, children: [_jsx(SelectTrigger, { className: "run-select", "aria-label": "Select run", children: _jsx(SelectValue, { placeholder: "No runs" }) }), _jsx(SelectContent, { children: runs.map(run => (_jsxs(SelectItem, { value: run.id, children: [run.name, " \u00B7 ", runtimeStatusLabel(normalizeRuntimeStatus(run.status))] }, run.id))) })] })] }));
318
+ }
319
+ export function retryTargetsForRun(run) {
320
+ const targets = new Map();
321
+ const add = (target) => {
322
+ if (target.value.length > 0 && !targets.has(target.value))
323
+ targets.set(target.value, target);
324
+ };
325
+ for (const frame of run?.dynamic?.frames ?? []) {
326
+ if (frame.status !== "failed")
327
+ continue;
328
+ if (frame.frameKind !== undefined && frame.frameKind !== "node" && frame.frameKind !== "loop")
329
+ continue;
330
+ add({
331
+ value: frame.frameKey,
332
+ label: frame.nodeId ? `frame: ${frame.nodeId}` : `frame: ${frame.frameKey}`,
333
+ kind: "frame",
334
+ });
335
+ }
336
+ for (const instance of run?.dynamic?.nodeInstances ?? []) {
337
+ if (instance.status !== "failed")
338
+ continue;
339
+ add({
340
+ value: instance.nodeKey,
341
+ label: `node: ${instance.nodeId}`,
342
+ kind: "node",
343
+ });
344
+ }
345
+ for (const member of run?.dynamic?.groupMembers ?? []) {
346
+ if (member.status !== "failed")
347
+ continue;
348
+ add({
349
+ value: member.memberKey,
350
+ label: `member: ${member.branchId ?? member.itemKey ?? member.memberKey}`,
351
+ kind: "member",
352
+ });
353
+ }
354
+ return [...targets.values()].sort((left, right) => left.value.localeCompare(right.value));
355
+ }
356
+ export function controlStateForRun(status, disabled, retryTargets = []) {
357
+ if (status === "failed") {
358
+ return [{
359
+ id: "retry",
360
+ label: "Retry",
361
+ tone: "retry",
362
+ disabled: disabled || retryTargets.length === 0,
363
+ title: retryTargets.length === 0 ? "No failed retry target found. Use CLI for run-level retry." : "Retry failed target",
364
+ }];
365
+ }
366
+ if (status === "paused") {
367
+ return [
368
+ controlSpec("resume", disabled),
369
+ controlSpec("cancel", disabled),
370
+ ];
371
+ }
372
+ if (status === "pending" || status === "running" || status === "awaiting") {
373
+ return [
374
+ controlSpec("pause", disabled),
375
+ controlSpec("cancel", disabled),
376
+ ];
377
+ }
378
+ return [
379
+ controlSpec("pause", true),
380
+ controlSpec("cancel", true),
381
+ ];
382
+ }
383
+ export function retryCommandTarget(retryTargets, selectedRetryTarget) {
384
+ if (retryTargets.length === 1)
385
+ return retryTargets[0].value;
386
+ return retryTargets.some(target => target.value === selectedRetryTarget) ? selectedRetryTarget : undefined;
387
+ }
388
+ export function commandForControl(controlId, retryTarget, selectedNodeId) {
389
+ if (controlId === "retry")
390
+ return retryTarget ? { type: "retry", target: retryTarget } : undefined;
391
+ if (controlId === "cancel")
392
+ return selectedNodeId ? { type: "cancel", target: selectedNodeId } : { type: "cancel" };
393
+ return { type: controlId };
394
+ }
395
+ export function confirmationForControl(controlId, targetLabel) {
396
+ if (controlId === "cancel") {
397
+ return {
398
+ title: targetLabel ? "Cancel selected target?" : "Cancel this run?",
399
+ detail: targetLabel ? `Cancel target ${targetLabel}. This cannot be undone.` : "Cancel the current run. This cannot be undone.",
400
+ confirmLabel: "Cancel",
401
+ tone: "cancel",
402
+ };
403
+ }
404
+ if (controlId === "retry") {
405
+ return {
406
+ title: "Retry failed target?",
407
+ detail: targetLabel ? `Retry ${targetLabel}. The selected failed target will be re-driven.` : "Retry the selected failed target.",
408
+ confirmLabel: "Retry",
409
+ tone: "retry",
410
+ };
411
+ }
412
+ if (controlId === "resume") {
413
+ return {
414
+ title: "Resume this run?",
415
+ detail: "Resume the paused run and continue eligible work.",
416
+ confirmLabel: "Resume",
417
+ tone: "resume",
418
+ };
419
+ }
420
+ return {
421
+ title: "Pause this run?",
422
+ detail: "Pause the run and stop active work as soon as the runtime can safely do so.",
423
+ confirmLabel: "Pause",
424
+ tone: "pause",
425
+ };
426
+ }
427
+ function controlSpec(id, disabled) {
428
+ return {
429
+ id,
430
+ label: id[0].toUpperCase() + id.slice(1),
431
+ tone: id,
432
+ disabled,
433
+ title: id[0].toUpperCase() + id.slice(1),
434
+ };
435
+ }
436
+ function controlIcon(id) {
437
+ if (id === "pause")
438
+ return _jsx(Pause, { size: 16 });
439
+ if (id === "resume")
440
+ return _jsx(Play, { size: 16 });
441
+ if (id === "retry")
442
+ return _jsx(RotateCcw, { size: 16 });
443
+ return _jsx(Square, { size: 16 });
444
+ }
445
+ function ConfirmDialog({ confirmation, restoreFocus, onCancel, onConfirm, }) {
446
+ return (_jsx(Dialog, { open: true, onOpenChange: open => {
447
+ if (!open)
448
+ onCancel();
449
+ }, children: _jsxs(DialogContent, { className: `confirm-dialog ${confirmation.tone}`, onCloseAutoFocus: event => {
450
+ event.preventDefault();
451
+ restoreFocus?.focus();
452
+ }, children: [_jsx(DialogTitle, { children: confirmation.title }), _jsx(DialogDescription, { children: confirmation.detail }), _jsxs("div", { className: "confirm-actions", children: [_jsx(Button, { type: "button", variant: "confirmSecondary", onClick: onCancel, children: "Back" }), _jsx(Button, { type: "button", variant: "confirmPrimary", tone: confirmation.tone, onClick: onConfirm, children: confirmation.confirmLabel })] })] }) }));
453
+ }
454
+ function Inspector({ runId, target, context, displayStatus, inspection, loading, }) {
455
+ const [activeTab, setActiveTab] = useState("overview");
456
+ useEffect(() => {
457
+ setActiveTab("overview");
458
+ }, [target]);
459
+ useEffect(() => {
460
+ const hasArtifacts = (inspection?.summary.artifacts.length ?? 0) > 0;
461
+ const hasExecution = inspection?.summary.staticKind === "agent";
462
+ if ((activeTab === "artifacts" && !hasArtifacts) || (activeTab === "execution" && !hasExecution)) {
463
+ setActiveTab("overview");
464
+ }
465
+ }, [activeTab, inspection?.summary.artifacts.length, inspection?.summary.staticKind]);
466
+ if (loading)
467
+ return _jsx(StateBlock, { tone: "loading", title: "Loading node details" });
468
+ if (!inspection)
469
+ return _jsx(StateBlock, { tone: "empty", title: "Select a graph node", detail: "Node runtime details appear here after selection." });
470
+ const summary = inspection.summary;
471
+ const runtimeStatus = displayStatus ?? normalizeRuntimeStatus(summary.nodeStatus ?? summary.runStatus);
472
+ const hasArtifacts = summary.artifacts.length > 0;
473
+ const hasExecution = summary.staticKind === "agent";
474
+ return (_jsxs("div", { className: "inspector-stack", children: [_jsxs("div", { className: "inspector-runtime-head", children: [_jsx(StatusPill, { status: runtimeStatus }), _jsxs("div", { children: [summary.runStartedAt && (_jsxs(_Fragment, { children: [_jsx("span", { children: "Start" }), _jsx("strong", { children: formatDate(summary.runStartedAt) })] })), summary.runDurationMs !== undefined && (_jsxs(_Fragment, { children: [_jsx("span", { children: "Duration" }), _jsx("strong", { children: formatDuration(summary.runDurationMs) })] }))] })] }), _jsxs(Tabs, { value: activeTab, onValueChange: value => setActiveTab(value), children: [_jsxs(TabsList, { className: "inspector-tabs", "aria-label": "Inspector sections", children: [_jsx(InspectorTab, { id: "overview", children: "Overview" }), hasArtifacts && _jsxs(InspectorTab, { id: "artifacts", children: ["Artifacts ", _jsx(Badge, { variant: "tabCount", children: summary.artifacts.length })] }), hasExecution && _jsx(InspectorTab, { id: "execution", children: "Execution" })] }), _jsx(InspectorTabPanel, { id: "overview", children: _jsxs(_Fragment, { children: [_jsxs(InspectorSection, { title: "Identity", children: [summary.nodeId && _jsx(KeyValue, { label: "Node ID", value: summary.nodeId }), summary.nodeKey && _jsx(KeyValue, { label: "Node Key", value: summary.nodeKey }), summary.frameKey && _jsx(KeyValue, { label: "Frame Key", value: summary.frameKey }), summary.staticKind && _jsx(KeyValue, { label: "Kind", value: summary.staticKind }), summary.staticOrder !== undefined && _jsx(KeyValue, { label: "Static order", value: String(summary.staticOrder) }), _jsx(KeyValue, { label: "Runtime", value: runtimeStatus }), summary.latestAttempt && _jsx(KeyValue, { label: "Latest attempt", value: `${summary.latestAttempt.attemptNo} · ${summary.latestAttempt.status}` })] }), summary.input && (_jsx(JsonSection, { title: summary.input.kind === "runtime" ? "Input" : "Authored Input", value: summary.input.value })), summary.prompt && (_jsx(InspectorSection, { title: "Prompt", children: _jsx(PromptContent, { runId: runId, prompt: summary.prompt }) })), summary.output !== undefined && (_jsx(JsonSection, { title: "Output", value: summary.output })), summary.error !== undefined && (_jsx(JsonSection, { title: "Diagnostics", value: summary.error }))] }) }), hasArtifacts && (_jsx(InspectorTabPanel, { id: "artifacts", children: _jsx(ArtifactList, { runId: runId, artifacts: summary.artifacts }) })), hasExecution && (_jsx(InspectorTabPanel, { id: "execution", children: runId && target && _jsx(AgentExecutionTab, { runId: runId, target: target, context: context, active: activeTab === "execution" }) }))] })] }));
475
+ }
476
+ function InspectorTab({ id, children }) {
477
+ return (_jsx(TabsTrigger, { value: id, id: `inspector-tab-${id}`, className: "inspector-tab", "aria-controls": `inspector-panel-${id}`, children: children }));
478
+ }
479
+ function InspectorTabPanel({ id, children }) {
480
+ return (_jsx(TabsContent, { value: id, id: `inspector-panel-${id}`, className: "inspector-tab-panel", "aria-labelledby": `inspector-tab-${id}`, children: children }));
481
+ }
482
+ function InspectorSection({ title, action, children }) {
483
+ return (_jsxs("section", { className: "inspector-section", children: [_jsxs("div", { className: "inspector-section-head", children: [_jsx("h3", { children: title }), action] }), _jsx("div", { className: "inspector-section-body", children: children })] }));
484
+ }
485
+ function JsonSection({ title, value }) {
486
+ return (_jsx(InspectorSection, { title: title, action: _jsx(JsonCopyButton, { value: value }), children: _jsx(JsonBlock, { value: value }) }));
487
+ }
488
+ function JsonCopyButton({ value }) {
489
+ const [state, setState] = useState("idle");
490
+ return (_jsxs(Button, { type: "button", variant: "ghost", className: `json-copy-button ${state}`, onClick: async () => {
491
+ try {
492
+ await navigator.clipboard.writeText(JSON.stringify(value, null, 2));
493
+ setState("copied");
494
+ window.setTimeout(() => setState("idle"), 1_400);
495
+ }
496
+ catch {
497
+ setState("failed");
498
+ window.setTimeout(() => setState("idle"), 1_800);
499
+ }
500
+ }, children: [_jsx(Copy, { size: 13 }), state === "copied" ? "Copied" : state === "failed" ? "Copy failed" : "Copy JSON"] }));
501
+ }
502
+ function PromptContent({ runId, prompt }) {
503
+ if (prompt.text)
504
+ return _jsx(MarkdownBlock, { value: prompt.text });
505
+ if (!runId || !prompt.artifactId)
506
+ return _jsx(StateBlock, { tone: "empty", title: "Prompt unavailable", detail: "No prompt artifact or inline prompt was recorded for this scope." });
507
+ return _jsx(ArtifactPreviewBlock, { runId: runId, artifactId: prompt.artifactId, ...(prompt.mediaType ? { mediaType: prompt.mediaType } : {}) });
508
+ }
509
+ function ArtifactList({ runId, artifacts }) {
510
+ const [selectedArtifactId, setSelectedArtifactId] = useState();
511
+ const selected = artifacts.find(artifact => artifact.id === selectedArtifactId);
512
+ return (_jsxs("div", { className: "artifact-stack", children: [_jsx("div", { className: "artifact-list", children: artifacts.map(artifact => (_jsxs(Button, { variant: "ghost", className: `artifact-row ${artifact.id === selectedArtifactId ? "selected" : ""}`, title: artifact.relativePath, "aria-label": `Artifact ${artifact.relativePath}`, onClick: () => setSelectedArtifactId(current => current === artifact.id ? undefined : artifact.id), children: [_jsx("span", { className: "artifact-title mono", title: artifact.relativePath, children: artifact.relativePath }), _jsx("span", { children: artifact.mediaType ?? "unknown" }), _jsx("span", { children: formatSize(artifact.size) })] }, artifact.id))) }), runId && selected && _jsx(ArtifactPreviewBlock, { runId: runId, artifactId: selected.id, ...(selected.mediaType ? { mediaType: selected.mediaType } : {}) })] }));
513
+ }
514
+ function ArtifactPreviewBlock({ runId, artifactId, mediaType }) {
515
+ const preview = useQuery({
516
+ queryKey: ["artifact-preview", runId, artifactId],
517
+ queryFn: () => getArtifactPreview(runId, artifactId),
518
+ });
519
+ if (preview.isLoading)
520
+ return _jsx(StateBlock, { tone: "loading", title: "Loading artifact" });
521
+ if (preview.error)
522
+ return _jsx(StateBlock, { tone: "error", title: "Artifact preview failed", detail: preview.error instanceof Error ? preview.error.message : String(preview.error) });
523
+ const loaded = preview.data;
524
+ if (!loaded)
525
+ return null;
526
+ const effectiveMediaType = mediaType ?? loaded.mediaType;
527
+ if (isJsonMedia(effectiveMediaType)) {
528
+ const value = tryParseJsonPreview(loaded.text);
529
+ return value.ok ? (_jsx("div", { className: "json-standalone", children: _jsx(JsonBlock, { value: value.value }) })) : (_jsx(TextArtifactPreview, { value: loaded.text, label: "Raw JSON text" }));
530
+ }
531
+ if (isMarkdownMedia(effectiveMediaType))
532
+ return _jsx(MarkdownBlock, { value: loaded.text });
533
+ if (isTextMedia(effectiveMediaType))
534
+ return _jsx(TextArtifactPreview, { value: loaded.text });
535
+ return _jsx(StateBlock, { tone: "empty", title: "Preview unavailable", detail: `Preview is not available for ${effectiveMediaType}.` });
536
+ }
537
+ function AgentExecutionTab({ runId, target, context, active }) {
538
+ const execution = useQuery({
539
+ queryKey: ["node-execution", runId, target, context],
540
+ queryFn: () => getNodeExecutionInspection(runId, target, context),
541
+ enabled: active,
542
+ refetchInterval: active ? 2_500 : false,
543
+ });
544
+ if (execution.isLoading)
545
+ return _jsx(StateBlock, { tone: "loading", title: "Loading execution telemetry" });
546
+ if (execution.error)
547
+ return _jsx(StateBlock, { tone: "error", title: "Execution telemetry failed", detail: execution.error instanceof Error ? execution.error.message : String(execution.error) });
548
+ if (!execution.data)
549
+ return _jsx(StateBlock, { tone: "empty", title: "No execution telemetry", detail: "No agent execution metadata exists for the selected scope." });
550
+ const data = execution.data;
551
+ if (!data.available)
552
+ return _jsx(StateBlock, { tone: "empty", title: "No execution telemetry", detail: data.reason ?? "No agent execution metadata exists for the selected scope." });
553
+ return (_jsxs("div", { className: "inspector-stack", children: [_jsxs(InspectorSection, { title: "Summary", children: [data.summary.status && _jsx(KeyValue, { label: "Status", value: data.summary.status }), data.lastActiveAt && _jsx(KeyValue, { label: "Last active", value: formatRelativeAge(data.lastActiveAt) }), data.summary.sessionName && _jsx(KeyValue, { label: "Session", value: data.summary.sessionName }), data.summary.turnCount !== undefined && _jsx(KeyValue, { label: "Turns", value: String(data.summary.turnCount) }), data.summary.message && _jsx(KeyValue, { label: "Message", value: data.summary.message })] }), _jsx(InspectorSection, { title: "Context Window", children: data.contextWindow ? _jsx(ContextWindowMeter, { context: data.contextWindow }) : _jsx(StateBlock, { tone: "empty", title: "No context window data", detail: "The selected agent attempt did not report context usage." }) }), _jsx(InspectorSection, { title: "Token Usage", children: data.tokenUsage ? _jsx(TokenUsageMetrics, { usage: data.tokenUsage }) : _jsx(StateBlock, { tone: "empty", title: "No token usage", detail: "The selected agent attempt did not report token usage." }) }), _jsx(InspectorSection, { title: "Output Stream", children: data.output ? _jsx(TextArtifactPreview, { value: data.output.tail, label: progressOutputLabel(data.output) }) : _jsx(StateBlock, { tone: "empty", title: "No streamed output", detail: "The selected agent attempt did not report streamed output." }) }), _jsx(InspectorSection, { title: "Last Tool Calls", children: data.lastToolCalls.length > 0 ? _jsx(ToolCallList, { calls: data.lastToolCalls, total: data.toolCallCount }) : _jsx(StateBlock, { tone: "empty", title: "No tool calls", detail: "No tool calls were recorded for the selected agent attempt." }) })] }));
554
+ }
555
+ function ContextWindowMeter({ context }) {
556
+ const percent = Math.max(0, Math.min(context.percent ?? 0, 100));
557
+ return (_jsxs("div", { className: "execution-card", children: [_jsxs("div", { className: "execution-meter-head", children: [_jsxs("strong", { children: [context.used ?? "?", " / ", context.size ?? "?"] }), context.percent !== undefined && _jsxs("span", { children: [context.percent, "%"] })] }), _jsx("div", { className: "execution-meter", "aria-label": `Context window ${context.percent ?? 0}% used`, children: _jsx("span", { style: { width: `${percent}%` } }) }), context.updatedAt && _jsxs("small", { children: ["Updated ", formatDate(context.updatedAt)] })] }));
558
+ }
559
+ function TokenUsageMetrics({ usage }) {
560
+ return (_jsxs("div", { className: "execution-metrics", children: [_jsx(Metric, { label: "Input", value: usage.inputTokens }), _jsx(Metric, { label: "Output", value: usage.outputTokens }), _jsx(Metric, { label: "Total", value: usage.totalTokens }), usage.source && _jsx(Metric, { label: "Source", value: usage.source })] }));
561
+ }
562
+ function progressOutputLabel(output) {
563
+ const retained = new TextEncoder().encode(output.tail).length;
564
+ return output.truncated ? `Last ${retained} of ${output.totalBytes} bytes` : `${output.totalBytes} bytes`;
565
+ }
566
+ function Metric({ label, value }) {
567
+ return (_jsxs("div", { className: "execution-metric", children: [_jsx("span", { children: label }), _jsx("strong", { children: value ?? "n/a" })] }));
568
+ }
569
+ function ToolCallList({ calls, total }) {
570
+ return (_jsxs("div", { className: "tool-call-stack", children: [total !== undefined && _jsxs("span", { className: "tool-call-summary", children: ["Last ", calls.length, " of ", total] }), calls.map((call, index) => (_jsxs("div", { className: "tool-call-row", children: [_jsxs("div", { className: "tool-call-head", children: [_jsxs("div", { children: [_jsx("strong", { children: call.toolName ?? "Tool call" }), _jsxs("span", { children: ["turn ", call.turn, call.durationMs !== undefined ? ` · ${formatDuration(call.durationMs)}` : ""] })] }), call.status && _jsx(ToolCallStatus, { status: call.status })] }), call.inputPreview && _jsx("p", { children: call.inputPreview }), call.outputPreview && _jsx("p", { children: call.outputPreview })] }, `${call.turn}-${call.toolCallId ?? index}`)))] }));
571
+ }
572
+ function ToolCallStatus({ status }) {
573
+ const display = normalizeRuntimeStatus(status);
574
+ return (_jsxs("span", { className: `tool-call-status ${display}`, children: [runStatusIcon(display), _jsx("span", { children: runtimeStatusLabel(display) })] }));
575
+ }
576
+ function JsonBlock({ value }) {
577
+ return (_jsx("div", { className: "json-viewer", children: _jsx(JsonView, { data: jsonViewData(value), shouldExpandNode: allExpanded, style: defaultStyles }) }));
578
+ }
579
+ function MarkdownBlock({ value }) {
580
+ return (_jsx("div", { className: "markdown-viewer", children: _jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], children: value }) }));
581
+ }
582
+ function TextArtifactPreview({ value, label }) {
583
+ return (_jsxs("div", { className: "text-artifact-shell", children: [label && _jsx("div", { className: "artifact-preview-label", children: label }), _jsx("pre", { className: "text-artifact-preview", children: value })] }));
584
+ }
585
+ function SignalBox({ wait, onSubmit, }) {
586
+ const [payload, setPayload] = useState("{}");
587
+ const [payloadError, setPayloadError] = useState();
588
+ return (_jsxs("form", { className: "signal-box", onSubmit: e => {
589
+ e.preventDefault();
590
+ try {
591
+ onSubmit(JSON.parse(payload));
592
+ setPayloadError(undefined);
593
+ }
594
+ catch {
595
+ setPayloadError("Signal payload must be valid JSON.");
596
+ }
597
+ }, children: [_jsx("strong", { children: "Awaiting Signal" }), wait.renderedPrompt && _jsx("p", { children: wait.renderedPrompt }), _jsx(Textarea, { value: payload, "aria-label": "Signal payload JSON", "aria-invalid": payloadError ? true : undefined, "aria-describedby": payloadError ? "signal-payload-error" : undefined, onChange: e => {
598
+ setPayload(e.target.value);
599
+ if (payloadError)
600
+ setPayloadError(undefined);
601
+ } }), payloadError && _jsx("p", { id: "signal-payload-error", className: "signal-error", role: "alert", children: payloadError }), _jsx(Button, { className: "primary-button", type: "submit", children: "Submit Signal" })] }));
602
+ }
603
+ function StatusInfoPopover({ health, config, }) {
604
+ const daemon = health?.checks.find(check => check.area === "daemon");
605
+ const checks = health?.checks.filter(check => check.area !== "daemon" && check.status !== "ok") ?? [];
606
+ const status = daemon?.status ?? (health ? "unknown" : "checking");
607
+ return (_jsxs(PopoverContent, { className: "status-info-popover", role: "dialog", "aria-labelledby": "status-info-title", children: [_jsxs("div", { className: "dialog-head", children: [_jsxs("div", { className: "status-info-title", children: [_jsx("span", { className: `sidebar-status-icon ${status}`, "aria-hidden": "true", children: sidebarStatusIcon(status) }), _jsx("h2", { id: "status-info-title", children: "Runtime status" })] }), _jsx(PopoverClose, { asChild: true, children: _jsx(Button, { variant: "ghost", className: "close-button", "aria-label": "Close", children: _jsx(XCircle, { size: 16 }) }) })] }), _jsxs("div", { className: "status-info-rows", children: [_jsx(KeyValue, { label: "Daemon", value: daemon?.message ? `${daemon.status}: ${daemon.message}` : status }), _jsx(KeyValue, { label: "Access", value: config?.access === "token" ? "Token" : "Open" }), _jsx(KeyValue, { label: "Workspace", value: config?.cwd ?? "Resolving" }), _jsx("div", { className: "status-health-summary", children: health ? (checks.length === 0 ? (_jsx("span", { children: "Health checks OK" })) : (checks.map(check => (_jsxs("span", { children: [check.status === "warn" ? _jsx(CircleAlert, { size: 14 }) : _jsx(XCircle, { size: 14 }), _jsx("strong", { children: check.area }), check.message] }, `${check.area}-${check.message}`))))) : (_jsx("span", { children: "Checking runtime health" })) })] })] }));
608
+ }
609
+ const SidebarStatus = React.forwardRef(({ health, config, ...props }, ref) => {
610
+ const daemon = health?.checks.find(check => check.area === "daemon");
611
+ const status = daemon?.status ?? (health ? "unknown" : "checking");
612
+ return (_jsxs(Button, { ref: ref, type: "button", variant: "ghost", className: "sidebar-status", title: "Runtime status", ...props, children: [_jsx("span", { className: `sidebar-status-icon ${status}`, "aria-hidden": "true", children: sidebarStatusIcon(status) }), _jsxs("span", { className: "sidebar-status-copy", children: [_jsx("span", { children: "Runtime status" }), _jsxs("small", { children: [status, " \u00B7 ", config?.access === "token" ? "token" : "open"] })] })] }));
613
+ });
614
+ SidebarStatus.displayName = "SidebarStatus";
615
+ function sidebarStatusIcon(status) {
616
+ if (status === "ok" || status === "running")
617
+ return _jsx(CheckCircle2, { size: 14, strokeWidth: 2 });
618
+ if (status === "warn")
619
+ return _jsx(CircleAlert, { size: 14, strokeWidth: 2 });
620
+ if (status === "fail" || status === "error")
621
+ return _jsx(XCircle, { size: 14, strokeWidth: 2 });
622
+ if (status === "checking")
623
+ return _jsx(LoaderCircle, { size: 14, strokeWidth: 2 });
624
+ return _jsx(Clock, { size: 14, strokeWidth: 2 });
625
+ }
626
+ function NavButton({ icon, label, active, onClick }) {
627
+ return (_jsxs(Button, { variant: "ghost", className: `nav-button ${active ? "active" : ""}`, "aria-label": label, "aria-current": active ? "page" : undefined, onClick: onClick, children: [icon, _jsx("span", { children: label })] }));
628
+ }
629
+ function IconButton({ icon, label, title, disabled, tone, onClick, }) {
630
+ return (_jsxs(Button, { variant: "icon", tone: tone, disabled: disabled, onClick: onClick, title: title, children: [icon, _jsx("span", { children: label })] }));
631
+ }
632
+ function PageHeader({ title, detail }) {
633
+ return (_jsxs("header", { className: "page-header", children: [_jsx("h2", { children: title }), _jsx("span", { className: "page-header-detail", children: detail })] }));
634
+ }
635
+ function StatusPill({ status }) {
636
+ return _jsx(Badge, { variant: "status", className: status, children: status });
637
+ }
638
+ function RunStatusIndicator({ status }) {
639
+ const display = normalizeRuntimeStatus(status);
640
+ const active = display === "running" || display === "awaiting";
641
+ return (_jsxs("span", { className: `run-status-indicator ${display} ${active ? "live" : ""}`, "aria-label": `Run status ${runtimeStatusLabel(display)}`, children: [_jsx("span", { className: "run-status-icon", children: runStatusIcon(display) }), _jsx("span", { className: "run-status-label", children: runtimeStatusLabel(display) })] }));
642
+ }
643
+ function isTerminalRunStatus(status) {
644
+ const display = normalizeRuntimeStatus(status);
645
+ return display === "completed" || display === "failed" || display === "canceled";
646
+ }
647
+ function runStatusIcon(status) {
648
+ if (status === "running")
649
+ return _jsx(LoaderCircle, { size: 13, strokeWidth: 2 });
650
+ if (status === "awaiting")
651
+ return _jsx(Radio, { size: 13, strokeWidth: 2 });
652
+ if (status === "paused")
653
+ return _jsx(Pause, { size: 13, strokeWidth: 2 });
654
+ if (status === "completed")
655
+ return _jsx(CheckCircle2, { size: 13, strokeWidth: 2 });
656
+ if (status === "failed")
657
+ return _jsx(XCircle, { size: 13, strokeWidth: 2 });
658
+ if (status === "canceled")
659
+ return _jsx(Ban, { size: 13, strokeWidth: 2 });
660
+ return _jsx(Clock, { size: 13, strokeWidth: 2 });
661
+ }
662
+ function KeyValue({ label, value }) {
663
+ return (_jsxs("div", { className: "key-value", tabIndex: 0, title: `${label}: ${value}`, "aria-label": `${label}: ${value}`, children: [_jsx("span", { children: label }), _jsx("strong", { children: value })] }));
664
+ }
665
+ function EmptyState({ title, detail }) {
666
+ return (_jsxs("div", { className: "empty-state", children: [_jsx(Boxes, { size: 22 }), _jsx("h2", { children: title }), _jsx("p", { children: detail })] }));
667
+ }
668
+ function StateBlock({ tone, title, detail }) {
669
+ const icon = tone === "loading"
670
+ ? _jsx(LoaderCircle, { size: 16 })
671
+ : tone === "error"
672
+ ? _jsx(CircleAlert, { size: 16 })
673
+ : _jsx(Boxes, { size: 16 });
674
+ return (_jsxs(Alert, { className: `state-block ${tone}`, role: tone === "error" ? "alert" : tone === "loading" ? "status" : undefined, "aria-busy": tone === "loading" ? true : undefined, children: [_jsx("span", { className: "state-block-icon", children: icon }), _jsxs("div", { children: [_jsx("strong", { children: title }), detail && _jsx("p", { children: detail }), tone === "loading" && (_jsxs("div", { className: "state-skeleton", "aria-hidden": "true", children: [_jsx("span", { className: "state-skeleton-line" }), _jsx("span", { className: "state-skeleton-line short" })] }))] })] }));
675
+ }
676
+ function formatDate(value) {
677
+ const date = new Date(value);
678
+ if (Number.isNaN(date.getTime()))
679
+ return value;
680
+ const pad = (part) => String(part).padStart(2, "0");
681
+ return `${date.getFullYear()}/${pad(date.getMonth() + 1)}/${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}`;
682
+ }
683
+ function formatRelativeAge(value) {
684
+ const timestamp = Date.parse(value);
685
+ if (!Number.isFinite(timestamp))
686
+ return value;
687
+ const ageMs = Math.max(0, Date.now() - timestamp);
688
+ return ageMs < 1_000 ? "<1s ago" : `${formatDuration(ageMs)} ago`;
689
+ }
690
+ function durationBetween(start, end) {
691
+ return Math.max(0, Date.parse(end) - Date.parse(start));
692
+ }
693
+ function formatDuration(ms) {
694
+ if (ms < 1000)
695
+ return `${ms}ms`;
696
+ const seconds = Math.round(ms / 1000);
697
+ if (seconds < 60)
698
+ return `${seconds}s`;
699
+ const minutes = Math.floor(seconds / 60);
700
+ const remainingSeconds = seconds % 60;
701
+ return remainingSeconds === 0 ? `${minutes}m` : `${minutes}m ${remainingSeconds}s`;
702
+ }
703
+ function formatSize(bytes) {
704
+ if (bytes < 1024)
705
+ return `${bytes} B`;
706
+ if (bytes < 1024 * 1024)
707
+ return `${(bytes / 1024).toFixed(1)} KB`;
708
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
709
+ }
710
+ function isJsonMedia(mediaType) {
711
+ return mediaType.includes("json") || mediaType.includes("ndjson");
712
+ }
713
+ function isMarkdownMedia(mediaType) {
714
+ return mediaType.includes("markdown") || mediaType.includes("md");
715
+ }
716
+ function isTextMedia(mediaType) {
717
+ return mediaType.startsWith("text/") || mediaType.includes("xml") || mediaType.includes("yaml");
718
+ }
719
+ function tryParseJsonPreview(text) {
720
+ try {
721
+ return { ok: true, value: JSON.parse(text) };
722
+ }
723
+ catch {
724
+ const lines = text.split("\n").filter(Boolean);
725
+ if (lines.length === 0)
726
+ return { ok: false };
727
+ const values = [];
728
+ for (const line of lines) {
729
+ try {
730
+ values.push(JSON.parse(line));
731
+ }
732
+ catch {
733
+ return { ok: false };
734
+ }
735
+ }
736
+ return { ok: true, value: values };
737
+ }
738
+ }
739
+ function jsonViewData(value) {
740
+ return value !== null && typeof value === "object" ? value : { value };
741
+ }
742
+ //# sourceMappingURL=App.js.map