@keyou007/agent-bot 0.1.9 → 0.1.11

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 (119) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +22 -10
  3. package/README.zh.md +22 -10
  4. package/assets/agent-bot-logo.png +0 -0
  5. package/dist/acp/AcpSessionManager.js +78 -46
  6. package/dist/acp/AcpSessionManager.js.map +1 -1
  7. package/dist/cli/FeishuAppConfiguration.js +84 -22
  8. package/dist/cli/FeishuAppConfiguration.js.map +1 -1
  9. package/dist/cli/FeishuAppRegistration.js +12 -9
  10. package/dist/cli/FeishuAppRegistration.js.map +1 -1
  11. package/dist/cli/Initializer.js +7 -6
  12. package/dist/cli/Initializer.js.map +1 -1
  13. package/dist/cli/LocalControlClient.js +3 -2
  14. package/dist/cli/LocalControlClient.js.map +1 -1
  15. package/dist/cli/LocalControlServer.js +2 -1
  16. package/dist/cli/LocalControlServer.js.map +1 -1
  17. package/dist/cli/OptionalAuthorizationSkip.js +27 -6
  18. package/dist/cli/OptionalAuthorizationSkip.js.map +1 -1
  19. package/dist/cli/ServerStarter.js +12 -3
  20. package/dist/cli/ServerStarter.js.map +1 -1
  21. package/dist/cli/SkillRegistry.js +5 -4
  22. package/dist/cli/SkillRegistry.js.map +1 -1
  23. package/dist/cli/VerificationOutput.js +2 -1
  24. package/dist/cli/VerificationOutput.js.map +1 -1
  25. package/dist/cli/help.js +48 -1
  26. package/dist/cli/help.js.map +1 -1
  27. package/dist/cli/i18n.js +27 -0
  28. package/dist/cli/i18n.js.map +1 -0
  29. package/dist/cli/initOptions.js +5 -4
  30. package/dist/cli/initOptions.js.map +1 -1
  31. package/dist/cli/packageVersion.js +2 -1
  32. package/dist/cli/packageVersion.js.map +1 -1
  33. package/dist/cli/profile.js +4 -3
  34. package/dist/cli/profile.js.map +1 -1
  35. package/dist/cli/serverStatus.js +15 -14
  36. package/dist/cli/serverStatus.js.map +1 -1
  37. package/dist/cli/taskChatRoute.js +3 -2
  38. package/dist/cli/taskChatRoute.js.map +1 -1
  39. package/dist/cli.js +165 -107
  40. package/dist/cli.js.map +1 -1
  41. package/dist/codex/AppServerConnection.js +15 -1
  42. package/dist/codex/AppServerConnection.js.map +1 -1
  43. package/dist/codex/CodexLocalActivityDetector.js +4 -1
  44. package/dist/codex/CodexLocalActivityDetector.js.map +1 -1
  45. package/dist/codex/CodexProcessManager.js +1 -0
  46. package/dist/codex/CodexProcessManager.js.map +1 -1
  47. package/dist/codex/CodexRuntime.js +77 -2
  48. package/dist/codex/CodexRuntime.js.map +1 -1
  49. package/dist/commands/CommandRouter.js +108 -47
  50. package/dist/commands/CommandRouter.js.map +1 -1
  51. package/dist/console/ConsoleTurnPresenter.js +1 -1
  52. package/dist/console/ConsoleTurnPresenter.js.map +1 -1
  53. package/dist/feishu/CardRenderer.js +345 -11
  54. package/dist/feishu/CardRenderer.js.map +1 -1
  55. package/dist/feishu/FeishuMessageClient.js +51 -5
  56. package/dist/feishu/FeishuMessageClient.js.map +1 -1
  57. package/dist/feishu/FeishuTurnPresenter.js +8 -3
  58. package/dist/feishu/FeishuTurnPresenter.js.map +1 -1
  59. package/dist/index.js +18 -17
  60. package/dist/index.js.map +1 -1
  61. package/dist/proxy/ProxySessionController.js +595 -205
  62. package/dist/proxy/ProxySessionController.js.map +1 -1
  63. package/dist/runtime/AcpRuntimeAdapter.js +1 -0
  64. package/dist/runtime/AcpRuntimeAdapter.js.map +1 -1
  65. package/dist/runtime/AgentRuntimeRegistry.js +7 -4
  66. package/dist/runtime/AgentRuntimeRegistry.js.map +1 -1
  67. package/dist/runtime/createAgentRuntimeRegistry.js +22 -0
  68. package/dist/runtime/createAgentRuntimeRegistry.js.map +1 -0
  69. package/dist/startup/SessionMetadataHydrator.js +2 -2
  70. package/dist/startup/SessionMetadataHydrator.js.map +1 -1
  71. package/dist/startup/StartupNotifier.js +1 -0
  72. package/dist/startup/StartupNotifier.js.map +1 -1
  73. package/dist/state/StateStore.js +21 -15
  74. package/dist/state/StateStore.js.map +1 -1
  75. package/dist/supervision/SafeRestartScheduler.js +5 -0
  76. package/dist/supervision/SafeRestartScheduler.js.map +1 -1
  77. package/docs/technical-reference.md +27 -6
  78. package/docs/technical-reference.zh.md +27 -6
  79. package/npm-shrinkwrap.json +2 -2
  80. package/package.json +2 -1
  81. package/skills/agent-bot/SKILL.md +19 -9
  82. package/src/acp/AcpSessionManager.ts +73 -54
  83. package/src/cli/FeishuAppConfiguration.ts +130 -18
  84. package/src/cli/FeishuAppRegistration.ts +24 -9
  85. package/src/cli/Initializer.ts +25 -6
  86. package/src/cli/LocalControlClient.ts +9 -2
  87. package/src/cli/LocalControlServer.ts +2 -1
  88. package/src/cli/OptionalAuthorizationSkip.ts +51 -6
  89. package/src/cli/ServerStarter.ts +20 -3
  90. package/src/cli/SkillRegistry.ts +17 -4
  91. package/src/cli/VerificationOutput.ts +4 -1
  92. package/src/cli/help.ts +50 -1
  93. package/src/cli/i18n.ts +38 -0
  94. package/src/cli/initOptions.ts +17 -4
  95. package/src/cli/packageVersion.ts +5 -1
  96. package/src/cli/profile.ts +13 -3
  97. package/src/cli/serverStatus.ts +19 -14
  98. package/src/cli/taskChatRoute.ts +9 -2
  99. package/src/cli.ts +290 -103
  100. package/src/codex/AppServerConnection.ts +21 -1
  101. package/src/codex/CodexLocalActivityDetector.ts +8 -1
  102. package/src/codex/CodexProcessManager.ts +1 -0
  103. package/src/codex/CodexRuntime.ts +91 -2
  104. package/src/commands/CommandRouter.ts +123 -46
  105. package/src/commands/commandTypes.ts +6 -11
  106. package/src/console/ConsoleTurnPresenter.ts +1 -1
  107. package/src/feishu/CardRenderer.ts +418 -11
  108. package/src/feishu/FeishuMessageClient.ts +66 -3
  109. package/src/feishu/FeishuTurnPresenter.ts +7 -2
  110. package/src/index.ts +21 -22
  111. package/src/proxy/ProxySessionController.ts +712 -208
  112. package/src/runtime/AcpRuntimeAdapter.ts +1 -0
  113. package/src/runtime/AgentRuntimeRegistry.ts +7 -6
  114. package/src/runtime/createAgentRuntimeRegistry.ts +25 -0
  115. package/src/runtime/types.ts +18 -0
  116. package/src/startup/SessionMetadataHydrator.ts +2 -2
  117. package/src/startup/StartupNotifier.ts +1 -0
  118. package/src/state/StateStore.ts +29 -15
  119. package/src/supervision/SafeRestartScheduler.ts +5 -0
