wave-agent-sdk 0.17.5 → 0.17.7
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 +18 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +114 -1
- package/dist/managers/MemoryRuleManager.d.ts.map +1 -1
- package/dist/managers/MemoryRuleManager.js +30 -13
- package/dist/managers/aiManager.d.ts +1 -0
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +20 -62
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +3 -1
- package/dist/managers/lspManager.d.ts.map +1 -1
- package/dist/managers/lspManager.js +12 -4
- package/dist/managers/mcpManager.d.ts.map +1 -1
- package/dist/managers/mcpManager.js +13 -6
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +0 -4
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +7 -2
- package/dist/managers/planManager.d.ts +3 -0
- package/dist/managers/planManager.d.ts.map +1 -1
- package/dist/managers/planManager.js +9 -0
- package/dist/managers/skillManager.d.ts +3 -0
- package/dist/managers/skillManager.d.ts.map +1 -1
- package/dist/managers/skillManager.js +69 -54
- package/dist/managers/slashCommandManager.d.ts +0 -6
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +0 -170
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +2 -5
- package/dist/prompts/planModeReminders.d.ts +0 -1
- package/dist/prompts/planModeReminders.d.ts.map +1 -1
- package/dist/prompts/planModeReminders.js +3 -12
- package/dist/services/MarketplaceService.d.ts.map +1 -1
- package/dist/services/MarketplaceService.js +12 -4
- package/dist/services/memory.d.ts.map +1 -1
- package/dist/services/memory.js +39 -5
- package/dist/services/pluginLoader.d.ts.map +1 -1
- package/dist/services/pluginLoader.js +30 -7
- package/dist/types/skills.d.ts +1 -0
- package/dist/types/skills.d.ts.map +1 -1
- package/dist/utils/customCommands.d.ts.map +1 -1
- package/dist/utils/customCommands.js +11 -9
- package/dist/utils/skillParser.d.ts.map +1 -1
- package/dist/utils/skillParser.js +3 -1
- package/dist/utils/subagentParser.d.ts.map +1 -1
- package/dist/utils/subagentParser.js +18 -7
- package/package.json +1 -1
- package/src/agent.ts +146 -1
- package/src/managers/MemoryRuleManager.ts +29 -14
- package/src/managers/aiManager.ts +28 -78
- package/src/managers/hookManager.ts +6 -1
- package/src/managers/lspManager.ts +23 -5
- package/src/managers/mcpManager.ts +24 -7
- package/src/managers/messageManager.ts +0 -5
- package/src/managers/permissionManager.ts +8 -1
- package/src/managers/planManager.ts +11 -0
- package/src/managers/skillManager.ts +90 -57
- package/src/managers/slashCommandManager.ts +0 -215
- package/src/managers/toolManager.ts +2 -9
- package/src/prompts/planModeReminders.ts +3 -15
- package/src/services/MarketplaceService.ts +22 -4
- package/src/services/memory.ts +43 -6
- package/src/services/pluginLoader.ts +35 -7
- package/src/types/skills.ts +1 -0
- package/src/utils/customCommands.ts +17 -12
- package/src/utils/skillParser.ts +3 -1
- package/src/utils/subagentParser.ts +22 -8
package/dist/services/memory.js
CHANGED
|
@@ -117,6 +117,22 @@ export class MemoryService {
|
|
|
117
117
|
userMemoryFile: USER_MEMORY_FILE,
|
|
118
118
|
contentLength: content.length,
|
|
119
119
|
});
|
|
120
|
+
// If the file is still the default empty template, fallback to ~/.claude/AGENTS.md
|
|
121
|
+
const defaultTemplate = "# User Memory\n\nThis is the user-level memory file, recording important information and context across projects.\n\n";
|
|
122
|
+
if (content === defaultTemplate) {
|
|
123
|
+
const claudeMemoryPath = path.join(homedir(), ".claude", "AGENTS.md");
|
|
124
|
+
try {
|
|
125
|
+
const claudeContent = await fs.readFile(claudeMemoryPath, "utf-8");
|
|
126
|
+
logger.debug("User memory content read from ~/.claude/AGENTS.md fallback", {
|
|
127
|
+
claudeMemoryPath,
|
|
128
|
+
contentLength: claudeContent.length,
|
|
129
|
+
});
|
|
130
|
+
return claudeContent;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// CLAUDE.md doesn't exist or can't be read, return the default template
|
|
134
|
+
}
|
|
135
|
+
}
|
|
120
136
|
return content;
|
|
121
137
|
}
|
|
122
138
|
catch (error) {
|
|
@@ -126,7 +142,6 @@ export class MemoryService {
|
|
|
126
142
|
}
|
|
127
143
|
async readMemoryFile(workdir) {
|
|
128
144
|
const memoryFilePath = path.join(workdir, "AGENTS.md");
|
|
129
|
-
// Direct file access
|
|
130
145
|
try {
|
|
131
146
|
const content = await fs.readFile(memoryFilePath, "utf-8");
|
|
132
147
|
logger.debug("Memory file read successfully via direct file access", {
|
|
@@ -137,10 +152,29 @@ export class MemoryService {
|
|
|
137
152
|
}
|
|
138
153
|
catch (error) {
|
|
139
154
|
if (error.code === "ENOENT") {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
155
|
+
// Fallback to CLAUDE.md
|
|
156
|
+
const claudeMemoryPath = path.join(workdir, "CLAUDE.md");
|
|
157
|
+
try {
|
|
158
|
+
const content = await fs.readFile(claudeMemoryPath, "utf-8");
|
|
159
|
+
logger.debug("Memory file read from CLAUDE.md fallback", {
|
|
160
|
+
memoryFilePath: claudeMemoryPath,
|
|
161
|
+
contentLength: content.length,
|
|
162
|
+
});
|
|
163
|
+
return content;
|
|
164
|
+
}
|
|
165
|
+
catch (claudeError) {
|
|
166
|
+
if (claudeError.code === "ENOENT") {
|
|
167
|
+
logger.debug("Neither AGENTS.md nor CLAUDE.md found", {
|
|
168
|
+
memoryFilePath,
|
|
169
|
+
});
|
|
170
|
+
return "";
|
|
171
|
+
}
|
|
172
|
+
logger.error("Failed to read CLAUDE.md fallback", {
|
|
173
|
+
memoryFilePath: claudeMemoryPath,
|
|
174
|
+
error: claudeError,
|
|
175
|
+
});
|
|
176
|
+
return "";
|
|
177
|
+
}
|
|
144
178
|
}
|
|
145
179
|
logger.error("Failed to read memory file", { memoryFilePath, error });
|
|
146
180
|
return "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pluginLoader.d.ts","sourceRoot":"","sources":["../../src/services/pluginLoader.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,KAAK,EACL,SAAS,EACT,SAAS,EACT,wBAAwB,EACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,4BAA4B,CAAC;AAGpC,qBAAa,YAAY;IACvB;;;OAGG;WACU,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"pluginLoader.d.ts","sourceRoot":"","sources":["../../src/services/pluginLoader.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,KAAK,EACL,SAAS,EACT,SAAS,EACT,wBAAwB,EACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,4BAA4B,CAAC;AAGpC,qBAAa,YAAY;IACvB;;;OAGG;WACU,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAyEtE;;;OAGG;IACH,MAAM,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB,EAAE;IAK7D;;;OAGG;WACU,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAuC7D;;OAEG;WACU,aAAa,CACxB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAUjC;;OAEG;WACU,aAAa,CACxB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAWjC;;OAEG;WACU,eAAe,CAC1B,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC;IAgBhD;;OAEG;WACU,UAAU,CACrB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,qBAAqB,EAAE,CAAC;IA2BnC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;CAgBhC"}
|
|
@@ -11,10 +11,12 @@ export class PluginLoader {
|
|
|
11
11
|
*/
|
|
12
12
|
static async loadManifest(pluginPath) {
|
|
13
13
|
const dotWavePluginPath = path.join(pluginPath, ".wave-plugin");
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
// Check if .wave-plugin/ directory exists
|
|
15
|
+
let wavePluginDirExists = false;
|
|
16
16
|
try {
|
|
17
17
|
const entries = await fs.readdir(dotWavePluginPath);
|
|
18
|
+
wavePluginDirExists = true;
|
|
19
|
+
// T018: Ensure plugin.json is the only file in .wave-plugin/
|
|
18
20
|
const misplaced = entries.filter((e) => e !== "plugin.json");
|
|
19
21
|
if (misplaced.length > 0) {
|
|
20
22
|
throw new Error(`Misplaced files/directories in .wave-plugin/: ${misplaced.join(", ")}. Only plugin.json should be in this directory.`);
|
|
@@ -23,12 +25,33 @@ export class PluginLoader {
|
|
|
23
25
|
catch (error) {
|
|
24
26
|
if (error instanceof Error &&
|
|
25
27
|
error.code === "ENOENT") {
|
|
26
|
-
|
|
28
|
+
// .wave-plugin/ doesn't exist, will try .claude-plugin/ fallback below
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (wavePluginDirExists) {
|
|
35
|
+
const manifestPath = path.join(dotWavePluginPath, "plugin.json");
|
|
36
|
+
try {
|
|
37
|
+
const content = await fs.readFile(manifestPath, "utf-8");
|
|
38
|
+
const manifest = JSON.parse(content);
|
|
39
|
+
this.validateManifest(manifest);
|
|
40
|
+
return manifest;
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (error instanceof Error &&
|
|
44
|
+
error.code === "ENOENT") {
|
|
45
|
+
throw new Error(`Plugin manifest not found at ${manifestPath}`);
|
|
46
|
+
}
|
|
47
|
+
throw new Error(`Failed to load plugin manifest at ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
27
48
|
}
|
|
28
|
-
throw error;
|
|
29
49
|
}
|
|
50
|
+
// Fallback to .claude-plugin/
|
|
51
|
+
const dotClaudePluginPath = path.join(pluginPath, ".claude-plugin");
|
|
52
|
+
const claudeManifestPath = path.join(dotClaudePluginPath, "plugin.json");
|
|
30
53
|
try {
|
|
31
|
-
const content = await fs.readFile(
|
|
54
|
+
const content = await fs.readFile(claudeManifestPath, "utf-8");
|
|
32
55
|
const manifest = JSON.parse(content);
|
|
33
56
|
this.validateManifest(manifest);
|
|
34
57
|
return manifest;
|
|
@@ -36,9 +59,9 @@ export class PluginLoader {
|
|
|
36
59
|
catch (error) {
|
|
37
60
|
if (error instanceof Error &&
|
|
38
61
|
error.code === "ENOENT") {
|
|
39
|
-
throw new Error(`Plugin manifest not found at ${
|
|
62
|
+
throw new Error(`Plugin manifest not found at ${dotWavePluginPath} or ${dotClaudePluginPath}`);
|
|
40
63
|
}
|
|
41
|
-
throw new Error(`Failed to load plugin manifest at ${
|
|
64
|
+
throw new Error(`Failed to load plugin manifest at ${claudeManifestPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
42
65
|
}
|
|
43
66
|
}
|
|
44
67
|
/**
|
package/dist/types/skills.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/types/skills.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/types/skills.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"customCommands.d.ts","sourceRoot":"","sources":["../../src/utils/customCommands.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAK5D;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAwC3E;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"customCommands.d.ts","sourceRoot":"","sources":["../../src/utils/customCommands.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAK5D;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAwC3E;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAuB7E"}
|
|
@@ -60,16 +60,18 @@ export function scanCommandsDirectory(dirPath) {
|
|
|
60
60
|
* Load all custom slash commands from both project and user directories
|
|
61
61
|
*/
|
|
62
62
|
export function loadCustomSlashCommands(workdir) {
|
|
63
|
-
const
|
|
64
|
-
const
|
|
65
|
-
|
|
63
|
+
const userClaudeCommands = scanCommandsDirectory(join(homedir(), ".claude", "commands"));
|
|
64
|
+
const userWaveCommands = scanCommandsDirectory(getUserCommandsDir());
|
|
65
|
+
const projectClaudeCommands = scanCommandsDirectory(join(workdir, ".claude", "commands"));
|
|
66
|
+
const projectWaveCommands = scanCommandsDirectory(getProjectCommandsDir(workdir));
|
|
66
67
|
const commandMap = new Map();
|
|
67
|
-
//
|
|
68
|
-
for (const command of
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
// Write in priority order: lowest first, highest last (overwrites)
|
|
69
|
+
for (const command of [
|
|
70
|
+
...userClaudeCommands,
|
|
71
|
+
...userWaveCommands,
|
|
72
|
+
...projectClaudeCommands,
|
|
73
|
+
...projectWaveCommands,
|
|
74
|
+
]) {
|
|
73
75
|
commandMap.set(command.id, command);
|
|
74
76
|
}
|
|
75
77
|
return Array.from(commandMap.values());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skillParser.d.ts","sourceRoot":"","sources":["../../src/utils/skillParser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EACf,iBAAiB,EAEjB,aAAa,EACd,MAAM,mBAAmB,CAAC;AAE3B;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,iBAAsB,GAC9B,eAAe,
|
|
1
|
+
{"version":3,"file":"skillParser.d.ts","sourceRoot":"","sources":["../../src/utils/skillParser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,eAAe,EACf,iBAAiB,EAEjB,aAAa,EACd,MAAM,mBAAmB,CAAC;AAE3B;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,iBAAsB,GAC9B,eAAe,CAkGjB;AAyDD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE,CAwCvE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOtD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAa5E"}
|
|
@@ -36,7 +36,9 @@ export function parseSkillFile(filePath, options = {}) {
|
|
|
36
36
|
// Determine skill type and path
|
|
37
37
|
const skillPath = basePath || dirname(filePath);
|
|
38
38
|
const skillType = skillPath.includes("/.wave/skills") ||
|
|
39
|
-
skillPath.includes("\\.wave\\skills")
|
|
39
|
+
skillPath.includes("\\.wave\\skills") ||
|
|
40
|
+
skillPath.includes("/.claude/skills") ||
|
|
41
|
+
skillPath.includes("\\.claude\\skills")
|
|
40
42
|
? "project"
|
|
41
43
|
: "personal";
|
|
42
44
|
// Extract allowed tools
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagentParser.d.ts","sourceRoot":"","sources":["../../src/utils/subagentParser.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAmKD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,QAAQ,EACf,UAAU,EAAE,MAAM,GACjB,qBAAqB,CAEvB;AAqCD;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,qBAAqB,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"subagentParser.d.ts","sourceRoot":"","sources":["../../src/utils/subagentParser.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAmKD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,QAAQ,EACf,UAAU,EAAE,MAAM,GACjB,qBAAqB,CAEvB;AAqCD;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAoClC;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAGvC"}
|
|
@@ -160,17 +160,28 @@ function scanSubagentDirectory(dirPath, scope) {
|
|
|
160
160
|
* Load all subagent configurations from project and user directories, plus built-in subagents
|
|
161
161
|
*/
|
|
162
162
|
export async function loadSubagentConfigurations(workdir) {
|
|
163
|
-
const
|
|
164
|
-
const
|
|
163
|
+
const projectWaveDir = join(workdir, ".wave", "agents");
|
|
164
|
+
const projectClaudeDir = join(workdir, ".claude", "agents");
|
|
165
|
+
const userWaveDir = join(process.env.HOME || "~", ".wave", "agents");
|
|
166
|
+
const userClaudeDir = join(process.env.HOME || "~", ".claude", "agents");
|
|
165
167
|
const builtinDir = getBuiltinSubagentsDir();
|
|
166
168
|
// Load configurations from all sources
|
|
167
169
|
const builtinConfigs = scanSubagentDirectory(builtinDir, "builtin");
|
|
168
|
-
const
|
|
169
|
-
const
|
|
170
|
-
|
|
170
|
+
const userClaudeConfigs = scanSubagentDirectory(userClaudeDir, "user");
|
|
171
|
+
const userWaveConfigs = scanSubagentDirectory(userWaveDir, "user");
|
|
172
|
+
const projectClaudeConfigs = scanSubagentDirectory(projectClaudeDir, "project");
|
|
173
|
+
const projectWaveConfigs = scanSubagentDirectory(projectWaveDir, "project");
|
|
174
|
+
// Merge configurations, with .wave taking priority over .claude
|
|
171
175
|
const configMap = new Map();
|
|
172
|
-
//
|
|
173
|
-
|
|
176
|
+
// Merge order: builtin → userClaude → userWave → projectClaude → projectWave
|
|
177
|
+
// Later writes override earlier ones, so .wave takes priority over .claude
|
|
178
|
+
for (const config of [
|
|
179
|
+
...builtinConfigs,
|
|
180
|
+
...userClaudeConfigs,
|
|
181
|
+
...userWaveConfigs,
|
|
182
|
+
...projectClaudeConfigs,
|
|
183
|
+
...projectWaveConfigs,
|
|
184
|
+
]) {
|
|
174
185
|
configMap.set(config.name, config);
|
|
175
186
|
}
|
|
176
187
|
return Array.from(configMap.values()).sort((a, b) => {
|
package/package.json
CHANGED
package/src/agent.ts
CHANGED
|
@@ -685,7 +685,152 @@ export class Agent {
|
|
|
685
685
|
}
|
|
686
686
|
|
|
687
687
|
public async clearMessages(): Promise<void> {
|
|
688
|
-
|
|
688
|
+
this.aiManager.abortAIMessage();
|
|
689
|
+
|
|
690
|
+
// Clear any active goal
|
|
691
|
+
this.goalManager.clearGoal();
|
|
692
|
+
|
|
693
|
+
// Capture old session info before clearing
|
|
694
|
+
const oldSessionId = this.messageManager.getSessionId();
|
|
695
|
+
const transcriptPath = this.messageManager.getTranscriptPath();
|
|
696
|
+
|
|
697
|
+
// Run SessionEnd hooks (cleanup before clear)
|
|
698
|
+
try {
|
|
699
|
+
await this.hookManager.executeSessionEndHooks(
|
|
700
|
+
"clear",
|
|
701
|
+
oldSessionId,
|
|
702
|
+
transcriptPath,
|
|
703
|
+
);
|
|
704
|
+
} catch (error) {
|
|
705
|
+
this.logger?.warn(
|
|
706
|
+
`SessionEnd hooks on clear failed: ${(error as Error).message}`,
|
|
707
|
+
);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// Clear messages and generate new session
|
|
711
|
+
this.messageManager.clearMessages();
|
|
712
|
+
const memoryService =
|
|
713
|
+
this.container.get<import("./services/memory.js").MemoryService>(
|
|
714
|
+
"MemoryService",
|
|
715
|
+
);
|
|
716
|
+
memoryService?.clearCache();
|
|
717
|
+
await this.taskManager.syncWithSession();
|
|
718
|
+
|
|
719
|
+
// Run SessionStart hooks (restore context for new session)
|
|
720
|
+
try {
|
|
721
|
+
const newSessionId = this.messageManager.getSessionId();
|
|
722
|
+
const sessionStartResult =
|
|
723
|
+
await this.hookManager.executeSessionStartHooks(
|
|
724
|
+
"clear",
|
|
725
|
+
newSessionId,
|
|
726
|
+
this.messageManager.getTranscriptPath(),
|
|
727
|
+
);
|
|
728
|
+
|
|
729
|
+
// Inject additionalContext as a meta user message
|
|
730
|
+
if (sessionStartResult.additionalContext) {
|
|
731
|
+
this.messageManager.addUserMessage({
|
|
732
|
+
content: `<system-reminder>\nSessionStart hook additional context: ${sessionStartResult.additionalContext}\n</system-reminder>`,
|
|
733
|
+
isMeta: true,
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// Inject initialUserMessage as a meta user message
|
|
738
|
+
if (sessionStartResult.initialUserMessage) {
|
|
739
|
+
this.messageManager.addUserMessage({
|
|
740
|
+
content: sessionStartResult.initialUserMessage,
|
|
741
|
+
isMeta: true,
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
} catch (error) {
|
|
745
|
+
this.logger?.warn(
|
|
746
|
+
`SessionStart hooks on clear failed: ${(error as Error).message}`,
|
|
747
|
+
);
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
await this.messageManager.saveSession();
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
/**
|
|
754
|
+
* Compact conversation history to reduce context usage
|
|
755
|
+
* @param customInstructions - Optional custom instructions for compaction
|
|
756
|
+
*/
|
|
757
|
+
public async compact(customInstructions?: string): Promise<void> {
|
|
758
|
+
this.aiManager.abortAIMessage();
|
|
759
|
+
|
|
760
|
+
await this.aiManager.compactConversation({
|
|
761
|
+
customInstructions,
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
await this.messageManager.saveSession();
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/**
|
|
768
|
+
* Set an autonomous goal for the session
|
|
769
|
+
* @param condition - The goal condition to achieve
|
|
770
|
+
*/
|
|
771
|
+
public async setGoal(condition: string): Promise<void> {
|
|
772
|
+
// Check plan mode
|
|
773
|
+
if (this.getPermissionMode() === "plan") {
|
|
774
|
+
this.messageManager.addUserMessage({
|
|
775
|
+
content:
|
|
776
|
+
"<system-reminder>Cannot set a goal in plan mode. Exit plan mode first.</system-reminder>",
|
|
777
|
+
isMeta: true,
|
|
778
|
+
});
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
this.goalManager.setGoal(condition);
|
|
783
|
+
this.messageManager.addUserMessage({
|
|
784
|
+
content: `<system-reminder>Goal set: ${condition}. The agent will work autonomously until this goal is achieved.</system-reminder>`,
|
|
785
|
+
isMeta: true,
|
|
786
|
+
});
|
|
787
|
+
// Add the goal as a user directive to start working
|
|
788
|
+
this.messageManager.addUserMessage({
|
|
789
|
+
content: condition,
|
|
790
|
+
});
|
|
791
|
+
this.aiManager.sendAIMessage();
|
|
792
|
+
|
|
793
|
+
await this.messageManager.saveSession();
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/**
|
|
797
|
+
* Clear the current autonomous goal
|
|
798
|
+
*/
|
|
799
|
+
public async clearGoal(): Promise<void> {
|
|
800
|
+
if (this.goalManager.isGoalActive()) {
|
|
801
|
+
this.goalManager.clearGoal();
|
|
802
|
+
this.messageManager.addUserMessage({
|
|
803
|
+
content: "<system-reminder>Goal cleared.</system-reminder>",
|
|
804
|
+
isMeta: true,
|
|
805
|
+
});
|
|
806
|
+
} else {
|
|
807
|
+
this.messageManager.addUserMessage({
|
|
808
|
+
content: "<system-reminder>No active goal to clear.</system-reminder>",
|
|
809
|
+
isMeta: true,
|
|
810
|
+
});
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
await this.messageManager.saveSession();
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* Show the current goal status
|
|
818
|
+
*/
|
|
819
|
+
public async showGoalStatus(): Promise<void> {
|
|
820
|
+
if (this.goalManager.isGoalActive()) {
|
|
821
|
+
this.messageManager.addUserMessage({
|
|
822
|
+
content: `<system-reminder>${this.goalManager.getStatusString()}</system-reminder>`,
|
|
823
|
+
isMeta: true,
|
|
824
|
+
});
|
|
825
|
+
} else {
|
|
826
|
+
this.messageManager.addUserMessage({
|
|
827
|
+
content:
|
|
828
|
+
"<system-reminder>No active goal. Use /goal <condition> to set one.</system-reminder>",
|
|
829
|
+
isMeta: true,
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
await this.messageManager.saveSession();
|
|
689
834
|
}
|
|
690
835
|
|
|
691
836
|
/** Unified interrupt method, interrupts both AI messages and command execution */
|
|
@@ -39,23 +39,26 @@ export class MemoryRuleManager {
|
|
|
39
39
|
* Scans .wave/rules and ~/.wave/rules for memory rule files.
|
|
40
40
|
*/
|
|
41
41
|
async discoverRules(): Promise<void> {
|
|
42
|
-
const
|
|
43
|
-
const
|
|
42
|
+
const projectWaveRulesDir = path.join(this.workdir, ".wave", "rules");
|
|
43
|
+
const projectClaudeRulesDir = path.join(this.workdir, ".claude", "rules");
|
|
44
|
+
const userWaveRulesDir = path.join(os.homedir(), ".wave", "rules");
|
|
45
|
+
const userClaudeRulesDir = path.join(os.homedir(), ".claude", "rules");
|
|
44
46
|
|
|
45
47
|
logger.debug(`Scanning for modular memory rules...`);
|
|
46
|
-
logger.debug(` User rules directory: ${
|
|
47
|
-
logger.debug(` Project rules directory: ${
|
|
48
|
+
logger.debug(` User rules directory: ${userWaveRulesDir}`);
|
|
49
|
+
logger.debug(` Project rules directory: ${projectWaveRulesDir}`);
|
|
48
50
|
|
|
49
51
|
const newRules: Record<string, MemoryRule> = {};
|
|
50
52
|
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
await this.scanDirectory(
|
|
54
|
-
await this.scanDirectory(
|
|
53
|
+
// Scan order: userClaude → userWave → projectClaude → projectWave
|
|
54
|
+
// Later writes override, so .wave takes priority over .claude
|
|
55
|
+
await this.scanDirectory(userClaudeRulesDir, "user", newRules);
|
|
56
|
+
await this.scanDirectory(userWaveRulesDir, "user", newRules);
|
|
57
|
+
await this.scanDirectory(projectClaudeRulesDir, "project", newRules);
|
|
58
|
+
await this.scanDirectory(projectWaveRulesDir, "project", newRules);
|
|
55
59
|
|
|
56
60
|
this.state.rules = newRules;
|
|
57
61
|
const ruleCount = Object.keys(newRules).length;
|
|
58
|
-
// Removed verbose logging of all discovered rules
|
|
59
62
|
logger.debug(`Discovered ${ruleCount} modular memory rules`);
|
|
60
63
|
}
|
|
61
64
|
|
|
@@ -124,11 +127,23 @@ export class MemoryRuleManager {
|
|
|
124
127
|
try {
|
|
125
128
|
const content = await fs.readFile(filePath, "utf-8");
|
|
126
129
|
const rule = this.service.parseRule(content, filePath, source);
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
|
|
131
|
+
// Determine rulesRoot dynamically based on actual file path
|
|
132
|
+
let rulesRoot: string;
|
|
133
|
+
if (source === "project") {
|
|
134
|
+
if (filePath.includes(path.join(".claude", "rules"))) {
|
|
135
|
+
rulesRoot = path.join(this.workdir, ".claude", "rules");
|
|
136
|
+
} else {
|
|
137
|
+
rulesRoot = path.join(this.workdir, ".wave", "rules");
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
if (filePath.includes(path.join(".claude", "rules"))) {
|
|
141
|
+
rulesRoot = path.join(os.homedir(), ".claude", "rules");
|
|
142
|
+
} else {
|
|
143
|
+
rulesRoot = path.join(os.homedir(), ".wave", "rules");
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
132
147
|
const relativeId = path.relative(rulesRoot, filePath);
|
|
133
148
|
rule.id = relativeId;
|
|
134
149
|
registry[rule.id] = rule;
|
|
@@ -26,7 +26,6 @@ import type { SkillManager } from "./skillManager.js";
|
|
|
26
26
|
import { buildSystemPrompt } from "../prompts/index.js";
|
|
27
27
|
import {
|
|
28
28
|
buildPlanModeReminder,
|
|
29
|
-
buildPlanModeSparseReminder,
|
|
30
29
|
buildPlanModeReEntryReminder,
|
|
31
30
|
buildExitedPlanModeReminder,
|
|
32
31
|
} from "../prompts/planModeReminders.js";
|
|
@@ -138,6 +137,14 @@ export class AIManager {
|
|
|
138
137
|
return this.container.get<PermissionManager>("PermissionManager");
|
|
139
138
|
}
|
|
140
139
|
|
|
140
|
+
private get planManager():
|
|
141
|
+
| import("./planManager.js").PlanManager
|
|
142
|
+
| undefined {
|
|
143
|
+
return this.container.get<import("./planManager.js").PlanManager>(
|
|
144
|
+
"PlanManager",
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
141
148
|
private get configurationService(): ConfigurationService {
|
|
142
149
|
return this.container.get<ConfigurationService>("ConfigurationService")!;
|
|
143
150
|
}
|
|
@@ -253,7 +260,6 @@ export class AIManager {
|
|
|
253
260
|
this.permissionManager.setNeedsPlanModeExitAttachment(false);
|
|
254
261
|
}
|
|
255
262
|
|
|
256
|
-
// Handle plan mode reminders
|
|
257
263
|
if (currentMode !== "plan") return messages;
|
|
258
264
|
|
|
259
265
|
const planFilePath = this.permissionManager.getPlanFilePath();
|
|
@@ -261,83 +267,27 @@ export class AIManager {
|
|
|
261
267
|
|
|
262
268
|
const planExists = existsSync(planFilePath);
|
|
263
269
|
|
|
264
|
-
//
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
// Count human turns (non-meta user messages without tool results)
|
|
284
|
-
const hasToolResult = msg.blocks?.some(
|
|
285
|
-
(b: { type: string }) => b.type === "tool",
|
|
286
|
-
);
|
|
287
|
-
if (!hasToolResult) {
|
|
288
|
-
if (!foundLastReminder) {
|
|
289
|
-
humanTurnsSinceLastReminder++;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
// Check for existing plan mode system-reminders
|
|
294
|
-
if (msg.role === "user" && msg.isMeta) {
|
|
295
|
-
const textContent = msg.blocks
|
|
296
|
-
?.filter((b) => b.type === "text")
|
|
297
|
-
.map((b) => ("content" in b ? b.content : ""))
|
|
298
|
-
.join("");
|
|
299
|
-
if (
|
|
300
|
-
textContent?.includes("Plan mode is active") ||
|
|
301
|
-
textContent?.includes("Plan mode still active")
|
|
302
|
-
) {
|
|
303
|
-
planModeReminderCount++;
|
|
304
|
-
if (!foundLastReminder) {
|
|
305
|
-
foundLastReminder = true;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
270
|
+
// One-time plan entry reminder
|
|
271
|
+
const planMgr = this.planManager;
|
|
272
|
+
if (planMgr?.isPlanEntryReminderPending()) {
|
|
273
|
+
if (this.permissionManager.hasExitedPlanModeInSession() && planExists) {
|
|
274
|
+
// Re-entry: use small reminder
|
|
275
|
+
messages.push({
|
|
276
|
+
role: "user",
|
|
277
|
+
content: buildPlanModeReEntryReminder(planFilePath),
|
|
278
|
+
});
|
|
279
|
+
} else {
|
|
280
|
+
// First entry: use full reminder
|
|
281
|
+
messages.push({
|
|
282
|
+
role: "user",
|
|
283
|
+
content: buildPlanModeReminder(
|
|
284
|
+
planFilePath,
|
|
285
|
+
planExists,
|
|
286
|
+
!!this.subagentType,
|
|
287
|
+
),
|
|
288
|
+
});
|
|
308
289
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
// Throttle: only inject every 5 human turns (but always inject on first turn)
|
|
312
|
-
const TURNS_BETWEEN_REMINDERS = 5;
|
|
313
|
-
const FULL_REMINDER_EVERY_N = 5;
|
|
314
|
-
|
|
315
|
-
if (
|
|
316
|
-
foundLastReminder &&
|
|
317
|
-
humanTurnsSinceLastReminder < TURNS_BETWEEN_REMINDERS
|
|
318
|
-
) {
|
|
319
|
-
return messages; // Throttled — skip reminder
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// Determine full vs sparse
|
|
323
|
-
// Every 5th reminder is full; rest are sparse
|
|
324
|
-
const reminderNumber = planModeReminderCount + 1;
|
|
325
|
-
const isFull = reminderNumber % FULL_REMINDER_EVERY_N === 1;
|
|
326
|
-
|
|
327
|
-
if (isFull) {
|
|
328
|
-
messages.push({
|
|
329
|
-
role: "user",
|
|
330
|
-
content: buildPlanModeReminder(
|
|
331
|
-
planFilePath,
|
|
332
|
-
planExists,
|
|
333
|
-
!!this.subagentType,
|
|
334
|
-
),
|
|
335
|
-
});
|
|
336
|
-
} else {
|
|
337
|
-
messages.push({
|
|
338
|
-
role: "user",
|
|
339
|
-
content: buildPlanModeSparseReminder(planFilePath),
|
|
340
|
-
});
|
|
290
|
+
planMgr.consumePlanEntryReminder();
|
|
341
291
|
}
|
|
342
292
|
|
|
343
293
|
return messages;
|
|
@@ -183,16 +183,21 @@ export class HookManager {
|
|
|
183
183
|
env: {
|
|
184
184
|
...("env" in context ? (context.env ?? {}) : {}),
|
|
185
185
|
WAVE_PLUGIN_ROOT: hookCommand.pluginRoot,
|
|
186
|
+
CLAUDE_PLUGIN_ROOT: hookCommand.pluginRoot,
|
|
186
187
|
},
|
|
187
188
|
}
|
|
188
189
|
: context;
|
|
189
190
|
|
|
190
|
-
// Substitute ${WAVE_PLUGIN_ROOT} in the command string
|
|
191
|
+
// Substitute ${WAVE_PLUGIN_ROOT} and ${CLAUDE_PLUGIN_ROOT} in the command string
|
|
191
192
|
if (hookCommand.pluginRoot) {
|
|
192
193
|
command = command.replace(
|
|
193
194
|
/\$\{WAVE_PLUGIN_ROOT\}/g,
|
|
194
195
|
hookCommand.pluginRoot,
|
|
195
196
|
);
|
|
197
|
+
command = command.replace(
|
|
198
|
+
/\$\{CLAUDE_PLUGIN_ROOT\}/g,
|
|
199
|
+
hookCommand.pluginRoot,
|
|
200
|
+
);
|
|
196
201
|
}
|
|
197
202
|
|
|
198
203
|
if (hookCommand.async) {
|