@neuralis/brain-core 0.3.2 → 0.4.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 (388) hide show
  1. package/README.md +80 -1410
  2. package/app/README.md +1 -1
  3. package/app/cards/FilesystemCardShell.tsx +42 -4
  4. package/app/cards/FilesystemChangeCard.tsx +34 -11
  5. package/app/cards/README.md +6 -5
  6. package/app/cards/diffUtils.ts +99 -1
  7. package/app/filesystem/FilesystemHost.tsx +17 -2
  8. package/app/filesystem/api/README.md +3 -3
  9. package/app/filesystem/api/index.ts +35 -11
  10. package/app/filesystem/api/projectPackages.ts +13 -102
  11. package/app/filesystem/domain/types.ts +30 -10
  12. package/app/filesystem/hooks/README.md +3 -3
  13. package/app/filesystem/hooks/useDiscoverableSources.ts +19 -30
  14. package/app/filesystem/hooks/useFilesystemSSE.ts +1 -1
  15. package/app/filesystem/host/README.md +5 -3
  16. package/app/filesystem/host/buildFilesystemHostValue.ts +19 -0
  17. package/app/filesystem/host/installFilesystemHostComponents.tsx +1 -1
  18. package/app/filesystem/lib/sourceKindForm.ts +118 -39
  19. package/app/filesystem/lib/treeVisualState.tsx +98 -4
  20. package/app/filesystem/store/README.md +1 -0
  21. package/app/filesystem/store/filesystemStore.ts +86 -5
  22. package/app/filesystem/store/gitSlice.ts +5 -0
  23. package/app/filesystem/store/helpers.ts +17 -0
  24. package/app/filesystem/store/listSlice.ts +8 -0
  25. package/app/filesystem/ui/CodeEditor.tsx +18 -3
  26. package/app/filesystem/ui/FileEditor.tsx +15 -10
  27. package/app/filesystem/ui/FileTree.tsx +41 -16
  28. package/app/filesystem/ui/FolderPicker.tsx +251 -0
  29. package/app/filesystem/ui/GitControlPanel.tsx +5 -0
  30. package/app/filesystem/ui/PackagesPanel.tsx +52 -374
  31. package/app/filesystem/ui/PolicyEditor.tsx +109 -24
  32. package/app/filesystem/ui/README.md +17 -11
  33. package/app/filesystem/ui/RawMediaPreview.tsx +58 -0
  34. package/app/filesystem/ui/SourceBranchHeader.tsx +4 -4
  35. package/app/filesystem/ui/SourcesPanel.tsx +420 -360
  36. package/app/filesystem/ui/Toolbar.tsx +1 -2
  37. package/app/shared/filesystem.png +0 -0
  38. package/dist/app/host.js +53 -48
  39. package/dist/scripts/sourceRootPairV1.d.ts +47 -0
  40. package/dist/scripts/sourceRootPairV1.d.ts.map +1 -0
  41. package/dist/scripts/sourceRootPairV1.js +147 -0
  42. package/dist/scripts/sourceRootPairV1.js.map +1 -0
  43. package/dist/scripts/sourceToFolderV1.d.ts +56 -0
  44. package/dist/scripts/sourceToFolderV1.d.ts.map +1 -0
  45. package/dist/scripts/sourceToFolderV1.js +152 -0
  46. package/dist/scripts/sourceToFolderV1.js.map +1 -0
  47. package/dist/scripts/sourceToHostV1.d.ts +56 -0
  48. package/dist/scripts/sourceToHostV1.d.ts.map +1 -0
  49. package/dist/scripts/sourceToHostV1.js +132 -0
  50. package/dist/scripts/sourceToHostV1.js.map +1 -0
  51. package/dist/src/config/env.d.ts +8 -0
  52. package/dist/src/config/env.d.ts.map +1 -1
  53. package/dist/src/config/env.js +17 -6
  54. package/dist/src/config/env.js.map +1 -1
  55. package/dist/src/connectors/AppSourceConfigStore.d.ts +17 -3
  56. package/dist/src/connectors/AppSourceConfigStore.d.ts.map +1 -1
  57. package/dist/src/connectors/AppSourceConfigStore.js +46 -6
  58. package/dist/src/connectors/AppSourceConfigStore.js.map +1 -1
  59. package/dist/src/connectors/HostConnector.d.ts +201 -0
  60. package/dist/src/connectors/HostConnector.d.ts.map +1 -0
  61. package/dist/src/connectors/HostConnector.js +903 -0
  62. package/dist/src/connectors/HostConnector.js.map +1 -0
  63. package/dist/src/connectors/inProcessTransport.d.ts +131 -0
  64. package/dist/src/connectors/inProcessTransport.d.ts.map +1 -0
  65. package/dist/src/connectors/inProcessTransport.js +447 -0
  66. package/dist/src/connectors/inProcessTransport.js.map +1 -0
  67. package/dist/src/domain/BrainError.d.ts +14 -0
  68. package/dist/src/domain/BrainError.d.ts.map +1 -1
  69. package/dist/src/domain/BrainError.js +21 -0
  70. package/dist/src/domain/BrainError.js.map +1 -1
  71. package/dist/src/domain/access/callerPermissions.d.ts +29 -0
  72. package/dist/src/domain/access/callerPermissions.d.ts.map +1 -1
  73. package/dist/src/domain/access/callerPermissions.js +85 -5
  74. package/dist/src/domain/access/callerPermissions.js.map +1 -1
  75. package/dist/src/domain/access/nativeLocalFence.d.ts +65 -0
  76. package/dist/src/domain/access/nativeLocalFence.d.ts.map +1 -0
  77. package/dist/src/domain/access/nativeLocalFence.js +171 -0
  78. package/dist/src/domain/access/nativeLocalFence.js.map +1 -0
  79. package/dist/src/domain/access/uriPermission.js +3 -3
  80. package/dist/src/domain/access/uriPermission.js.map +1 -1
  81. package/dist/src/domain/byteRange.d.ts +15 -0
  82. package/dist/src/domain/byteRange.d.ts.map +1 -0
  83. package/dist/src/domain/byteRange.js +30 -0
  84. package/dist/src/domain/byteRange.js.map +1 -0
  85. package/dist/src/domain/defaultPermissions.d.ts.map +1 -1
  86. package/dist/src/domain/defaultPermissions.js +29 -0
  87. package/dist/src/domain/defaultPermissions.js.map +1 -1
  88. package/dist/src/domain/mime.d.ts +8 -16
  89. package/dist/src/domain/mime.d.ts.map +1 -1
  90. package/dist/src/domain/mime.js +10 -99
  91. package/dist/src/domain/mime.js.map +1 -1
  92. package/dist/src/domain/paths.d.ts.map +1 -1
  93. package/dist/src/domain/paths.js +5 -3
  94. package/dist/src/domain/paths.js.map +1 -1
  95. package/dist/src/domain/sourceConfig.d.ts +52 -19
  96. package/dist/src/domain/sourceConfig.d.ts.map +1 -1
  97. package/dist/src/domain/sourceConfig.js +103 -19
  98. package/dist/src/domain/sourceConfig.js.map +1 -1
  99. package/dist/src/domain/sourcePackages.d.ts +8 -8
  100. package/dist/src/domain/sourcePackages.d.ts.map +1 -1
  101. package/dist/src/domain/sourceRootPair.d.ts +88 -0
  102. package/dist/src/domain/sourceRootPair.d.ts.map +1 -0
  103. package/dist/src/domain/sourceRootPair.js +108 -0
  104. package/dist/src/domain/sourceRootPair.js.map +1 -0
  105. package/dist/src/domain/syncTypes.d.ts +8 -1
  106. package/dist/src/domain/syncTypes.d.ts.map +1 -1
  107. package/dist/src/domain/syncTypes.js +1 -0
  108. package/dist/src/domain/syncTypes.js.map +1 -1
  109. package/dist/src/domain/types.d.ts +29 -1
  110. package/dist/src/domain/types.d.ts.map +1 -1
  111. package/dist/src/domain/uri.d.ts.map +1 -1
  112. package/dist/src/domain/uri.js +3 -2
  113. package/dist/src/domain/uri.js.map +1 -1
  114. package/dist/src/embeddings/clients/GeminiEmbedder.d.ts.map +1 -1
  115. package/dist/src/embeddings/clients/GeminiEmbedder.js +2 -5
  116. package/dist/src/embeddings/clients/GeminiEmbedder.js.map +1 -1
  117. package/dist/src/embeddings/clients/OpenAIEmbedder.d.ts.map +1 -1
  118. package/dist/src/embeddings/clients/OpenAIEmbedder.js +2 -3
  119. package/dist/src/embeddings/clients/OpenAIEmbedder.js.map +1 -1
  120. package/dist/src/embeddings/clients/QwenEmbedder.d.ts +2 -0
  121. package/dist/src/embeddings/clients/QwenEmbedder.d.ts.map +1 -1
  122. package/dist/src/embeddings/clients/QwenEmbedder.js +10 -2
  123. package/dist/src/embeddings/clients/QwenEmbedder.js.map +1 -1
  124. package/dist/src/embeddings/clients/VoyageEmbedder.d.ts +2 -0
  125. package/dist/src/embeddings/clients/VoyageEmbedder.d.ts.map +1 -1
  126. package/dist/src/embeddings/clients/VoyageEmbedder.js +8 -1
  127. package/dist/src/embeddings/clients/VoyageEmbedder.js.map +1 -1
  128. package/dist/src/embeddings/factory.d.ts +5 -3
  129. package/dist/src/embeddings/factory.d.ts.map +1 -1
  130. package/dist/src/embeddings/factory.js +7 -3
  131. package/dist/src/embeddings/factory.js.map +1 -1
  132. package/dist/src/embeddings/models.d.ts +2 -3
  133. package/dist/src/embeddings/models.d.ts.map +1 -1
  134. package/dist/src/embeddings/models.js +1 -2
  135. package/dist/src/embeddings/models.js.map +1 -1
  136. package/dist/src/embeddings/retry.js +1 -1
  137. package/dist/src/embeddings/retry.js.map +1 -1
  138. package/dist/src/embeddings/types.d.ts +6 -0
  139. package/dist/src/embeddings/types.d.ts.map +1 -1
  140. package/dist/src/embeddings/types.js +11 -0
  141. package/dist/src/embeddings/types.js.map +1 -1
  142. package/dist/src/git/GitRunner.d.ts +110 -30
  143. package/dist/src/git/GitRunner.d.ts.map +1 -1
  144. package/dist/src/git/GitRunner.js +511 -199
  145. package/dist/src/git/GitRunner.js.map +1 -1
  146. package/dist/src/git/GitWatchRegistry.d.ts +41 -35
  147. package/dist/src/git/GitWatchRegistry.d.ts.map +1 -1
  148. package/dist/src/git/GitWatchRegistry.js +61 -79
  149. package/dist/src/git/GitWatchRegistry.js.map +1 -1
  150. package/dist/src/git/gitPlace.d.ts +61 -0
  151. package/dist/src/git/gitPlace.d.ts.map +1 -0
  152. package/dist/src/git/gitPlace.js +74 -0
  153. package/dist/src/git/gitPlace.js.map +1 -0
  154. package/dist/src/git/sourceGitControl.d.ts +31 -19
  155. package/dist/src/git/sourceGitControl.d.ts.map +1 -1
  156. package/dist/src/git/sourceGitControl.js +208 -92
  157. package/dist/src/git/sourceGitControl.js.map +1 -1
  158. package/dist/src/git/sourceGitStatus.js +1 -1
  159. package/dist/src/git/sourceGitStatus.js.map +1 -1
  160. package/dist/src/git/untrackedStats.js +1 -1
  161. package/dist/src/git/untrackedStats.js.map +1 -1
  162. package/dist/src/index.d.ts +2 -1
  163. package/dist/src/index.d.ts.map +1 -1
  164. package/dist/src/index.js +2 -1
  165. package/dist/src/index.js.map +1 -1
  166. package/dist/src/lifecycle.d.ts +12 -16
  167. package/dist/src/lifecycle.d.ts.map +1 -1
  168. package/dist/src/lifecycle.js +2 -1
  169. package/dist/src/lifecycle.js.map +1 -1
  170. package/dist/src/routes/approve.d.ts.map +1 -1
  171. package/dist/src/routes/approve.js +3 -3
  172. package/dist/src/routes/approve.js.map +1 -1
  173. package/dist/src/routes/git.d.ts.map +1 -1
  174. package/dist/src/routes/git.js +183 -54
  175. package/dist/src/routes/git.js.map +1 -1
  176. package/dist/src/routes/health.d.ts.map +1 -1
  177. package/dist/src/routes/health.js +8 -5
  178. package/dist/src/routes/health.js.map +1 -1
  179. package/dist/src/routes/helpers/uriGuard.d.ts +1 -1
  180. package/dist/src/routes/helpers/uriGuard.d.ts.map +1 -1
  181. package/dist/src/routes/helpers/uriGuard.js +3 -2
  182. package/dist/src/routes/helpers/uriGuard.js.map +1 -1
  183. package/dist/src/routes/helpers.d.ts +20 -4
  184. package/dist/src/routes/helpers.d.ts.map +1 -1
  185. package/dist/src/routes/helpers.js +38 -5
  186. package/dist/src/routes/helpers.js.map +1 -1
  187. package/dist/src/routes/list.d.ts.map +1 -1
  188. package/dist/src/routes/list.js +5 -6
  189. package/dist/src/routes/list.js.map +1 -1
  190. package/dist/src/routes/pending.d.ts.map +1 -1
  191. package/dist/src/routes/pending.js +5 -5
  192. package/dist/src/routes/pending.js.map +1 -1
  193. package/dist/src/routes/policies.d.ts +6 -4
  194. package/dist/src/routes/policies.d.ts.map +1 -1
  195. package/dist/src/routes/policies.js +22 -16
  196. package/dist/src/routes/policies.js.map +1 -1
  197. package/dist/src/routes/raw.d.ts.map +1 -1
  198. package/dist/src/routes/raw.js +68 -14
  199. package/dist/src/routes/raw.js.map +1 -1
  200. package/dist/src/routes/read.d.ts.map +1 -1
  201. package/dist/src/routes/read.js +3 -3
  202. package/dist/src/routes/read.js.map +1 -1
  203. package/dist/src/routes/search.d.ts.map +1 -1
  204. package/dist/src/routes/search.js +3 -3
  205. package/dist/src/routes/search.js.map +1 -1
  206. package/dist/src/routes/sources.d.ts +60 -18
  207. package/dist/src/routes/sources.d.ts.map +1 -1
  208. package/dist/src/routes/sources.js +420 -308
  209. package/dist/src/routes/sources.js.map +1 -1
  210. package/dist/src/routes/upload.d.ts.map +1 -1
  211. package/dist/src/routes/upload.js +3 -3
  212. package/dist/src/routes/upload.js.map +1 -1
  213. package/dist/src/services/BridgeService.d.ts +15 -35
  214. package/dist/src/services/BridgeService.d.ts.map +1 -1
  215. package/dist/src/services/BridgeService.js +30 -88
  216. package/dist/src/services/BridgeService.js.map +1 -1
  217. package/dist/src/services/FilesystemService.d.ts +3 -2
  218. package/dist/src/services/FilesystemService.d.ts.map +1 -1
  219. package/dist/src/services/FilesystemService.js +116 -32
  220. package/dist/src/services/FilesystemService.js.map +1 -1
  221. package/dist/src/services/FilesystemUiService.d.ts +4 -1
  222. package/dist/src/services/FilesystemUiService.d.ts.map +1 -1
  223. package/dist/src/services/FilesystemUiService.js +71 -27
  224. package/dist/src/services/FilesystemUiService.js.map +1 -1
  225. package/dist/src/services/SyncScheduler.d.ts +12 -4
  226. package/dist/src/services/SyncScheduler.d.ts.map +1 -1
  227. package/dist/src/services/SyncScheduler.js +45 -10
  228. package/dist/src/services/SyncScheduler.js.map +1 -1
  229. package/dist/src/services/baselineRepair.d.ts +13 -3
  230. package/dist/src/services/baselineRepair.d.ts.map +1 -1
  231. package/dist/src/services/baselineRepair.js +13 -3
  232. package/dist/src/services/baselineRepair.js.map +1 -1
  233. package/dist/src/services/declaredSources.d.ts +125 -42
  234. package/dist/src/services/declaredSources.d.ts.map +1 -1
  235. package/dist/src/services/declaredSources.js +117 -45
  236. package/dist/src/services/declaredSources.js.map +1 -1
  237. package/dist/src/store/dataFormats.d.ts +17 -2
  238. package/dist/src/store/dataFormats.d.ts.map +1 -1
  239. package/dist/src/store/dataFormats.js +18 -3
  240. package/dist/src/store/dataFormats.js.map +1 -1
  241. package/dist/src/sync/DeltaSyncRunner.d.ts.map +1 -1
  242. package/dist/src/sync/DeltaSyncRunner.js +144 -4
  243. package/dist/src/sync/DeltaSyncRunner.js.map +1 -1
  244. package/dist/src/sync/SyncJobQueue.d.ts +14 -2
  245. package/dist/src/sync/SyncJobQueue.d.ts.map +1 -1
  246. package/dist/src/sync/SyncJobQueue.js +56 -10
  247. package/dist/src/sync/SyncJobQueue.js.map +1 -1
  248. package/dist/src/sync/SyncWatchService.d.ts +21 -4
  249. package/dist/src/sync/SyncWatchService.d.ts.map +1 -1
  250. package/dist/src/sync/SyncWatchService.js +115 -10
  251. package/dist/src/sync/SyncWatchService.js.map +1 -1
  252. package/dist/src/sync/categoryInference.d.ts +1 -1
  253. package/dist/src/sync/categoryInference.js +1 -1
  254. package/dist/src/tools/execCtx.d.ts +6 -0
  255. package/dist/src/tools/execCtx.d.ts.map +1 -1
  256. package/dist/src/tools/execCtx.js +11 -0
  257. package/dist/src/tools/execCtx.js.map +1 -1
  258. package/dist/src/tools/fs_list.js +2 -2
  259. package/dist/src/tools/fs_list.js.map +1 -1
  260. package/dist/src/tools/fs_read.js +2 -2
  261. package/dist/src/tools/fs_read.js.map +1 -1
  262. package/dist/src/tools/fs_search.js +2 -2
  263. package/dist/src/tools/fs_search.js.map +1 -1
  264. package/dist/src/tools/fs_write.js +2 -2
  265. package/dist/src/tools/fs_write.js.map +1 -1
  266. package/dist/src/usecases/admitSourceRoot.d.ts +65 -0
  267. package/dist/src/usecases/admitSourceRoot.d.ts.map +1 -0
  268. package/dist/src/usecases/admitSourceRoot.js +85 -0
  269. package/dist/src/usecases/admitSourceRoot.js.map +1 -0
  270. package/dist/src/usecases/browseSourceFolders.d.ts +85 -0
  271. package/dist/src/usecases/browseSourceFolders.d.ts.map +1 -0
  272. package/dist/src/usecases/browseSourceFolders.js +210 -0
  273. package/dist/src/usecases/browseSourceFolders.js.map +1 -0
  274. package/dist/src/usecases/createDeclaredSources.d.ts +13 -2
  275. package/dist/src/usecases/createDeclaredSources.d.ts.map +1 -1
  276. package/dist/src/usecases/createDeclaredSources.js +39 -0
  277. package/dist/src/usecases/createDeclaredSources.js.map +1 -1
  278. package/dist/src/usecases/deprovisionProject.d.ts +4 -5
  279. package/dist/src/usecases/deprovisionProject.d.ts.map +1 -1
  280. package/dist/src/usecases/deprovisionProject.js +3 -8
  281. package/dist/src/usecases/deprovisionProject.js.map +1 -1
  282. package/dist/src/usecases/list.d.ts.map +1 -1
  283. package/dist/src/usecases/list.js +83 -26
  284. package/dist/src/usecases/list.js.map +1 -1
  285. package/dist/src/usecases/listAttachableDevices.d.ts +13 -0
  286. package/dist/src/usecases/listAttachableDevices.d.ts.map +1 -0
  287. package/dist/src/usecases/listAttachableDevices.js +10 -0
  288. package/dist/src/usecases/listAttachableDevices.js.map +1 -0
  289. package/dist/src/usecases/listSourcePackages.d.ts.map +1 -1
  290. package/dist/src/usecases/listSourcePackages.js +95 -79
  291. package/dist/src/usecases/listSourcePackages.js.map +1 -1
  292. package/dist/src/usecases/purgeExcludedPoints.d.ts.map +1 -1
  293. package/dist/src/usecases/purgeExcludedPoints.js +3 -2
  294. package/dist/src/usecases/purgeExcludedPoints.js.map +1 -1
  295. package/dist/src/usecases/readFiles.d.ts.map +1 -1
  296. package/dist/src/usecases/readFiles.js +17 -1
  297. package/dist/src/usecases/readFiles.js.map +1 -1
  298. package/dist/src/usecases/reconcileSourcePackageRoots.d.ts +1 -1
  299. package/dist/src/usecases/reconcileSourcePackageRoots.d.ts.map +1 -1
  300. package/dist/src/usecases/reconcileSourcePackageRoots.js +2 -1
  301. package/dist/src/usecases/reconcileSourcePackageRoots.js.map +1 -1
  302. package/dist/src/usecases/revokePrincipal.d.ts +7 -5
  303. package/dist/src/usecases/revokePrincipal.d.ts.map +1 -1
  304. package/dist/src/usecases/revokePrincipal.js +29 -7
  305. package/dist/src/usecases/revokePrincipal.js.map +1 -1
  306. package/dist/src/usecases/scheduleSourceSync.d.ts +7 -0
  307. package/dist/src/usecases/scheduleSourceSync.d.ts.map +1 -1
  308. package/dist/src/usecases/scheduleSourceSync.js +6 -5
  309. package/dist/src/usecases/scheduleSourceSync.js.map +1 -1
  310. package/dist/src/usecases/searchFiles.d.ts.map +1 -1
  311. package/dist/src/usecases/searchFiles.js +13 -3
  312. package/dist/src/usecases/searchFiles.js.map +1 -1
  313. package/dist/src/usecases/sourcePackageInventory.d.ts +10 -2
  314. package/dist/src/usecases/sourcePackageInventory.d.ts.map +1 -1
  315. package/dist/src/usecases/sourcePackageInventory.js +24 -7
  316. package/dist/src/usecases/sourcePackageInventory.js.map +1 -1
  317. package/dist/src/usecases/triggerSourceSync.d.ts +46 -0
  318. package/dist/src/usecases/triggerSourceSync.d.ts.map +1 -0
  319. package/dist/src/usecases/triggerSourceSync.js +75 -0
  320. package/dist/src/usecases/triggerSourceSync.js.map +1 -0
  321. package/dist/src/usecases/uploadBinary.d.ts +2 -1
  322. package/dist/src/usecases/uploadBinary.d.ts.map +1 -1
  323. package/dist/src/usecases/uploadBinary.js +2 -2
  324. package/dist/src/usecases/uploadBinary.js.map +1 -1
  325. package/dist/src/usecases/vector/endpointGuard.d.ts +1 -1
  326. package/dist/src/usecases/vector/endpointGuard.js +1 -1
  327. package/dist/src/usecases/vectorActivityWatch.d.ts +20 -13
  328. package/dist/src/usecases/vectorActivityWatch.d.ts.map +1 -1
  329. package/dist/src/usecases/vectorActivityWatch.js +61 -36
  330. package/dist/src/usecases/vectorActivityWatch.js.map +1 -1
  331. package/dist/src/usecases/vectorMaintenance.d.ts.map +1 -1
  332. package/dist/src/usecases/vectorMaintenance.js +16 -1
  333. package/dist/src/usecases/vectorMaintenance.js.map +1 -1
  334. package/dist/src/usecases/write/index.d.ts.map +1 -1
  335. package/dist/src/usecases/write/index.js +17 -2
  336. package/dist/src/usecases/write/index.js.map +1 -1
  337. package/dist/src/usecases/write/occupancy.d.ts +5 -1
  338. package/dist/src/usecases/write/occupancy.d.ts.map +1 -1
  339. package/dist/src/usecases/write/occupancy.js +13 -4
  340. package/dist/src/usecases/write/occupancy.js.map +1 -1
  341. package/dist/src/usecases/write/structure.d.ts.map +1 -1
  342. package/dist/src/usecases/write/structure.js +20 -5
  343. package/dist/src/usecases/write/structure.js.map +1 -1
  344. package/dist/src/vector/FilesystemVectorIndex.d.ts +72 -2
  345. package/dist/src/vector/FilesystemVectorIndex.d.ts.map +1 -1
  346. package/dist/src/vector/FilesystemVectorIndex.js +211 -27
  347. package/dist/src/vector/FilesystemVectorIndex.js.map +1 -1
  348. package/dist/src/vector/InMemoryVectorIndex.d.ts.map +1 -1
  349. package/dist/src/vector/InMemoryVectorIndex.js +55 -7
  350. package/dist/src/vector/InMemoryVectorIndex.js.map +1 -1
  351. package/dist/src/vector/qdrantClient.d.ts +18 -1
  352. package/dist/src/vector/qdrantClient.d.ts.map +1 -1
  353. package/dist/src/vector/qdrantClient.js +48 -6
  354. package/dist/src/vector/qdrantClient.js.map +1 -1
  355. package/dist/src/wiring.d.ts +10 -12
  356. package/dist/src/wiring.d.ts.map +1 -1
  357. package/dist/src/wiring.js +101 -61
  358. package/dist/src/wiring.js.map +1 -1
  359. package/package.json +166 -54
  360. package/skills/connect-business-data/SKILL.md +2 -2
  361. package/skills/create-package/SKILL.md +18 -18
  362. package/skills/create-package/references/config-and-credentials.md +16 -13
  363. package/skills/create-package/references/connectors-and-uri-policies.md +36 -27
  364. package/skills/create-package/references/manifest-and-discovery.md +12 -12
  365. package/skills/create-package/references/runtime-and-build.md +18 -18
  366. package/skills/create-package/references/skills-and-context.md +35 -19
  367. package/skills/create-package/references/surfaces-and-design.md +16 -16
  368. package/skills/create-package/references/team-and-workflows.md +2 -2
  369. package/skills/create-package/references/test-and-ship.md +17 -17
  370. package/skills/create-package/references/tools-and-schemas.md +5 -5
  371. package/skills/create-package/scripts/{check-package.sh → check-package.mjs} +78 -64
  372. package/skills/create-package/scripts/{verify-loaded.sh → verify-loaded.mjs} +156 -162
  373. package/skills/git/SKILL.md +31 -29
  374. package/skills/manage-files/SKILL.md +11 -14
  375. package/skills/manage-sources/SKILL.md +85 -45
  376. package/skills/manage-uri-policy/SKILL.md +9 -6
  377. package/skills/sync/SKILL.md +2 -2
  378. package/dist/src/connectors/LocalDiskConnector.d.ts +0 -171
  379. package/dist/src/connectors/LocalDiskConnector.d.ts.map +0 -1
  380. package/dist/src/connectors/LocalDiskConnector.js +0 -1233
  381. package/dist/src/connectors/LocalDiskConnector.js.map +0 -1
  382. package/skills/manage-files/scripts/copy.sh +0 -7
  383. package/skills/manage-files/scripts/create.sh +0 -7
  384. package/skills/manage-files/scripts/mkdir.sh +0 -7
  385. package/skills/manage-files/scripts/modify.sh +0 -7
  386. package/skills/manage-files/scripts/upload.sh +0 -16
  387. package/skills/manage-files/scripts/write.sh +0 -29
  388. package/skills/manage-sources/scripts/reembed.sh +0 -23
