wave-agent-sdk 0.7.1 → 0.8.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 +9 -79
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +85 -302
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +20 -13
- package/dist/managers/backgroundTaskManager.d.ts +1 -1
- package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
- package/dist/managers/backgroundTaskManager.js +1 -1
- package/dist/managers/{bashManager.d.ts → bangManager.d.ts} +4 -4
- package/dist/managers/{bashManager.d.ts.map → bangManager.d.ts.map} +1 -1
- package/dist/managers/{bashManager.js → bangManager.js} +5 -6
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +12 -3
- package/dist/managers/messageManager.d.ts +18 -6
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +42 -20
- package/dist/managers/permissionManager.d.ts +22 -1
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +106 -85
- package/dist/managers/planManager.d.ts +6 -0
- package/dist/managers/planManager.d.ts.map +1 -1
- package/dist/managers/planManager.js +21 -0
- package/dist/managers/skillManager.d.ts +7 -2
- package/dist/managers/skillManager.d.ts.map +1 -1
- package/dist/managers/skillManager.js +30 -10
- package/dist/managers/slashCommandManager.d.ts +7 -0
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +57 -45
- package/dist/managers/subagentManager.d.ts +4 -0
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +47 -13
- package/dist/managers/toolManager.d.ts +7 -1
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +15 -2
- package/dist/prompts/index.d.ts +0 -4
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +0 -9
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +6 -6
- package/dist/services/configurationService.d.ts +2 -2
- package/dist/services/configurationService.d.ts.map +1 -1
- package/dist/services/configurationService.js +4 -4
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +6 -0
- package/dist/services/initializationService.d.ts +44 -0
- package/dist/services/initializationService.d.ts.map +1 -0
- package/dist/services/initializationService.js +170 -0
- package/dist/services/interactionService.d.ts +29 -0
- package/dist/services/interactionService.d.ts.map +1 -0
- package/dist/services/interactionService.js +97 -0
- package/dist/services/session.js +1 -1
- package/dist/services/taskManager.d.ts +5 -0
- package/dist/services/taskManager.d.ts.map +1 -1
- package/dist/services/taskManager.js +16 -2
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +7 -18
- package/dist/tools/editTool.js +1 -1
- package/dist/tools/exitPlanMode.js +1 -1
- package/dist/tools/lspTool.d.ts +2 -0
- package/dist/tools/lspTool.d.ts.map +1 -1
- package/dist/tools/lspTool.js +144 -52
- package/dist/tools/skillTool.d.ts.map +1 -1
- package/dist/tools/skillTool.js +97 -2
- package/dist/tools/taskManagementTools.d.ts.map +1 -1
- package/dist/tools/taskManagementTools.js +23 -2
- package/dist/tools/taskTool.d.ts.map +1 -1
- package/dist/tools/taskTool.js +9 -15
- package/dist/tools/types.d.ts +1 -2
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/writeTool.js +1 -1
- package/dist/types/agent.d.ts +64 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +1 -0
- package/dist/types/commands.d.ts +0 -4
- package/dist/types/commands.d.ts.map +1 -1
- package/dist/types/config.d.ts +1 -1
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/hooks.d.ts +3 -1
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +1 -0
- 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 +3 -3
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/skills.d.ts +13 -0
- package/dist/types/skills.d.ts.map +1 -1
- package/dist/utils/commandPathResolver.d.ts +3 -36
- package/dist/utils/commandPathResolver.d.ts.map +1 -1
- package/dist/utils/commandPathResolver.js +16 -93
- package/dist/utils/configValidator.d.ts +2 -2
- package/dist/utils/configValidator.d.ts.map +1 -1
- package/dist/utils/configValidator.js +4 -6
- package/dist/utils/containerSetup.d.ts +3 -4
- package/dist/utils/containerSetup.d.ts.map +1 -1
- package/dist/utils/containerSetup.js +14 -9
- package/dist/utils/customCommands.d.ts +2 -3
- package/dist/utils/customCommands.d.ts.map +1 -1
- package/dist/utils/customCommands.js +20 -60
- package/dist/utils/gitUtils.d.ts +25 -0
- package/dist/utils/gitUtils.d.ts.map +1 -1
- package/dist/utils/gitUtils.js +75 -0
- package/dist/utils/markdownParser.d.ts +4 -0
- package/dist/utils/markdownParser.d.ts.map +1 -1
- package/dist/utils/markdownParser.js +33 -0
- package/dist/utils/messageOperations.d.ts +16 -7
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +45 -20
- package/dist/utils/nameGenerator.d.ts +1 -1
- package/dist/utils/nameGenerator.d.ts.map +1 -1
- package/dist/utils/nameGenerator.js +10 -6
- package/dist/utils/skillParser.d.ts.map +1 -1
- package/dist/utils/skillParser.js +48 -0
- package/package.json +1 -1
- package/src/agent.ts +103 -458
- package/src/index.ts +2 -2
- package/src/managers/aiManager.ts +23 -17
- package/src/managers/backgroundTaskManager.ts +2 -2
- package/src/managers/{bashManager.ts → bangManager.ts} +11 -8
- package/src/managers/hookManager.ts +13 -3
- package/src/managers/messageManager.ts +55 -26
- package/src/managers/permissionManager.ts +121 -98
- package/src/managers/planManager.ts +26 -0
- package/src/managers/skillManager.ts +51 -14
- package/src/managers/slashCommandManager.ts +75 -55
- package/src/managers/subagentManager.ts +57 -13
- package/src/managers/toolManager.ts +22 -2
- package/src/prompts/index.ts +0 -15
- package/src/services/aiService.ts +9 -12
- package/src/services/configurationService.ts +4 -4
- package/src/services/hook.ts +7 -0
- package/src/services/initializationService.ts +291 -0
- package/src/services/interactionService.ts +171 -0
- package/src/services/session.ts +1 -1
- package/src/services/taskManager.ts +18 -2
- package/src/tools/bashTool.ts +8 -18
- package/src/tools/editTool.ts +1 -1
- package/src/tools/exitPlanMode.ts +1 -1
- package/src/tools/lsTool.ts +1 -1
- package/src/tools/lspTool.ts +184 -52
- package/src/tools/skillTool.ts +127 -2
- package/src/tools/taskManagementTools.ts +32 -2
- package/src/tools/taskTool.ts +13 -15
- package/src/tools/types.ts +1 -2
- package/src/tools/writeTool.ts +1 -1
- package/src/types/agent.ts +83 -0
- package/src/types/commands.ts +0 -6
- package/src/types/config.ts +1 -1
- package/src/types/hooks.ts +5 -1
- package/src/types/index.ts +1 -0
- package/src/types/messaging.ts +3 -3
- package/src/types/skills.ts +13 -0
- package/src/utils/commandPathResolver.ts +14 -117
- package/src/utils/configValidator.ts +5 -9
- package/src/utils/containerSetup.ts +17 -14
- package/src/utils/customCommands.ts +20 -83
- package/src/utils/gitUtils.ts +75 -0
- package/src/utils/markdownParser.ts +47 -0
- package/src/utils/messageOperations.ts +58 -28
- package/src/utils/nameGenerator.ts +10 -6
- package/src/utils/skillParser.ts +52 -0
- package/dist/managers/backgroundBashManager.d.ts +0 -27
- package/dist/managers/backgroundBashManager.d.ts.map +0 -1
- package/dist/managers/backgroundBashManager.js +0 -169
- package/src/managers/backgroundBashManager.ts +0 -206
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import * as fs from "fs/promises";
|
|
3
|
+
import os from "os";
|
|
4
|
+
import { handleSessionRestoration } from "./session.js";
|
|
5
|
+
import { setGlobalLogger } from "../utils/globalLogger.js";
|
|
6
|
+
import { LspManager } from "../managers/lspManager.js";
|
|
7
|
+
import type {
|
|
8
|
+
Message,
|
|
9
|
+
Logger,
|
|
10
|
+
AgentOptions,
|
|
11
|
+
ILspManager,
|
|
12
|
+
} from "../types/index.js";
|
|
13
|
+
import type { SkillManager } from "../managers/skillManager.js";
|
|
14
|
+
import type { SubagentManager } from "../managers/subagentManager.js";
|
|
15
|
+
import type { Container } from "../utils/container.js";
|
|
16
|
+
import type { ToolManager } from "../managers/toolManager.js";
|
|
17
|
+
import type { PluginManager } from "../managers/pluginManager.js";
|
|
18
|
+
import type { SlashCommandManager } from "../managers/slashCommandManager.js";
|
|
19
|
+
import type { McpManager } from "../managers/mcpManager.js";
|
|
20
|
+
import type { ConfigurationService } from "./configurationService.js";
|
|
21
|
+
import type { HookManager } from "../managers/hookManager.js";
|
|
22
|
+
import type { MessageManager } from "../managers/messageManager.js";
|
|
23
|
+
import type { MemoryRuleManager } from "../managers/MemoryRuleManager.js";
|
|
24
|
+
import type { LiveConfigManager } from "../managers/liveConfigManager.js";
|
|
25
|
+
import type { TaskManager } from "./taskManager.js";
|
|
26
|
+
import type { PermissionManager } from "../managers/permissionManager.js";
|
|
27
|
+
|
|
28
|
+
export interface InitializationContext {
|
|
29
|
+
skillManager: SkillManager;
|
|
30
|
+
subagentManager: SubagentManager;
|
|
31
|
+
container: Container;
|
|
32
|
+
toolManager: ToolManager;
|
|
33
|
+
pluginManager: PluginManager;
|
|
34
|
+
options: AgentOptions;
|
|
35
|
+
slashCommandManager: SlashCommandManager;
|
|
36
|
+
logger?: Logger;
|
|
37
|
+
mcpManager: McpManager;
|
|
38
|
+
workdir: string;
|
|
39
|
+
lspManager: ILspManager;
|
|
40
|
+
configurationService: ConfigurationService;
|
|
41
|
+
hookManager: HookManager;
|
|
42
|
+
messageManager: MessageManager;
|
|
43
|
+
memoryRuleManager: MemoryRuleManager;
|
|
44
|
+
liveConfigManager: LiveConfigManager;
|
|
45
|
+
taskManager: TaskManager;
|
|
46
|
+
setProjectMemory: (content: string) => void;
|
|
47
|
+
setUserMemory: (content: string) => void;
|
|
48
|
+
resolveAndValidateConfig: () => void;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class InitializationService {
|
|
52
|
+
public static async initialize(
|
|
53
|
+
context: InitializationContext,
|
|
54
|
+
options?: {
|
|
55
|
+
restoreSessionId?: string;
|
|
56
|
+
continueLastSession?: boolean;
|
|
57
|
+
messages?: Message[];
|
|
58
|
+
},
|
|
59
|
+
): Promise<void> {
|
|
60
|
+
const {
|
|
61
|
+
skillManager,
|
|
62
|
+
subagentManager,
|
|
63
|
+
container,
|
|
64
|
+
toolManager,
|
|
65
|
+
pluginManager,
|
|
66
|
+
options: agentOptions,
|
|
67
|
+
slashCommandManager,
|
|
68
|
+
logger,
|
|
69
|
+
mcpManager,
|
|
70
|
+
workdir,
|
|
71
|
+
lspManager,
|
|
72
|
+
configurationService,
|
|
73
|
+
hookManager,
|
|
74
|
+
messageManager,
|
|
75
|
+
memoryRuleManager,
|
|
76
|
+
liveConfigManager,
|
|
77
|
+
taskManager,
|
|
78
|
+
setProjectMemory,
|
|
79
|
+
setUserMemory,
|
|
80
|
+
resolveAndValidateConfig,
|
|
81
|
+
} = context;
|
|
82
|
+
|
|
83
|
+
// Initialize managers first
|
|
84
|
+
try {
|
|
85
|
+
// Initialize SkillManager
|
|
86
|
+
await skillManager.initialize();
|
|
87
|
+
|
|
88
|
+
// Initialize SubagentManager (load and cache configurations)
|
|
89
|
+
await subagentManager.initialize();
|
|
90
|
+
|
|
91
|
+
// Register managers in container for tool access
|
|
92
|
+
container.register("SubagentManager", subagentManager);
|
|
93
|
+
container.register("SkillManager", skillManager);
|
|
94
|
+
|
|
95
|
+
// Initialize built-in tools
|
|
96
|
+
toolManager.initializeBuiltInTools();
|
|
97
|
+
|
|
98
|
+
// Initialize plugins
|
|
99
|
+
await pluginManager.loadPlugins(agentOptions.plugins || []);
|
|
100
|
+
|
|
101
|
+
// Register skill commands
|
|
102
|
+
slashCommandManager.registerSkillCommands(
|
|
103
|
+
skillManager.getAvailableSkills(),
|
|
104
|
+
);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
logger?.error("Failed to initialize managers and tools:", error);
|
|
107
|
+
// Don't throw error to prevent app startup failure
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Initialize MCP servers with auto-connect
|
|
111
|
+
try {
|
|
112
|
+
await mcpManager.initialize(workdir, true);
|
|
113
|
+
if (lspManager instanceof LspManager) {
|
|
114
|
+
await lspManager.initialize(workdir);
|
|
115
|
+
}
|
|
116
|
+
} catch (error) {
|
|
117
|
+
logger?.error("Failed to initialize MCP servers:", error);
|
|
118
|
+
// Don't throw error to prevent app startup failure
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Initialize hooks configuration
|
|
122
|
+
try {
|
|
123
|
+
// Load hooks configuration using ConfigurationService
|
|
124
|
+
logger?.debug("Loading hooks configuration...");
|
|
125
|
+
const configResult =
|
|
126
|
+
await configurationService.loadMergedConfiguration(workdir);
|
|
127
|
+
|
|
128
|
+
hookManager.loadConfigurationFromWaveConfig(configResult.configuration);
|
|
129
|
+
|
|
130
|
+
// Update plugin manager with enabled plugins configuration
|
|
131
|
+
if (configResult.configuration?.enabledPlugins) {
|
|
132
|
+
pluginManager.updateEnabledPlugins(
|
|
133
|
+
configResult.configuration.enabledPlugins,
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Initialize permission manager with loaded rules
|
|
138
|
+
if (configResult.configuration?.permissions) {
|
|
139
|
+
const permissionManager =
|
|
140
|
+
context.container.get<PermissionManager>("PermissionManager");
|
|
141
|
+
if (permissionManager) {
|
|
142
|
+
if (configResult.configuration.permissions.allow) {
|
|
143
|
+
permissionManager.updateAllowedRules(
|
|
144
|
+
configResult.configuration.permissions.allow,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
if (configResult.configuration.permissions.deny) {
|
|
148
|
+
permissionManager.updateDeniedRules(
|
|
149
|
+
configResult.configuration.permissions.deny,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
if (configResult.configuration.permissions.defaultMode) {
|
|
153
|
+
permissionManager.updateConfiguredDefaultMode(
|
|
154
|
+
configResult.configuration.permissions.defaultMode,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
logger?.debug("Hooks system initialized successfully");
|
|
161
|
+
} catch (error) {
|
|
162
|
+
logger?.error("Failed to initialize hooks system:", error);
|
|
163
|
+
// Don't throw error to prevent app startup failure
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Trigger WorktreeCreate hook if this is a new worktree
|
|
167
|
+
if (agentOptions.isNewWorktree && hookManager) {
|
|
168
|
+
try {
|
|
169
|
+
logger?.info(
|
|
170
|
+
`Triggering WorktreeCreate hook for ${agentOptions.worktreeName}...`,
|
|
171
|
+
);
|
|
172
|
+
const hookResults = await hookManager.executeHooks("WorktreeCreate", {
|
|
173
|
+
event: "WorktreeCreate",
|
|
174
|
+
projectDir: workdir,
|
|
175
|
+
timestamp: new Date(),
|
|
176
|
+
sessionId: messageManager.getSessionId(),
|
|
177
|
+
transcriptPath: messageManager.getTranscriptPath(),
|
|
178
|
+
cwd: workdir,
|
|
179
|
+
worktreeName: agentOptions.worktreeName,
|
|
180
|
+
env: configurationService.getEnvironmentVars(),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// Process hook results
|
|
184
|
+
hookManager.processHookResults(
|
|
185
|
+
"WorktreeCreate",
|
|
186
|
+
hookResults,
|
|
187
|
+
messageManager,
|
|
188
|
+
);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
logger?.warn("WorktreeCreate hooks execution failed:", error);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Resolve and validate configuration after loading settings.json
|
|
195
|
+
resolveAndValidateConfig();
|
|
196
|
+
|
|
197
|
+
// Set global logger for SDK-wide access before discovering rules
|
|
198
|
+
setGlobalLogger(logger || null);
|
|
199
|
+
|
|
200
|
+
// Discover modular memory rules
|
|
201
|
+
try {
|
|
202
|
+
await memoryRuleManager.discoverRules();
|
|
203
|
+
} catch (error) {
|
|
204
|
+
logger?.error("Failed to discover memory rules:", error);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Initialize live configuration reload
|
|
208
|
+
try {
|
|
209
|
+
logger?.debug("Initializing live configuration reload...");
|
|
210
|
+
await liveConfigManager.initialize();
|
|
211
|
+
logger?.debug("Live configuration reload initialized successfully");
|
|
212
|
+
} catch (error) {
|
|
213
|
+
logger?.error("Failed to initialize live configuration reload:", error);
|
|
214
|
+
// Don't throw error to prevent app startup failure - continue without live reload
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Load memory files during initialization
|
|
218
|
+
try {
|
|
219
|
+
logger?.debug("Loading memory files...");
|
|
220
|
+
|
|
221
|
+
// Load project memory from AGENTS.md (bypass memory store for direct file access)
|
|
222
|
+
try {
|
|
223
|
+
const projectMemoryPath = path.join(workdir, "AGENTS.md");
|
|
224
|
+
const projectMemoryContent = await fs.readFile(
|
|
225
|
+
projectMemoryPath,
|
|
226
|
+
"utf-8",
|
|
227
|
+
);
|
|
228
|
+
setProjectMemory(projectMemoryContent);
|
|
229
|
+
logger?.debug("Project memory loaded successfully");
|
|
230
|
+
} catch (error) {
|
|
231
|
+
setProjectMemory("");
|
|
232
|
+
logger?.debug(
|
|
233
|
+
"Project memory file not found or unreadable, using empty content:",
|
|
234
|
+
error instanceof Error ? error.message : String(error),
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Load user memory (bypass memory store for direct file access)
|
|
239
|
+
try {
|
|
240
|
+
const userMemoryPath = path.join(os.homedir(), ".wave", "AGENTS.md");
|
|
241
|
+
const userMemoryContent = await fs.readFile(userMemoryPath, "utf-8");
|
|
242
|
+
setUserMemory(userMemoryContent);
|
|
243
|
+
logger?.debug("User memory loaded successfully");
|
|
244
|
+
} catch (error) {
|
|
245
|
+
setUserMemory("");
|
|
246
|
+
logger?.debug(
|
|
247
|
+
"User memory file not found or unreadable, using empty content:",
|
|
248
|
+
error instanceof Error ? error.message : String(error),
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
logger?.debug("Memory initialization completed");
|
|
253
|
+
} catch (error) {
|
|
254
|
+
// Ensure memory is always initialized even if loading fails
|
|
255
|
+
setProjectMemory("");
|
|
256
|
+
setUserMemory("");
|
|
257
|
+
logger?.error("Failed to load memory files:", error);
|
|
258
|
+
// Don't throw error to prevent app startup failure
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Handle session restoration or set provided messages
|
|
262
|
+
if (options?.messages) {
|
|
263
|
+
// If messages are provided, use them directly (useful for testing)
|
|
264
|
+
messageManager.setMessages(options.messages);
|
|
265
|
+
// Rebuild usage array from restored messages
|
|
266
|
+
messageManager.rebuildUsageFromMessages(options.messages);
|
|
267
|
+
} else {
|
|
268
|
+
// Otherwise, handle session restoration
|
|
269
|
+
const sessionToRestore = await handleSessionRestoration(
|
|
270
|
+
options?.restoreSessionId,
|
|
271
|
+
options?.continueLastSession,
|
|
272
|
+
messageManager.getWorkdir(),
|
|
273
|
+
);
|
|
274
|
+
// Rebuild usage array from restored messages
|
|
275
|
+
messageManager.rebuildUsageFromMessages(sessionToRestore?.messages || []);
|
|
276
|
+
|
|
277
|
+
if (sessionToRestore) {
|
|
278
|
+
messageManager.initializeFromSession(sessionToRestore);
|
|
279
|
+
|
|
280
|
+
// Update task manager with the root session ID to ensure continuity across compressions
|
|
281
|
+
taskManager.setTaskListId(
|
|
282
|
+
sessionToRestore.rootSessionId || sessionToRestore.id,
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
// After session is initialized, load tasks for the session
|
|
286
|
+
const tasks = await taskManager.listTasks();
|
|
287
|
+
agentOptions.callbacks?.onTasksChange?.(tasks);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { loadSessionFromJsonl } from "./session.js";
|
|
2
|
+
import type { Logger, AgentOptions } from "../types/index.js";
|
|
3
|
+
import type { MessageManager } from "../managers/messageManager.js";
|
|
4
|
+
import type { SlashCommandManager } from "../managers/slashCommandManager.js";
|
|
5
|
+
import type { HookManager } from "../managers/hookManager.js";
|
|
6
|
+
import type { ConfigurationService } from "./configurationService.js";
|
|
7
|
+
import type { AIManager } from "../managers/aiManager.js";
|
|
8
|
+
import type { SubagentManager } from "../managers/subagentManager.js";
|
|
9
|
+
import type { TaskManager } from "./taskManager.js";
|
|
10
|
+
|
|
11
|
+
export interface InteractionContext {
|
|
12
|
+
messageManager: MessageManager;
|
|
13
|
+
slashCommandManager: SlashCommandManager;
|
|
14
|
+
hookManager: HookManager;
|
|
15
|
+
workdir: string;
|
|
16
|
+
configurationService: ConfigurationService;
|
|
17
|
+
logger?: Logger;
|
|
18
|
+
aiManager: AIManager;
|
|
19
|
+
subagentManager: SubagentManager;
|
|
20
|
+
taskManager: TaskManager;
|
|
21
|
+
options: AgentOptions;
|
|
22
|
+
abortMessage: () => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class InteractionService {
|
|
26
|
+
public static async sendMessage(
|
|
27
|
+
context: InteractionContext,
|
|
28
|
+
content: string,
|
|
29
|
+
images?: Array<{ path: string; mimeType: string }>,
|
|
30
|
+
): Promise<void> {
|
|
31
|
+
const {
|
|
32
|
+
messageManager,
|
|
33
|
+
slashCommandManager,
|
|
34
|
+
hookManager,
|
|
35
|
+
workdir,
|
|
36
|
+
configurationService,
|
|
37
|
+
logger,
|
|
38
|
+
aiManager,
|
|
39
|
+
} = context;
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
// Handle slash command - check if it's a slash command (starts with /)
|
|
43
|
+
if (content.startsWith("/")) {
|
|
44
|
+
const command = content.trim();
|
|
45
|
+
if (!command || command === "/") return;
|
|
46
|
+
|
|
47
|
+
// Parse and validate slash command
|
|
48
|
+
const { isValid, commandId, args } =
|
|
49
|
+
slashCommandManager.parseAndValidateSlashCommand(command);
|
|
50
|
+
|
|
51
|
+
if (isValid && commandId !== undefined) {
|
|
52
|
+
// Execute valid slash command
|
|
53
|
+
await slashCommandManager.executeCommand(commandId, args);
|
|
54
|
+
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// If command doesn't exist, continue as normal message processing
|
|
59
|
+
// Don't add to history, let normal message processing logic below handle it
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Handle normal AI message
|
|
63
|
+
// Add user message first, will automatically sync to UI
|
|
64
|
+
messageManager.addUserMessage({
|
|
65
|
+
content,
|
|
66
|
+
images: images?.map((img) => ({
|
|
67
|
+
path: img.path,
|
|
68
|
+
mimeType: img.mimeType,
|
|
69
|
+
})),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Execute UserPromptSubmit hooks after adding the user message
|
|
73
|
+
if (hookManager) {
|
|
74
|
+
try {
|
|
75
|
+
const hookResults = await hookManager.executeHooks(
|
|
76
|
+
"UserPromptSubmit",
|
|
77
|
+
{
|
|
78
|
+
event: "UserPromptSubmit",
|
|
79
|
+
projectDir: workdir,
|
|
80
|
+
timestamp: new Date(),
|
|
81
|
+
// UserPromptSubmit doesn't need toolName
|
|
82
|
+
sessionId: messageManager.getSessionId(),
|
|
83
|
+
transcriptPath: messageManager.getTranscriptPath(),
|
|
84
|
+
cwd: workdir,
|
|
85
|
+
userPrompt: content,
|
|
86
|
+
env: configurationService.getEnvironmentVars(), // Include configuration environment variables
|
|
87
|
+
},
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
// Process hook results and determine if we should continue
|
|
91
|
+
const processResult = hookManager.processHookResults(
|
|
92
|
+
"UserPromptSubmit",
|
|
93
|
+
hookResults,
|
|
94
|
+
messageManager,
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
// If hook processing indicates we should block (exit code 2), stop here
|
|
98
|
+
if (processResult.shouldBlock) {
|
|
99
|
+
logger?.info(
|
|
100
|
+
"UserPromptSubmit hook blocked prompt processing with error:",
|
|
101
|
+
processResult.errorMessage,
|
|
102
|
+
);
|
|
103
|
+
return; // Don't send to AI
|
|
104
|
+
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
logger?.warn("UserPromptSubmit hooks execution failed:", error);
|
|
107
|
+
// Continue processing even if hooks fail
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Send AI message
|
|
112
|
+
await aiManager.sendAIMessage();
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error("Failed to add user message:", error);
|
|
115
|
+
// Loading state will be automatically updated by the useEffect that watches messages
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public static async restoreSession(
|
|
120
|
+
context: InteractionContext,
|
|
121
|
+
sessionId: string,
|
|
122
|
+
): Promise<void> {
|
|
123
|
+
const {
|
|
124
|
+
messageManager,
|
|
125
|
+
logger,
|
|
126
|
+
subagentManager,
|
|
127
|
+
taskManager,
|
|
128
|
+
options,
|
|
129
|
+
abortMessage,
|
|
130
|
+
} = context;
|
|
131
|
+
|
|
132
|
+
// 1. Validation
|
|
133
|
+
if (!sessionId || sessionId === messageManager.getSessionId()) {
|
|
134
|
+
return; // No-op if session ID is invalid or already current
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// 2. Auto-save current session
|
|
138
|
+
try {
|
|
139
|
+
await messageManager.saveSession();
|
|
140
|
+
} catch (error) {
|
|
141
|
+
logger?.warn("Failed to save current session before restore:", error);
|
|
142
|
+
// Continue with restoration even if save fails
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 3. Load target session
|
|
146
|
+
const sessionData = await loadSessionFromJsonl(
|
|
147
|
+
sessionId,
|
|
148
|
+
messageManager.getWorkdir(),
|
|
149
|
+
);
|
|
150
|
+
if (!sessionData) {
|
|
151
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 4. Clean current state
|
|
155
|
+
abortMessage(); // Abort any running operations
|
|
156
|
+
subagentManager.cleanup(); // Clean up active subagents
|
|
157
|
+
|
|
158
|
+
// 5. Rebuild usage (in correct order)
|
|
159
|
+
messageManager.rebuildUsageFromMessages(sessionData.messages);
|
|
160
|
+
|
|
161
|
+
// 6. Initialize session state last
|
|
162
|
+
messageManager.initializeFromSession(sessionData);
|
|
163
|
+
|
|
164
|
+
// Update task manager with the root session ID to ensure continuity across compressions
|
|
165
|
+
taskManager.setTaskListId(sessionData.rootSessionId || sessionData.id);
|
|
166
|
+
|
|
167
|
+
// 7. Load tasks for the restored session
|
|
168
|
+
const tasks = await taskManager.listTasks();
|
|
169
|
+
options.callbacks?.onTasksChange?.(tasks);
|
|
170
|
+
}
|
|
171
|
+
}
|
package/src/services/session.ts
CHANGED
|
@@ -768,7 +768,7 @@ export async function getFirstMessageContent(
|
|
|
768
768
|
}
|
|
769
769
|
|
|
770
770
|
const commandBlock = message.blocks.find(
|
|
771
|
-
(block) => block.type === "
|
|
771
|
+
(block) => block.type === "bang",
|
|
772
772
|
);
|
|
773
773
|
if (commandBlock && "command" in commandBlock) {
|
|
774
774
|
return commandBlock.command;
|
|
@@ -5,6 +5,7 @@ import { EventEmitter } from "events";
|
|
|
5
5
|
import { Task } from "../types/tasks.js";
|
|
6
6
|
import { logger } from "../utils/globalLogger.js";
|
|
7
7
|
import { Container } from "../utils/container.js";
|
|
8
|
+
import type { MessageManager } from "../managers/messageManager.js";
|
|
8
9
|
|
|
9
10
|
export class TaskManager extends EventEmitter {
|
|
10
11
|
private readonly baseDir: string;
|
|
@@ -27,6 +28,21 @@ export class TaskManager extends EventEmitter {
|
|
|
27
28
|
this.taskListId = taskListId;
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Syncs the task list ID with the current session's root session ID.
|
|
33
|
+
* This is typically called when the session is cleared or compressed.
|
|
34
|
+
*/
|
|
35
|
+
public async syncWithSession(): Promise<void> {
|
|
36
|
+
const messageManager = this.container.get<MessageManager>("MessageManager");
|
|
37
|
+
if (!messageManager) return;
|
|
38
|
+
|
|
39
|
+
const rootSessionId = messageManager.getRootSessionId();
|
|
40
|
+
if (this.taskListId !== rootSessionId && !process.env.WAVE_TASK_LIST_ID) {
|
|
41
|
+
this.setTaskListId(rootSessionId);
|
|
42
|
+
await this.refreshTasks();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
30
46
|
private getSessionDir(): string {
|
|
31
47
|
return join(this.baseDir, this.taskListId);
|
|
32
48
|
}
|
|
@@ -110,7 +126,7 @@ export class TaskManager extends EventEmitter {
|
|
|
110
126
|
const content = JSON.stringify(fullTask, null, 2);
|
|
111
127
|
await fs.writeFile(taskPath, content, "utf8");
|
|
112
128
|
this.emit("tasksChange", this.taskListId);
|
|
113
|
-
logger.
|
|
129
|
+
logger.debug(`Task ${taskId} created in task list ${this.taskListId}`);
|
|
114
130
|
return taskId;
|
|
115
131
|
});
|
|
116
132
|
}
|
|
@@ -141,7 +157,7 @@ export class TaskManager extends EventEmitter {
|
|
|
141
157
|
const content = JSON.stringify(task, null, 2);
|
|
142
158
|
await fs.writeFile(taskPath, content, "utf8");
|
|
143
159
|
this.emit("tasksChange", this.taskListId);
|
|
144
|
-
logger.
|
|
160
|
+
logger.debug(`Task ${task.id} updated in task list ${this.taskListId}`);
|
|
145
161
|
});
|
|
146
162
|
}
|
|
147
163
|
|
package/src/tools/bashTool.ts
CHANGED
|
@@ -153,7 +153,7 @@ Usage notes:
|
|
|
153
153
|
return {
|
|
154
154
|
success: false,
|
|
155
155
|
content: "",
|
|
156
|
-
error: `${BASH_TOOL_NAME} operation denied, reason: ${permissionResult.message || "No reason provided"}`,
|
|
156
|
+
error: `${BASH_TOOL_NAME} operation denied by user, reason: ${permissionResult.message || "No reason provided"}`,
|
|
157
157
|
};
|
|
158
158
|
}
|
|
159
159
|
} catch {
|
|
@@ -197,24 +197,9 @@ Usage notes:
|
|
|
197
197
|
|
|
198
198
|
let outputBuffer = "";
|
|
199
199
|
let errorBuffer = "";
|
|
200
|
-
let shortResultBuffer = "";
|
|
201
200
|
let isAborted = false;
|
|
202
201
|
let isBackgrounded = false;
|
|
203
202
|
|
|
204
|
-
const updateShortResult = (chunk: string) => {
|
|
205
|
-
if (!chunk) return;
|
|
206
|
-
shortResultBuffer += chunk;
|
|
207
|
-
if (shortResultBuffer.length > MAX_OUTPUT_LENGTH) {
|
|
208
|
-
shortResultBuffer = shortResultBuffer.slice(-MAX_OUTPUT_LENGTH);
|
|
209
|
-
}
|
|
210
|
-
const lastLines = shortResultBuffer
|
|
211
|
-
.trim()
|
|
212
|
-
.split("\n")
|
|
213
|
-
.slice(-3)
|
|
214
|
-
.join("\n");
|
|
215
|
-
context.onShortResultUpdate?.(lastLines || "");
|
|
216
|
-
};
|
|
217
|
-
|
|
218
203
|
const foregroundTaskId = `bash_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
219
204
|
|
|
220
205
|
// Register as foreground task
|
|
@@ -324,7 +309,6 @@ Usage notes:
|
|
|
324
309
|
if (!isAborted && !isBackgrounded && !runInBackground) {
|
|
325
310
|
const chunk = stripAnsiColors(data.toString());
|
|
326
311
|
outputBuffer += chunk;
|
|
327
|
-
updateShortResult(chunk);
|
|
328
312
|
}
|
|
329
313
|
});
|
|
330
314
|
|
|
@@ -332,7 +316,6 @@ Usage notes:
|
|
|
332
316
|
if (!isAborted && !isBackgrounded && !runInBackground) {
|
|
333
317
|
const chunk = stripAnsiColors(data.toString());
|
|
334
318
|
errorBuffer += chunk;
|
|
335
|
-
updateShortResult(chunk);
|
|
336
319
|
}
|
|
337
320
|
});
|
|
338
321
|
|
|
@@ -361,9 +344,16 @@ Usage notes:
|
|
|
361
344
|
"\n\n... (output truncated)"
|
|
362
345
|
: finalOutput;
|
|
363
346
|
|
|
347
|
+
const shortResult = combinedOutput
|
|
348
|
+
.trim()
|
|
349
|
+
.split("\n")
|
|
350
|
+
.slice(-3)
|
|
351
|
+
.join("\n");
|
|
352
|
+
|
|
364
353
|
resolve({
|
|
365
354
|
success: exitCode === 0,
|
|
366
355
|
content,
|
|
356
|
+
shortResult: shortResult || undefined,
|
|
367
357
|
error:
|
|
368
358
|
exitCode !== 0
|
|
369
359
|
? `Command failed with exit code: ${exitCode}`
|
package/src/tools/editTool.ts
CHANGED
|
@@ -182,7 +182,7 @@ Usage:
|
|
|
182
182
|
return {
|
|
183
183
|
success: false,
|
|
184
184
|
content: "",
|
|
185
|
-
error: `${EDIT_TOOL_NAME} operation denied, reason: ${permissionResult.message || "No reason provided"}`,
|
|
185
|
+
error: `${EDIT_TOOL_NAME} operation denied by user, reason: ${permissionResult.message || "No reason provided"}`,
|
|
186
186
|
};
|
|
187
187
|
}
|
|
188
188
|
} catch {
|
|
@@ -93,7 +93,7 @@ Ensure your plan is complete and unambiguous:
|
|
|
93
93
|
if (permissionResult.behavior === "deny") {
|
|
94
94
|
return {
|
|
95
95
|
success: false,
|
|
96
|
-
content: `
|
|
96
|
+
content: `Please update your proposal based on the following user feedback: ${permissionResult.message || "Plan rejected by user"}`,
|
|
97
97
|
error: permissionResult.message ? undefined : "Plan rejected by user",
|
|
98
98
|
};
|
|
99
99
|
}
|
package/src/tools/lsTool.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as fs from "fs";
|
|
|
2
2
|
import * as path from "path";
|
|
3
3
|
import { minimatch } from "minimatch";
|
|
4
4
|
import type { ToolPlugin, ToolResult, ToolContext } from "./types.js";
|
|
5
|
-
import { isBinary, getDisplayPath } from "
|
|
5
|
+
import { isBinary, getDisplayPath } from "../utils/path.js";
|
|
6
6
|
import {
|
|
7
7
|
LS_TOOL_NAME,
|
|
8
8
|
GLOB_TOOL_NAME,
|