ocwatch 0.4.0 → 0.6.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.
- package/README.md +22 -3
- package/package.json +4 -4
- package/src/client/dist/assets/GraphView-BZV40eAE.css +1 -0
- package/src/client/dist/assets/GraphView-KWCCGYb2.js +9 -0
- package/src/client/dist/assets/graph-Cw_XSlvx.js +7 -0
- package/src/client/dist/assets/index-CbgYG3pJ.js +23 -0
- package/src/client/dist/assets/index-CgDCc8Mm.css +1 -0
- package/src/client/dist/assets/motion-CGUGF2CN.js +9 -0
- package/src/client/dist/index.html +4 -2
- package/src/server/__tests__/helpers/testDb.ts +220 -0
- package/src/server/index.ts +27 -27
- package/src/server/logic/activityLogic.ts +260 -0
- package/src/server/logic/index.ts +2 -0
- package/src/server/logic/sessionLogic.ts +107 -0
- package/src/server/routes/parts.ts +9 -7
- package/src/server/routes/poll.ts +32 -46
- package/src/server/routes/projects.ts +10 -27
- package/src/server/routes/sessions.ts +159 -68
- package/src/server/routes/sse.ts +10 -4
- package/src/server/services/parsing.ts +211 -0
- package/src/server/services/pollService.ts +400 -116
- package/src/server/services/recentSessions.ts +14 -0
- package/src/server/services/sessionContext.ts +97 -0
- package/src/server/services/sessionService.ts +97 -193
- package/src/server/services/sessionTree.ts +92 -0
- package/src/server/storage/db.ts +63 -0
- package/src/server/storage/index.ts +28 -0
- package/src/server/storage/queries.ts +528 -0
- package/src/server/utils/projectResolver.ts +9 -3
- package/src/server/utils/sessionStatus.ts +5 -89
- package/src/server/validation.ts +2 -4
- package/src/server/watcher.ts +225 -82
- package/src/shared/constants.ts +8 -3
- package/src/shared/index.ts +3 -0
- package/src/shared/types/index.ts +48 -53
- package/src/shared/utils/activityUtils.ts +3 -2
- package/src/client/dist/assets/index-BIu7r5_5.css +0 -1
- package/src/client/dist/assets/index-BYMVif3u.js +0 -50
- package/src/server/storage/messageParser.ts +0 -169
- package/src/server/storage/partParser.ts +0 -532
- package/src/server/storage/sessionParser.ts +0 -180
package/README.md
CHANGED
|
@@ -19,9 +19,9 @@ Opens a dashboard at `http://localhost:50234` showing live agent sessions, tool
|
|
|
19
19
|
|
|
20
20
|
## Preview
|
|
21
21
|
|
|
22
|
-

|
|
22
|
+

|
|
23
23
|
|
|
24
|
-

