@neuralis/brain-core 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -35
- package/app/README.md +1 -1
- package/app/cards/DiffView.tsx +9 -7
- package/app/cards/README.md +1 -1
- package/app/cards/diffLine.tsx +2 -4
- package/app/filesystem/README.md +4 -4
- package/app/filesystem/api/README.md +3 -3
- package/app/filesystem/api/index.ts +137 -123
- package/app/filesystem/domain/types.ts +36 -5
- package/app/filesystem/hooks/README.md +5 -5
- package/app/filesystem/hooks/useDiscoverableSources.ts +4 -2
- package/app/filesystem/hooks/useFilesystemSSE.ts +31 -23
- package/app/filesystem/hooks/useGitChangesInventory.ts +4 -2
- package/app/filesystem/host/README.md +3 -2
- package/app/filesystem/host/installFilesystemHostComponents.tsx +22 -9
- package/app/filesystem/store/README.md +11 -7
- package/app/filesystem/store/filesystemStore.ts +454 -162
- package/app/filesystem/store/gitSlice.ts +6 -6
- package/app/filesystem/store/listSlice.ts +10 -6
- package/app/filesystem/store/searchSlice.ts +27 -4
- package/app/filesystem/ui/FileEditor.tsx +48 -35
- package/app/filesystem/ui/FileTree.tsx +10 -9
- package/app/filesystem/ui/FileTreeSearch.tsx +29 -2
- package/app/filesystem/ui/GitCommitChangesView.tsx +5 -3
- package/app/filesystem/ui/GitCommitGraph.tsx +6 -5
- package/app/filesystem/ui/GitControlPanel.tsx +14 -13
- package/app/filesystem/ui/GitDiffView.tsx +2 -1
- package/app/filesystem/ui/GitFileDiff.tsx +7 -6
- package/app/filesystem/ui/PendingChangesPanel.tsx +88 -28
- package/app/filesystem/ui/PendingReviewDialog.tsx +52 -24
- package/app/filesystem/ui/README.md +8 -7
- package/app/filesystem/ui/ReembedDialog.tsx +22 -9
- package/app/filesystem/ui/SourceDeleteConfirm.tsx +1 -1
- package/app/filesystem/ui/SourcesPanel.tsx +135 -42
- package/app/filesystem/ui/VectorHealthPanel.tsx +20 -4
- package/app/filesystem/ui/pendingChangesModel.ts +9 -5
- package/dist/app/chunks/{astro-LRAFGXNX.js → astro-B2J4AS2D.js} +1 -1
- package/dist/app/chunks/bash-KY6SAQTH.js +1 -0
- package/dist/app/chunks/c-OBOPYVZ7.js +1 -0
- package/dist/app/chunks/{chunk-5H7ZCOD3.js → chunk-2X3GNKJ3.js} +1 -1
- package/dist/app/chunks/{chunk-XIFGTNRM.js → chunk-JPJIVRFI.js} +1 -1
- package/dist/app/chunks/{chunk-RH3QY5LF.js → chunk-LEFIFWND.js} +1 -1
- package/dist/app/chunks/{chunk-G4RZ3UNX.js → chunk-N6RXX3PH.js} +1 -1
- package/dist/app/chunks/{chunk-QXXJ73P5.js → chunk-PZAW4HPB.js} +1 -1
- package/dist/app/chunks/{chunk-3QLE7Y4L.js → chunk-ZBYWWTO6.js} +1 -1
- package/dist/app/chunks/cpp-TVWVOTEQ.js +1 -0
- package/dist/app/chunks/css-MANZBYA4.js +1 -0
- package/dist/app/chunks/{elixir-M36XROA6.js → elixir-S725Z7EH.js} +1 -1
- package/dist/app/chunks/{elm-7BG6QAIK.js → elm-5WUUSTNB.js} +1 -1
- package/dist/app/chunks/graphql-UGOPR3WU.js +1 -0
- package/dist/app/chunks/html-F6FWTBSG.js +1 -0
- package/dist/app/chunks/java-ANIVV5H5.js +1 -0
- package/dist/app/chunks/javascript-IH374YWG.js +1 -0
- package/dist/app/chunks/json-WGGVVXSB.js +1 -0
- package/dist/app/chunks/jsx-OTXJQD32.js +1 -0
- package/dist/app/chunks/{latex-ZWK7SXB6.js → latex-QCZNITGN.js} +1 -1
- package/dist/app/chunks/lua-4CRZ64PU.js +1 -0
- package/dist/app/chunks/{nginx-2L6VRV3A.js → nginx-V4CYS7WR.js} +1 -1
- package/dist/app/chunks/{perl-PBUAXXK6.js → perl-BHTX7F5B.js} +1 -1
- package/dist/app/chunks/{php-QJX57PA6.js → php-AYGJ5WYZ.js} +1 -1
- package/dist/app/chunks/r-4YFCFA4B.js +1 -0
- package/dist/app/chunks/{ruby-RLOWMVPO.js → ruby-42NMJWAL.js} +1 -1
- package/dist/app/chunks/{scss-B5CAI3HR.js → scss-XD7VU2CU.js} +1 -1
- package/dist/app/chunks/sql-B55MH6JJ.js +1 -0
- package/dist/app/chunks/{svelte-GT3D4C44.js → svelte-WR3QPIJU.js} +1 -1
- package/dist/app/chunks/tsx-S73GAE2L.js +1 -0
- package/dist/app/chunks/typescript-NEWOAB5Z.js +1 -0
- package/dist/app/chunks/{vue-JOW62MHD.js → vue-CCDS4VZK.js} +1 -1
- package/dist/app/chunks/xml-UXKAGLDR.js +1 -0
- package/dist/app/chunks/yaml-UMWKDTK7.js +1 -0
- package/dist/app/host.js +46 -46
- package/dist/scripts/embeddingLockV3.d.ts +30 -0
- package/dist/scripts/embeddingLockV3.d.ts.map +1 -0
- package/dist/scripts/embeddingLockV3.js +100 -0
- package/dist/scripts/embeddingLockV3.js.map +1 -0
- package/dist/scripts/vectorProofV1.d.ts +90 -0
- package/dist/scripts/vectorProofV1.d.ts.map +1 -0
- package/dist/scripts/vectorProofV1.js +220 -0
- package/dist/scripts/vectorProofV1.js.map +1 -0
- package/dist/src/config/env.d.ts +21 -0
- package/dist/src/config/env.d.ts.map +1 -1
- package/dist/src/config/env.js +55 -0
- package/dist/src/config/env.js.map +1 -1
- package/dist/src/connectors/AppSourceConfigStore.d.ts +12 -2
- package/dist/src/connectors/AppSourceConfigStore.d.ts.map +1 -1
- package/dist/src/connectors/AppSourceConfigStore.js +48 -40
- package/dist/src/connectors/AppSourceConfigStore.js.map +1 -1
- package/dist/src/connectors/LocalDiskConnector.d.ts +11 -14
- package/dist/src/connectors/LocalDiskConnector.d.ts.map +1 -1
- package/dist/src/connectors/LocalDiskConnector.js +87 -107
- package/dist/src/connectors/LocalDiskConnector.js.map +1 -1
- package/dist/src/connectors/sourceConfigMutation.d.ts +11 -1
- package/dist/src/connectors/sourceConfigMutation.d.ts.map +1 -1
- package/dist/src/connectors/sourceConfigMutation.js +36 -3
- package/dist/src/connectors/sourceConfigMutation.js.map +1 -1
- package/dist/src/domain/chunker.js +8 -3
- package/dist/src/domain/chunker.js.map +1 -1
- package/dist/src/domain/healthTypes.d.ts +11 -0
- package/dist/src/domain/healthTypes.d.ts.map +1 -1
- package/dist/src/domain/mime.d.ts +1 -0
- package/dist/src/domain/mime.d.ts.map +1 -1
- package/dist/src/domain/mime.js +48 -0
- package/dist/src/domain/mime.js.map +1 -1
- package/dist/src/domain/pendingChange.d.ts +7 -0
- package/dist/src/domain/pendingChange.d.ts.map +1 -1
- package/dist/src/domain/pendingChange.js +11 -0
- package/dist/src/domain/pendingChange.js.map +1 -1
- package/dist/src/domain/sourceConfig.d.ts +7 -14
- package/dist/src/domain/sourceConfig.d.ts.map +1 -1
- package/dist/src/domain/sourceConfig.js +1 -13
- package/dist/src/domain/sourceConfig.js.map +1 -1
- package/dist/src/domain/sourcePackages.d.ts +11 -2
- package/dist/src/domain/sourcePackages.d.ts.map +1 -1
- package/dist/src/domain/syncTrigger.d.ts +2 -3
- package/dist/src/domain/syncTrigger.d.ts.map +1 -1
- package/dist/src/domain/syncTrigger.js +2 -3
- package/dist/src/domain/syncTrigger.js.map +1 -1
- package/dist/src/domain/syncTypes.d.ts +21 -4
- package/dist/src/domain/syncTypes.d.ts.map +1 -1
- package/dist/src/domain/syncTypes.js.map +1 -1
- package/dist/src/domain/text.d.ts +3 -0
- package/dist/src/domain/text.d.ts.map +1 -1
- package/dist/src/domain/text.js +5 -0
- package/dist/src/domain/text.js.map +1 -1
- package/dist/src/domain/types.d.ts +9 -0
- package/dist/src/domain/types.d.ts.map +1 -1
- package/dist/src/embeddings/clients/GeminiEmbedder.d.ts.map +1 -1
- package/dist/src/embeddings/clients/GeminiEmbedder.js +11 -5
- package/dist/src/embeddings/clients/GeminiEmbedder.js.map +1 -1
- package/dist/src/embeddings/clients/OllamaEmbedder.d.ts.map +1 -1
- package/dist/src/embeddings/clients/OllamaEmbedder.js +13 -6
- package/dist/src/embeddings/clients/OllamaEmbedder.js.map +1 -1
- package/dist/src/embeddings/clients/OpenAIEmbedder.d.ts.map +1 -1
- package/dist/src/embeddings/clients/OpenAIEmbedder.js +12 -9
- package/dist/src/embeddings/clients/OpenAIEmbedder.js.map +1 -1
- package/dist/src/embeddings/clients/QwenEmbedder.d.ts.map +1 -1
- package/dist/src/embeddings/clients/QwenEmbedder.js +12 -5
- package/dist/src/embeddings/clients/QwenEmbedder.js.map +1 -1
- package/dist/src/embeddings/clients/VoyageEmbedder.d.ts.map +1 -1
- package/dist/src/embeddings/clients/VoyageEmbedder.js +12 -5
- package/dist/src/embeddings/clients/VoyageEmbedder.js.map +1 -1
- package/dist/src/embeddings/factory.d.ts +2 -0
- package/dist/src/embeddings/factory.d.ts.map +1 -1
- package/dist/src/embeddings/factory.js +23 -3
- package/dist/src/embeddings/factory.js.map +1 -1
- package/dist/src/embeddings/lock.d.ts +22 -11
- package/dist/src/embeddings/lock.d.ts.map +1 -1
- package/dist/src/embeddings/lock.js +47 -29
- package/dist/src/embeddings/lock.js.map +1 -1
- package/dist/src/embeddings/retry.d.ts +5 -0
- package/dist/src/embeddings/retry.d.ts.map +1 -1
- package/dist/src/embeddings/retry.js +35 -0
- package/dist/src/embeddings/retry.js.map +1 -1
- package/dist/src/events/pending.d.ts +56 -0
- package/dist/src/events/pending.d.ts.map +1 -0
- package/dist/src/events/pending.js +108 -0
- package/dist/src/events/pending.js.map +1 -0
- package/dist/src/events/source.d.ts +60 -14
- package/dist/src/events/source.d.ts.map +1 -1
- package/dist/src/events/source.js +149 -31
- package/dist/src/events/source.js.map +1 -1
- package/dist/src/events/vector.d.ts +33 -0
- package/dist/src/events/vector.d.ts.map +1 -0
- package/dist/src/events/vector.js +57 -0
- package/dist/src/events/vector.js.map +1 -0
- package/dist/src/git/GitRunner.d.ts.map +1 -1
- package/dist/src/git/GitRunner.js +11 -8
- package/dist/src/git/GitRunner.js.map +1 -1
- package/dist/src/git/sourceGitControl.d.ts.map +1 -1
- package/dist/src/git/sourceGitControl.js +2 -1
- package/dist/src/git/sourceGitControl.js.map +1 -1
- package/dist/src/index.d.ts +5 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/lifecycle.d.ts +20 -4
- package/dist/src/lifecycle.d.ts.map +1 -1
- package/dist/src/lifecycle.js +5 -1
- package/dist/src/lifecycle.js.map +1 -1
- package/dist/src/routes/health.js +6 -1
- package/dist/src/routes/health.js.map +1 -1
- package/dist/src/routes/pending.d.ts.map +1 -1
- package/dist/src/routes/pending.js +2 -1
- package/dist/src/routes/pending.js.map +1 -1
- package/dist/src/routes/sources.d.ts.map +1 -1
- package/dist/src/routes/sources.js +60 -11
- package/dist/src/routes/sources.js.map +1 -1
- package/dist/src/services/BridgeService.d.ts +2 -2
- package/dist/src/services/BridgeService.d.ts.map +1 -1
- package/dist/src/services/BridgeService.js +11 -2
- package/dist/src/services/BridgeService.js.map +1 -1
- package/dist/src/services/FilesystemService.d.ts +3 -1
- package/dist/src/services/FilesystemService.d.ts.map +1 -1
- package/dist/src/services/FilesystemService.js +3 -1
- package/dist/src/services/FilesystemService.js.map +1 -1
- package/dist/src/services/FilesystemUiService.js +1 -1
- package/dist/src/services/FilesystemUiService.js.map +1 -1
- package/dist/src/services/SyncScheduler.d.ts.map +1 -1
- package/dist/src/services/SyncScheduler.js +0 -14
- package/dist/src/services/SyncScheduler.js.map +1 -1
- package/dist/src/services/VectorHealthService.d.ts.map +1 -1
- package/dist/src/services/VectorHealthService.js +2 -46
- package/dist/src/services/VectorHealthService.js.map +1 -1
- package/dist/src/services/baselineRepair.d.ts +2 -2
- package/dist/src/services/baselineRepair.js +2 -2
- package/dist/src/services/declaredSources.d.ts +8 -1
- package/dist/src/services/declaredSources.d.ts.map +1 -1
- package/dist/src/services/declaredSources.js +19 -19
- package/dist/src/services/declaredSources.js.map +1 -1
- package/dist/src/store/dataFormats.d.ts +14 -3
- package/dist/src/store/dataFormats.d.ts.map +1 -1
- package/dist/src/store/dataFormats.js +15 -5
- 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 +78 -243
- package/dist/src/sync/DeltaSyncRunner.js.map +1 -1
- package/dist/src/sync/SyncJobQueue.d.ts +33 -4
- package/dist/src/sync/SyncJobQueue.d.ts.map +1 -1
- package/dist/src/sync/SyncJobQueue.js +179 -19
- package/dist/src/sync/SyncJobQueue.js.map +1 -1
- package/dist/src/sync/moveDetector.d.ts +2 -1
- package/dist/src/sync/moveDetector.d.ts.map +1 -1
- package/dist/src/sync/moveDetector.js +2 -1
- package/dist/src/sync/moveDetector.js.map +1 -1
- package/dist/src/tools/fs_search.d.ts.map +1 -1
- package/dist/src/tools/fs_search.js +8 -0
- package/dist/src/tools/fs_search.js.map +1 -1
- package/dist/src/tools/fs_write.js +3 -1
- package/dist/src/tools/fs_write.js.map +1 -1
- package/dist/src/usecases/chunkUpsert.d.ts +4 -0
- package/dist/src/usecases/chunkUpsert.d.ts.map +1 -1
- package/dist/src/usecases/chunkUpsert.js +103 -60
- package/dist/src/usecases/chunkUpsert.js.map +1 -1
- package/dist/src/usecases/embeddingBacklog.d.ts +31 -0
- package/dist/src/usecases/embeddingBacklog.d.ts.map +1 -0
- package/dist/src/usecases/embeddingBacklog.js +244 -0
- package/dist/src/usecases/embeddingBacklog.js.map +1 -0
- package/dist/src/usecases/listSourcePackages.js +17 -1
- package/dist/src/usecases/listSourcePackages.js.map +1 -1
- package/dist/src/usecases/mediaLane.d.ts +11 -4
- package/dist/src/usecases/mediaLane.d.ts.map +1 -1
- package/dist/src/usecases/mediaLane.js +67 -30
- package/dist/src/usecases/mediaLane.js.map +1 -1
- package/dist/src/usecases/pendingReview.d.ts.map +1 -1
- package/dist/src/usecases/pendingReview.js +24 -7
- package/dist/src/usecases/pendingReview.js.map +1 -1
- package/dist/src/usecases/purgeExcludedPoints.d.ts +2 -0
- 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 +33 -6
- package/dist/src/usecases/readFiles.js.map +1 -1
- package/dist/src/usecases/reconcileSourcePackageRoots.d.ts +31 -0
- package/dist/src/usecases/reconcileSourcePackageRoots.d.ts.map +1 -0
- package/dist/src/usecases/reconcileSourcePackageRoots.js +114 -0
- package/dist/src/usecases/reconcileSourcePackageRoots.js.map +1 -0
- package/dist/src/usecases/searchFiles.d.ts.map +1 -1
- package/dist/src/usecases/searchFiles.js +62 -64
- package/dist/src/usecases/searchFiles.js.map +1 -1
- package/dist/src/usecases/syncIndexedFile.d.ts +42 -0
- package/dist/src/usecases/syncIndexedFile.d.ts.map +1 -0
- package/dist/src/usecases/syncIndexedFile.js +242 -0
- package/dist/src/usecases/syncIndexedFile.js.map +1 -0
- package/dist/src/usecases/syncPointWrites.d.ts +5 -0
- package/dist/src/usecases/syncPointWrites.d.ts.map +1 -1
- package/dist/src/usecases/syncPointWrites.js +32 -5
- package/dist/src/usecases/syncPointWrites.js.map +1 -1
- package/dist/src/usecases/uploadBinary.d.ts.map +1 -1
- package/dist/src/usecases/uploadBinary.js +36 -49
- package/dist/src/usecases/uploadBinary.js.map +1 -1
- package/dist/src/usecases/vector/endpointGuard.js +2 -1
- package/dist/src/usecases/vector/endpointGuard.js.map +1 -1
- package/dist/src/usecases/vector/estimate.d.ts +7 -4
- package/dist/src/usecases/vector/estimate.d.ts.map +1 -1
- package/dist/src/usecases/vector/estimate.js +8 -5
- package/dist/src/usecases/vector/estimate.js.map +1 -1
- package/dist/src/usecases/vector/rebuildGeneration.d.ts +29 -5
- package/dist/src/usecases/vector/rebuildGeneration.d.ts.map +1 -1
- package/dist/src/usecases/vector/rebuildGeneration.js +224 -82
- package/dist/src/usecases/vector/rebuildGeneration.js.map +1 -1
- package/dist/src/usecases/vectorMaintenance.d.ts +46 -4
- package/dist/src/usecases/vectorMaintenance.d.ts.map +1 -1
- package/dist/src/usecases/vectorMaintenance.js +190 -11
- package/dist/src/usecases/vectorMaintenance.js.map +1 -1
- package/dist/src/usecases/write/commit.d.ts +6 -8
- package/dist/src/usecases/write/commit.d.ts.map +1 -1
- package/dist/src/usecases/write/commit.js +96 -112
- package/dist/src/usecases/write/commit.js.map +1 -1
- package/dist/src/usecases/write/content.js +1 -2
- package/dist/src/usecases/write/content.js.map +1 -1
- package/dist/src/usecases/write/ports.d.ts +1 -0
- package/dist/src/usecases/write/ports.d.ts.map +1 -1
- package/dist/src/vector/FilesystemVectorIndex.d.ts +34 -3
- package/dist/src/vector/FilesystemVectorIndex.d.ts.map +1 -1
- package/dist/src/vector/FilesystemVectorIndex.js +254 -20
- package/dist/src/vector/FilesystemVectorIndex.js.map +1 -1
- package/dist/src/vector/InMemoryVectorIndex.d.ts +9 -2
- package/dist/src/vector/InMemoryVectorIndex.d.ts.map +1 -1
- package/dist/src/vector/InMemoryVectorIndex.js +25 -6
- package/dist/src/vector/InMemoryVectorIndex.js.map +1 -1
- package/dist/src/vector/QdrantVectorIndex.d.ts +35 -9
- package/dist/src/vector/QdrantVectorIndex.d.ts.map +1 -1
- package/dist/src/vector/QdrantVectorIndex.js +209 -90
- package/dist/src/vector/QdrantVectorIndex.js.map +1 -1
- package/dist/src/vector/qdrantFilter.d.ts +3 -1
- package/dist/src/vector/qdrantFilter.d.ts.map +1 -1
- package/dist/src/vector/qdrantFilter.js +2 -0
- package/dist/src/vector/qdrantFilter.js.map +1 -1
- package/dist/src/vector/types.d.ts +81 -0
- package/dist/src/vector/types.d.ts.map +1 -1
- package/dist/src/vector/types.js +2 -0
- package/dist/src/vector/types.js.map +1 -1
- package/dist/src/wiring.d.ts +6 -0
- package/dist/src/wiring.d.ts.map +1 -1
- package/dist/src/wiring.js +62 -3
- package/dist/src/wiring.js.map +1 -1
- package/dist/tools/fs_search.json +2 -2
- package/docs/drive-overview.md +2 -2
- package/instructions/brain-model.md +1 -1
- package/package.json +1000 -11
- package/rules/brain-rules.md +1 -1
- package/skills/connect-business-data/SKILL.md +6 -4
- package/skills/create-package/SKILL.md +14 -12
- package/skills/create-package/references/config-and-credentials.md +3 -3
- package/skills/create-package/references/connectors-and-uri-policies.md +5 -3
- package/skills/create-package/references/manifest-and-discovery.md +5 -4
- package/skills/create-package/references/runtime-and-build.md +9 -9
- package/skills/create-package/references/skills-and-context.md +3 -3
- package/skills/create-package/references/surfaces-and-design.md +9 -6
- package/skills/create-package/references/team-and-workflows.md +2 -2
- package/skills/create-package/references/test-and-ship.md +15 -15
- package/skills/create-package/references/tools-and-schemas.md +1 -1
- package/skills/create-package/scripts/check-package.sh +50 -4
- package/skills/create-package/scripts/verify-loaded.sh +16 -16
- package/skills/manage-files/SKILL.md +2 -2
- package/skills/manage-sources/SKILL.md +16 -15
- package/skills/manage-sources/scripts/reembed.sh +9 -3
- package/skills/sync/SKILL.md +4 -4
- package/tools/fs_search.json +2 -2
- package/app/filesystem/hooks/useContainerWidth.ts +0 -39
- package/dist/app/chunks/bash-M45GHPBQ.js +0 -1
- package/dist/app/chunks/c-X3REOAWD.js +0 -1
- package/dist/app/chunks/cpp-VOWI743W.js +0 -1
- package/dist/app/chunks/css-2ZVPHE25.js +0 -1
- package/dist/app/chunks/graphql-7V2NP54C.js +0 -1
- package/dist/app/chunks/html-UF3LFLNA.js +0 -1
- package/dist/app/chunks/java-PNTAU4L3.js +0 -1
- package/dist/app/chunks/javascript-4JJTQGEL.js +0 -1
- package/dist/app/chunks/json-VLQ6D3JH.js +0 -1
- package/dist/app/chunks/jsx-KQKSLAAH.js +0 -1
- package/dist/app/chunks/lua-UFPYUJ2O.js +0 -1
- package/dist/app/chunks/r-QEZB45SR.js +0 -1
- package/dist/app/chunks/sql-DTZHNUZP.js +0 -1
- package/dist/app/chunks/tsx-WPR2WRZD.js +0 -1
- package/dist/app/chunks/typescript-LWO362OA.js +0 -1
- package/dist/app/chunks/xml-A5H72RTS.js +0 -1
- package/dist/app/chunks/yaml-MXHSIJCI.js +0 -1
- package/dist/src/services/purgePendingNodes.d.ts +0 -32
- package/dist/src/services/purgePendingNodes.d.ts.map +0 -1
- package/dist/src/services/purgePendingNodes.js +0 -61
- package/dist/src/services/purgePendingNodes.js.map +0 -1
- /package/dist/app/chunks/{chunk-737Y24HS.js → chunk-3JASFUPF.js} +0 -0
- /package/dist/app/chunks/{chunk-DKD2L57N.js → chunk-6EYLOQ4F.js} +0 -0
- /package/dist/app/chunks/{chunk-KYH5EHHY.js → chunk-7YRZ5LOQ.js} +0 -0
- /package/dist/app/chunks/{chunk-6TC3DVWV.js → chunk-C7LU4RID.js} +0 -0
- /package/dist/app/chunks/{chunk-TY33BMKR.js → chunk-CD52YDZP.js} +0 -0
- /package/dist/app/chunks/{chunk-OLEIKJ3X.js → chunk-DCJKTCJ5.js} +0 -0
- /package/dist/app/chunks/{chunk-QLBZ4JR2.js → chunk-EXIU2KBV.js} +0 -0
- /package/dist/app/chunks/{chunk-SFUNBBEA.js → chunk-FDP4LO4P.js} +0 -0
- /package/dist/app/chunks/{chunk-BGRVFATT.js → chunk-HNETUS7U.js} +0 -0
- /package/dist/app/chunks/{chunk-4QNMHAIR.js → chunk-LBFZJEDR.js} +0 -0
- /package/dist/app/chunks/{chunk-TRRUHDPN.js → chunk-ULRXL5VM.js} +0 -0
- /package/dist/app/chunks/{chunk-S6B4WWIF.js → chunk-XJK47SMJ.js} +0 -0
- /package/dist/app/chunks/{chunk-DZ5C5FKI.js → chunk-YYAAIAU2.js} +0 -0
- /package/dist/app/chunks/{clojure-OC6KPSJO.js → clojure-4QCN4GHG.js} +0 -0
- /package/dist/app/chunks/{core-KGE7TQJ3.js → core-ZHTX3P2Q.js} +0 -0
- /package/dist/app/chunks/{csharp-E7VIFITL.js → csharp-HQWR4N52.js} +0 -0
- /package/dist/app/chunks/{dark-plus-BOSCZXE4.js → dark-plus-GYPKKZES.js} +0 -0
- /package/dist/app/chunks/{dart-6Y3X27SZ.js → dart-FO4TTVO2.js} +0 -0
- /package/dist/app/chunks/{diff-TR2NPA64.js → diff-SHANV4YC.js} +0 -0
- /package/dist/app/chunks/{dist-T32U2VVR.js → dist-WSDF34DM.js} +0 -0
- /package/dist/app/chunks/{docker-N33HOW54.js → docker-VX55HTDS.js} +0 -0
- /package/dist/app/chunks/{go-6DGG5UTP.js → go-5UCPEC6S.js} +0 -0
- /package/dist/app/chunks/{haskell-KK36PMMM.js → haskell-25PJ3OSG.js} +0 -0
- /package/dist/app/chunks/{ini-VHVQ5TPB.js → ini-BJIVD5MK.js} +0 -0
- /package/dist/app/chunks/{kotlin-44WS3JHE.js → kotlin-MNR6XOEQ.js} +0 -0
- /package/dist/app/chunks/{less-5WZ3KLAK.js → less-KA5JURX6.js} +0 -0
- /package/dist/app/chunks/{light-plus-HGGBC43G.js → light-plus-QXH2UUWZ.js} +0 -0
- /package/dist/app/chunks/{make-X7RXMVW7.js → make-LPD5KOCO.js} +0 -0
- /package/dist/app/chunks/{markdown-46IKUAIB.js → markdown-LMWF6MQR.js} +0 -0
- /package/dist/app/chunks/{mdx-DGLHDAO7.js → mdx-WPMNN5BS.js} +0 -0
- /package/dist/app/chunks/{nix-Q6FYQZLX.js → nix-QGWLUUMZ.js} +0 -0
- /package/dist/app/chunks/{powershell-L4KJJ6DK.js → powershell-7GSBBEFF.js} +0 -0
- /package/dist/app/chunks/{prisma-IKS4LVH2.js → prisma-FPMPQISO.js} +0 -0
- /package/dist/app/chunks/{proto-AYCDOTJO.js → proto-7KDX5Z2U.js} +0 -0
- /package/dist/app/chunks/{python-KXMCSAFQ.js → python-CFG4FTQW.js} +0 -0
- /package/dist/app/chunks/{rust-J3BC3P6V.js → rust-X7A37WU3.js} +0 -0
- /package/dist/app/chunks/{scala-AYIIHBJK.js → scala-OYHJSUG2.js} +0 -0
- /package/dist/app/chunks/{swift-QPHHCQD3.js → swift-PE7VNYW5.js} +0 -0
- /package/dist/app/chunks/{toml-UV7JK7K7.js → toml-ETQRDILP.js} +0 -0
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# @neuralis/brain-core
|
|
2
2
|
|
|
3
|
-
The brain of Neuralis: any system a connector can reach — local directories, repositories, machine sandboxes, the vector memory itself — joins ONE URI-addressed, vector-indexed, project/user/agent-scoped virtual filesystem, chunked and
|
|
3
|
+
The brain of Neuralis: any system a connector can reach — local directories, repositories, machine sandboxes, the vector memory itself — joins ONE URI-addressed, vector-indexed, project/user/agent-scoped virtual filesystem, chunked and indexed on sync with optional embedding, revertible on write, policy-governed per path. A synced source pays back twice: its content becomes searchable memory, and its markdown becomes source packages. Concretely: URI-native filesystem, vector memory, source connectors, and the Files UI.
|
|
4
4
|
|
|
5
5
|
## Responsibility
|
|
6
6
|
|
|
7
7
|
- Read, create, modify, list, and search files across every registered source through one URI vocabulary.
|
|
8
8
|
- Manage project-, user-, and agent-scoped source configurations and persist them in the platform zone.
|
|
9
9
|
- Host the connector registry contract: source connectors declared by other packages plug in via `SourceKindRegistry`.
|
|
10
|
-
- Sync connector content into a Qdrant-backed
|
|
10
|
+
- Sync connector content into a Qdrant-backed payload/full-text index, with optional chunked embeddings.
|
|
11
11
|
- Expose the Filesystem package routes (`/api/packages/brain-core/*`) and the agent tools (`fs_read`, `fs_write`, `fs_list`, `fs_search`).
|
|
12
12
|
- Render the workspace Files widget and the `filesystem.change` agent-card.
|
|
13
13
|
|
|
@@ -123,10 +123,12 @@ soft — no badges); (2) reject leading-dash refs/paths (option-injection)
|
|
|
123
123
|
and require `--` before path operands; (3) `-c core.hooksPath=/dev/null
|
|
124
124
|
-c core.fsmonitor=false -c core.pager=cat` on every call, defeating a malicious
|
|
125
125
|
repo-local `.git/config` (closes the malicious-checkout RCE class); (4) strip EVERY
|
|
126
|
-
ambient `GIT_*` env var
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
126
|
+
ambient `GIT_*` env var, then set `GIT_CONFIG_GLOBAL=/dev/null`,
|
|
127
|
+
`GIT_CONFIG_SYSTEM=/dev/null`, `GIT_TERMINAL_PROMPT=0` and `GIT_OPTIONAL_LOCKS=0`.
|
|
128
|
+
Simple-git v4 requires top-level `allowEnvironment` naming exactly those four
|
|
129
|
+
fixed defensive overrides, together with the existing explicit `unsafe:{…}`
|
|
130
|
+
opt-ins for floors (3)/(4). It blocks those same flags/env as attacker-injection
|
|
131
|
+
vectors — stripping ALL ambient `GIT_*` (not a denylist) remains the robust rule. It exports the
|
|
130
132
|
pure helpers `classifyGitOp(op, args) → 'read'|'mutating'|'destructive'` (for the
|
|
131
133
|
later approval gate) and `normalizeStatus`. Read primitives are fully implemented;
|
|
132
134
|
local-mutating ops are implemented but NOT yet tool-exposed (they wait on the
|
|
@@ -687,8 +689,8 @@ through the ordinary user/agent-equality filter, unchanged.
|
|
|
687
689
|
Lifecycle exports (`src/lifecycle.ts`):
|
|
688
690
|
|
|
689
691
|
- `init`, `start`, `onBootstrapComplete`, `drain`, `stop`, `api`, `onCredentialChanged`, `health`, `onPrincipalRevoked`, `provisionProject` (`usecases/provisionProject.ts` — a NEW project's declared `seed:'auto'` sources, written complete through the same create path as the boot repair; see Declared sources), `deprovisionProject` (`usecases/deprovisionProject.ts` — on a PERMANENT project delete, ALL of the project's vector points leave the shared index in ONE bounded `deleteByFilter({ must: [{ field: 'projectId', equals: id }] })` — chunks + folder-ancestor points covered by the same keyword-index filter. MUST-HAVE: a failed delete throws, and so does a degraded boot where Qdrant is configured but the in-memory index is wired (a delete there would leave every real point in Qdrant); the host then stops the purge before any file is removed. It runs BEFORE the fs tree is removed, so resolving the brain infra cannot re-materialize the project dir).
|
|
690
|
-
- `init` state exposes `services["package-source-roots"]` for kernel registration; its delegate is the same function as the direct API method.
|
|
691
|
-
- `BrainCoreApi` — `getProjectServices`, `getProjectInfra`, `getFilesystem`, `upsertSourceConfig`, `listShellSourceRoots(projectId)` (every shell-capable source with its persisted permissions; feeds agent-core's shell uri-policy gate and the terminal's host-tab resolver; NOT access-filtered — consumers evaluate the policy against the caller's own `SessionContext`. Rows carry an explicit **`plane`**: `container` sources contribute their `containerRoot`, resolved by the canonical `resolveLocalRoot`; **host-plane** sources contribute a raw `hostRoot` and an intentionally EMPTY `containerRoot` — no container path exists for them, and the empty value is load-bearing, because the consumer's container-plane filter drops rootless entries so a host source can never leak into a container-plane lookup even if `plane` were ignored. The plane is derived from the connector KIND, never from the slug string — an ordinary local source may legitimately be named `host-notes`. Kinds that host no shell at all (brain vectors, webtop) contribute nothing), and `listSourceRuntimeSummaries(projectId, { userId, agentId, role?, grantedFeatures? })` (the READ sibling of `listShellSourceRoots`, feeding agent-core's `<runtime_stack>` source rendering — **all** connector kinds, **access-filtered** (host-plane rows carry `containerDir: null` — their root is a path in the OPERATOR's filesystem with no container equivalent, and the local-shaped derivation would otherwise print a container path that does not exist, baked into every agent's cached system prompt) via `canAccessScope` → `filesystem.observeScoped`/deny-by-default, each row carrying connector, `os_uri`/`container_dir`, the caller-effective uri-policy, `description`, and the cached index snapshot; reads persisted source-config JSON ONLY — no live walk / no vector count — so it is safe to call once per stream. Agent-core renders the stable structure in the cached `<runtime_stack>` prefix and the volatile counts + on/off in `<workspace_live>`. Disabled sources are INCLUDED, marked `enabledEffective:false`). `listPackageSourceRoots(projectId)` (enumerate every project-associated source as a runtime
|
|
692
|
+
- `init` state exposes `services["package-source-roots"]` for kernel registration; its `listPackageSourceRoots` delegate is the same function as the direct API method, and its `subscribePackageSourceRoots(listener)` calls `listener(projectId)` after every committed source-config write of the app root (`SourceConfigMutation.onChanged` — fired outside the write lock, a no-op write never fires, a throwing listener is logged and never reaches the writer), so the host re-derives that project's flagged package roots at once.
|
|
693
|
+
- `BrainCoreApi` — `getProjectServices`, `getProjectInfra`, `getFilesystem`, `upsertSourceConfig`, `listShellSourceRoots(projectId)` (every shell-capable source with its persisted permissions; feeds agent-core's shell uri-policy gate and the terminal's host-tab resolver; NOT access-filtered — consumers evaluate the policy against the caller's own `SessionContext`. Rows carry an explicit **`plane`**: `container` sources contribute their `containerRoot`, resolved by the canonical `resolveLocalRoot`; **host-plane** sources contribute a raw `hostRoot` and an intentionally EMPTY `containerRoot` — no container path exists for them, and the empty value is load-bearing, because the consumer's container-plane filter drops rootless entries so a host source can never leak into a container-plane lookup even if `plane` were ignored. The plane is derived from the connector KIND, never from the slug string — an ordinary local source may legitimately be named `host-notes`. Kinds that host no shell at all (brain vectors, webtop) contribute nothing), and `listSourceRuntimeSummaries(projectId, { userId, agentId, role?, grantedFeatures? })` (the READ sibling of `listShellSourceRoots`, feeding agent-core's `<runtime_stack>` source rendering — **all** connector kinds, **access-filtered** (host-plane rows carry `containerDir: null` — their root is a path in the OPERATOR's filesystem with no container equivalent, and the local-shaped derivation would otherwise print a container path that does not exist, baked into every agent's cached system prompt) via `canAccessScope` → `filesystem.observeScoped`/deny-by-default, each row carrying connector, `os_uri`/`container_dir`, the caller-effective uri-policy, `description`, and the cached index snapshot; reads persisted source-config JSON ONLY — no live walk / no vector count — so it is safe to call once per stream. Agent-core renders the stable structure in the cached `<runtime_stack>` prefix and the volatile counts + on/off in `<workspace_live>`. Disabled sources are INCLUDED, marked `enabledEffective:false`). `listPackageSourceRoots(projectId)` (enumerate every project-associated source as a runtime package-source candidate `{ slug, uriRoot, containerRoot, scope, recognizesPackages, enabled, kind }`; identity-free like `listShellSourceRoots`, ALL candidates returned so the host applies the floor — project-scope + flagged + enabled + local; the host's `projectPackages` consumes it to scan + hot-reload flagged source dirs alongside `_packages/`). Filesystem events reach the `/brain-core/events` SSE route and the discovered `filesystem` channel of the host `/api/events` hub through ONE authorization adapter: it takes the real session, authorizes EACH requested agent deny-by-default (a foreign agent yields zero events, never an existence-confirming error), and filters events by user/project/types and the authorized agent or source.
|
|
692
694
|
|
|
693
695
|
**Cross-package writes go through `FilesystemService` itself, and its permission check is
|
|
694
696
|
the ONLY gate on that path.** `getProjectServices(projectId).filesystem` hands back the live
|
|
@@ -806,10 +808,9 @@ whole index: `enrichment_revision` (`src/sync/categoryInference.ts`) marks a pay
|
|
|
806
808
|
derived fields are what the current rules give for its own uri + content, a stamped point
|
|
807
809
|
is skipped before anything reads its content back, and only the unstamped candidates are
|
|
808
810
|
hydrated — payload-only upserts, existing vector reused, no re-embed. On a settled source
|
|
809
|
-
the sweep WRITES nothing. A point holding no inline text
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
full pass, but it is never re-written. The
|
|
811
|
+
the sweep WRITES nothing. A point holding no inline text (a media point) never becomes
|
|
812
|
+
stamped, so it stays a candidate and is re-hydrated each full pass, but it is never
|
|
813
|
+
re-written unless a URI-derived field drifted. The
|
|
813
814
|
stamp is written by ONE boundary,
|
|
814
815
|
`src/vector/FilesystemVectorIndex.ts`, on every index write from every path; a payload it
|
|
815
816
|
cannot derive from (a chunk, a tombstone, a `pending_review` draft, a node holding no
|
|
@@ -920,11 +921,11 @@ The embedding model registry (`src/embeddings/models.ts`, `EMBEDDING_MODELS`) is
|
|
|
920
921
|
|
|
921
922
|
Every cloud provider has its OWN platform credential (`embedding.<provider>`), never the chat provider's `llm.*` key — so an embed call is counted by the credential-use rules and priced by the embedding spend meter on its own; an operator endpoint's key is `embedding.endpoint.<endpointId>`. Every call to a public provider or endpoint is address-checked and IP-pinned by the kernel's SSRF floor on every call. Many rows expose MRL / Matryoshka selectable dimensions (`supportedDimensions`).
|
|
922
923
|
|
|
923
|
-
**Active vs target, and the switch.** The
|
|
924
|
+
**Active vs target, and the switch.** The v3 serving lock records metadata mode or a certified ACTIVE dense generation (model, dimension, recipe, collection). `embeddingEnabled:false` makes payload sync/writes and keyword/filter search provider-free; semantic requests fall back with `requested_mode`, `effective_mode` and `embedding_degraded`. Result rows expose current/stale/missing/unknown embedding status, so old vectors never imply fresh content. Existing no-lock collections preserve unknown vectors in metadata mode without inferring a model. Dense work uses the certified active generation. The configured `embeddingModelId`/`embeddingDimension` are the TARGET; a target that differs is a pending switch the admin Vector section shows with a sampled estimate — nothing switches by itself. The switch is a generation rebuild (`health/collection` `rebuild-generation`): the target re-embeds eligible points from their stored text into a new collection while the old one keeps serving, every write that lands meanwhile is mirrored onto it, and the swap moves the lock one generation on — `brain://` content and version history survive, and the dimension may change freely. It can be cancelled (the shadow is dropped, nothing else changes) and resumed after a restart (a restart pauses it). Separately, `sources/reindex` with `force` re-embeds a file, a folder or a source with the ACTIVE model, estimate first — an unchanged file keeps its payload (`updatedAt`, version history), so a re-embed never reads as an edit. Already recovery-only points with unavailable input retain their complete payload without vectors in the target; verified available input restores ordinary embedding. Unmarked missing input still pauses the rebuild. Recovery retention, cleanup and generation eligibility follow the constraints under Manifest-baseline merge below.
|
|
924
925
|
|
|
925
|
-
**Media — images, PDFs, video, audio.** With a multimodal ACTIVE model (`gemini-embedding-2` or `voyage-multimodal-3.5` — the registry `modalities` as far as the model's client can send them: an operator endpoint speaks the text-only `/v1/embeddings` wire, so its row's declared media modalities are kept but not embedded) the sync embeds media files from their BYTES: an image is one point, a PDF is embedded page by page through the connector's PDF renderer (the document point carries page 1, pages 2..`brainSyncMaxPdfPages` are page chunks), each point marked `modality` and carrying no stored bytes — a rebuild or a forced re-embed reads the source again. Each source chooses the kinds in its sync settings (`sync.media`): images and PDFs on, video and audio off by default; `brainSyncMaxMediaMb` bounds one file, and a kind switched off is purged by the next full pass. A text-only
|
|
926
|
+
**Media — images, PDFs, video, audio.** With a multimodal ACTIVE model (`gemini-embedding-2` or `voyage-multimodal-3.5` — the registry `modalities` as far as the model's client can send them: an operator endpoint speaks the text-only `/v1/embeddings` wire, so its row's declared media modalities are kept but not embedded) the sync embeds media files from their BYTES: an image is one point, a PDF is embedded page by page through the connector's PDF renderer (the document point carries page 1, pages 2..`brainSyncMaxPdfPages` are page chunks), each point marked `modality` and carrying no stored bytes — a rebuild or a forced re-embed reads the source again. Each source chooses the kinds in its sync settings (`sync.media`): images and PDFs on, video and audio off by default; `brainSyncMaxMediaMb` bounds one file, and a kind switched off is purged by the next full pass. A text-only model or disabled embedding still indexes enabled media metadata and PDF page inventory without provider calls, reporting embedding debt; it never invents OCR text or semantic vectors. Invoked PNG inputs receive bounded structural signature/chunk/CRC checks before provider work; an invalid skip preserves existing indexed and recovery payloads and is counted separately. This preflight does not decode pixels. A semantic search returns media hits with their `modality` (and a PDF's `page`); full-text search never matches them, they carry no text.
|
|
926
927
|
|
|
927
|
-
**Embedding spend.** Every priced or keyed embed call leaves one row in `<appRoot>/data/brain-core/embedding-usage.jsonl` (`{ts, model, tokens, estUsd, calls}`; an unpriced model is counted, never priced) and adds to today's aggregate the Vector section shows; `embeddingDailyUsdCap` (0 = off) stops embedding for the rest of the UTC day once reached — sync
|
|
928
|
+
**Embedding spend.** Every priced or keyed embed call leaves one row in `<appRoot>/data/brain-core/embedding-usage.jsonl` (`{ts, model, tokens, estUsd, calls}`; an unpriced model is counted, never priced) and adds to today's aggregate the Vector section shows; `embeddingDailyUsdCap` (0 = off) stops embedding for the rest of the UTC day once reached — payload sync continues with embedding debt and stops later provider calls for that job; semantic search falls back to full-text.
|
|
928
929
|
|
|
929
930
|
**Credential-use limits (v1).** Embedding spend is governed by the platform's per-credential
|
|
930
931
|
calls/period rules through `embeddings/usageGate.ts`: brain-core's `init` stashes the
|
|
@@ -934,13 +935,12 @@ batch that splits into several posts counts one use per post. This per-call hook
|
|
|
934
935
|
REAL enforcement for the embed class (not telemetry): the key is construction-captured and
|
|
935
936
|
`LazyEmbedder` memoizes the client, so the host's resolve-time counter sees roughly one
|
|
936
937
|
grant per process. A deny throws the typed `CredentialUseLimitedError`
|
|
937
|
-
(`code: 'credential_use_limited'`): **sync**
|
|
938
|
-
`
|
|
939
|
-
makes the retry cheap; there is no backoff — a denied source fail-fasts every tick),
|
|
938
|
+
(`code: 'credential_use_limited'`): **sync** continues payload indexing and records
|
|
939
|
+
`embeddingDegraded`; later provider calls in that job stop, while already running calls finish,
|
|
940
940
|
**semantic search** soft-degrades to the full-text filter search with a `warning` on the
|
|
941
941
|
response envelope — as it does for the embedding daily cap, a missing `embedding.*` key
|
|
942
942
|
(`EmbeddingCredentialMissingError`) and an active model the platform no longer defines;
|
|
943
|
-
every
|
|
943
|
+
Typed provider/network/timeout/quota unavailability degrades; validation, parse and local authorization errors propagate before the payload lands, storage errors propagate, and after the durable payload every embedding error — typed or not — is named debt in the answer (`usage.metadata.embeddingDeferred`), never a failed write. A sync against an out-of-credit embedder COMPLETES with `lastSyncResult.embeddingDegraded` (at most the concurrency's worth of provider calls, then no more that job) and writes its checkpoint, so the source is not due again until its own interval; only the embedding-only pass pauses, with the reason.
|
|
944
944
|
|
|
945
945
|
since 2026-08-18 the search degrade covers a SECOND typed code:
|
|
946
946
|
`ProviderQuotaExhaustedError` (`code: 'provider_quota_exhausted'`,
|
|
@@ -950,7 +950,7 @@ thrown immediately instead of burning the retry budget on a wait that cannot hel
|
|
|
950
950
|
semantic search answers from full-text rather than a 500. The classification **fails toward
|
|
951
951
|
retryable** — an unparseable or unrecognised body keeps the old backoff, because an
|
|
952
952
|
OpenAI-compatible custom `baseUrl` may return anything — and a genuine, retry-exhausted rate
|
|
953
|
-
limit
|
|
953
|
+
limit becomes typed availability after its retry budget, retaining the safe degraded reason. Every degrade code lives on
|
|
954
954
|
the USE-CASE, so the `fs_search` tool inherits it, not just the route.
|
|
955
955
|
Deterministic/Ollama models carry no credential and are never gated. Rules are set on the
|
|
956
956
|
admin Credentials tab (exact-id). The `embedding.*` keys are ordinary counted credentials —
|
|
@@ -973,9 +973,9 @@ There is intentionally no README inside the contribution folders; this section i
|
|
|
973
973
|
- `start(state)` begins the background vector activity watch (`startQdrantWatch` wires `usecases/vectorActivityWatch.ts`, every `brainQdrantWatchIntervalMs` — 30 s — `BRAIN_INFRA_MODE=local` only). The vector backend wired at init is **not** hot-swapped (out of scope); the watch surfaces a degraded flag and logs transitions — `vector.qdrant.lost` and `vector.qdrant.recovered` (the latter notes that a restart re-enables Qdrant-backed search when the wired backend is in-memory). While Qdrant is reachable the same tick reads the server's optimizer tracker (one `GET /collections/<c>/optimizations?with=completed`, at most 50 finished runs) — Qdrant does not log its own background optimization — and writes `vector.optimizer.completed {optimizer, status, points, segments, durationMs}` once per finished run (the SERVER's start/finish times, so a run shorter than the tick is not lost), `vector.optimizer.long` once for a run still going after 10 minutes, and `vector.optimizer.overflow {returned}` when every returned run is new while earlier ones were seen (the tracker rolled past runs between two reads). The first read only seeds: runs finished before the process started are not re-logged at every boot. These lines go to the console (`docker logs`) AND `vector.jsonl`; the per-probe `vector.qdrant.health` line stays file-only. The lifecycle `health(state)` returns structured backend/connectivity checks to the generic runtime health aggregate; no vector-status package API is exposed. The interval is cleared in `stop()`.
|
|
974
974
|
- `onBootstrapComplete(state, ctx: BootstrapCompleteContext)` is the single deferred-wiring entry point: it reads the published registries through `ctx.platform.connectorRegistries()` and starts the `SyncScheduler` from `ctx.platform.hostIdentity()`. The factory resolves those registries lazily through its init context. There are no imperative setters (`setHostIdentity`, `setConnectorRegistries`).
|
|
975
975
|
- `init` delegates to `wiring.buildBrainState`, wiring the declared `ctx.config` reader and GLOBAL-only `ctx.credentials.resolveCredential` into the embedding provider before shared infrastructure is built. Platform facts are read lazily through `ctx.platform`; no config setter or source-running bootstrap push is exposed. Credential changes reach the bounded lifecycle hook, and runtime health reads structured vector checks.
|
|
976
|
-
- **Data formats.** brain-core's three durable record kinds — `brain-core/embedding-lock` (
|
|
976
|
+
- **Data formats.** brain-core's three durable record kinds — `brain-core/embedding-lock` (v3), `brain-core/source-config` (v2) and `brain-core/pending-changes` (v1, the `_pending/changes.jsonl` journal) — are declared on the kernel's data-format ledger at module load (`src/store/dataFormats.ts`) and claimed at the top of `init`, before the first read: a kind a newer binary raised stops the init by name. Per record, the lock's `version` and a source config's or pending change's `formatVersion` (absent = 1) are checked before every rewrite — the check reads the STORED record, never the incoming one, so a config built fresh over a newer file is refused too — and a newer record is never rewritten (the journal's appends stay open; its compaction refuses). Every source-config write stamps the declared version (`SOURCE_CONFIG_FORMAT.version`, 2); an identical re-upsert still writes nothing. `embedding-lock` v3 and `source-config` v2 are `upgrade: offline` kinds: the app refuses to start over older data naming `neuralis upgrade`, which raises them (`scripts/embeddingLockV3.ts`, exported as `@neuralis/brain-core/upgrade`). Source configs are written durably, and one that fails validation is skipped AND logged (`source-config.invalid-skipped`), never silently gone.
|
|
977
977
|
- **Declared credentials + dead-sweep.** brain-core's manifest declares the four embedding credentials — `embedding.openai`, `embedding.gemini`, `embedding.qwen`, `embedding.voyage` — in `neuralis.credentials[]` (`category: 'vector'`), so they appear in the admin catalog for an owner to set; an operator endpoint's `embedding.endpoint.<id>` is a dynamic family, never declared. `qdrant.apiKey` is deliberately NOT declared: `getQdrantClient()` is synchronous and boot-critical, so it structurally cannot read the credential store; the value comes from `QDRANT_API_KEY` in the boot env (Qdrant is infrastructure topology, not a per-scope secret — see `src/config/README.md`; setup writes the line itself and the server enforces the key on every request, with a mismatch surfacing as the structured `vector.qdrant.unauthorized` log line + a degraded Vector tab, not a boot death). `src/config/env.ts` was swept of dead credential plumbing: the old `resolveCredential()` helper, `BRAIN_CREDENTIAL_MAP`, and the `s3.*` / `media.apiKey` env reads (declared nowhere, consumed nowhere) are all removed. Only `getNeuralisEnv().qdrant.*` (URL/apiKey/collection — boot-critical infra topology from `process.env`) and the registry-driven embedding resolvers remain.
|
|
978
|
-
- **Declared config settings.** brain-core's manifest declares its **
|
|
978
|
+
- **Declared config settings.** brain-core's manifest declares its **84** platform-config keys in `neuralis.configSettings[]` (`PackageConfigSetting[]`) — sync/scan/chunking/media/binary-sniff/git-panel/watch-recovery/vector-maintenance/vector-write-retry/pending-orphan-probe/search caps and timeouts across three categories: `brain` (78 keys), `vector` (5) and `debug` (1). (Re-count the manifest array before quoting this; it has been stale before.) The originals: the `brain` category (`brainAutoSyncMode`, `brainMaxScanFiles`, `inlineVideoMaxMb`, `brainSyncConcurrency`, `brainOllamaEmbedConcurrency`, `brainDebug` — `brainEmbedConcurrency` was DELETED: every embedder implements `embedBatch`, so the only fan-out fallback was dead code), the `vector` category (`embeddingModelId`, `embeddingDimension`, `ollamaUrl`, `openaiBaseUrl`, and `embeddingEndpoints` — written only through the host's endpoint route — rendered by the admin Vector tab, not the flat list), the embedding keys in `brain` (`embeddingEnabled`, `embeddingRequestTimeoutMs`, `qwenEmbeddingBaseUrl`, `embeddingDailyUsdCap`, `vectorKeepPreviousGeneration`), the media lane's `brainSyncMaxMediaMb` and `brainSyncMaxPdfPages`, and the `debug` category (`brainVectorLogConsole` — the stdout tee described under Observability below). The host registers them into `PlatformConfigStore` at bootstrap via the agent-core collector (first-party trust-gated); values reach brain-core through the injected `BrainConfigProvider`; the shared `getBrainConfigNumber(key, env, default)` live reader (config/env.ts) backs `brainSyncConcurrency` (DeltaSyncRunner) and `brainOllamaEmbedConcurrency` (the OllamaEmbedder semaphore, embeddings/factory.ts — applies on restart/embedder rebuild). The agent-core `configDeclarationDrift` test pins brain-core's consumed ⊆ declared set bidirectionally.
|
|
979
979
|
- The `CommunityInfraFactory` uses the kernel’s bounded `ProjectServiceFactory` internally. Routes and tools resolve services via `state.infraFactory.getServices(projectId)` — no global default-project state.
|
|
980
980
|
- Source connectors are declared in package manifests via `neuralis.connectors[]`. Connector **kinds** register into the host's `SourceKindRegistry` at boot (the factory templates); Brain-core itself contributes the built-in `local` and `brain` kinds via `LocalDiskConnector` and `BrainInternalConnector`. Connector **instances** are bound PER PROJECT — `buildCommunityFilesystemInfra` constructs a fresh `ConnectorRegistry` inside each project's `FilesystemInfra` and `registerForSource`s that project's source slugs into it. Two projects with the same local slugs (`data`/`packages`/`brain`/`app`) therefore never collide; the previously-shared host registry was last-writer-wins and leaked one tenant's filesystem (and poisoned the shared vector index) into another. The host-shared registry handed in at bootstrap is retained only as the boot-readiness gate, no longer a source-binding store.
|
|
981
981
|
- Brain-core declares **no hooks**. The former `hooks.json` / `host.ts` `onFileCreated` / `onFileModified` PostToolUse callbacks were deleted: they were intentional no-ops (the create/modify use cases update the vector index inline), and their registration produced a noisy `[hooks] Callback resolution failed` warning whenever `dist/src/host.js` drifted. The `./host` package export was removed with them.
|
|
@@ -1094,16 +1094,7 @@ URI the same way it ingests `machine_use screenshot`.
|
|
|
1094
1094
|
rather than as a re-resolvable `ref{uri}` — re-reading the `.pdf` uri on
|
|
1095
1095
|
replay would re-render non-deterministically (or, with rendering off,
|
|
1096
1096
|
return text → an empty image → a provider 400).
|
|
1097
|
-
- **
|
|
1098
|
-
vision block whenever the connector returns `bytes`. It degrades the
|
|
1099
|
-
file to a marker only when the runtime EXPLICITLY declares the matching
|
|
1100
|
-
capability disabled — `runtime.modelCapabilities.imageInput === false`
|
|
1101
|
-
or `videoInput === false`. Absent / partial `modelCapabilities`
|
|
1102
|
-
(programmatic callers, agent-core boundaries that don't snapshot the
|
|
1103
|
-
model registry) still emit the block; provider adapters that cannot
|
|
1104
|
-
accept it strip it at adapter time. The explicit-deny marker reads
|
|
1105
|
-
`[image/png 248 KB — imageInput disabled for this turn]`. This matches
|
|
1106
|
-
the `machine_use screenshot` semantics (unconditional emit).
|
|
1097
|
+
- **Unconditional producer.** `readFilesUseCase` emits media whenever the connector supplies bytes and a recognized media MIME. Both direct-URI and indexed reads use the existing binary-extension table when a byte-bearing connector omits MIME. Unknown valid UTF-8 remains text; invalid UTF-8 and opaque files keep their source URI and an honest marker. Upload/write paths preserve original bytes. The agent-core per-step delivery boundary alone decides model acceptance, image integrity and explicitly declared subtype limits; converters only translate shapes.
|
|
1107
1098
|
- **Per-batch budget.** The use-case sums approximate decoded sizes of
|
|
1108
1099
|
every attached block; once the running total crosses 12 MB, remaining
|
|
1109
1100
|
blocks downgrade to a `[batch image budget exceeded — request fewer
|
|
@@ -1339,7 +1330,7 @@ the package-manager content stores — `node_modules`, `.pnpm-store`, `.yarn/cac
|
|
|
1339
1330
|
root and nested — because an in-container `pnpm install` on a bind-mounted
|
|
1340
1331
|
repository lands `.pnpm-store/` at the repo root (5 124 files on one mounted
|
|
1341
1332
|
package, 2026-08-27), and a source's `sync.exclude` is ADDITIVE over this floor,
|
|
1342
|
-
so every existing source inherits a new floor entry at its next sync. Pattern/media exclusions remove obsolete parent/chunk search data. Recovery-bearing parents — pending/deleted records, saved baselines and sole-copy `brain://` content — retain their complete payload with `recovery_only:true`, no embedding stamp and no dense or BM25 vectors. Retrieval, browsing and review remain policy-gated; search, enrichment and source-package discovery exclude retained recovery points.
|
|
1333
|
+
so every existing source inherits a new floor entry at its next sync. Pattern/media exclusions remove obsolete parent/chunk search data. Recovery-bearing parents — pending/deleted records, saved baselines and sole-copy `brain://` content — retain their complete payload with `recovery_only:true`, no embedding stamp and no dense or BM25 vectors. Retrieval, browsing and review remain policy-gated; search, enrichment and source-package discovery exclude retained recovery points. Verified source input permits ordinary payload indexing again; missing/stale embedding debt remains explicit until real dense completion. Enabled/auto inactivity never purges an index, and an immutable READ floor alone never authorizes cleanup. Generation rebuilding classifies current source policy before provider work and again at its config-coordinated swap: unknown provenance or unavailable/invalid configuration pauses without swapping. The dollar estimate samples only eligible content and exposes protected/excluded/unresolved counts; it remains a range, not a hard spending bound. Full sync runs this cleanup at its existing end; targeted sync never purges.
|
|
1343
1334
|
|
|
1344
1335
|
**The READ FLOOR is the INDEX FLOOR.** Since 2026-08-05 the immutable `floor: true`
|
|
1345
1336
|
rows govern a THIRD axis: `isUriSyncIndexable` evaluates them alongside the
|
|
@@ -1501,7 +1492,7 @@ ADD gate remain AUTHORITATIVE for both families; a declaration's
|
|
|
1501
1492
|
`visibility.seeRequires` is defense-in-depth, unioned into the SEE filter, never
|
|
1502
1493
|
the boundary.
|
|
1503
1494
|
|
|
1504
|
-
The package declares the optional singleton `package-source-roots` service, delegating to its existing source-root enumerator with scope, enabled state and package-recognition flags intact. Project infrastructure uses the loader's bounded project factory; running jobs and event subscriptions pin the same infrastructure through idle eviction. Permanent purge fences new queue work and waits for existing writes before vector deletion, subscription disposal and cache invalidation. Shutdown `drain` stops background admission and awaits completion bookkeeping under the runtime bound.
|
|
1495
|
+
The package declares the optional singleton `package-source-roots` service, delegating to its existing source-root enumerator with scope, enabled state and package-recognition flags intact, plus a change subscription off the one source-config commit funnel. Project infrastructure uses the loader's bounded project factory; running jobs and event subscriptions pin the same infrastructure through idle eviction. Permanent purge fences new queue work and waits for existing writes before vector deletion, subscription disposal and cache invalidation. Shutdown `drain` stops background admission and awaits completion bookkeeping under the runtime bound.
|
|
1505
1496
|
|
|
1506
1497
|
## Gotchas
|
|
1507
1498
|
|
|
@@ -1509,7 +1500,7 @@ The package declares the optional singleton `package-source-roots` service, dele
|
|
|
1509
1500
|
- `FilePresence` is per-node: `brain` (vector-only), `synced` (index + connector agree), `unindexed` (on-disk but not yet indexed), `stale_indexed` (in index but no longer on connector). `fs_list` emits a single-character glyph (`●` / `○` / `✗`) only when a child's presence differs from its parent.
|
|
1510
1501
|
- `fs_read` and `fs_list` are **connector-first**: they take live data (and, for `fs_list`, the tree structure) from the connector even when the vector index is cold or unreachable, and reconcile presence by a targeted index lookup over exactly the listed URIs. Consequence: the live-merge `fs_list` tree shows `brain` / `synced` / `unindexed` only — `stale_indexed` appears in the `only_indexed:true` view, on the source registry's `indexed_count` vs `on_disk` drift, and on a per-source connector failure (the broken source's indexed slice is surfaced as `stale_indexed`). See `src/usecases/README.md` for the phase/budget model. `fs_search` in `semantic` / `filter` modes requires the index to be warm; `grep` mode bypasses the index entirely and runs ripgrep / git grep / grep over the live connector. The keyword surface (filter mode + the hybrid text prefetch) rides the `content` full-text payload index (word tokenizer, lowercase, max token 255 — the Lucene/ES convention; the whole content is indexed, only over-length junk tokens are skipped) — `ensurePayloadIndexes` RECONCILES a drifted text index (param mismatch or missing params → delete + recreate) instead of no-opping on "already exists", so a legacy case-sensitive index heals on the first vector op after deploy. Search failures surface as fixed client-safe error rows with `count.errors` (backend detail is server-logged only). `fs_search` now enforces the per-uri `read` policy on every result across all three modes (closing the prior gap where it only feature-gated) — so a `read:false` path is never search-visible, and `grep` is the uri-policy-gated path to literal search without `execute`/shell.
|
|
1511
1502
|
- Source slugs are URI schemes. Scoped clones use distinct schemes (`machine-alice://`, `local-bob://`) — never reuse a slug across scopes.
|
|
1512
|
-
- The embedding lock (`src/embeddings/lock.ts`, `~/.neuralis/app/config/embedding-lock.json`) records the ACTIVE model and dimension; changing `embeddingModelId`/`embeddingDimension` only sets the target, and the switch is the generation rebuild — never a silent re-point, never a reset. `QDRANT_COLLECTION_DIMENSION_MISMATCH` (`src/vector/QdrantVectorIndex.ts`) still fires when the live collection's vector size disagrees with the lock. **`pnpm reset:vector`** drops
|
|
1503
|
+
- The v3 embedding lock (`src/embeddings/lock.ts`, `~/.neuralis/app/config/embedding-lock.json`) records metadata serving or the certified ACTIVE model and dimension; changing `embeddingModelId`/`embeddingDimension` only sets the target, and the switch is the generation rebuild — never a silent re-point, never a reset. `QDRANT_COLLECTION_DIMENSION_MISMATCH` (`src/vector/QdrantVectorIndex.ts`) still fires when the live collection's vector size disagrees with the lock. The explicit `dense-clear` collection action removes only dense embeddings, preserving text/payload/history and leaving durable catchup debt. **`pnpm reset:vector`** requires proven offline quiescence and drops owned collections AND the lock only after all selected deletions succeed — and with them the `brain://` content and its version history, which live only in Qdrant; it is the last resort, not the model switch. Config resolution (`src/config/env.ts`, surfaced through the embedder factory) throws `EMBEDDING_CREDENTIAL_MISSING` / `UNSUPPORTED_EMBEDDING_DIMENSION` instead of silently falling back to a different provider, dimension or key.
|
|
1513
1504
|
- Every write snapshots `version.baseline` on the node, enabling `fs_write {revert:true}` (1-level undo) without an external embedder. The chain is the recovery contract — the policy layer does not consult a separate `getMutationSafety` resolver.
|
|
1514
1505
|
- A write's success response also surfaces `version: { diff: { added, removed }, changedAt? }` (real previous-vs-next line delta from `computeLineChangeStats`, not an input estimate). The `filesystem.change` card and the chat composer's Changes & Actions panel consume this directly so the `+N/-M` badge stays accurate even for `replace_text` where the find/replace fragments don't equal the actual line change.
|
|
1515
1506
|
- `commitWrite` (`usecases/write/commit.ts`) orders the slow phases so a write pays the least it can, and **every step of that order is an invariant** — the full rule, with its degrade matrix, lives in `src/usecases/README.md` and is stated there alone.
|
package/app/README.md
CHANGED
|
@@ -19,7 +19,7 @@ React surface contributed by `@neuralis/brain-core`: the Files widget, the `file
|
|
|
19
19
|
|
|
20
20
|
- `installFilesystemHostComponents({ registry, port })` registers the lazy `FilesystemWidget` in the host `PackageHostRegistry` under `componentImport: '@neuralis/brain-core/app/filesystem'` and registers `FilesystemChangeCard` for the `filesystem.change` card type via `agent-core`'s chat card registry — WITH the card's height model (`estimateFilesystemChangeCardHeight`) AND its composer-aggregation contract (`FILESYSTEM_COMPOSER_CONTRACT` from `app/cards/diffUtils.ts`): brain-core OWNS how its card's activity reaches the composer's Changes tab and the post-stream summary (`tab: 'changes'` + the `extractFilesystemComposerChanges` paths/`version.diff` extractor); agent-core's aggregation surfaces iterate the card registry and carry zero filesystem literals. Both are module-level stable references (the registry's idempotency check compares identity). The widget is wrapped in `<PackageApiProvider slug="brain-core" projectId agentId userId>` so all internal API calls resolve through the kernel client.
|
|
21
21
|
- The same install entry fills the host slot `workspace.provider:@neuralis/brain-core` with `<FilesystemPackageHost port={port}>`, which the host's provider root wraps around the workspace (registration order — after agent-core's fill, so inside it). It consumes the `WorkspaceHostPort` (active project/agent ids, agent map, file marks, event-stream URL builder) and exposes a `FilesystemHostValue` to every component below it. The `useBuildFilesystemHostValue` hook is the single adapter — the Files UI reads agents and file marks through that contract, never through host-specific imports.
|
|
22
|
-
- `app/filesystem/api/` calls the brain-core package routes
|
|
22
|
+
- `app/filesystem/api/` calls the brain-core package routes through a kernel `PackageApi` client each Files window passes (built over the window's project and bound agent) — no direct `fetch` against `/api/packages/brain-core/*` from components.
|
|
23
23
|
|
|
24
24
|
## Security & scope
|
|
25
25
|
|
package/app/cards/DiffView.tsx
CHANGED
|
@@ -72,12 +72,14 @@ export const DiffView = memo(
|
|
|
72
72
|
|
|
73
73
|
return (
|
|
74
74
|
<div className="font-mono text-[11px] leading-[18px] overflow-x-auto overflow-y-clip">
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
<div className="min-w-full w-max">
|
|
76
|
+
{elements}
|
|
77
|
+
{truncated && (
|
|
78
|
+
<div className="w-full text-[10px] text-white/40 bg-white/4 px-3 py-1 text-center">
|
|
79
|
+
··· {hunks.reduce((n, h) => n + h.lines.length, 0) - maxLines} more lines ···
|
|
80
|
+
</div>
|
|
81
|
+
)}
|
|
82
|
+
</div>
|
|
81
83
|
</div>
|
|
82
84
|
);
|
|
83
85
|
},
|
|
@@ -111,7 +113,7 @@ export const DiffView = memo(
|
|
|
111
113
|
|
|
112
114
|
function SkippedLines({ label }: { label: string }) {
|
|
113
115
|
return (
|
|
114
|
-
<div className="text-[10px] text-white/35 bg-white/[0.03] px-3 py-0.5 text-center border-y border-white/6 select-none">
|
|
116
|
+
<div className="w-full text-[10px] text-white/35 bg-white/[0.03] px-3 py-0.5 text-center border-y border-white/6 select-none">
|
|
115
117
|
{label}
|
|
116
118
|
</div>
|
|
117
119
|
);
|
package/app/cards/README.md
CHANGED
|
@@ -17,7 +17,7 @@ Filesystem agent-card: an IDE-style diff view rendered for `fs_write` tool calls
|
|
|
17
17
|
- `estimateFilesystemChangeCardHeight` (exported from `FilesystemCardShell.tsx`) — the card's OWN row-height model, handed to agent-core's card registry at install time. agent-core's timeline asks the registry for it before a row has been measured; a card with no model falls back to a generic constant. It is declared next to the chrome it describes because it drifted badly when it lived in the timeline: the host-side table once claimed 240 against a real ~117 — a live-measured `first-measure` delta of **−181px**, the worst of any builtin. The **COMPACT branch is variant-aware** (H1, residual-slide audit 2026-08-07): the body is content-height clipped at `maxHeight: 90`, NOT a constant, so the model is `27 + min(90, bodyContent)` where `bodyContent` mirrors the render dispatch — `18 × diffLines` for a CREATE's input-derived rows, `32` for the one-line fallbacks (pending "Running…", "Done"/"Operation failed", non-content ops), and the **90 CEILING for a completed content MODIFY deliberately** (H2 pre-reserve: the real LCS diff arrives from an async fetch and adds context rows the input-derived count cannot see — ceiling bias accepted so the arrival does not resize the row in view). The previous constant-117 model over-reserved every short-bodied variant by +18…+72. The **EXPANDED branch** models the diff body from `computeLineCounts` (the same helper the header badge uses) with a deliberate upward margin, and is not optional: returning the compact height for a row the disclosure store says is expanded measured **−1353px** live (114 estimated against 1479 rendered), and an under-reserve does not leave a gap — it paints the next row on top of this one. The memo is keyed by the tool object **with the status it computed at** — the tool mutates by reference across pending→settle, so a reference-only memo served the pending height after settle (the H3 class). Keep both branches in step with `renderHeader` / `compactHeight` / `DiffLineRow`'s `h-[18px]`, and keep the export a module-level reference (the registry compares estimator identity). Contract: agent-core `app/chat/cards/README.md` → "Card height model".
|
|
18
18
|
- `DiffView` — green/red line renderer with single-column line numbers, truncation and skipped-context markers.
|
|
19
19
|
- `NonContentOpView` — summary renderer for `set_fields`, `move`, `delete`, `revert`.
|
|
20
|
-
- `diffLine.tsx` — the **shared single-column diff-line primitive**: `DiffLineRow({ lineNo?, type, content })` + the `DIFF_LINE_BG` palette (`add` emerald / `remove` red / `context` colourless). ONE owning file for the green/red/colourless look + the line-number gutter. Its only consumer today is this card's `DiffView` — the Files-widget review diff moved to `@codemirror/merge` (`ReviewDiffView`) and the old hand-rolled `app/filesystem/ui/DiffView.tsx` was deleted. Keep it a standalone primitive: it is still the shared shape any future single-column diff renderer should reuse. No `+`/`-` prefix char — the row background conveys add/remove. **Gutter is git / VS Code unified-diff style:** every row numbered — REMOVE rows show their OLD (pre-edit) file line number, ADD + CONTEXT show the NEW one (so the column intentionally jumps back at a block replacement: old positions then new).
|
|
20
|
+
- `diffLine.tsx` — the **shared single-column diff-line primitive**: `DiffLineRow({ lineNo?, type, content })` + the `DIFF_LINE_BG` palette (`add` emerald / `remove` red / `context` colourless). ONE owning file for the green/red/colourless look + the line-number gutter. Its only consumer today is this card's `DiffView` — the Files-widget review diff moved to `@codemirror/merge` (`ReviewDiffView`) and the old hand-rolled `app/filesystem/ui/DiffView.tsx` was deleted. Keep it a standalone primitive: it is still the shared shape any future single-column diff renderer should reuse. No `+`/`-` prefix char — the row background conveys add/remove. `DiffView` owns one shared content-width wrapper; every row fills it so shorter coloured lines also cover the horizontal scroll extent. **Gutter is git / VS Code unified-diff style:** every row numbered — REMOVE rows show their OLD (pre-edit) file line number, ADD + CONTEXT show the NEW one (so the column intentionally jumps back at a block replacement: old positions then new).
|
|
21
21
|
- Diff utilities (`diffUtils.ts`): input-derived hunk builders (`computeCreateDiff`, `computeReplaceTextDiff`, `computeMultiEditDiff`, `computeUpdateDiff`, `computeTextInsertDiff`, `computeLineCounts`) AND the real baseline→current LCS (`computeLcsDiff` + `countHunks`) shared with Changes. Callers must bound the O(n·m) matrix before invoking `computeLcsDiff`; pending previews use `pendingDiffWithinBudget`, because a byte cap alone does not bound newline-dense text. Plus `detectLanguage`, `isContentAction`, `extractContentString`, and `parseToolInput` (the streaming-tolerant `}`-tail-checked input parse — the fs-specific name for agent-core's shared `parseSettledObject`; ONE owner within brain-core for the card AND the height model) — which now also runs `normalizeCardInput`, the ONE place two write vocabularies are reconciled. `fs_write` carries its intent in KEYS (`edit`, `insert`, `lines`, `overwrite`, `create`, `fields`, `move`, `copy`, `mkdir`, `revert`, `delete`); the old pair carried it in `action` plus a flat field per shape. A verb-key input is PROJECTED onto the shape the views already read (`edit[].old_string/new_string` → the `replace_text` `edits[]` pair, so the red/green hunk appears before the tool result lands and a pending approval renders the PROPOSITION), and a row written by `fs_create`/`fs_modify` passes through untouched — which is what keeps the stored history rendering. A composed call previews the most informative verb (`edit` before `lines`, `insert`, `overwrite`, `create`). Pinned by `test/ui/verbKeyCardInput.test.ts`. Types: `DiffHunk`, `DiffLine`, `DiffLineType`.
|
|
22
22
|
- Composer-aggregation ownership (`diffUtils.ts`, the composer-contract inversion): `extractResultVersionDiff` (the ONE `structuredContent.version.diff` reader — the card's `+N/−M` header badge AND the composer extractor share it; moved here from both its former private copy in `FilesystemChangeCard` and agent-core's deleted `extractResultDiff`), `extractFilesystemComposerChanges` (paths via agent-core's shared `extractPathsFromToolCall` + the former `deriveOpenPath` input-uri fallback for `ok:false` results; diff on the first entry), and `FILESYSTEM_COMPOSER_CONTRACT` (`{ tab: 'changes', changes }`, module-level stable) — registered in `installFilesystemHostComponents.tsx` so agent-core's Changes tab + post-stream summary learn about fs changes from the card REGISTRY, never from literals. Pinned by `test/ui/composerContract.test.ts` (parity: success uri+diff, diff-less results, `ok:false` input fallback, files[] multi-path, empty, and the reducer's string-input forms — a COMPLETE JSON string parses via the settled-object gate, a PARTIAL in-flight string yields nothing and is covered by agent-core's aggregate `openPath || label` fallback row).
|
|
23
23
|
|
package/app/cards/diffLine.tsx
CHANGED
|
@@ -34,11 +34,9 @@ export const DiffLineRow = memo(function DiffLineRow({
|
|
|
34
34
|
type: DiffLineType;
|
|
35
35
|
content: string;
|
|
36
36
|
}) {
|
|
37
|
-
//
|
|
38
|
-
// green/red background) and grows with long lines so the parent's
|
|
39
|
-
// `overflow-x-auto` scrolls horizontally instead of clipping.
|
|
37
|
+
// Every row fills the shared content width, including space beyond shorter lines.
|
|
40
38
|
return (
|
|
41
|
-
<div className={`flex h-[18px]
|
|
39
|
+
<div className={`flex h-[18px] w-full ${DIFF_LINE_BG[type]}`}>
|
|
42
40
|
<span className="shrink-0 w-10 text-right pr-2 select-none text-white/25 tabular-nums">
|
|
43
41
|
{lineNo ?? ''}
|
|
44
42
|
</span>
|
package/app/filesystem/README.md
CHANGED
|
@@ -11,13 +11,13 @@ Files widget package — the React surface mounted by the host as the brain-core
|
|
|
11
11
|
|
|
12
12
|
- `FilesystemWidget` — top-level component; takes `{ agentId, widgetId, state? }`. Mounted lazily by the host via `installFilesystemHostComponents`.
|
|
13
13
|
- `FilesystemHostProvider`, `useFilesystemHost`, `getFilesystemHostImperative`, `FilesystemHostValue` — the host-injection contract.
|
|
14
|
-
- `useFilesystemStore` and the `FileSystemState` shape — the Zustand store
|
|
14
|
+
- `useFilesystemStore` and the `FileSystemState` shape — the Files window's Zustand store, read through `FilesystemStoreProvider` (one store per window; see `store/README.md`).
|
|
15
15
|
- `AgentInfo`, the `domain/types` re-export, the `lib/projectFiles` and `lib/agentUtils` helpers.
|
|
16
16
|
- The `ui/` re-export bundle (14 symbols from `ui/index.ts`): `FilesystemWidget`, `FileTree`, `FileEditor`, `FileTab`, `FileMetaBar`, `CodeEditor` (CodeMirror 6 + Shiki editor), `ReviewDiffView` (`@codemirror/merge` review diff), `GitDiffView`, `GitFileDiff`, `GitCommitChangesView` (the Git Control diff surface — single-file and the multi-file stacked commit tab), `Toolbar`, `SourceTypeIcon`, `InlineUploader`, `PolicyEditor`. (`DiffView` — the old Myers review diff — was removed; the never-mounted `EditFileModal` / `UploadFileModal` were deleted 2026-09-04; the internal `EditorTabBar` / `DiffModeToggle` back `FileEditor`, and `PendingChangesPanel` is rendered by `FileEditor` rather than re-exported.)
|
|
17
17
|
|
|
18
18
|
## How it plugs into the package-system kernel
|
|
19
19
|
|
|
20
|
-
-
|
|
20
|
+
- Each window runs inside its own store (`FilesystemStoreProvider`, wired by `installFilesystemHostComponents`); every API call flows through that store's kernel `PackageApi` client — built over the window's project and bound agent — which translates calls into `/api/packages/brain-core/<route>` requests the route layer resolves to the real session.
|
|
21
21
|
- `FilesystemHostProvider` is built on top of `WorkspaceHostPort`. The adapter (`host/buildFilesystemHostValue.ts`) is the single bridge between the kernel port and the brain-core view; the widget never imports host-specific symbols.
|
|
22
22
|
- The SSE hook (`hooks/useFilesystemSSE.ts`) subscribes through `host.subscribeFilesystemEvents(agentId, projectId, …)`, which delegates to `WorkspaceHostPort.subscribeRealtime({ channel: 'filesystem', … })` — the ONE multiplexed `/api/events` hub, never a per-widget connection.
|
|
23
23
|
|
|
@@ -25,7 +25,7 @@ Files widget package — the React surface mounted by the host as the brain-core
|
|
|
25
25
|
|
|
26
26
|
- API calls are scoped by the kernel session (`projectId`, `agentId`, `userId`) — the UI cannot forge a request for another project. The brain-core route layer enforces feature grants and source scope.
|
|
27
27
|
- File marks (`useFileMarks(agentId)`) and the SSE event stream are per-agent. Cross-agent visibility requires the same feature grants enforced server-side.
|
|
28
|
-
- The store evicts COLD rows above `FILES_LRU_HARD_CAP` (never a source root, an expanded folder, its ancestors, its direct children, or an open file) so the UI cannot accumulate unbounded data even when many sources stream events — and the dock broom empties it
|
|
28
|
+
- The store evicts COLD rows above `FILES_LRU_HARD_CAP` (never a source root, an expanded folder, its ancestors, its direct children, or an open file) so the UI cannot accumulate unbounded data even when many sources stream events — the cap is PER window store, so N mounted windows hold up to N × the cap — and the dock broom empties the windows it scopes through the kernel port's `onClientStateReset`.
|
|
29
29
|
|
|
30
30
|
## Add Source — key suggestion
|
|
31
31
|
|
|
@@ -34,7 +34,7 @@ Files widget package — the React surface mounted by the host as the brain-core
|
|
|
34
34
|
|
|
35
35
|
## Pending Changes tab
|
|
36
36
|
|
|
37
|
-
`ui/PendingChangesPanel.tsx` is the **Pending Changes** view in the Files widget — a journal of revertible filesystem changes that an agent has made (the durable backend is `src/store/PendingChangeStore.ts`; the route is `pending`, see `src/routes/README.md`). It offers two genuinely distinct views: a **compact list** (filename + full folder path, no content fetch) and **diff cards** (the default — opened inline, each card loads its hunks lazily from ONE fresh `preview` (baseline + current state, the record's own fingerprint) through `hooks/useVisibleDiffCards.ts`; on a source-revision change or a virtualizer remount the card keeps its last preview on screen while the fresh one loads, and the index badge shows only for the current key's answer; `+N/−M` counts are computed from the loaded hunks when the record carries none). Records are ordered **oldest-first** so the review walks first→last. A focused-card cursor (◄/► header buttons, plus `↑`/`↓`/`←`/`→`, `a`=approve, `r`=revert, `x`=dismiss when the panel is focused) an **Approve N** (two-step confirm; only records that need no acknowledgement) button and an **M need confirmation** button make a full sweep fast — the latter opens `PendingReviewDialog`, grouped by reason, 100 records per batch; a finished batch disables its group buttons and offers **Next batch (K left)**; approving advances to the next change. Each live (non-orphaned) row also carries a neutral-tone **Dismiss** (x) button — "accept-and-stop-reviewing": the change is kept exactly as it is (a present file stays on disk + indexed, an agent's delete stays deleted) and only the review entry resolves, with no connector write (the `pending` route's `dismiss` action; see `src/routes/README.md`). Clicking a filename opens the file in the tree (never replacing the panel). A filter bar narrows by source / agent / conversation, and the conversation chip is **clearable** (the `×` resets `pendingPanelFilter`). The panel is registered as `WorkspacePanelId += 'pending'` in the store, a Toolbar button, and a `FileEditor` tab + render branch — `FileEditor`'s `showFilePane` **excludes** the pending tab so the file header / amber pending banner / file-content layer never overlay the panel (they share one flex container). The tab is gated by `drive.read` (visible to every drive user), while the *content* is filtered per record server-side (owner isolation + uri-policy on the `pending` route). The chat composer's "Open in Files" button (agent-core Changes&Actions) opens this tab scoped to a conversation; this is navigation only and is distinct from the chat approve/deny `PendingInteraction` card.
|
|
37
|
+
`ui/PendingChangesPanel.tsx` is the **Pending Changes** view in the Files widget — a journal of revertible filesystem changes that an agent has made (the durable backend is `src/store/PendingChangeStore.ts`; the route is `pending`, see `src/routes/README.md`). It offers two genuinely distinct views: a **compact list** (filename + full folder path, no content fetch) and **diff cards** (the default — opened inline, each card loads its hunks lazily from ONE fresh `preview` (baseline + current state, the record's own fingerprint) through `hooks/useVisibleDiffCards.ts`; on a source-revision change or a virtualizer remount the card keeps its last preview on screen while the fresh one loads, and the index badge shows only for the current key's answer; `+N/−M` counts are computed from the loaded hunks when the record carries none). Records are ordered **oldest-first** so the review walks first→last. A focused-card cursor (◄/► header buttons, plus `↑`/`↓`/`←`/`→`, `a`=approve, `r`=revert, `x`=dismiss when the panel is focused) an **Approve N** (two-step confirm; only records that need no acknowledgement) button and an **M need confirmation** button make a full sweep fast — the latter opens `PendingReviewDialog`, grouped by reason, 100 records per batch; a finished batch disables its group buttons and offers **Next batch (K left)**; approving advances to the next change. Each live (non-orphaned) row also carries a neutral-tone **Dismiss** (x) button — "accept-and-stop-reviewing": the change is kept exactly as it is (a present file stays on disk + indexed, an agent's delete stays deleted) and only the review entry resolves, with no connector write (the `pending` route's `dismiss` action; see `src/routes/README.md`). Clicking a filename opens the file in the tree (never replacing the panel). A filter bar narrows by source / agent / conversation, and the conversation chip is **clearable** (the `×` resets `pendingPanelFilter`). The panel is registered as `WorkspacePanelId += 'pending'` in the store, a Toolbar button, and a `FileEditor` tab + render branch — `FileEditor`'s `showFilePane` **excludes** the pending tab so the file header / amber pending banner / file-content layer never overlay the panel (they share one flex container). The tab is gated by `drive.read` (visible to every drive user), while the *content* is filtered per record server-side (owner isolation + uri-policy on the `pending` route). The chat composer's "Open in Files" button (agent-core Changes&Actions) opens this tab scoped to a conversation; this is navigation only and is distinct from the chat approve/deny `PendingInteraction` card. A notification row opens the widget through the same one-shot `applyNav`: `open-pending` (the pending summary), `open-sources` (a source's sync/embedding outcome) and `open-vector-health` (an operator's collection action) — navigation only, every gate re-applied by the panel's own reads.
|
|
38
38
|
|
|
39
39
|
## Open-to-file tree hydration
|
|
40
40
|
|
|
@@ -4,7 +4,7 @@ Typed client for brain-core package routes plus a small set of host-side helpers
|
|
|
4
4
|
|
|
5
5
|
## Responsibility
|
|
6
6
|
|
|
7
|
-
- Wrap
|
|
7
|
+
- Wrap a kernel `PackageApi` into typed functions that mirror every brain-core route; each takes that client as its LAST argument.
|
|
8
8
|
- Build raw-file URLs (`getRawFileUrl`) for the `<img>` / `<video>` preview elements. **Not for an iframe or any other document embed** — the byte lane serves the executable document class (SVG, HTML, XML) as `content-disposition: attachment`, so a document embed against it renders nothing, and making it render again would re-open a stored-XSS path. There is exactly one call site today (`FileEditor`).
|
|
9
9
|
- Provide the host-side helpers (`projectPackages.ts`) used by the Packages tab — these talk to the host's `/api/packages/runtime` and `/api/projects/:id/packages/:slug/{build,trust}` routes, NOT to brain-core.
|
|
10
10
|
|
|
@@ -18,7 +18,7 @@ Typed client for brain-core package routes plus a small set of host-side helpers
|
|
|
18
18
|
|
|
19
19
|
## How it plugs into the package-system kernel
|
|
20
20
|
|
|
21
|
-
-
|
|
21
|
+
- A Files window passes the client its store was created with — `createPackageApi` over the window's project and BOUND agent — so the X-Project-Id / X-Agent-Id headers are the window's own, fixed before any await, whatever other window is mounted beside it; a body may still name another agent (a file read through its writing agent). `readFiles` alone also runs without a client, for the chat change card, which is not a Files window and resolves the first registered `brain-core` provider.
|
|
22
22
|
- The `PackageApi` provided by `@neuralis/package-system/client` translates `.get(path, qs)`, `.post(path, body)`, `.patch`, `.del`, `.upload` into authenticated requests against `/api/packages/brain-core/<path>` with the active session attached by the host.
|
|
23
23
|
- Project-package helpers go directly to host routes (`/api/packages/runtime`, `/api/projects/:id/packages/:slug/build`, `/.../trust`) — these are NOT package routes and are not part of the brain-core surface; the helpers live here only because the Files widget's Packages tab consumes them.
|
|
24
24
|
|
|
@@ -34,4 +34,4 @@ Typed client for brain-core package routes plus a small set of host-side helpers
|
|
|
34
34
|
|
|
35
35
|
## Tests
|
|
36
36
|
|
|
37
|
-
Indirect coverage through the route tests under `test/routes/`.
|
|
37
|
+
Indirect coverage through the route tests under `test/routes/`. `test/ui/gitApi.repo.test.ts` and `test/ui/searchApi.wire.test.ts` pass a mocked `PackageApi` as the client and pin the wire shape; `test/store/filesWindows.test.ts` pins that each window's requests carry its own client and headers.
|