wave-agent-sdk 0.0.4 → 0.0.6
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/dist/agent.d.ts +63 -9
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +103 -27
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/managers/aiManager.d.ts +5 -2
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +121 -53
- package/dist/managers/backgroundBashManager.d.ts +1 -1
- package/dist/managers/backgroundBashManager.d.ts.map +1 -1
- package/dist/{hooks/manager.d.ts → managers/hookManager.d.ts} +26 -7
- package/dist/managers/hookManager.d.ts.map +1 -0
- package/dist/{hooks/manager.js → managers/hookManager.js} +108 -18
- package/dist/managers/mcpManager.d.ts +1 -1
- package/dist/managers/mcpManager.d.ts.map +1 -1
- package/dist/managers/mcpManager.js +5 -5
- package/dist/managers/messageManager.d.ts +29 -5
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +33 -12
- package/dist/managers/skillManager.d.ts +1 -1
- package/dist/managers/skillManager.d.ts.map +1 -1
- package/dist/managers/skillManager.js +3 -3
- package/dist/managers/slashCommandManager.d.ts +1 -1
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +1 -1
- package/dist/managers/subagentManager.d.ts +9 -12
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +43 -45
- package/dist/managers/toolManager.d.ts +1 -1
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/services/aiService.d.ts +10 -2
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +25 -4
- package/dist/services/hook.d.ts +56 -0
- package/dist/services/hook.d.ts.map +1 -0
- package/dist/services/hook.js +276 -0
- package/dist/services/memory.js +3 -3
- package/dist/services/session.d.ts +65 -16
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +85 -34
- package/dist/tools/bashTool.js +2 -2
- package/dist/tools/deleteFileTool.js +1 -1
- package/dist/tools/editTool.js +1 -1
- package/dist/tools/multiEditTool.js +2 -2
- package/dist/tools/taskTool.d.ts.map +1 -1
- package/dist/tools/taskTool.js +7 -3
- package/dist/tools/writeTool.js +1 -1
- package/dist/types/commands.d.ts +24 -0
- package/dist/types/commands.d.ts.map +1 -0
- package/dist/types/commands.js +5 -0
- package/dist/types/config.d.ts +13 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +5 -0
- package/dist/types/core.d.ts +38 -0
- package/dist/types/core.d.ts.map +1 -0
- package/dist/{types.js → types/core.js} +4 -13
- package/dist/{hooks/types.d.ts → types/hooks.d.ts} +2 -1
- package/dist/types/hooks.d.ts.map +1 -0
- package/dist/types/index.d.ts +20 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +21 -0
- package/dist/types/mcp.d.ts +28 -0
- package/dist/types/mcp.d.ts.map +1 -0
- package/dist/types/mcp.js +5 -0
- package/dist/types/messaging.d.ts +80 -0
- package/dist/types/messaging.d.ts.map +1 -0
- package/dist/types/messaging.js +5 -0
- package/dist/types/processes.d.ts +17 -0
- package/dist/types/processes.d.ts.map +1 -0
- package/dist/types/processes.js +5 -0
- package/dist/types/skills.d.ts +78 -0
- package/dist/types/skills.d.ts.map +1 -0
- package/dist/types/skills.js +17 -0
- package/dist/utils/configResolver.d.ts +1 -1
- package/dist/utils/configResolver.d.ts.map +1 -1
- package/dist/utils/configResolver.js +1 -1
- package/dist/utils/configValidator.d.ts +1 -1
- package/dist/utils/configValidator.d.ts.map +1 -1
- package/dist/utils/configValidator.js +1 -1
- package/dist/utils/convertMessagesForAPI.d.ts +1 -1
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
- package/dist/utils/customCommands.d.ts +1 -1
- package/dist/utils/customCommands.d.ts.map +1 -1
- package/dist/{hooks/matcher.d.ts → utils/hookMatcher.d.ts} +1 -1
- package/dist/utils/hookMatcher.d.ts.map +1 -0
- package/dist/utils/markdownParser.d.ts +1 -1
- package/dist/utils/markdownParser.d.ts.map +1 -1
- package/dist/utils/mcpUtils.d.ts +1 -1
- package/dist/utils/mcpUtils.d.ts.map +1 -1
- package/dist/utils/messageOperations.d.ts +7 -2
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +18 -1
- package/dist/utils/skillParser.d.ts +1 -1
- package/dist/utils/skillParser.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/agent.ts +150 -50
- package/src/index.ts +3 -4
- package/src/managers/aiManager.ts +282 -164
- package/src/managers/backgroundBashManager.ts +1 -1
- package/src/{hooks/manager.ts → managers/hookManager.ts} +163 -28
- package/src/managers/mcpManager.ts +6 -6
- package/src/managers/messageManager.ts +69 -10
- package/src/managers/skillManager.ts +4 -4
- package/src/managers/slashCommandManager.ts +6 -2
- package/src/managers/subagentManager.ts +58 -53
- package/src/managers/toolManager.ts +1 -1
- package/src/services/aiService.ts +37 -7
- package/src/services/hook.ts +360 -0
- package/src/services/memory.ts +3 -3
- package/src/services/session.ts +99 -33
- package/src/tools/bashTool.ts +2 -2
- package/src/tools/deleteFileTool.ts +1 -1
- package/src/tools/editTool.ts +1 -1
- package/src/tools/multiEditTool.ts +2 -2
- package/src/tools/taskTool.ts +13 -5
- package/src/tools/writeTool.ts +1 -1
- package/src/types/commands.ts +26 -0
- package/src/types/config.ts +14 -0
- package/src/types/core.ts +49 -0
- package/src/{hooks/types.ts → types/hooks.ts} +1 -0
- package/src/types/index.ts +23 -0
- package/src/{types.ts → types/index.ts.backup} +13 -0
- package/src/types/mcp.ts +31 -0
- package/src/types/messaging.ts +103 -0
- package/src/types/processes.ts +18 -0
- package/src/types/skills.ts +91 -0
- package/src/utils/configResolver.ts +1 -1
- package/src/utils/configValidator.ts +5 -1
- package/src/utils/convertMessagesForAPI.ts +1 -1
- package/src/utils/customCommands.ts +1 -1
- package/src/utils/markdownParser.ts +1 -1
- package/src/utils/mcpUtils.ts +1 -1
- package/src/utils/messageOperations.ts +22 -1
- package/src/utils/skillParser.ts +1 -1
- package/dist/hooks/executor.d.ts +0 -56
- package/dist/hooks/executor.d.ts.map +0 -1
- package/dist/hooks/executor.js +0 -312
- package/dist/hooks/index.d.ts +0 -17
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/index.js +0 -14
- package/dist/hooks/manager.d.ts.map +0 -1
- package/dist/hooks/matcher.d.ts.map +0 -1
- package/dist/hooks/settings.d.ts +0 -46
- package/dist/hooks/settings.d.ts.map +0 -1
- package/dist/hooks/settings.js +0 -100
- package/dist/hooks/types.d.ts.map +0 -1
- package/dist/types.d.ts +0 -276
- package/dist/types.d.ts.map +0 -1
- package/src/hooks/executor.ts +0 -440
- package/src/hooks/index.ts +0 -52
- package/src/hooks/settings.ts +0 -129
- /package/dist/{hooks/types.js → types/hooks.js} +0 -0
- /package/dist/{hooks/matcher.js → utils/hookMatcher.js} +0 -0
- /package/src/{hooks/matcher.ts → utils/hookMatcher.ts} +0 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook Services
|
|
3
|
+
*
|
|
4
|
+
* Consolidated hook services providing both execution and configuration functionality.
|
|
5
|
+
* Combines hook command execution and settings management into a single module.
|
|
6
|
+
*/
|
|
7
|
+
import { type HookExecutionContext, type HookExecutionResult, type HookExecutionOptions, type ExtendedHookExecutionContext, type PartialHookConfiguration } from "../types/hooks.js";
|
|
8
|
+
/**
|
|
9
|
+
* Execute a single hook command
|
|
10
|
+
*/
|
|
11
|
+
export declare function executeCommand(command: string, context: HookExecutionContext | ExtendedHookExecutionContext, options?: HookExecutionOptions): Promise<HookExecutionResult>;
|
|
12
|
+
/**
|
|
13
|
+
* Execute multiple commands in sequence
|
|
14
|
+
*/
|
|
15
|
+
export declare function executeCommands(commands: string[], context: HookExecutionContext | ExtendedHookExecutionContext, options?: HookExecutionOptions): Promise<HookExecutionResult[]>;
|
|
16
|
+
/**
|
|
17
|
+
* Validate command safety (basic checks)
|
|
18
|
+
*/
|
|
19
|
+
export declare function isCommandSafe(command: string): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Get the user-specific hooks configuration file path
|
|
22
|
+
*/
|
|
23
|
+
export declare function getUserHooksConfigPath(): string;
|
|
24
|
+
/**
|
|
25
|
+
* Get the project-specific hooks configuration file path
|
|
26
|
+
*/
|
|
27
|
+
export declare function getProjectHooksConfigPath(workdir: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Load hooks configuration from a JSON file
|
|
30
|
+
*/
|
|
31
|
+
export declare function loadHooksConfigFromFile(filePath: string): PartialHookConfiguration | null;
|
|
32
|
+
/**
|
|
33
|
+
* Load user-specific hooks configuration
|
|
34
|
+
*/
|
|
35
|
+
export declare function loadUserHooksConfig(): PartialHookConfiguration | null;
|
|
36
|
+
/**
|
|
37
|
+
* Load project-specific hooks configuration
|
|
38
|
+
*/
|
|
39
|
+
export declare function loadProjectHooksConfig(workdir: string): PartialHookConfiguration | null;
|
|
40
|
+
/**
|
|
41
|
+
* Load and merge hooks configuration from both user and project sources
|
|
42
|
+
*/
|
|
43
|
+
export declare function loadMergedHooksConfig(workdir: string): PartialHookConfiguration | null;
|
|
44
|
+
/**
|
|
45
|
+
* Check if hooks configuration exists (user or project)
|
|
46
|
+
*/
|
|
47
|
+
export declare function hasHooksConfiguration(workdir: string): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Get hooks configuration information for debugging
|
|
50
|
+
*/
|
|
51
|
+
export declare function getHooksConfigurationInfo(workdir: string): {
|
|
52
|
+
hasUser: boolean;
|
|
53
|
+
hasProject: boolean;
|
|
54
|
+
paths: string[];
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=hook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.d.ts","sourceRoot":"","sources":["../../src/services/hook.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,4BAA4B,EAGjC,KAAK,wBAAwB,EAG9B,MAAM,mBAAmB,CAAC;AA6C3B;;GAEG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,oBAAoB,GAAG,4BAA4B,EAC5D,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAiH9B;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAAE,EAClB,OAAO,EAAE,oBAAoB,GAAG,4BAA4B,EAC5D,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAchC;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAsBtD;AAMD;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,MAAM,GACf,wBAAwB,GAAG,IAAI,CAcjC;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,wBAAwB,GAAG,IAAI,CAErE;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,GACd,wBAAwB,GAAG,IAAI,CAEjC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,GACd,wBAAwB,GAAG,IAAI,CAiCjC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAK9D;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG;IAC1D,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB,CASA"}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook Services
|
|
3
|
+
*
|
|
4
|
+
* Consolidated hook services providing both execution and configuration functionality.
|
|
5
|
+
* Combines hook command execution and settings management into a single module.
|
|
6
|
+
*/
|
|
7
|
+
import { spawn } from "child_process";
|
|
8
|
+
import { existsSync, readFileSync } from "fs";
|
|
9
|
+
import { join } from "path";
|
|
10
|
+
import { homedir } from "os";
|
|
11
|
+
import { getSessionFilePath, isValidHookEvent, } from "../types/hooks.js";
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// Hook Execution Functions
|
|
14
|
+
// =============================================================================
|
|
15
|
+
/**
|
|
16
|
+
* Build JSON input data for hook stdin
|
|
17
|
+
*/
|
|
18
|
+
function buildHookJsonInput(context) {
|
|
19
|
+
const jsonInput = {
|
|
20
|
+
session_id: context.sessionId || "unknown",
|
|
21
|
+
transcript_path: context.transcriptPath ||
|
|
22
|
+
(context.sessionId ? getSessionFilePath(context.sessionId) : ""),
|
|
23
|
+
cwd: context.cwd || context.projectDir,
|
|
24
|
+
hook_event_name: context.event,
|
|
25
|
+
};
|
|
26
|
+
// Add optional fields based on event type
|
|
27
|
+
if (context.event === "PreToolUse" || context.event === "PostToolUse") {
|
|
28
|
+
if (context.toolName) {
|
|
29
|
+
jsonInput.tool_name = context.toolName;
|
|
30
|
+
}
|
|
31
|
+
if (context.toolInput !== undefined) {
|
|
32
|
+
jsonInput.tool_input = context.toolInput;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (context.event === "PostToolUse" && context.toolResponse !== undefined) {
|
|
36
|
+
jsonInput.tool_response = context.toolResponse;
|
|
37
|
+
}
|
|
38
|
+
if (context.event === "UserPromptSubmit" &&
|
|
39
|
+
context.userPrompt !== undefined) {
|
|
40
|
+
jsonInput.user_prompt = context.userPrompt;
|
|
41
|
+
}
|
|
42
|
+
return jsonInput;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Execute a single hook command
|
|
46
|
+
*/
|
|
47
|
+
export async function executeCommand(command, context, options) {
|
|
48
|
+
const defaultTimeout = 10000; // 10 seconds
|
|
49
|
+
const maxTimeout = 300000; // 5 minutes
|
|
50
|
+
const skipExecution = process.env.NODE_ENV === "test" &&
|
|
51
|
+
process.env.TEST_HOOK_EXECUTION !== "true";
|
|
52
|
+
const startTime = Date.now();
|
|
53
|
+
const timeout = Math.min(options?.timeout ?? defaultTimeout, maxTimeout);
|
|
54
|
+
// Return mock result if execution is skipped
|
|
55
|
+
if (skipExecution) {
|
|
56
|
+
return {
|
|
57
|
+
success: true,
|
|
58
|
+
exitCode: 0,
|
|
59
|
+
stdout: "",
|
|
60
|
+
stderr: "",
|
|
61
|
+
duration: 0,
|
|
62
|
+
timedOut: false,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return new Promise((resolve) => {
|
|
66
|
+
let stdout = "";
|
|
67
|
+
let stderr = "";
|
|
68
|
+
let timedOut = false;
|
|
69
|
+
// Parse command for shell execution
|
|
70
|
+
const isWindows = process.platform === "win32";
|
|
71
|
+
const shell = isWindows ? "cmd.exe" : "/bin/sh";
|
|
72
|
+
const shellFlag = isWindows ? "/c" : "-c";
|
|
73
|
+
const childProcess = spawn(shell, [shellFlag, command], {
|
|
74
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
75
|
+
cwd: context.projectDir,
|
|
76
|
+
env: {
|
|
77
|
+
...process.env,
|
|
78
|
+
HOOK_EVENT: context.event,
|
|
79
|
+
HOOK_TOOL_NAME: context.toolName || "",
|
|
80
|
+
HOOK_PROJECT_DIR: context.projectDir,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
// Set up timeout
|
|
84
|
+
const timeoutHandle = setTimeout(() => {
|
|
85
|
+
timedOut = true;
|
|
86
|
+
childProcess.kill("SIGTERM");
|
|
87
|
+
// Force kill after additional delay
|
|
88
|
+
setTimeout(() => {
|
|
89
|
+
if (!childProcess.killed) {
|
|
90
|
+
childProcess.kill("SIGKILL");
|
|
91
|
+
}
|
|
92
|
+
}, 2000);
|
|
93
|
+
}, timeout);
|
|
94
|
+
// Handle stdout
|
|
95
|
+
if (childProcess.stdout) {
|
|
96
|
+
childProcess.stdout.on("data", (data) => {
|
|
97
|
+
stdout += data.toString();
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
// Handle stderr
|
|
101
|
+
if (childProcess.stderr) {
|
|
102
|
+
childProcess.stderr.on("data", (data) => {
|
|
103
|
+
stderr += data.toString();
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// Send JSON input to stdin if we have extended context
|
|
107
|
+
if (childProcess.stdin && "sessionId" in context) {
|
|
108
|
+
try {
|
|
109
|
+
const jsonInput = buildHookJsonInput(context);
|
|
110
|
+
childProcess.stdin.write(JSON.stringify(jsonInput, null, 2));
|
|
111
|
+
childProcess.stdin.end();
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Continue execution even if JSON input fails
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else if (childProcess.stdin) {
|
|
118
|
+
childProcess.stdin.end();
|
|
119
|
+
}
|
|
120
|
+
// Handle process completion
|
|
121
|
+
childProcess.on("close", (code) => {
|
|
122
|
+
clearTimeout(timeoutHandle);
|
|
123
|
+
const duration = Date.now() - startTime;
|
|
124
|
+
resolve({
|
|
125
|
+
success: !timedOut && (code === 0 || code === null),
|
|
126
|
+
exitCode: code || 0,
|
|
127
|
+
stdout: stdout.trim(),
|
|
128
|
+
stderr: stderr.trim(),
|
|
129
|
+
duration,
|
|
130
|
+
timedOut,
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
// Handle process errors
|
|
134
|
+
childProcess.on("error", (error) => {
|
|
135
|
+
clearTimeout(timeoutHandle);
|
|
136
|
+
const duration = Date.now() - startTime;
|
|
137
|
+
resolve({
|
|
138
|
+
success: false,
|
|
139
|
+
exitCode: 1,
|
|
140
|
+
stdout: stdout.trim(),
|
|
141
|
+
stderr: error.message,
|
|
142
|
+
duration,
|
|
143
|
+
timedOut,
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Execute multiple commands in sequence
|
|
150
|
+
*/
|
|
151
|
+
export async function executeCommands(commands, context, options) {
|
|
152
|
+
const results = [];
|
|
153
|
+
for (const command of commands) {
|
|
154
|
+
const result = await executeCommand(command, context, options);
|
|
155
|
+
results.push(result);
|
|
156
|
+
// Stop on first failure unless continueOnFailure is set
|
|
157
|
+
if (!result.success && !options?.continueOnFailure) {
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return results;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Validate command safety (basic checks)
|
|
165
|
+
*/
|
|
166
|
+
export function isCommandSafe(command) {
|
|
167
|
+
const trimmed = command.trim();
|
|
168
|
+
// Empty commands are safe (no-op)
|
|
169
|
+
if (!trimmed) {
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
// Check for obviously dangerous patterns
|
|
173
|
+
const dangerousPatterns = [
|
|
174
|
+
/rm\s+-rf\s+\//, // rm -rf /
|
|
175
|
+
/sudo\s+rm/, // sudo rm
|
|
176
|
+
/>\s*\/dev\/sd[a-z]/, // writing to disk devices
|
|
177
|
+
/dd\s+if=.*of=\/dev/, // dd to devices
|
|
178
|
+
/mkfs/, // filesystem creation
|
|
179
|
+
/fdisk/, // disk partitioning
|
|
180
|
+
/format\s+[a-z]:/, // Windows format command
|
|
181
|
+
];
|
|
182
|
+
return !dangerousPatterns.some((pattern) => pattern.test(trimmed.toLowerCase()));
|
|
183
|
+
}
|
|
184
|
+
// =============================================================================
|
|
185
|
+
// Hook Settings Functions
|
|
186
|
+
// =============================================================================
|
|
187
|
+
/**
|
|
188
|
+
* Get the user-specific hooks configuration file path
|
|
189
|
+
*/
|
|
190
|
+
export function getUserHooksConfigPath() {
|
|
191
|
+
return join(homedir(), ".wave", "settings.json");
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Get the project-specific hooks configuration file path
|
|
195
|
+
*/
|
|
196
|
+
export function getProjectHooksConfigPath(workdir) {
|
|
197
|
+
return join(workdir, ".wave", "settings.json");
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Load hooks configuration from a JSON file
|
|
201
|
+
*/
|
|
202
|
+
export function loadHooksConfigFromFile(filePath) {
|
|
203
|
+
if (!existsSync(filePath)) {
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
const content = readFileSync(filePath, "utf-8");
|
|
207
|
+
const config = JSON.parse(content);
|
|
208
|
+
// Validate basic structure
|
|
209
|
+
if (!config || typeof config !== "object" || !config.hooks) {
|
|
210
|
+
throw new Error(`Invalid hooks configuration structure in ${filePath}`);
|
|
211
|
+
}
|
|
212
|
+
return config.hooks;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Load user-specific hooks configuration
|
|
216
|
+
*/
|
|
217
|
+
export function loadUserHooksConfig() {
|
|
218
|
+
return loadHooksConfigFromFile(getUserHooksConfigPath());
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Load project-specific hooks configuration
|
|
222
|
+
*/
|
|
223
|
+
export function loadProjectHooksConfig(workdir) {
|
|
224
|
+
return loadHooksConfigFromFile(getProjectHooksConfigPath(workdir));
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Load and merge hooks configuration from both user and project sources
|
|
228
|
+
*/
|
|
229
|
+
export function loadMergedHooksConfig(workdir) {
|
|
230
|
+
const userConfig = loadUserHooksConfig();
|
|
231
|
+
const projectConfig = loadProjectHooksConfig(workdir);
|
|
232
|
+
// No configuration found
|
|
233
|
+
if (!userConfig && !projectConfig) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
// Only one configuration found
|
|
237
|
+
if (!userConfig)
|
|
238
|
+
return projectConfig;
|
|
239
|
+
if (!projectConfig)
|
|
240
|
+
return userConfig;
|
|
241
|
+
// Merge configurations (project overrides user)
|
|
242
|
+
const merged = {};
|
|
243
|
+
// Combine all hook events
|
|
244
|
+
const allEvents = new Set([
|
|
245
|
+
...Object.keys(userConfig),
|
|
246
|
+
...Object.keys(projectConfig),
|
|
247
|
+
]);
|
|
248
|
+
for (const event of allEvents) {
|
|
249
|
+
if (!isValidHookEvent(event))
|
|
250
|
+
continue;
|
|
251
|
+
const userEventConfigs = userConfig[event] || [];
|
|
252
|
+
const projectEventConfigs = projectConfig[event] || [];
|
|
253
|
+
// Project configurations take precedence
|
|
254
|
+
merged[event] = [...userEventConfigs, ...projectEventConfigs];
|
|
255
|
+
}
|
|
256
|
+
return merged;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Check if hooks configuration exists (user or project)
|
|
260
|
+
*/
|
|
261
|
+
export function hasHooksConfiguration(workdir) {
|
|
262
|
+
return (existsSync(getUserHooksConfigPath()) ||
|
|
263
|
+
existsSync(getProjectHooksConfigPath(workdir)));
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Get hooks configuration information for debugging
|
|
267
|
+
*/
|
|
268
|
+
export function getHooksConfigurationInfo(workdir) {
|
|
269
|
+
const userPath = getUserHooksConfigPath();
|
|
270
|
+
const projectPath = getProjectHooksConfigPath(workdir);
|
|
271
|
+
return {
|
|
272
|
+
hasUser: existsSync(userPath),
|
|
273
|
+
hasProject: existsSync(projectPath),
|
|
274
|
+
paths: [userPath, projectPath],
|
|
275
|
+
};
|
|
276
|
+
}
|
package/dist/services/memory.js
CHANGED
|
@@ -32,7 +32,7 @@ export const addMemory = async (message, workdir) => {
|
|
|
32
32
|
const updatedContent = existingContent + memoryEntry;
|
|
33
33
|
// Write file
|
|
34
34
|
await fs.writeFile(memoryFilePath, updatedContent, "utf-8");
|
|
35
|
-
// logger.
|
|
35
|
+
// logger.debug(`Memory added to ${memoryFilePath}:`, message);
|
|
36
36
|
}
|
|
37
37
|
catch (error) {
|
|
38
38
|
// logger.error("Failed to add memory:", error);
|
|
@@ -53,7 +53,7 @@ export const ensureUserMemoryFile = async () => {
|
|
|
53
53
|
if (error.code === "ENOENT") {
|
|
54
54
|
const initialContent = "# User Memory\n\nThis is the user-level memory file, recording important information and context across projects.\n\n";
|
|
55
55
|
await fs.writeFile(USER_MEMORY_FILE, initialContent, "utf-8");
|
|
56
|
-
// logger.
|
|
56
|
+
// logger.debug(`Created user memory file: ${USER_MEMORY_FILE}`);
|
|
57
57
|
}
|
|
58
58
|
else {
|
|
59
59
|
throw error;
|
|
@@ -77,7 +77,7 @@ export const addUserMemory = async (message) => {
|
|
|
77
77
|
const updatedContent = existingContent + memoryEntry;
|
|
78
78
|
// Write file
|
|
79
79
|
await fs.writeFile(USER_MEMORY_FILE, updatedContent, "utf-8");
|
|
80
|
-
// logger.
|
|
80
|
+
// logger.debug(`User memory added to ${USER_MEMORY_FILE}:`, message);
|
|
81
81
|
}
|
|
82
82
|
catch (error) {
|
|
83
83
|
// logger.error("Failed to add user memory:", error);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Message } from "../types.js";
|
|
1
|
+
import type { Message } from "../types/index.js";
|
|
2
2
|
export interface SessionData {
|
|
3
3
|
id: string;
|
|
4
4
|
timestamp: string;
|
|
@@ -19,36 +19,85 @@ export interface SessionMetadata {
|
|
|
19
19
|
lastActiveAt: string;
|
|
20
20
|
latestTotalTokens: number;
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Resolve session directory path with fallback to default
|
|
24
|
+
* @param sessionDir Optional custom session directory
|
|
25
|
+
* @returns Resolved session directory path
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveSessionDir(sessionDir?: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Ensure session directory exists
|
|
30
|
+
* @param sessionDir Optional custom session directory
|
|
31
|
+
*/
|
|
32
|
+
export declare function ensureSessionDir(sessionDir?: string): Promise<void>;
|
|
22
33
|
/**
|
|
23
34
|
* Generate session file path
|
|
24
35
|
*/
|
|
25
|
-
export declare function getSessionFilePath(sessionId: string): string;
|
|
36
|
+
export declare function getSessionFilePath(sessionId: string, sessionDir?: string): string;
|
|
26
37
|
/**
|
|
27
|
-
* Save session data
|
|
38
|
+
* Save session data to storage
|
|
39
|
+
*
|
|
40
|
+
* @param sessionId - Unique identifier for the session
|
|
41
|
+
* @param messages - Array of messages to save
|
|
42
|
+
* @param workdir - Working directory for the session
|
|
43
|
+
* @param latestTotalTokens - Total tokens used in the session
|
|
44
|
+
* @param startedAt - ISO timestamp when session started (defaults to current time)
|
|
45
|
+
* @param sessionDir - Optional custom directory for session storage (defaults to ~/.wave/sessions/)
|
|
46
|
+
* @throws {Error} When session cannot be saved due to permission or disk space issues
|
|
28
47
|
*/
|
|
29
|
-
export declare function saveSession(sessionId: string, messages: Message[], workdir: string, latestTotalTokens?: number, startedAt?: string): Promise<void>;
|
|
48
|
+
export declare function saveSession(sessionId: string, messages: Message[], workdir: string, latestTotalTokens?: number, startedAt?: string, sessionDir?: string): Promise<void>;
|
|
30
49
|
/**
|
|
31
|
-
* Load session data
|
|
50
|
+
* Load session data from storage
|
|
51
|
+
*
|
|
52
|
+
* @param sessionId - Unique identifier for the session to load
|
|
53
|
+
* @param sessionDir - Optional custom directory for session storage (defaults to ~/.wave/sessions/)
|
|
54
|
+
* @returns Promise that resolves to session data or null if session doesn't exist
|
|
55
|
+
* @throws {Error} When session exists but cannot be read or contains invalid data
|
|
32
56
|
*/
|
|
33
|
-
export declare function loadSession(sessionId: string): Promise<SessionData | null>;
|
|
57
|
+
export declare function loadSession(sessionId: string, sessionDir?: string): Promise<SessionData | null>;
|
|
34
58
|
/**
|
|
35
|
-
* Get most recent session
|
|
59
|
+
* Get the most recent session for a specific working directory
|
|
60
|
+
*
|
|
61
|
+
* @param workdir - Working directory to find the most recent session for
|
|
62
|
+
* @param sessionDir - Optional custom directory for session storage (defaults to ~/.wave/sessions/)
|
|
63
|
+
* @returns Promise that resolves to the most recent session data or null if no sessions exist
|
|
64
|
+
* @throws {Error} When session directory cannot be accessed or session data is corrupted
|
|
36
65
|
*/
|
|
37
|
-
export declare function getLatestSession(workdir: string): Promise<SessionData | null>;
|
|
66
|
+
export declare function getLatestSession(workdir: string, sessionDir?: string): Promise<SessionData | null>;
|
|
38
67
|
/**
|
|
39
|
-
* List all sessions
|
|
68
|
+
* List all sessions for a specific working directory or across all working directories
|
|
69
|
+
*
|
|
70
|
+
* @param workdir - Working directory to filter sessions by
|
|
71
|
+
* @param includeAllWorkdirs - If true, returns sessions from all working directories
|
|
72
|
+
* @param sessionDir - Optional custom directory for session storage (defaults to ~/.wave/sessions/)
|
|
73
|
+
* @returns Promise that resolves to array of session metadata objects
|
|
74
|
+
* @throws {Error} When session directory cannot be accessed or read
|
|
40
75
|
*/
|
|
41
|
-
export declare function listSessions(workdir: string, includeAllWorkdirs?: boolean): Promise<SessionMetadata[]>;
|
|
76
|
+
export declare function listSessions(workdir: string, includeAllWorkdirs?: boolean, sessionDir?: string): Promise<SessionMetadata[]>;
|
|
42
77
|
/**
|
|
43
|
-
* Delete session
|
|
78
|
+
* Delete a session from storage
|
|
79
|
+
*
|
|
80
|
+
* @param sessionId - Unique identifier for the session to delete
|
|
81
|
+
* @param sessionDir - Optional custom directory for session storage (defaults to ~/.wave/sessions/)
|
|
82
|
+
* @returns Promise that resolves to true if session was deleted, false if it didn't exist
|
|
83
|
+
* @throws {Error} When session exists but cannot be deleted due to permission issues
|
|
44
84
|
*/
|
|
45
|
-
export declare function deleteSession(sessionId: string): Promise<boolean>;
|
|
85
|
+
export declare function deleteSession(sessionId: string, sessionDir?: string): Promise<boolean>;
|
|
46
86
|
/**
|
|
47
|
-
* Clean up expired sessions
|
|
87
|
+
* Clean up expired sessions older than the configured maximum age
|
|
88
|
+
*
|
|
89
|
+
* @param workdir - Working directory to clean up sessions for
|
|
90
|
+
* @param sessionDir - Optional custom directory for session storage (defaults to ~/.wave/sessions/)
|
|
91
|
+
* @returns Promise that resolves to the number of sessions that were deleted
|
|
92
|
+
* @throws {Error} When session directory cannot be accessed or sessions cannot be deleted
|
|
48
93
|
*/
|
|
49
|
-
export declare function cleanupExpiredSessions(workdir: string): Promise<number>;
|
|
94
|
+
export declare function cleanupExpiredSessions(workdir: string, sessionDir?: string): Promise<number>;
|
|
50
95
|
/**
|
|
51
|
-
* Check if session exists
|
|
96
|
+
* Check if a session exists in storage
|
|
97
|
+
*
|
|
98
|
+
* @param sessionId - Unique identifier for the session to check
|
|
99
|
+
* @param sessionDir - Optional custom directory for session storage (defaults to ~/.wave/sessions/)
|
|
100
|
+
* @returns Promise that resolves to true if session exists, false otherwise
|
|
52
101
|
*/
|
|
53
|
-
export declare function sessionExists(sessionId: string): Promise<boolean>;
|
|
102
|
+
export declare function sessionExists(sessionId: string, sessionDir?: string): Promise<boolean>;
|
|
54
103
|
//# sourceMappingURL=session.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/services/session.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/services/session.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAEjD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,QAAQ,EAAE;QACR,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAOD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOzE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAIR;AAcD;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,OAAO,EAAE,EACnB,OAAO,EAAE,MAAM,EACf,iBAAiB,GAAE,MAAU,EAC7B,SAAS,CAAC,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC,CAoCf;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAmB7B;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAa7B;AAED;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,kBAAkB,UAAQ,EAC1B,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,EAAE,CAAC,CA4C5B;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC,CAYlB;AAED;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,CAAC,CA2BjB;AAED;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC,CASlB"}
|