create-openclaw-bot 5.6.14 → 5.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,467 @@
1
+ // @ts-nocheck
2
+ /**
3
+ * @fileoverview Centralized bot configuration builders — single source of truth.
4
+ *
5
+ * Generates openclaw.json, auth-profiles.json, exec-approvals.json, and .env content.
6
+ * Used by BOTH the Wizard (IIFE bundle) and CLI (CJS require).
7
+ *
8
+ * Pattern: same as common-gen.js / workspace-gen.js — IIFE + CJS dual export.
9
+ */
10
+ (function (root) {
11
+
12
+ const _common = (typeof root !== 'undefined' && root.__openclawCommon) || {};
13
+
14
+ // ── Helper: slugify a bot name into a safe agent ID ─────────────────────────
15
+ function slugify(name) {
16
+ return String(name || 'bot').toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') || 'bot';
17
+ }
18
+
19
+ // ── Helper: detect if channel is zalo personal ───────────────────────────────
20
+ function isZaloPersonal(channelKey) {
21
+ return channelKey === 'zalo-personal';
22
+ }
23
+
24
+ // ── Helper: generate a random token (works in both browser + Node) ──────────
25
+ function generateToken() {
26
+ if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
27
+ return crypto.randomUUID().replace(/-/g, '');
28
+ }
29
+ // Fallback for older Node.js
30
+ const hex = '0123456789abcdef';
31
+ let result = '';
32
+ for (let i = 0; i < 32; i++) result += hex[Math.floor(Math.random() * 16)];
33
+ return result;
34
+ }
35
+
36
+
37
+ // ═══════════════════════════════════════════════════════════════════════════════
38
+ // buildOpenclawJson — the ONE function that generates the full openclaw.json
39
+ // ═══════════════════════════════════════════════════════════════════════════════
40
+ /**
41
+ * @param {object} opts
42
+ * @param {string} opts.channelKey - 'telegram' | 'zalo-personal' | 'zalo-bot'
43
+ * @param {string} opts.deployMode - 'docker' | 'native'
44
+ * @param {string} opts.providerKey - '9router' | 'openai' | 'ollama' | ...
45
+ * @param {object} opts.provider - Provider metadata object from PROVIDERS
46
+ * @param {string} opts.model - Primary model ID (e.g. 'smart-route', 'gemma4:e2b')
47
+ * @param {boolean} opts.isMultiBot - Multi-bot mode
48
+ * @param {Array} opts.agentMetas - [{ agentId, name, desc, persona, token, slashCmd, accountId, workspaceDir }]
49
+ * @param {string} opts.groupId - Telegram group ID (multi-bot only)
50
+ * @param {Array} opts.selectedSkills - ['browser', 'memory', 'scheduler', ...]
51
+ * @param {Array} opts.skills - Full SKILLS registry array
52
+ * @param {boolean} opts.hasBrowserDesktop - Browser desktop mode
53
+ * @param {boolean} opts.hasBrowserServer - Browser server mode
54
+ * @param {number} [opts.gatewayPort=18791]
55
+ * @param {Array} [opts.gatewayAllowedOrigins]
56
+ * @param {string} [opts.osChoice] - 'windows' | 'macos' | 'vps' | 'ubuntu'
57
+ * @param {string} [opts.selectedModel] - For Ollama: specific model selected
58
+ */
59
+ function buildOpenclawJson(opts) {
60
+ const {
61
+ channelKey = 'telegram',
62
+ deployMode = 'docker',
63
+ providerKey = '9router',
64
+ provider = {},
65
+ model = 'smart-route',
66
+ isMultiBot = false,
67
+ agentMetas = [],
68
+ groupId = '',
69
+ selectedSkills = [],
70
+ skills = [],
71
+ hasBrowserDesktop = false,
72
+ hasBrowserServer = false,
73
+ gatewayPort = 18791,
74
+ gatewayAllowedOrigins = [],
75
+ osChoice = '',
76
+ selectedModel = '',
77
+ } = opts;
78
+
79
+ const common = _common;
80
+ const is9Router = providerKey === '9router';
81
+ const isLocal = !!provider.isLocal;
82
+
83
+ // ── agents ────────────────────────────────────────────────────────────────
84
+ const agentsList = agentMetas.map((meta) => ({
85
+ id: meta.agentId,
86
+ ...(meta.name ? { name: meta.name } : {}),
87
+ workspace: `.openclaw/${meta.workspaceDir || 'workspace-' + meta.agentId}`,
88
+ agentDir: `agents/${meta.agentId}/agent`,
89
+ model: { primary: model, fallbacks: [] },
90
+ }));
91
+
92
+ const cfg = {
93
+ meta: { lastTouchedVersion: (_common.OPENCLAW_NPM_SPEC || 'latest').replace('openclaw@', '') },
94
+ agents: {
95
+ defaults: {
96
+ model: { primary: model, fallbacks: [] },
97
+ compaction: { mode: 'safeguard' },
98
+ timeoutSeconds: isLocal ? 900 : 120,
99
+ ...(isLocal ? { llm: { idleTimeoutSeconds: 300 } } : {}),
100
+ },
101
+ list: agentsList,
102
+ },
103
+ };
104
+
105
+ // ── models.providers ──────────────────────────────────────────────────────
106
+ if (is9Router && common.build9RouterProviderConfig) {
107
+ cfg.models = {
108
+ mode: 'merge',
109
+ providers: {
110
+ '9router': common.build9RouterProviderConfig(
111
+ common.get9RouterBaseUrl ? common.get9RouterBaseUrl(deployMode) : 'http://9router:20128/v1'
112
+ ),
113
+ },
114
+ };
115
+ } else if (isLocal) {
116
+ const ollamaBaseUrl = deployMode === 'docker' ? 'http://ollama:11434' : 'http://localhost:11434';
117
+ const OLLAMA_MODELS = (typeof root !== 'undefined' && root.__openclawData && root.__openclawData.OLLAMA_MODELS)
118
+ || (typeof _OLLAMA_MODELS !== 'undefined' ? _OLLAMA_MODELS : []);
119
+ const modelList = selectedModel
120
+ ? [{ id: selectedModel, name: selectedModel, contextWindow: 128000, maxTokens: 8192 }]
121
+ : OLLAMA_MODELS;
122
+ cfg.models = {
123
+ mode: 'merge',
124
+ providers: {
125
+ ollama: {
126
+ baseUrl: ollamaBaseUrl,
127
+ api: 'ollama',
128
+ apiKey: 'ollama-local',
129
+ models: modelList,
130
+ },
131
+ },
132
+ };
133
+ }
134
+
135
+ // ── commands ──────────────────────────────────────────────────────────────
136
+ cfg.commands = { native: 'auto', nativeSkills: 'auto', restart: true, ownerDisplay: 'raw' };
137
+
138
+ // ── bindings (multi-bot or Zalo) ─────────────────────────────────────────
139
+ if (isMultiBot && channelKey === 'telegram') {
140
+ cfg.bindings = agentMetas.map((meta) => ({
141
+ agentId: meta.agentId,
142
+ match: { channel: 'telegram', accountId: meta.accountId || 'default' },
143
+ }));
144
+ }
145
+
146
+ // ── channels ─────────────────────────────────────────────────────────────
147
+ cfg.channels = buildChannelConfig({
148
+ channelKey, isMultiBot, groupId, agentMetas, botName: agentMetas[0]?.name || 'Bot',
149
+ agentId: agentMetas[0]?.agentId || 'bot',
150
+ });
151
+
152
+ // ── tools ────────────────────────────────────────────────────────────────
153
+ cfg.tools = { profile: 'full', exec: { host: 'gateway', security: 'full', ask: 'off' } };
154
+ if (isMultiBot) {
155
+ cfg.tools.agentToAgent = {
156
+ enabled: true,
157
+ allow: agentMetas.map((meta) => meta.agentId),
158
+ };
159
+ }
160
+
161
+ // ── gateway ──────────────────────────────────────────────────────────────
162
+ cfg.gateway = {
163
+ port: gatewayPort,
164
+ mode: 'local',
165
+ bind: (deployMode === 'docker' || osChoice === 'vps') ? 'custom' : 'loopback',
166
+ ...(deployMode === 'docker' || osChoice === 'vps' ? { customBindHost: '0.0.0.0' } : {}),
167
+ controlUi: {
168
+ allowedOrigins: gatewayAllowedOrigins.length > 0
169
+ ? gatewayAllowedOrigins
170
+ : [`http://localhost:${gatewayPort}`, `http://127.0.0.1:${gatewayPort}`, `http://0.0.0.0:${gatewayPort}`],
171
+ },
172
+ auth: { mode: 'token', token: generateToken() },
173
+ };
174
+
175
+ // ── browser ──────────────────────────────────────────────────────────────
176
+ if (hasBrowserDesktop) {
177
+ cfg.browser = {
178
+ enabled: true,
179
+ defaultProfile: 'host-chrome',
180
+ profiles: { 'host-chrome': { cdpUrl: 'http://127.0.0.1:9222', color: '#4285F4' } },
181
+ };
182
+ } else if (hasBrowserServer) {
183
+ cfg.browser = { enabled: true };
184
+ }
185
+
186
+ // ── skills ───────────────────────────────────────────────────────────────
187
+ const skillEntries = buildSkillsEntries(skills, selectedSkills);
188
+ if (Object.keys(skillEntries).length > 0) {
189
+ cfg.skills = { entries: skillEntries };
190
+ }
191
+
192
+ // ── plugins (memory-core dreaming + zalo-mod) ────────────────────────────
193
+ const pluginsConfig = buildPluginsConfig({
194
+ channelKey,
195
+ selectedSkills,
196
+ botName: agentMetas[0]?.name || 'Bot',
197
+ agentId: agentMetas[0]?.agentId || 'bot',
198
+ });
199
+ cfg.plugins = pluginsConfig.plugins;
200
+
201
+ // ── bindings for zalouser ────────────────────────────────────────────────
202
+ if (isZaloPersonal(channelKey)) {
203
+ cfg.bindings = cfg.bindings || [];
204
+ const firstAgentId = agentMetas[0]?.agentId || 'bot';
205
+ if (!cfg.bindings.some(b => b.match && b.match.channel === 'zalouser')) {
206
+ cfg.bindings.push({ agentId: firstAgentId, match: { channel: 'zalouser' } });
207
+ }
208
+ }
209
+
210
+ return cfg;
211
+ }
212
+
213
+
214
+ // ═══════════════════════════════════════════════════════════════════════════════
215
+ // buildChannelConfig — returns the full `channels: { ... }` object
216
+ // ═══════════════════════════════════════════════════════════════════════════════
217
+ function buildChannelConfig(opts) {
218
+ const { channelKey, isMultiBot, groupId, agentMetas = [], botName, agentId } = opts;
219
+ const channels = {};
220
+
221
+ if (channelKey === 'telegram') {
222
+ const telegramConfig = {
223
+ enabled: true,
224
+ defaultAccount: 'default',
225
+ dmPolicy: 'open',
226
+ allowFrom: ['*'],
227
+ replyToMode: 'first',
228
+ reactionLevel: 'minimal',
229
+ actions: {
230
+ sendMessage: true,
231
+ reactions: true,
232
+ },
233
+ accounts: {},
234
+ };
235
+
236
+ if (isMultiBot) {
237
+ // Multiple accounts — each bot gets its own account keyed by accountId
238
+ telegramConfig.accounts = {};
239
+ for (const meta of agentMetas) {
240
+ telegramConfig.accounts[meta.accountId || 'default'] = {
241
+ botToken: meta.token || '<your_bot_token>',
242
+ };
243
+ }
244
+ telegramConfig.groupPolicy = groupId ? 'allowlist' : 'open';
245
+ telegramConfig.groupAllowFrom = ['*'];
246
+ telegramConfig.groups = {
247
+ [groupId || '*']: { enabled: true, requireMention: false },
248
+ };
249
+ } else {
250
+ // Single bot
251
+ telegramConfig.accounts = {
252
+ default: {
253
+ botToken: (agentMetas[0] && agentMetas[0].token) || '<your_bot_token>',
254
+ },
255
+ };
256
+ }
257
+
258
+ channels.telegram = telegramConfig;
259
+ } else if (isZaloPersonal(channelKey)) {
260
+ // Zalo Personal — matches live Mkt/Williams configs
261
+ channels.zalouser = {
262
+ enabled: true,
263
+ defaultAccount: 'default',
264
+ dmPolicy: 'open',
265
+ allowFrom: ['*'],
266
+ groupPolicy: 'allowlist',
267
+ groupAllowFrom: ['*'],
268
+ historyLimit: 50,
269
+ groups: {
270
+ '*': { enabled: true, requireMention: false },
271
+ },
272
+ };
273
+ } else if (channelKey === 'zalo-bot') {
274
+ channels.zalo = { enabled: true, provider: 'official_account' };
275
+ }
276
+
277
+ return channels;
278
+ }
279
+
280
+
281
+ // ═══════════════════════════════════════════════════════════════════════════════
282
+ // buildPluginsConfig — returns { plugins: { ... } }
283
+ // ═══════════════════════════════════════════════════════════════════════════════
284
+ function buildPluginsConfig(opts) {
285
+ const { channelKey, selectedSkills = [], botName = 'Bot', agentId = 'bot' } = opts;
286
+
287
+ const entries = {};
288
+
289
+ // memory-core with dreaming — always present
290
+ entries['memory-core'] = {
291
+ config: {
292
+ dreaming: {
293
+ enabled: selectedSkills.includes('memory'),
294
+ },
295
+ },
296
+ };
297
+
298
+ const allow = [];
299
+
300
+ // zalo-mod plugin for Zalo Personal
301
+ if (isZaloPersonal(channelKey)) {
302
+ allow.push('zalo-mod');
303
+ entries['zalo-mod'] = {
304
+ enabled: true,
305
+ config: {
306
+ botName: botName,
307
+ groupNames: {},
308
+ zaloDisplayNames: [botName],
309
+ welcomeEnabled: true,
310
+ spamRepeatN: 3,
311
+ spamWindowSeconds: 300,
312
+ },
313
+ };
314
+ }
315
+
316
+ const plugins = { entries };
317
+ if (allow.length > 0) {
318
+ plugins.allow = allow;
319
+ }
320
+
321
+ return { plugins };
322
+ }
323
+
324
+
325
+ // ═══════════════════════════════════════════════════════════════════════════════
326
+ // buildSkillsEntries — returns { slug: { enabled: true } } map
327
+ // ═══════════════════════════════════════════════════════════════════════════════
328
+ function buildSkillsEntries(skills, selectedSkillIds) {
329
+ const entries = {};
330
+ if (!skills || !selectedSkillIds) return entries;
331
+
332
+ for (const skill of skills) {
333
+ const skillId = skill.value || skill.id;
334
+ if (!selectedSkillIds.includes(skillId)) continue;
335
+ // Skills without a slug are native (browser, scheduler) — not in skills.entries
336
+ const slug = skill.slug;
337
+ if (!slug) continue;
338
+ // Skip browser-automation slug (handled by browser config)
339
+ if (slug === 'browser-automation') continue;
340
+ entries[slug] = { enabled: true };
341
+ }
342
+
343
+ return entries;
344
+ }
345
+
346
+
347
+ // ═══════════════════════════════════════════════════════════════════════════════
348
+ // buildExecApprovalsJson — exec-approvals.json content
349
+ // ═══════════════════════════════════════════════════════════════════════════════
350
+ function buildExecApprovalsJson(opts) {
351
+ const { agentMetas = [] } = opts;
352
+ const agentEntries = {};
353
+ agentEntries.main = { security: 'full', ask: 'off', askFallback: 'full', autoAllowSkills: true };
354
+ for (const meta of agentMetas) {
355
+ agentEntries[meta.agentId] = { security: 'full', ask: 'off', askFallback: 'full', autoAllowSkills: true };
356
+ }
357
+ return {
358
+ version: 1,
359
+ defaults: { security: 'full', ask: 'off', askFallback: 'full' },
360
+ agents: agentEntries,
361
+ };
362
+ }
363
+
364
+
365
+ // ═══════════════════════════════════════════════════════════════════════════════
366
+ // buildEnvFileContent — .env file content for a single bot
367
+ // ═══════════════════════════════════════════════════════════════════════════════
368
+ /**
369
+ * @param {object} opts
370
+ * @param {object} opts.provider - Provider metadata
371
+ * @param {string} opts.providerKeyVal - API key value
372
+ * @param {string} opts.channelKey - Channel type
373
+ * @param {string} opts.botToken - Bot token
374
+ * @param {boolean} opts.isMultiBot
375
+ * @param {string} opts.groupId
376
+ * @param {Array} opts.selectedSkills
377
+ * @param {string} opts.ttsOpenaiKey
378
+ * @param {string} opts.ttsElevenKey
379
+ * @param {string} opts.smtpHost
380
+ * @param {string} opts.smtpPort
381
+ * @param {string} opts.smtpUser
382
+ * @param {string} opts.smtpPass
383
+ * @param {boolean} opts.isSharedEnv - If true, omit per-bot token (multi-bot shared .env)
384
+ */
385
+ function buildEnvFileContent(opts) {
386
+ const {
387
+ provider = {},
388
+ providerKeyVal = '',
389
+ channelKey = 'telegram',
390
+ botToken = '',
391
+ isMultiBot = false,
392
+ groupId = '',
393
+ selectedSkills = [],
394
+ ttsOpenaiKey = '',
395
+ ttsElevenKey = '',
396
+ smtpHost = 'smtp.gmail.com',
397
+ smtpPort = '587',
398
+ smtpUser = '',
399
+ smtpPass = '',
400
+ isSharedEnv = false,
401
+ } = opts;
402
+
403
+ const lines = [];
404
+
405
+ if (provider.isLocal) {
406
+ lines.push('OLLAMA_HOST=http://localhost:11434');
407
+ lines.push('OLLAMA_API_KEY=ollama-local');
408
+ } else if (provider.isProxy) {
409
+ lines.push('# 9Router: no API key needed');
410
+ } else if (provider.envKey) {
411
+ lines.push(`${provider.envKey}=${providerKeyVal || '<your_api_key>'}`);
412
+ }
413
+
414
+ if (!isSharedEnv) {
415
+ if (channelKey === 'telegram') {
416
+ lines.push(`TELEGRAM_BOT_TOKEN=${botToken || '<your_bot_token>'}`);
417
+ if (isMultiBot && groupId) lines.push(`TELEGRAM_GROUP_ID=${groupId}`);
418
+ } else if (channelKey === 'zalo-bot') {
419
+ lines.push('ZALO_APP_ID=');
420
+ lines.push('ZALO_APP_SECRET=');
421
+ lines.push(`ZALO_BOT_TOKEN=${botToken || '<your_zalo_bot_token>'}`);
422
+ }
423
+ }
424
+
425
+ if (selectedSkills.includes('tts')) {
426
+ lines.push('');
427
+ lines.push('# --- Text-To-Speech ---');
428
+ if (ttsOpenaiKey) lines.push(`OPENAI_API_KEY=${ttsOpenaiKey}`);
429
+ if (ttsElevenKey) lines.push(`ELEVENLABS_API_KEY=${ttsElevenKey}`);
430
+ }
431
+
432
+ if (selectedSkills.includes('email')) {
433
+ lines.push('');
434
+ lines.push('# --- Email ---');
435
+ lines.push(`SMTP_HOST=${smtpHost}`);
436
+ lines.push(`SMTP_PORT=${smtpPort}`);
437
+ lines.push(`SMTP_USER=${smtpUser}`);
438
+ lines.push(`SMTP_PASS=${smtpPass}`);
439
+ }
440
+
441
+ return lines.join('\n') + '\n';
442
+ }
443
+
444
+
445
+ // ═══════════════════════════════════════════════════════════════════════════════
446
+ // Export
447
+ // ═══════════════════════════════════════════════════════════════════════════════
448
+ const exports = {
449
+ slugify,
450
+ isZaloPersonal,
451
+ generateToken,
452
+ buildOpenclawJson,
453
+ buildChannelConfig,
454
+ buildPluginsConfig,
455
+ buildSkillsEntries,
456
+ buildExecApprovalsJson,
457
+ buildEnvFileContent,
458
+ };
459
+
460
+ if (typeof root !== 'undefined') {
461
+ root.__openclawBotConfig = exports;
462
+ }
463
+
464
+ })(typeof globalThis !== 'undefined' ? globalThis : {});
465
+ if (typeof exports !== 'undefined' && typeof globalThis !== 'undefined' && globalThis.__openclawBotConfig) {
466
+ Object.assign(exports, globalThis.__openclawBotConfig);
467
+ }
@@ -1,6 +1,6 @@
1
1
  // @ts-nocheck
2
2
  (function (root) {
3
- const OPENCLAW_NPM_SPEC = 'openclaw@2026.4.14';
3
+ const OPENCLAW_NPM_SPEC = 'openclaw@latest';
4
4
  const OPENCLAW_RUNTIME_PACKAGES = 'grammy @grammyjs/runner @grammyjs/transformer-throttler @buape/carbon @larksuiteoapi/node-sdk @slack/web-api';
5
5
  const NINE_ROUTER_NPM_SPEC = '9router@latest';
6
6
  const NINE_ROUTER_PORT = 20128;