prompt_objects 0.3.1 → 0.4.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/Gemfile.lock +31 -29
  4. data/frontend/package-lock.json +123 -0
  5. data/frontend/package.json +4 -0
  6. data/frontend/src/App.tsx +58 -51
  7. data/frontend/src/canvas/CanvasView.tsx +113 -0
  8. data/frontend/src/canvas/ForceLayout.ts +115 -0
  9. data/frontend/src/canvas/SceneManager.ts +587 -0
  10. data/frontend/src/canvas/canvasStore.ts +47 -0
  11. data/frontend/src/canvas/constants.ts +95 -0
  12. data/frontend/src/canvas/controls/CameraControls.ts +98 -0
  13. data/frontend/src/canvas/edges/MessageArc.ts +149 -0
  14. data/frontend/src/canvas/inspector/InspectorPanel.tsx +31 -0
  15. data/frontend/src/canvas/inspector/POInspector.tsx +262 -0
  16. data/frontend/src/canvas/inspector/ToolCallInspector.tsx +67 -0
  17. data/frontend/src/canvas/nodes/PONode.ts +249 -0
  18. data/frontend/src/canvas/nodes/ToolCallNode.ts +116 -0
  19. data/frontend/src/canvas/types.ts +24 -0
  20. data/frontend/src/components/ChatPanel.tsx +13 -5
  21. data/frontend/src/components/Header.tsx +13 -1
  22. data/frontend/src/hooks/useWebSocket.ts +246 -189
  23. data/frontend/src/index.css +48 -0
  24. data/frontend/src/store/index.ts +19 -0
  25. data/frontend/src/types/index.ts +3 -0
  26. data/lib/prompt_objects/connectors/mcp.rb +3 -6
  27. data/lib/prompt_objects/environment.rb +8 -0
  28. data/lib/prompt_objects/mcp/tools/get_pending_requests.rb +1 -2
  29. data/lib/prompt_objects/mcp/tools/list_prompt_objects.rb +1 -2
  30. data/lib/prompt_objects/primitives/list_files.rb +1 -2
  31. data/lib/prompt_objects/prompt_object.rb +24 -6
  32. data/lib/prompt_objects/server/app.rb +9 -0
  33. data/lib/prompt_objects/server/public/assets/index-6y64NXFy.css +1 -0
  34. data/lib/prompt_objects/server/public/assets/index-xvyeb-5Z.js +4345 -0
  35. data/lib/prompt_objects/server/public/index.html +2 -2
  36. data/prompt_objects.gemspec +1 -1
  37. metadata +17 -4
  38. data/lib/prompt_objects/server/public/assets/index-Bkme6COu.css +0 -1
  39. data/lib/prompt_objects/server/public/assets/index-CQ7lVDF_.js +0 -77
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0a1ec32b66d34c2fe11c964759513487335794f9a8c336bd32f7ae9aeed5380c
4
- data.tar.gz: 9a6650251228ab4dae25f16120e8ae8c1992e4458faf0c858894b6e4848ae80b
3
+ metadata.gz: 92cf8b8492d42dee0adb37a4fb41692e6b228ab7a364f9176444c60cd81eb63d
4
+ data.tar.gz: 45e8828d53f7b9c4893fb6374535bbb099c77e92371a3e111bda07d9e35db93e
5
5
  SHA512:
6
- metadata.gz: 867fc4cb49114ace4af4682feff5a062eb414f0ce84e4be4e48632609d68cec2ac201be2cb43fb995ac5e9cb4ec0480399aa6eaad7580da81fd5451905b0ddf5
7
- data.tar.gz: 4b3d3c3d96d45a2573829345fd1f822fa3f8918c9d4088cccc46d82ba4fa797bb7c9838e74d443017069f7cd9b9d343d3bd92219930b12098f036d038e05ef83
6
+ metadata.gz: 123244bee715f744b7b377bbf4e2912ed28cbb966ce6b92bb7d43a5ea053bf2460e7bb10c35acf09ab5f4cfa8f0afeeb78198be62acfbde44b86f3c5f0559deb
7
+ data.tar.gz: 15ee859102e87e971df1e38b756d776a0f913148554974fc2fe9ae79b12853cf9028793aadfaabb92aa1d74961739c97a51c258c0e9e2a38cbf77fb5f931b46d
data/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  All notable changes to PromptObjects are documented in this file.
4
4
 
