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
@@ -42,12 +42,44 @@
42
42
 
43
43
  let capacitorFsPermissionGranted = false;
44
44
  let capacitorFsPermissionPromise = null;
45
- const CAPACITOR_GRAPH_BUILD_MAX_FILES = 2000;
46
- const CAPACITOR_GRAPH_BUILD_MAX_BYTES = 16 * 1024 * 1024;
47
45
  const CAPACITOR_GRAPH_BUILD_WORKER_TIMEOUT_MS = 20000;
48
46
  const CAPACITOR_BRIDGE_MAX_CHUNK_BYTES = 192 * 1024;
49
- const CAPACITOR_BRIDGE_MAX_TEXT_PAYLOAD_BYTES = 64 * 1024 * 1024;
50
47
  const CAPACITOR_GRAPH_SERIALIZATION_MAX_BYTES = 48 * 1024 * 1024;
48
+ const CAPACITOR_BRIDGE_MAX_TEXT_PAYLOAD_BYTES = 64 * 1024 * 1024;
49
+ const FALLBACK_MOBILE_RUNTIME_BUDGET = Object.freeze({
50
+ maxDocuments: 5000,
51
+ maxDocumentBytes: 16 * 1024 * 1024,
52
+ maxTotalInputBytes: 64 * 1024 * 1024,
53
+ maxEdges: 250000,
54
+ maxDepth: 64,
55
+ maxProjectionBytes: CAPACITOR_GRAPH_SERIALIZATION_MAX_BYTES
56
+ });
57
+
58
+ function getMobileRuntimeBudget() {
59
+ const candidate = typeof window !== 'undefined' ? window.NoteConnectionMobileBudget : null;
60
+ const runtime = candidate && candidate.runtime;
61
+ if (!runtime || typeof runtime !== 'object') {
62
+ return FALLBACK_MOBILE_RUNTIME_BUDGET;
63
+ }
64
+
65
+ const keys = Object.keys(FALLBACK_MOBILE_RUNTIME_BUDGET);
66
+ const isValid = keys.every((key) => Number.isInteger(runtime[key]) && runtime[key] > 0);
67
+ return isValid ? runtime : FALLBACK_MOBILE_RUNTIME_BUDGET;
68
+ }
69
+
70
+ function measureUtf8Bytes(textPayload) {
71
+ const text = String(textPayload || '');
72
+ if (!text) {
73
+ return 0;
74
+ }
75
+ if (typeof TextEncoder === 'function') {
76
+ return new TextEncoder().encode(text).length;
77
+ }
78
+ if (typeof Buffer !== 'undefined' && typeof Buffer.byteLength === 'function') {
79
+ return Buffer.byteLength(text, 'utf8');
80
+ }
81
+ return text.length;
82
+ }
51
83
 
52
84
  function getCapacitorDirectoryHints(filesystem) {
53
85
  const directoryHints = [];
@@ -170,13 +202,40 @@
170
202
  .pop() || '';
171
203
  }
172
204
 
205
+ function canonicalMobileNodeIdFromIdentity(identity) {
206
+ const sourceUri = identity && typeof identity.sourceUri === 'string'
207
+ ? identity.sourceUri
208
+ : '';
209
+ const prefix = 'note://workspace/v1/';
210
+ if (!sourceUri.startsWith(prefix)) {
211
+ return '';
212
+ }
213
+ try {
214
+ return decodeURIComponent(sourceUri.slice(prefix.length))
215
+ .replace(/\.(?:md|markdown)$/i, '')
216
+ .trim();
217
+ } catch (_error) {
218
+ return '';
219
+ }
220
+ }
221
+
222
+ async function createMobileResourceIdentity(relativePath, legacyId, content) {
223
+ const identityContract = typeof globalThis !== 'undefined'
224
+ ? globalThis.NoteConnectionMobileIdentity
225
+ : null;
226
+ if (!identityContract || typeof identityContract.createResourceIdentity !== 'function') {
227
+ throw new Error('Mobile identity contract is unavailable.');
228
+ }
229
+ return await identityContract.createResourceIdentity(relativePath, legacyId, content);
230
+ }
231
+
173
232
  function extractWikiLinks(content) {
174
233
  const links = new Set();
175
234
  const regex = /\[\[(.*?)(?:\|.*?)?\]\]/g;
176
235
  const text = String(content || '');
177
236
  let match;
178
237
  while ((match = regex.exec(text)) !== null) {
179
- const linked = stripMarkdownExtension(match[1]);
238
+ const linked = String(match[1] || '').trim();
180
239
  if (linked) {
181
240
  links.add(linked);
182
241
  }
@@ -184,6 +243,122 @@
184
243
  return Array.from(links);
185
244
  }
186
245
 
246
+ function extractMarkdownLinks(content) {
247
+ const links = new Set();
248
+ const regex = /\]\(([^)]+)\)/g;
249
+ const text = String(content || '');
250
+ let match;
251
+ while ((match = regex.exec(text)) !== null) {
252
+ const linked = String(match[1] || '').trim();
253
+ if (linked) {
254
+ links.add(linked);
255
+ }
256
+ }
257
+ return Array.from(links);
258
+ }
259
+
260
+ function normalizeCapacitorCanonicalId(value) {
261
+ const normalized = String(value || '')
262
+ .normalize('NFC')
263
+ .replace(/\\/g, '/')
264
+ .replace(/^knowledge_base\//i, '')
265
+ .replace(/^\/+/, '')
266
+ .trim();
267
+ const segments = [];
268
+ for (const segment of normalized.split('/')) {
269
+ if (!segment || segment === '.') {
270
+ continue;
271
+ }
272
+ if (segment === '..') {
273
+ if (segments.length === 0) {
274
+ return '';
275
+ }
276
+ segments.pop();
277
+ continue;
278
+ }
279
+ segments.push(segment);
280
+ }
281
+ return segments.join('/').replace(/\.(?:md|markdown)$/i, '').toLowerCase();
282
+ }
283
+
284
+ function cleanCapacitorReference(rawReference) {
285
+ let reference = String(rawReference || '').trim();
286
+ const wikiMatch = reference.match(/^\[\[(.*?)(?:\|.*?)?\]\]$/);
287
+ if (wikiMatch) {
288
+ reference = String(wikiMatch[1] || '').trim();
289
+ }
290
+ reference = reference.replace(/^['"]|['"]$/g, '').trim();
291
+ reference = reference.split('#')[0].split('?')[0].trim();
292
+ if (!reference || /^[a-z][a-z0-9+.-]*:/i.test(reference) || reference.startsWith('/')) {
293
+ return '';
294
+ }
295
+ try {
296
+ reference = decodeURIComponent(reference);
297
+ } catch (_error) {
298
+ return '';
299
+ }
300
+ return reference;
301
+ }
302
+
303
+ function resolveCapacitorReferencePath(sourceCanonicalId, rawReference) {
304
+ const reference = cleanCapacitorReference(rawReference);
305
+ if (!reference) {
306
+ return '';
307
+ }
308
+ const direct = normalizeCapacitorCanonicalId(reference);
309
+ const sourceSegments = normalizeCapacitorCanonicalId(sourceCanonicalId).split('/').filter(Boolean);
310
+ sourceSegments.pop();
311
+ const relative = normalizeCapacitorCanonicalId([...sourceSegments, reference].join('/'));
312
+ return { direct, relative };
313
+ }
314
+
315
+ function buildCapacitorReferenceIndex(files) {
316
+ const byCanonicalId = new Map();
317
+ const byLegacyId = new Map();
318
+ const byUniqueStem = new Map();
319
+ files.forEach((file) => {
320
+ const canonicalId = normalizeCapacitorCanonicalId(
321
+ file.canonicalId || canonicalMobileNodeIdFromIdentity(file) || file.path || file.id
322
+ );
323
+ if (!file.id || !canonicalId) {
324
+ return;
325
+ }
326
+ const legacyKey = String(file.id).normalize('NFC').toLowerCase();
327
+ if (byLegacyId.has(legacyKey)) {
328
+ throw new Error(`Capacitor graph contains an ambiguous legacy basename: ${file.id}`);
329
+ }
330
+ if (byCanonicalId.has(canonicalId)) {
331
+ throw new Error(`Capacitor graph contains duplicate canonical node id: ${canonicalId}`);
332
+ }
333
+ byLegacyId.set(legacyKey, file);
334
+ byCanonicalId.set(canonicalId, file);
335
+ const stem = canonicalId.split('/').pop() || canonicalId;
336
+ const stemCandidates = byUniqueStem.get(stem) || [];
337
+ stemCandidates.push(file);
338
+ byUniqueStem.set(stem, stemCandidates);
339
+ file.__canonicalId = canonicalId;
340
+ });
341
+ return { byCanonicalId, byLegacyId, byUniqueStem };
342
+ }
343
+
344
+ function resolveCapacitorReference(sourceFile, rawReference, referenceIndex) {
345
+ const paths = resolveCapacitorReferencePath(sourceFile.__canonicalId, rawReference);
346
+ if (!paths) {
347
+ return null;
348
+ }
349
+ const direct = referenceIndex.byCanonicalId.get(paths.direct);
350
+ if (direct) {
351
+ return direct;
352
+ }
353
+ const relative = referenceIndex.byCanonicalId.get(paths.relative);
354
+ if (relative) {
355
+ return relative;
356
+ }
357
+ const stem = paths.direct.split('/').pop() || paths.direct;
358
+ const candidates = referenceIndex.byUniqueStem.get(stem) || [];
359
+ return candidates.length === 1 ? candidates[0] : null;
360
+ }
361
+
187
362
  function normalizeCapacitorPath(pathValue, options) {
188
363
  const allowCurrentDir = Boolean(options && options.allowCurrentDir);
189
364
  const normalized = String(pathValue || '').replace(/\\/g, '/').replace(/^\/+/, '');
@@ -235,6 +410,20 @@
235
410
  return null;
236
411
  }
237
412
 
413
+ function extractRelativePathFromWorkspaceUri(rawFilePath) {
414
+ const normalized = String(rawFilePath || '').replace(/\\/g, '/');
415
+ const prefix = 'note://workspace/v1/';
416
+ if (!normalized.toLowerCase().startsWith(prefix)) {
417
+ return null;
418
+ }
419
+ try {
420
+ const relative = decodeURIComponent(normalized.slice(prefix.length));
421
+ return relative.length > 0 ? relative : null;
422
+ } catch (_error) {
423
+ throw new Error('Invalid workspace source URI for Capacitor content read.');
424
+ }
425
+ }
426
+
238
427
  function resolveCapacitorContentCandidatePath(rawFilePath) {
239
428
  const raw = String(rawFilePath || '').trim();
240
429
  if (!raw) {
@@ -247,6 +436,15 @@
247
436
  return normalizeCapacitorPath(`Knowledge_Base/${relativeFromKb}`);
248
437
  }
249
438
 
439
+ const relativeFromWorkspaceUri = extractRelativePathFromWorkspaceUri(raw);
440
+ if (relativeFromWorkspaceUri) {
441
+ return normalizeCapacitorPath(`Knowledge_Base/${relativeFromWorkspaceUri}`);
442
+ }
443
+
444
+ if (/^[A-Za-z][A-Za-z0-9+.-]*:\/\//.test(normalized)) {
445
+ throw new Error('Cannot map non-workspace URI on Capacitor without Knowledge_Base marker.');
446
+ }
447
+
250
448
  if (/^[A-Za-z]:\//.test(normalized) || normalized.startsWith('/')) {
251
449
  throw new Error('Cannot map absolute desktop path on Capacitor without Knowledge_Base marker.');
252
450
  }
@@ -404,20 +602,6 @@
404
602
  }
405
603
  }
406
604
 
407
- function measureUtf8Bytes(textPayload) {
408
- const text = String(textPayload || '');
409
- if (!text) {
410
- return 0;
411
- }
412
- if (typeof TextEncoder === 'function') {
413
- return new TextEncoder().encode(text).length;
414
- }
415
- if (typeof Buffer !== 'undefined' && typeof Buffer.byteLength === 'function') {
416
- return Buffer.byteLength(text, 'utf8');
417
- }
418
- return text.length;
419
- }
420
-
421
605
  async function writeCapacitorChunkSequenceToDirectory(filesystem, normalizedPath, chunkSequenceFactory, options) {
422
606
  const directory = options && Object.prototype.hasOwnProperty.call(options, 'directory')
423
607
  ? options.directory
@@ -580,6 +764,10 @@
580
764
  const explicitDirectory = options && Object.prototype.hasOwnProperty.call(options, 'directory')
581
765
  ? options.directory
582
766
  : undefined;
767
+ const maxBytes = Math.max(
768
+ 1024,
769
+ Math.floor(Number(options && options.maxBytes) || CAPACITOR_BRIDGE_MAX_TEXT_PAYLOAD_BYTES)
770
+ );
583
771
  const directoryHints = explicitDirectory === undefined
584
772
  ? getCapacitorDirectoryHints(filesystem)
585
773
  : [explicitDirectory];
@@ -591,9 +779,41 @@
591
779
  if (directory) {
592
780
  args.directory = directory;
593
781
  }
782
+ // Stat is a preflight guard: reading an oversized note first would
783
+ // defeat the low-memory contract even if the decoded text is later rejected.
784
+ if (typeof filesystem.stat === 'function') {
785
+ try {
786
+ const statResult = await filesystem.stat(args);
787
+ const reportedBytes = Number(statResult && statResult.size);
788
+ if (Number.isFinite(reportedBytes) && reportedBytes > maxBytes) {
789
+ const budgetError = new Error(
790
+ `Capacitor file exceeds ${maxBytes} bytes: ${normalizedPath}`
791
+ );
792
+ budgetError.code = 'MOBILE_BUDGET_EXCEEDED';
793
+ throw budgetError;
794
+ }
795
+ } catch (err) {
796
+ if (err && err.code === 'MOBILE_BUDGET_EXCEEDED') {
797
+ throw err;
798
+ }
799
+ // Some Capacitor versions do not expose stat for SAF handles;
800
+ // the bounded decoded-text check below remains the fallback.
801
+ }
802
+ }
594
803
  const result = await filesystem.readFile(args);
595
- return decodeCapacitorTextPayload(result);
804
+ const text = decodeCapacitorTextPayload(result);
805
+ if (measureUtf8Bytes(text) > maxBytes) {
806
+ const budgetError = new Error(
807
+ `Capacitor file exceeds ${maxBytes} bytes: ${normalizedPath}`
808
+ );
809
+ budgetError.code = 'MOBILE_BUDGET_EXCEEDED';
810
+ throw budgetError;
811
+ }
812
+ return text;
596
813
  } catch (err) {
814
+ if (err && err.code === 'MOBILE_BUDGET_EXCEEDED') {
815
+ throw err;
816
+ }
597
817
  lastError = err;
598
818
  }
599
819
  }
@@ -704,13 +924,21 @@
704
924
  }
