orchestrator: restore opencode web launcher
This commit is contained in:
@@ -543,3 +543,18 @@ session cc-ci-orchestrator-stale can be killed; recipe-mirrors org still private
|
|||||||
(c) ghost PR debug: plan-ghostpr-debug-fix.md + memory [[ghost-pr-debug]].
|
(c) ghost PR debug: plan-ghostpr-debug-fix.md + memory [[ghost-pr-debug]].
|
||||||
- NOT switching the upgrade to sequential (operator: concurrency is fine; the leak is the issue).
|
- NOT switching the upgrade to sequential (operator: concurrency is fine; the leak is the issue).
|
||||||
Duplicate ghost subagent from the interrupt churn — told the upgrader to TaskStop one.
|
Duplicate ghost subagent from the interrupt churn — told the upgrader to TaskStop one.
|
||||||
|
|
||||||
|
## 2026-06-12 15:43 UTC — opencode web restored + OpenAI launcher added
|
||||||
|
- Re-enabled `opencode-web.service` in `nix/hosts/cc-ci-orchestrator-hetzner/configuration.nix`
|
||||||
|
(`wantedBy = [ "multi-user.target" ]`) and persisted the broader PATH that the old runtime
|
||||||
|
override had been providing. `nixos-rebuild switch --flake .#cc-ci-orchestrator-hetzner`
|
||||||
|
brought the service back and it now passes `curl http://127.0.0.1:4096/global/health`.
|
||||||
|
- Added `cc-ci-plan/launch-opencode.sh` as a separate entrypoint that keeps the default
|
||||||
|
Claude `launch-orchestrator.sh` untouched. It rebuilds the host flake if `opencode-web`
|
||||||
|
is not enabled, starts the service if needed, then launches the orchestrator with
|
||||||
|
`LOOP_BACKEND=opencode`, `LOOP_MODEL=openai/gpt-5.4`, and default session name
|
||||||
|
`cc-ci-orchestrator-oc`.
|
||||||
|
- Patched `launch-orchestrator.py` so opencode launches can force the requested model even
|
||||||
|
though `opencode attach` has no `--model` flag: it now injects `OPENCODE_CONFIG_CONTENT`
|
||||||
|
for the session. Verified live: `cc-ci-orchestrator-oc` tmux session running on
|
||||||
|
`backend=opencode model=openai/gpt-5.4`, visible through the shared web server.
|
||||||
|
|||||||
Executable
+29
@@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SELF_DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
|
||||||
|
FLAKE_ROOT="$(readlink -f "$SELF_DIR/..")"
|
||||||
|
FLAKE_HOST="${FLAKE_HOST:-cc-ci-orchestrator-hetzner}"
|
||||||
|
DEFAULT_MODEL="${LOOP_MODEL:-openai/gpt-5.4}"
|
||||||
|
|
||||||
|
ensure_opencode_web() {
|
||||||
|
if ! systemctl is-enabled --quiet opencode-web.service; then
|
||||||
|
sudo nixos-rebuild switch --flake "$FLAKE_ROOT#$FLAKE_HOST"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! systemctl is-active --quiet opencode-web.service; then
|
||||||
|
sudo systemctl start opencode-web.service
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_opencode_web
|
||||||
|
|
||||||
|
export LOOP_BACKEND=opencode
|
||||||
|
export LOOP_MODEL="$DEFAULT_MODEL"
|
||||||
|
export ORCH_SESSION="${ORCH_SESSION:-cc-ci-orchestrator-oc}"
|
||||||
|
|
||||||
|
if [ "$#" -eq 0 ]; then
|
||||||
|
set -- fresh
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec python3 "$SELF_DIR/launch-orchestrator.py" "$@"
|
||||||
@@ -31,7 +31,7 @@ Env:
|
|||||||
the session title in the web UI is the SESSION name)
|
the session title in the web UI is the SESSION name)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os, sys, subprocess
|
import json, os, shlex, sys, subprocess
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -147,9 +147,15 @@ def start(mode="resume"):
|
|||||||
die(f"opencode not found at {OPENCODE_BIN}")
|
die(f"opencode not found at {OPENCODE_BIN}")
|
||||||
# Attach the orchestrator TUI to the shared opencode web server so it shows up in the
|
# Attach the orchestrator TUI to the shared opencode web server so it shows up in the
|
||||||
# same project/session listing as browser-created sessions.
|
# same project/session listing as browser-created sessions.
|
||||||
|
model_env = ""
|
||||||
|
if LOOP_MODEL:
|
||||||
|
# attach has no --model flag, so inject a one-off config overlay for this session.
|
||||||
|
model_env = (
|
||||||
|
f"OPENCODE_CONFIG_CONTENT={shlex.quote(json.dumps({'model': LOOP_MODEL}))} "
|
||||||
|
)
|
||||||
cmd = (
|
cmd = (
|
||||||
f"set -a; . /srv/cc-ci/.testenv; set +a; "
|
f"set -a; . /srv/cc-ci/.testenv; set +a; "
|
||||||
f"NO_COLOR=1 {OPENCODE_BIN} attach {OPENCODE_SERVER} --dir {WORKDIR}"
|
f"{model_env}NO_COLOR=1 {OPENCODE_BIN} attach {OPENCODE_SERVER} --dir {shlex.quote(WORKDIR)}"
|
||||||
)
|
)
|
||||||
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)")
|
||||||
|
|||||||
@@ -118,15 +118,12 @@ SSHCFG
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
# opencode web server — one shared instance; all agent sessions attach to it.
|
# opencode web server — one shared instance; agent sessions attach to it for web visibility.
|
||||||
# Serves the web UI at http://oc.commoninternet.net (via nginx below, tailscale-only).
|
# Serves the web UI at http://oc.commoninternet.net (via nginx below, tailscale-only).
|
||||||
# TINFOIL_API_KEY and other creds are read from /srv/cc-ci/.testenv at startup.
|
# Provider creds are read from /srv/cc-ci/.testenv at startup.
|
||||||
systemd.services.opencode-web = {
|
systemd.services.opencode-web = {
|
||||||
description = "opencode web server for cc-ci agents (tinfoil/deepseek backend)";
|
description = "opencode web server for cc-ci agents";
|
||||||
# PARKED 2026-06-01: loops run on the claude backend now, so the opencode web server is not
|
wantedBy = [ "multi-user.target" ];
|
||||||
# needed. Definition kept for easy re-enable — restore `wantedBy = [ "multi-user.target" ];`
|
|
||||||
# and rebuild to bring it back.
|
|
||||||
wantedBy = [ ];
|
|
||||||
after = [ "network-online.target" "tailscaled.service" ];
|
after = [ "network-online.target" "tailscaled.service" ];
|
||||||
wants = [ "network-online.target" ];
|
wants = [ "network-online.target" ];
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
@@ -139,17 +136,16 @@ SSHCFG
|
|||||||
Restart = "on-failure";
|
Restart = "on-failure";
|
||||||
RestartSec = "5s";
|
RestartSec = "5s";
|
||||||
};
|
};
|
||||||
environment = { HOME = "/home/loops"; };
|
environment = {
|
||||||
|
HOME = "/home/loops";
|
||||||
|
PATH = lib.mkForce "/run/wrappers/bin:/home/loops/.local/bin:/run/current-system/sw/bin:/usr/bin:/bin:/home/loops/.nix-profile/bin:/nix/profile/bin:/home/loops/.local/state/nix/profile/bin:/etc/profiles/per-user/loops/bin:/nix/var/nix/profiles/default/bin";
|
||||||
|
};
|
||||||
path = [ pkgs.bash pkgs.coreutils pkgs.git pkgs.python3 pkgs.openssh pkgs.tmux pkgs.nettools ];
|
path = [ pkgs.bash pkgs.coreutils pkgs.git pkgs.python3 pkgs.openssh pkgs.tmux pkgs.nettools ];
|
||||||
};
|
};
|
||||||
|
|
||||||
# nginx — reverse-proxy oc.commoninternet.net → opencode web server.
|
# nginx — reverse-proxy oc.commoninternet.net → opencode web server.
|
||||||
# Bound to the tailscale IP so it is only reachable on the tailnet.
|
# Bound to the tailscale IP so it is only reachable on the tailnet.
|
||||||
# PARKED 2026-06-01 alongside opencode-web (loops are on claude now): this vhost just proxies to
|
# DNS: add A record oc.commoninternet.net → 100.84.190.30 (operator step if hostname access is wanted).
|
||||||
# the now-stopped :4096 server, so it's harmless but dormant. Kept (not deleted) so re-enabling
|
|
||||||
# opencode-web restores the UI in one step. If opencode is dropped for good, remove this block
|
|
||||||
# and the DNS step below.
|
|
||||||
# DNS: add A record oc.commoninternet.net → 100.84.190.30 (operator step; only needed if re-enabled).
|
|
||||||
services.nginx = {
|
services.nginx = {
|
||||||
enable = true;
|
enable = true;
|
||||||
recommendedProxySettings = true;
|
recommendedProxySettings = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user