@andespindola/brainlink 0.1.0-beta.13 → 0.1.0-beta.15
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/AGENTS.md +5 -5
- package/CHANGELOG.md +2 -2
- package/CONTRIBUTING.md +2 -2
- package/README.md +13 -14
- package/SECURITY.md +1 -1
- package/dist/application/analyze-vault.js +1 -15
- package/dist/application/get-graph-layout.js +2 -2
- package/dist/application/get-graph-node.js +3 -3
- package/dist/application/get-graph-summary.js +3 -3
- package/dist/application/get-graph.js +3 -3
- package/dist/application/index-vault.js +5 -5
- package/dist/application/list-agents.js +3 -3
- package/dist/application/list-links.js +5 -5
- package/dist/application/search-graph-node-ids.js +3 -3
- package/dist/application/search-knowledge.js +6 -6
- package/dist/benchmarks/large-vault.js +1 -1
- package/dist/infrastructure/file-index.js +291 -0
- package/dist/infrastructure/search-packs.js +31 -6
- package/docs/AGENT_USAGE.md +14 -15
- package/docs/ARCHITECTURE.md +19 -27
- package/package.json +1 -3
- package/dist/infrastructure/sqlite/document-writer.js +0 -51
- package/dist/infrastructure/sqlite/graph-reader.js +0 -267
- package/dist/infrastructure/sqlite/recovery.js +0 -163
- package/dist/infrastructure/sqlite/schema.js +0 -114
- package/dist/infrastructure/sqlite/search-reader.js +0 -188
- package/dist/infrastructure/sqlite/types.js +0 -1
- package/dist/infrastructure/sqlite-index.js +0 -38
package/AGENTS.md
CHANGED
|
@@ -6,19 +6,19 @@ This file tells coding agents and AI assistants how to use this repository.
|
|
|
6
6
|
|
|
7
7
|
Brainlink is a local-first knowledge memory for agents.
|
|
8
8
|
|
|
9
|
-
It reads a Markdown vault, extracts `[[wiki links]]` and `#tags`, builds a local
|
|
9
|
+
It reads a Markdown vault, extracts `[[wiki links]]` and `#tags`, builds a local file index at `.brainlink/index.json`, and returns compact context packages that agents can inject into prompts.
|
|
10
10
|
|
|
11
11
|
## Source Of Truth
|
|
12
12
|
|
|
13
13
|
Markdown files are the source of truth.
|
|
14
14
|
|
|
15
|
-
The
|
|
15
|
+
The JSON index at `.brainlink/index.json` is derived. It can be deleted and rebuilt with:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
18
|
npm run dev -- index --vault ./vault
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
Do not store permanent knowledge only in
|
|
21
|
+
Do not store permanent knowledge only in index artifacts.
|
|
22
22
|
|
|
23
23
|
By default, the installed Brainlink CLI uses `$HOME/.brainlink/vault` as its vault. Passing `--vault` or setting `vault` in `brainlink.config.json` intentionally selects a custom vault such as `./vault`.
|
|
24
24
|
|
|
@@ -107,10 +107,10 @@ npm run dev -- doctor --vault ./vault
|
|
|
107
107
|
|
|
108
108
|
- Keep domain rules in `src/domain`.
|
|
109
109
|
- Keep use cases in `src/application`.
|
|
110
|
-
- Keep filesystem and
|
|
110
|
+
- Keep filesystem and index details in `src/infrastructure`.
|
|
111
111
|
- Keep CLI concerns in `src/cli`.
|
|
112
112
|
- Prefer pure functions for parsing, ranking, formatting, and transformation.
|
|
113
|
-
- Do not make
|
|
113
|
+
- Do not make index artifacts the canonical storage layer.
|
|
114
114
|
- Do not add comments with emojis.
|
|
115
115
|
- Keep JSON output backwards compatible where possible.
|
|
116
116
|
|
package/CHANGELOG.md
CHANGED
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
## 0.1.0-alpha.0
|
|
50
50
|
|
|
51
51
|
- Added local-first Markdown vault indexing.
|
|
52
|
-
- Added
|
|
53
|
-
- Added
|
|
52
|
+
- Added local full-text indexing, local semantic retrieval, wiki links, backlinks and graph retrieval.
|
|
53
|
+
- Added semantic candidate bucket indexing to narrow vector candidates for larger vaults.
|
|
54
54
|
- Optimized title/link resolution with precomputed agent-scoped title maps.
|
|
55
55
|
- Added CLI, JSON output, HTTP API and graph UI.
|
|
56
56
|
- Added vault diagnostics: stats, broken links, orphans, validation and doctor.
|
package/CONTRIBUTING.md
CHANGED
|
@@ -22,7 +22,7 @@ npm run pack:smoke
|
|
|
22
22
|
## Design Rules
|
|
23
23
|
|
|
24
24
|
- Markdown files are the source of truth.
|
|
25
|
-
-
|
|
25
|
+
- Local index artifacts are derived and must remain rebuildable.
|
|
26
26
|
- Domain parsing, graph analysis and layout should stay pure and testable.
|
|
27
|
-
- CLI, HTTP, filesystem and
|
|
27
|
+
- CLI, HTTP, filesystem and index code are adapters around application use cases.
|
|
28
28
|
- MCP integration should live outside this package by wrapping the CLI with `--json`.
|
package/README.md
CHANGED
|
@@ -52,14 +52,14 @@ LLMs do not have infinite context. Brainlink gives agents an external memory lay
|
|
|
52
52
|
1. Durable knowledge is written as Markdown.
|
|
53
53
|
2. Notes are connected with `[[wiki links]]`.
|
|
54
54
|
3. Concepts are classified with `#tags`.
|
|
55
|
-
4. Brainlink builds a local
|
|
55
|
+
4. Brainlink builds a local JSON index (`.brainlink/index.json`) and private encrypted search packs.
|
|
56
56
|
5. Agents query the index before responding.
|
|
57
57
|
6. Brainlink returns compact, source-backed context.
|
|
58
58
|
|
|
59
|
-
Markdown is the source of truth. `.brainlink/
|
|
60
|
-
|
|
61
|
-
After each index run, Brainlink also writes private encrypted search packs at `.brainlink/search-packs/*.blpk`. If SQLite is unavailable, search falls back to these packs automatically.
|
|
59
|
+
Markdown is the source of truth. `.brainlink/index.json` is a rebuildable index artifact.
|
|
60
|
+
After each index run, Brainlink also writes private encrypted search packs at `.brainlink/search-packs/*.blpk` to preserve fast retrieval and portable recovery.
|
|
62
61
|
Pack decryption uses a Brainlink key from `$BRAINLINK_HOME/keys` or from `BRAINLINK_SEARCH_PACK_KEY` when explicitly configured.
|
|
62
|
+
Legacy `.jsonl.gz` packs are upgraded to `.blpk` automatically on first search/context access.
|
|
63
63
|
|
|
64
64
|
## Features
|
|
65
65
|
|
|
@@ -68,7 +68,7 @@ Pack decryption uses a Brainlink key from `$BRAINLINK_HOME/keys` or from `BRAINL
|
|
|
68
68
|
- Weighted graph edges so agents can rank relationship importance and priority.
|
|
69
69
|
- Backlinks, broken-link reports, orphan detection and validation.
|
|
70
70
|
- Full-text, semantic and hybrid retrieval modes.
|
|
71
|
-
-
|
|
71
|
+
- Full-text, semantic and hybrid retrieval on a local file index.
|
|
72
72
|
- Agent namespaces under `agents/<agent-id>/`.
|
|
73
73
|
- S3-compatible bucket vaults through `s3://bucket/prefix` URIs.
|
|
74
74
|
- CLI with machine-readable `--json` output.
|
|
@@ -285,7 +285,7 @@ export BRAINLINK_S3_FORCE_PATH_STYLE=1
|
|
|
285
285
|
|
|
286
286
|
Bucket vaults mirror Markdown into a local cache under
|
|
287
287
|
`$BRAINLINK_HOME/bucket-cache`. The bucket remains canonical; the local
|
|
288
|
-
`.brainlink/
|
|
288
|
+
`.brainlink/index.json` stays a disposable index artifact. Run `index` after remote
|
|
289
289
|
bucket changes before relying on `search`, `context`, graph or validation
|
|
290
290
|
commands. Watch mode is only supported for local filesystem vaults.
|
|
291
291
|
|
|
@@ -301,7 +301,7 @@ vault/
|
|
|
301
301
|
research-agent/
|
|
302
302
|
source-review-policy.md
|
|
303
303
|
.brainlink/
|
|
304
|
-
|
|
304
|
+
index.json
|
|
305
305
|
```
|
|
306
306
|
|
|
307
307
|
Permanent data:
|
|
@@ -311,7 +311,7 @@ Permanent data:
|
|
|
311
311
|
|
|
312
312
|
Rebuildable data:
|
|
313
313
|
|
|
314
|
-
- `.brainlink/
|
|
314
|
+
- `.brainlink/index.json`
|
|
315
315
|
- full-text records
|
|
316
316
|
- local embedding vectors
|
|
317
317
|
- local embedding buckets
|
|
@@ -723,8 +723,8 @@ If `--mode` or `--limit` is omitted, Brainlink resolves values from the current
|
|
|
723
723
|
|
|
724
724
|
Modes:
|
|
725
725
|
|
|
726
|
-
- `hybrid`: default; combines
|
|
727
|
-
- `fts`: exact lexical retrieval
|
|
726
|
+
- `hybrid`: default; combines lexical matching with local embedding similarity.
|
|
727
|
+
- `fts`: exact lexical retrieval from the file index.
|
|
728
728
|
- `semantic`: local deterministic embedding similarity only.
|
|
729
729
|
|
|
730
730
|
Hybrid results are cached in-memory for a short TTL and invalidated automatically when the local index file changes.
|
|
@@ -976,7 +976,7 @@ src/
|
|
|
976
976
|
application/ use cases
|
|
977
977
|
cli/ command-line adapter
|
|
978
978
|
domain/ pure knowledge rules
|
|
979
|
-
infrastructure/ filesystem and
|
|
979
|
+
infrastructure/ filesystem and index adapters
|
|
980
980
|
```
|
|
981
981
|
|
|
982
982
|
Detailed notes:
|
|
@@ -988,7 +988,6 @@ Detailed notes:
|
|
|
988
988
|
## Current Limits
|
|
989
989
|
|
|
990
990
|
- Semantic search uses deterministic local embeddings, not a remote model provider.
|
|
991
|
-
- Semantic search uses SQLite embedding buckets to narrow candidates before cosine scoring.
|
|
992
991
|
- `embeddingProvider` currently supports `local` and `none`.
|
|
993
992
|
- Link resolution is title-based inside each agent namespace, with `shared` as fallback.
|
|
994
993
|
- HTTP API is local and unauthenticated.
|
|
@@ -999,7 +998,7 @@ Detailed notes:
|
|
|
999
998
|
The `0.1.0-beta` line is intended to stabilize the local-first memory loop:
|
|
1000
999
|
|
|
1001
1000
|
- Markdown as durable memory.
|
|
1002
|
-
-
|
|
1001
|
+
- Rebuildable file index plus local embeddings and encrypted pack exports.
|
|
1003
1002
|
- CLI as the primary agent interface.
|
|
1004
1003
|
- HTTP graph API and frontend as inspection tools.
|
|
1005
1004
|
- Agent namespaces to avoid context mixing.
|
|
@@ -1015,7 +1014,7 @@ Brainlink is local-first by default.
|
|
|
1015
1014
|
- Brainlink HTTP is localhost-only and refuses non-loopback hosts.
|
|
1016
1015
|
- Brainlink blocks common secret patterns by default when adding notes. Use `--allow-sensitive` only for intentional, protected vaults.
|
|
1017
1016
|
- Do not store secrets, credentials, API keys or regulated personal data unless the vault is protected by your own storage controls.
|
|
1018
|
-
- Treat `.brainlink/
|
|
1017
|
+
- Treat `.brainlink/index.json` and `.brainlink/search-packs/` as disposable derived artifacts.
|
|
1019
1018
|
|
|
1020
1019
|
See [SECURITY.md](SECURITY.md).
|
|
1021
1020
|
|
package/SECURITY.md
CHANGED
|
@@ -7,7 +7,7 @@ Brainlink is local-first.
|
|
|
7
7
|
- The HTTP server binds to `127.0.0.1` by default.
|
|
8
8
|
- The HTTP server always refuses non-loopback hosts.
|
|
9
9
|
- The HTTP server is read-only and does not expose note creation, indexing or update routes.
|
|
10
|
-
-
|
|
10
|
+
- Local index artifacts (`.brainlink/index.json` and `.brainlink/search-packs/`) are derived data.
|
|
11
11
|
- Markdown files are user-owned source data.
|
|
12
12
|
- Brainlink-created Markdown files use `0600` permissions.
|
|
13
13
|
- Brainlink-created directories and `.brainlink` use `0700` permissions.
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { stat } from 'node:fs/promises';
|
|
2
|
-
import { existsSync, readdirSync } from 'node:fs';
|
|
3
2
|
import { performance } from 'node:perf_hooks';
|
|
4
|
-
import { join } from 'node:path';
|
|
5
3
|
import { validateGraph, getBrokenLinks, getOrphanNodes, getVaultStats } from '../domain/graph-analysis.js';
|
|
6
4
|
import { ensureVault, listVaultFiles, readMarkdownFiles } from '../infrastructure/file-system-vault.js';
|
|
7
5
|
import { resolveAgentRuntimeDefaults } from '../infrastructure/config.js';
|
|
@@ -96,23 +94,11 @@ export const doctorVault = async (vaultPath) => {
|
|
|
96
94
|
const files = await readMarkdownFiles(absoluteVaultPath);
|
|
97
95
|
const graph = await getGraphSummary(absoluteVaultPath);
|
|
98
96
|
const validation = validateGraph(graph);
|
|
99
|
-
const backupPath = join(absoluteVaultPath, '.brainlink', 'brainlink.db.backup');
|
|
100
|
-
const snapshotDirectory = join(absoluteVaultPath, '.brainlink', 'brainlink.db.backup.snapshots');
|
|
101
|
-
const hasBackup = existsSync(backupPath);
|
|
102
|
-
const snapshotCount = existsSync(snapshotDirectory)
|
|
103
|
-
? readdirSync(snapshotDirectory).filter((name) => name.endsWith('.db')).length
|
|
104
|
-
: 0;
|
|
105
|
-
const backupReady = graph.nodes.length === 0 || hasBackup;
|
|
106
97
|
const checks = [
|
|
107
98
|
createCheck('vault', true, `Vault ready at ${absoluteVaultPath}`),
|
|
108
99
|
createCheck('markdown-files', files.length > 0, `${files.length} markdown files found`),
|
|
109
100
|
createCheck('index', graph.nodes.length > 0, `${graph.nodes.length} indexed documents found`),
|
|
110
|
-
createCheck('broken-links', validation.brokenLinks.length === 0, `${validation.brokenLinks.length} broken links found`)
|
|
111
|
-
createCheck('index-backup', backupReady, backupReady
|
|
112
|
-
? (hasBackup
|
|
113
|
-
? `SQLite recovery snapshot is available (${snapshotCount} rotating snapshots)`
|
|
114
|
-
: 'No index yet. Snapshot will be created after first indexing run')
|
|
115
|
-
: 'Recovery snapshot missing. Run blink index to create a rollback snapshot')
|
|
101
|
+
createCheck('broken-links', validation.brokenLinks.length === 0, `${validation.brokenLinks.length} broken links found`)
|
|
116
102
|
];
|
|
117
103
|
const recommendations = files.length === 0 && graph.nodes.length === 0
|
|
118
104
|
? [
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { stat } from 'node:fs/promises';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
3
|
import { createCauliflowerGraphLayout } from '../domain/graph-layout.js';
|
|
4
|
+
import { indexStoragePath } from '../infrastructure/file-index.js';
|
|
5
5
|
import { getGraphSummary } from './get-graph-summary.js';
|
|
6
6
|
const graphLayoutCache = new Map();
|
|
7
7
|
const readDatabaseSignature = async (vaultPath) => {
|
|
8
8
|
try {
|
|
9
|
-
const info = await stat(
|
|
9
|
+
const info = await stat(indexStoragePath(vaultPath));
|
|
10
10
|
return `${Math.floor(info.mtimeMs)}:${info.size}`;
|
|
11
11
|
}
|
|
12
12
|
catch {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ensureVault } from '../infrastructure/file-system-vault.js';
|
|
2
|
-
import {
|
|
2
|
+
import { openFileIndex } from '../infrastructure/file-index.js';
|
|
3
3
|
export const getGraphNode = async (vaultPath, id, agentId) => {
|
|
4
4
|
const absoluteVaultPath = await ensureVault(vaultPath);
|
|
5
|
-
const index =
|
|
5
|
+
const index = openFileIndex(absoluteVaultPath);
|
|
6
6
|
try {
|
|
7
|
-
return index.getGraphNode(id, agentId);
|
|
7
|
+
return await index.getGraphNode(id, agentId);
|
|
8
8
|
}
|
|
9
9
|
finally {
|
|
10
10
|
index.close();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ensureVault } from '../infrastructure/file-system-vault.js';
|
|
2
|
-
import {
|
|
2
|
+
import { openFileIndex } from '../infrastructure/file-index.js';
|
|
3
3
|
export const getGraphSummary = async (vaultPath, agentId) => {
|
|
4
4
|
const absoluteVaultPath = await ensureVault(vaultPath);
|
|
5
|
-
const index =
|
|
5
|
+
const index = openFileIndex(absoluteVaultPath);
|
|
6
6
|
try {
|
|
7
|
-
return index.getGraphSummary(agentId);
|
|
7
|
+
return await index.getGraphSummary(agentId);
|
|
8
8
|
}
|
|
9
9
|
finally {
|
|
10
10
|
index.close();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ensureVault } from '../infrastructure/file-system-vault.js';
|
|
2
|
-
import {
|
|
2
|
+
import { openFileIndex } from '../infrastructure/file-index.js';
|
|
3
3
|
export const getGraph = async (vaultPath, agentId) => {
|
|
4
4
|
const absoluteVaultPath = await ensureVault(vaultPath);
|
|
5
|
-
const index =
|
|
5
|
+
const index = openFileIndex(absoluteVaultPath);
|
|
6
6
|
try {
|
|
7
|
-
return index.getGraph(agentId);
|
|
7
|
+
return await index.getGraph(agentId);
|
|
8
8
|
}
|
|
9
9
|
finally {
|
|
10
10
|
index.close();
|
|
@@ -4,7 +4,7 @@ import { createEmbeddingProvider } from '../domain/embeddings.js';
|
|
|
4
4
|
import { loadBrainlinkConfig } from '../infrastructure/config.js';
|
|
5
5
|
import { ensureVault, readMarkdownFiles } from '../infrastructure/file-system-vault.js';
|
|
6
6
|
import { buildSearchPacks } from '../infrastructure/search-packs.js';
|
|
7
|
-
import {
|
|
7
|
+
import { openFileIndex } from '../infrastructure/file-index.js';
|
|
8
8
|
const toTitleKey = (title) => title.toLowerCase();
|
|
9
9
|
const appendTitleEntry = (map, document) => {
|
|
10
10
|
const key = toTitleKey(document.title);
|
|
@@ -60,15 +60,15 @@ export const indexVault = async (vaultPath) => {
|
|
|
60
60
|
}));
|
|
61
61
|
const titleMaps = createTitleMaps(documents);
|
|
62
62
|
const indexedDocuments = await embedIndexedDocuments(documents.map((document) => createIndexedDocument(document, createScopedTitleResolver(document, titleMaps), config.chunkSize)), config.embeddingProvider);
|
|
63
|
-
const index =
|
|
63
|
+
const index = openFileIndex(absoluteVaultPath);
|
|
64
64
|
try {
|
|
65
|
-
index.reset();
|
|
66
|
-
index.saveDocuments(indexedDocuments);
|
|
65
|
+
await index.reset();
|
|
66
|
+
await index.saveDocuments(indexedDocuments);
|
|
67
67
|
try {
|
|
68
68
|
await buildSearchPacks(absoluteVaultPath, indexedDocuments);
|
|
69
69
|
}
|
|
70
70
|
catch {
|
|
71
|
-
// Pack generation is best-effort.
|
|
71
|
+
// Pack generation is best-effort. The JSON index remains the primary path.
|
|
72
72
|
}
|
|
73
73
|
return {
|
|
74
74
|
documentCount: indexedDocuments.length,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ensureVault } from '../infrastructure/file-system-vault.js';
|
|
2
|
-
import {
|
|
2
|
+
import { openFileIndex } from '../infrastructure/file-index.js';
|
|
3
3
|
export const listAgents = async (vaultPath) => {
|
|
4
4
|
const absoluteVaultPath = await ensureVault(vaultPath);
|
|
5
|
-
const index =
|
|
5
|
+
const index = openFileIndex(absoluteVaultPath);
|
|
6
6
|
try {
|
|
7
|
-
return index.listAgents();
|
|
7
|
+
return await index.listAgents();
|
|
8
8
|
}
|
|
9
9
|
finally {
|
|
10
10
|
index.close();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ensureVault } from '../infrastructure/file-system-vault.js';
|
|
2
|
-
import {
|
|
2
|
+
import { openFileIndex } from '../infrastructure/file-index.js';
|
|
3
3
|
export const listLinks = async (vaultPath, agentId) => {
|
|
4
4
|
const absoluteVaultPath = await ensureVault(vaultPath);
|
|
5
|
-
const index =
|
|
5
|
+
const index = openFileIndex(absoluteVaultPath);
|
|
6
6
|
try {
|
|
7
|
-
return index.listLinks(agentId);
|
|
7
|
+
return await index.listLinks(agentId);
|
|
8
8
|
}
|
|
9
9
|
finally {
|
|
10
10
|
index.close();
|
|
@@ -12,9 +12,9 @@ export const listLinks = async (vaultPath, agentId) => {
|
|
|
12
12
|
};
|
|
13
13
|
export const listBacklinks = async (vaultPath, title, agentId) => {
|
|
14
14
|
const absoluteVaultPath = await ensureVault(vaultPath);
|
|
15
|
-
const index =
|
|
15
|
+
const index = openFileIndex(absoluteVaultPath);
|
|
16
16
|
try {
|
|
17
|
-
return index.listBacklinks(title, agentId);
|
|
17
|
+
return await index.listBacklinks(title, agentId);
|
|
18
18
|
}
|
|
19
19
|
finally {
|
|
20
20
|
index.close();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ensureVault } from '../infrastructure/file-system-vault.js';
|
|
2
|
-
import {
|
|
2
|
+
import { openFileIndex } from '../infrastructure/file-index.js';
|
|
3
3
|
export const searchGraphNodeIds = async (vaultPath, query, limit, agentId) => {
|
|
4
4
|
const absoluteVaultPath = await ensureVault(vaultPath);
|
|
5
|
-
const index =
|
|
5
|
+
const index = openFileIndex(absoluteVaultPath);
|
|
6
6
|
try {
|
|
7
|
-
return index.searchGraphNodeIds(query, limit, agentId);
|
|
7
|
+
return await index.searchGraphNodeIds(query, limit, agentId);
|
|
8
8
|
}
|
|
9
9
|
finally {
|
|
10
10
|
index.close();
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { stat } from 'node:fs/promises';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
2
|
import { ensureVault } from '../infrastructure/file-system-vault.js';
|
|
4
|
-
import { searchInPacks } from '../infrastructure/search-packs.js';
|
|
5
|
-
import {
|
|
3
|
+
import { ensurePrivatePacksFromLegacyIndex, searchInPacks } from '../infrastructure/search-packs.js';
|
|
4
|
+
import { indexStoragePath, openFileIndex } from '../infrastructure/file-index.js';
|
|
6
5
|
import { createEmbeddingProvider } from '../domain/embeddings.js';
|
|
7
6
|
import { loadBrainlinkConfig, sanitizeSearchMode } from '../infrastructure/config.js';
|
|
8
7
|
const hybridCacheTtlMs = 30_000;
|
|
@@ -10,7 +9,7 @@ const hybridCacheMaxEntries = 200;
|
|
|
10
9
|
const hybridSearchCache = new Map();
|
|
11
10
|
const readIndexMtimeMs = async (vaultPath) => {
|
|
12
11
|
try {
|
|
13
|
-
return (await stat(
|
|
12
|
+
return (await stat(indexStoragePath(vaultPath))).mtimeMs;
|
|
14
13
|
}
|
|
15
14
|
catch {
|
|
16
15
|
return 0;
|
|
@@ -47,6 +46,7 @@ export const searchKnowledge = async (vaultPath, query, limit, agentId, mode) =>
|
|
|
47
46
|
const absoluteVaultPath = await ensureVault(vaultPath);
|
|
48
47
|
const config = await loadBrainlinkConfig();
|
|
49
48
|
const searchMode = sanitizeSearchMode(mode, config.defaultSearchMode);
|
|
49
|
+
await ensurePrivatePacksFromLegacyIndex(absoluteVaultPath);
|
|
50
50
|
const cacheKey = searchMode === 'hybrid' ? toCacheKey(absoluteVaultPath, query, limit, agentId) : undefined;
|
|
51
51
|
const indexMtimeMs = cacheKey ? await readIndexMtimeMs(absoluteVaultPath) : 0;
|
|
52
52
|
const cached = cacheKey ? cacheGet(cacheKey, indexMtimeMs) : undefined;
|
|
@@ -57,9 +57,9 @@ export const searchKnowledge = async (vaultPath, query, limit, agentId, mode) =>
|
|
|
57
57
|
const shouldEmbedQuery = searchMode !== 'fts' && provider.name !== 'none';
|
|
58
58
|
const queryEmbedding = shouldEmbedQuery ? (await provider.embed([query]))[0] ?? [] : [];
|
|
59
59
|
try {
|
|
60
|
-
const index =
|
|
60
|
+
const index = openFileIndex(absoluteVaultPath);
|
|
61
61
|
try {
|
|
62
|
-
const results = index.search(query, limit, agentId, searchMode, queryEmbedding);
|
|
62
|
+
const results = await index.search(query, limit, agentId, searchMode, queryEmbedding);
|
|
63
63
|
if (cacheKey) {
|
|
64
64
|
cacheSet({
|
|
65
65
|
key: cacheKey,
|
|
@@ -21,7 +21,7 @@ const readOptions = (args) => ({
|
|
|
21
21
|
});
|
|
22
22
|
const topics = [
|
|
23
23
|
'authentication jwt token refresh policy',
|
|
24
|
-
'
|
|
24
|
+
'graph backlinks markdown vault indexing',
|
|
25
25
|
'frontend canvas layout graph interaction',
|
|
26
26
|
'agent memory context retrieval summarization',
|
|
27
27
|
'security local server vault path allowlist',
|