5
+ ## [0.4.0] - 2026-02-11
6
+
7
+ ### Added
8
+
9
+ - **Spatial Canvas** — Three.js 2D visualization at `/canvas` showing POs as glowing hexagonal nodes with force-directed layout, tool call diamonds, animated message arcs with traveling particles, and click-to-inspect side panels. Real-time updates from the same WebSocket feed as the dashboard. Zoom, pan, and keyboard shortcuts (F to fit, Escape to deselect).
10
+ - **PO-to-PO delegation broadcasting** — Server now broadcasts `po_delegation_started` and `po_delegation_completed` WebSocket events when one PO calls another. Delegated POs show as active in both the canvas (cyan glow, "called by X" status) and dashboard views. Replaces client-side inference from message history scanning.
11
+ - **Ruby 4 support** — CI now tests against Ruby 4. Fixed empty required parameter handling for compatibility. Thanks to [@radanskoric](https://github.com/radanskoric) for the contribution! ([#2](https://github.com/works-on-your-machine/prompt_objects/pull/2))
12
+
13
+ ### Fixed
14
+
15
+ - **WebSocket reconnection lifecycle** — Fixed duplicate connections on page refresh caused by zombie `onclose` handlers. Added socket identity guards, close-before-reconnect, and `handleMessageRef` pattern to prevent stale closures.
16
+ - **Stale state on disconnect** — PO statuses now reset to idle when WebSocket disconnects, preventing stuck "thinking" indicators and stale streaming content.
17
+ - **Chat input locked on disconnect** — Chat input is now only disabled when the PO is busy AND connected. Shows "Reconnecting..." indicator when disconnected instead of permanently locking.
18
+ - **Tool calls not appearing on canvas** — Tool call visualization now extracts from PO message history instead of looking for a format bus messages don't use.
19
+
5
20
  ## [0.3.1] - 2025-02-08
6
21
 
7
22
  ### Added
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- prompt_objects (0.3.1)
4
+ prompt_objects (0.4.0)
5
5
  anthropic (~> 1.0)
6
6
  async-websocket (~> 0.28)
7
7
  falcon (~> 0.50)
@@ -17,24 +17,25 @@ GEM
17
17
  specs:
18
18
  addressable (2.8.8)
19
19
  public_suffix (>= 2.0.2, < 8.0)
20
- anthropic (1.16.3)
20
+ anthropic (1.19.0)
21
+ cgi
21
22
  connection_pool
22
23
  ast (2.4.3)
23
- async (2.35.2)
24
+ async (2.36.0)
24
25
  console (~> 1.29)
25
26
  fiber-annotation
26
27
  io-event (~> 1.11)
27
28
  metrics (~> 0.12)
28
29
  traces (~> 0.18)
29
- async-container (0.27.7)
30
+ async-container (0.30.0)
30
31
  async (~> 2.22)
31
- async-container-supervisor (0.9.2)
32
+ async-container-supervisor (0.9.3)
32
33
  async-service
33
34
  io-endpoint
34
35
  memory (~> 0.7)
35
36
  memory-leak (~> 0.5)
36
37
  process-metrics
37
- async-http (0.94.0)
38
+ async-http (0.94.2)
38
39
  async (>= 2.10.2)
39
40
  async-pool (~> 0.11)
40
41
  io-endpoint (~> 0.14)
@@ -49,9 +50,9 @@ GEM
49
50
  async-http (~> 0.56)
50
51
  async-pool (0.11.1)
51
52
  async (>= 2.0)
52
- async-service (0.16.0)
53
+ async-service (0.19.0)
53
54
  async
54
- async-container (~> 0.16)
55
+ async-container (~> 0.29)
55
56
  string-format (~> 0.2)
56
57
  async-websocket (0.30.0)
57
58
  async-http (~> 0.76)
@@ -63,6 +64,7 @@ GEM
63
64
  samovar (~> 2.1)
64
65
  base64 (0.3.0)
65
66
  bigdecimal (4.0.1)
67
+ cgi (0.5.1)
66
68
  connection_pool (3.0.2)
67
69
  console (1.34.2)
68
70
  fiber-annotation
@@ -74,20 +76,20 @@ GEM
74
76
  reline (>= 0.3.8)
75
77
  erb (6.0.1)
76
78
  event_stream_parser (1.0.0)
77
- falcon (0.53.1)
79
+ falcon (0.54.2)
78
80
  async
79
81
  async-container (~> 0.20)
80
82
  async-container-supervisor (~> 0.6)
81
83
  async-http (~> 0.75)
82
84
  async-http-cache (~> 0.4)
83
- async-service (~> 0.16)
85
+ async-service (~> 0.19)
84
86
  bundler
85
87
  localhost (~> 1.1)
86
88
  openssl (>= 3.0)
87
89
  protocol-http (~> 0.31)
88
90
  protocol-rack (~> 0.7)
89
91
  samovar (~> 2.3)
90
- faraday (2.14.0)
92
+ faraday (2.14.1)
91
93
  faraday-net_http (>= 2.0, < 3.5)
92
94
  json
93
95
  logger
@@ -103,29 +105,29 @@ GEM
103
105
  fiber-storage (1.0.1)
104
106
  front_matter_parser (1.0.1)
105
107
  io-console (0.8.2)
106
- io-endpoint (0.16.0)
108
+ io-endpoint (0.17.2)
107
109
  io-event (1.14.2)
108
110
  io-stream (0.11.1)
109
- irb (1.16.0)
111
+ irb (1.17.0)
110
112
  pp (>= 0.6.0)
113
+ prism (>= 1.3.0)
111
114
  rdoc (>= 4.0.0)
112
115
  reline (>= 0.4.2)
113
- json (2.18.0)
116
+ json (2.18.1)
114
117
  json-schema (6.1.0)
115
118
  addressable (~> 2.8)
116
119
  bigdecimal (>= 3.1, < 5)
117
- json_rpc_handler (0.1.1)
118
120
  language_server-protocol (3.17.0.5)
119
121
  lint_roller (1.1.0)
120
- listen (3.9.0)
122
+ listen (3.10.0)
123
+ logger
121
124
  rb-fsevent (~> 0.10, >= 0.10.3)
122
125
  rb-inotify (~> 0.9, >= 0.9.10)
123
- localhost (1.6.0)
126
+ localhost (1.7.0)
124
127
  logger (1.7.0)
125
128
  mapping (1.1.3)
126
- mcp (0.4.0)
129
+ mcp (0.6.0)
127
130
  json-schema (>= 4.1)
128
- json_rpc_handler (~> 0.1)
129
131
  memory (0.12.0)
130
132
  bake (~> 0.15)
131
133
  console
@@ -139,25 +141,25 @@ GEM
139
141
  uri (>= 0.11.1)
140
142
  openssl (4.0.0)
141
143
  parallel (1.27.0)
142
- parser (3.3.10.0)
144
+ parser (3.3.10.1)
143
145
  ast (~> 2.4.1)
144
146
  racc
145
147
  pp (0.6.3)
146
148
  prettyprint
147
149
  prettyprint (0.2.0)
148
- prism (1.7.0)
150
+ prism (1.9.0)
149
151
  process-metrics (0.8.0)
150
152
  console (~> 1.8)
151
153
  json (~> 2)
152
154
  samovar (~> 2.1)
153
155
  protocol-hpack (1.5.1)
154
- protocol-http (0.58.0)
155
- protocol-http1 (0.36.0)
156
+ protocol-http (0.59.0)
157
+ protocol-http1 (0.37.0)
156
158
  protocol-http (~> 0.58)
157
- protocol-http2 (0.23.0)
159
+ protocol-http2 (0.24.0)
158
160
  protocol-hpack (~> 1.4)
159
161
  protocol-http (~> 0.47)
160
- protocol-rack (0.21.0)
162
+ protocol-rack (0.21.1)
161
163
  io-stream (>= 0.10)
162
164
  protocol-http (~> 0.58)
163
165
  rack (>= 1.0)
@@ -167,7 +169,7 @@ GEM
167
169
  psych (5.3.1)
168
170
  date
169
171
  stringio
170
- public_suffix (7.0.1)
172
+ public_suffix (7.0.2)
171
173
  racc (1.8.1)
172
174
  rack (3.2.4)
173
175
  rainbow (3.1.1)
@@ -175,14 +177,14 @@ GEM
175
177
  rb-fsevent (0.11.2)
176
178
  rb-inotify (0.11.1)
177
179
  ffi (~> 1.0)
178
- rdoc (7.0.3)
180
+ rdoc (7.2.0)
179
181
  erb
180
182
  psych (>= 4.0.0)
181
183
  tsort
182
184
  regexp_parser (2.11.3)
183
185
  reline (0.6.3)
184
186
  io-console (~> 0.5)
185
- rubocop (1.82.1)
187
+ rubocop (1.84.1)
186
188
  json (~> 2.3)
187
189
  language_server-protocol (~> 3.17.0.2)
188
190
  lint_roller (~> 1.1.0)
@@ -190,7 +192,7 @@ GEM
190
192
  parser (>= 3.3.0.2)
191
193
  rainbow (>= 2.2.2, < 4.0)
192
194
  regexp_parser (>= 2.9.3, < 3.0)
193
- rubocop-ast (>= 1.48.0, < 2.0)
195
+ rubocop-ast (>= 1.49.0, < 2.0)
194
196
  ruby-progressbar (~> 1.7)
195
197
  unicode-display_width (>= 2.4.0, < 4.0)
196
198
  rubocop-ast (1.49.0)
@@ -10,16 +10,20 @@
10
10
  "dependencies": {
11
11
  "@types/react-syntax-highlighter": "^15.5.13",
12
12
  "clsx": "^2.1.1",
13
+ "d3-force": "^3.0.0",
13
14
  "react": "^18.3.1",
14
15
  "react-dom": "^18.3.1",
15
16
  "react-markdown": "^10.1.0",
16
17
  "react-syntax-highlighter": "^16.1.0",
17
18
  "remark-gfm": "^4.0.1",
19
+ "three": "^0.182.0",
18
20
  "zustand": "^5.0.0"
19
21
  },
20
22
  "devDependencies": {
23
+ "@types/d3-force": "^3.0.10",
21
24
  "@types/react": "^18.3.12",
22
25
  "@types/react-dom": "^18.3.1",
26
+ "@types/three": "^0.182.0",
23
27
  "@vitejs/plugin-react": "^4.3.4",
24
28
  "autoprefixer": "^10.4.20",
25
29
  "postcss": "^8.4.49",
@@ -332,6 +336,13 @@
332
336
  "node": ">=6.9.0"
333
337
  }
334
338
  },
339
+ "node_modules/@dimforge/rapier3d-compat": {
340
+ "version": "0.12.0",
341
+ "resolved": "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz",
342
+ "integrity": "sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==",
343
+ "dev": true,
344
+ "license": "Apache-2.0"
345
+ },
335
346
  "node_modules/@esbuild/aix-ppc64": {
336
347
  "version": "0.25.12",
337
348
  "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
@@ -1219,6 +1230,13 @@
1219
1230
  "win32"
1220
1231
  ]
1221
1232
  },
1233
+ "node_modules/@tweenjs/tween.js": {
1234
+ "version": "23.1.3",
1235
+ "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz",
1236
+ "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==",
1237
+ "dev": true,
1238
+ "license": "MIT"
1239
+ },
1222
1240
  "node_modules/@types/babel__core": {
1223
1241
  "version": "7.20.5",
1224
1242
  "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -1264,6 +1282,13 @@
1264
1282
  "@babel/types": "^7.28.2"
1265
1283
  }
1266
1284
  },
1285
+ "node_modules/@types/d3-force": {
1286
+ "version": "3.0.10",
1287
+ "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz",
1288
+ "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==",
1289
+ "dev": true,
1290
+ "license": "MIT"
1291
+ },
1267
1292
  "node_modules/@types/debug": {
1268
1293
  "version": "4.1.12",
1269
1294
  "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
@@ -1353,12 +1378,42 @@
1353
1378
  "@types/react": "*"
1354
1379
  }
1355
1380
  },
1381
+ "node_modules/@types/stats.js": {
1382
+ "version": "0.17.4",
1383
+ "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz",
1384
+ "integrity": "sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==",
1385
+ "dev": true,
1386
+ "license": "MIT"
1387
+ },
1388
+ "node_modules/@types/three": {
1389
+ "version": "0.182.0",
1390
+ "resolved": "https://registry.npmjs.org/@types/three/-/three-0.182.0.tgz",
1391
+ "integrity": "sha512-WByN9V3Sbwbe2OkWuSGyoqQO8Du6yhYaXtXLoA5FkKTUJorZ+yOHBZ35zUUPQXlAKABZmbYp5oAqpA4RBjtJ/Q==",
1392
+ "dev": true,
1393
+ "license": "MIT",
1394
+ "dependencies": {
1395
+ "@dimforge/rapier3d-compat": "~0.12.0",
1396
+ "@tweenjs/tween.js": "~23.1.3",
1397
+ "@types/stats.js": "*",
1398
+ "@types/webxr": ">=0.5.17",
1399
+ "@webgpu/types": "*",
1400
+ "fflate": "~0.8.2",
1401
+ "meshoptimizer": "~0.22.0"
1402
+ }
1403
+ },
1356
1404
  "node_modules/@types/unist": {
1357
1405
  "version": "3.0.3",
1358
1406
  "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
1359
1407
  "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
1360
1408
  "license": "MIT"
1361
1409
  },
