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
18 changes: 10 additions & 8 deletions docs/0-requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,9 @@ logs/{部屋名}/{トピック}.jsonl そのトピックの発言、追記の

**起動時は新しいトピックを開く。** 最後のトピックの続きを自動では開かない。部屋は毎回空から始まり、過去は一覧から選んで開く。#48 の「起動時の部屋は新規である」は既定として残り、変わったのは「消えた先に読みに行ける場所があるか」ではなく「そこから戻せるか」になった点である。

**新規トピックは遅延生成する。** 起動のたびに索引へ空のトピックを書くと、何も話さずに閉じた回が一覧に残り続ける。起動時のトピックは「まだ索引に無い現在のトピック」として部屋が持ち、最初の投稿が着いた時点で索引とファイルができる。画面はそれを一覧に無くても現在のトピックとして描く——毎回の起動直後には、部屋に在って一覧に無いトピックがちょうど一つ在る。
**新規トピックは遅延生成する。** 起動のたびに索引へ空のトピックを書くと、何も話さずに閉じた回が一覧に残り続ける。起動時のトピックは「まだ索引に無い現在のトピック」として部屋が持ち、最初の投稿が着いた時点で索引とファイルができる。毎回の起動直後には、部屋に在って一覧に無いトピックがちょうど一つ在る。画面はそれを行としては描かず、一覧の先頭に固定で在る「新規」がその場所を言う(#125、決定1。下記「トピックの一覧」)。

**発言が無くても、席がそこで始まれば索引に入る。** セッションを始めるのは意図的な行為であり、その id が起動を越えて残らなければ resume の意味が無い。そのため席の記録は遅延生成を待たずにトピックを実体化する。この経路には題の元になる発言が無いため、索引には題の無い項目が残る——起動して一言も発しないまま終えた回がこれに当たる(#125)。実体化そのものは外さない。直すのは、その行の見せ方と消し方である。

**復帰の手段は二段構えである。** ネイティブ resume を持つ CLI はそれを使い、持たない CLI にはサイドカー経由の読み出しを与える。履歴をテキストで PTY へ流し込む力業は採らない。理由は三つある。トピックが伸びるほど毎回の起動が高くつく(参加者が要るかどうかに関わらず全部渡すため)。CLI は流し込まれた文をユーザ入力として読むため、「自分が言ったこと」と「言ったと聞かされたこと」を区別できない。そして端末ペインにその塊が見える——あのペインはセッションのものである、というのが `RESUMED_NOTICE` の設計思想である(#84)。読み出しは力業を push でやる代わりに pull にしたものであり、これが在れば力業は要らない。

Expand Down Expand Up @@ -297,7 +299,7 @@ logs/{部屋名}/{トピック}.jsonl そのトピックの発言、追記の

**確認ダイアログはセッションが止まることを述べる。** ログの削除だけを述べていると、止まったセッションが不意打ちになる。走っているセッションが無いときは述べない——そのときは事実ではない。

**空タイトルの行には削除ボタンを出さない(決定5)。** 一覧に出る行すべてにボタンを付ける形は取らない。そう読まれる行は二つあり、どちらもここから消す理由が無い——まだ何も言われていない現在のトピック(索引に無く、消すものが無い)と、索引に行があってファイルが無いトピック(#117)である。
**題の無い行も一覧から消せる(#125、決定2)。** #119 決定5 はここに削除ボタンを出さないと決めていた。理由は「そう読まれる二つの行は、どちらもここから消す理由が無い」であり、その片方——まだ何も言われていない現在のトピック——は決定1 が一覧から外した。一覧に残る題の無い行は、索引に在る行だけになる:ファイルの無い孤児(#117)と、発言が無いまま席の記録で実体化した行(上記)である。どちらも消したい行であり、消す手段が無いまま起動のたびに増えていた。決定5 は覆すのではなく、前提が外れる

**開いているトピックを消したら、新しいトピックへ移る(決定6、AI 判断)。** 消した直後の状態は起動直後の状態と同じもの——部屋は空で、まだ索引に無いトピックに居る——であり、アプリが既に持っている状態を使い回す。「次のトピックへ移る」は取らない:頼んでいない会話が開くうえ、要らないものを続けて消しているとき、次も消したいトピックへ落ちる。「開いているものは消せない」も取らない:見ているから要らないと判断したのに、一度離れてから消せというのは順序が逆である。

Expand Down Expand Up @@ -337,10 +339,10 @@ liplus-desktop の `stream_parser.rs` および `spawn_stream_pty` / `spawn_stre
- 拒否が返した発言の描画(画面。`message_id` による重複除去、返ってきた最新への透かしの前進、発言に載せて運ぶ宣言色、描いた分だけを述べる状況表示)
- 部屋のログ(`logs/main/{トピック}.jsonl` への追記、床の判定と同じロック内での書き込み、保存する五欄、`hue` と `own` を持ち込まない写像、追記の失敗の画面への通知、トピックを指定する読み出しコマンド、参加者への再配信をしないこと)
- トピック(手動の区切り、起動時の新規トピックと遅延生成、索引とディレクトリの照合、最初の発言からの命名とその場での変更、既存 `logs/main.jsonl` の移行、切り替え時の床の初期化)
- トピックの削除(行の `❌`、確認のダイアログ、ファイルと索引の項目の両方の削除、そのトピックで走っているセッションの終了、開いているトピックを消したときの新しいトピックへの移動、題の無い行にボタンを出さないこと
- トピックの削除(行の `❌`、確認のダイアログ、ファイルと索引の項目の両方の削除、そのトピックで走っているセッションの終了、開いているトピックを消したときの新しいトピックへの移動、題の無い行も消せること
- トピックの再開(アカウントの再開コマンド、`{session_id}` の置換、トピックへのセッション id の記録、再開できない席の新規着席)
- 参加者からの読み出し(サイドカーの `read_room_history`、`history` / `history_result` フレーム、pull のみ、ページと `before` の巻き戻し)
- トピックの一覧(会話面の左の列、新しい順、現在のトピックの描画、選択による部屋への読み戻し、参加者パネルと対の寸法、日付を含む時刻、名前から導く色)
- トピックの一覧(会話面の左の列、新しい順、先頭に固定の「新規」と索引に無い現在のトピックでのその選択状態、選択による部屋への読み戻し、参加者パネルと対の寸法、日付を含む時刻、名前から導く色)
- 参加者モデル(統一 `post` フレーム、発言者以外の全参加者への配送、接続同一性による自分の発言の抑止と名簿の同一性、人間を含む名簿)
- アカウント(作成・編集・削除、種別、名前と色と作業ディレクトリと起動オプション、リストでのオフライン表示、一つのアカウントは一つの部屋に一席まで、`config.json` からの移行)
- アカウントのキャラクター(output style の `name:` を持つ欄、起動時の `--settings` による選択、ファイルを書き出さない形、起動オプションの `--settings` との併記の拒否、宣言しないアカウントは既定のまま)
Expand Down Expand Up @@ -500,21 +502,21 @@ liplus-desktop の `stream_parser.rs` および `spawn_stream_pty` / `spawn_stre

**新しい順に並べる。** 会話の一覧が読まれるのはこちらの端からである。ファイルは起きた順(追記の順)を保ち、逆順は読みの判断であって保存の判断ではない。

**現在のトピックは一覧に無くても描く。** 遅延生成のため、毎回の起動直後には部屋に在って索引に無いトピックがちょうど一つ在る(上記「トピック」)。空白にすると、自分の部屋のトピックが自分の一覧に無い状態として読まれる
**索引に無い現在のトピックは行にしない(#125、決定1)。** 遅延生成のため、毎回の起動直後には部屋に在って索引に無いトピックがちょうど一つ在る(上記「トピック」)。以前はそれを一覧の先頭へ架空の行として足していた。その行は「名前の無いトピック」を名乗るが、実際には誰も始めていない会話であり、しかも索引に無い以上そこから消すものも持たない。代わりに「新規」が本当のこと——新しいトピックが始まる場所——を言う。**部屋がそのトピックに居る間、「新規」は選択状態で描く(AI 判断4)。** そうしないと、自分の居る場所が一覧のどこにも無い状態になり、架空の行が避けていた問題が形を変えて戻る

**一件が持つのは名前と作成時刻である。** 名前は一行で切り、溢れは省略する——一覧は左端を縦に読むものであり、三行に折り返した題は次の行の位置を前の行の長さで決めることになる。まだ何も言われていないトピックは「未命名」と出す空白にすると、読み出しに失敗した行と見分けが付かない。
**一件が持つのは名前と作成時刻である。** 名前は一行で切り、溢れは省略する——一覧は左端を縦に読むものであり、三行に折り返した題は次の行の位置を前の行の長さで決めることになる。**題の無い行は「未記入」と出す(#125、AI 判断3)。** 空白にすると、読み出しに失敗した行と見分けが付かない。確認ダイアログと削除後の状況行も同じ語を差し込む——差し込まなければ「トピック「」を削除します。」と出る。名前を直すときの欄は空のままである。「未記入」は空の題について画面が言う語であって、題ではない

**名前はその場で直す。** 行をダブルクリックすると入力欄になり、Enter が決定、Escape とフォーカス喪失が取消である。生成された題は編集できる欄に置かれた出発点であり、アカウントの名前と同じものである。

**行から消せる(#119)。** 行の右端に `❌` を置く。押すと確認のダイアログが開き、そこで答える——参加者パネルの `終了` と同じ記号・同じ危険色であり、同じ種類の操作だからである:その行で唯一取り消せない操作が、面を切り替えるだけの操作の隣に在る。行そのものは flex のトラックになり、`.pick` が残りの幅を取る。長い題は `❌` を押し出さずに省略される。

**題の無い行には出さない(決定5)。** 詳細と、そう読まれる二つの行については上記「トピック」に書いた。
**題の無い行にも出す(#125、決定2)。** 一覧に出る行はすべて索引の行になったため、どの行も消せる。#119 決定5 とその前提が外れた経緯は上記「トピック」に書いた。

**ダイアログは `#end-dialog` / `#quit-dialog` と同じ作法である。** webview 内の `<dialog>`、取消に焦点、Escape は取消。要素は別に持つ——一つの要素が三つの問いを持てば、開くたびにどの顔で開くかを決めることになり、答えは訊いた側へ帰る道を探すことになる。CSS は同じ規則で描く。形は一つであり、二つ目の写しは一つ目からずれる。

**ダイアログは二行を持つ。** 一行目はトピック名と、何が消えるか。二行目は止まるセッションの名前であり、走っていなければ出さない(上記「トピック」、決定4から導かれること)。二行目は一行目の限定ではなく、失われる二つ目のものであるため、別の文にする。

**「新規」は一覧の見出しの隣に置く。** 作る操作はそれが現れるリストの隣に置く——参加者パネルの「+」と同じ形である(#59)。
**「新規」は一覧の先頭に固定で置く(#125、決定1)。** 作る操作はそれが現れるリストの隣に置く(#59)という判断は残り、置き場が見出しの隣から一覧の先頭へ移った。一覧の行と同じ形で描き、選択状態も行と同じ形である——そこは行が立つ場所であり、行と同じように選ばれるからである。固定であるとは、索引から描き直す一覧の外に在るということである:索引の行ではないため、索引が空でも在る

**参加者パネルと対にする。** 幅(16.5rem)と地色を揃え、枠は会話面に向く側に置く(左は `border-right`、右は `border-left`)。部屋を挟む二つの面が別々の寸法を持てば、揃っていないこと自体が読まれる。中の部品は同じ語彙(`.panel-head` / `.panel-title` / `.empty`)を使う。選択中の行は、参加者パネルの選択中の行と同じく枠のある窓の地の箱である(#75)。

Expand Down
15 changes: 12 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,19 @@
<aside id="history" aria-label="トピック">
<div class="panel-head">
<h2 class="panel-title">トピック</h2>
<!-- Making one belongs next to the list it appears in, which is
where + sits on the panel opposite (#59). -->
<button id="topic-new" type="button" title="新しいトピックを始める">新規</button>
</div>
<!-- 新規, at the head of the list rather than beside the heading
(#125, 決定1). It is fixed: it stands outside the <ol> because the
list is redrawn from the index and this is not one of the index's
rows.

It is also what the top of the list used to hold. A launch opens a
topic the index does not carry yet (#115), and the list drew that
topic as a row of its own — a row naming a conversation nobody had
started, which is the thing 新規 says truthfully. Drawn as picked
while the room is in such a topic (#125, AI 判断4), so the place
the room is in is somewhere on this list. -->
<button id="topic-new" type="button" class="new" title="新しいトピックを始める">新規</button>
<!-- Seeded, because the index is read after the frame is up: an empty
list in that gap would say "there are no topics" at the one moment
nothing has been asked yet. -->
Expand Down
Loading