fix(launch-orchestrator): opencode uses plain TUI + ping, not run --attach
Same fix as the loops: opencode run --attach exits after one turn; plain opencode TUI stays alive in tmux. Send startup prompt via ping_session (Enter) after 8s init wait. Bootstrap points to JOURNAL.md rather than sending the full prompt inline. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
2aa3fbda8d
commit
6a6c17f526
@@ -78,6 +78,21 @@ def session_alive():
|
|||||||
["tmux", "has-session", "-t", SESSION], capture_output=True
|
["tmux", "has-session", "-t", SESSION], capture_output=True
|
||||||
).returncode == 0
|
).returncode == 0
|
||||||
|
|
||||||
|
def _ping(session, msg):
|
||||||
|
"""Type a message into the tmux session and submit with Enter."""
|
||||||
|
import time
|
||||||
|
subprocess.run(["tmux", "send-keys", "-t", session, "-l", "--", msg], capture_output=True)
|
||||||
|
time.sleep(0.5)
|
||||||
|
for _ in range(5):
|
||||||
|
subprocess.run(["tmux", "send-keys", "-t", session, "Enter"], capture_output=True)
|
||||||
|
time.sleep(1)
|
||||||
|
r = subprocess.run(["tmux", "capture-pane", "-pt", session],
|
||||||
|
capture_output=True, text=True)
|
||||||
|
if msg[:28] not in r.stdout.splitlines()[-4:]:
|
||||||
|
return
|
||||||
|
subprocess.run(["tmux", "send-keys", "-t", session, "C-m"], capture_output=True)
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
def resume_id():
|
def resume_id():
|
||||||
sid = os.environ.get("ORCH_SESSION_ID")
|
sid = os.environ.get("ORCH_SESSION_ID")
|
||||||
if sid:
|
if sid:
|
||||||
@@ -118,16 +133,13 @@ def start(mode="resume"):
|
|||||||
elif BACKEND == "opencode":
|
elif BACKEND == "opencode":
|
||||||
if not Path(OPENCODE_BIN).exists():
|
if not Path(OPENCODE_BIN).exists():
|
||||||
die(f"opencode not found at {OPENCODE_BIN}")
|
die(f"opencode not found at {OPENCODE_BIN}")
|
||||||
# No --resume equivalent in opencode; STARTUP_PROMPT orients the new session.
|
# Plain `opencode` TUI stays alive in tmux and auto-connects to the shared server.
|
||||||
# The session title in the web UI identifies it as the orchestrator.
|
# (`opencode attach URL` exits without a real TTY; plain TUI works because tmux
|
||||||
prompt = STARTUP_PROMPT or (
|
# allocates a PTY for the pane.) The startup prompt is sent via ping_session after
|
||||||
"You are the cc-ci orchestrator. Read /srv/cc-ci/AGENTS.md and "
|
# the TUI initialises. NO_COLOR=1 skips the first-run theme picker.
|
||||||
"cc-ci-plan/JOURNAL.md for context, then resume supervising the loops."
|
|
||||||
)
|
|
||||||
cmd = (
|
cmd = (
|
||||||
f"set -a; . /srv/cc-ci/.testenv; set +a; "
|
f"set -a; . /srv/cc-ci/.testenv; set +a; "
|
||||||
f"{OPENCODE_BIN} {model_flag} run --attach '{OPENCODE_SERVER}' "
|
f"NO_COLOR=1 {OPENCODE_BIN} {model_flag}"
|
||||||
f"--title '{SESSION}' '{prompt}'"
|
|
||||||
)
|
)
|
||||||
log(f"starting {SESSION} (backend=opencode, model={LOOP_MODEL or 'default'})")
|
log(f"starting {SESSION} (backend=opencode, model={LOOP_MODEL or 'default'})")
|
||||||
log(f" visible at http://oc.commoninternet.net (tailnet only)")
|
log(f" visible at http://oc.commoninternet.net (tailnet only)")
|
||||||
@@ -139,6 +151,22 @@ def start(mode="resume"):
|
|||||||
f"cat >> '{LOG_DIR}/{SESSION}.log'"])
|
f"cat >> '{LOG_DIR}/{SESSION}.log'"])
|
||||||
log(f"started. attach: tmux attach -t {SESSION}")
|
log(f"started. attach: tmux attach -t {SESSION}")
|
||||||
|
|
||||||
|
# opencode: send the startup prompt once the TUI has connected (~8s).
|
||||||
|
if BACKEND == "opencode":
|
||||||
|
import time
|
||||||
|
time.sleep(8)
|
||||||
|
prompt = STARTUP_PROMPT or (
|
||||||
|
"You are the cc-ci orchestrator. Read cc-ci-plan/JOURNAL.md for full "
|
||||||
|
"context on what's happened and what needs doing, then supervise the loops."
|
||||||
|
)
|
||||||
|
# Send a pointer to the journal rather than the full prompt (avoids length limits).
|
||||||
|
bootstrap = (
|
||||||
|
"You are the cc-ci orchestrator. Start by reading cc-ci-plan/JOURNAL.md "
|
||||||
|
"(`cat cc-ci-plan/JOURNAL.md`) for full context, then check loop status "
|
||||||
|
"(`cc-ci-plan/launch.sh status`) and resume supervising."
|
||||||
|
)
|
||||||
|
_ping(SESSION, bootstrap)
|
||||||
|
|
||||||
# ── main ──────────────────────────────────────────────────────────────────────
|
# ── main ──────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
Reference in New Issue
Block a user