agent-relay-orchestrator 0.120.0 → 0.120.1
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/package.json
CHANGED
package/src/spawn/supervisor.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { chmodSync, closeSync, existsSync, openSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { chmodSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import type { OrchestratorConfig } from "../config";
|
|
4
4
|
import type { ManagedSessionExitDiagnostics } from "../relay";
|
|
@@ -15,26 +15,33 @@ import { systemdMainPidAsync, systemdUnitDiagnostics, systemdUnitName } from "./
|
|
|
15
15
|
import type { SessionRecord, SessionSupervisor, SpawnedRunner } from "./types";
|
|
16
16
|
import { execProcess } from "../process";
|
|
17
17
|
|
|
18
|
+
const FILE_BACKED_ENV_PAYLOADS = new Map<string, string>([
|
|
19
|
+
["AGENT_RELAY_AGENT_PROFILE_JSON", "agent-profile.json"],
|
|
20
|
+
["AGENT_RELAY_WORKSPACE_JSON", "workspace.json"],
|
|
21
|
+
["AGENT_RELAY_INJECTION_EVENTS_JSON", "relay-injection-events.json"],
|
|
22
|
+
]);
|
|
23
|
+
|
|
18
24
|
export async function spawnRunner(name: string, command: string[], cwd: string, env: Record<string, string>, logFile: string): Promise<SpawnedRunner> {
|
|
25
|
+
const launchScript = launchScriptPath(name);
|
|
26
|
+
const launch = materializeLaunchPayload(launchScript, command, env);
|
|
19
27
|
if (await shouldUseSystemdSupervisor()) {
|
|
20
28
|
try {
|
|
21
|
-
return await spawnSystemdRunner(name, command, cwd, env, logFile);
|
|
29
|
+
return await spawnSystemdRunner(name, launch.command, cwd, launch.env, logFile);
|
|
22
30
|
} catch (error) {
|
|
23
31
|
console.error(`[orchestrator] systemd runner supervisor unavailable for ${name}: ${errMessage(error)}`);
|
|
24
32
|
console.error("[orchestrator] Falling back to process child; this agent will not survive orchestrator service restart.");
|
|
25
33
|
}
|
|
26
34
|
}
|
|
27
35
|
|
|
28
|
-
const launchScript = launchScriptPath(name);
|
|
29
36
|
ensureSessionDir();
|
|
30
|
-
writeFileSync(launchScript, buildLaunchScript(command, cwd, env), { mode: 0o700 });
|
|
37
|
+
writeFileSync(launchScript, buildLaunchScript(launch.command, cwd, launch.env), { mode: 0o700 });
|
|
31
38
|
chmodSync(launchScript, 0o700);
|
|
32
39
|
|
|
33
40
|
const logFd = openSync(logFile, "a");
|
|
34
41
|
try {
|
|
35
42
|
const proc = Bun.spawn([launchScript], {
|
|
36
43
|
cwd,
|
|
37
|
-
env,
|
|
44
|
+
env: launch.env,
|
|
38
45
|
stdin: "ignore",
|
|
39
46
|
stdout: logFd,
|
|
40
47
|
stderr: logFd,
|
|
@@ -86,6 +93,47 @@ function launchScriptPath(session: string): string {
|
|
|
86
93
|
return join(SESSION_DIR, `${safe}.sh`);
|
|
87
94
|
}
|
|
88
95
|
|
|
96
|
+
function launchPayloadDirPath(launchScript: string): string {
|
|
97
|
+
return `${launchScript}.d`;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function payloadFilePath(launchScript: string, filename: string): string {
|
|
101
|
+
return join(launchPayloadDirPath(launchScript), filename);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function materializeEnvPayload(env: Record<string, string>, launchScript: string): Record<string, string> {
|
|
105
|
+
const nextEnv = { ...env };
|
|
106
|
+
for (const [envKey, filename] of FILE_BACKED_ENV_PAYLOADS) {
|
|
107
|
+
const value = nextEnv[envKey];
|
|
108
|
+
if (typeof value !== "string" || value.length === 0) continue;
|
|
109
|
+
const filePath = payloadFilePath(launchScript, filename);
|
|
110
|
+
mkdirSync(launchPayloadDirPath(launchScript), { recursive: true });
|
|
111
|
+
writeFileSync(filePath, value);
|
|
112
|
+
delete nextEnv[envKey];
|
|
113
|
+
nextEnv[`${envKey}_FILE`] = filePath;
|
|
114
|
+
}
|
|
115
|
+
return nextEnv;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function materializeCommandArg(command: string[], env: Record<string, string>, launchScript: string, flag: string, envKey: string, filename: string): void {
|
|
119
|
+
const index = command.indexOf(flag);
|
|
120
|
+
if (index < 0 || !command[index + 1]) return;
|
|
121
|
+
const filePath = payloadFilePath(launchScript, filename);
|
|
122
|
+
mkdirSync(launchPayloadDirPath(launchScript), { recursive: true });
|
|
123
|
+
writeFileSync(filePath, command[index + 1]!);
|
|
124
|
+
command.splice(index, 2);
|
|
125
|
+
env[`${envKey}_FILE`] = filePath;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function materializeLaunchPayload(launchScript: string, command: string[], env: Record<string, string>): { command: string[]; env: Record<string, string> } {
|
|
129
|
+
const nextCommand = [...command];
|
|
130
|
+
const nextEnv = materializeEnvPayload(env, launchScript);
|
|
131
|
+
materializeCommandArg(nextCommand, nextEnv, launchScript, "--prompt", "AGENT_RELAY_PROMPT", "prompt.txt");
|
|
132
|
+
materializeCommandArg(nextCommand, nextEnv, launchScript, "--system-prompt-append", "AGENT_RELAY_SYSTEM_PROMPT_APPEND", "system-prompt-append.txt");
|
|
133
|
+
materializeCommandArg(nextCommand, nextEnv, launchScript, "--append-system-prompt", "AGENT_RELAY_SYSTEM_PROMPT_APPEND", "system-prompt-append.txt");
|
|
134
|
+
return { command: nextCommand, env: nextEnv };
|
|
135
|
+
}
|
|
136
|
+
|
|
89
137
|
export function buildLaunchScript(command: string[], cwd: string, env: Record<string, string>): string {
|
|
90
138
|
const exports = Object.entries(env)
|
|
91
139
|
.filter(([key, value]) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(key) && value !== undefined)
|
|
@@ -252,7 +300,10 @@ function killSystemdUnit(unit: string): void {
|
|
|
252
300
|
|
|
253
301
|
function cleanupSupervisor(supervisor: SessionSupervisor): void {
|
|
254
302
|
if (supervisor.type === "systemd" && supervisor.unit) stopSystemdUnit(supervisor.unit);
|
|
255
|
-
if (supervisor.launchScript)
|
|
303
|
+
if (supervisor.launchScript) {
|
|
304
|
+
rmSync(supervisor.launchScript, { force: true });
|
|
305
|
+
rmSync(launchPayloadDirPath(supervisor.launchScript), { recursive: true, force: true });
|
|
306
|
+
}
|
|
256
307
|
}
|
|
257
308
|
|
|
258
309
|
export function cleanupSessionRecord(record: SessionRecord): void {
|
|
@@ -91,7 +91,9 @@ export async function resolveSpawnWorkspace(input: WorkspaceResolutionInput): Pr
|
|
|
91
91
|
if (input.resumeWorkspace?.mode === "branch-from") {
|
|
92
92
|
const resume = input.resumeWorkspace;
|
|
93
93
|
const repoRoot = probe.repoRoot;
|
|
94
|
-
const
|
|
94
|
+
const startSha = await requireGit(["rev-parse", resume.branch], repoRoot);
|
|
95
|
+
const baseRef = resume.baseRef ?? await terminalBaseRef(repoRoot, resume.branch);
|
|
96
|
+
const baseSha = resume.baseSha ?? (baseRef ? await requireGit(["rev-parse", baseRef], repoRoot) : undefined);
|
|
95
97
|
const id = workspaceId(input);
|
|
96
98
|
const workspaceRoot = input.workspaceRoot ? resolve(input.workspaceRoot) : workspacesRoot(homedir());
|
|
97
99
|
const worktreePath = join(workspaceRoot, repoSlug(repoRoot), id);
|
|
@@ -103,7 +105,7 @@ export async function resolveSpawnWorkspace(input: WorkspaceResolutionInput): Pr
|
|
|
103
105
|
sourceCwd,
|
|
104
106
|
worktreePath,
|
|
105
107
|
branch: existing.branch,
|
|
106
|
-
baseRef
|
|
108
|
+
baseRef,
|
|
107
109
|
baseSha,
|
|
108
110
|
requestedMode,
|
|
109
111
|
probe,
|
|
@@ -112,7 +114,7 @@ export async function resolveSpawnWorkspace(input: WorkspaceResolutionInput): Pr
|
|
|
112
114
|
|
|
113
115
|
const branch = await availableBranch(repoRoot, branchName(input, id));
|
|
114
116
|
mkdirSync(join(worktreePath, ".."), { recursive: true });
|
|
115
|
-
await requireGit(["worktree", "add", "-b", branch, worktreePath,
|
|
117
|
+
await requireGit(["worktree", "add", "-b", branch, worktreePath, startSha], repoRoot);
|
|
116
118
|
const deps = await provisionWorkspaceDeps(repoRoot, worktreePath);
|
|
117
119
|
const symlinks = provisionWorkspaceSymlinks(repoRoot, worktreePath, input.workspaceSymlinks ?? []);
|
|
118
120
|
return {
|
|
@@ -125,8 +127,8 @@ export async function resolveSpawnWorkspace(input: WorkspaceResolutionInput): Pr
|
|
|
125
127
|
sourceCwd,
|
|
126
128
|
worktreePath,
|
|
127
129
|
branch,
|
|
128
|
-
baseRef:
|
|
129
|
-
baseSha,
|
|
130
|
+
...(baseRef ? { baseRef } : {}),
|
|
131
|
+
...(baseSha ? { baseSha } : {}),
|
|
130
132
|
status: "active",
|
|
131
133
|
deps,
|
|
132
134
|
...(symlinks.linked.length || symlinks.errors ? { symlinks } : {}),
|