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
@@ -3,36 +3,135 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MermaidProcessor = void 0;
4
4
  exports.fixMermaidSyntax = fixMermaidSyntax;
5
5
  const MERMAID_BLOCK_PATTERN = /```mermaid\s*([\s\S]*?)```/gi;
6
- function cleanQuotedNoteContent(rawContent) {
7
- return String(rawContent || '')
8
- .replace(/\[""\]/g, '')
9
- .replace(/\["\]/g, '')
10
- .replace(/\["/g, '[')
11
- .replace(/"\]/g, ']')
12
- .replace(/\s+/g, ' ')
6
+ const TABLE_PLACEHOLDER_PREFIX = '___MERMAID_TABLE_LINE_';
7
+ function normalizeMermaidLineBreaks(source) {
8
+ return String(source || '')
9
+ .replace(/\r\n?/g, '\n')
10
+ .replace(/<br\s*>/gi, '<br/>');
11
+ }
12
+ function stripWrappingDoubleQuotes(text) {
13
+ const trimmed = String(text || '').trim();
14
+ if (trimmed.length >= 2 && trimmed.startsWith('"') && trimmed.endsWith('"')) {
15
+ return trimmed.slice(1, -1);
16
+ }
17
+ return trimmed;
18
+ }
19
+ function escapeMermaidLabel(rawValue) {
20
+ return String(rawValue || '')
21
+ .replace(/\\/g, '\\\\')
22
+ .replace(/"/g, '\\"')
13
23
  .trim();
14
24
  }
15
- function expandNoteStatements(blockSource) {
16
- const nextLines = [];
17
- let changed = false;
18
- blockSource.split('\n').forEach((line) => {
19
- const match = /^(\s*)note\s+([A-Za-z0-9_]+)\s+"([^"]*)"\s*;?\s*$/i.exec(line);
20
- if (!match) {
21
- nextLines.push(line);
22
- return;
25
+ function escapeMermaidQuotedNodeLabel(rawValue) {
26
+ return String(rawValue || '')
27
+ .replace(/\\/g, '\\\\')
28
+ .replace(/"/g, '#quot;')
29
+ .trim();
30
+ }
31
+ function normalizeMermaidQuotedNodeLabels(source) {
32
+ return String(source || '')
33
+ .split('\n')
34
+ .map((line) => {
35
+ const text = String(line || '');
36
+ const startPattern = /([A-Za-z_][A-Za-z0-9_]*)\["/g;
37
+ let result = '';
38
+ let cursor = 0;
39
+ let match;
40
+ while ((match = startPattern.exec(text)) !== null) {
41
+ const labelStart = match.index + match[0].length;
42
+ let labelEnd = -1;
43
+ for (let index = labelStart; index < text.length - 1; index += 1) {
44
+ if (text.charAt(index) === '"' && text.charAt(index - 1) !== '\\' && text.charAt(index + 1) === ']') {
45
+ labelEnd = index;
46
+ break;
47
+ }
48
+ }
49
+ if (labelEnd < 0) {
50
+ continue;
51
+ }
52
+ result += text.slice(cursor, labelStart);
53
+ result += escapeMermaidQuotedNodeLabel(text.slice(labelStart, labelEnd));
54
+ result += '"]';
55
+ cursor = labelEnd + 2;
56
+ startPattern.lastIndex = cursor;
23
57
  }
24
- const indent = match[1] || '';
25
- const targetId = match[2];
26
- const noteId = `Note${targetId}`;
27
- const content = cleanQuotedNoteContent(match[3]);
28
- nextLines.push(`${indent}${noteId}["${content}"]`);
29
- nextLines.push(`${indent}${targetId} -.- ${noteId}`);
30
- changed = true;
31
- });
32
- return {
33
- next: nextLines.join('\n'),
34
- changed,
35
- };
58
+ return result + text.slice(cursor);
59
+ })
60
+ .join('\n');
61
+ }
62
+ function protectTableLines(content) {
63
+ const protectedLines = [];
64
+ const tableSeparatorRegex = /^\s*\|(?:[\s\t]*:?[\s\t]*-+[\s\t]*:?[\s\t]*\|)+[\s\t]*$/;
65
+ const next = String(content || '')
66
+ .split('\n')
67
+ .map((line) => {
68
+ if (line.includes(':-- :') || tableSeparatorRegex.test(line)) {
69
+ const placeholder = `${TABLE_PLACEHOLDER_PREFIX}${protectedLines.length}___`;
70
+ protectedLines.push(line);
71
+ return placeholder;
72
+ }
73
+ return line;
74
+ })
75
+ .join('\n');
76
+ return { next, protectedLines };
77
+ }
78
+ function restoreTableLines(content, protectedLines) {
79
+ return protectedLines.reduce((restored, line, index) => {
80
+ const placeholder = `${TABLE_PLACEHOLDER_PREFIX}${index}___`;
81
+ return restored.split(placeholder).join(line);
82
+ }, content);
83
+ }
84
+ function splitTopLevelStatements(source) {
85
+ const text = normalizeMermaidLineBreaks(source)
86
+ .split('\n')
87
+ .map((line) => rewriteQuotedLabelAfterSemicolonLine(line) || line)
88
+ .join('\n');
89
+ let result = '';
90
+ let quote = false;
91
+ let squareDepth = 0;
92
+ let roundDepth = 0;
93
+ let curlyDepth = 0;
94
+ for (let index = 0; index < text.length; index += 1) {
95
+ const char = text.charAt(index);
96
+ if (char === '"' && text.charAt(index - 1) !== '\\') {
97
+ quote = !quote;
98
+ result += char;
99
+ continue;
100
+ }
101
+ if (!quote) {
102
+ if (char === '[')
103
+ squareDepth += 1;
104
+ else if (char === ']')
105
+ squareDepth = Math.max(0, squareDepth - 1);
106
+ else if (char === '(')
107
+ roundDepth += 1;
108
+ else if (char === ')')
109
+ roundDepth = Math.max(0, roundDepth - 1);
110
+ else if (char === '{')
111
+ curlyDepth += 1;
112
+ else if (char === '}')
113
+ curlyDepth = Math.max(0, curlyDepth - 1);
114
+ if (char === ';' && squareDepth === 0 && roundDepth === 0 && curlyDepth === 0) {
115
+ result += '\n';
116
+ continue;
117
+ }
118
+ }
119
+ result += char;
120
+ }
121
+ return result;
122
+ }
123
+ function rewriteSingleDoubleDashLabelLine(line) {
124
+ const match = line.match(/^(.*?)\s*(?<!-)--(?!>|-)\s*"([^"\n]+)"\s*(?<!-)--(?!>|-)\s*(.+?)\s*;?\s*$/);
125
+ if (!match) {
126
+ return null;
127
+ }
128
+ const start = String(match[1] || '').trim();
129
+ const label = String(match[2] || '').trim();
130
+ const end = String(match[3] || '').trim();
131
+ if (!start || !label || !end || /^"/.test(end)) {
132
+ return null;
133
+ }
134
+ return `${start} -- "${label}" --> ${end};`;
36
135
  }
37
136
  function normalizeSubgraphLine(line) {
38
137
  const match = /^(\s*subgraph\s+)(.+)$/i.exec(line);
@@ -44,7 +143,6 @@ function normalizeSubgraphLine(line) {
44
143
  if (!rawTitle || rawTitle.startsWith('"') || rawTitle.startsWith("'")) {
45
144
  return { next: line, changed: false };
46
145
  }
47
- // Quote titles that contain spaces or punctuation to avoid Mermaid parse failures.
48
146
  if (/[\s()[\]{}:;,-]/.test(rawTitle)) {
49
147
  return {
50
148
  next: `${prefix}"${rawTitle.replace(/"/g, '\\"')}"`,
@@ -53,40 +151,292 @@ function normalizeSubgraphLine(line) {
53
151
  }
54
152
  return { next: line, changed: false };
55
153
  }
56
- function fixMermaidBlock(blockSource) {
154
+ function rewriteQuotedLabelAfterSemicolonLine(line) {
155
+ if (!line.includes('-->')) {
156
+ return null;
157
+ }
158
+ const match = line.match(/^(.*?)\s*(-->)\s*(.*?);\s*"([^"\n]+)"\s*$/);
159
+ if (!match) {
160
+ return null;
161
+ }
162
+ const source = String(match[1] || '').trim();
163
+ const arrow = String(match[2] || '').trim();
164
+ const target = String(match[3] || '').trim();
165
+ const label = String(match[4] || '').trim();
166
+ if (!source || !target || !label) {
167
+ return null;
168
+ }
169
+ return `${source} -- "${label}" ${arrow} ${target};`;
170
+ }
171
+ function mergeDoubleArrowLabelLine(line) {
172
+ const match = line.match(/^(.*?)\s*--\s*"([^"\n]+)"\s*--\s*"([^"\n]+)"\s*(-->|---)\s*(.*)$/);
173
+ if (!match) {
174
+ return null;
175
+ }
176
+ const start = String(match[1] || '').trim();
177
+ const labelLeft = String(match[2] || '').trim();
178
+ const labelRight = String(match[3] || '').trim();
179
+ const arrow = String(match[4] || '').trim();
180
+ const end = String(match[5] || '').trim();
181
+ if (!start || !labelLeft || !labelRight || !end) {
182
+ return null;
183
+ }
184
+ return `${start} -- "${labelLeft}<br/>${labelRight}" ${arrow} ${end}`;
185
+ }
186
+ function quoteUnquotedEdgeLabelLine(line) {
187
+ const match = line.match(/^(.*?)\s*--\s*([^"\n][^>\n]*?)\s*-->\s*(.*)$/);
188
+ if (!match) {
189
+ return null;
190
+ }
191
+ const start = String(match[1] || '').trim();
192
+ const label = String(match[2] || '').trim();
193
+ const end = String(match[3] || '').trim();
194
+ if (!start || !label || !end) {
195
+ return null;
196
+ }
197
+ if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(label) ||
198
+ /^[A-Za-z_][A-Za-z0-9_]*\s*[\[\(\{].*$/.test(label) ||
199
+ /^["[{(]/.test(label)) {
200
+ return null;
201
+ }
202
+ return `${start} -- "${label}" --> ${end}`;
203
+ }
204
+ function fixMalformedArrows(content) {
205
+ return String(content || '')
206
+ .replace(/[→⇒⟶⟹]/g, '-->')
207
+ .replace(/--\|>/g, '-->')
208
+ .replace(/<--/g, '-->')
209
+ .replace(/-- >/g, '-->');
210
+ }
211
+ function normalizeMermaidComments(content) {
212
+ return String(content || '')
213
+ .split('\n')
214
+ .map((line) => {
215
+ const hashCommentMatch = line.match(/^(\s*[A-Za-z0-9_()[\]{}"'\s.-]+?)\s*-->\s*([A-Za-z0-9_()[\]{}"'\s.-]+?)\s*;\s*#(.*)$/);
216
+ if (hashCommentMatch) {
217
+ return `${hashCommentMatch[1].trim()} -- "${hashCommentMatch[3].trim()}" --> ${hashCommentMatch[2].trim()};`;
218
+ }
219
+ const percentCommentMatch = line.match(/^(\s*[A-Za-z0-9_()[\]{}"'\s.-]+?)\s*-->\s*([A-Za-z0-9_()[\]{}"'\s.-]+?)\s*;\s*%(.*)$/);
220
+ if (percentCommentMatch) {
221
+ return `${percentCommentMatch[1].trim()} -- "${percentCommentMatch[3].trim()}" --> ${percentCommentMatch[2].trim()};`;
222
+ }
223
+ const slashCommentMatch = line.match(/^(\s*[A-Za-z0-9_()[\]{}"'\s.-]+?)\s*-->\s*([A-Za-z0-9_()[\]{}"'\s.-]+?)\s*;\s*\/\/(.*)$/);
224
+ if (slashCommentMatch) {
225
+ return `${slashCommentMatch[1].trim()} -- "${slashCommentMatch[3].trim()}" --> ${slashCommentMatch[2].trim()};`;
226
+ }
227
+ return line;
228
+ })
229
+ .join('\n');
230
+ }
231
+ function normalizeHtmlBreakBareNodeLabels(line) {
232
+ const text = String(line || '');
233
+ const arrowMatch = text.match(/^(.*?(?:-->|---|-\.->|\-.-))\s*([A-Za-z_][A-Za-z0-9_]*)\s+(.+?)\s*;?\s*$/);
234
+ if (!arrowMatch) {
235
+ return text;
236
+ }
237
+ const prefix = String(arrowMatch[1] || '');
238
+ const nodeId = String(arrowMatch[2] || '').trim();
239
+ const label = String(arrowMatch[3] || '').trim();
240
+ if (!nodeId || !label || !label.includes('<br/>')) {
241
+ return text;
242
+ }
243
+ if (/^[\[\(\{"]/.test(label)) {
244
+ return text;
245
+ }
246
+ if (/(?:-->|---|-\.->|\-.-)/.test(label)) {
247
+ return text;
248
+ }
249
+ return `${prefix} ${nodeId}["${escapeMermaidLabel(stripWrappingDoubleQuotes(label))}"]`;
250
+ }
251
+ function convertNoteLine(line, counters) {
252
+ const directionalMatch = line.match(/^\s*note\s+(?:right|left|top|bottom)\s+of\s+([A-Za-z0-9_]+)\s*:\s*(.+)$/i);
253
+ if (directionalMatch) {
254
+ const targetId = directionalMatch[1];
255
+ const noteId = `Note${targetId}`;
256
+ const noteText = escapeMermaidLabel(stripWrappingDoubleQuotes(directionalMatch[2]));
257
+ return [
258
+ `${noteId}["${noteText}"]`,
259
+ `${targetId} -.- ${noteId}`,
260
+ ];
261
+ }
262
+ const targetedMatch = line.match(/^\s*note\s+([A-Za-z0-9_]+)\s+"(.+)"\s*;?\s*$/i);
263
+ if (targetedMatch) {
264
+ const targetId = targetedMatch[1];
265
+ const noteId = `Note${targetId}`;
266
+ const noteText = escapeMermaidLabel(stripWrappingDoubleQuotes(targetedMatch[2]));
267
+ return [
268
+ `${noteId}["${noteText}"]`,
269
+ `${targetId} -.- ${noteId}`,
270
+ ];
271
+ }
272
+ const forOfMatch = line.match(/^\s*note\s+(?:for|of)\s+([A-Za-z0-9_]+)\s+(.+)$/i);
273
+ if (forOfMatch) {
274
+ const targetId = forOfMatch[1];
275
+ const noteId = `Note${targetId}`;
276
+ const noteText = escapeMermaidLabel(stripWrappingDoubleQuotes(forOfMatch[2].replace(/\]$/, '').trim()));
277
+ return [
278
+ `${noteId}["${noteText}"]`,
279
+ `${targetId} -.- ${noteId}`,
280
+ ];
281
+ }
282
+ const standaloneMatch = line.match(/^\s*note\s*:\s*(.+)$/i);
283
+ if (standaloneMatch) {
284
+ counters.note += 1;
285
+ const noteId = `NoteStandalone${counters.note}`;
286
+ const noteText = escapeMermaidLabel(stripWrappingDoubleQuotes(standaloneMatch[1]));
287
+ return [`${noteId}["${noteText}"]`];
288
+ }
289
+ return null;
290
+ }
291
+ function splitIntermediateNodeLine(line) {
292
+ const match = line.match(/^(.*?)\s*(-->|---)\s*([A-Za-z_][A-Za-z0-9_]*)\s*(\[[^\]]+\]|\([^)]+\)|\{[^}]+\})\s*(-->|---)\s*(.*)$/);
293
+ if (!match) {
294
+ return null;
295
+ }
296
+ const start = String(match[1] || '').trim();
297
+ const leftArrow = String(match[2] || '').trim();
298
+ const nodeId = String(match[3] || '').trim();
299
+ const nodeShape = String(match[4] || '').trim();
300
+ const rightArrow = String(match[5] || '').trim();
301
+ const end = String(match[6] || '').trim();
302
+ if (!start || !nodeId || !nodeShape || !end) {
303
+ return null;
304
+ }
305
+ return [
306
+ `${start} ${leftArrow} ${nodeId}${nodeShape}`,
307
+ `${nodeId} ${rightArrow} ${end}`,
308
+ ];
309
+ }
310
+ function normalizeMermaidPipes(content) {
311
+ return String(content || '')
312
+ .replace(/\|""\|"/g, '')
313
+ .replace(/"\[\]"/g, '');
314
+ }
315
+ function fixExcessiveBrackets(content) {
316
+ return String(content || '')
317
+ .replace(/\]{3,}/g, ']')
318
+ .replace(/\[""\]/g, '')
319
+ .replace(/\["\]/g, ']')
320
+ .replace(/\[\/\["/g, '["')
321
+ .replace(/\["\/\]/g, '"]');
322
+ }
323
+ function fixDanglingBracketedNodeLabelLine(line) {
324
+ const match = line.match(/^(\s*[A-Za-z_][A-Za-z0-9_]*)\["([^"\n]*)\["\s*;?\s*$/);
325
+ if (!match) {
326
+ return null;
327
+ }
328
+ const nodeId = String(match[1] || '').trim();
329
+ const label = String(match[2] || '').trim();
330
+ if (!nodeId || !label) {
331
+ return null;
332
+ }
333
+ return `${nodeId}["${escapeMermaidLabel(label)}"]`;
334
+ }
335
+ function applyDeepDebugMermaid(content) {
336
+ let next = normalizeMermaidPipes(content);
57
337
  const fixes = [];
58
- let next = blockSource.replace(/\r\n?/g, '\n');
59
- const replacements = [
60
- [/\t/g, ' ', 'Converted tab indentation to spaces.'],
61
- [/[→⇒⟶⟹]/g, '-->', 'Normalized Unicode arrows to Mermaid arrows.'],
62
- [/\b(end);+\s*$/gim, 'end', 'Removed invalid trailing semicolons after end.'],
63
- [/graph\s+([A-Z]{2})\s*;/g, 'graph $1', 'Removed semicolon after graph declaration.'],
64
- [/;\s*$/gm, ';', 'Normalized trailing semicolon spacing.'],
338
+ const passes = [
339
+ ['Normalized Mermaid line breaks.', normalizeMermaidLineBreaks],
340
+ ['Normalized malformed arrows and Unicode arrows.', fixMalformedArrows],
341
+ ['Converted Mermaid comments into explicit edge labels.', normalizeMermaidComments],
342
+ ['Cleaned excessive Mermaid brackets and placeholder artifacts.', fixExcessiveBrackets],
65
343
  ];
66
- replacements.forEach(([pattern, value, description]) => {
67
- const updated = next.replace(pattern, value);
344
+ passes.forEach(([description, apply]) => {
345
+ const updated = apply(next);
68
346
  if (updated !== next) {
69
347
  fixes.push(description);
70
348
  next = updated;
71
349
  }
72
350
  });
73
- const lines = next.split('\n');
74
- for (let i = 0; i < lines.length; i += 1) {
75
- const normalized = normalizeSubgraphLine(lines[i]);
76
- if (normalized.changed) {
77
- lines[i] = normalized.next;
351
+ const noteCounters = { note: 0 };
352
+ const nextLines = [];
353
+ next.split('\n').forEach((rawLine) => {
354
+ const subgraphNormalized = normalizeSubgraphLine(rawLine);
355
+ let line = subgraphNormalized.next;
356
+ if (subgraphNormalized.changed) {
78
357
  fixes.push('Quoted subgraph title with special characters.');
79
358
  }
359
+ const convertedNotes = convertNoteLine(line, noteCounters);
360
+ if (convertedNotes) {
361
+ nextLines.push(...convertedNotes);
362
+ fixes.push('Converted Mermaid note directives into linked note nodes.');
363
+ return;
364
+ }
365
+ const rewrittenQuotedLabel = rewriteQuotedLabelAfterSemicolonLine(line);
366
+ if (rewrittenQuotedLabel && rewrittenQuotedLabel !== line) {
367
+ line = rewrittenQuotedLabel;
368
+ fixes.push('Re-attached quoted edge labels that were displaced after semicolons.');
369
+ }
370
+ const mergedDoubleLabel = mergeDoubleArrowLabelLine(line);
371
+ if (mergedDoubleLabel && mergedDoubleLabel !== line) {
372
+ line = mergedDoubleLabel;
373
+ fixes.push('Merged legacy double-label Mermaid edges.');
374
+ }
375
+ const rewrittenSingleDoubleDash = rewriteSingleDoubleDashLabelLine(line);
376
+ if (rewrittenSingleDoubleDash && rewrittenSingleDoubleDash !== line) {
377
+ line = rewrittenSingleDoubleDash;
378
+ fixes.push('Converted legacy double-dash Mermaid edges into standard arrows.');
379
+ }
380
+ const quotedUnquotedLabel = quoteUnquotedEdgeLabelLine(line);
381
+ if (quotedUnquotedLabel && quotedUnquotedLabel !== line) {
382
+ line = quotedUnquotedLabel;
383
+ fixes.push('Quoted unquoted Mermaid edge labels.');
384
+ }
385
+ const htmlBreakLabel = normalizeHtmlBreakBareNodeLabels(line);
386
+ if (htmlBreakLabel !== line) {
387
+ line = htmlBreakLabel;
388
+ fixes.push('Wrapped bare Mermaid node labels containing HTML line breaks.');
389
+ }
390
+ const danglingLabelFix = fixDanglingBracketedNodeLabelLine(line);
391
+ if (danglingLabelFix && danglingLabelFix !== line) {
392
+ line = danglingLabelFix;
393
+ fixes.push('Closed Mermaid node labels that had a dangling opening bracket inside quotes.');
394
+ }
395
+ const splitIntermediate = splitIntermediateNodeLine(line);
396
+ if (splitIntermediate) {
397
+ nextLines.push(...splitIntermediate);
398
+ fixes.push('Split Mermaid intermediate node edges into valid statements.');
399
+ return;
400
+ }
401
+ nextLines.push(line);
402
+ });
403
+ next = nextLines
404
+ .join('\n')
405
+ .replace(/\n{3,}/g, '\n\n')
406
+ .trimEnd();
407
+ return {
408
+ next,
409
+ fixes: Array.from(new Set(fixes)),
410
+ };
411
+ }
412
+ function fixMermaidBlock(blockSource) {
413
+ const fixes = [];
414
+ const protectedTables = protectTableLines(blockSource);
415
+ let next = normalizeMermaidQuotedNodeLabels(protectedTables.next);
416
+ if (next !== protectedTables.next) {
417
+ fixes.push('Escaped stray double quotes inside Mermaid node labels.');
80
418
  }
81
- next = lines.join('\n');
82
- const expandedNotes = expandNoteStatements(next);
83
- if (expandedNotes.changed) {
84
- next = expandedNotes.next;
85
- fixes.push('Converted Mermaid note statements into linked note nodes.');
86
- }
419
+ next = splitTopLevelStatements(next);
420
+ const deepDebug = applyDeepDebugMermaid(next);
421
+ next = deepDebug.next;
422
+ fixes.push(...deepDebug.fixes);
423
+ next = restoreTableLines(next, protectedTables.protectedLines);
424
+ // Cleanup final syntax trivia after all structural passes.
425
+ const cleanupPasses = [
426
+ [/\b(end);+\s*$/gim, 'end', 'Removed invalid trailing semicolons after end.'],
427
+ [/graph\s+([A-Z]{2})\s*;/g, 'graph $1', 'Removed semicolon after graph declaration.'],
428
+ [/\n{3,}/g, '\n\n', 'Collapsed excessive blank lines inside Mermaid blocks.'],
429
+ ];
430
+ cleanupPasses.forEach(([pattern, replacement, description]) => {
431
+ const updated = next.replace(pattern, replacement);
432
+ if (updated !== next) {
433
+ next = updated;
434
+ fixes.push(description);
435
+ }
436
+ });
87
437
  return {
88
438
  block: next.trimEnd(),
89
- fixes,
439
+ fixes: Array.from(new Set(fixes)),
90
440
  };
91
441
  }
92
442
  class MermaidProcessor {