* Rename cmuxterm to cmux across entire codebase - Rename GitHub repos: manaflow-ai/cmuxterm -> manaflow-ai/cmux, manaflow-ai/homebrew-cmuxterm -> manaflow-ai/homebrew-cmux - Rename bundle IDs: com.cmuxterm.app -> com.cmux.app - Rename CLI: CLI/cmuxterm.swift -> CLI/cmux.swift - Rename homebrew submodule: homebrew-cmuxterm -> homebrew-cmux - Update all socket paths: /tmp/cmuxterm*.sock -> /tmp/cmux*.sock - Update all GitHub URLs, DMG names, Sparkle URLs - Update all source files, scripts, tests, docs, CI workflows * Bump version to 1.23.0
96 lines
3.5 KiB
Python
96 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Regression: GhosttyKit already injects zsh shell integration by setting ZDOTDIR
|
|
to Ghostty's own integration directory (and optionally preserving a user-set
|
|
ZDOTDIR in GHOSTTY_ZSH_ZDOTDIR).
|
|
|
|
cmux also injects its own zsh integration by setting ZDOTDIR to
|
|
Resources/shell-integration. If cmux incorrectly treats Ghostty's injected
|
|
ZDOTDIR as the "user" ZDOTDIR, zsh history will be isolated to the integration
|
|
directory rather than the user's HOME/ZDOTDIR, breaking cross-terminal history
|
|
and therefore zsh-autosuggestions.
|
|
|
|
This test simulates that stacked injection scenario and asserts HISTFILE ends
|
|
up at $HOME/.zsh_history (not inside Ghostty's integration directory).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
|
|
def _run_zsh_print_histfile(env: dict[str, str]) -> tuple[int, str]:
|
|
# A PTY is not required for this regression: we only need /etc/zshrc to run
|
|
# and set HISTFILE based on the restored ZDOTDIR/HOME.
|
|
result = subprocess.run(
|
|
["zsh", "-ic", 'print -r -- "$HISTFILE"'],
|
|
env=env,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=8,
|
|
)
|
|
return (result.returncode, (result.stdout or "") + (result.stderr or ""))
|
|
|
|
|
|
def main() -> int:
|
|
root = Path(__file__).resolve().parents[1]
|
|
cmux_wrapper_dir = root / "Resources" / "shell-integration"
|
|
ghostty_zsh_dir = root / "ghostty" / "src" / "shell-integration" / "zsh"
|
|
|
|
if not (cmux_wrapper_dir / ".zshenv").exists():
|
|
print(f"SKIP: missing cmux wrapper .zshenv at {cmux_wrapper_dir}")
|
|
return 0
|
|
if not (ghostty_zsh_dir / ".zshenv").exists():
|
|
print(f"SKIP: missing Ghostty zsh .zshenv at {ghostty_zsh_dir}")
|
|
return 0
|
|
|
|
base = Path("/tmp") / f"cmux_histfile_ghostty_stack_{os.getpid()}"
|
|
try:
|
|
shutil.rmtree(base, ignore_errors=True)
|
|
base.mkdir(parents=True, exist_ok=True)
|
|
home = base / "home"
|
|
home.mkdir(parents=True, exist_ok=True)
|
|
|
|
env = dict(os.environ)
|
|
env["HOME"] = str(home)
|
|
env.pop("HISTFILE", None)
|
|
# Keep this test focused and deterministic: don't run Ghostty's heavy zsh
|
|
# integration when executing under a PTY in CI/agent runs.
|
|
env.pop("GHOSTTY_RESOURCES_DIR", None)
|
|
env.pop("GHOSTTY_SHELL_FEATURES", None)
|
|
env.pop("GHOSTTY_BIN_DIR", None)
|
|
|
|
# Simulate the buggy situation: cmux stores Ghostty's injected ZDOTDIR
|
|
# as the "original" ZDOTDIR, then sets ZDOTDIR to its own wrapper.
|
|
env["CMUX_ORIGINAL_ZDOTDIR"] = str(ghostty_zsh_dir)
|
|
env["ZDOTDIR"] = str(cmux_wrapper_dir)
|
|
env["CMUX_SHELL_INTEGRATION"] = "0"
|
|
|
|
rc, out = _run_zsh_print_histfile(env)
|
|
if rc != 0:
|
|
print(f"FAIL: zsh exited non-zero rc={rc}")
|
|
return 1
|
|
|
|
lines = [ln.strip() for ln in out.splitlines() if ln.strip()]
|
|
if not lines:
|
|
print("FAIL: no output captured from zsh")
|
|
return 1
|
|
seen = lines[-1]
|
|
expected = str(home / ".zsh_history")
|
|
if seen != expected:
|
|
print(f"FAIL: HISTFILE={seen!r}, expected {expected!r}")
|
|
print(f" cmux_wrapper_dir={cmux_wrapper_dir}")
|
|
print(f" ghostty_zsh_dir={ghostty_zsh_dir}")
|
|
return 1
|
|
|
|
print("PASS: HISTFILE resolves to user home history (not Ghostty integration dir)")
|
|
return 0
|
|
finally:
|
|
shutil.rmtree(base, ignore_errors=True)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|