@clappstore/connect 0.7.7 → 0.7.8

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 (41) hide show
  1. package/dist/agent-client.d.ts +6 -0
  2. package/dist/agent-client.d.ts.map +1 -1
  3. package/dist/agent-client.js +109 -18
  4. package/dist/agent-client.js.map +1 -1
  5. package/dist/auth.d.ts +18 -0
  6. package/dist/auth.d.ts.map +1 -0
  7. package/dist/auth.js +248 -0
  8. package/dist/auth.js.map +1 -0
  9. package/dist/chat-handler.d.ts +52 -0
  10. package/dist/chat-handler.d.ts.map +1 -0
  11. package/dist/chat-handler.js +453 -0
  12. package/dist/chat-handler.js.map +1 -0
  13. package/dist/defaults.d.ts +1 -1
  14. package/dist/defaults.d.ts.map +1 -1
  15. package/dist/defaults.js +36 -23
  16. package/dist/defaults.js.map +1 -1
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +53 -30
  20. package/dist/index.js.map +1 -1
  21. package/dist/server.d.ts +1 -0
  22. package/dist/server.d.ts.map +1 -1
  23. package/dist/server.js +88 -7
  24. package/dist/server.js.map +1 -1
  25. package/dist/settings-handler.d.ts +76 -0
  26. package/dist/settings-handler.d.ts.map +1 -0
  27. package/dist/settings-handler.js +848 -0
  28. package/dist/settings-handler.js.map +1 -0
  29. package/package.json +4 -8
  30. package/web-app/assets/{index-CEpgiIwf.js → index-CWzlxjUK.js} +86 -56
  31. package/web-app/assets/index-Cic64hbc.css +1 -0
  32. package/web-app/index.html +2 -2
  33. package/clapps/settings/README.md +0 -74
  34. package/clapps/settings/clapp.json +0 -25
  35. package/clapps/settings/components/ProviderEditor.tsx +0 -512
  36. package/clapps/settings/components/ProviderList.tsx +0 -300
  37. package/clapps/settings/components/SessionList.tsx +0 -189
  38. package/clapps/settings/handlers/settings-handler.js +0 -742
  39. package/clapps/settings/views/default.settings.view.md +0 -35
  40. package/clapps/settings/views/settings.app.md +0 -12
  41. package/web-app/assets/index-BsI5PEAv.css +0 -1
