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
156 lines (155 loc) • 6.48 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/.
/**
* The `website-snapshot` adapter — akm 0.9.0 format-family work item (#46).
*
* A READ-ONLY (Mode A) view over a materialized crawl snapshot written by
* `src/sources/snapshot-fetchers/website-ingest.ts` (spec §6/§7). The on-disk
* pages are KNOWLEDGE-shaped markdown under `stash/knowledge/**` with no `type:`
* field; this adapter RE-TYPES them to the open `type: website`. Per
* open-question-3 (RESOLVED, maintainer 2026-07) the re-type is GATED — it
* applies only to a page carrying the `website` tag / a `sourceUrl` (a page
* lacking both is not re-typed); the document KEEPS its `sourceUrl` (surfaced as
* `sourceRef` on `documentJson`); and the conceptId STRIPS the
* `stash/knowledge/` prefix. `manifest.json` is snapshot PROVENANCE
* (`{url, fetchedAt}`), read by the probe but never indexed as a concept.
*
* Read-only ⇒ NO `placeNew` (Mode B export routes content through the
* DESTINATION adapter, which owns placement). `validate` runs base checks only
* (a mirror the adapter does not author has no native validators); `updated`
* never appears on a snapshot page, so `missing-updated` is filtered out.
*
* Conformance oracle (authored, DO NOT modify): fixture
* `tests/fixtures/bundles/website-snapshot/` + goldens
* `tests/fixtures/format-family-goldens/website-snapshot/{recognition,placement,lint,renderer}.json`.
*/
import fs from "node:fs";
import path from "node:path";
import { parse as parseYaml } from "yaml";
import { parseFrontmatter, parseFrontmatterBlock } from "../../asset/frontmatter.js";
import { toPosix } from "../../common.js";
import { hashContent, nonEmptyString, runBaseValidateChecks } from "./shared.js";
/** A snapshot bundle is single-component; its one component is `main`. */
const COMPONENT_ID = "main";
/** The crawl page root the snapshot writer materializes pages under. */
const PAGES_PREFIX = "stash/knowledge/";
/** The provenance manifest basename (probe marker only, never indexed). */
const MANIFEST_FILE = "manifest.json";
/** The tag the snapshot writer stamps on every crawled page. */
const WEBSITE_TAG = "website";
function parseSnapshotFrontmatter(raw) {
const out = { tags: [] };
const block = parseFrontmatterBlock(raw);
if (!block)
return out;
let data = {};
try {
const value = parseYaml(block.frontmatter);
if (value && typeof value === "object" && !Array.isArray(value))
data = value;
}
catch {
return out;
}
out.title = nonEmptyString(data.title);
out.description = nonEmptyString(data.description);
out.sourceUrl = nonEmptyString(data.sourceUrl);
if (Array.isArray(data.tags)) {
out.tags = data.tags.filter((t) => typeof t === "string" && t.trim().length > 0).map((t) => t.trim());
}
return out;
}
/** True when a page is a crawl snapshot page under `stash/knowledge/**`. */
function isSnapshotPage(relPath) {
const posix = toPosix(relPath);
return posix.startsWith(PAGES_PREFIX) && posix.toLowerCase().endsWith(".md");
}
/** The GATED re-type predicate (open-question-3): the page carries the `website` tag OR a `sourceUrl`. */
function isReTypeGated(fm) {
return fm.sourceUrl !== undefined || fm.tags.includes(WEBSITE_TAG);
}
/** conceptId = page path − `stash/knowledge/` prefix − `.md`. */
function conceptIdOf(relPath) {
return toPosix(relPath).slice(PAGES_PREFIX.length).replace(/\.md$/i, "");
}
function recognize(c, file) {
if (file.ext !== ".md" || !isSnapshotPage(file.relPath))
return null;
const raw = file.content();
const fm = parseSnapshotFrontmatter(raw);
if (!isReTypeGated(fm))
return null; // not a re-typed website page
const conceptId = conceptIdOf(file.relPath);
const name = fm.title ?? conceptId.split("/").pop() ?? conceptId;
const body = parseFrontmatter(raw).content;
const doc = {
ref: `${c.id}//${conceptId}`,
bundle: c.id,
component: COMPONENT_ID,
conceptId,
path: file.absPath,
hash: hashContent(raw),
adapterId: "website-snapshot",
ownsPresentation: true,
type: "website",
name,
content: body,
};
if (fm.description !== undefined)
doc.description = fm.description;
if (fm.sourceUrl !== undefined)
doc.documentJson = { sourceRef: fm.sourceUrl };
return doc;
}
async function validate(c, changes, ctx) {
const diagnostics = [];
for (const change of changes) {
if (change.op === "delete")
continue;
const raw = change.after ?? (await ctx.readFile(change.path));
if (typeof raw !== "string")
continue;
if (!isSnapshotPage(change.path))
continue;
const base = await runBaseValidateChecks(toPosix(change.path), parseFrontmatter(raw), c.root, ctx);
// A read-only crawl mirror carries `fetchedAt` provenance, never an `updated`
// field — so `missing-updated` is not a defect on a snapshot page.
diagnostics.push(...base.filter((d) => d.issue !== "missing-updated"));
}
return diagnostics;
}
export const websiteSnapshotAdapter = {
id: "website-snapshot",
version: "0.9.0",
extensions: [".md"],
recognize,
validate,
readCandidates(c, conceptId) {
const canonical = toPosix(conceptId).replace(/\.md$/i, "");
return [{ path: path.join(c.root, PAGES_PREFIX, `${canonical}.md`), conceptId: canonical }];
},
// No placeNew: the snapshot is READ-ONLY (Mode A). Export (Mode B) routes
// content through the DESTINATION adapter, which owns placement.
/**
* Install-time probe (§1.2): a root carrying the snapshot provenance
* `manifest.json` (`{url, fetchedAt}`). No other bundle root carries this
* exact marker, so the probe is unambiguous.
*/
looksLikeRoot(root) {
let raw;
try {
raw = fs.readFileSync(path.join(root, MANIFEST_FILE), "utf8");
}
catch {
return false;
}
try {
const manifest = JSON.parse(raw);
return typeof manifest.url === "string" && typeof manifest.fetchedAt === "string";
}
catch {
return false;
}
},
};