@next-open-ai/openclawx 0.6.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/README.md +523 -0
  2. package/apps/desktop/README.md +210 -0
  3. package/apps/desktop/renderer/dist/assets/index-CYkSfhcp.css +10 -0
  4. package/apps/desktop/renderer/dist/assets/index-FI6O25Ms.js +89 -0
  5. package/apps/desktop/renderer/dist/index.html +22 -0
  6. package/dist/cli/cli.d.ts +2 -0
  7. package/dist/cli/cli.js +198 -0
  8. package/dist/cli/service.d.ts +13 -0
  9. package/dist/cli/service.js +243 -0
  10. package/dist/cli.d.ts +5 -0
  11. package/dist/cli.js +5 -0
  12. package/dist/core/agent/agent-dir.d.ts +14 -0
  13. package/dist/core/agent/agent-dir.js +75 -0
  14. package/dist/core/agent/agent-manager.d.ts +64 -0
  15. package/dist/core/agent/agent-manager.js +278 -0
  16. package/dist/core/agent/config-manager.d.ts +25 -0
  17. package/dist/core/agent/config-manager.js +84 -0
  18. package/dist/core/agent/run.d.ts +26 -0
  19. package/dist/core/agent/run.js +65 -0
  20. package/dist/core/agent/skills.d.ts +20 -0
  21. package/dist/core/agent/skills.js +86 -0
  22. package/dist/core/config/desktop-config.d.ts +90 -0
  23. package/dist/core/config/desktop-config.js +521 -0
  24. package/dist/core/config/provider-support-default.d.ts +21 -0
  25. package/dist/core/config/provider-support-default.js +57 -0
  26. package/dist/core/installer/index.d.ts +1 -0
  27. package/dist/core/installer/index.js +1 -0
  28. package/dist/core/installer/skill-installer.d.ts +39 -0
  29. package/dist/core/installer/skill-installer.js +215 -0
  30. package/dist/core/mcp/adapter.d.ts +17 -0
  31. package/dist/core/mcp/adapter.js +49 -0
  32. package/dist/core/mcp/client.d.ts +24 -0
  33. package/dist/core/mcp/client.js +70 -0
  34. package/dist/core/mcp/config.d.ts +22 -0
  35. package/dist/core/mcp/config.js +69 -0
  36. package/dist/core/mcp/index.d.ts +18 -0
  37. package/dist/core/mcp/index.js +20 -0
  38. package/dist/core/mcp/operator.d.ts +15 -0
  39. package/dist/core/mcp/operator.js +72 -0
  40. package/dist/core/mcp/transport/index.d.ts +11 -0
  41. package/dist/core/mcp/transport/index.js +16 -0
  42. package/dist/core/mcp/transport/sse.d.ts +20 -0
  43. package/dist/core/mcp/transport/sse.js +82 -0
  44. package/dist/core/mcp/transport/stdio.d.ts +32 -0
  45. package/dist/core/mcp/transport/stdio.js +132 -0
  46. package/dist/core/mcp/types.d.ts +72 -0
  47. package/dist/core/mcp/types.js +5 -0
  48. package/dist/core/memory/build-summary.d.ts +6 -0
  49. package/dist/core/memory/build-summary.js +27 -0
  50. package/dist/core/memory/compaction-extension.d.ts +6 -0
  51. package/dist/core/memory/compaction-extension.js +23 -0
  52. package/dist/core/memory/embedding.d.ts +4 -0
  53. package/dist/core/memory/embedding.js +15 -0
  54. package/dist/core/memory/index.d.ts +29 -0
  55. package/dist/core/memory/index.js +70 -0
  56. package/dist/core/memory/remote-embedding.d.ts +10 -0
  57. package/dist/core/memory/remote-embedding.js +36 -0
  58. package/dist/core/memory/types.d.ts +16 -0
  59. package/dist/core/memory/types.js +1 -0
  60. package/dist/core/memory/vector-store.d.ts +15 -0
  61. package/dist/core/memory/vector-store.js +65 -0
  62. package/dist/core/tools/bookmark-tool.d.ts +9 -0
  63. package/dist/core/tools/bookmark-tool.js +118 -0
  64. package/dist/core/tools/browser-tool.d.ts +10 -0
  65. package/dist/core/tools/browser-tool.js +362 -0
  66. package/dist/core/tools/index.d.ts +4 -0
  67. package/dist/core/tools/index.js +4 -0
  68. package/dist/core/tools/install-skill-tool.d.ts +6 -0
  69. package/dist/core/tools/install-skill-tool.js +53 -0
  70. package/dist/core/tools/save-experience-tool.d.ts +5 -0
  71. package/dist/core/tools/save-experience-tool.js +54 -0
  72. package/dist/gateway/auth-hooks.d.ts +17 -0
  73. package/dist/gateway/auth-hooks.js +19 -0
  74. package/dist/gateway/backend-url.d.ts +2 -0
  75. package/dist/gateway/backend-url.js +11 -0
  76. package/dist/gateway/channel-handler.d.ts +6 -0
  77. package/dist/gateway/channel-handler.js +3 -0
  78. package/dist/gateway/clients.d.ts +5 -0
  79. package/dist/gateway/clients.js +4 -0
  80. package/dist/gateway/connection-handler.d.ts +6 -0
  81. package/dist/gateway/connection-handler.js +48 -0
  82. package/dist/gateway/index.d.ts +3 -0
  83. package/dist/gateway/index.js +2 -0
  84. package/dist/gateway/message-handler.d.ts +5 -0
  85. package/dist/gateway/message-handler.js +65 -0
  86. package/dist/gateway/methods/agent-cancel.d.ts +10 -0
  87. package/dist/gateway/methods/agent-cancel.js +17 -0
  88. package/dist/gateway/methods/agent-chat.d.ts +8 -0
  89. package/dist/gateway/methods/agent-chat.js +148 -0
  90. package/dist/gateway/methods/connect.d.ts +9 -0
  91. package/dist/gateway/methods/connect.js +18 -0
  92. package/dist/gateway/methods/install-skill-from-path.d.ts +13 -0
  93. package/dist/gateway/methods/install-skill-from-path.js +15 -0
  94. package/dist/gateway/methods/install-skill-from-upload.d.ts +14 -0
  95. package/dist/gateway/methods/install-skill-from-upload.js +13 -0
  96. package/dist/gateway/methods/run-scheduled-task.d.ts +15 -0
  97. package/dist/gateway/methods/run-scheduled-task.js +127 -0
  98. package/dist/gateway/paths.d.ts +20 -0
  99. package/dist/gateway/paths.js +19 -0
  100. package/dist/gateway/server.d.ts +8 -0
  101. package/dist/gateway/server.js +190 -0
  102. package/dist/gateway/sse-handler.d.ts +6 -0
  103. package/dist/gateway/sse-handler.js +3 -0
  104. package/dist/gateway/types.d.ts +90 -0
  105. package/dist/gateway/types.js +1 -0
  106. package/dist/gateway/utils.d.ts +22 -0
  107. package/dist/gateway/utils.js +67 -0
  108. package/dist/gateway/voice-handler.d.ts +12 -0
  109. package/dist/gateway/voice-handler.js +18 -0
  110. package/dist/index.d.ts +5 -0
  111. package/dist/index.js +5 -0
  112. package/dist/server/agent-config/agent-config.controller.d.ts +30 -0
  113. package/dist/server/agent-config/agent-config.controller.js +83 -0
  114. package/dist/server/agent-config/agent-config.module.d.ts +2 -0
  115. package/dist/server/agent-config/agent-config.module.js +19 -0
  116. package/dist/server/agent-config/agent-config.service.d.ts +53 -0
  117. package/dist/server/agent-config/agent-config.service.js +213 -0
  118. package/dist/server/agents/agents.controller.d.ts +41 -0
  119. package/dist/server/agents/agents.controller.js +118 -0
  120. package/dist/server/agents/agents.gateway.d.ts +21 -0
  121. package/dist/server/agents/agents.gateway.js +103 -0
  122. package/dist/server/agents/agents.module.d.ts +2 -0
  123. package/dist/server/agents/agents.module.js +20 -0
  124. package/dist/server/agents/agents.service.d.ts +63 -0
  125. package/dist/server/agents/agents.service.js +169 -0
  126. package/dist/server/app.module.d.ts +2 -0
  127. package/dist/server/app.module.js +38 -0
  128. package/dist/server/auth/auth.controller.d.ts +20 -0
  129. package/dist/server/auth/auth.controller.js +64 -0
  130. package/dist/server/auth/auth.module.d.ts +2 -0
  131. package/dist/server/auth/auth.module.js +19 -0
  132. package/dist/server/bootstrap.d.ts +15 -0
  133. package/dist/server/bootstrap.js +38 -0
  134. package/dist/server/config/config.controller.d.ts +73 -0
  135. package/dist/server/config/config.controller.js +95 -0
  136. package/dist/server/config/config.module.d.ts +2 -0
  137. package/dist/server/config/config.module.js +21 -0
  138. package/dist/server/config/config.service.d.ts +82 -0
  139. package/dist/server/config/config.service.js +123 -0
  140. package/dist/server/database/database.module.d.ts +2 -0
  141. package/dist/server/database/database.module.js +18 -0
  142. package/dist/server/database/database.service.d.ts +26 -0
  143. package/dist/server/database/database.service.js +253 -0
  144. package/dist/server/main.d.ts +1 -0
  145. package/dist/server/main.js +9 -0
  146. package/dist/server/saved-items/saved-items.controller.d.ts +57 -0
  147. package/dist/server/saved-items/saved-items.controller.js +229 -0
  148. package/dist/server/saved-items/saved-items.module.d.ts +2 -0
  149. package/dist/server/saved-items/saved-items.module.js +25 -0
  150. package/dist/server/saved-items/saved-items.service.d.ts +31 -0
  151. package/dist/server/saved-items/saved-items.service.js +105 -0
  152. package/dist/server/saved-items/tags.controller.d.ts +30 -0
  153. package/dist/server/saved-items/tags.controller.js +85 -0
  154. package/dist/server/saved-items/tags.service.d.ts +24 -0
  155. package/dist/server/saved-items/tags.service.js +84 -0
  156. package/dist/server/skills/skills.controller.d.ts +63 -0
  157. package/dist/server/skills/skills.controller.js +194 -0
  158. package/dist/server/skills/skills.module.d.ts +2 -0
  159. package/dist/server/skills/skills.module.js +22 -0
  160. package/dist/server/skills/skills.service.d.ts +65 -0
  161. package/dist/server/skills/skills.service.js +388 -0
  162. package/dist/server/tasks/tasks.controller.d.ts +52 -0
  163. package/dist/server/tasks/tasks.controller.js +163 -0
  164. package/dist/server/tasks/tasks.module.d.ts +2 -0
  165. package/dist/server/tasks/tasks.module.js +23 -0
  166. package/dist/server/tasks/tasks.service.d.ts +86 -0
  167. package/dist/server/tasks/tasks.service.js +327 -0
  168. package/dist/server/usage/usage.controller.d.ts +12 -0
  169. package/dist/server/usage/usage.controller.js +46 -0
  170. package/dist/server/usage/usage.module.d.ts +2 -0
  171. package/dist/server/usage/usage.module.js +19 -0
  172. package/dist/server/usage/usage.service.d.ts +21 -0
  173. package/dist/server/usage/usage.service.js +55 -0
  174. package/dist/server/users/users.controller.d.ts +35 -0
  175. package/dist/server/users/users.controller.js +69 -0
  176. package/dist/server/users/users.module.d.ts +2 -0
  177. package/dist/server/users/users.module.js +19 -0
  178. package/dist/server/users/users.service.d.ts +39 -0
  179. package/dist/server/users/users.service.js +140 -0
  180. package/dist/server/workspace/workspace.controller.d.ts +24 -0
  181. package/dist/server/workspace/workspace.controller.js +132 -0
  182. package/dist/server/workspace/workspace.module.d.ts +2 -0
  183. package/dist/server/workspace/workspace.module.js +21 -0
  184. package/dist/server/workspace/workspace.service.d.ts +36 -0
  185. package/dist/server/workspace/workspace.service.js +142 -0
  186. package/package.json +90 -0
  187. package/skills/agent-browser/SKILL.md +207 -0
  188. package/skills/agent-browser/references/authentication.md +202 -0
  189. package/skills/agent-browser/references/commands.md +259 -0
  190. package/skills/agent-browser/references/proxy-support.md +188 -0
  191. package/skills/agent-browser/references/session-management.md +193 -0
  192. package/skills/agent-browser/references/snapshot-refs.md +194 -0
  193. package/skills/agent-browser/references/video-recording.md +173 -0
  194. package/skills/agent-browser/templates/authenticated-session.sh +97 -0
  195. package/skills/agent-browser/templates/capture-workflow.sh +69 -0
  196. package/skills/agent-browser/templates/form-automation.sh +62 -0
  197. package/skills/find-skills/SKILL.md +140 -0
  198. package/skills/url-bookmark/SKILL.md +36 -0
