akm-cli 0.9.15 → 0.9.16-alpha.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.
Files changed (79) hide show
  1. package/CHANGELOG.md +144 -0
  2. package/dist/assets/tasks/core/index-refresh.yml +1 -1
  3. package/dist/cli/retired-commands.js +2 -0
  4. package/dist/cli/unknown-flags.js +36 -3
  5. package/dist/commands/improve/collapse-detector.js +2 -2
  6. package/dist/commands/improve/consolidate.js +6 -4
  7. package/dist/commands/improve/improve-cli.js +1 -1
  8. package/dist/commands/proposal/repository.js +12 -3
  9. package/dist/commands/read/curate.js +34 -44
  10. package/dist/commands/read/search.js +50 -2
  11. package/dist/commands/sources/index-status.js +99 -0
  12. package/dist/commands/sources/info.js +8 -8
  13. package/dist/commands/sources/installed-stashes.js +33 -12
  14. package/dist/commands/sources/source-add.js +21 -6
  15. package/dist/commands/sources/stash-cli.js +119 -111
  16. package/dist/core/adapter/adapters/akm-adapter.js +35 -3
  17. package/dist/core/adapter/adapters/akm-metadata.js +11 -1
  18. package/dist/core/asset/asset-placement.js +35 -0
  19. package/dist/core/config/schema/embedding.js +7 -30
  20. package/dist/core/config/schema/search.js +11 -9
  21. package/dist/core/errors.js +5 -2
  22. package/dist/core/hash.js +18 -0
  23. package/dist/core/maintenance-barrier.js +8 -6
  24. package/dist/core/paths.js +0 -11
  25. package/dist/core/run-lock.js +5 -2
  26. package/dist/core/state/migrations.js +26 -1
  27. package/dist/core/state-db.js +63 -27
  28. package/dist/indexer/drain.js +306 -0
  29. package/dist/indexer/embedding-identity.js +20 -0
  30. package/dist/indexer/enrich.js +260 -0
  31. package/dist/indexer/ensure-index.js +5 -0
  32. package/dist/indexer/index-written-assets.js +133 -171
  33. package/dist/indexer/indexer.js +458 -1621
  34. package/dist/indexer/lookup/adapter-concept-owner.js +19 -5
  35. package/dist/indexer/passes/metadata.js +18 -1
  36. package/dist/indexer/reconcile.js +890 -0
  37. package/dist/indexer/scan/drain-dir.js +27 -70
  38. package/dist/indexer/scan/parse-file.js +66 -0
  39. package/dist/indexer/search/db-search.js +373 -89
  40. package/dist/indexer/search/ranking-contributors.js +21 -16
  41. package/dist/indexer/search/ranking.js +135 -57
  42. package/dist/indexer/units/unit.js +159 -0
  43. package/dist/llm/client.js +10 -1
  44. package/dist/llm/embedder.js +10 -3
  45. package/dist/llm/embedders/provider-limits.js +288 -0
  46. package/dist/llm/embedders/remote.js +133 -104
  47. package/dist/llm/feature-gate.js +4 -2
  48. package/dist/llm/rerank-client.js +3 -3
  49. package/dist/output/shapes/passthrough.js +1 -0
  50. package/dist/output/text/command-format.js +19 -13
  51. package/dist/output/text/helpers.js +1 -1
  52. package/dist/output/text/index.js +5 -2
  53. package/dist/scripts/akm-migrate-node.js +1141 -1237
  54. package/dist/scripts/akm-migrate.js +1141 -1237
  55. package/dist/setup/semantic-assets.js +2 -2
  56. package/dist/setup/steps/connection.js +3 -2
  57. package/dist/storage/repositories/files-repository.js +181 -0
  58. package/dist/storage/repositories/index-connection.js +1 -3
  59. package/dist/storage/repositories/index-entries-repository.js +77 -68
  60. package/dist/storage/repositories/index-entry-schema.js +16 -25
  61. package/dist/storage/repositories/index-fts-repository.js +29 -263
  62. package/dist/storage/repositories/index-meta-repository.js +0 -29
  63. package/dist/storage/repositories/index-schema.js +115 -122
  64. package/dist/storage/repositories/index-utility-repository.js +1 -1
  65. package/dist/storage/repositories/index-vec-repository.js +21 -334
  66. package/dist/storage/repositories/units-repository.js +510 -0
  67. package/docs/migration/release-notes/0.9.15.md +34 -36
  68. package/docs/migration/release-notes/0.9.16.md +110 -0
  69. package/docs/migration/release-notes/README.md +5 -0
  70. package/docs/reference/cli.md +93 -87
  71. package/docs/reference/configuration.md +128 -89
  72. package/docs/reference/data-and-telemetry.md +2 -1
  73. package/package.json +1 -1
  74. package/schemas/akm-config.json +2 -58
  75. package/dist/indexer/index-db-contention.js +0 -56
  76. package/dist/indexer/index-rebuild-lock.js +0 -73
  77. package/dist/indexer/materialize-embeddings.js +0 -771
  78. package/dist/indexer/passes/dir-staleness.js +0 -161
  79. package/dist/storage/repositories/embedding-salvage-repository.js +0 -184
@@ -96,7 +96,7 @@ function inspectCandidate(sourcePath, realRoot, adapterId, candidate) {
96
96
  catch {
97
97
  return undefined;
98
98
  }
99
- return { path: authoredPath, realPath, conceptId: candidate.conceptId, adapterId };
99
+ return { path: authoredPath, realPath, conceptId: candidate.conceptId, adapterId, priority: candidate.priority };
100
100
  }
101
101
  function claimsWithoutContent(adapter, component, owner) {
102
102
  const file = buildFileContext(component.root, owner.path);
@@ -186,16 +186,30 @@ export function resolveAdapterConceptOwner(sourcePath, adapterId, conceptId, opt
186
186
  if (claimsWithoutContent(adapter, component, candidate))
187
187
  ownersByIdentity.set(identity, candidate);
188
188
  }
189
+ // Rank ascending by declared priority first (undefined — no declared rank —
190
+ // compares as 0, so candidates that never opted in keep tying with each
191
+ // other exactly as before this field existed), then by path within a rank
192
+ // for deterministic tie-break output.
189
193
  const owners = [...ownersByIdentity.values()]
190
194
  .filter((owner) => owner.conceptId === resolutionConceptId)
191
- .sort((left, right) => compareCodePoints(left.path, right.path));
195
+ .sort((left, right) => (left.priority ?? 0) - (right.priority ?? 0) || compareCodePoints(left.path, right.path));
192
196
  if (owners.length > 1) {
197
+ // Only owners tied on the BEST (lowest) priority present are competing —
198
+ // a lower-priority owner is shadowed by a higher-priority one that
199
+ // exists, per the adapter's own declared candidate order (#882), not a
200
+ // collision with it. Only a genuine tie at that best priority — e.g. the
201
+ // memory `.md`/`.derived.md` pair resolves here with no throw, while
202
+ // case-only filesystem siblings (same declared rank) still collide.
203
+ const bestPriority = owners[0].priority ?? 0;
204
+ const tied = owners.filter((owner) => (owner.priority ?? 0) === bestPriority);
205
+ if (tied.length === 1)
206
+ return tied[0];
193
207
  if (options?.mode !== "read") {
194
- throw new AdapterConceptCollisionError(adapterId, resolutionConceptId, owners.map((owner) => path.relative(sourcePath, owner.path).replaceAll("\\", "/")));
208
+ throw new AdapterConceptCollisionError(adapterId, resolutionConceptId, tied.map((owner) => path.relative(sourcePath, owner.path).replaceAll("\\", "/")));
195
209
  }
196
- const [winner, ...losers] = owners;
210
+ const [winner, ...losers] = tied;
197
211
  warnOnce(`adapter-concept-collision:${adapterId}:${resolutionConceptId}`, `Adapter "${adapterId}" has multiple physical owners for "${resolutionConceptId}": ` +
198
- `${owners.map((owner) => path.relative(sourcePath, owner.path).replaceAll("\\", "/")).join(", ")}. ` +
212
+ `${tied.map((owner) => path.relative(sourcePath, owner.path).replaceAll("\\", "/")).join(", ")}. ` +
199
213
  `Reading "${path.relative(sourcePath, winner.path).replaceAll("\\", "/")}" and ignoring ` +
200
214
  `${losers.map((owner) => path.relative(sourcePath, owner.path).replaceAll("\\", "/")).join(", ")}.`);
201
215
  return winner;
@@ -1349,7 +1349,24 @@ export function applyPostContributorFields(entry, file, canonicalName, dirPath)
1349
1349
  // filename word. `normalizeTerms` below dedupes author-restated tokens.
1350
1350
  entry.tags = [...(entry.tags ?? []), ...extractDirTagsFromName(canonicalName)];
1351
1351
  entry.tags = normalizeTerms(entry.tags ?? []);
1352
- entry.aliases = mergeAliases(entry.aliases, buildAliases(canonicalName, entry.tags));
1352
+ // fix-ranking-derived-outranks-primary: `.derived` is a structural marker
1353
+ // on a memory's OWN filename (memory-inference.ts's `derivedChildPath`/
1354
+ // `isDerivedByName` convention: `<parent>.derived.md`), not a topical
1355
+ // word — `extractTagsFromPath` above tokenizes on `.` alongside `-`/`_`,
1356
+ // so every derived twin's filename contributes a "derived" tag purely as
1357
+ // an artifact of that convention (kept in `entry.tags` itself; only the
1358
+ // ALIAS input below is filtered, so anything else keyed on the raw tag
1359
+ // set is unaffected). Left in, `buildAliases`' tags.join(" ") mints a
1360
+ // SYNTHETIC "<base> derived" alias purely because tags.length > 1, which
1361
+ // then wins `alias-ranking` credit any time the base name is a query
1362
+ // token — see `exactNameRankingContributor`, which already strips this
1363
+ // exact suffix before treating a derived twin's name as content, for the
1364
+ // identical reason. Scoped to memory so a coincidentally
1365
+ // ".derived"-suffixed asset of another type is untouched.
1366
+ const aliasTagInput = entry.type === "memory" && canonicalName.toLowerCase().endsWith(".derived")
1367
+ ? entry.tags.filter((tag) => tag !== "derived")
1368
+ : entry.tags;
1369
+ entry.aliases = mergeAliases(entry.aliases, buildAliases(canonicalName, aliasTagInput));
1353
1370
  // Search hints are only generated when LLM is configured (via enhanceStashWithLlm)
1354
1371
  // Heuristic search hints are too noisy to be useful for search quality
1355
1372
  entry.filename = path.basename(file);