Skip to content

feat(shell): /sessions — browse the session tree and switch - #419

Merged
jexShain merged 1 commit into
AI-Shell-Team:mainfrom
jexShain:feat/sessions-tree
Jul 29, 2026
Merged

feat(shell): /sessions — browse the session tree and switch#419
jexShain merged 1 commit into
AI-Shell-Team:mainfrom
jexShain:feat/sessions-tree

Conversation

@jexShain

@jexShain jexShain commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds the /sessions built-in command: an interactive panel that browses the session tree (roots + all descendants, indented by depth) and switches to the chosen session on submit.

Closes #412

What it does

  • Walks the full session forest depth-first (collect_session_tree) so nested forks stay visible, not just roots + direct children.
  • Submit switches to the selected session, persisting the current state first (persist_current=true, like /resume) so no cwd is lost.

Stacked on #418 (/fork)

This builds on the session data layer introduced by the /fork PR — session_roots / list_children / parent_session_uuid. Merge #418 first. The diff below includes that PR's commit until it lands.

Scope

Reuses the existing SearchSelectPanel + resume_session_with_options; no new UI primitives. Self-contained to the /sessions command + i18n.

Verification

  • cargo clippy -p aish-shell --all-targets -- -D warnings clean.
  • aish-session tests pass (9); slash_popup_commands tests pass (count + i18n).

Summary by CodeRabbit

  • New Features
    • Added the /sessions command to browse the session tree, including roots and forks.
    • Added an interactive session selector with details such as model, timestamp, current session, and summary.
    • Enabled switching to a selected saved session.
  • Localization
    • Added translations for the new command and session browsing messages in German, Spanish, French, Japanese, Simplified Chinese, and English.
    • Added messages for empty session lists and session loading or switching failures.

@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the pull request. A maintainer will review it when available.

Please keep the PR focused, explain the why in the description, and make sure local checks pass before requesting review.

Contribution guide: https://github.com/AI-Shell-Team/aish/blob/main/CONTRIBUTING.md

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 05805195-e9f8-43a1-a0ab-12a0454f2ad2

📥 Commits

Reviewing files that changed from the base of the PR and between 4ba0ffa and 412d4f5.

📒 Files selected for processing (9)
  • crates/aish-i18n/locales/de-DE.yaml
  • crates/aish-i18n/locales/en-US.yaml
  • crates/aish-i18n/locales/es-ES.yaml
  • crates/aish-i18n/locales/fr-FR.yaml
  • crates/aish-i18n/locales/ja-JP.yaml
  • crates/aish-i18n/locales/zh-CN.yaml
  • crates/aish-shell/src/app.rs
  • crates/aish-shell/src/readline.rs
  • crates/aish-shell/tests/slash_popup_commands.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/aish-shell/tests/slash_popup_commands.rs

📝 Walkthrough

Walkthrough

Adds the /sessions slash command, which recursively displays saved session roots and forks in an interactive selector and resumes the selected session. Command-count tests and localized labels and error messages are updated across six locales.

Changes

Session Navigation

Layer / File(s) Summary
Register and route /sessions
crates/aish-shell/src/readline.rs, crates/aish-shell/src/app.rs, crates/aish-shell/tests/slash_popup_commands.rs
Adds /sessions to the command registry, routes it through special-command handling, and updates command-count tests.
Browse and switch session trees
crates/aish-shell/src/app.rs
Loads session roots, recursively collects fork descendants, renders selectable tree rows, and resumes the selected session.
Localize session navigation
crates/aish-i18n/locales/*.yaml
Adds /sessions labels and messages for empty lists, switching failures, and listing failures in six locales.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AishShell
  participant SessionStore
  participant SearchSelectPanel
  AishShell->>SessionStore: load roots and child sessions
  SessionStore-->>AishShell: return session tree
  AishShell->>SearchSelectPanel: show selectable tree
  SearchSelectPanel-->>AishShell: return selected session
  AishShell->>SessionStore: persist and resume session
Loading

Possibly related PRs

Suggested labels: size: L

Suggested reviewers: f16shen

Poem

I hop through branches, neat and bright,
Selecting sessions left and right.
Roots and forks now form a tree,
With words in many tongues for me.
/sessions blooms—what joy to see!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding /sessions to browse and switch session trees.
Linked Issues check ✅ Passed The implementation matches #412: interactive depth-first tree browsing, session switching with persistence, and friendly handling for empty or unavailable stores.
Out of Scope Changes check ✅ Passed The changes stay focused on /sessions command logic, localization, and tests, with no clear unrelated additions.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

This pull request description looks incomplete. Please update the missing sections below before review.

Missing items:

  • User-visible Changes
  • Compatibility
  • Testing
  • Change Type
  • Scope

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
crates/aish-session/src/store.rs (1)

303-312: 🚀 Performance & Scalability | 🔵 Trivial

Consider an index on parent_session_uuid if session counts grow.

list_children is called once per node while building the /sessions forest, and each call full-scans sessions. An index keeps the tree walk linear-ish as history accumulates.

CREATE INDEX IF NOT EXISTS idx_sessions_parent ON sessions(parent_session_uuid);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/aish-session/src/store.rs` around lines 303 - 312, Add an index on
sessions.parent_session_uuid during database initialization or migration, using
the established schema setup path and the name idx_sessions_parent. Keep
list_children unchanged so its parent_session_uuid filter can use the index.
crates/aish-shell/src/app.rs (1)

3542-3555: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Bound the recursion depth.

Acyclicity is only an invariant of the /fork path — fork_session doesn't reject new_uuid == parent_uuid, and sessions.db is a user-writable file. A self-parent or cycle row makes this recurse until the stack overflows, killing the shell. A depth cap keeps it a display artifact instead.

🛡️ Cap the walk depth
     fn collect_session_tree(
         &self,
         store: &aish_session::SessionStore,
         node: &aish_session::SessionRecord,
         depth: usize,
         items: &mut Vec<aish_ui::SearchSelectItem>,
     ) {
         items.push(self.session_tree_item(node, depth));
+        // Defensive: a malformed/hand-edited sessions.db could contain a
+        // parent cycle, which would otherwise recurse until stack overflow.
+        if depth >= MAX_SESSION_TREE_DEPTH {
+            return;
+        }
         if let Ok(children) = store.list_children(&node.session_uuid) {

Plus a module-level constant:

/// Maximum nesting rendered by `/sessions`.
const MAX_SESSION_TREE_DEPTH: usize = 32;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/aish-shell/src/app.rs` around lines 3542 - 3555, Bound recursion in
collect_session_tree using a module-level MAX_SESSION_TREE_DEPTH constant set to
32. Stop descending once the current depth reaches the cap, while still
rendering the current node and preserving normal child traversal below the
limit.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/aish-session/src/store.rs`:
- Around line 598-625: Update add_column_if_missing to derive the target column
name and query PRAGMA table_info(sessions) before executing ALTER TABLE,
returning success when the column is already present. Preserve the
duplicate-column error fallback only as a documented concurrent-migration race
guard for this ADD COLUMN operation, while propagating unrelated SQLite errors
unchanged through the existing AishError::Session path; keep migrate_schema’s
two-column migration calls intact.

In `@crates/aish-shell/src/app.rs`:
- Around line 3404-3434: Update the manual-recovery hint in the
resume_session_with_options failure branch to pass the full new_uuid to the
shell.fork.switch_manual translation arguments instead of new_short, while
keeping the existing shortened identifier for the success message.

---

Nitpick comments:
In `@crates/aish-session/src/store.rs`:
- Around line 303-312: Add an index on sessions.parent_session_uuid during
database initialization or migration, using the established schema setup path
and the name idx_sessions_parent. Keep list_children unchanged so its
parent_session_uuid filter can use the index.

In `@crates/aish-shell/src/app.rs`:
- Around line 3542-3555: Bound recursion in collect_session_tree using a
module-level MAX_SESSION_TREE_DEPTH constant set to 32. Stop descending once the
current depth reaches the cap, while still rendering the current node and
preserving normal child traversal below the limit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f6eb1938-fb6a-4c0e-9739-08c5c50c8fa0

📥 Commits

Reviewing files that changed from the base of the PR and between 78117a9 and fe89d91.

📒 Files selected for processing (11)
  • crates/aish-i18n/locales/de-DE.yaml
  • crates/aish-i18n/locales/en-US.yaml
  • crates/aish-i18n/locales/es-ES.yaml
  • crates/aish-i18n/locales/fr-FR.yaml
  • crates/aish-i18n/locales/ja-JP.yaml
  • crates/aish-i18n/locales/zh-CN.yaml
  • crates/aish-session/src/models.rs
  • crates/aish-session/src/store.rs
  • crates/aish-shell/src/app.rs
  • crates/aish-shell/src/readline.rs
  • crates/aish-shell/tests/slash_popup_commands.rs

Comment thread crates/aish-session/src/store.rs
Comment thread crates/aish-shell/src/app.rs
@jexShain
jexShain force-pushed the feat/sessions-tree branch from fe89d91 to 4ba0ffa Compare July 29, 2026 05:36
@jexShain
jexShain force-pushed the feat/sessions-tree branch 2 times, most recently from fe4b7d8 to 38ae2b4 Compare July 29, 2026 08:25
`/sessions` opens an interactive panel showing the session forest (roots +
all descendants, indented by depth) and switches to the chosen session on
submit — switching persists the current state first so no cwd is lost.

- Depth-first descent (collect_session_tree) so nested forks stay visible,
  not just roots + direct children.
- Switch uses persist_current=true (like /resume) to avoid losing cwd.
- Reuses the existing SearchSelectPanel + resume path; no new UI primitives.

Depends on the /fork data layer (session_roots / list_children /
parent_session_uuid) — stacked on the /fork PR.

Closes AI-Shell-Team#412
@jexShain
jexShain force-pushed the feat/sessions-tree branch from 38ae2b4 to 412d4f5 Compare July 29, 2026 08:58
@github-actions github-actions Bot added size: S and removed size: L labels Jul 29, 2026
@jexShain
jexShain merged commit 239b400 into AI-Shell-Team:main Jul 29, 2026
8 checks passed
@jexShain
jexShain deleted the feat/sessions-tree branch July 29, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: /sessions 交互式会话树浏览与切换

1 participant