grepmax 0.1.0 → 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.
Files changed (61) hide show
  1. package/LICENSE +1 -1
  2. package/NOTICE +2 -2
  3. package/README.md +72 -72
  4. package/dist/commands/claude-code.js +6 -6
  5. package/dist/commands/codex.js +17 -17
  6. package/dist/commands/doctor.js +6 -5
  7. package/dist/commands/droid.js +22 -22
  8. package/dist/commands/index.js +1 -1
  9. package/dist/commands/list.js +82 -19
  10. package/dist/commands/mcp.js +161 -142
  11. package/dist/commands/opencode.js +26 -26
  12. package/dist/commands/search.js +23 -13
  13. package/dist/commands/serve.js +30 -30
  14. package/dist/commands/setup.js +51 -40
  15. package/dist/commands/skeleton.js +19 -13
  16. package/dist/commands/symbols.js +40 -2
  17. package/dist/commands/verify.js +1 -1
  18. package/dist/commands/watch.js +206 -0
  19. package/dist/config.js +37 -7
  20. package/dist/eval.js +14 -14
  21. package/dist/index.js +11 -7
  22. package/dist/lib/core/languages.js +28 -0
  23. package/dist/lib/index/chunker.js +6 -3
  24. package/dist/lib/index/grammar-loader.js +2 -2
  25. package/dist/lib/index/ignore-patterns.js +1 -1
  26. package/dist/lib/index/index-config.js +50 -10
  27. package/dist/lib/index/sync-helpers.js +1 -1
  28. package/dist/lib/index/syncer.js +67 -45
  29. package/dist/lib/index/walker.js +3 -3
  30. package/dist/lib/index/watcher.js +4 -4
  31. package/dist/lib/output/formatter.js +1 -1
  32. package/dist/lib/search/searcher.js +9 -9
  33. package/dist/lib/setup/model-loader.js +3 -3
  34. package/dist/lib/setup/setup-helpers.js +2 -4
  35. package/dist/lib/skeleton/body-fields.js +20 -0
  36. package/dist/lib/skeleton/retriever.js +1 -1
  37. package/dist/lib/skeleton/skeletonizer.js +8 -2
  38. package/dist/lib/skeleton/summary-formatter.js +1 -4
  39. package/dist/lib/store/meta-cache.js +28 -3
  40. package/dist/lib/store/vector-db.js +17 -9
  41. package/dist/lib/utils/formatter.js +3 -3
  42. package/dist/lib/utils/lock.js +1 -1
  43. package/dist/lib/utils/project-registry.js +83 -0
  44. package/dist/lib/utils/project-root.js +32 -57
  45. package/dist/lib/utils/watcher-registry.js +100 -0
  46. package/dist/lib/workers/colbert-math.js +2 -2
  47. package/dist/lib/workers/download-worker.js +2 -2
  48. package/dist/lib/workers/embeddings/colbert.js +2 -2
  49. package/dist/lib/workers/embeddings/granite.js +4 -4
  50. package/dist/lib/workers/embeddings/mlx-client.js +1 -1
  51. package/dist/lib/workers/orchestrator.js +8 -8
  52. package/dist/lib/workers/pool.js +1 -1
  53. package/dist/lib/workers/worker.js +4 -1
  54. package/package.json +20 -21
  55. package/plugins/{osgrep → grepmax}/.claude-plugin/plugin.json +4 -4
  56. package/plugins/grepmax/hooks/start.js +63 -0
  57. package/plugins/grepmax/hooks/stop.js +3 -0
  58. package/plugins/{osgrep/skills/osgrep → grepmax/skills/gmax}/SKILL.md +11 -11
  59. package/plugins/osgrep/hooks/start.js +0 -90
  60. package/plugins/osgrep/hooks/stop.js +0 -3
  61. /package/plugins/{osgrep → grepmax}/hooks.json +0 -0
@@ -3,7 +3,7 @@
3
3
  * Index configuration — tracks which models built the current index.
4
4
  * Prevents searching with incompatible vectors after a model swap.
5
5
  *
6
- * Also stores user preferences from `osgrep setup` (embed mode, MLX model).
6
+ * Also stores user preferences from `gmax setup` (embed mode, MLX model).
7
7
  */
8
8
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
9
  if (k2 === undefined) k2 = k;
@@ -39,12 +39,47 @@ var __importStar = (this && this.__importStar) || (function () {
39
39
  };
40
40
  })();
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.readGlobalConfig = readGlobalConfig;
43
+ exports.writeGlobalConfig = writeGlobalConfig;
44
+ exports.getModelIdsForTier = getModelIdsForTier;
42
45
  exports.readIndexConfig = readIndexConfig;
43
46
  exports.writeIndexConfig = writeIndexConfig;
44
47
  exports.writeSetupConfig = writeSetupConfig;
45
48
  exports.checkModelMismatch = checkModelMismatch;
