@ricsam/r5dctl 0.0.105 → 0.0.106

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 CHANGED
@@ -64,7 +64,7 @@ r5dctl -p <project> get envs --show-values
64
64
  r5dctl -p <project> get env API_KEY
65
65
  r5dctl -p <project> set envs --from-env-file ~/.env --only-missing
66
66
  r5dctl -p <project> set envs -e API_KEY=value --description "API credential"
67
- r5dctl -p <project> get sessions --branch <branch>
67
+ r5dctl -p <project> get sessions --branch <branch> # each session's live state and last activity
68
68
  r5dctl -p <project> create session -b <branch> --name "Spec session"
69
69
  r5dctl describe session <session-id>
70
70
  r5dctl -s <session-id> update session --name "Renamed session"
@@ -131,6 +131,10 @@ pull requests.
131
131
 
132
132
  `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.
133
133
 
134
+ `get sessions` lists a project's sessions, newest first, and appends each session's live state (`running`, `stopping`, `paused`, `provisioning`, `queued`, or `idle`) and how long ago its conversation last advanced (`running, last active 12s ago`). Several sessions can work in the same branch checkout at once (task chips, shared-mode sub-agents, sessions the user starts), so run it with `--branch` before relying on a working tree or reviewing what changed in it. A server that predates the fields prints the id, branch, and name only.
135
+
136
+ `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.
137
+
134
138
  `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.
135
139
 
136
140
  `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
