aegiscode 3.1.10 → 3.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/bin/aegis.js +165 -0
  2. package/package.json +18 -86
  3. package/LICENSE +0 -21
  4. package/README.md +0 -394
  5. package/dist/main.js +0 -2171
  6. package/gui/run-gui.cjs +0 -13
  7. package/src/agent/Agent.ts +0 -903
  8. package/src/agent/SimpleAgent.ts +0 -48
  9. package/src/agent/index.ts +0 -54
  10. package/src/agent/orchestrator/AppBuilder.ts +0 -443
  11. package/src/agent/orchestrator/CouncilAgent.ts +0 -310
  12. package/src/agent/orchestrator/DiscussionRoom.ts +0 -462
  13. package/src/agent/orchestrator/OrchestratorAgent.ts +0 -637
  14. package/src/agent/orchestrator/index.ts +0 -38
  15. package/src/agent/orchestrator/utils.ts +0 -397
  16. package/src/agent/pricing.ts +0 -115
  17. package/src/agent/router.ts +0 -74
  18. package/src/agent/routerStats.ts +0 -121
  19. package/src/agent/types.ts +0 -318
  20. package/src/auth/login.ts +0 -383
  21. package/src/cli/config.ts +0 -189
  22. package/src/cli/index.ts +0 -17
  23. package/src/cli/middleware.ts +0 -119
  24. package/src/cli/types.ts +0 -75
  25. package/src/config/ConfigManager.ts +0 -587
  26. package/src/config/index.ts +0 -7
  27. package/src/config/types.ts +0 -584
  28. package/src/context/CompactionService.ts +0 -300
  29. package/src/context/ContextManager.ts +0 -450
  30. package/src/context/FileAnalyzer.ts +0 -267
  31. package/src/context/TokenCounter.ts +0 -265
  32. package/src/context/index.ts +0 -27
  33. package/src/context/storage/CacheStore.ts +0 -176
  34. package/src/context/storage/JSONLStore.ts +0 -201
  35. package/src/context/storage/MemoryStore.ts +0 -205
  36. package/src/context/storage/PersistentStore.ts +0 -327
  37. package/src/context/storage/index.ts +0 -9
  38. package/src/context/storage/pathUtils.ts +0 -114
  39. package/src/context/test.ts +0 -309
  40. package/src/context/types.ts +0 -268
  41. package/src/hooks/HookExecutor.ts +0 -434
  42. package/src/hooks/HookManager.ts +0 -596
  43. package/src/hooks/HookService.ts +0 -269
  44. package/src/hooks/Matcher.ts +0 -157
  45. package/src/hooks/index.ts +0 -63
  46. package/src/hooks/types.ts +0 -424
  47. package/src/main.tsx +0 -596
  48. package/src/mcp/HealthMonitor.ts +0 -150
  49. package/src/mcp/McpClient.ts +0 -491
  50. package/src/mcp/McpRegistry.ts +0 -321
  51. package/src/mcp/createMcpTool.ts +0 -251
  52. package/src/mcp/index.ts +0 -15
  53. package/src/mcp/server.ts +0 -334
  54. package/src/mcp/test-server.ts +0 -88
  55. package/src/mcp/test.ts +0 -372
  56. package/src/mcp/types.ts +0 -247
  57. package/src/memory/AgentMemoryBus.ts +0 -432
  58. package/src/memory/CloudSync.ts +0 -99
  59. package/src/memory/DriveSync.ts +0 -106
  60. package/src/memory/SharedMemory.ts +0 -951
  61. package/src/memory/index.ts +0 -14
  62. package/src/memory/machineFingerprint.ts +0 -40
  63. package/src/orchestrator/SubAgentMetadata.ts +0 -136
  64. package/src/prompts/builder.ts +0 -213
  65. package/src/prompts/default.ts +0 -144
  66. package/src/prompts/index.ts +0 -16
  67. package/src/prompts/plan.ts +0 -64
  68. package/src/prompts/test.ts +0 -78
  69. package/src/services/AnthropicChatService.ts +0 -341
  70. package/src/services/ChatService.ts +0 -347
  71. package/src/services/ClaudeCliChatService.ts +0 -256
  72. package/src/services/CloudSync.ts +0 -168
  73. package/src/services/CostLedger.ts +0 -211
  74. package/src/services/Heartbeat.ts +0 -135
  75. package/src/services/LearningCollector.ts +0 -291
  76. package/src/services/OllamaInstaller.ts +0 -342
  77. package/src/services/VersionChecker.ts +0 -445
  78. package/src/services/index.ts +0 -57
  79. package/src/services/streaming/OpenAIEventAdapter.ts +0 -126
  80. package/src/services/streaming/RenderingProfile.ts +0 -90
  81. package/src/services/streaming/StreamEventParser.ts +0 -181
  82. package/src/services/streaming/ThrottledRenderer.ts +0 -139
  83. package/src/services/streaming/TranscriptBuffer.ts +0 -574
  84. package/src/services/streaming/eventStatusMap.ts +0 -52
  85. package/src/services/streaming/index.ts +0 -46
  86. package/src/services/streaming/renderFormatting.ts +0 -79
  87. package/src/services/streaming/types.ts +0 -234
  88. package/src/skills/SkillLoader.ts +0 -126
  89. package/src/skills/SkillRegistry.ts +0 -366
  90. package/src/skills/index.ts +0 -48
  91. package/src/skills/types.ts +0 -146
  92. package/src/slash-commands/billing.ts +0 -70
  93. package/src/slash-commands/build.ts +0 -413
  94. package/src/slash-commands/builtinCommands.ts +0 -2733
  95. package/src/slash-commands/clone.ts +0 -242
  96. package/src/slash-commands/council.ts +0 -125
  97. package/src/slash-commands/custom/CustomCommandExecutor.ts +0 -143
  98. package/src/slash-commands/custom/CustomCommandLoader.ts +0 -251
  99. package/src/slash-commands/custom/CustomCommandRegistry.ts +0 -144
  100. package/src/slash-commands/custom/index.ts +0 -7
  101. package/src/slash-commands/debate.ts +0 -254
  102. package/src/slash-commands/gmail.ts +0 -105
  103. package/src/slash-commands/index.ts +0 -388
  104. package/src/slash-commands/mcpCommand.ts +0 -205
  105. package/src/slash-commands/types.ts +0 -201
  106. package/src/store/index.ts +0 -76
  107. package/src/store/selectors.ts +0 -246
  108. package/src/store/slices/appSlice.ts +0 -205
  109. package/src/store/slices/commandSlice.ts +0 -115
  110. package/src/store/slices/configSlice.ts +0 -46
  111. package/src/store/slices/focusSlice.ts +0 -64
  112. package/src/store/slices/index.ts +0 -9
  113. package/src/store/slices/sessionSlice.ts +0 -424
  114. package/src/store/streaming-buffer.ts +0 -425
  115. package/src/store/test.ts +0 -296
  116. package/src/store/types.ts +0 -274
  117. package/src/store/vanilla.ts +0 -186
  118. package/src/tools/builtin/bash.ts +0 -236
  119. package/src/tools/builtin/council.ts +0 -105
  120. package/src/tools/builtin/edit.ts +0 -213
  121. package/src/tools/builtin/glob.ts +0 -136
  122. package/src/tools/builtin/grep.ts +0 -263
  123. package/src/tools/builtin/index.ts +0 -61
  124. package/src/tools/builtin/memory.ts +0 -66
  125. package/src/tools/builtin/read.ts +0 -168
  126. package/src/tools/builtin/skill.ts +0 -97
  127. package/src/tools/builtin/snapshot.ts +0 -40
  128. package/src/tools/builtin/task.ts +0 -106
  129. package/src/tools/builtin/write.ts +0 -134
  130. package/src/tools/createTool.ts +0 -221
  131. package/src/tools/execution/ExecutionPipeline.ts +0 -263
  132. package/src/tools/execution/index.ts +0 -40
  133. package/src/tools/execution/stages/CacheStage.ts +0 -131
  134. package/src/tools/execution/stages/ConfirmationStage.ts +0 -203
  135. package/src/tools/execution/stages/DiscoveryStage.ts +0 -46
  136. package/src/tools/execution/stages/ExecutionStage.ts +0 -48
  137. package/src/tools/execution/stages/FormattingStage.ts +0 -44
  138. package/src/tools/execution/stages/HookStage.ts +0 -72
  139. package/src/tools/execution/stages/PermissionStage.ts +0 -287
  140. package/src/tools/execution/stages/PostHookStage.ts +0 -71
  141. package/src/tools/execution/stages/index.ts +0 -12
  142. package/src/tools/execution/test.ts +0 -266
  143. package/src/tools/execution/types.ts +0 -273
  144. package/src/tools/index.ts +0 -81
  145. package/src/tools/registry.ts +0 -304
  146. package/src/tools/schemas.ts +0 -109
  147. package/src/tools/test.ts +0 -220
  148. package/src/tools/types.ts +0 -175
  149. package/src/tools/validation/PermissionChecker.ts +0 -242
  150. package/src/tools/validation/SensitiveFileDetector.ts +0 -210
  151. package/src/tools/validation/index.ts +0 -11
  152. package/src/ui/App.tsx +0 -166
  153. package/src/ui/components/AegisInterface.tsx +0 -484
  154. package/src/ui/components/common/ChatSearch.tsx +0 -150
  155. package/src/ui/components/common/ErrorBoundary.tsx +0 -82
  156. package/src/ui/components/common/ExitMessage.tsx +0 -120
  157. package/src/ui/components/common/LoadingIndicator.tsx +0 -49
  158. package/src/ui/components/common/index.ts +0 -6
  159. package/src/ui/components/dialog/ConfirmationPrompt.tsx +0 -208
  160. package/src/ui/components/dialog/InteractiveSelector.tsx +0 -149
  161. package/src/ui/components/dialog/SetupWizard.tsx +0 -297
  162. package/src/ui/components/dialog/UpdatePrompt.tsx +0 -155
  163. package/src/ui/components/dialog/index.ts +0 -8
  164. package/src/ui/components/index.ts +0 -28
  165. package/src/ui/components/input/CommandSuggestions.tsx +0 -139
  166. package/src/ui/components/input/CustomTextInput.tsx +0 -220
  167. package/src/ui/components/input/InputArea.tsx +0 -361
  168. package/src/ui/components/input/PromptSuggestions.tsx +0 -66
  169. package/src/ui/components/input/index.ts +0 -6
  170. package/src/ui/components/layout/ChatStatusBar.tsx +0 -90
  171. package/src/ui/components/layout/ContextBar.tsx +0 -79
  172. package/src/ui/components/layout/MessageArea.tsx +0 -96
  173. package/src/ui/components/layout/MessageList.tsx +0 -647
  174. package/src/ui/components/layout/MessageSeparator.tsx +0 -26
  175. package/src/ui/components/layout/WelcomeMessage.tsx +0 -93
  176. package/src/ui/components/layout/index.ts +0 -7
  177. package/src/ui/components/markdown/CodeHighlighter.tsx +0 -292
  178. package/src/ui/components/markdown/MessageRenderer.tsx +0 -1211
  179. package/src/ui/components/markdown/index.ts +0 -8
  180. package/src/ui/components/markdown/parser.ts +0 -336
  181. package/src/ui/components/markdown/types.ts +0 -66
  182. package/src/ui/focus/FocusManager.ts +0 -137
  183. package/src/ui/focus/index.ts +0 -13
  184. package/src/ui/focus/types.ts +0 -54
  185. package/src/ui/focus/useFocus.ts +0 -75
  186. package/src/ui/hooks/index.ts +0 -11
  187. package/src/ui/hooks/useAgent.ts +0 -284
  188. package/src/ui/hooks/useCommandHistory.ts +0 -87
  189. package/src/ui/hooks/useCommandProcessor.ts +0 -443
  190. package/src/ui/hooks/useConfirmation.ts +0 -99
  191. package/src/ui/hooks/useCtrlCHandler.ts +0 -100
  192. package/src/ui/hooks/useInputBuffer.ts +0 -122
  193. package/src/ui/hooks/useTerminalSize.ts +0 -68
  194. package/src/ui/hooks/useTerminalWidth.ts +0 -5
  195. package/src/ui/hooks/useWindowedList.ts +0 -118
  196. package/src/ui/render-debugger.ts +0 -621
  197. package/src/ui/test.ts +0 -189
  198. package/src/ui/themes/ThemeManager.ts +0 -332
  199. package/src/ui/themes/aegisTheme.ts +0 -87
  200. package/src/ui/themes/darkTheme.ts +0 -87
  201. package/src/ui/themes/defaultTheme.ts +0 -85
  202. package/src/ui/themes/index.ts +0 -10
  203. package/src/ui/themes/lightTheme.ts +0 -89
  204. package/src/ui/themes/popularThemes.ts +0 -187
  205. package/src/ui/themes/types.ts +0 -130
  206. package/src/utils/clipboard.ts +0 -48
  207. package/src/utils/debug.ts +0 -43
  208. package/src/utils/environment.ts +0 -68
  209. package/src/utils/index.ts +0 -10
