@keyou007/agent-bot 0.1.14 → 0.1.15-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +29 -24
  3. package/README.zh.md +29 -24
  4. package/config.example.yaml +1 -0
  5. package/dist/cli/FeishuAppConfiguration.js +42 -3
  6. package/dist/cli/FeishuAppConfiguration.js.map +1 -1
  7. package/dist/cli/help.js +6 -6
  8. package/dist/cli/initOptions.js +1 -4
  9. package/dist/cli/initOptions.js.map +1 -1
  10. package/dist/cli.js +8 -5
  11. package/dist/cli.js.map +1 -1
  12. package/dist/feishu/CardRenderer.js +91 -45
  13. package/dist/feishu/CardRenderer.js.map +1 -1
  14. package/dist/feishu/FeishuConnector.js +39 -12
  15. package/dist/feishu/FeishuConnector.js.map +1 -1
  16. package/dist/feishu/FeishuMarkdown.js +58 -6
  17. package/dist/feishu/FeishuMarkdown.js.map +1 -1
  18. package/dist/feishu/FeishuMessageClient.js +108 -4
  19. package/dist/feishu/FeishuMessageClient.js.map +1 -1
  20. package/dist/feishu/FeishuTurnPresenter.js +24 -1
  21. package/dist/feishu/FeishuTurnPresenter.js.map +1 -1
  22. package/dist/feishu/FinalResponseBranding.js +15 -0
  23. package/dist/feishu/FinalResponseBranding.js.map +1 -0
  24. package/dist/feishu/InboundText.js +13 -0
  25. package/dist/feishu/InboundText.js.map +1 -0
  26. package/dist/feishu/MergedForwardMessage.js +317 -0
  27. package/dist/feishu/MergedForwardMessage.js.map +1 -0
  28. package/dist/logging/DailyLogStream.js +73 -0
  29. package/dist/logging/DailyLogStream.js.map +1 -0
  30. package/dist/logging/logger.js +2 -1
  31. package/dist/logging/logger.js.map +1 -1
  32. package/dist/presentation/OutboundRouter.js +21 -0
  33. package/dist/presentation/OutboundRouter.js.map +1 -1
  34. package/dist/proxy/ProxySessionController.js +536 -58
  35. package/dist/proxy/ProxySessionController.js.map +1 -1
  36. package/dist/state/StateStore.js +161 -3
  37. package/dist/state/StateStore.js.map +1 -1
  38. package/dist/state/migrations.js +12 -0
  39. package/dist/state/migrations.js.map +1 -1
  40. package/dist/supervision/SupervisorDiagnostics.js +37 -21
  41. package/dist/supervision/SupervisorDiagnostics.js.map +1 -1
  42. package/dist/supervisor.js +11 -4
  43. package/dist/supervisor.js.map +1 -1
  44. package/dist/utils/executeShellCommand.js +83 -16
  45. package/dist/utils/executeShellCommand.js.map +1 -1
  46. package/docs/technical-reference.md +9 -8
  47. package/docs/technical-reference.zh.md +9 -8
  48. package/npm-shrinkwrap.json +2 -2
  49. package/package.json +1 -1
  50. package/skills/agent-bot/SKILL.md +1 -1
  51. package/src/cli/FeishuAppConfiguration.ts +76 -3
  52. package/src/cli/help.ts +6 -6
  53. package/src/cli/initOptions.ts +1 -10
  54. package/src/cli.ts +10 -6
  55. package/src/feishu/CardRenderer.ts +116 -45
  56. package/src/feishu/FeishuConnector.ts +55 -13
  57. package/src/feishu/FeishuMarkdown.ts +64 -5
  58. package/src/feishu/FeishuMessageClient.ts +151 -12
  59. package/src/feishu/FeishuTurnPresenter.ts +28 -4
  60. package/src/feishu/FinalResponseBranding.ts +18 -0
  61. package/src/feishu/InboundText.ts +12 -0
  62. package/src/feishu/MergedForwardMessage.ts +372 -0
  63. package/src/feishu/types.ts +15 -0
  64. package/src/logging/DailyLogStream.ts +88 -0
  65. package/src/logging/logger.ts +2 -1
  66. package/src/presentation/OutboundRouter.ts +28 -0
  67. package/src/proxy/ProxySessionController.ts +642 -55
  68. package/src/state/StateStore.ts +230 -2
  69. package/src/state/migrations.ts +12 -0
  70. package/src/supervision/SupervisorDiagnostics.ts +41 -25
  71. package/src/supervisor.ts +10 -4
  72. package/src/utils/executeShellCommand.ts +103 -15
@@ -1,3 +1,7 @@
1
+ import type { MergedForwardContent, ReferencedMessageContent } from "./MergedForwardMessage.js";
2
+
3
+ export type { MergedForwardContent, ReferencedMessageContent } from "./MergedForwardMessage.js";
4
+
1
5
  export interface IncomingMessage {
2
6
  messageId: string;
3
7
  contextKey: string;
@@ -12,12 +16,20 @@ export interface IncomingMessage {
12
16
  mentionedBot?: true;
13
17
  text: string;
14
18
  images?: IncomingImageReference[];
19
+ files?: IncomingFileReference[];
20
+ mergedForwardMessageId?: string;
21
+ displayText?: string;
15
22
  }
16
23
 
17
24
  export interface IncomingImageReference {
18
25
  imageKey: string;
19
26
  }
20
27
 
28
+ export interface IncomingFileReference {
29
+ fileKey: string;
30
+ fileName: string;
31
+ }
32
+
21
33
  export interface MessageReplyTarget {
22
34
  messageId: string;
23
35
  replyInThread: true;
@@ -54,6 +66,9 @@ export interface FeishuOutbound {
54
66
  addReaction?(messageId: string, emojiType: string): Promise<string | undefined>;
55
67
  deleteReaction?(messageId: string, reactionId: string): Promise<void>;
56
68
  downloadImage?(messageId: string, imageKey: string): Promise<string>;
69
+ downloadFile?(messageId: string, fileKey: string, fileName: string): Promise<string>;
70
+ readMergedForward?(messageId: string): Promise<MergedForwardContent>;
71
+ readReferencedMessage?(messageId: string): Promise<ReferencedMessageContent>;
57
72
  sendText(contextKey: string, text: string): Promise<string | undefined>;
58
73
  sendFile?(contextKey: string, filePath: string): Promise<string | undefined>;
59
74
  sendMarkdown(contextKey: string, markdown: string, idempotencyKey?: string): Promise<string | undefined>;
@@ -0,0 +1,88 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { Writable } from "node:stream";
4
+
5
+ interface DailyLogStreamOptions {
6
+ clock?: () => Date;
7
+ mode?: number;
8
+ beforeOpen?: (filePath: string) => void;
9
+ }
10
+
11
+ export class DailyLogStream extends Writable {
12
+ private currentPath?: string;
13
+ private lastPath?: string;
14
+ private currentStream?: fs.WriteStream;
15
+ private readonly clock: () => Date;
16
+
17
+ constructor(
18
+ private readonly basePath: string,
19
+ private readonly options: DailyLogStreamOptions = {},
20
+ ) {
21
+ super();
22
+ this.clock = options.clock ?? (() => new Date());
23
+ }
24
+
25
+ get filePath(): string | undefined {
26
+ return this.currentPath ?? this.lastPath;
27
+ }
28
+
29
+ override _write(
30
+ chunk: string | Buffer,
31
+ encoding: BufferEncoding,
32
+ callback: (error?: Error | null) => void,
33
+ ): void {
34
+ let stream: fs.WriteStream;
35
+ try {
36
+ stream = this.streamFor(this.clock());
37
+ } catch (error) {
38
+ callback(error instanceof Error ? error : new Error(String(error)));
39
+ return;
40
+ }
41
+ stream.write(chunk, encoding, callback);
42
+ }
43
+
44
+ override _final(callback: (error?: Error | null) => void): void {
45
+ const stream = this.currentStream;
46
+ this.currentStream = undefined;
47
+ this.currentPath = undefined;
48
+ if (!stream) {
49
+ callback();
50
+ return;
51
+ }
52
+ stream.end(callback);
53
+ }
54
+
55
+ override _destroy(error: Error | null, callback: (error?: Error | null) => void): void {
56
+ this.currentStream?.destroy();
57
+ this.currentStream = undefined;
58
+ this.currentPath = undefined;
59
+ callback(error);
60
+ }
61
+
62
+ private streamFor(date: Date): fs.WriteStream {
63
+ const targetPath = dailyLogPath(this.basePath, date);
64
+ if (this.currentStream && this.currentPath === targetPath) return this.currentStream;
65
+
66
+ const previous = this.currentStream;
67
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
68
+ this.options.beforeOpen?.(targetPath);
69
+ this.currentPath = targetPath;
70
+ this.lastPath = targetPath;
71
+ this.currentStream = fs.createWriteStream(targetPath, {
72
+ flags: "a",
73
+ ...(this.options.mode === undefined ? {} : { mode: this.options.mode }),
74
+ });
75
+ previous?.end();
76
+ return this.currentStream;
77
+ }
78
+ }
79
+
80
+ export function dailyLogPath(basePath: string, date: Date): string {
81
+ const parsed = path.parse(basePath);
82
+ const dateStamp = [
83
+ date.getFullYear(),
84
+ String(date.getMonth() + 1).padStart(2, "0"),
85
+ String(date.getDate()).padStart(2, "0"),
86
+ ].join("-");
87
+ return path.join(parsed.dir, `${parsed.name}.${dateStamp}${parsed.ext}`);
88
+ }
@@ -2,6 +2,7 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import pino, { type Logger } from "pino";
4
4
  import type { AppConfig } from "../config/schema.js";
5
+ import { DailyLogStream } from "./DailyLogStream.js";
5
6
 
6
7
  export function createLogger(config: AppConfig): Logger {
7
8
  const streams: pino.StreamEntry[] = [
@@ -13,7 +14,7 @@ export function createLogger(config: AppConfig): Logger {
13
14
  if (config.logging.path) {
14
15
  fs.mkdirSync(path.dirname(config.logging.path), { recursive: true });
15
16
  streams.push({
16
- stream: fs.createWriteStream(config.logging.path, { flags: "a" }),
17
+ stream: new DailyLogStream(config.logging.path),
17
18
  });
18
19
  }
19
20
 
@@ -4,7 +4,9 @@ import type {
4
4
  CreatedGroup,
5
5
  CreateGroupInput,
6
6
  FeishuOutbound,
7
+ MergedForwardContent,
7
8
  MessageReplyTarget,
9
+ ReferencedMessageContent,
8
10
  } from "../feishu/types.js";
9
11
 
10
12
  export interface TurnPresenter {
@@ -165,6 +167,32 @@ export class OutboundRouter {
165
167
  return download.call(outbound, messageId, imageKey);
166
168
  }
167
169
 
170
+ async downloadFile(
171
+ contextKey: string,
172
+ messageId: string,
173
+ fileKey: string,
174
+ fileName: string,
175
+ ): Promise<string> {
176
+ const outbound = this.route(contextKey).outbound;
177
+ const download = outbound.downloadFile;
178
+ if (!download) throw new Error("当前消息通道不支持下载文件。");
179
+ return download.call(outbound, messageId, fileKey, fileName);
180
+ }
181
+
182
+ async readMergedForward(contextKey: string, messageId: string): Promise<MergedForwardContent> {
183
+ const outbound = this.route(contextKey).outbound;
184
+ const read = outbound.readMergedForward;
185
+ if (!read) throw new Error("当前消息通道不支持读取合并转发消息。");
186
+ return read.call(outbound, messageId);
187
+ }
188
+
189
+ async readReferencedMessage(contextKey: string, messageId: string): Promise<ReferencedMessageContent> {
190
+ const outbound = this.route(contextKey).outbound;
191
+ const read = outbound.readReferencedMessage;
192
+ if (!read) throw new Error("当前消息通道不支持读取引用消息。");
193
+ return read.call(outbound, messageId);
194
+ }
195
+
168
196
  async createGroup(contextKey: string, input: CreateGroupInput): Promise<CreatedGroup> {
169
197
  const outbound = this.route(contextKey).outbound;
170
198
  const createGroup = outbound.createGroup;