VS Code / Cursor extension that turns a GitHub course repository (Learning Course Protocol) plus a source repository into a real local learning workspace. You learn by implementing feature increments, not by reverse-engineering the final tree.
This repo is a pnpm + Vite+ monorepo. It does not host courses, user accounts, or AI explanations.
Website: rjiazhen.github.io/learn-by-diff (Simplified Chinese first; English pages are placeholders).
Agents: start at AGENTS.md (architecture: docs/architecture.md).
| Path | Role |
|---|---|
packages/protocol |
LCP types, YAML parse, validation (@learn-by-diff/protocol) |
apps/vscode-extension |
VS Code extension (learn-by-diff) |
apps/website |
Project site (VitePress, GitHub Pages) |
sandbox/ |
F5 debug workspace (generated files are gitignored) |
skills/, examples/ |
Author skills (course scaffolding); committed local demo course/source |
Requires Node 22+, pnpm, Git, and the vp CLI from Vite+ (or use pnpm exec vp).
pnpm install
pnpm exec vp check
pnpm exec vp run -r test
pnpm exec vp run @learn-by-diff/protocol#pack
pnpm exec vp run learn-by-diff#pack
pnpm --filter website devPress F5 (Run Extension). The prelaunch task runs vp pack --watch, then the Extension Development Host opens sandbox/ in a temporary empty profile (no other user extensions). After code changes, reload the Extension Development Host window to pick up the rebuilt bundle. LearnByDiff: Open Course prefills examples/demo-course/.course-config/course.yml.
Real users pick a parent folder; the workspace is created as {parent}/{course.id}/.
With the extension installed, a link can launch VS Code or Cursor and run Open Course:
vscode://RuanJiazhen.learn-by-diff/open?url=<urlencoded-course.yml-or-repo>
cursor://RuanJiazhen.learn-by-diff/open?url=<urlencoded-course.yml-or-repo>
Optional parent=<urlencoded-absolute-folder> skips the folder picker. Example:
<a href="vscode://RuanJiazhen.learn-by-diff/open?url=https%3A%2F%2Fgithub.com%2Forg%2Fcourse.git">
Open in VS Code
</a>The IDE must already have LearnByDiff installed; the OS may ask to allow the vscode:// / cursor:// protocol once.
Course authors typically keep:
course.yml # Open Course takes this file
chapters/*.yml # default chaptersDir
# or
.course-config/course.yml
.course-config/chapters/*.yml
course.yml fields are all optional: id defaults from the course home folder (or {repo}-learn at a git root), title defaults to id, source.repository defaults to . (the course home), chaptersDir defaults to chapters next to course.yml. Optional source.root prefixes chapter dirs. Chapter YAML fields are all optional: id/title default from the filename, empty fromDir/toDir mean empty trees, omitted entryFiles auto-discovers all files under toDir, optional docs is an http(s) URL or a relative doc path under the chapter snapshot. Nested paths and unrelated parents in the same repo are supported; separate remotes per chapter are not.
Authoring: JSON Schema lives at packages/protocol/schema.json. Point YAML files at it with a top comment, e.g. # yaml-language-server: $schema=../../../packages/protocol/schema.json#/$defs/course. Runtime validation still uses @learn-by-diff/protocol.
Scaffold .course-config from chapter snapshot folders with the generate-course-config skill:
npx skills add RJiazhen/learn-by-diff@generate-course-config -yThen open an Agent chat and run /generate-course-config (or ask to generate course config). Without explicit directories, the skill tries to detect start / step-N-style siblings; if detection fails it asks you for paths. Details: skills/README.md.
Learning workspaces created by the extension use .learn/ (progress, source mirror, config copy). Opening a course repo to edit config does not restore a learning session.
Push an annotated tag vX.Y.Z matching apps/vscode-extension/package.json version. GitHub Actions packages one VSIX and publishes it to:
- Visual Studio Marketplace (
VSCE_PAT) - Open VSX (
OVSX_PAT)
publisher is RuanJiazhen (same as Powerful NPM Run); the Open VSX namespace must match. Both secrets are required; the job fails if either is missing.
Do not use local vsce publish as the release path. vsce package is fine for a local preview.