1410
+ "node_modules/@types/webxr": {
1411
+ "version": "0.5.24",
1412
+ "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.24.tgz",
1413
+ "integrity": "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==",
1414
+ "dev": true,
1415
+ "license": "MIT"
1416
+ },
1362
1417
  "node_modules/@ungap/structured-clone": {
1363
1418
  "version": "1.3.0",
1364
1419
  "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
@@ -1386,6 +1441,13 @@
1386
1441
  "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
1387
1442
  }
1388
1443
  },
1444
+ "node_modules/@webgpu/types": {
1445
+ "version": "0.1.69",
1446
+ "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.69.tgz",
1447
+ "integrity": "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==",
1448
+ "dev": true,
1449
+ "license": "BSD-3-Clause"
1450
+ },
1389
1451
  "node_modules/any-promise": {
1390
1452
  "version": "1.3.0",
1391
1453
  "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
@@ -1705,6 +1767,47 @@
1705
1767
  "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
1706
1768
  "license": "MIT"
1707
1769
  },
1770
+ "node_modules/d3-dispatch": {
1771
+ "version": "3.0.1",
1772
+ "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
1773
+ "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
1774
+ "license": "ISC",
1775
+ "engines": {
1776
+ "node": ">=12"
1777
+ }
1778
+ },
1779
+ "node_modules/d3-force": {
1780
+ "version": "3.0.0",
1781
+ "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
1782
+ "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
1783
+ "license": "ISC",
1784
+ "dependencies": {
1785
+ "d3-dispatch": "1 - 3",
1786
+ "d3-quadtree": "1 - 3",
1787
+ "d3-timer": "1 - 3"
1788
+ },
1789
+ "engines": {
1790
+ "node": ">=12"
1791
+ }
1792
+ },
1793
+ "node_modules/d3-quadtree": {
1794
+ "version": "3.0.1",
1795
+ "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
1796
+ "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==",
1797
+ "license": "ISC",
1798
+ "engines": {
1799
+ "node": ">=12"
1800
+ }
1801
+ },
1802
+ "node_modules/d3-timer": {
1803
+ "version": "3.0.1",
1804
+ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
1805
+ "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
1806
+ "license": "ISC",
1807
+ "engines": {
1808
+ "node": ">=12"
1809
+ }
1810
+ },
1708
1811
  "node_modules/debug": {
1709
1812
  "version": "4.4.3",
1710
1813
  "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
@@ -1911,6 +2014,13 @@
1911
2014
  "url": "https://github.com/sponsors/wooorm"
1912
2015
  }
1913
2016
  },
2017
+ "node_modules/fflate": {
2018
+ "version": "0.8.2",
2019
+ "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
2020
+ "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
2021
+ "dev": true,
2022
+ "license": "MIT"
2023
+ },
1914
2024
  "node_modules/fill-range": {
1915
2025
  "version": "7.1.1",
1916
2026
  "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
@@ -2624,6 +2734,13 @@
2624
2734
  "node": ">= 8"
2625
2735
  }
