@ricsam/r5dctl 0.0.100 → 0.0.103
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 +8 -1
- package/dist/cjs/cli.cjs +131 -15
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/cli.mjs +129 -15
- package/dist/mjs/package.json +1 -1
- package/dist/types/cli.d.ts +23 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -88,9 +88,12 @@ r5dctl -s <session-id> answer-env-request --worker <label> --mode agent --model
|
|
|
88
88
|
|
|
89
89
|
r5dctl -p <project> session start --worker <label> --worktree main --model max "Explore the failure"
|
|
90
90
|
r5dctl -p <project> session start --worker <label> --new-worktree fix/tests --source worktree:main --model max -f "Fix the failing tests"
|
|
91
|
+
r5dctl -p <project> session start --worker <label> --new-worktree fix/tests --source worktree:main --working-tree clean --model max "Fix the failing tests from main's committed state"
|
|
91
92
|
r5dctl session status <session-id>
|
|
92
93
|
r5dctl session prompt --worker <label> --mode agent --model max <session-id> "Also check the migration"
|
|
93
94
|
r5dctl session stop <session-id>
|
|
95
|
+
r5dctl session process-log <run-id> --tail 200
|
|
96
|
+
r5dctl session process-log <run-id> --grep "error|failed"
|
|
94
97
|
|
|
95
98
|
r5dctl -p <project> -b <branch> shell
|
|
96
99
|
r5dctl -p <project> -b <branch> shell -c "bun test"
|
|
@@ -116,7 +119,11 @@ repository. Trust applies to that workflow path on every Git ref and grants
|
|
|
116
119
|
cluster-admin, so protect workflow changes and do not invoke it for untrusted
|
|
117
120
|
pull requests.
|
|
118
121
|
|
|
119
|
-
`session start` creates an ordinary agent-mode chat on an explicitly selected existing worktree, or creates a named linked worktree from an explicit `worktree:<branch>` source. It requires project, worker, model, and prompt and never infers them from the current shell. Start returns a durable `provisioning` handle immediately; workspace synchronization, linked-worktree creation, and prompt enqueue continue in the background and are visible through `session status`. Idempotent request retries return the same handle. Prompts return after durable enqueue. Task specialization belongs in the prompt; there are no predefined debug, explore, research, or test agents. `session stop` returns as soon as the agent run is stopped; the stopped worktree's workspace Git synchronization finishes asynchronously behind the response.
|
|
122
|
+
`session start` creates an ordinary agent-mode chat on an explicitly selected existing worktree, or creates a named linked worktree from an explicit `worktree:<branch>` source. A new worktree is cut from the source branch's current commit; `--working-tree carry` (the default, `git switch -c` semantics) also copies the source checkout's uncommitted changes into it, while `--working-tree clean` checks out that commit only. The new session's first message states which mode applies, and the start output prints `Source` and `Working tree` lines. A clean request fails with a clear error when the selected worker predates the option, because such a worker would silently carry instead. It requires project, worker, model, and prompt and never infers them from the current shell. Start returns a durable `provisioning` handle immediately; workspace synchronization, linked-worktree creation, and prompt enqueue continue in the background and are visible through `session status`. Idempotent request retries return the same handle. Prompts return after durable enqueue. Task specialization belongs in the prompt; there are no predefined debug, explore, research, or test agents. `session stop` returns as soon as the agent run is stopped; the stopped worktree's workspace Git synchronization finishes asynchronously behind the response.
|
|
123
|
+
|
|
124
|
+
`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.
|
|
125
|
+
|
|
126
|
+
`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.
|
|
120
127
|
|
|
121
128
|
Add `-f`/`--follow`/`--watch` to `session start` to poll the provisioning handle and attach after enqueue, or to `conversation` to print the current transcript and follow new output. Assistant text is written to stdout and lifecycle/tool progress to stderr; `--tools` includes tool calls and results. With global `--json`, follow mode emits one JSON event per line. Ctrl-C only detaches and never stops the session. The CLI reconnects transiently interrupted event streams and resynchronizes committed conversation revisions without repeating assistant text.
|
|
122
129
|
|
package/dist/cjs/cli.cjs
CHANGED
|
@@ -57,6 +57,7 @@ __export(cli_exports, {
|
|
|
57
57
|
parsePromptArgs: () => parsePromptArgs,
|
|
58
58
|
parsePsHistoryArgs: () => parsePsHistoryArgs,
|
|
59
59
|
parsePsListArgs: () => parsePsListArgs,
|
|
60
|
+
parseSessionProcessLogArgs: () => parseSessionProcessLogArgs,
|
|
60
61
|
parseSessionRunCommand: () => parseSessionRunCommand,
|
|
61
62
|
parseSetEnvArgs: () => parseSetEnvArgs,
|
|
62
63
|
parseShellArgs: () => parseShellArgs,
|
|
@@ -73,6 +74,7 @@ __export(cli_exports, {
|
|
|
73
74
|
renderProcessHistory: () => renderProcessHistory,
|
|
74
75
|
renderProcessInspection: () => renderProcessInspection,
|
|
75
76
|
renderProcessList: () => renderProcessList,
|
|
77
|
+
renderProcessLog: () => renderProcessLog,
|
|
76
78
|
renderSessionRunStart: () => renderSessionRunStart,
|
|
77
79
|
renderSessionRunStatus: () => renderSessionRunStatus,
|
|
78
80
|
renderWorkspaceStatus: () => renderWorkspaceStatus,
|
|
@@ -155,14 +157,19 @@ const K8S_HELP_TEXT = [
|
|
|
155
157
|
].join("\n");
|
|
156
158
|
const SESSION_RUN_HELP_TEXT = [
|
|
157
159
|
"Usage:",
|
|
158
|
-
' r5dctl -p <project> session start --worker <label> --worktree <branch> --model <tier> [-f|--follow|--watch] [--tools] "<prompt>"',
|
|
159
|
-
' r5dctl -p <project> session start --worker <label> --new-worktree <branch> --source worktree:<branch> --model <tier> [-f|--follow|--watch] [--tools] "<prompt>"',
|
|
160
|
+
' r5dctl -p <project> session start --worker <label> --worktree <branch> --model <tier> [-f|--follow|--watch] [--tools] [--parent-session <session-id>] "<prompt>"',
|
|
161
|
+
' r5dctl -p <project> session start --worker <label> --new-worktree <branch> --source worktree:<branch> [--working-tree carry|clean] --model <tier> [-f|--follow|--watch] [--tools] [--parent-session <session-id>] "<prompt>"',
|
|
160
162
|
" r5dctl session status <session-id>",
|
|
161
163
|
' r5dctl session prompt --worker <label> --mode <mode> --model <tier> <session-id> "<prompt>"',
|
|
162
164
|
" r5dctl session stop <session-id>",
|
|
165
|
+
" r5dctl session process-log <run-id> [--tail <n>] [--grep <pattern>]",
|
|
163
166
|
"",
|
|
164
167
|
"Create, inspect, resume, and stop ordinary agent sessions.",
|
|
168
|
+
"A new worktree starts with the source checkout's uncommitted changes (--working-tree carry, the default);",
|
|
169
|
+
"--working-tree clean checks out the source branch's current commit only. Start and status print the mode, never a commit hash.",
|
|
165
170
|
"Use -f/--follow/--watch to attach after a start; Ctrl-C detaches without stopping the session.",
|
|
171
|
+
"process-log prints a shell run's stored stdout/stderr from the server: the whole log, its last n lines,",
|
|
172
|
+
"or the lines matching a JavaScript regular expression. The log is not a file on the worker.",
|
|
166
173
|
""
|
|
167
174
|
].join("\n");
|
|
168
175
|
const SHARED_HELP_ENTRIES = [
|
|
@@ -262,8 +269,8 @@ const SHARED_HELP_ENTRIES = [
|
|
|
262
269
|
},
|
|
263
270
|
{
|
|
264
271
|
section: "sessions",
|
|
265
|
-
usage: '-p <project> session start --worker <label> (--worktree <branch>|--new-worktree <branch> --source worktree:<branch>) --model <tier> [-f|--follow|--watch] [--tools] "<prompt>"',
|
|
266
|
-
description: "Start an ordinary agent session on an explicit existing or new worktree."
|
|
272
|
+
usage: '-p <project> session start --worker <label> (--worktree <branch>|--new-worktree <branch> --source worktree:<branch> [--working-tree carry|clean]) --model <tier> [-f|--follow|--watch] [--tools] [--parent-session <session-id>] "<prompt>"',
|
|
273
|
+
description: "Start an ordinary agent session on an explicit existing or new worktree. A new worktree carries the source checkout's uncommitted changes unless --working-tree clean is passed. --parent-session links it like start_subagent: the parent is notified when the run finishes."
|
|
267
274
|
},
|
|
268
275
|
{
|
|
269
276
|
section: "sessions",
|
|
@@ -280,6 +287,11 @@ const SHARED_HELP_ENTRIES = [
|
|
|
280
287
|
usage: "session stop <session-id>",
|
|
281
288
|
description: "Stop an active session generation."
|
|
282
289
|
},
|
|
290
|
+
{
|
|
291
|
+
section: "sessions",
|
|
292
|
+
usage: "session process-log <run-id> [--tail <n>] [--grep <pattern>]",
|
|
293
|
+
description: "Print a shell run's stored stdout/stderr from the server: the whole log, its last lines, or lines matching a regular expression."
|
|
294
|
+
},
|
|
283
295
|
{
|
|
284
296
|
section: "sessions",
|
|
285
297
|
usage: '-s <session-id> answer-questions --worker <label> --mode <mode> --model <tier> -a1 "<answer>" ...',
|
|
@@ -543,6 +555,12 @@ function parseWorktreeSource(rawValue) {
|
|
|
543
555
|
}
|
|
544
556
|
return { type, branchName };
|
|
545
557
|
}
|
|
558
|
+
function parseWorkingTreeMode(rawValue) {
|
|
559
|
+
if (rawValue === void 0) return "carry";
|
|
560
|
+
const mode = rawValue.trim();
|
|
561
|
+
if (mode !== "carry" && mode !== "clean") throw new Error("Invalid --working-tree. Expected carry or clean");
|
|
562
|
+
return mode;
|
|
563
|
+
}
|
|
546
564
|
function requireModel(value) {
|
|
547
565
|
const model = requireValue(value?.trim(), "--model <tier> is required");
|
|
548
566
|
if (!MODEL_TIERS.has(model)) throw new Error("Invalid --model. Expected one of: low, medium, high, max");
|
|
@@ -568,7 +586,7 @@ function parseSessionRunCommand(options, args) {
|
|
|
568
586
|
const project = requireValue(options.project, "--project/-p is required for `session start`");
|
|
569
587
|
const parsed = parseCommandOperands(
|
|
570
588
|
commandArgs,
|
|
571
|
-
/* @__PURE__ */ new Set(["--worker", "--worktree", "--new-worktree", "--source", "--model"]),
|
|
589
|
+
/* @__PURE__ */ new Set(["--worker", "--worktree", "--new-worktree", "--source", "--working-tree", "--model", "--parent-session"]),
|
|
572
590
|
/* @__PURE__ */ new Map([
|
|
573
591
|
["-f", "--follow"],
|
|
574
592
|
["--follow", "--follow"],
|
|
@@ -587,6 +605,9 @@ function parseSessionRunCommand(options, args) {
|
|
|
587
605
|
}
|
|
588
606
|
const sourceValue = parsed.values.get("--source");
|
|
589
607
|
if (worktree && sourceValue) throw new Error("--source is only supported with --new-worktree");
|
|
608
|
+
const workingTreeValue = parsed.values.get("--working-tree");
|
|
609
|
+
if (worktree && workingTreeValue !== void 0) throw new Error("--working-tree is only supported with --new-worktree");
|
|
610
|
+
const parentSessionId = parsed.values.get("--parent-session")?.trim();
|
|
590
611
|
return {
|
|
591
612
|
kind: "start",
|
|
592
613
|
project,
|
|
@@ -595,7 +616,8 @@ function parseSessionRunCommand(options, args) {
|
|
|
595
616
|
prompt,
|
|
596
617
|
follow: parsed.booleans.has("--follow"),
|
|
597
618
|
includeTools: parsed.booleans.has("--tools"),
|
|
598
|
-
...
|
|
619
|
+
...parentSessionId ? { parentSessionId } : {},
|
|
620
|
+
...worktree ? { worktree } : { newWorktree, source: parseWorktreeSource(sourceValue), workingTree: parseWorkingTreeMode(workingTreeValue) }
|
|
599
621
|
};
|
|
600
622
|
}
|
|
601
623
|
rejectSessionRunGlobalScopes(options, false);
|
|
@@ -621,6 +643,16 @@ function parseSessionRunCommand(options, args) {
|
|
|
621
643
|
}
|
|
622
644
|
throw new Error(`Unknown session command: ${subcommand}`);
|
|
623
645
|
}
|
|
646
|
+
function parseSessionProcessLogArgs(args) {
|
|
647
|
+
const parsed = parseCommandOperands(args, /* @__PURE__ */ new Set(["--tail", "--grep"]), /* @__PURE__ */ new Map(), "session process-log");
|
|
648
|
+
const runId = requireValue(parsed.positionals[0], "Process run id is required for `session process-log`");
|
|
649
|
+
if (parsed.positionals.length > 1) throw new Error(`Unexpected session process-log argument: ${parsed.positionals[1]}`);
|
|
650
|
+
const tailValue = parsed.values.get("--tail");
|
|
651
|
+
const tail = tailValue === void 0 ? void 0 : Number(tailValue);
|
|
652
|
+
if (tail !== void 0 && (!Number.isInteger(tail) || tail < 1)) throw new Error("--tail must be a positive integer");
|
|
653
|
+
const grep = parsed.values.get("--grep");
|
|
654
|
+
return { runId, ...tail !== void 0 ? { tail } : {}, ...grep !== void 0 ? { grep } : {} };
|
|
655
|
+
}
|
|
624
656
|
function assertAuthLoginArgs(args) {
|
|
625
657
|
const valueFlags = /* @__PURE__ */ new Set(["--device-name", "--worker-label"]);
|
|
626
658
|
const booleanFlags = /* @__PURE__ */ new Set(["--no-open", "--no-qr"]);
|
|
@@ -1678,6 +1710,32 @@ function renderProcessList(processes, nowMs = Date.now()) {
|
|
|
1678
1710
|
function renderProcessHistory(processes, nowMs = Date.now()) {
|
|
1679
1711
|
return processes.length === 0 ? "No process history.\n" : renderProcessList(processes, nowMs);
|
|
1680
1712
|
}
|
|
1713
|
+
function renderProcessLog(log) {
|
|
1714
|
+
const sections = [];
|
|
1715
|
+
for (const [name, stream] of [
|
|
1716
|
+
["stdout", log.stdout],
|
|
1717
|
+
["stderr", log.stderr]
|
|
1718
|
+
]) {
|
|
1719
|
+
if (stream.text.length === 0) continue;
|
|
1720
|
+
sections.push(`==> ${name} <==
|
|
1721
|
+
${stream.text.endsWith("\n") ? stream.text : `${stream.text}
|
|
1722
|
+
`}`);
|
|
1723
|
+
}
|
|
1724
|
+
const selection = [
|
|
1725
|
+
...log.grep !== void 0 ? [`lines matching /${log.grep}/`] : [],
|
|
1726
|
+
...log.tailLines !== void 0 ? [`last ${log.tailLines} lines`] : []
|
|
1727
|
+
];
|
|
1728
|
+
const cut = [log.stdout.truncated ? "stdout" : void 0, log.stderr.truncated ? "stderr" : void 0].filter(Boolean);
|
|
1729
|
+
const summary = [
|
|
1730
|
+
`Run ${log.runId} (${log.status}${log.exitCode !== void 0 ? `, exit ${log.exitCode}` : ""}): `,
|
|
1731
|
+
`stdout ${log.stdout.totalBytes} bytes, stderr ${log.stderr.totalBytes} bytes`,
|
|
1732
|
+
selection.length > 0 ? `; showing ${selection.join(", ")}` : "",
|
|
1733
|
+
cut.length > 0 ? `; ${cut.join(" and ")} cut to ${log.maxBytesPerStream} bytes, narrow with --tail or --grep` : "",
|
|
1734
|
+
sections.length === 0 ? "; no output to show" : ""
|
|
1735
|
+
].join("");
|
|
1736
|
+
return { text: sections.join(""), summary: `${summary}
|
|
1737
|
+
` };
|
|
1738
|
+
}
|
|
1681
1739
|
function renderProcessInspection(process2) {
|
|
1682
1740
|
return [
|
|
1683
1741
|
`Run: ${process2.runId}`,
|
|
@@ -1831,13 +1889,22 @@ function formatStatusValue(value) {
|
|
|
1831
1889
|
}
|
|
1832
1890
|
return value === void 0 || value === null ? void 0 : String(value);
|
|
1833
1891
|
}
|
|
1892
|
+
function pushWorktreeOriginLines(lines, session) {
|
|
1893
|
+
const source = responseString(session, "sourceBranch");
|
|
1894
|
+
const mode = responseString(session, "workingTree");
|
|
1895
|
+
if (!source || !mode) return;
|
|
1896
|
+
lines.push(`Source: ${source}`);
|
|
1897
|
+
const detail = mode === "carry" ? `carried ${source}'s uncommitted changes at launch` : mode === "clean" ? `clean checkout of ${source}'s commit at launch` : void 0;
|
|
1898
|
+
lines.push(`Working tree: ${mode}${detail ? ` (${detail})` : ""}`);
|
|
1899
|
+
}
|
|
1834
1900
|
function renderSessionRunStart(session) {
|
|
1835
1901
|
const lines = [
|
|
1836
1902
|
`Session: ${responseString(session, "sessionId") ?? "(unknown)"}`,
|
|
1837
1903
|
`Status: ${formatStatusValue(session.status) ?? "queued"}`,
|
|
1838
|
-
`Worktree: ${responseString(session, "branchName") ?? "(provisioning)"}
|
|
1839
|
-
`Worker: ${responseString(session, "worker") ?? "(unassigned)"}`
|
|
1904
|
+
`Worktree: ${responseString(session, "branchName") ?? "(provisioning)"}`
|
|
1840
1905
|
];
|
|
1906
|
+
pushWorktreeOriginLines(lines, session);
|
|
1907
|
+
lines.push(`Worker: ${responseString(session, "worker") ?? "(unassigned)"}`);
|
|
1841
1908
|
const sessionUrl = responseString(session, "sessionUrl");
|
|
1842
1909
|
if (sessionUrl) lines.push(`URL: ${sessionUrl}`);
|
|
1843
1910
|
const sessionId = responseString(session, "sessionId");
|
|
@@ -1845,29 +1912,50 @@ function renderSessionRunStart(session) {
|
|
|
1845
1912
|
return `${lines.join("\n")}
|
|
1846
1913
|
`;
|
|
1847
1914
|
}
|
|
1915
|
+
function formatBranchStateHint(branch) {
|
|
1916
|
+
const target = branch ?? "<branch>";
|
|
1917
|
+
const commands = [
|
|
1918
|
+
`git merge-base <your-branch> ${target}`,
|
|
1919
|
+
`git log --oneline <your-branch>..${target}`,
|
|
1920
|
+
"git status in the branch folder"
|
|
1921
|
+
];
|
|
1922
|
+
return `inspect the worktree with git (${commands.join("; ")})`;
|
|
1923
|
+
}
|
|
1924
|
+
function formatQueuedAt(value) {
|
|
1925
|
+
const time = Date.parse(value);
|
|
1926
|
+
return Number.isNaN(time) ? value : new Date(time).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
1927
|
+
}
|
|
1928
|
+
function formatProvisioningQueueLine(session) {
|
|
1929
|
+
const position = session.provisioningQueuePosition;
|
|
1930
|
+
const queuedAt = responseString(session, "provisioningQueuedAt");
|
|
1931
|
+
if (typeof position !== "number" || !Number.isInteger(position) || position < 0 || !queuedAt) return void 0;
|
|
1932
|
+
const since = formatQueuedAt(queuedAt);
|
|
1933
|
+
if (position === 0) return `Provisioning: worker started the branch operation at ${since}`;
|
|
1934
|
+
return `Provisioning: queued behind ${position} worker operation${position === 1 ? "" : "s"} since ${since}`;
|
|
1935
|
+
}
|
|
1848
1936
|
function renderSessionRunStatus(session) {
|
|
1849
1937
|
const status = formatStatusValue(session.status) ?? "unknown";
|
|
1850
1938
|
const lines = [`Session: ${responseString(session, "sessionId") ?? "(unknown)"}`, `Status: ${status}`];
|
|
1851
1939
|
const runStatus = formatStatusValue(session.runStatus);
|
|
1852
1940
|
if (runStatus) lines.push(`Run: ${runStatus}`);
|
|
1941
|
+
const provisioningQueue = formatProvisioningQueueLine(session);
|
|
1942
|
+
if (provisioningQueue) lines.push(provisioningQueue);
|
|
1853
1943
|
const promptDisposition = responseString(session, "promptDisposition");
|
|
1854
1944
|
if (promptDisposition) lines.push(`Prompt: ${promptDisposition}`);
|
|
1855
1945
|
const branch = responseString(session, "branchName");
|
|
1856
1946
|
if (branch) lines.push(`Worktree: ${branch}`);
|
|
1947
|
+
pushWorktreeOriginLines(lines, session);
|
|
1857
1948
|
for (const [label, key] of [
|
|
1858
|
-
["Workspace head", "workspaceHead"],
|
|
1859
|
-
["Baseline", "baselineCommit"],
|
|
1860
|
-
["Head", "headCommit"],
|
|
1861
1949
|
["Worker", "worker"],
|
|
1950
|
+
["Parent session", "parentSessionId"],
|
|
1862
1951
|
["Session", "sessionUrl"]
|
|
1863
1952
|
]) {
|
|
1864
1953
|
const value = responseString(session, key);
|
|
1865
1954
|
if (value) lines.push(`${label}: ${value}`);
|
|
1866
1955
|
}
|
|
1956
|
+
lines.push(`Branch state: ${formatBranchStateHint(branch)}`);
|
|
1867
1957
|
const error = responseString(session, "error");
|
|
1868
1958
|
if (error) lines.push(`Error: ${error}`);
|
|
1869
|
-
const headCommitError = responseString(session, "headCommitError");
|
|
1870
|
-
if (headCommitError) lines.push(`Head error: ${headCommitError}`);
|
|
1871
1959
|
const diffSummary = responseString(session, "diffSummary");
|
|
1872
1960
|
if (diffSummary) lines.push("", diffSummary);
|
|
1873
1961
|
const summary = responseString(session, "summary");
|
|
@@ -1885,13 +1973,14 @@ async function dispatchSessionRunCommand(client, command) {
|
|
|
1885
1973
|
prompt: command.prompt,
|
|
1886
1974
|
worker: command.worker,
|
|
1887
1975
|
model: command.model,
|
|
1888
|
-
requestId: (0, import_node_crypto.randomUUID)()
|
|
1976
|
+
requestId: (0, import_node_crypto.randomUUID)(),
|
|
1977
|
+
...command.parentSessionId ? { parentSessionId: command.parentSessionId } : {}
|
|
1889
1978
|
};
|
|
1890
1979
|
let input;
|
|
1891
1980
|
if (command.worktree !== void 0) {
|
|
1892
1981
|
input = { ...commonInput, worktree: command.worktree };
|
|
1893
1982
|
} else if (command.newWorktree !== void 0 && command.source !== void 0) {
|
|
1894
|
-
input = { ...commonInput, newWorktree: command.newWorktree, source: command.source };
|
|
1983
|
+
input = { ...commonInput, newWorktree: command.newWorktree, source: command.source, workingTree: command.workingTree };
|
|
1895
1984
|
} else {
|
|
1896
1985
|
throw new Error("Session start requires an existing or new worktree");
|
|
1897
1986
|
}
|
|
@@ -2531,6 +2620,17 @@ async function executeR5dctlCommand(client, json, args) {
|
|
|
2531
2620
|
`);
|
|
2532
2621
|
return;
|
|
2533
2622
|
}
|
|
2623
|
+
if (first === "session" && second === "process-log") {
|
|
2624
|
+
const selection = parseSessionProcessLogArgs(args.slice(2));
|
|
2625
|
+
const log = await client.processes.log(selection.runId, {
|
|
2626
|
+
...selection.tail !== void 0 ? { tail: selection.tail } : {},
|
|
2627
|
+
...selection.grep !== void 0 ? { grep: selection.grep } : {}
|
|
2628
|
+
});
|
|
2629
|
+
const rendered = renderProcessLog(log);
|
|
2630
|
+
write(log, rendered.text);
|
|
2631
|
+
if (!json) process.stderr.write(rendered.summary);
|
|
2632
|
+
return;
|
|
2633
|
+
}
|
|
2534
2634
|
if (first === "sessions" && second === "recent") {
|
|
2535
2635
|
const sessions = await client.sessions.recent(parseRecentSessionArgs(args.slice(2)));
|
|
2536
2636
|
write(sessions, renderRecentSessionList(sessions));
|
|
@@ -3138,6 +3238,20 @@ function resolveCommandExecution(options, rest) {
|
|
|
3138
3238
|
};
|
|
3139
3239
|
}
|
|
3140
3240
|
if (command === "session") {
|
|
3241
|
+
if (commandArgs[0] === "process-log") {
|
|
3242
|
+
rejectSessionRunGlobalScopes(options, false);
|
|
3243
|
+
const selection = parseSessionProcessLogArgs(commandArgs.slice(1));
|
|
3244
|
+
return {
|
|
3245
|
+
kind: "plugin",
|
|
3246
|
+
pluginArgs: [
|
|
3247
|
+
"session",
|
|
3248
|
+
"process-log",
|
|
3249
|
+
selection.runId,
|
|
3250
|
+
...selection.tail !== void 0 ? [`--tail=${selection.tail}`] : [],
|
|
3251
|
+
...selection.grep !== void 0 ? [`--grep=${selection.grep}`] : []
|
|
3252
|
+
]
|
|
3253
|
+
};
|
|
3254
|
+
}
|
|
3141
3255
|
return { kind: "session-run", command: parseSessionRunCommand(options, commandArgs) };
|
|
3142
3256
|
}
|
|
3143
3257
|
if (command === "answer-questions") {
|
|
@@ -3318,6 +3432,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
3318
3432
|
parsePromptArgs,
|
|
3319
3433
|
parsePsHistoryArgs,
|
|
3320
3434
|
parsePsListArgs,
|
|
3435
|
+
parseSessionProcessLogArgs,
|
|
3321
3436
|
parseSessionRunCommand,
|
|
3322
3437
|
parseSetEnvArgs,
|
|
3323
3438
|
parseShellArgs,
|
|
@@ -3334,6 +3449,7 @@ async function main(argv = process.argv.slice(2)) {
|
|
|
3334
3449
|
renderProcessHistory,
|
|
3335
3450
|
renderProcessInspection,
|
|
3336
3451
|
renderProcessList,
|
|
3452
|
+
renderProcessLog,
|
|
3337
3453
|
renderSessionRunStart,
|
|
3338
3454
|
renderSessionRunStatus,
|
|
3339
3455
|
renderWorkspaceStatus,
|
package/dist/cjs/package.json
CHANGED
package/dist/mjs/cli.mjs
CHANGED
|
@@ -72,14 +72,19 @@ const K8S_HELP_TEXT = [
|
|
|
72
72
|
].join("\n");
|
|
73
73
|
const SESSION_RUN_HELP_TEXT = [
|
|
74
74
|
"Usage:",
|
|
75
|
-
' r5dctl -p <project> session start --worker <label> --worktree <branch> --model <tier> [-f|--follow|--watch] [--tools] "<prompt>"',
|
|
76
|
-
' r5dctl -p <project> session start --worker <label> --new-worktree <branch> --source worktree:<branch> --model <tier> [-f|--follow|--watch] [--tools] "<prompt>"',
|
|
75
|
+
' r5dctl -p <project> session start --worker <label> --worktree <branch> --model <tier> [-f|--follow|--watch] [--tools] [--parent-session <session-id>] "<prompt>"',
|
|
76
|
+
' r5dctl -p <project> session start --worker <label> --new-worktree <branch> --source worktree:<branch> [--working-tree carry|clean] --model <tier> [-f|--follow|--watch] [--tools] [--parent-session <session-id>] "<prompt>"',
|
|
77
77
|
" r5dctl session status <session-id>",
|
|
78
78
|
' r5dctl session prompt --worker <label> --mode <mode> --model <tier> <session-id> "<prompt>"',
|
|
79
79
|
" r5dctl session stop <session-id>",
|
|
80
|
+
" r5dctl session process-log <run-id> [--tail <n>] [--grep <pattern>]",
|
|
80
81
|
"",
|
|
81
82
|
"Create, inspect, resume, and stop ordinary agent sessions.",
|
|
83
|
+
"A new worktree starts with the source checkout's uncommitted changes (--working-tree carry, the default);",
|
|
84
|
+
"--working-tree clean checks out the source branch's current commit only. Start and status print the mode, never a commit hash.",
|
|
82
85
|
"Use -f/--follow/--watch to attach after a start; Ctrl-C detaches without stopping the session.",
|
|
86
|
+
"process-log prints a shell run's stored stdout/stderr from the server: the whole log, its last n lines,",
|
|
87
|
+
"or the lines matching a JavaScript regular expression. The log is not a file on the worker.",
|
|
83
88
|
""
|
|
84
89
|
].join("\n");
|
|
85
90
|
const SHARED_HELP_ENTRIES = [
|
|
@@ -179,8 +184,8 @@ const SHARED_HELP_ENTRIES = [
|
|
|
179
184
|
},
|
|
180
185
|
{
|
|
181
186
|
section: "sessions",
|
|
182
|
-
usage: '-p <project> session start --worker <label> (--worktree <branch>|--new-worktree <branch> --source worktree:<branch>) --model <tier> [-f|--follow|--watch] [--tools] "<prompt>"',
|
|
183
|
-
description: "Start an ordinary agent session on an explicit existing or new worktree."
|
|
187
|
+
usage: '-p <project> session start --worker <label> (--worktree <branch>|--new-worktree <branch> --source worktree:<branch> [--working-tree carry|clean]) --model <tier> [-f|--follow|--watch] [--tools] [--parent-session <session-id>] "<prompt>"',
|
|
188
|
+
description: "Start an ordinary agent session on an explicit existing or new worktree. A new worktree carries the source checkout's uncommitted changes unless --working-tree clean is passed. --parent-session links it like start_subagent: the parent is notified when the run finishes."
|
|
184
189
|
},
|
|
185
190
|
{
|
|
186
191
|
section: "sessions",
|
|
@@ -197,6 +202,11 @@ const SHARED_HELP_ENTRIES = [
|
|
|
197
202
|
usage: "session stop <session-id>",
|
|
198
203
|
description: "Stop an active session generation."
|
|
199
204
|
},
|
|
205
|
+
{
|
|
206
|
+
section: "sessions",
|
|
207
|
+
usage: "session process-log <run-id> [--tail <n>] [--grep <pattern>]",
|
|
208
|
+
description: "Print a shell run's stored stdout/stderr from the server: the whole log, its last lines, or lines matching a regular expression."
|
|
209
|
+
},
|
|
200
210
|
{
|
|
201
211
|
section: "sessions",
|
|
202
212
|
usage: '-s <session-id> answer-questions --worker <label> --mode <mode> --model <tier> -a1 "<answer>" ...',
|
|
@@ -460,6 +470,12 @@ function parseWorktreeSource(rawValue) {
|
|
|
460
470
|
}
|
|
461
471
|
return { type, branchName };
|
|
462
472
|
}
|
|
473
|
+
function parseWorkingTreeMode(rawValue) {
|
|
474
|
+
if (rawValue === void 0) return "carry";
|
|
475
|
+
const mode = rawValue.trim();
|
|
476
|
+
if (mode !== "carry" && mode !== "clean") throw new Error("Invalid --working-tree. Expected carry or clean");
|
|
477
|
+
return mode;
|
|
478
|
+
}
|
|
463
479
|
function requireModel(value) {
|
|
464
480
|
const model = requireValue(value?.trim(), "--model <tier> is required");
|
|
465
481
|
if (!MODEL_TIERS.has(model)) throw new Error("Invalid --model. Expected one of: low, medium, high, max");
|
|
@@ -485,7 +501,7 @@ function parseSessionRunCommand(options, args) {
|
|
|
485
501
|
const project = requireValue(options.project, "--project/-p is required for `session start`");
|
|
486
502
|
const parsed = parseCommandOperands(
|
|
487
503
|
commandArgs,
|
|
488
|
-
/* @__PURE__ */ new Set(["--worker", "--worktree", "--new-worktree", "--source", "--model"]),
|
|
504
|
+
/* @__PURE__ */ new Set(["--worker", "--worktree", "--new-worktree", "--source", "--working-tree", "--model", "--parent-session"]),
|
|
489
505
|
/* @__PURE__ */ new Map([
|
|
490
506
|
["-f", "--follow"],
|
|
491
507
|
["--follow", "--follow"],
|
|
@@ -504,6 +520,9 @@ function parseSessionRunCommand(options, args) {
|
|
|
504
520
|
}
|
|
505
521
|
const sourceValue = parsed.values.get("--source");
|
|
506
522
|
if (worktree && sourceValue) throw new Error("--source is only supported with --new-worktree");
|
|
523
|
+
const workingTreeValue = parsed.values.get("--working-tree");
|
|
524
|
+
if (worktree && workingTreeValue !== void 0) throw new Error("--working-tree is only supported with --new-worktree");
|
|
525
|
+
const parentSessionId = parsed.values.get("--parent-session")?.trim();
|
|
507
526
|
return {
|
|
508
527
|
kind: "start",
|
|
509
528
|
project,
|
|
@@ -512,7 +531,8 @@ function parseSessionRunCommand(options, args) {
|
|
|
512
531
|
prompt,
|
|
513
532
|
follow: parsed.booleans.has("--follow"),
|
|
514
533
|
includeTools: parsed.booleans.has("--tools"),
|
|
515
|
-
...
|
|
534
|
+
...parentSessionId ? { parentSessionId } : {},
|
|
535
|
+
...worktree ? { worktree } : { newWorktree, source: parseWorktreeSource(sourceValue), workingTree: parseWorkingTreeMode(workingTreeValue) }
|
|
516
536
|
};
|
|
517
537
|
}
|
|
518
538
|
rejectSessionRunGlobalScopes(options, false);
|
|
@@ -538,6 +558,16 @@ function parseSessionRunCommand(options, args) {
|
|
|
538
558
|
}
|
|
539
559
|
throw new Error(`Unknown session command: ${subcommand}`);
|
|
540
560
|
}
|
|
561
|
+
function parseSessionProcessLogArgs(args) {
|
|
562
|
+
const parsed = parseCommandOperands(args, /* @__PURE__ */ new Set(["--tail", "--grep"]), /* @__PURE__ */ new Map(), "session process-log");
|
|
563
|
+
const runId = requireValue(parsed.positionals[0], "Process run id is required for `session process-log`");
|
|
564
|
+
if (parsed.positionals.length > 1) throw new Error(`Unexpected session process-log argument: ${parsed.positionals[1]}`);
|
|
565
|
+
const tailValue = parsed.values.get("--tail");
|
|
566
|
+
const tail = tailValue === void 0 ? void 0 : Number(tailValue);
|
|
567
|
+
if (tail !== void 0 && (!Number.isInteger(tail) || tail < 1)) throw new Error("--tail must be a positive integer");
|
|
568
|
+
const grep = parsed.values.get("--grep");
|
|
569
|
+
return { runId, ...tail !== void 0 ? { tail } : {}, ...grep !== void 0 ? { grep } : {} };
|
|
570
|
+
}
|
|
541
571
|
function assertAuthLoginArgs(args) {
|
|
542
572
|
const valueFlags = /* @__PURE__ */ new Set(["--device-name", "--worker-label"]);
|
|
543
573
|
const booleanFlags = /* @__PURE__ */ new Set(["--no-open", "--no-qr"]);
|
|
@@ -1595,6 +1625,32 @@ function renderProcessList(processes, nowMs = Date.now()) {
|
|
|
1595
1625
|
function renderProcessHistory(processes, nowMs = Date.now()) {
|
|
1596
1626
|
return processes.length === 0 ? "No process history.\n" : renderProcessList(processes, nowMs);
|
|
1597
1627
|
}
|
|
1628
|
+
function renderProcessLog(log) {
|
|
1629
|
+
const sections = [];
|
|
1630
|
+
for (const [name, stream] of [
|
|
1631
|
+
["stdout", log.stdout],
|
|
1632
|
+
["stderr", log.stderr]
|
|
1633
|
+
]) {
|
|
1634
|
+
if (stream.text.length === 0) continue;
|
|
1635
|
+
sections.push(`==> ${name} <==
|
|
1636
|
+
${stream.text.endsWith("\n") ? stream.text : `${stream.text}
|
|
1637
|
+
`}`);
|
|
1638
|
+
}
|
|
1639
|
+
const selection = [
|
|
1640
|
+
...log.grep !== void 0 ? [`lines matching /${log.grep}/`] : [],
|
|
1641
|
+
...log.tailLines !== void 0 ? [`last ${log.tailLines} lines`] : []
|
|
1642
|
+
];
|
|
1643
|
+
const cut = [log.stdout.truncated ? "stdout" : void 0, log.stderr.truncated ? "stderr" : void 0].filter(Boolean);
|
|
1644
|
+
const summary = [
|
|
1645
|
+
`Run ${log.runId} (${log.status}${log.exitCode !== void 0 ? `, exit ${log.exitCode}` : ""}): `,
|
|
1646
|
+
`stdout ${log.stdout.totalBytes} bytes, stderr ${log.stderr.totalBytes} bytes`,
|
|
1647
|
+
selection.length > 0 ? `; showing ${selection.join(", ")}` : "",
|
|
1648
|
+
cut.length > 0 ? `; ${cut.join(" and ")} cut to ${log.maxBytesPerStream} bytes, narrow with --tail or --grep` : "",
|
|
1649
|
+
sections.length === 0 ? "; no output to show" : ""
|
|
1650
|
+
].join("");
|
|
1651
|
+
return { text: sections.join(""), summary: `${summary}
|
|
1652
|
+
` };
|
|
1653
|
+
}
|
|
1598
1654
|
function renderProcessInspection(process2) {
|
|
1599
1655
|
return [
|
|
1600
1656
|
`Run: ${process2.runId}`,
|
|
@@ -1748,13 +1804,22 @@ function formatStatusValue(value) {
|
|
|
1748
1804
|
}
|
|
1749
1805
|
return value === void 0 || value === null ? void 0 : String(value);
|
|
1750
1806
|
}
|
|
1807
|
+
function pushWorktreeOriginLines(lines, session) {
|
|
1808
|
+
const source = responseString(session, "sourceBranch");
|
|
1809
|
+
const mode = responseString(session, "workingTree");
|
|
1810
|
+
if (!source || !mode) return;
|
|
1811
|
+
lines.push(`Source: ${source}`);
|
|
1812
|
+
const detail = mode === "carry" ? `carried ${source}'s uncommitted changes at launch` : mode === "clean" ? `clean checkout of ${source}'s commit at launch` : void 0;
|
|
1813
|
+
lines.push(`Working tree: ${mode}${detail ? ` (${detail})` : ""}`);
|
|
1814
|
+
}
|
|
1751
1815
|
function renderSessionRunStart(session) {
|
|
1752
1816
|
const lines = [
|
|
1753
1817
|
`Session: ${responseString(session, "sessionId") ?? "(unknown)"}`,
|
|
1754
1818
|
`Status: ${formatStatusValue(session.status) ?? "queued"}`,
|
|
1755
|
-
`Worktree: ${responseString(session, "branchName") ?? "(provisioning)"}
|
|
1756
|
-
`Worker: ${responseString(session, "worker") ?? "(unassigned)"}`
|
|
1819
|
+
`Worktree: ${responseString(session, "branchName") ?? "(provisioning)"}`
|
|
1757
1820
|
];
|
|
1821
|
+
pushWorktreeOriginLines(lines, session);
|
|
1822
|
+
lines.push(`Worker: ${responseString(session, "worker") ?? "(unassigned)"}`);
|
|
1758
1823
|
const sessionUrl = responseString(session, "sessionUrl");
|
|
1759
1824
|
if (sessionUrl) lines.push(`URL: ${sessionUrl}`);
|
|
1760
1825
|
const sessionId = responseString(session, "sessionId");
|
|
@@ -1762,29 +1827,50 @@ function renderSessionRunStart(session) {
|
|
|
1762
1827
|
return `${lines.join("\n")}
|
|
1763
1828
|
`;
|
|
1764
1829
|
}
|
|
1830
|
+
function formatBranchStateHint(branch) {
|
|
1831
|
+
const target = branch ?? "<branch>";
|
|
1832
|
+
const commands = [
|
|
1833
|
+
`git merge-base <your-branch> ${target}`,
|
|
1834
|
+
`git log --oneline <your-branch>..${target}`,
|
|
1835
|
+
"git status in the branch folder"
|
|
1836
|
+
];
|
|
1837
|
+
return `inspect the worktree with git (${commands.join("; ")})`;
|
|
1838
|
+
}
|
|
1839
|
+
function formatQueuedAt(value) {
|
|
1840
|
+
const time = Date.parse(value);
|
|
1841
|
+
return Number.isNaN(time) ? value : new Date(time).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
1842
|
+
}
|
|
1843
|
+
function formatProvisioningQueueLine(session) {
|
|
1844
|
+
const position = session.provisioningQueuePosition;
|
|
1845
|
+
const queuedAt = responseString(session, "provisioningQueuedAt");
|
|
1846
|
+
if (typeof position !== "number" || !Number.isInteger(position) || position < 0 || !queuedAt) return void 0;
|
|
1847
|
+
const since = formatQueuedAt(queuedAt);
|
|
1848
|
+
if (position === 0) return `Provisioning: worker started the branch operation at ${since}`;
|
|
1849
|
+
return `Provisioning: queued behind ${position} worker operation${position === 1 ? "" : "s"} since ${since}`;
|
|
1850
|
+
}
|
|
1765
1851
|
function renderSessionRunStatus(session) {
|
|
1766
1852
|
const status = formatStatusValue(session.status) ?? "unknown";
|
|
1767
1853
|
const lines = [`Session: ${responseString(session, "sessionId") ?? "(unknown)"}`, `Status: ${status}`];
|
|
1768
1854
|
const runStatus = formatStatusValue(session.runStatus);
|
|
1769
1855
|
if (runStatus) lines.push(`Run: ${runStatus}`);
|
|
1856
|
+
const provisioningQueue = formatProvisioningQueueLine(session);
|
|
1857
|
+
if (provisioningQueue) lines.push(provisioningQueue);
|
|
1770
1858
|
const promptDisposition = responseString(session, "promptDisposition");
|
|
1771
1859
|
if (promptDisposition) lines.push(`Prompt: ${promptDisposition}`);
|
|
1772
1860
|
const branch = responseString(session, "branchName");
|
|
1773
1861
|
if (branch) lines.push(`Worktree: ${branch}`);
|
|
1862
|
+
pushWorktreeOriginLines(lines, session);
|
|
1774
1863
|
for (const [label, key] of [
|
|
1775
|
-
["Workspace head", "workspaceHead"],
|
|
1776
|
-
["Baseline", "baselineCommit"],
|
|
1777
|
-
["Head", "headCommit"],
|
|
1778
1864
|
["Worker", "worker"],
|
|
1865
|
+
["Parent session", "parentSessionId"],
|
|
1779
1866
|
["Session", "sessionUrl"]
|
|
1780
1867
|
]) {
|
|
1781
1868
|
const value = responseString(session, key);
|
|
1782
1869
|
if (value) lines.push(`${label}: ${value}`);
|
|
1783
1870
|
}
|
|
1871
|
+
lines.push(`Branch state: ${formatBranchStateHint(branch)}`);
|
|
1784
1872
|
const error = responseString(session, "error");
|
|
1785
1873
|
if (error) lines.push(`Error: ${error}`);
|
|
1786
|
-
const headCommitError = responseString(session, "headCommitError");
|
|
1787
|
-
if (headCommitError) lines.push(`Head error: ${headCommitError}`);
|
|
1788
1874
|
const diffSummary = responseString(session, "diffSummary");
|
|
1789
1875
|
if (diffSummary) lines.push("", diffSummary);
|
|
1790
1876
|
const summary = responseString(session, "summary");
|
|
@@ -1802,13 +1888,14 @@ async function dispatchSessionRunCommand(client, command) {
|
|
|
1802
1888
|
prompt: command.prompt,
|
|
1803
1889
|
worker: command.worker,
|
|
1804
1890
|
model: command.model,
|
|
1805
|
-
requestId: randomUUID()
|
|
1891
|
+
requestId: randomUUID(),
|
|
1892
|
+
...command.parentSessionId ? { parentSessionId: command.parentSessionId } : {}
|
|
1806
1893
|
};
|
|
1807
1894
|
let input;
|
|
1808
1895
|
if (command.worktree !== void 0) {
|
|
1809
1896
|
input = { ...commonInput, worktree: command.worktree };
|
|
1810
1897
|
} else if (command.newWorktree !== void 0 && command.source !== void 0) {
|
|
1811
|
-
input = { ...commonInput, newWorktree: command.newWorktree, source: command.source };
|
|
1898
|
+
input = { ...commonInput, newWorktree: command.newWorktree, source: command.source, workingTree: command.workingTree };
|
|
1812
1899
|
} else {
|
|
1813
1900
|
throw new Error("Session start requires an existing or new worktree");
|
|
1814
1901
|
}
|
|
@@ -2448,6 +2535,17 @@ async function executeR5dctlCommand(client, json, args) {
|
|
|
2448
2535
|
`);
|
|
2449
2536
|
return;
|
|
2450
2537
|
}
|
|
2538
|
+
if (first === "session" && second === "process-log") {
|
|
2539
|
+
const selection = parseSessionProcessLogArgs(args.slice(2));
|
|
2540
|
+
const log = await client.processes.log(selection.runId, {
|
|
2541
|
+
...selection.tail !== void 0 ? { tail: selection.tail } : {},
|
|
2542
|
+
...selection.grep !== void 0 ? { grep: selection.grep } : {}
|
|
2543
|
+
});
|
|
2544
|
+
const rendered = renderProcessLog(log);
|
|
2545
|
+
write(log, rendered.text);
|
|
2546
|
+
if (!json) process.stderr.write(rendered.summary);
|
|
2547
|
+
return;
|
|
2548
|
+
}
|
|
2451
2549
|
if (first === "sessions" && second === "recent") {
|
|
2452
2550
|
const sessions = await client.sessions.recent(parseRecentSessionArgs(args.slice(2)));
|
|
2453
2551
|
write(sessions, renderRecentSessionList(sessions));
|
|
@@ -3055,6 +3153,20 @@ function resolveCommandExecution(options, rest) {
|
|
|
3055
3153
|
};
|
|
3056
3154
|
}
|
|
3057
3155
|
if (command === "session") {
|
|
3156
|
+
if (commandArgs[0] === "process-log") {
|
|
3157
|
+
rejectSessionRunGlobalScopes(options, false);
|
|
3158
|
+
const selection = parseSessionProcessLogArgs(commandArgs.slice(1));
|
|
3159
|
+
return {
|
|
3160
|
+
kind: "plugin",
|
|
3161
|
+
pluginArgs: [
|
|
3162
|
+
"session",
|
|
3163
|
+
"process-log",
|
|
3164
|
+
selection.runId,
|
|
3165
|
+
...selection.tail !== void 0 ? [`--tail=${selection.tail}`] : [],
|
|
3166
|
+
...selection.grep !== void 0 ? [`--grep=${selection.grep}`] : []
|
|
3167
|
+
]
|
|
3168
|
+
};
|
|
3169
|
+
}
|
|
3058
3170
|
return { kind: "session-run", command: parseSessionRunCommand(options, commandArgs) };
|
|
3059
3171
|
}
|
|
3060
3172
|
if (command === "answer-questions") {
|
|
@@ -3234,6 +3346,7 @@ export {
|
|
|
3234
3346
|
parsePromptArgs,
|
|
3235
3347
|
parsePsHistoryArgs,
|
|
3236
3348
|
parsePsListArgs,
|
|
3349
|
+
parseSessionProcessLogArgs,
|
|
3237
3350
|
parseSessionRunCommand,
|
|
3238
3351
|
parseSetEnvArgs,
|
|
3239
3352
|
parseShellArgs,
|
|
@@ -3250,6 +3363,7 @@ export {
|
|
|
3250
3363
|
renderProcessHistory,
|
|
3251
3364
|
renderProcessInspection,
|
|
3252
3365
|
renderProcessList,
|
|
3366
|
+
renderProcessLog,
|
|
3253
3367
|
renderSessionRunStart,
|
|
3254
3368
|
renderSessionRunStatus,
|
|
3255
3369
|
renderWorkspaceStatus,
|
package/dist/mjs/package.json
CHANGED
package/dist/types/cli.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R5dctlClient, type R5dctlConversationForkResponse, type R5dctlConversationHeadResponse, type R5dctlConversationRenderOptions, type R5dctlConversationResponse, type R5dctlConversationNodeResponse, type R5dctlConversationOverviewResponse, type R5dctlConversationWorkDetail, type R5dctlConversationWorkResponse, type R5dctlEnvData, type R5dctlK8sResourceHistory, type R5dctlK8sUsage, type R5dctlK8sWorkload, type R5dctlProcessInspection, type R5dctlProcessListInput, type R5dctlProcessRun, type R5dctlSessionEvent, type R5dctlSessionStartInput, type R5dctlWorkspaceStatus, type R5dctlWorkspaceSyncResult, type R5dctlWorktreeSource, type R5dctlSessionMode, type ChatMode, type ModelTier } from "@ricsam/r5d-api";
|
|
1
|
+
import { R5dctlClient, type R5dctlConversationForkResponse, type R5dctlConversationHeadResponse, type R5dctlConversationRenderOptions, type R5dctlConversationResponse, type R5dctlConversationNodeResponse, type R5dctlConversationOverviewResponse, type R5dctlConversationWorkDetail, type R5dctlConversationWorkResponse, type R5dctlEnvData, type R5dctlK8sResourceHistory, type R5dctlK8sUsage, type R5dctlK8sWorkload, type R5dctlProcessInspection, type R5dctlProcessListInput, type R5dctlProcessLog, type R5dctlProcessRun, type R5dctlSessionEvent, type R5dctlSessionStartInput, type R5dctlWorkspaceStatus, type R5dctlWorkspaceSyncResult, type R5dctlWorkingTreeMode, type R5dctlWorktreeSource, type R5dctlSessionMode, type ChatMode, type ModelTier } from "@ricsam/r5d-api";
|
|
2
2
|
export type GlobalOptions = {
|
|
3
3
|
baseUrl?: string;
|
|
4
4
|
json: boolean;
|
|
@@ -53,14 +53,17 @@ type R5dctlSessionStartCommand = {
|
|
|
53
53
|
prompt: string;
|
|
54
54
|
follow: boolean;
|
|
55
55
|
includeTools: boolean;
|
|
56
|
+
parentSessionId?: string;
|
|
56
57
|
} & ({
|
|
57
58
|
worktree: string;
|
|
58
59
|
newWorktree?: never;
|
|
59
60
|
source?: never;
|
|
61
|
+
workingTree?: never;
|
|
60
62
|
} | {
|
|
61
63
|
worktree?: never;
|
|
62
64
|
newWorktree: string;
|
|
63
65
|
source: R5dctlWorktreeSource;
|
|
66
|
+
workingTree: R5dctlWorkingTreeMode;
|
|
64
67
|
});
|
|
65
68
|
export type R5dctlSessionRunCommand = R5dctlSessionStartCommand | {
|
|
66
69
|
kind: "status";
|
|
@@ -77,6 +80,12 @@ export type R5dctlSessionRunCommand = R5dctlSessionStartCommand | {
|
|
|
77
80
|
sessionId: string;
|
|
78
81
|
};
|
|
79
82
|
export declare function parseSessionRunCommand(options: Pick<GlobalOptions, "project" | "branch" | "session">, args: string[]): R5dctlSessionRunCommand;
|
|
83
|
+
export type R5dctlSessionProcessLogArgs = {
|
|
84
|
+
runId: string;
|
|
85
|
+
tail?: number;
|
|
86
|
+
grep?: string;
|
|
87
|
+
};
|
|
88
|
+
export declare function parseSessionProcessLogArgs(args: string[]): R5dctlSessionProcessLogArgs;
|
|
80
89
|
export declare function parseGlobalArgs(argv: string[]): {
|
|
81
90
|
options: GlobalOptions;
|
|
82
91
|
rest: string[];
|
|
@@ -176,6 +185,11 @@ export declare function renderK8sUsageReport(report: K8sUsageReport): string;
|
|
|
176
185
|
export declare function formatProcessAge(startedAt: string, nowMs?: number): string;
|
|
177
186
|
export declare function renderProcessList(processes: R5dctlProcessRun[], nowMs?: number): string;
|
|
178
187
|
export declare function renderProcessHistory(processes: R5dctlProcessRun[], nowMs?: number): string;
|
|
188
|
+
/** Streams go to stdout under `==> name <==` headers; the selection summary is returned separately for stderr. */
|
|
189
|
+
export declare function renderProcessLog(log: R5dctlProcessLog): {
|
|
190
|
+
text: string;
|
|
191
|
+
summary: string;
|
|
192
|
+
};
|
|
179
193
|
export declare function renderProcessInspection(process: R5dctlProcessInspection): string;
|
|
180
194
|
export type EnvSummaryData = Record<string, {
|
|
181
195
|
description: string;
|
|
@@ -191,11 +205,19 @@ export type R5dctlCommandResponse = {
|
|
|
191
205
|
sessionId?: string;
|
|
192
206
|
sessionUrl?: string;
|
|
193
207
|
branchName?: string;
|
|
208
|
+
/** Launch-time worktree origin of a new-worktree run; absent or null on an existing worktree. */
|
|
209
|
+
sourceBranch?: string | null;
|
|
210
|
+
workingTree?: string | null;
|
|
211
|
+
/** Launch-time hashes: present in --json output but never rendered. */
|
|
194
212
|
baselineCommit?: string | null;
|
|
195
213
|
workspaceHead?: string | null;
|
|
196
214
|
worker?: string;
|
|
197
215
|
status?: string;
|
|
198
216
|
runStatus?: unknown;
|
|
217
|
+
/** Worker queue state while a new worktree provisions; older servers and workers omit it. */
|
|
218
|
+
provisioningQueuePosition?: number;
|
|
219
|
+
provisioningQueuedAt?: string;
|
|
220
|
+
/** Legacy fields older servers still send; never rendered because a reported hash goes stale. */
|
|
199
221
|
headCommit?: string | null;
|
|
200
222
|
headCommitError?: string;
|
|
201
223
|
promptDisposition?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ricsam/r5dctl",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.103",
|
|
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.103",
|
|
30
30
|
"dotenv": "^17",
|
|
31
31
|
"qrcode": "^1.5.4",
|
|
32
32
|
"ws": "^8.18.3"
|