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
|
@@ -106,26 +106,14 @@ This is critical - your turn should only end with either using the ${ASK_USER_QU
|
|
|
106
106
|
NOTE: At any point in time through this workflow you should feel free to ask the user questions or clarifications using the ${ASK_USER_QUESTION_TOOL_NAME} tool. Don't make large assumptions about user intent. The goal is to present a well researched plan to the user, and tie any loose ends before implementation begins.`);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
export function buildPlanModeSparseReminder(planFilePath: string): string {
|
|
110
|
-
return wrapInSystemReminder(
|
|
111
|
-
`Plan mode still active (see full instructions earlier in conversation). Read-only except plan file at ${planFilePath}. End turns with ${ASK_USER_QUESTION_TOOL_NAME} or ${EXIT_PLAN_MODE_TOOL_NAME}.`,
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
109
|
export function buildPlanModeReEntryReminder(planFilePath: string): string {
|
|
116
110
|
return wrapInSystemReminder(`## Re-entering Plan Mode
|
|
117
111
|
|
|
118
|
-
You are returning to plan mode
|
|
112
|
+
You are returning to plan mode. A plan file exists at ${planFilePath} from your previous session.
|
|
119
113
|
|
|
120
|
-
**Before proceeding with any new planning, you should:**
|
|
121
114
|
1. Read the existing plan file to understand what was previously planned
|
|
122
|
-
2.
|
|
123
|
-
3.
|
|
124
|
-
- **Different task**: If the user's request is for a different task—even if it's similar or related—start fresh by overwriting the existing plan
|
|
125
|
-
- **Same task, continuing**: If this is explicitly a continuation or refinement of the exact same task, modify the existing plan while cleaning up outdated or irrelevant sections
|
|
126
|
-
4. Continue on with the plan process and most importantly you should always edit the plan file one way or the other before calling ${EXIT_PLAN_MODE_TOOL_NAME}
|
|
127
|
-
|
|
128
|
-
Treat this as a fresh planning session. Do not assume the existing plan is relevant without evaluating it first.`);
|
|
115
|
+
2. Decide: if the user's request is a different task, start fresh by overwriting the plan; if it's a continuation, modify the existing plan
|
|
116
|
+
3. Edit the plan file as needed, then call ${EXIT_PLAN_MODE_TOOL_NAME}`);
|
|
129
117
|
}
|
|
130
118
|
|
|
131
119
|
export function buildExitedPlanModeReminder(
|
|
@@ -390,13 +390,21 @@ export class MarketplaceService {
|
|
|
390
390
|
async loadMarketplaceManifest(
|
|
391
391
|
marketplacePath: string,
|
|
392
392
|
): Promise<MarketplaceManifest> {
|
|
393
|
-
|
|
393
|
+
let manifestPath = path.join(
|
|
394
394
|
marketplacePath,
|
|
395
395
|
".wave-plugin",
|
|
396
396
|
"marketplace.json",
|
|
397
397
|
);
|
|
398
398
|
if (!existsSync(manifestPath)) {
|
|
399
|
-
|
|
399
|
+
// Fallback to .claude-plugin/marketplace.json
|
|
400
|
+
manifestPath = path.join(
|
|
401
|
+
marketplacePath,
|
|
402
|
+
".claude-plugin",
|
|
403
|
+
"marketplace.json",
|
|
404
|
+
);
|
|
405
|
+
if (!existsSync(manifestPath)) {
|
|
406
|
+
throw new Error(`Marketplace manifest not found at ${manifestPath}`);
|
|
407
|
+
}
|
|
400
408
|
}
|
|
401
409
|
const content = await fs.readFile(manifestPath, "utf-8");
|
|
402
410
|
const manifest = JSON.parse(content);
|
|
@@ -899,13 +907,23 @@ export class MarketplaceService {
|
|
|
899
907
|
pluginSrcPath = path.resolve(marketplacePath, pluginEntry.source);
|
|
900
908
|
}
|
|
901
909
|
|
|
902
|
-
|
|
910
|
+
let pluginManifestPath = path.join(
|
|
903
911
|
pluginSrcPath,
|
|
904
912
|
".wave-plugin",
|
|
905
913
|
"plugin.json",
|
|
906
914
|
);
|
|
907
915
|
if (!existsSync(pluginManifestPath)) {
|
|
908
|
-
|
|
916
|
+
// Fallback to .claude-plugin/plugin.json
|
|
917
|
+
pluginManifestPath = path.join(
|
|
918
|
+
pluginSrcPath,
|
|
919
|
+
".claude-plugin",
|
|
920
|
+
"plugin.json",
|
|
921
|
+
);
|
|
922
|
+
if (!existsSync(pluginManifestPath)) {
|
|
923
|
+
throw new Error(
|
|
924
|
+
`Plugin manifest not found at ${pluginManifestPath}`,
|
|
925
|
+
);
|
|
926
|
+
}
|
|
909
927
|
}
|
|
910
928
|
|
|
911
929
|
const pluginManifestContent = await fs.readFile(
|
package/src/services/memory.ts
CHANGED
|
@@ -130,6 +130,27 @@ export class MemoryService {
|
|
|
130
130
|
userMemoryFile: USER_MEMORY_FILE,
|
|
131
131
|
contentLength: content.length,
|
|
132
132
|
});
|
|
133
|
+
|
|
134
|
+
// If the file is still the default empty template, fallback to ~/.claude/AGENTS.md
|
|
135
|
+
const defaultTemplate =
|
|
136
|
+
"# User Memory\n\nThis is the user-level memory file, recording important information and context across projects.\n\n";
|
|
137
|
+
if (content === defaultTemplate) {
|
|
138
|
+
const claudeMemoryPath = path.join(homedir(), ".claude", "AGENTS.md");
|
|
139
|
+
try {
|
|
140
|
+
const claudeContent = await fs.readFile(claudeMemoryPath, "utf-8");
|
|
141
|
+
logger.debug(
|
|
142
|
+
"User memory content read from ~/.claude/AGENTS.md fallback",
|
|
143
|
+
{
|
|
144
|
+
claudeMemoryPath,
|
|
145
|
+
contentLength: claudeContent.length,
|
|
146
|
+
},
|
|
147
|
+
);
|
|
148
|
+
return claudeContent;
|
|
149
|
+
} catch {
|
|
150
|
+
// CLAUDE.md doesn't exist or can't be read, return the default template
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
133
154
|
return content;
|
|
134
155
|
} catch (error) {
|
|
135
156
|
logger.error("Failed to read user memory:", error);
|
|
@@ -139,8 +160,6 @@ export class MemoryService {
|
|
|
139
160
|
|
|
140
161
|
async readMemoryFile(workdir: string): Promise<string> {
|
|
141
162
|
const memoryFilePath = path.join(workdir, "AGENTS.md");
|
|
142
|
-
|
|
143
|
-
// Direct file access
|
|
144
163
|
try {
|
|
145
164
|
const content = await fs.readFile(memoryFilePath, "utf-8");
|
|
146
165
|
logger.debug("Memory file read successfully via direct file access", {
|
|
@@ -150,10 +169,28 @@ export class MemoryService {
|
|
|
150
169
|
return content;
|
|
151
170
|
} catch (error) {
|
|
152
171
|
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
172
|
+
// Fallback to CLAUDE.md
|
|
173
|
+
const claudeMemoryPath = path.join(workdir, "CLAUDE.md");
|
|
174
|
+
try {
|
|
175
|
+
const content = await fs.readFile(claudeMemoryPath, "utf-8");
|
|
176
|
+
logger.debug("Memory file read from CLAUDE.md fallback", {
|
|
177
|
+
memoryFilePath: claudeMemoryPath,
|
|
178
|
+
contentLength: content.length,
|
|
179
|
+
});
|
|
180
|
+
return content;
|
|
181
|
+
} catch (claudeError) {
|
|
182
|
+
if ((claudeError as NodeJS.ErrnoException).code === "ENOENT") {
|
|
183
|
+
logger.debug("Neither AGENTS.md nor CLAUDE.md found", {
|
|
184
|
+
memoryFilePath,
|
|
185
|
+
});
|
|
186
|
+
return "";
|
|
187
|
+
}
|
|
188
|
+
logger.error("Failed to read CLAUDE.md fallback", {
|
|
189
|
+
memoryFilePath: claudeMemoryPath,
|
|
190
|
+
error: claudeError,
|
|
191
|
+
});
|
|
192
|
+
return "";
|
|
193
|
+
}
|
|
157
194
|
}
|
|
158
195
|
logger.error("Failed to read memory file", { memoryFilePath, error });
|
|
159
196
|
return "";
|
|
@@ -23,11 +23,13 @@ export class PluginLoader {
|
|
|
23
23
|
*/
|
|
24
24
|
static async loadManifest(pluginPath: string): Promise<PluginManifest> {
|
|
25
25
|
const dotWavePluginPath = path.join(pluginPath, ".wave-plugin");
|
|
26
|
-
const manifestPath = path.join(dotWavePluginPath, "plugin.json");
|
|
27
26
|
|
|
28
|
-
//
|
|
27
|
+
// Check if .wave-plugin/ directory exists
|
|
28
|
+
let wavePluginDirExists = false;
|
|
29
29
|
try {
|
|
30
30
|
const entries = await fs.readdir(dotWavePluginPath);
|
|
31
|
+
wavePluginDirExists = true;
|
|
32
|
+
// T018: Ensure plugin.json is the only file in .wave-plugin/
|
|
31
33
|
const misplaced = entries.filter((e) => e !== "plugin.json");
|
|
32
34
|
if (misplaced.length > 0) {
|
|
33
35
|
throw new Error(
|
|
@@ -39,15 +41,39 @@ export class PluginLoader {
|
|
|
39
41
|
error instanceof Error &&
|
|
40
42
|
(error as { code?: string }).code === "ENOENT"
|
|
41
43
|
) {
|
|
44
|
+
// .wave-plugin/ doesn't exist, will try .claude-plugin/ fallback below
|
|
45
|
+
} else {
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (wavePluginDirExists) {
|
|
51
|
+
const manifestPath = path.join(dotWavePluginPath, "plugin.json");
|
|
52
|
+
try {
|
|
53
|
+
const content = await fs.readFile(manifestPath, "utf-8");
|
|
54
|
+
const manifest = JSON.parse(content) as PluginManifest;
|
|
55
|
+
this.validateManifest(manifest);
|
|
56
|
+
return manifest;
|
|
57
|
+
} catch (error) {
|
|
58
|
+
if (
|
|
59
|
+
error instanceof Error &&
|
|
60
|
+
(error as { code?: string }).code === "ENOENT"
|
|
61
|
+
) {
|
|
62
|
+
throw new Error(`Plugin manifest not found at ${manifestPath}`);
|
|
63
|
+
}
|
|
42
64
|
throw new Error(
|
|
43
|
-
`
|
|
65
|
+
`Failed to load plugin manifest at ${manifestPath}: ${
|
|
66
|
+
error instanceof Error ? error.message : String(error)
|
|
67
|
+
}`,
|
|
44
68
|
);
|
|
45
69
|
}
|
|
46
|
-
throw error;
|
|
47
70
|
}
|
|
48
71
|
|
|
72
|
+
// Fallback to .claude-plugin/
|
|
73
|
+
const dotClaudePluginPath = path.join(pluginPath, ".claude-plugin");
|
|
74
|
+
const claudeManifestPath = path.join(dotClaudePluginPath, "plugin.json");
|
|
49
75
|
try {
|
|
50
|
-
const content = await fs.readFile(
|
|
76
|
+
const content = await fs.readFile(claudeManifestPath, "utf-8");
|
|
51
77
|
const manifest = JSON.parse(content) as PluginManifest;
|
|
52
78
|
this.validateManifest(manifest);
|
|
53
79
|
return manifest;
|
|
@@ -56,10 +82,12 @@ export class PluginLoader {
|
|
|
56
82
|
error instanceof Error &&
|
|
57
83
|
(error as { code?: string }).code === "ENOENT"
|
|
58
84
|
) {
|
|
59
|
-
throw new Error(
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Plugin manifest not found at ${dotWavePluginPath} or ${dotClaudePluginPath}`,
|
|
87
|
+
);
|
|
60
88
|
}
|
|
61
89
|
throw new Error(
|
|
62
|
-
`Failed to load plugin manifest at ${
|
|
90
|
+
`Failed to load plugin manifest at ${claudeManifestPath}: ${
|
|
63
91
|
error instanceof Error ? error.message : String(error)
|
|
64
92
|
}`,
|
|
65
93
|
);
|
package/src/types/skills.ts
CHANGED
|
@@ -70,21 +70,26 @@ export function scanCommandsDirectory(dirPath: string): CustomSlashCommand[] {
|
|
|
70
70
|
* Load all custom slash commands from both project and user directories
|
|
71
71
|
*/
|
|
72
72
|
export function loadCustomSlashCommands(workdir: string): CustomSlashCommand[] {
|
|
73
|
-
const
|
|
74
|
-
|
|
73
|
+
const userClaudeCommands = scanCommandsDirectory(
|
|
74
|
+
join(homedir(), ".claude", "commands"),
|
|
75
|
+
);
|
|
76
|
+
const userWaveCommands = scanCommandsDirectory(getUserCommandsDir());
|
|
77
|
+
const projectClaudeCommands = scanCommandsDirectory(
|
|
78
|
+
join(workdir, ".claude", "commands"),
|
|
79
|
+
);
|
|
80
|
+
const projectWaveCommands = scanCommandsDirectory(
|
|
81
|
+
getProjectCommandsDir(workdir),
|
|
82
|
+
);
|
|
75
83
|
|
|
76
|
-
// Project commands take precedence over user commands with the same name
|
|
77
84
|
const commandMap = new Map<string, CustomSlashCommand>();
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
85
|
+
// Write in priority order: lowest first, highest last (overwrites)
|
|
86
|
+
for (const command of [
|
|
87
|
+
...userClaudeCommands,
|
|
88
|
+
...userWaveCommands,
|
|
89
|
+
...projectClaudeCommands,
|
|
90
|
+
...projectWaveCommands,
|
|
91
|
+
]) {
|
|
81
92
|
commandMap.set(command.id, command);
|
|
82
93
|
}
|
|
83
|
-
|
|
84
|
-
// Add project commands (will overwrite user commands with same name)
|
|
85
|
-
for (const command of projectCommands) {
|
|
86
|
-
commandMap.set(command.id, command);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
94
|
return Array.from(commandMap.values());
|
|
90
95
|
}
|
package/src/utils/skillParser.ts
CHANGED
|
@@ -55,7 +55,9 @@ export function parseSkillFile(
|
|
|
55
55
|
const skillPath = basePath || dirname(filePath);
|
|
56
56
|
const skillType =
|
|
57
57
|
skillPath.includes("/.wave/skills") ||
|
|
58
|
-
skillPath.includes("\\.wave\\skills")
|
|
58
|
+
skillPath.includes("\\.wave\\skills") ||
|
|
59
|
+
skillPath.includes("/.claude/skills") ||
|
|
60
|
+
skillPath.includes("\\.claude\\skills")
|
|
59
61
|
? "project"
|
|
60
62
|
: "personal";
|
|
61
63
|
|
|
@@ -230,20 +230,34 @@ function scanSubagentDirectory(
|
|
|
230
230
|
export async function loadSubagentConfigurations(
|
|
231
231
|
workdir: string,
|
|
232
232
|
): Promise<SubagentConfiguration[]> {
|
|
233
|
-
const
|
|
234
|
-
const
|
|
233
|
+
const projectWaveDir = join(workdir, ".wave", "agents");
|
|
234
|
+
const projectClaudeDir = join(workdir, ".claude", "agents");
|
|
235
|
+
const userWaveDir = join(process.env.HOME || "~", ".wave", "agents");
|
|
236
|
+
const userClaudeDir = join(process.env.HOME || "~", ".claude", "agents");
|
|
235
237
|
const builtinDir = getBuiltinSubagentsDir();
|
|
236
238
|
|
|
237
239
|
// Load configurations from all sources
|
|
238
240
|
const builtinConfigs = scanSubagentDirectory(builtinDir, "builtin");
|
|
239
|
-
const
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
241
|
+
const userClaudeConfigs = scanSubagentDirectory(userClaudeDir, "user");
|
|
242
|
+
const userWaveConfigs = scanSubagentDirectory(userWaveDir, "user");
|
|
243
|
+
const projectClaudeConfigs = scanSubagentDirectory(
|
|
244
|
+
projectClaudeDir,
|
|
245
|
+
"project",
|
|
246
|
+
);
|
|
247
|
+
const projectWaveConfigs = scanSubagentDirectory(projectWaveDir, "project");
|
|
248
|
+
|
|
249
|
+
// Merge configurations, with .wave taking priority over .claude
|
|
243
250
|
const configMap = new Map<string, SubagentConfiguration>();
|
|
244
251
|
|
|
245
|
-
//
|
|
246
|
-
|
|
252
|
+
// Merge order: builtin → userClaude → userWave → projectClaude → projectWave
|
|
253
|
+
// Later writes override earlier ones, so .wave takes priority over .claude
|
|
254
|
+
for (const config of [
|
|
255
|
+
...builtinConfigs,
|
|
256
|
+
...userClaudeConfigs,
|
|
257
|
+
...userWaveConfigs,
|
|
258
|
+
...projectClaudeConfigs,
|
|
259
|
+
...projectWaveConfigs,
|
|
260
|
+
]) {
|
|
247
261
|
configMap.set(config.name, config);
|
|
248
262
|
}
|
|
249
263
|
|