create-openclaw-bot 5.0.9 → 5.1.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.
- package/CHANGELOG.md +33 -3
- package/CHANGELOG.vi.md +33 -3
- package/README.md +5 -4
- package/README.vi.md +5 -4
- package/cli.js +2376 -1998
- package/docs/install-native.md +1 -1
- package/docs/install-native.vi.md +1 -1
- package/package.json +1 -1
- package/setup.js +132 -128
- package/tests/smoke-cli-logic.mjs +157 -5
|
@@ -38,6 +38,30 @@ checks.push(() => expectMatch(
|
|
|
38
38
|
'Docker branch must still auto-install Docker when missing'
|
|
39
39
|
));
|
|
40
40
|
|
|
41
|
+
checks.push(() => expectMatch(
|
|
42
|
+
cli,
|
|
43
|
+
/function shouldReuseInstalledGlobals\(\) \{[\s\S]*OPENCLAW_SETUP_REUSE_GLOBALS[\s\S]*trim\(\)\.toLowerCase\(\)/,
|
|
44
|
+
'CLI must expose an env-flag helper for fast test runs that reuse installed global packages'
|
|
45
|
+
));
|
|
46
|
+
|
|
47
|
+
checks.push(() => expectMatch(
|
|
48
|
+
cli,
|
|
49
|
+
/function installLatestOpenClaw\(\{ isVi, osChoice \}\) \{[\s\S]*installGlobalPackage\('openclaw@latest', \{ isVi, osChoice, displayName: 'openclaw' \}\)[\s\S]*process\.exit\(1\)/,
|
|
50
|
+
'CLI must provide a shared helper that always installs or upgrades openclaw@latest'
|
|
51
|
+
));
|
|
52
|
+
|
|
53
|
+
checks.push(() => expectMatch(
|
|
54
|
+
cli,
|
|
55
|
+
/function installLatestOpenClaw\(\{ isVi, osChoice \}\) \{[\s\S]*shouldReuseInstalledGlobals\(\) && isOpenClawInstalled\(\)[\s\S]*Reusing the installed openclaw/s,
|
|
56
|
+
'CLI fast-test mode must be able to reuse an existing openclaw install'
|
|
57
|
+
));
|
|
58
|
+
|
|
59
|
+
checks.push(() => expectMatch(
|
|
60
|
+
cli,
|
|
61
|
+
/installLatestOpenClaw\(\{ isVi, osChoice \}\);\s*if \(deployMode === 'docker'\) \{/,
|
|
62
|
+
'CLI must install or upgrade openclaw before entering the Docker/native branches'
|
|
63
|
+
));
|
|
64
|
+
|
|
41
65
|
checks.push(() => expectMatch(
|
|
42
66
|
cli,
|
|
43
67
|
/if \(!isOpenClawInstalled\(\)\) \{[\s\S]*installGlobalPackage\('openclaw@latest', \{ isVi, osChoice, displayName: 'openclaw' \}\)/,
|
|
@@ -52,10 +76,35 @@ checks.push(() => expectMatch(
|
|
|
52
76
|
|
|
53
77
|
checks.push(() => expectMatch(
|
|
54
78
|
cli,
|
|
55
|
-
/if \(providerKey === '9router'
|
|
79
|
+
/if \(providerKey === '9router'\) \{[\s\S]*else if \(!is9RouterInstalled\(\)\) \{[\s\S]*installGlobalPackage\('9router@latest', \{ isVi, osChoice, displayName: '9Router' \}\)/,
|
|
56
80
|
'Native 9Router flow must auto-install 9Router'
|
|
57
81
|
));
|
|
58
82
|
|
|
83
|
+
checks.push(() => expectMatch(
|
|
84
|
+
cli,
|
|
85
|
+
/if \(providerKey === '9router'\) \{[\s\S]*shouldReuseInstalledGlobals\(\) && is9RouterInstalled\(\)[\s\S]*Reusing the installed 9Router[\s\S]*else if \(!is9RouterInstalled\(\)\)/s,
|
|
86
|
+
'CLI fast-test mode must be able to reuse an existing 9Router install'
|
|
87
|
+
));
|
|
88
|
+
|
|
89
|
+
checks.push(() => expectMatch(
|
|
90
|
+
cli,
|
|
91
|
+
/function build9RouterSmartRouteSyncScript\(dbPath\) \{[\s\S]*safeDbPath[\s\S]*providerConnections[\s\S]*smart-route[\s\S]*async function writeNative9RouterSyncScript\(projectDir\) \{[\s\S]*getNative9RouterDataDir\(\), 'db\.json'/s,
|
|
92
|
+
'Native 9Router flow must write a smart-route sync script based on the platform-specific 9Router data directory'
|
|
93
|
+
));
|
|
94
|
+
|
|
95
|
+
checks.push(() => expectMatch(
|
|
96
|
+
cli,
|
|
97
|
+
/function getNative9RouterDataDir\(\) \{[\s\S]*process\.platform === 'win32'[\s\S]*AppData[\s\S]*Roaming[\s\S]*9router[\s\S]*os\.homedir\(\)[\s\S]*\.9router/s,
|
|
98
|
+
'CLI must resolve the correct native 9Router data directory on both Windows and Unix'
|
|
99
|
+
));
|
|
100
|
+
|
|
101
|
+
checks.push(() => expect(
|
|
102
|
+
cli.includes("Removed smart-route (no active providers)")
|
|
103
|
+
&& cli.includes("if(!a.length){removeSmartRoute();return;}")
|
|
104
|
+
&& cli.includes("if(!m.length){removeSmartRoute();return;}"),
|
|
105
|
+
'9Router sync logic in CLI must remove stale smart-route combos when providers are disabled'
|
|
106
|
+
));
|
|
107
|
+
|
|
59
108
|
checks.push(() => expectMatch(
|
|
60
109
|
cli,
|
|
61
110
|
/function ensureUserWritableGlobalNpm\(\{ isVi, osChoice \}\) \{[\s\S]*process\.env\.npm_config_prefix = npmInfo\.prefixDir[\s\S]*npm config set prefix "\$\{npmInfo\.prefixDir\.replace/s,
|
|
@@ -80,6 +129,48 @@ checks.push(() => expectMatch(
|
|
|
80
129
|
'Native PM2 flow must expose dashboard access info and the tokenized dashboard command'
|
|
81
130
|
));
|
|
82
131
|
|
|
132
|
+
checks.push(() => expectMatch(
|
|
133
|
+
cli,
|
|
134
|
+
/function printZaloPersonalLoginInfo\(\{ isVi, deployMode, projectDir \}\) \{[\s\S]*docker compose exec -it ai-bot openclaw channels login --channel zalouser --verbose[\s\S]*openclaw-zalouser-qr-default\.png[\s\S]*Copy-Item[\s\S]*docker compose cp ai-bot:\$\{qrPath\} \.\/zalo-login-qr\.png/s,
|
|
135
|
+
'CLI must print the dedicated Docker/native Zalo Personal login commands and QR copy path instead of onboarding'
|
|
136
|
+
));
|
|
137
|
+
|
|
138
|
+
checks.push(() => expectMatch(
|
|
139
|
+
cli,
|
|
140
|
+
/function extractZaloPairingCode\(text\) \{[\s\S]*openclaw pairing approve zalouser[\s\S]*Pairing code:/s,
|
|
141
|
+
'CLI must be able to extract a Zalo pairing code from the login output'
|
|
142
|
+
));
|
|
143
|
+
|
|
144
|
+
checks.push(() => expectMatch(
|
|
145
|
+
cli,
|
|
146
|
+
/function approveZaloPairingCode\(\{ pairingCode, projectDir, isVi \}\) \{[\s\S]*openclaw pairing approve zalouser \$\{pairingCode\}/s,
|
|
147
|
+
'CLI must be able to auto-approve a detected Zalo pairing code'
|
|
148
|
+
));
|
|
149
|
+
|
|
150
|
+
checks.push(() => expectMatch(
|
|
151
|
+
cli,
|
|
152
|
+
/async function runNativeZaloPersonalLoginFlow\(\{ isVi, projectDir \}\) \{[\s\S]*spawn\('openclaw', \['channels', 'login', '--channel', 'zalouser', '--verbose'\]/s,
|
|
153
|
+
'Native Zalo flow must run the zalouser login command'
|
|
154
|
+
));
|
|
155
|
+
|
|
156
|
+
checks.push(() => expectMatch(
|
|
157
|
+
cli,
|
|
158
|
+
/async function runNativeZaloPersonalLoginFlow\(\{ isVi, projectDir \}\) \{[\s\S]*fs\.remove\(qrSourcePath\)[\s\S]*fs\.remove\(qrProjectPath\)[\s\S]*fs\.copy\(qrSourcePath, qrProjectPath, \{ overwrite: true \}\)/s,
|
|
159
|
+
'Native Zalo flow must clear stale QR files and copy the fresh QR into the project folder'
|
|
160
|
+
));
|
|
161
|
+
|
|
162
|
+
checks.push(() => expectMatch(
|
|
163
|
+
cli,
|
|
164
|
+
/async function runNativeZaloPersonalLoginFlow\(\{ isVi, projectDir \}\) \{[\s\S]*outputBuffer[\s\S]*extractZaloPairingCode\(outputBuffer\)[\s\S]*approveZaloPairingCode\(\{ pairingCode, projectDir, isVi \}\)/s,
|
|
165
|
+
'Native Zalo flow must auto-approve pairing when the login command emits a pairing code'
|
|
166
|
+
));
|
|
167
|
+
|
|
168
|
+
checks.push(() => expectMatch(
|
|
169
|
+
cli,
|
|
170
|
+
/async function runNativeZaloPersonalLoginFlow\(\{ isVi, projectDir \}\) \{[\s\S]*let loginSucceeded = false[\s\S]*successPattern[\s\S]*if \(exitCode !== 0 && !loginSucceeded\)[\s\S]*else if \(loginSucceeded && exitCode !== 0\)/s,
|
|
171
|
+
'Native Zalo flow must tolerate non-standard exit codes when the login output already reports success'
|
|
172
|
+
));
|
|
173
|
+
|
|
83
174
|
checks.push(() => expectMatch(
|
|
84
175
|
cli,
|
|
85
176
|
/baseUrl: deployMode === 'native' \? 'http:\/\/localhost:20128\/v1' : 'http:\/\/9router:20128\/v1'/,
|
|
@@ -88,10 +179,46 @@ checks.push(() => expectMatch(
|
|
|
88
179
|
|
|
89
180
|
checks.push(() => expectMatch(
|
|
90
181
|
cli,
|
|
91
|
-
/
|
|
182
|
+
/channelKey === 'zalo-personal'\) \{\s*botConfig\.channels\['zalouser'\] = \{\s*enabled: true,\s*dmPolicy: 'pairing',\s*autoReply: true/s,
|
|
183
|
+
'CLI must configure Zalo Personal under channels.zalouser'
|
|
184
|
+
));
|
|
185
|
+
|
|
186
|
+
checks.push(() => expectMatch(
|
|
187
|
+
cli,
|
|
188
|
+
/function startNative9RouterPm2\(\{ isVi, projectDir, appName, syncScriptPath \}\) \{[\s\S]*9router -n -t -l -H 0\.0\.0\.0 -p 20128 --skip-update[\s\S]*9router-sync[\s\S]*runPm2Save\(\{ projectDir, isVi \}\)/s,
|
|
92
189
|
'VPS native 9Router flow must start a standalone 9Router dashboard on port 20128 via PM2'
|
|
93
190
|
));
|
|
94
191
|
|
|
192
|
+
checks.push(() => expectMatch(
|
|
193
|
+
cli,
|
|
194
|
+
/function spawnBackgroundProcess\(command, args, options = \{\}\) \{[\s\S]*if \(process\.platform === 'win32'\)[\s\S]*resolveWindowsCommand[\s\S]*Start-Process -WindowStyle Hidden[\s\S]*powershell\.exe/s,
|
|
195
|
+
'Native desktop background helpers must use hidden Start-Process launches on Windows'
|
|
196
|
+
));
|
|
197
|
+
|
|
198
|
+
checks.push(() => expectMatch(
|
|
199
|
+
cli,
|
|
200
|
+
/function resolveNative9RouterDesktopLaunch\(\) \{[\s\S]*process\.platform === 'win32'[\s\S]*npm root -g[\s\S]*9router', 'app', 'server\.js'[\s\S]*PORT: '20128'[\s\S]*HOSTNAME: '0\.0\.0\.0'[\s\S]*command: '9router'[\s\S]*\['-n', '-t', '-l', '-H', '0\.0\.0\.0', '-p', '20128', '--skip-update'\]/s,
|
|
201
|
+
'Native desktop 9Router launch must bypass the interactive CLI menu on Windows while preserving the standard CLI launch elsewhere'
|
|
202
|
+
));
|
|
203
|
+
|
|
204
|
+
checks.push(() => expectMatch(
|
|
205
|
+
cli,
|
|
206
|
+
/const native9RouterLaunch = resolveNative9RouterDesktopLaunch\(\);[\s\S]*spawnBackgroundProcess\(native9RouterLaunch\.command, native9RouterLaunch\.args, \{[\s\S]*env: native9RouterLaunch\.env/s,
|
|
207
|
+
'Native desktop 9Router flow must launch through the background helper with the resolved launch spec'
|
|
208
|
+
));
|
|
209
|
+
|
|
210
|
+
checks.push(() => expectMatch(
|
|
211
|
+
cli,
|
|
212
|
+
/const routerHealth = await waitFor9RouterApiReady\(\);[\s\S]*admin API chua san sang[\s\S]*admin API is not ready yet/s,
|
|
213
|
+
'Native desktop 9Router flow must warn when the dashboard port opens but the admin API never becomes ready'
|
|
214
|
+
));
|
|
215
|
+
|
|
216
|
+
checks.push(() => expectMatch(
|
|
217
|
+
cli,
|
|
218
|
+
/spawnBackgroundProcess\(process\.execPath, \[native9RouterSyncScriptPath\]/,
|
|
219
|
+
'Native desktop 9Router sync loop must launch through the background helper'
|
|
220
|
+
));
|
|
221
|
+
|
|
95
222
|
checks.push(() => expectMatch(
|
|
96
223
|
cli,
|
|
97
224
|
/function runPm2Save\(\{ projectDir, isVi \}\) \{[\s\S]*execSync\('pm2 save'[\s\S]*PM2 save did not complete/s,
|
|
@@ -100,8 +227,8 @@ checks.push(() => expectMatch(
|
|
|
100
227
|
|
|
101
228
|
checks.push(() => expectMatch(
|
|
102
229
|
cli,
|
|
103
|
-
/const child = spawn\('openclaw', \['gateway', 'run'\], \{
|
|
104
|
-
'Native desktop flows must
|
|
230
|
+
/if \(channelKey === 'zalo-personal'\) \{\s*await runNativeZaloPersonalLoginFlow\(\{ isVi, projectDir \}\);\s*\}[\s\S]*const child = spawn\('openclaw', \['gateway', 'run'\], \{/s,
|
|
231
|
+
'Native desktop flows must finish the Zalo login flow before starting openclaw in foreground'
|
|
105
232
|
));
|
|
106
233
|
|
|
107
234
|
checks.push(() => expectOrder(
|
|
@@ -155,10 +282,29 @@ checks.push(() => expectMatch(
|
|
|
155
282
|
|
|
156
283
|
checks.push(() => expectMatch(
|
|
157
284
|
setup,
|
|
158
|
-
/function providerLines\(arr, shell\) \{[\s\S]*npm install -g 9router[\s\S]*
|
|
285
|
+
/function providerLines\(arr, shell\) \{[\s\S]*npm install -g 9router[\s\S]*npm root -g[\s\S]*Join-Path \$npmRoot[\s\S]*Start-Process -WindowStyle Hidden -FilePath ''node\.exe''[\s\S]*9router-smart-route-sync\.js/s,
|
|
159
286
|
'Native script generation must install and start a standalone 9Router dashboard on port 20128'
|
|
160
287
|
));
|
|
161
288
|
|
|
289
|
+
checks.push(() => expectMatch(
|
|
290
|
+
setup,
|
|
291
|
+
/function native9RouterSyncScriptContent\(\) \{[\s\S]*process\.platform==='win32'[\s\S]*AppData[\s\S]*Roaming[\s\S]*providerConnections[\s\S]*smart-route/s,
|
|
292
|
+
'Native script generation must embed a 9Router smart-route sync script with the correct Windows data directory'
|
|
293
|
+
));
|
|
294
|
+
|
|
295
|
+
checks.push(() => expect(
|
|
296
|
+
setup.includes("Removed smart-route (no active providers)")
|
|
297
|
+
&& setup.includes("if(!a.length){removeSmartRoute();return;}")
|
|
298
|
+
&& setup.includes("if(!m.length){removeSmartRoute();return;}"),
|
|
299
|
+
'9Router sync logic in setup.js must remove stale smart-route combos when providers are disabled'
|
|
300
|
+
));
|
|
301
|
+
|
|
302
|
+
checks.push(() => expectMatch(
|
|
303
|
+
setup,
|
|
304
|
+
/\.openclaw\/9router-smart-route-sync\.js[\s\S]*pm2 start --name openclaw-9router-sync/s,
|
|
305
|
+
'VPS native script generation must write and run the 9Router smart-route sync loop'
|
|
306
|
+
));
|
|
307
|
+
|
|
162
308
|
checks.push(() => expectMatch(
|
|
163
309
|
cli,
|
|
164
310
|
/readdirSync\(dir\)\.find\(n=>\/\^gateway-cli-.*\\\\\.js\$\/\.test\(n\)\)[\s\S]*skipping timeout patch/,
|
|
@@ -201,6 +347,12 @@ checks.push(() => expectMatch(
|
|
|
201
347
|
'Auto-steps summary must mention OpenClaw CLI installation'
|
|
202
348
|
));
|
|
203
349
|
|
|
350
|
+
checks.push(() => expectMatch(
|
|
351
|
+
setup,
|
|
352
|
+
/Native setup now auto-runs the login flow and copies the QR into the project folder[\s\S]*docker compose exec -it ai-bot openclaw channels login --channel zalouser --verbose[\s\S]*docker compose cp ai-bot:\/tmp\/openclaw\/openclaw-zalouser-qr-default\.png \.\/zalo-login-qr\.png/s,
|
|
353
|
+
'Wizard copy must mention native auto-login and still show the dedicated Docker QR login command'
|
|
354
|
+
));
|
|
355
|
+
|
|
204
356
|
for (const check of checks) {
|
|
205
357
|
check();
|
|
206
358
|
}
|