noteconnection 1.7.0 → 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 (211) hide show
  1. package/LICENSE +674 -21
  2. package/README.md +242 -62
  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 +242 -62
  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 +2178 -62
  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 +2108 -130
  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 +393 -33
  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/source_manager.js +190 -21
  50. package/dist/src/frontend/styles.css +2720 -72
  51. package/dist/src/frontend/workbench_state.mjs +101 -0
  52. package/dist/src/frontend/workspace_panes.js +10168 -0
  53. package/dist/src/frontend.locale.contract.test.js +62 -0
  54. package/dist/src/godot.sidecar.bootstrap.contract.test.js +244 -0
  55. package/dist/src/indexing/IndexLifecycle.js +195 -0
  56. package/dist/src/indexing/IndexLifecycle.test.js +49 -0
  57. package/dist/src/indexing/SegmentBuilder.js +64 -0
  58. package/dist/src/indexing/UnitBuilder.js +48 -0
  59. package/dist/src/indexing/types.js +2 -0
  60. package/dist/src/knowledge.api.contract.test.js +170 -0
  61. package/dist/src/learning/KnowledgeLearningPlatform.js +10386 -0
  62. package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +327 -0
  63. package/dist/src/learning/KnowledgeLearningPlatform.program-f.test.js +99 -0
  64. package/dist/src/learning/KnowledgeLearningPlatform.test.js +2971 -0
  65. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +2974 -0
  66. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +3928 -0
  67. package/dist/src/learning/answerReleaseReview.js +4319 -0
  68. package/dist/src/learning/answerReleaseReview.test.js +2888 -0
  69. package/dist/src/learning/api.js +2 -0
  70. package/dist/src/learning/conversationComposer.js +1480 -0
  71. package/dist/src/learning/conversationComposer.test.js +1817 -0
  72. package/dist/src/learning/domains/ConversationManager.js +53 -0
  73. package/dist/src/learning/domains/KnowledgeIngestor.js +238 -0
  74. package/dist/src/learning/domains/KnowledgeQuerier.js +187 -0
  75. package/dist/src/learning/domains/MasteryEngine.js +387 -0
  76. package/dist/src/learning/domains/MemoryPolicyManager.js +408 -0
  77. package/dist/src/learning/domains/QualityEvaluator.js +307 -0
  78. package/dist/src/learning/domains/TutorRouter.js +313 -0
  79. package/dist/src/learning/domains/index.js +33 -0
  80. package/dist/src/learning/domains/types.js +7 -0
  81. package/dist/src/learning/errors.js +29 -0
  82. package/dist/src/learning/evidenceContextAssembler.js +1176 -0
  83. package/dist/src/learning/evidenceContextAssembler.test.js +6332 -0
  84. package/dist/src/learning/graphContextAssembler.js +870 -0
  85. package/dist/src/learning/graphContextAssembler.test.js +1033 -0
  86. package/dist/src/learning/index.js +28 -0
  87. package/dist/src/learning/queryBackend.js +1898 -0
  88. package/dist/src/learning/queryBackend.test.js +955 -0
  89. package/dist/src/learning/ragContextPack.js +257 -0
  90. package/dist/src/learning/ragContextPack.test.js +160 -0
  91. package/dist/src/learning/ragPublicText.js +38 -0
  92. package/dist/src/learning/ragSufficiencyJudge.js +161 -0
  93. package/dist/src/learning/ragSufficiencyJudge.test.js +177 -0
  94. package/dist/src/learning/ragSufficiencyProviderJudge.js +227 -0
  95. package/dist/src/learning/ragSufficiencyProviderJudge.test.js +156 -0
  96. package/dist/src/learning/requestNormalization.js +198 -0
  97. package/dist/src/learning/runtimeCapability.js +4677 -0
  98. package/dist/src/learning/runtimeCapability.test.js +3635 -0
  99. package/dist/src/learning/store.js +1240 -0
  100. package/dist/src/learning/store.test.js +1126 -0
  101. package/dist/src/learning/tutorAdapter.js +2 -0
  102. package/dist/src/learning/types.js +2 -0
  103. package/dist/src/learning/vectorAccelerationAdapter.js +942 -0
  104. package/dist/src/learning/vectorAccelerationAdapter.test.js +382 -0
  105. package/dist/src/lfs.asset.policy.contract.test.js +153 -0
  106. package/dist/src/license.policy.contract.test.js +66 -0
  107. package/dist/src/memory/MemoryGovernance.js +74 -0
  108. package/dist/src/memory/MemoryGovernance.test.js +46 -0
  109. package/dist/src/memory/types.js +2 -0
  110. package/dist/src/mermaid.frontend.guard.contract.test.js +77 -0
  111. package/dist/src/middleware/auth.js +17 -0
  112. package/dist/src/middleware/body-parser.js +45 -0
  113. package/dist/src/middleware/cors.js +44 -0
  114. package/dist/src/middleware/index.js +21 -0
  115. package/dist/src/middleware/request-trace.js +96 -0
  116. package/dist/src/notemd/AppConfigToml.js +6 -4
  117. package/dist/src/notemd/MermaidProcessor.js +400 -50
  118. package/dist/src/notemd/NotemdService.js +498 -13
  119. package/dist/src/notemd/PromptManager.js +15 -0
  120. package/dist/src/notemd/cli/commands.js +357 -0
  121. package/dist/src/notemd/cli/dispatcher.js +225 -0
  122. package/dist/src/notemd/cli/index.js +169 -0
  123. package/dist/src/notemd/cli/parser.js +68 -0
  124. package/dist/src/notemd/cli/types.js +2 -0
  125. package/dist/src/notemd/constants.js +43 -0
  126. package/dist/src/notemd/diagram/diagramGenerationService.js +78 -0
  127. package/dist/src/notemd/diagram/diagramSpec.js +79 -0
  128. package/dist/src/notemd/diagram/diagramSpecResponseParser.js +131 -0
  129. package/dist/src/notemd/diagram/intent.js +95 -0
  130. package/dist/src/notemd/diagram/planner.js +71 -0
  131. package/dist/src/notemd/diagram/prompts/diagramSpecPrompt.js +42 -0
  132. package/dist/src/notemd/diagram/types.js +18 -0
  133. package/dist/src/notemd/index.js +26 -0
  134. package/dist/src/notemd/operations/capabilityManifest.js +23 -0
  135. package/dist/src/notemd/operations/cliContracts.js +17 -0
  136. package/dist/src/notemd/operations/configProfileCommands.js +85 -0
  137. package/dist/src/notemd/operations/registry.contract.test.js +95 -0
  138. package/dist/src/notemd/operations/registry.js +991 -0
  139. package/dist/src/notemd/operations/types.js +2 -0
  140. package/dist/src/notemd/providerDiagnostics.js +220 -0
  141. package/dist/src/notemd/providerProfiles.js +42 -0
  142. package/dist/src/notemd/providerTemplates.js +231 -0
  143. package/dist/src/notemd/search/DuckDuckGoProvider.js +39 -0
  144. package/dist/src/notemd/search/SearchManager.js +13 -0
  145. package/dist/src/notemd/search/SearchProvider.js +2 -0
  146. package/dist/src/notemd/search/TavilyProvider.js +44 -0
  147. package/dist/src/notemd.agent.manifest.test.js +85 -0
  148. package/dist/src/notemd.api.contract.test.js +14 -1
  149. package/dist/src/notemd.app_config_toml.test.js +2 -1
  150. package/dist/src/notemd.batch.workflow.test.js +117 -0
  151. package/dist/src/notemd.cli.e2e.test.js +136 -0
  152. package/dist/src/notemd.core.test.js +51 -0
  153. package/dist/src/notemd.diagram.pipeline.test.js +233 -0
  154. package/dist/src/notemd.providerTemplates.test.js +34 -0
  155. package/dist/src/notemd.server.integration.test.js +143 -35
  156. package/dist/src/notemd.workflow.pipeline.test.js +162 -0
  157. package/dist/src/pathbridge.handshake.contract.test.js +16 -2
  158. package/dist/src/pathmode.background.contract.test.js +69 -0
  159. package/dist/src/pathmode.settings.api.contract.test.js +9 -0
  160. package/dist/src/pkg.sidecar.contract.test.js +9 -3
  161. package/dist/src/platform/ExportProfile.js +58 -0
  162. package/dist/src/platform/PlatformCapabilities.js +45 -0
  163. package/dist/src/platform/PlatformCapabilities.test.js +30 -0
  164. package/dist/src/platform/RenderMaterializer.js +33 -0
  165. package/dist/src/platform/RenderMaterializer.test.js +32 -0
  166. package/dist/src/query_backend.external_http.integration.test.js +410 -0
  167. package/dist/src/reader_renderer.js +404 -3
  168. package/dist/src/reader_renderer.test.js +87 -0
  169. package/dist/src/release.godot.mirror.contract.test.js +73 -0
  170. package/dist/src/resources/ResourceRegistry.js +223 -0
  171. package/dist/src/resources/ResourceRegistry.test.js +61 -0
  172. package/dist/src/resources/types.js +2 -0
  173. package/dist/src/routes/agentWorkspaceDiagnostics.js +173 -0
  174. package/dist/src/routes/data.js +267 -0
  175. package/dist/src/routes/diagnostics.js +51 -0
  176. package/dist/src/routes/index.js +23 -0
  177. package/dist/src/routes/knowledge.js +968 -0
  178. package/dist/src/routes/markdown.js +287 -0
  179. package/dist/src/routes/notemd.js +565 -0
  180. package/dist/src/routes/registry.contract.test.js +130 -0
  181. package/dist/src/routes/render.js +285 -0
  182. package/dist/src/routes/runtimeRunbookRouteOps.js +149 -0
  183. package/dist/src/routes/runtimeRunbookRouteOps.test.js +194 -0
  184. package/dist/src/routes/settings.js +6 -0
  185. package/dist/src/routes/staticFiles.js +94 -0
  186. package/dist/src/routes/types.js +2 -0
  187. package/dist/src/runtime.transport.adapter.contract.test.js +81 -0
  188. package/dist/src/server.js +11090 -1549
  189. package/dist/src/server.migration.test.js +193 -21
  190. package/dist/src/server.port.fallback.contract.test.js +63 -0
  191. package/dist/src/session/SessionStateStore.js +81 -0
  192. package/dist/src/session/SessionStateStore.test.js +58 -0
  193. package/dist/src/session/types.js +2 -0
  194. package/dist/src/settings.runtime.contract.test.js +50 -0
  195. package/dist/src/shared/types.contract.test.js +107 -0
  196. package/dist/src/shared/types.js +22 -0
  197. package/dist/src/sidecar.replacement.boundary.contract.test.js +128 -0
  198. package/dist/src/sidecar.supply.readiness.contract.test.js +144 -0
  199. package/dist/src/source_manager.loadflow.test.js +46 -0
  200. package/dist/src/startup.layout.snapshot.contract.test.js +57 -0
  201. package/dist/src/tauri.frontend.build.contract.test.js +60 -0
  202. package/dist/src/tauri.sidecar.cleanup.contract.test.js +21 -0
  203. package/dist/src/utils/RuntimePaths.js +4 -13
  204. package/dist/src/utils/platform.js +153 -0
  205. package/dist/src/workflows/WorkflowArtifactStore.js +96 -0
  206. package/dist/src/workflows/WorkflowArtifactStore.test.js +80 -0
  207. package/dist/src/workflows/types.js +2 -0
  208. package/dist/src/workspace/WorkspaceRegistry.js +122 -0
  209. package/dist/src/workspace/WorkspaceRegistry.test.js +29 -0
  210. package/dist/src/workspace/types.js +2 -0
  211. package/package.json +53 -10
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.normalizeMermaidDefinition = normalizeMermaidDefinition;
4
5
  exports.renderMathSvg = renderMathSvg;
