@ninebix/nmt-system 1.0.2 → 1.0.3

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 (430) hide show
  1. package/README.md +288 -213
  2. package/dashboard-lite/index.html +1083 -762
  3. package/dist/bin/nmt.js +171 -40
  4. package/dist/bin/nmt.js.map +1 -1
  5. package/dist/src/api/cli-server.d.ts.map +1 -1
  6. package/dist/src/api/cli-server.js +156 -0
  7. package/dist/src/api/cli-server.js.map +1 -1
  8. package/dist/src/core/attractor-model.d.ts +5 -2
  9. package/dist/src/core/attractor-model.d.ts.map +1 -1
  10. package/dist/src/core/attractor-model.js +7 -4
  11. package/dist/src/core/attractor-model.js.map +1 -1
  12. package/dist/src/core/neuron-graph.d.ts.map +1 -1
  13. package/dist/src/core/neuron-graph.js +41 -7
  14. package/dist/src/core/neuron-graph.js.map +1 -1
  15. package/dist/src/mcp/server.d.ts.map +1 -1
  16. package/dist/src/mcp/server.js +168 -34
  17. package/dist/src/mcp/server.js.map +1 -1
  18. package/dist/src/services/four-stage-learning.d.ts +19 -0
  19. package/dist/src/services/four-stage-learning.d.ts.map +1 -1
  20. package/dist/src/services/four-stage-learning.js +113 -17
  21. package/dist/src/services/four-stage-learning.js.map +1 -1
  22. package/dist/src/storage/neuron-store.d.ts +2 -0
  23. package/dist/src/storage/neuron-store.d.ts.map +1 -1
  24. package/dist/src/storage/neuron-store.js +22 -14
  25. package/dist/src/storage/neuron-store.js.map +1 -1
  26. package/package.json +1 -1
  27. package/dist/api/cli-server.d.ts +0 -83
  28. package/dist/api/cli-server.d.ts.map +0 -1
  29. package/dist/api/cli-server.js +0 -597
  30. package/dist/api/cli-server.js.map +0 -1
  31. package/dist/api/index.d.ts +0 -6
  32. package/dist/api/index.d.ts.map +0 -1
  33. package/dist/api/index.js +0 -6
  34. package/dist/api/index.js.map +0 -1
  35. package/dist/api/middleware/index.d.ts +0 -12
  36. package/dist/api/middleware/index.d.ts.map +0 -1
  37. package/dist/api/middleware/index.js +0 -13
  38. package/dist/api/middleware/index.js.map +0 -1
  39. package/dist/api/middleware/logger.d.ts +0 -21
  40. package/dist/api/middleware/logger.d.ts.map +0 -1
  41. package/dist/api/middleware/logger.js +0 -134
  42. package/dist/api/middleware/logger.js.map +0 -1
  43. package/dist/api/middleware/rate-limit.d.ts +0 -26
  44. package/dist/api/middleware/rate-limit.d.ts.map +0 -1
  45. package/dist/api/middleware/rate-limit.js +0 -107
  46. package/dist/api/middleware/rate-limit.js.map +0 -1
  47. package/dist/api/middleware/response.d.ts +0 -61
  48. package/dist/api/middleware/response.d.ts.map +0 -1
  49. package/dist/api/middleware/response.js +0 -86
  50. package/dist/api/middleware/response.js.map +0 -1
  51. package/dist/api/middleware/validation.d.ts +0 -43
  52. package/dist/api/middleware/validation.d.ts.map +0 -1
  53. package/dist/api/middleware/validation.js +0 -257
  54. package/dist/api/middleware/validation.js.map +0 -1
  55. package/dist/api/server.d.ts +0 -79
  56. package/dist/api/server.d.ts.map +0 -1
  57. package/dist/api/server.js +0 -2011
  58. package/dist/api/server.js.map +0 -1
  59. package/dist/cli/commands/attractor.d.ts +0 -6
  60. package/dist/cli/commands/attractor.d.ts.map +0 -1
  61. package/dist/cli/commands/attractor.js +0 -167
  62. package/dist/cli/commands/attractor.js.map +0 -1
  63. package/dist/cli/commands/dimension.d.ts +0 -6
  64. package/dist/cli/commands/dimension.d.ts.map +0 -1
  65. package/dist/cli/commands/dimension.js +0 -85
  66. package/dist/cli/commands/dimension.js.map +0 -1
  67. package/dist/cli/commands/index.d.ts +0 -11
  68. package/dist/cli/commands/index.d.ts.map +0 -1
  69. package/dist/cli/commands/index.js +0 -11
  70. package/dist/cli/commands/index.js.map +0 -1
  71. package/dist/cli/commands/infer.d.ts +0 -6
  72. package/dist/cli/commands/infer.d.ts.map +0 -1
  73. package/dist/cli/commands/infer.js +0 -139
  74. package/dist/cli/commands/infer.js.map +0 -1
  75. package/dist/cli/commands/learn.d.ts +0 -6
  76. package/dist/cli/commands/learn.d.ts.map +0 -1
  77. package/dist/cli/commands/learn.js +0 -87
  78. package/dist/cli/commands/learn.js.map +0 -1
  79. package/dist/cli/commands/orchestrate.d.ts +0 -6
  80. package/dist/cli/commands/orchestrate.d.ts.map +0 -1
  81. package/dist/cli/commands/orchestrate.js +0 -279
  82. package/dist/cli/commands/orchestrate.js.map +0 -1
  83. package/dist/cli/commands/prob.d.ts +0 -6
  84. package/dist/cli/commands/prob.d.ts.map +0 -1
  85. package/dist/cli/commands/prob.js +0 -256
  86. package/dist/cli/commands/prob.js.map +0 -1
  87. package/dist/cli/commands/quantum.d.ts +0 -6
  88. package/dist/cli/commands/quantum.d.ts.map +0 -1
  89. package/dist/cli/commands/quantum.js +0 -150
  90. package/dist/cli/commands/quantum.js.map +0 -1
  91. package/dist/cli/commands/sync.d.ts +0 -65
  92. package/dist/cli/commands/sync.d.ts.map +0 -1
  93. package/dist/cli/commands/sync.js +0 -338
  94. package/dist/cli/commands/sync.js.map +0 -1
  95. package/dist/cli/index.d.ts +0 -9
  96. package/dist/cli/index.d.ts.map +0 -1
  97. package/dist/cli/index.js +0 -9
  98. package/dist/cli/index.js.map +0 -1
  99. package/dist/cli/probabilistic-commands.d.ts +0 -39
  100. package/dist/cli/probabilistic-commands.d.ts.map +0 -1
  101. package/dist/cli/probabilistic-commands.js +0 -112
  102. package/dist/cli/probabilistic-commands.js.map +0 -1
  103. package/dist/cli/types.d.ts +0 -69
  104. package/dist/cli/types.d.ts.map +0 -1
  105. package/dist/cli/types.js +0 -5
  106. package/dist/cli/types.js.map +0 -1
  107. package/dist/cli/utils/formatters.d.ts +0 -51
  108. package/dist/cli/utils/formatters.d.ts.map +0 -1
  109. package/dist/cli/utils/formatters.js +0 -79
  110. package/dist/cli/utils/formatters.js.map +0 -1
  111. package/dist/cli/utils/helpers.d.ts +0 -21
  112. package/dist/cli/utils/helpers.d.ts.map +0 -1
  113. package/dist/cli/utils/helpers.js +0 -51
  114. package/dist/cli/utils/helpers.js.map +0 -1
  115. package/dist/cli/utils/index.d.ts +0 -7
  116. package/dist/cli/utils/index.d.ts.map +0 -1
  117. package/dist/cli/utils/index.js +0 -13
  118. package/dist/cli/utils/index.js.map +0 -1
  119. package/dist/cli/utils/validators.d.ts +0 -162
  120. package/dist/cli/utils/validators.d.ts.map +0 -1
  121. package/dist/cli/utils/validators.js +0 -351
  122. package/dist/cli/utils/validators.js.map +0 -1
  123. package/dist/core/advanced-embedding.d.ts +0 -154
  124. package/dist/core/advanced-embedding.d.ts.map +0 -1
  125. package/dist/core/advanced-embedding.js +0 -367
  126. package/dist/core/advanced-embedding.js.map +0 -1
  127. package/dist/core/attractor-model.d.ts +0 -381
  128. package/dist/core/attractor-model.d.ts.map +0 -1
  129. package/dist/core/attractor-model.js +0 -821
  130. package/dist/core/attractor-model.js.map +0 -1
  131. package/dist/core/bidirectional-inference.d.ts +0 -143
  132. package/dist/core/bidirectional-inference.d.ts.map +0 -1
  133. package/dist/core/bidirectional-inference.js +0 -501
  134. package/dist/core/bidirectional-inference.js.map +0 -1
  135. package/dist/core/chunk-engine.d.ts +0 -78
  136. package/dist/core/chunk-engine.d.ts.map +0 -1
  137. package/dist/core/chunk-engine.js +0 -192
  138. package/dist/core/chunk-engine.js.map +0 -1
  139. package/dist/core/dynamic-embedding.d.ts +0 -327
  140. package/dist/core/dynamic-embedding.d.ts.map +0 -1
  141. package/dist/core/dynamic-embedding.js +0 -527
  142. package/dist/core/dynamic-embedding.js.map +0 -1
  143. package/dist/core/embedding-similarity.d.ts +0 -68
  144. package/dist/core/embedding-similarity.d.ts.map +0 -1
  145. package/dist/core/embedding-similarity.js +0 -291
  146. package/dist/core/embedding-similarity.js.map +0 -1
  147. package/dist/core/evolution-scheduler.d.ts +0 -101
  148. package/dist/core/evolution-scheduler.d.ts.map +0 -1
  149. package/dist/core/evolution-scheduler.js +0 -235
  150. package/dist/core/evolution-scheduler.js.map +0 -1
  151. package/dist/core/hierarchical-chunker.d.ts +0 -108
  152. package/dist/core/hierarchical-chunker.d.ts.map +0 -1
  153. package/dist/core/hierarchical-chunker.js +0 -296
  154. package/dist/core/hierarchical-chunker.js.map +0 -1
  155. package/dist/core/hnsw-index.d.ts +0 -111
  156. package/dist/core/hnsw-index.d.ts.map +0 -1
  157. package/dist/core/hnsw-index.js +0 -466
  158. package/dist/core/hnsw-index.js.map +0 -1
  159. package/dist/core/index.d.ts +0 -23
  160. package/dist/core/index.d.ts.map +0 -1
  161. package/dist/core/index.js +0 -25
  162. package/dist/core/index.js.map +0 -1
  163. package/dist/core/language-analyzers.d.ts +0 -124
  164. package/dist/core/language-analyzers.d.ts.map +0 -1
  165. package/dist/core/language-analyzers.js +0 -365
  166. package/dist/core/language-analyzers.js.map +0 -1
  167. package/dist/core/local-embedding.d.ts +0 -109
  168. package/dist/core/local-embedding.d.ts.map +0 -1
  169. package/dist/core/local-embedding.js +0 -222
  170. package/dist/core/local-embedding.js.map +0 -1
  171. package/dist/core/merkle-engine.d.ts +0 -263
  172. package/dist/core/merkle-engine.d.ts.map +0 -1
  173. package/dist/core/merkle-engine.js +0 -528
  174. package/dist/core/merkle-engine.js.map +0 -1
  175. package/dist/core/multi-layer-reasoning.d.ts +0 -178
  176. package/dist/core/multi-layer-reasoning.d.ts.map +0 -1
  177. package/dist/core/multi-layer-reasoning.js +0 -607
  178. package/dist/core/multi-layer-reasoning.js.map +0 -1
  179. package/dist/core/neuron-graph.d.ts +0 -134
  180. package/dist/core/neuron-graph.d.ts.map +0 -1
  181. package/dist/core/neuron-graph.js +0 -436
  182. package/dist/core/neuron-graph.js.map +0 -1
  183. package/dist/core/probabilistic-neuron.d.ts +0 -251
  184. package/dist/core/probabilistic-neuron.d.ts.map +0 -1
  185. package/dist/core/probabilistic-neuron.js +0 -618
  186. package/dist/core/probabilistic-neuron.js.map +0 -1
  187. package/dist/core/probabilistic-orchestrator.d.ts +0 -408
  188. package/dist/core/probabilistic-orchestrator.d.ts.map +0 -1
  189. package/dist/core/probabilistic-orchestrator.js +0 -798
  190. package/dist/core/probabilistic-orchestrator.js.map +0 -1
  191. package/dist/core/semantic-chunker.d.ts +0 -117
  192. package/dist/core/semantic-chunker.d.ts.map +0 -1
  193. package/dist/core/semantic-chunker.js +0 -464
  194. package/dist/core/semantic-chunker.js.map +0 -1
  195. package/dist/events/event-bus.d.ts +0 -166
  196. package/dist/events/event-bus.d.ts.map +0 -1
  197. package/dist/events/event-bus.js +0 -228
  198. package/dist/events/event-bus.js.map +0 -1
  199. package/dist/events/index.d.ts +0 -7
  200. package/dist/events/index.d.ts.map +0 -1
  201. package/dist/events/index.js +0 -7
  202. package/dist/events/index.js.map +0 -1
  203. package/dist/events/progress-tracker.d.ts +0 -150
  204. package/dist/events/progress-tracker.d.ts.map +0 -1
  205. package/dist/events/progress-tracker.js +0 -290
  206. package/dist/events/progress-tracker.js.map +0 -1
  207. package/dist/extensions/clustering/community-detection.d.ts +0 -90
  208. package/dist/extensions/clustering/community-detection.d.ts.map +0 -1
  209. package/dist/extensions/clustering/community-detection.js +0 -470
  210. package/dist/extensions/clustering/community-detection.js.map +0 -1
  211. package/dist/extensions/clustering/index.d.ts +0 -114
  212. package/dist/extensions/clustering/index.d.ts.map +0 -1
  213. package/dist/extensions/clustering/index.js +0 -468
  214. package/dist/extensions/clustering/index.js.map +0 -1
  215. package/dist/extensions/clustering/topic-modeling.d.ts +0 -86
  216. package/dist/extensions/clustering/topic-modeling.d.ts.map +0 -1
  217. package/dist/extensions/clustering/topic-modeling.js +0 -355
  218. package/dist/extensions/clustering/topic-modeling.js.map +0 -1
  219. package/dist/extensions/distributed/coordinator.d.ts +0 -114
  220. package/dist/extensions/distributed/coordinator.d.ts.map +0 -1
  221. package/dist/extensions/distributed/coordinator.js +0 -319
  222. package/dist/extensions/distributed/coordinator.js.map +0 -1
  223. package/dist/extensions/distributed/index.d.ts +0 -10
  224. package/dist/extensions/distributed/index.d.ts.map +0 -1
  225. package/dist/extensions/distributed/index.js +0 -10
  226. package/dist/extensions/distributed/index.js.map +0 -1
  227. package/dist/extensions/distributed/queue.d.ts +0 -157
  228. package/dist/extensions/distributed/queue.d.ts.map +0 -1
  229. package/dist/extensions/distributed/queue.js +0 -326
  230. package/dist/extensions/distributed/queue.js.map +0 -1
  231. package/dist/extensions/distributed/scheduler.d.ts +0 -107
  232. package/dist/extensions/distributed/scheduler.d.ts.map +0 -1
  233. package/dist/extensions/distributed/scheduler.js +0 -301
  234. package/dist/extensions/distributed/scheduler.js.map +0 -1
  235. package/dist/extensions/distributed/worker.d.ts +0 -112
  236. package/dist/extensions/distributed/worker.d.ts.map +0 -1
  237. package/dist/extensions/distributed/worker.js +0 -260
  238. package/dist/extensions/distributed/worker.js.map +0 -1
  239. package/dist/index.d.ts +0 -14
  240. package/dist/index.d.ts.map +0 -1
  241. package/dist/index.js +0 -20
  242. package/dist/index.js.map +0 -1
  243. package/dist/mcp/server.d.ts +0 -43
  244. package/dist/mcp/server.d.ts.map +0 -1
  245. package/dist/mcp/server.js +0 -494
  246. package/dist/mcp/server.js.map +0 -1
  247. package/dist/services/adaptive-fallback.d.ts +0 -140
  248. package/dist/services/adaptive-fallback.d.ts.map +0 -1
  249. package/dist/services/adaptive-fallback.js +0 -273
  250. package/dist/services/adaptive-fallback.js.map +0 -1
  251. package/dist/services/answer-gate.d.ts +0 -112
  252. package/dist/services/answer-gate.d.ts.map +0 -1
  253. package/dist/services/answer-gate.js +0 -299
  254. package/dist/services/answer-gate.js.map +0 -1
  255. package/dist/services/auto-learning.d.ts +0 -135
  256. package/dist/services/auto-learning.d.ts.map +0 -1
  257. package/dist/services/auto-learning.js +0 -413
  258. package/dist/services/auto-learning.js.map +0 -1
  259. package/dist/services/context-compressor.d.ts +0 -77
  260. package/dist/services/context-compressor.d.ts.map +0 -1
  261. package/dist/services/context-compressor.js +0 -234
  262. package/dist/services/context-compressor.js.map +0 -1
  263. package/dist/services/efficient-rag.d.ts +0 -140
  264. package/dist/services/efficient-rag.d.ts.map +0 -1
  265. package/dist/services/efficient-rag.js +0 -311
  266. package/dist/services/efficient-rag.js.map +0 -1
  267. package/dist/services/embedding-provider.d.ts +0 -72
  268. package/dist/services/embedding-provider.d.ts.map +0 -1
  269. package/dist/services/embedding-provider.js +0 -176
  270. package/dist/services/embedding-provider.js.map +0 -1
  271. package/dist/services/file-ingestion.d.ts +0 -72
  272. package/dist/services/file-ingestion.d.ts.map +0 -1
  273. package/dist/services/file-ingestion.js +0 -237
  274. package/dist/services/file-ingestion.js.map +0 -1
  275. package/dist/services/four-stage-learning.d.ts +0 -552
  276. package/dist/services/four-stage-learning.d.ts.map +0 -1
  277. package/dist/services/four-stage-learning.js +0 -1110
  278. package/dist/services/four-stage-learning.js.map +0 -1
  279. package/dist/services/graph.d.ts +0 -94
  280. package/dist/services/graph.d.ts.map +0 -1
  281. package/dist/services/graph.js +0 -292
  282. package/dist/services/graph.js.map +0 -1
  283. package/dist/services/index.d.ts +0 -15
  284. package/dist/services/index.d.ts.map +0 -1
  285. package/dist/services/index.js +0 -18
  286. package/dist/services/index.js.map +0 -1
  287. package/dist/services/ingestion.d.ts +0 -98
  288. package/dist/services/ingestion.d.ts.map +0 -1
  289. package/dist/services/ingestion.js +0 -259
  290. package/dist/services/ingestion.js.map +0 -1
  291. package/dist/services/learning.d.ts +0 -67
  292. package/dist/services/learning.d.ts.map +0 -1
  293. package/dist/services/learning.js +0 -262
  294. package/dist/services/learning.js.map +0 -1
  295. package/dist/services/llm-router.d.ts +0 -143
  296. package/dist/services/llm-router.d.ts.map +0 -1
  297. package/dist/services/llm-router.js +0 -284
  298. package/dist/services/llm-router.js.map +0 -1
  299. package/dist/services/llm.d.ts +0 -86
  300. package/dist/services/llm.d.ts.map +0 -1
  301. package/dist/services/llm.js +0 -283
  302. package/dist/services/llm.js.map +0 -1
  303. package/dist/services/metrics-dashboard.d.ts +0 -262
  304. package/dist/services/metrics-dashboard.d.ts.map +0 -1
  305. package/dist/services/metrics-dashboard.js +0 -417
  306. package/dist/services/metrics-dashboard.js.map +0 -1
  307. package/dist/services/neuron-lifecycle.d.ts +0 -137
  308. package/dist/services/neuron-lifecycle.d.ts.map +0 -1
  309. package/dist/services/neuron-lifecycle.js +0 -422
  310. package/dist/services/neuron-lifecycle.js.map +0 -1
  311. package/dist/services/nmt-pipeline.d.ts +0 -219
  312. package/dist/services/nmt-pipeline.d.ts.map +0 -1
  313. package/dist/services/nmt-pipeline.js +0 -449
  314. package/dist/services/nmt-pipeline.js.map +0 -1
  315. package/dist/services/query-cache.d.ts +0 -136
  316. package/dist/services/query-cache.d.ts.map +0 -1
  317. package/dist/services/query-cache.js +0 -255
  318. package/dist/services/query-cache.js.map +0 -1
  319. package/dist/services/query-normalize.d.ts +0 -107
  320. package/dist/services/query-normalize.d.ts.map +0 -1
  321. package/dist/services/query-normalize.js +0 -366
  322. package/dist/services/query-normalize.js.map +0 -1
  323. package/dist/services/query.d.ts +0 -102
  324. package/dist/services/query.d.ts.map +0 -1
  325. package/dist/services/query.js +0 -227
  326. package/dist/services/query.js.map +0 -1
  327. package/dist/services/text-embedding.d.ts +0 -183
  328. package/dist/services/text-embedding.d.ts.map +0 -1
  329. package/dist/services/text-embedding.js +0 -633
  330. package/dist/services/text-embedding.js.map +0 -1
  331. package/dist/services/verification-gate.d.ts +0 -147
  332. package/dist/services/verification-gate.d.ts.map +0 -1
  333. package/dist/services/verification-gate.js +0 -344
  334. package/dist/services/verification-gate.js.map +0 -1
  335. package/dist/services/verify.d.ts +0 -114
  336. package/dist/services/verify.d.ts.map +0 -1
  337. package/dist/services/verify.js +0 -237
  338. package/dist/services/verify.js.map +0 -1
  339. package/dist/services/web-search.d.ts +0 -145
  340. package/dist/services/web-search.d.ts.map +0 -1
  341. package/dist/services/web-search.js +0 -534
  342. package/dist/services/web-search.js.map +0 -1
  343. package/dist/storage/chunk-store.d.ts +0 -107
  344. package/dist/storage/chunk-store.d.ts.map +0 -1
  345. package/dist/storage/chunk-store.js +0 -293
  346. package/dist/storage/chunk-store.js.map +0 -1
  347. package/dist/storage/hybrid-adapters.d.ts +0 -111
  348. package/dist/storage/hybrid-adapters.d.ts.map +0 -1
  349. package/dist/storage/hybrid-adapters.js +0 -223
  350. package/dist/storage/hybrid-adapters.js.map +0 -1
  351. package/dist/storage/hybrid-store.d.ts +0 -125
  352. package/dist/storage/hybrid-store.d.ts.map +0 -1
  353. package/dist/storage/hybrid-store.js +0 -655
  354. package/dist/storage/hybrid-store.js.map +0 -1
  355. package/dist/storage/index-store.d.ts +0 -126
  356. package/dist/storage/index-store.d.ts.map +0 -1
  357. package/dist/storage/index-store.js +0 -316
  358. package/dist/storage/index-store.js.map +0 -1
  359. package/dist/storage/index.d.ts +0 -45
  360. package/dist/storage/index.d.ts.map +0 -1
  361. package/dist/storage/index.js +0 -52
  362. package/dist/storage/index.js.map +0 -1
  363. package/dist/storage/neuron-store.d.ts +0 -121
  364. package/dist/storage/neuron-store.d.ts.map +0 -1
  365. package/dist/storage/neuron-store.js +0 -466
  366. package/dist/storage/neuron-store.js.map +0 -1
  367. package/dist/storage/ontology-store.d.ts +0 -132
  368. package/dist/storage/ontology-store.d.ts.map +0 -1
  369. package/dist/storage/ontology-store.js +0 -319
  370. package/dist/storage/ontology-store.js.map +0 -1
  371. package/dist/storage/probabilistic-store.d.ts +0 -104
  372. package/dist/storage/probabilistic-store.d.ts.map +0 -1
  373. package/dist/storage/probabilistic-store.js +0 -257
  374. package/dist/storage/probabilistic-store.js.map +0 -1
  375. package/dist/storage/redis-adapters.d.ts +0 -102
  376. package/dist/storage/redis-adapters.d.ts.map +0 -1
  377. package/dist/storage/redis-adapters.js +0 -205
  378. package/dist/storage/redis-adapters.js.map +0 -1
  379. package/dist/storage/redis-ontology-store.d.ts +0 -146
  380. package/dist/storage/redis-ontology-store.d.ts.map +0 -1
  381. package/dist/storage/redis-ontology-store.js +0 -384
  382. package/dist/storage/redis-ontology-store.js.map +0 -1
  383. package/dist/storage/redis-store.d.ts +0 -174
  384. package/dist/storage/redis-store.d.ts.map +0 -1
  385. package/dist/storage/redis-store.js +0 -506
  386. package/dist/storage/redis-store.js.map +0 -1
  387. package/dist/sync/change-journal.d.ts +0 -171
  388. package/dist/sync/change-journal.d.ts.map +0 -1
  389. package/dist/sync/change-journal.js +0 -362
  390. package/dist/sync/change-journal.js.map +0 -1
  391. package/dist/sync/index.d.ts +0 -8
  392. package/dist/sync/index.d.ts.map +0 -1
  393. package/dist/sync/index.js +0 -8
  394. package/dist/sync/index.js.map +0 -1
  395. package/dist/sync/state-sync.d.ts +0 -241
  396. package/dist/sync/state-sync.d.ts.map +0 -1
  397. package/dist/sync/state-sync.js +0 -396
  398. package/dist/sync/state-sync.js.map +0 -1
  399. package/dist/sync/vector-clock.d.ts +0 -144
  400. package/dist/sync/vector-clock.d.ts.map +0 -1
  401. package/dist/sync/vector-clock.js +0 -266
  402. package/dist/sync/vector-clock.js.map +0 -1
  403. package/dist/types/index.d.ts +0 -224
  404. package/dist/types/index.d.ts.map +0 -1
  405. package/dist/types/index.js +0 -24
  406. package/dist/types/index.js.map +0 -1
  407. package/dist/utils/hash.d.ts +0 -39
  408. package/dist/utils/hash.d.ts.map +0 -1
  409. package/dist/utils/hash.js +0 -56
  410. package/dist/utils/hash.js.map +0 -1
  411. package/dist/utils/index.d.ts +0 -26
  412. package/dist/utils/index.d.ts.map +0 -1
  413. package/dist/utils/index.js +0 -50
  414. package/dist/utils/index.js.map +0 -1
  415. package/dist/utils/logger.d.ts +0 -88
  416. package/dist/utils/logger.d.ts.map +0 -1
  417. package/dist/utils/logger.js +0 -157
  418. package/dist/utils/logger.js.map +0 -1
  419. package/dist/utils/metrics.d.ts +0 -232
  420. package/dist/utils/metrics.d.ts.map +0 -1
  421. package/dist/utils/metrics.js +0 -387
  422. package/dist/utils/metrics.js.map +0 -1
  423. package/dist/utils/similarity.d.ts +0 -64
  424. package/dist/utils/similarity.d.ts.map +0 -1
  425. package/dist/utils/similarity.js +0 -151
  426. package/dist/utils/similarity.js.map +0 -1
  427. package/dist/utils/uuid.d.ts +0 -23
  428. package/dist/utils/uuid.d.ts.map +0 -1
  429. package/dist/utils/uuid.js +0 -29
  430. package/dist/utils/uuid.js.map +0 -1
