@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
@@ -5,7 +5,7 @@ import { sourceFromUri } from './helpers';
5
5
  /**
6
6
  * gitSlice (G2.1 / spellbound-heron) — client state for the read-only "Git
7
7
  * Control" sidebar panel. Mirrors `searchSlice`'s shape: a plain slice combined
8
- * into the single `useFilesystemStore`, with async actions calling the `../api`
8
+ * into each window's Files store (`createFilesystemStore`), with async actions calling the `../api`
9
9
  * git fetchers.
10
10
  *
11
11
  * The FOCUSED repo is NOT a git-slice field — it is the PAIR
@@ -18,9 +18,6 @@ import { sourceFromUri } from './helpers';
18
18
  * branch repo-correct for free. Write actions pass both explicitly.
19
19
  */
20
20
 
21
- let gitStatusSeq = 0;
22
- let gitBranchSeq = 0;
23
-
24
21
  export interface GitSliceState {
25
22
  gitStatus: GitControlStatus | null;
26
23
  /**
@@ -144,6 +141,9 @@ export function createGitSlice(
144
141
  set: (fn: (s: any) => any) => void,
145
142
  get: () => any,
146
143
  ): GitSliceActions {
144
+ // The newest status / branch request of THIS store — an older answer is dropped.
145
+ let gitStatusSeq = 0;
146
+ let gitBranchSeq = 0;
147
147
  return {
148
148
  setGitViewMode: (mode) => set(() => ({ gitViewMode: mode })),
149
149
 
@@ -196,7 +196,7 @@ export function createGitSlice(
196
196
  ...(projectId ? { projectId } : {}),
197
197
  source: slug,
198
198
  ...(repoRel ? { repo: repoRel } : {}),
199
- });
199
+ }, get().client);
200
200
  if (mySeq !== gitStatusSeq) return;
201
201
  // `totals` rides the SAME response as the rows it sums (the server
202
202
  // computes it after its read filter and cap), so the header can never
@@ -232,7 +232,7 @@ export function createGitSlice(
232
232
  ...(projectId ? { projectId } : {}),
233
233
  source: slug,
234
234
  ...(repoRel ? { repo: repoRel } : {}),
235
- });
235
+ }, get().client);
236
236
  if (mySeq !== gitBranchSeq) return;
237
237
  set(() => ({ gitBranches: Array.isArray(res?.branches) ? res.branches : [] }));
238
238
  } catch (error) {
@@ -8,8 +8,6 @@ import {
8
8
  sourceFromUri,
9
9
  } from './helpers';
10
10
 
11
- const listInFlight = new Map<string, Promise<void>>();
12
-
13
11
  export interface ListSliceActions {
14
12
  /**
15
13
  * Load the SOURCE SUMMARIES — the registry rows the tree headers and the Sources
@@ -50,9 +48,10 @@ export interface ListSliceActions {
50
48
  * context's slice — THESE keys — there and restores it from there; a context
51
49
  * reset must never wipe it, that is the whole point of it),
52
50
  * or the named-exception list — so a new key has to be filed somewhere:
53
- * - preferences, deliberately kept: `activeAgentId`/`activeProjectId` (the callers
54
- * own them), `sidebarOpen`, `sidebarWidth`, `gitViewMode`, `searchMode`,
55
- * `previewEditorsEnabled`, `diffViewMode`;
51
+ * - preferences and window identity, deliberately kept: `activeAgentId`/
52
+ * `activeProjectId` (the callers own them), `windowId` + `client` (the window
53
+ * the store was created for), `sidebarOpen`, `sidebarWidth`, `gitViewMode`,
54
+ * `searchMode`, `previewEditorsEnabled`, `diffViewMode`;
56
55
  * - NOT reset, deliberately: `uploading` alone — it self-heals through the
57
56
  * upload's `finally`, and an upload in flight across a switch must still
58
57
  * release it.
@@ -92,10 +91,12 @@ export function contextResetPatch(): Record<string, unknown> {
92
91
  // Sources panel must not survive an agent/project switch — the panel
93
92
  // would then prefill an Add-Source form for the PREVIOUS context.
94
93
  pendingSourceSuggestion: null,
94
+ vectorHealthOpen: false,
95
95
  searchQuery: '',
96
96
  searchResults: [],
97
97
  searchLoading: false,
98
98
  searchError: undefined,
99
+ searchEffect: {},
99
100
  // Git Control state resets with the context (gitViewMode — a UI
100
101
  // preference — intentionally persists, mirroring searchMode).
101
102
  gitStatus: null,
@@ -228,6 +229,9 @@ export function createListSlice(
228
229
  set: (fn: (s: any) => any) => void,
229
230
  get: () => any,
230
231
  ): ListSliceActions {
232
+ // The root-listing dedup belongs to ONE store (one Files window): two windows
233
+ // listing the same agent must each get their own answer into their own store.
234
+ const listInFlight = new Map<string, Promise<void>>();
231
235
  return {
232
236
  async loadList({ agentId, projectId, userId, withCounts }) {
233
237
  if (!agentId) return;
@@ -310,7 +314,7 @@ export function createListSlice(
310
314
  sources_only: true,
311
315
  recursive: false,
312
316
  ...(withCounts ? { include_counts: true } : {}),
313
- });
317
+ }, get().client);
314
318
  } catch {
315
319
  set(() => ({ snapshotError: 'Filesystem service unavailable', sourcesLoading: false }));
316
320
  return;
@@ -1,8 +1,6 @@
1
1
  import { searchFiles } from '../api';
2
2
  import { sourceRootUri } from './helpers';
3
3
 
4
- let searchSeq = 0;
5
-
6
4
  export type SearchSliceHit = {
7
5
  id: string;
8
6
  uri: string;
@@ -13,6 +11,16 @@ export type SearchSliceHit = {
13
11
  chunk_end?: number;
14
12
  match_type?: 'semantic' | 'keyword' | 'hybrid';
15
13
  score?: number;
14
+ /** `current`, or why the point's semantic embedding is not (`missing` / `stale` / …). */
15
+ embedding_status?: string;
16
+ };
17
+
18
+ /** What the last search ran as, when that differs from what was asked (or carries a warning). */
19
+ export type SearchEffect = {
20
+ requestedMode?: string;
21
+ effectiveMode?: string;
22
+ embeddingDegraded?: string;
23
+ warning?: string;
16
24
  };
