Skip to content

feat: adaptive VS Code resume via IDE lock file polling#109

Merged
grimmerk merged 8 commits intomainfrom
feat/vscode-resume-lock-file-polling
Apr 6, 2026
Merged

feat: adaptive VS Code resume via IDE lock file polling#109
grimmerk merged 8 commits intomainfrom
feat/vscode-resume-lock-file-polling

Conversation

@grimmerk
Copy link
Copy Markdown
Owner

@grimmerk grimmerk commented Apr 6, 2026

Summary

Replace the fixed 2s delay in VS Code session resume with IDE lock file polling for adaptive timing. Fixes duplicate tab bug and non-working resume cases.

Three improvements in one

Improvement Before After
Duplicate tab (cases 3, 5, 7) Always duplicated Fixed — active sessions skip URI handler on window restore
Resume not working (case 2) Window focused but no tab opened Fixed — 500ms delay after window focus
Already-open project latency (cases 1, 2) Fixed 2s delay Instant — lock file detects project already open

Latency comparison (vs PR #103)

Scenario PR #103 This PR Change
Active switch (project open) Instant Instant Same
Resume in already-open project ~2s (fixed delay) ~0.5s (lock file + 500ms) 4x faster
Resume, VS Code open, project closed ~2s (fixed delay) ~2.5s (poll ~1s + 1.5s) Slightly slower but no duplicate
Resume, VS Code cold start ~3-5s (fixed delay) ~3-5s (poll + 1.5s) Similar but adaptive + no duplicate

How it works

User clicks VS Code session in CodeV
        │
        ▼
isVSCodeProjectOpen(projectPath)  ← reads ~/.claude/ide/*.lock
        │
   ┌────┴────┐
  found     not found
   │          │
   ▼          ▼
focus window  open -b (launch/restore)
+ 500ms       │
+ URI handler ├── active session? → done (restore handles tab)
              └── closed session? → poll lock file (250ms interval)
                                    → 1.5s delay (let restore finish)
                                    → URI handler

Test matrix (all 8 cases pass)

# VS Code Project window Session Result Latency Fix
1 Open Open Active ✅ Switch ~0.5s Focus window + 500ms + URI
2 Open Open Closed ✅ Resume ~0.5s Focus window + 500ms + URI
3 Open Closed Closed ✅ Resume ~2.5s open-b + poll ~1s + 1.5s + URI
4 Open Closed Closed ✅ Resume ~2.5s Same as 3
5 Closed Restored Active ✅ Restore ~2-3s open-b only (restore handles tab)
6 Closed Restored Closed ✅ Resume ~3-4s open-b + poll + 1.5s + URI
7 Closed Not restored Active ✅ Restore ~2-3s open-b only (restore handles tab)
8 Closed Not restored Closed ✅ Resume ~3-4s open-b + poll + 1.5s + URI

IDE lock file details

  • ~/.claude/ide/*.lock — created by Claude Code VS Code extension per window
  • Contains workspaceFolders + pid — can verify project is open + VS Code alive
  • Cleaned up on window close; stale files detectable via PID check
  • Fallback to fixed 2s delay if lock dir doesn't exist

Lock file polling vs #106 (JSONL reads) — different problem, different scale

#106 (JSONL reads) Lock file polling
Files per call ~100 JSONLs (tail + grep = spawn process) ~1-60 lock files (~200 bytes JSON)
Read method exec('tail | grep') = child process fs.readFileSync = direct I/O
Cost for 60 files ~300 processes spawned ~1.5ms (pure I/O)

Lock file reads use fs.readFileSync + JSON.parse — no process spawning. Even with 60 VS Code windows open: 60 × 200 bytes = 12KB total I/O ≈ 1.5ms. No need for Rust/native optimization.

Ref: #107

Test plan

  • Case 1: Active switch (instant)
  • Case 2: Resume in open project (500ms)
  • Case 3: Resume, project closed, VS Code open (no duplicate)
  • Case 5: Resume, VS Code quit + restore (no duplicate)
  • Case 7: Resume, VS Code quit + project closed (no duplicate)
  • Cases 6, 8: Resume closed sessions (still working)
  • Lock file dir missing → falls back to 2s delay (same as PR feat: VS Code session support + real-time preview refresh #103 behavior; duplicate tab issue may resurface if extension removes lock file mechanism in future)
  • Performance: no regression (polling is ~0.5ms per check)

🤖 On behalf of @grimmerk — generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Prevents duplicate Claude Code tabs when restoring VS Code windows
    • Improves session resume behavior for already-open projects
    • Fixes session switching to target the correct VS Code window
  • Documentation

    • Updated documentation to reflect adaptive session resume behavior with improved latency (~0.5s for open projects; ~2.5–4s for new projects)

grimmerk and others added 5 commits April 6, 2026 19:27
- isVSCodeProjectOpen(): check lock files for matching
  workspace + alive PID → instant URI handler if found
- waitForVSCodeExtensionReady(): poll every 300ms until
  extension creates lock file (max 8s timeout)
- Fallback to 2s delay if IDE lock dir doesn't exist
- Also applied to launchNewClaudeSession() VS Code path
- Fixes cold-start duplicate tab (waits for extension ready)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Active VS Code sessions were opening new sessions in the
wrong window because openSessionInVSCode was called without
projectPath — URI handler fired into whichever window was
focused. Now always passes projectPath and uses open -b to
focus the correct project window before URI handler.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
open -b callback fires before VS Code window is fully focused,
causing URI handler to silently fail. 500ms delay gives VS Code
time to complete window activation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… delay (cases 3, 5, 7)

- Active VS Code sessions + project not open: only open -b,
  skip URI handler (VS Code restore handles the session tab)
- Closed sessions + project not open: poll + 1.5s post-ready
  delay (lets VS Code finish restoring before URI handler,
  avoids duplicate tab)
- Fixes cases 3, 5, and 7 from test matrix

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

coderabbitai bot commented Apr 6, 2026

📝 Walkthrough

Walkthrough

This PR shifts VS Code session resume timing from fixed 2-second delays to adaptive polling based on IDE lock file detection. The logic now distinguishes between already-open projects (faster focus + URI handler) and cold starts (project launch + polling + 1.5s delay + URI handler), with separate handling for active vs inactive sessions to prevent duplicate tabs.

Changes

Cohort / File(s) Summary
Documentation & Version
CHANGELOG.md, README.md, package.json, docs/vscode-session-support-design.md
Added changelog entries documenting adaptive resume timing, updated terminal support table with ~0.5s polling behavior, bumped version to 1.0.69, and added comprehensive design documentation describing the new lock-file polling flow with measured latencies for both already-open and cold-start cases.
Core Resume Logic
src/claude-session-utility.ts
Introduced isVSCodeProjectOpen() helper to detect project readiness via ~/.claude/ide/*.lock JSON matching, added waitForVSCodeExtensionReady() for adaptive polling with 5s timeout, refactored openSessionInVSCode() to accept isActiveSession flag and branch behavior based on project state, and updated launchNewClaudeSession() to immediately fire URI handler for open projects or poll + delay before URI handler for cold starts.

Sequence Diagram

sequenceDiagram
    participant User as User Action
    participant CS as Claude Session<br/>Utility
    participant VL as VS Code Lock<br/>Detection
    participant VS as VS Code<br/>Instance
    participant EXT as VS Code<br/>Extension

    User->>CS: Open active session (project path provided)
    alt Project Already Open
        CS->>VS: Focus VS Code window
        Note over CS: Wait 500ms
        CS->>EXT: Fire URI handler
        EXT-->>User: Session opens in active VS Code
    else Project Not Open
        CS->>VS: Launch project via open -b
        CS->>VL: Poll ~/.claude/ide/*.lock<br/>(every 250ms, 5s timeout)
        VL-->>CS: Ready (workspaceFolders match + PID alive)
        Note over CS: Wait additional 1500ms
        CS->>EXT: Fire URI handler
        EXT-->>User: Session opens in new window
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Possibly related PRs

Poem

🐰 Poll, poll, hops the rabbit through lock files so keen,
No more two-second waits—just adaptive scene!
Already awake? Quick focus—off we go,
Cold starts get their polling, a thoughtful soft flow.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: replacing fixed 2s delay with adaptive VS Code resume timing based on IDE lock file polling.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/vscode-resume-lock-file-polling

Comment @coderabbitai help to get the list of available commands and usage tips.

grimmerk and others added 3 commits April 6, 2026 20:51
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace outdated '2s fixed delay' references with adaptive
lock file polling description. Add latency numbers and
VS Code-specific resume flow to README terminal table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Consolidates all differences between VS Code and terminal
sessions across every layer (detection, switch, resume,
readiness, restore conflict, etc.) in one table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@grimmerk grimmerk marked this pull request as ready for review April 6, 2026 12:56
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
docs/vscode-session-support-design.md (1)

76-82: Add blank line before table for markdown compliance.

Static analysis indicates the table at line 77 should be surrounded by blank lines (MD058). Add a blank line after "Measured latency:" for consistent markdown rendering.

📝 Suggested fix
 Measured latency:
+
 | Scenario | Time |
 |----------|------|
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/vscode-session-support-design.md` around lines 76 - 82, The markdown
table under the "Measured latency:" header lacks a separating blank line which
triggers MD058; edit the docs/vscode-session-support-design.md content around
the "Measured latency:" heading and insert a single blank line immediately after
the line that reads "Measured latency:" so the pipe-table (starting with "|
Scenario | Time |") is preceded by an empty line, preserving existing text and
spacing elsewhere.
src/claude-session-utility.ts (1)

1414-1423: Consider logging errors from the focus command.

Line 1417 uses an empty callback that ignores potential errors from open -b bundleId projectPath. While this is a fire-and-forget focus operation, logging errors would help with debugging.

♻️ Suggested improvement
-    execFile('open', ['-b', bundleId, projectPath], () => {
+    execFile('open', ['-b', bundleId, projectPath], (error: any) => {
+      if (error) console.error('[openSessionInVSCode] failed to focus window:', error);
       setTimeout(() => {
         execFile('open', [uri]);
       }, 500);
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/claude-session-utility.ts` around lines 1414 - 1423, The callback passed
to execFile when focusing the IDE (inside the isVSCodeProjectOpen check)
swallows errors; update the anonymous callback for execFile('open', ['-b',
bundleId, projectPath], ...) to accept an error parameter and log any error
(using the module's logger or console.error) along with context (include
bundleId and projectPath), so failures from getCurrentIDEBundleId()/execFile are
visible while keeping the existing setTimeout/execFile(uri) behavior intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@docs/vscode-session-support-design.md`:
- Around line 76-82: The markdown table under the "Measured latency:" header
lacks a separating blank line which triggers MD058; edit the
docs/vscode-session-support-design.md content around the "Measured latency:"
heading and insert a single blank line immediately after the line that reads
"Measured latency:" so the pipe-table (starting with "| Scenario | Time |") is
preceded by an empty line, preserving existing text and spacing elsewhere.

In `@src/claude-session-utility.ts`:
- Around line 1414-1423: The callback passed to execFile when focusing the IDE
(inside the isVSCodeProjectOpen check) swallows errors; update the anonymous
callback for execFile('open', ['-b', bundleId, projectPath], ...) to accept an
error parameter and log any error (using the module's logger or console.error)
along with context (include bundleId and projectPath), so failures from
getCurrentIDEBundleId()/execFile are visible while keeping the existing
setTimeout/execFile(uri) behavior intact.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1f097163-2af4-4833-b152-b2f1b6a01176

📥 Commits

Reviewing files that changed from the base of the PR and between 2810eae and cd9cff7.

📒 Files selected for processing (5)
  • CHANGELOG.md
  • README.md
  • docs/vscode-session-support-design.md
  • package.json
  • src/claude-session-utility.ts

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 5 files

@grimmerk grimmerk merged commit 4a00e9a into main Apr 6, 2026
3 checks passed
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.

1 participant