From 53f27fb7dbbaef4246374b7c08811b61dbb1551c Mon Sep 17 00:00:00 2001 From: Jeff Dickey <216188+jdx@users.noreply.github.com> Date: Sun, 6 Sep 2026 00:08:55 -0500 Subject: [PATCH 1/3] docs: overhaul guides and redesign the documentation site Entire-Checkpoint: 01M1THX7DZ2NKY3073EFHRHNPZ --- AGENTS.md | 39 +- CONTRIBUTING.md | 16 +- README.md | 111 +-- bin/generate_docs.rs | 4 +- docs/.vitepress/config.mts | 97 +- docs/.vitepress/sidebar.ts | 110 ++- docs/.vitepress/theme/HomePage.vue | 921 ++++++++++-------- docs/.vitepress/theme/Layout.vue | 133 +-- docs/.vitepress/theme/banner.css | 4 +- docs/.vitepress/theme/index.ts | 76 +- docs/.vitepress/theme/style.css | 503 +++------- docs/about.md | 40 +- docs/benchmarks.md | 125 +-- docs/builtins.md | 120 +-- docs/ci.md | 88 ++ docs/cli/agent.md | 21 + docs/cli/agent/hooks.md | 20 + docs/cli/agent/instructions.md | 20 + docs/cli/agent/mcp.md | 20 + docs/cli/builtins.md | 19 + docs/cli/cache/clear.md | 20 + docs/cli/check.md | 30 +- docs/cli/commands.json | 192 ++-- docs/cli/completion.md | 21 + docs/cli/config.md | 21 + docs/cli/config/dump.md | 20 + docs/cli/config/explain.md | 20 + docs/cli/config/get.md | 20 + docs/cli/config/sources.md | 20 + docs/cli/fix.md | 31 +- docs/cli/index.md | 27 +- docs/cli/init.md | 23 + docs/cli/install.md | 22 + docs/cli/mcp.md | 19 + docs/cli/migrate.md | 20 + docs/cli/migrate/pre-commit.md | 20 + docs/cli/run.md | 31 +- docs/cli/run/commit-msg.md | 19 +- docs/cli/run/post-checkout.md | 19 +- docs/cli/run/post-commit.md | 19 +- docs/cli/run/post-merge.md | 19 +- docs/cli/run/post-rewrite.md | 19 +- docs/cli/run/pre-commit.md | 28 +- docs/cli/run/pre-push.md | 19 +- docs/cli/run/pre-rebase.md | 19 +- docs/cli/run/prepare-commit-msg.md | 19 +- docs/cli/sponsors.md | 19 + docs/cli/test.md | 21 + docs/cli/uninstall.md | 20 + docs/cli/util.md | 20 + docs/cli/util/check-added-large-files.md | 19 + docs/cli/util/check-byte-order-marker.md | 19 + docs/cli/util/check-case-conflict.md | 19 + docs/cli/util/check-conventional-commit.md | 19 + .../util/check-executables-have-shebangs.md | 19 + docs/cli/util/check-merge-conflict.md | 19 + docs/cli/util/check-symlinks.md | 19 + docs/cli/util/detect-private-key.md | 19 + docs/cli/util/end-of-file-fixer.md | 20 + docs/cli/util/fix-byte-order-marker.md | 19 + docs/cli/util/fix-smart-quotes.md | 20 + docs/cli/util/mixed-line-ending.md | 20 + docs/cli/util/no-commit-to-branch.md | 19 + docs/cli/util/python-check-ast.md | 19 + docs/cli/util/python-debug-statements.md | 19 + docs/cli/util/trailing-whitespace.md | 20 + docs/cli/validate.md | 20 + docs/cli/version.md | 19 + docs/configuration.md | 518 ++++------ docs/contributing.md | 113 ++- docs/environment_variables.md | 415 +++----- docs/getting_started.md | 188 ++-- docs/glossary.md | 122 +-- docs/hooks.md | 215 ++-- docs/index.md | 4 +- docs/logging.md | 224 ++--- docs/mise_integration.md | 140 +-- docs/pkl_introduction.md | 233 +++-- docs/public/custom-linters.pkl | 117 +-- docs/public/javascript-project.pkl | 35 +- docs/public/llms.txt | 50 +- docs/public/monorepo.pkl | 42 +- docs/public/python-project.pkl | 57 +- docs/reference/examples/custom-linters.md | 176 +--- docs/reference/examples/index.md | 28 +- docs/reference/examples/javascript-project.md | 89 +- docs/reference/examples/monorepo.md | 168 +--- docs/reference/examples/python-project.md | 107 +- docs/shanty.md | 15 +- docs/why-hk.md | 137 +-- hk.usage.kdl | 8 +- mise-tasks/docs/build | 1 + mise-tasks/render/usage | 1 + pkl/Config.pkl | 82 +- scripts/check-docs-links.py | 62 ++ scripts/enrich-cli-docs.py | 157 +++ scripts/generate-examples.sh | 66 +- settings.toml | 102 +- src/hook_options.rs | 9 +- test/README.md | 102 +- 100 files changed, 3736 insertions(+), 3698 deletions(-) create mode 100644 docs/ci.md create mode 100644 scripts/check-docs-links.py create mode 100644 scripts/enrich-cli-docs.py diff --git a/AGENTS.md b/AGENTS.md index 3a3a3eaf9..ed8ff3f69 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ ## mbx build cache -`mise install` installs mbx 1.6. `mise run` activates the project's transparent +`mise install` installs the configured mbx version. `mise run` activates the project's transparent Cargo wrapper, so compilation-heavy mise tasks and hk checks use ordinary `cargo` commands. Standalone Cargo commands require an activated mise shell. If the wrapper fails or creates a development papercut, rerun the exact equivalent @@ -24,6 +24,7 @@ SHOULD use the same format: **Format:** `(): ` **Types:** + - `feat:` - New features - `fix:` - Bug fixes that affect the CLI behavior (not CI, docs, or infrastructure) - `refactor:` - Code refactoring @@ -37,15 +38,18 @@ SHOULD use the same format: - `revert:` - Reverting a previous change **Scopes:** + - For command-specific changes, use the command name: `check`, `fix`, `run`, `init`, `install`, `validate`, etc. - For subsystem changes: `hook`, `step`, `config`, `lock`, `pkl`, `builtins`, `stash`, `deps` **Description Style:** + - Start the description with a lowercase character - Use imperative mood ("add feature" not "added feature") - Keep it concise but descriptive **Examples:** + - `fix(step): resolve race condition in file locking` - `feat(check): add --slow flag for expensive linters` - `feat(builtins): add biome linter` @@ -66,11 +70,13 @@ imperative mood remains a review rule. ## Development Commands **Build the project:** + ```bash mise run build ``` **Run tests:** + ```bash # Run all tests (Rust unit tests + bats integration tests) mise run test @@ -89,6 +95,7 @@ mise run test:bats test/check.bats ``` **Lint and format code:** + ```bash # Run all linters and checks hk check --all @@ -103,28 +110,32 @@ hk fix --all --slow hk is a git hook manager and project linting tool written in Rust with emphasis on performance and concurrent execution. The architecture leverages file locks to maximize concurrency while preventing race conditions. -### Workspace Structure +### Crate Structure + +The root Cargo package builds the **hk** CLI and the **generate-docs** utility. +It depends on separately published crates for shared functionality: -The project is a Cargo workspace with these crates: -- **hk** (root): Main CLI application -- **xx**: HTTP client and utility library +- **xx**: HTTP client and utilities - **clx**: CLI/terminal UI utilities (progress indicators, styling) - **ensembler**: Script/command execution engine ### Core Components **Configuration System (src/config.rs):** + - Main config file: `hk.pkl` in project root - Uses Pkl (github.com/apple/pkl) as the configuration language - Config amends a base schema from `pkl/Config.pkl` **Hook System (src/hook.rs):** + - Manages git hooks (pre-commit, pre-push, commit-msg, prepare-commit-msg) - Supports custom hooks like "check" and "fix" for manual runs - Implements stashing strategies for git hooks - Handles concurrent step execution with proper locking **Step Execution (src/step/):** + - Steps are individual linting/formatting tasks - Each step can have: check, fix, shell commands - Steps support glob patterns for file filtering @@ -132,25 +143,35 @@ The project is a Cargo workspace with these crates: - Steps use read/write file locks to prevent conflicts **File Locking (src/file_rw_locks.rs):** + - Implements a sophisticated file locking system - Allows multiple readers or single writer per file - Prevents race conditions during concurrent execution - Critical for maximizing parallelism **Built-in Linters (pkl/builtins/):** + - Extensive library of pre-configured linters and formatters - Each builtin is a Pkl file defining step configuration - Used via `Builtins.linter_name` in hk.pkl **CLI Interface (src/cli/):** + - Subcommands: init, install, uninstall, check, fix, run, validate, config -- Uses clap for argument parsing +- Uses usage-rs for argument parsing - Supports running specific hooks or steps +### Documentation + +- Preview or build the website with `mise run docs` or `mise run docs:build`. +- Edit generated reference content at its source: `pkl/Config.pkl`, `settings.toml`, builtin definitions, and Rust CLI help comments. +- `scripts/enrich-cli-docs.py` adds maintained examples after CLI reference generation. +- Example pages include `docs/public/*.pkl` directly. Validate them with `scripts/generate-examples.sh` in the mise environment. + ### Key Design Patterns 1. **Concurrent Execution:** Steps run in parallel when possible, using tokio for async runtime -2. **File-based Coordination:** Uses file locks instead of in-memory coordination for cross-process safety +2. **File-based Coordination:** Uses in-memory read/write locks keyed by file path to coordinate steps within a hook run 3. **Pluggable Configuration:** Pkl-based config allows easy extension and customization 4. **Progressive Enhancement:** Works with or without git, libgit2, mise, etc. @@ -163,12 +184,14 @@ The project is a Cargo workspace with these crates: ### Testing Bats integration tests are in `test/*.bats`. Each test file uses a common setup pattern: + ```bash setup() { load 'test_helper/common_setup' _common_setup } ``` + Tests run in isolated temp directories with a clean git repo. The `$PKL_PATH` variable points to the pkl config directory for amending `Config.pkl`. #### Testing Builtins @@ -176,6 +199,7 @@ Tests run in isolated temp directories with a clean git repo. The `$PKL_PATH` va Builtins should have pkl-level tests defined via the `tests` field on the Step (see `pkl/Config.pkl` `StepTest`). These tests are run by `hk test` and exercised in CI via `test/builtins_tests.bats`, which loads all builtins and runs their tests. **Tool stubs** in `test/builtin_tool_stubs/` use `mise tool-stub` to auto-install the correct tool version on demand. Each stub is a small script: + ```bash #!/usr/bin/env -S mise tool-stub version = "2" @@ -183,6 +207,7 @@ tool = "aqua:golangci/golangci-lint" ``` To add a new builtin with tests: + 1. Define the builtin in `pkl/builtins/.pkl` with a `tests` block 2. Add a tool stub in `test/builtin_tool_stubs/` if the tool isn't already available 3. Use the `TestMaker` helper from `pkl/builtins/test/helpers.pkl` for standard check/fix test patterns diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9540019a1..296a8ff5c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,18 @@ -# Contributing +# Contributing to hk -See the [contributing guide](https://hk.jdx.dev/contributing). +Read the [contributing guide](docs/contributing.md) for review expectations, development setup, and how to add a builtin. It is also available on the [documentation website](https://hk.jdx.dev/contributing). + +To get a checkout ready: + +```sh +mise install +mise run build +mise run test +``` + +For a documentation change, use `mise run docs` to preview the site and `mise run docs:build` to validate it. Generated reference content has its own source files; see [editing documentation](docs/contributing.md#edit-documentation). + +PR titles must use Conventional Commits; use the same format for intermediate commits where practical, for example `fix(step): handle missing files` or `docs: clarify hook installation`. ## mbx build cache diff --git a/README.md b/README.md index 9c0110415..f6cd6bc59 100644 --- a/README.md +++ b/README.md @@ -1,63 +1,39 @@ # hk -A fast, language-agnostic git hook manager and project linter. +**Git hooks and project checks, in parallel.** -hk runs linters concurrently while coordinating access to files with read/write locks. This lets -formatters and other tools safely work on overlapping files without racing or silently overwriting -one another's changes. +hk runs linters and formatters with read/write file locks, so independent work runs concurrently and tools that modify the same files take turns. Use the same steps in Git hooks, from your terminal, and in CI. -- Runs independent checks and fixes in parallel -- Safely handles partially staged files by stashing and restoring unstaged changes -- Includes [built-in configurations](https://hk.jdx.dev/builtins) for common linters and formatters -- Uses typed [Pkl](https://pkl-lang.org/) configuration -- Integrates with [mise](https://mise.jdx.dev/) for tool and task management -- Provides fast native checks for common issues such as trailing whitespace and merge conflicts +[Get started](https://hk.jdx.dev/getting_started) · [Documentation](https://hk.jdx.dev/) · [Built-in linters](https://hk.jdx.dev/builtins) · [CLI reference](https://hk.jdx.dev/cli/) ## Quick start -From the project you want to configure, install hk with mise: +Install with [mise](https://mise.jdx.dev/), then run these commands inside your repository: ```sh -cd my-project mise use hk -hk --version -``` - -With Git 2.54 or newer, install hk's hooks once for every repository on your machine: - -```sh -hk install --global -``` - -Then enable hk in a project: - -```sh hk init +hk install +hk check --all ``` -`hk init` detects relevant linters and creates an `hk.pkl` configuration. Review the detected -linters, or use `hk init --interactive` to select them yourself. You can then commit as usual; hk -runs the configured `pre-commit` hook automatically. Repositories without an `hk.pkl` are left -untouched by the global hooks. +`hk init` detects project tools and generates `hk.pkl`. Review the selected linters and make sure their executables are available on `PATH`; hk configures how to run them, but does not install them. Use `hk init --interactive` to choose tools yourself. -On older Git versions, run `hk install` in each project instead. See the -[getting started guide](https://hk.jdx.dev/getting_started) for Homebrew, Cargo, and Aqua installation -options and detailed hook setup. +On Git 2.54+, you can run `hk install --global` once to enable hk across repositories. Installed hooks exit silently in projects without an hk configuration. See [installation options](https://hk.jdx.dev/getting_started#install-hooks) for older Git versions and mise environments. -## Example configuration +You can also install hk with `brew install hk` or `cargo install hk --locked`. The default Pkl evaluator is built into hk; a separate Pkl installation is optional. -The generated `hk.pkl` uses hk's built-in linter definitions, which you can extend when a project -needs different behavior: +## A configuration you can share + +This example uses hk’s built-in whitespace utilities, so it needs no additional linter: ```pkl amends "package://github.com/jdx/hk/releases/download/v1.58.1/hk@1.58.1#/Config.pkl" import "package://github.com/jdx/hk/releases/download/v1.58.1/hk@1.58.1#/Builtins.pkl" local linters = new Mapping { - ["eslint"] = Builtins.eslint - ["prettier"] = (Builtins.prettier) { - glob = List("*.js", "*.ts", "*.json", "*.md") - } + ["trailing-whitespace"] = Builtins.trailing_whitespace + ["newlines"] = Builtins.newlines } hooks { @@ -66,9 +42,7 @@ hooks { stash = "git" steps = linters } - ["check"] { - steps = linters - } + ["check"] { steps = linters } ["fix"] { fix = true steps = linters @@ -76,13 +50,32 @@ hooks { } ``` -Run the same checks directly at any time: +Add tools such as `Builtins.prettier`, `Builtins.eslint`, or `Builtins.ruff`, or [define your own steps](https://hk.jdx.dev/reference/examples/custom-linters). -```sh -hk check # check modified files -hk fix # fix modified files -hk check --all # check the entire repository, useful in CI -``` +## Everyday commands + +| Command | Use it to | +| ------------------------- | ----------------------------------------------------- | +| `hk check` | Check modified files | +| `hk fix` | Apply available fixes to modified files | +| `hk check --all` | Check the repository, including in CI | +| `hk check --plan` | Preview selected files and steps without running them | +| `hk check --why prettier` | Explain why a step will run or be skipped | + +By convention, checks do not modify files. Fixes may modify and stage files; review `git diff` and `git diff --cached`. Use `hk fix --no-stage` to leave fixes unstaged. The generated pre-commit hook stashes unstaged work before fixing staged files, then restores it afterward. [Learn about hooks and partial commits](https://hk.jdx.dev/hooks). + +## Why hk? + +- **Coordinate concurrent tools.** File locks protect overlapping steps; diff and file-list checks reduce the work that needs exclusive access. +- **Reuse linter configurations.** Builtins describe file patterns, check commands, fixes, and tool-specific optimizations. +- **Keep configuration maintainable.** Pkl provides types, imports, and reusable objects for sharing steps across hooks and projects. +- **Use your existing toolchain.** Run commands from `PATH`, or use [mise](https://hk.jdx.dev/mise_integration) to manage tools and environments. + +Read [how hk works](https://hk.jdx.dev/why-hk), browse [project examples](https://hk.jdx.dev/reference/examples/), or see the [benchmark methodology and results](https://hk.jdx.dev/benchmarks). + +## Demo + +![hk running project checks](docs/public/hk-demo.gif) ## Agent skills @@ -98,15 +91,9 @@ to those directories, so compatible installers can use the bundled instructions repository download. Making them available to an agent is opt-in; see [mise's skills documentation](https://mise.jdx.dev/dev-tools/packslip-resources.html). -## Documentation +## Contributing -- [Getting started](https://hk.jdx.dev/getting_started) -- [Configuration reference](https://hk.jdx.dev/configuration) -- [Configuration examples](https://hk.jdx.dev/reference/examples/) -- [Built-in linters](https://hk.jdx.dev/builtins) -- [CLI reference](https://hk.jdx.dev/cli/) -- [Why hk?](https://hk.jdx.dev/why-hk) -- [Contributing](CONTRIBUTING.md) +See the [contributing guide](CONTRIBUTING.md) for development setup, tests, and review expectations. hk is released under the [MIT license](LICENSE). ## Sponsors @@ -129,16 +116,6 @@ opt-in; see [mise's skills documentation](https://mise.jdx.dev/dev-tools/packsli View all sponsors