|
|
25
25
|
|
|
26
26
|
## Options
|
|
27
27
|
|
|
@@ -35,7 +35,7 @@ Opens a dashboard at `http://localhost:50234` showing live agent sessions, tool
|
|
|
35
35
|
## What it monitors
|
|
36
36
|
|
|
37
37
|
- **Sessions** — active and recent agent sessions
|
|
38
|
-
- **
|
|
38
|
+
- **Diagram view** — stable parent/child activity tree with focus controls and agent inspector
|
|
39
39
|
- **Tool calls** — live tool invocations with metadata (LSP, AST, MCPs)
|
|
40
40
|
- **Plan progress** — task completion from `.sisyphus/boulder.json`
|
|
41
41
|
- **Activity stream** — real-time feed of agent actions
|
|
@@ -46,6 +46,25 @@ Opens a dashboard at `http://localhost:50234` showing live agent sessions, tool
|
|
|
46
46
|
- macOS
|
|
47
47
|
- [OpenCode](https://github.com/anomalyco/opencode) running (reads from `~/.local/share/opencode/storage/`)
|
|
48
48
|
|
|
49
|
+
## Testing
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Root Bun suite (scoped to src/ via bunfig.toml)
|
|
53
|
+
bun test
|
|
54
|
+
|
|
55
|
+
# Project-standard server/shared/integration command
|
|
56
|
+
bun run test
|
|
57
|
+
|
|
58
|
+
# Client unit tests (Vitest)
|
|
59
|
+
cd src/client && bun run test
|
|
60
|
+
|
|
61
|
+
# Client E2E tests (Playwright)
|
|
62
|
+
cd src/client && bun run test:e2e
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- Client unit tests use `*.vitest.ts` / `*.vitest.tsx`.
|
|
66
|
+
- Playwright specs use `*.pw.ts`.
|
|
67
|
+
|
|
49
68
|
## Disclaimer
|
|
50
69
|
|
|
51
70
|
This project is not built by the OpenCode team and is not affiliated with or endorsed by [OpenCode](https://opencode.ai) or [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ocwatch",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Real-time web dashboard for monitoring OpenCode agent activity",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/server/index.ts",
|
|
@@ -49,11 +49,11 @@
|
|
|
49
49
|
"author": "Postmodum37",
|
|
50
50
|
"license": "MIT",
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"hono": "^4.
|
|
53
|
-
"zod": "
|
|
52
|
+
"hono": "^4.12.5",
|
|
53
|
+
"zod": "~4.3.6"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@types/bun": "latest",
|
|
57
|
-
"typescript": "
|
|
57
|
+
"typescript": "~5.9.3"
|
|
58
58
|
}
|
|
59
59
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #777;--xy-background-pattern-lines-color-default: #777;--xy-background-pattern-cross-color-default: #777;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{a as i,j as e}from"./motion-CGUGF2CN.js";import{H,P as z,g as X,i as Z,B as J,C as ee,M as te,a as G}from"./graph-Cw_XSlvx.js";import{c as A,g as ne,C as se,f as K,a as ae,b as re,L as oe,M as ie,d as ce,E as le,A as de}from"./index-CbgYG3pJ.js";const ue=[["path",{d:"M12 6v6l4 2",key:"mmk7yg"}],["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}]],U=A("clock",ue);const pe=[["path",{d:"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49",key:"ct8e1f"}],["path",{d:"M14.084 14.158a3 3 0 0 1-4.242-4.242",key:"151rxh"}],["path",{d:"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143",key:"13bj9a"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]],xe=A("eye-off",pe);const me=[["path",{d:"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",key:"1nclc0"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]],he=A("eye",me);const fe=[["path",{d:"M12.659 22H18a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v9.34",key:"o6klzx"}],["path",{d:"M14 2v5a1 1 0 0 0 1 1h5",key:"wfsgrz"}],["path",{d:"M10.378 12.622a1 1 0 0 1 3 3.003L8.36 20.637a2 2 0 0 1-.854.506l-2.867.837a.5.5 0 0 1-.62-.62l.836-2.869a2 2 0 0 1 .506-.853z",key:"zhnas1"}]],ge=A("file-pen",fe);const be=[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"m21 3-7 7",key:"1l2asr"}],["path",{d:"m3 21 7-7",key:"tjx5ai"}],["path",{d:"M9 21H3v-6",key:"wtvkvv"}]],ye=A("maximize-2",be);const we=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M21 9H3",key:"1338ky"}],["path",{d:"M21 15H3",key:"9uk58r"}]],ve=A("rows-3",we);const je=[["path",{d:"M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",key:"1s2grr"}],["path",{d:"M20 2v4",key:"1rf3ol"}],["path",{d:"M22 4h-4",key:"gwowj6"}],["circle",{cx:"4",cy:"20",r:"2",key:"6kqj1y"}]],Ne=A("sparkles",je);const ke=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["circle",{cx:"12",cy:"12",r:"6",key:"1vlfrh"}],["circle",{cx:"12",cy:"12",r:"2",key:"1c9p78"}]],Ce=A("target",ke);const Me=[["path",{d:"M12 19h8",key:"baeox8"}],["path",{d:"m4 17 6-6-6-6",key:"1yngyt"}]],De=A("terminal",Me),Ae=i.memo(function({agent:s,status:a,className:n=""}){const d=ne(s),h=a==="working";return e.jsx("span",{className:`
|
|
2
|
+
inline-flex items-center
|
|
3
|
+
px-2.5 py-1
|
|
4
|
+
rounded-md
|
|
5
|
+
text-white text-xs font-semibold
|
|
6
|
+
shrink-0
|
|
7
|
+
${h?"animate-badge-glow":""}
|
|
8
|
+
${n}
|
|
9
|
+
`,style:{backgroundColor:d,"--badge-color":`${d}60`},children:s})}),Se=["filePath","command","pattern","query","url"],q=60;function Te(r){for(const s of Se){const a=r[s];if(!(typeof a!="string"||a===""))return a.length>q?"..."+a.slice(-q):a}return null}function Ie(r){if(!r||r.length===0)return null;const s=r[0],a=s.name.replace("mcp_",""),n=Te(s.input);return{toolName:a,toolArg:n}}const Re=i.memo(function({status:s}){switch(s){case"working":return e.jsx("span",{className:"flex items-center justify-center w-4 h-4 rounded-full animate-badge-glow",style:{"--badge-color":"rgba(88, 166, 255, 0.5)"},role:"img","aria-label":"Working",children:e.jsx(oe,{className:"w-3 h-3 text-accent animate-spin"})});case"idle":return e.jsx("span",{className:"flex items-center justify-center w-4 h-4",role:"img","aria-label":"Idle",children:e.jsx(re,{className:"w-3 h-3 text-success animate-pulse"})});case"waiting":return e.jsx("span",{className:"flex items-center justify-center w-4 h-4",role:"img","aria-label":"Waiting",children:e.jsx(U,{className:"w-3 h-3 text-amber-500"})});default:return e.jsx("span",{className:"flex items-center justify-center w-4 h-4",role:"img","aria-label":"Completed",children:e.jsx(ae,{className:"w-3 h-3 text-green-500"})})}}),_e=i.memo(function({activityType:s,pendingCount:a,patchCount:n}){if(!s||s==="idle")return null;switch(s){case"reasoning":return e.jsx("span",{className:"flex items-center gap-1 text-purple-400",title:"Reasoning",children:e.jsx(Ne,{className:"w-3 h-3"})});case"patch":return e.jsxs("span",{className:"flex items-center gap-1 text-orange-400",title:`Writing ${n} files`,children:[e.jsx(ge,{className:"w-3 h-3"}),n&&n>1&&e.jsx("span",{className:"text-[10px]",children:n})]});case"tool":return e.jsxs("span",{className:"flex items-center gap-1 text-blue-400",title:`Running ${a} tools`,children:[e.jsx(De,{className:"w-3 h-3"}),a&&a>1&&e.jsx("span",{className:"text-[10px]",children:a})]});case"waiting-tools":return e.jsx("span",{className:"flex items-center gap-1 text-amber-400",title:"Waiting for tools",children:e.jsx(U,{className:"w-3 h-3"})});case"waiting-user":return e.jsx("span",{className:"flex items-center text-warning",title:"Waiting for your input",children:e.jsx(ie,{className:"w-3.5 h-3.5"})});default:return null}}),Ee=i.memo(function({data:s}){const a=s,n=a.session;if(!n?.id||!n?.agent)return e.jsx("div",{className:"flex items-center justify-center w-[320px] min-h-[60px] rounded-md border border-error/50 bg-surface text-error text-xs p-2",children:"Invalid node data"});const d=n.status||"completed",h=d==="completed";let p=n.currentAction;n.activityType==="waiting-user"&&(!p||p==="question")?p="Waiting for your response":p||(n.workingChildCount&&n.workingChildCount>0?p=`Waiting on ${n.workingChildCount} agent${n.workingChildCount>1?"s":""}`:h&&n.parentID&&n.title&&(p=n.title));const f=Ie(n.toolCalls);return e.jsxs("div",{className:["relative flex flex-col w-[320px] rounded-md border bg-surface transition-[opacity,border-color,box-shadow,transform] duration-200",a.isFocused?"border-accent ring-1 ring-accent shadow-[0_0_18px_rgba(88,166,255,0.18)]":"border-border",a.isDimmed?"opacity-35 scale-[0.98]":h?"opacity-80":"opacity-100",n.activityType==="waiting-user"?"border-l-2 border-l-warning":"",d==="working"&&!a.isDimmed?"animate-node-pulse":""].join(" "),children:[e.jsx(H,{type:"target",position:z.Top,className:"!bg-border !w-2 !h-2"}),e.jsxs("div",{className:"flex items-center justify-between px-3 py-2 border-b border-border/50 bg-black/20",children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsx(Ae,{agent:n.agent,status:d}),n.nodeKind==="phase"&&e.jsx("span",{className:"px-1.5 py-0.5 rounded text-[10px] uppercase tracking-wide border border-border text-text-secondary",children:"Phase"}),e.jsx(Re,{status:d})]}),e.jsx(_e,{activityType:n.activityType,pendingCount:n.pendingToolCount,patchCount:n.patchFilesCount})]}),e.jsxs("div",{className:"p-3 flex flex-col gap-2",children:[e.jsx("div",{className:"text-xs text-text-secondary line-clamp-2 min-h-[1.5em]",title:p||"",children:p||e.jsx("span",{className:"italic opacity-50",children:"No activity"})}),f&&!n.activityType?.startsWith("waiting")&&e.jsxs("div",{className:"flex items-center gap-1.5 text-xs text-text-primary font-mono bg-black/30 rounded px-1.5 py-1",children:[e.jsx("span",{className:"text-gray-400 shrink-0",children:f.toolName}),f.toolArg&&e.jsx("span",{className:"text-gray-500 truncate",title:f.toolArg,children:f.toolArg})]}),a.collapsedDescendantCount>0&&e.jsxs("button",{type:"button",className:"nodrag nopan inline-flex items-center gap-1.5 w-fit px-2 py-1 rounded-full border border-border bg-background/80 text-[11px] text-text-secondary hover:text-text-primary hover:border-accent transition-colors",onClick:u=>{u.stopPropagation(),a.onToggleCollapse(n.id)},children:[e.jsx(se,{className:"w-3 h-3"}),e.jsxs("span",{children:["+",a.collapsedDescendantCount," completed"]})]})]}),e.jsxs("div",{className:"px-3 py-2 border-t border-border/50 flex items-center justify-between text-[10px] text-text-secondary bg-black/10",children:[e.jsx("div",{className:"flex flex-col truncate",children:(n.providerID||n.modelID)&&e.jsxs("span",{className:"truncate",title:`${n.providerID}/${n.modelID}`,children:[n.providerID,"/",n.modelID]})}),e.jsxs("div",{className:"flex flex-col items-end shrink-0",children:[e.jsx("span",{children:K(n.updatedAt)}),n.tokens!==void 0&&e.jsxs("span",{children:[n.tokens.toLocaleString()," toks"]})]})]}),e.jsx(H,{type:"source",position:z.Bottom,className:"!bg-border !w-2 !h-2"})]})}),Le="#58a6ff",$e="#22c55e",Fe="#30363d";function We({sourceX:r,sourceY:s,targetX:a,targetY:n,sourcePosition:d,targetPosition:h,data:p}){const[f]=X({sourceX:r,sourceY:s,sourcePosition:d,targetX:a,targetY:n,targetPosition:h,borderRadius:18,offset:20}),u=p??{direction:null,isDimmed:!1,reducedMotion:!1},x=u.direction==="up",l=u.direction!==null,m=l?x?$e:Le:Fe,y=[u.isDimmed?"opacity-25":"opacity-100",u.reducedMotion||!l?"":x?"graph-edge-return":"graph-edge-flow"].filter(Boolean).join(" ");return e.jsx("path",{d:f,fill:"none",stroke:m,strokeWidth:l?2.5:2,strokeLinecap:"round",className:y,style:{transition:"opacity 200ms ease, stroke 200ms ease, stroke-width 200ms ease",strokeDasharray:l?"10 8":void 0}})}const Oe=i.memo(We),F=320,Pe=140,W=72,Be=120,He=120;function V(r,s){const a=new Date(r.createdAt).getTime()-new Date(s.createdAt).getTime();return a!==0?a:r.id.localeCompare(s.id)}function ze(r){return r.status!=="completed"}function Ge(r,s){const a=new Set;let n=s.get(r);for(;n?.parentID;)a.add(n.parentID),n=s.get(n.parentID);return a}function qe(r,s){const a=new Set,n=[...s.get(r)??[]];for(;n.length>0;){const d=n.pop();d&&(a.add(d.id),n.push(...s.get(d.id)??[]))}return a}function Ve(r,s,a){const n=new Map,d=new Map,h=u=>{const x=n.get(u);if(x!==void 0)return x;const l=s.get(u)??[];if(l.length===0)return n.set(u,F),F;let m=0;for(const k of l)m+=h(k.id);m+=W*Math.max(0,l.length-1);const y=Math.max(F,m);return n.set(u,y),y},p=(u,x,l)=>{const m=s.get(u)??[],y=h(u),k=x+y/2-F/2,C=l*(Pe+He);if(d.set(u,a==="TB"?{x:k,y:C}:{x:C,y:k}),m.length===0)return;const b=m.map(j=>h(j.id)),T=b.reduce((j,M)=>j+M,0)+W*Math.max(0,m.length-1);let I=x+(y-T)/2;for(let j=0;j<m.length;j+=1){const M=m[j],S=b[j];p(M.id,I,l+1),I+=S+W}};let f=0;for(const u of r){const x=h(u);p(u,f,0),f+=x+Be}return d}function Ke({sessions:r,direction:s,focusedNodeId:a,focusActive:n,showCompleted:d,expandedNodeIds:h,reverseFlowNodeIds:p,reducedMotion:f,onToggleCollapse:u}){const x=new Map,l=new Map;for(const t of r)x.set(t.id,t);const m=r.filter(t=>!t.parentID||!x.has(t.parentID)).sort(V);for(const t of r){if(!t.parentID||!x.has(t.parentID))continue;const w=l.get(t.parentID);w?w.push(t):l.set(t.parentID,[t])}for(const t of l.values())t.sort(V);const y=new Map,k=new Map,C=t=>{const w=l.get(t)??[];let v=0,o=!1;for(const c of w){const D=C(c.id);v+=D.descendants+1,o=o||ze(c)||D.hasActive}return y.set(t,v),k.set(t,o),{descendants:v,hasActive:o}};for(const t of m)C(t.id);const b=new Set,T=new Map,I=t=>t.status==="completed"&&!k.get(t.id)&&(y.get(t.id)??0)===0,j=t=>(n||!d)&&t.status==="completed"&&!k.get(t.id)&&(y.get(t.id)??0)>0&&!h.has(t.id),M=(t,w=!1)=>{const v=x.get(t);if(!v||!w&&(n||!d)&&I(v))return;if(b.add(t),j(v)){T.set(t,y.get(t)??0);return}const o=l.get(t)??[];for(const c of o)M(c.id)};for(const t of m)M(t.id,!0);const S=new Map;for(const[t,w]of l){const v=w.filter(o=>b.has(o.id));v.length>0&&S.set(t,v)}const R=m.filter(t=>b.has(t.id)),N=Ve(R.map(t=>t.id),S,s),g=new Set;if(a&&b.has(a)){g.add(a);for(const t of Ge(a,x))g.add(t);for(const t of qe(a,S))g.add(t)}const _=r.filter(t=>b.has(t.id)).map(t=>({id:t.id,type:"agentNode",position:N.get(t.id)??{x:0,y:0},draggable:!1,selectable:!1,data:{session:t,isFocused:a===t.id,isDimmed:g.size>0&&!g.has(t.id),collapsedDescendantCount:T.get(t.id)??0,onToggleCollapse:u}})),$=r.filter(t=>t.parentID&&b.has(t.id)&&b.has(t.parentID)).map(t=>{let w=null;t.status==="working"?w="down":p.has(t.id)&&(w="up");const v=g.size===0||(t.parentID?g.has(t.parentID)&&g.has(t.id):!1);return{id:`${t.parentID}-${t.id}`,source:t.parentID,target:t.id,type:"animatedEdge",selectable:!1,data:{direction:w,isDimmed:!v,reducedMotion:f}}});return{nodes:_,edges:$,visibleNodeCount:_.length,hiddenCompletedCount:Math.max(0,r.length-_.length),structureKey:[s,n?"focus":"all",d?"show":"hide",Array.from(h).sort().join("|"),_.map(t=>t.id).sort().join("|"),$.map(t=>t.id).sort().join("|")].join("::")}}const Ue={agentNode:Ee},Ye={animatedEdge:Oe},Qe=2500;function O({children:r,testId:s,headerRight:a}){return e.jsxs("div",{className:"h-full w-full bg-surface overflow-hidden flex flex-col","data-testid":s,children:[e.jsxs("div",{className:"px-4 py-3 border-b border-border flex items-center justify-between bg-surface z-10",children:[e.jsx("h3",{className:"font-semibold text-sm",children:"Live Activity"}),a]}),r]})}function Xe(){const[r,s]=i.useState(!1);return i.useEffect(()=>{const a=window.matchMedia("(prefers-reduced-motion: reduce)"),n=()=>s(a.matches);return n(),a.addEventListener("change",n),()=>a.removeEventListener("change",n)},[]),r}const tt=({rootSessionId:r,sessions:s,loading:a})=>{const n=Xe(),d=i.useRef(null),h=i.useRef(null),p=i.useRef(new Map),f=i.useRef(new Map),[u,x]=i.useState("TB"),[l,m]=i.useState(!0),[y,k]=i.useState(null),[C,b]=i.useState(null),[T,I]=i.useState(new Set),[j,M]=i.useState(new Set);i.useEffect(()=>{x("TB"),m(!0),k(null),b(null),I(new Set),M(new Set),p.current=new Map},[r]),i.useEffect(()=>{const o=f.current;return()=>{for(const c of o.values())clearTimeout(c);o.clear()}},[]),i.useEffect(()=>{const o=new Map(s.map(c=>[c.id,c]));for(const c of s){if(!c.parentID)continue;const D=p.current.get(c.id),Y=c.status??"completed",P=o.get(c.parentID),Q=P?.status==="working"||P?.status==="waiting";if(D==="working"&&Y==="completed"&&Q){M(E=>{const L=new Set(E);return L.add(c.id),L});const B=f.current.get(c.id);B&&clearTimeout(B),f.current.set(c.id,setTimeout(()=>{f.current.delete(c.id),M(E=>{if(!E.has(c.id))return E;const L=new Set(E);return L.delete(c.id),L})},Qe))}}p.current=new Map(s.map(c=>[c.id,c.status??"completed"]))},[s]);const S=i.useCallback(o=>{I(c=>{const D=new Set(c);return D.has(o)?D.delete(o):D.add(o),D})},[]),R=y??s.length>80,N=i.useMemo(()=>Ke({sessions:s,direction:u,focusedNodeId:C,focusActive:R,showCompleted:l,expandedNodeIds:T,reverseFlowNodeIds:j,reducedMotion:n,onToggleCollapse:S}),[s,u,C,R,l,T,j,n,S]),g=i.useCallback(()=>{!d.current||N.visibleNodeCount===0||d.current.fitView({padding:.18,duration:n?0:220,includeHiddenNodes:!1})},[N.visibleNodeCount,n]);i.useEffect(()=>{h.current!==r&&(h.current=r,N.visibleNodeCount!==0&&requestAnimationFrame(()=>{g()}))},[r,N.visibleNodeCount,g]);const _=i.useCallback((o,c)=>{b(c.id)},[]),$=i.useCallback(()=>{b(null)},[]),t=i.useMemo(()=>s.find(o=>o.id===C)??null,[s,C]),w=i.useMemo(()=>s.some(o=>o.status==="working"||o.status==="waiting"),[s]),v=i.useMemo(()=>s.filter(o=>o.status==="working"||o.status==="waiting"||o.status==="idle").length,[s]);return a&&s.length===0?e.jsx(O,{testId:"graph-view-loading",children:e.jsx(ce,{})}):s.length===0?e.jsx(O,{testId:"graph-view-empty",children:e.jsx(le,{icon:de,title:"No Activity",description:"Session activity will appear here when messages and tools start flowing."})}):e.jsx(O,{testId:"graph-view",headerRight:e.jsxs("div",{className:"flex items-center gap-3 text-xs text-text-secondary",children:[e.jsxs("span",{children:[v," active"]}),e.jsxs("span",{children:[N.visibleNodeCount," shown"]}),N.hiddenCompletedCount>0&&e.jsxs("span",{children:[N.hiddenCompletedCount," hidden"]}),w?e.jsxs("span",{className:"relative flex h-2 w-2",title:"Activity in progress",children:[e.jsx("span",{className:"animate-ping absolute inline-flex h-full w-full rounded-full bg-accent opacity-75"}),e.jsx("span",{className:"relative inline-flex rounded-full h-2 w-2 bg-accent"})]}):void 0]}),children:e.jsx("div",{className:"flex-1 w-full h-full relative",children:e.jsxs(Z,{nodes:N.nodes,edges:N.edges,nodeTypes:Ue,edgeTypes:Ye,onInit:o=>{d.current=o,g()},onNodeClick:_,onPaneClick:$,fitViewOptions:{padding:.18},nodesDraggable:!1,nodesConnectable:!1,elementsSelectable:!1,selectionOnDrag:!1,onlyRenderVisibleElements:N.visibleNodeCount>120,minZoom:.1,maxZoom:2,children:[e.jsx(J,{color:"#374151",gap:16}),e.jsx(ee,{showInteractive:!1}),N.visibleNodeCount>30?e.jsx(te,{pannable:!0,zoomable:!0,nodeColor:"#1f2937",maskColor:"rgba(13, 17, 23, 0.55)"}):null,e.jsx(G,{position:"top-left",children:e.jsxs("div",{className:"flex flex-wrap items-center gap-2 rounded-lg border border-border bg-surface/95 px-3 py-2 shadow-sm backdrop-blur",children:[e.jsxs("button",{type:"button",onClick:g,className:"inline-flex items-center gap-1.5 rounded-md border border-border px-2 py-1 text-xs text-text-secondary hover:text-text-primary hover:border-accent transition-colors",children:[e.jsx(ye,{className:"w-3.5 h-3.5"}),"Fit"]}),e.jsxs("button",{type:"button",onClick:()=>{x(o=>o==="TB"?"LR":"TB"),requestAnimationFrame(()=>g())},"aria-label":"Toggle graph direction",className:"inline-flex items-center gap-1.5 rounded-md border border-border px-2 py-1 text-xs text-text-secondary hover:text-text-primary hover:border-accent transition-colors",children:[e.jsx(ve,{className:"w-3.5 h-3.5"}),u==="TB"?"Top-down":"Left-right"]}),e.jsxs("button",{type:"button",onClick:()=>{k(!R),requestAnimationFrame(()=>g())},"aria-pressed":R,className:["inline-flex items-center gap-1.5 rounded-md border px-2 py-1 text-xs transition-colors",R?"border-accent text-accent bg-accent/10":"border-border text-text-secondary hover:text-text-primary hover:border-accent"].join(" "),children:[e.jsx(Ce,{className:"w-3.5 h-3.5"}),"Focus active"]}),e.jsxs("button",{type:"button",onClick:()=>{m(o=>!o),requestAnimationFrame(()=>g())},"aria-pressed":!l,className:["inline-flex items-center gap-1.5 rounded-md border px-2 py-1 text-xs transition-colors",l?"border-border text-text-secondary hover:text-text-primary hover:border-accent":"border-accent text-accent bg-accent/10"].join(" "),children:[l?e.jsx(he,{className:"w-3.5 h-3.5"}):e.jsx(xe,{className:"w-3.5 h-3.5"}),l?"Hide completed":"Show completed"]})]})}),t?e.jsx(G,{position:"bottom-left",children:e.jsxs("div",{className:"w-[300px] rounded-lg border border-border bg-surface/95 px-4 py-3 shadow-sm backdrop-blur",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"text-xs uppercase tracking-wide text-text-secondary",children:t.nodeKind==="phase"?"Agent phase":"Agent session"}),e.jsx("div",{className:"text-sm font-semibold text-text-primary truncate",children:t.agent}),e.jsx("div",{className:"text-xs text-text-secondary truncate",children:t.title||"Untitled session"})]}),e.jsx("button",{type:"button",onClick:()=>b(null),className:"text-xs text-text-secondary hover:text-text-primary transition-colors",children:"Clear"})]}),e.jsxs("div",{className:"mt-3 space-y-2 text-xs",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsx("span",{className:"inline-flex items-center rounded-full border border-border px-2 py-0.5 text-[10px] uppercase tracking-wide text-text-secondary",children:t.status??"completed"}),e.jsxs("span",{className:"text-text-secondary",children:["updated ",K(t.updatedAt)]})]}),e.jsx("div",{className:"text-text-secondary",children:t.currentAction||"No active task"}),e.jsxs("div",{className:"flex items-center justify-between gap-3 text-text-secondary",children:[e.jsx("span",{className:"truncate",children:t.providerID&&t.modelID?`${t.providerID}/${t.modelID}`:"model unknown"}),e.jsxs("span",{className:"shrink-0",children:[t.tokens?.toLocaleString()??0," toks"]})]}),t.toolCalls?.[0]?e.jsx("div",{className:"rounded-md bg-background/80 px-2 py-1 font-mono text-[11px] text-text-secondary truncate",children:t.toolCalls[0].summary}):null]})]})}):null]})})})};export{tt as GraphView,tt as default};
|