package/CHANGELOG.md CHANGED
@@ -6,6 +6,29 @@ The project follows [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.1.11] - 2026-08-02
10
+
11
+ - Retry Feishu messages, replies, and card updates rejected by email-address content auditing with audit-safe text; keep message reactions pending until terminal presentation succeeds while allowing session and queue state to settle after presentation failures.
12
+ - Use a shorter image-only prompt that asks the active Agent to inspect the attached image.
13
+ - Reduce the packaged project logo size without changing the documented asset path.
14
+ - Keep `/new` and `/newgroup` project options aligned: both support `--dir <cwd>` with `~`-based home-directory paths and `--nodir` for a forced Projectless Codex task, while `/newgroup` continues to inherit execution settings from the source task.
15
+ - Send `excludeTurns: true` by default for every Codex fork, reducing response size without removing branch history, and retry once without the experimental field when an older App Server explicitly rejects it.
16
+ - Remove obsolete `/mode`, `/modes`, `/ask`, `/agents`, and `/use` commands, consolidating Agent selection under `/agent`.
17
+ - Omit the `[Projectless]` segment from `/newgroup` and `/forkgroup` group names while preserving Projectless task behavior.
18
+ - Add a unified execution-settings card with Provider, Model, Thinking, and Permission tabs plus an Agent tab when multiple agents are configured; route multi-option Agent and Provider selection through the same card, report their current value directly when no alternative exists, persist and inherit Provider across task lifecycle operations, and leave new tasks on the Codex-configured default Provider.
19
+ - Make Feishu `/restart` schedule a safe restart by default, with `/restart --force` as the only immediate-restart form.
20
+ - Preserve Windows separators before dot-prefixed directories in Feishu file-change summaries instead of letting Markdown consume the separator as an escape.
21
+ - Isolate every configured Agent by standard name with its own process and runtime connection, aggregate Codex tasks across those isolated runtimes, and scope persisted remote task identities by Agent.
22
+ - Add the Agent Bot logo to both READMEs and include the high-resolution PNG in the npm package.
23
+
24
+ ## [0.1.10] - 2026-08-01
25
+
26
+ - Open a filtered Feishu Developer Console permission page for manual `im:message.group_msg` setup instead of incorrectly including the unsupported scope in one-click configuration; allow `Y` to skip its wait and report the resulting mention-only group behavior.
27
+ - Localize Agent Bot CLI help, status, progress, prompts, and CLI-owned errors for Chinese and English system locales, with English fallback for every unsupported locale and stable language-neutral JSON output.
28
+ - Support unambiguous slash-command prefixes and short aliases such as `/fg`, `/ng`, and `/ns`, with ambiguity guidance in `/help`.
29
+ - Show the inherited model, reasoning effort, and permission type in newly created `/forkgroup` groups.
30
+ - Accept unique slash-command prefixes and compound-command initialisms while rejecting ambiguous matches with a candidate list.
31
+
9
32
  ## [0.1.9] - 2026-08-01
10
33
 
11
34
  - Add `NewGroup` and `ForkGroup` actions to every task in the Lark `/sessions` card, using the selected task's project and latest completed turn.
package/README.md CHANGED
@@ -1,3 +1,7 @@
1
+ <p align="center">
2
+ <img src="assets/agent-bot-logo.png" alt="Agent Bot logo" width="180">
3
+ </p>
4
+
1
5
  # Agent Bot
2
6
 
3
7
  Use local Codex and ACP agents directly from Feishu.
@@ -37,7 +41,7 @@ agent-bot --version
37
41
  agent-bot --help
