akm-cli 0.10.261007-beta → 0.10.261009-beta
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/CHANGELOG.md +72 -0
- package/STABILITY.md +10 -4
- package/dist/api.d.ts +6 -0
- package/dist/api.js +12 -1
- package/dist/assets/prompts/consolidate-pair-check.md +2 -0
- package/dist/assets/prompts/consolidate-pair-same-age.md +1 -0
- package/dist/assets/prompts/consolidate-pair-terms.md +6 -0
- package/dist/assets/prompts/consolidate-pair.md +4 -12
- package/dist/commands/health.js +1 -2
- package/dist/commands/improve/consolidate/pair-pass.js +59 -31
- package/dist/commands/improve/extract.js +18 -12
- package/dist/commands/improve/memory/memory-belief.js +2 -2
- package/dist/commands/proposal/repository.js +44 -13
- package/dist/commands/read/curate.js +77 -18
- package/dist/commands/read/search-cli.js +25 -11
- package/dist/commands/read/search.js +3 -3
- package/dist/commands/read/show.js +47 -1
- package/dist/core/adapter/adapters/akm-adapter.js +1 -0
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +3 -5
- package/dist/core/adapter/adapters/okf-adapter.js +3 -16
- package/dist/core/asset/markdown-link-targets.js +43 -0
- package/dist/core/common.js +17 -2
- package/dist/core/config/config-io.js +14 -4
- package/dist/indexer/passes/metadata.js +17 -0
- package/dist/indexer/scan/doc-to-entry.js +1 -0
- package/dist/indexer/search/db-search.js +16 -7
- package/dist/indexer/search/search-hit-enrichers.js +3 -3
- package/dist/output/shapes/curate.js +3 -1
- package/dist/output/shapes/helpers.js +6 -0
- package/dist/output/text/show-format.js +7 -0
- package/dist/scripts/akm-migrate-node.js +1824 -324
- package/dist/scripts/akm-migrate.js +1824 -324
- package/dist/storage/repositories/index-entries-repository.js +16 -0
- package/dist/storage/repositories/index-fts-repository.js +28 -6
- package/dist/storage/repositories/index-vec-repository.js +19 -3
- package/docs/architecture/0.10-process-rules.md +4 -4
- package/docs/architecture/architecture.md +4 -0
- package/docs/architecture/persisted-data-compat.md +1 -1
- package/docs/reference/api.md +19 -1
- package/docs/reference/cli.md +56 -4
- package/docs/reference/data-and-telemetry.md +1 -1
- package/docs/reference/memory.md +7 -6
- package/package.json +2 -1
|
@@ -22,7 +22,7 @@ import { embed } from "../../llm/embedder.js";
|
|
|
22
22
|
import { applyEmbeddingTemplate, resolveEmbeddingProfile } from "../../llm/embedders/profile.js";
|
|
23
23
|
import { normalizeEmbeddingEndpoint } from "../../llm/embedders/remote.js";
|
|
24
24
|
import { assertIndexPathReadable, closeDatabase, openExistingDatabase, openReadonlyExistingDatabase, } from "../../storage/repositories/index-connection.js";
|
|
25
|
-
import { getAllEntries, getBaseBeliefStatesForDerivedTwins, getEntryById, getEntryCount, getEntryRefsAndTypes, } from "../../storage/repositories/index-entries-repository.js";
|
|
25
|
+
import { getAllEntries, getBaseBeliefStatesForDerivedTwins, getEntriesByIds, getEntryById, getEntryCount, getEntryRefsAndTypes, } from "../../storage/repositories/index-entries-repository.js";
|
|
26
26
|
import { searchFts } from "../../storage/repositories/index-fts-repository.js";
|
|
27
27
|
import { getMeta } from "../../storage/repositories/index-meta-repository.js";
|
|
28
28
|
import { getEmbeddingCount, searchVec } from "../../storage/repositories/index-vec-repository.js";
|
|
@@ -221,8 +221,14 @@ async function searchDatabase(db, input) {
|
|
|
221
221
|
const typeFilter = searchType === "any" ? undefined : searchType;
|
|
222
222
|
const startedAt = Date.now();
|
|
223
223
|
// The query embedding request goes out first, so FTS runs while it is in flight.
|
|
224
|
-
const
|
|
225
|
-
|
|
224
|
+
const filterCandidates = (ids) => {
|
|
225
|
+
const entries = getEntriesByIds(db, ids)
|
|
226
|
+
.filter(hasIndexedProvenance)
|
|
227
|
+
.filter((row) => (typeFilter ? row.entry.type === typeFilter : !defaultExcludes.includes(row.entry.type)));
|
|
228
|
+
return new Set(applyEntryFilters(entries, filterOptions).map((row) => row.id));
|
|
229
|
+
};
|
|
230
|
+
const vectorChannel = startVectorChannel(db, query, config, filterCandidates);
|
|
231
|
+
const lexical = searchFts(db, query, CHANNEL_DEPTH, typeFilter, defaultExcludes, filterCandidates);
|
|
226
232
|
const vector = await vectorChannel;
|
|
227
233
|
const embedMs = Date.now() - startedAt;
|
|
228
234
|
const tRank0 = Date.now();
|
|
@@ -244,6 +250,7 @@ async function searchDatabase(db, input) {
|
|
|
244
250
|
sources,
|
|
245
251
|
config,
|
|
246
252
|
db,
|
|
253
|
+
eligible: (row) => applyEntryFilters([row], filterOptions).length > 0,
|
|
247
254
|
})));
|
|
248
255
|
const mode = vector.warning ? "fts-fallback" : vector.neighbors ? "semantic" : "keyword";
|
|
249
256
|
return { embedMs, rankMs, hits, mode, semanticWarning: vector.warning, feedbackWarning: feedback.warning };
|
|
@@ -371,6 +378,7 @@ async function enumerateEntries(opts) {
|
|
|
371
378
|
sources,
|
|
372
379
|
config,
|
|
373
380
|
db,
|
|
381
|
+
eligible: (row) => applyEntryFilters([row], opts).length > 0,
|
|
374
382
|
})));
|
|
375
383
|
}
|
|
376
384
|
/**
|
|
@@ -378,7 +386,7 @@ async function enumerateEntries(opts) {
|
|
|
378
386
|
* source-narrowing → scope → proposed-quality → derived-twin belief
|
|
379
387
|
* inheritance → belief filter.
|
|
380
388
|
*/
|
|
381
|
-
function applyEntryFilters(items, opts) {
|
|
389
|
+
export function applyEntryFilters(items, opts) {
|
|
382
390
|
const { filters } = opts;
|
|
383
391
|
// Source filter: when the caller narrowed `sources` via `--from <name>`,
|
|
384
392
|
// drop entries whose filePath does not live under any requested source. The
|
|
@@ -428,7 +436,7 @@ function inheritDerivedTwinBeliefStates(db, items) {
|
|
|
428
436
|
}
|
|
429
437
|
}
|
|
430
438
|
}
|
|
431
|
-
function matchBeliefFilter(beliefState, filter) {
|
|
439
|
+
export function matchBeliefFilter(beliefState, filter) {
|
|
432
440
|
if (filter === "all")
|
|
433
441
|
return true;
|
|
434
442
|
// 03: the belief filter applies to ANY flagged entry, not just memories, so
|
|
@@ -452,7 +460,7 @@ function matchBeliefFilter(beliefState, filter) {
|
|
|
452
460
|
* query overlaps it. A slow or failing embedder degrades the search to keyword
|
|
453
461
|
* ranking with a warning after `embedding.queryTimeoutMs`.
|
|
454
462
|
*/
|
|
455
|
-
function startVectorChannel(db, query, config) {
|
|
463
|
+
function startVectorChannel(db, query, config, filterCandidates) {
|
|
456
464
|
if (config.semanticSearchMode === "off")
|
|
457
465
|
return Promise.resolve({ neighbors: null });
|
|
458
466
|
// A real-time completeness fact, not a cached verdict: skip the round trip
|
|
@@ -472,7 +480,7 @@ function startVectorChannel(db, query, config) {
|
|
|
472
480
|
});
|
|
473
481
|
const queryText = applyEmbeddingTemplate(resolveEmbeddingProfile(config.embedding).queryTemplate, query);
|
|
474
482
|
return Promise.race([embed(queryText, config.embedding, controller.signal), timeout])
|
|
475
|
-
.then((vector) => ({ neighbors: searchVec(db, vector, CHANNEL_DEPTH) }))
|
|
483
|
+
.then((vector) => ({ neighbors: searchVec(db, vector, CHANNEL_DEPTH, undefined, filterCandidates) }))
|
|
476
484
|
.catch((error) => ({ neighbors: null, warning: buildVectorFallbackWarning(config, error) }))
|
|
477
485
|
.finally(() => clearTimeout(timer));
|
|
478
486
|
}
|
|
@@ -574,6 +582,7 @@ export async function buildDbHit(input) {
|
|
|
574
582
|
stashDir: entryStashDir,
|
|
575
583
|
bundleId: input.bundleId,
|
|
576
584
|
db: input.db,
|
|
585
|
+
eligible: input.eligible,
|
|
577
586
|
});
|
|
578
587
|
return hit;
|
|
579
588
|
}
|
|
@@ -17,7 +17,7 @@ export async function enrichSearchHit(hit, ctx) {
|
|
|
17
17
|
renderer?.enrichSearchHit?.(hit, ctx.stashDir);
|
|
18
18
|
}
|
|
19
19
|
if (ctx.type === "memory" && ctx.db)
|
|
20
|
-
surfaceDerivedMemory(hit, ctx.db, ctx.bundleId);
|
|
20
|
+
surfaceDerivedMemory(hit, ctx.db, ctx.bundleId, ctx.eligible);
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* Phase 5A / Advantage D5 — when a parent memory has a `.derived` child
|
|
@@ -28,7 +28,7 @@ export async function enrichSearchHit(hit, ctx) {
|
|
|
28
28
|
* The parent ref is preserved on the hit — only the surface text is
|
|
29
29
|
* swapped, so links and provenance still point at the canonical parent.
|
|
30
30
|
*/
|
|
31
|
-
function surfaceDerivedMemory(hit, db, bundleId) {
|
|
31
|
+
function surfaceDerivedMemory(hit, db, bundleId, eligible) {
|
|
32
32
|
// Never recurse: a `.derived` hit is itself the child surface; leaving
|
|
33
33
|
// it untouched also avoids `<parent>.derived.derived` chains.
|
|
34
34
|
if (hit.name.toLowerCase().endsWith(".derived"))
|
|
@@ -38,7 +38,7 @@ function surfaceDerivedMemory(hit, db, bundleId) {
|
|
|
38
38
|
// carries. INTERNAL lookup key into `getDerivedForParent`: the `derived_from`
|
|
39
39
|
// column stores this same conceptId grammar.
|
|
40
40
|
const derived = getDerivedForParent(db, `memories/${hit.name}`, bundleId);
|
|
41
|
-
if (!derived)
|
|
41
|
+
if (!derived || (eligible && !eligible(derived)))
|
|
42
42
|
return;
|
|
43
43
|
// Swap description / tags from the derived child (SourceSearchHit carries no
|
|
44
44
|
// `searchHints`).
|
|
@@ -5,7 +5,7 @@ import { capDescription, NORMAL_DESCRIPTION_LIMIT, pickFields } from "./helpers.
|
|
|
5
5
|
// Curation is a small, high-signal top-N. Even at `brief` we keep `followUp`
|
|
6
6
|
// (the actionable `akm show <ref>` command) and `reason` (why this asset was
|
|
7
7
|
// selected) — these are the point of curate, unlike a bulk search listing.
|
|
8
|
-
const BRIEF_FIELDS = ["source", "type", "name", "ref", "id", "supportRefs", "followUp", "reason"];
|
|
8
|
+
const BRIEF_FIELDS = ["source", "type", "name", "ref", "id", "supportRefs", "beliefState", "followUp", "reason"];
|
|
9
9
|
const NORMAL_FIELDS = [
|
|
10
10
|
"source",
|
|
11
11
|
"type",
|
|
@@ -21,6 +21,7 @@ const NORMAL_FIELDS = [
|
|
|
21
21
|
"parameters",
|
|
22
22
|
"run",
|
|
23
23
|
"supportRefs",
|
|
24
|
+
"beliefState",
|
|
24
25
|
"followUp",
|
|
25
26
|
"reason",
|
|
26
27
|
"score",
|
|
@@ -37,6 +38,7 @@ const AGENT_FIELDS = [
|
|
|
37
38
|
"id",
|
|
38
39
|
"description",
|
|
39
40
|
"supportRefs",
|
|
41
|
+
"beliefState",
|
|
40
42
|
"followUp",
|
|
41
43
|
"reason",
|
|
42
44
|
"score",
|
|
@@ -386,6 +386,9 @@ export function shapeShowOutput(result, detail, shape = "human") {
|
|
|
386
386
|
"steps",
|
|
387
387
|
"keys",
|
|
388
388
|
"links",
|
|
389
|
+
"evidence",
|
|
390
|
+
"evidenceSources",
|
|
391
|
+
"provenance",
|
|
389
392
|
...FRAGMENT_PROVENANCE_FIELDS,
|
|
390
393
|
...FRAGMENT_CONTEXT_FIELDS,
|
|
391
394
|
]);
|
|
@@ -418,6 +421,9 @@ export function shapeShowOutput(result, detail, shape = "human") {
|
|
|
418
421
|
"activeRun",
|
|
419
422
|
"keys",
|
|
420
423
|
"links",
|
|
424
|
+
"evidence",
|
|
425
|
+
"evidenceSources",
|
|
426
|
+
"provenance",
|
|
421
427
|
...FRAGMENT_PROVENANCE_FIELDS,
|
|
422
428
|
...FRAGMENT_CONTEXT_FIELDS,
|
|
423
429
|
// ref, path, and editable are always projected — at every --detail level,
|
|
@@ -20,6 +20,13 @@ export function formatShowPlain(r, detail) {
|
|
|
20
20
|
}
|
|
21
21
|
if (r.description)
|
|
22
22
|
lines.push(`description: ${String(r.description)}`);
|
|
23
|
+
// Evidence is captured text: keep it on one line so it cannot forge other fields.
|
|
24
|
+
if (r.evidence)
|
|
25
|
+
lines.push(`evidence: ${String(r.evidence).replace(/\s+/g, " ")}`);
|
|
26
|
+
if (Array.isArray(r.evidenceSources))
|
|
27
|
+
lines.push(`evidenceSources: ${r.evidenceSources.join(", ")}`);
|
|
28
|
+
if (r.evidence && r.provenance)
|
|
29
|
+
lines.push(`provenance: ${JSON.stringify(r.provenance)}`);
|
|
23
30
|
if (r.workflowTitle)
|
|
24
31
|
lines.push(`workflowTitle: ${String(r.workflowTitle)}`);
|
|
25
32
|
if (r.agent)
|