flashclaw 1.0.0

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 (138) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +305 -0
  3. package/config/plugins.json +23 -0
  4. package/dist/agent-runner.d.ts +103 -0
  5. package/dist/agent-runner.d.ts.map +1 -0
  6. package/dist/agent-runner.js +530 -0
  7. package/dist/agent-runner.js.map +1 -0
  8. package/dist/cli.d.ts +7 -0
  9. package/dist/cli.d.ts.map +1 -0
  10. package/dist/cli.js +497 -0
  11. package/dist/cli.js.map +1 -0
  12. package/dist/commands.d.ts +68 -0
  13. package/dist/commands.d.ts.map +1 -0
  14. package/dist/commands.js +252 -0
  15. package/dist/commands.js.map +1 -0
  16. package/dist/config-schema.d.ts +21 -0
  17. package/dist/config-schema.d.ts.map +1 -0
  18. package/dist/config-schema.js +26 -0
  19. package/dist/config-schema.js.map +1 -0
  20. package/dist/config.d.ts +11 -0
  21. package/dist/config.d.ts.map +1 -0
  22. package/dist/config.js +36 -0
  23. package/dist/config.js.map +1 -0
  24. package/dist/core/api-client.d.ts +236 -0
  25. package/dist/core/api-client.d.ts.map +1 -0
  26. package/dist/core/api-client.js +369 -0
  27. package/dist/core/api-client.js.map +1 -0
  28. package/dist/core/memory.d.ts +291 -0
  29. package/dist/core/memory.d.ts.map +1 -0
  30. package/dist/core/memory.js +754 -0
  31. package/dist/core/memory.js.map +1 -0
  32. package/dist/core/model-capabilities.d.ts +45 -0
  33. package/dist/core/model-capabilities.d.ts.map +1 -0
  34. package/dist/core/model-capabilities.js +85 -0
  35. package/dist/core/model-capabilities.js.map +1 -0
  36. package/dist/db.d.ts +103 -0
  37. package/dist/db.d.ts.map +1 -0
  38. package/dist/db.js +380 -0
  39. package/dist/db.js.map +1 -0
  40. package/dist/errors.d.ts +22 -0
  41. package/dist/errors.d.ts.map +1 -0
  42. package/dist/errors.js +44 -0
  43. package/dist/errors.js.map +1 -0
  44. package/dist/health.d.ts +27 -0
  45. package/dist/health.d.ts.map +1 -0
  46. package/dist/health.js +55 -0
  47. package/dist/health.js.map +1 -0
  48. package/dist/index.d.ts +11 -0
  49. package/dist/index.d.ts.map +1 -0
  50. package/dist/index.js +1181 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/logger.d.ts +9 -0
  53. package/dist/logger.d.ts.map +1 -0
  54. package/dist/logger.js +19 -0
  55. package/dist/logger.js.map +1 -0
  56. package/dist/message-queue.d.ts +69 -0
  57. package/dist/message-queue.d.ts.map +1 -0
  58. package/dist/message-queue.js +198 -0
  59. package/dist/message-queue.js.map +1 -0
  60. package/dist/metrics.d.ts +46 -0
  61. package/dist/metrics.d.ts.map +1 -0
  62. package/dist/metrics.js +101 -0
  63. package/dist/metrics.js.map +1 -0
  64. package/dist/paths.d.ts +81 -0
  65. package/dist/paths.d.ts.map +1 -0
  66. package/dist/paths.js +127 -0
  67. package/dist/paths.js.map +1 -0
  68. package/dist/plugins/index.d.ts +9 -0
  69. package/dist/plugins/index.d.ts.map +1 -0
  70. package/dist/plugins/index.js +13 -0
  71. package/dist/plugins/index.js.map +1 -0
  72. package/dist/plugins/installer.d.ts +120 -0
  73. package/dist/plugins/installer.d.ts.map +1 -0
  74. package/dist/plugins/installer.js +1008 -0
  75. package/dist/plugins/installer.js.map +1 -0
  76. package/dist/plugins/loader.d.ts +37 -0
  77. package/dist/plugins/loader.d.ts.map +1 -0
  78. package/dist/plugins/loader.js +429 -0
  79. package/dist/plugins/loader.js.map +1 -0
  80. package/dist/plugins/manager.d.ts +72 -0
  81. package/dist/plugins/manager.d.ts.map +1 -0
  82. package/dist/plugins/manager.js +187 -0
  83. package/dist/plugins/manager.js.map +1 -0
  84. package/dist/plugins/types.d.ts +101 -0
  85. package/dist/plugins/types.d.ts.map +1 -0
  86. package/dist/plugins/types.js +12 -0
  87. package/dist/plugins/types.js.map +1 -0
  88. package/dist/session-tracker.d.ts +81 -0
  89. package/dist/session-tracker.d.ts.map +1 -0
  90. package/dist/session-tracker.js +228 -0
  91. package/dist/session-tracker.js.map +1 -0
  92. package/dist/task-scheduler.d.ts +47 -0
  93. package/dist/task-scheduler.d.ts.map +1 -0
  94. package/dist/task-scheduler.js +331 -0
  95. package/dist/task-scheduler.js.map +1 -0
  96. package/dist/types.d.ts +57 -0
  97. package/dist/types.d.ts.map +1 -0
  98. package/dist/types.js +2 -0
  99. package/dist/types.js.map +1 -0
  100. package/dist/utils/env-substitute.d.ts +63 -0
  101. package/dist/utils/env-substitute.d.ts.map +1 -0
  102. package/dist/utils/env-substitute.js +133 -0
  103. package/dist/utils/env-substitute.js.map +1 -0
  104. package/dist/utils/log-rotate.d.ts +19 -0
  105. package/dist/utils/log-rotate.d.ts.map +1 -0
  106. package/dist/utils/log-rotate.js +85 -0
  107. package/dist/utils/log-rotate.js.map +1 -0
  108. package/dist/utils/rate-limiter.d.ts +38 -0
  109. package/dist/utils/rate-limiter.d.ts.map +1 -0
  110. package/dist/utils/rate-limiter.js +79 -0
  111. package/dist/utils/rate-limiter.js.map +1 -0
  112. package/dist/utils/retry.d.ts +10 -0
  113. package/dist/utils/retry.d.ts.map +1 -0
  114. package/dist/utils/retry.js +47 -0
  115. package/dist/utils/retry.js.map +1 -0
  116. package/dist/utils.d.ts +86 -0
  117. package/dist/utils.d.ts.map +1 -0
  118. package/dist/utils.js +218 -0
  119. package/dist/utils.js.map +1 -0
  120. package/package.json +78 -0
  121. package/plugins/cancel-task/index.ts +161 -0
  122. package/plugins/cancel-task/plugin.json +9 -0
  123. package/plugins/feishu/index.ts +944 -0
  124. package/plugins/feishu/plugin.json +29 -0
  125. package/plugins/list-tasks/index.ts +150 -0
  126. package/plugins/list-tasks/plugin.json +9 -0
  127. package/plugins/memory/index.ts +190 -0
  128. package/plugins/memory/plugin.json +7 -0
  129. package/plugins/pause-task/index.ts +95 -0
  130. package/plugins/pause-task/plugin.json +8 -0
  131. package/plugins/register-group/index.ts +147 -0
  132. package/plugins/register-group/plugin.json +7 -0
  133. package/plugins/resume-task/index.ts +92 -0
  134. package/plugins/resume-task/plugin.json +8 -0
  135. package/plugins/schedule-task/index.ts +248 -0
  136. package/plugins/schedule-task/plugin.json +9 -0
  137. package/plugins/send-message/index.ts +75 -0
  138. package/plugins/send-message/plugin.json +9 -0
