Skip to content

feat: project-based session view + responsive sidebar - #6

Merged
aterrylu merged 1 commit into
mainfrom
terry/project-session-view
Mar 8, 2026
Merged

feat: project-based session view + responsive sidebar#6
aterrylu merged 1 commit into
mainfrom
terry/project-session-view

Conversation

@aterrylu

@aterrylu aterrylu commented Mar 8, 2026

Copy link
Copy Markdown
Owner

Summary

  • Project session browser: New /api/projects endpoint using Claude Agent SDK's listSessions() — returns all Claude Code sessions grouped by project directory, sorted by recency
  • Two-section sidebar: Live PTY sessions (top) + historical project sessions (bottom, expandable tree with summary, git branch, age)
  • Collapsible sidebar: Hidden by default, toggled via ☰ hamburger in the header
  • Responsive layout: Sidebar overlays on mobile (< md), sits inline on desktop (≥ md). Tap-outside-to-close on mobile
  • Mobile scroll fix: 100dvh + overflow: hidden on body to prevent header scrolling with page on Android Chrome
  • ROADMAP update: Reflects shipped work

Test plan

  • Click ☰ — sidebar opens/closes
  • Desktop: sidebar pushes terminal content inline
  • Mobile: sidebar overlays as drawer, tapping outside closes it
  • Projects section lists all Claude Code projects with session counts
  • Expanding a project shows individual sessions with summary + branch + age
  • Live sessions section still works (create/switch/kill)
  • Header stays fixed on mobile scroll

🤖 Generated with Claude Code

…sidebar

Add /api/projects endpoint using Claude Agent SDK's listSessions() to return
all Claude Code sessions grouped by project directory. Sidebar now shows two
sections: live PTY sessions and historical project sessions (expandable tree).
Sidebar is toggled via hamburger menu, overlays on mobile, inline on desktop.
Fix mobile viewport scroll by using 100dvh and locking body overflow.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@aterrylu
aterrylu enabled auto-merge (squash) March 8, 2026 19:05

