@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 +107 -18
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/cli.mjs +105 -18
- package/dist/mjs/package.json +1 -1
- package/dist/types/cli.d.ts +3 -1
- package/package.json +2 -2
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
|
|
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}
|
|
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 ?? "(
|
|
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
|
-
`
|
|
1064
|
-
`
|
|
1065
|
-
`
|
|
1066
|
-
`
|
|
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
|
package/dist/cjs/package.json
CHANGED
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
|
|
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}
|
|
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 ?? "(
|
|
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
|
-
`
|
|
1011
|
-
`
|
|
1012
|
-
`
|
|
1013
|
-
`
|
|
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
|
package/dist/mjs/package.json
CHANGED
package/dist/types/cli.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type R5dctlConversationRenderOptions, type R5dctlConversationResponse, type R5dctlConversationOverviewResponse, type R5dctlConversationWorkDetail, type R5dctlConversationWorkResponse, type R5dctlEnvData, type
|
|
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.
|
|
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.
|
|
29
|
+
"@ricsam/r5d-api": "^0.0.37",
|
|
30
30
|
"dotenv": "^17",
|
|
31
31
|
"ws": "^8.18.3"
|
|
32
32
|
},
|