clawcrib 0.1.0 → 0.1.2
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/bin/clawcrib.mjs +415 -34
- package/dist/.next/BUILD_ID +1 -1
- package/dist/.next/build-manifest.json +2 -2
- package/dist/.next/server/app/_global-error.html +2 -2
- package/dist/.next/server/app/_global-error.rsc +1 -1
- package/dist/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/dist/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/.next/server/app/_not-found.html +2 -2
- package/dist/.next/server/app/_not-found.rsc +1 -1
- package/dist/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/.next/server/app/browse.html +2 -2
- package/dist/.next/server/app/browse.rsc +1 -1
- package/dist/.next/server/app/browse.segments/_full.segment.rsc +1 -1
- package/dist/.next/server/app/browse.segments/_head.segment.rsc +1 -1
- package/dist/.next/server/app/browse.segments/_index.segment.rsc +1 -1
- package/dist/.next/server/app/browse.segments/_tree.segment.rsc +1 -1
- package/dist/.next/server/app/browse.segments/browse/__PAGE__.segment.rsc +1 -1
- package/dist/.next/server/app/browse.segments/browse.segment.rsc +1 -1
- package/dist/.next/server/app/builder.html +2 -2
- package/dist/.next/server/app/builder.rsc +1 -1
- package/dist/.next/server/app/builder.segments/_full.segment.rsc +1 -1
- package/dist/.next/server/app/builder.segments/_head.segment.rsc +1 -1
- package/dist/.next/server/app/builder.segments/_index.segment.rsc +1 -1
- package/dist/.next/server/app/builder.segments/_tree.segment.rsc +1 -1
- package/dist/.next/server/app/builder.segments/builder/__PAGE__.segment.rsc +1 -1
- package/dist/.next/server/app/builder.segments/builder.segment.rsc +1 -1
- package/dist/.next/server/app/crib.html +1 -1
- package/dist/.next/server/app/crib.rsc +1 -1
- package/dist/.next/server/app/crib.segments/_full.segment.rsc +1 -1
- package/dist/.next/server/app/crib.segments/_head.segment.rsc +1 -1
- package/dist/.next/server/app/crib.segments/_index.segment.rsc +1 -1
- package/dist/.next/server/app/crib.segments/_tree.segment.rsc +1 -1
- package/dist/.next/server/app/crib.segments/crib/__PAGE__.segment.rsc +1 -1
- package/dist/.next/server/app/crib.segments/crib.segment.rsc +1 -1
- package/dist/.next/server/app/demo.html +1 -1
- package/dist/.next/server/app/demo.rsc +1 -1
- package/dist/.next/server/app/demo.segments/_full.segment.rsc +1 -1
- package/dist/.next/server/app/demo.segments/_head.segment.rsc +1 -1
- package/dist/.next/server/app/demo.segments/_index.segment.rsc +1 -1
- package/dist/.next/server/app/demo.segments/_tree.segment.rsc +1 -1
- package/dist/.next/server/app/demo.segments/demo/__PAGE__.segment.rsc +1 -1
- package/dist/.next/server/app/demo.segments/demo.segment.rsc +1 -1
- package/dist/.next/server/app/feedback.html +2 -2
- package/dist/.next/server/app/feedback.rsc +1 -1
- package/dist/.next/server/app/feedback.segments/_full.segment.rsc +1 -1
- package/dist/.next/server/app/feedback.segments/_head.segment.rsc +1 -1
- package/dist/.next/server/app/feedback.segments/_index.segment.rsc +1 -1
- package/dist/.next/server/app/feedback.segments/_tree.segment.rsc +1 -1
- package/dist/.next/server/app/feedback.segments/feedback/__PAGE__.segment.rsc +1 -1
- package/dist/.next/server/app/feedback.segments/feedback.segment.rsc +1 -1
- package/dist/.next/server/app/gltest.html +1 -1
- package/dist/.next/server/app/gltest.rsc +1 -1
- package/dist/.next/server/app/gltest.segments/_full.segment.rsc +1 -1
- package/dist/.next/server/app/gltest.segments/_head.segment.rsc +1 -1
- package/dist/.next/server/app/gltest.segments/_index.segment.rsc +1 -1
- package/dist/.next/server/app/gltest.segments/_tree.segment.rsc +1 -1
- package/dist/.next/server/app/gltest.segments/gltest/__PAGE__.segment.rsc +1 -1
- package/dist/.next/server/app/gltest.segments/gltest.segment.rsc +1 -1
- package/dist/.next/server/app/help.html +2 -2
- package/dist/.next/server/app/help.rsc +1 -1
- package/dist/.next/server/app/help.segments/_full.segment.rsc +1 -1
- package/dist/.next/server/app/help.segments/_head.segment.rsc +1 -1
- package/dist/.next/server/app/help.segments/_index.segment.rsc +1 -1
- package/dist/.next/server/app/help.segments/_tree.segment.rsc +1 -1
- package/dist/.next/server/app/help.segments/help/__PAGE__.segment.rsc +1 -1
- package/dist/.next/server/app/help.segments/help.segment.rsc +1 -1
- package/dist/.next/server/app/index.html +1 -1
- package/dist/.next/server/app/index.rsc +2 -2
- package/dist/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/.next/server/app/index.segments/_full.segment.rsc +2 -2
- package/dist/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/.next/server/app/learn.html +2 -2
- package/dist/.next/server/app/learn.rsc +1 -1
- package/dist/.next/server/app/learn.segments/_full.segment.rsc +1 -1
- package/dist/.next/server/app/learn.segments/_head.segment.rsc +1 -1
- package/dist/.next/server/app/learn.segments/_index.segment.rsc +1 -1
- package/dist/.next/server/app/learn.segments/_tree.segment.rsc +1 -1
- package/dist/.next/server/app/learn.segments/learn/__PAGE__.segment.rsc +1 -1
- package/dist/.next/server/app/learn.segments/learn.segment.rsc +1 -1
- package/dist/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/.next/server/app/privacy.html +2 -2
- package/dist/.next/server/app/privacy.rsc +1 -1
- package/dist/.next/server/app/privacy.segments/_full.segment.rsc +1 -1
- package/dist/.next/server/app/privacy.segments/_head.segment.rsc +1 -1
- package/dist/.next/server/app/privacy.segments/_index.segment.rsc +1 -1
- package/dist/.next/server/app/privacy.segments/_tree.segment.rsc +1 -1
- package/dist/.next/server/app/privacy.segments/privacy/__PAGE__.segment.rsc +1 -1
- package/dist/.next/server/app/privacy.segments/privacy.segment.rsc +1 -1
- package/dist/.next/server/app/terms.html +2 -2
- package/dist/.next/server/app/terms.rsc +1 -1
- package/dist/.next/server/app/terms.segments/_full.segment.rsc +1 -1
- package/dist/.next/server/app/terms.segments/_head.segment.rsc +1 -1
- package/dist/.next/server/app/terms.segments/_index.segment.rsc +1 -1
- package/dist/.next/server/app/terms.segments/_tree.segment.rsc +1 -1
- package/dist/.next/server/app/terms.segments/terms/__PAGE__.segment.rsc +1 -1
- package/dist/.next/server/app/terms.segments/terms.segment.rsc +1 -1
- package/dist/.next/server/chunks/ssr/_a46dee72._.js +1 -1
- package/dist/.next/server/middleware-manifest.json +1 -1
- package/dist/.next/server/pages/404.html +2 -2
- package/dist/.next/server/pages/500.html +2 -2
- package/dist/.next/static/chunks/d6211ae3ff8400ff.js +1 -0
- package/package.json +1 -1
- package/dist/.next/static/chunks/46b6f1723e3c2623.js +0 -1
- /package/dist/.next/static/{LDs2QlURjFsxe6doQgQaH → zYUlp2fcVlJKBhUQk1Pns}/_buildManifest.js +0 -0
- /package/dist/.next/static/{LDs2QlURjFsxe6doQgQaH → zYUlp2fcVlJKBhUQk1Pns}/_clientMiddlewareManifest.json +0 -0
- /package/dist/.next/static/{LDs2QlURjFsxe6doQgQaH → zYUlp2fcVlJKBhUQk1Pns}/_ssgManifest.js +0 -0
package/bin/clawcrib.mjs
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
|
-
import { existsSync } from "node:fs";
|
|
4
|
+
import { existsSync, mkdirSync, openSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
|
+
import net from "node:net";
|
|
7
|
+
import os from "node:os";
|
|
6
8
|
import path from "node:path";
|
|
7
9
|
import { fileURLToPath } from "node:url";
|
|
8
10
|
|
|
@@ -14,24 +16,46 @@ const HELP = `
|
|
|
14
16
|
ClawCrib — the live 3D office for your OpenClaw agents
|
|
15
17
|
|
|
16
18
|
Usage
|
|
17
|
-
npx clawcrib [options]
|
|
19
|
+
npx clawcrib [command] [options]
|
|
20
|
+
|
|
21
|
+
Commands
|
|
22
|
+
(none) Run in the foreground until you press Ctrl-C
|
|
23
|
+
start Run in the background; survives closing the terminal
|
|
24
|
+
stop Stop the background instance
|
|
25
|
+
restart Stop, then start
|
|
26
|
+
status Is it running, and is it responding?
|
|
27
|
+
install-service Keep it running across reboots (systemd / launchd)
|
|
28
|
+
uninstall-service Remove that service file
|
|
18
29
|
|
|
19
30
|
Options
|
|
20
31
|
-p, --port <port> Port to listen on (default: 18787)
|
|
21
32
|
-g, --gateway <url> OpenClaw gateway WebSocket URL (e.g. ws://127.0.0.1:18789)
|
|
22
33
|
-t, --token <token> Gateway auth token
|
|
23
|
-
--host <host> Host to bind (default: 127.0.0.1
|
|
34
|
+
--host <host> Host to bind (default: 127.0.0.1 — use 0.0.0.0 to
|
|
35
|
+
reach it from another machine over LAN/SSH)
|
|
24
36
|
--no-open Don't open the browser
|
|
37
|
+
--demo Force the simulated team, even if a gateway is found
|
|
25
38
|
-v, --version Print version
|
|
26
39
|
-h, --help Show this help
|
|
27
40
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
A gateway on this machine (127.0.0.1:18789) is detected and connected
|
|
42
|
+
automatically — you only need --gateway for a remote one. With no gateway
|
|
43
|
+
anywhere, ClawCrib shows a simulated team so the floor is never empty.
|
|
44
|
+
Over SSH the bind defaults to 0.0.0.0 so you can reach it from your laptop.
|
|
45
|
+
OPENCLAW_GATEWAY_URL / OPENCLAW_GATEWAY_TOKEN are honored too.
|
|
31
46
|
`;
|
|
32
47
|
|
|
48
|
+
const COMMANDS = new Set(["start", "stop", "restart", "status", "install-service", "uninstall-service"]);
|
|
49
|
+
|
|
50
|
+
// Reached over SSH, a loopback bind is useless — the dashboard is only visible
|
|
51
|
+
// from inside the box you are already tunnelling into. Default to all
|
|
52
|
+
// interfaces there so `clawcrib start` just works; an explicit --host wins.
|
|
53
|
+
const OVER_SSH = Boolean(process.env.SSH_CONNECTION || process.env.SSH_TTY || process.env.SSH_CLIENT);
|
|
54
|
+
|
|
33
55
|
function parseArgs(argv) {
|
|
34
|
-
const opts = { port: 18787, host: "127.0.0.1", open: true, gateway: null, token: null };
|
|
56
|
+
const opts = { port: 18787, host: "127.0.0.1", open: true, gateway: null, token: null, cmd: "run", hostAuto: false, demo: false };
|
|
57
|
+
if (argv.length && COMMANDS.has(argv[0])) opts.cmd = argv.shift();
|
|
58
|
+
let hostGiven = false;
|
|
35
59
|
for (let i = 0; i < argv.length; i++) {
|
|
36
60
|
const a = argv[i];
|
|
37
61
|
switch (a) {
|
|
@@ -49,10 +73,14 @@ function parseArgs(argv) {
|
|
|
49
73
|
break;
|
|
50
74
|
case "--host":
|
|
51
75
|
opts.host = argv[++i];
|
|
76
|
+
hostGiven = true;
|
|
52
77
|
break;
|
|
53
78
|
case "--no-open":
|
|
54
79
|
opts.open = false;
|
|
55
80
|
break;
|
|
81
|
+
case "--demo":
|
|
82
|
+
opts.demo = true;
|
|
83
|
+
break;
|
|
56
84
|
case "-v":
|
|
57
85
|
case "--version":
|
|
58
86
|
console.log(pkg.version);
|
|
@@ -72,6 +100,10 @@ function parseArgs(argv) {
|
|
|
72
100
|
console.error("Invalid --port");
|
|
73
101
|
process.exit(1);
|
|
74
102
|
}
|
|
103
|
+
if (!hostGiven && OVER_SSH) {
|
|
104
|
+
opts.host = "0.0.0.0";
|
|
105
|
+
opts.hostAuto = true;
|
|
106
|
+
}
|
|
75
107
|
return opts;
|
|
76
108
|
}
|
|
77
109
|
|
|
@@ -112,38 +144,387 @@ const env = {
|
|
|
112
144
|
// tells the app it is a self-hosted dashboard, not the marketing site:
|
|
113
145
|
// the office is served at / and the website-only pages 404 (src/middleware.ts)
|
|
114
146
|
CLAWCRIB_APP: "1",
|
|
147
|
+
// a transitive dep still calls util._extend; the DEP0060 notice reads like a
|
|
148
|
+
// crash to someone running this for the first time and it is not actionable
|
|
149
|
+
NODE_OPTIONS: [process.env.NODE_OPTIONS, "--no-deprecation"].filter(Boolean).join(" "),
|
|
115
150
|
};
|
|
116
151
|
if (opts.gateway) env.OPENCLAW_GATEWAY_URL = opts.gateway;
|
|
117
152
|
if (opts.token) env.OPENCLAW_GATEWAY_TOKEN = opts.token;
|
|
118
153
|
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
154
|
+
const LOOPBACK = new Set(["127.0.0.1", "localhost", "::1"]);
|
|
155
|
+
const GATEWAY_PORT = 18789;
|
|
156
|
+
|
|
157
|
+
// The gateway almost always runs on the same box as the crib, so probe for a
|
|
158
|
+
// listener and say so rather than leaving someone in demo mode wondering why.
|
|
159
|
+
// TCP connect only: this never opens a session, so no device-pairing request
|
|
160
|
+
// is raised on the gateway.
|
|
161
|
+
function probePort(host, port, timeoutMs = 700) {
|
|
162
|
+
return new Promise((resolve) => {
|
|
163
|
+
const sock = net.connect({ host, port });
|
|
164
|
+
const finish = (ok) => {
|
|
165
|
+
sock.destroy();
|
|
166
|
+
resolve(ok);
|
|
167
|
+
};
|
|
168
|
+
sock.setTimeout(timeoutMs);
|
|
169
|
+
sock.once("connect", () => finish(true));
|
|
170
|
+
sock.once("timeout", () => finish(false));
|
|
171
|
+
sock.once("error", () => finish(false));
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// first non-internal IPv4, so a remote box can print a URL you can actually open
|
|
176
|
+
function lanAddress() {
|
|
177
|
+
for (const ifaces of Object.values(os.networkInterfaces())) {
|
|
178
|
+
for (const i of ifaces ?? []) {
|
|
179
|
+
if (i.family === "IPv4" && !i.internal) return i.address;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Must stay in step with device-identity.ts / api/crib/profiles: keyed off the
|
|
186
|
+
// user's home, never cwd (under npx the cwd is a throwaway cache directory).
|
|
187
|
+
const CONFIG_DIR = process.env.CLAWCRIB_CONFIG_DIR || path.join(os.homedir(), ".clawcrib");
|
|
188
|
+
const PID_FILE = path.join(CONFIG_DIR, "clawcrib.pid");
|
|
189
|
+
const LOG_FILE = path.join(CONFIG_DIR, "clawcrib.log");
|
|
190
|
+
|
|
191
|
+
// Health checks always go to loopback, but what we *print* when bound to all
|
|
192
|
+
// interfaces must be the address another machine can actually open. Printing
|
|
193
|
+
// "localhost" there is worse than useless: it is the one URL that cannot work
|
|
194
|
+
// from anywhere else.
|
|
195
|
+
const healthUrl = `http://${opts.host === "0.0.0.0" ? "127.0.0.1" : opts.host}:${opts.port}`;
|
|
196
|
+
const lanIp = lanAddress();
|
|
197
|
+
const url = opts.host === "0.0.0.0" && lanIp ? `http://${lanIp}:${opts.port}` : healthUrl;
|
|
198
|
+
let autoGateway = false;
|
|
199
|
+
|
|
200
|
+
// You installed this on the box your agents run on. Finding the gateway and
|
|
201
|
+
// then asking you to re-type its address is a step that exists for no reason —
|
|
202
|
+
// connect to it. `--demo` opts out, and an explicit --gateway always wins.
|
|
203
|
+
async function resolveGateway() {
|
|
204
|
+
if (env.OPENCLAW_GATEWAY_URL || opts.demo) return;
|
|
205
|
+
if (await probePort("127.0.0.1", GATEWAY_PORT)) {
|
|
206
|
+
env.OPENCLAW_GATEWAY_URL = `ws://127.0.0.1:${GATEWAY_PORT}`;
|
|
207
|
+
autoGateway = true;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function modeLine() {
|
|
212
|
+
if (!env.OPENCLAW_GATEWAY_URL) {
|
|
213
|
+
return opts.demo
|
|
214
|
+
? "demo mode (--demo)"
|
|
215
|
+
: "demo mode — no gateway found on this machine. Pass --gateway ws://host:18789 for a remote one.";
|
|
216
|
+
}
|
|
217
|
+
return autoGateway
|
|
218
|
+
? `live — auto-connected to the gateway on this machine (${env.OPENCLAW_GATEWAY_URL})`
|
|
219
|
+
: `live gateway: ${env.OPENCLAW_GATEWAY_URL}`;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const STATE_FILE = path.join(CONFIG_DIR, "clawcrib.json");
|
|
223
|
+
|
|
224
|
+
function readPid() {
|
|
225
|
+
try {
|
|
226
|
+
const pid = Number(readFileSync(PID_FILE, "utf8").trim());
|
|
227
|
+
// signal 0 tests for existence without touching the process
|
|
228
|
+
process.kill(pid, 0);
|
|
229
|
+
return pid;
|
|
230
|
+
} catch {
|
|
231
|
+
return null; // no pid file, or the process died without cleaning up
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// What the running instance was actually started with. Without this, `start`
|
|
236
|
+
// can only ask "is something alive?" and would report success while silently
|
|
237
|
+
// ignoring the --host/--port/--gateway you just asked for.
|
|
238
|
+
function readState() {
|
|
239
|
+
try {
|
|
240
|
+
return JSON.parse(readFileSync(STATE_FILE, "utf8"));
|
|
241
|
+
} catch {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function settingsDiffer(prev) {
|
|
247
|
+
if (!prev) return null;
|
|
248
|
+
const now = { host: opts.host, port: opts.port, gateway: env.OPENCLAW_GATEWAY_URL ?? null };
|
|
249
|
+
const changed = [];
|
|
250
|
+
if (prev.host !== now.host) changed.push(`host ${prev.host} → ${now.host}`);
|
|
251
|
+
if (prev.port !== now.port) changed.push(`port ${prev.port} → ${now.port}`);
|
|
252
|
+
if ((prev.gateway ?? null) !== now.gateway) changed.push(`gateway ${prev.gateway ?? "none"} → ${now.gateway ?? "none"}`);
|
|
253
|
+
return changed.length ? changed : null;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async function printDetails() {
|
|
257
|
+
if (LOOPBACK.has(opts.host)) {
|
|
258
|
+
console.log(` Note: bound to ${opts.host} — reachable only from this machine.`);
|
|
259
|
+
console.log(` For LAN/SSH access, use --host 0.0.0.0`);
|
|
260
|
+
if (lanIp) console.log(` then open http://${lanIp}:${opts.port}`);
|
|
261
|
+
} else if (opts.host === "0.0.0.0") {
|
|
262
|
+
if (opts.hostAuto) console.log(` Bind: 0.0.0.0 (auto: this is an SSH session — pass --host to override)`);
|
|
263
|
+
console.log(` Open: ${url} from another machine on this network`);
|
|
264
|
+
console.log(` Not loading? The port is probably firewalled:`);
|
|
265
|
+
console.log(` sudo ufw allow ${opts.port}/tcp # ufw`);
|
|
266
|
+
console.log(` sudo firewall-cmd --add-port=${opts.port}/tcp --permanent && sudo firewall-cmd --reload`);
|
|
267
|
+
}
|
|
268
|
+
if (autoGateway) {
|
|
269
|
+
console.log(` If the gateway asks to pair, approve it there:`);
|
|
270
|
+
console.log(` openclaw devices approve <requestId>`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function spawnServer(detached) {
|
|
275
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
276
|
+
const out = detached ? openSync(LOG_FILE, "a") : "pipe";
|
|
277
|
+
return spawn(process.execPath, [serverJs], {
|
|
278
|
+
cwd: path.dirname(serverJs),
|
|
279
|
+
env,
|
|
280
|
+
detached,
|
|
281
|
+
stdio: detached ? ["ignore", out, out] : ["ignore", "pipe", "inherit"],
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async function cmdStart() {
|
|
286
|
+
await resolveGateway();
|
|
287
|
+
const running = readPid();
|
|
288
|
+
if (running) {
|
|
289
|
+
const changed = settingsDiffer(readState());
|
|
290
|
+
if (!changed) {
|
|
291
|
+
console.log(`\n ClawCrib is already running (pid ${running}) at ${url}\n`);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
// You asked for different settings; honouring the old ones and calling it
|
|
295
|
+
// success is how "--host 0.0.0.0" silently did nothing.
|
|
296
|
+
console.log(`\n Restarting with new settings: ${changed.join(", ")}`);
|
|
297
|
+
await cmdStop();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// A clearer failure than Node's raw EADDRINUSE stack trace.
|
|
301
|
+
if (await probePort(opts.host === "0.0.0.0" ? "127.0.0.1" : opts.host, opts.port, 400)) {
|
|
302
|
+
console.error(
|
|
303
|
+
`\n Port ${opts.port} is already in use by something else.\n` +
|
|
304
|
+
` Free it, or pick another: clawcrib start --port 18788\n`
|
|
305
|
+
);
|
|
135
306
|
process.exit(1);
|
|
136
307
|
}
|
|
137
|
-
|
|
308
|
+
const child = spawnServer(true);
|
|
309
|
+
child.unref(); // survives this shell exiting
|
|
310
|
+
writeFileSync(PID_FILE, String(child.pid));
|
|
311
|
+
writeFileSync(
|
|
312
|
+
STATE_FILE,
|
|
313
|
+
JSON.stringify({ pid: child.pid, host: opts.host, port: opts.port, gateway: env.OPENCLAW_GATEWAY_URL ?? null })
|
|
314
|
+
);
|
|
315
|
+
if (!(await waitForServer(healthUrl))) {
|
|
316
|
+
console.error(`ClawCrib did not come up within 30s. Log: ${LOG_FILE}`);
|
|
317
|
+
try {
|
|
318
|
+
process.kill(child.pid);
|
|
319
|
+
} catch {
|
|
320
|
+
/* already gone */
|
|
321
|
+
}
|
|
322
|
+
rmSync(PID_FILE, { force: true });
|
|
323
|
+
process.exit(1);
|
|
324
|
+
}
|
|
325
|
+
console.log(`\n ClawCrib v${pkg.version} started in the background (pid ${child.pid})`);
|
|
138
326
|
console.log(` Crib: ${url}`);
|
|
139
|
-
console.log(` Mode: ${
|
|
140
|
-
|
|
141
|
-
});
|
|
327
|
+
console.log(` Mode: ${modeLine()}`);
|
|
328
|
+
await printDetails();
|
|
329
|
+
console.log(`\n Log: ${LOG_FILE}`);
|
|
330
|
+
console.log(` Stop: clawcrib stop\n`);
|
|
331
|
+
}
|
|
142
332
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
333
|
+
async function cmdStop() {
|
|
334
|
+
const pid = readPid();
|
|
335
|
+
if (!pid) {
|
|
336
|
+
console.log("\n ClawCrib is not running.\n");
|
|
337
|
+
rmSync(PID_FILE, { force: true });
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
process.kill(pid, "SIGTERM");
|
|
341
|
+
for (let i = 0; i < 40; i++) {
|
|
342
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
343
|
+
if (!readPid()) break;
|
|
344
|
+
}
|
|
345
|
+
if (readPid()) {
|
|
346
|
+
try {
|
|
347
|
+
process.kill(pid, "SIGKILL");
|
|
348
|
+
} catch {
|
|
349
|
+
/* raced with exit */
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
rmSync(PID_FILE, { force: true });
|
|
353
|
+
console.log(`\n ClawCrib stopped (pid ${pid}).\n`);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
async function cmdStatus() {
|
|
357
|
+
const pid = readPid();
|
|
358
|
+
if (!pid) {
|
|
359
|
+
console.log("\n ClawCrib is not running.\n");
|
|
360
|
+
process.exitCode = 1;
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
const responding = await waitForServer(healthUrl, 3000);
|
|
364
|
+
console.log(`\n ClawCrib is running (pid ${pid})`);
|
|
365
|
+
console.log(` Crib: ${url} — ${responding ? "responding" : "NOT responding"}`);
|
|
366
|
+
console.log(` Log: ${LOG_FILE}\n`);
|
|
367
|
+
if (!responding) process.exitCode = 1;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Keeps it alive across reboots. Uses the resolved bin path, which is why a
|
|
371
|
+
// global install matters: an npx path points into a cache that gets evicted.
|
|
372
|
+
function serviceFiles() {
|
|
373
|
+
const binPath = process.argv[1];
|
|
374
|
+
// Deliberately the FOREGROUND run, not `start`: systemd and launchd want to
|
|
375
|
+
// supervise the process themselves. Pointing them at `start` — which forks
|
|
376
|
+
// and exits — makes launchd's KeepAlive treat every launch as a crash and
|
|
377
|
+
// respawn in a loop.
|
|
378
|
+
const args = [binPath, "--no-open"];
|
|
379
|
+
if (opts.port !== 18787) args.push("--port", String(opts.port));
|
|
380
|
+
if (opts.host !== "127.0.0.1") args.push("--host", opts.host);
|
|
381
|
+
if (opts.gateway) args.push("--gateway", opts.gateway);
|
|
382
|
+
if (opts.token) args.push("--token", opts.token);
|
|
383
|
+
return { binPath, args };
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function cmdInstallService() {
|
|
387
|
+
const { binPath, args } = serviceFiles();
|
|
388
|
+
if (binPath.includes("_npx") || binPath.includes("npm/_cacache")) {
|
|
389
|
+
console.error(
|
|
390
|
+
"\n Refusing to install a service pointing at an npx cache path — it will be evicted.\n" +
|
|
391
|
+
" Install globally first: npm i -g clawcrib\n"
|
|
392
|
+
);
|
|
393
|
+
process.exit(1);
|
|
394
|
+
}
|
|
395
|
+
const exec = [process.execPath, ...args].map((a) => JSON.stringify(a)).join(" ");
|
|
396
|
+
|
|
397
|
+
if (process.platform === "linux") {
|
|
398
|
+
const unit = `[Unit]
|
|
399
|
+
Description=ClawCrib — live 3D office for OpenClaw agents
|
|
400
|
+
After=network-online.target
|
|
401
|
+
|
|
402
|
+
[Service]
|
|
403
|
+
Type=simple
|
|
404
|
+
ExecStart=${exec}
|
|
405
|
+
Restart=on-failure
|
|
406
|
+
RestartSec=5
|
|
407
|
+
Environment=CLAWCRIB_CONFIG_DIR=${CONFIG_DIR}
|
|
408
|
+
|
|
409
|
+
[Install]
|
|
410
|
+
WantedBy=default.target
|
|
411
|
+
`;
|
|
412
|
+
const dir = path.join(os.homedir(), ".config", "systemd", "user");
|
|
413
|
+
mkdirSync(dir, { recursive: true });
|
|
414
|
+
const file = path.join(dir, "clawcrib.service");
|
|
415
|
+
writeFileSync(file, unit);
|
|
416
|
+
console.log(`\n Wrote ${file}\n`);
|
|
417
|
+
console.log(" Enable it (starts now and on every boot):");
|
|
418
|
+
console.log(" systemctl --user daemon-reload");
|
|
419
|
+
console.log(" systemctl --user enable --now clawcrib");
|
|
420
|
+
console.log("\n So it keeps running after you log out of SSH:");
|
|
421
|
+
console.log(" sudo loginctl enable-linger $USER\n");
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
if (process.platform === "darwin") {
|
|
426
|
+
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
427
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
428
|
+
<plist version="1.0">
|
|
429
|
+
<dict>
|
|
430
|
+
<key>Label</key><string>ai.clearmud.clawcrib</string>
|
|
431
|
+
<key>ProgramArguments</key>
|
|
432
|
+
<array>
|
|
433
|
+
${[process.execPath, ...args].map((a) => ` <string>${a}</string>`).join("\n")}
|
|
434
|
+
</array>
|
|
435
|
+
<key>RunAtLoad</key><true/>
|
|
436
|
+
<key>KeepAlive</key><true/>
|
|
437
|
+
<key>StandardOutPath</key><string>${LOG_FILE}</string>
|
|
438
|
+
<key>StandardErrorPath</key><string>${LOG_FILE}</string>
|
|
439
|
+
</dict>
|
|
440
|
+
</plist>
|
|
441
|
+
`;
|
|
442
|
+
const dir = path.join(os.homedir(), "Library", "LaunchAgents");
|
|
443
|
+
mkdirSync(dir, { recursive: true });
|
|
444
|
+
const file = path.join(dir, "ai.clearmud.clawcrib.plist");
|
|
445
|
+
writeFileSync(file, plist);
|
|
446
|
+
console.log(`\n Wrote ${file}\n`);
|
|
447
|
+
console.log(" Enable it (starts now and on every login):");
|
|
448
|
+
console.log(` launchctl load -w ${file}\n`);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
console.error(`\n install-service supports linux (systemd) and macOS (launchd), not ${process.platform}.\n`);
|
|
453
|
+
process.exit(1);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function cmdUninstallService() {
|
|
457
|
+
const file =
|
|
458
|
+
process.platform === "linux"
|
|
459
|
+
? path.join(os.homedir(), ".config", "systemd", "user", "clawcrib.service")
|
|
460
|
+
: path.join(os.homedir(), "Library", "LaunchAgents", "ai.clearmud.clawcrib.plist");
|
|
461
|
+
if (!existsSync(file)) {
|
|
462
|
+
console.log("\n No service file installed.\n");
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
console.log(`\n Disable it first:`);
|
|
466
|
+
console.log(
|
|
467
|
+
process.platform === "linux"
|
|
468
|
+
? " systemctl --user disable --now clawcrib"
|
|
469
|
+
: ` launchctl unload -w ${file}`
|
|
470
|
+
);
|
|
471
|
+
rmSync(file, { force: true });
|
|
472
|
+
console.log(`\n Removed ${file}\n`);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
async function cmdRun() {
|
|
476
|
+
await resolveGateway();
|
|
477
|
+
const child = spawnServer(false);
|
|
478
|
+
child.stdout.on("data", () => {}); // keep Next's own listen log quiet; we print our own
|
|
479
|
+
|
|
480
|
+
waitForServer(healthUrl).then(async (up) => {
|
|
481
|
+
if (!up) {
|
|
482
|
+
console.error("ClawCrib server did not come up within 30s.");
|
|
483
|
+
child.kill();
|
|
484
|
+
process.exit(1);
|
|
485
|
+
}
|
|
486
|
+
console.log(`\n ClawCrib v${pkg.version}`);
|
|
487
|
+
console.log(` Crib: ${url}`);
|
|
488
|
+
console.log(` Mode: ${modeLine()}`);
|
|
489
|
+
await printDetails();
|
|
490
|
+
console.log(`\n Serving. Press Ctrl-C to stop.`);
|
|
491
|
+
console.log(` Prefer it always-on? clawcrib start (background)\n`);
|
|
492
|
+
|
|
493
|
+
// A headless box has no browser to open; spawning xdg-open just fails quietly.
|
|
494
|
+
const headless =
|
|
495
|
+
process.platform === "linux" && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY;
|
|
496
|
+
if (opts.open && !headless) openBrowser(url);
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
const shutdown = () => {
|
|
500
|
+
child.kill("SIGTERM");
|
|
501
|
+
process.exit(0);
|
|
502
|
+
};
|
|
503
|
+
process.on("SIGINT", shutdown);
|
|
504
|
+
process.on("SIGTERM", shutdown);
|
|
505
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
switch (opts.cmd) {
|
|
509
|
+
case "start":
|
|
510
|
+
await cmdStart();
|
|
511
|
+
break;
|
|
512
|
+
case "stop":
|
|
513
|
+
await cmdStop();
|
|
514
|
+
break;
|
|
515
|
+
case "restart":
|
|
516
|
+
await cmdStop();
|
|
517
|
+
await cmdStart();
|
|
518
|
+
break;
|
|
519
|
+
case "status":
|
|
520
|
+
await cmdStatus();
|
|
521
|
+
break;
|
|
522
|
+
case "install-service":
|
|
523
|
+
cmdInstallService();
|
|
524
|
+
break;
|
|
525
|
+
case "uninstall-service":
|
|
526
|
+
cmdUninstallService();
|
|
527
|
+
break;
|
|
528
|
+
default:
|
|
529
|
+
await cmdRun();
|
|
530
|
+
}
|
package/dist/.next/BUILD_ID
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
zYUlp2fcVlJKBhUQk1Pns
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
"static/chunks/a6dad97d9634a72d.js"
|
|
8
8
|
],
|
|
9
9
|
"lowPriorityFiles": [
|
|
10
|
-
"static/
|
|
11
|
-
"static/
|
|
10
|
+
"static/zYUlp2fcVlJKBhUQk1Pns/_ssgManifest.js",
|
|
11
|
+
"static/zYUlp2fcVlJKBhUQk1Pns/_buildManifest.js"
|
|
12
12
|
],
|
|
13
13
|
"rootMainFiles": [
|
|
14
14
|
"static/chunks/251e16428085edaf.js",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
2
|
-
@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">500</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">Internal Server Error.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/251e16428085edaf.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[39756,[\"/_next/static/chunks/ff1a16fafef87110.js\",\"/_next/static/chunks/0bd6498bda341889.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/ff1a16fafef87110.js\",\"/_next/static/chunks/0bd6498bda341889.js\"],\"default\"]\n4:I[97367,[\"/_next/static/chunks/ff1a16fafef87110.js\",\"/_next/static/chunks/0bd6498bda341889.js\"],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n7:I[97367,[\"/_next/static/chunks/ff1a16fafef87110.js\",\"/_next/static/chunks/0bd6498bda341889.js\"],\"ViewportBoundary\"]\n9:I[97367,[\"/_next/static/chunks/ff1a16fafef87110.js\",\"/_next/static/chunks/0bd6498bda341889.js\"],\"MetadataBoundary\"]\nb:I[68027,[\"/_next/static/chunks/ff1a16fafef87110.js\",\"/_next/static/chunks/0bd6498bda341889.js\"],\"default\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"
|
|
1
|
+
<!DOCTYPE html><!--zYUlp2fcVlJKBhUQk1Pns--><html id="__next_error__"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/251e16428085edaf.js"/><script src="/_next/static/chunks/f188e57e58a39d0f.js" async=""></script><script src="/_next/static/chunks/045c83caa4d15373.js" async=""></script><script src="/_next/static/chunks/619d93506b5beb32.js" async=""></script><script src="/_next/static/chunks/82abf2d65f5428ae.js" async=""></script><script src="/_next/static/chunks/turbopack-aadb2fcebd6885bc.js" async=""></script><script src="/_next/static/chunks/ff1a16fafef87110.js" async=""></script><script src="/_next/static/chunks/0bd6498bda341889.js" async=""></script><meta name="next-size-adjust" content=""/><title>500: Internal Server Error.</title><script src="/_next/static/chunks/a6dad97d9634a72d.js" noModule=""></script></head><body><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div style="line-height:48px"><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}
|
|
2
|
+
@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding-right:23px;font-size:24px;font-weight:500;vertical-align:top">500</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:28px">Internal Server Error.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/251e16428085edaf.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[39756,[\"/_next/static/chunks/ff1a16fafef87110.js\",\"/_next/static/chunks/0bd6498bda341889.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/ff1a16fafef87110.js\",\"/_next/static/chunks/0bd6498bda341889.js\"],\"default\"]\n4:I[97367,[\"/_next/static/chunks/ff1a16fafef87110.js\",\"/_next/static/chunks/0bd6498bda341889.js\"],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n7:I[97367,[\"/_next/static/chunks/ff1a16fafef87110.js\",\"/_next/static/chunks/0bd6498bda341889.js\"],\"ViewportBoundary\"]\n9:I[97367,[\"/_next/static/chunks/ff1a16fafef87110.js\",\"/_next/static/chunks/0bd6498bda341889.js\"],\"MetadataBoundary\"]\nb:I[68027,[\"/_next/static/chunks/ff1a16fafef87110.js\",\"/_next/static/chunks/0bd6498bda341889.js\"],\"default\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"zYUlp2fcVlJKBhUQk1Pns\",\"c\":[\"\",\"_global-error\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"__PAGE__\",{}]}],[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"html\",null,{\"id\":\"__next_error__\",\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"title\",null,{\"children\":\"500: Internal Server Error.\"}]}],[\"$\",\"body\",null,{\"children\":[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"style\":{\"lineHeight\":\"48px\"},\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}\\n@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"paddingRight\":23,\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\"},\"children\":\"500\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"28px\"},\"children\":\"Internal Server Error.\"}]}]]}]}]}]]}],[[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/ff1a16fafef87110.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/0bd6498bda341889.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,false]},null,false,false],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L7\",null,{\"children\":\"$L8\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$L9\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$La\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$b\",\"$undefined\"],\"S\":true}\n"])</script><script>self.__next_f.push([1,"8:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"6:null\na:[]\n"])</script></body></html>
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
7:I[97367,["/_next/static/chunks/ff1a16fafef87110.js","/_next/static/chunks/0bd6498bda341889.js"],"ViewportBoundary"]
|
|
7
7
|
9:I[97367,["/_next/static/chunks/ff1a16fafef87110.js","/_next/static/chunks/0bd6498bda341889.js"],"MetadataBoundary"]
|
|
8
8
|
b:I[68027,["/_next/static/chunks/ff1a16fafef87110.js","/_next/static/chunks/0bd6498bda341889.js"],"default"]
|
|
9
|
-
0:{"P":null,"b":"
|
|
9
|
+
0:{"P":null,"b":"zYUlp2fcVlJKBhUQk1Pns","c":["","_global-error"],"q":"","i":false,"f":[[["",{"children":["__PAGE__",{}]}],[["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[["$","html",null,{"id":"__next_error__","children":[["$","head",null,{"children":["$","title",null,{"children":"500: Internal Server Error."}]}],["$","body",null,{"children":["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"style":{"lineHeight":"48px"},"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}\n@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","paddingRight":23,"fontSize":24,"fontWeight":500,"verticalAlign":"top"},"children":"500"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"28px"},"children":"Internal Server Error."}]}]]}]}]}]]}],[["$","script","script-0",{"src":"/_next/static/chunks/ff1a16fafef87110.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/_next/static/chunks/0bd6498bda341889.js","async":true,"nonce":"$undefined"}]],["$","$L4",null,{"children":["$","$5",null,{"name":"Next.MetadataOutlet","children":"$@6"}]}]]}],{},null,false,false]},null,false,false],["$","$1","h",{"children":[null,["$","$L7",null,{"children":"$L8"}],["$","div",null,{"hidden":true,"children":["$","$L9",null,{"children":["$","$5",null,{"name":"Next.Metadata","children":"$La"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$b","$undefined"],"S":true}
|
|
10
10
|
8:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
|
11
11
|
6:null
|
|
12
12
|
a:[]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
1:"$Sreact.fragment"
|
|
2
2
|
2:I[97367,["/_next/static/chunks/ff1a16fafef87110.js","/_next/static/chunks/0bd6498bda341889.js"],"OutletBoundary"]
|
|
3
3
|
3:"$Sreact.suspense"
|
|
4
|
-
0:{"buildId":"
|
|
4
|
+
0:{"buildId":"zYUlp2fcVlJKBhUQk1Pns","rsc":["$","$1","c",{"children":[["$","html",null,{"id":"__next_error__","children":[["$","head",null,{"children":["$","title",null,{"children":"500: Internal Server Error."}]}],["$","body",null,{"children":["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"style":{"lineHeight":"48px"},"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}\n@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","paddingRight":23,"fontSize":24,"fontWeight":500,"verticalAlign":"top"},"children":"500"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"28px"},"children":"Internal Server Error."}]}]]}]}]}]]}],[["$","script","script-0",{"src":"/_next/static/chunks/ff1a16fafef87110.js","async":true}],["$","script","script-1",{"src":"/_next/static/chunks/0bd6498bda341889.js","async":true}]],["$","$L2",null,{"children":["$","$3",null,{"name":"Next.MetadataOutlet","children":"$@4"}]}]]}],"loading":null,"isPartial":false}
|
|
5
5
|
4:null
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
7:I[97367,["/_next/static/chunks/ff1a16fafef87110.js","/_next/static/chunks/0bd6498bda341889.js"],"ViewportBoundary"]
|
|
7
7
|
9:I[97367,["/_next/static/chunks/ff1a16fafef87110.js","/_next/static/chunks/0bd6498bda341889.js"],"MetadataBoundary"]
|
|
8
8
|
b:I[68027,["/_next/static/chunks/ff1a16fafef87110.js","/_next/static/chunks/0bd6498bda341889.js"],"default"]
|
|
9
|
-
0:{"P":null,"b":"
|
|
9
|
+
0:{"P":null,"b":"zYUlp2fcVlJKBhUQk1Pns","c":["","_global-error"],"q":"","i":false,"f":[[["",{"children":["__PAGE__",{}]}],[["$","$1","c",{"children":[null,["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","forbidden":"$undefined","unauthorized":"$undefined"}]]}],{"children":[["$","$1","c",{"children":[["$","html",null,{"id":"__next_error__","children":[["$","head",null,{"children":["$","title",null,{"children":"500: Internal Server Error."}]}],["$","body",null,{"children":["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"style":{"lineHeight":"48px"},"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}\n@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","paddingRight":23,"fontSize":24,"fontWeight":500,"verticalAlign":"top"},"children":"500"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"28px"},"children":"Internal Server Error."}]}]]}]}]}]]}],[["$","script","script-0",{"src":"/_next/static/chunks/ff1a16fafef87110.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/_next/static/chunks/0bd6498bda341889.js","async":true,"nonce":"$undefined"}]],["$","$L4",null,{"children":["$","$5",null,{"name":"Next.MetadataOutlet","children":"$@6"}]}]]}],{},null,false,false]},null,false,false],["$","$1","h",{"children":[null,["$","$L7",null,{"children":"$L8"}],["$","div",null,{"hidden":true,"children":["$","$L9",null,{"children":["$","$5",null,{"name":"Next.Metadata","children":"$La"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$b","$undefined"],"S":true}
|
|
10
10
|
8:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
|
11
11
|
6:null
|
|
12
12
|
a:[]
|
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
2:I[97367,["/_next/static/chunks/ff1a16fafef87110.js","/_next/static/chunks/0bd6498bda341889.js"],"ViewportBoundary"]
|
|
3
3
|
3:I[97367,["/_next/static/chunks/ff1a16fafef87110.js","/_next/static/chunks/0bd6498bda341889.js"],"MetadataBoundary"]
|
|
4
4
|
4:"$Sreact.suspense"
|
|
5
|
-
0:{"buildId":"
|
|
5
|
+
0:{"buildId":"zYUlp2fcVlJKBhUQk1Pns","rsc":["$","$1","h",{"children":[null,["$","$L2",null,{"children":[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]}],["$","div",null,{"hidden":true,"children":["$","$L3",null,{"children":["$","$4",null,{"name":"Next.Metadata","children":[]}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],"loading":null,"isPartial":false}
|