@agentxjs/portagent 0.0.9 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +9 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/public/assets/browser-C0DG1J1h.js +2 -0
- package/dist/public/assets/browser-C0DG1J1h.js.map +1 -0
- package/dist/public/assets/index-DYPjKVjB.css +1 -0
- package/dist/public/assets/index-DtLPjMmM.js +921 -0
- package/dist/public/assets/index-DtLPjMmM.js.map +1 -0
- package/dist/public/index.html +2 -2
- package/dist/server/index.js +196 -175
- package/dist/server/index.js.map +1 -1
- package/package.json +7 -5
- package/dist/chunk-7D4SUZUM.js +0 -38
- package/dist/chunk-7D4SUZUM.js.map +0 -1
- package/dist/public/assets/index-CwJV4aRD.css +0 -1
- package/dist/public/assets/index-Diy1g-AB.js +0 -245
- package/dist/public/assets/index-Diy1g-AB.js.map +0 -1
package/dist/public/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>Portagent - AgentX Portal</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DtLPjMmM.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DYPjKVjB.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
package/dist/server/index.js
CHANGED
|
@@ -1,23 +1,29 @@
|
|
|
1
1
|
// src/server/index.ts
|
|
2
2
|
import { dirname, resolve } from "path";
|
|
3
3
|
import { fileURLToPath } from "url";
|
|
4
|
-
import {
|
|
4
|
+
import { createServer } from "http";
|
|
5
5
|
import { Hono as Hono2 } from "hono";
|
|
6
6
|
import { cors } from "hono/cors";
|
|
7
7
|
import { serveStatic } from "@hono/node-server/serve-static";
|
|
8
8
|
import { existsSync, readFileSync } from "fs";
|
|
9
|
-
import { createAgentX
|
|
10
|
-
import { createAgentXHandler } from "agentxjs/server";
|
|
11
|
-
import { toHonoHandler } from "agentxjs/server/adapters/hono";
|
|
12
|
-
import { nodeRuntime } from "@agentxjs/node-runtime";
|
|
9
|
+
import { createAgentX } from "agentxjs";
|
|
13
10
|
import { homedir } from "os";
|
|
14
11
|
import { join } from "path";
|
|
12
|
+
import { mkdirSync } from "fs";
|
|
15
13
|
|
|
16
14
|
// src/server/auth.ts
|
|
17
15
|
import { Hono } from "hono";
|
|
18
16
|
import { createMiddleware } from "hono/factory";
|
|
19
17
|
import * as jose from "jose";
|
|
20
18
|
var TOKEN_EXPIRY = "7d";
|
|
19
|
+
function isValidInviteCode(code) {
|
|
20
|
+
const timestamp = parseInt(code, 10);
|
|
21
|
+
if (isNaN(timestamp)) return false;
|
|
22
|
+
const now = /* @__PURE__ */ new Date();
|
|
23
|
+
const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 1);
|
|
24
|
+
const expectedTimestamp = Math.floor(todayStart.getTime() / 1e3);
|
|
25
|
+
return timestamp === expectedTimestamp;
|
|
26
|
+
}
|
|
21
27
|
async function createToken(secret, userId) {
|
|
22
28
|
const secretKey = new TextEncoder().encode(secret);
|
|
23
29
|
const token = await new jose.SignJWT({ sub: userId }).setProtectedHeader({ alg: "HS256" }).setIssuedAt().setExpirationTime(TOKEN_EXPIRY).sign(secretKey);
|
|
@@ -43,13 +49,20 @@ function toUserInfo(user) {
|
|
|
43
49
|
createdAt: user.createdAt
|
|
44
50
|
};
|
|
45
51
|
}
|
|
46
|
-
function authRoutes(userRepository, jwtSecret, agentx) {
|
|
52
|
+
function authRoutes(userRepository, jwtSecret, agentx, config = {}) {
|
|
47
53
|
const app = new Hono();
|
|
54
|
+
const { inviteCodeRequired = true } = config;
|
|
55
|
+
app.get("/config", (c) => {
|
|
56
|
+
return c.json({ inviteCodeRequired });
|
|
57
|
+
});
|
|
48
58
|
app.post("/register", async (c) => {
|
|
49
59
|
try {
|
|
50
60
|
const body = await c.req.json();
|
|
51
|
-
if (!body.username || !body.
|
|
52
|
-
return c.json({ error: "Username
|
|
61
|
+
if (!body.username || !body.password) {
|
|
62
|
+
return c.json({ error: "Username and password are required" }, 400);
|
|
63
|
+
}
|
|
64
|
+
if (inviteCodeRequired && (!body.inviteCode || !isValidInviteCode(body.inviteCode))) {
|
|
65
|
+
return c.json({ error: "Invalid invite code" }, 400);
|
|
53
66
|
}
|
|
54
67
|
if (body.username.length < 3) {
|
|
55
68
|
return c.json({ error: "Username must be at least 3 characters" }, 400);
|
|
@@ -57,15 +70,19 @@ function authRoutes(userRepository, jwtSecret, agentx) {
|
|
|
57
70
|
if (body.password.length < 6) {
|
|
58
71
|
return c.json({ error: "Password must be at least 6 characters" }, 400);
|
|
59
72
|
}
|
|
60
|
-
if (!body.email.includes("@")) {
|
|
73
|
+
if (body.email && !body.email.includes("@")) {
|
|
61
74
|
return c.json({ error: "Invalid email format" }, 400);
|
|
62
75
|
}
|
|
63
|
-
const
|
|
76
|
+
const containerId = `user-${crypto.randomUUID()}`;
|
|
77
|
+
const containerRes = await agentx.request("container_create_request", { containerId });
|
|
78
|
+
if (containerRes.data.error) {
|
|
79
|
+
return c.json({ error: "Failed to create user container" }, 500);
|
|
80
|
+
}
|
|
64
81
|
const user = await userRepository.createUser({
|
|
65
82
|
username: body.username,
|
|
66
83
|
email: body.email,
|
|
67
84
|
password: body.password,
|
|
68
|
-
containerId
|
|
85
|
+
containerId,
|
|
69
86
|
displayName: body.displayName,
|
|
70
87
|
avatar: body.avatar
|
|
71
88
|
});
|
|
@@ -191,16 +208,17 @@ var SQLiteUserRepository = class {
|
|
|
191
208
|
if (await this.usernameExists(input.username)) {
|
|
192
209
|
throw new Error(`Username '${input.username}' already exists`);
|
|
193
210
|
}
|
|
194
|
-
if (await this.emailExists(input.email)) {
|
|
211
|
+
if (input.email && await this.emailExists(input.email)) {
|
|
195
212
|
throw new Error(`Email '${input.email}' already exists`);
|
|
196
213
|
}
|
|
197
214
|
const passwordHash = await hash(input.password, SALT_ROUNDS);
|
|
198
215
|
const userId = randomUUID();
|
|
199
216
|
const now = Date.now();
|
|
217
|
+
const email = input.email || `${userId}@noemail.portagent`;
|
|
200
218
|
const user = {
|
|
201
219
|
userId,
|
|
202
220
|
username: input.username,
|
|
203
|
-
email
|
|
221
|
+
email,
|
|
204
222
|
passwordHash,
|
|
205
223
|
containerId: input.containerId,
|
|
206
224
|
displayName: input.displayName,
|
|
@@ -395,143 +413,127 @@ var SQLiteUserRepository = class {
|
|
|
395
413
|
}
|
|
396
414
|
};
|
|
397
415
|
|
|
398
|
-
// src/server/
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
416
|
+
// src/server/logger.ts
|
|
417
|
+
import pino from "pino";
|
|
418
|
+
import fs from "fs";
|
|
419
|
+
import path from "path";
|
|
420
|
+
var LEVEL_MAP = {
|
|
421
|
+
debug: "debug",
|
|
422
|
+
info: "info",
|
|
423
|
+
warn: "warn",
|
|
424
|
+
error: "error",
|
|
425
|
+
silent: "silent"
|
|
426
|
+
};
|
|
427
|
+
var PinoLoggerAdapter = class {
|
|
428
|
+
constructor(name, level, pino2) {
|
|
429
|
+
this.name = name;
|
|
430
|
+
this.level = level;
|
|
431
|
+
this.pino = pino2;
|
|
432
|
+
}
|
|
433
|
+
debug(message, context) {
|
|
434
|
+
this.pino.debug(context || {}, message);
|
|
435
|
+
}
|
|
436
|
+
info(message, context) {
|
|
437
|
+
this.pino.info(context || {}, message);
|
|
438
|
+
}
|
|
439
|
+
warn(message, context) {
|
|
440
|
+
this.pino.warn(context || {}, message);
|
|
441
|
+
}
|
|
442
|
+
error(message, context) {
|
|
443
|
+
if (message instanceof Error) {
|
|
444
|
+
this.pino.error({ ...context, err: message }, message.message);
|
|
445
|
+
} else {
|
|
446
|
+
this.pino.error(context || {}, message);
|
|
406
447
|
}
|
|
407
448
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
449
|
+
isDebugEnabled() {
|
|
450
|
+
return this.pino.isLevelEnabled("debug");
|
|
451
|
+
}
|
|
452
|
+
isInfoEnabled() {
|
|
453
|
+
return this.pino.isLevelEnabled("info");
|
|
454
|
+
}
|
|
455
|
+
isWarnEnabled() {
|
|
456
|
+
return this.pino.isLevelEnabled("warn");
|
|
457
|
+
}
|
|
458
|
+
isErrorEnabled() {
|
|
459
|
+
return this.pino.isLevelEnabled("error");
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
var PinoLoggerFactory = class {
|
|
463
|
+
rootLogger;
|
|
464
|
+
constructor(options) {
|
|
465
|
+
const { level, logDir, pretty = process.env.NODE_ENV !== "production" } = options;
|
|
466
|
+
if (!fs.existsSync(logDir)) {
|
|
467
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
418
468
|
}
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
} catch {
|
|
432
|
-
return baseHandler(request);
|
|
469
|
+
const getLogFilePath = () => {
|
|
470
|
+
const now = /* @__PURE__ */ new Date();
|
|
471
|
+
const dateStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
|
|
472
|
+
return path.join(logDir, `portagent-${dateStr}.log`);
|
|
473
|
+
};
|
|
474
|
+
const targets = [];
|
|
475
|
+
targets.push({
|
|
476
|
+
target: "pino/file",
|
|
477
|
+
level: LEVEL_MAP[level],
|
|
478
|
+
options: {
|
|
479
|
+
destination: getLogFilePath(),
|
|
480
|
+
mkdir: true
|
|
433
481
|
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
status: 403,
|
|
444
|
-
headers: { "Content-Type": "application/json" }
|
|
445
|
-
});
|
|
446
|
-
}
|
|
447
|
-
return baseHandler(request);
|
|
448
|
-
} else {
|
|
449
|
-
try {
|
|
450
|
-
const body = await request.json();
|
|
451
|
-
const config = body.config || {};
|
|
452
|
-
config.ownerId = userId;
|
|
453
|
-
const modifiedBody = { ...body, config };
|
|
454
|
-
const modifiedRequest = new Request(request.url, {
|
|
455
|
-
method: request.method,
|
|
456
|
-
headers: request.headers,
|
|
457
|
-
body: JSON.stringify(modifiedBody)
|
|
458
|
-
});
|
|
459
|
-
return baseHandler(modifiedRequest);
|
|
460
|
-
} catch {
|
|
461
|
-
return baseHandler(request);
|
|
482
|
+
});
|
|
483
|
+
if (pretty) {
|
|
484
|
+
targets.push({
|
|
485
|
+
target: "pino-pretty",
|
|
486
|
+
level: LEVEL_MAP[level],
|
|
487
|
+
options: {
|
|
488
|
+
colorize: true,
|
|
489
|
+
translateTime: "SYS:standard",
|
|
490
|
+
ignore: "pid,hostname"
|
|
462
491
|
}
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
status: 404,
|
|
472
|
-
headers: { "Content-Type": "application/json" }
|
|
473
|
-
});
|
|
474
|
-
}
|
|
475
|
-
const ownerId = container.config?.ownerId;
|
|
476
|
-
if (ownerId && ownerId !== userId) {
|
|
477
|
-
return new Response(JSON.stringify({ error: "Access denied" }), {
|
|
478
|
-
status: 403,
|
|
479
|
-
headers: { "Content-Type": "application/json" }
|
|
480
|
-
});
|
|
481
|
-
}
|
|
482
|
-
return baseHandler(request);
|
|
483
|
-
}
|
|
484
|
-
const deleteContainerMatch = path.match(/\/containers\/([^/]+)$/);
|
|
485
|
-
if (method === "DELETE" && deleteContainerMatch) {
|
|
486
|
-
const containerId = deleteContainerMatch[1];
|
|
487
|
-
const container = await agentx.containers.get(containerId);
|
|
488
|
-
if (!container) {
|
|
489
|
-
return new Response(JSON.stringify({ error: "Container not found" }), {
|
|
490
|
-
status: 404,
|
|
491
|
-
headers: { "Content-Type": "application/json" }
|
|
492
|
-
});
|
|
493
|
-
}
|
|
494
|
-
const ownerId = container.config?.ownerId;
|
|
495
|
-
if (ownerId && ownerId !== userId) {
|
|
496
|
-
return new Response(JSON.stringify({ error: "Access denied" }), {
|
|
497
|
-
status: 403,
|
|
498
|
-
headers: { "Content-Type": "application/json" }
|
|
499
|
-
});
|
|
500
|
-
}
|
|
501
|
-
return baseHandler(request);
|
|
492
|
+
});
|
|
493
|
+
} else {
|
|
494
|
+
targets.push({
|
|
495
|
+
target: "pino/file",
|
|
496
|
+
level: LEVEL_MAP[level],
|
|
497
|
+
options: { destination: 1 }
|
|
498
|
+
// stdout
|
|
499
|
+
});
|
|
502
500
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
if (Array.isArray(body)) {
|
|
508
|
-
const filtered = body.filter((container) => {
|
|
509
|
-
const ownerId = container.config?.ownerId;
|
|
510
|
-
return !ownerId || ownerId === userId;
|
|
511
|
-
});
|
|
512
|
-
return new Response(JSON.stringify(filtered), {
|
|
513
|
-
status: 200,
|
|
514
|
-
headers: { "Content-Type": "application/json" }
|
|
515
|
-
});
|
|
516
|
-
}
|
|
501
|
+
this.rootLogger = pino({
|
|
502
|
+
level: LEVEL_MAP[level],
|
|
503
|
+
transport: {
|
|
504
|
+
targets
|
|
517
505
|
}
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
getLogger(name) {
|
|
509
|
+
const childLogger = this.rootLogger.child({ name });
|
|
510
|
+
return new PinoLoggerAdapter(name, this.rootLogger.level, childLogger);
|
|
511
|
+
}
|
|
512
|
+
};
|
|
523
513
|
|
|
524
514
|
// src/server/index.ts
|
|
525
515
|
var __filename = fileURLToPath(import.meta.url);
|
|
526
516
|
var __dirname = dirname(__filename);
|
|
517
|
+
function getDataPaths() {
|
|
518
|
+
const dataDir = process.env.PORTAGENT_DATA_DIR || join(homedir(), ".agentx");
|
|
519
|
+
const dataDirPath = join(dataDir, "data");
|
|
520
|
+
const logsDirPath = join(dataDir, "logs");
|
|
521
|
+
mkdirSync(dataDirPath, { recursive: true });
|
|
522
|
+
mkdirSync(logsDirPath, { recursive: true });
|
|
523
|
+
return {
|
|
524
|
+
dataDir,
|
|
525
|
+
dataDirPath,
|
|
526
|
+
logsDirPath,
|
|
527
|
+
userDbPath: join(dataDirPath, "portagent.db"),
|
|
528
|
+
agentxDbPath: join(dataDirPath, "agentx.db"),
|
|
529
|
+
logFilePath: join(logsDirPath, "portagent.log")
|
|
530
|
+
};
|
|
531
|
+
}
|
|
527
532
|
var PORT = parseInt(process.env.PORT || "5200", 10);
|
|
528
533
|
var JWT_SECRET = process.env.JWT_SECRET || crypto.randomUUID();
|
|
529
|
-
var
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
systemPrompt: "You are a helpful AI assistant."
|
|
533
|
-
});
|
|
534
|
-
function createApp() {
|
|
534
|
+
var INVITE_CODE_REQUIRED = process.env.INVITE_CODE_REQUIRED !== "false";
|
|
535
|
+
async function createApp() {
|
|
536
|
+
const paths = getDataPaths();
|
|
535
537
|
const app = new Hono2();
|
|
536
538
|
app.use(
|
|
537
539
|
"*",
|
|
@@ -541,23 +543,53 @@ function createApp() {
|
|
|
541
543
|
allowHeaders: ["Content-Type", "Authorization"]
|
|
542
544
|
})
|
|
543
545
|
);
|
|
544
|
-
const
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
546
|
+
const apiKey = process.env.LLM_PROVIDER_KEY;
|
|
547
|
+
if (!apiKey) {
|
|
548
|
+
console.error("Error: LLM_PROVIDER_KEY is required");
|
|
549
|
+
console.log("\nSet it via environment variable:");
|
|
550
|
+
console.log(" export LLM_PROVIDER_KEY=sk-ant-xxx");
|
|
551
|
+
process.exit(1);
|
|
552
|
+
}
|
|
553
|
+
const { getRequestListener } = await import("@hono/node-server");
|
|
554
|
+
const listener = getRequestListener(app.fetch);
|
|
555
|
+
const server = createServer(listener);
|
|
556
|
+
const logLevel = process.env.LOG_LEVEL || "info";
|
|
557
|
+
const loggerFactory = new PinoLoggerFactory({
|
|
558
|
+
level: logLevel,
|
|
559
|
+
logDir: paths.logsDirPath,
|
|
560
|
+
pretty: process.env.NODE_ENV !== "production"
|
|
552
561
|
});
|
|
553
|
-
|
|
554
|
-
|
|
562
|
+
const agentx = await createAgentX({
|
|
563
|
+
llm: {
|
|
564
|
+
apiKey,
|
|
565
|
+
baseUrl: process.env.LLM_PROVIDER_URL,
|
|
566
|
+
model: process.env.LLM_PROVIDER_MODEL
|
|
567
|
+
},
|
|
568
|
+
storage: {
|
|
569
|
+
driver: "sqlite",
|
|
570
|
+
path: paths.agentxDbPath
|
|
571
|
+
},
|
|
572
|
+
logger: {
|
|
573
|
+
level: logLevel,
|
|
574
|
+
factory: loggerFactory
|
|
575
|
+
},
|
|
576
|
+
server
|
|
577
|
+
// Attach to existing HTTP server
|
|
578
|
+
});
|
|
579
|
+
const userRepository = new SQLiteUserRepository(paths.userDbPath);
|
|
555
580
|
const authMiddleware = createAuthMiddleware(JWT_SECRET);
|
|
556
581
|
app.get("/health", (c) => c.json({ status: "ok", timestamp: Date.now() }));
|
|
557
|
-
app.route(
|
|
558
|
-
|
|
582
|
+
app.route(
|
|
583
|
+
"/api/auth",
|
|
584
|
+
authRoutes(userRepository, JWT_SECRET, agentx, { inviteCodeRequired: INVITE_CODE_REQUIRED })
|
|
585
|
+
);
|
|
559
586
|
app.use("/agentx/*", authMiddleware);
|
|
560
|
-
app.
|
|
587
|
+
app.get("/agentx/info", (c) => {
|
|
588
|
+
return c.json({
|
|
589
|
+
version: "0.1.0",
|
|
590
|
+
wsPath: "/ws"
|
|
591
|
+
});
|
|
592
|
+
});
|
|
561
593
|
const publicDir = resolve(__dirname, "../public");
|
|
562
594
|
const isDev = process.env.NODE_ENV !== "production";
|
|
563
595
|
if (existsSync(publicDir)) {
|
|
@@ -578,16 +610,10 @@ function createApp() {
|
|
|
578
610
|
);
|
|
579
611
|
});
|
|
580
612
|
}
|
|
581
|
-
return { app, agentx, userRepository };
|
|
613
|
+
return { app, server, agentx, userRepository, paths };
|
|
582
614
|
}
|
|
583
615
|
async function startServer() {
|
|
584
|
-
|
|
585
|
-
console.error("Error: LLM_PROVIDER_KEY is required");
|
|
586
|
-
console.log("\nSet it via environment variable:");
|
|
587
|
-
console.log(" export LLM_PROVIDER_KEY=sk-ant-xxx");
|
|
588
|
-
process.exit(1);
|
|
589
|
-
}
|
|
590
|
-
const { app, agentx, userRepository } = createApp();
|
|
616
|
+
const { server, agentx, userRepository, paths } = await createApp();
|
|
591
617
|
console.log(`
|
|
592
618
|
____ _ _
|
|
593
619
|
| _ \\ ___ _ __| |_ __ _ __ _ ___ _ __ | |_
|
|
@@ -600,35 +626,30 @@ async function startServer() {
|
|
|
600
626
|
`);
|
|
601
627
|
console.log("Configuration:");
|
|
602
628
|
console.log(` Port: ${PORT}`);
|
|
629
|
+
console.log(` Data Dir: ${paths.dataDir}`);
|
|
603
630
|
console.log(` API Key: ${process.env.LLM_PROVIDER_KEY.substring(0, 15)}...`);
|
|
604
|
-
console.log(` User DB: ${
|
|
605
|
-
console.log(` AgentX DB: ${
|
|
631
|
+
console.log(` User DB: ${paths.userDbPath}`);
|
|
632
|
+
console.log(` AgentX DB: ${paths.agentxDbPath}`);
|
|
633
|
+
console.log(` Logs: ${paths.logsDirPath}`);
|
|
634
|
+
console.log(` Invite Code: ${INVITE_CODE_REQUIRED ? "required" : "disabled"}`);
|
|
606
635
|
console.log(`
|
|
607
636
|
Endpoints:`);
|
|
608
637
|
console.log(` GET /health - Health check`);
|
|
609
638
|
console.log(` POST /api/auth/register - Register new user`);
|
|
610
639
|
console.log(` POST /api/auth/login - Login`);
|
|
611
640
|
console.log(` GET /api/auth/verify - Verify token`);
|
|
612
|
-
console.log(` --- AgentX API (protected) ---`);
|
|
613
641
|
console.log(` GET /agentx/info - Platform info`);
|
|
614
|
-
console.log(`
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
console.log(` DELETE /agentx/containers/:id - Delete container`);
|
|
618
|
-
console.log(` POST /agentx/agents - Create agent`);
|
|
619
|
-
console.log(` GET /agentx/agents/:id/sse - SSE stream`);
|
|
620
|
-
console.log(` POST /agentx/agents/:id/messages- Send message`);
|
|
621
|
-
serve({
|
|
622
|
-
fetch: app.fetch,
|
|
623
|
-
port: PORT,
|
|
624
|
-
hostname: "0.0.0.0"
|
|
625
|
-
});
|
|
626
|
-
console.log(`
|
|
642
|
+
console.log(` WS /ws - WebSocket connection`);
|
|
643
|
+
server.listen(PORT, "0.0.0.0", () => {
|
|
644
|
+
console.log(`
|
|
627
645
|
\u{1F680} Server running at http://localhost:${PORT}`);
|
|
646
|
+
console.log(`\u{1F50C} WebSocket available at ws://localhost:${PORT}/ws`);
|
|
647
|
+
});
|
|
628
648
|
const shutdown = async () => {
|
|
629
649
|
console.log("\nShutting down...");
|
|
630
|
-
await agentx.
|
|
650
|
+
await agentx.dispose();
|
|
631
651
|
userRepository.close();
|
|
652
|
+
server.close();
|
|
632
653
|
console.log("Server stopped");
|
|
633
654
|
process.exit(0);
|
|
634
655
|
};
|