@next-open-ai/openbot 0.1.8 → 0.2.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.
Files changed (81) hide show
  1. package/README.md +6 -6
  2. package/{desktop → apps/desktop}/README.md +3 -3
  3. package/{desktop/renderer/dist/assets/index-DL_hPION.js → apps/desktop/renderer/dist/assets/index-BOS-F8a4.js} +37 -37
  4. package/{desktop/renderer/dist/assets/index-BBoPEPR6.css → apps/desktop/renderer/dist/assets/index-DxqxayUL.css} +2 -2
  5. package/{desktop → apps/desktop}/renderer/dist/index.html +2 -2
  6. package/dist/cli/cli.d.ts +2 -0
  7. package/dist/cli/cli.js +172 -0
  8. package/dist/cli.d.ts +4 -1
  9. package/dist/cli.js +4 -172
  10. package/dist/gateway/auth-hooks.d.ts +17 -0
  11. package/dist/gateway/auth-hooks.js +19 -0
  12. package/dist/gateway/channel-handler.d.ts +6 -0
  13. package/dist/gateway/channel-handler.js +3 -0
  14. package/dist/gateway/index.d.ts +1 -1
  15. package/dist/gateway/index.js +1 -1
  16. package/dist/gateway/methods/agent-cancel.js +1 -1
  17. package/dist/gateway/methods/agent-chat.js +3 -3
  18. package/dist/gateway/methods/install-skill-from-path.js +1 -1
  19. package/dist/gateway/methods/run-scheduled-task.js +3 -3
  20. package/dist/gateway/paths.d.ts +20 -0
  21. package/dist/gateway/paths.js +19 -0
  22. package/dist/gateway/server.d.ts +2 -4
  23. package/dist/gateway/server.js +98 -208
  24. package/dist/gateway/sse-handler.d.ts +6 -0
  25. package/dist/gateway/sse-handler.js +3 -0
  26. package/dist/gateway/voice-handler.d.ts +12 -0
  27. package/dist/gateway/voice-handler.js +18 -0
  28. package/dist/index.d.ts +5 -5
  29. package/dist/index.js +5 -5
  30. package/dist/server/agents/agents.service.js +1 -1
  31. package/dist/server/bootstrap.d.ts +15 -0
  32. package/dist/server/bootstrap.js +38 -0
  33. package/dist/server/config/config.service.d.ts +1 -1
  34. package/dist/server/config/config.service.js +1 -1
  35. package/dist/server/database/database.service.d.ts +14 -6
  36. package/dist/server/database/database.service.js +99 -32
  37. package/dist/server/main.js +6 -19
  38. package/dist/server/skills/skills.service.js +1 -1
  39. package/dist/server/workspace/workspace.service.js +1 -1
  40. package/package.json +23 -20
  41. package/desktop/renderer/dist/assets/logo-RfPiqt5-.png +0 -0
  42. /package/dist/{agent → core/agent}/agent-dir.d.ts +0 -0
  43. /package/dist/{agent → core/agent}/agent-dir.js +0 -0
  44. /package/dist/{agent → core/agent}/agent-manager.d.ts +0 -0
  45. /package/dist/{agent → core/agent}/agent-manager.js +0 -0
  46. /package/dist/{agent → core/agent}/config-manager.d.ts +0 -0
  47. /package/dist/{agent → core/agent}/config-manager.js +0 -0
  48. /package/dist/{agent → core/agent}/run.d.ts +0 -0
  49. /package/dist/{agent → core/agent}/run.js +0 -0
  50. /package/dist/{agent → core/agent}/skills.d.ts +0 -0
  51. /package/dist/{agent → core/agent}/skills.js +0 -0
  52. /package/dist/{config → core/config}/desktop-config.d.ts +0 -0
  53. /package/dist/{config → core/config}/desktop-config.js +0 -0
  54. /package/dist/{config → core/config}/provider-support-default.d.ts +0 -0
  55. /package/dist/{config → core/config}/provider-support-default.js +0 -0
  56. /package/dist/{installer → core/installer}/index.d.ts +0 -0
  57. /package/dist/{installer → core/installer}/index.js +0 -0
  58. /package/dist/{installer → core/installer}/skill-installer.d.ts +0 -0
  59. /package/dist/{installer → core/installer}/skill-installer.js +0 -0
  60. /package/dist/{memory → core/memory}/build-summary.d.ts +0 -0
  61. /package/dist/{memory → core/memory}/build-summary.js +0 -0
  62. /package/dist/{memory → core/memory}/compaction-extension.d.ts +0 -0
  63. /package/dist/{memory → core/memory}/compaction-extension.js +0 -0
  64. /package/dist/{memory → core/memory}/embedding.d.ts +0 -0
  65. /package/dist/{memory → core/memory}/embedding.js +0 -0
  66. /package/dist/{memory → core/memory}/index.d.ts +0 -0
  67. /package/dist/{memory → core/memory}/index.js +0 -0
  68. /package/dist/{memory → core/memory}/remote-embedding.d.ts +0 -0
  69. /package/dist/{memory → core/memory}/remote-embedding.js +0 -0
  70. /package/dist/{memory → core/memory}/types.d.ts +0 -0
  71. /package/dist/{memory → core/memory}/types.js +0 -0
  72. /package/dist/{memory → core/memory}/vector-store.d.ts +0 -0
  73. /package/dist/{memory → core/memory}/vector-store.js +0 -0
  74. /package/dist/{tools → core/tools}/browser-tool.d.ts +0 -0
  75. /package/dist/{tools → core/tools}/browser-tool.js +0 -0
  76. /package/dist/{tools → core/tools}/index.d.ts +0 -0
  77. /package/dist/{tools → core/tools}/index.js +0 -0
  78. /package/dist/{tools → core/tools}/install-skill-tool.d.ts +0 -0
  79. /package/dist/{tools → core/tools}/install-skill-tool.js +0 -0
  80. /package/dist/{tools → core/tools}/save-experience-tool.d.ts +0 -0
  81. /package/dist/{tools → core/tools}/save-experience-tool.js +0 -0