38
42
  ```
39
43
 
40
- This installs the `agent-bot` command globally. Command-line help, status, progress, and errors are always displayed in English. See the [technical reference](docs/technical-reference.md#development-and-source-installation) to install from source.
44
+ This installs the `agent-bot` command globally. Command-line help, status, progress, prompts, and errors follow the system language for Chinese and English locales; all other locales fall back to English. JSON output remains language-neutral and stable. See the [technical reference](docs/technical-reference.md#development-and-source-installation) to install from source.
41
45
 
42
46
  ### Initialize
43
47
 
@@ -49,6 +53,8 @@ Follow the displayed link or scan the QR code to create and authorize the Feishu
49
53
 
50
54
  Only a complete app ID and secret saved locally count as a successful bot creation. If initialization is interrupted before both credentials are saved, rerunning `agent-bot init` creates a new bot. If credentials were saved, initialization resumes by auditing that bot's remote permissions and subscriptions.
51
55
 
56
+ The `im:message.group_msg` permission cannot be added through Feishu's one-click configuration. When it is missing, Agent Bot prints a QR code and a direct Developer Console link already filtered to that permission. Add it manually, publish the app version, and complete tenant approval if required. While Agent Bot waits for it to become active, enter `Y` to skip this permission and continue initialization; the final result warns that ordinary group messages which do not mention the bot will be unavailable.
57
+
52
58
  When optional permissions or subscriptions are missing, Agent Bot first shows their QR code and authorization link, then immediately waits up to five minutes for them to become active. The terminal offers only one choice: enter `Y` to skip optional authorization and continue. Otherwise, complete authorization in the browser while Agent Bot waits. Optional authorization failures or timeouts do not block startup, and Agent Bot reports which features may be unavailable.
53
59
 
54
60
  | Option | Purpose |
@@ -158,26 +164,32 @@ Plain text continues the current task. Messages beginning with `/` are commands.
158
164
  | `/queue <prompt>` | Queue a separate follow-up Prompt |
159
165
  | `/nosteer <prompt>` | Same as `/queue` |
160
166
  | `/goal [objective]` | View or manage a persistent Goal |
161
- | `/model [name]` | View or change the model |
162
- | `/thinking [level]` | View or change reasoning effort |
163
- | `/permissions auto\|confirm` | Change tool approval behavior |
164
- | `/newgroup [title]` | Create a private group for a new task |
167
+ | `/provider` | Open execution settings on the Provider tab |
168
+ | `/model` | Open execution settings on the Model tab |
169
+ | `/thinking` | Open execution settings on the Thinking tab |
170
+ | `/permissions` | Open execution settings on the Permission tab |
171
+ | `/newgroup [title] [--dir <cwd> \| --nodir]` | Create a private group for a new task |
165
172
  | `/forkgroup [title]` | Fork the current position into a private group |
166
- | `/agent [name]` | View or change the default agent |
167
- | `/use <agent> [cwd]` | Select an agent and create a task |
173
+ | `/agent [name]` | Open Agent settings or select the default Agent |
168
174
  | `! <command>` | Run a local command in the task directory |
169
- | `/restart` | Gracefully restart Agent Bot |
175
+ | `/restart [--force]` | Restart safely, or immediately with `--force` |
170
176
  | `/help` | Show in-chat help |
171
177
 
178
+ Slash commands accept any unique prefix, and compound commands accept registered initialisms: `/sess` runs `/sessions`, `/fg` runs `/forkgroup`, `/ng` runs `/newgroup`, and `/ns` runs `/nosteer`. Exact command names take priority. An ambiguous prefix such as `/s` or `/f` is rejected and reports every matching command.
179
+
180
+ `/agent`, `/provider`, `/model`, `/thinking`, and `/permissions` use the same execution-settings card when there is something to select. When more than one Agent is configured, the card adds an Agent tab for selecting the default Agent used by future tasks; `/agent` opens that tab, including when the chat has no current task. With only one configured Agent, `/agent` reports the current Agent directly instead. Existing tasks keep their original Agent, and tasks using different Agents run independently. `/agent <name>` remains available for direct selection. `/provider` likewise reports the current Provider directly when no alternative Provider is configured. The other four commands activate their matching tabs and do not accept arguments. A task created without inherited settings uses the default Provider from your Codex configuration.
181
+
172
182
  Private chats, group timelines, and threads keep separate current tasks. You can send an image by itself or together with text. While a task is running, plain text adds instructions to the current work; use `/queue` (or `/nosteer`) to always create a later turn.
173
183
 
174
184
  The `/sessions` card provides `NewGroup` and `ForkGroup` actions for each task, so you can create a project-matched group or fork a selected task directly into a new group.
175
185
 
176
186
  Inside a thread, `/forkgroup` forks from the thread's original turn until the thread task completes its own turn. After that, it forks from the thread task's latest completed turn. A currently running turn is never used as a fork point.
177
187
 
178
- `/newgroup` immediately creates a new task in the new group. It inherits the current task's project directory, model, reasoning effort, and permission mode without affecting the source task. If there is no current task, Agent Bot uses the selected agent and its runtime defaults. An explicit title becomes both the group suffix and the task title.
188
+ After `/forkgroup` creates the new group, its welcome message shows the forked task's current Provider, model, reasoning effort, and permission type.
189
+
190
+ `/new` and `/newgroup` accept the same project options. Pass `--dir <cwd>` to override the inherited project directory, or `--nodir` to force a Projectless Codex task; the two options are mutually exclusive. `~`, `~/...`, and `~\...` resolve from the current user's home directory for both commands. `/newgroup` immediately creates and binds the task in the new group while continuing to inherit the current task's Provider, model, reasoning effort, and permission mode without affecting the source task. If there is no current task, Agent Bot uses the selected agent and its runtime defaults. An explicit title becomes both the group suffix and the task title.
179
191
 
180
- When `/newgroup` omits the title, the task title is `新任务` and the default group name is `[agent] [project dir] 新任务 (mm-dd)`. When `/forkgroup` omits the title, its task and group name use the same persistent `source title(分支 N)` sequence as `/fork`, without a date suffix. Feishu group names created by `/newgroup` and `/forkgroup` are capped at 60 displayed characters. When a generated name is too long, Agent Bot truncates only the title portion in the group name; the task title itself stays unchanged.
192
+ When `/newgroup` omits the title, the task title is `新任务` and the default group name is `[agent] [project dir] 新任务 (mm-dd)`. Projectless groups omit the project segment entirely, using `[agent] title`. When `/forkgroup` omits the title, its task and group name use the same persistent `source title(分支 N)` sequence as `/fork`, without a date suffix. Feishu group names created by `/newgroup` and `/forkgroup` are capped at 60 displayed characters. When a generated name is too long, Agent Bot truncates only the title portion in the group name; the task title itself stays unchanged.
181
193
 
182
194
  Renaming a bound group to `[agent] [project dir] title` synchronizes only `title` to the current task. The Agent and project-directory prefixes remain group metadata and are never included in the Codex task title. The older `[agent] title` format remains supported.
183
195
 
package/README.zh.md CHANGED
@@ -1,3 +1,7 @@
1
+ <p align="center">
2
+ <img src="assets/agent-bot-logo.png" alt="Agent Bot Logo" width="180">
3
+ </p>
4
+
1
5
  # Agent Bot
2
6
 
3
7
  通过飞书使用本机上的 Codex 和 ACP Agent。
@@ -37,7 +41,7 @@ agent-bot --version
37
41
  agent-bot --help
38
42
  ```
