project-graph-mcp 2.2.4 → 2.3.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 (151) hide show
  1. package/ARCHITECTURE.md +81 -0
  2. package/CHANGELOG.md +57 -0
  3. package/README.md +9 -4
  4. package/package.json +6 -13
  5. package/src/compact/expand.js +2 -4
  6. package/src/core/graph-builder.js +2 -2
  7. package/src/core/parser.js +2 -2
  8. package/src/network/server.js +1 -2
  9. package/src/network/web-server.js +4 -1
  10. package/vendor/symbiote-node/CHANGELOG.md +31 -0
  11. package/vendor/symbiote-node/LICENSE +21 -0
  12. package/vendor/symbiote-node/README.md +206 -0
  13. package/vendor/symbiote-node/canvas/AutoLayout.js +725 -0
  14. package/vendor/symbiote-node/canvas/Breadcrumb/Breadcrumb.css.js +73 -0
  15. package/vendor/symbiote-node/canvas/Breadcrumb/Breadcrumb.js +93 -0
  16. package/vendor/symbiote-node/canvas/Breadcrumb/Breadcrumb.tpl.js +9 -0
  17. package/vendor/symbiote-node/canvas/CanvasConnectionRenderer.js +962 -0
  18. package/vendor/symbiote-node/canvas/ConnectionRenderer.js +1468 -0
  19. package/vendor/symbiote-node/canvas/FlowSimulator.js +323 -0
  20. package/vendor/symbiote-node/canvas/ForceLayout.js +189 -0
  21. package/vendor/symbiote-node/canvas/ForceWorker.js +1325 -0
  22. package/vendor/symbiote-node/canvas/GraphTabs/GraphTabs.css.js +97 -0
  23. package/vendor/symbiote-node/canvas/GraphTabs/GraphTabs.js +176 -0
  24. package/vendor/symbiote-node/canvas/GraphTabs/GraphTabs.tpl.js +12 -0
  25. package/vendor/symbiote-node/canvas/LODManager.js +88 -0
  26. package/vendor/symbiote-node/canvas/Minimap/Minimap.css.js +71 -0
  27. package/vendor/symbiote-node/canvas/Minimap/Minimap.js +207 -0
  28. package/vendor/symbiote-node/canvas/Minimap/Minimap.tpl.js +9 -0
  29. package/vendor/symbiote-node/canvas/NodeCanvas/NodeCanvas.css.js +261 -0
  30. package/vendor/symbiote-node/canvas/NodeCanvas/NodeCanvas.js +1840 -0
  31. package/vendor/symbiote-node/canvas/NodeCanvas/NodeCanvas.tpl.js +22 -0
  32. package/vendor/symbiote-node/canvas/NodeSearch/NodeSearch.css.js +97 -0
  33. package/vendor/symbiote-node/canvas/NodeSearch/NodeSearch.js +132 -0
  34. package/vendor/symbiote-node/canvas/NodeSearch/NodeSearch.tpl.js +21 -0
  35. package/vendor/symbiote-node/canvas/NodeViewManager.js +584 -0
  36. package/vendor/symbiote-node/canvas/PinExpansion.js +131 -0
  37. package/vendor/symbiote-node/canvas/PseudoConnection.js +80 -0
  38. package/vendor/symbiote-node/canvas/SubgraphManager.js +201 -0
  39. package/vendor/symbiote-node/canvas/SubgraphRouter.js +443 -0
  40. package/vendor/symbiote-node/canvas/ViewportActions.js +446 -0
  41. package/vendor/symbiote-node/core/Connection.js +45 -0
  42. package/vendor/symbiote-node/core/Editor.js +451 -0
  43. package/vendor/symbiote-node/core/Frame.js +31 -0
  44. package/vendor/symbiote-node/core/GraphMermaid.js +348 -0
  45. package/vendor/symbiote-node/core/GraphText.js +210 -0
  46. package/vendor/symbiote-node/core/Node.js +143 -0
  47. package/vendor/symbiote-node/core/Portal.js +104 -0
  48. package/vendor/symbiote-node/core/Socket.js +185 -0
  49. package/vendor/symbiote-node/core/SubgraphNode.js +125 -0
  50. package/vendor/symbiote-node/index.js +103 -0
  51. package/vendor/symbiote-node/inspector/InspectorPanel/InspectorPanel.css.js +361 -0
  52. package/vendor/symbiote-node/inspector/InspectorPanel/InspectorPanel.js +332 -0
  53. package/vendor/symbiote-node/inspector/InspectorPanel/InspectorPanel.tpl.js +96 -0
  54. package/vendor/symbiote-node/inspector/TemplatePreview/TemplatePreview.css.js +104 -0
  55. package/vendor/symbiote-node/inspector/TemplatePreview/TemplatePreview.js +133 -0
  56. package/vendor/symbiote-node/inspector/TemplatePreview/TemplatePreview.tpl.js +33 -0
  57. package/vendor/symbiote-node/interactions/ConnectFlow.js +307 -0
  58. package/vendor/symbiote-node/interactions/Drag.js +102 -0
  59. package/vendor/symbiote-node/interactions/Selector.js +132 -0
  60. package/vendor/symbiote-node/interactions/SnapGrid.js +65 -0
  61. package/vendor/symbiote-node/interactions/Zoom.js +140 -0
  62. package/vendor/symbiote-node/layout/ActionZone/ActionZone.css.js +88 -0
  63. package/vendor/symbiote-node/layout/ActionZone/ActionZone.js +254 -0
  64. package/vendor/symbiote-node/layout/ActionZone/ActionZone.tpl.js +11 -0
  65. package/vendor/symbiote-node/layout/Layout/Layout.css.js +88 -0
  66. package/vendor/symbiote-node/layout/Layout/Layout.js +622 -0
  67. package/vendor/symbiote-node/layout/Layout/Layout.tpl.js +25 -0
  68. package/vendor/symbiote-node/layout/LayoutNode/LayoutNode.css.js +293 -0
  69. package/vendor/symbiote-node/layout/LayoutNode/LayoutNode.js +467 -0
  70. package/vendor/symbiote-node/layout/LayoutNode/LayoutNode.tpl.js +33 -0
  71. package/vendor/symbiote-node/layout/LayoutPreview/LayoutPreview.css.js +46 -0
  72. package/vendor/symbiote-node/layout/LayoutPreview/LayoutPreview.js +102 -0
  73. package/vendor/symbiote-node/layout/LayoutPreview/LayoutPreview.tpl.js +6 -0
  74. package/vendor/symbiote-node/layout/LayoutRouter/LayoutRouter.js +156 -0
  75. package/vendor/symbiote-node/layout/LayoutRouter/routerSync.js +250 -0
  76. package/vendor/symbiote-node/layout/LayoutSidebar/LayoutSidebar.css.js +379 -0
  77. package/vendor/symbiote-node/layout/LayoutSidebar/LayoutSidebar.js +263 -0
  78. package/vendor/symbiote-node/layout/LayoutSidebar/LayoutSidebar.tpl.js +20 -0
  79. package/vendor/symbiote-node/layout/LayoutSidebar/SidebarSection.js +183 -0
  80. package/vendor/symbiote-node/layout/LayoutTree.js +246 -0
  81. package/vendor/symbiote-node/layout/PanelMenu/PanelMenu.css.js +43 -0
  82. package/vendor/symbiote-node/layout/PanelMenu/PanelMenu.js +89 -0
  83. package/vendor/symbiote-node/layout/PanelMenu/PanelMenu.tpl.js +14 -0
  84. package/vendor/symbiote-node/layout/index.js +16 -0
  85. package/vendor/symbiote-node/menu/ContextMenu/ContextMenu.css.js +61 -0
  86. package/vendor/symbiote-node/menu/ContextMenu/ContextMenu.js +79 -0
  87. package/vendor/symbiote-node/menu/ContextMenu/ContextMenu.tpl.js +19 -0
  88. package/vendor/symbiote-node/node/CtrlItem/CtrlItem.css.js +41 -0
  89. package/vendor/symbiote-node/node/CtrlItem/CtrlItem.js +24 -0
  90. package/vendor/symbiote-node/node/CtrlItem/CtrlItem.tpl.js +16 -0
  91. package/vendor/symbiote-node/node/GraphFrame/GraphFrame.css.js +65 -0
  92. package/vendor/symbiote-node/node/GraphFrame/GraphFrame.js +29 -0
  93. package/vendor/symbiote-node/node/GraphFrame/GraphFrame.tpl.js +13 -0
  94. package/vendor/symbiote-node/node/GraphNode/GraphNode.css.js +683 -0
  95. package/vendor/symbiote-node/node/GraphNode/GraphNode.js +92 -0
  96. package/vendor/symbiote-node/node/GraphNode/GraphNode.tpl.js +17 -0
  97. package/vendor/symbiote-node/node/NodeSocket/NodeSocket.js +25 -0
  98. package/vendor/symbiote-node/node/NodeSocket/NodeSocket.tpl.js +7 -0
  99. package/vendor/symbiote-node/node/PortItem/PortItem.css.js +90 -0
  100. package/vendor/symbiote-node/node/PortItem/PortItem.js +87 -0
  101. package/vendor/symbiote-node/node/PortItem/PortItem.tpl.js +10 -0
  102. package/vendor/symbiote-node/package.json +59 -0
  103. package/vendor/symbiote-node/palette/PaletteBrowser/PaletteBrowser.css.js +143 -0
  104. package/vendor/symbiote-node/palette/PaletteBrowser/PaletteBrowser.js +131 -0
  105. package/vendor/symbiote-node/palette/PaletteBrowser/PaletteBrowser.tpl.js +16 -0
  106. package/vendor/symbiote-node/plugins/History.js +384 -0
  107. package/vendor/symbiote-node/plugins/Readonly.js +59 -0
  108. package/vendor/symbiote-node/shapes/CircleShape.js +80 -0
  109. package/vendor/symbiote-node/shapes/CommentShape.js +35 -0
  110. package/vendor/symbiote-node/shapes/DiamondShape.js +115 -0
  111. package/vendor/symbiote-node/shapes/NodeShape.js +80 -0
  112. package/vendor/symbiote-node/shapes/PillShape.js +91 -0
  113. package/vendor/symbiote-node/shapes/RectShape.js +72 -0
  114. package/vendor/symbiote-node/shapes/SVGShape.js +494 -0
  115. package/vendor/symbiote-node/shapes/index.js +53 -0
  116. package/vendor/symbiote-node/themes/Palette.js +32 -0
  117. package/vendor/symbiote-node/themes/Skin.js +113 -0
  118. package/vendor/symbiote-node/themes/Theme.js +84 -0
  119. package/vendor/symbiote-node/themes/carbon.js +137 -0
  120. package/vendor/symbiote-node/themes/dark.js +137 -0
  121. package/vendor/symbiote-node/themes/ebook.js +138 -0
  122. package/vendor/symbiote-node/themes/grey.js +137 -0
  123. package/vendor/symbiote-node/themes/light.js +137 -0
  124. package/vendor/symbiote-node/themes/neon.js +138 -0
  125. package/vendor/symbiote-node/themes/pcb.js +273 -0
  126. package/vendor/symbiote-node/themes/synthwave.js +137 -0
  127. package/vendor/symbiote-node/toolbar/QuickToolbar/QuickToolbar.css.js +86 -0
  128. package/vendor/symbiote-node/toolbar/QuickToolbar/QuickToolbar.js +128 -0
  129. package/vendor/symbiote-node/toolbar/QuickToolbar/QuickToolbar.tpl.js +29 -0
  130. package/web/app.js +6 -5
  131. package/web/components/canvas-graph.js +1666 -0
  132. package/web/components/event-feed/CodeWidget.js +32 -0
  133. package/web/components/event-feed/EventWidget.js +97 -0
  134. package/web/components/event-feed/ListWidget.js +57 -0
  135. package/web/components/event-feed/MiniGraphWidget.js +69 -0
  136. package/web/dashboard.js +1 -1
  137. package/web/index.html +4 -0
  138. package/web/panels/ActionBoard/ActionBoard.js +1 -1
  139. package/web/panels/SettingsPanel/SettingsPanel.tpl.js +1 -1
  140. package/web/panels/code-viewer.js +50 -15
  141. package/web/panels/dep-graph.js +2712 -7
  142. package/web/panels/file-tree.js +5 -2
  143. package/web/panels/live-monitor.js +75 -3
  144. package/web/style.css +33 -0
  145. package/docs/img/explorer-compact.jpg +0 -0
  146. package/docs/img/explorer-expanded.jpg +0 -0
  147. package/src/.contextignore +0 -22
  148. package/src/.project-graph-cache.json +0 -1
  149. package/src/compact/.project-graph-cache.json +0 -1
  150. package/web/.project-graph-cache.json +0 -1
  151. package/web/panels/SettingsPanel/.project-graph-cache.json +0 -1
