nextclaw 0.4.13 → 0.4.15
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/dist/cli/index.js
CHANGED
|
@@ -81,7 +81,7 @@ import {
|
|
|
81
81
|
import { existsSync, mkdirSync, readFileSync, writeFileSync, rmSync } from "fs";
|
|
82
82
|
import { join, resolve } from "path";
|
|
83
83
|
import { spawn } from "child_process";
|
|
84
|
-
import { createServer } from "net";
|
|
84
|
+
import { createServer, isIP } from "net";
|
|
85
85
|
import { fileURLToPath } from "url";
|
|
86
86
|
import { getDataDir, getPackageVersion as getCorePackageVersion } from "@nextclaw/core";
|
|
87
87
|
function resolveUiConfig(config2, overrides) {
|
|
@@ -92,6 +92,41 @@ function resolveUiApiBase(host, port) {
|
|
|
92
92
|
const normalizedHost = host === "0.0.0.0" || host === "::" ? "127.0.0.1" : host;
|
|
93
93
|
return `http://${normalizedHost}:${port}`;
|
|
94
94
|
}
|
|
95
|
+
function isLoopbackHost(host) {
|
|
96
|
+
const normalized = host.trim().toLowerCase();
|
|
97
|
+
return normalized === "127.0.0.1" || normalized === "localhost" || normalized === "::1";
|
|
98
|
+
}
|
|
99
|
+
var PUBLIC_IP_CHECK_URLS = ["https://api.ipify.org", "https://ifconfig.me/ip"];
|
|
100
|
+
async function fetchPublicIpFrom(url, timeoutMs) {
|
|
101
|
+
const controller = new AbortController();
|
|
102
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
103
|
+
try {
|
|
104
|
+
const response = await fetch(url, {
|
|
105
|
+
signal: controller.signal,
|
|
106
|
+
headers: {
|
|
107
|
+
Accept: "text/plain"
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
if (!response.ok) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const text = (await response.text()).trim();
|
|
114
|
+
return isIP(text) ? text : null;
|
|
115
|
+
} catch {
|
|
116
|
+
return null;
|
|
117
|
+
} finally {
|
|
118
|
+
clearTimeout(timer);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async function resolvePublicIp(timeoutMs = 1500) {
|
|
122
|
+
for (const endpoint of PUBLIC_IP_CHECK_URLS) {
|
|
123
|
+
const candidate = await fetchPublicIpFrom(endpoint, timeoutMs);
|
|
124
|
+
if (candidate) {
|
|
125
|
+
return candidate;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
95
130
|
function isDevRuntime() {
|
|
96
131
|
return import.meta.url.includes("/src/cli/") || process.env.NEXTCLAW_DEV === "1";
|
|
97
132
|
}
|
|
@@ -989,6 +1024,12 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
989
1024
|
if (opts.uiOpen) {
|
|
990
1025
|
uiOverrides.open = true;
|
|
991
1026
|
}
|
|
1027
|
+
if (opts.public) {
|
|
1028
|
+
uiOverrides.enabled = true;
|
|
1029
|
+
if (!opts.uiHost) {
|
|
1030
|
+
uiOverrides.host = "0.0.0.0";
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
992
1033
|
await this.startGateway({ uiOverrides });
|
|
993
1034
|
}
|
|
994
1035
|
async ui(opts) {
|
|
@@ -1002,6 +1043,9 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1002
1043
|
if (opts.port) {
|
|
1003
1044
|
uiOverrides.port = Number(opts.port);
|
|
1004
1045
|
}
|
|
1046
|
+
if (opts.public && !opts.host) {
|
|
1047
|
+
uiOverrides.host = "0.0.0.0";
|
|
1048
|
+
}
|
|
1005
1049
|
await this.startGateway({ uiOverrides, allowMissingProvider: true });
|
|
1006
1050
|
}
|
|
1007
1051
|
async start(opts) {
|
|
@@ -1016,6 +1060,9 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1016
1060
|
if (opts.uiPort) {
|
|
1017
1061
|
uiOverrides.port = Number(opts.uiPort);
|
|
1018
1062
|
}
|
|
1063
|
+
if (opts.public && !opts.uiHost) {
|
|
1064
|
+
uiOverrides.host = "0.0.0.0";
|
|
1065
|
+
}
|
|
1019
1066
|
const devMode = isDevRuntime();
|
|
1020
1067
|
if (devMode) {
|
|
1021
1068
|
const requestedUiPort = Number.isFinite(Number(opts.uiPort)) ? Number(opts.uiPort) : 18792;
|
|
@@ -1048,6 +1095,19 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1048
1095
|
open: Boolean(opts.open)
|
|
1049
1096
|
});
|
|
1050
1097
|
}
|
|
1098
|
+
async restart(opts) {
|
|
1099
|
+
const state = readServiceState();
|
|
1100
|
+
if (state && isProcessRunning(state.pid)) {
|
|
1101
|
+
console.log(`Restarting ${APP_NAME}...`);
|
|
1102
|
+
await this.stopService();
|
|
1103
|
+
} else if (state) {
|
|
1104
|
+
clearServiceState();
|
|
1105
|
+
console.log("Service state was stale and has been cleaned up.");
|
|
1106
|
+
} else {
|
|
1107
|
+
console.log("No running service found. Starting a new service.");
|
|
1108
|
+
}
|
|
1109
|
+
await this.start(opts);
|
|
1110
|
+
}
|
|
1051
1111
|
async serve(opts) {
|
|
1052
1112
|
const uiOverrides = {
|
|
1053
1113
|
enabled: true,
|
|
@@ -1059,6 +1119,9 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
1059
1119
|
if (opts.uiPort) {
|
|
1060
1120
|
uiOverrides.port = Number(opts.uiPort);
|
|
1061
1121
|
}
|
|
1122
|
+
if (opts.public && !opts.uiHost) {
|
|
1123
|
+
uiOverrides.host = "0.0.0.0";
|
|
1124
|
+
}
|
|
1062
1125
|
const devMode = isDevRuntime();
|
|
1063
1126
|
if (devMode && uiOverrides.port === void 0) {
|
|
1064
1127
|
uiOverrides.port = 18792;
|
|
@@ -2091,6 +2154,20 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
2091
2154
|
setPluginRuntimeBridge(null);
|
|
2092
2155
|
}
|
|
2093
2156
|
}
|
|
2157
|
+
async printPublicUiUrls(host, port) {
|
|
2158
|
+
if (isLoopbackHost(host)) {
|
|
2159
|
+
console.log('Public URL: disabled (UI host is loopback). Use "--public" or "--ui-host 0.0.0.0" to expose it.');
|
|
2160
|
+
return;
|
|
2161
|
+
}
|
|
2162
|
+
const publicIp = await resolvePublicIp();
|
|
2163
|
+
if (!publicIp) {
|
|
2164
|
+
console.log("Public URL: UI is exposed, but automatic public IP detection failed.");
|
|
2165
|
+
return;
|
|
2166
|
+
}
|
|
2167
|
+
const publicBase = `http://${publicIp}:${port}`;
|
|
2168
|
+
console.log(`Public UI (if firewall/NAT allows): ${publicBase}`);
|
|
2169
|
+
console.log(`Public API (if firewall/NAT allows): ${publicBase}/api`);
|
|
2170
|
+
}
|
|
2094
2171
|
startUiIfEnabled(uiConfig, uiStaticDir) {
|
|
2095
2172
|
if (!uiConfig.enabled) {
|
|
2096
2173
|
return;
|
|
@@ -2106,6 +2183,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
2106
2183
|
if (uiStaticDir) {
|
|
2107
2184
|
console.log(`\u2713 UI frontend: ${uiUrl}`);
|
|
2108
2185
|
}
|
|
2186
|
+
void this.printPublicUiUrls(uiServer.host, uiServer.port);
|
|
2109
2187
|
if (uiConfig.open) {
|
|
2110
2188
|
openBrowser(uiUrl);
|
|
2111
2189
|
}
|
|
@@ -2196,6 +2274,7 @@ ${this.logo} ${APP_NAME} is ready! (${source})`);
|
|
|
2196
2274
|
console.log(`\u2713 ${APP_NAME} started in background (PID ${state.pid})`);
|
|
2197
2275
|
console.log(`UI: ${uiUrl}`);
|
|
2198
2276
|
console.log(`API: ${apiUrl}`);
|
|
2277
|
+
await this.printPublicUiUrls(uiConfig.host, uiConfig.port);
|
|
2199
2278
|
console.log(`Logs: ${logPath}`);
|
|
2200
2279
|
console.log(`Stop: ${APP_NAME} stop`);
|
|
2201
2280
|
if (options.open) {
|
|
@@ -2467,10 +2546,11 @@ var runtime = new CliRuntime({ logo: LOGO });
|
|
|
2467
2546
|
program.name(APP_NAME2).description(`${LOGO} ${APP_NAME2} - ${APP_TAGLINE}`).version(getPackageVersion(), "-v, --version", "show version");
|
|
2468
2547
|
program.command("onboard").description(`Initialize ${APP_NAME2} configuration and workspace`).action(async () => runtime.onboard());
|
|
2469
2548
|
program.command("init").description(`Initialize ${APP_NAME2} configuration and workspace`).option("-f, --force", "Overwrite existing template files").action(async (opts) => runtime.init({ force: Boolean(opts.force) }));
|
|
2470
|
-
program.command("gateway").description(`Start the ${APP_NAME2} gateway`).option("-p, --port <port>", "Gateway port", "18790").option("-v, --verbose", "Verbose output", false).option("--ui", "Enable UI server", false).option("--ui-host <host>", "UI host").option("--ui-port <port>", "UI port").option("--ui-open", "Open browser when UI starts", false).action(async (opts) => runtime.gateway(opts));
|
|
2471
|
-
program.command("ui").description(`Start the ${APP_NAME2} UI with gateway`).option("--host <host>", "UI host").option("--port <port>", "UI port").option("--no-open", "Disable opening browser").action(async (opts) => runtime.ui(opts));
|
|
2472
|
-
program.command("start").description(`Start the ${APP_NAME2} gateway + UI in the background`).option("--ui-host <host>", "UI host").option("--ui-port <port>", "UI port").option("--frontend", "Start UI frontend dev server").option("--frontend-port <port>", "UI frontend dev server port").option("--open", "Open browser after start", false).action(async (opts) => runtime.start(opts));
|
|
2473
|
-
program.command("
|
|
2549
|
+
program.command("gateway").description(`Start the ${APP_NAME2} gateway`).option("-p, --port <port>", "Gateway port", "18790").option("-v, --verbose", "Verbose output", false).option("--ui", "Enable UI server", false).option("--ui-host <host>", "UI host").option("--ui-port <port>", "UI port").option("--ui-open", "Open browser when UI starts", false).option("--public", "Expose UI on 0.0.0.0 and print public URL", false).action(async (opts) => runtime.gateway(opts));
|
|
2550
|
+
program.command("ui").description(`Start the ${APP_NAME2} UI with gateway`).option("--host <host>", "UI host").option("--port <port>", "UI port").option("--no-open", "Disable opening browser").option("--public", "Expose UI on 0.0.0.0 and print public URL", false).action(async (opts) => runtime.ui(opts));
|
|
2551
|
+
program.command("start").description(`Start the ${APP_NAME2} gateway + UI in the background`).option("--ui-host <host>", "UI host").option("--ui-port <port>", "UI port").option("--frontend", "Start UI frontend dev server").option("--frontend-port <port>", "UI frontend dev server port").option("--open", "Open browser after start", false).option("--public", "Expose UI on 0.0.0.0 and print public URL", false).action(async (opts) => runtime.start(opts));
|
|
2552
|
+
program.command("restart").description(`Restart the ${APP_NAME2} background service`).option("--ui-host <host>", "UI host").option("--ui-port <port>", "UI port").option("--frontend", "Start UI frontend dev server").option("--frontend-port <port>", "UI frontend dev server port").option("--open", "Open browser after restart", false).option("--public", "Expose UI on 0.0.0.0 and print public URL", false).action(async (opts) => runtime.restart(opts));
|
|
2553
|
+
program.command("serve").description(`Run the ${APP_NAME2} gateway + UI in the foreground`).option("--ui-host <host>", "UI host").option("--ui-port <port>", "UI port").option("--frontend", "Start UI frontend dev server").option("--frontend-port <port>", "UI frontend dev server port").option("--open", "Open browser after start", false).option("--public", "Expose UI on 0.0.0.0 and print public URL", false).action(async (opts) => runtime.serve(opts));
|
|
2474
2554
|
program.command("stop").description(`Stop the ${APP_NAME2} background service`).action(async () => runtime.stop());
|
|
2475
2555
|
program.command("agent").description("Interact with the agent directly").option("-m, --message <message>", "Message to send to the agent").option("-s, --session <session>", "Session ID", "cli:default").option("--no-markdown", "Disable Markdown rendering").action(async (opts) => runtime.agent(opts));
|
|
2476
2556
|
program.command("update").description(`Update ${APP_NAME2}`).option("--timeout <ms>", "Update command timeout in milliseconds").action(async (opts) => runtime.update(opts));
|