@toolbaux/guardian 0.1.21 → 0.1.22

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.
@@ -311,30 +311,63 @@ async function search(args) {
311
311
  // Frontend pages: match path or component
312
312
  const pages = (d.frontend_pages || []).filter((p) => p.path?.toLowerCase().includes(q) || p.component?.toLowerCase().includes(q) ||
313
313
  p.api_calls?.some((c) => c.toLowerCase().includes(q))).slice(0, 5).map((p) => `${p.path} → ${p.component}`);
314
- // Functions: search literal_index (tactic:simp, sorry, string patterns) + function names
314
+ // Functions: ranked search across names, literals, calls capped at 10 to prevent flooding
315
315
  const fnHits = [];
316
316
  const fi = await loadFuncIntel();
317
317
  if (fi) {
318
- // Literal index: exact key match + partial key match
318
+ // Build a field map: file field names (augments fn hits with model fields)
319
+ const fileToFields = new Map();
320
+ for (const m of Object.values(d.model_registry || {})) {
321
+ if (!m.file)
322
+ continue;
323
+ const existing = fileToFields.get(m.file) ?? [];
324
+ fileToFields.set(m.file, [...existing, ...(m.fields ?? [])]);
325
+ }
326
+ const scored = [];
327
+ const seen = new Set();
328
+ for (const fn of (fi.functions ?? [])) {
329
+ const nameNorm = (fn.name ?? "").toLowerCase();
330
+ const fileNorm = (fn.file ?? "").toLowerCase();
331
+ const callsNorm = (fn.calls ?? []).map((c) => c.toLowerCase());
332
+ const litsNorm = [...(fn.stringLiterals ?? []), ...(fn.regexPatterns ?? [])].map((l) => l.toLowerCase());
333
+ let score = 0;
334
+ if (nameNorm === q)
335
+ score = 1.0;
336
+ else if (nameNorm.includes(q))
337
+ score = 0.7;
338
+ else if (callsNorm.some((c) => c.includes(q)))
339
+ score = 0.5;
340
+ else if (litsNorm.some((l) => l.includes(q)))
341
+ score = 0.3;
342
+ else if (fileNorm.includes(q))
343
+ score = 0.2;
344
+ if (score > 0) {
345
+ scored.push({ fn, score });
346
+ seen.add(`${fn.file}:${fn.name}`);
347
+ }
348
+ }
349
+ // Also surface literal_index hits not already captured
319
350
  const litIndex = fi.literal_index ?? {};
320
351
  for (const [key, hits] of Object.entries(litIndex)) {
321
- if (key.includes(q)) {
322
- for (const h of hits.slice(0, 3)) {
323
- fnHits.push(`${h.function} [${h.file}:${h.line}] (lit:${key})`);
324
- }
352
+ if (!key.includes(q))
353
+ continue;
354
+ for (const h of hits) {
355
+ const uid = `${h.file}:${h.function}`;
356
+ if (seen.has(uid))
357
+ continue;
358
+ seen.add(uid);
359
+ const fn = fi.functions.find((f) => f.file === h.file && f.name === h.function);
360
+ scored.push({ fn: fn ?? { name: h.function, file: h.file, lines: [h.line, h.line], calls: [], stringLiterals: [], regexPatterns: [] }, score: 0.25 });
325
361
  }
326
- if (fnHits.length >= 10)
327
- break;
328
362
  }
329
- // Function names: match by name
330
- if (fnHits.length < 10) {
331
- for (const fn of (fi.functions ?? [])) {
332
- if (fn.name?.toLowerCase().includes(q)) {
333
- fnHits.push(`${fn.name} [${fn.file}:${fn.lines?.[0]}]`);
334
- if (fnHits.length >= 10)
335
- break;
336
- }
337
- }
363
+ // Sort by score desc, take top 10
364
+ scored.sort((a, b) => b.score - a.score);
365
+ const projectRoot = process.cwd();
366
+ for (const { fn } of scored.slice(0, 10)) {
367
+ const relFile = fn.file?.startsWith("/") ? require("path").relative(projectRoot, fn.file) : fn.file;
368
+ const fields = fileToFields.get(fn.file) ?? [];
369
+ const fieldSuffix = fields.length > 0 ? ` fields:${fields.slice(0, 5).join(",")}` : "";
370
+ fnHits.push(`${fn.name} [${relFile}:${fn.lines?.[0]}]${fieldSuffix}`);
338
371
  }
339
372
  }
340
373
  return compact({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@toolbaux/guardian",
3
- "version": "0.1.21",
3
+ "version": "0.1.22",
4
4
  "type": "module",
5
5
  "description": "Architectural intelligence for codebases. Verify that AI-generated code matches your architectural intent.",
6
6
  "keywords": [