noteconnection 1.7.0 → 1.9.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 (328) hide show
  1. package/LICENSE +674 -21
  2. package/README.md +260 -1626
  3. package/dist/src/agent_workspace.contract.parity.test.js +159 -0
  4. package/dist/src/agent_workspace.frontend.test.js +10388 -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/android.knowledgebase.picker.contract.test.js +102 -0
  8. package/dist/src/appimage.patchelf.test.js +113 -0
  9. package/dist/src/appimage.portability.test.js +156 -0
  10. package/dist/src/backend/FileLoader.js +18 -4
  11. package/dist/src/backend/FileLoader.test.js +125 -0
  12. package/dist/src/backend/GraphBuilder.identity.test.js +86 -0
  13. package/dist/src/backend/GraphBuilder.js +66 -18
  14. package/dist/src/backend/GraphBuilder.matching.test.js +127 -0
  15. package/dist/src/backend/GraphMetrics.js +0 -3
  16. package/dist/src/backend/ResourceIdentity.js +155 -0
  17. package/dist/src/backend/ResourceIdentity.test.js +113 -0
  18. package/dist/src/backend/algorithms/CycleDetection.js +0 -1
  19. package/dist/src/backend/algorithms/HybridEngine.js +0 -3
  20. package/dist/src/backend/algorithms/LayoutEngine.js +0 -1
  21. package/dist/src/backend/algorithms/StatisticalAnalyzer.js +0 -4
  22. package/dist/src/backend/algorithms/TopologicalSort.js +0 -2
  23. package/dist/src/backend/build_dag.js +0 -1
  24. package/dist/src/capacitor.bridge.serialization.contract.test.js +3 -0
  25. package/dist/src/capacitor.runtime.contract.test.js +11 -2
  26. package/dist/src/copy.assets.contract.test.js +130 -0
  27. package/dist/src/core/Graph.js +138 -42
  28. package/dist/src/core/Graph.test.js +74 -0
  29. package/dist/src/core/NoteConnection.js +2 -2
  30. package/dist/src/core/PathBridge.js +293 -5
  31. package/dist/src/core/ResourceReference.js +17 -0
  32. package/dist/src/desktop.godot.pack.test.js +142 -0
  33. package/dist/src/desktop.runtime.graph.test.js +66 -0
  34. package/dist/src/export/WorkspaceExportBundle.js +1174 -0
  35. package/dist/src/export/WorkspaceExportBundle.test.js +1541 -0
  36. package/dist/src/export/index.js +18 -0
  37. package/dist/src/export/types.js +2 -0
  38. package/dist/src/fixrisk.issue.verifier.contract.test.js +3 -1
  39. package/dist/src/foundation.ann.runtime.contract.test.js +81 -0
  40. package/dist/src/foundation.release.evidence.contract.test.js +524 -0
  41. package/dist/src/foundation.sqlite.runtime.contract.test.js +88 -0
  42. package/dist/src/frontend/README.md +260 -1626
  43. package/dist/src/frontend/agent_workspace.js +6011 -0
  44. package/dist/src/frontend/agent_workspace_runtime.js +4434 -0
  45. package/dist/src/frontend/analysis.js +31 -4
  46. package/dist/src/frontend/app.js +2178 -62
  47. package/dist/src/frontend/focus_mode_interactions.js +33 -0
  48. package/dist/src/frontend/godot_future_path_renderer.js +540 -0
  49. package/dist/src/frontend/godot_tree_interactions.js +178 -0
  50. package/dist/src/frontend/graph_state.mjs +105 -0
  51. package/dist/src/frontend/hosted_future_path_runtime.js +157 -0
  52. package/dist/src/frontend/i18n.mjs +186 -0
  53. package/dist/src/frontend/index.html +672 -268
  54. package/dist/src/frontend/knowledge_projection_contract.js +230 -0
  55. package/dist/src/frontend/knowledge_projection_store.js +214 -0
  56. package/dist/src/frontend/layout_gpu.js +12 -4
  57. package/dist/src/frontend/libs/path_core.js +158 -42
  58. package/dist/src/frontend/locales/en.json +753 -5
  59. package/dist/src/frontend/locales/zh.json +753 -5
  60. package/dist/src/frontend/main.mjs +60 -0
  61. package/dist/src/frontend/markdown_runtime.js +827 -0
  62. package/dist/src/frontend/mobile_budget_runtime.js +33 -0
  63. package/dist/src/frontend/mobile_exact_analyzer.js +393 -0
  64. package/dist/src/frontend/mobile_identity_contract.js +221 -0
  65. package/dist/src/frontend/mobile_semantic_comparator.js +264 -0
  66. package/dist/src/frontend/notemd.css +49 -0
  67. package/dist/src/frontend/notemd.html +7 -1
  68. package/dist/src/frontend/notemd.js +64 -0
  69. package/dist/src/frontend/path.html +113 -2
  70. package/dist/src/frontend/path_app.js +2108 -130
  71. package/dist/src/frontend/path_layout.mjs +143 -0
  72. package/dist/src/frontend/path_mermaid_utils.mjs +108 -0
  73. package/dist/src/frontend/path_modules_bridge.js +486 -0
  74. package/dist/src/frontend/path_state.mjs +118 -0
  75. package/dist/src/frontend/path_styles.css +146 -0
  76. package/dist/src/frontend/path_worker_bridge.mjs +85 -0
  77. package/dist/src/frontend/reader.js +393 -33
  78. package/dist/src/frontend/runtime_bridge.js +67 -54
  79. package/dist/src/frontend/runtime_bridge.mjs +279 -0
  80. package/dist/src/frontend/settings.js +130 -12
  81. package/dist/src/frontend/simulationWorker.js +1 -1
  82. package/dist/src/frontend/source_manager.js +297 -22
  83. package/dist/src/frontend/storage_provider.js +661 -71
  84. package/dist/src/frontend/styles.css +2814 -72
  85. package/dist/src/frontend/workbench_state.mjs +101 -0
  86. package/dist/src/frontend/workspace_panes.js +10272 -0
  87. package/dist/src/frontend.locale.contract.test.js +62 -0
  88. package/dist/src/frontend.runtime.assets.contract.test.js +81 -0
  89. package/dist/src/godot.sidecar.bootstrap.contract.test.js +244 -0
  90. package/dist/src/graph.answer.operator.contract.test.js +72 -0
  91. package/dist/src/index.js +6 -2
  92. package/dist/src/index.knowledge-root.test.js +118 -0
  93. package/dist/src/indexing/IndexLifecycle.js +217 -0
  94. package/dist/src/indexing/IndexLifecycle.test.js +73 -0
  95. package/dist/src/indexing/SegmentBuilder.js +64 -0
  96. package/dist/src/indexing/UnitBuilder.js +48 -0
  97. package/dist/src/indexing/types.js +2 -0
  98. package/dist/src/knowledge.api.contract.test.js +172 -0
  99. package/dist/src/knowledge_projection.contract.test.js +134 -0
  100. package/dist/src/knowledge_projection_store.test.js +200 -0
  101. package/dist/src/learning/AnswerQualityEvaluation.js +153 -0
  102. package/dist/src/learning/AnswerQualityEvaluation.test.js +118 -0
  103. package/dist/src/learning/KnowledgeLearningPlatform.js +11181 -0
  104. package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +745 -0
  105. package/dist/src/learning/KnowledgeLearningPlatform.program-f.test.js +99 -0
  106. package/dist/src/learning/KnowledgeLearningPlatform.test.js +3208 -0
  107. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +2998 -0
  108. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +3936 -0
  109. package/dist/src/learning/MeasurementEvidenceConflicts.test.js +78 -0
  110. package/dist/src/learning/PublicAnswerContract.test.js +85 -0
  111. package/dist/src/learning/PublicEvidenceSelection.test.js +94 -0
  112. package/dist/src/learning/PublicMeasurementDisclosure.test.js +54 -0
  113. package/dist/src/learning/agentConversationExecution.js +211 -0
  114. package/dist/src/learning/agentConversationExecution.test.js +209 -0
  115. package/dist/src/learning/agentConversationSerialization.js +266 -0
  116. package/dist/src/learning/agentConversationSerialization.test.js +165 -0
  117. package/dist/src/learning/agentResponseBudget.js +179 -0
  118. package/dist/src/learning/agentResponseBudget.test.js +97 -0
  119. package/dist/src/learning/agentWorkspaceCapabilityContracts.js +65 -0
  120. package/dist/src/learning/answerReleaseReview.js +5260 -0
  121. package/dist/src/learning/answerReleaseReview.test.js +4174 -0
  122. package/dist/src/learning/answerTaskPlan.js +473 -0
  123. package/dist/src/learning/api.js +2 -0
  124. package/dist/src/learning/conversationComposer.js +1721 -0
  125. package/dist/src/learning/conversationComposer.test.js +3220 -0
  126. package/dist/src/learning/domains/ConversationManager.js +53 -0
  127. package/dist/src/learning/domains/KnowledgeIngestor.js +238 -0
  128. package/dist/src/learning/domains/KnowledgeQuerier.js +187 -0
  129. package/dist/src/learning/domains/MasteryEngine.js +387 -0
  130. package/dist/src/learning/domains/MemoryPolicyManager.js +408 -0
  131. package/dist/src/learning/domains/QualityEvaluator.js +307 -0
  132. package/dist/src/learning/domains/TutorRouter.js +313 -0
  133. package/dist/src/learning/domains/index.js +33 -0
  134. package/dist/src/learning/domains/types.js +7 -0
  135. package/dist/src/learning/errors.js +29 -0
  136. package/dist/src/learning/evidenceContextAssembler.js +1368 -0
  137. package/dist/src/learning/evidenceContextAssembler.test.js +6332 -0
  138. package/dist/src/learning/graphAnswerCoverage.js +37 -0
  139. package/dist/src/learning/graphAnswerCoverage.test.js +93 -0
  140. package/dist/src/learning/graphAnswerCoverageCalibration.js +59 -0
  141. package/dist/src/learning/graphAnswerCoverageCalibration.test.js +46 -0
  142. package/dist/src/learning/graphAnswerFacts.js +94 -0
  143. package/dist/src/learning/graphAnswerFacts.test.js +39 -0
  144. package/dist/src/learning/graphAnswerPlan.js +908 -0
  145. package/dist/src/learning/graphAnswerPlan.test.js +907 -0
  146. package/dist/src/learning/graphAnswerQualityCalibration.js +255 -0
  147. package/dist/src/learning/graphAnswerQualityCalibration.test.js +72 -0
  148. package/dist/src/learning/graphAnswerQualityPolicy.js +30 -0
  149. package/dist/src/learning/graphClaimMatcher.js +104 -0
  150. package/dist/src/learning/graphConditionedContext.js +109 -0
  151. package/dist/src/learning/graphConditionedContext.test.js +99 -0
  152. package/dist/src/learning/graphContextAssembler.js +860 -0
  153. package/dist/src/learning/graphContextAssembler.test.js +1033 -0
  154. package/dist/src/learning/graphExpansionPolicy.js +22 -0
  155. package/dist/src/learning/graphExpansionPolicy.test.js +33 -0
  156. package/dist/src/learning/identityMetadata.test.js +26 -0
  157. package/dist/src/learning/index.js +29 -0
  158. package/dist/src/learning/mobileAnswerProjection.js +104 -0
  159. package/dist/src/learning/mobileAnswerProjection.test.js +102 -0
  160. package/dist/src/learning/queryBackend.js +1922 -0
  161. package/dist/src/learning/queryBackend.test.js +976 -0
  162. package/dist/src/learning/ragContextPack.js +356 -0
  163. package/dist/src/learning/ragContextPack.test.js +311 -0
  164. package/dist/src/learning/ragEvidenceQuality.js +96 -0
  165. package/dist/src/learning/ragEvidenceQuality.test.js +29 -0
  166. package/dist/src/learning/ragPublicText.js +101 -0
  167. package/dist/src/learning/ragPublicText.test.js +57 -0
  168. package/dist/src/learning/ragSufficiencyJudge.js +171 -0
  169. package/dist/src/learning/ragSufficiencyJudge.test.js +177 -0
  170. package/dist/src/learning/ragSufficiencyProviderJudge.js +217 -0
  171. package/dist/src/learning/ragSufficiencyProviderJudge.test.js +207 -0
  172. package/dist/src/learning/requestNormalization.js +304 -0
  173. package/dist/src/learning/requestNormalization.test.js +101 -0
  174. package/dist/src/learning/runtimeCapability.js +4677 -0
  175. package/dist/src/learning/runtimeCapability.test.js +3635 -0
  176. package/dist/src/learning/store.js +1344 -0
  177. package/dist/src/learning/store.test.js +1425 -0
  178. package/dist/src/learning/tutorAdapter.js +2 -0
  179. package/dist/src/learning/types.js +2 -0
  180. package/dist/src/learning/vectorAccelerationAdapter.js +958 -0
  181. package/dist/src/learning/vectorAccelerationAdapter.test.js +412 -0
  182. package/dist/src/learning/workspaceHydration.js +168 -0
  183. package/dist/src/learning/workspaceHydration.test.js +30 -0
  184. package/dist/src/lfs.asset.policy.contract.test.js +153 -0
  185. package/dist/src/license.policy.contract.test.js +71 -0
  186. package/dist/src/markdown/MarkdownGateway.js +4 -0
  187. package/dist/src/markdown/MarkdownGateway.test.js +59 -0
  188. package/dist/src/memory/MemoryGovernance.js +74 -0
  189. package/dist/src/memory/MemoryGovernance.test.js +46 -0
  190. package/dist/src/memory/types.js +2 -0
  191. package/dist/src/mermaid.frontend.guard.contract.test.js +77 -0
  192. package/dist/src/middleware/SseResponseWriter.js +122 -0
  193. package/dist/src/middleware/SseResponseWriter.test.js +54 -0
  194. package/dist/src/middleware/auth.js +38 -0
  195. package/dist/src/middleware/auth.test.js +33 -0
  196. package/dist/src/middleware/body-parser.js +45 -0
  197. package/dist/src/middleware/cors.js +44 -0
  198. package/dist/src/middleware/index.js +22 -0
  199. package/dist/src/middleware/request-trace.js +96 -0
  200. package/dist/src/mobile.android.evidence.contract.test.js +146 -0
  201. package/dist/src/mobile.android.signing.contract.test.js +66 -0
  202. package/dist/src/mobile.artifact.contract.test.js +144 -0
  203. package/dist/src/mobile.budget.contract.test.js +90 -0
  204. package/dist/src/mobile.canonical-id.readiness.test.js +54 -0
  205. package/dist/src/mobile.graph.parity.contract.test.js +207 -0
  206. package/dist/src/mobile.identity.contract.test.js +66 -0
  207. package/dist/src/mobile.identity.corpus.manifest.test.js +72 -0
  208. package/dist/src/mobile.identity.corpus.test.js +40 -0
  209. package/dist/src/mobile.native.recovery.contract.test.js +64 -0
  210. package/dist/src/mobile.pipeline.test.js +11 -1
  211. package/dist/src/mobile.profile.contract.test.js +225 -0
  212. package/dist/src/mobile.semantic.parity.test.js +92 -0
  213. package/dist/src/mobile_exact_analyzer.test.js +113 -0
  214. package/dist/src/notemd/AppConfigToml.js +6 -4
  215. package/dist/src/notemd/ContentGenerator.js +4 -9
  216. package/dist/src/notemd/FileProcessor.js +4 -9
  217. package/dist/src/notemd/MermaidProcessor.js +400 -50
  218. package/dist/src/notemd/NotemdService.js +506 -26
  219. package/dist/src/notemd/PromptManager.js +15 -0
  220. package/dist/src/notemd/Translator.js +4 -9
  221. package/dist/src/notemd/cli/commands.js +357 -0
  222. package/dist/src/notemd/cli/dispatcher.js +225 -0
  223. package/dist/src/notemd/cli/index.js +169 -0
  224. package/dist/src/notemd/cli/parser.js +68 -0
  225. package/dist/src/notemd/cli/types.js +2 -0
  226. package/dist/src/notemd/constants.js +43 -0
  227. package/dist/src/notemd/diagram/diagramGenerationService.js +78 -0
  228. package/dist/src/notemd/diagram/diagramSpec.js +79 -0
  229. package/dist/src/notemd/diagram/diagramSpecResponseParser.js +131 -0
  230. package/dist/src/notemd/diagram/intent.js +95 -0
  231. package/dist/src/notemd/diagram/planner.js +71 -0
  232. package/dist/src/notemd/diagram/prompts/diagramSpecPrompt.js +42 -0
  233. package/dist/src/notemd/diagram/types.js +18 -0
  234. package/dist/src/notemd/index.js +26 -0
  235. package/dist/src/notemd/operations/capabilityManifest.js +23 -0
  236. package/dist/src/notemd/operations/cliContracts.js +17 -0
  237. package/dist/src/notemd/operations/configProfileCommands.js +85 -0
  238. package/dist/src/notemd/operations/registry.contract.test.js +95 -0
  239. package/dist/src/notemd/operations/registry.js +991 -0
  240. package/dist/src/notemd/operations/types.js +2 -0
  241. package/dist/src/notemd/progressReporter.js +9 -0
  242. package/dist/src/notemd/providerDiagnostics.js +220 -0
  243. package/dist/src/notemd/providerProfiles.js +42 -0
  244. package/dist/src/notemd/providerTemplates.js +231 -0
  245. package/dist/src/notemd/search/DuckDuckGoProvider.js +39 -0
  246. package/dist/src/notemd/search/SearchManager.js +13 -0
  247. package/dist/src/notemd/search/SearchProvider.js +2 -0
  248. package/dist/src/notemd/search/TavilyProvider.js +44 -0
  249. package/dist/src/notemd.agent.manifest.test.js +85 -0
  250. package/dist/src/notemd.api.contract.test.js +14 -1
  251. package/dist/src/notemd.app_config_toml.test.js +2 -1
  252. package/dist/src/notemd.batch.workflow.test.js +117 -0
  253. package/dist/src/notemd.cli.e2e.test.js +136 -0
  254. package/dist/src/notemd.core.test.js +51 -0
  255. package/dist/src/notemd.diagram.pipeline.test.js +233 -0
  256. package/dist/src/notemd.providerTemplates.test.js +34 -0
  257. package/dist/src/notemd.server.integration.test.js +262 -39
  258. package/dist/src/notemd.workflow.pipeline.test.js +162 -0
  259. package/dist/src/pathbridge.handshake.contract.test.js +45 -2
  260. package/dist/src/pathbridge.host-adapter.contract.test.js +133 -0
  261. package/dist/src/pathcore.bundle.contract.test.js +8 -0
  262. package/dist/src/pathmode.background.contract.test.js +69 -0
  263. package/dist/src/pathmode.settings.api.contract.test.js +9 -0
  264. package/dist/src/pkg.sidecar.contract.test.js +9 -3
  265. package/dist/src/platform/ExportProfile.js +86 -0
  266. package/dist/src/platform/MobileBudget.js +11 -0
  267. package/dist/src/platform/PlatformCapabilities.js +59 -0
  268. package/dist/src/platform/PlatformCapabilities.test.js +36 -0
  269. package/dist/src/platform/RenderMaterializer.js +33 -0
  270. package/dist/src/platform/RenderMaterializer.test.js +32 -0
  271. package/dist/src/query_backend.external_http.integration.test.js +410 -0
  272. package/dist/src/reader_renderer.js +404 -3
  273. package/dist/src/reader_renderer.test.js +87 -0
  274. package/dist/src/release.godot.mirror.contract.test.js +97 -0
  275. package/dist/src/resources/ResourceRegistry.js +263 -0
  276. package/dist/src/resources/ResourceRegistry.test.js +97 -0
  277. package/dist/src/resources/types.js +2 -0
  278. package/dist/src/routes/agentWorkspaceDiagnostics.js +173 -0
  279. package/dist/src/routes/index.js +19 -0
  280. package/dist/src/routes/knowledge.js +981 -0
  281. package/dist/src/routes/knowledgePayload.js +185 -0
  282. package/dist/src/routes/knowledgePayload.test.js +53 -0
  283. package/dist/src/routes/markdown.js +295 -0
  284. package/dist/src/routes/notemd.js +1321 -0
  285. package/dist/src/routes/registry.contract.test.js +133 -0
  286. package/dist/src/routes/registry.shadow.contract.test.js +22 -0
  287. package/dist/src/routes/render.js +248 -0
  288. package/dist/src/routes/runtimeRunbookRouteOps.js +149 -0
  289. package/dist/src/routes/runtimeRunbookRouteOps.test.js +194 -0
  290. package/dist/src/routes/settings.js +6 -0
  291. package/dist/src/routes/staticFiles.js +94 -0
  292. package/dist/src/routes/types.js +2 -0
  293. package/dist/src/runtime.capabilities.test.js +18 -2
  294. package/dist/src/runtime.transport.adapter.contract.test.js +81 -0
  295. package/dist/src/server.js +10342 -1325
  296. package/dist/src/server.migration.test.js +584 -10
  297. package/dist/src/server.port.fallback.contract.test.js +63 -0
  298. package/dist/src/session/SessionStateStore.js +81 -0
  299. package/dist/src/session/SessionStateStore.test.js +58 -0
  300. package/dist/src/session/types.js +2 -0
  301. package/dist/src/settings.runtime.contract.test.js +50 -0
  302. package/dist/src/shared/types.contract.test.js +107 -0
  303. package/dist/src/shared/types.js +22 -0
  304. package/dist/src/sidecar.build.lock.contract.test.js +201 -0
  305. package/dist/src/sidecar.freshness.contract.test.js +184 -0
  306. package/dist/src/sidecar.replacement.boundary.contract.test.js +131 -0
  307. package/dist/src/sidecar.supply.readiness.contract.test.js +155 -0
  308. package/dist/src/simulation.worker.offline.test.js +104 -0
  309. package/dist/src/source_manager.loadflow.test.js +46 -0
  310. package/dist/src/startup.layout.snapshot.contract.test.js +57 -0
  311. package/dist/src/storage.provider.capacitor.content.contract.test.js +4 -1
  312. package/dist/src/storage.provider.contract.test.js +152 -1
  313. package/dist/src/tauri.frontend.build.contract.test.js +68 -0
  314. package/dist/src/tauri.sidecar.cleanup.contract.test.js +21 -0
  315. package/dist/src/tauri.window.evidence.execution.test.js +68 -0
  316. package/dist/src/utils/RuntimePaths.js +10 -13
  317. package/dist/src/utils/RuntimePaths.test.js +27 -0
  318. package/dist/src/utils/platform.js +153 -0
  319. package/dist/src/windows.installer.build.test.js +109 -0
  320. package/dist/src/windows.installer.payload.test.js +76 -0
  321. package/dist/src/windows.installer.runtime.test.js +69 -0
  322. package/dist/src/workflows/WorkflowArtifactStore.js +96 -0
  323. package/dist/src/workflows/WorkflowArtifactStore.test.js +80 -0
  324. package/dist/src/workflows/types.js +2 -0
  325. package/dist/src/workspace/WorkspaceRegistry.js +135 -0
  326. package/dist/src/workspace/WorkspaceRegistry.test.js +29 -0
  327. package/dist/src/workspace/types.js +2 -0
  328. package/package.json +80 -15
@@ -43,38 +43,39 @@ const FileProcessor_1 = require("./FileProcessor");
43
43
  const FormulaFixer_1 = require("./FormulaFixer");
44
44
  const MermaidProcessor_1 = require("./MermaidProcessor");
45
45
  const Translator_1 = require("./Translator");
46
+ const SearchManager_1 = require("./search/SearchManager");
47
+ const diagramGenerationService_1 = require("./diagram/diagramGenerationService");
48
+ const LlmProvider_1 = require("./LlmProvider");
46
49
  const types_1 = require("./types");
47
- function defaultReporter() {
48
- return {
49
- report: () => undefined,
50
- isCancelled: () => false,
51
- };
52
- }
50
+ const progressReporter_1 = require("./progressReporter");
53
51
  class NotemdService {
54
- constructor(fileProcessor = new FileProcessor_1.FileProcessor(), translator = new Translator_1.Translator(), contentGenerator = new ContentGenerator_1.ContentGenerator(), mermaidProcessor = new MermaidProcessor_1.MermaidProcessor(), formulaFixer = new FormulaFixer_1.FormulaFixer(), duplicateDetector = new DuplicateDetector_1.DuplicateDetector()) {
52
+ constructor(fileProcessor = new FileProcessor_1.FileProcessor(), translator = new Translator_1.Translator(), contentGenerator = new ContentGenerator_1.ContentGenerator(), mermaidProcessor = new MermaidProcessor_1.MermaidProcessor(), formulaFixer = new FormulaFixer_1.FormulaFixer(), duplicateDetector = new DuplicateDetector_1.DuplicateDetector(), llmProviderClient = new LlmProvider_1.LlmProviderClient()) {
53
+ // ── Batch progress tracking ──
54
+ this.batchOperations = new Map();
55
55
  this.fileProcessor = fileProcessor;
56
56
  this.translator = translator;
57
57
  this.contentGenerator = contentGenerator;
58
58
  this.mermaidProcessor = mermaidProcessor;
59
59
  this.formulaFixer = formulaFixer;
60
60
  this.duplicateDetector = duplicateDetector;
61
+ this.llmProviderClient = llmProviderClient;
61
62
  }
62
- processFile(request, settings, reporter = defaultReporter(), signal) {
63
+ processFile(request, settings, reporter = (0, progressReporter_1.createNoopProgressReporter)(), signal) {
63
64
  return this.fileProcessor.processFile(request, settings, reporter, signal);
64
65
  }
65
- processFolder(request, settings, reporter = defaultReporter(), signal) {
66
+ processFolder(request, settings, reporter = (0, progressReporter_1.createNoopProgressReporter)(), signal) {
66
67
  return this.fileProcessor.processFolder(request, settings, reporter, signal);
67
68
  }
68
- translateFile(request, settings, reporter = defaultReporter(), signal) {
69
+ translateFile(request, settings, reporter = (0, progressReporter_1.createNoopProgressReporter)(), signal) {
69
70
  return this.translator.translateFile(request, settings, reporter, signal);
70
71
  }
71
- translateFolder(folderPath, targetLanguage, settings, reporter = defaultReporter(), signal) {
72
+ translateFolder(folderPath, targetLanguage, settings, reporter = (0, progressReporter_1.createNoopProgressReporter)(), signal) {
72
73
  return this.translator.translateFolder(folderPath, targetLanguage, settings, reporter, signal);
73
74
  }
74
- generateContent(title, context, settings, reporter = defaultReporter(), signal) {
75
+ generateContent(title, context, settings, reporter = (0, progressReporter_1.createNoopProgressReporter)(), signal) {
75
76
  return this.contentGenerator.generateFromTitle({ title, context }, settings, reporter, signal);
76
77
  }
77
- generateFolderContent(folderPath, settings, reporter = defaultReporter(), signal) {
78
+ generateFolderContent(folderPath, settings, reporter = (0, progressReporter_1.createNoopProgressReporter)(), signal) {
78
79
  return this.contentGenerator.generateFolderFromTitles(folderPath, settings, reporter, signal);
79
80
  }
80
81
  async batchFixMermaid(folderPath, inPlace = true) {
@@ -129,6 +130,51 @@ class NotemdService {
129
130
  content: fixed.content,
130
131
  };
131
132
  }
133
+ async batchFixFormulas(folderPath, inPlace = true) {
134
+ const resolvedFolderPath = path.resolve(String(folderPath || '').trim());
135
+ const stats = await fs.promises.stat(resolvedFolderPath);
136
+ if (!stats.isDirectory())
137
+ throw new types_1.ValidationError(`Not a directory: ${resolvedFolderPath}`);
138
+ const files = await this.collectTextFiles(resolvedFolderPath);
139
+ const results = [];
140
+ for (const filePath of files) {
141
+ const result = await this.fixFormulas(filePath, inPlace);
142
+ results.push({
143
+ sourcePath: filePath,
144
+ modified: result.changed,
145
+ replacementCount: result.fixes.length
146
+ });
147
+ }
148
+ return {
149
+ folderPath: resolvedFolderPath,
150
+ totalFiles: files.length,
151
+ fixedFiles: results.filter(r => r.modified).length,
152
+ results
153
+ };
154
+ }
155
+ async collectTextFiles(rootDir) {
156
+ const results = [];
157
+ const queue = [rootDir];
158
+ while (queue.length > 0) {
159
+ const current = queue.shift();
160
+ if (!current)
161
+ continue;
162
+ const entries = await fs.promises.readdir(current, { withFileTypes: true });
163
+ for (const entry of entries) {
164
+ const fullPath = path.join(current, entry.name);
165
+ if (entry.isDirectory()) {
166
+ queue.push(fullPath);
167
+ continue;
168
+ }
169
+ if (!entry.isFile())
170
+ continue;
171
+ if (!constants_1.NOTEMD_SUPPORTED_TEXT_EXTENSIONS.has(path.extname(fullPath).toLowerCase()))
172
+ continue;
173
+ results.push(fullPath);
174
+ }
175
+ }
176
+ return results.sort((a, b) => a.localeCompare(b));
177
+ }
132
178
  async checkDuplicates(filePath) {
133
179
  const resolvedPath = path.resolve(String(filePath || '').trim());
134
180
  if (!resolvedPath) {
@@ -141,7 +187,7 @@ class NotemdService {
141
187
  duplicateWikiLinks: this.duplicateDetector.detectDuplicateWikiLinks(source),
142
188
  };
143
189
  }
144
- async extractConcepts(filePath, settings, reporter = defaultReporter(), signal) {
190
+ async extractConcepts(filePath, settings, reporter = (0, progressReporter_1.createNoopProgressReporter)(), signal) {
145
191
  const resolvedPath = path.resolve(String(filePath || '').trim());
146
192
  if (!resolvedPath) {
147
193
  throw new types_1.ValidationError('Missing filePath.');
@@ -153,26 +199,460 @@ class NotemdService {
153
199
  concepts: Array.from(concepts).sort((a, b) => a.localeCompare(b)),
154
200
  };
155
201
  }
156
- async oneClickExtract(filePath, settings, reporter = defaultReporter(), signal) {
157
- const resolvedPath = path.resolve(String(filePath || '').trim());
158
- if (!resolvedPath) {
202
+ // ── Workflow Pipeline (NoteConnection native) ──
203
+ async runWorkflow(request, settings, reporter = (0, progressReporter_1.createNoopProgressReporter)(), signal) {
204
+ const resolvedPath = path.resolve(String(request.filePath || '').trim());
205
+ if (!resolvedPath)
159
206
  throw new types_1.ValidationError('Missing filePath.');
160
- }
161
- const source = await fs.promises.readFile(resolvedPath, 'utf8');
162
- const concepts = Array.from(await this.fileProcessor.extractConceptsFromText(source, settings, reporter, signal)).sort((a, b) => a.localeCompare(b));
163
- const outputFolderPath = path.join(this.resolveKnowledgeBaseRootForFile(resolvedPath), path.basename(resolvedPath, path.extname(resolvedPath)));
207
+ const startedAt = Date.now();
208
+ const stages = [];
209
+ const errors = [];
210
+ const ext = path.extname(resolvedPath);
211
+ const baseName = path.basename(resolvedPath, ext);
212
+ const outputFolderPath = request.outputFolderPath
213
+ ? path.resolve(request.outputFolderPath)
214
+ : path.join(path.dirname(resolvedPath), `${baseName}_notemd_output`);
164
215
  await fs.promises.mkdir(outputFolderPath, { recursive: true });
165
- await this.scaffoldConceptFiles(outputFolderPath, concepts);
166
- const generated = await this.contentGenerator.generateFolderFromTitles(outputFolderPath, settings, reporter, signal);
167
- const mermaid = await this.batchFixMermaid(outputFolderPath, true);
216
+ const enableWikilinks = request.addWikiLinks === true;
217
+ const enableGenerate = !request.skipGenerate;
218
+ const enableMermaid = !request.skipMermaidFix;
219
+ const totalStages = 1 + (enableWikilinks ? 1 : 0) + (enableGenerate ? 1 : 0) + (enableMermaid ? 1 : 0);
220
+ let stageNum = 0;
221
+ // Stage 1: Extract Concepts
222
+ stageNum += 1;
223
+ stages.push({ stage: 'extract-concepts', status: 'running', percent: 0, message: 'Extracting concepts from source...' });
224
+ reporter.report({ type: 'status', message: `[${stageNum}/${totalStages}] Extracting concepts from ${baseName}${ext}`, percent: Math.floor((stageNum - 1) / totalStages * 100), operationId: 'workflow-extract' });
225
+ let concepts = [];
226
+ let sourceContent = '';
227
+ try {
228
+ sourceContent = await fs.promises.readFile(resolvedPath, 'utf8');
229
+ concepts = Array.from(await this.fileProcessor.extractConceptsFromText(sourceContent, settings, reporter, signal)).sort((a, b) => a.localeCompare(b));
230
+ await this.scaffoldConceptFiles(outputFolderPath, concepts);
231
+ stages[0] = { stage: 'extract-concepts', status: 'completed', percent: 100, message: `Extracted ${concepts.length} concepts`, details: { count: concepts.length, concepts } };
232
+ reporter.report({ type: 'status', message: `[${stageNum}/${totalStages}] ✓ Extracted ${concepts.length} concepts`, percent: Math.floor(stageNum / totalStages * 100), operationId: 'workflow-extract' });
233
+ }
234
+ catch (e) {
235
+ const msg = e instanceof Error ? e.message : String(e);
236
+ stages[0] = { stage: 'extract-concepts', status: 'error', percent: 100, message: msg };
237
+ errors.push(`extract-concepts: ${msg}`);
238
+ reporter.report({ type: 'error', message: `[${stageNum}/${totalStages}] ✕ Concept extraction failed: ${msg}`, percent: Math.floor(stageNum / totalStages * 100), operationId: 'workflow-extract' });
239
+ }
240
+ // Stage 2 (optional): Add Wiki-Links to source
241
+ let wikiLinkCount = 0;
242
+ if (enableWikilinks && concepts.length > 0) {
243
+ stageNum += 1;
244
+ stages.push({ stage: 'add-wikilinks', status: 'running', percent: 0, message: 'Adding wiki-links to source...' });
245
+ reporter.report({ type: 'status', message: `[${stageNum}/${totalStages}] Adding [[wiki-links]] for ${concepts.length} concepts`, percent: Math.floor((stageNum - 1) / totalStages * 100), operationId: 'workflow-wikilinks' });
246
+ try {
247
+ const injected = this.fileProcessor.injectWikiLinks(sourceContent, concepts);
248
+ wikiLinkCount = injected.linkCount;
249
+ // Write wikified output: in-place or _wikified copy
250
+ let wikifiedPath;
251
+ if (request.wikiLinksInPlace) {
252
+ wikifiedPath = resolvedPath;
253
+ }
254
+ else {
255
+ wikifiedPath = path.join(path.dirname(resolvedPath), `${baseName}_wikified${ext}`);
256
+ }
257
+ await fs.promises.writeFile(wikifiedPath, injected.content, 'utf8');
258
+ stages.push({ stage: 'add-wikilinks', status: 'completed', percent: 100, message: `Added ${wikiLinkCount} wiki-links`, details: { linkCount: wikiLinkCount, outputPath: wikifiedPath, inPlace: !!request.wikiLinksInPlace } });
259
+ reporter.report({ type: 'status', message: `[${stageNum}/${totalStages}] ✓ Added ${wikiLinkCount} wiki-links → ${path.basename(wikifiedPath)}`, percent: Math.floor(stageNum / totalStages * 100), operationId: 'workflow-wikilinks' });
260
+ }
261
+ catch (e) {
262
+ const msg = e instanceof Error ? e.message : String(e);
263
+ stages.push({ stage: 'add-wikilinks', status: 'error', percent: 100, message: msg });
264
+ errors.push(`add-wikilinks: ${msg}`);
265
+ reporter.report({ type: 'error', message: `[${stageNum}/${totalStages}] ✕ Wiki-link injection failed: ${msg}`, percent: Math.floor(stageNum / totalStages * 100), operationId: 'workflow-wikilinks' });
266
+ }
267
+ }
268
+ else if (enableWikilinks && concepts.length === 0) {
269
+ stageNum += 1;
270
+ stages.push({ stage: 'add-wikilinks', status: 'skipped', percent: 100, message: 'No concepts to link', details: { linkCount: 0 } });
271
+ }
272
+ // Stage 3 (optional): Generate from Titles
273
+ let generated = { totalFiles: 0, generatedFiles: 0, failedFiles: 0, outputs: [] };
274
+ if (enableGenerate) {
275
+ stageNum += 1;
276
+ stages.push({ stage: 'generate-titles', status: 'running', percent: 0, message: 'Generating content from titles...' });
277
+ reporter.report({ type: 'status', message: `[${stageNum}/${totalStages}] Generating content from titles in ${path.basename(outputFolderPath)}`, percent: Math.floor((stageNum - 1) / totalStages * 100), operationId: 'workflow-generate' });
278
+ try {
279
+ generated = await this.contentGenerator.generateFolderFromTitles(outputFolderPath, settings, reporter, signal);
280
+ stages.push({ stage: 'generate-titles', status: 'completed', percent: 100, message: `Generated ${generated.generatedFiles}/${generated.totalFiles} files`, details: { totalFiles: generated.totalFiles, generatedFiles: generated.generatedFiles, failedFiles: generated.failedFiles, outputs: generated.outputs } });
281
+ reporter.report({ type: 'status', message: `[${stageNum}/${totalStages}] ✓ Generated ${generated.generatedFiles}/${generated.totalFiles} files`, percent: Math.floor(stageNum / totalStages * 100), operationId: 'workflow-generate' });
282
+ }
283
+ catch (e) {
284
+ const msg = e instanceof Error ? e.message : String(e);
285
+ stages.push({ stage: 'generate-titles', status: 'error', percent: 100, message: msg });
286
+ errors.push(`generate-titles: ${msg}`);
287
+ reporter.report({ type: 'error', message: `[${stageNum}/${totalStages}] ✕ Content generation failed: ${msg}`, percent: Math.floor(stageNum / totalStages * 100), operationId: 'workflow-generate' });
288
+ }
289
+ }
290
+ // Stage 4 (optional): Mermaid Fix
291
+ let mermaid = { folderPath: outputFolderPath, totalFiles: 0, fixedFiles: 0, results: [] };
292
+ if (enableMermaid) {
293
+ stageNum += 1;
294
+ stages.push({ stage: 'mermaid-fix', status: 'running', percent: 0, message: 'Fixing Mermaid diagrams...' });
295
+ reporter.report({ type: 'status', message: `[${stageNum}/${totalStages}] Fixing Mermaid diagrams in ${path.basename(outputFolderPath)}`, percent: Math.floor((stageNum - 1) / totalStages * 100), operationId: 'workflow-mermaid' });
296
+ try {
297
+ mermaid = await this.batchFixMermaid(outputFolderPath, true);
298
+ stages.push({ stage: 'mermaid-fix', status: 'completed', percent: 100, message: `Fixed ${mermaid.fixedFiles}/${mermaid.totalFiles} files`, details: { fixedFiles: mermaid.fixedFiles, totalFiles: mermaid.totalFiles, results: mermaid.results } });
299
+ reporter.report({ type: 'status', message: `[${stageNum}/${totalStages}] ✓ Fixed ${mermaid.fixedFiles}/${mermaid.totalFiles} Mermaid diagrams`, percent: 100, operationId: 'workflow-mermaid' });
300
+ }
301
+ catch (e) {
302
+ const msg = e instanceof Error ? e.message : String(e);
303
+ stages.push({ stage: 'mermaid-fix', status: 'error', percent: 100, message: msg });
304
+ errors.push(`mermaid-fix: ${msg}`);
305
+ reporter.report({ type: 'error', message: `[${stageNum}/${totalStages}] ✕ Mermaid fix failed: ${msg}`, percent: 100, operationId: 'workflow-mermaid' });
306
+ }
307
+ }
308
+ reporter.report({ type: 'done', message: `Workflow complete for ${baseName}${ext}`, percent: 100, operationId: 'workflow' });
168
309
  return {
169
310
  sourceFilePath: resolvedPath,
170
311
  outputFolderPath,
312
+ stages,
313
+ summary: {
314
+ conceptsExtracted: concepts.length,
315
+ wikiLinksAdded: wikiLinkCount,
316
+ titlesGenerated: generated.generatedFiles,
317
+ titlesFailed: generated.failedFiles,
318
+ mermaidFilesFixed: mermaid.fixedFiles,
319
+ totalElapsedMs: Date.now() - startedAt,
320
+ },
321
+ errors,
322
+ };
323
+ }
324
+ async runBatchWorkflow(request, settings, reporter = (0, progressReporter_1.createNoopProgressReporter)(), signal) {
325
+ const resolvedFolderPath = path.resolve(String(request.folderPath || '').trim());
326
+ if (!resolvedFolderPath)
327
+ throw new types_1.ValidationError('Missing folderPath.');
328
+ const startedAt = Date.now();
329
+ const stats = await fs.promises.stat(resolvedFolderPath);
330
+ if (!stats.isDirectory())
331
+ throw new types_1.ValidationError(`Not a directory: ${resolvedFolderPath}`);
332
+ const outputBase = request.outputBasePath
333
+ ? path.resolve(request.outputBasePath)
334
+ : path.join(resolvedFolderPath, '_notemd_batch_output');
335
+ await fs.promises.mkdir(outputBase, { recursive: true });
336
+ reporter.report({ type: 'status', message: `Scanning ${resolvedFolderPath} for matching files...`, percent: 0, operationId: 'batch-workflow' });
337
+ // Collect matching files
338
+ let files = await this.collectTextFiles(resolvedFolderPath);
339
+ // Apply extension filter
340
+ if (request.fileExtensions && request.fileExtensions.length > 0) {
341
+ const exts = new Set(request.fileExtensions.map(e => e.toLowerCase()));
342
+ files = files.filter(f => exts.has(path.extname(f).toLowerCase()));
343
+ }
344
+ // Apply regex pattern filter
345
+ if (request.filePattern) {
346
+ try {
347
+ const regex = new RegExp(request.filePattern, 'i');
348
+ files = files.filter(f => regex.test(path.basename(f)));
349
+ }
350
+ catch {
351
+ throw new types_1.ValidationError(`Invalid regex pattern: ${request.filePattern}`);
352
+ }
353
+ }
354
+ // Limit files
355
+ if (request.maxFiles && request.maxFiles > 0) {
356
+ files = files.slice(0, request.maxFiles);
357
+ }
358
+ const totalFiles = files.length;
359
+ reporter.report({ type: 'status', message: `Found ${totalFiles} matching files. Starting batch workflow...`, percent: 5, operationId: 'batch-workflow' });
360
+ const results = [];
361
+ const errors = [];
362
+ for (let i = 0; i < files.length; i++) {
363
+ if (signal?.aborted)
364
+ break;
365
+ const filePath = files[i];
366
+ const fileBaseName = path.basename(filePath, path.extname(filePath));
367
+ const baseProgress = 5 + Math.floor((i / files.length) * 90);
368
+ reporter.report({
369
+ type: 'status',
370
+ message: `[${i + 1}/${totalFiles}] Processing ${path.basename(filePath)}...`,
371
+ percent: baseProgress,
372
+ operationId: 'batch-workflow'
373
+ });
374
+ try {
375
+ const fileOutputFolder = path.join(outputBase, fileBaseName);
376
+ const result = await this.runWorkflow({
377
+ filePath,
378
+ outputFolderPath: fileOutputFolder,
379
+ language: request.language,
380
+ skipGenerate: request.skipGenerate,
381
+ skipMermaidFix: request.skipMermaidFix,
382
+ }, settings, reporter, signal);
383
+ results.push(result);
384
+ }
385
+ catch (e) {
386
+ const msg = e instanceof Error ? e.message : String(e);
387
+ errors.push({ filePath, error: msg });
388
+ reporter.report({ type: 'error', message: `Failed ${path.basename(filePath)}: ${msg}`, percent: baseProgress, operationId: 'batch-workflow' });
389
+ }
390
+ }
391
+ reporter.report({ type: 'done', message: `Batch workflow complete: ${results.length}/${totalFiles} files processed`, percent: 100, operationId: 'batch-workflow' });
392
+ return {
393
+ folderPath: resolvedFolderPath,
394
+ outputBasePath: outputBase,
395
+ filter: { pattern: request.filePattern, extensions: request.fileExtensions },
396
+ totalFiles,
397
+ completedFiles: results.length,
398
+ failedFiles: errors.length,
399
+ results,
400
+ errors,
401
+ totalElapsedMs: Date.now() - startedAt,
402
+ };
403
+ }
404
+ // Backward-compatible wrapper — uses knowledge-base-root-relative output path
405
+ async oneClickExtract(filePath, settings, reporter = (0, progressReporter_1.createNoopProgressReporter)(), signal) {
406
+ const resolvedPath = path.resolve(String(filePath || '').trim());
407
+ const kbRoot = this.resolveKnowledgeBaseRootForFile(resolvedPath);
408
+ const outputFolderPath = path.join(kbRoot, path.basename(resolvedPath, path.extname(resolvedPath)));
409
+ const result = await this.runWorkflow({
410
+ filePath: resolvedPath,
411
+ outputFolderPath,
412
+ }, settings, reporter, signal);
413
+ const findStage = (name) => [...result.stages].reverse().find(s => s.stage === name);
414
+ const conceptsStage = findStage('extract-concepts');
415
+ const concepts = (conceptsStage?.status === 'completed' && conceptsStage?.details?.concepts)
416
+ ? conceptsStage.details.concepts
417
+ : [];
418
+ const genStage = findStage('generate-titles');
419
+ const genDetails = (genStage?.details || {});
420
+ const mermaidStage = findStage('mermaid-fix');
421
+ const mermaidDetails = (mermaidStage?.details || {});
422
+ return {
423
+ sourceFilePath: resolvedPath,
424
+ outputFolderPath: result.outputFolderPath,
171
425
  concepts,
172
- generated,
173
- mermaid,
426
+ generated: {
427
+ totalFiles: genDetails.totalFiles || 0,
428
+ generatedFiles: genDetails.generatedFiles || 0,
429
+ failedFiles: genDetails.failedFiles || 0,
430
+ outputs: genDetails.outputs || [],
431
+ },
432
+ mermaid: {
433
+ folderPath: result.outputFolderPath,
434
+ totalFiles: mermaidDetails.totalFiles || 0,
435
+ fixedFiles: mermaidDetails.fixedFiles || 0,
436
+ results: mermaidDetails.results || [],
437
+ },
438
+ };
439
+ }
440
+ // ── Diagram generation (obsidian-notemd v1.8.4) ──
441
+ async generateDiagram(request, settings, llmInvoker) {
442
+ const content = String(request.content || '').trim();
443
+ if (!content)
444
+ throw new types_1.ValidationError('Missing content for diagram generation.');
445
+ const intent = (request.intent || 'mermaid');
446
+ const compatMode = (request.compatibilityMode ?? settings.experimentalDiagramCompatibilityMode ?? 'legacy-mermaid');
447
+ const errors = [];
448
+ if (llmInvoker) {
449
+ try {
450
+ const result = await (0, diagramGenerationService_1.generateDiagramArtifact)(content, {
451
+ compatibilityMode: compatMode,
452
+ requestedIntent: intent,
453
+ targetLanguage: undefined,
454
+ llmInvoker
455
+ });
456
+ return {
457
+ diagramType: result.spec.intent,
458
+ spec: JSON.stringify(result.spec, null, 2),
459
+ mermaidCode: result.mermaidContent,
460
+ renderErrors: result.renderError ? [result.renderError] : [],
461
+ intent: result.spec.intent,
462
+ generatedAt: new Date().toISOString(),
463
+ };
464
+ }
465
+ catch (error) {
466
+ errors.push(error instanceof Error ? error.message : String(error));
467
+ }
468
+ }
469
+ // Fallback: basic Mermaid fix without LLM
470
+ const fixed = this.mermaidProcessor.fixInMarkdown(content);
471
+ return {
472
+ diagramType: intent,
473
+ spec: content,
474
+ mermaidCode: fixed.changed ? fixed.content : content,
475
+ renderErrors: fixed.changed ? ['Auto-fixed Mermaid syntax errors detected.', ...errors] : errors,
476
+ intent,
477
+ generatedAt: new Date().toISOString(),
478
+ };
479
+ }
480
+ async previewDiagram(request, _settings) {
481
+ const content = String(request.content || '').trim();
482
+ if (!content)
483
+ throw new types_1.ValidationError('Missing content for diagram preview.');
484
+ const fmt = request.format || 'png';
485
+ const fixed = this.mermaidProcessor.fixInMarkdown(content);
486
+ const errors = fixed.changed ? ['Mermaid syntax was auto-fixed in preview.'] : [];
487
+ return {
488
+ format: fmt,
489
+ dataUrl: '',
490
+ errors,
491
+ };
492
+ }
493
+ async exportDiagram(request, _settings) {
494
+ const content = String(request.content || '').trim();
495
+ if (!content)
496
+ throw new types_1.ValidationError('Missing content for diagram export.');
497
+ const outputPath = request.outputPath || '';
498
+ return {
499
+ outputPath,
500
+ format: request.format || 'png',
501
+ size: Buffer.byteLength(content, 'utf8'),
502
+ };
503
+ }
504
+ // ── Search (obsidian-notemd v1.8.4) ──
505
+ async search(request, settings) {
506
+ const query = String(request.query || '').trim();
507
+ if (!query) {
508
+ throw new types_1.ValidationError('Missing query for search.');
509
+ }
510
+ const provider = SearchManager_1.SearchManager.getProvider(request.provider || settings.searchProvider || 'duckduckgo');
511
+ let apiKey;
512
+ if (provider.name === 'tavily') {
513
+ apiKey = settings.tavilyApiKey;
514
+ if (!apiKey)
515
+ throw new types_1.ValidationError('Tavily API key is required in settings.');
516
+ }
517
+ const results = await provider.search({
518
+ query,
519
+ maxResults: request.maxResults ?? settings.tavilyMaxResults ?? 5,
520
+ searchDepth: request.searchDepth ?? settings.tavilySearchDepth ?? 'basic'
521
+ }, apiKey, settings.ddgFetchTimeout ?? 10000);
522
+ return {
523
+ query,
524
+ provider: provider.name,
525
+ results,
526
+ totalResults: results.length,
527
+ searchedAt: new Date().toISOString(),
528
+ };
529
+ }
530
+ // ── LLM diagnostics (obsidian-notemd v1.8.4) ──
531
+ async diagnoseLlmProvider(request, settings, llmCallImpl) {
532
+ const providerName = request.provider || settings.activeProvider || 'unknown';
533
+ const modelName = request.model || settings.providers.find(p => p.name === providerName)?.model || 'unknown';
534
+ const provider = settings.providers.find(p => p.name === providerName);
535
+ if (!provider)
536
+ throw new types_1.ValidationError(`Provider not found: ${providerName}`);
537
+ if (!llmCallImpl)
538
+ throw new types_1.ValidationError('LLM call implementation required for diagnostics.');
539
+ const startMs = Date.now();
540
+ try {
541
+ const { buildDefaultProviderDiagnosticPayload } = await Promise.resolve().then(() => __importStar(require('./providerDiagnostics')));
542
+ const payload = buildDefaultProviderDiagnosticPayload(providerName);
543
+ await llmCallImpl(provider, payload.prompt, payload.content, { ...settings, enableApiErrorDebugMode: true, enableStableApiCall: true });
544
+ return { provider: providerName, model: modelName, status: 'ok', latencyMs: Date.now() - startMs };
545
+ }
546
+ catch (e) {
547
+ const msg = e instanceof Error ? e.message : String(e);
548
+ return { provider: providerName, model: modelName, status: 'error', latencyMs: Date.now() - startMs, error: msg };
549
+ }
550
+ }
551
+ async testLlmConnection(request, settings) {
552
+ const requestedProvider = request && typeof request.provider === 'object'
553
+ ? request.provider
554
+ : null;
555
+ const requestedProviderName = String((request && typeof request.providerName === 'string' ? request.providerName : '') ||
556
+ (requestedProvider && typeof requestedProvider.name === 'string' ? requestedProvider.name : '') ||
557
+ settings.activeProvider ||
558
+ '').trim();
559
+ const persistedProvider = settings.providers.find((provider) => provider.name === requestedProviderName);
560
+ if (!persistedProvider && !requestedProvider) {
561
+ throw new types_1.ValidationError(`Provider not found: ${requestedProviderName || settings.activeProvider}`);
562
+ }
563
+ const resolvedProviderName = String((persistedProvider && persistedProvider.name) ||
564
+ requestedProviderName ||
565
+ settings.activeProvider).trim();
566
+ const provider = {
567
+ ...(persistedProvider || {
568
+ name: resolvedProviderName,
569
+ apiKey: '',
570
+ baseUrl: '',
571
+ model: '',
572
+ temperature: 0.5,
573
+ enabled: true,
574
+ }),
575
+ ...(requestedProvider ? {
576
+ name: resolvedProviderName,
577
+ apiKey: String(requestedProvider.apiKey || '').trim(),
578
+ baseUrl: String(requestedProvider.baseUrl || '').trim(),
579
+ model: String(requestedProvider.model || '').trim(),
580
+ temperature: Number.isFinite(Number(requestedProvider.temperature))
581
+ ? Number(requestedProvider.temperature)
582
+ : Number((persistedProvider && persistedProvider.temperature) || 0.5),
583
+ apiVersion: String(requestedProvider.apiVersion || '').trim(),
584
+ } : {}),
585
+ };
586
+ const result = await this.llmProviderClient.testConnection(provider);
587
+ return {
588
+ success: result.success,
589
+ message: result.message,
590
+ provider: provider.name,
591
+ model: provider.model,
174
592
  };
175
593
  }
594
+ // ── Extract original text (obsidian-notemd v1.8.4) ──
595
+ async extractOriginalText(request, _settings, _reporter = (0, progressReporter_1.createNoopProgressReporter)(), _signal) {
596
+ const resolvedPath = path.resolve(String(request.filePath || '').trim());
597
+ if (!resolvedPath)
598
+ throw new types_1.ValidationError('Missing filePath.');
599
+ const source = await fs.promises.readFile(resolvedPath, 'utf8');
600
+ const mergedMode = request.mergedMode ?? false;
601
+ const outputPath = request.outputPath || resolvedPath.replace(/\.md$/, '_original.md');
602
+ const replacedSuffixPath = resolvedPath.replace(/\.md$/, `${request.outputPath ? '' : '_original'}.md`);
603
+ const targetPath = outputPath || replacedSuffixPath;
604
+ if (targetPath !== resolvedPath) {
605
+ await fs.promises.writeFile(targetPath, source, 'utf8');
606
+ }
607
+ return {
608
+ filePath: resolvedPath,
609
+ outputPath: targetPath,
610
+ originalText: mergedMode ? source.replace(/\n/g, ' ').replace(/\[\[([^\]]+)\]\]/g, '$1') : source,
611
+ changed: targetPath !== resolvedPath,
612
+ };
613
+ }
614
+ getBatchProgress(operationId) {
615
+ if (operationId && this.batchOperations.has(operationId)) {
616
+ return this.batchOperations.get(operationId);
617
+ }
618
+ return {
619
+ operationId: operationId || '',
620
+ status: 'completed',
621
+ totalItems: 0,
622
+ completedItems: 0,
623
+ failedItems: 0,
624
+ logs: [],
625
+ percent: 100,
626
+ startedAt: new Date().toISOString(),
627
+ updatedAt: new Date().toISOString(),
628
+ };
629
+ }
630
+ startBatchOperation(operationId, totalItems) {
631
+ const progress = {
632
+ operationId,
633
+ status: 'running',
634
+ totalItems,
635
+ completedItems: 0,
636
+ failedItems: 0,
637
+ logs: [],
638
+ percent: 0,
639
+ startedAt: new Date().toISOString(),
640
+ updatedAt: new Date().toISOString(),
641
+ };
642
+ this.batchOperations.set(operationId, progress);
643
+ return progress;
644
+ }
645
+ updateBatchOperation(operationId, update) {
646
+ const existing = this.batchOperations.get(operationId);
647
+ if (!existing)
648
+ return undefined;
649
+ const updated = { ...existing, ...update, updatedAt: new Date().toISOString() };
650
+ if (updated.failedItems > 0 && updated.status === 'running') {
651
+ updated.status = 'error';
652
+ }
653
+ this.batchOperations.set(operationId, updated);
654
+ return updated;
655
+ }
176
656
  async scaffoldConceptFiles(outputFolderPath, concepts) {
177
657
  for (const concept of concepts) {
178
658
  const safeName = concept.replace(/[\\/:*?"<>|]/g, '').trim();
@@ -33,6 +33,21 @@ const DEFAULT_PROMPTS = {
33
33
  'Do not paraphrase.',
34
34
  'If none found, output: No match found in reference.',
35
35
  ].join('\n'),
36
+ extractOriginalTextMerged: [
37
+ 'For each user query, extract exact matching passages from reference content.',
38
+ 'Combine matching passages into a single merged response.',
39
+ 'Do not paraphrase. If none found, output: No match found in reference.',
40
+ ].join('\n'),
41
+ searchResearch: [
42
+ 'Research the given topic using web search results.',
43
+ 'Summarize findings in structured markdown with citations.',
44
+ 'Include key facts, different perspectives, and references.',
45
+ ].join('\n'),
46
+ ragSufficiencyJudge: [
47
+ 'Review whether the supplied RAG context is sufficient to answer the user query.',
48
+ 'Use only the supplied context and do not write the final answer.',
49
+ 'Return exactly one JSON object with status, score, reasons, and degradationState.',
50
+ ].join('\n'),
36
51
  };
37
52
  exports.DEFAULT_PROMPTS = DEFAULT_PROMPTS;
38
53
  function safeReplace(template, replacements) {
@@ -41,12 +41,7 @@ const constants_1 = require("./constants");
41
41
  const LlmProvider_1 = require("./LlmProvider");
42
42
  const PromptManager_1 = require("./PromptManager");
43
43
  const types_1 = require("./types");
44
- function defaultReporter() {
45
- return {
46
- report: () => undefined,
47
- isCancelled: () => false,
48
- };
49
- }
44
+ const progressReporter_1 = require("./progressReporter");
50
45
  function countWords(text) {
51
46
  return text
52
47
  .trim()
@@ -80,7 +75,7 @@ class Translator {
80
75
  this.promptManager = promptManager;
81
76
  this.batchProcessor = batchProcessor;
82
77
  }
83
- async translateText(content, targetLanguage, settings, reporter = defaultReporter(), signal) {
78
+ async translateText(content, targetLanguage, settings, reporter = (0, progressReporter_1.createNoopProgressReporter)(), signal) {
84
79
  const provider = (0, LlmProvider_1.selectProviderForTask)(settings, 'translate');
85
80
  const model = (0, LlmProvider_1.selectModelForTask)(settings, 'translate', provider);
86
81
  const chunks = splitByWordCount(content, settings.chunkWordCount);
@@ -117,7 +112,7 @@ class Translator {
117
112
  }
118
113
  return translatedChunks.join('\n\n').trim();
119
114
  }
120
- async translateFile(request, settings, reporter = defaultReporter(), signal) {
115
+ async translateFile(request, settings, reporter = (0, progressReporter_1.createNoopProgressReporter)(), signal) {
121
116
  const filePath = path.resolve(String(request.filePath || '').trim());
122
117
  if (!filePath) {
123
118
  throw new types_1.ValidationError('Missing filePath.');
@@ -144,7 +139,7 @@ class Translator {
144
139
  changed: translated !== source || outputPath !== filePath,
145
140
  };
146
141
  }
147
- async translateFolder(folderPath, targetLanguage, settings, reporter = defaultReporter(), signal) {
142
+ async translateFolder(folderPath, targetLanguage, settings, reporter = (0, progressReporter_1.createNoopProgressReporter)(), signal) {
148
143
  const root = path.resolve(String(folderPath || '').trim());
149
144
  const stats = await this.stat(root);
150
145
  if (!stats.isDirectory()) {