agentsbestfriend 0.1.3 → 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 CHANGED
@@ -5,16 +5,10 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
9
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
10
- }) : x)(function(x) {
11
- if (typeof require !== "undefined") return require.apply(this, arguments);
12
- throw Error('Dynamic require of "' + x + '" is not supported');
13
- });
14
8
  var __esm = (fn, res) => function __init() {
15
9
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
16
10
  };
17
- var __commonJS = (cb, mod) => function __require2() {
11
+ var __commonJS = (cb, mod) => function __require() {
18
12
  return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
19
13
  };
20
14
  var __export = (target, all) => {
@@ -18065,9 +18059,52 @@ Summary:`;
18065
18059
  // ../core/dist/llm/pipelines.js
18066
18060
  import { readFile } from "fs/promises";
18067
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
+ }
18068
18104
  var init_pipelines = __esm({
18069
18105
  "../core/dist/llm/pipelines.js"() {
18070
18106
  "use strict";
18107
+ init_drizzle_orm();
18071
18108
  init_connection();
18072
18109
  init_schema2();
18073
18110
  init_llm();
@@ -18177,7 +18214,7 @@ var init_search = __esm({
18177
18214
 
18178
18215
  // ../core/dist/utils/index.js
18179
18216
  import { createHash } from "crypto";
18180
- import { readFileSync as readFileSync3 } from "fs";
18217
+ import { readFileSync as readFileSync3, openSync, readSync, closeSync } from "fs";
18181
18218
  import { extname } from "path";
18182
18219
  function hashFileContent(content) {
18183
18220
  return createHash("sha256").update(content, "utf-8").digest("hex");
@@ -18267,9 +18304,9 @@ function countLines(content) {
18267
18304
  function isBinaryFile(filePath) {
18268
18305
  try {
18269
18306
  const buffer = Buffer.alloc(8192);
18270
- const fd = __require("fs").openSync(filePath, "r");
18271
- const bytesRead = __require("fs").readSync(fd, buffer, 0, 8192, 0);
18272
- __require("fs").closeSync(fd);
18307
+ const fd = openSync(filePath, "r");
18308
+ const bytesRead = readSync(fd, buffer, 0, 8192, 0);
18309
+ closeSync(fd);
18273
18310
  for (let i = 0; i < bytesRead; i++) {
18274
18311
  if (buffer[i] === 0)
18275
18312
  return true;
@@ -44523,7 +44560,7 @@ function registerGitTool(server) {
44523
44560
  line_start: external_exports3.number().int().optional().describe("Start line for blame range"),
44524
44561
  line_end: external_exports3.number().int().optional().describe("End line for blame range")
44525
44562
  }, async ({ action, file: file2, count, line_start, line_end }) => {
44526
- const cwd = process.cwd();
44563
+ const cwd = process.env.ABF_PROJECT_ROOT || process.cwd();
44527
44564
  if (!await isGitRepo(cwd)) {
44528
44565
  return {
44529
44566
  content: [
@@ -44601,16 +44638,17 @@ function errorResult(msg) {
44601
44638
 
44602
44639
  // ../server/dist/tools/index-tool.js
44603
44640
  init_indexer();
44604
- var IndexActionSchema = external_exports3.enum(["status", "rebuild", "update"]);
44641
+ init_llm();
44642
+ var IndexActionSchema = external_exports3.enum(["status", "rebuild", "update", "summarize"]);
44605
44643
  function registerIndexTool(server) {
44606
- server.tool("abf_index", "Manage the file index: check status, trigger rebuild, or incremental update.", {
44607
- 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)")
44608
44646
  }, async ({ action }) => {
44609
- const cwd = process.cwd();
44647
+ const projectRoot = process.env.ABF_PROJECT_ROOT || process.cwd();
44610
44648
  try {
44611
44649
  switch (action) {
44612
44650
  case "status": {
44613
- const status = await getIndexStatus(cwd);
44651
+ const status = await getIndexStatus(projectRoot);
44614
44652
  const lastUp = status.lastUpdated ? status.lastUpdated.toISOString() : "never";
44615
44653
  const sizeMb = (status.indexSizeBytes / (1024 * 1024)).toFixed(2);
44616
44654
  const text4 = [
@@ -44623,7 +44661,7 @@ function registerIndexTool(server) {
44623
44661
  }
44624
44662
  case "rebuild":
44625
44663
  case "update": {
44626
- const stats = await runIndexPipeline(cwd);
44664
+ const stats = await runIndexPipeline(projectRoot);
44627
44665
  const text4 = [
44628
44666
  `Index ${action} complete (${stats.durationMs}ms)`,
44629
44667
  `Discovered: ${stats.totalDiscovered}`,
@@ -44635,6 +44673,16 @@ function registerIndexTool(server) {
44635
44673
  ].filter(Boolean).join("\n");
44636
44674
  return { content: [{ type: "text", text: text4 }] };
44637
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
+ }
44638
44686
  }
44639
44687
  } catch (err) {
44640
44688
  const msg = err instanceof Error ? err.message : String(err);
@@ -44653,7 +44701,7 @@ function registerSymbolsTool(server) {
44653
44701
  file_path: external_exports3.string().describe("Path to the file (relative or absolute)"),
44654
44702
  depth: external_exports3.number().int().min(1).max(5).default(2).describe("How deep to show nested symbols")
44655
44703
  }, async ({ file_path, depth }) => {
44656
- const cwd = process.cwd();
44704
+ const cwd = process.env.ABF_PROJECT_ROOT || process.cwd();
44657
44705
  const absPath = file_path.startsWith("/") ? file_path : join9(cwd, file_path);
44658
44706
  try {
44659
44707
  const content = readFileSync6(absPath, "utf-8");
@@ -44695,17 +44743,43 @@ function formatSymbolTree(symbols2, maxDepth, currentDepth) {
44695
44743
  import { readFileSync as readFileSync7 } from "fs";
44696
44744
  import { join as join10 } from "path";
44697
44745
  function registerChunkTool(server) {
44698
- server.tool("abf_chunk", "Smart file chunking by symbol boundaries. Without chunk_index: returns chunk overview. With chunk_index: returns that chunk's content.", {
44699
- file_path: external_exports3.string().describe("Path to the file"),
44700
- chunk_index: external_exports3.number().int().min(0).optional().describe("Request a specific chunk by index (0-based). Omit for overview.")
44701
- }, async ({ file_path, chunk_index }) => {
44702
- const cwd = process.cwd();
44703
- const absPath = file_path.startsWith("/") ? file_path : join10(cwd, file_path);
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);
44704
44757
  try {
44705
44758
  const content = readFileSync7(absPath, "utf-8");
44706
44759
  const lines = content.split("\n");
44707
- const { symbols: symbols2 } = parseFile(absPath, content);
44708
- const chunks = buildChunks(symbols2, lines.length);
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);
44709
44783
  if (chunk_index !== void 0) {
44710
44784
  if (chunk_index < 0 || chunk_index >= chunks.length) {
44711
44785
  return {
@@ -44728,7 +44802,9 @@ function registerChunkTool(server) {
44728
44802
  }
44729
44803
  const overview = chunks.map((c, i) => `[${i}] ${c.label} L${c.startLine}-${c.endLine} (${c.endLine - c.startLine + 1} lines)`).join("\n");
44730
44804
  const text4 = `${chunks.length} chunks in ${file_path}:
44731
- ${overview}`;
44805
+ ${overview}
44806
+
44807
+ To get source code, call again with chunk_index=<number> or symbol=<name>.`;
44732
44808
  return { content: [{ type: "text", text: text4 }] };
44733
44809
  } catch (err) {
44734
44810
  const msg = err instanceof Error ? err.message : String(err);
@@ -44736,6 +44812,18 @@ ${overview}`;
44736
44812
  }
44737
44813
  });
44738
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
+ }
44739
44827
  var MAX_CHUNK_LINES = 200;
44740
44828
  function buildChunks(symbols2, totalLines) {
44741
44829
  if (symbols2.length === 0) {
@@ -44811,13 +44899,14 @@ function buildChunks(symbols2, totalLines) {
44811
44899
  import { readFileSync as readFileSync8 } from "fs";
44812
44900
  import { join as join11, dirname, resolve } from "path";
44813
44901
  import { existsSync as existsSync4 } from "fs";
44902
+ import { execFileSync } from "child_process";
44814
44903
  function registerDependenciesTool(server) {
44815
44904
  server.tool("abf_dependencies", "Show imports and reverse dependencies (imported_by) for a file.", {
44816
44905
  file_path: external_exports3.string().describe("Path to the file"),
44817
44906
  direction: external_exports3.enum(["imports", "imported_by", "both"]).default("both").describe("Which direction to analyze"),
44818
44907
  depth: external_exports3.number().int().min(1).max(3).default(1).describe("Depth of transitive dependencies")
44819
44908
  }, async ({ file_path, direction, depth }) => {
44820
- const cwd = process.cwd();
44909
+ const cwd = process.env.ABF_PROJECT_ROOT || process.cwd();
44821
44910
  const absPath = file_path.startsWith("/") ? file_path : join11(cwd, file_path);
44822
44911
  const relPath = file_path.startsWith("/") ? file_path.slice(cwd.length + 1) : file_path;
44823
44912
  try {
@@ -44883,7 +44972,6 @@ function tryResolve(importPath, fromDir) {
44883
44972
  return null;
44884
44973
  }
44885
44974
  function findImportedBy(cwd, targetRelPath) {
44886
- const { execFileSync } = __require("child_process");
44887
44975
  let filePaths;
44888
44976
  try {
44889
44977
  const stdout = execFileSync("git", ["ls-files", "--cached", "--others", "--exclude-standard"], { cwd, maxBuffer: 10 * 1024 * 1024 }).toString();
@@ -44944,7 +45032,7 @@ function registerImpactTool(server) {
44944
45032
  symbol_name: external_exports3.string().describe("The symbol (function, class, variable) name to find references for"),
44945
45033
  file_path: external_exports3.string().optional().describe("Optional: scope search to usages of this symbol from this file")
44946
45034
  }, async ({ symbol_name, file_path }) => {
44947
- const cwd = process.cwd();
45035
+ const cwd = process.env.ABF_PROJECT_ROOT || process.cwd();
44948
45036
  try {
44949
45037
  const results = await ripgrepSearch({
44950
45038
  query: `\\b${escapeRegex2(symbol_name)}\\b`,