Skip to content

tty field always null in --json tree output - #3236

Closed
lawrencecchen wants to merge 2 commits into
mainfrom
loader/issue-3098-tty-field-always-null-in-json-tree-output
Closed

lawrencecchen wants to merge 2 commits into
mainfrom
loader/issue-3098-tty-field-always-null-in-json-tree-output

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Apr 28, 2026 •

Copy link
Copy Markdown
Contributor

Addresses #3098

Generated by cmux-loader.

Codex final message:

Implemented in branch loader/issue-3098-tty-field-always-null-in-json-tree-output:

Verification performed:

  • Reviewed diffs for all touched files (no unrelated changes).
  • Confirmed basename-stripping patterns are removed from both shell integration scripts.
  • Ran required tagged build command:
    • ./scripts/reload.sh --tag loader
    • Result: failed immediately because zig is not installed (Error: zig is not installed. Install via: brew install zig).
    • Limitation: cannot complete artifact validation in this runner until zig is available.

Pull request:

  • Not opened/updated yet.
  • Limitation: gh auth status reports no GitHub authentication in this environment, so I couldn’t create/update a PR or push for PR creation here.

If you want, I can also provide the exact PR title/body text to use when you create it from your authenticated environment.

Summary by CodeRabbit

Improvements

  • Enhanced terminal identification across Bash and Zsh shell integrations for improved consistency and reliability in terminal management.

Summary by cubic

Fixes the tty field being null in cmux --json tree by preserving the full TTY device path from shell integration. The JSON now includes values like /dev/ttys001 instead of null.

  • Bug Fixes

    • Bash/zsh integration: stop stripping the basename; keep the full /dev/... path.
    • TerminalController: added a helper to pass only the basename to PortScanner, while keeping the full path in API payloads.
    • Updated tests to expect full-path tty values.
  • Refactors

    • Refreshed .github/swift-file-length-budget.tsv for Sources/TerminalController.swift.

Written for commit e294143. Summary will update on new commits. Review in cubic

Generated by cmux-loader.
@vercel

vercel Bot commented Apr 28, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Apr 28, 2026 11:23pm
cmux-staging Building Building Preview, Comment Apr 28, 2026 11:23pm

@coderabbitai

coderabbitai Bot commented Apr 28, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The shell integration scripts (bash and zsh) now preserve full TTY device paths instead of extracting just the basename. TerminalController adds a normalization helper that extracts the basename when registering TTYs with PortScanner, and test expectations are updated to match the new behavior.

Changes

Cohort / File(s) Summary
Shell Integration TTY Path Preservation
Resources/shell-integration/cmux-bash-integration.bash, Resources/shell-integration/cmux-zsh-integration.zsh
Removed basename extraction from tty command output in preexec/precmd hooks, so _CMUX_TTY_NAME now stores the full TTY device path (e.g., /dev/ttys123) instead of just the device name (ttys123).
TerminalController TTY Normalization
Sources/TerminalController.swift
Added private portScanTTYName helper function that normalizes TTY names by extracting the final path component (basename) before registering with PortScanner. Updated all non-remote PortScanner registration call sites to use this normalization.
Test Expectations Update
cmuxTests/GhosttyConfigTests.swift
Updated shell-integration handoff tests to expect _CMUX_TTY_NAME and report_tty outputs to contain full device paths (/dev/ttys*) rather than bare device names, with corresponding assertion updates.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 The TTY paths now run so deep,
From shell to scanner, full strides we keep,
Normalize when you register, that's the key,
Full paths above, basenames where they'll be,
A tidy flow through layers, just right for me! 🌿

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is vague and does not clearly convey the main change: preserving full tty device paths in API output and shell integration scripts. Use a more descriptive title that explains the fix, such as 'Preserve full tty device paths in shell integration and API output' or 'Fix tty field null in JSON tree output by preserving device paths'.
Description check ❓ Inconclusive PR description includes detailed technical explanation of changes, but lacks structured sections matching the template (Summary, Testing, Demo Video, Review Trigger, Checklist). Restructure the description using the required template with clear Summary, Testing, and Checklist sections. Include what changed and why, how it was tested, and confirm completion of the standard checklist items.
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 loader/issue-3098-tty-field-always-null-in-json-tree-output

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.

❤️ Share

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

@greptile-apps

