@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.
- package/README.md +80 -1410
- package/app/README.md +1 -1
- package/app/cards/FilesystemCardShell.tsx +42 -4
- package/app/cards/FilesystemChangeCard.tsx +34 -11
- package/app/cards/README.md +6 -5
- package/app/cards/diffUtils.ts +99 -1
- package/app/filesystem/FilesystemHost.tsx +17 -2
- package/app/filesystem/api/README.md +3 -3
- package/app/filesystem/api/index.ts +35 -11
- package/app/filesystem/api/projectPackages.ts +13 -102
- package/app/filesystem/domain/types.ts +30 -10
- package/app/filesystem/hooks/README.md +3 -3
- package/app/filesystem/hooks/useDiscoverableSources.ts +19 -30
- package/app/filesystem/hooks/useFilesystemSSE.ts +1 -1
- package/app/filesystem/host/README.md +5 -3
- package/app/filesystem/host/buildFilesystemHostValue.ts +19 -0
- package/app/filesystem/host/installFilesystemHostComponents.tsx +1 -1
- package/app/filesystem/lib/sourceKindForm.ts +118 -39
- package/app/filesystem/lib/treeVisualState.tsx +98 -4
- package/app/filesystem/store/README.md +1 -0
- package/app/filesystem/store/filesystemStore.ts +86 -5
- package/app/filesystem/store/gitSlice.ts +5 -0
- package/app/filesystem/store/helpers.ts +17 -0
- package/app/filesystem/store/listSlice.ts +8 -0
- package/app/filesystem/ui/CodeEditor.tsx +18 -3
- package/app/filesystem/ui/FileEditor.tsx +15 -10
- package/app/filesystem/ui/FileTree.tsx +41 -16
- package/app/filesystem/ui/FolderPicker.tsx +251 -0
- package/app/filesystem/ui/GitControlPanel.tsx +5 -0
- package/app/filesystem/ui/PackagesPanel.tsx +52 -374
- package/app/filesystem/ui/PolicyEditor.tsx +109 -24
- package/app/filesystem/ui/README.md +17 -11
- package/app/filesystem/ui/RawMediaPreview.tsx +58 -0
- package/app/filesystem/ui/SourceBranchHeader.tsx +4 -4
- package/app/filesystem/ui/SourcesPanel.tsx +420 -360
- package/app/filesystem/ui/Toolbar.tsx +1 -2
- package/app/shared/filesystem.png +0 -0
- package/dist/app/host.js +53 -48
- package/dist/scripts/sourceRootPairV1.d.ts +47 -0
- package/dist/scripts/sourceRootPairV1.d.ts.map +1 -0
- package/dist/scripts/sourceRootPairV1.js +147 -0
- package/dist/scripts/sourceRootPairV1.js.map +1 -0
- package/dist/scripts/sourceToFolderV1.d.ts +56 -0
- package/dist/scripts/sourceToFolderV1.d.ts.map +1 -0
- package/dist/scripts/sourceToFolderV1.js +152 -0
- package/dist/scripts/sourceToFolderV1.js.map +1 -0
- package/dist/scripts/sourceToHostV1.d.ts +56 -0
- package/dist/scripts/sourceToHostV1.d.ts.map +1 -0
- package/dist/scripts/sourceToHostV1.js +132 -0
- package/dist/scripts/sourceToHostV1.js.map +1 -0
- package/dist/src/config/env.d.ts +8 -0
- package/dist/src/config/env.d.ts.map +1 -1
- package/dist/src/config/env.js +17 -6
- package/dist/src/config/env.js.map +1 -1
- package/dist/src/connectors/AppSourceConfigStore.d.ts +17 -3
- package/dist/src/connectors/AppSourceConfigStore.d.ts.map +1 -1
- package/dist/src/connectors/AppSourceConfigStore.js +46 -6
- package/dist/src/connectors/AppSourceConfigStore.js.map +1 -1
- package/dist/src/connectors/HostConnector.d.ts +201 -0
- package/dist/src/connectors/HostConnector.d.ts.map +1 -0
- package/dist/src/connectors/HostConnector.js +903 -0
- package/dist/src/connectors/HostConnector.js.map +1 -0
- package/dist/src/connectors/inProcessTransport.d.ts +131 -0
- package/dist/src/connectors/inProcessTransport.d.ts.map +1 -0
- package/dist/src/connectors/inProcessTransport.js +447 -0
- package/dist/src/connectors/inProcessTransport.js.map +1 -0
- package/dist/src/domain/BrainError.d.ts +14 -0
- package/dist/src/domain/BrainError.d.ts.map +1 -1
- package/dist/src/domain/BrainError.js +21 -0
- package/dist/src/domain/BrainError.js.map +1 -1
- package/dist/src/domain/access/callerPermissions.d.ts +29 -0
- package/dist/src/domain/access/callerPermissions.d.ts.map +1 -1
- package/dist/src/domain/access/callerPermissions.js +85 -5
- package/dist/src/domain/access/callerPermissions.js.map +1 -1
- package/dist/src/domain/access/nativeLocalFence.d.ts +65 -0
- package/dist/src/domain/access/nativeLocalFence.d.ts.map +1 -0
- package/dist/src/domain/access/nativeLocalFence.js +171 -0
- package/dist/src/domain/access/nativeLocalFence.js.map +1 -0
- package/dist/src/domain/access/uriPermission.js +3 -3
- package/dist/src/domain/access/uriPermission.js.map +1 -1
- package/dist/src/domain/byteRange.d.ts +15 -0
- package/dist/src/domain/byteRange.d.ts.map +1 -0
- package/dist/src/domain/byteRange.js +30 -0
- package/dist/src/domain/byteRange.js.map +1 -0
- package/dist/src/domain/defaultPermissions.d.ts.map +1 -1
- package/dist/src/domain/defaultPermissions.js +29 -0
- package/dist/src/domain/defaultPermissions.js.map +1 -1
- package/dist/src/domain/mime.d.ts +8 -16
- package/dist/src/domain/mime.d.ts.map +1 -1
- package/dist/src/domain/mime.js +10 -99
- package/dist/src/domain/mime.js.map +1 -1
- package/dist/src/domain/paths.d.ts.map +1 -1
- package/dist/src/domain/paths.js +5 -3
- package/dist/src/domain/paths.js.map +1 -1
- package/dist/src/domain/sourceConfig.d.ts +52 -19
- package/dist/src/domain/sourceConfig.d.ts.map +1 -1
- package/dist/src/domain/sourceConfig.js +103 -19
- package/dist/src/domain/sourceConfig.js.map +1 -1
- package/dist/src/domain/sourcePackages.d.ts +8 -8
- package/dist/src/domain/sourcePackages.d.ts.map +1 -1
- package/dist/src/domain/sourceRootPair.d.ts +88 -0
- package/dist/src/domain/sourceRootPair.d.ts.map +1 -0
- package/dist/src/domain/sourceRootPair.js +108 -0
- package/dist/src/domain/sourceRootPair.js.map +1 -0
- package/dist/src/domain/syncTypes.d.ts +8 -1
- package/dist/src/domain/syncTypes.d.ts.map +1 -1
- package/dist/src/domain/syncTypes.js +1 -0
- package/dist/src/domain/syncTypes.js.map +1 -1
- package/dist/src/domain/types.d.ts +29 -1
- package/dist/src/domain/types.d.ts.map +1 -1
- package/dist/src/domain/uri.d.ts.map +1 -1
- package/dist/src/domain/uri.js +3 -2
- package/dist/src/domain/uri.js.map +1 -1
- package/dist/src/embeddings/clients/GeminiEmbedder.d.ts.map +1 -1
- package/dist/src/embeddings/clients/GeminiEmbedder.js +2 -5
- package/dist/src/embeddings/clients/GeminiEmbedder.js.map +1 -1
- package/dist/src/embeddings/clients/OpenAIEmbedder.d.ts.map +1 -1
- package/dist/src/embeddings/clients/OpenAIEmbedder.js +2 -3
- package/dist/src/embeddings/clients/OpenAIEmbedder.js.map +1 -1
- package/dist/src/embeddings/clients/QwenEmbedder.d.ts +2 -0
- package/dist/src/embeddings/clients/QwenEmbedder.d.ts.map +1 -1
- package/dist/src/embeddings/clients/QwenEmbedder.js +10 -2
- package/dist/src/embeddings/clients/QwenEmbedder.js.map +1 -1
- package/dist/src/embeddings/clients/VoyageEmbedder.d.ts +2 -0
- package/dist/src/embeddings/clients/VoyageEmbedder.d.ts.map +1 -1
- package/dist/src/embeddings/clients/VoyageEmbedder.js +8 -1
- package/dist/src/embeddings/clients/VoyageEmbedder.js.map +1 -1
- package/dist/src/embeddings/factory.d.ts +5 -3
- package/dist/src/embeddings/factory.d.ts.map +1 -1
- package/dist/src/embeddings/factory.js +7 -3
- package/dist/src/embeddings/factory.js.map +1 -1
- package/dist/src/embeddings/models.d.ts +2 -3
- package/dist/src/embeddings/models.d.ts.map +1 -1
- package/dist/src/embeddings/models.js +1 -2
- package/dist/src/embeddings/models.js.map +1 -1
- package/dist/src/embeddings/retry.js +1 -1
- package/dist/src/embeddings/retry.js.map +1 -1
- package/dist/src/embeddings/types.d.ts +6 -0
- package/dist/src/embeddings/types.d.ts.map +1 -1
- package/dist/src/embeddings/types.js +11 -0
- package/dist/src/embeddings/types.js.map +1 -1
- package/dist/src/git/GitRunner.d.ts +110 -30
- package/dist/src/git/GitRunner.d.ts.map +1 -1
- package/dist/src/git/GitRunner.js +511 -199
- package/dist/src/git/GitRunner.js.map +1 -1
- package/dist/src/git/GitWatchRegistry.d.ts +41 -35
- package/dist/src/git/GitWatchRegistry.d.ts.map +1 -1
- package/dist/src/git/GitWatchRegistry.js +61 -79
- package/dist/src/git/GitWatchRegistry.js.map +1 -1
- package/dist/src/git/gitPlace.d.ts +61 -0
- package/dist/src/git/gitPlace.d.ts.map +1 -0
- package/dist/src/git/gitPlace.js +74 -0
- package/dist/src/git/gitPlace.js.map +1 -0
- package/dist/src/git/sourceGitControl.d.ts +31 -19
- package/dist/src/git/sourceGitControl.d.ts.map +1 -1
- package/dist/src/git/sourceGitControl.js +208 -92
- package/dist/src/git/sourceGitControl.js.map +1 -1
- package/dist/src/git/sourceGitStatus.js +1 -1
- package/dist/src/git/sourceGitStatus.js.map +1 -1
- package/dist/src/git/untrackedStats.js +1 -1
- package/dist/src/git/untrackedStats.js.map +1 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/lifecycle.d.ts +12 -16
- package/dist/src/lifecycle.d.ts.map +1 -1
- package/dist/src/lifecycle.js +2 -1
- package/dist/src/lifecycle.js.map +1 -1
- package/dist/src/routes/approve.d.ts.map +1 -1
- package/dist/src/routes/approve.js +3 -3
- package/dist/src/routes/approve.js.map +1 -1
- package/dist/src/routes/git.d.ts.map +1 -1
- package/dist/src/routes/git.js +183 -54
- package/dist/src/routes/git.js.map +1 -1
- package/dist/src/routes/health.d.ts.map +1 -1
- package/dist/src/routes/health.js +8 -5
- package/dist/src/routes/health.js.map +1 -1
- package/dist/src/routes/helpers/uriGuard.d.ts +1 -1
- package/dist/src/routes/helpers/uriGuard.d.ts.map +1 -1
- package/dist/src/routes/helpers/uriGuard.js +3 -2
- package/dist/src/routes/helpers/uriGuard.js.map +1 -1
- package/dist/src/routes/helpers.d.ts +20 -4
- package/dist/src/routes/helpers.d.ts.map +1 -1
- package/dist/src/routes/helpers.js +38 -5
- package/dist/src/routes/helpers.js.map +1 -1
- package/dist/src/routes/list.d.ts.map +1 -1
- package/dist/src/routes/list.js +5 -6
- package/dist/src/routes/list.js.map +1 -1
- package/dist/src/routes/pending.d.ts.map +1 -1
- package/dist/src/routes/pending.js +5 -5
- package/dist/src/routes/pending.js.map +1 -1
- package/dist/src/routes/policies.d.ts +6 -4
- package/dist/src/routes/policies.d.ts.map +1 -1
- package/dist/src/routes/policies.js +22 -16
- package/dist/src/routes/policies.js.map +1 -1
- package/dist/src/routes/raw.d.ts.map +1 -1
- package/dist/src/routes/raw.js +68 -14
- package/dist/src/routes/raw.js.map +1 -1
- package/dist/src/routes/read.d.ts.map +1 -1
- package/dist/src/routes/read.js +3 -3
- package/dist/src/routes/read.js.map +1 -1
- package/dist/src/routes/search.d.ts.map +1 -1
- package/dist/src/routes/search.js +3 -3
- package/dist/src/routes/search.js.map +1 -1
- package/dist/src/routes/sources.d.ts +60 -18
- package/dist/src/routes/sources.d.ts.map +1 -1
- package/dist/src/routes/sources.js +420 -308
- package/dist/src/routes/sources.js.map +1 -1
- package/dist/src/routes/upload.d.ts.map +1 -1
- package/dist/src/routes/upload.js +3 -3
- package/dist/src/routes/upload.js.map +1 -1
- package/dist/src/services/BridgeService.d.ts +15 -35
- package/dist/src/services/BridgeService.d.ts.map +1 -1
- package/dist/src/services/BridgeService.js +30 -88
- package/dist/src/services/BridgeService.js.map +1 -1
- package/dist/src/services/FilesystemService.d.ts +3 -2
- package/dist/src/services/FilesystemService.d.ts.map +1 -1
- package/dist/src/services/FilesystemService.js +116 -32
- package/dist/src/services/FilesystemService.js.map +1 -1
- package/dist/src/services/FilesystemUiService.d.ts +4 -1
- package/dist/src/services/FilesystemUiService.d.ts.map +1 -1
- package/dist/src/services/FilesystemUiService.js +71 -27
- package/dist/src/services/FilesystemUiService.js.map +1 -1
- package/dist/src/services/SyncScheduler.d.ts +12 -4
- package/dist/src/services/SyncScheduler.d.ts.map +1 -1
- package/dist/src/services/SyncScheduler.js +45 -10
- package/dist/src/services/SyncScheduler.js.map +1 -1
- package/dist/src/services/baselineRepair.d.ts +13 -3
- package/dist/src/services/baselineRepair.d.ts.map +1 -1
- package/dist/src/services/baselineRepair.js +13 -3
- package/dist/src/services/baselineRepair.js.map +1 -1
- package/dist/src/services/declaredSources.d.ts +125 -42
- package/dist/src/services/declaredSources.d.ts.map +1 -1
- package/dist/src/services/declaredSources.js +117 -45
- package/dist/src/services/declaredSources.js.map +1 -1
- package/dist/src/store/dataFormats.d.ts +17 -2
- package/dist/src/store/dataFormats.d.ts.map +1 -1
- package/dist/src/store/dataFormats.js +18 -3
- package/dist/src/store/dataFormats.js.map +1 -1
- package/dist/src/sync/DeltaSyncRunner.d.ts.map +1 -1
- package/dist/src/sync/DeltaSyncRunner.js +144 -4
- package/dist/src/sync/DeltaSyncRunner.js.map +1 -1
- package/dist/src/sync/SyncJobQueue.d.ts +14 -2
- package/dist/src/sync/SyncJobQueue.d.ts.map +1 -1
- package/dist/src/sync/SyncJobQueue.js +56 -10
- package/dist/src/sync/SyncJobQueue.js.map +1 -1
- package/dist/src/sync/SyncWatchService.d.ts +21 -4
- package/dist/src/sync/SyncWatchService.d.ts.map +1 -1
- package/dist/src/sync/SyncWatchService.js +115 -10
- package/dist/src/sync/SyncWatchService.js.map +1 -1
- package/dist/src/sync/categoryInference.d.ts +1 -1
- package/dist/src/sync/categoryInference.js +1 -1
- package/dist/src/tools/execCtx.d.ts +6 -0
- package/dist/src/tools/execCtx.d.ts.map +1 -1
- package/dist/src/tools/execCtx.js +11 -0
- package/dist/src/tools/execCtx.js.map +1 -1
- package/dist/src/tools/fs_list.js +2 -2
- package/dist/src/tools/fs_list.js.map +1 -1
- package/dist/src/tools/fs_read.js +2 -2
- package/dist/src/tools/fs_read.js.map +1 -1
- package/dist/src/tools/fs_search.js +2 -2
- package/dist/src/tools/fs_search.js.map +1 -1
- package/dist/src/tools/fs_write.js +2 -2
- package/dist/src/tools/fs_write.js.map +1 -1
- package/dist/src/usecases/admitSourceRoot.d.ts +65 -0
- package/dist/src/usecases/admitSourceRoot.d.ts.map +1 -0
- package/dist/src/usecases/admitSourceRoot.js +85 -0
- package/dist/src/usecases/admitSourceRoot.js.map +1 -0
- package/dist/src/usecases/browseSourceFolders.d.ts +85 -0
- package/dist/src/usecases/browseSourceFolders.d.ts.map +1 -0
- package/dist/src/usecases/browseSourceFolders.js +210 -0
- package/dist/src/usecases/browseSourceFolders.js.map +1 -0
- package/dist/src/usecases/createDeclaredSources.d.ts +13 -2
- package/dist/src/usecases/createDeclaredSources.d.ts.map +1 -1
- package/dist/src/usecases/createDeclaredSources.js +39 -0
- package/dist/src/usecases/createDeclaredSources.js.map +1 -1
- package/dist/src/usecases/deprovisionProject.d.ts +4 -5
- package/dist/src/usecases/deprovisionProject.d.ts.map +1 -1
- package/dist/src/usecases/deprovisionProject.js +3 -8
- package/dist/src/usecases/deprovisionProject.js.map +1 -1
- package/dist/src/usecases/list.d.ts.map +1 -1
- package/dist/src/usecases/list.js +83 -26
- package/dist/src/usecases/list.js.map +1 -1
- package/dist/src/usecases/listAttachableDevices.d.ts +13 -0
- package/dist/src/usecases/listAttachableDevices.d.ts.map +1 -0
- package/dist/src/usecases/listAttachableDevices.js +10 -0
- package/dist/src/usecases/listAttachableDevices.js.map +1 -0
- package/dist/src/usecases/listSourcePackages.d.ts.map +1 -1
- package/dist/src/usecases/listSourcePackages.js +95 -79
- package/dist/src/usecases/listSourcePackages.js.map +1 -1
- package/dist/src/usecases/purgeExcludedPoints.d.ts.map +1 -1
- package/dist/src/usecases/purgeExcludedPoints.js +3 -2
- package/dist/src/usecases/purgeExcludedPoints.js.map +1 -1
- package/dist/src/usecases/readFiles.d.ts.map +1 -1
- package/dist/src/usecases/readFiles.js +17 -1
- package/dist/src/usecases/readFiles.js.map +1 -1
- package/dist/src/usecases/reconcileSourcePackageRoots.d.ts +1 -1
- package/dist/src/usecases/reconcileSourcePackageRoots.d.ts.map +1 -1
- package/dist/src/usecases/reconcileSourcePackageRoots.js +2 -1
- package/dist/src/usecases/reconcileSourcePackageRoots.js.map +1 -1
- package/dist/src/usecases/revokePrincipal.d.ts +7 -5
- package/dist/src/usecases/revokePrincipal.d.ts.map +1 -1
- package/dist/src/usecases/revokePrincipal.js +29 -7
- package/dist/src/usecases/revokePrincipal.js.map +1 -1
- package/dist/src/usecases/scheduleSourceSync.d.ts +7 -0
- package/dist/src/usecases/scheduleSourceSync.d.ts.map +1 -1
- package/dist/src/usecases/scheduleSourceSync.js +6 -5
- package/dist/src/usecases/scheduleSourceSync.js.map +1 -1
- package/dist/src/usecases/searchFiles.d.ts.map +1 -1
- package/dist/src/usecases/searchFiles.js +13 -3
- package/dist/src/usecases/searchFiles.js.map +1 -1
- package/dist/src/usecases/sourcePackageInventory.d.ts +10 -2
- package/dist/src/usecases/sourcePackageInventory.d.ts.map +1 -1
- package/dist/src/usecases/sourcePackageInventory.js +24 -7
- package/dist/src/usecases/sourcePackageInventory.js.map +1 -1
- package/dist/src/usecases/triggerSourceSync.d.ts +46 -0
- package/dist/src/usecases/triggerSourceSync.d.ts.map +1 -0
- package/dist/src/usecases/triggerSourceSync.js +75 -0
- package/dist/src/usecases/triggerSourceSync.js.map +1 -0
- package/dist/src/usecases/uploadBinary.d.ts +2 -1
- package/dist/src/usecases/uploadBinary.d.ts.map +1 -1
- package/dist/src/usecases/uploadBinary.js +2 -2
- package/dist/src/usecases/uploadBinary.js.map +1 -1
- package/dist/src/usecases/vector/endpointGuard.d.ts +1 -1
- package/dist/src/usecases/vector/endpointGuard.js +1 -1
- package/dist/src/usecases/vectorActivityWatch.d.ts +20 -13
- package/dist/src/usecases/vectorActivityWatch.d.ts.map +1 -1
- package/dist/src/usecases/vectorActivityWatch.js +61 -36
- package/dist/src/usecases/vectorActivityWatch.js.map +1 -1
- package/dist/src/usecases/vectorMaintenance.d.ts.map +1 -1
- package/dist/src/usecases/vectorMaintenance.js +16 -1
- package/dist/src/usecases/vectorMaintenance.js.map +1 -1
- package/dist/src/usecases/write/index.d.ts.map +1 -1
- package/dist/src/usecases/write/index.js +17 -2
- package/dist/src/usecases/write/index.js.map +1 -1
- package/dist/src/usecases/write/occupancy.d.ts +5 -1
- package/dist/src/usecases/write/occupancy.d.ts.map +1 -1
- package/dist/src/usecases/write/occupancy.js +13 -4
- package/dist/src/usecases/write/occupancy.js.map +1 -1
- package/dist/src/usecases/write/structure.d.ts.map +1 -1
- package/dist/src/usecases/write/structure.js +20 -5
- package/dist/src/usecases/write/structure.js.map +1 -1
- package/dist/src/vector/FilesystemVectorIndex.d.ts +72 -2
- package/dist/src/vector/FilesystemVectorIndex.d.ts.map +1 -1
- package/dist/src/vector/FilesystemVectorIndex.js +211 -27
- package/dist/src/vector/FilesystemVectorIndex.js.map +1 -1
- package/dist/src/vector/InMemoryVectorIndex.d.ts.map +1 -1
- package/dist/src/vector/InMemoryVectorIndex.js +55 -7
- package/dist/src/vector/InMemoryVectorIndex.js.map +1 -1
- package/dist/src/vector/qdrantClient.d.ts +18 -1
- package/dist/src/vector/qdrantClient.d.ts.map +1 -1
- package/dist/src/vector/qdrantClient.js +48 -6
- package/dist/src/vector/qdrantClient.js.map +1 -1
- package/dist/src/wiring.d.ts +10 -12
- package/dist/src/wiring.d.ts.map +1 -1
- package/dist/src/wiring.js +101 -61
- package/dist/src/wiring.js.map +1 -1
- package/package.json +166 -54
- package/skills/connect-business-data/SKILL.md +2 -2
- package/skills/create-package/SKILL.md +18 -18
- package/skills/create-package/references/config-and-credentials.md +16 -13
- package/skills/create-package/references/connectors-and-uri-policies.md +36 -27
- package/skills/create-package/references/manifest-and-discovery.md +12 -12
- package/skills/create-package/references/runtime-and-build.md +18 -18
- package/skills/create-package/references/skills-and-context.md +35 -19
- package/skills/create-package/references/surfaces-and-design.md +16 -16
- package/skills/create-package/references/team-and-workflows.md +2 -2
- package/skills/create-package/references/test-and-ship.md +17 -17
- package/skills/create-package/references/tools-and-schemas.md +5 -5
- package/skills/create-package/scripts/{check-package.sh → check-package.mjs} +78 -64
- package/skills/create-package/scripts/{verify-loaded.sh → verify-loaded.mjs} +156 -162
- package/skills/git/SKILL.md +31 -29
- package/skills/manage-files/SKILL.md +11 -14
- package/skills/manage-sources/SKILL.md +85 -45
- package/skills/manage-uri-policy/SKILL.md +9 -6
- package/skills/sync/SKILL.md +2 -2
- package/dist/src/connectors/LocalDiskConnector.d.ts +0 -171
- package/dist/src/connectors/LocalDiskConnector.d.ts.map +0 -1
- package/dist/src/connectors/LocalDiskConnector.js +0 -1233
- package/dist/src/connectors/LocalDiskConnector.js.map +0 -1
- package/skills/manage-files/scripts/copy.sh +0 -7
- package/skills/manage-files/scripts/create.sh +0 -7
- package/skills/manage-files/scripts/mkdir.sh +0 -7
- package/skills/manage-files/scripts/modify.sh +0 -7
- package/skills/manage-files/scripts/upload.sh +0 -16
- package/skills/manage-files/scripts/write.sh +0 -29
- package/skills/manage-sources/scripts/reembed.sh +0 -23
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `GET /sources/browse` — one level of FOLDERS, the step that precedes attaching
|
|
3
|
+
* a source. Two planes, one rule: **you may browse exactly what you would be
|
|
4
|
+
* allowed to attach.**
|
|
5
|
+
*
|
|
6
|
+
* - **This server** (`browseServerFolders`). The route admits `sources.mount`
|
|
7
|
+
* (the attach act's own gate) and hands over the gates it owns: the shared
|
|
8
|
+
* protected-root table (`/`, the App Zone and the Neuralis tree cost
|
|
9
|
+
* `sources.privileged` here exactly as at attach time), matched IS-or-UNDER
|
|
10
|
+
* so a parent stays walkable while a protected child is simply absent
|
|
11
|
+
* (hidden-not-locked), and the native folder fence. Natively any absolute
|
|
12
|
+
* path the gates admit; in Docker the `/mounts` zone and every folder under
|
|
13
|
+
* it, never above it. The gate runs on the lexical path AND again on the
|
|
14
|
+
* `realpath` — a symlink whose literal path is innocent can still point at
|
|
15
|
+
* `/`, a protected zone or out of `/mounts`.
|
|
16
|
+
* - **The caller's own device** (`browseDeviceFolders`). The device plane's
|
|
17
|
+
* ONE attach gate (agent-core's `mayAttach`: the device's owner holding
|
|
18
|
+
* `device.own`, nothing else — `sources.mount` is a manager default and never
|
|
19
|
+
* reaches somebody's machine) decides; every other caller gets ONE fixed
|
|
20
|
+
* refusal, the same bytes for an unknown id. The device's broker clamps the
|
|
21
|
+
* path against the folders its owner allowed THIS host, lexically before any
|
|
22
|
+
* realpath, so a refusal says nothing about existence. An empty path lists
|
|
23
|
+
* those allowed folders (where the picker starts).
|
|
24
|
+
*
|
|
25
|
+
* Invariant 9 on both planes: a failure never carries the path or an errno —
|
|
26
|
+
* one stable sentence on this server, a fixed code from a device; the operator
|
|
27
|
+
* reads the detail in the server log. Cost: one `readdir` + `realpath` per call
|
|
28
|
+
* here; one broker `/fs/list` (≤ 2 000 entries, folder names only on the way
|
|
29
|
+
* back) or one `/ceiling/roots` per call on a device. No cache, no timer.
|
|
30
|
+
*/
|
|
31
|
+
import { readdir, realpath, stat } from 'node:fs/promises';
|
|
32
|
+
import { platform } from 'node:os';
|
|
33
|
+
import { dirname, isAbsolute, join, posix, resolve } from 'node:path';
|
|
34
|
+
import { hostPathFlavour, isFilesystemRoot, isPathInside } from '@neuralis/package-system/paths';
|
|
35
|
+
import { NATIVE_LOCAL_REFUSAL, nativeLocalPlacement } from '../domain/access/nativeLocalFence.js';
|
|
36
|
+
/** One stable sentence for every server-side browse failure (invariant 9). */
|
|
37
|
+
export const BROWSE_UNREADABLE = 'That path is not available.';
|
|
38
|
+
/** The ONE answer to every caller the device attach gate does not admit — an unknown id included. */
|
|
39
|
+
export const DEVICE_BROWSE_REFUSAL = "Only the device's owner may browse it.";
|
|
40
|
+
/** The container's bind-mount zone: the only folders a Docker deployment can attach. */
|
|
41
|
+
export const DOCKER_MOUNTS_ROOT = '/mounts';
|
|
42
|
+
const refusedFeature = (feature) => ({ status: 403, body: { error: `Browsing this path requires the ${feature} feature.` } });
|
|
43
|
+
const unreadable = () => ({ status: 400, body: { error: BROWSE_UNREADABLE } });
|
|
44
|
+
/** The visible, non-dot sub-folders of `real`, sorted, as entries under `real`. */
|
|
45
|
+
async function listFolders(real, visible) {
|
|
46
|
+
const entries = await readdir(real, { withFileTypes: true });
|
|
47
|
+
return entries.filter((e) => e.isDirectory() && !e.name.startsWith('.'))
|
|
48
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
49
|
+
.map((e) => ({ name: e.name, path: join(real, e.name), type: 'directory' }))
|
|
50
|
+
.filter((e) => visible(e.path));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Docker: `/mounts` and anything under it — the zone's bind mounts and their
|
|
54
|
+
* sub-folders (an attach there derives its `hostRoot` from the bind, so a
|
|
55
|
+
* sub-folder works like the bind itself). Empty path ⇒ the zone. Outside the
|
|
56
|
+
* zone, lexically or by its realpath, is the one unreadable answer: the zone is
|
|
57
|
+
* the whole of what a container can attach. A zone that does not exist yet
|
|
58
|
+
* ("no mounts configured") is an empty list, not an error.
|
|
59
|
+
*/
|
|
60
|
+
async function browseDockerMounts(rawPath, gates, zone) {
|
|
61
|
+
const requested = rawPath || zone;
|
|
62
|
+
if (requested.includes('\0') || !posix.isAbsolute(requested))
|
|
63
|
+
return unreadable();
|
|
64
|
+
const canonical = posix.resolve(requested);
|
|
65
|
+
if (!isPathInside(zone, canonical, posix))
|
|
66
|
+
return unreadable();
|
|
67
|
+
let real;
|
|
68
|
+
let realZone;
|
|
69
|
+
try {
|
|
70
|
+
realZone = await realpath(zone);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return canonical === zone ? { status: 200, body: { entries: [], atRoot: true } } : unreadable();
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
real = await realpath(canonical);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return unreadable();
|
|
80
|
+
}
|
|
81
|
+
if (!isPathInside(realZone, real, posix))
|
|
82
|
+
return unreadable();
|
|
83
|
+
for (const candidate of new Set([canonical, real])) {
|
|
84
|
+
const missing = gates.missingFeatures(candidate);
|
|
85
|
+
if (missing.length > 0)
|
|
86
|
+
return refusedFeature(missing[0]);
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
return { status: 200, body: { entries: await listFolders(real, gates.childVisible), atRoot: real === realZone } };
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
console.warn('[sources/browse] readdir failed:', err instanceof Error ? err.message : String(err));
|
|
93
|
+
return unreadable();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** One level of folders on THIS server — the route has already admitted `sources.mount`. */
|
|
97
|
+
export async function browseServerFolders(input, gates) {
|
|
98
|
+
if (input.isDocker)
|
|
99
|
+
return browseDockerMounts(input.rawPath, gates, input.mountsRoot ?? DOCKER_MOUNTS_ROOT);
|
|
100
|
+
const rawPath = input.rawPath;
|
|
101
|
+
if (!rawPath)
|
|
102
|
+
return { status: 400, body: { error: 'Missing path parameter' } };
|
|
103
|
+
// A NUL byte survives `resolve()` unchanged and would slip past every string
|
|
104
|
+
// comparison in the table before `readdir` rejects it.
|
|
105
|
+
if (rawPath.includes('\0'))
|
|
106
|
+
return unreadable();
|
|
107
|
+
// A relative path would resolve against the SERVER process cwd — never what
|
|
108
|
+
// the caller meant, and it also closes the drive-relative `C:foo` form.
|
|
109
|
+
if (!isAbsolute(rawPath))
|
|
110
|
+
return { status: 400, body: { error: 'Path must be absolute' } };
|
|
111
|
+
// ONE canonical value from here on: the gate, the root test, the readdir and
|
|
112
|
+
// the child paths all use it.
|
|
113
|
+
const canonical = resolve(rawPath);
|
|
114
|
+
const denied = gates.missingFeatures(canonical);
|
|
115
|
+
if (denied.length > 0)
|
|
116
|
+
return refusedFeature(denied[0]);
|
|
117
|
+
const fenceRoot = await gates.fenceProject();
|
|
118
|
+
const fenceProject = fenceRoot ? resolve(fenceRoot) : '';
|
|
119
|
+
if (fenceRoot !== null && nativeLocalPlacement(canonical, fenceProject, gates.privilegedRoots) === 'outside') {
|
|
120
|
+
return { status: 403, body: NATIVE_LOCAL_REFUSAL };
|
|
121
|
+
}
|
|
122
|
+
// `resolve` is purely LEXICAL — re-run the same gate on the real path.
|
|
123
|
+
let real;
|
|
124
|
+
try {
|
|
125
|
+
real = await realpath(canonical);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return unreadable();
|
|
129
|
+
}
|
|
130
|
+
if (real !== canonical) {
|
|
131
|
+
const deniedReal = gates.missingFeatures(real);
|
|
132
|
+
if (deniedReal.length > 0)
|
|
133
|
+
return refusedFeature(deniedReal[0]);
|
|
134
|
+
}
|
|
135
|
+
const realProject = fenceProject ? await realpath(fenceProject).catch(() => fenceProject) : '';
|
|
136
|
+
const placement = fenceRoot === null ? null : nativeLocalPlacement(real, realProject, gates.privilegedRoots);
|
|
137
|
+
if (placement === 'outside')
|
|
138
|
+
return { status: 403, body: NATIVE_LOCAL_REFUSAL };
|
|
139
|
+
// Whole-host discovery by definition — the drive letters ARE the host. The
|
|
140
|
+
// filesystem-root floor already required the privileged feature; this second
|
|
141
|
+
// check keeps that true even if the table ever changes.
|
|
142
|
+
if (platform() === 'win32' && dirname(real) === real) {
|
|
143
|
+
if (!gates.mayBrowseDrives())
|
|
144
|
+
return refusedFeature(gates.privilegedFeature);
|
|
145
|
+
const drives = [];
|
|
146
|
+
for (const letter of 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') {
|
|
147
|
+
try {
|
|
148
|
+
await stat(`${letter}:\\`);
|
|
149
|
+
drives.push({ name: `${letter}:\\`, path: `${letter}:\\`, type: 'directory' });
|
|
150
|
+
}
|
|
151
|
+
catch { /* skip */ }
|
|
152
|
+
}
|
|
153
|
+
return { status: 200, body: { entries: drives, atRoot: true } };
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
const visible = (child) => gates.childVisible(child)
|
|
157
|
+
// Natively an ANCESTOR lists only the children on the way to an attachable root.
|
|
158
|
+
&& (placement !== 'ancestor' || nativeLocalPlacement(child, realProject, gates.privilegedRoots) !== 'outside');
|
|
159
|
+
// The "up" control's one answer — the kernel's root predicate, so a
|
|
160
|
+
// Windows drive root ends the climb exactly like `/`.
|
|
161
|
+
return { status: 200, body: { entries: await listFolders(real, visible), atRoot: isFilesystemRoot(real) } };
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
// Never the raw message: it carries the absolute path and tells "does not
|
|
165
|
+
// exist" from "cannot be read" — an existence oracle over the host.
|
|
166
|
+
console.warn('[sources/browse] readdir failed:', err instanceof Error ? err.message : String(err));
|
|
167
|
+
return unreadable();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* One level of folders on the caller's OWN paired device, or (empty path) the
|
|
172
|
+
* folders that device allows THIS host. `allowed` is the route's attach verdict
|
|
173
|
+
* (`devices.mayAttach`); agent-core re-checks it on every call. A device that
|
|
174
|
+
* cannot answer (offline, an older CLI, the folder outside what it allows) is a
|
|
175
|
+
* 200 with `state` = that fixed code and no entries — the picker says which,
|
|
176
|
+
* and a typed path still attaches (the create re-checks everything).
|
|
177
|
+
*/
|
|
178
|
+
export async function browseDeviceFolders(input, devices, session) {
|
|
179
|
+
const refused = { status: 403, body: { error: DEVICE_BROWSE_REFUSAL } };
|
|
180
|
+
if (!input.allowed || !devices)
|
|
181
|
+
return refused;
|
|
182
|
+
const { device, rawPath } = input;
|
|
183
|
+
if (!rawPath) {
|
|
184
|
+
const roots = await devices.ceilingRoots(session, device);
|
|
185
|
+
if (!roots.ok)
|
|
186
|
+
return roots.code === 'refused' ? refused : { status: 200, body: { entries: [], atRoot: true, roots: true, state: roots.code } };
|
|
187
|
+
const write = new Set(roots.write);
|
|
188
|
+
const all = [...new Set([...roots.read, ...roots.write])].sort((a, b) => a.localeCompare(b));
|
|
189
|
+
const entries = all.map((p) => ({ name: p, path: p, type: 'directory', access: write.has(p) ? 'write' : 'read' }));
|
|
190
|
+
return { status: 200, body: { entries, atRoot: true, roots: true, state: 'ok' } };
|
|
191
|
+
}
|
|
192
|
+
if (rawPath.includes('\0') || rawPath.length > 4096)
|
|
193
|
+
return unreadable();
|
|
194
|
+
if (!hostPathFlavour(rawPath).isAbsolute(rawPath))
|
|
195
|
+
return { status: 400, body: { error: 'Path must be absolute' } };
|
|
196
|
+
const listing = await devices.listFolder(session, device, rawPath);
|
|
197
|
+
if (!listing.ok)
|
|
198
|
+
return listing.code === 'refused' ? refused : { status: 200, body: { entries: [], atRoot: false, state: listing.code } };
|
|
199
|
+
return {
|
|
200
|
+
status: 200,
|
|
201
|
+
body: {
|
|
202
|
+
entries: listing.entries.map((e) => ({ ...e, type: 'directory' })),
|
|
203
|
+
atRoot: isFilesystemRoot(rawPath),
|
|
204
|
+
state: 'ok',
|
|
205
|
+
...(listing.truncated ? { truncated: true } : {}),
|
|
206
|
+
...(listing.symlinks > 0 ? { symlinks: listing.symlinks } : {}),
|
|
207
|
+
},
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=browseSourceFolders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browseSourceFolders.js","sourceRoot":"","sources":["../../../src/usecases/browseSourceFolders.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ConnectorHierarchicalPermissions, ConnectorPathPermission, PackageSourceDeclaration } from '@neuralis/package-system/contracts';
|
|
2
|
-
import type
|
|
2
|
+
import { type RuntimeStackInfo } from '@neuralis/package-system/paths';
|
|
3
3
|
import type { SourceConfigPort, SourceConfigScope } from '../connectors/types.js';
|
|
4
4
|
import type { SourceConfig } from '../domain/sourceConfig.js';
|
|
5
5
|
type RepairLogger = {
|
|
@@ -24,9 +24,20 @@ type RepairLogger = {
|
|
|
24
24
|
*/
|
|
25
25
|
export type DeclaredSourceFailure = {
|
|
26
26
|
source: string;
|
|
27
|
-
reason: 'baselines_unresolvable' | 'write_failed' | 'binding_failed';
|
|
27
|
+
reason: 'baselines_unresolvable' | 'root_outside_project' | 'write_failed' | 'binding_failed';
|
|
28
28
|
error: string;
|
|
29
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* Does a declared in-process folder's root leave its project zone on disk? The
|
|
32
|
+
* kernel validator already keeps a declared root project-relative (no `..`, no
|
|
33
|
+
* absolute path), so the LEXICAL path stays inside; what it never sees is a
|
|
34
|
+
* symlink standing at that path. This is the route's realpath arm for the third
|
|
35
|
+
* producer: the folder's REAL path must stay inside the project zone's real
|
|
36
|
+
* path, on either plane (natively the fence's own rule; in a container the zone
|
|
37
|
+
* is still the only place a declaration may name). A root that does not exist
|
|
38
|
+
* yet cannot point anywhere and passes; no known projects root ⇒ no judgement.
|
|
39
|
+
*/
|
|
40
|
+
export declare function declaredRootLeavesProject(config: Pick<SourceConfig, 'connection'>, runtimeStack: RuntimeStackInfo | null, projectId: string): Promise<boolean>;
|
|
30
41
|
export declare function createMissingDeclaredSources(deps: {
|
|
31
42
|
sourceConfigs: SourceConfigPort;
|
|
32
43
|
bindSource: (scope: SourceConfigScope, config: SourceConfig) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createDeclaredSources.d.ts","sourceRoot":"","sources":["../../../src/usecases/createDeclaredSources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gCAAgC,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"createDeclaredSources.d.ts","sourceRoot":"","sources":["../../../src/usecases/createDeclaredSources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gCAAgC,EAAE,uBAAuB,EAAE,wBAAwB,EAAE,MAAM,oCAAoC,CAAC;AAI9I,OAAO,EAAgB,KAAK,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAErF,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClF,OAAO,KAAK,EAA2B,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAGvF,KAAK,YAAY,GAAG;IAAE,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;CAAE,CAAC;AAEnJ;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,wBAAwB,GAAG,sBAAsB,GAAG,cAAc,GAAG,gBAAgB,CAAC;IAC9F,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,EACxC,YAAY,EAAE,gBAAgB,GAAG,IAAI,EACrC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,OAAO,CAAC,CAelB;AAED,wBAAsB,4BAA4B,CAChD,IAAI,EAAE;IACJ,aAAa,EAAE,gBAAgB,CAAC;IAChC,UAAU,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9E,aAAa,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,qBAAqB,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gCAAgC,CAAC,CAAC,CAAC;IAC9F,kBAAkB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,uBAAuB,EAAE,CAAC;IAChE,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACtC,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB,EACD,MAAM,EAAE;IACN,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,KAAK,EAAE,aAAa,CAAC;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,wBAAwB,CAAA;KAAE,CAAC,CAAC;CACjF,GACA,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,qBAAqB,EAAE,CAAA;CAAE,CAAC,CAoFhF"}
|
|
@@ -1,6 +1,39 @@
|
|
|
1
|
+
import { realpath } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { HOST_SOURCE_KIND, sourcePlane } from '@neuralis/package-system/contracts';
|
|
4
|
+
import { isPathInside } from '@neuralis/package-system/paths';
|
|
1
5
|
import { applyTrustedSourceBaselines, manifestBaselineScheme } from '@neuralis/package-system/policies';
|
|
2
6
|
import { buildDeclaredSourceConfig, isOwnDataZoneDeclaration } from '../services/declaredSources.js';
|
|
3
7
|
import { SOURCE_BASELINE_REPAIR_VERSION } from '../services/baselineRepair.js';
|
|
8
|
+
/**
|
|
9
|
+
* Does a declared in-process folder's root leave its project zone on disk? The
|
|
10
|
+
* kernel validator already keeps a declared root project-relative (no `..`, no
|
|
11
|
+
* absolute path), so the LEXICAL path stays inside; what it never sees is a
|
|
12
|
+
* symlink standing at that path. This is the route's realpath arm for the third
|
|
13
|
+
* producer: the folder's REAL path must stay inside the project zone's real
|
|
14
|
+
* path, on either plane (natively the fence's own rule; in a container the zone
|
|
15
|
+
* is still the only place a declaration may name). A root that does not exist
|
|
16
|
+
* yet cannot point anywhere and passes; no known projects root ⇒ no judgement.
|
|
17
|
+
*/
|
|
18
|
+
export async function declaredRootLeavesProject(config, runtimeStack, projectId) {
|
|
19
|
+
const { kind, config: connection } = config.connection;
|
|
20
|
+
if (kind !== HOST_SOURCE_KIND || sourcePlane(kind, connection) !== 'local')
|
|
21
|
+
return false;
|
|
22
|
+
const root = typeof connection.root === 'string' ? connection.root : '';
|
|
23
|
+
if (!root || !runtimeStack?.projectsRoot)
|
|
24
|
+
return false;
|
|
25
|
+
const projectRoot = path.join(runtimeStack.projectsRoot, projectId);
|
|
26
|
+
const lexical = path.resolve(projectRoot, root);
|
|
27
|
+
let real;
|
|
28
|
+
try {
|
|
29
|
+
real = await realpath(lexical);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return !isPathInside(projectRoot, lexical);
|
|
33
|
+
}
|
|
34
|
+
const realProject = await realpath(projectRoot).catch(() => projectRoot);
|
|
35
|
+
return !isPathInside(realProject, real);
|
|
36
|
+
}
|
|
4
37
|
export async function createMissingDeclaredSources(deps, target) {
|
|
5
38
|
const { projectId, userId, existing } = target;
|
|
6
39
|
let created = 0;
|
|
@@ -32,6 +65,12 @@ export async function createMissingDeclaredSources(deps, target) {
|
|
|
32
65
|
skipped += 1;
|
|
33
66
|
continue;
|
|
34
67
|
}
|
|
68
|
+
if (await declaredRootLeavesProject(built, deps.runtimeStack, projectId)) {
|
|
69
|
+
const error = 'the declared folder resolves outside this project on disk';
|
|
70
|
+
failed.push({ source: decl.source, reason: 'root_outside_project', error });
|
|
71
|
+
deps.logger?.warn?.('declared-source create refused: root outside the project zone', { source: decl.source, projectId });
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
35
74
|
let complete;
|
|
36
75
|
try {
|
|
37
76
|
const applied = applyTrustedSourceBaselines({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createDeclaredSources.js","sourceRoot":"","sources":["../../../src/usecases/createDeclaredSources.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"createDeclaredSources.js","sourceRoot":"","sources":["../../../src/usecases/createDeclaredSources.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AACnF,OAAO,EAAE,YAAY,EAAyB,MAAM,gCAAgC,CAAC;AACrF,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAC;AAGxG,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC;AACrG,OAAO,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAyB/E;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAAwC,EACxC,YAAqC,EACrC,SAAiB;IAEjB,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC;IACvD,IAAI,IAAI,KAAK,gBAAgB,IAAI,WAAW,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IACzF,MAAM,IAAI,GAAG,OAAO,UAAU,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACxE,IAAI,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,YAAY;QAAE,OAAO,KAAK,CAAC;IACvD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IACpE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IAChD,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IACD,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC;IACzE,OAAO,CAAC,YAAY,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAChD,IAWC,EACD,MAKC;IAED,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IAC/C,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,KAAK,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACnD,IAAI,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;gBAChF,IAAI,CAAC,MAAM;oBAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;gBAC7D,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;YACvD,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAClC,CAAC;YACD,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,yBAAyB,CAAC,IAAI,EAAE;YAC5C,SAAS;YACT,SAAS,EAAE,MAAM;YACjB,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE;YACf,YAAY,EAAE,IAAI,CAAC,YAAY;YAC/B,GAAG,CAAC,wBAAwB,CAAC,aAAa,EAAE,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC;gBACnE,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,kBAAkB,EAAE;gBAC3C,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC,CAAC;YACb,SAAS;QACX,CAAC;QACD,IAAI,MAAM,yBAAyB,CAAC,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,EAAE,CAAC;YACzE,MAAM,KAAK,GAAG,2DAA2D,CAAC;YAC1E,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,sBAAsB,EAAE,KAAK,EAAE,CAAC,CAAC;YAC5E,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,+DAA+D,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;YACzH,SAAS;QACX,CAAC;QACD,IAAI,QAAsB,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,2BAA2B,CAAC;gBAC1C,WAAW,EAAE,KAAK,CAAC,WAA0D;gBAC7E,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,kBAAkB,EAAE,IAAI,CAAC,qBAAqB,EAAE;gBAChD,eAAe,EAAE,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;gBAC/D,cAAc,EAAE,IAAI;aACrB,CAAC,CAAC;YACH,IAAI,CAAC,OAAO,IAAI,sBAAsB,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;gBACrD,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;YAC1D,CAAC;YACD,QAAQ,GAAG,OAAO;gBAChB,CAAC,CAAC;oBACE,GAAG,KAAK;oBACR,WAAW,EAAE,OAAO,CAAC,WAAiD;oBACtE,qBAAqB,EAAE,8BAA8B;iBACtD;gBACH,CAAC,CAAC,KAAK,CAAC;QACZ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC/D,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,wBAAwB,EAAE,KAAK,EAAE,CAAC,CAAC;YAC9E,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,oEAAoE,EAAE;gBACxF,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,SAAS;gBACT,KAAK;aACN,CAAC,CAAC;YACH,SAAS;QACX,CAAC;QACD,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,QAAQ,CAAC,CAAC;YACjE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC1B,OAAO,IAAI,CAAC,CAAC;QACf,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC/D,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC;YACpE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,+BAA+B,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;YAChG,SAAS;QACX,CAAC;QACD,IAAI,CAAC;YAAC,MAAM,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,QAAQ,CAAC,CAAC;QAAC,CAAC;QAC/D,OAAO,GAAG,EAAE,CAAC;YAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAAC,CAAC;IAClD,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAEpC,SAAS,aAAa,CAAC,MAAc,EAAE,GAAY;QACjD,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC/D,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,gCAAgC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IACtF,CAAC;AACH,CAAC"}
|
|
@@ -7,14 +7,13 @@
|
|
|
7
7
|
* the purge before its own destructive steps (the project stays archived and the
|
|
8
8
|
* purge can be retried — the filter matches nothing the second time).
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* not report as done.
|
|
10
|
+
* An unavailable vector store is such a failure: the shared index refuses with
|
|
11
|
+
* `VectorStoreUnavailableError` (no network call), so the purge stops here and
|
|
12
|
+
* is retried once the store is back.
|
|
14
13
|
*/
|
|
15
14
|
import type { DeprovisionProjectContext } from '@neuralis/package-system/contracts';
|
|
16
15
|
import type { BrainCoreState } from '../lifecycle.js';
|
|
17
|
-
export type DeprovisionProjectDeps = Pick<BrainCoreState, 'infraFactory' | '
|
|
16
|
+
export type DeprovisionProjectDeps = Pick<BrainCoreState, 'infraFactory' | 'syncQueue'> & {
|
|
18
17
|
syncLogger: Pick<BrainCoreState['syncLogger'], 'info'>;
|
|
19
18
|
};
|
|
20
19
|
export declare function deprovisionProject(deps: DeprovisionProjectDeps, ctx: DeprovisionProjectContext): Promise<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deprovisionProject.d.ts","sourceRoot":"","sources":["../../../src/usecases/deprovisionProject.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"deprovisionProject.d.ts","sourceRoot":"","sources":["../../../src/usecases/deprovisionProject.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,cAAc,EAAE,cAAc,GAAG,WAAW,CAAC,GAAG;IACxF,UAAU,EAAE,IAAI,CAAC,cAAc,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,CAAC;CACxD,CAAC;AAEF,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,sBAAsB,EAC5B,GAAG,EAAE,yBAAyB,GAC7B,OAAO,CAAC;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,CAYpC"}
|
|
@@ -7,16 +7,11 @@
|
|
|
7
7
|
* the purge before its own destructive steps (the project stays archived and the
|
|
8
8
|
* purge can be retried — the filter matches nothing the second time).
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* not report as done.
|
|
10
|
+
* An unavailable vector store is such a failure: the shared index refuses with
|
|
11
|
+
* `VectorStoreUnavailableError` (no network call), so the purge stops here and
|
|
12
|
+
* is retried once the store is back.
|
|
14
13
|
*/
|
|
15
|
-
import { inferInfraModeFromEnv } from '../wiring.js';
|
|
16
14
|
export async function deprovisionProject(deps, ctx) {
|
|
17
|
-
if (deps.vectorBackend === 'inmemory' && inferInfraModeFromEnv(process.env) !== 'inmemory') {
|
|
18
|
-
throw new Error('vector index degraded (Qdrant configured, in-memory fallback wired) — restart to purge vectors');
|
|
19
|
-
}
|
|
20
15
|
return deps.syncQueue.withProjectDrained(ctx.projectId, async () => {
|
|
21
16
|
const infra = await deps.infraFactory.getInfra(ctx.projectId);
|
|
22
17
|
const pointsRemoved = await infra.vector.deleteByFilter({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deprovisionProject.js","sourceRoot":"","sources":["../../../src/usecases/deprovisionProject.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"deprovisionProject.js","sourceRoot":"","sources":["../../../src/usecases/deprovisionProject.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AASH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAA4B,EAC5B,GAA8B;IAE9B,OAAO,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC9D,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC;YACtD,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;SACtD,CAAC,CAAC;QACH,2EAA2E;QAC3E,6EAA6E;QAC7E,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,+CAA+C,EAAE,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC;QACnH,OAAO,EAAE,aAAa,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/usecases/list.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAMtE,OAAO,KAAK,EACV,cAAc,EAEd,iBAAiB,EACjB,kBAAkB,EAEnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAA4B,KAAK,aAAa,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/usecases/list.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAMtE,OAAO,KAAK,EACV,cAAc,EAEd,iBAAiB,EACjB,kBAAkB,EAEnB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAA4B,KAAK,aAAa,EAAE,MAAM,oCAAoC,CAAC;AA0ClG,iFAAiF;AACjF,wBAAgB,eAAe,IAAI,MAAM,CAExC;AACD,kFAAkF;AAClF,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AACD,qFAAqF;AACrF,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AACD,0EAA0E;AAC1E,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAaD,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EAAE,CAAC,EAC3C,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAC7C,OAAO,CAAC,CAAC,EAAE,CAAC,CAed;AAkFD,MAAM,MAAM,QAAQ,GAAG;IACrB,MAAM,EAAE,eAAe,CAAC,cAAc,CAAC,CAAC;IACxC,gEAAgE;IAChE,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACxC;;;;;;;;OAQG;IACH,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,YAAY,EAAE,MAAM,EAAE,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3E;;;OAGG;IACH,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;KAAE,CAAC;CAC1E,CAAC;AAKF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,QAAQ,EACd,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,kBAAkB,CAAC,CA0kB7B;AAsZD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAetD"}
|
|
@@ -5,6 +5,7 @@ import { extractIndexText } from '../domain/text.js';
|
|
|
5
5
|
import { containsAbsolutePath } from '../domain/paths.js';
|
|
6
6
|
import { ConnectorRootAccessError } from '@neuralis/package-system/contracts';
|
|
7
7
|
import { getBrainConfigNumber } from '../config/env.js';
|
|
8
|
+
import { HostConnector } from '../connectors/HostConnector.js';
|
|
8
9
|
/** Internal summary budget for inline content attachments (see `summary_chars`). */
|
|
9
10
|
const SUMMARY_BUDGET_CHARS = 40_000;
|
|
10
11
|
/** Unindexed-file preview: max file size to read from connector. */
|
|
@@ -34,6 +35,8 @@ const MAX_FOLDER_ENRICH_PAGES_DEFAULT = 6;
|
|
|
34
35
|
* filesystem/network walks as the project has sources.
|
|
35
36
|
*/
|
|
36
37
|
const CONNECTOR_CONCURRENCY_DEFAULT = 4;
|
|
38
|
+
/** The host's `routeSlowMs` default: the registry's per-source line follows the route's slow line. */
|
|
39
|
+
const ROUTE_SLOW_MS_DEFAULT = 1_000;
|
|
37
40
|
/**
|
|
38
41
|
* Default cap on CONCURRENT git probes. Lower than the connector cap on purpose —
|
|
39
42
|
* each one is a child PROCESS, not an I/O handle.
|
|
@@ -391,7 +394,12 @@ export async function listUseCase(deps, ctx, req) {
|
|
|
391
394
|
// fall back (D-5) to the source's indexed slice as `stale_indexed`
|
|
392
395
|
// ("indexed but the live connector is unavailable") so a Docker host-pair
|
|
393
396
|
// miss still shows what is indexed instead of an empty drive.
|
|
394
|
-
|
|
397
|
+
// A device folder whose plane is down names it by the listing's own
|
|
398
|
+
// `live_reason` (the same probe), so `last_error` and `live_reason`
|
|
399
|
+
// agree; a refusal keeps its own sentence. A probe that throws leaves
|
|
400
|
+
// the walk's own description — the warn below logs the error either way.
|
|
401
|
+
const unavailable = connector instanceof HostConnector ? await connector.unavailable(err).catch(() => undefined) : undefined;
|
|
402
|
+
out.error = unavailable && 'live' in unavailable ? unavailable.reason : describeWalkError(err);
|
|
395
403
|
const raw = err;
|
|
396
404
|
deps.logger?.warn('list: source walk failed', {
|
|
397
405
|
source,
|
|
@@ -971,10 +979,16 @@ function computePerSourceLimit(connectors, budget, scopeSource) {
|
|
|
971
979
|
* With `includeCounts:false` the expensive count walk (`countByFilter` +
|
|
972
980
|
* `connector.count`) is skipped entirely; `on_disk` is still filled when the
|
|
973
981
|
* peekCount cache happens to be warm.
|
|
982
|
+
*
|
|
983
|
+
* The sources are probed CONCURRENTLY (at most `connectorConcurrency()` at once,
|
|
984
|
+
* the listing's own walk cap) and reported in their input order, each with its
|
|
985
|
+
* own error: the wall time is the slowest walks', never their sum. A registry
|
|
986
|
+
* that took at least the route slow threshold (`routeSlowMs`) logs one line with
|
|
987
|
+
* each source's milliseconds, beside the route's own slow line.
|
|
974
988
|
*/
|
|
975
989
|
async function computeSourcesRegistry(params) {
|
|
976
990
|
const { deps, ctx, scopeSource, scopeUri, onlyIndexed, includeCounts, qdrantError, connectorErrors } = params;
|
|
977
|
-
const
|
|
991
|
+
const startedAt = Date.now();
|
|
978
992
|
const sourcesToReport = new Set();
|
|
979
993
|
if (scopeSource) {
|
|
980
994
|
sourcesToReport.add(scopeSource);
|
|
@@ -986,22 +1000,50 @@ async function computeSourcesRegistry(params) {
|
|
|
986
1000
|
sourcesToReport.add(source);
|
|
987
1001
|
}
|
|
988
1002
|
}
|
|
989
|
-
|
|
1003
|
+
const deferred = [];
|
|
1004
|
+
const probed = await mapWithConcurrency([...sourcesToReport], connectorConcurrency(), async (source) => {
|
|
1005
|
+
const sourceStartedAt = Date.now();
|
|
1006
|
+
const entry = await probeSourceEntry(source);
|
|
1007
|
+
return { source, entry, ms: Date.now() - sourceStartedAt };
|
|
1008
|
+
});
|
|
1009
|
+
if (deferred.length > 0) {
|
|
1010
|
+
// The SAME cap as the probes: at most `connectorConcurrency()` walks in
|
|
1011
|
+
// flight. A cached, stale or remembered answer frees its slot in the same
|
|
1012
|
+
// turn, so only real walks queue; whatever has not settled after one turn
|
|
1013
|
+
// stays uncounted and a later call shows it (one walk per key — the
|
|
1014
|
+
// connector's single-flight). Never awaited: one slow device must not hold
|
|
1015
|
+
// the whole list.
|
|
1016
|
+
void mapWithConcurrency(deferred, connectorConcurrency(), async (job) => {
|
|
1017
|
+
job.outcome = await job.run().then((value) => ({ ok: true, value }), (error) => ({ ok: false, error }));
|
|
1018
|
+
});
|
|
1019
|
+
await new Promise((resolve) => { setImmediate(resolve); });
|
|
1020
|
+
for (const job of deferred)
|
|
1021
|
+
if (job.outcome)
|
|
1022
|
+
applyCount(job.entry, job.source, job.scan, job.outcome);
|
|
1023
|
+
}
|
|
1024
|
+
const ms = Date.now() - startedAt;
|
|
1025
|
+
const slowMs = getBrainConfigNumber('routeSlowMs', undefined, ROUTE_SLOW_MS_DEFAULT);
|
|
1026
|
+
if (includeCounts && ms >= slowMs) {
|
|
1027
|
+
deps.logger?.warn('list: source registry slow', {
|
|
1028
|
+
ms,
|
|
1029
|
+
concurrency: connectorConcurrency(),
|
|
1030
|
+
sources: Object.fromEntries(probed.map((p) => [p.source, p.ms])),
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
return probed.map((p) => p.entry);
|
|
1034
|
+
async function probeSourceEntry(source) {
|
|
990
1035
|
const uriRoot = `${source}://`;
|
|
991
1036
|
const connector = deps.connectors?.get(source);
|
|
992
|
-
const source_kind = source === 'brain'
|
|
993
|
-
? 'brain'
|
|
994
|
-
: connector?.kind === 'local' ? 'local-disk' : (connector?.kind ?? 'unknown');
|
|
1037
|
+
const source_kind = source === 'brain' ? 'brain' : (connector?.kind ?? 'unknown');
|
|
995
1038
|
const entry = { uri_root: uriRoot, source_kind };
|
|
996
1039
|
// Per-source connector-walk failure (Phase 2 isolation): surface the error
|
|
997
1040
|
// on this source row and skip the count probes — they would only re-hit the
|
|
998
|
-
// same broken connector. Other sources are unaffected.
|
|
1041
|
+
// same broken connector. Other sources are unaffected. `last_error` only:
|
|
1042
|
+
// `sync_status` is the SYNC's state, which a failed walk says nothing about.
|
|
999
1043
|
const connectorError = connectorErrors.get(source);
|
|
1000
1044
|
if (connectorError) {
|
|
1001
1045
|
entry.last_error = connectorError;
|
|
1002
|
-
entry
|
|
1003
|
-
entries.push(entry);
|
|
1004
|
-
continue;
|
|
1046
|
+
return entry;
|
|
1005
1047
|
}
|
|
1006
1048
|
// Exact indexed count via Qdrant count endpoint. Count-gated — this REST
|
|
1007
1049
|
// round-trip per source is part of the cost we make opt-in.
|
|
@@ -1037,35 +1079,50 @@ async function computeSourcesRegistry(params) {
|
|
|
1037
1079
|
? { excludeGlobs: scan.excludeGlobs, maxScanFiles: scan.maxScanFiles }
|
|
1038
1080
|
: undefined;
|
|
1039
1081
|
const cached = connector.peekCount?.(countKey, countOpts);
|
|
1082
|
+
const count = connector.count?.bind(connector);
|
|
1040
1083
|
if (typeof cached === 'number') {
|
|
1041
|
-
entry
|
|
1084
|
+
applyCount(entry, source, scan, { ok: true, value: cached });
|
|
1042
1085
|
}
|
|
1043
|
-
else if (includeCounts &&
|
|
1044
|
-
|
|
1045
|
-
|
|
1086
|
+
else if (includeCounts && count) {
|
|
1087
|
+
// A ONE-source listing (and a connector with no count cache) waits for
|
|
1088
|
+
// its walk; the every-source registry defers it (see `deferred`).
|
|
1089
|
+
if (scopeSource || !connector.peekCount) {
|
|
1090
|
+
applyCount(entry, source, scan, await count(countKey, countOpts).then((value) => ({ ok: true, value }), (error) => ({ ok: false, error })));
|
|
1046
1091
|
}
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
entry.last_error = entry.last_error ?? message;
|
|
1050
|
-
entry.sync_status = 'error';
|
|
1092
|
+
else {
|
|
1093
|
+
deferred.push({ source, entry, scan, run: () => count(countKey, countOpts) });
|
|
1051
1094
|
}
|
|
1052
1095
|
}
|
|
1096
|
+
}
|
|
1097
|
+
else {
|
|
1098
|
+
applyCount(entry, source, undefined, undefined);
|
|
1099
|
+
}
|
|
1100
|
+
// Surface qdrant-wide errors on the brain entry so the status has a home.
|
|
1101
|
+
if (source === 'brain' && qdrantError && !entry.last_error) {
|
|
1102
|
+
entry.last_error = qdrantError;
|
|
1103
|
+
}
|
|
1104
|
+
return entry;
|
|
1105
|
+
}
|
|
1106
|
+
/** A count's answer onto its row: the total (`N+` at the cap) and `unindexed`, or the failure as a code. */
|
|
1107
|
+
function applyCount(entry, source, scan, outcome) {
|
|
1108
|
+
if (outcome?.ok) {
|
|
1109
|
+
entry.on_disk = outcome.value;
|
|
1053
1110
|
// The count stopped at the cap ⇒ `on_disk` is a floor; flag it so the UI
|
|
1054
1111
|
// renders `N+` instead of presenting the cap value as the true total.
|
|
1055
|
-
if (scan &&
|
|
1112
|
+
if (scan && outcome.value >= scan.maxScanFiles)
|
|
1056
1113
|
entry.truncated = true;
|
|
1057
|
-
|
|
1114
|
+
}
|
|
1115
|
+
else if (outcome) {
|
|
1116
|
+
const err = outcome.error;
|
|
1117
|
+
// Member-facing, like the walk's: a code, never a path (security invariant 9).
|
|
1118
|
+
// `last_error` only — a failed COUNT is not a sync error.
|
|
1119
|
+
entry.last_error = entry.last_error ?? describeWalkError(err);
|
|
1120
|
+
deps.logger?.warn('list: source count failed', { source, error: err instanceof Error ? err.message : String(err) });
|
|
1058
1121
|
}
|
|
1059
1122
|
if (typeof entry.on_disk === 'number' && typeof entry.indexed_count === 'number') {
|
|
1060
1123
|
entry.unindexed = Math.max(0, entry.on_disk - entry.indexed_count);
|
|
1061
1124
|
}
|
|
1062
|
-
// Surface qdrant-wide errors on the brain entry so the status has a home.
|
|
1063
|
-
if (source === 'brain' && qdrantError && !entry.last_error) {
|
|
1064
|
-
entry.last_error = qdrantError;
|
|
1065
|
-
}
|
|
1066
|
-
entries.push(entry);
|
|
1067
1125
|
}
|
|
1068
|
-
return entries;
|
|
1069
1126
|
}
|
|
1070
1127
|
/**
|
|
1071
1128
|
* The per-source walk failure as it reaches `last_error` — a member-facing field
|