@ricsam/r5dctl 0.0.122 → 0.0.123

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
@@ -155,7 +155,9 @@ Add `-f`/`--follow`/`--watch` to `session start` to poll the provisioning handle
155
155
 
156
156
  `shell` connects to the same live worker PTY as the web Shell tab. Without `-c` it attaches the local terminal interactively. With `-c`/`--command`, it runs the supplied shell expression, streams combined PTY output, and exits with the remote command's status. Because command output uses a PTY, stdout and stderr are combined and programs may emit colors or other terminal control sequences.
157
157
 
158
- `ps list` shows active long-running commands managed by r5d. It does not expose the worker host's general OS process table or interactive PTYs. Global project, branch, and session options filter the list, while `--worker` selects a worker label. `ps stop` sends `SIGTERM` to the selected run. Inside an r5d-provided worker shell, the temporary credential can only list and stop runs on that shell's worker.
158
+ `ps list` shows active long-running commands managed by r5d. It does not expose the worker host's general OS process table or interactive PTYs. Global project, branch, and session options filter the list, while `--worker` selects a worker label. The `LANE` column names the worker command lane each run holds (`general`, `utility`, or `control`) or waits for (`queued:general`), from the worker's latest capacity report; `-` means the worker did not report the run. `ps stop` sends `SIGTERM` to the selected run. Inside an r5d-provided worker shell, the temporary credential can only list and stop runs on that shell's worker.
159
+
160
+ A managed worker runs two general shells at a time; a third waits up to 60 seconds and then fails with "command capacity is busy". Coordination does not compete for those slots: when an agent shell runs one plain `r5dctl` coordination command (`ps list`, `ps stop`, `workspace status`, `session status|stop|prompt|claim|claims|process-log`, `describe …`, `get …`, `sessions recent`, the `conversation` read forms, `create|update|delete session`, `answer-questions`, `answer-env-request`) with plain or simply quoted arguments, the platform runs it in a reserved control lane: two small slots, no shell, a 120-second limit. Shell operators, pipes, redirections, `$` expansions, environment assignments, wrappers, paths to r5dctl, `--`, `--follow`, and credential or endpoint flags make it an ordinary shell command again. `workspace status` prints each worker's lane totals, holders, and queue.
159
161
 
160
162
  `k8s usage` shows current and rolling CPU and memory usage for every workload container in your managed vCluster. The default window is `24h`; pass `--window 7d` for seven days. Filter with `--namespace`, `--workload`, or `--container`; a workload may be identified by name, `namespace/name`, or Kubernetes UID. Human-readable output shows current totals across sampled replicas and the selected window's maximum. Global `--json` includes min/max summaries, the complete five-minute history envelope, per-pod series, coverage, and freshness metadata.
161
163
 
