Skip to content

feat: external agent detection, worktree agents, and macOS fixes#141

Open
noam971 wants to merge 7 commits intopablodelucca:devfrom
noam971:feat/external-agents-and-fixes
Open

feat: external agent detection, worktree agents, and macOS fixes#141
noam971 wants to merge 7 commits intopablodelucca:devfrom
noam971:feat/external-agents-and-fixes

Conversation

@noam971
Copy link

@noam971 noam971 commented Mar 15, 2026

Description

Adds automatic detection of Claude sessions started outside the extension, a worktree agent launcher, and fixes several macOS bugs that caused agents to point to the wrong terminals.

Type of change

  • Bug fix
  • New feature

New Features

External agent detection — sessions started outside the "+" button now appear automatically:

  • VS Code terminal (claude typed manually): character created and correctly bound to that terminal, even when multiple terminals share the name "claude"
  • Ghostty / iTerm2 / external terminals: appear as headless "Ext" agents
  • Claude Code extension background process: correctly identified as headless, not mistaken for a terminal agent
  • Sessions already running when VS Code opens are adopted on startup

Worktree agents — new "⊕ Worktree" button in the bottom toolbar:

  • Prompts for a branch name (default: agent-YYYY-MM-DD-HHmm)
  • Runs git worktree add .worktrees/<branch> -b <branch> and launches Claude in the worktree dir
  • Agent labeled with the branch name; on close, offers to remove the worktree

macOS Bug Fixes

  • ps -o comm= truncation: macOS truncates Code Helper (Plugin) to ~16 chars, causing the extension host to be misclassified as a VS Code terminal. Fixed by using ps -o args= (full binary path).
  • Terminal name collisions: all terminals running claude get renamed to "claude" by VS Code. restoreAgents was matching every agent to the first one found by name. Fixed by persisting claudePid and using shell-PID ancestry matching (restoreAgents is now async).
  • Stale process attribution: long-lived background processes were attributed to newly-created JSONL files. Fixed by skipping processes whose elapsed time exceeds the file age by more than 5 minutes.
  • lsof false positives: fixed by adding -a flag so both conditions are ANDed.
  • Duplicate file watchers: webviewReady fires on every panel focus, re-calling restoreAgents. Agents already in the map are now skipped.

Test plan

  • PR targets dev branch
  • npm run build passes locally
  • Tested in Extension Development Host (F5)
  • No inline constants (all in src/constants.ts or webview-ui/src/constants.ts)

noam971 and others added 5 commits March 15, 2026 14:09
- Detect Claude sessions started outside VS Code (Ghostty, iTerm2, etc.)
  and create headless pixel agents for them
- Walk process tree to distinguish VS Code/Cursor sessions (ignored) from
  external terminal sessions (adopted as headless agents)
- Fix agent jumping: use stat.size as initialOffset for scan-detected sessions
- Fix sendCurrentAgentStatuses timing: send after layoutLoaded so characters
  exist when status messages arrive
- Fix subagent spawning: pass toolName in agentToolStart message and check
  toolName === 'Task' instead of status.startsWith('Subtask:') so tasks with
  no description also spawn subagent characters
- Fix terminal agent status refresh: call readNewLines on onDidChangeActiveTerminal
  so JSONL events missed while terminal was unfocused are processed immediately
- Reduce permission timer delay from 7s to 3s for faster ... bubble appearance
- Fix worktree path: use .worktrees/ inside repo instead of .pixel-worktrees/ outside
- Add Worktree Agent button to BottomToolbar (git repos only)
- Restore agent statuses correctly after VS Code reload

Co-Authored-By: noam971 <noam971@users.noreply.github.com>
When lsof returns a PID for a JSONL file that belongs to a Claude Code
extension session, that PID is the extension host reading the file, not
the claude writer. Code Helper (Plugin) has 'plugin' in its own comm,
so checking the PID's own comm before walking its parents correctly
returns null (ignore) for extension sessions.

Co-Authored-By: noam971 <noam971@users.noreply.github.com>
…for all headless

Key fixes:
- null now only returned for --session-id (+button) agents already tracked
- extension (--output-format) and plugin-parent sessions return EXTERNAL_AGENT_FOLDER_NAME
  instead of null, so they get a headless 'Ext' agent as the user expects
- replace lsof -t -- <file> (returns all readers incl. Pixel Agents own watchers)
  with lsof -p <pid> (per-process, only that process's open files)
- fallback heuristic scans bare/extension claudes via process tree
- adoptExistingJsonlFiles treats VSCODE_TERMINAL_SESSION as headless at startup

Co-Authored-By: noam971 <noam971@users.noreply.github.com>
…e coexist

- ps auxww: prevents --output-format from being truncated in long arg lists
- fallback heuristic: when both extension (--output-format) and bare claudes are
  running simultaneously, return EXTERNAL_AGENT_FOLDER_NAME instead of guessing
  VSCODE_TERMINAL_SESSION — avoids extension JSONL incorrectly adopting a terminal

Co-Authored-By: noam971 <noam971@users.noreply.github.com>
- Use ps args= instead of comm= in walkProcessTree so Code Helper (Plugin)
  isn't truncated to ~16 chars, preventing false vscode_terminal matches
- Add elapsed-time age filter in fallback: skip processes far older than the
  JSONL file (filters out long-lived extension claude processes)
- Persist claudePid in PersistedAgent so it survives webview reloads
- Make restoreAgents async; use shell-PID ancestry matching instead of
  terminal name matching so multiple terminals named "claude" each get the
  correct terminalRef
- Skip already-in-map agents on re-entry to prevent duplicate file watchers
  (webviewReady fires on every panel focus, re-calling restoreAgents)
- findOwningTerminal: use ownedShellPids set (ppid of each agent's claudePid)
  instead of terminalRef equality, which was stale after name-based restore
@noam971 noam971 force-pushed the feat/external-agents-and-fixes branch from bf20faf to 24f291f Compare March 15, 2026 12:10
chkp-noamerez and others added 2 commits March 16, 2026 21:20
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove bun.lock files (duplicate of package-lock.json) and replace
hardcoded local paths in launch.json with generic VS Code variables.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@florintimbuc florintimbuc added type: feature New feature or capability area: agent-connection Agent discovery, session linking, transcript communication platform: macos macOS-specific behavior or fix labels Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: agent-connection Agent discovery, session linking, transcript communication platform: macos macOS-specific behavior or fix type: feature New feature or capability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants