@ricsam/r5dctl 0.0.35 → 0.0.37

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
@@ -49,6 +49,8 @@ __export(cli_exports, {
49
49
  renderProcessHistory: () => renderProcessHistory,
50
50
  renderProcessInspection: () => renderProcessInspection,
51
51
  renderProcessList: () => renderProcessList,
52
+ renderWorkspaceStatus: () => renderWorkspaceStatus,
53
+ renderWorkspaceSync: () => renderWorkspaceSync,
52
54
  resolveCommandExecution: () => resolveCommandExecution,
53
55
  runR5dctlCli: () => runR5dctlCli,
54
56
  summarizeEnvData: () => summarizeEnvData
@@ -68,7 +70,6 @@ const CHAT_MODES = /* @__PURE__ */ new Set([
68
70
  "build",
69
71
  "agent",
70
72
  "explore",
71
- "review",
72
73
  "test",
73
74
  "research",
74
75
  "security_review",
@@ -133,6 +134,17 @@ const SHARED_HELP_ENTRIES = [
133
134
  },
134
135
  { section: "auth", usage: "auth api-key list", description: "List API keys for the current account." },
135
136
  { section: "auth", usage: "auth api-key revoke <key-id>", description: "Revoke an API key." },
137
+ { section: "workspace", usage: "workspace status", description: "Inspect the per-user canonical workspace and active remediation." },
138
+ {
139
+ section: "workspace",
140
+ usage: "workspace sync [--worker <label>]",
141
+ description: "Publish a connected worker into the canonical workspace now."
142
+ },
143
+ {
144
+ section: "workspace",
145
+ usage: "workspace reset [--worker <label>] --confirm",
146
+ description: "Destructively discard a blocked remediation candidate and restore canonical state."
147
+ },
136
148
  { section: "projects", usage: "get projects", description: "List projects you can access." },
137
149
  { section: "projects", usage: "describe project <namespace/name|id>", description: "Show details for a project." },
138
150
  { section: "projects", usage: "update project <namespace/name|id> --mode <greenfield|prod>", description: "Update project settings." },
@@ -159,6 +171,11 @@ const SHARED_HELP_ENTRIES = [
159
171
  usage: "-p <project> get sessions [--branch <branch>]",
160
172
  description: "List sessions for a project, optionally filtered by branch."
161
173
  },
174
+ {
175
+ section: "sessions",
176
+ usage: "sessions recent [--limit <n>]",
177
+ description: "List the most recently active sessions across your projects."
178
+ },
162
179
  {
163
180
  section: "sessions",
164
181
  usage: "-p <project> create session -b <branch> [--name <name>]",
@@ -210,7 +227,7 @@ const SHARED_HELP_ENTRIES = [
210
227
  {
211
228
  section: "processes",
212
229
  usage: "ps inspect <run-id>",
213
- description: "Inspect execution, synchronization, repository outcomes, and bounded output tails."
230
+ description: "Inspect process metadata and bounded stdout/stderr tails."
214
231
  },
215
232
  { section: "processes", usage: "ps stop <run-id>", description: "Gracefully stop an active process with SIGTERM." },
216
233
  {
@@ -230,6 +247,7 @@ const SHARED_HELP_ENTRIES = [
230
247
  ];
231
248
  const HELP_SECTION_ORDER = [
232
249
  "auth",
250
+ "workspace",
233
251
  "projects",
234
252
  "branches",
235
253
  "envs",
@@ -241,6 +259,7 @@ const HELP_SECTION_ORDER = [
241
259
  ];
242
260
  const HELP_SECTION_TITLES = {
243
261
  auth: "Auth",
262
+ workspace: "Canonical workspace",
244
263
  projects: "Projects",
245
264
  branches: "Branches",
246
265
  envs: "Environment variables",
@@ -851,6 +870,35 @@ function parsePsHistoryArgs(args) {
851
870
  }
852
871
  return { ...parsePsListArgs(filterArgs), ...limit !== void 0 ? { limit } : {} };
853
872
  }
873
+ function parseWorkspaceWorkerArgs(args, options = {}) {
874
+ let worker;
875
+ let confirmed = false;
876
+ for (let index = 0; index < args.length; index += 1) {
877
+ const arg = args[index];
878
+ if (arg === "--worker" || arg?.startsWith("--worker=")) {
879
+ if (worker) throw new Error("Use only one --worker value");
880
+ worker = requireValue(arg === "--worker" ? args[++index] : parseLongOptionWithEquals(arg, "--worker"), "Missing value for --worker");
881
+ continue;
882
+ }
883
+ if (arg === "--confirm" && options.allowConfirm) {
884
+ confirmed = true;
885
+ continue;
886
+ }
887
+ throw new Error(`Unknown workspace argument: ${arg ?? ""}`.trim());
888
+ }
889
+ if (options.allowConfirm && !confirmed) throw new Error("workspace reset requires --confirm");
890
+ return { ...worker ? { worker } : {}, ...confirmed ? { confirmed: true } : {} };
891
+ }
892
+ function parseRecentSessionArgs(args) {
893
+ if (args.length === 0) return {};
894
+ if (args.length > 2 || args[0] !== "--limit" && !args[0]?.startsWith("--limit=")) {
895
+ throw new Error(`Unknown sessions recent argument: ${args[0] ?? ""}`.trim());
896
+ }
897
+ const raw = args[0] === "--limit" ? args[1] : parseLongOptionWithEquals(args[0], "--limit");
898
+ const limit = Number(requireValue(raw, "Missing value for --limit"));
899
+ if (!Number.isInteger(limit) || limit < 1 || limit > 200) throw new Error("--limit must be an integer between 1 and 200");
900
+ return { limit };
901
+ }
854
902
  async function openInBrowser(url) {
855
903
  if (process.platform === "darwin") {
856
904
  (0, import_node_child_process.spawn)("open", [url], { stdio: "ignore", detached: true }).unref();
@@ -989,6 +1037,29 @@ function renderSessionList(sessions) {
989
1037
  return `${sessions.map((session) => `${session.id} ${session.branchName} ${session.name ?? "(unnamed)"}`).join("\n")}
990
1038
  `;
991
1039
  }
1040
+ function renderRecentSessionList(sessions) {
1041
+ if (sessions.length === 0) return "No recent sessions.\n";
1042
+ return `${sessions.map((session) => `${session.id} ${session.projectPath}/${session.branchName} ${session.name ?? "(unnamed)"}`).join("\n")}
1043
+ `;
1044
+ }
1045
+ function renderWorkspaceStatus(status) {
1046
+ const lines = [
1047
+ `Workspace HEAD: ${status.head ?? "(not initialized)"}`,
1048
+ `Latest sync: ${status.latestSync ? `${status.latestSync.outcome} on ${status.latestSync.workerLabel}` : "(none)"}`,
1049
+ `Remediation: ${status.incident ? `${status.incident.status} (${status.incident.id}) on ${status.incident.originWorkerLabel}` : "none"}`
1050
+ ];
1051
+ return `${lines.join("\n")}
1052
+ `;
1053
+ }
1054
+ function renderWorkspaceSync(result) {
1055
+ const head = result.publishedHead ?? result.candidateHead ?? result.startingHead ?? "(none)";
1056
+ const discarded = result.discardedPaths.length > 0 ? `
1057
+ Discarded paths: ${result.discardedPaths.join(", ")}` : "";
1058
+ const error = result.error ? `
1059
+ Error: ${result.error}` : "";
1060
+ return `Workspace sync ${result.outcome} on ${result.workerLabel}; HEAD ${head}; ${result.diffSizeBytes} bytes.${discarded}${error}
1061
+ `;
1062
+ }
992
1063
  function renderSessionDescription(session) {
993
1064
  return [`Session: ${session.id}`, `Project: ${session.projectPath}`, `Branch: ${session.branchName}`].join("\n") + "\n";
994
1065
  }
@@ -1040,33 +1111,26 @@ function renderProcessHistory(processes, nowMs = Date.now()) {
1040
1111
  return processes.length === 0 ? "No process history.\n" : renderProcessList(processes, nowMs);
1041
1112
  }
1042
1113
  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
1114
  return [
1047
1115
  `Run: ${process2.runId}`,
1048
- `Status: ${process2.status} / sync ${process2.syncState}`,
1116
+ `Status: ${process2.status}`,
1049
1117
  `Mode: ${process2.mode}`,
1050
1118
  `Worker: ${process2.workerLabel} (${process2.platform ?? "unknown"}/${process2.arch ?? "unknown"})`,
1051
1119
  `Project: ${process2.projectPath} ${process2.branchName}`,
1052
1120
  `Session: ${process2.sessionId}`,
1053
1121
  `Command: ${process2.command}`,
1054
1122
  `Argv: ${JSON.stringify(process2.argv)}`,
1055
- `CWD: ${process2.cwd ?? "(default checkout)"}`,
1123
+ `CWD: ${process2.cwd ?? "(project root)"}`,
1056
1124
  `PID/process group: ${process2.pid ?? "(unknown)"}/${process2.processGroupId ?? "(unknown)"}`,
1057
- `Starting canonical commit: ${process2.startCommitHash}`,
1058
1125
  `Started: ${process2.startedAt}`,
1059
1126
  `Updated: ${process2.updatedAt}`,
1060
1127
  `Completed: ${process2.completedAt ?? "(running)"}`,
1061
1128
  `Exit code: ${process2.exitCode ?? "(none)"}`,
1062
1129
  `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,
1130
+ `Workspace sync: ${process2.workspaceSync ? `${process2.workspaceSync.outcome} (${process2.workspaceSync.attemptId})` : "(pending or not observed)"}`,
1131
+ ...process2.workspaceSync?.affectedProjects.length ? [`Repositories observed during synchronization: ${process2.workspaceSync.affectedProjects.join(", ")}`] : [],
1132
+ ...process2.workspaceSync?.discardedPaths.length ? [`Discarded paths: ${process2.workspaceSync.discardedPaths.join(", ")}`] : [],
1133
+ `Log: ${process2.logPath}`,
1070
1134
  "",
1071
1135
  `stdout tail${process2.stdoutTailTruncated ? " (truncated)" : ""}:`,
1072
1136
  process2.stdoutTail || "(empty)",
@@ -1345,6 +1409,23 @@ async function executeR5dctlCommand(client, json, args) {
1345
1409
  write(result, "API key revoked.\n");
1346
1410
  return;
1347
1411
  }
1412
+ if (first === "workspace" && second === "status") {
1413
+ if (args.length > 2) throw new Error(`Unexpected workspace status argument: ${args[2]}`);
1414
+ const status = await client.workspace.status();
1415
+ write(status, renderWorkspaceStatus(status));
1416
+ return;
1417
+ }
1418
+ if (first === "workspace" && second === "sync") {
1419
+ const result = await client.workspace.sync(parseWorkspaceWorkerArgs(args.slice(2)));
1420
+ write(result, renderWorkspaceSync(result));
1421
+ return;
1422
+ }
1423
+ if (first === "workspace" && second === "reset") {
1424
+ const parsed = parseWorkspaceWorkerArgs(args.slice(2), { allowConfirm: true });
1425
+ const result = await client.workspace.reset({ worker: parsed.worker, confirmed: true });
1426
+ write(result, renderWorkspaceSync(result));
1427
+ return;
1428
+ }
1348
1429
  if (first === "ps" && second === "list") {
1349
1430
  const processes = await client.processes.list(parsePsListArgs(args.slice(2)));
1350
1431
  write(processes, renderProcessList(processes));
@@ -1356,6 +1437,7 @@ async function executeR5dctlCommand(client, json, args) {
1356
1437
  return;
1357
1438
  }
1358
1439
  if (first === "ps" && second === "inspect") {
1440
+ if (args.length > 3) throw new Error(`Unexpected ps inspect value: ${args[3]}`);
1359
1441
  const process2 = await client.processes.inspect(requireValue(args[2], "Missing process run id"));
1360
1442
  write(process2, renderProcessInspection(process2));
1361
1443
  return;
@@ -1366,6 +1448,11 @@ async function executeR5dctlCommand(client, json, args) {
1366
1448
  `);
1367
1449
  return;
1368
1450
  }
1451
+ if (first === "sessions" && second === "recent") {
1452
+ const sessions = await client.sessions.recent(parseRecentSessionArgs(args.slice(2)));
1453
+ write(sessions, renderRecentSessionList(sessions));
1454
+ return;
1455
+ }
1369
1456
  if (first === "projects" && second === "list" || first === "get" && second === "projects") {
1370
1457
  const projects = await client.projects.list();
1371
1458
  write(projects, renderProjectList(projects));
@@ -1603,7 +1690,7 @@ function resolveCommandExecution(options, rest) {
1603
1690
  pluginArgs: [...normalizedRest, "--help"]
1604
1691
  };
1605
1692
  }
1606
- if (command === "projects" || command === "sessions") {
1693
+ if (command === "projects" || command === "sessions" || command === "workspace") {
1607
1694
  return {
1608
1695
  kind: "plugin",
1609
1696
  pluginArgs: normalizedRest
@@ -1690,11 +1777,11 @@ function resolveCommandExecution(options, rest) {
1690
1777
  ["--project", filters.project],
1691
1778
  ["--branch", filters.branch],
1692
1779
  ["--session", filters.session],
1693
- ["--worker", filters.worker],
1694
- ["--limit", filters.limit?.toString()]
1780
+ ["--worker", filters.worker]
1695
1781
  ]) {
1696
1782
  if (value) pluginArgs.push(flag, value);
1697
1783
  }
1784
+ if (filters.limit !== void 0) pluginArgs.push("--limit", String(filters.limit));
1698
1785
  return { kind: "plugin", pluginArgs };
1699
1786
  }
1700
1787
  if (subcommand === "inspect") {
@@ -2145,6 +2232,8 @@ async function main(argv = process.argv.slice(2)) {
2145
2232
  renderProcessHistory,
2146
2233
  renderProcessInspection,
2147
2234
  renderProcessList,
2235
+ renderWorkspaceStatus,
2236
+ renderWorkspaceSync,
2148
2237
  resolveCommandExecution,
2149
2238
  runR5dctlCli,
2150
2239
  summarizeEnvData
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.35",
3
+ "version": "0.0.37",
4
4
  "type": "commonjs"
5
5
  }
package/dist/mjs/cli.mjs CHANGED
@@ -15,7 +15,6 @@ const CHAT_MODES = /* @__PURE__ */ new Set([
15
15
  "build",
16
16
  "agent",
17
17
  "explore",
18
- "review",
19
18
  "test",
20
19
  "research",
21
20
  "security_review",
@@ -80,6 +79,17 @@ const SHARED_HELP_ENTRIES = [
80
79
  },
81
80
  { section: "auth", usage: "auth api-key list", description: "List API keys for the current account." },
82
81
  { section: "auth", usage: "auth api-key revoke <key-id>", description: "Revoke an API key." },
82
+ { section: "workspace", usage: "workspace status", description: "Inspect the per-user canonical workspace and active remediation." },
83
+ {
84
+ section: "workspace",
85
+ usage: "workspace sync [--worker <label>]",
86
+ description: "Publish a connected worker into the canonical workspace now."
87
+ },
88
+ {
89
+ section: "workspace",
90
+ usage: "workspace reset [--worker <label>] --confirm",
91
+ description: "Destructively discard a blocked remediation candidate and restore canonical state."
92
+ },
83
93
  { section: "projects", usage: "get projects", description: "List projects you can access." },
84
94
  { section: "projects", usage: "describe project <namespace/name|id>", description: "Show details for a project." },
85
95
  { section: "projects", usage: "update project <namespace/name|id> --mode <greenfield|prod>", description: "Update project settings." },
@@ -106,6 +116,11 @@ const SHARED_HELP_ENTRIES = [
106
116
  usage: "-p <project> get sessions [--branch <branch>]",
107
117
  description: "List sessions for a project, optionally filtered by branch."
108
118
  },
119
+ {
120
+ section: "sessions",
121
+ usage: "sessions recent [--limit <n>]",
122
+ description: "List the most recently active sessions across your projects."
123
+ },
109
124
  {
110
125
  section: "sessions",
111
126
  usage: "-p <project> create session -b <branch> [--name <name>]",
@@ -157,7 +172,7 @@ const SHARED_HELP_ENTRIES = [
157
172
  {
158
173
  section: "processes",
159
174
  usage: "ps inspect <run-id>",
160
- description: "Inspect execution, synchronization, repository outcomes, and bounded output tails."
175
+ description: "Inspect process metadata and bounded stdout/stderr tails."
161
176
  },
162
177
  { section: "processes", usage: "ps stop <run-id>", description: "Gracefully stop an active process with SIGTERM." },
163
178
  {
@@ -177,6 +192,7 @@ const SHARED_HELP_ENTRIES = [
177
192
  ];
178
193
  const HELP_SECTION_ORDER = [
179
194
  "auth",
195
+ "workspace",
180
196
  "projects",
181
197
  "branches",
182
198
  "envs",
@@ -188,6 +204,7 @@ const HELP_SECTION_ORDER = [
188
204
  ];
189
205
  const HELP_SECTION_TITLES = {
190
206
  auth: "Auth",
207
+ workspace: "Canonical workspace",
191
208
  projects: "Projects",
192
209
  branches: "Branches",
193
210
  envs: "Environment variables",
@@ -798,6 +815,35 @@ function parsePsHistoryArgs(args) {
798
815
  }
799
816
  return { ...parsePsListArgs(filterArgs), ...limit !== void 0 ? { limit } : {} };
800
817
  }
818
+ function parseWorkspaceWorkerArgs(args, options = {}) {
819
+ let worker;
820
+ let confirmed = false;
821
+ for (let index = 0; index < args.length; index += 1) {
822
+ const arg = args[index];
823
+ if (arg === "--worker" || arg?.startsWith("--worker=")) {
824
+ if (worker) throw new Error("Use only one --worker value");
825
+ worker = requireValue(arg === "--worker" ? args[++index] : parseLongOptionWithEquals(arg, "--worker"), "Missing value for --worker");
826
+ continue;
827
+ }
828
+ if (arg === "--confirm" && options.allowConfirm) {
829
+ confirmed = true;
830
+ continue;
831
+ }
832
+ throw new Error(`Unknown workspace argument: ${arg ?? ""}`.trim());
833
+ }
834
+ if (options.allowConfirm && !confirmed) throw new Error("workspace reset requires --confirm");
835
+ return { ...worker ? { worker } : {}, ...confirmed ? { confirmed: true } : {} };
836
+ }
837
+ function parseRecentSessionArgs(args) {
838
+ if (args.length === 0) return {};
839
+ if (args.length > 2 || args[0] !== "--limit" && !args[0]?.startsWith("--limit=")) {
840
+ throw new Error(`Unknown sessions recent argument: ${args[0] ?? ""}`.trim());
841
+ }
842
+ const raw = args[0] === "--limit" ? args[1] : parseLongOptionWithEquals(args[0], "--limit");
843
+ const limit = Number(requireValue(raw, "Missing value for --limit"));
844
+ if (!Number.isInteger(limit) || limit < 1 || limit > 200) throw new Error("--limit must be an integer between 1 and 200");
845
+ return { limit };
846
+ }
801
847
  async function openInBrowser(url) {
802
848
  if (process.platform === "darwin") {
803
849
  spawn("open", [url], { stdio: "ignore", detached: true }).unref();
@@ -936,6 +982,29 @@ function renderSessionList(sessions) {
936
982
  return `${sessions.map((session) => `${session.id} ${session.branchName} ${session.name ?? "(unnamed)"}`).join("\n")}
937
983
  `;
938
984
  }
985
+ function renderRecentSessionList(sessions) {
986
+ if (sessions.length === 0) return "No recent sessions.\n";
987
+ return `${sessions.map((session) => `${session.id} ${session.projectPath}/${session.branchName} ${session.name ?? "(unnamed)"}`).join("\n")}
988
+ `;
989
+ }
990
+ function renderWorkspaceStatus(status) {
991
+ const lines = [
992
+ `Workspace HEAD: ${status.head ?? "(not initialized)"}`,
993
+ `Latest sync: ${status.latestSync ? `${status.latestSync.outcome} on ${status.latestSync.workerLabel}` : "(none)"}`,
994
+ `Remediation: ${status.incident ? `${status.incident.status} (${status.incident.id}) on ${status.incident.originWorkerLabel}` : "none"}`
995
+ ];
996
+ return `${lines.join("\n")}
997
+ `;
998
+ }
999
+ function renderWorkspaceSync(result) {
1000
+ const head = result.publishedHead ?? result.candidateHead ?? result.startingHead ?? "(none)";
1001
+ const discarded = result.discardedPaths.length > 0 ? `
1002
+ Discarded paths: ${result.discardedPaths.join(", ")}` : "";
1003
+ const error = result.error ? `
1004
+ Error: ${result.error}` : "";
1005
+ return `Workspace sync ${result.outcome} on ${result.workerLabel}; HEAD ${head}; ${result.diffSizeBytes} bytes.${discarded}${error}
1006
+ `;
1007
+ }
939
1008
  function renderSessionDescription(session) {
940
1009
  return [`Session: ${session.id}`, `Project: ${session.projectPath}`, `Branch: ${session.branchName}`].join("\n") + "\n";
941
1010
  }
@@ -987,33 +1056,26 @@ function renderProcessHistory(processes, nowMs = Date.now()) {
987
1056
  return processes.length === 0 ? "No process history.\n" : renderProcessList(processes, nowMs);
988
1057
  }
989
1058
  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
1059
  return [
994
1060
  `Run: ${process2.runId}`,
995
- `Status: ${process2.status} / sync ${process2.syncState}`,
1061
+ `Status: ${process2.status}`,
996
1062
  `Mode: ${process2.mode}`,
997
1063
  `Worker: ${process2.workerLabel} (${process2.platform ?? "unknown"}/${process2.arch ?? "unknown"})`,
998
1064
  `Project: ${process2.projectPath} ${process2.branchName}`,
999
1065
  `Session: ${process2.sessionId}`,
1000
1066
  `Command: ${process2.command}`,
1001
1067
  `Argv: ${JSON.stringify(process2.argv)}`,
1002
- `CWD: ${process2.cwd ?? "(default checkout)"}`,
1068
+ `CWD: ${process2.cwd ?? "(project root)"}`,
1003
1069
  `PID/process group: ${process2.pid ?? "(unknown)"}/${process2.processGroupId ?? "(unknown)"}`,
1004
- `Starting canonical commit: ${process2.startCommitHash}`,
1005
1070
  `Started: ${process2.startedAt}`,
1006
1071
  `Updated: ${process2.updatedAt}`,
1007
1072
  `Completed: ${process2.completedAt ?? "(running)"}`,
1008
1073
  `Exit code: ${process2.exitCode ?? "(none)"}`,
1009
1074
  `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,
1075
+ `Workspace sync: ${process2.workspaceSync ? `${process2.workspaceSync.outcome} (${process2.workspaceSync.attemptId})` : "(pending or not observed)"}`,
1076
+ ...process2.workspaceSync?.affectedProjects.length ? [`Repositories observed during synchronization: ${process2.workspaceSync.affectedProjects.join(", ")}`] : [],
1077
+ ...process2.workspaceSync?.discardedPaths.length ? [`Discarded paths: ${process2.workspaceSync.discardedPaths.join(", ")}`] : [],
1078
+ `Log: ${process2.logPath}`,
1017
1079
  "",
1018
1080
  `stdout tail${process2.stdoutTailTruncated ? " (truncated)" : ""}:`,
1019
1081
  process2.stdoutTail || "(empty)",
@@ -1292,6 +1354,23 @@ async function executeR5dctlCommand(client, json, args) {
1292
1354
  write(result, "API key revoked.\n");
1293
1355
  return;
1294
1356
  }
1357
+ if (first === "workspace" && second === "status") {
1358
+ if (args.length > 2) throw new Error(`Unexpected workspace status argument: ${args[2]}`);
1359
+ const status = await client.workspace.status();
1360
+ write(status, renderWorkspaceStatus(status));
1361
+ return;
1362
+ }
1363
+ if (first === "workspace" && second === "sync") {
1364
+ const result = await client.workspace.sync(parseWorkspaceWorkerArgs(args.slice(2)));
1365
+ write(result, renderWorkspaceSync(result));
1366
+ return;
1367
+ }
1368
+ if (first === "workspace" && second === "reset") {
1369
+ const parsed = parseWorkspaceWorkerArgs(args.slice(2), { allowConfirm: true });
1370
+ const result = await client.workspace.reset({ worker: parsed.worker, confirmed: true });
1371
+ write(result, renderWorkspaceSync(result));
1372
+ return;
1373
+ }
1295
1374
  if (first === "ps" && second === "list") {
1296
1375
  const processes = await client.processes.list(parsePsListArgs(args.slice(2)));
1297
1376
  write(processes, renderProcessList(processes));
@@ -1303,6 +1382,7 @@ async function executeR5dctlCommand(client, json, args) {
1303
1382
  return;
1304
1383
  }
1305
1384
  if (first === "ps" && second === "inspect") {
1385
+ if (args.length > 3) throw new Error(`Unexpected ps inspect value: ${args[3]}`);
1306
1386
  const process2 = await client.processes.inspect(requireValue(args[2], "Missing process run id"));
1307
1387
  write(process2, renderProcessInspection(process2));
1308
1388
  return;
@@ -1313,6 +1393,11 @@ async function executeR5dctlCommand(client, json, args) {
1313
1393
  `);
1314
1394
  return;
1315
1395
  }
1396
+ if (first === "sessions" && second === "recent") {
1397
+ const sessions = await client.sessions.recent(parseRecentSessionArgs(args.slice(2)));
1398
+ write(sessions, renderRecentSessionList(sessions));
1399
+ return;
1400
+ }
1316
1401
  if (first === "projects" && second === "list" || first === "get" && second === "projects") {
1317
1402
  const projects = await client.projects.list();
1318
1403
  write(projects, renderProjectList(projects));
@@ -1550,7 +1635,7 @@ function resolveCommandExecution(options, rest) {
1550
1635
  pluginArgs: [...normalizedRest, "--help"]
1551
1636
  };
1552
1637
  }
1553
- if (command === "projects" || command === "sessions") {
1638
+ if (command === "projects" || command === "sessions" || command === "workspace") {
1554
1639
  return {
1555
1640
  kind: "plugin",
1556
1641
  pluginArgs: normalizedRest
@@ -1637,11 +1722,11 @@ function resolveCommandExecution(options, rest) {
1637
1722
  ["--project", filters.project],
1638
1723
  ["--branch", filters.branch],
1639
1724
  ["--session", filters.session],
1640
- ["--worker", filters.worker],
1641
- ["--limit", filters.limit?.toString()]
1725
+ ["--worker", filters.worker]
1642
1726
  ]) {
1643
1727
  if (value) pluginArgs.push(flag, value);
1644
1728
  }
1729
+ if (filters.limit !== void 0) pluginArgs.push("--limit", String(filters.limit));
1645
1730
  return { kind: "plugin", pluginArgs };
1646
1731
  }
1647
1732
  if (subcommand === "inspect") {
@@ -2091,6 +2176,8 @@ export {
2091
2176
  renderProcessHistory,
2092
2177
  renderProcessInspection,
2093
2178
  renderProcessList,
2179
+ renderWorkspaceStatus,
2180
+ renderWorkspaceSync,
2094
2181
  resolveCommandExecution,
2095
2182
  runR5dctlCli,
2096
2183
  summarizeEnvData
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.35",
3
+ "version": "0.0.37",
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 R5dctlProcessInspection, 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 R5dctlProcessInspection, type R5dctlProcessListInput, type R5dctlProcessRun, type R5dctlWorkspaceStatus, type R5dctlWorkspaceSyncResult, type ChatMode, type ModelTier } from "@ricsam/r5d-api";
2
2
  export type GlobalOptions = {
3
3
  baseUrl?: string;
4
4
  json: boolean;
@@ -62,6 +62,8 @@ export declare function parseShellArgs(args: string[]): {
62
62
  };
63
63
  export declare function parsePsListArgs(args: string[]): R5dctlProcessListInput;
64
64
  export declare function parsePsHistoryArgs(args: string[]): R5dctlProcessListInput;
65
+ export declare function renderWorkspaceStatus(status: R5dctlWorkspaceStatus): string;
66
+ export declare function renderWorkspaceSync(result: R5dctlWorkspaceSyncResult): string;
65
67
  export declare function formatProcessAge(startedAt: string, nowMs?: number): string;
66
68
  export declare function renderProcessList(processes: R5dctlProcessRun[], nowMs?: number): string;
67
69
  export declare function renderProcessHistory(processes: R5dctlProcessRun[], nowMs?: number): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ricsam/r5dctl",
3
- "version": "0.0.35",
3
+ "version": "0.0.37",
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.35",
29
+ "@ricsam/r5d-api": "^0.0.37",
30
30
  "dotenv": "^17",
31
31
  "ws": "^8.18.3"
32
32
  },