wave-agent-sdk 0.13.4 → 0.13.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/builtin/skills/settings/HOOKS.md +25 -0
- package/builtin/skills/settings/MCP.md +22 -0
- package/builtin/skills/settings/SKILL.md +4 -1
- package/dist/agent.d.ts +21 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +102 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/managers/aiManager.d.ts +5 -0
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +19 -4
- package/dist/managers/bangManager.d.ts +1 -0
- package/dist/managers/bangManager.d.ts.map +1 -1
- package/dist/managers/bangManager.js +1 -0
- package/dist/managers/hookManager.d.ts +5 -1
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +55 -5
- package/dist/managers/lspManager.d.ts.map +1 -1
- package/dist/managers/lspManager.js +17 -2
- package/dist/managers/mcpManager.d.ts.map +1 -1
- package/dist/managers/mcpManager.js +20 -6
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +22 -0
- package/dist/managers/messageQueue.d.ts +20 -0
- package/dist/managers/messageQueue.d.ts.map +1 -0
- package/dist/managers/messageQueue.js +29 -0
- package/dist/managers/permissionManager.d.ts +5 -7
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +27 -22
- package/dist/managers/pluginManager.d.ts.map +1 -1
- package/dist/managers/pluginManager.js +5 -3
- package/dist/managers/skillManager.d.ts.map +1 -1
- package/dist/managers/skillManager.js +5 -0
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +12 -1
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +6 -18
- package/dist/services/autoMemoryService.d.ts.map +1 -1
- package/dist/services/autoMemoryService.js +1 -0
- package/dist/services/hook.d.ts +4 -0
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +10 -0
- package/dist/services/interactionService.d.ts.map +1 -1
- package/dist/services/interactionService.js +3 -0
- package/dist/services/pluginLoader.d.ts.map +1 -1
- package/dist/services/pluginLoader.js +3 -1
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +33 -2
- package/dist/tools/types.d.ts +2 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/types/agent.d.ts +4 -0
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/hooks.d.ts +6 -1
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +4 -0
- package/dist/types/lsp.d.ts +2 -0
- package/dist/types/lsp.d.ts.map +1 -1
- package/dist/types/mcp.d.ts +2 -0
- package/dist/types/mcp.d.ts.map +1 -1
- package/dist/types/skills.d.ts +1 -0
- package/dist/types/skills.d.ts.map +1 -1
- package/dist/utils/containerSetup.d.ts.map +1 -1
- package/dist/utils/containerSetup.js +4 -1
- package/package.json +1 -1
- package/src/agent.ts +122 -2
- package/src/index.ts +1 -0
- package/src/managers/aiManager.ts +35 -5
- package/src/managers/bangManager.ts +2 -0
- package/src/managers/hookManager.ts +78 -19
- package/src/managers/lspManager.ts +23 -2
- package/src/managers/mcpManager.ts +29 -6
- package/src/managers/messageManager.ts +38 -0
- package/src/managers/messageQueue.ts +41 -0
- package/src/managers/permissionManager.ts +32 -26
- package/src/managers/pluginManager.ts +5 -3
- package/src/managers/skillManager.ts +9 -0
- package/src/managers/slashCommandManager.ts +16 -4
- package/src/managers/subagentManager.ts +10 -25
- package/src/services/autoMemoryService.ts +1 -0
- package/src/services/hook.ts +15 -0
- package/src/services/interactionService.ts +3 -0
- package/src/services/pluginLoader.ts +3 -1
- package/src/tools/bashTool.ts +39 -2
- package/src/tools/types.ts +2 -0
- package/src/types/agent.ts +4 -0
- package/src/types/hooks.ts +13 -2
- package/src/types/lsp.ts +2 -0
- package/src/types/mcp.ts +2 -0
- package/src/types/skills.ts +1 -0
- package/src/utils/containerSetup.ts +5 -1
package/src/services/hook.ts
CHANGED
|
@@ -260,6 +260,21 @@ export async function executeCommands(
|
|
|
260
260
|
return results;
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Execute a CwdChanged hook
|
|
265
|
+
*/
|
|
266
|
+
export async function executeCwdChangedHooks(
|
|
267
|
+
oldCwd: string,
|
|
268
|
+
newCwd: string,
|
|
269
|
+
context: ExtendedHookExecutionContext,
|
|
270
|
+
): Promise<HookExecutionResult[]> {
|
|
271
|
+
// CwdChanged hooks are executed through HookManager.executeCwdChangedHooks()
|
|
272
|
+
void context;
|
|
273
|
+
void oldCwd;
|
|
274
|
+
void newCwd;
|
|
275
|
+
return [];
|
|
276
|
+
}
|
|
277
|
+
|
|
263
278
|
/**
|
|
264
279
|
* Validate command safety (basic checks)
|
|
265
280
|
*/
|
|
@@ -50,6 +50,9 @@ export class InteractionService {
|
|
|
50
50
|
|
|
51
51
|
if (isValid && commandId !== undefined) {
|
|
52
52
|
// Execute valid slash command
|
|
53
|
+
// Note: executeCommand sets isLoading early (e.g., custom commands set it
|
|
54
|
+
// before bash execution). sendAIMessage() no longer guards against isLoading,
|
|
55
|
+
// so callers can safely set it early without blocking subsequent AI calls.
|
|
53
56
|
await slashCommandManager.executeCommand(commandId, args);
|
|
54
57
|
|
|
55
58
|
return;
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from "../types/index.js";
|
|
11
11
|
import { scanCommandsDirectory } from "../utils/customCommands.js";
|
|
12
12
|
import { parseSkillFile } from "../utils/skillParser.js";
|
|
13
|
+
import { resolveMcpConfig } from "../managers/mcpManager.js";
|
|
13
14
|
|
|
14
15
|
export class PluginLoader {
|
|
15
16
|
/**
|
|
@@ -94,6 +95,7 @@ export class PluginLoader {
|
|
|
94
95
|
skills.push({
|
|
95
96
|
...parsed.skillMetadata,
|
|
96
97
|
type: "project", // Plugin skills are treated as project skills
|
|
98
|
+
pluginRoot: pluginPath,
|
|
97
99
|
content: parsed.content,
|
|
98
100
|
frontmatter: parsed.frontmatter,
|
|
99
101
|
isValid: parsed.isValid,
|
|
@@ -136,7 +138,7 @@ export class PluginLoader {
|
|
|
136
138
|
const mcpPath = path.join(pluginPath, ".mcp.json");
|
|
137
139
|
try {
|
|
138
140
|
const content = await fs.readFile(mcpPath, "utf-8");
|
|
139
|
-
return JSON.parse(content) as McpConfig;
|
|
141
|
+
return resolveMcpConfig(JSON.parse(content)) as McpConfig;
|
|
140
142
|
} catch {
|
|
141
143
|
return undefined;
|
|
142
144
|
}
|
package/src/tools/bashTool.ts
CHANGED
|
@@ -230,7 +230,14 @@ Use the gh command via the Bash tool for GitHub-related tasks including working
|
|
|
230
230
|
|
|
231
231
|
// Foreground execution (original behavior)
|
|
232
232
|
return new Promise((resolve) => {
|
|
233
|
-
|
|
233
|
+
// Create a temporary file to store the CWD
|
|
234
|
+
const tempCwdFile = path.join(
|
|
235
|
+
os.tmpdir(),
|
|
236
|
+
`wave_cwd_${Date.now()}_${Math.random().toString(36).substring(2, 11)}.tmp`,
|
|
237
|
+
);
|
|
238
|
+
const wrappedCommand = `${command} && pwd -P >| ${tempCwdFile}`;
|
|
239
|
+
|
|
240
|
+
const child: ChildProcess = spawn(wrappedCommand, {
|
|
234
241
|
shell: true,
|
|
235
242
|
stdio: "pipe",
|
|
236
243
|
cwd: context.workdir,
|
|
@@ -401,7 +408,7 @@ Use the gh command via the Bash tool for GitHub-related tasks including working
|
|
|
401
408
|
}
|
|
402
409
|
});
|
|
403
410
|
|
|
404
|
-
child.on("exit", (code) => {
|
|
411
|
+
child.on("exit", async (code) => {
|
|
405
412
|
isFinished = true;
|
|
406
413
|
if (context.foregroundTaskManager) {
|
|
407
414
|
context.foregroundTaskManager.unregisterForegroundTask(
|
|
@@ -414,6 +421,36 @@ Use the gh command via the Bash tool for GitHub-related tasks including working
|
|
|
414
421
|
clearTimeout(timeoutHandle);
|
|
415
422
|
}
|
|
416
423
|
|
|
424
|
+
// Read the new CWD from the temporary file
|
|
425
|
+
let newCwd: string | undefined;
|
|
426
|
+
try {
|
|
427
|
+
if (fs.existsSync(tempCwdFile)) {
|
|
428
|
+
newCwd = fs.readFileSync(tempCwdFile, "utf8").trim();
|
|
429
|
+
// Validate the path exists before calling the callback
|
|
430
|
+
fs.accessSync(newCwd, fs.constants.F_OK);
|
|
431
|
+
}
|
|
432
|
+
} catch (fileError) {
|
|
433
|
+
logger.warn(
|
|
434
|
+
`Could not read or validate new CWD from temp file ${tempCwdFile}:`,
|
|
435
|
+
fileError,
|
|
436
|
+
);
|
|
437
|
+
newCwd = undefined;
|
|
438
|
+
} finally {
|
|
439
|
+
// Ensure temp file is cleaned up even if reading fails
|
|
440
|
+
try {
|
|
441
|
+
if (fs.existsSync(tempCwdFile)) {
|
|
442
|
+
fs.unlinkSync(tempCwdFile);
|
|
443
|
+
}
|
|
444
|
+
} catch (fileError) {
|
|
445
|
+
logger.error("Failed to clean up temp CWD file:", fileError);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// If CWD changed, call the onCwdChange callback
|
|
450
|
+
if (newCwd && newCwd !== context.workdir && context.onCwdChange) {
|
|
451
|
+
context.onCwdChange(newCwd);
|
|
452
|
+
}
|
|
453
|
+
|
|
417
454
|
const exitCode = code ?? 0;
|
|
418
455
|
const combinedOutput =
|
|
419
456
|
outputBuffer + (errorBuffer ? "\n" + errorBuffer : "");
|
package/src/tools/types.ts
CHANGED
|
@@ -103,4 +103,6 @@ export interface ToolContext {
|
|
|
103
103
|
};
|
|
104
104
|
/** State of files read in the current session for deduplication */
|
|
105
105
|
readFileState?: Map<string, { mtime: number; hash: string }>;
|
|
106
|
+
/** Callback to notify when the current working directory changes */
|
|
107
|
+
onCwdChange?: (newCwd: string) => void;
|
|
106
108
|
}
|
package/src/types/agent.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ClientOptions } from "openai";
|
|
2
|
+
import type { QueuedMessage } from "../managers/messageQueue.js";
|
|
2
3
|
import type {
|
|
3
4
|
Message,
|
|
4
5
|
Logger,
|
|
@@ -96,4 +97,7 @@ export interface AgentCallbacks
|
|
|
96
97
|
onModelChange?: (model: string) => void;
|
|
97
98
|
onConfiguredModelsChange?: (models: string[]) => void;
|
|
98
99
|
onLoadingChange?: (loading: boolean) => void;
|
|
100
|
+
onCommandRunningChange?: (running: boolean) => void;
|
|
101
|
+
onWorkdirChange?: (newCwd: string) => void;
|
|
102
|
+
onQueuedMessagesChange?: (messages: QueuedMessage[]) => void;
|
|
99
103
|
}
|
package/src/types/hooks.ts
CHANGED
|
@@ -20,7 +20,8 @@ export type HookEvent =
|
|
|
20
20
|
| "Stop"
|
|
21
21
|
| "SubagentStop"
|
|
22
22
|
| "PermissionRequest"
|
|
23
|
-
| "WorktreeCreate"
|
|
23
|
+
| "WorktreeCreate"
|
|
24
|
+
| "CwdChanged";
|
|
24
25
|
|
|
25
26
|
// Individual hook command configuration
|
|
26
27
|
export interface HookCommand {
|
|
@@ -28,6 +29,7 @@ export interface HookCommand {
|
|
|
28
29
|
command: string;
|
|
29
30
|
async?: boolean;
|
|
30
31
|
timeout?: number; // seconds
|
|
32
|
+
pluginRoot?: string; // Plugin directory path for plugin-originated hooks
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
// Hook event configuration with optional pattern matching
|
|
@@ -102,6 +104,7 @@ export function isValidHookEvent(event: string): event is HookEvent {
|
|
|
102
104
|
"SubagentStop",
|
|
103
105
|
"PermissionRequest",
|
|
104
106
|
"WorktreeCreate",
|
|
107
|
+
"CwdChanged",
|
|
105
108
|
].includes(event);
|
|
106
109
|
}
|
|
107
110
|
|
|
@@ -128,6 +131,10 @@ export function isValidHookCommand(cmd: unknown): cmd is HookCommand {
|
|
|
128
131
|
return false;
|
|
129
132
|
}
|
|
130
133
|
|
|
134
|
+
if ("pluginRoot" in hookCmd && typeof hookCmd.pluginRoot !== "string") {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
|
|
131
138
|
return true;
|
|
132
139
|
}
|
|
133
140
|
|
|
@@ -154,7 +161,7 @@ export interface HookJsonInput {
|
|
|
154
161
|
session_id: string; // Format: "wave_session_{uuid}_{shortId}"
|
|
155
162
|
transcript_path: string; // Format: "~/.wave/sessions/session_{shortId}.json"
|
|
156
163
|
cwd: string; // Absolute path to current working directory
|
|
157
|
-
hook_event_name: HookEvent; // "PreToolUse" | "PostToolUse" | "UserPromptSubmit" | "Stop" | "SubagentStop" | "PermissionRequest" | "WorktreeCreate"
|
|
164
|
+
hook_event_name: HookEvent; // "PreToolUse" | "PostToolUse" | "UserPromptSubmit" | "Stop" | "SubagentStop" | "PermissionRequest" | "WorktreeCreate" | "CwdChanged"
|
|
158
165
|
|
|
159
166
|
// Optional fields based on event type
|
|
160
167
|
tool_name?: string; // Present for PreToolUse, PostToolUse, PermissionRequest
|
|
@@ -163,6 +170,8 @@ export interface HookJsonInput {
|
|
|
163
170
|
user_prompt?: string; // Present for UserPromptSubmit only
|
|
164
171
|
subagent_type?: string; // Present when hook is executed by a subagent
|
|
165
172
|
name?: string; // Present for WorktreeCreate events
|
|
173
|
+
old_cwd?: string; // Present for CwdChanged events
|
|
174
|
+
new_cwd?: string; // Present for CwdChanged events
|
|
166
175
|
}
|
|
167
176
|
|
|
168
177
|
// Extended context interface for passing additional data to hook executor
|
|
@@ -176,6 +185,8 @@ export interface ExtendedHookExecutionContext extends HookExecutionContext {
|
|
|
176
185
|
userPrompt?: string; // User prompt text (UserPromptSubmit only)
|
|
177
186
|
subagentType?: string; // Subagent type when hook is executed by a subagent
|
|
178
187
|
worktreeName?: string; // Worktree name (WorktreeCreate only)
|
|
188
|
+
oldCwd?: string; // Previous working directory (CwdChanged only)
|
|
189
|
+
newCwd?: string; // New working directory (CwdChanged only)
|
|
179
190
|
}
|
|
180
191
|
|
|
181
192
|
// Environment variables injected into hook processes
|
package/src/types/lsp.ts
CHANGED
|
@@ -15,6 +15,8 @@ export interface LspServerConfig {
|
|
|
15
15
|
shutdownTimeout?: number;
|
|
16
16
|
restartOnCrash?: boolean;
|
|
17
17
|
maxRestarts?: number;
|
|
18
|
+
/** Internal: plugin directory path when the server is registered by a plugin */
|
|
19
|
+
pluginRoot?: string;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export interface LspConfig {
|
package/src/types/mcp.ts
CHANGED
|
@@ -9,6 +9,8 @@ export interface McpServerConfig {
|
|
|
9
9
|
env?: Record<string, string>;
|
|
10
10
|
url?: string;
|
|
11
11
|
headers?: Record<string, string>;
|
|
12
|
+
/** Internal: plugin directory path when the server is registered by a plugin */
|
|
13
|
+
pluginRoot?: string;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
export interface McpConfig {
|
package/src/types/skills.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Container } from "./container.js";
|
|
|
2
2
|
import { ForegroundTaskManager } from "../managers/foregroundTaskManager.js";
|
|
3
3
|
import { BackgroundTaskManager } from "../managers/backgroundTaskManager.js";
|
|
4
4
|
import { NotificationQueue } from "../managers/notificationQueue.js";
|
|
5
|
+
import { MessageQueue } from "../managers/messageQueue.js";
|
|
5
6
|
import { TaskManager } from "../services/taskManager.js";
|
|
6
7
|
import { MessageManager } from "../managers/messageManager.js";
|
|
7
8
|
import { AIManager } from "../managers/aiManager.js";
|
|
@@ -76,10 +77,14 @@ export function setupAgentContainer(
|
|
|
76
77
|
const callbacks = options.callbacks || {};
|
|
77
78
|
const container = new Container();
|
|
78
79
|
container.register("AgentOptions", options);
|
|
80
|
+
container.register("Workdir", workdir);
|
|
79
81
|
|
|
80
82
|
const notificationQueue = new NotificationQueue();
|
|
81
83
|
container.register("NotificationQueue", notificationQueue);
|
|
82
84
|
|
|
85
|
+
const messageQueue = new MessageQueue();
|
|
86
|
+
container.register("MessageQueue", messageQueue);
|
|
87
|
+
|
|
83
88
|
const foregroundTaskManager = new ForegroundTaskManager(container);
|
|
84
89
|
container.register("ForegroundTaskManager", foregroundTaskManager);
|
|
85
90
|
container.register("ConfigurationService", configurationService);
|
|
@@ -147,7 +152,6 @@ export function setupAgentContainer(
|
|
|
147
152
|
container.register("LspManager", lspManager);
|
|
148
153
|
|
|
149
154
|
const permissionManager = new PermissionManager(container, {
|
|
150
|
-
workdir,
|
|
151
155
|
instanceAllowedRules: options.allowedTools,
|
|
152
156
|
instanceDeniedRules: options.disallowedTools,
|
|
153
157
|
});
|