wave-agent-sdk 0.10.4 → 0.11.0
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 +8 -6
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +12 -9
- package/dist/builtin-skills/builtin-skills/loop/SKILL.md +53 -0
- package/dist/builtin-skills/builtin-skills/loop/parsing.ts +159 -0
- package/dist/builtin-skills/builtin-skills/settings/HOOKS.md +82 -0
- package/dist/builtin-skills/{settings → builtin-skills/settings}/SKILL.md +1 -1
- package/dist/builtin-skills/loop/parsing.d.ts +13 -0
- package/dist/builtin-skills/loop/parsing.d.ts.map +1 -0
- package/dist/builtin-skills/loop/parsing.js +125 -0
- package/dist/constants/tools.d.ts +3 -0
- package/dist/constants/tools.d.ts.map +1 -1
- package/dist/constants/tools.js +3 -0
- 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 +0 -2
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +53 -14
- package/dist/managers/cronManager.d.ts +19 -0
- package/dist/managers/cronManager.d.ts.map +1 -0
- package/dist/managers/cronManager.js +124 -0
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +21 -13
- package/dist/managers/liveConfigManager.js +1 -1
- package/dist/managers/mcpManager.d.ts +1 -1
- package/dist/managers/mcpManager.d.ts.map +1 -1
- package/dist/managers/mcpManager.js +10 -2
- package/dist/managers/messageManager.d.ts +0 -1
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.d.ts +27 -7
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +119 -14
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +11 -0
- package/dist/managers/subagentManager.d.ts +3 -0
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +10 -17
- package/dist/managers/toolManager.d.ts +1 -1
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +28 -4
- package/dist/services/configurationService.d.ts.map +1 -1
- package/dist/services/configurationService.js +8 -7
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +3 -10
- package/dist/services/initializationService.js +2 -2
- package/dist/services/jsonlHandler.d.ts.map +1 -1
- package/dist/services/jsonlHandler.js +3 -0
- package/dist/services/reversionService.d.ts +2 -2
- package/dist/services/reversionService.d.ts.map +1 -1
- package/dist/services/reversionService.js +3 -3
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +18 -11
- package/dist/tools/agentTool.js +1 -1
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +5 -5
- package/dist/tools/cronCreateTool.d.ts +3 -0
- package/dist/tools/cronCreateTool.d.ts.map +1 -0
- package/dist/tools/cronCreateTool.js +59 -0
- package/dist/tools/cronDeleteTool.d.ts +3 -0
- package/dist/tools/cronDeleteTool.d.ts.map +1 -0
- package/dist/tools/cronDeleteTool.js +38 -0
- package/dist/tools/cronListTool.d.ts +3 -0
- package/dist/tools/cronListTool.d.ts.map +1 -0
- package/dist/tools/cronListTool.js +30 -0
- package/dist/tools/skillTool.d.ts +0 -3
- package/dist/tools/skillTool.d.ts.map +1 -1
- package/dist/tools/skillTool.js +4 -3
- package/dist/tools/taskOutputTool.d.ts.map +1 -1
- package/dist/tools/taskOutputTool.js +15 -8
- package/dist/tools/types.d.ts +2 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/types/agent.d.ts +10 -0
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/configuration.d.ts +1 -1
- package/dist/types/configuration.d.ts.map +1 -1
- package/dist/types/cron.d.ts +10 -0
- package/dist/types/cron.d.ts.map +1 -0
- package/dist/types/cron.js +1 -0
- package/dist/types/hooks.d.ts +1 -5
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/messaging.d.ts +1 -1
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/utils/containerSetup.d.ts.map +1 -1
- package/dist/utils/containerSetup.js +40 -13
- package/dist/utils/mcpUtils.d.ts +2 -2
- package/dist/utils/mcpUtils.d.ts.map +1 -1
- package/dist/utils/mcpUtils.js +1 -5
- package/package.json +2 -1
- package/src/agent.ts +17 -12
- package/src/builtin-skills/loop/SKILL.md +53 -0
- package/src/builtin-skills/loop/parsing.ts +159 -0
- package/src/builtin-skills/settings/HOOKS.md +44 -57
- package/src/builtin-skills/settings/SKILL.md +1 -1
- package/src/constants/tools.ts +3 -0
- package/src/index.ts +1 -0
- package/src/managers/aiManager.ts +72 -24
- package/src/managers/cronManager.ts +167 -0
- package/src/managers/hookManager.ts +27 -13
- package/src/managers/liveConfigManager.ts +2 -2
- package/src/managers/mcpManager.ts +23 -2
- package/src/managers/messageManager.ts +0 -6
- package/src/managers/permissionManager.ts +154 -18
- package/src/managers/slashCommandManager.ts +12 -0
- package/src/managers/subagentManager.ts +15 -19
- package/src/managers/toolManager.ts +37 -4
- package/src/services/configurationService.ts +8 -7
- package/src/services/hook.ts +5 -11
- package/src/services/initializationService.ts +3 -3
- package/src/services/jsonlHandler.ts +4 -0
- package/src/services/reversionService.ts +9 -4
- package/src/services/session.ts +19 -12
- package/src/tools/agentTool.ts +1 -1
- package/src/tools/bashTool.ts +6 -5
- package/src/tools/cronCreateTool.ts +73 -0
- package/src/tools/cronDeleteTool.ts +47 -0
- package/src/tools/cronListTool.ts +38 -0
- package/src/tools/skillTool.ts +6 -4
- package/src/tools/taskOutputTool.ts +14 -8
- package/src/tools/types.ts +2 -0
- package/src/types/agent.ts +10 -0
- package/src/types/configuration.ts +1 -1
- package/src/types/cron.ts +9 -0
- package/src/types/hooks.ts +5 -9
- package/src/types/index.ts +1 -0
- package/src/types/messaging.ts +1 -1
- package/src/utils/containerSetup.ts +50 -16
- package/src/utils/mcpUtils.ts +2 -5
- package/dist/builtin-skills/settings/HOOKS.md +0 -95
package/src/tools/bashTool.ts
CHANGED
|
@@ -377,11 +377,12 @@ Usage notes:
|
|
|
377
377
|
combinedOutput || `Command executed with exit code: ${exitCode}`;
|
|
378
378
|
const content = processOutput(finalOutput);
|
|
379
379
|
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
.
|
|
383
|
-
|
|
384
|
-
|
|
380
|
+
const lines = combinedOutput.trim().split("\n");
|
|
381
|
+
const shortResult =
|
|
382
|
+
lines.length <= 3
|
|
383
|
+
? lines.join("\n")
|
|
384
|
+
: lines.slice(0, 3).join("\n") +
|
|
385
|
+
`\n... +${lines.length - 3} lines`;
|
|
385
386
|
|
|
386
387
|
resolve({
|
|
387
388
|
success: exitCode === 0,
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { ToolPlugin, ToolResult, ToolContext } from "./types.js";
|
|
2
|
+
import { CRON_CREATE_TOOL_NAME } from "../constants/tools.js";
|
|
3
|
+
|
|
4
|
+
export const cronCreateTool: ToolPlugin = {
|
|
5
|
+
name: CRON_CREATE_TOOL_NAME,
|
|
6
|
+
config: {
|
|
7
|
+
type: "function",
|
|
8
|
+
function: {
|
|
9
|
+
name: CRON_CREATE_TOOL_NAME,
|
|
10
|
+
description:
|
|
11
|
+
"Schedule a prompt to be enqueued at a future time. Use for both recurring schedules and one-shot reminders.",
|
|
12
|
+
parameters: {
|
|
13
|
+
type: "object",
|
|
14
|
+
properties: {
|
|
15
|
+
cron: {
|
|
16
|
+
type: "string",
|
|
17
|
+
description:
|
|
18
|
+
'Standard 5-field cron expression in local time: "M H DoM Mon DoW"',
|
|
19
|
+
},
|
|
20
|
+
prompt: {
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "The prompt to enqueue at each fire time",
|
|
23
|
+
},
|
|
24
|
+
recurring: {
|
|
25
|
+
type: "boolean",
|
|
26
|
+
description:
|
|
27
|
+
"Default: true. true = fire on every cron match until deleted or auto-expired after 7 days. false = fire once at the next match, then auto-delete",
|
|
28
|
+
default: true,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
required: ["cron", "prompt"],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
execute: async (
|
|
36
|
+
args: Record<string, unknown>,
|
|
37
|
+
context: ToolContext,
|
|
38
|
+
): Promise<ToolResult> => {
|
|
39
|
+
const {
|
|
40
|
+
cron,
|
|
41
|
+
prompt,
|
|
42
|
+
recurring = true,
|
|
43
|
+
} = args as { cron: string; prompt: string; recurring?: boolean };
|
|
44
|
+
|
|
45
|
+
if (!context.cronManager) {
|
|
46
|
+
return {
|
|
47
|
+
success: false,
|
|
48
|
+
content: "",
|
|
49
|
+
error: "CronManager not available",
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const job = context.cronManager.createJob({
|
|
55
|
+
cron,
|
|
56
|
+
prompt,
|
|
57
|
+
recurring,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
success: true,
|
|
62
|
+
content: JSON.stringify({ id: job.id }, null, 2),
|
|
63
|
+
shortResult: `Scheduled job ${job.id}`,
|
|
64
|
+
};
|
|
65
|
+
} catch (error) {
|
|
66
|
+
return {
|
|
67
|
+
success: false,
|
|
68
|
+
content: "",
|
|
69
|
+
error: error instanceof Error ? error.message : String(error),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ToolPlugin, ToolResult, ToolContext } from "./types.js";
|
|
2
|
+
import { CRON_DELETE_TOOL_NAME } from "../constants/tools.js";
|
|
3
|
+
|
|
4
|
+
export const cronDeleteTool: ToolPlugin = {
|
|
5
|
+
name: CRON_DELETE_TOOL_NAME,
|
|
6
|
+
config: {
|
|
7
|
+
type: "function",
|
|
8
|
+
function: {
|
|
9
|
+
name: CRON_DELETE_TOOL_NAME,
|
|
10
|
+
description:
|
|
11
|
+
"Cancel a cron job previously scheduled with CronCreate. Removes it from the in-memory session store.",
|
|
12
|
+
parameters: {
|
|
13
|
+
type: "object",
|
|
14
|
+
properties: {
|
|
15
|
+
id: {
|
|
16
|
+
type: "string",
|
|
17
|
+
description: "Job ID returned by CronCreate",
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
required: ["id"],
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
execute: async (
|
|
25
|
+
args: Record<string, unknown>,
|
|
26
|
+
context: ToolContext,
|
|
27
|
+
): Promise<ToolResult> => {
|
|
28
|
+
const { id } = args as { id: string };
|
|
29
|
+
|
|
30
|
+
if (!context.cronManager) {
|
|
31
|
+
return {
|
|
32
|
+
success: false,
|
|
33
|
+
content: "",
|
|
34
|
+
error: "CronManager not available",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const success = context.cronManager.deleteJob(id);
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
success,
|
|
42
|
+
content: JSON.stringify({ success }, null, 2),
|
|
43
|
+
shortResult: success ? `Deleted job ${id}` : `Job ${id} not found`,
|
|
44
|
+
error: success ? undefined : `Job ${id} not found`,
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ToolPlugin, ToolResult, ToolContext } from "./types.js";
|
|
2
|
+
import { CRON_LIST_TOOL_NAME } from "../constants/tools.js";
|
|
3
|
+
|
|
4
|
+
export const cronListTool: ToolPlugin = {
|
|
5
|
+
name: CRON_LIST_TOOL_NAME,
|
|
6
|
+
config: {
|
|
7
|
+
type: "function",
|
|
8
|
+
function: {
|
|
9
|
+
name: CRON_LIST_TOOL_NAME,
|
|
10
|
+
description:
|
|
11
|
+
"List all cron jobs scheduled via CronCreate in this session.",
|
|
12
|
+
parameters: {
|
|
13
|
+
type: "object",
|
|
14
|
+
properties: {},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
execute: async (
|
|
19
|
+
_args: Record<string, unknown>,
|
|
20
|
+
context: ToolContext,
|
|
21
|
+
): Promise<ToolResult> => {
|
|
22
|
+
if (!context.cronManager) {
|
|
23
|
+
return {
|
|
24
|
+
success: false,
|
|
25
|
+
content: "",
|
|
26
|
+
error: "CronManager not available",
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const jobs = context.cronManager.listJobs();
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
success: true,
|
|
34
|
+
content: JSON.stringify({ jobs }, null, 2),
|
|
35
|
+
shortResult: `Found ${jobs.length} jobs`,
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
};
|
package/src/tools/skillTool.ts
CHANGED
|
@@ -11,14 +11,16 @@ import {
|
|
|
11
11
|
/**
|
|
12
12
|
* Skill tool plugin for invoking Wave skills
|
|
13
13
|
*/
|
|
14
|
+
const SKILL_TOOL_DESCRIPTION =
|
|
15
|
+
"Execute a skill within the main conversation. When users ask you to perform tasks, check if any of the available skills match. Skills provide specialized capabilities and domain knowledge.";
|
|
16
|
+
|
|
14
17
|
export const skillTool: ToolPlugin = {
|
|
15
18
|
name: SKILL_TOOL_NAME,
|
|
16
19
|
config: {
|
|
17
20
|
type: "function" as const,
|
|
18
21
|
function: {
|
|
19
22
|
name: SKILL_TOOL_NAME,
|
|
20
|
-
description:
|
|
21
|
-
"Invoke a Wave skill by name. Skills are user-defined automation templates that can be personal or project-specific.",
|
|
23
|
+
description: SKILL_TOOL_DESCRIPTION,
|
|
22
24
|
parameters: {
|
|
23
25
|
type: "object",
|
|
24
26
|
properties: {
|
|
@@ -41,7 +43,7 @@ export const skillTool: ToolPlugin = {
|
|
|
41
43
|
(skill) => !skill.disableModelInvocation,
|
|
42
44
|
);
|
|
43
45
|
if (!availableSkills || availableSkills.length === 0) {
|
|
44
|
-
return
|
|
46
|
+
return `${SKILL_TOOL_DESCRIPTION} No skills are currently available.`;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
const skillList = availableSkills
|
|
@@ -50,7 +52,7 @@ export const skillTool: ToolPlugin = {
|
|
|
50
52
|
)
|
|
51
53
|
.join("\n");
|
|
52
54
|
|
|
53
|
-
return
|
|
55
|
+
return `${SKILL_TOOL_DESCRIPTION} Do not invoke the same skill repeatedly if it has already been called with the same arguments.\n\nAvailable skills:\n${skillList}`;
|
|
54
56
|
},
|
|
55
57
|
|
|
56
58
|
execute: async (
|
|
@@ -31,7 +31,7 @@ export const taskOutputTool: ToolPlugin = {
|
|
|
31
31
|
description: "Max wait time in ms",
|
|
32
32
|
},
|
|
33
33
|
},
|
|
34
|
-
required: ["task_id"],
|
|
34
|
+
required: ["task_id", "block", "timeout"],
|
|
35
35
|
},
|
|
36
36
|
},
|
|
37
37
|
},
|
|
@@ -87,8 +87,8 @@ export const taskOutputTool: ToolPlugin = {
|
|
|
87
87
|
|
|
88
88
|
if (finalContent.length > MAX_OUTPUT_LENGTH) {
|
|
89
89
|
processedContent =
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
"\n\n... (output truncated)\n" +
|
|
91
|
+
finalContent.substring(finalContent.length - MAX_OUTPUT_LENGTH);
|
|
92
92
|
isTruncated = true;
|
|
93
93
|
}
|
|
94
94
|
|
|
@@ -155,11 +155,17 @@ export const taskOutputTool: ToolPlugin = {
|
|
|
155
155
|
if (context.abortSignal) {
|
|
156
156
|
context.abortSignal.removeEventListener("abort", onAbort);
|
|
157
157
|
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
158
|
+
const result = getResult();
|
|
159
|
+
if (result) {
|
|
160
|
+
result.shortResult = `${taskId}: timeout`;
|
|
161
|
+
resolve(result);
|
|
162
|
+
} else {
|
|
163
|
+
resolve({
|
|
164
|
+
success: true,
|
|
165
|
+
content: "Retrieval timed out",
|
|
166
|
+
shortResult: `${taskId}: timeout`,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
163
169
|
return;
|
|
164
170
|
}
|
|
165
171
|
|
package/src/tools/types.ts
CHANGED
|
@@ -79,6 +79,8 @@ export interface ToolContext {
|
|
|
79
79
|
subagentManager?: import("../managers/subagentManager.js").SubagentManager;
|
|
80
80
|
/** Skill manager instance for skill invocation */
|
|
81
81
|
skillManager?: import("../managers/skillManager.js").SkillManager;
|
|
82
|
+
/** Cron manager instance for scheduling tasks */
|
|
83
|
+
cronManager?: import("../managers/cronManager.js").CronManager;
|
|
82
84
|
/** Current session ID */
|
|
83
85
|
sessionId?: string;
|
|
84
86
|
/** The ID of the current tool call */
|
package/src/types/agent.ts
CHANGED
|
@@ -67,6 +67,16 @@ export interface AgentOptions {
|
|
|
67
67
|
isNewWorktree?: boolean;
|
|
68
68
|
/**Whether to watch for skill changes - defaults to true */
|
|
69
69
|
watchSkills?: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Optional list of tool names to always allow.
|
|
72
|
+
* These rules follow the standard permission rule syntax: `ToolName` or `ToolName(pattern)`.
|
|
73
|
+
*/
|
|
74
|
+
allowedTools?: string[];
|
|
75
|
+
/**
|
|
76
|
+
* Optional list of tool names to always disallow.
|
|
77
|
+
* These rules follow the standard permission rule syntax: `ToolName` or `ToolName(pattern)`.
|
|
78
|
+
*/
|
|
79
|
+
disallowedTools?: string[];
|
|
70
80
|
}
|
|
71
81
|
|
|
72
82
|
export interface AgentCallbacks
|
|
@@ -21,7 +21,7 @@ export interface WaveConfiguration {
|
|
|
21
21
|
permissions?: {
|
|
22
22
|
allow?: string[];
|
|
23
23
|
deny?: string[];
|
|
24
|
-
|
|
24
|
+
permissionMode?: PermissionMode; // Default permission mode for restricted tools
|
|
25
25
|
/**
|
|
26
26
|
* List of directories that are considered part of the Safe Zone.
|
|
27
27
|
* File operations within these directories can be auto-accepted.
|
package/src/types/hooks.ts
CHANGED
|
@@ -19,7 +19,7 @@ export type HookEvent =
|
|
|
19
19
|
| "UserPromptSubmit"
|
|
20
20
|
| "Stop"
|
|
21
21
|
| "SubagentStop"
|
|
22
|
-
| "
|
|
22
|
+
| "PermissionRequest"
|
|
23
23
|
| "WorktreeCreate";
|
|
24
24
|
|
|
25
25
|
// Individual hook command configuration
|
|
@@ -100,7 +100,7 @@ export function isValidHookEvent(event: string): event is HookEvent {
|
|
|
100
100
|
"UserPromptSubmit",
|
|
101
101
|
"Stop",
|
|
102
102
|
"SubagentStop",
|
|
103
|
-
"
|
|
103
|
+
"PermissionRequest",
|
|
104
104
|
"WorktreeCreate",
|
|
105
105
|
].includes(event);
|
|
106
106
|
}
|
|
@@ -154,16 +154,14 @@ export interface HookJsonInput {
|
|
|
154
154
|
session_id: string; // Format: "wave_session_{uuid}_{shortId}"
|
|
155
155
|
transcript_path: string; // Format: "~/.wave/sessions/session_{shortId}.json"
|
|
156
156
|
cwd: string; // Absolute path to current working directory
|
|
157
|
-
hook_event_name: HookEvent; // "PreToolUse" | "PostToolUse" | "UserPromptSubmit" | "Stop" | "SubagentStop" | "
|
|
157
|
+
hook_event_name: HookEvent; // "PreToolUse" | "PostToolUse" | "UserPromptSubmit" | "Stop" | "SubagentStop" | "PermissionRequest" | "WorktreeCreate"
|
|
158
158
|
|
|
159
159
|
// Optional fields based on event type
|
|
160
|
-
tool_name?: string; // Present for PreToolUse, PostToolUse
|
|
161
|
-
tool_input?: unknown; // Present for PreToolUse, PostToolUse
|
|
160
|
+
tool_name?: string; // Present for PreToolUse, PostToolUse, PermissionRequest
|
|
161
|
+
tool_input?: unknown; // Present for PreToolUse, PostToolUse, PermissionRequest
|
|
162
162
|
tool_response?: unknown; // Present for PostToolUse only
|
|
163
163
|
user_prompt?: string; // Present for UserPromptSubmit only
|
|
164
164
|
subagent_type?: string; // Present when hook is executed by a subagent
|
|
165
|
-
message?: string; // Present for Notification events
|
|
166
|
-
notification_type?: string; // Present for Notification events
|
|
167
165
|
name?: string; // Present for WorktreeCreate events
|
|
168
166
|
}
|
|
169
167
|
|
|
@@ -177,8 +175,6 @@ export interface ExtendedHookExecutionContext extends HookExecutionContext {
|
|
|
177
175
|
env?: Record<string, string>; // Additional environment variables (from configuration)
|
|
178
176
|
userPrompt?: string; // User prompt text (UserPromptSubmit only)
|
|
179
177
|
subagentType?: string; // Subagent type when hook is executed by a subagent
|
|
180
|
-
message?: string; // Notification message (Notification only)
|
|
181
|
-
notificationType?: string; // Notification type (Notification only)
|
|
182
178
|
worktreeName?: string; // Worktree name (WorktreeCreate only)
|
|
183
179
|
}
|
|
184
180
|
|
package/src/types/index.ts
CHANGED
package/src/types/messaging.ts
CHANGED
|
@@ -11,7 +11,7 @@ export enum MessageSource {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export interface Message {
|
|
14
|
-
id
|
|
14
|
+
id: string; // Unique identifier for the message
|
|
15
15
|
role: "user" | "assistant";
|
|
16
16
|
blocks: MessageBlock[];
|
|
17
17
|
usage?: Usage; // Usage data for this message's AI operation (assistant messages only)
|
|
@@ -14,6 +14,7 @@ import { SkillManager } from "../managers/skillManager.js";
|
|
|
14
14
|
import { SlashCommandManager } from "../managers/slashCommandManager.js";
|
|
15
15
|
import { PluginManager } from "../managers/pluginManager.js";
|
|
16
16
|
import { BangManager } from "../managers/bangManager.js";
|
|
17
|
+
import { CronManager } from "../managers/cronManager.js";
|
|
17
18
|
import { MemoryRuleManager } from "../managers/MemoryRuleManager.js";
|
|
18
19
|
import { ReversionManager } from "../managers/reversionManager.js";
|
|
19
20
|
import { SubagentManager } from "../managers/subagentManager.js";
|
|
@@ -21,6 +22,7 @@ import { LiveConfigManager } from "../managers/liveConfigManager.js";
|
|
|
21
22
|
import { ConfigurationService } from "../services/configurationService.js";
|
|
22
23
|
import { ReversionService } from "../services/reversionService.js";
|
|
23
24
|
import { MemoryService } from "../services/memory.js";
|
|
25
|
+
import { getGitMainRepoRoot } from "./gitUtils.js";
|
|
24
26
|
import type { AgentOptions } from "../types/index.js";
|
|
25
27
|
import type {
|
|
26
28
|
PermissionMode,
|
|
@@ -69,11 +71,17 @@ export function setupAgentContainer(
|
|
|
69
71
|
|
|
70
72
|
const callbacks = options.callbacks || {};
|
|
71
73
|
const container = new Container();
|
|
74
|
+
container.register("AgentOptions", options);
|
|
72
75
|
|
|
73
76
|
const foregroundTaskManager = new ForegroundTaskManager(container);
|
|
74
77
|
container.register("ForegroundTaskManager", foregroundTaskManager);
|
|
75
78
|
container.register("ConfigurationService", configurationService);
|
|
76
79
|
|
|
80
|
+
if (options.worktreeName) {
|
|
81
|
+
container.register("WorktreeName", options.worktreeName);
|
|
82
|
+
container.register("MainRepoRoot", getGitMainRepoRoot(workdir));
|
|
83
|
+
}
|
|
84
|
+
|
|
77
85
|
const memoryService = new MemoryService(container);
|
|
78
86
|
container.register("MemoryService", memoryService);
|
|
79
87
|
|
|
@@ -130,13 +138,17 @@ export function setupAgentContainer(
|
|
|
130
138
|
const lspManager = options.lspManager || new LspManager(container);
|
|
131
139
|
container.register("LspManager", lspManager);
|
|
132
140
|
|
|
133
|
-
const permissionManager = new PermissionManager(container, {
|
|
141
|
+
const permissionManager = new PermissionManager(container, {
|
|
142
|
+
workdir,
|
|
143
|
+
instanceAllowedRules: options.allowedTools,
|
|
144
|
+
instanceDeniedRules: options.disallowedTools,
|
|
145
|
+
});
|
|
134
146
|
if (configurationService.resolveAutoMemoryEnabled()) {
|
|
135
147
|
const autoMemoryDir = memoryService.getAutoMemoryDirectory(workdir);
|
|
136
148
|
permissionManager.addSystemAdditionalDirectory(autoMemoryDir);
|
|
137
149
|
}
|
|
138
150
|
container.register("PermissionManager", permissionManager);
|
|
139
|
-
permissionManager.
|
|
151
|
+
permissionManager.setOnConfiguredPermissionModeChange((mode) => {
|
|
140
152
|
handlePlanModeTransition(mode);
|
|
141
153
|
onPermissionModeChange(mode);
|
|
142
154
|
});
|
|
@@ -153,30 +165,45 @@ export function setupAgentContainer(
|
|
|
153
165
|
});
|
|
154
166
|
container.register("SkillManager", skillManager);
|
|
155
167
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
);
|
|
168
|
+
const rootSessionId = messageManager.getRootSessionId();
|
|
169
|
+
|
|
170
|
+
container.register("ReversionService", new ReversionService(rootSessionId));
|
|
160
171
|
const reversionManager = new ReversionManager(container);
|
|
161
172
|
container.register("ReversionManager", reversionManager);
|
|
162
173
|
|
|
163
|
-
const
|
|
174
|
+
const canUseToolWithPermissionRequest = options.canUseTool
|
|
164
175
|
? async (context: ToolPermissionContext) => {
|
|
165
176
|
try {
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
event: "Notification",
|
|
177
|
+
const results = await hookManager.executeHooks("PermissionRequest", {
|
|
178
|
+
event: "PermissionRequest",
|
|
169
179
|
projectDir: workdir,
|
|
170
180
|
timestamp: new Date(),
|
|
171
181
|
sessionId: messageManager.getSessionId(),
|
|
172
182
|
transcriptPath: messageManager.getTranscriptPath(),
|
|
173
183
|
cwd: workdir,
|
|
174
|
-
|
|
175
|
-
|
|
184
|
+
toolName: context.toolName,
|
|
185
|
+
toolInput: context.toolInput,
|
|
176
186
|
env: configurationService.getEnvironmentVars(),
|
|
177
187
|
});
|
|
188
|
+
|
|
189
|
+
if (results.length > 0) {
|
|
190
|
+
const processResult = hookManager.processHookResults(
|
|
191
|
+
"PermissionRequest",
|
|
192
|
+
results,
|
|
193
|
+
messageManager,
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
if (processResult.shouldBlock) {
|
|
197
|
+
return {
|
|
198
|
+
behavior: "deny",
|
|
199
|
+
message:
|
|
200
|
+
processResult.errorMessage ||
|
|
201
|
+
"Permission denied by hook execution",
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
}
|
|
178
205
|
} catch (error) {
|
|
179
|
-
logger.warn("Failed to execute
|
|
206
|
+
logger.warn("Failed to execute permission request hooks", {
|
|
180
207
|
toolName: context.toolName,
|
|
181
208
|
error: error instanceof Error ? error.message : String(error),
|
|
182
209
|
});
|
|
@@ -215,9 +242,9 @@ export function setupAgentContainer(
|
|
|
215
242
|
|
|
216
243
|
container.register("PermissionMode", options.permissionMode);
|
|
217
244
|
logger.info("Registering CanUseToolCallback", {
|
|
218
|
-
hasCallback: !!
|
|
245
|
+
hasCallback: !!canUseToolWithPermissionRequest,
|
|
219
246
|
});
|
|
220
|
-
container.register("CanUseToolCallback",
|
|
247
|
+
container.register("CanUseToolCallback", canUseToolWithPermissionRequest);
|
|
221
248
|
|
|
222
249
|
const liveConfigManager = new LiveConfigManager(container, { workdir });
|
|
223
250
|
container.register("LiveConfigManager", liveConfigManager);
|
|
@@ -233,11 +260,14 @@ export function setupAgentContainer(
|
|
|
233
260
|
onSubagentAssistantReasoningUpdated:
|
|
234
261
|
callbacks.onSubagentAssistantReasoningUpdated,
|
|
235
262
|
onSubagentToolBlockUpdated: callbacks.onSubagentToolBlockUpdated,
|
|
236
|
-
onSubagentMessagesChange:
|
|
263
|
+
onSubagentMessagesChange: (subagentId, messages) => {
|
|
264
|
+
callbacks.onSubagentMessagesChange?.(subagentId, messages);
|
|
265
|
+
},
|
|
237
266
|
onSubagentLatestTotalTokensChange:
|
|
238
267
|
callbacks.onSubagentLatestTotalTokensChange,
|
|
239
268
|
},
|
|
240
269
|
onUsageAdded: (usage: Usage) => addUsage(usage),
|
|
270
|
+
stream,
|
|
241
271
|
});
|
|
242
272
|
container.register("SubagentManager", subagentManager);
|
|
243
273
|
|
|
@@ -262,5 +292,9 @@ export function setupAgentContainer(
|
|
|
262
292
|
const bangManager = new BangManager(container, { workdir });
|
|
263
293
|
container.register("BangManager", bangManager);
|
|
264
294
|
|
|
295
|
+
const cronManager = new CronManager(container);
|
|
296
|
+
container.register("CronManager", cronManager);
|
|
297
|
+
cronManager.start();
|
|
298
|
+
|
|
265
299
|
return container;
|
|
266
300
|
}
|
package/src/utils/mcpUtils.ts
CHANGED
|
@@ -79,6 +79,7 @@ export function createMcpToolPlugin(
|
|
|
79
79
|
executeTool: (
|
|
80
80
|
name: string,
|
|
81
81
|
args: Record<string, unknown>,
|
|
82
|
+
context?: ToolContext,
|
|
82
83
|
) => Promise<{
|
|
83
84
|
success: boolean;
|
|
84
85
|
content: string;
|
|
@@ -95,11 +96,7 @@ export function createMcpToolPlugin(
|
|
|
95
96
|
context?: ToolContext,
|
|
96
97
|
): Promise<ToolResult> {
|
|
97
98
|
try {
|
|
98
|
-
|
|
99
|
-
if (context) {
|
|
100
|
-
// Future: Could pass working directory or other context to MCP tools
|
|
101
|
-
}
|
|
102
|
-
const result = await executeTool(prefixedName, args);
|
|
99
|
+
const result = await executeTool(prefixedName, args, context);
|
|
103
100
|
return {
|
|
104
101
|
success: true,
|
|
105
102
|
content: result.content || `Executed ${mcpTool.name}`,
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
# Wave Hooks Configuration
|
|
2
|
-
|
|
3
|
-
Hooks allow you to automate tasks when certain events occur in Wave. This document provides detailed guidance on how to configure complex hooks in `settings.json`.
|
|
4
|
-
|
|
5
|
-
## Hook Events
|
|
6
|
-
|
|
7
|
-
Wave supports the following hook events:
|
|
8
|
-
|
|
9
|
-
- `WorktreeCreate`: Triggered when a new worktree is created.
|
|
10
|
-
- `TaskStart`: Triggered when a task starts.
|
|
11
|
-
- `TaskComplete`: Triggered when a task is completed.
|
|
12
|
-
- `TaskError`: Triggered when a task fails.
|
|
13
|
-
- `SessionStart`: Triggered when a new session starts.
|
|
14
|
-
- `SessionEnd`: Triggered when a session ends.
|
|
15
|
-
|
|
16
|
-
## Hook Configuration Structure
|
|
17
|
-
|
|
18
|
-
Hooks are configured in the `hooks` field of `settings.json`. Each event can have multiple hook configurations.
|
|
19
|
-
|
|
20
|
-
```json
|
|
21
|
-
{
|
|
22
|
-
"hooks": {
|
|
23
|
-
"WorktreeCreate": [
|
|
24
|
-
{
|
|
25
|
-
"command": "pnpm install",
|
|
26
|
-
"description": "Install dependencies in new worktree",
|
|
27
|
-
"blocking": true,
|
|
28
|
-
"timeout": 300000
|
|
29
|
-
}
|
|
30
|
-
],
|
|
31
|
-
"TaskComplete": [
|
|
32
|
-
{
|
|
33
|
-
"command": "pnpm test",
|
|
34
|
-
"description": "Run tests after task completion",
|
|
35
|
-
"blocking": false
|
|
36
|
-
}
|
|
37
|
-
]
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Hook Configuration Fields
|
|
43
|
-
|
|
44
|
-
- `command`: The shell command to execute.
|
|
45
|
-
- `description`: A brief description of the hook's purpose.
|
|
46
|
-
- `blocking`: (Optional) Whether the hook should block the main agent's execution (default: `false`).
|
|
47
|
-
- `timeout`: (Optional) Maximum execution time in milliseconds (default: `60000`).
|
|
48
|
-
- `env`: (Optional) Environment variables specific to this hook.
|
|
49
|
-
- `cwd`: (Optional) Working directory for the hook command.
|
|
50
|
-
|
|
51
|
-
## Advanced Hook Examples
|
|
52
|
-
|
|
53
|
-
### 1. Conditional Hooks
|
|
54
|
-
You can use shell logic within the `command` field to create conditional hooks.
|
|
55
|
-
```json
|
|
56
|
-
{
|
|
57
|
-
"hooks": {
|
|
58
|
-
"TaskComplete": [
|
|
59
|
-
{
|
|
60
|
-
"command": "if [ \"$WAVE_TASK_STATUS\" = \"completed\" ]; then pnpm lint; fi",
|
|
61
|
-
"description": "Run linting only on successful task completion"
|
|
62
|
-
}
|
|
63
|
-
]
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
### 2. Hook Chaining
|
|
69
|
-
You can chain multiple commands in a single hook or define multiple hooks for the same event.
|
|
70
|
-
```json
|
|
71
|
-
{
|
|
72
|
-
"hooks": {
|
|
73
|
-
"WorktreeCreate": [
|
|
74
|
-
{
|
|
75
|
-
"command": "pnpm install && pnpm build",
|
|
76
|
-
"description": "Install and build in new worktree"
|
|
77
|
-
}
|
|
78
|
-
]
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### 3. Using Environment Variables
|
|
84
|
-
Wave provides several environment variables to hooks:
|
|
85
|
-
- `WAVE_PROJECT_DIR`: The root directory of the project.
|
|
86
|
-
- `WAVE_SESSION_ID`: The current session ID.
|
|
87
|
-
- `WAVE_TASK_ID`: The current task ID (if applicable).
|
|
88
|
-
- `WAVE_TASK_STATUS`: The status of the task (for `TaskComplete` and `TaskError`).
|
|
89
|
-
|
|
90
|
-
## Best Practices
|
|
91
|
-
|
|
92
|
-
- **Keep hooks fast**: Long-running hooks can slow down your workflow, especially if they are `blocking`.
|
|
93
|
-
- **Use descriptive names**: Help yourself and others understand what each hook does.
|
|
94
|
-
- **Test your hooks**: Run the commands manually first to ensure they work as expected.
|
|
95
|
-
- **Use local overrides**: For machine-specific hooks, use `.wave/settings.local.json`.
|