46
49
  const fs = __importStar(require("node:fs"));
50
+ const path = __importStar(require("node:path"));
47
51
  const config_1 = require("../../config");
52
+ const GLOBAL_CONFIG_PATH = path.join(config_1.PATHS.globalRoot, "config.json");
53
+ function readGlobalConfig() {
54
+ try {
55
+ const raw = fs.readFileSync(GLOBAL_CONFIG_PATH, "utf-8");
56
+ return JSON.parse(raw);
57
+ }
58
+ catch (_a) {
59
+ const tier = config_1.MODEL_TIERS[config_1.DEFAULT_MODEL_TIER];
60
+ return {
61
+ modelTier: config_1.DEFAULT_MODEL_TIER,
62
+ vectorDim: tier.vectorDim,
63
+ embedMode: "cpu",
64
+ };
65
+ }
66
+ }
67
+ function writeGlobalConfig(config) {
68
+ fs.mkdirSync(path.dirname(GLOBAL_CONFIG_PATH), { recursive: true });
69
+ fs.writeFileSync(GLOBAL_CONFIG_PATH, `${JSON.stringify(config, null, 2)}\n`);
70
+ }
71
+ /**
72
+ * Resolve the effective model IDs for a given tier.
73
+ */
74
+ function getModelIdsForTier(tierName) {
75
+ var _a;
76
+ const tier = (_a = config_1.MODEL_TIERS[tierName]) !== null && _a !== void 0 ? _a : config_1.MODEL_TIERS[config_1.DEFAULT_MODEL_TIER];
77
+ return {
78
+ embed: tier.onnxModel,
79
+ colbert: config_1.MODEL_IDS.colbert,
80
+ vectorDim: tier.vectorDim,
81
+ };
82
+ }
48
83
  function readIndexConfig(configPath) {
49
84
  try {
50
85
  const raw = fs.readFileSync(configPath, "utf-8");
@@ -55,32 +90,37 @@ function readIndexConfig(configPath) {
55
90
  }
56
91
  }
57
92
  function writeIndexConfig(configPath, extra) {
93
+ var _a;
58
94
  const existing = readIndexConfig(configPath);
95
+ const tierName = (_a = existing === null || existing === void 0 ? void 0 : existing.modelTier) !== null && _a !== void 0 ? _a : readGlobalConfig().modelTier;
96
+ const tierIds = getModelIdsForTier(tierName);
59
97
  const config = Object.assign({
60
98
  // Preserve user preferences from setup
61
- embedMode: existing === null || existing === void 0 ? void 0 : existing.embedMode, mlxModel: existing === null || existing === void 0 ? void 0 : existing.mlxModel,
99
+ embedMode: existing === null || existing === void 0 ? void 0 : existing.embedMode, mlxModel: existing === null || existing === void 0 ? void 0 : existing.mlxModel, modelTier: tierName,
62
100
  // Model identity from current run
63
- embedModel: config_1.MODEL_IDS.embed, colbertModel: config_1.MODEL_IDS.colbert, vectorDim: config_1.CONFIG.VECTOR_DIM, indexedAt: new Date().toISOString() }, extra);
64
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
101
+ embedModel: tierIds.embed, colbertModel: tierIds.colbert, vectorDim: tierIds.vectorDim, indexedAt: new Date().toISOString() }, extra);
102
+ fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
65
103
  }
66
104
  /**
67
105
  * Write only user preferences without touching model identity fields.
68
- * Used by `osgrep setup` before any indexing has happened.
106
+ * Used by `gmax setup` before any indexing has happened.
69
107
  */
70
108
  function writeSetupConfig(configPath, prefs) {
71
109
  const existing = readIndexConfig(configPath);
72
- const config = Object.assign(Object.assign({}, existing), { embedMode: prefs.embedMode, mlxModel: prefs.mlxModel });
73
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
110
+ const config = Object.assign(Object.assign({}, existing), { embedMode: prefs.embedMode, mlxModel: prefs.mlxModel, modelTier: prefs.modelTier });
111
+ fs.writeFileSync(configPath, `${JSON.stringify(config, null, 2)}\n`);
74
112
  }
75
113
  function checkModelMismatch(configPath) {
76
114
  const stored = readIndexConfig(configPath);
77
115
  if (!stored)
78
116
  return false; // No config yet — first index
79
- if (stored.embedModel !== config_1.MODEL_IDS.embed)
117
+ const globalConfig = readGlobalConfig();
118
+ const tierIds = getModelIdsForTier(globalConfig.modelTier);
119
+ if (stored.embedModel && stored.embedModel !== tierIds.embed)
80
120
  return true;
81
- if (stored.colbertModel !== config_1.MODEL_IDS.colbert)
121
+ if (stored.colbertModel && stored.colbertModel !== tierIds.colbert)
82
122
  return true;
83
- if (stored.vectorDim !== undefined && stored.vectorDim !== config_1.CONFIG.VECTOR_DIM)
123
+ if (stored.vectorDim !== undefined && stored.vectorDim !== tierIds.vectorDim)
84
124
  return true;
85
125
  return false;
86
126
  }
