feat: project-based session view + responsive sidebar - #6
Conversation
…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>
|
|
||
| /** GET /api/projects — all Claude Code sessions grouped by project */ | ||
| projectRouter.get("/", async (c) => { | ||
| const env = { ...process.env } as Record<string, string>; |
There was a problem hiding this comment.
🟡 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; | ||
|
|
There was a problem hiding this comment.
🟡 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
left a comment
There was a problem hiding this comment.
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.
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>
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>
…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>
Summary
/api/projectsendpoint using Claude Agent SDK'slistSessions()— returns all Claude Code sessions grouped by project directory, sorted by recency< md), sits inline on desktop (≥ md). Tap-outside-to-close on mobile100dvh+overflow: hiddenon body to prevent header scrolling with page on Android ChromeTest plan
🤖 Generated with Claude Code