aegiscode 3.1.8 → 3.1.10

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 (206) hide show
  1. package/README.md +23 -15
  2. package/dist/main.js +549 -552
  3. package/package.json +4 -2
  4. package/src/agent/Agent.ts +903 -0
  5. package/src/agent/SimpleAgent.ts +48 -0
  6. package/src/agent/index.ts +54 -0
  7. package/src/agent/orchestrator/AppBuilder.ts +443 -0
  8. package/src/agent/orchestrator/CouncilAgent.ts +310 -0
  9. package/src/agent/orchestrator/DiscussionRoom.ts +462 -0
  10. package/src/agent/orchestrator/OrchestratorAgent.ts +637 -0
  11. package/src/agent/orchestrator/index.ts +38 -0
  12. package/src/agent/orchestrator/utils.ts +397 -0
  13. package/src/agent/pricing.ts +115 -0
  14. package/src/agent/router.ts +74 -0
  15. package/src/agent/routerStats.ts +121 -0
  16. package/src/agent/types.ts +318 -0
  17. package/src/auth/login.ts +383 -0
  18. package/src/cli/config.ts +189 -0
  19. package/src/cli/index.ts +17 -0
  20. package/src/cli/middleware.ts +119 -0
  21. package/src/cli/types.ts +75 -0
  22. package/src/config/ConfigManager.ts +587 -0
  23. package/src/config/index.ts +7 -0
  24. package/src/config/types.ts +584 -0
  25. package/src/context/CompactionService.ts +300 -0
  26. package/src/context/ContextManager.ts +450 -0
  27. package/src/context/FileAnalyzer.ts +267 -0
  28. package/src/context/TokenCounter.ts +265 -0
  29. package/src/context/index.ts +27 -0
  30. package/src/context/storage/CacheStore.ts +176 -0
  31. package/src/context/storage/JSONLStore.ts +201 -0
  32. package/src/context/storage/MemoryStore.ts +205 -0
  33. package/src/context/storage/PersistentStore.ts +327 -0
  34. package/src/context/storage/index.ts +9 -0
  35. package/src/context/storage/pathUtils.ts +114 -0
  36. package/src/context/test.ts +309 -0
  37. package/src/context/types.ts +268 -0
  38. package/src/hooks/HookExecutor.ts +434 -0
  39. package/src/hooks/HookManager.ts +596 -0
  40. package/src/hooks/HookService.ts +269 -0
  41. package/src/hooks/Matcher.ts +157 -0
  42. package/src/hooks/index.ts +63 -0
  43. package/src/hooks/types.ts +424 -0
  44. package/src/main.tsx +596 -0
  45. package/src/mcp/HealthMonitor.ts +150 -0
  46. package/src/mcp/McpClient.ts +491 -0
  47. package/src/mcp/McpRegistry.ts +321 -0
  48. package/src/mcp/createMcpTool.ts +251 -0
  49. package/src/mcp/index.ts +15 -0
  50. package/src/mcp/server.ts +334 -0
  51. package/src/mcp/test-server.ts +88 -0
  52. package/src/mcp/test.ts +372 -0
  53. package/src/mcp/types.ts +247 -0
  54. package/src/memory/AgentMemoryBus.ts +432 -0
  55. package/src/memory/CloudSync.ts +99 -0
  56. package/src/memory/DriveSync.ts +106 -0
  57. package/src/memory/SharedMemory.ts +951 -0
  58. package/src/memory/index.ts +14 -0
  59. package/src/memory/machineFingerprint.ts +40 -0
  60. package/src/orchestrator/SubAgentMetadata.ts +136 -0
  61. package/src/prompts/builder.ts +213 -0
  62. package/src/prompts/default.ts +144 -0
  63. package/src/prompts/index.ts +16 -0
  64. package/src/prompts/plan.ts +64 -0
  65. package/src/prompts/test.ts +78 -0
  66. package/src/services/AnthropicChatService.ts +341 -0
  67. package/src/services/ChatService.ts +347 -0
  68. package/src/services/ClaudeCliChatService.ts +256 -0
  69. package/src/services/CloudSync.ts +168 -0
  70. package/src/services/CostLedger.ts +211 -0
  71. package/src/services/Heartbeat.ts +135 -0
  72. package/src/services/LearningCollector.ts +291 -0
  73. package/src/services/OllamaInstaller.ts +342 -0
  74. package/src/services/VersionChecker.ts +445 -0
  75. package/src/services/index.ts +57 -0
  76. package/src/services/streaming/OpenAIEventAdapter.ts +126 -0
  77. package/src/services/streaming/RenderingProfile.ts +90 -0
  78. package/src/services/streaming/StreamEventParser.ts +181 -0
  79. package/src/services/streaming/ThrottledRenderer.ts +139 -0
  80. package/src/services/streaming/TranscriptBuffer.ts +574 -0
  81. package/src/services/streaming/eventStatusMap.ts +52 -0
  82. package/src/services/streaming/index.ts +46 -0
  83. package/src/services/streaming/renderFormatting.ts +79 -0
  84. package/src/services/streaming/types.ts +234 -0
  85. package/src/skills/SkillLoader.ts +126 -0
  86. package/src/skills/SkillRegistry.ts +366 -0
  87. package/src/skills/index.ts +48 -0
  88. package/src/skills/types.ts +146 -0
  89. package/src/slash-commands/billing.ts +70 -0
  90. package/src/slash-commands/build.ts +413 -0
  91. package/src/slash-commands/builtinCommands.ts +2733 -0
  92. package/src/slash-commands/clone.ts +242 -0
  93. package/src/slash-commands/council.ts +125 -0
  94. package/src/slash-commands/custom/CustomCommandExecutor.ts +143 -0
  95. package/src/slash-commands/custom/CustomCommandLoader.ts +251 -0
  96. package/src/slash-commands/custom/CustomCommandRegistry.ts +144 -0
  97. package/src/slash-commands/custom/index.ts +7 -0
  98. package/src/slash-commands/debate.ts +254 -0
  99. package/src/slash-commands/gmail.ts +105 -0
  100. package/src/slash-commands/index.ts +388 -0
  101. package/src/slash-commands/mcpCommand.ts +205 -0
  102. package/src/slash-commands/types.ts +201 -0
  103. package/src/store/index.ts +76 -0
  104. package/src/store/selectors.ts +246 -0
  105. package/src/store/slices/appSlice.ts +205 -0
  106. package/src/store/slices/commandSlice.ts +115 -0
  107. package/src/store/slices/configSlice.ts +46 -0
  108. package/src/store/slices/focusSlice.ts +64 -0
  109. package/src/store/slices/index.ts +9 -0
  110. package/src/store/slices/sessionSlice.ts +424 -0
  111. package/src/store/streaming-buffer.ts +425 -0
  112. package/src/store/test.ts +296 -0
  113. package/src/store/types.ts +274 -0
  114. package/src/store/vanilla.ts +186 -0
  115. package/src/tools/builtin/bash.ts +236 -0
  116. package/src/tools/builtin/council.ts +105 -0
  117. package/src/tools/builtin/edit.ts +213 -0
  118. package/src/tools/builtin/glob.ts +136 -0
  119. package/src/tools/builtin/grep.ts +263 -0
  120. package/src/tools/builtin/index.ts +61 -0
  121. package/src/tools/builtin/memory.ts +66 -0
  122. package/src/tools/builtin/read.ts +168 -0
  123. package/src/tools/builtin/skill.ts +97 -0
  124. package/src/tools/builtin/snapshot.ts +40 -0
  125. package/src/tools/builtin/task.ts +106 -0
  126. package/src/tools/builtin/write.ts +134 -0
  127. package/src/tools/createTool.ts +221 -0
  128. package/src/tools/execution/ExecutionPipeline.ts +263 -0
  129. package/src/tools/execution/index.ts +40 -0
  130. package/src/tools/execution/stages/CacheStage.ts +131 -0
  131. package/src/tools/execution/stages/ConfirmationStage.ts +203 -0
  132. package/src/tools/execution/stages/DiscoveryStage.ts +46 -0
  133. package/src/tools/execution/stages/ExecutionStage.ts +48 -0
  134. package/src/tools/execution/stages/FormattingStage.ts +44 -0
  135. package/src/tools/execution/stages/HookStage.ts +72 -0
  136. package/src/tools/execution/stages/PermissionStage.ts +287 -0
  137. package/src/tools/execution/stages/PostHookStage.ts +71 -0
  138. package/src/tools/execution/stages/index.ts +12 -0
  139. package/src/tools/execution/test.ts +266 -0
  140. package/src/tools/execution/types.ts +273 -0
  141. package/src/tools/index.ts +81 -0
  142. package/src/tools/registry.ts +304 -0
  143. package/src/tools/schemas.ts +109 -0
  144. package/src/tools/test.ts +220 -0
  145. package/src/tools/types.ts +175 -0
  146. package/src/tools/validation/PermissionChecker.ts +242 -0
  147. package/src/tools/validation/SensitiveFileDetector.ts +210 -0
  148. package/src/tools/validation/index.ts +11 -0
  149. package/src/ui/App.tsx +166 -0
  150. package/src/ui/components/AegisInterface.tsx +484 -0
  151. package/src/ui/components/common/ChatSearch.tsx +150 -0
  152. package/src/ui/components/common/ErrorBoundary.tsx +82 -0
  153. package/src/ui/components/common/ExitMessage.tsx +120 -0
  154. package/src/ui/components/common/LoadingIndicator.tsx +49 -0
  155. package/src/ui/components/common/index.ts +6 -0
  156. package/src/ui/components/dialog/ConfirmationPrompt.tsx +208 -0
  157. package/src/ui/components/dialog/InteractiveSelector.tsx +149 -0
  158. package/src/ui/components/dialog/SetupWizard.tsx +297 -0
  159. package/src/ui/components/dialog/UpdatePrompt.tsx +155 -0
  160. package/src/ui/components/dialog/index.ts +8 -0
  161. package/src/ui/components/index.ts +28 -0
  162. package/src/ui/components/input/CommandSuggestions.tsx +139 -0
  163. package/src/ui/components/input/CustomTextInput.tsx +220 -0
  164. package/src/ui/components/input/InputArea.tsx +361 -0
  165. package/src/ui/components/input/PromptSuggestions.tsx +66 -0
  166. package/src/ui/components/input/index.ts +6 -0
  167. package/src/ui/components/layout/ChatStatusBar.tsx +90 -0
  168. package/src/ui/components/layout/ContextBar.tsx +79 -0
  169. package/src/ui/components/layout/MessageArea.tsx +96 -0
  170. package/src/ui/components/layout/MessageList.tsx +647 -0
  171. package/src/ui/components/layout/MessageSeparator.tsx +26 -0
  172. package/src/ui/components/layout/WelcomeMessage.tsx +93 -0
  173. package/src/ui/components/layout/index.ts +7 -0
  174. package/src/ui/components/markdown/CodeHighlighter.tsx +292 -0
  175. package/src/ui/components/markdown/MessageRenderer.tsx +1211 -0
  176. package/src/ui/components/markdown/index.ts +8 -0
  177. package/src/ui/components/markdown/parser.ts +336 -0
  178. package/src/ui/components/markdown/types.ts +66 -0
  179. package/src/ui/focus/FocusManager.ts +137 -0
  180. package/src/ui/focus/index.ts +13 -0
  181. package/src/ui/focus/types.ts +54 -0
  182. package/src/ui/focus/useFocus.ts +75 -0
  183. package/src/ui/hooks/index.ts +11 -0
  184. package/src/ui/hooks/useAgent.ts +284 -0
  185. package/src/ui/hooks/useCommandHistory.ts +87 -0
  186. package/src/ui/hooks/useCommandProcessor.ts +443 -0
  187. package/src/ui/hooks/useConfirmation.ts +99 -0
  188. package/src/ui/hooks/useCtrlCHandler.ts +100 -0
  189. package/src/ui/hooks/useInputBuffer.ts +122 -0
  190. package/src/ui/hooks/useTerminalSize.ts +68 -0
  191. package/src/ui/hooks/useTerminalWidth.ts +5 -0
  192. package/src/ui/hooks/useWindowedList.ts +118 -0
  193. package/src/ui/render-debugger.ts +621 -0
  194. package/src/ui/test.ts +189 -0
  195. package/src/ui/themes/ThemeManager.ts +332 -0
  196. package/src/ui/themes/aegisTheme.ts +87 -0
  197. package/src/ui/themes/darkTheme.ts +87 -0
  198. package/src/ui/themes/defaultTheme.ts +85 -0
  199. package/src/ui/themes/index.ts +10 -0
  200. package/src/ui/themes/lightTheme.ts +89 -0
  201. package/src/ui/themes/popularThemes.ts +187 -0
  202. package/src/ui/themes/types.ts +130 -0
  203. package/src/utils/clipboard.ts +48 -0
  204. package/src/utils/debug.ts +43 -0
  205. package/src/utils/environment.ts +68 -0
  206. package/src/utils/index.ts +10 -0
