86 lines
3.3 KiB
Bash
Executable File
86 lines
3.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Open one screen as a TUIOS pane, or adopt the pane that already runs it.
|
|
#
|
|
# One screen, one workspace, named after the screen. The pane runs a shell that
|
|
# starts the program and returns to the shell when the program exits, so the
|
|
# pane never closes by itself; a workspace that loses its last pane is deleted
|
|
# by TUIOS and the rest renumber, which is the failure this avoids.
|
|
#
|
|
# bin/screen tree
|
|
# bin/screen reply AUD-162
|
|
#
|
|
# Run it twice and the second run focuses the existing pane. Print "created" or
|
|
# "adopted" so the caller can tell which happened.
|
|
set -euo pipefail
|
|
|
|
# The session is named, never taken from where the caller happens to be.
|
|
# TUIOS_SESSION is the session of the pane you are typing in, which is not
|
|
# necessarily this project's session; using it once put a screen in the wrong
|
|
# place.
|
|
SESSION="${PAPERCLIP_HARNESS_SESSION:-paperclip-harness}"
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
BIN="$ROOT/bin/harness"
|
|
|
|
screen="${1:-}"
|
|
case "$screen" in
|
|
tree) args=(-screen tree -project "${2:-spike-2026-11-10}") ;;
|
|
new) args=(-screen new -project "${2:-spike-2026-11-10}") ;;
|
|
log) args=(-screen log -issue "${2:?log needs a task, for example AUD-160}") ;;
|
|
reply) args=(-screen reply -issue "${2:?reply needs a task, for example AUD-162}") ;;
|
|
*) echo "usage: $(basename "$0") tree|new [project] | reply|log <task>" >&2; exit 2 ;;
|
|
esac
|
|
|
|
if [ ! -x "$BIN" ] || [ -n "$(find "$ROOT/tui" -name '*.go' -newer "$BIN" -print -quit 2>/dev/null)" ]; then
|
|
if ! command -v go >/dev/null 2>&1; then
|
|
echo "no harness binary and no Go to build one" >&2
|
|
exit 1
|
|
fi
|
|
( cd "$ROOT/tui" && go build -o "$BIN" . )
|
|
fi
|
|
|
|
# Workspaces and windows are resolved by name every time. A number is never
|
|
# remembered, because closing a pane renumbers the rest.
|
|
state="$(python3 - "$SESSION" "$screen" <<'PY'
|
|
import json, subprocess, sys
|
|
session, want = sys.argv[1], sys.argv[2]
|
|
|
|
def call(*args):
|
|
out = subprocess.run(["tuios", *args, "--json"], capture_output=True, text=True)
|
|
if out.returncode != 0:
|
|
sys.exit("tuios " + " ".join(args) + " failed: " + out.stderr.strip())
|
|
return json.loads(out.stdout)
|
|
|
|
ws = call("list-workspaces", "-s", session)["workspaces"]
|
|
win = call("list-windows", "-s", session)["windows"]
|
|
|
|
for w in win:
|
|
# custom_name is the name we gave the pane. It survives the program
|
|
# exiting and a shell taking over the title, so it is what adoption reads.
|
|
if w.get("custom_name") == want:
|
|
print("adopt", w["window_id"]); sys.exit()
|
|
|
|
named = next((w["workspace"] for w in ws if w.get("name") == want), None)
|
|
if named is not None:
|
|
print("create", named); sys.exit()
|
|
|
|
free = next((w["workspace"] for w in ws if w.get("window_count") == 0), None)
|
|
if free is None:
|
|
sys.exit("no empty workspace in session %r; close a pane or add a workspace" % session)
|
|
print("create", free)
|
|
PY
|
|
)"
|
|
|
|
action="$(echo "$state" | awk '{print $1}')"
|
|
where="$(echo "$state" | awk '{print $2}')"
|
|
|
|
if [ "$action" = "adopt" ]; then
|
|
tuios focus-window "$where" -s "$SESSION" >/dev/null
|
|
echo "adopted $screen ($where) in session $SESSION"
|
|
exit 0
|
|
fi
|
|
|
|
tuios new-window "$screen" -s "$SESSION" --workspace "$where" --cwd "$ROOT" \
|
|
--no-focus --keep-open -- /bin/sh -c "$BIN ${args[*]}; exec zsh -i" >/dev/null
|
|
tuios set-workspace-name "$where" "$screen" -s "$SESSION" >/dev/null
|
|
echo "created $screen on workspace $where of session $SESSION"
|