Skip to content

Commit 03dbb04

Browse files
takemi-ohamaclaude
andauthored
feat(editor): Remote-SSH 跨ホストの attach 対応 + up 時のターミナル自動表示 (PLAN31_3) (#70)
* feat(editor): Remote-SSH 跨ホストの attach 対応 + up 時のターミナル自動表示 (PLAN31_3) Windows VS Code → Remote-SSH(Mac) → Mac の Docker 上コンテナ、という構成で devbase up の自動オープンが「コンテナが存在しません」で失敗する問題を修正。 実機検証の結果、ネスト authority attached-container+...@ssh-remote+<host> は 実際にサポートされており、これを使うと docker ルックアップが ssh 先(コンテナの ある側)で行われ解決できる(PLAN31_3 §2.3/§2.4 の当初想定を訂正)。 - build_attach_uri に ssh_host / docker_context を追加しネスト URI を生成 - DEVBASE_EDITOR_SSH_HOST(明示) / DEVBASE_EDITOR_DOCKER_CONTEXT(既定 docker context show) ※ ssh ホスト別名は VS Code が ssh 先端末 env に渡さず自動取得不可のため明示必須 - DEVBASE_OPEN_TERMINAL(既定 ON): up 時に folderOpen タスク .vscode/tasks.json を docker exec で配置し、フォルダを開くと統合ターミナルを自動表示(既存はスキップ) - CLI: --open-terminal / --no-open-terminal を追加 - docs / PLAN31_3 を実態へ更新、テスト追加 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(editor): ssh-remote ホスト名を ~/.vscode-server から自動検出 (env 変数不要化) 跨ホスト Remote-SSH attach に必要な ssh-remote authority ラベル(例 mac2)を、 ssh 先 ~/.vscode-server の File History (entries.json の resource URI に残る ssh-remote%2B<host>) から自動検出するようにし、DEVBASE_EDITOR_SSH_HOST の明示を 不要にした(明示は上書きとして残す)。 - IP / user@IP でのネスト attach は不可と実機確認(既存 ExecServer の authority と 一致が必須、"Parent authority found without ExecServer")。別名一致のみ有効 - resolve_editor_ssh_host: 明示 → ~/.vscode-server 自動検出 → None(フラット) の三段 - 複数 ssh-remote ホストは最新 mtime の entries.json を優先 - docs / PLAN31_3 を自動検出方式へ更新、テスト追加 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * perf(editor): ssh host 自動検出を mtime 降順・最初の一致で打ち切り _detect_ssh_host_from_vscode が全 entries.json を読んでいたのを、mtime 降順で 新しいファイルから順に読み最初の ssh-remote 一致で即 return する実装へ変更。 History が巨大でも全読み込みを避け devbase up の遅延を防ぐ (gemini 指摘 / major)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(editor): ssh host 自動検出を複数エディタのサーバーディレクトリへ拡張 DEVBASE_EDITOR=cursor / code-insiders 等でも跨ホスト自動検出が効くよう、 ~/.vscode-server に加え ~/.cursor-server / ~/.vscode-server-insiders / ~/.vscodium-server / ~/.windsurf-server を横断し、全 entries.json から最新 mtime のホストを採用する (_detect_ssh_host_from_dirs)。gemini 指摘 / major。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * perf(editor): ssh host 自動検出の entries.json 走査を上限 200 件に制限 無マッチ時に全 entries.json を read するのを避けるため、mtime 降順で新しい方から 最大 200 件のみ内容を読む (該当ホストは直近接続のファイルに載るため安全)。gemini 指摘 / minor。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * perf(editor): open_editor の skip 経路を URI 解決前に early return skip 判定 (非TTY/CI・code 不在等) でも resolve_container_name(docker compose ps) や resolve_docker_context(docker context show) を呼んでいたのを、skip を先に return して 無駄な外部コマンド実行を回避。gemini 指摘 / minor。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(editor): DEVBASE_EDITOR_SSH_HOST/DOCKER_CONTEXT の空文字でオプトアウト可能に env が空文字 ("") の場合を「明示的オプトアウト」として扱い、ssh host は自動推測を スキップしてフラット URI 強制、docker context は settings.context を付けない。 判定を `is not None` に変更 (定義されていれば値を尊重し、空なら None)。gemini 指摘 / major。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * perf(editor): コンテナ名解決を 1 回に集約し docker compose ps の二重実行を回避 _maybe_place_terminal_task が解決した実コンテナ名を返し、_maybe_open_editor → open_editor へ container_name として渡して resolve_container_name(docker compose ps) の重複呼び出しを除去。gemini 指摘 / minor。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(editor): folderOpen ターミナルタスクを SHELL 未設定でも起動可能に build_folder_open_tasks_json を type:shell + ${env:SHELL} から type:process + /bin/sh -lc 'exec "${SHELL:-/bin/sh}"' へ変更。SHELL 未設定コンテナで command が 空になりタスクが即失敗する問題を修正。codex 指摘 / major。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(editor): plain SSH では ssh host 自動検出を抑止 + open_index 集約 + scandir 化 - plain SSH (VS Code 外) は既存 ExecServer 不在でネスト URI が動かないため、自動検出は in_vscode の時だけ有効化 (resolve_editor_ssh_host に auto_detect 引数追加)。plain SSH は 明示設定時のみネスト URI を採用。codex 指摘 / major - open_index の env フォールバック+範囲チェックを _resolve_open_index に集約 (重複排除)。gemini / minor - ssh host 自動検出の History 走査を os.walk → os.scandir (固定深さ 1 階層) に変更。gemini / minor Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(editor): opener モジュール docstring を実態へ更新 (ネスト authority サポート) 冒頭 docstring が「ネスト authority は公式未サポート」と旧設計のまま残り実装・PLAN・ docs と矛盾していたのを、attached-container+...@ssh-remote+<host> 実サポート + 自動検出 + plain SSH degrade の現設計へ更新。codex 指摘 (round 4/5/10 で line 13 が diff 外のため inline 投稿 422 となり取りこぼしていた件) / minor。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent f235d4b commit 03dbb04

8 files changed

Lines changed: 752 additions & 56 deletions

File tree

docs/user/environment-variables.md

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,20 +149,54 @@ devbase はホストマシンの認証情報を自動収集し、コンテナ内
149149
| `DEVBASE_OPEN_EDITOR` | 真(`1`/`true`/`yes`/`on`)で `up` 後にエディタを開く(既定: OFF) |
150150
| `DEVBASE_EDITOR` | 起動コマンド(既定: `code`)。`cursor` / `code-insiders` 等も可 |
151151
| `DEVBASE_OPEN_INDEX` | scale 時に開く dev インスタンス番号(既定: `1`|
152+
| `DEVBASE_EDITOR_SSH_HOST` | Remote-SSH 跨ホスト構成での ssh-remote ホスト名(例 `mac2`)。**通常は `~/.vscode-server` から自動検出**され不要。検出が外れる場合のみ明示。下記「跨ホスト」参照 |
153+
| `DEVBASE_EDITOR_DOCKER_CONTEXT` | 跨ホスト時に ssh 先で使う docker context(既定: ホストの `docker context show`|
154+
| `DEVBASE_OPEN_TERMINAL` | 真で `up` 後に folderOpen ターミナル用 `.vscode/tasks.json` を配置(**既定: ON**|
152155

153-
都度の上書きは CLI フラグで行います: `devbase up --open` / `devbase up --no-open` / `devbase up --open-index N`(env より優先)。
156+
都度の上書きは CLI フラグで行います: `devbase up --open` / `--no-open` / `--open-index N` / `--open-terminal` / `--no-open-terminal`(env より優先)。
157+
158+
### 起動時に統合ターミナルを自動表示(`DEVBASE_OPEN_TERMINAL`
159+
160+
`up` 時に、開く dev コンテナのワークスペース(`/work/$GIT_REPO`)へ folderOpen タスク(`.vscode/tasks.json`)を `docker exec` で配置します(既存があれば変更しません)。VS Code はフォルダを開いた時にこのタスクで統合ターミナルを前面表示します。
161+
162+
VS Code 公式には「起動時にターミナルを開く」専用設定が無く、folderOpen タスクが唯一の方法です。なお自動実行には次の 2 つの **VS Code クライアント側ユーザー設定**が関わり、devbase からは制御できません(いずれも application/user スコープ専用):
163+
164+
- **Workspace Trust**: 信頼していないフォルダではタスクは自動実行されません(初回は「フォルダを信頼」が必要)。
165+
- **`task.allowAutomaticTasks`**: 既定 `off` ではフォルダごとに 1 回「自動タスクを許可」を尋ねます。`on` にするとプロンプト無しで実行されます。
166+
167+
→ 実際は「初回のみ信頼(+許可)クリック、以降は自動でターミナルが開く」挙動になります。無効化は `DEVBASE_OPEN_TERMINAL=0` または `devbase up --no-open-terminal`
154168

155169
### 実行コンテキスト別の挙動
156170

157171
| コンテキスト | 挙動 |
158172
|------|------|
159173
| ローカル端末(Mac/Linux) | ローカル VS Code が開く |
160174
| WSL 端末 | Windows 側 VS Code が開く(`code` ラッパ経由) |
161-
| VS Code の Remote-SSH 統合ターミナル | **クライアント側(手元)の VS Code** が開く(`code` シムが委譲) |
175+
| VS Code の Remote-SSH 統合ターミナル(同一ホストの Docker) | **クライアント側(手元)の VS Code** が開く(`code` シムが委譲) |
176+
| VS Code の Remote-SSH 統合ターミナル(**跨ホスト**: ssh 先の Docker にコンテナ) | `DEVBASE_EDITOR_SSH_HOST` 設定時にネスト URI で開く(下記「跨ホスト」参照) |
162177
| 手元から素の SSH(VS Code 外)で接続中 | クライアントへ自動で開く公式手段が無いため、手元で実行する `code --folder-uri ...` コマンドを提示 |
163178
| CI / 非対話(非 TTY) / `code` 不在 | 理由を表示してスキップ(`up` 自体は成功) |
164179

165-
> SSH 越しに「手元の VS Code」を自動で開きたい場合は、手元の VS Code から **Remote-SSH で接続した統合ターミナル内**`devbase up` を実行してください。そのターミナルの `code` はクライアント側 VS Code に委譲するため、リモートホスト上のコンテナへ接続した窓が手元に開きます。
180+
#### 跨ホスト(Windows VS Code → Remote-SSH → Mac のコンテナ)
181+
182+
手元(例 Windows)の VS Code から Remote-SSH で別ホスト(例 Mac)へ入り、その統合ターミナルで `devbase up` を実行する構成では、コンテナは **ssh 先(Mac)の Docker** 上にあります。このとき `code` の開く要求はクライアント(Windows)へ委譲されるため、フラットな attach URI のままだと **クライアント側の Docker** を見に行きコンテナが見つかりません(「コンテナーにアタッチできません。すでに存在しません」)。
183+
184+
これを解決するには、ネスト URI `vscode-remote://attached-container+<hex>@ssh-remote+<host>/work/...` を使い、docker ルックアップを ssh 先(コンテナのある Mac)で行わせます。`<host>`**手元 `~/.ssh/config``Host` 別名**(例 `mac2`)で、これは「今の VS Code 接続の authority ラベル」と完全一致する必要があります(ネスト attach は新規 ssh 接続を張らず既存接続を再利用するため。IP や `user@IP` は "Parent authority found without ExecServer" で不可)。
185+
186+
このラベルは VS Code が ssh 先の端末 env に渡さない(`SSH_CONNECTION` は IP のみ)ものの、**devbase は ssh 先(Mac)の VS Code 系サーバーディレクトリ(`~/.vscode-server` / `~/.cursor-server` / `~/.vscode-server-insiders` 等)の File History から自動検出**します(`DEVBASE_EDITOR` で cursor 等を使う場合も横断)。よって**通常は設定不要**です。docker context は `docker context show` から自動取得します。
187+
188+
自動検出が外れる場合(複数 ssh-remote ホストを使い分けている等)のみ明示します:
189+
190+
```sh
191+
# $DEVBASE_ROOT/env など(全プロジェクト共通にしたい場合)
192+
DEVBASE_EDITOR_SSH_HOST=mac2
193+
# 必要なら docker context も明示
194+
# DEVBASE_EDITOR_DOCKER_CONTEXT=desktop-linux
195+
```
196+
197+
解決順は **`DEVBASE_EDITOR_SSH_HOST` 明示 → `~/.vscode-server` 自動検出 → フラット URI**
198+
199+
> 同一ホスト構成(手元 Mac/Linux で直接、または ssh 先の Docker にコンテナが無い場合)では ssh-remote ホストは付かず、従来どおりフラット URI で開きます。
166200
167201
## ソースファイル変更検出
168202

issues/PLAN31_3_up-open-editor.md

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,24 +41,44 @@ vscode-remote://attached-container+<hex>/work/$GIT_REPO
4141
`<hex>`**`{"containerName":"/<実コンテナ名>"}` を UTF-8 hex 化**した文字列。
4242
(単純な名前の hex ではない点に注意。Docker 内部のコンテナ名は先頭 `/` 付き。)
4343

44-
### 2.3 ネスト authority は公式未サポート
44+
### 2.3 ネスト authority**実機で動作することを確認・当初想定を訂正**
4545

46-
`ssh-remote+<host>``attached-container+...` を 1 本の URI に合成する記法は
47-
**存在しない**(microsoft/vscode#242489 は *Closed as not planned*)。
48-
→ 「リモートホスト上のコンテナ」を単発 `code` で直接指定する手段は無い。
46+
> ⚠️ 訂正(2026-06-13 実装時の実機検証)。当初は「合成記法は存在しない
47+
> (microsoft/vscode#242489 *not planned*)」と記載していたが、**誤り**だった。
48+
49+
`attached-container+<hex>@ssh-remote+<host>` という**ネスト authority は実際に
50+
サポートされており動作する**(VS Code 1.124.2 / Dev Containers 0.459.1 で確認)。
51+
正常動作中の窓の resource URI を採取したところ:
52+
53+
```
54+
vscode-remote://attached-container+<hex>@ssh-remote+mac2/work/...
55+
hex = {"containerName":"/<name>","settings":{"context":"desktop-linux"}}
56+
```
57+
58+
`@ssh-remote+<host>` を付けると docker ルックアップが **ssh 先(コンテナのある
59+
ホスト)** で行われるため、跨ホスト(手元 Windows VS Code → ssh → Mac のコンテナ)
60+
でも単発 `code --folder-uri` で直接アタッチできる。`settings.context` は ssh 先で
61+
使う docker context を指定する。
4962

5063
### 2.4 結論(実行コンテキスト別マトリクス)
5164

5265
| コンテキスト | 自動オープン | 機構 / 根拠 |
5366
|---|---|---|
5467
| Mac/Linux ローカル端末 || ローカル `code` が attach URI を解決 |
5568
| WSL 端末 | ✓ (Windows VS Code) | `code` ラッパ→`code.exe`、Docker Desktop のコンテナへ attach |
56-
| VS Code **Remote-SSH 統合端末**(リモート=Mac) | ✓ (クライアント側) | `code` シム + `VSCODE_IPC_HOOK_CLI`。シムは既にクライアントへ接続済みなのでネスト URI 不要で attached-container を解決し、**クライアント(Windows)に窓が開く** |
57-
| plain SSH(WSL→ssh→Mac 等、VS Code 外) | ✗ → コマンド表示 | IPC hook 無し。公式にクライアントへ push 不可(§2.3)。手元で叩く `code` コマンドを提示するのが上限 |
69+
| VS Code **Remote-SSH 統合端末**(リモート=Mac・**同一ホストの Docker**| ✓ (クライアント側) | `code` シムが委譲。同一ホストの Docker にコンテナがある場合はフラット URI で解決 |
70+
| VS Code **Remote-SSH 統合端末****跨ホスト**: ssh 先 Mac の Docker にコンテナ) | ✓ (host 自動検出) | フラット URI だとクライアント(Windows)の Docker を見て失敗。**ネスト URI `@ssh-remote+<host>`(§2.3)で ssh 先の Docker を解決**`<host>`**ssh 先 `~/.vscode-server` の File History から自動検出**`DEVBASE_EDITOR_SSH_HOST` で上書き可)。IP/`user@IP` は既存 ExecServer 不一致で不可、別名一致が必須 |
71+
| plain SSH(WSL→ssh→Mac 等、VS Code 外) | ✗ → コマンド表示 | IPC hook 無し。手元で叩く `code` コマンドを提示するのが上限 |
5872
| CI / 非TTY / `code` 不在 | ✗ → info スキップ | エディタ起動の前提を満たさない |
5973

60-
→ ユーザ理想チェーンは **「手元 VS Code で Remote-SSH→Mac に入った統合ターミナルで
61-
`devbase up`」の場合に自動成立**。plain ssh の場合は正直にコマンド提示で degrade する。
74+
→ 跨ホスト(手元 Windows VS Code → Remote-SSH→Mac で `devbase up`、コンテナは Mac の
75+
Docker)が最頻ユースケース。ssh ホスト名(クライアント `~/.ssh/config` の Host 別名)は
76+
VS Code が ssh 先端末 env に渡さない(`SSH_CONNECTION` は IP のみ)が、**ssh 先 Mac の
77+
`~/.vscode-server` の File History(resource URI の `ssh-remote%2B<host>`)から自動検出**
78+
できるため**通常は設定不要で自動成立**する。検出が外れる場合のみ `DEVBASE_EDITOR_SSH_HOST`
79+
で上書き。IP/`user@IP` は「ネスト attach は新規 ssh 接続を張らず既存 ExecServer の authority
80+
と一致が必須」のため不可(実機: "Parent authority found without ExecServer")。
81+
plain ssh はコマンド提示で degrade。
6282

6383
## 3. 既存コード調査結果
6484

@@ -156,12 +176,22 @@ env 解釈は既存 `_parse_env_assignment`(`container.py:121`)に合わせ
156176
`--no-open`/`DEVBASE_OPEN_EDITOR=0` で呼ばれないこと
157177
- 既存 706 passed を維持
158178

159-
## 8. リスク・未確定
160-
161-
- **plain SSH では自動オープン不可**(§2.3 公式未サポート)。コマンド提示で degrade。
162-
この制約は README に明記する
163-
- VS Code Remote-SSH 統合端末でのクライアント側 attach は実機検証が必要
164-
`/ndf:investigation-rules`: 実機未検証の挙動は「推定」と明示)
179+
## 8. リスク・未確定(実機検証で更新)
180+
181+
- ~~VS Code Remote-SSH 統合端末でのクライアント側 attach は実機検証が必要~~
182+
**検証済み(2026-06-13)**。跨ホストではフラット URI だと失敗し、ネスト URI
183+
`@ssh-remote+<host>` + `settings.context` で成立することを確認(§2.3/§2.4 を訂正)。
184+
- ssh ホスト名は env には来ないが **`~/.vscode-server` の File History から自動検出**する
185+
ようにした(実機: ホストは `ssh-remote%2Bmac2` の 1 種のみで一意に取れた)。検出は VS Code
186+
内部データ依存のヒューリスティック(multi-host / バージョン差で外し得る)で、最新 mtime の
187+
entries.json を優先し、外れる場合は `DEVBASE_EDITOR_SSH_HOST` 明示・最終的にフラット URI へ degrade。
188+
- IP / `user@IP` でのネスト attach は不可(既存 Remote-SSH 接続=ExecServer の authority ラベルと
189+
完全一致が必須。新規 ssh 接続は張らない)。実機で "Parent authority found without ExecServer" を確認。
190+
- **plain SSH(VS Code 外)では自動オープン不可**。コマンド提示で degrade(変更なし)。
191+
- 統合ターミナル自動表示は `.vscode/tasks.json`(folderOpen) 配置で実現。VS Code 公式に
192+
起動時ターミナル設定は無く(`hideOnStartup` は復元セッションの表示制御のみ)folderOpen
193+
が唯一。自動実行は Workspace Trust と `task.allowAutomaticTasks`(共に user スコープ専用・
194+
devbase 制御外)に依存し、初回のみ承認クリックが要る。
165195
- `code` ラッパの非ブロッキング起動が `up` プロセス終了をブロックしないこと確認
166196

167197
## 9. 参考(一次情報)

lib/devbase/cli.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,13 @@ def _add_open_args(parser):
112112
parser.add_argument('--open-index', dest='open_index', type=int, default=None,
113113
metavar='N',
114114
help='Container index to open (default: 1)')
115+
parser.add_argument('--open-terminal', dest='open_terminal', action='store_true',
116+
default=None,
117+
help='Place .vscode/tasks.json so the integrated terminal '
118+
'auto-opens on folder open (overrides DEVBASE_OPEN_TERMINAL)')
119+
parser.add_argument('--no-open-terminal', dest='open_terminal', action='store_false',
120+
help='Do not place the folderOpen terminal tasks.json '
121+
'(overrides DEVBASE_OPEN_TERMINAL)')
115122
return parser
116123

117124

0 commit comments

Comments
 (0)