wave-agent-sdk 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/agent.d.ts +96 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +286 -0
- package/dist/hooks/executor.d.ts +56 -0
- package/dist/hooks/executor.d.ts.map +1 -0
- package/dist/hooks/executor.js +312 -0
- package/dist/hooks/index.d.ts +17 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +14 -0
- package/dist/hooks/manager.d.ts +90 -0
- package/dist/hooks/manager.d.ts.map +1 -0
- package/dist/hooks/manager.js +395 -0
- package/dist/hooks/matcher.d.ts +49 -0
- package/dist/hooks/matcher.d.ts.map +1 -0
- package/dist/hooks/matcher.js +147 -0
- package/dist/hooks/settings.d.ts +46 -0
- package/dist/hooks/settings.d.ts.map +1 -0
- package/dist/hooks/settings.js +100 -0
- package/dist/hooks/types.d.ts +80 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +59 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/managers/aiManager.d.ts +61 -0
- package/dist/managers/aiManager.d.ts.map +1 -0
- package/dist/managers/aiManager.js +415 -0
- package/dist/managers/backgroundBashManager.d.ts +27 -0
- package/dist/managers/backgroundBashManager.d.ts.map +1 -0
- package/dist/managers/backgroundBashManager.js +166 -0
- package/dist/managers/bashManager.d.ts +20 -0
- package/dist/managers/bashManager.d.ts.map +1 -0
- package/dist/managers/bashManager.js +66 -0
- package/dist/managers/mcpManager.d.ts +63 -0
- package/dist/managers/mcpManager.d.ts.map +1 -0
- package/dist/managers/mcpManager.js +378 -0
- package/dist/managers/messageManager.d.ts +85 -0
- package/dist/managers/messageManager.d.ts.map +1 -0
- package/dist/managers/messageManager.js +265 -0
- package/dist/managers/skillManager.d.ts +59 -0
- package/dist/managers/skillManager.d.ts.map +1 -0
- package/dist/managers/skillManager.js +317 -0
- package/dist/managers/slashCommandManager.d.ts +77 -0
- package/dist/managers/slashCommandManager.d.ts.map +1 -0
- package/dist/managers/slashCommandManager.js +208 -0
- package/dist/managers/toolManager.d.ts +23 -0
- package/dist/managers/toolManager.d.ts.map +1 -0
- package/dist/managers/toolManager.js +79 -0
- package/dist/services/aiService.d.ts +28 -0
- package/dist/services/aiService.d.ts.map +1 -0
- package/dist/services/aiService.js +180 -0
- package/dist/services/memory.d.ts +8 -0
- package/dist/services/memory.d.ts.map +1 -0
- package/dist/services/memory.js +128 -0
- package/dist/services/session.d.ts +54 -0
- package/dist/services/session.d.ts.map +1 -0
- package/dist/services/session.js +196 -0
- package/dist/tools/bashTool.d.ts +14 -0
- package/dist/tools/bashTool.d.ts.map +1 -0
- package/dist/tools/bashTool.js +351 -0
- package/dist/tools/deleteFileTool.d.ts +6 -0
- package/dist/tools/deleteFileTool.d.ts.map +1 -0
- package/dist/tools/deleteFileTool.js +67 -0
- package/dist/tools/editTool.d.ts +6 -0
- package/dist/tools/editTool.d.ts.map +1 -0
- package/dist/tools/editTool.js +168 -0
- package/dist/tools/globTool.d.ts +6 -0
- package/dist/tools/globTool.d.ts.map +1 -0
- package/dist/tools/globTool.js +113 -0
- package/dist/tools/grepTool.d.ts +6 -0
- package/dist/tools/grepTool.d.ts.map +1 -0
- package/dist/tools/grepTool.js +268 -0
- package/dist/tools/lsTool.d.ts +6 -0
- package/dist/tools/lsTool.d.ts.map +1 -0
- package/dist/tools/lsTool.js +160 -0
- package/dist/tools/multiEditTool.d.ts +6 -0
- package/dist/tools/multiEditTool.d.ts.map +1 -0
- package/dist/tools/multiEditTool.js +222 -0
- package/dist/tools/readTool.d.ts +6 -0
- package/dist/tools/readTool.d.ts.map +1 -0
- package/dist/tools/readTool.js +136 -0
- package/dist/tools/types.d.ts +35 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +4 -0
- package/dist/tools/writeTool.d.ts +6 -0
- package/dist/tools/writeTool.d.ts.map +1 -0
- package/dist/tools/writeTool.js +138 -0
- package/dist/types.d.ts +212 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/dist/utils/bashHistory.d.ts +46 -0
- package/dist/utils/bashHistory.d.ts.map +1 -0
- package/dist/utils/bashHistory.js +236 -0
- package/dist/utils/commandArgumentParser.d.ts +34 -0
- package/dist/utils/commandArgumentParser.d.ts.map +1 -0
- package/dist/utils/commandArgumentParser.js +123 -0
- package/dist/utils/constants.d.ts +27 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +28 -0
- package/dist/utils/convertMessagesForAPI.d.ts +9 -0
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -0
- package/dist/utils/convertMessagesForAPI.js +189 -0
- package/dist/utils/customCommands.d.ts +14 -0
- package/dist/utils/customCommands.d.ts.map +1 -0
- package/dist/utils/customCommands.js +71 -0
- package/dist/utils/fileFilter.d.ts +26 -0
- package/dist/utils/fileFilter.d.ts.map +1 -0
- package/dist/utils/fileFilter.js +177 -0
- package/dist/utils/markdownParser.d.ts +27 -0
- package/dist/utils/markdownParser.d.ts.map +1 -0
- package/dist/utils/markdownParser.js +109 -0
- package/dist/utils/mcpUtils.d.ts +24 -0
- package/dist/utils/mcpUtils.d.ts.map +1 -0
- package/dist/utils/mcpUtils.js +51 -0
- package/dist/utils/messageOperations.d.ts +118 -0
- package/dist/utils/messageOperations.d.ts.map +1 -0
- package/dist/utils/messageOperations.js +334 -0
- package/dist/utils/path.d.ts +25 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +109 -0
- package/dist/utils/skillParser.d.ts +18 -0
- package/dist/utils/skillParser.d.ts.map +1 -0
- package/dist/utils/skillParser.js +147 -0
- package/dist/utils/stringUtils.d.ts +13 -0
- package/dist/utils/stringUtils.d.ts.map +1 -0
- package/dist/utils/stringUtils.js +44 -0
- package/package.json +51 -0
- package/src/agent.ts +405 -0
- package/src/hooks/executor.ts +440 -0
- package/src/hooks/index.ts +52 -0
- package/src/hooks/manager.ts +618 -0
- package/src/hooks/matcher.ts +187 -0
- package/src/hooks/settings.ts +129 -0
- package/src/hooks/types.ts +169 -0
- package/src/index.ts +24 -0
- package/src/managers/aiManager.ts +573 -0
- package/src/managers/backgroundBashManager.ts +203 -0
- package/src/managers/bashManager.ts +97 -0
- package/src/managers/mcpManager.ts +493 -0
- package/src/managers/messageManager.ts +415 -0
- package/src/managers/skillManager.ts +404 -0
- package/src/managers/slashCommandManager.ts +293 -0
- package/src/managers/toolManager.ts +106 -0
- package/src/services/aiService.ts +252 -0
- package/src/services/memory.ts +149 -0
- package/src/services/session.ts +265 -0
- package/src/tools/bashTool.ts +402 -0
- package/src/tools/deleteFileTool.ts +81 -0
- package/src/tools/editTool.ts +192 -0
- package/src/tools/globTool.ts +135 -0
- package/src/tools/grepTool.ts +326 -0
- package/src/tools/lsTool.ts +187 -0
- package/src/tools/multiEditTool.ts +268 -0
- package/src/tools/readTool.ts +165 -0
- package/src/tools/types.ts +47 -0
- package/src/tools/writeTool.ts +163 -0
- package/src/types.ts +260 -0
- package/src/utils/bashHistory.ts +303 -0
- package/src/utils/commandArgumentParser.ts +153 -0
- package/src/utils/constants.ts +37 -0
- package/src/utils/convertMessagesForAPI.ts +236 -0
- package/src/utils/customCommands.ts +85 -0
- package/src/utils/fileFilter.ts +202 -0
- package/src/utils/markdownParser.ts +156 -0
- package/src/utils/mcpUtils.ts +81 -0
- package/src/utils/messageOperations.ts +506 -0
- package/src/utils/path.ts +118 -0
- package/src/utils/skillParser.ts +188 -0
- package/src/utils/stringUtils.ts +50 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook Pattern Matcher
|
|
3
|
+
*
|
|
4
|
+
* Provides pattern matching functionality for hook tool name matching.
|
|
5
|
+
* Supports exact matching, wildcard patterns, and pipe-separated alternatives.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { minimatch } from "minimatch";
|
|
9
|
+
|
|
10
|
+
export interface IHookMatcher {
|
|
11
|
+
// Test if pattern matches tool name
|
|
12
|
+
matches(pattern: string, toolName: string): boolean;
|
|
13
|
+
|
|
14
|
+
// Validate pattern syntax
|
|
15
|
+
isValidPattern(pattern: string): boolean;
|
|
16
|
+
|
|
17
|
+
// Get pattern type for optimization
|
|
18
|
+
getPatternType(pattern: string): "exact" | "glob" | "regex" | "alternatives";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class HookMatcher implements IHookMatcher {
|
|
22
|
+
/**
|
|
23
|
+
* Test if pattern matches tool name
|
|
24
|
+
* Supports multiple matching strategies:
|
|
25
|
+
* - Exact matching: "Edit" matches "Edit"
|
|
26
|
+
* - Pipe alternatives: "Edit|Write" matches "Edit" or "Write"
|
|
27
|
+
* - Glob patterns: "Edit*" matches "EditFile", "EditText", etc.
|
|
28
|
+
* - Case insensitive matching
|
|
29
|
+
*/
|
|
30
|
+
matches(pattern: string, toolName: string): boolean {
|
|
31
|
+
if (!pattern || !toolName) return false;
|
|
32
|
+
|
|
33
|
+
// Handle pipe-separated alternatives (e.g., "Edit|Write|Delete")
|
|
34
|
+
if (pattern.includes("|")) {
|
|
35
|
+
const alternatives = pattern.split("|").map((alt) => alt.trim());
|
|
36
|
+
return alternatives.some((alt) => this.matchesSingle(alt, toolName));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return this.matchesSingle(pattern, toolName);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Match a single pattern against tool name
|
|
44
|
+
*/
|
|
45
|
+
private matchesSingle(pattern: string, toolName: string): boolean {
|
|
46
|
+
// Exact match (case insensitive)
|
|
47
|
+
if (pattern.toLowerCase() === toolName.toLowerCase()) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Glob pattern matching using minimatch
|
|
52
|
+
try {
|
|
53
|
+
return minimatch(toolName, pattern, {
|
|
54
|
+
nocase: true, // Case insensitive
|
|
55
|
+
noglobstar: false, // Allow ** patterns
|
|
56
|
+
nonegate: true, // Disable negation for security
|
|
57
|
+
});
|
|
58
|
+
} catch {
|
|
59
|
+
// Invalid pattern, fall back to exact match
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Validate pattern syntax
|
|
66
|
+
*/
|
|
67
|
+
isValidPattern(pattern: string): boolean {
|
|
68
|
+
if (!pattern || typeof pattern !== "string") return false;
|
|
69
|
+
|
|
70
|
+
// Empty pattern is invalid
|
|
71
|
+
if (pattern.trim().length === 0) return false;
|
|
72
|
+
|
|
73
|
+
// Handle pipe-separated alternatives
|
|
74
|
+
if (pattern.includes("|")) {
|
|
75
|
+
const alternatives = pattern.split("|").map((alt) => alt.trim());
|
|
76
|
+
return (
|
|
77
|
+
alternatives.length > 0 &&
|
|
78
|
+
alternatives.every(
|
|
79
|
+
(alt) => alt.length > 0 && this.isValidSinglePattern(alt),
|
|
80
|
+
)
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return this.isValidSinglePattern(pattern);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Validate single pattern syntax
|
|
89
|
+
*/
|
|
90
|
+
private isValidSinglePattern(pattern: string): boolean {
|
|
91
|
+
// Basic validation - non-empty string
|
|
92
|
+
if (!pattern || pattern.trim().length === 0) return false;
|
|
93
|
+
|
|
94
|
+
// Check for dangerous characters that could be used for command injection
|
|
95
|
+
// Note: [ ] are allowed for glob patterns
|
|
96
|
+
const dangerousChars = /[;&|`$(){}><]/;
|
|
97
|
+
if (dangerousChars.test(pattern)) return false;
|
|
98
|
+
|
|
99
|
+
// Validate glob pattern syntax using minimatch
|
|
100
|
+
try {
|
|
101
|
+
// Test with a dummy string to validate pattern
|
|
102
|
+
minimatch("test", pattern, { nocase: true });
|
|
103
|
+
return true;
|
|
104
|
+
} catch {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get pattern type for optimization
|
|
111
|
+
*/
|
|
112
|
+
getPatternType(pattern: string): "exact" | "glob" | "regex" | "alternatives" {
|
|
113
|
+
if (!pattern) return "exact";
|
|
114
|
+
|
|
115
|
+
// Check for pipe alternatives first
|
|
116
|
+
if (pattern.includes("|")) {
|
|
117
|
+
return "alternatives";
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Check for regex patterns first (before glob check)
|
|
121
|
+
if (
|
|
122
|
+
pattern.startsWith("/") &&
|
|
123
|
+
pattern.endsWith("/") &&
|
|
124
|
+
pattern.length > 2
|
|
125
|
+
) {
|
|
126
|
+
return "regex";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Check for glob patterns
|
|
130
|
+
if (
|
|
131
|
+
pattern.includes("*") ||
|
|
132
|
+
pattern.includes("?") ||
|
|
133
|
+
pattern.includes("[")
|
|
134
|
+
) {
|
|
135
|
+
return "glob";
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return "exact";
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Get all tool names that would match this pattern from a given list
|
|
143
|
+
* Useful for testing and validation
|
|
144
|
+
*/
|
|
145
|
+
getMatches(pattern: string, toolNames: string[]): string[] {
|
|
146
|
+
return toolNames.filter((toolName) => this.matches(pattern, toolName));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Optimize pattern for repeated matching
|
|
151
|
+
* Returns a compiled matcher function for performance
|
|
152
|
+
*/
|
|
153
|
+
compile(pattern: string): (toolName: string) => boolean {
|
|
154
|
+
if (!this.isValidPattern(pattern)) {
|
|
155
|
+
return () => false;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const patternType = this.getPatternType(pattern);
|
|
159
|
+
|
|
160
|
+
switch (patternType) {
|
|
161
|
+
case "exact": {
|
|
162
|
+
const lowerPattern = pattern.toLowerCase();
|
|
163
|
+
return (toolName: string) => toolName.toLowerCase() === lowerPattern;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
case "alternatives": {
|
|
167
|
+
const alternatives = pattern
|
|
168
|
+
.split("|")
|
|
169
|
+
.map((alt) => alt.trim().toLowerCase());
|
|
170
|
+
return (toolName: string) => {
|
|
171
|
+
const lowerTool = toolName.toLowerCase();
|
|
172
|
+
return alternatives.some(
|
|
173
|
+
(alt) =>
|
|
174
|
+
lowerTool === alt || minimatch(toolName, alt, { nocase: true }),
|
|
175
|
+
);
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
case "glob":
|
|
180
|
+
return (toolName: string) =>
|
|
181
|
+
minimatch(toolName, pattern, { nocase: true });
|
|
182
|
+
|
|
183
|
+
default:
|
|
184
|
+
return (toolName: string) => this.matches(pattern, toolName);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook Settings Management
|
|
3
|
+
*
|
|
4
|
+
* Handles loading and merging of hook configurations from:
|
|
5
|
+
* - User settings: ~/.wave/hooks.json
|
|
6
|
+
* - Project settings: ./.wave/hooks.json
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { existsSync, readFileSync } from "fs";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
import { homedir } from "os";
|
|
12
|
+
import type { HookConfiguration, PartialHookConfiguration } from "./types.js";
|
|
13
|
+
import { isValidHookEvent } from "./types.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Get the user-specific hooks configuration file path
|
|
17
|
+
*/
|
|
18
|
+
export function getUserHooksConfigPath(): string {
|
|
19
|
+
return join(homedir(), ".wave", "hooks.json");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Get the project-specific hooks configuration file path
|
|
24
|
+
*/
|
|
25
|
+
export function getProjectHooksConfigPath(workdir: string): string {
|
|
26
|
+
return join(workdir, ".wave", "hooks.json");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Load hooks configuration from a JSON file
|
|
31
|
+
*/
|
|
32
|
+
export function loadHooksConfigFromFile(
|
|
33
|
+
filePath: string,
|
|
34
|
+
): PartialHookConfiguration | null {
|
|
35
|
+
try {
|
|
36
|
+
if (!existsSync(filePath)) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const content = readFileSync(filePath, "utf-8");
|
|
41
|
+
const config = JSON.parse(content) as HookConfiguration;
|
|
42
|
+
|
|
43
|
+
// Validate basic structure
|
|
44
|
+
if (!config || typeof config !== "object" || !config.hooks) {
|
|
45
|
+
console.warn(`Invalid hooks configuration structure in ${filePath}`);
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return config.hooks;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.warn(`Failed to load hooks configuration from ${filePath}:`, error);
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Load user hooks configuration
|
|
58
|
+
*/
|
|
59
|
+
export function loadUserHooksConfig(): PartialHookConfiguration | null {
|
|
60
|
+
return loadHooksConfigFromFile(getUserHooksConfigPath());
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Load project hooks configuration
|
|
65
|
+
*/
|
|
66
|
+
export function loadProjectHooksConfig(
|
|
67
|
+
workdir: string,
|
|
68
|
+
): PartialHookConfiguration | null {
|
|
69
|
+
return loadHooksConfigFromFile(getProjectHooksConfigPath(workdir));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Load and merge hooks configuration with project settings taking precedence
|
|
74
|
+
*/
|
|
75
|
+
export function loadMergedHooksConfig(
|
|
76
|
+
workdir: string,
|
|
77
|
+
): PartialHookConfiguration {
|
|
78
|
+
const userConfig = loadUserHooksConfig();
|
|
79
|
+
const projectConfig = loadProjectHooksConfig(workdir);
|
|
80
|
+
|
|
81
|
+
const merged: PartialHookConfiguration = {};
|
|
82
|
+
|
|
83
|
+
// Start with user configuration
|
|
84
|
+
if (userConfig) {
|
|
85
|
+
Object.entries(userConfig).forEach(([event, configs]) => {
|
|
86
|
+
if (isValidHookEvent(event)) {
|
|
87
|
+
merged[event] = [...configs];
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Override with project configuration (project takes precedence)
|
|
93
|
+
if (projectConfig) {
|
|
94
|
+
Object.entries(projectConfig).forEach(([event, configs]) => {
|
|
95
|
+
if (isValidHookEvent(event)) {
|
|
96
|
+
merged[event] = [...configs];
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return merged;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Check if any hooks configuration files exist
|
|
106
|
+
*/
|
|
107
|
+
export function hasHooksConfiguration(workdir: string): boolean {
|
|
108
|
+
return (
|
|
109
|
+
existsSync(getUserHooksConfigPath()) ||
|
|
110
|
+
existsSync(getProjectHooksConfigPath(workdir))
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get information about available hooks configuration files
|
|
116
|
+
*/
|
|
117
|
+
export function getHooksConfigurationInfo(workdir: string): {
|
|
118
|
+
userConfigExists: boolean;
|
|
119
|
+
projectConfigExists: boolean;
|
|
120
|
+
userConfigPath: string;
|
|
121
|
+
projectConfigPath: string;
|
|
122
|
+
} {
|
|
123
|
+
return {
|
|
124
|
+
userConfigExists: existsSync(getUserHooksConfigPath()),
|
|
125
|
+
projectConfigExists: existsSync(getProjectHooksConfigPath(workdir)),
|
|
126
|
+
userConfigPath: getUserHooksConfigPath(),
|
|
127
|
+
projectConfigPath: getProjectHooksConfigPath(workdir),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks System Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Provides comprehensive TypeScript types for the Wave Code hooks system,
|
|
5
|
+
* enabling automated actions at specific workflow points.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
import { homedir } from "os";
|
|
10
|
+
|
|
11
|
+
// Session path utility (from session.ts)
|
|
12
|
+
export function getSessionFilePath(sessionId: string): string {
|
|
13
|
+
const shortId = sessionId.split("_")[2] || sessionId.slice(-8);
|
|
14
|
+
return join(homedir(), ".wave", "sessions", `session_${shortId}.json`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Hook event types - trigger points in the AI workflow
|
|
18
|
+
export type HookEvent =
|
|
19
|
+
| "PreToolUse"
|
|
20
|
+
| "PostToolUse"
|
|
21
|
+
| "UserPromptSubmit"
|
|
22
|
+
| "Stop";
|
|
23
|
+
|
|
24
|
+
// Individual hook command configuration
|
|
25
|
+
export interface HookCommand {
|
|
26
|
+
type: "command";
|
|
27
|
+
command: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Hook event configuration with optional pattern matching
|
|
31
|
+
export interface HookEventConfig {
|
|
32
|
+
matcher?: string; // Required for PreToolUse/PostToolUse, omitted for others
|
|
33
|
+
hooks: HookCommand[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Root configuration structure for all hook definitions
|
|
37
|
+
export interface HookConfiguration {
|
|
38
|
+
hooks: Partial<Record<HookEvent, HookEventConfig[]>>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Partial hook configuration for loading/merging scenarios
|
|
42
|
+
export type PartialHookConfiguration = Partial<
|
|
43
|
+
Record<HookEvent, HookEventConfig[]>
|
|
44
|
+
>;
|
|
45
|
+
|
|
46
|
+
// Direct hook configuration record (for test convenience)
|
|
47
|
+
export type HookConfigurationRecord = Record<HookEvent, HookEventConfig[]>;
|
|
48
|
+
|
|
49
|
+
// Context passed to hook during execution
|
|
50
|
+
export interface HookExecutionContext {
|
|
51
|
+
event: HookEvent;
|
|
52
|
+
toolName?: string; // Present for PreToolUse/PostToolUse events
|
|
53
|
+
projectDir: string; // Absolute path for $WAVE_PROJECT_DIR
|
|
54
|
+
timestamp: Date;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Result of hook execution
|
|
58
|
+
export interface HookExecutionResult {
|
|
59
|
+
success: boolean;
|
|
60
|
+
exitCode?: number;
|
|
61
|
+
stdout?: string;
|
|
62
|
+
stderr?: string;
|
|
63
|
+
duration: number; // milliseconds
|
|
64
|
+
timedOut: boolean;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Hook execution options
|
|
68
|
+
export interface HookExecutionOptions {
|
|
69
|
+
timeout?: number; // milliseconds, default 10000
|
|
70
|
+
cwd?: string; // working directory, defaults to projectDir
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Validation result for hook configuration
|
|
74
|
+
export interface ValidationResult {
|
|
75
|
+
valid: boolean;
|
|
76
|
+
errors: string[];
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Hook execution errors (non-blocking)
|
|
80
|
+
export class HookExecutionError extends Error {
|
|
81
|
+
constructor(
|
|
82
|
+
public readonly hookCommand: string,
|
|
83
|
+
public readonly originalError: Error,
|
|
84
|
+
public readonly context: HookExecutionContext,
|
|
85
|
+
) {
|
|
86
|
+
super(`Hook execution failed: ${hookCommand} - ${originalError.message}`);
|
|
87
|
+
this.name = "HookExecutionError";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Configuration validation errors (blocking)
|
|
92
|
+
export class HookConfigurationError extends Error {
|
|
93
|
+
constructor(
|
|
94
|
+
public readonly configPath: string,
|
|
95
|
+
public readonly validationErrors: string[],
|
|
96
|
+
) {
|
|
97
|
+
super(
|
|
98
|
+
`Hook configuration error in ${configPath}: ${validationErrors.join(", ")}`,
|
|
99
|
+
);
|
|
100
|
+
this.name = "HookConfigurationError";
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Type guards for runtime validation
|
|
105
|
+
export function isValidHookEvent(event: string): event is HookEvent {
|
|
106
|
+
return ["PreToolUse", "PostToolUse", "UserPromptSubmit", "Stop"].includes(
|
|
107
|
+
event,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function isValidHookCommand(cmd: unknown): cmd is HookCommand {
|
|
112
|
+
return (
|
|
113
|
+
typeof cmd === "object" &&
|
|
114
|
+
cmd !== null &&
|
|
115
|
+
"type" in cmd &&
|
|
116
|
+
cmd.type === "command" &&
|
|
117
|
+
"command" in cmd &&
|
|
118
|
+
typeof cmd.command === "string" &&
|
|
119
|
+
cmd.command.length > 0
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function isValidHookEventConfig(
|
|
124
|
+
config: unknown,
|
|
125
|
+
): config is HookEventConfig {
|
|
126
|
+
if (typeof config !== "object" || config === null) return false;
|
|
127
|
+
|
|
128
|
+
const cfg = config as Record<string, unknown>;
|
|
129
|
+
|
|
130
|
+
// Validate hooks array
|
|
131
|
+
if (!Array.isArray(cfg.hooks) || cfg.hooks.length === 0) return false;
|
|
132
|
+
if (!cfg.hooks.every(isValidHookCommand)) return false;
|
|
133
|
+
|
|
134
|
+
// Validate optional matcher
|
|
135
|
+
if ("matcher" in cfg && typeof cfg.matcher !== "string") return false;
|
|
136
|
+
|
|
137
|
+
return true;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// JSON structure passed to hooks via stdin
|
|
141
|
+
export interface HookJsonInput {
|
|
142
|
+
// Required fields for all events
|
|
143
|
+
session_id: string; // Format: "wave_session_{uuid}_{shortId}"
|
|
144
|
+
transcript_path: string; // Format: "~/.wave/sessions/session_{shortId}.json"
|
|
145
|
+
cwd: string; // Absolute path to current working directory
|
|
146
|
+
hook_event_name: HookEvent; // "PreToolUse" | "PostToolUse" | "UserPromptSubmit" | "Stop"
|
|
147
|
+
|
|
148
|
+
// Optional fields based on event type
|
|
149
|
+
tool_name?: string; // Present for PreToolUse, PostToolUse
|
|
150
|
+
tool_input?: unknown; // Present for PreToolUse, PostToolUse
|
|
151
|
+
tool_response?: unknown; // Present for PostToolUse only
|
|
152
|
+
user_prompt?: string; // Present for UserPromptSubmit only
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Extended context interface for passing additional data to hook executor
|
|
156
|
+
export interface ExtendedHookExecutionContext extends HookExecutionContext {
|
|
157
|
+
sessionId?: string; // Session identifier for JSON construction
|
|
158
|
+
transcriptPath?: string; // Path to session transcript file
|
|
159
|
+
cwd?: string; // Current working directory
|
|
160
|
+
toolInput?: unknown; // Tool input parameters (PreToolUse/PostToolUse)
|
|
161
|
+
toolResponse?: unknown; // Tool execution result (PostToolUse only)
|
|
162
|
+
userPrompt?: string; // User prompt text (UserPromptSubmit only)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Environment variables injected into hook processes
|
|
166
|
+
export interface HookEnvironment {
|
|
167
|
+
WAVE_PROJECT_DIR: string; // Absolute path to project root
|
|
168
|
+
[key: string]: string; // Inherit all parent process environment variables
|
|
169
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Export all services
|
|
2
|
+
export * from "./services/aiService.js";
|
|
3
|
+
export * from "./services/memory.js";
|
|
4
|
+
export * from "./services/session.js";
|
|
5
|
+
|
|
6
|
+
// Export main agent
|
|
7
|
+
export * from "./agent.js";
|
|
8
|
+
|
|
9
|
+
// Export all utilities
|
|
10
|
+
export * from "./utils/bashHistory.js";
|
|
11
|
+
export * from "./utils/convertMessagesForAPI.js";
|
|
12
|
+
export * from "./utils/fileFilter.js";
|
|
13
|
+
export * from "./utils/mcpUtils.js";
|
|
14
|
+
export * from "./utils/messageOperations.js";
|
|
15
|
+
export * from "./utils/path.js";
|
|
16
|
+
export * from "./utils/stringUtils.js";
|
|
17
|
+
export * from "./utils/markdownParser.js";
|
|
18
|
+
export * from "./utils/customCommands.js";
|
|
19
|
+
|
|
20
|
+
// Export hooks system
|
|
21
|
+
export * from "./hooks/index.js";
|
|
22
|
+
|
|
23
|
+
// Export types
|
|
24
|
+
export * from "./types.js";
|