Skip to content

feat: expanded view toggle and AI-generated session titles#26

Merged
amahpour merged 5 commits intomainfrom
feat/expanded-view-ai-summaries-16
Apr 6, 2026
Merged

feat: expanded view toggle and AI-generated session titles#26
amahpour merged 5 commits intomainfrom
feat/expanded-view-ai-summaries-16

Conversation

@amahpour
Copy link
Copy Markdown
Owner

@amahpour amahpour commented Apr 5, 2026

Summary

  • Expanded view toggle: "Expanded" button in the topbar switches all tiles to show last 5 transcript entries inline (no chevron). Grid widens in expanded mode. State persists via localStorage.
  • AI session summaries: Every N user messages (default 5, configurable), runs claude -p in the background to generate an evolving 3-8 word session title. Respects title lock, disables gracefully if claude CLI is unavailable.
  • Manual rename auto-locks: Editing a session title now sets display_name_locked: true so AI summaries don't overwrite user renames.
  • Settings UI: New "AI Summaries" tab with configurable interval.

Closes #16

Test plan

  • Open dashboard, click "Expanded" button — tiles show last 5 transcript lines inline
  • Toggle off — compact view returns with chevron-based preview
  • Refresh page — expanded state persists
  • Start a Claude Code session, send 5+ user messages — verify title updates in server logs and on dashboard
  • Manually rename a session — verify lock icon activates and AI does not overwrite
  • Open Settings > AI Summaries — change interval, save, verify it persists
  • make check passes (ruff, mypy, pytest — 256 tests)

🤖 Generated with Claude Code

Add an "Expanded" button that toggles tiles to show the last 5 transcript
entries inline. Periodically run `claude -p` every N user messages to
generate evolving session titles. Manual renames now auto-lock the title.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 5, 2026

Coverage

Unit Test Coverage
FileStmtsMissCoverMissing
__init__.py00100% 
db.py163298%133–134
hooks.py1921990%222–230, 236–242, 258, 262, 265
main.py370100% 
pr_lookup.py113298%53–54
sessions.py00100% 
watcher.py5442894%26–29, 345, 516–517, 520–521, 636, 705, 786, 791–797, 844–852
routes
   __init__.py00100% 
   api.py1440100% 
   ws.py41392%47, 64–65
TOTAL12345495% 

Tests Skipped Failures Errors Time
308 0 💤 0 ❌ 0 🔥 4.640s ⏱️

amahpour and others added 3 commits April 5, 2026 16:55
Rewrite the claude -p prompt to use structured input (labeled roles,
current session state) and request JSON output with title, ticket_id,
and pr_url. Fetch last 5 user+assistant messages (skipping tool_result
noise) via a single SQL query. Only backfill ticket/PR if not already set.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
48 new tests covering: get_recent_conversation DB helper, structured
prompt builder, JSON response parser, summary interval settings,
threshold gating, subprocess success/failure/timeout/lock paths, user
message counting in watcher, and stop_watcher cleanup.

Coverage: 88% → 96% overall, watcher.py 78% → 95%.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix XSS risk: escape role in expanded preview class attribute
- Pass prompt via stdin to claude -p instead of CLI arg (avoids OS
  length limits)
- Validate summary_interval >= 1 at API boundary
- Only lock title on non-empty manual rename
- Toggle button text between Compact/Expanded
- Case-insensitive markdown fence stripping in response parser

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@amahpour
Copy link
Copy Markdown
Owner Author

amahpour commented Apr 6, 2026

Codex Adversarial Review

Target: branch diff against main
Verdict: ⚠️ needs-attention

No-ship: the new AI summary worker can leak untracked claude subprocesses under failure, and it stores model-emitted PR URLs without validation, turning transcript content into trusted dashboard links.


Findings

[high] Timed-out or cancelled AI summaries leave claude children running

Location: server/watcher.py:521-580

_generate_ai_summary starts a claude -p subprocess and wraps proc.communicate() in asyncio.wait_for(). On timeout it only logs and exits; on task cancellation the coroutine also exits through finally without terminating the child. In asyncio that does not reap the subprocess for you. The result is orphaned claude processes that keep consuming local resources and possibly billable background work, while _summary_tasks has already been cleared so later triggers can start even more of them.

Recommendation: Track the subprocess handle and, in timeout/cancellation/finally paths, explicitly kill() or terminate() it and await proc.communicate() before dropping _summary_tasks. Add a regression test that asserts the child is reaped on timeout and watcher shutdown.


[high] AI-extracted pr_url is trusted enough to become a stored dashboard link

Location: server/watcher.py:500-556

The response parser accepts any string for pr_url, and _generate_ai_summary persists it with no scheme, host, or path validation. That new value is later rendered as the session card's PR link, so any URL mentioned in the conversation can be mislabeled as a trusted PR/MR and clicked from the dashboard; a javascript: or arbitrary external URL would be especially bad. This is a new trust-boundary violation from transcript/model output into persisted UI navigation.

Recommendation: Validate AI-derived metadata before storing it: require https, restrict hosts to the repo's GitHub/GitLab remote or an allowlist, and require /pull/<id> or /merge_requests/<id> path shapes. Reject anything else, and consider a frontend safe-link check as defense in depth.


Next Steps

  • Reap summary subprocesses on timeout and cancellation before merging this feature.
  • Add strict server-side validation for AI-populated pr_url values before they are persisted or rendered.

🤖 Generated by Codex adversarial review via Claude Code

- Kill and wait for claude subprocess on timeout/exception to prevent
  orphaned processes consuming resources
- Validate pr_url from AI response: require https scheme and
  /pull/<id> or /merge_requests/<id> path shape; reject javascript:,
  http:, and arbitrary URLs
- Add 9 regression tests covering subprocess reaping and URL validation

Addresses adversarial review findings on PR #26.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@amahpour amahpour merged commit 4e49b4f into main Apr 6, 2026
6 checks passed
@amahpour amahpour deleted the feat/expanded-view-ai-summaries-16 branch April 6, 2026 03:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Evolving session titles via Claude Code hook injection

1 participant