explico 0.13.1 → 0.14.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 +879 -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 +43 -0
- package/dist/compiler/cli-main.js +392 -0
- package/dist/compiler/cli.d.ts +424 -9
- package/dist/compiler/cli.js +1289 -8
- package/dist/compiler/collections.d.ts +88 -1
- package/dist/compiler/collections.js +170 -25
- 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 +359 -58
- package/dist/compiler/page-versions.d.ts +160 -0
- package/dist/compiler/page-versions.js +198 -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 +76 -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 +1 -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 +221 -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 +30 -7
- package/dist/rules/rules.schema.json +259 -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 +29 -9
- package/docs/authoring/agents.md +63 -16
- package/docs/authoring/components.md +15 -0
- package/docs/authoring/deck.md +588 -0
- package/docs/authoring/migrating.md +1045 -16
- package/docs/authoring/notation.md +49 -6
- package/docs/authoring/structure.md +80 -1
- package/docs/authoring/versioning.md +54 -2
- package/docs/authoring/visualizations.md +7 -2
- package/docs/course-agent/AGENTS.md +37 -0
- package/docs/course-agent/agents/rules-reviewer.md +33 -0
- package/docs/course-agent/skills/draft-lesson/SKILL.md +37 -0
- package/docs/course-agent/skills/migrate-course/SKILL.md +31 -0
- package/docs/course-agent/skills/release-content/SKILL.md +24 -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 +469 -0
- package/src/compiler/cli.ts +1905 -16
- package/src/compiler/collections.ts +284 -25
- 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 +558 -63
- package/src/compiler/page-versions.ts +359 -0
- package/src/compiler/resolution-report.ts +38 -7
- package/src/compiler/validate-content.ts +212 -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 +126 -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-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 +257 -4
- package/src/rules/course-rules.ts +21 -1
- package/src/rules/in-effect.ts +54 -8
- 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,392 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
ContentCliError,
|
|
5
|
+
applyEditPlan,
|
|
6
|
+
changedLessonIds,
|
|
7
|
+
contentBindings,
|
|
8
|
+
contentCheck,
|
|
9
|
+
contentContext,
|
|
10
|
+
contentDiagnostics,
|
|
11
|
+
contentEquation,
|
|
12
|
+
contentMigrate,
|
|
13
|
+
contentRule,
|
|
14
|
+
contentRules,
|
|
15
|
+
contentStatus,
|
|
16
|
+
contentSymbol,
|
|
17
|
+
contentWarnings,
|
|
18
|
+
filterDiagnostics,
|
|
19
|
+
findLesson,
|
|
20
|
+
formatBindingsReport,
|
|
21
|
+
formatCliDiagnostic,
|
|
22
|
+
formatDiagnosticsSummary,
|
|
23
|
+
formatEquationReport,
|
|
24
|
+
formatMigrateReport,
|
|
25
|
+
formatRuleReport,
|
|
26
|
+
formatSymbolReport,
|
|
27
|
+
ownerTag,
|
|
28
|
+
parseRulesFilter,
|
|
29
|
+
planFix,
|
|
30
|
+
planInitAgent,
|
|
31
|
+
planMove,
|
|
32
|
+
planRename,
|
|
33
|
+
renderEditPlan,
|
|
34
|
+
scaffoldDeck,
|
|
35
|
+
scaffoldLesson,
|
|
36
|
+
scaffoldTerm,
|
|
37
|
+
summarizeDiagnostics
|
|
38
|
+
} from "./cli.js";
|
|
39
|
+
import { compileManifest } from "./manifest.js";
|
|
40
|
+
const CONTENT_USAGE = `Usage:
|
|
41
|
+
pnpm content status
|
|
42
|
+
pnpm content diagnostics [info|warning|error] [--all | --code <c> | --lesson <id> | --changed] [--json]
|
|
43
|
+
pnpm content warnings [--json]
|
|
44
|
+
pnpm content context <lesson> [--json]
|
|
45
|
+
pnpm content equation "<latex>" [--lesson <id>] [--json]
|
|
46
|
+
pnpm content bindings <lesson> [--json]
|
|
47
|
+
pnpm content symbol <latex | key> [--json]
|
|
48
|
+
pnpm content check <lesson | deck>\u2026 [--changed] [--json]
|
|
49
|
+
pnpm content rule <ID> [--json]
|
|
50
|
+
pnpm content migrate [--from <version>] [--to <version>] [--json]
|
|
51
|
+
pnpm content rules [--element <e>[,<e>]] [--enforcement script|partial|guide|locked] [--edition chapter|deck] [--json]
|
|
52
|
+
pnpm content move <lesson>:<key> [--to <key>] [--write]
|
|
53
|
+
pnpm content rename <old> <new> [--write]
|
|
54
|
+
pnpm content fix <lesson> [--write]
|
|
55
|
+
pnpm content new lesson <id>
|
|
56
|
+
pnpm content new deck <lesson | part>
|
|
57
|
+
pnpm content new term <key>
|
|
58
|
+
pnpm content init-agent [--write]`;
|
|
59
|
+
const VALUED_FLAGS = ["element", "enforcement", "edition", "code", "lesson", "from", "to"];
|
|
60
|
+
function parseContentArgs(argv) {
|
|
61
|
+
const positionals = [];
|
|
62
|
+
const values = {};
|
|
63
|
+
let json = false;
|
|
64
|
+
let changed = false;
|
|
65
|
+
let all = false;
|
|
66
|
+
let write = false;
|
|
67
|
+
const valued = new RegExp(`^--(${VALUED_FLAGS.join("|")})(?:=(.*))?$`);
|
|
68
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
69
|
+
const arg = argv[i];
|
|
70
|
+
const match = valued.exec(arg);
|
|
71
|
+
if (arg === "--json") json = true;
|
|
72
|
+
else if (arg === "--changed") changed = true;
|
|
73
|
+
else if (arg === "--all") all = true;
|
|
74
|
+
else if (arg === "--write") write = true;
|
|
75
|
+
else if (match) values[match[1]] = match[2] ?? argv[i += 1] ?? "";
|
|
76
|
+
else positionals.push(arg);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
command: positionals[0] ?? "",
|
|
80
|
+
positionals: positionals.slice(1),
|
|
81
|
+
json,
|
|
82
|
+
changed,
|
|
83
|
+
all,
|
|
84
|
+
write,
|
|
85
|
+
...values
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
const PROCESS_IO = {
|
|
89
|
+
out: (text) => process.stdout.write(text),
|
|
90
|
+
err: (text) => process.stderr.write(text)
|
|
91
|
+
};
|
|
92
|
+
class Usage extends Error {
|
|
93
|
+
constructor(code, message) {
|
|
94
|
+
super(message);
|
|
95
|
+
this.code = code;
|
|
96
|
+
}
|
|
97
|
+
code;
|
|
98
|
+
}
|
|
99
|
+
function usage(code, message) {
|
|
100
|
+
throw new Usage(code, message);
|
|
101
|
+
}
|
|
102
|
+
function writeScaffold(scaffold) {
|
|
103
|
+
const written = [];
|
|
104
|
+
for (const file of [{ path: scaffold.path, contents: scaffold.contents }, ...scaffold.companions]) {
|
|
105
|
+
const absolute = join(process.cwd(), file.path);
|
|
106
|
+
mkdirSync(dirname(absolute), { recursive: true });
|
|
107
|
+
writeFileSync(absolute, file.contents, { flag: "wx" });
|
|
108
|
+
written.push(file.path);
|
|
109
|
+
}
|
|
110
|
+
return written;
|
|
111
|
+
}
|
|
112
|
+
async function runContentCli(courseConfig, argv = process.argv.slice(2), io = PROCESS_IO) {
|
|
113
|
+
const args = parseContentArgs(argv);
|
|
114
|
+
const json = (value) => io.out(`${JSON.stringify(value, null, 2)}
|
|
115
|
+
`);
|
|
116
|
+
try {
|
|
117
|
+
return await dispatch(courseConfig, args, io, json);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
const code = error instanceof Usage || error instanceof ContentCliError ? error.code : "internal";
|
|
120
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
121
|
+
if (args.json) json({ ok: false, error: { code, message } });
|
|
122
|
+
else io.err(`Error [${code}]: ${message}
|
|
123
|
+
`);
|
|
124
|
+
return 1;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async function dispatch(courseConfig, args, io, json) {
|
|
128
|
+
const out = io.out;
|
|
129
|
+
if (args.command === "" || args.command === "help" || args.command === "--help") {
|
|
130
|
+
out(`${CONTENT_USAGE}
|
|
131
|
+
`);
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
if (args.command === "new") {
|
|
135
|
+
const [kind, id] = args.positionals;
|
|
136
|
+
if (kind !== "lesson" && kind !== "deck" && kind !== "term") {
|
|
137
|
+
usage("unknown-kind", 'content new expects "lesson", "deck" or "term".');
|
|
138
|
+
}
|
|
139
|
+
if (!id) usage("usage", `content new ${kind} needs an id.`);
|
|
140
|
+
if (args.positionals.length > 2) {
|
|
141
|
+
usage("usage", `content new ${kind} takes one id; got also ${args.positionals.slice(2).join(" ")}.`);
|
|
142
|
+
}
|
|
143
|
+
const scaffold = kind === "lesson" ? scaffoldLesson(id) : kind === "deck" ? scaffoldDeck(id) : scaffoldTerm(id);
|
|
144
|
+
const written = writeScaffold(scaffold);
|
|
145
|
+
if (args.json) json({ ok: true, created: written });
|
|
146
|
+
else out(`Created:
|
|
147
|
+
${written.map((p) => ` ${p}`).join("\n")}
|
|
148
|
+
`);
|
|
149
|
+
return 0;
|
|
150
|
+
}
|
|
151
|
+
if (["status", "rules", "warnings"].includes(args.command) && args.positionals.length > 0) {
|
|
152
|
+
usage("usage", `content ${args.command} takes no <lesson>; got ${args.positionals.join(" ")}.`);
|
|
153
|
+
}
|
|
154
|
+
if (args.command === "init-agent") {
|
|
155
|
+
if (args.positionals.length > 0) usage("usage", `content init-agent takes no argument; got ${args.positionals.join(" ")}.`);
|
|
156
|
+
const plan = planInitAgent();
|
|
157
|
+
if (args.json) json({ ...plan, written: args.write });
|
|
158
|
+
else out(renderEditPlan(plan));
|
|
159
|
+
if (plan.edits.length === 0) return 0;
|
|
160
|
+
if (args.write) {
|
|
161
|
+
const touched = applyEditPlan(plan);
|
|
162
|
+
if (!args.json) out(`
|
|
163
|
+
written: ${touched.join(", ")}
|
|
164
|
+
`);
|
|
165
|
+
} else if (!args.json) out("\ndry run: nothing written. Add --write to install.\n");
|
|
166
|
+
return 0;
|
|
167
|
+
}
|
|
168
|
+
if (args.command === "migrate") {
|
|
169
|
+
if (args.positionals.length > 0) {
|
|
170
|
+
usage("usage", `content migrate takes no positional argument; got ${args.positionals.join(" ")}. Use --from and --to.`);
|
|
171
|
+
}
|
|
172
|
+
const report = contentMigrate({
|
|
173
|
+
...args.from === void 0 ? {} : { from: args.from },
|
|
174
|
+
...args.to === void 0 ? {} : { to: args.to }
|
|
175
|
+
});
|
|
176
|
+
if (args.json) json(report);
|
|
177
|
+
else out(formatMigrateReport(report));
|
|
178
|
+
return 0;
|
|
179
|
+
}
|
|
180
|
+
const known = [
|
|
181
|
+
"status",
|
|
182
|
+
"move",
|
|
183
|
+
"rename",
|
|
184
|
+
"fix",
|
|
185
|
+
"rule",
|
|
186
|
+
"rules",
|
|
187
|
+
"warnings",
|
|
188
|
+
"diagnostics",
|
|
189
|
+
"context",
|
|
190
|
+
"equation",
|
|
191
|
+
"bindings",
|
|
192
|
+
"symbol",
|
|
193
|
+
"check"
|
|
194
|
+
];
|
|
195
|
+
if (!known.includes(args.command)) {
|
|
196
|
+
usage("unknown-command", `Unknown command "${args.command}".
|
|
197
|
+
${CONTENT_USAGE}`);
|
|
198
|
+
}
|
|
199
|
+
const manifest = await compileManifest(courseConfig);
|
|
200
|
+
switch (args.command) {
|
|
201
|
+
case "status": {
|
|
202
|
+
const report = contentStatus(manifest);
|
|
203
|
+
if (args.json) {
|
|
204
|
+
json(report);
|
|
205
|
+
return 0;
|
|
206
|
+
}
|
|
207
|
+
const c = report.counts;
|
|
208
|
+
const unreleased = report.pageVersions.unreleased;
|
|
209
|
+
out(
|
|
210
|
+
`Knowledge version ${report.knowledgeVersion}
|
|
211
|
+
Page versions: ${report.pageVersions.tracked} page(s) tracked, ${unreleased.length} with changes not yet released${unreleased.length > 0 ? ` (${unreleased.join(", ")})` : ""}
|
|
212
|
+
Lessons ${c.lessons} \xB7 competencies ${c.competencies} \xB7 assessments ${c.assessments} \xB7 sources ${c.sources} \xB7 tracks ${c.tracks} \xB7 notation ${c.notationDefinitions} \xB7 keyed equations ${c.keyedEquations} \xB7 tables ${c.keyedTables} \xB7 figures ${c.keyedFigures} \xB7 diagrams ${c.keyedDiagrams} \xB7 example sets ${c.keyedExamples}
|
|
213
|
+
Diagnostics: ${report.diagnostics.errors} error(s), ${report.diagnostics.warnings} warning(s), ${report.diagnostics.infos} info
|
|
214
|
+
Orphans: ${report.orphans.length}
|
|
215
|
+
Agent surfaces (estimated tokens): ${report.agentSurfaces.map((s) => `${s.name} ${(s.tokens / 1e3).toFixed(1)}k`).join(" \xB7 ")}
|
|
216
|
+
Agent guide: ${report.agentGuide.agentsFile === null ? "no AGENTS.md \u2014 `pnpm content init-agent --write` installs the baseline" : report.agentGuide.linksGuide ? `${report.agentGuide.agentsFile} points at the engine's guide` : `${report.agentGuide.agentsFile} does not point at node_modules/explico/docs/authoring/agents.md \u2014 add that line`}; procedures ${report.agentGuide.skillsInstalled ? "installed" : "not installed (`pnpm content init-agent --write`)"}
|
|
217
|
+
`
|
|
218
|
+
);
|
|
219
|
+
return 0;
|
|
220
|
+
}
|
|
221
|
+
case "move":
|
|
222
|
+
case "rename":
|
|
223
|
+
case "fix": {
|
|
224
|
+
let plan;
|
|
225
|
+
if (args.command === "move") {
|
|
226
|
+
const [target, ...extra] = args.positionals;
|
|
227
|
+
const [lesson, key] = (target ?? "").split(":");
|
|
228
|
+
if (!lesson || !key || extra.length > 0) usage("usage", "content move needs <lesson>:<key> and optionally --to <key>.");
|
|
229
|
+
plan = planMove(manifest, lesson, key, args.to === void 0 ? {} : { to: args.to });
|
|
230
|
+
} else if (args.command === "rename") {
|
|
231
|
+
const [oldKey, newKey, ...extra] = args.positionals;
|
|
232
|
+
if (!oldKey || !newKey || extra.length > 0) usage("usage", "content rename needs <old> <new>.");
|
|
233
|
+
plan = planRename(manifest, oldKey, newKey);
|
|
234
|
+
} else {
|
|
235
|
+
const [lesson, ...extra] = args.positionals;
|
|
236
|
+
if (!lesson || extra.length > 0) usage("usage", "content fix needs one <lesson> id.");
|
|
237
|
+
plan = planFix(manifest, lesson);
|
|
238
|
+
}
|
|
239
|
+
if (args.json) json({ ...plan, written: args.write });
|
|
240
|
+
else out(renderEditPlan(plan));
|
|
241
|
+
if (plan.edits.length === 0) return 0;
|
|
242
|
+
if (args.write) {
|
|
243
|
+
const touched = applyEditPlan(plan);
|
|
244
|
+
if (!args.json) out(`
|
|
245
|
+
written: ${touched.join(", ")}
|
|
246
|
+
next: ${plan.next.join(" \xB7 ")}
|
|
247
|
+
`);
|
|
248
|
+
} else if (!args.json) {
|
|
249
|
+
out(`
|
|
250
|
+
dry run: nothing written. Add --write to apply; then ${plan.next.join(" \xB7 ")}.
|
|
251
|
+
`);
|
|
252
|
+
}
|
|
253
|
+
return 0;
|
|
254
|
+
}
|
|
255
|
+
case "rule": {
|
|
256
|
+
const [id, ...extra] = args.positionals;
|
|
257
|
+
if (!id) usage("usage", "content rule needs a rule ID: N4, V8, X1, or an invariant such as keyed-floats.");
|
|
258
|
+
if (extra.length > 0) usage("usage", `content rule takes one ID; got also ${extra.join(" ")}.`);
|
|
259
|
+
const report = contentRule(manifest, id);
|
|
260
|
+
if (args.json) json(report);
|
|
261
|
+
else out(formatRuleReport(report));
|
|
262
|
+
return report.status === "unknown" ? 1 : 0;
|
|
263
|
+
}
|
|
264
|
+
case "rules": {
|
|
265
|
+
const filter = parseRulesFilter({
|
|
266
|
+
...args.element === void 0 ? {} : { element: args.element },
|
|
267
|
+
...args.enforcement === void 0 ? {} : { enforcement: args.enforcement },
|
|
268
|
+
...args.edition === void 0 ? {} : { edition: args.edition }
|
|
269
|
+
});
|
|
270
|
+
const report = contentRules(manifest, filter);
|
|
271
|
+
if (args.json) json({ filter: report.filter, count: report.count, rules: report.rules });
|
|
272
|
+
else out(report.markdown);
|
|
273
|
+
return 0;
|
|
274
|
+
}
|
|
275
|
+
case "warnings": {
|
|
276
|
+
const report = contentWarnings(manifest);
|
|
277
|
+
if (args.json) json(report);
|
|
278
|
+
else {
|
|
279
|
+
for (const warning of report.warnings) out(`${formatCliDiagnostic(warning)}
|
|
280
|
+
`);
|
|
281
|
+
out(`${report.count} warning(s)
|
|
282
|
+
`);
|
|
283
|
+
}
|
|
284
|
+
return 0;
|
|
285
|
+
}
|
|
286
|
+
case "diagnostics": {
|
|
287
|
+
const [requested = "info", ...extra] = args.positionals;
|
|
288
|
+
if (extra.length > 0 || requested !== "info" && requested !== "warning" && requested !== "error") {
|
|
289
|
+
usage("usage", "content diagnostics expects one of: info, warning, error.");
|
|
290
|
+
}
|
|
291
|
+
let report = contentDiagnostics(manifest, requested);
|
|
292
|
+
let narrowed = false;
|
|
293
|
+
if (args.code !== void 0) {
|
|
294
|
+
report = filterDiagnostics(report, { code: args.code });
|
|
295
|
+
narrowed = true;
|
|
296
|
+
}
|
|
297
|
+
if (args.lesson !== void 0) {
|
|
298
|
+
report = filterDiagnostics(report, { files: [findLesson(manifest, args.lesson).file] });
|
|
299
|
+
narrowed = true;
|
|
300
|
+
}
|
|
301
|
+
if (args.changed) {
|
|
302
|
+
const ids = new Set(changedLessonIds());
|
|
303
|
+
const files = manifest.lessons.filter((l) => ids.has(l.id)).map((l) => l.file);
|
|
304
|
+
report = filterDiagnostics(report, { files });
|
|
305
|
+
narrowed = true;
|
|
306
|
+
}
|
|
307
|
+
if (args.json) json(report);
|
|
308
|
+
else if (args.all || narrowed) {
|
|
309
|
+
for (const diagnostic of report.diagnostics) out(`${formatCliDiagnostic(diagnostic)}
|
|
310
|
+
`);
|
|
311
|
+
out(`${report.count} diagnostic(s) at ${report.minimumSeverity} or higher
|
|
312
|
+
`);
|
|
313
|
+
} else out(formatDiagnosticsSummary(summarizeDiagnostics(report)));
|
|
314
|
+
return 0;
|
|
315
|
+
}
|
|
316
|
+
case "context": {
|
|
317
|
+
const [lesson, ...extra] = args.positionals;
|
|
318
|
+
if (!lesson) usage("usage", "content context needs a <lesson> id.");
|
|
319
|
+
if (extra.length > 0) usage("usage", `content context takes one <lesson> id; got also ${extra.join(" ")}.`);
|
|
320
|
+
const report = contentContext(manifest, lesson);
|
|
321
|
+
if (args.json) {
|
|
322
|
+
json(report);
|
|
323
|
+
return 0;
|
|
324
|
+
}
|
|
325
|
+
const t = report.tokens;
|
|
326
|
+
out(
|
|
327
|
+
`${report.lesson.id} \u2014 ${report.lesson.title}
|
|
328
|
+
teaches: ${report.lesson.teaches.join(", ") || "(none)"}
|
|
329
|
+
requires: ${report.lesson.requires.join(", ") || "(none)"}
|
|
330
|
+
notation: ${report.notation.map((n) => n.key).join(", ") || "(none)"}
|
|
331
|
+
sources: ${report.sources.map((s) => s.id).join(", ") || "(none)"}
|
|
332
|
+
diagnostics: ${report.diagnostics.length}
|
|
333
|
+
tokens: context ${t.context} vs doc set ${t.docSet} + corpus ${t.corpus} (${(t.ratio * 100).toFixed(2)}% of the baseline)
|
|
334
|
+
`
|
|
335
|
+
);
|
|
336
|
+
return 0;
|
|
337
|
+
}
|
|
338
|
+
case "equation": {
|
|
339
|
+
const [latex, ...extra] = args.positionals;
|
|
340
|
+
if (!latex) usage("usage", "content equation needs one quoted LaTeX string: content equation 'v_0 \\sin(\\theta)' --lesson <id>.");
|
|
341
|
+
if (extra.length > 0) usage("usage", `content equation takes one string; got also ${extra.join(" ")}. Quote the whole expression.`);
|
|
342
|
+
const report = contentEquation(manifest, latex, args.lesson === void 0 ? {} : { lesson: args.lesson });
|
|
343
|
+
if (args.json) json(report);
|
|
344
|
+
else out(formatEquationReport(report));
|
|
345
|
+
return report.ok ? 0 : 1;
|
|
346
|
+
}
|
|
347
|
+
case "bindings": {
|
|
348
|
+
const [lesson, ...extra] = args.positionals;
|
|
349
|
+
if (!lesson) usage("usage", "content bindings needs a <lesson> id.");
|
|
350
|
+
if (extra.length > 0) usage("usage", `content bindings takes one <lesson> id; got also ${extra.join(" ")}.`);
|
|
351
|
+
const report = contentBindings(manifest, lesson);
|
|
352
|
+
if (args.json) json(report);
|
|
353
|
+
else out(formatBindingsReport(report));
|
|
354
|
+
return 0;
|
|
355
|
+
}
|
|
356
|
+
case "symbol": {
|
|
357
|
+
const [query, ...extra] = args.positionals;
|
|
358
|
+
if (!query) usage("usage", "content symbol needs a <latex | key>; quote a backslash: '\\theta'.");
|
|
359
|
+
if (extra.length > 0) {
|
|
360
|
+
usage("usage", `content symbol takes one <latex | key>; got also ${extra.join(" ")}. Quote a symbol with spaces: 'v(t)'.`);
|
|
361
|
+
}
|
|
362
|
+
const report = contentSymbol(manifest, query);
|
|
363
|
+
if (args.json) json(report);
|
|
364
|
+
else out(formatSymbolReport(report));
|
|
365
|
+
return 0;
|
|
366
|
+
}
|
|
367
|
+
case "check": {
|
|
368
|
+
const report = await contentCheck(manifest, { lessons: args.positionals, changed: args.changed });
|
|
369
|
+
if (args.json) json(report);
|
|
370
|
+
else {
|
|
371
|
+
for (const entry of report.lessons) {
|
|
372
|
+
out(`${entry.ok ? "ok " : "FAIL"} ${entry.lesson}${entry.rendered ? "" : " (render failed)"}
|
|
373
|
+
`);
|
|
374
|
+
for (const diagnostic of entry.diagnostics) {
|
|
375
|
+
out(` [${diagnostic.severity}] ${diagnostic.code}${ownerTag(diagnostic)}: ${diagnostic.message}
|
|
376
|
+
`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
if (report.lessons.length === 0) out("No changed lessons.\n");
|
|
380
|
+
}
|
|
381
|
+
return report.ok ? 0 : 1;
|
|
382
|
+
}
|
|
383
|
+
default:
|
|
384
|
+
return usage("unknown-command", `Unknown command "${args.command}".
|
|
385
|
+
${CONTENT_USAGE}`);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
export {
|
|
389
|
+
CONTENT_USAGE,
|
|
390
|
+
parseContentArgs,
|
|
391
|
+
runContentCli
|
|
392
|
+
};
|