@@ -1,8 +1,13 @@
1
1
  /**
2
- * WebSocket Gateway 入口:提供 WS JSON-RPC(如 agent.chat),并代理 /server-api 到 Desktop 后端(src/server/)。
3
- * Nest Desktop Backend 是不同进程;本进程可拉 Nest 子进程并转发请求。
2
+ * Gateway 单进程入口:内嵌 Nest,按 path 分流。
3
+ * - /server-api Nest(业务 REST)
4
+ * - /ws → Agent 对话 WebSocket
5
+ * - /ws/voice → 语音通道(占位)
6
+ * - /sse → SSE(占位)
7
+ * - /channel → 通道模块(占位)
8
+ * - 其余 → 静态资源
4
9
  */
5
- /* Avoid MaxListenersExceededWarning: Browser Tool / Playwright attach abort listeners to same AbortSignal; Node default maxListeners is 10. */
10
+ /* Avoid MaxListenersExceededWarning */
6
11
  const Et = globalThis.EventTarget;
7
12
  if (Et?.prototype?.addEventListener && Et.prototype.setMaxListeners) {
8
13
  const add = Et.prototype.addEventListener;
@@ -13,70 +18,26 @@ if (Et?.prototype?.addEventListener && Et.prototype.setMaxListeners) {
13
18
  return add.call(this, type, listener, options);
14
19
  };
15
20
  }
21
+ import express from "express";
22
+ import { createServer } from "http";
16
23
  import { WebSocketServer } from "ws";
17
- import { createServer, request as httpRequest } from "http";
18
- import { handleConnection } from "./connection-handler.js";
19
24
  import { readFile, stat } from "fs/promises";
20
25
  import { join, extname, dirname } from "path";
21
26
  import { fileURLToPath } from "node:url";
22
- import { existsSync } from "fs";
23
- import { spawn } from "child_process";
24
- import { createServer as createNetServer } from "net";
27
+ import { PATHS } from "./paths.js";
28
+ import { authHookServerApi, authHookChannel, authHookSse, authHookWs } from "./auth-hooks.js";
29
+ import { handleChannel } from "./channel-handler.js";
30
+ import { handleSse } from "./sse-handler.js";
31
+ import { handleVoiceUpgrade } from "./voice-handler.js";
32
+ import { handleConnection } from "./connection-handler.js";
25
33
  import { handleRunScheduledTask } from "./methods/run-scheduled-task.js";
