agent-muster 0.1.1 → 0.1.2
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 +99 -54
- package/README.zh-CN.md +170 -0
- package/bin/agent-muster.js +0 -0
- package/dist/cli.js +16 -2
- package/dist/feishu-bridge.js +96 -0
- package/dist/feishu.js +232 -0
- package/dist/server.js +91 -3
- package/dist/sessions.js +23 -5
- package/dist/updates.js +40 -0
- package/package.json +10 -5
- package/web/dist/assets/index-5eptghP4.js +83 -0
- package/web/dist/assets/index-B-OcUiqP.css +1 -0
- package/web/dist/index.html +2 -2
- package/web/dist/assets/index-C9mqFMZx.css +0 -1
- package/web/dist/assets/index-DFo3V_i1.js +0 -83
package/README.md
CHANGED
|
@@ -1,124 +1,169 @@
|
|
|
1
1
|
# Agent Muster
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
English | [简体中文](./README.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Manage local AI coding agents, projects, and conversations in your browser. Send tasks and receive replies through DingTalk or Feishu bots.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- 按项目管理对话,在多个窗口中查看和继续不同任务。
|
|
9
|
-
- 选择 Agent 和模型,实时查看回复、工具调用、执行状态及可用的 Token 用量。
|
|
10
|
-
- 保存项目和对话记录,支持停止正在运行的任务。
|
|
11
|
-
- 扫码创建钉钉应用,绑定项目和 Agent,将钉钉消息接入本地对话。
|
|
7
|
+
## Features
|
|
12
8
|
|
|
13
|
-
|
|
9
|
+
- Detect installed Codex, Claude Code, Pi, and Kimi CLI agents.
|
|
10
|
+
- Organize conversations by project and work across one, two, or four conversation panes.
|
|
11
|
+
- Select agents and models, and view live replies, tool calls, execution status, and available token usage.
|
|
12
|
+
- Save projects and conversation history, resume conversations, and stop running tasks.
|
|
13
|
+
- Connect DingTalk and Feishu applications to local agents through the dedicated IM integration page.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
- 要执行任务,需要先安装并配置至少一个支持的 Agent CLI,并确保其命令在 `PATH` 中可用。
|
|
17
|
-
- Agent 的登录、模型权限和费用由对应服务管理。
|
|
15
|
+
## Requirements
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
- Node.js **22.19.0 or later**.
|
|
18
|
+
- Install and configure at least one supported agent CLI, with its command available in `PATH`.
|
|
19
|
+
- Authentication, model access, and charges are managed by each agent's provider.
|
|
20
|
+
|
|
21
|
+
| Agent | Detected command |
|
|
20
22
|
| --- | --- |
|
|
21
23
|
| Codex | `codex` |
|
|
22
24
|
| Claude Code | `claude` |
|
|
23
25
|
| Pi | `pi` |
|
|
24
26
|
| Kimi CLI | `kimi` |
|
|
25
27
|
|
|
26
|
-
##
|
|
28
|
+
## Quick Start
|
|
27
29
|
|
|
28
|
-
|
|
30
|
+
Run without a global installation:
|
|
29
31
|
|
|
30
32
|
```bash
|
|
31
33
|
npx agent-muster
|
|
32
34
|
```
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
The browser opens automatically at the default address:
|
|
35
37
|
|
|
36
38
|
```text
|
|
37
39
|
http://127.0.0.1:17321
|
|
38
40
|
```
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
Or install globally:
|
|
41
43
|
|
|
42
44
|
```bash
|
|
43
45
|
npm install -g agent-muster
|
|
44
46
|
agent-muster
|
|
45
47
|
```
|
|
46
48
|
|
|
47
|
-
|
|
49
|
+
Keep the terminal running. Press `Ctrl+C` to stop the service. The current web interface uses Chinese labels; their names are included below so you can find the relevant controls.
|
|
48
50
|
|
|
49
|
-
##
|
|
51
|
+
## Commands
|
|
50
52
|
|
|
51
|
-
|
|
|
53
|
+
| Command | Description |
|
|
52
54
|
| --- | --- |
|
|
53
|
-
| `agent-muster` |
|
|
54
|
-
| `agent-muster web` |
|
|
55
|
-
| `agent-muster web --no-open` |
|
|
56
|
-
| `agent-muster web --port 18000` |
|
|
57
|
-
| `agent-muster agents` |
|
|
58
|
-
| `agent-muster sessions` |
|
|
55
|
+
| `agent-muster` | Start the web interface and open the browser |
|
|
56
|
+
| `agent-muster web` | Explicitly start the web interface |
|
|
57
|
+
| `agent-muster web --no-open` | Start without opening the browser |
|
|
58
|
+
| `agent-muster web --port 18000` | Use a custom listening port |
|
|
59
|
+
| `agent-muster agents` | List agents and their installation status |
|
|
60
|
+
| `agent-muster sessions` | List saved conversations |
|
|
61
|
+
| `agent-muster update` | Check for updates and update the global installation |
|
|
59
62
|
|
|
60
|
-
|
|
63
|
+
Combine port and browser options:
|
|
61
64
|
|
|
62
65
|
```bash
|
|
63
66
|
npx agent-muster web --port 18000 --no-open
|
|
64
67
|
```
|
|
65
68
|
|
|
66
|
-
|
|
69
|
+
The service listens only on `127.0.0.1`. With the custom port above, visit `http://127.0.0.1:18000`.
|
|
70
|
+
|
|
71
|
+
## Create Your First Task
|
|
72
|
+
|
|
73
|
+
1. Start Agent Muster and add a local project directory using **添加项目** (Add project).
|
|
74
|
+
2. Create a conversation in that project using **创建对话** (Create conversation), then select an installed agent and a model.
|
|
75
|
+
3. Enter a task, such as: `Inspect this project's startup flow and explain how to run it.`
|
|
76
|
+
4. Follow replies, tool calls, and execution status in the conversation pane. Send further messages to continue the task.
|
|
77
|
+
|
|
78
|
+
The agent runs in the selected project directory. Model availability depends on the corresponding CLI configuration and access permissions. Continuing a conversation requires a resumable session created by the agent.
|
|
79
|
+
|
|
80
|
+
## IM Integration
|
|
81
|
+
|
|
82
|
+
Open **IM 集成** (IM integration) in the sidebar and choose **钉钉** (DingTalk) or **飞书** (Feishu). Each application has its own project and agent binding.
|
|
83
|
+
|
|
84
|
+
| Capability | DingTalk | Feishu |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| Application creation | Scan a QR code with DingTalk | Scan a QR code with Feishu |
|
|
87
|
+
| Message listener | DingTalk Stream SDK | Feishu SDK WebSocket connection |
|
|
88
|
+
| Incoming messages | Text, images, and rich text with images | Text |
|
|
89
|
+
| Conversations | Direct messages and group mentions of the bot | Direct messages and group mentions of the bot |
|
|
90
|
+
| Replies | Automatic agent replies and messages sent from the web interface | Automatic agent replies and messages sent from the web interface |
|
|
91
|
+
| Application management | Project/agent binding, name/icon sync, and local removal | Project/agent binding, name/icon sync, connection status, and local removal |
|
|
92
|
+
|
|
93
|
+
### Create and Connect an Application
|
|
94
|
+
|
|
95
|
+
1. Add a project in Agent Muster and confirm the target agent is installed and configured.
|
|
96
|
+
2. Open **IM 集成**, choose a platform, and click **扫码创建应用** (Create application by scanning).
|
|
97
|
+
3. Scan the QR code with the selected platform's mobile app. Follow the authorization page to create and authorize the application. If the QR code expires, request a new one.
|
|
98
|
+
4. Select a project and an agent for the new application. Click **一键同步** (Sync) to refresh its name and icon from the platform.
|
|
99
|
+
5. Send the bot a direct message, or add it to a group and mention it with a task. For Feishu, check that the application shows **消息监听已连接** (Message listener connected).
|
|
100
|
+
|
|
101
|
+
Keep Agent Muster running and connected to the selected platform. Messages are received through SDK connections established by the local service, so a public webhook address is not required.
|
|
67
102
|
|
|
68
|
-
|
|
103
|
+
### Receive Tasks and Reply
|
|
69
104
|
|
|
70
|
-
|
|
71
|
-
2. 在该项目下新建对话,选择已安装的 Agent 和模型。
|
|
72
|
-
3. 输入任务并发送,例如:`检查这个项目的启动流程,说明如何运行。`
|
|
73
|
-
4. 在对话窗口查看回复、工具调用和执行状态,继续发送消息完成任务。
|
|
105
|
+
An incoming message starts a task using the bound agent in the bound project. When execution finishes, Agent Muster sends the result back to the original IM conversation.
|
|
74
106
|
|
|
75
|
-
|
|
107
|
+
Messages in the same IM conversation reuse its local agent session and are processed in order. Changing an application's project or agent binding clears its IM conversation mappings; the next incoming message starts a new local conversation.
|
|
76
108
|
|
|
77
|
-
|
|
109
|
+
DingTalk image input is supported by the Codex, Claude Code, and Pi integrations. The Kimi CLI integration does not support image input. The Feishu integration currently processes text messages only.
|
|
78
110
|
|
|
79
|
-
|
|
80
|
-
2. 打开「钉钉接入」,点击「扫码创建应用」。
|
|
81
|
-
3. 使用钉钉扫描二维码,按授权页面提示完成应用创建和授权。
|
|
82
|
-
4. 为创建的应用选择项目和 Agent,可点击「一键同步」更新名称和图标。
|
|
83
|
-
5. 在钉钉中向该机器人发送消息,群聊中可通过提及机器人发送任务。
|
|
111
|
+
### Send Messages from the Web Interface
|
|
84
112
|
|
|
85
|
-
|
|
113
|
+
Open a conversation created through IM, then use the send-mode selector beside the message input:
|
|
86
114
|
|
|
87
|
-
|
|
115
|
+
- **发送到钉钉** / **发送到飞书** (Send to DingTalk / Feishu): send the entered text directly to the linked IM conversation as the application, without running the agent. The sent message is recorded in the local conversation.
|
|
116
|
+
- **交给 Agent** (Send to agent): continue the local agent task. This mode does not automatically send the resulting reply to IM.
|
|
88
117
|
|
|
89
|
-
|
|
118
|
+
Direct sending requires an existing IM conversation mapping. The Feishu sender splits long replies into multiple text messages.
|
|
90
119
|
|
|
91
|
-
|
|
120
|
+
### Remove an Integration
|
|
92
121
|
|
|
93
|
-
|
|
122
|
+
Click **删除** (Delete) on the application entry to remove its local integration and stop receiving its messages. Existing conversation history is retained. The application on DingTalk or Feishu is not deleted.
|
|
94
123
|
|
|
95
|
-
##
|
|
124
|
+
## Local Data
|
|
96
125
|
|
|
97
|
-
|
|
126
|
+
Projects, conversations, and IM configuration are stored in `.agent-muster` under your home directory and loaded again on startup. DingTalk and Feishu application credentials are stored in `dingtalk-apps.json` and `feishu-apps.json`, respectively. Keep these files private.
|
|
98
127
|
|
|
99
|
-
|
|
128
|
+
## FAQ
|
|
100
129
|
|
|
101
|
-
###
|
|
130
|
+
### An Agent Appears Uninstalled
|
|
102
131
|
|
|
103
|
-
|
|
132
|
+
Run its command in the terminal used to start Agent Muster. Confirm that the CLI is installed and works. Restart Agent Muster after installation or changes to `PATH`.
|
|
133
|
+
|
|
134
|
+
### The Default Port Is in Use
|
|
135
|
+
|
|
136
|
+
Choose another port:
|
|
104
137
|
|
|
105
138
|
```bash
|
|
106
139
|
npx agent-muster web --port 18000
|
|
107
140
|
```
|
|
108
141
|
|
|
109
|
-
###
|
|
142
|
+
### An IM Bot Does Not Reply
|
|
143
|
+
|
|
144
|
+
Confirm that Agent Muster is running, platform authorization is complete, and the application is bound to a project and an available agent. In groups, mention the bot. For Feishu, check its connection status and use a text message. Inspect the web conversation log and startup terminal for task status and errors.
|
|
145
|
+
|
|
146
|
+
### A Message Cannot Be Sent from the Web Interface
|
|
147
|
+
|
|
148
|
+
Send a message to the bot from IM first, then open the resulting local conversation. Confirm that the integration still exists and its project/agent binding has not changed. Select **发送到钉钉** or **发送到飞书** before sending.
|
|
110
149
|
|
|
111
|
-
|
|
150
|
+
## Updates
|
|
112
151
|
|
|
113
|
-
|
|
152
|
+
On web startup, Agent Muster checks for a newer version in the background and prints an update notice in the terminal.
|
|
153
|
+
|
|
154
|
+
For a global installation:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
agent-muster update
|
|
158
|
+
```
|
|
114
159
|
|
|
115
|
-
|
|
160
|
+
This command checks the latest version and uses npm to update the global installation when an update is available. Restart the service afterward. You can also update manually:
|
|
116
161
|
|
|
117
162
|
```bash
|
|
118
163
|
npm install -g agent-muster@latest
|
|
119
164
|
```
|
|
120
165
|
|
|
121
|
-
|
|
166
|
+
When using `npx`, explicitly select the latest published version:
|
|
122
167
|
|
|
123
168
|
```bash
|
|
124
169
|
npx agent-muster@latest
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Agent Muster
|
|
2
|
+
|
|
3
|
+
[English](./README.md) | 简体中文
|
|
4
|
+
|
|
5
|
+
在本地浏览器中管理多个 AI 编码 Agent、项目和对话,也可以通过钉钉或飞书机器人向 Agent 发送任务并接收回复。
|
|
6
|
+
|
|
7
|
+
## 功能
|
|
8
|
+
|
|
9
|
+
- 自动检测本机已安装的 Codex、Claude Code、Pi 和 Kimi CLI。
|
|
10
|
+
- 按项目管理对话,支持单窗、双窗和四窗布局,同时查看和继续不同任务。
|
|
11
|
+
- 选择 Agent 和模型,实时查看回复、工具调用、执行状态及可用的 Token 用量。
|
|
12
|
+
- 保存项目和对话记录,支持继续对话和停止正在运行的任务。
|
|
13
|
+
- 通过独立的 IM 集成页面,将钉钉和飞书应用接入本地 Agent。
|
|
14
|
+
|
|
15
|
+
## 环境要求
|
|
16
|
+
|
|
17
|
+
- Node.js **22.19.0 或更高版本**。
|
|
18
|
+
- 要执行任务,需要先安装并配置至少一个支持的 Agent CLI,并确保其命令在 `PATH` 中可用。
|
|
19
|
+
- Agent 的登录、模型权限和费用由对应服务管理。
|
|
20
|
+
|
|
21
|
+
| Agent | 检测的命令 |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| Codex | `codex` |
|
|
24
|
+
| Claude Code | `claude` |
|
|
25
|
+
| Pi | `pi` |
|
|
26
|
+
| Kimi CLI | `kimi` |
|
|
27
|
+
|
|
28
|
+
## 快速开始
|
|
29
|
+
|
|
30
|
+
无需全局安装,直接启动:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npx agent-muster
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
启动后会自动打开浏览器,默认地址为:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
http://127.0.0.1:17321
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
也可以全局安装:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm install -g agent-muster
|
|
46
|
+
agent-muster
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
保持启动终端运行,按 `Ctrl+C` 停止服务。当前 Web 界面使用中文标签。
|
|
50
|
+
|
|
51
|
+
## 命令
|
|
52
|
+
|
|
53
|
+
| 命令 | 说明 |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| `agent-muster` | 启动 Web 界面并打开浏览器 |
|
|
56
|
+
| `agent-muster web` | 显式启动 Web 界面 |
|
|
57
|
+
| `agent-muster web --no-open` | 启动服务,不自动打开浏览器 |
|
|
58
|
+
| `agent-muster web --port 18000` | 指定监听端口 |
|
|
59
|
+
| `agent-muster agents` | 列出 Agent 及安装状态 |
|
|
60
|
+
| `agent-muster sessions` | 列出已保存的对话 |
|
|
61
|
+
| `agent-muster update` | 检查并更新全局安装到最新版本 |
|
|
62
|
+
|
|
63
|
+
端口和浏览器选项可以组合使用:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx agent-muster web --port 18000 --no-open
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
服务仅监听本机地址 `127.0.0.1`,使用上述自定义端口时,请访问 `http://127.0.0.1:18000`。
|
|
70
|
+
|
|
71
|
+
## 创建第一个任务
|
|
72
|
+
|
|
73
|
+
1. 启动 Agent Muster,在 Web 界面点击「添加项目」,选择一个本地项目目录。
|
|
74
|
+
2. 在该项目下点击「创建对话」,选择已安装的 Agent 和模型。
|
|
75
|
+
3. 输入任务并发送,例如:`检查这个项目的启动流程,说明如何运行。`
|
|
76
|
+
4. 在对话窗口查看回复、工具调用和执行状态,继续发送消息完成任务。
|
|
77
|
+
|
|
78
|
+
Agent 在选中的项目目录中执行任务。模型列表取决于对应 CLI 的配置与可用权限。继续对话需要 Agent 已创建可恢复的会话。
|
|
79
|
+
|
|
80
|
+
## IM 集成
|
|
81
|
+
|
|
82
|
+
在侧边栏打开「IM 集成」,选择「钉钉」或「飞书」。每个应用分别绑定项目和 Agent。
|
|
83
|
+
|
|
84
|
+
| 能力 | 钉钉 | 飞书 |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| 创建应用 | 使用钉钉扫码创建 | 使用飞书扫码创建 |
|
|
87
|
+
| 消息监听 | 钉钉 Stream SDK | 飞书 SDK WebSocket 长连接 |
|
|
88
|
+
| 接收消息 | 文本、图片和图文消息 | 文本消息 |
|
|
89
|
+
| 对话场景 | 单聊、群聊中提及机器人 | 单聊、群聊中提及机器人 |
|
|
90
|
+
| 消息回复 | Agent 自动回复、Web 界面主动发送 | Agent 自动回复、Web 界面主动发送 |
|
|
91
|
+
| 应用管理 | 绑定项目和 Agent、同步名称和图标、删除本地接入 | 绑定项目和 Agent、同步名称和图标、查看连接状态、删除本地接入 |
|
|
92
|
+
|
|
93
|
+
### 扫码创建与绑定应用
|
|
94
|
+
|
|
95
|
+
1. 先在 Agent Muster 中添加项目,确认目标 Agent 已安装并配置完成。
|
|
96
|
+
2. 打开「IM 集成」,选择平台,点击「扫码创建应用」。
|
|
97
|
+
3. 使用对应平台的手机应用扫描二维码,按授权页面提示完成应用创建和授权。二维码过期后可重新获取。
|
|
98
|
+
4. 为创建的应用选择项目和 Agent,点击「一键同步」可更新平台上的名称和图标。
|
|
99
|
+
5. 向机器人发送单聊消息,或将机器人加入群聊并提及它发送任务。使用飞书时,确认应用状态显示「消息监听已连接」。
|
|
100
|
+
|
|
101
|
+
接入期间需要保持 Agent Muster 运行,并能连接对应平台。本地服务通过 SDK 建立连接接收消息,无需提供公网 Webhook 地址。
|
|
102
|
+
|
|
103
|
+
### 接收任务与自动回复
|
|
104
|
+
|
|
105
|
+
收到消息后,Agent Muster 会在绑定项目中调用选定的 Agent,任务结束后将结果发送回原 IM 对话。
|
|
106
|
+
|
|
107
|
+
同一 IM 对话会继续使用已有的本地 Agent 会话,消息按顺序处理。修改应用绑定的项目或 Agent 会清空 IM 对话映射,下一条消息将创建新的本地对话。
|
|
108
|
+
|
|
109
|
+
钉钉图片输入支持 Codex、Claude Code 和 Pi,当前 Kimi CLI 接入不支持图片输入。飞书接入目前只处理文本消息。
|
|
110
|
+
|
|
111
|
+
### 在 Web 界面主动发送消息
|
|
112
|
+
|
|
113
|
+
打开由 IM 创建的本地对话,在输入框旁选择发送方式:
|
|
114
|
+
|
|
115
|
+
- 「发送到钉钉」或「发送到飞书」:以应用身份将输入的文本直接发送到关联的 IM 对话,不运行 Agent;发送记录保存在本地对话中。
|
|
116
|
+
- 「交给 Agent」:继续本地 Agent 任务,此模式不会将执行结果自动发送到 IM。
|
|
117
|
+
|
|
118
|
+
主动发送需要已有的 IM 对话映射。飞书发送较长的回复时会分成多条文本消息。
|
|
119
|
+
|
|
120
|
+
### 删除接入
|
|
121
|
+
|
|
122
|
+
点击应用条目中的「删除」,可移除本地接入并停止接收该应用的消息。已有对话记录会保留,钉钉或飞书平台中的应用不会被删除。
|
|
123
|
+
|
|
124
|
+
## 本地数据
|
|
125
|
+
|
|
126
|
+
项目、对话和 IM 接入配置保存在用户主目录下的 `.agent-muster` 中,重新启动后会读取已有记录。钉钉和飞书应用凭证分别保存在 `dingtalk-apps.json` 和 `feishu-apps.json` 中,请妥善保管这些文件。
|
|
127
|
+
|
|
128
|
+
## 常见问题
|
|
129
|
+
|
|
130
|
+
### Agent 显示未安装
|
|
131
|
+
|
|
132
|
+
在启动 Agent Muster 的终端中运行对应命令,确认 CLI 已安装且可以正常执行。安装或调整 `PATH` 后重新启动 Agent Muster。
|
|
133
|
+
|
|
134
|
+
### 默认端口被占用
|
|
135
|
+
|
|
136
|
+
通过 `--port` 指定其他端口:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
npx agent-muster web --port 18000
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### IM 机器人没有回复
|
|
143
|
+
|
|
144
|
+
确认本地服务仍在运行,已完成平台授权,应用已绑定项目和可用的 Agent。群聊中需要提及机器人;使用飞书时,检查连接状态并发送文本消息。可以在 Web 对话日志和启动终端中查看任务状态与错误信息。
|
|
145
|
+
|
|
146
|
+
### Web 界面无法主动发送消息
|
|
147
|
+
|
|
148
|
+
先从 IM 向机器人发送一条消息,再打开由此创建的本地对话。确认应用接入仍存在,项目和 Agent 绑定未被修改,并选择「发送到钉钉」或「发送到飞书」后发送。
|
|
149
|
+
|
|
150
|
+
## 更新
|
|
151
|
+
|
|
152
|
+
启动 Web 服务时会在后台检查新版本,并在终端显示更新提示。
|
|
153
|
+
|
|
154
|
+
全局安装的用户可以运行:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
agent-muster update
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
命令会检查最新版本,已有新版本时通过 npm 更新全局安装。更新完成后重新启动服务即可生效,也可以手动更新:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
npm install -g agent-muster@latest
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
使用 `npx` 时,可以明确指定最新发布版本:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
npx agent-muster@latest
|
|
170
|
+
```
|
package/bin/agent-muster.js
CHANGED
|
File without changes
|
package/dist/cli.js
CHANGED
|
@@ -2,9 +2,12 @@ import { spawn } from 'node:child_process';
|
|
|
2
2
|
import { AgentRegistry } from './agents.js';
|
|
3
3
|
import { DingTalkBridge } from './dingtalk-bridge.js';
|
|
4
4
|
import { DingTalkRegistry } from './dingtalk.js';
|
|
5
|
+
import { FeishuRegistry } from './feishu.js';
|
|
6
|
+
import { FeishuBridge } from './feishu-bridge.js';
|
|
5
7
|
import { ProjectRegistry } from './projects.js';
|
|
6
8
|
import { SessionManager } from './sessions.js';
|
|
7
9
|
import { startServer } from './server.js';
|
|
10
|
+
import { checkForUpdates, updatePackage } from './updates.js';
|
|
8
11
|
function openBrowser(url) {
|
|
9
12
|
const command = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'cmd' : 'xdg-open';
|
|
10
13
|
const args = process.platform === 'win32' ? ['/c', 'start', '', url] : [url];
|
|
@@ -12,6 +15,10 @@ function openBrowser(url) {
|
|
|
12
15
|
}
|
|
13
16
|
async function main() {
|
|
14
17
|
const [command = 'web', ...options] = process.argv.slice(2);
|
|
18
|
+
if (command === 'update') {
|
|
19
|
+
await updatePackage();
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
15
22
|
const registry = new AgentRegistry();
|
|
16
23
|
await registry.scan();
|
|
17
24
|
const sessions = new SessionManager();
|
|
@@ -20,6 +27,8 @@ async function main() {
|
|
|
20
27
|
await projects.load();
|
|
21
28
|
const dingtalk = new DingTalkRegistry();
|
|
22
29
|
await dingtalk.load();
|
|
30
|
+
const feishu = new FeishuRegistry();
|
|
31
|
+
await feishu.load();
|
|
23
32
|
if (command === 'agents') {
|
|
24
33
|
console.log('Installed Agents\n');
|
|
25
34
|
for (const agent of registry.list())
|
|
@@ -38,12 +47,16 @@ async function main() {
|
|
|
38
47
|
for (const { sessionId, appId } of dingtalk.sessionBindings())
|
|
39
48
|
sessions.linkDingTalkSession(sessionId, appId);
|
|
40
49
|
new DingTalkBridge(dingtalk, registry, sessions);
|
|
50
|
+
for (const { sessionId, appId } of feishu.sessionBindings())
|
|
51
|
+
sessions.linkFeishuSession(sessionId, appId);
|
|
52
|
+
new FeishuBridge(feishu, registry, sessions);
|
|
41
53
|
const portIndex = options.indexOf('--port');
|
|
42
54
|
const port = portIndex >= 0 ? Number(options[portIndex + 1]) : 17321;
|
|
43
55
|
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
44
56
|
throw new Error('Port must be 1–65535');
|
|
45
|
-
const server = await startServer(port, registry, projects, sessions, dingtalk);
|
|
57
|
+
const server = await startServer(port, registry, projects, sessions, dingtalk, feishu, options.includes('--dev'));
|
|
46
58
|
dingtalk.startSubscriptions();
|
|
59
|
+
feishu.startSubscriptions();
|
|
47
60
|
const url = `http://127.0.0.1:${port}`;
|
|
48
61
|
console.log(`Agent Muster started\n\nWeb: ${url}\n\nDetected Agents:`);
|
|
49
62
|
for (const agent of registry.list())
|
|
@@ -51,8 +64,9 @@ async function main() {
|
|
|
51
64
|
console.log('\nPress Ctrl+C to stop');
|
|
52
65
|
if (!options.includes('--no-open'))
|
|
53
66
|
openBrowser(url);
|
|
54
|
-
const shutdown = () => { dingtalk.shutdown(); sessions.shutdown(); server.close(); server.closeAllConnections(); };
|
|
67
|
+
const shutdown = () => { dingtalk.shutdown(); feishu.shutdown(); sessions.shutdown(); server.close(); server.closeAllConnections(); };
|
|
55
68
|
process.once('SIGINT', shutdown);
|
|
56
69
|
process.once('SIGTERM', shutdown);
|
|
70
|
+
void checkForUpdates().catch(() => console.warn('无法检查更新,请稍后运行 agent-muster update 重试。'));
|
|
57
71
|
}
|
|
58
72
|
main().catch(error => { console.error(error.message); process.exitCode = 1; });
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const terminalStatuses = new Set(['completed', 'failed', 'stopped']);
|
|
2
|
+
function waitForCompletion(sessions, session) {
|
|
3
|
+
if (terminalStatuses.has(session.status) && !sessions.isRunning(session.id))
|
|
4
|
+
return Promise.resolve();
|
|
5
|
+
return new Promise(resolve => {
|
|
6
|
+
const check = () => {
|
|
7
|
+
if (!terminalStatuses.has(session.status) || sessions.isRunning(session.id))
|
|
8
|
+
return;
|
|
9
|
+
sessions.off(session.id, onEvent);
|
|
10
|
+
sessions.off(`${session.id}:idle`, check);
|
|
11
|
+
resolve();
|
|
12
|
+
};
|
|
13
|
+
const onEvent = (event) => { if (event.type === 'status')
|
|
14
|
+
check(); };
|
|
15
|
+
sessions.on(session.id, onEvent);
|
|
16
|
+
sessions.on(`${session.id}:idle`, check);
|
|
17
|
+
check();
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export class FeishuBridge {
|
|
21
|
+
feishu;
|
|
22
|
+
agents;
|
|
23
|
+
sessions;
|
|
24
|
+
queues = new Map();
|
|
25
|
+
seen = new Set();
|
|
26
|
+
constructor(feishu, agents, sessions) {
|
|
27
|
+
this.feishu = feishu;
|
|
28
|
+
this.agents = agents;
|
|
29
|
+
this.sessions = sessions;
|
|
30
|
+
feishu.on('message', event => this.enqueue(event));
|
|
31
|
+
}
|
|
32
|
+
enqueue({ appId, message: event }) {
|
|
33
|
+
const { message, sender } = event;
|
|
34
|
+
if (sender.sender_type !== 'user' || message.message_type !== 'text')
|
|
35
|
+
return;
|
|
36
|
+
const key = `${appId}:${message.chat_id}`;
|
|
37
|
+
const messageKey = `${appId}:${message.message_id}`;
|
|
38
|
+
if (this.seen.has(messageKey))
|
|
39
|
+
return;
|
|
40
|
+
this.seen.add(messageKey);
|
|
41
|
+
if (this.seen.size > 1000)
|
|
42
|
+
this.seen.delete(this.seen.values().next().value);
|
|
43
|
+
const task = (this.queues.get(key) || Promise.resolve()).then(() => this.process(appId, event)).catch(async (error) => {
|
|
44
|
+
console.error(`飞书消息 ${message.message_id} 处理失败:`, error);
|
|
45
|
+
try {
|
|
46
|
+
await this.feishu.send(appId, message.chat_id, 'Agent 执行失败,请在 Agent Muster 中查看会话日志。');
|
|
47
|
+
}
|
|
48
|
+
catch (replyError) {
|
|
49
|
+
console.error('飞书错误消息发送失败:', replyError);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
this.queues.set(key, task);
|
|
53
|
+
void task.finally(() => { if (this.queues.get(key) === task)
|
|
54
|
+
this.queues.delete(key); });
|
|
55
|
+
}
|
|
56
|
+
async process(appId, { message, sender }) {
|
|
57
|
+
const body = JSON.parse(message.content);
|
|
58
|
+
let content = body.text;
|
|
59
|
+
for (const mention of message.mentions || [])
|
|
60
|
+
content = content.replaceAll(mention.key, mention.mentioned_type === 'app' ? '' : `@${mention.name}`);
|
|
61
|
+
content = content.trim();
|
|
62
|
+
if (!content)
|
|
63
|
+
return;
|
|
64
|
+
const binding = this.feishu.getBinding(appId);
|
|
65
|
+
if (!binding?.project || !binding.agent) {
|
|
66
|
+
await this.feishu.send(appId, message.chat_id, '请先在 Agent Muster 中为此应用绑定项目和 Agent。');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (!this.agents.get(binding.agent)?.installed) {
|
|
70
|
+
await this.feishu.send(appId, message.chat_id, '绑定的 Agent 当前不可用。');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const senderId = sender.sender_id?.open_id;
|
|
74
|
+
if (!senderId)
|
|
75
|
+
throw new Error('飞书消息缺少发送人标识');
|
|
76
|
+
const conversation = { type: message.chat_type === 'group' ? 'group' : 'single', senderId };
|
|
77
|
+
const prompt = message.chat_type === 'group' ? `${senderId} 在群聊中说:\n${content}` : content;
|
|
78
|
+
const previousId = this.feishu.getSession(appId, message.chat_id);
|
|
79
|
+
let session = previousId ? this.sessions.get(previousId) : undefined;
|
|
80
|
+
if (session && (this.sessions.isRunning(session.id) || !terminalStatuses.has(session.status)))
|
|
81
|
+
await waitForCompletion(this.sessions, session);
|
|
82
|
+
const lastEventId = session?.events.at(-1)?.id || 0;
|
|
83
|
+
if (session) {
|
|
84
|
+
this.sessions.linkFeishuSession(session.id, appId);
|
|
85
|
+
this.sessions.send(session.id, prompt, undefined, undefined, undefined, conversation);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
session = await this.sessions.create(binding.agent, binding.project, prompt, undefined, undefined, undefined, undefined, { appId, conversation });
|
|
89
|
+
await this.feishu.setSession(appId, message.chat_id, session.id);
|
|
90
|
+
}
|
|
91
|
+
await waitForCompletion(this.sessions, session);
|
|
92
|
+
const output = session.events.filter(event => event.id > lastEventId && event.type === 'output').at(-1)?.text.trim();
|
|
93
|
+
const reply = session.status === 'completed' ? output || 'Agent 已执行完成。' : 'Agent 执行失败,请在 Agent Muster 中查看会话日志。';
|
|
94
|
+
await this.feishu.send(appId, message.chat_id, reply);
|
|
95
|
+
}
|
|
96
|
+
}
|