feat(workspace): reuse checkout sessions per ChatGPT conversation - #128
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe PR adds conversation-scoped checkout reuse, isolated worktree creation, persisted bootstrap delivery, review checkpoint recovery, request metadata extraction, workspace metadata rendering, database migrations, tests, and workflow guidance. ChangesWorkspace lifecycle
Estimated code review effort: 4 (Complex) | ~65 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant open_workspace
participant request_meta
participant WorkspaceRegistry
participant WorkspaceStore
participant ReviewCheckpointManager
participant WorkspaceCard
Client->>open_workspace: Request workspace
open_workspace->>request_meta: Extract openai/session scope
open_workspace->>WorkspaceRegistry: Open workspace with scope
WorkspaceRegistry->>WorkspaceStore: Resolve binding and claim bootstrap
WorkspaceRegistry->>ReviewCheckpointManager: Initialize checkpoints
WorkspaceRegistry-->>open_workspace: Return workspace context
open_workspace->>WorkspaceCard: Send workspace metadata
WorkspaceCard-->>Client: Render workspace information
Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
Greptile SummaryAdds conversation-scoped reuse of checkout workspaces while keeping worktree opens isolated and preserving bootstrap and review state across restarts.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| src/workspaces.ts | Implements canonical conversation-scoped checkout reuse, isolated worktree creation, stale-binding recovery, and bootstrap claiming. |
| src/workspace-store.ts | Adds persistent conversation bindings and transactional per-project bootstrap claims. |
| src/db/migrations.ts | Creates the new persistence tables and deterministically backfills bootstrap history from existing bindings. |
| src/review-checkpoints.ts | Persists distinct workspace-open and last-shown checkpoints and safely handles restarts, missing refs, and concurrent initialization. |
| src/server.ts | Extracts OpenAI conversation metadata, connects reuse to workspace opening, and separates visible bootstrap output from complete card metadata. |
| src/ui/workspace-app.tsx | Renders expanded workspace, worktree, agent-provider, agent, instruction, and diagnostic details. |
Sequence Diagram
sequenceDiagram
participant Host as ChatGPT host
participant Server as MCP server
participant Registry as WorkspaceRegistry
participant Store as SQLite store
Host->>Server: open_workspace(path, openai/session)
Server->>Registry: openWorkspace(path, conversationScopeId)
Registry->>Store: lookup checkout binding
alt valid checkout binding
Store-->>Registry: existing workspace session
Registry-->>Server: "workspaceReused=true"
else no valid binding
Registry->>Registry: create checkout workspace
Registry->>Store: persist conversation binding
Registry-->>Server: "workspaceReused=false"
end
Registry->>Store: claim project bootstrap
Store-->>Registry: first delivery or already claimed
Registry-->>Server: workspace plus bootstrap state
Server-->>Host: visible result and complete hidden card metadata
Reviews (3): Last reviewed commit: "docs(workspace): describe resume behavio..." | Re-trigger Greptile
[gpt-5.6] RESPONDING ON BEHALF OF WAISHNAVAddressed the two test findings from the latest CodeRabbit review.
The focused review suite, complete |
|
@coderabbitai, @greptileai full review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (5)
docs/gotchas.md (1)
151-154: 🚀 Performance & Scalability | 🔵 Trivial | 🏗️ Heavy liftDefine and implement retention before long-lived deployment.
The document states that workspace sessions, conversation bindings, bootstrap records, and review refs have no expiration or orphan cleanup. Repeated conversations and worktree opens can grow database and repository metadata without a bound.
Define cleanup per record type. Preserve active workspaces and review checkpoints. Remove orphaned records and refs safely.
🤖 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 `@docs/gotchas.md` around lines 151 - 154, Define and implement retention policies for workspace sessions, conversation bindings, conversation bootstrap records, and review refs before long-lived deployment. Add bounded expiration and safe orphan cleanup for each record type, while preserving active workspaces and review checkpoints and ensuring repository refs are removed only when no longer needed.src/review-checkpoints.test.ts (1)
94-128: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd coverage for the
workspace_openselector and the missing-open-checkpoint errors.
ReviewSinceexposes"workspace_open", but the tests only cover the implicit fallback from"last_shown". Add tests forreviewChanges({ since: "workspace_open", ... })including the open-ref-missing and both-refs-missing error paths.🤖 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 `@src/review-checkpoints.test.ts` around lines 94 - 128, Add tests in the review checkpoint suite for explicit since: "workspace_open" via reviewChanges, covering the normal comparison and the error when the workspace-open ref is missing. Also cover the error when both the workspace-open and last-shown refs are missing, using the existing checkpoint setup and ref-deletion helpers.src/workspaces.ts (1)
237-249: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider refreshing skills for a reused workspace.
reusedWorkspaceContextreloadsagentProfiles,agentsFiles, andavailableAgentsFiles, but it keeps theskillsandskillDiagnosticscaptured at the first open. A reused checkout therefore reports stale skill metadata toopen_workspacecard output after the user adds or edits aSKILL.mdin the same conversation.loadSkillsForWorkspaceis synchronous and cheap, so refreshing keeps all bootstrap-derived data consistent.♻️ Proposed refresh of skill metadata
private async reusedWorkspaceContext(workspace: Workspace): Promise<WorkspaceContext> { + Object.assign(workspace, this.loadSkillsForWorkspace(workspace.root)); workspace.agentProfiles = await loadLocalAgentProfiles(this.config, workspace.root); const agentsFiles = await this.loadInitialAgentsFiles(workspace.root); const availableAgentsFiles = await this.findAvailableAgentsFiles(workspace.root, agentsFiles);🤖 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 `@src/workspaces.ts` around lines 237 - 249, Update reusedWorkspaceContext to refresh the workspace’s skills and skillDiagnostics by calling loadSkillsForWorkspace for workspace.root before constructing the returned WorkspaceContext, and include the refreshed values in the return object so reused workspaces report current skill metadata.src/ui/card-types.test.ts (1)
34-66: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd coverage for the new
worktreeandinstructionexpansion branches.
isExpandableCardgained two more workspace branches insrc/ui/card-types.tsat lines 174-175:Boolean(card.worktree)andBoolean(card.instruction). Neither branch is exercised here.💚 Proposed additional tests
+test("a workspace card expands when it contains worktree metadata", () => { + assert.equal( + isExpandableCard({ tool: "open_workspace", worktree: { path: "/tmp/wt" } }), + true, + ); +}); + +test("a workspace card expands when it contains an instruction", () => { + assert.equal( + isExpandableCard({ tool: "open_workspace", instruction: "Reuse this workspaceId." }), + true, + ); +}); + test("an empty workspace card stays collapsed", () => { assert.equal(isExpandableCard({ tool: "open_workspace" }), false); });🤖 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 `@src/ui/card-types.test.ts` around lines 34 - 66, Add tests in the workspace-card section covering `isExpandableCard` returning true when `worktree` is present and when `instruction` is present. Keep the existing empty-card assertion to verify cards without any expandable metadata remain collapsed.src/workspace-conversation.test.ts (1)
487-490: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRename the cleanup loop variable.
The loop variable
openStoreshadows theopenStorefactory declared at line 477 and holds aSqliteWorkspaceStoreinstance, not a factory. Rename it to make the cleanup intent clear.♻️ Proposed rename
t.after(async () => { - for (const openStore of stores) openStore.close(); + for (const store of stores) store.close(); await rm(root, { recursive: true, force: true }); });🤖 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 `@src/workspace-conversation.test.ts` around lines 487 - 490, Rename the cleanup loop variable in the t.after teardown from openStore to a name representing its SqliteWorkspaceStore instance, and update the corresponding close() call; leave the openStore factory declaration and cleanup behavior unchanged.
🤖 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 `@src/review-checkpoints.ts`:
- Around line 96-109: The availability flags openRefAvailable and
baselineRefAvailable are set once during initialization and never refreshed, so
a checkpoint ref removed after startup will still appear available. Before
trusting these flags to determine which ref to use, verify that the selected
baselineRef (derived from effectiveSince and either state.openRef or
state.baselineRef) actually resolves to a commit by attempting the git rev-parse
command. If the ref resolution fails, handle it as an unavailable checkpoint by
applying the same fallback or error-handling logic that occurs in the guard
conditions at lines 96-106, rather than letting the raw git error propagate to
the user.
In `@src/workspace-conversation.test.ts`:
- Around line 383-392: The test around WorkspaceRegistry.openWorkspace should
not require better-sqlite3’s exact error message. Assert the observable
rejection behavior or use the message only as a non-essential secondary check,
while preserving verification that the storage error is propagated rather than
treated as a stale binding.
---
Nitpick comments:
In `@docs/gotchas.md`:
- Around line 151-154: Define and implement retention policies for workspace
sessions, conversation bindings, conversation bootstrap records, and review refs
before long-lived deployment. Add bounded expiration and safe orphan cleanup for
each record type, while preserving active workspaces and review checkpoints and
ensuring repository refs are removed only when no longer needed.
In `@src/review-checkpoints.test.ts`:
- Around line 94-128: Add tests in the review checkpoint suite for explicit
since: "workspace_open" via reviewChanges, covering the normal comparison and
the error when the workspace-open ref is missing. Also cover the error when both
the workspace-open and last-shown refs are missing, using the existing
checkpoint setup and ref-deletion helpers.
In `@src/ui/card-types.test.ts`:
- Around line 34-66: Add tests in the workspace-card section covering
`isExpandableCard` returning true when `worktree` is present and when
`instruction` is present. Keep the existing empty-card assertion to verify cards
without any expandable metadata remain collapsed.
In `@src/workspace-conversation.test.ts`:
- Around line 487-490: Rename the cleanup loop variable in the t.after teardown
from openStore to a name representing its SqliteWorkspaceStore instance, and
update the corresponding close() call; leave the openStore factory declaration
and cleanup behavior unchanged.
In `@src/workspaces.ts`:
- Around line 237-249: Update reusedWorkspaceContext to refresh the workspace’s
skills and skillDiagnostics by calling loadSkillsForWorkspace for workspace.root
before constructing the returned WorkspaceContext, and include the refreshed
values in the return object so reused workspaces report current skill metadata.
🪄 Autofix
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: cc4bdd41-1c88-4447-a6b5-35526fc795fc
📒 Files selected for processing (19)
docs/chatgpt-coding-workflow.mddocs/gotchas.mdpackage.jsonsrc/db/migrations.tssrc/db/schema.tssrc/oauth-store.test.tssrc/request-meta.test.tssrc/request-meta.tssrc/review-checkpoints.test.tssrc/review-checkpoints.tssrc/server.tssrc/ui/card-types.test.tssrc/ui/card-types.tssrc/ui/workspace-app.tsxsrc/workspace-conversation.test.tssrc/workspace-store.test.tssrc/workspace-store.tssrc/workspaces.test.tssrc/workspaces.ts
Summary
DevSpace currently creates a new checkout workspace when
open_workspaceis called again, which losesworkspaceIdcontinuity and repeats workspace context in a ChatGPT conversation.This PR adds optional conversation-scoped checkout recovery using a non-empty
_meta["openai/session"]value as an opaque OpenAI-host correlation key. The same conversation opening the same canonical checkout reuses its persisted workspace session, including across MCP reconnects and DevSpace restarts.Behavior
workspaceId.workspaceIdworkflow and receive complete context on each open.Conversation metadata is an optional OpenAI host-adapter enhancement, not a standard MCP conversation identifier. The portable contract remains
open_workspacereturning aworkspaceIdthat later tools pass explicitly.Model and UI contract
Workspace lifecycle bookkeeping remains internal:
workspaceReusedandincludeBootstrapContextare not part of the model-facing output schema orstructuredContent.Opened workspace,Reused workspace, andOpened worktree.Repeated-context suppression is derived from actual reuse of the same checkout. There is no separate persisted project-bootstrap ledger.
Persistence and recovery
Review checkpoints
Stable workspace IDs require review checkpoints to survive reinitialization. This PR preserves the existing workspace-open and last-shown checkpoint meanings across restart and concurrent initialization, validates workspace/root consistency, supports safe fallback when the last-shown ref is missing after restart, and retains unborn-repository recovery.
The public
show_changestool contract is unchanged; this PR does not add asinceparameter or another model-selectable review baseline.Validation
Validated with the project-supported Node 22 runtime:
npm test npm run typecheck npm run build git diff --checkThe repository CI matrix covers Ubuntu, macOS, and Windows.