@@ -0,0 +1,187 @@
1
+ /**
2
+ * FlashClaw 插件管理器
3
+ * 负责插件的注册、卸载和查询
4
+ */
5
+ import { isToolPlugin, isChannelPlugin, } from './types.js';
6
+ import { createLogger } from '../logger.js';
7
+ const logger = createLogger('PluginManager');
8
+ /**
9
+ * 插件管理器
10
+ * 管理所有已加载的插件
11
+ */
12
+ export class PluginManager {
13
+ // 插件注册表:name -> PluginEntry
14
+ plugins = new Map();
15
+ /**
16
+ * 注册插件
17
+ * @param plugin 插件实例
18
+ * @returns 是否注册成功
19
+ */
20
+ register(plugin) {
21
+ const name = plugin.name;
22
+ // 检查是否已存在
23
+ if (this.plugins.has(name)) {
24
+ logger.warn({ plugin: name }, '插件已存在,跳过注册');
25
+ return false;
26
+ }
27
+ // 确定插件类型
28
+ const type = isToolPlugin(plugin) ? 'tool' : 'channel';
29
+ // 注册
30
+ this.plugins.set(name, {
31
+ plugin,
32
+ type,
33
+ loadedAt: new Date(),
34
+ });
35
+ logger.info({ plugin: name, type, version: plugin.version }, '⚡ 已注册插件');
36
+ return true;
37
+ }
38
+ /**
39
+ * 卸载插件
40
+ * @param name 插件名称
41
+ * @returns 是否卸载成功
42
+ */
43
+ async unregister(name) {
44
+ const entry = this.plugins.get(name);
45
+ if (!entry) {
46
+ logger.warn({ plugin: name }, '插件不存在');
47
+ return false;
48
+ }
49
+ // 如果是渠道插件,先停止
50
+ if (isChannelPlugin(entry.plugin)) {
51
+ try {
52
+ await entry.plugin.stop();
53
+ }
54
+ catch (err) {
55
+ logger.error({ plugin: name, err }, '停止渠道插件失败');
56
+ }
57
+ }
58
+ this.plugins.delete(name);
59
+ logger.info({ plugin: name }, '⚡ 已卸载插件');
60
+ return true;
61
+ }
62
+ /**
63
+ * 获取所有工具的 Schema
64
+ * 用于传递给 AI Agent
65
+ */
66
+ getActiveTools() {
67
+ const schemas = [];
68
+ for (const entry of this.plugins.values()) {
69
+ if (entry.type === 'tool' && isToolPlugin(entry.plugin)) {
70
+ // 支持多工具插件(tools 数组)
71
+ if (entry.plugin.tools && Array.isArray(entry.plugin.tools)) {
72
+ schemas.push(...entry.plugin.tools);
73
+ }
74
+ else if (entry.plugin.schema) {
75
+ // 单工具插件
76
+ schemas.push(entry.plugin.schema);
77
+ }
78
+ }
79
+ }
80
+ return schemas;
81
+ }
82
+ /**
83
+ * 获取所有渠道插件
84
+ */
85
+ getActiveChannels() {
86
+ const channels = [];
87
+ for (const entry of this.plugins.values()) {
88
+ if (entry.type === 'channel' && isChannelPlugin(entry.plugin)) {
89
+ channels.push(entry.plugin);
90
+ }
91
+ }
92
+ return channels;
93
+ }
94
+ /**
95
+ * 获取指定工具插件
96
+ * @param toolName 工具名称
97
+ * @returns 插件和是否为多工具模式
98
+ */
99
+ getTool(toolName) {
100
+ // 1. 先按插件名称查找(单工具模式:插件名 = 工具名)
101
+ const entry = this.plugins.get(toolName);
102
+ if (entry && entry.type === 'tool' && isToolPlugin(entry.plugin)) {
103
+ return { plugin: entry.plugin, isMultiTool: false };
104
+ }
105
+ // 2. 再在所有工具插件的 tools 数组中查找(多工具模式)
106
+ for (const pluginEntry of this.plugins.values()) {
107
+ if (pluginEntry.type === 'tool' && isToolPlugin(pluginEntry.plugin)) {
108
+ const plugin = pluginEntry.plugin;
109
+ if (plugin.tools && Array.isArray(plugin.tools)) {
110
+ const found = plugin.tools.some(t => t.name === toolName);
111
+ if (found) {
112
+ return { plugin, isMultiTool: true };
113
+ }
114
+ }
115
+ }
116
+ }
117
+ return null;
118
+ }
119
+ /**
120
+ * 获取指定渠道插件
121
+ * @param name 渠道名称
122
+ */
123
+ getChannel(name) {
124
+ const entry = this.plugins.get(name);
125
+ if (entry && entry.type === 'channel' && isChannelPlugin(entry.plugin)) {
126
+ return entry.plugin;
127
+ }
128
+ return null;
129
+ }
130
+ /**
131
+ * 获取所有已注册的插件名称
132
+ */
133
+ getPluginNames() {
134
+ return Array.from(this.plugins.keys());
135
+ }
136
+ /**
137
+ * 获取插件数量统计
138
+ */
139
+ getStats() {
140
+ let tools = 0;
141
+ let channels = 0;
142
+ for (const entry of this.plugins.values()) {
143
+ if (entry.type === 'tool')
144
+ tools++;
145
+ else
146
+ channels++;
147
+ }
148
+ return { total: this.plugins.size, tools, channels };
149
+ }
150
+ /**
151
+ * 清空所有插件
152
+ */
153
+ async clear() {
154
+ // 先停止所有渠道
155
+ for (const entry of this.plugins.values()) {
156
+ if (isChannelPlugin(entry.plugin)) {
157
+ await entry.plugin.stop().catch(() => { });
158
+ }
159
+ }
160
+ this.plugins.clear();
161
+ logger.info('⚡ 已清空所有插件');
162
+ }
163
+ /**
164
+ * 停止所有渠道插件(不清空注册)
165
+ */
166
+ async stopAll() {
167
+ const promises = [];
168
+ for (const entry of this.plugins.values()) {
169
+ if (isChannelPlugin(entry.plugin)) {
170
+ promises.push(entry.plugin.stop().catch((err) => {
171
+ logger.warn({ plugin: entry.plugin.name, err }, '停止插件失败');
172
+ }));
173
+ }
174
+ }
175
+ await Promise.all(promises);
176
+ logger.info('⚡ 所有渠道插件已停止');
177
+ }
178
+ }
179
+ function getPluginManager() {
180
+ if (!global.__flashclaw_plugin_manager) {
181
+ global.__flashclaw_plugin_manager = new PluginManager();
182
+ }
183
+ return global.__flashclaw_plugin_manager;
184
+ }
185
+ // 导出单例(通过全局变量)
186
+ export const pluginManager = getPluginManager();
187
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/plugins/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * FlashClaw 插件类型定义
3
+ * 乐高式架构 - 放进去就能用
4
+ */
5
+ export interface PluginConfig {
6
+ [key: string]: unknown;
7
+ }
8
+ export interface ToolContext {
9
+ chatId: string;
10
+ groupId: string;
11
+ userId: string;
12
+ sendMessage: (content: string) => Promise<void>;
13
+ }
14
+ export interface ToolResult {
15
+ success: boolean;
16
+ data?: unknown;
17
+ error?: string;
18
+ }
19
+ export interface Attachment {
20
+ type: 'image' | 'video' | 'audio' | 'file';
21
+ content?: string;
22
+ mimeType?: string;
23
+ fileName?: string;
24
+ fileKey?: string;
25
+ }
26
+ export interface Message {
27
+ id: string;
28
+ chatId: string;
29
+ senderId: string;
30
+ senderName: string;
31
+ content: string;
32
+ timestamp: string;
33
+ chatType: 'p2p' | 'group';
34
+ platform: string;
35
+ attachments?: Attachment[];
36
+ mentions?: string[];
37
+ replyToMessageId?: string;
38
+ }
39
+ export type MessageHandler = (message: Message) => Promise<void>;
40
+ export interface ToolSchema {
41
+ name: string;
42
+ description: string;
43
+ input_schema: {
44
+ type: 'object';
45
+ properties: Record<string, unknown>;
46
+ required?: string[];
47
+ };
48
+ }
49
+ export interface PluginManifest {
50
+ name: string;
51
+ version: string;
52
+ type: 'tool' | 'channel';
53
+ description: string;
54
+ author?: string;
55
+ main: string;
56
+ config?: Record<string, {
57
+ type: string;
58
+ required?: boolean;
59
+ env?: string;
60
+ default?: unknown;
61
+ }>;
62
+ dependencies?: string[];
63
+ }
64
+ export interface ToolPlugin {
65
+ name: string;
66
+ version: string;
67
+ description: string;
68
+ schema?: ToolSchema;
69
+ tools?: ToolSchema[];
70
+ init?(config: PluginConfig): Promise<void>;
71
+ execute(paramsOrToolName: unknown, contextOrParams?: ToolContext | unknown, context?: ToolContext): Promise<ToolResult>;
72
+ reload?(): Promise<void>;
73
+ cleanup?(): Promise<void>;
74
+ }
75
+ export interface SendMessageOptions {
76
+ placeholderMessageId?: string;
77
+ attachments?: Attachment[];
78
+ }
79
+ export interface SendMessageResult {
80
+ messageId?: string;
81
+ success: boolean;
82
+ error?: string;
83
+ }
84
+ export interface ChannelPlugin {
85
+ name: string;
86
+ version: string;
87
+ init(config: PluginConfig): Promise<void>;
88
+ start(): Promise<void>;
89
+ stop(): Promise<void>;
90
+ onMessage(handler: MessageHandler): void;
91
+ sendMessage(chatId: string, content: string, options?: SendMessageOptions): Promise<SendMessageResult>;
92
+ updateMessage?(messageId: string, content: string): Promise<void>;
93
+ deleteMessage?(messageId: string): Promise<void>;
94
+ sendImage?(chatId: string, imageData: string | Buffer, caption?: string): Promise<SendMessageResult>;
95
+ sendFile?(chatId: string, filePath: string, fileName?: string): Promise<SendMessageResult>;
96
+ reload?(): Promise<void>;
97
+ }
98
+ export type Plugin = ToolPlugin | ChannelPlugin;
99
+ export declare function isToolPlugin(plugin: Plugin): plugin is ToolPlugin;
100
+ export declare function isChannelPlugin(plugin: Plugin): plugin is ChannelPlugin;
101
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/plugins/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * FlashClaw 插件类型定义
3
+ * 乐高式架构 - 放进去就能用
4
+ */
5
+ // 类型守卫
6
+ export function isToolPlugin(plugin) {
7
+ return ('schema' in plugin || 'tools' in plugin) && 'execute' in plugin;
8
+ }
9
+ export function isChannelPlugin(plugin) {
10
+ return 'onMessage' in plugin && 'sendMessage' in plugin;
11
+ }
12
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/plugins/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAwIH,OAAO;AACP,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO,CAAC,QAAQ,IAAI,MAAM,IAAI,OAAO,IAAI,MAAM,CAAC,IAAI,SAAS,IAAI,MAAM,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,OAAO,WAAW,IAAI,MAAM,IAAI,aAAa,IAAI,MAAM,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Session Tracker
3
+ *
4
+ * 追踪每个会话的 token 使用量和状态
5
+ */
6
+ /**
7
+ * 会话统计数据
8
+ */
9
+ export interface SessionData {
10
+ /** 会话 ID (chatId) */
11
+ chatId: string;
12
+ /** 消息数量 */
13
+ messageCount: number;
14
+ /** 累计输入 token */
15
+ inputTokens: number;
16
+ /** 累计输出 token */
17
+ outputTokens: number;
18
+ /** 总 token 数 */
19
+ totalTokens: number;
20
+ /** 使用的模型 */
21
+ model: string;
22
+ /** 会话开始时间 */
23
+ startedAt: string;
24
+ /** 最后活动时间 */
25
+ lastActivityAt: string;
26
+ /** 是否已提示过压缩 */
27
+ compactSuggested: boolean;
28
+ }
29
+ /**
30
+ * Token 使用情况
31
+ */
32
+ export interface TokenUsage {
33
+ inputTokens: number;
34
+ outputTokens: number;
35
+ }
36
+ /**
37
+ * 获取或创建会话数据
38
+ */
39
+ export declare function getOrCreateSession(chatId: string, model?: string): SessionData;
40
+ /**
41
+ * 获取会话数据(不创建)
42
+ */
43
+ export declare function getSession(chatId: string): SessionData | null;
44
+ /**
45
+ * 记录 token 使用
46
+ */
47
+ export declare function recordTokenUsage(chatId: string, usage: TokenUsage, model?: string): SessionData;
48
+ /**
49
+ * 获取模型的上下文窗口大小
50
+ */
51
+ export declare function getContextWindowSize(model?: string): number;
52
+ /**
53
+ * 检查是否需要提示压缩
54
+ *
55
+ * @returns 如果需要提示返回使用率百分比,否则返回 null
56
+ */
57
+ export declare function checkCompactThreshold(chatId: string): number | null;
58
+ /**
59
+ * 重置会话
60
+ */
61
+ export declare function resetSession(chatId: string): void;
62
+ /**
63
+ * 获取会话统计(用于 /status 命令)
64
+ */
65
+ export declare function getSessionStats(chatId: string): {
66
+ messageCount: number;
67
+ tokenCount: number;
68
+ maxTokens: number;
69
+ model: string;
70
+ startedAt: string;
71
+ usagePercent: number;
72
+ } | null;
73
+ /**
74
+ * 获取所有活跃会话数量
75
+ */
76
+ export declare function getActiveSessionCount(): number;
77
+ /**
78
+ * 清理过期会话(超过 24 小时无活动)
79
+ */
80
+ export declare function cleanupStaleSessions(maxAgeMs?: number): number;
81
+ //# sourceMappingURL=session-tracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-tracker.d.ts","sourceRoot":"","sources":["../src/session-tracker.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,qBAAqB;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,aAAa;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa;IACb,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe;IACf,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAyDD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,CAqB9E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAE7D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,WAAW,CA8B/F;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAsB3D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiBnE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAIjD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG;IAC/C,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,IAAI,CAiBP;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,GAAE,MAA4B,GAAG,MAAM,CAkBnF"}
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Session Tracker
3
+ *
4
+ * 追踪每个会话的 token 使用量和状态
5
+ */
6
+ import pino from 'pino';
7
+ import { existsSync, readFileSync, statSync } from 'fs';
8
+ import { promises as fs } from 'fs';
9
+ import { join } from 'path';
10
+ import { getFlashClawHome } from './paths.js';
11
+ const logger = pino({
12
+ level: process.env.LOG_LEVEL || 'info',
13
+ transport: { target: 'pino-pretty', options: { colorize: true } }
14
+ });
15
+ // 内存存储 - 按 chatId 存储会话数据
16
+ const sessions = new Map();
17
+ const SESSION_CACHE_PATH = join(getFlashClawHome(), 'cache', 'session-tracker.json');
18
+ const MAX_SESSION_CACHE_BYTES = 10 * 1024 * 1024;
19
+ let persistTimer = null;
20
+ function loadSessionsFromDisk() {
21
+ try {
22
+ if (!existsSync(SESSION_CACHE_PATH))
23
+ return;
24
+ const stat = statSync(SESSION_CACHE_PATH);
25
+ if (stat.size > MAX_SESSION_CACHE_BYTES) {
26
+ logger.warn({ size: stat.size }, '📊 会话追踪缓存文件过大,跳过加载');
27
+ return;
28
+ }
29
+ const content = readFileSync(SESSION_CACHE_PATH, 'utf-8');
30
+ const parsed = JSON.parse(content);
31
+ if (!Array.isArray(parsed))
32
+ return;
33
+ for (const item of parsed) {
34
+ if (item && typeof item.chatId === 'string') {
35
+ sessions.set(item.chatId, item);
36
+ }
37
+ }
38
+ logger.debug({ count: sessions.size }, '📊 会话追踪缓存已加载');
39
+ }
40
+ catch (error) {
41
+ logger.warn({ error }, '📊 加载会话追踪缓存失败');
42
+ }
43
+ }
44
+ async function persistSessions() {
45
+ try {
46
+ const cacheDir = join(getFlashClawHome(), 'cache');
47
+ await fs.mkdir(cacheDir, { recursive: true });
48
+ const payload = JSON.stringify(Array.from(sessions.values()), null, 2);
49
+ await fs.writeFile(SESSION_CACHE_PATH, payload, 'utf-8');
50
+ }
51
+ catch (error) {
52
+ logger.warn({ error }, '📊 保存会话追踪缓存失败');
53
+ }
54
+ }
55
+ function schedulePersist() {
56
+ if (persistTimer)
57
+ return;
58
+ persistTimer = setTimeout(() => {
59
+ persistTimer = null;
60
+ void persistSessions();
61
+ }, 1000);
62
+ persistTimer.unref?.();
63
+ }
64
+ // 默认上下文窗口大小(Claude 3.5 Sonnet = 200k)
65
+ const DEFAULT_CONTEXT_WINDOW = 200000;
66
+ // 压缩提示阈值(70%)
67
+ const COMPACT_THRESHOLD = 0.7;
68
+ /**
69
+ * 获取或创建会话数据
70
+ */
71
+ export function getOrCreateSession(chatId, model) {
72
+ let session = sessions.get(chatId);
73
+ if (!session) {
74
+ const now = new Date().toISOString();
75
+ session = {
76
+ chatId,
77
+ messageCount: 0,
78
+ inputTokens: 0,
79
+ outputTokens: 0,
80
+ totalTokens: 0,
81
+ model: model || process.env.AI_MODEL || 'claude-4-5-sonnet-20250929',
82
+ startedAt: now,
83
+ lastActivityAt: now,
84
+ compactSuggested: false
85
+ };
86
+ sessions.set(chatId, session);
87
+ logger.debug({ chatId }, '📊 新建会话追踪');
88
+ }
89
+ return session;
90
+ }
91
+ /**
92
+ * 获取会话数据(不创建)
93
+ */
94
+ export function getSession(chatId) {
95
+ return sessions.get(chatId) || null;
96
+ }
97
+ /**
98
+ * 记录 token 使用
99
+ */
100
+ export function recordTokenUsage(chatId, usage, model) {
101
+ const session = getOrCreateSession(chatId, model);
102
+ const inputTokens = Number.isFinite(usage.inputTokens) && usage.inputTokens >= 0 ? usage.inputTokens : 0;
103
+ const outputTokens = Number.isFinite(usage.outputTokens) && usage.outputTokens >= 0 ? usage.outputTokens : 0;
104
+ if (inputTokens !== usage.inputTokens || outputTokens !== usage.outputTokens) {
105
+ logger.warn({ chatId, usage }, '📊 发现无效 token 数据,已忽略');
106
+ }
107
+ session.messageCount += 1;
108
+ session.inputTokens += inputTokens;
109
+ session.outputTokens += outputTokens;
110
+ session.totalTokens = session.inputTokens + session.outputTokens;
111
+ session.lastActivityAt = new Date().toISOString();
112
+ if (model) {
113
+ session.model = model;
114
+ }
115
+ logger.debug({
116
+ chatId,
117
+ inputTokens,
118
+ outputTokens,
119
+ totalTokens: session.totalTokens
120
+ }, '📊 Token 使用已记录');
121
+ schedulePersist();
122
+ return session;
123
+ }
124
+ /**
125
+ * 获取模型的上下文窗口大小
126
+ */
127
+ export function getContextWindowSize(model) {
128
+ // Claude 模型的上下文窗口
129
+ const contextWindows = {
130
+ 'claude-4-5-sonnet-20250929': 200000,
131
+ 'claude-3-5-sonnet-20241022': 200000,
132
+ 'claude-3-opus-20240229': 200000,
133
+ 'claude-3-sonnet-20240229': 200000,
134
+ 'claude-3-haiku-20240307': 200000,
135
+ };
136
+ // 匹配模型名称(支持部分匹配)
137
+ if (!model) {
138
+ return DEFAULT_CONTEXT_WINDOW;
139
+ }
140
+ for (const [key, value] of Object.entries(contextWindows)) {
141
+ if (model.includes(key) || key.includes(model)) {
142
+ return value;
143
+ }
144
+ }
145
+ return DEFAULT_CONTEXT_WINDOW;
146
+ }
147
+ /**
148
+ * 检查是否需要提示压缩
149
+ *
150
+ * @returns 如果需要提示返回使用率百分比,否则返回 null
151
+ */
152
+ export function checkCompactThreshold(chatId) {
153
+ const session = sessions.get(chatId);
154
+ if (!session)
155
+ return null;
156
+ // 已经提示过了
157
+ if (session.compactSuggested)
158
+ return null;
159
+ const maxTokens = getContextWindowSize(session.model);
160
+ if (!Number.isFinite(maxTokens) || maxTokens <= 0)
161
+ return null;
162
+ const usageRate = session.totalTokens / maxTokens;
163
+ if (usageRate >= COMPACT_THRESHOLD) {
164
+ session.compactSuggested = true;
165
+ return Math.round(usageRate * 100);
166
+ }
167
+ return null;
168
+ }
169
+ /**
170
+ * 重置会话
171
+ */
172
+ export function resetSession(chatId) {
173
+ sessions.delete(chatId);
174
+ schedulePersist();
175
+ logger.debug({ chatId }, '📊 会话追踪已重置');
176
+ }
177
+ /**
178
+ * 获取会话统计(用于 /status 命令)
179
+ */
180
+ export function getSessionStats(chatId) {
181
+ const session = sessions.get(chatId);
182
+ if (!session)
183
+ return null;
184
+ const maxTokens = getContextWindowSize(session.model);
185
+ const usagePercent = maxTokens > 0
186
+ ? Math.round((session.totalTokens / maxTokens) * 100)
187
+ : 0;
188
+ return {
189
+ messageCount: session.messageCount,
190
+ tokenCount: session.totalTokens,
191
+ maxTokens,
192
+ model: session.model,
193
+ startedAt: session.startedAt,
194
+ usagePercent
195
+ };
196
+ }
197
+ /**
198
+ * 获取所有活跃会话数量
199
+ */
200
+ export function getActiveSessionCount() {
201
+ return sessions.size;
202
+ }
203
+ /**
204
+ * 清理过期会话(超过 24 小时无活动)
205
+ */
206
+ export function cleanupStaleSessions(maxAgeMs = 24 * 60 * 60 * 1000) {
207
+ const now = Date.now();
208
+ let cleaned = 0;
209
+ for (const [chatId, session] of sessions) {
210
+ const lastActivity = new Date(session.lastActivityAt).getTime();
211
+ if (now - lastActivity > maxAgeMs) {
212
+ sessions.delete(chatId);
213
+ cleaned++;
214
+ }
215
+ }
216
+ if (cleaned > 0) {
217
+ logger.info({ cleaned }, '📊 清理过期会话');
218
+ schedulePersist();
219
+ }
220
+ return cleaned;
221
+ }
222
+ // 初始化:加载缓存并定期清理
223
+ loadSessionsFromDisk();
224
+ const cleanupTimer = setInterval(() => {
225
+ cleanupStaleSessions();
226
+ }, 60 * 60 * 1000);
227
+ cleanupTimer.unref?.();
228
+ //# sourceMappingURL=session-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-tracker.js","sourceRoot":"","sources":["../src/session-tracker.ts"],"names":[],"mappings":"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"}