This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
A reusable CLI (lecture-toolkit) that wraps Slidev workflows for lecture repositories. It is not itself a lecture repo — it is installed as a dev dependency into lecture repos (e.g. mpd-lectures) that contain a decks/ directory, one subdirectory per deck with a slides.md.
Pure ESM Node project ("type": "module", Node >= 20). No build step, no TypeScript, no test suite, and no lint config — source in src/ is published and run as-is. pnpm is the package manager.
node bin/lecture-toolkit.js <command> [args] # run the CLI directly from this repoThere are no dev/build/test/lint scripts in package.json. The only script is release (semantic-release, normally run by CI). To exercise commands manually you must run inside a lecture repo containing a decks/ directory, since nearly every command calls findProjectRoot() and aborts otherwise.
Releases are automated: Conventional Commits on main drive semantic-release (.releaserc.json, .github/workflows/release.yml), publishing a git tag, GitHub Release, and an npm package to GitHub Packages. fix: → patch, feat: → minor, feat!:/BREAKING CHANGE: → major. Commit messages therefore directly determine version bumps.
Entry: bin/lecture-toolkit.js → src/index.js runCommand(), a single switch dispatching the first argv token to one run* function per command in src/commands/. To add a command: create src/commands/<name>.js exporting a run* function, then import + add a case in src/index.js and a line in usage().
Three shared libraries in src/lib/ underpin every command:
project.js— the contract all commands share.findProjectRoot()walks up from cwd looking for adecks/dir (throws if none).resolveSlidesPath()/ensureSlidesPath()turn a<deck>argument into an absoluteslides.mdpath, accepting three forms: a directory-name prefix (e.g.09or09-DFS-BFS, first match by sorted order),decks/<deck>, ordecks/<deck>/slides.md.parseDeckArg()extracts the single deck arg (tolerating a leading--). Any command taking a deck should reuse these rather than re-parsing paths.exec.js—run(command, args, opts)wrapsspawnSyncwithstdio: 'inherit'and throws on non-zero exit. This is how commands shell out topnpm slidev,dot,pdflatex,bash, etc. Use it for synchronous external tools; commands needing concurrency (dev-deck,watch-notes) usespawn/spawnSyncdirectly.config.js—loadToolkitConfig(rootDir)reads optionallecture-toolkit.config.jsonfrom the lecture repo root (returns{}if absent);pickSection(config, name)pulls a validated object subsection. Config sections seen so far:index(build-index branding) andchangelog.
- Notes:
export-notesparsesslides.md(frontmatter-aware, fenced-code-aware slide splitting) and writes anotes.mdwith a timestamped header, GitLab blob links, and a Bear tag footer; the lecture short-name is derived from the repo-name prefix (mpd-lectures→mpd).watch-notesdebounce-regeneratesnotes.mdon file changes.strip-presenter-notesremoves presenter<!-- ... -->notes from aslides.md(also invoked standalone by the changelog script). - Build/export:
build-deck/build-allrunpnpm slidev buildper deck intodist/<name>with--base /<CI_PROJECT_NAME or "lectures">/<name>/ --without-notes. This subpath base is broken by a Slidev 52.16.0 regression: in-deck navigation under any non-root base doubles the path (…/<deck>/<deck>/2→ 404) in bothhistoryandhashrouterMode. Cause: the client'sgetSlidePath()began prependingimport.meta.env.BASE_URLwhilecreateWebHistory(BASE_URL)already adds it (base-relative/${no}up to 52.15.0, base-prefixed from 52.16.0). The fix lives in the consuming repo, not here — pin@slidev/clito52.15.0. See the README "Subpath Hosting" section.export-pdf-deck/export-pdfsproduce PDFs.build-indexgenerates a landingindex.htmlover all decks (branding from theindexconfig section / CLI flags).dev-deckrunsslidev --remoteand auto-spawnswatch-notessonotes.mdstays current while editing. - Figures:
render-dot(Graphviz.dot→.svg) andrender-tikz(LaTeX TikZ → image) scan every deck'sfigures-src/and write into the deck'sfigures/. - Changelogs:
generate-changelogs.jsis a thin wrapper that shells intosrc/scripts/generate-changelogs.sh, passing all configuration viaLECTURE_TOOLKIT_*env vars (decks dir, output dir, global reset file/date, and the path to the strip-presenter-notes script). The substantive logic lives in the bash script.
- Commands
throwon error; the top-level runners inbin/andsrc/index.jscatch, print the message, andprocess.exit(1). Don't add ad-hocprocess.exitinside command bodies — throw instead. - Diagnostic/progress output goes to stderr (
console.error), keeping stdout clean. CI_PROJECT_NAME(GitLab CI) sets the deploy base path for builds; defaults tolectureslocally.- Conventions, paths, and the
decks/layout are a contract with consuming lecture repos — changing argument forms, output locations, or config keys is a breaking change for downstream repos and should be afeat!:/BREAKING CHANGE:commit.