@wrongstack/tools 0.66.13 → 0.73.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/dist/index.d.ts CHANGED
@@ -33,7 +33,7 @@ export { forgetTool, rememberTool } from './memory.js';
33
33
  export { createModeTool } from './mode.js';
34
34
  export { KillOpts, RegistryStats, TrackedProcess, _resetProcessRegistry, getProcessRegistry } from './process-registry.js';
35
35
  export { CircuitBreaker, CircuitBreakerConfig, CircuitBreakerSnapshot } from './circuit-breaker.js';
36
- export { g as codebaseIndexTool, h as codebaseSearchTool, i as codebaseStatsTool } from './codebase-stats-tool-C8ApERbn.js';
36
+ export { g as cancelPendingReindexes, h as codebaseIndexTool, i as codebaseSearchTool, j as codebaseStatsTool, k as enqueueReindex, l as isIndexableFile, r as runStartupIndex } from './background-indexer-sbsseCCC.js';
37
37
  export { builtinTools } from './builtin.js';
38
38
  export { builtinToolsPack } from './pack.js';
39
39
  import 'node:child_process';
package/dist/index.js CHANGED
@@ -3112,8 +3112,8 @@ var jsonTool = {
3112
3112
  };
3113
3113
  }
3114
3114
  };
3115
- function query(data, path18) {
3116
- const parts = path18.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
3115
+ function query(data, path19) {
3116
+ const parts = path19.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
3117
3117
  let current = data;
3118
3118
  for (const part of parts) {
3119
3119
  if (current === null || current === void 0) return void 0;
@@ -4404,7 +4404,7 @@ async function dockerLogs(service, lines, filterRe, cwd, signal, since) {
4404
4404
  }
4405
4405
  var DOCKER_LOGS_TIMEOUT_MS = 3e3;
4406
4406
  var MAX_TAIL_LINES = 1e5;
4407
- async function fileLogs(path18, lines, filterRe, stream) {
4407
+ async function fileLogs(path19, lines, filterRe, stream) {
4408
4408
  const { createInterface } = await import('node:readline');
4409
4409
  const { createReadStream } = await import('node:fs');
4410
4410
  const entries = [];
@@ -4413,7 +4413,7 @@ async function fileLogs(path18, lines, filterRe, stream) {
4413
4413
  let writeIdx = 0;
4414
4414
  let totalLines = 0;
4415
4415
  const rl = createInterface({
4416
- input: createReadStream(path18),
4416
+ input: createReadStream(path19),
4417
4417
  crlfDelay: Number.POSITIVE_INFINITY
4418
4418
  });
4419
4419
  for await (const line of rl) {
@@ -4434,7 +4434,7 @@ async function fileLogs(path18, lines, filterRe, stream) {
4434
4434
  if (parsed) entries.push(parsed);
4435
4435
  }
4436
4436
  return {
4437
- source: path18,
4437
+ source: path19,
4438
4438
  entries,
4439
4439
  total: entries.length,
4440
4440
  truncated: totalLines > effLines,
@@ -4874,10 +4874,14 @@ var toolSearchTool = {
4874
4874
  permission: t.permission,
4875
4875
  mutating: t.mutating
4876
4876
  }));
4877
+ const totalAvailable = tools.length;
4878
+ const hint = results.length === 0 && query2 ? `No tools matched "${input.query}". Use tool-help (without arguments) to see all ${totalAvailable} available tools.` : void 0;
4877
4879
  return {
4878
4880
  tools: results,
4879
4881
  total: filtered.length,
4880
- truncated: filtered.length > limit
4882
+ truncated: filtered.length > limit,
4883
+ ...hint ? { hint } : {},
4884
+ _available: totalAvailable
4881
4885
  };
4882
4886
  }
4883
4887
  };
@@ -5565,6 +5569,17 @@ var IndexStore = class {
5565
5569
  ({ id, text }) => ({ id, text })
5566
5570
  );
5567
5571
  }
5572
+ /**
5573
+ * Largest symbol id currently in the table (0 when empty). New ids must be
5574
+ * allocated from this, NOT from `COUNT(*)`: incremental reindexes delete a
5575
+ * changed file's rows, so the row count drops below the max id and a
5576
+ * count-based id would collide with a surviving row (UNIQUE constraint on
5577
+ * `symbols.id`). Ids may have gaps — that is fine.
5578
+ */
5579
+ getMaxSymbolId() {
5580
+ const rows = this.db.prepare("SELECT MAX(id) AS m FROM symbols").all();
5581
+ return rows[0]?.m ?? 0;
5582
+ }
5568
5583
  // ─── Stats ───────────────────────────────────────────────────────────────────
5569
5584
  getStats() {
5570
5585
  const sizeBytes = this.sizeBytes();
@@ -6883,6 +6898,56 @@ function makeSymbol2(opts) {
6883
6898
  text: `${opts.name} ${opts.signature}`.trim()
6884
6899
  };
6885
6900
  }
6901
+ function globBody(glob) {
6902
+ return compileGlob(glob).source.replace(/^\^/, "").replace(/\$$/, "");
6903
+ }
6904
+ function compileGitignore(lines) {
6905
+ const rules = [];
6906
+ for (const raw of lines) {
6907
+ let line = raw.replace(/\r$/, "");
6908
+ if (!line.trim() || line.trimStart().startsWith("#")) continue;
6909
+ line = line.trim();
6910
+ let negated = false;
6911
+ if (line.startsWith("!")) {
6912
+ negated = true;
6913
+ line = line.slice(1);
6914
+ }
6915
+ let dirOnly = false;
6916
+ if (line.endsWith("/")) {
6917
+ dirOnly = true;
6918
+ line = line.slice(0, -1);
6919
+ }
6920
+ if (!line) continue;
6921
+ const anchored = line.startsWith("/") || line.includes("/");
6922
+ if (line.startsWith("/")) line = line.slice(1);
6923
+ const body = globBody(line);
6924
+ const prefix = anchored ? "^" : "(?:^|.*/)";
6925
+ rules.push({
6926
+ eqOrUnder: new RegExp(`${prefix}${body}(?:/.*)?$`),
6927
+ under: new RegExp(`${prefix}${body}/.*$`),
6928
+ negated,
6929
+ dirOnly
6930
+ });
6931
+ }
6932
+ return (relPath, isDir) => {
6933
+ const p = relPath.replace(/\\/g, "/").replace(/^\/+/, "");
6934
+ let ignored = false;
6935
+ for (const r of rules) {
6936
+ const re = r.dirOnly && !isDir ? r.under : r.eqOrUnder;
6937
+ if (re.test(p)) ignored = !r.negated;
6938
+ }
6939
+ return ignored;
6940
+ };
6941
+ }
6942
+ async function loadGitignoreMatcher(projectRoot) {
6943
+ let lines = [];
6944
+ try {
6945
+ const raw = await fs4.readFile(path.join(projectRoot, ".gitignore"), "utf8");
6946
+ lines = raw.split("\n");
6947
+ } catch {
6948
+ }
6949
+ return compileGitignore(lines);
6950
+ }
6886
6951
 
6887
6952
  // src/codebase-index/indexer.ts
6888
6953
  var DEFAULT_IGNORE5 = [
@@ -6896,7 +6961,7 @@ var DEFAULT_IGNORE5 = [
6896
6961
  "__snapshots__",
6897
6962
  ".nyc_output"
6898
6963
  ];
6899
- async function findSourceFiles(projectRoot, ignore) {
6964
+ async function findSourceFiles(projectRoot, ignore, isGitIgnored) {
6900
6965
  const results = [];
6901
6966
  const ignoreSet = /* @__PURE__ */ new Set([...DEFAULT_IGNORE5, ...ignore]);
6902
6967
  const globs = [
@@ -6921,10 +6986,12 @@ async function findSourceFiles(projectRoot, ignore) {
6921
6986
  for (const e of entries) {
6922
6987
  if (ignoreSet.has(e.name)) continue;
6923
6988
  const full = path.join(dir, e.name);
6989
+ const rel = path.relative(projectRoot, full).replace(/\\/g, "/");
6924
6990
  if (e.isDirectory()) {
6991
+ if (isGitIgnored(rel, true)) continue;
6925
6992
  await walk(full);
6926
6993
  } else if (e.isFile()) {
6927
- const rel = path.relative(projectRoot, full).replace(/\\/g, "/");
6994
+ if (isGitIgnored(rel, false)) continue;
6928
6995
  const ext = path.extname(e.name);
6929
6996
  for (const { ext: extName, pat } of globs) {
6930
6997
  if (ext === extName && (pat.test(rel) || pat.test(e.name))) {
@@ -6967,11 +7034,12 @@ async function runIndexer(_ctx, opts) {
6967
7034
  const langStats = {};
6968
7035
  let filesIndexed = 0;
6969
7036
  let symbolsIndexed = 0;
7037
+ const isGitIgnored = await loadGitignoreMatcher(projectRoot);
6970
7038
  let files;
6971
7039
  if (opts.files && opts.files.length > 0) {
6972
- files = opts.files.map((f) => path.resolve(projectRoot, f));
7040
+ files = opts.files.map((f) => path.resolve(projectRoot, f)).filter((f) => !isGitIgnored(path.relative(projectRoot, f).replace(/\\/g, "/"), false));
6973
7041
  } else {
6974
- files = await findSourceFiles(projectRoot, ignore);
7042
+ files = await findSourceFiles(projectRoot, ignore, isGitIgnored);
6975
7043
  }
6976
7044
  if (langs && langs.length > 0) {
6977
7045
  const langSet = new Set(langs);
@@ -7003,8 +7071,8 @@ async function runIndexer(_ctx, opts) {
7003
7071
  filesIndexed++;
7004
7072
  continue;
7005
7073
  }
7006
- store.deleteSymbolsForFile(file);
7007
7074
  store.deleteRefsForFile(file);
7075
+ store.deleteSymbolsForFile(file);
7008
7076
  let content;
7009
7077
  try {
7010
7078
  content = await fs4.readFile(file, "utf8");
@@ -7030,7 +7098,7 @@ async function runIndexer(_ctx, opts) {
7030
7098
  filesIndexed++;
7031
7099
  continue;
7032
7100
  }
7033
- const nextId = store.getStats().totalSymbols + 1;
7101
+ const nextId = store.getMaxSymbolId() + 1;
7034
7102
  const symbolsWithIds = parsed.symbols.map((s, i) => ({ ...s, id: nextId + i }));
7035
7103
  store.insertSymbols(symbolsWithIds, nextId);
7036
7104
  const count = symbolsWithIds.length;
@@ -7316,6 +7384,70 @@ var codebaseStatsTool = {
7316
7384
  }
7317
7385
  };
7318
7386
 
7387
+ // src/codebase-index/background-indexer.ts
7388
+ function stubCtx(projectRoot) {
7389
+ return {
7390
+ projectRoot,
7391
+ cwd: projectRoot,
7392
+ messages: [],
7393
+ todos: [],
7394
+ readFiles: /* @__PURE__ */ new Set(),
7395
+ fileMtimes: /* @__PURE__ */ new Map()
7396
+ };
7397
+ }
7398
+ var chain = Promise.resolve();
7399
+ function withMutex(job) {
7400
+ const run = chain.then(job, job);
7401
+ chain = run.then(
7402
+ () => void 0,
7403
+ () => void 0
7404
+ );
7405
+ return run;
7406
+ }
7407
+ var DEFAULT_DEBOUNCE_MS = 400;
7408
+ var debounceTimers = /* @__PURE__ */ new Map();
7409
+ function debounceKey(indexDir, file) {
7410
+ return `${indexDir ?? ""}|${file}`;
7411
+ }
7412
+ function isIndexableFile(filePath) {
7413
+ return detectLang(filePath) !== null;
7414
+ }
7415
+ function runStartupIndex(opts) {
7416
+ return withMutex(
7417
+ () => runIndexer(stubCtx(opts.projectRoot), {
7418
+ projectRoot: opts.projectRoot,
7419
+ indexDir: opts.indexDir,
7420
+ force: opts.force
7421
+ })
7422
+ );
7423
+ }
7424
+ function enqueueReindex(opts) {
7425
+ const files = opts.files.filter(isIndexableFile);
7426
+ if (files.length === 0) return;
7427
+ const ms = opts.debounceMs ?? DEFAULT_DEBOUNCE_MS;
7428
+ for (const file of files) {
7429
+ const key = debounceKey(opts.indexDir, file);
7430
+ const existing = debounceTimers.get(key);
7431
+ if (existing) clearTimeout(existing);
7432
+ const timer = setTimeout(() => {
7433
+ debounceTimers.delete(key);
7434
+ void withMutex(
7435
+ () => runIndexer(stubCtx(opts.projectRoot), {
7436
+ projectRoot: opts.projectRoot,
7437
+ files: [file],
7438
+ indexDir: opts.indexDir
7439
+ })
7440
+ ).catch((err) => opts.onError?.(err));
7441
+ }, ms);
7442
+ timer.unref?.();
7443
+ debounceTimers.set(key, timer);
7444
+ }
7445
+ }
7446
+ function cancelPendingReindexes() {
7447
+ for (const t of debounceTimers.values()) clearTimeout(t);
7448
+ debounceTimers.clear();
7449
+ }
7450
+
7319
7451
  // src/builtin.ts
7320
7452
  var builtinTools = [
7321
7453
  readTool,
@@ -7361,6 +7493,6 @@ var builtinToolsPack = {
7361
7493
  tools: builtinTools
7362
7494
  };
7363
7495
 
7364
- export { CircuitBreaker, _resetProcessRegistry, auditTool, bashTool, batchToolUseTool, builtinTools, builtinToolsPack, codebaseIndexTool, codebaseSearchTool, codebaseStatsTool, createModeTool, diffTool, documentTool, editTool, execTool, fetchTool, forgetTool, formatTool, getProcessRegistry, gitTool, globTool, grepTool, installTool, jsonTool, lintTool, logsTool, outdatedTool, patchTool, planTool, readTool, rememberTool, replaceTool, scaffoldTool, searchTool, testTool, todoTool, toolHelpTool, toolSearchTool, toolUseTool, treeTool, typecheckTool, writeTool };
7496
+ export { CircuitBreaker, _resetProcessRegistry, auditTool, bashTool, batchToolUseTool, builtinTools, builtinToolsPack, cancelPendingReindexes, codebaseIndexTool, codebaseSearchTool, codebaseStatsTool, createModeTool, diffTool, documentTool, editTool, enqueueReindex, execTool, fetchTool, forgetTool, formatTool, getProcessRegistry, gitTool, globTool, grepTool, installTool, isIndexableFile, jsonTool, lintTool, logsTool, outdatedTool, patchTool, planTool, readTool, rememberTool, replaceTool, runStartupIndex, scaffoldTool, searchTool, testTool, todoTool, toolHelpTool, toolSearchTool, toolUseTool, treeTool, typecheckTool, writeTool };
7365
7497
  //# sourceMappingURL=index.js.map
7366
7498
  //# sourceMappingURL=index.js.map