akm-cli 0.8.0-rc.10 → 0.8.0-rc.11

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.
@@ -265,8 +265,21 @@ async function searchDatabase(db, query, searchType, limit, stashDir, allSourceD
265
265
  // Default floor: 0.2. Set search.minScore = 0 in config to disable.
266
266
  const minScore = config.search?.minScore ?? 0.2;
267
267
  const preFilter = minScore > 0 ? scored.filter((item) => item.rankingMode !== "semantic" || item.score >= minScore) : scored;
268
- // Deterministic tiebreaker on equal scores
269
- preFilter.sort((a, b) => b.score - a.score || a.entry.name.localeCompare(b.entry.name));
268
+ // Deterministic tiebreaker on equal scores.
269
+ //
270
+ // CRITICAL: sort on the SAME clamped+rounded value the user sees (see the
271
+ // `finalScore`/round-to-4dp logic below at buildDbHit), NOT the raw pre-clamp
272
+ // `item.score`. The boost loop can push scores above 1.0 (utility, graph,
273
+ // project boosts) and carries ~15 significant digits. Two entries that DISPLAY
274
+ // an identical score (e.g. both clamp to 1.0000) can still differ in their raw
275
+ // pre-clamp score by a timing-dependent epsilon — utility recency uses
276
+ // `Date.now()` and `last_used_at`, so the same query run twice in one process
277
+ // can yield raw scores that diverge at the 6th decimal. Sorting on the raw
278
+ // value lets that invisible epsilon decide the order, so the visible name
279
+ // tiebreaker never engages and the order flips run-to-run (Issue #14). Quantize
280
+ // to the display value first; only then does `localeCompare` break true ties.
281
+ const displayScore = (s) => Math.round(Math.min(1, Math.max(0, s)) * 10000) / 10000;
282
+ preFilter.sort((a, b) => displayScore(b.score) - displayScore(a.score) || a.entry.name.localeCompare(b.entry.name));
270
283
  // Deduplicate by file path — keep only the highest-scored entry per file.
271
284
  // Multiple .stash.json entries can map to the same file (e.g. entries without
272
285
  // a filename field all collapse to files[0]). Showing the same path/ref
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akm-cli",
3
- "version": "0.8.0-rc.10",
3
+ "version": "0.8.0-rc.11",
4
4
  "type": "module",
5
5
  "description": "akm (Agent Knowledge Management) — A package manager for AI agent skills, commands, tools, and knowledge. Works with Claude Code, OpenCode, Cursor, and any AI coding assistant.",
6
6
  "keywords": [