blob: d3457fae09e0d3c80dd6b1b9b67386ebd944601e (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
#!/usr/bin/env bash
# tuicr-wrapper: open tuicr in a zellij floating pane (or split) from a
# non-TTY context (e.g. claude-code, copilot CLI). Blocks on a FIFO until
# the spawned tuicr process exits, then emits any instructions written by
# tuicr's --output to stdout, wrapped in markers the agent recognises.
#
# Adapted from agavra/tuicr's tmux-based reference wrapper.
# See: dot_claude/skills/tuicr/SKILL.md
set -euo pipefail
TARGET_DIR="${1:-$PWD}"
if [ -z "${ZELLIJ:-}" ]; then
cat <<'EOF' >&2
ERROR: not running inside a zellij session.
Restart the agent from inside a zellij session and try again:
zellij
# then, inside zellij:
claude # or: copilot
EOF
exit 1
fi
if ! command -v tuicr >/dev/null 2>&1; then
cat <<'EOF' >&2
ERROR: 'tuicr' is not installed.
Provisioned via nix; rebuild your profile:
# host (Arch):
just nix-switch
# remote-dev VM:
cd ~/.local/share/dotfiles/remote-dev
home-manager switch --impure --flake .#vm -b backup
EOF
exit 1
fi
if ! git -C "$TARGET_DIR" rev-parse --git-dir >/dev/null 2>&1; then
echo "ERROR: '$TARGET_DIR' is not a git repository" >&2
exit 1
fi
# Refuse to nest if another tuicr is already running (zellij has no
# tmux-style 'list-panes | grep'; pgrep is the closest cross-pane probe).
if pgrep -x tuicr >/dev/null 2>&1; then
echo "ERROR: tuicr is already running in this session" >&2
exit 1
fi
# Per-invocation tmpdir holds:
# done - FIFO; child writes one byte on exit, parent blocks read
# output - tuicr --output target (instructions to relay back)
TMPDIR_TUICR="$(mktemp -d -t tuicr.XXXXXX)"
DONE_FIFO="$TMPDIR_TUICR/done"
OUTPUT_FILE="$TMPDIR_TUICR/output"
trap 'rm -rf "$TMPDIR_TUICR"' EXIT
mkfifo "$DONE_FIFO"
: >"$OUTPUT_FILE"
PANE_MODE="${TUICR_PANE_MODE:-floating}"
SPLIT_DIR="${TUICR_SPLIT_DIR:-down}"
# Child command: cd into the repo, run tuicr exporting instructions, then
# signal the parent regardless of exit status.
CHILD_CMD="cd $(printf %q "$TARGET_DIR") && \
tuicr --output $(printf %q "$OUTPUT_FILE"); \
printf done > $(printf %q "$DONE_FIFO")"
case "$PANE_MODE" in
floating)
zellij action new-pane --floating \
--cwd "$TARGET_DIR" \
-- bash -lc "$CHILD_CMD" >/dev/null
;;
split)
zellij action new-pane \
--direction "$SPLIT_DIR" \
--cwd "$TARGET_DIR" \
-- bash -lc "$CHILD_CMD" >/dev/null
;;
*)
echo "ERROR: invalid TUICR_PANE_MODE='$PANE_MODE' (expected floating|split)" >&2
exit 1
;;
esac
# Block until the child writes its sentinel.
read -r _ <"$DONE_FIFO"
# Relay instructions back to the agent if tuicr wrote any.
if [ -s "$OUTPUT_FILE" ]; then
echo "=== TUICR INSTRUCTIONS ==="
cat "$OUTPUT_FILE"
echo
echo "=== END TUICR INSTRUCTIONS ==="
else
echo "tuicr exited with no instructions" >&2
fi
|