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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-relay-orchestrator",
3
- "version": "0.120.0",
3
+ "version": "0.120.1",
4
4
  "description": "Agent Relay orchestrator — manages agent lifecycle across hosts",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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) rmSync(supervisor.launchScript, { force: true });
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 baseSha = await requireGit(["rev-parse", resume.branch], repoRoot);
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: resume.branch,
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, baseSha], repoRoot);
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: resume.branch,
129
- baseSha,
130
+ ...(baseRef ? { baseRef } : {}),
131
+ ...(baseSha ? { baseSha } : {}),
130
132
  status: "active",
131
133
  deps,
132
134
  ...(symlinks.linked.length || symlinks.errors ? { symlinks } : {}),