feat(workspace): reuse checkout opens and trim repeated bootstrap - #125
feat(workspace): reuse checkout opens and trim repeated bootstrap#125Waishnav wants to merge 25 commits into
Conversation
Greptile SummaryThe PR separates workspace reuse from bootstrap delivery and preserves review state across repeated opens and restarts.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| src/workspaces.ts | Adds canonical project keys, persisted checkout reuse, stale-binding replacement, and fresh worktree behavior. |
| src/workspace-store.ts | Adds atomic persisted conversation bindings and project-bootstrap claims. |
| src/review-checkpoints.ts | Restores checkpoint refs after restart, tracks partial availability, and provides the public baseline fallback. |
| src/server.ts | Connects conversation metadata to workspace opening, awaits checkpoint restoration, and separates model-visible bootstrap data from the complete card payload. |
| src/db/migrations.ts | Adds binding and bootstrap-ledger migrations with backfill from historical conversation targets. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[open_workspace] --> B{Conversation scope available?}
B -- No --> C[Create new workspace]
B -- Yes --> D{Mode}
D -- Worktree --> E[Create fresh managed worktree]
D -- Checkout --> F{Valid persisted binding?}
F -- Yes --> G[Reuse checkout workspace]
F -- No --> H[Create checkout and persist binding]
C --> I{First project open in conversation?}
E --> I
G --> I
H --> I
I -- Yes --> J[Return full bootstrap]
I -- No --> K[Omit repeated model bootstrap]
J --> L[Send complete hidden card payload]
K --> L
L --> M[Restore or initialize review checkpoints]
Reviews (11): Last reviewed commit: "fix(review): fall back when last-shown c..." | Re-trigger Greptile
2e2c471 to
866d49e
Compare
|
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 workspace reuse with persisted SQLite bindings and one-time bootstrap claims. It also adds concurrent checkpoint initialization, canonical path handling, conditional server output, richer workspace card metadata, migration coverage, and updated workflow documentation. ChangesConversation-scoped workspace reuse
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related issues
Possibly related PRs
Poem
Sequence Diagram(s)sequenceDiagram
participant ChatGPT
participant Server
participant WorkspaceRegistry
participant WorkspaceStore
participant SQLite
ChatGPT->>Server: open_workspace(request metadata)
Server->>WorkspaceRegistry: openWorkspace(target, conversationScopeId)
WorkspaceRegistry->>WorkspaceStore: get or set conversation binding
WorkspaceStore->>SQLite: query or persist binding
SQLite-->>WorkspaceStore: workspace session binding
WorkspaceRegistry->>WorkspaceStore: claimConversationBootstrap(scope, project)
WorkspaceStore->>SQLite: insert or update bootstrap record
WorkspaceRegistry-->>Server: workspace context and bootstrap flag
Server-->>ChatGPT: conditional bootstrap output and workspace metadata
🚥 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 |
|
@coderabbitai full review |
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/server.ts (1)
755-772: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy liftAdd the
reopeninput that the PR objectives and the docs promise.The PR objectives state that
reopen: truerequests a fresh workspace. The input schema at lines 756-772 accepts onlypath,mode, andbaseRef. Noreopenfield exists, andOpenWorkspaceOptionsin src/workspaces.ts carries onlyconversationScopeHash.Without that input there is no way to force a new workspace inside one ChatGPT conversation. docs/chatgpt-coding-workflow.md line 34 still lists "the user explicitly asks to reopen" as a reopen trigger, but a repeated call now returns the existing
workspaceIdand omits bootstrap details. A user request to reopen therefore cannot be satisfied.Add a
reopenboolean to the input schema, forward it throughOpenWorkspaceOptions, and bypass the binding lookup when it is set.🤖 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/server.ts` around lines 755 - 772, Add an optional boolean reopen field to the workspace tool input schema and OpenWorkspaceOptions, then propagate it through the workspace-opening flow. Update the binding lookup logic to bypass the existing workspace when reopen is true, while preserving normal reuse behavior when it is false or omitted.
🤖 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/workspaces.ts`:
- Around line 100-121: Make concurrent conversation-scoped opens deterministic
by updating openWorkspace in src/workspaces.ts#L100-L121 to register the
in-flight promise synchronously, keyed by conversationScopeHash, and compute
targetKey inside that promise; retain cleanup of the exact registered promise.
Update src/workspaces.test.ts#L194-L208 to assert order-independent results:
both calls share one workspace.id and workspace.root, and exactly one result has
includeBootstrapContext === true.
---
Outside diff comments:
In `@src/server.ts`:
- Around line 755-772: Add an optional boolean reopen field to the workspace
tool input schema and OpenWorkspaceOptions, then propagate it through the
workspace-opening flow. Update the binding lookup logic to bypass the existing
workspace when reopen is true, while preserving normal reuse behavior when it is
false or omitted.
🪄 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: e525385f-701f-49ca-a756-40126f1e95cc
📒 Files selected for processing (13)
docs/chatgpt-coding-workflow.mdpackage.jsonsrc/db/migrations.tssrc/db/schema.tssrc/oauth-store.test.tssrc/request-meta.test.tssrc/request-meta.tssrc/server.tssrc/ui/tool-display.test.tssrc/ui/tool-display.tssrc/workspace-store.tssrc/workspaces.test.tssrc/workspaces.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/workspace-store.ts (1)
144-172: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winAvoid the extra round trip and the unchecked non-null assertion in
setConversationBinding.After
.onConflictDoUpdate(...).run(), the method re-queries withthis.getConversationBinding(...)!. This adds an extra database round trip. The!only affects the type; it performs no runtime check. IfgetConversationBindingever returnsundefinedat that point (for example, a delete of the binding races with this call), the method returnsundefinedtyped asWorkspaceConversationBinding, and a caller can later dereference it and crash.drizzle-orm supports
.returning()after.onConflictDoUpdate()for SQLite, including composite-key targets. Use it to fetch the affected row from the same statement.♻️ Proposed fix using `.returning()`
setConversationBinding(input: { conversationScopeHash: string; targetKey: string; workspaceSessionId: string; }): WorkspaceConversationBinding { const now = new Date().toISOString(); - this.database.db + const [row] = this.database.db .insert(workspaceConversationBindings) .values({ conversationScopeHash: input.conversationScopeHash, targetKey: input.targetKey, workspaceSessionId: input.workspaceSessionId, createdAt: now, lastUsedAt: now, }) .onConflictDoUpdate({ target: [ workspaceConversationBindings.conversationScopeHash, workspaceConversationBindings.targetKey, ], set: { workspaceSessionId: input.workspaceSessionId, lastUsedAt: now, }, }) - .run(); - - return this.getConversationBinding(input.conversationScopeHash, input.targetKey)!; + .returning() + .all(); + + return rowToWorkspaceConversationBinding(row); }Please confirm
.returning()behaves as expected with thebetter-sqlite3driver at drizzle-orm 0.45.2 before applying.🤖 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-store.ts` around lines 144 - 172, Update setConversationBinding to append Drizzle’s returning() to the insert/onConflictDoUpdate statement and capture the affected row from run(), eliminating the follow-up getConversationBinding query and its non-null assertion. Preserve the composite conflict target and return the returned WorkspaceConversationBinding, with explicit handling if the statement unexpectedly returns no row.src/server.ts (1)
896-902: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueReport
skillDiagnosticsas 0 for reused workspaces.The other summary counts derive from the suppressed collections and become 0 on reuse.
skillDiagnosticsstill reportsworkspace.skillDiagnostics.length, so the card can advertise diagnostics that the response omits.♻️ Proposed summary alignment
- skillDiagnostics: workspace.skillDiagnostics.length, + skillDiagnostics: includeBootstrapContext ? workspace.skillDiagnostics.length : 0,🤖 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/server.ts` around lines 896 - 902, Update the summary construction around the reused workspace handling so the skillDiagnostics count is reported as 0 when reused, matching the suppressed diagnostics collection in the response; retain workspace.skillDiagnostics.length for non-reused workspaces.src/workspaces.ts (1)
139-154: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueClean up the orphaned workspace session when a binding is discarded.
The recovery path removes the in-memory entry and the binding row. It leaves the persisted
workspaceSessionsrow, so stale rows accumulate for every discarded binding. Thecatchblock also hides the recovery reason, which makes allowed-root or filesystem problems hard to diagnose.Consider deleting or marking the session record and logging the discarded binding at debug level. Do you want me to open an issue to track session cleanup for discarded bindings?
🤖 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 139 - 154, Update the discarded-binding recovery path in the workspace binding logic to also remove or mark deleted the persisted workspace session associated with binding.workspaceSessionId, alongside the existing in-memory and binding cleanup. Replace the empty catch in this path with debug-level logging that includes the binding/session identifiers and the failure details, while preserving recovery by discarding the unusable binding.
🤖 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/workspaces.test.ts`:
- Around line 194-208: Update the concurrent open assertions in the
persistentRegistry.openWorkspace test to avoid assuming which result has
includeBootstrapContext true. Assert that both results share the same workspace
identity and that exactly one result includes bootstrap context, while
preserving the existing shared-root and agent-file assertions.
---
Nitpick comments:
In `@src/server.ts`:
- Around line 896-902: Update the summary construction around the reused
workspace handling so the skillDiagnostics count is reported as 0 when reused,
matching the suppressed diagnostics collection in the response; retain
workspace.skillDiagnostics.length for non-reused workspaces.
In `@src/workspace-store.ts`:
- Around line 144-172: Update setConversationBinding to append Drizzle’s
returning() to the insert/onConflictDoUpdate statement and capture the affected
row from run(), eliminating the follow-up getConversationBinding query and its
non-null assertion. Preserve the composite conflict target and return the
returned WorkspaceConversationBinding, with explicit handling if the statement
unexpectedly returns no row.
In `@src/workspaces.ts`:
- Around line 139-154: Update the discarded-binding recovery path in the
workspace binding logic to also remove or mark deleted the persisted workspace
session associated with binding.workspaceSessionId, alongside the existing
in-memory and binding cleanup. Replace the empty catch in this path with
debug-level logging that includes the binding/session identifiers and the
failure details, while preserving recovery by discarding the unusable binding.
🪄 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: 8d5a656d-0a46-4528-bd92-fe0506cbb741
📒 Files selected for processing (13)
docs/chatgpt-coding-workflow.mdpackage.jsonsrc/db/migrations.tssrc/db/schema.tssrc/oauth-store.test.tssrc/request-meta.test.tssrc/request-meta.tssrc/server.tssrc/ui/tool-display.test.tssrc/ui/tool-display.tssrc/workspace-store.tssrc/workspaces.test.tssrc/workspaces.ts
|
@coderabbitai full review |
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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/ui/card-types.ts`:
- Around line 52-53: Update isExpandableCard to return true when either
agentProviders or agents is present and non-empty, alongside the existing
expandable-content checks. Add a regression test covering a card containing only
these metadata arrays and verify both fields expose the expansion affordance.
🪄 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: 45a10ac5-c984-44d4-a437-04754c3ff418
📒 Files selected for processing (6)
docs/chatgpt-coding-workflow.mdsrc/server.tssrc/ui/card-types.tssrc/ui/tool-display.test.tssrc/workspaces.test.tssrc/workspaces.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- docs/chatgpt-coding-workflow.md
- src/server.ts
- src/workspaces.ts
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
src/workspace-store.ts (1)
144-172: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick winUse
.returning()to avoid a redundant query and a non-null assertion.
setConversationBindingperformsinsert().onConflictDoUpdate()and then issues a separategetConversationBindingcall with a non-null assertion (!) to obtain the result. Drizzle's SQLite dialect supports.returning()directly after.onConflictDoUpdate(), including with a composite conflict target. Use it to return the upserted row from the same statement, removing the extra round-trip and the assumption that the row still exists when the second query runs.♻️ Proposed refactor using `.returning()`
setConversationBinding(input: { conversationScopeHash: string; targetKey: string; workspaceSessionId: string; }): WorkspaceConversationBinding { const now = new Date().toISOString(); - this.database.db + const [row] = this.database.db .insert(workspaceConversationBindings) .values({ conversationScopeHash: input.conversationScopeHash, targetKey: input.targetKey, workspaceSessionId: input.workspaceSessionId, createdAt: now, lastUsedAt: now, }) .onConflictDoUpdate({ target: [ workspaceConversationBindings.conversationScopeHash, workspaceConversationBindings.targetKey, ], set: { workspaceSessionId: input.workspaceSessionId, lastUsedAt: now, }, }) - .run(); - - return this.getConversationBinding(input.conversationScopeHash, input.targetKey)!; + .returning() + .all(); + + return rowToWorkspaceConversationBinding(row); }🤖 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-store.ts` around lines 144 - 172, Update setConversationBinding to chain returning() after onConflictDoUpdate(), capture the single returned workspace conversation binding, and return it directly. Remove the separate getConversationBinding call and its non-null assertion while preserving the existing insert values and composite conflict target.src/request-meta.ts (1)
11-20: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winConsider a keyed hash for real anonymization.
openAiConversationScopeHashuses a plain, unkeyed SHA-256 hash. The"openai"prefix is a public constant, so it adds no secrecy. Anyone with a candidate session string can recompute the same hash and confirm a match against the persistedconversationScopeHashcolumn.Use HMAC-SHA256 with a server-local secret instead of a plain hash. This prevents offline correlation of persisted conversation scopes if the database is ever exposed, and keeps hash determinism per install.
Confirm whether
openai/sessionvalues are guaranteed to be high-entropy, opaque identifiers. If they are predictable or low-entropy, the current unkeyed hash provides weaker protection than the "anonymized" claim implies.🔒 Proposed HMAC-based fix
-import { createHash } from "node:crypto"; +import { createHmac } from "node:crypto"; + +const CONVERSATION_SCOPE_SECRET = + process.env.DEVSPACE_CONVERSATION_SCOPE_SECRET ?? "devspace-conversation-scope"; export function openAiConversationScopeHash( meta: Record<string, unknown> | undefined, ): string | undefined { const session = metadataString(meta, "openai/session"); if (!session) return undefined; - return createHash("sha256") - .update(JSON.stringify(["openai", session])) - .digest("hex"); + return createHmac("sha256", CONVERSATION_SCOPE_SECRET) + .update(JSON.stringify(["openai", session])) + .digest("hex"); }🤖 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/request-meta.ts` around lines 11 - 20, Update openAiConversationScopeHash to use deterministic HMAC-SHA256 with a server-local secret instead of the unkeyed createHash flow, preserving undefined behavior when openai/session is absent. Reuse the project’s established secret/configuration source and confirm whether session values are opaque high-entropy identifiers; ensure the resulting digest remains stable per installation.src/ui/tool-display.test.ts (1)
28-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winThese reuse cases do not exercise any reuse behavior.
src/server.tsLines 910-918 build the card summary frommode,agentsFiles,availableAgentsFiles,skills,agentProviders,agents, andskillDiagnostics. It never setsreused.getToolDisplayignoressummaryentirely, andgetToolHeaderSummaryreads onlymode,agentsFiles, andskills. Both assertions therefore pass for a key that no producer emits, so they pin no reuse contract.Choose one option:
- Add
reusedto the card summary insrc/server.tsand toToolHeaderSummaryhandling if the widget should show reuse.- Remove
reusedfrom these test cards to keep the fixtures aligned with the emitted summary.Also applies to: 102-108
🤖 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/tool-display.test.ts` around lines 28 - 31, Align the reuse test fixtures with the actual card-summary contract: either add and propagate reused through the server card summary and ToolHeaderSummary/getToolDisplay handling if reuse should affect the widget, or remove summary.reused from both assertions if it is not emitted. Keep the chosen behavior consistent across the affected tests and production symbols.
🤖 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/server.ts`:
- Around line 811-816: Update the workspace setup around
reviewCheckpoints.initializeWorkspace so persisted workspaces are initialized
whenever reviewChanges/show_changes may access them, including when
includeBootstrapContext is false. Register or initialize the workspace before
the config.widgets === "changes" and includeBootstrapContext gate, while
preserving the existing initialization inputs and avoiding duplicate
initialization.
In `@src/workspaces.test.ts`:
- Around line 209-210: Update the concurrent open assertions in the workspace
test to avoid assuming which Promise.all result receives bootstrap context.
Assert that both results share the same workspace identity and that exactly one
concurrent open includes bootstrap context, preserving the existing behavior
without checking a fixed result order.
---
Nitpick comments:
In `@src/request-meta.ts`:
- Around line 11-20: Update openAiConversationScopeHash to use deterministic
HMAC-SHA256 with a server-local secret instead of the unkeyed createHash flow,
preserving undefined behavior when openai/session is absent. Reuse the project’s
established secret/configuration source and confirm whether session values are
opaque high-entropy identifiers; ensure the resulting digest remains stable per
installation.
In `@src/ui/tool-display.test.ts`:
- Around line 28-31: Align the reuse test fixtures with the actual card-summary
contract: either add and propagate reused through the server card summary and
ToolHeaderSummary/getToolDisplay handling if reuse should affect the widget, or
remove summary.reused from both assertions if it is not emitted. Keep the chosen
behavior consistent across the affected tests and production symbols.
In `@src/workspace-store.ts`:
- Around line 144-172: Update setConversationBinding to chain returning() after
onConflictDoUpdate(), capture the single returned workspace conversation
binding, and return it directly. Remove the separate getConversationBinding call
and its non-null assertion while preserving the existing insert values and
composite conflict target.
🪄 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: ac3719ff-95f2-4b9e-81c2-7f8d8846f21b
📒 Files selected for processing (13)
docs/chatgpt-coding-workflow.mdpackage.jsonsrc/db/migrations.tssrc/db/schema.tssrc/oauth-store.test.tssrc/request-meta.test.tssrc/request-meta.tssrc/server.tssrc/ui/card-types.tssrc/ui/tool-display.test.tssrc/workspace-store.tssrc/workspaces.test.tssrc/workspaces.ts
|
@coderabbitai full review |
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/review-checkpoints.test.ts (1)
43-52: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtend the restart test to also cover
workspace_openpreservation.This test confirms that
since: "last_shown"(baselineRef) survives a manager restart.initializeWorkspaceStateinsrc/review-checkpoints.ts(lines 137-149) independently preservesopenRefandbaselineRefbased on separatehasCommitRefchecks. Add an assertion forsince: "workspace_open"after restart, so the test verifies both refs survive restart, not only the default one.🧪 Suggested addition
assert.equal(afterRestart.summary.files, 2); assert.match(afterRestart.patch, /world/); + + const sinceOpen = await restartedManager.reviewChanges({ + workspaceId: "ws_review", + root, + since: "workspace_open", + markReviewed: false, + }); + assert.equal(sinceOpen.summary.files, 2);🤖 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 43 - 52, Extend the restart scenario in the review checkpoint test after the existing restartedManager review to call reviewChanges with since: "workspace_open" and markReviewed: false, then assert the result matches the expected workspace-open baseline (including the appropriate file count or patch content). Keep the existing last_shown assertions 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 120-163: Update the reviewChanges state lookup to treat a cached
WorkspaceReviewState as ready only when it has either gitRoot or diagnostic;
when both are absent, re-enter initializeWorkspace so the existing
initialization promise is awaited instead of rejecting prematurely. Preserve the
existing deduplication behavior for concurrent workspace initialization and use
the relevant state/cache symbols already in the reviewChanges flow.
---
Nitpick comments:
In `@src/review-checkpoints.test.ts`:
- Around line 43-52: Extend the restart scenario in the review checkpoint test
after the existing restartedManager review to call reviewChanges with since:
"workspace_open" and markReviewed: false, then assert the result matches the
expected workspace-open baseline (including the appropriate file count or patch
content). Keep the existing last_shown assertions unchanged.
🪄 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: 3b4d0541-f32c-4dc9-aeae-39ff81fcfce1
📒 Files selected for processing (3)
src/review-checkpoints.test.tssrc/review-checkpoints.tssrc/server.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/server.ts
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/review-checkpoints.ts (1)
120-134: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winPublish the workspace state only after initialization resolves.
Line 127 inserts an incomplete state into the shared
statesmap beforegetGitEligibilityruns.reviewChangestreats any present state as ready: it checksif (!state)at line 82, so it skipsinitializeWorkspace, then fails at line 87 on!state?.gitRoot. Ashow_changescall that overlaps an in-flightopen_workspaceinitialization therefore throws "show_changes requires a Git workspace in this version." even though initialization is about to succeed.The previous fix hardened the
initializeWorkspacefast path, but the early publication at line 127 is the root cause andreviewChangesstill reads the map directly. Build the state locally and insert it once, aftergitRootordiagnosticis set.🛡️ Proposed fix to remove the incomplete-state window
const refs = reviewRefs(workspaceId); const state: WorkspaceReviewState = { root, ...refs }; - states.set(workspaceId, state); try { const eligibility = await getGitEligibility(root); if (!eligibility.ok || !eligibility.gitRoot) { state.diagnostic = eligibility.message ?? "show_changes requires a Git workspace in this version."; return; } @@ } catch (error) { state.diagnostic = error instanceof Error ? error.message : String(error); + } finally { + states.set(workspaceId, state); } }🤖 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.ts` around lines 120 - 134, Update initializeWorkspaceState so the WorkspaceReviewState remains local while getGitEligibility and the subsequent initialization complete; move states.set(workspaceId, state) to the point after either gitRoot or diagnostic has been assigned. Preserve the existing initialized state contents and diagnostic behavior, ensuring reviewChanges never observes an incomplete state.
🧹 Nitpick comments (1)
src/workspace-store.ts (1)
144-202: 🗄️ Data Integrity & Integration | 🔵 TrivialAdd retention for unused
workspace_conversation_bindings.
workspace_conversation_bindingsaccumulates one row per conversation/target unless the same binding is reused or the linkedworkspace_sessionis deleted.last_used_atis updated, but no query or prune deletes stale binding rows, and no index covers it. Add alast_used_at-based cleanup path plus an index if this table is expected to grow long-term.🤖 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-store.ts` around lines 144 - 202, The workspace conversation binding store updates lastUsedAt but never removes stale rows or indexes that timestamp. Add a lastUsedAt index to the workspaceConversationBindings schema and implement a cleanup method that deletes bindings older than a supplied retention cutoff, preserving active bindings; expose the cleanup through the store’s existing maintenance path if one exists.
🤖 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/workspaces.ts`:
- Around line 137-166: Limit the try/catch in openConversationWorkspace to
validating the persisted binding: resolving the workspace, checking
workspace.root with stat, and determining whether it is a directory. Move
reusedWorkspaceContext(workspace) outside the try so errors from context
initialization, including agent/profile loading, propagate without deleting the
healthy binding or creating a replacement workspace. Preserve
touchConversationBinding and the existing cleanup behavior only when binding
validation fails.
- Around line 179-190: The reusedWorkspaceContext method should skip
loadInitialAgentsFiles and findAvailableAgentsFiles when includeBootstrapContext
is false, while preserving agentProfiles loading. Return empty agentsFiles and
availableAgentsFiles arrays for reused contexts, and update the reboundWorkspace
and concurrent worktree reuse assertions in the workspace tests to expect the
empty results.
---
Duplicate comments:
In `@src/review-checkpoints.ts`:
- Around line 120-134: Update initializeWorkspaceState so the
WorkspaceReviewState remains local while getGitEligibility and the subsequent
initialization complete; move states.set(workspaceId, state) to the point after
either gitRoot or diagnostic has been assigned. Preserve the existing
initialized state contents and diagnostic behavior, ensuring reviewChanges never
observes an incomplete state.
---
Nitpick comments:
In `@src/workspace-store.ts`:
- Around line 144-202: The workspace conversation binding store updates
lastUsedAt but never removes stale rows or indexes that timestamp. Add a
lastUsedAt index to the workspaceConversationBindings schema and implement a
cleanup method that deletes bindings older than a supplied retention cutoff,
preserving active bindings; expose the cleanup through the store’s existing
maintenance path if one exists.
🪄 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: 5d2ba1a0-3114-4e2f-b8e1-ce666cadf55f
📒 Files selected for processing (16)
docs/chatgpt-coding-workflow.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-store.tssrc/workspaces.test.tssrc/workspaces.ts
|
✅ Action performedFull review finished. |
[GPT-5.6 Thinking] RESPONDING ON BEHALF OF WAISHNAVMerged current @coderabbitai full review |
|
✅ Action performedFull review finished. |
[GPT-5.6 Thinking] RESPONDING ON BEHALF OF WAISHNAVFollow-up CI fix in @coderabbitai full review |
|
✅ Action performedFull review finished. |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/review-checkpoints.test.ts (1)
82-82: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert that the baseline ref exists before deleting it.
git update-ref -dexits successfully when the ref is absent. Line 82 hardcodes the ref name, while the production code derives it throughsafeWorkspaceRefSegment. If that naming changes, this line deletes nothing, the partial-restore branch is never exercised, and the test still passes.Verify the ref resolves before the deletion.
💚 Proposed hardening
+ await git(root, ["rev-parse", "--verify", "refs/devspace/review/ws_review/baseline^{commit}"]); await git(root, ["update-ref", "-d", "refs/devspace/review/ws_review/baseline"]);🤖 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` at line 82, Update the deletion setup in the review-checkpoint test to derive the baseline ref using the same safeWorkspaceRefSegment-based naming as production, then verify that ref resolves before invoking git update-ref -d. Make the test fail explicitly when the expected baseline ref is absent so the partial-restore branch is genuinely exercised.
🤖 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 `@docs/chatgpt-coding-workflow.md`:
- Around line 36-40: Add checkout/worktree mode changes to the reopen conditions
in the open_workspace guidance, alongside unknown workspaceId, project-folder
changes, and requests for a new isolated worktree. Keep the existing conditions
unchanged and ensure the documented behavior matches the corresponding rules in
src/server.ts and AGENTS.md.
In `@src/request-meta.ts`:
- Around line 1-13: Update openAiConversationScopeId and the reusable
conversation-binding flow so the client-provided _meta value alone cannot
determine workspace reuse; accept openai/session only when verified against an
explicitly trusted ChatGPT identity token/context, or incorporate authenticated
client identity into the binding key. Preserve reuse only for requests sharing
the same authenticated identity and validated session scope.
In `@src/workspaces.ts`:
- Around line 172-178: Update the reusable workspace branch in the
workspace-opening method to await reusedWorkspaceContext before calling
store?.claimConversationBootstrap. Apply the claimed boolean to the constructed
context result’s includeBootstrapContext field, preserving
touchConversationBinding and existing fallback behavior.
---
Nitpick comments:
In `@src/review-checkpoints.test.ts`:
- Line 82: Update the deletion setup in the review-checkpoint test to derive the
baseline ref using the same safeWorkspaceRefSegment-based naming as production,
then verify that ref resolves before invoking git update-ref -d. Make the test
fail explicitly when the expected baseline ref is absent so the partial-restore
branch is genuinely exercised.
🪄 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: 7b2fc268-7ad5-4b6e-8e9b-c1435466c9e7
📒 Files selected for processing (17)
AGENTS.mddocs/chatgpt-coding-workflow.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-store.tssrc/workspaces.test.tssrc/workspaces.ts
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
src/workspaces.ts (1)
172-178: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winClaim the bootstrap after the reused context is built.
Line 176 evaluates
claimConversationBootstrapbeforereusedWorkspaceContextruns its body. IfloadLocalAgentProfiles,loadInitialAgentsFiles, orfindAvailableAgentsFilesthrows, the claim is already consumed. The call rejects, and every later open for the sameconversationScopeIdandprojectKeyreceivesincludeBootstrapContext: false. The bootstrap payload is then never delivered for that project in that conversation.
src/workspaces.test.tslines 183-202 reach this failure path. That test asserts the binding survives, but it does not assert that the bootstrap claim survives.Build the context first, then claim, then attach the flag.
The new-workspace branch at lines 190-194 is already safe, because nothing after the claim can throw.
🐛 Proposed fix for the claim ordering
if (reusableWorkspace) { this.store?.touchConversationBinding(conversationScopeId, targetKey); - return await this.reusedWorkspaceContext( - reusableWorkspace, - this.store?.claimConversationBootstrap(conversationScopeId, projectKey) ?? true, - ); + const reused = await this.reusedWorkspaceContext(reusableWorkspace, true); + return { + ...reused, + includeBootstrapContext: + this.store?.claimConversationBootstrap(conversationScopeId, projectKey) ?? 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/workspaces.ts` around lines 172 - 178, Update the reusable-workspace branch in the workspace-opening flow to build the result with reusedWorkspaceContext before calling claimConversationBootstrap, so failures during context construction do not consume the claim. After the context is built, claim using conversationScopeId and projectKey, then attach the resulting includeBootstrapContext flag to the returned context; preserve touchConversationBinding and the new-workspace branch behavior.
🤖 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 `@docs/chatgpt-coding-workflow.md`:
- Around line 20-23: Update the session-scope retention statement in the ChatGPT
workflow documentation to say that DevSpace persists a derived hash of the
opaque openai/session metadata, not the raw session identifier. Keep the
correlation-scope and workspaceId reuse behavior unchanged.
In `@src/review-checkpoints.ts`:
- Around line 55-60: Update the existing-state readiness checks in
initializeWorkspace and the corresponding reviewChanges flow to treat only a
defined existingState.gitRoot as initialized; do not use
existingState.diagnostic to short-circuit eligibility retries. Preserve the
diagnostic as the latest failure, and add a regression covering an unborn
repository that receives its first commit before reviewChanges is called again
with the same manager.
---
Duplicate comments:
In `@src/workspaces.ts`:
- Around line 172-178: Update the reusable-workspace branch in the
workspace-opening flow to build the result with reusedWorkspaceContext before
calling claimConversationBootstrap, so failures during context construction do
not consume the claim. After the context is built, claim using
conversationScopeId and projectKey, then attach the resulting
includeBootstrapContext flag to the returned context; preserve
touchConversationBinding and the new-workspace branch behavior.
🪄 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: 492ecee9-d739-4c18-b6a5-05b1fd8dbb5f
📒 Files selected for processing (16)
docs/chatgpt-coding-workflow.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-store.tssrc/workspaces.test.tssrc/workspaces.ts
[GPT-5.6 Thinking] RESPONDING ON BEHALF OF WAISHNAVPushed the final review follow-ups on head
I did not adopt the request to transform Verification on @coderabbitai full review |
|
✅ Action performedFull review finished. |
[GPT-5.6 Thinking] RESPONDING ON BEHALF OF WAISHNAVFinal follow-up pushed on head The review comment describing a persisted derived hash is obsolete against the final branch: @coderabbitai full review |
|
✏️ Learnings added
✅ Action performedFull review finished. |
There was a problem hiding this comment.
♻️ Duplicate comments (1)
src/review-checkpoints.ts (1)
58-63: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winReadiness includes
diagnostic, so eligibility never retries.initializeWorkspaceandisInitializedStateboth accept a defineddiagnosticas initialized. A workspace that fails eligibility once keeps returning that diagnostic for the lifetime of the manager, even after the repository becomes eligible.
src/review-checkpoints.ts#L58-L63: dropexistingState.diagnostic !== undefinedfrom the early return, and changeisInitializedStateat Lines 178-180 to test onlygitRoot.src/review-checkpoints.test.ts#L116-L138: add a case that initializes a repository withoutHEAD, creates the first commit, and then callsreviewChangeson the same manager.🤖 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.ts` around lines 58 - 63, Update src/review-checkpoints.ts: in the existing-state early return around initializeWorkspace, stop treating existingState.diagnostic as initialized, and change isInitializedState to check only gitRoot so failed eligibility can be retried. Add a test in src/review-checkpoints.test.ts covering initialization without HEAD, creating the first commit, then calling reviewChanges on the same manager.
🧹 Nitpick comments (1)
src/review-checkpoints.test.ts (1)
116-138: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a regression for eligibility retry after a diagnostic.
The added cases cover partial ref loss well. They do not cover a cached diagnostic. Add a case that initializes a repository without
HEAD, creates the first commit, and then callsreviewChangeswith the same manager. That case currently fails because the manager treats a defineddiagnosticas initialized. See the related comment onsrc/review-checkpoints.ts.🤖 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 116 - 138, Extend the review checkpoint tests with a cached-diagnostic regression: initialize a repository without HEAD, create its first commit, then call reviewChanges again using the same manager and verify eligibility succeeds. Anchor the case around createReviewCheckpointManager, initializeWorkspace, and reviewChanges, ensuring a defined diagnostic does not prevent retrying initialization after the repository becomes eligible.
🤖 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.
Duplicate comments:
In `@src/review-checkpoints.ts`:
- Around line 58-63: Update src/review-checkpoints.ts: in the existing-state
early return around initializeWorkspace, stop treating existingState.diagnostic
as initialized, and change isInitializedState to check only gitRoot so failed
eligibility can be retried. Add a test in src/review-checkpoints.test.ts
covering initialization without HEAD, creating the first commit, then calling
reviewChanges on the same manager.
---
Nitpick comments:
In `@src/review-checkpoints.test.ts`:
- Around line 116-138: Extend the review checkpoint tests with a
cached-diagnostic regression: initialize a repository without HEAD, create its
first commit, then call reviewChanges again using the same manager and verify
eligibility succeeds. Anchor the case around createReviewCheckpointManager,
initializeWorkspace, and reviewChanges, ensuring a defined diagnostic does not
prevent retrying initialization after the repository becomes eligible.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: fb610c40-bfbc-4c06-b9aa-7760d3140158
📒 Files selected for processing (16)
docs/chatgpt-coding-workflow.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-store.tssrc/workspaces.test.tssrc/workspaces.ts
There was a problem hiding this comment.
🧹 Nitpick comments (2)
src/review-checkpoints.test.ts (1)
147-150: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winTighten the rejection matcher for the unborn repository case.
The regex
/commit|HEAD|Git/imatches every diagnostic this path can produce, including "workspace is not inside a git repository" and the generic fallback "show_changes requires a Git workspace in this version.". The test can then pass when eligibility fails for the wrong reason.getGitEligibilityreturns "repository has no HEAD commit" for an unborn repository, so assert that message.♻️ Proposed change
await assert.rejects( () => unbornManager.reviewChanges({ workspaceId: "ws_unborn", root: unbornRoot }), - /commit|HEAD|Git/i, + /no HEAD commit/, );🤖 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 147 - 150, In the unborn repository rejection test for unbornManager.reviewChanges, replace the broad /commit|HEAD|Git/i matcher with an assertion targeting the exact getGitEligibility message “repository has no HEAD commit,” so failures for unrelated workspace or fallback diagnostics do not satisfy the test.src/workspaces.ts (1)
439-453: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAvoid the in-place
reverse()inside the loop.
missingSegments.reverse()mutates the array. Today it runs only on the successful iteration, becauseawait realpath(candidate)is evaluated before the spread argument. That correctness depends on argument evaluation order relative to theawait. A later reorder, for example hoisting therealpathresult into a variable placed after the spread, would reverse the array on each retry and corrupt the key.Use a non-mutating copy.
♻️ Proposed non-mutating variant
while (true) { try { - return resolve(await realpath(candidate), ...missingSegments.reverse()); + const resolvedPrefix = await realpath(candidate); + return resolve(resolvedPrefix, ...missingSegments.slice().reverse()); } catch {🤖 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 439 - 453, Update canonicalPath to avoid mutating missingSegments when restoring the collected path components: replace the in-place reverse operation with a non-mutating reversed copy while preserving the existing realpath retry and resolution behavior.
🤖 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.
Nitpick comments:
In `@src/review-checkpoints.test.ts`:
- Around line 147-150: In the unborn repository rejection test for
unbornManager.reviewChanges, replace the broad /commit|HEAD|Git/i matcher with
an assertion targeting the exact getGitEligibility message “repository has no
HEAD commit,” so failures for unrelated workspace or fallback diagnostics do not
satisfy the test.
In `@src/workspaces.ts`:
- Around line 439-453: Update canonicalPath to avoid mutating missingSegments
when restoring the collected path components: replace the in-place reverse
operation with a non-mutating reversed copy while preserving the existing
realpath retry and resolution behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 2a42c706-77cc-465a-af13-552506e7d878
📒 Files selected for processing (16)
docs/chatgpt-coding-workflow.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-store.tssrc/workspaces.test.tssrc/workspaces.ts
[GPT-5.6 Thinking] RESPONDING ON BEHALF OF WAISHNAVPushed Full tests, typecheck, production build, and diff checks pass locally. @coderabbitai full review |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/workspaces.test.ts (1)
365-369: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAssert
workspaceReusedfor the aliased open.The aliased open is the case that must prove alias-to-canonical reuse. The test checks
includeBootstrapContextand the workspace id, but notworkspaceReused. The parallel stale-alias case at Line 381 does check it. Add the flag assertion so a regression that returns a new workspace with a copied id cannot pass.♻️ Proposed additional assertion
assert.equal(aliasedConversationWorkspace.includeBootstrapContext, false); + assert.equal(aliasedConversationWorkspace.workspaceReused, true); assert.equal( aliasedConversationWorkspace.workspace.id, directConversationWorkspace.workspace.id, );🤖 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.test.ts` around lines 365 - 369, Add an assertion for the workspaceReused flag in the aliased open test case at lines 365-369. Reference the stale-alias case at line 381 which already includes this assertion and apply the same pattern. This assertion is necessary to ensure the test catches regressions where a new workspace is returned with a copied id instead of truly reusing the canonical workspace through the alias.
🤖 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/ui/workspace-app.tsx`:
- Around line 504-514: Update the unavailable-reason handling near agent
rendering in workspace-app.tsx to use a truthy fallback when
agent.providerUnavailableReason is empty, ensuring the unavailable marker
remains present instead of being removed by filter(Boolean).
---
Nitpick comments:
In `@src/workspaces.test.ts`:
- Around line 365-369: Add an assertion for the workspaceReused flag in the
aliased open test case at lines 365-369. Reference the stale-alias case at line
381 which already includes this assertion and apply the same pattern. This
assertion is necessary to ensure the test catches regressions where a new
workspace is returned with a copied id instead of truly reusing the canonical
workspace through the alias.
🪄 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: 56277d7e-f79f-4e3b-ab16-6ae88dbaf930
📒 Files selected for processing (16)
docs/chatgpt-coding-workflow.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-store.tssrc/workspaces.test.tssrc/workspaces.ts
ChatGPT can issue
open_workspacemore than once for the same project during one conversation. Returning the full bootstrap every time repeats project instructions, nested instruction paths, skills, subagent metadata, and diagnostics in the model context.DevSpace now treats workspace lifecycle and bootstrap delivery as separate concerns:
show_changes.The implementation canonicalizes project paths, makes concurrent project-bootstrap claims atomic, validates restored checkout roots, and keeps worktree calls independent. Tests cover checkout reuse, fresh sequential and concurrent worktrees, both cross-mode directions, aliases, stale roots, persistence, checkpoint restoration, migration backfill, and UI display behavior.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Tests