@@ -1,450 +0,0 @@
1
- /**
2
- *
3
- *
4
- *
5
- */
6
-
7
- import { nanoid } from 'nanoid';
8
- import * as fs from 'node:fs';
9
- import * as os from 'node:os';
10
- import * as path from 'node:path';
11
- import type {
12
- ContextData,
13
- ContextMessage,
14
- ContextManagerOptions,
15
- SystemContext,
16
- WorkspaceContext,
17
- CompactionResult,
18
- } from './types.js';
19
- import { MemoryStore, PersistentStore, CacheStore, getStorageRoot, detectGitBranch, detectGitRemote } from './storage/index.js';
20
- import { TokenCounter } from './TokenCounter.js';
21
- import { CompactionService } from './CompactionService.js';
22
-
23
- export class ContextManager {
24
- private readonly memory: MemoryStore;
25
- private readonly persistent: PersistentStore;
26
- private readonly cache: CacheStore;
27
- private readonly options: ContextManagerOptions;
28
-
29
- private currentSessionId: string | null = null;
30
- private readonly pendingSaves: Array<Promise<void>> = [];
31
-
32
- constructor(options: Partial<ContextManagerOptions> = {}) {
33
- // 默认配
34
- this.options = {
35
- storage: {
36
- maxMemorySize: 1000,
37
- persistentPath: getStorageRoot(),
38
- cacheSize: 100,
39
- compressionEnabled: true,
40
- ...options.storage,
41
- },
42
- defaultFilter: {
43
- maxTokens: 32000,
44
- maxMessages: 50,
45
- timeWindow: 24 * 60 * 60 * 1000, // 24小
46
- ...options.defaultFilter,
47
- },
48
- compressionThreshold: options.compressionThreshold || 100000, // 100k tokens
49
- };
50
-
51
- // 初始化存储
52
- this.memory = new MemoryStore(this.options.storage.maxMemorySize);
53
- this.persistent = new PersistentStore(process.cwd(), 100);
54
- this.cache = new CacheStore(this.options.storage.cacheSize, 5 * 60 * 1000);
55
- }
56
-
57
- /**
58
- *
59
- */
60
- async createSession(
61
- userId?: string,
62
- preferences: Record<string, unknown> = {},
63
- configuration: Record<string, unknown> = {}
64
- ): Promise<string> {
65
- // 使用 nanoid 生成会话 ID,或使用提供
66
- const sessionId = (configuration.sessionId as string) || nanoid();
67
- const now = Date.now();
68
-
69
- // 创建初始上下
70
- const contextData: ContextData = {
71
- layers: {
72
- system: await this.createSystemContext(),
73
- session: {
74
- sessionId,
75
- userId,
76
- preferences,
77
- configuration,
78
- startTime: now,
79
- },
80
- conversation: {
81
- messages: [],
82
- topics: [],
83
- lastActivity: now,
84
- },
85
- tool: {
86
- recentCalls: [],
87
- toolStates: {},
88
- dependencies: {},
89
- },
90
- workspace: await this.createWorkspaceContext(),
91
- },
92
- metadata: {
93
- totalTokens: 0,
94
- priority: 1,
95
- lastUpdated: now,
96
- },
97
- };
98
-
99
- // 存储到内
100
- this.memory.setContext(contextData);
101
-
102
- this.currentSessionId = sessionId;
103
- return sessionId;
104
- }
105
-
106
- /**
107
- *
108
- */
109
- private async createSystemContext(): Promise<SystemContext> {
110
- return {
111
- osType: os.type(),
112
- osVersion: os.release(),
113
- shell: process.env.SHELL || 'unknown',
114
- nodeVersion: process.version,
115
- cwd: process.cwd(),
116
- };
117
- }
118
-
119
- /**
120
- *
121
- */
122
- private async createWorkspaceContext(): Promise<WorkspaceContext> {
123
- const projectPath = process.cwd();
124
-
125
- // 尝试读
126
- let packageJson: WorkspaceContext['packageJson'];
127
- try {
128
- const { readFile } = await import('node:fs/promises');
129
- const { join } = await import('node:path');
130
- const content = await readFile(join(projectPath, 'package.json'), 'utf-8');
131
- const pkg = JSON.parse(content);
132
- packageJson = {
133
- name: pkg.name,
134
- version: pkg.version,
135
- dependencies: pkg.dependencies,
136
- };
137
- } catch {
138
- // 忽略错
139
- }
140
-
141
- return {
142
- projectPath,
143
- gitBranch: detectGitBranch(projectPath),
144
- gitRemote: detectGitRemote(projectPath),
145
- packageJson,
146
- };
147
- }
148
-
149
- /**
150
- *
151
- */
152
- async addMessage(
153
- role: ContextMessage['role'],
154
- content: string,
155
- metadata?: Record<string, unknown>
156
- ): Promise<void> {
157
- if (!this.currentSessionId) {
158
- throw new Error('没有活动会话');
159
- }
160
-
161
- const message: ContextMessage = {
162
- id: nanoid(),
163
- role,
164
- content,
165
- timestamp: Date.now(),
166
- metadata,
167
- };
168
-
169
- // 添加到内
170
- this.memory.addMessage(message);
171
-
172
- // 检查是否需要压
173
- const contextData = this.memory.getContext();
174
- if (contextData && this.shouldCompress(contextData)) {
175
- await this.compressCurrentContext();
176
- }
177
-
178
- // 持久化保存到 JSONL 文件
179
- await this.saveMessagePersist(message);
180
- }
181
-
182
- /**
183
- *
184
- */
185
- private shouldCompress(contextData: ContextData): boolean {
186
- return contextData.metadata.totalTokens > this.options.compressionThreshold;
187
- }
188
-
189
- /**
190
- * Persist message to JSONL synchronously (awaited by the caller).
191
- * The promise is tracked so cleanup() can flush before exit.
192
- */
193
- private async saveMessagePersist(message: ContextMessage): Promise<void> {
194
- if (!this.currentSessionId) return;
195
- const promise = this.persistent.saveMessage(
196
- this.currentSessionId!,
197
- message.role as 'user' | 'assistant' | 'system',
198
- message.content,
199
- null,
200
- message.metadata as any
201
- ).catch(error => {
202
- console.error('[ContextManager] 保存消息失败:', error);
203
- });
204
- this.pendingSaves.push(promise as Promise<void>);
205
- await promise;
206
- }
207
-
208
- /**
209
- * Flush all pending saves — call before exit to ensure no data loss.
210
- */
211
- async flush(): Promise<void> {
212
- const pending = [...this.pendingSaves];
213
- this.pendingSaves.length = 0;
214
- await Promise.all(pending);
215
- }
216
-
217
- /**
218
- *
219
- */
220
- async compressCurrentContext(): Promise<CompactionResult | null> {
221
- const contextData = this.memory.getContext();
222
- if (!contextData) {
223
- return null;
224
- }
225
-
226
- const messages = contextData.layers.conversation.messages.map(m => ({
227
- role: m.role as 'user' | 'assistant' | 'system' | 'tool',
228
- content: m.content,
229
- }));
230
-
231
- const result = await CompactionService.compact(messages, {
232
- trigger: 'auto',
233
- modelName: (() => {
234
- try {
235
- const cfg = JSON.parse(fs.readFileSync(path.join(os.homedir(), '.aegiscode', 'config.json'), 'utf8'));
236
- return cfg?.default?.model || 'claude-sonnet-4-6';
237
- } catch { return 'claude-sonnet-4-6'; }
238
- })(),
239
- maxContextTokens: this.options.compressionThreshold,
240
- });
241
-
242
- if (result.success) {
243
- // 更新内存中的消
244
- const newMessages: ContextMessage[] = result.compactedMessages.map(m => ({
245
- id: nanoid(),
246
- role: m.role as ContextMessage['role'],
247
- content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
248
- timestamp: Date.now(),
249
- }));
250
-
251
- this.memory.setMessages(newMessages);
252
- this.memory.updateTokenCount(result.postTokens);
253
-
254
- // 保存压缩记
255
- if (this.currentSessionId) {
256
- await this.persistent.saveCompaction(
257
- this.currentSessionId,
258
- result.summary,
259
- {
260
- trigger: 'auto',
261
- preTokens: result.preTokens,
262
- postTokens: result.postTokens,
263
- filesIncluded: result.filesIncluded,
264
- }
265
- );
266
- }
267
- }
268
-
269
- return result;
270
- }
271
-
272
- /**
273
- *
274
- */
275
- async manualCompact(): Promise<CompactionResult | null> {
276
- const contextData = this.memory.getContext();
277
- if (!contextData) {
278
- return null;
279
- }
280
-
281
- const messages = contextData.layers.conversation.messages.map(m => ({
282
- role: m.role as 'user' | 'assistant' | 'system' | 'tool',
283
- content: m.content,
284
- }));
285
-
286
- const result = await CompactionService.compact(messages, {
287
- trigger: 'manual',
288
- modelName: 'claude-sonnet-4-6',
289
- maxContextTokens: this.options.compressionThreshold,
290
- });
291
-
292
- if (result.success) {
293
- const newMessages: ContextMessage[] = result.compactedMessages.map(m => ({
294
- id: nanoid(),
295
- role: m.role as ContextMessage['role'],
296
- content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
297
- timestamp: Date.now(),
298
- }));
299
-
300
- this.memory.setMessages(newMessages);
301
- this.memory.updateTokenCount(result.postTokens);
302
-
303
- if (this.currentSessionId) {
304
- await this.persistent.saveCompaction(
305
- this.currentSessionId,
306
- result.summary,
307
- {
308
- trigger: 'manual',
309
- preTokens: result.preTokens,
310
- postTokens: result.postTokens,
311
- filesIncluded: result.filesIncluded,
312
- }
313
- );
314
- }
315
- }
316
-
317
- return result;
318
- }
319
-
320
- /**
321
- *
322
- */
323
- async loadSession(sessionId: string): Promise<boolean> {
324
- try {
325
- // 先尝试从内存加
326
- let contextData = this.memory.getContext();
327
-
328
- if (!contextData || contextData.layers.session.sessionId !== sessionId) {
329
- // 从持久化存储加
330
- const [session, conversation] = await Promise.all([
331
- this.persistent.loadSession(sessionId),
332
- this.persistent.loadConversation(sessionId),
333
- ]);
334
-
335
- if (!session || !conversation) {
336
- return false;
337
- }
338
-
339
- // 重建完整的上下文数
340
- contextData = {
341
- layers: {
342
- system: await this.createSystemContext(),
343
- session,
344
- conversation,
345
- tool: { recentCalls: [], toolStates: {}, dependencies: {} },
346
- workspace: await this.createWorkspaceContext(),
347
- },
348
- metadata: {
349
- totalTokens: 0,
350
- priority: 1,
351
- lastUpdated: Date.now(),
352
- },
353
- };
354
-
355
- this.memory.setContext(contextData);
356
- }
357
-
358
- this.currentSessionId = sessionId;
359
- return true;
360
- } catch (error) {
361
- console.error('[ContextManager] 加载会话失败:', error);
362
- return false;
363
- }
364
- }
365
-
366
- /**
367
- *
368
- */
369
- getCurrentSessionId(): string | null {
370
- return this.currentSessionId;
371
- }
372
-
373
- /**
374
- *
375
- */
376
- getContext(): ContextData | null {
377
- return this.memory.getContext();
378
- }
379
-
380
- /**
381
- *
382
- */
383
- getMessages(): ContextMessage[] {
384
- return this.memory.getMessages();
385
- }
386
-
387
- /**
388
- *
389
- */
390
- getTokenCount(): number {
391
- return this.memory.getTokenCount();
392
- }
393
-
394
- /**
395
- *
396
- */
397
- updateTokenCount(tokens: number): void {
398
- this.memory.updateTokenCount(tokens);
399
- }
400
-
401
- /**
402
- *
403
- */
404
- replaceMessages(messages: ContextMessage[]): void {
405
- this.memory.setMessages(messages);
406
- }
407
-
408
- /**
409
- *
410
- */
411
- getCache<T>(key: string): T | undefined {
412
- return this.cache.get<T>(key);
413
- }
414
-
415
- /**
416
- *
417
- */
418
- setCache<T>(key: string, value: T, ttl?: number): void {
419
- this.cache.set(key, value, ttl);
420
- }
421
-
422
- /**
423
- *
424
- */
425
- async listSessions(): Promise<string[]> {
426
- return this.persistent.listSessions();
427
- }
428
-
429
- /**
430
- *
431
- */
432
- async deleteSession(sessionId: string): Promise<void> {
433
- await this.persistent.deleteSession(sessionId);
434
-
435
- if (this.currentSessionId === sessionId) {
436
- this.memory.clear();
437
- this.currentSessionId = null;
438
- }
439
- }
440
-
441
- /**
442
- *
443
- */
444
- async cleanup(): Promise<void> {
445
- await this.flush();
446
- this.memory.clear();
447
- this.cache.clear();
448
- TokenCounter.clearCache();
449
- }
450
- }
@@ -1,267 +0,0 @@
1
- /**
2
- *
3
- *
4
- *
5
- */
6
-
7
- import * as fs from 'node:fs/promises';
8
- import { existsSync } from 'node:fs';
9
- import * as path from 'node:path';
10
- import type { Message } from '../agent/types.js';
11
- import type { FileReference, FileContent } from './types.js';
12
-
13
- export class FileAnalyzer {
14
- /** 最多包含的文件数量 */
15
- private static readonly MAX_FILES = 5;
16
- /** 单个文件最大行数 */
17
- private static readonly MAX_LINES_PER_FILE = 1000;
18
- /** 单个文件最大字符数 */
19
- private static readonly MAX_CHARS_PER_FILE = 50000;
20
-
21
- /**
22
- *
23
- */
24
- static analyzeFiles(messages: Message[]): FileReference[] {
25
- const fileMap = new Map<string, FileReference>();
26
-
27
- messages.forEach((msg, index) => {
28
- // 从消息内容中提取文件路
29
- if (msg.content) {
30
- const content = typeof msg.content === 'string'
31
- ? msg.content
32
- : JSON.stringify(msg.content);
33
- const contentFiles = this.extractFilePathsFromContent(content);
34
- contentFiles.forEach(filePath => {
35
- this.updateFileReference(fileMap, filePath, index, false);
36
- });
37
- }
38
-
39
- // 从工具调用中提取文件路
40
- if (msg.tool_calls && Array.isArray(msg.tool_calls)) {
41
- for (const call of msg.tool_calls) {
42
- const toolFiles = this.extractFilePathsFromToolCall(call);
43
- const wasModified = ['Write', 'Edit'].includes(call.function?.name || '');
44
- toolFiles.forEach(filePath => {
45
- this.updateFileReference(fileMap, filePath, index, wasModified);
46
- });
47
- }
48
- }
49
- });
50
-
51
- // 按重要性排序:1. 是否被修改 2. 提及次数 3. 最近
52
- return Array.from(fileMap.values())
53
- .filter(ref => this.isValidFilePath(ref.path))
54
- .sort((a, b) => {
55
- if (a.wasModified !== b.wasModified) return a.wasModified ? -1 : 1;
56
- if (a.mentions !== b.mentions) return b.mentions - a.mentions;
57
- return b.lastMentioned - a.lastMentioned;
58
- })
59
- .slice(0, this.MAX_FILES);
60
- }
61
-
62
- /**
63
- *
64
- */
65
- private static extractFilePathsFromContent(content: string): string[] {
66
- const paths: string[] = [];
67
-
68
- // 匹配常见的文件路径模
69
- const patterns = [
70
- // 绝对路
71
- /(?:^|\s|["'`])(\/?(?:[\w.-]+\/)+[\w.-]+\.[a-zA-Z]{1,10})(?:\s|$|["'`]|:)/gm,
72
- // 相对路
73
- /(?:^|\s|["'`])(\.\/(?:[\w.-]+\/)*[\w.-]+\.[a-zA-Z]{1,10})(?:\s|$|["'`]|:)/gm,
74
- // 代码块中的文件路
75
- /```\d+:\d+:([\w./-]+)/gm,
76
- ];
77
-
78
- for (const pattern of patterns) {
79
- let match;
80
- while ((match = pattern.exec(content)) !== null) {
81
- const filePath = match[1];
82
- if (filePath && !paths.includes(filePath)) {
83
- paths.push(filePath);
84
- }
85
- }
86
- }
87
-
88
- return paths;
89
- }
90
-
91
- /**
92
- *
93
- */
94
- private static extractFilePathsFromToolCall(
95
- toolCall: { function?: { name?: string; arguments?: string } }
96
- ): string[] {
97
- const paths: string[] = [];
98
-
99
- const functionName = toolCall.function?.name;
100
- let args: Record<string, unknown> = {};
101
-
102
- try {
103
- if (typeof toolCall.function?.arguments === 'string') {
104
- args = JSON.parse(toolCall.function.arguments);
105
- } else if (toolCall.function?.arguments) {
106
- args = toolCall.function.arguments as Record<string, unknown>;
107
- }
108
- } catch {
109
- return paths;
110
- }
111
-
112
- // 文件操作工
113
- const fileTools = ['Read', 'Write', 'Edit', 'Glob', 'Grep', 'NotebookEdit'];
114
-
115
- if (fileTools.includes(functionName || '')) {
116
- const pathKeys = ['file_path', 'path', 'notebook_path', 'filePath'];
117
- for (const key of pathKeys) {
118
- if (args[key] && typeof args[key] === 'string') {
119
- paths.push(args[key] as string);
120
- }
121
- }
122
- }
123
-
124
- return paths;
125
- }
126
-
127
- /**
128
- *
129
- */
130
- private static updateFileReference(
131
- fileMap: Map<string, FileReference>,
132
- filePath: string,
133
- messageIndex: number,
134
- wasModified: boolean
135
- ): void {
136
- const existing = fileMap.get(filePath);
137
-
138
- if (existing) {
139
- existing.mentions++;
140
- existing.lastMentioned = Math.max(existing.lastMentioned, messageIndex);
141
- existing.wasModified = existing.wasModified || wasModified;
142
- } else {
143
- fileMap.set(filePath, {
144
- path: filePath,
145
- mentions: 1,
146
- lastMentioned: messageIndex,
147
- wasModified,
148
- });
149
- }
150
- }
151
-
152
- /**
153
- *
154
- */
155
- private static isValidFilePath(filePath: string): boolean {
156
- // 排除常见的非文件路
157
- const excludePatterns = [
158
- /^https?:\/\//, // URL
159
- /^node_modules\//, // node_modules
160
- /^\.git\//, // git 目
161
- /\.(png|jpg|jpeg|gif|svg|ico|webp|mp4|mp3|wav|pdf|zip|tar|gz)$/i, // 二进制文
162
- ];
163
-
164
- for (const pattern of excludePatterns) {
165
- if (pattern.test(filePath)) {
166
- return false;
167
- }
168
- }
169
-
170
- // 检查文件是否存
171
- try {
172
- const absolutePath = path.isAbsolute(filePath)
173
- ? filePath
174
- : path.join(process.cwd(), filePath);
175
- return existsSync(absolutePath);
176
- } catch {
177
- return false;
178
- }
179
- }
180
-
181
- /**
182
- *
183
- */
184
- static async readFilesContent(filePaths: string[]): Promise<FileContent[]> {
185
- const results: FileContent[] = [];
186
-
187
- for (const filePath of filePaths) {
188
- try {
189
- const absolutePath = path.isAbsolute(filePath)
190
- ? filePath
191
- : path.join(process.cwd(), filePath);
192
-
193
- if (!existsSync(absolutePath)) {
194
- continue;
195
- }
196
-
197
- const content = await fs.readFile(absolutePath, 'utf-8');
198
- const lines = content.split('\n');
199
-
200
- let truncated = false;
201
- let finalContent = content;
202
-
203
- // 检查行数限
204
- if (lines.length > this.MAX_LINES_PER_FILE) {
205
- finalContent = lines.slice(0, this.MAX_LINES_PER_FILE).join('\n');
206
- truncated = true;
207
- }
208
-
209
- // 检查字符数限
210
- if (finalContent.length > this.MAX_CHARS_PER_FILE) {
211
- finalContent = finalContent.substring(0, this.MAX_CHARS_PER_FILE);
212
- truncated = true;
213
- }
214
-
215
- if (truncated) {
216
- finalContent += '\n\n[... 内容已截断 ...]';
217
- }
218
-
219
- results.push({
220
- path: filePath,
221
- content: finalContent,
222
- lines: lines.length,
223
- truncated,
224
- });
225
- } catch (error) {
226
- console.warn(`[FileAnalyzer] 读取文件失败: ${filePath}`, error);
227
- }
228
- }
229
-
230
- return results;
231
- }
232
-
233
- /**
234
- *
235
- */
236
- static async getFileSummary(filePath: string): Promise<string | null> {
237
- try {
238
- const absolutePath = path.isAbsolute(filePath)
239
- ? filePath
240
- : path.join(process.cwd(), filePath);
241
-
242
- if (!existsSync(absolutePath)) {
243
- return null;
244
- }
245
-
246
- const stats = await fs.stat(absolutePath);
247
- const content = await fs.readFile(absolutePath, 'utf-8');
248
- const lines = content.split('\n');
249
-
250
- return `文件: ${filePath}
251
- 大小: ${this.formatFileSize(stats.size)}
252
- 行数: ${lines.length}
253
- 最后修改: ${stats.mtime.toISOString()}`;
254
- } catch {
255
- return null;
256
- }
257
- }
258
-
259
- /**
260
- *
261
- */
262
- private static formatFileSize(bytes: number): string {
263
- if (bytes < 1024) return `${bytes} B`;
264
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
265
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
266
- }
267
- }