@@ -0,0 +1,242 @@
1
+ /**
2
+ *
3
+ *
4
+ */
5
+
6
+ import { minimatch } from 'minimatch';
7
+ import {
8
+ PermissionResult,
9
+ type PermissionCheckResult,
10
+ type PermissionConfig,
11
+ type ToolInvocationDescriptor,
12
+ } from '../execution/types.js';
13
+
14
+ /**
15
+ *
16
+ */
17
+ export const DEFAULT_PERMISSION_CONFIG: PermissionConfig = {
18
+ allow: [
19
+ // 只读工具默认允
20
+ 'Read(**/*)',
21
+ 'Glob(**/*)',
22
+ 'Grep(**/*)',
23
+ ],
24
+ deny: [
25
+ // 危险命令默认拒
26
+ 'Bash(rm -rf:*)',
27
+ 'Bash(sudo:*)',
28
+ 'Write(/etc/*)',
29
+ 'Write(/usr/*)',
30
+ 'Write(/System/*)',
31
+ ],
32
+ ask: [],
33
+ };
34
+
35
+ /**
36
+ *
37
+ */
38
+ export class PermissionChecker {
39
+ private config: PermissionConfig;
40
+
41
+ constructor(config?: Partial<PermissionConfig>) {
42
+ this.config = {
43
+ allow: [...DEFAULT_PERMISSION_CONFIG.allow, ...(config?.allow || [])],
44
+ deny: [...DEFAULT_PERMISSION_CONFIG.deny, ...(config?.deny || [])],
45
+ ask: [...DEFAULT_PERMISSION_CONFIG.ask, ...(config?.ask || [])],
46
+ };
47
+ }
48
+
49
+ /**
50
+ *
51
+ */
52
+ check(descriptor: ToolInvocationDescriptor): PermissionCheckResult {
53
+ const signature = PermissionChecker.buildSignature(descriptor);
54
+
55
+ // 1. 检查 deny 规则(优先级最
56
+ for (const rule of this.config.deny) {
57
+ if (this.matchesRule(signature, rule, descriptor)) {
58
+ return {
59
+ result: PermissionResult.DENY,
60
+ matchedRule: rule,
61
+ reason: `Not executed: rule "${rule}" excludes this action. Choose a different approach.`,
62
+ };
63
+ }
64
+ }
65
+
66
+ // 2. 检查 allow 规
67
+ for (const rule of this.config.allow) {
68
+ if (this.matchesRule(signature, rule, descriptor)) {
69
+ return {
70
+ result: PermissionResult.ALLOW,
71
+ matchedRule: rule,
72
+ reason: `Allowed by rule: ${rule}`,
73
+ };
74
+ }
75
+ }
76
+
77
+ // 3. 检查 ask 规
78
+ for (const rule of this.config.ask) {
79
+ if (this.matchesRule(signature, rule, descriptor)) {
80
+ return {
81
+ result: PermissionResult.ASK,
82
+ matchedRule: rule,
83
+ reason: `Requires confirmation by rule: ${rule}`,
84
+ };
85
+ }
86
+ }
87
+
88
+ // 4. 默
89
+ return {
90
+ result: PermissionResult.ASK,
91
+ matchedRule: 'default',
92
+ reason: 'No matching rule, requires confirmation',
93
+ };
94
+ }
95
+
96
+ /**
97
+ *
98
+ */
99
+ static buildSignature(descriptor: ToolInvocationDescriptor): string {
100
+ const { toolName, params, tool } = descriptor;
101
+
102
+ // 使用工具的 extractSignatureContent 方法(如果存
103
+ if (tool?.extractSignatureContent) {
104
+ const content = tool.extractSignatureContent(params);
105
+ return `${toolName}(${content})`;
106
+ }
107
+
108
+ // 如果没有工具对象,尝试从常见参数提取签名内
109
+ const signatureContent = PermissionChecker.extractDefaultSignatureContent(toolName, params);
110
+ if (signatureContent) {
111
+ return `${toolName}(${signatureContent})`;
112
+ }
113
+
114
+ // 默认:只返回工具
115
+ return toolName;
116
+ }
117
+
118
+ /**
119
+ *
120
+ */
121
+ private static extractDefaultSignatureContent(
122
+ toolName: string,
123
+ params: Record<string, unknown>
124
+ ): string | null {
125
+ switch (toolName) {
126
+ case 'Bash':
127
+ if (typeof params.command === 'string') {
128
+ return params.command;
129
+ }
130
+ break;
131
+ case 'Read':
132
+ case 'Write':
133
+ case 'Edit':
134
+ if (typeof params.file_path === 'string') {
135
+ return params.file_path;
136
+ }
137
+ break;
138
+ case 'Glob':
139
+ if (typeof params.pattern === 'string') {
140
+ return params.pattern;
141
+ }
142
+ break;
143
+ case 'Grep':
144
+ if (typeof params.pattern === 'string') {
145
+ return params.pattern;
146
+ }
147
+ break;
148
+ }
149
+ return null;
150
+ }
151
+
152
+ /**
153
+ *
154
+ */
155
+ private matchesRule(
156
+ signature: string,
157
+ rule: string,
158
+ descriptor: ToolInvocationDescriptor
159
+ ): boolean {
160
+ // 1. 精确匹配工具
161
+ if (rule === descriptor.toolName) {
162
+ return true;
163
+ }
164
+
165
+ // 2. 解析规
166
+ const match = rule.match(/^(\w+)(?:\((.+)\))?$/);
167
+ if (!match) {
168
+ return false;
169
+ }
170
+
171
+ const [, ruleTool, rulePattern] = match;
172
+
173
+ // 工具名不匹
174
+ if (ruleTool !== descriptor.toolName) {
175
+ return false;
176
+ }
177
+
178
+ // 没有参数模式,匹配所有该工具的调
179
+ if (!rulePattern) {
180
+ return true;
181
+ }
182
+
183
+ // 3. 提取签名内
184
+ const signatureContent = this.extractSignatureContent(signature);
185
+
186
+ // 4. 匹配模
187
+ return this.matchPattern(signatureContent, rulePattern);
188
+ }
189
+
190
+ /**
191
+ *
192
+ */
193
+ private extractSignatureContent(signature: string): string {
194
+ const match = signature.match(/^\w+\((.+)\)$/);
195
+ return match ? match[1] : '';
196
+ }
197
+
198
+ /**
199
+ *
200
+ */
201
+ private matchPattern(content: string, pattern: string): boolean {
202
+ // 1. 前缀通配符 (npm:*
203
+ if (pattern.endsWith(':*')) {
204
+ const prefix = pattern.slice(0, -2);
205
+ return content.startsWith(prefix);
206
+ }
207
+
208
+ // 2. Glob 模
209
+ if (pattern.includes('*') || pattern.includes('?')) {
210
+ return minimatch(content, pattern, { dot: true });
211
+ }
212
+
213
+ // 3. 精确匹
214
+ return content === pattern;
215
+ }
216
+
217
+ /**
218
+ *
219
+ */
220
+ addRule(type: 'allow' | 'deny' | 'ask', rule: string): void {
221
+ this.config[type].push(rule);
222
+ }
223
+
224
+ /**
225
+ *
226
+ */
227
+ removeRule(type: 'allow' | 'deny' | 'ask', rule: string): boolean {
228
+ const index = this.config[type].indexOf(rule);
229
+ if (index !== -1) {
230
+ this.config[type].splice(index, 1);
231
+ return true;
232
+ }
233
+ return false;
234
+ }
235
+
236
+ /**
237
+ *
238
+ */
239
+ getConfig(): PermissionConfig {
240
+ return { ...this.config };
241
+ }
242
+ }
@@ -0,0 +1,210 @@
1
+ /**
2
+ *
3
+ *
4
+ */
5
+
6
+ // ========== 敏感级
7
+
8
+ /**
9
+ *
10
+ */
11
+ export enum SensitivityLevel {
12
+ /** 低敏感:配置文件 */
13
+ LOW = 'low',
14
+ /** 中敏感:数据库、日志 */
15
+ MEDIUM = 'medium',
16
+ /** 高敏感:密钥、凭证 */
17
+ HIGH = 'high',
18
+ }
19
+
20
+ // ========== 检测结
21
+
22
+ /**
23
+ *
24
+ */
25
+ export interface SensitivityResult {
26
+ sensitive: boolean;
27
+ level?: SensitivityLevel;
28
+ reason?: string;
29
+ }
30
+
31
+ /**
32
+ *
33
+ */
34
+ export interface SensitivityResultWithPath {
35
+ path: string;
36
+ result: SensitivityResult;
37
+ }
38
+
39
+ // ========== 敏感规
40
+
41
+ /**
42
+ *
43
+ */
44
+ interface SensitiveRule {
45
+ pattern: RegExp;
46
+ level: SensitivityLevel;
47
+ reason: string;
48
+ }
49
+
50
+ // ========== 检测
51
+
52
+ /**
53
+ *
54
+ */
55
+ export class SensitiveFileDetector {
56
+ /**
57
+ *
58
+ */
59
+ private static readonly SENSITIVE_PATTERNS: SensitiveRule[] = [
60
+ // ========== 高敏
61
+ // 环境变
62
+ { pattern: /\.env$/, level: SensitivityLevel.HIGH, reason: '环境变量文件可能包含密钥' },
63
+ { pattern: /\.env\.(local|development|production|test)$/, level: SensitivityLevel.HIGH, reason: '环境变量文件可能包含密钥' },
64
+
65
+ // 凭证文
66
+ { pattern: /credentials?\.json$/, level: SensitivityLevel.HIGH, reason: '凭证文件' },
67
+ { pattern: /secrets?\.json$/, level: SensitivityLevel.HIGH, reason: '密钥文件' },
68
+ { pattern: /\.credentials$/, level: SensitivityLevel.HIGH, reason: '凭证文件' },
69
+
70
+ // 密钥文
71
+ { pattern: /\.pem$/, level: SensitivityLevel.HIGH, reason: '私钥/证书文件' },
72
+ { pattern: /\.key$/, level: SensitivityLevel.HIGH, reason: '密钥文件' },
73
+ { pattern: /\.p12$/, level: SensitivityLevel.HIGH, reason: 'PKCS12 证书文件' },
74
+ { pattern: /\.pfx$/, level: SensitivityLevel.HIGH, reason: 'PFX 证书文件' },
75
+
76
+ // SSH 密
77
+ { pattern: /id_rsa/, level: SensitivityLevel.HIGH, reason: 'SSH RSA 私钥' },
78
+ { pattern: /id_ed25519/, level: SensitivityLevel.HIGH, reason: 'SSH Ed25519 私钥' },
79
+ { pattern: /id_ecdsa/, level: SensitivityLevel.HIGH, reason: 'SSH ECDSA 私钥' },
80
+ { pattern: /id_dsa/, level: SensitivityLevel.HIGH, reason: 'SSH DSA 私钥' },
81
+
82
+ // AWS
83
+ { pattern: /\.aws\/credentials$/, level: SensitivityLevel.HIGH, reason: 'AWS 凭证文件' },
84
+
85
+ // 其
86
+ { pattern: /\.htpasswd$/, level: SensitivityLevel.HIGH, reason: 'HTTP 密码文件' },
87
+ { pattern: /\.netrc$/, level: SensitivityLevel.HIGH, reason: '网络凭证文件' },
88
+
89
+ // ========== 中敏
90
+ // 数据
91
+ { pattern: /\.sqlite3?$/, level: SensitivityLevel.MEDIUM, reason: 'SQLite 数据库文件' },
92
+ { pattern: /\.db$/, level: SensitivityLevel.MEDIUM, reason: '数据库文件' },
93
+
94
+ // 日
95
+ { pattern: /\.log$/, level: SensitivityLevel.MEDIUM, reason: '日志文件可能包含敏感信息' },
96
+
97
+ // 历史记
98
+ { pattern: /\.bash_history$/, level: SensitivityLevel.MEDIUM, reason: 'Bash 历史记录' },
99
+ { pattern: /\.zsh_history$/, level: SensitivityLevel.MEDIUM, reason: 'Zsh 历史记录' },
100
+
101
+ // 其他配
102
+ { pattern: /\.npmrc$/, level: SensitivityLevel.MEDIUM, reason: 'npm 配置可能包含 token' },
103
+ { pattern: /\.pypirc$/, level: SensitivityLevel.MEDIUM, reason: 'PyPI 配置可能包含 token' },
104
+
105
+ // ========== 低敏
106
+ // 配置文
107
+ { pattern: /config\.json$/, level: SensitivityLevel.LOW, reason: '配置文件' },
108
+ { pattern: /settings\.json$/, level: SensitivityLevel.LOW, reason: '设置文件' },
109
+ { pattern: /\.gitconfig$/, level: SensitivityLevel.LOW, reason: 'Git 配置文件' },
110
+ ];
111
+
112
+ /**
113
+ *
114
+ */
115
+ private static readonly DANGEROUS_PATHS: RegExp[] = [
116
+ /^\/etc\//,
117
+ /^\/usr\//,
118
+ /^\/System\//,
119
+ /^\/var\//,
120
+ /^\/root\//,
121
+ /^C:\\Windows\\/i,
122
+ /^C:\\Program Files/i,
123
+ ];
124
+
125
+ /**
126
+ *
127
+ */
128
+ static check(filePath: string): SensitivityResult {
129
+ const normalizedPath = filePath.replace(/\\/g, '/');
130
+
131
+ for (const rule of this.SENSITIVE_PATTERNS) {
132
+ if (rule.pattern.test(normalizedPath)) {
133
+ return {
134
+ sensitive: true,
135
+ level: rule.level,
136
+ reason: rule.reason,
137
+ };
138
+ }
139
+ }
140
+
141
+ return { sensitive: false };
142
+ }
143
+
144
+ /**
145
+ *
146
+ */
147
+ static isDangerousPath(filePath: string): boolean {
148
+ const normalizedPath = filePath.replace(/\\/g, '/');
149
+ return this.DANGEROUS_PATHS.some(pattern => pattern.test(normalizedPath));
150
+ }
151
+
152
+ /**
153
+ *
154
+ */
155
+ static checkMultiple(filePaths: string[]): SensitivityResultWithPath[] {
156
+ return filePaths.map(path => ({
157
+ path,
158
+ result: this.check(path),
159
+ }));
160
+ }
161
+
162
+ /**
163
+ *
164
+ */
165
+ static filterSensitive(
166
+ filePaths: string[],
167
+ minLevel: SensitivityLevel = SensitivityLevel.LOW
168
+ ): SensitivityResultWithPath[] {
169
+ const levelOrder = {
170
+ [SensitivityLevel.LOW]: 0,
171
+ [SensitivityLevel.MEDIUM]: 1,
172
+ [SensitivityLevel.HIGH]: 2,
173
+ };
174
+
175
+ return this.checkMultiple(filePaths).filter(
176
+ item =>
177
+ item.result.sensitive &&
178
+ item.result.level &&
179
+ levelOrder[item.result.level] >= levelOrder[minLevel]
180
+ );
181
+ }
182
+
183
+ /**
184
+ *
185
+ */
186
+ static getLevelDescription(level: SensitivityLevel): string {
187
+ switch (level) {
188
+ case SensitivityLevel.LOW:
189
+ return '低敏感';
190
+ case SensitivityLevel.MEDIUM:
191
+ return '中敏感';
192
+ case SensitivityLevel.HIGH:
193
+ return '高敏感';
194
+ }
195
+ }
196
+
197
+ /**
198
+ *
199
+ */
200
+ static getLevelAction(level: SensitivityLevel): string {
201
+ switch (level) {
202
+ case SensitivityLevel.LOW:
203
+ return '正常流程处理';
204
+ case SensitivityLevel.MEDIUM:
205
+ return '需要用户确认';
206
+ case SensitivityLevel.HIGH:
207
+ return '默认拒绝访问';
208
+ }
209
+ }
210
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ *
3
+ */
4
+
5
+ export { PermissionChecker, DEFAULT_PERMISSION_CONFIG } from './PermissionChecker.js';
6
+ export {
7
+ SensitiveFileDetector,
8
+ SensitivityLevel,
9
+ type SensitivityResult,
10
+ type SensitivityResultWithPath,
11
+ } from './SensitiveFileDetector.js';
package/src/ui/App.tsx ADDED
@@ -0,0 +1,166 @@
1
+ /**
2
+ * App.tsx - rooted UI with stable references
3
+ */
4
+
5
+ import React, { useState, useCallback, useEffect, useRef } from 'react';
6
+ import { Box, Text } from 'ink';
7
+
8
+ import { ErrorBoundary } from './components/common/ErrorBoundary.js';
9
+ import pkg from '../../package.json' with { type: 'json' };
10
+ import { UpdatePrompt } from './components/dialog/UpdatePrompt.js';
11
+ import { AegisInterface } from './components/AegisInterface.js';
12
+ import { themeManager } from './themes/index.js';
13
+ import type { PermissionMode } from '../cli/types.js';
14
+ import type { VersionCheckResult } from '../services/VersionChecker.js';
15
+ import type { RuntimeConfig, ClawdConfig } from '../config/types.js';
16
+ import { DEFAULT_CONFIG } from '../config/types.js';
17
+ import {
18
+ ensureStoreInitialized,
19
+ appActions,
20
+ configActions,
21
+ getConfig,
22
+ useInitializationStatus,
23
+ } from '../store/index.js';
24
+
25
+ export interface AppProps {
26
+ apiKey: string;
27
+ baseURL?: string;
28
+ model?: string;
29
+ initialMessage?: string;
30
+ debug?: boolean;
31
+ permissionMode?: PermissionMode;
32
+ versionCheckPromise?: Promise<VersionCheckResult | null>;
33
+ resumeSessionId?: string;
34
+ routerEnabled?: boolean;
35
+ }
36
+
37
+ function mergeRuntimeConfig(baseConfig: ClawdConfig, props: AppProps): RuntimeConfig {
38
+ const runtimeConfig: RuntimeConfig = { ...baseConfig };
39
+
40
+ if (props.initialMessage) runtimeConfig.initialMessage = props.initialMessage;
41
+ if (props.resumeSessionId) runtimeConfig.resumeSessionId = props.resumeSessionId;
42
+ if (props.permissionMode) runtimeConfig.defaultPermissionMode = props.permissionMode;
43
+ if (props.routerEnabled) {
44
+ runtimeConfig.autoRouter = { ...runtimeConfig.autoRouter, enabled: true };
45
+ }
46
+ if (props.model) {
47
+ // Try to map model name to model ID first
48
+ const models = baseConfig.models || [];
49
+ const matched = models.find((m: any) => m.model === props.model || m.id === props.model);
50
+ runtimeConfig.currentModelId = matched ? matched.id : props.model;
51
+ }
52
+
53
+ return runtimeConfig;
54
+ }
55
+
56
+ function initializeStoreState(config: RuntimeConfig): void {
57
+ configActions().setConfig(config);
58
+
59
+ const isRealKey = (key?: string) => !!key && !key.startsWith('YOUR_');
60
+ const hasRealDefault = isRealKey(config.default?.apiKey);
61
+ const hasRealModel = config.models?.some(m => isRealKey((m as any).apiKey));
62
+
63
+ if (!hasRealDefault && !hasRealModel) {
64
+ appActions().setInitializationStatus('needsSetup');
65
+ } else {
66
+ appActions().setInitializationStatus('ready');
67
+ }
68
+ }
69
+
70
+ const AppWrapper: React.FC<AppProps> = (props) => {
71
+ const { versionCheckPromise, permissionMode, ...mainProps } = props;
72
+
73
+ const initializationStatus = useInitializationStatus();
74
+
75
+ const [versionInfo, setVersionInfo] = useState<VersionCheckResult | null>(null);
76
+ const [showUpdatePrompt, setShowUpdatePrompt] = useState(false);
77
+ const initDoneRef = useRef(false);
78
+
79
+ // Stable initializeApp using ref to avoid re-creating on every render
80
+ const propsRef = useRef(props);
81
+ propsRef.current = props;
82
+ const initializeApp = useCallback(async () => {
83
+ const p = propsRef.current;
84
+ if (p.debug) console.log('[DEBUG] Initializing application and Store...');
85
+
86
+ try {
87
+ appActions().setInitializationStatus('loading');
88
+
89
+ await ensureStoreInitialized();
90
+
91
+ const baseConfig = getConfig() ?? DEFAULT_CONFIG;
92
+ const mergedConfig = mergeRuntimeConfig(baseConfig, p);
93
+ initializeStoreState(mergedConfig);
94
+
95
+ initDoneRef.current = true;
96
+ if (p.debug) console.log('[DEBUG] Store initialized successfully');
97
+ } catch (error) {
98
+ appActions().setInitializationError(
99
+ error instanceof Error ? error.message : 'Unknown initialization error'
100
+ );
101
+ if (propsRef.current.debug) console.log('[DEBUG] Store initialization failed:', error);
102
+ }
103
+ }, []);
104
+
105
+ useEffect(() => {
106
+ // Start initialization immediately — don't wait for version check
107
+ const initPromise = initializeApp();
108
+
109
+ if (versionCheckPromise) {
110
+ // Run version check in parallel; only show prompt if init hasn't finished
111
+ versionCheckPromise
112
+ .then((versionResult) => {
113
+ if (versionResult && versionResult.shouldPrompt && !initDoneRef.current) {
114
+ setVersionInfo(versionResult);
115
+ setShowUpdatePrompt(true);
116
+ }
117
+ })
118
+ .catch((error) => {
119
+ if (props.debug) console.log('[DEBUG] Version check failed:', error);
120
+ });
121
+ }
122
+
123
+ // Keep the lint happy — both are used
124
+ void initPromise;
125
+ // eslint-disable-next-line react-hooks/exhaustive-deps
126
+ }, [versionCheckPromise, props.debug]);
127
+
128
+ if (showUpdatePrompt && versionInfo) {
129
+ return (
130
+ <UpdatePrompt
131
+ versionInfo={versionInfo}
132
+ onComplete={async () => {
133
+ setShowUpdatePrompt(false);
134
+ await initializeApp();
135
+ }}
136
+ />
137
+ );
138
+ }
139
+
140
+ if (initializationStatus === 'pending' || initializationStatus === 'loading') {
141
+ return (
142
+ <Box padding={1}>
143
+
144
+ </Box>
145
+ );
146
+ }
147
+
148
+ if (initializationStatus === 'error') {
149
+ return (
150
+ <Box padding={1} flexDirection="column">
151
+ <Text color="red">❌ Initialization failed</Text>
152
+ <Text color="gray">Please check your configuration and try again.</Text>
153
+ </Box>
154
+ );
155
+ }
156
+
157
+ return <AegisInterface {...mainProps} />;
158
+ };
159
+
160
+ export const App: React.FC<AppProps> = (props) => {
161
+ return (
162
+ <ErrorBoundary>
163
+ <AppWrapper {...props} />
164
+ </ErrorBoundary>
165
+ );
166
+ };