wave-agent-sdk 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.d.ts +23 -1
- package/dist/agent.js +34 -4
- package/dist/managers/aiManager.d.ts +36 -0
- package/dist/managers/aiManager.js +240 -8
- package/dist/managers/messageManager.d.ts +1 -3
- package/dist/managers/messageManager.js +19 -9
- package/dist/managers/slashCommandManager.js +28 -0
- package/dist/managers/subagentManager.d.ts +0 -2
- package/dist/services/session.js +2 -9
- package/dist/telemetry/instrumentation.d.ts +1 -1
- package/dist/telemetry/instrumentation.js +57 -28
- package/dist/tools/bashTool.js +16 -6
- package/dist/tools/grepTool.js +11 -3
- package/dist/types/index.d.ts +3 -0
- package/dist/types/messaging.d.ts +2 -0
- package/dist/utils/containerSetup.js +0 -3
- package/dist/utils/messageOperations.d.ts +10 -1
- package/dist/utils/messageOperations.js +19 -1
- package/dist/utils/notificationXml.js +5 -0
- package/dist/utils/ripgrep.d.ts +4 -4
- package/dist/utils/ripgrep.js +4 -27
- package/package.json +20 -8
- package/bin/rg +0 -79
- package/dist/managers/forkedAgentManager.d.ts +0 -50
- package/dist/managers/forkedAgentManager.js +0 -130
- package/scripts/install_ripgrep.js +0 -111
- package/scripts/postinstall.js +0 -38
- package/src/agent.ts +0 -1271
- package/src/constants/subagents.ts +0 -4
- package/src/constants/toolLimits.ts +0 -15
- package/src/constants/tools.ts +0 -24
- package/src/core/plugin.ts +0 -237
- package/src/core/session.ts +0 -9
- package/src/index.ts +0 -38
- package/src/managers/MemoryRuleManager.ts +0 -198
- package/src/managers/aiManager.ts +0 -2429
- package/src/managers/backgroundTaskManager.ts +0 -480
- package/src/managers/bangManager.ts +0 -119
- package/src/managers/cronManager.ts +0 -401
- package/src/managers/foregroundTaskManager.ts +0 -30
- package/src/managers/forkedAgentManager.ts +0 -216
- package/src/managers/hookManager.ts +0 -1089
- package/src/managers/liveConfigManager.ts +0 -445
- package/src/managers/lspManager.ts +0 -470
- package/src/managers/mcpManager.ts +0 -1010
- package/src/managers/messageManager.ts +0 -1180
- package/src/managers/messageQueue.ts +0 -157
- package/src/managers/permissionManager.ts +0 -1140
- package/src/managers/planManager.ts +0 -112
- package/src/managers/pluginManager.ts +0 -330
- package/src/managers/pluginScopeManager.ts +0 -124
- package/src/managers/reversionManager.ts +0 -178
- package/src/managers/skillManager.ts +0 -578
- package/src/managers/slashCommandManager.ts +0 -564
- package/src/managers/subagentManager.ts +0 -915
- package/src/managers/toolManager.ts +0 -489
- package/src/managers/workflowManager.ts +0 -493
- package/src/prompts/autoMemory.ts +0 -33
- package/src/prompts/autoMemoryExtraction.ts +0 -146
- package/src/prompts/index.ts +0 -506
- package/src/prompts/planModeReminders.ts +0 -126
- package/src/services/GitService.ts +0 -131
- package/src/services/MarketplaceService.ts +0 -1052
- package/src/services/MemoryRuleService.ts +0 -71
- package/src/services/aiService.ts +0 -919
- package/src/services/authService.ts +0 -565
- package/src/services/autoMemoryService.ts +0 -280
- package/src/services/configurationService.ts +0 -1520
- package/src/services/fileWatcher.ts +0 -319
- package/src/services/hook.ts +0 -348
- package/src/services/initializationService.ts +0 -357
- package/src/services/interactionService.ts +0 -229
- package/src/services/jsonlHandler.ts +0 -295
- package/src/services/memory.ts +0 -234
- package/src/services/pluginLoader.ts +0 -252
- package/src/services/remoteSettingsService.ts +0 -366
- package/src/services/reversionService.ts +0 -122
- package/src/services/session.ts +0 -922
- package/src/services/taskManager.ts +0 -321
- package/src/telemetry/events.ts +0 -65
- package/src/telemetry/instrumentation.ts +0 -499
- package/src/telemetry/sessionTracing.ts +0 -348
- package/src/tools/agentTool.ts +0 -322
- package/src/tools/askUserQuestion.ts +0 -160
- package/src/tools/bashTool.ts +0 -621
- package/src/tools/buildTool.ts +0 -61
- package/src/tools/cronCreateTool.ts +0 -161
- package/src/tools/cronDeleteTool.ts +0 -51
- package/src/tools/cronListTool.ts +0 -47
- package/src/tools/editTool.ts +0 -313
- package/src/tools/enterPlanMode.ts +0 -124
- package/src/tools/enterWorktreeTool.ts +0 -190
- package/src/tools/exitPlanMode.ts +0 -139
- package/src/tools/exitWorktreeTool.ts +0 -236
- package/src/tools/globTool.ts +0 -167
- package/src/tools/grepTool.ts +0 -399
- package/src/tools/lspTool.ts +0 -883
- package/src/tools/readTool.ts +0 -426
- package/src/tools/skillTool.ts +0 -248
- package/src/tools/taskManagementTools.ts +0 -574
- package/src/tools/taskStopTool.ts +0 -78
- package/src/tools/types.ts +0 -137
- package/src/tools/webFetchTool.ts +0 -373
- package/src/tools/workflowTool.ts +0 -205
- package/src/tools/writeTool.ts +0 -267
- package/src/types/agent.ts +0 -128
- package/src/types/auth.ts +0 -19
- package/src/types/commands.ts +0 -30
- package/src/types/config.ts +0 -43
- package/src/types/configuration.ts +0 -168
- package/src/types/core.ts +0 -105
- package/src/types/cron.ts +0 -13
- package/src/types/environment.ts +0 -106
- package/src/types/fileSearch.ts +0 -4
- package/src/types/history.ts +0 -7
- package/src/types/hooks.ts +0 -256
- package/src/types/index.ts +0 -41
- package/src/types/lsp.ts +0 -98
- package/src/types/marketplace.ts +0 -71
- package/src/types/mcp.ts +0 -43
- package/src/types/memoryRule.ts +0 -31
- package/src/types/messaging.ts +0 -114
- package/src/types/permissions.ts +0 -80
- package/src/types/plugins.ts +0 -39
- package/src/types/processes.ts +0 -99
- package/src/types/reversion.ts +0 -29
- package/src/types/session.ts +0 -12
- package/src/types/skills.ts +0 -108
- package/src/types/tasks.ts +0 -13
- package/src/types/telemetry.ts +0 -98
- package/src/types/tools.ts +0 -44
- package/src/types/workflow.ts +0 -6
- package/src/utils/abortUtils.ts +0 -118
- package/src/utils/atomicWrite.ts +0 -61
- package/src/utils/bashParser.ts +0 -899
- package/src/utils/cacheControlUtils.ts +0 -426
- package/src/utils/commandArgumentParser.ts +0 -161
- package/src/utils/commandPathResolver.ts +0 -88
- package/src/utils/configPaths.ts +0 -220
- package/src/utils/configValidator.ts +0 -100
- package/src/utils/constants.ts +0 -39
- package/src/utils/container.ts +0 -92
- package/src/utils/containerSetup.ts +0 -371
- package/src/utils/convertMessagesForAPI.ts +0 -326
- package/src/utils/cronTasks.ts +0 -128
- package/src/utils/cronTasksLock.ts +0 -182
- package/src/utils/cronToHuman.ts +0 -99
- package/src/utils/customCommands.ts +0 -95
- package/src/utils/editUtils.ts +0 -20
- package/src/utils/fileFormat.ts +0 -40
- package/src/utils/fileSearch.ts +0 -151
- package/src/utils/fileUtils.ts +0 -223
- package/src/utils/gitUtils.ts +0 -315
- package/src/utils/globalLogger.ts +0 -128
- package/src/utils/groupMessagesByApiRound.ts +0 -121
- package/src/utils/hookMatcher.ts +0 -176
- package/src/utils/markdownParser.ts +0 -317
- package/src/utils/mcpUtils.ts +0 -138
- package/src/utils/messageOperations.ts +0 -641
- package/src/utils/modelCapabilities.ts +0 -30
- package/src/utils/nameGenerator.ts +0 -99
- package/src/utils/notificationXml.ts +0 -57
- package/src/utils/openaiClient.ts +0 -251
- package/src/utils/parseCronExpression.ts +0 -78
- package/src/utils/path.ts +0 -72
- package/src/utils/pathEncoder.ts +0 -400
- package/src/utils/pathSafety.ts +0 -40
- package/src/utils/promptHistory.ts +0 -168
- package/src/utils/ripgrep.ts +0 -35
- package/src/utils/shellResolver.ts +0 -190
- package/src/utils/skillParser.ts +0 -246
- package/src/utils/stringUtils.ts +0 -156
- package/src/utils/subagentParser.ts +0 -279
- package/src/utils/taskReminder.ts +0 -96
- package/src/utils/tokenCalculation.ts +0 -43
- package/src/utils/tokenEstimate.ts +0 -34
- package/src/utils/toolResultStorage.ts +0 -117
- package/src/utils/worktreeSession.ts +0 -26
- package/src/utils/worktreeUtils.ts +0 -786
- package/src/workflow/budgetTracker.ts +0 -34
- package/src/workflow/concurrencyLimiter.ts +0 -47
- package/src/workflow/journal.ts +0 -95
- package/src/workflow/progressReporter.ts +0 -141
- package/src/workflow/runState.ts +0 -65
- package/src/workflow/scriptRuntime.ts +0 -274
- package/src/workflow/structuredOutput.ts +0 -123
- package/src/workflow/types.ts +0 -101
- package/src/workflow/workflowApis.ts +0 -410
- package/vendor/ripgrep/linux-aarch64/rg +0 -0
- package/vendor/ripgrep/linux-x86_64/rg +0 -0
- package/vendor/ripgrep/macos-aarch64/rg +0 -0
- package/vendor/ripgrep/macos-x86_64/rg +0 -0
- package/vendor/ripgrep/windows-aarch64/rg.exe +0 -0
- package/vendor/ripgrep/windows-x86_64/rg.exe +0 -0
|
@@ -1,564 +0,0 @@
|
|
|
1
|
-
import type { MessageManager } from "./messageManager.js";
|
|
2
|
-
import type { AIManager } from "./aiManager.js";
|
|
3
|
-
import type { SlashCommand, CustomSlashCommand } from "../types/index.js";
|
|
4
|
-
import { loadCustomSlashCommands } from "../utils/customCommands.js";
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
substituteCommandParameters,
|
|
8
|
-
parseSlashCommandInput,
|
|
9
|
-
hasParameterPlaceholders,
|
|
10
|
-
} from "../utils/commandArgumentParser.js";
|
|
11
|
-
import { Container } from "../utils/container.js";
|
|
12
|
-
import {
|
|
13
|
-
parseBashCommands,
|
|
14
|
-
replaceBashCommandsWithOutput,
|
|
15
|
-
executeBashCommands,
|
|
16
|
-
} from "../utils/markdownParser.js";
|
|
17
|
-
import {
|
|
18
|
-
countToolBlocks,
|
|
19
|
-
formatToolTokenSummary,
|
|
20
|
-
} from "../utils/messageOperations.js";
|
|
21
|
-
import type { SkillManager } from "./skillManager.js";
|
|
22
|
-
import type { SkillMetadata } from "../types/skills.js";
|
|
23
|
-
import type { SubagentManager } from "./subagentManager.js";
|
|
24
|
-
import { logger } from "../utils/globalLogger.js";
|
|
25
|
-
|
|
26
|
-
export interface SlashCommandManagerOptions {
|
|
27
|
-
workdir: string;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export class SlashCommandManager {
|
|
31
|
-
private commands = new Map<string, SlashCommand>();
|
|
32
|
-
private customCommands = new Map<string, CustomSlashCommand>();
|
|
33
|
-
private skillCommandIds = new Set<string>();
|
|
34
|
-
private workdir: string;
|
|
35
|
-
private currentCommandAbortController: AbortController | null = null;
|
|
36
|
-
|
|
37
|
-
constructor(
|
|
38
|
-
private container: Container,
|
|
39
|
-
options: SlashCommandManagerOptions,
|
|
40
|
-
) {
|
|
41
|
-
this.workdir = options.workdir;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
public initialize(): void {
|
|
45
|
-
this.loadCustomCommands();
|
|
46
|
-
|
|
47
|
-
// Listen for skill refreshes and update skill commands
|
|
48
|
-
const skillManager = this.container.get<SkillManager>("SkillManager");
|
|
49
|
-
if (skillManager) {
|
|
50
|
-
skillManager.on("refreshed", (skills: SkillMetadata[]) => {
|
|
51
|
-
this.registerSkillCommands(skills);
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
private get messageManager(): MessageManager {
|
|
57
|
-
return this.container.get<MessageManager>("MessageManager")!;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
private get aiManager(): AIManager {
|
|
61
|
-
return this.container.get<AIManager>("AIManager")!;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
private get skillManager(): SkillManager {
|
|
65
|
-
return this.container.get<SkillManager>("SkillManager")!;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
private get subagentManager(): SubagentManager {
|
|
69
|
-
return this.container.get<SubagentManager>("SubagentManager")!;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Load custom commands from filesystem
|
|
74
|
-
*/
|
|
75
|
-
private loadCustomCommands(): void {
|
|
76
|
-
try {
|
|
77
|
-
const customCommands = loadCustomSlashCommands(this.workdir);
|
|
78
|
-
|
|
79
|
-
for (const command of customCommands) {
|
|
80
|
-
this.customCommands.set(command.id, command);
|
|
81
|
-
|
|
82
|
-
// Generate description: prioritize custom description, otherwise use default description
|
|
83
|
-
const description =
|
|
84
|
-
command.description ||
|
|
85
|
-
`Custom command: ${command.name}${hasParameterPlaceholders(command.content) ? " (supports parameters)" : ""}`;
|
|
86
|
-
|
|
87
|
-
// Register as a regular command with a handler that executes the custom command
|
|
88
|
-
this.registerCommand({
|
|
89
|
-
id: command.id,
|
|
90
|
-
name: command.name,
|
|
91
|
-
description,
|
|
92
|
-
handler: async (args?: string) => {
|
|
93
|
-
// Substitute parameters in the command content
|
|
94
|
-
let processedContent = command.content;
|
|
95
|
-
|
|
96
|
-
if (args) {
|
|
97
|
-
processedContent = substituteCommandParameters(
|
|
98
|
-
processedContent,
|
|
99
|
-
args,
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
await this.executeCustomCommandInMainAgent(
|
|
104
|
-
command.name,
|
|
105
|
-
processedContent,
|
|
106
|
-
command.config,
|
|
107
|
-
);
|
|
108
|
-
},
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
logger?.debug(`Loaded ${customCommands.length} custom commands`);
|
|
113
|
-
} catch (error) {
|
|
114
|
-
logger?.warn("Failed to load custom commands:", error);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Register skills as slash commands
|
|
120
|
-
*/
|
|
121
|
-
public registerSkillCommands(skills: SkillMetadata[]): void {
|
|
122
|
-
// Clear existing skill commands
|
|
123
|
-
for (const commandId of this.skillCommandIds) {
|
|
124
|
-
this.unregisterCommand(commandId);
|
|
125
|
-
}
|
|
126
|
-
this.skillCommandIds.clear();
|
|
127
|
-
|
|
128
|
-
for (const skill of skills) {
|
|
129
|
-
if (skill.userInvocable === false) {
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
const commandId = skill.name;
|
|
133
|
-
this.skillCommandIds.add(commandId);
|
|
134
|
-
|
|
135
|
-
this.registerCommand({
|
|
136
|
-
id: commandId,
|
|
137
|
-
name: skill.name,
|
|
138
|
-
description: `Skill: ${skill.description}`,
|
|
139
|
-
handler: async (args?: string, signal?: AbortSignal) => {
|
|
140
|
-
try {
|
|
141
|
-
// 1. Prepare skill content immediately
|
|
142
|
-
const prepared = await this.skillManager.prepareSkill({
|
|
143
|
-
skill_name: skill.name,
|
|
144
|
-
args,
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
if (!prepared.skill) {
|
|
148
|
-
// If skill not found or invalid, add error
|
|
149
|
-
this.messageManager.addErrorBlock(prepared.content);
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (skill.context === "fork") {
|
|
154
|
-
// Forked skill execution: add user message with text + tool block
|
|
155
|
-
const messageId = this.messageManager.addUserMessage({
|
|
156
|
-
content: `/${skill.name}${args ? ` ${args}` : ""}`,
|
|
157
|
-
customCommandContent: prepared.content,
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
const toolBlockId = this.messageManager.addToolBlockToMessage(
|
|
161
|
-
messageId,
|
|
162
|
-
{
|
|
163
|
-
name: skill.name,
|
|
164
|
-
parameters: prepared.content,
|
|
165
|
-
stage: "running",
|
|
166
|
-
},
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
// Forked skill execution
|
|
170
|
-
const subagentConfigs =
|
|
171
|
-
await this.subagentManager.loadConfigurations();
|
|
172
|
-
const subagentType = skill.agent || "general-purpose";
|
|
173
|
-
const config = subagentConfigs.find(
|
|
174
|
-
(c) => c.name === subagentType,
|
|
175
|
-
);
|
|
176
|
-
if (!config) {
|
|
177
|
-
throw new Error(
|
|
178
|
-
`Subagent configuration for ${subagentType} not found`,
|
|
179
|
-
);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
try {
|
|
183
|
-
const instance = await this.subagentManager.createInstance(
|
|
184
|
-
config,
|
|
185
|
-
{
|
|
186
|
-
description: skill.description,
|
|
187
|
-
prompt: prepared.content,
|
|
188
|
-
subagent_type: subagentType,
|
|
189
|
-
model: skill.model,
|
|
190
|
-
},
|
|
191
|
-
false,
|
|
192
|
-
() => {
|
|
193
|
-
// Update the tool block with progress
|
|
194
|
-
const subagent = this.subagentManager.getInstance(
|
|
195
|
-
instance.subagentId,
|
|
196
|
-
);
|
|
197
|
-
if (subagent) {
|
|
198
|
-
const messages = subagent.messages;
|
|
199
|
-
const tokens =
|
|
200
|
-
subagent.messageManager.getLatestTotalTokens();
|
|
201
|
-
const usedTools = subagent.usedTools;
|
|
202
|
-
|
|
203
|
-
const toolCount = countToolBlocks(messages);
|
|
204
|
-
const summary = formatToolTokenSummary(toolCount, tokens);
|
|
205
|
-
|
|
206
|
-
const getDisplayParam = (t: {
|
|
207
|
-
name: string;
|
|
208
|
-
parameters: string;
|
|
209
|
-
compactParams?: string;
|
|
210
|
-
stage?: string;
|
|
211
|
-
}) => {
|
|
212
|
-
if (
|
|
213
|
-
(t.stage === "end" || t.stage === "running") &&
|
|
214
|
-
t.compactParams
|
|
215
|
-
) {
|
|
216
|
-
return t.compactParams;
|
|
217
|
-
}
|
|
218
|
-
const flat = t.parameters.replace(/\n/g, "\\n");
|
|
219
|
-
return flat.length > 30 ? `…${flat.slice(-30)}` : flat;
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
let shortResult = "";
|
|
223
|
-
if (toolCount > 2) {
|
|
224
|
-
shortResult += "... ";
|
|
225
|
-
}
|
|
226
|
-
shortResult += summary;
|
|
227
|
-
if (usedTools.length > 0) {
|
|
228
|
-
shortResult +=
|
|
229
|
-
"\n" +
|
|
230
|
-
usedTools
|
|
231
|
-
.map((t) => `${t.name} ${getDisplayParam(t)}`)
|
|
232
|
-
.join("\n");
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
this.messageManager.updateToolBlock({
|
|
236
|
-
id: toolBlockId,
|
|
237
|
-
messageId,
|
|
238
|
-
shortResult,
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
},
|
|
242
|
-
);
|
|
243
|
-
|
|
244
|
-
// Show loading while subagent runs
|
|
245
|
-
this.aiManager.setIsLoading(true);
|
|
246
|
-
try {
|
|
247
|
-
const result = await this.subagentManager.executeAgent(
|
|
248
|
-
instance,
|
|
249
|
-
prepared.content,
|
|
250
|
-
signal,
|
|
251
|
-
);
|
|
252
|
-
|
|
253
|
-
// Update the ToolBlock with final result
|
|
254
|
-
this.messageManager.updateToolBlock({
|
|
255
|
-
id: toolBlockId,
|
|
256
|
-
messageId,
|
|
257
|
-
result,
|
|
258
|
-
stage: "end",
|
|
259
|
-
success: true,
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
// Trigger AI to process the tool result
|
|
263
|
-
await this.aiManager.sendAIMessage();
|
|
264
|
-
} finally {
|
|
265
|
-
this.subagentManager.cleanupInstance(instance.subagentId);
|
|
266
|
-
}
|
|
267
|
-
} catch (error) {
|
|
268
|
-
// Update the ToolBlock with error
|
|
269
|
-
this.messageManager.updateToolBlock({
|
|
270
|
-
id: toolBlockId,
|
|
271
|
-
messageId,
|
|
272
|
-
stage: "end",
|
|
273
|
-
success: false,
|
|
274
|
-
error: error instanceof Error ? error.message : String(error),
|
|
275
|
-
});
|
|
276
|
-
throw error; // Re-throw to be caught by outer catch for logging/error block
|
|
277
|
-
}
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// Non-forked skill: execute and trigger AI response
|
|
282
|
-
this.aiManager.setIsLoading(true);
|
|
283
|
-
const result = await this.skillManager.executeSkill({
|
|
284
|
-
skill_name: skill.name,
|
|
285
|
-
args,
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
// Add user message with the processed content
|
|
289
|
-
this.messageManager.addUserMessage({
|
|
290
|
-
content: `/${skill.name}${args ? ` ${args}` : ""}`,
|
|
291
|
-
customCommandContent: result.content,
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
// Trigger AI response
|
|
295
|
-
await this.aiManager.sendAIMessage({
|
|
296
|
-
model: skill.model,
|
|
297
|
-
allowedRules: result.allowedTools,
|
|
298
|
-
});
|
|
299
|
-
} catch (error) {
|
|
300
|
-
this.aiManager.setIsLoading(false);
|
|
301
|
-
|
|
302
|
-
logger?.error(error);
|
|
303
|
-
this.messageManager.addErrorBlock(
|
|
304
|
-
`Failed to execute skill command '${skill.name}': ${
|
|
305
|
-
error instanceof Error ? error.message : String(error)
|
|
306
|
-
}`,
|
|
307
|
-
);
|
|
308
|
-
}
|
|
309
|
-
},
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
logger?.debug(`Registered ${skills.length} skill commands`);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Register commands from a plugin with namespacing
|
|
318
|
-
*/
|
|
319
|
-
public registerPluginCommands(
|
|
320
|
-
pluginName: string,
|
|
321
|
-
commands: CustomSlashCommand[],
|
|
322
|
-
): void {
|
|
323
|
-
for (const command of commands) {
|
|
324
|
-
const namespacedId = `${pluginName}:${command.id}`;
|
|
325
|
-
const namespacedName = `${pluginName}:${command.name}`;
|
|
326
|
-
|
|
327
|
-
this.customCommands.set(namespacedId, command);
|
|
328
|
-
|
|
329
|
-
// Generate description: prioritize custom description, otherwise use default description
|
|
330
|
-
const description =
|
|
331
|
-
command.description ||
|
|
332
|
-
`Plugin command: ${namespacedName}${hasParameterPlaceholders(command.content) ? " (supports parameters)" : ""}`;
|
|
333
|
-
|
|
334
|
-
this.registerCommand({
|
|
335
|
-
id: namespacedId,
|
|
336
|
-
name: namespacedName,
|
|
337
|
-
description,
|
|
338
|
-
handler: async (args?: string) => {
|
|
339
|
-
// Substitute parameters in the command content
|
|
340
|
-
let processedContent = command.content;
|
|
341
|
-
|
|
342
|
-
if (args) {
|
|
343
|
-
processedContent = substituteCommandParameters(
|
|
344
|
-
processedContent,
|
|
345
|
-
args,
|
|
346
|
-
);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
await this.executeCustomCommandInMainAgent(
|
|
350
|
-
namespacedName,
|
|
351
|
-
processedContent,
|
|
352
|
-
command.config,
|
|
353
|
-
args,
|
|
354
|
-
);
|
|
355
|
-
},
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
logger?.debug(
|
|
360
|
-
`Registered ${commands.length} commands from plugin '${pluginName}'`,
|
|
361
|
-
);
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* Reload custom commands (useful for development)
|
|
366
|
-
*/
|
|
367
|
-
public reloadCustomCommands(): void {
|
|
368
|
-
// Clear existing custom commands
|
|
369
|
-
for (const commandId of this.customCommands.keys()) {
|
|
370
|
-
this.unregisterCommand(commandId);
|
|
371
|
-
}
|
|
372
|
-
this.customCommands.clear();
|
|
373
|
-
|
|
374
|
-
// Reload
|
|
375
|
-
this.loadCustomCommands();
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* Register new command
|
|
380
|
-
*/
|
|
381
|
-
public registerCommand(command: SlashCommand): void {
|
|
382
|
-
this.commands.set(command.id, command);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
/**
|
|
386
|
-
* Unregister command
|
|
387
|
-
*/
|
|
388
|
-
private unregisterCommand(commandId: string): boolean {
|
|
389
|
-
return this.commands.delete(commandId);
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* Get all available commands
|
|
394
|
-
*/
|
|
395
|
-
public getCommands(): SlashCommand[] {
|
|
396
|
-
return Array.from(this.commands.values());
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* Get command by ID
|
|
401
|
-
*/
|
|
402
|
-
public getCommand(commandId: string): SlashCommand | undefined {
|
|
403
|
-
return this.commands.get(commandId);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* Execute command
|
|
408
|
-
*/
|
|
409
|
-
public async executeCommand(
|
|
410
|
-
commandId: string,
|
|
411
|
-
args?: string,
|
|
412
|
-
): Promise<boolean> {
|
|
413
|
-
const command = this.commands.get(commandId);
|
|
414
|
-
if (!command) {
|
|
415
|
-
return false;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// Abort any previous command if it's still running
|
|
419
|
-
this.currentCommandAbortController?.abort();
|
|
420
|
-
this.currentCommandAbortController = new AbortController();
|
|
421
|
-
|
|
422
|
-
try {
|
|
423
|
-
await command.handler(args, this.currentCommandAbortController.signal);
|
|
424
|
-
return true;
|
|
425
|
-
} catch (error) {
|
|
426
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
427
|
-
logger?.debug(`Slash command ${commandId} was aborted`);
|
|
428
|
-
} else {
|
|
429
|
-
console.error(`Failed to execute slash command ${commandId}:`, error);
|
|
430
|
-
}
|
|
431
|
-
return false;
|
|
432
|
-
} finally {
|
|
433
|
-
this.currentCommandAbortController = null;
|
|
434
|
-
// FR-013: Ensure slash commands are persisted to the session file
|
|
435
|
-
await this.messageManager.saveSession();
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* Parse and validate a slash command input
|
|
441
|
-
* Returns whether the command is valid along with parsed commandId and args
|
|
442
|
-
*/
|
|
443
|
-
public parseAndValidateSlashCommand(input: string): {
|
|
444
|
-
isValid: boolean;
|
|
445
|
-
commandId?: string;
|
|
446
|
-
args?: string;
|
|
447
|
-
} {
|
|
448
|
-
try {
|
|
449
|
-
const { command: commandId, args } = parseSlashCommandInput(input);
|
|
450
|
-
const isValid = this.hasCommand(commandId);
|
|
451
|
-
return {
|
|
452
|
-
isValid,
|
|
453
|
-
commandId: isValid ? commandId : undefined,
|
|
454
|
-
args: isValid ? args || undefined : undefined, // Convert empty string to undefined
|
|
455
|
-
};
|
|
456
|
-
} catch (error) {
|
|
457
|
-
console.error(`Failed to parse slash command input "${input}":`, error);
|
|
458
|
-
return { isValid: false };
|
|
459
|
-
}
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
/**
|
|
463
|
-
* Check if command exists
|
|
464
|
-
*/
|
|
465
|
-
public hasCommand(commandId: string): boolean {
|
|
466
|
-
return this.commands.has(commandId);
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* Check if a slash command should bypass the message queue when AI is busy.
|
|
471
|
-
* Returns true for commands marked as immediate (boolean or function).
|
|
472
|
-
*/
|
|
473
|
-
public isImmediateCommand(input: string): boolean {
|
|
474
|
-
const { command: commandId, args } = parseSlashCommandInput(input);
|
|
475
|
-
const command = this.commands.get(commandId);
|
|
476
|
-
if (!command?.immediate) return false;
|
|
477
|
-
if (typeof command.immediate === "boolean") return command.immediate;
|
|
478
|
-
return command.immediate(args);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
/**
|
|
482
|
-
* Get custom command details
|
|
483
|
-
*/
|
|
484
|
-
public getCustomCommand(commandId: string): CustomSlashCommand | undefined {
|
|
485
|
-
return this.customCommands.get(commandId);
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* Get all custom commands
|
|
490
|
-
*/
|
|
491
|
-
public getCustomCommands(): CustomSlashCommand[] {
|
|
492
|
-
return Array.from(this.customCommands.values());
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
/**
|
|
496
|
-
* Execute custom command in main agent instead of sub-agent
|
|
497
|
-
*/
|
|
498
|
-
private async executeCustomCommandInMainAgent(
|
|
499
|
-
commandName: string,
|
|
500
|
-
content: string,
|
|
501
|
-
config?: { model?: string; allowedTools?: string[] },
|
|
502
|
-
args?: string,
|
|
503
|
-
): Promise<void> {
|
|
504
|
-
try {
|
|
505
|
-
// Set loading early so UI shows feedback during bash execution
|
|
506
|
-
this.aiManager.setIsLoading(true);
|
|
507
|
-
|
|
508
|
-
// Parse bash commands from the content
|
|
509
|
-
const { commands, processedContent } = parseBashCommands(content);
|
|
510
|
-
|
|
511
|
-
// Add user message immediately so text block shows before bash execution
|
|
512
|
-
const messageId = this.messageManager.addUserMessage({
|
|
513
|
-
content: `/${commandName}${args ? ` ${args}` : ""}`,
|
|
514
|
-
customCommandContent: processedContent,
|
|
515
|
-
});
|
|
516
|
-
|
|
517
|
-
// Execute bash commands and update the message if any exist
|
|
518
|
-
if (commands.length > 0) {
|
|
519
|
-
const bashResults = await executeBashCommands(commands, this.workdir);
|
|
520
|
-
const finalContent = replaceBashCommandsWithOutput(
|
|
521
|
-
processedContent,
|
|
522
|
-
bashResults,
|
|
523
|
-
);
|
|
524
|
-
|
|
525
|
-
// Update the user message with the bash-processed content
|
|
526
|
-
this.messageManager.updateUserMessage(messageId, {
|
|
527
|
-
customCommandContent: finalContent,
|
|
528
|
-
});
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
// Execute the AI conversation with custom configuration
|
|
532
|
-
await this.aiManager.sendAIMessage({
|
|
533
|
-
model: config?.model,
|
|
534
|
-
allowedRules: config?.allowedTools,
|
|
535
|
-
});
|
|
536
|
-
} catch (error) {
|
|
537
|
-
this.aiManager.setIsLoading(false);
|
|
538
|
-
|
|
539
|
-
logger?.error(
|
|
540
|
-
`Failed to execute custom command '${commandName}':`,
|
|
541
|
-
error,
|
|
542
|
-
);
|
|
543
|
-
|
|
544
|
-
// Add error to message manager
|
|
545
|
-
this.messageManager.addErrorBlock(
|
|
546
|
-
`Failed to execute custom command '${commandName}': ${
|
|
547
|
-
error instanceof Error ? error.message : String(error)
|
|
548
|
-
}`,
|
|
549
|
-
);
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* Interrupt the currently executing slash command
|
|
555
|
-
*/
|
|
556
|
-
public abortCurrentCommand(): void {
|
|
557
|
-
// Abort the AI manager if it's running
|
|
558
|
-
this.aiManager.abortAIMessage();
|
|
559
|
-
|
|
560
|
-
// Abort the current slash command handler
|
|
561
|
-
this.currentCommandAbortController?.abort();
|
|
562
|
-
this.currentCommandAbortController = null;
|
|
563
|
-
}
|
|
564
|
-
}
|