/** GET /api/projects — all Claude Code sessions grouped by project */
projectRouter.get("/", async (c) => {
const env = { ...process.env } as Record<string, string>;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟡 Warning

Problem: env is built and sanitized but never passed to listSessions(). The SDK call on line 25 ignores it entirely.

Why it matters: This looks like a half-finished security measure — the intent was probably to strip CLAUDECODE (or other sensitive keys) from the environment before the SDK uses it. As written, it is dead code that gives a false sense of sanitization while listSessions() still has full access to process.env.

Suggested fix:

// Either pass it (if the SDK accepts it):
const sessions = await listSessions({ env });

// Or remove the dead code entirely if the SDK does not accept env overrides:
const sessions = await listSessions();

projectRouter.get("/", async (c) => {
const env = { ...process.env } as Record<string, string>;
delete env.CLAUDECODE;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🟡 Warning

Problem: listSessions() is called with no error handling. A filesystem error, SDK misconfiguration, or missing ~/.claude directory will cause an unhandled rejection and return a 500 with a stack trace.

Why it matters: This endpoint is polled every 30 seconds from the dashboard. Any transient failure surfaces as an error in the browser and could expose internal paths via the stack trace.

Suggested fix:

let sessions: Awaited<ReturnType<typeof listSessions>>;
try {
  sessions = await listSessions();
} catch (err) {
  console.error("[projects] listSessions failed:", err);
  return c.json([], 200); // return empty rather than 500
}

@nox-0x nox-0x left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Clean feature — the two-section sidebar with project history is a nice UX improvement and the responsive overlay pattern is solid. Two warnings in projects.ts worth a follow-up: (1) the env variable is dead code — it sanitizes process.env but is never passed to listSessions(), creating a false sense of security; (2) listSessions() has no try/catch, so any SDK or filesystem error will 500 and leak a stack trace to the browser on a polled endpoint. Neither blocks merge but both should be addressed soon.

@aterrylu
aterrylu merged commit 7acdd75 into main Mar 8, 2026
1 check passed
@aterrylu
aterrylu deleted the terry/project-session-view branch March 8, 2026 19:09
aterrylu added a commit that referenced this pull request Jun 6, 2026
The written runbook the pipeline was missing — releasing is no longer tribal
knowledge.

- docs/RELEASE.md: the full runbook. Mental model (changesets → Version PR →
  auto-tag → release.yml), day-to-day changeset ritual, how to cut a release,
  beta/pre-release, rollback, local DMG builds, the secrets table, and
  troubleshooting.
- docs/DECISIONS.md ADR-031: the release-pipeline decision record — context
  (version drift + hand-built DMG), the 6-PR design, scope decisions (macOS-only
  desktop, universal2 from day one, changesets over release-please), rationale,
  alternatives, and implications.

ADR-031 is team-lead-owned — drafted here, flagged for review. Numbering note:
ADR-030 informally forward-referenced "ADR-031" for unbuilt named-profiles; this
ADR claims it for the release pipeline (the real decision), noted in the entry.

SLSA provenance (the other half of PR #6) edits release.yml, which lives in the
unmerged PR #3 — deferred to a follow-up once #3 lands to avoid a conflict.

Docs-only, no version impact (empty changeset).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
aterrylu added a commit that referenced this pull request Jun 6, 2026
docs(release): add RELEASE.md runbook + ADR-031 (pipeline PR 6/6, docs)

The written runbook the pipeline was missing — releasing is no longer tribal
knowledge.

- docs/RELEASE.md: the full runbook. Mental model (changesets → Version PR →
  auto-tag → release.yml), day-to-day changeset ritual, how to cut a release,
  beta/pre-release, rollback, local DMG builds, the secrets table, and
  troubleshooting.
- docs/DECISIONS.md ADR-031: the release-pipeline decision record — context
  (version drift + hand-built DMG), the 6-PR design, scope decisions (macOS-only
  desktop, universal2 from day one, changesets over release-please), rationale,
  alternatives, and implications.

ADR-031 is team-lead-owned — drafted here, flagged for review. Numbering note:
ADR-030 informally forward-referenced "ADR-031" for unbuilt named-profiles; this
ADR claims it for the release pipeline (the real decision), noted in the entry.

SLSA provenance (the other half of PR #6) edits release.yml, which lives in the
unmerged PR #3 — deferred to a follow-up once #3 lands to avoid a conflict.

Docs-only, no version impact (empty changeset).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
aterrylu added a commit that referenced this pull request Jun 9, 2026
…ted (Phase 2) (#192)

* test(server): real-claude L3 integration via mock backend, CI-only gated (Phase 2)

Phase 2 of the test redesign (docs/TESTING.md). Spawns the REAL `claude` binary
through autonomOS's real provider → node-pty → hook-relay path against a mock
Anthropic /v1/messages SSE backend (helpers/mock-anthropic.ts) — zero API cost,
zero argv mutation. Asserts the agent reaches running, the server receives real
SessionStart/UserPromptSubmit/Stop hook telemetry, and it exits cleanly (liveness).
Chose real-claude+mock over testagent (rejected: argv divergence — see docs).

SAFETY (after an incident where a subagent's `pkill -f claude` cleanup killed the
operator's live agents on this dev box, which is also a live deployment):
- The whole suite is gated behind AUTONOMOS_INTEGRATION=1, set ONLY in CI
  (test.yml). Local `make check` skips it entirely — verified: 0 claude processes
  spawned locally, live agents untouched.
- The test only ever kills its own scoped agent id / server child — never a broad
  pkill. Documented as convention #6 in docs/TESTING.md.

CI installs @anthropic-ai/claude-code@2.1.168 (pinned, no auth needed to install).
Suite 2 (real spawn) is validated by CI on a clean machine, not locally — by design.
make check green locally (suite skipped); biome clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci(test): pre-seed Claude Code onboarding config so the L3 spawn fires hooks

The real-claude L3 suite passed server-boot (Suite 1) in CI but the agent-spawn
assertion timed out waiting for SessionStart. Cause: a freshly-installed claude
shows a first-run onboarding/theme prompt that blocks the interactive PTY session,
so no hooks fire. Seed ~/.claude.json with hasCompletedOnboarding=true (the same
fields a configured claude carries) before make check. Locally unaffected (suite
is gated AUTONOMOS_INTEGRATION=1, CI-only).

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

2 participants