39
43
 
40
- 该命令会全局安装 `agent-bot`。命令行帮助、状态、进度和错误统一使用英文。从源码安装的方法见[技术参考](docs/technical-reference.zh.md#开发与源码安装)。
44
+ 该命令会全局安装 `agent-bot`。命令行帮助、状态、进度、交互提示和错误会根据系统语言显示中文或英文;其他未支持语言统一回退英文。JSON 输出不做本地化并保持字段稳定。从源码安装的方法见[技术参考](docs/technical-reference.zh.md#开发与源码安装)。
41
45
 
42
46
  ### 初始化
43
47
 
@@ -49,6 +53,8 @@ agent-bot init
49
53
 
50
54
  只有 App ID 和 App Secret 都已保存到本地才视为机器人创建成功。如果初始化在完整凭据保存前中断,再次运行 `agent-bot init` 会创建新机器人;如果凭据已经保存,则会继续检查该机器人的远端权限和订阅。
51
55
 
56
+ `im:message.group_msg` 无法通过飞书一键配置新增。缺少该权限时,Agent Bot 会显示二维码,以及已筛选该权限的开发者后台直达链接。请手动新增权限、发布应用版本,并在需要时完成租户管理员审批。Agent Bot 等待权限生效时,可输入 `Y` 跳过该权限并继续初始化;最终结果会提示机器人无法响应未 @ 它的普通群消息。
57
+
52
58
  缺少非核心权限或订阅时,Agent Bot 会先显示二维码和授权链接,然后立即等待最多 5 分钟使配置生效。终端只提供一个选项:输入 `Y` 跳过可选授权并继续;否则直接在浏览器中完成授权,Agent Bot 会持续等待。可选授权失败或超时不会阻止启动,Agent Bot 会提示可能无法使用的功能。
53
59
 
54
60
  | 参数 | 作用 |
@@ -158,26 +164,32 @@ agent-bot task stop <任务>
158
164
  | `/queue <prompt>` | 排队一个独立的后续 Prompt |
159
165
  | `/nosteer <prompt>` | 与 `/queue` 相同 |
160
166
  | `/goal [目标]` | 查看或管理持久 Goal |
161
- | `/model [名称]` | 查看或切换模型 |
162
- | `/thinking [级别]` | 查看或切换思考强度 |
163
- | `/permissions auto\|confirm` | 修改工具授权方式 |
164
- | `/newgroup [标题]` | 为新任务创建私有群 |
167
+ | `/provider` | 打开运行设置的 Provider tab |
168
+ | `/model` | 打开运行设置的 Model tab |
169
+ | `/thinking` | 打开运行设置的 Thinking tab |
170
+ | `/permissions` | 打开运行设置的 Permission tab |
171
+ | `/newgroup [标题] [--dir <cwd> \| --nodir]` | 为新任务创建私有群 |
165
172
  | `/forkgroup [标题]` | 将当前位置分支到私有群 |
166
- | `/agent [名称]` | 查看或切换默认 Agent |
167
- | `/use <agent> [cwd]` | 选择 Agent 并创建任务 |
173
+ | `/agent [名称]` | 打开 Agent 设置或切换默认 Agent |
168
174
  | `! <命令>` | 在任务目录执行本地命令 |
169
- | `/restart` | 优雅重启 Agent Bot |
175
+ | `/restart [--force]` | 默认安全重启;`--force` 立即重启 |
170
176
  | `/help` | 显示聊天内帮助 |
171
177
 
178
+ 斜杠命令支持任意唯一前缀,复合命令还支持首字母缩写:`/sess` 等同于 `/sessions`,`/fg` 等同于 `/forkgroup`,`/ng` 等同于 `/newgroup`,`/ns` 等同于 `/nosteer`。完整命令名优先;`/s`、`/f` 等匹配多个命令的前缀会被拒绝,并列出全部候选命令。
179
+
180
+ `/agent`、`/provider`、`/model`、`/thinking` 和 `/permissions` 在存在可选项时使用同一张运行设置卡片。配置了多个 Agent 时,卡片会增加 Agent tab,用于选择后续新任务使用的默认 Agent;即使当前聊天还没有任务,`/agent` 也能打开该 tab。只配置一个 Agent 时,`/agent` 直接显示当前 Agent,不打开卡片。现有任务仍保持原来的 Agent,使用不同 Agent 的任务可以相互独立地运行。`/agent <名称>` 继续支持直接选择。没有可切换的 Provider 时,`/provider` 同样只显示当前 Provider。其余四个命令激活各自对应的 tab,且不接受参数。没有可继承设置的新任务使用 Codex 配置中的默认 Provider。
181
+
172
182
  私聊、群正文和话题分别维护当前任务。可以单独发送图片,也可以同时发送文字和图片。任务运行中发送普通文字会追加指令;需要确保形成后续 turn 时使用 `/queue`(或 `/nosteer`)。
173
183
 
174
184
  `/sessions` 卡片为每个任务提供 `NewGroup` 和 `ForkGroup` 操作,可直接按所选任务创建同项目的新群,或把所选任务 Fork 到新群。
175
185
 
176
186
  在话题中使用 `/forkgroup` 时,如果话题任务还没有完成过自己的 turn,则从话题原始 turn fork;完成过后则从话题任务最近完成的 turn fork。正在执行的 turn 不会作为 fork 点。
177
187
 
178
- `/newgroup` 会立即在新群中创建并绑定一个新任务。新任务继承当前任务的项目目录、模型、思考强度和权限模式,不影响来源任务;来源聊天没有当前任务时,则使用选定 Agent 及其运行时默认设置。显式标题会同时作为群名后缀和任务标题。
188
+ `/forkgroup` 创建新群后,群内欢迎消息会显示分支任务当前使用的 Provider、模型、思考强度和权限类型。
189
+
190
+ `/new` 和 `/newgroup` 支持相同的项目参数:使用 `--dir <cwd>` 覆盖继承的项目目录,或使用 `--nodir` 强制创建 Projectless Codex 任务,二者不能同时使用。两条命令中的 `~`、`~/...` 和 `~\...` 均表示当前用户目录。`/newgroup` 会立即在新群中创建并绑定任务,同时继续继承当前任务的 Provider、模型、思考强度和权限模式,不影响来源任务。来源聊天没有当前任务时,则使用选定 Agent 及其运行时默认设置。显式标题会同时作为群名后缀和任务标题。
179
191
 
180
- `/newgroup` 省略标题时,任务标题为 `新任务`,默认群名为 `[agent] [project dir] 新任务 (mm-dd)`。`/forkgroup` 省略标题时,任务标题和群名都与 `/fork` 一样使用持久递增的 `源标题(分支 N)`,不追加日期。`/newgroup` 和 `/forkgroup` 创建的飞书群名最多显示 60 个字符。生成后的群名过长时,Agent Bot 只截断群名中的标题部分,任务标题本身保持不变。
192
+ `/newgroup` 省略标题时,任务标题为 `新任务`,默认群名为 `[agent] [project dir] 新任务 (mm-dd)`。Projectless 群会完全省略项目段,群名格式为 `[agent] title`。`/forkgroup` 省略标题时,任务标题和群名都与 `/fork` 一样使用持久递增的 `源标题(分支 N)`,不追加日期。`/newgroup` 和 `/forkgroup` 创建的飞书群名最多显示 60 个字符。生成后的群名过长时,Agent Bot 只截断群名中的标题部分,任务标题本身保持不变。
181
193
 
182
194
  把已绑定任务的群改名为 `[agent] [project dir] title` 时,只会把 `title` 同步到当前任务;Agent 和工程目录前缀仅作为群元数据,不会写入 Codex 任务标题。旧的 `[agent] title` 格式仍然兼容。
183
195
 
Binary file
@@ -1,12 +1,15 @@
1
1
  import path from "node:path";
2
2
  export class AcpSessionManager {
3
- config;
3
+ agentName;
4
+ agent;
4
5
  processManager;
5
6
  logger;
6
7
  sessions = new Map();
7
8
  sessionsByAcpId = new Map();
8
- constructor(config, processManager, logger) {
9
- this.config = config;
9
+ processStart;
10
+ constructor(agentName, agent, processManager, logger) {
11
+ this.agentName = agentName;
12
+ this.agent = agent;
10
13
  this.processManager = processManager;
11
14
  this.logger = logger;
12
15
  }
@@ -14,55 +17,17 @@ export class AcpSessionManager {
14
17
  return this.sessions.get(localSessionId);
15
18
  }
16
19
  async create(input) {
17
- const agent = this.config.agents[input.agentName];
18
- if (!agent) {
19
- throw new Error(`Unknown agent: ${input.agentName}`);
20
- }
20
+ if (input.agentName !== this.agentName)
21
+ throw new Error(`Unexpected agent: ${input.agentName}`);
21
22
  const cwd = path.resolve(input.cwd);
22
- const processKey = input.localSessionId;
23
- const managed = this.processManager.start(processKey, input.agentName, agent);
23
+ const managed = await this.process();
24
24
  const connection = managed.connection;
25
- let runtime;
26
- connection.registerHandler("session/request_permission", async (params) => {
27
- if (!runtime) {
28
- throw new Error("Received permission request before session was ready.");
29
- }
30
- return input.onPermissionRequest(runtime, params);
31
- });
32
- connection.on("notification", (_method, params) => {
33
- if (_method !== "session/update") {
34
- return;
35
- }
36
- const updateParams = params;
37
- const target = this.sessionsByAcpId.get(updateParams.sessionId);
38
- if (!target) {
39
- this.logger.debug({ updateParams }, "Ignoring update for unknown ACP session.");
40
- return;
41
- }
42
- this.applySessionUpdate(target, updateParams.update);
43
- input.onUpdate(target, updateParams.update);
44
- });
45
- const initializeResult = await connection.request("initialize", {
46
- protocolVersion: 1,
47
- clientCapabilities: {},
48
- clientInfo: {
49
- name: "agent-bot",
50
- title: "Agent Bot",
51
- version: "0.1.0",
52
- },
53
- });
54
- if (initializeResult.authMethods?.length) {
55
- const method = initializeResult.authMethods[0];
56
- this.logger.info({ methodId: method.id }, "Authenticating ACP agent with first advertised method.");
57
- await connection.request("authenticate", { methodId: method.id });
58
- }
59
25
  const newSessionResult = await connection.request("session/new", {
60
26
  cwd,
61
27
  mcpServers: [],
62
28
  });
63
- runtime = {
29
+ const runtime = {
64
30
  localSessionId: input.localSessionId,
65
- processKey,
66
31
  agentName: input.agentName,
67
32
  cwd,
68
33
  acpSessionId: newSessionResult.sessionId,
@@ -70,6 +35,8 @@ export class AcpSessionManager {
70
35
  running: false,
71
36
  modes: newSessionResult.modes,
72
37
  configOptions: newSessionResult.configOptions,
38
+ onUpdate: input.onUpdate,
39
+ onPermissionRequest: input.onPermissionRequest,
73
40
  };
74
41
  this.sessions.set(input.localSessionId, runtime);
75
42
  this.sessionsByAcpId.set(runtime.acpSessionId, runtime);
@@ -114,7 +81,12 @@ export class AcpSessionManager {
114
81
  }
115
82
  this.sessions.delete(localSessionId);
116
83
  this.sessionsByAcpId.delete(session.acpSessionId);
117
- this.processManager.stop(session.processKey);
84
+ }
85
+ shutdown() {
86
+ this.sessions.clear();
87
+ this.sessionsByAcpId.clear();
88
+ this.processStart = undefined;
89
+ this.processManager.stopAll();
118
90
  }
119
91
  async setMode(localSessionId, modeId) {
120
92
  const session = this.requireSession(localSessionId);
@@ -142,6 +114,66 @@ export class AcpSessionManager {
142
114
  }
143
115
  return session;
144
116
  }
117
+ async process() {
118
+ const existing = this.processManager.get(this.agentName);
119
+ if (existing)
120
+ return existing;
121
+ if (this.processStart)
122
+ return this.processStart;
123
+ const start = this.startProcess();
124
+ this.processStart = start;
125
+ try {
126
+ return await start;
127
+ }
128
+ finally {
129
+ if (this.processStart === start)
130
+ this.processStart = undefined;
131
+ }
132
+ }
133
+ async startProcess() {
134
+ const managed = this.processManager.start(this.agentName, this.agentName, this.agent);
135
+ try {
136
+ const connection = managed.connection;
137
+ connection.registerHandler("session/request_permission", async (params) => {
138
+ const permission = params;
139
+ const target = this.sessionsByAcpId.get(permission.sessionId);
140
+ if (!target)
141
+ throw new Error(`Unknown ACP session requesting permission: ${permission.sessionId}`);
142
+ return target.onPermissionRequest(target, permission);
143
+ });
144
+ connection.on("notification", (method, params) => {
145
+ if (method !== "session/update")
146
+ return;
147
+ const updateParams = params;
148
+ const target = this.sessionsByAcpId.get(updateParams.sessionId);
149
+ if (!target) {
150
+ this.logger.debug({ updateParams }, "Ignoring update for unknown ACP session.");
151
+ return;
152
+ }
153
+ this.applySessionUpdate(target, updateParams.update);
154
+ target.onUpdate(target, updateParams.update);
155
+ });
156
+ const initializeResult = await connection.request("initialize", {
157
+ protocolVersion: 1,
158
+ clientCapabilities: {},
159
+ clientInfo: {
160
+ name: "agent-bot",
161
+ title: "Agent Bot",
162
+ version: "0.1.0",
163
+ },
164
+ });
165
+ if (initializeResult.authMethods?.length) {
166
+ const method = initializeResult.authMethods[0];
167
+ this.logger.info({ methodId: method.id }, "Authenticating ACP agent with first advertised method.");
168
+ await connection.request("authenticate", { methodId: method.id });
169
+ }
170
+ return managed;
171
+ }
172
+ catch (error) {
173
+ this.processManager.stop(this.agentName);
174
+ throw error;
175
+ }
176
+ }
145
177
  applySessionUpdate(session, update) {
146
178
  const updateType = update.sessionUpdate;
147
179
  if (updateType === "config_option_update" && "configOptions" in update) {
@@ -1 +1 @@
1
- {"version":3,"file":"AcpSessionManager.js","sourceRoot":"","sources":["../../src/acp/AcpSessionManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AcpSessionManager.js","sourceRoot":"","sources":["../../src/acp/AcpSessionManager.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { gzipSync } from "node:zlib";
2
+ import { cliText } from "./i18n.js";
2
3
  const FEISHU_OPEN_BASE_URL = "https://open.feishu.cn";
3
4
  const TENANT_TOKEN_PATH = "/open-apis/auth/v3/tenant_access_token/internal";
4
5
  const APPLICATION_PATH_PREFIX = "/open-apis/application/v6/applications";
@@ -61,6 +62,7 @@ const CORE_FEISHU_SCOPES = new Set([
61
62
  "im:message:send_as_bot",
62
63
  ]);
63
64
  const CORE_FEISHU_EVENTS = new Set(["im.message.receive_v1"]);
65
+ const MANUAL_FEISHU_SCOPES = new Set(["im:message.group_msg"]);
64
66
  export async function ensureFeishuAppConfiguration(credentials, options = {}) {
65
67
  const fetchImpl = options.fetch ?? globalThis.fetch;
66
68
  const sleep = options.sleep ?? delay;
@@ -93,38 +95,72 @@ export async function ensureFeishuAppConfiguration(credentials, options = {}) {
93
95
  await requestMissingFeishuConfiguration(credentials.appId, coreMissing, true, options.onVerification);
94
96
  let remainingMs = timeoutMs;
95
97
  let lastError;
98
+ let refreshImmediately = options.manualPermissionSkipSignal?.aborted === true;
96
99
  while (remainingMs > 0) {
97
100
  const waitMs = Math.min(pollIntervalMs, remainingMs);
98
- await sleepWithAbort(sleep, waitMs, options.signal);
99
- remainingMs -= waitMs;
101
+ if (!refreshImmediately) {
102
+ const waitResult = options.manualPermissionSkipSignal?.aborted
103
+ ? await sleepWithAbort(sleep, waitMs, options.signal).then(() => "elapsed")
104
+ : await sleepWithOptionalSkip(sleep, waitMs, options.signal, options.manualPermissionSkipSignal);
105
+ if (waitResult === "elapsed")
106
+ remainingMs -= waitMs;
107
+ }
108
+ refreshImmediately = false;
100
109
  try {
101
110
  configuration = await readFeishuAppConfiguration(credentials, fetchImpl, options.signal);
102
111
  const remaining = missingFeishuAppConfiguration(configuration);
103
- if (!hasMissingConfiguration(coreMissingFeishuAppConfiguration(remaining))) {
104
- return completeOptionalFeishuConfiguration(credentials, configuration, missing, fetchImpl, sleep, pollIntervalMs, optionalTimeoutMs, options);
112
+ const unresolvedCore = coreMissingFeishuAppConfiguration(remaining);
113
+ if (!hasBlockingCoreConfiguration(unresolvedCore, options.manualPermissionSkipSignal)) {
114
+ return completeOptionalFeishuConfiguration(credentials, configuration, missing, fetchImpl, sleep, pollIntervalMs, optionalTimeoutMs, options, skippedManualScopes(coreMissing, options.manualPermissionSkipSignal));
105
115
  }
106
116
  lastError = undefined;
107
117
  }
108
118
  catch (error) {
109
119
  if (options.signal?.aborted)
110
120
  throw abortError(options.signal);
121
+ const knownRemaining = missingFeishuAppConfiguration(configuration);
122
+ if (!hasBlockingCoreConfiguration(coreMissingFeishuAppConfiguration(knownRemaining), options.manualPermissionSkipSignal)) {
123
+ return completeOptionalFeishuConfiguration(credentials, configuration, missing, fetchImpl, sleep, pollIntervalMs, optionalTimeoutMs, options, skippedManualScopes(coreMissing, options.manualPermissionSkipSignal));
124
+ }
111
125
  lastError = error;
112
126
  }
113
127
  }
114
- const detail = lastError instanceof Error ? ` Last check failed: ${lastError.message}` : "";
115
- throw new Error(`Timed out waiting for the core Lark scopes and message event. Run agent-bot init again.${detail}`);
128
+ const detail = lastError instanceof Error
129
+ ? cliText(` Last check failed: ${lastError.message}`, ` 上次检查失败:${lastError.message}`)
130
+ : "";
131
+ throw new Error(cliText(`Timed out waiting for the core Lark scopes and message event. Run agent-bot init again.${detail}`, `等待飞书核心权限和消息事件超时。请重新运行 agent-bot init。${detail}`));
116
132
  }
117
133
  async function requestMissingFeishuConfiguration(appId, missing, blocking, onVerification) {
118
- const verificationUrl = buildFeishuConfigurationUrl(appId, missing);
119
- await onVerification?.({ verificationUrl, missing, blocking });
134
+ const launcherMissing = {
135
+ scopes: missing.scopes.filter((scope) => !MANUAL_FEISHU_SCOPES.has(scope)),
136
+ events: missing.events,
137
+ callbacks: missing.callbacks,
138
+ };
139
+ if (hasMissingConfiguration(launcherMissing)) {
140
+ await onVerification?.({
141
+ kind: "launcher",
142
+ verificationUrl: buildFeishuConfigurationUrl(appId, launcherMissing),
143
+ missing: launcherMissing,
144
+ blocking,
145
+ });
146
+ }
147
+ for (const scope of missing.scopes.filter((value) => MANUAL_FEISHU_SCOPES.has(value))) {
148
+ await onVerification?.({
149
+ kind: "manual_scope",
150
+ verificationUrl: buildFeishuPermissionManagementUrl(appId, scope),
151
+ missing: { scopes: [scope], events: [], callbacks: [] },
152
+ blocking,
153
+ });
154
+ }
120
155
  }
121
- async function completeOptionalFeishuConfiguration(credentials, initialConfiguration, initialMissing, fetchImpl, sleep, pollIntervalMs, timeoutMs, options) {
156
+ async function completeOptionalFeishuConfiguration(credentials, initialConfiguration, initialMissing, fetchImpl, sleep, pollIntervalMs, timeoutMs, options, ignoredScopes = new Set()) {
122
157
  let configuration = initialConfiguration;
123
158
  let remaining = missingFeishuAppConfiguration(configuration);
124
- if (hasMissingConfiguration(remaining)) {
125
- await requestMissingFeishuConfiguration(credentials.appId, remaining, false, options.onVerification);
159
+ const requested = withoutIgnoredScopes(remaining, ignoredScopes);
160
+ if (hasMissingConfiguration(requested)) {
161
+ await requestMissingFeishuConfiguration(credentials.appId, requested, false, options.onVerification);
126
162
  if (!options.optionalSkipSignal?.aborted) {
127
- const completed = await waitForOptionalFeishuConfiguration(credentials, configuration, fetchImpl, sleep, pollIntervalMs, timeoutMs, options.signal, options.optionalSkipSignal);
163
+ const completed = await waitForOptionalFeishuConfiguration(credentials, configuration, fetchImpl, sleep, pollIntervalMs, timeoutMs, options.signal, options.optionalSkipSignal, ignoredScopes);
128
164
  configuration = completed.configuration;
129
165
  remaining = completed.remaining;
130
166
  }
@@ -136,11 +172,11 @@ async function completeOptionalFeishuConfiguration(credentials, initialConfigura
136
172
  remaining,
137
173
  };
138
174
  }
139
- async function waitForOptionalFeishuConfiguration(credentials, initialConfiguration, fetchImpl, sleep, pollIntervalMs, timeoutMs, signal, optionalSkipSignal) {
175
+ async function waitForOptionalFeishuConfiguration(credentials, initialConfiguration, fetchImpl, sleep, pollIntervalMs, timeoutMs, signal, optionalSkipSignal, ignoredScopes = new Set()) {
140
176
  let configuration = initialConfiguration;
141
177
  let remaining = missingFeishuAppConfiguration(configuration);
142
178
  let remainingMs = timeoutMs;
143
- while (remainingMs > 0 && hasMissingConfiguration(remaining)) {
179
+ while (remainingMs > 0 && hasMissingConfiguration(withoutIgnoredScopes(remaining, ignoredScopes))) {
144
180
  if (optionalSkipSignal?.aborted)
145
181
  break;
146
182
  const waitMs = Math.min(pollIntervalMs, remainingMs);
@@ -219,13 +255,20 @@ export function buildFeishuConfigurationUrl(appId, missing) {
219
255
  url.searchParams.set("addons", encoded);
220
256
  return url.toString();
221
257
  }
258
+ export function buildFeishuPermissionManagementUrl(appId, scope) {
259
+ const url = new URL(`/app/${encodeURIComponent(appId)}/auth`, FEISHU_OPEN_BASE_URL);
260
+ url.searchParams.set("q", scope);
261
+ url.searchParams.set("op_from", "openapi");
262
+ url.searchParams.set("token_type", "tenant");
263
+ return url.toString();
264
+ }
222
265
  async function readFeishuAppConfiguration(credentials, fetchImpl, signal) {
223
266
  const token = await getTenantAccessToken(credentials, fetchImpl, signal);
224
267
  const appId = encodeURIComponent(credentials.appId);
225
268
  const headers = { Authorization: `Bearer ${token}` };
226
269
  const [application, versions] = await Promise.all([
227
- fetchJson(fetchImpl, `${FEISHU_OPEN_BASE_URL}${APPLICATION_PATH_PREFIX}/${appId}?lang=zh_cn`, { headers }, signal, "Read Lark app configuration"),
228
- fetchJson(fetchImpl, `${FEISHU_OPEN_BASE_URL}${APPLICATION_PATH_PREFIX}/${appId}/app_versions?lang=zh_cn&page_size=2`, { headers }, signal, "Read Lark app versions"),
270
+ fetchJson(fetchImpl, `${FEISHU_OPEN_BASE_URL}${APPLICATION_PATH_PREFIX}/${appId}?lang=zh_cn`, { headers }, signal, cliText("Read Lark app configuration", "读取飞书应用配置")),
271
+ fetchJson(fetchImpl, `${FEISHU_OPEN_BASE_URL}${APPLICATION_PATH_PREFIX}/${appId}/app_versions?lang=zh_cn&page_size=2`, { headers }, signal, cliText("Read Lark app versions", "读取飞书应用版本")),
229
272
  ]);
230
273
  const app = readObject(readObject(application, "data"), "app");
231
274
  const callbackInfo = readObject(app, "callback_info");
@@ -260,10 +303,10 @@ async function getTenantAccessToken(credentials, fetchImpl, signal) {
260
303
  app_id: credentials.appId,
261
304
  app_secret: credentials.appSecret,
262
305
  }),
263
- }, signal, "Get the Lark tenant_access_token");
306
+ }, signal, cliText("Get the Lark tenant_access_token", "获取飞书 tenant_access_token"));
264
307
  const token = readString(payload, "tenant_access_token");
265
308
  if (!token)
266
- throw new Error("The Lark tenant_access_token response is missing the access token.");
309
+ throw new Error(cliText("The Lark tenant_access_token response is missing the access token.", "飞书 tenant_access_token 响应中缺少访问令牌。"));
267
310
  return token;
268
311
  }
269
312
  async function fetchJson(fetchImpl, url, init, parentSignal, operation) {
@@ -277,11 +320,11 @@ async function fetchJson(fetchImpl, url, init, parentSignal, operation) {
277
320
  const response = await fetchImpl(url, { ...init, signal: controller.signal });
278
321
  const payload = (await response.json().catch(() => undefined));
279
322
  if (!isJsonObject(payload)) {
280
- throw new Error(`${operation} returned an invalid response (HTTP ${response.status}).`);
323
+ throw new Error(cliText(`${operation} returned an invalid response (HTTP ${response.status}).`, `${operation}返回了无效响应(HTTP ${response.status})。`));
281
324
  }
282
325
  const code = readNumber(payload, "code");
283
326
  if (!response.ok || code !== 0) {
284
- throw new FeishuConfigurationApiError(`${operation} failed: ${readString(payload, "msg") || response.statusText || `HTTP ${response.status}`}`, code, response.status);
327
+ throw new FeishuConfigurationApiError(cliText(`${operation} failed: ${readString(payload, "msg") || response.statusText || `HTTP ${response.status}`}`, `${operation}失败:${readString(payload, "msg") || response.statusText || `HTTP ${response.status}`}`), code, response.status);
285
328
  }
286
329
  return payload;
287
330
  }
@@ -289,7 +332,7 @@ async function fetchJson(fetchImpl, url, init, parentSignal, operation) {
289
332
  if (parentSignal?.aborted)
290
333
  throw abortError(parentSignal);
291
334
  if (controller.signal.aborted)
292
- throw new Error(`${operation} timed out.`);
335
+ throw new Error(cliText(`${operation} timed out.`, `${operation}超时。`));
293
336
  throw error;
294
337
  }
295
338
  finally {
@@ -316,6 +359,23 @@ function isPermissionError(error) {
316
359
  function hasMissingConfiguration(missing) {
317
360
  return missing.scopes.length > 0 || missing.events.length > 0 || missing.callbacks.length > 0;
318
361
  }
362
+ function hasBlockingCoreConfiguration(missing, manualPermissionSkipSignal) {
363
+ if (!manualPermissionSkipSignal?.aborted)
364
+ return hasMissingConfiguration(missing);
365
+ return hasMissingConfiguration(withoutIgnoredScopes(missing, MANUAL_FEISHU_SCOPES));
366
+ }
367
+ function skippedManualScopes(initialCoreMissing, manualPermissionSkipSignal) {
368
+ if (!manualPermissionSkipSignal?.aborted)
369
+ return new Set();
370
+ return new Set(initialCoreMissing.scopes.filter((scope) => MANUAL_FEISHU_SCOPES.has(scope)));
371
+ }
372
+ function withoutIgnoredScopes(missing, ignoredScopes) {
373
+ return {
374
+ scopes: missing.scopes.filter((scope) => !ignoredScopes.has(scope)),
375
+ events: missing.events,
376
+ callbacks: missing.callbacks,
377
+ };
378
+ }
319
379
  function coreMissingFeishuAppConfiguration(missing) {
320
380
  return {
321
381
  scopes: missing.scopes.filter((scope) => CORE_FEISHU_SCOPES.has(scope)),
@@ -371,7 +431,9 @@ function positiveInteger(value) {
371
431
  return Number.isInteger(value) && value !== undefined && value > 0 ? value : undefined;
372
432
  }
373
433
  function abortError(signal) {
374
- return signal.reason instanceof Error ? signal.reason : new Error("Lark app configuration was cancelled.");
434
+ return signal.reason instanceof Error
435
+ ? signal.reason
436
+ : new Error(cliText("Lark app configuration was cancelled.", "飞书应用配置已取消。"));
375
437
  }
376
438
  function delay(milliseconds) {
377
439
  return new Promise((resolve) => setTimeout(resolve, milliseconds));