# Iris 開発ガイド(コントリビューター向け) このドキュメントは Iris を**開発する人**向けです。Iris を**使うだけ**なら [README.md](./README.md) と [docs/slack-setup.md](./docs/slack-setup.md) で完結します (Slack App は 1 つ作れば十分です)。 設計・アーキテクチャの詳細は [.claude/CLAUDE.md](./.claude/CLAUDE.md) を参照してください。 ## 前提 - Node 22(`.node-version` で 22.18.0 に固定。nodenv 等で合わせる) - pnpm ```bash pnpm install # 初回。prepare フックで lefthook も入る ``` ## 品質ゲート ```bash pnpm verify # typecheck → lint → format:check → test(push 前にこれが通ること) pnpm test # 単体テスト(node:test) pnpm test:coverage # カバレッジ(lcov.info を出力) pnpm lint # eslint + 複雑度チェック pnpm format # prettier --write ``` - `pre-push` で `pnpm verify` が自動実行されます(lefthook)。 - GitHub Actions でも push / PR 時に verify + coverage を実行します。 ## ブランチ運用 `feature/*`(または `refactor/*` `fix/*`)ブランチ → Pull Request → CI 確認 → マージ。 `main` への直 push はしません。 ```bash git checkout -b feature/xxx # 変更・pnpm verify git push -u origin feature/xxx gh pr create --base main --fill gh pr merge --squash --delete-branch ``` ## 設定ファイル(TOML 一本) 設定はすべて 1 つの TOML ファイルです。`.env` は使いません。探索順: | 条件 | 使うファイル | |------|-------------| | `IRIS_CONFIG=` | その指定パス | | (未指定) | `./iris.config.toml`(リポジトリ内 = 開発) | | (上が無ければ) | `~/.iris-slack/config.toml`(本番 / インストール後) | 開発では **リポジトリ直下の `iris.config.toml`** を置けば自動で使われます (テンプレート: [iris.config.example.toml](./iris.config.example.toml)。`iris.config.toml` は gitignore 済み)。 ```bash cp iris.config.example.toml iris.config.toml # トークン・work_dir・許可リストを記入 pnpm dev # tsx watch(自動再起動)で起動 ``` ## 本番と開発を同時に動かす(Slack App を分ける) 1 つの Slack App は Socket Mode の接続枠を 1 つしか持ちません。本番(launchd 常駐)と 開発(ローカル `src` 起動)が**同じ App のトークンを共有すると、メッセージがどちらの 接続に届くか不定**になり混線します(実際に起きます)。 そこで **開発用の Slack App を別に作り**(本番と同じスコープ / イベント / Interactivity 設定)、その**開発用トークンを開発の `iris.config.toml` に書きます**。本番は `~/.iris-slack/config.toml`(本番 App トークン)。設定ファイルが別なので、本番を 止めずに開発用 App でローカルの `src` を再起動し放題になります。 ## 起動方法まとめ | コマンド | 用途 | 使う設定 | コード | |----------|------|---------|--------| | `pnpm dev` | 開発(監視・自動再起動) | `./iris.config.toml` | `src`(tsx) | | `pnpm start:dev` | 開発(単発) | `./iris.config.toml` | `src`(tsx) | | `iris install` | 本番(launchd 常駐) | `~/.iris-slack/config.toml` | `dist`(npm 配布物) | > 検証で複数プロセスを立てると混乱のもとです。`ps aux | grep -iE "iris|dist/cli"` > で `src` 系・`dist` 系を**広く**確認し、不要なプロセスは PID 指定で停止してください > (`pkill` で `claude` 系を巻き込むと他セッションに影響するので避ける)。 ## プロジェクト構成 | ファイル | 責務 | |------|------| | `src/index.ts` | Bolt(Socket Mode)。設定ロード・ルーティング・Slack 送受信 | | `src/claude.ts` | Claude Code 子プロセス + stream-json | | `src/protocol.ts` | stream-json の純粋パーサ(テスト容易) | | `src/session.ts` | thread_ts ⇄ プロセスの対応表、resume / clear | | `src/permission.ts` | 権限要求 ⇄ Block Kit ボタン | | `src/attachments.ts` | 受信ファイル(画像 base64 / ファイル保存) | | `src/file-upload.ts` | 生成ファイルの Slack アップロード | | `src/stream-buffer.ts` | ストリーミングの逐次更新 | | `src/commands.ts` | スラッシュコマンド | | `src/config.ts` | TOML + 環境変数の設定ロード | | `src/format.ts` | mrkdwn 変換 / `NO_REPLY` / usage footer | | `src/cli.ts` | `iris` CLI(install / uninstall / status) | ## macOS スタンドアロンバイナリ(Node 不要) `@t2tx/iris` の npm 配布とは別に、Node ランタイムを同梱した単一実行バイナリ(Node SEA)を作れます。利用者は Node/npm 無しでダウンロード&実行できます。 ```bash pnpm build:sea # ad-hoc 署名(自分の Mac 用)→ dist-sea/iris (arm64, ~108MB) ``` 中身: esbuild で 1 ファイルに bundle → Node SEA でブロブを node バイナリ (nodenv shim でなく `process.execPath` の実 Mach-O)に postject で注入 → 署名。 `cli.ts` は `node:sea` で SEA 実行を検出し、launchd plist を「バイナリ直実行」に する(`node