Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions docs/0-requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ liplus-desktop の `stream_parser.rs` および `spawn_stream_pty` / `spawn_stre
- 参加者パネル(一つのリスト、種別ごとのグループと件数、参加者ごとの色、オフラインの薄い表示、部屋ソケット、セッションの生死と終了コード、接続方法・起動コマンド・作業ディレクトリ・開始時刻・ウィンドウ)
- アカウントのモーダル(作成・編集・削除、決定と取消、2 クリックの削除、走る行の表示)
- アカウントごとの端末(リストの行で選ぶ、行からの終了、切り替えで残るスクロールバック)
- 行のライフサイクル操作の記号表示(開始 ▶️ / 終了 ❌ / 編集 ⚙️、語は `aria-label` と `title`、幅を固定した列)と、終了の確認ダイアログ(webview 内の `<dialog>`、取消に焦点、Escape は取消)
- 診断面(アカウントごとの CLI の端末表示と入力)
- Windows CI(`npm ci` と Rust コンパイル確認)、Release 公開時の CD

Expand All @@ -275,6 +276,7 @@ liplus-desktop の `stream_parser.rs` および `spawn_stream_pty` / `spawn_stre
- アカウントごとの端末と終了の実機確認。2 セッションでの出力の分離、入力の宛先、切り替え後のスクロールバック、終了後の席の解放と再起動はいずれも実装済みであり、CI の型検査は通っているが、実機での操作は未確認である。
- 一つのリストとアカウントのモーダルの実機確認。種別ごとのグループと件数、オフラインの表示、行からの終了、モーダルの決定と取消、本人のアカウントへの移行はいずれも実装済みで、CI の型検査とテストは通っているが、実機での操作は未確認である。`hello` の `account_id` が実際の部屋で名簿へ届くところも未計測である。
- 会話面の文字サイズのうち、ヘッダのピッカー、再起動後の保持、上下限の実機確認。いずれも実装済みで CI の型検査は通っているが、実機での操作は未確認である。キー操作(`Ctrl` + `=` / `-` / `0`)と、効く範囲が会話面に留まること(参加者パネル・診断面・端末・入力欄が動かないこと)は 2026-08-24 の実機観察で確認済みである。後者が webview 自身のズームも閉じている——キーを受ければ寸法は無条件に動くため、動いたこと自体は既定動作を止められた証拠にならないが、会話面以外が一緒に動かなかった以上、webview のズームは走っていない。
- 行の記号表示と終了の確認ダイアログの実機確認。三つの記号が Windows のフォントで揃って出ること、幅を固定した列で本人の行の名前が出ること、ダイアログの取消・終了・Escape はいずれも実装済みで CI の型検査は通っているが、実機での操作は未確認である。
- 会話ログの永続化と観測 UI
- plugin としての allowlist 掲載(配布の第二段階)

