Skip to content

feat: add cwd to surface list API responses - #1287

Open
PabloLION wants to merge 1 commit into
manaflow-ai:mainfrom
PabloLION:feat/surface-list-cwd
Open

PabloLION wants to merge 1 commit into
manaflow-ai:mainfrom
PabloLION:feat/surface-list-cwd

Conversation

@PabloLION

@PabloLION PabloLION commented Mar 12, 2026 •

Copy link
Copy Markdown

Summary

  • Expose per-surface working directory (tracked via OSC 7) in surface.list and pane.surfaces v2 JSON-RPC responses as a new cwd field
  • Motivation: callers need CWD of all surfaces for workspace-aware tooling (e.g., agent orchestration)

Changes

All in Sources/TerminalController.swift:

  1. v2SurfaceList — added "cwd": v2OrNull(ws.panelDirectories[panel.id])
  2. v2PaneSurfaces — added "cwd": v2OrNull(panelId.flatMap { ws.panelDirectories[$0] })

The v1 list_surfaces text format is intentionally left unchanged to avoid breaking existing parsers in tests/cmux.py and cmuxUITests/MultiWindowNotificationsUITests.swift that extract UUIDs by splitting on whitespace.

Test plan

  • Verify surface.list response includes cwd field with correct path
  • Verify pane.surfaces response includes cwd field
  • Verify cwd is null when OSC 7 hasn't reported yet
  • Verify v1 list_surfaces output is unchanged

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added per-surface current working directory metadata to the surface list payload.
    • Added per-surface current working directory metadata to the workspace view payload.
    • Added per-surface current working directory metadata to pane surfaces payloads.
    • These additions provide clearer context for each surface, improving location awareness and navigation without changing existing behavior.

@vercel

vercel Bot commented Mar 12, 2026

Copy link
Copy Markdown

@PabloLION is attempting to deploy a commit to the Manaflow Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Mar 12, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 67d9fac4-5891-4db8-a4c8-06f7d580d494

📥 Commits

Reviewing files that changed from the base of the PR and between 7e3b5d3 and ecbdf84.

📒 Files selected for processing (1)
  • Sources/TerminalController.swift
🚧 Files skipped from review as they are similar to previous changes (1)
  • Sources/TerminalController.swift

📝 Walkthrough

Walkthrough

Added per-surface current working directory (cwd) metadata to three v2 response payloads in TerminalController.swift: v2SurfaceList, v2TreeWorkspaceNode, and v2PaneSurfaces. Each cwd value is sourced from ws.panelDirectories for the corresponding panel ID.

Changes

Cohort / File(s) Summary
V2 Payload Enrichment
Sources/TerminalController.swift
Added a cwd field to v2SurfaceList, v2TreeWorkspaceNode, and v2PaneSurfaces payloads using v2OrNull(ws.panelDirectories[panel.id]) / v2OrNull(panelId.flatMap { ws.panelDirectories[$0] }) to expose per-surface working directory metadata.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

🐰 I hop from pane to pane with glee,
Carrying cwd for all to see,
Through trees and lists I softly tread,
Paths tucked safely where I'm led,
A tiny rabbit, trailing bread crumbs of directory.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly and concisely describes the main change: adding a cwd field to surface list API responses.
Description check ✅ Passed The description covers the summary and changes comprehensively, but the testing section lacks confirmation of actual test execution.
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 unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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

Tip

You can customize the tone of the review comments and chat replies.

Configure the tone_instructions setting to customize the tone of the review comments and chat replies. For example, you can set the tone to Act like a strict teacher, Act like a pirate and more.

@greptile-apps

greptile-apps Bot commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR exposes the per-surface working directory (tracked via OSC 7) in the surface.list and pane.surfaces v2 JSON-RPC responses as a new cwd field, and also appends the CWD to the v1 list_surfaces text output. The v2 changes are clean and consistent with existing patterns. However, the v1 text format change introduces a breaking regression — both the Python test client (tests/cmux.py) and the Swift UI test helper (cmuxUITests/MultiWindowNotificationsUITests.swift) parse the list_surfaces output by naively splitting on whitespace, and will capture "<UUID> /path/to/cwd" as the surface ID instead of just the UUID whenever a CWD has been reported.

Key changes:

  • v2 surface.list (v2SurfaceList): adds "cwd": v2OrNull(ws.panelDirectories[panel.id]) — correct
  • v2 pane.surfaces (v2PaneSurfaces): adds "cwd": v2OrNull(panelId.flatMap { ws.panelDirectories[$0] }) — correct
  • v1 list_surfaces (listSurfaces): appends /path/to/cwd to each line — breaks existing parsers in tests/cmux.py (line 347: surface_id = parts[1]) and cmuxUITests/MultiWindowNotificationsUITests.swift (line 563–565: UUID(uuidString: candidate) returns nil when candidate includes cwd suffix)

Confidence Score: 2/5

  • Not safe to merge — the v1 text format change silently breaks UUID extraction in existing test helpers and will cause test failures and incorrect surface-ID usage at runtime.
  • The v2 JSON additions are correct and additive, but the v1 list_surfaces line format change is backward-incompatible. Two well-established parsers (Python test client and Swift UI test helper) both strip leading markers and then capture everything after "index: " as the surface ID; with the new CWD suffix they will receive a malformed UUID-plus-path string, breaking any subsequent operation that relies on the surface ID. Additionally, the space-delimited format is inherently ambiguous for directory paths that contain spaces.
  • Sources/TerminalController.swift (lines 10763–10764) — the v1 format change; also review tests/cmux.py (lines 344–348) and cmuxUITests/MultiWindowNotificationsUITests.swift (lines 560–567) for required parser updates

Important Files Changed

Filename Overview
Sources/TerminalController.swift Adds cwd field (from panelDirectories) to v2 surface.list and pane.surfaces responses (correct) and appends CWD to the v1 list_surfaces text lines (breaking: existing parsers in tests/cmux.py and cmuxUITests extract the UUID by naive whitespace splitting and will receive a corrupted "<UUID> /path" string instead of a bare UUID)

Sequence Diagram

sequenceDiagram
    participant Client
    participant TerminalController
    participant Workspace

    Note over Client,Workspace: v2 surface.list
    Client->>TerminalController: surface.list {workspace_id}
    TerminalController->>Workspace: panelDirectories[panel.id]
    Workspace-->>TerminalController: String? (OSC 7 path)
    TerminalController-->>Client: {surfaces: [{id, cwd: "/path" | null, ...}]}

    Note over Client,Workspace: v2 pane.surfaces
    Client->>TerminalController: pane.surfaces {pane_id}
    TerminalController->>Workspace: panelDirectories[panelId]
    Workspace-->>TerminalController: String? (OSC 7 path)
    TerminalController-->>Client: {surfaces: [{id, cwd: "/path" | null, ...}]}

    Note over Client,Workspace: v1 list_surfaces (⚠️ breaking)
    Client->>TerminalController: list_surfaces [tab]
    TerminalController->>Workspace: panelDirectories[panel.id]
    Workspace-->>TerminalController: String? (OSC 7 path)
    TerminalController-->>Client: "* 0: UUID /cwd/path\n  1: UUID"
    Note over Client: ⚠️ Parsers split on space and<br/>capture "UUID /cwd/path" as surface_id
Loading

Last reviewed commit: 7e3b5d3

Comment thread Sources/TerminalController.swift Outdated
Comment on lines +10763 to +10764
let cwdSuffix = tab.panelDirectories[panel.id].map { " \($0)" } ?? ""
return "\(selected) \(index): \(panel.id.uuidString)\(cwdSuffix)"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

V1 format change breaks existing parsers

Appending the CWD with a space separator breaks two existing parsers that parse the v1 list_surfaces text output:

1. tests/cmux.py lines 344–348:

parts = line.lstrip("* ").split(" ", 1)
if len(parts) >= 2:
    index = int(parts[0].rstrip(":"))
    surface_id = parts[1]   # ← was UUID alone; now "UUID /cwd/path" when cwd is known

After this PR, when cwd is available, surface_id will be set to "<UUID> /path/to/cwd" instead of just "<UUID>". Every downstream call that passes this string as a surface/panel ID (e.g. focus_surface, close_surface) will silently receive an invalid UUID and fail or behave unexpectedly.

2. cmuxUITests/MultiWindowNotificationsUITests.swift lines 560–567:

let parts = line.split(separator: ":", maxSplits: 1, ...)
let candidate = String(parts[1]).trimmingCharacters(in: .whitespacesAndNewlines)
if UUID(uuidString: candidate) != nil { return candidate }

After this change, candidate becomes "<UUID> /path/to/cwd", which is not a valid UUID string, so UUID(uuidString:) returns nil and firstSurfaceId() will always return nil when CWD is set, silently breaking the UI test helpers.

Both parsers need to be updated to strip the optional cwd suffix. Alternatively, consider using a more unambiguous delimiter (e.g., a tab \t) between the UUID and the cwd to make the format forward-compatible and less fragile for paths that contain spaces:

Suggested change
let cwdSuffix = tab.panelDirectories[panel.id].map { " \($0)" } ?? ""
return "\(selected) \(index): \(panel.id.uuidString)\(cwdSuffix)"
let cwdSuffix = tab.panelDirectories[panel.id].map { "\t\($0)" } ?? ""
return "\(selected) \(index): \(panel.id.uuidString)\(cwdSuffix)"

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/TerminalController.swift (1)

10663-10664: ⚠️ Potential issue | 🟡 Minor

Escape cwd before appending it to v1 output.

list_surfaces is a line-oriented text protocol, but this now concatenates the raw directory path. Since panelDirectories can contain decoded OSC 7 paths, a cwd with \n, \r, or other control characters will corrupt the response format and break parsers.

[suggested fix]

Escape the suffix before formatting the line
-                let cwdSuffix = tab.panelDirectories[panel.id].map { " \($0)" } ?? ""
+                let cwdSuffix = tab.panelDirectories[panel.id].map { " \(Self.escapeSocketLineValue($0))" } ?? ""
                 return "\(selected) \(index): \(panel.id.uuidString)\(cwdSuffix)"
private nonisolated static func escapeSocketLineValue(_ value: String) -> String {
    value
        .replacingOccurrences(of: "\\", with: "\\\\")
        .replacingOccurrences(of: "\n", with: "\\n")
        .replacingOccurrences(of: "\r", with: "\\r")
        .replacingOccurrences(of: "\t", with: "\\t")
        .replacingOccurrences(of: "\u{1B}", with: "\\e")
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/TerminalController.swift` around lines 10663 - 10664, The
listWorkspaces() output currently appends raw cwd values which can include
control characters and break the line-oriented list_surfaces protocol; fix by
escaping the suffix before formatting each line—add a helper (e.g., nonisolated
static func escapeSocketLineValue(_:)) that replaces backslash, newline,
carriage return, tab and ESC with safe escape sequences and call this helper
when building each line in listWorkspaces() (use
escapeSocketLineValue(panelDirectory) or equivalent) so the emitted v1 lines
never contain raw control characters.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@Sources/TerminalController.swift`:
- Around line 10663-10664: The listWorkspaces() output currently appends raw cwd
values which can include control characters and break the line-oriented
list_surfaces protocol; fix by escaping the suffix before formatting each
line—add a helper (e.g., nonisolated static func escapeSocketLineValue(_:)) that
replaces backslash, newline, carriage return, tab and ESC with safe escape
sequences and call this helper when building each line in listWorkspaces() (use
escapeSocketLineValue(panelDirectory) or equivalent) so the emitted v1 lines
never contain raw control characters.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 126c00d3-a922-4a8b-a70b-8bde0e0a2dee

📥 Commits

Reviewing files that changed from the base of the PR and between 78e4bd3 and 7e3b5d3.

📒 Files selected for processing (1)
  • Sources/TerminalController.swift

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No issues found across 1 file


Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Add one-off context when rerunning by tagging @cubic-dev-ai with guidance or docs links (including llms.txt)
  • Ask questions if you need clarification on any suggestion

Expose per-surface working directory (tracked via OSC 7) in
surface.list and pane.surfaces v2 JSON-RPC responses. Callers can
now query CWD of all open terminal surfaces in a single call.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@PabloLION
PabloLION force-pushed the feat/surface-list-cwd branch from 7e3b5d3 to ecbdf84 Compare March 12, 2026 17:05
@PabloLION

PabloLION commented Mar 12, 2026 •

Copy link
Copy Markdown
Author

Dropped the v1 list_surfaces format change in the amended commit (ecbdf84b). The PR now only adds cwd to the two v2 JSON-RPC responses (surface.list and pane.surfaces).

Reason: The v1 text format is parsed by tests/cmux.py (line 347) and cmuxUITests/MultiWindowNotificationsUITests.swift (line 563) — both extract the surface UUID by splitting on whitespace. Appending CWD would break UUID extraction in both parsers. Since v2 already covers the use case with proper JSON fields, changing v1 isn't worth the breakage.

The outside-diff comment about escaping control characters in v1 output is no longer applicable.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cli The cmux CLI, cmux-tui, the socket API and SDKs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants