@h-rig/runtime 0.0.6-alpha.22 → 0.0.6-alpha.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/rig-agent-dispatch.js +333 -23
- package/dist/src/control-plane/agent-wrapper.js +336 -23
- package/dist/src/control-plane/harness-main.js +142 -17
- package/dist/src/control-plane/hooks/completion-verification.js +142 -17
- package/dist/src/control-plane/native/harness-cli.js +142 -17
- package/dist/src/control-plane/native/pr-automation.js +142 -17
- package/dist/src/control-plane/native/pr-review-gate.js +142 -17
- package/dist/src/control-plane/native/run-ops.js +1 -1
- package/dist/src/control-plane/native/task-ops.js +142 -17
- package/dist/src/control-plane/native/verifier.js +142 -17
- package/dist/src/control-plane/pi-sessiond/bin.js +793 -0
- package/dist/src/control-plane/pi-sessiond/client.js +41 -0
- package/dist/src/control-plane/pi-sessiond/event-hub.js +59 -0
- package/dist/src/control-plane/pi-sessiond/extension-ui-context.js +198 -0
- package/dist/src/control-plane/pi-sessiond/launcher.js +163 -0
- package/dist/src/control-plane/pi-sessiond/server.js +802 -0
- package/dist/src/control-plane/pi-sessiond/session-service.js +540 -0
- package/dist/src/control-plane/pi-sessiond/types.js +1 -0
- package/dist/src/control-plane/runtime/index.js +17 -0
- package/dist/src/control-plane/runtime/isolation/home.js +17 -0
- package/dist/src/control-plane/runtime/isolation/index.js +17 -0
- package/dist/src/control-plane/runtime/isolation/runner.js +17 -0
- package/dist/src/control-plane/runtime/isolation.js +17 -0
- package/dist/src/control-plane/runtime/queue.js +17 -0
- package/package.json +7 -7
|
@@ -568,8 +568,8 @@ var init_backend_bwrap = __esm(() => {
|
|
|
568
568
|
|
|
569
569
|
// packages/runtime/src/control-plane/agent-wrapper.ts
|
|
570
570
|
import { createRequire } from "module";
|
|
571
|
-
import { resolve as
|
|
572
|
-
import { existsSync as
|
|
571
|
+
import { resolve as resolve36 } from "path";
|
|
572
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync20, writeFileSync as writeFileSync13 } from "fs";
|
|
573
573
|
|
|
574
574
|
// packages/runtime/src/control-plane/runtime/context.ts
|
|
575
575
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
@@ -5518,6 +5518,21 @@ var GITHUB_KNOWN_HOSTS = [
|
|
|
5518
5518
|
"github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk="
|
|
5519
5519
|
].join(`
|
|
5520
5520
|
`);
|
|
5521
|
+
function resolveControlPlaneSourceRoot(projectRoot) {
|
|
5522
|
+
const candidates = [
|
|
5523
|
+
process.env.RIG_CONTROL_PLANE_SOURCE_ROOT?.trim(),
|
|
5524
|
+
process.env.RIG_HOST_PROJECT_ROOT?.trim(),
|
|
5525
|
+
resolve25(import.meta.dir, "../../../../.."),
|
|
5526
|
+
projectRoot
|
|
5527
|
+
].filter((value) => Boolean(value));
|
|
5528
|
+
for (const candidate of candidates) {
|
|
5529
|
+
const root = resolve25(candidate);
|
|
5530
|
+
if (existsSync24(resolve25(root, "packages/runtime/src/control-plane/pi-sessiond/bin.ts"))) {
|
|
5531
|
+
return root;
|
|
5532
|
+
}
|
|
5533
|
+
}
|
|
5534
|
+
return "";
|
|
5535
|
+
}
|
|
5521
5536
|
async function runtimeEnv(projectRoot, runtime) {
|
|
5522
5537
|
const bunBinaryPath = resolveBunBinaryPath();
|
|
5523
5538
|
const bunDir = resolveBunInstallDir(bunBinaryPath);
|
|
@@ -5563,9 +5578,11 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5563
5578
|
const runtimeRigGit = resolve25(runtime.binDir, runtimeRigGitFileName());
|
|
5564
5579
|
const preferredShell = existsSync24(runtimeBash) ? runtimeBash : "/bin/bash";
|
|
5565
5580
|
const nativeRuntimeLibraryPath = await materializeNativeRuntimeLibrary(runtime.binDir);
|
|
5581
|
+
const controlPlaneSourceRoot = resolveControlPlaneSourceRoot(projectRoot);
|
|
5566
5582
|
const env = {
|
|
5567
5583
|
PROJECT_RIG_ROOT: projectRoot,
|
|
5568
5584
|
RIG_HOST_PROJECT_ROOT: projectRoot,
|
|
5585
|
+
...controlPlaneSourceRoot ? { RIG_CONTROL_PLANE_SOURCE_ROOT: controlPlaneSourceRoot } : {},
|
|
5569
5586
|
HOME: runtime.homeDir,
|
|
5570
5587
|
TMPDIR: runtime.tmpDir,
|
|
5571
5588
|
XDG_CACHE_HOME: runtime.cacheDir,
|
|
@@ -8884,6 +8901,163 @@ function formatJsonRpcError(error) {
|
|
|
8884
8901
|
return parts.join(" ");
|
|
8885
8902
|
}
|
|
8886
8903
|
|
|
8904
|
+
// packages/runtime/src/control-plane/pi-sessiond/launcher.ts
|
|
8905
|
+
import { randomBytes } from "crypto";
|
|
8906
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync19, readFileSync as readFileSync16, rmSync as rmSync13 } from "fs";
|
|
8907
|
+
import { dirname as dirname14, resolve as resolve35 } from "path";
|
|
8908
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8909
|
+
|
|
8910
|
+
// packages/runtime/src/control-plane/pi-sessiond/client.ts
|
|
8911
|
+
class RigPiSessionDaemonClient {
|
|
8912
|
+
baseUrl;
|
|
8913
|
+
token;
|
|
8914
|
+
constructor(options) {
|
|
8915
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
8916
|
+
this.token = options.token;
|
|
8917
|
+
}
|
|
8918
|
+
static fromConnection(connection, token) {
|
|
8919
|
+
if (connection.mode === "http")
|
|
8920
|
+
return new RigPiSessionDaemonClient({ baseUrl: connection.baseUrl, token });
|
|
8921
|
+
throw new Error("Unix-socket Rig Pi daemon connections are not implemented in this build; use loopback HTTP.");
|
|
8922
|
+
}
|
|
8923
|
+
async request(method, path, body) {
|
|
8924
|
+
const response = await fetch(`${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`, {
|
|
8925
|
+
method,
|
|
8926
|
+
headers: {
|
|
8927
|
+
authorization: `Bearer ${this.token}`,
|
|
8928
|
+
...body === undefined ? {} : { "content-type": "application/json" }
|
|
8929
|
+
},
|
|
8930
|
+
body: body === undefined ? undefined : JSON.stringify(body)
|
|
8931
|
+
});
|
|
8932
|
+
const text = await response.text();
|
|
8933
|
+
const payload = text.trim() ? JSON.parse(text) : undefined;
|
|
8934
|
+
if (!response.ok) {
|
|
8935
|
+
const message = payload && typeof payload === "object" && !Array.isArray(payload) && typeof payload.error === "string" ? payload.error : text || response.statusText;
|
|
8936
|
+
throw new Error(`Rig Pi session daemon request failed (${response.status}): ${message}`);
|
|
8937
|
+
}
|
|
8938
|
+
return payload;
|
|
8939
|
+
}
|
|
8940
|
+
webSocketUrl(path) {
|
|
8941
|
+
const url = new URL(`${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`);
|
|
8942
|
+
url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
|
8943
|
+
url.searchParams.set("token", this.token);
|
|
8944
|
+
return url.toString();
|
|
8945
|
+
}
|
|
8946
|
+
}
|
|
8947
|
+
|
|
8948
|
+
// packages/runtime/src/control-plane/pi-sessiond/launcher.ts
|
|
8949
|
+
var BUILD_CONFIG2 = {};
|
|
8950
|
+
var BAKED_RIG_SOURCE_ROOT = BUILD_CONFIG2.RIG_SOURCE_ROOT ?? "";
|
|
8951
|
+
async function ensureRigPiSessionDaemon(input) {
|
|
8952
|
+
const rootDir = resolve35(input.rootDir);
|
|
8953
|
+
mkdirSync19(rootDir, { recursive: true });
|
|
8954
|
+
const readyFile = resolve35(rootDir, "ready.json");
|
|
8955
|
+
const existing = readDaemonReadyFile(readyFile);
|
|
8956
|
+
const existingHandle = existing ? await tryReady(existing) : null;
|
|
8957
|
+
if (existingHandle)
|
|
8958
|
+
return existingHandle;
|
|
8959
|
+
try {
|
|
8960
|
+
rmSync13(readyFile, { force: true });
|
|
8961
|
+
} catch {}
|
|
8962
|
+
const token = randomBytes(32).toString("hex");
|
|
8963
|
+
const binPath = resolveRigPiSessionDaemonBinPath(input.env);
|
|
8964
|
+
const bunPath = input.env.RIG_BUN_PATH || process.execPath;
|
|
8965
|
+
const proc = Bun.spawn([bunPath, binPath], {
|
|
8966
|
+
cwd: rootDir,
|
|
8967
|
+
env: {
|
|
8968
|
+
...input.env,
|
|
8969
|
+
RIG_PI_SESSIOND_ROOT: rootDir,
|
|
8970
|
+
RIG_PI_SESSIOND_TOKEN: token,
|
|
8971
|
+
RIG_PI_SESSIOND_READY_FILE: readyFile,
|
|
8972
|
+
RIG_PI_SESSIOND_HOST: "127.0.0.1",
|
|
8973
|
+
RIG_PI_SESSIOND_PORT: "0",
|
|
8974
|
+
...input.version ? { RIG_VERSION: input.version } : {},
|
|
8975
|
+
...input.commit ? { RIG_GIT_COMMIT: input.commit } : {}
|
|
8976
|
+
},
|
|
8977
|
+
stdin: "ignore",
|
|
8978
|
+
stdout: "ignore",
|
|
8979
|
+
stderr: "inherit"
|
|
8980
|
+
});
|
|
8981
|
+
proc.unref();
|
|
8982
|
+
const deadline = Date.now() + (input.timeoutMs ?? 15000);
|
|
8983
|
+
while (Date.now() < deadline) {
|
|
8984
|
+
const ready = readDaemonReadyFile(readyFile);
|
|
8985
|
+
const handle = ready ? await tryReady(ready) : null;
|
|
8986
|
+
if (handle)
|
|
8987
|
+
return handle;
|
|
8988
|
+
await sleep(100);
|
|
8989
|
+
}
|
|
8990
|
+
throw new Error(`Rig Pi session daemon did not become ready at ${readyFile}`);
|
|
8991
|
+
}
|
|
8992
|
+
function privateMetadataForDaemon(input) {
|
|
8993
|
+
return { public: input.publicMetadata, daemonConnection: input.connection };
|
|
8994
|
+
}
|
|
8995
|
+
async function tryReady(ready) {
|
|
8996
|
+
const host = typeof ready.host === "string" ? ready.host : "127.0.0.1";
|
|
8997
|
+
const port = typeof ready.port === "number" ? ready.port : Number(ready.port);
|
|
8998
|
+
const token = typeof ready.token === "string" ? ready.token : "";
|
|
8999
|
+
if (!Number.isFinite(port) || port <= 0 || !token)
|
|
9000
|
+
return null;
|
|
9001
|
+
const baseUrl = `http://${host}:${port}`;
|
|
9002
|
+
const client = new RigPiSessionDaemonClient({ baseUrl, token });
|
|
9003
|
+
try {
|
|
9004
|
+
await client.request("GET", "/health");
|
|
9005
|
+
} catch {
|
|
9006
|
+
return null;
|
|
9007
|
+
}
|
|
9008
|
+
return {
|
|
9009
|
+
client,
|
|
9010
|
+
connection: { mode: "http", baseUrl, tokenRef: tokenRefFromReady(ready) },
|
|
9011
|
+
token,
|
|
9012
|
+
ready
|
|
9013
|
+
};
|
|
9014
|
+
}
|
|
9015
|
+
function tokenRefFromReady(ready) {
|
|
9016
|
+
const token = typeof ready.token === "string" ? ready.token : "";
|
|
9017
|
+
return token ? `inline:${token}` : "missing";
|
|
9018
|
+
}
|
|
9019
|
+
function resolveRigPiSessionDaemonBinPath(env) {
|
|
9020
|
+
const explicit = env.RIG_PI_SESSIOND_BIN?.trim();
|
|
9021
|
+
if (explicit)
|
|
9022
|
+
return explicit;
|
|
9023
|
+
const roots = [
|
|
9024
|
+
env.RIG_CONTROL_PLANE_SOURCE_ROOT?.trim(),
|
|
9025
|
+
BAKED_RIG_SOURCE_ROOT.trim(),
|
|
9026
|
+
process.env.RIG_CONTROL_PLANE_SOURCE_ROOT?.trim(),
|
|
9027
|
+
process.env.RIG_HOST_PROJECT_ROOT?.trim(),
|
|
9028
|
+
process.env.PROJECT_RIG_ROOT?.trim()
|
|
9029
|
+
].filter((value) => Boolean(value));
|
|
9030
|
+
for (const root of roots) {
|
|
9031
|
+
const candidate = resolve35(root, "packages/runtime/src/control-plane/pi-sessiond/bin.ts");
|
|
9032
|
+
if (existsSync33(candidate))
|
|
9033
|
+
return candidate;
|
|
9034
|
+
}
|
|
9035
|
+
const moduleCandidate = fileURLToPath2(new URL("./bin.ts", import.meta.url));
|
|
9036
|
+
if (existsSync33(moduleCandidate))
|
|
9037
|
+
return moduleCandidate;
|
|
9038
|
+
throw new Error("Unable to locate rig-pi-sessiond entrypoint. Set RIG_PI_SESSIOND_BIN or RIG_CONTROL_PLANE_SOURCE_ROOT to the Rig source checkout.");
|
|
9039
|
+
}
|
|
9040
|
+
function readDaemonReadyFile(path) {
|
|
9041
|
+
if (!existsSync33(path))
|
|
9042
|
+
return null;
|
|
9043
|
+
try {
|
|
9044
|
+
const parsed = JSON.parse(readFileSync16(path, "utf8"));
|
|
9045
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
9046
|
+
} catch {
|
|
9047
|
+
return null;
|
|
9048
|
+
}
|
|
9049
|
+
}
|
|
9050
|
+
function sleep(ms) {
|
|
9051
|
+
return new Promise((resolveSleep) => setTimeout(resolveSleep, ms));
|
|
9052
|
+
}
|
|
9053
|
+
function resolveRigPiSessionDaemonRoot(stateDir) {
|
|
9054
|
+
const root = resolve35(stateDir, "pi-sessiond");
|
|
9055
|
+
mkdirSync19(dirname14(root), { recursive: true });
|
|
9056
|
+
if (!existsSync33(root))
|
|
9057
|
+
mkdirSync19(root, { recursive: true });
|
|
9058
|
+
return root;
|
|
9059
|
+
}
|
|
9060
|
+
|
|
8887
9061
|
// packages/runtime/src/control-plane/agent-wrapper.ts
|
|
8888
9062
|
var requireFromRuntime = createRequire(import.meta.url);
|
|
8889
9063
|
async function finalizeRuntimeSnapshot(snapshotSidecar, providerCommand, exitCode, context) {
|
|
@@ -8918,7 +9092,7 @@ async function startOptionalRuntimeSnapshotSidecar(runtime, startSidecar = start
|
|
|
8918
9092
|
}
|
|
8919
9093
|
}
|
|
8920
9094
|
async function runAgentWrapper(options = {}) {
|
|
8921
|
-
const projectRoot =
|
|
9095
|
+
const projectRoot = resolve36(options.projectRoot || process.env.PROJECT_RIG_ROOT || process.cwd());
|
|
8922
9096
|
const monorepoRoot = resolveMonorepoRoot2(projectRoot);
|
|
8923
9097
|
const argv = options.argv || process.argv.slice(2);
|
|
8924
9098
|
if (argv.length === 0 || argv[0] === "--version" || argv[0] === "--help" || argv[0] === "help") {
|
|
@@ -8981,7 +9155,8 @@ async function runAgentWrapper(options = {}) {
|
|
|
8981
9155
|
return 1;
|
|
8982
9156
|
}
|
|
8983
9157
|
const providerArgs = buildProviderArgs(provider, runtime, argv);
|
|
8984
|
-
const
|
|
9158
|
+
const normalPiDaemonPath = provider === "pi" && process.env.RIG_PI_RPC_FALLBACK !== "1";
|
|
9159
|
+
const providerCommand = normalPiDaemonPath ? ["rig-pi-sessiond", ...providerArgs] : [providerBinary(provider), ...providerArgs];
|
|
8985
9160
|
emitWrapperEvent("provider.launch", {
|
|
8986
9161
|
provider,
|
|
8987
9162
|
runtimeId: runtime.id,
|
|
@@ -8993,11 +9168,11 @@ async function runAgentWrapper(options = {}) {
|
|
|
8993
9168
|
const bypassOuterRuntimeSandbox = shouldBypassProviderSandboxOnPlatform(provider, process.platform);
|
|
8994
9169
|
const runClaudeCompatUnsandboxed = provider === "claude-code" && bypassOuterRuntimeSandbox;
|
|
8995
9170
|
if (runClaudeCompatUnsandboxed && process.env.HOME?.trim()) {
|
|
8996
|
-
env.CLAUDE_HOME =
|
|
9171
|
+
env.CLAUDE_HOME = resolve36(process.env.HOME.trim(), ".claude");
|
|
8997
9172
|
env.RIG_CLAUDE_RUNTIME_HOME = runtime.claudeHomeDir;
|
|
8998
9173
|
}
|
|
8999
9174
|
if (provider === "pi") {
|
|
9000
|
-
env.PI_CODING_AGENT_DIR =
|
|
9175
|
+
env.PI_CODING_AGENT_DIR = resolve36(runtime.homeDir, ".pi", "agent");
|
|
9001
9176
|
env.PI_CODING_AGENT_SESSION_DIR = runtime.sessionDir;
|
|
9002
9177
|
}
|
|
9003
9178
|
env.RIG_RUNTIME_SANDBOX = "enforce";
|
|
@@ -9031,9 +9206,19 @@ async function runAgentWrapper(options = {}) {
|
|
|
9031
9206
|
},
|
|
9032
9207
|
command: providerCommand
|
|
9033
9208
|
})).command;
|
|
9034
|
-
if (provider === "pi" &&
|
|
9209
|
+
if (provider === "pi" && process.env.RIG_PI_RPC_FALLBACK !== "1") {
|
|
9035
9210
|
const prompt = await readProcessStdin();
|
|
9036
|
-
exitCode = await
|
|
9211
|
+
exitCode = await runPiSessionDaemonProvider({
|
|
9212
|
+
projectRoot,
|
|
9213
|
+
runtime,
|
|
9214
|
+
env,
|
|
9215
|
+
prompt,
|
|
9216
|
+
runId: process.env.RIG_SERVER_RUN_ID?.trim() || process.env.RIG_RUN_ID?.trim() || undefined,
|
|
9217
|
+
sessionName: process.env.RIG_SERVER_RUN_ID?.trim() ? `Rig ${process.env.RIG_SERVER_RUN_ID.trim()}` : `Rig ${runtime.taskId}`
|
|
9218
|
+
});
|
|
9219
|
+
} else if (provider === "pi" && isPiRpcArgs(providerArgs)) {
|
|
9220
|
+
const prompt = await readProcessStdin();
|
|
9221
|
+
exitCode = await runPiRpcProviderFallback({
|
|
9037
9222
|
command,
|
|
9038
9223
|
cwd: runtime.workspaceDir,
|
|
9039
9224
|
env,
|
|
@@ -9164,7 +9349,129 @@ function steeringMessageText(entry) {
|
|
|
9164
9349
|
function isPiRpcArgs(args) {
|
|
9165
9350
|
return cliOptionValue(args, "--mode") === "rpc";
|
|
9166
9351
|
}
|
|
9167
|
-
async function
|
|
9352
|
+
async function runPiSessionDaemonProvider(input) {
|
|
9353
|
+
const stdout = input.stdout ?? process.stdout;
|
|
9354
|
+
const stderr = input.stderr ?? process.stderr;
|
|
9355
|
+
const runId = input.runId ?? input.runtime.taskId;
|
|
9356
|
+
emitWrapperEvent("pi.sessiond.starting", {
|
|
9357
|
+
runId,
|
|
9358
|
+
runtimeId: input.runtime.id,
|
|
9359
|
+
workspaceDir: input.runtime.workspaceDir
|
|
9360
|
+
});
|
|
9361
|
+
const daemon = await ensureRigPiSessionDaemon({
|
|
9362
|
+
rootDir: resolveRigPiSessionDaemonRoot(input.runtime.stateDir),
|
|
9363
|
+
env: input.env,
|
|
9364
|
+
version: process.env.RIG_VERSION?.trim() || "dev",
|
|
9365
|
+
commit: process.env.RIG_GIT_COMMIT?.trim() || undefined
|
|
9366
|
+
});
|
|
9367
|
+
emitWrapperEvent("pi.sessiond.ready", {
|
|
9368
|
+
runId,
|
|
9369
|
+
runtimeId: input.runtime.id,
|
|
9370
|
+
connection: daemon.connection,
|
|
9371
|
+
ready: daemon.ready
|
|
9372
|
+
});
|
|
9373
|
+
const start = await daemon.client.request("POST", "/sessions", {
|
|
9374
|
+
runId,
|
|
9375
|
+
cwd: input.runtime.workspaceDir,
|
|
9376
|
+
agentDir: input.env.PI_CODING_AGENT_DIR || resolve36(input.runtime.homeDir, ".pi", "agent"),
|
|
9377
|
+
sessionDir: input.runtime.sessionDir,
|
|
9378
|
+
sessionName: input.sessionName
|
|
9379
|
+
});
|
|
9380
|
+
const privateMetadata = privateMetadataForDaemon({ publicMetadata: start.metadata, connection: daemon.connection });
|
|
9381
|
+
emitWrapperEvent("pi.session.ready", {
|
|
9382
|
+
runId,
|
|
9383
|
+
runtimeId: input.runtime.id,
|
|
9384
|
+
metadata: start.metadata,
|
|
9385
|
+
privateMetadata
|
|
9386
|
+
});
|
|
9387
|
+
const eventStream = waitForPiSessionEvents({
|
|
9388
|
+
url: daemon.client.webSocketUrl(`/sessions/${encodeURIComponent(start.metadata.sessionId)}/events`),
|
|
9389
|
+
stdout,
|
|
9390
|
+
stderr,
|
|
9391
|
+
runId
|
|
9392
|
+
});
|
|
9393
|
+
emitWrapperEvent("pi.session.event_stream.connected", { runId, sessionId: start.metadata.sessionId });
|
|
9394
|
+
const forwardSigterm = () => {
|
|
9395
|
+
daemon.client.request("POST", `/sessions/${encodeURIComponent(start.metadata.sessionId)}/abort`).catch(() => {
|
|
9396
|
+
return;
|
|
9397
|
+
});
|
|
9398
|
+
eventStream.close();
|
|
9399
|
+
};
|
|
9400
|
+
process.once("SIGTERM", forwardSigterm);
|
|
9401
|
+
try {
|
|
9402
|
+
if (input.prompt.trim()) {
|
|
9403
|
+
await daemon.client.request("POST", `/sessions/${encodeURIComponent(start.metadata.sessionId)}/prompt`, { text: input.prompt });
|
|
9404
|
+
emitWrapperEvent("pi.prompt.sent", { runId, sessionId: start.metadata.sessionId, bytes: Buffer.byteLength(input.prompt) });
|
|
9405
|
+
} else {
|
|
9406
|
+
emitWrapperEvent("pi.prompt.waiting", { runId, sessionId: start.metadata.sessionId, reason: "empty-initial-prompt" });
|
|
9407
|
+
}
|
|
9408
|
+
const result = await eventStream.done;
|
|
9409
|
+
if (result.error) {
|
|
9410
|
+
stderr.write(`[rig-agent] Pi session daemon stream failed: ${result.error}
|
|
9411
|
+
`);
|
|
9412
|
+
return 1;
|
|
9413
|
+
}
|
|
9414
|
+
return 0;
|
|
9415
|
+
} finally {
|
|
9416
|
+
process.off("SIGTERM", forwardSigterm);
|
|
9417
|
+
eventStream.close();
|
|
9418
|
+
}
|
|
9419
|
+
}
|
|
9420
|
+
function waitForPiSessionEvents(input) {
|
|
9421
|
+
let closed = false;
|
|
9422
|
+
let resolved = false;
|
|
9423
|
+
let socket = null;
|
|
9424
|
+
let resolveDone = () => {
|
|
9425
|
+
return;
|
|
9426
|
+
};
|
|
9427
|
+
const done = new Promise((resolveDoneInner) => {
|
|
9428
|
+
resolveDone = resolveDoneInner;
|
|
9429
|
+
});
|
|
9430
|
+
const finish = (value) => {
|
|
9431
|
+
if (resolved)
|
|
9432
|
+
return;
|
|
9433
|
+
resolved = true;
|
|
9434
|
+
resolveDone(value);
|
|
9435
|
+
};
|
|
9436
|
+
socket = new WebSocket(input.url);
|
|
9437
|
+
socket.addEventListener("message", (message) => {
|
|
9438
|
+
const text = typeof message.data === "string" ? message.data : Buffer.from(message.data).toString("utf8");
|
|
9439
|
+
input.stdout.write(`${text}
|
|
9440
|
+
`);
|
|
9441
|
+
const envelope = parseJsonRecord(text);
|
|
9442
|
+
if (!envelope)
|
|
9443
|
+
return;
|
|
9444
|
+
if (envelope.type === "pi.event") {
|
|
9445
|
+
const event = envelope.event && typeof envelope.event === "object" && !Array.isArray(envelope.event) ? envelope.event : null;
|
|
9446
|
+
if (event?.type === "agent_end") {
|
|
9447
|
+
emitWrapperEvent("pi.session.agent_end", { runId: input.runId, sessionId: envelope.sessionId });
|
|
9448
|
+
finish({});
|
|
9449
|
+
}
|
|
9450
|
+
}
|
|
9451
|
+
if (envelope.type === "error") {
|
|
9452
|
+
emitWrapperEvent("pi.session.error", { runId: input.runId, message: envelope.message, detail: envelope.detail ?? null });
|
|
9453
|
+
finish({ error: envelope.message });
|
|
9454
|
+
}
|
|
9455
|
+
});
|
|
9456
|
+
socket.addEventListener("error", () => {
|
|
9457
|
+
if (!closed)
|
|
9458
|
+
finish({ error: "WebSocket error" });
|
|
9459
|
+
});
|
|
9460
|
+
socket.addEventListener("close", () => {
|
|
9461
|
+
if (!closed && !resolved)
|
|
9462
|
+
finish({ error: "WebSocket closed before agent_end" });
|
|
9463
|
+
});
|
|
9464
|
+
return {
|
|
9465
|
+
done,
|
|
9466
|
+
close: () => {
|
|
9467
|
+
closed = true;
|
|
9468
|
+
try {
|
|
9469
|
+
socket?.close();
|
|
9470
|
+
} catch {}
|
|
9471
|
+
}
|
|
9472
|
+
};
|
|
9473
|
+
}
|
|
9474
|
+
async function runPiRpcProviderFallback(input) {
|
|
9168
9475
|
const stdout = input.stdout ?? process.stdout;
|
|
9169
9476
|
const stderr = input.stderr ?? process.stderr;
|
|
9170
9477
|
const proc = Bun.spawn(input.command, {
|
|
@@ -9231,7 +9538,7 @@ async function runPiRpcProvider(input) {
|
|
|
9231
9538
|
error: error instanceof Error ? error.message : String(error)
|
|
9232
9539
|
});
|
|
9233
9540
|
}
|
|
9234
|
-
await
|
|
9541
|
+
await sleep2(1000);
|
|
9235
9542
|
}
|
|
9236
9543
|
};
|
|
9237
9544
|
const stdoutPump = pumpReadableLines(proc.stdout, (line) => {
|
|
@@ -9327,6 +9634,9 @@ function buildProviderArgs(provider, runtime, argv) {
|
|
|
9327
9634
|
}
|
|
9328
9635
|
if (provider === "pi") {
|
|
9329
9636
|
const piArgs = [...argv];
|
|
9637
|
+
if (piArgs.includes("__rig_pi_session_daemon__")) {
|
|
9638
|
+
return piArgs.filter((arg) => arg !== "__rig_pi_session_daemon__");
|
|
9639
|
+
}
|
|
9330
9640
|
const piProvider = cliOptionValue(piArgs, "--provider") || process.env.RIG_PI_PROVIDER?.trim() || "openai-codex";
|
|
9331
9641
|
if (!hasCliOption(piArgs, "--provider")) {
|
|
9332
9642
|
piArgs.unshift(piProvider);
|
|
@@ -9457,8 +9767,8 @@ function resolveFromShellPath(binary) {
|
|
|
9457
9767
|
function resolveBundledPiBinary() {
|
|
9458
9768
|
try {
|
|
9459
9769
|
const packageJson = requireFromRuntime.resolve("@earendil-works/pi-coding-agent/package.json");
|
|
9460
|
-
const binaryPath =
|
|
9461
|
-
return
|
|
9770
|
+
const binaryPath = resolve36(packageJson, "..", "dist", "cli.js");
|
|
9771
|
+
return existsSync34(binaryPath) ? binaryPath : null;
|
|
9462
9772
|
} catch {
|
|
9463
9773
|
return null;
|
|
9464
9774
|
}
|
|
@@ -9479,7 +9789,7 @@ function providerBinary(provider) {
|
|
|
9479
9789
|
function emitWrapperEvent(type, payload) {
|
|
9480
9790
|
console.log(`__RIG_WRAPPER_EVENT__${JSON.stringify({ type, payload, at: new Date().toISOString() })}`);
|
|
9481
9791
|
}
|
|
9482
|
-
function
|
|
9792
|
+
function sleep2(ms) {
|
|
9483
9793
|
return new Promise((resolveSleep) => setTimeout(resolveSleep, ms));
|
|
9484
9794
|
}
|
|
9485
9795
|
async function waitForDirtyBaselineReady(runtime, taskId) {
|
|
@@ -9494,11 +9804,11 @@ async function waitForDirtyBaselineReady(runtime, taskId) {
|
|
|
9494
9804
|
workspaceDir: runtime.workspaceDir,
|
|
9495
9805
|
readyFile
|
|
9496
9806
|
});
|
|
9497
|
-
while (!
|
|
9807
|
+
while (!existsSync34(readyFile)) {
|
|
9498
9808
|
if (Date.now() >= deadline) {
|
|
9499
9809
|
throw new Error(`Timed out waiting for dirty baseline ready file: ${readyFile}`);
|
|
9500
9810
|
}
|
|
9501
|
-
await
|
|
9811
|
+
await sleep2(50);
|
|
9502
9812
|
}
|
|
9503
9813
|
emitWrapperEvent("runtime.baseline.completed", {
|
|
9504
9814
|
runtimeId: runtime.id,
|
|
@@ -9562,9 +9872,9 @@ async function readPluginTaskStatus(projectRoot, taskId) {
|
|
|
9562
9872
|
}
|
|
9563
9873
|
}
|
|
9564
9874
|
function recordRuntimeHandoff(hostProjectRoot, runtime, taskId, exitCode) {
|
|
9565
|
-
const handoffDir =
|
|
9566
|
-
|
|
9567
|
-
const handoffPath =
|
|
9875
|
+
const handoffDir = resolve36(hostProjectRoot, ".rig/runtime/handoffs");
|
|
9876
|
+
mkdirSync20(handoffDir, { recursive: true });
|
|
9877
|
+
const handoffPath = resolve36(handoffDir, `${taskId}-${Date.now()}.json`);
|
|
9568
9878
|
const handoff = {
|
|
9569
9879
|
taskId,
|
|
9570
9880
|
runtimeId: runtime.id,
|
|
@@ -9630,13 +9940,13 @@ async function readTaskMetadata2(taskRoot, taskId) {
|
|
|
9630
9940
|
async function readTaskConfigHints(taskRoot, taskId) {
|
|
9631
9941
|
const runtimeContext = loadRuntimeContextFromEnv();
|
|
9632
9942
|
const candidates = [
|
|
9633
|
-
runtimeContext?.monorepoMainRoot ?
|
|
9634
|
-
process.env.MONOREPO_MAIN_ROOT?.trim() ?
|
|
9635
|
-
|
|
9636
|
-
|
|
9943
|
+
runtimeContext?.monorepoMainRoot ? resolve36(runtimeContext.monorepoMainRoot, ".rig", "task-config.json") : "",
|
|
9944
|
+
process.env.MONOREPO_MAIN_ROOT?.trim() ? resolve36(process.env.MONOREPO_MAIN_ROOT.trim(), ".rig", "task-config.json") : "",
|
|
9945
|
+
resolve36(taskRoot, ".rig", "task-config.json"),
|
|
9946
|
+
resolve36(taskRoot, "rig", "task-config.json")
|
|
9637
9947
|
].filter(Boolean);
|
|
9638
9948
|
for (const configPath of candidates) {
|
|
9639
|
-
if (!
|
|
9949
|
+
if (!existsSync34(configPath)) {
|
|
9640
9950
|
continue;
|
|
9641
9951
|
}
|
|
9642
9952
|
try {
|