akm-cli
Version:
akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cur
82 lines (81 loc) • 3.03 kB
JavaScript
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
/**
* Return per-field search text for multi-column FTS5 indexing.
*
* Text keeps its case: FTS5's `unicode61` tokenizer folds case itself, and
* `buildSearchText` feeds the embedder, where case carries meaning.
*
* Fields:
* - name: entry name with hyphens/underscores replaced by spaces
* - description: entry description
* - tags: tags + aliases joined
* - hints: searchHints + examples + usage + intent fields
* - content: bounded native/adapter body projection + TOC headings + parameters
* (lowest-weight catch-all)
*/
export function buildSearchFields(entry) {
const name = entry.name.replace(/[-_]/g, " ");
const description = entry.description ?? "";
const tagParts = [];
if (entry.tags)
tagParts.push(entry.tags.join(" "));
if (entry.aliases)
tagParts.push(entry.aliases.join(" "));
const tags = tagParts.join(" ");
const hintParts = [];
if (entry.hints)
hintParts.push(entry.hints.join(" "));
if (entry.searchHints)
hintParts.push(entry.searchHints.join(" "));
if (entry.examples)
hintParts.push(entry.examples.join(" "));
if (entry.usage)
hintParts.push(entry.usage.join(" "));
if (entry.intent) {
if (entry.intent.when)
hintParts.push(entry.intent.when);
if (entry.intent.input)
hintParts.push(entry.intent.input);
if (entry.intent.output)
hintParts.push(entry.intent.output);
}
if (entry.xrefs)
hintParts.push(entry.xrefs.join(" "));
if (entry.pageKind)
hintParts.push(entry.pageKind);
if (entry.whenToUse)
hintParts.push(entry.whenToUse);
const hints = hintParts.join(" ");
const contentParts = [];
if (entry.toc) {
contentParts.push(entry.toc.map((h) => h.text).join(" "));
}
if (entry.parameters) {
for (const param of entry.parameters) {
contentParts.push(param.name);
if (param.description)
contentParts.push(param.description);
}
}
if (entry.content)
contentParts.push(entry.content);
const content = contentParts.join(" ");
return { name, description, tags, hints, content };
}
/**
* Build a single concatenated search text string for an entry: the text its
* vector is embedded from, derived from the stored document when the entry is
* embedded (`entries.embed_hash` holds its hash).
*/
export function buildSearchText(entry) {
const fields = buildSearchFields(entry);
const structured = [fields.name, fields.description, fields.tags, fields.hints]
.filter((field) => field.length > 0)
.join(" ");
if (!fields.content)
return structured;
const separator = structured ? " " : "";
return `${structured}${separator}${fields.content}`;
}