17
25
 
18
26
  /** UI search modes → wire `search_mode`: keyword→filter, semantic→semantic, grep→grep. */
@@ -39,6 +47,8 @@ export interface SearchSliceState {
39
47
  searchResults: SearchSliceHit[];
40
48
  searchLoading: boolean;
41
49
  searchError?: string;
50
+ /** Empty when the search ran as asked, with no warning. */
51
+ searchEffect: SearchEffect;
42
52
  }
43
53
 
44
54
  export interface SearchSliceActions {
@@ -66,6 +76,7 @@ export const searchSliceInitial: SearchSliceState = {
66
76
  searchResults: [],
67
77
  searchLoading: false,
68
78
  searchError: undefined,
79
+ searchEffect: {},
69
80
  };
70
81
 
71
82
  /** Grep needs a live-connector folder scope; brain:// has no live text to scan. */
@@ -82,6 +93,8 @@ export function createSearchSlice(
82
93
  set: (fn: (s: any) => any) => void,
83
94
  get: () => any,
84
95
  ): SearchSliceActions {
96
+ // The newest search of THIS store — an older answer never overwrites a newer one.
97
+ let searchSeq = 0;
85
98
  return {
86
99
  setSearchQuery: (query) => set(() => ({ searchQuery: query })),
87
100
  setSearchMode: (mode) => set(() => ({ searchMode: mode })),
@@ -94,6 +107,7 @@ export function createSearchSlice(
94
107
  searchResults: [],
95
108
  searchLoading: false,
96
109
  searchError: undefined,
110
+ searchEffect: {},
97
111
  })),
98
112
 
99
113
  async runSearch({ agentId, projectId }) {
@@ -108,7 +122,7 @@ export function createSearchSlice(
108
122
  ? query.length >= 2 || glob.length >= 2
109
123
  : query.length >= 2;
110
124
  if (!agentId || !runnable) {
111
- set(() => ({ searchResults: [], searchLoading: false, searchError: undefined }));
125
+ set(() => ({ searchResults: [], searchLoading: false, searchError: undefined, searchEffect: {} }));
112
126
  return;
113
127
  }
114
128
 
@@ -127,6 +141,7 @@ export function createSearchSlice(
127
141
  searchResults: [],
128
142
  searchLoading: false,
129
143
  searchError: 'Grep needs a non-brain folder scope — select a folder in a disk-backed source.',
144
+ searchEffect: {},
130
145
  }));
131
146
  return;
132
147
  }
