@realtimex/sdk 1.7.28 → 2.0.1

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 (66) hide show
  1. package/dist/chunk-ORAAYW4C.mjs +271 -0
  2. package/dist/errors-C98IGxYU.d.mts +168 -0
  3. package/dist/errors-C98IGxYU.d.ts +168 -0
  4. package/dist/index.d.mts +8 -2048
  5. package/dist/index.d.ts +8 -2048
  6. package/dist/index.js +168 -4723
  7. package/dist/index.mjs +7 -3783
  8. package/dist/v1/index.d.mts +3 -56
  9. package/dist/v1/index.d.ts +3 -56
  10. package/dist/v1/index.js +2 -756
  11. package/dist/v1/index.mjs +2 -42
  12. package/package.json +6 -7
  13. package/dist/chunk-Z5GAUBIM.mjs +0 -993
  14. package/dist/errors-NufsyIZ-.d.mts +0 -678
  15. package/dist/errors-NufsyIZ-.d.ts +0 -678
  16. package/skills/realtimex-moderator-sdk/SKILL.md +0 -102
  17. package/skills/realtimex-moderator-sdk/references/activities.md +0 -14
  18. package/skills/realtimex-moderator-sdk/references/agents.md +0 -13
  19. package/skills/realtimex-moderator-sdk/references/api-reference/acpagent.md +0 -105
  20. package/skills/realtimex-moderator-sdk/references/api-reference/activities.md +0 -24
  21. package/skills/realtimex-moderator-sdk/references/api-reference/agent.md +0 -27
  22. package/skills/realtimex-moderator-sdk/references/api-reference/api.md +0 -17
  23. package/skills/realtimex-moderator-sdk/references/api-reference/auth.md +0 -36
  24. package/skills/realtimex-moderator-sdk/references/api-reference/contract.md +0 -27
  25. package/skills/realtimex-moderator-sdk/references/api-reference/core.md +0 -40
  26. package/skills/realtimex-moderator-sdk/references/api-reference/database.md +0 -24
  27. package/skills/realtimex-moderator-sdk/references/api-reference/index.md +0 -43
  28. package/skills/realtimex-moderator-sdk/references/api-reference/llm.md +0 -176
  29. package/skills/realtimex-moderator-sdk/references/api-reference/mcp.md +0 -50
  30. package/skills/realtimex-moderator-sdk/references/api-reference/port.md +0 -21
  31. package/skills/realtimex-moderator-sdk/references/api-reference/stt.md +0 -15
  32. package/skills/realtimex-moderator-sdk/references/api-reference/task.md +0 -62
  33. package/skills/realtimex-moderator-sdk/references/api-reference/tts.md +0 -18
  34. package/skills/realtimex-moderator-sdk/references/api-reference/v1-acpauth.md +0 -21
  35. package/skills/realtimex-moderator-sdk/references/api-reference/v1-acpcommands.md +0 -15
  36. package/skills/realtimex-moderator-sdk/references/api-reference/v1-admin.md +0 -48
  37. package/skills/realtimex-moderator-sdk/references/api-reference/v1-auth.md +0 -18
  38. package/skills/realtimex-moderator-sdk/references/api-reference/v1-channels.md +0 -78
  39. package/skills/realtimex-moderator-sdk/references/api-reference/v1-credentials.md +0 -27
  40. package/skills/realtimex-moderator-sdk/references/api-reference/v1-customthemes.md +0 -24
  41. package/skills/realtimex-moderator-sdk/references/api-reference/v1-desktopbrowser.md +0 -39
  42. package/skills/realtimex-moderator-sdk/references/api-reference/v1-desktopembed.md +0 -24
  43. package/skills/realtimex-moderator-sdk/references/api-reference/v1-desktopruntimesessions.md +0 -33
  44. package/skills/realtimex-moderator-sdk/references/api-reference/v1-document.md +0 -39
  45. package/skills/realtimex-moderator-sdk/references/api-reference/v1-embed.md +0 -27
  46. package/skills/realtimex-moderator-sdk/references/api-reference/v1-openai.md +0 -21
  47. package/skills/realtimex-moderator-sdk/references/api-reference/v1-sttapi.md +0 -12
  48. package/skills/realtimex-moderator-sdk/references/api-reference/v1-system.md +0 -36
  49. package/skills/realtimex-moderator-sdk/references/api-reference/v1-thread.md +0 -26
  50. package/skills/realtimex-moderator-sdk/references/api-reference/v1-users.md +0 -15
  51. package/skills/realtimex-moderator-sdk/references/api-reference/v1-workspace.md +0 -39
  52. package/skills/realtimex-moderator-sdk/references/api-reference/webhook.md +0 -13
  53. package/skills/realtimex-moderator-sdk/references/api-reference.md +0 -1330
  54. package/skills/realtimex-moderator-sdk/references/app-concepts.md +0 -1276
  55. package/skills/realtimex-moderator-sdk/references/browser.md +0 -27
  56. package/skills/realtimex-moderator-sdk/references/channels.md +0 -189
  57. package/skills/realtimex-moderator-sdk/references/credentials.md +0 -111
  58. package/skills/realtimex-moderator-sdk/references/known-issues.md +0 -237
  59. package/skills/realtimex-moderator-sdk/references/llm.md +0 -13
  60. package/skills/realtimex-moderator-sdk/references/mcp.md +0 -13
  61. package/skills/realtimex-moderator-sdk/references/permissions.md +0 -30
  62. package/skills/realtimex-moderator-sdk/references/quickstart.md +0 -16
  63. package/skills/realtimex-moderator-sdk/references/terminal-sessions.md +0 -34
  64. package/skills/realtimex-moderator-sdk/references/workspaces.md +0 -20
  65. package/skills/realtimex-moderator-sdk/scripts/lib/sdk-init.js +0 -171
  66. package/skills/realtimex-moderator-sdk/scripts/rtx.js +0 -1359
@@ -1,1359 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
- /**
4
- * rtx.js — RealTimeX SDK CLI (source-verified)
5
- * AUTO-GENERATED by scripts/generate-skill.mjs — do not edit by hand.
6
- *
7
- * All method signatures derived from the @realtimex/sdk TypeScript source.
8
- *
9
- * Usage: node rtx.js <command> [args...] [--flags]
10
- * Global flags:
11
- * --api-key=<key> Override API key
12
- * --env-dir=<path> Directory containing .env (default: cwd)
13
- * --url=<url> RealTimeX server URL (default: http://localhost:3001)
14
- */
15
-
16
- const path = require('path');
17
- const fs = require('fs');
18
- const { initSDK } = require('./lib/sdk-init');
19
-
20
- // ---------------------------------------------------------------------------
21
- // Arg parsing
22
- // ---------------------------------------------------------------------------
23
- function parseArgs(argv) {
24
- const flags = {}, positional = [];
25
- for (const arg of argv) {
26
- if (arg.startsWith('--')) {
27
- const [k, ...rest] = arg.slice(2).split('=');
28
- flags[k] = rest.length ? rest.join('=') : true;
29
- } else { positional.push(arg); }
30
- }
31
- return { flags, positional };
32
- }
33
- const { flags, positional } = parseArgs(process.argv.slice(2));
34
- const [command, ...cmdArgs] = positional;
35
-
36
- // ---------------------------------------------------------------------------
37
- // Helpers
38
- // ---------------------------------------------------------------------------
39
- function print(obj) { console.log(JSON.stringify(obj, null, 2)); }
40
- function printTable(rows, cols) {
41
- if (!rows?.length) { console.log('(no results)'); return; }
42
- const keys = cols || Object.keys(rows[0]);
43
- const widths = keys.map(k => Math.max(k.length, ...rows.map(r => String(r[k] ?? '').length)));
44
- const pad = (s, w) => String(s ?? '').padEnd(w);
45
- console.log(keys.map((k, i) => pad(k, widths[i])).join(' '));
46
- console.log(widths.map(w => '-'.repeat(w)).join(' '));
47
- for (const r of rows) console.log(keys.map((k, i) => pad(r[k], widths[i])).join(' '));
48
- }
49
-
50
- let _sdk = null;
51
- async function getSDK() {
52
- if (_sdk) return _sdk;
53
- _sdk = await initSDK({ envDir: flags['env-dir'] || process.cwd(), apiKey: flags['api-key'], url: flags['url'] });
54
- return _sdk;
55
- }
56
-
57
- function applyWorkspaceThreadDefaults(body = {}, context = {}) {
58
- const nextBody = { ...body };
59
- if (!nextBody.workspaceSlug && context?.workspaceSlug) {
60
- nextBody.workspaceSlug = context.workspaceSlug;
61
- }
62
- if (!nextBody.threadSlug && context?.threadSlug) {
63
- nextBody.threadSlug = context.threadSlug;
64
- }
65
- return nextBody;
66
- }
67
-
68
- function resolveWorkspaceFlagOrContext(context = {}) {
69
- return flags.workspace || context?.workspaceSlug || null;
70
- }
71
-
72
- const SKILL_ROOT = path.resolve(__dirname, '..');
73
- const REFERENCES_DIR = path.join(SKILL_ROOT, 'references');
74
-
75
- const SKILL_DOCS = {
76
- core: ['quickstart.md', 'permissions.md', 'workspaces.md'],
77
- quickstart: ['quickstart.md'],
78
- permissions: ['permissions.md'],
79
- workspaces: ['workspaces.md'],
80
- workspace: ['workspaces.md'],
81
- threads: ['workspaces.md'],
82
- agents: ['agents.md'],
83
- agent: ['agents.md'],
84
- terminal: ['terminal-sessions.md'],
85
- terminals: ['terminal-sessions.md'],
86
- 'terminal-sessions': ['terminal-sessions.md'],
87
- browser: ['browser.md'],
88
- channels: ['channels.md'],
89
- channel: ['channels.md'],
90
- llm: ['llm.md'],
91
- vectors: ['llm.md'],
92
- 'vector-store': ['llm.md'],
93
- mcp: ['mcp.md'],
94
- activities: ['activities.md'],
95
- activity: ['activities.md'],
96
- credentials: ['credentials.md'],
97
- issues: ['known-issues.md'],
98
- 'known-issues': ['known-issues.md'],
99
- concepts: ['app-concepts.md'],
100
- api: ['api-reference/index.md'],
101
- };
102
-
103
- function readReferenceFile(relPath) {
104
- const fullPath = path.resolve(REFERENCES_DIR, relPath);
105
- if (!fullPath.startsWith(REFERENCES_DIR + path.sep)) {
106
- throw new Error('Invalid skill reference path');
107
- }
108
- return fs.readFileSync(fullPath, 'utf-8');
109
- }
110
-
111
- function listApiReferenceSlugs() {
112
- const apiDir = path.join(REFERENCES_DIR, 'api-reference');
113
- if (!fs.existsSync(apiDir)) return [];
114
- return fs.readdirSync(apiDir)
115
- .filter((file) => file.endsWith('.md') && file !== 'index.md')
116
- .map((file) => `api:${file.replace(/\.md$/, '')}`)
117
- .sort();
118
- }
119
-
120
- function resolveSkillDoc(topic) {
121
- const normalized = String(topic || 'core').trim().toLowerCase();
122
- if (normalized.startsWith('api:')) {
123
- const slug = normalized.slice(4);
124
- if (!slug) return ['api-reference/index.md'];
125
- return [`api-reference/${slug}.md`];
126
- }
127
- return SKILL_DOCS[normalized] || null;
128
- }
129
-
130
- function printSkillDoc(topic, { full = false } = {}) {
131
- const refs = resolveSkillDoc(topic);
132
- if (!refs) {
133
- console.error(`Unknown skill topic: ${topic}`);
134
- console.error('Run: node rtx.js skills list');
135
- process.exit(1);
136
- }
137
-
138
- const chunks = [];
139
- for (const rel of refs) {
140
- chunks.push(readReferenceFile(rel).trimEnd());
141
- }
142
-
143
- if (full && topic !== 'api' && !String(topic || '').startsWith('api:')) {
144
- chunks.push(readReferenceFile('api-reference/index.md').trimEnd());
145
- }
146
-
147
- console.log(chunks.join('\n\n---\n\n'));
148
- }
149
-
150
- // ---------------------------------------------------------------------------
151
- // Commands
152
- // ---------------------------------------------------------------------------
153
- const CMD = {};
154
-
155
- CMD.context = async () => {
156
- const { context } = await getSDK();
157
- print({
158
- workspaceSlug: context?.workspaceSlug || null,
159
- threadSlug: context?.threadSlug || null,
160
- hasContext: Boolean(context?.workspaceSlug || context?.threadSlug),
161
- });
162
- };
163
-
164
- CMD.skills = async () => {
165
- const [subcommand, topic] = cmdArgs;
166
- if (!subcommand || subcommand === 'list') {
167
- console.log('Available skill topics:');
168
- for (const key of Object.keys(SKILL_DOCS).sort()) {
169
- console.log(` ${key}`);
170
- }
171
- const apiTopics = listApiReferenceSlugs();
172
- if (apiTopics.length) {
173
- console.log('');
174
- console.log('Available API reference topics:');
175
- for (const key of apiTopics) {
176
- console.log(` ${key}`);
177
- }
178
- }
179
- console.log('');
180
- console.log('Usage: node rtx.js skills get <topic> [--full]');
181
- return;
182
- }
183
-
184
- if (subcommand === 'get') {
185
- printSkillDoc(topic || 'core', { full: flags.full === true || flags.full === 'true' });
186
- return;
187
- }
188
-
189
- console.error('Usage: node rtx.js skills list');
190
- console.error(' or: node rtx.js skills get <topic> [--full]');
191
- process.exit(1);
192
- };
193
-
194
- // -- ping -------------------------------------------------------------------
195
- // Source: index.ts → sdk.ping() → { success, mode, appId, timestamp }
196
- CMD.ping = async () => { const { sdk } = await getSDK(); print(await sdk.ping()); };
197
-
198
- // -- info -------------------------------------------------------------------
199
- CMD.info = async () => {
200
- const { sdk, apiKey } = await getSDK();
201
- console.log('API key: ' + apiKey.slice(0, 8) + '...');
202
- try { console.log('Data dir: ' + await sdk.getAppDataDir()); } catch (_) {}
203
- print(await sdk.ping());
204
- };
205
-
206
- // -- agents -----------------------------------------------------------------
207
- // Source: modules/api.ts → ApiModule.getAgents() → Agent[]
208
- // Agent: { slug, name, description?, hub_id? }
209
- // NOTE: on sdk.api, NOT sdk directly
210
- CMD.agents = async () => {
211
- const { sdk } = await getSDK();
212
- printTable(await sdk.api.getAgents(), ['slug', 'name', 'description']);
213
- };
214
-
215
- // -- workspaces -------------------------------------------------------------
216
- // Source: ApiModule.getWorkspaces() → Workspace[] { id, slug, name, type }
217
- CMD.workspaces = async () => {
218
- const { sdk } = await getSDK();
219
- printTable(await sdk.api.getWorkspaces(), ['id', 'slug', 'name', 'type']);
220
- };
221
-
222
- // -- threads ----------------------------------------------------------------
223
- // Source: ApiModule.getThreads(workspaceSlug) → Thread[] { id, slug, name }
224
- CMD.threads = async () => {
225
- const [slugArg] = cmdArgs;
226
- const { sdk, context } = await getSDK();
227
- const slug = slugArg || resolveWorkspaceFlagOrContext(context);
228
- if (!slug) { console.error('Usage: rtx.js threads <workspace-slug>'); process.exit(1); }
229
- printTable(await sdk.api.getThreads(slug), ['id', 'slug', 'name']);
230
- };
231
-
232
- // -- task -------------------------------------------------------------------
233
- // Source: ApiModule.getTask(taskUuid) → Task { uuid, title, status, ..., runs }
234
- CMD.task = async () => {
235
- const [uuid] = cmdArgs;
236
- if (!uuid) { console.error('Usage: rtx.js task <uuid>'); process.exit(1); }
237
- const { sdk } = await getSDK();
238
- print(await sdk.api.getTask(uuid));
239
- };
240
-
241
- // -- activities -------------------------------------------------------------
242
- // Source: ActivitiesModule.list(options?) → Activity[] (direct array, NOT { activities: [...] })
243
- CMD.activities = async () => {
244
- const { sdk } = await getSDK();
245
- const opts = {};
246
- if (flags.status) opts.status = flags.status;
247
- if (flags.limit) opts.limit = Number(flags.limit);
248
- if (flags.offset) opts.offset = Number(flags.offset);
249
- print(await sdk.activities.list(opts));
250
- };
251
-
252
- // -- activity-get -----------------------------------------------------------
253
- // Source: ActivitiesModule.get(id) → Activity | null
254
- CMD['activity-get'] = async () => {
255
- const [id] = cmdArgs;
256
- if (!id) { console.error('Usage: rtx.js activity-get <id>'); process.exit(1); }
257
- const { sdk } = await getSDK();
258
- print(await sdk.activities.get(id));
259
- };
260
-
261
- // -- activity-create --------------------------------------------------------
262
- // Source: ActivitiesModule.insert(rawData: Record<string,unknown>) → Activity
263
- // rawData is your payload; SDK wraps it in { raw_data: rawData } automatically.
264
- CMD['activity-create'] = async () => {
265
- const [jsonStr] = cmdArgs;
266
- if (!jsonStr) { console.error('Usage: rtx.js activity-create <json-payload>'); process.exit(1); }
267
- const { sdk } = await getSDK();
268
- print(await sdk.activities.insert(JSON.parse(jsonStr)));
269
- };
270
-
271
- // -- activity-update --------------------------------------------------------
272
- // Source: ActivitiesModule.update(id, updates: Partial<Activity>) → Activity
273
- CMD['activity-update'] = async () => {
274
- const [id, jsonStr] = cmdArgs;
275
- if (!id || !jsonStr) { console.error('Usage: rtx.js activity-update <id> <json-updates>'); process.exit(1); }
276
- const { sdk } = await getSDK();
277
- print(await sdk.activities.update(id, JSON.parse(jsonStr)));
278
- };
279
-
280
- // -- activity-delete --------------------------------------------------------
281
- // Source: ActivitiesModule.delete(id) → void
282
- CMD['activity-delete'] = async () => {
283
- const [id] = cmdArgs;
284
- if (!id) { console.error('Usage: rtx.js activity-delete <id>'); process.exit(1); }
285
- const { sdk } = await getSDK();
286
- await sdk.activities.delete(id);
287
- console.log('Deleted.');
288
- };
289
-
290
- // -- task-start / task-complete / task-fail ---------------------------------
291
- // Source: modules/task.ts
292
- // CORRECT signatures (positional, NOT { task_uuid } object):
293
- // start(taskUuid, machineIdOrOptions?)
294
- // complete(taskUuid, result?, machineIdOrOptions?)
295
- // fail(taskUuid, error: string, machineIdOrOptions?)
296
- CMD['task-start'] = async () => {
297
- const [uuid] = cmdArgs;
298
- if (!uuid) { console.error('Usage: rtx.js task-start <uuid> [--machine=<id>]'); process.exit(1); }
299
- const { sdk } = await getSDK();
300
- print(await sdk.task.start(uuid, flags.machine ? { machineId: flags.machine } : undefined));
301
- };
302
- CMD['task-complete'] = async () => {
303
- const [uuid, resultStr] = cmdArgs;
304
- if (!uuid) { console.error('Usage: rtx.js task-complete <uuid> [<result-json>] [--machine=<id>]'); process.exit(1); }
305
- const { sdk } = await getSDK();
306
- print(await sdk.task.complete(uuid, resultStr ? JSON.parse(resultStr) : {}, flags.machine ? { machineId: flags.machine } : undefined));
307
- };
308
- CMD['task-fail'] = async () => {
309
- const [uuid, ...errParts] = cmdArgs;
310
- const errMsg = errParts.join(' ');
311
- if (!uuid || !errMsg) { console.error('Usage: rtx.js task-fail <uuid> <error-message>'); process.exit(1); }
312
- const { sdk } = await getSDK();
313
- print(await sdk.task.fail(uuid, errMsg, flags.machine ? { machineId: flags.machine } : undefined));
314
- };
315
- CMD['task-progress'] = async () => {
316
- const [uuid, dataStr] = cmdArgs;
317
- if (!uuid) { console.error('Usage: rtx.js task-progress <uuid> [<progress-json>]'); process.exit(1); }
318
- const { sdk } = await getSDK();
319
- print(await sdk.task.progress(uuid, dataStr ? JSON.parse(dataStr) : {}));
320
- };
321
- CMD['task-cancel'] = async () => {
322
- const [uuid, ...reasonParts] = cmdArgs;
323
- if (!uuid) { console.error('Usage: rtx.js task-cancel <uuid> [<reason>]'); process.exit(1); }
324
- const { sdk } = await getSDK();
325
- print(await sdk.task.cancel(uuid, reasonParts.join(' ') || undefined));
326
- };
327
-
328
- // -- trigger-agent ----------------------------------------------------------
329
- // IMPORTANT: sdk.webhook.triggerAgent() sends event "task.trigger" which the
330
- // server rejects (expects "trigger-agent"). This command bypasses the SDK
331
- // method and uses a direct fetch call with the correct event string.
332
- // Source evidence: modules/webhook.ts hardcodes event: 'task.trigger'
333
- // server/endpoints/sdk/webhook.js enum: ['trigger-agent',...]
334
- CMD['trigger-agent'] = async () => {
335
- const [agentName, workspaceSlug, ...promptParts] = cmdArgs;
336
- const prompt = promptParts.join(' ');
337
- if (!agentName || !workspaceSlug || !prompt) {
338
- console.error('Usage: rtx.js trigger-agent <agent-name> <workspace-slug> <prompt> [--thread=<slug>] [--data=<json>]');
339
- process.exit(1);
340
- }
341
- const { apiKey } = await getSDK();
342
- const resp = await fetch('http://localhost:3001/webhooks/realtimex', {
343
- method: 'POST',
344
- headers: { 'Content-Type': 'application/json', Authorization: 'Bearer ' + apiKey },
345
- body: JSON.stringify({
346
- event: 'trigger-agent',
347
- payload: {
348
- auto_run: true,
349
- agent_name: agentName,
350
- workspace_slug: workspaceSlug,
351
- thread_slug: flags.thread || undefined,
352
- prompt,
353
- raw_data: flags.data ? JSON.parse(flags.data) : {},
354
- },
355
- }),
356
- });
357
- print(await resp.json());
358
- };
359
-
360
- // -- webhook-ping -----------------------------------------------------------
361
- // Source: WebhookModule.ping() → sends event: 'system.ping' (accepted by server)
362
- CMD['webhook-ping'] = async () => {
363
- const { sdk } = await getSDK();
364
- print(await sdk.webhook.ping());
365
- };
366
-
367
- // -- llm-providers ----------------------------------------------------------
368
- // Source: LLMModule.chatProviders() → { success, providers: [{ provider, models }] }
369
- CMD['llm-providers'] = async () => {
370
- const { sdk } = await getSDK();
371
- const { providers } = await sdk.llm.chatProviders();
372
- for (const p of (providers || [])) {
373
- console.log('\nProvider: ' + p.provider);
374
- if (p.models?.length) printTable(p.models, ['id', 'name']);
375
- }
376
- };
377
- CMD['embed-providers'] = async () => {
378
- const { sdk } = await getSDK();
379
- const { providers } = await sdk.llm.embedProviders();
380
- for (const p of (providers || [])) {
381
- console.log('\nProvider: ' + p.provider);
382
- if (p.models?.length) printTable(p.models, ['id', 'name']);
383
- }
384
- };
385
-
386
- // -- llm-chat ---------------------------------------------------------------
387
- // Source: LLMModule.chat() → ChatResponse { success, response?: { content, model, metrics } }
388
- // Access text via res.response?.content (NOT choices[0].message.content)
389
- // Stream: yields StreamChunk { textResponse?, close?, error? } (NOT delta.content)
390
- CMD['llm-chat'] = async () => {
391
- const message = cmdArgs.join(' ');
392
- if (!message) { console.error('Usage: rtx.js llm-chat <message> [--stream] [--model=<m>] [--provider=<p>]'); process.exit(1); }
393
- const { sdk } = await getSDK();
394
- const opts = {};
395
- if (flags.model) opts.model = flags.model;
396
- if (flags.provider) opts.provider = flags.provider;
397
- if (flags.stream) {
398
- for await (const chunk of sdk.llm.chatStream([{ role: 'user', content: message }], opts)) {
399
- if (chunk.textResponse) process.stdout.write(chunk.textResponse);
400
- if (chunk.close) break;
401
- }
402
- process.stdout.write('\n');
403
- } else {
404
- const res = await sdk.llm.chat([{ role: 'user', content: message }], opts);
405
- console.log(res.response?.content ?? res.error ?? JSON.stringify(res));
406
- }
407
- };
408
-
409
- // -- llm-embed --------------------------------------------------------------
410
- // Source: LLMModule.embed(input: string | string[], options?)
411
- // Returns: EmbedResponse { success, embeddings: number[][], model, dimensions }
412
- CMD['llm-embed'] = async () => {
413
- const text = cmdArgs.join(' ');
414
- if (!text) { console.error('Usage: rtx.js llm-embed <text> [--model=<m>]'); process.exit(1); }
415
- const { sdk } = await getSDK();
416
- const res = await sdk.llm.embed(text, { model: flags.model, provider: flags.provider });
417
- console.log('success: ' + res.success + ', model: ' + res.model + ', dimensions: ' + res.dimensions);
418
- if (flags.vectors && res.embeddings?.[0]) print(res.embeddings[0].slice(0, 10));
419
- };
420
-
421
- // -- mcp-servers ------------------------------------------------------------
422
- // Source: MCPModule.getServers(provider?: 'local'|'remote'|'all')
423
- // CORRECT: plain string arg, NOT { provider: 'all' }
424
- CMD['mcp-servers'] = async () => {
425
- const { sdk } = await getSDK();
426
- printTable(await sdk.mcp.getServers(flags.provider || 'all'), ['name', 'provider', 'status']);
427
- };
428
- CMD['mcp-tools'] = async () => {
429
- const [name] = cmdArgs;
430
- if (!name) { console.error('Usage: rtx.js mcp-tools <server-name> [--provider=local|remote]'); process.exit(1); }
431
- const { sdk } = await getSDK();
432
- printTable(await sdk.mcp.getTools(name, flags.provider), ['name', 'description']);
433
- };
434
- CMD['mcp-exec'] = async () => {
435
- const [server, tool, argsStr] = cmdArgs;
436
- if (!server || !tool) { console.error('Usage: rtx.js mcp-exec <server> <tool> [<args-json>] [--provider=local|remote]'); process.exit(1); }
437
- const { sdk } = await getSDK();
438
- print(await sdk.mcp.executeTool(server, tool, argsStr ? JSON.parse(argsStr) : {}, flags.provider));
439
- };
440
-
441
- // -- credentials ------------------------------------------------------------
442
- CMD['credentials'] = async () => {
443
- const { sdk } = await getSDK();
444
- const list = await sdk.credentials.list();
445
- printTable(list, ['name', 'type']);
446
- };
447
-
448
- function getDesktopRuntimeSessionsModule(sdk) {
449
- const module = sdk?.desktopRuntimeSessions || sdk?.v1?.desktopRuntimeSessions;
450
- if (!module) {
451
- throw new Error('sdk.desktopRuntimeSessions is unavailable. Ensure the SDK was initialized with Developer API access.');
452
- }
453
- return module;
454
- }
455
-
456
- function getDesktopBrowserModule(sdk) {
457
- const module = sdk?.desktopBrowser || sdk?.v1?.desktopBrowser;
458
- if (!module) {
459
- throw new Error('sdk.desktopBrowser is unavailable. Ensure the SDK was initialized with Developer API access.');
460
- }
461
- return module;
462
- }
463
-
464
- // -- terminal-launcher / terminal sessions ----------------------------------
465
- CMD['terminal-open-launcher'] = async () => {
466
- const { sdk, context } = await getSDK();
467
- const terminal = getDesktopRuntimeSessionsModule(sdk);
468
- const body = applyWorkspaceThreadDefaults({}, context);
469
- if (flags.workspace) body.workspaceSlug = flags.workspace;
470
- if (flags.thread) body.threadSlug = flags.thread;
471
- if (flags.presentation) body.presentationMode = flags.presentation;
472
- if (flags.agent) body.preferredAgentName = flags.agent;
473
- if (flags.provider) body.preferredAgentProviderId = flags.provider;
474
- print(await terminal.openLauncher(body));
475
- };
476
-
477
- CMD['terminal-launch-shell'] = async () => {
478
- const { sdk, context } = await getSDK();
479
- const terminal = getDesktopRuntimeSessionsModule(sdk);
480
- const body = applyWorkspaceThreadDefaults({}, context);
481
- if (flags.workspace) body.workspaceSlug = flags.workspace;
482
- if (flags.thread) body.threadSlug = flags.thread;
483
- if (flags.presentation) body.presentationMode = flags.presentation;
484
- if (flags.command) body.initialCommand = flags.command;
485
- if (flags['command-mode']) {
486
- body.initialCommandMode = flags['command-mode'];
487
- } else if (flags.command) {
488
- body.initialCommandMode = 'direct';
489
- }
490
- if (flags.title) body.title = flags.title;
491
- if (flags.subtitle) body.subtitle = flags.subtitle;
492
- print(await terminal.launchTerminalShell(body));
493
- };
494
-
495
- CMD['terminal-launch-cli-agent'] = async () => {
496
- const [agentName, providerId, ...messageParts] = cmdArgs;
497
- const message = messageParts.join(' ');
498
- if (!agentName) {
499
- console.error('Usage: rtx.js terminal-launch-cli-agent <agent-name> [<provider-id>] [<message>] [--workspace=<slug>] [--thread=<slug>] [--presentation=panel|tab] [--model=<id>]');
500
- process.exit(1);
501
- }
502
- const { sdk, context } = await getSDK();
503
- const terminal = getDesktopRuntimeSessionsModule(sdk);
504
- const body = applyWorkspaceThreadDefaults({ agentName }, context);
505
- if (providerId) body.providerId = providerId;
506
- if (message) body.message = message;
507
- if (flags.workspace) body.workspaceSlug = flags.workspace;
508
- if (flags.thread) body.threadSlug = flags.thread;
509
- if (flags.presentation) body.presentationMode = flags.presentation;
510
- if (flags.model) body.modelId = flags.model;
511
- print(await terminal.launchTerminalCliAgent(body));
512
- };
513
-
514
- CMD['terminal-sessions'] = async () => {
515
- const { sdk } = await getSDK();
516
- const terminal = getDesktopRuntimeSessionsModule(sdk);
517
- const sessions = await terminal.listRuntimeSessions();
518
- print(sessions);
519
- };
520
-
521
- CMD['terminal-session-get'] = async () => {
522
- const [sessionId] = cmdArgs;
523
- if (!sessionId) {
524
- console.error('Usage: rtx.js terminal-session-get <session-id>');
525
- process.exit(1);
526
- }
527
- const { sdk } = await getSDK();
528
- const terminal = getDesktopRuntimeSessionsModule(sdk);
529
- print(await terminal.getRuntimeSession(sessionId));
530
- };
531
-
532
- CMD['terminal-write'] = async () => {
533
- const [sessionId, ...rest] = cmdArgs;
534
- if (!sessionId || rest.length === 0) {
535
- console.error('Usage: rtx.js terminal-write <session-id> <message> [--raw]');
536
- process.exit(1);
537
- }
538
- const { sdk } = await getSDK();
539
- const terminal = getDesktopRuntimeSessionsModule(sdk);
540
- const payload = rest.join(' ');
541
- print(await terminal.write(sessionId, flags.raw ? { input: payload } : { message: payload }));
542
- };
543
-
544
- CMD['terminal-permission'] = async () => {
545
- const [sessionId, outcome, actionId] = cmdArgs;
546
- if (!sessionId || !outcome) {
547
- console.error('Usage: rtx.js terminal-permission <session-id> <approved|denied> [<action-id>] [--option-id=<id>] [--reason=<text>]');
548
- process.exit(1);
549
- }
550
- const { sdk } = await getSDK();
551
- const terminal = getDesktopRuntimeSessionsModule(sdk);
552
- const body = { outcome };
553
- if (actionId) body.actionId = actionId;
554
- if (flags['option-id']) body.optionId = flags['option-id'];
555
- if (flags.reason) body.reason = flags.reason;
556
- print(await terminal.permission(sessionId, body));
557
- };
558
-
559
- CMD['terminal-close'] = async () => {
560
- const [sessionId] = cmdArgs;
561
- if (!sessionId) {
562
- console.error('Usage: rtx.js terminal-close <session-id>');
563
- process.exit(1);
564
- }
565
- const { sdk } = await getSDK();
566
- const terminal = getDesktopRuntimeSessionsModule(sdk);
567
- print(await terminal.deleteRuntimeSession(sessionId));
568
- };
569
-
570
- CMD['browser-sessions'] = async () => {
571
- const { sdk } = await getSDK();
572
- const browser = getDesktopBrowserModule(sdk);
573
- print(await browser.listSessions());
574
- };
575
-
576
- CMD['browser-session-create'] = async () => {
577
- const [sessionName] = cmdArgs;
578
- if (!sessionName) {
579
- console.error('Usage: rtx.js browser-session-create <session-name> [--port=<n>]');
580
- process.exit(1);
581
- }
582
- const { sdk } = await getSDK();
583
- const browser = getDesktopBrowserModule(sdk);
584
- const body = {
585
- sessionName,
586
- ...(flags.port ? { remoteDebugPort: Number(flags.port) } : {}),
587
- };
588
- print(await browser.createSession(body));
589
- };
590
-
591
- CMD['browser-session-get'] = async () => {
592
- const [sessionName] = cmdArgs;
593
- if (!sessionName) {
594
- console.error('Usage: rtx.js browser-session-get <session-name>');
595
- process.exit(1);
596
- }
597
- const { sdk } = await getSDK();
598
- const browser = getDesktopBrowserModule(sdk);
599
- print(await browser.getSession(sessionName));
600
- };
601
-
602
- CMD['browser-session-delete'] = async () => {
603
- const [sessionName] = cmdArgs;
604
- if (!sessionName) {
605
- console.error('Usage: rtx.js browser-session-delete <session-name>');
606
- process.exit(1);
607
- }
608
- const { sdk } = await getSDK();
609
- const browser = getDesktopBrowserModule(sdk);
610
- print(await browser.deleteSession(sessionName));
611
- };
612
-
613
- CMD['browser-tab-create'] = async () => {
614
- const [url] = cmdArgs;
615
- if (!url) {
616
- console.error('Usage: rtx.js browser-tab-create <url> [--session=<name>] [--focus=true|false] [--focus-window=true|false]');
617
- process.exit(1);
618
- }
619
- const { sdk } = await getSDK();
620
- const browser = getDesktopBrowserModule(sdk);
621
- const body = {
622
- url,
623
- ...(flags.session ? { sessionName: flags.session } : {}),
624
- ...(flags.focus !== undefined ? { focus: flags.focus !== 'false' } : {}),
625
- ...(flags['focus-window'] !== undefined ? { focusWindow: flags['focus-window'] !== 'false' } : {}),
626
- };
627
- print(await browser.createTab(body));
628
- };
629
-
630
- CMD['browser-tab-get'] = async () => {
631
- const [tabRef] = cmdArgs;
632
- if (!tabRef) {
633
- console.error('Usage: rtx.js browser-tab-get <tab-ref>');
634
- process.exit(1);
635
- }
636
- const { sdk } = await getSDK();
637
- const browser = getDesktopBrowserModule(sdk);
638
- print(await browser.getTab(tabRef));
639
- };
640
-
641
- CMD['browser-tab-focus'] = async () => {
642
- const [tabRef] = cmdArgs;
643
- if (!tabRef) {
644
- console.error('Usage: rtx.js browser-tab-focus <tab-ref> [--focus-window=true|false]');
645
- process.exit(1);
646
- }
647
- const { sdk } = await getSDK();
648
- const browser = getDesktopBrowserModule(sdk);
649
- const body = flags['focus-window'] !== undefined ? { focusWindow: flags['focus-window'] !== 'false' } : {};
650
- print(await browser.focusTab(tabRef, body));
651
- };
652
-
653
- CMD['browser-tab-navigate'] = async () => {
654
- const [tabRef, url] = cmdArgs;
655
- if (!tabRef || !url) {
656
- console.error('Usage: rtx.js browser-tab-navigate <tab-ref> <url> [--focus=true|false] [--focus-window=true|false]');
657
- process.exit(1);
658
- }
659
- const { sdk } = await getSDK();
660
- const browser = getDesktopBrowserModule(sdk);
661
- const body = {
662
- url,
663
- ...(flags.focus !== undefined ? { focus: flags.focus !== 'false' } : {}),
664
- ...(flags['focus-window'] !== undefined ? { focusWindow: flags['focus-window'] !== 'false' } : {}),
665
- };
666
- print(await browser.navigateTab(tabRef, body));
667
- };
668
-
669
- CMD['browser-tab-evaluate'] = async () => {
670
- const [tabRef, ...expressionParts] = cmdArgs;
671
- if (!tabRef || expressionParts.length === 0) {
672
- console.error('Usage: rtx.js browser-tab-evaluate <tab-ref> <expression> [--user-gesture=true|false]');
673
- process.exit(1);
674
- }
675
- const { sdk } = await getSDK();
676
- const browser = getDesktopBrowserModule(sdk);
677
- const body = {
678
- expression: expressionParts.join(' '),
679
- ...(flags['user-gesture'] !== undefined ? { userGesture: flags['user-gesture'] !== 'false' } : {}),
680
- };
681
- print(await browser.evaluateTab(tabRef, body));
682
- };
683
-
684
- CMD['browser-tab-close'] = async () => {
685
- const [tabRef] = cmdArgs;
686
- if (!tabRef) {
687
- console.error('Usage: rtx.js browser-tab-close <tab-ref>');
688
- process.exit(1);
689
- }
690
- const { sdk } = await getSDK();
691
- const browser = getDesktopBrowserModule(sdk);
692
- print(await browser.deleteTab(tabRef));
693
- };
694
-
695
- // -- acp-agents -------------------------------------------------------------
696
- // Source: AcpAgentModule.listAgents({ includeModels? })
697
- // Returns: AcpAgentInfo[] { id, label, handles[], installed, authReady, status }
698
- CMD['acp-agents'] = async () => {
699
- const { sdk } = await getSDK();
700
- printTable(await sdk.acpAgent.listAgents({ includeModels: flags.models === 'true' }), ['id', 'label', 'status', 'authReady', 'installed']);
701
- };
702
-
703
- // -- acp-sessions -----------------------------------------------------------
704
- // Source: AcpAgentModule.listSessions() → AcpSessionStatus[]
705
- CMD['acp-sessions'] = async () => {
706
- const { sdk } = await getSDK();
707
- print(await sdk.acpAgent.listSessions());
708
- };
709
-
710
- // -- acp-session-create -----------------------------------------------------
711
- // Source: AcpAgentModule.createSession(options) → AcpSession { session_key, agent_id, state, ... }
712
- // Prints session_key so callers can pass --session=<key> on subsequent calls.
713
- CMD['acp-session-create'] = async () => {
714
- const [agentId] = cmdArgs;
715
- if (!agentId) {
716
- console.error('Usage: rtx.js acp-session-create <agent-id> [--cwd=<path>] [--model=<m>] [--policy=approve-all|approve-reads|deny-all]');
717
- process.exit(1);
718
- }
719
- const { sdk } = await getSDK();
720
- const opts = {
721
- agent_id: agentId,
722
- cwd: flags.cwd || process.cwd(),
723
- approvalPolicy: flags.policy || 'approve-all',
724
- };
725
- if (flags.model) opts.model = flags.model;
726
- const session = await sdk.acpAgent.createSession(opts);
727
- process.stderr.write('Session created.\n');
728
- print(session);
729
- };
730
-
731
- // -- acp-session-get --------------------------------------------------------
732
- // Source: AcpAgentModule.getSession(sessionKey) → AcpSessionStatus
733
- CMD['acp-session-get'] = async () => {
734
- const [sessionKey] = cmdArgs;
735
- if (!sessionKey) { console.error('Usage: rtx.js acp-session-get <session-key>'); process.exit(1); }
736
- const { sdk } = await getSDK();
737
- print(await sdk.acpAgent.getSession(sessionKey));
738
- };
739
-
740
- // -- acp-session-patch ------------------------------------------------------
741
- // Source: AcpAgentModule.patchSession(sessionKey, patch) → void
742
- // patch fields: model?, cwd?, timeoutSeconds?, runtimeMode?, approvalPolicy?
743
- CMD['acp-session-patch'] = async () => {
744
- const [sessionKey] = cmdArgs;
745
- if (!sessionKey) {
746
- console.error('Usage: rtx.js acp-session-patch <session-key> [--cwd=<path>] [--model=<m>] [--policy=<p>] [--timeout=<s>]');
747
- process.exit(1);
748
- }
749
- const { sdk } = await getSDK();
750
- const patch = {};
751
- if (flags.cwd) patch.cwd = flags.cwd;
752
- if (flags.model) patch.model = flags.model;
753
- if (flags.policy) patch.approvalPolicy = flags.policy;
754
- if (flags.timeout) patch.timeoutSeconds = Number(flags.timeout);
755
- await sdk.acpAgent.patchSession(sessionKey, patch);
756
- console.log('Session patched.');
757
- };
758
-
759
- // -- acp-session-close ------------------------------------------------------
760
- // Source: AcpAgentModule.closeSession(sessionKey, reason?) → void
761
- CMD['acp-session-close'] = async () => {
762
- const [sessionKey, ...reasonParts] = cmdArgs;
763
- if (!sessionKey) { console.error('Usage: rtx.js acp-session-close <session-key> [<reason>]'); process.exit(1); }
764
- const { sdk } = await getSDK();
765
- await sdk.acpAgent.closeSession(sessionKey, reasonParts.join(' ') || undefined);
766
- console.log('Session closed.');
767
- };
768
-
769
- // -- acp-cancel -------------------------------------------------------------
770
- // Source: AcpAgentModule.cancelTurn(sessionKey, reason?) → void
771
- CMD['acp-cancel'] = async () => {
772
- const [sessionKey, ...reasonParts] = cmdArgs;
773
- if (!sessionKey) { console.error('Usage: rtx.js acp-cancel <session-key> [<reason>]'); process.exit(1); }
774
- const { sdk } = await getSDK();
775
- await sdk.acpAgent.cancelTurn(sessionKey, reasonParts.join(' ') || undefined);
776
- console.log('Turn cancelled.');
777
- };
778
-
779
- // -- acp-resolve ------------------------------------------------------------
780
- // Source: AcpAgentModule.resolvePermission(sessionKey, { requestId, optionId, outcome? }) → void
781
- // Must be called while streamChat SSE is still active for that session.
782
- CMD['acp-resolve'] = async () => {
783
- const [sessionKey, requestId, optionId] = cmdArgs;
784
- if (!sessionKey || !requestId || !optionId) {
785
- console.error('Usage: rtx.js acp-resolve <session-key> <request-id> <option-id> [--outcome=approved]');
786
- process.exit(1);
787
- }
788
- const { sdk } = await getSDK();
789
- await sdk.acpAgent.resolvePermission(sessionKey, {
790
- requestId,
791
- optionId,
792
- outcome: flags.outcome || 'approved',
793
- });
794
- console.log('Permission resolved.');
795
- };
796
-
797
- // -- acp-send ---------------------------------------------------------------
798
- // Source: AcpAgentModule.chat(sessionKey, message) → AcpChatResponse (sync, waits for full reply)
799
- // Reuses existing session; never creates a new one.
800
- CMD['acp-send'] = async () => {
801
- const [sessionKey, ...msgParts] = cmdArgs;
802
- const message = msgParts.join(' ');
803
- if (!sessionKey || !message) {
804
- console.error('Usage: rtx.js acp-send <session-key> <message>');
805
- process.exit(1);
806
- }
807
- const { sdk } = await getSDK();
808
- const res = await sdk.acpAgent.chat(sessionKey, message);
809
- console.log(res.text ?? JSON.stringify(res));
810
- };
811
-
812
- // -- acp-stream -------------------------------------------------------------
813
- // Source: AcpAgentModule.streamChat(sessionKey, message) — SSE stream on existing session.
814
- // Handles permission_request events automatically via resolvePermission().
815
- // Reuses existing session; never creates a new one.
816
- CMD['acp-stream'] = async () => {
817
- const [sessionKey, ...msgParts] = cmdArgs;
818
- const message = msgParts.join(' ');
819
- if (!sessionKey || !message) {
820
- console.error('Usage: rtx.js acp-stream <session-key> <message> [--thoughts] [--quiet]');
821
- process.exit(1);
822
- }
823
- const { sdk } = await getSDK();
824
- await acpStreamWithPermissions(sdk, sessionKey, message);
825
- };
826
-
827
- // ---------------------------------------------------------------------------
828
- // ACP helpers
829
- // ---------------------------------------------------------------------------
830
-
831
- /**
832
- * Extract a stable string id from a permission option entry.
833
- * Options can be raw numbers, strings, or objects with numeric/string id fields.
834
- * IMPORTANT: must use != null (not ||) to handle id === 0 (falsy but valid).
835
- */
836
- function optionId(opt, index) {
837
- if (opt == null) return String(index);
838
- if (typeof opt === 'number') return String(opt);
839
- if (typeof opt === 'string') return opt;
840
- if (opt.id != null) return String(opt.id);
841
- if (opt.optionId != null) return String(opt.optionId);
842
- if (opt.value != null) return String(opt.value);
843
- return String(index);
844
- }
845
-
846
- /** Extract a human-readable label from a permission option entry. */
847
- function optionLabel(opt, index) {
848
- if (opt == null) return String(index);
849
- if (typeof opt === 'number') return String(opt);
850
- if (typeof opt === 'string') return opt;
851
- return opt.label || opt.name || opt.description || optionId(opt, index);
852
- }
853
-
854
- /**
855
- * Stream a chat turn on an existing session, auto-resolving permission_request
856
- * events via sdk.acpAgent.resolvePermission().
857
- *
858
- * Permission resolution strategy (--policy-override flag):
859
- * approve-all (default) — approve: label-match → last option (typically "Yes/Always")
860
- * deny-all — deny: label-match → first option (typically "No/Cancel")
861
- * prompt — pause and ask the user interactively via stdin
862
- *
863
- * Why last-option for approve-all fallback:
864
- * Qwen/Claude-style dialogs are ordered [Deny=0, Approve-once=1, Approve-always=2].
865
- * Picking options[0] = Deny. We want the last approve variant when no label matches.
866
- */
867
- async function acpStreamWithPermissions(sdk, sessionKey, message) {
868
- const policyOverride = flags['policy-override'] || 'approve-all';
869
-
870
- for await (const event of sdk.acpAgent.streamChat(sessionKey, message)) {
871
- switch (event.type) {
872
-
873
- case 'text_delta': {
874
- if (event.data && event.data.type === 'thinking') {
875
- if (flags.thoughts) process.stderr.write('[thought] ' + String(event.data.text ?? '') + '\n');
876
- } else {
877
- process.stdout.write(String(event.data?.text ?? event.data ?? ''));
878
- }
879
- break;
880
- }
881
-
882
- case 'permission_request': {
883
- const req = event.data || {};
884
- const requestId = req.requestId || req.id || req.request_id;
885
- const options = Array.isArray(req.options) ? req.options : [];
886
-
887
- // Always show the full raw payload — critical for diagnosing option structure
888
- if (!flags.quiet) {
889
- process.stderr.write('\n[Permission Request] id=' + requestId + '\n');
890
- if (req.title) process.stderr.write(' title: ' + req.title + '\n');
891
- if (req.description) process.stderr.write(' details: ' + req.description + '\n');
892
- options.forEach((o, i) => {
893
- process.stderr.write(' [' + optionId(o, i) + '] ' + optionLabel(o, i) + '\n');
894
- });
895
- if (flags.debug) {
896
- process.stderr.write(' raw: ' + JSON.stringify(req) + '\n');
897
- }
898
- }
899
-
900
- let chosenId = null;
901
-
902
- if (policyOverride === 'prompt') {
903
- const readline = require('readline');
904
- const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
905
- const answer = await new Promise(resolve => {
906
- rl.question(' Choose option id (Enter = last/approve): ', ans => { rl.close(); resolve(ans.trim()); });
907
- });
908
- // Use typed answer, or fall back to last option (approve-always)
909
- chosenId = answer || (options.length ? optionId(options[options.length - 1], options.length - 1) : null);
910
-
911
- } else if (policyOverride === 'deny-all') {
912
- // Label-match for deny keywords first, then fall back to first option (index 0 = No/Cancel)
913
- const idx = options.findIndex(o => /deny|cancel|no|reject/i.test(optionLabel(o, 0)));
914
- const pick = idx >= 0 ? options[idx] : options[0];
915
- const pickIdx = idx >= 0 ? idx : 0;
916
- if (pick != null) chosenId = optionId(pick, pickIdx);
917
-
918
- } else {
919
- // approve-all: label-match first, then LAST option (not first — first is typically Deny)
920
- const idx = options.findIndex(o => /approve|allow|yes|confirm|ok|always/i.test(optionLabel(o, 0)));
921
- if (idx >= 0) {
922
- chosenId = optionId(options[idx], idx);
923
- } else if (options.length > 0) {
924
- // Last option is safest approve fallback (e.g. "Yes, don't ask again" / "Approve always")
925
- const lastIdx = options.length - 1;
926
- chosenId = optionId(options[lastIdx], lastIdx);
927
- }
928
- }
929
-
930
- if (chosenId !== null && requestId) {
931
- if (!flags.quiet) process.stderr.write(' → resolving with option: ' + chosenId + '\n');
932
- await sdk.acpAgent.resolvePermission(sessionKey, {
933
- requestId,
934
- optionId: chosenId,
935
- outcome: policyOverride === 'deny-all' ? 'denied' : 'approved',
936
- });
937
- } else {
938
- if (!flags.quiet) process.stderr.write(' → no options to resolve\n');
939
- }
940
- break;
941
- }
942
-
943
- case 'tool_call': {
944
- if (!flags.quiet) {
945
- const tool = event.data?.tool || event.data?.name || JSON.stringify(event.data);
946
- process.stderr.write('\n[tool: ' + tool + ']\n');
947
- }
948
- break;
949
- }
950
-
951
- case 'status': {
952
- if (!flags.quiet && event.data?.message) {
953
- process.stderr.write('[status] ' + event.data.message + '\n');
954
- }
955
- break;
956
- }
957
-
958
- case 'error': {
959
- process.stderr.write('\n[Error] ' + (event.data?.message || JSON.stringify(event.data)) + '\n');
960
- break;
961
- }
962
-
963
- case 'done':
964
- case 'close':
965
- process.stdout.write('\n');
966
- break;
967
-
968
- default:
969
- if (flags.debug) process.stderr.write('[event:' + event.type + '] ' + JSON.stringify(event.data) + '\n');
970
- break;
971
- }
972
- }
973
- }
974
-
975
- /**
976
- * Find a reusable session for agentId+cwd, or create a fresh one.
977
- *
978
- * Resolution order:
979
- * 1. --session=<key> → validate it exists and is not closed/stale, use it
980
- * 2. listSessions() → find first session matching agent_id (and cwd if --cwd given)
981
- * whose state is not 'closed' or 'stale'
982
- * 3. createSession() → spawn a new process
983
- *
984
- * Pass --new to always create a fresh session regardless.
985
- */
986
- async function findOrCreateSession(sdk, agentId) {
987
- const cwd = flags.cwd || process.cwd();
988
- const policy = flags.policy || 'approve-all';
989
-
990
- // Force-new
991
- if (flags.new) {
992
- process.stderr.write('Creating new ACP session for "' + agentId + '"...\n');
993
- const s = await sdk.acpAgent.createSession({ agent_id: agentId, cwd, approvalPolicy: policy, ...(flags.model ? { model: flags.model } : {}) });
994
- process.stderr.write('Session: ' + s.session_key + '\n');
995
- return s.session_key;
996
- }
997
-
998
- // Explicit key
999
- if (flags.session) {
1000
- try {
1001
- const status = await sdk.acpAgent.getSession(flags.session);
1002
- const state = status?.state || status?.runtime_options?.state;
1003
- if (state !== 'closed' && state !== 'stale') {
1004
- process.stderr.write('Reusing session (--session): ' + flags.session + '\n');
1005
- return flags.session;
1006
- }
1007
- process.stderr.write('Session ' + flags.session + ' is ' + state + ', will create new.\n');
1008
- } catch (e) {
1009
- process.stderr.write('Session lookup failed (' + (e.message || e) + '), will create new.\n');
1010
- }
1011
- }
1012
-
1013
- // Search existing sessions
1014
- try {
1015
- const sessions = await sdk.acpAgent.listSessions();
1016
- if (Array.isArray(sessions)) {
1017
- for (const s of sessions) {
1018
- const key = s.session_key || s.key;
1019
- const sid = s.agent_id || s.agentId;
1020
- const state = s.state || s.runtime_options?.state;
1021
- const sCwd = s.cwd || s.runtime_options?.cwd;
1022
- if (state === 'closed' || state === 'stale') continue;
1023
- if (sid && sid !== agentId) continue;
1024
- if (flags.cwd && sCwd && sCwd !== cwd) continue;
1025
- if (key) {
1026
- process.stderr.write('Reusing existing session: ' + key + (sid ? ' (' + sid + ')' : '') + '\n');
1027
- return key;
1028
- }
1029
- }
1030
- }
1031
- } catch (_) { /* listSessions not supported or empty — fall through */ }
1032
-
1033
- // Create new
1034
- process.stderr.write('Creating new ACP session for "' + agentId + '"...\n');
1035
- const session = await sdk.acpAgent.createSession({
1036
- agent_id: agentId,
1037
- cwd,
1038
- approvalPolicy: policy,
1039
- ...(flags.model ? { model: flags.model } : {}),
1040
- });
1041
- process.stderr.write('Session: ' + session.session_key + '\n');
1042
- return session.session_key;
1043
- }
1044
-
1045
- // -- acp-chat ---------------------------------------------------------------
1046
- // Smart version: reuses existing sessions, handles permission_request via resolvePermission().
1047
- //
1048
- // Flags:
1049
- // --session=<key> Reuse this specific session key
1050
- // --new Always create a fresh session
1051
- // --cwd=<path> Working directory (used for new session + matching)
1052
- // --model=<m> Model override
1053
- // --policy=approve-all approvalPolicy for new sessions
1054
- // --policy-override=<p> Runtime permission decision: approve-all|deny-all|prompt
1055
- // --close Close the session after this turn
1056
- // --thoughts Print reasoning/thinking tokens to stderr
1057
- // --quiet Suppress tool/status/permission stderr output
1058
- // --debug Print all unhandled SSE event types
1059
- CMD['acp-chat'] = async () => {
1060
- const [agentId, ...msgParts] = cmdArgs;
1061
- const message = msgParts.join(' ');
1062
- if (!agentId || !message) {
1063
- console.error('Usage: rtx.js acp-chat <agent-id> <message>\n' +
1064
- ' [--session=<key>] [--new] [--cwd=<path>] [--model=<m>]\n' +
1065
- ' [--policy=approve-all] [--policy-override=approve-all|deny-all|prompt]\n' +
1066
- ' [--close] [--thoughts] [--quiet] [--debug]');
1067
- process.exit(1);
1068
- }
1069
- const { sdk } = await getSDK();
1070
- const sessionKey = await findOrCreateSession(sdk, agentId);
1071
-
1072
- try {
1073
- await acpStreamWithPermissions(sdk, sessionKey, message);
1074
- } finally {
1075
- if (flags.close) {
1076
- await sdk.acpAgent.closeSession(sessionKey, 'chat complete').catch(() => {});
1077
- process.stderr.write('Session closed.\n');
1078
- } else {
1079
- process.stderr.write('Session key (reuse with --session=' + sessionKey + ')\n');
1080
- }
1081
- }
1082
- };
1083
-
1084
- // -- tts-providers / stt-providers ------------------------------------------
1085
- CMD['tts-providers'] = async () => { const { sdk } = await getSDK(); printTable(await sdk.tts.listProviders(), ['id', 'name', 'type', 'configured', 'supportsStreaming']); };
1086
- CMD['stt-providers'] = async () => { const { sdk } = await getSDK(); print(await sdk.stt.listProviders()); };
1087
-
1088
- // -- vectors ----------------------------------------------------------------
1089
- // Source: LLMModule.vectors (VectorStore sub-module)
1090
- CMD['vectors-workspaces'] = async () => { const { sdk } = await getSDK(); print(await sdk.llm.vectors.listWorkspaces()); };
1091
- // llm.search() embeds query then calls vectors.query() — high-level helper
1092
- CMD['vectors-query'] = async () => {
1093
- const query = cmdArgs.join(' ');
1094
- if (!query) { console.error('Usage: rtx.js vectors-query <query> [--workspace-id=<id>] [--top=5]'); process.exit(1); }
1095
- const { sdk } = await getSDK();
1096
- print(await sdk.llm.search(query, { topK: flags.top ? Number(flags.top) : 5, workspaceId: flags['workspace-id'] }));
1097
- };
1098
- // vectors.upsert: VectorRecord[] = { id, vector: number[], metadata? }
1099
- CMD['vectors-upsert'] = async () => {
1100
- const [jsonStr] = cmdArgs;
1101
- if (!jsonStr) { console.error('Usage: rtx.js vectors-upsert <json-VectorRecord[]> [--workspace-id=<id>]'); process.exit(1); }
1102
- const { sdk } = await getSDK();
1103
- print(await sdk.llm.vectors.upsert(JSON.parse(jsonStr), { workspaceId: flags['workspace-id'] }));
1104
- };
1105
- // vectors.delete requires { deleteAll: true } — partial delete by ID not supported
1106
- CMD['vectors-delete'] = async () => {
1107
- if (!flags['workspace-id'] && !flags.all) { console.error('Usage: rtx.js vectors-delete --workspace-id=<id> OR --all'); process.exit(1); }
1108
- const { sdk } = await getSDK();
1109
- print(await sdk.llm.vectors.delete({ deleteAll: true, workspaceId: flags['workspace-id'] }));
1110
- };
1111
-
1112
- // -- contract ---------------------------------------------------------------
1113
- CMD['contract-info'] = async () => { const { sdk } = await getSDK(); print(await sdk.contract.getLocalAppV1()); };
1114
- CMD['contract-capabilities'] = async () => { const { sdk } = await getSDK(); print(await sdk.contract.listCapabilities()); };
1115
- CMD['contract-search'] = async () => {
1116
- const query = cmdArgs.join(' ');
1117
- if (!query) { console.error('Usage: rtx.js contract-search <query>'); process.exit(1); }
1118
- const { sdk } = await getSDK();
1119
- print(await sdk.contract.searchCapabilities(query));
1120
- };
1121
- CMD['contract-invoke'] = async () => {
1122
- const [capId, ...rest] = cmdArgs;
1123
- if (!capId) { console.error('Usage: rtx.js contract-invoke <capability-id> [<args-json>]'); process.exit(1); }
1124
- const { sdk } = await getSDK();
1125
- print(await sdk.contract.invoke({ capability_id: capId, args: rest[0] ? JSON.parse(rest[0]) : {}, auto_run: true, agent_name: flags.agent, workspace_slug: flags.workspace, prompt: flags.prompt }));
1126
- };
1127
-
1128
- // -- database / auth --------------------------------------------------------
1129
- CMD['db-config'] = async () => { const { sdk } = await getSDK(); print(await sdk.database.getConfig()); };
1130
- CMD['auth-token'] = async () => { const { sdk } = await getSDK(); print(await sdk.auth.getAccessToken()); };
1131
-
1132
- // -- help -------------------------------------------------------------------
1133
- CMD.help = async () => {
1134
- console.log(`
1135
- RealTimeX SDK CLI (source-verified) — rtx.js
1136
- ============================================
1137
-
1138
- Usage: node rtx.js <command> [args...] [--flags]
1139
-
1140
- Global flags:
1141
- --api-key=<key> Override API key (skips .env lookup)
1142
- --env-dir=<path> Directory containing .env (default: cwd)
1143
- --url=<url> RealTimeX server URL (default: http://localhost:3001)
1144
-
1145
- Connection:
1146
- ping / info
1147
-
1148
- Skill docs:
1149
- skills list
1150
- List version-matched workflow/API skill topics bundled with this SDK.
1151
-
1152
- skills get <topic> [--full]
1153
- Print a focused skill guide from the installed SDK version.
1154
- Examples:
1155
- skills get core
1156
- skills get channels
1157
- skills get browser
1158
- skills get api:v1-channels --full
1159
-
1160
- sdk.api.*:
1161
- agents / workspaces / threads <slug> / task <uuid>
1162
- context
1163
-
1164
- sdk.activities.*:
1165
- activities [--status --limit --offset]
1166
- activity-get <id>
1167
- activity-create <json>
1168
- activity-update <id> <json>
1169
- activity-delete <id>
1170
-
1171
- sdk.task.* (positional args — NOT { task_uuid }):
1172
- task-start <uuid> [--machine=<id>]
1173
- task-complete <uuid> [<result-json>] [--machine=<id>]
1174
- task-fail <uuid> <error-message>
1175
- task-progress <uuid> [<progress-json>]
1176
- task-cancel <uuid> [<reason>]
1177
-
1178
- Trigger (raw fetch — SDK method sends wrong event type):
1179
- trigger-agent <agent-name> <workspace-slug> <prompt>
1180
- [--thread=<slug>] [--data=<json>]
1181
-
1182
- Webhook:
1183
- webhook-ping
1184
-
1185
- sdk.llm.*:
1186
- llm-providers / embed-providers
1187
- llm-chat <message> [--stream] [--model] [--provider]
1188
- llm-embed <text> [--model] [--vectors]
1189
-
1190
- sdk.llm.vectors.*:
1191
- vectors-workspaces
1192
- vectors-query <text> [--workspace-id] [--top=5]
1193
- vectors-upsert <json-VectorRecord[]> [--workspace-id]
1194
- vectors-delete --workspace-id=<id> | --all
1195
-
1196
- sdk.mcp.*:
1197
- mcp-servers [--provider=local|remote|all]
1198
- mcp-tools <server> [--provider]
1199
- mcp-exec <server> <tool> [<args-json>] [--provider]
1200
-
1201
- sdk.credentials.*:
1202
- credentials
1203
- List available credentials (names and types, no values).
1204
-
1205
- sdk.desktopRuntimeSessions.* — Desktop terminal sessions:
1206
- terminal-open-launcher
1207
- [--workspace=<slug>] [--thread=<slug>] [--presentation=panel|tab]
1208
- Open the terminal launcher UI in the Electron app.
1209
-
1210
- terminal-launch-shell
1211
- [--workspace=<slug>] [--thread=<slug>] [--presentation=panel|tab]
1212
- [--command="pwd"] [--command-mode=direct|prefill|shell]
1213
- Launch a visible shell terminal.
1214
- Default: when --command is provided, it runs in direct mode unless --command-mode is explicitly set.
1215
-
1216
- terminal-launch-cli-agent <agent-name> [<provider-id>] [<message>]
1217
- [--workspace=<slug>] [--thread=<slug>] [--presentation=panel|tab] [--model=<id>]
1218
- Launch a visible CLI agent terminal.
1219
- Example: terminal-launch-cli-agent claude claude-cli "what is current working dir"
1220
-
1221
- terminal-sessions
1222
- List desktop terminal sessions.
1223
-
1224
- terminal-session-get <session-id>
1225
- Fetch one desktop terminal session by runtime session id.
1226
-
1227
- terminal-write <session-id> <message> [--raw]
1228
- Send another message or raw PTY input to an existing terminal session.
1229
-
1230
- terminal-permission <session-id> <approved|denied> [<action-id>] [--option-id=<id>] [--reason=<text>]
1231
- Resolve a pending terminal approval request.
1232
-
1233
- terminal-close <session-id>
1234
- Close a desktop terminal session.
1235
-
1236
- Compatibility:
1237
- The SDK also exposes this module as sdk.v1.desktopRuntimeSessions.
1238
-
1239
- sdk.desktopBrowser.* — RealTimeX Browser sessions and tabs:
1240
- browser-sessions
1241
- List named RealTimeX Browser sessions.
1242
-
1243
- browser-session-create <session-name> [--port=<n>]
1244
- Create a named browser session.
1245
-
1246
- browser-session-get <session-name>
1247
- Fetch one named browser session.
1248
-
1249
- browser-session-delete <session-name>
1250
- Delete a named browser session.
1251
-
1252
- browser-tab-create <url> [--session=<name>] [--focus=true|false] [--focus-window=true|false]
1253
- Create a managed browser tab.
1254
-
1255
- browser-tab-get <tab-ref>
1256
- Fetch one browser tab snapshot by tab ref.
1257
-
1258
- browser-tab-focus <tab-ref> [--focus-window=true|false]
1259
- Focus a managed browser tab.
1260
-
1261
- browser-tab-navigate <tab-ref> <url> [--focus=true|false] [--focus-window=true|false]
1262
- Navigate a managed browser tab.
1263
-
1264
- browser-tab-evaluate <tab-ref> <expression> [--user-gesture=true|false]
1265
- Evaluate JavaScript in a managed browser tab.
1266
-
1267
- browser-tab-close <tab-ref>
1268
- Close a managed browser tab.
1269
-
1270
- Workflow note:
1271
- Each session has seperated browser profile, use session's remoteDebugPort with the agent-browser skill
1272
- over CDP for page interaction and automation.
1273
-
1274
- Compatibility:
1275
- The SDK also exposes this module as sdk.v1.desktopBrowser.
1276
-
1277
- sdk.acpAgent.* — Session Management:
1278
- acp-agents [--models=true]
1279
- List available ACP CLI agents.
1280
-
1281
- acp-sessions
1282
- List all active sessions owned by this app.
1283
-
1284
- acp-session-create <agent-id>
1285
- [--cwd=<path>] [--model=<m>] [--policy=approve-all|approve-reads|deny-all]
1286
- Spawn a new agent process. Prints session_key for reuse.
1287
-
1288
- acp-session-get <session-key>
1289
- Get session status and runtime options.
1290
-
1291
- acp-session-patch <session-key>
1292
- [--cwd=<path>] [--model=<m>] [--policy=<p>] [--timeout=<s>]
1293
- Update runtime options (applied on next turn).
1294
-
1295
- acp-session-close <session-key> [<reason>]
1296
- Stop the agent process and close the session.
1297
-
1298
- acp-cancel <session-key> [<reason>]
1299
- Cancel the currently active turn on a session.
1300
-
1301
- acp-resolve <session-key> <request-id> <option-id> [--outcome=approved]
1302
- Manually resolve a pending permission request (while stream is active).
1303
-
1304
- acp-send <session-key> <message>
1305
- Synchronous chat on an existing session (waits for full reply).
1306
-
1307
- acp-stream <session-key> <message>
1308
- [--policy-override=approve-all|deny-all|prompt] [--thoughts] [--quiet] [--debug]
1309
- Streaming chat on an existing session. Auto-resolves permission_request events.
1310
-
1311
- acp-chat <agent-id> <message>
1312
- [--session=<key>] Reuse a specific session key
1313
- [--new] Force-create a new session
1314
- [--cwd=<path>] Working directory (for new session and session matching)
1315
- [--model=<m>] Model override
1316
- [--policy=approve-all] approvalPolicy for newly created sessions
1317
- [--policy-override=approve-all|deny-all|prompt] Runtime permission handling
1318
- [--close] Close session after this turn
1319
- [--thoughts] Print reasoning tokens to stderr
1320
- [--quiet] Suppress tool/status/permission stderr output
1321
- [--debug] Print all unhandled SSE events
1322
-
1323
- Smart session reuse: checks --session flag → searches listSessions() for a
1324
- compatible active session → creates new only if none found.
1325
- Handles permission_request events inline via resolvePermission().
1326
-
1327
- sdk.tts.* / sdk.stt.*:
1328
- tts-providers / stt-providers
1329
-
1330
- sdk.contract.*:
1331
- contract-info / contract-capabilities
1332
- contract-search <query>
1333
- contract-invoke <capability-id> [<args-json>] [--agent] [--workspace] [--prompt]
1334
-
1335
- sdk.database.* / sdk.auth.*:
1336
- db-config / auth-token
1337
-
1338
- help
1339
- `);
1340
- };
1341
-
1342
- // ---------------------------------------------------------------------------
1343
- // Entry point
1344
- // ---------------------------------------------------------------------------
1345
- (async () => {
1346
- const handler = CMD[command];
1347
- if (!handler) {
1348
- console.error('Unknown command: ' + (command || '(none)') + '\nRun: node rtx.js help');
1349
- process.exit(1);
1350
- }
1351
- try {
1352
- await handler();
1353
- process.exit(0);
1354
- } catch (err) {
1355
- console.error('Error:', err.message || err);
1356
- if (flags.debug) console.error(err);
1357
- process.exit(1);
1358
- }
1359
- })();