Skip to content

refactor(adapters): extract the shell-dialect seam from new_window/new_parked_window#47

Merged
pbean merged 2 commits into
bmad-code-org:mainfrom
dracic:refactor/gh-46-shell-dialect-seam
Jul 3, 2026
Merged

refactor(adapters): extract the shell-dialect seam from new_window/new_parked_window#47
pbean merged 2 commits into
bmad-code-org:mainfrom
dracic:refactor/gh-46-shell-dialect-seam

Conversation

@dracic

@dracic dracic commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

What

BaseTmuxBackend.new_window/new_parked_window no longer hard-code the POSIX shell wrapper: the tmux argv construction, parked-window protocol, and recipe shape stay in the base once, while the shell-dialect fragments become small overridable hooks with POSIX-sh defaults.

Why

A native-Windows tmux-family leaf (follow-up to #40) has no /bin/sh; with the wrapper hard-coded it had to duplicate both entire methods just to swap the shell dialect — the biggest drift risk in the adapter layer.

Fixes #46

How

  • Added dialect hooks on BaseTmuxBackend: _EXIT_CAPTURE/_ECHO/_PARK fragments, _join_argv, _parked_trailer, _source_prefix, _shell_wrap, _window_launch — each maps 1:1 to a divergence a non-POSIX leaf actually needs; the recipe line itself is dialect-neutral (; sequencing and "$ec" interpolation are common across the family).
  • Rewrote new_window/new_parked_window to compose from the hooks; the POSIX leaf (tmux_backend.py) overrides nothing and its output is byte-identical.
  • Documented the hook contract (an _EXIT_CAPTURE override must bind ec; _source_prefix must self-terminate with "; "; which hooks a non-POSIX leaf must override). No non-POSIX implementation lands here — this only opens the seam.

Testing

New tests lock the exact pre-refactor subprocess.run argv (including the full sh -c source literal) for both methods, and a fake-dialect test leaf proves overriding only the hooks keeps the base scaffolding intact. tests/test_multiplexer.py 11/11; full suite green on Windows against the known baseline (pytest -k "not real_signal", 1322 passed).

Summary by CodeRabbit

  • Bug Fixes

    • Improved POSIX tmux window and parked-window launch command assembly for more consistent behavior.
    • Refined shell-dialect handling so dialect-specific overrides are applied cleanly, including environment flag generation.
  • Tests

    • Added stricter coverage to confirm byte-identical command argv construction and correct routing through shell-dialect hooks.
  • Documentation

    • Updated adapter authoring and porting guidance to clarify the supported tmux shell-dialect customization surface.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: de87a0b5-61d5-45ff-aefa-73e437fb01f9

📥 Commits

Reviewing files that changed from the base of the PR and between 5bb6937 and ccb042a.

📒 Files selected for processing (3)
  • docs/adapter-authoring-guide.md
  • docs/porting-to-a-new-os.md
  • src/bmad_loop/adapters/tmux_base.py
✅ Files skipped from review due to trivial changes (2)
  • docs/porting-to-a-new-os.md
  • docs/adapter-authoring-guide.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/bmad_loop/adapters/tmux_base.py

Walkthrough

The PR factors tmux shell-dialect handling into overridable hooks, updates new_window and new_parked_window to use them, and keeps POSIX argv output byte-identical. Tests cover both exact POSIX command arrays and hook-driven composition with a fake dialect subclass.

Changes

Tmux shell dialect seam

Layer / File(s) Summary
Dialect seam hooks and constants
src/bmad_loop/adapters/tmux_base.py
Module docs and BaseTmuxBackend add POSIX shell fragment constants plus hook methods for argv joining, source prefixing, shell wrapping, parked trailers, and new-window launch args.
Window and parked-window wiring
src/bmad_loop/adapters/tmux_base.py
new_window now delegates launch argv assembly to _window_launch, and new_parked_window builds its shell source from the new dialect hooks before wrapping and spawning it.
POSIX and fake-dialect tests
tests/test_multiplexer.py, docs/adapter-authoring-guide.md, docs/porting-to-a-new-os.md
Tests capture argv, assert byte-identical POSIX output, and verify fake-dialect hook composition; docs update the backend-extension guidance to describe the new shell-dialect seam.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

Poem

I’m a rabbit with a tmux tune,
Hopping past sh -c to a seam in bloom.
Hooks now nibble the shell just right,
POSIX bytes stay crisp and bright,
And fake dialects dance by moonlight. 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main refactor: extracting the shell-dialect seam from new_window/new_parked_window.
Linked Issues check ✅ Passed The changes match #46 by moving shell-dialect behavior into overridable hooks, preserving the base recipe, and keeping POSIX behavior byte-identical.
Out of Scope Changes check ✅ Passed The added tests and documentation updates directly support the seam refactor and do not introduce unrelated scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@augmentcode

augmentcode Bot commented Jul 3, 2026

Copy link
Copy Markdown
🤖 Augment PR Summary

Summary: This PR refactors tmux window creation to separate the shell-dialect-specific pieces from the shared tmux argv/protocol scaffolding.

Changes:

  • Introduced a “shell dialect seam” in BaseTmuxBackend via small overridable hooks (_shell_wrap, _join_argv, _source_prefix, _parked_trailer, _window_launch) and recipe fragments (_EXIT_CAPTURE/_ECHO/_PARK).
  • Rewrote new_window to route env/command trailing args through _window_launch.
  • Rewrote new_parked_window to compose its parked-window shell source from the new hooks and wrap it via _shell_wrap.
  • Kept POSIX-sh defaults so the existing POSIX leaf does not need overrides and behavior remains unchanged.
  • Added tests that lock the exact subprocess.run argv for POSIX output (byte-identical to pre-refactor) for both methods.
  • Added a fake “dialect” leaf test proving overriding only the hooks changes dialect behavior while preserving the base tmux scaffolding.

Technical Notes: The intent is to enable non-POSIX / native-Windows tmux-family backends to swap shell dialect details without duplicating full contract method bodies, reducing adapter drift risk.

🤖 Was this summary useful? React with 👍 or 👎

@augmentcode augmentcode 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.

Review completed. No suggestions at this time.

Comment augment review to trigger a new review at any time.

@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.

🧹 Nitpick comments (1)
tests/test_multiplexer.py (1)

345-376: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Exercise shell quoting in the byte-identity fixture.

This test would still pass if _join_argv regressed from shlex.join(argv) to a naive " ".join(argv). Use an argv containing spaces or shell metacharacters so the POSIX byte-identity check also locks the quoting contract.

🧪 Proposed test strengthening
 _PARKED_SH_SOURCE = (
-    'echo hi; ec=$?; echo "[bmad-auto exited $ec — press enter]"; read -r; '
+    "echo 'two words' 'semi;colon'; ec=$?; "
+    'echo "[bmad-auto exited $ec — press enter]"; read -r; '
     "ret=$(tmux show-options -wqv %3 2>/dev/null); "
     'if [ "$ret" = "detach" ]; then tmux detach-client 2>/dev/null; '
     'elif [ -n "$ret" ]; then '
     'tmux switch-client -t "$ret" 2>/dev/null || tmux switch-client -l 2>/dev/null; fi'
 )
@@
-    TmuxMultiplexer().new_parked_window("s", "n", tmp_path, ["echo", "hi"], "%3")
+    TmuxMultiplexer().new_parked_window(
+        "s", "n", tmp_path, ["echo", "two words", "semi;colon"], "%3"
+    )
🤖 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 `@tests/test_multiplexer.py` around lines 345 - 376, The byte-identity check in
test_new_parked_window_posix_argv_byte_identical is too weak because it still
passes with naive argv joining. Strengthen the fixture by using an argv in
TmuxMultiplexer.new_parked_window that includes spaces or shell metacharacters,
and update the expected _PARKED_SH_SOURCE assertion so the test verifies correct
shlex-style quoting rather than plain string concatenation.
🤖 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 `@tests/test_multiplexer.py`:
- Around line 345-376: The byte-identity check in
test_new_parked_window_posix_argv_byte_identical is too weak because it still
passes with naive argv joining. Strengthen the fixture by using an argv in
TmuxMultiplexer.new_parked_window that includes spaces or shell metacharacters,
and update the expected _PARKED_SH_SOURCE assertion so the test verifies correct
shlex-style quoting rather than plain string concatenation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2fcd55cc-0106-46b9-b1fb-343427e344f8

📥 Commits

Reviewing files that changed from the base of the PR and between 3dc6e80 and ed87eb3.

📒 Files selected for processing (2)
  • src/automator/adapters/tmux_base.py
  • tests/test_multiplexer.py

…w_parked_window

The tmux argv construction, parked-window protocol, and recipe shape stay
in BaseTmuxBackend once; the shell-dialect fragments (exit capture, echo,
park, argv join, trailer, source prefix, shell wrap, window launch) become
overridable hooks with POSIX-sh defaults. POSIX output is byte-identical,
locked by tests asserting the literal subprocess argv; a test leaf proves a
non-POSIX dialect overrides only hook strings, never a contract method body.
@dracic dracic force-pushed the refactor/gh-46-shell-dialect-seam branch from ed87eb3 to 5bb6937 Compare July 3, 2026 18:32
… guides

Review follow-up: the module docstring claimed a non-POSIX leaf never edits
a contract method body, but pipe_pane still hands tmux a POSIX `cat >>`
redirection — scope the claim to new_window/new_parked_window and name
pipe_pane as the remaining method-body override. Update
adapter-authoring-guide.md and porting-to-a-new-os.md, which still described
the pre-seam model ('override the few divergent methods, e.g. the
parked-window trailer'), to point at the shell-dialect hooks instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pbean

pbean commented Jul 3, 2026

Copy link
Copy Markdown
Collaborator

Reviewed — the seam is sound: POSIX argv/source verified byte-identical, the leaf overrides nothing, all call sites unaffected. Pushed ccb042a directly (maintainer edit) to fold in the three doc-level review nits rather than round-tripping comments:

  • tmux_base.py module docstring: scoped the "without editing … any contract method body" claim to new_window/new_parked_windowpipe_pane still hands tmux a POSIX cat >> redirection, so it remains the one method-body override a non-POSIX leaf needs.
  • docs/adapter-authoring-guide.md + docs/porting-to-a-new-os.md: both still described the pre-seam model ("override the few divergent methods, e.g. the parked-window trailer"); now point at the dialect hooks.

No code-behavior changes; tests/test_multiplexer.py 11/11 and the full suite green locally.

@pbean pbean merged commit 61567b2 into bmad-code-org:main Jul 3, 2026
9 checks passed
@dracic dracic deleted the refactor/gh-46-shell-dialect-seam branch July 4, 2026 08:22
@pbean pbean mentioned this pull request Jul 6, 2026
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.

Tmux-family base: factor the shell-dialect wrapper out of new_window/new_parked_window into overridable hooks

2 participants