greptile-apps Bot commented Apr 28, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes the tty field being null in cmux --json tree output by removing the ${t##*/} basename stripping from both the bash and zsh shell integrations, so _CMUX_TTY_NAME now carries the full /dev/ttyXXX device path that gets stored in surfaceTTYNames and surfaced in the API. A new portScanTTYName(from:) helper re-extracts the basename before passing it to PortScanner.registerTTY, preserving the existing port-scan behaviour; the remote-workspace path was already normalising via normalizedRemotePortScanTTYName and is unaffected.

Confidence Score: 4/5

Safe to merge; the fix is minimal and well-scoped with only P2 suggestions remaining.

All findings are P2 (missing test coverage for the new helper and one stale fixture). The core logic — removing basename stripping in both shell integrations and re-normalising for PortScanner — is correct, and the remote-workspace codepath already had its own normalisation that is unaffected.

Sources/TerminalController.swift — portScanTTYName lacks a unit test; cmuxTests/TerminalControllerSocketSecurityTests.swift — fixture still uses old bare-name format.

Important Files Changed

Filename Overview
Resources/shell-integration/cmux-bash-integration.bash Removes three occurrences of ${t##*/} basename stripping in _cmux_preexec_command and _cmux_prompt_command so _CMUX_TTY_NAME now carries the full /dev/ttyXXX device path.
Resources/shell-integration/cmux-zsh-integration.zsh Removes two occurrences of ${t##*/} stripping in _cmux_preexec and _cmux_precmd — symmetric to the bash change.
Sources/TerminalController.swift Adds portScanTTYName(from:) to re-extract the basename for PortScanner.registerTTY while leaving the full path in surfaceTTYNames; no unit test for the helper.
cmuxTests/GhosttyConfigTests.swift Updates five test fixtures from bare tty names (ttys999) to full paths (/dev/ttys999) to match the new shell-reported format.

Sequence Diagram

sequenceDiagram
    participant Shell as Shell (bash/zsh)
    participant Socket as Unix Socket
    participant TC as TerminalController
    participant WS as Workspace.surfaceTTYNames
    participant PS as PortScanner
    participant API as --json tree

    Note over Shell: OLD: t="${t##*/}" → ttys001
    Note over Shell: NEW: full path kept → /dev/ttys001

    Shell->>Socket: report_tty /dev/ttys001 --tab=X
    Socket->>TC: reportTTY("/dev/ttys001 --tab=X")
    TC->>WS: surfaceTTYNames[panelId] = "/dev/ttys001"
    TC->>TC: portScanTTYName("/dev/ttys001") → "ttys001"
    TC->>PS: registerTTY(ttyName: "ttys001")
    PS->>PS: ps -t ttys001 (basename, unchanged)
    API->>WS: surfaceTTYNames[panelId]
    WS-->>API: "/dev/ttys001" (was null before fix)
Loading

Comments Outside Diff (1)

  1. cmuxTests/TerminalControllerSocketSecurityTests.swift, line 270-282 (link)

    P2 Stale bare-basename fixture not updated

    This test still passes the old bare-name "ttys999" (no /dev/ prefix) to surface.report_tty and asserts the value is stored verbatim. The assertion is technically still correct — the API is a passthrough — but after this fix the real path emitted by the shell is /dev/ttys999. A companion assertion or a second test case with the full-path form would confirm that surfaceTTYNames is populated correctly for the scenario this bug fix specifically addresses.

Reviews (1): Last reviewed commit: "Address https://github.com/manaflow-ai/c..." | Re-trigger Greptile

Comment on lines +484 to +488
private static func portScanTTYName(from ttyName: String) -> String {
let trimmed = ttyName.trimmingCharacters(in: .whitespacesAndNewlines)
let candidate = trimmed.split(separator: "/").last.map(String.init) ?? trimmed
return candidate.isEmpty ? trimmed : candidate
}

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.

P2 No unit test for portScanTTYName

The new portScanTTYName(from:) helper is the critical bridge that prevents a regression in port-scan behavior: it must convert /dev/ttys001 → ttys001 while leaving bare names like ttys001 untouched. It currently has no dedicated unit test. A simple parametric test covering /dev/ttys001, ttys001, an empty string, and a trailing-slash edge case (e.g. /dev/ttys001/) would lock in the invariant and prevent future accidental changes.

@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in cmux backlog Sep 23, 2026

This branch was successfully deployed

1 active deployment
Preview – cmux — e2941431 Deployed Apr 28, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants