@silicaclaw/cli 1.0.0-beta.15 → 1.0.0-beta.17

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.15",
3
+ "version": "1.0.0-beta.17",
4
4
  "private": false,
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -87,31 +87,28 @@ function showUpdateGuide(current, latest, beta) {
87
87
  console.log("Update available.");
88
88
  }
89
89
  console.log("");
90
- console.log("Recommended commands:");
91
- console.log("1) npx mode (recommended, zero setup)");
92
- console.log(" npx @silicaclaw/cli@beta onboard");
93
- console.log(" npx @silicaclaw/cli@beta connect");
94
- console.log(" npx @silicaclaw/cli@beta update");
95
- console.log("");
96
- console.log("2) shell alias mode (no global install / no PATH edits)");
97
- console.log(" alias silicaclaw='npx -y @silicaclaw/cli@beta'");
98
- console.log(" silicaclaw version");
90
+ console.log("Quick next commands:");
91
+ console.log("1) Start local gateway");
92
+ console.log(" silicaclaw gateway start --mode=local");
93
+ console.log("2) Check gateway status");
94
+ console.log(" silicaclaw gateway status");
95
+ console.log("3) npx one-shot (no alias/global install)");
96
+ console.log(" npx -y @silicaclaw/cli@beta gateway start --mode=local");
99
97
  console.log("");
98
+
100
99
  const writableGlobal = canWriteGlobalPrefix();
101
100
  if (!npxRuntime && writableGlobal) {
102
- console.log("3) global install mode (optional)");
101
+ console.log("Optional global install:");
103
102
  console.log(" npm i -g @silicaclaw/cli@beta");
104
103
  console.log(" silicaclaw version");
105
104
  console.log("");
106
105
  } else if (!npxRuntime) {
107
- console.log("Global install skipped: current npm global directory is not writable (likely EACCES).");
108
- console.log("Use npx or alias mode above.");
106
+ console.log("Global install skipped: npm global directory is not writable (likely EACCES).");
109
107
  console.log("");
110
108
  }
111
109
  if (npxRuntime) {
112
- console.log("Detected npx runtime: use npx commands above for immediate update.");
113
- console.log("If `silicaclaw: command not found`, run:");
114
- console.log("alias silicaclaw='npx -y @silicaclaw/cli@beta'");
110
+ console.log("Detected npx runtime.");
111
+ console.log("If `silicaclaw` is unavailable in this shell, use the npx one-shot command above.");
115
112
  }
116
113
  }
117
114
 
@@ -146,6 +143,11 @@ Usage:
146
143
  silicaclaw onboard
147
144
  silicaclaw connect
148
145
  silicaclaw update
146
+ silicaclaw start [--mode=local|lan|global-preview]
147
+ silicaclaw stop
148
+ silicaclaw restart [--mode=local|lan|global-preview]
149
+ silicaclaw status
150
+ silicaclaw logs [local-console|signaling]
149
151
  silicaclaw gateway <start|stop|restart|status|logs>
150
152
  silicaclaw local-console
151
153
  silicaclaw explorer
@@ -158,6 +160,11 @@ Commands:
158
160
  onboard Interactive step-by-step onboarding (recommended)
159
161
  connect Cross-network connect wizard (global-preview first)
160
162
  update Check latest npm version and show upgrade commands
163
+ start Start gateway-managed background services
164
+ stop Stop gateway-managed background services
165
+ restart Restart gateway-managed background services
166
+ status Show gateway-managed service status
167
+ logs Show gateway-managed service logs
161
168
  gateway Manage background services (start/stop/restart/status/logs)
162
169
  local-console Start local console (http://localhost:4310)
163
170
  explorer Start public explorer (http://localhost:4311)
@@ -191,6 +198,15 @@ switch (cmd) {
191
198
  cwd: process.cwd(),
192
199
  });
193
200
  break;
201
+ case "start":
202
+ case "stop":
203
+ case "restart":
204
+ case "status":
205
+ case "logs":
206
+ run("node", [resolve(ROOT_DIR, "scripts", "silicaclaw-gateway.mjs"), cmd, ...process.argv.slice(3)], {
207
+ cwd: process.cwd(),
208
+ });
209
+ break;
194
210
  case "local-console":
195
211
  case "console":
196
212
  run("npm", ["run", "local-console"]);
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { spawn } from "node:child_process";
3
+ import { spawn, spawnSync } from "node:child_process";
4
4
  import { existsSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync } from "node:fs";
5
5
  import { homedir } from "node:os";
6
6
  import { dirname, join, resolve } from "node:path";
@@ -13,6 +13,25 @@ const ROOT_DIR = resolve(__dirname, "..");
13
13
  const argv = process.argv.slice(2);
14
14
  const cmd = String(argv[0] || "help").toLowerCase();
15
15
 
16
+ function readJson(file) {
17
+ try {
18
+ return JSON.parse(String(readFileSync(file, "utf8")));
19
+ } catch {
20
+ return null;
21
+ }
22
+ }
23
+
24
+ function isSilicaClawDir(dir) {
25
+ const pkgPath = join(dir, "package.json");
26
+ if (!existsSync(pkgPath)) return false;
27
+ const pkg = readJson(pkgPath);
28
+ if (!pkg || typeof pkg !== "object") return false;
29
+ const name = String(pkg.name || "");
30
+ if (name === "@silicaclaw/cli" || name === "silicaclaw") return true;
31
+ const scripts = pkg.scripts && typeof pkg.scripts === "object" ? pkg.scripts : {};
32
+ return Boolean(scripts.gateway || scripts["local-console"] || scripts["public-explorer"]);
33
+ }
34
+
16
35
  function parseFlag(name, fallback = "") {
17
36
  const prefix = `--${name}=`;
18
37
  for (const item of argv) {
@@ -27,17 +46,17 @@ function hasFlag(name) {
27
46
 
28
47
  function detectAppDir() {
29
48
  const envDir = process.env.SILICACLAW_APP_DIR;
30
- if (envDir && existsSync(join(envDir, "package.json"))) {
49
+ if (envDir && isSilicaClawDir(envDir)) {
31
50
  return resolve(envDir);
32
51
  }
33
52
 
34
53
  const cwd = process.cwd();
35
- if (existsSync(join(cwd, "package.json"))) {
54
+ if (isSilicaClawDir(cwd)) {
36
55
  return resolve(cwd);
37
56
  }
38
57
 
39
58
  const homeCandidate = join(homedir(), "silicaclaw");
40
- if (existsSync(join(homeCandidate, "package.json"))) {
59
+ if (isSilicaClawDir(homeCandidate)) {
41
60
  return resolve(homeCandidate);
42
61
  }
43
62
 
@@ -193,6 +212,74 @@ function showStatus() {
193
212
  updated_at: state?.updated_at || null,
194
213
  };
195
214
  console.log(JSON.stringify(payload, null, 2));
215
+ return payload;
216
+ }
217
+
218
+ function printConnectionSummary(status) {
219
+ if (!status?.local_console?.running) return;
220
+ console.log("");
221
+ console.log("Gateway connection summary:");
222
+ console.log(`- local-console: http://localhost:4310`);
223
+ console.log(`- mode: ${status.mode}`);
224
+ console.log(`- adapter: ${status.adapter}`);
225
+ if (status.mode === "global-preview") {
226
+ const signalingUrl = status?.signaling?.url || "http://localhost:4510";
227
+ const room = status?.signaling?.room || "silicaclaw-demo";
228
+ console.log(`- signaling: ${signalingUrl} (room=${room})`);
229
+ }
230
+ console.log(`- local-console log: ${status?.local_console?.log_file || CONSOLE_LOG_FILE}`);
231
+ console.log(`- status: silicaclaw gateway status`);
232
+ console.log(`- logs: silicaclaw gateway logs local-console`);
233
+ console.log(`- stop: silicaclaw gateway stop`);
234
+ }
235
+
236
+ function listeningProcessOnPort(port) {
237
+ try {
238
+ const pidRes = spawnSync("lsof", ["-nP", `-iTCP:${port}`, "-sTCP:LISTEN", "-t"], {
239
+ encoding: "utf8",
240
+ stdio: ["ignore", "pipe", "ignore"],
241
+ });
242
+ const pid = String(pidRes.stdout || "")
243
+ .split(/\r?\n/)
244
+ .map((s) => s.trim())
245
+ .find(Boolean);
246
+ if (!pid) return null;
247
+
248
+ const cmdRes = spawnSync("ps", ["-p", pid, "-o", "command="], {
249
+ encoding: "utf8",
250
+ stdio: ["ignore", "pipe", "ignore"],
251
+ });
252
+ const command = String(cmdRes.stdout || "").trim() || "unknown";
253
+ return { pid, command };
254
+ } catch {
255
+ return null;
256
+ }
257
+ }
258
+
259
+ function printStopSummary() {
260
+ const localListener = listeningProcessOnPort(4310);
261
+ const signalingListener = listeningProcessOnPort(4510);
262
+ console.log("");
263
+ console.log("Gateway stop summary:");
264
+ if (!localListener) {
265
+ console.log("- local-console port 4310: stopped");
266
+ } else {
267
+ console.log(`- local-console port 4310: still in use by pid=${localListener.pid}`);
268
+ console.log(` command: ${localListener.command}`);
269
+ console.log(" this is likely another process not started by gateway");
270
+ console.log(` inspect: lsof -nP -iTCP:4310 -sTCP:LISTEN`);
271
+ console.log(` stop it: kill ${localListener.pid}`);
272
+ }
273
+ if (!signalingListener) {
274
+ console.log("- signaling port 4510: stopped");
275
+ } else {
276
+ console.log(`- signaling port 4510: still in use by pid=${signalingListener.pid}`);
277
+ console.log(` command: ${signalingListener.command}`);
278
+ console.log(" this is likely another process not started by gateway");
279
+ console.log(` inspect: lsof -nP -iTCP:4510 -sTCP:LISTEN`);
280
+ console.log(` stop it: kill ${signalingListener.pid}`);
281
+ }
282
+ console.log(`- check status: silicaclaw gateway status`);
196
283
  }
197
284
 
198
285
  function tailFile(file, lines = 80) {
@@ -287,18 +374,21 @@ async function main() {
287
374
  }
288
375
  if (cmd === "start") {
289
376
  startAll();
290
- showStatus();
377
+ const status = showStatus();
378
+ printConnectionSummary(status);
291
379
  return;
292
380
  }
293
381
  if (cmd === "stop") {
294
382
  await stopAll();
295
383
  showStatus();
384
+ printStopSummary();
296
385
  return;
297
386
  }
298
387
  if (cmd === "restart") {
299
388
  await stopAll();
300
389
  startAll();
301
- showStatus();
390
+ const status = showStatus();
391
+ printConnectionSummary(status);
302
392
  return;
303
393
  }
304
394
  if (cmd === "logs") {
@@ -318,4 +408,3 @@ main().catch((error) => {
318
408
  console.error(error?.message || String(error));
319
409
  process.exit(1);
320
410
  });
321
-