@@ -0,0 +1,22 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
+ <title>OpenBot</title>
9
+ <link rel="preconnect" href="https://fonts.googleapis.com">
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
+ <link
12
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Roboto+Mono:wght@400;500&display=swap"
13
+ rel="stylesheet">
14
+ <script type="module" crossorigin src="/assets/index-FI6O25Ms.js"></script>
15
+ <link rel="stylesheet" crossorigin href="/assets/index-CYkSfhcp.css">
16
+ </head>
17
+
18
+ <body>
19
+ <div id="app"></div>
20
+ </body>
21
+
22
+ </html>
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,198 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from "node:module";
3
+ import { dirname, join } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { Command } from "commander";
6
+ import { getOpenbotAgentDir } from "../core/agent/agent-dir.js";
7
+ import { run } from "../core/agent/run.js";
8
+ import { loadDesktopAgentConfig, getBoundAgentIdForCli, setProviderApiKey, setDefaultModel, getDesktopConfigList, syncDesktopConfigToModelsJson, ensureDesktopConfigInitialized, } from "../core/config/desktop-config.js";
9
+ import { writeGatewayPid, removeGatewayPidFile, serviceInstall, serviceUninstall, serviceStop, } from "./service.js";
10
+ const require = createRequire(import.meta.url);
11
+ const PKG = require("../../package.json");
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
13
+ const PKG_ROOT = join(__dirname, "..", "..");
14
+ async function runAction(positionalPrompt, opts) {
15
+ const skillPaths = opts.skillPath || [];
16
+ const agentId = (opts.agent && String(opts.agent).trim()) || (await getBoundAgentIdForCli());
17
+ const prompt = (opts.prompt ?? positionalPrompt ?? "").trim();
18
+ if (!prompt) {
19
+ console.error("Error: 请提供提示词(位置参数或 --prompt)");
20
+ process.exit(1);
21
+ }
22
+ console.error(`[openbot] Using agent: ${agentId}${!opts.agent ? " (default from config)" : ""}`);
23
+ const needDesktop = opts.apiKey === undefined || opts.provider === undefined || opts.model === undefined;
24
+ const desktopConfig = needDesktop ? await loadDesktopAgentConfig(agentId) : null;
25
+ const provider = opts.provider ?? desktopConfig?.provider ?? "deepseek";
26
+ const model = opts.model ?? desktopConfig?.model ?? "deepseek-chat";
27
+ const apiKey = opts.apiKey ?? process.env.OPENAI_API_KEY ?? desktopConfig?.apiKey ?? "";
28
+ if (desktopConfig && (desktopConfig.provider || desktopConfig.model)) {
29
+ console.error(`[openbot] Using model: ${provider}/${model} (from desktop config)`);
30
+ }
31
+ if (opts.timing)
32
+ process.env.OPENBOT_TIMING = "1";
33
+ const workspaceName = desktopConfig?.workspace ?? agentId;
34
+ try {
35
+ const result = await run({
36
+ workspace: workspaceName,
37
+ skillPaths,
38
+ userPrompt: prompt,
39
+ dryRun: opts.dryRun ?? false,
40
+ model,
41
+ provider,
42
+ agentDir: opts.agentDir ?? getOpenbotAgentDir(),
43
+ apiKey: apiKey || undefined,
44
+ });
45
+ if (result.dryRun) {
46
+ console.log("=== System prompt (skills) ===");
47
+ console.log(result.systemPrompt);
48
+ console.log("\n=== User prompt ===");
49
+ console.log(result.userPrompt);
50
+ console.log("\n(dry-run: 未调用 LLM,设置 OPENAI_API_KEY 可实际调用)");
51
+ return;
52
+ }
53
+ // Content is already streamed by run()
54
+ if (!result.dryRun &&
55
+ (result.assistantContent === undefined || result.assistantContent === "")) {
56
+ console.warn("(模型返回为空;若此前有工具调用提示,说明当前为单轮模式,模型会基于技能描述直接以文本回答。)");
57
+ }
58
+ }
59
+ catch (err) {
60
+ console.error(err);
61
+ process.exit(1);
62
+ }
63
+ }
64
+ const program = new Command();
65
+ program
66
+ .name("openbot")
67
+ .description("CLI to run prompts with skill paths (Agent Skills style)")
68
+ .version(PKG.version, "-v, --version", "显示版本号")
69
+ .option("-s, --skill-path <paths...>", "Additional skill paths to load")
70
+ .option("-a, --agent <id>", "指定智能体 ID,不传则使用桌面配置中的缺省智能体")
71
+ .option("-p, --prompt <text>", "用户提示词(与位置参数二选一)")
72
+ .option("--dry-run", "只输出组装的 system/user 内容,不调用 LLM")
73
+ .option("--model <id>", "模型 ID", "deepseek-chat")
74
+ .option("--provider <name>", "Provider(pi ModelRegistry);可选 deepseek、dashscope、openai", "deepseek")
75
+ .option("--agent-dir <path>", "Agent 配置目录(默认 ~/.openbot/agent)", getOpenbotAgentDir())
76
+ .option("--api-key <key>", "API Key(不传则使用环境变量 OPENAI_API_KEY)")
77
+ .option("--timing", "打印每轮 LLM 与 tool 耗时到 stderr")
78
+ .option("--max-tool-turns <n>", "最大工具调用轮数(默认 30);可设环境变量 OPENBOT_MAX_TOOL_TURNS", (v) => parseInt(v, 10) || 0, 0)
79
+ .argument("[prompt]", "用户提示词(与 --prompt 二选一)")
80
+ .action(async (positionalPrompt) => {
81
+ await runAction(positionalPrompt, program.opts());
82
+ });
83
+ program.addHelpText("after", `
84
+ Environment:
85
+ DEEPSEEK_API_KEY 默认 provider 为 deepseek 时使用;不设时回退 OPENAI_API_KEY
86
+ OPENAI_API_KEY 通用 API Key(可被 --api-key 覆盖)
87
+ DASHSCOPE_API_KEY provider=dashscope 时使用;不设时回退 OPENAI_API_KEY
88
+ OPENAI_BASE_URL 可选,在 pi 未找到模型时使用的 endpoint
89
+ OPENBOT_AGENT_DIR 缺省 agent 目录(默认 ~/.openbot/agent)
90
+ OPENBOT_TIMING=1 等同 --timing
91
+ OPENBOT_ALLOW_RUN_CODE 缺省 1(启用 run_python);设为 0 关闭
92
+ OPENBOT_MAX_TOOL_TURNS 最大工具轮数(默认 30)
93
+
94
+ Examples:
95
+ openbot "总结一下当前有哪些技能"
96
+ openbot -a my-agent "总结一下当前有哪些技能" 使用指定智能体
97
+ openbot -s ./skills "总结一下当前有哪些技能"
98
+ openbot -s ./my-skills --prompt "用 weather 技能查北京天气" --dry-run
99
+ `);
100
+ // Gateway server command
101
+ program
102
+ .command("gateway")
103
+ .description("Start WebSocket gateway server")
104
+ .option("-p, --port <port>", "Port to listen on", "38080")
105
+ .action(async (options) => {
106
+ const port = parseInt(options.port, 10);
107
+ if (isNaN(port) || port <= 0 || port > 65535) {
108
+ console.error("Error: Invalid port number");
109
+ process.exit(1);
110
+ }
111
+ writeGatewayPid();
112
+ const { startGatewayServer } = await import("../gateway/index.js");
113
+ const { close } = await startGatewayServer(port);
114
+ const shutdown = async () => {
115
+ console.log("\nShutting down...");
116
+ removeGatewayPidFile();
117
+ await close();
118
+ process.exit(0);
119
+ };
120
+ process.on("SIGINT", shutdown);
121
+ process.on("SIGTERM", shutdown);
122
+ });
123
+ // Service: 开机自启 install / uninstall,以及 stop
124
+ const serviceCmd = program
125
+ .command("service")
126
+ .description("Gateway 开机/登录自启与停止(Linux cron、macOS LaunchAgent、Windows 计划任务)");
127
+ serviceCmd
128
+ .command("install")
129
+ .description("添加开机/登录自启:下次重启或登录后自动启动 gateway")
130
+ .action(() => {
131
+ const nodePath = process.execPath;
132
+ const cliPath = join(__dirname, "cli.js");
133
+ serviceInstall({ nodePath, cliPath });
134
+ });
135
+ serviceCmd
136
+ .command("uninstall")
137
+ .description("移除开机/登录自启")
138
+ .action(() => {
139
+ serviceUninstall();
140
+ });
141
+ serviceCmd
142
+ .command("stop")
143
+ .description("停止当前运行的 gateway 进程")
144
+ .action(() => {
145
+ serviceStop();
146
+ });
147
+ // Login command(写入桌面 config;可选 model,不传则取该 provider 第一个模型,补齐后可直接运行)
148
+ program
149
+ .command("login")
150
+ .description("Save API key for a provider to desktop config (~/.openbot/desktop); optional model, default first model")
151
+ .argument("<provider>", "Provider name (e.g., deepseek, dashscope, openai)")
152
+ .argument("<apiKey>", "API Key")
153
+ .argument("[model]", "Model ID (optional; default: first model for provider)")
154
+ .action(async (provider, apiKey, model) => {
155
+ await setProviderApiKey(provider, apiKey, model);
156
+ console.log(`[openbot] API key saved for provider: ${provider}`);
157
+ });
158
+ // Config command
159
+ const configCmd = program.command("config").description("Manage configurations");
160
+ configCmd
161
+ .command("set-model")
162
+ .description("Set default provider and model in desktop config (~/.openbot/desktop)")
163
+ .argument("<provider>", "Provider name")
164
+ .argument("<modelId>", "Model ID")
165
+ .action(async (provider, modelId) => {
166
+ await setDefaultModel(provider, modelId);
167
+ console.log(`[openbot] Default model set: ${provider}/${modelId}`);
168
+ });
169
+ configCmd
170
+ .command("list")
171
+ .description("List desktop config (centralized config source)")
172
+ .action(async () => {
173
+ const list = await getDesktopConfigList();
174
+ if (list.providers.length === 0) {
175
+ console.log("No providers in desktop config. Run: openbot login <provider> <apiKey>");
176
+ return;
177
+ }
178
+ console.log(`Default: ${list.defaultProvider} / ${list.defaultModel}\n`);
179
+ console.table(list.providers.map((r) => ({
180
+ Provider: r.provider,
181
+ "Default Model": r.defaultModel,
182
+ "API Key": r.hasKey ? "✅" : "❌",
183
+ })));
184
+ });
185
+ configCmd
186
+ .command("sync")
187
+ .description("Sync desktop config to ~/.openbot/agent/models.json for pi-agent")
188
+ .action(async () => {
189
+ await syncDesktopConfigToModelsJson();
190
+ console.log("[openbot] Synced desktop providers to agent models.json");
191
+ });
192
+ (async () => {
193
+ await ensureDesktopConfigInitialized();
194
+ await program.parseAsync(process.argv);
195
+ })().catch((err) => {
196
+ console.error(err);
197
+ process.exit(1);
198
+ });
@@ -0,0 +1,13 @@
1
+ /** 供 gateway 命令调用:写入当前进程 PID */
2
+ export declare function writeGatewayPid(): void;
3
+ /** 供 gateway 命令调用:关闭时删除 PID 文件 */
4
+ export declare function removeGatewayPidFile(): void;
5
+ /** 获取 PID 文件路径(供外部读取) */
6
+ export declare function getGatewayPidPath(): string;
7
+ export type ServiceOptions = {
8
+ nodePath: string;
9
+ cliPath: string;
10
+ };
11
+ export declare function serviceInstall(opts: ServiceOptions): void;
12
+ export declare function serviceUninstall(): void;
13
+ export declare function serviceStop(): boolean;
@@ -0,0 +1,243 @@
1
+ /**
2
+ * openbot service install / uninstall / stop
3
+ * - install: 开机/登录自启(Linux cron @reboot, macOS LaunchAgent, Windows 计划任务)
4
+ * - uninstall: 移除自启
5
+ * - stop: 停止当前运行的 gateway 进程(依赖 gateway 写入的 PID 文件)
6
+ */
7
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
8
+ import { homedir, platform } from "node:os";
9
+ import { join } from "node:path";
10
+ import { execSync, spawnSync } from "node:child_process";
11
+ const OPENBOT_USER_DIR = process.env.OPENBOT_USER_DIR ?? join(homedir(), ".openbot");
12
+ const GATEWAY_PID_FILE = join(OPENBOT_USER_DIR, "gateway.pid");
13
+ const GATEWAY_PORT = 38080;
14
+ /** 供 gateway 命令调用:写入当前进程 PID */
15
+ export function writeGatewayPid() {
16
+ if (!existsSync(OPENBOT_USER_DIR))
17
+ mkdirSync(OPENBOT_USER_DIR, { recursive: true });
18
+ writeFileSync(GATEWAY_PID_FILE, String(process.pid), "utf-8");
19
+ }
20
+ /** 供 gateway 命令调用:关闭时删除 PID 文件 */
21
+ export function removeGatewayPidFile() {
22
+ try {
23
+ if (existsSync(GATEWAY_PID_FILE))
24
+ rmSync(GATEWAY_PID_FILE);
25
+ }
26
+ catch {
27
+ // ignore
28
+ }
29
+ }
30
+ /** 获取 PID 文件路径(供外部读取) */
31
+ export function getGatewayPidPath() {
32
+ return GATEWAY_PID_FILE;
33
+ }
34
+ function getBootCommand(nodePath, cliPath) {
35
+ const port = process.env.OPENBOT_GATEWAY_PORT ?? String(GATEWAY_PORT);
36
+ return `"${nodePath}" "${cliPath}" gateway -p ${port}`;
37
+ }
38
+ function detectPlatform() {
39
+ const p = platform();
40
+ if (p === "win32")
41
+ return "win32";
42
+ if (p === "darwin")
43
+ return "darwin";
44
+ return "linux";
45
+ }
46
+ /** Linux: cron @reboot */
47
+ function installLinux(nodePath, cliPath) {
48
+ const cronLine = `@reboot ${getBootCommand(nodePath, cliPath)}\n`;
49
+ const marker = "# openbot-gateway";
50
+ let current = "";
51
+ try {
52
+ current = execSync("crontab -l 2>/dev/null || true", { encoding: "utf-8" });
53
+ }
54
+ catch {
55
+ // no crontab
56
+ }
57
+ if (current.includes(marker)) {
58
+ throw new Error("已存在 openbot gateway 的开机自启,请先执行 openbot service uninstall");
59
+ }
60
+ const newCrontab = current.trimEnd() + (current ? "\n" : "") + marker + "\n" + cronLine;
61
+ execSync("crontab -", { input: newCrontab, stdio: ["pipe", "inherit", "inherit"] });
62
+ console.log("[openbot] 已添加 cron @reboot,下次重启将自动启动 gateway");
63
+ }
64
+ function uninstallLinux() {
65
+ let current = "";
66
+ try {
67
+ current = execSync("crontab -l 2>/dev/null || true", { encoding: "utf-8" });
68
+ }
69
+ catch {
70
+ console.log("[openbot] 未找到 crontab 或已为空");
71
+ return;
72
+ }
73
+ const marker = "# openbot-gateway";
74
+ const lines = current.split("\n");
75
+ const out = [];
76
+ let skipNext = false;
77
+ for (const line of lines) {
78
+ if (line.includes(marker)) {
79
+ skipNext = true;
80
+ continue;
81
+ }
82
+ if (skipNext && line.trim().startsWith("@reboot") && line.includes("gateway")) {
83
+ skipNext = false;
84
+ continue;
85
+ }
86
+ skipNext = false;
87
+ out.push(line);
88
+ }
89
+ const newCrontab = out.join("\n").replace(/\n\n+/g, "\n").trim();
90
+ if (newCrontab)
91
+ execSync("crontab -", { input: newCrontab, stdio: ["pipe", "inherit", "inherit"] });
92
+ else
93
+ execSync("crontab -r 2>/dev/null || true", { stdio: "inherit" });
94
+ console.log("[openbot] 已移除 cron @reboot");
95
+ }
96
+ function escapePlistString(s) {
97
+ return s
98
+ .replace(/&/g, "&amp;")
99
+ .replace(/</g, "&lt;")
100
+ .replace(/>/g, "&gt;")
101
+ .replace(/"/g, "&quot;");
102
+ }
103
+ /** macOS: LaunchAgent (用户级,登录时运行) */
104
+ function installDarwin(nodePath, cliPath) {
105
+ const launchAgentsDir = join(homedir(), "Library", "LaunchAgents");
106
+ if (!existsSync(launchAgentsDir))
107
+ mkdirSync(launchAgentsDir, { recursive: true });
108
+ const plistPath = join(launchAgentsDir, "com.openbot.gateway.plist");
109
+ if (existsSync(plistPath)) {
110
+ throw new Error("已存在 openbot gateway 自启,请先执行 openbot service uninstall");
111
+ }
112
+ const port = process.env.OPENBOT_GATEWAY_PORT ?? String(GATEWAY_PORT);
113
+ const plist = `<?xml version="1.0" encoding="UTF-8"?>
114
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
115
+ <plist version="1.0">
116
+ <dict>
117
+ <key>Label</key>
118
+ <string>com.openbot.gateway</string>
119
+ <key>ProgramArguments</key>
120
+ <array>
121
+ <string>${escapePlistString(nodePath)}</string>
122
+ <string>${escapePlistString(cliPath)}</string>
123
+ <string>gateway</string>
124
+ <string>-p</string>
125
+ <string>${port}</string>
126
+ </array>
127
+ <key>RunAtLoad</key>
128
+ <true/>
129
+ <key>KeepAlive</key>
130
+ <false/>
131
+ <key>StandardOutPath</key>
132
+ <string>${escapePlistString(OPENBOT_USER_DIR)}/gateway.log</string>
133
+ <key>StandardErrorPath</key>
134
+ <string>${escapePlistString(OPENBOT_USER_DIR)}/gateway.err</string>
135
+ </dict>
136
+ </plist>
137
+ `;
138
+ writeFileSync(plistPath, plist, "utf-8");
139
+ execSync(`launchctl load "${plistPath}"`, { stdio: "inherit" });
140
+ console.log("[openbot] 已安装 LaunchAgent,下次登录将自动启动 gateway");
141
+ }
142
+ function uninstallDarwin() {
143
+ const plistPath = join(homedir(), "Library", "LaunchAgents", "com.openbot.gateway.plist");
144
+ if (existsSync(plistPath)) {
145
+ try {
146
+ execSync(`launchctl unload "${plistPath}"`, { stdio: "inherit" });
147
+ }
148
+ catch {
149
+ // may already be unloaded
150
+ }
151
+ rmSync(plistPath);
152
+ console.log("[openbot] 已移除 LaunchAgent");
153
+ }
154
+ else {
155
+ console.log("[openbot] 未找到自启配置");
156
+ }
157
+ }
158
+ /** Windows: 任务计划(用户登录时运行) */
159
+ function installWin32(nodePath, cliPath) {
160
+ const taskName = "OpenBotGateway";
161
+ const r = spawnSync("schtasks", ["/query", "/tn", taskName], { encoding: "utf-8" });
162
+ if (r.status === 0) {
163
+ throw new Error("已存在 OpenBot Gateway 自启任务,请先执行 openbot service uninstall");
164
+ }
165
+ const port = process.env.OPENBOT_GATEWAY_PORT ?? String(GATEWAY_PORT);
166
+ const cmd = `"${nodePath}" "${cliPath}" gateway -p ${port}`;
167
+ const r2 = spawnSync("schtasks", [
168
+ "/create",
169
+ "/tn", taskName,
170
+ "/tr", cmd,
171
+ "/sc", "onlogon",
172
+ "/rl", "highest",
173
+ "/f",
174
+ ], { encoding: "utf-8", stdio: "inherit", shell: true });
175
+ if (r2.status !== 0) {
176
+ throw new Error("创建计划任务失败,请以管理员身份运行或检查 schtasks");
177
+ }
178
+ console.log("[openbot] 已创建计划任务,下次登录将自动启动 gateway");
179
+ }
180
+ function uninstallWin32() {
181
+ const taskName = "OpenBotGateway";
182
+ const r = spawnSync("schtasks", ["/query", "/tn", taskName], { encoding: "utf-8" });
183
+ if (r.status !== 0) {
184
+ console.log("[openbot] 未找到自启任务");
185
+ return;
186
+ }
187
+ spawnSync("schtasks", ["/delete", "/tn", taskName, "/f"], { stdio: "inherit", shell: true });
188
+ console.log("[openbot] 已删除计划任务");
189
+ }
190
+ /** 停止 gateway:读 PID 文件发 SIGTERM */
191
+ function stopGateway() {
192
+ if (!existsSync(GATEWAY_PID_FILE)) {
193
+ console.log("[openbot] 未找到 gateway PID 文件,可能未以后台/服务方式运行");
194
+ return false;
195
+ }
196
+ const pidStr = readFileSync(GATEWAY_PID_FILE, "utf-8").trim();
197
+ const pid = parseInt(pidStr, 10);
198
+ if (Number.isNaN(pid)) {
199
+ console.log("[openbot] PID 文件内容无效");
200
+ return false;
201
+ }
202
+ try {
203
+ if (platform() === "win32") {
204
+ spawnSync("taskkill", ["/pid", String(pid), "/f"], { stdio: "inherit", shell: true });
205
+ }
206
+ else {
207
+ process.kill(pid, "SIGTERM");
208
+ }
209
+ }
210
+ catch (e) {
211
+ const msg = e instanceof Error ? e.message : String(e);
212
+ if (msg.includes("kill") || msg.includes("ESRCH")) {
213
+ console.log("[openbot] 进程已不存在");
214
+ }
215
+ else {
216
+ throw e;
217
+ }
218
+ }
219
+ removeGatewayPidFile();
220
+ console.log("[openbot] 已停止 gateway");
221
+ return true;
222
+ }
223
+ export function serviceInstall(opts) {
224
+ const p = detectPlatform();
225
+ if (p === "linux")
226
+ installLinux(opts.nodePath, opts.cliPath);
227
+ else if (p === "darwin")
228
+ installDarwin(opts.nodePath, opts.cliPath);
229
+ else
230
+ installWin32(opts.nodePath, opts.cliPath);
231
+ }
232
+ export function serviceUninstall() {
233
+ const p = detectPlatform();
234
+ if (p === "linux")
235
+ uninstallLinux();
236
+ else if (p === "darwin")
237
+ uninstallDarwin();
238
+ else
239
+ uninstallWin32();
240
+ }
241
+ export function serviceStop() {
242
+ return stopGateway();
243
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 兼容旧命令 node dist/cli.js / openbot → 实际入口为 dist/cli/cli.js
4
+ */
5
+ import "./cli/cli.js";
package/dist/cli.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 兼容旧命令 node dist/cli.js / openbot → 实际入口为 dist/cli/cli.js
4
+ */
5
+ import "./cli/cli.js";
@@ -0,0 +1,14 @@
1
+ /**
2
+ * 获取 openbot agent 配置目录(默认 ~/.openbot/agent)
3
+ * 可通过环境变量 OPENBOT_AGENT_DIR 覆盖
4
+ */
5
+ export declare function getOpenbotAgentDir(): string;
6
+ /**
7
+ * 获取 openbot 工作空间根目录(默认 ~/.openbot/workspace)
8
+ * 可通过环境变量 OPENBOT_WORKSPACE_DIR 覆盖
9
+ */
10
+ export declare function getOpenbotWorkspaceDir(): string;
11
+ /**
12
+ * 确保 agent 目录存在,并创建默认配置文件
13
+ */
14
+ export declare function ensureDefaultAgentDir(agentDir: string): void;
@@ -0,0 +1,75 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ /**
5
+ * 获取 openbot agent 配置目录(默认 ~/.openbot/agent)
6
+ * 可通过环境变量 OPENBOT_AGENT_DIR 覆盖
7
+ */
8
+ export function getOpenbotAgentDir() {
9
+ return process.env.OPENBOT_AGENT_DIR ?? join(homedir(), ".openbot", "agent");
10
+ }
11
+ /**
12
+ * 获取 openbot 工作空间根目录(默认 ~/.openbot/workspace)
13
+ * 可通过环境变量 OPENBOT_WORKSPACE_DIR 覆盖
14
+ */
15
+ export function getOpenbotWorkspaceDir() {
16
+ return process.env.OPENBOT_WORKSPACE_DIR ?? join(homedir(), ".openbot", "workspace");
17
+ }
18
+ /**
19
+ * 确保 agent 目录存在,并创建默认配置文件
20
+ */
21
+ export function ensureDefaultAgentDir(agentDir) {
22
+ if (!existsSync(agentDir)) {
23
+ mkdirSync(agentDir, { recursive: true });
24
+ }
25
+ const modelsJsonPath = join(agentDir, "models.json");
26
+ if (!existsSync(modelsJsonPath)) {
27
+ const defaultModels = {
28
+ providers: {
29
+ deepseek: {
30
+ name: "DeepSeek",
31
+ apiKey: "OPENAI_API_KEY",
32
+ api: "openai-completions",
33
+ baseUrl: "https://api.deepseek.com/v1",
34
+ authHeader: true,
35
+ models: [
36
+ {
37
+ id: "deepseek-chat",
38
+ name: "DeepSeek Chat",
39
+ contextWindow: 64000,
40
+ supportsTools: true
41
+ },
42
+ {
43
+ id: "deepseek-reasoner",
44
+ name: "DeepSeek Reasoner",
45
+ contextWindow: 64000,
46
+ supportsTools: true
47
+ }
48
+ ]
49
+ },
50
+ dashscope: {
51
+ name: "DashScope (Alibaba)",
52
+ apiKey: "DASHSCOPE_API_KEY",
53
+ api: "openai-completions",
54
+ baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
55
+ authHeader: true,
56
+ models: [
57
+ {
58
+ id: "qwen-max",
59
+ name: "Qwen Max",
60
+ contextWindow: 30000,
61
+ supportsTools: true
62
+ },
63
+ {
64
+ id: "qwen-plus",
65
+ name: "Qwen Plus",
66
+ contextWindow: 128000,
67
+ supportsTools: true
68
+ }
69
+ ]
70
+ }
71
+ }
72
+ };
73
+ writeFileSync(modelsJsonPath, JSON.stringify(defaultModels, null, 2), "utf-8");
74
+ }
75
+ }
@@ -0,0 +1,64 @@
1
+ import type { AgentSession } from "@mariozechner/pi-coding-agent";
2
+ import type { McpServerConfig } from "../mcp/index.js";
3
+ import type { Skill } from "./skills.js";
4
+ export interface AgentManagerOptions {
5
+ agentDir?: string;
6
+ workspace?: string;
7
+ skillPaths?: string[];
8
+ skills?: Skill[];
9
+ }
10
+ /**
11
+ * Unified Agent Manager for both CLI and Gateway
12
+ */
13
+ export declare class AgentManager {
14
+ private sessions;
15
+ /** 每个 session 最后被使用的时间戳,用于 LRU 淘汰 */
16
+ private sessionLastActiveAt;
17
+ private agentDir;
18
+ private workspaceDir;
19
+ private skillPaths;
20
+ private preLoadedSkills;
21
+ constructor(options?: AgentManagerOptions);
22
+ /**
23
+ * Re-configure the manager
24
+ */
25
+ configure(options: AgentManagerOptions): void;
26
+ /**
27
+ * Build system prompt with skills and browser tool description
28
+ */
29
+ buildSystemPrompt(skills: Skill[]): string;
30
+ /**
31
+ * Get the initial context (prompt and skills)
32
+ */
33
+ getContext(): Promise<{
34
+ systemPrompt: string;
35
+ skills: Skill[];
36
+ }>;
37
+ private createResourceLoader;
38
+ /**
39
+ * Resolve all relevant skill paths (Global, Project, Workspace)
40
+ * @param workspaceDir 当前会话使用的工作区目录,不传则用 manager 默认
41
+ */
42
+ private resolveSkillPaths;
43
+ /**
44
+ * Get or create an agent session.
45
+ * @param options.workspace 该会话绑定的工作区名(来自 agent 配置),不传则用 default,创建时 cwd/技能路径依此
46
+ * @param options.provider / options.modelId 来自 agent 配置的大模型,不传则用环境变量默认
47
+ * @param options.maxSessions 若提供且当前 session 数 >= 该值,会先淘汰最后调用时间最早的 session 再创建新的
48
+ * @param options.targetAgentId 创建时绑定到 install_skill 工具,用于安装目标(具体 agentId 或 global)
49
+ */
50
+ getOrCreateSession(sessionId: string, options?: {
51
+ workspace?: string;
52
+ provider?: string;
53
+ modelId?: string;
54
+ apiKey?: string;
55
+ maxSessions?: number;
56
+ targetAgentId?: string;
57
+ /** MCP 服务器配置列表(与 Skill 类似,配到 Agent 后在创建 Session 时传入) */
58
+ mcpServers?: McpServerConfig[];
59
+ }): Promise<AgentSession>;
60
+ getSession(sessionId: string): AgentSession | undefined;
61
+ deleteSession(sessionId: string): boolean;
62
+ clearAll(): void;
63
+ }
64
+ export declare const agentManager: AgentManager;