@@ -3,15 +3,45 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>NMT Dashboard Lite</title>
6
+ <title>NMT Dashboard</title>
7
7
  <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://d3js.org/d3.v7.min.js"></script>
8
9
  <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
10
+ <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
11
+ <link href="https://fonts.googleapis.com/icon?family=Material+Icons+Outlined" rel="stylesheet">
9
12
  <script>
10
13
  tailwind.config = {
14
+ darkMode: 'class',
11
15
  theme: {
12
16
  extend: {
13
17
  fontFamily: {
14
- mono: ['ui-monospace', 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New', 'monospace'],
18
+ roboto: ['Roboto', 'sans-serif'],
19
+ mono: ['Roboto Mono', 'ui-monospace', 'monospace'],
20
+ },
21
+ colors: {
22
+ md: {
23
+ primary: '#1976D2',
24
+ 'primary-dark': '#1565C0',
25
+ 'primary-light': '#42A5F5',
26
+ 'on-primary': '#FFFFFF',
27
+ secondary: '#9C27B0',
28
+ surface: '#FFFFFF',
29
+ 'surface-dark': '#1E1E1E',
30
+ 'surface-variant': '#F5F5F5',
31
+ 'surface-variant-dark': '#2D2D2D',
32
+ outline: '#E0E0E0',
33
+ 'outline-dark': '#424242',
34
+ 'on-surface': '#1C1B1F',
35
+ 'on-surface-dark': '#E6E1E5',
36
+ error: '#B3261E',
37
+ success: '#2E7D32',
38
+ }
39
+ },
40
+ boxShadow: {
41
+ 'md-1': '0 1px 2px rgba(0,0,0,0.3), 0 1px 3px 1px rgba(0,0,0,0.15)',
42
+ 'md-2': '0 1px 2px rgba(0,0,0,0.3), 0 2px 6px 2px rgba(0,0,0,0.15)',
43
+ 'md-3': '0 4px 8px 3px rgba(0,0,0,0.15), 0 1px 3px rgba(0,0,0,0.3)',
44
+ 'md-4': '0 6px 10px 4px rgba(0,0,0,0.15), 0 2px 3px rgba(0,0,0,0.3)',
15
45
  }
16
46
  }
17
47
  }
@@ -19,699 +49,942 @@
19
49
  </script>
20
50
  <style>
21
51
  [x-cloak] { display: none !important; }
22
- ::-webkit-scrollbar { width: 6px; height: 6px; }
23
- ::-webkit-scrollbar-track { background: #f1f5f9; }
24
- ::-webkit-scrollbar-thumb { background: #94a3b8; border-radius: 3px; }
25
- ::-webkit-scrollbar-thumb:hover { background: #64748b; }
52
+ ::-webkit-scrollbar { width: 8px; height: 8px; }
53
+ ::-webkit-scrollbar-track { background: transparent; }
54
+ ::-webkit-scrollbar-thumb { background: #BDBDBD; border-radius: 4px; }
55
+ .dark ::-webkit-scrollbar-thumb { background: #616161; }
56
+ ::-webkit-scrollbar-thumb:hover { background: #9E9E9E; }
57
+ .dark ::-webkit-scrollbar-thumb:hover { background: #757575; }
58
+ .material-icons-outlined { font-size: 24px; vertical-align: middle; }
59
+ .nav-item { transition: background-color 0.2s, color 0.2s; }
60
+ .nav-item:hover { background-color: rgba(25, 118, 210, 0.08); }
61
+ .dark .nav-item:hover { background-color: rgba(66, 165, 245, 0.12); }
62
+ .nav-item.active { background-color: rgba(25, 118, 210, 0.12); color: #1976D2; }
63
+ .dark .nav-item.active { background-color: rgba(66, 165, 245, 0.16); color: #42A5F5; }
64
+ .ripple { position: relative; overflow: hidden; }
65
+ .ripple::after { content: ''; position: absolute; inset: 0; background: radial-gradient(circle, rgba(255,255,255,0.3) 10%, transparent 10.01%); transform: scale(10); opacity: 0; transition: transform 0.5s, opacity 0.3s; }
66
+ .ripple:active::after { transform: scale(0); opacity: 0.3; transition: 0s; }
67
+ .card { transition: box-shadow 0.2s ease; }
68
+ .card:hover { box-shadow: 0 6px 10px 4px rgba(0,0,0,0.15), 0 2px 3px rgba(0,0,0,0.3); }
26
69
  </style>
27
70
  </head>
28
- <body class="bg-gray-100 min-h-screen" x-data="dashboard()" x-init="init()">
71
+ <body class="font-roboto bg-md-surface-variant dark:bg-md-surface-dark min-h-screen transition-colors duration-300"
72
+ x-data="dashboard()" x-init="init()" :class="{ 'dark': darkMode }">
73
+
74
+ <!-- Top Navigation Bar -->
75
+ <header class="fixed top-0 left-0 right-0 z-50 bg-md-primary dark:bg-md-surface-dark shadow-md-2 h-16">
76
+ <div class="flex items-center h-full px-4">
77
+ <!-- Menu Toggle -->
78
+ <button @click="sidebarOpen = !sidebarOpen"
79
+ class="w-10 h-10 flex items-center justify-center rounded-full hover:bg-white/10 transition-colors mr-4">
80
+ <span class="material-icons-outlined text-white dark:text-md-on-surface-dark">menu</span>
81
+ </button>
29
82
 
30
- <!-- Header -->
31
- <header class="bg-white border-b border-gray-200 shadow-sm">
32
- <div class="max-w-screen-2xl mx-auto px-4 sm:px-6 lg:px-8 h-14 flex items-center justify-between">
83
+ <!-- Title -->
33
84
  <div class="flex items-center gap-3">
34
- <h1 class="text-lg font-bold text-gray-900 tracking-tight">NMT Dashboard</h1>
35
- <span class="text-xs font-medium text-indigo-600 bg-indigo-50 px-2 py-0.5 rounded-full">Lite</span>
85
+ <span class="material-icons-outlined text-white dark:text-md-primary-light">hub</span>
86
+ <h1 class="text-xl font-medium text-white dark:text-md-on-surface-dark tracking-wide">NMT Dashboard</h1>
87
+ <span class="text-xs font-medium bg-white/20 dark:bg-md-primary/30 text-white dark:text-md-primary-light px-2 py-0.5 rounded-full">v1.0.3</span>
36
88
  </div>
37
- <div class="flex items-center gap-3">
38
- <span x-show="connected" x-cloak class="flex items-center gap-1.5 text-xs font-medium text-emerald-700 bg-emerald-50 border border-emerald-200 px-2.5 py-1 rounded-full">
39
- <span class="w-1.5 h-1.5 bg-emerald-500 rounded-full animate-pulse"></span>
40
- Connected
41
- </span>
42
- <span x-show="!connected" class="flex items-center gap-1.5 text-xs font-medium text-red-700 bg-red-50 border border-red-200 px-2.5 py-1 rounded-full">
43
- <span class="w-1.5 h-1.5 bg-red-500 rounded-full"></span>
44
- Offline
45
- </span>
89
+
90
+ <!-- Search Bar -->
91
+ <div class="flex-1 max-w-xl mx-8 hidden md:block">
92
+ <div class="relative">
93
+ <span class="material-icons-outlined absolute left-3 top-1/2 -translate-y-1/2 text-white/70 dark:text-gray-400 text-xl">search</span>
94
+ <input type="text"
95
+ x-model="globalSearch"
96
+ @keydown.enter="doGlobalSearch()"
97
+ placeholder="Search neurons, content..."
98
+ class="w-full bg-white/10 dark:bg-md-surface-variant-dark border-0 rounded-full pl-10 pr-4 py-2.5 text-sm text-white dark:text-md-on-surface-dark placeholder-white/60 dark:placeholder-gray-500 focus:bg-white/20 dark:focus:bg-md-surface-variant-dark focus:outline-none focus:ring-2 focus:ring-white/30 dark:focus:ring-md-primary transition-all">
99
+ </div>
46
100
  </div>
47
- </div>
48
- </header>
49
101
 
50
- <!-- Tab Navigation -->
51
- <nav class="bg-white border-b border-gray-200">
52
- <div class="max-w-screen-2xl mx-auto px-4 sm:px-6 lg:px-8">
53
- <div class="flex gap-0 -mb-px">
54
- <template x-for="tab in tabs" :key="tab.id">
55
- <button
56
- @click="switchTab(tab.id)"
57
- :class="activeTab === tab.id
58
- ? 'border-indigo-600 text-indigo-600 font-semibold'
59
- : 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 font-medium'"
60
- class="px-4 py-3 text-sm border-b-2 transition-colors whitespace-nowrap"
61
- x-text="tab.label"
62
- ></button>
63
- </template>
102
+ <!-- Right Actions -->
103
+ <div class="flex items-center gap-2 ml-auto">
104
+ <!-- Connection Status -->
105
+ <div class="flex items-center gap-2 px-3 py-1.5 rounded-full"
106
+ :class="connected ? 'bg-md-success/20 dark:bg-md-success/30' : 'bg-md-error/20 dark:bg-md-error/30'">
107
+ <span class="w-2 h-2 rounded-full" :class="connected ? 'bg-md-success animate-pulse' : 'bg-md-error'"></span>
108
+ <span class="text-xs font-medium" :class="connected ? 'text-white dark:text-green-400' : 'text-white dark:text-red-400'"
109
+ x-text="connected ? 'Connected' : 'Offline'"></span>
110
+ </div>
111
+
112
+ <!-- Dark Mode Toggle -->
113
+ <button @click="toggleDarkMode()"
114
+ class="w-10 h-10 flex items-center justify-center rounded-full hover:bg-white/10 dark:hover:bg-white/5 transition-colors">
115
+ <span x-show="!darkMode" class="material-icons-outlined text-white">dark_mode</span>
116
+ <span x-show="darkMode" x-cloak class="material-icons-outlined text-md-on-surface-dark">light_mode</span>
117
+ </button>
118
+
119
+ <!-- Refresh -->
120
+ <button @click="refreshAll()"
121
+ class="w-10 h-10 flex items-center justify-center rounded-full hover:bg-white/10 dark:hover:bg-white/5 transition-colors">
122
+ <span class="material-icons-outlined text-white dark:text-md-on-surface-dark" :class="{ 'animate-spin': refreshing }">refresh</span>
123
+ </button>
64
124
  </div>
65
125
  </div>
66
- </nav>
67
-
68
- <!-- Main Content Area -->
69
- <main class="max-w-screen-2xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
70
-
71
- <!-- ============================================================ -->
72
- <!-- TAB 1: OVERVIEW -->
73
- <!-- ============================================================ -->
74
- <section x-show="activeTab === 'overview'" x-cloak>
75
- <div class="flex items-center justify-between mb-5">
76
- <h2 class="text-base font-semibold text-gray-900">System Overview</h2>
77
- <span class="text-xs text-gray-400" x-text="lastRefresh ? 'Updated ' + lastRefresh : ''"></span>
78
- </div>
126
+ </header>
79
127
 
80
- <!-- Stat Cards -->
81
- <div class="grid grid-cols-2 lg:grid-cols-3 gap-4 mb-6">
82
- <!-- Neurons -->
83
- <div class="bg-gray-50 border border-gray-200 rounded-lg p-5">
84
- <p class="text-2xl font-bold text-gray-900" x-text="formatNumber(stats.neurons ?? '--')"></p>
85
- <p class="text-xs font-medium text-gray-500 mt-1 uppercase tracking-wide">Neurons</p>
86
- </div>
87
- <!-- Synapses -->
88
- <div class="bg-gray-50 border border-gray-200 rounded-lg p-5">
89
- <p class="text-2xl font-bold text-gray-900" x-text="formatNumber(stats.synapses ?? '--')"></p>
90
- <p class="text-xs font-medium text-gray-500 mt-1 uppercase tracking-wide">Synapses</p>
91
- </div>
92
- <!-- Chunks -->
93
- <div class="bg-gray-50 border border-gray-200 rounded-lg p-5">
94
- <p class="text-2xl font-bold text-gray-900" x-text="formatNumber(stats.chunks?.total ?? '--')"></p>
95
- <p class="text-xs font-medium text-gray-500 mt-1 uppercase tracking-wide">Chunks</p>
96
- </div>
97
- <!-- Total Size -->
98
- <div class="bg-gray-50 border border-gray-200 rounded-lg p-5">
99
- <p class="text-2xl font-bold text-gray-900" x-text="formatBytes(stats.chunks?.totalSize)"></p>
100
- <p class="text-xs font-medium text-gray-500 mt-1 uppercase tracking-wide">Total Size</p>
128
+ <!-- Side Navigation -->
129
+ <aside :class="sidebarOpen ? 'translate-x-0' : '-translate-x-full lg:translate-x-0 lg:w-20'"
130
+ class="fixed left-0 top-16 bottom-0 z-40 w-64 bg-md-surface dark:bg-md-surface-dark shadow-md-2 transition-all duration-300 overflow-hidden">
131
+ <nav class="py-4 h-full overflow-y-auto">
132
+ <template x-for="item in navItems" :key="item.id">
133
+ <button @click="switchTab(item.id); if(window.innerWidth < 1024) sidebarOpen = false"
134
+ :class="{ 'active': activeTab === item.id }"
135
+ class="nav-item w-full flex items-center gap-4 px-6 py-3 text-md-on-surface dark:text-md-on-surface-dark">
136
+ <span class="material-icons-outlined" :class="activeTab === item.id ? 'text-md-primary dark:text-md-primary-light' : ''" x-text="item.icon"></span>
137
+ <span x-show="sidebarOpen" class="text-sm font-medium" x-text="item.label"></span>
138
+ </button>
139
+ </template>
140
+
141
+ </nav>
142
+ </aside>
143
+
144
+ <!-- Main Content -->
145
+ <main :class="sidebarOpen ? 'lg:ml-64' : 'lg:ml-20'"
146
+ class="pt-16 min-h-screen transition-all duration-300">
147
+ <div class="p-6">
148
+
149
+ <!-- OVERVIEW TAB -->
150
+ <section x-show="activeTab === 'overview'" x-cloak>
151
+ <!-- Page Header -->
152
+ <div class="flex items-center justify-between mb-6">
153
+ <div>
154
+ <h2 class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark">System Overview</h2>
155
+ <p class="text-sm text-gray-500 dark:text-gray-400 mt-1" x-text="lastRefresh ? 'Last updated: ' + lastRefresh : 'Loading...'"></p>
156
+ </div>
101
157
  </div>
102
- <!-- HNSW Vectors -->
103
- <div class="bg-gray-50 border border-gray-200 rounded-lg p-5">
104
- <p class="text-2xl font-bold text-gray-900" x-text="formatNumber(stats.hnsw?.totalNodes ?? '--')"></p>
105
- <p class="text-xs font-medium text-gray-500 mt-1 uppercase tracking-wide">HNSW Vectors</p>
158
+
159
+ <!-- Stats Cards Grid -->
160
+ <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
161
+ <!-- Neurons Card -->
162
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-5 shadow-md-1">
163
+ <div class="flex items-center justify-between mb-3">
164
+ <span class="material-icons-outlined text-md-primary text-3xl">psychology</span>
165
+ <span class="text-xs font-medium text-md-success bg-md-success/10 px-2 py-1 rounded-full">Active</span>
166
+ </div>
167
+ <p class="text-3xl font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="formatNumber(stats.neurons ?? 0)"></p>
168
+ <p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Total Neurons</p>
169
+ </div>
170
+
171
+ <!-- Synapses Card -->
172
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-5 shadow-md-1">
173
+ <div class="flex items-center justify-between mb-3">
174
+ <span class="material-icons-outlined text-md-secondary text-3xl">share</span>
175
+ </div>
176
+ <p class="text-3xl font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="formatNumber(stats.synapses ?? 0)"></p>
177
+ <p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Connections</p>
178
+ </div>
179
+
180
+ <!-- Chunks Card -->
181
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-5 shadow-md-1">
182
+ <div class="flex items-center justify-between mb-3">
183
+ <span class="material-icons-outlined text-amber-600 text-3xl">inventory_2</span>
184
+ </div>
185
+ <p class="text-3xl font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="formatNumber(stats.chunks?.total ?? 0)"></p>
186
+ <p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Data Chunks</p>
187
+ </div>
188
+
189
+ <!-- Storage Card -->
190
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-5 shadow-md-1">
191
+ <div class="flex items-center justify-between mb-3">
192
+ <span class="material-icons-outlined text-teal-600 text-3xl">storage</span>
193
+ </div>
194
+ <p class="text-3xl font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="formatBytes(stats.chunks?.totalSize)"></p>
195
+ <p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Total Storage</p>
196
+ </div>
106
197
  </div>
107
- <!-- HNSW Layers -->
108
- <div class="bg-gray-50 border border-gray-200 rounded-lg p-5">
109
- <p class="text-2xl font-bold text-gray-900" x-text="stats.hnsw?.maxLayer ?? '--'"></p>
110
- <p class="text-xs font-medium text-gray-500 mt-1 uppercase tracking-wide">HNSW Max Layer</p>
198
+
199
+ <!-- Second Row Cards -->
200
+ <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
201
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-5 shadow-md-1">
202
+ <div class="flex items-center gap-3 mb-3">
203
+ <span class="material-icons-outlined text-indigo-500">scatter_plot</span>
204
+ <span class="text-sm font-medium text-gray-500 dark:text-gray-400">HNSW Vectors</span>
205
+ </div>
206
+ <p class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="formatNumber(stats.hnsw?.totalNodes ?? 0)"></p>
207
+ </div>
208
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-5 shadow-md-1">
209
+ <div class="flex items-center gap-3 mb-3">
210
+ <span class="material-icons-outlined text-pink-500">layers</span>
211
+ <span class="text-sm font-medium text-gray-500 dark:text-gray-400">HNSW Layers</span>
212
+ </div>
213
+ <p class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="stats.hnsw?.maxLayer ?? 0"></p>
214
+ </div>
215
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-5 shadow-md-1">
216
+ <div class="flex items-center gap-3 mb-3">
217
+ <span class="material-icons-outlined text-cyan-500">dns</span>
218
+ <span class="text-sm font-medium text-gray-500 dark:text-gray-400">Storage Backend</span>
219
+ </div>
220
+ <p class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="stats.storage?.backend ?? 'LevelDB'"></p>
221
+ </div>
222
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-5 shadow-md-1">
223
+ <div class="flex items-center gap-3 mb-3">
224
+ <span class="material-icons-outlined text-orange-500">data_array</span>
225
+ <span class="text-sm font-medium text-gray-500 dark:text-gray-400">Avg Chunk Size</span>
226
+ </div>
227
+ <p class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="formatBytes(stats.chunks?.avgSize)"></p>
228
+ </div>
111
229
  </div>
112
- </div>
113
230
 
114
- <!-- Storage Info -->
115
- <div class="bg-white border border-gray-200 rounded-lg p-5">
116
- <h3 class="text-sm font-semibold text-gray-700 mb-3 uppercase tracking-wide">Storage</h3>
117
- <div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
118
- <div>
119
- <span class="text-xs text-gray-500">Backend</span>
120
- <p class="text-sm font-medium text-gray-900 font-mono" x-text="stats.storage?.backend ?? '--'"></p>
231
+ <!-- Recent Activity Table -->
232
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 overflow-hidden">
233
+ <div class="px-6 py-4 border-b border-md-outline dark:border-md-outline-dark">
234
+ <h3 class="text-lg font-medium text-md-on-surface dark:text-md-on-surface-dark flex items-center gap-2">
235
+ <span class="material-icons-outlined text-md-primary">history</span>
236
+ Recent Neurons
237
+ </h3>
121
238
  </div>
122
- <div>
123
- <span class="text-xs text-gray-500">Data Directory</span>
124
- <p class="text-sm font-medium text-gray-900 font-mono break-all" x-text="stats.storage?.dataDir ?? '--'"></p>
239
+ <div class="overflow-x-auto">
240
+ <table class="w-full">
241
+ <thead>
242
+ <tr class="bg-md-surface-variant dark:bg-md-surface-dark border-b border-md-outline dark:border-md-outline-dark">
243
+ <th class="text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider px-6 py-3">ID</th>
244
+ <th class="text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider px-6 py-3">Type</th>
245
+ <th class="text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider px-6 py-3">Tags</th>
246
+ <th class="text-right text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider px-6 py-3">Chunks</th>
247
+ </tr>
248
+ </thead>
249
+ <tbody class="divide-y divide-md-outline dark:divide-md-outline-dark">
250
+ <template x-for="neuron in recentNeurons.slice(0, 5)" :key="neuron.id">
251
+ <tr class="hover:bg-md-surface-variant dark:hover:bg-md-surface-dark transition-colors">
252
+ <td class="px-6 py-4">
253
+ <span class="font-mono text-sm text-md-primary dark:text-md-primary-light" x-text="neuron.id?.substring(0, 12) + '...'"></span>
254
+ </td>
255
+ <td class="px-6 py-4">
256
+ <span class="text-sm text-md-on-surface dark:text-md-on-surface-dark" x-text="neuron.sourceType || 'Unknown'"></span>
257
+ </td>
258
+ <td class="px-6 py-4">
259
+ <div class="flex flex-wrap gap-1">
260
+ <template x-for="tag in (neuron.tags || []).slice(0, 3)" :key="tag">
261
+ <span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-md-primary/10 text-md-primary dark:bg-md-primary/20 dark:text-md-primary-light" x-text="tag"></span>
262
+ </template>
263
+ </div>
264
+ </td>
265
+ <td class="px-6 py-4 text-right">
266
+ <span class="text-sm font-mono text-md-on-surface dark:text-md-on-surface-dark" x-text="neuron.chunks ?? 0"></span>
267
+ </td>
268
+ </tr>
269
+ </template>
270
+ <tr x-show="recentNeurons.length === 0">
271
+ <td colspan="4" class="px-6 py-8 text-center text-gray-500 dark:text-gray-400">
272
+ <span class="material-icons-outlined text-4xl mb-2 block">inbox</span>
273
+ No neurons yet. Start by ingesting some content.
274
+ </td>
275
+ </tr>
276
+ </tbody>
277
+ </table>
125
278
  </div>
279
+ </div>
280
+ </section>
281
+
282
+ <!-- NEURONS TAB -->
283
+ <section x-show="activeTab === 'neurons'" x-cloak>
284
+ <div class="flex items-center justify-between mb-6">
126
285
  <div>
127
- <span class="text-xs text-gray-500">Average Chunk Size</span>
128
- <p class="text-sm font-medium text-gray-900 font-mono" x-text="formatBytes(stats.chunks?.avgSize)"></p>
286
+ <h2 class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark">Neurons</h2>
287
+ <p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Total: <span x-text="neuronTotal"></span> neurons</p>
129
288
  </div>
130
- </div>
131
- </div>
132
- </section>
133
-
134
- <!-- ============================================================ -->
135
- <!-- TAB 2: NEURONS -->
136
- <!-- ============================================================ -->
137
- <section x-show="activeTab === 'neurons'" x-cloak>
138
- <div class="flex items-center justify-between mb-4">
139
- <h2 class="text-base font-semibold text-gray-900">
140
- Neurons
141
- <span class="text-sm font-normal text-gray-500 ml-1" x-show="neuronTotal > 0" x-text="'(' + neuronTotal + ' total)'"></span>
142
- </h2>
143
- <div class="flex items-center gap-2">
144
- <button @click="loadNeurons()" class="text-xs text-indigo-600 hover:text-indigo-800 font-medium px-2 py-1 rounded hover:bg-indigo-50 transition-colors">
289
+ <button @click="loadNeurons()"
290
+ class="flex items-center gap-2 px-4 py-2 bg-md-primary text-white rounded-full text-sm font-medium hover:bg-md-primary-dark shadow-md-1 transition-all">
291
+ <span class="material-icons-outlined text-xl">refresh</span>
145
292
  Refresh
146
293
  </button>
147
294
  </div>
148
- </div>
149
295
 
150
- <div class="flex gap-4">
151
- <!-- Neurons Table -->
152
- <div class="flex-1 min-w-0">
153
- <!-- Empty State -->
154
- <div x-show="!neuronsLoading && neurons.length === 0" class="bg-white border border-gray-200 rounded-lg p-12 text-center">
155
- <p class="text-sm text-gray-500">No neurons found</p>
156
- </div>
157
-
158
- <!-- Loading -->
159
- <div x-show="neuronsLoading" class="bg-white border border-gray-200 rounded-lg p-12 text-center">
160
- <div class="inline-block w-5 h-5 border-2 border-indigo-200 border-t-indigo-600 rounded-full animate-spin"></div>
161
- <p class="text-sm text-gray-500 mt-2">Loading neurons...</p>
162
- </div>
163
-
164
- <!-- Table -->
165
- <div x-show="!neuronsLoading && neurons.length > 0" class="bg-white border border-gray-200 rounded-lg overflow-hidden">
166
- <div class="overflow-x-auto">
167
- <table class="w-full text-sm">
168
- <thead>
169
- <tr class="border-b border-gray-200 bg-gray-50">
170
- <th class="text-left text-xs font-semibold text-gray-600 uppercase tracking-wide px-4 py-2.5">ID</th>
171
- <th class="text-left text-xs font-semibold text-gray-600 uppercase tracking-wide px-4 py-2.5">Type</th>
172
- <th class="text-left text-xs font-semibold text-gray-600 uppercase tracking-wide px-4 py-2.5">Tags</th>
173
- <th class="text-right text-xs font-semibold text-gray-600 uppercase tracking-wide px-4 py-2.5">Chunks</th>
174
- <th class="text-left text-xs font-semibold text-gray-600 uppercase tracking-wide px-4 py-2.5">Created</th>
175
- </tr>
176
- </thead>
177
- <tbody>
178
- <template x-for="neuron in neurons" :key="neuron.id">
179
- <tr
180
- @click="selectNeuron(neuron)"
181
- :class="selectedNeuron?.id === neuron.id ? 'bg-indigo-50' : 'hover:bg-gray-50'"
182
- class="border-b border-gray-100 cursor-pointer transition-colors"
183
- >
184
- <td class="px-4 py-2.5 font-mono text-xs text-indigo-700" x-text="neuron.id.substring(0, 8) + '...'"></td>
185
- <td class="px-4 py-2.5 text-gray-700" x-text="neuron.sourceType || '--'"></td>
186
- <td class="px-4 py-2.5">
187
- <div class="flex flex-wrap gap-1">
188
- <template x-for="tag in (neuron.tags || [])" :key="tag">
189
- <span class="inline-block bg-indigo-50 text-indigo-700 text-xs font-medium px-1.5 py-0.5 rounded" x-text="tag"></span>
190
- </template>
191
- <span x-show="!neuron.tags || neuron.tags.length === 0" class="text-xs text-gray-400">--</span>
192
- </div>
193
- </td>
194
- <td class="px-4 py-2.5 text-right text-gray-700 font-mono text-xs" x-text="neuron.chunks ?? '--'"></td>
195
- <td class="px-4 py-2.5 text-gray-500 text-xs whitespace-nowrap" x-text="formatDate(neuron.createdAt)"></td>
296
+ <div class="flex gap-6">
297
+ <!-- Neurons List -->
298
+ <div class="flex-1">
299
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 overflow-hidden">
300
+ <div x-show="neuronsLoading" class="p-12 text-center">
301
+ <div class="inline-block w-8 h-8 border-4 border-md-primary/20 border-t-md-primary rounded-full animate-spin"></div>
302
+ <p class="mt-4 text-gray-500 dark:text-gray-400">Loading neurons...</p>
303
+ </div>
304
+ <div x-show="!neuronsLoading">
305
+ <table class="w-full">
306
+ <thead>
307
+ <tr class="bg-md-surface-variant dark:bg-md-surface-dark border-b border-md-outline dark:border-md-outline-dark">
308
+ <th class="text-left text-xs font-medium text-gray-500 uppercase tracking-wider px-6 py-3">ID</th>
309
+ <th class="text-left text-xs font-medium text-gray-500 uppercase tracking-wider px-6 py-3">Type</th>
310
+ <th class="text-left text-xs font-medium text-gray-500 uppercase tracking-wider px-6 py-3">Tags</th>
311
+ <th class="text-right text-xs font-medium text-gray-500 uppercase tracking-wider px-6 py-3">Chunks</th>
196
312
  </tr>
197
- </template>
198
- </tbody>
199
- </table>
200
- </div>
201
-
202
- <!-- Pagination -->
203
- <div class="flex items-center justify-between px-4 py-3 border-t border-gray-200 bg-gray-50">
204
- <span class="text-xs text-gray-500" x-text="paginationLabel()"></span>
205
- <div class="flex items-center gap-2">
206
- <button
207
- @click="prevPage()"
208
- :disabled="neuronPage === 0"
209
- :class="neuronPage === 0 ? 'opacity-40 cursor-not-allowed' : 'hover:bg-gray-200'"
210
- class="px-3 py-1.5 text-xs font-medium text-gray-700 bg-white border border-gray-300 rounded transition-colors"
211
- >
212
- Prev
213
- </button>
214
- <button
215
- @click="nextPage()"
216
- :disabled="(neuronPage + 1) * neuronLimit >= neuronTotal"
217
- :class="(neuronPage + 1) * neuronLimit >= neuronTotal ? 'opacity-40 cursor-not-allowed' : 'hover:bg-gray-200'"
218
- class="px-3 py-1.5 text-xs font-medium text-gray-700 bg-white border border-gray-300 rounded transition-colors"
219
- >
220
- Next
221
- </button>
313
+ </thead>
314
+ <tbody class="divide-y divide-md-outline dark:divide-md-outline-dark">
315
+ <template x-for="neuron in neurons" :key="neuron.id">
316
+ <tr @click="selectNeuron(neuron)"
317
+ :class="selectedNeuron?.id === neuron.id ? 'bg-md-primary/5 dark:bg-md-primary/10' : 'hover:bg-md-surface-variant dark:hover:bg-md-surface-dark'"
318
+ class="cursor-pointer transition-colors">
319
+ <td class="px-6 py-4 font-mono text-sm text-md-primary dark:text-md-primary-light" x-text="neuron.id?.substring(0, 12) + '...'"></td>
320
+ <td class="px-6 py-4 text-sm text-md-on-surface dark:text-md-on-surface-dark" x-text="neuron.sourceType || '--'"></td>
321
+ <td class="px-6 py-4">
322
+ <div class="flex flex-wrap gap-1">
323
+ <template x-for="tag in (neuron.tags || []).slice(0, 3)" :key="tag">
324
+ <span class="px-2 py-0.5 text-xs rounded-full bg-md-primary/10 text-md-primary dark:bg-md-primary/20 dark:text-md-primary-light" x-text="tag"></span>
325
+ </template>
326
+ </div>
327
+ </td>
328
+ <td class="px-6 py-4 text-right font-mono text-sm text-md-on-surface dark:text-md-on-surface-dark" x-text="neuron.chunks ?? '--'"></td>
329
+ </tr>
330
+ </template>
331
+ </tbody>
332
+ </table>
333
+ <!-- Pagination -->
334
+ <div class="flex items-center justify-between px-6 py-4 bg-md-surface-variant dark:bg-md-surface-dark border-t border-md-outline dark:border-md-outline-dark">
335
+ <span class="text-sm text-gray-500 dark:text-gray-400" x-text="paginationLabel()"></span>
336
+ <div class="flex gap-2">
337
+ <button @click="prevPage()" :disabled="neuronPage === 0"
338
+ class="px-4 py-2 text-sm font-medium rounded-full border border-md-outline dark:border-md-outline-dark disabled:opacity-40 hover:bg-md-surface-variant dark:hover:bg-md-surface transition-colors">
339
+ Previous
340
+ </button>
341
+ <button @click="nextPage()" :disabled="(neuronPage + 1) * neuronLimit >= neuronTotal"
342
+ class="px-4 py-2 text-sm font-medium rounded-full border border-md-outline dark:border-md-outline-dark disabled:opacity-40 hover:bg-md-surface-variant dark:hover:bg-md-surface transition-colors">
343
+ Next
344
+ </button>
345
+ </div>
346
+ </div>
222
347
  </div>
223
348
  </div>
224
349
  </div>
225
- </div>
226
350
 
227
- <!-- Detail Panel -->
228
- <div x-show="selectedNeuron" x-cloak x-transition class="w-96 flex-shrink-0">
229
- <div class="bg-white border border-gray-200 rounded-lg overflow-hidden sticky top-4">
230
- <div class="flex items-center justify-between px-4 py-3 border-b border-gray-200 bg-gray-50">
231
- <h3 class="text-sm font-semibold text-gray-700">Neuron Detail</h3>
232
- <button @click="selectedNeuron = null; selectedContent = ''" class="text-gray-400 hover:text-gray-600 text-lg leading-none">&times;</button>
233
- </div>
234
- <div class="p-4 space-y-3 max-h-[calc(100vh-16rem)] overflow-y-auto">
235
- <!-- ID -->
236
- <div>
237
- <label class="text-xs text-gray-500 block">ID</label>
238
- <p class="text-xs font-mono text-gray-900 break-all select-all" x-text="selectedNeuron?.id"></p>
239
- </div>
240
- <!-- Merkle Root -->
241
- <div>
242
- <label class="text-xs text-gray-500 block">Merkle Root</label>
243
- <p class="text-xs font-mono text-gray-900 break-all select-all" x-text="selectedNeuron?.merkleRoot || '--'"></p>
244
- </div>
245
- <!-- Source Type -->
246
- <div>
247
- <label class="text-xs text-gray-500 block">Source Type</label>
248
- <p class="text-sm text-gray-900" x-text="selectedNeuron?.sourceType || '--'"></p>
249
- </div>
250
- <!-- Tags -->
251
- <div>
252
- <label class="text-xs text-gray-500 block mb-1">Tags</label>
253
- <div class="flex flex-wrap gap-1">
254
- <template x-for="tag in (selectedNeuron?.tags || [])" :key="tag">
255
- <span class="inline-block bg-indigo-50 text-indigo-700 text-xs font-medium px-1.5 py-0.5 rounded" x-text="tag"></span>
256
- </template>
257
- <span x-show="!selectedNeuron?.tags || selectedNeuron?.tags.length === 0" class="text-xs text-gray-400">None</span>
258
- </div>
351
+ <!-- Detail Panel -->
352
+ <div x-show="selectedNeuron" x-cloak class="w-96 flex-shrink-0">
353
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-2 sticky top-24 overflow-hidden">
354
+ <div class="flex items-center justify-between px-6 py-4 bg-md-primary dark:bg-md-primary-dark">
355
+ <h3 class="text-lg font-medium text-white flex items-center gap-2">
356
+ <span class="material-icons-outlined">info</span>
357
+ Details
358
+ </h3>
359
+ <button @click="selectedNeuron = null" class="w-8 h-8 flex items-center justify-center rounded-full hover:bg-white/10">
360
+ <span class="material-icons-outlined text-white">close</span>
361
+ </button>
259
362
  </div>
260
- <!-- Metadata Row -->
261
- <div class="grid grid-cols-2 gap-3">
363
+ <div class="p-6 space-y-4 max-h-[calc(100vh-200px)] overflow-y-auto">
262
364
  <div>
263
- <label class="text-xs text-gray-500 block">Chunks</label>
264
- <p class="text-sm font-mono text-gray-900" x-text="selectedNeuron?.chunkHashes?.length ?? selectedNeuron?.chunks ?? '--'"></p>
365
+ <label class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Neuron ID</label>
366
+ <p class="font-mono text-sm text-md-on-surface dark:text-md-on-surface-dark mt-1 break-all" x-text="selectedNeuron?.id"></p>
265
367
  </div>
266
368
  <div>
267
- <label class="text-xs text-gray-500 block">Access Count</label>
268
- <p class="text-sm font-mono text-gray-900" x-text="selectedNeuron?.accessCount ?? '--'"></p>
369
+ <label class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Merkle Root</label>
370
+ <p class="font-mono text-sm text-md-on-surface dark:text-md-on-surface-dark mt-1 break-all" x-text="selectedNeuron?.merkleRoot || '--'"></p>
269
371
  </div>
270
- </div>
271
- <!-- Dates -->
272
- <div class="grid grid-cols-2 gap-3">
273
372
  <div>
274
- <label class="text-xs text-gray-500 block">Created</label>
275
- <p class="text-xs text-gray-900" x-text="formatDate(selectedNeuron?.createdAt)"></p>
276
- </div>
277
- <div>
278
- <label class="text-xs text-gray-500 block">Updated</label>
279
- <p class="text-xs text-gray-900" x-text="formatDate(selectedNeuron?.updatedAt)"></p>
280
- </div>
281
- </div>
282
- <div>
283
- <label class="text-xs text-gray-500 block">Last Accessed</label>
284
- <p class="text-xs text-gray-900" x-text="formatDate(selectedNeuron?.lastAccessed)"></p>
285
- </div>
286
- <!-- Synapses -->
287
- <div x-show="selectedNeuron?.synapses">
288
- <label class="text-xs text-gray-500 block mb-1">Synapses</label>
289
- <div class="flex gap-4">
290
- <span class="text-xs text-gray-700">
291
- Outgoing: <span class="font-semibold font-mono" x-text="selectedNeuron?.synapses?.outgoing?.length ?? selectedNeuron?.synapses?.outgoing ?? 0"></span>
292
- </span>
293
- <span class="text-xs text-gray-700">
294
- Incoming: <span class="font-semibold font-mono" x-text="selectedNeuron?.synapses?.incoming?.length ?? selectedNeuron?.synapses?.incoming ?? 0"></span>
295
- </span>
296
- </div>
297
- </div>
298
- <!-- Content -->
299
- <div>
300
- <label class="text-xs text-gray-500 block mb-1">Content</label>
301
- <div x-show="contentLoading" class="text-xs text-gray-400">Loading content...</div>
302
- <pre x-show="selectedContent && !contentLoading" class="bg-gray-50 border border-gray-200 rounded p-3 text-xs text-gray-800 font-mono whitespace-pre-wrap break-words max-h-64 overflow-y-auto" x-text="selectedContent"></pre>
303
- <p x-show="!selectedContent && !contentLoading" class="text-xs text-gray-400">No content available</p>
304
- </div>
305
- <!-- Delete -->
306
- <div class="pt-2 border-t border-gray-200">
307
- <button
308
- x-show="!confirmDelete"
309
- @click="confirmDelete = true"
310
- class="w-full px-3 py-2 text-xs font-medium text-red-700 bg-red-50 border border-red-200 rounded hover:bg-red-100 transition-colors"
311
- >
312
- Delete Neuron
313
- </button>
314
- <div x-show="confirmDelete" class="space-y-2">
315
- <p class="text-xs text-red-600 font-medium">Are you sure? This cannot be undone.</p>
316
- <div class="flex gap-2">
317
- <button
318
- @click="deleteNeuron(selectedNeuron.id)"
319
- :disabled="deleting"
320
- class="flex-1 px-3 py-2 text-xs font-medium text-white bg-red-600 rounded hover:bg-red-700 transition-colors disabled:opacity-50"
321
- >
322
- <span x-show="!deleting">Confirm Delete</span>
323
- <span x-show="deleting">Deleting...</span>
324
- </button>
325
- <button
326
- @click="confirmDelete = false"
327
- class="flex-1 px-3 py-2 text-xs font-medium text-gray-700 bg-white border border-gray-300 rounded hover:bg-gray-50 transition-colors"
328
- >
329
- Cancel
330
- </button>
331
- </div>
373
+ <label class="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Content</label>
374
+ <pre class="mt-2 bg-md-surface-variant dark:bg-md-surface-dark rounded-lg p-4 text-sm text-md-on-surface dark:text-md-on-surface-dark max-h-60 overflow-y-auto whitespace-pre-wrap" x-text="selectedContent || 'Loading...'"></pre>
332
375
  </div>
333
376
  </div>
334
377
  </div>
335
378
  </div>
336
379
  </div>
337
- </div>
338
- </section>
339
-
340
- <!-- ============================================================ -->
341
- <!-- TAB 3: SEARCH -->
342
- <!-- ============================================================ -->
343
- <section x-show="activeTab === 'search'" x-cloak>
344
- <h2 class="text-base font-semibold text-gray-900 mb-4">Semantic Search</h2>
380
+ </section>
345
381
 
346
- <!-- Search Form -->
347
- <div class="bg-white border border-gray-200 rounded-lg p-5 mb-5">
348
- <div class="flex flex-col sm:flex-row gap-3">
349
- <div class="flex-1">
350
- <label class="text-xs font-medium text-gray-600 block mb-1">Query</label>
351
- <input
352
- type="text"
353
- x-model="searchQuery"
354
- @keydown.enter="doSearch()"
355
- placeholder="Enter search query..."
356
- class="w-full px-3 py-2 text-sm border border-gray-300 rounded-md focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none transition"
357
- >
358
- </div>
359
- <div class="w-24">
360
- <label class="text-xs font-medium text-gray-600 block mb-1">Top-K</label>
361
- <input
362
- type="number"
363
- x-model.number="searchK"
364
- min="1"
365
- max="100"
366
- class="w-full px-3 py-2 text-sm border border-gray-300 rounded-md focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none transition"
367
- >
368
- </div>
369
- <div class="flex items-end gap-3">
370
- <label class="flex items-center gap-2 pb-2 cursor-pointer select-none">
371
- <input type="checkbox" x-model="searchIncludeContent" class="w-4 h-4 text-indigo-600 border-gray-300 rounded focus:ring-indigo-500">
372
- <span class="text-xs font-medium text-gray-600 whitespace-nowrap">Include Content</span>
373
- </label>
374
- <button
375
- @click="doSearch()"
376
- :disabled="searching || !searchQuery.trim()"
377
- class="px-5 py-2 text-sm font-medium text-white bg-indigo-600 rounded-md hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center gap-2"
378
- >
379
- <span x-show="searching" class="w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin"></span>
380
- Search
382
+ <!-- GRAPH TAB -->
383
+ <section x-show="activeTab === 'graph'" x-cloak x-init="$watch('activeTab', val => { if(val === 'graph') setTimeout(() => renderGraph(), 100) })">
384
+ <div class="flex items-center justify-between mb-6">
385
+ <h2 class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark">Knowledge Graph</h2>
386
+ <div class="flex items-center gap-3">
387
+ <button @click="graphViewMode = graphViewMode === 'graph' ? 'table' : 'graph'"
388
+ class="flex items-center gap-2 px-4 py-2 bg-md-surface dark:bg-md-surface-variant-dark border border-md-outline dark:border-md-outline-dark rounded-full text-sm font-medium hover:bg-md-surface-variant transition-colors">
389
+ <span class="material-icons-outlined text-xl" x-text="graphViewMode === 'graph' ? 'table_rows' : 'hub'"></span>
390
+ <span x-text="graphViewMode === 'graph' ? 'Table' : 'Graph'"></span>
391
+ </button>
392
+ <button @click="loadGraph(); setTimeout(() => renderGraph(), 200)" class="flex items-center gap-2 px-4 py-2 bg-md-primary text-white rounded-full text-sm font-medium hover:bg-md-primary-dark shadow-md-1">
393
+ <span class="material-icons-outlined text-xl">refresh</span>
394
+ Refresh
381
395
  </button>
382
396
  </div>
383
397
  </div>
384
- </div>
385
398
 
386
- <!-- Search Results -->
387
- <div x-show="searchResults.length > 0" class="space-y-3">
388
- <p class="text-xs text-gray-500 font-medium" x-text="searchResults.length + ' result(s) found'"></p>
389
- <template x-for="(result, idx) in searchResults" :key="idx">
390
- <div class="bg-white border border-gray-200 rounded-lg p-4">
391
- <div class="flex items-start justify-between mb-2">
392
- <div class="flex items-center gap-3">
393
- <span class="font-mono text-xs text-indigo-700 bg-indigo-50 px-2 py-0.5 rounded" x-text="result.neuronId?.substring(0, 12) + '...'"></span>
394
- <span
395
- :class="result.score > 0.8 ? 'text-emerald-700 bg-emerald-50' : result.score > 0.5 ? 'text-amber-700 bg-amber-50' : 'text-gray-600 bg-gray-100'"
396
- class="text-xs font-semibold px-2 py-0.5 rounded"
397
- x-text="'Score: ' + (typeof result.score === 'number' ? result.score.toFixed(4) : result.score)"
398
- ></span>
399
- </div>
400
- <span class="text-xs text-gray-500" x-text="result.sourceType || ''"></span>
399
+ <!-- Graph Stats -->
400
+ <div class="grid grid-cols-1 sm:grid-cols-4 gap-4 mb-6">
401
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-5 shadow-md-1">
402
+ <div class="flex items-center gap-3 mb-2">
403
+ <span class="material-icons-outlined text-md-primary">hub</span>
404
+ <span class="text-sm text-gray-500 dark:text-gray-400">Nodes</span>
401
405
  </div>
402
- <div class="flex flex-wrap gap-1 mb-2" x-show="result.tags && result.tags.length > 0">
403
- <template x-for="tag in (result.tags || [])" :key="tag">
404
- <span class="inline-block bg-indigo-50 text-indigo-700 text-xs font-medium px-1.5 py-0.5 rounded" x-text="tag"></span>
405
- </template>
406
+ <p class="text-3xl font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="graphData.stats?.nodeCount ?? 0"></p>
407
+ </div>
408
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-5 shadow-md-1">
409
+ <div class="flex items-center gap-3 mb-2">
410
+ <span class="material-icons-outlined text-md-success">link</span>
411
+ <span class="text-sm text-gray-500 dark:text-gray-400">Edges</span>
406
412
  </div>
407
- <div x-show="result.content" class="mt-2">
408
- <pre class="bg-gray-50 border border-gray-200 rounded p-3 text-xs text-gray-800 font-mono whitespace-pre-wrap break-words max-h-48 overflow-y-auto" x-text="result.content"></pre>
413
+ <p class="text-3xl font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="graphData.stats?.edgeCount ?? 0"></p>
414
+ </div>
415
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-5 shadow-md-1">
416
+ <div class="flex items-center gap-3 mb-2">
417
+ <span class="material-icons-outlined text-amber-500">analytics</span>
418
+ <span class="text-sm text-gray-500 dark:text-gray-400">Avg Connections</span>
409
419
  </div>
420
+ <p class="text-3xl font-medium text-md-on-surface dark:text-md-on-surface-dark"
421
+ x-text="graphData.stats?.nodeCount > 0 ? (graphData.stats?.edgeCount / graphData.stats?.nodeCount).toFixed(2) : '0'"></p>
410
422
  </div>
411
- </template>
412
- </div>
423
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-5 shadow-md-1">
424
+ <div class="flex items-center gap-3 mb-2">
425
+ <span class="material-icons-outlined text-purple-500">category</span>
426
+ <span class="text-sm text-gray-500 dark:text-gray-400">Edge Types</span>
427
+ </div>
428
+ <p class="text-3xl font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="[...new Set((graphData.edges || []).map(e => e.type))].length"></p>
429
+ </div>
430
+ </div>
413
431
 
414
- <!-- No Results -->
415
- <div x-show="searchPerformed && searchResults.length === 0 && !searching" class="bg-white border border-gray-200 rounded-lg p-12 text-center">
416
- <p class="text-sm text-gray-500">No results found</p>
417
- <p class="text-xs text-gray-400 mt-1">Try a different query or adjust the Top-K value</p>
418
- </div>
432
+ <!-- Graph Visualization -->
433
+ <div x-show="graphViewMode === 'graph'" class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 overflow-hidden">
434
+ <div class="px-6 py-4 border-b border-md-outline dark:border-md-outline-dark flex items-center justify-between">
435
+ <h3 class="text-lg font-medium text-md-on-surface dark:text-md-on-surface-dark flex items-center gap-2">
436
+ <span class="material-icons-outlined text-md-primary">scatter_plot</span>
437
+ Interactive Graph
438
+ </h3>
439
+ <div class="flex items-center gap-4 text-xs text-gray-500">
440
+ <span class="flex items-center gap-1"><span class="w-3 h-3 rounded-full bg-md-primary"></span> Neurons</span>
441
+ <span class="flex items-center gap-1"><span class="w-8 h-0.5 bg-gray-400"></span> Synapses</span>
442
+ <span>Drag to move | Scroll to zoom</span>
443
+ </div>
444
+ </div>
445
+ <div id="graph-container" class="relative" style="height: 500px;">
446
+ <svg id="graph-svg" class="w-full h-full"></svg>
447
+ <!-- Tooltip -->
448
+ <div id="graph-tooltip" class="absolute hidden bg-md-surface-dark text-white text-xs px-3 py-2 rounded-lg shadow-md-3 pointer-events-none z-10">
449
+ <p class="font-mono" id="tooltip-id"></p>
450
+ <p id="tooltip-label"></p>
451
+ </div>
452
+ <!-- Empty State -->
453
+ <div x-show="!graphData.nodes || graphData.nodes.length === 0" class="absolute inset-0 flex items-center justify-center">
454
+ <div class="text-center">
455
+ <span class="material-icons-outlined text-6xl text-gray-300 dark:text-gray-600">hub</span>
456
+ <p class="mt-4 text-gray-500 dark:text-gray-400">No graph data available</p>
457
+ <p class="text-sm text-gray-400 dark:text-gray-500">Ingest some content to see the knowledge graph</p>
458
+ </div>
459
+ </div>
460
+ </div>
461
+ </div>
419
462
 
420
- <!-- Search Error -->
421
- <div x-show="searchError" x-cloak class="bg-red-50 border border-red-200 rounded-lg p-4">
422
- <p class="text-sm text-red-700 font-medium">Search Error</p>
423
- <p class="text-xs text-red-600 mt-1" x-text="searchError"></p>
424
- </div>
425
- </section>
463
+ <!-- Table View -->
464
+ <div x-show="graphViewMode === 'table'" class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 overflow-hidden">
465
+ <div class="px-6 py-4 border-b border-md-outline dark:border-md-outline-dark">
466
+ <h3 class="text-lg font-medium text-md-on-surface dark:text-md-on-surface-dark flex items-center gap-2">
467
+ <span class="material-icons-outlined text-md-primary">table_rows</span>
468
+ Edge List
469
+ </h3>
470
+ </div>
471
+ <div class="max-h-96 overflow-y-auto">
472
+ <table class="w-full">
473
+ <thead class="sticky top-0 bg-md-surface-variant dark:bg-md-surface-dark">
474
+ <tr class="border-b border-md-outline dark:border-md-outline-dark">
475
+ <th class="text-left text-xs font-medium text-gray-500 uppercase px-6 py-3">Source</th>
476
+ <th class="text-left text-xs font-medium text-gray-500 uppercase px-6 py-3">Target</th>
477
+ <th class="text-left text-xs font-medium text-gray-500 uppercase px-6 py-3">Type</th>
478
+ <th class="text-right text-xs font-medium text-gray-500 uppercase px-6 py-3">Weight</th>
479
+ </tr>
480
+ </thead>
481
+ <tbody class="divide-y divide-md-outline dark:divide-md-outline-dark">
482
+ <template x-for="(edge, i) in (graphData.edges || []).slice(0, 100)" :key="i">
483
+ <tr class="hover:bg-md-surface-variant dark:hover:bg-md-surface-dark">
484
+ <td class="px-6 py-3 font-mono text-sm text-md-primary dark:text-md-primary-light" x-text="edge.source?.substring(0, 12) + '...'"></td>
485
+ <td class="px-6 py-3 font-mono text-sm text-md-primary dark:text-md-primary-light" x-text="edge.target?.substring(0, 12) + '...'"></td>
486
+ <td class="px-6 py-3">
487
+ <span class="px-2 py-1 text-xs rounded-full bg-md-secondary/10 text-md-secondary" x-text="edge.type"></span>
488
+ </td>
489
+ <td class="px-6 py-3 text-right font-mono text-sm" x-text="edge.weight?.toFixed(4)"></td>
490
+ </tr>
491
+ </template>
492
+ <tr x-show="!graphData.edges || graphData.edges.length === 0">
493
+ <td colspan="4" class="px-6 py-8 text-center text-gray-500">No edges found</td>
494
+ </tr>
495
+ </tbody>
496
+ </table>
497
+ </div>
498
+ </div>
499
+ </section>
426
500
 
427
- <!-- ============================================================ -->
428
- <!-- TAB 4: INGEST -->
429
- <!-- ============================================================ -->
430
- <section x-show="activeTab === 'ingest'" x-cloak>
431
- <h2 class="text-base font-semibold text-gray-900 mb-4">Ingest Content</h2>
501
+ <!-- INFERENCE TAB -->
502
+ <section x-show="activeTab === 'inference'" x-cloak>
503
+ <h2 class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark mb-6">Inference Engine</h2>
432
504
 
433
- <div class="grid grid-cols-1 lg:grid-cols-2 gap-5">
434
- <!-- Ingest Form -->
435
- <div class="bg-white border border-gray-200 rounded-lg p-5">
436
- <div class="space-y-4">
437
- <div>
438
- <div class="flex items-center justify-between mb-1">
439
- <label class="text-xs font-medium text-gray-600">Text Content</label>
440
- <span class="text-xs text-gray-400" x-text="ingestText.length + ' characters'"></span>
441
- </div>
442
- <textarea
443
- x-model="ingestText"
444
- rows="10"
445
- placeholder="Enter or paste text content to ingest..."
446
- class="w-full px-3 py-2 text-sm border border-gray-300 rounded-md focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none transition resize-y font-mono"
447
- ></textarea>
448
- </div>
449
- <div class="grid grid-cols-2 gap-3">
505
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
506
+ <!-- Input Form -->
507
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 overflow-hidden">
508
+ <div class="px-6 py-4 bg-md-primary dark:bg-md-primary-dark">
509
+ <h3 class="text-lg font-medium text-white flex items-center gap-2">
510
+ <span class="material-icons-outlined">play_arrow</span>
511
+ Run Inference
512
+ </h3>
513
+ </div>
514
+ <div class="p-6 space-y-4">
450
515
  <div>
451
- <label class="text-xs font-medium text-gray-600 block mb-1">Source Type</label>
452
- <input
453
- type="text"
454
- x-model="ingestSourceType"
455
- placeholder="dashboard"
456
- class="w-full px-3 py-2 text-sm border border-gray-300 rounded-md focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none transition"
457
- >
516
+ <label class="text-sm font-medium text-md-on-surface dark:text-md-on-surface-dark block mb-2">Neuron ID</label>
517
+ <input type="text" x-model="inferNeuronId" placeholder="Enter neuron ID..."
518
+ class="w-full px-4 py-3 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm font-mono focus:ring-2 focus:ring-md-primary focus:border-transparent outline-none transition-all">
458
519
  </div>
459
- <div>
460
- <label class="text-xs font-medium text-gray-600 block mb-1">Tags (comma-separated)</label>
461
- <input
462
- type="text"
463
- x-model="ingestTags"
464
- placeholder="tag1, tag2"
465
- class="w-full px-3 py-2 text-sm border border-gray-300 rounded-md focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none transition"
466
- >
520
+ <div class="grid grid-cols-2 gap-4">
521
+ <div>
522
+ <label class="text-sm font-medium text-md-on-surface dark:text-md-on-surface-dark block mb-2">Inference Type</label>
523
+ <select x-model="inferType" class="w-full px-4 py-3 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
524
+ <option value="forward">Forward</option>
525
+ <option value="backward">Backward</option>
526
+ <option value="causal">Causal</option>
527
+ <option value="bidirectional">Bidirectional</option>
528
+ </select>
529
+ </div>
530
+ <div>
531
+ <label class="text-sm font-medium text-md-on-surface dark:text-md-on-surface-dark block mb-2">Depth</label>
532
+ <input type="number" x-model.number="inferDepth" min="1" max="10"
533
+ class="w-full px-4 py-3 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
534
+ </div>
467
535
  </div>
536
+ <button @click="runInference()" :disabled="inferring || !inferNeuronId"
537
+ class="w-full py-3 bg-md-primary text-white rounded-lg font-medium hover:bg-md-primary-dark disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2 shadow-md-1 transition-all">
538
+ <span x-show="inferring" class="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin"></span>
539
+ <span class="material-icons-outlined" x-show="!inferring">play_arrow</span>
540
+ Run Inference
541
+ </button>
468
542
  </div>
469
- <button
470
- @click="doIngest()"
471
- :disabled="ingesting || !ingestText.trim()"
472
- class="w-full px-4 py-2.5 text-sm font-medium text-white bg-emerald-600 rounded-md hover:bg-emerald-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center justify-center gap-2"
473
- >
474
- <span x-show="ingesting" class="w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin"></span>
475
- <span x-text="ingesting ? 'Ingesting...' : 'Ingest'"></span>
476
- </button>
477
543
  </div>
478
- </div>
479
544
 
480
- <!-- Result Panel -->
481
- <div>
482
- <!-- Success -->
483
- <div x-show="ingestResult" x-cloak class="bg-emerald-50 border border-emerald-200 rounded-lg p-5">
484
- <h3 class="text-sm font-semibold text-emerald-800 mb-3">Ingestion Successful</h3>
485
- <div class="space-y-2">
486
- <div>
487
- <label class="text-xs text-emerald-600">Neuron ID</label>
488
- <p class="text-xs font-mono text-emerald-900 break-all select-all" x-text="ingestResult?.neuronId"></p>
545
+ <!-- Results -->
546
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 overflow-hidden">
547
+ <div class="px-6 py-4 border-b border-md-outline dark:border-md-outline-dark">
548
+ <h3 class="text-lg font-medium text-md-on-surface dark:text-md-on-surface-dark flex items-center gap-2">
549
+ <span class="material-icons-outlined text-md-primary">insights</span>
550
+ Results
551
+ </h3>
552
+ </div>
553
+ <div class="p-6">
554
+ <div x-show="inferResults" class="space-y-4">
555
+ <div class="flex flex-wrap gap-4 text-sm">
556
+ <span class="px-3 py-1 bg-md-primary/10 text-md-primary rounded-full">Type: <span class="font-medium" x-text="inferResults?.type"></span></span>
557
+ <span class="px-3 py-1 bg-md-success/10 text-md-success rounded-full">Found: <span class="font-medium" x-text="inferResults?.totalFound"></span></span>
558
+ </div>
559
+ <div class="max-h-72 overflow-y-auto space-y-2">
560
+ <template x-for="(r, i) in (inferResults?.results || []).slice(0, 20)" :key="i">
561
+ <div class="flex items-center justify-between p-3 bg-md-surface-variant dark:bg-md-surface-dark rounded-lg">
562
+ <span class="font-mono text-sm text-md-primary dark:text-md-primary-light" x-text="r.id?.substring(0, 16) + '...'"></span>
563
+ <span class="text-xs px-2 py-1 bg-md-outline dark:bg-md-outline-dark rounded-full" x-text="'Depth: ' + r.distance"></span>
564
+ </div>
565
+ </template>
566
+ </div>
489
567
  </div>
490
- <div>
491
- <label class="text-xs text-emerald-600">Merkle Root</label>
492
- <p class="text-xs font-mono text-emerald-900 break-all select-all" x-text="ingestResult?.merkleRoot"></p>
568
+ <div x-show="!inferResults" class="text-center py-12">
569
+ <span class="material-icons-outlined text-6xl text-gray-300 dark:text-gray-600">timeline</span>
570
+ <p class="mt-4 text-gray-500 dark:text-gray-400">Run inference to see results</p>
493
571
  </div>
494
- <div class="flex gap-4">
572
+ </div>
573
+ </div>
574
+ </div>
575
+ </section>
576
+
577
+ <!-- ATTRACTORS TAB -->
578
+ <section x-show="activeTab === 'attractors'" x-cloak>
579
+ <h2 class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark mb-6">Attractor Model</h2>
580
+
581
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 p-8">
582
+ <div class="text-center max-w-2xl mx-auto">
583
+ <span class="material-icons-outlined text-6xl text-md-primary mb-4">track_changes</span>
584
+ <h3 class="text-xl font-medium text-md-on-surface dark:text-md-on-surface-dark mb-2">Goal-Oriented Reasoning</h3>
585
+ <p class="text-gray-500 dark:text-gray-400 mb-6">Attractors define goal states that influence current decisions through probabilistic pathfinding.</p>
586
+
587
+ <div class="bg-md-surface-variant dark:bg-md-surface-dark rounded-xl p-6 text-left">
588
+ <h4 class="text-sm font-medium text-md-on-surface dark:text-md-on-surface-dark mb-4 flex items-center gap-2">
589
+ <span class="material-icons-outlined text-md-primary">terminal</span>
590
+ CLI Commands
591
+ </h4>
592
+ <div class="font-mono text-sm space-y-3">
495
593
  <div>
496
- <label class="text-xs text-emerald-600">Chunks</label>
497
- <p class="text-sm font-semibold text-emerald-900" x-text="ingestResult?.chunks"></p>
594
+ <p class="text-gray-500 dark:text-gray-400"># Create attractor</p>
595
+ <p class="text-md-primary dark:text-md-primary-light">nmt attractor create "Goal Name" --strength 0.8</p>
498
596
  </div>
499
597
  <div>
500
- <label class="text-xs text-emerald-600">Source Type</label>
501
- <p class="text-sm text-emerald-900" x-text="ingestResult?.sourceType"></p>
598
+ <p class="text-gray-500 dark:text-gray-400"># List all attractors</p>
599
+ <p class="text-md-primary dark:text-md-primary-light">nmt attractor list</p>
502
600
  </div>
503
- </div>
504
- <div x-show="ingestResult?.tags?.length > 0">
505
- <label class="text-xs text-emerald-600 block mb-1">Tags</label>
506
- <div class="flex flex-wrap gap-1">
507
- <template x-for="tag in (ingestResult?.tags || [])" :key="tag">
508
- <span class="inline-block bg-emerald-100 text-emerald-800 text-xs font-medium px-1.5 py-0.5 rounded" x-text="tag"></span>
509
- </template>
601
+ <div>
602
+ <p class="text-gray-500 dark:text-gray-400"># Find path to goal</p>
603
+ <p class="text-md-primary dark:text-md-primary-light">nmt attractor path &lt;neuron-id&gt; &lt;attractor-id&gt;</p>
604
+ </div>
605
+ <div>
606
+ <p class="text-gray-500 dark:text-gray-400"># Calculate influence</p>
607
+ <p class="text-md-primary dark:text-md-primary-light">nmt attractor influence &lt;neuron-id&gt;</p>
510
608
  </div>
511
609
  </div>
512
610
  </div>
513
611
  </div>
612
+ </div>
613
+ </section>
614
+
615
+ <!-- LEARNING TAB -->
616
+ <section x-show="activeTab === 'learning'" x-cloak>
617
+ <h2 class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark mb-6">Four-Stage Learning</h2>
514
618
 
515
- <!-- Error -->
516
- <div x-show="ingestError" x-cloak class="bg-red-50 border border-red-200 rounded-lg p-5">
517
- <h3 class="text-sm font-semibold text-red-800 mb-1">Ingestion Failed</h3>
518
- <p class="text-xs text-red-600" x-text="ingestError"></p>
619
+ <!-- Pipeline Steps -->
620
+ <div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
621
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-6 shadow-md-1 text-center">
622
+ <div class="w-14 h-14 bg-blue-100 dark:bg-blue-900/30 rounded-full flex items-center justify-center mx-auto mb-4">
623
+ <span class="material-icons-outlined text-blue-600 dark:text-blue-400 text-2xl">search</span>
624
+ </div>
625
+ <h4 class="font-medium text-md-on-surface dark:text-md-on-surface-dark">1. Extract</h4>
626
+ <p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Identify information</p>
519
627
  </div>
628
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-6 shadow-md-1 text-center">
629
+ <div class="w-14 h-14 bg-green-100 dark:bg-green-900/30 rounded-full flex items-center justify-center mx-auto mb-4">
630
+ <span class="material-icons-outlined text-green-600 dark:text-green-400 text-2xl">pattern</span>
631
+ </div>
632
+ <h4 class="font-medium text-md-on-surface dark:text-md-on-surface-dark">2. Pattern</h4>
633
+ <p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Recognize patterns</p>
634
+ </div>
635
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-6 shadow-md-1 text-center">
636
+ <div class="w-14 h-14 bg-amber-100 dark:bg-amber-900/30 rounded-full flex items-center justify-center mx-auto mb-4">
637
+ <span class="material-icons-outlined text-amber-600 dark:text-amber-400 text-2xl">memory</span>
638
+ </div>
639
+ <h4 class="font-medium text-md-on-surface dark:text-md-on-surface-dark">3. Process</h4>
640
+ <p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Learn reasoning</p>
641
+ </div>
642
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl p-6 shadow-md-1 text-center">
643
+ <div class="w-14 h-14 bg-purple-100 dark:bg-purple-900/30 rounded-full flex items-center justify-center mx-auto mb-4">
644
+ <span class="material-icons-outlined text-purple-600 dark:text-purple-400 text-2xl">check_circle</span>
645
+ </div>
646
+ <h4 class="font-medium text-md-on-surface dark:text-md-on-surface-dark">4. Outcome</h4>
647
+ <p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Apply feedback</p>
648
+ </div>
649
+ </div>
520
650
 
521
- <!-- Empty State -->
522
- <div x-show="!ingestResult && !ingestError" class="bg-white border border-gray-200 rounded-lg p-12 text-center">
523
- <p class="text-sm text-gray-400">Results will appear here after ingestion</p>
651
+ <!-- CLI Commands -->
652
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 p-6">
653
+ <h3 class="text-lg font-medium text-md-on-surface dark:text-md-on-surface-dark mb-4 flex items-center gap-2">
654
+ <span class="material-icons-outlined text-md-primary">terminal</span>
655
+ CLI Commands
656
+ </h3>
657
+ <div class="bg-md-surface-variant dark:bg-md-surface-dark rounded-lg p-4 font-mono text-sm space-y-3">
658
+ <div>
659
+ <p class="text-gray-500 dark:text-gray-400"># Start learning session</p>
660
+ <p class="text-md-primary dark:text-md-primary-light">nmt learn session start</p>
661
+ </div>
662
+ <div>
663
+ <p class="text-gray-500 dark:text-gray-400"># Extract from neuron</p>
664
+ <p class="text-md-primary dark:text-md-primary-light">nmt learn extract &lt;neuron-id&gt; --limit 20</p>
665
+ </div>
666
+ <div>
667
+ <p class="text-gray-500 dark:text-gray-400"># Full learning pipeline</p>
668
+ <p class="text-md-primary dark:text-md-primary-light">nmt orchestrate learn --input "Q" --output "A" --success</p>
669
+ </div>
524
670
  </div>
525
671
  </div>
526
- </div>
527
- </section>
672
+ </section>
528
673
 
529
- <!-- ============================================================ -->
530
- <!-- TAB 5: VERIFY -->
531
- <!-- ============================================================ -->
532
- <section x-show="activeTab === 'verify'" x-cloak>
533
- <h2 class="text-base font-semibold text-gray-900 mb-4">Data Integrity Verification</h2>
674
+ <!-- SYNC TAB -->
675
+ <section x-show="activeTab === 'sync'" x-cloak>
676
+ <div class="flex items-center justify-between mb-6">
677
+ <h2 class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark">State Synchronization</h2>
678
+ <button @click="loadSyncStatus()" class="flex items-center gap-2 px-4 py-2 bg-md-primary text-white rounded-full text-sm font-medium hover:bg-md-primary-dark shadow-md-1">
679
+ <span class="material-icons-outlined text-xl">refresh</span>
680
+ Refresh Status
681
+ </button>
682
+ </div>
534
683
 
535
- <div class="grid grid-cols-1 lg:grid-cols-2 gap-5">
684
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
685
+ <!-- Current State -->
686
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 overflow-hidden">
687
+ <div class="px-6 py-4 bg-md-primary dark:bg-md-primary-dark">
688
+ <h3 class="text-lg font-medium text-white flex items-center gap-2">
689
+ <span class="material-icons-outlined">sync</span>
690
+ Current State
691
+ </h3>
692
+ </div>
693
+ <div class="p-6 space-y-4">
694
+ <div class="flex justify-between items-center py-2 border-b border-md-outline dark:border-md-outline-dark">
695
+ <span class="text-sm text-gray-500 dark:text-gray-400">Node ID</span>
696
+ <span class="font-mono text-sm text-md-on-surface dark:text-md-on-surface-dark" x-text="syncStatus?.nodeId ?? '--'"></span>
697
+ </div>
698
+ <div class="flex justify-between items-center py-2 border-b border-md-outline dark:border-md-outline-dark">
699
+ <span class="text-sm text-gray-500 dark:text-gray-400">Sequence</span>
700
+ <span class="font-mono text-sm text-md-on-surface dark:text-md-on-surface-dark" x-text="syncStatus?.sequence ?? 0"></span>
701
+ </div>
702
+ <div class="flex justify-between items-center py-2 border-b border-md-outline dark:border-md-outline-dark">
703
+ <span class="text-sm text-gray-500 dark:text-gray-400">Neurons</span>
704
+ <span class="font-mono text-sm text-md-on-surface dark:text-md-on-surface-dark" x-text="syncStatus?.neuronCount ?? 0"></span>
705
+ </div>
706
+ <div class="flex justify-between items-center py-2">
707
+ <span class="text-sm text-gray-500 dark:text-gray-400">Peers</span>
708
+ <span class="font-mono text-sm text-md-on-surface dark:text-md-on-surface-dark" x-text="syncStatus?.peers?.length ?? 0"></span>
709
+ </div>
710
+ </div>
711
+ </div>
536
712
 
537
- <!-- Verify All -->
538
- <div class="space-y-4">
539
- <div class="bg-white border border-gray-200 rounded-lg p-5">
540
- <h3 class="text-sm font-semibold text-gray-700 mb-3">Verify All Neurons</h3>
541
- <button
542
- @click="doVerifyAll()"
543
- :disabled="verifying"
544
- class="px-4 py-2 text-sm font-medium text-white bg-indigo-600 rounded-md hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center gap-2"
545
- >
546
- <span x-show="verifying" class="w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin"></span>
547
- <span x-text="verifying ? 'Verifying...' : 'Run Verification'"></span>
548
- </button>
713
+ <!-- CLI Commands -->
714
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 p-6">
715
+ <h3 class="text-lg font-medium text-md-on-surface dark:text-md-on-surface-dark mb-4 flex items-center gap-2">
716
+ <span class="material-icons-outlined text-md-primary">terminal</span>
717
+ CLI Commands
718
+ </h3>
719
+ <div class="bg-md-surface-variant dark:bg-md-surface-dark rounded-lg p-4 font-mono text-sm space-y-3">
720
+ <div>
721
+ <p class="text-gray-500 dark:text-gray-400"># Check sync status</p>
722
+ <p class="text-md-primary dark:text-md-primary-light">nmt sync status</p>
723
+ </div>
724
+ <div>
725
+ <p class="text-gray-500 dark:text-gray-400"># View change log</p>
726
+ <p class="text-md-primary dark:text-md-primary-light">nmt sync changes --from 0</p>
727
+ </div>
728
+ <div>
729
+ <p class="text-gray-500 dark:text-gray-400"># Export state</p>
730
+ <p class="text-md-primary dark:text-md-primary-light">nmt sync export --output backup.json</p>
731
+ </div>
732
+ <div>
733
+ <p class="text-gray-500 dark:text-gray-400"># Import state</p>
734
+ <p class="text-md-primary dark:text-md-primary-light">nmt sync import backup.json</p>
735
+ </div>
736
+ </div>
549
737
  </div>
738
+ </div>
739
+ </section>
550
740
 
551
- <!-- Verify All Results -->
552
- <div x-show="verifyAllResult" x-cloak class="bg-white border border-gray-200 rounded-lg overflow-hidden">
553
- <!-- Summary -->
554
- <div class="px-4 py-3 border-b border-gray-200 bg-gray-50 flex items-center gap-4">
555
- <span class="text-xs font-medium text-gray-600">
556
- Total: <span class="font-semibold text-gray-900" x-text="verifyAllResult?.total"></span>
557
- </span>
558
- <span class="text-xs font-medium text-emerald-600">
559
- Valid: <span class="font-semibold" x-text="verifyAllResult?.valid"></span>
560
- </span>
561
- <span class="text-xs font-medium text-red-600">
562
- Invalid: <span class="font-semibold" x-text="verifyAllResult?.invalid"></span>
563
- </span>
564
- </div>
565
- <!-- Results Table -->
566
- <div class="max-h-80 overflow-y-auto">
567
- <table class="w-full text-sm">
568
- <thead class="sticky top-0 bg-white">
569
- <tr class="border-b border-gray-100">
570
- <th class="text-left text-xs font-semibold text-gray-600 px-4 py-2">Neuron ID</th>
571
- <th class="text-center text-xs font-semibold text-gray-600 px-4 py-2">Status</th>
572
- <th class="text-left text-xs font-semibold text-gray-600 px-4 py-2">Errors</th>
573
- </tr>
574
- </thead>
575
- <tbody>
576
- <template x-for="(r, idx) in (verifyAllResult?.results || [])" :key="idx">
577
- <tr class="border-b border-gray-50">
578
- <td class="px-4 py-2 font-mono text-xs text-gray-700" x-text="r.neuronId?.substring(0, 12) + '...'"></td>
579
- <td class="px-4 py-2 text-center">
580
- <span x-show="r.valid" class="inline-block w-5 h-5 text-xs leading-5 text-center text-emerald-700 bg-emerald-100 rounded-full font-bold">OK</span>
581
- <span x-show="!r.valid" class="inline-block w-5 h-5 text-xs leading-5 text-center text-red-700 bg-red-100 rounded-full font-bold">!</span>
582
- </td>
583
- <td class="px-4 py-2 text-xs text-red-600" x-text="r.errors?.join(', ') || '--'"></td>
584
- </tr>
585
- </template>
586
- </tbody>
587
- </table>
741
+ <!-- SEARCH TAB -->
742
+ <section x-show="activeTab === 'search'" x-cloak>
743
+ <h2 class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark mb-6">Semantic Search</h2>
744
+
745
+ <!-- Search Box -->
746
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 p-6 mb-6">
747
+ <div class="flex flex-col sm:flex-row gap-4">
748
+ <div class="flex-1 relative">
749
+ <span class="material-icons-outlined absolute left-4 top-1/2 -translate-y-1/2 text-gray-400">search</span>
750
+ <input type="text" x-model="searchQuery" @keydown.enter="doSearch()"
751
+ placeholder="Enter your search query..."
752
+ class="w-full pl-12 pr-4 py-3 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-full text-sm focus:ring-2 focus:ring-md-primary focus:border-transparent outline-none transition-all">
588
753
  </div>
589
- <div x-show="!verifyAllResult?.results || verifyAllResult.results.length === 0" class="p-6 text-center">
590
- <p class="text-xs text-gray-400">No verification results</p>
754
+ <div class="flex gap-3">
755
+ <input type="number" x-model.number="searchK" min="1" max="100" placeholder="K"
756
+ class="w-20 px-4 py-3 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-full text-sm text-center focus:ring-2 focus:ring-md-primary outline-none">
757
+ <label class="flex items-center gap-2 px-4 py-3 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-full text-sm cursor-pointer">
758
+ <input type="checkbox" x-model="searchIncludeContent" class="rounded text-md-primary focus:ring-md-primary">
759
+ <span class="text-md-on-surface dark:text-md-on-surface-dark">Content</span>
760
+ </label>
761
+ <button @click="doSearch()" :disabled="searching || !searchQuery"
762
+ class="px-6 py-3 bg-md-primary text-white rounded-full font-medium hover:bg-md-primary-dark disabled:opacity-50 shadow-md-1 flex items-center gap-2 transition-all">
763
+ <span x-show="searching" class="w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin"></span>
764
+ <span class="material-icons-outlined" x-show="!searching">search</span>
765
+ Search
766
+ </button>
591
767
  </div>
592
768
  </div>
593
769
  </div>
594
770
 
595
- <!-- Verify Single -->
771
+ <!-- Results -->
596
772
  <div class="space-y-4">
597
- <div class="bg-white border border-gray-200 rounded-lg p-5">
598
- <h3 class="text-sm font-semibold text-gray-700 mb-3">Verify Single Neuron</h3>
599
- <div class="flex gap-2">
600
- <input
601
- type="text"
602
- x-model="verifyNeuronId"
603
- placeholder="Enter neuron ID..."
604
- @keydown.enter="doVerifySingle()"
605
- class="flex-1 px-3 py-2 text-sm font-mono border border-gray-300 rounded-md focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none transition"
606
- >
607
- <button
608
- @click="doVerifySingle()"
609
- :disabled="verifySingleLoading || !verifyNeuronId.trim()"
610
- class="px-4 py-2 text-sm font-medium text-white bg-indigo-600 rounded-md hover:bg-indigo-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors flex items-center gap-2"
611
- >
612
- <span x-show="verifySingleLoading" class="w-3.5 h-3.5 border-2 border-white/30 border-t-white rounded-full animate-spin"></span>
613
- Verify
614
- </button>
773
+ <template x-for="(r, i) in searchResults" :key="i">
774
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 p-5 hover:shadow-md-2 transition-shadow">
775
+ <div class="flex items-center gap-4 mb-3">
776
+ <span class="font-mono text-sm px-3 py-1 bg-md-primary/10 text-md-primary dark:bg-md-primary/20 dark:text-md-primary-light rounded-full" x-text="r.neuronId?.substring(0, 16) + '...'"></span>
777
+ <span class="text-sm font-medium px-3 py-1 rounded-full"
778
+ :class="r.score > 0.8 ? 'bg-md-success/10 text-md-success' : r.score > 0.5 ? 'bg-amber-500/10 text-amber-600' : 'bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-300'"
779
+ x-text="'Score: ' + r.score?.toFixed(4)"></span>
780
+ </div>
781
+ <pre x-show="r.content" class="bg-md-surface-variant dark:bg-md-surface-dark rounded-lg p-4 text-sm font-mono text-md-on-surface dark:text-md-on-surface-dark whitespace-pre-wrap max-h-40 overflow-y-auto" x-text="r.content"></pre>
615
782
  </div>
783
+ </template>
784
+ <div x-show="searchResults.length === 0 && !searching" class="text-center py-12">
785
+ <span class="material-icons-outlined text-6xl text-gray-300 dark:text-gray-600">manage_search</span>
786
+ <p class="mt-4 text-gray-500 dark:text-gray-400">Enter a query to search</p>
616
787
  </div>
788
+ </div>
789
+ </section>
617
790
 
618
- <!-- Single Verify Result -->
619
- <div x-show="verifySingleResult" x-cloak>
620
- <div
621
- :class="verifySingleResult?.valid ? 'bg-emerald-50 border-emerald-200' : 'bg-red-50 border-red-200'"
622
- class="border rounded-lg p-5"
623
- >
624
- <div class="flex items-center gap-2 mb-3">
625
- <span
626
- :class="verifySingleResult?.valid ? 'text-emerald-800 bg-emerald-200' : 'text-red-800 bg-red-200'"
627
- class="text-xs font-bold px-2 py-0.5 rounded"
628
- x-text="verifySingleResult?.valid ? 'VALID' : 'INVALID'"
629
- ></span>
791
+ <!-- INGEST TAB -->
792
+ <section x-show="activeTab === 'ingest'" x-cloak>
793
+ <h2 class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark mb-6">Ingest Content</h2>
794
+
795
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
796
+ <!-- Input Form -->
797
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 overflow-hidden">
798
+ <div class="px-6 py-4 bg-md-success dark:bg-green-800">
799
+ <h3 class="text-lg font-medium text-white flex items-center gap-2">
800
+ <span class="material-icons-outlined">upload_file</span>
801
+ Add Content
802
+ </h3>
803
+ </div>
804
+ <div class="p-6 space-y-4">
805
+ <div>
806
+ <label class="text-sm font-medium text-md-on-surface dark:text-md-on-surface-dark block mb-2">Text Content</label>
807
+ <textarea x-model="ingestText" rows="8" placeholder="Paste or type text to ingest..."
808
+ class="w-full px-4 py-3 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm font-mono resize-y focus:ring-2 focus:ring-md-primary focus:border-transparent outline-none transition-all"></textarea>
630
809
  </div>
631
- <div class="space-y-2">
810
+ <div class="grid grid-cols-2 gap-4">
632
811
  <div>
633
- <label class="text-xs" :class="verifySingleResult?.valid ? 'text-emerald-600' : 'text-red-600'">Neuron ID</label>
634
- <p class="text-xs font-mono break-all" :class="verifySingleResult?.valid ? 'text-emerald-900' : 'text-red-900'" x-text="verifySingleResult?.neuronId"></p>
812
+ <label class="text-sm font-medium text-md-on-surface dark:text-md-on-surface-dark block mb-2">Source Type</label>
813
+ <input type="text" x-model="ingestSourceType" placeholder="dashboard"
814
+ class="w-full px-4 py-3 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
635
815
  </div>
636
816
  <div>
637
- <label class="text-xs" :class="verifySingleResult?.valid ? 'text-emerald-600' : 'text-red-600'">Merkle Root</label>
638
- <p class="text-xs font-mono break-all" :class="verifySingleResult?.valid ? 'text-emerald-900' : 'text-red-900'" x-text="verifySingleResult?.merkleRoot || '--'"></p>
817
+ <label class="text-sm font-medium text-md-on-surface dark:text-md-on-surface-dark block mb-2">Tags (comma-separated)</label>
818
+ <input type="text" x-model="ingestTags" placeholder="tag1, tag2, tag3"
819
+ class="w-full px-4 py-3 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm focus:ring-2 focus:ring-md-primary outline-none">
639
820
  </div>
640
- <div x-show="verifySingleResult?.details" class="grid grid-cols-2 gap-2 pt-2 border-t" :class="verifySingleResult?.valid ? 'border-emerald-200' : 'border-red-200'">
641
- <div>
642
- <label class="text-xs" :class="verifySingleResult?.valid ? 'text-emerald-600' : 'text-red-600'">Chunks Verified</label>
643
- <p class="text-sm font-semibold" :class="verifySingleResult?.valid ? 'text-emerald-900' : 'text-red-900'" x-text="verifySingleResult?.details?.chunksVerified ?? '--'"></p>
644
- </div>
645
- <div>
646
- <label class="text-xs" :class="verifySingleResult?.valid ? 'text-emerald-600' : 'text-red-600'">Chunks Failed</label>
647
- <p class="text-sm font-semibold" :class="verifySingleResult?.valid ? 'text-emerald-900' : 'text-red-900'" x-text="verifySingleResult?.details?.chunksFailed ?? '--'"></p>
648
- </div>
649
- <div>
650
- <label class="text-xs" :class="verifySingleResult?.valid ? 'text-emerald-600' : 'text-red-600'">Merkle Valid</label>
651
- <p class="text-sm font-semibold" :class="verifySingleResult?.valid ? 'text-emerald-900' : 'text-red-900'" x-text="verifySingleResult?.details?.merkleValid ? 'Yes' : 'No'"></p>
652
- </div>
653
- <div>
654
- <label class="text-xs" :class="verifySingleResult?.valid ? 'text-emerald-600' : 'text-red-600'">Embedding Valid</label>
655
- <p class="text-sm font-semibold" :class="verifySingleResult?.valid ? 'text-emerald-900' : 'text-red-900'" x-text="verifySingleResult?.details?.embeddingValid ? 'Yes' : 'No'"></p>
656
- </div>
821
+ </div>
822
+ <button @click="doIngest()" :disabled="ingesting || !ingestText"
823
+ class="w-full py-3 bg-md-success text-white rounded-lg font-medium hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2 shadow-md-1 transition-all">
824
+ <span x-show="ingesting" class="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin"></span>
825
+ <span class="material-icons-outlined" x-show="!ingesting">upload</span>
826
+ <span x-text="ingesting ? 'Ingesting...' : 'Ingest Content'"></span>
827
+ </button>
828
+ </div>
829
+ </div>
830
+
831
+ <!-- Result -->
832
+ <div class="space-y-4">
833
+ <div x-show="ingestResult" class="card bg-md-success/10 dark:bg-md-success/20 border border-md-success/30 rounded-xl p-6">
834
+ <div class="flex items-center gap-3 mb-4">
835
+ <span class="material-icons-outlined text-md-success text-3xl">check_circle</span>
836
+ <h3 class="text-lg font-medium text-md-success">Success!</h3>
837
+ </div>
838
+ <div class="space-y-2 font-mono text-sm">
839
+ <p class="text-md-on-surface dark:text-md-on-surface-dark"><span class="text-gray-500">ID:</span> <span x-text="ingestResult?.neuronId"></span></p>
840
+ <p class="text-md-on-surface dark:text-md-on-surface-dark"><span class="text-gray-500">Chunks:</span> <span x-text="ingestResult?.chunks"></span></p>
841
+ </div>
842
+ </div>
843
+ <div x-show="ingestError" class="card bg-md-error/10 dark:bg-md-error/20 border border-md-error/30 rounded-xl p-6">
844
+ <div class="flex items-center gap-3 mb-2">
845
+ <span class="material-icons-outlined text-md-error text-3xl">error</span>
846
+ <h3 class="text-lg font-medium text-md-error">Error</h3>
847
+ </div>
848
+ <p class="text-sm text-md-error" x-text="ingestError"></p>
849
+ </div>
850
+ </div>
851
+ </div>
852
+ </section>
853
+
854
+ <!-- VERIFY TAB -->
855
+ <section x-show="activeTab === 'verify'" x-cloak>
856
+ <h2 class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark mb-6">Data Integrity</h2>
857
+
858
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
859
+ <!-- Verify All -->
860
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 overflow-hidden">
861
+ <div class="px-6 py-4 border-b border-md-outline dark:border-md-outline-dark">
862
+ <h3 class="text-lg font-medium text-md-on-surface dark:text-md-on-surface-dark flex items-center gap-2">
863
+ <span class="material-icons-outlined text-md-primary">verified</span>
864
+ Verify All Neurons
865
+ </h3>
866
+ </div>
867
+ <div class="p-6">
868
+ <button @click="doVerifyAll()" :disabled="verifying"
869
+ class="w-full py-3 bg-md-primary text-white rounded-lg font-medium hover:bg-md-primary-dark disabled:opacity-50 flex items-center justify-center gap-2 shadow-md-1 transition-all">
870
+ <span x-show="verifying" class="w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin"></span>
871
+ <span class="material-icons-outlined" x-show="!verifying">verified_user</span>
872
+ <span x-text="verifying ? 'Verifying...' : 'Run Verification'"></span>
873
+ </button>
874
+
875
+ <div x-show="verifyAllResult" class="mt-6 grid grid-cols-3 gap-4">
876
+ <div class="text-center p-4 bg-md-surface-variant dark:bg-md-surface-dark rounded-lg">
877
+ <p class="text-2xl font-medium text-md-on-surface dark:text-md-on-surface-dark" x-text="verifyAllResult?.total"></p>
878
+ <p class="text-xs text-gray-500 mt-1">Total</p>
657
879
  </div>
658
- <div x-show="verifySingleResult?.errors?.length > 0" class="pt-2">
659
- <label class="text-xs text-red-600">Errors</label>
660
- <template x-for="(err, i) in (verifySingleResult?.errors || [])" :key="i">
661
- <p class="text-xs text-red-800 font-mono" x-text="err"></p>
662
- </template>
880
+ <div class="text-center p-4 bg-md-success/10 dark:bg-md-success/20 rounded-lg">
881
+ <p class="text-2xl font-medium text-md-success" x-text="verifyAllResult?.valid"></p>
882
+ <p class="text-xs text-md-success mt-1">Valid</p>
883
+ </div>
884
+ <div class="text-center p-4 bg-md-error/10 dark:bg-md-error/20 rounded-lg">
885
+ <p class="text-2xl font-medium text-md-error" x-text="verifyAllResult?.invalid"></p>
886
+ <p class="text-xs text-md-error mt-1">Invalid</p>
663
887
  </div>
664
888
  </div>
665
889
  </div>
666
890
  </div>
667
891
 
668
- <!-- Verify Error -->
669
- <div x-show="verifySingleError" x-cloak class="bg-red-50 border border-red-200 rounded-lg p-4">
670
- <p class="text-sm text-red-700 font-medium">Verification Error</p>
671
- <p class="text-xs text-red-600 mt-1" x-text="verifySingleError"></p>
672
- </div>
892
+ <!-- Verify Single -->
893
+ <div class="card bg-md-surface dark:bg-md-surface-variant-dark rounded-xl shadow-md-1 overflow-hidden">
894
+ <div class="px-6 py-4 border-b border-md-outline dark:border-md-outline-dark">
895
+ <h3 class="text-lg font-medium text-md-on-surface dark:text-md-on-surface-dark flex items-center gap-2">
896
+ <span class="material-icons-outlined text-md-primary">fact_check</span>
897
+ Verify Single Neuron
898
+ </h3>
899
+ </div>
900
+ <div class="p-6">
901
+ <div class="flex gap-3">
902
+ <input type="text" x-model="verifyNeuronId" placeholder="Enter neuron ID..."
903
+ class="flex-1 px-4 py-3 bg-md-surface-variant dark:bg-md-surface-dark border border-md-outline dark:border-md-outline-dark rounded-lg text-sm font-mono focus:ring-2 focus:ring-md-primary outline-none">
904
+ <button @click="doVerifySingle()" :disabled="verifySingleLoading || !verifyNeuronId"
905
+ class="px-6 py-3 bg-md-primary text-white rounded-lg font-medium hover:bg-md-primary-dark disabled:opacity-50 shadow-md-1 transition-all">
906
+ Verify
907
+ </button>
908
+ </div>
673
909
 
674
- <!-- Empty State -->
675
- <div x-show="!verifySingleResult && !verifySingleError" class="bg-white border border-gray-200 rounded-lg p-12 text-center">
676
- <p class="text-sm text-gray-400">Enter a neuron ID to verify its integrity</p>
910
+ <div x-show="verifySingleResult" class="mt-6">
911
+ <div :class="verifySingleResult?.valid ? 'bg-md-success/10 border-md-success/30' : 'bg-md-error/10 border-md-error/30'"
912
+ class="border rounded-lg p-4 flex items-center gap-3">
913
+ <span class="material-icons-outlined text-3xl" :class="verifySingleResult?.valid ? 'text-md-success' : 'text-md-error'"
914
+ x-text="verifySingleResult?.valid ? 'check_circle' : 'cancel'"></span>
915
+ <div>
916
+ <p class="font-medium" :class="verifySingleResult?.valid ? 'text-md-success' : 'text-md-error'"
917
+ x-text="verifySingleResult?.valid ? 'Valid' : 'Invalid'"></p>
918
+ <p class="text-sm text-gray-500">Merkle proof verification complete</p>
919
+ </div>
920
+ </div>
921
+ </div>
922
+ </div>
677
923
  </div>
678
924
  </div>
679
- </div>
680
- </section>
925
+ </section>
681
926
 
927
+ </div>
682
928
  </main>
683
929
 
930
+ <!-- Overlay for mobile sidebar -->
931
+ <div x-show="sidebarOpen" x-cloak
932
+ @click="sidebarOpen = false"
933
+ class="fixed inset-0 bg-black/50 z-30 lg:hidden transition-opacity"></div>
934
+
684
935
  <script>
685
936
  function dashboard() {
686
937
  return {
938
+ // Theme
939
+ darkMode: localStorage.getItem('darkMode') === 'true',
940
+
687
941
  // Navigation
942
+ sidebarOpen: window.innerWidth >= 1024,
688
943
  activeTab: 'overview',
689
- tabs: [
690
- { id: 'overview', label: 'Overview' },
691
- { id: 'neurons', label: 'Neurons' },
692
- { id: 'search', label: 'Search' },
693
- { id: 'ingest', label: 'Ingest' },
694
- { id: 'verify', label: 'Verify' },
944
+ navItems: [
945
+ { id: 'overview', label: 'Overview', icon: 'dashboard' },
946
+ { id: 'neurons', label: 'Neurons', icon: 'psychology' },
947
+ { id: 'graph', label: 'Graph', icon: 'hub' },
948
+ { id: 'inference', label: 'Inference', icon: 'timeline' },
949
+ { id: 'attractors', label: 'Attractors', icon: 'track_changes' },
950
+ { id: 'learning', label: 'Learning', icon: 'school' },
951
+ { id: 'sync', label: 'Sync', icon: 'sync' },
952
+ { id: 'search', label: 'Search', icon: 'search' },
953
+ { id: 'ingest', label: 'Ingest', icon: 'upload_file' },
954
+ { id: 'verify', label: 'Verify', icon: 'verified' },
695
955
  ],
696
956
 
697
957
  // Connection
698
958
  connected: false,
959
+ refreshing: false,
699
960
  lastRefresh: '',
961
+ globalSearch: '',
700
962
 
701
- // Stats
963
+ // Data
702
964
  stats: {},
703
-
704
- // Neurons
965
+ recentNeurons: [],
705
966
  neurons: [],
706
967
  neuronTotal: 0,
707
968
  neuronPage: 0,
708
- neuronLimit: 50,
969
+ neuronLimit: 20,
709
970
  neuronsLoading: false,
710
971
  selectedNeuron: null,
711
972
  selectedContent: '',
712
- contentLoading: false,
713
- confirmDelete: false,
714
- deleting: false,
973
+
974
+ // Graph
975
+ graphData: { nodes: [], edges: [], stats: {} },
976
+ graphViewMode: 'graph',
977
+ graphSimulation: null,
978
+
979
+ // Inference
980
+ inferNeuronId: '',
981
+ inferType: 'forward',
982
+ inferDepth: 3,
983
+ inferring: false,
984
+ inferResults: null,
985
+
986
+ // Sync
987
+ syncStatus: null,
715
988
 
716
989
  // Search
717
990
  searchQuery: '',
@@ -719,8 +992,6 @@
719
992
  searchIncludeContent: true,
720
993
  searchResults: [],
721
994
  searching: false,
722
- searchPerformed: false,
723
- searchError: null,
724
995
 
725
996
  // Ingest
726
997
  ingestText: '',
@@ -736,267 +1007,317 @@
736
1007
  verifyNeuronId: '',
737
1008
  verifySingleResult: null,
738
1009
  verifySingleLoading: false,
739
- verifySingleError: null,
740
1010
 
741
- // Auto-refresh interval
742
- _refreshInterval: null,
743
-
744
- // --------------------------------------------------------
745
- // Initialization
746
- // --------------------------------------------------------
747
1011
  async init() {
748
1012
  await this.checkHealth();
749
1013
  await this.loadStats();
750
- this._refreshInterval = setInterval(() => {
751
- if (this.activeTab === 'overview') {
752
- this.loadStats();
753
- }
754
- }, 30000);
1014
+ await this.loadRecentNeurons();
1015
+ setInterval(() => { if (this.activeTab === 'overview') this.loadStats(); }, 30000);
1016
+
1017
+ window.addEventListener('resize', () => {
1018
+ this.sidebarOpen = window.innerWidth >= 1024;
1019
+ });
755
1020
  },
756
1021
 
757
- // --------------------------------------------------------
758
- // Tab Switching
759
- // --------------------------------------------------------
760
- switchTab(tabId) {
761
- this.activeTab = tabId;
762
- if (tabId === 'overview') {
763
- this.loadStats();
764
- } else if (tabId === 'neurons') {
765
- this.loadNeurons();
766
- }
1022
+ toggleDarkMode() {
1023
+ this.darkMode = !this.darkMode;
1024
+ localStorage.setItem('darkMode', this.darkMode);
1025
+ },
1026
+
1027
+ async refreshAll() {
1028
+ this.refreshing = true;
1029
+ await this.loadStats();
1030
+ await this.loadRecentNeurons();
1031
+ this.refreshing = false;
1032
+ },
1033
+
1034
+ switchTab(id) {
1035
+ this.activeTab = id;
1036
+ if (id === 'overview') { this.loadStats(); this.loadRecentNeurons(); }
1037
+ else if (id === 'neurons') this.loadNeurons();
1038
+ else if (id === 'graph') { this.loadGraph().then(() => setTimeout(() => this.renderGraph(), 100)); }
1039
+ else if (id === 'sync') this.loadSyncStatus();
767
1040
  },
768
1041
 
769
- // --------------------------------------------------------
770
- // API Helper
771
- // --------------------------------------------------------
772
1042
  async api(method, path, body) {
773
- const opts = {
774
- method,
775
- headers: { 'Content-Type': 'application/json' },
776
- };
777
- if (body) {
778
- opts.body = JSON.stringify(body);
779
- }
1043
+ const opts = { method, headers: { 'Content-Type': 'application/json' } };
1044
+ if (body) opts.body = JSON.stringify(body);
780
1045
  try {
781
1046
  const res = await fetch('/api/v1' + path, opts);
782
- if (!res.ok) {
783
- const errBody = await res.json().catch(() => ({}));
784
- throw new Error(errBody.error || errBody.message || `HTTP ${res.status}`);
785
- }
1047
+ if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error || `HTTP ${res.status}`);
786
1048
  this.connected = true;
787
1049
  return await res.json();
788
1050
  } catch (err) {
789
- if (err.message === 'Failed to fetch' || err.message.includes('NetworkError')) {
790
- this.connected = false;
791
- }
1051
+ if (err.message.includes('fetch')) this.connected = false;
792
1052
  throw err;
793
1053
  }
794
1054
  },
795
1055
 
796
- // --------------------------------------------------------
797
- // Health & Stats
798
- // --------------------------------------------------------
799
- async checkHealth() {
800
- try {
801
- await this.api('GET', '/health');
802
- this.connected = true;
803
- } catch {
804
- this.connected = false;
805
- }
806
- },
1056
+ async checkHealth() { try { await this.api('GET', '/health'); this.connected = true; } catch { this.connected = false; } },
807
1057
 
808
1058
  async loadStats() {
809
1059
  try {
810
1060
  this.stats = await this.api('GET', '/stats');
811
1061
  this.lastRefresh = new Date().toLocaleTimeString();
812
- } catch {
813
- // silent
814
- }
1062
+ } catch {}
1063
+ },
1064
+
1065
+ async loadRecentNeurons() {
1066
+ try {
1067
+ const d = await this.api('GET', '/neurons?limit=5&offset=0');
1068
+ this.recentNeurons = d.neurons || [];
1069
+ } catch { this.recentNeurons = []; }
815
1070
  },
816
1071
 
817
- // --------------------------------------------------------
818
- // Neurons
819
- // --------------------------------------------------------
820
1072
  async loadNeurons() {
821
1073
  this.neuronsLoading = true;
822
1074
  try {
823
- const offset = this.neuronPage * this.neuronLimit;
824
- const data = await this.api('GET', `/neurons?limit=${this.neuronLimit}&offset=${offset}`);
825
- this.neurons = data.neurons || [];
826
- this.neuronTotal = data.total || 0;
827
- } catch {
828
- this.neurons = [];
829
- } finally {
830
- this.neuronsLoading = false;
831
- }
1075
+ const d = await this.api('GET', `/neurons?limit=${this.neuronLimit}&offset=${this.neuronPage * this.neuronLimit}`);
1076
+ this.neurons = d.neurons || [];
1077
+ this.neuronTotal = d.total || 0;
1078
+ } catch { this.neurons = []; }
1079
+ this.neuronsLoading = false;
832
1080
  },
833
1081
 
834
- async selectNeuron(neuron) {
835
- this.confirmDelete = false;
836
- this.selectedContent = '';
837
- this.contentLoading = true;
1082
+ async selectNeuron(n) {
1083
+ this.selectedNeuron = n;
1084
+ this.selectedContent = 'Loading...';
838
1085
  try {
839
- const detail = await this.api('GET', `/neurons/${neuron.id}`);
840
- this.selectedNeuron = detail;
841
- } catch {
842
- this.selectedNeuron = neuron;
843
- }
844
- try {
845
- const contentData = await this.api('GET', `/neurons/${neuron.id}/content`);
846
- this.selectedContent = contentData.content || '';
847
- } catch {
848
- this.selectedContent = '';
849
- } finally {
850
- this.contentLoading = false;
851
- }
1086
+ const d = await this.api('GET', `/neurons/${n.id}/content`);
1087
+ this.selectedContent = d.content || '';
1088
+ } catch { this.selectedContent = 'Failed to load content'; }
852
1089
  },
853
1090
 
854
- async deleteNeuron(id) {
855
- this.deleting = true;
856
- try {
857
- await this.api('DELETE', `/neurons/${id}`);
858
- this.selectedNeuron = null;
859
- this.selectedContent = '';
860
- this.confirmDelete = false;
861
- await this.loadNeurons();
862
- } catch (err) {
863
- alert('Delete failed: ' + err.message);
864
- } finally {
865
- this.deleting = false;
866
- }
1091
+ prevPage() { if (this.neuronPage > 0) { this.neuronPage--; this.loadNeurons(); } },
1092
+ nextPage() { if ((this.neuronPage + 1) * this.neuronLimit < this.neuronTotal) { this.neuronPage++; this.loadNeurons(); } },
1093
+ paginationLabel() {
1094
+ if (this.neuronTotal === 0) return 'No neurons';
1095
+ return `${this.neuronPage * this.neuronLimit + 1}-${Math.min((this.neuronPage + 1) * this.neuronLimit, this.neuronTotal)} of ${this.neuronTotal}`;
867
1096
  },
868
1097
 
869
- prevPage() {
870
- if (this.neuronPage > 0) {
871
- this.neuronPage--;
872
- this.loadNeurons();
873
- }
1098
+ async loadGraph() {
1099
+ try { this.graphData = await this.api('GET', '/graph'); }
1100
+ catch { this.graphData = { nodes: [], edges: [], stats: {} }; }
874
1101
  },
875
1102
 
876
- nextPage() {
877
- if ((this.neuronPage + 1) * this.neuronLimit < this.neuronTotal) {
878
- this.neuronPage++;
879
- this.loadNeurons();
880
- }
1103
+ renderGraph() {
1104
+ const container = document.getElementById('graph-container');
1105
+ const svg = d3.select('#graph-svg');
1106
+ if (!container || !svg.node()) return;
1107
+
1108
+ // Clear previous
1109
+ svg.selectAll('*').remove();
1110
+ if (this.graphSimulation) this.graphSimulation.stop();
1111
+
1112
+ const nodes = this.graphData.nodes || [];
1113
+ const edges = this.graphData.edges || [];
1114
+ if (nodes.length === 0) return;
1115
+
1116
+ const width = container.clientWidth;
1117
+ const height = container.clientHeight;
1118
+ const isDark = this.darkMode;
1119
+
1120
+ // Create node map for edge references
1121
+ const nodeMap = new Map(nodes.map(n => [n.id, n]));
1122
+
1123
+ // Prepare links (D3 needs source/target as node references or ids)
1124
+ const links = edges.map(e => ({
1125
+ source: e.source,
1126
+ target: e.target,
1127
+ weight: e.weight || 0.5,
1128
+ type: e.type || 'SEMANTIC'
1129
+ })).filter(l => nodeMap.has(l.source) && nodeMap.has(l.target));
1130
+
1131
+ // Color scale for edge types
1132
+ const edgeColors = {
1133
+ 'SEMANTIC': '#1976D2',
1134
+ 'CAUSAL': '#2E7D32',
1135
+ 'TEMPORAL': '#ED6C02',
1136
+ 'ASSOCIATIVE': '#9C27B0',
1137
+ 'HIERARCHICAL': '#D32F2F',
1138
+ 'DUPLICATE': '#757575'
1139
+ };
1140
+
1141
+ // Create simulation
1142
+ this.graphSimulation = d3.forceSimulation(nodes)
1143
+ .force('link', d3.forceLink(links).id(d => d.id).distance(80).strength(0.5))
1144
+ .force('charge', d3.forceManyBody().strength(-200))
1145
+ .force('center', d3.forceCenter(width / 2, height / 2))
1146
+ .force('collision', d3.forceCollide().radius(25));
1147
+
1148
+ // Zoom behavior
1149
+ const zoom = d3.zoom()
1150
+ .scaleExtent([0.2, 4])
1151
+ .on('zoom', (event) => g.attr('transform', event.transform));
1152
+ svg.call(zoom);
1153
+
1154
+ // Main group for zoom/pan
1155
+ const g = svg.append('g');
1156
+
1157
+ // Draw edges
1158
+ const link = g.append('g')
1159
+ .selectAll('line')
1160
+ .data(links)
1161
+ .join('line')
1162
+ .attr('stroke', d => edgeColors[d.type] || '#999')
1163
+ .attr('stroke-opacity', 0.6)
1164
+ .attr('stroke-width', d => Math.max(1, d.weight * 3));
1165
+
1166
+ // Draw nodes
1167
+ const node = g.append('g')
1168
+ .selectAll('circle')
1169
+ .data(nodes)
1170
+ .join('circle')
1171
+ .attr('r', 10)
1172
+ .attr('fill', '#1976D2')
1173
+ .attr('stroke', isDark ? '#424242' : '#fff')
1174
+ .attr('stroke-width', 2)
1175
+ .style('cursor', 'pointer')
1176
+ .call(d3.drag()
1177
+ .on('start', (event, d) => {
1178
+ if (!event.active) this.graphSimulation.alphaTarget(0.3).restart();
1179
+ d.fx = d.x; d.fy = d.y;
1180
+ })
1181
+ .on('drag', (event, d) => { d.fx = event.x; d.fy = event.y; })
1182
+ .on('end', (event, d) => {
1183
+ if (!event.active) this.graphSimulation.alphaTarget(0);
1184
+ d.fx = null; d.fy = null;
1185
+ }));
1186
+
1187
+ // Tooltip
1188
+ const tooltip = document.getElementById('graph-tooltip');
1189
+ const tooltipId = document.getElementById('tooltip-id');
1190
+ const tooltipLabel = document.getElementById('tooltip-label');
1191
+
1192
+ node.on('mouseenter', (event, d) => {
1193
+ tooltip.classList.remove('hidden');
1194
+ tooltipId.textContent = d.id.substring(0, 20) + '...';
1195
+ tooltipLabel.textContent = d.label || 'Neuron';
1196
+ })
1197
+ .on('mousemove', (event) => {
1198
+ tooltip.style.left = (event.offsetX + 15) + 'px';
1199
+ tooltip.style.top = (event.offsetY - 10) + 'px';
1200
+ })
1201
+ .on('mouseleave', () => tooltip.classList.add('hidden'));
1202
+
1203
+ // Node labels (short)
1204
+ const labels = g.append('g')
1205
+ .selectAll('text')
1206
+ .data(nodes)
1207
+ .join('text')
1208
+ .text(d => d.id.substring(0, 6))
1209
+ .attr('font-size', '8px')
1210
+ .attr('fill', isDark ? '#E6E1E5' : '#1C1B1F')
1211
+ .attr('text-anchor', 'middle')
1212
+ .attr('dy', 20)
1213
+ .style('pointer-events', 'none');
1214
+
1215
+ // Update positions on tick
1216
+ this.graphSimulation.on('tick', () => {
1217
+ link
1218
+ .attr('x1', d => d.source.x)
1219
+ .attr('y1', d => d.source.y)
1220
+ .attr('x2', d => d.target.x)
1221
+ .attr('y2', d => d.target.y);
1222
+ node.attr('cx', d => d.x).attr('cy', d => d.y);
1223
+ labels.attr('x', d => d.x).attr('y', d => d.y);
1224
+ });
1225
+
1226
+ // Initial zoom to fit
1227
+ setTimeout(() => {
1228
+ const bounds = g.node().getBBox();
1229
+ if (bounds.width > 0 && bounds.height > 0) {
1230
+ const scale = Math.min(width / bounds.width, height / bounds.height) * 0.8;
1231
+ const tx = (width - bounds.width * scale) / 2 - bounds.x * scale;
1232
+ const ty = (height - bounds.height * scale) / 2 - bounds.y * scale;
1233
+ svg.transition().duration(500).call(zoom.transform, d3.zoomIdentity.translate(tx, ty).scale(scale));
1234
+ }
1235
+ }, 500);
881
1236
  },
882
1237
 
883
- paginationLabel() {
884
- const start = this.neuronPage * this.neuronLimit + 1;
885
- const end = Math.min((this.neuronPage + 1) * this.neuronLimit, this.neuronTotal);
886
- return `Showing ${start}-${end} of ${this.neuronTotal}`;
1238
+ async runInference() {
1239
+ if (!this.inferNeuronId) return;
1240
+ this.inferring = true;
1241
+ this.inferResults = null;
1242
+ try {
1243
+ this.inferResults = await this.api('POST', `/inference/${this.inferType}`, {
1244
+ neuronId: this.inferNeuronId,
1245
+ depth: this.inferDepth
1246
+ });
1247
+ } catch (e) { alert(e.message); }
1248
+ this.inferring = false;
1249
+ },
1250
+
1251
+ async loadSyncStatus() {
1252
+ try { this.syncStatus = await this.api('GET', '/sync/status'); } catch {}
887
1253
  },
888
1254
 
889
- // --------------------------------------------------------
890
- // Search
891
- // --------------------------------------------------------
892
1255
  async doSearch() {
893
- if (!this.searchQuery.trim()) return;
1256
+ if (!this.searchQuery) return;
894
1257
  this.searching = true;
895
1258
  this.searchResults = [];
896
- this.searchError = null;
897
- this.searchPerformed = false;
898
1259
  try {
899
- const data = await this.api('POST', '/search', {
1260
+ const d = await this.api('POST', '/search', {
900
1261
  query: this.searchQuery,
901
1262
  k: this.searchK,
902
- includeContent: this.searchIncludeContent,
1263
+ includeContent: this.searchIncludeContent
903
1264
  });
904
- this.searchResults = data.results || [];
905
- this.searchPerformed = true;
906
- } catch (err) {
907
- this.searchError = err.message;
908
- this.searchPerformed = true;
909
- } finally {
910
- this.searching = false;
1265
+ this.searchResults = d.results || [];
1266
+ } catch {}
1267
+ this.searching = false;
1268
+ },
1269
+
1270
+ async doGlobalSearch() {
1271
+ if (this.globalSearch) {
1272
+ this.searchQuery = this.globalSearch;
1273
+ this.activeTab = 'search';
1274
+ await this.doSearch();
911
1275
  }
912
1276
  },
913
1277
 
914
- // --------------------------------------------------------
915
- // Ingest
916
- // --------------------------------------------------------
917
1278
  async doIngest() {
918
- if (!this.ingestText.trim()) return;
1279
+ if (!this.ingestText) return;
919
1280
  this.ingesting = true;
920
1281
  this.ingestResult = null;
921
1282
  this.ingestError = null;
922
1283
  try {
923
- const tags = this.ingestTags
924
- .split(',')
925
- .map(t => t.trim())
926
- .filter(t => t.length > 0);
927
- const data = await this.api('POST', '/ingest', {
1284
+ const tags = this.ingestTags.split(',').map(t => t.trim()).filter(t => t);
1285
+ this.ingestResult = await this.api('POST', '/ingest', {
928
1286
  text: this.ingestText,
929
- sourceType: this.ingestSourceType || 'dashboard',
930
- tags: tags.length > 0 ? tags : undefined,
1287
+ sourceType: this.ingestSourceType,
1288
+ tags
931
1289
  });
932
- this.ingestResult = data;
933
1290
  this.ingestText = '';
934
1291
  this.ingestTags = '';
935
- } catch (err) {
936
- this.ingestError = err.message;
937
- } finally {
938
- this.ingesting = false;
939
- }
1292
+ } catch (e) { this.ingestError = e.message; }
1293
+ this.ingesting = false;
940
1294
  },
941
1295
 
942
- // --------------------------------------------------------
943
- // Verify
944
- // --------------------------------------------------------
945
1296
  async doVerifyAll() {
946
1297
  this.verifying = true;
947
- this.verifyAllResult = null;
948
- try {
949
- this.verifyAllResult = await this.api('GET', '/verify');
950
- } catch (err) {
951
- this.verifyAllResult = { total: 0, valid: 0, invalid: 0, results: [], error: err.message };
952
- } finally {
953
- this.verifying = false;
954
- }
1298
+ try { this.verifyAllResult = await this.api('GET', '/verify'); } catch {}
1299
+ this.verifying = false;
955
1300
  },
956
1301
 
957
1302
  async doVerifySingle() {
958
- if (!this.verifyNeuronId.trim()) return;
1303
+ if (!this.verifyNeuronId) return;
959
1304
  this.verifySingleLoading = true;
960
1305
  this.verifySingleResult = null;
961
- this.verifySingleError = null;
962
- try {
963
- this.verifySingleResult = await this.api('GET', `/verify/${this.verifyNeuronId.trim()}`);
964
- } catch (err) {
965
- this.verifySingleError = err.message;
966
- } finally {
967
- this.verifySingleLoading = false;
968
- }
1306
+ try { this.verifySingleResult = await this.api('GET', `/verify/${this.verifyNeuronId}`); } catch {}
1307
+ this.verifySingleLoading = false;
969
1308
  },
970
1309
 
971
- // --------------------------------------------------------
972
- // Formatters
973
- // --------------------------------------------------------
974
- formatNumber(val) {
975
- if (val === null || val === undefined || val === '--') return '--';
976
- return Number(val).toLocaleString();
1310
+ formatNumber(v) {
1311
+ return v == null || v === '--' ? '0' : Number(v).toLocaleString();
977
1312
  },
978
-
979
- formatBytes(bytes) {
980
- if (bytes === null || bytes === undefined) return '--';
981
- if (bytes === 0) return '0 B';
982
- const units = ['B', 'KB', 'MB', 'GB', 'TB'];
983
- const i = Math.floor(Math.log(bytes) / Math.log(1024));
984
- const val = bytes / Math.pow(1024, i);
985
- return val.toFixed(i === 0 ? 0 : 1) + ' ' + units[i];
986
- },
987
-
988
- formatDate(dateStr) {
989
- if (!dateStr) return '--';
990
- try {
991
- const d = new Date(dateStr);
992
- return d.toLocaleDateString() + ' ' + d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
993
- } catch {
994
- return dateStr;
995
- }
1313
+ formatBytes(b) {
1314
+ if (b == null || b === 0) return '0 B';
1315
+ const u = ['B','KB','MB','GB'];
1316
+ const i = Math.floor(Math.log(b)/Math.log(1024));
1317
+ return (b/Math.pow(1024,i)).toFixed(1) + ' ' + u[i];
996
1318
  },
997
1319
  };
998
1320
  }
999
1321
  </script>
1000
-
1001
1322
  </body>
1002
1323
  </html>