@neuralis/brain-core 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (383) hide show
  1. package/README.md +26 -35
  2. package/app/cards/DiffView.tsx +9 -7
  3. package/app/cards/README.md +1 -1
  4. package/app/cards/diffLine.tsx +2 -4
  5. package/app/filesystem/README.md +1 -1
  6. package/app/filesystem/api/index.ts +14 -5
  7. package/app/filesystem/domain/types.ts +24 -5
  8. package/app/filesystem/store/filesystemStore.ts +20 -1
  9. package/app/filesystem/store/listSlice.ts +2 -0
  10. package/app/filesystem/store/searchSlice.ts +24 -1
  11. package/app/filesystem/ui/FileTreeSearch.tsx +29 -2
  12. package/app/filesystem/ui/PendingChangesPanel.tsx +74 -17
  13. package/app/filesystem/ui/PendingReviewDialog.tsx +45 -20
  14. package/app/filesystem/ui/README.md +8 -7
  15. package/app/filesystem/ui/ReembedDialog.tsx +20 -9
  16. package/app/filesystem/ui/SourceDeleteConfirm.tsx +1 -1
  17. package/app/filesystem/ui/SourcesPanel.tsx +110 -17
  18. package/app/filesystem/ui/VectorHealthPanel.tsx +14 -0
  19. package/app/filesystem/ui/pendingChangesModel.ts +9 -5
  20. package/dist/app/chunks/{astro-LRAFGXNX.js → astro-B2J4AS2D.js} +1 -1
  21. package/dist/app/chunks/bash-KY6SAQTH.js +1 -0
  22. package/dist/app/chunks/c-OBOPYVZ7.js +1 -0
  23. package/dist/app/chunks/{chunk-5H7ZCOD3.js → chunk-2X3GNKJ3.js} +1 -1
  24. package/dist/app/chunks/{chunk-XIFGTNRM.js → chunk-JPJIVRFI.js} +1 -1
  25. package/dist/app/chunks/{chunk-RH3QY5LF.js → chunk-LEFIFWND.js} +1 -1
  26. package/dist/app/chunks/{chunk-G4RZ3UNX.js → chunk-N6RXX3PH.js} +1 -1
  27. package/dist/app/chunks/{chunk-QXXJ73P5.js → chunk-PZAW4HPB.js} +1 -1
  28. package/dist/app/chunks/{chunk-3QLE7Y4L.js → chunk-ZBYWWTO6.js} +1 -1
  29. package/dist/app/chunks/cpp-TVWVOTEQ.js +1 -0
  30. package/dist/app/chunks/css-MANZBYA4.js +1 -0
  31. package/dist/app/chunks/{elixir-M36XROA6.js → elixir-S725Z7EH.js} +1 -1
  32. package/dist/app/chunks/{elm-7BG6QAIK.js → elm-5WUUSTNB.js} +1 -1
  33. package/dist/app/chunks/graphql-UGOPR3WU.js +1 -0
  34. package/dist/app/chunks/html-F6FWTBSG.js +1 -0
  35. package/dist/app/chunks/java-ANIVV5H5.js +1 -0
  36. package/dist/app/chunks/javascript-IH374YWG.js +1 -0
  37. package/dist/app/chunks/json-WGGVVXSB.js +1 -0
  38. package/dist/app/chunks/jsx-OTXJQD32.js +1 -0
  39. package/dist/app/chunks/{latex-ZWK7SXB6.js → latex-QCZNITGN.js} +1 -1
  40. package/dist/app/chunks/lua-4CRZ64PU.js +1 -0
  41. package/dist/app/chunks/{nginx-2L6VRV3A.js → nginx-V4CYS7WR.js} +1 -1
  42. package/dist/app/chunks/{perl-PBUAXXK6.js → perl-BHTX7F5B.js} +1 -1
  43. package/dist/app/chunks/{php-QJX57PA6.js → php-AYGJ5WYZ.js} +1 -1
  44. package/dist/app/chunks/r-4YFCFA4B.js +1 -0
  45. package/dist/app/chunks/{ruby-RLOWMVPO.js → ruby-42NMJWAL.js} +1 -1
  46. package/dist/app/chunks/{scss-B5CAI3HR.js → scss-XD7VU2CU.js} +1 -1
  47. package/dist/app/chunks/sql-B55MH6JJ.js +1 -0
  48. package/dist/app/chunks/{svelte-GT3D4C44.js → svelte-WR3QPIJU.js} +1 -1
  49. package/dist/app/chunks/tsx-S73GAE2L.js +1 -0
  50. package/dist/app/chunks/typescript-NEWOAB5Z.js +1 -0
  51. package/dist/app/chunks/{vue-JOW62MHD.js → vue-CCDS4VZK.js} +1 -1
  52. package/dist/app/chunks/xml-UXKAGLDR.js +1 -0
  53. package/dist/app/chunks/yaml-UMWKDTK7.js +1 -0
  54. package/dist/app/host.js +40 -40
  55. package/dist/scripts/embeddingLockV3.d.ts +30 -0
  56. package/dist/scripts/embeddingLockV3.d.ts.map +1 -0
  57. package/dist/scripts/embeddingLockV3.js +100 -0
  58. package/dist/scripts/embeddingLockV3.js.map +1 -0
  59. package/dist/scripts/vectorProofV1.d.ts +90 -0
  60. package/dist/scripts/vectorProofV1.d.ts.map +1 -0
  61. package/dist/scripts/vectorProofV1.js +220 -0
  62. package/dist/scripts/vectorProofV1.js.map +1 -0
  63. package/dist/src/config/env.d.ts +21 -0
  64. package/dist/src/config/env.d.ts.map +1 -1
  65. package/dist/src/config/env.js +55 -0
  66. package/dist/src/config/env.js.map +1 -1
  67. package/dist/src/connectors/AppSourceConfigStore.d.ts +12 -2
  68. package/dist/src/connectors/AppSourceConfigStore.d.ts.map +1 -1
  69. package/dist/src/connectors/AppSourceConfigStore.js +48 -40
  70. package/dist/src/connectors/AppSourceConfigStore.js.map +1 -1
  71. package/dist/src/connectors/LocalDiskConnector.d.ts +11 -14
  72. package/dist/src/connectors/LocalDiskConnector.d.ts.map +1 -1
  73. package/dist/src/connectors/LocalDiskConnector.js +87 -107
  74. package/dist/src/connectors/LocalDiskConnector.js.map +1 -1
  75. package/dist/src/connectors/sourceConfigMutation.d.ts +11 -1
  76. package/dist/src/connectors/sourceConfigMutation.d.ts.map +1 -1
  77. package/dist/src/connectors/sourceConfigMutation.js +36 -3
  78. package/dist/src/connectors/sourceConfigMutation.js.map +1 -1
  79. package/dist/src/domain/chunker.js +8 -3
  80. package/dist/src/domain/chunker.js.map +1 -1
  81. package/dist/src/domain/healthTypes.d.ts +11 -0
  82. package/dist/src/domain/healthTypes.d.ts.map +1 -1
  83. package/dist/src/domain/mime.d.ts +1 -0
  84. package/dist/src/domain/mime.d.ts.map +1 -1
  85. package/dist/src/domain/mime.js +48 -0
  86. package/dist/src/domain/mime.js.map +1 -1
  87. package/dist/src/domain/pendingChange.d.ts +7 -0
  88. package/dist/src/domain/pendingChange.d.ts.map +1 -1
  89. package/dist/src/domain/pendingChange.js +11 -0
  90. package/dist/src/domain/pendingChange.js.map +1 -1
  91. package/dist/src/domain/sourceConfig.d.ts +7 -14
  92. package/dist/src/domain/sourceConfig.d.ts.map +1 -1
  93. package/dist/src/domain/sourceConfig.js +1 -13
  94. package/dist/src/domain/sourceConfig.js.map +1 -1
  95. package/dist/src/domain/sourcePackages.d.ts +11 -2
  96. package/dist/src/domain/sourcePackages.d.ts.map +1 -1
  97. package/dist/src/domain/syncTrigger.d.ts +2 -3
  98. package/dist/src/domain/syncTrigger.d.ts.map +1 -1
  99. package/dist/src/domain/syncTrigger.js +2 -3
  100. package/dist/src/domain/syncTrigger.js.map +1 -1
  101. package/dist/src/domain/syncTypes.d.ts +21 -4
  102. package/dist/src/domain/syncTypes.d.ts.map +1 -1
  103. package/dist/src/domain/syncTypes.js.map +1 -1
  104. package/dist/src/domain/text.d.ts +3 -0
  105. package/dist/src/domain/text.d.ts.map +1 -1
  106. package/dist/src/domain/text.js +5 -0
  107. package/dist/src/domain/text.js.map +1 -1
  108. package/dist/src/domain/types.d.ts +9 -0
  109. package/dist/src/domain/types.d.ts.map +1 -1
  110. package/dist/src/embeddings/clients/GeminiEmbedder.d.ts.map +1 -1
  111. package/dist/src/embeddings/clients/GeminiEmbedder.js +11 -5
  112. package/dist/src/embeddings/clients/GeminiEmbedder.js.map +1 -1
  113. package/dist/src/embeddings/clients/OllamaEmbedder.d.ts.map +1 -1
  114. package/dist/src/embeddings/clients/OllamaEmbedder.js +13 -6
  115. package/dist/src/embeddings/clients/OllamaEmbedder.js.map +1 -1
  116. package/dist/src/embeddings/clients/OpenAIEmbedder.d.ts.map +1 -1
  117. package/dist/src/embeddings/clients/OpenAIEmbedder.js +12 -9
  118. package/dist/src/embeddings/clients/OpenAIEmbedder.js.map +1 -1
  119. package/dist/src/embeddings/clients/QwenEmbedder.d.ts.map +1 -1
  120. package/dist/src/embeddings/clients/QwenEmbedder.js +12 -5
  121. package/dist/src/embeddings/clients/QwenEmbedder.js.map +1 -1
  122. package/dist/src/embeddings/clients/VoyageEmbedder.d.ts.map +1 -1
  123. package/dist/src/embeddings/clients/VoyageEmbedder.js +12 -5
  124. package/dist/src/embeddings/clients/VoyageEmbedder.js.map +1 -1
  125. package/dist/src/embeddings/factory.d.ts +2 -0
  126. package/dist/src/embeddings/factory.d.ts.map +1 -1
  127. package/dist/src/embeddings/factory.js +23 -3
  128. package/dist/src/embeddings/factory.js.map +1 -1
  129. package/dist/src/embeddings/lock.d.ts +22 -11
  130. package/dist/src/embeddings/lock.d.ts.map +1 -1
  131. package/dist/src/embeddings/lock.js +47 -29
  132. package/dist/src/embeddings/lock.js.map +1 -1
  133. package/dist/src/embeddings/retry.d.ts +5 -0
  134. package/dist/src/embeddings/retry.d.ts.map +1 -1
  135. package/dist/src/embeddings/retry.js +35 -0
  136. package/dist/src/embeddings/retry.js.map +1 -1
  137. package/dist/src/events/pending.d.ts +56 -0
  138. package/dist/src/events/pending.d.ts.map +1 -0
  139. package/dist/src/events/pending.js +108 -0
  140. package/dist/src/events/pending.js.map +1 -0
  141. package/dist/src/events/source.d.ts +60 -14
  142. package/dist/src/events/source.d.ts.map +1 -1
  143. package/dist/src/events/source.js +149 -31
  144. package/dist/src/events/source.js.map +1 -1
  145. package/dist/src/events/vector.d.ts +33 -0
  146. package/dist/src/events/vector.d.ts.map +1 -0
  147. package/dist/src/events/vector.js +57 -0
  148. package/dist/src/events/vector.js.map +1 -0
  149. package/dist/src/git/GitRunner.d.ts.map +1 -1
  150. package/dist/src/git/GitRunner.js +11 -8
  151. package/dist/src/git/GitRunner.js.map +1 -1
  152. package/dist/src/git/sourceGitControl.d.ts.map +1 -1
  153. package/dist/src/git/sourceGitControl.js +2 -1
  154. package/dist/src/git/sourceGitControl.js.map +1 -1
  155. package/dist/src/index.d.ts +5 -4
  156. package/dist/src/index.d.ts.map +1 -1
  157. package/dist/src/index.js +4 -3
  158. package/dist/src/index.js.map +1 -1
  159. package/dist/src/lifecycle.d.ts +20 -4
  160. package/dist/src/lifecycle.d.ts.map +1 -1
  161. package/dist/src/lifecycle.js +5 -1
  162. package/dist/src/lifecycle.js.map +1 -1
  163. package/dist/src/routes/health.js +6 -1
  164. package/dist/src/routes/health.js.map +1 -1
  165. package/dist/src/routes/pending.d.ts.map +1 -1
  166. package/dist/src/routes/pending.js +2 -1
  167. package/dist/src/routes/pending.js.map +1 -1
  168. package/dist/src/routes/sources.d.ts.map +1 -1
  169. package/dist/src/routes/sources.js +60 -11
  170. package/dist/src/routes/sources.js.map +1 -1
  171. package/dist/src/services/BridgeService.d.ts +2 -2
  172. package/dist/src/services/BridgeService.d.ts.map +1 -1
  173. package/dist/src/services/BridgeService.js +11 -2
  174. package/dist/src/services/BridgeService.js.map +1 -1
  175. package/dist/src/services/FilesystemService.d.ts +3 -1
  176. package/dist/src/services/FilesystemService.d.ts.map +1 -1
  177. package/dist/src/services/FilesystemService.js +3 -1
  178. package/dist/src/services/FilesystemService.js.map +1 -1
  179. package/dist/src/services/FilesystemUiService.js +1 -1
  180. package/dist/src/services/FilesystemUiService.js.map +1 -1
  181. package/dist/src/services/SyncScheduler.d.ts.map +1 -1
  182. package/dist/src/services/SyncScheduler.js +0 -14
  183. package/dist/src/services/SyncScheduler.js.map +1 -1
  184. package/dist/src/services/VectorHealthService.d.ts.map +1 -1
  185. package/dist/src/services/VectorHealthService.js +2 -46
  186. package/dist/src/services/VectorHealthService.js.map +1 -1
  187. package/dist/src/services/baselineRepair.d.ts +2 -2
  188. package/dist/src/services/baselineRepair.js +2 -2
  189. package/dist/src/services/declaredSources.d.ts +8 -1
  190. package/dist/src/services/declaredSources.d.ts.map +1 -1
  191. package/dist/src/services/declaredSources.js +19 -19
  192. package/dist/src/services/declaredSources.js.map +1 -1
  193. package/dist/src/store/dataFormats.d.ts +14 -3
  194. package/dist/src/store/dataFormats.d.ts.map +1 -1
  195. package/dist/src/store/dataFormats.js +15 -5
  196. package/dist/src/store/dataFormats.js.map +1 -1
  197. package/dist/src/sync/DeltaSyncRunner.d.ts.map +1 -1
  198. package/dist/src/sync/DeltaSyncRunner.js +78 -243
  199. package/dist/src/sync/DeltaSyncRunner.js.map +1 -1
  200. package/dist/src/sync/SyncJobQueue.d.ts +33 -4
  201. package/dist/src/sync/SyncJobQueue.d.ts.map +1 -1
  202. package/dist/src/sync/SyncJobQueue.js +179 -19
  203. package/dist/src/sync/SyncJobQueue.js.map +1 -1
  204. package/dist/src/sync/moveDetector.d.ts +2 -1
  205. package/dist/src/sync/moveDetector.d.ts.map +1 -1
  206. package/dist/src/sync/moveDetector.js +2 -1
  207. package/dist/src/sync/moveDetector.js.map +1 -1
  208. package/dist/src/tools/fs_search.d.ts.map +1 -1
  209. package/dist/src/tools/fs_search.js +8 -0
  210. package/dist/src/tools/fs_search.js.map +1 -1
  211. package/dist/src/tools/fs_write.js +3 -1
  212. package/dist/src/tools/fs_write.js.map +1 -1
  213. package/dist/src/usecases/chunkUpsert.d.ts +4 -0
  214. package/dist/src/usecases/chunkUpsert.d.ts.map +1 -1
  215. package/dist/src/usecases/chunkUpsert.js +103 -60
  216. package/dist/src/usecases/chunkUpsert.js.map +1 -1
  217. package/dist/src/usecases/embeddingBacklog.d.ts +31 -0
  218. package/dist/src/usecases/embeddingBacklog.d.ts.map +1 -0
  219. package/dist/src/usecases/embeddingBacklog.js +244 -0
  220. package/dist/src/usecases/embeddingBacklog.js.map +1 -0
  221. package/dist/src/usecases/listSourcePackages.js +17 -1
  222. package/dist/src/usecases/listSourcePackages.js.map +1 -1
  223. package/dist/src/usecases/mediaLane.d.ts +11 -4
  224. package/dist/src/usecases/mediaLane.d.ts.map +1 -1
  225. package/dist/src/usecases/mediaLane.js +67 -30
  226. package/dist/src/usecases/mediaLane.js.map +1 -1
  227. package/dist/src/usecases/pendingReview.d.ts.map +1 -1
  228. package/dist/src/usecases/pendingReview.js +24 -7
  229. package/dist/src/usecases/pendingReview.js.map +1 -1
  230. package/dist/src/usecases/purgeExcludedPoints.d.ts +2 -0
  231. package/dist/src/usecases/purgeExcludedPoints.d.ts.map +1 -1
  232. package/dist/src/usecases/purgeExcludedPoints.js +3 -2
  233. package/dist/src/usecases/purgeExcludedPoints.js.map +1 -1
  234. package/dist/src/usecases/readFiles.d.ts.map +1 -1
  235. package/dist/src/usecases/readFiles.js +33 -6
  236. package/dist/src/usecases/readFiles.js.map +1 -1
  237. package/dist/src/usecases/reconcileSourcePackageRoots.d.ts +31 -0
  238. package/dist/src/usecases/reconcileSourcePackageRoots.d.ts.map +1 -0
  239. package/dist/src/usecases/reconcileSourcePackageRoots.js +114 -0
  240. package/dist/src/usecases/reconcileSourcePackageRoots.js.map +1 -0
  241. package/dist/src/usecases/searchFiles.d.ts.map +1 -1
  242. package/dist/src/usecases/searchFiles.js +62 -64
  243. package/dist/src/usecases/searchFiles.js.map +1 -1
  244. package/dist/src/usecases/syncIndexedFile.d.ts +42 -0
  245. package/dist/src/usecases/syncIndexedFile.d.ts.map +1 -0
  246. package/dist/src/usecases/syncIndexedFile.js +242 -0
  247. package/dist/src/usecases/syncIndexedFile.js.map +1 -0
  248. package/dist/src/usecases/syncPointWrites.d.ts +5 -0
  249. package/dist/src/usecases/syncPointWrites.d.ts.map +1 -1
  250. package/dist/src/usecases/syncPointWrites.js +32 -5
  251. package/dist/src/usecases/syncPointWrites.js.map +1 -1
  252. package/dist/src/usecases/uploadBinary.d.ts.map +1 -1
  253. package/dist/src/usecases/uploadBinary.js +36 -49
  254. package/dist/src/usecases/uploadBinary.js.map +1 -1
  255. package/dist/src/usecases/vector/endpointGuard.js +2 -1
  256. package/dist/src/usecases/vector/endpointGuard.js.map +1 -1
  257. package/dist/src/usecases/vector/estimate.d.ts +7 -4
  258. package/dist/src/usecases/vector/estimate.d.ts.map +1 -1
  259. package/dist/src/usecases/vector/estimate.js +8 -5
  260. package/dist/src/usecases/vector/estimate.js.map +1 -1
  261. package/dist/src/usecases/vector/rebuildGeneration.d.ts +29 -5
  262. package/dist/src/usecases/vector/rebuildGeneration.d.ts.map +1 -1
  263. package/dist/src/usecases/vector/rebuildGeneration.js +224 -82
  264. package/dist/src/usecases/vector/rebuildGeneration.js.map +1 -1
  265. package/dist/src/usecases/vectorMaintenance.d.ts +46 -4
  266. package/dist/src/usecases/vectorMaintenance.d.ts.map +1 -1
  267. package/dist/src/usecases/vectorMaintenance.js +190 -11
  268. package/dist/src/usecases/vectorMaintenance.js.map +1 -1
  269. package/dist/src/usecases/write/commit.d.ts +6 -8
  270. package/dist/src/usecases/write/commit.d.ts.map +1 -1
  271. package/dist/src/usecases/write/commit.js +96 -112
  272. package/dist/src/usecases/write/commit.js.map +1 -1
  273. package/dist/src/usecases/write/content.js +1 -2
  274. package/dist/src/usecases/write/content.js.map +1 -1
  275. package/dist/src/usecases/write/ports.d.ts +1 -0
  276. package/dist/src/usecases/write/ports.d.ts.map +1 -1
  277. package/dist/src/vector/FilesystemVectorIndex.d.ts +34 -3
  278. package/dist/src/vector/FilesystemVectorIndex.d.ts.map +1 -1
  279. package/dist/src/vector/FilesystemVectorIndex.js +254 -20
  280. package/dist/src/vector/FilesystemVectorIndex.js.map +1 -1
  281. package/dist/src/vector/InMemoryVectorIndex.d.ts +9 -2
  282. package/dist/src/vector/InMemoryVectorIndex.d.ts.map +1 -1
  283. package/dist/src/vector/InMemoryVectorIndex.js +25 -6
  284. package/dist/src/vector/InMemoryVectorIndex.js.map +1 -1
  285. package/dist/src/vector/QdrantVectorIndex.d.ts +35 -9
  286. package/dist/src/vector/QdrantVectorIndex.d.ts.map +1 -1
  287. package/dist/src/vector/QdrantVectorIndex.js +209 -90
  288. package/dist/src/vector/QdrantVectorIndex.js.map +1 -1
  289. package/dist/src/vector/qdrantFilter.d.ts +3 -1
  290. package/dist/src/vector/qdrantFilter.d.ts.map +1 -1
  291. package/dist/src/vector/qdrantFilter.js +2 -0
  292. package/dist/src/vector/qdrantFilter.js.map +1 -1
  293. package/dist/src/vector/types.d.ts +81 -0
  294. package/dist/src/vector/types.d.ts.map +1 -1
  295. package/dist/src/vector/types.js +2 -0
  296. package/dist/src/vector/types.js.map +1 -1
  297. package/dist/src/wiring.d.ts +6 -0
  298. package/dist/src/wiring.d.ts.map +1 -1
  299. package/dist/src/wiring.js +62 -3
  300. package/dist/src/wiring.js.map +1 -1
  301. package/dist/tools/fs_search.json +2 -2
  302. package/docs/drive-overview.md +2 -2
  303. package/instructions/brain-model.md +1 -1
  304. package/package.json +999 -10
  305. package/rules/brain-rules.md +1 -1
  306. package/skills/connect-business-data/SKILL.md +6 -4
  307. package/skills/create-package/SKILL.md +14 -12
  308. package/skills/create-package/references/config-and-credentials.md +3 -3
  309. package/skills/create-package/references/connectors-and-uri-policies.md +5 -3
  310. package/skills/create-package/references/manifest-and-discovery.md +4 -3
  311. package/skills/create-package/references/runtime-and-build.md +9 -9
  312. package/skills/create-package/references/skills-and-context.md +3 -3
  313. package/skills/create-package/references/surfaces-and-design.md +2 -1
  314. package/skills/create-package/references/team-and-workflows.md +2 -2
  315. package/skills/create-package/references/test-and-ship.md +15 -15
  316. package/skills/create-package/references/tools-and-schemas.md +1 -1
  317. package/skills/create-package/scripts/check-package.sh +3 -3
  318. package/skills/create-package/scripts/verify-loaded.sh +16 -16
  319. package/skills/manage-files/SKILL.md +2 -2
  320. package/skills/manage-sources/SKILL.md +16 -15
  321. package/skills/manage-sources/scripts/reembed.sh +9 -3
  322. package/skills/sync/SKILL.md +4 -4
  323. package/tools/fs_search.json +2 -2
  324. package/dist/app/chunks/bash-M45GHPBQ.js +0 -1
  325. package/dist/app/chunks/c-X3REOAWD.js +0 -1
  326. package/dist/app/chunks/cpp-VOWI743W.js +0 -1
  327. package/dist/app/chunks/css-2ZVPHE25.js +0 -1
  328. package/dist/app/chunks/graphql-7V2NP54C.js +0 -1
  329. package/dist/app/chunks/html-UF3LFLNA.js +0 -1
  330. package/dist/app/chunks/java-PNTAU4L3.js +0 -1
  331. package/dist/app/chunks/javascript-4JJTQGEL.js +0 -1
  332. package/dist/app/chunks/json-VLQ6D3JH.js +0 -1
  333. package/dist/app/chunks/jsx-KQKSLAAH.js +0 -1
  334. package/dist/app/chunks/lua-UFPYUJ2O.js +0 -1
  335. package/dist/app/chunks/r-QEZB45SR.js +0 -1
  336. package/dist/app/chunks/sql-DTZHNUZP.js +0 -1
  337. package/dist/app/chunks/tsx-WPR2WRZD.js +0 -1
  338. package/dist/app/chunks/typescript-LWO362OA.js +0 -1
  339. package/dist/app/chunks/xml-A5H72RTS.js +0 -1
  340. package/dist/app/chunks/yaml-MXHSIJCI.js +0 -1
  341. package/dist/src/services/purgePendingNodes.d.ts +0 -32
  342. package/dist/src/services/purgePendingNodes.d.ts.map +0 -1
  343. package/dist/src/services/purgePendingNodes.js +0 -61
  344. package/dist/src/services/purgePendingNodes.js.map +0 -1
  345. /package/dist/app/chunks/{chunk-737Y24HS.js → chunk-3JASFUPF.js} +0 -0
  346. /package/dist/app/chunks/{chunk-DKD2L57N.js → chunk-6EYLOQ4F.js} +0 -0
  347. /package/dist/app/chunks/{chunk-KYH5EHHY.js → chunk-7YRZ5LOQ.js} +0 -0
  348. /package/dist/app/chunks/{chunk-6TC3DVWV.js → chunk-C7LU4RID.js} +0 -0
  349. /package/dist/app/chunks/{chunk-TY33BMKR.js → chunk-CD52YDZP.js} +0 -0
  350. /package/dist/app/chunks/{chunk-OLEIKJ3X.js → chunk-DCJKTCJ5.js} +0 -0
  351. /package/dist/app/chunks/{chunk-QLBZ4JR2.js → chunk-EXIU2KBV.js} +0 -0
  352. /package/dist/app/chunks/{chunk-SFUNBBEA.js → chunk-FDP4LO4P.js} +0 -0
  353. /package/dist/app/chunks/{chunk-BGRVFATT.js → chunk-HNETUS7U.js} +0 -0
  354. /package/dist/app/chunks/{chunk-4QNMHAIR.js → chunk-LBFZJEDR.js} +0 -0
  355. /package/dist/app/chunks/{chunk-TRRUHDPN.js → chunk-ULRXL5VM.js} +0 -0
  356. /package/dist/app/chunks/{chunk-S6B4WWIF.js → chunk-XJK47SMJ.js} +0 -0
  357. /package/dist/app/chunks/{chunk-DZ5C5FKI.js → chunk-YYAAIAU2.js} +0 -0
  358. /package/dist/app/chunks/{clojure-OC6KPSJO.js → clojure-4QCN4GHG.js} +0 -0
  359. /package/dist/app/chunks/{core-KGE7TQJ3.js → core-ZHTX3P2Q.js} +0 -0
  360. /package/dist/app/chunks/{csharp-E7VIFITL.js → csharp-HQWR4N52.js} +0 -0
  361. /package/dist/app/chunks/{dark-plus-BOSCZXE4.js → dark-plus-GYPKKZES.js} +0 -0
  362. /package/dist/app/chunks/{dart-6Y3X27SZ.js → dart-FO4TTVO2.js} +0 -0
  363. /package/dist/app/chunks/{diff-TR2NPA64.js → diff-SHANV4YC.js} +0 -0
  364. /package/dist/app/chunks/{dist-T32U2VVR.js → dist-WSDF34DM.js} +0 -0
  365. /package/dist/app/chunks/{docker-N33HOW54.js → docker-VX55HTDS.js} +0 -0
  366. /package/dist/app/chunks/{go-6DGG5UTP.js → go-5UCPEC6S.js} +0 -0
  367. /package/dist/app/chunks/{haskell-KK36PMMM.js → haskell-25PJ3OSG.js} +0 -0
  368. /package/dist/app/chunks/{ini-VHVQ5TPB.js → ini-BJIVD5MK.js} +0 -0
  369. /package/dist/app/chunks/{kotlin-44WS3JHE.js → kotlin-MNR6XOEQ.js} +0 -0
  370. /package/dist/app/chunks/{less-5WZ3KLAK.js → less-KA5JURX6.js} +0 -0
  371. /package/dist/app/chunks/{light-plus-HGGBC43G.js → light-plus-QXH2UUWZ.js} +0 -0
  372. /package/dist/app/chunks/{make-X7RXMVW7.js → make-LPD5KOCO.js} +0 -0
  373. /package/dist/app/chunks/{markdown-46IKUAIB.js → markdown-LMWF6MQR.js} +0 -0
  374. /package/dist/app/chunks/{mdx-DGLHDAO7.js → mdx-WPMNN5BS.js} +0 -0
  375. /package/dist/app/chunks/{nix-Q6FYQZLX.js → nix-QGWLUUMZ.js} +0 -0
  376. /package/dist/app/chunks/{powershell-L4KJJ6DK.js → powershell-7GSBBEFF.js} +0 -0
  377. /package/dist/app/chunks/{prisma-IKS4LVH2.js → prisma-FPMPQISO.js} +0 -0
  378. /package/dist/app/chunks/{proto-AYCDOTJO.js → proto-7KDX5Z2U.js} +0 -0
  379. /package/dist/app/chunks/{python-KXMCSAFQ.js → python-CFG4FTQW.js} +0 -0
  380. /package/dist/app/chunks/{rust-J3BC3P6V.js → rust-X7A37WU3.js} +0 -0
  381. /package/dist/app/chunks/{scala-AYIIHBJK.js → scala-OYHJSUG2.js} +0 -0
  382. /package/dist/app/chunks/{swift-QPHHCQD3.js → swift-PE7VNYW5.js} +0 -0
  383. /package/dist/app/chunks/{toml-UV7JK7K7.js → toml-ETQRDILP.js} +0 -0