26
34
  import { handleInstallSkillFromPath } from "./methods/install-skill-from-path.js";
27
35
  import { setBackendBaseUrl } from "./backend-url.js";
28
- import { ensureDesktopConfigInitialized } from "../config/desktop-config.js";
36
+ import { ensureDesktopConfigInitialized } from "../core/config/desktop-config.js";
37
+ import { createNestAppEmbedded } from "../server/bootstrap.js";
29
38
  const __dirname = dirname(fileURLToPath(import.meta.url));
30
- /** 包根目录(dist/gateway 的上级的上级),npm 安装后静态资源在 desktop/renderer/dist */
31
39
  const PACKAGE_ROOT = join(__dirname, "..", "..");
32
- const STATIC_DIR = join(PACKAGE_ROOT, "desktop", "renderer", "dist");
33
- /**
34
- * Find an available port starting from startPort
35
- */
36
- async function findAvailablePort(startPort) {
37
- let port = startPort;
38
- while (true) {
39
- try {
40
- await new Promise((resolve, reject) => {
41
- const server = createNetServer();
42
- server.once("error", (err) => {
43
- if (err.code === "EADDRINUSE") {
44
- resolve(); // Port taken, try next
45
- }
46
- else {
47
- reject(err);
48
- }
49
- });
50
- server.once("listening", () => {
51
- server.close(() => resolve()); // Port available
52
- });
53
- server.listen(port);
54
- });
55
- // If we get here and the server listened successfully (then closed), checking if it was actually available logic needs care.
56
- // Actually the above logic is slightly flawed for "resolve on error".
57
- // Let's refine:
58
- // If listen succeeds -> port is free. return it.
59
- // If EADDRINUSE -> port busy. loop continue.
60
- const isAvailable = await new Promise((resolve) => {
61
- const server = createNetServer();
62
- server.once("error", () => resolve(false));
63
- server.once("listening", () => {
64
- server.close(() => resolve(true));
65
- });
66
- server.listen(port);
67
- });
68
- if (isAvailable)
69
- return port;
70
- port++;
71
- }
72
- catch (e) {
73
- port++;
74
- }
75
- }
76
- }
77
- /**
78
- * MIME types for static files
79
- */
40
+ const STATIC_DIR = join(PACKAGE_ROOT, "apps", "desktop", "renderer", "dist");
80
41
  const MIME_TYPES = {
81
42
  ".html": "text/html",
82
43
  ".js": "text/javascript",
@@ -92,137 +53,65 @@ const MIME_TYPES = {
92
53
  ".ttf": "font/ttf",
93
54
  ".eot": "application/vnd.ms-fontobject",
94
55
  };
95
- /**
96
- * Start WebSocket gateway server
97
- */
98
56
  export async function startGatewayServer(port = 38080) {
99
57
  await ensureDesktopConfigInitialized();
100
58
  console.log(`Starting gateway server on port ${port}...`);
101
- // 1. Find available port for Desktop Server
102
- const backendPort = await findAvailablePort(38081);
103
- console.log(`Found available port for Desktop Server: ${backendPort}`);
104
- setBackendBaseUrl(`http://localhost:${backendPort}`);
105
- // 2. Start Desktop Server(从包根目录找 dist/server,npm 全局安装时也能启动)
106
- let backendProcess = null;
107
- const serverPath = join(PACKAGE_ROOT, "dist", "server", "main.js");
108
- if (existsSync(serverPath)) {
109
- console.log(`Spawning Desktop Server at ${serverPath}...`);
110
- backendProcess = spawn("node", [serverPath], {
111
- cwd: PACKAGE_ROOT,
112
- env: { ...process.env, PORT: backendPort.toString() },
113
- stdio: ["ignore", "pipe", "pipe"], // Pipe stdout/stderr to capture logs
114
- });
115
- backendProcess.stdout?.on("data", (data) => {
116
- const str = data.toString().trim();
117
- if (str)
118
- console.log(`[Desktop Server] ${str}`);
119
- });
120
- backendProcess.stderr?.on("data", (data) => {
121
- const str = data.toString().trim();
122
- if (str)
123
- console.error(`[Desktop Server Error] ${str}`);
124
- });
125
- backendProcess.on("exit", (code) => {
126
- if (code !== 0 && code !== null) {
127
- console.error(`Desktop Server exited with code ${code}`);
128
- }
59
+ setBackendBaseUrl(`http://localhost:${port}`);
60
+ const { app: nestApp, express: nestExpress } = await createNestAppEmbedded();
61
+ const gatewayExpress = express();
62
+ gatewayExpress.get(PATHS.HEALTH, (_req, res) => {
63
+ res.status(200).json({ status: "ok", timestamp: Date.now() });
64
+ });
65
+ gatewayExpress.post(PATHS.RUN_SCHEDULED_TASK, async (req, res) => {
66
+ await handleRunScheduledTask(req, res);
67
+ });
68
+ gatewayExpress.post(`${PATHS.SERVER_API}/skills/install-from-path`, async (req, res) => {
69
+ const body = await new Promise((resolve, reject) => {
70
+ const chunks = [];
71
+ req.on("data", (chunk) => chunks.push(chunk));
72
+ req.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
73
+ req.on("error", reject);
129
74
  });
130
- }
131
- else {
132
- console.warn("⚠️ Desktop Server build not found. Skipping auto-start.");
133
- console.warn(" Run 'npm run desktop:build' to build the server.");
134
- }
135
- // Create HTTP server
136
- const httpServer = createServer(async (req, res) => {
137
- // Simple health check endpoint
138
- if (req.url === "/health") {
139
- res.writeHead(200, { "Content-Type": "application/json" });
140
- res.end(JSON.stringify({ status: "ok", timestamp: Date.now() }));
141
- return;
142
- }
143
- // Scheduled task: run agent and POST assistant message back to Nest
144
- const pathname = req.url?.split("?")[0] || "";
145
- if (req.method === "POST" && pathname === "/run-scheduled-task") {
146
- await handleRunScheduledTask(req, res);
147
- return;
148
- }
149
- // 本地技能目录安装:在 Gateway 层直接处理,不依赖 Nest,保证桌面端稳定可用
150
- if (req.method === "POST" && pathname === "/server-api/skills/install-from-path") {
151
- const body = await new Promise((resolve, reject) => {
152
- const chunks = [];
153
- req.on("data", (chunk) => chunks.push(chunk));
154
- req.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
155
- req.on("error", reject);
75
+ try {
76
+ const parsed = JSON.parse(body || "{}");
77
+ const result = await handleInstallSkillFromPath({
78
+ path: parsed.path ?? "",
79
+ scope: parsed.scope === "workspace" ? "workspace" : "global",
80
+ workspace: parsed.workspace,
156
81
  });
157
- try {
158
- const parsed = JSON.parse(body || "{}");
159
- const result = await handleInstallSkillFromPath({
160
- path: parsed.path ?? "",
161
- scope: parsed.scope === "workspace" ? "workspace" : "global",
162
- workspace: parsed.workspace,
163
- });
164
- res.writeHead(200, { "Content-Type": "application/json" });
165
- res.end(JSON.stringify(result));
166
- }
167
- catch (err) {
168
- const message = err instanceof Error ? err.message : String(err);
169
- const code = message.includes("required") || message.includes("不存在") || message.includes("SKILL.md") || message.includes("目录名") ? 400 : 500;
170
- res.writeHead(code, { "Content-Type": "application/json" });
171
- res.end(JSON.stringify({ success: false, message }));
172
- }
173
- return;
82
+ res.status(200).json(result);
174
83
  }
175
- // Proxy API requests to Backend (prefixed with /server-api)
176
- if (req.url && req.url.startsWith("/server-api")) {
177
- const options = {
178
- hostname: "localhost",
179
- port: backendPort, // Use discovered port
180
- path: req.url,
181
- method: req.method,
182
- headers: req.headers,
183
- };
184
- const proxyReq = httpRequest(options, (proxyRes) => {
185
- res.writeHead(proxyRes.statusCode || 500, proxyRes.headers);
186
- proxyRes.pipe(res, { end: true });
187
- });
188
- proxyReq.on("error", (err) => {
189
- console.error(`Proxy error to :${backendPort}`, err);
190
- if (!res.headersSent) {
191
- res.writeHead(502, { "Content-Type": "application/json" });
192
- res.end(JSON.stringify({ error: "Bad Gateway", message: "Failed to connect to backend server" }));
193
- }
194
- });
195
- req.pipe(proxyReq, { end: true });
196
- return;
84
+ catch (err) {
85
+ const message = err instanceof Error ? err.message : String(err);
86
+ const code = message.includes("required") || message.includes("不存在") || message.includes("SKILL.md") || message.includes("目录名") ? 400 : 500;
87
+ res.status(code).json({ success: false, message });
197
88
  }
198
- // Serve static files (from package root so npm install works)
89
+ });
90
+ gatewayExpress.use(PATHS.SERVER_API, authHookServerApi, nestExpress);
91
+ gatewayExpress.use(PATHS.CHANNEL, authHookChannel, (req, res) => handleChannel(req, res));
92
+ gatewayExpress.use(PATHS.SSE, authHookSse, (req, res) => handleSse(req, res));
93
+ gatewayExpress.use(async (req, res) => {
94
+ const staticDir = STATIC_DIR;
95
+ const urlPath = req.url?.split("?")[0] || "/";
96
+ let filePath = join(staticDir, urlPath === "/" ? "index.html" : urlPath);
199
97
  try {
200
- const staticDir = STATIC_DIR;
201
- // Normalize URL to remove query parameters and ensuring it starts with /
202
- const urlPath = req.url?.split("?")[0] || "/";
203
- // Determine file path
204
- let filePath = join(staticDir, urlPath === "/" ? "index.html" : urlPath);
205
- // Check if file exists
206
- try {
207
- const stats = await stat(filePath);
208
- if (stats.isDirectory()) {
209
- filePath = join(filePath, "index.html");
210
- await stat(filePath); // Check if index.html exists
211
- }
98
+ const stats = await stat(filePath);
99
+ if (stats.isDirectory()) {
100
+ filePath = join(filePath, "index.html");
101
+ await stat(filePath);
102
+ }
103
+ }
104
+ catch {
105
+ if (req.headers.accept?.includes("text/html") && req.method === "GET") {
106
+ filePath = join(staticDir, "index.html");
212
107
  }
213
- catch {
214
- // File not found
215
- // SPA Fallback: serve index.html for non-API requests accepting HTML
216
- if (req.headers.accept?.includes("text/html") && req.method === "GET") {
217
- filePath = join(staticDir, "index.html");
218
- }
219
- else {
220
- res.writeHead(404, { "Content-Type": "text/plain" });
221
- res.end("Not Found");
222
- return;
223
- }
108
+ else {
109
+ res.writeHead(404, { "Content-Type": "text/plain" });
110
+ res.end("Not Found");
111
+ return;
224
112
  }
225
- // Read and serve file
113
+ }
114
+ try {
226
115
  const content = await readFile(filePath);
227
116
  const ext = extname(filePath).toLowerCase();
228
117
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
@@ -235,41 +124,42 @@ export async function startGatewayServer(port = 38080) {
235
124
  res.end("Internal Server Error");
236
125
  }
237
126
  });
238
- // Create WebSocket server
239
- const wss = new WebSocketServer({ server: httpServer });
240
- // Handle new connections
241
- wss.on("connection", (ws, req) => {
242
- handleConnection(ws, req);
127
+ const httpServer = createServer(gatewayExpress);
128
+ const wss = new WebSocketServer({ noServer: true });
129
+ wss.on("connection", (ws, req) => handleConnection(ws, req));
130
+ httpServer.on("upgrade", (req, socket, head) => {
131
+ const path = req.url?.split("?")[0] || "";
132
+ if (handleVoiceUpgrade(req, socket, head)) {
133
+ return;
134
+ }
135
+ const isAgentWs = path === PATHS.WS || path === "/";
136
+ if (isAgentWs && authHookWs(req, path)) {
137
+ wss.handleUpgrade(req, socket, head, (ws) => {
138
+ wss.emit("connection", ws, req);
139
+ });
140
+ }
141
+ else {
142
+ socket.destroy();
143
+ }
243
144
  });
244
- // Start listening
245
- await new Promise((resolve) => {
145
+ const actualPort = await new Promise((resolve) => {
246
146
  httpServer.listen(port, () => {
247
- console.log(`✅ Gateway server listening on ws://localhost:${port}`);
248
- console.log(` Health check: http://localhost:${port}/health`);
249
- resolve();
147
+ const addr = httpServer.address();
148
+ const p = typeof addr === "object" && addr && "port" in addr ? addr.port : port;
149
+ console.log(`✅ Gateway server listening on ws://localhost:${p}`);
150
+ console.log(` Health: http://localhost:${p}${PATHS.HEALTH}`);
151
+ console.log(` API: http://localhost:${p}${PATHS.SERVER_API}`);
152
+ console.log(` WS: ws://localhost:${p}${PATHS.WS}`);
153
+ resolve(p);
250
154
  });
251
155
  });
252
- // Cleanup function
253
156
  const close = async () => {
254
157
  console.log("Closing gateway server...");
255
- // Stop Desktop Server
256
- if (backendProcess) {
257
- console.log("Stopping Desktop Server...");
258
- backendProcess.kill();
259
- }
260
- // Close all WebSocket connections
261
- wss.clients.forEach((client) => {
262
- client.close();
263
- });
264
- // Close WebSocket server
265
- await new Promise((resolve) => {
266
- wss.close(() => resolve());
267
- });
268
- // Close HTTP server
269
- await new Promise((resolve) => {
270
- httpServer.close(() => resolve());
271
- });
158
+ await nestApp.close();
159
+ wss.clients.forEach((c) => c.close());
160
+ await new Promise((r) => wss.close(() => r()));
161
+ await new Promise((r) => httpServer.close(() => r()));
272
162
  console.log("Gateway server closed");
273
163
  };
274
- return { httpServer, wss, close };
164
+ return { httpServer, wss, port: actualPort, close };
275
165
  }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * SSE 端点(占位)。
3
+ * 后续:Agent 流式输出;当前返回 501 或简单说明。
4
+ */
5
+ import type { Request, Response } from 'express';
6
+ export declare function handleSse(_req: Request, res: Response): void;
@@ -0,0 +1,3 @@
1
+ export function handleSse(_req, res) {
2
+ res.status(501).setHeader('Content-Type', 'application/json').end(JSON.stringify({ ok: false, message: 'SSE endpoint not implemented yet' }));
3
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * 语音通道 WebSocket(占位)。
3
+ * 后续:/ws/voice 建连、二进制/信令、与语音服务对接;当前仅关闭连接并返回 400 或不做 upgrade。
4
+ */
5
+ import type { IncomingMessage } from 'http';
6
+ import type { Duplex } from 'stream';
7
+ /**
8
+ * 处理 /ws/voice 的 upgrade 请求(占位)。
9
+ * 返回 true 表示已处理(例如拒绝并关闭),调用方不必再交给 agent /ws;
10
+ * 返回 false 表示未处理。
11
+ */
12
+ export declare function handleVoiceUpgrade(req: IncomingMessage, socket: Duplex, _head: Buffer): boolean;
@@ -0,0 +1,18 @@
1
+ import { PATHS } from './paths.js';
2
+ /**
3
+ * 处理 /ws/voice 的 upgrade 请求(占位)。
4
+ * 返回 true 表示已处理(例如拒绝并关闭),调用方不必再交给 agent /ws;
5
+ * 返回 false 表示未处理。
6
+ */
7
+ export function handleVoiceUpgrade(req, socket, _head) {
8
+ const path = req.url?.split('?')[0] || '';
9
+ if (path !== PATHS.WS_VOICE) {
10
+ return false;
11
+ }
12
+ socket.write('HTTP/1.1 501 Not Implemented\r\n' +
13
+ 'Content-Type: application/json\r\n' +
14
+ 'Connection: close\r\n\r\n' +
15
+ JSON.stringify({ ok: false, message: 'Voice WebSocket not implemented yet' }));
16
+ socket.destroy();
17
+ return true;
18
+ }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- export { loadSkillsFromDir, loadSkillsFromPaths, formatSkillsForPrompt, type Skill, type LoadSkillsFromDirOptions, } from "./agent/skills.js";
2
- export { run, type RunOptions, type RunResult } from "./agent/run.js";
3
- export { getOpenbotAgentDir, ensureDefaultAgentDir } from "./agent/agent-dir.js";
4
- export { resolveInstallTarget, installSkillByUrl, installSkillFromPath, type InstallByUrlOptions, type InstallByUrlResult, type InstallFromPathOptions, type InstallFromPathResult, } from "./installer/index.js";
5
- export { getProviderSupport, ensureProviderSupportFile, syncDesktopConfigToModelsJson, type ProviderSupport, type ProviderSupportEntry, type ProviderSupportModel, type ModelSupportType, } from "./config/desktop-config.js";
1
+ export { loadSkillsFromDir, loadSkillsFromPaths, formatSkillsForPrompt, type Skill, type LoadSkillsFromDirOptions, } from "./core/agent/skills.js";
2
+ export { run, type RunOptions, type RunResult } from "./core/agent/run.js";
3
+ export { getOpenbotAgentDir, ensureDefaultAgentDir } from "./core/agent/agent-dir.js";
4
+ export { resolveInstallTarget, installSkillByUrl, installSkillFromPath, type InstallByUrlOptions, type InstallByUrlResult, type InstallFromPathOptions, type InstallFromPathResult, } from "./core/installer/index.js";
5
+ export { getProviderSupport, ensureProviderSupportFile, syncDesktopConfigToModelsJson, type ProviderSupport, type ProviderSupportEntry, type ProviderSupportModel, type ModelSupportType, } from "./core/config/desktop-config.js";
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export { loadSkillsFromDir, loadSkillsFromPaths, formatSkillsForPrompt, } from "./agent/skills.js";
2
- export { run } from "./agent/run.js";
3
- export { getOpenbotAgentDir, ensureDefaultAgentDir } from "./agent/agent-dir.js";
4
- export { resolveInstallTarget, installSkillByUrl, installSkillFromPath, } from "./installer/index.js";
5
- export { getProviderSupport, ensureProviderSupportFile, syncDesktopConfigToModelsJson, } from "./config/desktop-config.js";
1
+ export { loadSkillsFromDir, loadSkillsFromPaths, formatSkillsForPrompt, } from "./core/agent/skills.js";
2
+ export { run } from "./core/agent/run.js";
3
+ export { getOpenbotAgentDir, ensureDefaultAgentDir } from "./core/agent/agent-dir.js";
4
+ export { resolveInstallTarget, installSkillByUrl, installSkillFromPath, } from "./core/installer/index.js";
5
+ export { getProviderSupport, ensureProviderSupportFile, syncDesktopConfigToModelsJson, } from "./core/config/desktop-config.js";
@@ -9,7 +9,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  };
10
10
  import { Injectable } from '@nestjs/common';
11
11
  import { randomUUID } from 'crypto';
12
- import { agentManager } from '../../agent/agent-manager.js';
12
+ import { agentManager } from '../../core/agent/agent-manager.js';
13
13
  import { DatabaseService } from '../database/database.service.js';
14
14
  /**
15
15
  * Agents service: session + history storage in SQLite.
@@ -0,0 +1,15 @@
1
+ import type { INestApplication } from '@nestjs/common';
2
+ import type { Express } from 'express';
3
+ export interface NestAppResult {
4
+ app: INestApplication;
5
+ express: Express;
6
+ }
7
+ /**
8
+ * 创建 Nest 应用(内嵌模式):不 listen,不设置 globalPrefix。
9
+ * Gateway 将返回的 express 挂到 /server-api,请求路径会剥掉前缀后进入 Nest。
10
+ */
11
+ export declare function createNestAppEmbedded(): Promise<NestAppResult>;
12
+ /**
13
+ * 独立启动时使用:设置 globalPrefix 并监听端口。
14
+ */
15
+ export declare function createNestAppStandalone(port?: number): Promise<INestApplication>;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Nest 应用创建:支持「内嵌到 Gateway」与「独立监听」两种模式。
3
+ * - 内嵌:不设置 globalPrefix、不 listen,返回 { app, express } 供 Gateway 挂载到 /server-api。
4
+ * - 独立:设置 globalPrefix('server-api') 并 listen(port),用于单独启动 Desktop Server。
5
+ */
6
+ import { NestFactory } from '@nestjs/core';
7
+ import { AppModule } from './app.module.js';
8
+ /**
9
+ * 创建 Nest 应用(内嵌模式):不 listen,不设置 globalPrefix。
10
+ * Gateway 将返回的 express 挂到 /server-api,请求路径会剥掉前缀后进入 Nest。
11
+ */
12
+ export async function createNestAppEmbedded() {
13
+ const app = await NestFactory.create(AppModule, {
14
+ cors: true,
15
+ });
16
+ app.enableCors({
17
+ origin: ['http://localhost:5173', 'http://localhost:38080', 'http://localhost:38081'],
18
+ credentials: true,
19
+ });
20
+ await app.init();
21
+ const express = app.getHttpAdapter().getInstance();
22
+ return { app, express };
23
+ }
24
+ /**
25
+ * 独立启动时使用:设置 globalPrefix 并监听端口。
26
+ */
27
+ export async function createNestAppStandalone(port = 38081) {
28
+ const app = await NestFactory.create(AppModule, {
29
+ cors: true,
30
+ });
31
+ app.setGlobalPrefix('server-api');
32
+ app.enableCors({
33
+ origin: ['http://localhost:5173', 'http://localhost:38080', 'http://localhost:38081'],
34
+ credentials: true,
35
+ });
36
+ await app.listen(port);
37
+ return app;
38
+ }
@@ -78,5 +78,5 @@ export declare class ConfigService {
78
78
  types?: string[];
79
79
  }[]>;
80
80
  /** 完整 provider 目录(支持列表 + 各 provider 的模型),供前端一次拉取 */
81
- getProviderSupport(): Promise<import("../../config/provider-support-default.js").ProviderSupport>;
81
+ getProviderSupport(): Promise<import("../../core/config/provider-support-default.js").ProviderSupport>;
82
82
  }
@@ -11,7 +11,7 @@ import { Injectable } from '@nestjs/common';
11
11
  import { readFile, writeFile, mkdir } from 'fs/promises';
12
12
  import { join } from 'path';
13
13
  import { existsSync } from 'fs';
14
- import { getProviderSupport, syncDesktopConfigToModelsJson } from '../../config/desktop-config.js';
14
+ import { getProviderSupport, syncDesktopConfigToModelsJson } from '../../core/config/desktop-config.js';
15
15
  import { AgentConfigService } from '../agent-config/agent-config.service.js';
16
16
  let ConfigService = class ConfigService {
17
17
  agentConfigService;
@@ -1,10 +1,18 @@
1
- import { OnModuleDestroy } from '@nestjs/common';
2
- import Database from 'better-sqlite3';
3
- export declare class DatabaseService implements OnModuleDestroy {
4
- private db;
5
- getDb(): Database.Database;
1
+ import { OnModuleDestroy, OnModuleInit } from '@nestjs/common';
2
+ /** RunResult compatible with better-sqlite3 for callers that use .changes / .lastInsertRowid */
3
+ export interface RunResult {
4
+ changes: number;
5
+ lastInsertRowid: number;
6
+ }
7
+ export declare class DatabaseService implements OnModuleInit, OnModuleDestroy {
8
+ private sqlDb;
9
+ private dbPath;
10
+ private initPromise;
11
+ onModuleInit(): Promise<void>;
12
+ private doInit;
13
+ private getDb;
6
14
  private runMigrations;
7
- run(sql: string, params?: unknown[]): Database.RunResult;
15
+ run(sql: string, params?: unknown[]): RunResult;
8
16
  get<T>(sql: string, params?: unknown[]): T | undefined;
9
17
  all<T>(sql: string, params?: unknown[]): T[];
10
18
  onModuleDestroy(): void;