@silicaclaw/cli 1.0.0-beta.29 → 1.0.0-beta.30

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@silicaclaw/cli",
3
- "version": "1.0.0-beta.29",
3
+ "version": "1.0.0-beta.30",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { spawnSync } from "node:child_process";
4
- import { accessSync, constants, cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { accessSync, constants, cpSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
5
5
  import { homedir } from "node:os";
6
6
  import { dirname, resolve } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
@@ -29,7 +29,7 @@ function paint(text, ...styles) {
29
29
  }
30
30
 
31
31
  function headline() {
32
- console.log(`${paint("SilicaClaw", COLOR.bold, COLOR.orange)} ${paint(readVersion(), COLOR.dim)}`);
32
+ console.log(`${paint("SilicaClaw", COLOR.bold, COLOR.orange)} ${paint(readPackageVersion(), COLOR.dim)}`);
33
33
  console.log(paint("Public identity and discovery for OpenClaw agents.", COLOR.dim));
34
34
  }
35
35
 
@@ -137,6 +137,24 @@ function ensureLineInFile(filePath, block) {
137
137
  }
138
138
  }
139
139
 
140
+ function describeFileOwner(filePath) {
141
+ try {
142
+ if (!existsSync(filePath)) return null;
143
+ const stat = statSync(filePath);
144
+ return String(stat.uid);
145
+ } catch {
146
+ return null;
147
+ }
148
+ }
149
+
150
+ function currentUid() {
151
+ try {
152
+ return typeof process.getuid === "function" ? String(process.getuid()) : null;
153
+ } catch {
154
+ return null;
155
+ }
156
+ }
157
+
140
158
  function shellInitTargets() {
141
159
  const home = homedir();
142
160
  const shell = String(process.env.SHELL || "");
@@ -197,11 +215,15 @@ function installPersistentCommand() {
197
215
  );
198
216
  const rcFiles = shellInitTargets();
199
217
  const updatedFiles = [];
218
+ const configuredFiles = [];
200
219
  const failedFiles = [];
201
220
  for (const filePath of rcFiles) {
202
221
  const result = ensureLineInFile(filePath, rcBlock);
203
222
  if (result.changed) {
204
223
  updatedFiles.push(filePath);
224
+ configuredFiles.push(filePath);
225
+ } else if (!result.error) {
226
+ configuredFiles.push(filePath);
205
227
  }
206
228
  if (result.error) {
207
229
  failedFiles.push({ filePath, error: result.error });
@@ -210,24 +232,29 @@ function installPersistentCommand() {
210
232
 
211
233
  headline();
212
234
  console.log("");
213
- console.log(`${paint("Installed", COLOR.bold)} persistent command`);
235
+ console.log(`${paint("Installed", COLOR.bold)} \`silicaclaw\` command`);
214
236
  kv("Command", "silicaclaw");
215
- kv("Shim", shimPath);
216
- kv("Env", envFile);
217
- kv("Shell init", rcFiles.join(", "));
218
237
  console.log("");
219
238
  kv("Activate", `source "${envFile}"`);
220
- if (updatedFiles.length === 0) {
221
- kv("Startup", "shell files already configured");
239
+ if (configuredFiles.length > 0) {
240
+ kv("Startup", "configured");
241
+ } else {
242
+ kv("Startup", "manual setup required");
222
243
  }
223
244
  if (failedFiles.length > 0) {
224
245
  console.log("");
225
- console.log(paint("Shell files not updated automatically", COLOR.bold, COLOR.yellow));
246
+ console.log(paint("Shell files skipped", COLOR.bold, COLOR.yellow));
247
+ const uid = currentUid();
226
248
  for (const item of failedFiles) {
227
- kv(item.filePath, item.error);
249
+ const owner = describeFileOwner(item.filePath);
250
+ const reason =
251
+ owner && uid && owner !== uid
252
+ ? `${item.error} (owned by another user)`
253
+ : item.error;
254
+ kv(item.filePath, reason);
228
255
  }
229
256
  console.log("");
230
- kv("Manual line", '[ -f "$HOME/.silicaclaw/env.sh" ] && . "$HOME/.silicaclaw/env.sh"');
257
+ kv("Manual", '[ -f "$HOME/.silicaclaw/env.sh" ] && . "$HOME/.silicaclaw/env.sh"');
231
258
  }
232
259
  }
233
260
 
@@ -250,44 +277,17 @@ function canWriteGlobalPrefix() {
250
277
  }
251
278
 
252
279
  function showUpdateGuide(current, latest, beta) {
253
- const npxRuntime = isNpxRun();
254
280
  headline();
255
281
  console.log("");
256
- console.log(paint("Update check", COLOR.bold));
257
- kv("Current", current);
258
- kv("Latest", latest || "-");
259
- kv("Beta", beta || "-");
260
- console.log("");
261
-
262
282
  const upToDate = Boolean(beta) && current === beta;
263
283
  if (upToDate) {
264
- console.log(`${paint("Ready", COLOR.bold)} you're already on the latest beta.`);
284
+ kv("Status", `up to date (${current})`);
265
285
  } else {
266
- console.log(`${paint("Update available", COLOR.bold, COLOR.yellow)} install the latest beta and refresh your services.`);
286
+ kv("Status", `beta update available (${beta || "-"})`);
267
287
  }
268
288
  console.log("");
269
- console.log(paint("Next commands", COLOR.bold));
270
- kv("Start", "silicaclaw start --mode=global-preview");
289
+ kv("Start", "silicaclaw start");
271
290
  kv("Status", "silicaclaw status");
272
- kv("Install", "npx -y @silicaclaw/cli@beta install");
273
- kv("One-shot", "npx -y @silicaclaw/cli@beta start --mode=global-preview");
274
- console.log("");
275
-
276
- const writableGlobal = canWriteGlobalPrefix();
277
- if (!npxRuntime && writableGlobal) {
278
- console.log(paint("Optional global install", COLOR.bold));
279
- kv("Install", "npm i -g @silicaclaw/cli@beta");
280
- kv("Verify", "silicaclaw version");
281
- console.log("");
282
- } else if (!npxRuntime) {
283
- console.log(paint("Global install skipped", COLOR.bold, COLOR.yellow));
284
- console.log("npm global directory is not writable on this machine.");
285
- console.log("");
286
- }
287
- if (npxRuntime) {
288
- console.log(paint("Detected npx runtime", COLOR.bold));
289
- console.log("Run `npx -y @silicaclaw/cli@beta install` once to make `silicaclaw` available in new shells.");
290
- }
291
291
  }
292
292
 
293
293
  function getGatewayStatus() {
@@ -352,15 +352,11 @@ function syncCurrentPackageToAppDir(appDir) {
352
352
  function restartGatewayIfRunning() {
353
353
  const status = getGatewayStatus();
354
354
  const appDir = status?.app_dir ? String(status.app_dir) : "";
355
- const synced = syncCurrentPackageToAppDir(appDir);
356
- if (synced) {
357
- kv("Synced", appDir);
358
- }
355
+ syncCurrentPackageToAppDir(appDir);
359
356
 
360
357
  const localRunning = Boolean(status?.local_console?.running);
361
358
  const signalingRunning = Boolean(status?.signaling?.running);
362
359
  if (!localRunning && !signalingRunning) {
363
- kv("Runtime", "gateway not running; no refresh needed");
364
360
  return;
365
361
  }
366
362
 
@@ -374,7 +370,7 @@ function restartGatewayIfRunning() {
374
370
  }
375
371
 
376
372
  console.log("");
377
- console.log(paint("Refreshing background services", COLOR.bold));
373
+ console.log(paint("Refreshing services", COLOR.bold));
378
374
  runInherit("node", args, { cwd: process.cwd() });
379
375
  }
380
376
 
@@ -409,11 +405,11 @@ function update() {
409
405
 
410
406
  if (hasNewBeta) {
411
407
  if (npxRuntime) {
412
- kv("Update", `new beta detected (${beta}); npx will use it on the next run`);
408
+ kv("Update", `next run will use ${beta}`);
413
409
  } else if (tryGlobalUpgrade(beta)) {
414
- kv("Upgrade", `global install updated to ${beta}`);
410
+ kv("Update", `installed ${beta}`);
415
411
  } else {
416
- kv("Upgrade", "skipped global install");
412
+ kv("Update", `install ${beta} manually if needed`);
417
413
  }
418
414
  }
419
415
 
@@ -33,7 +33,18 @@ function paint(text, ...styles) {
33
33
  }
34
34
 
35
35
  function headline() {
36
- const version = existsSync(join(ROOT_DIR, "VERSION")) ? String(readFileSync(join(ROOT_DIR, "VERSION"), "utf8")).trim() : "unknown";
36
+ const pkgPath = join(ROOT_DIR, "package.json");
37
+ let version = "unknown";
38
+ if (existsSync(pkgPath)) {
39
+ try {
40
+ const pkg = JSON.parse(String(readFileSync(pkgPath, "utf8")));
41
+ version = String(pkg.version || "unknown");
42
+ } catch {
43
+ version = "unknown";
44
+ }
45
+ } else if (existsSync(join(ROOT_DIR, "VERSION"))) {
46
+ version = String(readFileSync(join(ROOT_DIR, "VERSION"), "utf8")).trim() || "unknown";
47
+ }
37
48
  console.log(`${paint("SilicaClaw", COLOR.bold, COLOR.orange)} ${paint(version, COLOR.dim)}`);
38
49
  console.log(paint("Public identity and discovery for OpenClaw agents.", COLOR.dim));
39
50
  }
@@ -253,27 +264,17 @@ function showStatusHuman() {
253
264
  const payload = buildStatusPayload();
254
265
  headline();
255
266
  console.log("");
256
- console.log(paint("Gateway status", COLOR.bold));
257
- kv("App dir", payload.app_dir);
258
- kv("Mode", payload.mode);
259
- kv("Adapter", payload.adapter);
260
267
  kv(
261
- "Console",
268
+ "Status",
262
269
  payload.local_console.running
263
- ? `${paint("running", COLOR.green)} (pid=${payload.local_console.pid})`
264
- : paint("stopped", COLOR.dim)
270
+ ? `${paint("running", COLOR.green)} · ${payload.mode}`
271
+ : `${paint("stopped", COLOR.dim)} · ${payload.mode}`
265
272
  );
266
273
  if (payload.mode === "global-preview") {
267
274
  kv("Relay", payload.signaling.url || "https://relay.silicaclaw.com");
268
275
  kv("Room", payload.signaling.room || "silicaclaw-global-preview");
269
276
  }
270
- if (payload.signaling.running) {
271
- kv("Signaling", `${paint("running", COLOR.green)} (pid=${payload.signaling.pid})`);
272
- }
273
- console.log("");
274
- kv("Open", "http://localhost:4310");
275
- kv("Logs", "silicaclaw logs local-console");
276
- kv("Stop", "silicaclaw stop");
277
+ if (payload.local_console.running) kv("Open", "http://localhost:4310");
277
278
  return payload;
278
279
  }
279
280
 
@@ -281,21 +282,14 @@ function printConnectionSummary(status, verb = "Started") {
281
282
  if (!status?.local_console?.running) return;
282
283
  headline();
283
284
  console.log("");
284
- console.log(`${paint(verb, COLOR.bold)} background services`);
285
+ kv("Status", `${verb.toLowerCase()} · ${status.mode}`);
285
286
  kv("Console", `http://localhost:4310`);
286
- kv("Console pid", String(status?.local_console?.pid || "-"));
287
- kv("Mode", status.mode);
288
- kv("Adapter", status.adapter);
289
287
  if (status.mode === "global-preview") {
290
288
  const signalingUrl = status?.signaling?.url || "https://relay.silicaclaw.com";
291
289
  const room = status?.signaling?.room || "silicaclaw-global-preview";
292
290
  kv("Relay", signalingUrl);
293
291
  kv("Room", room);
294
292
  }
295
- console.log("");
296
- kv("Status", "silicaclaw status");
297
- kv("Logs", "silicaclaw logs local-console");
298
- kv("Stop", "silicaclaw stop");
299
293
  }
300
294
 
301
295
  function listeningProcessOnPort(port) {
@@ -326,7 +320,7 @@ function printStopSummary() {
326
320
  const signalingListener = listeningProcessOnPort(4510);
327
321
  headline();
328
322
  console.log("");
329
- console.log(`${paint("Stopped", COLOR.bold)} background services`);
323
+ kv("Status", "stopped");
330
324
  if (!localListener) {
331
325
  kv("Console", paint("stopped", COLOR.green));
332
326
  } else {
@@ -341,8 +335,6 @@ function printStopSummary() {
341
335
  kv("Inspect", "lsof -nP -iTCP:4510 -sTCP:LISTEN");
342
336
  kv("Stop pid", `kill ${signalingListener.pid}`);
343
337
  }
344
- console.log("");
345
- kv("Status", "silicaclaw status");
346
338
  }
347
339
 
348
340
  function tailFile(file, lines = 80) {