@rethinkingstudio/clawpilot 2.0.0-beta.0 → 2.0.0-beta.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.
@@ -1,275 +0,0 @@
1
- import { readFile, writeFile, mkdir, readdir } from "fs/promises";
2
- import { join } from "path";
3
- import { PROVIDER_REGISTRY } from "./provider-registry.js";
4
- import { resolveOpenclawConfigPath, resolveOpenclawDir } from "./openclaw-cli.js";
5
-
6
- // ---------------------------------------------------------------------------
7
- // Types
8
- // ---------------------------------------------------------------------------
9
-
10
- export interface ProviderEntry {
11
- id: string; // e.g. "anthropic", "custom-<uuid>"
12
- type: string; // provider type key
13
- name: string; // display name from registry
14
- baseUrl: string;
15
- modelId: string | null; // model used for this provider
16
- keyMasked: string | null; // e.g. "sk-a***xyz", null if no key
17
- hasKey: boolean;
18
- isDefault: boolean;
19
- }
20
-
21
- // ---------------------------------------------------------------------------
22
- // Internal helpers
23
- // ---------------------------------------------------------------------------
24
-
25
- function maskKey(key: string): string {
26
- if (key.length <= 8) return key.slice(0, 2) + "***" + key.slice(-2);
27
- return key.slice(0, 4) + "***" + key.slice(-4);
28
- }
29
-
30
- async function resolveAgentId(): Promise<string> {
31
- const agentsDir = join(resolveOpenclawDir(), "agents");
32
- try {
33
- const entries = await readdir(agentsDir, { withFileTypes: true });
34
- const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
35
- if (dirs.length > 0) return dirs[0];
36
- } catch {
37
- // agents dir missing or unreadable
38
- }
39
- return "main";
40
- }
41
-
42
- async function readJson(filePath: string): Promise<Record<string, unknown>> {
43
- try {
44
- const raw = await readFile(filePath, "utf-8");
45
- return JSON.parse(raw) as Record<string, unknown>;
46
- } catch {
47
- return {};
48
- }
49
- }
50
-
51
- async function writeJson(filePath: string, data: unknown): Promise<void> {
52
- await writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
53
- }
54
-
55
- function getNestedObj(
56
- root: Record<string, unknown>,
57
- keys: string[],
58
- ): Record<string, unknown> {
59
- let cur: Record<string, unknown> = root;
60
- for (const key of keys) {
61
- if (cur[key] == null || typeof cur[key] !== "object" || Array.isArray(cur[key])) {
62
- cur[key] = {};
63
- }
64
- cur = cur[key] as Record<string, unknown>;
65
- }
66
- return cur;
67
- }
68
-
69
- function authProfilesPath(agentId: string): string {
70
- return join(resolveOpenclawDir(), "agents", agentId, "agent", "auth-profiles.json");
71
- }
72
-
73
- /** Extract the first model ID from a provider's models array in openclaw.json */
74
- function extractModelId(providerRaw: Record<string, unknown>): string | null {
75
- const models = providerRaw["models"];
76
- if (Array.isArray(models) && models.length > 0) {
77
- const first = models[0] as Record<string, unknown>;
78
- return typeof first["id"] === "string" ? first["id"] : null;
79
- }
80
- return null;
81
- }
82
-
83
- /** Infer provider type from its id in models.providers */
84
- function inferType(id: string): string {
85
- // custom providers have ids like "custom-<uuid>"
86
- if (id.startsWith("custom-")) return "custom";
87
- return id;
88
- }
89
-
90
- // ---------------------------------------------------------------------------
91
- // Public API
92
- // ---------------------------------------------------------------------------
93
-
94
- export async function listProviderEntries(): Promise<ProviderEntry[]> {
95
- const config = await readJson(resolveOpenclawConfigPath());
96
-
97
- const agentId = await resolveAgentId();
98
- const authProfiles = await readJson(authProfilesPath(agentId));
99
- const profiles = (authProfiles["profiles"] as Record<string, unknown> | undefined) ?? {};
100
-
101
- // Determine current default
102
- const agents = (config["agents"] as Record<string, unknown> | undefined) ?? {};
103
- const defaults = (agents["defaults"] as Record<string, unknown> | undefined) ?? {};
104
- const model = (defaults["model"] as Record<string, unknown> | undefined) ?? {};
105
- const primaryModel = typeof model["primary"] === "string" ? model["primary"] : "";
106
-
107
- const entries: ProviderEntry[] = [];
108
-
109
- // --- Providers from models.providers (non-builtIn) ---
110
- const models = (config["models"] as Record<string, unknown> | undefined) ?? {};
111
- const providers = (models["providers"] as Record<string, unknown> | undefined) ?? {};
112
-
113
- for (const [id, providerRaw] of Object.entries(providers)) {
114
- const p = (providerRaw as Record<string, unknown>) ?? {};
115
- const type = inferType(id);
116
- const info = PROVIDER_REGISTRY[type];
117
- const baseUrl = typeof p["baseUrl"] === "string" ? p["baseUrl"] : "";
118
- const modelId = extractModelId(p);
119
-
120
- // auth-profiles key is "${id}:default"
121
- const profileKey = `${id}:default`;
122
- const profileRaw = profiles[profileKey];
123
- const profile = profileRaw != null && typeof profileRaw === "object" && !Array.isArray(profileRaw)
124
- ? (profileRaw as Record<string, unknown>)
125
- : null;
126
- const apiKey = profile != null && typeof profile["key"] === "string" ? profile["key"] : null;
127
-
128
- const hasKey = apiKey != null && apiKey.length > 0;
129
- const keyMasked = hasKey ? maskKey(apiKey!) : null;
130
- const isDefault = primaryModel === id || primaryModel.startsWith(`${id}/`);
131
-
132
- entries.push({
133
- id,
134
- type,
135
- name: info?.displayName ?? type,
136
- baseUrl,
137
- modelId,
138
- keyMasked,
139
- hasKey,
140
- isDefault,
141
- });
142
- }
143
-
144
- // --- Built-in providers (anthropic, google) — detected via auth-profiles ---
145
- for (const [type, info] of Object.entries(PROVIDER_REGISTRY)) {
146
- if (!info.builtIn) continue;
147
- const profileKey = `${type}:default`;
148
- const profileRaw = profiles[profileKey];
149
- if (profileRaw == null) continue; // not configured
150
-
151
- const profile = typeof profileRaw === "object" && !Array.isArray(profileRaw)
152
- ? (profileRaw as Record<string, unknown>)
153
- : null;
154
- const apiKey = profile != null && typeof profile["key"] === "string" ? profile["key"] : null;
155
- const hasKey = apiKey != null && apiKey.length > 0;
156
- const keyMasked = hasKey ? maskKey(apiKey!) : null;
157
- const isDefault = primaryModel === type || primaryModel.startsWith(`${type}/`);
158
-
159
- entries.push({
160
- id: type,
161
- type,
162
- name: info.displayName,
163
- baseUrl: info.defaultBaseUrl,
164
- modelId: info.defaultModelId ?? null,
165
- keyMasked,
166
- hasKey,
167
- isDefault,
168
- });
169
- }
170
-
171
- return entries;
172
- }
173
-
174
- export async function addProvider(params: {
175
- id: string;
176
- type: string;
177
- apiKey: string | null;
178
- baseUrl: string;
179
- api: string;
180
- apiKeyEnvName: string; // env var name, written as "apiKey" in openclaw.json
181
- modelId?: string;
182
- }): Promise<void> {
183
- const { id, type, apiKey, baseUrl, api, apiKeyEnvName, modelId } = params;
184
- const info = PROVIDER_REGISTRY[type];
185
-
186
- // --- Update openclaw.json (skip for builtIn providers) ---
187
- if (!info?.builtIn) {
188
- const config = await readJson(resolveOpenclawConfigPath());
189
- const models = getNestedObj(config, ["models"]);
190
- const providers = getNestedObj(models, ["providers"]);
191
-
192
- // "apiKey" is the env var name reference (not the actual key value)
193
- const providerEntry: Record<string, unknown> = { type, baseUrl, api, apiKey: apiKeyEnvName };
194
- if (modelId !== undefined && modelId.length > 0) {
195
- providerEntry["models"] = [{ id: modelId, name: modelId }];
196
- }
197
- providers[id] = providerEntry;
198
-
199
- await writeJson(resolveOpenclawConfigPath(), config);
200
- }
201
-
202
- // --- Update auth-profiles.json (only if apiKey provided) ---
203
- if (apiKey != null && apiKey.length > 0) {
204
- const agentId = await resolveAgentId();
205
- const profilesPath = authProfilesPath(agentId);
206
- const profilesDir = join(resolveOpenclawDir(), "agents", agentId, "agent");
207
-
208
- await mkdir(profilesDir, { recursive: true });
209
-
210
- const authProfiles = await readJson(profilesPath);
211
- const profiles = getNestedObj(authProfiles, ["profiles"]);
212
-
213
- // Profile key is "${id}:default" — for builtIn, id === type
214
- const profileKey = `${id}:default`;
215
- profiles[profileKey] = { type: "api_key", provider: type, key: apiKey };
216
-
217
- await writeJson(profilesPath, authProfiles);
218
- }
219
- }
220
-
221
- export async function deleteProvider(id: string): Promise<void> {
222
- const type = inferType(id);
223
- const info = PROVIDER_REGISTRY[type];
224
-
225
- // --- Update openclaw.json (skip for builtIn) ---
226
- if (!info?.builtIn) {
227
- const config = await readJson(resolveOpenclawConfigPath());
228
- const models = getNestedObj(config, ["models"]);
229
- const providers = getNestedObj(models, ["providers"]);
230
- delete providers[id];
231
- await writeJson(resolveOpenclawConfigPath(), config);
232
- }
233
-
234
- // --- Update auth-profiles.json ---
235
- const agentId = await resolveAgentId();
236
- const profilesPath = authProfilesPath(agentId);
237
- const authProfiles = await readJson(profilesPath);
238
- const profiles = getNestedObj(authProfiles, ["profiles"]);
239
-
240
- const profileKey = `${id}:default`;
241
- if (profileKey in profiles) {
242
- delete profiles[profileKey];
243
- await writeJson(profilesPath, authProfiles);
244
- }
245
- }
246
-
247
- export async function setDefaultProvider(id: string): Promise<void> {
248
- const type = inferType(id);
249
- const info = PROVIDER_REGISTRY[type];
250
-
251
- // Determine the model ID for this provider
252
- let modelId: string | null = null;
253
-
254
- if (info?.builtIn) {
255
- // Built-in providers: use registry default, no models.providers entry
256
- modelId = info.defaultModelId ?? null;
257
- } else {
258
- // Read from models.providers entry
259
- const config = await readJson(resolveOpenclawConfigPath());
260
- const models = (config["models"] as Record<string, unknown>) ?? {};
261
- const providers = (models["providers"] as Record<string, unknown>) ?? {};
262
- const providerRaw = (providers[id] as Record<string, unknown>) ?? {};
263
- modelId = extractModelId(providerRaw) ?? info?.defaultModelId ?? null;
264
- }
265
-
266
- const primary = modelId ? `${id}/${modelId}` : id;
267
-
268
- const config = await readJson(resolveOpenclawConfigPath());
269
- const agents = getNestedObj(config, ["agents"]);
270
- const defaults = getNestedObj(agents, ["defaults"]);
271
- const model = getNestedObj(defaults, ["model"]);
272
- model["primary"] = primary;
273
-
274
- await writeJson(resolveOpenclawConfigPath(), config);
275
- }
@@ -1,184 +0,0 @@
1
- import { execSync } from "child_process";
2
- import { randomUUID } from "crypto";
3
- import type { LocalResult } from "./local-handlers.js";
4
- import { execOpenclaw, SUBPROCESS_ENV } from "./openclaw-cli.js";
5
- import { PROVIDER_REGISTRY } from "./provider-registry.js";
6
- import {
7
- listProviderEntries,
8
- addProvider,
9
- deleteProvider,
10
- setDefaultProvider,
11
- } from "./provider-config.js";
12
-
13
- function restartGateway(): void {
14
- try {
15
- execOpenclaw("gateway restart");
16
- console.log("[provider] gateway restarted");
17
- } catch (err) {
18
- console.warn("[provider] gateway restart failed:", String(err));
19
- }
20
- }
21
-
22
- // ---------------------------------------------------------------------------
23
- // HTTP key validation
24
- // ---------------------------------------------------------------------------
25
-
26
- async function validateApiKey(
27
- type: string,
28
- apiKey: string,
29
- baseUrl: string
30
- ): Promise<{ ok: boolean; error?: string }> {
31
- const info = PROVIDER_REGISTRY[type];
32
- if (!info) return { ok: false, error: `Unknown provider type: ${type}` };
33
- if (!info.requiresApiKey || !apiKey) return { ok: true };
34
-
35
- return new Promise((resolve) => {
36
- try {
37
- const url = new URL(info.validationPath, baseUrl);
38
- if (info.validationAuth === "google-query-param") {
39
- url.searchParams.set("key", apiKey);
40
- }
41
-
42
- const headers: Record<string, string> = {};
43
- if (info.validationAuth === "bearer") {
44
- headers["Authorization"] = `Bearer ${apiKey}`;
45
- } else if (info.validationAuth === "x-api-key") {
46
- headers["x-api-key"] = apiKey;
47
- headers["anthropic-version"] = "2023-06-01";
48
- }
49
-
50
- // Use http or https based on protocol
51
- // eslint-disable-next-line @typescript-eslint/no-require-imports
52
- const mod = url.protocol === "https:" ? require("https") : require("http");
53
- const req = mod.get(
54
- {
55
- hostname: url.hostname,
56
- port: url.port || undefined,
57
- path: url.pathname + url.search,
58
- headers,
59
- },
60
- (res: { statusCode?: number; resume: () => void }) => {
61
- res.resume(); // drain body
62
- const status = res.statusCode ?? 0;
63
- if (status >= 200 && status < 300) {
64
- resolve({ ok: true });
65
- } else if (status === 401 || status === 403) {
66
- resolve({ ok: false, error: "API Key 无效" });
67
- } else {
68
- resolve({ ok: false, error: `验证失败 (HTTP ${status})` });
69
- }
70
- }
71
- );
72
- req.setTimeout(10_000, () => {
73
- req.destroy();
74
- resolve({ ok: false, error: "验证超时" });
75
- });
76
- req.on("error", (e: Error) => resolve({ ok: false, error: e.message }));
77
- } catch (e) {
78
- resolve({ ok: false, error: String(e) });
79
- }
80
- });
81
- }
82
-
83
- // ---------------------------------------------------------------------------
84
- // Command handlers
85
- // ---------------------------------------------------------------------------
86
-
87
- async function cmdList(): Promise<LocalResult> {
88
- try {
89
- const providers = await listProviderEntries();
90
- return { ok: true, payload: { providers } };
91
- } catch (err) {
92
- return { ok: false, error: String(err) };
93
- }
94
- }
95
-
96
- async function cmdValidateKey(params: Record<string, unknown>): Promise<LocalResult> {
97
- try {
98
- const type = params.type as string;
99
- const apiKey = params.apiKey as string;
100
- const baseUrl = (params.baseUrl as string | undefined) ?? PROVIDER_REGISTRY[type]?.defaultBaseUrl ?? "";
101
- const result = await validateApiKey(type, apiKey, baseUrl);
102
- if (result.ok) return { ok: true };
103
- return { ok: false, error: result.error ?? "验证失败" };
104
- } catch (err) {
105
- return { ok: false, error: String(err) };
106
- }
107
- }
108
-
109
- async function cmdAdd(params: Record<string, unknown>): Promise<LocalResult> {
110
- try {
111
- const type = params.type as string;
112
- const apiKey = (params.apiKey as string | null | undefined) ?? null;
113
- const info = PROVIDER_REGISTRY[type];
114
- if (!info) return { ok: false, error: `Unknown provider type: ${type}` };
115
-
116
- const baseUrl = (params.baseUrl as string | undefined) || info.defaultBaseUrl;
117
- const modelId = (params.modelId as string | undefined) ?? info.defaultModelId;
118
-
119
- // Validate key before writing config
120
- if (info.requiresApiKey && apiKey) {
121
- const v = await validateApiKey(type, apiKey, baseUrl);
122
- if (!v.ok) return { ok: false, error: v.error ?? "API Key 无效" };
123
- }
124
-
125
- // custom providers get a UUID suffix; id and apiKeyEnvName share the same UUID so they're traceable
126
- const uuid = info.allowMultiple ? randomUUID() : null;
127
- const id = uuid ? `custom-${uuid}` : type;
128
- const apiKeyEnvName = uuid
129
- ? `CUSTOM_${uuid.replace(/-/g, "_").toUpperCase()}_API_KEY`
130
- : info.apiKeyEnvName;
131
-
132
- await addProvider({ id, type, apiKey, baseUrl, api: info.api, apiKeyEnvName, modelId });
133
- restartGateway();
134
- return { ok: true, payload: { id } };
135
- } catch (err) {
136
- return { ok: false, error: String(err) };
137
- }
138
- }
139
-
140
- async function cmdDelete(params: Record<string, unknown>): Promise<LocalResult> {
141
- try {
142
- const id = params.id as string;
143
- if (!id) return { ok: false, error: "id required" };
144
- await deleteProvider(id);
145
- restartGateway();
146
- return { ok: true };
147
- } catch (err) {
148
- return { ok: false, error: String(err) };
149
- }
150
- }
151
-
152
- async function cmdSetDefault(params: Record<string, unknown>): Promise<LocalResult> {
153
- try {
154
- const id = params.id as string;
155
- if (!id) return { ok: false, error: "id required" };
156
- await setDefaultProvider(id);
157
- restartGateway();
158
- return { ok: true };
159
- } catch (err) {
160
- return { ok: false, error: String(err) };
161
- }
162
- }
163
-
164
- // ---------------------------------------------------------------------------
165
- // Main dispatch
166
- // ---------------------------------------------------------------------------
167
-
168
- export function handleProviderCommand(
169
- method: string,
170
- params: unknown
171
- ): Promise<LocalResult> | null {
172
- if (!method.startsWith("clawpilot.provider.")) return null;
173
- const p = (params ?? {}) as Record<string, unknown>;
174
-
175
- switch (method) {
176
- case "clawpilot.provider.list": return cmdList();
177
- case "clawpilot.provider.validateKey": return cmdValidateKey(p);
178
- case "clawpilot.provider.add": return cmdAdd(p);
179
- case "clawpilot.provider.delete": return cmdDelete(p);
180
- case "clawpilot.provider.setDefault": return cmdSetDefault(p);
181
- default:
182
- return Promise.resolve({ ok: false, error: `Unknown provider command: ${method}` });
183
- }
184
- }
@@ -1,138 +0,0 @@
1
- export interface ProviderTypeInfo {
2
- displayName: string;
3
- defaultBaseUrl: string;
4
- api: "anthropic-messages" | "openai-completions" | "openai-responses";
5
- apiKeyEnvName: string;
6
- validationPath: string;
7
- validationAuth: "bearer" | "x-api-key" | "google-query-param" | "none";
8
- requiresApiKey: boolean;
9
- allowMultiple: boolean;
10
- showBaseUrl: boolean;
11
- showModelId: boolean;
12
- defaultModelId?: string;
13
- /**
14
- * Built-in OpenClaw providers (anthropic, google) — do NOT write a
15
- * models.providers entry; only write to auth-profiles.json.
16
- */
17
- builtIn?: boolean;
18
- }
19
-
20
- export const PROVIDER_REGISTRY: Record<string, ProviderTypeInfo> = {
21
- anthropic: {
22
- displayName: "Anthropic",
23
- defaultBaseUrl: "https://api.anthropic.com",
24
- api: "anthropic-messages",
25
- apiKeyEnvName: "ANTHROPIC_API_KEY",
26
- validationPath: "/v1/models",
27
- validationAuth: "x-api-key",
28
- requiresApiKey: true,
29
- allowMultiple: false,
30
- showBaseUrl: false,
31
- showModelId: false,
32
- defaultModelId: "claude-opus-4-6",
33
- builtIn: true,
34
- },
35
- openai: {
36
- displayName: "OpenAI",
37
- defaultBaseUrl: "https://api.openai.com",
38
- api: "openai-responses",
39
- apiKeyEnvName: "OPENAI_API_KEY",
40
- validationPath: "/v1/models",
41
- validationAuth: "bearer",
42
- requiresApiKey: true,
43
- allowMultiple: false,
44
- showBaseUrl: false,
45
- showModelId: false,
46
- defaultModelId: "gpt-4o",
47
- },
48
- google: {
49
- displayName: "Google",
50
- defaultBaseUrl: "https://generativelanguage.googleapis.com",
51
- api: "openai-completions",
52
- apiKeyEnvName: "GOOGLE_API_KEY",
53
- validationPath: "/v1beta/models",
54
- validationAuth: "google-query-param",
55
- requiresApiKey: true,
56
- allowMultiple: false,
57
- showBaseUrl: false,
58
- showModelId: false,
59
- defaultModelId: "gemini-2.0-flash",
60
- builtIn: true,
61
- },
62
- openrouter: {
63
- displayName: "OpenRouter",
64
- defaultBaseUrl: "https://openrouter.ai",
65
- api: "openai-completions",
66
- apiKeyEnvName: "OPENROUTER_API_KEY",
67
- validationPath: "/api/v1/models",
68
- validationAuth: "bearer",
69
- requiresApiKey: true,
70
- allowMultiple: false,
71
- showBaseUrl: false,
72
- showModelId: false,
73
- defaultModelId: "anthropic/claude-opus-4-6",
74
- },
75
- ark: {
76
- displayName: "ByteDance (Ark)",
77
- defaultBaseUrl: "https://ark.cn-beijing.volces.com",
78
- api: "openai-completions",
79
- apiKeyEnvName: "ARK_API_KEY",
80
- validationPath: "/api/v3/models",
81
- validationAuth: "bearer",
82
- requiresApiKey: true,
83
- allowMultiple: false,
84
- showBaseUrl: false,
85
- showModelId: true, // Ark is a platform; user must specify the model endpoint ID
86
- },
87
- moonshot: {
88
- displayName: "Moonshot (Kimi)",
89
- defaultBaseUrl: "https://api.moonshot.cn",
90
- api: "openai-completions",
91
- apiKeyEnvName: "MOONSHOT_API_KEY",
92
- validationPath: "/v1/models",
93
- validationAuth: "bearer",
94
- requiresApiKey: true,
95
- allowMultiple: false,
96
- showBaseUrl: false,
97
- showModelId: false,
98
- defaultModelId: "kimi-k2.5",
99
- },
100
- siliconflow: {
101
- displayName: "SiliconFlow",
102
- defaultBaseUrl: "https://api.siliconflow.cn",
103
- api: "openai-completions",
104
- apiKeyEnvName: "SILICONFLOW_API_KEY",
105
- validationPath: "/v1/models",
106
- validationAuth: "bearer",
107
- requiresApiKey: true,
108
- allowMultiple: false,
109
- showBaseUrl: false,
110
- showModelId: false,
111
- defaultModelId: "Qwen/QwQ-32B",
112
- },
113
- ollama: {
114
- displayName: "Ollama",
115
- defaultBaseUrl: "http://localhost:11434",
116
- api: "openai-completions",
117
- apiKeyEnvName: "OLLAMA_API_KEY",
118
- validationPath: "/api/tags",
119
- validationAuth: "none",
120
- requiresApiKey: false,
121
- allowMultiple: false,
122
- showBaseUrl: true,
123
- showModelId: true, // User must specify which model they have pulled
124
- },
125
- custom: {
126
- displayName: "Custom",
127
- defaultBaseUrl: "",
128
- api: "openai-completions",
129
- apiKeyEnvName: "CUSTOM_API_KEY",
130
- validationPath: "/v1/models",
131
- validationAuth: "bearer",
132
- requiresApiKey: false,
133
- allowMultiple: true,
134
- showBaseUrl: true,
135
- showModelId: true,
136
- defaultModelId: "custom-model",
137
- },
138
- };
@@ -1,34 +0,0 @@
1
- import { readConfig, readGatewayUrl, readGatewayAuth } from "../config/config.js";
2
- import { runRelayManager } from "../relay/relay-manager.js";
3
- import { withReconnect } from "../relay/reconnect.js";
4
- import { t } from "../i18n/index.js";
5
-
6
- export async function runCommand(): Promise<void> {
7
- const config = readConfig();
8
- const gatewayUrl = readGatewayUrl();
9
- const gatewayAuth = readGatewayAuth(config);
10
-
11
- console.log(t("run.starting"));
12
- console.log(t("run.gatewayId", config.gatewayId));
13
- console.log(t("run.relayServer", config.relayServerUrl));
14
- console.log(t("run.gatewayUrl", gatewayUrl));
15
-
16
- await withReconnect(
17
- () =>
18
- runRelayManager({
19
- relayServerUrl: config.relayServerUrl,
20
- gatewayId: config.gatewayId,
21
- relaySecret: config.relaySecret,
22
- gatewayUrl,
23
- gatewayToken: gatewayAuth.token,
24
- gatewayPassword: gatewayAuth.password,
25
- onConnected: () => console.log(t("run.connected")),
26
- onDisconnected: () => console.log(t("run.disconnected")),
27
- }),
28
- {
29
- onRetry: (attempt, delayMs) => {
30
- console.log(t("run.retry", String(attempt), String(delayMs)));
31
- },
32
- }
33
- );
34
- }
@@ -1,42 +0,0 @@
1
- import { basename } from "path";
2
- import { t } from "../i18n/index.js";
3
- import { sendSyntheticAssistantMessage } from "./assistant-send.js";
4
- import { uploadFile } from "./upload.js";
5
-
6
- export interface SendCommandOptions {
7
- json?: boolean;
8
- }
9
-
10
- export async function sendCommand(filePath: string, options: SendCommandOptions = {}): Promise<void> {
11
- if (!options.json) {
12
- console.log(t("send.preparing", filePath));
13
- }
14
-
15
- const uploaded = await uploadFile(filePath);
16
- const result = await sendSyntheticAssistantMessage({
17
- message: "uploaded file",
18
- url: uploaded.url,
19
- mimeType: uploaded.mimeType,
20
- fileName: uploaded.fileName || basename(uploaded.path),
21
- thumbnailUrl: uploaded.thumbnailUrl ?? undefined,
22
- size: String(uploaded.size),
23
- });
24
-
25
- if (options.json) {
26
- console.log(JSON.stringify({
27
- path: uploaded.path,
28
- fileName: uploaded.fileName,
29
- mimeType: uploaded.mimeType,
30
- url: uploaded.url,
31
- thumbnailUrl: uploaded.thumbnailUrl,
32
- size: uploaded.size,
33
- runId: result.runId,
34
- sessionKey: result.sessionKey,
35
- messageId: result.messageId,
36
- }));
37
- return;
38
- }
39
-
40
- console.log(t("send.completed", uploaded.fileName, result.sessionKey));
41
- console.log(uploaded.url);
42
- }