@@ -12,7 +12,7 @@ The `fs_*` tools (`fs_read`, `fs_write`, etc.) remain the primary path for one-o
12
12
  file operations — this skill is for *bulk*: iterating with a shell loop, posting a
13
13
  batch, or scripting an `upload + approve` sequence end-to-end. Call the routes with
14
14
  `neuralis request` (the session ticket inside an activated skill, `neuralis login`
15
- on your own machine); `write` and `upload` go through their scripts.
15
+ on your own machine) — every route is one call line, with no script in between.
16
16
 
17
17
  ## Routes covered
18
18
 
@@ -22,8 +22,8 @@ on your own machine); `write` and `upload` go through their scripts.
22
22
  | Search vector index | POST | `search` | `files.search` |
23
23
  | Read multiple files | POST | `read` | `files.read` |
24
24
  | Raw (un-summarized) read | GET | `raw` | `files.read` |
25
- | Write — every verb (create / overwrite / edit / insert / lines / fields / move / copy / mkdir / revert / delete) | POST | `write` — `scripts/write.sh` | `files.write` |
26
- | Upload a payload (multipart/form-data) | POST | `upload` — `scripts/upload.sh` | `files.write` |
25
+ | Write — every verb (create / overwrite / edit / insert / lines / fields / move / copy / mkdir / revert / delete) | POST | `write` | `files.write` |
26
+ | Upload a payload (multipart/form-data) | POST | `upload` | `files.write` |
27
27
  | Approve a pending change | POST | `approve` | `files.write` |
