noteconnection 1.6.8 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (212) hide show
  1. package/LICENSE +674 -21
  2. package/README.md +258 -64
  3. package/dist/src/agent_workspace.contract.parity.test.js +475 -0
  4. package/dist/src/agent_workspace.frontend.test.js +9989 -0
  5. package/dist/src/agent_workspace.locale.contract.test.js +95 -0
  6. package/dist/src/agent_workspace.runtime.behavior.test.js +5072 -0
  7. package/dist/src/copy.assets.contract.test.js +130 -0
  8. package/dist/src/core/PathBridge.js +28 -3
  9. package/dist/src/export/WorkspaceExportBundle.js +1130 -0
  10. package/dist/src/export/WorkspaceExportBundle.test.js +1480 -0
  11. package/dist/src/export/index.js +18 -0
  12. package/dist/src/export/types.js +2 -0
  13. package/dist/src/fixrisk.issue.verifier.contract.test.js +3 -1
  14. package/dist/src/foundation.ann.runtime.contract.test.js +81 -0
  15. package/dist/src/foundation.release.evidence.contract.test.js +406 -0
  16. package/dist/src/foundation.sqlite.runtime.contract.test.js +82 -0
  17. package/dist/src/frontend/README.md +258 -64
  18. package/dist/src/frontend/agent_workspace.js +5353 -0
  19. package/dist/src/frontend/agent_workspace_runtime.js +4434 -0
  20. package/dist/src/frontend/analysis.js +31 -4
  21. package/dist/src/frontend/app.js +3597 -141
  22. package/dist/src/frontend/focus_mode_interactions.js +33 -0
  23. package/dist/src/frontend/godot_future_path_renderer.js +540 -0
  24. package/dist/src/frontend/godot_tree_interactions.js +178 -0
  25. package/dist/src/frontend/graph_state.mjs +105 -0
  26. package/dist/src/frontend/hosted_future_path_runtime.js +157 -0
  27. package/dist/src/frontend/i18n.mjs +186 -0
  28. package/dist/src/frontend/index.html +641 -266
  29. package/dist/src/frontend/layout_gpu.js +12 -4
  30. package/dist/src/frontend/locales/en.json +721 -5
  31. package/dist/src/frontend/locales/zh.json +721 -5
  32. package/dist/src/frontend/main.mjs +60 -0
  33. package/dist/src/frontend/markdown_runtime.js +827 -0
  34. package/dist/src/frontend/notemd.css +49 -0
  35. package/dist/src/frontend/notemd.html +7 -1
  36. package/dist/src/frontend/notemd.js +64 -0
  37. package/dist/src/frontend/path.html +107 -0
  38. package/dist/src/frontend/path_app.js +2189 -150
  39. package/dist/src/frontend/path_layout.mjs +143 -0
  40. package/dist/src/frontend/path_mermaid_utils.mjs +108 -0
  41. package/dist/src/frontend/path_modules_bridge.js +486 -0
  42. package/dist/src/frontend/path_state.mjs +118 -0
  43. package/dist/src/frontend/path_styles.css +146 -0
  44. package/dist/src/frontend/path_worker_bridge.mjs +85 -0
  45. package/dist/src/frontend/reader.js +522 -27
  46. package/dist/src/frontend/runtime_bridge.js +67 -54
  47. package/dist/src/frontend/runtime_bridge.mjs +279 -0
  48. package/dist/src/frontend/settings.js +130 -12
  49. package/dist/src/frontend/simulationWorker.js +241 -6
  50. package/dist/src/frontend/source_manager.js +190 -21
  51. package/dist/src/frontend/styles.css +2853 -72
  52. package/dist/src/frontend/workbench_state.mjs +101 -0
  53. package/dist/src/frontend/workspace_panes.js +10168 -0
  54. package/dist/src/frontend.locale.contract.test.js +62 -0
  55. package/dist/src/godot.sidecar.bootstrap.contract.test.js +244 -0
  56. package/dist/src/indexing/IndexLifecycle.js +195 -0
  57. package/dist/src/indexing/IndexLifecycle.test.js +49 -0
  58. package/dist/src/indexing/SegmentBuilder.js +64 -0
  59. package/dist/src/indexing/UnitBuilder.js +48 -0
  60. package/dist/src/indexing/types.js +2 -0
  61. package/dist/src/knowledge.api.contract.test.js +170 -0
  62. package/dist/src/learning/KnowledgeLearningPlatform.js +10386 -0
  63. package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +327 -0
  64. package/dist/src/learning/KnowledgeLearningPlatform.program-f.test.js +99 -0
  65. package/dist/src/learning/KnowledgeLearningPlatform.test.js +2971 -0
  66. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +2974 -0
  67. package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +3928 -0
  68. package/dist/src/learning/answerReleaseReview.js +4319 -0
  69. package/dist/src/learning/answerReleaseReview.test.js +2888 -0
  70. package/dist/src/learning/api.js +2 -0
  71. package/dist/src/learning/conversationComposer.js +1480 -0
  72. package/dist/src/learning/conversationComposer.test.js +1817 -0
  73. package/dist/src/learning/domains/ConversationManager.js +53 -0
  74. package/dist/src/learning/domains/KnowledgeIngestor.js +238 -0
  75. package/dist/src/learning/domains/KnowledgeQuerier.js +187 -0
  76. package/dist/src/learning/domains/MasteryEngine.js +387 -0
  77. package/dist/src/learning/domains/MemoryPolicyManager.js +408 -0
  78. package/dist/src/learning/domains/QualityEvaluator.js +307 -0
  79. package/dist/src/learning/domains/TutorRouter.js +313 -0
  80. package/dist/src/learning/domains/index.js +33 -0
  81. package/dist/src/learning/domains/types.js +7 -0
  82. package/dist/src/learning/errors.js +29 -0
  83. package/dist/src/learning/evidenceContextAssembler.js +1176 -0
  84. package/dist/src/learning/evidenceContextAssembler.test.js +6332 -0
  85. package/dist/src/learning/graphContextAssembler.js +870 -0
  86. package/dist/src/learning/graphContextAssembler.test.js +1033 -0
  87. package/dist/src/learning/index.js +28 -0
  88. package/dist/src/learning/queryBackend.js +1898 -0
  89. package/dist/src/learning/queryBackend.test.js +955 -0
  90. package/dist/src/learning/ragContextPack.js +257 -0
  91. package/dist/src/learning/ragContextPack.test.js +160 -0
  92. package/dist/src/learning/ragPublicText.js +38 -0
  93. package/dist/src/learning/ragSufficiencyJudge.js +161 -0
  94. package/dist/src/learning/ragSufficiencyJudge.test.js +177 -0
  95. package/dist/src/learning/ragSufficiencyProviderJudge.js +227 -0
  96. package/dist/src/learning/ragSufficiencyProviderJudge.test.js +156 -0
  97. package/dist/src/learning/requestNormalization.js +198 -0
  98. package/dist/src/learning/runtimeCapability.js +4677 -0
  99. package/dist/src/learning/runtimeCapability.test.js +3635 -0
  100. package/dist/src/learning/store.js +1240 -0
  101. package/dist/src/learning/store.test.js +1126 -0
  102. package/dist/src/learning/tutorAdapter.js +2 -0
  103. package/dist/src/learning/types.js +2 -0
  104. package/dist/src/learning/vectorAccelerationAdapter.js +942 -0
  105. package/dist/src/learning/vectorAccelerationAdapter.test.js +382 -0
  106. package/dist/src/lfs.asset.policy.contract.test.js +153 -0
  107. package/dist/src/license.policy.contract.test.js +66 -0
  108. package/dist/src/memory/MemoryGovernance.js +74 -0
  109. package/dist/src/memory/MemoryGovernance.test.js +46 -0
  110. package/dist/src/memory/types.js +2 -0
  111. package/dist/src/mermaid.frontend.guard.contract.test.js +77 -0
  112. package/dist/src/middleware/auth.js +17 -0
  113. package/dist/src/middleware/body-parser.js +45 -0
  114. package/dist/src/middleware/cors.js +44 -0
  115. package/dist/src/middleware/index.js +21 -0
  116. package/dist/src/middleware/request-trace.js +96 -0
  117. package/dist/src/notemd/AppConfigToml.js +6 -4
  118. package/dist/src/notemd/MermaidProcessor.js +400 -50
  119. package/dist/src/notemd/NotemdService.js +498 -13
  120. package/dist/src/notemd/PromptManager.js +15 -0
  121. package/dist/src/notemd/cli/commands.js +357 -0
  122. package/dist/src/notemd/cli/dispatcher.js +225 -0
  123. package/dist/src/notemd/cli/index.js +169 -0
  124. package/dist/src/notemd/cli/parser.js +68 -0
  125. package/dist/src/notemd/cli/types.js +2 -0
  126. package/dist/src/notemd/constants.js +43 -0
  127. package/dist/src/notemd/diagram/diagramGenerationService.js +78 -0
  128. package/dist/src/notemd/diagram/diagramSpec.js +79 -0
  129. package/dist/src/notemd/diagram/diagramSpecResponseParser.js +131 -0
  130. package/dist/src/notemd/diagram/intent.js +95 -0
  131. package/dist/src/notemd/diagram/planner.js +71 -0
  132. package/dist/src/notemd/diagram/prompts/diagramSpecPrompt.js +42 -0
  133. package/dist/src/notemd/diagram/types.js +18 -0
  134. package/dist/src/notemd/index.js +26 -0
  135. package/dist/src/notemd/operations/capabilityManifest.js +23 -0
  136. package/dist/src/notemd/operations/cliContracts.js +17 -0
  137. package/dist/src/notemd/operations/configProfileCommands.js +85 -0
  138. package/dist/src/notemd/operations/registry.contract.test.js +95 -0
  139. package/dist/src/notemd/operations/registry.js +991 -0
  140. package/dist/src/notemd/operations/types.js +2 -0
  141. package/dist/src/notemd/providerDiagnostics.js +220 -0
  142. package/dist/src/notemd/providerProfiles.js +42 -0
  143. package/dist/src/notemd/providerTemplates.js +231 -0
  144. package/dist/src/notemd/search/DuckDuckGoProvider.js +39 -0
  145. package/dist/src/notemd/search/SearchManager.js +13 -0
  146. package/dist/src/notemd/search/SearchProvider.js +2 -0
  147. package/dist/src/notemd/search/TavilyProvider.js +44 -0
  148. package/dist/src/notemd.agent.manifest.test.js +85 -0
  149. package/dist/src/notemd.api.contract.test.js +14 -1
  150. package/dist/src/notemd.app_config_toml.test.js +2 -1
  151. package/dist/src/notemd.batch.workflow.test.js +117 -0
  152. package/dist/src/notemd.cli.e2e.test.js +136 -0
  153. package/dist/src/notemd.core.test.js +51 -0
  154. package/dist/src/notemd.diagram.pipeline.test.js +233 -0
  155. package/dist/src/notemd.providerTemplates.test.js +34 -0
  156. package/dist/src/notemd.server.integration.test.js +143 -35
  157. package/dist/src/notemd.workflow.pipeline.test.js +162 -0
  158. package/dist/src/pathbridge.handshake.contract.test.js +16 -2
  159. package/dist/src/pathmode.background.contract.test.js +69 -0
  160. package/dist/src/pathmode.settings.api.contract.test.js +9 -0
  161. package/dist/src/pkg.sidecar.contract.test.js +9 -3
  162. package/dist/src/platform/ExportProfile.js +58 -0
  163. package/dist/src/platform/PlatformCapabilities.js +45 -0
  164. package/dist/src/platform/PlatformCapabilities.test.js +30 -0
  165. package/dist/src/platform/RenderMaterializer.js +33 -0
  166. package/dist/src/platform/RenderMaterializer.test.js +32 -0
  167. package/dist/src/query_backend.external_http.integration.test.js +410 -0
  168. package/dist/src/reader_renderer.js +404 -3
  169. package/dist/src/reader_renderer.test.js +87 -0
  170. package/dist/src/release.godot.mirror.contract.test.js +73 -0
  171. package/dist/src/resources/ResourceRegistry.js +223 -0
  172. package/dist/src/resources/ResourceRegistry.test.js +61 -0
  173. package/dist/src/resources/types.js +2 -0
  174. package/dist/src/routes/agentWorkspaceDiagnostics.js +173 -0
  175. package/dist/src/routes/data.js +267 -0
  176. package/dist/src/routes/diagnostics.js +51 -0
  177. package/dist/src/routes/index.js +23 -0
  178. package/dist/src/routes/knowledge.js +968 -0
  179. package/dist/src/routes/markdown.js +287 -0
  180. package/dist/src/routes/notemd.js +565 -0
  181. package/dist/src/routes/registry.contract.test.js +130 -0
  182. package/dist/src/routes/render.js +285 -0
  183. package/dist/src/routes/runtimeRunbookRouteOps.js +149 -0
  184. package/dist/src/routes/runtimeRunbookRouteOps.test.js +194 -0
  185. package/dist/src/routes/settings.js +6 -0
  186. package/dist/src/routes/staticFiles.js +94 -0
  187. package/dist/src/routes/types.js +2 -0
  188. package/dist/src/runtime.transport.adapter.contract.test.js +81 -0
  189. package/dist/src/server.js +11090 -1549
  190. package/dist/src/server.migration.test.js +193 -21
  191. package/dist/src/server.port.fallback.contract.test.js +63 -0
  192. package/dist/src/session/SessionStateStore.js +81 -0
  193. package/dist/src/session/SessionStateStore.test.js +58 -0
  194. package/dist/src/session/types.js +2 -0
  195. package/dist/src/settings.runtime.contract.test.js +50 -0
  196. package/dist/src/shared/types.contract.test.js +107 -0
  197. package/dist/src/shared/types.js +22 -0
  198. package/dist/src/sidecar.replacement.boundary.contract.test.js +128 -0
  199. package/dist/src/sidecar.supply.readiness.contract.test.js +144 -0
  200. package/dist/src/source_manager.loadflow.test.js +46 -0
  201. package/dist/src/startup.layout.snapshot.contract.test.js +57 -0
  202. package/dist/src/tauri.frontend.build.contract.test.js +60 -0
  203. package/dist/src/tauri.sidecar.cleanup.contract.test.js +21 -0
  204. package/dist/src/utils/RuntimePaths.js +4 -13
  205. package/dist/src/utils/platform.js +153 -0
  206. package/dist/src/workflows/WorkflowArtifactStore.js +96 -0
  207. package/dist/src/workflows/WorkflowArtifactStore.test.js +80 -0
  208. package/dist/src/workflows/types.js +2 -0
  209. package/dist/src/workspace/WorkspaceRegistry.js +122 -0
  210. package/dist/src/workspace/WorkspaceRegistry.test.js +29 -0
  211. package/dist/src/workspace/types.js +2 -0
  212. package/package.json +61 -10