@@ -0,0 +1,86 @@
1
+ /**
2
+ * QuickToolbar styles
3
+ * @module symbiote-node/toolbar/QuickToolbar.css
4
+ */
5
+ import { css } from '@symbiotejs/symbiote';
6
+
7
+ export const styles = css`
8
+ quick-toolbar {
9
+ position: absolute;
10
+ z-index: 150;
11
+ pointer-events: all;
12
+ transform-origin: center bottom;
13
+
14
+ &[hidden] {
15
+ display: none;
16
+ }
17
+
18
+ & .toolbar {
19
+ display: flex;
20
+ gap: 2px;
21
+ padding: 4px;
22
+ border-radius: 10px;
23
+ background: var(--sn-toolbar-bg, rgba(22, 33, 62, 0.92));
24
+ backdrop-filter: blur(12px);
25
+ -webkit-backdrop-filter: blur(12px);
26
+ border: 1px solid var(--sn-toolbar-border, rgba(255, 255, 255, 0.1));
27
+ box-shadow: 0 8px 32px var(--sn-shadow-color, rgba(0, 0, 0, 0.45)), 0 0 0 1px var(--sn-shadow-color, rgba(0, 0, 0, 0.1));
28
+ transform: translateX(-50%);
29
+ animation: toolbar-in 0.2s ease-out;
30
+ }
31
+ }
32
+
33
+ @keyframes toolbar-in {
34
+ from {
35
+ opacity: 0;
36
+ transform: translateX(-50%) translateY(6px) scale(0.92);
37
+ }
38
+ to {
39
+ opacity: 1;
40
+ transform: translateX(-50%) translateY(0) scale(1);
41
+ }
42
+ }
43
+
44
+ .tb-btn {
45
+ display: flex;
46
+ align-items: center;
47
+ justify-content: center;
48
+ width: 32px;
49
+ height: 32px;
50
+ border: none;
51
+ border-radius: 6px;
52
+ background: transparent;
53
+ color: var(--sn-toolbar-color, #c0c8d8);
54
+ cursor: pointer;
55
+ transition: background 0.12s, color 0.12s, transform 0.12s;
56
+
57
+ &[hidden] {
58
+ display: none;
59
+ }
60
+
61
+ &:hover {
62
+ background: var(--sn-toolbar-hover, rgba(74, 158, 255, 0.2));
63
+ color: var(--sn-toolbar-active, #e2e8f0);
64
+ transform: scale(1.1);
65
+ }
66
+
67
+ &:active {
68
+ transform: scale(0.95);
69
+ }
70
+ }
71
+
72
+ .tb-btn--danger:hover {
73
+ background: var(--sn-toolbar-danger, rgba(255, 107, 107, 0.25));
74
+ color: var(--sn-toolbar-danger-color, #ff6b6b);
75
+ }
76
+
77
+ .tb-btn--enter:hover {
78
+ background: color-mix(in srgb, var(--sn-cat-data, #a78bfa) 25%, transparent);
79
+ color: var(--sn-cat-data, #a78bfa);
80
+ }
81
+
82
+ .tb-icon {
83
+ font-size: 18px;
84
+ pointer-events: none;
85
+ }
86
+ `;
@@ -0,0 +1,128 @@
1
+ /**
2
+ * QuickToolbar — floating action bar above selected node
3
+ *
4
+ * Shows contextual SVG buttons when a single node is selected:
5
+ * Delete, Duplicate, Mute.
6
+ * Positioned above the node and follows zoom/pan transform.
7
+ *
8
+ * @module symbiote-node/toolbar/QuickToolbar
9
+ */
10
+
11
+ import Symbiote from '@symbiotejs/symbiote';
12
+ import { template } from './QuickToolbar.tpl.js';
13
+ import { styles } from './QuickToolbar.css.js';
14
+
15
+ /**
16
+ * @typedef {object} ToolbarAction
17
+ * @property {string} id - Action identifier
18
+ * @property {string} icon - Material Symbols icon name
19
+ * @property {string} label - Tooltip text
20
+ */
21
+
22
+ /** @type {ToolbarAction[]} */
23
+ const ACTIONS = [
24
+ { id: 'duplicate', icon: 'content_copy', label: 'Duplicate' },
25
+ { id: 'mute', icon: 'visibility_off', label: 'Mute' },
26
+ { id: 'delete', icon: 'delete', label: 'Delete' },
27
+ ];
28
+
29
+ export class QuickToolbar extends Symbiote {
30
+
31
+ init$ = {
32
+ items: ACTIONS,
33
+ visible: false,
34
+ onBtnClick: (/** @type {Event} */ e) => {
35
+ const btn = e.target.closest('[data-action]');
36
+ if (!btn) return;
37
+ const action = btn.getAttribute('data-action');
38
+ if (this._onAction) this._onAction(action, this._nodeId);
39
+ },
40
+ };
41
+
42
+ /** @type {string|null} */
43
+ _nodeId = null;
44
+
45
+ /** @type {function|null} */
46
+ _onAction = null;
47
+
48
+ /** @type {number} Toolbar height + gap */
49
+ static OFFSET_Y = 48;
50
+
51
+ /** @type {{ zoom: number, panX: number, panY: number }} */
52
+ _transform = { zoom: 1, panX: 0, panY: 0 };
53
+
54
+ /**
55
+ * Show toolbar above a node
56
+ * @param {string} nodeId
57
+ * @param {HTMLElement} nodeEl - The graph-node element
58
+ */
59
+ show(nodeId, nodeEl) {
60
+ this._nodeId = nodeId;
61
+ this._nodeEl = nodeEl;
62
+ this.$.visible = true;
63
+
64
+ this.#positionAtNode(nodeEl);
65
+
66
+ // Update collapse icon based on current state
67
+ this.#updateIcons(nodeEl);
68
+
69
+ // Show/hide enter button for subgraph nodes
70
+ const enterBtn = this.querySelector('[data-action="enter"]');
71
+ if (enterBtn) {
72
+ enterBtn.hidden = nodeEl.getAttribute('node-type') !== 'subgraph';
73
+ }
74
+ }
75
+
76
+ /** Hide toolbar */
77
+ hide() {
78
+ this._nodeId = null;
79
+ this._nodeEl = null;
80
+ this.$.visible = false;
81
+ }
82
+
83
+ renderCallback() {
84
+ this.sub('visible', (val) => {
85
+ this.toggleAttribute('hidden', !val);
86
+ });
87
+ }
88
+
89
+ /**
90
+ * Update position to follow node movement
91
+ * @param {HTMLElement} nodeEl
92
+ */
93
+ updatePosition(nodeEl) {
94
+ if (!this._nodeId) return;
95
+ this.#positionAtNode(nodeEl);
96
+ }
97
+
98
+ /**
99
+ * Position toolbar centered above a node in world-space.
100
+ * Since toolbar is inside .content, it inherits zoom/pan transform.
101
+ * @param {HTMLElement} nodeEl
102
+ */
103
+ #positionAtNode(nodeEl) {
104
+ const w = nodeEl.offsetWidth || nodeEl._cachedW || 180;
105
+ const pos = nodeEl._position || { x: 0, y: 0 };
106
+
107
+ const x = pos.x + w / 2;
108
+ const y = pos.y - QuickToolbar.OFFSET_Y;
109
+
110
+ this.style.transform = `translate(${x}px, ${y}px)`;
111
+ }
112
+
113
+ /**
114
+ * Update toggle icons based on node state
115
+ * @param {HTMLElement} nodeEl
116
+ */
117
+ #updateIcons(nodeEl) {
118
+ const isMuted = nodeEl.hasAttribute('data-muted');
119
+
120
+ const muteBtn = this.querySelector('[data-action="mute"] .tb-icon');
121
+
122
+ if (muteBtn) muteBtn.textContent = isMuted ? 'visibility' : 'visibility_off';
123
+ }
124
+ }
125
+
126
+ QuickToolbar.template = template;
127
+ QuickToolbar.rootStyles = styles;
128
+ QuickToolbar.reg('quick-toolbar');
@@ -0,0 +1,29 @@
1
+ /**
2
+ * QuickToolbar template
3
+ * @module symbiote-node/toolbar/QuickToolbar.tpl
4
+ */
5
+ import { html } from '@symbiotejs/symbiote';
6
+
7
+ export const template = html`
8
+ <div class="toolbar" ${{ onclick: 'onBtnClick' }}>
9
+ <button class="tb-btn tb-btn--enter" data-action="enter" title="Enter Subgraph" hidden>
10
+ <span class="material-symbols-outlined tb-icon">login</span>
11
+ </button>
12
+ <button class="tb-btn" data-action="explore" title="Explore connections">
13
+ <span class="material-symbols-outlined tb-icon">hub</span>
14
+ </button>
15
+ <button class="tb-btn" data-action="view-code" title="View Code">
16
+ <span class="material-symbols-outlined tb-icon">code</span>
17
+ </button>
18
+ <button class="tb-btn" data-action="duplicate" title="Duplicate">
19
+ <span class="material-symbols-outlined tb-icon">content_copy</span>
20
+ </button>
21
+
22
+ <button class="tb-btn" data-action="mute" title="Mute">
23
+ <span class="material-symbols-outlined tb-icon">visibility_off</span>
24
+ </button>
25
+ <button class="tb-btn tb-btn--danger" data-action="delete" title="Delete">
26
+ <span class="material-symbols-outlined tb-icon">delete</span>
27
+ </button>
28
+ </div>
29
+ `;
package/web/app.js CHANGED
@@ -1,6 +1,5 @@
1
1
  // @ctx .context/web/app.ctx
