agentsbestfriend 0.1.4 → 0.2.0
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/index.js +113 -19
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -18059,9 +18059,52 @@ Summary:`;
|
|
|
18059
18059
|
// ../core/dist/llm/pipelines.js
|
|
18060
18060
|
import { readFile } from "fs/promises";
|
|
18061
18061
|
import { join as join4 } from "path";
|
|
18062
|
+
async function generateSummaries(projectRoot, opts) {
|
|
18063
|
+
const start = Date.now();
|
|
18064
|
+
const provider = getLlmProvider();
|
|
18065
|
+
if (!provider) {
|
|
18066
|
+
throw new LlmUnavailableError("none", "LLM provider is set to 'none'");
|
|
18067
|
+
}
|
|
18068
|
+
if (!await provider.isAvailable()) {
|
|
18069
|
+
throw new LlmUnavailableError(provider.name, "Cannot reach Ollama. Is it running?");
|
|
18070
|
+
}
|
|
18071
|
+
const db = createProjectDb(projectRoot);
|
|
18072
|
+
const stats = {
|
|
18073
|
+
generated: 0,
|
|
18074
|
+
skipped: 0,
|
|
18075
|
+
errors: 0,
|
|
18076
|
+
durationMs: 0
|
|
18077
|
+
};
|
|
18078
|
+
try {
|
|
18079
|
+
const rows = opts?.force ? db.select({ id: files.id, path: files.path }).from(files).all() : db.select({ id: files.id, path: files.path }).from(files).where(isNull(files.summary)).all();
|
|
18080
|
+
const batchSize = opts?.batchSize ?? 5;
|
|
18081
|
+
for (let i = 0; i < rows.length; i += batchSize) {
|
|
18082
|
+
const batch = rows.slice(i, i + batchSize);
|
|
18083
|
+
for (const row of batch) {
|
|
18084
|
+
try {
|
|
18085
|
+
const absPath = join4(projectRoot, row.path);
|
|
18086
|
+
const content = await readFile(absPath, "utf-8");
|
|
18087
|
+
const summary = await provider.generateSummary(content, row.path);
|
|
18088
|
+
db.update(files).set({ summary }).where(eq(files.id, row.id)).run();
|
|
18089
|
+
stats.generated++;
|
|
18090
|
+
} catch (err) {
|
|
18091
|
+
if (err instanceof LlmUnavailableError)
|
|
18092
|
+
throw err;
|
|
18093
|
+
stats.errors++;
|
|
18094
|
+
}
|
|
18095
|
+
}
|
|
18096
|
+
}
|
|
18097
|
+
stats.skipped = rows.length === 0 ? db.select({ id: files.id }).from(files).all().length : 0;
|
|
18098
|
+
stats.durationMs = Date.now() - start;
|
|
18099
|
+
return stats;
|
|
18100
|
+
} finally {
|
|
18101
|
+
closeDb(db);
|
|
18102
|
+
}
|
|
18103
|
+
}
|
|
18062
18104
|
var init_pipelines = __esm({
|
|
18063
18105
|
"../core/dist/llm/pipelines.js"() {
|
|
18064
18106
|
"use strict";
|
|
18107
|
+
init_drizzle_orm();
|
|
18065
18108
|
init_connection();
|
|
18066
18109
|
init_schema2();
|
|
18067
18110
|
init_llm();
|
|
@@ -44517,7 +44560,7 @@ function registerGitTool(server) {
|
|
|
44517
44560
|
line_start: external_exports3.number().int().optional().describe("Start line for blame range"),
|
|
44518
44561
|
line_end: external_exports3.number().int().optional().describe("End line for blame range")
|
|
44519
44562
|
}, async ({ action, file: file2, count, line_start, line_end }) => {
|
|
44520
|
-
const cwd = process.cwd();
|
|
44563
|
+
const cwd = process.env.ABF_PROJECT_ROOT || process.cwd();
|
|
44521
44564
|
if (!await isGitRepo(cwd)) {
|
|
44522
44565
|
return {
|
|
44523
44566
|
content: [
|
|
@@ -44595,16 +44638,17 @@ function errorResult(msg) {
|
|
|
44595
44638
|
|
|
44596
44639
|
// ../server/dist/tools/index-tool.js
|
|
44597
44640
|
init_indexer();
|
|
44598
|
-
|
|
44641
|
+
init_llm();
|
|
44642
|
+
var IndexActionSchema = external_exports3.enum(["status", "rebuild", "update", "summarize"]);
|
|
44599
44643
|
function registerIndexTool(server) {
|
|
44600
|
-
server.tool("abf_index", "Manage the file index: check status, trigger rebuild, or
|
|
44601
|
-
action: IndexActionSchema.describe("status: show index info, rebuild: full re-index, update: incremental update")
|
|
44644
|
+
server.tool("abf_index", "Manage the file index: check status, trigger rebuild, incremental update, or generate LLM summaries (requires Ollama).", {
|
|
44645
|
+
action: IndexActionSchema.describe("status: show index info, rebuild: full re-index, update: incremental update, summarize: generate LLM file summaries (requires Ollama)")
|
|
44602
44646
|
}, async ({ action }) => {
|
|
44603
|
-
const
|
|
44647
|
+
const projectRoot = process.env.ABF_PROJECT_ROOT || process.cwd();
|
|
44604
44648
|
try {
|
|
44605
44649
|
switch (action) {
|
|
44606
44650
|
case "status": {
|
|
44607
|
-
const status = await getIndexStatus(
|
|
44651
|
+
const status = await getIndexStatus(projectRoot);
|
|
44608
44652
|
const lastUp = status.lastUpdated ? status.lastUpdated.toISOString() : "never";
|
|
44609
44653
|
const sizeMb = (status.indexSizeBytes / (1024 * 1024)).toFixed(2);
|
|
44610
44654
|
const text4 = [
|
|
@@ -44617,7 +44661,7 @@ function registerIndexTool(server) {
|
|
|
44617
44661
|
}
|
|
44618
44662
|
case "rebuild":
|
|
44619
44663
|
case "update": {
|
|
44620
|
-
const stats = await runIndexPipeline(
|
|
44664
|
+
const stats = await runIndexPipeline(projectRoot);
|
|
44621
44665
|
const text4 = [
|
|
44622
44666
|
`Index ${action} complete (${stats.durationMs}ms)`,
|
|
44623
44667
|
`Discovered: ${stats.totalDiscovered}`,
|
|
@@ -44629,6 +44673,16 @@ function registerIndexTool(server) {
|
|
|
44629
44673
|
].filter(Boolean).join("\n");
|
|
44630
44674
|
return { content: [{ type: "text", text: text4 }] };
|
|
44631
44675
|
}
|
|
44676
|
+
case "summarize": {
|
|
44677
|
+
const stats = await generateSummaries(projectRoot);
|
|
44678
|
+
const text4 = [
|
|
44679
|
+
`Summary generation complete (${stats.durationMs}ms)`,
|
|
44680
|
+
`Generated: ${stats.generated}`,
|
|
44681
|
+
`Skipped (already have summary): ${stats.skipped}`,
|
|
44682
|
+
stats.errors > 0 ? `Errors: ${stats.errors}` : null
|
|
44683
|
+
].filter(Boolean).join("\n");
|
|
44684
|
+
return { content: [{ type: "text", text: text4 }] };
|
|
44685
|
+
}
|
|
44632
44686
|
}
|
|
44633
44687
|
} catch (err) {
|
|
44634
44688
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -44647,7 +44701,7 @@ function registerSymbolsTool(server) {
|
|
|
44647
44701
|
file_path: external_exports3.string().describe("Path to the file (relative or absolute)"),
|
|
44648
44702
|
depth: external_exports3.number().int().min(1).max(5).default(2).describe("How deep to show nested symbols")
|
|
44649
44703
|
}, async ({ file_path, depth }) => {
|
|
44650
|
-
const cwd = process.cwd();
|
|
44704
|
+
const cwd = process.env.ABF_PROJECT_ROOT || process.cwd();
|
|
44651
44705
|
const absPath = file_path.startsWith("/") ? file_path : join9(cwd, file_path);
|
|
44652
44706
|
try {
|
|
44653
44707
|
const content = readFileSync6(absPath, "utf-8");
|
|
@@ -44689,17 +44743,43 @@ function formatSymbolTree(symbols2, maxDepth, currentDepth) {
|
|
|
44689
44743
|
import { readFileSync as readFileSync7 } from "fs";
|
|
44690
44744
|
import { join as join10 } from "path";
|
|
44691
44745
|
function registerChunkTool(server) {
|
|
44692
|
-
server.tool("abf_chunk",
|
|
44693
|
-
|
|
44694
|
-
|
|
44695
|
-
|
|
44696
|
-
|
|
44697
|
-
|
|
44746
|
+
server.tool("abf_chunk", `Smart file chunking by symbol boundaries. Returns actual source code.
|
|
44747
|
+
Use EXACTLY ONE of these modes:
|
|
44748
|
+
- symbol: pass a symbol name to get its full source code directly
|
|
44749
|
+
- chunk_index: pass a 0-based chunk index to get that chunk's code
|
|
44750
|
+
- (neither): returns a chunk overview listing \u2014 use this first to discover available chunks, then call again with chunk_index to retrieve code`, {
|
|
44751
|
+
file_path: external_exports3.string().describe("Path to the file (relative or absolute)"),
|
|
44752
|
+
chunk_index: external_exports3.number().int().min(0).optional().describe("0-based chunk index to retrieve that chunk's source code. Get the index from the overview first."),
|
|
44753
|
+
symbol: external_exports3.string().optional().describe("Name of a symbol (function, class, etc.) to retrieve its full source code directly.")
|
|
44754
|
+
}, async ({ file_path, chunk_index, symbol: symbol2 }) => {
|
|
44755
|
+
const projectRoot = process.env.ABF_PROJECT_ROOT || process.cwd();
|
|
44756
|
+
const absPath = file_path.startsWith("/") ? file_path : join10(projectRoot, file_path);
|
|
44698
44757
|
try {
|
|
44699
44758
|
const content = readFileSync7(absPath, "utf-8");
|
|
44700
44759
|
const lines = content.split("\n");
|
|
44701
|
-
const { symbols:
|
|
44702
|
-
|
|
44760
|
+
const { symbols: parsedSymbols } = parseFile(absPath, content);
|
|
44761
|
+
if (symbol2) {
|
|
44762
|
+
const match = findSymbol(parsedSymbols, symbol2);
|
|
44763
|
+
if (!match) {
|
|
44764
|
+
const available = parsedSymbols.map((s) => `${s.kind} ${s.name}`).join(", ");
|
|
44765
|
+
return {
|
|
44766
|
+
content: [
|
|
44767
|
+
{
|
|
44768
|
+
type: "text",
|
|
44769
|
+
text: `Symbol "${symbol2}" not found in ${file_path}. Available: ${available || "(none)"}`
|
|
44770
|
+
}
|
|
44771
|
+
]
|
|
44772
|
+
};
|
|
44773
|
+
}
|
|
44774
|
+
const chunkLines = lines.slice(match.startLine - 1, match.endLine);
|
|
44775
|
+
const text5 = [
|
|
44776
|
+
`${match.kind} ${match.name} (L${match.startLine}-${match.endLine})`,
|
|
44777
|
+
"---",
|
|
44778
|
+
...chunkLines
|
|
44779
|
+
].join("\n");
|
|
44780
|
+
return { content: [{ type: "text", text: text5 }] };
|
|
44781
|
+
}
|
|
44782
|
+
const chunks = buildChunks(parsedSymbols, lines.length);
|
|
44703
44783
|
if (chunk_index !== void 0) {
|
|
44704
44784
|
if (chunk_index < 0 || chunk_index >= chunks.length) {
|
|
44705
44785
|
return {
|
|
@@ -44722,7 +44802,9 @@ function registerChunkTool(server) {
|
|
|
44722
44802
|
}
|
|
44723
44803
|
const overview = chunks.map((c, i) => `[${i}] ${c.label} L${c.startLine}-${c.endLine} (${c.endLine - c.startLine + 1} lines)`).join("\n");
|
|
44724
44804
|
const text4 = `${chunks.length} chunks in ${file_path}:
|
|
44725
|
-
${overview}
|
|
44805
|
+
${overview}
|
|
44806
|
+
|
|
44807
|
+
To get source code, call again with chunk_index=<number> or symbol=<name>.`;
|
|
44726
44808
|
return { content: [{ type: "text", text: text4 }] };
|
|
44727
44809
|
} catch (err) {
|
|
44728
44810
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -44730,6 +44812,18 @@ ${overview}`;
|
|
|
44730
44812
|
}
|
|
44731
44813
|
});
|
|
44732
44814
|
}
|
|
44815
|
+
function findSymbol(symbols2, name) {
|
|
44816
|
+
const lower = name.toLowerCase();
|
|
44817
|
+
for (const sym of symbols2) {
|
|
44818
|
+
if (sym.name.toLowerCase() === lower)
|
|
44819
|
+
return sym;
|
|
44820
|
+
for (const child of sym.children) {
|
|
44821
|
+
if (child.name.toLowerCase() === lower)
|
|
44822
|
+
return child;
|
|
44823
|
+
}
|
|
44824
|
+
}
|
|
44825
|
+
return void 0;
|
|
44826
|
+
}
|
|
44733
44827
|
var MAX_CHUNK_LINES = 200;
|
|
44734
44828
|
function buildChunks(symbols2, totalLines) {
|
|
44735
44829
|
if (symbols2.length === 0) {
|
|
@@ -44812,7 +44906,7 @@ function registerDependenciesTool(server) {
|
|
|
44812
44906
|
direction: external_exports3.enum(["imports", "imported_by", "both"]).default("both").describe("Which direction to analyze"),
|
|
44813
44907
|
depth: external_exports3.number().int().min(1).max(3).default(1).describe("Depth of transitive dependencies")
|
|
44814
44908
|
}, async ({ file_path, direction, depth }) => {
|
|
44815
|
-
const cwd = process.cwd();
|
|
44909
|
+
const cwd = process.env.ABF_PROJECT_ROOT || process.cwd();
|
|
44816
44910
|
const absPath = file_path.startsWith("/") ? file_path : join11(cwd, file_path);
|
|
44817
44911
|
const relPath = file_path.startsWith("/") ? file_path.slice(cwd.length + 1) : file_path;
|
|
44818
44912
|
try {
|
|
@@ -44938,7 +45032,7 @@ function registerImpactTool(server) {
|
|
|
44938
45032
|
symbol_name: external_exports3.string().describe("The symbol (function, class, variable) name to find references for"),
|
|
44939
45033
|
file_path: external_exports3.string().optional().describe("Optional: scope search to usages of this symbol from this file")
|
|
44940
45034
|
}, async ({ symbol_name, file_path }) => {
|
|
44941
|
-
const cwd = process.cwd();
|
|
45035
|
+
const cwd = process.env.ABF_PROJECT_ROOT || process.cwd();
|
|
44942
45036
|
try {
|
|
44943
45037
|
const results = await ripgrepSearch({
|
|
44944
45038
|
query: `\\b${escapeRegex2(symbol_name)}\\b`,
|