Last active
August 10, 2026 18:45
-
-
Save sloev/b2d8dd0844eadb510a1b5bbfefdcb74d to your computer and use it in GitHub Desktop.
deepinfra opencode setup
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { createSignal } from "solid-js" | |
| import { jsx } from "@opentui/solid/jsx-runtime" | |
| import type { TuiPlugin, TuiPluginApi, TuiPluginModule } from "@opencode-ai/plugin/tui" | |
| import { | |
| fetchBudgetState, | |
| fmt, | |
| type BudgetState, | |
| type Status, | |
| } from "../deepinfra-budget-lib.ts" | |
| const REFRESH_MS = 60_000 | |
| const PASEO_THROTTLE_MS = 5 * 60_000 | |
| const tui: TuiPlugin = async (api: TuiPluginApi) => { | |
| const [state, setState] = createSignal<BudgetState>({ | |
| error: null, | |
| dailyPart: "loading…", | |
| dailyPct: "", | |
| dailyStatus: "ok", | |
| monthPart: "loading…", | |
| monthPct: "", | |
| monthStatus: "ok", | |
| blocked: false, | |
| blockReason: null, | |
| todaySpend: 0, | |
| dailyLimit: null, | |
| rollover: null, | |
| monthlySpend: 0, | |
| monthlyBudget: null, | |
| monthlyRemaining: null, | |
| }) | |
| let lastPaseoTs = 0 | |
| let prevExceeded = false | |
| function paseoNotify(event: string) { | |
| if (!process.env.PASEO_TERMINAL_ID) return | |
| if (typeof Bun === "undefined") return | |
| try { | |
| const child = Bun.spawn(["paseo", "hooks", "opencode", event], { | |
| stdin: "ignore", | |
| stdout: "ignore", | |
| stderr: "ignore", | |
| }) | |
| void child.exited.catch(() => {}) | |
| } catch {} | |
| } | |
| async function refresh() { | |
| const next = await fetchBudgetState() | |
| setState(next) | |
| if (next.error) return | |
| const exceeded = next.blocked | |
| if (exceeded && !prevExceeded) { | |
| paseoNotify("budget.daily.exceeded") | |
| api.ui.toast({ | |
| variant: "error", | |
| title: "DeepInfra budget", | |
| message: `Blocked — ${next.blockReason ?? "budget exceeded"}: $${fmt(next.todaySpend)} / $${fmt(next.dailyLimit ?? 0)} daily`, | |
| duration: 6000, | |
| }) | |
| } | |
| prevExceeded = exceeded | |
| if (!exceeded && Date.now() - lastPaseoTs > PASEO_THROTTLE_MS) { | |
| lastPaseoTs = Date.now() | |
| paseoNotify("budget.update") | |
| } | |
| } | |
| paseoNotify("budget.start") | |
| void refresh() | |
| const timer = setInterval(() => void refresh(), REFRESH_MS) | |
| const offIdle = api.event.on("session.idle", () => void refresh()) | |
| api.slots.register({ | |
| order: 100, | |
| slots: { | |
| app_bottom(ctx) { | |
| const s = state() | |
| const th = ctx.theme.current | |
| if (s.error) { | |
| return jsx("box", { | |
| width: "100%", | |
| paddingTop: 1, | |
| paddingLeft: 2, | |
| paddingRight: 2, | |
| flexShrink: 0, | |
| children: jsx("text", { | |
| fg: th.error, | |
| children: [ | |
| "DeepInfra budget: ", | |
| jsx("span", { style: { fg: th.textMuted }, children: s.error }), | |
| ], | |
| }), | |
| }) | |
| } | |
| const fg = (st: Status) => | |
| st === "blocked" | |
| ? th.error | |
| : st === "bad" | |
| ? th.error | |
| : st === "warn" | |
| ? th.warning | |
| : th.success | |
| const children: ReturnType<typeof jsx>[] = [ | |
| jsx("text", { fg: th.textMuted, children: "DeepInfra" }), | |
| jsx("text", { fg: th.textMuted, children: s.dailyPart }), | |
| jsx("text", { fg: fg(s.dailyStatus), children: s.dailyPct }), | |
| jsx("text", { fg: th.textMuted, children: "·" }), | |
| jsx("text", { fg: th.textMuted, children: s.monthPart }), | |
| jsx("text", { fg: fg(s.monthStatus), children: s.monthPct }), | |
| ] | |
| if (s.blocked) { | |
| children.push( | |
| jsx("text", { fg: th.textMuted, children: "·" }), | |
| jsx("text", { | |
| fg: th.error, | |
| style: { bold: true }, | |
| children: `BLOCKED${s.blockReason ? ` (${s.blockReason})` : ""}`, | |
| }), | |
| ) | |
| } | |
| return jsx("box", { | |
| width: "100%", | |
| paddingTop: 1, | |
| paddingLeft: 2, | |
| paddingRight: 2, | |
| flexDirection: "row", | |
| gap: 2, | |
| flexShrink: 0, | |
| children, | |
| }) | |
| }, | |
| }, | |
| }) | |
| api.lifecycle.onDispose(() => { | |
| clearInterval(timer) | |
| offIdle?.() | |
| }) | |
| } | |
| const plugin: TuiPluginModule & { id: string } = { | |
| id: "deepinfra-budget", | |
| tui, | |
| } | |
| export default plugin |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| set -u | |
| HOST=127.0.0.1 | |
| PORT=4096 | |
| log() { echo "[opencode-expose] $*" >&2; } | |
| wait_for_port() { | |
| local attempt=0 | |
| while true; do | |
| attempt=$((attempt + 1)) | |
| code=$(curl -s --max-time 3 -o /dev/null -w '%{http_code}' "http://${HOST}:${PORT}") | |
| rc=$? | |
| if [ "$rc" -eq 0 ]; then | |
| log "attempt ${attempt}: connected, http ${code}" | |
| return 0 | |
| fi | |
| if [ $((attempt % 5)) -eq 1 ]; then | |
| log "attempt ${attempt}: curl exit ${rc} (timeout/refused), retrying" | |
| fi | |
| sleep 1 | |
| done | |
| } | |
| ensure_serve() { | |
| if ! /usr/bin/tailscale serve status 2>/dev/null | grep -q "localhost:${PORT}"; then | |
| log "serve config missing, (re)configuring" | |
| timeout 15 /usr/bin/tailscale serve --bg --https=443 "localhost:${PORT}" \ | |
| || log "tailscale serve command failed, will retry in 30s" | |
| fi | |
| } | |
| log "waiting for opencode on ${HOST}:${PORT}" | |
| wait_for_port | |
| log "opencode is up" | |
| while true; do | |
| ensure_serve | |
| sleep 30 | |
| done |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [Unit] | |
| Description=Expose OpenCode on Tailscale Serve | |
| After=network-online.target tailscaled.service opencode-tailscale.service | |
| Requires=tailscaled.service | |
| BindsTo=opencode-tailscale.service | |
| StartLimitIntervalSec=0 | |
| [Service] | |
| Type=simple | |
| User=nihil | |
| Group=nihil | |
| ExecStart=/home//.opencode/bin/opencode-expose.sh | |
| ExecStop=-/usr/bin/timeout 5 /usr/bin/tailscale serve --https=443 off | |
| Restart=always | |
| RestartSec=30 | |
| TimeoutStopSec=10 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [Unit] | |
| Description=OpenCode Web Server | |
| After=network-online.target | |
| Wants=network-online.target opencode-tailscale-expose.service | |
| StartLimitIntervalSec=0 | |
| [Service] | |
| Type=simple | |
| User=nihil | |
| Group=nihil | |
| Environment="OPENCODE_SERVER_USERNAME=supernihil" | |
| Environment="OPENCODE_SERVER_PASSWORD=break1Down" | |
| Environment="PATH=/home/some/.opencode/bin:/home/nihil/.local/bin:/usr/local/bin:/usr/bin:/bin" | |
| ExecStart=/home//.opencode/bin/opencode web --hostname 127.0.0.1 --port 4096 | |
| ExecStopPost=-/usr/bin/pkill -9 -f '/home/nihil/.opencode/bin/opencode web' | |
| Restart=always | |
| RestartSec=5 | |
| TimeoutStopSec=10 | |
| [Install] | |
| WantedBy=multi-user.target |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment