@retell-ai/retell-cli 0.7.0 → 0.9.0

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 CHANGED
@@ -40,7 +40,9 @@ retell auth whoami
40
40
  retell auth logout
41
41
  ```
42
42
 
43
- `retell auth login` reports any current credential by source and masks its value. Press Enter to keep an existing keychain/config credential, or enter a new key to replace it. If `RETELL_API_KEY` is set, it remains authoritative; run `unset RETELL_API_KEY` in the current shell before logging in with a different active key.
43
+ `retell auth login` reports any current credential by source, and its org and API key name if it's still valid. Press Enter to keep an existing keychain/config credential, or enter a new key to replace it. A new key is validated against the Retell API before it's stored — invalid keys are rejected and nothing is written to disk. If `RETELL_API_KEY` is set, it remains authoritative; run `unset RETELL_API_KEY` in the current shell before logging in with a different active key.
44
+
45
+ `retell auth whoami` shows the org, API key name, and credential source, without printing the raw key value.
44
46
 
45
47
  `retell auth logout` clears keychain/config credentials and verifies that they are gone. It cannot unset `RETELL_API_KEY` in the parent shell, so it prints a warning when the environment variable keeps authentication active.
46
48
 
@@ -65,4 +67,4 @@ For password, token, or API-key request fields, prefer `--body -` or stdin so th
65
67
 
66
68
  Use `--dry-run` to inspect a redacted request without sending it.
67
69
 
68
- `--base-url` is intended for trusted development servers and proxies. The CLI sends the configured Retell bearer credential to the overridden URL, matching the Retell SDK behavior. API requests time out after 60 seconds, except multipart/file-upload requests, which time out after 300 seconds.
70
+ `--base-url` is intended for trusted development servers and proxies. The CLI sends the configured Retell bearer credential to the overridden URL, matching the Retell SDK behavior. API requests time out after 60 seconds, except multipart/file-upload requests, which time out after 300 seconds.
@@ -3,7 +3,7 @@ export const catalogMetadata = {
3
3
  "title": "Retell SDK",
4
4
  "apiVersion": "3.0.0",
5
5
  "server": "https://api.retellai.com",
6
- "sourceSha256": "cc08c5273d301322a16e22fd70291fef4e653ecb3cccd81ce2bdb307e1c31968",
6
+ "sourceSha256": "bf6aa757ac4071a5740c53352c070217f94e2fd1d4631e529c53dabc3461b237",
7
7
  "operationCount": 81
8
8
  };
9
9
  export const schemaDefinitions = {
@@ -9437,7 +9437,7 @@ export const operations = [
9437
9437
  "deprecated": false,
9438
9438
  "authenticated": true,
9439
9439
  "parameters": [],
9440
- "responseContractHash": "d4d6024d778dacf042a8c11156c6ac38f1b5ecdb6c6a681e586193919e8a6b30"
9440
+ "responseContractHash": "83a410882e0a73c1d43433f23611e69ad2d9b5ceb5ab1b370c5799d7f2c0c14a"
9441
9441
  },
9442
9442
  {
9443
9443
  "operationId": "getBatchTest",
package/dist/src/index.js CHANGED
@@ -8,7 +8,10 @@ import { sendRequest } from "./runtime/http.js";
8
8
  import { renderOutput, resolveOutputFormat } from "./runtime/output.js";
9
9
  import { dryRunOutput, prepareRequest } from "./runtime/request.js";
10
10
  import { cliVersion } from "./runtime/version.js";
11
- const operations = generatedOperations;
11
+ // getApiKeyInfo backs `auth login`/`auth whoami` internally; hidden from direct
12
+ // use so it isn't a general-purpose way to dump org_id/api_key_name.
13
+ const HIDDEN_OPERATION_IDS = new Set(["getApiKeyInfo"]);
14
+ const operations = generatedOperations.filter((operation) => !HIDDEN_OPERATION_IDS.has(operation.operationId));
12
15
  async function main() {
13
16
  const [first, ...rest] = process.argv.slice(2);
14
17
  if (!first || first === "--help" || first === "-h" || first === "help" && !rest[0]) {
@@ -24,6 +27,9 @@ async function main() {
24
27
  return;
25
28
  }
26
29
  const commandName = first === "help" ? rest.shift() : first;
30
+ if (commandName === "get-api-key-info") {
31
+ throw new Error("get-api-key-info isn't a standalone command. Use 'retell auth login' or 'retell auth whoami' instead.");
32
+ }
27
33
  const operation = operations.find((candidate) => candidate.command === commandName);
28
34
  if (!operation)
29
35
  throw new Error(`Unknown command: ${commandName}. Run 'retell --help' to list commands.`);
@@ -1,16 +1,48 @@
1
- import { clearApiKey, maskApiKey, resolveApiKey, storeApiKey } from "./credentials.js";
1
+ import { clearApiKey, resolveApiKey, storeApiKey } from "./credentials.js";
2
+ import { catalogMetadata } from "../generated/operations.js";
3
+ import { fetchApiKeyIdentity } from "./identity.js";
4
+ const defaultBaseUrl = catalogMetadata.server;
2
5
  function authHelp() {
3
6
  return `Manage Retell API authentication.\n\n` +
4
7
  `Usage:\n` +
5
- ` retell auth login [--with-token]\n` +
6
- ` retell auth whoami\n` +
8
+ ` retell auth login [--with-token] [--base-url <URL>]\n` +
9
+ ` retell auth whoami [--base-url <URL>]\n` +
7
10
  ` retell auth logout\n\n` +
8
11
  `Commands:\n` +
9
- ` login Prompt for and securely store a Retell API key\n` +
10
- ` whoami Show whether authentication is configured and its source\n` +
12
+ ` login Validate and securely store a Retell API key\n` +
13
+ ` whoami Show authentication status and the org/key it belongs to\n` +
11
14
  ` logout Delete the stored Retell API key\n\n` +
12
15
  `RETELL_API_KEY overrides any stored credential.\n`;
13
16
  }
17
+ /**
18
+ * Prints org/key identity first (or a soft warning if the live check fails),
19
+ * then a blank line, then the given status line and credential source.
20
+ * Shared by login's "Already authenticated" message and `whoami`.
21
+ */
22
+ async function printCredentialStatus(credential, baseUrl, statusLine) {
23
+ if (credential.value) {
24
+ try {
25
+ const identity = await fetchApiKeyIdentity(credential.value, baseUrl);
26
+ process.stdout.write(`Org: ${identity.orgName}\n`);
27
+ if (identity.apiKeyName)
28
+ process.stdout.write(`API key name: ${identity.apiKeyName}\n`);
29
+ }
30
+ catch (error) {
31
+ process.stdout.write(`Could not verify this key with the Retell API: ${error instanceof Error ? error.message : String(error)}\n`);
32
+ }
33
+ }
34
+ process.stdout.write(`${statusLine}\nSource: ${credential.source}\n`);
35
+ }
36
+ /** Extracts `--base-url <URL>` from an auth subcommand's options, returning the remaining options. */
37
+ function takeBaseUrl(options) {
38
+ const index = options.indexOf("--base-url");
39
+ if (index === -1)
40
+ return { rest: options };
41
+ const value = options[index + 1];
42
+ if (value === undefined)
43
+ throw new Error("--base-url requires a value");
44
+ return { baseUrl: value, rest: [...options.slice(0, index), ...options.slice(index + 2)] };
45
+ }
14
46
  async function readAllStdin() {
15
47
  const chunks = [];
16
48
  for await (const chunk of process.stdin)
@@ -61,42 +93,46 @@ export async function handleAuth(tokens) {
61
93
  return;
62
94
  }
63
95
  if (command === "login") {
64
- if (options.some((option) => option !== "--with-token" && option !== "--help" && option !== "-h")) {
65
- throw new Error(`Unknown auth login option: ${options.find((option) => !["--with-token", "--help", "-h"].includes(option))}`);
96
+ const { baseUrl, rest: loginOptions } = takeBaseUrl(options);
97
+ if (loginOptions.some((option) => option !== "--with-token" && option !== "--help" && option !== "-h")) {
98
+ throw new Error(`Unknown auth login option: ${loginOptions.find((option) => !["--with-token", "--help", "-h"].includes(option))}`);
66
99
  }
67
- if (options.includes("--help") || options.includes("-h")) {
100
+ if (loginOptions.includes("--help") || loginOptions.includes("-h")) {
68
101
  process.stdout.write(`Store a Retell API key.\n\nUsage:\n retell auth login\n printf '%s' "$RETELL_API_KEY" | retell auth login --with-token\n`);
69
102
  return;
70
103
  }
71
104
  const current = await resolveApiKey();
72
105
  if (current.source !== "unset") {
73
- process.stdout.write(`Already authenticated.\nSource: ${current.source}\nAPI key: ${maskApiKey(current.value)}\n`);
106
+ await printCredentialStatus(current, baseUrl ?? defaultBaseUrl, "Already authenticated.");
74
107
  }
75
108
  if (current.source === "env") {
76
109
  const guidance = "RETELL_API_KEY overrides stored credentials. Run 'unset RETELL_API_KEY' in this shell before logging in with a different key.";
77
- if (options.includes("--with-token"))
110
+ if (loginOptions.includes("--with-token"))
78
111
  throw new Error(guidance);
79
112
  process.stdout.write(`${guidance}\n`);
80
113
  return;
81
114
  }
82
- const token = options.includes("--with-token")
115
+ const token = loginOptions.includes("--with-token")
83
116
  ? await readAllStdin()
84
117
  : await promptHidden(current.source === "unset" ? "Retell API key: " : "New Retell API key (press Enter to keep current): ");
85
118
  if (!token.trim() && current.source !== "unset") {
86
119
  process.stdout.write("Existing Retell API key kept unchanged.\n");
87
120
  return;
88
121
  }
122
+ const identity = await fetchApiKeyIdentity(token.trim(), baseUrl ?? defaultBaseUrl);
89
123
  const source = await storeApiKey(token);
90
124
  process.stdout.write(source === "keyring"
91
125
  ? "Retell API key stored in the OS keychain.\n"
92
126
  : "OS keychain unavailable; Retell API key stored in ~/.config/retell/credentials.json with mode 0600.\n");
127
+ process.stdout.write(`Logged in to ${identity.orgName}${identity.apiKeyName ? ` as key "${identity.apiKeyName}"` : ""}.\n`);
93
128
  return;
94
129
  }
95
130
  if (command === "whoami") {
131
+ const { baseUrl, rest: whoamiOptions } = takeBaseUrl(options);
132
+ if (whoamiOptions.length)
133
+ throw new Error(`Unknown auth whoami option: ${whoamiOptions[0]}`);
96
134
  const credential = await resolveApiKey();
97
- process.stdout.write(`Authentication: ${credential.source === "unset" ? "not configured" : "configured"}\n`);
98
- process.stdout.write(`Source: ${credential.source}\n`);
99
- process.stdout.write(`API key: ${maskApiKey(credential.value)}\n`);
135
+ await printCredentialStatus(credential, baseUrl ?? defaultBaseUrl, `Authentication: ${credential.source === "unset" ? "not configured" : "configured"}`);
100
136
  return;
101
137
  }
102
138
  if (command === "logout") {
@@ -0,0 +1,38 @@
1
+ import { operations } from "../generated/operations.js";
2
+ import { sendRequest } from "./http.js";
3
+ import { prepareRequest } from "./request.js";
4
+ const getApiKeyInfoOperation = operations.find((operation) => operation.operationId === "getApiKeyInfo");
5
+ function emptyArgs() {
6
+ return {
7
+ pathValues: new Map(),
8
+ queryValues: new Map(),
9
+ headerValues: new Map(),
10
+ cookieValues: new Map(),
11
+ bodyValues: new Map(),
12
+ multipartValues: new Map(),
13
+ dryRun: false,
14
+ };
15
+ }
16
+ /** Calls GET /get-api-key-info to confirm an API key is valid and fetch its org/key identity. */
17
+ export async function fetchApiKeyIdentity(apiKey, baseUrl, fetchImplementation = fetch) {
18
+ if (!getApiKeyInfoOperation)
19
+ throw new Error("getApiKeyInfo operation is missing from the generated catalog.");
20
+ const request = await prepareRequest(getApiKeyInfoOperation, emptyArgs(), apiKey, baseUrl);
21
+ const response = await sendRequest(getApiKeyInfoOperation, request.url, request.init, fetchImplementation);
22
+ const text = await response.text();
23
+ const value = text ? (() => { try {
24
+ return JSON.parse(text);
25
+ }
26
+ catch {
27
+ return text;
28
+ } })() : null;
29
+ if (!response.ok) {
30
+ if (response.status === 401)
31
+ throw new Error("This API key was rejected by the Retell API.");
32
+ throw new Error(`Retell API request failed (${response.status}): ${typeof value === "string" ? value : JSON.stringify(value)}`);
33
+ }
34
+ return {
35
+ orgName: value.org_name,
36
+ apiKeyName: value.api_key_name ?? null,
37
+ };
38
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@retell-ai/retell-cli",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "description": "Generated command line interface for the Retell API",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {