@silicaclaw/cli 1.0.0-beta.7 → 1.0.0-beta.8
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/INSTALL.md +19 -0
- package/README.md +19 -0
- package/package.json +2 -1
- package/scripts/silicaclaw-cli.mjs +92 -0
- package/scripts/silicaclaw-gateway.mjs +321 -0
package/INSTALL.md
CHANGED
|
@@ -28,6 +28,21 @@ Cross-network quick wizard (defaults to global-preview):
|
|
|
28
28
|
npx @silicaclaw/cli@beta connect
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
Check/update CLI version:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx @silicaclaw/cli@beta update
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Gateway background service commands:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx @silicaclaw/cli@beta gateway start --mode=local
|
|
41
|
+
npx @silicaclaw/cli@beta gateway status
|
|
42
|
+
npx @silicaclaw/cli@beta gateway restart --mode=lan
|
|
43
|
+
npx @silicaclaw/cli@beta gateway stop
|
|
44
|
+
```
|
|
45
|
+
|
|
31
46
|
For most home users, just press Enter on defaults and use `local` mode first.
|
|
32
47
|
|
|
33
48
|
Optional global install (advanced users only):
|
|
@@ -36,6 +51,10 @@ Optional global install (advanced users only):
|
|
|
36
51
|
npm i -g @silicaclaw/cli
|
|
37
52
|
silicaclaw onboard
|
|
38
53
|
silicaclaw connect
|
|
54
|
+
silicaclaw update
|
|
55
|
+
silicaclaw gateway start --mode=local
|
|
56
|
+
silicaclaw gateway status
|
|
57
|
+
silicaclaw gateway stop
|
|
39
58
|
```
|
|
40
59
|
|
|
41
60
|
## 3. Run
|
package/README.md
CHANGED
|
@@ -34,6 +34,21 @@ Cross-network preview quick wizard:
|
|
|
34
34
|
npx @silicaclaw/cli@beta connect
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
Check and update CLI version:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx @silicaclaw/cli@beta update
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Background gateway service:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx @silicaclaw/cli@beta gateway start --mode=local
|
|
47
|
+
npx @silicaclaw/cli@beta gateway status
|
|
48
|
+
npx @silicaclaw/cli@beta gateway restart --mode=lan
|
|
49
|
+
npx @silicaclaw/cli@beta gateway stop
|
|
50
|
+
```
|
|
51
|
+
|
|
37
52
|
Or manual:
|
|
38
53
|
|
|
39
54
|
```bash
|
|
@@ -71,6 +86,10 @@ Optional global install:
|
|
|
71
86
|
npm i -g @silicaclaw/cli
|
|
72
87
|
silicaclaw onboard
|
|
73
88
|
silicaclaw connect
|
|
89
|
+
silicaclaw update
|
|
90
|
+
silicaclaw gateway start --mode=local
|
|
91
|
+
silicaclaw gateway status
|
|
92
|
+
silicaclaw gateway stop
|
|
74
93
|
```
|
|
75
94
|
|
|
76
95
|
## Quick Start (OpenClaw-style)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@silicaclaw/cli",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.8",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
"dev": "npm run --workspace @silicaclaw/local-console dev",
|
|
54
54
|
"onboard": "node scripts/silicaclaw-cli.mjs onboard",
|
|
55
55
|
"quickstart": "bash scripts/quickstart.sh",
|
|
56
|
+
"gateway": "node scripts/silicaclaw-gateway.mjs",
|
|
56
57
|
"local-console": "npm run --workspace @silicaclaw/local-console dev",
|
|
57
58
|
"public-explorer": "npm run --workspace @silicaclaw/public-explorer dev",
|
|
58
59
|
"logo": "bash scripts/install-logo.sh",
|
|
@@ -23,12 +23,92 @@ function run(cmd, args, extra = {}) {
|
|
|
23
23
|
process.exit(result.status ?? 0);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
function runCapture(cmd, args, extra = {}) {
|
|
27
|
+
const result = spawnSync(cmd, args, {
|
|
28
|
+
cwd: ROOT_DIR,
|
|
29
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
30
|
+
encoding: "utf8",
|
|
31
|
+
env: process.env,
|
|
32
|
+
...extra,
|
|
33
|
+
});
|
|
34
|
+
if (result.error) {
|
|
35
|
+
throw result.error;
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
|
|
26
40
|
function readVersion() {
|
|
27
41
|
const versionFile = resolve(ROOT_DIR, "VERSION");
|
|
28
42
|
if (!existsSync(versionFile)) return "unknown";
|
|
29
43
|
return readFileSync(versionFile, "utf8").trim() || "unknown";
|
|
30
44
|
}
|
|
31
45
|
|
|
46
|
+
function readPackageVersion() {
|
|
47
|
+
const pkgFile = resolve(ROOT_DIR, "package.json");
|
|
48
|
+
if (!existsSync(pkgFile)) return "unknown";
|
|
49
|
+
try {
|
|
50
|
+
const pkg = JSON.parse(readFileSync(pkgFile, "utf8"));
|
|
51
|
+
return String(pkg.version || "unknown");
|
|
52
|
+
} catch {
|
|
53
|
+
return "unknown";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isNpxRun() {
|
|
58
|
+
return ROOT_DIR.includes("/.npm/_npx/");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function showUpdateGuide(current, latest, beta) {
|
|
62
|
+
console.log("SilicaClaw update check");
|
|
63
|
+
console.log(`current: ${current}`);
|
|
64
|
+
console.log(`latest : ${latest || "-"}`);
|
|
65
|
+
console.log(`beta : ${beta || "-"}`);
|
|
66
|
+
console.log("");
|
|
67
|
+
|
|
68
|
+
const upToDate = Boolean(beta) && current === beta;
|
|
69
|
+
if (upToDate) {
|
|
70
|
+
console.log("You are already on the latest beta.");
|
|
71
|
+
} else {
|
|
72
|
+
console.log("Update available.");
|
|
73
|
+
}
|
|
74
|
+
console.log("");
|
|
75
|
+
console.log("Recommended commands:");
|
|
76
|
+
console.log("1) npx mode (no global install)");
|
|
77
|
+
console.log(" npx @silicaclaw/cli@beta onboard");
|
|
78
|
+
console.log(" npx @silicaclaw/cli@beta connect");
|
|
79
|
+
console.log("");
|
|
80
|
+
console.log("2) global install mode");
|
|
81
|
+
console.log(" npm i -g @silicaclaw/cli@beta");
|
|
82
|
+
console.log(" silicaclaw version");
|
|
83
|
+
console.log("");
|
|
84
|
+
if (isNpxRun()) {
|
|
85
|
+
console.log("Detected npx runtime: use npx commands above for immediate update.");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function update() {
|
|
90
|
+
const current = readPackageVersion();
|
|
91
|
+
try {
|
|
92
|
+
const result = runCapture("npm", ["view", "@silicaclaw/cli", "dist-tags", "--json"]);
|
|
93
|
+
if ((result.status ?? 1) !== 0) {
|
|
94
|
+
console.error("Failed to query npm dist-tags.");
|
|
95
|
+
if (result.stderr) console.error(result.stderr.trim());
|
|
96
|
+
process.exit(result.status ?? 1);
|
|
97
|
+
}
|
|
98
|
+
const text = String(result.stdout || "").trim();
|
|
99
|
+
const tags = text ? JSON.parse(text) : {};
|
|
100
|
+
const latest = tags.latest ? String(tags.latest) : "";
|
|
101
|
+
const beta = tags.beta ? String(tags.beta) : "";
|
|
102
|
+
showUpdateGuide(current, latest, beta);
|
|
103
|
+
process.exit(0);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error(`Update check failed: ${error.message}`);
|
|
106
|
+
console.log("Try manually:");
|
|
107
|
+
console.log("npm view @silicaclaw/cli dist-tags --json");
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
32
112
|
function help() {
|
|
33
113
|
console.log(`
|
|
34
114
|
SilicaClaw CLI
|
|
@@ -36,6 +116,8 @@ SilicaClaw CLI
|
|
|
36
116
|
Usage:
|
|
37
117
|
silicaclaw onboard
|
|
38
118
|
silicaclaw connect
|
|
119
|
+
silicaclaw update
|
|
120
|
+
silicaclaw gateway <start|stop|restart|status|logs>
|
|
39
121
|
silicaclaw local-console
|
|
40
122
|
silicaclaw explorer
|
|
41
123
|
silicaclaw signaling
|
|
@@ -46,6 +128,8 @@ Usage:
|
|
|
46
128
|
Commands:
|
|
47
129
|
onboard Interactive step-by-step onboarding (recommended)
|
|
48
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)
|
|
49
133
|
local-console Start local console (http://localhost:4310)
|
|
50
134
|
explorer Start public explorer (http://localhost:4311)
|
|
51
135
|
signaling Start WebRTC signaling preview server
|
|
@@ -70,6 +154,14 @@ switch (cmd) {
|
|
|
70
154
|
},
|
|
71
155
|
});
|
|
72
156
|
break;
|
|
157
|
+
case "update":
|
|
158
|
+
update();
|
|
159
|
+
break;
|
|
160
|
+
case "gateway":
|
|
161
|
+
run("node", [resolve(ROOT_DIR, "scripts", "silicaclaw-gateway.mjs"), ...process.argv.slice(3)], {
|
|
162
|
+
cwd: process.cwd(),
|
|
163
|
+
});
|
|
164
|
+
break;
|
|
73
165
|
case "local-console":
|
|
74
166
|
case "console":
|
|
75
167
|
run("npm", ["run", "local-console"]);
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import { existsSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { dirname, join, resolve } from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
const ROOT_DIR = resolve(__dirname, "..");
|
|
12
|
+
|
|
13
|
+
const argv = process.argv.slice(2);
|
|
14
|
+
const cmd = String(argv[0] || "help").toLowerCase();
|
|
15
|
+
|
|
16
|
+
function parseFlag(name, fallback = "") {
|
|
17
|
+
const prefix = `--${name}=`;
|
|
18
|
+
for (const item of argv) {
|
|
19
|
+
if (item.startsWith(prefix)) return item.slice(prefix.length);
|
|
20
|
+
}
|
|
21
|
+
return fallback;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function hasFlag(name) {
|
|
25
|
+
return argv.includes(`--${name}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function detectAppDir() {
|
|
29
|
+
const envDir = process.env.SILICACLAW_APP_DIR;
|
|
30
|
+
if (envDir && existsSync(join(envDir, "package.json"))) {
|
|
31
|
+
return resolve(envDir);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const cwd = process.cwd();
|
|
35
|
+
if (existsSync(join(cwd, "package.json"))) {
|
|
36
|
+
return resolve(cwd);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const homeCandidate = join(homedir(), "silicaclaw");
|
|
40
|
+
if (existsSync(join(homeCandidate, "package.json"))) {
|
|
41
|
+
return resolve(homeCandidate);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return ROOT_DIR;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const APP_DIR = detectAppDir();
|
|
48
|
+
const STATE_DIR = join(APP_DIR, ".silicaclaw", "gateway");
|
|
49
|
+
const CONSOLE_PID_FILE = join(STATE_DIR, "local-console.pid");
|
|
50
|
+
const CONSOLE_LOG_FILE = join(STATE_DIR, "local-console.log");
|
|
51
|
+
const SIGNALING_PID_FILE = join(STATE_DIR, "signaling.pid");
|
|
52
|
+
const SIGNALING_LOG_FILE = join(STATE_DIR, "signaling.log");
|
|
53
|
+
const STATE_FILE = join(STATE_DIR, "state.json");
|
|
54
|
+
|
|
55
|
+
function ensureStateDir() {
|
|
56
|
+
mkdirSync(STATE_DIR, { recursive: true });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function readPid(file) {
|
|
60
|
+
if (!existsSync(file)) return null;
|
|
61
|
+
const text = String(readFileSync(file, "utf8")).trim();
|
|
62
|
+
const pid = Number(text);
|
|
63
|
+
return Number.isFinite(pid) && pid > 0 ? pid : null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function isRunning(pid) {
|
|
67
|
+
if (!pid) return false;
|
|
68
|
+
try {
|
|
69
|
+
process.kill(pid, 0);
|
|
70
|
+
return true;
|
|
71
|
+
} catch {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function removeFileIfExists(path) {
|
|
77
|
+
if (existsSync(path)) rmSync(path, { force: true });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function stopPid(pid, name) {
|
|
81
|
+
if (!pid || !isRunning(pid)) return;
|
|
82
|
+
try {
|
|
83
|
+
process.kill(pid, "SIGTERM");
|
|
84
|
+
} catch {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const start = Date.now();
|
|
88
|
+
while (Date.now() - start < 5000) {
|
|
89
|
+
if (!isRunning(pid)) return;
|
|
90
|
+
await new Promise((r) => setTimeout(r, 200));
|
|
91
|
+
}
|
|
92
|
+
if (isRunning(pid)) {
|
|
93
|
+
try {
|
|
94
|
+
process.kill(pid, "SIGKILL");
|
|
95
|
+
} catch {
|
|
96
|
+
// ignore
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (isRunning(pid)) {
|
|
100
|
+
console.error(`failed to stop ${name} (pid=${pid})`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function parseMode(raw) {
|
|
105
|
+
const mode = String(raw || "local").trim().toLowerCase();
|
|
106
|
+
if (mode === "lan" || mode === "global-preview" || mode === "local") return mode;
|
|
107
|
+
return "local";
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function adapterForMode(mode) {
|
|
111
|
+
if (mode === "lan") return "real-preview";
|
|
112
|
+
if (mode === "global-preview") return "webrtc-preview";
|
|
113
|
+
return "local-event-bus";
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function parseUrlHostPort(url) {
|
|
117
|
+
try {
|
|
118
|
+
const u = new URL(url);
|
|
119
|
+
return {
|
|
120
|
+
host: u.hostname || "",
|
|
121
|
+
port: Number(u.port || 4510),
|
|
122
|
+
};
|
|
123
|
+
} catch {
|
|
124
|
+
return { host: "", port: 4510 };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function spawnBackground(command, args, env, logFile, pidFile) {
|
|
129
|
+
const outFd = openSync(logFile, "a");
|
|
130
|
+
const child = spawn(command, args, {
|
|
131
|
+
cwd: APP_DIR,
|
|
132
|
+
env: { ...process.env, ...env },
|
|
133
|
+
detached: true,
|
|
134
|
+
stdio: ["ignore", outFd, outFd],
|
|
135
|
+
});
|
|
136
|
+
child.unref();
|
|
137
|
+
writeFileSync(pidFile, String(child.pid));
|
|
138
|
+
return child.pid;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function writeState(state) {
|
|
142
|
+
ensureStateDir();
|
|
143
|
+
writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function readState() {
|
|
147
|
+
if (!existsSync(STATE_FILE)) return null;
|
|
148
|
+
try {
|
|
149
|
+
return JSON.parse(readFileSync(STATE_FILE, "utf8"));
|
|
150
|
+
} catch {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function printHelp() {
|
|
156
|
+
console.log(`
|
|
157
|
+
SilicaClaw Gateway
|
|
158
|
+
|
|
159
|
+
Usage:
|
|
160
|
+
silicaclaw gateway start [--mode=local|lan|global-preview] [--signaling-url=http://host:4510] [--room=silicaclaw-demo]
|
|
161
|
+
silicaclaw gateway stop
|
|
162
|
+
silicaclaw gateway restart [--mode=...]
|
|
163
|
+
silicaclaw gateway status
|
|
164
|
+
silicaclaw gateway logs [local-console|signaling]
|
|
165
|
+
|
|
166
|
+
Notes:
|
|
167
|
+
- Default app dir: current directory; fallback: ~/silicaclaw
|
|
168
|
+
- State dir: .silicaclaw/gateway
|
|
169
|
+
- global-preview + localhost signaling URL will auto-start signaling server
|
|
170
|
+
`.trim());
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function showStatus() {
|
|
174
|
+
const localPid = readPid(CONSOLE_PID_FILE);
|
|
175
|
+
const sigPid = readPid(SIGNALING_PID_FILE);
|
|
176
|
+
const state = readState();
|
|
177
|
+
const payload = {
|
|
178
|
+
app_dir: APP_DIR,
|
|
179
|
+
mode: state?.mode || "unknown",
|
|
180
|
+
adapter: state?.adapter || "unknown",
|
|
181
|
+
local_console: {
|
|
182
|
+
pid: localPid,
|
|
183
|
+
running: isRunning(localPid),
|
|
184
|
+
log_file: CONSOLE_LOG_FILE,
|
|
185
|
+
},
|
|
186
|
+
signaling: {
|
|
187
|
+
pid: sigPid,
|
|
188
|
+
running: isRunning(sigPid),
|
|
189
|
+
log_file: SIGNALING_LOG_FILE,
|
|
190
|
+
url: state?.signaling_url || null,
|
|
191
|
+
room: state?.room || null,
|
|
192
|
+
},
|
|
193
|
+
updated_at: state?.updated_at || null,
|
|
194
|
+
};
|
|
195
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function tailFile(file, lines = 80) {
|
|
199
|
+
if (!existsSync(file)) {
|
|
200
|
+
console.log(`log file not found: ${file}`);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const text = String(readFileSync(file, "utf8"));
|
|
204
|
+
const out = text.split(/\r?\n/).slice(-lines).join("\n");
|
|
205
|
+
console.log(out);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
async function stopAll() {
|
|
209
|
+
const localPid = readPid(CONSOLE_PID_FILE);
|
|
210
|
+
const sigPid = readPid(SIGNALING_PID_FILE);
|
|
211
|
+
await stopPid(localPid, "local-console");
|
|
212
|
+
await stopPid(sigPid, "signaling");
|
|
213
|
+
removeFileIfExists(CONSOLE_PID_FILE);
|
|
214
|
+
removeFileIfExists(SIGNALING_PID_FILE);
|
|
215
|
+
writeState({
|
|
216
|
+
...(readState() || {}),
|
|
217
|
+
updated_at: Date.now(),
|
|
218
|
+
});
|
|
219
|
+
console.log("gateway stopped");
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function startAll() {
|
|
223
|
+
ensureStateDir();
|
|
224
|
+
|
|
225
|
+
const mode = parseMode(parseFlag("mode", process.env.NETWORK_MODE || "local"));
|
|
226
|
+
const adapter = adapterForMode(mode);
|
|
227
|
+
const signalingUrl = parseFlag("signaling-url", process.env.WEBRTC_SIGNALING_URL || "http://localhost:4510");
|
|
228
|
+
const room = parseFlag("room", process.env.WEBRTC_ROOM || "silicaclaw-demo");
|
|
229
|
+
const shouldDisableSignaling = hasFlag("no-signaling");
|
|
230
|
+
|
|
231
|
+
const currentLocalPid = readPid(CONSOLE_PID_FILE);
|
|
232
|
+
const currentSigPid = readPid(SIGNALING_PID_FILE);
|
|
233
|
+
if (isRunning(currentLocalPid)) {
|
|
234
|
+
console.log(`local-console already running (pid=${currentLocalPid})`);
|
|
235
|
+
} else {
|
|
236
|
+
removeFileIfExists(CONSOLE_PID_FILE);
|
|
237
|
+
const env = {
|
|
238
|
+
NETWORK_ADAPTER: adapter,
|
|
239
|
+
NETWORK_MODE: mode,
|
|
240
|
+
WEBRTC_SIGNALING_URL: signalingUrl,
|
|
241
|
+
WEBRTC_ROOM: room,
|
|
242
|
+
};
|
|
243
|
+
const pid = spawnBackground("npm", ["run", "local-console"], env, CONSOLE_LOG_FILE, CONSOLE_PID_FILE);
|
|
244
|
+
console.log(`local-console started (pid=${pid})`);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const { host, port } = parseUrlHostPort(signalingUrl);
|
|
248
|
+
const shouldAutoStartSignaling =
|
|
249
|
+
mode === "global-preview" &&
|
|
250
|
+
!shouldDisableSignaling &&
|
|
251
|
+
(host === "localhost" || host === "127.0.0.1");
|
|
252
|
+
|
|
253
|
+
if (shouldAutoStartSignaling) {
|
|
254
|
+
if (isRunning(currentSigPid)) {
|
|
255
|
+
console.log(`signaling already running (pid=${currentSigPid})`);
|
|
256
|
+
} else {
|
|
257
|
+
removeFileIfExists(SIGNALING_PID_FILE);
|
|
258
|
+
const pid = spawnBackground(
|
|
259
|
+
"npm",
|
|
260
|
+
["run", "webrtc-signaling"],
|
|
261
|
+
{ PORT: String(port) },
|
|
262
|
+
SIGNALING_LOG_FILE,
|
|
263
|
+
SIGNALING_PID_FILE,
|
|
264
|
+
);
|
|
265
|
+
console.log(`signaling started (pid=${pid}, port=${port})`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
writeState({
|
|
270
|
+
app_dir: APP_DIR,
|
|
271
|
+
mode,
|
|
272
|
+
adapter,
|
|
273
|
+
signaling_url: signalingUrl,
|
|
274
|
+
room,
|
|
275
|
+
updated_at: Date.now(),
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async function main() {
|
|
280
|
+
if (cmd === "help" || cmd === "-h" || cmd === "--help") {
|
|
281
|
+
printHelp();
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (cmd === "status") {
|
|
285
|
+
showStatus();
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (cmd === "start") {
|
|
289
|
+
startAll();
|
|
290
|
+
showStatus();
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
if (cmd === "stop") {
|
|
294
|
+
await stopAll();
|
|
295
|
+
showStatus();
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (cmd === "restart") {
|
|
299
|
+
await stopAll();
|
|
300
|
+
startAll();
|
|
301
|
+
showStatus();
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
if (cmd === "logs") {
|
|
305
|
+
const target = String(argv[1] || "local-console");
|
|
306
|
+
if (target === "signaling") {
|
|
307
|
+
tailFile(SIGNALING_LOG_FILE);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
tailFile(CONSOLE_LOG_FILE);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
printHelp();
|
|
314
|
+
process.exitCode = 1;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
main().catch((error) => {
|
|
318
|
+
console.error(error?.message || String(error));
|
|
319
|
+
process.exit(1);
|
|
320
|
+
});
|
|
321
|
+
|