diff --git a/.gitignore b/.gitignore index 08772cfdc..30ad0db2c 100644 --- a/.gitignore +++ b/.gitignore @@ -120,6 +120,8 @@ book/tools/scripts/testing/logs/ *.lof *.lot *.pdf +# Callout icon PDFs needed for PDF builds (and parallel worktree builds) +!book/quarto/assets/images/icons/callouts/*.pdf # Database *.db diff --git a/book/quarto/assets/images/icons/callouts/icon_callout_fallacy.pdf b/book/quarto/assets/images/icons/callouts/icon_callout_fallacy.pdf new file mode 100644 index 000000000..e368c46ff Binary files /dev/null and b/book/quarto/assets/images/icons/callouts/icon_callout_fallacy.pdf differ diff --git a/book/quarto/assets/images/icons/callouts/icon_callout_pitfall.pdf b/book/quarto/assets/images/icons/callouts/icon_callout_pitfall.pdf new file mode 100644 index 000000000..ca77cda86 Binary files /dev/null and b/book/quarto/assets/images/icons/callouts/icon_callout_pitfall.pdf differ diff --git a/book/quarto/assets/images/icons/callouts/icon_callout_takeaways.pdf b/book/quarto/assets/images/icons/callouts/icon_callout_takeaways.pdf new file mode 100644 index 000000000..30b93f31d Binary files /dev/null and b/book/quarto/assets/images/icons/callouts/icon_callout_takeaways.pdf differ diff --git a/book/vscode-ext/README.md b/book/vscode-ext/README.md index f03617354..61b8ad98d 100644 --- a/book/vscode-ext/README.md +++ b/book/vscode-ext/README.md @@ -49,6 +49,21 @@ This keeps daily actions focused while preserving easy access to tuning controls - Validate content: `./book/binder validate all` - Maintenance checks: `./book/binder maintain repo-health` +## Parallel builds (Test All Chapters) + +**Build All Chapters (Parallel)** in the Debug view runs each chapter in a separate git worktree so multiple PDF builds run at once. + +**Requirements:** + +1. **Open the repo root** — Open the folder that contains `book/` (e.g. `mlsysbook-vols`), not a subfolder like `book/` or `book/quarto/`. The extension needs `book/binder` to be present to register commands and run parallel jobs. +2. **Git in PATH** — Parallel mode uses `git worktree add --detach`; ensure `git` is available in the environment where the extension runs. +3. **Optional settings** (VS Code/Cursor → Settings → MLSysBook): + - `mlsysbook.parallelDebugWorkers` — number of concurrent builds (default: 4). + - `mlsysbook.parallelDebugRoot` — directory for worktrees under repo root (default: `.mlsysbook/worktrees`). + - `mlsysbook.keepFailedWorktrees` — keep worktrees for failed chapters for inspection (default: true). + +If worktree creation fails, check the **MLSysBook Parallel Debug** output channel; the first failure will include a tip about repo root and git. + ## Quarto Visual Customization The extension includes QMD-focused visual highlighting to improve scanability in long Quarto documents. diff --git a/book/vscode-ext/src/commands/debugCommands.ts b/book/vscode-ext/src/commands/debugCommands.ts index 8cbdc5153..ed04afb6b 100644 --- a/book/vscode-ext/src/commands/debugCommands.ts +++ b/book/vscode-ext/src/commands/debugCommands.ts @@ -18,11 +18,19 @@ const STATE_LAST_PARALLEL_VOLUME = 'mlsysbook.lastParallelVolume'; /** * Test All Chapters — prompts for volume only, then builds every chapter * in parallel using PDF format and the configured worker count. + * Requires workspace opened at repo root (folder containing book/) and git in PATH. */ async function runTestAllChapters( root: string, context: vscode.ExtensionContext, ): Promise { + const repoRoot = getRepoRoot(); + if (!repoRoot) { + vscode.window.showErrorMessage( + 'MLSysBook: Parallel build requires the workspace to be the repository root (the folder that contains book/). Open that folder and try again.', + ); + return; + } const defaultVolume = context.workspaceState.get(STATE_LAST_PARALLEL_VOLUME); const picks = [ { label: defaultVolume === 'vol1' ? 'Volume I (last used)' : 'Volume I', id: 'vol1' as VolumeId }, @@ -32,7 +40,7 @@ async function runTestAllChapters( if (!selection) { return; } const volumeId = selection.id; - const volumes = discoverChapters(root); + const volumes = discoverChapters(repoRoot); const volume = volumes.find(v => v.id === volumeId); if (!volume || volume.chapters.length === 0) { vscode.window.showWarningMessage(`No chapters found for ${volumeId}.`); @@ -51,7 +59,7 @@ async function runTestAllChapters( ); await runParallelChapterDebug({ - repoRoot: root, + repoRoot, volume: volumeId, format: 'pdf', chapters: allChapters, diff --git a/book/vscode-ext/src/utils/parallelDebug.ts b/book/vscode-ext/src/utils/parallelDebug.ts index 19ea59a43..2fc376aa3 100644 --- a/book/vscode-ext/src/utils/parallelDebug.ts +++ b/book/vscode-ext/src/utils/parallelDebug.ts @@ -442,6 +442,9 @@ async function runParallelDebugBatch(options: BatchRunOptions): Promise<{ result elapsedMs: Date.now() - start, }); channel.appendLine(`[${tag}] failed to create worktree (exit ${addCode})`); + if (index === 0) { + channel.appendLine('[session] Tip: ensure the workspace is the repo root and `git` is in PATH.'); + } continue; }