-## Demo - -![hk demo](docs/public/hk-demo.gif) - -## CI - -

- - Namespace - -

- Thanks to [Namespace](https://namespace.so) for providing CI for hk. + +Namespace diff --git a/bin/generate_docs.rs b/bin/generate_docs.rs index 7274f4d66..0815353ab 100644 --- a/bin/generate_docs.rs +++ b/bin/generate_docs.rs @@ -34,7 +34,7 @@ fn generate_settings_doc() -> Result<(), Box> { // Include per-setting docs as collapsible sections for key in &keys { let opt = registry.options.get(key).unwrap(); - md.push_str(&format!("### `{}`\n\n", key.replace('_', "-"))); + md.push_str(&format!("### `{key}`\n\n")); // Metadata: unordered list with type, default (if any), and sources md.push_str(&format!("- Type: `{}`\n", opt.typ)); if let Some(default) = &opt.default { @@ -308,6 +308,8 @@ fn generate_builtins_doc() -> Result<(), Box> { let display_name = info.name.replace('_', "-"); md.push_str(&format!("### `{}`\n\n", display_name)); + md.push_str(&format!("**Pkl:** `Builtins.{}`\n\n", info.name)); + if !info.description.is_empty() { md.push_str(&format!("{}\n\n", info.description)); } diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 3a7680a95..ed7ebc2c0 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -1,18 +1,20 @@ import { socialCard, writeSocialCard } from "./social-images.mjs"; -import { readFileSync } from 'node:fs' -import { dirname, resolve } from 'node:path' -import { fileURLToPath } from 'node:url' -import { defineConfig } from 'vitepress' +import { readFileSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { defineConfig } from "vitepress"; -import pklLang from '../pkl.tmLanguage.json' -import { sidebar } from './sidebar' +import pklLang from "../pkl.tmLanguage.json"; +import { sidebar } from "./sidebar"; const configDir = dirname(fileURLToPath(import.meta.url)); -const cargoToml = readFileSync(resolve(configDir, '../../Cargo.toml'), 'utf8'); -const versionMatch = cargoToml.match(/^\[package\][\s\S]*?^\s*version\s*=\s*"([^"]+)"/m); +const cargoToml = readFileSync(resolve(configDir, "../../Cargo.toml"), "utf8"); +const versionMatch = cargoToml.match( + /^\[package\][\s\S]*?^\s*version\s*=\s*"([^"]+)"/m, +); if (!versionMatch) { - console.warn('Unable to find package version in Cargo.toml'); + console.warn("Unable to find package version in Cargo.toml"); } -const latestVersion = versionMatch?.[1] ?? '0.0.0'; +const latestVersion = versionMatch?.[1] ?? "0.0.0"; const siteUrl = "https://hk.jdx.dev"; const siteDescription = "Fast, language-agnostic git hooks and project linting with parallel execution, automatic fixes, file locking, and shareable Pkl configuration."; @@ -23,49 +25,57 @@ export default defineConfig({ description: siteDescription, lang: "en-US", lastUpdated: true, - appearance: "force-dark", + appearance: "dark", + // Included reference fragments are not standalone pages. + srcExclude: ["gen/**"], sitemap: { hostname: siteUrl, }, themeConfig: { // https://vitepress.dev/reference/default-theme-config - logo: '/logo-small.png', + logo: "/logo-small.png", nav: [ - { text: 'Getting Started', link: '/getting_started' }, - { text: 'Contributing', link: '/contributing' }, - { text: 'Configuration', link: '/configuration' }, - { text: 'CLI Reference', link: '/cli/' }, - { text: `v${latestVersion}`, link: 'https://github.com/jdx/hk/releases' }, + { + text: "Guide", + link: "/getting_started", + activeMatch: "^/(getting_started|hooks|ci|mise_integration|logging)", + }, + { text: "Configuration", link: "/configuration" }, + { text: "Builtins", link: "/builtins" }, + { text: "CLI", link: "/cli/", activeMatch: "^/cli/" }, + { text: `v${latestVersion}`, link: "https://github.com/jdx/hk/releases" }, ], sidebar, socialLinks: [ - { icon: 'github', link: 'https://github.com/jdx/hk' }, - { icon: 'discord', link: 'https://discord.gg/UBa7pJUN7Z' }, + { icon: "github", link: "https://github.com/jdx/hk" }, + { icon: "discord", link: "https://discord.gg/UBa7pJUN7Z" }, ], editLink: { pattern: "https://github.com/jdx/hk/edit/main/docs/:path", }, search: { - provider: 'local', + provider: "local", }, - footer: false, + outline: { level: [2, 3], label: "On this page" }, }, markdown: { // https://github.com/vuejs/vitepress/discussions/3724 config(md) { - const defaultCodeInline = md.renderer.rules.code_inline! + const defaultCodeInline = md.renderer.rules.code_inline!; md.renderer.rules.code_inline = (tokens, idx, options, env, self) => { - tokens[idx].attrSet('v-pre', '') - return defaultCodeInline(tokens, idx, options, env, self) - } + tokens[idx].attrSet("v-pre", ""); + return defaultCodeInline(tokens, idx, options, env, self); + }; }, - languages: [{ - name: 'pkl', - displayName: 'pkl', - scopeName: 'source.pkl', - repository: {}, - patterns: pklLang.patterns as any, - }] + languages: [ + { + name: "pkl", + displayName: "pkl", + scopeName: "source.pkl", + repository: {}, + patterns: pklLang.patterns as any, + }, + ], }, head: [ [ @@ -110,10 +120,25 @@ export default defineConfig({ ["meta", { name: "twitter:card", content: "summary_large_image" }], ["meta", { name: "twitter:site", content: "@jdxcode" }], ["link", { rel: "icon", href: "/favicon.ico", sizes: "any" }], - ["link", { rel: "icon", type: "image/png", sizes: "32x32", href: "/favicon-32x32.png" }], - ["link", { rel: "apple-touch-icon", sizes: "180x180", href: "/apple-touch-icon.png" }], + [ + "link", + { + rel: "icon", + type: "image/png", + sizes: "32x32", + href: "/favicon-32x32.png", + }, + ], + [ + "link", + { + rel: "apple-touch-icon", + sizes: "180x180", + href: "/apple-touch-icon.png", + }, + ], ["link", { rel: "manifest", href: "/site.webmanifest" }], - ["meta", { name: "theme-color", content: "#0d0221" }], + ["meta", { name: "theme-color", content: "#101a23" }], ], transformHead({ pageData, title, description, siteConfig }) { const heading = @@ -153,4 +178,4 @@ export default defineConfig({ ], ]; }, -}) +}); diff --git a/docs/.vitepress/sidebar.ts b/docs/.vitepress/sidebar.ts index 7e111118d..c97c7ea2c 100644 --- a/docs/.vitepress/sidebar.ts +++ b/docs/.vitepress/sidebar.ts @@ -1,67 +1,85 @@ -import spec from '../cli/commands.json' with { type: 'json' } +import spec from "../cli/commands.json" with { type: "json" }; +import type { DefaultTheme } from "vitepress"; +export type SidebarItem = DefaultTheme.SidebarItem; interface Command { - subcommands: Record + subcommands?: Record; + hide?: boolean; + full_cmd?: string[]; } -export interface SidebarItem { - text: string - link?: string - items?: SidebarItem[] +function commandItems(cmd: Command): DefaultTheme.SidebarItem[] { + return Object.entries(cmd.subcommands ?? {}).flatMap(([name, sub]) => { + const items = commandItems(sub); + if (sub.hide) return items; + return [ + { + text: sub.full_cmd?.join(" ") ?? name, + link: `/cli/${sub.full_cmd?.join("/") ?? name}`, + ...(items.length ? { collapsed: true, items } : {}), + }, + ]; + }); } -/** Return every visible command path in depth-first CLI order. */ -function getCommands(cmd: Command): string[][] { - const commands: string[][] = [] - for (const sub of Object.values(cmd.subcommands)) { - if (sub.hide) continue - commands.push(sub.full_cmd) - commands.push(...getCommands(sub)) - } - return commands -} - -const commands = getCommands(spec.cmd) - -// Shared by VitePress and the llms.txt generator so both expose the same pages. export const sidebar: SidebarItem[] = [ - { text: 'Getting Started', link: '/getting_started' }, - { text: 'Configuration', link: '/configuration' }, { - text: 'Guides', + text: "Start here", items: [ - { text: 'Built-in Linters', link: '/builtins' }, - { text: 'Configuration Examples', link: '/reference/examples/' }, - { text: 'Git Hooks', link: '/hooks' }, - { text: 'mise Integration', link: '/mise_integration' }, - { text: 'Coding Agents', link: '/agents' }, + { text: "Getting started", link: "/getting_started" }, + { text: "Why hk?", link: "/why-hk" }, + { text: "Pkl essentials", link: "/pkl_introduction" }, ], }, { - text: 'CLI Reference', - link: '/cli/', - items: commands.map((cmd) => ({ - text: cmd.join(' '), - link: `/cli/${cmd.join('/')}`, - })), + text: "Guides", + items: [ + { text: "Git hooks and stashing", link: "/hooks" }, + { text: "Continuous integration", link: "/ci" }, + { text: "mise integration", link: "/mise_integration" }, + { text: "Troubleshooting", link: "/logging" }, + { text: "Coding agents", link: "/agents" }, + { + text: "Configuration examples", + link: "/reference/examples/", + collapsed: false, + items: [ + { + text: "JavaScript and TypeScript", + link: "/reference/examples/javascript-project", + }, + { text: "Python", link: "/reference/examples/python-project" }, + { text: "Monorepo", link: "/reference/examples/monorepo" }, + { + text: "Custom steps", + link: "/reference/examples/custom-linters", + }, + ], + }, + ], }, { - text: 'Reference', + text: "Reference", items: [ - { text: 'Environment Variables', link: '/environment_variables' }, - { text: 'Pkl Introduction', link: '/pkl_introduction' }, - { text: 'Logging and Debugging', link: '/logging' }, - { text: 'Glossary', link: '/glossary' }, + { text: "Configuration", link: "/configuration" }, + { text: "Built-in linters", link: "/builtins" }, + { text: "Environment variables", link: "/environment_variables" }, + { text: "Glossary", link: "/glossary" }, + { + text: "CLI commands", + link: "/cli/", + collapsed: true, + items: commandItems(spec.cmd), + }, ], }, { - text: 'Project', + text: "Project", items: [ - { text: 'Why hk?', link: '/why-hk' }, - { text: 'Benchmarks', link: '/benchmarks' }, - { text: 'Contributing', link: '/contributing' }, - { text: 'About', link: '/about' }, - { text: 'Sea Shanty', link: '/shanty' }, + { text: "Benchmarks", link: "/benchmarks" }, + { text: "About hk", link: "/about" }, + { text: "Contributing", link: "/contributing" }, + { text: "Sea shanty", link: "/shanty" }, ], }, -] +]; diff --git a/docs/.vitepress/theme/HomePage.vue b/docs/.vitepress/theme/HomePage.vue index 01a592b70..142909e2d 100644 --- a/docs/.vitepress/theme/HomePage.vue +++ b/docs/.vitepress/theme/HomePage.vue @@ -1,511 +1,566 @@ -