@sapienx/agentos 0.5.3 → 0.5.5
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 +477 -31
- package/bin/terminal-boot.js +618 -0
- package/bundle/.next/BUILD_ID +1 -1
- package/bundle/.next/app-path-routes-manifest.json +8 -8
- 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 +6 -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 +8 -8
- 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 +4 -4
- 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 → tsDQB0DKe1D5mWm-AHkYf}/_buildManifest.js +0 -0
- /package/bundle/.next/static/{easVJgXM2ae2U4xGhNmSj → tsDQB0DKe1D5mWm-AHkYf}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -29,6 +29,7 @@ agentos update
|
|
|
29
29
|
agentos update --check
|
|
30
30
|
agentos stop
|
|
31
31
|
agentos stop --port 3000 --force
|
|
32
|
+
agentos status
|
|
32
33
|
agentos doctor
|
|
33
34
|
agentos uninstall
|
|
34
35
|
```
|
|
@@ -41,7 +42,9 @@ AGENTOS_PORT=3000
|
|
|
41
42
|
AGENTOS_OPEN=1
|
|
42
43
|
```
|
|
43
44
|
|
|
44
|
-
`agentos
|
|
45
|
+
`agentos status` prints a concise local dashboard for Gateway, runtime, model, channel, and server readiness.
|
|
46
|
+
|
|
47
|
+
`agentos doctor` prints deeper install diagnostics: effective URL, bundle status, Node.js compatibility, OpenClaw detection, Gateway reachability, and browser auto-open support.
|
|
45
48
|
|
|
46
49
|
`agentos stop` sends `SIGTERM` to the AgentOS server listening on the selected port. If the runtime state is stale and no process is listening there, the CLI clears that stale state automatically.
|
|
47
50
|
|
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,34 @@ 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 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
|
+
boot.start();
|
|
175
|
+
boot.updateStatus("workspaceEngine", "loading", "bundle ready");
|
|
176
|
+
applyOpenClawBootStatus(boot, openClawCheck);
|
|
152
177
|
}
|
|
153
178
|
|
|
154
179
|
if (options.open && !browserOpener.available) {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
180
|
+
const message = `Browser auto-open is unavailable on this machine${browserOpener.detail ? ` (${browserOpener.detail})` : ""}.`;
|
|
181
|
+
if (boot.isPlain()) {
|
|
182
|
+
console.warn(message);
|
|
183
|
+
} else {
|
|
184
|
+
boot.warn(message);
|
|
185
|
+
}
|
|
158
186
|
}
|
|
159
187
|
|
|
160
188
|
const child = spawn(process.execPath, [bundledServerPath], {
|
|
@@ -187,14 +215,46 @@ async function startServer(rawArgs) {
|
|
|
187
215
|
throw error;
|
|
188
216
|
}
|
|
189
217
|
|
|
218
|
+
if (!boot.isPlain()) {
|
|
219
|
+
boot.updateStatus("workspaceEngine", "ready", "runtime state written");
|
|
220
|
+
boot.updateStatus("agentRuntime", "starting", `pid ${child.pid}`);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const startupState = {
|
|
224
|
+
ready: false,
|
|
225
|
+
completing: false,
|
|
226
|
+
completed: boot.isPlain(),
|
|
227
|
+
bufferedLogs: []
|
|
228
|
+
};
|
|
190
229
|
const browserState = { opened: false };
|
|
191
|
-
const
|
|
192
|
-
|
|
230
|
+
const onServerReady = () => {
|
|
231
|
+
if (startupState.ready) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
startupState.ready = true;
|
|
236
|
+
|
|
237
|
+
if (options.open && browserOpener.available && !browserState.opened) {
|
|
238
|
+
browserState.opened = true;
|
|
239
|
+
openBrowser(url, browserOpener);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (boot.isPlain()) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
startupState.completing = true;
|
|
247
|
+
void completeBootAfterServerReady(boot, startupState, url);
|
|
248
|
+
};
|
|
249
|
+
const relayStdout = createRelay(process.stdout, boot, startupState, onServerReady);
|
|
250
|
+
const relayStderr = createRelay(process.stderr, boot, startupState, onServerReady);
|
|
193
251
|
|
|
194
252
|
child.stdout.on("data", relayStdout);
|
|
195
253
|
child.stderr.on("data", relayStderr);
|
|
196
254
|
|
|
197
|
-
|
|
255
|
+
if (boot.isPlain()) {
|
|
256
|
+
schedulePassiveUpdateNotice();
|
|
257
|
+
}
|
|
198
258
|
|
|
199
259
|
let cleanedUp = false;
|
|
200
260
|
const shutdownState = {
|
|
@@ -227,8 +287,12 @@ async function startServer(rawArgs) {
|
|
|
227
287
|
shutdownState.parentSignal = signal;
|
|
228
288
|
|
|
229
289
|
if (signal === "SIGINT") {
|
|
290
|
+
boot.stop({ clear: true });
|
|
291
|
+
flushBufferedStartupLogs(startupState);
|
|
230
292
|
process.stdout.write("\nStopping AgentOS... Press Ctrl+C again to force quit.\n");
|
|
231
293
|
} else {
|
|
294
|
+
boot.stop({ clear: true });
|
|
295
|
+
flushBufferedStartupLogs(startupState);
|
|
232
296
|
console.log(`Stopping AgentOS after ${signal}...`);
|
|
233
297
|
}
|
|
234
298
|
|
|
@@ -247,6 +311,8 @@ async function startServer(rawArgs) {
|
|
|
247
311
|
|
|
248
312
|
child.on("error", (error) => {
|
|
249
313
|
cleanup();
|
|
314
|
+
boot.stop({ clear: true });
|
|
315
|
+
flushBufferedStartupLogs(startupState);
|
|
250
316
|
console.error(`AgentOS failed to start: ${error.message}`);
|
|
251
317
|
process.exit(1);
|
|
252
318
|
});
|
|
@@ -254,6 +320,11 @@ async function startServer(rawArgs) {
|
|
|
254
320
|
child.on("exit", (code, signal) => {
|
|
255
321
|
cleanup();
|
|
256
322
|
|
|
323
|
+
if (!startupState.completed) {
|
|
324
|
+
boot.stop({ clear: true });
|
|
325
|
+
flushBufferedStartupLogs(startupState);
|
|
326
|
+
}
|
|
327
|
+
|
|
257
328
|
if (shutdownState.parentSignal) {
|
|
258
329
|
process.kill(process.pid, shutdownState.parentSignal);
|
|
259
330
|
return;
|
|
@@ -271,55 +342,63 @@ async function startServer(rawArgs) {
|
|
|
271
342
|
function runDoctor() {
|
|
272
343
|
const options = parseStartArgs([]);
|
|
273
344
|
const openClawCheck = detectOpenClaw();
|
|
345
|
+
const gatewayStatus = openClawCheck.available ? inspectOpenClawGatewayStatus(openClawCheck) : null;
|
|
274
346
|
const browserOpener = detectBrowserOpener();
|
|
275
347
|
const targetUrl = `http://${displayHost(options.host)}:${options.port}`;
|
|
276
348
|
const checks = [
|
|
277
349
|
{
|
|
278
|
-
|
|
350
|
+
state: "ok",
|
|
279
351
|
label: "Package",
|
|
280
352
|
detail: `${packageJson.name}@${packageJson.version}`
|
|
281
353
|
},
|
|
282
354
|
{
|
|
283
|
-
|
|
355
|
+
state: "ok",
|
|
284
356
|
label: "Install",
|
|
285
357
|
detail: formatInstallKind(inspectInstallation())
|
|
286
358
|
},
|
|
287
359
|
{
|
|
288
|
-
|
|
360
|
+
state: isSupportedNodeVersion(process.versions.node) ? "ok" : "failed",
|
|
289
361
|
label: "Node.js",
|
|
290
362
|
detail: `${process.version} (required >= 20.9.0)`
|
|
291
363
|
},
|
|
292
364
|
{
|
|
293
|
-
|
|
365
|
+
state: "ok",
|
|
294
366
|
label: "Platform",
|
|
295
367
|
detail: `${os.platform()} ${os.release()}`
|
|
296
368
|
},
|
|
297
369
|
{
|
|
298
|
-
|
|
370
|
+
state: existsSync(bundledServerPath) ? "ok" : "failed",
|
|
299
371
|
label: "Bundle",
|
|
300
372
|
detail: existsSync(bundledServerPath)
|
|
301
373
|
? `ready at ${bundledServerPath}`
|
|
302
374
|
: `missing at ${bundledServerPath}`
|
|
303
375
|
},
|
|
304
376
|
{
|
|
305
|
-
|
|
377
|
+
state: "ok",
|
|
306
378
|
label: "Target URL",
|
|
307
379
|
detail: targetUrl
|
|
308
380
|
},
|
|
309
381
|
{
|
|
310
|
-
|
|
382
|
+
state: "ok",
|
|
311
383
|
label: "Configured env",
|
|
312
384
|
detail: formatConfiguredEnv(options)
|
|
313
385
|
},
|
|
314
386
|
{
|
|
315
|
-
|
|
387
|
+
state: openClawCheck.available ? "ok" : "warning",
|
|
316
388
|
label: "OpenClaw",
|
|
317
389
|
detail: openClawCheck.available
|
|
318
390
|
? `${openClawCheck.version || "installed"}${openClawCheck.path ? ` at ${openClawCheck.path}` : ""}`
|
|
319
391
|
: "not found in PATH or default local install paths; install OpenClaw or continue with the AgentOS onboarding flow"
|
|
320
392
|
},
|
|
321
393
|
{
|
|
322
|
-
|
|
394
|
+
state: !openClawCheck.available ? "disabled" : gatewayStatus?.ok ? "ok" : "warning",
|
|
395
|
+
label: "Gateway",
|
|
396
|
+
detail: !openClawCheck.available
|
|
397
|
+
? "OpenClaw is required before Gateway RPC can be checked"
|
|
398
|
+
: gatewayStatus?.gatewayMessage || "Gateway status unavailable"
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
state: browserOpener.available ? "ok" : "warning",
|
|
323
402
|
label: "Browser opener",
|
|
324
403
|
detail: browserOpener.available
|
|
325
404
|
? `${browserOpener.command} is available`
|
|
@@ -327,11 +406,83 @@ function runDoctor() {
|
|
|
327
406
|
}
|
|
328
407
|
];
|
|
329
408
|
|
|
330
|
-
|
|
331
|
-
|
|
409
|
+
console.log(renderDoctorReport({
|
|
410
|
+
title: "AGENTOS DOCTOR",
|
|
411
|
+
rows: checks.map((check) => ({
|
|
412
|
+
label: check.label,
|
|
413
|
+
state: check.state,
|
|
414
|
+
message: check.detail
|
|
415
|
+
})),
|
|
416
|
+
footer: "Doctor shows install and runtime diagnostics. The in-app diagnostics panel has live Gateway/model detail."
|
|
417
|
+
}));
|
|
418
|
+
|
|
419
|
+
if (checks.some((check) => check.state === "failed")) {
|
|
420
|
+
process.exitCode = 1;
|
|
332
421
|
}
|
|
422
|
+
}
|
|
333
423
|
|
|
334
|
-
|
|
424
|
+
function runStatus(rawArgs) {
|
|
425
|
+
const options = parseStatusArgs(rawArgs);
|
|
426
|
+
const runtimeStatePath = resolveRuntimeStatePath(options.port);
|
|
427
|
+
const trackedState = readRuntimeState(runtimeStatePath);
|
|
428
|
+
const listeningPid = findListeningPidForPort(options.port);
|
|
429
|
+
const trackedPid = trackedState?.pid && isProcessRunning(trackedState.pid) ? trackedState.pid : null;
|
|
430
|
+
const runningPid = listeningPid ?? trackedPid;
|
|
431
|
+
const host = trackedState?.host || options.host;
|
|
432
|
+
const url = createAgentOsUrl(host, options.port);
|
|
433
|
+
const openClawCheck = detectOpenClaw();
|
|
434
|
+
const gatewayStatus = openClawCheck.available ? inspectOpenClawGatewayStatus(openClawCheck) : null;
|
|
435
|
+
const bundleReady = existsSync(bundledServerPath);
|
|
436
|
+
const rows = [
|
|
437
|
+
{
|
|
438
|
+
label: "OpenClaw Gateway",
|
|
439
|
+
state: !openClawCheck.available ? "warning" : gatewayStatus?.ok ? "connected" : "degraded",
|
|
440
|
+
message: !openClawCheck.available
|
|
441
|
+
? "OpenClaw not found; setup will guide installation"
|
|
442
|
+
: gatewayStatus?.gatewayMessage || "needs attention"
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
label: "Native Gateway",
|
|
446
|
+
state: !openClawCheck.available ? "disabled" : gatewayStatus?.nativeState || "warning",
|
|
447
|
+
message: !openClawCheck.available
|
|
448
|
+
? "waiting for OpenClaw"
|
|
449
|
+
: gatewayStatus?.nativeMessage || "check Gateway diagnostics"
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
label: "Workspace Engine",
|
|
453
|
+
state: bundleReady ? "ready" : "failed",
|
|
454
|
+
message: bundleReady ? "bundle ready" : "bundle missing"
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
label: "Agent Runtime",
|
|
458
|
+
state: runningPid ? "ready" : "inactive",
|
|
459
|
+
message: runningPid ? `server running (PID ${runningPid})` : "server not running"
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
label: "Models",
|
|
463
|
+
state: runningPid ? "warning" : "pending",
|
|
464
|
+
message: runningPid ? "verify in setup or diagnostics" : "available after server start"
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
label: "Channels",
|
|
468
|
+
state: "disabled",
|
|
469
|
+
message: "no channel status loaded from CLI"
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
label: "Local Server",
|
|
473
|
+
state: runningPid ? "ready" : "pending",
|
|
474
|
+
message: url
|
|
475
|
+
}
|
|
476
|
+
];
|
|
477
|
+
|
|
478
|
+
console.log(renderStatusDashboard({
|
|
479
|
+
title: "SYSTEM CHECK",
|
|
480
|
+
rows,
|
|
481
|
+
finalInfo: runningPid ? url : "",
|
|
482
|
+
footer: runningPid ? "" : "AgentOS is not running. Start it with agentos start --open."
|
|
483
|
+
}));
|
|
484
|
+
|
|
485
|
+
if (!bundleReady) {
|
|
335
486
|
process.exitCode = 1;
|
|
336
487
|
}
|
|
337
488
|
}
|
|
@@ -465,12 +616,219 @@ async function runStop(rawArgs) {
|
|
|
465
616
|
console.log(`Stopped AgentOS on port ${options.port}.`);
|
|
466
617
|
}
|
|
467
618
|
|
|
619
|
+
function applyOpenClawBootStatus(boot, openClawCheck) {
|
|
620
|
+
if (!openClawCheck.available) {
|
|
621
|
+
boot.updateStatus("openclawGateway", "warning", "OpenClaw not found; onboarding will guide setup");
|
|
622
|
+
boot.updateStatus("nativeGateway", "disabled", "waiting for OpenClaw");
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
boot.updateStatus("openclawGateway", "checking", openClawCheck.version || "OpenClaw detected");
|
|
627
|
+
boot.updateStatus("nativeGateway", "waiting", "probing gateway");
|
|
628
|
+
|
|
629
|
+
const gatewayStatus = inspectOpenClawGatewayStatus(openClawCheck);
|
|
630
|
+
|
|
631
|
+
if (gatewayStatus.ok) {
|
|
632
|
+
boot.updateStatus("openclawGateway", "connected", gatewayStatus.gatewayMessage);
|
|
633
|
+
boot.updateStatus("nativeGateway", gatewayStatus.nativeState, gatewayStatus.nativeMessage);
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
boot.updateStatus("openclawGateway", "warning", gatewayStatus.gatewayMessage);
|
|
638
|
+
boot.updateStatus("nativeGateway", "disabled", gatewayStatus.nativeMessage);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function inspectOpenClawGatewayStatus(openClawCheck) {
|
|
642
|
+
const command = openClawCheck.path || "openclaw";
|
|
643
|
+
const result = spawnSync(command, ["gateway", "status", "--json"], {
|
|
644
|
+
encoding: "utf8",
|
|
645
|
+
timeout: 1_500
|
|
646
|
+
});
|
|
647
|
+
const output = `${result.stdout || ""}\n${result.stderr || ""}`.trim();
|
|
648
|
+
|
|
649
|
+
if (result.error) {
|
|
650
|
+
return {
|
|
651
|
+
ok: false,
|
|
652
|
+
gatewayMessage: result.error.code === "ETIMEDOUT" ? "gateway probe timed out" : "gateway status unavailable",
|
|
653
|
+
nativeMessage: "Gateway will be checked in the UI",
|
|
654
|
+
nativeState: "disabled"
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
if (result.status !== 0) {
|
|
659
|
+
return {
|
|
660
|
+
ok: false,
|
|
661
|
+
gatewayMessage: summarizeBootText(output) || "gateway not reachable yet",
|
|
662
|
+
nativeMessage: "start or repair OpenClaw Gateway in setup",
|
|
663
|
+
nativeState: "disabled"
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
const parsed = parseFirstJsonObject(output);
|
|
668
|
+
const capability = String(parsed?.capability || parsed?.Capability || "");
|
|
669
|
+
const connected = /connected|ok|reachable/i.test(output);
|
|
670
|
+
const missingOperatorScope = /no-operator-scope|operator scope/i.test(capability || output);
|
|
671
|
+
|
|
672
|
+
return {
|
|
673
|
+
ok: true,
|
|
674
|
+
gatewayMessage: connected ? "reachable" : "status available",
|
|
675
|
+
nativeState: missingOperatorScope ? "warning" : "active",
|
|
676
|
+
nativeMessage: missingOperatorScope ? "operator scope needs repair" : "native RPC available"
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
async function completeBootAfterServerReady(boot, startupState, url) {
|
|
681
|
+
boot.updateStatus("agentRuntime", "ready", "server ready");
|
|
682
|
+
boot.updateStatus("localServerUrl", "ready", url);
|
|
683
|
+
boot.updateStatus("models", "loading", "checking readiness");
|
|
684
|
+
boot.updateStatus("channels", "loading", "checking registry");
|
|
685
|
+
|
|
686
|
+
const readiness = await readStartupReadiness(url);
|
|
687
|
+
|
|
688
|
+
if (readiness.openClawGateway) {
|
|
689
|
+
boot.updateStatus("openclawGateway", readiness.openClawGateway.state, readiness.openClawGateway.message);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
if (readiness.nativeGateway) {
|
|
693
|
+
boot.updateStatus("nativeGateway", readiness.nativeGateway.state, readiness.nativeGateway.message);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
boot.updateStatus("workspaceEngine", readiness.workspaceEngine.state, readiness.workspaceEngine.message);
|
|
697
|
+
boot.updateStatus("models", readiness.models.state, readiness.models.message);
|
|
698
|
+
boot.updateStatus("channels", readiness.channels.state, readiness.channels.message);
|
|
699
|
+
boot.complete(url);
|
|
700
|
+
startupState.bufferedLogs = [];
|
|
701
|
+
startupState.completed = true;
|
|
702
|
+
schedulePassiveUpdateNotice();
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
async function readStartupReadiness(url) {
|
|
706
|
+
const fallback = {
|
|
707
|
+
workspaceEngine: { state: "ready", message: "available" },
|
|
708
|
+
models: { state: "warning", message: "finish setup in the UI" },
|
|
709
|
+
channels: { state: "disabled", message: "none confirmed yet" }
|
|
710
|
+
};
|
|
711
|
+
const controller = new AbortController();
|
|
712
|
+
const timeout = setTimeout(() => controller.abort(), 2_500);
|
|
713
|
+
|
|
714
|
+
try {
|
|
715
|
+
const response = await fetch(`${url}/api/snapshot`, {
|
|
716
|
+
signal: controller.signal
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
if (!response.ok) {
|
|
720
|
+
return fallback;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
const snapshot = await response.json();
|
|
724
|
+
return summarizeStartupSnapshot(snapshot);
|
|
725
|
+
} catch {
|
|
726
|
+
return fallback;
|
|
727
|
+
} finally {
|
|
728
|
+
clearTimeout(timeout);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
function summarizeStartupSnapshot(snapshot) {
|
|
733
|
+
const diagnostics = isRecord(snapshot?.diagnostics) ? snapshot.diagnostics : {};
|
|
734
|
+
const modelReadiness = isRecord(diagnostics.modelReadiness) ? diagnostics.modelReadiness : {};
|
|
735
|
+
const transport = isRecord(diagnostics.transport) ? diagnostics.transport : {};
|
|
736
|
+
const workspaces = Array.isArray(snapshot?.workspaces) ? snapshot.workspaces : [];
|
|
737
|
+
const channelAccounts = Array.isArray(snapshot?.channelAccounts) ? snapshot.channelAccounts : [];
|
|
738
|
+
const channelRegistry = isRecord(snapshot?.channelRegistry) && Array.isArray(snapshot.channelRegistry.channels)
|
|
739
|
+
? snapshot.channelRegistry.channels
|
|
740
|
+
: [];
|
|
741
|
+
const rpcOk = diagnostics.rpcOk === true;
|
|
742
|
+
const modelReady = modelReadiness.ready === true || modelReadiness.defaultModelReady === true;
|
|
743
|
+
const availableModelCount = numberOrZero(modelReadiness.availableModelCount);
|
|
744
|
+
const modelIssues = Array.isArray(modelReadiness.issues) ? modelReadiness.issues.filter(Boolean) : [];
|
|
745
|
+
const enabledChannels = channelAccounts.filter((channel) => channel && channel.enabled !== false).length + channelRegistry.length;
|
|
746
|
+
const transportStatus = typeof transport.gatewayMode === "string"
|
|
747
|
+
? transport.gatewayMode
|
|
748
|
+
: typeof transport.statusLabel === "string"
|
|
749
|
+
? transport.statusLabel
|
|
750
|
+
: "";
|
|
751
|
+
|
|
752
|
+
return {
|
|
753
|
+
openClawGateway: {
|
|
754
|
+
state: rpcOk ? "connected" : "warning",
|
|
755
|
+
message: rpcOk ? "authenticated RPC ready" : summarizeBootText(diagnostics.health) || "setup may be required"
|
|
756
|
+
},
|
|
757
|
+
nativeGateway: {
|
|
758
|
+
state: rpcOk ? "active" : "warning",
|
|
759
|
+
message: transportStatus || (rpcOk ? "native Gateway active" : "check diagnostics")
|
|
760
|
+
},
|
|
761
|
+
workspaceEngine: {
|
|
762
|
+
state: "ready",
|
|
763
|
+
message: workspaces.length > 0 ? `${workspaces.length} workspace${workspaces.length === 1 ? "" : "s"}` : "ready for first workspace"
|
|
764
|
+
},
|
|
765
|
+
models: {
|
|
766
|
+
state: modelReady || availableModelCount > 0 ? "ready" : "warning",
|
|
767
|
+
message: modelReady
|
|
768
|
+
? modelReadiness.resolvedDefaultModel || modelReadiness.defaultModel || "default model ready"
|
|
769
|
+
: modelIssues[0] || "model setup needed"
|
|
770
|
+
},
|
|
771
|
+
channels: {
|
|
772
|
+
state: enabledChannels > 0 ? "ready" : "disabled",
|
|
773
|
+
message: enabledChannels > 0 ? `${enabledChannels} configured` : "no channels configured"
|
|
774
|
+
}
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
function flushBufferedStartupLogs(startupState) {
|
|
779
|
+
if (!startupState?.bufferedLogs?.length) {
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
for (const entry of startupState.bufferedLogs) {
|
|
784
|
+
entry.target.write(entry.text);
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
startupState.bufferedLogs = [];
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
function parseFirstJsonObject(value) {
|
|
791
|
+
if (!value) {
|
|
792
|
+
return null;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
const start = value.indexOf("{");
|
|
796
|
+
const end = value.lastIndexOf("}");
|
|
797
|
+
|
|
798
|
+
if (start < 0 || end <= start) {
|
|
799
|
+
return null;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
try {
|
|
803
|
+
return JSON.parse(value.slice(start, end + 1));
|
|
804
|
+
} catch {
|
|
805
|
+
return null;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
function summarizeBootText(value) {
|
|
810
|
+
if (typeof value !== "string") {
|
|
811
|
+
return "";
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
return value.replace(/\s+/g, " ").trim().slice(0, 96);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
function numberOrZero(value) {
|
|
818
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
function isRecord(value) {
|
|
822
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
823
|
+
}
|
|
824
|
+
|
|
468
825
|
function parseStartArgs(rawArgs) {
|
|
469
826
|
const envPort = process.env.AGENTOS_PORT || process.env.PORT;
|
|
470
827
|
const options = {
|
|
471
828
|
host: process.env.AGENTOS_HOST || "127.0.0.1",
|
|
472
829
|
port: envPort && /^\d+$/.test(envPort) ? Number(envPort) : 3000,
|
|
473
|
-
open: parseBooleanEnv(process.env.AGENTOS_OPEN)
|
|
830
|
+
open: parseBooleanEnv(process.env.AGENTOS_OPEN),
|
|
831
|
+
plain: false
|
|
474
832
|
};
|
|
475
833
|
|
|
476
834
|
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
@@ -516,6 +874,57 @@ function parseStartArgs(rawArgs) {
|
|
|
516
874
|
continue;
|
|
517
875
|
}
|
|
518
876
|
|
|
877
|
+
if (arg === "--plain") {
|
|
878
|
+
options.plain = true;
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
return options;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
function parseStatusArgs(rawArgs) {
|
|
889
|
+
const envPort = process.env.AGENTOS_PORT || process.env.PORT;
|
|
890
|
+
const options = {
|
|
891
|
+
host: process.env.AGENTOS_HOST || "127.0.0.1",
|
|
892
|
+
port: envPort && /^\d+$/.test(envPort) ? Number(envPort) : 3000
|
|
893
|
+
};
|
|
894
|
+
|
|
895
|
+
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
896
|
+
const arg = rawArgs[index];
|
|
897
|
+
|
|
898
|
+
if (arg === "--port" || arg === "-p") {
|
|
899
|
+
const value = rawArgs[index + 1];
|
|
900
|
+
index += 1;
|
|
901
|
+
assertPort(value);
|
|
902
|
+
options.port = Number(value);
|
|
903
|
+
continue;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
if (arg.startsWith("--port=")) {
|
|
907
|
+
const value = arg.slice("--port=".length);
|
|
908
|
+
assertPort(value);
|
|
909
|
+
options.port = Number(value);
|
|
910
|
+
continue;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
if (arg === "--host" || arg === "-H") {
|
|
914
|
+
const value = rawArgs[index + 1];
|
|
915
|
+
index += 1;
|
|
916
|
+
assertHost(value);
|
|
917
|
+
options.host = value;
|
|
918
|
+
continue;
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
if (arg.startsWith("--host=")) {
|
|
922
|
+
const value = arg.slice("--host=".length);
|
|
923
|
+
assertHost(value);
|
|
924
|
+
options.host = value;
|
|
925
|
+
continue;
|
|
926
|
+
}
|
|
927
|
+
|
|
519
928
|
throw new Error(`Unknown argument: ${arg}`);
|
|
520
929
|
}
|
|
521
930
|
|
|
@@ -798,6 +1207,8 @@ function printHelp() {
|
|
|
798
1207
|
Usage:
|
|
799
1208
|
agentos
|
|
800
1209
|
agentos start --port 3000 --host 127.0.0.1 --open
|
|
1210
|
+
agentos dev --plain
|
|
1211
|
+
agentos status
|
|
801
1212
|
agentos update [--check]
|
|
802
1213
|
agentos stop --port 3000 [--force]
|
|
803
1214
|
agentos doctor
|
|
@@ -809,11 +1220,27 @@ Options:
|
|
|
809
1220
|
start: --host, -H Host to bind the local server (default: 127.0.0.1)
|
|
810
1221
|
start: --open, -o Open AgentOS in the default browser after startup or reuse an existing instance
|
|
811
1222
|
start: --no-open Disable browser auto-open even if AGENTOS_OPEN is set
|
|
1223
|
+
start: --plain Disable the AgentOS boot splash and live startup UI
|
|
1224
|
+
status: --port, -p Port to inspect (default: 3000)
|
|
1225
|
+
status: --host, -H Host to display when no runtime state exists (default: 127.0.0.1)
|
|
812
1226
|
stop: --port, -p Port to stop (default: 3000)
|
|
813
1227
|
stop: --force, -f Send SIGKILL if SIGTERM does not stop the server
|
|
814
1228
|
`);
|
|
815
1229
|
}
|
|
816
1230
|
|
|
1231
|
+
function printStatusHelp() {
|
|
1232
|
+
console.log(`Show the local AgentOS runtime dashboard.
|
|
1233
|
+
|
|
1234
|
+
Usage:
|
|
1235
|
+
agentos status
|
|
1236
|
+
agentos status --port 3000 --host 127.0.0.1
|
|
1237
|
+
|
|
1238
|
+
Options:
|
|
1239
|
+
--port, -p Port to inspect (default: 3000)
|
|
1240
|
+
--host, -H Host to display when no runtime state exists (default: 127.0.0.1)
|
|
1241
|
+
`);
|
|
1242
|
+
}
|
|
1243
|
+
|
|
817
1244
|
function printStopHelp() {
|
|
818
1245
|
console.log(`Stop a running AgentOS server.
|
|
819
1246
|
|
|
@@ -840,22 +1267,41 @@ Options:
|
|
|
840
1267
|
`);
|
|
841
1268
|
}
|
|
842
1269
|
|
|
843
|
-
function createRelay(target,
|
|
1270
|
+
function createRelay(target, boot, startupState, onServerReady) {
|
|
844
1271
|
return (chunk) => {
|
|
845
1272
|
const text = chunk.toString();
|
|
846
|
-
|
|
1273
|
+
const ready = isServerReadyOutput(text);
|
|
847
1274
|
|
|
848
|
-
if (
|
|
1275
|
+
if (ready) {
|
|
1276
|
+
onServerReady();
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
if (boot.isPlain() || startupState.completed) {
|
|
1280
|
+
target.write(text);
|
|
849
1281
|
return;
|
|
850
1282
|
}
|
|
851
1283
|
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
1284
|
+
startupState.bufferedLogs.push({
|
|
1285
|
+
target,
|
|
1286
|
+
text
|
|
1287
|
+
});
|
|
1288
|
+
|
|
1289
|
+
if (target === process.stderr) {
|
|
1290
|
+
boot.warn(text);
|
|
1291
|
+
} else if (isImportantStartupLog(text)) {
|
|
1292
|
+
boot.log(text);
|
|
855
1293
|
}
|
|
856
1294
|
};
|
|
857
1295
|
}
|
|
858
1296
|
|
|
1297
|
+
function isServerReadyOutput(text) {
|
|
1298
|
+
return text.includes("Ready in") || text.includes("Local:");
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
function isImportantStartupLog(text) {
|
|
1302
|
+
return /\b(warn|warning|error|failed|exception|EADDRINUSE|EACCES)\b/i.test(text);
|
|
1303
|
+
}
|
|
1304
|
+
|
|
859
1305
|
function printUpdateStatus(status, options = {}) {
|
|
860
1306
|
if (status.updateAvailable) {
|
|
861
1307
|
console.log(`Update available: ${status.currentVersion} -> ${status.latestVersion}.`);
|