@ricsam/r5dctl 0.0.131 → 0.0.132
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/README.md +3 -0
- package/dist/cjs/cli.cjs +30 -0
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/cli.mjs +29 -0
- package/dist/mjs/package.json +1 -1
- package/dist/types/cli.d.ts +10 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -136,6 +136,7 @@ r5dctl session status <session-id>
|
|
|
136
136
|
r5dctl session prompt --worker <label> --mode agent --model max --delivery steer <session-id> "Also check the migration"
|
|
137
137
|
r5dctl session prompt --worker <label> --mode agent --model max --delivery force <session-id> "Stop that and fix the build first"
|
|
138
138
|
r5dctl session stop <session-id>
|
|
139
|
+
r5dctl session set-worker <session-id> --worker <label>
|
|
139
140
|
r5dctl session process-log <run-id> --tail 200
|
|
140
141
|
r5dctl session process-log <run-id> --grep "error|failed"
|
|
141
142
|
|
|
@@ -169,6 +170,8 @@ Delivery is not acknowledgment. If a merge or shared-checkout change depends on
|
|
|
169
170
|
|
|
170
171
|
`session stop` also stops every sub-agent session the stopped session started, directly or through its own children, and `session status` prints `Child sessions: <active> active of <total>` for a session that launched sub-agents.
|
|
171
172
|
|
|
173
|
+
`session set-worker` rebinds a stopped session to another connected worker, exactly like the composer's worker selector: it publishes the current worker's workspace, synchronizes the target worker, persists the binding, and the session resumes there on its next prompt or resume. It is refused with `409` while the session's agent runs and with `403` for a worker credential. A running project agent moves its own session with the `switch_worker` tool instead, which needs no stop; workspace chats are rebound only while stopped. Shell runs, r5dctl shells, browser port forwards, and sub-agents started earlier stay on the worker that started them.
|
|
174
|
+
|
|
172
175
|
`session status` reports the run lifecycle and the launch-time `Source` and `Working tree` facts only. It deliberately prints no commit hash for the worktree, not even the launch baseline: a hash would be stale by the time a caller acts on it, because commits can land between the read and the action. Find the base and the branch's commits with git in the worker checkout instead, for example `git merge-base <your-branch> <branch>`, `git log --oneline <your-branch>..<branch>`, and `git status` in the branch folder, as the `Branch state` line reminds you. While a new worktree is still provisioning, a `Provisioning` line reports where its creation stands in the worker's operation queue and since when (`Provisioning: queued behind 3 worker operations since 2026-09-03T11:41:30Z`); a worker that predates operation receipts leaves that line out.
|
|
173
176
|
|
|
174
177
|
`session process-log` prints a shell run's stored stdout and stderr from the server, where r5d keeps every run's full output; the `logPath` in tool results names that server-side store, not a file on the worker. Without flags it prints the whole log, `--tail <n>` keeps the last n lines, and `--grep <pattern>` keeps the lines matching a JavaScript regular expression (combine both for the last n matches). Each stream is capped at 512 KB per call and printed under a `==> stdout <==` or `==> stderr <==` header; a one-line summary with byte totals, the selection, and any truncation goes to stderr so stdout stays clean for `grep`, `head`, and `tail`. Inside an r5d worker shell the temporary credential can only read runs on that shell's worker.
|
package/dist/cjs/cli.cjs
CHANGED
|
@@ -95,6 +95,7 @@ __export(cli_exports, {
|
|
|
95
95
|
renderSessionList: () => renderSessionList,
|
|
96
96
|
renderSessionRunStart: () => renderSessionRunStart,
|
|
97
97
|
renderSessionRunStatus: () => renderSessionRunStatus,
|
|
98
|
+
renderSessionSetWorker: () => renderSessionSetWorker,
|
|
98
99
|
renderWorkerCapacity: () => renderWorkerCapacity,
|
|
99
100
|
renderWorkspaceStatus: () => renderWorkspaceStatus,
|
|
100
101
|
renderWorkspaceSync: () => renderWorkspaceSync,
|
|
@@ -175,6 +176,7 @@ const SESSION_RUN_HELP_TEXT = [
|
|
|
175
176
|
" r5dctl session status <session-id>",
|
|
176
177
|
' r5dctl session prompt --worker <label> --mode <mode> --model <tier> [--delivery queue|steer|force] [--sender <name>] <session-id> "<prompt>"',
|
|
177
178
|
" r5dctl session stop <session-id>",
|
|
179
|
+
" r5dctl session set-worker <session-id> --worker <label>",
|
|
178
180
|
" r5dctl session process-log <run-id> [--tail <n>] [--grep <pattern>]",
|
|
179
181
|
" r5dctl [-s <session-id>] session claim <topic> [--ttl <duration>] [--note <text>]",
|
|
180
182
|
" r5dctl [-s <session-id>] session claim <topic> --status | --renew [--ttl <duration>] | --release",
|
|
@@ -197,6 +199,8 @@ const SESSION_RUN_HELP_TEXT = [
|
|
|
197
199
|
"Use -f/--follow/--watch to attach after a start; Ctrl-C detaches without stopping the session.",
|
|
198
200
|
"process-log prints a shell run's stored stdout/stderr from the server: the whole log, its last n lines,",
|
|
199
201
|
"or the lines matching a JavaScript regular expression. The log is not a file on the worker.",
|
|
202
|
+
"set-worker rebinds a stopped session to another connected worker: it publishes the current worker's workspace,",
|
|
203
|
+
"synchronizes the target, and the session resumes there. A running agent moves itself with its switch_worker tool.",
|
|
200
204
|
""
|
|
201
205
|
].join("\n");
|
|
202
206
|
const SHARED_HELP_ENTRIES = [
|
|
@@ -335,6 +339,11 @@ const SHARED_HELP_ENTRIES = [
|
|
|
335
339
|
usage: "session stop <session-id>",
|
|
336
340
|
description: "Stop an active session generation."
|
|
337
341
|
},
|
|
342
|
+
{
|
|
343
|
+
section: "sessions",
|
|
344
|
+
usage: "session set-worker <session-id> --worker <label>",
|
|
345
|
+
description: "Rebind a stopped session to another connected worker: publish the current worker's workspace, synchronize the target, and resume there. Refused while the agent runs; a running agent switches itself with switch_worker."
|
|
346
|
+
},
|
|
338
347
|
{
|
|
339
348
|
section: "sessions",
|
|
340
349
|
usage: "[-s <session-id>] session claim <topic> [--ttl <duration>] [--note <text>] [--status|--renew|--release]",
|
|
@@ -903,6 +912,12 @@ function parseSessionRunCommand(options, args, env = process.env) {
|
|
|
903
912
|
if (parsed.positionals.length > 1) throw new Error(`Unexpected session ${subcommand} argument: ${parsed.positionals[1]}`);
|
|
904
913
|
return { kind: subcommand, sessionId };
|
|
905
914
|
}
|
|
915
|
+
if (subcommand === "set-worker") {
|
|
916
|
+
const parsed = parseCommandOperands(commandArgs, /* @__PURE__ */ new Set(["--worker"]), /* @__PURE__ */ new Map(), "session set-worker");
|
|
917
|
+
const sessionId = requireValue(parsed.positionals[0], "Session id is required for `session set-worker`");
|
|
918
|
+
if (parsed.positionals.length > 1) throw new Error(`Unexpected session set-worker argument: ${parsed.positionals[1]}`);
|
|
919
|
+
return { kind: "set-worker", sessionId, worker: requireWorker(parsed.values) };
|
|
920
|
+
}
|
|
906
921
|
if (subcommand === "prompt") {
|
|
907
922
|
const parsed = parseCommandOperands(
|
|
908
923
|
commandArgs,
|
|
@@ -2279,9 +2294,23 @@ async function dispatchSessionRunCommand(client, command) {
|
|
|
2279
2294
|
});
|
|
2280
2295
|
return { data: data2, human: renderSessionRunStatus(data2) };
|
|
2281
2296
|
}
|
|
2297
|
+
if (command.kind === "set-worker") {
|
|
2298
|
+
const data2 = await client.sessions.setWorker(command.sessionId, { worker: command.worker });
|
|
2299
|
+
return { data: data2, human: renderSessionSetWorker(data2) };
|
|
2300
|
+
}
|
|
2282
2301
|
const data = await client.sessions.stop(command.sessionId);
|
|
2283
2302
|
return { data, human: renderSessionRunStatus(data) };
|
|
2284
2303
|
}
|
|
2304
|
+
function renderSessionSetWorker(response) {
|
|
2305
|
+
const previous = typeof response.previousWorker === "string" && response.previousWorker.length > 0 ? response.previousWorker : null;
|
|
2306
|
+
const lines = [
|
|
2307
|
+
`Session: ${responseString(response, "sessionId") ?? "(unknown)"}`,
|
|
2308
|
+
`Worker: ${responseString(response, "worker") ?? "(unassigned)"}${previous ? ` (was ${previous})` : ""}`,
|
|
2309
|
+
"The session resumes on this worker; shell runs and sub-agents started earlier stay where they ran."
|
|
2310
|
+
];
|
|
2311
|
+
return `${lines.join("\n")}
|
|
2312
|
+
`;
|
|
2313
|
+
}
|
|
2285
2314
|
async function waitForSessionProvisioning(client, initial, options = {}) {
|
|
2286
2315
|
const sessionId = requireValue(responseString(initial, "sessionId"), "Session start did not return a session id");
|
|
2287
2316
|
const wait = options.wait ?? import_promises.setTimeout;
|
|
@@ -3880,6 +3909,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
3880
3909
|
renderSessionList,
|
|
3881
3910
|
renderSessionRunStart,
|
|
3882
3911
|
renderSessionRunStatus,
|
|
3912
|
+
renderSessionSetWorker,
|
|
3883
3913
|
renderWorkerCapacity,
|
|
3884
3914
|
renderWorkspaceStatus,
|
|
3885
3915
|
renderWorkspaceSync,
|
package/dist/cjs/package.json
CHANGED
package/dist/mjs/cli.mjs
CHANGED
|
@@ -70,6 +70,7 @@ const SESSION_RUN_HELP_TEXT = [
|
|
|
70
70
|
" r5dctl session status <session-id>",
|
|
71
71
|
' r5dctl session prompt --worker <label> --mode <mode> --model <tier> [--delivery queue|steer|force] [--sender <name>] <session-id> "<prompt>"',
|
|
72
72
|
" r5dctl session stop <session-id>",
|
|
73
|
+
" r5dctl session set-worker <session-id> --worker <label>",
|
|
73
74
|
" r5dctl session process-log <run-id> [--tail <n>] [--grep <pattern>]",
|
|
74
75
|
" r5dctl [-s <session-id>] session claim <topic> [--ttl <duration>] [--note <text>]",
|
|
75
76
|
" r5dctl [-s <session-id>] session claim <topic> --status | --renew [--ttl <duration>] | --release",
|
|
@@ -92,6 +93,8 @@ const SESSION_RUN_HELP_TEXT = [
|
|
|
92
93
|
"Use -f/--follow/--watch to attach after a start; Ctrl-C detaches without stopping the session.",
|
|
93
94
|
"process-log prints a shell run's stored stdout/stderr from the server: the whole log, its last n lines,",
|
|
94
95
|
"or the lines matching a JavaScript regular expression. The log is not a file on the worker.",
|
|
96
|
+
"set-worker rebinds a stopped session to another connected worker: it publishes the current worker's workspace,",
|
|
97
|
+
"synchronizes the target, and the session resumes there. A running agent moves itself with its switch_worker tool.",
|
|
95
98
|
""
|
|
96
99
|
].join("\n");
|
|
97
100
|
const SHARED_HELP_ENTRIES = [
|
|
@@ -230,6 +233,11 @@ const SHARED_HELP_ENTRIES = [
|
|
|
230
233
|
usage: "session stop <session-id>",
|
|
231
234
|
description: "Stop an active session generation."
|
|
232
235
|
},
|
|
236
|
+
{
|
|
237
|
+
section: "sessions",
|
|
238
|
+
usage: "session set-worker <session-id> --worker <label>",
|
|
239
|
+
description: "Rebind a stopped session to another connected worker: publish the current worker's workspace, synchronize the target, and resume there. Refused while the agent runs; a running agent switches itself with switch_worker."
|
|
240
|
+
},
|
|
233
241
|
{
|
|
234
242
|
section: "sessions",
|
|
235
243
|
usage: "[-s <session-id>] session claim <topic> [--ttl <duration>] [--note <text>] [--status|--renew|--release]",
|
|
@@ -798,6 +806,12 @@ function parseSessionRunCommand(options, args, env = process.env) {
|
|
|
798
806
|
if (parsed.positionals.length > 1) throw new Error(`Unexpected session ${subcommand} argument: ${parsed.positionals[1]}`);
|
|
799
807
|
return { kind: subcommand, sessionId };
|
|
800
808
|
}
|
|
809
|
+
if (subcommand === "set-worker") {
|
|
810
|
+
const parsed = parseCommandOperands(commandArgs, /* @__PURE__ */ new Set(["--worker"]), /* @__PURE__ */ new Map(), "session set-worker");
|
|
811
|
+
const sessionId = requireValue(parsed.positionals[0], "Session id is required for `session set-worker`");
|
|
812
|
+
if (parsed.positionals.length > 1) throw new Error(`Unexpected session set-worker argument: ${parsed.positionals[1]}`);
|
|
813
|
+
return { kind: "set-worker", sessionId, worker: requireWorker(parsed.values) };
|
|
814
|
+
}
|
|
801
815
|
if (subcommand === "prompt") {
|
|
802
816
|
const parsed = parseCommandOperands(
|
|
803
817
|
commandArgs,
|
|
@@ -2174,9 +2188,23 @@ async function dispatchSessionRunCommand(client, command) {
|
|
|
2174
2188
|
});
|
|
2175
2189
|
return { data: data2, human: renderSessionRunStatus(data2) };
|
|
2176
2190
|
}
|
|
2191
|
+
if (command.kind === "set-worker") {
|
|
2192
|
+
const data2 = await client.sessions.setWorker(command.sessionId, { worker: command.worker });
|
|
2193
|
+
return { data: data2, human: renderSessionSetWorker(data2) };
|
|
2194
|
+
}
|
|
2177
2195
|
const data = await client.sessions.stop(command.sessionId);
|
|
2178
2196
|
return { data, human: renderSessionRunStatus(data) };
|
|
2179
2197
|
}
|
|
2198
|
+
function renderSessionSetWorker(response) {
|
|
2199
|
+
const previous = typeof response.previousWorker === "string" && response.previousWorker.length > 0 ? response.previousWorker : null;
|
|
2200
|
+
const lines = [
|
|
2201
|
+
`Session: ${responseString(response, "sessionId") ?? "(unknown)"}`,
|
|
2202
|
+
`Worker: ${responseString(response, "worker") ?? "(unassigned)"}${previous ? ` (was ${previous})` : ""}`,
|
|
2203
|
+
"The session resumes on this worker; shell runs and sub-agents started earlier stay where they ran."
|
|
2204
|
+
];
|
|
2205
|
+
return `${lines.join("\n")}
|
|
2206
|
+
`;
|
|
2207
|
+
}
|
|
2180
2208
|
async function waitForSessionProvisioning(client, initial, options = {}) {
|
|
2181
2209
|
const sessionId = requireValue(responseString(initial, "sessionId"), "Session start did not return a session id");
|
|
2182
2210
|
const wait = options.wait ?? sleep;
|
|
@@ -3774,6 +3802,7 @@ export {
|
|
|
3774
3802
|
renderSessionList,
|
|
3775
3803
|
renderSessionRunStart,
|
|
3776
3804
|
renderSessionRunStatus,
|
|
3805
|
+
renderSessionSetWorker,
|
|
3777
3806
|
renderWorkerCapacity,
|
|
3778
3807
|
renderWorkspaceStatus,
|
|
3779
3808
|
renderWorkspaceSync,
|
package/dist/mjs/package.json
CHANGED
package/dist/types/cli.d.ts
CHANGED
|
@@ -84,6 +84,10 @@ export type R5dctlSessionRunCommand = R5dctlSessionStartCommand | {
|
|
|
84
84
|
} | {
|
|
85
85
|
kind: "stop";
|
|
86
86
|
sessionId: string;
|
|
87
|
+
} | {
|
|
88
|
+
kind: "set-worker";
|
|
89
|
+
sessionId: string;
|
|
90
|
+
worker: string;
|
|
87
91
|
};
|
|
88
92
|
export type R5dctlBranchCreateArgs = {
|
|
89
93
|
source: R5dctlWorktreeSource;
|
|
@@ -312,6 +316,8 @@ export type R5dctlCommandResponse = {
|
|
|
312
316
|
baselineCommit?: string | null;
|
|
313
317
|
workspaceHead?: string | null;
|
|
314
318
|
worker?: string;
|
|
319
|
+
/** The binding a `session set-worker` replaced; null when the session had none. */
|
|
320
|
+
previousWorker?: string | null;
|
|
315
321
|
status?: string;
|
|
316
322
|
runStatus?: unknown;
|
|
317
323
|
/** Worker queue state while a new worktree provisions; older servers and workers omit it. */
|
|
@@ -347,6 +353,9 @@ export type R5dctlSessionRunClient = {
|
|
|
347
353
|
delivery?: R5dctlPromptDelivery;
|
|
348
354
|
}) => Promise<R5dctlCommandResponse>;
|
|
349
355
|
stop: (sessionId: string) => Promise<R5dctlCommandResponse>;
|
|
356
|
+
setWorker: (sessionId: string, input: {
|
|
357
|
+
worker: string;
|
|
358
|
+
}) => Promise<R5dctlCommandResponse>;
|
|
350
359
|
};
|
|
351
360
|
};
|
|
352
361
|
export declare function renderSessionRunStart(session: R5dctlCommandResponse): string;
|
|
@@ -356,6 +365,7 @@ export type R5dctlCommandDispatchResult = {
|
|
|
356
365
|
human: string;
|
|
357
366
|
};
|
|
358
367
|
export declare function dispatchSessionRunCommand(client: R5dctlSessionRunClient, command: R5dctlSessionRunCommand): Promise<R5dctlCommandDispatchResult>;
|
|
368
|
+
export declare function renderSessionSetWorker(response: R5dctlCommandResponse): string;
|
|
359
369
|
export declare function waitForSessionProvisioning(client: Pick<R5dctlSessionRunClient, "sessions">, initial: R5dctlCommandResponse, options?: {
|
|
360
370
|
intervalMs?: number;
|
|
361
371
|
wait?: (milliseconds: number) => Promise<unknown>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ricsam/r5dctl",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.132",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/cjs/cli.cjs",
|
|
6
6
|
"module": "./dist/mjs/cli.mjs",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"r5dctl": "dist/cjs/main.cjs"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@ricsam/r5d-api": "^0.0.
|
|
29
|
+
"@ricsam/r5d-api": "^0.0.132",
|
|
30
30
|
"dotenv": "^17",
|
|
31
31
|
"qrcode": "^1.5.4",
|
|
32
32
|
"ws": "^8.18.3"
|