@neuralis/brain-core 0.1.0 → 0.2.1

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 (401) hide show
  1. package/README.md +26 -35
  2. package/app/README.md +1 -1
  3. package/app/cards/DiffView.tsx +9 -7
  4. package/app/cards/README.md +1 -1
  5. package/app/cards/diffLine.tsx +2 -4
  6. package/app/filesystem/README.md +4 -4
  7. package/app/filesystem/api/README.md +3 -3
  8. package/app/filesystem/api/index.ts +137 -123
  9. package/app/filesystem/domain/types.ts +36 -5
  10. package/app/filesystem/hooks/README.md +5 -5
  11. package/app/filesystem/hooks/useDiscoverableSources.ts +4 -2
  12. package/app/filesystem/hooks/useFilesystemSSE.ts +31 -23
  13. package/app/filesystem/hooks/useGitChangesInventory.ts +4 -2
  14. package/app/filesystem/host/README.md +3 -2
  15. package/app/filesystem/host/installFilesystemHostComponents.tsx +22 -9
  16. package/app/filesystem/store/README.md +11 -7
  17. package/app/filesystem/store/filesystemStore.ts +454 -162
  18. package/app/filesystem/store/gitSlice.ts +6 -6
  19. package/app/filesystem/store/listSlice.ts +10 -6
  20. package/app/filesystem/store/searchSlice.ts +27 -4
  21. package/app/filesystem/ui/FileEditor.tsx +48 -35
  22. package/app/filesystem/ui/FileTree.tsx +10 -9
  23. package/app/filesystem/ui/FileTreeSearch.tsx +29 -2
  24. package/app/filesystem/ui/GitCommitChangesView.tsx +5 -3
  25. package/app/filesystem/ui/GitCommitGraph.tsx +6 -5
  26. package/app/filesystem/ui/GitControlPanel.tsx +14 -13
  27. package/app/filesystem/ui/GitDiffView.tsx +2 -1
  28. package/app/filesystem/ui/GitFileDiff.tsx +7 -6
  29. package/app/filesystem/ui/PendingChangesPanel.tsx +88 -28
  30. package/app/filesystem/ui/PendingReviewDialog.tsx +52 -24
  31. package/app/filesystem/ui/README.md +8 -7
  32. package/app/filesystem/ui/ReembedDialog.tsx +22 -9
  33. package/app/filesystem/ui/SourceDeleteConfirm.tsx +1 -1
  34. package/app/filesystem/ui/SourcesPanel.tsx +135 -42
  35. package/app/filesystem/ui/VectorHealthPanel.tsx +20 -4
  36. package/app/filesystem/ui/pendingChangesModel.ts +9 -5
  37. package/dist/app/chunks/{astro-LRAFGXNX.js → astro-B2J4AS2D.js} +1 -1
  38. package/dist/app/chunks/bash-KY6SAQTH.js +1 -0
  39. package/dist/app/chunks/c-OBOPYVZ7.js +1 -0
  40. package/dist/app/chunks/{chunk-5H7ZCOD3.js → chunk-2X3GNKJ3.js} +1 -1
  41. package/dist/app/chunks/{chunk-XIFGTNRM.js → chunk-JPJIVRFI.js} +1 -1
  42. package/dist/app/chunks/{chunk-RH3QY5LF.js → chunk-LEFIFWND.js} +1 -1
  43. package/dist/app/chunks/{chunk-G4RZ3UNX.js → chunk-N6RXX3PH.js} +1 -1
  44. package/dist/app/chunks/{chunk-QXXJ73P5.js → chunk-PZAW4HPB.js} +1 -1
  45. package/dist/app/chunks/{chunk-3QLE7Y4L.js → chunk-ZBYWWTO6.js} +1 -1
  46. package/dist/app/chunks/cpp-TVWVOTEQ.js +1 -0
  47. package/dist/app/chunks/css-MANZBYA4.js +1 -0
  48. package/dist/app/chunks/{elixir-M36XROA6.js → elixir-S725Z7EH.js} +1 -1
  49. package/dist/app/chunks/{elm-7BG6QAIK.js → elm-5WUUSTNB.js} +1 -1
  50. package/dist/app/chunks/graphql-UGOPR3WU.js +1 -0
  51. package/dist/app/chunks/html-F6FWTBSG.js +1 -0
  52. package/dist/app/chunks/java-ANIVV5H5.js +1 -0
  53. package/dist/app/chunks/javascript-IH374YWG.js +1 -0
  54. package/dist/app/chunks/json-WGGVVXSB.js +1 -0
  55. package/dist/app/chunks/jsx-OTXJQD32.js +1 -0
  56. package/dist/app/chunks/{latex-ZWK7SXB6.js → latex-QCZNITGN.js} +1 -1
  57. package/dist/app/chunks/lua-4CRZ64PU.js +1 -0
  58. package/dist/app/chunks/{nginx-2L6VRV3A.js → nginx-V4CYS7WR.js} +1 -1
  59. package/dist/app/chunks/{perl-PBUAXXK6.js → perl-BHTX7F5B.js} +1 -1
  60. package/dist/app/chunks/{php-QJX57PA6.js → php-AYGJ5WYZ.js} +1 -1
  61. package/dist/app/chunks/r-4YFCFA4B.js +1 -0
  62. package/dist/app/chunks/{ruby-RLOWMVPO.js → ruby-42NMJWAL.js} +1 -1
  63. package/dist/app/chunks/{scss-B5CAI3HR.js → scss-XD7VU2CU.js} +1 -1
  64. package/dist/app/chunks/sql-B55MH6JJ.js +1 -0
  65. package/dist/app/chunks/{svelte-GT3D4C44.js → svelte-WR3QPIJU.js} +1 -1
  66. package/dist/app/chunks/tsx-S73GAE2L.js +1 -0
  67. package/dist/app/chunks/typescript-NEWOAB5Z.js +1 -0
  68. package/dist/app/chunks/{vue-JOW62MHD.js → vue-CCDS4VZK.js} +1 -1
  69. package/dist/app/chunks/xml-UXKAGLDR.js +1 -0
  70. package/dist/app/chunks/yaml-UMWKDTK7.js +1 -0
  71. package/dist/app/host.js +46 -46
  72. package/dist/scripts/embeddingLockV3.d.ts +30 -0
  73. package/dist/scripts/embeddingLockV3.d.ts.map +1 -0
  74. package/dist/scripts/embeddingLockV3.js +100 -0
  75. package/dist/scripts/embeddingLockV3.js.map +1 -0
  76. package/dist/scripts/vectorProofV1.d.ts +90 -0
  77. package/dist/scripts/vectorProofV1.d.ts.map +1 -0
  78. package/dist/scripts/vectorProofV1.js +220 -0
  79. package/dist/scripts/vectorProofV1.js.map +1 -0
  80. package/dist/src/config/env.d.ts +21 -0
  81. package/dist/src/config/env.d.ts.map +1 -1
  82. package/dist/src/config/env.js +55 -0
  83. package/dist/src/config/env.js.map +1 -1
  84. package/dist/src/connectors/AppSourceConfigStore.d.ts +12 -2
  85. package/dist/src/connectors/AppSourceConfigStore.d.ts.map +1 -1
  86. package/dist/src/connectors/AppSourceConfigStore.js +48 -40
  87. package/dist/src/connectors/AppSourceConfigStore.js.map +1 -1
  88. package/dist/src/connectors/LocalDiskConnector.d.ts +11 -14
  89. package/dist/src/connectors/LocalDiskConnector.d.ts.map +1 -1
  90. package/dist/src/connectors/LocalDiskConnector.js +87 -107
  91. package/dist/src/connectors/LocalDiskConnector.js.map +1 -1
  92. package/dist/src/connectors/sourceConfigMutation.d.ts +11 -1
  93. package/dist/src/connectors/sourceConfigMutation.d.ts.map +1 -1
  94. package/dist/src/connectors/sourceConfigMutation.js +36 -3
  95. package/dist/src/connectors/sourceConfigMutation.js.map +1 -1
  96. package/dist/src/domain/chunker.js +8 -3
  97. package/dist/src/domain/chunker.js.map +1 -1
  98. package/dist/src/domain/healthTypes.d.ts +11 -0
  99. package/dist/src/domain/healthTypes.d.ts.map +1 -1
  100. package/dist/src/domain/mime.d.ts +1 -0
  101. package/dist/src/domain/mime.d.ts.map +1 -1
  102. package/dist/src/domain/mime.js +48 -0
  103. package/dist/src/domain/mime.js.map +1 -1
  104. package/dist/src/domain/pendingChange.d.ts +7 -0
  105. package/dist/src/domain/pendingChange.d.ts.map +1 -1
  106. package/dist/src/domain/pendingChange.js +11 -0
  107. package/dist/src/domain/pendingChange.js.map +1 -1
  108. package/dist/src/domain/sourceConfig.d.ts +7 -14
  109. package/dist/src/domain/sourceConfig.d.ts.map +1 -1
  110. package/dist/src/domain/sourceConfig.js +1 -13
  111. package/dist/src/domain/sourceConfig.js.map +1 -1
  112. package/dist/src/domain/sourcePackages.d.ts +11 -2
  113. package/dist/src/domain/sourcePackages.d.ts.map +1 -1
  114. package/dist/src/domain/syncTrigger.d.ts +2 -3
  115. package/dist/src/domain/syncTrigger.d.ts.map +1 -1
  116. package/dist/src/domain/syncTrigger.js +2 -3
  117. package/dist/src/domain/syncTrigger.js.map +1 -1
  118. package/dist/src/domain/syncTypes.d.ts +21 -4
  119. package/dist/src/domain/syncTypes.d.ts.map +1 -1
  120. package/dist/src/domain/syncTypes.js.map +1 -1
  121. package/dist/src/domain/text.d.ts +3 -0
  122. package/dist/src/domain/text.d.ts.map +1 -1
  123. package/dist/src/domain/text.js +5 -0
  124. package/dist/src/domain/text.js.map +1 -1
  125. package/dist/src/domain/types.d.ts +9 -0
  126. package/dist/src/domain/types.d.ts.map +1 -1
  127. package/dist/src/embeddings/clients/GeminiEmbedder.d.ts.map +1 -1
  128. package/dist/src/embeddings/clients/GeminiEmbedder.js +11 -5
  129. package/dist/src/embeddings/clients/GeminiEmbedder.js.map +1 -1
  130. package/dist/src/embeddings/clients/OllamaEmbedder.d.ts.map +1 -1
  131. package/dist/src/embeddings/clients/OllamaEmbedder.js +13 -6
  132. package/dist/src/embeddings/clients/OllamaEmbedder.js.map +1 -1
  133. package/dist/src/embeddings/clients/OpenAIEmbedder.d.ts.map +1 -1
  134. package/dist/src/embeddings/clients/OpenAIEmbedder.js +12 -9
  135. package/dist/src/embeddings/clients/OpenAIEmbedder.js.map +1 -1
  136. package/dist/src/embeddings/clients/QwenEmbedder.d.ts.map +1 -1
  137. package/dist/src/embeddings/clients/QwenEmbedder.js +12 -5
  138. package/dist/src/embeddings/clients/QwenEmbedder.js.map +1 -1
  139. package/dist/src/embeddings/clients/VoyageEmbedder.d.ts.map +1 -1
  140. package/dist/src/embeddings/clients/VoyageEmbedder.js +12 -5
  141. package/dist/src/embeddings/clients/VoyageEmbedder.js.map +1 -1
  142. package/dist/src/embeddings/factory.d.ts +2 -0
  143. package/dist/src/embeddings/factory.d.ts.map +1 -1
  144. package/dist/src/embeddings/factory.js +23 -3
  145. package/dist/src/embeddings/factory.js.map +1 -1
  146. package/dist/src/embeddings/lock.d.ts +22 -11
  147. package/dist/src/embeddings/lock.d.ts.map +1 -1
  148. package/dist/src/embeddings/lock.js +47 -29
  149. package/dist/src/embeddings/lock.js.map +1 -1
  150. package/dist/src/embeddings/retry.d.ts +5 -0
  151. package/dist/src/embeddings/retry.d.ts.map +1 -1
  152. package/dist/src/embeddings/retry.js +35 -0
  153. package/dist/src/embeddings/retry.js.map +1 -1
  154. package/dist/src/events/pending.d.ts +56 -0
  155. package/dist/src/events/pending.d.ts.map +1 -0
  156. package/dist/src/events/pending.js +108 -0
  157. package/dist/src/events/pending.js.map +1 -0
  158. package/dist/src/events/source.d.ts +60 -14
  159. package/dist/src/events/source.d.ts.map +1 -1
  160. package/dist/src/events/source.js +149 -31
  161. package/dist/src/events/source.js.map +1 -1
  162. package/dist/src/events/vector.d.ts +33 -0
  163. package/dist/src/events/vector.d.ts.map +1 -0
  164. package/dist/src/events/vector.js +57 -0
  165. package/dist/src/events/vector.js.map +1 -0
  166. package/dist/src/git/GitRunner.d.ts.map +1 -1
  167. package/dist/src/git/GitRunner.js +11 -8
  168. package/dist/src/git/GitRunner.js.map +1 -1
  169. package/dist/src/git/sourceGitControl.d.ts.map +1 -1
  170. package/dist/src/git/sourceGitControl.js +2 -1
  171. package/dist/src/git/sourceGitControl.js.map +1 -1
  172. package/dist/src/index.d.ts +5 -4
  173. package/dist/src/index.d.ts.map +1 -1
  174. package/dist/src/index.js +4 -3
  175. package/dist/src/index.js.map +1 -1
  176. package/dist/src/lifecycle.d.ts +20 -4
  177. package/dist/src/lifecycle.d.ts.map +1 -1
  178. package/dist/src/lifecycle.js +5 -1
  179. package/dist/src/lifecycle.js.map +1 -1
  180. package/dist/src/routes/health.js +6 -1
  181. package/dist/src/routes/health.js.map +1 -1
  182. package/dist/src/routes/pending.d.ts.map +1 -1
  183. package/dist/src/routes/pending.js +2 -1
  184. package/dist/src/routes/pending.js.map +1 -1
  185. package/dist/src/routes/sources.d.ts.map +1 -1
  186. package/dist/src/routes/sources.js +60 -11
  187. package/dist/src/routes/sources.js.map +1 -1
  188. package/dist/src/services/BridgeService.d.ts +2 -2
  189. package/dist/src/services/BridgeService.d.ts.map +1 -1
  190. package/dist/src/services/BridgeService.js +11 -2
  191. package/dist/src/services/BridgeService.js.map +1 -1
  192. package/dist/src/services/FilesystemService.d.ts +3 -1
  193. package/dist/src/services/FilesystemService.d.ts.map +1 -1
  194. package/dist/src/services/FilesystemService.js +3 -1
  195. package/dist/src/services/FilesystemService.js.map +1 -1
  196. package/dist/src/services/FilesystemUiService.js +1 -1
  197. package/dist/src/services/FilesystemUiService.js.map +1 -1
  198. package/dist/src/services/SyncScheduler.d.ts.map +1 -1
  199. package/dist/src/services/SyncScheduler.js +0 -14
  200. package/dist/src/services/SyncScheduler.js.map +1 -1
  201. package/dist/src/services/VectorHealthService.d.ts.map +1 -1
  202. package/dist/src/services/VectorHealthService.js +2 -46
  203. package/dist/src/services/VectorHealthService.js.map +1 -1
  204. package/dist/src/services/baselineRepair.d.ts +2 -2
  205. package/dist/src/services/baselineRepair.js +2 -2
  206. package/dist/src/services/declaredSources.d.ts +8 -1
  207. package/dist/src/services/declaredSources.d.ts.map +1 -1
  208. package/dist/src/services/declaredSources.js +19 -19
  209. package/dist/src/services/declaredSources.js.map +1 -1
  210. package/dist/src/store/dataFormats.d.ts +14 -3
  211. package/dist/src/store/dataFormats.d.ts.map +1 -1
  212. package/dist/src/store/dataFormats.js +15 -5
  213. package/dist/src/store/dataFormats.js.map +1 -1
  214. package/dist/src/sync/DeltaSyncRunner.d.ts.map +1 -1
  215. package/dist/src/sync/DeltaSyncRunner.js +78 -243
  216. package/dist/src/sync/DeltaSyncRunner.js.map +1 -1
  217. package/dist/src/sync/SyncJobQueue.d.ts +33 -4
  218. package/dist/src/sync/SyncJobQueue.d.ts.map +1 -1
  219. package/dist/src/sync/SyncJobQueue.js +179 -19
  220. package/dist/src/sync/SyncJobQueue.js.map +1 -1
  221. package/dist/src/sync/moveDetector.d.ts +2 -1
  222. package/dist/src/sync/moveDetector.d.ts.map +1 -1
  223. package/dist/src/sync/moveDetector.js +2 -1
  224. package/dist/src/sync/moveDetector.js.map +1 -1
  225. package/dist/src/tools/fs_search.d.ts.map +1 -1
  226. package/dist/src/tools/fs_search.js +8 -0
  227. package/dist/src/tools/fs_search.js.map +1 -1
  228. package/dist/src/tools/fs_write.js +3 -1
  229. package/dist/src/tools/fs_write.js.map +1 -1
  230. package/dist/src/usecases/chunkUpsert.d.ts +4 -0
  231. package/dist/src/usecases/chunkUpsert.d.ts.map +1 -1
  232. package/dist/src/usecases/chunkUpsert.js +103 -60
  233. package/dist/src/usecases/chunkUpsert.js.map +1 -1
  234. package/dist/src/usecases/embeddingBacklog.d.ts +31 -0
  235. package/dist/src/usecases/embeddingBacklog.d.ts.map +1 -0
  236. package/dist/src/usecases/embeddingBacklog.js +244 -0
  237. package/dist/src/usecases/embeddingBacklog.js.map +1 -0
  238. package/dist/src/usecases/listSourcePackages.js +17 -1
  239. package/dist/src/usecases/listSourcePackages.js.map +1 -1
  240. package/dist/src/usecases/mediaLane.d.ts +11 -4
  241. package/dist/src/usecases/mediaLane.d.ts.map +1 -1
  242. package/dist/src/usecases/mediaLane.js +67 -30
  243. package/dist/src/usecases/mediaLane.js.map +1 -1
  244. package/dist/src/usecases/pendingReview.d.ts.map +1 -1
  245. package/dist/src/usecases/pendingReview.js +24 -7
  246. package/dist/src/usecases/pendingReview.js.map +1 -1
  247. package/dist/src/usecases/purgeExcludedPoints.d.ts +2 -0
  248. package/dist/src/usecases/purgeExcludedPoints.d.ts.map +1 -1
  249. package/dist/src/usecases/purgeExcludedPoints.js +3 -2
  250. package/dist/src/usecases/purgeExcludedPoints.js.map +1 -1
  251. package/dist/src/usecases/readFiles.d.ts.map +1 -1
  252. package/dist/src/usecases/readFiles.js +33 -6
  253. package/dist/src/usecases/readFiles.js.map +1 -1
  254. package/dist/src/usecases/reconcileSourcePackageRoots.d.ts +31 -0
  255. package/dist/src/usecases/reconcileSourcePackageRoots.d.ts.map +1 -0
  256. package/dist/src/usecases/reconcileSourcePackageRoots.js +114 -0
  257. package/dist/src/usecases/reconcileSourcePackageRoots.js.map +1 -0
  258. package/dist/src/usecases/searchFiles.d.ts.map +1 -1
  259. package/dist/src/usecases/searchFiles.js +62 -64
  260. package/dist/src/usecases/searchFiles.js.map +1 -1
  261. package/dist/src/usecases/syncIndexedFile.d.ts +42 -0
  262. package/dist/src/usecases/syncIndexedFile.d.ts.map +1 -0
  263. package/dist/src/usecases/syncIndexedFile.js +242 -0
  264. package/dist/src/usecases/syncIndexedFile.js.map +1 -0
  265. package/dist/src/usecases/syncPointWrites.d.ts +5 -0
  266. package/dist/src/usecases/syncPointWrites.d.ts.map +1 -1
  267. package/dist/src/usecases/syncPointWrites.js +32 -5
  268. package/dist/src/usecases/syncPointWrites.js.map +1 -1
  269. package/dist/src/usecases/uploadBinary.d.ts.map +1 -1
  270. package/dist/src/usecases/uploadBinary.js +36 -49
  271. package/dist/src/usecases/uploadBinary.js.map +1 -1
  272. package/dist/src/usecases/vector/endpointGuard.js +2 -1
  273. package/dist/src/usecases/vector/endpointGuard.js.map +1 -1
  274. package/dist/src/usecases/vector/estimate.d.ts +7 -4
  275. package/dist/src/usecases/vector/estimate.d.ts.map +1 -1
  276. package/dist/src/usecases/vector/estimate.js +8 -5
  277. package/dist/src/usecases/vector/estimate.js.map +1 -1
  278. package/dist/src/usecases/vector/rebuildGeneration.d.ts +29 -5
  279. package/dist/src/usecases/vector/rebuildGeneration.d.ts.map +1 -1
  280. package/dist/src/usecases/vector/rebuildGeneration.js +224 -82
  281. package/dist/src/usecases/vector/rebuildGeneration.js.map +1 -1
  282. package/dist/src/usecases/vectorMaintenance.d.ts +46 -4
  283. package/dist/src/usecases/vectorMaintenance.d.ts.map +1 -1
  284. package/dist/src/usecases/vectorMaintenance.js +190 -11
  285. package/dist/src/usecases/vectorMaintenance.js.map +1 -1
  286. package/dist/src/usecases/write/commit.d.ts +6 -8
  287. package/dist/src/usecases/write/commit.d.ts.map +1 -1
  288. package/dist/src/usecases/write/commit.js +96 -112
  289. package/dist/src/usecases/write/commit.js.map +1 -1
  290. package/dist/src/usecases/write/content.js +1 -2
  291. package/dist/src/usecases/write/content.js.map +1 -1
  292. package/dist/src/usecases/write/ports.d.ts +1 -0
  293. package/dist/src/usecases/write/ports.d.ts.map +1 -1
  294. package/dist/src/vector/FilesystemVectorIndex.d.ts +34 -3
  295. package/dist/src/vector/FilesystemVectorIndex.d.ts.map +1 -1
  296. package/dist/src/vector/FilesystemVectorIndex.js +254 -20
  297. package/dist/src/vector/FilesystemVectorIndex.js.map +1 -1
  298. package/dist/src/vector/InMemoryVectorIndex.d.ts +9 -2
  299. package/dist/src/vector/InMemoryVectorIndex.d.ts.map +1 -1
  300. package/dist/src/vector/InMemoryVectorIndex.js +25 -6
  301. package/dist/src/vector/InMemoryVectorIndex.js.map +1 -1
  302. package/dist/src/vector/QdrantVectorIndex.d.ts +35 -9
  303. package/dist/src/vector/QdrantVectorIndex.d.ts.map +1 -1
  304. package/dist/src/vector/QdrantVectorIndex.js +209 -90
  305. package/dist/src/vector/QdrantVectorIndex.js.map +1 -1
  306. package/dist/src/vector/qdrantFilter.d.ts +3 -1
  307. package/dist/src/vector/qdrantFilter.d.ts.map +1 -1
  308. package/dist/src/vector/qdrantFilter.js +2 -0
  309. package/dist/src/vector/qdrantFilter.js.map +1 -1
  310. package/dist/src/vector/types.d.ts +81 -0
  311. package/dist/src/vector/types.d.ts.map +1 -1
  312. package/dist/src/vector/types.js +2 -0
  313. package/dist/src/vector/types.js.map +1 -1
  314. package/dist/src/wiring.d.ts +6 -0
  315. package/dist/src/wiring.d.ts.map +1 -1
  316. package/dist/src/wiring.js +62 -3
  317. package/dist/src/wiring.js.map +1 -1
  318. package/dist/tools/fs_search.json +2 -2
  319. package/docs/drive-overview.md +2 -2
  320. package/instructions/brain-model.md +1 -1
  321. package/package.json +1000 -11
  322. package/rules/brain-rules.md +1 -1
  323. package/skills/connect-business-data/SKILL.md +6 -4
  324. package/skills/create-package/SKILL.md +14 -12
  325. package/skills/create-package/references/config-and-credentials.md +3 -3
  326. package/skills/create-package/references/connectors-and-uri-policies.md +5 -3
  327. package/skills/create-package/references/manifest-and-discovery.md +5 -4
  328. package/skills/create-package/references/runtime-and-build.md +9 -9
  329. package/skills/create-package/references/skills-and-context.md +3 -3
  330. package/skills/create-package/references/surfaces-and-design.md +9 -6
  331. package/skills/create-package/references/team-and-workflows.md +2 -2
  332. package/skills/create-package/references/test-and-ship.md +15 -15
  333. package/skills/create-package/references/tools-and-schemas.md +1 -1
  334. package/skills/create-package/scripts/check-package.sh +50 -4
  335. package/skills/create-package/scripts/verify-loaded.sh +16 -16
  336. package/skills/manage-files/SKILL.md +2 -2
  337. package/skills/manage-sources/SKILL.md +16 -15
  338. package/skills/manage-sources/scripts/reembed.sh +9 -3
  339. package/skills/sync/SKILL.md +4 -4
  340. package/tools/fs_search.json +2 -2
  341. package/app/filesystem/hooks/useContainerWidth.ts +0 -39
  342. package/dist/app/chunks/bash-M45GHPBQ.js +0 -1
  343. package/dist/app/chunks/c-X3REOAWD.js +0 -1
  344. package/dist/app/chunks/cpp-VOWI743W.js +0 -1
  345. package/dist/app/chunks/css-2ZVPHE25.js +0 -1
  346. package/dist/app/chunks/graphql-7V2NP54C.js +0 -1
  347. package/dist/app/chunks/html-UF3LFLNA.js +0 -1
  348. package/dist/app/chunks/java-PNTAU4L3.js +0 -1
  349. package/dist/app/chunks/javascript-4JJTQGEL.js +0 -1
  350. package/dist/app/chunks/json-VLQ6D3JH.js +0 -1
  351. package/dist/app/chunks/jsx-KQKSLAAH.js +0 -1
  352. package/dist/app/chunks/lua-UFPYUJ2O.js +0 -1
  353. package/dist/app/chunks/r-QEZB45SR.js +0 -1
  354. package/dist/app/chunks/sql-DTZHNUZP.js +0 -1
  355. package/dist/app/chunks/tsx-WPR2WRZD.js +0 -1
  356. package/dist/app/chunks/typescript-LWO362OA.js +0 -1
  357. package/dist/app/chunks/xml-A5H72RTS.js +0 -1
  358. package/dist/app/chunks/yaml-MXHSIJCI.js +0 -1
  359. package/dist/src/services/purgePendingNodes.d.ts +0 -32
  360. package/dist/src/services/purgePendingNodes.d.ts.map +0 -1
  361. package/dist/src/services/purgePendingNodes.js +0 -61
  362. package/dist/src/services/purgePendingNodes.js.map +0 -1
  363. /package/dist/app/chunks/{chunk-737Y24HS.js → chunk-3JASFUPF.js} +0 -0
  364. /package/dist/app/chunks/{chunk-DKD2L57N.js → chunk-6EYLOQ4F.js} +0 -0
  365. /package/dist/app/chunks/{chunk-KYH5EHHY.js → chunk-7YRZ5LOQ.js} +0 -0
  366. /package/dist/app/chunks/{chunk-6TC3DVWV.js → chunk-C7LU4RID.js} +0 -0
  367. /package/dist/app/chunks/{chunk-TY33BMKR.js → chunk-CD52YDZP.js} +0 -0
  368. /package/dist/app/chunks/{chunk-OLEIKJ3X.js → chunk-DCJKTCJ5.js} +0 -0
  369. /package/dist/app/chunks/{chunk-QLBZ4JR2.js → chunk-EXIU2KBV.js} +0 -0
  370. /package/dist/app/chunks/{chunk-SFUNBBEA.js → chunk-FDP4LO4P.js} +0 -0
  371. /package/dist/app/chunks/{chunk-BGRVFATT.js → chunk-HNETUS7U.js} +0 -0
  372. /package/dist/app/chunks/{chunk-4QNMHAIR.js → chunk-LBFZJEDR.js} +0 -0
  373. /package/dist/app/chunks/{chunk-TRRUHDPN.js → chunk-ULRXL5VM.js} +0 -0
  374. /package/dist/app/chunks/{chunk-S6B4WWIF.js → chunk-XJK47SMJ.js} +0 -0
  375. /package/dist/app/chunks/{chunk-DZ5C5FKI.js → chunk-YYAAIAU2.js} +0 -0
  376. /package/dist/app/chunks/{clojure-OC6KPSJO.js → clojure-4QCN4GHG.js} +0 -0
  377. /package/dist/app/chunks/{core-KGE7TQJ3.js → core-ZHTX3P2Q.js} +0 -0
  378. /package/dist/app/chunks/{csharp-E7VIFITL.js → csharp-HQWR4N52.js} +0 -0
  379. /package/dist/app/chunks/{dark-plus-BOSCZXE4.js → dark-plus-GYPKKZES.js} +0 -0
  380. /package/dist/app/chunks/{dart-6Y3X27SZ.js → dart-FO4TTVO2.js} +0 -0
  381. /package/dist/app/chunks/{diff-TR2NPA64.js → diff-SHANV4YC.js} +0 -0
  382. /package/dist/app/chunks/{dist-T32U2VVR.js → dist-WSDF34DM.js} +0 -0
  383. /package/dist/app/chunks/{docker-N33HOW54.js → docker-VX55HTDS.js} +0 -0
  384. /package/dist/app/chunks/{go-6DGG5UTP.js → go-5UCPEC6S.js} +0 -0
  385. /package/dist/app/chunks/{haskell-KK36PMMM.js → haskell-25PJ3OSG.js} +0 -0
  386. /package/dist/app/chunks/{ini-VHVQ5TPB.js → ini-BJIVD5MK.js} +0 -0
  387. /package/dist/app/chunks/{kotlin-44WS3JHE.js → kotlin-MNR6XOEQ.js} +0 -0
  388. /package/dist/app/chunks/{less-5WZ3KLAK.js → less-KA5JURX6.js} +0 -0
  389. /package/dist/app/chunks/{light-plus-HGGBC43G.js → light-plus-QXH2UUWZ.js} +0 -0
  390. /package/dist/app/chunks/{make-X7RXMVW7.js → make-LPD5KOCO.js} +0 -0
  391. /package/dist/app/chunks/{markdown-46IKUAIB.js → markdown-LMWF6MQR.js} +0 -0
  392. /package/dist/app/chunks/{mdx-DGLHDAO7.js → mdx-WPMNN5BS.js} +0 -0
  393. /package/dist/app/chunks/{nix-Q6FYQZLX.js → nix-QGWLUUMZ.js} +0 -0
  394. /package/dist/app/chunks/{powershell-L4KJJ6DK.js → powershell-7GSBBEFF.js} +0 -0
  395. /package/dist/app/chunks/{prisma-IKS4LVH2.js → prisma-FPMPQISO.js} +0 -0
  396. /package/dist/app/chunks/{proto-AYCDOTJO.js → proto-7KDX5Z2U.js} +0 -0
  397. /package/dist/app/chunks/{python-KXMCSAFQ.js → python-CFG4FTQW.js} +0 -0
  398. /package/dist/app/chunks/{rust-J3BC3P6V.js → rust-X7A37WU3.js} +0 -0
  399. /package/dist/app/chunks/{scala-AYIIHBJK.js → scala-OYHJSUG2.js} +0 -0
  400. /package/dist/app/chunks/{swift-QPHHCQD3.js → swift-PE7VNYW5.js} +0 -0
  401. /package/dist/app/chunks/{toml-UV7JK7K7.js → toml-ETQRDILP.js} +0 -0