5
6
  exports.renderMermaidSvg = renderMermaidSvg;
6
7
  exports.collectMermaidRenderStageSnapshots = collectMermaidRenderStageSnapshots;
@@ -90,6 +91,403 @@ const MERMAID_GLOBAL_BINDING_KEYS = [
90
91
  'Node',
91
92
  'getComputedStyle',
92
93
  ];
94
+ function normalizeMermaidLineBreaks(source) {
95
+ return String(source || '')
96
+ .replace(/\r\n?/g, '\n')
97
+ .replace(/<br\s*>/gi, '<br/>');
98
+ }
99
+ function stripWrappingDoubleQuotes(text) {
100
+ const trimmed = String(text || '').trim();
101
+ if (trimmed.length >= 2 && trimmed.startsWith('"') && trimmed.endsWith('"')) {
102
+ return trimmed.slice(1, -1);
103
+ }
104
+ return trimmed;
105
+ }
106
+ function normalizeMermaidQuotedNodeLabels(source) {
107
+ return String(source || "")
108
+ .split("\n")
109
+ .map((line) => {
110
+ const text = String(line || "");
111
+ const startPattern = /([A-Za-z_][A-Za-z0-9_]*)\["/g;
112
+ let result = "";
113
+ let cursor = 0;
114
+ let match;
115
+ while ((match = startPattern.exec(text)) !== null) {
116
+ const labelStart = match.index + match[0].length;
117
+ let labelEnd = -1;
118
+ for (let index = labelStart; index < text.length - 1; index += 1) {
119
+ if (text.charAt(index) === "\"" && text.charAt(index - 1) !== "\\" && text.charAt(index + 1) === "]") {
120
+ labelEnd = index;
121
+ break;
122
+ }
123
+ }
124
+ if (labelEnd < 0) {
125
+ continue;
126
+ }
127
+ result += text.slice(cursor, labelStart);
128
+ result += escapeMermaidQuotedNodeLabel(text.slice(labelStart, labelEnd));
129
+ result += "\"]";
130
+ cursor = labelEnd + 2;
131
+ startPattern.lastIndex = cursor;
132
+ }
133
+ return result + text.slice(cursor);
134
+ })
135
+ .join("\n");
136
+ }
137
+ function splitMermaidTopLevelStatements(source) {
138
+ const text = normalizeMermaidQuotedNodeLabels(normalizeMermaidLineBreaks(source))
139
+ .split('\n')
140
+ .map((line) => rewriteQuotedLabelAfterSemicolonLine(line) || line)
141
+ .join('\n');
142
+ let result = '';
143
+ let quote = false;
144
+ let squareDepth = 0;
145
+ let roundDepth = 0;
146
+ let curlyDepth = 0;
147
+ for (let index = 0; index < text.length; index += 1) {
148
+ const char = text.charAt(index);
149
+ if (char === '"' && text.charAt(index - 1) !== '\\') {
150
+ quote = !quote;
151
+ result += char;
152
+ continue;
153
+ }
154
+ if (!quote) {
155
+ if (char === '[')
156
+ squareDepth += 1;
157
+ else if (char === ']')
158
+ squareDepth = Math.max(0, squareDepth - 1);
159
+ else if (char === '(')
160
+ roundDepth += 1;
161
+ else if (char === ')')
162
+ roundDepth = Math.max(0, roundDepth - 1);
163
+ else if (char === '{')
164
+ curlyDepth += 1;
165
+ else if (char === '}')
166
+ curlyDepth = Math.max(0, curlyDepth - 1);
167
+ if (char === ';' && squareDepth === 0 && roundDepth === 0 && curlyDepth === 0) {
168
+ result += '\n';
169
+ continue;
170
+ }
171
+ }
172
+ result += char;
173
+ }
174
+ return result;
175
+ }
176
+ function rewriteQuotedLabelAfterSemicolonLine(line) {
177
+ if (!line.includes('-->')) {
178
+ return null;
179
+ }
180
+ const match = line.match(/^(.*?)\s*(-->)\s*(.*?);\s*"([^"\n]+)"\s*$/);
181
+ if (!match) {
182
+ return null;
183
+ }
184
+ const source = String(match[1] || '').trim();
185
+ const arrow = String(match[2] || '').trim();
186
+ const target = String(match[3] || '').trim();
187
+ const label = String(match[4] || '').trim();
188
+ if (!source || !target || !label) {
189
+ return null;
190
+ }
191
+ return `${source} -- "${label}" ${arrow} ${target};`;
192
+ }
193
+ function rewriteSingleDoubleDashLabelLine(line) {
194
+ const match = line.match(/^(.*?)\s*(?<!-)--(?!>|-)\s*"([^"\n]+)"\s*(?<!-)--(?!>|-)\s*(.+?)\s*;?\s*$/);
195
+ if (!match) {
196
+ return null;
197
+ }
198
+ const start = String(match[1] || '').trim();
199
+ const label = String(match[2] || '').trim();
200
+ const end = String(match[3] || '').trim();
201
+ if (!start || !label || !end || /^"/.test(end)) {
202
+ return null;
203
+ }
204
+ return `${start} -- "${label}" --> ${end};`;
205
+ }
206
+ function mergeDoubleArrowLabelLine(line) {
207
+ const match = line.match(/^(.*?)\s*--\s*"([^"\n]+)"\s*--\s*"([^"\n]+)"\s*(-->|---)\s*(.*)$/);
208
+ if (!match) {
209
+ return null;
210
+ }
211
+ const start = String(match[1] || '').trim();
212
+ const labelLeft = String(match[2] || '').trim();
213
+ const labelRight = String(match[3] || '').trim();
214
+ const arrow = String(match[4] || '').trim();
215
+ const end = String(match[5] || '').trim();
216
+ if (!start || !labelLeft || !labelRight || !end) {
217
+ return null;
218
+ }
219
+ return `${start} -- "${labelLeft}<br/>${labelRight}" ${arrow} ${end}`;
220
+ }
221
+ function quoteUnquotedEdgeLabelLine(line) {
222
+ const match = line.match(/^(.*?)\s*--\s*([^"\n][^>\n]*?)\s*-->\s*(.*)$/);
223
+ if (!match) {
224
+ return null;
225
+ }
226
+ const start = String(match[1] || '').trim();
227
+ const label = String(match[2] || '').trim();
228
+ const end = String(match[3] || '').trim();
229
+ if (!start || !label || !end) {
230
+ return null;
231
+ }
232
+ if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(label)
233
+ || /^[A-Za-z_][A-Za-z0-9_]*\s*[\[\(\{].*$/.test(label)
234
+ || /^["[{(]/.test(label)) {
235
+ return null;
236
+ }
237
+ return `${start} -- "${label}" --> ${end}`;
238
+ }
239
+ function normalizeSubgraphLine(line) {
240
+ const match = /^(\s*subgraph\s+)(.+)$/i.exec(line);
241
+ if (!match) {
242
+ return { next: line, changed: false };
243
+ }
244
+ const prefix = match[1];
245
+ const rawTitle = match[2].trim();
246
+ if (!rawTitle || rawTitle.startsWith('"') || rawTitle.startsWith("'")) {
247
+ return { next: line, changed: false };
248
+ }
249
+ if (/[\s()[\]{}:;,-]/.test(rawTitle)) {
250
+ return {
251
+ next: `${prefix}"${rawTitle.replace(/"/g, '\\"')}"`,
252
+ changed: true,
253
+ };
254
+ }
255
+ return { next: line, changed: false };
256
+ }
257
+ function splitIntermediateNodeLine(line) {
258
+ const match = line.match(/^(.*?)\s*(-->|---)\s*([A-Za-z_][A-Za-z0-9_]*)\s*(\[[^\]]+\]|\([^)]+\)|\{[^}]+\})\s*(-->|---)\s*(.*)$/);
259
+ if (!match) {
260
+ return null;
261
+ }
262
+ const start = String(match[1] || '').trim();
263
+ const leftArrow = String(match[2] || '').trim();
264
+ const nodeId = String(match[3] || '').trim();
265
+ const nodeShape = String(match[4] || '').trim();
266
+ const rightArrow = String(match[5] || '').trim();
267
+ const end = String(match[6] || '').trim();
268
+ if (!start || !nodeId || !nodeShape || !end) {
269
+ return null;
270
+ }
271
+ return [
272
+ `${start} ${leftArrow} ${nodeId}${nodeShape}`,
273
+ `${nodeId} ${rightArrow} ${end}`,
274
+ ];
275
+ }
276
+ function normalizeMermaidPipes(content) {
277
+ return String(content || '')
278
+ .replace(/\|""\|"/g, '')
279
+ .replace(/"\[\]"/g, '');
280
+ }
281
+ function fixExcessiveBrackets(content) {
282
+ return String(content || '')
283
+ .replace(/\]{3,}/g, ']')
284
+ .replace(/\[""\]/g, '')
285
+ .replace(/\["\]/g, ']')
286
+ .replace(/\[\/\["/g, '["')
287
+ .replace(/\["\/\]/g, '"]');
288
+ }
289
+ function normalizeMermaidComments(content) {
290
+ return String(content || '')
291
+ .split('\n')
292
+ .map((line) => {
293
+ const hashCommentMatch = line.match(/^(\s*[A-Za-z0-9_()[\]{}"'\s.-]+?)\s*-->\s*([A-Za-z0-9_()[\]{}"'\s.-]+?)\s*;\s*#(.*)$/);
294
+ if (hashCommentMatch) {
295
+ return `${hashCommentMatch[1].trim()} -- "${hashCommentMatch[3].trim()}" --> ${hashCommentMatch[2].trim()};`;
296
+ }
297
+ const percentCommentMatch = line.match(/^(\s*[A-Za-z0-9_()[\]{}"'\s.-]+?)\s*-->\s*([A-Za-z0-9_()[\]{}"'\s.-]+?)\s*;\s*%(.*)$/);
298
+ if (percentCommentMatch) {
299
+ return `${percentCommentMatch[1].trim()} -- "${percentCommentMatch[3].trim()}" --> ${percentCommentMatch[2].trim()};`;
300
+ }
301
+ const slashCommentMatch = line.match(/^(\s*[A-Za-z0-9_()[\]{}"'\s.-]+?)\s*-->\s*([A-Za-z0-9_()[\]{}"'\s.-]+?)\s*;\s*\/\/(.*)$/);
302
+ if (slashCommentMatch) {
303
+ return `${slashCommentMatch[1].trim()} -- "${slashCommentMatch[3].trim()}" --> ${slashCommentMatch[2].trim()};`;
304
+ }
305
+ return line;
306
+ })
307
+ .join('\n');
308
+ }
309
+ function fixDanglingBracketedNodeLabelLine(line) {
310
+ const match = line.match(/^(\s*[A-Za-z_][A-Za-z0-9_]*)\["([^"\n]*)\["\s*;?\s*$/);
311
+ if (!match) {
312
+ return null;
313
+ }
314
+ const nodeId = String(match[1] || '').trim();
315
+ const label = String(match[2] || '').trim();
316
+ if (!nodeId || !label) {
317
+ return null;
318
+ }
319
+ return `${nodeId}["${escapeMermaidLabel(label)}"]`;
320
+ }
321
+ function sanitizeMermaidIdentifier(rawValue, fallbackPrefix, counter) {
322
+ const raw = String(rawValue || '').trim();
323
+ const prefixedMatch = raw.match(/^([A-Za-z][A-Za-z0-9_]*)/);
324
+ if (prefixedMatch && prefixedMatch[1]) {
325
+ return prefixedMatch[1];
326
+ }
327
+ return `${fallbackPrefix}${counter}`;
328
+ }
329
+ function escapeMermaidLabel(rawValue) {
330
+ return String(rawValue || '')
331
+ .replace(/\\/g, '\\\\')
332
+ .replace(/"/g, '\\"')
333
+ .trim();
334
+ }
335
+ function escapeMermaidQuotedNodeLabel(rawValue) {
336
+ return String(rawValue || "")
337
+ .replace(/\\/g, "\\\\")
338
+ .replace(/"/g, "#quot;")
339
+ .trim();
340
+ }
341
+ function isMermaidControlLine(line) {
342
+ return /^\s*(?:graph|flowchart|subgraph|end|classDef|class|style|linkStyle|click|%%)\b/i.test(line);
343
+ }
344
+ function convertNoteLine(line, state) {
345
+ const directionalMatch = line.match(/^\s*note\s+(?:right|left|top|bottom)\s+of\s+([A-Za-z0-9_]+)\s*:\s*(.+)$/i);
346
+ if (directionalMatch) {
347
+ state.syntheticCounter += 1;
348
+ const noteId = `AutoNote${state.syntheticCounter}`;
349
+ const noteText = escapeMermaidLabel(stripWrappingDoubleQuotes(directionalMatch[2]));
350
+ return [
351
+ `${noteId}["${noteText}"]`,
352
+ `${directionalMatch[1]} -.- ${noteId}`,
353
+ ];
354
+ }
355
+ const targetedMatch = line.match(/^\s*note\s+([A-Za-z0-9_]+)\s+"(.+)"\s*$/i);
356
+ if (targetedMatch) {
357
+ state.syntheticCounter += 1;
358
+ const noteId = `AutoNote${state.syntheticCounter}`;
359
+ const noteText = escapeMermaidLabel(stripWrappingDoubleQuotes(targetedMatch[2]));
360
+ return [
361
+ `${noteId}["${noteText}"]`,
362
+ `${targetedMatch[1]} -.- ${noteId}`,
363
+ ];
364
+ }
365
+ return null;
366
+ }
367
+ function normalizeMermaidEdgeLabels(line) {
368
+ return String(line || '')
369
+ .replace(/--\s*"([^"\n]+)"\s*-->/g, '-->|$1|')
370
+ .replace(/--\s*"([^"\n]+)"\s*--\s*/g, ' -->|$1| ');
371
+ }
372
+ function normalizeMermaidHtmlLineBreakLabels(line) {
373
+ const text = String(line || '');
374
+ const arrowMatch = text.match(/^(.*?(?:-->|---|-\.->|\-.-))\s*([A-Za-z_][A-Za-z0-9_]*)\s+(.+?)\s*;?\s*$/);
375
+ if (!arrowMatch) {
376
+ return text;
377
+ }
378
+ const prefix = String(arrowMatch[1] || '');
379
+ const nodeId = String(arrowMatch[2] || '').trim();
380
+ const label = String(arrowMatch[3] || '').trim();
381
+ if (!nodeId || !label || !label.includes('<br/>')) {
382
+ return text;
383
+ }
384
+ if (/^[\[\(\{"]/.test(label)) {
385
+ return text;
386
+ }
387
+ if (/(?:-->|---|-\.->|\-.-)/.test(label)) {
388
+ return text;
389
+ }
390
+ return `${prefix} ${nodeId}["${escapeMermaidLabel(stripWrappingDoubleQuotes(label))}"]`;
391
+ }
392
+ function fixMalformedMermaidArrows(line) {
393
+ return String(line || '')
394
+ .replace(/--\|>/g, '-->')
395
+ .replace(/<--/g, '-->')
396
+ .replace(/-- >/g, '-->')
397
+ .replace(/--\s*"([^"\n]+)"\s*--\s*([A-Za-z_][A-Za-z0-9_]*)\s*;/g, '-- "$1" --> $2;');
398
+ }
399
+ function isMermaidErrorSvgMarkup(markup) {
400
+ const text = String(markup || '').toLowerCase();
401
+ if (!text) {
402
+ return false;
403
+ }
404
+ return (text.includes('syntax error in text') ||
405
+ text.includes('lexical error on line') ||
406
+ text.includes('parse error on line') ||
407
+ text.includes('mermaid version') ||
408
+ text.includes('class="error-icon"') ||
409
+ text.includes('id="error-icon"'));
410
+ }
411
+ function normalizeMermaidEndpoint(rawValue, state) {
412
+ const raw = String(rawValue || '').trim();
413
+ if (!raw)
414
+ return raw;
415
+ if (/^(?:\[|\{|\(|")/.test(raw))
416
+ return raw;
417
+ if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(raw))
418
+ return raw;
419
+ if (/^[A-Za-z_][A-Za-z0-9_]*\s*[\[\(\{].*$/.test(raw))
420
+ return raw;
421
+ let nodeId = state.labelToId.get(raw);
422
+ if (!nodeId) {
423
+ state.syntheticCounter += 1;
424
+ nodeId = sanitizeMermaidIdentifier(raw, 'AutoNode', state.syntheticCounter);
425
+ state.labelToId.set(raw, nodeId);
426
+ }
427
+ return `${nodeId}["${escapeMermaidLabel(raw)}"]`;
428
+ }
429
+ function normalizeMermaidEdgeLine(line, state) {
430
+ const next = normalizeMermaidEdgeLabels(line);
431
+ const match = /(.*?)(--(?:>|o|x)(?:\|[^|]*\|)?\s*)(.+)$/.exec(next);
432
+ if (!match) {
433
+ return next;
434
+ }
435
+ const left = String(match[1] || '');
436
+ const connector = String(match[2] || '');
437
+ const right = String(match[3] || '').trim();
438
+ if (!right) {
439
+ return next;
440
+ }
441
+ return `${left}${connector}${normalizeMermaidEndpoint(right, state)}`;
442
+ }
443
+ function applyLegacyMermaidRepairs(line, state) {
444
+ const subgraphNormalized = normalizeSubgraphLine(line);
445
+ let next = String(subgraphNormalized.next || '');
446
+ next = normalizeMermaidComments(next);
447
+ next = fixExcessiveBrackets(normalizeMermaidPipes(next));
448
+ const noteLines = convertNoteLine(next, state);
449
+ if (noteLines) {
450
+ return noteLines;
451
+ }
452
+ next = fixMalformedMermaidArrows(next);
453
+ next = rewriteQuotedLabelAfterSemicolonLine(next) || next;
454
+ next = mergeDoubleArrowLabelLine(next) || next;
455
+ next = rewriteSingleDoubleDashLabelLine(next) || next;
456
+ next = quoteUnquotedEdgeLabelLine(next) || next;
457
+ next = normalizeMermaidHtmlLineBreakLabels(next);
458
+ next = fixDanglingBracketedNodeLabelLine(next) || next;
459
+ const splitIntermediate = splitIntermediateNodeLine(next);
460
+ if (splitIntermediate) {
461
+ return splitIntermediate;
462
+ }
463
+ return [next];
464
+ }
465
+ function normalizeMermaidDefinition(source) {
466
+ const split = splitMermaidTopLevelStatements(source);
467
+ const state = {
468
+ labelToId: new Map(),
469
+ syntheticCounter: 0,
470
+ };
471
+ return split
472
+ .split('\n')
473
+ .reduce((lines, rawLine) => {
474
+ const repairedLines = applyLegacyMermaidRepairs(rawLine, state);
475
+ repairedLines.forEach((line) => {
476
+ if (!String(line || '').trim()) {
477
+ return;
478
+ }
479
+ if (isMermaidControlLine(line)) {
480
+ lines.push(line.trimEnd());
481
+ return;
482
+ }
483
+ lines.push(normalizeMermaidEdgeLine(line, state).trimEnd());
484
+ });
485
+ return lines;
486
+ }, [])
487
+ .join('\n')
488
+ .replace(/\n{3,}/g, '\n\n')
489
+ .trim();
490
+ }
93
491
  async function renderMathSvg(source, options = {}) {
94
492
  const trimmedSource = source.trim();
95
493
  if (!trimmedSource) {
@@ -143,6 +541,9 @@ async function buildMermaidRenderArtifacts(trimmedSource, options) {
143
541
  const host = environment.host;
144
542
  host.innerHTML = '';
145
543
  const result = await withMermaidDomGlobals(environment.window, async () => environment.mermaid.render(renderId, trimmedSource, host));
544
+ if (result && typeof result.svg === 'string' && isMermaidErrorSvgMarkup(result.svg)) {
545
+ throw new Error('Mermaid renderer produced an error SVG instead of a diagram.');
546
+ }
146
547
  const svgMarkup = sanitizeSvgMarkup(result.svg);
147
548
  const svgDom = new jsdom_1.JSDOM(svgMarkup, { contentType: 'image/svg+xml' });
148
549
  installSvgMeasurementPolyfills(svgDom.window);
@@ -180,7 +581,7 @@ async function buildMermaidRenderArtifacts(trimmedSource, options) {
180
581
  };
181
582
  }
182
583
  async function renderMermaidSvg(source, options = {}) {
183
- const trimmedSource = source.trim();
584
+ const trimmedSource = normalizeMermaidDefinition(source);
184
585
  if (!trimmedSource) {
185
586
  throw new Error('Cannot render an empty Mermaid definition.');
186
587
  }
@@ -190,7 +591,7 @@ async function renderMermaidSvg(source, options = {}) {
190
591
  });
191
592
  }
192
593
  async function collectMermaidRenderStageSnapshots(source, options = {}) {
193
- const trimmedSource = source.trim();
594
+ const trimmedSource = normalizeMermaidDefinition(source);
194
595
  if (!trimmedSource) {
195
596
  throw new Error('Cannot render an empty Mermaid definition.');
196
597
  }
@@ -374,7 +775,7 @@ function getMermaidConfig(theme) {
374
775
  securityLevel: 'loose',
375
776
  theme,
376
777
  fontFamily: MERMAID_FONT_FAMILY,
377
- // Keep Mermaid output in pure SVG text so Godot's SVG loader can render it reliably.
778
+ // Keep Mermaid output free of HTML label nodes so rasterization stays deterministic.
378
779
  htmlLabels: false,
379
780
  markdownAutoWrap: true,
380
781
  maxTextSize: 200000,
@@ -129,6 +129,93 @@ describe('reader_renderer', () => {
129
129
  expect(svg).toContain('Start');
130
130
  expect(svg).toContain('Segoe UI');
131
131
  });
132
+ it('normalizes semicolon-chained Mermaid statements and quoted edge labels before rendering', () => {
133
+ const svg = runRenderer('renderMermaidSvg', [
134
+ 'graph TD;',
135
+ 'P["入射波"] -- "入射角 θi" -- N; P -- "反射角 θr" -- R;',
136
+ 'N --> T["透射波"]',
137
+ ].join('\n'), { theme: 'dark' });
138
+ expect(svg.startsWith('<svg')).toBe(true);
139
+ expect(svg).toContain('入射波');
140
+ expect(svg).toContain('透射波');
141
+ });
142
+ it('wraps bare Mermaid node labels that contain html line breaks or mixed CJK text', () => {
143
+ const svg = runRenderer('renderMermaidSvg', [
144
+ 'graph TD',
145
+ 'A[Incident Wave] --> I界面<br>Interface;',
146
+ 'I --> R反射波<br>Reflected Wave;',
147
+ ].join('\n'), { theme: 'dark' });
148
+ expect(svg.startsWith('<svg')).toBe(true);
149
+ expect(svg).toContain('Incident Wave');
150
+ expect(svg).toContain('Interface');
151
+ });
152
+ it('rewrites quoted labels that were displaced after a semicolon into valid Mermaid edge labels', () => {
153
+ const svg = runRenderer('renderMermaidSvg', [
154
+ 'flowchart TD',
155
+ 'A[Incident Wave] --> I[Interface]; "界面法线 Normal"',
156
+ 'I --> R[Reflected Wave]',
157
+ ].join('\n'), { theme: 'dark' });
158
+ expect(svg.startsWith('<svg')).toBe(true);
159
+ expect(svg).toContain('界面法线');
160
+ expect(svg).toContain('Reflected Wave');
161
+ });
162
+ it('converts directional note directives into note nodes instead of leaving parser-breaking legacy syntax', () => {
163
+ const svg = runRenderer('renderMermaidSvg', [
164
+ 'flowchart TD',
165
+ 'A[Incident Wave] --> B[Interface]',
166
+ 'note right of A : Important constraint',
167
+ ].join('\n'), { theme: 'dark' });
168
+ expect(svg.startsWith('<svg')).toBe(true);
169
+ expect(svg).toContain('Important constraint');
170
+ expect(svg).toContain('Incident Wave');
171
+ });
172
+ it('repairs legacy double-dash labelled edges before rendering', () => {
173
+ const svg = runRenderer('renderMermaidSvg', [
174
+ 'graph TD;',
175
+ 'P["Incident Wave"] -- "theta_i" -- N;',
176
+ 'P -- "theta_r" -- R;',
177
+ 'N --> T["Transmitted Wave"]',
178
+ ].join('\n'), { theme: 'dark' });
179
+ expect(svg.startsWith('<svg')).toBe(true);
180
+ expect(svg).toContain('Incident Wave');
181
+ expect(svg).toContain('Transmitted Wave');
182
+ expect(svg).toContain('theta_i');
183
+ expect(svg).toContain('theta_r');
184
+ });
185
+ it('wraps spaced mixed-language html-break labels into Mermaid node syntax', () => {
186
+ const svg = runRenderer('renderMermaidSvg', [
187
+ 'flowchart TD',
188
+ 'A[Incident Wave] --> I Interface<br/>Boundary;',
189
+ 'I --> R Reflected<br/>Wave;',
190
+ ].join('\n'), { theme: 'dark' });
191
+ expect(svg.startsWith('<svg')).toBe(true);
192
+ expect(svg).toContain('Incident Wave');
193
+ expect(svg).toContain('Interface');
194
+ expect(svg).toContain('Reflected');
195
+ });
196
+ it('repairs Mermaid nodes whose quoted labels end with a stray opening bracket', () => {
197
+ const svg = runRenderer('renderMermaidSvg', [
198
+ 'graph LR',
199
+ 'IncidentWave["入射波 Incident Wave"]',
200
+ 'InteractionPoint["作用点 Interaction Point["',
201
+ 'IncidentWave --> InteractionPoint',
202
+ 'InteractionPoint --> Absorption["吸收 Absorption"]',
203
+ ].join('\n'), { theme: 'dark' });
204
+ expect(svg.startsWith('<svg')).toBe(true);
205
+ expect(svg).toContain('作用点');
206
+ expect(svg).toContain('吸收');
207
+ });
208
+ it("escapes stray quotes inside Mermaid bracketed node labels before rendering", () => {
209
+ const svg = runRenderer("renderMermaidSvg", [
210
+ "flowchart TD",
211
+ "HQWG[\"High Quality Water Glass\"] -->|\"&gt;Superior Overall\"| FS[\"Final Score \"&gt;Superior Overall\"| FS\"]",
212
+ ].join("\n"), { theme: "dark" });
213
+ expect(svg.startsWith("<svg")).toBe(true);
214
+ expect(svg).toContain("High Quality Water Glass");
215
+ expect(svg).toContain("Superior");
216
+ expect(svg).toContain("Overall");
217
+ expect(svg).toContain("Final Score");
218
+ });
132
219
  it('does not leak JSDOM globals onto Node global scope after Mermaid rendering', () => {
133
220
  const scopeProbe = runRendererScopeProbe(['flowchart TD', 'A[Start] --> B{Check}', 'B -->|Yes| C[Done]', 'B -->|No| D[Retry]'].join('\n'), { theme: 'dark' });
134
221
  expect(scopeProbe.afterWindow).toBe(scopeProbe.beforeWindow);
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const fs = __importStar(require("fs"));
37
+ const path = __importStar(require("path"));
38
+ describe('release workflow godot mirror contract', () => {
39
+ const repoRoot = path.resolve(__dirname, '..');
40
+ const workflowPath = path.join(repoRoot, '.github', 'workflows', 'release-desktop-multi-os.yml');
41
+ test('release workflow seeds a project-controlled godot mirror and builds from that mirror first', () => {
42
+ const workflow = fs.readFileSync(workflowPath, 'utf8');
43
+ expect(workflow).toContain('allow_godot_upstream_fallback:');
44
+ expect(workflow).toContain('description: "Allow desktop release jobs to fall back to the upstream Godot release when the project mirror is unavailable."');
45
+ expect(workflow).toContain('default: true');
46
+ expect(workflow).toContain('type: boolean');
47
+ expect(workflow).toContain('GODOT_MIRROR_TAG: "godot-mirror-v4.3-stable"');
48
+ expect(workflow).toContain('GODOT_WINDOWS_ARCHIVE_SHA256: "8f2c75b734bd956027ae3ca92c41f78b5d5a255dacc0f20e4e3c523c545ad410"');
49
+ expect(workflow).toContain('GODOT_LINUX_ARCHIVE_SHA256: "7de56444b130b10af84d19c7e0cf63cf9e9937ee4ba94364c3b7dd114253ca21"');
50
+ expect(workflow).toContain('GODOT_MACOS_ARCHIVE_SHA256: "d17940b913b3f3bf54c941eeb09042099d93865c6e2638e09e20f7c649aa474a"');
51
+ expect(workflow).toContain("GODOT_ALLOW_UPSTREAM_FALLBACK: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.allow_godot_upstream_fallback != 'false' }}");
52
+ expect(workflow).toContain('ensure-godot-mirror-assets:');
53
+ expect(workflow).toContain('gh release view "$GODOT_MIRROR_TAG" --repo "$GITHUB_REPOSITORY"');
54
+ expect(workflow).toContain('gh release create "$GODOT_MIRROR_TAG" \\');
55
+ expect(workflow).toContain('--repo "$GITHUB_REPOSITORY" \\');
56
+ expect(workflow).toContain('--target "$GITHUB_SHA" \\');
57
+ expect(workflow).toContain('EXPECTED_SHA256="$(expected_sha256_for_asset "$ASSET_NAME")"');
58
+ expect(workflow).toContain('sha256sum "$ARCHIVE_PATH"');
59
+ expect(workflow).toContain('Archive digest mismatch for $ASSET_NAME');
60
+ expect(workflow).toContain('gh release upload "$GODOT_MIRROR_TAG" "$ARCHIVE_PATH" --repo "$GITHUB_REPOSITORY" --clobber');
61
+ expect(workflow).toContain('https://github.com/Jacobinwwey/NoteConnection/releases/download/${GODOT_MIRROR_TAG}');
62
+ expect(workflow).toContain('$allowUpstreamFallback = "$env:GODOT_ALLOW_UPSTREAM_FALLBACK".ToLower() -eq "true"');
63
+ expect(workflow).toContain('if (-not $allowUpstreamFallback) {');
64
+ expect(workflow).toContain('throw "Project mirror download failed and upstream fallback is disabled');
65
+ expect(workflow).toContain('if [ "${GODOT_ALLOW_UPSTREAM_FALLBACK}" != "true" ]; then');
66
+ expect(workflow).toContain('echo "::error::Project mirror download failed and upstream fallback is disabled."');
67
+ expect(workflow).toContain('Get-FileHash -Path $archive -Algorithm SHA256');
68
+ expect(workflow).toContain('Downloaded Godot archive digest mismatch');
69
+ expect(workflow).toContain('ACTUAL_SHA256="$(sha256sum build/godot/godot-linux.zip | awk \'{print $1}\')"');
70
+ expect(workflow).toContain('ACTUAL_SHA256="$(sha256sum build/godot/godot-macos.zip | awk \'{print $1}\')"');
71
+ expect(workflow).toContain('needs: [ensure-release, ensure-godot-mirror-assets]');
72
+ });
73
+ });