@@ -12,6 +12,194 @@ let currentSettings = {
12
12
  velocityDecay: 0.2
13
13
  };
14
14
 
15
+ let startupProfile = {
16
+ id: 'default',
17
+ pilotEnabled: false,
18
+ tickMaxFps: 0,
19
+ lowAlphaTickMaxFps: 0,
20
+ lowAlphaThreshold: 0.08,
21
+ stableAlphaThreshold: 0.05,
22
+ stableHoldTicks: 8,
23
+ stableTimeoutMs: 12000,
24
+ deltaEnabled: false,
25
+ deltaEpsilonPx: 0.6,
26
+ fullSyncEveryTicks: 3,
27
+ lowAlphaDeltaEpsilonMultiplier: 1.35,
28
+ lowAlphaFullSyncEveryTicks: 5
29
+ };
30
+
31
+ let startupRuntimeState = {
32
+ tickMinIntervalMs: 0,
33
+ lowAlphaTickMinIntervalMs: 0,
34
+ lastTickEmitTs: 0,
35
+ initTs: 0,
36
+ stableTickStreak: 0,
37
+ stableAnnounced: false,
38
+ tickCount: 0,
39
+ prevPositions: new Map()
40
+ };
41
+
42
+ function parseFiniteNumber(value, fallback) {
43
+ if (Number.isFinite(value)) {
44
+ return value;
45
+ }
46
+ const parsed = Number(value);
47
+ return Number.isFinite(parsed) ? parsed : fallback;
48
+ }
49
+
50
+ function parsePositiveInt(value, fallback) {
51
+ const parsed = Math.floor(parseFiniteNumber(value, fallback));
52
+ return parsed > 0 ? parsed : fallback;
53
+ }
54
+
55
+ function configureStartupProfile(profile) {
56
+ const next = {
57
+ id: (profile && typeof profile.id === 'string' && profile.id.trim().length > 0)
58
+ ? profile.id.trim()
59
+ : 'default',
60
+ pilotEnabled: Boolean(profile && profile.pilotEnabled === true),
61
+ tickMaxFps: Math.max(0, parsePositiveInt(profile ? profile.tickMaxFps : 0, 0)),
62
+ lowAlphaTickMaxFps: Math.max(0, parsePositiveInt(profile ? profile.lowAlphaTickMaxFps : 0, 0)),
63
+ lowAlphaThreshold: Math.max(0.0001, parseFiniteNumber(profile ? profile.lowAlphaThreshold : 0.08, 0.08)),
64
+ stableAlphaThreshold: Math.max(0.0001, parseFiniteNumber(profile ? profile.stableAlphaThreshold : 0.05, 0.05)),
65
+ stableHoldTicks: Math.max(1, parsePositiveInt(profile ? profile.stableHoldTicks : 8, 8)),
66
+ stableTimeoutMs: Math.max(1000, parsePositiveInt(profile ? profile.stableTimeoutMs : 12000, 12000)),
67
+ deltaEnabled: Boolean(profile && profile.deltaEnabled === true),
68
+ deltaEpsilonPx: Math.max(0.0001, parseFiniteNumber(profile ? profile.deltaEpsilonPx : 0.6, 0.6)),
69
+ fullSyncEveryTicks: Math.max(1, parsePositiveInt(profile ? profile.fullSyncEveryTicks : 3, 3)),
70
+ lowAlphaDeltaEpsilonMultiplier: Math.max(
71
+ 1,
72
+ parseFiniteNumber(profile ? profile.lowAlphaDeltaEpsilonMultiplier : 1.35, 1.35)
73
+ ),
74
+ lowAlphaFullSyncEveryTicks: Math.max(
75
+ 1,
76
+ parsePositiveInt(
77
+ profile ? profile.lowAlphaFullSyncEveryTicks : Math.max(4, parsePositiveInt(profile ? profile.fullSyncEveryTicks : 3, 3)),
78
+ Math.max(4, parsePositiveInt(profile ? profile.fullSyncEveryTicks : 3, 3))
79
+ )
80
+ )
81
+ };
82
+
83
+ startupProfile = next;
84
+ startupRuntimeState = {
85
+ tickMinIntervalMs: next.tickMaxFps > 0 ? Math.max(1, Math.floor(1000 / next.tickMaxFps)) : 0,
86
+ lowAlphaTickMinIntervalMs: next.lowAlphaTickMaxFps > 0 ? Math.max(1, Math.floor(1000 / next.lowAlphaTickMaxFps)) : 0,
87
+ lastTickEmitTs: 0,
88
+ initTs: Date.now(),
89
+ stableTickStreak: 0,
90
+ stableAnnounced: false,
91
+ tickCount: 0,
92
+ prevPositions: new Map()
93
+ };
94
+
95
+ console.log('[Worker] Startup profile configured:', {
96
+ id: next.id,
97
+ pilotEnabled: next.pilotEnabled,
98
+ tickMaxFps: next.tickMaxFps,
99
+ tickMinIntervalMs: startupRuntimeState.tickMinIntervalMs,
100
+ lowAlphaTickMaxFps: next.lowAlphaTickMaxFps,
101
+ lowAlphaTickMinIntervalMs: startupRuntimeState.lowAlphaTickMinIntervalMs,
102
+ lowAlphaThreshold: next.lowAlphaThreshold,
103
+ stableAlphaThreshold: next.stableAlphaThreshold,
104
+ stableHoldTicks: next.stableHoldTicks,
105
+ stableTimeoutMs: next.stableTimeoutMs,
106
+ deltaEnabled: next.deltaEnabled,
107
+ deltaEpsilonPx: next.deltaEpsilonPx,
108
+ fullSyncEveryTicks: next.fullSyncEveryTicks,
109
+ lowAlphaDeltaEpsilonMultiplier: next.lowAlphaDeltaEpsilonMultiplier,
110
+ lowAlphaFullSyncEveryTicks: next.lowAlphaFullSyncEveryTicks
111
+ });
112
+ }
113
+
114
+ function resolveTickMinIntervalMs(alpha) {
115
+ const highAlphaIntervalMs = startupRuntimeState.tickMinIntervalMs;
116
+ const lowAlphaIntervalMs = startupRuntimeState.lowAlphaTickMinIntervalMs;
117
+ if (lowAlphaIntervalMs <= 0) {
118
+ return highAlphaIntervalMs;
119
+ }
120
+ if (alpha <= startupProfile.lowAlphaThreshold) {
121
+ return Math.max(highAlphaIntervalMs, lowAlphaIntervalMs);
122
+ }
123
+ return highAlphaIntervalMs;
124
+ }
125
+
126
+ function resolveDeltaEpsilonPx(alpha) {
127
+ let epsilon = startupProfile.deltaEpsilonPx;
128
+ if (alpha <= startupProfile.lowAlphaThreshold) {
129
+ epsilon *= startupProfile.lowAlphaDeltaEpsilonMultiplier;
130
+ }
131
+ return Math.max(0.0001, epsilon);
132
+ }
133
+
134
+ function resolveFullSyncEveryTicks(alpha) {
135
+ if (alpha <= startupProfile.lowAlphaThreshold) {
136
+ return Math.max(startupProfile.fullSyncEveryTicks, startupProfile.lowAlphaFullSyncEveryTicks);
137
+ }
138
+ return startupProfile.fullSyncEveryTicks;
139
+ }
140
+
141
+ function buildFullPositionPayload() {
142
+ const payload = new Array(nodes.length);
143
+ for (let index = 0; index < nodes.length; index += 1) {
144
+ const n = nodes[index];
145
+ const x = Number.isFinite(n.x) ? n.x : 0;
146
+ const y = Number.isFinite(n.y) ? n.y : 0;
147
+ payload[index] = { id: n.id, i: index, x, y };
148
+ startupRuntimeState.prevPositions.set(n.id, { x, y });
149
+ }
150
+ return payload;
151
+ }
152
+
153
+ function buildDeltaPositionPayload(alpha) {
154
+ const payload = [];
155
+ const epsilon = resolveDeltaEpsilonPx(alpha);
156
+ for (let index = 0; index < nodes.length; index += 1) {
157
+ const n = nodes[index];
158
+ const x = Number.isFinite(n.x) ? n.x : 0;
159
+ const y = Number.isFinite(n.y) ? n.y : 0;
160
+ const prev = startupRuntimeState.prevPositions.get(n.id);
161
+ if (!prev || Math.abs(prev.x - x) >= epsilon || Math.abs(prev.y - y) >= epsilon) {
162
+ payload.push({ id: n.id, i: index, x, y });
163
+ startupRuntimeState.prevPositions.set(n.id, { x, y });
164
+ }
165
+ }
166
+ return payload;
167
+ }
168
+
169
+ function buildTickPositionsPayload(alpha) {
170
+ startupRuntimeState.tickCount += 1;
171
+ const activeFullSyncEveryTicks = resolveFullSyncEveryTicks(alpha);
172
+ const forceFull =
173
+ startupRuntimeState.tickCount === 1 ||
174
+ startupProfile.deltaEnabled !== true ||
175
+ activeFullSyncEveryTicks <= 1 ||
176
+ (startupRuntimeState.tickCount % activeFullSyncEveryTicks) === 0;
177
+
178
+ if (forceFull) {
179
+ return {
180
+ nodes: buildFullPositionPayload(),
181
+ isDelta: false,
182
+ tickMode: 'full'
183
+ };
184
+ }
185
+
186
+ const deltaNodes = buildDeltaPositionPayload(alpha);
187
+ const changeRatio = nodes.length > 0 ? (deltaNodes.length / nodes.length) : 0;
188
+ if (changeRatio >= 0.7) {
189
+ return {
190
+ nodes: buildFullPositionPayload(),
191
+ isDelta: false,
192
+ tickMode: 'full'
193
+ };
194
+ }
195
+
196
+ return {
197
+ nodes: deltaNodes,
198
+ isDelta: true,
199
+ tickMode: 'delta'
200
+ };
201
+ }
202
+
15
203
  onmessage = function(event) {
16
204
  const { type, payload } = event.data;
17
205
 
@@ -52,10 +240,12 @@ function initSimulation(data) {
52
240
  nodes = data.nodes;
53
241
  links = data.links;
54
242
  const { width, height } = data;
55
- const { settings } = data; // Settings if provided
243
+ const { settings, startupProfile: startupProfilePayload } = data; // Settings if provided
56
244
 
57
245
  console.log(`[Worker] Initializing simulation with ${nodes.length} nodes, ${links.length} edges`);
58
246
 
247
+ configureStartupProfile(startupProfilePayload || {});
248
+
59
249
  if (settings) {
60
250
  currentSettings = { ...currentSettings, ...settings };
61
251
  }
@@ -89,10 +279,53 @@ function initSimulation(data) {
89
279
  .velocityDecay(currentSettings.velocityDecay);
90
280
 
91
281
  simulation.on("tick", () => {
92
- // Optimization: For very large graphs, maybe use Float32Array?
93
- // For now, post simplified objects
94
- const positions = nodes.map(n => ({ id: n.id, x: n.x, y: n.y }));
95
- postMessage({ type: 'tick', nodes: positions });
282
+ const now = Date.now();
283
+ const alpha = (simulation && typeof simulation.alpha === 'function')
284
+ ? simulation.alpha()
285
+ : 1;
286
+ const activeTickMinIntervalMs = resolveTickMinIntervalMs(alpha);
287
+ if (
288
+ activeTickMinIntervalMs > 0 &&
289
+ (now - startupRuntimeState.lastTickEmitTs) < activeTickMinIntervalMs
290
+ ) {
291
+ return;
292
+ }
293
+ startupRuntimeState.lastTickEmitTs = now;
294
+
295
+ let isStartupStable = false;
296
+
297
+ if (!startupRuntimeState.stableAnnounced) {
298
+ if (alpha <= startupProfile.stableAlphaThreshold) {
299
+ startupRuntimeState.stableTickStreak += 1;
300
+ } else {
301
+ startupRuntimeState.stableTickStreak = 0;
302
+ }
303
+
304
+ const elapsedMs = now - startupRuntimeState.initTs;
305
+ if (
306
+ startupRuntimeState.stableTickStreak >= startupProfile.stableHoldTicks ||
307
+ elapsedMs >= startupProfile.stableTimeoutMs
308
+ ) {
309
+ startupRuntimeState.stableAnnounced = true;
310
+ isStartupStable = true;
311
+ postMessage({
312
+ type: 'startupStable',
313
+ alpha,
314
+ elapsedMs
315
+ });
316
+ }
317
+ }
318
+
319
+ const tickPositions = buildTickPositionsPayload(alpha);
320
+ postMessage({
321
+ type: 'tick',
322
+ nodes: tickPositions.nodes,
323
+ isDelta: tickPositions.isDelta,
324
+ tickMode: tickPositions.tickMode,
325
+ alpha,
326
+ emittedAt: now,
327
+ isStartupStable
328
+ });
96
329
  });
97
330
 
98
331
  // Initial warmup
@@ -175,6 +408,8 @@ function setNodes(payload) {
175
408
  // Re-initialize key forces
176
409
  simulation.nodes(nodes);
177
410
  simulation.force("link").links(links);
411
+ startupRuntimeState.prevPositions = new Map();
412
+ startupRuntimeState.tickCount = 0;
178
413
 
179
414
  // If we want to support collision updates based on new subset
180
415
  // simulation.force("collide")...
@@ -216,7 +451,7 @@ function fixNodes(nodeUpdates) {
216
451
  nodeUpdates.forEach(update => {
217
452
  const node = nodes.find(n => n.id === update.id);
218
453
  if (node) {
219
- if (update.cod === 'fix') {
454
+ if (update.cmd === 'fix') {
220
455
  node.fx = update.x;
221
456
  node.fy = update.y;
222
457
  } else if (update.cmd === 'unfix') {
@@ -1,10 +1,57 @@
1
1
  document.addEventListener('DOMContentLoaded', () => {
2
+ const hasExplicitBrowserRuntimeBootstrap = () => {
3
+ if (typeof window === 'undefined' || !window.__NC_SIDECAR_RUNTIME) {
4
+ return false;
5
+ }
6
+ const currentOrigin = String((window.location && window.location.origin) || '').trim().replace(/\/+$/, '');
7
+ const runtimeBaseUrl = String(window.__NC_SIDECAR_RUNTIME.baseUrl || '').trim().replace(/\/+$/, '');
8
+ return Boolean(currentOrigin && runtimeBaseUrl && currentOrigin === runtimeBaseUrl);
9
+ };
10
+
11
+ const isDetachedTauriCliPreviewPage = () =>
12
+ !window.__TAURI__ &&
13
+ Array.from(document.scripts || []).some((script) =>
14
+ /__tauri_cli/.test(String(script && (script.text || script.textContent) || ''))
15
+ );
16
+
17
+ const getRuntimeBaseOrigin = () => {
18
+ const bridge = (typeof window !== 'undefined') ? window.NoteConnectionRuntime : null;
19
+ const baseUrl = bridge && typeof bridge.getBaseUrl === 'function'
20
+ ? String(bridge.getBaseUrl() || '').trim()
21
+ : '';
22
+ if (!baseUrl) {
23
+ return '';
24
+ }
25
+ try {
26
+ return new URL(baseUrl).origin;
27
+ } catch (_error) {
28
+ return '';
29
+ }
30
+ };
31
+
32
+ const isDetachedPreviewWithoutRuntimeBootstrap = () =>
33
+ isDetachedTauriCliPreviewPage() && window.location.origin !== getRuntimeBaseOrigin();
34
+
35
+ const canUseBrowserRuntimeBackend = () => {
36
+ if (typeof window === 'undefined' || window.__TAURI__) {
37
+ return false;
38
+ }
39
+ if (isDetachedPreviewWithoutRuntimeBootstrap()) {
40
+ return false;
41
+ }
42
+ if (hasExplicitBrowserRuntimeBootstrap()) {
43
+ return true;
44
+ }
45
+ const origin = String((window.location && window.location.origin) || '').trim().toLowerCase();
46
+ return /^https?:\/\/(?:127\.0\.0\.1|localhost):3000$/.test(origin);
47
+ };
48
+
2
49
  let runtimeCaps = {
3
50
  platform: 'web',
4
- supports_sidecar: true,
5
- supports_build: true,
6
- supports_content_api: true,
7
- supports_kb_runtime_change: true,
51
+ supports_sidecar: canUseBrowserRuntimeBackend(),
52
+ supports_build: canUseBrowserRuntimeBackend(),
53
+ supports_content_api: canUseBrowserRuntimeBackend(),
54
+ supports_kb_runtime_change: false,
8
55
  supports_native_pathmode: false,
9
56
  supports_mobile_wasm_compute: false,
10
57
  mobile_wasm_reason: 'non-mobile-runtime'
@@ -38,6 +85,11 @@ document.addEventListener('DOMContentLoaded', () => {
38
85
  return null;
39
86
  };
40
87
 
88
+ const isStandaloneFrontendPreviewRuntime = () =>
89
+ !window.__TAURI__ &&
90
+ !resolveCapacitorPlatform() &&
91
+ runtimeCaps.supports_sidecar !== true;
92
+
41
93
  const supportsCapacitorContentApi = () => {
42
94
  if (typeof window === 'undefined') {
43
95
  return false;
@@ -190,6 +242,20 @@ document.addEventListener('DOMContentLoaded', () => {
190
242
  supports_mobile_wasm_compute: runtimeCaps.supports_mobile_wasm_compute,
191
243
  mobile_wasm_reason: runtimeCaps.mobile_wasm_reason
192
244
  });
245
+ } else {
246
+ const browserRuntimeBackend = canUseBrowserRuntimeBackend();
247
+ runtimeCaps = {
248
+ ...runtimeCaps,
249
+ platform: 'web',
250
+ supports_sidecar: browserRuntimeBackend,
251
+ supports_build: browserRuntimeBackend,
252
+ supports_content_api: browserRuntimeBackend,
253
+ supports_kb_runtime_change: false,
254
+ supports_native_pathmode: false
255
+ };
256
+ if (!browserRuntimeBackend) {
257
+ console.log('[SourceManager] Frontend preview runtime detected: backend-dependent APIs disabled until a runtime bootstrap is provided.');
258
+ }
193
259
  }
194
260
  exposeRuntimeCaps();
195
261
  return;
@@ -249,6 +315,39 @@ document.addEventListener('DOMContentLoaded', () => {
249
315
  const parseGraphDataPayload = (text) => {
250
316
  const trimmed = text.trim();
251
317
  let parsed = null;
318
+ const extractAssignedJson = (sourceText, equalsIndex) => {
319
+ const textAfterEquals = sourceText.slice(equalsIndex + 1);
320
+ const openingIndex = textAfterEquals.search(/[\[{]/);
321
+ if (openingIndex < 0) {
322
+ return '';
323
+ }
324
+ const startIndex = equalsIndex + 1 + openingIndex;
325
+ const openingChar = sourceText.charAt(startIndex);
326
+ const closingChar = openingChar === '{' ? '}' : ']';
327
+ let depth = 0;
328
+ let inString = false;
329
+
330
+ for (let cursor = startIndex; cursor < sourceText.length; cursor += 1) {
331
+ const char = sourceText.charAt(cursor);
332
+ const previous = sourceText.charAt(cursor - 1);
333
+ if (char === '"' && previous !== '\\') {
334
+ inString = !inString;
335
+ }
336
+ if (inString) {
337
+ continue;
338
+ }
339
+ if (char === openingChar) {
340
+ depth += 1;
341
+ } else if (char === closingChar) {
342
+ depth -= 1;
343
+ if (depth === 0) {
344
+ return sourceText.slice(startIndex, cursor + 1);
345
+ }
346
+ }
347
+ }
348
+
349
+ return '';
350
+ };
252
351
 
253
352
  // Expected format: const graphData = {...};
254
353
  if (
@@ -258,10 +357,7 @@ document.addEventListener('DOMContentLoaded', () => {
258
357
  ) {
259
358
  const eqPos = trimmed.indexOf('=');
260
359
  if (eqPos > -1) {
261
- let jsonText = trimmed.slice(eqPos + 1).trim();
262
- if (jsonText.endsWith(';')) {
263
- jsonText = jsonText.slice(0, -1);
264
- }
360
+ const jsonText = extractAssignedJson(trimmed, eqPos);
265
361
  parsed = JSON.parse(jsonText);
266
362
  }
267
363
  } else if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
@@ -284,10 +380,7 @@ document.addEventListener('DOMContentLoaded', () => {
284
380
  if (equalsIndex < 0) {
285
381
  continue;
286
382
  }
287
- let candidateJson = trimmed.slice(equalsIndex + 1).trim();
288
- if (candidateJson.endsWith(';')) {
289
- candidateJson = candidateJson.slice(0, -1).trim();
290
- }
383
+ const candidateJson = extractAssignedJson(trimmed, equalsIndex);
291
384
  if (!candidateJson) {
292
385
  continue;
293
386
  }
@@ -324,6 +417,23 @@ document.addEventListener('DOMContentLoaded', () => {
324
417
  }
325
418
  }
326
419
 
420
+ if (isDetachedPreviewWithoutRuntimeBootstrap()) {
421
+ throw new Error('Detached preview runtime has no sidecar-backed graph asset bootstrap.');
422
+ }
423
+
424
+ if (!window.__TAURI__ && runtimeCaps.supports_sidecar !== true) {
425
+ const previewUrl = `${src}?v=${Date.now()}`;
426
+ const response = await fetch(previewUrl, { cache: 'no-store' });
427
+ if (!response.ok) {
428
+ throw new Error(`Failed to fetch ${src}: HTTP ${response.status}`);
429
+ }
430
+ const text = await response.text();
431
+ const parsed = parseGraphDataPayload(text);
432
+ window.graphData = parsed;
433
+ console.log(`[Loader] Loaded ${src} via frontend preview asset: ${parsed.nodes.length} nodes`);
434
+ return;
435
+ }
436
+
327
437
  // ─── Strategy 1: HTTP fetch from sidecar (works in browser, may fail in Tauri WebView) ───
328
438
  // 策略1:通过 HTTP 从 sidecar 获取(浏览器中有效,Tauri WebView 中可能因混合内容限制而失败)
329
439
  const maxAttempts = (window.__TAURI__ && runtimeCaps.supports_sidecar) ? 20 : 1;
@@ -379,10 +489,7 @@ document.addEventListener('DOMContentLoaded', () => {
379
489
 
380
490
  const loadScript = async (src) => {
381
491
  const isRuntimeGeneratedDataAsset = src.startsWith('data');
382
- const useRuntimeGeneratedAssetFlow = Boolean(
383
- isRuntimeGeneratedDataAsset &&
384
- (window.__TAURI__ || (typeof runtimeCaps.platform === 'string' && runtimeCaps.platform.startsWith('capacitor-')))
385
- );
492
+ const useRuntimeGeneratedAssetFlow = Boolean(isRuntimeGeneratedDataAsset);
386
493
  if (useRuntimeGeneratedAssetFlow) {
387
494
  await loadGraphDataFromSidecar(src);
388
495
  return;
@@ -452,6 +559,19 @@ document.addEventListener('DOMContentLoaded', () => {
452
559
  };
453
560
 
454
561
  const bootstrapScriptLoad = () => {
562
+ if (isDetachedPreviewWithoutRuntimeBootstrap()) {
563
+ console.log('[Loader] Detached preview runtime detected. Skipping runtime graph preload and loading app.js directly.');
564
+ triggerWelcomeModal(false);
565
+ loadScript('app.js')
566
+ .then(() => {
567
+ console.log('[Loader] app.js loaded successfully');
568
+ })
569
+ .catch(err => {
570
+ console.error('[Loader] Failed to load app.js (Critical Error):', err);
571
+ });
572
+ return;
573
+ }
574
+
455
575
  // Load data.js first (Critical Data), then app.js (Application Logic)
456
576
  loadScript('data.js')
457
577
  .then(() => {
@@ -492,7 +612,7 @@ document.addEventListener('DOMContentLoaded', () => {
492
612
 
493
613
  if (!folderSelect || !loadBtn) return;
494
614
  if (loadBtn.dataset.sourceManagerBound === '1') {
495
- console.warn('[SourceManager] Already initialized, skipping duplicate binding.');
615
+ console.log('[SourceManager] Duplicate binding guard triggered; skipping re-initialization.');
496
616
  return;
497
617
  }
498
618
  loadBtn.dataset.sourceManagerBound = '1';
@@ -610,6 +730,33 @@ document.addEventListener('DOMContentLoaded', () => {
610
730
  return await provider.checkCache(target);
611
731
  };
612
732
 
733
+ const ACTIVE_SOURCE_TARGET_EVENT = 'noteconnection:active-target-changed';
734
+
735
+ const normalizeActiveSourceTarget = (target) => {
736
+ const normalized = String(target || '').trim();
737
+ return normalized || 'ALL_FOLDERS';
738
+ };
739
+
740
+ const publishActiveSourceTarget = (target, source) => {
741
+ const normalizedTarget = normalizeActiveSourceTarget(target);
742
+ const payload = {
743
+ target: normalizedTarget,
744
+ source: String(source || 'source-manager').trim() || 'source-manager',
745
+ scope: normalizedTarget === 'ALL_FOLDERS'
746
+ ? null
747
+ : {
748
+ workspaceId: normalizedTarget.toLowerCase(),
749
+ corpusId: normalizedTarget.toLowerCase(),
750
+ sourcePathPrefixes: [`Knowledge_Base/${normalizedTarget}`],
751
+ },
752
+ };
753
+ window.__NC_ACTIVE_SOURCE_TARGET = payload;
754
+ if (typeof window.dispatchEvent === 'function' && typeof window.CustomEvent === 'function') {
755
+ window.dispatchEvent(new CustomEvent(ACTIVE_SOURCE_TARGET_EVENT, { detail: payload }));
756
+ }
757
+ return payload;
758
+ };
759
+
613
760
  const syncSidecarKbPath = async (kbPath) => {
614
761
  if (!kbPath) {
615
762
  return;
@@ -775,7 +922,13 @@ document.addEventListener('DOMContentLoaded', () => {
775
922
  let folders = [];
776
923
  const inCapacitorRuntime = isCapacitorNativeRuntime();
777
924
 
778
- if (inCapacitorRuntime) {
925
+ if (
926
+ isStandaloneFrontendPreviewRuntime() ||
927
+ isDetachedPreviewWithoutRuntimeBootstrap()
928
+ ) {
929
+ kbPath = t('source.previewPath');
930
+ folders = [];
931
+ } else if (inCapacitorRuntime) {
779
932
  kbPath = t('source.capacitor.bundlePath');
780
933
  const provider = getStorageProvider();
781
934
  let listedFolders = [];
@@ -868,6 +1021,17 @@ document.addEventListener('DOMContentLoaded', () => {
868
1021
  folderSelect.appendChild(packagedOption);
869
1022
  }
870
1023
 
1024
+ if (folderSelect.options.length === 0 && isStandaloneFrontendPreviewRuntime()) {
1025
+ const previewOption = document.createElement('option');
1026
+ previewOption.value = '';
1027
+ previewOption.disabled = true;
1028
+ previewOption.selected = true;
1029
+ previewOption.textContent = t('source.previewPath');
1030
+ folderSelect.appendChild(previewOption);
1031
+ loadBtn.disabled = true;
1032
+ return;
1033
+ }
1034
+
871
1035
  if (folderSelect.options.length === 0) {
872
1036
  const emptyOption = document.createElement('option');
873
1037
  emptyOption.value = '';
@@ -892,6 +1056,7 @@ document.addEventListener('DOMContentLoaded', () => {
892
1056
  } else {
893
1057
  folderSelect.value = folderSelect.options[0].value;
894
1058
  }
1059
+ publishActiveSourceTarget(folderSelect.value, 'folder-bootstrap');
895
1060
  console.log('[SourceManager] Folder dropdown populated with', folderSelect.options.length, 'options');
896
1061
 
897
1062
  } catch (err) {
@@ -913,10 +1078,10 @@ document.addEventListener('DOMContentLoaded', () => {
913
1078
  updateRuntimeCapabilityNotice();
914
1079
  updateKbPathControls();
915
1080
 
916
- // Start static graph/frontend bootstrap immediately so UI initialization
917
- // does not block on sidecar ping retries.
1081
+ if (window.__TAURI__ && runtimeCaps.supports_sidecar) {
1082
+ await waitForSidecarReady();
1083
+ }
918
1084
  bootstrapScriptLoad();
919
- await waitForSidecarReady();
920
1085
 
921
1086
  if (window.i18n && window.i18n.isInitialized) {
922
1087
  await fetchFolders();
@@ -938,6 +1103,7 @@ document.addEventListener('DOMContentLoaded', () => {
938
1103
  if (folderSelect.value) {
939
1104
  localStorage.setItem(LAST_TARGET_KEY, folderSelect.value);
940
1105
  }
1106
+ publishActiveSourceTarget(folderSelect.value, 'folder-change');
941
1107
  });
942
1108
 
943
1109
  // Add refresh functionality (will be triggered by IPC event from main process)
@@ -1039,6 +1205,7 @@ document.addEventListener('DOMContentLoaded', () => {
1039
1205
  return;
1040
1206
  }
1041
1207
  localStorage.setItem(LAST_TARGET_KEY, target);
1208
+ publishActiveSourceTarget(target, 'build-request');
1042
1209
 
1043
1210
  // Feature: Check for cached graph (Multi-Session Optimization)
1044
1211
  // Bridge-first runtime: sidecar HTTP path with Tauri IPC fallback.
@@ -1067,6 +1234,7 @@ document.addEventListener('DOMContentLoaded', () => {
1067
1234
  const restoreSuccess = await storageProvider.restoreCache(target);
1068
1235
 
1069
1236
  if (restoreSuccess) {
1237
+ publishActiveSourceTarget(target, 'cache-restore');
1070
1238
  keepLockedForReload = requestSafeReload('cache-restore', { force: true });
1071
1239
  return;
1072
1240
  }
@@ -1134,6 +1302,7 @@ document.addEventListener('DOMContentLoaded', () => {
1134
1302
  }
1135
1303
 
1136
1304
  if (success) {
1305
+ publishActiveSourceTarget(target, 'build-success');
1137
1306
  keepLockedForReload = true;
1138
1307
 
1139
1308
  // v1.0.1: Pre-verify data.js is accessible before triggering reload.