@@ -56,7 +56,7 @@ function createIndexingSpinner(root, label = "Indexing files...", options = {})
56
56
  info.filePath.startsWith("Processing") ||
57
57
  info.filePath.startsWith("Checking for changes"))) {
58
58
  spinner.text = info.filePath;
59
- if (process.env.OSGREP_DEBUG_INDEX === "1") {
59
+ if (process.env.GMAX_DEBUG_INDEX === "1") {
60
60
  console.log(`[progress] ${info.filePath}`);
61
61
  }
62
62
  return;
@@ -57,10 +57,11 @@ const meta_cache_1 = require("../store/meta-cache");
57
57
  const vector_db_1 = require("../store/vector-db");
58
58
  const file_utils_1 = require("../utils/file-utils");
59
59
  const lock_1 = require("../utils/lock");
60
+ const project_registry_1 = require("../utils/project-registry");
60
61
  const project_root_1 = require("../utils/project-root");
61
62
  const pool_1 = require("../workers/pool");
62
- const walker_1 = require("./walker");
63
63
  const index_config_1 = require("./index-config");
64
+ const walker_1 = require("./walker");
64
65
  function flushBatch(db, meta, vectors, pendingMeta, pendingDeletes, dryRun) {
65
66
  return __awaiter(this, void 0, void 0, function* () {
66
67
  if (dryRun)
@@ -87,6 +88,16 @@ function createNoopMetaCache() {
87
88
  return new Set(store.keys());
88
89
  });
89
90
  },
91
+ getKeysWithPrefix(prefix) {
92
+ return __awaiter(this, void 0, void 0, function* () {
93
+ const keys = new Set();
94
+ for (const k of store.keys()) {
95
+ if (k.startsWith(prefix))
96
+ keys.add(k);
97
+ }
98
+ return keys;
99
+ });
100
+ },
90
101
  put: (filePath, entry) => {
91
102
  store.set(filePath, entry);
92
103
  },
@@ -101,15 +112,20 @@ function initialSync(options) {
101
112
  var _a, e_1, _b, _c;
102
113
  const { projectRoot, dryRun = false, reset = false, onProgress, signal, } = options;
103
114
  const paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
115
+ const resolvedRoot = path.resolve(projectRoot);
116
+ // Path prefix for scoping — all absolute paths for this project start with this
117
+ const rootPrefix = resolvedRoot.endsWith("/")
118
+ ? resolvedRoot
119
+ : `${resolvedRoot}/`;
104
120
  // Propagate project root to worker processes
105
- process.env.OSGREP_PROJECT_ROOT = paths.root;
121
+ process.env.GMAX_PROJECT_ROOT = paths.root;
106
122
  let lock = null;
107
123
  const vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
108
124
  const treatAsEmptyCache = reset && dryRun;
109
125
  let metaCache = null;
110
126
  try {
111
127
  if (!dryRun) {
112
- lock = yield (0, lock_1.acquireWriterLockWithRetry)(paths.osgrepDir);
128
+ lock = yield (0, lock_1.acquireWriterLockWithRetry)(paths.dataDir);
113
129
  // Open MetaCache only after lock is acquired
114
130
  metaCache = new meta_cache_1.MetaCache(paths.lmdbPath);
115
131
  }
@@ -117,33 +133,28 @@ function initialSync(options) {
117
133
  metaCache = createNoopMetaCache();
118
134
  }
119
135
  if (!dryRun) {
120
- const hasRows = yield vectorDb.hasAnyRows();
121
- const hasMeta = (yield metaCache.getAllKeys()).size > 0;
122
- const isInconsistent = (hasRows && !hasMeta) || (!hasRows && hasMeta);
136
+ // Scope checks to this project's paths only
137
+ const projectKeys = yield metaCache.getKeysWithPrefix(rootPrefix);
123
138
  const modelChanged = (0, index_config_1.checkModelMismatch)(paths.configPath);
124
- if (reset || isInconsistent || modelChanged) {
139
+ if (reset || modelChanged) {
125
140
  if (modelChanged) {
126
141
  const stored = (0, index_config_1.readIndexConfig)(paths.configPath);
127
142
  console.warn(`[syncer] Embedding model changed: ${stored === null || stored === void 0 ? void 0 : stored.embedModel} → ${config_1.MODEL_IDS.embed}. Forcing full re-index.`);
128
143
  }
129
- else if (isInconsistent) {
130
- console.warn("[syncer] Detected inconsistent state (VectorDB/MetaCache mismatch). Forcing re-sync.");
131
- }
132
- yield vectorDb.drop();
133
- metaCache.close();
134
- try {
135
- fs.rmSync(paths.lmdbPath, { force: true });
144
+ // Only delete this project's data from the centralized store
145
+ yield vectorDb.deletePathsWithPrefix(rootPrefix);
146
+ for (const key of projectKeys) {
147
+ metaCache.delete(key);
136
148
  }
137
- catch (_d) { }
138
- metaCache = new meta_cache_1.MetaCache(paths.lmdbPath);
139
149
  }
140
150
  }
141
151
  let total = 0;
142
152
  onProgress === null || onProgress === void 0 ? void 0 : onProgress({ processed: 0, indexed: 0, total, filePath: "Scanning..." });
143
153
  const pool = (0, pool_1.getWorkerPool)();
154
+ // Get only this project's cached paths (scoped by prefix)
144
155
  const cachedPaths = dryRun || treatAsEmptyCache
145
156
  ? new Set()
146
- : yield metaCache.getAllKeys();
157
+ : yield metaCache.getKeysWithPrefix(rootPrefix);
147
158
  const seenPaths = new Set();
148
159
  const visitedRealPaths = new Set();
149
160
  const batch = [];
@@ -196,12 +207,12 @@ function initialSync(options) {
196
207
  yield flushLock;
197
208
  });
198
209
  const isTimeoutError = (err) => { var _a; return err instanceof Error && ((_a = err.message) === null || _a === void 0 ? void 0 : _a.toLowerCase().includes("timed out")); };
199
- const processFileWithRetry = (relPath, absPath) => __awaiter(this, void 0, void 0, function* () {
210
+ const processFileWithRetry = (absPath) => __awaiter(this, void 0, void 0, function* () {
200
211
  let retries = 0;
201
212
  while (true) {
202
213
  try {
203
214
  return yield pool.processFile({
204
- path: relPath,
215
+ path: absPath,
205
216
  absolutePath: absPath,
206
217
  });
207
218
  }
@@ -227,18 +238,16 @@ function initialSync(options) {
227
238
  }
228
239
  });
229
240
  try {
230
- for (var _e = true, _f = __asyncValues((0, walker_1.walk)(paths.root, {
231
- additionalPatterns: ["**/.git/**", "**/.osgrep/**"], // exclude .git and .osgrep explicitly if walker doesn't
232
- })), _g; _g = yield _f.next(), _a = _g.done, !_a; _e = true) {
233
- _c = _g.value;
234
- _e = false;
241
+ for (var _d = true, _e = __asyncValues((0, walker_1.walk)(paths.root, {
242
+ additionalPatterns: ["**/.git/**", "**/.gmax/**", "**/.osgrep/**"],
243
+ })), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
244
+ _c = _f.value;
245
+ _d = false;
235
246
  const relPath = _c;
236
247
  if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
237
248
  shouldSkipCleanup = true;
238
249
  break;
239
250
  }
240
- // Walker yields relative paths
241
- // if (ignoreFilter.ignores(relPath)) continue; // Handled by walker
242
251
  const absPath = path.join(paths.root, relPath);
243
252
  // Check real path to avoid duplicates and loops
244
253
  try {
@@ -247,7 +256,7 @@ function initialSync(options) {
247
256
  continue;
248
257
  visitedRealPaths.add(realPath);
249
258
  }
250
- catch (_h) {
259
+ catch (_g) {
251
260
  // Skip broken symlinks or inaccessible files
252
261
  continue;
253
262
  }
@@ -263,18 +272,19 @@ function initialSync(options) {
263
272
  if (!(0, file_utils_1.isIndexableFile)(absPath, stats.size)) {
264
273
  return;
265
274
  }
275
+ // Use absolute path as the key for MetaCache
266
276
  const cached = treatAsEmptyCache
267
277
  ? undefined
268
- : metaCache.get(relPath);
278
+ : metaCache.get(absPath);
269
279
  if (cached &&
270
280
  cached.mtimeMs === stats.mtimeMs &&
271
281
  cached.size === stats.size) {
272
282
  processed += 1;
273
- seenPaths.add(relPath);
283
+ seenPaths.add(absPath);
274
284
  markProgress(relPath);
275
285
  return;
276
286
  }
277
- const result = yield processFileWithRetry(relPath, absPath);
287
+ const result = yield processFileWithRetry(absPath);
278
288
  const metaEntry = {
279
289
  hash: result.hash,
280
290
  mtimeMs: result.mtimeMs,
@@ -282,41 +292,41 @@ function initialSync(options) {
282
292
  };
283
293
  if (result.shouldDelete) {
284
294
  if (!dryRun) {
285
- pendingDeletes.add(relPath);
286
- pendingMeta.set(relPath, metaEntry);
295
+ pendingDeletes.add(absPath);
296
+ pendingMeta.set(absPath, metaEntry);
287
297
  yield flush(false);
288
298
  }
289
299
  processed += 1;
290
- seenPaths.add(relPath);
300
+ seenPaths.add(absPath);
291
301
  markProgress(relPath);
292
302
  return;
293
303
  }
294
304
  if (cached && cached.hash === result.hash) {
295
305
  if (!dryRun) {
296
- metaCache.put(relPath, metaEntry);
306
+ metaCache.put(absPath, metaEntry);
297
307
  }
298
308
  processed += 1;
299
- seenPaths.add(relPath);
309
+ seenPaths.add(absPath);
300
310
  markProgress(relPath);
301
311
  return;
302
312
  }
303
313
  if (dryRun) {
304
314
  processed += 1;
305
315
  indexed += 1;
306
- seenPaths.add(relPath);
316
+ seenPaths.add(absPath);
307
317
  markProgress(relPath);
308
318
  return;
309
319
  }
310
- pendingDeletes.add(relPath);
320
+ pendingDeletes.add(absPath);
311
321
  if (result.vectors.length > 0) {
312
322
  batch.push(...result.vectors);
313
- pendingMeta.set(relPath, metaEntry);
323
+ pendingMeta.set(absPath, metaEntry);
314
324
  indexed += 1;
315
325
  }
316
326
  else {
317
- pendingMeta.set(relPath, metaEntry);
327
+ pendingMeta.set(absPath, metaEntry);
318
328
  }
319
- seenPaths.add(relPath);
329
+ seenPaths.add(absPath);
320
330
  processed += 1;
321
331
  markProgress(relPath);
322
332
  yield flush(false);
@@ -325,10 +335,10 @@ function initialSync(options) {
325
335
  const code = err === null || err === void 0 ? void 0 : err.code;
326
336
  if (code === "ENOENT") {
327
337
  // Treat missing files as deletions.
328
- pendingDeletes.add(relPath);
329
- pendingMeta.delete(relPath);
338
+ pendingDeletes.add(absPath);
339
+ pendingMeta.delete(absPath);
330
340
  if (!dryRun) {
331
- metaCache.delete(relPath);
341
+ metaCache.delete(absPath);
332
342
  }
333
343
  processed += 1;
334
344
  markProgress(relPath);
@@ -337,7 +347,7 @@ function initialSync(options) {
337
347
  }
338
348
  failedFiles += 1;
339
349
  processed += 1;
340
- seenPaths.add(relPath);
350
+ seenPaths.add(absPath);
341
351
  console.error(`[sync] Failed to process ${relPath}:`, err);
342
352
  markProgress(relPath);
343
353
  }
@@ -347,7 +357,7 @@ function initialSync(options) {
347
357
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
348
358
  finally {
349
359
  try {
350
- if (!_e && !_a && (_b = _f.return)) yield _b.call(_f);
360
+ if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
351
361
  }
352
362
  finally { if (e_1) throw e_1.error; }
353
363
  }
@@ -370,6 +380,7 @@ function initialSync(options) {
370
380
  });
371
381
  yield vectorDb.createFTSIndex();
372
382
  }
383
+ // Stale cleanup: only remove paths scoped to this project's root
373
384
  const stale = Array.from(cachedPaths).filter((p) => !seenPaths.has(p));
374
385
  if (!dryRun && stale.length > 0 && !shouldSkipCleanup) {
375
386
  yield vectorDb.deletePaths(stale);
@@ -380,6 +391,17 @@ function initialSync(options) {
380
391
  // Write model config so future runs can detect model changes
381
392
  if (!dryRun) {
382
393
  (0, index_config_1.writeIndexConfig)(paths.configPath);
394
+ // Register project in global registry
395
+ const globalConfig = (0, index_config_1.readGlobalConfig)();
396
+ (0, project_registry_1.registerProject)({
397
+ root: paths.root,
398
+ name: path.basename(paths.root),
399
+ vectorDim: globalConfig.vectorDim,
400
+ modelTier: globalConfig.modelTier,
401
+ embedMode: globalConfig.embedMode,
402
+ lastIndexed: new Date().toISOString(),
403
+ chunkCount: indexed,
404
+ });
383
405
  }
384
406
  // Finalize total so callers can display a meaningful summary.
385
407
  total = processed;
@@ -86,7 +86,7 @@ function getIgnoreFilter(dir, ignoreFiles) {
86
86
  filter = (0, ignore_1.default)();
87
87
  filter.add(content);
88
88
  }
89
- catch (err) {
89
+ catch (_err) {
90
90
  // Ignore missing files
91
91
  }
92
92
  }
@@ -95,7 +95,7 @@ function getIgnoreFilter(dir, ignoreFiles) {
95
95
  }
96
96
  function walk(rootDir_1) {
97
97
  return __asyncGenerator(this, arguments, function* walk_1(rootDir, options = {}) {
98
- const ignoreFiles = options.ignoreFiles || [".gitignore", ".osgrepignore"];
98
+ const ignoreFiles = options.ignoreFiles || [".gitignore", ".gmaxignore"];
99
99
  const rootParams = (0, ignore_1.default)().add(ignore_patterns_1.DEFAULT_IGNORE_PATTERNS);
100
100
  if (options.additionalPatterns) {
101
101
  rootParams.add(options.additionalPatterns);
@@ -125,7 +125,7 @@ function _walk(currentDir, rootDir, stack, ignoreFiles) {
125
125
  try {
126
126
  entries = yield __await(fs.readdir(currentDir, { withFileTypes: true }));
127
127
  }
128
- catch (err) {
128
+ catch (_err) {
129
129
  return yield __await(void 0);
130
130
  }
131
131
  for (const entry of entries) {
@@ -56,7 +56,7 @@ const pool_1 = require("../workers/pool");
56
56
  exports.WATCHER_IGNORE_PATTERNS = [
57
57
  "**/node_modules/**",
58
58
  "**/.git/**",
59
- "**/.osgrep/**",
59
+ "**/.gmax/**",
60
60
  "**/dist/**",
61
61
  "**/build/**",
62
62
  "**/out/**",
@@ -66,12 +66,12 @@ exports.WATCHER_IGNORE_PATTERNS = [
66
66
  "**/venv/**",
67
67
  "**/.next/**",
68
68
  "**/lancedb/**",
69
- /(^|[\/\\])\../, // dotfiles
69
+ /(^|[/\\])\../, // dotfiles
70
70
  ];
71
71
  const DEBOUNCE_MS = 2000;
72
72
  const FTS_REBUILD_INTERVAL_MS = 5 * 60 * 1000;
73
73
  function startWatcher(opts) {
74
- const { projectRoot, vectorDb, metaCache, osgrepDir, onReindex } = opts;
74
+ const { projectRoot, vectorDb, metaCache, dataDir, onReindex } = opts;
75
75
  const pending = new Map();
76
76
  let debounceTimer = null;
77
77
  let processing = false;
@@ -104,7 +104,7 @@ function startWatcher(opts) {
104
104
  const start = Date.now();
105
105
  let reindexed = 0;
106
106
  try {
107
- const lock = yield (0, lock_1.acquireWriterLockWithRetry)(osgrepDir, {
107
+ const lock = yield (0, lock_1.acquireWriterLockWithRetry)(dataDir, {
108
108
  maxRetries: 3,
109
109
  retryDelayMs: 500,
110
110
  });
@@ -143,7 +143,7 @@ function formatTrace(graph) {
143
143
  lines.push("");
144
144
  }
145
145
  // 2. Center (The Symbol)
146
- lines.push(style.bold("▶ " + graph.center.symbol));
146
+ lines.push(style.bold(`▶ ${graph.center.symbol}`));
147
147
  lines.push(` ${style.dim(`Defined in ${graph.center.file}:${graph.center.line}`)}`);
148
148
  lines.push(` ${style.dim(`Role: ${graph.center.role}`)}`);
149
149
  lines.push("");
@@ -137,7 +137,7 @@ class Searcher {
137
137
  // Item 6: Anchors are recall helpers, not rank contenders
138
138
  if (record.is_anchor) {
139
139
  // Minimal penalty to break ties
140
- const anchorPenalty = Number.parseFloat((_a = process.env.OSGREP_ANCHOR_PENALTY) !== null && _a !== void 0 ? _a : "") || 0.99;
140
+ const anchorPenalty = Number.parseFloat((_a = process.env.GMAX_ANCHOR_PENALTY) !== null && _a !== void 0 ? _a : "") || 0.99;
141
141
  adjusted *= anchorPenalty;
142
142
  }
143
143
  else {
@@ -197,7 +197,7 @@ class Searcher {
197
197
  const isTestPath = /(^|\/)(__tests__|tests?|specs?|benchmark)(\/|$)/i.test(pathStr) ||
198
198
  /\.(test|spec)\.[cm]?[jt]sx?$/i.test(pathStr);
199
199
  if (isTestPath) {
200
- const testPenalty = Number.parseFloat((_c = process.env.OSGREP_TEST_PENALTY) !== null && _c !== void 0 ? _c : "") || 0.5;
200
+ const testPenalty = Number.parseFloat((_c = process.env.GMAX_TEST_PENALTY) !== null && _c !== void 0 ? _c : "") || 0.5;
201
201
  adjusted *= testPenalty;
202
202
  }
203
203
  if (pathStr.endsWith(".md") ||
@@ -206,7 +206,7 @@ class Searcher {
206
206
  pathStr.endsWith(".json") ||
207
207
  pathStr.endsWith(".lock") ||
208
208
  pathStr.includes("/docs/")) {
209
- const docPenalty = Number.parseFloat((_d = process.env.OSGREP_DOC_PENALTY) !== null && _d !== void 0 ? _d : "") || 0.6;
209
+ const docPenalty = Number.parseFloat((_d = process.env.GMAX_DOC_PENALTY) !== null && _d !== void 0 ? _d : "") || 0.6;
210
210
  adjusted *= docPenalty; // Downweight docs/data
211
211
  }
212
212
  // Import-only penalty
@@ -297,7 +297,7 @@ class Searcher {
297
297
  // For now, let's just rely on boosting.
298
298
  }
299
299
  const whereClause = whereClauseParts.length > 0 ? whereClauseParts.join(" AND ") : undefined;
300
- const envPreK = Number.parseInt((_d = process.env.OSGREP_PRE_K) !== null && _d !== void 0 ? _d : "", 10);
300
+ const envPreK = Number.parseInt((_d = process.env.GMAX_PRE_K) !== null && _d !== void 0 ? _d : "", 10);
301
301
  const PRE_RERANK_K = Number.isFinite(envPreK) && envPreK > 0
302
302
  ? envPreK
303
303
  : Math.max(finalLimit * 5, 500);
@@ -363,17 +363,17 @@ class Searcher {
363
363
  .filter(Boolean);
364
364
  // Item 8: Widen PRE_RERANK_K
365
365
  // Retrieve a wide set for Stage 1 filtering
366
- const envStage1 = Number.parseInt((_e = process.env.OSGREP_STAGE1_K) !== null && _e !== void 0 ? _e : "", 10);
366
+ const envStage1 = Number.parseInt((_e = process.env.GMAX_STAGE1_K) !== null && _e !== void 0 ? _e : "", 10);
367
367
  const STAGE1_K = Number.isFinite(envStage1) && envStage1 > 0 ? envStage1 : 200;
368
368
  const topCandidates = fused.slice(0, STAGE1_K);
369
369
  // Item 9: Two-stage rerank
370
370
  // Stage 1: Cheap pooled cosine filter
371
371
  let stage2Candidates = topCandidates;
372
- const envStage2K = Number.parseInt((_f = process.env.OSGREP_STAGE2_K) !== null && _f !== void 0 ? _f : "", 10);
372
+ const envStage2K = Number.parseInt((_f = process.env.GMAX_STAGE2_K) !== null && _f !== void 0 ? _f : "", 10);
373
373
  const STAGE2_K = Number.isFinite(envStage2K) && envStage2K > 0 ? envStage2K : 40;
374
- const envRerankTop = Number.parseInt((_g = process.env.OSGREP_RERANK_TOP) !== null && _g !== void 0 ? _g : "", 10);
374
+ const envRerankTop = Number.parseInt((_g = process.env.GMAX_RERANK_TOP) !== null && _g !== void 0 ? _g : "", 10);
375
375
  const RERANK_TOP = Number.isFinite(envRerankTop) && envRerankTop > 0 ? envRerankTop : 20;
376
- const envBlend = Number.parseFloat((_h = process.env.OSGREP_RERANK_BLEND) !== null && _h !== void 0 ? _h : "");
376
+ const envBlend = Number.parseFloat((_h = process.env.GMAX_RERANK_BLEND) !== null && _h !== void 0 ? _h : "");
377
377
  const FUSED_WEIGHT = Number.isFinite(envBlend) && envBlend >= 0 ? envBlend : 0.5;
378
378
  if (queryPooled && topCandidates.length > STAGE2_K) {
379
379
  const cosineScores = topCandidates.map((doc) => {
@@ -439,7 +439,7 @@ class Searcher {
439
439
  // Item 10: Per-file diversification
440
440
  const seenFiles = new Map();
441
441
  const diversified = [];
442
- const envMaxPerFile = Number.parseInt((_j = process.env.OSGREP_MAX_PER_FILE) !== null && _j !== void 0 ? _j : "", 10);
442
+ const envMaxPerFile = Number.parseInt((_j = process.env.GMAX_MAX_PER_FILE) !== null && _j !== void 0 ? _j : "", 10);
443
443
  const MAX_PER_FILE = Number.isFinite(envMaxPerFile) && envMaxPerFile > 0 ? envMaxPerFile : 3;
444
444
  for (const item of uniqueScored) {
445
445
  const path = item.record.path || "";
@@ -50,9 +50,9 @@ const path = __importStar(require("node:path"));
50
50
  const node_worker_threads_1 = require("node:worker_threads");
51
51
  const config_1 = require("../../config");
52
52
  const HOMEDIR = os.homedir();
53
- const CACHE_DIR = path.join(HOMEDIR, ".osgrep", "models");
54
- const LOG_MODELS = process.env.OSGREP_DEBUG_MODELS === "1" ||
55
- process.env.OSGREP_DEBUG_MODELS === "true";
53
+ const CACHE_DIR = path.join(HOMEDIR, ".gmax", "models");
54
+ const LOG_MODELS = process.env.GMAX_DEBUG_MODELS === "1" ||
55
+ process.env.GMAX_DEBUG_MODELS === "true";
56
56
  /**
57
57
  * Triggers the download of models by spawning a worker thread.
58
58
  * This prevents the main thread from loading onnxruntime, avoiding exit crashes.
@@ -58,7 +58,7 @@ function getPaths() {
58
58
  };
59
59
  }
60
60
  /**
61
- * Idempotent helper that ensures osgrep directories and models exist.
61
+ * Idempotent helper that ensures gmax directories and models exist.
62
62
  * Returns status about work performed so callers can decide what to show.
63
63
  */
64
64
  function ensureSetup() {
@@ -67,9 +67,7 @@ function ensureSetup() {
67
67
  const dirs = [paths.root, paths.models, paths.grammars];
68
68
  const needsDirs = dirs.some((dir) => !fs.existsSync(dir));
69
69
  let createdDirs = false;
70
- const dirSpinner = !silent && needsDirs
71
- ? (0, ora_1.default)("Preparing osgrep directories...").start()
72
- : null;
70
+ const dirSpinner = !silent && needsDirs ? (0, ora_1.default)("Preparing gmax directories...").start() : null;
73
71
  try {
74
72
  if (needsDirs) {
75
73
  dirs.forEach((dir) => {
@@ -114,6 +114,18 @@ exports.BODY_FIELDS = {
114
114
  class_declaration: null, // Container (class/interface/enum)
115
115
  object_declaration: null, // Container (object/companion)
116
116
  },
117
+ bash: {
118
+ function_definition: "body", // positional fallback → compound_statement
119
+ },
120
+ scala: {
121
+ function_definition: "body", // positional — expression bodies
122
+ class_definition: null, // Container
123
+ object_definition: null, // Container
124
+ trait_definition: null, // Container
125
+ },
126
+ lua: {
127
+ function_declaration: "body", // named "body" field → block
128
+ },
117
129
  };
118
130
  /**
119
131
  * Container types - these hold methods/functions but shouldn't be elided themselves.
@@ -139,6 +151,14 @@ exports.CONTAINER_TYPES = {
139
151
  "protocol_body",
140
152
  ],
141
153
  kotlin: ["class_declaration", "class_body", "object_declaration"],
154
+ bash: [],
155
+ scala: [
156
+ "class_definition",
157
+ "object_definition",
158
+ "trait_definition",
159
+ "template_body",
160
+ ],
161
+ lua: [],
142
162
  };
143
163
  /**
144
164
  * Check if a node type is a container (holds methods).
@@ -28,7 +28,7 @@ function getStoredSkeleton(db, filePath) {
28
28
  }
29
29
  return null;
30
30
  }
31
- catch (e) {
31
+ catch (_e) {
32
32
  // If table doesn't exist or query fails, return null
33
33
  return null;
34
34
  }
@@ -205,7 +205,11 @@ class Skeletonizer {
205
205
  // Try named field first, then fall back to finding child by type
206
206
  // (some grammars like Kotlin use positional children, not named fields)
207
207
  const bodyNode = ((_a = node.childForFieldName) === null || _a === void 0 ? void 0 : _a.call(node, bodyFieldName)) ||
208
- (node.namedChildren || []).find((c) => c.type === "function_body" || c.type === bodyFieldName) ||
208
+ (node.namedChildren || []).find((c) => c.type === "function_body" ||
209
+ c.type === "compound_statement" ||
210
+ c.type === "block" ||
211
+ c.type === "template_body" ||
212
+ c.type === bodyFieldName) ||
209
213
  null;
210
214
  if (bodyNode) {
211
215
  const summary = this.createSummary(bodyNode, langId, opts);
@@ -359,7 +363,9 @@ class Skeletonizer {
359
363
  const seen = new Set();
360
364
  const extract = (n) => {
361
365
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
362
- if (n.type === "call_expression" || n.type === "call") {
366
+ if (n.type === "call_expression" ||
367
+ n.type === "call" ||
368
+ n.type === "function_call") {
363
369
  const func = (_a = n.childForFieldName) === null || _a === void 0 ? void 0 : _a.call(n, "function");
364
370
  if (func) {
365
371
  let funcName = func.text;
@@ -60,7 +60,6 @@ function getCommentPrefix(style) {
60
60
  return "#";
61
61
  case "dash":
62
62
  return "--";
63
- case "slash":
64
63
  default:
65
64
  return "//";
66
65
  }
@@ -85,8 +84,6 @@ function getCommentStyle(langId) {
85
84
  * Format the skeleton file header comment.
86
85
  */
87
86
  function formatSkeletonHeader(filePath, tokenEstimate, langId) {
88
- const prefix = langId
89
- ? getCommentPrefix(getCommentStyle(langId))
90
- : "//";
87
+ const prefix = langId ? getCommentPrefix(getCommentStyle(langId)) : "//";
91
88
  return `${prefix} ${filePath} (skeleton, ~${tokenEstimate} tokens)`;
92
89
  }