@keyou007/agent-bot 0.1.15-alpha.5 → 0.1.15-alpha.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.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,11 @@ The project follows [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.1.15-alpha.6] - 2026-08-20
10
+
11
+ - Allow separate configurable Project and Projectless Lark group-name templates with OS, Agent, project, task-title, and local date placeholders while preserving legacy defaults and task-title synchronization.
12
+ - Point the AgentBot signature on final Lark replies to the public project website.
13
+
9
14
  ## [0.1.15-alpha.5] - 2026-08-19
10
15
 
11
16
  - Wrap compound shell commands across readable lines with explicit `\` continuation markers in expanded Feishu thinking-card tool details.
package/README.md CHANGED
@@ -214,7 +214,7 @@ agentbot task dismiss [task] --yes
214
214
 
215
215
  Inside an Agent started by Agent Bot, `[task]` defaults to the current task; use `--task <task>` to target another task explicitly. A regular terminal must supply a task. `task current` shows the automatically detected task details. A task reference can be a number from `task list`, a task ID, or an unambiguous task-ID prefix. Every Feishu task, fork, queue, Agent, Provider, model, thinking, permission, Goal, historical Turn, Reset, group mute, group dismissal, directory, file, shell, and restart operation has a CLI counterpart. Run `agentbot --help` for the complete list and options.
216
216
 
217
- `task newgroup` creates a Feishu group and a new task. By default, it inherits the source task's Agent and execution settings. `--agent <standard-name>` selects another configured Agent; the source project shape is still inherited, while Provider, model, reasoning effort, and permission mode use the target Agent's own Runtime defaults. `--dir` overrides the project directory and supports `~`; `--nodir` forces a Projectless App Server task. Generated group names show at most the final two levels of the Project directory. `task forkgroup` forks from the source task's latest available completed turn without interrupting an active turn. Both commands require the Server to be running, invite the authorizing user saved in the Profile, leave the source conversation on its current task, and support `--json`.
217
+ `task newgroup` creates a Feishu group and a new task. By default, it inherits the source task's Agent and execution settings. `--agent <standard-name>` selects another configured Agent; the source project shape is still inherited, while Provider, model, reasoning effort, and permission mode use the target Agent's own Runtime defaults. `--dir` overrides the project directory and supports `~`; `--nodir` forces a Projectless App Server task. Project and Projectless group names can be customized separately through `feishu.groupNameFormat`. `task forkgroup` forks from the source task's latest available completed turn without interrupting an active turn. Both commands require the Server to be running, invite the authorizing user saved in the Profile, leave the source conversation on its current task, and support `--json`.
218
218
 
219
219
  ## Feishu Commands
220
220
 
@@ -278,6 +278,8 @@ Agent Bot keeps user-owned files outside the repository:
278
278
 
279
279
  Set `AGENT_BOT_HOME` to use another user-data directory. See [config.example.yaml](config.example.yaml) for configuration examples.
280
280
 
281
+ `feishu.groupNameFormat` defines separate name templates for new Project and Projectless groups, with variables for the operating system, Agent, project, task name, and date. See the [technical reference](docs/technical-reference.md#configuration-model) for the complete format.
282
+
281
283
  Agent processes inherit ordinary parent-process variables and their explicit `agents.<name>.env` settings. Before starting an Agent, Agent Bot removes inherited `FEISHU_*` credentials and internal `AGENT_BOT_*` state, then provides only namespaced, non-secret Profile and Lark identity context. `FEISHU_APP_SECRET` is never forwarded to an Agent process.
282
284
 
283
285
  By default, `feishu.respondToOwnerOnly: true` accepts only messages and card actions from the bot owner identified by `feishu.userOpenId`; other users are ignored before any processing reaction is added. Set it to `false` to allow collaborators. When enabled without an owner Open ID, all Feishu user input is ignored until the owner is configured.
package/README.zh.md CHANGED
@@ -214,7 +214,7 @@ agentbot task dismiss [任务] --yes
214
214
 
215
215
  在 Agent Bot 启动的 Agent 中,省略 `[任务]` 会自动使用当前任务;需要操作其他任务时可传入 `--task <任务>`。普通终端仍必须指定任务。`task current` 用于查看自动识别出的任务详情。任务引用可以是 `task list` 中的序号、任务 ID 或唯一的任务 ID 前缀。飞书中的任务、分支、排队、Agent、Provider、模型、思考强度、权限、Goal、历史 Turn、Reset、群静音、解散群、目录、文件、Shell 和重启能力都有对应的 CLI 命令;运行 `agentbot --help` 查看完整列表和参数。
216
216
 
217
- `task newgroup` 会创建飞书群和新任务。默认继承源任务的 Agent 和运行设置;`--agent <标准名>` 可选择另一个已配置的 Agent,此时仍继承源任务的项目形态,但 Provider、模型、思考强度和权限模式使用目标 Agent 自己的 Runtime 默认值。`--dir` 可覆盖项目目录并支持 `~`,`--nodir` 会强制创建 Projectless App Server 任务。自动生成的群名最多显示 Project 目录末尾两级。`task forkgroup` 从源任务最新可用的已完成 turn 创建分支,不会中断正在执行的 turn。两个命令都要求 Server 正在运行,邀请 Profile 中保存的授权用户,不会切换源会话的当前任务,并支持 `--json`。
217
+ `task newgroup` 会创建飞书群和新任务。默认继承源任务的 Agent 和运行设置;`--agent <标准名>` 可选择另一个已配置的 Agent,此时仍继承源任务的项目形态,但 Provider、模型、思考强度和权限模式使用目标 Agent 自己的 Runtime 默认值。`--dir` 可覆盖项目目录并支持 `~`,`--nodir` 会强制创建 Projectless App Server 任务。Project 与 Projectless 群名可在 `feishu.groupNameFormat` 中分别自定义。`task forkgroup` 从源任务最新可用的已完成 turn 创建分支,不会中断正在执行的 turn。两个命令都要求 Server 正在运行,邀请 Profile 中保存的授权用户,不会切换源会话的当前任务,并支持 `--json`。
218
218
 
219
219
  ## 飞书命令
220
220
 
@@ -278,6 +278,8 @@ Agent Bot 将用户相关文件保存在仓库之外:
278
278
 
279
279
  可通过 `AGENT_BOT_HOME` 修改用户数据目录。配置示例见 [config.example.yaml](config.example.yaml)。
280
280
 
281
+ `feishu.groupNameFormat` 可分别设置 Project 与 Projectless 新群的名称模板,支持系统、Agent、项目、任务名和日期变量。完整格式说明见[技术参考](docs/technical-reference.zh.md#配置模型)。
282
+
281
283
  Agent 进程会继承普通父进程变量及其显式配置的 `agents.<name>.env`。启动 Agent 前,Agent Bot 会移除继承的 `FEISHU_*` 凭据和内部 `AGENT_BOT_*` 状态,再仅提供带命名空间的非敏感 Profile 与 Lark 身份上下文;`FEISHU_APP_SECRET` 永远不会传入 Agent 进程。
282
284
 
283
285
  默认配置 `feishu.respondToOwnerOnly: true` 只接受 `feishu.userOpenId` 所标识的机器人拥有者发送的消息和卡片操作;其他用户会在添加处理 reaction 之前被忽略。设为 `false` 可允许其他协作者使用。开启后若未配置拥有者 Open ID,Agent Bot 会忽略所有飞书用户输入,直到完成拥有者配置。
@@ -6,6 +6,12 @@ feishu:
6
6
  respondToOwnerOnly: true
7
7
  # Fresh init and init --reset ask whether group messages require an @ mention.
8
8
  respondToAllGroupMessages: true
9
+ # New-group templates. Supported placeholders: os, agent, project, taskname, date.
10
+ # Use {date:yyyy-MM-dd} to override dateFormat for one date placeholder.
11
+ groupNameFormat:
12
+ project: "[{agent}] [{project}] {taskname}"
13
+ projectless: "[{agent}] {taskname}"
14
+ dateFormat: "MM-dd"
9
15
  # Use "timeline" to temporarily restore the original thinking-card layout.
10
16
  thinkingCardLayout: "grouped"
11
17
 
@@ -11,6 +11,10 @@ const DEFAULT_CONFIG = `feishu:
11
11
  userOpenId: "\${FEISHU_USER_OPEN_ID}"
12
12
  respondToOwnerOnly: true
13
13
  respondToAllGroupMessages: true
14
+ groupNameFormat:
15
+ project: "[{agent}] [{project}] {taskname}"
16
+ projectless: "[{agent}] {taskname}"
17
+ dateFormat: "MM-dd"
14
18
  thinkingCardLayout: "grouped"
15
19
 
16
20
  console:
@@ -1 +1 @@
1
- {"version":3,"file":"loadConfig.js","sourceRoot":"","sources":["../../src/config/loadConfig.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loadConfig.js","sourceRoot":"","sources":["../../src/config/loadConfig.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,eAAe,EAAkB,MAAM,aAAa,CAAC;AAC9D,OAAO,EACL,8BAA8B,EAC9B,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,GAAG,sBAAsB,CAAC;AAC3C,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDtB,CAAC;AAEF,MAAM,UAAU,UAAU,CACxB,UAAmB;IAEnB,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,EAAE,EAAE,CAAC;QAC7F,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IACzC,CAAC;IACD,UAAU,CAAC;QACT,IAAI,EAAE,iBAAiB,EAAE;QACzB,KAAK,EAAE,IAAI;QACX,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,KAAK,GAAG;KAC9D,CAAC,CAAC;IAEH,MAAM,cAAc,GAAG,aAAa,CAAC,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC/E,MAAM,YAAY,GAAG,eAAe,CAAC,cAAc,IAAI,iBAAiB,EAAE,CAAC,CAAC;IAC5E,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,IAAI,cAAc;YAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,YAAY,EAAE,CAAC,CAAC;QACnF,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,EAAE,CAAC,aAAa,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAY,CAAC;IAC/C,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAE7C,MAAM,YAAY,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,kBAAkB,YAAY,sBAAsB,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;IAC/E,OAAO;QACL,GAAG,MAAM;QACT,QAAQ,EAAE;YACR,GAAG,MAAM,CAAC,QAAQ;YAClB,KAAK,EAAE,YAAY;YACnB,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;SACvC;QACD,OAAO,EAAE;YACP,UAAU;SACX;QACD,OAAO,EAAE;YACP,GAAG,MAAM,CAAC,OAAO;YACjB,IAAI,EAAE,eAAe,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,eAAe,CAAC;SAC5D;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oCAAoC,CAAC,UAAmB;IACtE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACzD,IAAI,CAAC;QACH,OAAO,UAAU,CAAC,UAAU,CAAC,CAAC;IAChC,CAAC;YAAS,CAAC;QACT,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5C,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvD,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,WAAW,EAAE,CAAC;YACxC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;QAC5B,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,OAAO,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,IAAY,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;AACrF,CAAC;AAED,SAAS,aAAa,CAAC,GAAG,MAAiC;IACzD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAChF,CAAC"}
@@ -1,6 +1,36 @@
1
1
  import { z } from "zod";
2
2
  import { DEFAULT_LOG_PATH, DEFAULT_SQLITE_PATH } from "./paths.js";
3
3
  const envRecordSchema = z.record(z.string(), z.string()).default({});
4
+ export const DEFAULT_GROUP_NAME_FORMAT = {
5
+ project: "[{agent}] [{project}] {taskname}",
6
+ projectless: "[{agent}] {taskname}",
7
+ dateFormat: "MM-dd",
8
+ };
9
+ const groupNameTemplateSchema = z.string().min(1).max(240).superRefine((template, context) => {
10
+ const tokens = [...template.matchAll(/\{([^{}]+)\}/gu)].map((match) => match[1]);
11
+ const taskNameCount = tokens.filter((token) => token === "taskname").length;
12
+ if (taskNameCount !== 1) {
13
+ context.addIssue({
14
+ code: "custom",
15
+ message: "A group name format must contain exactly one {taskname} placeholder.",
16
+ });
17
+ }
18
+ for (const token of tokens) {
19
+ if (["os", "agent", "project", "taskname", "date"].includes(token))
20
+ continue;
21
+ if (token.startsWith("date:") && token.slice("date:".length).trim())
22
+ continue;
23
+ context.addIssue({
24
+ code: "custom",
25
+ message: `Unsupported group name placeholder: {${token}}.`,
26
+ });
27
+ }
28
+ });
29
+ const groupNameFormatSchema = z.object({
30
+ project: groupNameTemplateSchema.default(DEFAULT_GROUP_NAME_FORMAT.project),
31
+ projectless: groupNameTemplateSchema.default(DEFAULT_GROUP_NAME_FORMAT.projectless),
32
+ dateFormat: z.string().min(1).max(80).default(DEFAULT_GROUP_NAME_FORMAT.dateFormat),
33
+ }).default(DEFAULT_GROUP_NAME_FORMAT);
4
34
  const agentKindSchema = z.union([
5
35
  z.literal("acp"),
6
36
  z.literal("app-server"),
@@ -26,6 +56,7 @@ export const appConfigSchema = z.object({
26
56
  userOpenId: z.string().optional(),
27
57
  respondToOwnerOnly: z.boolean().default(true),
28
58
  respondToAllGroupMessages: z.boolean().default(true),
59
+ groupNameFormat: groupNameFormatSchema,
29
60
  thinkingCardLayout: z.enum(["grouped", "timeline"]).default("grouped"),
30
61
  useConsoleWhenMissingCredentials: z.boolean().default(false),
31
62
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AAErE,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC;IAC9B,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC;IAChB,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;IACvB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,YAAqB,CAAC;CAC1D,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAElB,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACxB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACrC,GAAG,EAAE,eAAe;CACrB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,OAAO,EAAE,CAAC;SACP,MAAM,CAAC;QACN,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;KACnC,CAAC;SACD,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC7B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;QAC7D,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC5B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAChC,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QACjC,kBAAkB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;QAC7C,yBAAyB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;QACpD,kBAAkB,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;QACtE,gCAAgC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;KAC7D,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC,MAAM,CAC3D,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,EAC1C,wCAAwC,CACzC;IACD,QAAQ,EAAE,CAAC;SACR,MAAM,CAAC;QACN,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC5B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC;KAC7B,CAAC;SACD,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IACxB,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC;QAChB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC;KACpD,CAAC,CAAC,OAAO,CAAC,EAAE,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAC/C,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC;QAChB,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;QACnF,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC;KACtD,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC;CACtD,CAAC,CAAC"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- export const FINAL_RESPONSE_BRANDING = "> Powered by [AgentBot](https://bytedance.larkoffice.com/docx/UTukdYBopojSivxRVeUcCXTtnid)";
1
+ export const FINAL_RESPONSE_BRANDING = "> Powered by [AgentBot](https://keyou.github.io/agent-bot/)";
2
2
  export const FINAL_RESPONSE_BRANDING_BLOCK = `----\n\n${FINAL_RESPONSE_BRANDING}`;
3
3
  export function splitFinalResponseBranding(markdown) {
4
4
  if (markdown === FINAL_RESPONSE_BRANDING_BLOCK) {
@@ -1 +1 @@
1
- {"version":3,"file":"FinalResponseBranding.js","sourceRoot":"","sources":["../../src/feishu/FinalResponseBranding.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,uBAAuB,GAClC,4FAA4F,CAAC;AAC/F,MAAM,CAAC,MAAM,6BAA6B,GAAG,WAAW,uBAAuB,EAAE,CAAC;AAElF,MAAM,UAAU,0BAA0B,CAAC,QAAgB;IAIzD,IAAI,QAAQ,KAAK,6BAA6B,EAAE,CAAC;QAC/C,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,uBAAuB,EAAE,CAAC;IAC5D,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,6BAA6B,EAAE,CAAC;IACtD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IAC7D,OAAO;QACL,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;QAC1C,QAAQ,EAAE,uBAAuB;KAClC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"FinalResponseBranding.js","sourceRoot":"","sources":["../../src/feishu/FinalResponseBranding.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,uBAAuB,GAClC,6DAA6D,CAAC;AAChE,MAAM,CAAC,MAAM,6BAA6B,GAAG,WAAW,uBAAuB,EAAE,CAAC;AAElF,MAAM,UAAU,0BAA0B,CAAC,QAAgB;IAIzD,IAAI,QAAQ,KAAK,6BAA6B,EAAE,CAAC;QAC/C,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,uBAAuB,EAAE,CAAC;IAC5D,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,6BAA6B,EAAE,CAAC;IACtD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;IAC7D,OAAO;QACL,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC;QAC1C,QAAQ,EAAE,uBAAuB;KAClC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,193 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+ import { DEFAULT_GROUP_NAME_FORMAT, } from "../config/schema.js";
4
+ export const FEISHU_GROUP_NAME_MAX_LENGTH = 60;
5
+ const GROUP_PROJECT_NAME_MAX_LENGTH = 15;
6
+ const PLACEHOLDER_PATTERN = /\{([^{}]+)\}/gu;
7
+ const TASK_NAME_PLACEHOLDER = "{taskname}";
8
+ export function formatNewGroupName(input) {
9
+ const format = input.format ?? DEFAULT_GROUP_NAME_FORMAT;
10
+ const template = input.projectCwd ? format.project : format.projectless;
11
+ const taskNameIndex = template.indexOf(TASK_NAME_PLACEHOLDER);
12
+ const values = templateValues(input, format);
13
+ const prefix = renderTemplate(template.slice(0, taskNameIndex), values);
14
+ const suffix = renderTemplate(template.slice(taskNameIndex + TASK_NAME_PLACEHOLDER.length), values);
15
+ const availableTaskNameLength = FEISHU_GROUP_NAME_MAX_LENGTH
16
+ - Array.from(prefix).length
17
+ - Array.from(suffix).length;
18
+ const taskName = truncateTail(input.taskName, availableTaskNameLength);
19
+ return truncateTail(`${prefix}${taskName}${suffix}`.trim(), FEISHU_GROUP_NAME_MAX_LENGTH);
20
+ }
21
+ export function parseTaskNameFromGroupName(input) {
22
+ const format = input.format ?? DEFAULT_GROUP_NAME_FORMAT;
23
+ const template = input.projectCwd ? format.project : format.projectless;
24
+ const values = templateValues(input, format);
25
+ let pattern = "^";
26
+ let cursor = 0;
27
+ let match;
28
+ PLACEHOLDER_PATTERN.lastIndex = 0;
29
+ while ((match = PLACEHOLDER_PATTERN.exec(template)) !== null) {
30
+ pattern += escapeRegExp(template.slice(cursor, match.index));
31
+ const token = match[1];
32
+ if (token === "taskname")
33
+ pattern += "(?<taskname>.+?)";
34
+ else if (token === "date" || token.startsWith("date:")) {
35
+ const dateFormat = token === "date" ? format.dateFormat : token.slice("date:".length);
36
+ pattern += dateFormatPattern(dateFormat);
37
+ }
38
+ else {
39
+ pattern += escapeRegExp(placeholderValue(token, values));
40
+ }
41
+ cursor = match.index + match[0].length;
42
+ }
43
+ pattern += `${escapeRegExp(template.slice(cursor))}$`;
44
+ const parsed = new RegExp(pattern, "iu").exec(input.groupName.trim())?.groups?.taskname?.trim();
45
+ return parsed || undefined;
46
+ }
47
+ export function formatGroupNameDate(date, format) {
48
+ const year = date.getFullYear();
49
+ const month = date.getMonth() + 1;
50
+ const day = date.getDate();
51
+ const hour = date.getHours();
52
+ const minute = date.getMinutes();
53
+ const second = date.getSeconds();
54
+ const values = new Map([
55
+ ["yyyy", String(year).padStart(4, "0")],
56
+ ["YYYY", String(year).padStart(4, "0")],
57
+ ["yy", String(year % 100).padStart(2, "0")],
58
+ ["YY", String(year % 100).padStart(2, "0")],
59
+ ["MM", String(month).padStart(2, "0")],
60
+ ["M", String(month)],
61
+ ["dd", String(day).padStart(2, "0")],
62
+ ["DD", String(day).padStart(2, "0")],
63
+ ["d", String(day)],
64
+ ["D", String(day)],
65
+ ["HH", String(hour).padStart(2, "0")],
66
+ ["H", String(hour)],
67
+ ["mm", String(minute).padStart(2, "0")],
68
+ ["m", String(minute)],
69
+ ["ss", String(second).padStart(2, "0")],
70
+ ["s", String(second)],
71
+ ]);
72
+ return replaceDateTokens(format, (token) => values.get(token));
73
+ }
74
+ export function groupNameOs(platform = process.platform) {
75
+ if (platform === "win32")
76
+ return "win";
77
+ if (platform === "darwin")
78
+ return "mac";
79
+ if (platform === "linux")
80
+ return "linux";
81
+ return platform;
82
+ }
83
+ export function formatGroupProjectName(projectCwd) {
84
+ const value = abbreviateHomeDirectory(projectCwd);
85
+ const levels = value
86
+ .replace(/[\\/]+$/, "")
87
+ .split(/[\\/]+/)
88
+ .filter(Boolean)
89
+ .slice(-2);
90
+ const separator = value.includes("\\") ? path.win32.sep : path.posix.sep;
91
+ return fitTrailingPathLevels(levels, GROUP_PROJECT_NAME_MAX_LENGTH, separator);
92
+ }
93
+ function templateValues(input, format) {
94
+ return {
95
+ agent: input.agentName,
96
+ project: input.projectCwd ? formatGroupProjectName(input.projectCwd) : "",
97
+ os: groupNameOs(input.platform),
98
+ date: input.date ?? new Date(),
99
+ dateFormat: format.dateFormat,
100
+ };
101
+ }
102
+ function renderTemplate(template, values) {
103
+ PLACEHOLDER_PATTERN.lastIndex = 0;
104
+ return template.replace(PLACEHOLDER_PATTERN, (_placeholder, token) => {
105
+ if (token === "date")
106
+ return formatGroupNameDate(values.date, values.dateFormat);
107
+ if (token.startsWith("date:")) {
108
+ return formatGroupNameDate(values.date, token.slice("date:".length));
109
+ }
110
+ return placeholderValue(token, values);
111
+ });
112
+ }
113
+ function placeholderValue(token, values) {
114
+ if (token === "agent")
115
+ return values.agent;
116
+ if (token === "project")
117
+ return values.project;
118
+ if (token === "os")
119
+ return values.os;
120
+ return "";
121
+ }
122
+ function dateFormatPattern(format) {
123
+ return replaceDateTokens(format, (token) => {
124
+ if (["yyyy", "YYYY"].includes(token))
125
+ return "\\d{4}";
126
+ if (["yy", "YY", "MM", "dd", "DD", "HH", "mm", "ss"].includes(token))
127
+ return "\\d{2}";
128
+ return "\\d{1,2}";
129
+ }, escapeRegExp);
130
+ }
131
+ const DATE_TOKENS = [
132
+ "yyyy", "YYYY", "yy", "YY", "MM", "dd", "DD", "HH", "mm", "ss", "M", "d", "D", "H", "m", "s",
133
+ ];
134
+ function replaceDateTokens(format, replaceToken, replaceLiteral = (literal) => literal) {
135
+ let result = "";
136
+ for (let index = 0; index < format.length;) {
137
+ const token = DATE_TOKENS.find((candidate) => format.startsWith(candidate, index));
138
+ if (token) {
139
+ result += replaceToken(token);
140
+ index += token.length;
141
+ }
142
+ else {
143
+ result += replaceLiteral(format[index]);
144
+ index += 1;
145
+ }
146
+ }
147
+ return result;
148
+ }
149
+ function abbreviateHomeDirectory(value) {
150
+ const homeDirectory = os.homedir();
151
+ const valueIsWindows = isWindowsAbsolutePath(value);
152
+ const homeIsWindows = isWindowsAbsolutePath(homeDirectory);
153
+ if (valueIsWindows !== homeIsWindows && (valueIsWindows || path.posix.isAbsolute(value)))
154
+ return value;
155
+ const pathApi = valueIsWindows ? path.win32 : path;
156
+ const relative = pathApi.relative(homeDirectory, value);
157
+ if (relative === "")
158
+ return "~";
159
+ if (pathApi.isAbsolute(relative) || relative === ".." || relative.startsWith(`..${pathApi.sep}`))
160
+ return value;
161
+ return `~${pathApi.sep}${relative}`;
162
+ }
163
+ function isWindowsAbsolutePath(value) {
164
+ return /^[a-z]:[\\/]|^\\\\/iu.test(value);
165
+ }
166
+ function fitTrailingPathLevels(levels, maxLength, separator) {
167
+ if (levels.length === 0)
168
+ return "";
169
+ if (levels.length === 1)
170
+ return truncateTail(levels[0], maxLength);
171
+ const parent = levels[0];
172
+ const leaf = levels[1];
173
+ const joined = `${parent}${separator}${leaf}`;
174
+ if (Array.from(joined).length <= maxLength)
175
+ return joined;
176
+ if (Array.from(leaf).length <= maxLength)
177
+ return leaf;
178
+ return truncateTail(leaf, maxLength);
179
+ }
180
+ function truncateTail(value, maxLength) {
181
+ const characters = Array.from(value);
182
+ if (characters.length <= maxLength)
183
+ return value;
184
+ if (maxLength <= 0)
185
+ return "";
186
+ if (maxLength <= 3)
187
+ return ".".repeat(maxLength);
188
+ return `${characters.slice(0, maxLength - 3).join("")}...`;
189
+ }
190
+ function escapeRegExp(value) {
191
+ return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
192
+ }
193
+ //# sourceMappingURL=GroupNameFormatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GroupNameFormatter.js","sourceRoot":"","sources":["../../src/feishu/GroupNameFormatter.ts"],"names":[],"mappings":"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"}
@@ -4,11 +4,13 @@ import os from "node:os";
4
4
  import path from "node:path";
5
5
  import { createProjectlessWorkspace, detectProjectlessWorkspace } from "../codex/ProjectlessWorkspace.js";
6
6
  import { resolveUserPath } from "../config/paths.js";
7
+ import { DEFAULT_GROUP_NAME_FORMAT } from "../config/schema.js";
7
8
  import { CommandRouter } from "../commands/CommandRouter.js";
8
9
  import { baseChatContextKey, isThreadContextKey } from "../feishu/contextKey.js";
9
10
  import { CardRenderer, } from "../feishu/CardRenderer.js";
10
11
  import { CardUpdateScheduler } from "../feishu/CardUpdateScheduler.js";
11
12
  import { generateGroupAvatarPng, resolveGroupAvatarProjectName } from "../feishu/GroupAvatarGenerator.js";
13
+ import { formatGroupNameDate, formatNewGroupName, parseTaskNameFromGroupName, } from "../feishu/GroupNameFormatter.js";
12
14
  import { normalizeFeishuPostText } from "../feishu/InboundText.js";
13
15
  import { allowsFeishuUser } from "../feishu/ownerAccess.js";
14
16
  import { buildTurnGraphRows } from "../presentation/turnGraph.js";
@@ -2476,8 +2478,8 @@ export class ProxySessionController {
2476
2478
  }
2477
2479
  async createFeishuGroupWithTask(sourceContextKey, agentName, requestedTitle, userId, boundProjectCwd, executionSettings) {
2478
2480
  const explicitTitle = normalizeTaskTitle(requestedTitle);
2479
- const taskTitle = explicitTitle ?? `新任务 (${formatGroupDateSuffix(new Date())})`;
2480
- const group = await this.createFeishuGroupContext(sourceContextKey, agentName, taskTitle, userId, boundProjectCwd, "/newgroup", false);
2481
+ const taskTitle = explicitTitle ?? `新任务 (${formatGroupNameDate(new Date(), this.config.feishu?.groupNameFormat?.dateFormat ?? DEFAULT_GROUP_NAME_FORMAT.dateFormat)})`;
2482
+ const group = await this.createFeishuGroupContext(sourceContextKey, agentName, taskTitle, userId, boundProjectCwd, "/newgroup");
2481
2483
  let task;
2482
2484
  try {
2483
2485
  task = await this.createSession(group.contextKey, agentName, boundProjectCwd, false, false, undefined, undefined, taskTitle, executionSettings);
@@ -2523,7 +2525,7 @@ export class ProxySessionController {
2523
2525
  async forkPreparedSessionToFeishuGroup(sourceContextKey, prepared, userId, sourceSummary) {
2524
2526
  const { plan } = prepared;
2525
2527
  const boundProjectCwd = detectProjectlessWorkspace(plan.cwd) ? undefined : plan.cwd;
2526
- const group = await this.createFeishuGroupContext(sourceContextKey, plan.agentName, plan.forkTitle, userId, boundProjectCwd, "/forkgroup", false);
2528
+ const group = await this.createFeishuGroupContext(sourceContextKey, plan.agentName, plan.forkTitle, userId, boundProjectCwd, "/forkgroup");
2527
2529
  let forked;
2528
2530
  try {
2529
2531
  forked = await this.forkSessionIntoContext(group.contextKey, plan);
@@ -2547,11 +2549,17 @@ export class ProxySessionController {
2547
2549
  await this.outbound.sendText(sourceContextKey, `已将${sourceSummary} Fork 到飞书群:${group.name};新群当前任务为 ${taskDescription}。`);
2548
2550
  return { group, task: forked.record };
2549
2551
  }
2550
- async createFeishuGroupContext(sourceContextKey, agentName, taskTitle, userId, boundProjectCwd, commandName, includeTimestamp) {
2552
+ async createFeishuGroupContext(sourceContextKey, agentName, taskTitle, userId, boundProjectCwd, commandName) {
2551
2553
  if (!userId?.startsWith("ou_")) {
2552
2554
  throw new Error(`${commandName} 只能由具有 open_id 的飞书用户消息触发。`);
2553
2555
  }
2554
- const groupName = formatNewGroupName(agentName, boundProjectCwd, taskTitle, new Date(), includeTimestamp);
2556
+ const groupName = formatNewGroupName({
2557
+ agentName,
2558
+ projectCwd: boundProjectCwd,
2559
+ taskName: taskTitle,
2560
+ date: new Date(),
2561
+ format: this.config.feishu?.groupNameFormat,
2562
+ });
2555
2563
  const group = await this.outbound.createGroup(sourceContextKey, {
2556
2564
  name: groupName,
2557
2565
  userOpenId: userId,
@@ -3680,18 +3688,29 @@ export class ProxySessionController {
3680
3688
  await this.outbound.sendText(contextKey, `已将当前任务标题修改为:${normalizedTitle}`);
3681
3689
  }
3682
3690
  async syncTaskTitleFromGroupName(contextKey, event) {
3683
- const parsed = parseAgentGroupName(event.afterName);
3684
- if (!parsed)
3685
- return;
3686
3691
  const context = this.store.getUserContext(contextKey);
3687
3692
  if (!context?.currentSessionId)
3688
3693
  return;
3689
3694
  const record = this.store.getSessionForContext(context.currentSessionId, contextKey);
3690
3695
  if (!record || record.status === "closed")
3691
3696
  return;
3692
- if (record.agentName.toLowerCase() !== parsed.agentName.toLowerCase())
3697
+ const nameFormat = this.config.feishu?.groupNameFormat ?? DEFAULT_GROUP_NAME_FORMAT;
3698
+ const projectCwd = detectProjectlessWorkspace(record.cwd) ? undefined : record.cwd;
3699
+ const templateTitle = parseTaskNameFromGroupName({
3700
+ agentName: record.agentName,
3701
+ groupName: event.afterName,
3702
+ projectCwd,
3703
+ format: nameFormat,
3704
+ });
3705
+ const legacy = parseAgentGroupName(event.afterName);
3706
+ const legacyTitle = legacy && record.agentName.toLowerCase() === legacy.agentName.toLowerCase()
3707
+ ? legacy.title
3708
+ : undefined;
3709
+ if (isDefaultGroupNameFormat(nameFormat) && isLegacyGroupPrefixOnly(event.afterName))
3693
3710
  return;
3694
- const title = normalizeTaskTitle(parsed.title);
3711
+ const title = normalizeTaskTitle(isDefaultGroupNameFormat(nameFormat)
3712
+ ? legacyTitle ?? templateTitle
3713
+ : templateTitle ?? legacyTitle);
3695
3714
  if (!title || title === record.title)
3696
3715
  return;
3697
3716
  const loaded = await this.loadSession(record);
@@ -5714,34 +5733,6 @@ function isRecoveryAttemptRecent(attempt, cutoff) {
5714
5733
  const updatedAt = Date.parse(attempt.updatedAt);
5715
5734
  return Number.isFinite(updatedAt) && updatedAt >= cutoff;
5716
5735
  }
5717
- function formatGroupDateSuffix(date) {
5718
- const month = String(date.getMonth() + 1).padStart(2, "0");
5719
- const day = String(date.getDate()).padStart(2, "0");
5720
- return `${month}-${day}`;
5721
- }
5722
- function formatNewGroupName(agentName, projectCwd, taskTitle, date, includeTimestamp) {
5723
- const prefix = `[${agentName}] `;
5724
- const projectPrefix = projectCwd ? `${formatGroupProjectDirectory(projectCwd)} ` : "";
5725
- const titlePrefix = `${prefix}${projectPrefix}`;
5726
- const timestampSuffix = includeTimestamp ? ` (${formatGroupDateSuffix(date)})` : "";
5727
- const availableTitleLength = FEISHU_GROUP_NAME_MAX_LENGTH
5728
- - Array.from(titlePrefix).length
5729
- - Array.from(timestampSuffix).length;
5730
- const title = truncateTail(taskTitle, availableTitleLength);
5731
- return truncateTail(`${titlePrefix}${title}${timestampSuffix}`, FEISHU_GROUP_NAME_MAX_LENGTH);
5732
- }
5733
- const FEISHU_GROUP_NAME_MAX_LENGTH = 60;
5734
- const GROUP_PROJECT_DIRECTORY_MAX_LENGTH = 15;
5735
- function formatGroupProjectDirectory(projectCwd) {
5736
- const value = abbreviateHomeDirectory(projectCwd);
5737
- const levels = value
5738
- .replace(/[\\/]+$/, "")
5739
- .split(/[\\/]+/)
5740
- .filter(Boolean)
5741
- .slice(-2);
5742
- const separator = value.includes("\\") ? path.win32.sep : path.posix.sep;
5743
- return `[${fitTrailingPathLevels(levels, GROUP_PROJECT_DIRECTORY_MAX_LENGTH, separator)}]`;
5744
- }
5745
5736
  function abbreviateHomeDirectory(value) {
5746
5737
  const homeDirectory = os.homedir();
5747
5738
  const valueIsWindows = isWindowsAbsolutePath(value);
@@ -5759,33 +5750,6 @@ function abbreviateHomeDirectory(value) {
5759
5750
  function isWindowsAbsolutePath(value) {
5760
5751
  return /^[a-z]:[\\/]|^\\\\/iu.test(value);
5761
5752
  }
5762
- function fitTrailingPathLevels(levels, maxLength, separator) {
5763
- if (levels.length === 0)
5764
- return "";
5765
- if (levels.length === 1)
5766
- return truncatePathLevel(levels[0], maxLength);
5767
- const parent = levels[0];
5768
- const leaf = levels[1];
5769
- const joined = `${parent}${separator}${leaf}`;
5770
- if (Array.from(joined).length <= maxLength)
5771
- return joined;
5772
- if (Array.from(leaf).length <= maxLength)
5773
- return leaf;
5774
- return truncatePathLevel(leaf, maxLength);
5775
- }
5776
- function truncatePathLevel(value, maxLength) {
5777
- return truncateTail(value, maxLength);
5778
- }
5779
- function truncateTail(value, maxLength) {
5780
- const characters = Array.from(value);
5781
- if (characters.length <= maxLength)
5782
- return value;
5783
- if (maxLength <= 0)
5784
- return "";
5785
- if (maxLength <= 3)
5786
- return ".".repeat(maxLength);
5787
- return `${characters.slice(0, maxLength - 3).join("")}...`;
5788
- }
5789
5753
  function parseAgentGroupName(value) {
5790
5754
  const match = /^\[([^[\]]+)\]\s+(.+)$/.exec(value.trim());
5791
5755
  const agentName = match?.[1]?.trim();
@@ -5796,6 +5760,13 @@ function parseAgentGroupName(value) {
5796
5760
  const title = projectPrefix ? projectPrefix[2]?.trim() : remainder;
5797
5761
  return agentName && title ? { agentName, title } : undefined;
5798
5762
  }
5763
+ function isDefaultGroupNameFormat(format) {
5764
+ return format.project === DEFAULT_GROUP_NAME_FORMAT.project
5765
+ && format.projectless === DEFAULT_GROUP_NAME_FORMAT.projectless;
5766
+ }
5767
+ function isLegacyGroupPrefixOnly(value) {
5768
+ return /^\[[^[\]]+\]\s+\[[^[\]]+\]\s*$/u.test(value.trim());
5769
+ }
5799
5770
  function validateGoalObjective(objective) {
5800
5771
  const length = Array.from(objective.trim()).length;
5801
5772
  if (length === 0)