@@ -152,7 +167,7 @@ export function createSearchSlice(
152
167
  ...(searchMode !== 'grep' && filters.createdAfter.trim() ? { created_after: filters.createdAfter.trim() } : {}),
153
168
  ...(searchMode !== 'grep' && filters.createdBefore.trim() ? { created_before: filters.createdBefore.trim() } : {}),
154
169
  limit: searchMode === 'semantic' ? 30 : 50,
155
- });
170
+ }, get().client);
156
171
  if (mySeq !== searchSeq) return;
157
172
  const rows = res.results || [];
158
173
  // Backend error rows (grep guidance, index-unavailable) carry `error`
@@ -170,11 +185,18 @@ export function createSearchSlice(
170
185
  chunk_end: r.chunk_end,
171
186
  match_type: r.match_type,
172
187
  score: r.score,
188
+ ...(typeof r.embedding_status === 'string' ? { embedding_status: r.embedding_status } : {}),
173
189
  }));
174
190
  set(() => ({
175
191
  searchResults: hits,
176
192
  searchLoading: false,
177
193
  searchError: errorRow ? String((errorRow as any).error) : undefined,
194
+ searchEffect: {
195
+ ...(res.requested_mode ? { requestedMode: res.requested_mode } : {}),
196
+ ...(res.effective_mode ? { effectiveMode: res.effective_mode } : {}),
197
+ ...(res.embedding_degraded ? { embeddingDegraded: res.embedding_degraded } : {}),
198
+ ...(res.warning ? { warning: res.warning } : {}),
199
+ },
178
200
  }));
179
201
  } catch (error) {
180
202
  if (mySeq !== searchSeq) return;
@@ -182,6 +204,7 @@ export function createSearchSlice(
182
204
  searchResults: [],
183
205
  searchLoading: false,
184
206
  searchError: error instanceof Error ? error.message : 'Search failed',
207
+ searchEffect: {},
185
208
  }));
186
209
  }
187
210
  },
@@ -6,7 +6,7 @@ import { RefreshCw, FileCode, Pencil, Trash2, Loader2, Upload, Check, X, GitComp
6
6
  import { cn } from '../lib/cn';
7
7
  import { useFilesystemHost } from '../FilesystemHost';
8
8
  import { buildAgentIndex } from '../lib/agentUtils';
9
- import { useContainerWidth } from '../hooks/useContainerWidth';
9
+ import { useContainerWidth } from '@neuralis/package-system/client';
10
10
  import { detectCodeLanguage } from '../lib/detectLanguage';
11
11
  import { parseGitLineStatus, isEmptyGitLineStatus, type GitLineStatusMap } from './codeEditor/gitLineStatus';
12
12
  import { EditorTabBar, EditorTabsMenu, TAB_SCROLLER_ATTR } from './EditorTabBar';
@@ -45,6 +45,7 @@ function normalizeUserUriInput(raw: string, fallbackUri: string): string {
45
45
  }
46
46
 
47
47
  export function FileEditor() {
48
+ const client = useFilesystemStore((s) => s.client);
48
49
  const openFiles = useFilesystemStore((s) => s.openFiles);
49
50
  const activeFile = useFilesystemStore((s) => s.activeFile);
50
51
  const files = useFilesystemStore((s) => s.files);
@@ -169,7 +170,7 @@ export function FileEditor() {
169
170
  }
170
171
  void (async () => {
171
172
  try {
172
- const res = await getGitDiff({ agentId: targetAgentId, ...(projectId ? { projectId } : {}), source, path, staged: false });
173
+ const res = await getGitDiff({ agentId: targetAgentId, ...(projectId ? { projectId } : {}), source, path, staged: false }, client);
173
174
  if (cancelled) return;
174
175
  if (res && (res as { ok?: boolean }).ok === false) {
175
176
  setGitLineStatus(undefined);
@@ -243,7 +244,7 @@ export function FileEditor() {
243
244
  id: activeNode.id,
244
245
  uri: activeNode.uri,
245
246
  fields: { status: 'active' },
246
- });
247
+ }, client);
247
248
  if (res && res.ok === false) {
248
249
  setEditError(writeRefusalMessage(res, 'Restore failed'));
249
250
  return;
@@ -275,7 +276,7 @@ export function FileEditor() {
275
276
  ...(projectId ? { projectId } : {}),
276
277
  id: activeNode.id,
277
278
  uri: activeNode.uri,
278
- });
279
+ }, client);
279
280
  if (res && res.ok) {
280
281
  const nodeKey = activeNode.storeKey || activeFile || fileKeyFromNode(activeNode);
281
282
  if (nodeKey) {
@@ -310,7 +311,7 @@ export function FileEditor() {
310
311
  id: activeNode.id,
311
312
  uri: activeNode.uri,
312
313
  revert: true,
313
- });
314
+ }, client);
314
315
  if (res && res.ok === false) {
315
316
  setEditError(writeRefusalMessage(res, 'Revert failed'));
316
317
  return;
@@ -434,98 +435,107 @@ export function FileEditor() {
434
435
  <div {...{ [TAB_SCROLLER_ATTR]: '' }} className="flex min-w-0 flex-1 overflow-x-auto overflow-y-hidden">
435
436
  <EditorTabBar />
436
437
  {workspacePanels.upload ? (
438
+ <div className="group flex shrink-0 items-center">
437
439
  <button
438
440
  type="button"
439
441
  className={cn(
440
- 'group flex items-center gap-1.5 px-3 py-2 text-xs min-w-[120px] max-w-[240px] rounded-lg',
442
+ 'flex items-center gap-1.5 px-3 py-2 text-xs min-w-[120px] max-w-[240px] rounded-lg',
441
443
  showUploadTab ? 'bg-white/10 text-white' : 'text-white/50 hover:bg-white/5 hover:text-white/80',
442
444
  )}
443
445
  onClick={() => setActiveWorkspaceTab('upload')}
444
446
  >
445
447
  <Upload className="w-3.5 h-3.5 shrink-0" />
446
448
  <span className="truncate flex-1">Upload</span>
447
- <span
448
- className="opacity-0 group-hover:opacity-100 p-0.5 rounded hover:bg-white/10"
449
+ </button>
450
+ <button type="button" aria-label="Close Upload"
451
+ className="opacity-0 group-hover:opacity-100 focus-visible:opacity-100 p-0.5 rounded hover:bg-white/10"
449
452
  onClick={(e) => {
450
453
  e.stopPropagation();
451
454
  setWorkspacePanelOpen('upload', false);
452
455
  }}
453
456
  >
454
457
  <X className="w-3 h-3" />
455
- </span>
456
- </button>
458
+ </button>
459
+ </div>
457
460
  ) : null}
458
461
  {supportsSources && workspacePanels.sources ? (
462
+ <div className="group flex shrink-0 items-center">
459
463
  <button
460
464
  type="button"
461
465
  className={cn(
462
- 'group flex items-center gap-1.5 px-3 py-2 text-xs min-w-[120px] max-w-[240px] rounded-lg',
466
+ 'flex items-center gap-1.5 px-3 py-2 text-xs min-w-[120px] max-w-[240px] rounded-lg',
463
467
  showSourcesTab ? 'bg-white/10 text-white' : 'text-white/50 hover:bg-white/5 hover:text-white/80',
464
468
  )}
465
469
  onClick={() => setActiveWorkspaceTab('sources')}
466
470
  >
467
471
  <SlidersHorizontal className="w-3.5 h-3.5 shrink-0" />
468
472
  <span className="truncate flex-1">Sources</span>
469
- <span
470
- className="opacity-0 group-hover:opacity-100 p-0.5 rounded hover:bg-white/10"
473
+ </button>
474
+ <button type="button" aria-label="Close Sources"
475
+ className="opacity-0 group-hover:opacity-100 focus-visible:opacity-100 p-0.5 rounded hover:bg-white/10"
471
476
  onClick={(e) => {
472
477
  e.stopPropagation();
473
478
  setWorkspacePanelOpen('sources', false);
474
479
  }}
475
480
  >
476
481
  <X className="w-3 h-3" />
477
- </span>
478
- </button>
482
+ </button>
483
+ </div>
479
484
  ) : null}
480
485
  {workspacePanels.packages ? (
486
+ <div className="group flex shrink-0 items-center">
481
487
  <button
482
488
  type="button"
483
489
  className={cn(
484
- 'group flex items-center gap-1.5 px-3 py-2 text-xs min-w-[120px] max-w-[240px] rounded-lg',
490
+ 'flex items-center gap-1.5 px-3 py-2 text-xs min-w-[120px] max-w-[240px] rounded-lg',
485
491
  showPackagesTab ? 'bg-white/10 text-white' : 'text-white/50 hover:bg-white/5 hover:text-white/80',
486
492
  )}
487
493
  onClick={() => setActiveWorkspaceTab('packages')}
488
494
  >
489
495
  <Package className="w-3.5 h-3.5 shrink-0" />
490
496
  <span className="truncate flex-1">Packages</span>
491
- <span
492
- className="opacity-0 group-hover:opacity-100 p-0.5 rounded hover:bg-white/10"
497
+ </button>
498
+ <button type="button" aria-label="Close Packages"
499
+ className="opacity-0 group-hover:opacity-100 focus-visible:opacity-100 p-0.5 rounded hover:bg-white/10"
493
500
  onClick={(e) => {
494
501
  e.stopPropagation();
495
502
  setWorkspacePanelOpen('packages', false);
496
503
  }}
497
504
  >
498
505
  <X className="w-3 h-3" />
499
- </span>
500
- </button>
506
+ </button>
507
+ </div>
501
508
  ) : null}
502
509
  {workspacePanels.pending ? (
510
+ <div className="group flex shrink-0 items-center">
503
511
  <button
504
512
  type="button"
505
513
  className={cn(
506
- 'group flex items-center gap-1.5 px-3 py-2 text-xs min-w-[120px] max-w-[240px] rounded-lg',
514
+ 'flex items-center gap-1.5 px-3 py-2 text-xs min-w-[120px] max-w-[240px] rounded-lg',
507
515
  showPendingTab ? 'bg-white/10 text-white' : 'text-white/50 hover:bg-white/5 hover:text-white/80',
508
516
  )}
509
517
  onClick={() => setActiveWorkspaceTab('pending')}
510
518
  >
511
519
  <FileDiff className="w-3.5 h-3.5 shrink-0" />
512
520
  <span className="truncate flex-1">Changes</span>
513
- <span
514
- className="opacity-0 group-hover:opacity-100 p-0.5 rounded hover:bg-white/10"
521
+ </button>
522
+ <button type="button" aria-label="Close Changes"
523
+ className="opacity-0 group-hover:opacity-100 focus-visible:opacity-100 p-0.5 rounded hover:bg-white/10"
515
524
  onClick={(e) => {
516
525
  e.stopPropagation();
517
526
  setWorkspacePanelOpen('pending', false);
518
527
  }}
519
528
  >
520
529
  <X className="w-3 h-3" />
521
- </span>
522
- </button>
530
+ </button>
531
+ </div>
523
532
  ) : null}
524
533
  {gitDiffTarget ? (
534
+ <div className="group flex shrink-0 items-center">
525
535
  <button
526
536
  type="button"
527
537
  className={cn(
528
- 'group flex items-center gap-1.5 px-3 py-2 text-xs min-w-[120px] max-w-[240px] rounded-lg',
538
+ 'flex items-center gap-1.5 px-3 py-2 text-xs min-w-[120px] max-w-[240px] rounded-lg',
529
539
  showGitDiff ? 'bg-white/10 text-white' : 'text-white/50 hover:bg-white/5 hover:text-white/80',
530
540
  )}
531
541
  onClick={() => setActiveWorkspaceTab('git-diff')}
@@ -537,8 +547,9 @@ export function FileEditor() {
537
547
  <span className="truncate flex-1">
538
548
  {repoQualifiedLabel(gitDiffTarget.repo, extractFilename(gitDiffTarget.path) || gitDiffTarget.path)}
539
549
  </span>
540
- <span
541
- className="opacity-0 group-hover:opacity-100 p-0.5 rounded hover:bg-white/10"
550
+ </button>
551
+ <button type="button" aria-label="Close Git diff"
552
+ className="opacity-0 group-hover:opacity-100 focus-visible:opacity-100 p-0.5 rounded hover:bg-white/10"
542
553
  onClick={(e) => {
543
554
  e.stopPropagation();
544
555
  setGitDiffTarget(null);
@@ -546,14 +557,15 @@ export function FileEditor() {
546
557
  }}
547
558
  >
548
559
  <X className="w-3 h-3" />
549
- </span>
550
- </button>
560
+ </button>
561
+ </div>
551
562
  ) : null}
552
563
  {gitCommitTarget ? (
564
+ <div className="group flex shrink-0 items-center">
553
565
  <button
554
566
  type="button"
555
567
  className={cn(
556
- 'group flex items-center gap-1.5 px-3 py-2 text-xs min-w-[120px] max-w-[240px] rounded-lg',
568
+ 'flex items-center gap-1.5 px-3 py-2 text-xs min-w-[120px] max-w-[240px] rounded-lg',
557
569
  showGitCommit ? 'bg-white/10 text-white' : 'text-white/50 hover:bg-white/5 hover:text-white/80',
558
570
  )}
559
571
  onClick={() => setActiveWorkspaceTab('git-commit')}
@@ -575,8 +587,9 @@ export function FileEditor() {
575
587
  ? repoQualifiedLabel(gitCommitTarget.repo, `${shortSha(gitCommitTarget.sha)} ${gitCommitTarget.subject}`)
576
588
  : repoQualifiedLabel(gitCommitTarget.repo, 'Outgoing changes')}
577
589
  </span>
578
- <span
579
- className="opacity-0 group-hover:opacity-100 p-0.5 rounded hover:bg-white/10"
590
+ </button>
591
+ <button type="button" aria-label="Close Git commit"
592
+ className="opacity-0 group-hover:opacity-100 focus-visible:opacity-100 p-0.5 rounded hover:bg-white/10"
580
593
  onClick={(e) => {
581
594
  e.stopPropagation();
582
595
  // The 'file' fallback for an ACTIVE git-commit tab lives in
@@ -585,8 +598,8 @@ export function FileEditor() {
585
598
  }}
586
599
  >
587
600
  <X className="w-3 h-3" />
588
- </span>
589
- </button>
601
+ </button>
602
+ </div>
590
603
  ) : null}
591
604
  </div>
592
605
  <EditorTabsMenu />
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { useFilesystemStore, type SidebarView } from '../store/filesystemStore';
3
+ import { useFilesystemStore, useFilesystemStoreApi, type SidebarView } from '../store/filesystemStore';
4
4
  import React, { useMemo, useState, useCallback, useRef, useEffect } from 'react';
5
5
  import { SkillLauncher } from '@neuralis/package-system/client';
6
6
  import { meetsRequires } from '@neuralis/package-system/access';
@@ -197,6 +197,7 @@ export function flattenSource(
197
197
  export function FileTree(props: { agentId: string; sidebarView?: SidebarView }) {
198
198
  const { agentId, sidebarView = 'tree' } = props;
199
199
  const host = useFilesystemHost();
200
+ const storeApi = useFilesystemStoreApi();
200
201
 
201
202
  const files = useFilesystemStore((s) => s.files);
202
203
  const folderBadges = useFilesystemStore((s) => s.folderBadges);
@@ -527,12 +528,12 @@ export function FileTree(props: { agentId: string; sidebarView?: SidebarView })
527
528
  // Expand + load the parent so the inline input row is visible in place.
528
529
  if (!parentUri.endsWith('://') && !expanded.has(parentUri)) {
529
530
  toggleFolder(parentUri);
530
- void useFilesystemStore.getState().ensureFolderLoaded({ agentId, projectId, uri: parentUri });
531
+ void storeApi.getState().ensureFolderLoaded({ agentId, projectId, uri: parentUri });
531
532
  }
532
533
  setCreating({ parentUri, kind });
533
534
  }
534
535
  },
535
- [contextMenu, menuTargets, expanded, toggleFolder, agentId, projectId, clipboard, pasteNodes],
536
+ [contextMenu, menuTargets, expanded, toggleFolder, agentId, projectId, clipboard, pasteNodes, storeApi],
536
537
  );
537
538
 
538
539
  const handleCreateCommit = useCallback(
@@ -607,12 +608,12 @@ export function FileTree(props: { agentId: string; sidebarView?: SidebarView })
607
608
  setActiveFolderPath(params.key);
608
609
  toggleFolder(params.key);
609
610
  if (wasExpanded) return;
610
- await useFilesystemStore.getState().ensureFolderLoaded({
611
+ await storeApi.getState().ensureFolderLoaded({
611
612
  agentId,
612
613
  projectId,
613
614
  uri: params.key,
614
615
  });
615
- }, [agentId, expanded, projectId, setActiveFolderPath, toggleFolder]);
616
+ }, [agentId, expanded, projectId, setActiveFolderPath, toggleFolder, storeApi]);
616
617
 
617
618
  const handleOpenFile = useCallback((params: { agentId: string; projectId: string | null; uri: string; readAgentId?: string }) => {
618
619
  if (params.uri) {
@@ -644,7 +645,7 @@ export function FileTree(props: { agentId: string; sidebarView?: SidebarView })
644
645
  */
645
646
  const handleRefreshSource = useCallback(async (uriRoot: string) => {
646
647
  if (!agentId) return;
647
- const store = useFilesystemStore.getState();
648
+ const store = storeApi.getState();
648
649
  setSourceBranchExpanded((prev) => (prev[uriRoot] ? prev : { ...prev, [uriRoot]: true }));
649
650
  if (store.loadedFolders?.[uriRoot]) {
650
651
  const source = sourceFromUri(uriRoot);
@@ -652,7 +653,7 @@ export function FileTree(props: { agentId: string; sidebarView?: SidebarView })
652
653
  return;
653
654
  }
654
655
  await store.ensureFolderLoaded({ agentId, projectId, uri: uriRoot, force: true });
655
- }, [agentId, projectId]);
656
+ }, [agentId, projectId, storeApi]);
656
657
 
657
658
  // Hydrate what is VISIBLE and not yet fetched.
658
659
  //
@@ -664,7 +665,7 @@ export function FileTree(props: { agentId: string; sidebarView?: SidebarView })
664
665
  // rather than retry-looping. `ensureFolderLoaded` is itself idempotent.
665
666
  useEffect(() => {
666
667
  if (!agentId) return;
667
- const state = useFilesystemStore.getState();
668
+ const state = storeApi.getState();
668
669
  const wanted: string[] = [];
669
670
  for (const info of sourceInfos) {
670
671
  if (sourceBranchExpanded[info.uri_root]) wanted.push(info.uri_root);
@@ -676,7 +677,7 @@ export function FileTree(props: { agentId: string; sidebarView?: SidebarView })
676
677
  if (hydration && hydration !== 'idle') continue;
677
678
  void state.ensureFolderLoaded({ agentId, projectId, uri });
678
679
  }
679
- }, [agentId, projectId, sourceInfos, sourceBranchExpanded, expanded]);
680
+ }, [agentId, projectId, sourceInfos, sourceBranchExpanded, expanded, storeApi]);
680
681
 
681
682
  const handleMoveFileToFolder = useCallback(
682
683
  async ({ fromUri, id, toFolderUri }: { fromUri: string; id?: string; toFolderUri: string }) => {
@@ -4,7 +4,7 @@ import React, { useEffect, useMemo, useState } from 'react';
4
4
  import { SlidersHorizontal } from 'lucide-react';
5
5
  import { useFilesystemStore } from '../store/filesystemStore';
6
6
  import { folderUri } from '../store/helpers';
7
- import { grepScopeFor, type SearchUiMode } from '../store/searchSlice';
7
+ import { grepScopeFor, type SearchEffect, type SearchUiMode } from '../store/searchSlice';
8
8
 
9
9
  const MODES: Array<{ id: SearchUiMode; label: string; hint: string }> = [
10
10
  { id: 'keyword', label: 'Keyword', hint: 'Indexed word search (primary)' },
@@ -20,6 +20,19 @@ const filterInputClass =
20
20
  * input itself lives in the sidebar HEADER row (FilesystemWidget) — this
21
21
  * panel renders only while `sidebarView === 'search'`.
22
22
  */
23
+ /**
24
+ * The one line that says a search did not run as asked: a semantic request
25
+ * answered by keyword search because embedding is unavailable (the reason is
26
+ * the server's), or the server's own warning. `null` when it ran as asked.
27
+ */
28
+ export function searchEffectLine(effect: SearchEffect | undefined): string | null {
29
+ if (!effect) return null;
30
+ if (effect.requestedMode === 'semantic' && effect.effectiveMode && effect.effectiveMode !== 'semantic') {
31
+ return `Searched as keyword — semantic search unavailable${effect.embeddingDegraded ? ` (${effect.embeddingDegraded})` : ''}. Use specific words.`;
32
+ }
33
+ return effect.warning ?? null;
34
+ }
35
+
23
36
  export function FileTreeSearch({ agentId }: { agentId: string }) {
24
37
  const projectId = useFilesystemStore((s) => s.activeProjectId);
25
38
  const setActiveFolderPath = useFilesystemStore((s) => s.setActiveFolderPath);
@@ -32,6 +45,8 @@ export function FileTreeSearch({ agentId }: { agentId: string }) {
32
45
  const searchResults = useFilesystemStore((s) => s.searchResults);
33
46
  const searchLoading = useFilesystemStore((s) => s.searchLoading);
34
47
  const searchError = useFilesystemStore((s) => s.searchError);
48
+ const searchEffect = useFilesystemStore((s) => s.searchEffect);
49
+ const effectLine = searchEffectLine(searchEffect);
35
50
  const runSearch = useFilesystemStore((s) => s.runSearch);
36
51
  const activeFolderPath = useFilesystemStore((s) => s.activeFolderPath);
37
52
  const sources = useFilesystemStore((s) => s.sources);
@@ -185,9 +200,15 @@ export function FileTreeSearch({ agentId }: { agentId: string }) {
185
200
  ) : searchError ? (
186
201
  <div className="px-2 py-3 text-[11px] text-red-300/70">{searchError}</div>
187
202
  ) : searchResults.length === 0 ? (
188
- <div className="px-2 py-3 text-[11px] text-white/35">No matches</div>
203
+ <div className="px-2 py-3 text-[11px] text-white/35">
204
+ {effectLine ? <div role="status" className="mb-1 text-[10px] text-amber-200/70">{effectLine}</div> : null}
205
+ No matches
206
+ </div>
189
207
  ) : (
190
208
  <div className="space-y-1">
209
+ {effectLine ? (
210
+ <div role="status" className="px-2 py-1 text-[10px] text-amber-200/70">{effectLine}</div>
211
+ ) : null}
191
212
  {searchResults.map((result) => (
192
213
  <button
193
214
  key={`${result.id}:${result.uri}:${result.chunk_start ?? ''}`}
@@ -203,6 +224,12 @@ export function FileTreeSearch({ agentId }: { agentId: string }) {
203
224
  {typeof result.score === 'number' ? (
204
225
  <span className="text-[9px] text-white/30 shrink-0">{result.score.toFixed(2)}</span>
205
226
  ) : null}
227
+ {result.embedding_status === 'missing' || result.embedding_status === 'stale' ? (
228
+ <span className="text-[9px] px-1 py-0.5 rounded bg-white/[0.06] text-white/40 shrink-0"
229
+ title="This file is text-searchable; its semantic embedding is not current">
230
+ embedding {result.embedding_status}
231
+ </span>
232
+ ) : null}
206
233
  {result.match_type ? (
207
234
  <span className="text-[9px] px-1 py-0.5 rounded bg-white/[0.06] text-white/40 shrink-0">
208
235
  {result.match_type === 'hybrid' ? 'H' : result.match_type === 'semantic' ? 'S' : 'K'}
@@ -16,6 +16,7 @@ import type { GitCommitFileChange, GitCommitTarget } from '../domain/types';
16
16
  import { useVisibleDiffCards, type VisibleDiffQueue } from '../hooks/useVisibleDiffCards';
17
17
  import { GitFileDiff } from './GitFileDiff';
18
18
  import { shortSha, type GitFileDiffMode } from './gitFileDiffMode';
19
+ import { useFilesystemStore } from '../store/filesystemStore';
19
20
 
20
21
  /**
21
22
  * GitCommitChangesView (G2.4/C2+C3 / cobalt-wren) — the multi-file stacked
@@ -182,6 +183,7 @@ export function GitCommitChangesView({
182
183
  agentId: string | null;
183
184
  projectId: string | null;
184
185
  }): React.ReactElement {
186
+ const client = useFilesystemStore((s) => s.client);
185
187
  const [scrollRoot, setScrollRoot] = useState<HTMLDivElement | null>(null);
186
188
  const queue = useVisibleDiffCards(scrollRoot);
187
189
  const [state, setState] = useState<ListState>({ phase: 'loading' });
@@ -211,7 +213,7 @@ export function GitCommitChangesView({
211
213
  source,
212
214
  ...(repo ? { repo } : {}),
213
215
  sha: target.sha,
214
- });
216
+ }, client);
215
217
  if (cancelled) return;
216
218
  if (res.ok === false) {
217
219
  setState({ phase: 'unavailable' });
@@ -228,7 +230,7 @@ export function GitCommitChangesView({
228
230
  ...(repo ? { repo } : {}),
229
231
  maxCount: 1,
230
232
  ref: target.sha,
231
- });
233
+ }, client);
232
234
  const head = Array.isArray(log?.commits) ? log.commits[0] : undefined;
233
235
  if (!cancelled && head) setMeta({ author: head.author, date: head.date });
234
236
  } catch {
@@ -240,7 +242,7 @@ export function GitCommitChangesView({
240
242
  ...(projectId ? { projectId } : {}),
241
243
  source,
242
244
  ...(repo ? { repo } : {}),
243
- });
245
+ }, client);
244
246
  if (cancelled) return;
245
247
  // 3b: a deep-fail is a typed `{ok:false,'unavailable'}` refusal now — treat
246
248
  // it like no-upstream (nothing to show), never crash on a missing files[].