@panaversity/ksor 0.0.39 → 0.0.41
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 +965 -0
- package/README.md +29 -9
- package/dist/checker/check-main.mjs +14049 -0
- package/dist/cli.mjs +11528 -5213
- package/dist/gateway-api-CF4ED9_g-BQusM_dK.mjs +10895 -0
- package/dist/gateway.d.mts +52 -13
- package/dist/gateway.mjs +2 -2
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{src-pl4aOpVs.mjs → src-dqpI-p1a.mjs} +1 -0
- package/docs/authorization.md +8 -6
- package/docs/deploying.md +36 -25
- package/docs/index.md +26 -13
- package/docs/ingesting.md +70 -22
- package/docs/tool-surface.md +69 -16
- package/package.json +4 -3
- package/schema/migrations/2.4-2.5__okf-profile.sql +114 -0
- package/schema/schema.sql +77 -14
- package/templates/scaffold/.agents/skills/add-sources/SKILL.md +63 -18
- package/templates/scaffold/.agents/skills/format-checker/SKILL.md +42 -33
- package/templates/scaffold/.agents/skills/format-checker/check.mjs +13827 -1314
- package/templates/scaffold/.agents/skills/intake-interview/SKILL.md +65 -27
- package/templates/scaffold/.agents/skills/make-slides/SKILL.md +7 -5
- package/templates/scaffold/.agents/skills/make-summary/SKILL.md +13 -6
- package/templates/scaffold/.claude/skills/add-sources/SKILL.md +63 -18
- package/templates/scaffold/.claude/skills/format-checker/SKILL.md +42 -33
- package/templates/scaffold/.claude/skills/format-checker/check.mjs +13827 -1314
- package/templates/scaffold/.claude/skills/intake-interview/SKILL.md +65 -27
- package/templates/scaffold/.claude/skills/make-slides/SKILL.md +7 -5
- package/templates/scaffold/.claude/skills/make-summary/SKILL.md +13 -6
- package/templates/scaffold/.github/workflows/validate.yml +9 -1
- package/templates/scaffold/.ksor/governance.yaml +17 -0
- package/templates/scaffold/AGENTS.md +293 -119
- package/templates/scaffold/Dockerfile +5 -1
- package/templates/scaffold/README.md +160 -42
- package/templates/scaffold/env.example +37 -6
- package/templates/scaffold/gitignore +14 -6
- package/templates/scaffold/instance.md +21 -17
- package/templates/scaffold/knowledge/governance-ladder.md +11 -2
- package/templates/scaffold/knowledge/index.md +9 -0
- package/templates/scaffold/knowledge/surfaces/for-agents.md +13 -6
- package/templates/scaffold/knowledge/surfaces/for-people.md +7 -6
- package/templates/scaffold/knowledge/surfaces/index.md +4 -20
- package/templates/scaffold/knowledge/surfaces/overview.md +25 -0
- package/templates/scaffold/knowledge/what-is-a-ksor.md +6 -5
- package/templates/scaffold/knowledge/what-is-a-ksor.summary.md +4 -0
- package/templates/scaffold/package.json +3 -4
- package/templates/scaffold/pnpm-lock.yaml +3 -0
- package/templates/scaffold/system/gateways/content.ts +13 -0
- package/templates/scaffold/system/site/app/(home)/page.tsx +2 -2
- package/templates/scaffold/system/site/app/.well-known/mcp/server.json/route.ts +10 -0
- package/templates/scaffold/system/site/app/docs/[[...slug]]/page.tsx +134 -91
- package/templates/scaffold/system/site/app/global.css +198 -6
- package/templates/scaffold/system/site/app/layout.tsx +8 -3
- package/templates/scaffold/system/site/app/llms-full.txt/route.ts +13 -7
- package/templates/scaffold/system/site/app/llms.txt/route.ts +12 -7
- package/templates/scaffold/system/site/app/md/[[...slug]]/route.ts +26 -25
- package/templates/scaffold/system/site/components/code-block.tsx +87 -0
- package/templates/scaffold/system/site/components/embed.tsx +276 -0
- package/templates/scaffold/system/site/components/footer-mark.tsx +3 -2
- package/templates/scaffold/system/site/components/governance.tsx +219 -87
- package/templates/scaffold/system/site/components/mdx.tsx +10 -2
- package/templates/scaffold/system/site/components/record-index.tsx +5 -5
- package/templates/scaffold/system/site/components/record-stack.tsx +10 -9
- package/templates/scaffold/system/site/components/record-views.tsx +6 -17
- package/templates/scaffold/system/site/components/sidebar-status.tsx +19 -18
- package/templates/scaffold/system/site/lib/alert-rule.ts +214 -0
- package/templates/scaffold/system/site/lib/attachment-rule.ts +6 -1
- package/templates/scaffold/system/site/lib/attachments.ts +0 -28
- package/templates/scaffold/system/site/lib/audience-rule.ts +15 -21
- package/templates/scaffold/system/site/lib/audience.ts +42 -146
- package/templates/scaffold/system/site/lib/embed-rule.ts +255 -0
- package/templates/scaffold/system/site/lib/governance.ts +339 -225
- package/templates/scaffold/system/site/lib/index-routes.ts +125 -0
- package/templates/scaffold/system/site/lib/lifecycle-rule.ts +52 -0
- package/templates/scaffold/system/site/lib/lock.ts +282 -0
- package/templates/scaffold/system/site/lib/order-rule.ts +37 -0
- package/templates/scaffold/system/site/lib/record-href.ts +68 -0
- package/templates/scaffold/system/site/lib/record-link.tsx +26 -0
- package/templates/scaffold/system/site/lib/rules-version.ts +11 -0
- package/templates/scaffold/system/site/lib/shared.ts +67 -104
- package/templates/scaffold/system/site/lib/sim-rule.ts +49 -0
- package/templates/scaffold/system/site/lib/source.ts +256 -186
- package/templates/scaffold/system/site/lib/stage-knowledge.ts +638 -467
- package/templates/scaffold/system/site/lib/stage-manifest.ts +128 -0
- package/templates/scaffold/system/site/package.json +1 -0
- package/templates/scaffold/system/site/record/actor.ts +23 -0
- package/templates/scaffold/system/site/record/check.ts +571 -0
- package/templates/scaffold/system/site/record/citations.ts +312 -0
- package/templates/scaffold/system/site/record/frontmatter.ts +134 -0
- package/templates/scaffold/system/site/record/git-ledger.ts +171 -0
- package/templates/scaffold/system/site/record/hygiene.ts +320 -0
- package/templates/scaffold/system/site/record/index-file.ts +150 -0
- package/templates/scaffold/system/site/record/index.ts +103 -0
- package/templates/scaffold/system/site/record/instance.ts +257 -0
- package/templates/scaffold/system/site/record/instant.ts +43 -0
- package/templates/scaffold/system/site/record/ledger.ts +694 -0
- package/templates/scaffold/system/site/record/load.ts +129 -0
- package/templates/scaffold/system/site/record/lock.ts +306 -0
- package/templates/scaffold/system/site/record/near-miss.ts +37 -0
- package/templates/scaffold/system/site/record/policy.ts +414 -0
- package/templates/scaffold/system/site/record/profile.ts +535 -0
- package/templates/scaffold/system/site/record/refusal.ts +106 -0
- package/templates/scaffold/system/site/record/yaml-file.ts +103 -0
- package/templates/scaffold/system/site/source.config.ts +109 -23
- package/dist/gateway-api-CmIthmJS-IUA9qS-T.mjs +0 -3225
- package/templates/scaffold/system/site/lib/denial-rule.ts +0 -220
- package/templates/scaffold/system/site/lib/page-order.ts +0 -93
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One reader for the control files beside the bundle (`.ksor/*.yaml`): the
|
|
3
|
+
* same parser posture as a concept's frontmatter — one document, unique keys,
|
|
4
|
+
* plain data throughout, a mapping at the root — refused under the file's own
|
|
5
|
+
* slug.
|
|
6
|
+
*
|
|
7
|
+
* Every clause of that posture was re-probed against `yaml` 2.9.0 on
|
|
8
|
+
* 2026-08-25, because the previous wording listed `schema: "core"` among them
|
|
9
|
+
* as though it were a safety property. What the options really buy:
|
|
10
|
+
*
|
|
11
|
+
* - `uniqueKeys` makes a repeated key an ERROR, so a second `takedown_authorities:`
|
|
12
|
+
* cannot quietly win over the first.
|
|
13
|
+
* - An unknown tag (`!Foo`) is an error, so nothing resolves through a handler
|
|
14
|
+
* this codebase never wrote.
|
|
15
|
+
* - An alias bomb throws at `toJS()` ("Excessive alias count"), which the
|
|
16
|
+
* `catch` turns into a refusal rather than a hung process.
|
|
17
|
+
* - `schema: "core"` decides how PLAIN scalars resolve — `.inf` is a number,
|
|
18
|
+
* `2026-01-01` stays a string — and that is all it decides. It does NOT
|
|
19
|
+
* refuse the YAML 1.1 type tags: `!!binary` resolves to a Buffer, `!!set` to
|
|
20
|
+
* a Set and `!!omap` to a Map, with no error and no warning. The root-only
|
|
21
|
+
* mapping check never looked at a value, so a control file could carry an
|
|
22
|
+
* object no rule here is written against — `Policy.raw` is published
|
|
23
|
+
* verbatim — which is why `firstNonPlain` walks the whole document.
|
|
24
|
+
* - `__proto__` needs no defence and gets none: `yaml` assigns through
|
|
25
|
+
* `Object.defineProperty`, so it lands as an ordinary own key and the global
|
|
26
|
+
* prototype is untouched. Pinned in the tests, not asserted here.
|
|
27
|
+
*/
|
|
28
|
+
import { parseAllDocuments } from "yaml";
|
|
29
|
+
|
|
30
|
+
import type { Refusal, RefusalSlug } from "./refusal";
|
|
31
|
+
|
|
32
|
+
export type YamlFileResult =
|
|
33
|
+
| { readonly ok: true; readonly value: Readonly<Record<string, unknown>> }
|
|
34
|
+
| { readonly ok: false; readonly refusals: readonly Refusal[] };
|
|
35
|
+
|
|
36
|
+
const SHAPE_FIX = "fix the YAML so the file is one mapping of the keys the spec names";
|
|
37
|
+
|
|
38
|
+
export function parseYamlFile(text: string, path: string, slug: RefusalSlug): YamlFileResult {
|
|
39
|
+
const refuse = (why: string, fix: string = SHAPE_FIX): YamlFileResult => ({
|
|
40
|
+
ok: false,
|
|
41
|
+
refusals: [{ slug, path, why, fix }],
|
|
42
|
+
});
|
|
43
|
+
let value: unknown;
|
|
44
|
+
try {
|
|
45
|
+
const docs = parseAllDocuments(text.replace(/^\uFEFF/, ""), {
|
|
46
|
+
schema: "core",
|
|
47
|
+
uniqueKeys: true,
|
|
48
|
+
logLevel: "silent",
|
|
49
|
+
});
|
|
50
|
+
if (docs.length > 1) return refuse("the file holds more than one YAML document");
|
|
51
|
+
const problem = docs[0]?.errors[0] ?? docs[0]?.warnings[0];
|
|
52
|
+
if (problem !== undefined) {
|
|
53
|
+
return refuse(`not valid YAML: ${problem.message.split("\n")[0] ?? ""}`);
|
|
54
|
+
}
|
|
55
|
+
value = docs[0]?.toJS();
|
|
56
|
+
} catch (error) {
|
|
57
|
+
const first = String(error).split("\n")[0] ?? "";
|
|
58
|
+
return refuse(`not valid YAML: ${first.replace(/^\w*Error: /, "")}`);
|
|
59
|
+
}
|
|
60
|
+
if (value === null || value === undefined) value = {};
|
|
61
|
+
if (!isPlainMapping(value)) return refuse("the file is not a mapping at its root");
|
|
62
|
+
const tagged = firstNonPlain(value, "");
|
|
63
|
+
if (tagged !== null) {
|
|
64
|
+
return refuse(
|
|
65
|
+
`the value at \`${tagged}\` is not plain data — a \`!!tag\` turned it into something no reader expects`,
|
|
66
|
+
"write strings, numbers, booleans, lists and mappings only; timestamps stay quoted strings",
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
return { ok: true, value };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function isPlainMapping(value: unknown): value is Record<string, unknown> {
|
|
73
|
+
if (typeof value !== "object" || value === null) return false;
|
|
74
|
+
const proto: unknown = Object.getPrototypeOf(value);
|
|
75
|
+
return proto === Object.prototype || proto === null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Path of the first value that is neither a scalar, an array nor a plain
|
|
80
|
+
* mapping — `null` when all are. One walk, shared with `splitFrontmatter`: the
|
|
81
|
+
* frontmatter reader grew it first, and a control file that decides authority
|
|
82
|
+
* and denial is the last place to enforce a weaker rule than a document's own
|
|
83
|
+
* header does.
|
|
84
|
+
*/
|
|
85
|
+
export function firstNonPlain(value: unknown, at: string): string | null {
|
|
86
|
+
if (value === null) return null;
|
|
87
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
if (Array.isArray(value)) {
|
|
91
|
+
for (const [i, item] of value.entries()) {
|
|
92
|
+
const hit = firstNonPlain(item, `${at}[${i}]`);
|
|
93
|
+
if (hit !== null) return hit;
|
|
94
|
+
}
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
if (!isPlainMapping(value)) return at === "" ? "(root)" : at;
|
|
98
|
+
for (const [key, item] of Object.entries(value)) {
|
|
99
|
+
const hit = firstNonPlain(item, at === "" ? key : `${at}.${key}`);
|
|
100
|
+
if (hit !== null) return hit;
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
1
3
|
import { defineCollections, defineConfig, defineDocs } from "fumadocs-mdx/config";
|
|
4
|
+
import { rehypeCodeDefaultOptions } from "fumadocs-core/mdx-plugins";
|
|
2
5
|
import { remarkCodeTab } from "fumadocs-core/mdx-plugins/remark-code-tab";
|
|
6
|
+
import { rehypeGithubAlerts } from "./lib/alert-rule";
|
|
7
|
+
import { rehypeEmbeds } from "./lib/embed-rule";
|
|
3
8
|
import { metaSchema, pageSchema } from "fumadocs-core/source/schema";
|
|
4
9
|
import { z } from "zod";
|
|
5
10
|
import { DeckSchema } from "./lib/deck";
|
|
@@ -7,40 +12,50 @@ import { QuizSchema } from "./lib/quiz";
|
|
|
7
12
|
import { SlidesSchema } from "./lib/slides";
|
|
8
13
|
import { isAttachment } from "./lib/attachment-rule";
|
|
9
14
|
import { rehypeTeachingAid } from "./lib/teaching-aid-rule";
|
|
15
|
+
import { STAGE_DIR } from "./lib/stage-manifest";
|
|
10
16
|
import { knowledgeSourceDir } from "./lib/stage-knowledge";
|
|
11
17
|
|
|
12
|
-
// The record lives at <repo>/knowledge — two levels up from this site.
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
//
|
|
18
|
+
// The record lives at <repo>/knowledge — two levels up from this site. The
|
|
19
|
+
// profile's governance frontmatter (record spec §2) is tolerated on top of
|
|
20
|
+
// the default page schema so a governed document always renders; the record
|
|
21
|
+
// checker, which staging runs, is what enforces it.
|
|
16
22
|
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
23
|
+
// The documents this build's viewer may see (and the assets they reference)
|
|
24
|
+
// are staged into a filtered copy FIRST, for EVERY build, and this is where
|
|
25
|
+
// that copy is chosen: one directory, one filter, every surface downstream.
|
|
26
|
+
// See lib/stage-knowledge.ts.
|
|
21
27
|
export const docs = defineDocs({
|
|
22
28
|
dir: knowledgeSourceDir(),
|
|
23
29
|
docs: {
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
//
|
|
27
|
-
//
|
|
28
|
-
// every surface at once. Doing it
|
|
29
|
-
// research/visibility.md §4-§5 is cited
|
|
30
|
-
// even sufficient, because
|
|
31
|
-
//
|
|
32
|
-
|
|
30
|
+
// TWO exclusions, and they are the whole of "an attachment is not a
|
|
31
|
+
// document" and "an index is not a document". The route table, the
|
|
32
|
+
// sidebar, llms.txt, llms-full.txt, /md/, the search index and the badge
|
|
33
|
+
// map ALL read `source`, and `source` reads exactly this collection — so
|
|
34
|
+
// subtracting here subtracts from every surface at once. Doing it
|
|
35
|
+
// per-surface is the failure mode research/visibility.md §4-§5 is cited
|
|
36
|
+
// for; pruning the page tree is not even sufficient, because the search
|
|
37
|
+
// index never consults the tree. The regenerated `index.md` is rendered by
|
|
38
|
+
// the folder page component instead (record spec §1: no route, no twin,
|
|
39
|
+
// no llms.txt line — it carries no governance to publish under).
|
|
40
|
+
// `.md` only: the record is CommonMark (record spec §1), the checker
|
|
41
|
+
// refuses an `.mdx` under knowledge/ by name (`ksor-file-type`), and
|
|
42
|
+
// staging copies nothing else — so an `.mdx` pattern here advertised a
|
|
43
|
+
// shape the stage can never contain.
|
|
44
|
+
files: ["**/*.md", "!**/*.summary.md", "!**/index.md"],
|
|
33
45
|
schema: pageSchema
|
|
34
46
|
.extend({
|
|
47
|
+
type: z.string().optional(),
|
|
35
48
|
status: z.string().optional(),
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
superseded_by: z.string().optional(),
|
|
49
|
+
order: z.number().optional(),
|
|
50
|
+
ksor: z.record(z.string(), z.any()).optional(),
|
|
39
51
|
})
|
|
40
52
|
.catchall(z.any()),
|
|
41
53
|
postprocess: {
|
|
42
|
-
// Exposes each page's processed markdown
|
|
43
|
-
//
|
|
54
|
+
// Exposes each page's processed markdown, for the page's reading time.
|
|
55
|
+
// NOT for the machine surfaces: `/md/` and `llms-full.txt` republish the
|
|
56
|
+
// STAGED bytes, because the processed markdown is the mdast serialized
|
|
57
|
+
// after every remark plugin has run and carries this shell's rendering
|
|
58
|
+
// rather than the record's grammar (lib/stage-manifest.ts, `stagedBody`).
|
|
44
59
|
includeProcessedMarkdown: true,
|
|
45
60
|
},
|
|
46
61
|
},
|
|
@@ -117,13 +132,84 @@ export const slides = defineCollections({
|
|
|
117
132
|
|
|
118
133
|
export default defineConfig({
|
|
119
134
|
mdxOptions: {
|
|
135
|
+
/**
|
|
136
|
+
* A bundle-absolute image (``) resolves against the
|
|
137
|
+
* STAGE, which is where `/`-rooted links resolve everywhere else in the
|
|
138
|
+
* record.
|
|
139
|
+
*
|
|
140
|
+
* OKF §6.1 allows both link forms and record spec §2.3 says the record
|
|
141
|
+
* carries both, so the checker accepts `/chart.png` and staging copies the
|
|
142
|
+
* file to `.staged-knowledge/chart.png`. fumadocs' `remarkImage` is applied
|
|
143
|
+
* by default and resolves a `/`-rooted src against `<cwd>/public` — a
|
|
144
|
+
* directory this scaffold does not have — so it emitted
|
|
145
|
+
* `import __img0 from "../../public/chart.png"` and the export died with
|
|
146
|
+
* "Module not found" naming a path that exists nowhere in the record. Two
|
|
147
|
+
* halves of one pipeline resolving the same string against two roots; this
|
|
148
|
+
* gives them one root. Absolute, because `remarkImage` joins it with the
|
|
149
|
+
* src and then takes a path RELATIVE to the document's directory.
|
|
150
|
+
*/
|
|
151
|
+
remarkImageOptions: { publicDir: path.resolve(process.cwd(), STAGE_DIR) },
|
|
152
|
+
/**
|
|
153
|
+
* A fence in a language the highlighter does not carry renders as PLAIN
|
|
154
|
+
* TEXT rather than failing the build.
|
|
155
|
+
*
|
|
156
|
+
* A record is not a code project: an author writing ```promql, ```logql or
|
|
157
|
+
* ```gotemplate is describing their own stack, and shiki throws on a
|
|
158
|
+
* language it has no grammar for. Without this, one fence anywhere in the
|
|
159
|
+
* record takes the whole site down with a stack trace naming a file in
|
|
160
|
+
* node_modules — found live on a real 187-document handbook, where three
|
|
161
|
+
* such languages appeared across 3,000 fences.
|
|
162
|
+
*
|
|
163
|
+
* `lazy` so only the grammars a record actually uses are loaded, which is
|
|
164
|
+
* also what keeps that first unknown fence from being fatal.
|
|
165
|
+
*
|
|
166
|
+
* The defaults are SPREAD, not replaced: `RehypeCodeOptions` is a full
|
|
167
|
+
* options object (it requires `themes`), so passing the two keys alone
|
|
168
|
+
* type-errors on a manager that resolves fumadocs fresh rather than from
|
|
169
|
+
* the pinned lockfile — found in CI on the npm and bun scaffolds, which
|
|
170
|
+
* ship no lockfile by design (decision 25).
|
|
171
|
+
*/
|
|
172
|
+
rehypeCodeOptions: {
|
|
173
|
+
...rehypeCodeDefaultOptions,
|
|
174
|
+
lazy: true,
|
|
175
|
+
fallbackLanguage: "text",
|
|
176
|
+
},
|
|
120
177
|
/**
|
|
121
178
|
* WHERE the teaching aid sits: after the document's introduction, which
|
|
122
179
|
* is everything before its first `##` section. The plugin only marks the
|
|
123
180
|
* place; the page decides whether there is a deck to put there. See
|
|
124
181
|
* lib/teaching-aid-rule.ts.
|
|
125
182
|
*/
|
|
126
|
-
rehypePlugins: [
|
|
183
|
+
rehypePlugins: [
|
|
184
|
+
[rehypeTeachingAid, { isAttachment }],
|
|
185
|
+
/**
|
|
186
|
+
* A passage the reader must not miss, as a CALLOUT.
|
|
187
|
+
*
|
|
188
|
+
* GitHub's alert syntax: a blockquote whose first line is `[!WARNING]`.
|
|
189
|
+
* GitHub renders it as a styled alert, every other viewer renders an
|
|
190
|
+
* ordinary blockquote carrying a visible label, and it reaches `/md/`
|
|
191
|
+
* and `llms-full.txt` as the author's blockquote rather than as markup.
|
|
192
|
+
*
|
|
193
|
+
* Not `:::warning`. fumadocs ships `remarkAdmonition` for that form and
|
|
194
|
+
* deprecates it in favour of a `remark-directive` setup — but the deeper
|
|
195
|
+
* objection is that `:::` is a dialect, and a record written in one
|
|
196
|
+
* renders as literal punctuation everywhere it is read outside this site.
|
|
197
|
+
*
|
|
198
|
+
* REHYPE rather than remark, and lib/alert-rule.ts records why: the
|
|
199
|
+
* record's markdown is serialized from the mdast, so converting there
|
|
200
|
+
* publishes this site's React component to the agent surface.
|
|
201
|
+
*/
|
|
202
|
+
rehypeGithubAlerts,
|
|
203
|
+
/**
|
|
204
|
+
* An interactive page the document points at, as a click-to-load
|
|
205
|
+
* frame. Authored as an ordinary link titled `embed`, so the record
|
|
206
|
+
* stays CommonMark and every other reader of it sees a link.
|
|
207
|
+
*
|
|
208
|
+
* REHYPE, so `/md/` and `llms-full.txt` keep the author's link
|
|
209
|
+
* rather than this site's component. See lib/embed-rule.ts.
|
|
210
|
+
*/
|
|
211
|
+
rehypeEmbeds,
|
|
212
|
+
],
|
|
127
213
|
/**
|
|
128
214
|
* Alternative versions of the same instruction, as TABS.
|
|
129
215
|
*
|