@ricsam/r5dctl 0.0.34 → 0.0.35

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
@@ -38,6 +38,7 @@ __export(cli_exports, {
38
38
  parseEnvFlags: () => parseEnvFlags,
39
39
  parseGlobalArgs: () => parseGlobalArgs,
40
40
  parsePromptArgs: () => parsePromptArgs,
41
+ parsePsHistoryArgs: () => parsePsHistoryArgs,
41
42
  parsePsListArgs: () => parsePsListArgs,
42
43
  parseSetEnvArgs: () => parseSetEnvArgs,
43
44
  parseShellArgs: () => parseShellArgs,
@@ -45,6 +46,8 @@ __export(cli_exports, {
45
46
  renderConversationOverviewResponse: () => renderConversationOverviewResponse,
46
47
  renderConversationResponse: () => renderConversationResponse,
47
48
  renderConversationWorkResponse: () => renderConversationWorkResponse,
49
+ renderProcessHistory: () => renderProcessHistory,
50
+ renderProcessInspection: () => renderProcessInspection,
48
51
  renderProcessList: () => renderProcessList,
49
52
  resolveCommandExecution: () => resolveCommandExecution,
50
53
  runR5dctlCli: () => runR5dctlCli,
@@ -112,10 +115,12 @@ const CLI_ONLY_COMMAND_HELP = [
112
115
  const PS_HELP_TEXT = [
113
116
  "Usage:",
114
117
  " r5dctl ps list [--worker <label>]",
118
+ " r5dctl ps history [--worker <label>] [--limit <n>]",
119
+ " r5dctl ps inspect <run-id>",
115
120
  " r5dctl ps stop <run-id>",
116
121
  "",
117
- "List or gracefully stop active r5d-managed worker processes.",
118
- "Use -p/--project, -b/--branch, or -s/--session to filter ps list.",
122
+ "List, inspect, or gracefully stop r5d-managed worker processes.",
123
+ "Use -p/--project, -b/--branch, or -s/--session to filter list and history.",
119
124
  ""
120
125
  ].join("\n");
121
126
  const SHARED_HELP_ENTRIES = [
@@ -197,6 +202,16 @@ const SHARED_HELP_ENTRIES = [
197
202
  usage: "ps list [--worker <label>]",
198
203
  description: "List active r5d-managed worker processes; global project, branch, and session filters apply."
199
204
  },
205
+ {
206
+ section: "processes",
207
+ usage: "ps history [--worker <label>] [--limit <n>]",
208
+ description: "List recent process runs, defaulting to the 50 most recent; global filters apply."
209
+ },
210
+ {
211
+ section: "processes",
212
+ usage: "ps inspect <run-id>",
213
+ description: "Inspect execution, synchronization, repository outcomes, and bounded output tails."
214
+ },
200
215
  { section: "processes", usage: "ps stop <run-id>", description: "Gracefully stop an active process with SIGTERM." },
201
216
  {
202
217
  section: "agents",
@@ -817,6 +832,25 @@ function parsePsListArgs(args) {
817
832
  }
818
833
  return input;
819
834
  }
835
+ function parsePsHistoryArgs(args) {
836
+ const filterArgs = [];
837
+ let limit;
838
+ for (let index = 0; index < args.length; index += 1) {
839
+ const arg = args[index];
840
+ if (arg === "--limit" || arg?.startsWith("--limit=")) {
841
+ if (limit !== void 0) throw new Error("Use only one --limit value");
842
+ const raw = arg === "--limit" ? args[++index] : parseLongOptionWithEquals(arg, "--limit");
843
+ const parsed = Number(requireValue(raw, "Missing value for --limit"));
844
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > 200) {
845
+ throw new Error("--limit must be an integer between 1 and 200");
846
+ }
847
+ limit = parsed;
848
+ continue;
849
+ }
850
+ if (arg) filterArgs.push(arg);
851
+ }
852
+ return { ...parsePsListArgs(filterArgs), ...limit !== void 0 ? { limit } : {} };
853
+ }
820
854
  async function openInBrowser(url) {
821
855
  if (process.platform === "darwin") {
822
856
  (0, import_node_child_process.spawn)("open", [url], { stdio: "ignore", detached: true }).unref();
@@ -1002,6 +1036,46 @@ function renderProcessList(processes, nowMs = Date.now()) {
1002
1036
  return `${[formatRow(headers), separator, ...rows.map(formatRow)].join("\n")}
1003
1037
  `;
1004
1038
  }
1039
+ function renderProcessHistory(processes, nowMs = Date.now()) {
1040
+ return processes.length === 0 ? "No process history.\n" : renderProcessList(processes, nowMs);
1041
+ }
1042
+ function renderProcessInspection(process2) {
1043
+ const repositories = process2.repositoryOutcomes.length === 0 ? " (none)" : process2.repositoryOutcomes.map(
1044
+ (outcome) => ` ${outcome.projectPath ?? outcome.projectId} ${outcome.branchName}: ${outcome.status}${outcome.startCommitHash ? `; start ${outcome.startCommitHash}` : ""}${outcome.publishedCommitHash ? ` (${outcome.publishedCommitHash})` : ""}${outcome.branchActionId ? `; branch action ${outcome.branchActionId}` : ""}${outcome.largeDiffIncidentId ? `; incident ${outcome.largeDiffIncidentId}` : ""}${outcome.diffSizeBytes !== void 0 ? `; ${outcome.diffSizeBytes} diff bytes` : ""}${outcome.principalSynchronizationState ? `; principal ${outcome.principalSynchronizationState}` : ""}${outcome.fanOutState ? `; fan-out ${outcome.fanOutState}` : ""}${outcome.error ? ` \u2014 ${outcome.error}` : ""}`
1045
+ ).join("\n");
1046
+ return [
1047
+ `Run: ${process2.runId}`,
1048
+ `Status: ${process2.status} / sync ${process2.syncState}`,
1049
+ `Mode: ${process2.mode}`,
1050
+ `Worker: ${process2.workerLabel} (${process2.platform ?? "unknown"}/${process2.arch ?? "unknown"})`,
1051
+ `Project: ${process2.projectPath} ${process2.branchName}`,
1052
+ `Session: ${process2.sessionId}`,
1053
+ `Command: ${process2.command}`,
1054
+ `Argv: ${JSON.stringify(process2.argv)}`,
1055
+ `CWD: ${process2.cwd ?? "(default checkout)"}`,
1056
+ `PID/process group: ${process2.pid ?? "(unknown)"}/${process2.processGroupId ?? "(unknown)"}`,
1057
+ `Starting canonical commit: ${process2.startCommitHash}`,
1058
+ `Started: ${process2.startedAt}`,
1059
+ `Updated: ${process2.updatedAt}`,
1060
+ `Completed: ${process2.completedAt ?? "(running)"}`,
1061
+ `Exit code: ${process2.exitCode ?? "(none)"}`,
1062
+ `Error: ${process2.error ?? "(none)"}`,
1063
+ `Launch action: ${process2.launchWorkspaceActionId ?? "(none)"}`,
1064
+ `Terminal sync action: ${process2.terminalWorkspaceActionId ?? "(pending)"}`,
1065
+ `Terminal sync claimed: ${process2.terminalSyncClaimedAt ?? "(pending)"}`,
1066
+ `Published origin commit: ${process2.publishedCommitHash ?? "(none)"}`,
1067
+ `Principal synchronization: ${process2.principalSynchronizationState ?? "(pending)"}`,
1068
+ "Repositories observed during synchronization:",
1069
+ repositories,
1070
+ "",
1071
+ `stdout tail${process2.stdoutTailTruncated ? " (truncated)" : ""}:`,
1072
+ process2.stdoutTail || "(empty)",
1073
+ "",
1074
+ `stderr tail${process2.stderrTailTruncated ? " (truncated)" : ""}:`,
1075
+ process2.stderrTail || "(empty)",
1076
+ ""
1077
+ ].join("\n");
1078
+ }
1005
1079
  function summarizeEnvData(data) {
1006
1080
  return Object.fromEntries(
1007
1081
  Object.entries(data).sort(([left], [right]) => left.localeCompare(right)).map(([name, env]) => [
@@ -1276,6 +1350,16 @@ async function executeR5dctlCommand(client, json, args) {
1276
1350
  write(processes, renderProcessList(processes));
1277
1351
  return;
1278
1352
  }
1353
+ if (first === "ps" && second === "history") {
1354
+ const processes = await client.processes.history(parsePsHistoryArgs(args.slice(2)));
1355
+ write(processes, renderProcessHistory(processes));
1356
+ return;
1357
+ }
1358
+ if (first === "ps" && second === "inspect") {
1359
+ const process2 = await client.processes.inspect(requireValue(args[2], "Missing process run id"));
1360
+ write(process2, renderProcessInspection(process2));
1361
+ return;
1362
+ }
1279
1363
  if (first === "ps" && second === "stop") {
1280
1364
  const process2 = await client.processes.stop(requireValue(args[2], "Missing process run id"));
1281
1365
  write(process2, `Stopped process ${process2.runId}: ${process2.command}
@@ -1593,6 +1677,31 @@ function resolveCommandExecution(options, rest) {
1593
1677
  }
1594
1678
  return { kind: "plugin", pluginArgs };
1595
1679
  }
1680
+ if (subcommand === "history") {
1681
+ const commandFilters = parsePsHistoryArgs(commandArgs.slice(1));
1682
+ const filters = {
1683
+ ...commandFilters,
1684
+ ...options.project ? { project: options.project } : {},
1685
+ ...options.branch ? { branch: options.branch } : {},
1686
+ ...options.session ? { session: options.session } : {}
1687
+ };
1688
+ const pluginArgs = ["ps", "history"];
1689
+ for (const [flag, value] of [
1690
+ ["--project", filters.project],
1691
+ ["--branch", filters.branch],
1692
+ ["--session", filters.session],
1693
+ ["--worker", filters.worker],
1694
+ ["--limit", filters.limit?.toString()]
1695
+ ]) {
1696
+ if (value) pluginArgs.push(flag, value);
1697
+ }
1698
+ return { kind: "plugin", pluginArgs };
1699
+ }
1700
+ if (subcommand === "inspect") {
1701
+ const runId = requireValue(commandArgs[1], "Missing process run id");
1702
+ if (commandArgs.length > 2) throw new Error(`Unexpected ps inspect value: ${commandArgs[2]}`);
1703
+ return { kind: "plugin", pluginArgs: ["ps", "inspect", runId] };
1704
+ }
1596
1705
  if (subcommand === "stop") {
1597
1706
  const runId = requireValue(commandArgs[1], "Missing process run id");
1598
1707
  if (commandArgs.length > 2) {
@@ -2025,6 +2134,7 @@ async function main(argv = process.argv.slice(2)) {
2025
2134
  parseEnvFlags,
2026
2135
  parseGlobalArgs,
2027
2136
  parsePromptArgs,
2137
+ parsePsHistoryArgs,
2028
2138
  parsePsListArgs,
2029
2139
  parseSetEnvArgs,
2030
2140
  parseShellArgs,
@@ -2032,6 +2142,8 @@ async function main(argv = process.argv.slice(2)) {
2032
2142
  renderConversationOverviewResponse,
2033
2143
  renderConversationResponse,
2034
2144
  renderConversationWorkResponse,
2145
+ renderProcessHistory,
2146
+ renderProcessInspection,
2035
2147
  renderProcessList,
2036
2148
  resolveCommandExecution,
2037
2149
  runR5dctlCli,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.34",
3
+ "version": "0.0.35",
4
4
  "type": "commonjs"
5
5
  }
package/dist/mjs/cli.mjs CHANGED
@@ -62,10 +62,12 @@ const CLI_ONLY_COMMAND_HELP = [
62
62
  const PS_HELP_TEXT = [
63
63
  "Usage:",
64
64
  " r5dctl ps list [--worker <label>]",
65
+ " r5dctl ps history [--worker <label>] [--limit <n>]",
66
+ " r5dctl ps inspect <run-id>",
65
67
  " r5dctl ps stop <run-id>",
66
68
  "",
67
- "List or gracefully stop active r5d-managed worker processes.",
68
- "Use -p/--project, -b/--branch, or -s/--session to filter ps list.",
69
+ "List, inspect, or gracefully stop r5d-managed worker processes.",
70
+ "Use -p/--project, -b/--branch, or -s/--session to filter list and history.",
69
71
  ""
70
72
  ].join("\n");
71
73
  const SHARED_HELP_ENTRIES = [
@@ -147,6 +149,16 @@ const SHARED_HELP_ENTRIES = [
147
149
  usage: "ps list [--worker <label>]",
148
150
  description: "List active r5d-managed worker processes; global project, branch, and session filters apply."
149
151
  },
152
+ {
153
+ section: "processes",
154
+ usage: "ps history [--worker <label>] [--limit <n>]",
155
+ description: "List recent process runs, defaulting to the 50 most recent; global filters apply."
156
+ },
157
+ {
158
+ section: "processes",
159
+ usage: "ps inspect <run-id>",
160
+ description: "Inspect execution, synchronization, repository outcomes, and bounded output tails."
161
+ },
150
162
  { section: "processes", usage: "ps stop <run-id>", description: "Gracefully stop an active process with SIGTERM." },
151
163
  {
152
164
  section: "agents",
@@ -767,6 +779,25 @@ function parsePsListArgs(args) {
767
779
  }
768
780
  return input;
769
781
  }
782
+ function parsePsHistoryArgs(args) {
783
+ const filterArgs = [];
784
+ let limit;
785
+ for (let index = 0; index < args.length; index += 1) {
786
+ const arg = args[index];
787
+ if (arg === "--limit" || arg?.startsWith("--limit=")) {
788
+ if (limit !== void 0) throw new Error("Use only one --limit value");
789
+ const raw = arg === "--limit" ? args[++index] : parseLongOptionWithEquals(arg, "--limit");
790
+ const parsed = Number(requireValue(raw, "Missing value for --limit"));
791
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > 200) {
792
+ throw new Error("--limit must be an integer between 1 and 200");
793
+ }
794
+ limit = parsed;
795
+ continue;
796
+ }
797
+ if (arg) filterArgs.push(arg);
798
+ }
799
+ return { ...parsePsListArgs(filterArgs), ...limit !== void 0 ? { limit } : {} };
800
+ }
770
801
  async function openInBrowser(url) {
771
802
  if (process.platform === "darwin") {
772
803
  spawn("open", [url], { stdio: "ignore", detached: true }).unref();
@@ -952,6 +983,46 @@ function renderProcessList(processes, nowMs = Date.now()) {
952
983
  return `${[formatRow(headers), separator, ...rows.map(formatRow)].join("\n")}
953
984
  `;
954
985
  }
986
+ function renderProcessHistory(processes, nowMs = Date.now()) {
987
+ return processes.length === 0 ? "No process history.\n" : renderProcessList(processes, nowMs);
988
+ }
989
+ function renderProcessInspection(process2) {
990
+ const repositories = process2.repositoryOutcomes.length === 0 ? " (none)" : process2.repositoryOutcomes.map(
991
+ (outcome) => ` ${outcome.projectPath ?? outcome.projectId} ${outcome.branchName}: ${outcome.status}${outcome.startCommitHash ? `; start ${outcome.startCommitHash}` : ""}${outcome.publishedCommitHash ? ` (${outcome.publishedCommitHash})` : ""}${outcome.branchActionId ? `; branch action ${outcome.branchActionId}` : ""}${outcome.largeDiffIncidentId ? `; incident ${outcome.largeDiffIncidentId}` : ""}${outcome.diffSizeBytes !== void 0 ? `; ${outcome.diffSizeBytes} diff bytes` : ""}${outcome.principalSynchronizationState ? `; principal ${outcome.principalSynchronizationState}` : ""}${outcome.fanOutState ? `; fan-out ${outcome.fanOutState}` : ""}${outcome.error ? ` \u2014 ${outcome.error}` : ""}`
992
+ ).join("\n");
993
+ return [
994
+ `Run: ${process2.runId}`,
995
+ `Status: ${process2.status} / sync ${process2.syncState}`,
996
+ `Mode: ${process2.mode}`,
997
+ `Worker: ${process2.workerLabel} (${process2.platform ?? "unknown"}/${process2.arch ?? "unknown"})`,
998
+ `Project: ${process2.projectPath} ${process2.branchName}`,
999
+ `Session: ${process2.sessionId}`,
1000
+ `Command: ${process2.command}`,
1001
+ `Argv: ${JSON.stringify(process2.argv)}`,
1002
+ `CWD: ${process2.cwd ?? "(default checkout)"}`,
1003
+ `PID/process group: ${process2.pid ?? "(unknown)"}/${process2.processGroupId ?? "(unknown)"}`,
1004
+ `Starting canonical commit: ${process2.startCommitHash}`,
1005
+ `Started: ${process2.startedAt}`,
1006
+ `Updated: ${process2.updatedAt}`,
1007
+ `Completed: ${process2.completedAt ?? "(running)"}`,
1008
+ `Exit code: ${process2.exitCode ?? "(none)"}`,
1009
+ `Error: ${process2.error ?? "(none)"}`,
1010
+ `Launch action: ${process2.launchWorkspaceActionId ?? "(none)"}`,
1011
+ `Terminal sync action: ${process2.terminalWorkspaceActionId ?? "(pending)"}`,
1012
+ `Terminal sync claimed: ${process2.terminalSyncClaimedAt ?? "(pending)"}`,
1013
+ `Published origin commit: ${process2.publishedCommitHash ?? "(none)"}`,
1014
+ `Principal synchronization: ${process2.principalSynchronizationState ?? "(pending)"}`,
1015
+ "Repositories observed during synchronization:",
1016
+ repositories,
1017
+ "",
1018
+ `stdout tail${process2.stdoutTailTruncated ? " (truncated)" : ""}:`,
1019
+ process2.stdoutTail || "(empty)",
1020
+ "",
1021
+ `stderr tail${process2.stderrTailTruncated ? " (truncated)" : ""}:`,
1022
+ process2.stderrTail || "(empty)",
1023
+ ""
1024
+ ].join("\n");
1025
+ }
955
1026
  function summarizeEnvData(data) {
956
1027
  return Object.fromEntries(
957
1028
  Object.entries(data).sort(([left], [right]) => left.localeCompare(right)).map(([name, env]) => [
@@ -1226,6 +1297,16 @@ async function executeR5dctlCommand(client, json, args) {
1226
1297
  write(processes, renderProcessList(processes));
1227
1298
  return;
1228
1299
  }
1300
+ if (first === "ps" && second === "history") {
1301
+ const processes = await client.processes.history(parsePsHistoryArgs(args.slice(2)));
1302
+ write(processes, renderProcessHistory(processes));
1303
+ return;
1304
+ }
1305
+ if (first === "ps" && second === "inspect") {
1306
+ const process2 = await client.processes.inspect(requireValue(args[2], "Missing process run id"));
1307
+ write(process2, renderProcessInspection(process2));
1308
+ return;
1309
+ }
1229
1310
  if (first === "ps" && second === "stop") {
1230
1311
  const process2 = await client.processes.stop(requireValue(args[2], "Missing process run id"));
1231
1312
  write(process2, `Stopped process ${process2.runId}: ${process2.command}
@@ -1543,6 +1624,31 @@ function resolveCommandExecution(options, rest) {
1543
1624
  }
1544
1625
  return { kind: "plugin", pluginArgs };
1545
1626
  }
1627
+ if (subcommand === "history") {
1628
+ const commandFilters = parsePsHistoryArgs(commandArgs.slice(1));
1629
+ const filters = {
1630
+ ...commandFilters,
1631
+ ...options.project ? { project: options.project } : {},
1632
+ ...options.branch ? { branch: options.branch } : {},
1633
+ ...options.session ? { session: options.session } : {}
1634
+ };
1635
+ const pluginArgs = ["ps", "history"];
1636
+ for (const [flag, value] of [
1637
+ ["--project", filters.project],
1638
+ ["--branch", filters.branch],
1639
+ ["--session", filters.session],
1640
+ ["--worker", filters.worker],
1641
+ ["--limit", filters.limit?.toString()]
1642
+ ]) {
1643
+ if (value) pluginArgs.push(flag, value);
1644
+ }
1645
+ return { kind: "plugin", pluginArgs };
1646
+ }
1647
+ if (subcommand === "inspect") {
1648
+ const runId = requireValue(commandArgs[1], "Missing process run id");
1649
+ if (commandArgs.length > 2) throw new Error(`Unexpected ps inspect value: ${commandArgs[2]}`);
1650
+ return { kind: "plugin", pluginArgs: ["ps", "inspect", runId] };
1651
+ }
1546
1652
  if (subcommand === "stop") {
1547
1653
  const runId = requireValue(commandArgs[1], "Missing process run id");
1548
1654
  if (commandArgs.length > 2) {
@@ -1974,6 +2080,7 @@ export {
1974
2080
  parseEnvFlags,
1975
2081
  parseGlobalArgs,
1976
2082
  parsePromptArgs,
2083
+ parsePsHistoryArgs,
1977
2084
  parsePsListArgs,
1978
2085
  parseSetEnvArgs,
1979
2086
  parseShellArgs,
@@ -1981,6 +2088,8 @@ export {
1981
2088
  renderConversationOverviewResponse,
1982
2089
  renderConversationResponse,
1983
2090
  renderConversationWorkResponse,
2091
+ renderProcessHistory,
2092
+ renderProcessInspection,
1984
2093
  renderProcessList,
1985
2094
  resolveCommandExecution,
1986
2095
  runR5dctlCli,
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.34",
3
+ "version": "0.0.35",
4
4
  "type": "module"
5
5
  }
@@ -1,4 +1,4 @@
1
- import { type R5dctlConversationRenderOptions, type R5dctlConversationResponse, type R5dctlConversationOverviewResponse, type R5dctlConversationWorkDetail, type R5dctlConversationWorkResponse, type R5dctlEnvData, type R5dctlProcessListInput, type R5dctlProcessRun, type ChatMode, type ModelTier } from "@ricsam/r5d-api";
1
+ import { type R5dctlConversationRenderOptions, type R5dctlConversationResponse, type R5dctlConversationOverviewResponse, type R5dctlConversationWorkDetail, type R5dctlConversationWorkResponse, type R5dctlEnvData, type R5dctlProcessListInput, type R5dctlProcessInspection, type R5dctlProcessRun, type ChatMode, type ModelTier } from "@ricsam/r5d-api";
2
2
  export type GlobalOptions = {
3
3
  baseUrl?: string;
4
4
  json: boolean;
@@ -61,8 +61,11 @@ export declare function parseShellArgs(args: string[]): {
61
61
  command?: string;
62
62
  };
63
63
  export declare function parsePsListArgs(args: string[]): R5dctlProcessListInput;
64
+ export declare function parsePsHistoryArgs(args: string[]): R5dctlProcessListInput;
64
65
  export declare function formatProcessAge(startedAt: string, nowMs?: number): string;
65
66
  export declare function renderProcessList(processes: R5dctlProcessRun[], nowMs?: number): string;
67
+ export declare function renderProcessHistory(processes: R5dctlProcessRun[], nowMs?: number): string;
68
+ export declare function renderProcessInspection(process: R5dctlProcessInspection): string;
66
69
  export type EnvSummaryData = Record<string, {
67
70
  optional: boolean;
68
71
  description: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.34",
3
+ "version": "0.0.35",
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.34",
29
+ "@ricsam/r5d-api": "^0.0.35",
30
30
  "dotenv": "^17",
31
31
  "ws": "^8.18.3"
32
32
  },