@tryarcanist/cli 0.1.64 → 0.1.66

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.
Files changed (2) hide show
  1. package/dist/index.js +90 -0
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2070,6 +2070,85 @@ async function stopCommand(sessionId, options = {}, command) {
2070
2070
  );
2071
2071
  }
2072
2072
 
2073
+ // src/commands/test-creds.ts
2074
+ import { readFileSync as readFileSync2 } from "fs";
2075
+ function parseRepoArg(repo) {
2076
+ const trimmed = repo.trim();
2077
+ const slashIndex = trimmed.indexOf("/");
2078
+ if (slashIndex <= 0 || slashIndex === trimmed.length - 1) {
2079
+ throw new CliError("user", `repo must be in the form 'owner/name' (got: '${repo}')`);
2080
+ }
2081
+ return { owner: trimmed.slice(0, slashIndex), name: trimmed.slice(slashIndex + 1) };
2082
+ }
2083
+ function basePath(businessId, repo) {
2084
+ return `/api/businesses/${encodeURIComponent(businessId)}/repos/${encodeURIComponent(repo.owner)}/${encodeURIComponent(repo.name)}/test-credentials`;
2085
+ }
2086
+ function readValue(options) {
2087
+ const sources = [options.value, options.valueFile, options.valueStdin].filter((v) => v !== void 0 && v !== false);
2088
+ if (sources.length !== 1) {
2089
+ throw new CliError("user", "Provide exactly one of --value, --value-file, or --value-stdin.");
2090
+ }
2091
+ if (options.value !== void 0) return options.value;
2092
+ const raw = options.valueFile ? readFileSync2(options.valueFile, "utf8") : readFileSync2(0, "utf8");
2093
+ return raw.replace(/\r?\n$/, "");
2094
+ }
2095
+ async function listTestCredentialsCommand(repo, options, command) {
2096
+ const runtime = getRuntimeOptions(command, options);
2097
+ const config = requireConfig(runtime);
2098
+ const repoArg = parseRepoArg(repo);
2099
+ const payload = await apiFetch(config, basePath(options.business, repoArg));
2100
+ if (isJson(command, options)) {
2101
+ writeJson(payload);
2102
+ return;
2103
+ }
2104
+ if (payload.credentials.length === 0) {
2105
+ console.log(`No test credentials configured for ${repoArg.owner}/${repoArg.name}.`);
2106
+ return;
2107
+ }
2108
+ for (const cred of payload.credentials) {
2109
+ const ts = new Date(cred.updatedAt).toISOString();
2110
+ console.log(`${cred.name} ${ts} ${cred.rotatedByUserId ?? "-"}`);
2111
+ }
2112
+ }
2113
+ async function setTestCredentialCommand(repo, name, options, command) {
2114
+ const runtime = getRuntimeOptions(command, options);
2115
+ const config = requireConfig(runtime);
2116
+ const repoArg = parseRepoArg(repo);
2117
+ const value = readValue(options);
2118
+ const payload = await apiFetch(
2119
+ config,
2120
+ `${basePath(options.business, repoArg)}/${encodeURIComponent(name)}`,
2121
+ { method: "PUT", body: JSON.stringify({ value }) }
2122
+ );
2123
+ if (isJson(command, options)) {
2124
+ writeJson(payload);
2125
+ return;
2126
+ }
2127
+ console.log(`Set test credential '${name}' for ${repoArg.owner}/${repoArg.name}.`);
2128
+ }
2129
+ async function deleteTestCredentialCommand(repo, name, options, command) {
2130
+ if (isJson(command, options) && options.yes !== true) {
2131
+ throw new CliError("user", "`test-creds delete --json` requires --yes.");
2132
+ }
2133
+ if (options.yes !== true) {
2134
+ const repoArg2 = parseRepoArg(repo);
2135
+ await confirmOrThrow(`Delete test credential '${name}' for ${repoArg2.owner}/${repoArg2.name}?`);
2136
+ }
2137
+ const runtime = getRuntimeOptions(command, options);
2138
+ const config = requireConfig(runtime);
2139
+ const repoArg = parseRepoArg(repo);
2140
+ const payload = await apiFetch(
2141
+ config,
2142
+ `${basePath(options.business, repoArg)}/${encodeURIComponent(name)}`,
2143
+ { method: "DELETE" }
2144
+ );
2145
+ if (isJson(command, options)) {
2146
+ writeJson(payload);
2147
+ return;
2148
+ }
2149
+ console.log(`Deleted test credential '${name}' for ${repoArg.owner}/${repoArg.name}.`);
2150
+ }
2151
+
2073
2152
  // src/commands/tokens.ts
2074
2153
  async function listTokensCommand(options, command) {
2075
2154
  const runtime = getRuntimeOptions(command, options);
@@ -2318,6 +2397,17 @@ Examples:
2318
2397
  arcanist tokens revoke 42 --yes --json
2319
2398
  `
2320
2399
  ).action((id, options, command) => revokeTokenCommand(id, options, command));
2400
+ var testCreds = program.command("test-creds").description("Manage repo-scoped test credentials referenced by appRuntime.e2e.credentials in .arcanist.json");
2401
+ testCreds.command("list").description("List test credentials configured for a repo").argument("<repo>", "Repository in 'owner/name' form").requiredOption("--business <id>", "Business ID that owns the repo").action((repo, options, command) => listTestCredentialsCommand(repo, options, command));
2402
+ testCreds.command("set").description("Set or rotate a test credential value").argument("<repo>", "Repository in 'owner/name' form").argument("<name>", "Credential name (must match credentials[].name in .arcanist.json)").requiredOption("--business <id>", "Business ID that owns the repo").option("--value <value>", "Credential value (insecure on shared shells; prefer --value-stdin)").option("--value-file <path>", "Read value from a file").option("--value-stdin", "Read value from stdin").addHelpText(
2403
+ "after",
2404
+ `
2405
+ Examples:
2406
+ echo "$E2E_PASS" | arcanist test-creds set tryarcanist/arcanist test_user_password --business biz-1 --value-stdin
2407
+ arcanist test-creds set tryarcanist/arcanist test_user_email --business biz-1 --value-file ./email.txt
2408
+ `
2409
+ ).action((repo, name, options, command) => setTestCredentialCommand(repo, name, options, command));
2410
+ testCreds.command("delete").description("Delete a test credential").argument("<repo>", "Repository in 'owner/name' form").argument("<name>", "Credential name").requiredOption("--business <id>", "Business ID that owns the repo").option("--yes", "Confirm deletion without prompting").action((repo, name, options, command) => deleteTestCredentialCommand(repo, name, options, command));
2321
2411
  program.command("login").description("Authenticate with a personal access token").option("--token-stdin", "Read token from stdin instead of interactive prompt").option("--api-url <url>", "Set custom API URL").action((options, command) => {
2322
2412
  printDeprecatedAlias("login", "auth login", command);
2323
2413
  return loginCommand(options, command);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tryarcanist/cli",
3
- "version": "0.1.64",
3
+ "version": "0.1.66",
4
4
  "description": "CLI for Arcanist — create and manage coding agent sessions",
5
5
  "type": "module",
6
6
  "bin": {