package/dist/cjs/cli.cjs CHANGED
@@ -43,6 +43,7 @@ __export(cli_exports, {
43
43
  formatK8sCpu: () => formatK8sCpu,
44
44
  formatK8sMemory: () => formatK8sMemory,
45
45
  formatProcessAge: () => formatProcessAge,
46
+ formatProcessLane: () => formatProcessLane,
46
47
  getCliHelpText: () => getCliHelpText,
47
48
  getK8sUsageState: () => getK8sUsageState,
48
49
  getProjectEnvValue: () => getProjectEnvValue,
@@ -100,6 +101,7 @@ __export(cli_exports, {
100
101
  renderSessionList: () => renderSessionList,
101
102
  renderSessionRunStart: () => renderSessionRunStart,
102
103
  renderSessionRunStatus: () => renderSessionRunStatus,
104
+ renderWorkerCapacity: () => renderWorkerCapacity,
103
105
  renderWorkspaceStatus: () => renderWorkspaceStatus,
104
106
  renderWorkspaceSync: () => renderWorkspaceSync,
105
107
  resolveCommandExecution: () => resolveCommandExecution,
@@ -1890,6 +1892,23 @@ function renderRecentSessionList(sessions) {
1890
1892
  return `${sessions.map((session) => `${session.id} ${session.projectPath}/${session.branchName} ${session.name ?? "(unnamed)"}`).join("\n")}
1891
1893
  `;
1892
1894
  }
1895
+ function renderWorkerCapacity(workerLabel, capacity) {
1896
+ if (!capacity) return [`Command capacity on ${workerLabel}: not reported yet`];
1897
+ if (!capacity.bounded) return [`Command capacity on ${workerLabel}: unbounded (no managed launcher)`];
1898
+ const describeLane = (lane) => {
1899
+ const report = capacity.lanes[lane];
1900
+ const slots = report.slots === null ? "?" : String(report.slots);
1901
+ const holders = report.active.map((entry) => `${entry.id}${entry.sessionId ? ` (session ${entry.sessionId})` : ""}`);
1902
+ const queued = report.queued.map((entry) => `${entry.id}${entry.sessionId ? ` (session ${entry.sessionId})` : ""}`);
1903
+ return ` ${lane}: ${report.active.length}/${slots} busy${holders.length ? `, held by ${holders.join(", ")}` : ""}${queued.length ? `; queued: ${queued.join(", ")}` : ""}`;
1904
+ };
1905
+ return [
1906
+ `Command capacity on ${workerLabel} (reported ${capacity.reportedAt}):`,
1907
+ describeLane("general"),
1908
+ describeLane("utility"),
1909
+ `${describeLane("control")}${capacity.controlRuntimeMs !== null ? ` (plain r5dctl coordination, ${Math.round(capacity.controlRuntimeMs / 1e3)}s limit)` : ""}`
1910
+ ];
1911
+ }
1893
1912
  function renderWorkspaceStatus(status) {
1894
1913
  const lines = [
1895
1914
  `Workspace HEAD: ${status.head ?? "(not initialized)"}`,
@@ -1897,7 +1916,8 @@ function renderWorkspaceStatus(status) {
1897
1916
  `Remediation: ${status.incident ? `${status.incident.kind} ${status.incident.status} (${status.incident.id}) on ${status.incident.originWorkerLabel}` : "none"}`,
1898
1917
  ...status.workers.flatMap((worker) => [
1899
1918
  `Worker ${worker.workerLabel}: ${worker.configured ? "configured" : "configuring"}; head ${worker.localHead ?? "(none)"}; pending checkouts ${worker.pendingCheckouts.length}`,
1900
- ...renderMissingCheckouts(worker.workerLabel, worker.missingCheckouts ?? [])
1919
+ ...renderMissingCheckouts(worker.workerLabel, worker.missingCheckouts ?? []),
1920
+ ...renderWorkerCapacity(worker.workerLabel, worker.capacity)
1901
1921
  ])
1902
1922
  ];
1903
1923
  if (status.latestSync?.missingCheckouts?.length && !status.workers.some((worker) => worker.missingCheckouts?.length)) {
@@ -2131,10 +2151,11 @@ function renderProcessList(processes, nowMs = Date.now()) {
2131
2151
  if (processes.length === 0) {
2132
2152
  return "No active processes.\n";
2133
2153
  }
2134
- const headers = ["RUN ID", "STATUS", "AGE", "WORKER", "TARGET", "SCOPE", "SESSION", "COMMAND"];
2154
+ const headers = ["RUN ID", "STATUS", "LANE", "AGE", "WORKER", "TARGET", "SCOPE", "SESSION", "COMMAND"];
2135
2155
  const rows = processes.map((process2) => [
2136
2156
  process2.runId,
2137
2157
  process2.status,
2158
+ formatProcessLane(process2),
2138
2159
  formatProcessAge(process2.startedAt, nowMs),
2139
2160
  process2.workerLabel,
2140
2161
  process2.projectPath,
@@ -2148,6 +2169,10 @@ function renderProcessList(processes, nowMs = Date.now()) {
2148
2169
  return `${[formatRow(headers), separator, ...rows.map(formatRow)].join("\n")}
2149
2170
  `;
2150
2171
  }
2172
+ function formatProcessLane(process2) {
2173
+ if (process2.admission) return process2.admission.phase === "queued" ? `queued:${process2.admission.lane}` : process2.admission.lane;
2174
+ return process2.commandClass ?? "-";
2175
+ }
2151
2176
  function renderProcessHistory(processes, nowMs = Date.now()) {
2152
2177
  return processes.length === 0 ? "No process history.\n" : renderProcessList(processes, nowMs);
2153
2178
  }
@@ -2185,6 +2210,7 @@ function renderProcessInspection(process2) {
2185
2210
  `Worker: ${process2.workerLabel} (${process2.platform ?? "unknown"}/${process2.arch ?? "unknown"})`,
2186
2211
  `Target: ${process2.projectPath} ${process2.target.type === "project" ? process2.target.branchName : process2.target.rootProfile}`,
2187
2212
  `Session: ${process2.sessionId}`,
2213
+ `Lane: ${formatProcessLane(process2)}${process2.admission ? ` since ${process2.admission.since}` : ""}`,
2188
2214
  `Command: ${process2.command}`,
2189
2215
  `Argv: ${JSON.stringify(process2.argv)}`,
2190
2216
  `CWD: ${process2.cwd ?? "(execution root)"}`,
@@ -4046,6 +4072,7 @@ async function main(argv = process.argv.slice(2)) {
4046
4072
  formatK8sCpu,
4047
4073
  formatK8sMemory,
4048
4074
  formatProcessAge,
4075
+ formatProcessLane,
4049
4076
  getCliHelpText,
4050
4077
  getK8sUsageState,
4051
4078
  getProjectEnvValue,
@@ -4103,6 +4130,7 @@ async function main(argv = process.argv.slice(2)) {
4103
4130
  renderSessionList,
4104
4131
  renderSessionRunStart,
4105
4132
  renderSessionRunStatus,
4133
+ renderWorkerCapacity,
4106
4134
  renderWorkspaceStatus,
4107
4135
  renderWorkspaceSync,
4108
4136
  resolveCommandExecution,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.122",
3
+ "version": "0.0.123",
4
4
  "type": "commonjs"
5
5
  }
package/dist/mjs/cli.mjs CHANGED
@@ -1781,6 +1781,23 @@ function renderRecentSessionList(sessions) {
1781
1781
  return `${sessions.map((session) => `${session.id} ${session.projectPath}/${session.branchName} ${session.name ?? "(unnamed)"}`).join("\n")}
1782
1782
  `;
1783
1783
  }
1784
+ function renderWorkerCapacity(workerLabel, capacity) {
1785
+ if (!capacity) return [`Command capacity on ${workerLabel}: not reported yet`];
1786
+ if (!capacity.bounded) return [`Command capacity on ${workerLabel}: unbounded (no managed launcher)`];
1787
+ const describeLane = (lane) => {
1788
+ const report = capacity.lanes[lane];
1789
+ const slots = report.slots === null ? "?" : String(report.slots);
1790
+ const holders = report.active.map((entry) => `${entry.id}${entry.sessionId ? ` (session ${entry.sessionId})` : ""}`);
1791
+ const queued = report.queued.map((entry) => `${entry.id}${entry.sessionId ? ` (session ${entry.sessionId})` : ""}`);
1792
+ return ` ${lane}: ${report.active.length}/${slots} busy${holders.length ? `, held by ${holders.join(", ")}` : ""}${queued.length ? `; queued: ${queued.join(", ")}` : ""}`;
1793
+ };
1794
+ return [
1795
+ `Command capacity on ${workerLabel} (reported ${capacity.reportedAt}):`,
1796
+ describeLane("general"),
1797
+ describeLane("utility"),
1798
+ `${describeLane("control")}${capacity.controlRuntimeMs !== null ? ` (plain r5dctl coordination, ${Math.round(capacity.controlRuntimeMs / 1e3)}s limit)` : ""}`
1799
+ ];
1800
+ }
1784
1801
  function renderWorkspaceStatus(status) {
1785
1802
  const lines = [
1786
1803
  `Workspace HEAD: ${status.head ?? "(not initialized)"}`,
@@ -1788,7 +1805,8 @@ function renderWorkspaceStatus(status) {
1788
1805
  `Remediation: ${status.incident ? `${status.incident.kind} ${status.incident.status} (${status.incident.id}) on ${status.incident.originWorkerLabel}` : "none"}`,
1789
1806
  ...status.workers.flatMap((worker) => [
1790
1807
  `Worker ${worker.workerLabel}: ${worker.configured ? "configured" : "configuring"}; head ${worker.localHead ?? "(none)"}; pending checkouts ${worker.pendingCheckouts.length}`,
1791
- ...renderMissingCheckouts(worker.workerLabel, worker.missingCheckouts ?? [])
1808
+ ...renderMissingCheckouts(worker.workerLabel, worker.missingCheckouts ?? []),
1809
+ ...renderWorkerCapacity(worker.workerLabel, worker.capacity)
1792
1810
  ])
1793
1811
  ];
1794
1812
  if (status.latestSync?.missingCheckouts?.length && !status.workers.some((worker) => worker.missingCheckouts?.length)) {
@@ -2022,10 +2040,11 @@ function renderProcessList(processes, nowMs = Date.now()) {
2022
2040
  if (processes.length === 0) {
2023
2041
  return "No active processes.\n";
2024
2042
  }
2025
- const headers = ["RUN ID", "STATUS", "AGE", "WORKER", "TARGET", "SCOPE", "SESSION", "COMMAND"];
2043
+ const headers = ["RUN ID", "STATUS", "LANE", "AGE", "WORKER", "TARGET", "SCOPE", "SESSION", "COMMAND"];
2026
2044
  const rows = processes.map((process2) => [
2027
2045
  process2.runId,
2028
2046
  process2.status,
2047
+ formatProcessLane(process2),
2029
2048
  formatProcessAge(process2.startedAt, nowMs),
2030
2049
  process2.workerLabel,
2031
2050
  process2.projectPath,
@@ -2039,6 +2058,10 @@ function renderProcessList(processes, nowMs = Date.now()) {
2039
2058
  return `${[formatRow(headers), separator, ...rows.map(formatRow)].join("\n")}
2040
2059
  `;
2041
2060
  }
2061
+ function formatProcessLane(process2) {
2062
+ if (process2.admission) return process2.admission.phase === "queued" ? `queued:${process2.admission.lane}` : process2.admission.lane;
2063
+ return process2.commandClass ?? "-";
2064
+ }
2042
2065
  function renderProcessHistory(processes, nowMs = Date.now()) {
2043
2066
  return processes.length === 0 ? "No process history.\n" : renderProcessList(processes, nowMs);
2044
2067
  }
@@ -2076,6 +2099,7 @@ function renderProcessInspection(process2) {
2076
2099
  `Worker: ${process2.workerLabel} (${process2.platform ?? "unknown"}/${process2.arch ?? "unknown"})`,
2077
2100
  `Target: ${process2.projectPath} ${process2.target.type === "project" ? process2.target.branchName : process2.target.rootProfile}`,
2078
2101
  `Session: ${process2.sessionId}`,
2102
+ `Lane: ${formatProcessLane(process2)}${process2.admission ? ` since ${process2.admission.since}` : ""}`,
2079
2103
  `Command: ${process2.command}`,
2080
2104
  `Argv: ${JSON.stringify(process2.argv)}`,
2081
2105
  `CWD: ${process2.cwd ?? "(execution root)"}`,
@@ -3936,6 +3960,7 @@ export {
3936
3960
  formatK8sCpu,
3937
3961
  formatK8sMemory,
3938
3962
  formatProcessAge,
3963
+ formatProcessLane,
3939
3964
  getCliHelpText,
3940
3965
  getK8sUsageState,
3941
3966
  getProjectEnvValue,
@@ -3993,6 +4018,7 @@ export {
3993
4018
  renderSessionList,
3994
4019
  renderSessionRunStart,
3995
4020
  renderSessionRunStatus,
4021
+ renderWorkerCapacity,
3996
4022
  renderWorkspaceStatus,
3997
4023
  renderWorkspaceSync,
3998
4024
  resolveCommandExecution,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.122",
3
+ "version": "0.0.123",
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 R5dctlBranchDeletionStatus, type R5dctlBranchDescription, type R5dctlBranchOperation, type R5dctlSessionSummary, type R5dctlSessionClaim, type R5dctlSessionClaimListResponse, type R5dctlSessionEvent, type R5dctlSessionStartInput, type R5dctlWorkspaceStatus, type R5dctlWorkspaceSyncResult, type R5dctlWorkingTreeMode, type R5dctlWorktreeSource, type R5dctlPromptDelivery, 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 R5dctlWorkerCapacityReport, type R5dctlBranch, type R5dctlBranchDeletionStatus, type R5dctlBranchDescription, type R5dctlBranchOperation, type R5dctlSessionSummary, type R5dctlSessionClaim, type R5dctlSessionClaimListResponse, type R5dctlSessionEvent, type R5dctlSessionStartInput, type R5dctlWorkspaceStatus, type R5dctlWorkspaceSyncResult, type R5dctlWorkingTreeMode, type R5dctlWorktreeSource, type R5dctlPromptDelivery, type R5dctlSessionMode, type ChatMode, type ModelTier } from "@ricsam/r5d-api";
2
2
  export type GlobalOptions = {
3
3
  baseUrl?: string;
4
4
  json: boolean;
@@ -278,6 +278,8 @@ export declare function advanceTransientDevicePollBackoff(intervalMs: number, tr
278
278
  };
279
279
  export declare function handleAuthLogin(client: R5dctlClient, options: GlobalOptions, commandArgs: string[], config: R5dctlConfig): Promise<void>;
280
280
  export declare function renderSessionList(sessions: R5dctlSessionSummary[], nowMs?: number): string;
281
+ /** One line per worker naming every lane's holders and queue, so an agent can see whom to ask to free capacity. */
282
+ export declare function renderWorkerCapacity(workerLabel: string, capacity: R5dctlWorkerCapacityReport | null | undefined): string[];
281
283
  export declare function renderWorkspaceStatus(status: R5dctlWorkspaceStatus): string;
282
284
  export declare function renderBranchList(branches: R5dctlBranch[]): string;
283
285
  export declare function renderWorkspaceSync(result: R5dctlWorkspaceSyncResult): string;
@@ -318,6 +320,8 @@ export declare function getK8sUsageState(entry: K8sUsageReport["entries"][number
318
320
  export declare function renderK8sUsageReport(report: K8sUsageReport): string;
319
321
  export declare function formatProcessAge(startedAt: string, nowMs?: number): string;
320
322
  export declare function renderProcessList(processes: R5dctlProcessRun[], nowMs?: number): string;
323
+ /** `general`, `control`, `queued:general`, or `-` when the worker reported nothing for this run. */
324
+ export declare function formatProcessLane(process: Pick<R5dctlProcessRun, "admission" | "commandClass">): string;
321
325
  export declare function renderProcessHistory(processes: R5dctlProcessRun[], nowMs?: number): string;
322
326
  /** Streams go to stdout under `==> name <==` headers; the selection summary is returned separately for stderr. */
323
327
  export declare function renderProcessLog(log: R5dctlProcessLog): {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.122",
3
+ "version": "0.0.123",
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.122",
29
+ "@ricsam/r5d-api": "^0.0.123",
30
30
  "dotenv": "^17",
31
31
  "qrcode": "^1.5.4",
32
32
  "ws": "^8.18.3"