2626
2736
  },
2737
+ "node_modules/meshoptimizer": {
2738
+ "version": "0.22.0",
2739
+ "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.22.0.tgz",
2740
+ "integrity": "sha512-IebiK79sqIy+E4EgOr+CAw+Ke8hAspXKzBd0JdgEmPHiAwmvEj2S4h1rfvo+o/BnfEYd/jAOg5IeeIjzlzSnDg==",
2741
+ "dev": true,
2742
+ "license": "MIT"
2743
+ },
2627
2744
  "node_modules/micromark": {
2628
2745
  "version": "4.0.2",
2629
2746
  "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz",
@@ -4006,6 +4123,12 @@
4006
4123
  "node": ">=0.8"
4007
4124
  }
4008
4125
  },
4126
+ "node_modules/three": {
4127
+ "version": "0.182.0",
4128
+ "resolved": "https://registry.npmjs.org/three/-/three-0.182.0.tgz",
4129
+ "integrity": "sha512-GbHabT+Irv+ihI1/f5kIIsZ+Ef9Sl5A1Y7imvS5RQjWgtTPfPnZ43JmlYI7NtCRDK9zir20lQpfg8/9Yd02OvQ==",
4130
+ "license": "MIT"
4131
+ },
4009
4132
  "node_modules/tinyglobby": {
4010
4133
  "version": "0.2.15",
4011
4134
  "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
@@ -12,16 +12,20 @@
12
12
  "dependencies": {
13
13
  "@types/react-syntax-highlighter": "^15.5.13",
14
14
  "clsx": "^2.1.1",
15
+ "d3-force": "^3.0.0",
15
16
  "react": "^18.3.1",
16
17
  "react-dom": "^18.3.1",
17
18
  "react-markdown": "^10.1.0",
18
19
  "react-syntax-highlighter": "^16.1.0",
19
20
  "remark-gfm": "^4.0.1",
21
+ "three": "^0.182.0",
20
22
  "zustand": "^5.0.0"
21
23
  },
22
24
  "devDependencies": {
25
+ "@types/d3-force": "^3.0.10",
23
26
  "@types/react": "^18.3.12",
24
27
  "@types/react-dom": "^18.3.1",
28
+ "@types/three": "^0.182.0",
25
29
  "@vitejs/plugin-react": "^4.3.4",
26
30
  "autoprefixer": "^10.4.20",
27
31
  "postcss": "^8.4.49",
data/frontend/src/App.tsx CHANGED
@@ -8,11 +8,12 @@ import { MessageBus } from './components/MessageBus'
8
8
  import { NotificationPanel } from './components/NotificationPanel'
9
9
  import { ThreadsSidebar } from './components/ThreadsSidebar'
10
10
  import { UsagePanel } from './components/UsagePanel'
11
+ import { CanvasView } from './canvas/CanvasView'
11
12
 
12
13
  export default function App() {
13
14
  const { sendMessage, respondToNotification, createSession, switchSession, switchLLM, createThread, updatePrompt, requestUsage, exportThread } =
14
15
  useWebSocket()
15
- const { selectedPO, busOpen, notifications, usageData, clearUsageData } = useStore()
16
+ const { selectedPO, busOpen, notifications, usageData, clearUsageData, currentView } = useStore()
16
17
  const selectedPOData = useSelectedPO()
17
18
  const [splitView, setSplitView] = useState(true) // Default to split view
18
19
 
@@ -21,67 +22,73 @@ export default function App() {
21
22
  <Header switchLLM={switchLLM} />
22
23
 
23
24
  <div className="flex-1 flex overflow-hidden">
24
- {/* Split view: Dashboard sidebar on left when PO selected */}
25
- {splitView && selectedPO && (
25
+ {currentView === 'canvas' ? (
26
+ <CanvasView />
27
+ ) : (
26
28
  <>
27
- {/* PO List */}
28
- <aside className="w-56 border-r border-po-border bg-po-surface overflow-hidden flex flex-col">
29
- <div className="p-3 border-b border-po-border flex items-center justify-between">
30
- <h2 className="text-sm font-medium text-gray-400">Prompt Objects</h2>
29
+ {/* Split view: Dashboard sidebar on left when PO selected */}
30
+ {splitView && selectedPO && (
31
+ <>
32
+ {/* PO List */}
33
+ <aside className="w-56 border-r border-po-border bg-po-surface overflow-hidden flex flex-col">
34
+ <div className="p-3 border-b border-po-border flex items-center justify-between">
35
+ <h2 className="text-sm font-medium text-gray-400">Prompt Objects</h2>
36
+ <button
37
+ onClick={() => setSplitView(false)}
38
+ className="text-xs text-gray-500 hover:text-white"
39
+ title="Hide sidebar"
40
+ >
41
+
42
+ </button>
43
+ </div>
44
+ <div className="flex-1 overflow-auto">
45
+ <Dashboard compact />
46
+ </div>
47
+ </aside>
48
+
49
+ {/* Threads List for selected PO */}
50
+ {selectedPOData && (
51
+ <aside className="w-56 border-r border-po-border bg-po-bg overflow-hidden">
52
+ <ThreadsSidebar
53
+ po={selectedPOData}
54
+ switchSession={switchSession}
55
+ createThread={createThread}
56
+ requestUsage={requestUsage}
57
+ exportThread={exportThread}
58
+ />
59
+ </aside>
60
+ )}
61
+ </>
62
+ )}
63
+
64
+ {/* Main content */}
65
+ <main className="flex-1 overflow-hidden flex flex-col">
66
+ {/* Show expand button when sidebar is hidden */}
67
+ {!splitView && selectedPO && (
31
68
  <button
32
- onClick={() => setSplitView(false)}
33
- className="text-xs text-gray-500 hover:text-white"
34
- title="Hide sidebar"
69
+ onClick={() => setSplitView(true)}
70
+ className="absolute left-2 top-16 z-10 bg-po-surface border border-po-border rounded px-2 py-1 text-xs text-gray-400 hover:text-white hover:border-po-accent transition-colors"
71
+ title="Show dashboard sidebar"
35
72
  >
36
-
73
+ ☰ POs
37
74
  </button>
38
- </div>
39
- <div className="flex-1 overflow-auto">
40
- <Dashboard compact />
41
- </div>
42
- </aside>
75
+ )}
43
76
 
44
- {/* Threads List for selected PO */}
45
- {selectedPOData && (
46
- <aside className="w-56 border-r border-po-border bg-po-bg overflow-hidden">
47
- <ThreadsSidebar
48
- po={selectedPOData}
77
+ {selectedPO ? (
78
+ <PODetail
79
+ sendMessage={sendMessage}
80
+ createSession={createSession}
49
81
  switchSession={switchSession}
50
82
  createThread={createThread}
51
- requestUsage={requestUsage}
52
- exportThread={exportThread}
83
+ updatePrompt={updatePrompt}
53
84
  />
54
- </aside>
55
- )}
85
+ ) : (
86
+ <Dashboard />
87
+ )}
88
+ </main>
56
89
  </>
57
90
  )}
58
91
 
59
- {/* Main content */}
60
- <main className="flex-1 overflow-hidden flex flex-col">
61
- {/* Show expand button when sidebar is hidden */}
62
- {!splitView && selectedPO && (
63
- <button
64
- onClick={() => setSplitView(true)}
65
- className="absolute left-2 top-16 z-10 bg-po-surface border border-po-border rounded px-2 py-1 text-xs text-gray-400 hover:text-white hover:border-po-accent transition-colors"
66
- title="Show dashboard sidebar"
67
- >
68
- ☰ POs
69
- </button>
70
- )}
71
-
72
- {selectedPO ? (
73
- <PODetail
74
- sendMessage={sendMessage}
75
- createSession={createSession}
76
- switchSession={switchSession}
77
- createThread={createThread}
78
- updatePrompt={updatePrompt}
79
- />
80
- ) : (
81
- <Dashboard />
82
- )}
83
- </main>
84
-
85
92
  {/* Message Bus sidebar */}
86
93
  {busOpen && (
87
94
  <aside className="w-80 flex-shrink-0 border-l border-po-border bg-po-surface overflow-hidden">