create-openclaw-bot 5.1.13 → 5.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -1
- package/CHANGELOG.vi.md +18 -1
- package/README.md +11 -14
- package/README.vi.md +11 -14
- package/cli.js +290 -224
- package/docs/install-docker.md +3 -2
- package/docs/install-docker.vi.md +3 -2
- package/package.json +1 -1
- package/setup.js +405 -213
- package/tests/smoke-cli-logic.mjs +130 -23
|
@@ -52,8 +52,8 @@ checks.push(() => expectMatch(
|
|
|
52
52
|
|
|
53
53
|
checks.push(() => expectMatch(
|
|
54
54
|
cli,
|
|
55
|
-
/function installLatestOpenClaw\(\{ isVi, osChoice \}\) \{[\s\S]*installGlobalPackage\(
|
|
56
|
-
'CLI must provide a shared helper that always installs or upgrades openclaw
|
|
55
|
+
/function installLatestOpenClaw\(\{ isVi, osChoice \}\) \{[\s\S]*installGlobalPackage\(OPENCLAW_NPM_SPEC, \{ isVi, osChoice, displayName: 'openclaw' \}\)[\s\S]*process\.exit\(1\)/,
|
|
56
|
+
'CLI must provide a shared helper that always installs or upgrades the pinned openclaw version'
|
|
57
57
|
));
|
|
58
58
|
|
|
59
59
|
checks.push(() => expectMatch(
|
|
@@ -70,7 +70,7 @@ checks.push(() => expectMatch(
|
|
|
70
70
|
|
|
71
71
|
checks.push(() => expectMatch(
|
|
72
72
|
cli,
|
|
73
|
-
/if \(!isOpenClawInstalled\(\)\) \{[\s\S]*installGlobalPackage\(
|
|
73
|
+
/if \(!isOpenClawInstalled\(\)\) \{[\s\S]*installGlobalPackage\(OPENCLAW_NPM_SPEC, \{ isVi, osChoice, displayName: 'openclaw' \}\)/,
|
|
74
74
|
'Native branch must auto-install openclaw'
|
|
75
75
|
));
|
|
76
76
|
|
|
@@ -97,14 +97,14 @@ checks.push(() => expect(
|
|
|
97
97
|
&& cli.includes('const safeDbPath = JSON.stringify(dbPath);')
|
|
98
98
|
&& cli.includes("const ROUTER='http://localhost:20128';")
|
|
99
99
|
&& cli.includes("fetch(ROUTER + '/api/providers')")
|
|
100
|
-
&& cli.includes("build9RouterSmartRouteSyncScript(path.join(
|
|
101
|
-
'Native 9Router flow must write a smart-route sync script
|
|
100
|
+
&& cli.includes("build9RouterSmartRouteSyncScript(path.join(getProject9RouterDataDir(projectDir), 'db.json'))"),
|
|
101
|
+
'Native 9Router flow must write a smart-route sync script into the project-controlled 9Router data directory'
|
|
102
102
|
));
|
|
103
103
|
|
|
104
104
|
checks.push(() => expectMatch(
|
|
105
105
|
cli,
|
|
106
|
-
/function
|
|
107
|
-
'CLI
|
|
106
|
+
/function getProjectRuntimeEnv\(projectDir, extraEnv = \{\}\) \{[\s\S]*OPENCLAW_HOME: getProjectOpenClawHome\(projectDir\)[\s\S]*OPENCLAW_STATE_DIR: getProjectOpenClawHome\(projectDir\)[\s\S]*DATA_DIR: getProject9RouterDataDir\(projectDir\)/s,
|
|
107
|
+
'CLI native runtime must derive OPENCLAW_HOME, OPENCLAW_STATE_DIR, and DATA_DIR from the chosen project directory'
|
|
108
108
|
));
|
|
109
109
|
|
|
110
110
|
checks.push(() => expect(
|
|
@@ -146,8 +146,8 @@ checks.push(() => expectMatch(
|
|
|
146
146
|
|
|
147
147
|
checks.push(() => expectMatch(
|
|
148
148
|
cli,
|
|
149
|
-
/
|
|
150
|
-
'Native single-bot VPS must start gateway through PM2'
|
|
149
|
+
/execFileSync\('pm2', \[[\s\S]*'openclaw'[\s\S]*'gateway'[\s\S]*'run'[\s\S]*getProjectRuntimeEnv\(projectDir\)/s,
|
|
150
|
+
'Native single-bot VPS must start gateway through PM2 with the project runtime environment'
|
|
151
151
|
));
|
|
152
152
|
|
|
153
153
|
checks.push(() => expectMatch(
|
|
@@ -216,6 +216,25 @@ checks.push(() => expectMatch(
|
|
|
216
216
|
'Native per-bot gateway config must seed control UI allowed origins for each port'
|
|
217
217
|
));
|
|
218
218
|
|
|
219
|
+
checks.push(() => expectMatch(
|
|
220
|
+
cli,
|
|
221
|
+
/const dockerDir = path\.join\(projectDir, 'docker', 'openclaw'\);\s*await fs\.ensureDir\(dockerDir\);\s*await fs\.writeFile\(path\.join\(dockerDir, 'Dockerfile'\), dockerfile\);[\s\S]*await fs\.ensureDir\(dockerDir\);\s*await fs\.writeFile\(path\.join\(dockerDir, 'docker-compose\.yml'\), compose\);/s,
|
|
222
|
+
'Docker CLI flow must ensure docker/openclaw exists immediately before writing Dockerfile and docker-compose.yml'
|
|
223
|
+
));
|
|
224
|
+
|
|
225
|
+
checks.push(() => expectMatch(
|
|
226
|
+
cli,
|
|
227
|
+
/RUN npm install -g \$\{OPENCLAW_NPM_SPEC\} grammy/,
|
|
228
|
+
'Docker CLI image must install grammy alongside openclaw so Telegram runtime dependencies resolve'
|
|
229
|
+
));
|
|
230
|
+
|
|
231
|
+
checks.push(() => expect(
|
|
232
|
+
cli.includes("a.add('http://' + entry.address + ':18791')")
|
|
233
|
+
&& cli.includes('allowedOrigins:Array.from(a).filter(Boolean)')
|
|
234
|
+
&& !cli.includes("a.add(`http://${entry.address}:18791`)"),
|
|
235
|
+
'Docker CLI patch script must avoid shell-expanding ${entry.address} and must filter null origins'
|
|
236
|
+
));
|
|
237
|
+
|
|
219
238
|
checks.push(() => expectMatch(
|
|
220
239
|
cli,
|
|
221
240
|
/channelKey === 'zalo-personal'\) \{\s*botConfig\.channels\['zalouser'\] = \{\s*enabled: true,\s*dmPolicy: 'open',\s*autoReply: true/s,
|
|
@@ -236,13 +255,13 @@ checks.push(() => expectMatch(
|
|
|
236
255
|
|
|
237
256
|
checks.push(() => expectMatch(
|
|
238
257
|
cli,
|
|
239
|
-
/function resolveNative9RouterDesktopLaunch\(\) \{[\s\S]*command: process\.execPath[\s\S]*
|
|
258
|
+
/function resolveNative9RouterDesktopLaunch\(\) \{[\s\S]*get9RouterServerEntryCandidates\(\)\.find\([\s\S]*command: process\.execPath[\s\S]*args: \[serverEntry\][\s\S]*PORT: '20128'[\s\S]*HOSTNAME: '0\.0\.0\.0'/s,
|
|
240
259
|
'Native desktop 9Router launch must bypass the interactive CLI menu by running the 9Router server entry directly'
|
|
241
260
|
));
|
|
242
261
|
|
|
243
262
|
checks.push(() => expectMatch(
|
|
244
263
|
cli,
|
|
245
|
-
/const native9RouterLaunch = resolveNative9RouterDesktopLaunch\(\);[\s\S]*spawnBackgroundProcess\(native9RouterLaunch\.command, native9RouterLaunch\.args, \{[\s\S]*
|
|
264
|
+
/const native9RouterLaunch = resolveNative9RouterDesktopLaunch\(\);[\s\S]*spawnBackgroundProcess\(native9RouterLaunch\.command, native9RouterLaunch\.args, \{[\s\S]*getProjectRuntimeEnv\(projectDir, native9RouterLaunch\.env\)/s,
|
|
246
265
|
'Native desktop 9Router flow must launch through the background helper with the resolved launch spec'
|
|
247
266
|
));
|
|
248
267
|
|
|
@@ -272,9 +291,16 @@ checks.push(() => expectMatch(
|
|
|
272
291
|
|
|
273
292
|
checks.push(() => expectOrder(
|
|
274
293
|
cli,
|
|
275
|
-
"await
|
|
294
|
+
"await ensureProjectRuntimeDirs(projectDir, isVi);",
|
|
276
295
|
"installRelayPluginForProject(projectDir, isVi);",
|
|
277
|
-
'Relay plugin install must happen after
|
|
296
|
+
'Relay plugin install must happen after preparing the project runtime directories in native flow'
|
|
297
|
+
));
|
|
298
|
+
|
|
299
|
+
checks.push(() => expect(
|
|
300
|
+
!cli.includes('Config synced to ~/.openclaw/')
|
|
301
|
+
&& !cli.includes('Config đã được sync vào ~/.openclaw/')
|
|
302
|
+
&& !cli.includes("cp -rn ${localClawDir}/. ${globalClawDir}/"),
|
|
303
|
+
'CLI native flow must no longer sync project config into the global ~/.openclaw directory'
|
|
278
304
|
));
|
|
279
305
|
|
|
280
306
|
checks.push(() => expectMatch(
|
|
@@ -303,32 +329,113 @@ checks.push(() => expectMatch(
|
|
|
303
329
|
|
|
304
330
|
checks.push(() => expectMatch(
|
|
305
331
|
setup,
|
|
306
|
-
/if \(state\.nativeOs === 'win'\) \{[\s\S]*scriptName = isDocker \? 'setup-openclaw-docker-win\.bat' : 'setup-openclaw-win\.bat';[\s\S]*npm install -g openclaw@
|
|
332
|
+
/if \(state\.nativeOs === 'win'\) \{[\s\S]*scriptName = isDocker \? 'setup-openclaw-docker-win\.bat' : 'setup-openclaw-win\.bat';[\s\S]*npm install -g openclaw@2026\.4\.5[\s\S]*openclaw gateway run/s,
|
|
307
333
|
'Windows native/docker script generation must use the correct file name and start command'
|
|
308
334
|
));
|
|
309
335
|
|
|
310
336
|
checks.push(() => expectMatch(
|
|
311
337
|
setup,
|
|
312
|
-
/else if \(state\.nativeOs === 'linux'\) \{[\s\S]*scriptName = isDocker \? 'setup-openclaw-docker-macos\.sh' : 'setup-openclaw-macos\.sh';[\s\S]*npm config set prefix "\$HOME\/\.local"[\s\S]*npm install -g openclaw@
|
|
338
|
+
/else if \(state\.nativeOs === 'linux'\) \{[\s\S]*scriptName = isDocker \? 'setup-openclaw-docker-macos\.sh' : 'setup-openclaw-macos\.sh';[\s\S]*npm config set prefix "\$HOME\/\.local"[\s\S]*npm install -g openclaw@2026\.4\.5[\s\S]*openclaw gateway run/s,
|
|
313
339
|
'macOS script generation must use the correct file name and start command'
|
|
314
340
|
));
|
|
315
341
|
|
|
316
342
|
checks.push(() => expectMatch(
|
|
317
343
|
setup,
|
|
318
|
-
/
|
|
319
|
-
'
|
|
344
|
+
/RUN npm install -g openclaw@2026\.4\.5 grammy/,
|
|
345
|
+
'Wizard Dockerfile generation must install grammy alongside openclaw so Telegram runtime dependencies resolve'
|
|
346
|
+
));
|
|
347
|
+
|
|
348
|
+
checks.push(() => expect(
|
|
349
|
+
setup.includes("a.add('http://' + entry.address + ':18791')")
|
|
350
|
+
&& setup.includes('allowedOrigins:Array.from(a).filter(Boolean)')
|
|
351
|
+
&& !setup.includes("a.add(\\`http://\\${entry.address}:18791\\`)"),
|
|
352
|
+
'Wizard Docker patch command must avoid shell-expanding ${entry.address} and must filter null origins'
|
|
320
353
|
));
|
|
321
354
|
|
|
322
355
|
checks.push(() => expectMatch(
|
|
323
356
|
setup,
|
|
324
|
-
/
|
|
357
|
+
/else if \(state\.nativeOs === 'vps'\) \{[\s\S]*scriptName = 'setup-openclaw-vps\.sh';[\s\S]*npm config set prefix "\$HOME\/\.local"[\s\S]*PROJECT_DIR="[\s\S]*export OPENCLAW_HOME="\$PROJECT_DIR\/\.openclaw"[\s\S]*export OPENCLAW_STATE_DIR="\$PROJECT_DIR\/\.openclaw"[\s\S]*export DATA_DIR="\$PROJECT_DIR\/\.9router"[\s\S]*npm install -g openclaw@2026\.4\.5 pm2@latest[\s\S]*pm2 save && pm2 startup/s,
|
|
358
|
+
'VPS native script generation must keep runtime files project-local, install openclaw+pm2, and persist PM2 startup'
|
|
359
|
+
));
|
|
360
|
+
|
|
361
|
+
checks.push(() => expect(
|
|
362
|
+
setup.includes('scriptName = isDocker ? \'setup-openclaw-docker-macos.sh\' : \'setup-openclaw-macos.sh\';')
|
|
363
|
+
&& setup.includes('scriptName = \'setup-openclaw-linux.sh\';')
|
|
364
|
+
&& setup.includes('cd "$PROJECT_DIR"')
|
|
365
|
+
&& setup.includes('export OPENCLAW_HOME="$PROJECT_DIR/.openclaw"')
|
|
366
|
+
&& setup.includes('export OPENCLAW_STATE_DIR="$PROJECT_DIR/.openclaw"')
|
|
367
|
+
&& setup.includes('export DATA_DIR="$PROJECT_DIR/.9router"'),
|
|
368
|
+
'Unix native script generation must use project-local runtime directories and launch from PROJECT_DIR'
|
|
369
|
+
));
|
|
370
|
+
|
|
371
|
+
checks.push(() => expect(
|
|
372
|
+
setup.includes("arr.push('call npm install -g 9router || goto :fail');")
|
|
373
|
+
&& setup.includes('function native9RouterServerEntryLookup() {')
|
|
374
|
+
&& setup.includes('return "node -e ')
|
|
375
|
+
&& !setup.includes('return "node -p ')
|
|
376
|
+
&& setup.includes('function windowsHiddenNodeLaunch(targetPath, extraEnv = {}) {')
|
|
377
|
+
&& setup.includes('NINE_ROUTER_ENTRY=%%I')
|
|
378
|
+
&& setup.includes("windowsHiddenNodeLaunch('%NINE_ROUTER_ENTRY%', { PORT: '20128', HOSTNAME: '0.0.0.0', DATA_DIR: '%DATA_DIR%' })")
|
|
379
|
+
&& setup.includes('NINE_ROUTER_ENTRY="$(${native9RouterServerEntryLookup()})"')
|
|
380
|
+
&& setup.includes("const p=path.join(process.env.DATA_DIR||'.9router','db.json');")
|
|
381
|
+
&& setup.includes('nohup env PORT=20128 HOSTNAME=0.0.0.0 DATA_DIR="$PWD/.9router" node "$NINE_ROUTER_ENTRY" >/tmp/9router.log 2>&1 &')
|
|
382
|
+
&& setup.includes('nohup env DATA_DIR="$PWD/.9router" node ./.openclaw/9router-smart-route-sync.js >/tmp/9router-sync.log 2>&1 &')
|
|
383
|
+
&& setup.includes('set "PROJECT_DIR=')
|
|
384
|
+
&& setup.includes('set "OPENCLAW_HOME=%PROJECT_DIR%\\\\.openclaw"')
|
|
385
|
+
&& setup.includes('set "OPENCLAW_STATE_DIR=%PROJECT_DIR%\\\\.openclaw"')
|
|
386
|
+
&& setup.includes('set "DATA_DIR=%PROJECT_DIR%\\\\.9router"'),
|
|
325
387
|
'Native script generation must install and start a standalone 9Router dashboard on port 20128'
|
|
326
388
|
));
|
|
327
389
|
|
|
390
|
+
checks.push(() => expect(
|
|
391
|
+
setup.includes("echo OpenClaw Dashboard: http://127.0.0.1:18791")
|
|
392
|
+
&& setup.includes("echo Other reachable URLs: http://localhost:18791")
|
|
393
|
+
&& setup.includes("echo If the dashboard asks for a Gateway Token, run: openclaw dashboard")
|
|
394
|
+
&& setup.includes("echo 9Router Dashboard: http://127.0.0.1:20128/dashboard")
|
|
395
|
+
&& !setup.includes('set "HOME=%PROJECT_DIR%"')
|
|
396
|
+
&& !setup.includes('set "USERPROFILE=%PROJECT_DIR%"'),
|
|
397
|
+
'Windows native script generation must print OpenClaw and 9Router dashboard URLs'
|
|
398
|
+
));
|
|
399
|
+
|
|
400
|
+
checks.push(() => expect(
|
|
401
|
+
setup.includes("bind: 'custom'")
|
|
402
|
+
&& setup.includes("customBindHost: '0.0.0.0'")
|
|
403
|
+
&& !setup.includes("bind: '0.0.0.0'")
|
|
404
|
+
&& setup.includes("state.bots[state.activeBotIndex].provider = key;")
|
|
405
|
+
&& setup.includes("state.bots[state.activeBotIndex].model = p.models[0].id;")
|
|
406
|
+
&& setup.includes("state.bots[state.activeBotIndex].provider = state.config.provider;")
|
|
407
|
+
&& setup.includes("state.bots[state.activeBotIndex].model = state.config.model;")
|
|
408
|
+
&& setup.includes("if (state.botCount <= 1 && state.bots[state.activeBotIndex]) {")
|
|
409
|
+
&& setup.includes("state.bots[state.activeBotIndex].token = botTokenEl.value;")
|
|
410
|
+
&& setup.includes("state.bots[state.activeBotIndex].apiKey = apiKeyEl.value;")
|
|
411
|
+
&& setup.includes("const authProviderName = provider.isProxy ? '9router' : state.config.provider;")
|
|
412
|
+
&& setup.includes("const authProviderName = botProvider.isProxy ? '9router' : (bot.provider || state.config.provider);")
|
|
413
|
+
&& setup.includes("const nativeSkillConfigs = state.config.skills")
|
|
414
|
+
&& setup.includes("const nativeSkillInstallCmds = nativeSkillConfigs.map((skill) => `call openclaw skills install ${skill.slug} || echo Warning: Failed to install skill ${skill.slug}`);")
|
|
415
|
+
&& setup.includes("lines.push('call npm install -g agent-browser playwright || goto :fail');")
|
|
416
|
+
&& setup.includes("lines.push('call npx playwright install chromium || goto :fail');")
|
|
417
|
+
&& setup.includes("lines.push('echo Cai skills...');")
|
|
418
|
+
&& !setup.includes("const authProviderName = provider.isProxy ? '9router' : provider.id;")
|
|
419
|
+
&& !setup.includes("const authProviderName = botProvider.isProxy ? '9router' : botProvider.id;"),
|
|
420
|
+
'Wizard native config generation must avoid legacy gateway.bind aliases, preserve concrete auth provider ids, and sync single-bot provider/model selections into bot state'
|
|
421
|
+
));
|
|
422
|
+
|
|
423
|
+
checks.push(() => expectMatch(
|
|
424
|
+
setup,
|
|
425
|
+
/window\.downloadNativeScript = function\(\) \{[\s\S]*generateOutput\(\);[\s\S]*const script = window\._nativeScript;/,
|
|
426
|
+
'Native script download must regenerate the latest wizard output before reading the cached script'
|
|
427
|
+
));
|
|
428
|
+
|
|
429
|
+
checks.push(() => expectMatch(
|
|
430
|
+
setup,
|
|
431
|
+
/} else if \(is9Router\) \{[\s\S]*container_name: openclaw-bot[\s\S]*depends_on:[\s\S]*- 9router[\s\S]*container_name: 9router[\s\S]*PORT=20128[\s\S]*HOSTNAME=0\.0\.0\.0[\s\S]*9router-data:/s,
|
|
432
|
+
'Wizard single-bot Docker compose must include the 9Router sidecar service and named volume when provider is 9Router'
|
|
433
|
+
));
|
|
434
|
+
|
|
328
435
|
checks.push(() => expectMatch(
|
|
329
436
|
setup,
|
|
330
|
-
/function native9RouterSyncScriptContent\(\) \{[\s\S]*path\.join\(process\.env\.
|
|
331
|
-
'Native script generation must
|
|
437
|
+
/function native9RouterSyncScriptContent\(\) \{[\s\S]*const p=path\.join\(process\.env\.DATA_DIR\|\|'\.9router','db\.json'\);[\s\S]*const ROUTER='http:\/\/localhost:20128';[\s\S]*fetch\(ROUTER\+'\/api\/providers'\)[\s\S]*d\.connections[\s\S]*smart-route/s,
|
|
438
|
+
'Native script generation must keep the 9Router sync script project-local via DATA_DIR and sync active providers from the 9Router API'
|
|
332
439
|
));
|
|
333
440
|
|
|
334
441
|
checks.push(() => expect(
|
|
@@ -369,19 +476,19 @@ checks.push(() => expect(
|
|
|
369
476
|
|
|
370
477
|
checks.push(() => expectMatch(
|
|
371
478
|
setup,
|
|
372
|
-
/else if \(state\.nativeOs === 'vps'\) \{[\s\S]*PORT=20128 HOSTNAME=0\.0\.0\.0 pm2 start "
|
|
479
|
+
/else if \(state\.nativeOs === 'vps'\) \{[\s\S]*NINE_ROUTER_ENTRY="\$\([\s\S]*PORT=20128 HOSTNAME=0\.0\.0\.0 pm2 start "\$NINE_ROUTER_ENTRY" --name openclaw-multibot-9router --interpreter "\$\(command -v node\)"[\s\S]*pm2 start --name openclaw-multibot -- sh -c "openclaw gateway run"[\s\S]*pm2 logs openclaw-multibot/s,
|
|
373
480
|
'VPS multi-bot native script must start the shared gateway via PM2'
|
|
374
481
|
));
|
|
375
482
|
|
|
376
483
|
checks.push(() => expectMatch(
|
|
377
484
|
setup,
|
|
378
|
-
/else if \(state\.nativeOs === 'vps'\) \{[\s\S]*PORT=20128 HOSTNAME=0\.0\.0\.0 pm2 start "
|
|
485
|
+
/else if \(state\.nativeOs === 'vps'\) \{[\s\S]*NINE_ROUTER_ENTRY="\$\([\s\S]*PORT=20128 HOSTNAME=0\.0\.0\.0 pm2 start "\$NINE_ROUTER_ENTRY" --name openclaw-9router --interpreter "\$\(command -v node\)"[\s\S]*pm2 start --name openclaw -- sh -c "openclaw gateway run"[\s\S]*pm2 logs openclaw/s,
|
|
379
486
|
'VPS single-bot native script must start one bot via PM2'
|
|
380
487
|
));
|
|
381
488
|
|
|
382
489
|
checks.push(() => expectMatch(
|
|
383
490
|
setup,
|
|
384
|
-
/else if \(state\.nativeOs === 'linux-desktop'\) \{[\s\S]*scriptName = 'setup-openclaw-linux\.sh';[\s\S]*npm config set prefix "\$HOME\/\.local"[\s\S]*npm install -g openclaw@
|
|
491
|
+
/else if \(state\.nativeOs === 'linux-desktop'\) \{[\s\S]*scriptName = 'setup-openclaw-linux\.sh';[\s\S]*npm config set prefix "\$HOME\/\.local"[\s\S]*npm install -g openclaw@2026\.4\.5[\s\S]*openclaw gateway run/s,
|
|
385
492
|
'Linux Desktop native script generation must install openclaw and run the gateway'
|
|
386
493
|
));
|
|
387
494
|
|