# 0001. アーキテクチャとロードマップ(ドラフト v0.1) - 状態: **未合意ドラフト**(ユーザー承認待ち) - 作成: 2026-10-18 - 前提調査: `docs/research/2026-10-18-*.md`(4本 + 追加1本) --- ## 1. 目的と非目的 ### 1.1 目的(ユーザー回答の逐語に基づく) > 「見た目が気に入らない。日本語ネイティブではなく、更新で崩れる可能性もある。 > 将来的にハーネスごとオリジナルにしたいので、TUIをいまから作っておいてUXを研究し、 > ハーネスチューニングを研究したい。」 これを分解すると、このプロジェクトの成果物は「TUI」そのものではなく **研究基盤**である。 | # | 目的 | 対応する設計要求 | |---|---|---| | P1 | **見た目を自分で設計できる** | 描画層を自前で握る。装飾演出を既定で入れない | | P2 | **日本語ネイティブ** | 文言を最初からカタログ化。日本語を第一級に(言語パックに追い出さない) | | P3 | **上流更新で崩れにくい** | 依存する上流の非公開契約を最小化し、その数を常時計測する | | P4 | **UX研究の土台** | UI層とハーネス層を分離し、UIの反復試行を安くする | | P5 | **将来ハーネスごと差し替える** | ハーネス境界を1箇所(アダプタ層)に閉じ込める | > **2026-10-18 ユーザー回答による修正**: P4/P5 は**思想として保持するが、設計上の特別な考慮はしない**。 > 三層構造(§3.1)は P5 のためではなく、**UIを単体でテストできること**と**上流の変更を閉じ込めること**という > 実利のために採用する。P5 は「結果的にそうなっている」状態に留める。 > また **自前入口は必須要件とする**(§3.3)。 | P6 | **ハーネスチューニング研究** | ハーネスの挙動(プロンプト/ツール/権限/モデル路由)を外から差し替え可能に保つ | ### 1.2 非目的(v0 では作らない) dsh-TUI の機能棚卸し(`2026-10-18-dsh-tui-feature-inventory.md`)の13カテゴリのうち、以下は v0 の非目的とする。 - マルチバックエンド(Claude / Codex)— `src/backends/` 28,909行 相当 - 画像(Kitty/Sixel・プレビュー・貼付)— 端末依存が重い - Mermaid / LaTeX 描画 - プラグインエコシステム(第三者プラグインのホスト、`tui.dsh/v1alpha1` 相当) - 他エージェントからの会話移行、`/update`、`/star` - 起動演出(ランチパッド・ピクセルクジラ・コンパニオン・tips) - 購読枠/コスト見積り、軌跡シーン、サブエージェントDashboard > 判断理由: P1(見た目を自分で設計)と P4(UX研究)に対し、これらは「他人のUXを移植する」作業であり、 > 研究の初期段階では情報量あたりのコストが最も悪い。 --- ## 2. 前提となる事実(調査で確定したもの) 出典は各ノートの該当節。ここには設計判断に効くものだけ置く。 | # | 事実 | 出典 | |---|---|---| | F1 | DSH の実行単位は「プロファイル = バンドル(Cordis プラグイン木)の合成」。第三者がバンドルを足すのは**公式の拡張点** | `dsh-integration-surfaces.md` §1 | | F2 | バンドル自作に必要な宣言は `dsh.bundle.patch` のみ。型は `@deepseek-ai/dsh-package-manifest` が公開 | 同 §1.5 | | F3 | 承認とユーザー質問は `dsh-base` が**サービスとして持つが UI を持たない**(`user-questions` / `approval` 行) | 同 §1.6 | | F4 | プラットフォーム非依存の UI 契約は `web` のみ公開。**TUI は in-process の Host プラグイン以外に道が無い** | 同 §9 | | F5 | 公式の別プロセス口(SDK JSON-RPC / ACP)には**承認・質問・モデル切替のチャネルが無い** | 同 §3, §9 | | F6 | 参考実装は `ink` パッケージを使わず、**37k行の自前レンダラ+Yoga移植**を持つ。React dev ビルドで 4GB OOM の実障害記録あり | 同 §11 | | F7 | 参考実装は DSH の boot 手順を**複製**しており、`HOST_MODULES` 8モジュールの export 名に依存。壊れると無言で `dsh --profile` 経路へ落ちる | `dsh-tui-seam.md` §1, §4-b | | F8 | `loadProfileDirectory` は互換性 NG のバンドルを**エラーにせず黙って skip** する | `dsh-core-public-surface.md` §2 | | F9 | 上流の非公開契約変更で実際に起動不能になった事例がある(dsh-tui #1595) | `dsh-third-party-tui-web.md` §3 | | F10 | DSH は developer preview で「互換性破壊的変更がある」と README に明記 | 同 §1 | | F11 | 参考実装の DSH 接続コアは **5,000〜8,000行規模**(推測)。UI層 93,235行は削れない | `dsh-tui-seam.md` §5 | --- ## 3. アーキテクチャ方針 ### 3.1 三層構造(実利のための分割) 分割の目的は2つだけである。 1. **UI を DSH 抜きでテストできる**(見た目の反復試行が速くなる) 2. **上流の変更をアダプタ層に閉じ込める**(P3) ``` ┌─────────────────────────────────────────────┐ │ UI 層 画面・部品・描画・キー入力 │ ← P1(見た目) │ ハーネスの語彙を知らない │ ├─────────────────────────────────────────────┤ │ 中立ドメイン AgentEvent / TuiCommand 型のみ │ ← 差し替え境界 ├─────────────────────────────────────────────┤ │ ハーネスアダプタ DSH の Cordis プラグイン │ ← P3 / P5 / P6 │ @deepseek-ai/* を import する唯一の層│ └─────────────────────────────────────────────┘ ``` **規則(強制する)**: `@deepseek-ai/*` の import は アダプタ層のディレクトリ内のみ。 参考実装も `ADAPTER.md:9` で同じ規則を明文化しており、これは実証済みの設計である(`dsh-tui-seam.md` §2)。 > 副次的効果として、将来ハーネスを自作するときはアダプタ層だけを書き換えれば済む。 > ただしこれは**設計目標ではなく結果**である(P4/P5 は思想として保持、§1.1 の注記)。 ### 3.2 DSH への載せ方 - 自前 npm パッケージ(scoped)を1つ作り、`dsh.bundle.patch` で `cordis.patch.yml` を宣言する(F2)。 - プロファイル `` を作り、`dsh.profile.bundles = ["@deepseek-ai/dsh-base", "<自作パッケージ>"]` とする。 - 起動は **`dsh --profile ` の一本**とする。 ### 3.3 判断: 自前入口は持つ。ただし方式を3つに分けて評価する **自前入口は必須要件とする**(2026-10-18 ユーザー回答)。ただし「自前入口」には実装量が2桁違う3方式がある。 | 方式 | 実装量 | 得られるもの | 壊れやすさ | |---|---|---|---| | **A. `dsh --profile ` のみ** | 0 | 起動できる | なし | | **B. 薄いラッパー** — `bin` から `exec dsh --profile "$@"` | **数行** | 独自コマンド名/引数の素通し/上流の起動をそのまま使う | なし(上流の `--profile` 起動が壊れない限り) | | **C. フル host-entry** | **約100行**(公開関数の呼び出し) | 上記に加え、DSH を in-process で取り込み自前の構成根を持つ | 依存は **2モジュール・2エクスポート**のみ(Phase 0 実測) | **決定: C(フル host-entry)を最初から作る**(2026-10-18 ユーザー選択)。 > **2026-10-18 訂正(Phase 0 の実測による)**: 本節の初稿は C のコストを「736行 + boot手順の複製」と見積もり、 > `HOST_MODULES` 8モジュールへの依存を脆さとして挙げていた。**これは参考実装が boot 手順を写した場合の話**である。 > `dsh/lib/bin.js:213-222` を読むと、ランチャ自身が公開関数 `runProfile(...)` を呼んでいるだけだった。 > **同じ公開関数を自分の入口から呼べば、複製は不要**である。Phase 0 で実装・検証済み。 C が実際に依存するもの(Phase 0 実測・`src/host-contract.ts`): | 依存 | 何のため | 壊れたときの症状 | |---|---|---| | `@deepseek-ai/dsh/profile-boot` の `runProfile` | プロファイルを合成して木をマウントする | 起動失敗 → **B へフォールバック**(実測で確認) | | `@deepseek-ai/dsh-app-boot` の `loadLayeredEnv` | 起動環境のスナップショットを取る | 同上 | **C に課す設計制約(4件)と Phase 0 時点の状態**: | # | 制約 | 状態 | |---|---|---| | 1 | **失敗時は必ず B(`dsh --profile` 子プロセス)へフォールバックする** | **実装済み・検証済み**(`verify-bundle.mjs` の検査 D) | | 2 | **上流への依存は1ファイルに集約する** | **実装済み**(`src/host-contract.ts`。依存は上記2件のみ) | | 3 | 依存している上流ファイルの同一性を機械的に検出する | **未実装**(差分がまだ無いため。Phase 1 以降) | | 4 | 「意図的に上流と違う点」を記録する | **未実装**(同上) | ### 3.4 描画層(D3) 評価基準は §3.4 旧稿の6項目(マウス選択/スクロール固定/長セッション/日本語幅/依存の少なさ/実装量)。 追加調査(`docs/research/2026-10-18-renderer-options.md`)の結果を当てはめる。 | 候補 | マウス選択 | スクロール固定 | 長セッション | 日本語幅 | 依存 | 実装量 | |---|---|---|---|---|---|---| | **Ink v8.0.0** | **✗** v8 で未認識シーケンス(マウス等)を**破棄**。`useMouse` 無し | **✗** ScrollView 無し。#222 は2019年起票で未解決 | **△** #978 native(external) リークが open。差分描画は既定 OFF・行単位 | △ `string-width` 依存 | 中(React 19 + yoga) | **大**(Ink の外側を全部自作することになる) | | **`@earendil-works/pi-tui`** | **✓** 文字/単語/行単位の選択、MouseRegion、ヒットテスト | **✓** ScrollView、速度適応ホイール | **✓** 行差分+CSI 2026 同期出力 | **✓** `get-east-asian-width` + `Intl.Segmenter` 内蔵 | **極小(2つ)** | 小 | | `@opentui/core` | ✓ セル単位・既定有効 | ✓ | ✓ | 未確認 | 大(Zig ネイティブ) | 最小だが**本環境で動作しない** | | 自前実装 | 自作 | 自作 | 自作 | 自作 | ゼロ | 最大(参考実装は37k行) | **決定: upstream の Ink を fork し、必要な機能を自前で足す**(2026-10-18 ユーザー選択)。 > この決定は「Ink をそのまま使う」ではない。**Ink は要求機能を持っていない**ことが実測で確定しているため > (§3.4 の表・上記の反証)、fork して自分で実装するという意味である。 > これは参考実装 dsh-TUI が取った道と同じであり、彼らの `src/ink/` は > `update-overflow-guard.ts:12` のコメントで「**the upstream fork lineage**」と自認している。 #### fork の起点(決定済み) **決定: (1) upstream Ink v8.0.0 から fork する**(2026-10-18 ユーザー選択)。 | 起点 | 規模 | 利点 | 欠点 | |---|---|---|---| | **(1) upstream Ink v8.0.0** ← **採用** | 約620KB(`dist.unpackedSize`)/ 依存23個 | 素性が明快。自分が書いていないコードを持たない。上流の修正を取り込む余地を残せる | マウス・選択・ヒットテスト・スクロール固定を**全部自分で書く**(参考実装はここに約24k行を積んだ) | | (2) 参考実装 dsh-TUI の `src/ink/`(MIT) | 33,755行(+ Yoga移植 3,296行) | マウス選択・ヒットテスト・スクロールが既に入っている | 他人の設計判断と 33.7k行を初日から引き受ける。動機(ブラックボックスを捨てる)と矛盾する | **fork 元の記録(初日に `UPSTREAM.md` へ書く値・実測済み)**: | 項目 | 値 | |---|---| | 上流 | `ink`(npm)/ `vadimdemedes/ink`(GitHub) | | バージョン | **8.0.0** | | 公開日 | 2026-10-03T11:23:24Z | | **upstream コミット** | **`26d2c3f83008142061c22267482489588cc3823c`**(npm `gitHead`) | | ライセンス | MIT | | `engines.node` | `>=22` | | peer | `react >=19.3.0`, `@types/react >=19.3.0`, `react-devtools-core >=6.1.2` | | 依存 | 23個(`chalk` / `yoga-layout` / `react-reconciler` / `string-width` / `@alcalzone/ansi-tokenize` / `wrap-ansi` / `cli-truncate` / `ansi-styles` / `terminal-size` ほか) | #### fork に課す規律(4件・必須) 参考実装は上流との差分管理に苦労した形跡がある(`update-overflow-guard.ts:12`「the upstream fork lineage hit this repeatedly」)。同じ轍を踏まないため、fork の初日に次を敷く。 1. **fork 元を1ファイルに記録する** — 上流リポジトリ・タグ・コミットSHA・取得日 2. **上流との差分を一覧で維持する** — 「上流にあるが我々が変えた点」「我々が足した点」を分けて記録 3. **上流の更新を検出できるようにする** — 上流の新リリースと fork 元の差分をコマンド1つで見られる状態にする 4. **fork したコードと自作コードを物理的に分ける** — **決定: `src/ink/` に置く**(D7)。 参考実装と同じ配置であり、ディレクトリ名で上流由来であることを示す。上流由来ファイルには 先頭に由来コメントを残し、自作ファイルと区別できるようにする #### fork に伴う未検証リスク | # | リスク | 状態 | |---|---|---| | V1 | **実描画性能のベンチマークが無い**(Ink 公式にも無い。issue #205 は O(n³) の疑い、#826 は `lastOutput` 二重保持) | 実測が必要 | | V2 | Ink v8 の `incrementalRendering` は**既定 OFF・行単位**。セル単位が必要なら自作 | 設計判断 | | V3 | Ink v8 は**未認識シーケンスを `useInput` に流さない**。マウスは fork 側で stdin 層から拾い直す必要がある | 実装方針は明確 | | V4 | React 19.3+ の dev ビルドで **4GB OOM の実障害記録**(参考実装 b1e06d8)。`NODE_ENV=production` 強制が必要 | 対策既知 | | V5 | 日本語幅は `string-width` 依存。ambiguous 幅・VS16・ZWJ の**実端末値は未検証** | 実機確認が必要 | | V6 | Ink v8 は**依存23個**を持ち、その中に **`yoga-layout`(ネイティブ/WASM)** が含まれる。参考実装は Yoga を **TS 移植(3,296行)で置き換えて**この依存を消している | 方式の選択が必要 | --- ### 3.5 検討したが採らなかった代替案(批判的検討) 目的 P1(見た目)だけを見れば、より安い道が2つある。**採らない理由を明示しておく。** | 代替案 | 利点 | 採らない理由 | |---|---|---| | **(a) dsh-TUI をフォークし、スタイルだけ変える** | 「見た目」だけなら最安。アダプタ層 58,122行と描画層 33,755行が既にある | P5(将来ハーネスごと差し替え)に到達しない。230,275行のコードベースを保守する前提を負う。P1 の「自分で設計する」が「他人の設計を塗り替える」に退化する | | **(b) 既存の軽量 DSH TUI を土台にする** | 2026-10-18 時点で DSH 用 TUI は GitHub 検索で **229件**。軽量な実装が複数ある(例: `dsh-blue/blue` "a TUI is not a package, it is a Cordis plugin tree" / `fan56/dsh-tui-pi` "pure cordis plugins with zero upstream patches") | 同上。加えて P6(ハーネスチューニング研究)には、土台の設計を理解している必要があり、他人の設計を読むコストが自作と同等以上になりうる | > **ただし (b) は「読む」目的では価値が高い。** 特に「上流パッチを1つも持たない純 Cordis プラグイン構成」を > 名乗る実装は、Phase 0/1 の最大の未知(DSH バンドルとして正しく載るか)を先に解いている。 > そこで **Phase -1** を置く(§6)。 ### 3.6 検証環境(開発環境固有・実測済み) 本プロジェクトの開発環境はファイルサンドボックス化されており、**ワークスペース外は読み取り専用**である (`mkdir ~/.dsh/profiles/...` → `Read-only file system`)。したがって `$HOME/.dsh` に触れずに DSH を動かす必要がある。 **確立した方法**: `DSH_HOME` をワークスペース内へ向ける。 ```sh DSH_HOME="$PWD/.dsh-home" dsh --profile ... ``` | 実証項目 | 結果 | |---|---| | `--dump-config`(マウントなし) | 96行の合成ツリーを出力、exit 0 | | 実際の起動(`--profile headless --help`) | 起動、exit 0 | | 実モデル実行(`--json`) | exit 0、`session`/`status`/`thinking`/`text`/`final` の8イベントを取得 | API キーは環境変数で供給する(`COMMANDCODE_API_KEY` など)。詳細は `docs/research/2026-10-18-sandbox-and-dsh-home.md`。 ## 4. 決定ログ | ID | 決定 | 状態 | 根拠 | |---|---|---|---| | D1 | 統合方式は **in-process バンドル型** | **確定**(ユーザー選択) | F4, F5。承認・質問・モデル切替を人対話で行うには他に道が無い | | D2 | **C(フル host-entry)を最初から作る** | **確定**(ユーザー選択 2026-10-18)。C のフォールバック経路は B と同一なので、B は自動的に存在する | §3.3, F7 | | D3 | 描画層は **upstream Ink v8.0.0 を fork して自前で拡張する**(upstream commit `26d2c3f8`) | **確定**(ユーザー選択 2026-10-18) | §3.4 | | D4 | v0 の機能範囲は §5 の最小核10項目のみ | **確定**(ユーザー選択 2026-10-18) | §1.2, §5 | | D5 | **GitHub に公開リポジトリを作る**。名称は `DSH-forJP-TUI` / npm `dsh-forjp-tui` / profile `forjp` / cmd `dsh-forjp` | **確定**(ユーザー選択 2026-10-18。全名称の空きを registry で確認済み) | `gh` 認証済み(`mugi995` / id `151381455`)。git 識別情報は `mugi995` + `151381455+mugi995@users.noreply.github.com` | | D6 | 公開物は**ローカル絶対パスをマスクしてから** push する | **確定**(ユーザー選択 2026-10-18) | 調査ノート5ファイルに `$HOME` 配下の絶対パスが含まれるため | | D7 | fork した Ink は **`src/ink/`** に置く(単一パッケージ) | **確定**(ユーザー選択 2026-10-18) | §3.4 規律4 | | D8 | **ライセンスは MIT** | **確定**(ユーザー選択 2026-10-18) | 参考実装 dsh-TUI・DSH 本体・fork 元の Ink と同じ。Ink の MIT 表示を同梱する | | D9 | 対応 DSH バージョンの固定方法 | **訂正**: `engines.dsh` は **`dsh-app-boot` に読み取り箇所が無く無効**(Phase 0 実測)。実際に効くのは **`peerDependencies` を exact `0.2.0-rc.2` で書くこと**。範囲指定(`^0.2.0`)は prerelease に非適合で**行が無言で disabled 化される** | `dsh-app-boot/lib/index.js:286-313, 2085-2089`。`docs/reports/2026-10-18-phase0-walking-skeleton.md` §3.2 | --- ## 5. v0 の機能範囲(最小核) 機能棚卸しの「必須」10項目を、我々の目的に合わせて再定義する。 | # | 機能 | 備考 | |---|---|---| | 1 | 端末入力解析(キー・マウス・ブラケットペースト) | 描画層の一部 | | 2 | 差分描画・レイアウト | 描画層の一部 | | 3 | **全角/絵文字の幅計算** | P2 の生命線 | | 4 | 入力欄(複数行・カーソル) | | | 5 | 会話ストリーム表示(逐次・Markdown) | Markdown は最小限(見出し/強調/コード/リスト)から | | 6 | ツール呼び出しカード(引数と出力) | | | 7 | **承認パネル(許可/拒否)** | F3。無いと権限 `ask` の下でツールが実行できない | | 8 | **ユーザー質問パネル(`ask_user_question`)** | F3。同上 | | 9 | セッション結線(`agents.create` / `followup` / `steer` / `session/event` 購読) | F3 の逆側。アダプタ層の中核 | | 10 | 中断(Esc)と終了、最小コマンド(`/help` `/new` `/exit`) | | **v0 に入れない**: `/model` 切替(`initialize` 相当の再構成が要る)、セッション再開 UI、テーマ切替 UI、設定画面。 → v1 以降で P1/P4 の知見を得ながら追加する。 --- ## 6. ロードマップ 各フェーズは「合意 → 実装 → 検証」を1単位とし、**合意なしに次フェーズへ進まない**。 ### Phase -1: 先行実装を読む(数時間・実装なし) - **目的**: Phase 0/1 の未知を、他者が既に解いている分だけ先に回収する - **やること**: 上流パッチを持たない軽量 DSH TUI を1〜2本読み、 (a) `cordis.patch.yml` に何を挿したか (b) 上流のどのサービス/イベントに繋いだか (c) 描画層に何を選んだか を記録する - **候補**: `fan56/dsh-tui-pi`("pure cordis plugins with zero upstream patches")、`dsh-blue/blue`、`boxeryao/dsh-mini-tui` - **成果物**: `docs/research/` に比較ノート1本 - **注意**: コードを写経しない。**構成の事実だけを取る** ### Phase 0: 走路骨格(walking skeleton) — **完了(2026-10-18)** > 結果: `docs/reports/2026-10-18-phase0-walking-skeleton.md` / 検証: `node scripts/verify-bundle.mjs`(12検査 PASS) > 4項目すべて達成。C のコストは初稿の見積り(736行)ではなく約100行だった(§3.3 の訂正を参照)。 - **目的**: 最大の未知である「DSH バンドルとして自作 TUI が本当に載るか」を最小コストで検証する(F1, F2, F4) - **参照すべき公式の手本**: `@deepseek-ai/dsh-headless`。 これは「エージェント identity を解決 → タスクを user message として submit → quiescence まで待つ → イベントを畳む」 という、我々のアダプタ層の中核と**ほぼ同じ処理**を、公式が最小構成で実装している (`lib/index.js` 13,864 bytes + `lib/startup.js` 4,471 bytes + `cordis.patch.yml`)。 参考実装 dsh-TUI の `src/dsh-adapter/` 58,122行を読む前に、まずこちらを読む。 #### Phase 0 の内訳 | 段階 | やること | 完了の判定 | |---|---|---| | **0a** | `dsh-headless` の実装と `cordis.patch.yml` から、**バンドルの書き方**と**エージェント駆動の最小手順**を抽出する | 抽出結果が `docs/research/` に記録されている | | **0b** | バンドル骨格: `package.json`(`dsh.bundle.patch` / `engines.dsh` / peerDeps)/`cordis.patch.yml`/最小の Cordis プラグイン/`tsconfig.json`/ビルド | `dsh --profile forjp` で自作プラグインの `apply` が呼ばれる | | **0c** | C(フル host-entry)の最小版。**失敗時は必ず B へフォールバック**(§3.3 制約1)。依存する上流 export 名を1ファイルに集約(同 制約2) | C 経路で起動する。**C を故意に壊すと B へ落ちて起動し続ける** | | **0d** | `session/event` の購読。生イベントをファイルへダンプする(表示は捨て UI でよい) | C 経路と B 経路の両方で、`session/event` の生ダンプがファイルに残る | #### 成果物 - `UPSTREAM.md`(fork 元の記録・Phase 0.5 の項目4と共通) - `src/` の骨格とビルド設定 - `docs/research/` に 0a の抽出結果 #### 制約 - **ここで描画層に投資しない**。`src/ink/`(Ink fork)には着手しない。検証用の捨て UI でよい - ブランチを切って PR を出す(AGENTS.md の開発タスク規定) ### Phase 0.5: Ink fork の足場作り - **目的**: §3.4 の「fork に課す規律」4件を初日に敷き、fork が無法地帯にならないようにする - **やること**: 1. fork 元(上流リポジトリ・タグ・コミットSHA・取得日)を1ファイルに記録する 2. 上流との差分を一覧で維持する仕組みを作る 3. 上流の新リリースと fork 元の差分をコマンド1つで見られるようにする 4. fork したコードと自作コードを物理的に分ける 5. V1(描画性能)を実測する — 1万行相当の transcript で描画時間とメモリを計測 6. V3(マウス)の疎通 — Ink v8 は未認識シーケンスを `useInput` に流さないため、stdin 層から拾い直す経路を通す 7. V4(React dev ビルドの OOM)対策 — `NODE_ENV ??= 'production'` を最初から入れる 8. V5(日本語幅)— 全角・結合文字・絵文字を実端末で確認し、`string-width` の理論値とのずれを記録する - **完了条件**: fork 元と差分が記録され、V1/V3/V4/V5 の実測値が残っている ### Phase 1: ハーネス境界の確定 - **目的**: P5 の土台。中立ドメイン型(`AgentEvent` / `TuiCommand`)を定義する - **作る**: アダプタ層(`agents.create` / `followup` / `steer` / `session/event` / `agent/assistant-stream` / `approval/request` の6点) - **検証**: 承認が発生する操作を投げ、`ask` ポリシー下で承認要求が中立イベントとして上がること - **完了条件**: 参考実装の `src/dsh-adapter/` 58,122行のうち、我々が書いた行数が計測され、5,000行以内に収まる見込みが立つ ### Phase 2: 描画層の投入(D3 確定済み: Ink v8 fork) - **目的**: P1。見た目の設計を始められる状態にする - **作る**: 決定した描画層で、入力欄・ストリーム表示・ツールカード・承認パネル - **検証**: 日本語・全角・絵文字・結合文字の表示テスト、長文スクロール、マウス選択コピー - **完了条件**: 自分のターミナルで「日本語で対話できる」と感じられる ### Phase 3: UX 研究サイクル - **目的**: P4。見た目と操作を反復して変える - **作る**: テーマ、レイアウト、通知、キーマップ - **完了条件**: 変更→体感→記録のサイクルが1週間で回る ### Phase 4: ハーネスチューニング研究 - **目的**: P6。`cordis.patch.yml` でプロンプト・ツール・権限・モデル路由を差し替える - **完了条件**: ハーネス側の変更が UI 層に波及しないことを確認できる ### Phase 5(構想): ハーネスごとオリジナル - アダプタ層を自作ハーネス向けに書き換える。UI 層と中立ドメインは無傷 --- ## 7. リスクと対策 | # | リスク | 影響 | 対策 | |---|---|---|---| | R1 | DSH が developer preview で互換性を破壊する(F10)。**C 採用により非公開契約への依存が増える** | C 経路が落ちる/無言の挙動ずれ(F9 の実例あり) | 対応版を固定し、`dsh` の更新は明示的に行う。`engines.dsh` を宣言。検証済み版を1ファイルに記録(D6)。**C は必ず B へフォールバックする**(§3.3 制約1) | | R2 | 互換性 NG のバンドルが黙って skip される(F8) | 無言で壊れ、原因が見えない | 起動時に自分のバンドルが木に載ったかを自己申告するログを出す | | R3 | 描画層を自前で作ると基盤作りに時間を食われる(F6 の 37k行) | 研究目的に到達しない | Phase 0/1 では描画層に投資しない。D3 は「最小で目的を満たす」方を選ぶ | | R4 | スコープ膨張(dsh-TUI の機能を全部欲しくなる) | 同上 | §1.2 の非目的を明文化。追加はフェーズ合意としてのみ行う | | R5 | 参考実装の写経になり、P1(自分の見た目)が達成されない | 目的喪失 | UI 層は参考実装を読まない方針にする(アダプタ層のみ参考にする) | | R6 | **fork が上流から乖離し、上流の修正を取り込めなくなる**(参考実装が実際に踏んでいる) | fork が独自進化して保守不能になる | §3.4 の規律4件。特に「差分一覧の維持」と「上流差分を1コマンドで見る」 | | R7 | C(host-entry)を先に作ることで、上流追随の保守が初日から発生する | 開発速度の低下 | C の依存を1ファイルに集約し(§3.3 制約2)、壊れたら黙って B へ落ちる設計にする | | R8 | **Ink の描画性能に公式ベンチマークが無い**(V1)。差分描画は既定 OFF・行単位 | 長セッションで性能問題が出る | Phase 0.5-5 で実測。必要ならセル単位差分を自作する(参考実装は `frame.ts` / `flush-tick.ts` 等で実装) | | R7 | C(host-entry)を先に作ることで、上流追随の保守が初日から発生する | 開発速度の低下 | C の依存を1ファイルに集約し(§3.3 制約2)、壊れたら黙って B へ落ちる設計にする | --- ## 8. 未解決事項 | # | 事項 | 状態 | |---|---|---| | 1 | **開発環境** — 本環境の Node v22.22.1 は Amaro 無しで `workflow` が使えない。テスト実行基盤をどうするか | 要調査 | | 2 | **検証の自動化** — 参考実装は `scripts/` に 620ファイル/192,705行・`verify:*` 126本を持つ。我々はどこまで敷くか | 要決定 | | 3 | **DSH 本体のどれを「公開面」とみなすか** — `./src/*` export は同梱されておらず解決不能、`./types` は使える等、粒度が一定でない(`dsh-core-public-surface.md` §4) | 要調査 | | 4 | **日本語の幅の実端末値** — ambiguous 幅・VS16 絵文字・ZWJ 連結の実測(Phase 0.5-8 で取得) | 要実測 | ## 9. 承認後にやること(Phase 0 の着手前) 1. `git init` と git 識別情報の設定(`mugi995` / `151381455+mugi995@users.noreply.github.com`) 2. 公開前サニタイズ(D6)— ローカル絶対パスを `$HOME` 等へマスク 3. GitHub に公開リポジトリ `DSH-forJP-TUI` を作成し、`docs/` を初回コミット 4. `UPSTREAM.md` の作成(§3.4 の fork 元記録) 5. Ink v8.0.0 を `src/ink/` へ vendoring(D7) 6. AGENTS.md の開発タスク規定に従い、以降は**ブランチを切って PR** で進める 3. **開発環境** — Node は `^22.19 || >=24` を要求する参考実装に対し、現環境は v22.22.1 で条件を満たす。ただし本環境の Node は Amaro 無しで `workflow` が使えない。テスト実行基盤をどうするか 4. **検証の自動化** — 参考実装は `scripts/` に 620ファイル/192,705行・`verify:*` 126本を持つ。我々はどこまで自動検証を敷くか 5. **DSH 本体のどれを「公開面」とみなすか** — `./src/*` export は同梱されておらず解決不能、`./types` は使える等、粒度が一定でない(`dsh-core-public-surface.md` §4)