Expand Down Expand Up @@ -308,17 +310,19 @@ liplus-desktop の `stream_parser.rs` および `spawn_stream_pty` / `spawn_stre

**行の操作は名前の後ろの二列である。一列目がライフサイクル、二列目が編集。** 列は行の状態で動かない。以前の並びは「編集」「終了」であり、終了が稼働中の行にしか出ないため、未起動の行では編集が左へずれていた。

- 一列目 = 「開始」または「終了」。種別 `ai` のアカウントの行にだけ出る。
- 二列目 = 「編集」。アカウントを持つ行には常に出る。
- 一列目 = 開始 ▶️ または終了 ❌。種別 `ai` のアカウントの行にだけ出る。
- 二列目 = 編集 ⚙️。アカウントを持つ行には常に出る。
- **列は中身の有無に依らず幅を持つ。** ライフサイクルを持たない行——種別 `user`、および端末の操作を持たない行——も列を閉じない。閉じれば編集がその行だけ左へ寄る。

armed の「本当に終了」は「終了」より広く、その幅は名前の側へ伸びる。編集の位置は動かない。ライフサイクルの列を armed の幅に固定する形は採らない——パネルは 16.5rem しかなく、実測では本人の行の名前(「マスター」+「(あなた)」)が出なくなる。四秒間の一行のために、リスト全行の名前の幅を払うことになる。
**行の操作は記号で表示する。** 三つとも語ではなく記号であり、語は `aria-label` と `title` に入る。記号は読み上げに耐えず、名前ではない——何をする操作かを言うのは label の側である。

**記号の列は幅を固定する。** 絵文字の送り幅はフォントが決めるものであり、そのフォントはホストが選ぶ。字面から幅を取れば同じ画面が機械ごとに違う形になる。ボタンの寸法を固定し、記号はその中で中央に置く。名前の列は残りを全て取る——パネルは 16.5rem しかなく、実測で本人の行(「マスター」+「(あなた)」)が出なくなるのが、ライフサイクルの列を広げない理由であった(#71 以前は終了が武装時に広がるため、この列は下限だけを持っていた)。

端末を持たないアカウントに端末の操作は出ない。未起動のアカウントに出せる端末の操作は無い(#57 の条件を維持)。開始はこれに含まれない——端末の操作ではなく、端末を作る操作である。

**種別 `user` の行にライフサイクルは無い。** 人間は起動されるものではなく、`start_session` が既に拒否している(上記「アカウント」)。列は空のまま残り、その行の編集は他の行と同じ位置に並ぶ。

**開始は 2 段階にしない。** 終了が二度押しなのは取り消せないためである(下記「診断面」)。開始は取り消せる——間違えて始めたセッションは、その場所を引き継ぐ終了が終わらせる。取り消せる操作に arm を付けると、undo が効く失敗を防ぐために全ての意図的な操作が二度押しになる
**開始は確認を挟まない。** 終了が確認を取るのは取り消せないためである(下記「診断面」)。開始は取り消せる——間違えて始めたセッションは、その場所を引き継ぐ終了が終わらせる。取り消せる操作に確認を付けると、undo が効く失敗を防ぐために全ての意図的な操作が二段階になる

**起動中と起動失敗は行が読める。** 押した直後から起動が返るまで、その行の開始は押せなくなる。状態の語は名前の隣の note に入る——「未起動」「終了」と同じ場所であり、note は状態を、ボタンは行為を言う。

Expand Down Expand Up @@ -401,9 +405,13 @@ armed の「本当に終了」は「終了」より広く、その幅は名前

**終了はアカウントごとに行う。** 参加者のリストのその行から、そのアカウントのセッションを終了する。席の解放は別途要らない——`RoomSeats` は稼働の有無を PTY へ問うため、終了すれば席は空き、そのまま再起動できる(上記「アカウント」)。

終了は取り消せない操作であり、表示を切り替えるだけの操作の隣に並ぶ。無地のクリック一つでは実行しない。一度目のクリックは武装するだけで、ボタンの文言と見た目が変わり、数秒で武装は解ける。二度目のクリックが実行する。
終了は取り消せない操作であり、表示を切り替えるだけの操作の隣に並ぶ。無地のクリック一つでは実行しない。クリックは確認のダイアログを開き、そこで答えるまで何も終わらない。ダイアログは「取消」と「終了」の二つの答えを持ち、焦点は「取消」にある。Escape は取消と同じ答えである——開いたダイアログの上で当てずっぽうに押した鍵が、何も変えない側へ倒れる。

**`window.confirm` を使わない。** ホストが答えなかった場合の失敗の向きがどちらも誤りであるためである。答えを待たない実装ではボタンが黙って何もしない側へ倒れ、答えを既定で肯定と読む実装では一度のクリックで落ちる。`window.confirm` はこのアプリのどこにも残っていない。

**確認は webview の中の `<dialog>` で出す。** これは上とは別の判断である。`window.confirm` を断るのはホストに答えを預けないためであり、確認をどの面へ出すかはそこから決まらない。#71 以前は確認をボタン自身に置いていた——一度目のクリックが武装し、ボタンの文言と見た目が変わり、二度目が実行する形である。ダイアログへ移したことで「どちらの状態にいるかをボタン自身が表示する」形は手放した(#71)。ホスト依存の失敗の向きは、この `<dialog>` がアプリの中にあるため、そもそも起こらない。

`window.confirm` を使わないのは、ホストが答えなかった場合の失敗の向きがどちらも誤りであるためである。答えを待たない実装ではボタンが黙って何もしない側へ倒れ、答えを既定で肯定と読む実装では一度のクリックで落ちる。画面側で武装状態を持てばどちらも起きず、どちらの状態にいるかをボタン自身が表示する。アカウントの削除も同じ形を取る(下記「アカウント」)。`window.confirm` はこのアプリのどこにも残っていない
アカウントの削除は二度押しのまま残っている(下記「アカウント」)。同じ形へ揃えるかは #71 では決めず、#72 で扱う

端末はセッションへの入力路でもある。キー入力はそのまま PTY へ渡り、ウィンドウのリサイズは CLI 側へ伝わる。

Expand Down Expand Up @@ -471,7 +479,7 @@ armed の「本当に終了」は「終了」より広く、その幅は名前

これは形の移動ではない。以前は各欄が `change` で保存されており、`+` を押した瞬間にアカウントが実在し、以後はその場で直していく形だった。決定も取消も無かった。モーダルへ移すこと自体はこれを直さない——モーダルの中で `change` 保存を続ければ同じである。直しているのは保存の時点である。

削除はモーダルの中にあり、終了と同じ 2 クリックを取る。一度目は武装するだけで、二度目が実行する。稼働中のアカウントと、この画面の本人のアカウントは削除を拒否する。
削除はモーダルの中にあり、2 クリックを取る。一度目は武装するだけで、二度目が実行する。稼働中のアカウントと、この画面の本人のアカウントは削除を拒否する。終了も #71 まではこの形であったが、確認のダイアログへ移った(上記「診断面」)。削除を揃えるかは #72 で扱う

#### ランチャ行は無い

Expand Down
35 changes: 31 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -204,17 +204,44 @@ <h2 id="account-dialog-title">アカウント</h2>
<p id="dialog-error" class="error" role="alert"></p>

<menu class="actions">
<!-- Two clicks, like 終了 in the list and for the same reason: this
one cannot be taken back and it sits beside two that can. Not
`window.confirm`, whose two failure directions are both wrong
here (#57). -->
<!-- Two clicks: this one cannot be taken back and it sits beside
two that can. Not `window.confirm`, whose two failure
directions are both wrong here (#57). 終了 in the list asked
the same question in this same shape until #71 moved it into a
dialog of its own; whether this one follows is #72. -->
<button id="dialog-delete" type="button" class="delete">削除</button>
<span class="spacer"></span>
<button id="dialog-cancel" type="button">取消</button>
<button id="dialog-commit" type="submit" value="commit">決定</button>
</menu>
</form>
</dialog>

<!-- The 終了 confirmation. One click on the row opens this, and the
question is answered here rather than on the button itself (#71).

Its own `<dialog>`, not the account form above. That one is a form
for editing an account; a single element holding both would have to
decide which of its two faces to open in every time it opens.

In the webview, and not `window.confirm`: a host that answers
nothing fails in one of two directions and both are wrong here — the
button goes silently dead, or a default-yes ends the session on one
click (#57). A `<dialog>` on this side has neither failure.

取消 holds the focus, so a stray Enter or Space on an opened dialog
answers the safe way. Escape closes it, which is the same answer. -->
<dialog id="end-dialog" aria-labelledby="end-dialog-title">
<div class="confirm">
<h2 id="end-dialog-title">セッションの終了</h2>
<p id="end-dialog-message"></p>
<menu class="actions">
<span class="spacer"></span>
<button id="end-cancel" type="button" autofocus>取消</button>
<button id="end-commit" type="button" class="danger">終了</button>
</menu>
</div>
</dialog>
</div>
</body>
</html>
Loading