@viraatdas/rudder 3.5.7 → 3.6.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/dist/cloud-pull.d.ts +46 -0
- package/dist/cloud-pull.js +228 -0
- package/dist/cloud-pull.js.map +1 -0
- package/dist/cloud.js +22 -0
- package/dist/cloud.js.map +1 -1
- package/dist/main.js +12 -0
- package/dist/main.js.map +1 -1
- package/dist/native/darwin-arm64/rudder-native +0 -0
- package/dist/native/darwin-x64/rudder-native +0 -0
- package/dist/native/linux-x64/rudder-native +0 -0
- package/package.json +1 -1
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { JsonValue } from "./types.js";
|
|
2
|
+
export type PullExport = {
|
|
3
|
+
head: string;
|
|
4
|
+
base: string | null;
|
|
5
|
+
title: string;
|
|
6
|
+
task: string;
|
|
7
|
+
backend: string;
|
|
8
|
+
model: string | null;
|
|
9
|
+
sessionId: string | null;
|
|
10
|
+
};
|
|
11
|
+
export type PullImport = {
|
|
12
|
+
path: string;
|
|
13
|
+
runId: string;
|
|
14
|
+
title: string;
|
|
15
|
+
resumable: boolean;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Home side: bundle run `runId` of the clone at `repoRoot` into `outFile` (a
|
|
19
|
+
* .tgz move bundle with one agent). Any status pulls, the main row included:
|
|
20
|
+
* its `@` is the clone's own working copy.
|
|
21
|
+
*/
|
|
22
|
+
export declare function exportRunForPull(repoRoot: string, runId: string, outFile: string): Promise<PullExport>;
|
|
23
|
+
/**
|
|
24
|
+
* Laptop side: adopt a bundle made by exportRunForPull into the checkout at
|
|
25
|
+
* `repoRoot`. A run with the same id already here is replaced only when it is
|
|
26
|
+
* the row that moved to the home machine, or an earlier pull nothing runs.
|
|
27
|
+
*/
|
|
28
|
+
export declare function importPulledRun(repoRoot: string, archive: string, homeDir?: string): Promise<PullImport>;
|
|
29
|
+
/** The slice of the cloud client a pull needs (src/cloud.ts builds it). */
|
|
30
|
+
export type PullClient = {
|
|
31
|
+
request<T>(pathOrUrl: string, init: {
|
|
32
|
+
method: string;
|
|
33
|
+
body?: JsonValue;
|
|
34
|
+
}): Promise<T>;
|
|
35
|
+
download(pathname: string): Promise<Buffer>;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* `rudder cloud pull <runId> [--json]`, in a local clone of a repo open on the
|
|
39
|
+
* home machine.
|
|
40
|
+
*/
|
|
41
|
+
export declare function pullFromHome(args: string[], options: {
|
|
42
|
+
json?: boolean;
|
|
43
|
+
}, deps: {
|
|
44
|
+
client: PullClient;
|
|
45
|
+
githubSlug: (root: string) => Promise<string | null>;
|
|
46
|
+
}): Promise<PullImport>;
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// Pulling one agent from the home machine back to this computer: the reverse
|
|
2
|
+
// of `rudder cloud move` (src/move-home.ts), and built from the same parts.
|
|
3
|
+
//
|
|
4
|
+
// home exportRunForPull (`rudder __pull-export`, run by the supervisor):
|
|
5
|
+
// a move bundle holding the run's jj `@` commit (the working copy is
|
|
6
|
+
// snapshotted first, so uncommitted edits come along; what origin's
|
|
7
|
+
// default branch has stays behind), its run.json and its Claude
|
|
8
|
+
// transcript or Codex rollout, tarred. The supervisor PUTs it to the
|
|
9
|
+
// control plane as a one-shot sync blob.
|
|
10
|
+
// laptop pullFromHome (`rudder cloud pull <run>`): ask for it, download the
|
|
11
|
+
// blob, and adopt it like the home adopts a move: a jj workspace under
|
|
12
|
+
// .rudder-workspaces whose `@` IS the pulled commit, the conversation
|
|
13
|
+
// placed where `--resume` looks for it at the new cwd, and a `paused`
|
|
14
|
+
// run.json the dashboard lists and resumes on Enter.
|
|
15
|
+
//
|
|
16
|
+
// It is a copy, not a move: the agent keeps running on the home machine.
|
|
17
|
+
import fsp from "node:fs/promises";
|
|
18
|
+
import os from "node:os";
|
|
19
|
+
import path from "node:path";
|
|
20
|
+
import { findRepoRoot } from "./git.js";
|
|
21
|
+
import { currentJjCommitId } from "./jj.js";
|
|
22
|
+
import { adoptMovedAgents, buildMoveBundle, findCodexMainThreadForCwd, } from "./move-home.js";
|
|
23
|
+
import { adoptLegacyWorkspaceKey, AGENT_WORKSPACES_DIR, ensureProjectRuntimeIgnored, workspacePath } from "./state.js";
|
|
24
|
+
import { nowIso, pathExists, readJson, runCommand, shortHash, writeJson } from "./util.js";
|
|
25
|
+
const RUN_ID_RE = /^[A-Za-z0-9._-]{1,120}$/;
|
|
26
|
+
function validRunId(runId) {
|
|
27
|
+
return RUN_ID_RE.test(runId) && !runId.startsWith(".");
|
|
28
|
+
}
|
|
29
|
+
async function originDefaultCommit(repoRoot) {
|
|
30
|
+
const head = await runCommand("git", ["symbolic-ref", "-q", "refs/remotes/origin/HEAD"], { cwd: repoRoot, allowFailure: true });
|
|
31
|
+
for (const ref of [head.stdout.trim(), "refs/remotes/origin/main", "refs/remotes/origin/master"].filter(Boolean)) {
|
|
32
|
+
const sha = await runCommand("git", ["rev-parse", "--verify", "-q", ref], { cwd: repoRoot, allowFailure: true });
|
|
33
|
+
if (sha.code === 0) {
|
|
34
|
+
return sha.stdout.trim();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Home side: bundle run `runId` of the clone at `repoRoot` into `outFile` (a
|
|
41
|
+
* .tgz move bundle with one agent). Any status pulls, the main row included:
|
|
42
|
+
* its `@` is the clone's own working copy.
|
|
43
|
+
*/
|
|
44
|
+
export async function exportRunForPull(repoRoot, runId, outFile) {
|
|
45
|
+
if (!validRunId(runId)) {
|
|
46
|
+
throw new Error("bad run id");
|
|
47
|
+
}
|
|
48
|
+
const record = await readJson(path.join(repoRoot, ".rudder", "runs", runId, "run.json"));
|
|
49
|
+
if (!record || record.id !== runId) {
|
|
50
|
+
throw new Error(`no agent ${runId} on the home machine`);
|
|
51
|
+
}
|
|
52
|
+
adoptLegacyWorkspaceKey(record);
|
|
53
|
+
const workspace = (record.workspace ?? {});
|
|
54
|
+
const ownWorkspace = workspace.enabled === true && typeof workspace.path === "string" && workspace.path
|
|
55
|
+
&& (await pathExists(workspace.path)) ? workspace.path : null;
|
|
56
|
+
const workspaceDir = ownWorkspace ?? repoRoot;
|
|
57
|
+
const backend = String(record.backend ?? "claude");
|
|
58
|
+
const session = (record.session ?? {});
|
|
59
|
+
let sessionId = typeof session.nativeSessionId === "string" && session.nativeSessionId.trim() ? session.nativeSessionId.trim() : undefined;
|
|
60
|
+
if (!sessionId && backend === "codex") {
|
|
61
|
+
sessionId = (await findCodexMainThreadForCwd(workspaceDir)) ?? undefined;
|
|
62
|
+
}
|
|
63
|
+
const candidate = {
|
|
64
|
+
runId,
|
|
65
|
+
task: String(record.task ?? ""),
|
|
66
|
+
taskSummary: typeof record.taskSummary === "string" ? record.taskSummary : undefined,
|
|
67
|
+
backend,
|
|
68
|
+
status: String(record.status ?? ""),
|
|
69
|
+
workspacePath: workspaceDir,
|
|
70
|
+
workspaceName: ownWorkspace && typeof workspace.workspaceName === "string" ? workspace.workspaceName : undefined,
|
|
71
|
+
sessionId,
|
|
72
|
+
};
|
|
73
|
+
const stage = await fsp.mkdtemp(path.join(os.tmpdir(), "rudder-pull-stage-"));
|
|
74
|
+
try {
|
|
75
|
+
const manifest = await buildMoveBundle(repoRoot, [candidate], stage);
|
|
76
|
+
await runCommand("tar", ["-czf", outFile, "-C", stage, "."], { cwd: stage });
|
|
77
|
+
const agent = manifest.agents[0];
|
|
78
|
+
return {
|
|
79
|
+
head: agent.commit,
|
|
80
|
+
base: await originDefaultCommit(repoRoot),
|
|
81
|
+
title: (candidate.taskSummary || candidate.task || runId).slice(0, 200),
|
|
82
|
+
task: candidate.task,
|
|
83
|
+
backend,
|
|
84
|
+
model: typeof record.model === "string" ? record.model : null,
|
|
85
|
+
sessionId: agent.sessionId || null,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
await fsp.rm(stage, { recursive: true, force: true });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Laptop side: adopt a bundle made by exportRunForPull into the checkout at
|
|
94
|
+
* `repoRoot`. A run with the same id already here is replaced only when it is
|
|
95
|
+
* the row that moved to the home machine, or an earlier pull nothing runs.
|
|
96
|
+
*/
|
|
97
|
+
export async function importPulledRun(repoRoot, archive, homeDir = os.homedir()) {
|
|
98
|
+
const dir = await fsp.mkdtemp(path.join(os.tmpdir(), "rudder-pull-in-"));
|
|
99
|
+
try {
|
|
100
|
+
await runCommand("tar", ["-xzf", archive, "-C", dir]);
|
|
101
|
+
const manifest = await readJson(path.join(dir, "manifest.json"));
|
|
102
|
+
const agent = manifest?.agents?.[0];
|
|
103
|
+
if (!manifest || manifest.kind !== "rudder-move" || manifest.agents.length !== 1 || !agent || !validRunId(agent.runId)) {
|
|
104
|
+
throw new Error("not a Rudder pull bundle");
|
|
105
|
+
}
|
|
106
|
+
const runId = agent.runId;
|
|
107
|
+
const recordPath = path.join(repoRoot, ".rudder", "runs", runId, "run.json");
|
|
108
|
+
const existing = await readJson(recordPath);
|
|
109
|
+
if (existing) {
|
|
110
|
+
const migration = (existing.migration ?? {});
|
|
111
|
+
const status = String(existing.status ?? "");
|
|
112
|
+
const replaceable = status === "migrated" || (migration.pulledFrom === "home" && status !== "running");
|
|
113
|
+
if (!replaceable && migration.fromCommit !== agent.commit) {
|
|
114
|
+
throw new Error(`an agent ${runId} already exists in this checkout (${status || "unknown status"}); delete it first`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Same place under .rudder-workspaces as on the home machine, unless that
|
|
118
|
+
// directory is taken here (the workspace this agent left when it moved,
|
|
119
|
+
// or an earlier pull): then a sibling, so nothing local is overwritten.
|
|
120
|
+
const parts = (agent.relativeWorkspacePath ?? "").split("/");
|
|
121
|
+
let relative = parts.length >= 2 && parts[0] === AGENT_WORKSPACES_DIR
|
|
122
|
+
? agent.relativeWorkspacePath
|
|
123
|
+
: path.relative(repoRoot, workspacePath(repoRoot, runId, agent.taskSummary || agent.task)).split(path.sep).join("/");
|
|
124
|
+
const sameCommit = existing && (existing.migration ?? {}).fromCommit === agent.commit;
|
|
125
|
+
if (!sameCommit && (await pathExists(path.join(repoRoot, relative)))) {
|
|
126
|
+
relative = `${relative}-${shortHash(`${runId}:${agent.commit}`).slice(0, 4)}`;
|
|
127
|
+
if (await pathExists(path.join(repoRoot, relative))) {
|
|
128
|
+
throw new Error(`${relative} already exists; delete it to pull this agent again`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
agent.relativeWorkspacePath = relative;
|
|
132
|
+
// adoptMovedAgents reads the manifest from disk.
|
|
133
|
+
await writeJson(path.join(dir, "manifest.json"), manifest);
|
|
134
|
+
// A record that moved there and back is adopted fresh, not "already adopted".
|
|
135
|
+
if (existing && !sameCommit) {
|
|
136
|
+
await fsp.rm(recordPath, { force: true });
|
|
137
|
+
}
|
|
138
|
+
await ensureProjectRuntimeIgnored(repoRoot);
|
|
139
|
+
const result = await adoptMovedAgents(repoRoot, dir, homeDir);
|
|
140
|
+
const adopted = result.adopted[0];
|
|
141
|
+
if (!adopted) {
|
|
142
|
+
if (existing && !sameCommit) {
|
|
143
|
+
await writeJson(recordPath, existing);
|
|
144
|
+
}
|
|
145
|
+
throw new Error(result.failed[0]?.error ?? "could not stage the agent here");
|
|
146
|
+
}
|
|
147
|
+
const record = (await readJson(recordPath)) ?? {};
|
|
148
|
+
const migration = (record.migration ?? {});
|
|
149
|
+
record.migration = { ...migration, origin: "home", pulledFrom: "home", at: nowIso(), pendingResume: false, pendingFresh: false };
|
|
150
|
+
delete record.movedTo;
|
|
151
|
+
// A main row on the home machine is an isolated worker here, and it belongs
|
|
152
|
+
// to no plan in this checkout.
|
|
153
|
+
if (record.mode === "main" || record.mode === "one-off") {
|
|
154
|
+
record.mode = "execute";
|
|
155
|
+
}
|
|
156
|
+
for (const key of ["nodeId", "planId", "gam", "resolverFor", "resolverRunId"]) {
|
|
157
|
+
delete record[key];
|
|
158
|
+
}
|
|
159
|
+
record.updatedAt = String(Date.now());
|
|
160
|
+
await writeJson(recordPath, record);
|
|
161
|
+
return {
|
|
162
|
+
path: adopted.workspacePath,
|
|
163
|
+
runId,
|
|
164
|
+
title: String(agent.taskSummary || agent.task || runId).slice(0, 200),
|
|
165
|
+
resumable: adopted.resumable,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
await fsp.rm(dir, { recursive: true, force: true });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function retryable(message) {
|
|
173
|
+
return /\b503\b|waking|asleep|not connected|starting|did not answer|fetch failed/i.test(message);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* `rudder cloud pull <runId> [--json]`, in a local clone of a repo open on the
|
|
177
|
+
* home machine.
|
|
178
|
+
*/
|
|
179
|
+
export async function pullFromHome(args, options, deps) {
|
|
180
|
+
const runId = args.find((arg) => !arg.startsWith("-")) ?? "";
|
|
181
|
+
if (!validRunId(runId)) {
|
|
182
|
+
throw new Error("Usage: rudder cloud pull <runId> [--json] (the run id is in the app's agent menu and `rudder cloud home`)");
|
|
183
|
+
}
|
|
184
|
+
const root = findRepoRoot();
|
|
185
|
+
const slug = await deps.githubSlug(root);
|
|
186
|
+
if (!slug) {
|
|
187
|
+
throw new Error("Run `rudder cloud pull` inside a local clone of the GitHub repo the agent works in.");
|
|
188
|
+
}
|
|
189
|
+
const home = await deps.client.request("/api/rudder/home", { method: "GET" });
|
|
190
|
+
if (!(home.projects ?? []).some((project) => project.repo?.toLowerCase() === slug.toLowerCase())) {
|
|
191
|
+
throw new Error(`${slug} is not open on your cloud machine, so it has no agent to pull here.`);
|
|
192
|
+
}
|
|
193
|
+
if (!options.json) {
|
|
194
|
+
process.stderr.write("Asking the cloud machine for the agent's work (waking it if it is asleep)...\n");
|
|
195
|
+
}
|
|
196
|
+
const ask = () => deps.client.request("/api/rudder/home/pull", { method: "POST", body: { repo: slug, runId } });
|
|
197
|
+
let response;
|
|
198
|
+
try {
|
|
199
|
+
response = await ask();
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
203
|
+
if (!retryable(message)) {
|
|
204
|
+
throw error;
|
|
205
|
+
}
|
|
206
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
207
|
+
response = await ask();
|
|
208
|
+
}
|
|
209
|
+
if (!response.download || !/^\/api\/rudder\/home\/syncs\/[^/]+$/.test(response.download)) {
|
|
210
|
+
throw new Error("the cloud machine did not send the agent's work");
|
|
211
|
+
}
|
|
212
|
+
const scratch = await fsp.mkdtemp(path.join(os.tmpdir(), "rudder-pull-"));
|
|
213
|
+
try {
|
|
214
|
+
const archive = path.join(scratch, "pull.tgz");
|
|
215
|
+
await fsp.writeFile(archive, await deps.client.download(response.download));
|
|
216
|
+
const imported = await importPulledRun(root, archive);
|
|
217
|
+
// Not every jj state survives a bundle; read back what the workspace holds.
|
|
218
|
+
const here = await currentJjCommitId(imported.path).catch(() => "");
|
|
219
|
+
if (here && response.head && here !== response.head) {
|
|
220
|
+
process.stderr.write(`note: the workspace is at ${here.slice(0, 12)}, the cloud sent ${response.head.slice(0, 12)}\n`);
|
|
221
|
+
}
|
|
222
|
+
return { ...imported, title: response.title || imported.title };
|
|
223
|
+
}
|
|
224
|
+
finally {
|
|
225
|
+
await fsp.rm(scratch, { recursive: true, force: true });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=cloud-pull.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloud-pull.js","sourceRoot":"","sources":["../src/cloud-pull.ts"],"names":[],"mappings":"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"}
|
package/dist/cloud.js
CHANGED
|
@@ -13,6 +13,7 @@ import { cloudAuthPath } from "./state.js";
|
|
|
13
13
|
import { runLaptopOnboarding } from "./onboarding.js";
|
|
14
14
|
import { renderQrForTerminal } from "./qr.js";
|
|
15
15
|
import { describeSync, exportWork, importWork, syncCheckout } from "./checkout-sync.js";
|
|
16
|
+
import { pullFromHome } from "./cloud-pull.js";
|
|
16
17
|
import { ensureDir, commandExists, expandHome, isTty, newRunId, nowIso, pathExists, promptConfirm, promptText, promptSelect, promptSecret, readJson, runCommand, shortenHome, shellQuote, writeJson, } from "./util.js";
|
|
17
18
|
const DEFAULT_LOGIN_INTERVAL_MS = 2000;
|
|
18
19
|
const DEFAULT_LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
|
|
@@ -195,6 +196,9 @@ export async function runCloudCommand(command, args, options = {}) {
|
|
|
195
196
|
case "move":
|
|
196
197
|
await moveCommand(rest, options);
|
|
197
198
|
return;
|
|
199
|
+
case "pull":
|
|
200
|
+
await pullCommand(rest, options);
|
|
201
|
+
return;
|
|
198
202
|
case "bootstrap":
|
|
199
203
|
await bootstrap(rest, options);
|
|
200
204
|
return;
|
|
@@ -3656,6 +3660,10 @@ Usage:
|
|
|
3656
3660
|
move this repo's unfinished agents (or just the named ones) to the
|
|
3657
3661
|
home machine: their jj changes and conversations go along, nothing is
|
|
3658
3662
|
pushed to GitHub, and they keep working with this laptop closed
|
|
3663
|
+
rudder cloud pull <runId> [--json]
|
|
3664
|
+
copy one of the home machine's agents to this computer, in a local
|
|
3665
|
+
clone of its repo: a jj workspace at its change (uncommitted edits
|
|
3666
|
+
included) and its conversation, listed paused in the dashboard
|
|
3659
3667
|
rudder cloud app
|
|
3660
3668
|
a one-time code that signs the phone app in to this account
|
|
3661
3669
|
rudder cloud doctor
|
|
@@ -3967,6 +3975,20 @@ async function ensureVaultGithubToken(client, slug, interactive = true) {
|
|
|
3967
3975
|
}
|
|
3968
3976
|
const HOME_MOVE_POLL_MS = 1500;
|
|
3969
3977
|
const HOME_MOVE_DEADLINE_MS = 15 * 60 * 1000;
|
|
3978
|
+
// `rudder cloud pull <runId>`: the reverse of move, for one agent (src/cloud-pull.ts).
|
|
3979
|
+
async function pullCommand(args, options) {
|
|
3980
|
+
const client = await cloudClient({ requireToken: true });
|
|
3981
|
+
const json = options.json || args.includes("--json");
|
|
3982
|
+
const pulled = await pullFromHome(args, { json }, { client, githubSlug: githubSlugFromOrigin });
|
|
3983
|
+
if (json) {
|
|
3984
|
+
printJson({ path: pulled.path, runId: pulled.runId, title: pulled.title });
|
|
3985
|
+
return;
|
|
3986
|
+
}
|
|
3987
|
+
console.log(`Pulled "${pulled.title}" to ${pulled.path}`);
|
|
3988
|
+
console.log(pulled.resumable
|
|
3989
|
+
? "It is paused in the dashboard here; Enter on its row continues the conversation."
|
|
3990
|
+
: "It is paused in the dashboard here; its conversation did not come along, so Enter starts it fresh on its work.");
|
|
3991
|
+
}
|
|
3970
3992
|
async function moveCommand(args, options) {
|
|
3971
3993
|
const yes = options.yes || args.includes("--yes") || args.includes("-y");
|
|
3972
3994
|
const runIds = args.filter((arg) => !arg.startsWith("-"));
|