@tangle-network/charts 2.0.13 → 2.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/AgentGraphCanvas-B74GN1o6.js +1184 -0
- package/dist/elk-loader-CrLO557o.d.ts +268 -0
- package/dist/flow-trace-DRluIYw8.js +10 -0
- package/dist/flow-waterfall-model-DvrgPLGS.js +4747 -0
- package/dist/graph-style-fealnLLn.js +356 -0
- package/dist/index.js +2 -1
- package/dist/latest-events-iiWwpIck.js +491 -0
- package/dist/motion-DILryczn.js +7 -0
- package/dist/react/agent-graph/index.d.ts +157 -0
- package/dist/react/agent-graph/index.js +1191 -0
- package/dist/react/agent-graph/presentation.d.ts +8 -0
- package/dist/react/agent-graph/presentation.js +3 -0
- package/dist/react/agent-graph.css +1800 -0
- package/dist/react/flow-waterfall.css +10 -13
- package/dist/react/index.js +93 -4821
- package/dist/{flow-trace-k097Ukvs.js → timeline-B7c-cede.js} +1 -10
- package/package.json +37 -7
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import { D as statusMeta, m as quietGap } from "./flow-waterfall-model-DvrgPLGS.js";
|
|
2
|
+
import { Component, useEffect, useLayoutEffect, useState, useSyncExternalStore } from "react";
|
|
3
|
+
//#region src/react/agent-graph/format.ts
|
|
4
|
+
/**
|
|
5
|
+
* Display formatters for the workflow graph's live run-state chips. Pure and
|
|
6
|
+
* dependency-free so they can be unit-tested without rendering the graph.
|
|
7
|
+
*/
|
|
8
|
+
/** Human-readable duration: `850ms`, `4.2s`, `1m30s`. Undefined for an absent,
|
|
9
|
+
* non-finite, or negative input (e.g. clock skew) so the caller renders no
|
|
10
|
+
* chip rather than a confusing `-5ms`. */
|
|
11
|
+
function fmtDuration(ms) {
|
|
12
|
+
if (ms === void 0 || !Number.isFinite(ms) || ms < 0) return void 0;
|
|
13
|
+
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
14
|
+
const s = ms / 1e3;
|
|
15
|
+
if (s < 60) return `${s.toFixed(1)}s`;
|
|
16
|
+
const totalSeconds = Math.round(s);
|
|
17
|
+
return `${Math.floor(totalSeconds / 60)}m${totalSeconds % 60}s`;
|
|
18
|
+
}
|
|
19
|
+
/** Human-readable USD cost: `$0`, `$0.0032` (sub-cent, 4dp), `$1.20`. Undefined
|
|
20
|
+
* for an absent, non-finite, or negative input — a cost is a billing amount, so
|
|
21
|
+
* a negative value is bad data, not a refund to render. */
|
|
22
|
+
function fmtCost(usd) {
|
|
23
|
+
if (usd === void 0 || !Number.isFinite(usd) || usd < 0) return void 0;
|
|
24
|
+
if (usd === 0) return "$0";
|
|
25
|
+
return usd < .01 ? `$${usd.toFixed(4)}` : `$${usd.toFixed(2)}`;
|
|
26
|
+
}
|
|
27
|
+
/** Bound host-supplied preview/error text to a fixed length (with an ellipsis)
|
|
28
|
+
* before it reaches the DOM, so an oversized payload can't bloat the node tree —
|
|
29
|
+
* the card only ever shows a short preview, and CSS clamping is visual only.
|
|
30
|
+
* Truncation is code-point aware: it never slices through a surrogate pair (which
|
|
31
|
+
* would leave a lone surrogate that renders as the replacement character). */
|
|
32
|
+
function clampPreview(text, max = 200) {
|
|
33
|
+
if (text.length <= max) return text;
|
|
34
|
+
const lastCode = text.charCodeAt(max - 1);
|
|
35
|
+
const end = lastCode >= 55296 && lastCode <= 56319 ? max - 1 : max;
|
|
36
|
+
return `${text.slice(0, end)}…`;
|
|
37
|
+
}
|
|
38
|
+
/** Human-readable token usage: `1200/340 tok`. Undefined when neither side is a
|
|
39
|
+
* finite, non-negative count, so the caller renders no chip; an invalid side
|
|
40
|
+
* (negative / NaN / absent) shows as 0 rather than leaking `-5/NaN tok`. */
|
|
41
|
+
function fmtTokens(input, output) {
|
|
42
|
+
const valid = (n) => n !== void 0 && Number.isFinite(n) && n >= 0 ? n : void 0;
|
|
43
|
+
const i = valid(input);
|
|
44
|
+
const o = valid(output);
|
|
45
|
+
if (i === void 0 && o === void 0) return void 0;
|
|
46
|
+
return `${i ?? 0}/${o ?? 0} tok`;
|
|
47
|
+
}
|
|
48
|
+
/** A token total in a few characters: `840 tok`, `12.4k tok`, `1.2M tok`.
|
|
49
|
+
* Undefined for an absent, non-finite or negative count. */
|
|
50
|
+
function fmtTokenTotal(tokens) {
|
|
51
|
+
if (tokens == null || !Number.isFinite(tokens) || tokens < 0) return void 0;
|
|
52
|
+
if (tokens < 1e3) return `${Math.round(tokens)} tok`;
|
|
53
|
+
if (tokens < 1e6) return `${(tokens / 1e3).toFixed(tokens < 1e4 ? 1 : 0)}k tok`;
|
|
54
|
+
return `${(tokens / 1e6).toFixed(1)}M tok`;
|
|
55
|
+
}
|
|
56
|
+
function fmtEventTime(at, now, frozen = false) {
|
|
57
|
+
if (at == null || !Number.isFinite(at)) return "—";
|
|
58
|
+
if (frozen) return new Date(at).toLocaleTimeString([], {
|
|
59
|
+
hour: "2-digit",
|
|
60
|
+
minute: "2-digit",
|
|
61
|
+
hourCycle: "h23"
|
|
62
|
+
});
|
|
63
|
+
const seconds = Math.max(0, Math.floor((now - at) / 1e3));
|
|
64
|
+
return seconds < 5 ? "now" : seconds < 60 ? `${seconds}s` : seconds < 3600 ? `${Math.floor(seconds / 60)}m` : `${Math.floor(seconds / 3600)}h`;
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/react/agent-graph/run-ui-state.ts
|
|
68
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
69
|
+
let clock = Date.now();
|
|
70
|
+
let timer;
|
|
71
|
+
function tick() {
|
|
72
|
+
clock = Date.now();
|
|
73
|
+
for (const listener of listeners) listener();
|
|
74
|
+
timer = setTimeout(tick, 1e3 - Date.now() % 1e3);
|
|
75
|
+
}
|
|
76
|
+
function subscribe(listener) {
|
|
77
|
+
listeners.add(listener);
|
|
78
|
+
if (listeners.size === 1) tick();
|
|
79
|
+
return () => {
|
|
80
|
+
listeners.delete(listener);
|
|
81
|
+
if (!listeners.size) clearTimeout(timer);
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const noSubscribe = () => () => {};
|
|
85
|
+
function useRunNow(fixed) {
|
|
86
|
+
const now = useSyncExternalStore(fixed === void 0 ? subscribe : noSubscribe, () => fixed ?? clock, () => fixed ?? 0);
|
|
87
|
+
return fixed ?? now;
|
|
88
|
+
}
|
|
89
|
+
const motionQuery = () => typeof matchMedia === "undefined" ? null : matchMedia("(prefers-reduced-motion: reduce)");
|
|
90
|
+
const subscribeMotion = (listener) => {
|
|
91
|
+
const query = motionQuery();
|
|
92
|
+
query?.addEventListener("change", listener);
|
|
93
|
+
return () => query?.removeEventListener("change", listener);
|
|
94
|
+
};
|
|
95
|
+
function useMotionAllowed() {
|
|
96
|
+
return useSyncExternalStore(subscribeMotion, () => motionQuery()?.matches === false, () => false);
|
|
97
|
+
}
|
|
98
|
+
function tokenMilliseconds(token, element) {
|
|
99
|
+
if (typeof document === "undefined") return 0;
|
|
100
|
+
const value = getComputedStyle(element ?? document.documentElement).getPropertyValue(token).trim();
|
|
101
|
+
return (parseFloat(value) || 0) * (value.endsWith("ms") ? 1 : 1e3);
|
|
102
|
+
}
|
|
103
|
+
const ambientStyle = { animation: "tangle-breathe var(--motion-ambient) infinite" };
|
|
104
|
+
/** The document timeline is the page's epoch, including marks mounted later. */
|
|
105
|
+
function syncAmbient(event) {
|
|
106
|
+
for (const animation of event.currentTarget.getAnimations()) if (animation.animationName === "tangle-breathe") animation.startTime = 0;
|
|
107
|
+
}
|
|
108
|
+
function activityTiming(agent) {
|
|
109
|
+
const times = Number.isFinite(agent.lastActivityAt) && Number.isFinite(agent.medianEventGapMs) && agent.medianEventGapMs >= 0 ? [] : (agent.events ?? []).flatMap((e) => e.at != null && Number.isFinite(e.at) ? [e.at] : []).sort((a, b) => a - b);
|
|
110
|
+
const last = Number.isFinite(agent.lastActivityAt) ? agent.lastActivityAt : times.at(-1);
|
|
111
|
+
const gaps = times.slice(1).map((time, i) => time - times[i]).sort((a, b) => a - b);
|
|
112
|
+
const middle = Math.floor(gaps.length / 2);
|
|
113
|
+
return {
|
|
114
|
+
lastActivityAt: last,
|
|
115
|
+
medianEventGapMs: Number.isFinite(agent.medianEventGapMs) && agent.medianEventGapMs >= 0 ? agent.medianEventGapMs : gaps.length ? gaps.length % 2 ? gaps[middle] : (gaps[middle - 1] + gaps[middle]) / 2 : 0
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function agentQuietActivity(agent, now) {
|
|
119
|
+
if (agent.status !== "running") return null;
|
|
120
|
+
const { lastActivityAt, medianEventGapMs } = activityTiming(agent);
|
|
121
|
+
if (lastActivityAt == null || !Number.isFinite(lastActivityAt)) return null;
|
|
122
|
+
const { quietMs, quiet } = quietGap(lastActivityAt, medianEventGapMs, now);
|
|
123
|
+
return quiet ? {
|
|
124
|
+
quietMs,
|
|
125
|
+
label: `Quiet ${Math.floor(quietMs / 6e4)}m`
|
|
126
|
+
} : null;
|
|
127
|
+
}
|
|
128
|
+
/** Attention is finite and state changes work without animation completion. */
|
|
129
|
+
function useAttention(ref, status) {
|
|
130
|
+
const allowed = useMotionAllowed();
|
|
131
|
+
useEffect(() => {
|
|
132
|
+
const element = ref.current;
|
|
133
|
+
if (!element || !allowed || status !== "needs-you" && status !== "failed") return;
|
|
134
|
+
const token = statusMeta(status).token;
|
|
135
|
+
const duration = tokenMilliseconds("--duration-ambient", element) * (status === "needs-you" ? .45 : .3);
|
|
136
|
+
element.dataset.attn = status;
|
|
137
|
+
const shadow = getComputedStyle(element).boxShadow;
|
|
138
|
+
const resting = shadow === "none" ? "" : `, ${shadow}`;
|
|
139
|
+
const animation = element.animate([{ boxShadow: `0 0 0 0 color-mix(in srgb, var(${token}) 40%, transparent)${resting}` }, { boxShadow: `0 0 0 6px transparent${resting}` }], {
|
|
140
|
+
duration,
|
|
141
|
+
iterations: status === "needs-you" ? 2 : 1,
|
|
142
|
+
easing: getComputedStyle(element).getPropertyValue("--ease-exit").trim() || "ease-out"
|
|
143
|
+
});
|
|
144
|
+
const end = setTimeout(() => {
|
|
145
|
+
delete element.dataset.attn;
|
|
146
|
+
}, duration * (status === "needs-you" ? 2 : 1));
|
|
147
|
+
return () => {
|
|
148
|
+
animation.cancel();
|
|
149
|
+
clearTimeout(end);
|
|
150
|
+
delete element.dataset.attn;
|
|
151
|
+
};
|
|
152
|
+
}, [
|
|
153
|
+
ref,
|
|
154
|
+
status,
|
|
155
|
+
allowed
|
|
156
|
+
]);
|
|
157
|
+
}
|
|
158
|
+
//#endregion
|
|
159
|
+
//#region src/react/agent-graph/graph-lazy.tsx
|
|
160
|
+
function retryImport(factory, retries = 2, delayMs = 350) {
|
|
161
|
+
return factory().catch((err) => {
|
|
162
|
+
if (retries <= 0) throw err;
|
|
163
|
+
return new Promise((resolve, reject) => {
|
|
164
|
+
setTimeout(() => retryImport(factory, retries - 1, delayMs).then(resolve, reject), delayMs);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
var GraphErrorBoundary = class extends Component {
|
|
169
|
+
state = { hasError: false };
|
|
170
|
+
static getDerivedStateFromError() {
|
|
171
|
+
return { hasError: true };
|
|
172
|
+
}
|
|
173
|
+
render() {
|
|
174
|
+
return this.state.hasError ? this.props.fallback : this.props.children;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
//#endregion
|
|
178
|
+
//#region src/react/agent-graph/elk-loader.ts
|
|
179
|
+
/** One ELK instance per page. `null` once loading failed, so a host without
|
|
180
|
+
* the peer pays for one failed import, not one per render. */
|
|
181
|
+
let elkInstance;
|
|
182
|
+
function loadElk() {
|
|
183
|
+
elkInstance ??= import("elkjs/lib/elk.bundled.js").then((mod) => {
|
|
184
|
+
const Elk = mod.default;
|
|
185
|
+
return new Elk();
|
|
186
|
+
}).catch(() => null);
|
|
187
|
+
return elkInstance;
|
|
188
|
+
}
|
|
189
|
+
//#endregion
|
|
190
|
+
//#region src/react/agent-graph/naming.ts
|
|
191
|
+
/**
|
|
192
|
+
* Human-facing naming for workflow nodes. A definition addresses things by
|
|
193
|
+
* machine identifier — an action kind (`agent.run`), a hub action path
|
|
194
|
+
* (`github.pulls.reviews.create`), a profile slug (`pr-reviewer`) — and showing
|
|
195
|
+
* those verbatim on a node makes the graph read like a config file. These turn
|
|
196
|
+
* an identifier into the label a person would say out loud.
|
|
197
|
+
*
|
|
198
|
+
* Pure and dependency-free so the naming rules are unit-testable without the
|
|
199
|
+
* YAML parser or a render.
|
|
200
|
+
*/
|
|
201
|
+
/** Identifier fragments that read as an initialism, so they are upper-cased
|
|
202
|
+
* whole rather than sentence-cased into "Pr" / "Api". */
|
|
203
|
+
const ACRONYMS = /* @__PURE__ */ new Set([
|
|
204
|
+
"ai",
|
|
205
|
+
"api",
|
|
206
|
+
"cd",
|
|
207
|
+
"ci",
|
|
208
|
+
"cli",
|
|
209
|
+
"cpu",
|
|
210
|
+
"css",
|
|
211
|
+
"csv",
|
|
212
|
+
"db",
|
|
213
|
+
"dns",
|
|
214
|
+
"gpu",
|
|
215
|
+
"html",
|
|
216
|
+
"http",
|
|
217
|
+
"https",
|
|
218
|
+
"id",
|
|
219
|
+
"io",
|
|
220
|
+
"ip",
|
|
221
|
+
"json",
|
|
222
|
+
"llm",
|
|
223
|
+
"mcp",
|
|
224
|
+
"ml",
|
|
225
|
+
"pr",
|
|
226
|
+
"qa",
|
|
227
|
+
"sdk",
|
|
228
|
+
"sla",
|
|
229
|
+
"sql",
|
|
230
|
+
"ssh",
|
|
231
|
+
"ui",
|
|
232
|
+
"url",
|
|
233
|
+
"uuid",
|
|
234
|
+
"vm",
|
|
235
|
+
"yaml"
|
|
236
|
+
]);
|
|
237
|
+
/** Split a machine identifier into its words, on separators and camelCase humps. */
|
|
238
|
+
function words(id) {
|
|
239
|
+
return id.replace(/[._\-/]+/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").trim().split(/\s+/).filter(Boolean);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Humanize a machine identifier: `pr-reviewer` → "PR reviewer", `sandbox.spawn`
|
|
243
|
+
* → "Sandbox spawn", `postMessage` → "Post message". Known initialisms are
|
|
244
|
+
* upper-cased wherever they appear; `lead` picks the case of the rest.
|
|
245
|
+
*
|
|
246
|
+
* - `sentence` (default): "Create issue comment" — a label or a title.
|
|
247
|
+
* - `lower`: "create issue comment" — a fragment that sits INSIDE a phrase
|
|
248
|
+
* ("On pull request"), where a capital would read as a new sentence. An
|
|
249
|
+
* initialism still wins: `ci_run_completed` → "CI run completed", never
|
|
250
|
+
* "cI run completed".
|
|
251
|
+
* - `title`: "Google Sheets" — a brand/proper name.
|
|
252
|
+
*
|
|
253
|
+
* An identifier that carries no word characters is returned verbatim rather than
|
|
254
|
+
* blanked.
|
|
255
|
+
*/
|
|
256
|
+
function humanizeIdentifier(id, lead = "sentence") {
|
|
257
|
+
const parts = words(id);
|
|
258
|
+
if (parts.length === 0) return id;
|
|
259
|
+
return parts.map((word, i) => {
|
|
260
|
+
const lower = word.toLowerCase();
|
|
261
|
+
if (ACRONYMS.has(lower)) return lower.toUpperCase();
|
|
262
|
+
const capitalized = lower.charAt(0).toUpperCase() + lower.slice(1);
|
|
263
|
+
if (lead === "title") return capitalized;
|
|
264
|
+
if (i > 0) return lower;
|
|
265
|
+
return lead === "lower" ? lower : capitalized;
|
|
266
|
+
}).join(" ");
|
|
267
|
+
}
|
|
268
|
+
/** A model slug without its provider prefix (`anthropic/claude-sonnet-5` →
|
|
269
|
+
* `claude-sonnet-5`) — the vendor is noise on a card whose width is the scarce
|
|
270
|
+
* resource, and the full slug stays in the node's config for the detail view. */
|
|
271
|
+
function shortModel(model) {
|
|
272
|
+
const slash = model.lastIndexOf("/");
|
|
273
|
+
return slash === -1 ? model : model.slice(slash + 1);
|
|
274
|
+
}
|
|
275
|
+
/** The charset a hub action path is made of (mirrors the server's path schema:
|
|
276
|
+
* `<provider>.<action…>`, letters/digits/`_`/`-` per segment). A value that
|
|
277
|
+
* isn't one — most importantly a `${…}` mapping expression, which also contains
|
|
278
|
+
* dots — must not be split into a bogus provider (whose brand logo we'd then go
|
|
279
|
+
* and fetch). */
|
|
280
|
+
const ACTION_PATH = /^[a-z0-9_-]+(\.[a-z0-9_-]+)+$/i;
|
|
281
|
+
/** Split a hub action path into provider / resource / operation. Null when the
|
|
282
|
+
* value isn't a dotted path (a `${…}` expression, or a bare word), so callers
|
|
283
|
+
* fall back to showing it verbatim instead of inventing structure. */
|
|
284
|
+
function parseActionPath(path) {
|
|
285
|
+
if (!ACTION_PATH.test(path.trim())) return null;
|
|
286
|
+
const [provider, ...rest] = path.trim().split(".");
|
|
287
|
+
return {
|
|
288
|
+
provider,
|
|
289
|
+
operation: rest[rest.length - 1],
|
|
290
|
+
resource: rest.length > 1 ? rest.slice(0, -1).join(".") : void 0
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* The operation label for an action path, in n8n's `operation: resource` shape:
|
|
295
|
+
* `github.pulls.reviews.create` → "create: pulls.reviews", `slack.postMessage`
|
|
296
|
+
* → "post message". The provider names the node itself (its title + logo), so
|
|
297
|
+
* it is deliberately absent here. A path we can't split is shown verbatim.
|
|
298
|
+
*/
|
|
299
|
+
function actionPathLabel(path) {
|
|
300
|
+
const parts = parseActionPath(path);
|
|
301
|
+
if (!parts) return path;
|
|
302
|
+
const operation = humanizeIdentifier(parts.operation, "lower");
|
|
303
|
+
return parts.resource ? `${operation}: ${parts.resource}` : operation;
|
|
304
|
+
}
|
|
305
|
+
//#endregion
|
|
306
|
+
//#region src/react/agent-graph/canvas-theme.ts
|
|
307
|
+
/** Motion is opt-OUT, so it is only used where the reader's preference can be
|
|
308
|
+
* read and says nothing against it. Somewhere without `matchMedia` cannot say
|
|
309
|
+
* a reader tolerates movement, so it gets none. */
|
|
310
|
+
function motionAllowed() {
|
|
311
|
+
return typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches === false;
|
|
312
|
+
}
|
|
313
|
+
/** React Flow adds its own .light/.dark class below the graph wrapper. Read
|
|
314
|
+
* that wrapper's inherited scheme so a nested WorkspaceLayout theme wins over
|
|
315
|
+
* the page root without React Flow's class influencing the answer. */
|
|
316
|
+
function currentColorMode(anchor) {
|
|
317
|
+
if (typeof document === "undefined" || typeof window === "undefined") return "light";
|
|
318
|
+
const scheme = window.getComputedStyle(anchor ?? document.documentElement).colorScheme;
|
|
319
|
+
if (scheme.startsWith("dark")) return "dark";
|
|
320
|
+
if (scheme.startsWith("light")) return "light";
|
|
321
|
+
return (anchor ?? document.documentElement).closest(".dark") ? "dark" : "light";
|
|
322
|
+
}
|
|
323
|
+
function useColorMode(wrapperRef, hasGraph) {
|
|
324
|
+
const [mode, setMode] = useState(() => currentColorMode(null));
|
|
325
|
+
useLayoutEffect(() => {
|
|
326
|
+
const anchor = hasGraph ? wrapperRef.current : null;
|
|
327
|
+
const update = () => setMode(currentColorMode(anchor));
|
|
328
|
+
update();
|
|
329
|
+
const observer = new MutationObserver(update);
|
|
330
|
+
for (let el = anchor ?? document.documentElement; el; el = el.parentElement) observer.observe(el, {
|
|
331
|
+
attributes: true,
|
|
332
|
+
attributeFilter: [
|
|
333
|
+
"class",
|
|
334
|
+
"data-theme",
|
|
335
|
+
"data-sandbox-theme",
|
|
336
|
+
"style"
|
|
337
|
+
]
|
|
338
|
+
});
|
|
339
|
+
return () => observer.disconnect();
|
|
340
|
+
}, [wrapperRef, hasGraph]);
|
|
341
|
+
return mode;
|
|
342
|
+
}
|
|
343
|
+
/** Selection preserves the status border and stays quieter than failure or a response request. */
|
|
344
|
+
const SELECTION_OUTLINE = {
|
|
345
|
+
outline: "1px solid hsl(var(--foreground) / .45)",
|
|
346
|
+
outlineOffset: 2
|
|
347
|
+
};
|
|
348
|
+
//#endregion
|
|
349
|
+
//#region src/react/agent-graph/graph-style.ts
|
|
350
|
+
const RESTING_SHADOW = "inset 0 1px 0 hsl(var(--foreground) / 0.06), 0 1px 3px hsl(var(--shadow-color) / 0.08)";
|
|
351
|
+
const RESTING_BORDER = "hsl(var(--foreground) / 0.14)";
|
|
352
|
+
function edgeColor(status) {
|
|
353
|
+
return status === "failed" || status === "waiting" ? `var(${statusMeta(status === "waiting" ? "needs-you" : "failed").token})` : "color-mix(in srgb, hsl(var(--muted-foreground)) 80%, transparent)";
|
|
354
|
+
}
|
|
355
|
+
//#endregion
|
|
356
|
+
export { fmtCost as C, fmtTokens as D, fmtTokenTotal as E, clampPreview as S, fmtEventTime as T, syncAmbient as _, motionAllowed as a, useMotionAllowed as b, humanizeIdentifier as c, loadElk as d, GraphErrorBoundary as f, ambientStyle as g, agentQuietActivity as h, SELECTION_OUTLINE as i, parseActionPath as l, activityTiming as m, RESTING_SHADOW as n, useColorMode as o, retryImport as p, edgeColor as r, actionPathLabel as s, RESTING_BORDER as t, shortModel as u, tokenMilliseconds as v, fmtDuration as w, useRunNow as x, useAttention as y };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as titled, A as pct, B as usdTick, C as costText, D as intervalGap, E as estimateNote, F as rateOrder, H as MARKER_SHAPES, I as tierAtLeast, J as markerPath, K as hbar, L as tierSummary, M as pts, N as rateDataGap, O as intervalName, P as rateIntervalGap, Q as text, R as tierTotal, S as TIERS_BEST_FIRST, T as duration, U as circle, V as table, W as hatch, X as rect, Y as polyline, Z as svgRoot, _ as groupRowHeight, a as OUTCOME_COLORS, at as plural, b as isRefusal, c as checkerColor, ct as wrap, d as MARK_VERDICTS, et as wideWidth, f as drawBands, g as eventsTable, h as eventsGap, i as ENDING_ORDER, it as listJoin, j as perPass, k as kn, l as EVENTS_READ, m as drawMarks, n as CHECKER_HUES, nt as esc, o as OUTCOME_ORDER, ot as textBlock, p as drawGroups, q as line, r as ENDING_COLORS, rt as fitLines, s as checkerClass, st as textWidth, t as timeline, tt as capitalize, v as markLabelRows, w as drawable, x as METHOD_NAME, z as usd } from "./timeline-B7c-cede.js";
|
|
2
|
+
import { n as reportedCount, r as sumReportedCounts, t as finiteNumber } from "./flow-trace-DRluIYw8.js";
|
|
2
3
|
//#region src/block.ts
|
|
3
4
|
/**
|
|
4
5
|
* The figure block: one markup for every figure on every surface.
|