@dxos/react-ui-trace 0.11.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.
- package/LICENSE +105 -0
- package/README.md +3 -0
- package/dist/lib/index.mjs +2868 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/testing.mjs +338 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/lib/translations.mjs +19 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/types/src/components/Gantt/Gantt.d.ts +68 -0
- package/dist/types/src/components/Gantt/Gantt.d.ts.map +1 -0
- package/dist/types/src/components/Gantt/Gantt.stories.d.ts +30 -0
- package/dist/types/src/components/Gantt/Gantt.stories.d.ts.map +1 -0
- package/dist/types/src/components/Gantt/index.d.ts +2 -0
- package/dist/types/src/components/Gantt/index.d.ts.map +1 -0
- package/dist/types/src/components/ProcessTree/ProcessTree.d.ts +32 -0
- package/dist/types/src/components/ProcessTree/ProcessTree.d.ts.map +1 -0
- package/dist/types/src/components/ProcessTree/ProcessTree.stories.d.ts +8 -0
- package/dist/types/src/components/ProcessTree/ProcessTree.stories.d.ts.map +1 -0
- package/dist/types/src/components/ProcessTree/index.d.ts +2 -0
- package/dist/types/src/components/ProcessTree/index.d.ts.map +1 -0
- package/dist/types/src/components/Timeline/Timeline.d.ts +50 -0
- package/dist/types/src/components/Timeline/Timeline.d.ts.map +1 -0
- package/dist/types/src/components/Timeline/Timeline.stories.d.ts +24 -0
- package/dist/types/src/components/Timeline/Timeline.stories.d.ts.map +1 -0
- package/dist/types/src/components/Timeline/index.d.ts +4 -0
- package/dist/types/src/components/Timeline/index.d.ts.map +1 -0
- package/dist/types/src/components/Timeline/timeline-options.d.ts +9 -0
- package/dist/types/src/components/Timeline/timeline-options.d.ts.map +1 -0
- package/dist/types/src/components/Timeline/timeline-printer.d.ts +7 -0
- package/dist/types/src/components/Timeline/timeline-printer.d.ts.map +1 -0
- package/dist/types/src/components/Timeline/timeline-printer.test.d.ts +2 -0
- package/dist/types/src/components/Timeline/timeline-printer.test.d.ts.map +1 -0
- package/dist/types/src/components/TracePanel/TracePanel.d.ts +28 -0
- package/dist/types/src/components/TracePanel/TracePanel.d.ts.map +1 -0
- package/dist/types/src/components/TracePanel/dxn-extractor.d.ts +19 -0
- package/dist/types/src/components/TracePanel/dxn-extractor.d.ts.map +1 -0
- package/dist/types/src/components/TracePanel/dxn-extractor.test.d.ts +2 -0
- package/dist/types/src/components/TracePanel/dxn-extractor.test.d.ts.map +1 -0
- package/dist/types/src/components/TracePanel/index.d.ts +4 -0
- package/dist/types/src/components/TracePanel/index.d.ts.map +1 -0
- package/dist/types/src/components/TracePanel/trace-filter.d.ts +39 -0
- package/dist/types/src/components/TracePanel/trace-filter.d.ts.map +1 -0
- package/dist/types/src/components/TracePanel/trace-filter.test.d.ts +2 -0
- package/dist/types/src/components/TracePanel/trace-filter.test.d.ts.map +1 -0
- package/dist/types/src/components/TracePanel/useTraceMenu.d.ts +15 -0
- package/dist/types/src/components/TracePanel/useTraceMenu.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +5 -0
- package/dist/types/src/components/index.d.ts.map +1 -0
- package/dist/types/src/execution-graph/execution-graph.d.ts +139 -0
- package/dist/types/src/execution-graph/execution-graph.d.ts.map +1 -0
- package/dist/types/src/execution-graph/execution-graph.test.d.ts +2 -0
- package/dist/types/src/execution-graph/execution-graph.test.d.ts.map +1 -0
- package/dist/types/src/execution-graph/index.d.ts +4 -0
- package/dist/types/src/execution-graph/index.d.ts.map +1 -0
- package/dist/types/src/execution-graph/pending-block-status.d.ts +26 -0
- package/dist/types/src/execution-graph/pending-block-status.d.ts.map +1 -0
- package/dist/types/src/execution-graph/pending-block-status.test.d.ts +2 -0
- package/dist/types/src/execution-graph/pending-block-status.test.d.ts.map +1 -0
- package/dist/types/src/execution-graph/remote-snapshot.test.d.ts +2 -0
- package/dist/types/src/execution-graph/remote-snapshot.test.d.ts.map +1 -0
- package/dist/types/src/execution-graph/span-tree.d.ts +106 -0
- package/dist/types/src/execution-graph/span-tree.d.ts.map +1 -0
- package/dist/types/src/execution-graph/span-tree.test.d.ts +2 -0
- package/dist/types/src/execution-graph/span-tree.test.d.ts.map +1 -0
- package/dist/types/src/execution-graph/sub-agent-delegation.test.d.ts +2 -0
- package/dist/types/src/execution-graph/sub-agent-delegation.test.d.ts.map +1 -0
- package/dist/types/src/execution-graph/testing/collect-trace-events.d.ts +40 -0
- package/dist/types/src/execution-graph/testing/collect-trace-events.d.ts.map +1 -0
- package/dist/types/src/execution-graph/testing/index.d.ts +2 -0
- package/dist/types/src/execution-graph/testing/index.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +4 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -0
- package/dist/types/src/hooks/useExecutionGraph.d.ts +17 -0
- package/dist/types/src/hooks/useExecutionGraph.d.ts.map +1 -0
- package/dist/types/src/hooks/useSessionTimeline.d.ts +17 -0
- package/dist/types/src/hooks/useSessionTimeline.d.ts.map +1 -0
- package/dist/types/src/hooks/useTraceMessages.d.ts +17 -0
- package/dist/types/src/hooks/useTraceMessages.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +5 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/session-timeline/index.d.ts +3 -0
- package/dist/types/src/session-timeline/index.d.ts.map +1 -0
- package/dist/types/src/session-timeline/session-timeline.d.ts +19 -0
- package/dist/types/src/session-timeline/session-timeline.d.ts.map +1 -0
- package/dist/types/src/session-timeline/session-timeline.test.d.ts +2 -0
- package/dist/types/src/session-timeline/session-timeline.test.d.ts.map +1 -0
- package/dist/types/src/session-timeline/types.d.ts +129 -0
- package/dist/types/src/session-timeline/types.d.ts.map +1 -0
- package/dist/types/src/testing/index.d.ts +5 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/simulated-agent.d.ts +63 -0
- package/dist/types/src/testing/simulated-agent.d.ts.map +1 -0
- package/dist/types/src/testing/snapshot-playback.d.ts +12 -0
- package/dist/types/src/testing/snapshot-playback.d.ts.map +1 -0
- package/dist/types/src/testing/test-trace.d.ts +5 -0
- package/dist/types/src/testing/test-trace.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +19 -0
- package/dist/types/src/translations.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +77 -0
- package/src/components/Gantt/Gantt.stories.tsx +241 -0
- package/src/components/Gantt/Gantt.tsx +589 -0
- package/src/components/Gantt/index.ts +5 -0
- package/src/components/ProcessTree/ProcessTree.stories.tsx +95 -0
- package/src/components/ProcessTree/ProcessTree.tsx +265 -0
- package/src/components/ProcessTree/index.ts +5 -0
- package/src/components/Timeline/Timeline.stories.tsx +326 -0
- package/src/components/Timeline/Timeline.tsx +534 -0
- package/src/components/Timeline/git.drawio.svg +821 -0
- package/src/components/Timeline/index.ts +7 -0
- package/src/components/Timeline/timeline-options.ts +27 -0
- package/src/components/Timeline/timeline-printer.test.ts +76 -0
- package/src/components/Timeline/timeline-printer.ts +223 -0
- package/src/components/TracePanel/TracePanel.tsx +248 -0
- package/src/components/TracePanel/dxn-extractor.test.ts +153 -0
- package/src/components/TracePanel/dxn-extractor.ts +166 -0
- package/src/components/TracePanel/index.ts +7 -0
- package/src/components/TracePanel/trace-filter.test.ts +137 -0
- package/src/components/TracePanel/trace-filter.ts +120 -0
- package/src/components/TracePanel/useTraceMenu.ts +95 -0
- package/src/components/index.ts +8 -0
- package/src/execution-graph/SPEC.md +749 -0
- package/src/execution-graph/execution-graph.test.ts +1205 -0
- package/src/execution-graph/execution-graph.ts +1076 -0
- package/src/execution-graph/index.ts +35 -0
- package/src/execution-graph/pending-block-status.test.ts +118 -0
- package/src/execution-graph/pending-block-status.ts +88 -0
- package/src/execution-graph/remote-snapshot.test.ts +116 -0
- package/src/execution-graph/span-tree.test.ts +370 -0
- package/src/execution-graph/span-tree.ts +404 -0
- package/src/execution-graph/sub-agent-delegation.test.ts +65 -0
- package/src/execution-graph/testing/collect-trace-events.ts +76 -0
- package/src/execution-graph/testing/index.ts +5 -0
- package/src/execution-graph/testing/sub-agent-delegation.json +1285 -0
- package/src/hooks/index.ts +7 -0
- package/src/hooks/useExecutionGraph.ts +107 -0
- package/src/hooks/useSessionTimeline.ts +53 -0
- package/src/hooks/useTraceMessages.ts +58 -0
- package/src/index.ts +8 -0
- package/src/session-timeline/index.ts +6 -0
- package/src/session-timeline/session-timeline.test.ts +662 -0
- package/src/session-timeline/session-timeline.ts +605 -0
- package/src/session-timeline/types.ts +100 -0
- package/src/testing/index.ts +8 -0
- package/src/testing/simulated-agent.ts +293 -0
- package/src/testing/snapshot-playback.ts +45 -0
- package/src/testing/test-trace.ts +22 -0
- package/src/translations.ts +29 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useAtomValue } from '@effect/atom-react/Hooks';
|
|
6
|
+
import * as Duration from 'effect/Duration';
|
|
7
|
+
import { pipe } from 'effect/Function';
|
|
8
|
+
import * as Atom from 'effect/unstable/reactivity/Atom';
|
|
9
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
10
|
+
|
|
11
|
+
import * as Process from '@dxos/compute/Process';
|
|
12
|
+
import { type Space } from '@dxos/react-client/echo';
|
|
13
|
+
|
|
14
|
+
import { filterTraceMessages } from '../components/TracePanel/trace-filter.ts';
|
|
15
|
+
import { type ExecutionGraph, buildExecutionGraph } from '../execution-graph/index.ts';
|
|
16
|
+
|
|
17
|
+
import { getTraceMessagesAtom } from './useTraceMessages.ts';
|
|
18
|
+
|
|
19
|
+
// Stable refs.
|
|
20
|
+
const atomEmpty = Atom.make(() => [] as const);
|
|
21
|
+
const NO_PIDS: readonly string[] = [];
|
|
22
|
+
|
|
23
|
+
// How often the graph re-checks for spans that timed out with no closing event.
|
|
24
|
+
// Coarse-grained on purpose: `spanTimeoutMs` operates on a 20-minute scale, so there is no
|
|
25
|
+
// benefit to re-deriving the graph more often than this just to catch the timeout crossing.
|
|
26
|
+
const SPAN_TIMEOUT_CHECK_INTERVAL_MS = 60_000;
|
|
27
|
+
|
|
28
|
+
export type UseExecutionGraphOptions = {
|
|
29
|
+
collapseCompletedSpans?: boolean;
|
|
30
|
+
eventLimit?: number;
|
|
31
|
+
/** Pids to narrow the graph to (with their descendants); empty shows everything. */
|
|
32
|
+
selectedPids?: readonly string[];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The commit graph of a space's trace, rebuilt as messages land and as the process tree changes.
|
|
37
|
+
* `processesAtom` is the host's live process tree (a running agent draws a spinner commit); without
|
|
38
|
+
* it the graph is the durable trace alone.
|
|
39
|
+
*/
|
|
40
|
+
export const useExecutionGraph = (
|
|
41
|
+
space: Space,
|
|
42
|
+
processesAtom: Atom.Atom<readonly Process.Info[]> | undefined,
|
|
43
|
+
{ collapseCompletedSpans, eventLimit, selectedPids = NO_PIDS }: UseExecutionGraphOptions = {},
|
|
44
|
+
): ExecutionGraph => {
|
|
45
|
+
// Ticks periodically so spans that are still open purely because no new trace event has
|
|
46
|
+
// arrived (e.g. the runtime crashed before writing its `operationEnd`) eventually get
|
|
47
|
+
// force-closed by `buildExecutionGraph`'s `spanTimeoutMs` check, instead of staying stuck
|
|
48
|
+
// until unrelated trace activity happens to trigger a recompute.
|
|
49
|
+
const [now, setNow] = useState(() => Date.now());
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
const id = setInterval(() => setNow(Date.now()), SPAN_TIMEOUT_CHECK_INTERVAL_MS);
|
|
52
|
+
return () => clearInterval(id);
|
|
53
|
+
}, []);
|
|
54
|
+
|
|
55
|
+
const atom = useMemo(
|
|
56
|
+
() =>
|
|
57
|
+
getExecutionGraph(space, processesAtom ?? atomEmpty, { collapseCompletedSpans, eventLimit, selectedPids, now }),
|
|
58
|
+
[space, processesAtom, collapseCompletedSpans, eventLimit, selectedPids, now],
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
return useAtomValue(atom);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** Identity for the graph: only a process appearing, disappearing or changing state redraws it. */
|
|
65
|
+
const sameProcesses = (left: readonly Process.Info[], right: readonly Process.Info[]): boolean =>
|
|
66
|
+
left.length === right.length &&
|
|
67
|
+
left.every((process, index) => process.pid === right[index].pid && process.state === right[index].state);
|
|
68
|
+
|
|
69
|
+
const getExecutionGraph = (
|
|
70
|
+
space: Space,
|
|
71
|
+
processesAtom: Atom.Atom<readonly Process.Info[]>,
|
|
72
|
+
{
|
|
73
|
+
collapseCompletedSpans = true,
|
|
74
|
+
eventLimit = 100,
|
|
75
|
+
selectedPids = NO_PIDS,
|
|
76
|
+
now,
|
|
77
|
+
}: UseExecutionGraphOptions & { now: number },
|
|
78
|
+
): Atom.Atom<ExecutionGraph> => {
|
|
79
|
+
const traceMessages = getTraceMessagesAtom(space).pipe(
|
|
80
|
+
Atom.map((messages) => filterTraceMessages(messages, selectedPids)),
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const activeProcesses = pipe(
|
|
84
|
+
processesAtom,
|
|
85
|
+
Atom.debounce(Duration.millis(500)),
|
|
86
|
+
Atom.map((processes) =>
|
|
87
|
+
processes.filter(
|
|
88
|
+
(process) =>
|
|
89
|
+
(process.state === Process.State.RUNNING || process.state === Process.State.HYBERNATING) &&
|
|
90
|
+
(selectedPids.length === 0 || selectedPids.includes(process.pid)),
|
|
91
|
+
),
|
|
92
|
+
),
|
|
93
|
+
// The monitor rebuilds the process list on every poll, so without a structural comparison the
|
|
94
|
+
// graph would be rebuilt on each tick even when nothing moved.
|
|
95
|
+
Atom.withEquality(sameProcesses),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
return Atom.make((get) =>
|
|
99
|
+
buildExecutionGraph({
|
|
100
|
+
traceMessages: get(traceMessages),
|
|
101
|
+
activeProcesses: get(activeProcesses),
|
|
102
|
+
collapseCompletedSpans,
|
|
103
|
+
eventLimit,
|
|
104
|
+
now,
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
107
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Duration from 'effect/Duration';
|
|
6
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
7
|
+
|
|
8
|
+
import type * as Process from '@dxos/compute/Process';
|
|
9
|
+
import { type Space } from '@dxos/react-client/echo';
|
|
10
|
+
import { type Task } from '@dxos/types';
|
|
11
|
+
|
|
12
|
+
import { type Session, type SessionTimeline, buildSessionTimeline } from '../session-timeline/index.ts';
|
|
13
|
+
|
|
14
|
+
import { useTraceMessages } from './useTraceMessages.ts';
|
|
15
|
+
|
|
16
|
+
/** How often `now` advances while a session is open, so a running lane's range keeps growing. */
|
|
17
|
+
const TICK_MS = 5_000;
|
|
18
|
+
|
|
19
|
+
// The trace feed emits continuously while anything runs, and every emission rebuilds the whole
|
|
20
|
+
// timeline from the full message history — so the rebuild rate is capped rather than the feed's.
|
|
21
|
+
const TRACE_DEBOUNCE = Duration.millis(500);
|
|
22
|
+
|
|
23
|
+
const NO_PROCESSES: readonly Process.Info[] = [];
|
|
24
|
+
|
|
25
|
+
export type UseSessionTimelineOptions = {
|
|
26
|
+
/** The sessions shown; each contributes a session lane and its checklist's task lanes. */
|
|
27
|
+
sessions: readonly Session[];
|
|
28
|
+
tasks?: readonly Task.Task[];
|
|
29
|
+
/** The live process tree, from whichever monitor the host has; without it a session's liveness is read from the trace alone. */
|
|
30
|
+
processes?: readonly Process.Info[];
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The live gantt-shaped view of the given sessions: rebuilt as trace events land on the space's
|
|
35
|
+
* trace feed and as the process tree changes, and ticked so open lanes keep extending.
|
|
36
|
+
*/
|
|
37
|
+
export const useSessionTimeline = (
|
|
38
|
+
space: Space | undefined,
|
|
39
|
+
{ sessions, tasks, processes = NO_PROCESSES }: UseSessionTimelineOptions,
|
|
40
|
+
): SessionTimeline => {
|
|
41
|
+
const traceMessages = useTraceMessages(space, { debounce: TRACE_DEBOUNCE });
|
|
42
|
+
|
|
43
|
+
const [now, setNow] = useState(() => Date.now());
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
const interval = setInterval(() => setNow(Date.now()), TICK_MS);
|
|
46
|
+
return () => clearInterval(interval);
|
|
47
|
+
}, []);
|
|
48
|
+
|
|
49
|
+
return useMemo(
|
|
50
|
+
() => buildSessionTimeline({ traceMessages, processes, sessions, tasks, now }),
|
|
51
|
+
[traceMessages, processes, sessions, tasks, now],
|
|
52
|
+
);
|
|
53
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useAtomValue } from '@effect/atom-react/Hooks';
|
|
6
|
+
import * as Duration from 'effect/Duration';
|
|
7
|
+
import { pipe } from 'effect/Function';
|
|
8
|
+
import * as Atom from 'effect/unstable/reactivity/Atom';
|
|
9
|
+
import { useMemo } from 'react';
|
|
10
|
+
|
|
11
|
+
import { FeedTraceSink } from '@dxos/compute-runtime';
|
|
12
|
+
import * as Trace from '@dxos/compute/Trace';
|
|
13
|
+
import { Filter, Query } from '@dxos/echo';
|
|
14
|
+
import { type Space } from '@dxos/react-client/echo';
|
|
15
|
+
|
|
16
|
+
const atomEmpty = Atom.make(() => [] as const);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Atom of raw trace messages for a space — the input to `buildExecutionGraph`.
|
|
20
|
+
*/
|
|
21
|
+
export const getTraceMessagesAtom = (space: Space): Atom.Atom<readonly Trace.Message[]> =>
|
|
22
|
+
pipe(
|
|
23
|
+
space.db.query(FeedTraceSink.query).atom,
|
|
24
|
+
Atom.map(
|
|
25
|
+
(feeds) =>
|
|
26
|
+
// Query across ALL trace feeds: writers race on feed creation (the edge's indexer-backed
|
|
27
|
+
// lookup can miss a not-yet-indexed feed and create a duplicate), so a space may hold
|
|
28
|
+
// several trace feeds — reading only one would silently drop the others' events.
|
|
29
|
+
space.db.query(
|
|
30
|
+
feeds.length > 0
|
|
31
|
+
? Query.type(Trace.Message).from([...feeds])
|
|
32
|
+
: (Query.select(Filter.nothing()) as Query.Query<never>),
|
|
33
|
+
).atom,
|
|
34
|
+
),
|
|
35
|
+
(atom) => Atom.make((get) => get(get(atom))),
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
export type UseTraceMessagesOptions = {
|
|
39
|
+
/** Caps the re-render rate; the feed emits per message, which is far faster than a reader can read. */
|
|
40
|
+
debounce?: Duration.Duration;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Subscribes to the space invocation trace feed.
|
|
45
|
+
*/
|
|
46
|
+
export const useTraceMessages = (
|
|
47
|
+
space?: Space,
|
|
48
|
+
{ debounce }: UseTraceMessagesOptions = {},
|
|
49
|
+
): readonly Trace.Message[] => {
|
|
50
|
+
const atom = useMemo(() => {
|
|
51
|
+
if (!space) {
|
|
52
|
+
return atomEmpty;
|
|
53
|
+
}
|
|
54
|
+
const traces = getTraceMessagesAtom(space);
|
|
55
|
+
return debounce ? traces.pipe(Atom.debounce(debounce)) : traces;
|
|
56
|
+
}, [space, debounce]);
|
|
57
|
+
return useAtomValue(atom);
|
|
58
|
+
};
|
package/src/index.ts
ADDED