project-graph-mcp 2.3.2 → 2.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.
- package/package.json +3 -2
- package/src/analysis/analysis-cache.ctx +9 -0
- package/src/analysis/analysis-cache.js +1 -1
- package/src/analysis/complexity.ctx +6 -0
- package/src/analysis/complexity.js +1 -1
- package/src/analysis/custom-rules.ctx +14 -0
- package/src/analysis/custom-rules.js +1 -1
- package/src/analysis/db-analysis.ctx +7 -0
- package/src/analysis/db-analysis.js +1 -1
- package/src/analysis/dead-code.ctx +6 -0
- package/src/analysis/dead-code.js +1 -1
- package/src/analysis/full-analysis.ctx +9 -0
- package/src/analysis/full-analysis.js +1 -1
- package/src/analysis/jsdoc-checker.ctx +10 -0
- package/src/analysis/jsdoc-checker.js +1 -1
- package/src/analysis/jsdoc-generator.ctx +9 -0
- package/src/analysis/jsdoc-generator.js +1 -1
- package/src/analysis/large-files.ctx +6 -0
- package/src/analysis/large-files.js +1 -1
- package/src/analysis/outdated-patterns.ctx +7 -0
- package/src/analysis/outdated-patterns.js +1 -1
- package/src/analysis/similar-functions.ctx +6 -0
- package/src/analysis/similar-functions.js +1 -1
- package/src/analysis/test-annotations.ctx +11 -0
- package/src/analysis/test-annotations.js +1 -1
- package/src/analysis/type-checker.ctx +6 -0
- package/src/analysis/type-checker.js +1 -1
- package/src/analysis/undocumented.ctx +8 -0
- package/src/analysis/undocumented.js +1 -1
- package/src/cli/cli-handlers.ctx +7 -0
- package/src/cli/cli-handlers.js +1 -1
- package/src/cli/cli.ctx +6 -0
- package/src/cli/cli.js +1 -1
- package/src/compact/ai-context.ctx +6 -0
- package/src/compact/ai-context.js +1 -1
- package/src/compact/compact-migrate.ctx +8 -0
- package/src/compact/compact-migrate.js +1 -1
- package/src/compact/compact.ctx +11 -0
- package/src/compact/compact.js +1 -1
- package/src/compact/compress.ctx +7 -0
- package/src/compact/compress.js +1 -1
- package/src/compact/ctx-resolver.ctx +2 -0
- package/src/compact/ctx-resolver.js +1 -1
- package/src/compact/ctx-to-jsdoc.ctx +11 -0
- package/src/compact/ctx-to-jsdoc.js +1 -1
- package/src/compact/doc-dialect.ctx +11 -0
- package/src/compact/doc-dialect.js +2 -2
- package/src/compact/expand.ctx +14 -0
- package/src/compact/expand.js +1 -1
- package/src/compact/framework-references.ctx +7 -0
- package/src/compact/framework-references.js +1 -1
- package/src/compact/instructions.ctx +6 -0
- package/src/compact/instructions.js +1 -1
- package/src/compact/jsdoc-builder.ctx +4 -0
- package/src/compact/jsdoc-builder.js +1 -1
- package/src/compact/mode-config.ctx +8 -0
- package/src/compact/mode-config.js +1 -1
- package/src/compact/split-declarations.ctx +6 -0
- package/src/compact/split-declarations.js +1 -1
- package/src/compact/validate-pipeline.ctx +12 -0
- package/src/compact/validate-pipeline.js +1 -1
- package/src/core/event-bus.ctx +9 -0
- package/src/core/event-bus.js +1 -1
- package/src/core/file-walker.ctx +1 -0
- package/src/core/file-walker.js +1 -1
- package/src/core/filters.ctx +12 -0
- package/src/core/filters.js +1 -1
- package/src/core/graph-builder.ctx +7 -0
- package/src/core/graph-builder.js +1 -1
- package/src/core/parser.ctx +12 -0
- package/src/core/parser.js +1 -1
- package/src/core/utils.ctx +1 -0
- package/src/core/utils.js +1 -1
- package/src/core/workspace.ctx +7 -0
- package/src/core/workspace.js +1 -1
- package/src/lang/lang-go.ctx +8 -0
- package/src/lang/lang-go.js +1 -1
- package/src/lang/lang-python.ctx +5 -0
- package/src/lang/lang-python.js +1 -1
- package/src/lang/lang-sql.ctx +10 -0
- package/src/lang/lang-sql.js +1 -1
- package/src/lang/lang-typescript.ctx +6 -0
- package/src/lang/lang-typescript.js +1 -1
- package/src/lang/lang-utils.ctx +5 -0
- package/src/lang/lang-utils.js +1 -1
- package/src/mcp/mcp-server.ctx +6 -0
- package/src/mcp/mcp-server.js +1 -1
- package/src/mcp/tool-defs.ctx +2 -0
- package/src/mcp/tool-defs.js +1 -1
- package/src/mcp/tools.ctx +13 -0
- package/src/mcp/tools.js +1 -1
- package/src/network/backend-lifecycle.ctx +10 -0
- package/src/network/backend-lifecycle.js +1 -1
- package/src/network/backend.ctx +5 -0
- package/src/network/backend.js +1 -1
- package/src/network/local-gateway.ctx +9 -0
- package/src/network/local-gateway.js +1 -1
- package/src/network/mdns.ctx +6 -0
- package/src/network/mdns.js +1 -1
- package/src/network/server.ctx +2 -0
- package/src/network/server.js +2 -2
- package/src/network/web-server.ctx +17 -0
- package/src/network/web-server.js +2 -2
- package/web/follow-controller.js +94 -25
- package/web/panels/dep-graph.js +207 -21
- package/project-graph-mcp-2.3.0.tgz +0 -0
- package/vendor/symbiote-node/CHANGELOG.md +0 -31
- package/vendor/symbiote-node/LICENSE +0 -21
- package/vendor/symbiote-node/README.md +0 -206
- package/vendor/symbiote-node/canvas/AutoLayout.js +0 -725
- package/vendor/symbiote-node/canvas/Breadcrumb/Breadcrumb.css.js +0 -73
- package/vendor/symbiote-node/canvas/Breadcrumb/Breadcrumb.js +0 -93
- package/vendor/symbiote-node/canvas/Breadcrumb/Breadcrumb.tpl.js +0 -9
- package/vendor/symbiote-node/canvas/CanvasConnectionRenderer.js +0 -962
- package/vendor/symbiote-node/canvas/ConnectionRenderer.js +0 -1468
- package/vendor/symbiote-node/canvas/FlowSimulator.js +0 -323
- package/vendor/symbiote-node/canvas/ForceLayout.js +0 -189
- package/vendor/symbiote-node/canvas/ForceWorker.js +0 -1325
- package/vendor/symbiote-node/canvas/GraphTabs/GraphTabs.css.js +0 -97
- package/vendor/symbiote-node/canvas/GraphTabs/GraphTabs.js +0 -176
- package/vendor/symbiote-node/canvas/GraphTabs/GraphTabs.tpl.js +0 -12
- package/vendor/symbiote-node/canvas/LODManager.js +0 -88
- package/vendor/symbiote-node/canvas/Minimap/Minimap.css.js +0 -71
- package/vendor/symbiote-node/canvas/Minimap/Minimap.js +0 -207
- package/vendor/symbiote-node/canvas/Minimap/Minimap.tpl.js +0 -9
- package/vendor/symbiote-node/canvas/NodeCanvas/NodeCanvas.css.js +0 -261
- package/vendor/symbiote-node/canvas/NodeCanvas/NodeCanvas.js +0 -1840
- package/vendor/symbiote-node/canvas/NodeCanvas/NodeCanvas.tpl.js +0 -22
- package/vendor/symbiote-node/canvas/NodeSearch/NodeSearch.css.js +0 -97
- package/vendor/symbiote-node/canvas/NodeSearch/NodeSearch.js +0 -132
- package/vendor/symbiote-node/canvas/NodeSearch/NodeSearch.tpl.js +0 -21
- package/vendor/symbiote-node/canvas/NodeViewManager.js +0 -584
- package/vendor/symbiote-node/canvas/PinExpansion.js +0 -131
- package/vendor/symbiote-node/canvas/PseudoConnection.js +0 -80
- package/vendor/symbiote-node/canvas/SubgraphManager.js +0 -201
- package/vendor/symbiote-node/canvas/SubgraphRouter.js +0 -443
- package/vendor/symbiote-node/canvas/ViewportActions.js +0 -446
- package/vendor/symbiote-node/core/Connection.js +0 -45
- package/vendor/symbiote-node/core/Editor.js +0 -451
- package/vendor/symbiote-node/core/Frame.js +0 -31
- package/vendor/symbiote-node/core/GraphMermaid.js +0 -348
- package/vendor/symbiote-node/core/GraphText.js +0 -210
- package/vendor/symbiote-node/core/Node.js +0 -143
- package/vendor/symbiote-node/core/Portal.js +0 -104
- package/vendor/symbiote-node/core/Socket.js +0 -185
- package/vendor/symbiote-node/core/SubgraphNode.js +0 -125
- package/vendor/symbiote-node/engine/AgentUICommands.js +0 -100
- package/vendor/symbiote-node/engine/Executor.js +0 -371
- package/vendor/symbiote-node/engine/Graph.js +0 -314
- package/vendor/symbiote-node/engine/GraphServer.js +0 -353
- package/vendor/symbiote-node/engine/HandlerLoader.js +0 -145
- package/vendor/symbiote-node/engine/History.js +0 -83
- package/vendor/symbiote-node/engine/Lifecycle.js +0 -118
- package/vendor/symbiote-node/engine/Persistence.js +0 -84
- package/vendor/symbiote-node/engine/Registry.js +0 -264
- package/vendor/symbiote-node/engine/SocketTypes.js +0 -79
- package/vendor/symbiote-node/engine/cli.js +0 -404
- package/vendor/symbiote-node/engine/index.js +0 -56
- package/vendor/symbiote-node/engine/nanoid.js +0 -28
- package/vendor/symbiote-node/engine/package.json +0 -26
- package/vendor/symbiote-node/engine/packs/ai/beat-detect.handler.js +0 -215
- package/vendor/symbiote-node/engine/packs/ai/content-adapt.handler.js +0 -238
- package/vendor/symbiote-node/engine/packs/ai/face-detect.handler.js +0 -287
- package/vendor/symbiote-node/engine/packs/ai/grok-generate.handler.js +0 -565
- package/vendor/symbiote-node/engine/packs/ai/kling-lipsync.handler.js +0 -414
- package/vendor/symbiote-node/engine/packs/ai/lesson-generate.handler.js +0 -343
- package/vendor/symbiote-node/engine/packs/ai/opencode.handler.js +0 -164
- package/vendor/symbiote-node/engine/packs/ai/replicate-lipsync.handler.js +0 -341
- package/vendor/symbiote-node/engine/packs/ai/tts.handler.js +0 -241
- package/vendor/symbiote-node/engine/packs/ai/whisper.handler.js +0 -191
- package/vendor/symbiote-node/engine/packs/data/db-query.handler.js +0 -67
- package/vendor/symbiote-node/engine/packs/data/news-accumulate.handler.js +0 -281
- package/vendor/symbiote-node/engine/packs/data/personas.handler.js +0 -160
- package/vendor/symbiote-node/engine/packs/data/prompt-loader.handler.js +0 -193
- package/vendor/symbiote-node/engine/packs/data/roles.handler.js +0 -216
- package/vendor/symbiote-node/engine/packs/data/rss-feed.handler.js +0 -244
- package/vendor/symbiote-node/engine/packs/debug/inject.handler.js +0 -52
- package/vendor/symbiote-node/engine/packs/flow/agent.handler.js +0 -73
- package/vendor/symbiote-node/engine/packs/flow/if.handler.js +0 -107
- package/vendor/symbiote-node/engine/packs/flow/loop.handler.js +0 -58
- package/vendor/symbiote-node/engine/packs/flow/merge.handler.js +0 -60
- package/vendor/symbiote-node/engine/packs/flow/retry.handler.js +0 -65
- package/vendor/symbiote-node/engine/packs/flow/switch.handler.js +0 -64
- package/vendor/symbiote-node/engine/packs/flow/wait-all.handler.js +0 -39
- package/vendor/symbiote-node/engine/packs/io/http-request.handler.js +0 -82
- package/vendor/symbiote-node/engine/packs/io/read-file.handler.js +0 -60
- package/vendor/symbiote-node/engine/packs/io/write-file.handler.js +0 -63
- package/vendor/symbiote-node/engine/packs/transform/anchor-match.handler.js +0 -494
- package/vendor/symbiote-node/engine/packs/transform/effects-skeleton.handler.js +0 -417
- package/vendor/symbiote-node/engine/packs/transform/json-parse.handler.js +0 -43
- package/vendor/symbiote-node/engine/packs/transform/lipsync-select.handler.js +0 -339
- package/vendor/symbiote-node/engine/packs/transform/riopla-adapt.handler.js +0 -432
- package/vendor/symbiote-node/engine/packs/transform/set.handler.js +0 -57
- package/vendor/symbiote-node/engine/packs/transform/template-builder.handler.js +0 -134
- package/vendor/symbiote-node/engine/packs/transform/template.handler.js +0 -79
- package/vendor/symbiote-node/engine/packs/transform/timeline-build.handler.js +0 -399
- package/vendor/symbiote-node/engine/packs/util/delay.handler.js +0 -39
- package/vendor/symbiote-node/engine/packs/util/log.handler.js +0 -44
- package/vendor/symbiote-node/engine/packs/video-pack.js +0 -323
- package/vendor/symbiote-node/index.js +0 -103
- package/vendor/symbiote-node/inspector/InspectorPanel/InspectorPanel.css.js +0 -361
- package/vendor/symbiote-node/inspector/InspectorPanel/InspectorPanel.js +0 -332
- package/vendor/symbiote-node/inspector/InspectorPanel/InspectorPanel.tpl.js +0 -96
- package/vendor/symbiote-node/inspector/TemplatePreview/TemplatePreview.css.js +0 -104
- package/vendor/symbiote-node/inspector/TemplatePreview/TemplatePreview.js +0 -133
- package/vendor/symbiote-node/inspector/TemplatePreview/TemplatePreview.tpl.js +0 -33
- package/vendor/symbiote-node/interactions/ConnectFlow.js +0 -307
- package/vendor/symbiote-node/interactions/Drag.js +0 -102
- package/vendor/symbiote-node/interactions/Selector.js +0 -132
- package/vendor/symbiote-node/interactions/SnapGrid.js +0 -65
- package/vendor/symbiote-node/interactions/Zoom.js +0 -140
- package/vendor/symbiote-node/layout/ActionZone/ActionZone.css.js +0 -88
- package/vendor/symbiote-node/layout/ActionZone/ActionZone.js +0 -254
- package/vendor/symbiote-node/layout/ActionZone/ActionZone.tpl.js +0 -11
- package/vendor/symbiote-node/layout/Layout/Layout.css.js +0 -88
- package/vendor/symbiote-node/layout/Layout/Layout.js +0 -622
- package/vendor/symbiote-node/layout/Layout/Layout.tpl.js +0 -25
- package/vendor/symbiote-node/layout/LayoutNode/LayoutNode.css.js +0 -293
- package/vendor/symbiote-node/layout/LayoutNode/LayoutNode.js +0 -467
- package/vendor/symbiote-node/layout/LayoutNode/LayoutNode.tpl.js +0 -33
- package/vendor/symbiote-node/layout/LayoutPreview/LayoutPreview.css.js +0 -46
- package/vendor/symbiote-node/layout/LayoutPreview/LayoutPreview.js +0 -102
- package/vendor/symbiote-node/layout/LayoutPreview/LayoutPreview.tpl.js +0 -6
- package/vendor/symbiote-node/layout/LayoutRouter/LayoutRouter.js +0 -156
- package/vendor/symbiote-node/layout/LayoutRouter/routerSync.js +0 -250
- package/vendor/symbiote-node/layout/LayoutSidebar/LayoutSidebar.css.js +0 -379
- package/vendor/symbiote-node/layout/LayoutSidebar/LayoutSidebar.js +0 -263
- package/vendor/symbiote-node/layout/LayoutSidebar/LayoutSidebar.tpl.js +0 -20
- package/vendor/symbiote-node/layout/LayoutSidebar/SidebarSection.js +0 -183
- package/vendor/symbiote-node/layout/LayoutTree.js +0 -246
- package/vendor/symbiote-node/layout/PanelMenu/PanelMenu.css.js +0 -43
- package/vendor/symbiote-node/layout/PanelMenu/PanelMenu.js +0 -89
- package/vendor/symbiote-node/layout/PanelMenu/PanelMenu.tpl.js +0 -14
- package/vendor/symbiote-node/layout/index.js +0 -16
- package/vendor/symbiote-node/menu/ContextMenu/ContextMenu.css.js +0 -61
- package/vendor/symbiote-node/menu/ContextMenu/ContextMenu.js +0 -79
- package/vendor/symbiote-node/menu/ContextMenu/ContextMenu.tpl.js +0 -19
- package/vendor/symbiote-node/node/CtrlItem/CtrlItem.css.js +0 -41
- package/vendor/symbiote-node/node/CtrlItem/CtrlItem.js +0 -24
- package/vendor/symbiote-node/node/CtrlItem/CtrlItem.tpl.js +0 -16
- package/vendor/symbiote-node/node/GraphFrame/GraphFrame.css.js +0 -65
- package/vendor/symbiote-node/node/GraphFrame/GraphFrame.js +0 -29
- package/vendor/symbiote-node/node/GraphFrame/GraphFrame.tpl.js +0 -13
- package/vendor/symbiote-node/node/GraphNode/GraphNode.css.js +0 -683
- package/vendor/symbiote-node/node/GraphNode/GraphNode.js +0 -92
- package/vendor/symbiote-node/node/GraphNode/GraphNode.tpl.js +0 -17
- package/vendor/symbiote-node/node/NodeSocket/NodeSocket.js +0 -25
- package/vendor/symbiote-node/node/NodeSocket/NodeSocket.tpl.js +0 -7
- package/vendor/symbiote-node/node/PortItem/PortItem.css.js +0 -90
- package/vendor/symbiote-node/node/PortItem/PortItem.js +0 -87
- package/vendor/symbiote-node/node/PortItem/PortItem.tpl.js +0 -10
- package/vendor/symbiote-node/package.json +0 -59
- package/vendor/symbiote-node/palette/PaletteBrowser/PaletteBrowser.css.js +0 -143
- package/vendor/symbiote-node/palette/PaletteBrowser/PaletteBrowser.js +0 -131
- package/vendor/symbiote-node/palette/PaletteBrowser/PaletteBrowser.tpl.js +0 -16
- package/vendor/symbiote-node/plugins/History.js +0 -384
- package/vendor/symbiote-node/plugins/Readonly.js +0 -59
- package/vendor/symbiote-node/shapes/CircleShape.js +0 -80
- package/vendor/symbiote-node/shapes/CommentShape.js +0 -35
- package/vendor/symbiote-node/shapes/DiamondShape.js +0 -115
- package/vendor/symbiote-node/shapes/NodeShape.js +0 -80
- package/vendor/symbiote-node/shapes/PillShape.js +0 -91
- package/vendor/symbiote-node/shapes/RectShape.js +0 -72
- package/vendor/symbiote-node/shapes/SVGShape.js +0 -494
- package/vendor/symbiote-node/shapes/index.js +0 -53
- package/vendor/symbiote-node/themes/Palette.js +0 -32
- package/vendor/symbiote-node/themes/Skin.js +0 -113
- package/vendor/symbiote-node/themes/Theme.js +0 -84
- package/vendor/symbiote-node/themes/carbon.js +0 -137
- package/vendor/symbiote-node/themes/dark.js +0 -137
- package/vendor/symbiote-node/themes/ebook.js +0 -138
- package/vendor/symbiote-node/themes/grey.js +0 -137
- package/vendor/symbiote-node/themes/light.js +0 -137
- package/vendor/symbiote-node/themes/neon.js +0 -138
- package/vendor/symbiote-node/themes/pcb.js +0 -273
- package/vendor/symbiote-node/themes/synthwave.js +0 -137
- package/vendor/symbiote-node/toolbar/QuickToolbar/QuickToolbar.css.js +0 -86
- package/vendor/symbiote-node/toolbar/QuickToolbar/QuickToolbar.js +0 -128
- package/vendor/symbiote-node/toolbar/QuickToolbar/QuickToolbar.tpl.js +0 -29
package/web/follow-controller.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// @ctx .context/web/follow-controller.ctx
|
|
2
2
|
/**
|
|
3
|
-
* FollowController — Central orchestrator for Follow Mode.
|
|
3
|
+
* FollowController — Central orchestrator for Follow Mode (Magic Automation Theater).
|
|
4
4
|
*
|
|
5
|
-
* Classifies incoming tool-events and
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Classifies incoming tool-events and drives the UI:
|
|
6
|
+
* 1. Switches the active panel (graph, code, analysis) via hash routing.
|
|
7
|
+
* 2. Dispatches debounced focus-change signals to visible panels.
|
|
8
|
+
* 3. Manages the status ribbon text shown during active follow.
|
|
8
9
|
*
|
|
9
10
|
* NOTE: Does NOT import from app.js to avoid circular dependency.
|
|
10
11
|
* Call init(events, emit) before enable().
|
|
@@ -13,6 +14,9 @@
|
|
|
13
14
|
/** Debounce delay for heavy visual updates (camera, code loading) */
|
|
14
15
|
const HEAVY_DEBOUNCE = 800;
|
|
15
16
|
|
|
17
|
+
/** Delay to allow panel mount after hash change before sending focus */
|
|
18
|
+
const PANEL_MOUNT_DELAY = 300;
|
|
19
|
+
|
|
16
20
|
class FollowController {
|
|
17
21
|
/** @type {boolean} */
|
|
18
22
|
enabled = false;
|
|
@@ -30,6 +34,8 @@ class FollowController {
|
|
|
30
34
|
_events = null;
|
|
31
35
|
/** @type {Function|null} */
|
|
32
36
|
_emit = null;
|
|
37
|
+
/** @type {string} Current active panel type in follow mode */
|
|
38
|
+
_activePanel = 'graph';
|
|
33
39
|
|
|
34
40
|
/**
|
|
35
41
|
* Late-bind events bus and emit function (breaks circular import).
|
|
@@ -48,6 +54,7 @@ class FollowController {
|
|
|
48
54
|
|
|
49
55
|
// Save current location for restoring later
|
|
50
56
|
this._previousHash = location.hash;
|
|
57
|
+
this._activePanel = 'graph';
|
|
51
58
|
|
|
52
59
|
// Bind tool-event listener
|
|
53
60
|
this._boundHandler = (e) => this._onToolEvent(e.detail);
|
|
@@ -105,12 +112,54 @@ class FollowController {
|
|
|
105
112
|
// Visual focus — classify and dispatch (debounced for heavy ops)
|
|
106
113
|
const action = this._classify(shortName, args, isCall, isResult, event);
|
|
107
114
|
if (action) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
115
|
+
this._routeAndFocus(action);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Route to the correct panel, then emit focus.
|
|
121
|
+
* Two-phase: if the target panel differs from current, switch hash first,
|
|
122
|
+
* then wait for mount before emitting focus.
|
|
123
|
+
* @param {{focus: object, debounce?: number, immediate?: boolean}} action
|
|
124
|
+
*/
|
|
125
|
+
_routeAndFocus(action) {
|
|
126
|
+
const targetPanel = action.focus.type === 'file' ? 'code' : action.focus.type || 'graph';
|
|
127
|
+
|
|
128
|
+
const needsSwitch = this._activePanel !== targetPanel;
|
|
129
|
+
this._activePanel = targetPanel;
|
|
130
|
+
|
|
131
|
+
if (needsSwitch) {
|
|
132
|
+
// Build new hash for the follow section
|
|
133
|
+
const hashSection = this._panelToHash(targetPanel);
|
|
134
|
+
// Use replaceState to avoid polluting browser history during follow
|
|
135
|
+
const newHash = `#${hashSection}`;
|
|
136
|
+
if (location.hash !== newHash) {
|
|
137
|
+
// We need to trigger hashchange so the layout system picks it up
|
|
138
|
+
location.hash = hashSection;
|
|
112
139
|
}
|
|
113
140
|
}
|
|
141
|
+
|
|
142
|
+
// Emit focus — with delay if panel needed mounting, otherwise respect debounce
|
|
143
|
+
if (needsSwitch) {
|
|
144
|
+
// Wait for panel to mount after layout change
|
|
145
|
+
setTimeout(() => {
|
|
146
|
+
this._emitFocusNow(action.focus);
|
|
147
|
+
}, PANEL_MOUNT_DELAY);
|
|
148
|
+
} else if (action.immediate) {
|
|
149
|
+
this._emitFocusNow(action.focus);
|
|
150
|
+
} else {
|
|
151
|
+
this._emitFocusDebounced(action.focus, action.debounce || HEAVY_DEBOUNCE);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Map panel type to hash section.
|
|
157
|
+
* In follow mode, graph/code/analysis all live under the 'follow' section
|
|
158
|
+
* but we can use the hash to give routing hints.
|
|
159
|
+
*/
|
|
160
|
+
_panelToHash(panel) {
|
|
161
|
+
// All panels are within the 'follow' layout, no need to switch section
|
|
162
|
+
return 'follow';
|
|
114
163
|
}
|
|
115
164
|
|
|
116
165
|
/**
|
|
@@ -136,6 +185,9 @@ class FollowController {
|
|
|
136
185
|
if (args.action === 'call_chain' && args.from && args.to) {
|
|
137
186
|
return { focus: { type: 'graph', target: { from: args.from, to: args.to }, action: 'chain' }, immediate: true };
|
|
138
187
|
}
|
|
188
|
+
if (args.action === 'sub_projects') {
|
|
189
|
+
return { focus: { type: 'graph', action: 'fit' }, immediate: true };
|
|
190
|
+
}
|
|
139
191
|
}
|
|
140
192
|
|
|
141
193
|
// === Skeleton / Overview ===
|
|
@@ -148,9 +200,25 @@ class FollowController {
|
|
|
148
200
|
return { focus: { type: 'file', target: args.path }, debounce: HEAVY_DEBOUNCE };
|
|
149
201
|
}
|
|
150
202
|
|
|
203
|
+
// === Documentation ===
|
|
204
|
+
if (tool === 'docs' && args.file) {
|
|
205
|
+
return { focus: { type: 'file', target: args.file }, debounce: HEAVY_DEBOUNCE };
|
|
206
|
+
}
|
|
207
|
+
|
|
151
208
|
// === Analysis ===
|
|
152
209
|
if (tool === 'analyze') {
|
|
153
|
-
|
|
210
|
+
// Analysis events should pulse the graph to show "thinking"
|
|
211
|
+
return { focus: { type: 'graph', action: 'fit' }, immediate: true };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// === JSDoc ===
|
|
215
|
+
if (tool === 'jsdoc' && args.path) {
|
|
216
|
+
return { focus: { type: 'file', target: args.path }, debounce: HEAVY_DEBOUNCE };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// === Focus zone ===
|
|
220
|
+
if (tool === 'get_focus_zone') {
|
|
221
|
+
return { focus: { type: 'graph', action: 'fit' }, immediate: true };
|
|
154
222
|
}
|
|
155
223
|
|
|
156
224
|
return null;
|
|
@@ -169,23 +237,24 @@ class FollowController {
|
|
|
169
237
|
|
|
170
238
|
switch (tool) {
|
|
171
239
|
case 'navigate': {
|
|
172
|
-
if (args.action === 'expand') return
|
|
173
|
-
if (args.action === 'deps') return
|
|
174
|
-
if (args.action === 'usages') return
|
|
175
|
-
if (args.action === 'call_chain') return
|
|
176
|
-
if (args.action === 'sub_projects') return
|
|
177
|
-
return
|
|
240
|
+
if (args.action === 'expand') return `🔍 Expanding ${args.symbol}`;
|
|
241
|
+
if (args.action === 'deps') return `🔗 Tracing deps of ${args.symbol}`;
|
|
242
|
+
if (args.action === 'usages') return `📡 Finding usages of ${args.symbol}`;
|
|
243
|
+
if (args.action === 'call_chain') return `⛓ Tracing ${args.from} → ${args.to}`;
|
|
244
|
+
if (args.action === 'sub_projects') return `📦 Scanning sub-projects`;
|
|
245
|
+
return `🧭 Navigating graph`;
|
|
178
246
|
}
|
|
179
|
-
case 'get_skeleton': return
|
|
180
|
-
case 'get_ai_context': return
|
|
181
|
-
case '
|
|
182
|
-
case '
|
|
183
|
-
case '
|
|
184
|
-
case '
|
|
185
|
-
case '
|
|
186
|
-
case '
|
|
187
|
-
case '
|
|
188
|
-
|
|
247
|
+
case 'get_skeleton': return `🗺️ Scanning project structure`;
|
|
248
|
+
case 'get_ai_context': return `🧠 Loading AI context`;
|
|
249
|
+
case 'get_focus_zone': return `🎯 Analyzing recent changes`;
|
|
250
|
+
case 'compact': return `📄 Reading ${short}`;
|
|
251
|
+
case 'analyze': return `📊 Analyzing: ${args.action || ''}`;
|
|
252
|
+
case 'docs': return `📝 Documentation: ${args.action || ''}`;
|
|
253
|
+
case 'jsdoc': return `📋 JSDoc: ${args.action || ''}`;
|
|
254
|
+
case 'db': return `🗄️ Database: ${args.action || ''}`;
|
|
255
|
+
case 'testing': return `🧪 Tests: ${args.action || ''}`;
|
|
256
|
+
case 'filters': return `⚙️ Filters: ${args.action || ''}`;
|
|
257
|
+
default: return tool ? `⚡ ${tool}` : '';
|
|
189
258
|
}
|
|
190
259
|
}
|
|
191
260
|
|
package/web/panels/dep-graph.js
CHANGED
|
@@ -115,6 +115,154 @@ function buildBasenameIndex(knownFiles) {
|
|
|
115
115
|
return _basenameIndex;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Build a file-level graph from skeleton data.
|
|
120
|
+
* Each file becomes a Node, each import relationship becomes a Connection.
|
|
121
|
+
*
|
|
122
|
+
* @param {object} skeleton - skeleton from get_skeleton
|
|
123
|
+
* @returns {{ editor: NodeEditor, fileMap: Map<string, string> }}
|
|
124
|
+
*/
|
|
125
|
+
function buildFileGraph(skeleton) {
|
|
126
|
+
const editor = new NodeEditor();
|
|
127
|
+
const fileMap = new Map(); // filePath → nodeId
|
|
128
|
+
const dirMap = new Map(); // dirPath → nodeId (hub nodes)
|
|
129
|
+
|
|
130
|
+
// Collect all files that have symbols
|
|
131
|
+
const files = new Set();
|
|
132
|
+
const assetFiles = new Set(); // non-source files (.css, .html, .json, .md, etc.)
|
|
133
|
+
// From nodes (classes) — each has .f (file) property
|
|
134
|
+
for (const data of Object.values(skeleton.n || {})) {
|
|
135
|
+
if (data.f) files.add(data.f);
|
|
136
|
+
}
|
|
137
|
+
// From exports map — keys are files
|
|
138
|
+
for (const file of Object.keys(skeleton.X || {})) {
|
|
139
|
+
files.add(file);
|
|
140
|
+
}
|
|
141
|
+
// From source files without symbols
|
|
142
|
+
for (const [dir, names] of Object.entries(skeleton.f || {})) {
|
|
143
|
+
for (const name of names) {
|
|
144
|
+
files.add(dir === './' ? name : dir + name);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// From non-source/asset files (.css, .html, .json, .md, etc.)
|
|
148
|
+
for (const [dir, names] of Object.entries(skeleton.a || {})) {
|
|
149
|
+
for (const name of names) {
|
|
150
|
+
const fullPath = dir === './' ? name : dir + name;
|
|
151
|
+
files.add(fullPath);
|
|
152
|
+
assetFiles.add(fullPath);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (files.size === 0) return { editor, fileMap };
|
|
157
|
+
|
|
158
|
+
// Group files by directory
|
|
159
|
+
const dirFiles = new Map();
|
|
160
|
+
for (const file of files) {
|
|
161
|
+
const dir = dirOf(file);
|
|
162
|
+
if (!dirFiles.has(dir)) dirFiles.set(dir, []);
|
|
163
|
+
dirFiles.get(dir).push(file);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// TODO Phase 2: Create directory hub nodes when LOD zoom expansion is ready
|
|
167
|
+
// Hub nodes without connections create disconnected groups — skip for now
|
|
168
|
+
// for (const [dir, dirFileList] of dirFiles) {
|
|
169
|
+
// if (dirFileList.length < 2) continue;
|
|
170
|
+
// const dirLabel = dir.replace(/\/$/, '').split('/').pop() || 'root';
|
|
171
|
+
// const hubNode = new Node(dirLabel, { type: 'directory', category: 'server', shape: 'hexagon' });
|
|
172
|
+
// hubNode.params = { path: dir, dir, isHub: true };
|
|
173
|
+
// hubNode.addOutput('out', new Output(S_EXPORT, ''));
|
|
174
|
+
// hubNode.addInput('in', new Input(S_IMPORT, ''));
|
|
175
|
+
// editor.addNode(hubNode);
|
|
176
|
+
// dirMap.set(dir, hubNode.id);
|
|
177
|
+
// }
|
|
178
|
+
|
|
179
|
+
// Create file nodes (standard HTML nodes with icons)
|
|
180
|
+
for (const file of files) {
|
|
181
|
+
const dir = dirOf(file);
|
|
182
|
+
const label = baseName(file);
|
|
183
|
+
const isAsset = assetFiles.has(file);
|
|
184
|
+
const node = new Node(label, {
|
|
185
|
+
type: isAsset ? 'asset' : 'file',
|
|
186
|
+
category: isAsset ? 'asset' : 'file',
|
|
187
|
+
});
|
|
188
|
+
node.params = { path: file, dir };
|
|
189
|
+
|
|
190
|
+
// Every file has one output (exports) and one input (imports)
|
|
191
|
+
node.addOutput('out', new Output(S_EXPORT, ''));
|
|
192
|
+
node.addInput('in', new Input(S_IMPORT, ''));
|
|
193
|
+
|
|
194
|
+
editor.addNode(node);
|
|
195
|
+
fileMap.set(file, node.id);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Build import edges from skeleton.I (file-level import map)
|
|
199
|
+
// skeleton.I[file] = [source1, source2, ...]
|
|
200
|
+
const edgesAdded = new Set();
|
|
201
|
+
for (const [srcFile, sources] of Object.entries(skeleton.I || {})) {
|
|
202
|
+
const srcId = fileMap.get(srcFile);
|
|
203
|
+
if (!srcId) continue;
|
|
204
|
+
|
|
205
|
+
for (const impPath of sources) {
|
|
206
|
+
// Skip node builtins and external packages
|
|
207
|
+
if (impPath.startsWith('node:') || (!impPath.startsWith('.') && !impPath.startsWith('/'))) continue;
|
|
208
|
+
|
|
209
|
+
const targetFile = resolveImport(impPath, srcFile, files);
|
|
210
|
+
if (!targetFile) continue;
|
|
211
|
+
|
|
212
|
+
const tgtId = fileMap.get(targetFile);
|
|
213
|
+
if (!tgtId || tgtId === srcId) continue;
|
|
214
|
+
|
|
215
|
+
const edgeKey = `${srcId}->${tgtId}`;
|
|
216
|
+
if (edgesAdded.has(edgeKey)) continue;
|
|
217
|
+
edgesAdded.add(edgeKey);
|
|
218
|
+
|
|
219
|
+
const srcNode = editor.getNode(srcId);
|
|
220
|
+
const tgtNode = editor.getNode(tgtId);
|
|
221
|
+
try {
|
|
222
|
+
const conn = new Connection(srcNode, 'out', tgtNode, 'in');
|
|
223
|
+
// Phase 3: tag cross-directory connections as "via"
|
|
224
|
+
const srcDir = dirOf(srcFile);
|
|
225
|
+
const tgtDir = dirOf(targetFile);
|
|
226
|
+
if (srcDir !== tgtDir) {
|
|
227
|
+
conn._via = true;
|
|
228
|
+
conn._srcDir = srcDir;
|
|
229
|
+
conn._tgtDir = tgtDir;
|
|
230
|
+
}
|
|
231
|
+
editor.addConnection(conn);
|
|
232
|
+
} catch {
|
|
233
|
+
// Skip invalid connections
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Hub node: find node with highest connectivity → module category
|
|
239
|
+
const connCounts = new Map();
|
|
240
|
+
for (const conn of editor.getConnections()) {
|
|
241
|
+
connCounts.set(conn.from, (connCounts.get(conn.from) || 0) + 1);
|
|
242
|
+
connCounts.set(conn.to, (connCounts.get(conn.to) || 0) + 1);
|
|
243
|
+
}
|
|
244
|
+
let maxConns = 0;
|
|
245
|
+
let hubId = null;
|
|
246
|
+
for (const [nodeId, count] of connCounts) {
|
|
247
|
+
if (count > maxConns) {
|
|
248
|
+
maxConns = count;
|
|
249
|
+
hubId = nodeId;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (hubId) {
|
|
253
|
+
const hubNode = editor.getNode(hubId);
|
|
254
|
+
if (hubNode && hubNode.options) {
|
|
255
|
+
hubNode.options.category = 'module';
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// ── Build Reverse ID Lookup ──
|
|
260
|
+
const idToPath = new Map();
|
|
261
|
+
for (const [path, id] of fileMap.entries()) idToPath.set(id, path);
|
|
262
|
+
|
|
263
|
+
return { editor, fileMap, dirMap, dirFiles, idToPath };
|
|
264
|
+
}
|
|
265
|
+
|
|
118
266
|
/**
|
|
119
267
|
* Build a hierarchical SubgraphNode graph:
|
|
120
268
|
* Level 0: directories (SubgraphNode)
|
|
@@ -723,7 +871,11 @@ export class DepGraph extends Symbiote {
|
|
|
723
871
|
if (!loader) return;
|
|
724
872
|
loader.setAttribute('data-hidden', '');
|
|
725
873
|
// Remove from DOM after fade to avoid blocking pointer events
|
|
726
|
-
setTimeout(() =>
|
|
874
|
+
setTimeout(() => {
|
|
875
|
+
loader.remove();
|
|
876
|
+
// Replay any follow-focus that arrived while the graph was building
|
|
877
|
+
this._replayPendingFollowFocus();
|
|
878
|
+
}, 350);
|
|
727
879
|
}
|
|
728
880
|
|
|
729
881
|
/** Show (or re-show) the PCB preloader overlay — safe to call multiple times */
|
|
@@ -891,18 +1043,20 @@ export class DepGraph extends Symbiote {
|
|
|
891
1043
|
viewModeBtn.removeAttribute('data-active');
|
|
892
1044
|
}
|
|
893
1045
|
}
|
|
894
|
-
// Hide structured-only buttons in flat mode
|
|
895
1046
|
this._updateStructuredOnlyVisibility(this._viewMode);
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
this._viewMode
|
|
1047
|
+
|
|
1048
|
+
this._setMode = (newMode) => {
|
|
1049
|
+
if (this._viewMode === newMode) return;
|
|
1050
|
+
this._viewMode = newMode;
|
|
899
1051
|
const label = this._viewMode === 'flat' ? 'FLAT' : 'TREE';
|
|
900
1052
|
const icon = this._viewMode === 'flat' ? 'account_tree' : 'grid_view';
|
|
901
|
-
viewModeBtn
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
1053
|
+
if (viewModeBtn) {
|
|
1054
|
+
viewModeBtn.innerHTML = `<span class="material-symbols-outlined">${icon}</span>${label}`;
|
|
1055
|
+
if (this._viewMode === 'structured') {
|
|
1056
|
+
viewModeBtn.setAttribute('data-active', '');
|
|
1057
|
+
} else {
|
|
1058
|
+
viewModeBtn.removeAttribute('data-active');
|
|
1059
|
+
}
|
|
906
1060
|
}
|
|
907
1061
|
this._updateStructuredOnlyVisibility(this._viewMode);
|
|
908
1062
|
|
|
@@ -923,6 +1077,11 @@ export class DepGraph extends Symbiote {
|
|
|
923
1077
|
if (state.skeleton) {
|
|
924
1078
|
this._buildGraph(state.skeleton);
|
|
925
1079
|
}
|
|
1080
|
+
};
|
|
1081
|
+
|
|
1082
|
+
viewModeBtn?.addEventListener('click', () => {
|
|
1083
|
+
const wantFlat = this._viewMode !== 'flat';
|
|
1084
|
+
this._setMode(wantFlat ? 'flat' : 'structured');
|
|
926
1085
|
});
|
|
927
1086
|
|
|
928
1087
|
// Connection Path Style toggling
|
|
@@ -981,8 +1140,14 @@ export class DepGraph extends Symbiote {
|
|
|
981
1140
|
requestAnimationFrame(() => this._buildGraph(e.detail));
|
|
982
1141
|
};
|
|
983
1142
|
|
|
1143
|
+
this._onFollowStateChanged = (e) => {
|
|
1144
|
+
const enabled = e.detail?.enabled;
|
|
1145
|
+
if (enabled && this._viewMode !== 'flat') {
|
|
1146
|
+
this._setMode('flat');
|
|
1147
|
+
}
|
|
1148
|
+
};
|
|
1149
|
+
|
|
984
1150
|
this._onFollowFocusChanged = (e) => {
|
|
985
|
-
if (this.style.display === 'none' || this.offsetWidth === 0) return;
|
|
986
1151
|
this._handleFollowFocus(e.detail);
|
|
987
1152
|
};
|
|
988
1153
|
|
|
@@ -1018,6 +1183,7 @@ export class DepGraph extends Symbiote {
|
|
|
1018
1183
|
|
|
1019
1184
|
// Autopilot: listen for orchestrator events
|
|
1020
1185
|
events.addEventListener('follow-focus-changed', this._onFollowFocusChanged);
|
|
1186
|
+
events.addEventListener('follow-state-changed', this._onFollowStateChanged);
|
|
1021
1187
|
|
|
1022
1188
|
// Update route within graph section
|
|
1023
1189
|
// On node click → save file path (just focusing)
|
|
@@ -1049,10 +1215,7 @@ export class DepGraph extends Symbiote {
|
|
|
1049
1215
|
// Root level: path goes into ?focus= parameter
|
|
1050
1216
|
this._updateHashParam('focus', path);
|
|
1051
1217
|
this._updateHashParam('in', null);
|
|
1052
|
-
|
|
1053
|
-
if (nodeId && this._canvas?.flyToNode) {
|
|
1054
|
-
this._canvas.flyToNode(nodeId, { zoom: 0.9 });
|
|
1055
|
-
}
|
|
1218
|
+
|
|
1056
1219
|
} else {
|
|
1057
1220
|
// Inside a group: preserve drill context URL, set &focus= with relative name
|
|
1058
1221
|
const drillBase = window.location.hash.split('?')[0]; // e.g. #graph/src/analysis/
|
|
@@ -1063,10 +1226,7 @@ export class DepGraph extends Symbiote {
|
|
|
1063
1226
|
this._updateHashParam('focus', relativeName);
|
|
1064
1227
|
this._updateHashParam('in', '1');
|
|
1065
1228
|
|
|
1066
|
-
|
|
1067
|
-
if (nodeId && this._canvas?.flyToNode) {
|
|
1068
|
-
this._canvas.flyToNode(nodeId, { zoom: 0.9 });
|
|
1069
|
-
}
|
|
1229
|
+
|
|
1070
1230
|
}
|
|
1071
1231
|
// Sync: highlight file in the tree sidebar
|
|
1072
1232
|
emit('file-selected', { path, source: 'canvas' });
|
|
@@ -1155,6 +1315,7 @@ export class DepGraph extends Symbiote {
|
|
|
1155
1315
|
disconnectedCallback() {
|
|
1156
1316
|
super.disconnectedCallback?.();
|
|
1157
1317
|
if (this._onSkeletonLoaded) events.removeEventListener('skeleton-loaded', this._onSkeletonLoaded);
|
|
1318
|
+
if (this._onFollowStateChanged) events.removeEventListener('follow-state-changed', this._onFollowStateChanged);
|
|
1158
1319
|
if (this._onFollowFocusChanged) events.removeEventListener('follow-focus-changed', this._onFollowFocusChanged);
|
|
1159
1320
|
if (this._onFileSelected) events.removeEventListener('file-selected', this._onFileSelected);
|
|
1160
1321
|
if (this._onHashChange) window.removeEventListener('hashchange', this._onHashChange);
|
|
@@ -1558,6 +1719,8 @@ export class DepGraph extends Symbiote {
|
|
|
1558
1719
|
this._setProgress(15, 'Parsing graph…', isStructured ? 'structured mode' : 'flat mode');
|
|
1559
1720
|
if (isStructured) {
|
|
1560
1721
|
({ editor, fileMap, dirFiles, dirNodeMap, idToPath, symbolMap } = buildStructuredGraph(skeleton));
|
|
1722
|
+
} else {
|
|
1723
|
+
({ editor, fileMap, dirFiles, idToPath, symbolMap: symbolMap = new Map() } = buildFileGraph(skeleton));
|
|
1561
1724
|
}
|
|
1562
1725
|
|
|
1563
1726
|
this._setProgress(40, 'Building nodes…', `${editor.getNodes().length} nodes`);
|
|
@@ -2492,9 +2655,21 @@ export class DepGraph extends Symbiote {
|
|
|
2492
2655
|
* @param {object} detail
|
|
2493
2656
|
*/
|
|
2494
2657
|
_handleFollowFocus({ type, target, action }) {
|
|
2495
|
-
if (
|
|
2496
|
-
|
|
2658
|
+
if (type !== 'graph' && type !== 'file') return;
|
|
2659
|
+
|
|
2660
|
+
// If graph isn't ready yet, queue the focus and replay after build
|
|
2661
|
+
if (!this._editor || !this._canvas || !this._graphBuilt) {
|
|
2662
|
+
this._pendingFollowFocus = { type, target, action };
|
|
2663
|
+
return;
|
|
2664
|
+
}
|
|
2497
2665
|
|
|
2666
|
+
this._executeFollowFocus(type, target, action);
|
|
2667
|
+
}
|
|
2668
|
+
|
|
2669
|
+
/**
|
|
2670
|
+
* Execute a follow focus action (called when graph is confirmed ready).
|
|
2671
|
+
*/
|
|
2672
|
+
_executeFollowFocus(type, target, action) {
|
|
2498
2673
|
if (type === 'graph') {
|
|
2499
2674
|
if (action === 'focus' && target) {
|
|
2500
2675
|
this._focusSymbol(target);
|
|
@@ -2511,6 +2686,17 @@ export class DepGraph extends Symbiote {
|
|
|
2511
2686
|
}
|
|
2512
2687
|
}
|
|
2513
2688
|
|
|
2689
|
+
/**
|
|
2690
|
+
* Replay any pending follow focus that was queued before the graph was ready.
|
|
2691
|
+
*/
|
|
2692
|
+
_replayPendingFollowFocus() {
|
|
2693
|
+
if (this._pendingFollowFocus) {
|
|
2694
|
+
const { type, target, action } = this._pendingFollowFocus;
|
|
2695
|
+
this._pendingFollowFocus = null;
|
|
2696
|
+
this._executeFollowFocus(type, target, action);
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2514
2700
|
// ── Phase 4: Camera Animation & Code Drill-down ──
|
|
2515
2701
|
|
|
2516
2702
|
/**
|
|
Binary file
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to symbiote-node will be documented in this file.
|
|
4
|
-
|
|
5
|
-
## [0.3.0-alpha.0] — 2026-04-18
|
|
6
|
-
|
|
7
|
-
### Fixed
|
|
8
|
-
- **Memory leak**: zombie `setTimeout` loops in SubgraphNode preview rendering — replaced with on-demand redraws
|
|
9
|
-
- **Memory leak**: event listener accumulation in `NodeCanvas.setEditor()` — added explicit unsubscribe on context switch
|
|
10
|
-
- **Memory leak**: incorrect `cancelAnimationFrame` cleanup for `setTimeout` IDs in `NodeViewManager.removeView()`
|
|
11
|
-
- **Layout overlap**: nodes measured as 4px height (DOM not ready) caused overlap — enforced minimum `nodeHeight` floor in `getSize()`
|
|
12
|
-
- **Inspector z-index**: panel header overlapped toolbar buttons — removed header, added toolbar-aware padding
|
|
13
|
-
|
|
14
|
-
### Added
|
|
15
|
-
- `Editor.removeAllListeners()` — clean teardown method for editor event system
|
|
16
|
-
- `computeTreeLayout()` — directory-hierarchy-aware tree layout with indent levels
|
|
17
|
-
- Shape primitives: `CircleShape`, `DiamondShape`, `PillShape`, `RectShape`
|
|
18
|
-
- PCB dark theme enhancements: improved node styling, copper trace connections
|
|
19
|
-
|
|
20
|
-
### Breaking
|
|
21
|
-
- `InspectorPanel` no longer renders a title header bar — consumers relying on `.insp-header` CSS should update
|
|
22
|
-
|
|
23
|
-
## [0.2.1] — 2026-04-13
|
|
24
|
-
|
|
25
|
-
- Initial open-source release
|
|
26
|
-
- Node graph editor with Symbiote.js web components
|
|
27
|
-
- Sugiyama-based auto layout (`computeAutoLayout`)
|
|
28
|
-
- PCB/Carbon theming system
|
|
29
|
-
- Inspector panel with resize handle
|
|
30
|
-
- Subgraph navigation (drill-down/drill-up)
|
|
31
|
-
- Execution engine with topological sorting
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 RND-PRO
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|