wave-agent-sdk 0.6.4 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.d.ts +8 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +49 -240
- package/dist/constants/tools.d.ts +0 -2
- package/dist/constants/tools.d.ts.map +1 -1
- package/dist/constants/tools.js +0 -2
- package/dist/core/plugin.d.ts +86 -0
- package/dist/core/plugin.d.ts.map +1 -0
- package/dist/core/plugin.js +164 -0
- package/dist/index.d.ts +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -5
- package/dist/managers/MemoryRuleManager.d.ts +3 -1
- package/dist/managers/MemoryRuleManager.d.ts.map +1 -1
- package/dist/managers/MemoryRuleManager.js +2 -1
- package/dist/managers/aiManager.d.ts +13 -23
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +59 -32
- package/dist/managers/backgroundTaskManager.d.ts +3 -1
- package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
- package/dist/managers/backgroundTaskManager.js +2 -1
- package/dist/managers/bashManager.d.ts +4 -4
- package/dist/managers/bashManager.d.ts.map +1 -1
- package/dist/managers/bashManager.js +5 -2
- package/dist/managers/foregroundTaskManager.d.ts +3 -0
- package/dist/managers/foregroundTaskManager.d.ts.map +1 -1
- package/dist/managers/foregroundTaskManager.js +2 -1
- package/dist/managers/hookManager.d.ts +3 -3
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +20 -19
- package/dist/managers/liveConfigManager.d.ts +6 -13
- package/dist/managers/liveConfigManager.d.ts.map +1 -1
- package/dist/managers/liveConfigManager.js +50 -45
- package/dist/managers/lspManager.d.ts +4 -5
- package/dist/managers/lspManager.d.ts.map +1 -1
- package/dist/managers/lspManager.js +13 -12
- package/dist/managers/mcpManager.d.ts +3 -2
- package/dist/managers/mcpManager.d.ts.map +1 -1
- package/dist/managers/mcpManager.js +16 -15
- package/dist/managers/messageManager.d.ts +5 -7
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +12 -7
- package/dist/managers/permissionManager.d.ts +6 -4
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +39 -63
- package/dist/managers/planManager.d.ts +4 -6
- package/dist/managers/planManager.d.ts.map +1 -1
- package/dist/managers/planManager.js +18 -4
- package/dist/managers/pluginManager.d.ts +10 -22
- package/dist/managers/pluginManager.d.ts.map +1 -1
- package/dist/managers/pluginManager.js +27 -14
- package/dist/managers/reversionManager.d.ts +4 -3
- package/dist/managers/reversionManager.d.ts.map +1 -1
- package/dist/managers/reversionManager.js +5 -2
- package/dist/managers/skillManager.d.ts +3 -2
- package/dist/managers/skillManager.d.ts.map +1 -1
- package/dist/managers/skillManager.js +15 -14
- package/dist/managers/slashCommandManager.d.ts +9 -16
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +21 -10
- package/dist/managers/subagentManager.d.ts +7 -17
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +41 -34
- package/dist/managers/toolManager.d.ts +15 -38
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +66 -56
- package/dist/prompts/index.d.ts +6 -3
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +8 -16
- package/dist/services/MarketplaceService.d.ts.map +1 -1
- package/dist/services/MarketplaceService.js +13 -0
- package/dist/services/aiService.d.ts +4 -0
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +47 -7
- package/dist/services/configurationService.d.ts.map +1 -1
- package/dist/services/configurationService.js +30 -11
- package/dist/services/taskManager.d.ts +3 -1
- package/dist/services/taskManager.d.ts.map +1 -1
- package/dist/services/taskManager.js +2 -1
- package/dist/tools/bashTool.js +2 -2
- package/dist/tools/editTool.d.ts.map +1 -1
- package/dist/tools/editTool.js +9 -1
- package/dist/tools/readTool.d.ts.map +1 -1
- package/dist/tools/readTool.js +2 -2
- package/dist/tools/skillTool.d.ts +2 -4
- package/dist/tools/skillTool.d.ts.map +1 -1
- package/dist/tools/skillTool.js +61 -61
- package/dist/tools/taskOutputTool.js +1 -1
- package/dist/tools/taskTool.d.ts +2 -4
- package/dist/tools/taskTool.d.ts.map +1 -1
- package/dist/tools/taskTool.js +192 -187
- package/dist/tools/types.d.ts +11 -1
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/writeTool.d.ts.map +1 -1
- package/dist/tools/writeTool.js +4 -2
- package/dist/types/marketplace.d.ts +8 -0
- package/dist/types/marketplace.d.ts.map +1 -1
- package/dist/types/permissions.d.ts +1 -1
- package/dist/types/permissions.d.ts.map +1 -1
- package/dist/types/permissions.js +1 -3
- package/dist/types/skills.d.ts +0 -2
- package/dist/types/skills.d.ts.map +1 -1
- package/dist/types/tools.d.ts +0 -15
- package/dist/types/tools.d.ts.map +1 -1
- package/dist/utils/container.d.ts +31 -0
- package/dist/utils/container.d.ts.map +1 -0
- package/dist/utils/container.js +79 -0
- package/dist/utils/containerSetup.d.ts +26 -0
- package/dist/utils/containerSetup.d.ts.map +1 -0
- package/dist/utils/containerSetup.js +165 -0
- package/dist/utils/editUtils.d.ts +0 -3
- package/dist/utils/editUtils.d.ts.map +1 -1
- package/dist/utils/editUtils.js +4 -3
- package/dist/utils/hookMatcher.d.ts +1 -1
- package/dist/utils/hookMatcher.d.ts.map +1 -1
- package/dist/utils/hookMatcher.js +2 -2
- package/dist/utils/openaiClient.js +2 -2
- package/dist/utils/stringUtils.d.ts +6 -0
- package/dist/utils/stringUtils.d.ts.map +1 -1
- package/dist/utils/stringUtils.js +8 -0
- package/package.json +1 -1
- package/src/agent.ts +60 -282
- package/src/constants/tools.ts +0 -2
- package/src/core/plugin.ts +224 -0
- package/src/index.ts +1 -6
- package/src/managers/MemoryRuleManager.ts +6 -1
- package/src/managers/aiManager.ts +83 -58
- package/src/managers/backgroundTaskManager.ts +5 -1
- package/src/managers/bashManager.ts +9 -4
- package/src/managers/foregroundTaskManager.ts +3 -0
- package/src/managers/hookManager.ts +21 -23
- package/src/managers/liveConfigManager.ts +57 -53
- package/src/managers/lspManager.ts +14 -19
- package/src/managers/mcpManager.ts +20 -20
- package/src/managers/messageManager.ts +19 -12
- package/src/managers/permissionManager.ts +45 -70
- package/src/managers/planManager.ts +26 -7
- package/src/managers/pluginManager.ts +37 -33
- package/src/managers/reversionManager.ts +5 -3
- package/src/managers/skillManager.ts +19 -20
- package/src/managers/slashCommandManager.ts +30 -25
- package/src/managers/subagentManager.ts +53 -53
- package/src/managers/toolManager.ts +91 -90
- package/src/prompts/index.ts +12 -24
- package/src/services/MarketplaceService.ts +13 -0
- package/src/services/aiService.ts +61 -15
- package/src/services/configurationService.ts +34 -13
- package/src/services/taskManager.ts +5 -1
- package/src/tools/bashTool.ts +2 -2
- package/src/tools/editTool.ts +9 -1
- package/src/tools/readTool.ts +2 -2
- package/src/tools/skillTool.ts +75 -71
- package/src/tools/taskOutputTool.ts +1 -1
- package/src/tools/taskTool.ts +224 -225
- package/src/tools/types.ts +12 -1
- package/src/tools/writeTool.ts +4 -2
- package/src/types/marketplace.ts +9 -0
- package/src/types/permissions.ts +0 -4
- package/src/types/skills.ts +0 -3
- package/src/types/tools.ts +0 -17
- package/src/utils/container.ts +92 -0
- package/src/utils/containerSetup.ts +256 -0
- package/src/utils/editUtils.ts +4 -3
- package/src/utils/hookMatcher.ts +2 -2
- package/src/utils/openaiClient.ts +2 -2
- package/src/utils/stringUtils.ts +9 -0
- package/dist/tools/deleteFileTool.d.ts +0 -6
- package/dist/tools/deleteFileTool.d.ts.map +0 -1
- package/dist/tools/deleteFileTool.js +0 -100
- package/dist/tools/multiEditTool.d.ts +0 -6
- package/dist/tools/multiEditTool.d.ts.map +0 -1
- package/dist/tools/multiEditTool.js +0 -246
- package/src/tools/deleteFileTool.ts +0 -127
- package/src/tools/multiEditTool.ts +0 -306
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
UserMessageParams,
|
|
11
11
|
type AgentToolBlockUpdateParams,
|
|
12
12
|
} from "../utils/messageOperations.js";
|
|
13
|
-
import type {
|
|
13
|
+
import type { Message, Usage, SlashCommand } from "../types/index.js";
|
|
14
14
|
import { join } from "path";
|
|
15
15
|
import {
|
|
16
16
|
appendMessages,
|
|
@@ -23,6 +23,8 @@ import { ChatCompletionMessageFunctionToolCall } from "openai/resources.js";
|
|
|
23
23
|
import type { MemoryRuleManager } from "./MemoryRuleManager.js";
|
|
24
24
|
import { pathEncoder } from "../utils/pathEncoder.js";
|
|
25
25
|
|
|
26
|
+
import { Container } from "../utils/container.js";
|
|
27
|
+
|
|
26
28
|
export interface MessageManagerCallbacks {
|
|
27
29
|
onMessagesChange?: (messages: Message[]) => void;
|
|
28
30
|
onSessionIdChange?: (sessionId: string) => void;
|
|
@@ -59,13 +61,13 @@ export interface MessageManagerCallbacks {
|
|
|
59
61
|
) => void;
|
|
60
62
|
}
|
|
61
63
|
|
|
64
|
+
import { logger } from "../utils/globalLogger.js";
|
|
65
|
+
|
|
62
66
|
export interface MessageManagerOptions {
|
|
63
67
|
callbacks: MessageManagerCallbacks;
|
|
64
68
|
workdir: string;
|
|
65
|
-
logger?: Logger;
|
|
66
69
|
sessionType?: "main" | "subagent";
|
|
67
70
|
subagentType?: string;
|
|
68
|
-
memoryRuleManager?: MemoryRuleManager;
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
export class MessageManager {
|
|
@@ -77,16 +79,17 @@ export class MessageManager {
|
|
|
77
79
|
private latestTotalTokens: number;
|
|
78
80
|
private workdir: string;
|
|
79
81
|
private encodedWorkdir: string; // Cached encoded workdir
|
|
80
|
-
private logger?: Logger; // Add optional logger property
|
|
81
82
|
private callbacks: MessageManagerCallbacks;
|
|
82
83
|
private transcriptPath: string; // Cached transcript path
|
|
83
84
|
private savedMessageCount: number; // Track how many messages have been saved to prevent duplication
|
|
84
85
|
private filesInContext: Set<string> = new Set(); // Track files mentioned in the conversation
|
|
85
|
-
private memoryRuleManager?: MemoryRuleManager;
|
|
86
86
|
private sessionType: "main" | "subagent";
|
|
87
87
|
private subagentType?: string;
|
|
88
88
|
|
|
89
|
-
constructor(
|
|
89
|
+
constructor(
|
|
90
|
+
private container: Container,
|
|
91
|
+
options: MessageManagerOptions,
|
|
92
|
+
) {
|
|
90
93
|
this.sessionId = generateSessionId();
|
|
91
94
|
this.rootSessionId = this.sessionId;
|
|
92
95
|
this.messages = [];
|
|
@@ -94,16 +97,20 @@ export class MessageManager {
|
|
|
94
97
|
this.workdir = options.workdir;
|
|
95
98
|
this.encodedWorkdir = pathEncoder.encodeSync(this.workdir); // Cache encoded workdir
|
|
96
99
|
this.callbacks = options.callbacks;
|
|
97
|
-
this.logger = options.logger;
|
|
98
100
|
this.savedMessageCount = 0; // Initialize saved message count tracker
|
|
99
101
|
this.sessionType = options.sessionType || "main";
|
|
100
102
|
this.subagentType = options.subagentType;
|
|
101
|
-
this.memoryRuleManager = options.memoryRuleManager;
|
|
102
103
|
|
|
103
104
|
// Compute and cache the transcript path
|
|
104
105
|
this.transcriptPath = this.computeTranscriptPath();
|
|
105
106
|
}
|
|
106
107
|
|
|
108
|
+
private get memoryRuleManager(): MemoryRuleManager | undefined {
|
|
109
|
+
return this.container.has("MemoryRuleManager")
|
|
110
|
+
? this.container.get<MemoryRuleManager>("MemoryRuleManager")
|
|
111
|
+
: undefined;
|
|
112
|
+
}
|
|
113
|
+
|
|
107
114
|
// Getter methods
|
|
108
115
|
public getSessionId(): string {
|
|
109
116
|
return this.sessionId;
|
|
@@ -155,7 +162,7 @@ export class MessageManager {
|
|
|
155
162
|
const filesInContext = this.getFilesInContext();
|
|
156
163
|
const activeRules = this.memoryRuleManager.getActiveRules(filesInContext);
|
|
157
164
|
if (activeRules.length > 0) {
|
|
158
|
-
|
|
165
|
+
logger?.debug(
|
|
159
166
|
`Active modular rules (${activeRules.length}): ${activeRules.map((r) => r.id).join(", ")}`,
|
|
160
167
|
);
|
|
161
168
|
if (combined) {
|
|
@@ -200,7 +207,7 @@ export class MessageManager {
|
|
|
200
207
|
try {
|
|
201
208
|
await createSession(this.sessionId, this.workdir, this.sessionType);
|
|
202
209
|
} catch (error) {
|
|
203
|
-
|
|
210
|
+
logger?.error("Failed to create session:", error);
|
|
204
211
|
}
|
|
205
212
|
}
|
|
206
213
|
|
|
@@ -242,7 +249,7 @@ export class MessageManager {
|
|
|
242
249
|
// Update the saved message count
|
|
243
250
|
this.savedMessageCount = this.messages.length;
|
|
244
251
|
} catch (error) {
|
|
245
|
-
|
|
252
|
+
logger?.error("Failed to save session:", error);
|
|
246
253
|
}
|
|
247
254
|
}
|
|
248
255
|
|
|
@@ -741,7 +748,7 @@ export class MessageManager {
|
|
|
741
748
|
|
|
742
749
|
await writeFile(this.transcriptPath, content, "utf8");
|
|
743
750
|
} catch (error) {
|
|
744
|
-
|
|
751
|
+
logger?.error("Failed to rewrite session file:", error);
|
|
745
752
|
}
|
|
746
753
|
}
|
|
747
754
|
|
|
@@ -27,18 +27,17 @@ import { isPathInside } from "../utils/pathSafety.js";
|
|
|
27
27
|
import {
|
|
28
28
|
BASH_TOOL_NAME,
|
|
29
29
|
EDIT_TOOL_NAME,
|
|
30
|
-
MULTI_EDIT_TOOL_NAME,
|
|
31
|
-
DELETE_FILE_TOOL_NAME,
|
|
32
30
|
WRITE_TOOL_NAME,
|
|
33
31
|
READ_TOOL_NAME,
|
|
34
32
|
LS_TOOL_NAME,
|
|
35
33
|
} from "../constants/tools.js";
|
|
34
|
+
import { Container } from "../utils/container.js";
|
|
36
35
|
|
|
37
36
|
const SAFE_COMMANDS = ["cd", "ls", "pwd", "true", "false"];
|
|
38
37
|
|
|
38
|
+
import { logger } from "../utils/globalLogger.js";
|
|
39
|
+
|
|
39
40
|
export interface PermissionManagerOptions {
|
|
40
|
-
/** Logger for debugging permission decisions */
|
|
41
|
-
logger?: Logger;
|
|
42
41
|
/** Configured default permission mode from settings */
|
|
43
42
|
configuredDefaultMode?: PermissionMode;
|
|
44
43
|
/** Allowed rules from settings */
|
|
@@ -51,10 +50,11 @@ export interface PermissionManagerOptions {
|
|
|
51
50
|
workdir?: string;
|
|
52
51
|
/** Path to the current plan file */
|
|
53
52
|
planFilePath?: string;
|
|
53
|
+
/** Optional logger */
|
|
54
|
+
logger?: Logger;
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
export class PermissionManager {
|
|
57
|
-
private logger?: Logger;
|
|
58
58
|
private configuredDefaultMode?: PermissionMode;
|
|
59
59
|
private allowedRules: string[] = [];
|
|
60
60
|
private deniedRules: string[] = [];
|
|
@@ -63,14 +63,18 @@ export class PermissionManager {
|
|
|
63
63
|
private workdir?: string;
|
|
64
64
|
private planFilePath?: string;
|
|
65
65
|
private onConfiguredDefaultModeChange?: (mode: PermissionMode) => void;
|
|
66
|
+
private _logger?: Logger;
|
|
66
67
|
|
|
67
|
-
constructor(
|
|
68
|
-
|
|
68
|
+
constructor(
|
|
69
|
+
private container: Container,
|
|
70
|
+
options: PermissionManagerOptions = {},
|
|
71
|
+
) {
|
|
69
72
|
this.configuredDefaultMode = options.configuredDefaultMode;
|
|
70
73
|
this.allowedRules = options.allowedRules || [];
|
|
71
74
|
this.deniedRules = options.deniedRules || [];
|
|
72
75
|
this.workdir = options.workdir;
|
|
73
76
|
this.planFilePath = options.planFilePath;
|
|
77
|
+
this._logger = options.logger;
|
|
74
78
|
this.updateAdditionalDirectories(options.additionalDirectories || []);
|
|
75
79
|
}
|
|
76
80
|
|
|
@@ -89,7 +93,7 @@ export class PermissionManager {
|
|
|
89
93
|
updateConfiguredDefaultMode(defaultMode?: PermissionMode): void {
|
|
90
94
|
const oldEffectiveMode = this.getCurrentEffectiveMode();
|
|
91
95
|
|
|
92
|
-
|
|
96
|
+
logger?.debug("Updating configured default permission mode", {
|
|
93
97
|
previous: this.configuredDefaultMode,
|
|
94
98
|
new: defaultMode,
|
|
95
99
|
});
|
|
@@ -100,7 +104,7 @@ export class PermissionManager {
|
|
|
100
104
|
oldEffectiveMode !== newEffectiveMode &&
|
|
101
105
|
this.onConfiguredDefaultModeChange
|
|
102
106
|
) {
|
|
103
|
-
|
|
107
|
+
logger?.debug(
|
|
104
108
|
"Effective permission mode changed due to configuration update",
|
|
105
109
|
{
|
|
106
110
|
oldMode: oldEffectiveMode,
|
|
@@ -122,7 +126,7 @@ export class PermissionManager {
|
|
|
122
126
|
* Update the allowed rules (e.g., when configuration reloads)
|
|
123
127
|
*/
|
|
124
128
|
updateAllowedRules(rules: string[]): void {
|
|
125
|
-
|
|
129
|
+
logger?.debug("Updating allowed permission rules", {
|
|
126
130
|
count: rules.length,
|
|
127
131
|
});
|
|
128
132
|
this.allowedRules = rules;
|
|
@@ -132,7 +136,7 @@ export class PermissionManager {
|
|
|
132
136
|
* Update the denied rules (e.g., when configuration reloads)
|
|
133
137
|
*/
|
|
134
138
|
updateDeniedRules(rules: string[]): void {
|
|
135
|
-
|
|
139
|
+
logger?.debug("Updating denied permission rules", {
|
|
136
140
|
count: rules.length,
|
|
137
141
|
});
|
|
138
142
|
this.deniedRules = rules;
|
|
@@ -142,7 +146,7 @@ export class PermissionManager {
|
|
|
142
146
|
* Add temporary rules for the current session
|
|
143
147
|
*/
|
|
144
148
|
public addTemporaryRules(rules: string[]): void {
|
|
145
|
-
|
|
149
|
+
logger?.debug("Adding temporary permission rules", {
|
|
146
150
|
count: rules.length,
|
|
147
151
|
rules,
|
|
148
152
|
});
|
|
@@ -153,7 +157,7 @@ export class PermissionManager {
|
|
|
153
157
|
* Clear all temporary rules
|
|
154
158
|
*/
|
|
155
159
|
public clearTemporaryRules(): void {
|
|
156
|
-
|
|
160
|
+
logger?.debug("Clearing temporary permission rules");
|
|
157
161
|
this.temporaryRules = [];
|
|
158
162
|
}
|
|
159
163
|
|
|
@@ -161,7 +165,7 @@ export class PermissionManager {
|
|
|
161
165
|
* Update the additional directories (e.g., when configuration reloads)
|
|
162
166
|
*/
|
|
163
167
|
updateAdditionalDirectories(directories: string[]): void {
|
|
164
|
-
|
|
168
|
+
logger?.debug("Updating additional directories", {
|
|
165
169
|
count: directories.length,
|
|
166
170
|
});
|
|
167
171
|
this.additionalDirectories = directories.map((dir) => {
|
|
@@ -176,7 +180,7 @@ export class PermissionManager {
|
|
|
176
180
|
* Update the working directory
|
|
177
181
|
*/
|
|
178
182
|
updateWorkdir(workdir: string): void {
|
|
179
|
-
|
|
183
|
+
logger?.debug("Updating working directory", {
|
|
180
184
|
workdir,
|
|
181
185
|
});
|
|
182
186
|
this.workdir = workdir;
|
|
@@ -186,7 +190,7 @@ export class PermissionManager {
|
|
|
186
190
|
* Set the current plan file path
|
|
187
191
|
*/
|
|
188
192
|
public setPlanFilePath(path: string | undefined): void {
|
|
189
|
-
|
|
193
|
+
logger?.debug("Setting plan file path", { path });
|
|
190
194
|
this.planFilePath = path;
|
|
191
195
|
}
|
|
192
196
|
|
|
@@ -224,7 +228,7 @@ export class PermissionManager {
|
|
|
224
228
|
}
|
|
225
229
|
}
|
|
226
230
|
|
|
227
|
-
|
|
231
|
+
logger?.debug("Path is outside Safe Zone", {
|
|
228
232
|
absolutePath,
|
|
229
233
|
workdir: effectiveWorkdir,
|
|
230
234
|
additionalDirectories: this.additionalDirectories,
|
|
@@ -248,7 +252,7 @@ export class PermissionManager {
|
|
|
248
252
|
): PermissionMode {
|
|
249
253
|
// CLI override takes highest precedence
|
|
250
254
|
if (cliPermissionMode !== undefined) {
|
|
251
|
-
|
|
255
|
+
logger?.debug("Using CLI permission mode override", {
|
|
252
256
|
cliMode: cliPermissionMode,
|
|
253
257
|
configuredDefault: this.configuredDefaultMode,
|
|
254
258
|
});
|
|
@@ -257,14 +261,14 @@ export class PermissionManager {
|
|
|
257
261
|
|
|
258
262
|
// Use configured default mode if available
|
|
259
263
|
if (this.configuredDefaultMode !== undefined) {
|
|
260
|
-
|
|
264
|
+
logger?.debug("Using configured default permission mode", {
|
|
261
265
|
configuredDefault: this.configuredDefaultMode,
|
|
262
266
|
});
|
|
263
267
|
return this.configuredDefaultMode;
|
|
264
268
|
}
|
|
265
269
|
|
|
266
270
|
// Fall back to system default
|
|
267
|
-
|
|
271
|
+
logger?.debug("Using system default permission mode");
|
|
268
272
|
return "default";
|
|
269
273
|
}
|
|
270
274
|
|
|
@@ -275,7 +279,7 @@ export class PermissionManager {
|
|
|
275
279
|
async checkPermission(
|
|
276
280
|
context: ToolPermissionContext,
|
|
277
281
|
): Promise<PermissionDecision> {
|
|
278
|
-
|
|
282
|
+
logger?.debug("Checking permission for tool", {
|
|
279
283
|
toolName: context.toolName,
|
|
280
284
|
permissionMode: context.permissionMode,
|
|
281
285
|
hasCallback: !!context.canUseToolCallback,
|
|
@@ -284,7 +288,7 @@ export class PermissionManager {
|
|
|
284
288
|
// 0. Check denied rules first - Deny always takes precedence
|
|
285
289
|
for (const rule of this.deniedRules) {
|
|
286
290
|
if (this.matchesRule(context, rule)) {
|
|
287
|
-
|
|
291
|
+
logger?.warn("Permission denied by rule", {
|
|
288
292
|
toolName: context.toolName,
|
|
289
293
|
rule,
|
|
290
294
|
});
|
|
@@ -297,24 +301,18 @@ export class PermissionManager {
|
|
|
297
301
|
|
|
298
302
|
// 1. If bypassPermissions mode, always allow
|
|
299
303
|
if (context.permissionMode === "bypassPermissions") {
|
|
300
|
-
|
|
304
|
+
logger?.debug("Permission bypassed for tool", {
|
|
301
305
|
toolName: context.toolName,
|
|
302
306
|
});
|
|
303
307
|
return { behavior: "allow" };
|
|
304
308
|
}
|
|
305
309
|
|
|
306
|
-
// 1.1 If acceptEdits mode, allow Edit,
|
|
310
|
+
// 1.1 If acceptEdits mode, allow Edit, Write
|
|
307
311
|
if (context.permissionMode === "acceptEdits") {
|
|
308
|
-
const autoAcceptedTools = [
|
|
309
|
-
EDIT_TOOL_NAME,
|
|
310
|
-
MULTI_EDIT_TOOL_NAME,
|
|
311
|
-
DELETE_FILE_TOOL_NAME,
|
|
312
|
-
WRITE_TOOL_NAME,
|
|
313
|
-
];
|
|
312
|
+
const autoAcceptedTools = [EDIT_TOOL_NAME, WRITE_TOOL_NAME];
|
|
314
313
|
if (autoAcceptedTools.includes(context.toolName)) {
|
|
315
314
|
// Enforce Safe Zone for file operations
|
|
316
|
-
const targetPath =
|
|
317
|
-
context.toolInput?.target_file) as string | undefined;
|
|
315
|
+
const targetPath = context.toolInput?.file_path as string | undefined;
|
|
318
316
|
const workdir = context.toolInput?.workdir as string | undefined;
|
|
319
317
|
|
|
320
318
|
if (targetPath) {
|
|
@@ -323,7 +321,7 @@ export class PermissionManager {
|
|
|
323
321
|
workdir,
|
|
324
322
|
);
|
|
325
323
|
if (!isInside) {
|
|
326
|
-
|
|
324
|
+
logger?.info(
|
|
327
325
|
"File operation outside the Safe Zone in acceptEdits mode, falling back to manual confirmation",
|
|
328
326
|
{
|
|
329
327
|
toolName: context.toolName,
|
|
@@ -333,7 +331,7 @@ export class PermissionManager {
|
|
|
333
331
|
);
|
|
334
332
|
// Fall through to normal permission check flow to trigger confirmation prompt
|
|
335
333
|
} else {
|
|
336
|
-
|
|
334
|
+
logger?.debug(
|
|
337
335
|
"Permission automatically accepted for tool in acceptEdits mode",
|
|
338
336
|
{
|
|
339
337
|
toolName: context.toolName,
|
|
@@ -347,7 +345,7 @@ export class PermissionManager {
|
|
|
347
345
|
|
|
348
346
|
// 1.2 Check if tool call is allowed by persistent or temporary rules
|
|
349
347
|
if (this.isAllowedByRule(context)) {
|
|
350
|
-
|
|
348
|
+
logger?.debug("Permission allowed by persistent rule", {
|
|
351
349
|
toolName: context.toolName,
|
|
352
350
|
});
|
|
353
351
|
return { behavior: "allow" };
|
|
@@ -355,29 +353,16 @@ export class PermissionManager {
|
|
|
355
353
|
|
|
356
354
|
// 1.3 If plan mode, allow Read-only tools and Edit/Write for plan file
|
|
357
355
|
if (context.permissionMode === "plan") {
|
|
358
|
-
const writeTools = [
|
|
359
|
-
EDIT_TOOL_NAME,
|
|
360
|
-
MULTI_EDIT_TOOL_NAME,
|
|
361
|
-
WRITE_TOOL_NAME,
|
|
362
|
-
DELETE_FILE_TOOL_NAME,
|
|
363
|
-
];
|
|
364
|
-
if (context.toolName === DELETE_FILE_TOOL_NAME) {
|
|
365
|
-
return {
|
|
366
|
-
behavior: "deny",
|
|
367
|
-
message: "Delete operations are not allowed in plan mode.",
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
|
|
356
|
+
const writeTools = [EDIT_TOOL_NAME, WRITE_TOOL_NAME];
|
|
371
357
|
if (writeTools.includes(context.toolName)) {
|
|
372
|
-
const targetPath =
|
|
373
|
-
context.toolInput?.target_file) as string | undefined;
|
|
358
|
+
const targetPath = context.toolInput?.file_path as string | undefined;
|
|
374
359
|
|
|
375
360
|
if (this.planFilePath && targetPath) {
|
|
376
361
|
const absoluteTargetPath = path.resolve(targetPath);
|
|
377
362
|
const absolutePlanPath = path.resolve(this.planFilePath);
|
|
378
363
|
|
|
379
364
|
if (absoluteTargetPath === absolutePlanPath) {
|
|
380
|
-
|
|
365
|
+
logger?.debug("Allowing write to plan file in plan mode", {
|
|
381
366
|
toolName: context.toolName,
|
|
382
367
|
targetPath,
|
|
383
368
|
});
|
|
@@ -394,7 +379,7 @@ export class PermissionManager {
|
|
|
394
379
|
|
|
395
380
|
// 2. If not a restricted tool, always allow
|
|
396
381
|
if (!this.isRestrictedTool(context.toolName)) {
|
|
397
|
-
|
|
382
|
+
logger?.debug("Tool is not restricted, allowing", {
|
|
398
383
|
toolName: context.toolName,
|
|
399
384
|
});
|
|
400
385
|
return { behavior: "allow" };
|
|
@@ -403,11 +388,11 @@ export class PermissionManager {
|
|
|
403
388
|
// 3. If custom callback provided, call it and return result
|
|
404
389
|
if (context.canUseToolCallback) {
|
|
405
390
|
try {
|
|
406
|
-
|
|
391
|
+
logger?.debug("Calling custom permission callback for tool", {
|
|
407
392
|
toolName: context.toolName,
|
|
408
393
|
});
|
|
409
394
|
const decision = await context.canUseToolCallback(context);
|
|
410
|
-
|
|
395
|
+
logger?.debug("Custom callback returned decision", {
|
|
411
396
|
toolName: context.toolName,
|
|
412
397
|
decision,
|
|
413
398
|
});
|
|
@@ -415,7 +400,7 @@ export class PermissionManager {
|
|
|
415
400
|
} catch (error) {
|
|
416
401
|
const errorMessage =
|
|
417
402
|
error instanceof Error ? error.message : String(error);
|
|
418
|
-
|
|
403
|
+
logger?.error("Error in permission callback", {
|
|
419
404
|
toolName: context.toolName,
|
|
420
405
|
error: errorMessage,
|
|
421
406
|
});
|
|
@@ -428,7 +413,7 @@ export class PermissionManager {
|
|
|
428
413
|
|
|
429
414
|
// 4. For default mode on restricted tools without callback, integrate with CLI confirmation
|
|
430
415
|
// Note: CLI confirmation integration will be implemented in Phase 2
|
|
431
|
-
|
|
416
|
+
logger?.warn(
|
|
432
417
|
"No permission callback provided for restricted tool in default mode",
|
|
433
418
|
{
|
|
434
419
|
toolName: context.toolName,
|
|
@@ -447,7 +432,7 @@ export class PermissionManager {
|
|
|
447
432
|
const isRestricted = (RESTRICTED_TOOLS as readonly string[]).includes(
|
|
448
433
|
toolName,
|
|
449
434
|
);
|
|
450
|
-
|
|
435
|
+
logger?.debug("Checking if tool is restricted", {
|
|
451
436
|
toolName,
|
|
452
437
|
isRestricted,
|
|
453
438
|
});
|
|
@@ -483,16 +468,9 @@ export class PermissionManager {
|
|
|
483
468
|
};
|
|
484
469
|
|
|
485
470
|
// Set hidePersistentOption for out-of-bounds file operations
|
|
486
|
-
const fileTools = [
|
|
487
|
-
EDIT_TOOL_NAME,
|
|
488
|
-
MULTI_EDIT_TOOL_NAME,
|
|
489
|
-
DELETE_FILE_TOOL_NAME,
|
|
490
|
-
WRITE_TOOL_NAME,
|
|
491
|
-
];
|
|
471
|
+
const fileTools = [EDIT_TOOL_NAME, WRITE_TOOL_NAME];
|
|
492
472
|
if (fileTools.includes(toolName)) {
|
|
493
|
-
const targetPath =
|
|
494
|
-
| string
|
|
495
|
-
| undefined;
|
|
473
|
+
const targetPath = toolInput?.file_path as string | undefined;
|
|
496
474
|
const workdir = toolInput?.workdir as string | undefined;
|
|
497
475
|
|
|
498
476
|
if (targetPath) {
|
|
@@ -543,7 +521,7 @@ export class PermissionManager {
|
|
|
543
521
|
}
|
|
544
522
|
}
|
|
545
523
|
|
|
546
|
-
|
|
524
|
+
logger?.debug("Created permission context", {
|
|
547
525
|
toolName,
|
|
548
526
|
permissionMode,
|
|
549
527
|
hasCallback: !!callback,
|
|
@@ -593,13 +571,10 @@ export class PermissionManager {
|
|
|
593
571
|
READ_TOOL_NAME,
|
|
594
572
|
WRITE_TOOL_NAME,
|
|
595
573
|
EDIT_TOOL_NAME,
|
|
596
|
-
MULTI_EDIT_TOOL_NAME,
|
|
597
|
-
DELETE_FILE_TOOL_NAME,
|
|
598
574
|
LS_TOOL_NAME,
|
|
599
575
|
];
|
|
600
576
|
if (pathTools.includes(toolName)) {
|
|
601
577
|
const targetPath = (context.toolInput?.file_path ||
|
|
602
|
-
context.toolInput?.target_file ||
|
|
603
578
|
context.toolInput?.path) as string | undefined;
|
|
604
579
|
|
|
605
580
|
if (targetPath) {
|
|
@@ -2,15 +2,19 @@ import path from "node:path";
|
|
|
2
2
|
import fs from "node:fs/promises";
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import { generateRandomName } from "../utils/nameGenerator.js";
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
import { Container } from "../utils/container.js";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Manages plan files for plan mode
|
|
9
10
|
*/
|
|
11
|
+
import { logger } from "../utils/globalLogger.js";
|
|
12
|
+
|
|
10
13
|
export class PlanManager {
|
|
11
14
|
private planDir: string;
|
|
15
|
+
private currentPlanFilePath: string | null = null;
|
|
12
16
|
|
|
13
|
-
constructor(private
|
|
17
|
+
constructor(private container: Container) {
|
|
14
18
|
this.planDir = path.join(os.homedir(), ".wave", "plans");
|
|
15
19
|
}
|
|
16
20
|
|
|
@@ -24,15 +28,30 @@ export class PlanManager {
|
|
|
24
28
|
try {
|
|
25
29
|
await fs.mkdir(this.planDir, { recursive: true });
|
|
26
30
|
} catch (error) {
|
|
27
|
-
|
|
28
|
-
`Failed to create plan directory: ${this.planDir}`,
|
|
29
|
-
error,
|
|
30
|
-
);
|
|
31
|
+
logger?.error(`Failed to create plan directory: ${this.planDir}`, error);
|
|
31
32
|
throw error;
|
|
32
33
|
}
|
|
33
34
|
const name = generateRandomName(seed);
|
|
34
35
|
const filePath = path.join(this.planDir, `${name}.md`);
|
|
35
|
-
|
|
36
|
+
|
|
37
|
+
if (this.currentPlanFilePath !== filePath) {
|
|
38
|
+
try {
|
|
39
|
+
await fs.unlink(filePath);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (
|
|
42
|
+
error instanceof Error &&
|
|
43
|
+
(error as Error & { code?: string }).code !== "ENOENT"
|
|
44
|
+
) {
|
|
45
|
+
logger?.error(
|
|
46
|
+
`Failed to remove existing plan file: ${filePath}`,
|
|
47
|
+
error,
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
this.currentPlanFilePath = filePath;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
logger?.info(`Generated plan file path: ${filePath}`);
|
|
36
55
|
return { path: filePath, name };
|
|
37
56
|
}
|
|
38
57
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { logger } from "../utils/globalLogger.js";
|
|
2
|
+
import { Plugin, PluginConfig } from "../types/index.js";
|
|
2
3
|
import { PluginLoader } from "../services/pluginLoader.js";
|
|
3
4
|
import * as path from "path";
|
|
4
5
|
import { SkillManager } from "./skillManager.js";
|
|
@@ -8,41 +9,48 @@ import { McpManager } from "./mcpManager.js";
|
|
|
8
9
|
import { SlashCommandManager } from "./slashCommandManager.js";
|
|
9
10
|
import { MarketplaceService } from "../services/MarketplaceService.js";
|
|
10
11
|
import { ConfigurationService } from "../services/configurationService.js";
|
|
12
|
+
import { Container } from "../utils/container.js";
|
|
11
13
|
|
|
12
14
|
export interface PluginManagerOptions {
|
|
13
15
|
workdir: string;
|
|
14
|
-
logger?: Logger;
|
|
15
|
-
skillManager?: SkillManager;
|
|
16
|
-
hookManager?: HookManager;
|
|
17
|
-
lspManager?: LspManager;
|
|
18
|
-
mcpManager?: McpManager;
|
|
19
|
-
slashCommandManager?: SlashCommandManager;
|
|
20
16
|
enabledPlugins?: Record<string, boolean>;
|
|
21
|
-
configurationService?: ConfigurationService;
|
|
22
17
|
}
|
|
23
18
|
|
|
24
19
|
export class PluginManager {
|
|
25
20
|
private plugins = new Map<string, Plugin>();
|
|
26
21
|
private workdir: string;
|
|
27
|
-
private logger?: Logger;
|
|
28
|
-
private skillManager?: SkillManager;
|
|
29
|
-
private hookManager?: HookManager;
|
|
30
|
-
private lspManager?: LspManager;
|
|
31
|
-
private mcpManager?: McpManager;
|
|
32
|
-
private slashCommandManager?: SlashCommandManager;
|
|
33
22
|
private enabledPlugins: Record<string, boolean>;
|
|
34
|
-
private configurationService?: ConfigurationService;
|
|
35
23
|
|
|
36
|
-
constructor(
|
|
24
|
+
constructor(
|
|
25
|
+
private container: Container,
|
|
26
|
+
options: PluginManagerOptions,
|
|
27
|
+
) {
|
|
37
28
|
this.workdir = options.workdir;
|
|
38
|
-
this.logger = options.logger;
|
|
39
|
-
this.skillManager = options.skillManager;
|
|
40
|
-
this.hookManager = options.hookManager;
|
|
41
|
-
this.lspManager = options.lspManager;
|
|
42
|
-
this.mcpManager = options.mcpManager;
|
|
43
|
-
this.slashCommandManager = options.slashCommandManager;
|
|
44
29
|
this.enabledPlugins = options.enabledPlugins || {};
|
|
45
|
-
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private get skillManager(): SkillManager | undefined {
|
|
33
|
+
return this.container.get<SkillManager>("SkillManager");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private get hookManager(): HookManager | undefined {
|
|
37
|
+
return this.container.get<HookManager>("HookManager");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private get lspManager(): LspManager | undefined {
|
|
41
|
+
return this.container.get<LspManager>("LspManager");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private get mcpManager(): McpManager | undefined {
|
|
45
|
+
return this.container.get<McpManager>("McpManager");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private get slashCommandManager(): SlashCommandManager | undefined {
|
|
49
|
+
return this.container.get<SlashCommandManager>("SlashCommandManager");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private get configurationService(): ConfigurationService | undefined {
|
|
53
|
+
return this.container.get<ConfigurationService>("ConfigurationService");
|
|
46
54
|
}
|
|
47
55
|
|
|
48
56
|
/**
|
|
@@ -70,15 +78,13 @@ export class PluginManager {
|
|
|
70
78
|
for (const p of installedRegistry.plugins) {
|
|
71
79
|
const pluginId = `${p.name}@${p.marketplace}`;
|
|
72
80
|
if (this.enabledPlugins[pluginId] !== true) {
|
|
73
|
-
|
|
74
|
-
`Plugin ${pluginId} is not enabled via configuration`,
|
|
75
|
-
);
|
|
81
|
+
logger?.info(`Plugin ${pluginId} is not enabled via configuration`);
|
|
76
82
|
continue;
|
|
77
83
|
}
|
|
78
84
|
await this.loadSinglePlugin(p.cachePath);
|
|
79
85
|
}
|
|
80
86
|
} catch (error) {
|
|
81
|
-
|
|
87
|
+
logger?.error("Failed to load installed plugins:", error);
|
|
82
88
|
}
|
|
83
89
|
}
|
|
84
90
|
|
|
@@ -91,9 +97,7 @@ export class PluginManager {
|
|
|
91
97
|
|
|
92
98
|
if (this.plugins.has(manifest.name)) {
|
|
93
99
|
// If already loaded (e.g. via explicit config), skip
|
|
94
|
-
|
|
95
|
-
`Plugin with name '${manifest.name}' is already loaded`,
|
|
96
|
-
);
|
|
100
|
+
logger?.warn(`Plugin with name '${manifest.name}' is already loaded`);
|
|
97
101
|
return;
|
|
98
102
|
}
|
|
99
103
|
|
|
@@ -138,9 +142,9 @@ export class PluginManager {
|
|
|
138
142
|
}
|
|
139
143
|
|
|
140
144
|
this.plugins.set(manifest.name, plugin);
|
|
141
|
-
|
|
145
|
+
logger?.info(`Loaded plugin: ${manifest.name} v${manifest.version}`);
|
|
142
146
|
} catch (error) {
|
|
143
|
-
|
|
147
|
+
logger?.error(`Failed to load plugin from ${absolutePath}`, error);
|
|
144
148
|
}
|
|
145
149
|
}
|
|
146
150
|
|
|
@@ -152,7 +156,7 @@ export class PluginManager {
|
|
|
152
156
|
// Load plugins from configuration (e.g. --plugin-dir) first to give them higher priority
|
|
153
157
|
for (const config of configs) {
|
|
154
158
|
if (config.type !== "local") {
|
|
155
|
-
|
|
159
|
+
logger?.warn(`Unsupported plugin type: ${config.type}`);
|
|
156
160
|
continue;
|
|
157
161
|
}
|
|
158
162
|
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import fs from "fs/promises";
|
|
2
2
|
import { FileSnapshot } from "../types/reversion.js";
|
|
3
3
|
import { ReversionService } from "../services/reversionService.js";
|
|
4
|
+
import { Container } from "../utils/container.js";
|
|
4
5
|
|
|
5
6
|
export class ReversionManager {
|
|
6
7
|
private buffer: Map<string, FileSnapshot> = new Map();
|
|
7
|
-
private reversionService: ReversionService;
|
|
8
8
|
|
|
9
|
-
constructor(
|
|
10
|
-
|
|
9
|
+
constructor(private container: Container) {}
|
|
10
|
+
|
|
11
|
+
private get reversionService(): ReversionService {
|
|
12
|
+
return this.container.get<ReversionService>("ReversionService")!;
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
/**
|