## 概要
- [[Spoon]]版の[[🦉JINRAI]]からnative版の[[🦉JINRAI]]に向けて、ドキュメンテーションを移行する
- ドキュメントにあるけど存在しない機能
- 重要な実装漏れは機能追加
- それ以外はドキュメントから削除
- ドキュメントにないけど存在する機能
- ドキュメントに追加
## jinrai: docs を Swift 実装に合わせて全面修正 + direction.direct 実装
### Context
`docs/` 配下のドキュメントサイト(zensical)は Hammerspoon Spoon 版(../jinrai-spoon)からそのままコピーされたもので、全ページが Lua 設定・SpoonInstall・`spoon.Jinrai:setup` 前提のまま。一方 jinrai 本体は Swift 製メニューバーアプリで、設定は `~/.config/jinrai/config.jsonc`(JSONC)。設定スキーマにも実質差分が多数ある。
ユーザー決定事項:
- **`window_hints.navigation.direction.direct`(ヒントを開かず修飾キー+方向キーで直接フォーカス移動)のみ Swift 側へ実装追加**
- それ以外の実装に存在しない項目(`macos_native_tabs: false` 無効化、spaceBadge カスタム色、フォント名・余白等の見た目設定、`selectedArea.appearance.styles`、Lua callbacks)は**ドキュメントから削除・修正**
実装の正(設定スキーマの一次情報): `Sources/JinraiCore/Config/*.swift`(RootConfig / WindowHints / WindowMover / ApplicationHints / FocusBack / FocusBorder / JinraiMode)と `Sources/Jinrai/ConfigLoader.swift`(テンプレート)。
### Part 1: direction.direct の実装(Swift)
ヒントを開かずにグローバルホットキー(修飾キー+方向キー)で隣のウィンドウへ直接フォーカス移動する。Spoon版(`jinrai-spoon/Jinrai.spoon/window_hints.lua` の directDirectionHotkeys)と同仕様。
#### 1-1. 設定追加 — `Sources/JinraiCore/Config/WindowHintsConfig.swift`
- struct に追加:
```swift
public struct DirectDirectionHotkeys: Equatable, Sendable {
public var modifiers: [String]
public var keys: [Direction: String] // 方向 → キー名
}
public var directDirectionHotkeys: DirectDirectionHotkeys?
```
- `WindowHintsConfigBuilder.build` で `navigation.direction.direct.{modifiers,keys}` をパース(既存 `navigation.direction.hints.keys` パースの直後)。バリデーション(Spoon版準拠):
- 方向名は `Direction(rawValue:)` で検証、不正なら ConfigError
- キーは小文字化し、重複は ConfigError
- `keys` が空/未指定 → direct 全体を nil(黙って無効)
- `keys` があるのに `modifiers` が空/欠落 → ConfigError
- **`fn` は ConfigError にする**: Carbon `RegisterEventHotKey` は fn 修飾非対応で、`KeyCodes.carbonModifiers` では黙って無視され「fnなしホットキー」になってしまうため(許可リスト: cmd/command, alt/option, ctrl/control, shift)
#### 1-2. ホットキー登録 — `Sources/Jinrai/Features/WindowHintsFeature.swift`
- プロパティ `private var directDirectionHotkeys: [Hotkey] = []` を追加。
- `init` 内(既存の本体ホットキー登録 L96-103 の直後)で、方向ごとに `Hotkey(modifiers:key:)` を登録。ハンドラは `guard !self.isVisible else { return }` の防御付きで `runDirectionalMove(direction)` を呼ぶ。登録失敗は NSLog。
- `runDirectionalMove` は**変更不要**: 非表示時でも `WindowEnumerator.orderedWindows()` をその場で列挙し、`close()`/`dismissSpotlight` は非表示時 no-op。current は最前面標準ウィンドウ。
- `teardown()` で全 `directDirectionHotkeys` を unregister → 設定リロード時の再登録は既存フロー(`AppDelegate.reloadConfig` → teardown → start)で自動成立。**AppDelegate の変更は不要**。
- ヒント表示中の競合なし: 表示中は EventTap が keyDown を消費するため Carbon ホットキーには届かない(既存コメント L878 と同じ前提)。「表示中は hints.keys、非表示中は direct」の住み分けをコメントに残す。
#### 1-3. テスト — `Tests/JinraiCoreTests/ConfigTests.swift`(WindowHintsConfigTests Suite)
1. デフォルトで `directDirectionHotkeys == nil`
2. modifiers+keys 両指定でパース成功(小文字化・斜め方向 upLeft 等の受理も確認)
3. 空 keys → nil(エラーにしない)
4. keys あり・modifiers なし → ConfigError
5. 不正な方向名 → ConfigError
6. キー重複 → ConfigError
7. modifiers に "fn" → ConfigError
### Part 2: ドキュメント全面修正
#### 2-1. 全ページ共通の変換
- Lua コードブロック → JSONC(`~/.config/jinrai/config.jsonc` の該当セクション)。キーパスは基本同一(`window_hints.hint.chars` 等)だが、値の記法を JSON に(`{ red = 0.4 }` → `{ "red": 0.4 }`、`nil` → 項目省略)。
- 「Hammerspoonスクリプト」「Hammerspoon Spoon」→「macOS用ネイティブアプリ」等の表現に変更。
- `spoon.Jinrai:setup({...})` の外殻を除去し、config.jsonc のトップレベル構造で提示。
#### 2-2. ファイル別の修正内容
**docs/zensical.toml**
- `site_description`: 「…hammerspoonスクリプト」→「思考の速度で素早くウィンドウ操作を行うmacOS用ツール」(README と統一)。
**docs/docs/index.md**
- L6, L17 の Hammerspoon 記述を修正。他はほぼ流用可。
**docs/docs/setup.md(全面書き換え)** — README.md の内容を正として:
- 前提準備(Hammerspoon/SpoonInstall)を削除。
- インストール: Homebrew `brew install tadashi-aikawa/tap/jinrai`(推奨)/ 手動 zip + Gatekeeper 手順(README L27-45 を反映)。
- 権限: アクセシビリティ必須、Window Hints のプレビューには画面収録も必要。
- 最小設定: 初回起動で `~/.config/jinrai/config.jsonc` が自動生成される(`ConfigLoader.defaultConfigTemplate` の内容を掲載)。`$XDG_CONFIG_HOME` 尊重。編集後はメニューバーの「設定を再読込」。
- アップデート: メニューバー「アップデートを確認…」(自動DL・置換・再起動)/ Homebrew 管理下は `brew upgrade --cask jinrai` 案内のみになる旨(UpdaterFeature の挙動)。
**docs/docs/configuration.md(全面書き換え)** — `Sources/JinraiCore/Config/*.swift` のデフォルト値・キーパスから再生成:
- トップレベルキー: `macos_native_tabs`(snake_case に変更)、`jinrai_mode`、`focus_border`、`window_hints`、`focus_back`、`window_mover`、`application_hints`。
- 削除する項目(実装に存在しない):
- window_hints: `hint.collisionOffset`、`hint.key.size / horizontalPadding / gap / fontName`、`hint.title.fontName / rowGap`、`hint.spaceBadge.*`(バッジは固定デザインで常時表示、と本文で言及)、`navigation.direction.scoring.debug`、`behavior.callbacks`
- focus_back: なし(`urlEvent.name` は残す。説明を `jinrai://<名前>` に)
- window_mover: `selectedArea.appearance.borderWidth / cornerRadius / styles`
- application_hints: `newWindow.callback`、`behavior.callbacks`
- `macosNativeTabs = false` での無効化記述
- 変更する項目:
- `selectedArea.defaultScreen`: UUID 文字列参照 → **エリア名→キーのマップを直接指定**(WindowMoverConfig.swift の SelectedArea.defaultScreen: [String: String]?)
- `application_hints.newWindow`: `callback` → `url`(指定時は open を最優先)
- 追記する項目(実装にあり docs にない):
- window_hints: `focusedWindowSpotlight.alpha`(既定 0.5)、`behavior.showFadeIn.hints`(0.05)/ `behavior.showFadeIn.spotlight`(0.4)
- window_mover: `selectedArea.activeWindowSpotlight.alpha`(0.5)、`selectedArea.activeWindowHighlight.borderColor / borderWidth(13) / cornerRadius(12)`
- application_hints: `appearance.keyHighlightColor`
- direction.direct は Part 1 実装後の仕様で記載(fn 修飾不可の注意含む)。
- 「選択肢と共通ルール」: 修飾キーは `cmd/command`、`alt/option`、`ctrl/control`、`shift`、`fn`(KeyCodes.swift:74-98 が正)。色は「Hammerspoonの色テーブル」→ JSON オブジェクト。コールバック節は削除。
**docs/docs/window-hints.md**
- Lua → JSONC。`hint.key.size / fontName`、`title.fontName`、`spaceBadge` 設定、`collisionOffset` を設定例から削除。
- `navigation.direction.direct` は新実装の仕様に合わせて記載。
- 隠れウィンドウのプレビューに画面収録権限が必要な旨を追記。
**docs/docs/application-hints.md**
- 「アプリ固有の新規ウィンドウ作成」節: `newWindow.callback`(hs.urlevent)→ `newWindow.url` に書き換え(Obsidian 例は `"url": "obsidian://open?path=..."`)。
- `appearance.keyHighlightColor` に触れる(任意)。
**docs/docs/window-mover.md**
- `selectedArea.defaultScreen` の説明と例を「エリア→キーのマップ直接指定」に修正。
- 「選択画面の見た目」節: `appearance.borderWidth / cornerRadius / styles` を削除し、`appearance.state.normal / dimmed`(実装で読込)+ `activeWindowHighlight / activeWindowSpotlight` に差し替え。
**docs/docs/focus-back.md**
- `hammerspoon://<名前>` → `jinrai://<名前>`(Info.plist の URL scheme + AppDelegate:182 の分岐)。
**docs/docs/focus-border.md、jinrai-mode.md、window-mover-areas.md**
- Lua → JSONC の書式変換のみ(スキーマは一致)。
**docs/docs/macos-native-tabs.md**
- キー名を `macos_native_tabs` に。`spoon.Jinrai:setup` 外殻除去。
- 「補正を無効化(`= false`)」節を削除(実装に無効化手段なし)。
**README.md**
- 「ドキュメント」節の TODO 2件を実 URL(https://tadashi-aikawa.github.io/jinrai/ と https://deepwiki.com/tadashi-aikawa/jinrai)に置換。
#### 2-3. 対象外(変更しない)
- `docs/site/`(ビルド成果物)、`docs/.venv/`、`docs/.cache/`
- デモ動画(YouTube)・ブログ記事リンク: そのまま残す
- `docs/pyproject.toml` の description 等の雛形値
### 検証
1. `swift build && swift test`(direction.direct のロジックテスト含む)
2. `./scripts/make-app.sh && open .build/Jinrai.app` で direction.direct の実機確認(config.jsonc に direct 設定を書き、修飾キー+hjkl で隣のウィンドウへフォーカス移動すること、Window Hints 表示中の挙動と競合しないこと)
3. docs: `cd docs && uv run zensical serve`(または build)でビルドエラー・リンク切れがないことを確認し、主要ページを目視
4. ドキュメントの JSONC 例が `RootConfigBuilder.build(text:)` で実際にパース可能なことをスポットチェック(テンプレート+代表例)