705
925
 
706
926
  async function collectCapacitorMarkdownFiles(targetPath) {
707
- const queue = [normalizeCapacitorPath(targetPath, { allowCurrentDir: true })];
927
+ const budget = getMobileRuntimeBudget();
928
+ const queue = [{
929
+ path: normalizeCapacitorPath(targetPath, { allowCurrentDir: true }),
930
+ depth: 0
931
+ }];
708
932
  const visited = new Set();
709
933
  const files = [];
710
934
  let totalBytes = 0;
711
935
 
712
936
  while (queue.length > 0) {
713
- const current = queue.shift();
937
+ const currentEntry = queue.shift();
938
+ const current = currentEntry && currentEntry.path;
939
+ const currentDepth = currentEntry && Number.isInteger(currentEntry.depth)
940
+ ? currentEntry.depth
941
+ : 0;
714
942
  if (!current || visited.has(current)) {
715
943
  continue;
716
944
  }
@@ -723,23 +951,47 @@
723
951
  }
724
952
 
725
953
  const looksLikeMarkdown = /\.md$/i.test(entry.name);
954
+ const entryDepth = currentDepth + 1;
955
+ if (entryDepth > budget.maxDepth) {
956
+ throw new Error(
957
+ `Capacitor local build directory depth exceeds ${budget.maxDepth}. ` +
958
+ 'Please flatten the knowledge base or build on desktop.'
959
+ );
960
+ }
726
961
  if (entry.isDirectory === true) {
727
- queue.push(entry.path);
962
+ queue.push({ path: entry.path, depth: entryDepth });
728
963
  continue;
729
964
  }
730
965
  if (entry.isDirectory === null && !looksLikeMarkdown) {
731
- queue.push(entry.path);
966
+ queue.push({ path: entry.path, depth: entryDepth });
732
967
  continue;
733
968
  }
734
969
  if (!looksLikeMarkdown) {
735
970
  continue;
736
971
  }
737
972
 
738
- const rawText = await capacitorReadText(entry.path, { directory: entry.directory });
739
- totalBytes += rawText.length;
740
- if (totalBytes > CAPACITOR_GRAPH_BUILD_MAX_BYTES) {
973
+ if (files.length >= budget.maxDocuments) {
741
974
  throw new Error(
742
- `Capacitor local build payload exceeds ${CAPACITOR_GRAPH_BUILD_MAX_BYTES} bytes. ` +
975
+ `Capacitor local build file count exceeds ${budget.maxDocuments}. ` +
976
+ 'Please build on desktop for large datasets.'
977
+ );
978
+ }
979
+
980
+ const rawText = await capacitorReadText(entry.path, {
981
+ directory: entry.directory,
982
+ maxBytes: budget.maxDocumentBytes
983
+ });
984
+ const documentBytes = measureUtf8Bytes(rawText);
985
+ if (documentBytes > budget.maxDocumentBytes) {
986
+ throw new Error(
987
+ `Capacitor local build document exceeds ${budget.maxDocumentBytes} bytes. ` +
988
+ 'Please split the note or build on desktop.'
989
+ );
990
+ }
991
+ totalBytes += documentBytes;
992
+ if (totalBytes > budget.maxTotalInputBytes) {
993
+ throw new Error(
994
+ `Capacitor local build payload exceeds ${budget.maxTotalInputBytes} bytes. ` +
743
995
  'Please build on desktop for large datasets.'
744
996
  );
745
997
  }
@@ -753,22 +1005,21 @@
753
1005
  const relativePath = entry.path;
754
1006
  const segments = relativePath.split('/').filter(Boolean);
755
1007
  const clusterId = segments.length > 1 ? segments[segments.length - 2] : 'root';
1008
+ const identity = await createMobileResourceIdentity(relativePath, filename, rawText);
756
1009
 
757
1010
  files.push({
758
1011
  id: filename,
1012
+ canonicalId: identity.canonicalId || canonicalMobileNodeIdFromIdentity(identity),
759
1013
  label: filename,
760
1014
  path: relativePath,
1015
+ sourceUri: identity.sourceUri,
1016
+ revision: identity.revision,
1017
+ identityAliases: identity.identityAliases,
761
1018
  content: rawText,
762
1019
  metadata,
763
1020
  clusterId
764
1021
  });
765
1022
 
766
- if (files.length > CAPACITOR_GRAPH_BUILD_MAX_FILES) {
767
- throw new Error(
768
- `Capacitor local build file count exceeds ${CAPACITOR_GRAPH_BUILD_MAX_FILES}. ` +
769
- 'Please build on desktop for large datasets.'
770
- );
771
- }
772
1023
  }
773
1024
  }