28
28
  | List pending changes (project-wide) | GET | `pending` | `files.read` |
29
29
 
@@ -37,13 +37,12 @@ server-side **403** from `search` even though the other routes work.
37
37
 
38
38
  ## Bodies
39
39
 
40
- - `list` / `search` / `read` / `approve` take a JSON body (`--input - <<<'<json>'`);
41
- `write.sh` takes it as `BODY_JSON`. `create.sh`, `modify.sh`, `copy.sh` and `mkdir.sh` are kept only so an imported skill's existing path still writes; they exec `write.sh`, so they take the same verb-keyed body.
42
- - `/write` body = `{"agentId":"…","uri":"data://notes/plan.md","<verb>":…}` — the VERB is a KEY and its presence is the intent. Content verbs COMPOSE in one call, in a fixed order, as ONE write with ONE baseline: `create` (`{content, client_request_id?}` — never overwrites; a taken name lands BESIDE as `name-2.ext` and the response `uri` is where it went, so read it back), `overwrite` (`{content}` — refuses on a missing file and names `create`), `edit` (`[{old_string, new_string?, replace_all?, expected_replacements?}]`, applied in order, one failure discards all of them), `insert` (`{insert_text, insert_line?}` — inserts AFTER that line, `0` = start of file, omitted = append), `lines` (`{line_start, line_end, content}`), `fields` (`{category, status, pinned, tags{add,remove,set}, metadata}`). Structural verbs stand ALONE: `move`/`copy` (a destination uri or, for a file move, a bare new filename; `copy` may cross sources), `mkdir:true` (a real empty directory; not on `brain://`, where folders are implicit), `revert:true` (one-level undo), `delete:true` (a file, or a whole folder recursively). **A 2xx does not mean success** — a refusal is 200 with `ok:false`, so branch on `ok`. A `move` (or a `revert` that relocates or re-creates) onto a uri that already holds something answers `ok:false` + `error:"DESTINATION_EXISTS"` — nothing was overwritten; delete or rename the occupant first. A delete has ONE spelling, the `delete` key: `fields.status:"deleted"` is refused. `review` is never read from the body — a content edit (`overwrite`/`edit`/`insert`/`lines`) lands `pending_review` on every lane (visible and revertible in Changes); `create`/`move`/`copy`/`mkdir` land committed for a human interactive caller and `pending_review` from this ticket lane; `/upload` also journals agent-origin uploads as pending review; interactive human uploads land committed. Use `/write` for JSON text and `/upload` for multipart file bytes. A missing `agentId`/`uri` is a **400** naming the field, a body the server could not parse a **400** `Request body must be a JSON object`. A uri-policy denial is a **403 with no `ok` field**, a disabled source a **409** with `code:"source_disabled"`. A source slug this project does not have answers one of two ways, and BOTH mean "stop guessing this name": with a scheme (`zzz://a.md`) the uri gate answers **403 `uri_policy_denied`** first; without one (`notes.md`) you get **404 `code:"source_not_configured"`** carrying `availableSources` — the sources you CAN address. `/list` gives the 404 in both forms. Switch to a source from that list (or from `<runtime_stack>`); retrying the same name never works. `/read` is different again: it reports PER FILE inside a 200, so a denied or disabled source arrives as `{uri, error, code:"forbidden"}` — never a 409 — and a missing file as `code:"not_found"`. No code means the read failed for some other reason; do not conclude the file is gone. A folder delete or copy that partly succeeded reports what really happened: `affected` (files touched) and `failed` (the NAMES that could not be), so "failed" does not mean "nothing happened". `warning:"moved_with_source_retained"` on a move means the copy landed but the original could not be removed — BOTH copies exist on purpose; do not re-run the move. `indexed:false` means the bytes DID land and are readable, but search indexing was skipped or failed; report it, do not re-write. Sync retries failed indexing only for eligible files; excluded files remain unindexed. A non-2xx prints the route's body too — on stderr, followed by an `HTTP <code>` line, under a `--- stderr ---` separator, so read the whole output.
40
+ - `list` / `search` / `read` / `approve` / `write` take a JSON body on stdin (`echo '<json>' | neuralis request POST @neuralis/brain-core/<route> --input -`, the one form bash and PowerShell both parse; a `'` inside the text is written `\u0027` in the JSON); file content and other free text ride that body, never a `-f` argument (PowerShell strips the quotes inside an argument).
41
+ - `/write` body = `{"agentId":"…","uri":"data://notes/plan.md","<verb>":…}` — the VERB is a KEY and its presence is the intent. Content verbs COMPOSE in one call, in a fixed order, as ONE write with ONE baseline: `create` (`{content, client_request_id?}` — never overwrites; a taken name lands BESIDE as `name-2.ext` and the response `uri` is where it went, so read it back), `overwrite` (`{content}` — refuses on a missing file and names `create`), `edit` (`[{old_string, new_string?, replace_all?, expected_replacements?}]`, applied in order, one failure discards all of them), `insert` (`{insert_text, insert_line?}` — inserts AFTER that line, `0` = start of file, omitted = append), `lines` (`{line_start, line_end, content}`), `fields` (`{category, status, pinned, tags{add,remove,set}, metadata}`). Structural verbs stand ALONE: `move`/`copy` (a destination uri or, for a file move, a bare new filename; `copy` may cross sources), `mkdir:true` (a real empty directory; not on `brain://`, where folders are implicit), `revert:true` (one-level undo), `delete:true` (a file, or a whole folder recursively). **A 2xx does not mean success** — a refusal is 200 with `ok:false` and the CLI exits 0, so branch on `ok`, never the status or the exit code. A `move` (or a `revert` that relocates or re-creates) onto a uri that already holds something answers `ok:false` + `error:"DESTINATION_EXISTS"` — nothing was overwritten; delete or rename the occupant first. A delete has ONE spelling, the `delete` key: `fields.status:"deleted"` is refused. `review` is never read from the body — a content edit (`overwrite`/`edit`/`insert`/`lines`) lands `pending_review` on every lane (visible and revertible in Changes); `create`/`move`/`copy`/`mkdir` land committed for a human interactive caller and `pending_review` from this ticket lane; `/upload` also journals agent-origin uploads as pending review; interactive human uploads land committed. Use `/write` for JSON text and `/upload` for multipart file bytes. A missing `agentId`/`uri` is a **400** naming the field, a body the server could not parse a **400** `Request body must be a JSON object`. A uri-policy denial is a **403 with no `ok` field**, a disabled source a **409** with `code:"source_disabled"`. A source slug this project does not have answers one of two ways, and BOTH mean "stop guessing this name": with a scheme (`zzz://a.md`) the uri gate answers **403 `uri_policy_denied`** first; without one (`notes.md`) you get **404 `code:"source_not_configured"`** carrying `availableSources` — the sources you CAN address. `/list` gives the 404 in both forms. Switch to a source from that list (or from `<runtime_stack>`); retrying the same name never works. `/read` is different again: it reports PER FILE inside a 200, so a denied or disabled source arrives as `{uri, error, code:"forbidden"}` — never a 409 — a missing file as `code:"not_found"`, and a device folder that cannot serve as `code:"source_unavailable"` or `"device_refused"` with a `reason` (`device_not_ready` adds `not_ready`: what the device's owner fixes there). No code means the read failed for some other reason; do not conclude the file is gone. `code:"vector_store_unavailable"` (per file on `/read`, `ok:false` on `/write`, a **503** elsewhere) means the index is not available yet: a new file on a folder source still lands, a `brain://` file, an edit, move or delete waits — nothing was changed; retry later. A folder delete or copy that partly succeeded reports what really happened: `affected` (files touched) and `failed` (the NAMES that could not be), so "failed" does not mean "nothing happened". `warning:"moved_with_source_retained"` on a move means the copy landed but the original could not be removed — BOTH copies exist on purpose; do not re-run the move. `indexed:false` means the bytes DID land and are readable, but search indexing was skipped or failed; report it, do not re-write. Sync retries failed indexing only for eligible files; excluded files remain unindexed. A non-2xx prints the route's body too — on stderr, followed by an `HTTP <code>` line, under a `--- stderr ---` separator, so read the whole output.
43
42
  - `/search` body key is `search_mode` (semantic|filter|grep) — the SAME vocabulary as the `fs_search` tool; the legacy `mode` key is rejected with 400. The route forwards `search_mode`, `query`, `folder_uri`, `glob`, `category`, `tags`, `status`, `created_after`/`created_before`, `limit`, and the grep-only `path_glob`, `context` and `case_sensitive`. In `grep` mode the search is uri-policy `read`-gated (only paths the caller holds `read` policy on are grepped), the match is a FIXED STRING, and the answer carries `truncated` + `total_seen` — a cut set says so, so never read a full-looking list as proof that the rest is absent.
44
43
  - `/raw` is a GET — pass the file URI as `-f uri=<uri>` and redirect stdout to a file: it always returns the full bytes, unaffected by the response headers; what those headers say is a BROWSER instruction. Safe types (images except SVG, video, audio, PDF, text, JSON) are marked for inline display; SVG, HTML and XML are marked `attachment` so a person clicking the link downloads them instead of executing them on the app origin. Do not describe a `.svg` or `.html` you wrote as viewable in the browser — offer it as a download, or convert it to a raster image if a human needs to look at it.
45
44
  - `/read` is at parity with the `fs_read` tool: the body takes `files[]` — each entry a URI string or `{"uri":"…","line_start":N,"line_end":M}` with that file's own window — plus `read_version`, batch-level `line_start`/`line_end` and `include_ids`. An entry that is neither shape is a **400**. Text is a bounded preview; native media may accompany it, while unsupported/invalid binary data has a URI and marker. For a byte-exact binary copy use the authorized `/raw` byte lane and multipart `/upload`, never re-encode a text preview. If you only need the pre-edit content, a plain `/read` response already carries it: each file's `version.baseline.content`, with `available_versions` listing `baseline` exactly when one exists.
46
- - `/upload` is **multipart/form-data**, NOT JSON — `upload.sh` takes `FILE_PATH=…` `AGENT_ID=…` (required) plus optional `URI=…` / `TAGS=a,b`; a JSON body is rejected with 400. The 200 carries `indexed`: `false` means the bytes DID land but search indexing was skipped by the source selection or failed (provider outage/quota) — report it, do not re-upload. An eligible sync retries failed indexing; excluded uploads remain unindexed until the selection changes. The 200 also carries `mimeType`, and it may differ from what the upload declared: the stored type is resolved from the filename extension first, with the declared value kept only for an extension the platform does not know, and a common-image claim the leading bytes contradict falls back to `application/octet-stream`. Give the file a truthful extension and the stored type follows.
45
+ - `/upload` is **multipart/form-data**, NOT JSON — `--form file=@<local path>` and `--form agentId=<id>` are required, `--form uri=…` / `--form tags=a,b` optional; a JSON body is rejected with 400. The 200 carries `indexed`: `false` means the bytes DID land but search indexing was skipped by the source selection or failed (provider outage/quota) — report it, do not re-upload. An eligible sync retries failed indexing; excluded uploads remain unindexed until the selection changes. The 200 also carries `mimeType`, and it may differ from what the upload declared: the stored type is resolved from the filename extension first, with the declared value kept only for an extension the platform does not know, and a common-image claim the leading bytes contradict falls back to `application/octet-stream`. Give the file a truthful extension and the stored type follows.
47
46
  - `GET /pending` lists durable pending records inside the Changes workspace. `status` (`pending_review`\|`approved`\|`reverted`), `source`, `op` (`create`\|`modify`\|`delete`\|`move`) and `limit` filter the list; owner/scope and URI READ gates apply per record. Review begins with `POST /pending` `{action:"preview",id}`: it returns the current connector content separately from the recorded snapshot and saved baseline, typed missing/unavailable/binary/too-large states, `indexState`, `requiresAcknowledgement`, and `expectedFingerprint`. The preview is bounded by `pendingPreviewMaxBytes`; it never fabricates missing content or vectors. Resolve through `POST /approve` `{id,expectedFingerprint}` or `POST /pending` `{action:"revert"|"dismiss",id,expectedFingerprint}`. If the preview requires acknowledgement, inspect those states and include `acknowledgeCurrentState:true`; never auto-acknowledge an unseen preview. The server rechecks freshness and WRITE authority at apply: a changed fingerprint requires a new preview, and acknowledgement grants no missing permission. Bare legacy `/write revert:true` refuses unsafe pending recovery; ordinary non-pending one-level undo remains available. Approval/dismissal preserve the stored snapshot/index state (including recovery-only or absent index), rather than certifying current connector bytes as indexed. For a file the preview shows `missing` with a saved `journal-latest-write` baseline, an acknowledged approve/dismiss closes the review and the file stays gone; revert is the restore. Terminal retries remain owner-gated and idempotent; `uri` is omitted without current READ and WRITE access. Revert restores the saved baseline and refuses missing baselines or occupied move destinations. Discard/Repair remain orphan-only, owner-gated operations; no transient outage is proof of orphanhood.
48
47
 
49
48
 
@@ -55,14 +54,14 @@ For a disposable pending record you created in your project, substitute its real
55
54
 
56
55
  ```bash
57
56
  neuralis request POST @neuralis/brain-core/pending -f action=preview -f id=<scratch-record-id>
58
- neuralis request POST @neuralis/brain-core/pending --input - <<<'{"action":"revert","id":"<scratch-record-id>","expectedFingerprint":"<64-hex-preview-fingerprint>","acknowledgeCurrentState":true}'
57
+ echo '{"action":"revert","id":"<scratch-record-id>","expectedFingerprint":"<64-hex-preview-fingerprint>","acknowledgeCurrentState":true}' | neuralis request POST @neuralis/brain-core/pending --input -
59
58
  ```
60
59
 
61
60
  Pending calls return one page; scan-orphans preserves that page in `changes` and puts its orphan subset in `orphans`/`orphanIds`: pass `cursor` from `nextCursor` unchanged with the same filters, or `uri` for an exact URI. Check `complete`, `partial` and `hasMoreAvailable`; a partial exhausted branch remains incomplete. On `restartRequired`, restart the list instead of retrying the old cursor. Repair returns scannedVisible/orphaned/attempted/discarded/refused/failed/reasons for one batch; continue only via nextCursor; pause on partial and use an explicit Continue available/Retry.
62
61
 
63
62
  ```bash
64
63
  # Recursive list of /data
65
- neuralis request POST @neuralis/brain-core/list --input - <<<'{"uri":"data://","recursive":true,"limit":100}'
64
+ echo '{"uri":"data://","recursive":true,"limit":100}' | neuralis request POST @neuralis/brain-core/list --input -
66
65
 
67
66
  # Vector search across all sources (body key is `search_mode`, same as the fs_search tool)
68
67
  neuralis request POST @neuralis/brain-core/search -f search_mode=semantic -f query='telemetry pipeline' -F limit=10
@@ -74,15 +73,13 @@ neuralis request GET @neuralis/brain-core/pending -f status=pending_review -f li
74
73
  neuralis request GET @neuralis/brain-core/raw -f uri=data://report.pdf > /tmp/report.pdf
75
74
 
76
75
  # Create a text file — the journaled write lane. The verb is the KEY.
77
- # `<agent-id>` is a placeholder; a real id makes this line write for real.
78
- BODY_JSON='{"agentId":"<agent-id>","uri":"data://scratch/manage-files-probe.md","create":{"content":"# probe\n"}}' \
79
- bash ${SKILL_DIR}/scripts/write.sh
76
+ # `<agent-id>` is a placeholder; a real id makes this line write for real. Read `ok` in the answer.
77
+ echo '{"agentId":"<agent-id>","uri":"data://scratch/manage-files-probe.md","create":{"content":"# probe\n"}}' | neuralis request POST @neuralis/brain-core/write --input -
80
78
 
81
79
  # Upload a payload (multipart, NOT JSON): file + agentId are required form fields.
82
80
  # The route never overwrites: a `URI` already in use lands the upload BESIDE the
83
81
  # existing file as `name (2).ext`, and the response `uri` is where it went — read
84
82
  # it, do not assume the path. `<agent-id>` is a placeholder; take a real id from the agents
85
83
  # list, and note that a real id makes this line write for real.
86
- FILE_PATH=/tmp/report.pdf AGENT_ID=<agent-id> URI='data://report.pdf' TAGS='reports,q3' \
87
- bash ${SKILL_DIR}/scripts/upload.sh
84
+ neuralis request POST @neuralis/brain-core/upload --form file=@/tmp/report.pdf --form agentId=<agent-id> --form uri=data://report.pdf --form tags=reports,q3
88
85
  ```
@@ -32,8 +32,10 @@ To just **survey** the configured sources and their freshness (read-only, the
32
32
  are opt-in: without `include_counts` the registry still lists the sources but
33
33
  `on_disk`/`indexed_count`/`unindexed` are usually omitted (survey mode is
34
34
  exactly when you want them).
35
- 2. For any source in `sync_status: "error"`, report `last_error` — it is the
36
- per-source diagnosis and needs no extra call. Do **not** reach for the log
35
+ 2. For any source that carries `last_error`, report it — it is the per-source
36
+ diagnosis and needs no extra call. `sync_status: "error"` means the last
37
+ SYNC failed; a `last_error` without it means the walk or count failed now
38
+ (no `on_disk`), not the sync. Do **not** reach for the log
37
39
  files with `fs_read`: `data://<package>/logs/**` is read-denied by uri policy
38
40
  for everyone below owner/admin, so on a member's behalf that call fails.
39
41
  Read them through `inspect-agent-core` (or, for the platform-wide view, the
@@ -61,18 +63,18 @@ server-side source rows rather than the index-count survey.)
61
63
  | List registered kinds | GET | `sources/kinds` | | `files.read` |
62
64
  | Get a kind's config schema | GET | `sources/kinds/<kind>/schema` | | `files.read` |
63
65
  | Discoverable connectors (filesystem hints) | GET | `sources/discoverable` | | `sources.mount` |
64
- | Browse a filesystem path before adding it | GET | `sources/browse` | `path` | `sources.mount` |
66
+ | Browse folders before adding one | GET | `sources/browse` | `path`, `device?` | `sources.mount`; with `device` the device's owner (`device.own`) |
65
67
  | Create a new source | POST | `sources` | body (below) | `sources.mount` |
66
68
  | Update an existing source | PATCH | `sources` | body (below) | `sources.mount` |
67
69
  | Delete a source | DELETE | `sources/<slug>[?purge=1]` | | `sources.mount` |
68
70
  | Enable / disable a source | POST | `sources/enabled` | `source`, `enabled` (`true`\|`false`\|`"auto"`) | `sources.mount` |
69
- | Trigger sync (202 + queue job snapshot) | POST | `sources/sync` | `source`, `agentId?` | `sources.sync` |
71
+ | Trigger sync (202 + queue job snapshot) | POST | `sources/sync` | `source`, `agentId?`, `confirmEmpty?` | `sources.sync` |
70
72
  | Cancel an in-flight sync | POST | `sources/cancel` | `source?` | `sources.sync` |
71
73
  | Job status | GET | `sources/sync-status` | `source?` | `sources.sync` |
72
74
  | Forget sync state (next tick re-walks; deletes nothing) | POST | `sources/reset` | `source` | `sources.sync` |
73
75
  | Rescan changes (full re-walk now; unchanged files keep their vectors; 202 + job) | POST | `sources/reindex` | `source`, `agentId?` | `sources.sync` |
74
76
  | Clean a file / folder / source index (estimate first) | POST | `sources/purge` | body (below) | `sources.mount` + `sources.sync` |
75
- | Catch up embedding debt; FORCE=1 re-embeds (estimate first) | POST | `sources/reindex` + `embeddingOnly` or `force` — run `bash ${SKILL_DIR}/scripts/reembed.sh` | env | `sources.sync` |
77
+ | Catch up embedding debt, or re-embed with `force` (estimate first) | POST | `sources/reindex` + `embeddingOnly` or `force` (lines under §Re-embed) | `source`, `folder?`/`uri?`, `estimate?` | `sources.sync` |
76
78
 
77
79
  > **`update` takes no `<slug>`.** PATCH targets the bare `sources` path; the
78
80
  > source to patch is the body `source` field (the handler ignores the path).
@@ -99,19 +101,28 @@ feature server-side, beyond the `files.read` floor — a caller holding only
99
101
  - **`sources.mount`** — create, update, delete, enable/disable, browse and the
100
102
  discoverable list. Browsing and the
101
103
  discoverable list are the steps that PRECEDE attaching, and they enumerate the
102
- host: you may browse exactly what you would be allowed to attach.
104
+ host: you may browse exactly what you would be allowed to attach. On a native
105
+ install (no container) a folder on this server may root only in the project's own
106
+ folder — browsable with its parents on the way down to it — or a privileged
107
+ zone below; any other folder answers `403 native_local_root_outside_project`
108
+ and is attached as a folder on the user's own paired device instead.
103
109
  - **`sources.privileged`** — browsing the filesystem root or any
104
110
  protected host zone (the App Zone, the Neuralis tree), the same zones whose
105
111
  ATTACH needs it. A protected directory is also omitted from the listing of a
106
112
  parent you may browse, so an absent entry is not proof it does not exist.
107
- - **`sources.sync`** — sync, cancel, reset, reindex, `reembed.sh`, sync-status.
113
+ - **`sources.sync`** — sync, cancel, reset, reindex, re-embed, sync-status.
108
114
 
109
115
  The index purge requires both `sources.mount` and `sources.sync`, source-scope management authority and current READ visibility.
110
116
 
111
117
  Create/update/delete/enable additionally enforce `canAccessScope(.., 'write')`
112
118
  on the target source's scope, and create validates the kind's scope rules.
119
+ Send a folder's `root` alone: the server derives its `hostRoot` (the same
120
+ folder on the machine) and stores both, so the source opens whether the server runs
121
+ in Docker or natively. A `hostRoot` that contradicts that derivation answers
122
+ `400 source_root_pair_mismatch`; one nothing derives is accepted only from a
123
+ `sources.privileged` caller, and audited.
113
124
 
114
- ### Privileged and host-plane sources
125
+ ### Privileged sources and device folders
115
126
 
116
127
  One escalation sits above `sources.mount`, not granted below the `admin` tier (`admin` holds
117
128
  it through its enumerated default grant, `owner` through the `'*'` wildcard; grantable to any
@@ -122,17 +133,33 @@ custom role):
122
133
  filesystem (`/`). Containment is checked in both directions on canonical paths, so a
123
134
  sub-path or an ancestor of a protected zone is caught too.
124
135
 
125
- A source on the HOST plane (a connector kind of `host` / `host-*`, on a paired device
126
- rather than in the container) has one rule: **only that device's owner, holding
127
- `device.own`, attaches or edits it** — at every root, and no role feature replaces it.
128
- Anyone else gets 403, whatever they hold.
136
+ A folder is one kind, `host`, on one of two places its stored config names: without
137
+ `connection.config.device` it is a folder on this server; with one it is a folder on that
138
+ paired device (the DEVICE plane), reached through the device's broker. A device folder has one
139
+ rule: **only that device's owner, holding `device.own`, attaches or edits it** — at every
140
+ root, and no role feature replaces it. Anyone else gets 403, whatever they hold. It is
141
+ attached at user scope unless you send `"scope":"project"` (never `agent`), its `root` is an
142
+ absolute path on that device, and the place never changes after the attach — to move a
143
+ folder between this server and a device, delete it and attach it again.
129
144
 
130
- A host source is also bounded by the device's own allowlist, which the platform cannot
145
+ A device folder is also bounded by the device's own allowlist, which the platform cannot
131
146
  widen: even a permissive source policy only reaches paths the device's owner granted. If a
132
- host read or write fails while the source policy allows it, report the allowlist as the
133
- limit — the owner widens it with `neuralis device grant`, not a policy edit.
134
-
135
- Attaching a host source is not the same act as granting host command execution: reading
147
+ device read or write fails while the source policy allows it, report the allowlist as the
148
+ limit — the owner widens it with `neuralis device grant`, not a policy edit. The git panel
149
+ and `/git/*` answer for a folder on this server only.
150
+
151
+ To find the folder on your OWN device, browse it: `sources/browse -f device=dev_… -f path=`
152
+ (empty path) lists the folders that device allows this server, with `-f path=/abs/dir` one
153
+ level below. Anyone but the owner gets `403 Only the device's owner may browse it.`, an
154
+ unknown id too. A `200` with `state` other than `ok` and no entries is the device's answer:
155
+ `ceiling_denied` (not allowed yet), `device_offline`, `broker_outdated` (an older CLI there).
156
+ For a folder it does not allow yet, ask the device to record it for its owner — the grant
157
+ stays on that machine (tray → Allow a folder…, or `neuralis device grant <dir>`):
158
+ `neuralis request POST @neuralis/agent-core/devices/dev_…/requests -f path=/abs/dir -f list=read`
159
+ (`list=write` for a writable folder) → `{recorded:true}`, or `{recorded:false,
160
+ reason:"inside_ceiling"}` when it is already allowed.
161
+
162
+ Attaching a device folder is not the same act as granting host command execution: reading
136
163
  files through `fs_*` and running commands there are separate grants.
137
164
 
138
165
  The same split holds for every exec-capable source (a virtual desktop, any
@@ -153,13 +180,15 @@ server-side sync queue. Poll `sources/sync-status` (`-f source=<slug>`) until
153
180
  with `source` stops one source's job mid-run; without it, EVERY job on
154
181
  sources you can see.
155
182
 
156
- An embedding job can end `paused`: report `result.embedding.pausedReason` and partial counts. Resume is a new explicitly authorized `reembed.sh` request, using durable point debt; no saved job ID or automatic paid restart.
183
+ An embedding job can end `paused`: report `result.embedding.pausedReason` and partial counts. Resume is a new explicitly authorized `embeddingOnly` request, using durable point debt; no saved job ID or automatic paid restart.
157
184
 
158
185
  `sources/sync` refuses in two ways worth telling apart. **404** — the slug does not
159
186
  resolve for you (it does not exist, or it is outside your scope; the two answer
160
187
  alike on purpose). **400** — the source exists but carries no `sync` block, so
161
188
  there is nothing to trigger: add one with an update first. Neither is a server
162
- fault, so neither should be retried unchanged.
189
+ fault, so neither should be retried unchanged. A job that fails `root_empty`
190
+ (or `root_unreachable`) removed nothing; `confirmEmpty:true` is for a folder the
191
+ user confirmed is empty (the `sync` skill).
163
192
 
164
193
  ## Fields, bodies and script env
165
194
 
@@ -171,20 +200,20 @@ fault, so neither should be retried unchanged.
171
200
  - `?purge=1` on delete enqueues an async vector purge. Delete then returns
172
201
  **202 + `{purgeJob, …}`** (vs 200 normally). Any delete resolves the source's
173
202
  open notifications (its unread failure warnings) for you and its creator.
174
- - `reembed.sh` takes `SOURCE` (required) and `FOLDER` / `URI` — its scope (one of them, inside `SOURCE`; neither = the whole
175
- source). `CONFIRM=1` starts debt catchup; without it the script only ESTIMATES. `FORCE=1` selects a forced connector re-embed instead.
176
- `SCOPE=platform` (catch-up only, whole source, needs `platform.vector.maintain`) catches up EVERY
203
+ - The re-embed body takes `source` (required) and `folder` / `uri` — its scope (one of them, inside `source`; neither = the whole
204
+ source). `embeddingOnly:true` catches up debt, `force:true` selects a forced connector re-embed instead, and `estimate:true` on
205
+ either only ESTIMATES. `scope:"platform"` (catch-up only, whole source, needs `platform.vector.maintain`) catches up EVERY
177
206
  writer's points of the source, not only yours — the way back after an operator dense clear.
178
207
  - Create and update bodies (`--input -`) MUST include
179
208
  `source` + `permissions`; create additionally requires `connection.kind`. May also
180
- carry `recognizesPackages` (boolean; absent or `null` = unchanged, so a listing
209
+ carry `packageFolders` (an array of folders; absent or `null` = unchanged, so a listing
181
210
  round-tripped through jq never 400s on it) — see **Package sources** below. A `sync`
182
211
  block may carry an `include` allowlist alongside `exclude`/`trigger`
183
212
  (`"sync": {"exclude": [], "include": ["skills/**"], "trigger": "manual"}`): non-empty
184
213
  means only matching files sync, and an exclude still wins. A `sync.media` object
185
214
  (`{"images":true,"pdf":true,"video":false,"audio":false}`, absent key = that default)
186
215
  picks which binary kinds a MULTIMODAL active model embeds; a text-only model embeds
187
- none, and `lastSyncResult.mediaSkipped` counts what was left out; `lastSyncResult.binarySkipped` is the last count of binary files not indexed as text (a binary extension, or a NUL in the first `brainSyncBinarySniffChars` characters); `lastSyncResult.embeddingDegraded` lists the reasons (`quota`, `credentials`, `rate_limit`, …) when the embedder was unavailable during the pass — the files are indexed and text-searchable, their semantic embedding is owed and caught up by `reembed.sh` once the embedder answers. The `invalid` reason is a local PNG structural check before provider work; invalid input preserves existing indexed and recovery payloads. **`include` bounds the
216
+ none, and `lastSyncResult.mediaSkipped` counts what was left out; `lastSyncResult.binarySkipped` is the last count of binary files not indexed as text (a binary extension, or a NUL in the first `brainSyncBinarySniffChars` characters); `lastSyncResult.embeddingDegraded` lists the reasons (`quota`, `credentials`, `rate_limit`, …) when the embedder was unavailable during the pass — the files are indexed and text-searchable, their semantic embedding is owed and caught up by an `embeddingOnly` re-embed once the embedder answers. The `invalid` reason is a local PNG structural check before provider work; invalid input preserves existing indexed and recovery payloads. **`include` bounds the
188
217
  INDEX, never the read.** What an agent can `fs_read` is set by the source ROOT and by
189
218
  `permissions.paths[]` — so narrowing a wide source with `include` alone leaves every
190
219
  file under that root readable. Re-root it, or add a path deny, or both.
@@ -221,25 +250,35 @@ theirs.
221
250
 
222
251
  ```bash
223
252
  # Disposable source from the lifecycle walkthrough only; estimate first.
224
- neuralis request POST @neuralis/brain-core/sources/purge --input - <<<'{"source":"scratch-demo","mode":"estimate","obsoleteOnly":true,"selector":{"kind":"source"}}'
253
+ echo '{"source":"scratch-demo","mode":"estimate","obsoleteOnly":true,"selector":{"kind":"source"}}' | neuralis request POST @neuralis/brain-core/sources/purge --input -
225
254
  # Apply only after reviewing the same selection’s counts.
226
- neuralis request POST @neuralis/brain-core/sources/purge --input - <<<'{"source":"scratch-demo","mode":"apply","obsoleteOnly":true,"selector":{"kind":"source"}}'
255
+ echo '{"source":"scratch-demo","mode":"apply","obsoleteOnly":true,"selector":{"kind":"source"}}' | neuralis request POST @neuralis/brain-core/sources/purge --input -
227
256
  # A canonical folder selection, still estimate-only:
228
- neuralis request POST @neuralis/brain-core/sources/purge --input - <<<'{"source":"scratch-demo","mode":"estimate","obsoleteOnly":false,"selector":{"kind":"folder","uri":"scratch-demo://docs"}}'
257
+ echo '{"source":"scratch-demo","mode":"estimate","obsoleteOnly":false,"selector":{"kind":"folder","uri":"scratch-demo://docs"}}' | neuralis request POST @neuralis/brain-core/sources/purge --input -
229
258
  ```
230
259
 
231
260
  ## Re-embed (a file, a folder, a source)
232
261
 
233
- "Rescan changes" reuses unchanged indexed files, but rebuilds re-included recovery-only content. `reembed.sh` catches up missing/stale indexed embeddings, including brain-only and unchanged legacy records. Its read-only estimate returns `estimate_kind:scope_upper_bound`: authorized indexed scope counts are an upper bound, not a provider quote; no provider call or job starts. Show the estimate before `CONFIRM=1` (202 + embedding job; poll `sources/sync-status`). Disabled embedding refuses: each `GET sources` row's `embedding_enabled` is the live platform switch, and while it is `false` `reembed.sh` answers 409 `embedding_disabled`; without an active dense generation the estimate refuses and a submitted job pauses as `metadata_only`, never activating a model. `FORCE=1` instead rereads and re-embeds the connector scope; its estimate includes `{documents,estimate:{tokens,relStdErr,usd,seconds}}` (`usd:null` for an unpriced model). A single file you may not read answers
262
+ "Rescan changes" reuses unchanged indexed files, but rebuilds re-included recovery-only content. `embeddingOnly:true` catches up missing/stale indexed embeddings, including brain-only and unchanged legacy records. Its read-only estimate returns `estimate_kind:scope_upper_bound`: authorized indexed scope counts are an upper bound, not a provider quote; no provider call or job starts. Show the estimate before you send the same body without `estimate` (202 + embedding job; poll `sources/sync-status`). Disabled embedding refuses: each `GET sources` row's `embedding_enabled` is the live platform switch, and while it is `false` the re-embed answers 409 `embedding_disabled`; without an active dense generation the estimate refuses and a submitted job pauses as `metadata_only`, never activating a model. `force:true` instead rereads and re-embeds the connector scope; its estimate includes `{documents,estimate:{tokens,relStdErr,usd,seconds}}` (`usd:null` for an unpriced model). A single file you may not read answers
234
263
  `404`, exactly like a missing one. Switching the platform to a DIFFERENT model is not this:
235
264
  that is the owner's rebuild in the admin Vector section.
236
265
 
237
- ## Package sources (`recognizesPackages`)
266
+ ```bash
267
+ # Read-only estimates first (no job, no provider call): debt catch-up, then a forced re-embed of one folder.
268
+ neuralis request POST @neuralis/brain-core/sources/reindex -f source=scratch-demo -F embeddingOnly=true -F estimate=true
269
+ neuralis request POST @neuralis/brain-core/sources/reindex -f source=scratch-demo -f folder=scratch-demo://docs -F force=true -F estimate=true
270
+ # Starts a paid embedding job (202) — the same body without `estimate`.
271
+ neuralis request POST @neuralis/brain-core/sources/reindex -f source=scratch-demo -F embeddingOnly=true
272
+ ```
273
+
274
+ ## Package sources (`packageFolders`)
238
275
 
239
- Create and update accept `recognizesPackages` (boolean) in the body. It does
240
- NOT switch markdown discovery on — a synced source's markdown becomes source-package
241
- contributions (skill / instruction / rule / agent / docs) either way; the flag lets the host
242
- load the source as a runtime package source (create-package
276
+ Create and update accept `packageFolders` in the body: the folders of the source, relative
277
+ to its root, whose packages the host loads (`""` = the whole source, `"tools/pkgs"` = that
278
+ folder; no `..`, no absolute path; `[]` clears them). It does NOT switch markdown discovery
279
+ on — a synced source's markdown becomes source-package contributions (skill / instruction /
280
+ rule / agent / docs) either way; the folders let the host load packages from them as runtime
281
+ package sources (create-package
243
282
  `references/connectors-and-uri-policies.md` §Declare source instances owns the details). Two
244
283
  server-side gates apply regardless of what you send (`src/routes/sources.ts`):
245
284
 
@@ -249,14 +288,16 @@ server-side gates apply regardless of what you send (`src/routes/sources.ts`):
249
288
  member 20 · viewer 30, lower = stronger), or who holds a `'*'` wildcard
250
289
  feature grant. A CUSTOM role that declares `priority: 2` passes exactly like
251
290
  the built-in `admin`; a role NAMED `admin` is not what is checked. Anything
252
- weaker gets `403 Setting recognizesPackages requires an owner/admin-effective
291
+ weaker gets `403 Setting packageFolders requires an owner/admin-effective
253
292
  role.` — quote that string verbatim when you report it. It names the required
254
293
  STRENGTH, not a role you have to be called. This is the SECOND gate on the
255
294
  route: `sources.mount` is checked first for the whole PATCH, so a caller without
256
295
  it never reaches this message and sees `403 Updating sources requires
257
296
  sources.mount.` instead. Read the two strings as different answers — a missing
258
297
  feature grant versus insufficient role strength.
259
- - **Local-kind only** — setting it on a non-`local` connection returns `400`.
298
+ - **`host` kind only** — setting it on another kind returns `400`. On a folder on a paired
299
+ device the packages are read over its link, never copied here; their skill scripts run on
300
+ that device. While it is offline its packages read "Not available".
260
301
 
261
302
  A package delivered through a **user/agent-scoped** source is advertised only to that
262
303
  scope (a different run identity sees nothing — correct-by-design, not a load failure).
@@ -266,11 +307,11 @@ scope (a different run identity sees nothing — correct-by-design, not a load f
266
307
  # and already holds markdown, so this edits a REAL source. `repo` is a stand-in:
267
308
  # substitute a slug from the sources list. The effect is live — every matching .md under
268
309
  # it starts being advertised as a package contribution on the next sync — and it
269
- # is reversible only by resending the same body with `recognizesPackages:false`.
310
+ # is reversible only by resending the same body with `packageFolders:[]`.
270
311
  # Needs sources.mount, then priority <= 2 (the admin anchor) or a '*' grant, and a
271
- # local-kind source. The body carries the source's CURRENT permissions back —
312
+ # folder source. The body carries the source's CURRENT permissions back —
272
313
  # PATCH replaces them:
273
- neuralis request GET @neuralis/brain-core/sources --jq '.[] | select(.source=="repo") | {source, permissions, recognizesPackages:true}' | neuralis request PATCH @neuralis/brain-core/sources --input -
314
+ neuralis request GET @neuralis/brain-core/sources --jq '.[] | select(.source=="repo") | {source, permissions, packageFolders:[""]}' | neuralis request PATCH @neuralis/brain-core/sources --input -
274
315
  ```
275
316
 
276
317
  ## `description` field
@@ -299,18 +340,17 @@ neuralis request GET @neuralis/brain-core/sources
299
340
  # a TOP-LEVEL ARRAY → filter with .[] (NOT .sources[]):
300
341
  # Each row IS the source config: the slug lives in `.source` (there is no `.slug` key).
301
342
  neuralis request GET @neuralis/brain-core/sources --jq '.[] | {source, enabled, kind: .connection.kind, orphan}'
302
- neuralis request GET @neuralis/brain-core/sources --jq '.[] | select(.connection.kind=="local")'
343
+ neuralis request GET @neuralis/brain-core/sources --jq '.[] | select(.connection.kind=="host" and (.connection.config.device|not))'
303
344
  # The kind is the registry KIND, not a connector id or a UI label. Enumerate them
304
- # (today: brain, host, local, webtop); an unregistered value is 404
345
+ # (today: brain, host, webtop); an unregistered value is 404
305
346
  # `Unknown kind "<x>"` for EVERY caller, so it is never a permission problem.
306
- # The on-disk connector's id is `local-disk` but its kind is `local` — send `local`.
307
347
  neuralis request GET @neuralis/brain-core/sources/kinds --jq '.kinds[].kind'
308
- neuralis request GET @neuralis/brain-core/sources/kinds/local/schema
348
+ neuralis request GET @neuralis/brain-core/sources/kinds/host/schema
309
349
  neuralis request POST @neuralis/brain-core/sources/sync -f source=data # needs sources.sync
310
350
  neuralis request GET @neuralis/brain-core/sources/sync-status -f source=data
311
351
  # `"auto"` = live only while the source's runtime runs; a boolean is typed with -F
312
352
  neuralis request POST @neuralis/brain-core/sources/enabled -f source=data -F enabled=true
313
- neuralis request GET @neuralis/brain-core/sources/browse -f path=/tmp # needs sources.mount
353
+ neuralis request GET @neuralis/brain-core/sources/browse -f path="$DATA_ROOT" # needs sources.mount; DATA_ROOT = the data source's container= path
314
354
  ```
315
355
 
316
356
  ### Lifecycle walkthrough — create → update → delete
@@ -328,7 +368,7 @@ the throwaway.
328
368
  ```bash
329
369
  # 1. Create (needs sources.mount). source + connection.kind + permissions.default.* required.
330
370
  # The root does not have to exist yet — create records the coordinate, sync walks it.
331
- neuralis request POST @neuralis/brain-core/sources --input - <<<'{"source":"scratch-demo","connection":{"kind":"local","config":{"root":"/tmp/scratch-demo"}},"permissions":{"default":{"read":true,"write":true,"exec":false}}}'
371
+ echo '{"source":"scratch-demo","connection":{"kind":"host","config":{"root":"/tmp/scratch-demo"}},"permissions":{"default":{"read":true,"write":true,"exec":false}}}' | neuralis request POST @neuralis/brain-core/sources --input -
332
372
  # 2. Update — NO SLUG; the body `source` field is the key (needs sources.mount).
333
373
  # Sets the description shown in the agent <runtime_stack>. `permissions` is
334
374
  # REPLACED, so read the live object back and resend it unchanged, editing only
@@ -391,5 +431,5 @@ neuralis request GET @neuralis/brain-core/health/scan
391
431
  duplicate groups (from `/health/scan`); unindexed/stale per source (from `fs_list`).
392
432
  3. A changed embedding model is never mixed in: the index keeps embedding with the model
393
433
  it was built with until the owner rebuilds it from the admin Vector section — no reset.
394
- 4. If issues found, suggest specific remediation: source sync for stale data, `reembed.sh` for
434
+ 4. If issues found, suggest specific remediation: source sync for stale data, a `force` re-embed for
395
435
  files whose vectors look wrong, `POST /health/gc` to gc / repair-orphans / deduplicate.
@@ -66,22 +66,25 @@ undone.
66
66
  # 0. Read the policy you are about to change, so you can prove you restored it.
67
67
  neuralis request GET @neuralis/brain-core/policies/uri/data
68
68
  # 1. Add the rule (LIVE — members lose read on this subtree immediately).
69
- neuralis request POST @neuralis/brain-core/policies/uri --input - <<<'{"source":"data","addPaths":[{"pattern":"data://agent-core/admin/**","permissions":{"read":false},"roles":["member"]}]}'
69
+ echo '{"source":"data","addPaths":[{"pattern":"data://agent-core/admin/**","permissions":{"read":false},"roles":["member"]}]}' | neuralis request POST @neuralis/brain-core/policies/uri --input -
70
70
  # 2. Take it back — same source, same pattern, byte for byte.
71
- neuralis request POST @neuralis/brain-core/policies/uri --input - <<<'{"source":"data","removePatterns":["data://agent-core/admin/**"]}'
71
+ echo '{"source":"data","removePatterns":["data://agent-core/admin/**"]}' | neuralis request POST @neuralis/brain-core/policies/uri --input -
72
72
  ```
73
73
 
74
74
  To keep a rule, run step 1 and stop; step 2 exists so the example is reversible
75
75
  rather than a permanent edit to a live source's access policy.
76
76
 
77
77
  Body: `source` (slug, required) plus either `addPaths` — rules of `{pattern,
78
- permissions, roles?}`, where `pattern` takes `**` wildcards, `permissions` maps
79
- `read`/`write`/`exec` to `false` (deny) or `true` (allow) and `roles` scopes the
80
- rule — or `removePatterns` (the patterns to take back).
78
+ permissions, roles?, priority?, override?}`, where `pattern` takes `**` wildcards, `permissions` maps
79
+ `read`/`write`/`exec` to `false` (deny) or `true` (allow), `roles` scopes the
80
+ rule to named project roles (each must exist in the project, else 400) and
81
+ `priority: 2` to callers whose role priority is 2 or stronger — admin and owner,
82
+ lower = stronger (an integer 1..99, only on a grant row: `override: true` with every
83
+ listed bit `true`); present fields all apply — or `removePatterns` (the patterns to take back).
81
84
 
82
85
  `exec` decides whether a shell may START in that directory — on an exec-capable
83
86
  source (a virtual desktop or any other one whose connector runs commands) as
84
- well as in the container. A caller also needs that plane's entry feature; the
87
+ well as on the app's own machine. A caller also needs that plane's entry feature; the
85
88
  policy row alone does not grant one, and the entry alone does not grant the row.
86
89
  So a source whose owner reports "I hold the feature and the shell is still
87
90
  refused" usually needs an `exec` ALLOW row for their role or agent here.
@@ -13,8 +13,8 @@ Trigger a delta sync for the brain-core filesystem.
13
13
 
14
14
  1. Use `fs_list` with no `uri` first to identify configured sources, scopes, current sync status, and recent errors.
15
15
  2. Call the brain-core source sync route for the intended source. The route answers 202 + a queue job snapshot — the sync runs in the background. Explicit sync requires `sources.sync`; source create/update/delete uses `sources.mount`; file writes use `files.write`.
16
- 3. Poll `GET /sources/sync-status?source=<slug>` until the job finishes, then report the job `result` counts: `filesAdded`, `filesUpdated`, `filesRemoved`, `filesSkipped`, `filesMoved`, `chunksRemoved`, `chunksEmbedded` and `chunksSkipped` plus `embeddingDegraded` (safe, deduplicated embedding stop reasons). Payload indexing can succeed with missing/stale embeddings; report that debt separately. Read the two flags before interpreting completion. `cancelled: true` is not a failure, but the run stopped early: the counts are partial and a re-run converges. `truncated: true` means the walk stopped at `filesScanCap`, so files past the cap were never examined and no deletion or move was inferred — call that a partial pass, never a completed sync.
17
- 4. If any errors occur, list them clearly with the affected source, scope, and file path.
16
+ 3. Poll `GET /sources/sync-status?source=<slug>` until the job finishes, then report the job `result` counts: `filesAdded`, `filesUpdated`, `filesRemoved`, `filesSkipped`, `filesMoved`, `chunksRemoved`, `chunksEmbedded` and `chunksSkipped` plus `embeddingDegraded` (safe, deduplicated embedding stop reasons). Payload indexing can succeed with missing/stale embeddings; report that debt separately. Read the two flags before interpreting completion. `cancelled: true` is not a failure, but the run stopped early: the counts are partial and a re-run converges. `truncated: true` means the walk stopped at `filesScanCap`, so files past the cap were never examined and no deletion or move was inferred — call that a partial pass, never a completed sync. A job that stays `pending` while other calls answer `vector_store_unavailable` is held for the vector store: it runs by itself when the store is back — stop polling and report it as waiting, never as failed.
17
+ 4. If any errors occur, list them clearly with the affected source, scope, and file path. Two job errors are fixed codes and removed nothing: `root_unreachable` (the source root cannot be reached — unmounted, renamed, device offline; fix the mount, then sync again) and `root_empty` (the root answers but holds no file while the index still holds some). Re-send `confirmEmpty:true` with the sync only after the user confirms the folder really is empty — that one pass removes its files from the index.
18
18
  5. Distinguish live connector data, indexed payload and embedding freshness. Provider outage or disabled embedding preserves metadata/full-text indexing; semantic results may be old, or the response may fall back to filter search. Ordinary sync completion does not settle all embedding debt. Use `manage-sources` explicit debt catchup; terminal `paused` carries `result.embedding.pausedReason`, and Resume creates a new authorized job from durable debt.
19
19
 
20
20
  ## What a sync will and will not index
@@ -1,171 +0,0 @@
1
- import type { ConnectorPort, ConnectorCapability, ConnectorListItem, ConnectorReadResult, ConnectorReadRawOpts, ConnectorReadRawResult, ConnectorStatResult, ConnectorMoveResult, ConnectorWriteResult, ConnectorDeltaRequest, ConnectorDeltaResult, ConnectorCountOpts, ConnectorWalkOpts, ScanContentOpts, ScanContentResult, ConnectorFactoryContext, ConnectorChangeEvent, ConnectorEventSubscription, ConnectorSubscribeOpts, ConnectorConnectionProbe } from '@neuralis/package-system/contracts';
2
- import { ConnectorRootAccessError } from '@neuralis/package-system/contracts';
3
- import { type OsMount } from '@neuralis/package-system/paths';
4
- /**
5
- * Concrete root-access error thrown by the local-disk connector. Routes +
6
- * services catch the abstract base (`ConnectorRootAccessError`), not this
7
- * class specifically — so every future connector that touches a real FS
8
- * surface can share the same structured-warning pathway.
9
- */
10
- export declare class LocalDiskRootAccessError extends ConnectorRootAccessError {
11
- constructor(code: 'ROOT_MISSING' | 'ROOT_PERMISSION_DENIED', rootPath: string, uri: string, cause?: unknown);
12
- }
13
- /**
14
- * The capability set the local on-disk connector implements. This MUST stay
15
- * byte-equal to the `local` connector's `capabilities` array in
16
- * `package.json#neuralis.connectors` — `SourceLoader.instantiateConnector`
17
- * fails closed (`ConnectorCapabilityMismatch`) on any divergence, and for a
18
- * first-party connector `wiring.ts` now re-throws that (boot-fatal) instead of
19
- * silently degrading the kind. `localDiskCapabilities.test.ts` is the
20
- * derive-and-verify drift guard that catches a mismatch at TEST time.
21
- */
22
- export declare const LOCAL_DISK_CAPABILITIES: readonly ConnectorCapability[];
23
- /**
24
- * Structured failure thrown by `LocalDiskConnector.resolveOsUri` when the
25
- * connector is running inside a Docker container but no host-pair root has
26
- * been configured. Returning a container-internal path here would corrupt
27
- * vector payloads + filesystem-node `os_uri` fields with paths that do not
28
- * exist on the host. Callers (sync runner, the write engine) catch this
29
- * and either skip the upsert or persist `os_uri: undefined` instead.
30
- */
31
- export declare class OsUriUnresolvableError extends Error {
32
- readonly code: 'os_uri_host_pair_missing';
33
- readonly source: string;
34
- readonly uri: string;
35
- constructor(params: {
36
- source: string;
37
- uri: string;
38
- root?: string;
39
- });
40
- }
41
- /**
42
- * Connector for local filesystem access — URI-native.
43
- *
44
- * Contributed by brain-core via `neuralis.connectors[]` manifest entry
45
- * `{ kind: 'local', configSchema: { root, hostRoot? } }`. The package loader
46
- * instantiates it via `createLocalDiskConnector(ctx)` for each source binding.
47
- */
48
- export declare class LocalDiskConnector implements ConnectorPort {
49
- #private;
50
- readonly kind = "local";
51
- readonly source: string;
52
- readonly portVersion: 4;
53
- constructor(root: string, source: string, hostRoot?: string, isDocker?: boolean);
54
- capabilities(): ReadonlySet<ConnectorCapability>;
55
- /** Expose the resolved root path for diagnostics / wiring logs. */
56
- get root(): string;
57
- probeRoot(): Promise<{
58
- rootPath: string;
59
- exists: boolean;
60
- readable: boolean;
61
- error?: string;
62
- }>;
63
- /**
64
- * Connector-owned liveness — whether the backing host directory is reachable.
65
- * Wraps {@link probeRoot} but maps to the fixed `SourceLiveReason` enum and
66
- * DISCARDS the raw `rootPath`/`error` (those carry the absolute host-mount
67
- * path — leaking them to a member via the tone-title is a path-disclosure
68
- * regression). UI-tone + `<runtime_stack>` signal only; never gates access.
69
- */
70
- probeConnection(): Promise<ConnectorConnectionProbe>;
71
- list(uri: string): Promise<ConnectorListItem[]>;
72
- /**
73
- * Existence + metadata, on the SAME guarded path as `read` and without
74
- * transferring a byte of content. `null` = the path resolved but nothing is
75
- * there (`ENOENT`, from either the guard's per-segment walk or the `lstat`);
76
- * every other failure THROWS exactly as `read` would — a traversal/symlink
77
- * refusal, an EACCES, a root-access error — so the caller's existing
78
- * "gone vs. could-not-ask" split keeps working unchanged.
79
- *
80
- * `lstat`, never `stat`: `resolveAndGuard` REFUSES a symlink rather than
81
- * resolving through it, so following one here would answer for a target the
82
- * read path would never have served.
83
- */
84
- stat(uri: string): Promise<ConnectorStatResult | null>;
85
- /**
86
- * The sync media lane's PDF read — NOT a kernel `ConnectorPort` member (only
87
- * a connector that holds the file on its own disk can render it; the lane
88
- * treats a connector without it as "unavailable"). The raw bytes' sha256
89
- * (the point's `content_hash`) and pages `first..last` rendered by the ONE
90
- * renderer — none when the hash equals `unlessHash`, so an unchanged PDF is
91
- * never re-rendered. `null` when `pdftoppm` is not installed; the same
92
- * containment and read cap as `read`.
93
- */
94
- renderPdfPages(uri: string, opts: {
95
- first: number;
96
- last: number;
97
- unlessHash?: string;
98
- }): Promise<{
99
- contentHash: string;
100
- pages: Array<{
101
- page: number;
102
- png: Buffer;
103
- }>;
104
- } | null>;
105
- /**
106
- * The byte-exact read. Same guarded resolver as `read`; the cap is
107
- * `min(opts.maxBytes, brainMaxReadFileMb)`, checked on the OPENED
108
- * descriptor's size before any byte is buffered, and the read itself pulls
109
- * at most that size+1 bytes — a file that grew after the size check is
110
- * refused (over the cap: the too-large refusal), never cut.
111
- */
112
- readRaw(uri: string, opts: ConnectorReadRawOpts): Promise<ConnectorReadRawResult>;
113
- read(uri: string): Promise<ConnectorReadResult>;
114
- write(uri: string, content: string | Uint8Array): Promise<ConnectorWriteResult>;
115
- delete(uri: string): Promise<void>;
116
- move(fromUri: string, toUri: string): Promise<ConnectorMoveResult>;
117
- mkdir(uri: string): Promise<void>;
118
- rmdir(uri: string): Promise<void>;
119
- /**
120
- * OS-level change events under `rootUri`, fed by the shared FsWatchHub
121
- * (D6: ONE watcher substrate). Catches EVERY background change — shell
122
- * writes, host edits, git checkouts, external programs — not just app
123
- * writes. URI mapping happens here (the hub only knows absolute paths);
124
- * exclude filtering and debounce are the SUBSCRIBER's job. An `overflow`
125
- * event means "event delivery can no longer be trusted — full reconcile".
126
- */
127
- subscribeEvents(rootUri: string, listener: (event: ConnectorChangeEvent) => void, opts?: ConnectorSubscribeOpts): ConnectorEventSubscription;
128
- scanDelta(request: ConnectorDeltaRequest): Promise<ConnectorDeltaResult>;
129
- resolveOsUri(uri: string): string;
130
- peekCount(rootUri: string, opts?: ConnectorCountOpts): number | undefined;
131
- walk(rootUri: string, opts?: ConnectorWalkOpts): Promise<ConnectorListItem[]>;
132
- walkWithStatus(rootUri: string, opts?: ConnectorWalkOpts): Promise<{
133
- items: ConnectorListItem[];
134
- complete: boolean;
135
- truncated: boolean;
136
- }>;
137
- count(rootUri: string, opts?: ConnectorCountOpts): Promise<number>;
138
- scanContent(rootUri: string, query: string, opts?: ScanContentOpts): Promise<ScanContentResult[]>;
139
- }
140
- /**
141
- * Factory: builds a LocalDiskConnector instance for a specific source binding.
142
- *
143
- * Resolves `config.root` against the current projectRoot
144
- * (`resolveLocalRoot`): a relative path joins onto `ctx.projectRoot`, an
145
- * absolute one is the container path as written.
146
- */
147
- export declare function createLocalDiskConnector(ctx: ConnectorFactoryContext): ConnectorPort;
148
- /**
149
- * Derive a host-side root for `resolvedRoot` from the os-mount table. Returns
150
- * the host path for the *longest* matching mount whose `containerPath` is the
151
- * root itself or a path-boundary-correct ancestor (`/mounts/repo` matches
152
- * `/mounts/repo` and `/mounts/repo/sub`, but NOT `/mounts/repo2`). Mounts
153
- * without a `hostPath` (no `NEURALIS_MOUNT_HOST_*` pair) are skipped. Returns
154
- * `undefined` when nothing matches, so the caller falls through to the
155
- * fail-loud `OsUriUnresolvableError` path in Docker.
156
- */
157
- export declare function deriveHostRootFromOsMounts(resolvedRoot: string, mounts: OsMount[]): string | undefined;
158
- /**
159
- * Canonical container-root resolution for a local source's configured root.
160
- * Exported so the brain-core API can hand agent-core's shell uri-policy gate
161
- * the SAME resolved roots the connector itself mounts — the two branches
162
- * (relative under the project root, absolute as written) are never re-typed.
163
- */
164
- export declare function resolveLocalRoot(params: {
165
- configured: string;
166
- projectRoot: string;
167
- source: string;
168
- }): {
169
- resolvedRoot: string;
170
- };
171
- //# sourceMappingURL=LocalDiskConnector.d.ts.map