2
- import{Layout as e,LayoutTree as t,applyTheme as n}from"symbiote-node";
3
- import{CARBON as o}from"./vendor/symbiote-node/themes/carbon.js";
2
+ import{Layout as e,LayoutTree as t,applyTheme as n,CARBON as o}from"symbiote-node";
4
3
  import{state as a,subscribe as s,onEvent as i,call as r,connect as c}from"./state.js";
5
4
  import"./panels/file-tree.js";
6
5
  import"./panels/code-viewer.js";
@@ -10,14 +9,16 @@ import"./panels/health-panel.js";
10
9
  import"./panels/live-monitor.js";
11
10
  import"./panels/SettingsPanel/SettingsPanel.js";
12
11
  import"./components/quick-open.js";
12
+ import"./components/canvas-graph.js";
13
13
  export const state={skeleton:null,activeFile:null,ws:null,monitorEvents:[]};
14
14
  export{formatStats}from"./stats-format.js";
15
15
  export const baseUrl=new URL(".",import.meta.url).href;const l=baseUrl;
16
16
  export async function api(e,t={}){if(a.connected&&e.startsWith("/api/")){const n=await async function(e,t){const n={"/api/skeleton":{name:"get_skeleton",args:e=>({path:e.path})},"/api/file":{name:"compact",args:e=>({action:"compact_file",path:e.path,beautify:!0})},"/api/analysis":{name:"analyze",args:e=>({action:"full_analysis",path:e.path})},"/api/analysis-summary":{name:"analyze",args:e=>({action:"analysis_summary",path:e.path})},"/api/deps":{name:"navigate",args:e=>({action:"deps",symbol:e.symbol})},"/api/usages":{name:"navigate",args:e=>({action:"usages",symbol:e.symbol})},"/api/expand":{name:"navigate",args:e=>({action:"expand",symbol:e.symbol})},"/api/chain":{name:"navigate",args:e=>({action:"call_chain",from:e.from,to:e.to})}}[e];return n?r(n.name,n.args(t)):null}(e,t);if(null!==n)return n}const n=new URLSearchParams(t).toString(),o=e.replace(/^\//, ""),s=n?`${l}${o}?${n}`:`${l}${o}`,i=await fetch(s);if(!i.ok)throw new Error(`API error: ${i.status}`);return i.json()}
17
17
  export const events=new EventTarget;
18
18
  export function emit(e,t={}){events.dispatchEvent(new CustomEvent(e,{detail:t}))}
19
- const p={"file-tree":{title:"Files",icon:"folder",component:"pg-file-tree"},"code-viewer":{title:"Code",icon:"code",component:"pg-code-viewer"},"ctx-panel":{title:"Documentation",icon:"description",component:"pg-ctx-panel"},"dep-graph":{title:"Dependencies",icon:"account_tree",component:"pg-dep-graph"},health:{title:"Health",icon:"analytics",component:"pg-health-panel"},monitor:{title:"Live Monitor",icon:"monitor_heart",component:"pg-live-monitor"},settings:{title:"Settings",icon:"settings",component:"pg-settings-panel"}},m=[{id:"explorer",icon:"folder_open",label:"Explorer"},{id:"analysis",icon:"analytics",label:"Analysis"},{id:"monitor",icon:"monitor_heart",label:"Monitor"},{id:"settings",icon:"settings",label:"Settings"}],d={explorer:()=>t.createSplit("horizontal",t.createPanel("file-tree"),t.createSplit("horizontal",t.createPanel("code-viewer"),t.createPanel("ctx-panel"),.65),.2),analysis:()=>t.createSplit("horizontal",t.createPanel("health"),t.createPanel("dep-graph"),.5),monitor:()=>t.createPanel("monitor"),settings:()=>t.createPanel("settings")};
20
- async function u(){(function(){n(document.documentElement,o);const e=document.querySelector(".app-workspace"),t=document.createElement("layout-sidebar");e.prepend(t);const a=e.querySelector(".app-content"),s=document.createElement("panel-layout");s.setAttribute("storage-key","pg-explorer-layout"),s.setAttribute("min-panel-size","150"),s.id="main-layout",a.appendChild(s),requestAnimationFrame(()=>{for(const[e,t]of Object.entries(p))s.registerPanelType(e,t);function e(){const e=location.hash.replace("#","")||"explorer",t=e.indexOf("?"),n=t>=0?e.substring(0,t):e,o=n.indexOf("/"),a=o>=0?n.substring(0,o):n,i=o>=0?n.substring(o+1):"";d[a]&&s.setLayout(d[a]()),"explorer"===a&&i&&requestAnimationFrame(()=>{state.activeFile=i,emit("file-selected",{path:i,fromRoute:!0})})}t.setSections(m),window.addEventListener("hashchange",e),events.addEventListener("file-selected",e=>{if(e.detail.fromRoute)return;const t=e.detail.path;t&&history.replaceState(null,"",`#explorer/${t}`)}),localStorage.getItem("pg-explorer-layout")||s.setLayout(d.explorer()),location.hash&&"#"!==location.hash?e():location.hash="explorer"})})(),s("project",e=>{e&&(document.title=`${e.name} — Project Graph`,document.getElementById("project-name").textContent=e.name,document.documentElement.style.setProperty("--project-accent",e.color),g(e.agents))}),events.addEventListener("skeleton-loaded",e=>{const t=e.detail;if(!t)return;state.skeleton=t;const n=new Set;for(const e of Object.values(t.n||{}))e.f&&n.add(e.f);for(const e of Object.keys(t.X||{}))n.add(e);for(const[e,o]of Object.entries(t.f||{}))for(const t of o)n.add("./"===e?t:`${e}${t}`);for(const[e,o]of Object.entries(t.a||{}))for(const t of o)n.add("./"===e?t:`${e}${t}`);const o=document.getElementById("project-files");o&&(o.textContent=`${n.size} files`)}),s("skeleton",e=>{if(!e)return;state.skeleton=e;emit("skeleton-loaded",e)}),s("connected",e=>{const t=document.getElementById("status-indicator");t&&(t.className=e?"status connected":"status disconnected")}),i(e=>{if("agent_connect"===e.type||"agent_disconnect"===e.type)return g(e.agents),void emit("agent-event",e);state.monitorEvents.push(e),state.monitorEvents.length>500&&state.monitorEvents.shift(),emit("tool-event",e)}),c()}
19
+ const p={"file-tree":{title:"Files",icon:"folder",component:"pg-file-tree"},"code-viewer":{title:"Code",icon:"code",component:"pg-code-viewer"},"ctx-panel":{title:"Documentation",icon:"description",component:"pg-ctx-panel"},"dep-graph":{title:"Dependencies",icon:"account_tree",component:"pg-dep-graph"},health:{title:"Health",icon:"analytics",component:"pg-health-panel"},monitor:{title:"Live Monitor",icon:"monitor_heart",component:"pg-live-monitor"},settings:{title:"Settings",icon:"settings",component:"pg-settings-panel"}},m=[{id:"explorer",icon:"folder_open",label:"Explorer"},{id:"graph",icon:"developer_board",label:"Graph"},{id:"analysis",icon:"analytics",label:"Analysis"},{id:"monitor",icon:"monitor_heart",label:"Monitor"},{id:"settings",icon:"settings",label:"Settings"}],d={explorer:()=>t.createSplit("horizontal",t.createPanel("file-tree"),t.createSplit("horizontal",t.createPanel("code-viewer"),t.createPanel("ctx-panel"),.65),.2),graph:()=>t.createSplit("horizontal",t.createPanel("file-tree"),t.createPanel("dep-graph"),.18),analysis:()=>t.createPanel("health"),monitor:()=>t.createPanel("monitor"),settings:()=>t.createPanel("settings")};
20
+ async function u(){(function(){n(document.documentElement,o);const e=document.querySelector(".app-workspace"),t=document.createElement("layout-sidebar");e.prepend(t);const a=e.querySelector(".app-content"),s=document.createElement("panel-layout");s.setAttribute("storage-key","pg-explorer-layout"),s.setAttribute("min-panel-size","150"),s.id="main-layout",a.appendChild(s),requestAnimationFrame(()=>{for(const[e,t]of Object.entries(p))s.registerPanelType(e,t);let lastSection="";function e(){const e=location.hash.replace("#","")||"explorer",t=e.indexOf("?"),n=t>=0?e.substring(0,t):e,o=n.indexOf("/"),a=o>=0?n.substring(0,o):n,i=o>=0?n.substring(o+1):"";if(d[a]&&a!==lastSection){lastSection=a;s.setLayout(d[a]())}"explorer"===a&&i&&requestAnimationFrame(()=>{state.activeFile=i,emit("file-selected",{path:i,fromRoute:!0})})}t.setSections(m),window.addEventListener("hashchange",e),events.addEventListener("file-selected",e=>{if(e.detail.fromRoute)return;if(e.detail.source==="canvas")return;const t=e.detail.path;const _sec=(location.hash.replace("#","").split("?")[0].split("/")[0])||"explorer";if(t&&_sec==="explorer")history.replaceState(null,"",`#explorer/${t}`)}),localStorage.getItem("pg-explorer-layout")||s.setLayout(d.explorer()),location.hash&&"#"!==location.hash?e():location.hash="explorer"})})(),s("project",e=>{e&&(document.title=`${e.name} — Project Graph`,document.getElementById("project-name").textContent=e.name,document.documentElement.style.setProperty("--project-accent",e.color),g(e.agents))}),events.addEventListener("skeleton-loaded",e=>{const t=e.detail;if(!t)return;state.skeleton=t;const n=new Set;for(const e of Object.values(t.n||{}))e.f&&n.add(e.f);for(const e of Object.keys(t.X||{}))n.add(e);for(const[e,o]of Object.entries(t.f||{}))for(const t of o)n.add("./"===e?t:`${e}${t}`);for(const[e,o]of Object.entries(t.a||{}))for(const t of o)n.add("./"===e?t:`${e}${t}`);const o=document.getElementById("project-files");o&&(o.textContent=`${n.size} files`)}),s("skeleton",e=>{if(!e)return;state.skeleton=e;emit("skeleton-loaded",e)}),s("connected",e=>{const t=document.getElementById("status-indicator");t&&(t.className=e?"status connected":"status disconnected")}),i(e=>{if("agent_connect"===e.type||"agent_disconnect"===e.type)return g(e.agents),void emit("agent-event",e);state.monitorEvents.push(e),state.monitorEvents.length>500&&state.monitorEvents.shift(),emit("tool-event",e)}),c()}
21
21
  function g(e){let t=document.getElementById("agent-badge");if(!t){const e=document.querySelector(".app-topbar");if(!e)return;t=document.createElement("span"),t.id="agent-badge",t.className="agent-badge",e.appendChild(t)}t.textContent=e>0?`● ${e} agent${1!==e?"s":""}`:"",t.style.display=e>0?"":"none"}
22
22
  function f(){document.querySelector("pg-quick-open")||document.body.appendChild(document.createElement("pg-quick-open"))}
23
- "loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{u(),f()}):(u(),f());
23
+ function h(){const btn=document.getElementById("follow-btn");if(!btn)return;let active=false;btn.addEventListener("click",()=>{active=!active;if(active){btn.setAttribute("data-active","");btn.classList.add("active")}else{btn.removeAttribute("data-active");btn.classList.remove("active")}events.dispatchEvent(new CustomEvent("follow-mode-changed",{detail:{enabled:active}}))})}
24
+ "loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{u(),f(),h()}):(u(),f(),h());