Skip to content

feat(setup): Notion CLI ntn を Tier 2 の宣言的導入に組み込む - #81

Merged
gotomts merged 4 commits into
mainfrom
feat/notion-cli-bootstrap
Sep 13, 2026
Merged

feat(setup): Notion CLI ntn を Tier 2 の宣言的導入に組み込む#81
gotomts merged 4 commits into
mainfrom
feat/notion-cli-bootstrap

Conversation

@gotomts

@gotomts gotomts commented Sep 13, 2026

Copy link
Copy Markdown
Owner

概要

Notion CLI (ntn) を dotfiles のグローバルスコープに恒久対応として組み込む。Homebrew formula が存在しないため homebrew.nix では宣言できず、公式配布バイナリを Tier 2 スクリプトで導入する。

ntn は mise の npm backend でも導入できるが、グローバル CLI を Node ランタイムに依存させないため公式配布バイナリを選んでいる。

変更内容

新規 setup/notion.zsh(Tier 2)

  • 公式インストーラ (https://ntn.dev/install.sh) に 2 つの環境変数を渡して導入結果を宣言側で決めきる
    • NTN_INSTALL_DIR = ${HOME}/.local/bin。インストーラ既定の導入先選択は実行時の PATH の形に依存して揺れるため固定する
    • NTN_VERSION = NTN_PINNED_VERSION0.23.4)。既定の latest だと「導入した日」で版が決まり PC ごとに別物が入る
  • ${HOME}/.local/bin/ntn が既に実行可能なファイルなら インストーラを一切呼ばない。判定は -x 単独ではなく -f && -x(実行ビットの立ったディレクトリを導入済みと誤判定しないため)
  • curlbash に直結せず一旦ファイルへ落とす(取得失敗時に空スクリプトを実行して「成功」に見えるのを防ぐ)
  • 初回ダウンロードの失敗は fail-closedntn は恒久的に宣言したグローバル必須ツールなので「入らなかったが成功」を健全な状態として扱わない。既にバイナリがある PC では一切ネットワークに出ないため、オフラインでも --apply は通る
  • トークン(NOTION_API_KEY 等)は読まない・要求しない・保存しない

新規 setup/lib/notion.zsh

宣言する版(NTN_PINNED_VERSION)とパス解決を集約する。導入する側(notion.zsh)と確認する側(migrate.zsh の health check)が別々に値を持つと、版を上げたときに片方だけ古い値を見に行くため(setup/lib/herdr.zsh と同じ理由)。

setup/migrate.zsh

  • Phase 3 に notion ステップを追加(languages / defaults / claude-sync / codex-sync / herdr-sync / notion
  • health check が実体を -f && -x で確認し、さらに ntn --versionNTN_PINNED_VERSION と一致するかを検証する
    • 版まで見るのは notion.zsh が install-if-absent のため。宣言の版を上げても実体のある PC は古いまま success になり続ける(版が効くのは新規導入時だけ)
    • 自動では差し替えない。実行中かもしれないバイナリを migrate が黙って置き換えないため、fail-closed に落として人が実体を削除してから --apply を再実行する経路に寄せる
    • probe は root 起動時に sudo -u <元ユーザー> -H -- を前置して元ユーザーとして実行する。実体は元ユーザーの $HOME 配下にあり本人が書き換えられるファイルなので、検証のために root 権限で走らせる理由が無い。元ユーザーを特定できなければ probe せず fail-closed に落ちる

PATH

zshenv${HOME}/.local/bin を PATH へ append で 1 箇所だけ 追加する。偶然 PATH に載っている状態に依存させないため。prepend にすると Homebrew/mise が供給する同名コマンドを横取りして既存の解決順が変わるので append を維持している。zshrc にあった同じ追加は削除した(重複を 2 箇所に置くと片方を直しても解決順が変わらず原因を追いにくい)。

CI

.github/workflows/setup-check.ymlpathszshenv / zshrc を追加。PATH 宣言の検証が setup/** を伴わない単独編集でも走るようにする。

ドキュメント

setup/README.mdAGENTS.md を更新(リポジトリ構造、Phase 3 の構成、CLI 管理の例外規定)。

動作確認

bats

$ bats setup/tests/*.bats
151 件すべて成功(exit 0)

新規・更新したテスト:

  • setup/tests/notion.bats(新規): 新規導入 / 導入先の固定 / 既存バイナリがあればインストーラを呼ばない / 取得失敗で fail / バイナリが現れなければ fail / 実行ビットの立ったディレクトリを導入済みと誤判定しない / トークン参照が実行行に無い / 版が宣言値どおりインストーラへ渡る
  • setup/tests/migrate.bats: 版一致で通る・不一致(0.1.0-stale)で落ちる・版を報告できない場合も落ちる / 落ちた後も実体は書き換わらない / root 起動時は probe が sudo -u <user> -H -- 経由になる / 非 root 時は sudo を介さない / manifest から notion の success を除いても notion.zsh 自身の guard で再ダウンロードしない
  • setup/tests/zshenv.bats / setup/tests/zshrc.bats: PATH 追加が append 形で 1 箇所だけ存在すること

テストは実ネットワーク・実インストーラに一切触れない。単体テストは curl を stub に差し替え、migrate.zsh 経由の統合テストは NTN_INSTALLER_URLfile:// の偽インストーラを渡して実 curl をオフラインで走らせる(migrate.zsh の委譲実行は Homebrew prefix を PATH 先頭に固定で差し込むため、stub だと実機の Homebrew 版 curl に負けて実ネットワークに出てしまう)。

dry-run

サンドボックス HOME での migrate.zsh --dry-run で、notion が Phase 3 に [WOULD RUN] として並ぶことを確認済み:

  [WOULD RUN] herdr-sync: .../setup/herdr-sync.zsh
  [WOULD RUN] notion: .../setup/notion.zsh

実機への適用

実機の sudo zsh ${HOME}/.dotfiles/setup/migrate.zsh --apply は、この PR の merge 後に人が実行する。 この PR の作業中には実行していない。

現在の作業機には公式インストーラ経由の ntn 0.23.4 が既に入っているため、適用しても notion ステップは skip され、health check の版検証も通る想定。

🤖 Generated with Claude Code

gotomts and others added 4 commits September 13, 2026 03:46
ntn には Homebrew formula が無いため homebrew.nix では宣言できない。公式
インストーラを使う Tier 2 ステップ setup/notion.zsh を新設し、migrate.zsh の
Phase 3 と health check に組み込む。

- notion.zsh は ${HOME}/.local/bin/ntn が実行可能なら何もしない(既存バイナリを
  上書きしない)。導入時は NTN_INSTALL_DIR で導入先を固定する。インストーラ既定の
  導入先選択は実行時の PATH に依存して揺れ、health check と食い違うため
- curl は bash に直結せず一旦ファイルへ落とす。取得失敗時に空スクリプトを実行して
  「成功」に見えるのを防ぐ
- トークン(NOTION_API_KEY 等)は読まない・要求しない・保存しない
- zshenv が ${HOME}/.local/bin を PATH へ明示する。偶然 PATH に載っている状態に
  依存させないため
- migrate.bats の統合テストは curl stub を使わず file:// の偽インストーラで実
  curl をオフライン実行する。migrate.zsh の委譲実行は Homebrew prefix を PATH
  先頭に固定で差し込むため、stub は実機の Homebrew 版 curl に負ける

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
独立レビューの指摘に対応する。

- PATH: ${HOME}/.local/bin の追加を zshenv の append 1 箇所に寄せ、zshrc 側の
  重複を削除する。prepend にすると Homebrew/mise が供給する同名コマンドを横取り
  して既存の解決順が変わるため append を維持する
- 版固定: NTN_PINNED_VERSION=0.23.4 を NTN_VERSION としてインストーラへ渡す。
  既定の latest だと「導入した日」で版が決まり PC ごとに別物が入る。更新は
  dotfiles 側の明示変更で行う
- fail-closed: ntn は恒久的に宣言したグローバル必須ツールなので初回ダウンロード
  失敗は migrate 全体の失敗として扱う。既にバイナリがあればネットワークに出ない
  ことと併せて README に明記する
- 実体判定: notion.zsh の導入済み判定と migrate.zsh の health check を
  [[ -f && -x ]] にする。-x 単独では実行ビットの立ったディレクトリを導入済みと
  誤判定する
- テスト: migrate.bats の再実行テストは manifest から notion の success を除き、
  notion.zsh 自身の既存バイナリ guard まで到達させる(manifest skip だけでは
  オフライン機・manifest 消失機での挙動を検証できない)。ステップ数表記も実数へ
- CI: setup-check の paths に zshenv/zshrc を追加し、PATH 宣言の検証が
  setup/** を伴わない単独編集でも走るようにする

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
再レビューの残件に対応する。

- 版検証: migrate.zsh の health check が ${HOME}/.local/bin/ntn --version を
  実行し、NTN_PINNED_VERSION と一致しなければ落とす。notion.zsh は
  install-if-absent なので、宣言の版を上げても実体のある PC は古いまま success に
  なり続ける(版が効くのは新規導入時だけ)。実体の自動差し替えはせず、人が削除して
  から --apply を再実行する経路に寄せる
- 宣言値とパスを setup/lib/notion.zsh へ集約し、導入する側 (notion.zsh) と確認する側
  (migrate.zsh) が同じ定義を引くようにする(setup/lib/herdr.zsh と同じ理由)
- AGENTS.md: 「mise backend が無い」は誤り。ntn は npm backend で導入できるが、
  グローバル CLI を Node ランタイムに依存させないため公式配布バイナリを選ぶ、と
  正確に書き直す
- migrate.bats 冒頭の script 数コメントを 7 から 9 へ
- README: 「zshrc 側にあった重複を削除済み」という変更履歴表現を、現行仕様
  「PATH 追加は zshenv の append 1 箇所」の記述だけに置き換える

テストはサンドボックスの偽インストーラが「要求された版を報告する ntn」を置く形に
変え、版一致・不一致・版を報告できない場合の 3 通りを固定する。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
最終レビューの残件に対応する。

- migrate::ntn_version を追加し、health check の `ntn --version` を EUID 0 のとき
  `sudo -u <元ユーザー> -H --` 経由で実行する。実体は元ユーザーの $HOME 配下にあり
  本人が書き換えられるファイルなので、検証のために root 権限で走らせる理由が無い。
  元ユーザーを特定できなければ probe せず空を返し、版不一致として fail-closed に落ちる
  (非 root ステップの privilege_ok と同じ規則)
- notion::installed_version は実体パス 1 個ではなく argv 全体を受け取る形にし、
  呼び出し側が sudo を前置できるようにする
- notion.bats の 0.23.4 ハードコードを setup/lib/notion.zsh から読んだ宣言値へ置き換え、
  pin を上げたときにテストが追従するようにする

sudo スタブは実 sudo と同じく `--` を引数終端として読み飛ばす。root 起動で委譲される
ことと、非 root 起動では sudo を介さないことの双方をテストで固定する。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gotomts
gotomts merged commit 5ff1b88 into main Sep 13, 2026
1 check passed
@gotomts
gotomts deleted the feat/notion-cli-bootstrap branch September 13, 2026 00:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant