@silicaclaw/cli 1.0.0-beta.21 → 1.0.0-beta.23

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.
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { spawnSync } from "node:child_process";
4
- import { accessSync, constants, cpSync, existsSync, readFileSync } from "node:fs";
4
+ import { accessSync, constants, cpSync, existsSync, mkdirSync, readFileSync, 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
 
@@ -67,6 +68,69 @@ function readPackageVersion() {
67
68
  }
68
69
  }
69
70
 
71
+ function preferredShellRcFile() {
72
+ const shell = String(process.env.SHELL || "");
73
+ if (shell.endsWith("/zsh")) return resolve(homedir(), ".zshrc");
74
+ if (shell.endsWith("/bash")) return resolve(homedir(), ".bashrc");
75
+ if (process.env.ZSH_VERSION) return resolve(homedir(), ".zshrc");
76
+ return resolve(homedir(), ".bashrc");
77
+ }
78
+
79
+ function userShimDir() {
80
+ return resolve(homedir(), ".silicaclaw", "bin");
81
+ }
82
+
83
+ function userShimPath() {
84
+ return resolve(userShimDir(), "silicaclaw");
85
+ }
86
+
87
+ function ensureLineInFile(filePath, block) {
88
+ const current = existsSync(filePath) ? readFileSync(filePath, "utf8") : "";
89
+ if (current.includes(block.trim())) {
90
+ return false;
91
+ }
92
+ const next = `${current.replace(/\s*$/, "")}\n\n${block}\n`;
93
+ mkdirSync(dirname(filePath), { recursive: true });
94
+ writeFileSync(filePath, next, "utf8");
95
+ return true;
96
+ }
97
+
98
+ function installPersistentCommand() {
99
+ const binDir = userShimDir();
100
+ const shimPath = userShimPath();
101
+ const rcFile = preferredShellRcFile();
102
+ const markerBlock = [
103
+ "# >>> silicaclaw >>>",
104
+ 'export PATH="$HOME/.silicaclaw/bin:$PATH"',
105
+ "# <<< silicaclaw <<<",
106
+ ].join("\n");
107
+
108
+ mkdirSync(binDir, { recursive: true });
109
+ writeFileSync(
110
+ shimPath,
111
+ [
112
+ "#!/usr/bin/env bash",
113
+ "set -euo pipefail",
114
+ 'exec npx -y @silicaclaw/cli@beta "$@"',
115
+ "",
116
+ ].join("\n"),
117
+ { encoding: "utf8", mode: 0o755 }
118
+ );
119
+ const rcUpdated = ensureLineInFile(rcFile, markerBlock);
120
+
121
+ console.log("Installed persistent `silicaclaw` command.");
122
+ console.log(`- shim: ${shimPath}`);
123
+ console.log(`- shell rc: ${rcFile}`);
124
+ console.log("");
125
+ if (rcUpdated) {
126
+ console.log("To activate in the current shell:");
127
+ console.log(`source "${rcFile}"`);
128
+ } else {
129
+ console.log("Shell PATH entry already existed.");
130
+ console.log(`If needed, run: source "${rcFile}"`);
131
+ }
132
+ }
133
+
70
134
  function isNpxRun() {
71
135
  return ROOT_DIR.includes("/.npm/_npx/");
72
136
  }
@@ -102,11 +166,13 @@ function showUpdateGuide(current, latest, beta) {
102
166
  console.log("");
103
167
  console.log("Quick next commands:");
104
168
  console.log("1) Start internet gateway");
105
- console.log(" silicaclaw start --mode=global-preview --signaling-url=https://your-relay.example");
169
+ console.log(" silicaclaw start --mode=global-preview");
106
170
  console.log("2) Check gateway status");
107
171
  console.log(" silicaclaw status");
108
- console.log("3) npx one-shot (no alias/global install)");
109
- console.log(" npx -y @silicaclaw/cli@beta start --mode=global-preview --signaling-url=https://your-relay.example");
172
+ console.log("3) Install persistent command (recommended once)");
173
+ console.log(" npx -y @silicaclaw/cli@beta install");
174
+ console.log("4) npx one-shot (no install)");
175
+ console.log(" npx -y @silicaclaw/cli@beta start --mode=global-preview");
110
176
  console.log("");
111
177
 
112
178
  const writableGlobal = canWriteGlobalPrefix();
@@ -121,7 +187,7 @@ function showUpdateGuide(current, latest, beta) {
121
187
  }
122
188
  if (npxRuntime) {
123
189
  console.log("Detected npx runtime.");
124
- console.log("If `silicaclaw` is unavailable in this shell, use the npx one-shot command above.");
190
+ console.log("Run `npx -y @silicaclaw/cli@beta install` once to make `silicaclaw` available in new shells.");
125
191
  }
126
192
  }
127
193
 
@@ -265,6 +331,7 @@ Usage:
265
331
  silicaclaw onboard
266
332
  silicaclaw connect
267
333
  silicaclaw update
334
+ silicaclaw install
268
335
  silicaclaw start [--mode=local|lan|global-preview]
269
336
  silicaclaw stop
270
337
  silicaclaw restart [--mode=local|lan|global-preview]
@@ -282,6 +349,7 @@ Commands:
282
349
  onboard Interactive step-by-step onboarding (recommended)
283
350
  connect Cross-network connect wizard (global-preview first)
284
351
  update Check latest npm version and show upgrade commands
352
+ install Install persistent silicaclaw command for future shells
285
353
  start Start gateway-managed background services
286
354
  stop Stop gateway-managed background services
287
355
  restart Restart gateway-managed background services
@@ -315,6 +383,9 @@ switch (cmd) {
315
383
  case "update":
316
384
  update();
317
385
  break;
386
+ case "install":
387
+ installPersistentCommand();
388
+ break;
318
389
  case "gateway":
319
390
  run("node", [resolve(ROOT_DIR, "scripts", "silicaclaw-gateway.mjs"), ...process.argv.slice(3)], {
320
391
  cwd: process.cwd(),
@@ -176,7 +176,7 @@ function printHelp() {
176
176
  SilicaClaw Gateway
177
177
 
178
178
  Usage:
179
- silicaclaw gateway start [--mode=local|lan|global-preview] [--signaling-url=http://host:4510] [--room=silicaclaw-demo]
179
+ silicaclaw gateway start [--mode=local|lan|global-preview] [--signaling-url=https://relay.silicaclaw.com] [--room=silicaclaw-global-preview]
180
180
  silicaclaw gateway stop
181
181
  silicaclaw gateway restart [--mode=...]
182
182
  silicaclaw gateway status
@@ -224,8 +224,8 @@ function printConnectionSummary(status) {
224
224
  console.log(`- mode: ${status.mode}`);
225
225
  console.log(`- adapter: ${status.adapter}`);
226
226
  if (status.mode === "global-preview") {
227
- const signalingUrl = status?.signaling?.url || "http://localhost:4510";
228
- const room = status?.signaling?.room || "silicaclaw-demo";
227
+ const signalingUrl = status?.signaling?.url || "https://relay.silicaclaw.com";
228
+ const room = status?.signaling?.room || "silicaclaw-global-preview";
229
229
  console.log(`- signaling: ${signalingUrl} (room=${room})`);
230
230
  }
231
231
  console.log(`- local-console log: ${status?.local_console?.log_file || CONSOLE_LOG_FILE}`);
@@ -312,8 +312,8 @@ function startAll() {
312
312
 
313
313
  const mode = parseMode(parseFlag("mode", process.env.NETWORK_MODE || "global-preview"));
314
314
  const adapter = adapterForMode(mode);
315
- const signalingUrl = parseFlag("signaling-url", process.env.WEBRTC_SIGNALING_URL || "http://localhost:4510");
316
- const room = parseFlag("room", process.env.WEBRTC_ROOM || "silicaclaw-demo");
315
+ const signalingUrl = parseFlag("signaling-url", process.env.WEBRTC_SIGNALING_URL || "https://relay.silicaclaw.com");
316
+ const room = parseFlag("room", process.env.WEBRTC_ROOM || "silicaclaw-global-preview");
317
317
  const shouldDisableSignaling = hasFlag("no-signaling");
318
318
 
319
319
  const currentLocalPid = readPid(CONSOLE_PID_FILE);
@@ -153,7 +153,35 @@ const server = http.createServer(async (req, res) => {
153
153
  const roomId = String(url.searchParams.get('room') || 'silicaclaw-room');
154
154
  const room = getRoom(roomId);
155
155
  cleanupRoom(roomId);
156
- return json(res, 200, { ok: true, peers: Array.from(room.peers.keys()) });
156
+ return json(res, 200, {
157
+ ok: true,
158
+ room: roomId,
159
+ peer_count: room.peers.size,
160
+ peers: Array.from(room.peers.keys()),
161
+ peer_details: Array.from(room.peers.entries()).map(([peerId, peer]) => ({
162
+ peer_id: peerId,
163
+ last_seen_at: peer.last_seen_at,
164
+ signal_queue_size: (room.queues.get(peerId) || []).length,
165
+ relay_queue_size: (room.relay_queues.get(peerId) || []).length,
166
+ })),
167
+ });
168
+ }
169
+
170
+ if (req.method === 'GET' && url.pathname === '/room') {
171
+ const roomId = String(url.searchParams.get('room') || 'silicaclaw-room');
172
+ const room = getRoom(roomId);
173
+ cleanupRoom(roomId);
174
+ return json(res, 200, {
175
+ ok: true,
176
+ room: roomId,
177
+ peer_count: room.peers.size,
178
+ peers: Array.from(room.peers.entries()).map(([peerId, peer]) => ({
179
+ peer_id: peerId,
180
+ last_seen_at: peer.last_seen_at,
181
+ signal_queue_size: (room.queues.get(peerId) || []).length,
182
+ relay_queue_size: (room.relay_queues.get(peerId) || []).length,
183
+ })),
184
+ });
157
185
  }
158
186
 
159
187
  if (req.method === 'GET' && url.pathname === '/poll') {