agent-relay-orchestrator 0.39.0 → 0.41.0

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.39.0",
3
+ "version": "0.41.0",
4
4
  "description": "Agent Relay orchestrator — manages agent lifecycle across hosts",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,7 @@
16
16
  "test": "bun test"
17
17
  },
18
18
  "dependencies": {
19
- "agent-relay-sdk": "0.2.24"
19
+ "agent-relay-sdk": "0.2.26"
20
20
  },
21
21
  "devDependencies": {
22
22
  "@types/bun": "latest",
package/src/control.ts CHANGED
@@ -4,7 +4,7 @@ import type { ManagedAgentReport, RelayClient, RelayCommand } from "./relay";
4
4
  import { handleSelfUpgrade } from "./self-upgrade";
5
5
  import { spawnAgent, stopSession, type SpawnOptions } from "./spawn";
6
6
  import { cleanupWorkspace, mergeWorkspace, pruneWorktrees, reconcileWorkspace, refreshWorkspaceDeps, workspacesRoot } from "./workspace-probe";
7
- import { armWorkspacePrAutoMerge } from "./workspace-pr";
7
+ import { armWorkspacePrAutoMerge, mergeWorkspacePr } from "./workspace-pr";
8
8
 
9
9
  interface ControlHandler {
10
10
  handleCommand(command: RelayCommand): Promise<boolean>;
@@ -135,6 +135,17 @@ export function createControlHandler(
135
135
  prUrl: typeof command.params.prUrl === "string" ? command.params.prUrl : undefined,
136
136
  });
137
137
  await relay.updateCommand(command.id, result.autoMergeArmed ? "succeeded" : "failed", result as unknown as Record<string, unknown>, result.error);
138
+ } else if (command.type === "workspace.pr-merge") {
139
+ const rawPrNumber = command.params.prNumber;
140
+ const result = mergeWorkspacePr({
141
+ id: typeof command.params.workspaceId === "string" ? command.params.workspaceId : undefined,
142
+ repoRoot: typeof command.params.repoRoot === "string" ? command.params.repoRoot : undefined,
143
+ worktreePath: typeof command.params.worktreePath === "string" ? command.params.worktreePath : undefined,
144
+ branch: typeof command.params.branch === "string" ? command.params.branch : undefined,
145
+ prNumber: typeof rawPrNumber === "number" && Number.isSafeInteger(rawPrNumber) ? rawPrNumber : undefined,
146
+ prUrl: typeof command.params.prUrl === "string" ? command.params.prUrl : undefined,
147
+ });
148
+ await relay.updateCommand(command.id, result.relayMerged ? "succeeded" : "failed", result as unknown as Record<string, unknown>, result.error);
138
149
  } else if (command.type === "workspace.deps-refresh") {
139
150
  const result = refreshWorkspaceDeps(
140
151
  typeof command.params.repoRoot === "string" ? command.params.repoRoot : "",
@@ -9,6 +9,8 @@ interface PullRequestState {
9
9
  number?: number;
10
10
  reviewDecision?: PrReviewDecision;
11
11
  statusCheckRollup?: unknown[];
12
+ mergeable?: string;
13
+ mergeStateStatus?: string;
12
14
  }
13
15
 
14
16
  function prReviewDecision(value: unknown): PrReviewDecision | undefined {
@@ -17,7 +19,7 @@ function prReviewDecision(value: unknown): PrReviewDecision | undefined {
17
19
 
18
20
  export function prMergedState(cwd: string, branch: string | undefined): PullRequestState | undefined {
19
21
  if (!branch) return undefined;
20
- const proc = Bun.spawnSync(["gh", "pr", "view", branch, "--json", "state,url,mergeCommit,number,reviewDecision,statusCheckRollup"], {
22
+ const proc = Bun.spawnSync(["gh", "pr", "view", branch, "--json", "state,url,mergeCommit,number,reviewDecision,statusCheckRollup,mergeable,mergeStateStatus"], {
21
23
  cwd,
22
24
  stdin: "ignore",
23
25
  stdout: "pipe",
@@ -33,12 +35,16 @@ export function prMergedState(cwd: string, branch: string | undefined): PullRequ
33
35
  number?: number;
34
36
  reviewDecision?: unknown;
35
37
  statusCheckRollup?: unknown;
38
+ mergeable?: unknown;
39
+ mergeStateStatus?: unknown;
36
40
  };
37
41
  if (!data.state) return undefined;
38
42
  const sha = data.mergeCommit?.oid;
39
43
  const number = typeof data.number === "number" && Number.isSafeInteger(data.number) ? data.number : undefined;
40
44
  const reviewDecision = prReviewDecision(data.reviewDecision);
41
45
  const statusCheckRollup = Array.isArray(data.statusCheckRollup) ? data.statusCheckRollup : undefined;
46
+ const mergeable = typeof data.mergeable === "string" ? data.mergeable : undefined;
47
+ const mergeStateStatus = typeof data.mergeStateStatus === "string" ? data.mergeStateStatus : undefined;
42
48
  return {
43
49
  state: data.state === "MERGED" ? "merged" : "open",
44
50
  url: data.url,
@@ -46,6 +52,8 @@ export function prMergedState(cwd: string, branch: string | undefined): PullRequ
46
52
  ...(number ? { number } : {}),
47
53
  ...(reviewDecision ? { reviewDecision } : {}),
48
54
  ...(statusCheckRollup ? { statusCheckRollup } : {}),
55
+ ...(mergeable ? { mergeable } : {}),
56
+ ...(mergeStateStatus ? { mergeStateStatus } : {}),
49
57
  };
50
58
  } catch {
51
59
  return undefined;
@@ -83,3 +91,35 @@ export function armWorkspacePrAutoMerge(input: {
83
91
  }
84
92
  return { workspaceId: input.id, status: "merge_planned", autoMergeArmed: true, prNumber: input.prNumber, prUrl: input.prUrl };
85
93
  }
94
+
95
+ export function mergeWorkspacePr(input: {
96
+ id?: string;
97
+ repoRoot?: string;
98
+ worktreePath?: string;
99
+ branch?: string;
100
+ prNumber?: number;
101
+ prUrl?: string;
102
+ }): { workspaceId?: string; status: "merge_planned"; relayMerged: boolean; prNumber?: number; prUrl?: string; error?: string } {
103
+ const cwd = input.worktreePath ? resolve(input.worktreePath) : input.repoRoot ? resolve(input.repoRoot) : undefined;
104
+ if (!cwd) return { workspaceId: input.id, status: "merge_planned", relayMerged: false, error: "worktreePath or repoRoot required" };
105
+ const target = input.prNumber ? String(input.prNumber) : input.prUrl ?? input.branch;
106
+ if (!target) return { workspaceId: input.id, status: "merge_planned", relayMerged: false, error: "prNumber, prUrl, or branch required" };
107
+ const proc = Bun.spawnSync(["gh", "pr", "merge", target, "--merge"], {
108
+ cwd,
109
+ stdin: "ignore",
110
+ stdout: "pipe",
111
+ stderr: "pipe",
112
+ env: process.env,
113
+ });
114
+ if (proc.exitCode !== 0) {
115
+ return {
116
+ workspaceId: input.id,
117
+ status: "merge_planned",
118
+ relayMerged: false,
119
+ prNumber: input.prNumber,
120
+ prUrl: input.prUrl,
121
+ error: proc.stderr.toString().trim() || proc.stdout.toString().trim() || "gh pr merge failed",
122
+ };
123
+ }
124
+ return { workspaceId: input.id, status: "merge_planned", relayMerged: true, prNumber: input.prNumber, prUrl: input.prUrl };
125
+ }
@@ -787,7 +787,7 @@ function applyPrMergeState(base: WorkspaceMergePreview, cwd: string, branch: str
787
787
  if (pr.url) base.prUrl = pr.url;
788
788
  if (pr.number) base.prNumber = pr.number;
789
789
  if (pr.reviewDecision) base.reviewDecision = pr.reviewDecision;
790
- if (pr.statusCheckRollup) base.statusCheckRollup = pr.statusCheckRollup;
790
+ if (pr.statusCheckRollup) base.statusCheckRollup = pr.statusCheckRollup; if (pr.mergeable) base.mergeable = pr.mergeable; if (pr.mergeStateStatus) base.mergeStateStatus = pr.mergeStateStatus;
791
791
  if (pr.state !== "merged") return false;
792
792
  base.prMerged = true;
793
793
  if (pr.sha) base.prMergeSha = pr.sha;