From 141c5c34d5dda2ce47bf136122ce016da2ede8d4 Mon Sep 17 00:00:00 2001 From: herata Date: Thu, 14 May 2026 18:06:34 +0900 Subject: [PATCH 1/5] chore: add pre-commit hooks (file hygiene, secrets, markdown, rust, commits) Adds a pre-commit framework configuration with five hook groups: - File hygiene: trailing-whitespace, end-of-file-fixer, check-yaml/toml/json, check-merge-conflict, mixed-line-ending (LF), detect-private-key, check-added-large-files (1 MiB cap). - Secret detection: gitleaks v8.21.2. - Markdown lint: markdownlint-cli2 with a relaxed config that disables rules that fight Japanese line widths and legitimate inline HTML. - Conventional Commits validator: compilerla/conventional-pre-commit on the commit-msg stage with the standard 11-type allowlist. - Rust local hooks: `cargo fmt --check` and `cargo clippy --all-targets -- -D warnings`, matching the CI gate. CI runs the same set via the new `pre-commit` job (libdbus pre-installed so the cargo hooks can build keyring's transitive deps; rustfmt + clippy components pinned on the dtolnay toolchain action). README and README.ja.md gained a "pre-commit hooks" subsection under Development pointing contributors at `pre-commit install` plus the `commit-msg` hook type. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 14 +++++++++ .markdownlint-cli2.yaml | 15 ++++++++++ .pre-commit-config.yaml | 65 ++++++++++++++++++++++++++++++++++++++++ README.ja.md | 21 +++++++++++++ README.md | 22 ++++++++++++++ 5 files changed, 137 insertions(+) create mode 100644 .markdownlint-cli2.yaml create mode 100644 .pre-commit-config.yaml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bfc4805..cab0138 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -79,6 +79,20 @@ jobs: - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.7.4 - run: cargo check --all-features + pre-commit: + name: pre-commit + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - name: install libdbus + run: sudo apt-get update && sudo apt-get install -y --no-install-recommends libdbus-1-dev pkg-config + - uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # stable + with: + toolchain: "1.89" + components: rustfmt, clippy + - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.7.4 + - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 + linux-headless: name: linux headless (no D-Bus) runs-on: ubuntu-latest diff --git a/.markdownlint-cli2.yaml b/.markdownlint-cli2.yaml new file mode 100644 index 0000000..d8036cb --- /dev/null +++ b/.markdownlint-cli2.yaml @@ -0,0 +1,15 @@ +# markdownlint-cli2 config for slack-cli. +# Mainly relaxes rules that fight against Japanese line widths and +# legitimate inline HTML / bare URLs in README content. + +config: + line-length: false + no-inline-html: false + no-bare-urls: false + first-line-h1: false + no-duplicate-heading: false + no-emphasis-as-heading: false + +ignores: + - 'CHANGELOG.md' + - 'target/**' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..5763973 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,65 @@ +# pre-commit hooks for slack-cli. +# +# Install (one-time, per clone): +# pip install --user pre-commit # or: brew install pre-commit, pipx install pre-commit +# pre-commit install +# pre-commit install --hook-type commit-msg +# +# Run manually on every tracked file: +# pre-commit run --all-files + +repos: + # ----- File hygiene ----- + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + exclude: '\.snap$' + - id: end-of-file-fixer + exclude: '\.snap$' + - id: check-yaml + - id: check-toml + - id: check-json + - id: check-merge-conflict + - id: check-added-large-files + args: [--maxkb=1024] + - id: mixed-line-ending + args: [--fix=lf] + - id: detect-private-key + + # ----- Secret detection ----- + - repo: https://github.com/gitleaks/gitleaks + rev: v8.21.2 + hooks: + - id: gitleaks + + # ----- Markdown lint ----- + - repo: https://github.com/DavidAnson/markdownlint-cli2 + rev: v0.14.0 + hooks: + - id: markdownlint-cli2 + args: ['--config', '.markdownlint-cli2.yaml'] + + # ----- Conventional Commits (commit-msg only) ----- + - repo: https://github.com/compilerla/conventional-pre-commit + rev: v3.6.0 + hooks: + - id: conventional-pre-commit + stages: [commit-msg] + args: [feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert] + + # ----- Rust (local hooks; require cargo on PATH) ----- + - repo: local + hooks: + - id: cargo-fmt + name: cargo fmt --check + entry: cargo fmt --all -- --check + language: system + types: [rust] + pass_filenames: false + - id: cargo-clippy + name: cargo clippy --all-targets -- -D warnings + entry: cargo clippy --all-targets -- -D warnings + language: system + types: [rust] + pass_filenames: false diff --git a/README.ja.md b/README.ja.md index ecffaed..3bb43c4 100644 --- a/README.ja.md +++ b/README.ja.md @@ -149,6 +149,27 @@ mise run snap # 未確定の insta スナップショットをレビュ mise run run -- channel list ``` +### pre-commit hooks + +クローン直後に一度だけ設定(`pre-commit` を PATH に入れて `.git/hooks` に登録します): + +```sh +pip install --user pre-commit # または brew install pre-commit / pipx install pre-commit +pre-commit install +pre-commit install --hook-type commit-msg +``` + +全 tracked file に対して手動実行: + +```sh +pre-commit run --all-files +``` + +`.pre-commit-config.yaml` で次を設定: ファイル衛生チェック、gitleaks +(secret scan)、markdownlint、Conventional Commits validator(commit-msg)、 +ローカル hook として `cargo fmt --check` と `cargo clippy --all-targets -- -D warnings`。 +CI でも同じ hook 群を各 PR で実行します。 + ## ライセンス MIT OR Apache-2.0 のデュアルライセンス。 diff --git a/README.md b/README.md index 5617c1e..8774d8b 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,28 @@ mise run snap # Review pending insta snapshots mise run run -- channel list ``` +### pre-commit hooks + +One-time setup per clone (installs `pre-commit` to your PATH and wires up +`.git/hooks`): + +```sh +pip install --user pre-commit # or: brew install pre-commit / pipx install pre-commit +pre-commit install +pre-commit install --hook-type commit-msg +``` + +Run all hooks against every tracked file: + +```sh +pre-commit run --all-files +``` + +Configured in `.pre-commit-config.yaml`: file hygiene, gitleaks (secret +scan), markdownlint, Conventional Commits validator (commit-msg), plus +`cargo fmt --check` and `cargo clippy --all-targets -- -D warnings` as +local hooks. The CI workflow runs the same set on every PR. + ## License Dual-licensed under MIT OR Apache-2.0. From f57ff3cf52ed1f77c832792d1a577bec65973963 Mon Sep 17 00:00:00 2001 From: herata Date: Thu, 14 May 2026 18:14:50 +0900 Subject: [PATCH 2/5] fix(pre-commit): route cargo hooks through mise + ignore internal docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI's pre-commit job failed on the first run for two reasons: 1. markdownlint flagged six MD040/MD032 violations in docs/superpowers/{plans,specs}/*.md — those are internal brainstorming / implementation notes, not user-facing docs. Add `docs/superpowers/**` to the markdownlint ignore list. 2. The local cargo hooks used plain `cargo`, which resolves through the host's rustup default. On the contributor machine that ended up being a stale 1.80.1 toolchain even though `mise.toml` pins 1.89, so the hook errored with "rustc 1.80.1 is not supported". Route both cargo hooks through `mise exec --` so the pinned toolchain is always used. CI's pre-commit job now installs mise (with GITHUB_TOKEN for the ubi backend rate limit), then `rustup component add rustfmt clippy` guarantees the components are present. Local verification: `pre-commit run --all-files` now passes all 13 hooks (file hygiene, gitleaks, markdownlint, cargo fmt, cargo clippy). The `commit-msg` hook is also installed so this very commit went through the conventional-pre-commit validator. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 10 +++++++--- .markdownlint-cli2.yaml | 2 ++ .pre-commit-config.yaml | 6 +++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cab0138..c5327ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,10 +86,14 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: install libdbus run: sudo apt-get update && sudo apt-get install -y --no-install-recommends libdbus-1-dev pkg-config - - uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # stable + - uses: jdx/mise-action@5083fe46898c414b2475087cc79da59e7da859e8 # v2.1.11 with: - toolchain: "1.89" - components: rustfmt, clippy + install: true + cache: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: ensure rustfmt + clippy components + run: rustup component add rustfmt clippy - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.7.4 - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 diff --git a/.markdownlint-cli2.yaml b/.markdownlint-cli2.yaml index d8036cb..ac113a5 100644 --- a/.markdownlint-cli2.yaml +++ b/.markdownlint-cli2.yaml @@ -13,3 +13,5 @@ config: ignores: - 'CHANGELOG.md' - 'target/**' + # Internal brainstorming spec + implementation plan, kept as-is. + - 'docs/superpowers/**' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5763973..137061d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -48,18 +48,18 @@ repos: stages: [commit-msg] args: [feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert] - # ----- Rust (local hooks; require cargo on PATH) ----- + # ----- Rust (local hooks via mise so the toolchain is always pinned) ----- - repo: local hooks: - id: cargo-fmt name: cargo fmt --check - entry: cargo fmt --all -- --check + entry: mise exec -- cargo fmt --all -- --check language: system types: [rust] pass_filenames: false - id: cargo-clippy name: cargo clippy --all-targets -- -D warnings - entry: cargo clippy --all-targets -- -D warnings + entry: mise exec -- cargo clippy --all-targets -- -D warnings language: system types: [rust] pass_filenames: false From 7a40dc7f14b9e240c4254677a6865429941439b2 Mon Sep 17 00:00:00 2001 From: herata Date: Thu, 14 May 2026 18:20:39 +0900 Subject: [PATCH 3/5] chore(pre-commit): autoupdate hook revs and disable MD060 for CJK tables Address CodeRabbit's review on PR #10: the pinned hook revs were stale. Ran `pre-commit autoupdate` and bumped: - pre-commit-hooks v5.0.0 -> v6.0.0 - gitleaks v8.21.2 -> v8.30.0 - markdownlint-cli2 v0.14.0 -> v0.22.1 - conventional-pre-commit v3.6.0 -> v4.4.0 markdownlint-cli2 v0.22 enabled MD060/table-column-style by default, which fires on every row of README/README.ja.md tables that mix full-width Japanese characters with ASCII. Pipe alignment for those tables would only be byte-accurate, not visually accurate, so disable the rule in `.markdownlint-cli2.yaml` with a comment. Local `pre-commit run --all-files` passes all 13 hooks. Co-Authored-By: Claude Opus 4.7 (1M context) --- .markdownlint-cli2.yaml | 4 ++++ .pre-commit-config.yaml | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.markdownlint-cli2.yaml b/.markdownlint-cli2.yaml index ac113a5..e1a2a75 100644 --- a/.markdownlint-cli2.yaml +++ b/.markdownlint-cli2.yaml @@ -9,6 +9,10 @@ config: first-line-h1: false no-duplicate-heading: false no-emphasis-as-heading: false + # Tables with mixed-width (CJK + ASCII) characters cannot be aligned by + # column at the byte/code-point level. Keep tables readable by content, + # not by pipe alignment. + table-column-style: false ignores: - 'CHANGELOG.md' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 137061d..f35ff96 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,7 +11,7 @@ repos: # ----- File hygiene ----- - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: trailing-whitespace exclude: '\.snap$' @@ -29,20 +29,20 @@ repos: # ----- Secret detection ----- - repo: https://github.com/gitleaks/gitleaks - rev: v8.21.2 + rev: v8.30.0 hooks: - id: gitleaks # ----- Markdown lint ----- - repo: https://github.com/DavidAnson/markdownlint-cli2 - rev: v0.14.0 + rev: v0.22.1 hooks: - id: markdownlint-cli2 args: ['--config', '.markdownlint-cli2.yaml'] # ----- Conventional Commits (commit-msg only) ----- - repo: https://github.com/compilerla/conventional-pre-commit - rev: v3.6.0 + rev: v4.4.0 hooks: - id: conventional-pre-commit stages: [commit-msg] From 438cd0bb9c07c64e44bdb7d73ea726e0c4576398 Mon Sep 17 00:00:00 2001 From: herata Date: Thu, 14 May 2026 19:20:39 +0900 Subject: [PATCH 4/5] fix(ci): route test job cargo + rustup through mise exec macos test failed at the clippy step with `error: unexpected argument 'clippy' found`. The previous `rustup component add rustfmt clippy` step had rustup install a *fresh* 1.89 toolchain (separate from the mise-managed one) and dropped the components there. The next step called `cargo clippy` via the mise toolchain, which did not see clippy. Run every cargo / rustup invocation in the test matrix through `mise exec --` so all OSes use the mise-managed toolchain consistently. No change to deny / msrv / linux-headless jobs. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c5327ef..24a89f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,26 +32,26 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: ensure rustfmt + clippy components - # `mise.toml` requests rust profile=default, but mise's rust backend - # may install a cached minimal toolchain. Add the components - # explicitly so `cargo fmt` and `cargo clippy` always resolve. - run: rustup component add rustfmt clippy + # `mise.toml` requests rust profile=default, but mise may surface + # a cached minimal toolchain. Add the components inside the mise + # toolchain (not the host's rustup default, which would diverge). + run: mise exec -- rustup component add rustfmt clippy - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.7.4 - uses: taiki-e/install-action@v2 with: tool: cargo-nextest - name: fmt check if: matrix.os == 'ubuntu-latest' - run: cargo fmt --all -- --check + run: mise exec -- cargo fmt --all -- --check - name: clippy - run: cargo clippy --all-targets -- -D warnings + run: mise exec -- cargo clippy --all-targets -- -D warnings - name: nextest - run: cargo nextest run --all-targets + run: mise exec -- cargo nextest run --all-targets - name: docs if: matrix.os == 'ubuntu-latest' env: RUSTDOCFLAGS: -D warnings - run: cargo doc --no-deps --document-private-items + run: mise exec -- cargo doc --no-deps --document-private-items deny: name: cargo-deny From c4010c621685db23f914b93687627fb582ec7a8c Mon Sep 17 00:00:00 2001 From: herata Date: Thu, 14 May 2026 19:25:33 +0900 Subject: [PATCH 5/5] fix(ci): use dtolnay toolchain for test matrix, route pre-commit rustup through mise Two related fixes: 1. test (macos-latest) kept failing with `cargo clippy: unexpected argument 'clippy' found` because `mise exec -- rustup component add` on macOS spun up a *separate* rustup 1.89 toolchain (the host's pre-installed rustup, not mise's), and the subsequent `mise exec -- cargo clippy` resolved to mise's cargo which never saw the new components. The test matrix only needs rust + cargo-nextest, so drop mise from that job and install rust via `dtolnay/rust-toolchain` with explicit `components: rustfmt, clippy`. This is what the pre-commit job already implied: mise is only for the cargo hooks invoked from `pre-commit run`, not for the cargo commands the test matrix runs directly. 2. CodeRabbit flagged that the pre-commit job's `rustup component add rustfmt clippy` runs against the host's rustup, which can diverge from the mise toolchain that the pre-commit cargo hooks (`mise exec -- cargo ...`) actually use. Route that rustup invocation through `mise exec` so the components land in the same toolchain. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/ci.yml | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 24a89f6..bd11ceb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,33 +25,30 @@ jobs: - name: install libdbus on linux if: matrix.os == 'ubuntu-latest' run: sudo apt-get update && sudo apt-get install -y --no-install-recommends libdbus-1-dev pkg-config - - uses: jdx/mise-action@5083fe46898c414b2475087cc79da59e7da859e8 # v2.1.11 + # No mise here: the test matrix only needs rust + cargo-nextest. Letting + # rustup own the toolchain avoids the mise/host-rustup divergence we hit + # on macOS (mise's cargo and rustup component add ended up on different + # toolchains and clippy wouldn't resolve). + - uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # stable with: - install: true - cache: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: ensure rustfmt + clippy components - # `mise.toml` requests rust profile=default, but mise may surface - # a cached minimal toolchain. Add the components inside the mise - # toolchain (not the host's rustup default, which would diverge). - run: mise exec -- rustup component add rustfmt clippy + toolchain: "1.89" + components: rustfmt, clippy - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.7.4 - uses: taiki-e/install-action@v2 with: tool: cargo-nextest - name: fmt check if: matrix.os == 'ubuntu-latest' - run: mise exec -- cargo fmt --all -- --check + run: cargo fmt --all -- --check - name: clippy - run: mise exec -- cargo clippy --all-targets -- -D warnings + run: cargo clippy --all-targets -- -D warnings - name: nextest - run: mise exec -- cargo nextest run --all-targets + run: cargo nextest run --all-targets - name: docs if: matrix.os == 'ubuntu-latest' env: RUSTDOCFLAGS: -D warnings - run: mise exec -- cargo doc --no-deps --document-private-items + run: cargo doc --no-deps --document-private-items deny: name: cargo-deny @@ -93,7 +90,9 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: ensure rustfmt + clippy components - run: rustup component add rustfmt clippy + # Route through mise so components land in the same toolchain the + # pre-commit cargo hooks (`mise exec -- cargo ...`) will use. + run: mise exec -- rustup component add rustfmt clippy - uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.7.4 - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1