@silicaclaw/cli 1.0.0-beta.8 → 2026.3.18-2
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 +93 -0
- package/INSTALL.md +24 -13
- package/README.md +62 -18
- package/VERSION +1 -1
- package/apps/local-console/package.json +1 -0
- package/apps/local-console/public/index.html +2113 -473
- package/apps/local-console/src/server.ts +108 -31
- package/apps/public-explorer/public/index.html +283 -61
- package/docs/CLOUDFLARE_RELAY.md +61 -0
- package/docs/NEW_USER_INSTALL.md +166 -0
- package/docs/NEW_USER_OPERATIONS.md +265 -0
- package/package.json +2 -2
- package/packages/core/dist/socialConfig.d.ts +1 -1
- package/packages/core/dist/socialConfig.js +7 -6
- package/packages/core/dist/socialResolver.js +15 -5
- package/packages/core/src/socialConfig.ts +8 -7
- package/packages/core/src/socialResolver.ts +17 -5
- package/packages/network/dist/index.d.ts +1 -0
- package/packages/network/dist/index.js +1 -0
- package/packages/network/dist/relayPreview.d.ts +166 -0
- package/packages/network/dist/relayPreview.js +430 -0
- package/packages/network/src/index.ts +1 -0
- package/packages/network/src/relayPreview.ts +552 -0
- package/packages/storage/dist/socialRuntimeRepo.js +4 -4
- package/packages/storage/src/socialRuntimeRepo.ts +4 -4
- package/scripts/quickstart.sh +269 -43
- package/scripts/silicaclaw-cli.mjs +418 -56
- package/scripts/silicaclaw-gateway.mjs +197 -46
- package/scripts/webrtc-signaling-server.mjs +89 -5
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import { accessSync, constants, cpSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { homedir } from "node:os";
|
|
5
6
|
import { dirname, resolve } from "node:path";
|
|
6
7
|
import { fileURLToPath } from "node:url";
|
|
7
8
|
|
|
@@ -9,6 +10,42 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
9
10
|
const __dirname = dirname(__filename);
|
|
10
11
|
const ROOT_DIR = resolve(__dirname, "..");
|
|
11
12
|
|
|
13
|
+
const COLOR = {
|
|
14
|
+
reset: "\x1b[0m",
|
|
15
|
+
bold: "\x1b[1m",
|
|
16
|
+
dim: "\x1b[2m",
|
|
17
|
+
orange: "\x1b[38;5;208m",
|
|
18
|
+
green: "\x1b[32m",
|
|
19
|
+
yellow: "\x1b[33m",
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function useColor() {
|
|
23
|
+
return Boolean(process.stdout.isTTY && !process.env.NO_COLOR);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function paint(text, ...styles) {
|
|
27
|
+
if (!useColor() || styles.length === 0) return text;
|
|
28
|
+
return `${styles.join("")}${text}${COLOR.reset}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function displayVersion(raw) {
|
|
32
|
+
const text = String(raw || "unknown").trim() || "unknown";
|
|
33
|
+
return text.startsWith("v") ? text : `v${text}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function headline() {
|
|
37
|
+
console.log(`${paint("SilicaClaw", COLOR.bold, COLOR.orange)} ${paint(displayVersion(readVersion()), COLOR.dim)}`);
|
|
38
|
+
console.log(paint("Public identity and discovery for OpenClaw agents.", COLOR.dim));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function kv(label, value) {
|
|
42
|
+
console.log(`${paint(label.padEnd(14), COLOR.dim)} ${value}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function section(title) {
|
|
46
|
+
console.log(paint(title, COLOR.bold));
|
|
47
|
+
}
|
|
48
|
+
|
|
12
49
|
function run(cmd, args, extra = {}) {
|
|
13
50
|
const result = spawnSync(cmd, args, {
|
|
14
51
|
cwd: ROOT_DIR,
|
|
@@ -17,7 +54,10 @@ function run(cmd, args, extra = {}) {
|
|
|
17
54
|
...extra,
|
|
18
55
|
});
|
|
19
56
|
if (result.error) {
|
|
20
|
-
|
|
57
|
+
headline();
|
|
58
|
+
console.log("");
|
|
59
|
+
console.error(`${paint("Command failed", COLOR.bold, COLOR.yellow)} ${cmd}`);
|
|
60
|
+
console.error(result.error.message);
|
|
21
61
|
process.exit(1);
|
|
22
62
|
}
|
|
23
63
|
process.exit(result.status ?? 0);
|
|
@@ -37,10 +77,30 @@ function runCapture(cmd, args, extra = {}) {
|
|
|
37
77
|
return result;
|
|
38
78
|
}
|
|
39
79
|
|
|
80
|
+
function runInherit(cmd, args, extra = {}) {
|
|
81
|
+
const result = spawnSync(cmd, args, {
|
|
82
|
+
cwd: ROOT_DIR,
|
|
83
|
+
stdio: "inherit",
|
|
84
|
+
env: process.env,
|
|
85
|
+
...extra,
|
|
86
|
+
});
|
|
87
|
+
if (result.error) {
|
|
88
|
+
throw result.error;
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function compactOutput(text, limit = 18) {
|
|
94
|
+
const lines = String(text || "")
|
|
95
|
+
.split(/\r?\n/)
|
|
96
|
+
.map((line) => line.trimEnd())
|
|
97
|
+
.filter(Boolean);
|
|
98
|
+
if (lines.length <= limit) return lines.join("\n");
|
|
99
|
+
return lines.slice(-limit).join("\n");
|
|
100
|
+
}
|
|
101
|
+
|
|
40
102
|
function readVersion() {
|
|
41
|
-
|
|
42
|
-
if (!existsSync(versionFile)) return "unknown";
|
|
43
|
-
return readFileSync(versionFile, "utf8").trim() || "unknown";
|
|
103
|
+
return readPackageVersion();
|
|
44
104
|
}
|
|
45
105
|
|
|
46
106
|
function readPackageVersion() {
|
|
@@ -54,36 +114,292 @@ function readPackageVersion() {
|
|
|
54
114
|
}
|
|
55
115
|
}
|
|
56
116
|
|
|
117
|
+
function preferredShellRcFile() {
|
|
118
|
+
const shell = String(process.env.SHELL || "");
|
|
119
|
+
if (shell.endsWith("/zsh")) return resolve(homedir(), ".zshrc");
|
|
120
|
+
if (shell.endsWith("/bash")) return resolve(homedir(), ".bashrc");
|
|
121
|
+
if (process.env.ZSH_VERSION) return resolve(homedir(), ".zshrc");
|
|
122
|
+
return resolve(homedir(), ".bashrc");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function userShimDir() {
|
|
126
|
+
return resolve(homedir(), ".silicaclaw", "bin");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function userShimPath() {
|
|
130
|
+
return resolve(userShimDir(), "silicaclaw");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function userEnvFile() {
|
|
134
|
+
return resolve(homedir(), ".silicaclaw", "env.sh");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function userNpmCacheDir() {
|
|
138
|
+
return resolve(homedir(), ".silicaclaw", "npm-cache");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function ensureLineInFile(filePath, block) {
|
|
142
|
+
try {
|
|
143
|
+
const current = existsSync(filePath) ? readFileSync(filePath, "utf8") : "";
|
|
144
|
+
if (current.includes(block.trim())) {
|
|
145
|
+
return { changed: false, error: null };
|
|
146
|
+
}
|
|
147
|
+
const next = `${current.replace(/\s*$/, "")}\n\n${block}\n`;
|
|
148
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
149
|
+
writeFileSync(filePath, next, "utf8");
|
|
150
|
+
return { changed: true, error: null };
|
|
151
|
+
} catch (error) {
|
|
152
|
+
return { changed: false, error: error instanceof Error ? error.message : String(error) };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function describeFileOwner(filePath) {
|
|
157
|
+
try {
|
|
158
|
+
if (!existsSync(filePath)) return null;
|
|
159
|
+
const stat = statSync(filePath);
|
|
160
|
+
return String(stat.uid);
|
|
161
|
+
} catch {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function currentUid() {
|
|
167
|
+
try {
|
|
168
|
+
return typeof process.getuid === "function" ? String(process.getuid()) : null;
|
|
169
|
+
} catch {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function shellInitTargets() {
|
|
175
|
+
const home = homedir();
|
|
176
|
+
const shell = String(process.env.SHELL || "");
|
|
177
|
+
const targets = [];
|
|
178
|
+
const add = (filePath) => {
|
|
179
|
+
if (!targets.includes(filePath)) {
|
|
180
|
+
targets.push(filePath);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
if (shell.endsWith("/zsh") || process.env.ZSH_VERSION || existsSync(resolve(home, ".zshrc"))) {
|
|
185
|
+
add(resolve(home, ".zshrc"));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Bash login shells on macOS often read .bash_profile instead of .bashrc.
|
|
189
|
+
if (
|
|
190
|
+
shell.endsWith("/bash") ||
|
|
191
|
+
process.env.BASH_VERSION ||
|
|
192
|
+
existsSync(resolve(home, ".bashrc")) ||
|
|
193
|
+
existsSync(resolve(home, ".bash_profile"))
|
|
194
|
+
) {
|
|
195
|
+
add(resolve(home, ".bashrc"));
|
|
196
|
+
add(resolve(home, ".bash_profile"));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (targets.length === 0) {
|
|
200
|
+
add(preferredShellRcFile());
|
|
201
|
+
}
|
|
202
|
+
return targets;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function installPersistentCommand() {
|
|
206
|
+
const binDir = userShimDir();
|
|
207
|
+
const shimPath = userShimPath();
|
|
208
|
+
const envFile = userEnvFile();
|
|
209
|
+
const npmCacheDir = userNpmCacheDir();
|
|
210
|
+
const envBlock = [
|
|
211
|
+
"#!/usr/bin/env bash",
|
|
212
|
+
'export PATH="$HOME/.silicaclaw/bin:$PATH"',
|
|
213
|
+
'export npm_config_cache="$HOME/.silicaclaw/npm-cache"',
|
|
214
|
+
"",
|
|
215
|
+
].join("\n");
|
|
216
|
+
const rcBlock = [
|
|
217
|
+
"# >>> silicaclaw >>>",
|
|
218
|
+
'[ -f "$HOME/.silicaclaw/env.sh" ] && . "$HOME/.silicaclaw/env.sh"',
|
|
219
|
+
"# <<< silicaclaw <<<",
|
|
220
|
+
].join("\n");
|
|
221
|
+
|
|
222
|
+
mkdirSync(binDir, { recursive: true });
|
|
223
|
+
mkdirSync(npmCacheDir, { recursive: true });
|
|
224
|
+
writeFileSync(envFile, envBlock, { encoding: "utf8", mode: 0o755 });
|
|
225
|
+
writeFileSync(
|
|
226
|
+
shimPath,
|
|
227
|
+
[
|
|
228
|
+
"#!/usr/bin/env bash",
|
|
229
|
+
"set -euo pipefail",
|
|
230
|
+
'export npm_config_cache="${npm_config_cache:-$HOME/.silicaclaw/npm-cache}"',
|
|
231
|
+
'exec npx -y @silicaclaw/cli@beta "$@"',
|
|
232
|
+
"",
|
|
233
|
+
].join("\n"),
|
|
234
|
+
{ encoding: "utf8", mode: 0o755 }
|
|
235
|
+
);
|
|
236
|
+
const rcFiles = shellInitTargets();
|
|
237
|
+
const updatedFiles = [];
|
|
238
|
+
const configuredFiles = [];
|
|
239
|
+
const failedFiles = [];
|
|
240
|
+
for (const filePath of rcFiles) {
|
|
241
|
+
const result = ensureLineInFile(filePath, rcBlock);
|
|
242
|
+
if (result.changed) {
|
|
243
|
+
updatedFiles.push(filePath);
|
|
244
|
+
configuredFiles.push(filePath);
|
|
245
|
+
} else if (!result.error) {
|
|
246
|
+
configuredFiles.push(filePath);
|
|
247
|
+
}
|
|
248
|
+
if (result.error) {
|
|
249
|
+
failedFiles.push({ filePath, error: result.error });
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
headline();
|
|
254
|
+
console.log("");
|
|
255
|
+
console.log(`${paint("Installed", COLOR.bold)} \`silicaclaw\` command`);
|
|
256
|
+
kv("Command", "silicaclaw");
|
|
257
|
+
console.log("");
|
|
258
|
+
kv("Activate", `source "${envFile}"`);
|
|
259
|
+
if (configuredFiles.length > 0) {
|
|
260
|
+
kv("Startup", "configured");
|
|
261
|
+
} else {
|
|
262
|
+
kv("Startup", "manual setup required");
|
|
263
|
+
}
|
|
264
|
+
if (failedFiles.length > 0) {
|
|
265
|
+
console.log("");
|
|
266
|
+
console.log(paint("Shell files skipped", COLOR.bold, COLOR.yellow));
|
|
267
|
+
const uid = currentUid();
|
|
268
|
+
for (const item of failedFiles) {
|
|
269
|
+
const owner = describeFileOwner(item.filePath);
|
|
270
|
+
const reason =
|
|
271
|
+
owner && uid && owner !== uid
|
|
272
|
+
? `${item.error} (owned by another user)`
|
|
273
|
+
: item.error;
|
|
274
|
+
kv(item.filePath, reason);
|
|
275
|
+
}
|
|
276
|
+
console.log("");
|
|
277
|
+
kv("Manual", '[ -f "$HOME/.silicaclaw/env.sh" ] && . "$HOME/.silicaclaw/env.sh"');
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
57
281
|
function isNpxRun() {
|
|
58
282
|
return ROOT_DIR.includes("/.npm/_npx/");
|
|
59
283
|
}
|
|
60
284
|
|
|
285
|
+
function canWriteGlobalPrefix() {
|
|
286
|
+
try {
|
|
287
|
+
const prefixResult = runCapture("npm", ["prefix", "-g"]);
|
|
288
|
+
if ((prefixResult.status ?? 1) !== 0) return false;
|
|
289
|
+
const prefix = String(prefixResult.stdout || "").trim();
|
|
290
|
+
if (!prefix) return false;
|
|
291
|
+
const targetDir = resolve(prefix, "lib", "node_modules");
|
|
292
|
+
accessSync(targetDir, constants.W_OK);
|
|
293
|
+
return true;
|
|
294
|
+
} catch {
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
61
299
|
function showUpdateGuide(current, latest, beta) {
|
|
62
|
-
|
|
63
|
-
console.log(`current: ${current}`);
|
|
64
|
-
console.log(`latest : ${latest || "-"}`);
|
|
65
|
-
console.log(`beta : ${beta || "-"}`);
|
|
300
|
+
headline();
|
|
66
301
|
console.log("");
|
|
67
|
-
|
|
68
302
|
const upToDate = Boolean(beta) && current === beta;
|
|
69
303
|
if (upToDate) {
|
|
70
|
-
|
|
304
|
+
kv("Status", `up to date (${current})`);
|
|
71
305
|
} else {
|
|
72
|
-
|
|
306
|
+
kv("Status", `beta update available (${beta || "-"})`);
|
|
73
307
|
}
|
|
74
308
|
console.log("");
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
309
|
+
kv("Start", "silicaclaw start");
|
|
310
|
+
kv("Status", "silicaclaw status");
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function getGatewayStatus() {
|
|
314
|
+
try {
|
|
315
|
+
const result = runCapture("node", [resolve(ROOT_DIR, "scripts", "silicaclaw-gateway.mjs"), "status", "--json"], {
|
|
316
|
+
cwd: process.cwd(),
|
|
317
|
+
});
|
|
318
|
+
if ((result.status ?? 1) !== 0) return null;
|
|
319
|
+
const text = String(result.stdout || "").trim();
|
|
320
|
+
return text ? JSON.parse(text) : null;
|
|
321
|
+
} catch {
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function isManagedAppDir(appDir) {
|
|
327
|
+
if (!appDir || !existsSync(resolve(appDir, "package.json"))) return false;
|
|
328
|
+
try {
|
|
329
|
+
const pkg = JSON.parse(readFileSync(resolve(appDir, "package.json"), "utf8"));
|
|
330
|
+
const name = String(pkg?.name || "");
|
|
331
|
+
return name === "@silicaclaw/cli" || name === "silicaclaw";
|
|
332
|
+
} catch {
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function syncCurrentPackageToAppDir(appDir) {
|
|
338
|
+
if (!appDir || resolve(appDir) === ROOT_DIR) return false;
|
|
339
|
+
if (!isManagedAppDir(appDir)) return false;
|
|
340
|
+
|
|
341
|
+
const entries = [
|
|
342
|
+
"apps/local-console",
|
|
343
|
+
"apps/public-explorer",
|
|
344
|
+
"packages/core",
|
|
345
|
+
"packages/network",
|
|
346
|
+
"packages/storage",
|
|
347
|
+
"scripts",
|
|
348
|
+
"README.md",
|
|
349
|
+
"INSTALL.md",
|
|
350
|
+
"CHANGELOG.md",
|
|
351
|
+
"ARCHITECTURE.md",
|
|
352
|
+
"ROADMAP.md",
|
|
353
|
+
"SOCIAL_MD_SPEC.md",
|
|
354
|
+
"DEMO_GUIDE.md",
|
|
355
|
+
"RELEASE_NOTES_v1.0.md",
|
|
356
|
+
"social.md.example",
|
|
357
|
+
"openclaw.social.md.example",
|
|
358
|
+
"VERSION",
|
|
359
|
+
"package.json",
|
|
360
|
+
"package-lock.json",
|
|
361
|
+
];
|
|
362
|
+
|
|
363
|
+
for (const rel of entries) {
|
|
364
|
+
const src = resolve(ROOT_DIR, rel);
|
|
365
|
+
if (!existsSync(src)) continue;
|
|
366
|
+
const dst = resolve(appDir, rel);
|
|
367
|
+
cpSync(src, dst, { recursive: true, force: true });
|
|
368
|
+
}
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function restartGatewayIfRunning() {
|
|
373
|
+
const status = getGatewayStatus();
|
|
374
|
+
const appDir = status?.app_dir ? String(status.app_dir) : "";
|
|
375
|
+
syncCurrentPackageToAppDir(appDir);
|
|
376
|
+
|
|
377
|
+
const localRunning = Boolean(status?.local_console?.running);
|
|
378
|
+
const signalingRunning = Boolean(status?.signaling?.running);
|
|
379
|
+
if (!localRunning && !signalingRunning) {
|
|
380
|
+
return;
|
|
86
381
|
}
|
|
382
|
+
|
|
383
|
+
const mode = String(status?.mode || "local");
|
|
384
|
+
const args = [resolve(ROOT_DIR, "scripts", "silicaclaw-gateway.mjs"), "restart", `--mode=${mode}`];
|
|
385
|
+
if (mode === "global-preview" && status?.signaling?.url) {
|
|
386
|
+
args.push(`--signaling-url=${status.signaling.url}`);
|
|
387
|
+
}
|
|
388
|
+
if (mode === "global-preview" && status?.signaling?.room) {
|
|
389
|
+
args.push(`--room=${status.signaling.room}`);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
console.log("");
|
|
393
|
+
console.log(paint("Refreshing services", COLOR.bold));
|
|
394
|
+
runInherit("node", args, { cwd: process.cwd() });
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function tryGlobalUpgrade(beta) {
|
|
398
|
+
const writableGlobal = canWriteGlobalPrefix();
|
|
399
|
+
if (!writableGlobal) return false;
|
|
400
|
+
kv("Upgrade", `installing @silicaclaw/cli@${beta} globally`);
|
|
401
|
+
const result = runInherit("npm", ["i", "-g", `@silicaclaw/cli@${beta}`]);
|
|
402
|
+
return (result.status ?? 1) === 0;
|
|
87
403
|
}
|
|
88
404
|
|
|
89
405
|
function update() {
|
|
@@ -91,8 +407,12 @@ function update() {
|
|
|
91
407
|
try {
|
|
92
408
|
const result = runCapture("npm", ["view", "@silicaclaw/cli", "dist-tags", "--json"]);
|
|
93
409
|
if ((result.status ?? 1) !== 0) {
|
|
94
|
-
|
|
410
|
+
headline();
|
|
411
|
+
console.log("");
|
|
412
|
+
console.error(paint("Update check failed", COLOR.bold, COLOR.yellow));
|
|
95
413
|
if (result.stderr) console.error(result.stderr.trim());
|
|
414
|
+
console.log("");
|
|
415
|
+
kv("Try", "npm view @silicaclaw/cli dist-tags --json");
|
|
96
416
|
process.exit(result.status ?? 1);
|
|
97
417
|
}
|
|
98
418
|
const text = String(result.stdout || "").trim();
|
|
@@ -100,43 +420,73 @@ function update() {
|
|
|
100
420
|
const latest = tags.latest ? String(tags.latest) : "";
|
|
101
421
|
const beta = tags.beta ? String(tags.beta) : "";
|
|
102
422
|
showUpdateGuide(current, latest, beta);
|
|
423
|
+
const hasNewBeta = Boolean(beta) && beta !== current;
|
|
424
|
+
const npxRuntime = isNpxRun();
|
|
425
|
+
|
|
426
|
+
if (hasNewBeta) {
|
|
427
|
+
if (npxRuntime) {
|
|
428
|
+
kv("Update", `next run will use ${beta}`);
|
|
429
|
+
} else if (tryGlobalUpgrade(beta)) {
|
|
430
|
+
kv("Update", `installed ${beta}`);
|
|
431
|
+
} else {
|
|
432
|
+
kv("Update", `install ${beta} manually if needed`);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
restartGatewayIfRunning();
|
|
103
437
|
process.exit(0);
|
|
104
438
|
} catch (error) {
|
|
105
|
-
|
|
106
|
-
console.log("
|
|
107
|
-
console.
|
|
439
|
+
headline();
|
|
440
|
+
console.log("");
|
|
441
|
+
console.error(paint("Update check failed", COLOR.bold, COLOR.yellow));
|
|
442
|
+
console.error(error.message);
|
|
443
|
+
console.log("");
|
|
444
|
+
kv("Try", "npm view @silicaclaw/cli dist-tags --json");
|
|
108
445
|
process.exit(1);
|
|
109
446
|
}
|
|
110
447
|
}
|
|
111
448
|
|
|
449
|
+
function doctor() {
|
|
450
|
+
const steps = [
|
|
451
|
+
{ label: "Check", cmd: "npm", args: ["run", "-ws", "check"] },
|
|
452
|
+
{ label: "Build", cmd: "npm", args: ["run", "-ws", "build"] },
|
|
453
|
+
{ label: "Functional", cmd: "node", args: ["scripts/functional-check.mjs"] },
|
|
454
|
+
];
|
|
455
|
+
|
|
456
|
+
headline();
|
|
457
|
+
console.log("");
|
|
458
|
+
|
|
459
|
+
for (const step of steps) {
|
|
460
|
+
const result = runCapture(step.cmd, step.args, { cwd: ROOT_DIR });
|
|
461
|
+
if ((result.status ?? 1) === 0) {
|
|
462
|
+
kv(step.label, paint("ok", COLOR.green));
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
kv(step.label, paint("failed", COLOR.yellow));
|
|
467
|
+
const detail = compactOutput(`${result.stdout || ""}\n${result.stderr || ""}`);
|
|
468
|
+
if (detail) {
|
|
469
|
+
console.log("");
|
|
470
|
+
console.log(detail);
|
|
471
|
+
}
|
|
472
|
+
process.exit(result.status ?? 1);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
112
476
|
function help() {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
silicaclaw
|
|
118
|
-
silicaclaw
|
|
119
|
-
silicaclaw
|
|
120
|
-
silicaclaw
|
|
121
|
-
silicaclaw
|
|
122
|
-
silicaclaw
|
|
123
|
-
silicaclaw
|
|
124
|
-
silicaclaw doctor
|
|
125
|
-
silicaclaw
|
|
126
|
-
silicaclaw help
|
|
127
|
-
|
|
128
|
-
Commands:
|
|
129
|
-
onboard Interactive step-by-step onboarding (recommended)
|
|
130
|
-
connect Cross-network connect wizard (global-preview first)
|
|
131
|
-
update Check latest npm version and show upgrade commands
|
|
132
|
-
gateway Manage background services (start/stop/restart/status/logs)
|
|
133
|
-
local-console Start local console (http://localhost:4310)
|
|
134
|
-
explorer Start public explorer (http://localhost:4311)
|
|
135
|
-
signaling Start WebRTC signaling preview server
|
|
136
|
-
doctor Run project checks (npm run health)
|
|
137
|
-
version Print SilicaClaw version
|
|
138
|
-
help Show this help
|
|
139
|
-
`.trim());
|
|
477
|
+
headline();
|
|
478
|
+
console.log("");
|
|
479
|
+
section("Commands");
|
|
480
|
+
kv("Install", "npx -y @silicaclaw/cli@beta install");
|
|
481
|
+
kv("Start", "silicaclaw start");
|
|
482
|
+
kv("Status", "silicaclaw status");
|
|
483
|
+
kv("Stop", "silicaclaw stop");
|
|
484
|
+
kv("Update", "silicaclaw update");
|
|
485
|
+
kv("Onboard", "silicaclaw onboard");
|
|
486
|
+
kv("Connect", "silicaclaw connect");
|
|
487
|
+
kv("Logs", "silicaclaw logs local-console");
|
|
488
|
+
kv("Doctor", "silicaclaw doctor");
|
|
489
|
+
kv("Help", "silicaclaw help");
|
|
140
490
|
}
|
|
141
491
|
|
|
142
492
|
const cmd = String(process.argv[2] || "help").trim().toLowerCase();
|
|
@@ -157,11 +507,23 @@ switch (cmd) {
|
|
|
157
507
|
case "update":
|
|
158
508
|
update();
|
|
159
509
|
break;
|
|
510
|
+
case "install":
|
|
511
|
+
installPersistentCommand();
|
|
512
|
+
break;
|
|
160
513
|
case "gateway":
|
|
161
514
|
run("node", [resolve(ROOT_DIR, "scripts", "silicaclaw-gateway.mjs"), ...process.argv.slice(3)], {
|
|
162
515
|
cwd: process.cwd(),
|
|
163
516
|
});
|
|
164
517
|
break;
|
|
518
|
+
case "start":
|
|
519
|
+
case "stop":
|
|
520
|
+
case "restart":
|
|
521
|
+
case "status":
|
|
522
|
+
case "logs":
|
|
523
|
+
run("node", [resolve(ROOT_DIR, "scripts", "silicaclaw-gateway.mjs"), cmd, ...process.argv.slice(3)], {
|
|
524
|
+
cwd: process.cwd(),
|
|
525
|
+
});
|
|
526
|
+
break;
|
|
165
527
|
case "local-console":
|
|
166
528
|
case "console":
|
|
167
529
|
run("npm", ["run", "local-console"]);
|
|
@@ -175,12 +537,12 @@ switch (cmd) {
|
|
|
175
537
|
run("npm", ["run", "webrtc-signaling"]);
|
|
176
538
|
break;
|
|
177
539
|
case "doctor":
|
|
178
|
-
|
|
540
|
+
doctor();
|
|
179
541
|
break;
|
|
180
542
|
case "version":
|
|
181
543
|
case "-v":
|
|
182
544
|
case "--version":
|
|
183
|
-
|
|
545
|
+
headline();
|
|
184
546
|
break;
|
|
185
547
|
case "help":
|
|
186
548
|
case "-h":
|