@ricsam/r5dctl 0.0.126 → 0.0.128

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/cli.cjs CHANGED
@@ -34,18 +34,14 @@ __export(cli_exports, {
34
34
  branchDeletionConfirmationMessage: () => branchDeletionConfirmationMessage,
35
35
  branchDeletionsConfirmationMessage: () => branchDeletionsConfirmationMessage,
36
36
  branchDeletionsFailureMessage: () => branchDeletionsFailureMessage,
37
- collectK8sUsage: () => collectK8sUsage,
38
37
  createBranchThroughPlatform: () => createBranchThroughPlatform,
39
38
  deleteBranchThroughPlatform: () => deleteBranchThroughPlatform,
40
39
  deleteBranchesThroughPlatform: () => deleteBranchesThroughPlatform,
41
40
  dispatchSessionRunCommand: () => dispatchSessionRunCommand,
42
41
  followR5dctlSession: () => followR5dctlSession,
43
- formatK8sCpu: () => formatK8sCpu,
44
- formatK8sMemory: () => formatK8sMemory,
45
42
  formatProcessAge: () => formatProcessAge,
46
43
  formatProcessLane: () => formatProcessLane,
47
44
  getCliHelpText: () => getCliHelpText,
48
- getK8sUsageState: () => getK8sUsageState,
49
45
  getProjectEnvValue: () => getProjectEnvValue,
50
46
  getR5dctlVersion: () => getR5dctlVersion,
51
47
  getTransientDevicePollDelay: () => getTransientDevicePollDelay,
@@ -66,7 +62,6 @@ __export(cli_exports, {
66
62
  parseEnvRequestResponseArgs: () => parseEnvRequestResponseArgs,
67
63
  parseGetEnvsArgs: () => parseGetEnvsArgs,
68
64
  parseGlobalArgs: () => parseGlobalArgs,
69
- parseK8sUsageArgs: () => parseK8sUsageArgs,
70
65
  parsePromptArgs: () => parsePromptArgs,
71
66
  parsePsHistoryArgs: () => parsePsHistoryArgs,
72
67
  parsePsListArgs: () => parsePsListArgs,
@@ -91,7 +86,6 @@ __export(cli_exports, {
91
86
  renderConversationWorkResponse: () => renderConversationWorkResponse,
92
87
  renderDeviceAuthorizationPrompt: () => renderDeviceAuthorizationPrompt,
93
88
  renderEnvValues: () => renderEnvValues,
94
- renderK8sUsageReport: () => renderK8sUsageReport,
95
89
  renderProcessHistory: () => renderProcessHistory,
96
90
  renderProcessInspection: () => renderProcessInspection,
97
91
  renderProcessList: () => renderProcessList,
@@ -122,6 +116,7 @@ var import_promises = require("node:timers/promises");
122
116
  var import_dotenv = require("dotenv");
123
117
  var import_r5d_api = require("@ricsam/r5d-api");
124
118
  var import_shell = require("./shell.cjs");
119
+ var import_account = require("./account.cjs");
125
120
  const CHAT_MODES = /* @__PURE__ */ new Set(["plan", "agent", "large_diff_remediation"]);
126
121
  const R5DCTL_SESSION_MODES = /* @__PURE__ */ new Set(["plan", "agent"]);
127
122
  const R5DCTL_PROMPT_DELIVERIES = /* @__PURE__ */ new Set(["queue", "steer", "force"]);
@@ -169,20 +164,10 @@ const PS_HELP_TEXT = [
169
164
  " r5dctl ps inspect <run-id>",
170
165
  " r5dctl ps stop <run-id>",
171
166
  "",
172
- "List, inspect, or gracefully stop r5d-managed worker processes.",
167
+ "List, inspect, or gracefully stop agent processes on workers.",
173
168
  "Use -p/--project, -b/--branch, or -s/--session to filter list and history.",
174
169
  ""
175
170
  ].join("\n");
176
- const K8S_HELP_TEXT = [
177
- "Usage:",
178
- " r5dctl k8s usage [--namespace <name>] [--workload <name|namespace/name|uid>] [--container <name>] [--window <24h|7d>]",
179
- " r5dctl vcluster trusted-workflow add --repo <owner/repository> --workflow <.github/workflows/file.yml>",
180
- " r5dctl vcluster trusted-workflow list",
181
- " r5dctl vcluster trusted-workflow remove <workflow-id>",
182
- "",
183
- "Show current and rolling CPU and memory usage for managed-vCluster workload containers.",
184
- ""
185
- ].join("\n");
186
171
  const SESSION_RUN_HELP_TEXT = [
187
172
  "Usage:",
188
173
  ' r5dctl -p <project> session start --worker <label> --worktree <branch> --model <tier> [-f|--follow|--watch] [--tools] [--parent-session <session-id>] "<prompt>"',
@@ -215,6 +200,7 @@ const SESSION_RUN_HELP_TEXT = [
215
200
  ""
216
201
  ].join("\n");
217
202
  const SHARED_HELP_ENTRIES = [
203
+ ...import_account.ACCOUNT_HELP_ENTRIES.map((entry) => ({ ...entry, section: "account" })),
218
204
  { section: "auth", usage: "auth status", description: "Show the current authenticated user and credential source." },
219
205
  { section: "auth", usage: "auth logout", description: "Revoke the current credential and clear saved auth." },
220
206
  {
@@ -374,26 +360,10 @@ const SHARED_HELP_ENTRIES = [
374
360
  usage: "-s <session-id> answer-env-request --worker <label> --mode <mode> --model <tier> [-e KEY=value] [--context <text>]",
375
361
  description: "Answer a pending environment variable request with values, context, or both."
376
362
  },
377
- {
378
- section: "kubernetes",
379
- usage: "k8s usage [--namespace <name>] [--workload <name|namespace/name|uid>] [--container <name>] [--window <24h|7d>]",
380
- description: "Show current and rolling CPU and memory usage for managed-vCluster workload containers."
381
- },
382
- {
383
- section: "kubernetes",
384
- usage: "vcluster trusted-workflow add --repo <owner/repository> --workflow <.github/workflows/file.yml>",
385
- description: "Trust an exact GitHub Actions workflow path to authenticate kubectl against your managed vCluster."
386
- },
387
- { section: "kubernetes", usage: "vcluster trusted-workflow list", description: "List trusted GitHub Actions workflows." },
388
- {
389
- section: "kubernetes",
390
- usage: "vcluster trusted-workflow remove <workflow-id>",
391
- description: "Revoke a trusted GitHub Actions workflow and its outstanding credentials."
392
- },
393
363
  {
394
364
  section: "processes",
395
365
  usage: "ps list [--worker <label>]",
396
- description: "List active r5d-managed worker processes; global project, branch, and session filters apply."
366
+ description: "List active agent processes on workers; global project, branch, and session filters apply."
397
367
  },
398
368
  {
399
369
  section: "processes",
@@ -409,23 +379,23 @@ const SHARED_HELP_ENTRIES = [
409
379
  ];
410
380
  const HELP_SECTION_ORDER = [
411
381
  "auth",
382
+ "account",
412
383
  "workspace",
413
384
  "projects",
414
385
  "branches",
415
386
  "envs",
416
387
  "sessions",
417
- "kubernetes",
418
388
  "processes",
419
389
  "shell"
420
390
  ];
421
391
  const HELP_SECTION_TITLES = {
422
392
  auth: "Auth",
393
+ account: "Account instructions, environment variables, and secret files",
423
394
  workspace: "Canonical workspace",
424
395
  projects: "Projects",
425
396
  branches: "Branches",
426
397
  envs: "Environment variables",
427
398
  sessions: "Sessions",
428
- kubernetes: "Kubernetes",
429
399
  processes: "Processes",
430
400
  shell: "Shell"
431
401
  };
@@ -749,7 +719,10 @@ async function deleteBranchThroughPlatform(client, projectRef, branchName, optio
749
719
  const branchId = branch.branchId;
750
720
  let accepted;
751
721
  try {
752
- accepted = await requireServerRouteSupport("delete branch", () => client.projects.branches.delete(projectRef, branchName, { branchId }));
722
+ accepted = await requireServerRouteSupport(
723
+ "delete branch",
724
+ () => client.projects.branches.delete(projectRef, branchName, { branchId })
725
+ );
753
726
  } catch (error) {
754
727
  const landed = error instanceof import_r5d_api.R5dctlApiError ? await resolveUncertainAcceptance(client, projectRef, branchId, error) : null;
755
728
  if (!landed) throw error;
@@ -1090,12 +1063,31 @@ function parseGlobalArgs(argv) {
1090
1063
  version: false
1091
1064
  };
1092
1065
  const rest = [];
1066
+ const seenGlobalFlags = /* @__PURE__ */ new Set();
1067
+ let duplicateGlobalFlag;
1093
1068
  for (let i = 0; i < argv.length; i += 1) {
1094
1069
  const arg = argv[i];
1070
+ if (rest[0] === "account" && (arg === "--value" || arg === "--file" || arg === "--description")) {
1071
+ rest.push(arg);
1072
+ if (i + 1 < argv.length) rest.push(argv[++i]);
1073
+ continue;
1074
+ }
1075
+ if (rest[0] === "account" && arg === "") {
1076
+ rest.push(arg);
1077
+ continue;
1078
+ }
1095
1079
  if (!arg) {
1096
1080
  continue;
1097
1081
  }
1082
+ const globalName = { "-p": "--project", "-b": "--branch", "-s": "--session", "-h": "--help", "-v": "--version" }[arg] ?? arg.split("=", 1)[0];
1083
+ if (["--base-url", "--json", "--config", "--token", "--api-key", "--project", "--branch", "--session", "--help", "--version"].includes(
1084
+ globalName
1085
+ )) {
1086
+ if (seenGlobalFlags.has(globalName)) duplicateGlobalFlag ??= globalName;
1087
+ seenGlobalFlags.add(globalName);
1088
+ }
1098
1089
  if (arg === "--") {
1090
+ if (rest[0] === "account") rest.push(arg);
1099
1091
  rest.push(...argv.slice(i + 1));
1100
1092
  break;
1101
1093
  }
@@ -1176,6 +1168,7 @@ function parseGlobalArgs(argv) {
1176
1168
  }
1177
1169
  rest.push(arg);
1178
1170
  }
1171
+ if (rest[0] === "account" && duplicateGlobalFlag) throw new Error(`${duplicateGlobalFlag} may only be provided once`);
1179
1172
  return { options, rest };
1180
1173
  }
1181
1174
  function parseConfig(configPath) {
@@ -1664,36 +1657,6 @@ function parseRecentSessionArgs(args) {
1664
1657
  if (!Number.isInteger(limit) || limit < 1 || limit > 200) throw new Error("--limit must be an integer between 1 and 200");
1665
1658
  return { limit };
1666
1659
  }
1667
- function parseK8sUsageArgs(args) {
1668
- const parsed = { window: "24h" };
1669
- const seen = /* @__PURE__ */ new Set();
1670
- for (let index = 0; index < args.length; index += 1) {
1671
- const arg = args[index];
1672
- if (!arg) continue;
1673
- const option = ["--namespace", "--workload", "--container", "--window"].find(
1674
- (candidate) => arg === candidate || arg.startsWith(`${candidate}=`)
1675
- );
1676
- if (!option) throw new Error(`Unknown k8s usage argument: ${arg}`);
1677
- if (seen.has(option)) throw new Error(`Use ${option} only once`);
1678
- seen.add(option);
1679
- const inlineValue = parseLongOptionWithEquals(arg, option);
1680
- const candidateValue = inlineValue ?? args[index + 1];
1681
- if (!candidateValue || candidateValue.startsWith("--")) throw new Error(`Missing value for ${option}`);
1682
- const value = candidateValue;
1683
- if (inlineValue === void 0) index += 1;
1684
- if (option === "--window") {
1685
- if (value !== "24h" && value !== "7d") throw new Error("--window must be 24h or 7d");
1686
- parsed.window = value;
1687
- } else if (option === "--namespace") {
1688
- parsed.namespace = value;
1689
- } else if (option === "--workload") {
1690
- parsed.workload = value;
1691
- } else {
1692
- parsed.container = value;
1693
- }
1694
- }
1695
- return parsed;
1696
- }
1697
1660
  async function openInBrowser(url) {
1698
1661
  if (process.platform === "darwin") {
1699
1662
  (0, import_node_child_process.spawn)("open", [url], { stdio: "ignore", detached: true }).unref();
@@ -1884,7 +1847,9 @@ function renderSessionList(sessions, nowMs = Date.now()) {
1884
1847
  if (sessions.length === 0) {
1885
1848
  return "No sessions found.\n";
1886
1849
  }
1887
- return `${sessions.map((session) => [session.id, session.branchName, formatSessionActivity(session, nowMs), session.name ?? "(unnamed)"].filter(Boolean).join(" ")).join("\n")}
1850
+ return `${sessions.map(
1851
+ (session) => [session.id, session.branchName, formatSessionActivity(session, nowMs), session.name ?? "(unnamed)"].filter(Boolean).join(" ")
1852
+ ).join("\n")}
1888
1853
  `;
1889
1854
  }
1890
1855
  function renderRecentSessionList(sessions) {
@@ -1956,171 +1921,6 @@ Error: ${result.error}` : "";
1956
1921
  return `Workspace sync ${result.outcome} on ${result.workerLabel}; HEAD ${head}; ${result.diffSizeBytes} bytes.${discarded}${error}
1957
1922
  `;
1958
1923
  }
1959
- function summarizeK8sHistory(history) {
1960
- if (history.envelope.length === 0) {
1961
- return {
1962
- cpuMinNanoCores: null,
1963
- cpuMaxNanoCores: null,
1964
- memoryMinBytes: null,
1965
- memoryMaxBytes: null,
1966
- sampleCount: 0
1967
- };
1968
- }
1969
- return {
1970
- cpuMinNanoCores: Math.min(...history.envelope.map((point) => point.cpuMinNanoCores)),
1971
- cpuMaxNanoCores: Math.max(...history.envelope.map((point) => point.cpuMaxNanoCores)),
1972
- memoryMinBytes: Math.min(...history.envelope.map((point) => point.memoryMinBytes)),
1973
- memoryMaxBytes: Math.max(...history.envelope.map((point) => point.memoryMaxBytes)),
1974
- sampleCount: history.envelope.reduce((total, point) => total + point.sampleCount, 0)
1975
- };
1976
- }
1977
- async function mapWithConcurrency(items, concurrency, fn) {
1978
- const results = new Array(items.length);
1979
- let nextIndex = 0;
1980
- await Promise.all(
1981
- Array.from({ length: Math.min(concurrency, items.length) }, async () => {
1982
- while (nextIndex < items.length) {
1983
- const index = nextIndex++;
1984
- const item = items[index];
1985
- if (item !== void 0) results[index] = await fn(item);
1986
- }
1987
- })
1988
- );
1989
- return results;
1990
- }
1991
- async function collectK8sUsage(client, options) {
1992
- const resources = await client.k8s.resources();
1993
- const candidates = resources.workloads.flatMap((workload) => workload.containers.map((container) => ({ workload, container }))).filter(({ workload, container }) => {
1994
- const workloadMatches = !options.workload || options.workload === workload.name || options.workload === `${workload.namespace}/${workload.name}` || options.workload === workload.uid;
1995
- return (!options.namespace || options.namespace === workload.namespace) && workloadMatches && (!options.container || options.container === container.name);
1996
- }).sort(
1997
- (left, right) => left.workload.namespace.localeCompare(right.workload.namespace) || left.workload.name.localeCompare(right.workload.name) || left.container.name.localeCompare(right.container.name)
1998
- );
1999
- if (candidates.length === 0 && (options.namespace || options.workload || options.container)) {
2000
- throw new Error("No managed-vCluster workload containers matched the requested filters");
2001
- }
2002
- const entries = await mapWithConcurrency(candidates, 8, async ({ workload, container }) => {
2003
- const history = await client.k8s.resourceHistory({ workloadUid: workload.uid, containerName: container.name, window: options.window });
2004
- return {
2005
- workload: {
2006
- uid: workload.uid,
2007
- kind: workload.kind,
2008
- namespace: workload.namespace,
2009
- name: workload.name,
2010
- replicas: workload.replicas,
2011
- readyReplicas: workload.readyReplicas
2012
- },
2013
- container: {
2014
- name: container.name,
2015
- currentUsage: container.currentUsage,
2016
- pods: container.pods
2017
- },
2018
- sampledPodCount: container.pods.filter((pod) => pod.cpuNanoCores !== null || pod.memoryBytes !== null).length,
2019
- summary: summarizeK8sHistory(history),
2020
- history
2021
- };
2022
- });
2023
- return {
2024
- window: options.window,
2025
- collectedAt: resources.collectedAt,
2026
- metricsFreshAt: resources.metricsFreshAt,
2027
- metricsStale: resources.metricsStale,
2028
- filters: {
2029
- namespace: options.namespace,
2030
- workload: options.workload,
2031
- container: options.container
2032
- },
2033
- entries
2034
- };
2035
- }
2036
- function formatDecimal(value) {
2037
- if (value >= 100) return value.toFixed(0);
2038
- if (value >= 10) return value.toFixed(1).replace(/\.0$/, "");
2039
- return value.toFixed(2).replace(/\.0+$/, "").replace(/(\.\d)0$/, "$1");
2040
- }
2041
- function formatK8sCpu(value) {
2042
- if (value === null) return "-";
2043
- const milliCores = value / 1e6;
2044
- return `${formatDecimal(milliCores)}m`;
2045
- }
2046
- function formatK8sMemory(value) {
2047
- if (value === null) return "-";
2048
- const units = ["B", "Ki", "Mi", "Gi", "Ti"];
2049
- let amount = value;
2050
- let unitIndex = 0;
2051
- while (amount >= 1024 && unitIndex < units.length - 1) {
2052
- amount /= 1024;
2053
- unitIndex += 1;
2054
- }
2055
- return `${formatDecimal(amount)}${units[unitIndex]}`;
2056
- }
2057
- function getK8sUsageState(entry) {
2058
- const hasHistory = entry.history.envelope.length > 0;
2059
- const terminalPods = entry.container.pods.filter((pod) => pod.phase === "Succeeded" || pod.phase === "Failed").length;
2060
- const inactive = entry.sampledPodCount === 0 && (entry.workload.replicas === 0 || entry.container.pods.length > 0 && terminalPods === entry.container.pods.length || entry.workload.kind === "CronJob" && entry.container.pods.length === 0);
2061
- if (inactive) return "inactive";
2062
- if (entry.sampledPodCount === 0) return hasHistory ? entry.history.stale ? "stale" : "no current" : "no data";
2063
- if (!hasHistory) return "warming";
2064
- if (entry.history.stale) return "stale";
2065
- if (entry.history.incomplete) return "partial";
2066
- return "healthy";
2067
- }
2068
- function abbreviatedK8sKind(kind) {
2069
- switch (kind) {
2070
- case "Deployment":
2071
- return "deploy";
2072
- case "StatefulSet":
2073
- return "sts";
2074
- case "DaemonSet":
2075
- return "ds";
2076
- case "CronJob":
2077
- return "cron";
2078
- case "ReplicaSet":
2079
- return "rs";
2080
- case "Job":
2081
- return "job";
2082
- case "Pod":
2083
- return "pod";
2084
- }
2085
- }
2086
- function renderK8sUsageReport(report) {
2087
- const freshness = report.metricsFreshAt ?? "unavailable";
2088
- const lines = [
2089
- `Window: ${report.window} Collector: ${report.metricsStale ? "stale" : "current"} Fresh: ${freshness}`,
2090
- "PODS counts pods with current metrics."
2091
- ];
2092
- if (report.entries.length === 0) return `${lines.join("\n")}
2093
- No managed-vCluster workload containers found.
2094
- `;
2095
- const headers = ["WORKLOAD", "CONTAINER", "PODS", "CPU NOW", "CPU MAX", "MEM NOW", "MEM MAX", "STATE"];
2096
- const grouped = /* @__PURE__ */ new Map();
2097
- for (const entry of report.entries) {
2098
- const entries = grouped.get(entry.workload.namespace) ?? [];
2099
- entries.push(entry);
2100
- grouped.set(entry.workload.namespace, entries);
2101
- }
2102
- for (const [namespace, entries] of grouped) {
2103
- const rows = entries.map((entry) => {
2104
- const state = getK8sUsageState(entry);
2105
- return [
2106
- `${abbreviatedK8sKind(entry.workload.kind)}/${entry.workload.name}`,
2107
- entry.container.name,
2108
- String(entry.sampledPodCount),
2109
- formatK8sCpu(entry.container.currentUsage.cpuNanoCores),
2110
- formatK8sCpu(entry.summary.cpuMaxNanoCores),
2111
- formatK8sMemory(entry.container.currentUsage.memoryBytes),
2112
- formatK8sMemory(entry.summary.memoryMaxBytes),
2113
- state === "healthy" ? "-" : state
2114
- ];
2115
- });
2116
- const widths = headers.map((header, column) => Math.max(header.length, ...rows.map((row) => row[column]?.length ?? 0)));
2117
- const formatRow = (row) => row.map((value, column) => column === row.length - 1 ? value : value.padEnd(widths[column] ?? value.length)).join(" ");
2118
- const separator = widths.map((width) => "-".repeat(width)).join(" ");
2119
- lines.push("", `Namespace: ${namespace}`, formatRow(headers), separator, ...rows.map(formatRow));
2120
- }
2121
- return `${lines.join("\n")}
2122
- `;
2123
- }
2124
1924
  function renderSessionDescription(session) {
2125
1925
  return [`Session: ${session.id}`, `Project: ${session.projectPath}`, `Branch: ${session.branchName}`].join("\n") + "\n";
2126
1926
  }
@@ -3047,45 +2847,6 @@ async function executeR5dctlCommand(client, json, args) {
3047
2847
  write(result, renderWorkspaceSync(result));
3048
2848
  return;
3049
2849
  }
3050
- if (first === "k8s" && second === "usage") {
3051
- const report = await collectK8sUsage(client, parseK8sUsageArgs(args.slice(2)));
3052
- write(report, renderK8sUsageReport(report));
3053
- return;
3054
- }
3055
- if (first === "vcluster" && second === "trusted-workflow") {
3056
- const subcommand = requireValue(args[2], "Missing trusted-workflow command");
3057
- if (subcommand === "add") {
3058
- const parsed = parseCommandOperands(args.slice(3), /* @__PURE__ */ new Set(["--repo", "--workflow"]), /* @__PURE__ */ new Map(), "trusted-workflow add");
3059
- if (parsed.positionals.length > 0) throw new Error(`Unexpected trusted-workflow add value: ${parsed.positionals[0]}`);
3060
- const workflow = await client.k8s.trustedWorkflows.add({
3061
- repository: requireValue(parsed.values.get("--repo"), "--repo <owner/repository> is required"),
3062
- workflowPath: requireValue(parsed.values.get("--workflow"), "--workflow <path> is required")
3063
- });
3064
- write(workflow, "Trusted GitHub workflow configured successfully.\n");
3065
- return;
3066
- }
3067
- if (subcommand === "list") {
3068
- if (args.length > 3) throw new Error(`Unexpected trusted-workflow list value: ${args[3]}`);
3069
- const workflows = await client.k8s.trustedWorkflows.list();
3070
- write(
3071
- workflows,
3072
- workflows.length === 0 ? "No trusted GitHub workflows.\n" : `${workflows.map(
3073
- (workflow) => `${workflow.id} ${workflow.repository} ${workflow.workflowPath} ${workflow.revokedAt ? "revoked" : "active"}`
3074
- ).join("\n")}
3075
- `
3076
- );
3077
- return;
3078
- }
3079
- if (subcommand === "remove") {
3080
- const workflowId = requireValue(args[3], "Missing trusted workflow id");
3081
- if (args.length > 4) throw new Error(`Unexpected trusted-workflow remove value: ${args[4]}`);
3082
- const result = await client.k8s.trustedWorkflows.revoke(workflowId);
3083
- if (!result.success) throw new Error("Trusted GitHub workflow was not found or was already revoked");
3084
- write(result, "Trusted GitHub workflow revoked.\n");
3085
- return;
3086
- }
3087
- throw new Error(`Unknown trusted-workflow command: ${subcommand}`);
3088
- }
3089
2850
  if (first === "ps" && second === "list") {
3090
2851
  const processes = await client.processes.list(parsePsListArgs(args.slice(2)));
3091
2852
  write(processes, renderProcessList(processes));
@@ -3121,7 +2882,9 @@ async function executeR5dctlCommand(client, json, args) {
3121
2882
  });
3122
2883
  write(result2, renderSessionClaimResponse(result2, nowMs));
3123
2884
  if (result2.outcome === "held_by_other") {
3124
- throw new Error(`Claim ${claim.topic} is held by session ${result2.claim.holderSessionId} until ${result2.claim.expiresAt}; not acquired`);
2885
+ throw new Error(
2886
+ `Claim ${claim.topic} is held by session ${result2.claim.holderSessionId} until ${result2.claim.expiresAt}; not acquired`
2887
+ );
3125
2888
  }
3126
2889
  return;
3127
2890
  }
@@ -3141,12 +2904,20 @@ async function executeR5dctlCommand(client, json, args) {
3141
2904
  return;
3142
2905
  }
3143
2906
  if (!current.heldByActor) {
3144
- write({ outcome: "not_holder", actorSessionId: list.actorSessionId, claim: current }, renderSessionClaimResponse({ outcome: "not_holder", actorSessionId: list.actorSessionId, claim: current }, nowMs));
2907
+ write(
2908
+ { outcome: "not_holder", actorSessionId: list.actorSessionId, claim: current },
2909
+ renderSessionClaimResponse({ outcome: "not_holder", actorSessionId: list.actorSessionId, claim: current }, nowMs)
2910
+ );
3145
2911
  throw new Error(`Claim ${claim.topic} is held by session ${current.holderSessionId}, not by ${list.actorSessionId}`);
3146
2912
  }
3147
2913
  generation = current.generation;
3148
2914
  }
3149
- const result = claim.action === "renew" ? await client.claims.renew({ topic: claim.topic, ...scope, generation, ...claim.ttlSeconds !== void 0 ? { ttlSeconds: claim.ttlSeconds } : {} }) : await client.claims.release({ topic: claim.topic, ...scope, generation });
2915
+ const result = claim.action === "renew" ? await client.claims.renew({
2916
+ topic: claim.topic,
2917
+ ...scope,
2918
+ generation,
2919
+ ...claim.ttlSeconds !== void 0 ? { ttlSeconds: claim.ttlSeconds } : {}
2920
+ }) : await client.claims.release({ topic: claim.topic, ...scope, generation });
3150
2921
  write(result, renderSessionClaimResponse(result, nowMs));
3151
2922
  const succeeded = result.outcome === "renewed" || result.outcome === "released" || claim.action === "release" && result.outcome === "missing";
3152
2923
  if (!succeeded) throw new Error(`Claim ${claim.topic}: ${CLAIM_OUTCOME_TEXT[result.outcome] ?? result.outcome}`);
@@ -3263,7 +3034,10 @@ ${result.deletion ? `Deletion: ${result.deletion.status}${result.deletion.error
3263
3034
  const offset = first === "describe" ? 2 : 3;
3264
3035
  const projectRef = requireValue(args[offset], "Missing project reference");
3265
3036
  const branchId = requireValue(args[offset + 1], "Missing branch id");
3266
- const status = await requireServerRouteSupport("describe branch-deletion", () => client.projects.branches.describeDeletion(projectRef, branchId));
3037
+ const status = await requireServerRouteSupport(
3038
+ "describe branch-deletion",
3039
+ () => client.projects.branches.describeDeletion(projectRef, branchId)
3040
+ );
3267
3041
  write(status, renderBranchDeletionStatus(status));
3268
3042
  return;
3269
3043
  }
@@ -3408,25 +3182,26 @@ ${result.deletion ? `Deletion: ${result.deletion.status}${result.deletion.error
3408
3182
  throw new Error(`Unknown command: ${args.join(" ")}`);
3409
3183
  }
3410
3184
  function resolveCommandExecution(options, rest) {
3411
- const trailingHelp = isHelpFlag(rest.at(-1));
3185
+ const accountLiteralHelp = rest[0] === "account" && ["--value", "--file", "--description"].includes(rest.at(-2) ?? "");
3186
+ const trailingHelp = isHelpFlag(rest.at(-1)) && !accountLiteralHelp;
3412
3187
  const normalizedRest = trailingHelp ? rest.slice(0, -1) : rest;
3413
3188
  const command = normalizedRest[0];
3414
3189
  if (!command) {
3415
3190
  throw new Error("Missing command");
3416
3191
  }
3417
3192
  const commandArgs = normalizedRest.slice(1);
3193
+ if (command === "account") {
3194
+ if (trailingHelp || commandArgs.length <= 1) {
3195
+ return { kind: "cli-help", text: (0, import_account.getAccountHelp)(commandArgs.slice(0, 2)) };
3196
+ }
3197
+ return { kind: "account", command: (0, import_account.parseAccountCommand)(commandArgs) };
3198
+ }
3418
3199
  if (command === "ps" && commandArgs.length === 0) {
3419
3200
  return {
3420
3201
  kind: "cli-help",
3421
3202
  text: PS_HELP_TEXT
3422
3203
  };
3423
3204
  }
3424
- if (command === "k8s" && commandArgs.length === 0) {
3425
- return {
3426
- kind: "cli-help",
3427
- text: K8S_HELP_TEXT
3428
- };
3429
- }
3430
3205
  if (command === "session" && commandArgs.length === 0) {
3431
3206
  return {
3432
3207
  kind: "cli-help",
@@ -3448,10 +3223,7 @@ function resolveCommandExecution(options, rest) {
3448
3223
  text: sharedHelp
3449
3224
  };
3450
3225
  }
3451
- return {
3452
- kind: "plugin",
3453
- pluginArgs: [...normalizedRest, "--help"]
3454
- };
3226
+ throw new Error(`Unknown command: ${normalizedRest.join(" ")}`);
3455
3227
  }
3456
3228
  if (command === "projects" || command === "sessions" || command === "workspace") {
3457
3229
  return {
@@ -3561,26 +3333,6 @@ function resolveCommandExecution(options, rest) {
3561
3333
  }
3562
3334
  throw new Error(`Unknown ps command: ${subcommand ?? ""}`.trim());
3563
3335
  }
3564
- if (command === "k8s") {
3565
- const subcommand = commandArgs[0];
3566
- if (options.project || options.branch || options.session) {
3567
- throw new Error("Project, branch, and session scopes are not supported for `k8s`");
3568
- }
3569
- if (subcommand === "usage") {
3570
- parseK8sUsageArgs(commandArgs.slice(1));
3571
- return { kind: "plugin", pluginArgs: ["k8s", "usage", ...commandArgs.slice(1)] };
3572
- }
3573
- throw new Error(`Unknown k8s command: ${subcommand ?? ""}`.trim());
3574
- }
3575
- if (command === "vcluster") {
3576
- if (options.project || options.branch || options.session) {
3577
- throw new Error("Project, branch, and session scopes are not supported for `vcluster`");
3578
- }
3579
- if (commandArgs[0] !== "trusted-workflow") {
3580
- throw new Error(`Unknown vcluster command: ${commandArgs[0] ?? ""}`.trim());
3581
- }
3582
- return { kind: "plugin", pluginArgs: ["vcluster", "trusted-workflow", ...commandArgs.slice(1)] };
3583
- }
3584
3336
  if (command === "get") {
3585
3337
  const target = commandArgs[0];
3586
3338
  if (target === "projects") {
@@ -3955,6 +3707,10 @@ async function runCommand(argv) {
3955
3707
  const clientOptions = resolveClientOptions(options, config);
3956
3708
  const client = new import_r5d_api.R5dctlClient(clientOptions);
3957
3709
  const execution = resolveCommandExecution(options, rest);
3710
+ if (execution.kind === "account") {
3711
+ await (0, import_account.executeAccountCommand)(client, execution.command, options.json);
3712
+ return 0;
3713
+ }
3958
3714
  if (execution.kind === "auth-login") {
3959
3715
  await handleAuthLogin(client, options, execution.commandArgs, config);
3960
3716
  return 0;
@@ -4063,18 +3819,14 @@ async function main(argv = process.argv.slice(2)) {
4063
3819
  branchDeletionConfirmationMessage,
4064
3820
  branchDeletionsConfirmationMessage,
4065
3821
  branchDeletionsFailureMessage,
4066
- collectK8sUsage,
4067
3822
  createBranchThroughPlatform,
4068
3823
  deleteBranchThroughPlatform,
4069
3824
  deleteBranchesThroughPlatform,
4070
3825
  dispatchSessionRunCommand,
4071
3826
  followR5dctlSession,
4072
- formatK8sCpu,
4073
- formatK8sMemory,
4074
3827
  formatProcessAge,
4075
3828
  formatProcessLane,
4076
3829
  getCliHelpText,
4077
- getK8sUsageState,
4078
3830
  getProjectEnvValue,
4079
3831
  getR5dctlVersion,
4080
3832
  getTransientDevicePollDelay,
@@ -4095,7 +3847,6 @@ async function main(argv = process.argv.slice(2)) {
4095
3847
  parseEnvRequestResponseArgs,
4096
3848
  parseGetEnvsArgs,
4097
3849
  parseGlobalArgs,
4098
- parseK8sUsageArgs,
4099
3850
  parsePromptArgs,
4100
3851
  parsePsHistoryArgs,
4101
3852
  parsePsListArgs,
@@ -4120,7 +3871,6 @@ async function main(argv = process.argv.slice(2)) {
4120
3871
  renderConversationWorkResponse,
4121
3872
  renderDeviceAuthorizationPrompt,
4122
3873
  renderEnvValues,
4123
- renderK8sUsageReport,
4124
3874
  renderProcessHistory,
4125
3875
  renderProcessInspection,
4126
3876
  renderProcessList,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.126",
3
+ "version": "0.0.128",
4
4
  "type": "commonjs"
5
5
  }