@sapienx/agentos 0.5.3 → 0.5.6
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/README.md +4 -1
- package/bin/agentos.js +580 -31
- package/bin/terminal-boot.js +620 -0
- package/bundle/.next/BUILD_ID +1 -1
- package/bundle/.next/app-path-routes-manifest.json +9 -9
- package/bundle/.next/build-manifest.json +2 -2
- package/bundle/.next/prerender-manifest.json +3 -3
- package/bundle/.next/required-server-files.json +1 -1
- package/bundle/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/bundle/.next/server/app/_global-error.html +1 -1
- package/bundle/.next/server/app/_global-error.rsc +1 -1
- package/bundle/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/bundle/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/bundle/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/bundle/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/bundle/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/bundle/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/bundle/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/bundle/.next/server/app/_not-found.html +1 -1
- package/bundle/.next/server/app/_not-found.rsc +1 -1
- package/bundle/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/bundle/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/bundle/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/bundle/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/bundle/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/bundle/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/bundle/.next/server/app/api/agents/[agentId]/chat/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/agents/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/diagnostics/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/gateway/control/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/mission/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/models/catalog/route.js +2 -1
- package/bundle/.next/server/app/api/models/catalog/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/models/providers/route.js +2 -1
- package/bundle/.next/server/app/api/models/providers/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/onboarding/models/route.js +8 -7
- package/bundle/.next/server/app/api/onboarding/models/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/onboarding/route.js +12 -6
- package/bundle/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/planner/[planId]/deploy/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/planner/[planId]/document-rewrite/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/planner/[planId]/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/planner/[planId]/simulate/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/planner/[planId]/turn/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/planner/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/reset/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/runtimes/[runtimeId]/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/settings/gateway/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/settings/openclaw-binary/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/settings/workspace-root/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/snapshot/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/stream/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/tasks/[taskId]/abort/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/tasks/[taskId]/control/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/tasks/[taskId]/stream/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/update/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/workspaces/[workspaceId]/channels/discovered-groups/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/workspaces/[workspaceId]/channels/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/workspaces/[workspaceId]/edit-draft/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/workspaces/[workspaceId]/files/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/workspaces/[workspaceId]/surfaces/discovery/route.js.nft.json +1 -1
- package/bundle/.next/server/app/api/workspaces/route.js.nft.json +1 -1
- package/bundle/.next/server/app/page.js.nft.json +1 -1
- package/bundle/.next/server/app/page_client-reference-manifest.js +1 -1
- package/bundle/.next/server/app/settings/page.js.nft.json +1 -1
- package/bundle/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/bundle/.next/server/app-paths-manifest.json +9 -9
- package/bundle/.next/server/chunks/4767.js +9 -9
- package/bundle/.next/server/chunks/5151.js +2 -2
- package/bundle/.next/server/chunks/6639.js +6 -5
- package/bundle/.next/server/chunks/7125.js +4 -4
- package/bundle/.next/server/middleware-build-manifest.js +1 -1
- package/bundle/.next/server/pages/404.html +1 -1
- package/bundle/.next/server/pages/500.html +1 -1
- package/bundle/.next/server/server-reference-manifest.json +1 -1
- package/bundle/.next/static/chunks/{7442-f5f805e43da2c5b6.js → 7442-e148a49efcfa2d32.js} +4 -4
- package/bundle/server.js +1 -1
- package/package.json +1 -1
- package/bundle/.next/server/chunks/5831.js +0 -2
- /package/bundle/.next/static/{easVJgXM2ae2U4xGhNmSj → ujFbMZ9arxb7I3_g4GzfY}/_buildManifest.js +0 -0
- /package/bundle/.next/static/{easVJgXM2ae2U4xGhNmSj → ujFbMZ9arxb7I3_g4GzfY}/_ssgManifest.js +0 -0
package/bin/agentos.js
CHANGED
|
@@ -9,6 +9,8 @@ import path from "node:path";
|
|
|
9
9
|
import process from "node:process";
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
11
|
|
|
12
|
+
import { createTerminalBoot, renderDoctorReport, renderStatusDashboard } from "./terminal-boot.js";
|
|
13
|
+
|
|
12
14
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
13
15
|
const packageRoot = path.resolve(__dirname, "..");
|
|
14
16
|
const packageJsonPath = path.join(packageRoot, "package.json");
|
|
@@ -69,6 +71,16 @@ async function main() {
|
|
|
69
71
|
return;
|
|
70
72
|
}
|
|
71
73
|
|
|
74
|
+
if (firstArg === "status") {
|
|
75
|
+
if (args[1] === "--help" || args[1] === "-h" || args[1] === "help") {
|
|
76
|
+
printStatusHelp();
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
runStatus(args.slice(1));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
72
84
|
if (firstArg === "update") {
|
|
73
85
|
if (args[1] === "--help" || args[1] === "-h" || args[1] === "help") {
|
|
74
86
|
printUpdateHelp();
|
|
@@ -99,7 +111,7 @@ async function main() {
|
|
|
99
111
|
return;
|
|
100
112
|
}
|
|
101
113
|
|
|
102
|
-
if (firstArg === "start") {
|
|
114
|
+
if (firstArg === "start" || firstArg === "dev") {
|
|
103
115
|
await startServer(args.slice(1));
|
|
104
116
|
return;
|
|
105
117
|
}
|
|
@@ -143,18 +155,35 @@ async function startServer(rawArgs) {
|
|
|
143
155
|
clearRuntimeState(runtimeStatePath);
|
|
144
156
|
}
|
|
145
157
|
|
|
146
|
-
|
|
158
|
+
const boot = createTerminalBoot({
|
|
159
|
+
plain: options.plain,
|
|
160
|
+
stdout: process.stdout,
|
|
161
|
+
stderr: process.stderr,
|
|
162
|
+
env: process.env
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
if (boot.isPlain()) {
|
|
166
|
+
console.log(`Starting AgentOS ${packageJson.version} on ${url}`);
|
|
147
167
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
168
|
+
if (!openClawCheck.available) {
|
|
169
|
+
console.log("OpenClaw was not found in PATH or the default local install paths. AgentOS will start and guide onboarding in the UI.");
|
|
170
|
+
} else if (openClawCheck.version) {
|
|
171
|
+
console.log(`OpenClaw detected: ${openClawCheck.version}`);
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
initializeBootVersionStatus(boot);
|
|
175
|
+
boot.start();
|
|
176
|
+
boot.updateStatus("workspaceEngine", "loading", "bundle ready");
|
|
177
|
+
applyOpenClawBootStatus(boot, openClawCheck);
|
|
152
178
|
}
|
|
153
179
|
|
|
154
180
|
if (options.open && !browserOpener.available) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
181
|
+
const message = `Browser auto-open is unavailable on this machine${browserOpener.detail ? ` (${browserOpener.detail})` : ""}.`;
|
|
182
|
+
if (boot.isPlain()) {
|
|
183
|
+
console.warn(message);
|
|
184
|
+
} else {
|
|
185
|
+
boot.warn(message);
|
|
186
|
+
}
|
|
158
187
|
}
|
|
159
188
|
|
|
160
189
|
const child = spawn(process.execPath, [bundledServerPath], {
|
|
@@ -187,14 +216,46 @@ async function startServer(rawArgs) {
|
|
|
187
216
|
throw error;
|
|
188
217
|
}
|
|
189
218
|
|
|
219
|
+
if (!boot.isPlain()) {
|
|
220
|
+
boot.updateStatus("workspaceEngine", "ready", "runtime state written");
|
|
221
|
+
boot.updateStatus("agentRuntime", "starting", `pid ${child.pid}`);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const startupState = {
|
|
225
|
+
ready: false,
|
|
226
|
+
completing: false,
|
|
227
|
+
completed: boot.isPlain(),
|
|
228
|
+
bufferedLogs: []
|
|
229
|
+
};
|
|
190
230
|
const browserState = { opened: false };
|
|
191
|
-
const
|
|
192
|
-
|
|
231
|
+
const onServerReady = () => {
|
|
232
|
+
if (startupState.ready) {
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
startupState.ready = true;
|
|
237
|
+
|
|
238
|
+
if (options.open && browserOpener.available && !browserState.opened) {
|
|
239
|
+
browserState.opened = true;
|
|
240
|
+
openBrowser(url, browserOpener);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (boot.isPlain()) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
startupState.completing = true;
|
|
248
|
+
void completeBootAfterServerReady(boot, startupState, url);
|
|
249
|
+
};
|
|
250
|
+
const relayStdout = createRelay(process.stdout, boot, startupState, onServerReady);
|
|
251
|
+
const relayStderr = createRelay(process.stderr, boot, startupState, onServerReady);
|
|
193
252
|
|
|
194
253
|
child.stdout.on("data", relayStdout);
|
|
195
254
|
child.stderr.on("data", relayStderr);
|
|
196
255
|
|
|
197
|
-
|
|
256
|
+
if (boot.isPlain()) {
|
|
257
|
+
schedulePassiveUpdateNotice();
|
|
258
|
+
}
|
|
198
259
|
|
|
199
260
|
let cleanedUp = false;
|
|
200
261
|
const shutdownState = {
|
|
@@ -227,8 +288,12 @@ async function startServer(rawArgs) {
|
|
|
227
288
|
shutdownState.parentSignal = signal;
|
|
228
289
|
|
|
229
290
|
if (signal === "SIGINT") {
|
|
291
|
+
boot.stop({ clear: true });
|
|
292
|
+
flushBufferedStartupLogs(startupState);
|
|
230
293
|
process.stdout.write("\nStopping AgentOS... Press Ctrl+C again to force quit.\n");
|
|
231
294
|
} else {
|
|
295
|
+
boot.stop({ clear: true });
|
|
296
|
+
flushBufferedStartupLogs(startupState);
|
|
232
297
|
console.log(`Stopping AgentOS after ${signal}...`);
|
|
233
298
|
}
|
|
234
299
|
|
|
@@ -247,6 +312,8 @@ async function startServer(rawArgs) {
|
|
|
247
312
|
|
|
248
313
|
child.on("error", (error) => {
|
|
249
314
|
cleanup();
|
|
315
|
+
boot.stop({ clear: true });
|
|
316
|
+
flushBufferedStartupLogs(startupState);
|
|
250
317
|
console.error(`AgentOS failed to start: ${error.message}`);
|
|
251
318
|
process.exit(1);
|
|
252
319
|
});
|
|
@@ -254,6 +321,11 @@ async function startServer(rawArgs) {
|
|
|
254
321
|
child.on("exit", (code, signal) => {
|
|
255
322
|
cleanup();
|
|
256
323
|
|
|
324
|
+
if (!startupState.completed) {
|
|
325
|
+
boot.stop({ clear: true });
|
|
326
|
+
flushBufferedStartupLogs(startupState);
|
|
327
|
+
}
|
|
328
|
+
|
|
257
329
|
if (shutdownState.parentSignal) {
|
|
258
330
|
process.kill(process.pid, shutdownState.parentSignal);
|
|
259
331
|
return;
|
|
@@ -271,55 +343,63 @@ async function startServer(rawArgs) {
|
|
|
271
343
|
function runDoctor() {
|
|
272
344
|
const options = parseStartArgs([]);
|
|
273
345
|
const openClawCheck = detectOpenClaw();
|
|
346
|
+
const gatewayStatus = openClawCheck.available ? inspectOpenClawGatewayStatus(openClawCheck) : null;
|
|
274
347
|
const browserOpener = detectBrowserOpener();
|
|
275
348
|
const targetUrl = `http://${displayHost(options.host)}:${options.port}`;
|
|
276
349
|
const checks = [
|
|
277
350
|
{
|
|
278
|
-
|
|
351
|
+
state: "ok",
|
|
279
352
|
label: "Package",
|
|
280
353
|
detail: `${packageJson.name}@${packageJson.version}`
|
|
281
354
|
},
|
|
282
355
|
{
|
|
283
|
-
|
|
356
|
+
state: "ok",
|
|
284
357
|
label: "Install",
|
|
285
358
|
detail: formatInstallKind(inspectInstallation())
|
|
286
359
|
},
|
|
287
360
|
{
|
|
288
|
-
|
|
361
|
+
state: isSupportedNodeVersion(process.versions.node) ? "ok" : "failed",
|
|
289
362
|
label: "Node.js",
|
|
290
363
|
detail: `${process.version} (required >= 20.9.0)`
|
|
291
364
|
},
|
|
292
365
|
{
|
|
293
|
-
|
|
366
|
+
state: "ok",
|
|
294
367
|
label: "Platform",
|
|
295
368
|
detail: `${os.platform()} ${os.release()}`
|
|
296
369
|
},
|
|
297
370
|
{
|
|
298
|
-
|
|
371
|
+
state: existsSync(bundledServerPath) ? "ok" : "failed",
|
|
299
372
|
label: "Bundle",
|
|
300
373
|
detail: existsSync(bundledServerPath)
|
|
301
374
|
? `ready at ${bundledServerPath}`
|
|
302
375
|
: `missing at ${bundledServerPath}`
|
|
303
376
|
},
|
|
304
377
|
{
|
|
305
|
-
|
|
378
|
+
state: "ok",
|
|
306
379
|
label: "Target URL",
|
|
307
380
|
detail: targetUrl
|
|
308
381
|
},
|
|
309
382
|
{
|
|
310
|
-
|
|
383
|
+
state: "ok",
|
|
311
384
|
label: "Configured env",
|
|
312
385
|
detail: formatConfiguredEnv(options)
|
|
313
386
|
},
|
|
314
387
|
{
|
|
315
|
-
|
|
388
|
+
state: openClawCheck.available ? "ok" : "warning",
|
|
316
389
|
label: "OpenClaw",
|
|
317
390
|
detail: openClawCheck.available
|
|
318
391
|
? `${openClawCheck.version || "installed"}${openClawCheck.path ? ` at ${openClawCheck.path}` : ""}`
|
|
319
392
|
: "not found in PATH or default local install paths; install OpenClaw or continue with the AgentOS onboarding flow"
|
|
320
393
|
},
|
|
321
394
|
{
|
|
322
|
-
|
|
395
|
+
state: !openClawCheck.available ? "disabled" : gatewayStatus?.ok ? "ok" : "warning",
|
|
396
|
+
label: "Gateway",
|
|
397
|
+
detail: !openClawCheck.available
|
|
398
|
+
? "OpenClaw is required before Gateway RPC can be checked"
|
|
399
|
+
: gatewayStatus?.gatewayMessage || "Gateway status unavailable"
|
|
400
|
+
},
|
|
401
|
+
{
|
|
402
|
+
state: browserOpener.available ? "ok" : "warning",
|
|
323
403
|
label: "Browser opener",
|
|
324
404
|
detail: browserOpener.available
|
|
325
405
|
? `${browserOpener.command} is available`
|
|
@@ -327,11 +407,90 @@ function runDoctor() {
|
|
|
327
407
|
}
|
|
328
408
|
];
|
|
329
409
|
|
|
330
|
-
|
|
331
|
-
|
|
410
|
+
console.log(renderDoctorReport({
|
|
411
|
+
title: "AGENTOS DOCTOR",
|
|
412
|
+
rows: checks.map((check) => ({
|
|
413
|
+
label: check.label,
|
|
414
|
+
state: check.state,
|
|
415
|
+
message: check.detail
|
|
416
|
+
})),
|
|
417
|
+
footer: "Doctor shows install and runtime diagnostics. The in-app diagnostics panel has live Gateway/model detail."
|
|
418
|
+
}));
|
|
419
|
+
|
|
420
|
+
if (checks.some((check) => check.state === "failed")) {
|
|
421
|
+
process.exitCode = 1;
|
|
332
422
|
}
|
|
423
|
+
}
|
|
333
424
|
|
|
334
|
-
|
|
425
|
+
function runStatus(rawArgs) {
|
|
426
|
+
const options = parseStatusArgs(rawArgs);
|
|
427
|
+
const runtimeStatePath = resolveRuntimeStatePath(options.port);
|
|
428
|
+
const trackedState = readRuntimeState(runtimeStatePath);
|
|
429
|
+
const listeningPid = findListeningPidForPort(options.port);
|
|
430
|
+
const trackedPid = trackedState?.pid && isProcessRunning(trackedState.pid) ? trackedState.pid : null;
|
|
431
|
+
const runningPid = listeningPid ?? trackedPid;
|
|
432
|
+
const host = trackedState?.host || options.host;
|
|
433
|
+
const url = createAgentOsUrl(host, options.port);
|
|
434
|
+
const openClawCheck = detectOpenClaw();
|
|
435
|
+
const gatewayStatus = openClawCheck.available ? inspectOpenClawGatewayStatus(openClawCheck) : null;
|
|
436
|
+
const bundleReady = existsSync(bundledServerPath);
|
|
437
|
+
const install = inspectInstallation();
|
|
438
|
+
const rows = [
|
|
439
|
+
{
|
|
440
|
+
label: "AgentOS",
|
|
441
|
+
state: "ready",
|
|
442
|
+
message: packageJson.version
|
|
443
|
+
},
|
|
444
|
+
buildUpdateDashboardRow(install),
|
|
445
|
+
{
|
|
446
|
+
label: "OpenClaw Gateway",
|
|
447
|
+
state: !openClawCheck.available ? "warning" : gatewayStatus?.ok ? "connected" : "degraded",
|
|
448
|
+
message: !openClawCheck.available
|
|
449
|
+
? "OpenClaw not found; setup will guide installation"
|
|
450
|
+
: gatewayStatus?.gatewayMessage || "needs attention"
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
label: "Native Gateway",
|
|
454
|
+
state: !openClawCheck.available ? "disabled" : gatewayStatus?.nativeState || "warning",
|
|
455
|
+
message: !openClawCheck.available
|
|
456
|
+
? "waiting for OpenClaw"
|
|
457
|
+
: gatewayStatus?.nativeMessage || "check Gateway diagnostics"
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
label: "Workspace Engine",
|
|
461
|
+
state: bundleReady ? "ready" : "failed",
|
|
462
|
+
message: bundleReady ? "bundle ready" : "bundle missing"
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
label: "Agent Runtime",
|
|
466
|
+
state: runningPid ? "ready" : "inactive",
|
|
467
|
+
message: runningPid ? `server running (PID ${runningPid})` : "server not running"
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
label: "Models",
|
|
471
|
+
state: runningPid ? "warning" : "pending",
|
|
472
|
+
message: runningPid ? "verify in setup or diagnostics" : "available after server start"
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
label: "Channels",
|
|
476
|
+
state: "disabled",
|
|
477
|
+
message: "no channel status loaded from CLI"
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
label: "Local Server",
|
|
481
|
+
state: runningPid ? "ready" : "pending",
|
|
482
|
+
message: url
|
|
483
|
+
}
|
|
484
|
+
];
|
|
485
|
+
|
|
486
|
+
console.log(renderStatusDashboard({
|
|
487
|
+
title: "SYSTEM CHECK",
|
|
488
|
+
rows,
|
|
489
|
+
finalInfo: runningPid ? url : "",
|
|
490
|
+
footer: runningPid ? "" : "AgentOS is not running. Start it with agentos start --open."
|
|
491
|
+
}));
|
|
492
|
+
|
|
493
|
+
if (!bundleReady) {
|
|
335
494
|
process.exitCode = 1;
|
|
336
495
|
}
|
|
337
496
|
}
|
|
@@ -465,12 +624,314 @@ async function runStop(rawArgs) {
|
|
|
465
624
|
console.log(`Stopped AgentOS on port ${options.port}.`);
|
|
466
625
|
}
|
|
467
626
|
|
|
627
|
+
function applyOpenClawBootStatus(boot, openClawCheck) {
|
|
628
|
+
if (!openClawCheck.available) {
|
|
629
|
+
boot.updateStatus("openclawGateway", "warning", "OpenClaw not found; onboarding will guide setup");
|
|
630
|
+
boot.updateStatus("nativeGateway", "disabled", "waiting for OpenClaw");
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
boot.updateStatus("openclawGateway", "checking", openClawCheck.version || "OpenClaw detected");
|
|
635
|
+
boot.updateStatus("nativeGateway", "waiting", "probing gateway");
|
|
636
|
+
|
|
637
|
+
const gatewayStatus = inspectOpenClawGatewayStatus(openClawCheck);
|
|
638
|
+
|
|
639
|
+
if (gatewayStatus.ok) {
|
|
640
|
+
boot.updateStatus("openclawGateway", "connected", gatewayStatus.gatewayMessage);
|
|
641
|
+
boot.updateStatus("nativeGateway", gatewayStatus.nativeState, gatewayStatus.nativeMessage);
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
boot.updateStatus("openclawGateway", "warning", gatewayStatus.gatewayMessage);
|
|
646
|
+
boot.updateStatus("nativeGateway", "disabled", gatewayStatus.nativeMessage);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
function initializeBootVersionStatus(boot) {
|
|
650
|
+
boot.updateStatus("agentosVersion", "ready", packageJson.version);
|
|
651
|
+
|
|
652
|
+
const install = inspectInstallation();
|
|
653
|
+
const cached = readCachedUpdateStatus(install);
|
|
654
|
+
|
|
655
|
+
if (install.kind === "source") {
|
|
656
|
+
boot.updateStatus("update", "disabled", "source checkout");
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
if (cached) {
|
|
661
|
+
updateBootUpdateStatus(boot, buildUpdateStatusFromCache(cached, install));
|
|
662
|
+
} else {
|
|
663
|
+
boot.updateStatus("update", "checking", "checking latest version");
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if (cached && isUpdateCacheFresh(cached)) {
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
void getUpdateStatus({
|
|
671
|
+
install,
|
|
672
|
+
forceRefresh: false,
|
|
673
|
+
timeoutMs: 1_500,
|
|
674
|
+
fallbackToCache: true
|
|
675
|
+
})
|
|
676
|
+
.then((status) => {
|
|
677
|
+
if (!status.ok) {
|
|
678
|
+
boot.updateStatus("update", "disabled", "check unavailable");
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
updateBootUpdateStatus(boot, status);
|
|
683
|
+
})
|
|
684
|
+
.catch(() => {
|
|
685
|
+
boot.updateStatus("update", "disabled", "check unavailable");
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
function updateBootUpdateStatus(boot, status) {
|
|
690
|
+
const row = buildUpdateRowFromStatus(status);
|
|
691
|
+
boot.updateStatus("update", row.state, row.message);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
function buildUpdateDashboardRow(install) {
|
|
695
|
+
if (install.kind === "source") {
|
|
696
|
+
return {
|
|
697
|
+
label: "Update",
|
|
698
|
+
state: "disabled",
|
|
699
|
+
message: "source checkout"
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
const cached = readCachedUpdateStatus(install);
|
|
704
|
+
|
|
705
|
+
if (!cached) {
|
|
706
|
+
return {
|
|
707
|
+
label: "Update",
|
|
708
|
+
state: "pending",
|
|
709
|
+
message: 'run "agentos update --check"'
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
return {
|
|
714
|
+
label: "Update",
|
|
715
|
+
...buildUpdateRowFromStatus(buildUpdateStatusFromCache(cached, install))
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
function buildUpdateRowFromStatus(status) {
|
|
720
|
+
if (status.updateAvailable) {
|
|
721
|
+
return {
|
|
722
|
+
state: "warning",
|
|
723
|
+
message: `${status.latestVersion} available · ${formatBootUpdateAction(status.install)}`
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
return {
|
|
728
|
+
state: "ready",
|
|
729
|
+
message: "up to date"
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
function formatBootUpdateAction(install) {
|
|
734
|
+
if (install.kind === "release") {
|
|
735
|
+
return "run agentos update";
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if (install.kind === "package-manager") {
|
|
739
|
+
return "update package";
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
return 'run "agentos update --check"';
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
function inspectOpenClawGatewayStatus(openClawCheck) {
|
|
746
|
+
const command = openClawCheck.path || "openclaw";
|
|
747
|
+
const result = spawnSync(command, ["gateway", "status", "--json"], {
|
|
748
|
+
encoding: "utf8",
|
|
749
|
+
timeout: 1_500
|
|
750
|
+
});
|
|
751
|
+
const output = `${result.stdout || ""}\n${result.stderr || ""}`.trim();
|
|
752
|
+
|
|
753
|
+
if (result.error) {
|
|
754
|
+
return {
|
|
755
|
+
ok: false,
|
|
756
|
+
gatewayMessage: result.error.code === "ETIMEDOUT" ? "gateway probe timed out" : "gateway status unavailable",
|
|
757
|
+
nativeMessage: "Gateway will be checked in the UI",
|
|
758
|
+
nativeState: "disabled"
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
if (result.status !== 0) {
|
|
763
|
+
return {
|
|
764
|
+
ok: false,
|
|
765
|
+
gatewayMessage: summarizeBootText(output) || "gateway not reachable yet",
|
|
766
|
+
nativeMessage: "start or repair OpenClaw Gateway in setup",
|
|
767
|
+
nativeState: "disabled"
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
const parsed = parseFirstJsonObject(output);
|
|
772
|
+
const capability = String(parsed?.capability || parsed?.Capability || "");
|
|
773
|
+
const connected = /connected|ok|reachable/i.test(output);
|
|
774
|
+
const missingOperatorScope = /no-operator-scope|operator scope/i.test(capability || output);
|
|
775
|
+
|
|
776
|
+
return {
|
|
777
|
+
ok: true,
|
|
778
|
+
gatewayMessage: connected ? "reachable" : "status available",
|
|
779
|
+
nativeState: missingOperatorScope ? "warning" : "active",
|
|
780
|
+
nativeMessage: missingOperatorScope ? "operator scope needs repair" : "native RPC available"
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
async function completeBootAfterServerReady(boot, startupState, url) {
|
|
785
|
+
boot.updateStatus("agentRuntime", "ready", "server ready");
|
|
786
|
+
boot.updateStatus("localServerUrl", "ready", url);
|
|
787
|
+
boot.updateStatus("models", "loading", "checking readiness");
|
|
788
|
+
boot.updateStatus("channels", "loading", "checking registry");
|
|
789
|
+
|
|
790
|
+
const readiness = await readStartupReadiness(url);
|
|
791
|
+
|
|
792
|
+
if (readiness.openClawGateway) {
|
|
793
|
+
boot.updateStatus("openclawGateway", readiness.openClawGateway.state, readiness.openClawGateway.message);
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
if (readiness.nativeGateway) {
|
|
797
|
+
boot.updateStatus("nativeGateway", readiness.nativeGateway.state, readiness.nativeGateway.message);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
boot.updateStatus("workspaceEngine", readiness.workspaceEngine.state, readiness.workspaceEngine.message);
|
|
801
|
+
boot.updateStatus("models", readiness.models.state, readiness.models.message);
|
|
802
|
+
boot.updateStatus("channels", readiness.channels.state, readiness.channels.message);
|
|
803
|
+
boot.complete(url);
|
|
804
|
+
startupState.bufferedLogs = [];
|
|
805
|
+
startupState.completed = true;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
async function readStartupReadiness(url) {
|
|
809
|
+
const fallback = {
|
|
810
|
+
workspaceEngine: { state: "ready", message: "available" },
|
|
811
|
+
models: { state: "warning", message: "finish setup in the UI" },
|
|
812
|
+
channels: { state: "disabled", message: "none confirmed yet" }
|
|
813
|
+
};
|
|
814
|
+
const controller = new AbortController();
|
|
815
|
+
const timeout = setTimeout(() => controller.abort(), 2_500);
|
|
816
|
+
|
|
817
|
+
try {
|
|
818
|
+
const response = await fetch(`${url}/api/snapshot`, {
|
|
819
|
+
signal: controller.signal
|
|
820
|
+
});
|
|
821
|
+
|
|
822
|
+
if (!response.ok) {
|
|
823
|
+
return fallback;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
const snapshot = await response.json();
|
|
827
|
+
return summarizeStartupSnapshot(snapshot);
|
|
828
|
+
} catch {
|
|
829
|
+
return fallback;
|
|
830
|
+
} finally {
|
|
831
|
+
clearTimeout(timeout);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
function summarizeStartupSnapshot(snapshot) {
|
|
836
|
+
const diagnostics = isRecord(snapshot?.diagnostics) ? snapshot.diagnostics : {};
|
|
837
|
+
const modelReadiness = isRecord(diagnostics.modelReadiness) ? diagnostics.modelReadiness : {};
|
|
838
|
+
const transport = isRecord(diagnostics.transport) ? diagnostics.transport : {};
|
|
839
|
+
const workspaces = Array.isArray(snapshot?.workspaces) ? snapshot.workspaces : [];
|
|
840
|
+
const channelAccounts = Array.isArray(snapshot?.channelAccounts) ? snapshot.channelAccounts : [];
|
|
841
|
+
const channelRegistry = isRecord(snapshot?.channelRegistry) && Array.isArray(snapshot.channelRegistry.channels)
|
|
842
|
+
? snapshot.channelRegistry.channels
|
|
843
|
+
: [];
|
|
844
|
+
const rpcOk = diagnostics.rpcOk === true;
|
|
845
|
+
const modelReady = modelReadiness.ready === true || modelReadiness.defaultModelReady === true;
|
|
846
|
+
const availableModelCount = numberOrZero(modelReadiness.availableModelCount);
|
|
847
|
+
const modelIssues = Array.isArray(modelReadiness.issues) ? modelReadiness.issues.filter(Boolean) : [];
|
|
848
|
+
const enabledChannels = channelAccounts.filter((channel) => channel && channel.enabled !== false).length + channelRegistry.length;
|
|
849
|
+
const transportStatus = typeof transport.gatewayMode === "string"
|
|
850
|
+
? transport.gatewayMode
|
|
851
|
+
: typeof transport.statusLabel === "string"
|
|
852
|
+
? transport.statusLabel
|
|
853
|
+
: "";
|
|
854
|
+
|
|
855
|
+
return {
|
|
856
|
+
openClawGateway: {
|
|
857
|
+
state: rpcOk ? "connected" : "warning",
|
|
858
|
+
message: rpcOk ? "authenticated RPC ready" : summarizeBootText(diagnostics.health) || "setup may be required"
|
|
859
|
+
},
|
|
860
|
+
nativeGateway: {
|
|
861
|
+
state: rpcOk ? "active" : "warning",
|
|
862
|
+
message: transportStatus || (rpcOk ? "native Gateway active" : "check diagnostics")
|
|
863
|
+
},
|
|
864
|
+
workspaceEngine: {
|
|
865
|
+
state: "ready",
|
|
866
|
+
message: workspaces.length > 0 ? `${workspaces.length} workspace${workspaces.length === 1 ? "" : "s"}` : "ready for first workspace"
|
|
867
|
+
},
|
|
868
|
+
models: {
|
|
869
|
+
state: modelReady || availableModelCount > 0 ? "ready" : "warning",
|
|
870
|
+
message: modelReady
|
|
871
|
+
? modelReadiness.resolvedDefaultModel || modelReadiness.defaultModel || "default model ready"
|
|
872
|
+
: modelIssues[0] || "model setup needed"
|
|
873
|
+
},
|
|
874
|
+
channels: {
|
|
875
|
+
state: enabledChannels > 0 ? "ready" : "disabled",
|
|
876
|
+
message: enabledChannels > 0 ? `${enabledChannels} configured` : "no channels configured"
|
|
877
|
+
}
|
|
878
|
+
};
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
function flushBufferedStartupLogs(startupState) {
|
|
882
|
+
if (!startupState?.bufferedLogs?.length) {
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
for (const entry of startupState.bufferedLogs) {
|
|
887
|
+
entry.target.write(entry.text);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
startupState.bufferedLogs = [];
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
function parseFirstJsonObject(value) {
|
|
894
|
+
if (!value) {
|
|
895
|
+
return null;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
const start = value.indexOf("{");
|
|
899
|
+
const end = value.lastIndexOf("}");
|
|
900
|
+
|
|
901
|
+
if (start < 0 || end <= start) {
|
|
902
|
+
return null;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
try {
|
|
906
|
+
return JSON.parse(value.slice(start, end + 1));
|
|
907
|
+
} catch {
|
|
908
|
+
return null;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
function summarizeBootText(value) {
|
|
913
|
+
if (typeof value !== "string") {
|
|
914
|
+
return "";
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
return value.replace(/\s+/g, " ").trim().slice(0, 96);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
function numberOrZero(value) {
|
|
921
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
function isRecord(value) {
|
|
925
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
926
|
+
}
|
|
927
|
+
|
|
468
928
|
function parseStartArgs(rawArgs) {
|
|
469
929
|
const envPort = process.env.AGENTOS_PORT || process.env.PORT;
|
|
470
930
|
const options = {
|
|
471
931
|
host: process.env.AGENTOS_HOST || "127.0.0.1",
|
|
472
932
|
port: envPort && /^\d+$/.test(envPort) ? Number(envPort) : 3000,
|
|
473
|
-
open: parseBooleanEnv(process.env.AGENTOS_OPEN)
|
|
933
|
+
open: parseBooleanEnv(process.env.AGENTOS_OPEN),
|
|
934
|
+
plain: false
|
|
474
935
|
};
|
|
475
936
|
|
|
476
937
|
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
@@ -516,6 +977,57 @@ function parseStartArgs(rawArgs) {
|
|
|
516
977
|
continue;
|
|
517
978
|
}
|
|
518
979
|
|
|
980
|
+
if (arg === "--plain") {
|
|
981
|
+
options.plain = true;
|
|
982
|
+
continue;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
return options;
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
function parseStatusArgs(rawArgs) {
|
|
992
|
+
const envPort = process.env.AGENTOS_PORT || process.env.PORT;
|
|
993
|
+
const options = {
|
|
994
|
+
host: process.env.AGENTOS_HOST || "127.0.0.1",
|
|
995
|
+
port: envPort && /^\d+$/.test(envPort) ? Number(envPort) : 3000
|
|
996
|
+
};
|
|
997
|
+
|
|
998
|
+
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
999
|
+
const arg = rawArgs[index];
|
|
1000
|
+
|
|
1001
|
+
if (arg === "--port" || arg === "-p") {
|
|
1002
|
+
const value = rawArgs[index + 1];
|
|
1003
|
+
index += 1;
|
|
1004
|
+
assertPort(value);
|
|
1005
|
+
options.port = Number(value);
|
|
1006
|
+
continue;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
if (arg.startsWith("--port=")) {
|
|
1010
|
+
const value = arg.slice("--port=".length);
|
|
1011
|
+
assertPort(value);
|
|
1012
|
+
options.port = Number(value);
|
|
1013
|
+
continue;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
if (arg === "--host" || arg === "-H") {
|
|
1017
|
+
const value = rawArgs[index + 1];
|
|
1018
|
+
index += 1;
|
|
1019
|
+
assertHost(value);
|
|
1020
|
+
options.host = value;
|
|
1021
|
+
continue;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
if (arg.startsWith("--host=")) {
|
|
1025
|
+
const value = arg.slice("--host=".length);
|
|
1026
|
+
assertHost(value);
|
|
1027
|
+
options.host = value;
|
|
1028
|
+
continue;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
519
1031
|
throw new Error(`Unknown argument: ${arg}`);
|
|
520
1032
|
}
|
|
521
1033
|
|
|
@@ -798,6 +1310,8 @@ function printHelp() {
|
|
|
798
1310
|
Usage:
|
|
799
1311
|
agentos
|
|
800
1312
|
agentos start --port 3000 --host 127.0.0.1 --open
|
|
1313
|
+
agentos dev --plain
|
|
1314
|
+
agentos status
|
|
801
1315
|
agentos update [--check]
|
|
802
1316
|
agentos stop --port 3000 [--force]
|
|
803
1317
|
agentos doctor
|
|
@@ -809,11 +1323,27 @@ Options:
|
|
|
809
1323
|
start: --host, -H Host to bind the local server (default: 127.0.0.1)
|
|
810
1324
|
start: --open, -o Open AgentOS in the default browser after startup or reuse an existing instance
|
|
811
1325
|
start: --no-open Disable browser auto-open even if AGENTOS_OPEN is set
|
|
1326
|
+
start: --plain Disable the AgentOS boot splash and live startup UI
|
|
1327
|
+
status: --port, -p Port to inspect (default: 3000)
|
|
1328
|
+
status: --host, -H Host to display when no runtime state exists (default: 127.0.0.1)
|
|
812
1329
|
stop: --port, -p Port to stop (default: 3000)
|
|
813
1330
|
stop: --force, -f Send SIGKILL if SIGTERM does not stop the server
|
|
814
1331
|
`);
|
|
815
1332
|
}
|
|
816
1333
|
|
|
1334
|
+
function printStatusHelp() {
|
|
1335
|
+
console.log(`Show the local AgentOS runtime dashboard.
|
|
1336
|
+
|
|
1337
|
+
Usage:
|
|
1338
|
+
agentos status
|
|
1339
|
+
agentos status --port 3000 --host 127.0.0.1
|
|
1340
|
+
|
|
1341
|
+
Options:
|
|
1342
|
+
--port, -p Port to inspect (default: 3000)
|
|
1343
|
+
--host, -H Host to display when no runtime state exists (default: 127.0.0.1)
|
|
1344
|
+
`);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
817
1347
|
function printStopHelp() {
|
|
818
1348
|
console.log(`Stop a running AgentOS server.
|
|
819
1349
|
|
|
@@ -840,22 +1370,41 @@ Options:
|
|
|
840
1370
|
`);
|
|
841
1371
|
}
|
|
842
1372
|
|
|
843
|
-
function createRelay(target,
|
|
1373
|
+
function createRelay(target, boot, startupState, onServerReady) {
|
|
844
1374
|
return (chunk) => {
|
|
845
1375
|
const text = chunk.toString();
|
|
846
|
-
|
|
1376
|
+
const ready = isServerReadyOutput(text);
|
|
1377
|
+
|
|
1378
|
+
if (ready) {
|
|
1379
|
+
onServerReady();
|
|
1380
|
+
}
|
|
847
1381
|
|
|
848
|
-
if (
|
|
1382
|
+
if (boot.isPlain() || startupState.completed) {
|
|
1383
|
+
target.write(text);
|
|
849
1384
|
return;
|
|
850
1385
|
}
|
|
851
1386
|
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
1387
|
+
startupState.bufferedLogs.push({
|
|
1388
|
+
target,
|
|
1389
|
+
text
|
|
1390
|
+
});
|
|
1391
|
+
|
|
1392
|
+
if (target === process.stderr) {
|
|
1393
|
+
boot.warn(text);
|
|
1394
|
+
} else if (isImportantStartupLog(text)) {
|
|
1395
|
+
boot.log(text);
|
|
855
1396
|
}
|
|
856
1397
|
};
|
|
857
1398
|
}
|
|
858
1399
|
|
|
1400
|
+
function isServerReadyOutput(text) {
|
|
1401
|
+
return text.includes("Ready in") || text.includes("Local:");
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
function isImportantStartupLog(text) {
|
|
1405
|
+
return /\b(warn|warning|error|failed|exception|EADDRINUSE|EACCES)\b/i.test(text);
|
|
1406
|
+
}
|
|
1407
|
+
|
|
859
1408
|
function printUpdateStatus(status, options = {}) {
|
|
860
1409
|
if (status.updateAvailable) {
|
|
861
1410
|
console.log(`Update available: ${status.currentVersion} -> ${status.latestVersion}.`);
|