774
1025
 
@@ -778,6 +1029,8 @@
778
1029
  function buildCapacitorGraphData(files) {
779
1030
  const nodeMap = new Map();
780
1031
  const edgeMap = new Map();
1032
+ const sourceFiles = Array.isArray(files) ? files.filter((file) => file && file.id) : [];
1033
+ const referenceIndex = buildCapacitorReferenceIndex(sourceFiles);
781
1034
 
782
1035
  const addEdge = (source, target, type) => {
783
1036
  if (!source || !target || source === target) {
@@ -786,25 +1039,39 @@
786
1039
  if (!nodeMap.has(source) || !nodeMap.has(target)) {
787
1040
  return;
788
1041
  }
789
- const key = `${source}->${target}`;
1042
+ const edgeType = type || 'association';
1043
+ const key = `${source}->${target}:${edgeType}`;
790
1044
  if (edgeMap.has(key)) {
791
1045
  return;
792
1046
  }
1047
+ const sourceNode = nodeMap.get(source);
1048
+ const targetNode = nodeMap.get(target);
793
1049
  edgeMap.set(key, {
794
1050
  source,
795
1051
  target,
796
- type: type || 'association',
1052
+ type: edgeType,
1053
+ kind: 'explicit',
1054
+ provenance: edgeType,
1055
+ sourceUri: sourceNode && sourceNode.sourceUri ? sourceNode.sourceUri : '',
1056
+ targetUri: targetNode && targetNode.sourceUri ? targetNode.sourceUri : '',
797
1057
  weight: 1
798
1058
  });
799
1059
  };
800
1060
 
801
- files.forEach((file) => {
802
- if (!file || !file.id || nodeMap.has(file.id)) {
1061
+ sourceFiles.forEach((file) => {
1062
+ if (!file || !file.id) {
803
1063
  return;
804
1064
  }
1065
+ if (nodeMap.has(file.id)) {
1066
+ throw new Error(`Capacitor graph contains duplicate legacy node id: ${file.id}`);
1067
+ }
805
1068
  nodeMap.set(file.id, {
806
1069
  id: file.id,
1070
+ canonicalId: file.canonicalId || file.__canonicalId || '',
807
1071
  label: file.label || file.id,
1072
+ sourceUri: file.sourceUri || '',
1073
+ revision: file.revision || '',
1074
+ identityAliases: Array.isArray(file.identityAliases) ? file.identityAliases : [],
808
1075
  inDegree: 0,
809
1076
  outDegree: 0,
810
1077
  metadata: {
@@ -819,7 +1086,7 @@
819
1086
  });
820
1087
  });
821
1088
 
822
- files.forEach((file) => {
1089
+ sourceFiles.forEach((file) => {
823
1090
  const sourceId = file.id;
824
1091
  if (!nodeMap.has(sourceId)) {
825
1092
  return;
@@ -829,24 +1096,37 @@
829
1096
  ? file.metadata.prerequisites
830
1097
  : [];
831
1098
  prerequisites.forEach((rawPrereq) => {
832
- const prereqId = stripMarkdownExtension(rawPrereq);
833
- addEdge(prereqId, sourceId, 'explicit-prerequisite');
1099
+ const prerequisiteFile = resolveCapacitorReference(file, rawPrereq, referenceIndex);
1100
+ addEdge(prerequisiteFile && prerequisiteFile.id, sourceId, 'explicit-prerequisite');
834
1101
  });
835
1102
 
836
1103
  const nextItems = Array.isArray(file.metadata && file.metadata.next)
837
1104
  ? file.metadata.next
838
1105
  : [];
839
1106
  nextItems.forEach((rawNext) => {
840
- const nextId = stripMarkdownExtension(rawNext);
841
- addEdge(sourceId, nextId, 'explicit-next');
1107
+ const nextFile = resolveCapacitorReference(file, rawNext, referenceIndex);
1108
+ addEdge(sourceId, nextFile && nextFile.id, 'explicit-next');
1109
+ });
1110
+
1111
+ extractWikiLinks(file.content).forEach((rawLink) => {
1112
+ const linkedFile = resolveCapacitorReference(file, rawLink, referenceIndex);
1113
+ addEdge(sourceId, linkedFile && linkedFile.id, 'wiki-link');
842
1114
  });
843
1115
 
844
- extractWikiLinks(file.content).forEach((linkedId) => {
845
- addEdge(linkedId, sourceId, 'wiki-link');
1116
+ extractMarkdownLinks(file.content).forEach((rawLink) => {
1117
+ const linkedFile = resolveCapacitorReference(file, rawLink, referenceIndex);
1118
+ addEdge(sourceId, linkedFile && linkedFile.id, 'markdown-link');
846
1119
  });
847
1120
  });
848
1121
 
849
1122
  const edges = Array.from(edgeMap.values());
1123
+ const budget = getMobileRuntimeBudget();
1124
+ if (edges.length > budget.maxEdges) {
1125
+ throw new Error(
1126
+ `Capacitor graph edge count exceeds ${budget.maxEdges}. ` +
1127
+ 'Please reduce links or build on desktop for large datasets.'
1128
+ );
1129
+ }
850
1130
  edges.forEach((edge) => {
851
1131
  const sourceNode = nodeMap.get(edge.source);
852
1132
  const targetNode = nodeMap.get(edge.target);
@@ -889,13 +1169,78 @@
889
1169
  ' try {',
890
1170
  ' var files = Array.isArray(event.data && event.data.files) ? event.data.files : [];',
891
1171
  ' function stripMarkdownExtension(value) {',
892
- " return String(value || '')",
893
- ' .trim()',
894
- " .replace(/\\.md$/i, '')",
1172
+ ' var normalized = String(value || "").trim()',
1173
+ " .replace(/\\.(?:md|markdown)$/i, '')",
895
1174
  " .replace(/\\\\/g, '/')",
896
- " .split('/')",
897
- ' .filter(Boolean)',
898
- ' .pop() || "";',
1175
+ ' .replace(/^knowledge_base\\//i, "")',
1176
+ ' .replace(/^\\/+/, "");',
1177
+ ' var parts = [];',
1178
+ ' normalized.split("/").forEach(function(part) {',
1179
+ ' if (!part || part === ".") return;',
1180
+ ' if (part === "..") { if (parts.length > 0) parts.pop(); return; }',
1181
+ ' parts.push(part);',
1182
+ ' });',
1183
+ ' return parts.join("/").normalize("NFC").toLowerCase();',
1184
+ ' }',
1185
+ '',
1186
+ ' function cleanReference(rawReference) {',
1187
+ ' var reference = String(rawReference || "").trim();',
1188
+ ' var wikiMatch = reference.match(/^\\[\\[(.*?)(?:\\|.*?)?\\]\\]$/);',
1189
+ ' if (wikiMatch) reference = String(wikiMatch[1] || "").trim();',
1190
+ ' reference = reference.replace(/^[\'\"]|[\'\"]$/g, "").split("#")[0].split("?")[0].trim();',
1191
+ ' if (!reference || /^[a-z][a-z0-9+.-]*:/i.test(reference) || reference.charAt(0) === "/") return "";',
1192
+ ' try { return decodeURIComponent(reference); } catch (_error) { return ""; }',
1193
+ ' }',
1194
+ '',
1195
+ ' function canonicalIdFromSourceUri(file) {',
1196
+ ' var sourceUri = String(file && file.sourceUri || "");',
1197
+ ' var prefix = "note://workspace/v1/";',
1198
+ ' if (!sourceUri.startsWith(prefix)) return "";',
1199
+ ' try { return stripMarkdownExtension(decodeURIComponent(sourceUri.slice(prefix.length))); }',
1200
+ ' catch (_error) { return ""; }',
1201
+ ' }',
1202
+ '',
1203
+ ' function resolveReferencePath(sourceCanonicalId, rawReference) {',
1204
+ ' var reference = cleanReference(rawReference);',
1205
+ ' if (!reference) return null;',
1206
+ ' var direct = stripMarkdownExtension(reference);',
1207
+ ' var sourceSegments = stripMarkdownExtension(sourceCanonicalId).split("/").filter(Boolean);',
1208
+ ' sourceSegments.pop();',
1209
+ ' var relative = stripMarkdownExtension(sourceSegments.concat([reference]).join("/"));',
1210
+ ' return { direct: direct, relative: relative };',
1211
+ ' }',
1212
+ '',
1213
+ ' function buildReferenceIndex(files) {',
1214
+ ' var byCanonicalId = new Map();',
1215
+ ' var byLegacyId = new Map();',
1216
+ ' var byUniqueStem = new Map();',
1217
+ ' files.forEach(function(file) {',
1218
+ ' var canonicalId = stripMarkdownExtension(file.canonicalId || canonicalIdFromSourceUri(file) || file.path || file.id);',
1219
+ ' var legacyKey = String(file.id || "").normalize("NFC").toLowerCase();',
1220
+ ' if (!file.id || !canonicalId) return;',
1221
+ ' if (byLegacyId.has(legacyKey)) throw new Error("Capacitor graph contains an ambiguous legacy basename: " + file.id);',
1222
+ ' if (byCanonicalId.has(canonicalId)) throw new Error("Capacitor graph contains duplicate canonical node id: " + canonicalId);',
1223
+ ' file.__canonicalId = canonicalId;',
1224
+ ' byLegacyId.set(legacyKey, file);',
1225
+ ' byCanonicalId.set(canonicalId, file);',
1226
+ ' var stem = canonicalId.split("/").pop() || canonicalId;',
1227
+ ' var candidates = byUniqueStem.get(stem) || [];',
1228
+ ' candidates.push(file);',
1229
+ ' byUniqueStem.set(stem, candidates);',
1230
+ ' });',
1231
+ ' return { byCanonicalId: byCanonicalId, byUniqueStem: byUniqueStem };',
1232
+ ' }',
1233
+ '',
1234
+ ' function resolveReference(sourceFile, rawReference, index) {',
1235
+ ' var paths = resolveReferencePath(sourceFile.__canonicalId, rawReference);',
1236
+ ' if (!paths) return null;',
1237
+ ' var direct = index.byCanonicalId.get(paths.direct);',
1238
+ ' if (direct) return direct;',
1239
+ ' var relative = index.byCanonicalId.get(paths.relative);',
1240
+ ' if (relative) return relative;',
1241
+ ' var stem = paths.direct.split("/").pop() || paths.direct;',
1242
+ ' var candidates = index.byUniqueStem.get(stem) || [];',
1243
+ ' return candidates.length === 1 ? candidates[0] : null;',
899
1244
  ' }',
900
1245
  '',
901
1246
  ' function extractWikiLinks(content) {',
@@ -904,7 +1249,21 @@
904
1249
  " var text = String(content || '');",
905
1250
  ' var match;',
906
1251
  ' while ((match = regex.exec(text)) !== null) {',
907
- ' var linked = stripMarkdownExtension(match[1]);',
1252
+ ' var linked = String(match[1] || "").trim();',
1253
+ ' if (linked) {',
1254
+ ' links.add(linked);',
1255
+ ' }',
1256
+ ' }',
1257
+ ' return Array.from(links);',
1258
+ ' }',
1259
+ '',
1260
+ ' function extractMarkdownLinks(content) {',
1261
+ ' var links = new Set();',
1262
+ ' var regex = /\\]\\(([^)]+)\\)/g;',
1263
+ " var text = String(content || '');",
1264
+ ' var match;',
1265
+ ' while ((match = regex.exec(text)) !== null) {',
1266
+ " var linked = String(match[1] || '').trim();",
908
1267
  ' if (linked) {',
909
1268
  ' links.add(linked);',
910
1269
  ' }',
@@ -914,6 +1273,7 @@
914
1273
  '',
915
1274
  ' var nodeMap = new Map();',
916
1275
  ' var edgeMap = new Map();',
1276
+ ' var referenceIndex = buildReferenceIndex(files);',
917
1277
  '',
918
1278
  ' function addEdge(source, target, type) {',
919
1279
  ' if (!source || !target || source === target) {',
@@ -922,21 +1282,40 @@
922
1282
  ' if (!nodeMap.has(source) || !nodeMap.has(target)) {',
923
1283
  ' return;',
924
1284
  ' }',
925
- ' var key = source + "->" + target;',
1285
+ ' var edgeType = type || "association";',
1286
+ ' var key = source + "->" + target + ":" + edgeType;',
926
1287
  ' if (edgeMap.has(key)) {',
927
1288
  ' return;',
928
1289
  ' }',
929
- ' edgeMap.set(key, { source: source, target: target, type: type || "association", weight: 1 });',
1290
+ ' var sourceNode = nodeMap.get(source);',
1291
+ ' var targetNode = nodeMap.get(target);',
1292
+ ' edgeMap.set(key, {',
1293
+ ' source: source,',
1294
+ ' target: target,',
1295
+ ' type: edgeType,',
1296
+ ' kind: "explicit",',
1297
+ ' provenance: edgeType,',
1298
+ ' sourceUri: sourceNode && sourceNode.sourceUri ? sourceNode.sourceUri : "",',
1299
+ ' targetUri: targetNode && targetNode.sourceUri ? targetNode.sourceUri : "",',
1300
+ ' weight: 1',
1301
+ ' });',
930
1302
  ' }',
931
1303
  '',
932
1304
  ' files.forEach(function(file) {',
933
- ' if (!file || !file.id || nodeMap.has(file.id)) {',
1305
+ ' if (!file || !file.id) {',
934
1306
  ' return;',
935
1307
  ' }',
1308
+ ' if (nodeMap.has(file.id)) {',
1309
+ ' throw new Error("Capacitor graph contains duplicate legacy node id: " + file.id);',
1310
+ ' }',
936
1311
  ' var metadata = file.metadata || {};',
937
1312
  ' nodeMap.set(file.id, {',
938
1313
  ' id: file.id,',
1314
+ ' canonicalId: file.canonicalId || file.__canonicalId || "",',
939
1315
  ' label: file.label || file.id,',
1316
+ ' sourceUri: file.sourceUri || "",',
1317
+ ' revision: file.revision || "",',
1318
+ ' identityAliases: Array.isArray(file.identityAliases) ? file.identityAliases : [],',
940
1319
  ' inDegree: 0,',
941
1320
  ' outDegree: 0,',
942
1321
  ' metadata: {',
@@ -959,18 +1338,24 @@
959
1338
  ' var metadata = file.metadata || {};',
960
1339
  ' var prerequisites = Array.isArray(metadata.prerequisites) ? metadata.prerequisites : [];',
961
1340
  ' prerequisites.forEach(function(rawPrereq) {',
962
- ' var prereqId = stripMarkdownExtension(rawPrereq);',
963
- ' addEdge(prereqId, sourceId, "explicit-prerequisite");',
1341
+ ' var prerequisiteFile = resolveReference(file, rawPrereq, referenceIndex);',
1342
+ ' addEdge(prerequisiteFile && prerequisiteFile.id, sourceId, "explicit-prerequisite");',
964
1343
  ' });',
965
1344
  '',
966
1345
  ' var nextItems = Array.isArray(metadata.next) ? metadata.next : [];',
967
1346
  ' nextItems.forEach(function(rawNext) {',
968
- ' var nextId = stripMarkdownExtension(rawNext);',
969
- ' addEdge(sourceId, nextId, "explicit-next");',
1347
+ ' var nextFile = resolveReference(file, rawNext, referenceIndex);',
1348
+ ' addEdge(sourceId, nextFile && nextFile.id, "explicit-next");',
1349
+ ' });',
1350
+ '',
1351
+ ' extractWikiLinks(file.content).forEach(function(rawLink) {',
1352
+ ' var linkedFile = resolveReference(file, rawLink, referenceIndex);',
1353
+ ' addEdge(sourceId, linkedFile && linkedFile.id, "wiki-link");',
970
1354
  ' });',
971
1355
  '',
972
- ' extractWikiLinks(file.content).forEach(function(linkedId) {',
973
- ' addEdge(linkedId, sourceId, "wiki-link");',
1356
+ ' extractMarkdownLinks(file.content).forEach(function(rawLink) {',
1357
+ ' var linkedFile = resolveReference(file, rawLink, referenceIndex);',
1358
+ ' addEdge(sourceId, linkedFile && linkedFile.id, "markdown-link");',
974
1359
  ' });',
975
1360
  ' });',
976
1361
  '',
@@ -1143,9 +1528,22 @@
1143
1528
  }
1144
1529
 
1145
1530
  async function buildCapacitorGraphDataWithWorkerFallback(files) {
1531
+ const budget = getMobileRuntimeBudget();
1532
+ const validateGraphBudget = (graphData) => {
1533
+ if (!graphData || !Array.isArray(graphData.nodes) || !Array.isArray(graphData.edges)) {
1534
+ throw new Error('Capacitor graph payload is invalid.');
1535
+ }
1536
+ if (graphData.nodes.length > budget.maxDocuments) {
1537
+ throw new Error(`Capacitor graph node count exceeds ${budget.maxDocuments}.`);
1538
+ }
1539
+ if (graphData.edges.length > budget.maxEdges) {
1540
+ throw new Error(`Capacitor graph edge count exceeds ${budget.maxEdges}.`);
1541
+ }
1542
+ return graphData;
1543
+ };
1146
1544
  if (!supportsCapacitorGraphBuildWorker()) {
1147
1545
  return {
1148
- graphData: buildCapacitorGraphData(files),
1546
+ graphData: validateGraphBudget(buildCapacitorGraphData(files)),
1149
1547
  buildMode: 'single-thread'
1150
1548
  };
1151
1549
  }
@@ -1156,7 +1554,7 @@
1156
1554
  throw new Error('Capacitor worker returned invalid graph payload.');
1157
1555
  }
1158
1556
  return {
1159
- graphData: workerGraph,
1557
+ graphData: validateGraphBudget(workerGraph),
1160
1558
  buildMode: 'worker'
1161
1559
  };
1162
1560
  } catch (workerErr) {
@@ -1166,7 +1564,7 @@
1166
1564
  workerErr
1167
1565
  );
1168
1566
  return {
1169
- graphData: buildCapacitorGraphData(files),
1567
+ graphData: validateGraphBudget(buildCapacitorGraphData(files)),
1170
1568
  buildMode: 'single-thread-fallback',
1171
1569
  warning
1172
1570
  };
@@ -1208,16 +1606,27 @@
1208
1606
 
1209
1607
  const files = await collectCapacitorMarkdownFiles(targetPath);
1210
1608
  const buildResult = await buildCapacitorGraphDataWithWorkerFallback(files);
1211
- const graphData = buildResult.graphData;
1609
+ const projectionApi = window.NoteConnectionKnowledgeProjection;
1610
+ if (!projectionApi || typeof projectionApi.createKnowledgeProjection !== 'function') {
1611
+ throw new Error('Knowledge projection contract is unavailable in the mobile runtime.');
1612
+ }
1613
+ const graphData = projectionApi.createKnowledgeProjection(buildResult.graphData, {
1614
+ workspaceId: 'mobile-workspace',
1615
+ });
1616
+ const projectionMaxBytes = getMobileRuntimeBudget().maxProjectionBytes;
1617
+ const graphSerializationMaxBytes = Math.min(
1618
+ CAPACITOR_GRAPH_SERIALIZATION_MAX_BYTES,
1619
+ projectionMaxBytes
1620
+ );
1212
1621
  const graphJsChunkFactory = createCapacitorGraphJavascriptChunkFactory(graphData);
1213
1622
  const graphJsonChunkFactory = createCapacitorGraphJsonChunkFactory(graphData);
1214
1623
 
1215
1624
  await capacitorWriteChunkSequence('data.js', graphJsChunkFactory, {
1216
- maxPayloadBytes: CAPACITOR_GRAPH_SERIALIZATION_MAX_BYTES,
1625
+ maxPayloadBytes: graphSerializationMaxBytes,
1217
1626
  payloadLabel: 'data.js graph payload'
1218
1627
  });
1219
1628
  await capacitorWriteChunkSequence('graph_data.json', graphJsonChunkFactory, {
1220
- maxPayloadBytes: CAPACITOR_GRAPH_SERIALIZATION_MAX_BYTES,
1629
+ maxPayloadBytes: graphSerializationMaxBytes,
1221
1630
  payloadLabel: 'graph_data.json graph payload'
1222
1631
  });
1223
1632
 
@@ -1225,11 +1634,11 @@
1225
1634
  const targetName = sanitizeTargetName(rawTarget);
1226
1635
  if (targetName) {
1227
1636
  await capacitorWriteChunkSequence(`data_${targetName}.js`, graphJsChunkFactory, {
1228
- maxPayloadBytes: CAPACITOR_GRAPH_SERIALIZATION_MAX_BYTES,
1637
+ maxPayloadBytes: graphSerializationMaxBytes,
1229
1638
  payloadLabel: `data_${targetName}.js graph payload`
1230
1639
  });
1231
1640
  await capacitorWriteChunkSequence(`graph_data_${targetName}.json`, graphJsonChunkFactory, {
1232
- maxPayloadBytes: CAPACITOR_GRAPH_SERIALIZATION_MAX_BYTES,
1641
+ maxPayloadBytes: graphSerializationMaxBytes,
1233
1642
  payloadLabel: `graph_data_${targetName}.json graph payload`
1234
1643
  });
1235
1644
  }
@@ -1295,6 +1704,23 @@
1295
1704
  return new Error(`Storage provider operation is unsupported in this runtime: ${operation}`);
1296
1705
  }
1297
1706
 
1707
+ function normalizeStorageProviderKind(value) {
1708
+ const normalized = String(value || '').trim().toLowerCase();
1709
+ if (normalized === 'sqlite' || normalized === 'embedded' || normalized === 'embedded-sqlite' || normalized === 'embedded_sqlite') {
1710
+ return 'sqlite';
1711
+ }
1712
+ if (normalized === 'file' || normalized === 'local-file' || normalized === 'snapshot') {
1713
+ return 'file';
1714
+ }
1715
+ if (normalized === 'projection' || normalized === 'mobile_projection' || normalized === 'mobile-slim') {
1716
+ return 'projection';
1717
+ }
1718
+ if (normalized === 'remote' || normalized === 'http' || normalized === 'external_http' || normalized === 'remote-http' || normalized === 'service') {
1719
+ return 'remote';
1720
+ }
1721
+ return null;
1722
+ }
1723
+
1298
1724
  function formatCapacitorMtime(statObject) {
1299
1725
  if (!statObject || typeof statObject !== 'object') {
1300
1726
  return '';
@@ -1320,6 +1746,65 @@
1320
1746
  class RuntimeStorageProvider {
1321
1747
  constructor(runtimeCaps) {
1322
1748
  this.runtimeCaps = runtimeCaps || {};
1749
+ this.mobileExactIndexPromise = null;
1750
+ }
1751
+
1752
+ getStorageResolution() {
1753
+ const runtimePlatform = String(this.runtimeCaps.platform || '').trim().toLowerCase();
1754
+ const mobileRuntime = isCapacitorNativeRuntime()
1755
+ || runtimePlatform.includes('android')
1756
+ || runtimePlatform.includes('ios')
1757
+ || runtimePlatform === 'mobile';
1758
+ const requestedProvider = normalizeStorageProviderKind(
1759
+ this.runtimeCaps.storage_requested_provider
1760
+ ) || (mobileRuntime ? 'projection' : 'sqlite');
1761
+ const reportedProvider = normalizeStorageProviderKind(this.runtimeCaps.storage_resolved_provider);
1762
+ const resolvedProvider = mobileRuntime
1763
+ ? 'projection'
1764
+ : reportedProvider || undefined;
1765
+ const fallbackReason = String(
1766
+ this.runtimeCaps.storage_fallback_reason
1767
+ || (mobileRuntime && requestedProvider === 'sqlite' ? 'native_sqlite_runtime_unavailable' : '')
1768
+ ).trim();
1769
+ return Object.freeze({
1770
+ requestedProvider,
1771
+ resolvedProvider,
1772
+ fallbackReason: fallbackReason || undefined,
1773
+ supportsSqlite: !mobileRuntime && resolvedProvider === 'sqlite',
1774
+ supportsProjection: this.runtimeCaps.supports_projection_store !== false
1775
+ && resolvedProvider === 'projection',
1776
+ });
1777
+ }
1778
+
1779
+ async refreshStorageResolution() {
1780
+ const current = this.getStorageResolution();
1781
+ if (isCapacitorNativeRuntime() || !this._supportsSidecar()) {
1782
+ return current;
1783
+ }
1784
+ try {
1785
+ const payload = await sidecarFetchJson('api/knowledge/store-diagnostics');
1786
+ const store = payload && payload.store && typeof payload.store === 'object'
1787
+ ? payload.store
1788
+ : null;
1789
+ const resolvedProvider = normalizeStorageProviderKind(
1790
+ store && (store.resolvedProvider || store.storageEngine || store.provider)
1791
+ );
1792
+ if (resolvedProvider) {
1793
+ this.runtimeCaps = {
1794
+ ...this.runtimeCaps,
1795
+ storage_requested_provider: normalizeStorageProviderKind(
1796
+ store.requestedProvider
1797
+ ) || current.requestedProvider,
1798
+ storage_resolved_provider: resolvedProvider,
1799
+ storage_fallback_reason: String(store.fallbackReason || '').trim(),
1800
+ supports_sqlite: resolvedProvider === 'sqlite',
1801
+ };
1802
+ }
1803
+ } catch (_error) {
1804
+ // Capability probing is advisory; the normal storage operation
1805
+ // still owns the authoritative failure/fallback behavior.
1806
+ }
1807
+ return this.getStorageResolution();
1323
1808
  }
1324
1809
 
1325
1810
  _supportsSidecar() {
@@ -1558,6 +2043,95 @@
1558
2043
  throw unsupportedOperationError('buildGraph');
1559
2044
  }
1560
2045
 
2046
+ async _loadMobileExactIndex() {
2047
+ if (this.mobileExactIndexPromise) {
2048
+ return await this.mobileExactIndexPromise;
2049
+ }
2050
+
2051
+ this.mobileExactIndexPromise = (async () => {
2052
+ const analyzer = window.NoteConnectionMobileExactAnalyzer;
2053
+ if (!analyzer || typeof analyzer.createMobileExactIndex !== 'function') {
2054
+ throw unsupportedOperationError('mobileExactAnalysis');
2055
+ }
2056
+ const storeApi = window.NoteConnectionKnowledgeProjectionStore;
2057
+ if (!storeApi || typeof storeApi.createProjectionStore !== 'function') {
2058
+ throw unsupportedOperationError('projectionStore');
2059
+ }
2060
+ const projectionStore = typeof storeApi.createFileProjectionStore === 'function'
2061
+ ? storeApi.createFileProjectionStore({
2062
+ fileName: 'graph_data.json',
2063
+ maxBytes: getMobileRuntimeBudget().maxProjectionBytes,
2064
+ readFile: async (filename) => await this.readGeneratedAsset(filename),
2065
+ })
2066
+ : storeApi.createProjectionStore({
2067
+ maxBytes: getMobileRuntimeBudget().maxProjectionBytes,
2068
+ read: async () => await this.readGeneratedAsset('graph_data.json'),
2069
+ });
2070
+ const graph = await projectionStore.load();
2071
+ return analyzer.createMobileExactIndex(graph);
2072
+ })();
2073
+
2074
+ try {
2075
+ return await this.mobileExactIndexPromise;
2076
+ } catch (error) {
2077
+ this.mobileExactIndexPromise = null;
2078
+ throw error;
2079
+ }
2080
+ }
2081
+
2082
+ async queryKnowledgeBaseExact(request) {
2083
+ const payload = request && typeof request === 'object' ? request : {};
2084
+ const query = typeof payload.query === 'string' ? payload.query.trim() : '';
2085
+ if (!query) {
2086
+ throw new Error('Local exact query requires a non-empty query.');
2087
+ }
2088
+ const index = await this._loadMobileExactIndex();
2089
+ const matches = index.searchExact(query, payload.maxMatches);
2090
+ return {
2091
+ query,
2092
+ matches: matches.map((node) => ({
2093
+ ...node,
2094
+ neighbors: index.neighbors(
2095
+ node.id,
2096
+ payload.maxNeighborsPerMatch,
2097
+ payload.edgeKinds
2098
+ ),
2099
+ learningRoute: typeof index.learningRoute === 'function'
2100
+ ? index.learningRoute(node.id, 6)
2101
+ : []
2102
+ })),
2103
+ statistics: index.statistics({ includeProvenance: true }),
2104
+ execution: 'local-exact',
2105
+ remoteInferenceUsed: false
2106
+ };
2107
+ }
2108
+
2109
+ async findKnowledgePath(request) {
2110
+ const payload = request && typeof request === 'object' ? request : {};
2111
+ const sourceNodeId = typeof payload.sourceNodeId === 'string'
2112
+ ? payload.sourceNodeId.trim()
2113
+ : '';
2114
+ const targetNodeId = typeof payload.targetNodeId === 'string'
2115
+ ? payload.targetNodeId.trim()
2116
+ : '';
2117
+ if (!sourceNodeId || !targetNodeId) {
2118
+ throw new Error('Local knowledge path requires sourceNodeId and targetNodeId.');
2119
+ }
2120
+ const index = await this._loadMobileExactIndex();
2121
+ return {
2122
+ sourceNodeId,
2123
+ targetNodeId,
2124
+ path: index.shortestPath(
2125
+ sourceNodeId,
2126
+ targetNodeId,
2127
+ payload.maxDepth,
2128
+ payload.maxVisitedNodes
2129
+ ),
2130
+ execution: 'local-exact',
2131
+ remoteInferenceUsed: false
2132
+ };
2133
+ }
2134
+
1561
2135
  async readContent(filePath) {
1562
2136
  if (!this._supportsContentApi()) {
1563
2137
  throw unsupportedOperationError('readContent');
@@ -1565,7 +2139,9 @@
1565
2139
 
1566
2140
  if (isCapacitorNativeRuntime()) {
1567
2141
  const capacitorPath = resolveCapacitorContentCandidatePath(filePath);
1568
- return await capacitorReadText(capacitorPath);
2142
+ return await capacitorReadText(capacitorPath, {
2143
+ maxBytes: getMobileRuntimeBudget().maxDocumentBytes
2144
+ });
1569
2145
  }
1570
2146
 
1571
2147
  if (this._supportsSidecar()) {
@@ -1630,7 +2206,9 @@
1630
2206
  try {
1631
2207
  // Prefer local runtime-generated assets first so on-device builds
1632
2208
  // are picked up without requiring an app rebundle.
1633
- return await capacitorReadText(normalized);
2209
+ return await capacitorReadText(normalized, {
2210
+ maxBytes: getMobileRuntimeBudget().maxProjectionBytes
2211
+ });
1634
2212
  } catch (_fsErr) {
1635
2213
  // Fall through to bundled asset fetch.
1636
2214
  }
@@ -1658,6 +2236,18 @@
1658
2236
  }
1659
2237
 
1660
2238
  window.NoteConnectionStorage = {
1661
- createProvider
2239
+ createProvider,
2240
+ measureUtf8Bytes
1662
2241
  };
2242
+
2243
+ if (typeof module === 'object' && module.exports) {
2244
+ module.exports = {
2245
+ createProvider,
2246
+ buildCapacitorGraphData,
2247
+ getCapacitorGraphBuildWorkerSource,
2248
+ createMobileResourceIdentity,
2249
+ getMobileRuntimeBudget,
2250
+ measureUtf8Bytes,
2251
+ };
2252
+ }
1663
2253
  }());