@@ -89,6 +89,7 @@ __export(cli_exports, {
89
89
  renderProcessInspection: () => renderProcessInspection,
90
90
  renderProcessList: () => renderProcessList,
91
91
  renderProcessLog: () => renderProcessLog,
92
+ renderSessionList: () => renderSessionList,
92
93
  renderSessionRunStart: () => renderSessionRunStart,
93
94
  renderSessionRunStatus: () => renderSessionRunStatus,
94
95
  renderWorkspaceStatus: () => renderWorkspaceStatus,
@@ -1635,11 +1636,15 @@ function renderProjectList(projects) {
1635
1636
  Mode: ${project.mode}`).join("\n\n")}
1636
1637
  `;
1637
1638
  }
1638
- function renderSessionList(sessions) {
1639
+ function formatSessionActivity(session, nowMs) {
1640
+ if (!session.runState) return void 0;
1641
+ return session.lastActivityAt ? `${session.runState}, last active ${formatProcessAge(session.lastActivityAt, nowMs)} ago` : session.runState;
1642
+ }
1643
+ function renderSessionList(sessions, nowMs = Date.now()) {
1639
1644
  if (sessions.length === 0) {
1640
1645
  return "No sessions found.\n";
1641
1646
  }
1642
- return `${sessions.map((session) => `${session.id} ${session.branchName} ${session.name ?? "(unnamed)"}`).join("\n")}
1647
+ return `${sessions.map((session) => [session.id, session.branchName, formatSessionActivity(session, nowMs), session.name ?? "(unnamed)"].filter(Boolean).join(" ")).join("\n")}
1643
1648
  `;
1644
1649
  }
1645
1650
  function renderRecentSessionList(sessions) {
@@ -2130,6 +2135,13 @@ function formatProvisioningQueueLine(session) {
2130
2135
  if (position === 0) return `Provisioning: worker started the branch operation at ${since}`;
2131
2136
  return `Provisioning: queued behind ${position} worker operation${position === 1 ? "" : "s"} since ${since}`;
2132
2137
  }
2138
+ function formatChildSessionsLine(session) {
2139
+ const children = session.childSessions;
2140
+ if (!children || typeof children !== "object") return void 0;
2141
+ const { total, active } = children;
2142
+ if (!Number.isInteger(total) || !Number.isInteger(active) || total <= 0 || active < 0) return void 0;
2143
+ return `Child sessions: ${active} active of ${total}`;
2144
+ }
2133
2145
  function renderSessionRunStatus(session) {
2134
2146
  const status = formatStatusValue(session.status) ?? "unknown";
2135
2147
  const lines = [`Session: ${responseString(session, "sessionId") ?? "(unknown)"}`, `Status: ${status}`];
@@ -2150,6 +2162,8 @@ function renderSessionRunStatus(session) {
2150
2162
  const value = responseString(session, key);
2151
2163
  if (value) lines.push(`${label}: ${value}`);
2152
2164
  }
2165
+ const childSessions = formatChildSessionsLine(session);
2166
+ if (childSessions) lines.push(childSessions);
2153
2167
  lines.push(`Branch state: ${formatBranchStateHint(branch)}`);
2154
2168
  const error = responseString(session, "error");
2155
2169
  if (error) lines.push(`Error: ${error}`);
@@ -3742,6 +3756,7 @@ async function main(argv = process.argv.slice(2)) {
3742
3756
  renderProcessInspection,
3743
3757
  renderProcessList,
3744
3758
  renderProcessLog,
3759
+ renderSessionList,
3745
3760
  renderSessionRunStart,
3746
3761
  renderSessionRunStatus,
3747
3762
  renderWorkspaceStatus,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.105",
3
+ "version": "0.0.106",
4
4
  "type": "commonjs"
5
5
  }
package/dist/mjs/cli.mjs CHANGED
@@ -1536,11 +1536,15 @@ function renderProjectList(projects) {
1536
1536
  Mode: ${project.mode}`).join("\n\n")}
1537
1537
  `;
1538
1538
  }
1539
- function renderSessionList(sessions) {
1539
+ function formatSessionActivity(session, nowMs) {
1540
+ if (!session.runState) return void 0;
1541
+ return session.lastActivityAt ? `${session.runState}, last active ${formatProcessAge(session.lastActivityAt, nowMs)} ago` : session.runState;
1542
+ }
1543
+ function renderSessionList(sessions, nowMs = Date.now()) {
1540
1544
  if (sessions.length === 0) {
1541
1545
  return "No sessions found.\n";
1542
1546
  }
1543
- return `${sessions.map((session) => `${session.id} ${session.branchName} ${session.name ?? "(unnamed)"}`).join("\n")}
1547
+ return `${sessions.map((session) => [session.id, session.branchName, formatSessionActivity(session, nowMs), session.name ?? "(unnamed)"].filter(Boolean).join(" ")).join("\n")}
1544
1548
  `;
1545
1549
  }
1546
1550
  function renderRecentSessionList(sessions) {
@@ -2031,6 +2035,13 @@ function formatProvisioningQueueLine(session) {
2031
2035
  if (position === 0) return `Provisioning: worker started the branch operation at ${since}`;
2032
2036
  return `Provisioning: queued behind ${position} worker operation${position === 1 ? "" : "s"} since ${since}`;
2033
2037
  }
2038
+ function formatChildSessionsLine(session) {
2039
+ const children = session.childSessions;
2040
+ if (!children || typeof children !== "object") return void 0;
2041
+ const { total, active } = children;
2042
+ if (!Number.isInteger(total) || !Number.isInteger(active) || total <= 0 || active < 0) return void 0;
2043
+ return `Child sessions: ${active} active of ${total}`;
2044
+ }
2034
2045
  function renderSessionRunStatus(session) {
2035
2046
  const status = formatStatusValue(session.status) ?? "unknown";
2036
2047
  const lines = [`Session: ${responseString(session, "sessionId") ?? "(unknown)"}`, `Status: ${status}`];
@@ -2051,6 +2062,8 @@ function renderSessionRunStatus(session) {
2051
2062
  const value = responseString(session, key);
2052
2063
  if (value) lines.push(`${label}: ${value}`);
2053
2064
  }
2065
+ const childSessions = formatChildSessionsLine(session);
2066
+ if (childSessions) lines.push(childSessions);
2054
2067
  lines.push(`Branch state: ${formatBranchStateHint(branch)}`);
2055
2068
  const error = responseString(session, "error");
2056
2069
  if (error) lines.push(`Error: ${error}`);
@@ -3642,6 +3655,7 @@ export {
3642
3655
  renderProcessInspection,
3643
3656
  renderProcessList,
3644
3657
  renderProcessLog,
3658
+ renderSessionList,
3645
3659
  renderSessionRunStart,
3646
3660
  renderSessionRunStatus,
3647
3661
  renderWorkspaceStatus,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.105",
3
+ "version": "0.0.106",
4
4
  "type": "module"
5
5
  }
@@ -1,4 +1,4 @@
1
- import { R5dctlApiError, 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 R5dctlBranch, type R5dctlBranchDeleteResponse, type R5dctlBranchDescription, type R5dctlBranchOperation, type R5dctlSessionEvent, type R5dctlSessionStartInput, type R5dctlWorkspaceStatus, type R5dctlWorkspaceSyncResult, type R5dctlWorkingTreeMode, type R5dctlWorktreeSource, type R5dctlSessionMode, type ChatMode, type ModelTier } from "@ricsam/r5d-api";
1
+ import { R5dctlApiError, 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 R5dctlBranch, type R5dctlBranchDeleteResponse, type R5dctlBranchDescription, type R5dctlBranchOperation, type R5dctlSessionSummary, 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;
@@ -204,6 +204,7 @@ export declare function advanceTransientDevicePollBackoff(intervalMs: number, tr
204
204
  nextBackoffMs: number;
205
205
  };
206
206
  export declare function handleAuthLogin(client: R5dctlClient, options: GlobalOptions, commandArgs: string[], config: R5dctlConfig): Promise<void>;
207
+ export declare function renderSessionList(sessions: R5dctlSessionSummary[], nowMs?: number): string;
207
208
  export declare function renderWorkspaceStatus(status: R5dctlWorkspaceStatus): string;
208
209
  export declare function renderBranchList(branches: R5dctlBranch[]): string;
209
210
  export declare function renderWorkspaceSync(result: R5dctlWorkspaceSyncResult): string;
@@ -284,6 +285,11 @@ export type R5dctlCommandResponse = {
284
285
  error?: string;
285
286
  summary?: string;
286
287
  diffSummary?: string;
288
+ /** Sub-agent sessions this session launched; older servers omit it. */
289
+ childSessions?: {
290
+ total: number;
291
+ active: number;
292
+ };
287
293
  };
288
294
  export type R5dctlSessionRunClient = {
289
295
  projects: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.105",
3
+ "version": "0.0.106",
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.105",
29
+ "@ricsam/r5d-api": "^0.0.106",
30
30
  "dotenv": "^17",
31
31
  "qrcode": "^1.5.4",
32
32
  "ws": "^8.18.3"