explico 0.13.1 → 0.15.0
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 +990 -1
- package/README.md +200 -30
- package/dist/compiler/astro.d.ts +15 -2
- package/dist/compiler/astro.js +40 -11
- package/dist/compiler/cli-main.d.ts +100 -0
- package/dist/compiler/cli-main.js +433 -0
- package/dist/compiler/cli-reference.d.ts +50 -0
- package/dist/compiler/cli-reference.js +213 -0
- package/dist/compiler/cli-verbs.d.ts +45 -0
- package/dist/compiler/cli-verbs.js +224 -0
- package/dist/compiler/cli-verify.d.ts +51 -0
- package/dist/compiler/cli-verify.js +151 -0
- package/dist/compiler/cli.d.ts +408 -24
- package/dist/compiler/cli.js +1328 -8
- package/dist/compiler/collections.d.ts +88 -1
- package/dist/compiler/collections.js +170 -25
- package/dist/compiler/content-release.d.ts +49 -0
- package/dist/compiler/content-release.js +63 -0
- package/dist/compiler/content-schemas.d.ts +2 -2
- package/dist/compiler/course-config.d.ts +1 -1
- package/dist/compiler/course-config.js +105 -1
- package/dist/compiler/decks.d.ts +161 -0
- package/dist/compiler/decks.js +235 -0
- package/dist/compiler/exports/combined-html.d.ts +5 -1
- package/dist/compiler/exports/deck-fit.d.ts +55 -0
- package/dist/compiler/exports/deck-fit.js +90 -0
- package/dist/compiler/exports/export-chapters.d.ts +37 -6
- package/dist/compiler/exports/export-chapters.js +64 -5
- package/dist/compiler/exports/export-pages.d.ts +30 -3
- package/dist/compiler/exports/export-pages.js +24 -1
- package/dist/compiler/exports/latex/beamerthemeexplico.sty +124 -0
- package/dist/compiler/exports/latex/cache.d.ts +78 -0
- package/dist/compiler/exports/latex/cache.js +129 -0
- package/dist/compiler/exports/latex/capture.d.ts +10 -1
- package/dist/compiler/exports/latex/capture.js +3 -1
- package/dist/compiler/exports/latex/compile.d.ts +13 -2
- package/dist/compiler/exports/latex/compile.js +12 -1
- package/dist/compiler/exports/latex/deck.d.ts +92 -0
- package/dist/compiler/exports/latex/deck.js +349 -0
- package/dist/compiler/exports/latex/document.d.ts +51 -6
- package/dist/compiler/exports/latex/document.js +71 -12
- package/dist/compiler/exports/latex/explico-common.sty +198 -0
- package/dist/compiler/exports/latex/explico.cls +13 -183
- package/dist/compiler/exports/latex/serialize.d.ts +60 -4
- package/dist/compiler/exports/latex/serialize.js +4 -2
- package/dist/compiler/exports/latex-export.d.ts +24 -2
- package/dist/compiler/exports/latex-export.js +107 -26
- package/dist/compiler/exports/markdown/serialize.d.ts +24 -4
- package/dist/compiler/exports/markdown/serialize.js +85 -8
- package/dist/compiler/exports/markdown-export.d.ts +6 -1
- package/dist/compiler/exports/markdown-export.js +50 -11
- package/dist/compiler/exports/standalone-html.d.ts +10 -5
- package/dist/compiler/exports/standalone-html.js +3 -3
- package/dist/compiler/exports/static-tree.d.ts +38 -1
- package/dist/compiler/exports/static-tree.js +120 -4
- package/dist/compiler/knowledge-version.d.ts +26 -2
- package/dist/compiler/knowledge-version.js +27 -17
- package/dist/compiler/lesson-derivation.d.ts +143 -6
- package/dist/compiler/lesson-derivation.js +145 -13
- package/dist/compiler/manifest.d.ts +133 -4
- package/dist/compiler/manifest.js +364 -58
- package/dist/compiler/page-versions.d.ts +184 -0
- package/dist/compiler/page-versions.js +217 -0
- package/dist/compiler/render-diagnostics.d.ts +5 -1
- package/dist/compiler/resolution-report.d.ts +24 -6
- package/dist/compiler/resolution-report.js +22 -4
- package/dist/compiler/validate-content.d.ts +7 -0
- package/dist/compiler/validate-content.js +160 -0
- package/dist/{course-config-rRtME5UV.d.ts → course-config-BLtIdkei.d.ts} +164 -1
- package/dist/curriculum/competency-graph.d.ts +54 -0
- package/dist/curriculum/competency-graph.js +41 -0
- package/dist/reference/base-library.d.mts +8 -0
- package/dist/reference/base-library.mjs +19 -0
- package/dist/reference/consistency.d.ts +8 -4
- package/dist/reference/consistency.js +82 -26
- package/dist/reference/deck-remark.d.mts +123 -0
- package/dist/reference/deck-remark.mjs +600 -0
- package/dist/reference/deck-source.d.ts +107 -0
- package/dist/reference/deck-source.js +140 -0
- package/dist/reference/decks-validate.d.ts +133 -0
- package/dist/reference/decks-validate.js +359 -0
- package/dist/reference/derived-entries.d.ts +5 -1
- package/dist/reference/diagram-fit.d.ts +6 -2
- package/dist/reference/diagram-fit.js +5 -1
- package/dist/reference/figure-symbols.d.ts +23 -6
- package/dist/reference/figure-symbols.js +51 -15
- package/dist/reference/float-name.d.ts +43 -0
- package/dist/reference/float-name.js +58 -0
- package/dist/reference/folds-validate.d.ts +1 -1
- package/dist/reference/gate-abbreviations.d.ts +1 -1
- package/dist/reference/gate-indices.js +5 -4
- package/dist/reference/gate-math.d.ts +29 -2
- package/dist/reference/gate-math.js +99 -18
- package/dist/reference/gate-part-pages.d.ts +1 -1
- package/dist/reference/lab-katex-validate.d.ts +10 -6
- package/dist/reference/lab-katex-validate.js +17 -9
- package/dist/reference/lab-math-scope.js +29 -4
- package/dist/reference/math-glyphs.d.mts +25 -0
- package/dist/reference/math-glyphs.mjs +189 -25
- package/dist/reference/page-notation.d.ts +22 -3
- package/dist/reference/page-notation.js +32 -10
- package/dist/reference/references.d.ts +14 -1
- package/dist/reference/references.js +13 -0
- package/dist/reference/registry-scope.d.mts +33 -0
- package/dist/reference/registry-scope.mjs +34 -0
- package/dist/reference/registry.js +29 -10
- package/dist/reference/rehype-deck.d.mts +6 -0
- package/dist/reference/rehype-deck.mjs +286 -0
- package/dist/reference/rehype-heading-anchors.d.mts +20 -0
- package/dist/reference/rehype-heading-anchors.mjs +48 -6
- package/dist/reference/remark-notation.mjs +249 -40
- package/dist/reference/source-lines.d.mts +12 -0
- package/dist/reference/source-lines.mjs +65 -0
- package/dist/reference/types.d.ts +28 -0
- package/dist/rules/catalog.d.ts +21 -4
- package/dist/rules/catalog.js +237 -2
- package/dist/rules/course-rules.d.ts +5 -1
- package/dist/rules/course-rules.js +17 -3
- package/dist/rules/course-rules.schema.json +12 -0
- package/dist/rules/in-effect.d.ts +13 -3
- package/dist/rules/in-effect.js +34 -10
- package/dist/rules/rules.schema.json +280 -1
- package/dist/rules/settings.d.ts +1 -1
- package/dist/session/PreferenceStore.d.ts +6 -0
- package/dist/session/PreferenceStore.js +18 -1
- package/dist/session/deck-memory.d.ts +116 -0
- package/dist/session/deck-memory.js +143 -0
- package/dist/session/reading-memory.d.ts +96 -0
- package/dist/session/reading-memory.js +133 -0
- package/docs/VERSIONING.md +21 -18
- package/docs/authoring/README.md +31 -9
- package/docs/authoring/agents.md +72 -18
- package/docs/authoring/cli-reference.json +2172 -0
- package/docs/authoring/cli.md +887 -0
- package/docs/authoring/components.md +15 -0
- package/docs/authoring/deck.md +612 -0
- package/docs/authoring/migrating.md +1195 -16
- package/docs/authoring/notation.md +49 -6
- package/docs/authoring/structure.md +80 -1
- package/docs/authoring/versioning.md +56 -3
- package/docs/authoring/visualizations.md +7 -2
- package/docs/course-agent/AGENTS.md +40 -0
- package/docs/course-agent/agents/rules-reviewer.md +33 -0
- package/docs/course-agent/skills/draft-lesson/SKILL.md +38 -0
- package/docs/course-agent/skills/migrate-course/SKILL.md +32 -0
- package/docs/course-agent/skills/release-content/SKILL.md +26 -0
- package/docs/diagram-scaling.md +148 -0
- package/docs/privacy.md +59 -0
- package/package.json +8 -2
- package/src/compiler/astro.ts +60 -21
- package/src/compiler/cli-main.ts +557 -0
- package/src/compiler/cli-reference.ts +285 -0
- package/src/compiler/cli-verbs.ts +270 -0
- package/src/compiler/cli-verify.ts +241 -0
- package/src/compiler/cli.ts +2119 -170
- package/src/compiler/collections.ts +284 -25
- package/src/compiler/content-release.ts +91 -0
- package/src/compiler/course-config.ts +267 -0
- package/src/compiler/decks.ts +455 -0
- package/src/compiler/exports/deck-fit.ts +127 -0
- package/src/compiler/exports/export-chapters.ts +105 -6
- package/src/compiler/exports/export-pages.ts +46 -2
- package/src/compiler/exports/latex/beamerthemeexplico.sty +124 -0
- package/src/compiler/exports/latex/cache.ts +183 -0
- package/src/compiler/exports/latex/capture.ts +5 -2
- package/src/compiler/exports/latex/compile.ts +18 -0
- package/src/compiler/exports/latex/deck.ts +419 -0
- package/src/compiler/exports/latex/document.ts +117 -21
- package/src/compiler/exports/latex/explico-common.sty +198 -0
- package/src/compiler/exports/latex/explico.cls +13 -183
- package/src/compiler/exports/latex/serialize.ts +25 -21
- package/src/compiler/exports/latex/texlive-packages.txt +6 -2
- package/src/compiler/exports/latex-export.ts +187 -45
- package/src/compiler/exports/markdown/serialize.ts +118 -9
- package/src/compiler/exports/markdown-export.ts +56 -11
- package/src/compiler/exports/standalone-html.ts +8 -7
- package/src/compiler/exports/static-tree.ts +175 -3
- package/src/compiler/knowledge-version.ts +56 -21
- package/src/compiler/lesson-derivation.ts +282 -16
- package/src/compiler/manifest.ts +568 -63
- package/src/compiler/page-versions.ts +401 -0
- package/src/compiler/resolution-report.ts +38 -7
- package/src/compiler/validate-content.ts +215 -0
- package/src/components/CourseContents.astro +124 -6
- package/src/components/CurriculumMap.astro +49 -1
- package/src/components/FloatIndex.astro +1 -1
- package/src/components/PartOverview.astro +51 -5
- package/src/components/assessments/AssessmentSet.astro +41 -15
- package/src/components/block-heading.ts +15 -6
- package/src/components/card-carry.ts +7 -4
- package/src/components/card-manager.ts +14 -2
- package/src/components/card-memory.ts +13 -9
- package/src/components/deck/DeckEnhancer.astro +13 -0
- package/src/components/deck/deck-context.ts +104 -0
- package/src/components/deck/deck-controller.ts +1287 -0
- package/src/components/deck/deck-map.ts +91 -0
- package/src/components/deck-lane.ts +163 -0
- package/src/components/diagram/Diagram.astro +131 -86
- package/src/components/disclosure/persisted-disclosure.ts +9 -1
- package/src/components/figure/Figure.astro +7 -2
- package/src/components/figure/FloatCaption.astro +5 -3
- package/src/components/fold/Fold.astro +2 -2
- package/src/components/notation/NotationFormula.astro +81 -11
- package/src/components/notation/NotationGlossary.astro +132 -1
- package/src/components/notation/NotationLayer.astro +15 -7
- package/src/components/starlight/AboutPanel.astro +186 -3
- package/src/components/starlight/CollapsibleSections.astro +24 -3
- package/src/components/starlight/DiagramEnhancer.astro +5 -1
- package/src/components/starlight/HeadingAnchorEnhancer.astro +1 -1
- package/src/components/starlight/LayoutHeader.astro +17 -0
- package/src/components/starlight/LayoutPageTitle.astro +110 -0
- package/src/components/starlight/LayoutSidebar.astro +807 -21
- package/src/components/starlight/LayoutSocialIcons.astro +62 -6
- package/src/components/starlight/LessonExportActions.astro +27 -9
- package/src/components/starlight/LessonFooter.astro +59 -0
- package/src/components/starlight/ReadingMemoryNotice.astro +114 -0
- package/src/components/starlight/TextSizeControl.astro +24 -13
- package/src/components/starlight/page-marks.ts +139 -0
- package/src/components/starlight/section-summary.ts +1 -1
- package/src/components/starlight/sidebar-editions.ts +245 -0
- package/src/components/table/Table.astro +15 -7
- package/src/content-config.ts +87 -1
- package/src/curriculum/competency-graph.ts +95 -0
- package/src/reference/base-library.mjs +19 -0
- package/src/reference/consistency.ts +137 -39
- package/src/reference/deck-remark.mjs +600 -0
- package/src/reference/deck-source.ts +273 -0
- package/src/reference/decks-validate.ts +604 -0
- package/src/reference/diagram-fit.ts +18 -4
- package/src/reference/diagram-layout.ts +3 -1
- package/src/reference/figure-symbols.ts +108 -31
- package/src/reference/folds-validate.ts +1 -1
- package/src/reference/gate-indices.ts +5 -3
- package/src/reference/gate-math.ts +169 -25
- package/src/reference/lab-katex-validate.ts +30 -15
- package/src/reference/lab-math-scope.ts +34 -3
- package/src/reference/math-glyphs.mjs +189 -25
- package/src/reference/page-notation.ts +69 -15
- package/src/reference/references.ts +28 -0
- package/src/reference/registry-scope.mjs +34 -0
- package/src/reference/registry.ts +41 -11
- package/src/reference/rehype-deck.mjs +286 -0
- package/src/reference/rehype-heading-anchors.mjs +48 -6
- package/src/reference/remark-notation.mjs +249 -40
- package/src/reference/source-lines.mjs +65 -0
- package/src/reference/types.ts +28 -0
- package/src/rules/catalog.ts +274 -4
- package/src/rules/course-rules.ts +21 -1
- package/src/rules/in-effect.ts +58 -11
- package/src/session/PreferenceStore.ts +23 -0
- package/src/session/deck-memory.ts +263 -0
- package/src/session/reading-memory.ts +243 -0
- package/src/styles/deck.css +1150 -0
- package/src/styles/global.css +958 -27
- package/src/styles/zones.css +277 -0
- /package/src/{components → reference}/float-name.ts +0 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { closeSync, existsSync, mkdirSync, openSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join, relative } from "node:path";
|
|
5
|
+
const VERIFY_DIR = join("node_modules", ".cache", "explico", "verify");
|
|
6
|
+
const RECORD = "last-pass.json";
|
|
7
|
+
const TAIL_LINES = 20;
|
|
8
|
+
function verifyTreeHash(cwd) {
|
|
9
|
+
try {
|
|
10
|
+
const git = (args) => execFileSync("git", args, { cwd, maxBuffer: 1 << 30, stdio: ["ignore", "pipe", "ignore"] });
|
|
11
|
+
const hash = createHash("sha1");
|
|
12
|
+
hash.update(git(["rev-parse", "HEAD"]));
|
|
13
|
+
hash.update(git(["diff", "HEAD", "--binary"]));
|
|
14
|
+
const untracked = git(["ls-files", "--others", "--exclude-standard", "-z"]).toString("utf8").split("\0").filter(Boolean).sort();
|
|
15
|
+
for (const file of untracked) {
|
|
16
|
+
hash.update(`\0${file}\0`);
|
|
17
|
+
if (existsSync(join(cwd, file))) hash.update(readFileSync(join(cwd, file)));
|
|
18
|
+
}
|
|
19
|
+
return hash.digest("hex");
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function scriptCommand(script, args) {
|
|
25
|
+
const execpath = process.env.npm_execpath ?? "";
|
|
26
|
+
const manager = /pnpm/.test(execpath) ? "pnpm" : /yarn/.test(execpath) ? "yarn" : /npm/.test(execpath) ? "npm" : "pnpm";
|
|
27
|
+
const tail = manager === "npm" && args.length > 0 ? ["run", script, "--", ...args] : ["run", script, ...args];
|
|
28
|
+
const display = `${manager} ${tail.join(" ")}`;
|
|
29
|
+
if (execpath === "" || !execpath.includes(manager)) return { file: manager, argv: tail, display };
|
|
30
|
+
return /\.[cm]?js$/.test(execpath) ? { file: process.execPath, argv: [execpath, ...tail], display } : { file: execpath, argv: tail, display };
|
|
31
|
+
}
|
|
32
|
+
function binCommand(cwd, bin, args) {
|
|
33
|
+
return { file: join(cwd, "node_modules", ".bin", process.platform === "win32" ? `${bin}.cmd` : bin), argv: [...args], display: [bin, ...args].join(" ") };
|
|
34
|
+
}
|
|
35
|
+
function slug(name) {
|
|
36
|
+
return name.replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
37
|
+
}
|
|
38
|
+
function tailOf(file) {
|
|
39
|
+
const lines = readFileSync(file, "utf8").split("\n").map((line) => line.trimEnd()).filter((line) => line !== "");
|
|
40
|
+
return lines.slice(-TAIL_LINES);
|
|
41
|
+
}
|
|
42
|
+
function runVerify(options = {}) {
|
|
43
|
+
const cwd = options.cwd ?? process.cwd();
|
|
44
|
+
const e2e = options.e2e ?? false;
|
|
45
|
+
const dir = join(cwd, VERIFY_DIR);
|
|
46
|
+
const recordFile = join(dir, RECORD);
|
|
47
|
+
if (!options.force && existsSync(recordFile)) {
|
|
48
|
+
try {
|
|
49
|
+
const record = JSON.parse(readFileSync(recordFile, "utf8"));
|
|
50
|
+
const tree2 = verifyTreeHash(cwd);
|
|
51
|
+
if (tree2 !== null && record.tree === tree2 && (record.e2e || !e2e)) {
|
|
52
|
+
return { ok: true, cached: true, since: record.when, tree: tree2, e2e: record.e2e, steps: record.steps };
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
mkdirSync(dir, { recursive: true });
|
|
58
|
+
const pkg = JSON.parse(readFileSync(join(cwd, "package.json"), "utf8"));
|
|
59
|
+
const scripts = pkg.scripts ?? {};
|
|
60
|
+
const has = (path) => existsSync(join(cwd, path));
|
|
61
|
+
const playwrightConfig = ["playwright.config.ts", "playwright.config.mts", "playwright.config.js", "playwright.config.mjs"].some(has);
|
|
62
|
+
const plans = [
|
|
63
|
+
scripts["validate:content"] === void 0 ? { name: "validate:content", reason: "package.json has no validate:content script", fail: true } : { name: "validate:content", command: scriptCommand("validate:content", []) },
|
|
64
|
+
scripts.content === void 0 ? { name: "check --changed", reason: "package.json has no content script", fail: true } : { name: "check --changed", command: scriptCommand("content", ["check", "--changed"]) },
|
|
65
|
+
// Without @astrojs/check, `astro check` stops to ask whether to install it.
|
|
66
|
+
has(join("node_modules", "@astrojs", "check", "package.json")) ? { name: "astro check", command: binCommand(cwd, "astro", ["check"]) } : { name: "astro check", reason: "@astrojs/check is not installed (pnpm add -D @astrojs/check typescript)" },
|
|
67
|
+
scripts.test === void 0 ? { name: "tests", reason: "package.json has no test script" } : { name: "tests", command: scriptCommand("test", []) },
|
|
68
|
+
{ name: "astro build", command: binCommand(cwd, "astro", ["build"]) }
|
|
69
|
+
];
|
|
70
|
+
if (e2e) {
|
|
71
|
+
plans.push(
|
|
72
|
+
scripts["test:e2e"] !== void 0 ? { name: "e2e", command: scriptCommand("test:e2e", []) } : playwrightConfig ? { name: "e2e", command: binCommand(cwd, "playwright", ["test"]) } : { name: "e2e", reason: "no test:e2e script and no playwright.config" }
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
const steps = [];
|
|
76
|
+
for (const plan of plans) {
|
|
77
|
+
options.onStep?.({ phase: "start", name: plan.name });
|
|
78
|
+
let step;
|
|
79
|
+
if (plan.command === void 0) {
|
|
80
|
+
step = { name: plan.name, status: plan.fail ? "fail" : "skipped", reason: plan.reason };
|
|
81
|
+
} else {
|
|
82
|
+
const log = join(dir, `${slug(plan.name)}.log`);
|
|
83
|
+
const fd = openSync(log, "w");
|
|
84
|
+
const started = Date.now();
|
|
85
|
+
let result;
|
|
86
|
+
try {
|
|
87
|
+
result = spawnSync(plan.command.file, plan.command.argv, {
|
|
88
|
+
cwd,
|
|
89
|
+
stdio: ["ignore", fd, fd],
|
|
90
|
+
shell: process.platform === "win32",
|
|
91
|
+
env: process.env
|
|
92
|
+
});
|
|
93
|
+
} finally {
|
|
94
|
+
closeSync(fd);
|
|
95
|
+
}
|
|
96
|
+
const seconds = Math.round((Date.now() - started) / 100) / 10;
|
|
97
|
+
const passed = result.error === void 0 && result.status === 0;
|
|
98
|
+
step = {
|
|
99
|
+
name: plan.name,
|
|
100
|
+
status: passed ? "pass" : "fail",
|
|
101
|
+
command: plan.command.display,
|
|
102
|
+
seconds,
|
|
103
|
+
log: relative(cwd, log),
|
|
104
|
+
...result.error === void 0 ? {} : { reason: result.error.message },
|
|
105
|
+
...passed ? {} : { tail: tailOf(log) }
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
steps.push(step);
|
|
109
|
+
options.onStep?.({ phase: "end", step });
|
|
110
|
+
}
|
|
111
|
+
const ok = steps.every((step) => step.status !== "fail");
|
|
112
|
+
const tree = verifyTreeHash(cwd);
|
|
113
|
+
if (ok && tree !== null) {
|
|
114
|
+
const record = { tree, e2e, when: (/* @__PURE__ */ new Date()).toISOString(), steps };
|
|
115
|
+
writeFileSync(recordFile, `${JSON.stringify(record, null, 2)}
|
|
116
|
+
`);
|
|
117
|
+
}
|
|
118
|
+
return { ok, cached: false, tree, e2e, steps };
|
|
119
|
+
}
|
|
120
|
+
function formatVerifyReport(report) {
|
|
121
|
+
if (report.cached) {
|
|
122
|
+
return `verify: PASS, unchanged since ${report.since} (${report.e2e ? "with" : "without"} e2e); --force reruns
|
|
123
|
+
`;
|
|
124
|
+
}
|
|
125
|
+
const out = [];
|
|
126
|
+
for (const step of report.steps) {
|
|
127
|
+
if (step.status !== "fail") continue;
|
|
128
|
+
out.push("", `${step.name} failed${step.reason === void 0 ? "" : `: ${step.reason}`}${step.log === void 0 ? "" : ` \u2014 last lines of ${step.log}:`}`);
|
|
129
|
+
for (const line of step.tail ?? []) out.push(` ${line}`);
|
|
130
|
+
}
|
|
131
|
+
const failed = report.steps.filter((step) => step.status === "fail").map((step) => step.name);
|
|
132
|
+
out.push(
|
|
133
|
+
"",
|
|
134
|
+
failed.length === 0 ? `verify: PASS${report.tree === null ? " (not a git repository: nothing recorded)" : ""}` : `verify: FAIL \u2014 ${failed.join(", ")}; whole output under ${VERIFY_DIR}/`
|
|
135
|
+
);
|
|
136
|
+
return `${out.join("\n").replace(/^\n/, "")}
|
|
137
|
+
`;
|
|
138
|
+
}
|
|
139
|
+
function formatVerifyStep(step) {
|
|
140
|
+
const verdict = step.status === "pass" ? "ok" : step.status === "fail" ? "FAIL" : "skipped";
|
|
141
|
+
const detail = step.seconds !== void 0 ? `${step.seconds.toFixed(1)}s` : step.reason ?? "";
|
|
142
|
+
return ` ${step.name.padEnd(18)} ${verdict.padEnd(7)} ${detail}
|
|
143
|
+
`;
|
|
144
|
+
}
|
|
145
|
+
export {
|
|
146
|
+
VERIFY_DIR,
|
|
147
|
+
formatVerifyReport,
|
|
148
|
+
formatVerifyStep,
|
|
149
|
+
runVerify,
|
|
150
|
+
verifyTreeHash
|
|
151
|
+
};
|
package/dist/compiler/cli.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { DiagnosticSeverity } from '../reference/types.js';
|
|
2
|
-
import { EquationLink } from '../reference/gate-math.js';
|
|
3
|
-
import {
|
|
2
|
+
import { EquationLink, ScopeEntry } from '../reference/gate-math.js';
|
|
3
|
+
import { ManifestLesson, ManifestLessonFloat, Manifest } from './manifest.js';
|
|
4
4
|
import { RenderDiagnostic } from './render-diagnostics.js';
|
|
5
|
+
import { RetiredRule } from '../rules/catalog.js';
|
|
5
6
|
import { RulesFilter, RuleInEffect } from '../rules/in-effect.js';
|
|
6
7
|
import '../curriculum/validation.js';
|
|
7
8
|
import '../reference/consistency.js';
|
|
8
|
-
import '../course-config-
|
|
9
|
-
import '../rules/catalog.js';
|
|
9
|
+
import '../course-config-BLtIdkei.js';
|
|
10
10
|
import '../rules/course-rules.js';
|
|
11
11
|
import './collections.js';
|
|
12
12
|
import '../reference/gate-retired-keys.js';
|
|
@@ -25,12 +25,17 @@ import '../reference/mixed-content.js';
|
|
|
25
25
|
import '../reference/gloss.js';
|
|
26
26
|
import '../rules/waivers.js';
|
|
27
27
|
import './knowledge-version.js';
|
|
28
|
+
import './page-versions.js';
|
|
29
|
+
import './decks.js';
|
|
30
|
+
import '../reference/decks-validate.js';
|
|
31
|
+
import '../reference/deck-source.js';
|
|
28
32
|
import './lesson-derivation.js';
|
|
29
33
|
|
|
30
34
|
/**
|
|
31
35
|
* The `content` CLI core (Phase G1).
|
|
32
36
|
*
|
|
33
|
-
* `
|
|
37
|
+
* `./cli-main` is the router (`runContentCli`), a course's `scripts/content.ts`
|
|
38
|
+
* a three-line shim over it; every command's logic lives here
|
|
34
39
|
* as a pure-ish function that takes a compiled {@link Manifest} and returns a
|
|
35
40
|
* plain data object. The router is **read-only** — only `content new` touches
|
|
36
41
|
* the filesystem, and even then `scaffoldLesson` / `scaffoldTerm` only return
|
|
@@ -59,7 +64,7 @@ import './lesson-derivation.js';
|
|
|
59
64
|
* under the `render:` source.
|
|
60
65
|
*/
|
|
61
66
|
|
|
62
|
-
type ContentCliCode = 'unknown-command' | 'usage' | 'unknown-lesson' | 'unknown-kind' | 'invalid-id' | 'exists' | 'not-a-lesson' | 'no-git';
|
|
67
|
+
type ContentCliCode = 'unknown-command' | 'usage' | 'unknown-lesson' | 'unknown-kind' | 'invalid-id' | 'exists' | 'not-a-lesson' | 'no-git' | 'unknown-version' | 'migration-gap' | 'unknown-key' | 'no-changelog';
|
|
63
68
|
/** A user-facing failure with a stable code and no stack in `--json` output. */
|
|
64
69
|
declare class ContentCliError extends Error {
|
|
65
70
|
readonly code: ContentCliCode;
|
|
@@ -74,6 +79,8 @@ interface CliDiagnostic {
|
|
|
74
79
|
* which `tests/rules/catalog.test.ts` treats as a bug.
|
|
75
80
|
*/
|
|
76
81
|
readonly rule?: string;
|
|
82
|
+
/** The owner's page and anchor under `docs/authoring/`, `notation.md#n4`. */
|
|
83
|
+
readonly doc?: string;
|
|
77
84
|
readonly severity: DiagnosticSeverity;
|
|
78
85
|
readonly message: string;
|
|
79
86
|
readonly file?: string;
|
|
@@ -87,13 +94,23 @@ interface CliDiagnostic {
|
|
|
87
94
|
*/
|
|
88
95
|
readonly equation?: EquationLink;
|
|
89
96
|
}
|
|
97
|
+
/** ` [N4 · notation.md#n4]` for a diagnostic the catalog owns; empty otherwise. */
|
|
98
|
+
declare function ownerTag(diagnostic: Pick<CliDiagnostic, 'rule' | 'doc'>): string;
|
|
99
|
+
/**
|
|
100
|
+
* One text line for a diagnostic, the shape every verb prints:
|
|
101
|
+
* `file:line:column: severity code [rule · doc]: message`. The location is
|
|
102
|
+
* left out when the diagnostic has no file, and reads `1:1` when the file is
|
|
103
|
+
* known but the position is not, so an editor opens the file. The rule and its page are on the
|
|
104
|
+
* line so a reader needs no second lookup to find what the code answers to.
|
|
105
|
+
*/
|
|
106
|
+
declare function formatCliDiagnostic(diagnostic: CliDiagnostic): string;
|
|
90
107
|
/**
|
|
91
108
|
* Every manifest diagnostic that names this lesson (by id or file), normalized
|
|
92
109
|
* to {@link CliDiagnostic}. Corpus-wide checks (curriculum) are included only
|
|
93
110
|
* when their message mentions the lesson; per-file checks (notation, math,
|
|
94
111
|
* equations, consistency) are filtered by `file`.
|
|
95
112
|
*/
|
|
96
|
-
declare function lessonDiagnostics(manifest: Manifest, lesson:
|
|
113
|
+
declare function lessonDiagnostics(manifest: Manifest, lesson: CheckTarget, rendered?: readonly RenderDiagnostic[]): CliDiagnostic[];
|
|
97
114
|
interface RenderResult {
|
|
98
115
|
readonly rendered: boolean;
|
|
99
116
|
readonly diagnostics: readonly CliDiagnostic[];
|
|
@@ -139,6 +156,34 @@ interface DomainFileSignatures {
|
|
|
139
156
|
interface StatusReport {
|
|
140
157
|
/** The course's published knowledge version (`about.version`). */
|
|
141
158
|
readonly knowledgeVersion: string;
|
|
159
|
+
/**
|
|
160
|
+
* What an agent is told to read before working, in estimated tokens: the
|
|
161
|
+
* course's `AGENTS.md`, the repository's one level up when the course is a
|
|
162
|
+
* workspace package, and the rules-in-effect page. A budget to watch; the
|
|
163
|
+
* estimate is bytes over four.
|
|
164
|
+
*/
|
|
165
|
+
readonly agentSurfaces: readonly {
|
|
166
|
+
readonly name: string;
|
|
167
|
+
readonly tokens: number;
|
|
168
|
+
}[];
|
|
169
|
+
/**
|
|
170
|
+
* Whether the course's own `AGENTS.md` points an agent at the engine's
|
|
171
|
+
* guide (`docs/authoring/agents.md`), and whether the procedures
|
|
172
|
+
* `content init-agent` installs are in `.claude/`.
|
|
173
|
+
*/
|
|
174
|
+
readonly agentGuide: {
|
|
175
|
+
readonly agentsFile: string | null;
|
|
176
|
+
readonly linksGuide: boolean;
|
|
177
|
+
readonly skillsInstalled: boolean;
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* Rule C5: how many chapters and part pages carry a version of their own,
|
|
181
|
+
* and the slugs of those with a change `## [Unreleased]` has not released.
|
|
182
|
+
*/
|
|
183
|
+
readonly pageVersions: {
|
|
184
|
+
readonly tracked: number;
|
|
185
|
+
readonly unreleased: readonly string[];
|
|
186
|
+
};
|
|
142
187
|
readonly counts: {
|
|
143
188
|
readonly lessons: number;
|
|
144
189
|
readonly competencies: number;
|
|
@@ -166,6 +211,46 @@ interface DiagnosticsReport {
|
|
|
166
211
|
readonly count: number;
|
|
167
212
|
readonly diagnostics: readonly CliDiagnostic[];
|
|
168
213
|
}
|
|
214
|
+
/**
|
|
215
|
+
* The diagnostics list folded to what an agent decides from: how many, of
|
|
216
|
+
* what, and where. The default text output, since a course can have hundreds
|
|
217
|
+
* of lines of two codes and the list is what `--all` is for.
|
|
218
|
+
*/
|
|
219
|
+
interface DiagnosticsSummary {
|
|
220
|
+
readonly minimumSeverity: DiagnosticThreshold;
|
|
221
|
+
readonly count: number;
|
|
222
|
+
readonly bySeverity: {
|
|
223
|
+
readonly errors: number;
|
|
224
|
+
readonly warnings: number;
|
|
225
|
+
readonly infos: number;
|
|
226
|
+
};
|
|
227
|
+
/** One row per code and severity, most frequent first. */
|
|
228
|
+
readonly byCode: readonly {
|
|
229
|
+
readonly code: string;
|
|
230
|
+
readonly rule?: string;
|
|
231
|
+
readonly doc?: string;
|
|
232
|
+
readonly severity: DiagnosticSeverity;
|
|
233
|
+
readonly count: number;
|
|
234
|
+
}[];
|
|
235
|
+
/** One row per file, most diagnostics first; `(no file)` for the rest. */
|
|
236
|
+
readonly byFile: readonly {
|
|
237
|
+
readonly file: string;
|
|
238
|
+
readonly count: number;
|
|
239
|
+
readonly errors: number;
|
|
240
|
+
readonly warnings: number;
|
|
241
|
+
readonly infos: number;
|
|
242
|
+
}[];
|
|
243
|
+
}
|
|
244
|
+
declare function summarizeDiagnostics(report: DiagnosticsReport): DiagnosticsSummary;
|
|
245
|
+
/** The diagnostics of one code (with or without its `source:` prefix) or of some files. */
|
|
246
|
+
declare function filterDiagnostics(report: DiagnosticsReport, filter: {
|
|
247
|
+
readonly code?: string;
|
|
248
|
+
readonly files?: readonly string[];
|
|
249
|
+
}): DiagnosticsReport;
|
|
250
|
+
/** The summary as text: a severity line, then counts by code and by file, the file list capped. */
|
|
251
|
+
declare function formatDiagnosticsSummary(summary: DiagnosticsSummary, options?: {
|
|
252
|
+
readonly fileCap?: number;
|
|
253
|
+
}): string;
|
|
169
254
|
interface WarningsReport {
|
|
170
255
|
readonly count: number;
|
|
171
256
|
readonly warnings: readonly CliDiagnostic[];
|
|
@@ -191,6 +276,8 @@ interface RulesReport {
|
|
|
191
276
|
declare function parseRulesFilter(input: {
|
|
192
277
|
readonly element?: string;
|
|
193
278
|
readonly enforcement?: string;
|
|
279
|
+
/** `chapter` (the default page) or `deck` (`<lesson>.deck.mdx`). */
|
|
280
|
+
readonly edition?: string;
|
|
194
281
|
}): RulesFilter;
|
|
195
282
|
/** The rules this course has in effect, optionally narrowed. */
|
|
196
283
|
declare function contentRules(manifest: Manifest, filter?: RulesFilter): RulesReport;
|
|
@@ -204,6 +291,8 @@ interface ContextReport {
|
|
|
204
291
|
readonly teaches: readonly string[];
|
|
205
292
|
readonly requires: readonly string[];
|
|
206
293
|
readonly assumptions: readonly string[];
|
|
294
|
+
/** The version the page's content last changed in; `null` for a change not yet released (rule C5). */
|
|
295
|
+
readonly since: string | null;
|
|
207
296
|
readonly notationLocal: unknown;
|
|
208
297
|
readonly body: string;
|
|
209
298
|
};
|
|
@@ -223,22 +312,10 @@ interface ContextReport {
|
|
|
223
312
|
units?: string;
|
|
224
313
|
formula?: string;
|
|
225
314
|
}[];
|
|
226
|
-
readonly equations: readonly
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
readonly tables: readonly {
|
|
231
|
-
key: string;
|
|
232
|
-
number: string;
|
|
233
|
-
}[];
|
|
234
|
-
readonly figures: readonly {
|
|
235
|
-
key: string;
|
|
236
|
-
number: string;
|
|
237
|
-
}[];
|
|
238
|
-
readonly diagrams: readonly {
|
|
239
|
-
key: string;
|
|
240
|
-
number: string;
|
|
241
|
-
}[];
|
|
315
|
+
readonly equations: readonly ManifestLessonFloat[];
|
|
316
|
+
readonly tables: readonly ManifestLessonFloat[];
|
|
317
|
+
readonly figures: readonly ManifestLessonFloat[];
|
|
318
|
+
readonly diagrams: readonly ManifestLessonFloat[];
|
|
242
319
|
/** Worked-example sets: `short` is the title `[[ex-key]]` names. */
|
|
243
320
|
readonly examples: readonly {
|
|
244
321
|
key: string;
|
|
@@ -268,7 +345,298 @@ interface ContextReport {
|
|
|
268
345
|
readonly diagnostics: readonly CliDiagnostic[];
|
|
269
346
|
readonly tokens: TokenCounts;
|
|
270
347
|
}
|
|
348
|
+
interface MigrationSection {
|
|
349
|
+
readonly from: string;
|
|
350
|
+
readonly to: string;
|
|
351
|
+
readonly heading: string;
|
|
352
|
+
readonly markdown: string;
|
|
353
|
+
readonly tokens: number;
|
|
354
|
+
}
|
|
355
|
+
interface MigrateReport {
|
|
356
|
+
readonly from: string;
|
|
357
|
+
readonly to: string;
|
|
358
|
+
readonly file: string;
|
|
359
|
+
readonly sections: readonly MigrationSection[];
|
|
360
|
+
readonly tokens: number;
|
|
361
|
+
}
|
|
362
|
+
/** Every `## <from> → <to>` section of the guide, in file order (newest first). */
|
|
363
|
+
declare function parseMigrationSections(markdown: string): MigrationSection[];
|
|
364
|
+
/**
|
|
365
|
+
* The sections that take a course from `from` to `to`, oldest first: each
|
|
366
|
+
* section's left side matches where the previous one ended. A hole in the
|
|
367
|
+
* chain is an error naming the version no section continues from, since a
|
|
368
|
+
* skipped section is a skipped migration.
|
|
369
|
+
*/
|
|
370
|
+
declare function selectMigrationPath(sections: readonly MigrationSection[], from: string, to: string): MigrationSection[];
|
|
371
|
+
/** The engine version the course has installed: the package beside it, or this one. */
|
|
372
|
+
declare function installedEngineVersion(): string | undefined;
|
|
373
|
+
/**
|
|
374
|
+
* The engine version `package.json` pins at HEAD — what the course last
|
|
375
|
+
* migrated to, before the working tree bumped it. `workspace:*` or a range
|
|
376
|
+
* is no version, so the caller asks for `--from`.
|
|
377
|
+
*/
|
|
378
|
+
declare function pinnedEngineVersion(): string | undefined;
|
|
379
|
+
declare function contentMigrate(options?: {
|
|
380
|
+
readonly from?: string;
|
|
381
|
+
readonly to?: string;
|
|
382
|
+
}): MigrateReport;
|
|
383
|
+
/** The sections, oldest first, under one line that says how much is coming. */
|
|
384
|
+
declare function formatMigrateReport(report: MigrateReport): string;
|
|
385
|
+
interface SpanBinding {
|
|
386
|
+
readonly token: string;
|
|
387
|
+
readonly key: string;
|
|
388
|
+
/** The resolver's match kind; `explicit` for an `\explain` wrap. */
|
|
389
|
+
readonly how: string;
|
|
390
|
+
}
|
|
391
|
+
interface ExplicitWrap {
|
|
392
|
+
readonly key: string;
|
|
393
|
+
readonly inner: string;
|
|
394
|
+
/** The bare `inner` resolves to exactly this card: the wrap costs tokens and binds nothing new. */
|
|
395
|
+
readonly redundant: boolean;
|
|
396
|
+
}
|
|
397
|
+
interface UnresolvedGlyph {
|
|
398
|
+
readonly token: string;
|
|
399
|
+
readonly suspended?: string;
|
|
400
|
+
/** Rule N23: indexed entries whose base this bare letter is; none lends it a card. */
|
|
401
|
+
readonly lenders?: readonly string[];
|
|
402
|
+
/** Where `content symbol` finds the token defined: exact hits, then near misses. */
|
|
403
|
+
readonly defined: readonly {
|
|
404
|
+
readonly tier: SymbolTier;
|
|
405
|
+
readonly key: string;
|
|
406
|
+
readonly where: string;
|
|
407
|
+
}[];
|
|
408
|
+
readonly near: readonly {
|
|
409
|
+
readonly latex: string;
|
|
410
|
+
readonly key: string;
|
|
411
|
+
}[];
|
|
412
|
+
}
|
|
413
|
+
interface SpanBindings {
|
|
414
|
+
readonly bindings: readonly SpanBinding[];
|
|
415
|
+
readonly wraps: readonly ExplicitWrap[];
|
|
416
|
+
readonly unresolved: readonly Omit<UnresolvedGlyph, 'defined' | 'near'>[];
|
|
417
|
+
/** The resolver rejected the span (a KaTeX parse error or a rule it enforces, N13 say); its message. */
|
|
418
|
+
readonly error?: string;
|
|
419
|
+
}
|
|
420
|
+
interface BindingsSpan extends Omit<SpanBindings, 'unresolved'> {
|
|
421
|
+
readonly line: number;
|
|
422
|
+
readonly column: number;
|
|
423
|
+
readonly display: boolean;
|
|
424
|
+
readonly latex: string;
|
|
425
|
+
readonly unresolved: readonly UnresolvedGlyph[];
|
|
426
|
+
}
|
|
427
|
+
interface BindingsReport {
|
|
428
|
+
readonly lesson: string;
|
|
429
|
+
readonly file: string;
|
|
430
|
+
readonly scope: readonly {
|
|
431
|
+
readonly key: string;
|
|
432
|
+
readonly notation: string;
|
|
433
|
+
readonly scope: 'shared' | 'local';
|
|
434
|
+
}[];
|
|
435
|
+
readonly spans: readonly BindingsSpan[];
|
|
436
|
+
readonly counts: {
|
|
437
|
+
readonly spans: number;
|
|
438
|
+
readonly bindings: number;
|
|
439
|
+
readonly unresolved: number;
|
|
440
|
+
readonly wraps: number;
|
|
441
|
+
readonly redundantWraps: number;
|
|
442
|
+
readonly errors: number;
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* One span against a scope. Exported for tests and for a caller with a span
|
|
447
|
+
* of its own (`content equation`).
|
|
448
|
+
*/
|
|
449
|
+
declare function spanBindings(latex: string, scope: readonly ScopeEntry[], options?: {
|
|
450
|
+
readonly suspended?: readonly string[];
|
|
451
|
+
readonly derive?: boolean;
|
|
452
|
+
}): SpanBindings;
|
|
453
|
+
declare function contentBindings(manifest: Manifest, rawId: string): BindingsReport;
|
|
454
|
+
/** The text form: a counts line, the scope, then one line per span. */
|
|
455
|
+
declare function formatBindingsReport(report: BindingsReport): string;
|
|
456
|
+
/**
|
|
457
|
+
* One LaTeX string, resolved the way the gate will: against a lesson's
|
|
458
|
+
* scope, or against every shared card when no lesson is named (the table a
|
|
459
|
+
* notation entry's body and formula use). The inner loop while drafting:
|
|
460
|
+
* a few lines out, non-zero exit when the build would refuse the span.
|
|
461
|
+
*/
|
|
462
|
+
interface EquationReport extends Omit<SpanBindings, 'unresolved'> {
|
|
463
|
+
readonly latex: string;
|
|
464
|
+
readonly against: {
|
|
465
|
+
readonly kind: 'lesson';
|
|
466
|
+
readonly lesson: string;
|
|
467
|
+
readonly cards: number;
|
|
468
|
+
} | {
|
|
469
|
+
readonly kind: 'shared';
|
|
470
|
+
readonly cards: number;
|
|
471
|
+
};
|
|
472
|
+
readonly unresolved: readonly UnresolvedGlyph[];
|
|
473
|
+
readonly ok: boolean;
|
|
474
|
+
}
|
|
475
|
+
declare function contentEquation(manifest: Manifest, latex: string, options?: {
|
|
476
|
+
readonly lesson?: string;
|
|
477
|
+
}): EquationReport;
|
|
478
|
+
declare function formatEquationReport(report: EquationReport): string;
|
|
479
|
+
interface FileEdit {
|
|
480
|
+
/** Course-relative path. */
|
|
481
|
+
readonly file: string;
|
|
482
|
+
/** `null` when the file is created. */
|
|
483
|
+
readonly before: string | null;
|
|
484
|
+
/** `null` when the file is deleted. */
|
|
485
|
+
readonly after: string | null;
|
|
486
|
+
}
|
|
487
|
+
interface EditPlan {
|
|
488
|
+
readonly summary: readonly string[];
|
|
489
|
+
readonly edits: readonly FileEdit[];
|
|
490
|
+
/** What to run after writing. */
|
|
491
|
+
readonly next: readonly string[];
|
|
492
|
+
}
|
|
493
|
+
/** `[[old]]` and `\explain{old}` become `new`; nothing else is touched. Returns the count. */
|
|
494
|
+
declare function rewriteKeyReferences(text: string, oldKey: string, newKey: string): {
|
|
495
|
+
text: string;
|
|
496
|
+
count: number;
|
|
497
|
+
};
|
|
498
|
+
/**
|
|
499
|
+
* Remove one `notation.local` item from a lesson file's text, by key, keeping
|
|
500
|
+
* the rest of the frontmatter byte for byte. An item runs from its `- key:`
|
|
501
|
+
* line to the next line indented no deeper than the dash; an emptied list
|
|
502
|
+
* becomes `local: []`.
|
|
503
|
+
*/
|
|
504
|
+
declare function removeLocalItem(text: string, key: string): {
|
|
505
|
+
text: string;
|
|
506
|
+
removed: boolean;
|
|
507
|
+
};
|
|
508
|
+
/**
|
|
509
|
+
* A shared card's file from a page-local entry's fields, nothing invented: no
|
|
510
|
+
* body (the glossary shows the meaning; what a reader needs beyond it is the
|
|
511
|
+
* author's to write, and a placeholder would publish), and the label only
|
|
512
|
+
* when the entry has one. `domain` is the caller's pick, else the key's
|
|
513
|
+
* prefix, else `general`.
|
|
514
|
+
*/
|
|
515
|
+
declare function sharedCardFromLocal(local: Record<string, unknown>, options: {
|
|
516
|
+
readonly key: string;
|
|
517
|
+
readonly fromLesson: string;
|
|
518
|
+
readonly domain?: string;
|
|
519
|
+
}): string;
|
|
520
|
+
/**
|
|
521
|
+
* `content move <lesson>:<key> [--to <key>]`: a page-local entry becomes a
|
|
522
|
+
* shared card. Every lesson that declares the key loses its copy (the card
|
|
523
|
+
* serves them all; copies that differ are reported, the named lesson's text
|
|
524
|
+
* wins), and with `--to` every `[[key]]` and `\explain{key}` follows.
|
|
525
|
+
*/
|
|
526
|
+
declare function planMove(manifest: Manifest, lessonId: string, key: string, options?: {
|
|
527
|
+
readonly to?: string;
|
|
528
|
+
}): EditPlan;
|
|
529
|
+
/** `content rename <old> <new>`: a shared card's key, everywhere it is named. */
|
|
530
|
+
declare function planRename(manifest: Manifest, oldKey: string, newKey: string): EditPlan;
|
|
531
|
+
/**
|
|
532
|
+
* `content fix <lesson>`: the diagnostics with one mechanical repair, applied.
|
|
533
|
+
* Today: every `\explain{key}{inner}` the gate reports as `explain-redundant`
|
|
534
|
+
* becomes `inner`.
|
|
535
|
+
*/
|
|
536
|
+
declare function planFix(manifest: Manifest, lessonId: string): EditPlan;
|
|
537
|
+
/** `content fix` over several lessons (or every one, `--all`) as one plan: the lessons with nothing to fix are counted, not listed. */
|
|
538
|
+
declare function planFixMany(manifest: Manifest, lessonIds: readonly string[]): EditPlan;
|
|
539
|
+
/** The plan as a unified diff (git's), file by file, under its summary lines. */
|
|
540
|
+
declare function renderEditPlan(plan: EditPlan): string;
|
|
541
|
+
/** Write a plan's edits. Returns the files touched. */
|
|
542
|
+
declare function applyEditPlan(plan: EditPlan): string[];
|
|
543
|
+
/**
|
|
544
|
+
* The engine's course-facing agent procedures (`docs/course-agent/`): skills,
|
|
545
|
+
* the `rules-reviewer` agent and the `AGENTS.md` baseline, beside the
|
|
546
|
+
* installed package or above this module.
|
|
547
|
+
*/
|
|
548
|
+
declare function courseAgentDir(): string | undefined;
|
|
549
|
+
/**
|
|
550
|
+
* `content init-agent [--write]`: install or refresh the engine's agent
|
|
551
|
+
* procedures in this course — every skill under `.claude/skills/`, the
|
|
552
|
+
* reviewer under `.claude/agents/` — and, only when the course has no
|
|
553
|
+
* `AGENTS.md`, the baseline one. An existing `AGENTS.md` is never edited;
|
|
554
|
+
* when it does not point at the engine's guide, the plan says what to add.
|
|
555
|
+
*/
|
|
556
|
+
declare function planInitAgent(): EditPlan;
|
|
557
|
+
/**
|
|
558
|
+
* One rule, whole: the catalog entry as this course has it (enforcement,
|
|
559
|
+
* codes, settings in effect, whether it is on) and the rule page's own
|
|
560
|
+
* section, example included. About half a thousand tokens where opening the
|
|
561
|
+
* page costs twenty thousand.
|
|
562
|
+
*/
|
|
563
|
+
interface RuleReport {
|
|
564
|
+
readonly id: string;
|
|
565
|
+
readonly status: 'in-effect' | 'retired' | 'unknown';
|
|
566
|
+
readonly rule?: RuleInEffect;
|
|
567
|
+
readonly retired?: RetiredRule;
|
|
568
|
+
/** The rule page's section for this rule, when the page is at hand. */
|
|
569
|
+
readonly section?: {
|
|
570
|
+
readonly file: string;
|
|
571
|
+
readonly markdown: string;
|
|
572
|
+
readonly tokens: number;
|
|
573
|
+
};
|
|
574
|
+
/** For `unknown`: the IDs this course has, so the caller can pick one. */
|
|
575
|
+
readonly known: readonly string[];
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* The engine's `docs/authoring/`: beside the installed package in a course
|
|
579
|
+
* (`node_modules/explico/docs/authoring`, the path the rules-in-effect page
|
|
580
|
+
* links), or above this module in the repository and in the package itself.
|
|
581
|
+
*/
|
|
582
|
+
declare function authoringDocsDir(): string | undefined;
|
|
583
|
+
/**
|
|
584
|
+
* The section of a rule page that `anchor` names: from the heading whose
|
|
585
|
+
* slug is the anchor (`## N4` → `n4`, `## Reference systems` →
|
|
586
|
+
* `reference-systems`) to the next heading of the same or a higher level,
|
|
587
|
+
* trailing rules and blank lines dropped.
|
|
588
|
+
*/
|
|
589
|
+
declare function ruleSection(page: string, anchor: string): string | undefined;
|
|
590
|
+
declare function contentRule(manifest: Manifest, rawId: string): RuleReport;
|
|
591
|
+
/** The text form of a rule report: the entry's facts, then the page section. */
|
|
592
|
+
declare function formatRuleReport(report: RuleReport): string;
|
|
271
593
|
declare function contentContext(manifest: Manifest, rawId: string): ContextReport;
|
|
594
|
+
/** Where a hit is defined: a shared card, a lesson's `notation.local`, or a card's gloss. */
|
|
595
|
+
type SymbolTier = 'shared' | 'local' | 'gloss';
|
|
596
|
+
interface SymbolHit {
|
|
597
|
+
readonly tier: SymbolTier;
|
|
598
|
+
readonly key: string;
|
|
599
|
+
readonly latex: string;
|
|
600
|
+
readonly label: string;
|
|
601
|
+
readonly meaning?: string;
|
|
602
|
+
readonly units?: string;
|
|
603
|
+
/** How the query matched: the latex as written, an alias, or the key. */
|
|
604
|
+
readonly matchedBy: 'latex' | 'alias' | 'key';
|
|
605
|
+
/** shared: the entry file; local: the lesson id; gloss: the owning card. */
|
|
606
|
+
readonly where: string;
|
|
607
|
+
/** shared only: the pages (lessons and overview pages) whose bundle binds the card. */
|
|
608
|
+
readonly boundIn?: readonly string[];
|
|
609
|
+
}
|
|
610
|
+
interface SymbolReport {
|
|
611
|
+
readonly query: string;
|
|
612
|
+
readonly shared: readonly SymbolHit[];
|
|
613
|
+
readonly local: readonly SymbolHit[];
|
|
614
|
+
readonly glosses: readonly SymbolHit[];
|
|
615
|
+
/** Entries whose latex contains the query as a glyph, not matched above. */
|
|
616
|
+
readonly contains: readonly SymbolHit[];
|
|
617
|
+
/** How many `contains` candidates there were before the list was capped. */
|
|
618
|
+
readonly containsTotal: number;
|
|
619
|
+
}
|
|
620
|
+
declare function contentSymbol(manifest: Manifest, rawQuery: string): SymbolReport;
|
|
621
|
+
/**
|
|
622
|
+
* The text form of a symbol report: one block per tier, then the near
|
|
623
|
+
* misses, then one line that counts what was found, worded for the next
|
|
624
|
+
* step an author takes.
|
|
625
|
+
*/
|
|
626
|
+
declare function formatSymbolReport(report: SymbolReport): string;
|
|
627
|
+
/**
|
|
628
|
+
* A page `content check` checks: a lesson's (its chapter, or a slides-first
|
|
629
|
+
* lesson's deck), or a deck beside its chapter or a part's, by its page id.
|
|
630
|
+
*/
|
|
631
|
+
type CheckTarget = Pick<ManifestLesson, 'id' | 'file' | 'assessments'> & {
|
|
632
|
+
readonly notation: Pick<ManifestLesson['notation'], 'definitionIds'>;
|
|
633
|
+
};
|
|
634
|
+
/**
|
|
635
|
+
* The lesson `rawId` names, or the deck whose page it names: a deck beside
|
|
636
|
+
* its chapter by its route (`motion/range/slides`), a part's deck by its own
|
|
637
|
+
* (`motion/slides`).
|
|
638
|
+
*/
|
|
639
|
+
declare function findCheckTarget(manifest: Manifest, rawId: string): CheckTarget;
|
|
272
640
|
interface CheckLessonResult {
|
|
273
641
|
readonly lesson: string;
|
|
274
642
|
readonly file: string;
|
|
@@ -299,6 +667,22 @@ interface Scaffold {
|
|
|
299
667
|
}[];
|
|
300
668
|
}
|
|
301
669
|
declare function scaffoldLesson(rawId: string): Scaffold;
|
|
670
|
+
/**
|
|
671
|
+
* `content new deck <lesson>`: the slide edition of a lesson, as a draft to
|
|
672
|
+
* rewrite (`docs/authoring/deck.md`). Beside an existing chapter it starts
|
|
673
|
+
* from the chapter: a `##` section per chapter section, a `###` frame per
|
|
674
|
+
* subsection (or one for a section without any), a `<Recall>` for each
|
|
675
|
+
* numbered equation, figure, table and diagram there, and the section's first
|
|
676
|
+
* sentence in the frame's notes. Without a chapter it is a slides-first
|
|
677
|
+
* lesson, with the lesson's frontmatter and a skeleton frame.
|
|
678
|
+
*
|
|
679
|
+
* `content new deck <part>`, for a part's directory with its page
|
|
680
|
+
* (`index.mdx`), drafts the part's deck (`<part>/index.deck.mdx`): a
|
|
681
|
+
* `## <chapter title> [chapter: <name>]` section per chapter, in the order
|
|
682
|
+
* the tracks read them, and a frame per section of the chapter, with a
|
|
683
|
+
* `<Recall>` for each float it numbers and its first sentence in the notes.
|
|
684
|
+
*/
|
|
685
|
+
declare function scaffoldDeck(rawId: string): Scaffold;
|
|
302
686
|
declare function scaffoldTerm(rawKey: string): Scaffold;
|
|
303
687
|
|
|
304
|
-
export { type CheckLessonResult, type CheckReport, type CliDiagnostic, type ContentCliCode, ContentCliError, type ContextReport, type DiagnosticThreshold, type DiagnosticsReport, type DomainFileSignatures, type RenderResult, type RulesReport, type Scaffold, type StatusReport, type TokenCounts, type WarningsReport, changedLessonIds, contentCheck, contentContext, contentDiagnostics, contentRules, contentStatus, contentWarnings, estimateTokens, findLesson, lessonDiagnostics, lessonSource, normalizeLessonId, parseRulesFilter, renderLesson, scaffoldLesson, scaffoldTerm };
|
|
688
|
+
export { type BindingsReport, type BindingsSpan, type CheckLessonResult, type CheckReport, type CheckTarget, type CliDiagnostic, type ContentCliCode, ContentCliError, type ContextReport, type DiagnosticThreshold, type DiagnosticsReport, type DiagnosticsSummary, type DomainFileSignatures, type EditPlan, type EquationReport, type ExplicitWrap, type FileEdit, type MigrateReport, type MigrationSection, type RenderResult, type RuleReport, type RulesReport, type Scaffold, type SpanBinding, type SpanBindings, type StatusReport, type SymbolHit, type SymbolReport, type SymbolTier, type TokenCounts, type UnresolvedGlyph, type WarningsReport, applyEditPlan, authoringDocsDir, changedLessonIds, contentBindings, contentCheck, contentContext, contentDiagnostics, contentEquation, contentMigrate, contentRule, contentRules, contentStatus, contentSymbol, contentWarnings, courseAgentDir, estimateTokens, filterDiagnostics, findCheckTarget, findLesson, formatBindingsReport, formatCliDiagnostic, formatDiagnosticsSummary, formatEquationReport, formatMigrateReport, formatRuleReport, formatSymbolReport, installedEngineVersion, lessonDiagnostics, lessonSource, normalizeLessonId, ownerTag, parseMigrationSections, parseRulesFilter, pinnedEngineVersion, planFix, planFixMany, planInitAgent, planMove, planRename, removeLocalItem, renderEditPlan, renderLesson, rewriteKeyReferences, ruleSection, scaffoldDeck, scaffoldLesson, scaffoldTerm, selectMigrationPath, sharedCardFromLocal, spanBindings, summarizeDiagnostics };
|