@ricsam/r5dctl 0.0.127 → 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/README.md +35 -1
- package/dist/cjs/cli.cjs +60 -7
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/cli.mjs +60 -7
- package/dist/mjs/package.json +1 -1
- package/dist/types/account.d.ts +67 -0
- package/dist/types/cli.d.ts +4 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @ricsam/r5dctl
|
|
2
2
|
|
|
3
|
-
CLI for managing r5d.dev
|
|
3
|
+
CLI for managing r5d.dev account instructions, environment variables, secret files, projects, branches, and sessions.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -39,6 +39,40 @@ Credentials are stored in:
|
|
|
39
39
|
- `-b, --branch <branch>`
|
|
40
40
|
- `-s, --session <sessionId>`
|
|
41
41
|
|
|
42
|
+
## Account instructions and credentials
|
|
43
|
+
|
|
44
|
+
The same commands work for authenticated users and agents. They manage the authenticated account across all projects, workspaces, and workers. Project, branch, and session flags do not narrow their scope.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
r5dctl account instructions get > AGENTS.md
|
|
48
|
+
r5dctl account instructions set --file AGENTS.md
|
|
49
|
+
cat AGENTS.md | r5dctl account instructions set --stdin
|
|
50
|
+
printf '' | r5dctl account instructions set --stdin # clear account instructions
|
|
51
|
+
r5dctl --json account instructions get
|
|
52
|
+
|
|
53
|
+
r5dctl account env list
|
|
54
|
+
r5dctl account env set API_TOKEN --description "Service API access" --file ./api-token.txt
|
|
55
|
+
r5dctl account env set REGION --description "Default region" --value eu-north-1
|
|
56
|
+
cat ./api-token.txt | r5dctl account env set API_TOKEN --stdin
|
|
57
|
+
r5dctl account env set API_TOKEN --description "Updated purpose" # preserve its value
|
|
58
|
+
r5dctl account env revoke API_TOKEN # remove the value, retain its metadata
|
|
59
|
+
r5dctl account env delete API_TOKEN # remove the entry
|
|
60
|
+
|
|
61
|
+
r5dctl account secrets list
|
|
62
|
+
r5dctl account secrets set KUBECONFIG --description "Personal Kubernetes access" --file ~/.kube/config
|
|
63
|
+
cat ./private-key.pem | r5dctl account secrets set PRIVATE_KEY_FILE --description "Signing key" --stdin
|
|
64
|
+
r5dctl account secrets revoke PRIVATE_KEY_FILE
|
|
65
|
+
r5dctl account secrets delete PRIVATE_KEY_FILE
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`instructions get` writes the saved AGENTS.md content exactly, with no extra newline. With `--json`, it returns an object containing `content` and `updatedAt`. Setting instructions requires exactly one of `--file` or `--stdin`; empty input clears them. File and stdin input must be UTF-8, and leading/trailing whitespace, line endings, and a UTF-8 BOM are preserved. Stdin is read only with an explicit `--stdin` flag.
|
|
69
|
+
|
|
70
|
+
`env` entries are delivered as environment variable values. `secrets` entries are delivered as protected files, with each entry's environment variable containing the file path. Both kinds are encrypted at rest. Their names share one account namespace and must be valid environment variable names, at most 128 characters; `R5D_` and `R5DCTL_` prefixes are reserved. The CLI refuses to change an entry's kind through the other command group.
|
|
71
|
+
|
|
72
|
+
New entries require `--description` and one value source. Existing entries preserve their description when the flag is omitted, and preserve their value when only a description is supplied. `--value` is supported only for `env`; use `--file` or `--stdin` for secret files and sensitive environment values so contents are absent from shell arguments and history. Explicit empty input sets an empty value; use `revoke` to remove the value. Lists show metadata and whether a value is configured, including under `--json`; neither lists nor mutation responses print values. There is no command to read stored credential values.
|
|
73
|
+
|
|
74
|
+
Updates and revocations affect future command delivery. Existing commands and interactive shells keep their current environment until they finish or are restarted. Revoke does not invalidate a credential at its provider or remove a copy already retained by a process; rotate the provider credential when that is needed.
|
|
75
|
+
|
|
42
76
|
## Common Commands
|
|
43
77
|
|
|
44
78
|
```bash
|
package/dist/cjs/cli.cjs
CHANGED
|
@@ -116,6 +116,7 @@ var import_promises = require("node:timers/promises");
|
|
|
116
116
|
var import_dotenv = require("dotenv");
|
|
117
117
|
var import_r5d_api = require("@ricsam/r5d-api");
|
|
118
118
|
var import_shell = require("./shell.cjs");
|
|
119
|
+
var import_account = require("./account.cjs");
|
|
119
120
|
const CHAT_MODES = /* @__PURE__ */ new Set(["plan", "agent", "large_diff_remediation"]);
|
|
120
121
|
const R5DCTL_SESSION_MODES = /* @__PURE__ */ new Set(["plan", "agent"]);
|
|
121
122
|
const R5DCTL_PROMPT_DELIVERIES = /* @__PURE__ */ new Set(["queue", "steer", "force"]);
|
|
@@ -199,6 +200,7 @@ const SESSION_RUN_HELP_TEXT = [
|
|
|
199
200
|
""
|
|
200
201
|
].join("\n");
|
|
201
202
|
const SHARED_HELP_ENTRIES = [
|
|
203
|
+
...import_account.ACCOUNT_HELP_ENTRIES.map((entry) => ({ ...entry, section: "account" })),
|
|
202
204
|
{ section: "auth", usage: "auth status", description: "Show the current authenticated user and credential source." },
|
|
203
205
|
{ section: "auth", usage: "auth logout", description: "Revoke the current credential and clear saved auth." },
|
|
204
206
|
{
|
|
@@ -377,6 +379,7 @@ const SHARED_HELP_ENTRIES = [
|
|
|
377
379
|
];
|
|
378
380
|
const HELP_SECTION_ORDER = [
|
|
379
381
|
"auth",
|
|
382
|
+
"account",
|
|
380
383
|
"workspace",
|
|
381
384
|
"projects",
|
|
382
385
|
"branches",
|
|
@@ -387,6 +390,7 @@ const HELP_SECTION_ORDER = [
|
|
|
387
390
|
];
|
|
388
391
|
const HELP_SECTION_TITLES = {
|
|
389
392
|
auth: "Auth",
|
|
393
|
+
account: "Account instructions, environment variables, and secret files",
|
|
390
394
|
workspace: "Canonical workspace",
|
|
391
395
|
projects: "Projects",
|
|
392
396
|
branches: "Branches",
|
|
@@ -715,7 +719,10 @@ async function deleteBranchThroughPlatform(client, projectRef, branchName, optio
|
|
|
715
719
|
const branchId = branch.branchId;
|
|
716
720
|
let accepted;
|
|
717
721
|
try {
|
|
718
|
-
accepted = await requireServerRouteSupport(
|
|
722
|
+
accepted = await requireServerRouteSupport(
|
|
723
|
+
"delete branch",
|
|
724
|
+
() => client.projects.branches.delete(projectRef, branchName, { branchId })
|
|
725
|
+
);
|
|
719
726
|
} catch (error) {
|
|
720
727
|
const landed = error instanceof import_r5d_api.R5dctlApiError ? await resolveUncertainAcceptance(client, projectRef, branchId, error) : null;
|
|
721
728
|
if (!landed) throw error;
|
|
@@ -1056,12 +1063,31 @@ function parseGlobalArgs(argv) {
|
|
|
1056
1063
|
version: false
|
|
1057
1064
|
};
|
|
1058
1065
|
const rest = [];
|
|
1066
|
+
const seenGlobalFlags = /* @__PURE__ */ new Set();
|
|
1067
|
+
let duplicateGlobalFlag;
|
|
1059
1068
|
for (let i = 0; i < argv.length; i += 1) {
|
|
1060
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
|
+
}
|
|
1061
1079
|
if (!arg) {
|
|
1062
1080
|
continue;
|
|
1063
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
|
+
}
|
|
1064
1089
|
if (arg === "--") {
|
|
1090
|
+
if (rest[0] === "account") rest.push(arg);
|
|
1065
1091
|
rest.push(...argv.slice(i + 1));
|
|
1066
1092
|
break;
|
|
1067
1093
|
}
|
|
@@ -1142,6 +1168,7 @@ function parseGlobalArgs(argv) {
|
|
|
1142
1168
|
}
|
|
1143
1169
|
rest.push(arg);
|
|
1144
1170
|
}
|
|
1171
|
+
if (rest[0] === "account" && duplicateGlobalFlag) throw new Error(`${duplicateGlobalFlag} may only be provided once`);
|
|
1145
1172
|
return { options, rest };
|
|
1146
1173
|
}
|
|
1147
1174
|
function parseConfig(configPath) {
|
|
@@ -1820,7 +1847,9 @@ function renderSessionList(sessions, nowMs = Date.now()) {
|
|
|
1820
1847
|
if (sessions.length === 0) {
|
|
1821
1848
|
return "No sessions found.\n";
|
|
1822
1849
|
}
|
|
1823
|
-
return `${sessions.map(
|
|
1850
|
+
return `${sessions.map(
|
|
1851
|
+
(session) => [session.id, session.branchName, formatSessionActivity(session, nowMs), session.name ?? "(unnamed)"].filter(Boolean).join(" ")
|
|
1852
|
+
).join("\n")}
|
|
1824
1853
|
`;
|
|
1825
1854
|
}
|
|
1826
1855
|
function renderRecentSessionList(sessions) {
|
|
@@ -2853,7 +2882,9 @@ async function executeR5dctlCommand(client, json, args) {
|
|
|
2853
2882
|
});
|
|
2854
2883
|
write(result2, renderSessionClaimResponse(result2, nowMs));
|
|
2855
2884
|
if (result2.outcome === "held_by_other") {
|
|
2856
|
-
throw new Error(
|
|
2885
|
+
throw new Error(
|
|
2886
|
+
`Claim ${claim.topic} is held by session ${result2.claim.holderSessionId} until ${result2.claim.expiresAt}; not acquired`
|
|
2887
|
+
);
|
|
2857
2888
|
}
|
|
2858
2889
|
return;
|
|
2859
2890
|
}
|
|
@@ -2873,12 +2904,20 @@ async function executeR5dctlCommand(client, json, args) {
|
|
|
2873
2904
|
return;
|
|
2874
2905
|
}
|
|
2875
2906
|
if (!current.heldByActor) {
|
|
2876
|
-
write(
|
|
2907
|
+
write(
|
|
2908
|
+
{ outcome: "not_holder", actorSessionId: list.actorSessionId, claim: current },
|
|
2909
|
+
renderSessionClaimResponse({ outcome: "not_holder", actorSessionId: list.actorSessionId, claim: current }, nowMs)
|
|
2910
|
+
);
|
|
2877
2911
|
throw new Error(`Claim ${claim.topic} is held by session ${current.holderSessionId}, not by ${list.actorSessionId}`);
|
|
2878
2912
|
}
|
|
2879
2913
|
generation = current.generation;
|
|
2880
2914
|
}
|
|
2881
|
-
const result = claim.action === "renew" ? await client.claims.renew({
|
|
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 });
|
|
2882
2921
|
write(result, renderSessionClaimResponse(result, nowMs));
|
|
2883
2922
|
const succeeded = result.outcome === "renewed" || result.outcome === "released" || claim.action === "release" && result.outcome === "missing";
|
|
2884
2923
|
if (!succeeded) throw new Error(`Claim ${claim.topic}: ${CLAIM_OUTCOME_TEXT[result.outcome] ?? result.outcome}`);
|
|
@@ -2995,7 +3034,10 @@ ${result.deletion ? `Deletion: ${result.deletion.status}${result.deletion.error
|
|
|
2995
3034
|
const offset = first === "describe" ? 2 : 3;
|
|
2996
3035
|
const projectRef = requireValue(args[offset], "Missing project reference");
|
|
2997
3036
|
const branchId = requireValue(args[offset + 1], "Missing branch id");
|
|
2998
|
-
const status = await requireServerRouteSupport(
|
|
3037
|
+
const status = await requireServerRouteSupport(
|
|
3038
|
+
"describe branch-deletion",
|
|
3039
|
+
() => client.projects.branches.describeDeletion(projectRef, branchId)
|
|
3040
|
+
);
|
|
2999
3041
|
write(status, renderBranchDeletionStatus(status));
|
|
3000
3042
|
return;
|
|
3001
3043
|
}
|
|
@@ -3140,13 +3182,20 @@ ${result.deletion ? `Deletion: ${result.deletion.status}${result.deletion.error
|
|
|
3140
3182
|
throw new Error(`Unknown command: ${args.join(" ")}`);
|
|
3141
3183
|
}
|
|
3142
3184
|
function resolveCommandExecution(options, rest) {
|
|
3143
|
-
const
|
|
3185
|
+
const accountLiteralHelp = rest[0] === "account" && ["--value", "--file", "--description"].includes(rest.at(-2) ?? "");
|
|
3186
|
+
const trailingHelp = isHelpFlag(rest.at(-1)) && !accountLiteralHelp;
|
|
3144
3187
|
const normalizedRest = trailingHelp ? rest.slice(0, -1) : rest;
|
|
3145
3188
|
const command = normalizedRest[0];
|
|
3146
3189
|
if (!command) {
|
|
3147
3190
|
throw new Error("Missing command");
|
|
3148
3191
|
}
|
|
3149
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
|
+
}
|
|
3150
3199
|
if (command === "ps" && commandArgs.length === 0) {
|
|
3151
3200
|
return {
|
|
3152
3201
|
kind: "cli-help",
|
|
@@ -3658,6 +3707,10 @@ async function runCommand(argv) {
|
|
|
3658
3707
|
const clientOptions = resolveClientOptions(options, config);
|
|
3659
3708
|
const client = new import_r5d_api.R5dctlClient(clientOptions);
|
|
3660
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
|
+
}
|
|
3661
3714
|
if (execution.kind === "auth-login") {
|
|
3662
3715
|
await handleAuthLogin(client, options, execution.commandArgs, config);
|
|
3663
3716
|
return 0;
|
package/dist/cjs/package.json
CHANGED
package/dist/mjs/cli.mjs
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
R5dctlClient
|
|
12
12
|
} from "@ricsam/r5d-api";
|
|
13
13
|
import { runR5dctlShell } from "./shell.mjs";
|
|
14
|
+
import { ACCOUNT_HELP_ENTRIES, executeAccountCommand, getAccountHelp, parseAccountCommand } from "./account.mjs";
|
|
14
15
|
const CHAT_MODES = /* @__PURE__ */ new Set(["plan", "agent", "large_diff_remediation"]);
|
|
15
16
|
const R5DCTL_SESSION_MODES = /* @__PURE__ */ new Set(["plan", "agent"]);
|
|
16
17
|
const R5DCTL_PROMPT_DELIVERIES = /* @__PURE__ */ new Set(["queue", "steer", "force"]);
|
|
@@ -94,6 +95,7 @@ const SESSION_RUN_HELP_TEXT = [
|
|
|
94
95
|
""
|
|
95
96
|
].join("\n");
|
|
96
97
|
const SHARED_HELP_ENTRIES = [
|
|
98
|
+
...ACCOUNT_HELP_ENTRIES.map((entry) => ({ ...entry, section: "account" })),
|
|
97
99
|
{ section: "auth", usage: "auth status", description: "Show the current authenticated user and credential source." },
|
|
98
100
|
{ section: "auth", usage: "auth logout", description: "Revoke the current credential and clear saved auth." },
|
|
99
101
|
{
|
|
@@ -272,6 +274,7 @@ const SHARED_HELP_ENTRIES = [
|
|
|
272
274
|
];
|
|
273
275
|
const HELP_SECTION_ORDER = [
|
|
274
276
|
"auth",
|
|
277
|
+
"account",
|
|
275
278
|
"workspace",
|
|
276
279
|
"projects",
|
|
277
280
|
"branches",
|
|
@@ -282,6 +285,7 @@ const HELP_SECTION_ORDER = [
|
|
|
282
285
|
];
|
|
283
286
|
const HELP_SECTION_TITLES = {
|
|
284
287
|
auth: "Auth",
|
|
288
|
+
account: "Account instructions, environment variables, and secret files",
|
|
285
289
|
workspace: "Canonical workspace",
|
|
286
290
|
projects: "Projects",
|
|
287
291
|
branches: "Branches",
|
|
@@ -610,7 +614,10 @@ async function deleteBranchThroughPlatform(client, projectRef, branchName, optio
|
|
|
610
614
|
const branchId = branch.branchId;
|
|
611
615
|
let accepted;
|
|
612
616
|
try {
|
|
613
|
-
accepted = await requireServerRouteSupport(
|
|
617
|
+
accepted = await requireServerRouteSupport(
|
|
618
|
+
"delete branch",
|
|
619
|
+
() => client.projects.branches.delete(projectRef, branchName, { branchId })
|
|
620
|
+
);
|
|
614
621
|
} catch (error) {
|
|
615
622
|
const landed = error instanceof R5dctlApiError ? await resolveUncertainAcceptance(client, projectRef, branchId, error) : null;
|
|
616
623
|
if (!landed) throw error;
|
|
@@ -951,12 +958,31 @@ function parseGlobalArgs(argv) {
|
|
|
951
958
|
version: false
|
|
952
959
|
};
|
|
953
960
|
const rest = [];
|
|
961
|
+
const seenGlobalFlags = /* @__PURE__ */ new Set();
|
|
962
|
+
let duplicateGlobalFlag;
|
|
954
963
|
for (let i = 0; i < argv.length; i += 1) {
|
|
955
964
|
const arg = argv[i];
|
|
965
|
+
if (rest[0] === "account" && (arg === "--value" || arg === "--file" || arg === "--description")) {
|
|
966
|
+
rest.push(arg);
|
|
967
|
+
if (i + 1 < argv.length) rest.push(argv[++i]);
|
|
968
|
+
continue;
|
|
969
|
+
}
|
|
970
|
+
if (rest[0] === "account" && arg === "") {
|
|
971
|
+
rest.push(arg);
|
|
972
|
+
continue;
|
|
973
|
+
}
|
|
956
974
|
if (!arg) {
|
|
957
975
|
continue;
|
|
958
976
|
}
|
|
977
|
+
const globalName = { "-p": "--project", "-b": "--branch", "-s": "--session", "-h": "--help", "-v": "--version" }[arg] ?? arg.split("=", 1)[0];
|
|
978
|
+
if (["--base-url", "--json", "--config", "--token", "--api-key", "--project", "--branch", "--session", "--help", "--version"].includes(
|
|
979
|
+
globalName
|
|
980
|
+
)) {
|
|
981
|
+
if (seenGlobalFlags.has(globalName)) duplicateGlobalFlag ??= globalName;
|
|
982
|
+
seenGlobalFlags.add(globalName);
|
|
983
|
+
}
|
|
959
984
|
if (arg === "--") {
|
|
985
|
+
if (rest[0] === "account") rest.push(arg);
|
|
960
986
|
rest.push(...argv.slice(i + 1));
|
|
961
987
|
break;
|
|
962
988
|
}
|
|
@@ -1037,6 +1063,7 @@ function parseGlobalArgs(argv) {
|
|
|
1037
1063
|
}
|
|
1038
1064
|
rest.push(arg);
|
|
1039
1065
|
}
|
|
1066
|
+
if (rest[0] === "account" && duplicateGlobalFlag) throw new Error(`${duplicateGlobalFlag} may only be provided once`);
|
|
1040
1067
|
return { options, rest };
|
|
1041
1068
|
}
|
|
1042
1069
|
function parseConfig(configPath) {
|
|
@@ -1715,7 +1742,9 @@ function renderSessionList(sessions, nowMs = Date.now()) {
|
|
|
1715
1742
|
if (sessions.length === 0) {
|
|
1716
1743
|
return "No sessions found.\n";
|
|
1717
1744
|
}
|
|
1718
|
-
return `${sessions.map(
|
|
1745
|
+
return `${sessions.map(
|
|
1746
|
+
(session) => [session.id, session.branchName, formatSessionActivity(session, nowMs), session.name ?? "(unnamed)"].filter(Boolean).join(" ")
|
|
1747
|
+
).join("\n")}
|
|
1719
1748
|
`;
|
|
1720
1749
|
}
|
|
1721
1750
|
function renderRecentSessionList(sessions) {
|
|
@@ -2748,7 +2777,9 @@ async function executeR5dctlCommand(client, json, args) {
|
|
|
2748
2777
|
});
|
|
2749
2778
|
write(result2, renderSessionClaimResponse(result2, nowMs));
|
|
2750
2779
|
if (result2.outcome === "held_by_other") {
|
|
2751
|
-
throw new Error(
|
|
2780
|
+
throw new Error(
|
|
2781
|
+
`Claim ${claim.topic} is held by session ${result2.claim.holderSessionId} until ${result2.claim.expiresAt}; not acquired`
|
|
2782
|
+
);
|
|
2752
2783
|
}
|
|
2753
2784
|
return;
|
|
2754
2785
|
}
|
|
@@ -2768,12 +2799,20 @@ async function executeR5dctlCommand(client, json, args) {
|
|
|
2768
2799
|
return;
|
|
2769
2800
|
}
|
|
2770
2801
|
if (!current.heldByActor) {
|
|
2771
|
-
write(
|
|
2802
|
+
write(
|
|
2803
|
+
{ outcome: "not_holder", actorSessionId: list.actorSessionId, claim: current },
|
|
2804
|
+
renderSessionClaimResponse({ outcome: "not_holder", actorSessionId: list.actorSessionId, claim: current }, nowMs)
|
|
2805
|
+
);
|
|
2772
2806
|
throw new Error(`Claim ${claim.topic} is held by session ${current.holderSessionId}, not by ${list.actorSessionId}`);
|
|
2773
2807
|
}
|
|
2774
2808
|
generation = current.generation;
|
|
2775
2809
|
}
|
|
2776
|
-
const result = claim.action === "renew" ? await client.claims.renew({
|
|
2810
|
+
const result = claim.action === "renew" ? await client.claims.renew({
|
|
2811
|
+
topic: claim.topic,
|
|
2812
|
+
...scope,
|
|
2813
|
+
generation,
|
|
2814
|
+
...claim.ttlSeconds !== void 0 ? { ttlSeconds: claim.ttlSeconds } : {}
|
|
2815
|
+
}) : await client.claims.release({ topic: claim.topic, ...scope, generation });
|
|
2777
2816
|
write(result, renderSessionClaimResponse(result, nowMs));
|
|
2778
2817
|
const succeeded = result.outcome === "renewed" || result.outcome === "released" || claim.action === "release" && result.outcome === "missing";
|
|
2779
2818
|
if (!succeeded) throw new Error(`Claim ${claim.topic}: ${CLAIM_OUTCOME_TEXT[result.outcome] ?? result.outcome}`);
|
|
@@ -2890,7 +2929,10 @@ ${result.deletion ? `Deletion: ${result.deletion.status}${result.deletion.error
|
|
|
2890
2929
|
const offset = first === "describe" ? 2 : 3;
|
|
2891
2930
|
const projectRef = requireValue(args[offset], "Missing project reference");
|
|
2892
2931
|
const branchId = requireValue(args[offset + 1], "Missing branch id");
|
|
2893
|
-
const status = await requireServerRouteSupport(
|
|
2932
|
+
const status = await requireServerRouteSupport(
|
|
2933
|
+
"describe branch-deletion",
|
|
2934
|
+
() => client.projects.branches.describeDeletion(projectRef, branchId)
|
|
2935
|
+
);
|
|
2894
2936
|
write(status, renderBranchDeletionStatus(status));
|
|
2895
2937
|
return;
|
|
2896
2938
|
}
|
|
@@ -3035,13 +3077,20 @@ ${result.deletion ? `Deletion: ${result.deletion.status}${result.deletion.error
|
|
|
3035
3077
|
throw new Error(`Unknown command: ${args.join(" ")}`);
|
|
3036
3078
|
}
|
|
3037
3079
|
function resolveCommandExecution(options, rest) {
|
|
3038
|
-
const
|
|
3080
|
+
const accountLiteralHelp = rest[0] === "account" && ["--value", "--file", "--description"].includes(rest.at(-2) ?? "");
|
|
3081
|
+
const trailingHelp = isHelpFlag(rest.at(-1)) && !accountLiteralHelp;
|
|
3039
3082
|
const normalizedRest = trailingHelp ? rest.slice(0, -1) : rest;
|
|
3040
3083
|
const command = normalizedRest[0];
|
|
3041
3084
|
if (!command) {
|
|
3042
3085
|
throw new Error("Missing command");
|
|
3043
3086
|
}
|
|
3044
3087
|
const commandArgs = normalizedRest.slice(1);
|
|
3088
|
+
if (command === "account") {
|
|
3089
|
+
if (trailingHelp || commandArgs.length <= 1) {
|
|
3090
|
+
return { kind: "cli-help", text: getAccountHelp(commandArgs.slice(0, 2)) };
|
|
3091
|
+
}
|
|
3092
|
+
return { kind: "account", command: parseAccountCommand(commandArgs) };
|
|
3093
|
+
}
|
|
3045
3094
|
if (command === "ps" && commandArgs.length === 0) {
|
|
3046
3095
|
return {
|
|
3047
3096
|
kind: "cli-help",
|
|
@@ -3553,6 +3602,10 @@ async function runCommand(argv) {
|
|
|
3553
3602
|
const clientOptions = resolveClientOptions(options, config);
|
|
3554
3603
|
const client = new R5dctlClient(clientOptions);
|
|
3555
3604
|
const execution = resolveCommandExecution(options, rest);
|
|
3605
|
+
if (execution.kind === "account") {
|
|
3606
|
+
await executeAccountCommand(client, execution.command, options.json);
|
|
3607
|
+
return 0;
|
|
3608
|
+
}
|
|
3556
3609
|
if (execution.kind === "auth-login") {
|
|
3557
3610
|
await handleAuthLogin(client, options, execution.commandArgs, config);
|
|
3558
3611
|
return 0;
|
package/dist/mjs/package.json
CHANGED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { type R5dctlClient } from "@ricsam/r5d-api";
|
|
2
|
+
export declare const ACCOUNT_HELP_ENTRIES: readonly [{
|
|
3
|
+
readonly usage: "account instructions get";
|
|
4
|
+
readonly description: "Write account AGENTS.md exactly to stdout; --json prints its metadata and content.";
|
|
5
|
+
}, {
|
|
6
|
+
readonly usage: "account instructions set (--file <path>|--stdin)";
|
|
7
|
+
readonly description: "Replace account AGENTS.md, including clearing it with empty input.";
|
|
8
|
+
}, {
|
|
9
|
+
readonly usage: "account env list";
|
|
10
|
+
readonly description: "List account environment variable metadata without revealing values.";
|
|
11
|
+
}, {
|
|
12
|
+
readonly usage: "account env set <name> [--description <text>] [--value <value>|--file <path>|--stdin]";
|
|
13
|
+
readonly description: "Set an account environment variable, or edit an existing entry's description.";
|
|
14
|
+
}, {
|
|
15
|
+
readonly usage: "account env revoke <name>";
|
|
16
|
+
readonly description: "Remove the stored value while retaining its name and description.";
|
|
17
|
+
}, {
|
|
18
|
+
readonly usage: "account env delete <name>";
|
|
19
|
+
readonly description: "Delete an account environment entry.";
|
|
20
|
+
}, {
|
|
21
|
+
readonly usage: "account secrets list";
|
|
22
|
+
readonly description: "List account secret-file metadata without revealing contents.";
|
|
23
|
+
}, {
|
|
24
|
+
readonly usage: "account secrets set <name> [--description <text>] [--file <path>|--stdin]";
|
|
25
|
+
readonly description: "Store a secret file whose path is delivered through the named environment variable.";
|
|
26
|
+
}, {
|
|
27
|
+
readonly usage: "account secrets revoke <name>";
|
|
28
|
+
readonly description: "Remove a stored secret file's contents while retaining its metadata.";
|
|
29
|
+
}, {
|
|
30
|
+
readonly usage: "account secrets delete <name>";
|
|
31
|
+
readonly description: "Delete an account secret-file entry.";
|
|
32
|
+
}];
|
|
33
|
+
type ValueSource = {
|
|
34
|
+
kind: "value";
|
|
35
|
+
value: string;
|
|
36
|
+
} | {
|
|
37
|
+
kind: "file";
|
|
38
|
+
path: string;
|
|
39
|
+
} | {
|
|
40
|
+
kind: "stdin";
|
|
41
|
+
};
|
|
42
|
+
export type AccountCommand = {
|
|
43
|
+
group: "instructions";
|
|
44
|
+
action: "get";
|
|
45
|
+
} | {
|
|
46
|
+
group: "instructions";
|
|
47
|
+
action: "set";
|
|
48
|
+
source: ValueSource;
|
|
49
|
+
} | {
|
|
50
|
+
group: "env" | "secrets";
|
|
51
|
+
action: "list";
|
|
52
|
+
} | {
|
|
53
|
+
group: "env" | "secrets";
|
|
54
|
+
action: "set";
|
|
55
|
+
name: string;
|
|
56
|
+
description?: string;
|
|
57
|
+
source?: ValueSource;
|
|
58
|
+
} | {
|
|
59
|
+
group: "env" | "secrets";
|
|
60
|
+
action: "revoke" | "delete";
|
|
61
|
+
name: string;
|
|
62
|
+
};
|
|
63
|
+
/** Keep input values out of every parser error, including unknown flags and operands. */
|
|
64
|
+
export declare function parseAccountCommand(args: string[]): AccountCommand;
|
|
65
|
+
export declare function getAccountHelp(args: string[]): string;
|
|
66
|
+
export declare function executeAccountCommand(client: R5dctlClient, command: AccountCommand, json: boolean): Promise<void>;
|
|
67
|
+
export {};
|
package/dist/types/cli.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { R5dctlApiError, R5dctlClient, type R5dctlConversationForkResponse, type R5dctlConversationHeadResponse, type R5dctlConversationRenderOptions, type R5dctlConversationResponse, type R5dctlConversationNodeResponse, type R5dctlConversationOverviewResponse, type R5dctlConversationWorkDetail, type R5dctlConversationWorkResponse, type R5dctlEnvData, type R5dctlProcessInspection, type R5dctlProcessListInput, type R5dctlProcessLog, type R5dctlProcessRun, type R5dctlWorkerCapacityReport, type R5dctlBranch, type R5dctlBranchDeletionStatus, type R5dctlBranchDescription, type R5dctlBranchOperation, type R5dctlSessionSummary, type R5dctlSessionClaim, type R5dctlSessionClaimListResponse, type R5dctlSessionEvent, type R5dctlSessionStartInput, type R5dctlWorkspaceStatus, type R5dctlWorkspaceSyncResult, type R5dctlWorkingTreeMode, type R5dctlWorktreeSource, type R5dctlPromptDelivery, type R5dctlSessionMode, type ChatMode, type ModelTier } from "@ricsam/r5d-api";
|
|
2
|
+
import { type AccountCommand } from "./account";
|
|
2
3
|
export type GlobalOptions = {
|
|
3
4
|
baseUrl?: string;
|
|
4
5
|
json: boolean;
|
|
@@ -17,6 +18,9 @@ export type R5dctlConfig = {
|
|
|
17
18
|
apiKey?: string;
|
|
18
19
|
};
|
|
19
20
|
type CommandExecutionPlan = {
|
|
21
|
+
kind: "account";
|
|
22
|
+
command: AccountCommand;
|
|
23
|
+
} | {
|
|
20
24
|
kind: "plugin";
|
|
21
25
|
pluginArgs: string[];
|
|
22
26
|
clearAuthOnSuccess?: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ricsam/r5dctl",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.128",
|
|
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.128",
|
|
30
30
|
"dotenv": "^17",
|
|
31
31
|
"qrcode": "^1.5.4",
|
|
32
32
|
"ws": "^8.18.3"
|