@@ -44,6 +44,7 @@ import {
44
44
  type IndexPurgeSelector,
45
45
  cancelSync,
46
46
  getSyncStatus,
47
+ startReembed,
47
48
  resetSync,
48
49
  browseDirectories,
49
50
  listSourceKinds,
@@ -70,6 +71,7 @@ import type {
70
71
  HierarchicalPermissionsRecord,
71
72
  PathPermissionRecord,
72
73
  SyncMediaRecord,
74
+ SyncJobSnapshotRecord,
73
75
  } from '../domain/types';
74
76
 
75
77
  type Props = {
@@ -113,7 +115,7 @@ type AddDraftState = {
113
115
  * in the Policy editor after saving.
114
116
  */
115
117
  policies: PathPermissionRecord[];
116
- /** R2b — create this local source as a WASM-package source (owner/admin). */
118
+ /** R2b — create this local source as a package source too (owner/admin). */
117
119
  recognizesPackages: boolean;
118
120
  };
119
121
 
@@ -329,6 +331,26 @@ function mediaSkipLine(skipped: { textOnlyModel: number; off: number; tooLarge:
329
331
  return parts.length > 0 ? parts.join(' · ') : null;
330
332
  }
331
333
 
334
+ /**
335
+ * The source's semantic-embedding line, or `null` when nothing is owed.
336
+ * OFF is the platform's LIVE intent (`embedding_enabled`), never a last pass's
337
+ * echo — a watcher pass that changed nothing must not erase it. Off is a
338
+ * choice, said neutrally. The last pass's OTHER reasons (`quota`,
339
+ * `credentials`, …) are owed work and read amber. The data landed either way.
340
+ */
341
+ export function embeddingLine(reasons: string[] | undefined, enabled: boolean | undefined): { text: string; attention: boolean } | null {
342
+ if (enabled === false) return { text: 'Semantic embedding off — text and field search only', attention: false };
343
+ const owed = (reasons ?? []).filter((reason) => reason !== 'disabled');
344
+ if (owed.length === 0) return null;
345
+ return { text: `Semantic embedding pending: ${owed.join(', ')} — files are indexed and text-searchable`, attention: true };
346
+ }
347
+
348
+ /** The last run's binary line, or `null` when none was skipped. */
349
+ export function binarySkipLine(count: number | undefined): string | null {
350
+ if (!count) return null;
351
+ return `${count} binary file${count === 1 ? '' : 's'} not indexed`;
352
+ }
353
+
332
354
  /**
333
355
  * Does this save change what the row's NUMBERS would report?
334
356
  *
@@ -448,6 +470,7 @@ const textareaCls = cn(
448
470
  // ---------------------------------------------------------------------------
449
471
 
450
472
  export function SourcesPanel(props: Props) {
473
+ const client = useFilesystemStore((s) => s.client);
451
474
  const { agentId, projectId, isDocker } = props;
452
475
  const open = useFilesystemStore((s) => s.workspacePanels.sources);
453
476
  const setWorkspacePanelOpen = useFilesystemStore((s) => s.setWorkspacePanelOpen);
@@ -507,6 +530,10 @@ export function SourcesPanel(props: Props) {
507
530
  const [resettingSource, setResettingSource] = useState<string | null>(null);
508
531
  /** Source whose "Re-embed…" dialog is open (estimate → confirm). */
509
532
  const [reembedFor, setReembedFor] = useState<string | null>(null);
533
+ /** Source whose "Embed pending…" dialog is open (estimate → confirm). */
534
+ const [embedPendingFor, setEmbedPendingFor] = useState<string | null>(null);
535
+ /** An embedding-only pass that ended `paused`, by source → its reason (cleared on Resume). */
536
+ const [embeddingPaused, setEmbeddingPaused] = useState<Record<string, string>>({});
510
537
  const [purgeFor, setPurgeFor] = useState<string | null>(null);
511
538
  const [purgeKind, setPurgeKind] = useState<'source' | 'folder' | 'file'>('source');
512
539
  const [purgeUri, setPurgeUri] = useState('');
@@ -531,7 +558,8 @@ export function SourcesPanel(props: Props) {
531
558
  return () => { mountedRef.current = false; };
532
559
  }, []);
533
560
  const [addCreating, setAddCreating] = useState(false);
534
- const [healthOpen, setHealthOpen] = useState(false);
561
+ const healthOpen = useFilesystemStore((s) => s.vectorHealthOpen);
562
+ const setVectorHealthOpen = useFilesystemStore((s) => s.setVectorHealthOpen);
535
563
  const [mountOpen, setMountOpen] = useState(false);
536
564
  const [browseOpen, setBrowseOpen] = useState(false);
537
565
  const [browseEntries, setBrowseEntries] = useState<Array<{ name: string; path: string }>>([]);
@@ -550,7 +578,7 @@ export function SourcesPanel(props: Props) {
550
578
  // schema-driven picker (replacing the old hardcoded KIND_META).
551
579
  useEffect(() => {
552
580
  let cancelled = false;
553
- listSourceKinds()
581
+ listSourceKinds(client)
554
582
  .then((res) => {
555
583
  if (cancelled) return;
556
584
  setKinds(res.kinds ?? []);
@@ -677,8 +705,8 @@ export function SourcesPanel(props: Props) {
677
705
  agentId,
678
706
  projectId,
679
707
  scope: activeScope,
680
- }),
681
- listDiscoverableSources({ agentId, projectId })
708
+ }, client),
709
+ listDiscoverableSources({ agentId, projectId }, client)
682
710
  .catch(() => ({ suggestions: [] as DiscoverableSourceSuggestion[] })),
683
711
  ]);
684
712
  setConfigs(next);
@@ -719,7 +747,7 @@ export function SourcesPanel(props: Props) {
719
747
  });
720
748
  if (alreadyLoading) return;
721
749
  try {
722
- const info = await fetchSourceCounts(agentId, projectId ?? undefined, source);
750
+ const info = await fetchSourceCounts(agentId, projectId ?? undefined, source, client);
723
751
  if (info) setCountsBySource((prev) => ({ ...prev, [source]: info }));
724
752
  } catch {
725
753
  // Count failure is non-fatal — the row still works, the stats row just stays blank.
@@ -766,7 +794,7 @@ export function SourcesPanel(props: Props) {
766
794
  useEffect(() => {
767
795
  if (!showAddForm || !isDocker || !canMount) return;
768
796
  setDockerMountsLoading(true);
769
- browseDirectories({ path: '/mounts', agentId, ...(projectId ? { projectId } : {}) })
797
+ browseDirectories({ path: '/mounts', agentId, ...(projectId ? { projectId } : {}) }, client)
770
798
  .then((result) => {
771
799
  // Filter out volumes already configured as sources
772
800
  const configuredSources = new Set(configs.map((c) => c.source));
@@ -878,7 +906,7 @@ export function SourcesPanel(props: Props) {
878
906
  agentId,
879
907
  ...(projectId ? { projectId } : {}),
880
908
  config: { ...payload, ...(clearSync ? { clearSync: true } : {}) },
881
- });
909
+ }, client);
882
910
  setConfigs((s) => s.map((e) => (e.source === updated.source ? updated : e)));
883
911
  setDrafts((s) => ({ ...s, [updated.source]: buildDraft(updated) }));
884
912
  // Counted refresh ONLY when the save moved the sync FILTER set — that is
@@ -916,7 +944,7 @@ export function SourcesPanel(props: Props) {
916
944
  agentId,
917
945
  ...(projectId ? { projectId } : {}),
918
946
  config: { ...currentDraft, permissions: nextPerms },
919
- });
947
+ }, client);
920
948
  setConfigs((s) => s.map((e) => (e.source === updated.source ? updated : e)));
921
949
  setDrafts((s) => ({ ...s, [updated.source]: buildDraft(updated) }));
922
950
  // A permissions edit moves no number: the indexed count is a
@@ -939,7 +967,7 @@ export function SourcesPanel(props: Props) {
939
967
  * pending/running so the row spinner reflects the real run (Cancel stays
940
968
  * available the whole time), then surface a failed job's error.
941
969
  */
942
- const pollSyncJob = useCallback(async (source: string): Promise<void> => {
970
+ const pollSyncJob = useCallback(async (source: string): Promise<SyncJobSnapshotRecord | null> => {
943
971
  const POLL_MS = 1_500;
944
972
  const MAX_POLLS = 2_400; // 60 min safety bound — repo-sized syncs are long
945
973
  for (let i = 0; i < MAX_POLLS; i++) {
@@ -949,16 +977,18 @@ export function SourcesPanel(props: Props) {
949
977
  // wanted the answer had unmounted — once per sync, per source. The ref
950
978
  // is cleared on UNMOUNT ONLY (never in a dependency-change cleanup), so a
951
979
  // live poll is never dropped while the panel is still mounted.
952
- if (!mountedRef.current) return;
953
- const status = await getSyncStatus({ agentId, ...(projectId ? { projectId } : {}), source });
980
+ if (!mountedRef.current) return null;
981
+ const status = await getSyncStatus({ agentId, ...(projectId ? { projectId } : {}), source }, client);
954
982
  const job = status.job;
955
- if (!job) return;
983
+ if (!job) return null;
956
984
  if (job.status === 'pending' || job.status === 'running') continue;
957
985
  if (job.status === 'failed') {
958
986
  throw new Error(job.error ?? job.result?.error ?? 'Sync failed');
959
987
  }
960
- return;
988
+ // `paused` is terminal, not a failure: an embedding-only pass names why.
989
+ return job;
961
990
  }
991
+ return null;
962
992
  }, [agentId, projectId]);
963
993
 
964
994
  // EVERY hook is above this line. It used to sit ~110 lines higher, with
@@ -976,7 +1006,7 @@ export function SourcesPanel(props: Props) {
976
1006
  setSyncingSource(source);
977
1007
  setError(null);
978
1008
  try {
979
- await triggerSourceSync({ agentId, ...(projectId ? { projectId } : {}), source });
1009
+ await triggerSourceSync({ agentId, ...(projectId ? { projectId } : {}), source }, client);
980
1010
  await pollSyncJob(source);
981
1011
  await load();
982
1012
  await refresh({ agentId, projectId, withCounts: true });
@@ -990,7 +1020,7 @@ export function SourcesPanel(props: Props) {
990
1020
 
991
1021
  const handleCancelSync = async (source?: string) => {
992
1022
  try {
993
- await cancelSync({ agentId, ...(projectId ? { projectId } : {}), ...(source ? { source } : {}) });
1023
+ await cancelSync({ agentId, ...(projectId ? { projectId } : {}), ...(source ? { source } : {}) }, client);
994
1024
  // The polling loop in handleSync/handleReindex observes the cancelled
995
1025
  // status and clears the spinner; clear eagerly for instant feedback.
996
1026
  setSyncingSource(null);
@@ -1009,7 +1039,12 @@ export function SourcesPanel(props: Props) {
1009
1039
  setError(null);
1010
1040
  try {
1011
1041
  await enqueue();
1012
- await pollSyncJob(source);
1042
+ const job = await pollSyncJob(source);
1043
+ const paused = job?.status === 'paused' ? job.result?.embedding?.pausedReason ?? 'paused' : null;
1044
+ setEmbeddingPaused((prev) => {
1045
+ const { [source]: _previous, ...rest } = prev;
1046
+ return paused ? { ...rest, [source]: paused } : rest;
1047
+ });
1013
1048
  await load();
1014
1049
  await refresh({ agentId, projectId, withCounts: true });
1015
1050
  clearCachedCounts(source);
@@ -1020,11 +1055,19 @@ export function SourcesPanel(props: Props) {
1020
1055
  }
1021
1056
  };
1022
1057
 
1058
+ /** Resume a paused embedding-only pass: the same owed-only apply, already confirmed once. */
1059
+ const handleResumeEmbedding = (source: string) =>
1060
+ followReindex(
1061
+ source,
1062
+ () => startReembed({ agentId, ...(projectId ? { projectId } : {}), source }, 'pending', client),
1063
+ 'Embedding failed',
1064
+ );
1065
+
1023
1066
  /** "Rescan changes" — changed files are embedded again; unchanged ones keep their vectors. */
1024
1067
  const handleReindex = (source: string) =>
1025
1068
  followReindex(
1026
1069
  source,
1027
- () => reindexSource({ agentId, ...(projectId ? { projectId } : {}), source }),
1070
+ () => reindexSource({ agentId, ...(projectId ? { projectId } : {}), source }, client),
1028
1071
  'Rescan failed',
1029
1072
  );
1030
1073
 
@@ -1034,7 +1077,7 @@ export function SourcesPanel(props: Props) {
1034
1077
  setPurgeBusy(true);
1035
1078
  setError(null);
1036
1079
  try {
1037
- const counts = await purgeSourceIndex({ agentId, ...(projectId ? { projectId } : {}), source, selector, mode, obsoleteOnly: purgeObsoleteOnly });
1080
+ const counts = await purgeSourceIndex({ agentId, ...(projectId ? { projectId } : {}), source, selector, mode, obsoleteOnly: purgeObsoleteOnly }, client);
1038
1081
  if (epoch !== purgeEpoch.current) return;
1039
1082
  if (mode === 'estimate') setPurgeCounts(counts);
1040
1083
  else { setPurgeFor(null); setPurgeCounts(null); clearCachedCounts(source); await load(); await refresh({ agentId, projectId, withCounts: true }); }
@@ -1046,7 +1089,7 @@ export function SourcesPanel(props: Props) {
1046
1089
  setResettingSource(source);
1047
1090
  setError(null);
1048
1091
  try {
1049
- await resetSync({ agentId, ...(projectId ? { projectId } : {}), source });
1092
+ await resetSync({ agentId, ...(projectId ? { projectId } : {}), source }, client);
1050
1093
  await load();
1051
1094
  } catch (err) {
1052
1095
  setError(err instanceof Error ? err.message : 'Reset failed');
@@ -1065,7 +1108,7 @@ export function SourcesPanel(props: Props) {
1065
1108
  setTogglingEnabledSource(source);
1066
1109
  setError(null);
1067
1110
  try {
1068
- await setSourceEnabled({ agentId, ...(projectId ? { projectId } : {}), source, enabled: next });
1111
+ await setSourceEnabled({ agentId, ...(projectId ? { projectId } : {}), source, enabled: next }, client);
1069
1112
  await load();
1070
1113
  } catch (err) {
1071
1114
  setError(err instanceof Error ? err.message : 'Toggle failed');
@@ -1083,7 +1126,7 @@ export function SourcesPanel(props: Props) {
1083
1126
  ...(projectId ? { projectId } : {}),
1084
1127
  source,
1085
1128
  ...(opts.purgeVectors ? { purgeVectors: true } : {}),
1086
- });
1129
+ }, client);
1087
1130
  await load();
1088
1131
  // The deleted row is gone; no surviving source's count moved, so the
1089
1132
  // refresh runs count-free. `clearCachedCounts` still drops the row's own
@@ -1109,7 +1152,7 @@ export function SourcesPanel(props: Props) {
1109
1152
  setBrowseLoading(true);
1110
1153
  setBrowseError(null);
1111
1154
  try {
1112
- const result = await browseDirectories({ path, agentId, ...(projectId ? { projectId } : {}) });
1155
+ const result = await browseDirectories({ path, agentId, ...(projectId ? { projectId } : {}) }, client);
1113
1156
  setBrowseEntries(result.entries);
1114
1157
  setBrowsePath(path);
1115
1158
  } catch {
@@ -1170,7 +1213,7 @@ export function SourcesPanel(props: Props) {
1170
1213
  ...(isOwnerEffective && addKind === 'local' && addDraft.recognizesPackages
1171
1214
  ? { recognizesPackages: true }
1172
1215
  : {}),
1173
- });
1216
+ }, client);
1174
1217
  setShowAddForm(false);
1175
1218
  {
1176
1219
  const reset = buildAddDraft(selectedKind, sourceKeyIds);
@@ -1335,7 +1378,7 @@ export function SourcesPanel(props: Props) {
1335
1378
  <>
1336
1379
  <div className="text-[10px] text-amber-300/70 bg-amber-500/8 rounded px-2 py-1.5">
1337
1380
  Docker mode: host folders still need the CLI mount script:{' '}
1338
- <code className="text-amber-200/90 font-mono">pnpm neuralis:mount add</code>{' '}
1381
+ <code className="text-amber-200/90 font-mono">neuralis mount add</code>{' '}
1339
1382
  on the host, then restart the container. Package sources like Machine do not require a host path here.
1340
1383
  </div>
1341
1384
  {/* Unmounted volume mounts */}
@@ -1567,7 +1610,7 @@ export function SourcesPanel(props: Props) {
1567
1610
  <span>
1568
1611
  Recognize packages
1569
1612
  <span className="block text-[9px] text-white/35 normal-case font-normal">
1570
- Load WASM packages dropped in this folder (in addition to <code>_packages/</code>). Advertised only within this source&apos;s scope.
1613
+ Load packages found in this folder (in addition to <code>_packages/</code>) as soon as the source is added. Advertised only within this source&apos;s scope.
1571
1614
  </span>
1572
1615
  </span>
1573
1616
  </label>
@@ -1630,13 +1673,11 @@ export function SourcesPanel(props: Props) {
1630
1673
 
1631
1674
  return (
1632
1675
  <div key={fileKey(sourceRootUri(config.source))} className="rounded-sm">
1633
- {/* Accordion header */}
1634
- <button
1635
- type="button"
1636
- onClick={() => toggleSource(config.source)}
1637
- title={disconnected ? sourceLiveReasonLabel(config.live_reason) : undefined}
1638
- className="w-full flex items-center gap-2 py-2 text-left group hover:bg-white/[0.02] rounded-md px-1 transition"
1639
- >
1676
+ {/* Accordion header: selection and enabled actions are siblings. */}
1677
+ <div className="w-full flex items-center gap-2 py-2 text-left group hover:bg-white/[0.02] rounded-md px-1 transition">
1678
+ <button type="button" onClick={() => toggleSource(config.source)} aria-expanded={isOpen}
1679
+ title={disconnected ? sourceLiveReasonLabel(config.live_reason) : undefined}
1680
+ className="min-w-0 flex-1 flex items-center gap-2">
1640
1681
  {/* Git indicator (G2.1) — a GitBranch overlay on a git-repo
1641
1682
  source's icon, ORTHOGONAL to the sync tone (visualTone still
1642
1683
  owns the icon colour). */}
@@ -1671,6 +1712,7 @@ export function SourcesPanel(props: Props) {
1671
1712
  {dirty && (
1672
1713
  <span className="shrink-0 rounded px-1 py-0.5 text-[8px] font-medium text-amber-300/80 bg-amber-500/10">unsaved</span>
1673
1714
  )}
1715
+ </button>
1674
1716
  {/* W3K — enabled toggle (per scope, per source). Machine sources also offer Auto. */}
1675
1717
  {(() => {
1676
1718
  const enabled = config.enabled ?? true;
@@ -1721,7 +1763,7 @@ export function SourcesPanel(props: Props) {
1721
1763
  {describeConn(config, meta)}
1722
1764
  </span>
1723
1765
  <ChevronDown className={cn('h-3 w-3 text-white/25 shrink-0 transition-transform', isOpen && 'rotate-180')} />
1724
- </button>
1766
+ </div>
1725
1767
 
1726
1768
  {/* Expanded body — when open it expands to full height (no clamp)
1727
1769
  so every Path Rule / uri-policy is visible; the outer panel
@@ -1818,8 +1860,8 @@ export function SourcesPanel(props: Props) {
1818
1860
  </div>
1819
1861
 
1820
1862
  {/* R2b — Recognize packages toggle. Owner/admin-effective +
1821
- local-kind only (server re-gates). Turns this source into a
1822
- WASM-package source; advertised only within its own scope. */}
1863
+ local-kind only (server re-gates). Makes this source a package
1864
+ source too; advertised only within its own scope. */}
1823
1865
  {editable && isOwnerEffective && (meta?.kind ?? config.connection.kind) === 'local' && (
1824
1866
  <div className="pl-0">
1825
1867
  <label className="flex items-start gap-1.5 py-1 cursor-pointer">
@@ -1833,7 +1875,7 @@ export function SourcesPanel(props: Props) {
1833
1875
  <span className="text-[10px] text-white/70 leading-tight">
1834
1876
  Recognize packages
1835
1877
  <span className="block text-[9px] text-white/35 normal-case font-normal">
1836
- Load WASM packages dropped here (additive to <code>_packages/</code>); advertised only within this source&apos;s scope. Save to apply.
1878
+ Load packages found in this folder (in addition to <code>_packages/</code>) — applied on save; advertised only within this source&apos;s scope.
1837
1879
  </span>
1838
1880
  </span>
1839
1881
  </label>
@@ -2018,6 +2060,29 @@ export function SourcesPanel(props: Props) {
2018
2060
  {mediaSkipLine(config.sync?.lastSyncResult?.mediaSkipped)}
2019
2061
  </div>
2020
2062
  )}
2063
+ {binarySkipLine(config.sync?.lastSyncResult?.binarySkipped) && (
2064
+ <div className="text-[9px] text-white/40" role="status">
2065
+ {binarySkipLine(config.sync?.lastSyncResult?.binarySkipped)}
2066
+ </div>
2067
+ )}
2068
+ {(() => {
2069
+ const line = embeddingLine(config.sync?.lastSyncResult?.embeddingDegraded, config.embedding_enabled);
2070
+ return line ? (
2071
+ <div className={line.attention ? 'text-[9px] text-amber-200/70' : 'text-[9px] text-white/40'} role="status">
2072
+ {line.text}
2073
+ </div>
2074
+ ) : null;
2075
+ })()}
2076
+ {embeddingPaused[config.source] && (
2077
+ <div className="text-[9px] text-amber-200/70 flex items-center gap-2" role="status">
2078
+ <span>Embedding paused: {embeddingPaused[config.source]}</span>
2079
+ <button type="button" disabled={reindexing}
2080
+ onClick={() => void handleResumeEmbedding(config.source)}
2081
+ className="h-5 px-1.5 rounded bg-white/[0.04] hover:bg-white/[0.08] text-amber-200/90 disabled:opacity-35">
2082
+ Resume
2083
+ </button>
2084
+ </div>
2085
+ )}
2021
2086
  </>
2022
2087
  )}
2023
2088
  </div>
@@ -2052,13 +2117,29 @@ export function SourcesPanel(props: Props) {
2052
2117
  <Database className="h-2.5 w-2.5" />
2053
2118
  Rescan changes
2054
2119
  </button>
2055
- <button type="button" disabled={reindexing}
2120
+ <button type="button" disabled={reindexing || config.embedding_enabled === false}
2056
2121
  onClick={() => setReembedFor(config.source)}
2057
- title="Embed every file of this source again with the active model — shows the estimated cost first"
2122
+ title={config.embedding_enabled === false
2123
+ ? 'Semantic embedding is off — turn it on in the platform settings first'
2124
+ : 'Embed every file of this source again with the active model — shows the estimated cost first'}
2058
2125
  className="h-6 px-2 rounded-md bg-white/[0.04] hover:bg-white/[0.08] text-[9px] font-medium text-cyan-300/80 hover:text-cyan-200 transition disabled:opacity-35 inline-flex items-center gap-1">
2059
2126
  <RefreshCcw className="h-2.5 w-2.5" />
2060
2127
  Re-embed…
2061
2128
  </button>
2129
+ {(() => {
2130
+ const off = config.embedding_enabled === false;
2131
+ return (
2132
+ <button type="button" disabled={reindexing || off}
2133
+ onClick={() => setEmbedPendingFor(config.source)}
2134
+ title={off
2135
+ ? 'Semantic embedding is off — turn it on in the platform settings first'
2136
+ : 'Embed only the files whose semantic embedding is missing or stale — shows the estimate first'}
2137
+ className="h-6 px-2 rounded-md bg-white/[0.04] hover:bg-white/[0.08] text-[9px] font-medium text-cyan-300/80 hover:text-cyan-200 transition disabled:opacity-35 inline-flex items-center gap-1">
2138
+ <Database className="h-2.5 w-2.5" />
2139
+ Embed pending…
2140
+ </button>
2141
+ );
2142
+ })()}
2062
2143
  <button type="button" disabled={resettingSource === config.source}
2063
2144
  onClick={() => void handleResetSync(config.source)}
2064
2145
  title="Forgets what the last sync saw — the next sync compares every file again. Deletes no file and no vector."
@@ -2122,6 +2203,18 @@ export function SourcesPanel(props: Props) {
2122
2203
  onConfirm={(opts) => void handleDelete(config.source, opts)}
2123
2204
  />
2124
2205
  )}
2206
+ {embedPendingFor === config.source && (
2207
+ <ReembedDialog
2208
+ kind="pending"
2209
+ agentId={agentId}
2210
+ {...(projectId ? { projectId } : {})}
2211
+ target={{ source: config.source, label: config.source }}
2212
+ onClose={() => setEmbedPendingFor(null)}
2213
+ onStarted={() =>
2214
+ void followReindex(config.source, () => Promise.resolve(), 'Embedding failed')
2215
+ }
2216
+ />
2217
+ )}
2125
2218
  {reembedFor === config.source && (
2126
2219
  <ReembedDialog
2127
2220
  agentId={agentId}
@@ -2149,7 +2242,7 @@ export function SourcesPanel(props: Props) {
2149
2242
 
2150
2243
  {/* Vector Health */}
2151
2244
  <div className="border-t border-white/[0.06] pt-2 mt-3">
2152
- <button type="button" onClick={() => setHealthOpen((v) => !v)}
2245
+ <button type="button" onClick={() => setVectorHealthOpen(!healthOpen)}
2153
2246
  className="flex items-center gap-2 py-1.5 w-full text-left">
2154
2247
  <Database className="h-4 w-4 text-cyan-400 shrink-0" />
2155
2248
  <span className="text-sm font-semibold text-white/92 flex-1">Vector Health</span>
@@ -2189,13 +2282,13 @@ export function SourcesPanel(props: Props) {
2189
2282
  arguments to print usage:
2190
2283
  </p>
2191
2284
  <div className="rounded bg-black/30 border border-white/[0.05] p-2">
2192
- <pre className="text-[11px] font-mono text-white/85 whitespace-pre-wrap break-all">pnpm neuralis:mount</pre>
2285
+ <pre className="text-[11px] font-mono text-white/85 whitespace-pre-wrap break-all">neuralis mount</pre>
2193
2286
  </div>
2194
2287
  <div className="rounded bg-black/30 border border-white/[0.05] p-2 space-y-1">
2195
2288
  <div className="text-[9px] uppercase tracking-wider text-white/40 font-semibold">
2196
2289
  Example — expose a host folder as a mount
2197
2290
  </div>
2198
- <pre className="text-[10px] font-mono text-white/80 whitespace-pre-wrap break-all">pnpm neuralis:mount add &lt;host-path&gt; --slug &lt;name&gt;</pre>
2291
+ <pre className="text-[10px] font-mono text-white/80 whitespace-pre-wrap break-all">neuralis mount add &lt;host-path&gt; --slug &lt;name&gt;</pre>
2199
2292
  <div className="text-[9px] text-white/35 italic">
2200
2293
  The CLI is infra-only: it registers the bind mount + host-pair
2201
2294
  env in the machine-local compose override, never a source.
@@ -7,6 +7,7 @@ import { hasFeature } from '@neuralis/package-system/access';
7
7
  import { useFilesystemHost } from '../FilesystemHost';
8
8
  import { cn } from '../lib/cn';
9
9
  import { checkVectorHealth, scanVectorHealth, runHealthAction, getSourcesHealth } from '../api';
10
+ import { useFilesystemStore } from '../store/filesystemStore';
10
11
 
11
12
  type Props = {
12
13
  agentId: string;
@@ -29,9 +30,19 @@ type HealthReport = {
29
30
  last_sync?: string;
30
31
  sync_status?: string;
31
32
  }>;
33
+ embedding?: { enabled: boolean; mode: 'metadata' | 'dense' | null; missing: number; stale: number };
32
34
  generatedAt?: string;
33
35
  };
34
36
 
37
+ /** "Semantic: off / metadata only / dense (N missing · M stale)" — `null` for an older server. */
38
+ export function semanticLine(embedding: HealthReport['embedding']): string | null {
39
+ if (!embedding) return null;
40
+ const owed = `${embedding.missing} missing · ${embedding.stale} stale`;
41
+ if (!embedding.enabled) return `Semantic: off — text and field search only (${owed} if turned on)`;
42
+ if (embedding.mode !== 'dense') return `Semantic: metadata only — no embedding model active (${owed})`;
43
+ return `Semantic: dense (${owed})`;
44
+ }
45
+
35
46
  type ActionKind = 'gc' | 'repair-orphans' | 'repair-pending' | 'deduplicate';
36
47
  type ActionResult = Record<string, unknown>;
37
48
 
@@ -63,6 +74,7 @@ const ACTION_COPY: Record<ActionKind, { label: string; explainer: string; toolti
63
74
  };
64
75
 
65
76
  export function VectorHealthPanel({ agentId, projectId }: Props) {
77
+ const client = useFilesystemStore((s) => s.client);
66
78
  const host = useFilesystemHost();
67
79
  // A mirror only — the server's `drive.write` escalation is the gate.
68
80
  const canWrite = hasFeature({ grantedFeatures: [...(host.grantedFeatures ?? [])] }, 'drive.write');
@@ -98,8 +110,8 @@ export function VectorHealthPanel({ agentId, projectId }: Props) {
98
110
  // table so it surfaces real "when was this source last synced"
99
111
  // info instead of being a count-only view.
100
112
  const [data, sourcesHealth] = await Promise.all([
101
- checkVectorHealth({ agentId, ...(projectId ? { projectId } : {}) }),
102
- getSourcesHealth({ agentId, ...(projectId ? { projectId } : {}) })
113
+ checkVectorHealth({ agentId, ...(projectId ? { projectId } : {}) }, client),
114
+ getSourcesHealth({ agentId, ...(projectId ? { projectId } : {}) }, client)
103
115
  .catch(() => [] as Array<{ source: string; last_sync?: string; sync_status: string }>),
104
116
  ]);
105
117
  const lastSyncBySource = new Map<string, { last_sync?: string; sync_status: string }>();
@@ -128,7 +140,7 @@ export function VectorHealthPanel({ agentId, projectId }: Props) {
128
140
  setScanLoading(true);
129
141
  setError(null);
130
142
  try {
131
- const result = await scanVectorHealth({ agentId, ...(projectId ? { projectId } : {}) });
143
+ const result = await scanVectorHealth({ agentId, ...(projectId ? { projectId } : {}) }, client);
132
144
  setScan({ orphanChunkCount: result.orphanChunkCount ?? 0, duplicateGroups: result.duplicateGroups ?? 0 });
133
145
  } catch (err) {
134
146
  setError(err instanceof Error ? err.message : 'Scan failed');
@@ -158,7 +170,7 @@ export function VectorHealthPanel({ agentId, projectId }: Props) {
158
170
  // we're actually deleting something (`dryRun=false`).
159
171
  setPrevReport(!dryRun ? report : null);
160
172
  try {
161
- const result = await runHealthAction({ agentId, ...(projectId ? { projectId } : {}), action, dryRun, retentionHours });
173
+ const result = await runHealthAction({ agentId, ...(projectId ? { projectId } : {}), action, dryRun, retentionHours }, client);
162
174
  setActionResult(result);
163
175
  if (!dryRun) {
164
176
  void fetchReport();
@@ -239,6 +251,10 @@ export function VectorHealthPanel({ agentId, projectId }: Props) {
239
251
  ))}
240
252
  </div>
241
253
 
254
+ {semanticLine(report.embedding) && (
255
+ <div className="text-[9px] text-white/45" role="status">{semanticLine(report.embedding)}</div>
256
+ )}
257
+
242
258
  {/* Metadata */}
243
259
  <div className="flex items-center gap-3 text-[9px] text-white/35">
244
260
  <span>Total points: {report.totalPoints ?? '-'}</span>
@@ -11,6 +11,7 @@
11
11
 
12
12
  import { normalizePolicyUri } from '@neuralis/package-system/policies';
13
13
  import { ackHintFor } from '@neuralis/brain-core/domain/pending-change';
14
+ export { acceptsAbsence } from '@neuralis/brain-core/domain/pending-change';
14
15
  import type { GitControlStatus, GitRepoInfo } from '../domain/types';
15
16
  import type { PendingChangeRecord, PendingPreview } from '../api';
16
17
  import { computeLcsDiff, type DiffHunk } from '../../cards/diffUtils';
@@ -133,17 +134,19 @@ export function isMeasuredRow(kind: ChangeItem['kind']): boolean {
133
134
  /**
134
135
  * Split the first `cap` visible, non-orphaned records into the ones the Approve
135
136
  * sweep can take as-is and the ones its record already proves need an
136
- * acknowledgement. `externalChanged`/`unreviewable` are known only from a preview,
137
- * so the sweep still reports them per record after it runs.
137
+ * acknowledgement. `externalChanged`/`unreviewable` are known only from a preview:
138
+ * a record whose ALREADY-LOADED preview (`knownPreview`, never a fetch) needs one
139
+ * counts as needing it; the rest the sweep hands to the review dialog after it runs.
138
140
  */
139
- export function splitApprovable(visible: PendingChangeRecord[], orphanIds: ReadonlySet<string>, cap = 100): {
141
+ export function splitApprovable(visible: PendingChangeRecord[], orphanIds: ReadonlySet<string>, cap = 100,
142
+ knownPreview?: (id: string) => PendingPreview | undefined): {
140
143
  approvable: PendingChangeRecord[]; needsAck: PendingChangeRecord[];
141
144
  } {
142
145
  const approvable: PendingChangeRecord[] = [];
143
146
  const needsAck: PendingChangeRecord[] = [];
144
147
  for (const rec of visible) {
145
148
  if (orphanIds.has(rec.id)) continue;
146
- if (ackHintFor(rec)) needsAck.push(rec);
149
+ if (ackHintFor(rec) || knownPreview?.(rec.id)?.requiresAcknowledgement.length) needsAck.push(rec);
147
150
  else if (approvable.length < cap) approvable.push(rec);
148
151
  }
149
152
  return { approvable, needsAck };
@@ -154,7 +157,8 @@ export type ReviewOutcome = 'ok' | 'changed' | 'needs-ack' | 'error';
154
157
  /** The refusal a review verb answered, named for the per-record result row. */
155
158
  export function classifyReviewOutcome(error: unknown): Exclude<ReviewOutcome, 'ok'> {
156
159
  const message = error instanceof Error ? error.message : String(error ?? '');
157
- if (message.includes('PENDING_STATE_CHANGED')) return 'changed';
160
+ // The record's point moved under the preview: the same "check again" answer.
161
+ if (message.includes('PENDING_STATE_CHANGED') || message.includes('PENDING_GENERATION_CHANGED')) return 'changed';
158
162
  if (message.includes('CURRENT_STATE_ACKNOWLEDGEMENT_REQUIRED')) return 'needs-ack';
159
163
  return 'error';
160
164
  }