mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
fix(coding-agent): support bundled experimental processes
This commit is contained in:
parent
c399e34658
commit
a789067a0d
9 changed files with 54 additions and 17 deletions
|
|
@ -23,6 +23,10 @@ export const isBunBinary =
|
|||
/** Detect if Bun is the runtime (compiled binary or bun run) */
|
||||
export const isBunRuntime = !!process.versions.bun;
|
||||
|
||||
/** Detect the esbuild-bundled Node.js distribution. */
|
||||
declare const PI_BUNDLED_NODE: boolean;
|
||||
export const isBundledNode = typeof PI_BUNDLED_NODE !== "undefined" && PI_BUNDLED_NODE;
|
||||
|
||||
// =============================================================================
|
||||
// Install Method Detection
|
||||
// =============================================================================
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import { createJiti } from "jiti/static";
|
|||
import * as _bundledTypebox from "typebox";
|
||||
import * as _bundledTypeboxCompile from "typebox/compile";
|
||||
import * as _bundledTypeboxValue from "typebox/value";
|
||||
import { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from "../../config.ts";
|
||||
import { CONFIG_DIR_NAME, getAgentDir, isBunBinary, isBundledNode } from "../../config.ts";
|
||||
// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,
|
||||
// avoiding a circular dependency. Extensions can import from @earendil-works/pi-coding-agent.
|
||||
import * as _bundledPiCodingAgent from "../../index.ts";
|
||||
|
|
@ -78,8 +78,6 @@ const require = createRequire(import.meta.url);
|
|||
const isNodeSeaBinary =
|
||||
("sea" in process.features && process.features.sea === true) ||
|
||||
process.getBuiltinModule("node:sea")?.isSea() === true;
|
||||
declare const PI_BUNDLED_NODE: boolean;
|
||||
const isBundledNode = typeof PI_BUNDLED_NODE !== "undefined" && PI_BUNDLED_NODE;
|
||||
const isTypeScriptSourceRuntime = !isBunBinary && path.extname(fileURLToPath(import.meta.url)) === ".ts";
|
||||
|
||||
/**
|
||||
|
|
|
|||
10
packages/coding-agent/src/experimental/coordinator-entry.ts
Normal file
10
packages/coding-agent/src/experimental/coordinator-entry.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env node
|
||||
import { runCoordinatorProcess } from "./coordinator.ts";
|
||||
import { consumeInternalProcessRole } from "./process.ts";
|
||||
|
||||
const role = consumeInternalProcessRole();
|
||||
if (role !== "coordinator") throw new Error("Coordinator entrypoint requires an internal coordinator invocation");
|
||||
void runCoordinatorProcess(process.argv.slice(2)).catch((error: unknown) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
@ -1,13 +1,12 @@
|
|||
import { randomUUID } from "node:crypto";
|
||||
import { chmod, lstat, unlink } from "node:fs/promises";
|
||||
import { createConnection, createServer, type Server, type Socket } from "node:net";
|
||||
import { resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import Type, { type Static } from "typebox";
|
||||
import { Check } from "typebox/value";
|
||||
import {
|
||||
consumeInternalProcessRole,
|
||||
encodeControlLine,
|
||||
isDirectInternalProcessEntry,
|
||||
MAX_CONTROL_LINE_BYTES,
|
||||
spawnInternalProcess,
|
||||
} from "./process.ts";
|
||||
|
|
@ -603,7 +602,7 @@ async function cleanupSocket(path: string): Promise<void> {
|
|||
});
|
||||
}
|
||||
|
||||
if (process.argv[1] !== undefined && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
||||
if (isDirectInternalProcessEntry(import.meta.url)) {
|
||||
const role = consumeInternalProcessRole();
|
||||
if (role !== "coordinator") throw new Error("Coordinator entrypoint requires an internal coordinator invocation");
|
||||
void runCoordinatorProcess(process.argv.slice(2)).catch((error: unknown) => {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,22 @@
|
|||
import { type ChildProcess, spawn } from "node:child_process";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { isBunBinary } from "../config.ts";
|
||||
import { join, resolve } from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import { getPackageDir, isBunBinary, isBundledNode } from "../config.ts";
|
||||
|
||||
export const INTERNAL_PROCESS_ENV = "__PI_INTERNAL_SPAWN";
|
||||
|
||||
export type InternalProcessRole = "coordinator" | "server" | "session-worker";
|
||||
|
||||
/** Detect a directly executed source or unbundled internal-process module. */
|
||||
export function isDirectInternalProcessEntry(moduleUrl: string): boolean {
|
||||
return (
|
||||
!isBunBinary &&
|
||||
!isBundledNode &&
|
||||
process.argv[1] !== undefined &&
|
||||
resolve(process.argv[1]) === fileURLToPath(moduleUrl)
|
||||
);
|
||||
}
|
||||
|
||||
/** Read and validate an internal process role without consuming it. */
|
||||
export function getInternalProcessRole(): InternalProcessRole | undefined {
|
||||
const role = process.env[INTERNAL_PROCESS_ENV];
|
||||
|
|
@ -71,6 +82,10 @@ export async function terminateInternalProcess(child: ChildProcess): Promise<voi
|
|||
|
||||
function defaultEntryUrl(role: InternalProcessRole, override: URL | undefined): URL {
|
||||
if (override) return override;
|
||||
if (isBundledNode) {
|
||||
const entry = role === "coordinator" ? "coordinator.js" : "cli.js";
|
||||
return pathToFileURL(join(getPackageDir(), "dist", "bundle", entry));
|
||||
}
|
||||
const javaScript = import.meta.url.endsWith(".js");
|
||||
if (role === "coordinator") {
|
||||
return new URL(javaScript ? "coordinator.js" : "coordinator.ts", import.meta.url);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { randomUUID } from "node:crypto";
|
||||
import { chmod, lstat, mkdir, readFile, writeFile } from "node:fs/promises";
|
||||
import { homedir } from "node:os";
|
||||
import { isAbsolute, join, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { isAbsolute, join } from "node:path";
|
||||
import {
|
||||
BACKGROUND_CONTEXT,
|
||||
type JsonlSessionMetadata,
|
||||
|
|
@ -19,7 +18,12 @@ import lockfile from "proper-lockfile";
|
|||
import { getAgentDir } from "../config.ts";
|
||||
import { resolvePath } from "../utils/paths.ts";
|
||||
import { CoordinatorConnection, type CoordinatorStartupLease, ensureCoordinator } from "./coordinator.ts";
|
||||
import { consumeInternalProcessRole, spawnInternalProcess, terminateInternalProcess } from "./process.ts";
|
||||
import {
|
||||
consumeInternalProcessRole,
|
||||
isDirectInternalProcessEntry,
|
||||
spawnInternalProcess,
|
||||
terminateInternalProcess,
|
||||
} from "./process.ts";
|
||||
import { createExperimentalServerServices } from "./services/server.ts";
|
||||
import { SessionWorkerManager } from "./session-worker-manager.ts";
|
||||
|
||||
|
|
@ -621,7 +625,7 @@ export async function runServerProcess(args: readonly string[]): Promise<void> {
|
|||
}
|
||||
}
|
||||
|
||||
if (process.argv[1] !== undefined && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
||||
if (isDirectInternalProcessEntry(import.meta.url)) {
|
||||
const role = consumeInternalProcessRole();
|
||||
if (role !== "server") throw new Error("Server entrypoint requires an internal server invocation");
|
||||
void runServerProcess(process.argv.slice(2)).catch((error: unknown) => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { randomUUID } from "node:crypto";
|
||||
import { createConnection, type Socket } from "node:net";
|
||||
import { isAbsolute, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { isAbsolute } from "node:path";
|
||||
import {
|
||||
AgentHarness,
|
||||
type AgentHarness as AgentHarnessInstance,
|
||||
|
|
@ -48,7 +47,12 @@ import {
|
|||
toWireLaneSnapshot,
|
||||
toWireRunResult,
|
||||
} from "./harness-wire-adapter.ts";
|
||||
import { consumeInternalProcessRole, encodeControlLine, MAX_CONTROL_LINE_BYTES } from "./process.ts";
|
||||
import {
|
||||
consumeInternalProcessRole,
|
||||
encodeControlLine,
|
||||
isDirectInternalProcessEntry,
|
||||
MAX_CONTROL_LINE_BYTES,
|
||||
} from "./process.ts";
|
||||
import {
|
||||
createSessionWorkerServices,
|
||||
ServiceOperationResultSchema,
|
||||
|
|
@ -952,7 +956,7 @@ export function runSessionWorkerProcess(args: readonly string[]): Promise<void>
|
|||
return runSessionWorkerWithHarness(args, createCodingAgentHarness);
|
||||
}
|
||||
|
||||
if (process.argv[1] !== undefined && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
||||
if (isDirectInternalProcessEntry(import.meta.url)) {
|
||||
const role = consumeInternalProcessRole();
|
||||
if (role !== "session-worker") {
|
||||
throw new Error("Session worker entrypoint requires an internal session-worker invocation");
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ if [[ "$use_stable" == true ]]; then
|
|||
exec "$stable_pi" ${args[@]+"${args[@]}"}
|
||||
fi
|
||||
|
||||
dev_pi="$repo_dir/packages/coding-agent/dist/cli.js"
|
||||
dev_pi="$repo_dir/packages/coding-agent/dist/bundle/cli.js"
|
||||
if [[ ! -x "$dev_pi" ]]; then
|
||||
echo "error: development pi build not found; run \`npm run build\` in $repo_dir" >&2
|
||||
exit 1
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ function outputBytes(metafiles) {
|
|||
|
||||
for (const entry of [
|
||||
join(codingAgentDistDir, "cli.js"),
|
||||
join(codingAgentDistDir, "experimental", "coordinator-entry.js"),
|
||||
join(codingAgentDistDir, "index.js"),
|
||||
join(codingAgentDistDir, "rpc-entry.js"),
|
||||
join(codingAgentDistDir, "client", "index.js"),
|
||||
|
|
@ -134,6 +135,7 @@ const mainResult = await build({
|
|||
entryPoints: {
|
||||
cli: join(codingAgentDistDir, "cli.js"),
|
||||
client: join(codingAgentDistDir, "client", "index.js"),
|
||||
coordinator: join(codingAgentDistDir, "experimental", "coordinator-entry.js"),
|
||||
index: join(codingAgentDistDir, "index.js"),
|
||||
"rpc-entry": join(codingAgentDistDir, "rpc-entry.js"),
|
||||
},
|
||||
|
|
@ -177,6 +179,7 @@ if (dirname(imageResizeOutput) !== dirname(imageResizeWorkerOutput)) {
|
|||
|
||||
validateExternalImports([mainResult.metafile, lazyResult.metafile]);
|
||||
chmodSync(join(bundleDir, "cli.js"), 0o755);
|
||||
chmodSync(join(bundleDir, "coordinator.js"), 0o755);
|
||||
chmodSync(join(bundleDir, "rpc-entry.js"), 0o755);
|
||||
|
||||
const files = new Set([...Object.keys(mainResult.metafile.outputs), ...Object.keys(lazyResult.metafile.outputs)]).size;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue