aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/dot_claude/skills/tuicr/executable_tuicr-wrapper.sh
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