@@ -1,8 +1,11 @@
1
+ import { syncIndexedFile, createSyncJobEmbedder, isBinaryFile } from '../usecases/syncIndexedFile.js';
2
+ import { looksBinaryContent, BINARY_SNIFF_CHARS } from '../domain/text.js';
1
3
  import { createHash } from 'node:crypto';
2
4
  import { deriveSourceKind, normalizeSource } from '../domain/source.js';
3
5
  import { resolveOsUri } from '../domain/paths.js';
4
6
  import { uriAncestors, extractFilename } from '../domain/uri.js';
5
7
  import { buildVersionInfo } from '../domain/versioning.js';
8
+ import { embeddingUnavailableReason } from '../embeddings/factory.js';
6
9
  import { isEmbeddingBudgetStopError } from '../embeddings/usage.js';
7
10
  import { ConnectorNotFoundError } from '@neuralis/package-system/contracts';
8
11
  import { compileSyncFilters, isUriIndexableUnderFilters } from '../domain/syncignore.js';
@@ -11,11 +14,11 @@ import { isAppendShaped } from '../domain/chunker.js';
11
14
  import { getBrainConfigProvider, getBrainConfigNumber } from '../config/env.js';
12
15
  import { resolveSyncCategory, computeContributionEnrichment, buildEnrichmentRefresh, isEnrichmentCurrent, } from './categoryInference.js';
13
16
  import { MoveClaims } from './moveDetector.js';
14
- import { upsertChunksForContent, relocateChunksForParent, pickUriNode } from '../usecases/chunkUpsert.js';
17
+ import { pickUriNode } from '../usecases/chunkUpsert.js';
15
18
  import { uriLogHash } from '../domain/contentHash.js';
16
19
  import { purgeExcludedPoints } from '../usecases/purgeExcludedPoints.js';
17
20
  import { emptyMediaSkipCounts, mediaKindOf, mediaLaneOn, mediaSkipSummary, upsertMediaFromSource, } from '../usecases/mediaLane.js';
18
- import { syncEmbeddingText, syncStoredText, hashSyncedFile, storedVectorMatchesText, isVectorMissingError, tombstoneSyncedPoint, readHealContent, } from '../usecases/syncPointWrites.js';
21
+ import { hashSyncedFile, tombstoneSyncedPoint, } from '../usecases/syncPointWrites.js';
19
22
  import { noopLogger } from '@neuralis/package-system/data';
20
23
  const SCROLL_BATCH = 200;
21
24
  /**
@@ -46,6 +49,10 @@ const INVENTORY_PAYLOAD_FIELDS = [
46
49
  // A payload-only write REPLACES the payload (`overwritePayload`), so the
47
50
  // vector's model marker must travel with every row a writer might spread.
48
51
  'embed_model',
52
+ 'embedding_status',
53
+ 'embedding_input_hash',
54
+ 'embedding_generation',
55
+ 'embedding_updated_at',
49
56
  // …and so must a media point's modality (the purge's lane decision reads it too).
50
57
  'modality',
51
58
  'recovery_only',
@@ -87,19 +94,6 @@ function limitConcurrency(tasks, concurrency, signal) {
87
94
  const workers = Array.from({ length: Math.min(concurrency, tasks.length) }, () => worker());
88
95
  return Promise.all(workers).then(() => results);
89
96
  }
90
- const BINARY_EXTENSIONS = new Set([
91
- '.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.ico', '.bmp',
92
- '.mp4', '.webm', '.avi', '.mov', '.mkv',
93
- '.mp3', '.wav', '.ogg', '.flac', '.aac',
94
- '.zip', '.tar', '.gz', '.bz2', '.7z', '.rar',
95
- '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx',
96
- '.exe', '.dll', '.so', '.dylib', '.wasm',
97
- '.ttf', '.otf', '.woff', '.woff2', '.eot',
98
- ]);
99
- function isBinaryFile(filename) {
100
- const ext = filename.slice(filename.lastIndexOf('.')).toLowerCase();
101
- return BINARY_EXTENSIONS.has(ext);
102
- }
103
97
  function isMissingFileError(error) {
104
98
  return typeof error === 'object' && error !== null && 'code' in error
105
99
  && error.code === 'ENOENT';
@@ -277,7 +271,10 @@ export class DeltaSyncRunner {
277
271
  const uri = typeof point.payload.uri === 'string' ? point.payload.uri : '';
278
272
  if (!uri || !shouldSyncUri(uri) || knownUris.has(uri))
279
273
  continue;
280
- if (point.payload.status === 'deleted' || point.payload.category === 'chunk')
274
+ // A point under review is never paired as a move: relocating it would
275
+ // strand its review record at the old uri. It is tombstoned below like
276
+ // any vanished file, and the new uri is an ordinary add.
277
+ if (point.payload.status === 'deleted' || point.payload.status === 'pending_review' || point.payload.category === 'chunk')
281
278
  continue;
282
279
  disappeared.set(uri, {
283
280
  pointId: point.id,
@@ -292,11 +289,15 @@ export class DeltaSyncRunner {
292
289
  let filesMoved = 0;
293
290
  let totalChunksEmbedded = 0;
294
291
  let totalChunksSkipped = 0;
292
+ const embeddingReasons = new Set();
295
293
  const mediaSkipped = emptyMediaSkipCounts();
296
294
  const syncErrors = [];
297
295
  const movedOldRefs = new Set();
298
296
  emitProgress({ phase: 'processing', processed: 0, total: changed.length });
299
297
  const syncConcurrency = Math.max(1, getBrainConfigNumber('brainSyncConcurrency', 'BRAIN_SYNC_CONCURRENCY', DEFAULT_SYNC_CONCURRENCY));
298
+ const binarySniffChars = binarySniffCharsSetting();
299
+ const binaryUris = new Set();
300
+ let binarySkipped = 0;
300
301
  let processed = 0;
301
302
  // Credential-use deny / embedding daily cap short-circuit: the first
302
303
  // typed stop error stops every not-yet-started task — a denied window
@@ -312,7 +313,7 @@ export class DeltaSyncRunner {
312
313
  return { entry, upserted: { action: 'skipped', chunksEmbedded: 0, chunksSkipped: 0 }, error: null };
313
314
  }
314
315
  const existing = existingByUri.get(entry.uri) ?? null;
315
- return this.#upsertFromSource(normalizedJob, connector, entry, existing, moves)
316
+ return this.#upsertFromSource(normalizedJob, connector, entry, existing, moves, binarySniffChars)
316
317
  .then((upserted) => ({ entry, upserted, error: null }))
317
318
  .catch((error) => {
318
319
  if (normalizedJob.signal?.aborted)
@@ -331,6 +332,8 @@ export class DeltaSyncRunner {
331
332
  if (r.status !== 'fulfilled' || !r.value)
332
333
  continue;
333
334
  const { entry, upserted, error } = r.value;
335
+ if (upserted?.embeddingDegraded)
336
+ embeddingReasons.add(upserted.embeddingDegraded);
334
337
  if (error || !upserted) {
335
338
  filesSkipped += 1;
336
339
  if (syncErrors.length < 20)
@@ -340,6 +343,10 @@ export class DeltaSyncRunner {
340
343
  filesSkipped += 1;
341
344
  if (upserted.mediaSkip)
342
345
  mediaSkipped[upserted.mediaSkip] += 1;
346
+ if (upserted.binarySkip)
347
+ binarySkipped += 1;
348
+ if (upserted.binarySkip === 'content')
349
+ binaryUris.add(entry.uri);
343
350
  }
344
351
  else {
345
352
  if (upserted.action === 'added')
@@ -419,30 +426,11 @@ export class DeltaSyncRunner {
419
426
  const point = sweepPoints.get(uri);
420
427
  if (!point)
421
428
  continue; // vanished between the inventory and the hydrate
422
- // A content-less point (written before the write path kept inline
423
- // content) is HEALED from disk when the file still holds the bytes
424
- // its vector was built from — the uri already passed the index gate
425
- // above. Otherwise its category is never re-derived from an empty
426
- // string: that would demote a declared contribution the write path
427
- // already resolved.
428
- const inline = typeof point.payload.content === 'string' ? point.payload.content : undefined;
429
- let healed;
430
- try {
431
- healed = inline === undefined ? await readHealContent(connector, point) : undefined;
432
- }
433
- catch (error) {
434
- // A heal is an optional backfill for a point whose vector is fine:
435
- // an unreadable file is reported, never a failed pass — that would
436
- // freeze the checkpoint and park the source in error for good.
437
- this.#logger.warn('sync.runner.heal.read_failed', {
438
- uri,
439
- code: error?.code ?? null,
440
- error: error instanceof Error ? error.message : String(error),
441
- });
442
- }
443
- const content = inline ?? healed;
444
- const derived = buildEnrichmentRefresh(point.payload, uri, content, computeContributionEnrichment(uri, content ?? ''));
445
- const refreshed = healed === undefined ? derived : { ...(derived ?? point.payload), content: healed };
429
+ // A point without inline text (a media point) never has its category
430
+ // re-derived from an empty string: that would demote a declared
431
+ // contribution the write path already resolved.
432
+ const content = typeof point.payload.content === 'string' ? point.payload.content : undefined;
433
+ const refreshed = buildEnrichmentRefresh(point.payload, uri, content, computeContributionEnrichment(uri, content ?? ''));
446
434
  // Write even when nothing DRIFTED: this is the one-time upgrade pass
447
435
  // that lands the stamp, and without it an already-correct point stays
448
436
  // unstamped and is re-hydrated by every later full sync. The write is
@@ -452,13 +440,12 @@ export class DeltaSyncRunner {
452
440
  // EXCEPT for a point whose content is not in hand: `stampEnrichment`
453
441
  // REMOVES the stamp from an underivable payload by design, so such a
454
442
  // point can never become current and an unconditional write here would
455
- // re-write it on EVERY full pass, forever. A heal that found no
456
- // matching bytes leaves the point here. Drift still writes; a no-op
443
+ // re-write it on EVERY full pass, forever. Drift still writes; a no-op
457
444
  // upgrade on an underivable point does not.
458
445
  if (!refreshed && content === undefined)
459
446
  continue;
460
447
  try {
461
- await this.#deps.vector.upsert({ id: point.id, payload: refreshed ?? point.payload });
448
+ await this.#deps.vector.writePayload({ id: point.id, payload: refreshed ?? point.payload });
462
449
  if (refreshed)
463
450
  enrichmentRefreshed += 1;
464
451
  }
@@ -497,6 +484,9 @@ export class DeltaSyncRunner {
497
484
  const media = mediaKindOf(extractFilename(String(point.payload.uri ?? '')) ?? '');
498
485
  return media !== null && !mediaLaneOn(normalizedJob.syncConfig.media, media.kind);
499
486
  },
487
+ // A file this pass READ and judged binary by content: a point an
488
+ // earlier pass left is withdrawn here, recovery-aware like a pattern.
489
+ binaryUris,
500
490
  signal: normalizedJob.signal,
501
491
  });
502
492
  for (const message of purged.errors)
@@ -583,12 +573,14 @@ export class DeltaSyncRunner {
583
573
  chunksEmbedded: totalChunksEmbedded,
584
574
  chunksSkipped: totalChunksSkipped,
585
575
  durationMs: Date.now() - startedAt,
576
+ ...(embeddingReasons.size ? { embeddingDegraded: [...embeddingReasons] } : {}),
586
577
  ...(filesTotal !== undefined ? { filesTotal } : {}),
587
578
  ...(indexedTotal !== undefined ? { indexedTotal } : {}),
588
579
  ...(unindexedTotal !== undefined ? { unindexedTotal } : {}),
589
580
  ...(fullScan.truncated ? { truncated: true, filesScanCap: scanCap } : {}),
590
581
  ...(checkpoint ? { checkpoint } : {}),
591
582
  ...(mediaSkipSummary(mediaSkipped) ? { mediaSkipped } : {}),
583
+ ...(binarySkipped > 0 ? { binarySkipped } : {}),
592
584
  ...(syncErrors.length > 0 ? {
593
585
  error: `${syncErrors.length} sync item(s) failed: ${syncErrors.join(' | ')}`,
594
586
  errors: syncErrors,
@@ -668,6 +660,7 @@ export class DeltaSyncRunner {
668
660
  let filesMoved = 0;
669
661
  let totalChunksEmbedded = 0;
670
662
  let totalChunksSkipped = 0;
663
+ const embeddingReasons = new Set();
671
664
  const syncErrors = [];
672
665
  const movedOldRefs = new Set();
673
666
  const disappeared = new Map();
@@ -677,7 +670,8 @@ export class DeltaSyncRunner {
677
670
  continue;
678
671
  disappeared.set(uri, {
679
672
  pointId: point.id,
680
- contentHash: typeof point.payload.content_hash === 'string' ? point.payload.content_hash : '',
673
+ // No hash, no move claim: a point under review is tombstoned, never relocated.
674
+ contentHash: point.payload.status !== 'pending_review' && typeof point.payload.content_hash === 'string' ? point.payload.content_hash : '',
681
675
  });
682
676
  }
683
677
  const moves = new MoveClaims(disappeared);
@@ -699,6 +693,8 @@ export class DeltaSyncRunner {
699
693
  // fail-fasts every tick; documented residual.)
700
694
  let useLimitedError = null;
701
695
  const mediaSkipped = emptyMediaSkipCounts();
696
+ const binarySniffChars = binarySniffCharsSetting();
697
+ let binarySkipped = 0;
702
698
  const targetedTasks = changedUris.map((uri) => async () => {
703
699
  if (job.signal?.aborted || useLimitedError)
704
700
  return null;
@@ -718,7 +714,7 @@ export class DeltaSyncRunner {
718
714
  modifiedAt: now,
719
715
  ...(typeof stat?.size === 'number' ? { size: stat.size } : {}),
720
716
  };
721
- const upserted = await this.#upsertFromSource(job, connector, entry, existing, moves);
717
+ const upserted = await this.#upsertFromSource(job, connector, entry, existing, moves, binarySniffChars);
722
718
  return { uri, existing, upserted, error: null };
723
719
  }
724
720
  catch (error) {
@@ -741,6 +737,8 @@ export class DeltaSyncRunner {
741
737
  continue;
742
738
  const { uri, existing, upserted, error } = settled.value;
743
739
  if (upserted) {
740
+ if (upserted.embeddingDegraded)
741
+ embeddingReasons.add(upserted.embeddingDegraded);
744
742
  if (upserted.action === 'added')
745
743
  filesAdded += 1;
746
744
  else if (upserted.action === 'updated')
@@ -754,6 +752,8 @@ export class DeltaSyncRunner {
754
752
  filesSkipped += 1;
755
753
  if (upserted.mediaSkip)
756
754
  mediaSkipped[upserted.mediaSkip] += 1;
755
+ if (upserted.binarySkip)
756
+ binarySkipped += 1;
757
757
  }
758
758
  totalChunksEmbedded += upserted.chunksEmbedded;
759
759
  totalChunksSkipped += upserted.chunksSkipped;
@@ -818,7 +818,9 @@ export class DeltaSyncRunner {
818
818
  chunksEmbedded: totalChunksEmbedded,
819
819
  chunksSkipped: totalChunksSkipped,
820
820
  durationMs: Date.now() - startedAt,
821
+ ...(embeddingReasons.size ? { embeddingDegraded: [...embeddingReasons] } : {}),
821
822
  ...(mediaSkipSummary(mediaSkipped) ? { mediaSkipped } : {}),
823
+ ...(binarySkipped > 0 ? { binarySkipped } : {}),
822
824
  ...(cancelled ? { error: 'Sync cancelled' } : syncErrors.length > 0 ? {
823
825
  error: `${syncErrors.length} sync item(s) failed: ${syncErrors.join(' | ')}`,
824
826
  errors: syncErrors,
@@ -945,13 +947,23 @@ export class DeltaSyncRunner {
945
947
  } while (cursor);
946
948
  return points;
947
949
  }
950
+ #embeddingByJob = new WeakMap();
951
+ #embedderFor(job) {
952
+ let embedder = this.#embeddingByJob.get(job);
953
+ if (!embedder) {
954
+ embedder = createSyncJobEmbedder(this.#deps.embedder);
955
+ this.#embeddingByJob.set(job, embedder);
956
+ }
957
+ return embedder;
958
+ }
948
959
  /** The ACTIVE model's modalities, asked once per job (a text-only port answers `['text']`). */
949
960
  #modalitiesByJob = new WeakMap();
950
961
  #modalitiesFor(job) {
951
962
  let pending = this.#modalitiesByJob.get(job);
952
963
  if (!pending) {
953
964
  pending = this.#deps.embedder.modalities
954
- ? this.#deps.embedder.modalities().catch(() => ['text'])
965
+ ? this.#deps.embedder.modalities().catch(error => { if (!embeddingUnavailableReason(error))
966
+ throw error; return ['text']; })
955
967
  : Promise.resolve(['text']);
956
968
  this.#modalitiesByJob.set(job, pending);
957
969
  }
@@ -970,7 +982,7 @@ export class DeltaSyncRunner {
970
982
  const id = existing?.id ?? deterministicExternalNodeId(job, uri);
971
983
  const now = this.#deps.clock.nowIso();
972
984
  const osUri = resolveOsUri(uri, connector);
973
- const outcome = await upsertMediaFromSource({ vector: this.#deps.vector, embedder: this.#deps.embedder }, connector, {
985
+ const outcome = await upsertMediaFromSource({ vector: this.#deps.vector, embedder: this.#embedderFor(job) }, connector, {
974
986
  kind: media.kind,
975
987
  mime: media.mime,
976
988
  uri,
@@ -1024,12 +1036,14 @@ export class DeltaSyncRunner {
1024
1036
  return outcome.reason ? { ...skipped, mediaSkip: outcome.reason } : skipped;
1025
1037
  return {
1026
1038
  action: existing ? 'updated' : 'added',
1027
- chunksEmbedded: Math.max(0, outcome.pagesEmbedded - 1),
1039
+ chunksEmbedded: outcome.chunksEmbedded,
1028
1040
  chunksSkipped: 0,
1041
+ ...(outcome.embeddingDegraded ? { embeddingDegraded: outcome.embeddingDegraded } : {}),
1029
1042
  };
1030
1043
  }
1031
- async #upsertFromSource(job, connector, entry, indexedAtUri, moves) {
1044
+ async #upsertFromSource(job, connector, entry, indexedAtUri, moves, binarySniffChars) {
1032
1045
  const skipped = { action: 'skipped', chunksEmbedded: 0, chunksSkipped: 0 };
1046
+ const binary = (by) => ({ ...skipped, binarySkip: by });
1033
1047
  const uri = entry.uri;
1034
1048
  const filename = extractFilename(uri);
1035
1049
  if (!filename)
@@ -1040,7 +1054,7 @@ export class DeltaSyncRunner {
1040
1054
  if (media)
1041
1055
  return this.#upsertMedia(job, connector, entry, indexedAtUri, filename, media);
1042
1056
  if (isBinaryFile(filename))
1043
- return skipped;
1057
+ return binary('extension');
1044
1058
  // Skip files larger than the size cap (live): `brainSyncMaxFileMb` (5 MB),
1045
1059
  // or `brainSyncMaxAppendFileMb` (20 MB) for an append-shaped file, whose
1046
1060
  // append re-embeds only the tail — never above the connector read cap
@@ -1052,6 +1066,8 @@ export class DeltaSyncRunner {
1052
1066
  return skipped;
1053
1067
  const readResult = await connector.read(entry.uri);
1054
1068
  const content = String(readResult.text ?? '');
1069
+ if (looksBinaryContent(content, binarySniffChars))
1070
+ return binary('content');
1055
1071
  const { contentHash: content_hash, provenPrefixChars, stored } = hashSyncedFile(filename, content, indexedAtUri?.payload);
1056
1072
  const now = this.#deps.clock.nowIso();
1057
1073
  // A new uri whose content is exactly ONE point that left disk in this pass
@@ -1074,201 +1090,20 @@ export class DeltaSyncRunner {
1074
1090
  const written = (action, chunks) => (movedFrom
1075
1091
  ? { action: 'moved', movedFrom, chunksEmbedded: chunks.embedded, chunksSkipped: chunks.skipped }
1076
1092
  : { action, chunksEmbedded: chunks.embedded, chunksSkipped: chunks.skipped });
1077
- const sourceChangedAt = entry.modifiedAt || now;
1078
- const restoringDraft = !movedFrom && existing?.payload.recovery_only === true
1079
- && existing.payload.status === 'pending_review' && existing.payload.content_hash === content_hash;
1080
- // If the file currently has a pending draft, do NOT overwrite draft content or undo state.
1081
- // Only refresh the last known upstream/source version metadata behind the file.
1082
- if (!movedFrom && existing?.payload?.status === 'pending_review' && !restoringDraft) {
1083
- const payload = {
1084
- ...existing.payload,
1085
- version: buildVersionInfo({
1086
- previous: existing.payload.version,
1087
- previousContent: existing.payload.content,
1088
- nextContent: existing.payload.content,
1089
- changedAt: existing.payload.version?.changedAt ?? existing.payload.updatedAt,
1090
- sourceChangedAt,
1091
- sourceVersion: content_hash,
1092
- indexedAt: now,
1093
- sync: {
1094
- ...(existing.payload.version?.sync ?? {}),
1095
- sourceUpdatedAt: entry.modifiedAt,
1096
- sourceSize: entry.size,
1097
- syncedAt: now,
1098
- upstreamContentHash: content_hash,
1099
- lastSyncedAgentId: job.agentId,
1100
- status: 'stale',
1101
- },
1102
- }),
1103
- status: 'pending_review',
1104
- updatedAt: now,
1105
- };
1106
- if (existing.payload.recovery_only === true) {
1107
- await this.#deps.vector.retainPayload({ id, payload });
1108
- }
1109
- else {
1110
- await this.#deps.vector.upsert({ id, payload });
1111
- }
1112
- return written('updated', { embedded: 0, skipped: 0 });
1113
- }
1114
- const enrichment = computeContributionEnrichment(entry.uri, content);
1115
- // The first reuse gate — an unchanged committed file only refreshes its
1116
- // payload. A forced re-embed skips it, and keeps that payload instead
1117
- // (below): an unchanged file must not read as changed.
1118
- const sameContent = !movedFrom && existing?.payload?.content_hash === content_hash && existing.payload.status === 'committed' && !existing.payload.recovery_only;
1119
- if (!job.force && sameContent) {
1120
- // Payload-only refresh BEFORE the content-hash skip: unchanged files
1121
- // still pick up new category/frontmatter/manifest enrichment after a
1122
- // deploy (the stored vector is kept). One sync pass migrates a source.
1123
- // A point that lost its inline content gets it back here — it is in hand.
1124
- const contentless = typeof existing.payload.content !== 'string';
1125
- const derived = buildEnrichmentRefresh(existing.payload, entry.uri, content, enrichment);
1126
- const refreshed = contentless ? { ...(derived ?? existing.payload), content: stored } : derived;
1127
- // A hash-matched point that has NOT drifted still needs the stamp, or it
1128
- // stays a sweep candidate forever: the sweep skips it (it is in the
1129
- // changed set) and the next full pass no longer sees it as changed. One
1130
- // payload-only write here closes it in the same pass.
1131
- if (refreshed || !isEnrichmentCurrent(existing.payload)) {
1132
- await this.#deps.vector.upsert({ id, payload: refreshed ?? existing.payload });
1133
- }
1134
- return skipped;
1135
- }
1136
- // The parent vector is keyed on its embedding TEXT: when the stored one was
1137
- // built from the same text (an append past the text cap, a move that kept
1138
- // its filename), the parent write below is payload-only.
1139
- const embeddingText = syncEmbeddingText(filename, content);
1140
- const embedParent = () => this.#deps.embedder.embedText(embeddingText, job.signal ? { signal: job.signal } : undefined);
1141
- // The second reuse gate — the stored parent vector was built from this
1142
- // exact text. A forced re-embed skips it too.
1143
- const reuseVector = !job.force && existing && !existing.payload.recovery_only ? storedVectorMatchesText(existing.payload, embeddingText) : false;
1144
- let embedded = null;
1145
- try {
1146
- if (!reuseVector)
1147
- embedded = await embedParent();
1148
- }
1149
- catch (error) {
1150
- // An embed outage (exhausted credits, a provider 429) must not freeze the
1151
- // existing point's DERIVED metadata: the index keeps carrying the OLD
1152
- // content, so category / frontmatter / manifest flags are re-derived from
1153
- // THAT content, payload-only (vector kept) — exactly what the enrichment
1154
- // sweep would do, which skips this file only because it sits in the
1155
- // changed set. The file's own failure is still reported by the caller;
1156
- // nothing here claims the new content was indexed.
1157
- if (!movedFrom && existing?.payload && typeof existing.payload.content === 'string') {
1158
- const stale = existing.payload.content;
1159
- const refreshed = buildEnrichmentRefresh(existing.payload, entry.uri, stale, computeContributionEnrichment(entry.uri, stale));
1160
- if (refreshed) {
1161
- try {
1162
- await this.#deps.vector.upsert({ id, payload: refreshed });
1163
- }
1164
- catch {
1165
- // The embed failure is the error the caller reports; a failed
1166
- // metadata refresh changes nothing about that.
1167
- }
1168
- }
1169
- }
1170
- throw error;
1171
- }
1172
- // A forced re-embed of UNCHANGED content writes the stored payload back as
1173
- // it is (`updatedAt`, `version`, `createdAt`, …) with the inline text it
1174
- // embeds; only the vector and the boundary's `embed_model` stamp move.
1175
- const payload = (sameContent || restoringDraft) && existing ? { ...existing.payload, content: stored } : {
1176
- id,
1177
- uri,
1178
- folder_ancestors: uriAncestors(uri),
1179
- filename,
1180
- os_uri: resolveOsUri(uri, connector),
1181
- userId: job.userId,
1182
- projectId: job.projectId,
1183
- agentId: job.agentId,
1184
- ...(existing?.payload.userName ? { userName: existing.payload.userName } : {}),
1185
- // A payload-only write (the reused vector) keeps the stored marker; a
1186
- // vector write is re-stamped by the write boundary.
1187
- ...(existing?.payload.embed_model ? { embed_model: existing.payload.embed_model } : {}),
1188
- pinned: existing?.payload.pinned === true,
1189
- status: 'committed',
1190
- category: resolveSyncCategory(existing?.payload.category, entry.uri, content),
1191
- tags: existing?.payload.tags ?? [],
1192
- metadata: {
1193
- ...(existing?.payload.metadata ?? {}),
1194
- },
1195
- // Source-package enrichment (A3) — file points only, never chunks (F8).
1196
- ...(enrichment.manifest_usable ? { manifest_usable: true } : {}),
1197
- ...(enrichment.agent_owner ? { agent_owner: enrichment.agent_owner } : {}),
1198
- ...(enrichment.frontmatter ? { frontmatter: enrichment.frontmatter } : {}),
1199
- content: stored, // the indexed prefix; `content_hash` stays the WHOLE file's
1200
- content_hash,
1201
- createdAt: existing?.payload.createdAt ?? now,
1202
- updatedAt: now,
1203
- version: buildVersionInfo({
1204
- previous: existing?.payload.version,
1205
- previousContent: typeof existing?.payload.content === 'string' ? syncStoredText(existing.payload.content) : undefined,
1206
- nextContent: stored,
1207
- previousChangedAt: existing?.payload.version?.changedAt ?? existing?.payload.updatedAt,
1208
- changedAt: now,
1209
- sourceChangedAt,
1210
- sourceVersion: content_hash,
1211
- indexedAt: now,
1212
- sync: {
1213
- sourceUpdatedAt: entry.modifiedAt,
1214
- sourceSize: entry.size,
1215
- syncedAt: now,
1216
- upstreamContentHash: content_hash,
1217
- lastSyncedAgentId: job.agentId,
1218
- status: 'synced',
1219
- },
1220
- }),
1093
+ const result = await syncIndexedFile({ vector: this.#deps.vector, embedder: this.#embedderFor(job) }, {
1094
+ job, connector, entry, existing, id, filename, content, contentHash: content_hash,
1095
+ stored, provenPrefixChars, now, movedFrom, indexedAtUri: Boolean(indexedAtUri),
1096
+ });
1097
+ return result.action === 'skipped' ? skipped : {
1098
+ ...written(result.action, { embedded: result.chunksEmbedded, skipped: result.chunksSkipped }),
1099
+ ...(result.embeddingDegraded ? { embeddingDegraded: result.embeddingDegraded } : {}),
1221
1100
  };
1222
- // Chunk ingestion BEFORE the parent upsert: the parent's content_hash is
1223
- // the convergence marker — if an abort lands mid-chunking, the parent
1224
- // still carries the OLD hash, so the next run reprocesses the file and
1225
- // the deterministic chunk ids converge. (Parent-first left a window where
1226
- // a hash-matched skip would never backfill the missing chunks.)
1227
- let chunksEmbedded = 0;
1228
- let chunksSkipped = 0;
1229
- if (content.length > 0) {
1230
- // The chunks inherit the fields the parent point carries (a carried
1231
- // payload keeps its own writer's identity, so its chunks do too).
1232
- const parentFields = {
1233
- userId: payload.userId,
1234
- projectId: payload.projectId,
1235
- agentId: payload.agentId,
1236
- uri: payload.uri,
1237
- folder_ancestors: payload.folder_ancestors,
1238
- filename: payload.filename,
1239
- os_uri: payload.os_uri,
1240
- status: 'committed',
1241
- };
1242
- const chunkUsage = {};
1243
- const chunkResult = await upsertChunksForContent({ vector: this.#deps.vector, embedder: this.#deps.embedder }, id, parentFields, content, entry.uri, chunkUsage, {
1244
- ...(job.signal ? { signal: job.signal } : {}),
1245
- ...(provenPrefixChars !== undefined && !job.force ? { appendOf: { prefixChars: provenPrefixChars } } : {}),
1246
- ...(job.force ? { force: true } : {}),
1247
- });
1248
- chunksEmbedded = chunkResult.embedded;
1249
- chunksSkipped = chunkResult.skipped;
1250
- // A moved point's chunks kept their vectors (same ids, same text); only
1251
- // their denormalized location follows the parent, payload-only.
1252
- if (movedFrom)
1253
- await relocateChunksForParent({ vector: this.#deps.vector }, id, parentFields);
1254
- }
1255
- if (embedded) {
1256
- await this.#deps.vector.upsert({ id, vector: embedded.embedding, payload });
1257
- }
1258
- else {
1259
- try {
1260
- await this.#deps.vector.upsert({ id, payload });
1261
- }
1262
- catch (error) {
1263
- // The text matched but no vector is stored under the id: embed after all.
1264
- if (!isVectorMissingError(error))
1265
- throw error;
1266
- await this.#deps.vector.upsert({ id, vector: (await embedParent()).embedding, payload });
1267
- }
1268
- }
1269
- return written(indexedAtUri ? 'updated' : 'added', { embedded: chunksEmbedded, skipped: chunksSkipped });
1270
1101
  }
1271
1102
  }
1103
+ /** Read once per job, never per file (`brainSyncBinarySniffChars`, 0 = off). */
1104
+ function binarySniffCharsSetting() {
1105
+ return Math.max(0, Math.floor(getBrainConfigNumber('brainSyncBinarySniffChars', undefined, BINARY_SNIFF_CHARS)));
1106
+ }
1272
1107
  function deterministicExternalNodeId(job, sourceRef) {
1273
1108
  const hash = createHash('sha1')
1274
1109
  .update(`${job.userId}:${job.projectId}:${job.source}:${sourceRef}`)