brain-cache 0.3.1 → 0.3.3
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/dist/{askCodebase-GXUB6477.js → askCodebase-OAAG35G5.js} +3 -3
- package/dist/{buildContext-AHUWIN6M.js → buildContext-QIMH5LQY.js} +3 -3
- package/dist/{chunk-MSI4MDIM.js → chunk-DDDLTKDT.js} +2 -1
- package/dist/{chunk-6MACVOTO.js → chunk-DTJNPRN6.js} +1 -1
- package/dist/{chunk-H4XSGUHL.js → chunk-QNPB2UD2.js} +4 -14
- package/dist/cli.js +8 -8
- package/dist/{doctor-3RIVSSNB.js → doctor-DRVKTWPW.js} +1 -1
- package/dist/{init-SXC4MWOR.js → init-ILR3VJNO.js} +1 -1
- package/dist/mcp.js +12 -14
- package/dist/{search-ZP4NKKAZ.js → search-RGK2FEM5.js} +2 -2
- package/dist/{status-JYNMLSXZ.js → status-4IWQTGPA.js} +2 -2
- package/dist/{workflows-TWA2GDHJ.js → workflows-SYWKVVOK.js} +10 -4
- package/package.json +2 -1
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
} from "./chunk-GGOUKACO.js";
|
|
5
5
|
import {
|
|
6
6
|
runBuildContext
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QNPB2UD2.js";
|
|
8
8
|
import "./chunk-5FXXZBZV.js";
|
|
9
9
|
import "./chunk-BF5UDEIF.js";
|
|
10
10
|
import "./chunk-GR6QXZ4J.js";
|
|
11
11
|
import "./chunk-V4ARVFRG.js";
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
import "./chunk-DTJNPRN6.js";
|
|
13
|
+
import "./chunk-DDDLTKDT.js";
|
|
14
14
|
import {
|
|
15
15
|
childLogger
|
|
16
16
|
} from "./chunk-3SFDFUEX.js";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runBuildContext
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QNPB2UD2.js";
|
|
5
5
|
import "./chunk-5FXXZBZV.js";
|
|
6
6
|
import "./chunk-BF5UDEIF.js";
|
|
7
7
|
import "./chunk-GR6QXZ4J.js";
|
|
8
8
|
import "./chunk-V4ARVFRG.js";
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-DTJNPRN6.js";
|
|
10
|
+
import "./chunk-DDDLTKDT.js";
|
|
11
11
|
import "./chunk-3SFDFUEX.js";
|
|
12
12
|
export {
|
|
13
13
|
runBuildContext
|
|
@@ -38,7 +38,8 @@ var IndexStateSchema = z.object({
|
|
|
38
38
|
dimension: z.number().int(),
|
|
39
39
|
indexedAt: z.string().datetime(),
|
|
40
40
|
fileCount: z.number().int(),
|
|
41
|
-
chunkCount: z.number().int()
|
|
41
|
+
chunkCount: z.number().int(),
|
|
42
|
+
totalTokens: z.number().int().default(0)
|
|
42
43
|
});
|
|
43
44
|
|
|
44
45
|
// src/services/capability.ts
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
assembleContext
|
|
4
|
-
countChunkTokens
|
|
3
|
+
assembleContext
|
|
5
4
|
} from "./chunk-5FXXZBZV.js";
|
|
6
5
|
import {
|
|
7
6
|
RETRIEVAL_STRATEGIES,
|
|
@@ -18,16 +17,15 @@ import {
|
|
|
18
17
|
import {
|
|
19
18
|
openDatabase,
|
|
20
19
|
readIndexState
|
|
21
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-DTJNPRN6.js";
|
|
22
21
|
import {
|
|
23
22
|
readProfile
|
|
24
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-DDDLTKDT.js";
|
|
25
24
|
import {
|
|
26
25
|
DEFAULT_TOKEN_BUDGET
|
|
27
26
|
} from "./chunk-3SFDFUEX.js";
|
|
28
27
|
|
|
29
28
|
// src/workflows/buildContext.ts
|
|
30
|
-
import { readFile } from "fs/promises";
|
|
31
29
|
import { resolve } from "path";
|
|
32
30
|
async function runBuildContext(query, opts) {
|
|
33
31
|
const profile = await readProfile();
|
|
@@ -64,15 +62,7 @@ async function runBuildContext(query, opts) {
|
|
|
64
62
|
const results = await searchChunks(table, queryVector, strategy);
|
|
65
63
|
const deduped = deduplicateChunks(results);
|
|
66
64
|
const assembled = assembleContext(deduped, { maxTokens });
|
|
67
|
-
const
|
|
68
|
-
let estimatedWithoutBraincache = 0;
|
|
69
|
-
for (const filePath of uniqueFiles) {
|
|
70
|
-
try {
|
|
71
|
-
const fileContent = await readFile(filePath, "utf-8");
|
|
72
|
-
estimatedWithoutBraincache += countChunkTokens(fileContent);
|
|
73
|
-
} catch {
|
|
74
|
-
}
|
|
75
|
-
}
|
|
65
|
+
const estimatedWithoutBraincache = indexState.totalTokens;
|
|
76
66
|
const reductionPct = estimatedWithoutBraincache > 0 ? Math.round((1 - assembled.tokenCount / estimatedWithoutBraincache) * 100) : 0;
|
|
77
67
|
const result = {
|
|
78
68
|
content: assembled.content,
|
package/dist/cli.js
CHANGED
|
@@ -5,23 +5,23 @@ import {
|
|
|
5
5
|
|
|
6
6
|
// src/cli/index.ts
|
|
7
7
|
import { Command } from "commander";
|
|
8
|
-
var version = "0.3.
|
|
8
|
+
var version = "0.3.3";
|
|
9
9
|
var program = new Command();
|
|
10
10
|
program.name("brain-cache").description("Local AI runtime \u2014 GPU cache layer for Claude").version(version);
|
|
11
11
|
program.command("init").description("Detect hardware, pull embedding model, create config directory").action(async () => {
|
|
12
|
-
const { runInit } = await import("./init-
|
|
12
|
+
const { runInit } = await import("./init-ILR3VJNO.js");
|
|
13
13
|
await runInit();
|
|
14
14
|
});
|
|
15
15
|
program.command("doctor").description("Report system health: GPU, VRAM tier, Ollama status").action(async () => {
|
|
16
|
-
const { runDoctor } = await import("./doctor-
|
|
16
|
+
const { runDoctor } = await import("./doctor-DRVKTWPW.js");
|
|
17
17
|
await runDoctor();
|
|
18
18
|
});
|
|
19
19
|
program.command("index").description("Index a codebase: parse, chunk, embed, and store in LanceDB").argument("[path]", "Directory to index (defaults to current directory)").option("-f, --force", "Force full reindex, ignoring cached file hashes").action(async (path, opts) => {
|
|
20
|
-
const { runIndex } = await import("./workflows-
|
|
20
|
+
const { runIndex } = await import("./workflows-SYWKVVOK.js");
|
|
21
21
|
await runIndex(path, { force: opts.force });
|
|
22
22
|
});
|
|
23
23
|
program.command("search").description("Search indexed codebase with a natural language query").argument("<query>", "Natural language query string").option("-n, --limit <n>", "Maximum number of results", "10").option("-p, --path <path>", "Project root directory").action(async (query, opts) => {
|
|
24
|
-
const { runSearch } = await import("./search-
|
|
24
|
+
const { runSearch } = await import("./search-RGK2FEM5.js");
|
|
25
25
|
await runSearch(query, {
|
|
26
26
|
limit: parseInt(opts.limit, 10),
|
|
27
27
|
path: opts.path
|
|
@@ -30,12 +30,12 @@ program.command("search").description("Search indexed codebase with a natural la
|
|
|
30
30
|
program.command("status").description(
|
|
31
31
|
"Show index stats: files indexed, chunks stored, last indexed time"
|
|
32
32
|
).argument("[path]", "Project root directory (defaults to current directory)").action(async (path) => {
|
|
33
|
-
const { runStatus } = await import("./status-
|
|
33
|
+
const { runStatus } = await import("./status-4IWQTGPA.js");
|
|
34
34
|
await runStatus(path);
|
|
35
35
|
});
|
|
36
36
|
program.command("context").description("Build token-budgeted context from codebase for a query").argument("<query>", "Natural language query string").option("-n, --limit <n>", "Maximum number of search results", "10").option("-b, --budget <tokens>", "Token budget for assembled context", "4096").option("-p, --path <path>", "Project root directory").option("--raw", "Output raw JSON (MCP transport compatible)").action(
|
|
37
37
|
async (query, opts) => {
|
|
38
|
-
const { runBuildContext } = await import("./buildContext-
|
|
38
|
+
const { runBuildContext } = await import("./buildContext-QIMH5LQY.js");
|
|
39
39
|
const result = await runBuildContext(query, {
|
|
40
40
|
limit: parseInt(opts.limit, 10),
|
|
41
41
|
maxTokens: parseInt(opts.budget, 10),
|
|
@@ -61,7 +61,7 @@ ${formatTokenSavings({ tokensSent: result.metadata.tokensSent, estimatedWithout,
|
|
|
61
61
|
program.command("ask").description(
|
|
62
62
|
"Ask a natural language question about the codebase \u2014 retrieves context locally, reasons via Claude"
|
|
63
63
|
).argument("<question>", "Natural language question about the codebase").option("-b, --budget <tokens>", "Token budget for context retrieval", "4096").option("-p, --path <path>", "Project root directory").action(async (question, opts) => {
|
|
64
|
-
const { runAskCodebase } = await import("./askCodebase-
|
|
64
|
+
const { runAskCodebase } = await import("./askCodebase-OAAG35G5.js");
|
|
65
65
|
const result = await runAskCodebase(question, {
|
|
66
66
|
path: opts.path,
|
|
67
67
|
maxContextTokens: parseInt(opts.budget, 10)
|
package/dist/mcp.js
CHANGED
|
@@ -91,7 +91,8 @@ var IndexStateSchema = z.object({
|
|
|
91
91
|
dimension: z.number().int(),
|
|
92
92
|
indexedAt: z.string().datetime(),
|
|
93
93
|
fileCount: z.number().int(),
|
|
94
|
-
chunkCount: z.number().int()
|
|
94
|
+
chunkCount: z.number().int(),
|
|
95
|
+
totalTokens: z.number().int().default(0)
|
|
95
96
|
});
|
|
96
97
|
|
|
97
98
|
// src/lib/config.ts
|
|
@@ -796,6 +797,10 @@ async function runIndex(targetPath, opts) {
|
|
|
796
797
|
delete updatedHashes[filePath];
|
|
797
798
|
}
|
|
798
799
|
const filesToProcess = [...newFiles, ...changedFiles];
|
|
800
|
+
let allFilesTotalTokens = 0;
|
|
801
|
+
for (const [, content] of contentMap) {
|
|
802
|
+
allFilesTotalTokens += countChunkTokens(content);
|
|
803
|
+
}
|
|
799
804
|
if (filesToProcess.length === 0) {
|
|
800
805
|
process.stderr.write(`brain-cache: nothing to re-index
|
|
801
806
|
`);
|
|
@@ -811,7 +816,8 @@ async function runIndex(targetPath, opts) {
|
|
|
811
816
|
dimension: dim,
|
|
812
817
|
indexedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
813
818
|
fileCount: totalFiles2,
|
|
814
|
-
chunkCount: chunkCount2
|
|
819
|
+
chunkCount: chunkCount2,
|
|
820
|
+
totalTokens: allFilesTotalTokens
|
|
815
821
|
});
|
|
816
822
|
process.stderr.write(
|
|
817
823
|
`brain-cache: indexing complete
|
|
@@ -902,7 +908,8 @@ async function runIndex(targetPath, opts) {
|
|
|
902
908
|
dimension: dim,
|
|
903
909
|
indexedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
904
910
|
fileCount: totalFiles,
|
|
905
|
-
chunkCount
|
|
911
|
+
chunkCount,
|
|
912
|
+
totalTokens: allFilesTotalTokens
|
|
906
913
|
});
|
|
907
914
|
const reductionPct = totalRawTokens > 0 ? Math.round((1 - totalChunkTokens / totalRawTokens) * 100) : 0;
|
|
908
915
|
const savingsBlock = formatTokenSavings({
|
|
@@ -1080,7 +1087,6 @@ async function runSearch(query, opts) {
|
|
|
1080
1087
|
}
|
|
1081
1088
|
|
|
1082
1089
|
// src/workflows/buildContext.ts
|
|
1083
|
-
import { readFile as readFile5 } from "fs/promises";
|
|
1084
1090
|
import { resolve as resolve3 } from "path";
|
|
1085
1091
|
async function runBuildContext(query, opts) {
|
|
1086
1092
|
const profile = await readProfile();
|
|
@@ -1117,15 +1123,7 @@ async function runBuildContext(query, opts) {
|
|
|
1117
1123
|
const results = await searchChunks(table, queryVector, strategy);
|
|
1118
1124
|
const deduped = deduplicateChunks(results);
|
|
1119
1125
|
const assembled = assembleContext(deduped, { maxTokens });
|
|
1120
|
-
const
|
|
1121
|
-
let estimatedWithoutBraincache = 0;
|
|
1122
|
-
for (const filePath of uniqueFiles) {
|
|
1123
|
-
try {
|
|
1124
|
-
const fileContent = await readFile5(filePath, "utf-8");
|
|
1125
|
-
estimatedWithoutBraincache += countChunkTokens(fileContent);
|
|
1126
|
-
} catch {
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1126
|
+
const estimatedWithoutBraincache = indexState.totalTokens;
|
|
1129
1127
|
const reductionPct = estimatedWithoutBraincache > 0 ? Math.round((1 - assembled.tokenCount / estimatedWithoutBraincache) * 100) : 0;
|
|
1130
1128
|
const result = {
|
|
1131
1129
|
content: assembled.content,
|
|
@@ -1146,7 +1144,7 @@ async function runBuildContext(query, opts) {
|
|
|
1146
1144
|
}
|
|
1147
1145
|
|
|
1148
1146
|
// src/mcp/index.ts
|
|
1149
|
-
var version = "0.3.
|
|
1147
|
+
var version = "0.3.3";
|
|
1150
1148
|
var log9 = childLogger("mcp");
|
|
1151
1149
|
var server = new McpServer({ name: "brain-cache", version });
|
|
1152
1150
|
server.registerTool(
|
|
@@ -14,10 +14,10 @@ import {
|
|
|
14
14
|
import {
|
|
15
15
|
openDatabase,
|
|
16
16
|
readIndexState
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-DTJNPRN6.js";
|
|
18
18
|
import {
|
|
19
19
|
readProfile
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-DDDLTKDT.js";
|
|
21
21
|
import "./chunk-3SFDFUEX.js";
|
|
22
22
|
|
|
23
23
|
// src/workflows/search.ts
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
readIndexState
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-DTJNPRN6.js";
|
|
5
5
|
import {
|
|
6
6
|
readProfile
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-DDDLTKDT.js";
|
|
8
8
|
import "./chunk-3SFDFUEX.js";
|
|
9
9
|
|
|
10
10
|
// src/workflows/status.ts
|
|
@@ -20,10 +20,10 @@ import {
|
|
|
20
20
|
readFileHashes,
|
|
21
21
|
writeFileHashes,
|
|
22
22
|
writeIndexState
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-DTJNPRN6.js";
|
|
24
24
|
import {
|
|
25
25
|
readProfile
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-DDDLTKDT.js";
|
|
27
27
|
import {
|
|
28
28
|
DEFAULT_BATCH_SIZE,
|
|
29
29
|
DEFAULT_EMBEDDING_DIMENSION,
|
|
@@ -345,6 +345,10 @@ async function runIndex(targetPath, opts) {
|
|
|
345
345
|
delete updatedHashes[filePath];
|
|
346
346
|
}
|
|
347
347
|
const filesToProcess = [...newFiles, ...changedFiles];
|
|
348
|
+
let allFilesTotalTokens = 0;
|
|
349
|
+
for (const [, content] of contentMap) {
|
|
350
|
+
allFilesTotalTokens += countChunkTokens(content);
|
|
351
|
+
}
|
|
348
352
|
if (filesToProcess.length === 0) {
|
|
349
353
|
process.stderr.write(`brain-cache: nothing to re-index
|
|
350
354
|
`);
|
|
@@ -360,7 +364,8 @@ async function runIndex(targetPath, opts) {
|
|
|
360
364
|
dimension: dim,
|
|
361
365
|
indexedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
362
366
|
fileCount: totalFiles2,
|
|
363
|
-
chunkCount: chunkCount2
|
|
367
|
+
chunkCount: chunkCount2,
|
|
368
|
+
totalTokens: allFilesTotalTokens
|
|
364
369
|
});
|
|
365
370
|
process.stderr.write(
|
|
366
371
|
`brain-cache: indexing complete
|
|
@@ -451,7 +456,8 @@ async function runIndex(targetPath, opts) {
|
|
|
451
456
|
dimension: dim,
|
|
452
457
|
indexedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
453
458
|
fileCount: totalFiles,
|
|
454
|
-
chunkCount
|
|
459
|
+
chunkCount,
|
|
460
|
+
totalTokens: allFilesTotalTokens
|
|
455
461
|
});
|
|
456
462
|
const reductionPct = totalRawTokens > 0 ? Math.round((1 - totalChunkTokens / totalRawTokens) * 100) : 0;
|
|
457
463
|
const savingsBlock = formatTokenSavings({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brain-cache",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Local MCP-first context engine for Claude. Index your codebase, retrieve only what matters, and cut token usage.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"scripts": {
|
|
27
27
|
"dev": "tsx src/cli/index.ts",
|
|
28
28
|
"build": "tsup",
|
|
29
|
+
"prepare": "npm run build",
|
|
29
30
|
"link": "npm link",
|
|
30
31
|
"test": "vitest run",
|
|
31
32
|
"test:watch": "vitest"
|