@@ -1,742 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { spawnSync } from "node:child_process";
3
- import { dirname, resolve } from "node:path";
4
- import { homedir } from "node:os";
5
- // --- CLI helpers ---
6
- function runCli(args) {
7
- try {
8
- const result = spawnSync("openclaw", args, {
9
- encoding: "utf-8",
10
- timeout: 15_000,
11
- });
12
- if (result.status !== 0)
13
- return null;
14
- return JSON.parse(result.stdout);
15
- }
16
- catch {
17
- return null;
18
- }
19
- }
20
- let _modelsStatusCache = null;
21
- function getModelsStatus() {
22
- const now = Date.now();
23
- if (_modelsStatusCache && now - _modelsStatusCache.ts < 5_000) {
24
- return _modelsStatusCache.data;
25
- }
26
- const result = runCli(["models", "status", "--json"]);
27
- if (result && typeof result === "object") {
28
- _modelsStatusCache = { data: result, ts: now };
29
- return _modelsStatusCache.data;
30
- }
31
- return null;
32
- }
33
- let _modelCatalogCache = null;
34
- function getModelCatalog() {
35
- const now = Date.now();
36
- if (_modelCatalogCache && now - _modelCatalogCache.ts < 30_000) {
37
- return _modelCatalogCache.data;
38
- }
39
- const result = runCli(["models", "list", "--json"]);
40
- if (Array.isArray(result)) {
41
- _modelCatalogCache = { data: result, ts: now };
42
- return result;
43
- }
44
- return null;
45
- }
46
- function getAuthStorePath() {
47
- const status = getModelsStatus();
48
- const auth = status?.auth;
49
- if (typeof auth?.storePath === "string" && auth.storePath.length > 0) {
50
- return auth.storePath;
51
- }
52
- // Fallback to default path
53
- return resolve(homedir(), ".openclaw", "agents", "main", "agent", "auth-profiles.json");
54
- }
55
- // --- Helper functions ---
56
- function generateProfileId(provider, customName) {
57
- const suffix = customName
58
- ? customName.toLowerCase().replace(/[^a-z0-9]/g, "-").replace(/-+/g, "-")
59
- : "manual";
60
- return `${provider}:${suffix}`;
61
- }
62
- function maskCredential(credential) {
63
- if (credential.length <= 12)
64
- return "***";
65
- return credential.slice(0, 7) + "..." + credential.slice(-4);
66
- }
67
- function formatProviderName(provider) {
68
- const names = {
69
- anthropic: "Anthropic",
70
- openai: "OpenAI",
71
- "openai-codex": "OpenAI Codex",
72
- gemini: "Google Gemini",
73
- google: "Google",
74
- "kimi-coding": "Kimi Coding",
75
- nvidia: "NVIDIA",
76
- ollama: "Ollama",
77
- };
78
- return names[provider] ?? provider.charAt(0).toUpperCase() + provider.slice(1);
79
- }
80
- function formatModelLabelFromId(modelId) {
81
- if (!modelId)
82
- return "Unknown";
83
- const aliases = {
84
- "anthropic/claude-opus-4-5": "Claude Opus 4.5",
85
- "anthropic/claude-opus-4-6": "Claude Opus 4.6",
86
- "anthropic/claude-sonnet-4-5": "Claude Sonnet 4.5",
87
- "openai-codex/gpt-5.3-codex": "Codex (GPT-5.3)",
88
- "openai/gpt-5.2": "GPT-5.2",
89
- "kimi-coding/k2p5": "Kimi K2.5",
90
- };
91
- return aliases[modelId] || modelId.split("/").pop() || modelId;
92
- }
93
- function formatSessionLabel(key, agentId, originLabel, displayName) {
94
- if (originLabel) {
95
- const namePart = originLabel.split(" (")[0].split(" @")[0].split(" id:")[0];
96
- if (namePart && namePart.length > 0 && namePart.length < 30) {
97
- return namePart;
98
- }
99
- }
100
- if (displayName)
101
- return displayName;
102
- const parts = key.split(":");
103
- if (parts[0] === "agent")
104
- return agentId || parts[1] || key;
105
- const channelNames = {
106
- telegram: "Telegram",
107
- discord: "Discord",
108
- whatsapp: "WhatsApp",
109
- signal: "Signal",
110
- slack: "Slack",
111
- irc: "IRC",
112
- };
113
- return channelNames[parts[0]] || parts[0];
114
- }
115
- function detectAuthType(profileId, profile) {
116
- if (profile.access || profile.refresh)
117
- return "subscription";
118
- const lowerProfileId = profileId.toLowerCase();
119
- if (lowerProfileId.includes("-sub") || lowerProfileId.includes("sub-"))
120
- return "subscription";
121
- if (profile.provider === "anthropic" && profile.token) {
122
- if (profile.token.startsWith("sk-ant-api"))
123
- return "api-key";
124
- if (profile.token.startsWith("sk-ant-oat") || profile.token.startsWith("sk-ant-sid"))
125
- return "subscription";
126
- }
127
- if (profile.provider === "openai-codex")
128
- return "subscription";
129
- return "api-key";
130
- }
131
- function getActiveModel() {
132
- const status = getModelsStatus();
133
- if (typeof status?.defaultModel === "string") {
134
- return status.defaultModel;
135
- }
136
- return null;
137
- }
138
- function getModelCatalogByProvider() {
139
- const map = new Map();
140
- const catalog = getModelCatalog();
141
- if (!catalog)
142
- return map;
143
- for (const entry of catalog) {
144
- const m = entry;
145
- const key = m.key;
146
- if (typeof key !== "string" || !key.includes("/"))
147
- continue;
148
- const [provider] = key.split("/");
149
- if (!provider)
150
- continue;
151
- const name = typeof m.name === "string" ? m.name : key.split("/").slice(1).join("/");
152
- const existing = map.get(provider) ?? [];
153
- existing.push({ id: key, label: name });
154
- map.set(provider, existing);
155
- }
156
- for (const [provider, entries] of map) {
157
- entries.sort((a, b) => a.label.localeCompare(b.label));
158
- map.set(provider, entries);
159
- }
160
- return map;
161
- }
162
- function getFirstModelForProvider(provider) {
163
- const modelsByProvider = getModelCatalogByProvider();
164
- const normalizedProviderAliases = {
165
- "openai codex": "openai-codex",
166
- "google gemini": "gemini",
167
- "kimi coding": "kimi-coding",
168
- "kimi k2": "nvidia",
169
- glm5: "nvidia",
170
- };
171
- const normalizedProvider = normalizedProviderAliases[provider] ?? provider;
172
- const models = modelsByProvider.get(normalizedProvider) ?? [];
173
- return models[0]?.id ?? null;
174
- }
175
- function getConfiguredProviders() {
176
- const providers = [];
177
- const activeModelId = getActiveModel();
178
- const modelsByProvider = getModelCatalogByProvider();
179
- const authPath = getAuthStorePath();
180
- try {
181
- if (!existsSync(authPath))
182
- return providers;
183
- const data = JSON.parse(readFileSync(authPath, "utf-8"));
184
- for (const [profileId, profile] of Object.entries(data.profiles)) {
185
- let maskedCred = "";
186
- let mode = profile.type;
187
- let authType = "api-key";
188
- if (profile.token) {
189
- maskedCred = maskCredential(profile.token);
190
- mode = "token";
191
- authType = detectAuthType(profileId, profile);
192
- }
193
- else if (profile.key) {
194
- maskedCred = maskCredential(profile.key);
195
- mode = "api_key";
196
- authType = "api-key";
197
- }
198
- else if (profile.access) {
199
- maskedCred = "OAuth connected";
200
- mode = "oauth";
201
- authType = "subscription";
202
- }
203
- if (maskedCred) {
204
- const activeProvider = activeModelId?.split("/")[0];
205
- const isActive = activeProvider === profile.provider;
206
- const profileIdentifier = profileId.includes(":") ? profileId.split(":")[1] : profileId;
207
- const baseName = formatProviderName(profile.provider);
208
- const displayName = profile.customName || `${baseName} · ${profileIdentifier}`;
209
- providers.push({
210
- id: profileId,
211
- name: displayName,
212
- configured: true,
213
- mode,
214
- authType,
215
- maskedCredential: maskedCred,
216
- active: isActive,
217
- models: modelsByProvider.get(profile.provider) ?? [],
218
- });
219
- }
220
- }
221
- providers.sort((a, b) => {
222
- if (a.active && !b.active)
223
- return -1;
224
- if (!a.active && b.active)
225
- return 1;
226
- return a.name.localeCompare(b.name);
227
- });
228
- }
229
- catch (err) {
230
- console.warn(`[settings] Failed to read auth-profiles.json: ${err}`);
231
- }
232
- return providers;
233
- }
234
- function readAuthProfiles() {
235
- const authPath = getAuthStorePath();
236
- try {
237
- if (existsSync(authPath)) {
238
- return JSON.parse(readFileSync(authPath, "utf-8"));
239
- }
240
- }
241
- catch {
242
- // Start fresh
243
- }
244
- return { version: 1, profiles: {} };
245
- }
246
- function writeAuthProfiles(profiles) {
247
- const authPath = getAuthStorePath();
248
- mkdirSync(dirname(authPath), { recursive: true });
249
- writeFileSync(authPath, JSON.stringify(profiles, null, 2), "utf-8");
250
- }
251
- function getSessionsData() {
252
- try {
253
- const listResult = spawnSync("openclaw", ["gateway", "call", "sessions.list", "--params", '{"limit": 50}', "--json"], { encoding: "utf-8", timeout: 15_000 });
254
- if (listResult.status !== 0)
255
- return { sessions: [], globalModel: null };
256
- let rawSessions = [];
257
- try {
258
- const parsed = JSON.parse(listResult.stdout);
259
- rawSessions = parsed.sessions || [];
260
- }
261
- catch {
262
- return { sessions: [], globalModel: null };
263
- }
264
- const globalModelId = getActiveModel();
265
- const sessions = rawSessions
266
- .filter((s) => s.kind === "direct")
267
- .map((s) => {
268
- const sessionModel = s.modelProvider && s.model
269
- ? `${s.modelProvider}/${s.model}`
270
- : s.model || globalModelId;
271
- const isOverride = sessionModel !== globalModelId;
272
- return {
273
- key: s.key,
274
- label: formatSessionLabel(s.key, s.agentId, s.origin?.label, s.displayName),
275
- model: sessionModel,
276
- modelLabel: formatModelLabelFromId(sessionModel),
277
- isOverride,
278
- lastUpdated: s.updatedAt ? new Date(s.updatedAt).toISOString() : undefined,
279
- };
280
- })
281
- .sort((a, b) => {
282
- if (a.isOverride && !b.isOverride)
283
- return -1;
284
- if (!a.isOverride && b.isOverride)
285
- return 1;
286
- return 0;
287
- });
288
- return { sessions, globalModel: globalModelId };
289
- }
290
- catch {
291
- return { sessions: [], globalModel: null };
292
- }
293
- }
294
- // === Factory ===
295
- export default function createSettingsHandler(ctx) {
296
- function writeSettingsState() {
297
- const providers = getConfiguredProviders();
298
- const isConfigured = providers.length > 0;
299
- const activeModelId = getActiveModel();
300
- const activeProvider = providers.find((p) => p.active);
301
- const sessionsData = getSessionsData();
302
- const state = {
303
- version: Date.now(),
304
- timestamp: new Date().toISOString(),
305
- state: {
306
- active: {
307
- isConfigured,
308
- provider: activeProvider?.name ?? null,
309
- model: activeModelId,
310
- },
311
- configuredProviders: providers,
312
- sessions: sessionsData,
313
- },
314
- };
315
- const statePath = resolve(ctx.stateDir, "settings.json");
316
- writeFileSync(statePath, JSON.stringify(state, null, 2), "utf-8");
317
- }
318
- function pushSettingsState() {
319
- const statePath = resolve(ctx.stateDir, "settings.json");
320
- const content = readFileSync(statePath, "utf-8");
321
- ctx.setState("settings", JSON.parse(content));
322
- }
323
- function pushStatusState() {
324
- const statePath = resolve(ctx.stateDir, "_status.json");
325
- if (existsSync(statePath)) {
326
- const content = readFileSync(statePath, "utf-8");
327
- ctx.setState("_status", JSON.parse(content));
328
- }
329
- }
330
- function afterCredentialChange() {
331
- // Invalidate caches so next read picks up changes
332
- _modelsStatusCache = null;
333
- writeSettingsState();
334
- pushSettingsState();
335
- ctx.checkAuthStatus();
336
- pushStatusState();
337
- }
338
- function patchAllSessionModels(newModelId) {
339
- try {
340
- const listResult = spawnSync("openclaw", ["gateway", "call", "sessions.list", "--params", '{"limit": 100}', "--json"], { encoding: "utf-8", timeout: 15_000 });
341
- if (listResult.status !== 0) {
342
- console.warn(`[settings] Failed to list sessions: ${listResult.stderr}`);
343
- return;
344
- }
345
- let sessions = [];
346
- try {
347
- const parsed = JSON.parse(listResult.stdout);
348
- sessions = parsed.sessions || [];
349
- }
350
- catch {
351
- console.warn(`[settings] Failed to parse sessions list`);
352
- return;
353
- }
354
- const mainSessions = sessions.filter((s) => s.kind === "direct" || s.key.endsWith(":main"));
355
- for (const session of mainSessions) {
356
- const idempotencyKey = `clapps-model-${session.key}-${Date.now()}`;
357
- const sendResult = spawnSync("openclaw", [
358
- "gateway",
359
- "call",
360
- "chat.send",
361
- "--params",
362
- JSON.stringify({
363
- sessionKey: session.key,
364
- message: `/model ${newModelId}`,
365
- idempotencyKey,
366
- }),
367
- ], { encoding: "utf-8", timeout: 10_000 });
368
- if (sendResult.status === 0) {
369
- console.log(`[settings] Sent /model to session "${session.key}"`);
370
- }
371
- else {
372
- console.warn(`[settings] Failed to send /model to "${session.key}": ${sendResult.stderr}`);
373
- }
374
- }
375
- }
376
- catch (err) {
377
- console.warn(`[settings] Failed to update session models: ${err}`);
378
- }
379
- }
380
- function clearAgentModelOverrides(newModelId) {
381
- try {
382
- const configPath = resolve(homedir(), ".openclaw", "openclaw.json");
383
- if (!existsSync(configPath))
384
- return;
385
- const config = JSON.parse(readFileSync(configPath, "utf-8"));
386
- if (Array.isArray(config.agents?.list)) {
387
- let changed = false;
388
- for (const agent of config.agents.list) {
389
- if (agent.model && agent.model !== newModelId) {
390
- agent.model = newModelId;
391
- changed = true;
392
- console.log(`[settings] Updated agent "${agent.id}" model to ${newModelId}`);
393
- }
394
- }
395
- if (changed) {
396
- if (config.meta)
397
- config.meta.lastTouchedAt = new Date().toISOString();
398
- writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
399
- console.log(`[settings] Saved openclaw.json with updated agent models`);
400
- }
401
- }
402
- }
403
- catch (err) {
404
- console.warn(`[settings] Failed to update agent model overrides: ${err}`);
405
- }
406
- patchAllSessionModels(newModelId);
407
- }
408
- function listSessions() {
409
- try {
410
- const listResult = spawnSync("openclaw", ["gateway", "call", "sessions.list", "--params", '{"limit": 50}', "--json"], { encoding: "utf-8", timeout: 15_000 });
411
- if (listResult.status !== 0) {
412
- console.warn(`[settings] Failed to list sessions: ${listResult.stderr}`);
413
- return;
414
- }
415
- let rawSessions = [];
416
- try {
417
- const parsed = JSON.parse(listResult.stdout);
418
- rawSessions = parsed.sessions || [];
419
- }
420
- catch {
421
- console.warn(`[settings] Failed to parse sessions list`);
422
- return;
423
- }
424
- const globalModelId = getActiveModel();
425
- const sessions = rawSessions
426
- .filter((s) => s.kind === "direct")
427
- .map((s) => {
428
- const sessionModel = s.modelProvider && s.model
429
- ? `${s.modelProvider}/${s.model}`
430
- : s.model || globalModelId;
431
- const isOverride = sessionModel !== globalModelId;
432
- return {
433
- key: s.key,
434
- label: formatSessionLabel(s.key, s.agentId, s.origin?.label, s.displayName),
435
- model: sessionModel,
436
- modelLabel: formatModelLabelFromId(sessionModel),
437
- isOverride,
438
- lastUpdated: s.updatedAt ? new Date(s.updatedAt).toISOString() : undefined,
439
- };
440
- })
441
- .sort((a, b) => {
442
- if (a.isOverride && !b.isOverride)
443
- return -1;
444
- if (!a.isOverride && b.isOverride)
445
- return 1;
446
- return 0;
447
- });
448
- const statePath = resolve(ctx.stateDir, "sessions.json");
449
- const state = {
450
- version: Date.now(),
451
- timestamp: new Date().toISOString(),
452
- state: { sessions, globalModel: globalModelId },
453
- };
454
- writeFileSync(statePath, JSON.stringify(state, null, 2), "utf-8");
455
- ctx.setState("sessions", state);
456
- }
457
- catch (err) {
458
- console.warn(`[settings] Failed to list sessions: ${err}`);
459
- }
460
- }
461
- // --- Credential setters ---
462
- function setAnthropicKey(apiKey, customName, existingProfileId) {
463
- const profiles = readAuthProfiles();
464
- const profileId = existingProfileId ?? generateProfileId("anthropic", customName);
465
- profiles.profiles[profileId] = {
466
- type: "token",
467
- provider: "anthropic",
468
- token: apiKey,
469
- customName: customName || "Anthropic API",
470
- };
471
- writeAuthProfiles(profiles);
472
- console.log(`[settings] Anthropic API key saved (profile: ${profileId})`);
473
- afterCredentialChange();
474
- }
475
- function setClaudeToken(token, customName) {
476
- const profiles = readAuthProfiles();
477
- const profileId = generateProfileId("anthropic", customName || "claude-sub");
478
- profiles.profiles[profileId] = {
479
- type: "token",
480
- provider: "anthropic",
481
- token,
482
- customName: customName || "Claude Subscription",
483
- };
484
- writeAuthProfiles(profiles);
485
- console.log(`[settings] Claude subscription token saved (profile: ${profileId})`);
486
- afterCredentialChange();
487
- }
488
- function setOpenAIKey(apiKey, customName, existingProfileId) {
489
- const profiles = readAuthProfiles();
490
- const profileId = existingProfileId ?? generateProfileId("openai", customName);
491
- profiles.profiles[profileId] = {
492
- type: "token",
493
- provider: "openai",
494
- token: apiKey,
495
- customName: customName || "OpenAI API",
496
- };
497
- writeAuthProfiles(profiles);
498
- console.log(`[settings] OpenAI API key saved (profile: ${profileId})`);
499
- afterCredentialChange();
500
- }
501
- function setKimiCodingKey(apiKey, customName, existingProfileId) {
502
- const profiles = readAuthProfiles();
503
- const profileId = existingProfileId ?? generateProfileId("kimi-coding", customName);
504
- profiles.profiles[profileId] = {
505
- type: "token",
506
- provider: "kimi-coding",
507
- token: apiKey,
508
- customName: customName || "Kimi Coding",
509
- };
510
- writeAuthProfiles(profiles);
511
- console.log(`[settings] Kimi Coding API key saved (profile: ${profileId})`);
512
- afterCredentialChange();
513
- }
514
- function startOAuth(provider, customName) {
515
- const result = spawnSync("openclaw", ["models", "auth", "login", "--provider", provider], { encoding: "utf-8", timeout: 30_000, stdio: "inherit" });
516
- if (result.status !== 0) {
517
- console.error(`[settings] OAuth login failed for ${provider}`);
518
- return;
519
- }
520
- if (customName) {
521
- try {
522
- const authPath = getAuthStorePath();
523
- if (existsSync(authPath)) {
524
- const profiles = JSON.parse(readFileSync(authPath, "utf-8"));
525
- for (const [_key, profile] of Object.entries(profiles.profiles)) {
526
- if (profile.provider === provider && (profile.access || profile.refresh)) {
527
- profile.customName = customName;
528
- break;
529
- }
530
- }
531
- writeFileSync(authPath, JSON.stringify(profiles, null, 2), "utf-8");
532
- }
533
- }
534
- catch {
535
- // Ignore
536
- }
537
- }
538
- console.log(`[settings] OAuth login completed for ${provider}`);
539
- afterCredentialChange();
540
- }
541
- function deleteProvider(profileId) {
542
- try {
543
- const authPath = getAuthStorePath();
544
- if (!existsSync(authPath)) {
545
- console.warn(`[settings] No auth-profiles.json found`);
546
- return;
547
- }
548
- const profiles = JSON.parse(readFileSync(authPath, "utf-8"));
549
- if (!profiles.profiles[profileId]) {
550
- console.warn(`[settings] Profile "${profileId}" not found`);
551
- return;
552
- }
553
- delete profiles.profiles[profileId];
554
- writeFileSync(authPath, JSON.stringify(profiles, null, 2), "utf-8");
555
- console.log(`[settings] Deleted provider profile: ${profileId}`);
556
- afterCredentialChange();
557
- }
558
- catch (err) {
559
- console.error(`[settings] Failed to delete provider: ${err}`);
560
- }
561
- }
562
- function setActiveProvider(provider) {
563
- const modelId = getFirstModelForProvider(provider);
564
- if (!modelId) {
565
- console.warn(`[settings] Unknown provider or no models available: ${provider}`);
566
- return;
567
- }
568
- setActiveModel(modelId);
569
- }
570
- function setActiveModel(modelId) {
571
- const result = spawnSync("openclaw", ["models", "set", modelId], {
572
- encoding: "utf-8",
573
- timeout: 20_000,
574
- });
575
- if (result.status !== 0) {
576
- const msg = (result.stderr || result.error?.message || "unknown error").toString().trim();
577
- console.error(`[settings] Failed to set default model: ${msg}`);
578
- return;
579
- }
580
- _modelsStatusCache = null;
581
- clearAgentModelOverrides(modelId);
582
- console.log(`[settings] Active model set system-wide to ${modelId}`);
583
- writeSettingsState();
584
- pushSettingsState();
585
- }
586
- function resetSessionModel(sessionKey) {
587
- const globalModelId = getActiveModel();
588
- if (!globalModelId) {
589
- console.warn(`[settings] No global default model configured`);
590
- return;
591
- }
592
- const result = spawnSync("openclaw", [
593
- "gateway",
594
- "call",
595
- "chat.send",
596
- "--params",
597
- JSON.stringify({
598
- sessionKey,
599
- message: `/model ${globalModelId}`,
600
- idempotencyKey: `clapps-reset-${sessionKey}-${Date.now()}`,
601
- }),
602
- ], { encoding: "utf-8", timeout: 10_000 });
603
- if (result.status === 0) {
604
- console.log(`[settings] Reset session "${sessionKey}" to default model`);
605
- }
606
- else {
607
- console.warn(`[settings] Failed to reset session "${sessionKey}": ${result.stderr}`);
608
- }
609
- setTimeout(() => listSessions(), 1000);
610
- }
611
- function applyDefaultToAllSessions() {
612
- const globalModelId = getActiveModel();
613
- if (!globalModelId) {
614
- console.warn(`[settings] No global default model configured`);
615
- return;
616
- }
617
- patchAllSessionModels(globalModelId);
618
- setTimeout(() => listSessions(), 2000);
619
- }
620
- function refreshSettingsState() {
621
- _modelsStatusCache = null;
622
- _modelCatalogCache = null;
623
- writeSettingsState();
624
- pushSettingsState();
625
- listSessions();
626
- }
627
- // --- Handler interface ---
628
- return {
629
- handleIntent(intent) {
630
- if (!intent.intent.startsWith("settings."))
631
- return false;
632
- const customName = typeof intent.payload.customName === "string"
633
- ? intent.payload.customName.trim()
634
- : undefined;
635
- const profileId = typeof intent.payload.profileId === "string"
636
- ? intent.payload.profileId.trim()
637
- : undefined;
638
- switch (intent.intent) {
639
- case "settings.setAnthropicKey": {
640
- const apiKey = intent.payload.apiKey;
641
- if (typeof apiKey !== "string" || apiKey.trim().length === 0) {
642
- console.warn("[settings] Invalid apiKey payload, ignoring");
643
- return true;
644
- }
645
- setAnthropicKey(apiKey.trim(), customName, profileId);
646
- return true;
647
- }
648
- case "settings.setClaudeToken": {
649
- const token = intent.payload.setupToken ?? intent.payload.token;
650
- if (typeof token !== "string" || token.trim().length === 0) {
651
- console.warn("[settings] Invalid token/setupToken payload, ignoring");
652
- return true;
653
- }
654
- setClaudeToken(token.trim(), customName);
655
- return true;
656
- }
657
- case "settings.setOpenAIKey": {
658
- const apiKey = intent.payload.apiKey;
659
- if (typeof apiKey !== "string" || apiKey.trim().length === 0) {
660
- console.warn("[settings] Invalid apiKey payload, ignoring");
661
- return true;
662
- }
663
- setOpenAIKey(apiKey.trim(), customName, profileId);
664
- return true;
665
- }
666
- case "settings.setKimiCodingKey": {
667
- const apiKey = intent.payload.apiKey;
668
- if (typeof apiKey !== "string" || apiKey.trim().length === 0) {
669
- console.warn("[settings] Invalid apiKey payload, ignoring");
670
- return true;
671
- }
672
- setKimiCodingKey(apiKey.trim(), customName, profileId);
673
- return true;
674
- }
675
- case "settings.startOAuth": {
676
- const provider = intent.payload.provider;
677
- if (typeof provider !== "string" || provider.trim().length === 0) {
678
- console.warn("[settings] Invalid provider payload for OAuth, ignoring");
679
- return true;
680
- }
681
- startOAuth(provider.trim(), customName);
682
- return true;
683
- }
684
- case "settings.deleteProvider": {
685
- if (!profileId) {
686
- console.warn("[settings] Missing profileId for deleteProvider, ignoring");
687
- return true;
688
- }
689
- deleteProvider(profileId);
690
- return true;
691
- }
692
- case "settings.setActiveProvider": {
693
- const provider = intent.payload.provider;
694
- if (typeof provider !== "string" || provider.trim().length === 0) {
695
- console.warn("[settings] Invalid provider payload, ignoring");
696
- return true;
697
- }
698
- setActiveProvider(provider.trim().toLowerCase());
699
- return true;
700
- }
701
- case "settings.setActiveModel": {
702
- const model = intent.payload.model;
703
- if (typeof model !== "string" || model.trim().length === 0) {
704
- console.warn("[settings] Invalid model payload, ignoring");
705
- return true;
706
- }
707
- setActiveModel(model.trim().toLowerCase());
708
- return true;
709
- }
710
- case "settings.listSessions": {
711
- listSessions();
712
- return true;
713
- }
714
- case "settings.resetSessionModel": {
715
- const sessionKey = intent.payload.sessionKey;
716
- if (typeof sessionKey !== "string" || sessionKey.trim().length === 0) {
717
- console.warn("[settings] Invalid sessionKey payload, ignoring");
718
- return true;
719
- }
720
- resetSessionModel(sessionKey.trim());
721
- return true;
722
- }
723
- case "settings.applyDefaultToAll": {
724
- applyDefaultToAllSessions();
725
- return true;
726
- }
727
- default:
728
- console.warn(`[settings] Unknown settings intent: ${intent.intent}`);
729
- return true;
730
- }
731
- },
732
- onConnect() {
733
- refreshSettingsState();
734
- },
735
- refresh() {
736
- refreshSettingsState();
737
- },
738
- init() {
739
- writeSettingsState();
740
- },
741
- };
742
- }