@realtimex/sdk 1.5.0 → 1.6.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/dist/index.d.mts CHANGED
@@ -1660,6 +1660,32 @@ declare class AuthModule {
1660
1660
  getAccessToken(): Promise<AuthTokenResponse | null>;
1661
1661
  }
1662
1662
 
1663
+ /**
1664
+ * Credentials Module — read-only access to user-managed credentials
1665
+ *
1666
+ * Credential values are encrypted at rest and decrypted only on get().
1667
+ * Values should NEVER be printed to stdout or included in agent responses.
1668
+ */
1669
+
1670
+ interface CredentialInfo {
1671
+ name: string;
1672
+ type: "http_header" | "query_auth" | "basic_auth" | "env_var";
1673
+ metadata: Record<string, any> | null;
1674
+ }
1675
+ interface CredentialPayload {
1676
+ name: string;
1677
+ type: string;
1678
+ payload: Record<string, string>;
1679
+ }
1680
+ declare class CredentialsModule {
1681
+ private httpClient;
1682
+ constructor(httpClient: HttpClient);
1683
+ /** List available credentials (names and types, no values). */
1684
+ list(): Promise<CredentialInfo[]>;
1685
+ /** Get a credential's decrypted payload by name. */
1686
+ get(name: string): Promise<CredentialPayload>;
1687
+ }
1688
+
1663
1689
  interface ContractHttpClientConfig {
1664
1690
  baseUrl: string;
1665
1691
  appId?: string;
@@ -1987,6 +2013,7 @@ declare class RealtimeXSDK {
1987
2013
  contractRuntime: ContractRuntime;
1988
2014
  database: DatabaseModule;
1989
2015
  auth: AuthModule;
2016
+ credentials: CredentialsModule;
1990
2017
  readonly appId: string;
1991
2018
  readonly appName: string | undefined;
1992
2019
  readonly apiKey: string | undefined;
package/dist/index.d.ts CHANGED
@@ -1660,6 +1660,32 @@ declare class AuthModule {
1660
1660
  getAccessToken(): Promise<AuthTokenResponse | null>;
1661
1661
  }
1662
1662
 
1663
+ /**
1664
+ * Credentials Module — read-only access to user-managed credentials
1665
+ *
1666
+ * Credential values are encrypted at rest and decrypted only on get().
1667
+ * Values should NEVER be printed to stdout or included in agent responses.
1668
+ */
1669
+
1670
+ interface CredentialInfo {
1671
+ name: string;
1672
+ type: "http_header" | "query_auth" | "basic_auth" | "env_var";
1673
+ metadata: Record<string, any> | null;
1674
+ }
1675
+ interface CredentialPayload {
1676
+ name: string;
1677
+ type: string;
1678
+ payload: Record<string, string>;
1679
+ }
1680
+ declare class CredentialsModule {
1681
+ private httpClient;
1682
+ constructor(httpClient: HttpClient);
1683
+ /** List available credentials (names and types, no values). */
1684
+ list(): Promise<CredentialInfo[]>;
1685
+ /** Get a credential's decrypted payload by name. */
1686
+ get(name: string): Promise<CredentialPayload>;
1687
+ }
1688
+
1663
1689
  interface ContractHttpClientConfig {
1664
1690
  baseUrl: string;
1665
1691
  appId?: string;
@@ -1987,6 +2013,7 @@ declare class RealtimeXSDK {
1987
2013
  contractRuntime: ContractRuntime;
1988
2014
  database: DatabaseModule;
1989
2015
  auth: AuthModule;
2016
+ credentials: CredentialsModule;
1990
2017
  readonly appId: string;
1991
2018
  readonly appName: string | undefined;
1992
2019
  readonly apiKey: string | undefined;
package/dist/index.js CHANGED
@@ -3009,6 +3009,33 @@ var AuthModule = class {
3009
3009
  }
3010
3010
  };
3011
3011
 
3012
+ // src/modules/credentials.ts
3013
+ var CredentialsModule = class {
3014
+ constructor(httpClient) {
3015
+ this.httpClient = httpClient;
3016
+ }
3017
+ /** List available credentials (names and types, no values). */
3018
+ async list() {
3019
+ const response = await this.httpClient.fetch("/sdk/credentials");
3020
+ const data = await response.json();
3021
+ if (!response.ok) {
3022
+ throw new Error(data?.error || "Failed to list credentials");
3023
+ }
3024
+ return data.credentials || [];
3025
+ }
3026
+ /** Get a credential's decrypted payload by name. */
3027
+ async get(name) {
3028
+ const response = await this.httpClient.fetch(
3029
+ `/sdk/credentials/${encodeURIComponent(name)}`
3030
+ );
3031
+ const data = await response.json();
3032
+ if (!response.ok) {
3033
+ throw new Error(data?.error || `Failed to get credential: ${name}`);
3034
+ }
3035
+ return data.credential;
3036
+ }
3037
+ };
3038
+
3012
3039
  // src/core/auth/AuthProvider.ts
3013
3040
  var StaticAuthProvider = class {
3014
3041
  constructor(options = {}) {
@@ -3706,6 +3733,7 @@ var _RealtimeXSDK = class _RealtimeXSDK {
3706
3733
  });
3707
3734
  this.database = new DatabaseModule(this.realtimexUrl, this.appId, this.apiKey);
3708
3735
  this.auth = new AuthModule(this.realtimexUrl, this.appId, this.apiKey);
3736
+ this.credentials = new CredentialsModule(this.httpClient);
3709
3737
  if (this.permissions.length > 0 && this.appId && !this.apiKey) {
3710
3738
  this.register().catch((err) => {
3711
3739
  console.error("[RealtimeX SDK] Auto-registration failed:", err.message);
package/dist/index.mjs CHANGED
@@ -2916,6 +2916,33 @@ var AuthModule = class {
2916
2916
  }
2917
2917
  };
2918
2918
 
2919
+ // src/modules/credentials.ts
2920
+ var CredentialsModule = class {
2921
+ constructor(httpClient) {
2922
+ this.httpClient = httpClient;
2923
+ }
2924
+ /** List available credentials (names and types, no values). */
2925
+ async list() {
2926
+ const response = await this.httpClient.fetch("/sdk/credentials");
2927
+ const data = await response.json();
2928
+ if (!response.ok) {
2929
+ throw new Error(data?.error || "Failed to list credentials");
2930
+ }
2931
+ return data.credentials || [];
2932
+ }
2933
+ /** Get a credential's decrypted payload by name. */
2934
+ async get(name) {
2935
+ const response = await this.httpClient.fetch(
2936
+ `/sdk/credentials/${encodeURIComponent(name)}`
2937
+ );
2938
+ const data = await response.json();
2939
+ if (!response.ok) {
2940
+ throw new Error(data?.error || `Failed to get credential: ${name}`);
2941
+ }
2942
+ return data.credential;
2943
+ }
2944
+ };
2945
+
2919
2946
  // src/core/auth/AuthProvider.ts
2920
2947
  var StaticAuthProvider = class {
2921
2948
  constructor(options = {}) {
@@ -3613,6 +3640,7 @@ var _RealtimeXSDK = class _RealtimeXSDK {
3613
3640
  });
3614
3641
  this.database = new DatabaseModule(this.realtimexUrl, this.appId, this.apiKey);
3615
3642
  this.auth = new AuthModule(this.realtimexUrl, this.appId, this.apiKey);
3643
+ this.credentials = new CredentialsModule(this.httpClient);
3616
3644
  if (this.permissions.length > 0 && this.appId && !this.apiKey) {
3617
3645
  this.register().catch((err) => {
3618
3646
  console.error("[RealtimeX SDK] Auto-registration failed:", err.message);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@realtimex/sdk",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "SDK for building Local Apps that integrate with RealtimeX",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -1,30 +1,13 @@
1
1
  ---
2
2
  name: realtimex-moderator-sdk
3
3
  description: Control and interact with the RealTimeX application through its Node.js SDK. This skill should be used when users want to manage workspaces, threads, agents, activities, LLM chat, vector store, MCP tools, ACP agent sessions, TTS/STT, or any other RealTimeX platform feature via the API. All method signatures are verified against the SDK source code.
4
- generated: 2026-03-31
5
- sdk_version: 1.5.0
4
+ generated: 2026-04-03
5
+ sdk_version: 1.6.0
6
6
  ---
7
7
 
8
8
  # RealTimeX Moderator (SDK Source-Verified)
9
9
 
10
- Interact with the RealTimeX desktop app (`http://localhost:3001`) using `@realtimex/sdk` **v1.5.0** in Developer Mode (API Key).
11
-
12
- > Auto-generated from the `@realtimex/sdk` TypeScript source.
13
- > Refresh: `node scripts/generate-skill.mjs --force` from the SDK repo root.
14
-
15
- ---
16
-
17
- ## Authentication
18
-
19
- When running inside RealtimeX (via an agent session or on the same machine), authentication is **automatic** — no setup needed.
20
-
21
- Handled by `scripts/lib/sdk-init.js` — credential resolution priority:
22
- 1. Explicit override passed to `initSDK({ apiKey })` or `initSDK({ appId })`
23
- 2. `REALTIMEX_API_KEY` / `REALTIMEX_AI_API_KEY` in `<cwd>/.env`
24
- 3. `RTX_API_KEY` / `REALTIMEX_API_KEY` / `REALTIMEX_AI_API_KEY` from `process.env`
25
- 4. `RTX_APP_ID` from `process.env` (injected by RealtimeX for agents / local apps)
26
- 5. `~/.realtimex.ai/.sdk-app-id` file (written by RealTimeX server on startup)
27
- 6. Interactive readline prompt (dev fallback)
10
+ Interact with the RealTimeX platform (`http://localhost:3001`) using `@realtimex/sdk` **v1.6.0**. Authentication is automatic when running inside RealtimeX.
28
11
 
29
12
  `<SKILL_DIR>` below refers to the directory containing this SKILL.md.
30
13
 
@@ -52,10 +35,13 @@ node "$SKILL" help
52
35
 
53
36
  ```js
54
37
  const { initSDK } = require('<SKILL_DIR>/scripts/lib/sdk-init');
55
- const { sdk, apiKey } = await initSDK({ envDir: process.cwd() });
38
+ const { sdk } = await initSDK();
56
39
  // All SDK APIs — see references/api-reference.md
57
40
  ```
58
41
 
42
+ When writing helper scripts, use the working directory or system temp — never the SKILL directory.
43
+ Scripts using the SDK must exit explicitly — `process.exit(0)` on success, `process.exit(1)` on error — or they hang on open HTTP sockets.
44
+
59
45
  ---
60
46
 
61
47
  ## ACP Session Management
@@ -177,6 +163,28 @@ for await (const event of sdk.acpAgent.streamChat(sessionKey, 'build a website')
177
163
 
178
164
  ---
179
165
 
166
+ ## Credentials
167
+
168
+ Use credentials stored in RealTimeX (Settings > Credentials) to authenticate with external services.
169
+
170
+ **CRITICAL: Never output credential values in your response, logs, or tool output.**
171
+
172
+ ```bash
173
+ node "$SKILL" credentials # List available (names + types, no values)
174
+ ```
175
+
176
+ `sdk.credentials.get(name)` returns `{ name, type, payload }`. Use `payload` fields directly:
177
+ - `http_header` → `{ payload: { name: "Authorization", value: "Bearer xxx" } }` → `headers[payload.name] = payload.value`
178
+ - `basic_auth` → `{ payload: { username, password } }` → encode as Basic auth
179
+ - `query_auth` → `{ payload: { name, value } }` → append as query param
180
+ - `env_var` → `{ payload: { name, value } }` → set in subprocess env
181
+
182
+ Values are **pre-formatted** — use as-is, never wrap with `Bearer` or other prefixes.
183
+
184
+ **Full examples**: See [references/credentials.md](references/credentials.md)
185
+
186
+ ---
187
+
180
188
  ## Critical Rules (source-detected)
181
189
 
182
190
  | # | Issue |
@@ -1,6 +1,6 @@
1
1
  # RealTimeX SDK — API Reference
2
2
 
3
- > Auto-generated from `@realtimex/sdk` source · v**1.5.0** · 2026-03-31
3
+ > Auto-generated from `@realtimex/sdk` source · v**1.6.0** · 2026-04-03
4
4
 
5
5
  **Package:** `@realtimex/sdk` (CJS) · **Server:** `http://localhost:3001`
6
6
  **Developer Mode auth:** `Authorization: Bearer <apiKey>`
@@ -50,6 +50,7 @@
50
50
  - `contractRuntime: ContractRuntime`
51
51
  - `database: DatabaseModule`
52
52
  - `auth: AuthModule`
53
+ - `credentials: CredentialsModule`
53
54
 
54
55
  ```ts
55
56
  // Register app with RealtimeX hub and request declared permissions upfront.
@@ -0,0 +1,111 @@
1
+ # Credentials Reference
2
+
3
+ Credentials are managed by the user in **Settings > Credentials**. Agents have read-only access via `sdk.credentials`.
4
+
5
+ ## Security Rules
6
+
7
+ 1. **Never** print credential values to stdout (they become tool results in chat history)
8
+ 2. **Never** include credential values in your response text
9
+ 3. **Never** write credential values to files or logs
10
+ 4. **Never** pass credential values as CLI arguments (visible in process list)
11
+ 5. **Always** consume credentials inside scripts — fetch, use, discard
12
+ 6. **Always** call `process.exit(0)` at the end of custom scripts (prevents hanging on open HTTP sockets)
13
+ 7. **Never** write helper scripts into the SKILL directory — use the working directory or system temp
14
+
15
+ ## Credential Types
16
+
17
+ | Type | Payload | How to Apply |
18
+ |------|---------|-------------|
19
+ | `http_header` | `{ name, value }` | Set as HTTP header: `headers[payload.name] = payload.value` |
20
+ | `query_auth` | `{ name, value }` | Append to URL: `?${payload.name}=${payload.value}` |
21
+ | `basic_auth` | `{ username, password }` | Encode: `Authorization: Basic ${btoa(username + ":" + password)}` |
22
+ | `env_var` | `{ name, value }` | Set in subprocess: `env[payload.name] = payload.value` |
23
+
24
+ ## Usage Patterns
25
+
26
+ ### List available credentials
27
+
28
+ ```bash
29
+ node "$SKILL" credentials
30
+ ```
31
+
32
+ Output: table of names and types (no values).
33
+
34
+ ### Important: credential payload structure
35
+
36
+ `sdk.credentials.get(name)` returns `{ name, type, payload }`. The `payload` object contains structured fields — use them directly. **Never** extract raw values and construct headers manually.
37
+
38
+ ### Use an http_header credential in a script
39
+
40
+ ```javascript
41
+ const { initSDK } = require('<SKILL_DIR>/scripts/lib/sdk-init');
42
+ (async () => {
43
+ const { sdk } = await initSDK();
44
+ const cred = await sdk.credentials.get('github-token');
45
+ // cred.type === "http_header"
46
+ // cred.payload === { name: "Authorization", value: "Bearer ghp_xxx" }
47
+ // The value already includes the full header value — use as-is
48
+ const res = await fetch('https://api.github.com/user', {
49
+ headers: { [cred.payload.name]: cred.payload.value }
50
+ });
51
+ console.log('Status:', res.status); // Only non-sensitive output
52
+ process.exit(0);
53
+ })();
54
+ // WRONG: const token = cred.payload.value; headers.Authorization = `Bearer ${token}`
55
+ // The value already contains "Bearer ..." — adding prefix again causes 401
56
+ ```
57
+
58
+ ### Use a basic_auth credential
59
+
60
+ ```javascript
61
+ const { initSDK } = require('<SKILL_DIR>/scripts/lib/sdk-init');
62
+ (async () => {
63
+ const { sdk } = await initSDK();
64
+ const cred = await sdk.credentials.get('registry-login');
65
+ const auth = Buffer.from(cred.payload.username + ':' + cred.payload.password).toString('base64');
66
+ const res = await fetch('https://registry.example.com/v2/_catalog', {
67
+ headers: { 'Authorization': 'Basic ' + auth }
68
+ });
69
+ console.log('Status:', res.status);
70
+ process.exit(0);
71
+ })();
72
+ ```
73
+
74
+ ### Use an env_var credential with a subprocess
75
+
76
+ ```javascript
77
+ const { initSDK } = require('<SKILL_DIR>/scripts/lib/sdk-init');
78
+ const { execSync } = require('child_process');
79
+ (async () => {
80
+ const { sdk } = await initSDK();
81
+ const cred = await sdk.credentials.get('aws-key');
82
+ // cred.type === "env_var"
83
+ // cred.payload === { name: "AWS_ACCESS_KEY_ID", value: "AKIA..." }
84
+ execSync('aws s3 ls', {
85
+ env: { ...process.env, [cred.payload.name]: cred.payload.value },
86
+ stdio: 'inherit'
87
+ });
88
+ process.exit(0);
89
+ })();
90
+ ```
91
+
92
+ ### Error handling
93
+
94
+ ```javascript
95
+ const { initSDK } = require('<SKILL_DIR>/scripts/lib/sdk-init');
96
+ (async () => {
97
+ try {
98
+ const { sdk } = await initSDK();
99
+ const cred = await sdk.credentials.get('my-key');
100
+ // use cred...
101
+ process.exit(0);
102
+ } catch (err) {
103
+ if (err.message.includes('not found')) {
104
+ console.log('Credential not found. Ask the user to add it in Settings > Credentials.');
105
+ } else {
106
+ console.log('Error:', err.message);
107
+ }
108
+ process.exit(1);
109
+ }
110
+ })();
111
+ ```
@@ -1,6 +1,6 @@
1
1
  # Known Issues — Source-Detected
2
2
 
3
- > Auto-generated by `scripts/generate-skill.mjs` · SDK **1.5.0** · 2026-03-31
3
+ > Auto-generated by `scripts/generate-skill.mjs` · SDK **1.6.0** · 2026-04-03
4
4
 
5
5
  Run `node scripts/generate-skill.mjs --force` after SDK source changes to refresh.
6
6
 
@@ -1,17 +1,15 @@
1
1
  'use strict';
2
2
  /**
3
- * sdk-init.js — SDK initializer with automatic credential resolution
3
+ * sdk-init.js — SDK initializer
4
4
  * AUTO-GENERATED by scripts/generate-skill.mjs — do not edit by hand.
5
5
  *
6
- * Source reference: typescript/src/index.ts (RealtimeXSDK constructor)
7
- *
8
- * Credential resolution priority:
6
+ * Credential resolution:
9
7
  * 1. Explicit override passed to initSDK({ apiKey } or { appId })
10
- * 2. REALTIMEX_API_KEY / REALTIMEX_AI_API_KEY in <envDir>/.env
11
- * 3. RTX_API_KEY / REALTIMEX_API_KEY / REALTIMEX_AI_API_KEY in process.env
12
- * 4. RTX_APP_ID in process.env (injected by RealtimeX for agents / local apps)
13
- * 5. ~/.realtimex.ai/.sdk-app-id file (written by RealtimeX server on startup)
14
- * 6. Interactive readline prompt (dev fallback)
8
+ * 2. ~/.realtimex.ai/.sdk-app-id file (written by RealtimeX server)
9
+ * 3. RTX_APP_ID in process.env (injected by RealtimeX for local apps)
10
+ * 4. RTX_API_KEY in process.env (standalone dev)
11
+ * 5. REALTIMEX_API_KEY / REALTIMEX_AI_API_KEY in <envDir>/.env (standalone dev)
12
+ * 6. Interactive readline prompt (fallback)
15
13
  */
16
14
 
17
15
  const path = require('path');
@@ -27,7 +25,7 @@ const ALL_PERMISSIONS = [
27
25
  'tts.generate', 'mcp.servers', 'mcp.tools', 'acp.agent',
28
26
  ];
29
27
 
30
- /** Well-known file written by RealtimeX server for seamless SDK auth. */
28
+ /** Well-known file written by RealtimeX server for seamless auth. */
31
29
  const SDK_APP_ID_FILE = path.join(os.homedir(), '.realtimex.ai', '.sdk-app-id');
32
30
 
33
31
  function parseEnvFile(filePath) {
@@ -46,28 +44,16 @@ function parseEnvFile(filePath) {
46
44
  }
47
45
 
48
46
  /**
49
- * Resolve credentials using the full priority chain.
50
- * Returns { apiKey, appId } exactly one will be set.
47
+ * Resolve credentials. The well-known app ID file is checked first so
48
+ * agents running inside RealtimeX authenticate without hitting stale
49
+ * or inherited env vars.
51
50
  */
52
51
  async function resolveCredentials({ envDir, apiKey, appId } = {}) {
53
52
  // 1. Explicit overrides
54
53
  if (apiKey) return { apiKey, appId: null };
55
54
  if (appId) return { apiKey: null, appId };
56
55
 
57
- // 2. .env file
58
- const envVars = parseEnvFile(path.join(envDir || process.cwd(), '.env'));
59
- const fromFile = envVars.REALTIMEX_API_KEY || envVars.REALTIMEX_AI_API_KEY;
60
- if (fromFile) return { apiKey: fromFile, appId: null };
61
-
62
- // 3. Process env — API key
63
- const fromEnv = process.env.RTX_API_KEY || process.env.REALTIMEX_API_KEY || process.env.REALTIMEX_AI_API_KEY;
64
- if (fromEnv) return { apiKey: fromEnv, appId: null };
65
-
66
- // 4. Process env — App ID (injected by RealtimeX for agents / local apps)
67
- const envAppId = process.env.RTX_APP_ID;
68
- if (envAppId) return { apiKey: null, appId: envAppId };
69
-
70
- // 5. Well-known file (written by RealtimeX server on startup)
56
+ // 2. Well-known file (written by RealtimeX server — highest auto priority)
71
57
  try {
72
58
  if (fs.existsSync(SDK_APP_ID_FILE)) {
73
59
  const fileAppId = fs.readFileSync(SDK_APP_ID_FILE, 'utf-8').trim();
@@ -75,7 +61,19 @@ async function resolveCredentials({ envDir, apiKey, appId } = {}) {
75
61
  }
76
62
  } catch { /* ignore read errors */ }
77
63
 
78
- // 6. Interactive prompt (dev fallback)
64
+ // 3. RTX_APP_ID from process.env (injected by Electron for local apps)
65
+ const envAppId = process.env.RTX_APP_ID;
66
+ if (envAppId) return { apiKey: null, appId: envAppId };
67
+
68
+ // 4. RTX_API_KEY from process.env (standalone dev — explicit, no collision risk)
69
+ if (process.env.RTX_API_KEY) return { apiKey: process.env.RTX_API_KEY, appId: null };
70
+
71
+ // 5. .env file (standalone dev)
72
+ const envVars = parseEnvFile(path.join(envDir || process.cwd(), '.env'));
73
+ const fromFile = envVars.RTX_API_KEY || envVars.REALTIMEX_API_KEY || envVars.REALTIMEX_AI_API_KEY;
74
+ if (fromFile) return { apiKey: fromFile, appId: null };
75
+
76
+ // 6. Interactive prompt (fallback)
79
77
  const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
80
78
  const answer = await new Promise((resolve) => {
81
79
  rl.question('RealTimeX API key not found. Enter your API key: ', (ans) => {
@@ -88,19 +86,13 @@ async function resolveCredentials({ envDir, apiKey, appId } = {}) {
88
86
  return { apiKey: null, appId: null };
89
87
  }
90
88
 
91
- /** @deprecated Use resolveCredentials() instead */
92
- async function resolveApiKey(opts = {}) {
93
- const { apiKey } = await resolveCredentials(opts);
94
- return apiKey;
95
- }
96
-
97
89
  async function initSDK(opts = {}) {
98
90
  const { RealtimeXSDK } = require('@realtimex/sdk');
99
91
  const { apiKey, appId } = await resolveCredentials(opts);
100
92
 
101
93
  if (!apiKey && !appId) {
102
94
  throw new Error(
103
- 'No credentials found. Set REALTIMEX_API_KEY in .env, or run inside RealtimeX for automatic auth.'
95
+ 'No credentials found. Run inside RealtimeX for automatic auth, or set RTX_API_KEY.'
104
96
  );
105
97
  }
106
98
 
@@ -116,4 +108,4 @@ async function initSDK(opts = {}) {
116
108
  return { sdk, apiKey: apiKey || null, appId: appId || null };
117
109
  }
118
110
 
119
- module.exports = { initSDK, resolveCredentials, resolveApiKey, parseEnvFile, ALL_PERMISSIONS, SDK_APP_ID_FILE };
111
+ module.exports = { initSDK, resolveCredentials, parseEnvFile, ALL_PERMISSIONS, SDK_APP_ID_FILE };
@@ -304,6 +304,13 @@ CMD['mcp-exec'] = async () => {
304
304
  print(await sdk.mcp.executeTool(server, tool, argsStr ? JSON.parse(argsStr) : {}, flags.provider));
305
305
  };
306
306
 
307
+ // -- credentials ------------------------------------------------------------
308
+ CMD['credentials'] = async () => {
309
+ const { sdk } = await getSDK();
310
+ const list = await sdk.credentials.list();
311
+ printTable(list, ['name', 'type']);
312
+ };
313
+
307
314
  // -- acp-agents -------------------------------------------------------------
308
315
  // Source: AcpAgentModule.listAgents({ includeModels? })
309
316
  // Returns: AcpAgentInfo[] { id, label, handles[], installed, authReady, status }
@@ -797,6 +804,10 @@ sdk.mcp.*:
797
804
  mcp-tools <server> [--provider]
798
805
  mcp-exec <server> <tool> [<args-json>] [--provider]
799
806
 
807
+ sdk.credentials.*:
808
+ credentials
809
+ List available credentials (names and types, no values).
810
+
800
811
  sdk.acpAgent.* — Session Management:
801
812
  acp-agents [--models=true]
802
813
  List available ACP CLI agents.
@@ -871,8 +882,10 @@ sdk.database.* / sdk.auth.*:
871
882
  console.error('Unknown command: ' + (command || '(none)') + '\nRun: node rtx.js help');
872
883
  process.exit(1);
873
884
  }
874
- try { await handler(); }
875
- catch (err) {
885
+ try {
886
+ await handler();
887
+ process.exit(0);
888
+ } catch (err) {
876
889
  console.error('Error:', err.message || err);
877
890
  if (flags.debug) console.error(err);
878
891
  process.exit(1);