From ec24ab22784aa2fe1501d935c5c34c15e8a1ba77 Mon Sep 17 00:00:00 2001 From: gotomts Date: Sun, 13 Sep 2026 03:46:40 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat(setup):=20Notion=20CLI=20ntn=20?= =?UTF-8?q?=E3=82=92=20Tier=202=20=E3=81=AE=E5=AE=A3=E8=A8=80=E7=9A=84?= =?UTF-8?q?=E5=B0=8E=E5=85=A5=E3=81=AB=E7=B5=84=E3=81=BF=E8=BE=BC=E3=82=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- AGENTS.md | 4 +- setup/README.md | 24 ++++++-- setup/migrate.zsh | 13 ++-- setup/notion.zsh | 71 ++++++++++++++++++++++ setup/tests/herdr-sync.bats | 6 +- setup/tests/migrate.bats | 59 ++++++++++++++++-- setup/tests/notion.bats | 118 ++++++++++++++++++++++++++++++++++++ setup/tests/zshenv.bats | 7 +++ zshenv | 5 ++ 9 files changed, 290 insertions(+), 17 deletions(-) create mode 100644 setup/notion.zsh create mode 100644 setup/tests/notion.bats diff --git a/AGENTS.md b/AGENTS.md index ed665cd..1b09723 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,7 +5,7 @@ - `CONTEXT.md` — AI エージェント指示の層(規範フラグメント・グローバル / プロジェクト AGENTS.md・SOUL.md・CLAUDE.local.md・channel prompt)を区別する用語集 - `aliases` — alias 定義の SSOT(root 直下、`~/.aliases` にシンボリックリンク)。旧 `nix/modules/home/zsh.nix` の `shellAliases` から移行(`setup/link.zsh` が配置、Tier 1) - `scripts/` — 外部シェルスクリプト(`aliases` の alias から呼び出される。旧 `aliase/` から改名) -- `setup/` — Tier 1(リアルタイム symlink)・Tier 2(明示的スクリプト実行)・Tier 3(カットオーバー・ロールバック)の実装。`darwin-rebuild switch` を使わず、`zsh setup/link.zsh` で dotfiles を配置し(Tier 1)、`setup/languages.zsh`(mise による言語ランタイム + corepack + バージョン固定 CLI)/`setup/defaults.zsh`(macOS defaults・IME)/`setup/pam.zsh`(Touch ID for sudo)/`setup/claude-sync.zsh`(skills clone・plugin sync・MCP merge)/`setup/codex-sync.zsh`(config.toml seed-if-absent)/`setup/herdr-sync.zsh`(Herdr ローカルプラグインの link・allowlist 配置)を個別実行する(Tier 2)。既存 PC を home-manager 込みの旧構成から移行する場合は `setup/cutover.zsh`(pre-flight build 確認 + `darwin-rebuild switch`)/`setup/rollback.zsh`(`.before-nix` 衝突検出付きロールバック)を使う(Tier 3)。**実機での実行は `setup/migrate.zsh` が唯一のエントリポイント**(`--dry-run`/`--apply`。Tier 1/2/3 を依存順(Phase 1: link → Phase 2: cutover/pam [root] → Phase 3: languages/defaults/claude-sync/codex-sync/herdr-sync)で実行し、`~/.dotfiles-migrate/manifest.log` で部分適用を検出・再開する。fail-closed、rollback.zsh は自動では呼ばない)。個別スクリプトの直接実行はメンテナンス目的のみ。詳細は `setup/README.md` と `docs/superpowers/specs/2026-08-21-restore-script-management-inventory.md`・`docs/superpowers/specs/2026-08-22-restore-script-management-tier3-cutover-design.md`・`docs/superpowers/specs/2026-08-22-migrate-orchestrator-recovery-plan.md` を参照 +- `setup/` — Tier 1(リアルタイム symlink)・Tier 2(明示的スクリプト実行)・Tier 3(カットオーバー・ロールバック)の実装。`darwin-rebuild switch` を使わず、`zsh setup/link.zsh` で dotfiles を配置し(Tier 1)、`setup/languages.zsh`(mise による言語ランタイム + corepack + バージョン固定 CLI)/`setup/defaults.zsh`(macOS defaults・IME)/`setup/pam.zsh`(Touch ID for sudo)/`setup/claude-sync.zsh`(skills clone・plugin sync・MCP merge)/`setup/codex-sync.zsh`(config.toml seed-if-absent)/`setup/herdr-sync.zsh`(Herdr ローカルプラグインの link・allowlist 配置)/`setup/notion.zsh`(Notion CLI `ntn` を公式インストーラで `${HOME}/.local/bin` へ install-if-absent)を個別実行する(Tier 2)。既存 PC を home-manager 込みの旧構成から移行する場合は `setup/cutover.zsh`(pre-flight build 確認 + `darwin-rebuild switch`)/`setup/rollback.zsh`(`.before-nix` 衝突検出付きロールバック)を使う(Tier 3)。**実機での実行は `setup/migrate.zsh` が唯一のエントリポイント**(`--dry-run`/`--apply`。Tier 1/2/3 を依存順(Phase 1: link → Phase 2: cutover/pam [root] → Phase 3: languages/defaults/claude-sync/codex-sync/herdr-sync/notion)で実行し、`~/.dotfiles-migrate/manifest.log` で部分適用を検出・再開する。fail-closed、rollback.zsh は自動では呼ばない)。個別スクリプトの直接実行はメンテナンス目的のみ。詳細は `setup/README.md` と `docs/superpowers/specs/2026-08-21-restore-script-management-inventory.md`・`docs/superpowers/specs/2026-08-22-restore-script-management-tier3-cutover-design.md`・`docs/superpowers/specs/2026-08-22-migrate-orchestrator-recovery-plan.md` を参照 - `claude/` — Claude Code 設定(`~/.claude/` にシンボリックリンク) - `claude/rules/` — 全 AI エージェント向けグローバル指示のフラグメント(SSOT)。`core` / `worker` / `orchestrator` / `hermes-identity` の 4 ファイルを `scripts/build-agent-rules.zsh`(旧 `aliase/build-agent-rules.zsh`)が結合して生成物を作る - `claude/hermes/SOUL.md` — Hermes Agent 用グローバル指示の生成物(`~/.hermes/SOUL.md` にシンボリックリンク)。直接編集しない @@ -26,7 +26,7 @@ - `ssh/` — SSH 設定(`~/.ssh/` にシンボリックリンク) - `zsh/` — zsh 補完ファイル(`~/.zsh/` にシンボリックリンク) - `zshrc` — zsh 設定(`~/.zshrc` にシンボリックリンク) -- `zshenv` — zsh 環境変数(`~/.zshenv` にシンボリックリンク) +- `zshenv` — zsh 環境変数(`~/.zshenv` にシンボリックリンク)。`${HOME}/.local/bin` を PATH へ明示的に載せる唯一の場所(pipx の出力先であり、Homebrew formula が無い CLI の導入先。例: `setup/notion.zsh` が入れる `ntn`) # シンボリックリンク管理 diff --git a/setup/README.md b/setup/README.md index 7318891..5104860 100644 --- a/setup/README.md +++ b/setup/README.md @@ -16,7 +16,7 @@ Tier を跨いだ実行順序・部分適用の検出/復旧を担う `setup/mig ## 使い方(実機での唯一のエントリポイントは `setup/migrate.zsh`) Tier 1/2/3 の各スクリプト(`link.zsh`/`languages.zsh`/`defaults.zsh`/`pam.zsh`/ -`claude-sync.zsh`/`codex-sync.zsh`/`herdr-sync.zsh`/`cutover.zsh`)を実機で直接実行することは非推奨。 +`claude-sync.zsh`/`codex-sync.zsh`/`herdr-sync.zsh`/`notion.zsh`/`cutover.zsh`)を実機で直接実行することは非推奨。 順序管理なしに個別実行すると部分適用インシデントを再現する(過去に実際に発生した)。 実機での実行は必ず `setup/migrate.zsh` からのみ行う: @@ -33,7 +33,7 @@ alias・関数に依存しないため、これが標準の入口。 zsh ${HOME}/.dotfiles/setup/migrate.zsh --dry-run # 計画を実行する。単一の root 起動で全 Phase (link -> cutover/pam -> languages/defaults/ -# claude-sync/codex-sync/herdr-sync) が完結する。sudo が自動設定する SUDO_USER から元ユーザーを +# claude-sync/codex-sync/herdr-sync/notion) が完結する。sudo が自動設定する SUDO_USER から元ユーザーを # 特定し、非 root ステップは元ユーザーへ委譲実行する(詳細は # docs/superpowers/specs/2026-08-22-migrate-orchestrator-recovery-plan.md 参照) sudo zsh ${HOME}/.dotfiles/setup/migrate.zsh --apply @@ -67,6 +67,7 @@ zsh ${HOME}/.dotfiles/setup/pam.zsh zsh ${HOME}/.dotfiles/setup/claude-sync.zsh zsh ${HOME}/.dotfiles/setup/codex-sync.zsh zsh ${HOME}/.dotfiles/setup/herdr-sync.zsh +zsh ${HOME}/.dotfiles/setup/notion.zsh sudo USER=${USER} zsh ${HOME}/.dotfiles/setup/cutover.zsh ``` @@ -105,6 +106,15 @@ symlink 越しに即座に反映される。再実行が必要なのは「`setup primary 以外から実行された場合は両方まとめてスキップする。登録先パスが既に一致して いれば何もせず、`repos.local.json`(マシンローカルの allowlist)は seed-if-absent で 既存の中身に触れない。 +- `notion.zsh`: Notion CLI (`ntn`) に Homebrew formula が無いため、公式インストーラ + (`https://ntn.dev/install.sh`) を使う唯一の Tier 2 ステップ。`${HOME}/.local/bin/ntn` が + 既に実行可能なら **インストーラを一切呼ばない**(既存バイナリを上書きしない・バージョン + 更新もしない)。導入するときは `NTN_INSTALL_DIR` で導入先を `${HOME}/.local/bin` に固定 + する(インストーラ既定の導入先選択は実行時の PATH の形に依存して揺れるため、宣言側で + 固定して health check と一致させる)。`curl` は `bash` に直結せず一旦ファイルへ落とす + (取得失敗時に空スクリプトを実行して「成功」に見えるのを防ぐ)。トークン(`NOTION_API_KEY` + 等)は読まない・要求しない・保存しない。導入後の認証は人間が `ntn` 側の手順で行う。 + PATH への `${HOME}/.local/bin` 追加は Tier 1 の `zshenv` が担当する。 - `cutover.zsh`: 実行前に `darwin-rebuild --list-generations` の出力を `~/.dotfiles-cutover-backup/pre-cutover-generations-.txt` へ記録してから `nix build`(副作用なし)で pre-flight 確認し、成功したときだけ `darwin-rebuild switch` @@ -115,7 +125,7 @@ symlink 越しに即座に反映される。再実行が必要なのは「`setup `fs::ensure_realfile` と同じ no-data-loss 方針で、自動退避はしない)。 - `migrate.zsh`: Tier 1/2/3 を跨いだ唯一のオーケストレーター。実行順序は Phase 1 (`link`) → Phase 2 (`cutover`/`pam`、root 必須) → Phase 3 (`languages`/`defaults`/ - `claude-sync`/`codex-sync`/`herdr-sync`)。`languages.zsh` 自身が「mise は darwin-switch で事前導入 + `claude-sync`/`codex-sync`/`herdr-sync`/`notion`)。`languages.zsh` 自身が「mise は darwin-switch で事前導入 済みが前提」と明記しているため、cutover を languages より先に置く。各ステップの結果は `~/.dotfiles-migrate/manifest.log` に永続化し、success 済みステップは再実行しない (idempotent な部分適用検出・再開)。ただし `cutover` だけは、必須バイナリの実在と @@ -157,11 +167,17 @@ bats herdr/plugins/*/tests/*.bats 委譲実行を health check にまで広げるほどの利得が無いため)。 `fs::link_file`/`fs::ensure_realfile` は関数単位、`link.zsh`/`languages.zsh`/`defaults.zsh`/ -`pam.zsh`/`claude-sync.zsh`/`codex-sync.zsh`/`herdr-sync.zsh`/`cutover.zsh`/`rollback.zsh`/ +`pam.zsh`/`claude-sync.zsh`/`codex-sync.zsh`/`herdr-sync.zsh`/`notion.zsh`/`cutover.zsh`/`rollback.zsh`/ `migrate.zsh` は、 実コマンド(`defaults`/`mise`/`corepack`/`claude`/`herdr`/`git`/`darwin-rebuild`/`nix`)を PATH 上の stub 実行ファイルに差し替え、`$HOME` を一時ディレクトリに差し替えたサンドボックスでの統合テスト (実機・実ネットワーク・実パッケージマネージャ・実 `darwin-rebuild switch` には一切触れない)。 + +`notion.zsh` だけは `curl` の扱いが 2 通りある。単体テスト(`setup/tests/notion.bats`)は +`curl` を stub に差し替えて取得失敗の経路まで見る。`migrate.zsh` 経由の統合テストでは stub を +使わず、`NTN_INSTALLER_URL` に `file://` の偽インストーラを渡して **実 `curl` をオフラインで** +走らせる。`migrate.zsh` の委譲実行は Homebrew prefix を PATH 先頭に固定で差し込むため、 +そこでの `curl` stub は実機に Homebrew 版 `curl` があると負けて実ネットワークに出てしまう。 `migrate.zsh` のテストは Tier 1 が作る `~/.zshenv` symlink を経由して後続の子 `zsh` プロセスが 実際の zshenv を re-source する(Phase を跨いだ実行を初めて連結するテストのため、単独スクリプトの テストでは踏まなかった経路)。stub 実行ファイルを `#!/bin/bash` にしているのはこのため diff --git a/setup/migrate.zsh b/setup/migrate.zsh index b9aeb5b..3750821 100755 --- a/setup/migrate.zsh +++ b/setup/migrate.zsh @@ -31,8 +31,8 @@ # ため、Phase 3 より前に置く。pam は cutover と同じく # root 必須なので同じ Phase にまとめ、sudo プロンプトを # 1 回にまとめる) -# Phase 3: languages, defaults, claude-sync, codex-sync, herdr-sync (root 起動時は元ユーザーへ -# 委譲。 +# Phase 3: languages, defaults, claude-sync, codex-sync, herdr-sync, notion +# (root 起動時は元ユーザーへ委譲。 # mise は Phase 2 で導入済み) # # 安全設計: @@ -100,7 +100,7 @@ source "${SETUP_DIR}/lib/herdr.zsh" # --------------------------------------------------------------------------- PHASE1_STEPS=(link) PHASE2_STEPS=(cutover pam) -PHASE3_STEPS=(languages defaults claude-sync codex-sync herdr-sync) +PHASE3_STEPS=(languages defaults claude-sync codex-sync herdr-sync notion) # この --apply の中で cutover 直前に退避した Touch ID ファイルのパス( # migrate::pam_restore_pristine_if_safe が設定し、migrate::pam_discard_vacated が使う)。 @@ -761,6 +761,11 @@ migrate::health_check() { [[ -f "${home_dir}/.codex/config.toml" ]] || failures+=("codex-sync: ${home_dir}/.codex/config.toml がありません") + # ntn は Homebrew 管理外なので migrate::command_available(Homebrew prefix + # フォールバック)では確認できない。notion.zsh が導入先を ${HOME}/.local/bin に + # 固定しているので、対象ユーザーのホーム配下を直接見る。 + [[ -x "${home_dir}/.local/bin/ntn" ]] || failures+=("notion: ${home_dir}/.local/bin/ntn が実行可能ではありません") + # herdr plugin の allowlist。パスは herdr-sync.zsh と同じ setup/lib/herdr.zsh の # 解決関数から引く(配置する側と確認する側で別々にパスを組み立てると、Herdr が # 設定ディレクトリの位置を変えたときに health check だけが古い場所を見に行く)。 @@ -889,7 +894,7 @@ migrate::usage() { Phase 1: link (root 起動時は元ユーザーへ委譲) Phase 2: cutover, pam (root 必須) -Phase 3: languages, defaults, claude-sync, codex-sync, herdr-sync (root 起動時は元ユーザーへ委譲) +Phase 3: languages, defaults, claude-sync, codex-sync, herdr-sync, notion (root 起動時は元ユーザーへ委譲) 個別スクリプト(link.zsh 等)は内部実装です。実機での実行はこのスクリプトからのみ 行ってください。詳細は setup/README.md を参照。 diff --git a/setup/notion.zsh b/setup/notion.zsh new file mode 100644 index 0000000..06a74c5 --- /dev/null +++ b/setup/notion.zsh @@ -0,0 +1,71 @@ +#!/bin/zsh +# setup/notion.zsh +# +# Tier 2: Notion CLI (ntn) を ${HOME}/.local/bin へ導入する。 +# +# Homebrew formula が存在しないため homebrew.nix では宣言できない。公式インストーラ +# (https://ntn.dev/install.sh) が置く単一バイナリを、NTN_INSTALL_DIR で導入先を +# ${HOME}/.local/bin に固定したうえで使う(インストーラ既定の導入先選択は PATH の +# 現状に依存して揺れるため、宣言側で固定して health check と一致させる)。 +# PATH への ${HOME}/.local/bin の追加は Tier 1 の zshenv が担当する。 +# +# 冪等性: 既に ntn が実行可能なら何もしない。バージョン更新はこのスクリプトの責務では +# ない(更新したいときは実体を消してから再実行するか、ntn 自身の更新手順に従う)。 +# +# 認証は扱わない: NOTION_API_KEY 等のトークンをこのスクリプトは読まない・要求しない・ +# 保存しない。導入後の認証は人間が ntn 側の手順で行う。 +# +# 使い方: +# zsh ${HOME}/.dotfiles/setup/notion.zsh +# +# 終了コード: +# 0 成功(既に導入済みで skip した場合も含む) +# 1 curl 不在、インストーラの取得/実行の失敗、または実行後に ntn が現れなかった + +set -eu + +SETUP_DIR="${0:A:h}" +source "${SETUP_DIR}/lib/util.zsh" + +NTN_INSTALL_DIR="${HOME}/.local/bin" +NTN_BIN="${NTN_INSTALL_DIR}/ntn" +# テストではサンドボックス内のスタブを指す URL に差し替える(実ネットワークに触れない)。 +NTN_INSTALLER_URL="${NTN_INSTALLER_URL:-https://ntn.dev/install.sh}" + +util::info "=== Tier 2: Notion CLI (ntn) ===" + +if [[ -x "${NTN_BIN}" ]]; then + util::skip "${NTN_BIN} は既に実行可能です(インストーラを呼びません)" + exit 0 +fi + +if ! command -v curl &>/dev/null; then + util::error "curl が見つかりません。ntn の導入をスキップせず失敗として扱います" + exit 1 +fi + +installer="$(mktemp)" +trap '/bin/rm -f "${installer}"' EXIT + +util::action "公式インストーラを取得します: ${NTN_INSTALLER_URL}" +# curl を pipe で bash に直結しない。取得失敗時に空スクリプトを実行して「成功」に +# 見えてしまうのを防ぐため、ファイルへ落として取得の exit code を確かめる。 +if ! curl -fsSL -o "${installer}" "${NTN_INSTALLER_URL}"; then + util::error "インストーラの取得に失敗しました: ${NTN_INSTALLER_URL}" + exit 1 +fi + +util::action "ntn を ${NTN_INSTALL_DIR} へ導入します" +mkdir -p "${NTN_INSTALL_DIR}" +# インストーラは bash 前提(#!/usr/bin/env bash)なので zsh では実行しない。 +if ! NTN_INSTALL_DIR="${NTN_INSTALL_DIR}" bash "${installer}"; then + util::error "インストーラの実行に失敗しました" + exit 1 +fi + +if [[ ! -x "${NTN_BIN}" ]]; then + util::error "インストーラは成功しましたが ${NTN_BIN} が実行可能になっていません" + exit 1 +fi + +util::info "${NTN_BIN} を導入しました" diff --git a/setup/tests/herdr-sync.bats b/setup/tests/herdr-sync.bats index 64caaa1..cbf1fe7 100644 --- a/setup/tests/herdr-sync.bats +++ b/setup/tests/herdr-sync.bats @@ -127,8 +127,10 @@ assert_no_real_herdr() { } @test "migrate.zsh runs herdr-sync as part of phase 3" { - grep -q 'PHASE3_STEPS=(languages defaults claude-sync codex-sync herdr-sync)' \ - "${SETUP_DIR}/migrate.zsh" + # Assert membership, not the exact roster: this test is about herdr-sync + # being a phase 3 step, and pinning the whole line makes every unrelated + # step addition fail here instead of where it belongs. + grep -qE 'PHASE3_STEPS=\(.*\bherdr-sync\b.*\)' "${SETUP_DIR}/migrate.zsh" } @test "migrate health check verifies the allowlist symlink" { diff --git a/setup/tests/migrate.bats b/setup/tests/migrate.bats index 24783ac..131d781 100644 --- a/setup/tests/migrate.bats +++ b/setup/tests/migrate.bats @@ -9,6 +9,11 @@ REPO_ROOT="$(cd "${SETUP_DIR}/.." && pwd)" # mise/corepack (languages), defaults (defaults), git/claude (claude-sync), # darwin-rebuild/nix (cutover). codex-sync/pam need no external command # (SUDO_LOCAL_PATH redirects pam's write target instead of /etc). +# notion uses the real curl, pointed at a file:// URL holding a fake installer +# (NTN_INSTALLER_URL below) -- no stub, no network, and still the real download +# path. A PATH stub would not be reliable here anyway: migrate.zsh prepends the +# hardcoded Homebrew prefixes when delegating, so a real /opt/homebrew/bin/curl +# would win over a stub. _install_full_stubs() { local bin_dir="${1}" mkdir -p "${bin_dir}" @@ -159,6 +164,18 @@ setup() { # the stub dir so the single-root-invocation test never resolves this # machine's real Homebrew mise (if installed) via the delegated step. export HOMEBREW_PATH_PREFIX_OVERRIDE="${STUB_BIN}" + + # notion.zsh's installer source. Models the one thing the real installer + # contract guarantees and notion.zsh relies on: it honors NTN_INSTALL_DIR. + NTN_INSTALLER_FILE="${BATS_TEST_TMPDIR}/ntn-install.sh" + cat > "${NTN_INSTALLER_FILE}" <<'EOF' +#!/usr/bin/env bash +set -euo pipefail +mkdir -p "${NTN_INSTALL_DIR}" +printf '#!/bin/sh\necho "ntn 0.0.0-stub"\n' > "${NTN_INSTALL_DIR}/ntn" +chmod +x "${NTN_INSTALL_DIR}/ntn" +EOF + export NTN_INSTALLER_URL="file://${NTN_INSTALLER_FILE}" } @test "zsh -n syntax check passes" { @@ -197,11 +214,11 @@ setup() { [[ "${output}" != *"rollback"* ]] } -@test "dry-run lists all 7 steps and executes nothing" { +@test "dry-run lists all 8 steps and executes nothing" { run zsh "${SETUP_DIR}/migrate.zsh" --dry-run [ "${status}" -eq 0 ] - for step in link languages defaults pam claude-sync codex-sync cutover; do + for step in link languages defaults pam claude-sync codex-sync herdr-sync notion cutover; do [[ "${output}" == *"${step}"* ]] done @@ -224,7 +241,7 @@ setup() { MIGRATE_EUID_OVERRIDE=0 MIGRATE_SUDO_USER_OVERRIDE=testuser \ run zsh "${SETUP_DIR}/migrate.zsh" --dry-run [ "${status}" -eq 0 ] - for step in link languages defaults pam claude-sync codex-sync cutover; do + for step in link languages defaults pam claude-sync codex-sync herdr-sync notion cutover; do [[ "${output}" == *"[WOULD RUN] ${step}:"* ]] done [[ "${output}" != *"[BLOCKED]"* ]] @@ -237,7 +254,7 @@ setup() { # so it alone stays WOULD RUN. MIGRATE_EUID_OVERRIDE=0 USER= run zsh "${SETUP_DIR}/migrate.zsh" --dry-run [ "${status}" -eq 0 ] - for step in link languages defaults claude-sync codex-sync cutover; do + for step in link languages defaults claude-sync codex-sync herdr-sync notion cutover; do [[ "${output}" == *"[BLOCKED] ${step}:"* ]] done [[ "${output}" == *"[WOULD RUN] pam:"* ]] @@ -284,6 +301,7 @@ setup() { [ -f "${SUDO_LOCAL_PATH}" ] [ -f "${HOME}/.claude.json" ] [ -f "${HOME}/.codex/config.toml" ] + [ -x "${HOME}/.local/bin/ntn" ] run cat "${DARWIN_REBUILD_LOG}" [[ "${output}" == *"switch --flake"* ]] run cat "${MISE_LOG}" @@ -295,7 +313,7 @@ setup() { # `sudo -u testuser -H env PATH=... zsh