diff --git a/.yoi/tickets/00001KVWPVHFJ/artifacts/.gitkeep b/.yoi/tickets/00001KVWPVHFJ/artifacts/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/.yoi/tickets/00001KVWPVHFJ/item.md b/.yoi/tickets/00001KVWPVHFJ/item.md new file mode 100644 index 00000000..f1f9f541 --- /dev/null +++ b/.yoi/tickets/00001KVWPVHFJ/item.md @@ -0,0 +1,148 @@ +--- +title: 'Pod/session storage cleanup CLI を追加する' +state: 'ready' +created_at: '2026-06-24T11:39:41Z' +updated_at: '2026-06-24T11:39:41Z' +assignee: null +readiness: 'implementation_ready' +risk_flags: ['pod-lifecycle', 'persistence', 'destructive-operation', 'cli-ux', 'session-history', 'authority-boundary'] +--- + +## User claims / request snapshot + +- Pod 名を指定して Pod を消去する CLI コマンドを実装する。 +- Pod から参照されていないセッションを削除するコマンドを用意する。 +- 古い Pod / セッションを削除するコマンドを用意する。 +- コマンド名は以下で合意済み: + - `yoi pod delete [--force] [--dry-run]` + - `yoi pod prune [--older-than ] [--force] [--dry-run]` + - `yoi session prune --unreferenced [--older-than ] [--force] [--dry-run]` + +## Confirmed facts / sources + +- 関連 closed Ticket `00001KTJ7MACG` は fresh-start 専用 UX を実装しない方針で closed 済み。ただし resolution で、Pod 名を明示的に空ける archive/delete と storage cleanup/prune commands は必要になれば別 Ticket として扱う、と記録されている。 +- `crates/pod-store/src/lib.rs` では Pod metadata authority は `{data_dir}/pods/{pod_name}/metadata.json` であり、`PodMetadataStore::delete_by_name` / `FsPodStore::delete_by_name` が既に存在する。 +- `crates/session-store/src/fs_store.rs` / `crates/session-store/src/lib.rs` では session log は `{sessions_root}/{session_id}/{segment_id}.jsonl` と trace jsonl で、`FsStore` は `list_sessions`, `list_segments`, `lookup_session_of` を持つ。確認範囲では削除用 public API は見当たらない。 +- `crates/yoi/src/main.rs` では `yoi pod ...` は現在 `pod::entrypoint::run_cli_from("yoi pod", args)` に委譲されており、Pod runtime spawn/restore 用 entrypoint として使われている。 +- `crates/yoi/src/session_cli.rs` では `yoi session ...` は現在 `analyze --json` のみ。 +- `crates/pod/src/entrypoint.rs` では `--pod ` は name-keyed Pod state があれば restore、なければ fresh create する。sessions dir は `--store` または `manifest::paths::sessions_dir()`、Pod store は `manifest::paths::data_dir()/pods` から解決している。 +- duplicate / related search では、直接同じ目的の open Ticket は見つからなかった。関連 closed Ticket は `00001KTJ7MACG`, `00001KSTRGFX0`, `00001KSXXRRC8`。 + +## Unverified hypotheses + +- live Pod protection は runtime socket / Pod registry / discovery layer と組み合わせて判定できる可能性が高いが、実装時に正確な helper/API を確認する必要がある。 +- orphan session 判定は「active Pod metadata から参照されない SessionId」を基本にできそうだが、fork/segment lineage、trace file、古い closed metadata、manual session restore use case をどこまで保存対象にするかは実装時に注意する必要がある。 +- `yoi pod delete` を runtime entrypoint に足すより、product CLI 側で `yoi pod delete` を捕捉するほうが安全かもしれないが、既存 `yoi pod` の意味と衝突しない設計確認が必要。 + +## Undecided points / open questions + +- Blocking open question は現時点ではない。 +- 実装中に CLI boundary が既存 `yoi pod` runtime entrypoint と衝突する場合は、Orchestrator / maintainer に escalate する。 +- orphan session 判定で session lineage semantics や manual restore use case への影響が大きい場合は、削除範囲を安全側に狭めるか follow-up に分ける。 + +## Background + +以前の fresh-start Ticket では、restore bypass 専用 path を作らず、Pod 名の衝突解消や古い履歴蓄積は Pod/session storage cleanup commands として扱う方針になった。現在も Pod metadata と session logs は durable authority が分かれており、手で `~/.yoi/pods` や `~/.yoi/sessions` を消すのは危険で discoverable ではない。公式 CLI と safety rails が必要。 + +## Requirements + +- Pod 名を指定して、name-keyed Pod metadata を削除できる CLI を追加する。 + - コマンド名は `yoi pod delete [--force] [--dry-run]` とする。 + - 削除後、同じ Pod 名の通常起動は既存の `missing -> spawn fresh` path に乗る。 + - session logs/history は `pod delete` では削除しない。 +- live/reachable Pod の metadata 削除は拒否する。 + - 実装が live 判定できない場合は安全側に倒し、削除せず診断する。 + - live Pod を止める操作や stop semantics の変更はこの Ticket の主目的にしない。 +- orphan session cleanup CLI を追加する。 + - コマンド名は `yoi session prune --unreferenced [--older-than ] [--force] [--dry-run]` とする。 + - Pod metadata の active pointer から参照されていない session/segment を候補として列挙できる。 + - 実削除は `--force` が必要。 + - 初期実装は dry-run / report を重視し、削除対象と根拠を表示する。 +- old Pod / old session cleanup CLI を追加する。 + - Pod 側は `yoi pod prune [--older-than ] [--force] [--dry-run]` とする。 + - 「古い」の判定は暗黙 default を持たせず、`--older-than ` のような明示 threshold を要求する。 + - threshold 未指定で「古い」と判断して削除しない。 +- destructive operation は共通で: + - default は dry-run または削除拒否にする。 + - 実削除には `--force` を要求する。 + - 削除対象、保持対象、拒否理由を bounded に表示する。 +- product CLI help/docs を更新し、manual data-dir surgery ではなく公式 command を案内する。 +- `yoi pod` が既存 runtime entrypoint として使われている境界を壊さない。 + - management subcommands を product CLI 側で捕捉するか、runtime entrypoint 側に安全に追加するかは実装判断でよいが、既存 spawn/restore options と互換的に動くこと。 + +## Acceptance criteria + +- `yoi pod delete ` 相当の公式 CLI で stopped/restorable Pod metadata を削除できる。 +- 削除後、同名 Pod 起動は existing metadata restore ではなく fresh create path になる。 +- live/reachable Pod に対する delete/prune は拒否され、理由が表示される。 +- `pod delete` は session logs を削除しない。 +- Pod metadata から参照されていない session を dry-run で列挙でき、`--force` 指定時だけ削除できる。 +- 古い Pod / session cleanup は `--older-than` 等の明示条件なしでは削除しない。 +- prune/delete の出力は、削除予定/削除済み/保持/拒否をユーザーが確認できる。 +- focused tests が以下を cover する: + - stopped/restorable Pod delete success。 + - live Pod delete refusal。 + - Pod delete 後の same-name missing/fresh behavior。 + - referenced session is preserved。 + - unreferenced session prune dry-run and force behavior。 + - old Pod/session prune requires explicit threshold。 + - CLI parsing/help。 + +## Binding decisions / invariants + +- No silent restore bypass. Fresh same-name start は、ユーザーが明示的に metadata を削除した結果としてのみ発生する。 +- Pod metadata delete の副作用として session history を自動削除しない。 +- live/reachable Pod metadata を削除しない。 +- 暗黙の “old” threshold を持たせない。old Pod/session cleanup では age criteria をユーザーが明示する。 +- destructive deletion には明示的な `--force` を要求し、dry-run/report behavior を提供する。 +- Pod metadata authority は `pod-store`、session log authority は `session-store` のままにする。 +- legacy top-level resume flags や bare Pod-name inference を再導入しない。 +- この Ticket では Panel/TUI を broad Pod manager にしない。CLI 実装で十分とし、Panel integration は必要なら follow-up に分ける。 + +## Implementation latitude + +- 合意済み command spelling は維持する。ただし clap/parser 上の曖昧さを避けるための minor option shape 調整は、既存 UX を壊さない範囲で許容する。 +- product CLI 側で management subcommands を捕捉するか、runtime entrypoint 側へ安全に追加するかは実装判断でよい。 +- 必要なら product CLI から使う shared cleanup module を作ってよい。 +- 必要なら `session-store` に削除 API を追加してよい。その場合は path safety と trace/log cleanup の tests を追加する。 +- Orphan session detection は初期実装では active `PodMetadata.active.session_id` references を authority としてよい。より高度な lineage-aware retention は、referenced sessions を削除しない限り follow-up に分けてよい。 +- Output は初期実装では human-readable でよい。JSON output は周辺 CLI と自然に揃えられる場合を除き follow-up でよい。 + +## Readiness + +- readiness: implementation_ready +- risk_flags: [pod-lifecycle, persistence, destructive-operation, cli-ux, session-history, authority-boundary] + +## Escalation conditions + +以下の場合は実装を進める前に Orchestrator / maintainer に escalate する。 + +- live Pod detection を安全に拒否できるほど reliable にできない。 +- orphan detection が session lineage semantics の変更を必要とする。 +- Pod delete の副作用として sessions を削除する必要が出る。 +- storage migration や compatibility fallback が必要になる。 +- command design が `yoi pod` runtime entrypoint usage と衝突する。 +- cleanup が Panel role-session/Ticket claims、worktrees、branches、Ticket state を mutate しようとする。 + +## Validation + +- `cargo fmt --check` +- focused `cargo test` for `yoi`, `pod-store`, `session-store`, and affected Pod/discovery code +- `cargo check -p yoi -p pod -p pod-store -p session-store` +- `target/debug/yoi ticket doctor` または `yoi ticket doctor` +- `git diff --check` + +Reviewer は path safety、live/refusal behavior、dry-run/force semantics、session history を accidental に削除しないことを重点確認する。 + +## Related work + +- Related closed Ticket: `00001KTJ7MACG` — Add Pod archive and fresh-start path. +- Related closed Ticket: `00001KSTRGFX0` — Split Pod metadata into a dedicated pod-store crate. +- Related closed Ticket: `00001KSXXRRC8` — Pod tools: unify pod listing and rename restore operation. +- Files inspected: + - `crates/yoi/src/main.rs` + - `crates/yoi/src/session_cli.rs` + - `crates/pod/src/entrypoint.rs` + - `crates/pod-store/src/lib.rs` + - `crates/session-store/src/fs_store.rs` + - `crates/session-store/src/lib.rs` diff --git a/.yoi/tickets/00001KVWPVHFJ/thread.md b/.yoi/tickets/00001KVWPVHFJ/thread.md new file mode 100644 index 00000000..693cca01 --- /dev/null +++ b/.yoi/tickets/00001KVWPVHFJ/thread.md @@ -0,0 +1,7 @@ + + +## 作成 + +LocalTicketBackend によって作成されました。 + +--- diff --git a/.yoi/tickets/00001KVWPW3KX/artifacts/.gitkeep b/.yoi/tickets/00001KVWPW3KX/artifacts/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/.yoi/tickets/00001KVWPW3KX/item.md b/.yoi/tickets/00001KVWPW3KX/item.md new file mode 100644 index 00000000..cda4f4b1 --- /dev/null +++ b/.yoi/tickets/00001KVWPW3KX/item.md @@ -0,0 +1,122 @@ +--- +title: 'TUI Console: 連続した Thinking block を一つの表示グループにまとめる' +state: 'ready' +created_at: '2026-06-24T11:39:59Z' +updated_at: '2026-06-24T11:56:52Z' +assignee: null +readiness: 'implementation_ready' +risk_flags: ['tui-rendering', 'reasoning-display', 'block-aggregation', 'text-selection'] +--- + +## User claims / request snapshot + +- ユーザーは、TUI Console で連続した `Thinking` を `Read` tool 表示のように一つにまとめて表示したいと依頼した。 +- 対象 workspace は `yoi`。 +- Panel handoff の orchestrator Pod は `yoi-orchestrator`。 + +## Confirmed facts / sources + +- 既存 Ticket 確認では、同じ目的の active duplicate は見当たらなかった。 +- 関連 closed Ticket: + - `00001KT5D44Z0` — reasoning / thinking persistence を block lifecycle に統一済み。 + - `00001KVMT2J25` — in-flight snapshot が unfinished thinking block を含め、TUI が snapshot から unfinished thinking を seed して live delta 継続できるようにした。 + - `00001KVHX0WBE` — Dashboard / Console / TUI の呼称と module boundary を整理済み。今回の対象は Console / single-Pod chat surface。 + - `00001KTKCK8W8` — chat view の Markdown rendering 改善。今回と同じく表示層の変更であり、history / context 変更は避ける方針が近い。 +- `00001KSVP63K8` は planning の in-flight composer injection で、今回の Thinking 表示集約とは別件。 +- `crates/tui/src/block.rs` では `Block::Thinking(ThinkingBlock)` が独立した history block として存在し、`ThinkingState::{Streaming, Finished, Incomplete}` を持つ。 +- `crates/tui/src/app.rs` では `Event::ThinkingStart` ごとに新しい `Block::Thinking` を push し、`ThinkingDelta` は最後の streaming thinking に追記し、`ThinkingDone` で finished にする。 +- `crates/tui/src/ui.rs` の `compute_history` は block 列を走査し、`Block::ToolCall` だけ `crate::tool::render_tool(...)` に委譲して複数 block 消費を許している。 +- `crates/tui/src/tool.rs` の `Read` renderer は、連続する `Read` tool call block を `render_read_aggregate` でまとめ、1つの header と path list として表示している。 +- `crates/tui/src/ui.rs` の `render_thinking` は現在、各 `ThinkingBlock` を個別に header / body preview / detail として描画している。連続 Thinking をまとめる専用 path は見当たらない。 + +## Unverified hypotheses + +- 実装は `Read` と同様に `compute_history` 側で連続する `Block::Thinking` をまとめる renderer を導入する形が自然そう。 +- 「連続」は、同じ turn 内で他の block を挟まない `Block::Thinking` の連なりとして扱うのが妥当そう。 +- Normal mode では 1 header + 最新または先頭 preview、Detail mode では各 Thinking body を連結または小見出し付きで読める形にすればよさそう。 + +## Undecided points / open questions + +- blocking な未決定点はない。 +- 表示文言の細部(例: `Thoughts — 3 blocks` / `Thinking... (3 blocks)` / elapsed 表示の集約方法)は実装者判断でよい。 +- ただし、連続していない Thinking や turn を跨ぐ Thinking までまとめるべきではない、という invariant は維持する。 + +## Background + +Provider / model によっては 1 turn 内で Thinking / reasoning block が複数連続して発生する。現状の Console 表示では、それぞれが個別の Thinking 表示になり、会話ログが冗長に見える可能性がある。`Read` tool は連続する `Read` call を 1つの表示グループにまとめる既存 UX があるため、Thinking でも同様の表示集約を行う。 + +## Requirements + +- TUI Console の history rendering で、連続する `Block::Thinking` を一つの logical display group として表示する。 +- 対象は Console / single-Pod chat view の表示層に限定する。 +- `Read` tool の連続 aggregation と同じく、rendering 時に複数 block を消費して一つの表示にまとめられること。 +- 連続していない Thinking、別 turn の Thinking、間に `AssistantText` / `ToolCall` / `User` / `System` などを挟む Thinking はまとめない。 +- `Streaming` / `Finished` / `Incomplete` が混在しても、状態が誤解されない header / body 表示にする。 +- Normal / Detail / Overview mode の既存意味を保つ。 +- Pod history、session log、worker history、prompt context、protocol event model、reasoning persistence は変更しない。 +- In-flight snapshot から復元された unfinished Thinking と live delta continuation の表示が退行しない。 + +## Acceptance criteria + +- 1 turn 内で `Thinking` block が複数連続する場合、Console history 上では 1つの Thinking group として表示される。 +- 連続 Thinking group は、少なくとも group header と読み取り可能な preview / detail body を持つ。 +- Normal mode で冗長な `Thought` / `Thinking...` header が連続表示されない。 +- Detail mode では、集約された各 Thinking の本文が欠落せず読める。 +- Overview mode でも 1 group として扱われ、行数が不必要に増えない。 +- 間に non-Thinking block がある場合や turn を跨ぐ場合は、別 group として表示される。 +- Text selection / copy の既存方針が壊れない。Thinking は現在 text-like selectable block ではないため、集約後も不用意に selectable transcript text にしない。 +- Read tool aggregation、ToolCall rendering、AssistantText rendering に退行がない。 +- Focused TUI rendering test が追加または更新される。 + +## Binding decisions / invariants + +- これは TUI Console の表示改善であり、reasoning / thinking の protocol、persistence、provider event semantics の変更ではない。 +- Thinking content を history / context に別形式で保存し直さない。 +- 未完了 Thinking を finalized assistant history と混同しない。 +- `Read` aggregation と同じく render-time aggregation として扱い、source block sequence 自体は保持する。 +- Turn boundary を跨いで group 化しない。 +- Non-Thinking block を跨いで group 化しない。 +- Dashboard / Panel の Ticket rows や web UI は対象外。 + +## Implementation latitude + +- `compute_history` に `Block::Thinking` の consecutive aggregation path を追加し、`tool::render_tool` と同様に consumed count を返す helper を作ってよい。 +- `render_thinking` を単体 renderer として残しつつ、複数 block 用の `render_thinking_aggregate` を追加してよい。 +- Header 文言、elapsed 表示、複数 state 混在時の summary は実装者判断でよい。ただし streaming / incomplete を隠さない。 +- Detail mode で各 block の境界を薄い separator / index / blank line で示すか、単純連結するかは実装者判断でよい。 +- Existing tests に加えて、synthetic `App { blocks: [...] }` から `compute_history` output を見る focused unit test を追加するのが自然。 + +## Readiness + +- readiness: implementation_ready +- risk_flags: [tui-rendering, reasoning-display, block-aggregation, text-selection] + +## Escalation conditions + +- protocol / pod / persistence 層の変更が必要だと分かった場合。 +- Thinking を selectable / copyable transcript text として扱う UX 変更が必要になる場合。 +- Provider-specific reasoning metadata の扱いに踏み込む必要が出た場合。 +- Console 以外の Dashboard / web / protocol UI surface まで範囲が広がる場合。 +- 表示集約のために broad TUI rendering rewrite が必要になる場合。 + +## Validation + +- `cargo test -p tui` または focused `cargo test -p tui thinking` / rendering tests。 +- `cargo fmt --check`。 +- `git diff --check`。 +- 必要に応じて `cargo check -p tui`。 +- 変更範囲が TUI / package integration に広がる場合のみ `nix build .#yoi` を検討。 + +## Related work + +- Tickets: + - `00001KT5D44Z0` — Unify reasoning persistence with block lifecycle + - `00001KVMT2J25` — Pod protocol: in-flight LLM response reconnect snapshot should include unfinished blocks + - `00001KVHX0WBE` — Dashboard / Console 呼称導入と TUI モジュール境界整理 + - `00001KTKCK8W8` — TUI chat view should render Markdown tables + - related but not duplicate: `00001KSVP63K8` +- Files: + - `crates/tui/src/block.rs` + - `crates/tui/src/app.rs` + - `crates/tui/src/ui.rs` + - `crates/tui/src/tool.rs` diff --git a/.yoi/tickets/00001KVWPW3KX/thread.md b/.yoi/tickets/00001KVWPW3KX/thread.md new file mode 100644 index 00000000..5bc47f38 --- /dev/null +++ b/.yoi/tickets/00001KVWPW3KX/thread.md @@ -0,0 +1,23 @@ + + +## 作成 + +LocalTicketBackend によって作成されました。 + +--- + + + +## Intake summary + +ユーザーが draft 内容を確認し、Ticket `00001KVWPW3KX` を ready にするよう明示した。Ticket 本文には implementation_ready、blocking open questions なし、対象範囲・invariants・validation が記録済みで、Orchestrator が implementation routing を判断できる。 + +--- + + + +## State changed + +ユーザー確認済みのため planning から ready へ移行する。blocking open questions はなく、Orchestrator は通常の routing 判断に進める。 + +---