worker: make/jq/gopls in base image + per-repo .lvmh/setup.sh hook (agent-driven persistent setup)
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
# docker/ — worker image & bridge
|
||||
|
||||
## lvmh-worker image (`worker.Dockerfile`)
|
||||
|
||||
Headless pi worker: node 24, pi (global npm), golang, git, ripgrep, make, jq,
|
||||
gopls, plus the user's pi config baked from dotfiles (`deploy/rsync-pi-agent.sh`:
|
||||
settings/skills/agents/extensions; no auth.json/sessions/cache; `git:` packages
|
||||
dropped — postinstalls crash headless installs).
|
||||
|
||||
## Per-repo setup hook (agent-driven image setup)
|
||||
|
||||
The agent works as root with network access, so it can `apt-get install` /
|
||||
`go install` anything **in-session**. Containers are ephemeral, so system
|
||||
packages vanish on container stop. For durability, a repo can ship:
|
||||
|
||||
/workspace/.lvmh/setup.sh
|
||||
|
||||
The bridge (`bridge/index.mjs`) runs it with bash on **every spawn** before the
|
||||
pi session starts (10-min timeout, failure is non-fatal — logged, session
|
||||
continues). Since `/workspace` is a persistent per-repo volume, the hook
|
||||
survives container death. Agents that need extra tooling should write that
|
||||
script into the repo (e.g. `apt-get update && apt-get install -y sqlite3`).
|
||||
|
||||
## bridge/index.mjs
|
||||
|
||||
Hosts the SDK session (`createAgentSession` + `bindExtensions({mode:"rpc"})` —
|
||||
the SDK never fires `session_start` without the explicit bind, and the lvmh
|
||||
plugin dials home off that event).
|
||||
@@ -2,13 +2,51 @@
|
||||
// at /root/.pi/agent/extensions/lvmh-agent.ts) dials the daemon and delivers
|
||||
// web prompts through pi.sendUserMessage. This process just hosts the session.
|
||||
// Global npm layout: resolve pi via absolute path (NODE_PATH does not apply to ESM).
|
||||
import { spawn } from "node:child_process";
|
||||
import { existsSync } from "node:fs";
|
||||
import { createAgentSession } from "/usr/local/lib/node_modules/@earendil-works/pi-coding-agent/dist/index.js";
|
||||
|
||||
const SETUP_PATH = "/workspace/.lvmh/setup.sh";
|
||||
const SETUP_TIMEOUT_MS = 10 * 60 * 1000;
|
||||
|
||||
// Repo-level setup hook: if the repo ships .lvmh/setup.sh, run it before the
|
||||
// session starts (apt-get/go install/pip — anything the agent needs).
|
||||
// /workspace is a persistent per-repo volume, so the hook survives container
|
||||
// restarts and re-runs on every spawn. Failure is non-fatal: log and continue.
|
||||
async function runRepoSetup() {
|
||||
if (!existsSync(SETUP_PATH)) return;
|
||||
console.error(`[lvmh-bridge] running repo setup: ${SETUP_PATH}`);
|
||||
const code = await new Promise((resolve) => {
|
||||
const child = spawn("bash", [SETUP_PATH], {
|
||||
cwd: "/workspace",
|
||||
stdio: ["ignore", "inherit", "inherit"],
|
||||
});
|
||||
const timer = setTimeout(() => {
|
||||
console.error(`[lvmh-bridge] setup timed out after ${SETUP_TIMEOUT_MS}ms, killing`);
|
||||
child.kill("SIGKILL");
|
||||
resolve(124);
|
||||
}, SETUP_TIMEOUT_MS);
|
||||
timer.unref?.();
|
||||
child.on("error", (err) => {
|
||||
clearTimeout(timer);
|
||||
console.error("[lvmh-bridge] setup spawn error:", err);
|
||||
resolve(1);
|
||||
});
|
||||
child.on("exit", (c) => {
|
||||
clearTimeout(timer);
|
||||
resolve(c ?? 1);
|
||||
});
|
||||
});
|
||||
if (code === 0) console.error("[lvmh-bridge] setup completed");
|
||||
else console.error(`[lvmh-bridge] setup exited ${code} — continuing anyway`);
|
||||
}
|
||||
|
||||
process.on("unhandledRejection", (err) => {
|
||||
console.error("[lvmh-bridge] unhandledRejection:", err);
|
||||
});
|
||||
|
||||
try {
|
||||
await runRepoSetup();
|
||||
const { session } = await createAgentSession();
|
||||
// SDK does not bind extensions implicitly (unlike TUI/RPC modes); without
|
||||
// bindExtensions the session_start event never fires, so the lvmh plugin
|
||||
|
||||
@@ -5,10 +5,12 @@ FROM node:24-bookworm-slim
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
bash ca-certificates git ripgrep curl xz-utils \
|
||||
bash ca-certificates git ripgrep curl xz-utils make jq \
|
||||
golang-go \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN GOBIN=/usr/local/bin go install golang.org/x/tools/gopls@latest || true
|
||||
|
||||
RUN npm install -g --ignore-scripts @earendil-works/pi-coding-agent
|
||||
|
||||
# User's pi config from dotfiles (settings, skills, agents, extensions,
|
||||
|
||||
Reference in New Issue
Block a user