agent-relay-orchestrator 0.91.3 → 0.92.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 +3 -2
- package/src/control.ts +27 -1
- package/src/index.ts +7 -3
- package/src/shared-callmux.ts +44 -5
- package/src/spawn/runtime.ts +7 -4
- package/src/spawn/sessions.ts +10 -2
- package/src/spawn/supervisor.ts +1 -39
- package/src/spawn/systemd.ts +73 -6
- package/src/spawn/types.ts +3 -0
- package/src/workspace-probe/idle-refresh.ts +110 -0
- package/src/workspace-probe/index.ts +1 -0
- package/src/workspace-probe/merge.ts +5 -1
- package/src/workspace-probe/probe.ts +58 -1
- package/src/workspace-probe/types.ts +17 -0
- package/vendor/callmux/bin/callmux.js +47579 -0
- package/vendor/callmux/package.json +11 -0
- package/vendor/callmux/schema.json +868 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdirSync, statSync } from "node:fs";
|
|
1
|
+
import { existsSync, mkdirSync, statSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
4
|
import type { WorkspaceMode, WorkspaceProbe } from "agent-relay-sdk";
|
|
@@ -61,6 +61,63 @@ export async function resolveSpawnWorkspace(input: WorkspaceResolutionInput): Pr
|
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
// #635 — attach to an existing worktree instead of creating a fresh one.
|
|
65
|
+
if (input.resumeWorkspace?.mode === "attach") {
|
|
66
|
+
const resume = input.resumeWorkspace;
|
|
67
|
+
const wtp = resume.worktreePath;
|
|
68
|
+
if (!wtp) throw new Error("resumeWorkspace attach: worktreePath is required");
|
|
69
|
+
if (!existsSync(wtp)) throw new Error(`resumeWorkspace attach: worktree does not exist: ${wtp}`);
|
|
70
|
+
return {
|
|
71
|
+
cwd: wtp,
|
|
72
|
+
workspace: {
|
|
73
|
+
...(resume.workspaceId ? { id: resume.workspaceId } : { id: workspaceId(input) }),
|
|
74
|
+
mode: "isolated",
|
|
75
|
+
requestedMode,
|
|
76
|
+
repoRoot: probe.repoRoot,
|
|
77
|
+
sourceCwd,
|
|
78
|
+
worktreePath: wtp,
|
|
79
|
+
branch: resume.branch,
|
|
80
|
+
...(resume.baseRef ? { baseRef: resume.baseRef } : {}),
|
|
81
|
+
...(resume.baseSha ? { baseSha: resume.baseSha } : {}),
|
|
82
|
+
status: "active",
|
|
83
|
+
probe,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// #635 — create a fresh worktree off an existing branch's HEAD instead of main's HEAD.
|
|
89
|
+
if (input.resumeWorkspace?.mode === "branch-from") {
|
|
90
|
+
const resume = input.resumeWorkspace;
|
|
91
|
+
const repoRoot = probe.repoRoot;
|
|
92
|
+
const baseSha = requireGit(["rev-parse", resume.branch], repoRoot);
|
|
93
|
+
const id = workspaceId(input);
|
|
94
|
+
const branch = await availableBranch(repoRoot, branchName(input, id));
|
|
95
|
+
const workspaceRoot = input.workspaceRoot ? resolve(input.workspaceRoot) : workspacesRoot(homedir());
|
|
96
|
+
const worktreePath = join(workspaceRoot, repoSlug(repoRoot), id);
|
|
97
|
+
mkdirSync(join(worktreePath, ".."), { recursive: true });
|
|
98
|
+
requireGit(["worktree", "add", "-b", branch, worktreePath, baseSha], repoRoot);
|
|
99
|
+
const deps = provisionWorkspaceDeps(repoRoot, worktreePath);
|
|
100
|
+
const symlinks = provisionWorkspaceSymlinks(repoRoot, worktreePath, input.workspaceSymlinks ?? []);
|
|
101
|
+
return {
|
|
102
|
+
cwd: worktreePath,
|
|
103
|
+
workspace: {
|
|
104
|
+
id,
|
|
105
|
+
mode: "isolated",
|
|
106
|
+
requestedMode,
|
|
107
|
+
repoRoot,
|
|
108
|
+
sourceCwd,
|
|
109
|
+
worktreePath,
|
|
110
|
+
branch,
|
|
111
|
+
baseRef: resume.branch,
|
|
112
|
+
baseSha,
|
|
113
|
+
status: "active",
|
|
114
|
+
deps,
|
|
115
|
+
...(symlinks.linked.length || symlinks.errors ? { symlinks } : {}),
|
|
116
|
+
probe,
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
64
121
|
const id = workspaceId(input);
|
|
65
122
|
const repoRoot = probe.repoRoot;
|
|
66
123
|
const baseRef = terminalBaseRef(repoRoot, probe.branch);
|
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import type { WorkspaceMetadata, WorkspaceMode } from "agent-relay-sdk";
|
|
2
2
|
import type { WorkspaceMergeResult } from "agent-relay-sdk";
|
|
3
3
|
|
|
4
|
+
/** Attach to or branch off an existing managed worktree instead of creating a fresh one (#635). */
|
|
5
|
+
export interface ResumeWorkspaceTarget {
|
|
6
|
+
branch: string;
|
|
7
|
+
/** `attach` = reuse the existing worktree as-is (crash recovery). `branch-from` = new worktree off the existing branch HEAD. */
|
|
8
|
+
mode: "attach" | "branch-from";
|
|
9
|
+
/** Resolved worktree path from the relay DB. For `attach`: must exist on disk. For `branch-from`: unused (HEAD resolved from branch). */
|
|
10
|
+
worktreePath?: string;
|
|
11
|
+
/** Existing workspace DB id. For `attach`: passed back so the relay reuses the same record (avoids duplicates). */
|
|
12
|
+
workspaceId?: string;
|
|
13
|
+
/** Preserved baseRef from the original workspace. For `attach` only. */
|
|
14
|
+
baseRef?: string;
|
|
15
|
+
/** Preserved baseSha from the original workspace. For `attach` only. */
|
|
16
|
+
baseSha?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
4
19
|
export interface WorkspaceResolutionInput {
|
|
5
20
|
cwd: string;
|
|
6
21
|
label?: string;
|
|
@@ -11,6 +26,8 @@ export interface WorkspaceResolutionInput {
|
|
|
11
26
|
workspaceSymlinks?: string[];
|
|
12
27
|
automationId?: string;
|
|
13
28
|
automationRunId?: string;
|
|
29
|
+
/** #635 — attach to or branch off an existing worktree instead of creating a fresh one. */
|
|
30
|
+
resumeWorkspace?: ResumeWorkspaceTarget;
|
|
14
31
|
}
|
|
15
32
|
|
|
16
33
|
export interface WorkspaceResolution {
|