noteconnection 1.6.8 → 1.8.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 (212) hide show
  1. package/LICENSE +674 -21
  2. package/README.md +258 -64
  3. package/dist/src/agent_workspace.contract.parity.test.js +475 -0
  4. package/dist/src/agent_workspace.frontend.test.js +9989 -0
  5. package/dist/src/agent_workspace.locale.contract.test.js +95 -0
  6. package/dist/src/agent_workspace.runtime.behavior.test.js +5072 -0
  7. package/dist/src/copy.assets.contract.test.js +130 -0
  8. package/dist/src/core/PathBridge.js +28 -3
  9. package/dist/src/export/WorkspaceExportBundle.js +1130 -0
  10. package/dist/src/export/WorkspaceExportBundle.test.js +1480 -0
  11. package/dist/src/export/index.js +18 -0
  12. package/dist/src/export/types.js +2 -0
  13. package/dist/src/fixrisk.issue.verifier.contract.test.js +3 -1
  14. package/dist/src/foundation.ann.runtime.contract.test.js +81 -0
  15. package/dist/src/foundation.release.evidence.contract.test.js +406 -0
  16. package/dist/src/foundation.sqlite.runtime.contract.test.js +82 -0
  17. package/dist/src/frontend/README.md +258 -64
  18. package/dist/src/frontend/agent_workspace.js +5353 -0
  19. package/dist/src/frontend/agent_workspace_runtime.js +4434 -0
  20. package/dist/src/frontend/analysis.js +31 -4
  21. package/dist/src/frontend/app.js +3597 -141
  22. package/dist/src/frontend/focus_mode_interactions.js +33 -0
  23. package/dist/src/frontend/godot_future_path_renderer.js +540 -0
  24. package/dist/src/frontend/godot_tree_interactions.js +178 -0
  25. package/dist/src/frontend/graph_state.mjs +105 -0
  26. package/dist/src/frontend/hosted_future_path_runtime.js +157 -0
  27. package/dist/src/frontend/i18n.mjs +186 -0
  28. package/dist/src/frontend/index.html +641 -266
  29. package/dist/src/frontend/layout_gpu.js +12 -4
  30. package/dist/src/frontend/locales/en.json +721 -5
  31. package/dist/src/frontend/locales/zh.json +721 -5
  32. package/dist/src/frontend/main.mjs +60 -0
  33. package/dist/src/frontend/markdown_runtime.js +827 -0
  34. package/dist/src/frontend/notemd.css +49 -0
  35. package/dist/src/frontend/notemd.html +7 -1
  36. package/dist/src/frontend/notemd.js +64 -0
  37. package/dist/src/frontend/path.html +107 -0
  38. package/dist/src/frontend/path_app.js +2189 -150
  39. package/dist/src/frontend/path_layout.mjs +143 -0
  40. package/dist/src/frontend/path_mermaid_utils.mjs +108 -0
  41. package/dist/src/frontend/path_modules_bridge.js +486 -0
  42. package/dist/src/frontend/path_state.mjs +118 -0
  43. package/dist/src/frontend/path_styles.css +146 -0
  44. package/dist/src/frontend/path_worker_bridge.mjs +85 -0
  45. package/dist/src/frontend/reader.js +522 -27
  46. package/dist/src/frontend/runtime_bridge.js +67 -54
  47. package/dist/src/frontend/runtime_bridge.mjs +279 -0
  48. package/dist/src/frontend/settings.js +130 -12
  49. package/dist/src/frontend/simulationWorker.js +241 -6
  50. package/dist/src/frontend/source_manager.js +190 -21
  51. package/dist/src/frontend/styles.css +2853 -72
  52. package/dist/src/frontend/workbench_state.mjs +101 -0
  53. package/dist/src/frontend/workspace_panes.js +10168 -0
  54. package/dist/src/frontend.locale.contract.test.js +62 -0
  55. package/dist/src/godot.sidecar.bootstrap.contract.test.js +244 -0
  56. package/dist/src/indexing/IndexLifecycle.js +195 -0
  57. package/dist/src/indexing/IndexLifecycle.test.js +49 -0
  58. package/dist/src/indexing/SegmentBuilder.js +64 -0
  59. package/dist/src/indexing/UnitBuilder.js +48 -0
  60. package/dist/src/indexing/types.js +2 -0
  61. package/dist/src/knowledge.api.contract.test.js +170 -0
  62. package/dist/src/learning/KnowledgeLearningPlatform.js +10386 -0
  63. package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +327 -0
  64. package/dist/src/learning/KnowledgeLearningPlatform.program-f.test.js +99 -0
  65. package/dist/src/learning/KnowledgeLearningPlatform.test.js +2971 -0
  66. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +2974 -0
  67. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +3928 -0
  68. package/dist/src/learning/answerReleaseReview.js +4319 -0
  69. package/dist/src/learning/answerReleaseReview.test.js +2888 -0
  70. package/dist/src/learning/api.js +2 -0
  71. package/dist/src/learning/conversationComposer.js +1480 -0
  72. package/dist/src/learning/conversationComposer.test.js +1817 -0
  73. package/dist/src/learning/domains/ConversationManager.js +53 -0
  74. package/dist/src/learning/domains/KnowledgeIngestor.js +238 -0
  75. package/dist/src/learning/domains/KnowledgeQuerier.js +187 -0
  76. package/dist/src/learning/domains/MasteryEngine.js +387 -0
  77. package/dist/src/learning/domains/MemoryPolicyManager.js +408 -0
  78. package/dist/src/learning/domains/QualityEvaluator.js +307 -0
  79. package/dist/src/learning/domains/TutorRouter.js +313 -0
  80. package/dist/src/learning/domains/index.js +33 -0
  81. package/dist/src/learning/domains/types.js +7 -0
  82. package/dist/src/learning/errors.js +29 -0
  83. package/dist/src/learning/evidenceContextAssembler.js +1176 -0
  84. package/dist/src/learning/evidenceContextAssembler.test.js +6332 -0
  85. package/dist/src/learning/graphContextAssembler.js +870 -0
  86. package/dist/src/learning/graphContextAssembler.test.js +1033 -0
  87. package/dist/src/learning/index.js +28 -0
  88. package/dist/src/learning/queryBackend.js +1898 -0
  89. package/dist/src/learning/queryBackend.test.js +955 -0
  90. package/dist/src/learning/ragContextPack.js +257 -0
  91. package/dist/src/learning/ragContextPack.test.js +160 -0
  92. package/dist/src/learning/ragPublicText.js +38 -0
  93. package/dist/src/learning/ragSufficiencyJudge.js +161 -0
  94. package/dist/src/learning/ragSufficiencyJudge.test.js +177 -0
  95. package/dist/src/learning/ragSufficiencyProviderJudge.js +227 -0
  96. package/dist/src/learning/ragSufficiencyProviderJudge.test.js +156 -0
  97. package/dist/src/learning/requestNormalization.js +198 -0
  98. package/dist/src/learning/runtimeCapability.js +4677 -0
  99. package/dist/src/learning/runtimeCapability.test.js +3635 -0
  100. package/dist/src/learning/store.js +1240 -0
  101. package/dist/src/learning/store.test.js +1126 -0
  102. package/dist/src/learning/tutorAdapter.js +2 -0
  103. package/dist/src/learning/types.js +2 -0
  104. package/dist/src/learning/vectorAccelerationAdapter.js +942 -0
  105. package/dist/src/learning/vectorAccelerationAdapter.test.js +382 -0
  106. package/dist/src/lfs.asset.policy.contract.test.js +153 -0
  107. package/dist/src/license.policy.contract.test.js +66 -0
  108. package/dist/src/memory/MemoryGovernance.js +74 -0
  109. package/dist/src/memory/MemoryGovernance.test.js +46 -0
  110. package/dist/src/memory/types.js +2 -0
  111. package/dist/src/mermaid.frontend.guard.contract.test.js +77 -0
  112. package/dist/src/middleware/auth.js +17 -0
  113. package/dist/src/middleware/body-parser.js +45 -0
  114. package/dist/src/middleware/cors.js +44 -0
  115. package/dist/src/middleware/index.js +21 -0
  116. package/dist/src/middleware/request-trace.js +96 -0
  117. package/dist/src/notemd/AppConfigToml.js +6 -4
  118. package/dist/src/notemd/MermaidProcessor.js +400 -50
  119. package/dist/src/notemd/NotemdService.js +498 -13
  120. package/dist/src/notemd/PromptManager.js +15 -0
  121. package/dist/src/notemd/cli/commands.js +357 -0
  122. package/dist/src/notemd/cli/dispatcher.js +225 -0
  123. package/dist/src/notemd/cli/index.js +169 -0
  124. package/dist/src/notemd/cli/parser.js +68 -0
  125. package/dist/src/notemd/cli/types.js +2 -0
  126. package/dist/src/notemd/constants.js +43 -0
  127. package/dist/src/notemd/diagram/diagramGenerationService.js +78 -0
  128. package/dist/src/notemd/diagram/diagramSpec.js +79 -0
  129. package/dist/src/notemd/diagram/diagramSpecResponseParser.js +131 -0
  130. package/dist/src/notemd/diagram/intent.js +95 -0
  131. package/dist/src/notemd/diagram/planner.js +71 -0
  132. package/dist/src/notemd/diagram/prompts/diagramSpecPrompt.js +42 -0
  133. package/dist/src/notemd/diagram/types.js +18 -0
  134. package/dist/src/notemd/index.js +26 -0
  135. package/dist/src/notemd/operations/capabilityManifest.js +23 -0
  136. package/dist/src/notemd/operations/cliContracts.js +17 -0
  137. package/dist/src/notemd/operations/configProfileCommands.js +85 -0
  138. package/dist/src/notemd/operations/registry.contract.test.js +95 -0
  139. package/dist/src/notemd/operations/registry.js +991 -0
  140. package/dist/src/notemd/operations/types.js +2 -0
  141. package/dist/src/notemd/providerDiagnostics.js +220 -0
  142. package/dist/src/notemd/providerProfiles.js +42 -0
  143. package/dist/src/notemd/providerTemplates.js +231 -0
  144. package/dist/src/notemd/search/DuckDuckGoProvider.js +39 -0
  145. package/dist/src/notemd/search/SearchManager.js +13 -0
  146. package/dist/src/notemd/search/SearchProvider.js +2 -0
  147. package/dist/src/notemd/search/TavilyProvider.js +44 -0
  148. package/dist/src/notemd.agent.manifest.test.js +85 -0
  149. package/dist/src/notemd.api.contract.test.js +14 -1
  150. package/dist/src/notemd.app_config_toml.test.js +2 -1
  151. package/dist/src/notemd.batch.workflow.test.js +117 -0
  152. package/dist/src/notemd.cli.e2e.test.js +136 -0
  153. package/dist/src/notemd.core.test.js +51 -0
  154. package/dist/src/notemd.diagram.pipeline.test.js +233 -0
  155. package/dist/src/notemd.providerTemplates.test.js +34 -0
  156. package/dist/src/notemd.server.integration.test.js +143 -35
  157. package/dist/src/notemd.workflow.pipeline.test.js +162 -0
  158. package/dist/src/pathbridge.handshake.contract.test.js +16 -2
  159. package/dist/src/pathmode.background.contract.test.js +69 -0
  160. package/dist/src/pathmode.settings.api.contract.test.js +9 -0
  161. package/dist/src/pkg.sidecar.contract.test.js +9 -3
  162. package/dist/src/platform/ExportProfile.js +58 -0
  163. package/dist/src/platform/PlatformCapabilities.js +45 -0
  164. package/dist/src/platform/PlatformCapabilities.test.js +30 -0
  165. package/dist/src/platform/RenderMaterializer.js +33 -0
  166. package/dist/src/platform/RenderMaterializer.test.js +32 -0
  167. package/dist/src/query_backend.external_http.integration.test.js +410 -0
  168. package/dist/src/reader_renderer.js +404 -3
  169. package/dist/src/reader_renderer.test.js +87 -0
  170. package/dist/src/release.godot.mirror.contract.test.js +73 -0
  171. package/dist/src/resources/ResourceRegistry.js +223 -0
  172. package/dist/src/resources/ResourceRegistry.test.js +61 -0
  173. package/dist/src/resources/types.js +2 -0
  174. package/dist/src/routes/agentWorkspaceDiagnostics.js +173 -0
  175. package/dist/src/routes/data.js +267 -0
  176. package/dist/src/routes/diagnostics.js +51 -0
  177. package/dist/src/routes/index.js +23 -0
  178. package/dist/src/routes/knowledge.js +968 -0
  179. package/dist/src/routes/markdown.js +287 -0
  180. package/dist/src/routes/notemd.js +565 -0
  181. package/dist/src/routes/registry.contract.test.js +130 -0
  182. package/dist/src/routes/render.js +285 -0
  183. package/dist/src/routes/runtimeRunbookRouteOps.js +149 -0
  184. package/dist/src/routes/runtimeRunbookRouteOps.test.js +194 -0
  185. package/dist/src/routes/settings.js +6 -0
  186. package/dist/src/routes/staticFiles.js +94 -0
  187. package/dist/src/routes/types.js +2 -0
  188. package/dist/src/runtime.transport.adapter.contract.test.js +81 -0
  189. package/dist/src/server.js +11090 -1549
  190. package/dist/src/server.migration.test.js +193 -21
  191. package/dist/src/server.port.fallback.contract.test.js +63 -0
  192. package/dist/src/session/SessionStateStore.js +81 -0
  193. package/dist/src/session/SessionStateStore.test.js +58 -0
  194. package/dist/src/session/types.js +2 -0
  195. package/dist/src/settings.runtime.contract.test.js +50 -0
  196. package/dist/src/shared/types.contract.test.js +107 -0
  197. package/dist/src/shared/types.js +22 -0
  198. package/dist/src/sidecar.replacement.boundary.contract.test.js +128 -0
  199. package/dist/src/sidecar.supply.readiness.contract.test.js +144 -0
  200. package/dist/src/source_manager.loadflow.test.js +46 -0
  201. package/dist/src/startup.layout.snapshot.contract.test.js +57 -0
  202. package/dist/src/tauri.frontend.build.contract.test.js +60 -0
  203. package/dist/src/tauri.sidecar.cleanup.contract.test.js +21 -0
  204. package/dist/src/utils/RuntimePaths.js +4 -13
  205. package/dist/src/utils/platform.js +153 -0
  206. package/dist/src/workflows/WorkflowArtifactStore.js +96 -0
  207. package/dist/src/workflows/WorkflowArtifactStore.test.js +80 -0
  208. package/dist/src/workflows/types.js +2 -0
  209. package/dist/src/workspace/WorkspaceRegistry.js +122 -0
  210. package/dist/src/workspace/WorkspaceRegistry.test.js +29 -0
  211. package/dist/src/workspace/types.js +2 -0
  212. package/package.json +61 -10
@@ -0,0 +1,33 @@
1
+ (function () {
2
+ function normalizeText(value) {
3
+ return String(value == null ? '' : value).replace(/\s+/g, ' ').trim();
4
+ }
5
+
6
+ function resolveDoubleClickAction(input) {
7
+ const currentAnchorId = normalizeText(input && input.currentAnchorId);
8
+ const clickedNodeId = normalizeText(input && input.clickedNodeId);
9
+ if (!clickedNodeId) {
10
+ return {
11
+ action: 'noop',
12
+ clickedNodeId: '',
13
+ currentAnchorId,
14
+ };
15
+ }
16
+ if (currentAnchorId && currentAnchorId === clickedNodeId) {
17
+ return {
18
+ action: 'open-reader',
19
+ clickedNodeId,
20
+ currentAnchorId,
21
+ };
22
+ }
23
+ return {
24
+ action: 'switch-focus',
25
+ clickedNodeId,
26
+ currentAnchorId,
27
+ };
28
+ }
29
+
30
+ window.NoteConnectionFocusModeInteractions = {
31
+ resolveDoubleClickAction,
32
+ };
33
+ }());
@@ -0,0 +1,540 @@
1
+ (function () {
2
+ const NODE_WIDTH = 140;
3
+ const NODE_HEIGHT = 50;
4
+ const NODE_PADDING_X = 24;
5
+ const NODE_PADDING_Y = 24;
6
+ const SURFACE_PADDING = 120;
7
+ const MIN_SURFACE_WIDTH = 760;
8
+ const MIN_SURFACE_HEIGHT = 460;
9
+
10
+ function escapeHtml(value) {
11
+ return String(value == null ? '' : value)
12
+ .replace(/&/g, '&')
13
+ .replace(/</g, '&lt;')
14
+ .replace(/>/g, '&gt;')
15
+ .replace(/"/g, '&quot;')
16
+ .replace(/'/g, '&#39;');
17
+ }
18
+
19
+ function normalizeText(value) {
20
+ return String(value == null ? '' : value).replace(/\s+/g, ' ').trim();
21
+ }
22
+
23
+ function normalizeBoolean(value) {
24
+ return value === true || value === 'true' || value === 1 || value === '1';
25
+ }
26
+
27
+ function normalizeTextList(value) {
28
+ return Array.isArray(value)
29
+ ? value.map((item) => normalizeText(item)).filter(Boolean)
30
+ : [];
31
+ }
32
+
33
+ function normalizeNode(rawNode) {
34
+ const id = normalizeText(rawNode && (rawNode.id || rawNode.nodeId || rawNode.key));
35
+ const x = Number(rawNode && rawNode.x);
36
+ const y = Number(rawNode && rawNode.y);
37
+ if (!id || !Number.isFinite(x) || !Number.isFinite(y)) {
38
+ return null;
39
+ }
40
+ return {
41
+ id,
42
+ label: normalizeText(rawNode && (rawNode.label || rawNode.title || rawNode.name || id)) || id,
43
+ x,
44
+ y,
45
+ isSpine: normalizeBoolean(rawNode && rawNode.isSpine),
46
+ hasPrereqs: normalizeBoolean(rawNode && rawNode.hasPrereqs),
47
+ isExpanded: normalizeBoolean(rawNode && rawNode.isExpanded),
48
+ inDegree: Number(rawNode && rawNode.inDegree),
49
+ outDegree: Number(rawNode && rawNode.outDegree),
50
+ inDegreeNames: normalizeTextList(rawNode && rawNode.inDegreeNames),
51
+ outDegreeNames: normalizeTextList(rawNode && rawNode.outDegreeNames),
52
+ inDegreeIds: normalizeTextList(rawNode && rawNode.inDegreeIds),
53
+ outDegreeIds: normalizeTextList(rawNode && rawNode.outDegreeIds),
54
+ };
55
+ }
56
+
57
+ function normalizeEdge(rawEdge) {
58
+ const from = normalizeText(rawEdge && (rawEdge.from || rawEdge.source || rawEdge.sourceId));
59
+ const to = normalizeText(rawEdge && (rawEdge.to || rawEdge.target || rawEdge.targetId));
60
+ if (!from || !to) {
61
+ return null;
62
+ }
63
+ return { from, to };
64
+ }
65
+
66
+ function normalizeHull(rawHull, nodeIds) {
67
+ const groupNodeId = normalizeText(rawHull && rawHull.groupNodeId);
68
+ const memberIds = Array.isArray(rawHull && rawHull.memberIds)
69
+ ? rawHull.memberIds.map((id) => normalizeText(id)).filter((id) => id && nodeIds.has(id))
70
+ : [];
71
+ if (!groupNodeId || memberIds.length <= 0) {
72
+ return null;
73
+ }
74
+ return { groupNodeId, memberIds };
75
+ }
76
+
77
+ function createHullMap(hulls) {
78
+ const hullMap = new Map();
79
+ hulls.forEach((hull) => {
80
+ hullMap.set(hull.groupNodeId, hull.memberIds.slice());
81
+ });
82
+ return hullMap;
83
+ }
84
+
85
+ function collectValidHullMembers(hullMap, rootId) {
86
+ const members = [];
87
+ const visited = new Set();
88
+ const stack = [rootId];
89
+ while (stack.length > 0) {
90
+ const current = stack.pop();
91
+ if (!current || visited.has(current)) {
92
+ continue;
93
+ }
94
+ visited.add(current);
95
+ if (!hullMap.has(current)) {
96
+ continue;
97
+ }
98
+ hullMap.get(current).forEach((memberId) => {
99
+ if (!memberId || memberId === current || visited.has(memberId)) {
100
+ return;
101
+ }
102
+ members.push(memberId);
103
+ stack.push(memberId);
104
+ });
105
+ }
106
+ return Array.from(new Set(members));
107
+ }
108
+
109
+ function resolveActiveHullRoot(layout, hoveredNodeId) {
110
+ const rawNodes = Array.isArray(layout && layout.nodes) ? layout.nodes : [];
111
+ const nodeIds = new Set(rawNodes.map((node) => normalizeText(node && (node.id || node.nodeId || node.key))).filter(Boolean));
112
+ const hulls = (Array.isArray(layout && layout.hulls) ? layout.hulls : [])
113
+ .map((hull) => normalizeHull(hull, nodeIds))
114
+ .filter(Boolean);
115
+ if (hulls.length <= 0) {
116
+ return '';
117
+ }
118
+ const hullMap = createHullMap(hulls);
119
+ let largestRootId = '';
120
+ let largestDescendantCount = -1;
121
+ hulls.forEach((hull) => {
122
+ const descendants = collectValidHullMembers(hullMap, hull.groupNodeId);
123
+ if (descendants.length > largestDescendantCount) {
124
+ largestDescendantCount = descendants.length;
125
+ largestRootId = hull.groupNodeId;
126
+ }
127
+ });
128
+ const hoveredId = normalizeText(hoveredNodeId);
129
+ if (!hoveredId) {
130
+ return largestRootId;
131
+ }
132
+ let smallestRootId = '';
133
+ let smallestDescendantCount = Number.MAX_SAFE_INTEGER;
134
+ hulls.forEach((hull) => {
135
+ const descendants = collectValidHullMembers(hullMap, hull.groupNodeId);
136
+ if ((hull.groupNodeId === hoveredId || descendants.includes(hoveredId)) && descendants.length < smallestDescendantCount) {
137
+ smallestDescendantCount = descendants.length;
138
+ smallestRootId = hull.groupNodeId;
139
+ }
140
+ });
141
+ return smallestRootId || largestRootId;
142
+ }
143
+
144
+ function cross(origin, left, right) {
145
+ return (left.x - origin.x) * (right.y - origin.y) - (left.y - origin.y) * (right.x - origin.x);
146
+ }
147
+
148
+ function convexHull(points) {
149
+ const sorted = points
150
+ .filter((point) => Number.isFinite(point.x) && Number.isFinite(point.y))
151
+ .sort((left, right) => left.x === right.x ? left.y - right.y : left.x - right.x);
152
+ if (sorted.length <= 2) {
153
+ return sorted;
154
+ }
155
+ const lower = [];
156
+ sorted.forEach((point) => {
157
+ while (lower.length >= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], point) <= 0) {
158
+ lower.pop();
159
+ }
160
+ lower.push(point);
161
+ });
162
+ const upper = [];
163
+ for (let index = sorted.length - 1; index >= 0; index -= 1) {
164
+ const point = sorted[index];
165
+ while (upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], point) <= 0) {
166
+ upper.pop();
167
+ }
168
+ upper.push(point);
169
+ }
170
+ upper.pop();
171
+ lower.pop();
172
+ return lower.concat(upper);
173
+ }
174
+
175
+ function buildHullPolygonPoints(memberIds, nodeById, edges) {
176
+ const memberSet = new Set(memberIds);
177
+ const rx = (NODE_WIDTH * 0.5) + NODE_PADDING_X;
178
+ const ry = (NODE_HEIGHT * 0.5) + NODE_PADDING_Y;
179
+ const points = [];
180
+ memberIds.forEach((nodeId) => {
181
+ const node = nodeById.get(nodeId);
182
+ if (!node) {
183
+ return;
184
+ }
185
+ points.push(
186
+ { x: node.projectedX - rx, y: node.projectedY - ry },
187
+ { x: node.projectedX + rx, y: node.projectedY - ry },
188
+ { x: node.projectedX + rx, y: node.projectedY + ry },
189
+ { x: node.projectedX - rx, y: node.projectedY + ry }
190
+ );
191
+ });
192
+ edges.forEach((edge) => {
193
+ if (!memberSet.has(edge.from) || !memberSet.has(edge.to)) {
194
+ return;
195
+ }
196
+ const fromNode = nodeById.get(edge.from);
197
+ const toNode = nodeById.get(edge.to);
198
+ if (!fromNode || !toNode) {
199
+ return;
200
+ }
201
+ const dx = toNode.projectedX - fromNode.projectedX;
202
+ const dy = toNode.projectedY - fromNode.projectedY;
203
+ const length = Math.sqrt((dx * dx) + (dy * dy)) || 1;
204
+ const perpX = (-dy / length) * ry * 0.8;
205
+ const perpY = (dx / length) * ry * 0.8;
206
+ points.push(
207
+ { x: fromNode.projectedX + perpX, y: fromNode.projectedY + perpY },
208
+ { x: fromNode.projectedX - perpX, y: fromNode.projectedY - perpY },
209
+ { x: toNode.projectedX - perpX, y: toNode.projectedY - perpY },
210
+ { x: toNode.projectedX + perpX, y: toNode.projectedY + perpY }
211
+ );
212
+ });
213
+ return convexHull(points);
214
+ }
215
+
216
+ function projectTreeLayout(layout, options = {}) {
217
+ const currentId = normalizeText(options.currentId || options.targetId || layout && (layout.currentId || layout.targetId));
218
+ const completedIds = new Set((Array.isArray(options.completedIds) ? options.completedIds : [])
219
+ .map((id) => normalizeText(id))
220
+ .filter(Boolean));
221
+ const nodes = (Array.isArray(layout && layout.nodes) ? layout.nodes : [])
222
+ .map(normalizeNode)
223
+ .filter(Boolean);
224
+ if (nodes.length <= 0) {
225
+ return null;
226
+ }
227
+ const nodeIds = new Set(nodes.map((node) => node.id));
228
+ const edges = (Array.isArray(layout && layout.edges) ? layout.edges : [])
229
+ .map(normalizeEdge)
230
+ .filter((edge) => edge && nodeIds.has(edge.from) && nodeIds.has(edge.to));
231
+ const hulls = (Array.isArray(layout && layout.hulls) ? layout.hulls : [])
232
+ .map((hull) => normalizeHull(hull, nodeIds))
233
+ .filter(Boolean);
234
+ const minX = Math.min(...nodes.map((node) => node.x));
235
+ const maxX = Math.max(...nodes.map((node) => node.x));
236
+ const minY = Math.min(...nodes.map((node) => node.y));
237
+ const maxY = Math.max(...nodes.map((node) => node.y));
238
+ const surfaceWidth = Math.max(MIN_SURFACE_WIDTH, (maxX - minX) + (SURFACE_PADDING * 2));
239
+ const surfaceHeight = Math.max(MIN_SURFACE_HEIGHT, (maxY - minY) + (SURFACE_PADDING * 2));
240
+ const projectedNodes = nodes.map((node) => ({
241
+ ...node,
242
+ projectedX: node.x - minX + SURFACE_PADDING,
243
+ projectedY: node.y - minY + SURFACE_PADDING,
244
+ isCurrent: node.id === currentId,
245
+ isCompleted: completedIds.has(node.id),
246
+ }));
247
+ const nodeById = new Map(projectedNodes.map((node) => [node.id, node]));
248
+ const currentNode = currentId ? nodeById.get(currentId) : null;
249
+ const highlightIds = new Set();
250
+ if (currentId) {
251
+ highlightIds.add(currentId);
252
+ edges.forEach((edge) => {
253
+ if (edge.to === currentId) {
254
+ highlightIds.add(edge.from);
255
+ }
256
+ });
257
+ }
258
+ const hullMap = createHullMap(hulls);
259
+ const activeHullRootId = resolveActiveHullRoot({ nodes: projectedNodes, hulls }, options.hoveredNodeId);
260
+ const projectedHulls = hulls.map((hull) => {
261
+ const memberIds = collectValidHullMembers(hullMap, hull.groupNodeId)
262
+ .filter((nodeId) => nodeById.has(nodeId));
263
+ const polygon = buildHullPolygonPoints(memberIds, nodeById, edges);
264
+ return {
265
+ ...hull,
266
+ memberIds,
267
+ polygon,
268
+ isActive: hull.groupNodeId === activeHullRootId,
269
+ };
270
+ }).filter((hull) => hull.memberIds.length > 0 && hull.polygon.length >= 3);
271
+ return {
272
+ currentId,
273
+ completedIds: Array.from(completedIds),
274
+ nodes: projectedNodes,
275
+ edges,
276
+ hulls: projectedHulls,
277
+ activeHullRootId,
278
+ surfaceWidth,
279
+ surfaceHeight,
280
+ currentX: currentNode ? currentNode.projectedX : 0,
281
+ currentY: currentNode ? currentNode.projectedY : 0,
282
+ focusModeEnabled: options.focusModeEnabled !== false,
283
+ };
284
+ }
285
+
286
+ function buildBezierPath(fromNode, toNode) {
287
+ const primaryDistance = (toNode.projectedX - fromNode.projectedX) * 0.5;
288
+ if (Math.abs(primaryDistance * 2) > 300) {
289
+ return '';
290
+ }
291
+ const cp1x = fromNode.projectedX + primaryDistance;
292
+ const cp1y = fromNode.projectedY;
293
+ const cp2x = toNode.projectedX - primaryDistance;
294
+ const cp2y = toNode.projectedY;
295
+ return [
296
+ 'M', fromNode.projectedX.toFixed(2), fromNode.projectedY.toFixed(2),
297
+ 'C', cp1x.toFixed(2), cp1y.toFixed(2),
298
+ cp2x.toFixed(2), cp2y.toFixed(2),
299
+ toNode.projectedX.toFixed(2), toNode.projectedY.toFixed(2),
300
+ ].join(' ');
301
+ }
302
+
303
+ function wrapNodeLabel(label) {
304
+ const words = normalizeText(label).split(/\s+/).filter(Boolean);
305
+ if (words.length <= 0) {
306
+ return [];
307
+ }
308
+ const lines = [];
309
+ let currentLine = '';
310
+ const maxChars = 16;
311
+ words.forEach((word) => {
312
+ const candidate = currentLine ? `${currentLine} ${word}` : word;
313
+ if (candidate.length > maxChars && currentLine) {
314
+ lines.push(currentLine);
315
+ currentLine = word;
316
+ } else {
317
+ currentLine = candidate;
318
+ }
319
+ });
320
+ if (currentLine) {
321
+ lines.push(currentLine);
322
+ }
323
+ if (lines.length <= 2) {
324
+ return lines;
325
+ }
326
+ return [lines[0], `${lines.slice(1).join(' ').slice(0, maxChars - 1)}...`];
327
+ }
328
+
329
+ function buildNodeLabelHtml(label) {
330
+ const lines = wrapNodeLabel(label);
331
+ if (lines.length <= 0) {
332
+ return '';
333
+ }
334
+ return lines.map((line) => `<span class="agent-godot-future-path-node-label-line">${escapeHtml(line)}</span>`).join('');
335
+ }
336
+
337
+ function buildNodeHoverHtml(node) {
338
+ const inNames = node.inDegreeNames.slice(0, 4);
339
+ const outNames = node.outDegreeNames.slice(0, 4);
340
+ const inCount = Number.isFinite(node.inDegree) ? node.inDegree : node.inDegreeNames.length;
341
+ const outCount = Number.isFinite(node.outDegree) ? node.outDegree : node.outDegreeNames.length;
342
+ const inText = inNames.length > 0 ? inNames.join(', ') : 'none';
343
+ const outText = outNames.length > 0 ? outNames.join(', ') : 'none';
344
+ return `
345
+ <span class="agent-godot-future-path-node-popover" aria-hidden="true">
346
+ <strong>${escapeHtml(node.label)}</strong>
347
+ <span>${escapeHtml(`In ${inCount} / Out ${outCount}`)}</span>
348
+ <span>${escapeHtml(`<- ${inText}`)}</span>
349
+ <span>${escapeHtml(`-> ${outText}`)}</span>
350
+ </span>
351
+ `;
352
+ }
353
+
354
+ function buildUnavailableHtml(options = {}) {
355
+ const title = normalizeText(options.targetLabel) || 'Future Path';
356
+ const message = normalizeText(options.unavailableLabel) || 'Godot Future Path target is unavailable.';
357
+ const reason = normalizeText(options.reason);
358
+ return `
359
+ <div
360
+ class="agent-godot-future-path-shell"
361
+ data-agent-godot-future-path-shell="true"
362
+ data-agent-godot-future-path-hosted="true"
363
+ data-godot-tree-renderer="false"
364
+ >
365
+ <div class="agent-godot-future-path-title">${escapeHtml(title)}</div>
366
+ <div class="agent-godot-future-path-status" data-agent-godot-future-path-status="true">
367
+ ${escapeHtml(message)}${reason ? ` (${escapeHtml(reason)})` : ''}
368
+ </div>
369
+ </div>
370
+ `;
371
+ }
372
+
373
+ function buildSurfaceHtml(input = {}) {
374
+ const projection = projectTreeLayout(input.treeLayout || input.layout, {
375
+ currentId: input.currentId || input.targetId,
376
+ targetId: input.targetId,
377
+ completedIds: input.completedIds,
378
+ hoveredNodeId: input.hoveredNodeId,
379
+ focusModeEnabled: input.focusModeEnabled !== false,
380
+ });
381
+ if (!projection) {
382
+ return buildUnavailableHtml(input);
383
+ }
384
+ const selectedNodeId = normalizeText(input.selectedNodeId);
385
+ const lastSignal = input.lastSignal && typeof input.lastSignal === 'object'
386
+ ? normalizeText(input.lastSignal.signal)
387
+ : normalizeText(input.lastSignal);
388
+ const nodeById = new Map(projection.nodes.map((node) => [node.id, node]));
389
+ const edgeHtml = projection.edges.map((edge) => {
390
+ const fromNode = nodeById.get(edge.from);
391
+ const toNode = nodeById.get(edge.to);
392
+ if (!fromNode || !toNode) {
393
+ return '';
394
+ }
395
+ const path = buildBezierPath(fromNode, toNode);
396
+ if (!path) {
397
+ return '';
398
+ }
399
+ const bright = edge.to === projection.currentId;
400
+ return `
401
+ <path
402
+ class="agent-godot-future-path-edge${bright ? ' agent-godot-future-path-edge--active' : ''}"
403
+ d="${path}"
404
+ data-godot-tree-edge-from="${escapeHtml(edge.from)}"
405
+ data-godot-tree-edge-to="${escapeHtml(edge.to)}"
406
+ ></path>
407
+ `;
408
+ }).join('');
409
+ const hullHtml = projection.hulls.map((hull) => `
410
+ <polygon
411
+ class="agent-godot-future-path-hull${hull.isActive ? ' agent-godot-future-path-hull--active' : ''}"
412
+ points="${hull.polygon.map((point) => `${point.x.toFixed(2)},${point.y.toFixed(2)}`).join(' ')}"
413
+ data-godot-tree-hull-root="${escapeHtml(hull.groupNodeId)}"
414
+ data-godot-tree-hull-members="${escapeHtml(hull.memberIds.join('|'))}"
415
+ ></polygon>
416
+ `).join('');
417
+ const nodeHtml = projection.nodes.map((node) => {
418
+ const highlight = !projection.focusModeEnabled || !projection.currentId || projection.edges.some((edge) => (
419
+ edge.to === projection.currentId && edge.from === node.id
420
+ )) || node.id === projection.currentId;
421
+ const classes = [
422
+ 'agent-godot-future-path-node',
423
+ 'agent-godot-tree-node',
424
+ node.isSpine ? 'agent-godot-future-path-node--spine' : 'agent-godot-future-path-node--tributary',
425
+ node.isCurrent ? 'agent-godot-future-path-node--current' : '',
426
+ node.isCompleted ? 'agent-godot-future-path-node--completed' : '',
427
+ node.isExpanded ? 'agent-godot-future-path-node--expanded' : '',
428
+ node.id === selectedNodeId ? 'agent-godot-future-path-node--selected' : '',
429
+ !highlight ? 'agent-godot-future-path-node--dimmed' : '',
430
+ ].filter(Boolean).join(' ');
431
+ return `
432
+ <button
433
+ type="button"
434
+ class="${classes}"
435
+ data-godot-tree-node-id="${escapeHtml(node.id)}"
436
+ data-agent-future-path-node-id="${escapeHtml(node.id)}"
437
+ data-agent-future-path-node-spine="${node.isSpine ? 'true' : 'false'}"
438
+ data-agent-future-path-node-has-prereqs="${node.hasPrereqs ? 'true' : 'false'}"
439
+ data-agent-future-path-node-expanded="${node.isExpanded ? 'true' : 'false'}"
440
+ data-godot-tree-node-current="${node.isCurrent ? 'true' : 'false'}"
441
+ data-godot-tree-node-spine="${node.isSpine ? 'true' : 'false'}"
442
+ data-godot-tree-node-has-prereqs="${node.hasPrereqs ? 'true' : 'false'}"
443
+ data-godot-tree-node-expanded="${node.isExpanded ? 'true' : 'false'}"
444
+ data-godot-tree-node-in-count="${Number.isFinite(node.inDegree) ? String(node.inDegree) : String(node.inDegreeNames.length)}"
445
+ data-godot-tree-node-out-count="${Number.isFinite(node.outDegree) ? String(node.outDegree) : String(node.outDegreeNames.length)}"
446
+ style="left: ${node.projectedX.toFixed(2)}px; top: ${node.projectedY.toFixed(2)}px;"
447
+ title="${escapeHtml(node.label)}"
448
+ aria-label="${escapeHtml(node.label)}"
449
+ >
450
+ <span class="agent-godot-future-path-node-label">${buildNodeLabelHtml(node.label)}</span>
451
+ ${node.hasPrereqs && node.isSpine ? `
452
+ <span
453
+ class="agent-godot-future-path-node-badge"
454
+ data-godot-tree-expansion-badge="true"
455
+ aria-hidden="true"
456
+ >${node.isExpanded ? '-' : '+'}</span>
457
+ ` : ''}
458
+ ${buildNodeHoverHtml(node)}
459
+ </button>
460
+ `;
461
+ }).join('');
462
+ const title = normalizeText(input.targetLabel) || normalizeText(input.title) || normalizeText(input.targetId) || 'Future Path';
463
+ const status = normalizeText(input.statusLabel) || 'Godot Future Path requested: Diffusion / Core';
464
+ return `
465
+ <div
466
+ class="agent-godot-future-path-shell"
467
+ data-agent-godot-future-path-shell="true"
468
+ data-agent-godot-future-path-hosted="true"
469
+ data-godot-tree-renderer="true"
470
+ data-godot-tree-active-hull-root="${escapeHtml(projection.activeHullRootId)}"
471
+ data-godot-tree-selected-node-id="${escapeHtml(selectedNodeId)}"
472
+ data-godot-tree-last-signal="${escapeHtml(lastSignal)}"
473
+ >
474
+ <div class="agent-godot-future-path-header">
475
+ <div class="agent-godot-future-path-title">${escapeHtml(title)}</div>
476
+ <div class="agent-godot-future-path-status" data-agent-godot-future-path-status="true">
477
+ ${escapeHtml(status)}
478
+ </div>
479
+ </div>
480
+ <div
481
+ class="agent-godot-future-path-viewport"
482
+ data-godot-tree-viewport="true"
483
+ data-godot-tree-zoom="1"
484
+ data-godot-tree-pan-x="0"
485
+ data-godot-tree-pan-y="0"
486
+ data-godot-tree-auto-fit="pending"
487
+ >
488
+ <div
489
+ class="agent-godot-future-path-surface"
490
+ data-agent-godot-future-path-surface="true"
491
+ data-godot-tree-transform-target="true"
492
+ data-agent-godot-future-path-target-id="${escapeHtml(projection.currentId || input.targetId || '')}"
493
+ data-godot-tree-surface-width="${projection.surfaceWidth.toFixed(0)}"
494
+ data-godot-tree-surface-height="${projection.surfaceHeight.toFixed(0)}"
495
+ data-godot-tree-current-x="${projection.currentX.toFixed(2)}"
496
+ data-godot-tree-current-y="${projection.currentY.toFixed(2)}"
497
+ data-godot-tree-selected-node-id="${escapeHtml(selectedNodeId)}"
498
+ style="width: ${projection.surfaceWidth.toFixed(0)}px; height: ${projection.surfaceHeight.toFixed(0)}px;"
499
+ >
500
+ <svg
501
+ class="agent-godot-future-path-lines"
502
+ viewBox="0 0 ${projection.surfaceWidth.toFixed(0)} ${projection.surfaceHeight.toFixed(0)}"
503
+ preserveAspectRatio="xMinYMin meet"
504
+ aria-hidden="true"
505
+ >
506
+ ${hullHtml}
507
+ ${edgeHtml}
508
+ </svg>
509
+ ${nodeHtml}
510
+ </div>
511
+ </div>
512
+ </div>
513
+ `;
514
+ }
515
+
516
+ function updateActiveHullRoot(root, activeRootId) {
517
+ if (!root || typeof root.querySelectorAll !== 'function') {
518
+ return;
519
+ }
520
+ const normalizedRootId = normalizeText(activeRootId);
521
+ root.querySelectorAll('[data-godot-tree-hull-root]').forEach((hullNode) => {
522
+ const isActive = normalizeText(hullNode.getAttribute('data-godot-tree-hull-root')) === normalizedRootId;
523
+ hullNode.classList.toggle('agent-godot-future-path-hull--active', isActive);
524
+ });
525
+ const shell = root.matches && root.matches('[data-godot-tree-renderer="true"]')
526
+ ? root
527
+ : root.querySelector('[data-godot-tree-renderer="true"]');
528
+ if (shell) {
529
+ shell.setAttribute('data-godot-tree-active-hull-root', normalizedRootId);
530
+ }
531
+ }
532
+
533
+ window.NoteConnectionGodotFuturePathRenderer = {
534
+ projectTreeLayout,
535
+ buildSurfaceHtml,
536
+ buildUnavailableHtml,
537
+ resolveActiveHullRoot,
538
+ updateActiveHullRoot,
539
+ };
540
+ }());