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.
- package/README.md +23 -15
- package/dist/main.js +549 -552
- package/package.json +4 -2
- package/src/agent/Agent.ts +903 -0
- package/src/agent/SimpleAgent.ts +48 -0
- package/src/agent/index.ts +54 -0
- package/src/agent/orchestrator/AppBuilder.ts +443 -0
- package/src/agent/orchestrator/CouncilAgent.ts +310 -0
- package/src/agent/orchestrator/DiscussionRoom.ts +462 -0
- package/src/agent/orchestrator/OrchestratorAgent.ts +637 -0
- package/src/agent/orchestrator/index.ts +38 -0
- package/src/agent/orchestrator/utils.ts +397 -0
- package/src/agent/pricing.ts +115 -0
- package/src/agent/router.ts +74 -0
- package/src/agent/routerStats.ts +121 -0
- package/src/agent/types.ts +318 -0
- package/src/auth/login.ts +383 -0
- package/src/cli/config.ts +189 -0
- package/src/cli/index.ts +17 -0
- package/src/cli/middleware.ts +119 -0
- package/src/cli/types.ts +75 -0
- package/src/config/ConfigManager.ts +587 -0
- package/src/config/index.ts +7 -0
- package/src/config/types.ts +584 -0
- package/src/context/CompactionService.ts +300 -0
- package/src/context/ContextManager.ts +450 -0
- package/src/context/FileAnalyzer.ts +267 -0
- package/src/context/TokenCounter.ts +265 -0
- package/src/context/index.ts +27 -0
- package/src/context/storage/CacheStore.ts +176 -0
- package/src/context/storage/JSONLStore.ts +201 -0
- package/src/context/storage/MemoryStore.ts +205 -0
- package/src/context/storage/PersistentStore.ts +327 -0
- package/src/context/storage/index.ts +9 -0
- package/src/context/storage/pathUtils.ts +114 -0
- package/src/context/test.ts +309 -0
- package/src/context/types.ts +268 -0
- package/src/hooks/HookExecutor.ts +434 -0
- package/src/hooks/HookManager.ts +596 -0
- package/src/hooks/HookService.ts +269 -0
- package/src/hooks/Matcher.ts +157 -0
- package/src/hooks/index.ts +63 -0
- package/src/hooks/types.ts +424 -0
- package/src/main.tsx +596 -0
- package/src/mcp/HealthMonitor.ts +150 -0
- package/src/mcp/McpClient.ts +491 -0
- package/src/mcp/McpRegistry.ts +321 -0
- package/src/mcp/createMcpTool.ts +251 -0
- package/src/mcp/index.ts +15 -0
- package/src/mcp/server.ts +334 -0
- package/src/mcp/test-server.ts +88 -0
- package/src/mcp/test.ts +372 -0
- package/src/mcp/types.ts +247 -0
- package/src/memory/AgentMemoryBus.ts +432 -0
- package/src/memory/CloudSync.ts +99 -0
- package/src/memory/DriveSync.ts +106 -0
- package/src/memory/SharedMemory.ts +951 -0
- package/src/memory/index.ts +14 -0
- package/src/memory/machineFingerprint.ts +40 -0
- package/src/orchestrator/SubAgentMetadata.ts +136 -0
- package/src/prompts/builder.ts +213 -0
- package/src/prompts/default.ts +144 -0
- package/src/prompts/index.ts +16 -0
- package/src/prompts/plan.ts +64 -0
- package/src/prompts/test.ts +78 -0
- package/src/services/AnthropicChatService.ts +341 -0
- package/src/services/ChatService.ts +347 -0
- package/src/services/ClaudeCliChatService.ts +256 -0
- package/src/services/CloudSync.ts +168 -0
- package/src/services/CostLedger.ts +211 -0
- package/src/services/Heartbeat.ts +135 -0
- package/src/services/LearningCollector.ts +291 -0
- package/src/services/OllamaInstaller.ts +342 -0
- package/src/services/VersionChecker.ts +445 -0
- package/src/services/index.ts +57 -0
- package/src/services/streaming/OpenAIEventAdapter.ts +126 -0
- package/src/services/streaming/RenderingProfile.ts +90 -0
- package/src/services/streaming/StreamEventParser.ts +181 -0
- package/src/services/streaming/ThrottledRenderer.ts +139 -0
- package/src/services/streaming/TranscriptBuffer.ts +574 -0
- package/src/services/streaming/eventStatusMap.ts +52 -0
- package/src/services/streaming/index.ts +46 -0
- package/src/services/streaming/renderFormatting.ts +79 -0
- package/src/services/streaming/types.ts +234 -0
- package/src/skills/SkillLoader.ts +126 -0
- package/src/skills/SkillRegistry.ts +366 -0
- package/src/skills/index.ts +48 -0
- package/src/skills/types.ts +146 -0
- package/src/slash-commands/billing.ts +70 -0
- package/src/slash-commands/build.ts +413 -0
- package/src/slash-commands/builtinCommands.ts +2733 -0
- package/src/slash-commands/clone.ts +242 -0
- package/src/slash-commands/council.ts +125 -0
- package/src/slash-commands/custom/CustomCommandExecutor.ts +143 -0
- package/src/slash-commands/custom/CustomCommandLoader.ts +251 -0
- package/src/slash-commands/custom/CustomCommandRegistry.ts +144 -0
- package/src/slash-commands/custom/index.ts +7 -0
- package/src/slash-commands/debate.ts +254 -0
- package/src/slash-commands/gmail.ts +105 -0
- package/src/slash-commands/index.ts +388 -0
- package/src/slash-commands/mcpCommand.ts +205 -0
- package/src/slash-commands/types.ts +201 -0
- package/src/store/index.ts +76 -0
- package/src/store/selectors.ts +246 -0
- package/src/store/slices/appSlice.ts +205 -0
- package/src/store/slices/commandSlice.ts +115 -0
- package/src/store/slices/configSlice.ts +46 -0
- package/src/store/slices/focusSlice.ts +64 -0
- package/src/store/slices/index.ts +9 -0
- package/src/store/slices/sessionSlice.ts +424 -0
- package/src/store/streaming-buffer.ts +425 -0
- package/src/store/test.ts +296 -0
- package/src/store/types.ts +274 -0
- package/src/store/vanilla.ts +186 -0
- package/src/tools/builtin/bash.ts +236 -0
- package/src/tools/builtin/council.ts +105 -0
- package/src/tools/builtin/edit.ts +213 -0
- package/src/tools/builtin/glob.ts +136 -0
- package/src/tools/builtin/grep.ts +263 -0
- package/src/tools/builtin/index.ts +61 -0
- package/src/tools/builtin/memory.ts +66 -0
- package/src/tools/builtin/read.ts +168 -0
- package/src/tools/builtin/skill.ts +97 -0
- package/src/tools/builtin/snapshot.ts +40 -0
- package/src/tools/builtin/task.ts +106 -0
- package/src/tools/builtin/write.ts +134 -0
- package/src/tools/createTool.ts +221 -0
- package/src/tools/execution/ExecutionPipeline.ts +263 -0
- package/src/tools/execution/index.ts +40 -0
- package/src/tools/execution/stages/CacheStage.ts +131 -0
- package/src/tools/execution/stages/ConfirmationStage.ts +203 -0
- package/src/tools/execution/stages/DiscoveryStage.ts +46 -0
- package/src/tools/execution/stages/ExecutionStage.ts +48 -0
- package/src/tools/execution/stages/FormattingStage.ts +44 -0
- package/src/tools/execution/stages/HookStage.ts +72 -0
- package/src/tools/execution/stages/PermissionStage.ts +287 -0
- package/src/tools/execution/stages/PostHookStage.ts +71 -0
- package/src/tools/execution/stages/index.ts +12 -0
- package/src/tools/execution/test.ts +266 -0
- package/src/tools/execution/types.ts +273 -0
- package/src/tools/index.ts +81 -0
- package/src/tools/registry.ts +304 -0
- package/src/tools/schemas.ts +109 -0
- package/src/tools/test.ts +220 -0
- package/src/tools/types.ts +175 -0
- package/src/tools/validation/PermissionChecker.ts +242 -0
- package/src/tools/validation/SensitiveFileDetector.ts +210 -0
- package/src/tools/validation/index.ts +11 -0
- package/src/ui/App.tsx +166 -0
- package/src/ui/components/AegisInterface.tsx +484 -0
- package/src/ui/components/common/ChatSearch.tsx +150 -0
- package/src/ui/components/common/ErrorBoundary.tsx +82 -0
- package/src/ui/components/common/ExitMessage.tsx +120 -0
- package/src/ui/components/common/LoadingIndicator.tsx +49 -0
- package/src/ui/components/common/index.ts +6 -0
- package/src/ui/components/dialog/ConfirmationPrompt.tsx +208 -0
- package/src/ui/components/dialog/InteractiveSelector.tsx +149 -0
- package/src/ui/components/dialog/SetupWizard.tsx +297 -0
- package/src/ui/components/dialog/UpdatePrompt.tsx +155 -0
- package/src/ui/components/dialog/index.ts +8 -0
- package/src/ui/components/index.ts +28 -0
- package/src/ui/components/input/CommandSuggestions.tsx +139 -0
- package/src/ui/components/input/CustomTextInput.tsx +220 -0
- package/src/ui/components/input/InputArea.tsx +361 -0
- package/src/ui/components/input/PromptSuggestions.tsx +66 -0
- package/src/ui/components/input/index.ts +6 -0
- package/src/ui/components/layout/ChatStatusBar.tsx +90 -0
- package/src/ui/components/layout/ContextBar.tsx +79 -0
- package/src/ui/components/layout/MessageArea.tsx +96 -0
- package/src/ui/components/layout/MessageList.tsx +647 -0
- package/src/ui/components/layout/MessageSeparator.tsx +26 -0
- package/src/ui/components/layout/WelcomeMessage.tsx +93 -0
- package/src/ui/components/layout/index.ts +7 -0
- package/src/ui/components/markdown/CodeHighlighter.tsx +292 -0
- package/src/ui/components/markdown/MessageRenderer.tsx +1211 -0
- package/src/ui/components/markdown/index.ts +8 -0
- package/src/ui/components/markdown/parser.ts +336 -0
- package/src/ui/components/markdown/types.ts +66 -0
- package/src/ui/focus/FocusManager.ts +137 -0
- package/src/ui/focus/index.ts +13 -0
- package/src/ui/focus/types.ts +54 -0
- package/src/ui/focus/useFocus.ts +75 -0
- package/src/ui/hooks/index.ts +11 -0
- package/src/ui/hooks/useAgent.ts +284 -0
- package/src/ui/hooks/useCommandHistory.ts +87 -0
- package/src/ui/hooks/useCommandProcessor.ts +443 -0
- package/src/ui/hooks/useConfirmation.ts +99 -0
- package/src/ui/hooks/useCtrlCHandler.ts +100 -0
- package/src/ui/hooks/useInputBuffer.ts +122 -0
- package/src/ui/hooks/useTerminalSize.ts +68 -0
- package/src/ui/hooks/useTerminalWidth.ts +5 -0
- package/src/ui/hooks/useWindowedList.ts +118 -0
- package/src/ui/render-debugger.ts +621 -0
- package/src/ui/test.ts +189 -0
- package/src/ui/themes/ThemeManager.ts +332 -0
- package/src/ui/themes/aegisTheme.ts +87 -0
- package/src/ui/themes/darkTheme.ts +87 -0
- package/src/ui/themes/defaultTheme.ts +85 -0
- package/src/ui/themes/index.ts +10 -0
- package/src/ui/themes/lightTheme.ts +89 -0
- package/src/ui/themes/popularThemes.ts +187 -0
- package/src/ui/themes/types.ts +130 -0
- package/src/utils/clipboard.ts +48 -0
- package/src/utils/debug.ts +43 -0
- package/src/utils/environment.ts +68 -0
- package/src/utils/index.ts +10 -0
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook Service - Hooks 系统的简洁 API 层
|
|
3
|
+
*
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { getHookManager } from './HookManager.js';
|
|
9
|
+
import type { HookContext } from './types.js';
|
|
10
|
+
import type { PermissionMode } from '../agent/types.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
function createContext(
|
|
16
|
+
sessionId: string,
|
|
17
|
+
projectDir?: string,
|
|
18
|
+
permissionMode?: string
|
|
19
|
+
): HookContext {
|
|
20
|
+
return {
|
|
21
|
+
sessionId,
|
|
22
|
+
projectDir: projectDir || process.cwd(),
|
|
23
|
+
permissionMode: (permissionMode || 'default') as PermissionMode,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
*
|
|
29
|
+
*/
|
|
30
|
+
export function isHooksAvailable(): boolean {
|
|
31
|
+
const manager = getHookManager();
|
|
32
|
+
return manager.isInitialized() && manager.isEnabled();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ==================== 生命周
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
*/
|
|
40
|
+
export async function onSessionStart(sessionId: string, projectDir?: string): Promise<void> {
|
|
41
|
+
if (!isHooksAvailable()) return;
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
await getHookManager().executeSessionStartHooks(
|
|
45
|
+
createContext(sessionId, projectDir)
|
|
46
|
+
);
|
|
47
|
+
} catch (error) {
|
|
48
|
+
console.warn('[HookService] SessionStart hook error:', error);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
*
|
|
54
|
+
*/
|
|
55
|
+
export async function onSessionEnd(sessionId: string, projectDir?: string): Promise<void> {
|
|
56
|
+
if (!isHooksAvailable()) return;
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
await getHookManager().executeSessionEndHooks(
|
|
60
|
+
createContext(sessionId, projectDir)
|
|
61
|
+
);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
console.warn('[HookService] SessionEnd hook error:', error);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
*
|
|
69
|
+
* @returns 注入的上下文(如果有)
|
|
70
|
+
*/
|
|
71
|
+
export async function onUserPromptSubmit(
|
|
72
|
+
promptContent: string,
|
|
73
|
+
sessionId: string,
|
|
74
|
+
projectDir?: string
|
|
75
|
+
): Promise<string | undefined> {
|
|
76
|
+
if (!isHooksAvailable()) return undefined;
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const result = await getHookManager().executeUserPromptHooks(
|
|
80
|
+
promptContent,
|
|
81
|
+
createContext(sessionId, projectDir)
|
|
82
|
+
);
|
|
83
|
+
return result.injectedContext;
|
|
84
|
+
} catch (error) {
|
|
85
|
+
console.warn('[HookService] UserPromptSubmit hook error:', error);
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ==================== 控制
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Agent 停止
|
|
94
|
+
* @returns true 表示应该继续执行
|
|
95
|
+
*/
|
|
96
|
+
export async function onStop(
|
|
97
|
+
stopReason: string | undefined,
|
|
98
|
+
sessionId: string,
|
|
99
|
+
projectDir?: string
|
|
100
|
+
): Promise<boolean> {
|
|
101
|
+
if (!isHooksAvailable()) return false;
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const result = await getHookManager().executeStopHooks(
|
|
105
|
+
stopReason,
|
|
106
|
+
createContext(sessionId, projectDir)
|
|
107
|
+
);
|
|
108
|
+
return result.shouldContinue;
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.warn('[HookService] Stop hook error:', error);
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
*
|
|
117
|
+
* @returns true 表示应该阻止压缩
|
|
118
|
+
*/
|
|
119
|
+
export async function onCompaction(
|
|
120
|
+
preTokens: number,
|
|
121
|
+
messageCount: number,
|
|
122
|
+
sessionId: string,
|
|
123
|
+
projectDir?: string
|
|
124
|
+
): Promise<boolean> {
|
|
125
|
+
if (!isHooksAvailable()) return false;
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
const result = await getHookManager().executeCompactionHooks(
|
|
129
|
+
preTokens,
|
|
130
|
+
messageCount,
|
|
131
|
+
createContext(sessionId, projectDir)
|
|
132
|
+
);
|
|
133
|
+
return result.shouldPrevent;
|
|
134
|
+
} catch (error) {
|
|
135
|
+
console.warn('[HookService] Compaction hook error:', error);
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ==================== 工具执
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* PreToolUse Hook 结果
|
|
144
|
+
*/
|
|
145
|
+
export interface PreToolHookResult {
|
|
146
|
+
decision: 'allow' | 'deny' | 'ask';
|
|
147
|
+
reason?: string;
|
|
148
|
+
modifiedInput?: Record<string, unknown>;
|
|
149
|
+
warning?: string;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* PostToolUse Hook 结果
|
|
154
|
+
*/
|
|
155
|
+
export interface PostToolHookResult {
|
|
156
|
+
additionalContext?: string;
|
|
157
|
+
modifiedOutput?: unknown;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
*
|
|
162
|
+
*/
|
|
163
|
+
export async function onPreToolUse(
|
|
164
|
+
toolName: string,
|
|
165
|
+
toolUseId: string,
|
|
166
|
+
toolInput: Record<string, unknown>,
|
|
167
|
+
sessionId: string,
|
|
168
|
+
projectDir?: string,
|
|
169
|
+
permissionMode?: string
|
|
170
|
+
): Promise<PreToolHookResult> {
|
|
171
|
+
if (!isHooksAvailable()) {
|
|
172
|
+
return { decision: 'allow' };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
return await getHookManager().executePreToolHooks(
|
|
177
|
+
toolName,
|
|
178
|
+
toolUseId,
|
|
179
|
+
toolInput,
|
|
180
|
+
createContext(sessionId, projectDir, permissionMode)
|
|
181
|
+
);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
console.warn('[HookService] PreToolUse hook error:', error);
|
|
184
|
+
return { decision: 'allow' };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
*
|
|
190
|
+
*/
|
|
191
|
+
export async function onPostToolUse(
|
|
192
|
+
toolName: string,
|
|
193
|
+
toolUseId: string,
|
|
194
|
+
toolInput: Record<string, unknown>,
|
|
195
|
+
toolResult: { success: boolean; llmContent?: string },
|
|
196
|
+
sessionId: string,
|
|
197
|
+
projectDir?: string,
|
|
198
|
+
permissionMode?: string
|
|
199
|
+
): Promise<PostToolHookResult> {
|
|
200
|
+
if (!isHooksAvailable()) {
|
|
201
|
+
return {};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
try {
|
|
205
|
+
return await getHookManager().executePostToolHooks(
|
|
206
|
+
toolName,
|
|
207
|
+
toolUseId,
|
|
208
|
+
toolInput,
|
|
209
|
+
toolResult,
|
|
210
|
+
createContext(sessionId, projectDir, permissionMode)
|
|
211
|
+
);
|
|
212
|
+
} catch (error) {
|
|
213
|
+
console.warn('[HookService] PostToolUse hook error:', error);
|
|
214
|
+
return {};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
*
|
|
220
|
+
*/
|
|
221
|
+
export async function onPostToolUseFailure(
|
|
222
|
+
toolName: string,
|
|
223
|
+
toolUseId: string,
|
|
224
|
+
toolInput: Record<string, unknown>,
|
|
225
|
+
errorMessage: string,
|
|
226
|
+
sessionId: string,
|
|
227
|
+
projectDir?: string,
|
|
228
|
+
permissionMode?: string
|
|
229
|
+
): Promise<void> {
|
|
230
|
+
if (!isHooksAvailable()) return;
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
await getHookManager().executePostToolFailureHooks(
|
|
234
|
+
toolName,
|
|
235
|
+
toolUseId,
|
|
236
|
+
toolInput,
|
|
237
|
+
errorMessage,
|
|
238
|
+
createContext(sessionId, projectDir, permissionMode)
|
|
239
|
+
);
|
|
240
|
+
} catch (error) {
|
|
241
|
+
console.warn('[HookService] PostToolUseFailure hook error:', error);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
*
|
|
247
|
+
* @returns 'approve' | 'deny' | 'ask'
|
|
248
|
+
*/
|
|
249
|
+
export async function onPermissionRequest(
|
|
250
|
+
toolName: string,
|
|
251
|
+
toolInput: Record<string, unknown>,
|
|
252
|
+
sessionId: string,
|
|
253
|
+
projectDir?: string,
|
|
254
|
+
permissionMode?: string
|
|
255
|
+
): Promise<'approve' | 'deny' | 'ask'> {
|
|
256
|
+
if (!isHooksAvailable()) return 'ask';
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
const result = await getHookManager().executePermissionHooks(
|
|
260
|
+
toolName,
|
|
261
|
+
toolInput,
|
|
262
|
+
createContext(sessionId, projectDir, permissionMode)
|
|
263
|
+
);
|
|
264
|
+
return result.decision;
|
|
265
|
+
} catch (error) {
|
|
266
|
+
console.warn('[HookService] PermissionRequest hook error:', error);
|
|
267
|
+
return 'ask';
|
|
268
|
+
}
|
|
269
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook 匹配器
|
|
3
|
+
*
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { minimatch } from 'minimatch';
|
|
9
|
+
import type { MatcherConfig, MatchContext, HookMatcher, Hook } from './types.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Hook 匹配器
|
|
13
|
+
*/
|
|
14
|
+
export class Matcher {
|
|
15
|
+
/**
|
|
16
|
+
*
|
|
17
|
+
*/
|
|
18
|
+
matches(config: MatcherConfig | undefined, context: MatchContext): boolean {
|
|
19
|
+
// 无匹配器配置 = 匹配所
|
|
20
|
+
if (!config) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// 检查工具名匹
|
|
25
|
+
if (config.tools && context.toolName) {
|
|
26
|
+
if (!this.matchesPattern(context.toolName, config.tools)) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 检查文件路径匹
|
|
32
|
+
if (config.paths && context.filePath) {
|
|
33
|
+
if (!this.matchesGlob(context.filePath, config.paths)) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// 检查命令匹
|
|
39
|
+
if (config.commands && context.command) {
|
|
40
|
+
if (!this.matchesPattern(context.command, config.commands)) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
*
|
|
50
|
+
*/
|
|
51
|
+
getMatchingHooks(matchers: HookMatcher[] | undefined, context: MatchContext): Hook[] {
|
|
52
|
+
if (!matchers || matchers.length === 0) {
|
|
53
|
+
return [];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const result: Hook[] = [];
|
|
57
|
+
|
|
58
|
+
for (const matcher of matchers) {
|
|
59
|
+
if (this.matches(matcher.matcher, context)) {
|
|
60
|
+
result.push(...matcher.hooks);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
*
|
|
69
|
+
*
|
|
70
|
+
*
|
|
71
|
+
* - 简单字符串: "Read"
|
|
72
|
+
* - 管道分隔: "Read|Write|Edit"
|
|
73
|
+
* - 正则表达式: "Bash\\(.*\\)"
|
|
74
|
+
*/
|
|
75
|
+
private matchesPattern(value: string, pattern: string): boolean {
|
|
76
|
+
// 尝试作为管道分隔的简单模
|
|
77
|
+
if (!pattern.includes('\\') && !pattern.includes('^') && !pattern.includes('$')) {
|
|
78
|
+
const parts = pattern.split('|');
|
|
79
|
+
for (const part of parts) {
|
|
80
|
+
if (value === part.trim()) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 尝试作为正则表达
|
|
87
|
+
try {
|
|
88
|
+
const regex = new RegExp(`^(${pattern})$`);
|
|
89
|
+
return regex.test(value);
|
|
90
|
+
} catch {
|
|
91
|
+
// 正则无效,使用简单字符串比
|
|
92
|
+
return value === pattern;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Glob 模式匹配
|
|
98
|
+
*
|
|
99
|
+
*
|
|
100
|
+
* - 通配符: "*.ts"
|
|
101
|
+
* - 双星: "**\/*.tsx"
|
|
102
|
+
* - 多模式: "**\/*.{ts,tsx,js,jsx}"
|
|
103
|
+
*/
|
|
104
|
+
private matchesGlob(filePath: string, pattern: string): boolean {
|
|
105
|
+
// 处理管道分隔的多
|
|
106
|
+
const patterns = pattern.split('|').map(p => p.trim());
|
|
107
|
+
|
|
108
|
+
for (const p of patterns) {
|
|
109
|
+
if (minimatch(filePath, p, { matchBase: true })) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
*
|
|
120
|
+
*/
|
|
121
|
+
export function extractFilePath(toolInput: Record<string, unknown>): string | undefined {
|
|
122
|
+
// 常见的文件路径字段
|
|
123
|
+
const pathFields = ['file_path', 'path', 'filePath', 'file', 'target'];
|
|
124
|
+
|
|
125
|
+
for (const field of pathFields) {
|
|
126
|
+
const value = toolInput[field];
|
|
127
|
+
if (typeof value === 'string' && value.length > 0) {
|
|
128
|
+
return value;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
*
|
|
137
|
+
*/
|
|
138
|
+
export function extractCommand(
|
|
139
|
+
toolName: string,
|
|
140
|
+
toolInput: Record<string, unknown>
|
|
141
|
+
): string | undefined {
|
|
142
|
+
// 只有 Bash 工具有命
|
|
143
|
+
if (toolName !== 'Bash' && toolName !== 'Shell') {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const commandFields = ['command', 'cmd', 'script'];
|
|
148
|
+
|
|
149
|
+
for (const field of commandFields) {
|
|
150
|
+
const value = toolInput[field];
|
|
151
|
+
if (typeof value === 'string' && value.length > 0) {
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return undefined;
|
|
157
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks 系统模块
|
|
3
|
+
*
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// 类型导
|
|
8
|
+
export * from './types.js';
|
|
9
|
+
|
|
10
|
+
// 核心类导
|
|
11
|
+
export { HookManager, getHookManager } from './HookManager.js';
|
|
12
|
+
export { HookExecutor } from './HookExecutor.js';
|
|
13
|
+
export { Matcher, extractFilePath, extractCommand } from './Matcher.js';
|
|
14
|
+
|
|
15
|
+
// Hook Service - 简洁 API 层(独立函
|
|
16
|
+
export {
|
|
17
|
+
isHooksAvailable,
|
|
18
|
+
// 生命周
|
|
19
|
+
onSessionStart,
|
|
20
|
+
onSessionEnd,
|
|
21
|
+
onUserPromptSubmit,
|
|
22
|
+
// 控制
|
|
23
|
+
onStop,
|
|
24
|
+
onCompaction,
|
|
25
|
+
// 工具执
|
|
26
|
+
onPreToolUse,
|
|
27
|
+
onPostToolUse,
|
|
28
|
+
onPostToolUseFailure,
|
|
29
|
+
onPermissionRequest,
|
|
30
|
+
// 类
|
|
31
|
+
type PreToolHookResult,
|
|
32
|
+
type PostToolHookResult,
|
|
33
|
+
} from './HookService.js';
|
|
34
|
+
|
|
35
|
+
// 便捷函
|
|
36
|
+
import { getHookManager } from './HookManager.js';
|
|
37
|
+
import type { HookConfig } from './types.js';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
*
|
|
41
|
+
*/
|
|
42
|
+
export function initializeHooks(config: Partial<HookConfig>): void {
|
|
43
|
+
const manager = getHookManager();
|
|
44
|
+
manager.loadConfig(config);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
*
|
|
49
|
+
*/
|
|
50
|
+
export function isHooksEnabled(): boolean {
|
|
51
|
+
return getHookManager().isEnabled();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
*
|
|
56
|
+
*/
|
|
57
|
+
export function getHookStats(): { enabled: boolean; counts: Record<string, number> } {
|
|
58
|
+
const manager = getHookManager();
|
|
59
|
+
return {
|
|
60
|
+
enabled: manager.isEnabled(),
|
|
61
|
+
counts: manager.getHookCounts(),
|
|
62
|
+
};
|
|
63
|
+
}
|