@sapienx/agentos 0.5.2 → 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 +498 -32
- package/bin/terminal-boot.js +618 -0
- package/bundle/.next/BUILD_ID +1 -1
- package/bundle/.next/app-path-routes-manifest.json +11 -11
- 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 +11 -11
- package/bundle/.next/server/chunks/4767.js +11 -11
- package/bundle/.next/server/chunks/5151.js +2 -2
- package/bundle/.next/server/chunks/6639.js +5 -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/package.json +1 -1
- package/bundle/server.js +1 -1
- package/package.json +1 -1
- package/bundle/.next/server/chunks/5831.js +0 -2
- /package/bundle/.next/static/{uAxTxVvm7tdXyEJ7SnLpD → tsDQB0DKe1D5mWm-AHkYf}/_buildManifest.js +0 -0
- /package/bundle/.next/static/{uAxTxVvm7tdXyEJ7SnLpD → tsDQB0DKe1D5mWm-AHkYf}/_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");
|
|
@@ -29,6 +31,16 @@ const updateCacheTtlMs = 24 * 60 * 60 * 1000;
|
|
|
29
31
|
const updateWarningCooldownMs = 24 * 60 * 60 * 1000;
|
|
30
32
|
const updateRequestTimeoutMs = 5_000;
|
|
31
33
|
const cliSmokeTestMode = process.env.AGENTOS_CLI_TEST === "1";
|
|
34
|
+
const bundleRuntimeEnvFiles = [
|
|
35
|
+
".env",
|
|
36
|
+
".env.local",
|
|
37
|
+
".env.development",
|
|
38
|
+
".env.development.local",
|
|
39
|
+
".env.production",
|
|
40
|
+
".env.production.local",
|
|
41
|
+
".env.test",
|
|
42
|
+
".env.test.local"
|
|
43
|
+
];
|
|
32
44
|
|
|
33
45
|
main().catch((error) => {
|
|
34
46
|
console.error(error instanceof Error ? error.message : String(error));
|
|
@@ -59,6 +71,16 @@ async function main() {
|
|
|
59
71
|
return;
|
|
60
72
|
}
|
|
61
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
|
+
|
|
62
84
|
if (firstArg === "update") {
|
|
63
85
|
if (args[1] === "--help" || args[1] === "-h" || args[1] === "help") {
|
|
64
86
|
printUpdateHelp();
|
|
@@ -89,7 +111,7 @@ async function main() {
|
|
|
89
111
|
return;
|
|
90
112
|
}
|
|
91
113
|
|
|
92
|
-
if (firstArg === "start") {
|
|
114
|
+
if (firstArg === "start" || firstArg === "dev") {
|
|
93
115
|
await startServer(args.slice(1));
|
|
94
116
|
return;
|
|
95
117
|
}
|
|
@@ -99,6 +121,7 @@ async function main() {
|
|
|
99
121
|
|
|
100
122
|
async function startServer(rawArgs) {
|
|
101
123
|
ensureBundleExists();
|
|
124
|
+
removeBundleRuntimeEnvFiles();
|
|
102
125
|
|
|
103
126
|
const options = parseStartArgs(rawArgs);
|
|
104
127
|
const runtimeStatePath = resolveRuntimeStatePath(options.port);
|
|
@@ -132,18 +155,34 @@ async function startServer(rawArgs) {
|
|
|
132
155
|
clearRuntimeState(runtimeStatePath);
|
|
133
156
|
}
|
|
134
157
|
|
|
135
|
-
|
|
158
|
+
const boot = createTerminalBoot({
|
|
159
|
+
plain: options.plain,
|
|
160
|
+
stdout: process.stdout,
|
|
161
|
+
stderr: process.stderr,
|
|
162
|
+
env: process.env
|
|
163
|
+
});
|
|
136
164
|
|
|
137
|
-
if (
|
|
138
|
-
console.log(
|
|
139
|
-
|
|
140
|
-
|
|
165
|
+
if (boot.isPlain()) {
|
|
166
|
+
console.log(`Starting AgentOS on ${url}`);
|
|
167
|
+
|
|
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);
|
|
141
177
|
}
|
|
142
178
|
|
|
143
179
|
if (options.open && !browserOpener.available) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
+
}
|
|
147
186
|
}
|
|
148
187
|
|
|
149
188
|
const child = spawn(process.execPath, [bundledServerPath], {
|
|
@@ -152,7 +191,10 @@ async function startServer(rawArgs) {
|
|
|
152
191
|
env: {
|
|
153
192
|
...process.env,
|
|
154
193
|
PORT: String(options.port),
|
|
155
|
-
HOSTNAME: options.host
|
|
194
|
+
HOSTNAME: options.host,
|
|
195
|
+
AGENTOS_PACKAGE_RUNTIME: "1",
|
|
196
|
+
AGENTOS_RUNTIME_DIR: runtimeInstallRoot,
|
|
197
|
+
AGENTOS_BUNDLE_DIR: bundleDir
|
|
156
198
|
}
|
|
157
199
|
});
|
|
158
200
|
|
|
@@ -173,14 +215,46 @@ async function startServer(rawArgs) {
|
|
|
173
215
|
throw error;
|
|
174
216
|
}
|
|
175
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
|
+
};
|
|
176
229
|
const browserState = { opened: false };
|
|
177
|
-
const
|
|
178
|
-
|
|
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);
|
|
179
251
|
|
|
180
252
|
child.stdout.on("data", relayStdout);
|
|
181
253
|
child.stderr.on("data", relayStderr);
|
|
182
254
|
|
|
183
|
-
|
|
255
|
+
if (boot.isPlain()) {
|
|
256
|
+
schedulePassiveUpdateNotice();
|
|
257
|
+
}
|
|
184
258
|
|
|
185
259
|
let cleanedUp = false;
|
|
186
260
|
const shutdownState = {
|
|
@@ -213,8 +287,12 @@ async function startServer(rawArgs) {
|
|
|
213
287
|
shutdownState.parentSignal = signal;
|
|
214
288
|
|
|
215
289
|
if (signal === "SIGINT") {
|
|
290
|
+
boot.stop({ clear: true });
|
|
291
|
+
flushBufferedStartupLogs(startupState);
|
|
216
292
|
process.stdout.write("\nStopping AgentOS... Press Ctrl+C again to force quit.\n");
|
|
217
293
|
} else {
|
|
294
|
+
boot.stop({ clear: true });
|
|
295
|
+
flushBufferedStartupLogs(startupState);
|
|
218
296
|
console.log(`Stopping AgentOS after ${signal}...`);
|
|
219
297
|
}
|
|
220
298
|
|
|
@@ -233,6 +311,8 @@ async function startServer(rawArgs) {
|
|
|
233
311
|
|
|
234
312
|
child.on("error", (error) => {
|
|
235
313
|
cleanup();
|
|
314
|
+
boot.stop({ clear: true });
|
|
315
|
+
flushBufferedStartupLogs(startupState);
|
|
236
316
|
console.error(`AgentOS failed to start: ${error.message}`);
|
|
237
317
|
process.exit(1);
|
|
238
318
|
});
|
|
@@ -240,6 +320,11 @@ async function startServer(rawArgs) {
|
|
|
240
320
|
child.on("exit", (code, signal) => {
|
|
241
321
|
cleanup();
|
|
242
322
|
|
|
323
|
+
if (!startupState.completed) {
|
|
324
|
+
boot.stop({ clear: true });
|
|
325
|
+
flushBufferedStartupLogs(startupState);
|
|
326
|
+
}
|
|
327
|
+
|
|
243
328
|
if (shutdownState.parentSignal) {
|
|
244
329
|
process.kill(process.pid, shutdownState.parentSignal);
|
|
245
330
|
return;
|
|
@@ -257,55 +342,63 @@ async function startServer(rawArgs) {
|
|
|
257
342
|
function runDoctor() {
|
|
258
343
|
const options = parseStartArgs([]);
|
|
259
344
|
const openClawCheck = detectOpenClaw();
|
|
345
|
+
const gatewayStatus = openClawCheck.available ? inspectOpenClawGatewayStatus(openClawCheck) : null;
|
|
260
346
|
const browserOpener = detectBrowserOpener();
|
|
261
347
|
const targetUrl = `http://${displayHost(options.host)}:${options.port}`;
|
|
262
348
|
const checks = [
|
|
263
349
|
{
|
|
264
|
-
|
|
350
|
+
state: "ok",
|
|
265
351
|
label: "Package",
|
|
266
352
|
detail: `${packageJson.name}@${packageJson.version}`
|
|
267
353
|
},
|
|
268
354
|
{
|
|
269
|
-
|
|
355
|
+
state: "ok",
|
|
270
356
|
label: "Install",
|
|
271
357
|
detail: formatInstallKind(inspectInstallation())
|
|
272
358
|
},
|
|
273
359
|
{
|
|
274
|
-
|
|
360
|
+
state: isSupportedNodeVersion(process.versions.node) ? "ok" : "failed",
|
|
275
361
|
label: "Node.js",
|
|
276
362
|
detail: `${process.version} (required >= 20.9.0)`
|
|
277
363
|
},
|
|
278
364
|
{
|
|
279
|
-
|
|
365
|
+
state: "ok",
|
|
280
366
|
label: "Platform",
|
|
281
367
|
detail: `${os.platform()} ${os.release()}`
|
|
282
368
|
},
|
|
283
369
|
{
|
|
284
|
-
|
|
370
|
+
state: existsSync(bundledServerPath) ? "ok" : "failed",
|
|
285
371
|
label: "Bundle",
|
|
286
372
|
detail: existsSync(bundledServerPath)
|
|
287
373
|
? `ready at ${bundledServerPath}`
|
|
288
374
|
: `missing at ${bundledServerPath}`
|
|
289
375
|
},
|
|
290
376
|
{
|
|
291
|
-
|
|
377
|
+
state: "ok",
|
|
292
378
|
label: "Target URL",
|
|
293
379
|
detail: targetUrl
|
|
294
380
|
},
|
|
295
381
|
{
|
|
296
|
-
|
|
382
|
+
state: "ok",
|
|
297
383
|
label: "Configured env",
|
|
298
384
|
detail: formatConfiguredEnv(options)
|
|
299
385
|
},
|
|
300
386
|
{
|
|
301
|
-
|
|
387
|
+
state: openClawCheck.available ? "ok" : "warning",
|
|
302
388
|
label: "OpenClaw",
|
|
303
389
|
detail: openClawCheck.available
|
|
304
390
|
? `${openClawCheck.version || "installed"}${openClawCheck.path ? ` at ${openClawCheck.path}` : ""}`
|
|
305
391
|
: "not found in PATH or default local install paths; install OpenClaw or continue with the AgentOS onboarding flow"
|
|
306
392
|
},
|
|
307
393
|
{
|
|
308
|
-
|
|
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",
|
|
309
402
|
label: "Browser opener",
|
|
310
403
|
detail: browserOpener.available
|
|
311
404
|
? `${browserOpener.command} is available`
|
|
@@ -313,15 +406,93 @@ function runDoctor() {
|
|
|
313
406
|
}
|
|
314
407
|
];
|
|
315
408
|
|
|
316
|
-
|
|
317
|
-
|
|
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;
|
|
318
421
|
}
|
|
422
|
+
}
|
|
319
423
|
|
|
320
|
-
|
|
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) {
|
|
321
486
|
process.exitCode = 1;
|
|
322
487
|
}
|
|
323
488
|
}
|
|
324
489
|
|
|
490
|
+
function removeBundleRuntimeEnvFiles() {
|
|
491
|
+
for (const fileName of bundleRuntimeEnvFiles) {
|
|
492
|
+
rmSync(path.join(bundleDir, fileName), { force: true });
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
325
496
|
async function runUpdate(rawArgs) {
|
|
326
497
|
const options = parseUpdateArgs(rawArgs);
|
|
327
498
|
const install = inspectInstallation();
|
|
@@ -445,12 +616,219 @@ async function runStop(rawArgs) {
|
|
|
445
616
|
console.log(`Stopped AgentOS on port ${options.port}.`);
|
|
446
617
|
}
|
|
447
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
|
+
|
|
448
825
|
function parseStartArgs(rawArgs) {
|
|
449
826
|
const envPort = process.env.AGENTOS_PORT || process.env.PORT;
|
|
450
827
|
const options = {
|
|
451
828
|
host: process.env.AGENTOS_HOST || "127.0.0.1",
|
|
452
829
|
port: envPort && /^\d+$/.test(envPort) ? Number(envPort) : 3000,
|
|
453
|
-
open: parseBooleanEnv(process.env.AGENTOS_OPEN)
|
|
830
|
+
open: parseBooleanEnv(process.env.AGENTOS_OPEN),
|
|
831
|
+
plain: false
|
|
454
832
|
};
|
|
455
833
|
|
|
456
834
|
for (let index = 0; index < rawArgs.length; index += 1) {
|
|
@@ -496,6 +874,57 @@ function parseStartArgs(rawArgs) {
|
|
|
496
874
|
continue;
|
|
497
875
|
}
|
|
498
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
|
+
|
|
499
928
|
throw new Error(`Unknown argument: ${arg}`);
|
|
500
929
|
}
|
|
501
930
|
|
|
@@ -778,6 +1207,8 @@ function printHelp() {
|
|
|
778
1207
|
Usage:
|
|
779
1208
|
agentos
|
|
780
1209
|
agentos start --port 3000 --host 127.0.0.1 --open
|
|
1210
|
+
agentos dev --plain
|
|
1211
|
+
agentos status
|
|
781
1212
|
agentos update [--check]
|
|
782
1213
|
agentos stop --port 3000 [--force]
|
|
783
1214
|
agentos doctor
|
|
@@ -789,11 +1220,27 @@ Options:
|
|
|
789
1220
|
start: --host, -H Host to bind the local server (default: 127.0.0.1)
|
|
790
1221
|
start: --open, -o Open AgentOS in the default browser after startup or reuse an existing instance
|
|
791
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)
|
|
792
1226
|
stop: --port, -p Port to stop (default: 3000)
|
|
793
1227
|
stop: --force, -f Send SIGKILL if SIGTERM does not stop the server
|
|
794
1228
|
`);
|
|
795
1229
|
}
|
|
796
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
|
+
|
|
797
1244
|
function printStopHelp() {
|
|
798
1245
|
console.log(`Stop a running AgentOS server.
|
|
799
1246
|
|
|
@@ -820,22 +1267,41 @@ Options:
|
|
|
820
1267
|
`);
|
|
821
1268
|
}
|
|
822
1269
|
|
|
823
|
-
function createRelay(target,
|
|
1270
|
+
function createRelay(target, boot, startupState, onServerReady) {
|
|
824
1271
|
return (chunk) => {
|
|
825
1272
|
const text = chunk.toString();
|
|
826
|
-
|
|
1273
|
+
const ready = isServerReadyOutput(text);
|
|
827
1274
|
|
|
828
|
-
if (
|
|
1275
|
+
if (ready) {
|
|
1276
|
+
onServerReady();
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
if (boot.isPlain() || startupState.completed) {
|
|
1280
|
+
target.write(text);
|
|
829
1281
|
return;
|
|
830
1282
|
}
|
|
831
1283
|
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
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);
|
|
835
1293
|
}
|
|
836
1294
|
};
|
|
837
1295
|
}
|
|
838
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
|
+
|
|
839
1305
|
function printUpdateStatus(status, options = {}) {
|
|
840
1306
|
if (status.updateAvailable) {
|
|
841
1307
|
console.log(`Update available: ${status.currentVersion} -> ${status.latestVersion}.`);
|