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
|
@@ -12,6 +12,28 @@ import { splitBashCommand, stripEnvVars, stripRedirections, getSmartPrefix, DANG
|
|
|
12
12
|
import { isPathInside } from "../utils/pathSafety.js";
|
|
13
13
|
import { BASH_TOOL_NAME, EDIT_TOOL_NAME, WRITE_TOOL_NAME, READ_TOOL_NAME, LS_TOOL_NAME, } from "../constants/tools.js";
|
|
14
14
|
const SAFE_COMMANDS = ["cd", "ls", "pwd", "true", "false"];
|
|
15
|
+
const DEFAULT_ALLOWED_RULES = [
|
|
16
|
+
"Bash(git status*)",
|
|
17
|
+
"Bash(git diff*)",
|
|
18
|
+
"Bash(git log*)",
|
|
19
|
+
"Bash(git show*)",
|
|
20
|
+
"Bash(git branch*)",
|
|
21
|
+
"Bash(git tag*)",
|
|
22
|
+
"Bash(git remote*)",
|
|
23
|
+
"Bash(git ls-files*)",
|
|
24
|
+
"Bash(git rev-parse*)",
|
|
25
|
+
"Bash(git config --list*)",
|
|
26
|
+
"Bash(git config -l*)",
|
|
27
|
+
"Bash(git cat-file*)",
|
|
28
|
+
"Bash(git count-objects*)",
|
|
29
|
+
"Bash(echo*)",
|
|
30
|
+
"Bash(which*)",
|
|
31
|
+
"Bash(type*)",
|
|
32
|
+
"Bash(hostname*)",
|
|
33
|
+
"Bash(whoami*)",
|
|
34
|
+
"Bash(date*)",
|
|
35
|
+
"Bash(uptime*)",
|
|
36
|
+
];
|
|
15
37
|
import { logger } from "../utils/globalLogger.js";
|
|
16
38
|
export class PermissionManager {
|
|
17
39
|
constructor(container, options = {}) {
|
|
@@ -39,69 +61,71 @@ export class PermissionManager {
|
|
|
39
61
|
*/
|
|
40
62
|
updateConfiguredDefaultMode(defaultMode) {
|
|
41
63
|
const oldEffectiveMode = this.getCurrentEffectiveMode();
|
|
42
|
-
logger?.debug("Updating configured default permission mode", {
|
|
43
|
-
previous: this.configuredDefaultMode,
|
|
44
|
-
new: defaultMode,
|
|
45
|
-
});
|
|
46
64
|
this.configuredDefaultMode = defaultMode;
|
|
47
65
|
const newEffectiveMode = this.getCurrentEffectiveMode();
|
|
48
66
|
if (oldEffectiveMode !== newEffectiveMode &&
|
|
49
67
|
this.onConfiguredDefaultModeChange) {
|
|
50
|
-
logger?.debug("Effective permission mode changed due to configuration update", {
|
|
51
|
-
oldMode: oldEffectiveMode,
|
|
52
|
-
newMode: newEffectiveMode,
|
|
53
|
-
});
|
|
54
68
|
this.onConfiguredDefaultModeChange(newEffectiveMode);
|
|
55
69
|
}
|
|
56
70
|
}
|
|
57
71
|
/**
|
|
58
|
-
* Get
|
|
72
|
+
* Get the configured default mode
|
|
73
|
+
*/
|
|
74
|
+
getConfiguredDefaultMode() {
|
|
75
|
+
return this.configuredDefaultMode;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get all currently allowed rules (user-defined)
|
|
59
79
|
*/
|
|
60
80
|
getAllowedRules() {
|
|
61
81
|
return [...this.allowedRules];
|
|
62
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Get all currently denied rules
|
|
85
|
+
*/
|
|
86
|
+
getDeniedRules() {
|
|
87
|
+
return [...this.deniedRules];
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get all additional directories
|
|
91
|
+
*/
|
|
92
|
+
getAdditionalDirectories() {
|
|
93
|
+
return [...this.additionalDirectories];
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get all default allowed rules
|
|
97
|
+
*/
|
|
98
|
+
getDefaultAllowedRules() {
|
|
99
|
+
return [...DEFAULT_ALLOWED_RULES];
|
|
100
|
+
}
|
|
63
101
|
/**
|
|
64
102
|
* Update the allowed rules (e.g., when configuration reloads)
|
|
65
103
|
*/
|
|
66
104
|
updateAllowedRules(rules) {
|
|
67
|
-
logger?.debug("Updating allowed permission rules", {
|
|
68
|
-
count: rules.length,
|
|
69
|
-
});
|
|
70
105
|
this.allowedRules = rules;
|
|
71
106
|
}
|
|
72
107
|
/**
|
|
73
108
|
* Update the denied rules (e.g., when configuration reloads)
|
|
74
109
|
*/
|
|
75
110
|
updateDeniedRules(rules) {
|
|
76
|
-
logger?.debug("Updating denied permission rules", {
|
|
77
|
-
count: rules.length,
|
|
78
|
-
});
|
|
79
111
|
this.deniedRules = rules;
|
|
80
112
|
}
|
|
81
113
|
/**
|
|
82
114
|
* Add temporary rules for the current session
|
|
83
115
|
*/
|
|
84
116
|
addTemporaryRules(rules) {
|
|
85
|
-
logger?.debug("Adding temporary permission rules", {
|
|
86
|
-
count: rules.length,
|
|
87
|
-
rules,
|
|
88
|
-
});
|
|
89
117
|
this.temporaryRules.push(...rules);
|
|
90
118
|
}
|
|
91
119
|
/**
|
|
92
120
|
* Clear all temporary rules
|
|
93
121
|
*/
|
|
94
122
|
clearTemporaryRules() {
|
|
95
|
-
logger?.debug("Clearing temporary permission rules");
|
|
96
123
|
this.temporaryRules = [];
|
|
97
124
|
}
|
|
98
125
|
/**
|
|
99
126
|
* Update the additional directories (e.g., when configuration reloads)
|
|
100
127
|
*/
|
|
101
128
|
updateAdditionalDirectories(directories) {
|
|
102
|
-
logger?.debug("Updating additional directories", {
|
|
103
|
-
count: directories.length,
|
|
104
|
-
});
|
|
105
129
|
this.additionalDirectories = directories.map((dir) => {
|
|
106
130
|
if (this.workdir && !path.isAbsolute(dir)) {
|
|
107
131
|
return path.resolve(this.workdir, dir);
|
|
@@ -113,16 +137,12 @@ export class PermissionManager {
|
|
|
113
137
|
* Update the working directory
|
|
114
138
|
*/
|
|
115
139
|
updateWorkdir(workdir) {
|
|
116
|
-
logger?.debug("Updating working directory", {
|
|
117
|
-
workdir,
|
|
118
|
-
});
|
|
119
140
|
this.workdir = workdir;
|
|
120
141
|
}
|
|
121
142
|
/**
|
|
122
143
|
* Set the current plan file path
|
|
123
144
|
*/
|
|
124
145
|
setPlanFilePath(path) {
|
|
125
|
-
logger?.debug("Setting plan file path", { path });
|
|
126
146
|
this.planFilePath = path;
|
|
127
147
|
}
|
|
128
148
|
/**
|
|
@@ -150,11 +170,6 @@ export class PermissionManager {
|
|
|
150
170
|
return { isInside: true, resolvedPath: absolutePath };
|
|
151
171
|
}
|
|
152
172
|
}
|
|
153
|
-
logger?.debug("Path is outside Safe Zone", {
|
|
154
|
-
absolutePath,
|
|
155
|
-
workdir: effectiveWorkdir,
|
|
156
|
-
additionalDirectories: this.additionalDirectories,
|
|
157
|
-
});
|
|
158
173
|
return { isInside: false, resolvedPath: absolutePath };
|
|
159
174
|
}
|
|
160
175
|
/**
|
|
@@ -169,21 +184,13 @@ export class PermissionManager {
|
|
|
169
184
|
resolveEffectivePermissionMode(cliPermissionMode) {
|
|
170
185
|
// CLI override takes highest precedence
|
|
171
186
|
if (cliPermissionMode !== undefined) {
|
|
172
|
-
logger?.debug("Using CLI permission mode override", {
|
|
173
|
-
cliMode: cliPermissionMode,
|
|
174
|
-
configuredDefault: this.configuredDefaultMode,
|
|
175
|
-
});
|
|
176
187
|
return cliPermissionMode;
|
|
177
188
|
}
|
|
178
189
|
// Use configured default mode if available
|
|
179
190
|
if (this.configuredDefaultMode !== undefined) {
|
|
180
|
-
logger?.debug("Using configured default permission mode", {
|
|
181
|
-
configuredDefault: this.configuredDefaultMode,
|
|
182
|
-
});
|
|
183
191
|
return this.configuredDefaultMode;
|
|
184
192
|
}
|
|
185
193
|
// Fall back to system default
|
|
186
|
-
logger?.debug("Using system default permission mode");
|
|
187
194
|
return "default";
|
|
188
195
|
}
|
|
189
196
|
/**
|
|
@@ -191,11 +198,6 @@ export class PermissionManager {
|
|
|
191
198
|
* Called by individual tools after validation/diff, before real operation
|
|
192
199
|
*/
|
|
193
200
|
async checkPermission(context) {
|
|
194
|
-
logger?.debug("Checking permission for tool", {
|
|
195
|
-
toolName: context.toolName,
|
|
196
|
-
permissionMode: context.permissionMode,
|
|
197
|
-
hasCallback: !!context.canUseToolCallback,
|
|
198
|
-
});
|
|
199
201
|
// 0. Check denied rules first - Deny always takes precedence
|
|
200
202
|
for (const rule of this.deniedRules) {
|
|
201
203
|
if (this.matchesRule(context, rule)) {
|
|
@@ -211,9 +213,6 @@ export class PermissionManager {
|
|
|
211
213
|
}
|
|
212
214
|
// 1. If bypassPermissions mode, always allow
|
|
213
215
|
if (context.permissionMode === "bypassPermissions") {
|
|
214
|
-
logger?.debug("Permission bypassed for tool", {
|
|
215
|
-
toolName: context.toolName,
|
|
216
|
-
});
|
|
217
216
|
return { behavior: "allow" };
|
|
218
217
|
}
|
|
219
218
|
// 1.1 If acceptEdits mode, allow Edit, Write
|
|
@@ -234,9 +233,6 @@ export class PermissionManager {
|
|
|
234
233
|
// Fall through to normal permission check flow to trigger confirmation prompt
|
|
235
234
|
}
|
|
236
235
|
else {
|
|
237
|
-
logger?.debug("Permission automatically accepted for tool in acceptEdits mode", {
|
|
238
|
-
toolName: context.toolName,
|
|
239
|
-
});
|
|
240
236
|
return { behavior: "allow" };
|
|
241
237
|
}
|
|
242
238
|
}
|
|
@@ -244,9 +240,6 @@ export class PermissionManager {
|
|
|
244
240
|
}
|
|
245
241
|
// 1.2 Check if tool call is allowed by persistent or temporary rules
|
|
246
242
|
if (this.isAllowedByRule(context)) {
|
|
247
|
-
logger?.debug("Permission allowed by persistent rule", {
|
|
248
|
-
toolName: context.toolName,
|
|
249
|
-
});
|
|
250
243
|
return { behavior: "allow" };
|
|
251
244
|
}
|
|
252
245
|
// 1.3 If plan mode, allow Read-only tools and Edit/Write for plan file
|
|
@@ -258,10 +251,6 @@ export class PermissionManager {
|
|
|
258
251
|
const absoluteTargetPath = path.resolve(targetPath);
|
|
259
252
|
const absolutePlanPath = path.resolve(this.planFilePath);
|
|
260
253
|
if (absoluteTargetPath === absolutePlanPath) {
|
|
261
|
-
logger?.debug("Allowing write to plan file in plan mode", {
|
|
262
|
-
toolName: context.toolName,
|
|
263
|
-
targetPath,
|
|
264
|
-
});
|
|
265
254
|
return { behavior: "allow" };
|
|
266
255
|
}
|
|
267
256
|
}
|
|
@@ -273,22 +262,18 @@ export class PermissionManager {
|
|
|
273
262
|
}
|
|
274
263
|
// 2. If not a restricted tool, always allow
|
|
275
264
|
if (!this.isRestrictedTool(context.toolName)) {
|
|
276
|
-
logger?.debug("Tool is not restricted, allowing", {
|
|
277
|
-
toolName: context.toolName,
|
|
278
|
-
});
|
|
279
265
|
return { behavior: "allow" };
|
|
280
266
|
}
|
|
281
267
|
// 3. If custom callback provided, call it and return result
|
|
282
268
|
if (context.canUseToolCallback) {
|
|
283
269
|
try {
|
|
284
|
-
logger?.debug("Calling custom permission callback for tool", {
|
|
285
|
-
toolName: context.toolName,
|
|
286
|
-
});
|
|
287
270
|
const decision = await context.canUseToolCallback(context);
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
271
|
+
if (decision.behavior !== "allow") {
|
|
272
|
+
logger?.debug("Custom callback returned decision", {
|
|
273
|
+
toolName: context.toolName,
|
|
274
|
+
decision,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
292
277
|
return decision;
|
|
293
278
|
}
|
|
294
279
|
catch (error) {
|
|
@@ -317,12 +302,7 @@ export class PermissionManager {
|
|
|
317
302
|
* Determine if a tool requires permission checks based on its name
|
|
318
303
|
*/
|
|
319
304
|
isRestrictedTool(toolName) {
|
|
320
|
-
|
|
321
|
-
logger?.debug("Checking if tool is restricted", {
|
|
322
|
-
toolName,
|
|
323
|
-
isRestricted,
|
|
324
|
-
});
|
|
325
|
-
return isRestricted;
|
|
305
|
+
return RESTRICTED_TOOLS.includes(toolName);
|
|
326
306
|
}
|
|
327
307
|
/**
|
|
328
308
|
* Helper method to create a permission context for CLI integration
|
|
@@ -388,13 +368,6 @@ export class PermissionManager {
|
|
|
388
368
|
context.hidePersistentOption = true;
|
|
389
369
|
}
|
|
390
370
|
}
|
|
391
|
-
logger?.debug("Created permission context", {
|
|
392
|
-
toolName,
|
|
393
|
-
permissionMode,
|
|
394
|
-
hasCallback: !!callback,
|
|
395
|
-
hasToolInput: !!toolInput,
|
|
396
|
-
suggestedPrefix,
|
|
397
|
-
});
|
|
398
371
|
return context;
|
|
399
372
|
}
|
|
400
373
|
/**
|
|
@@ -424,8 +397,9 @@ export class PermissionManager {
|
|
|
424
397
|
const regexPattern = pattern
|
|
425
398
|
.replace(/[.+^${}()|[\]\\?]/g, "\\$&") // Escape regex special chars including ?
|
|
426
399
|
.replace(/\*/g, ".*"); // Replace * with .*
|
|
427
|
-
const regex = new RegExp(`^${regexPattern}
|
|
428
|
-
|
|
400
|
+
const regex = new RegExp(`^${regexPattern}$`, "s");
|
|
401
|
+
const matched = regex.test(processedPart);
|
|
402
|
+
return matched;
|
|
429
403
|
}
|
|
430
404
|
// Handle path-based rules (e.g., "Read(**/*.env)")
|
|
431
405
|
const pathTools = [
|
|
@@ -490,7 +464,9 @@ export class PermissionManager {
|
|
|
490
464
|
...ctx,
|
|
491
465
|
toolInput: { ...ctx.toolInput, command: processedPart },
|
|
492
466
|
};
|
|
493
|
-
const allowedByRule = rules.some((rule) =>
|
|
467
|
+
const allowedByRule = rules.some((rule) => {
|
|
468
|
+
return this.matchesRule(partContext, rule);
|
|
469
|
+
});
|
|
494
470
|
if (allowedByRule)
|
|
495
471
|
return true;
|
|
496
472
|
return !this.isRestrictedTool(ctx.toolName);
|
|
@@ -504,7 +480,11 @@ export class PermissionManager {
|
|
|
504
480
|
return true;
|
|
505
481
|
}
|
|
506
482
|
// Check persistent allowed rules
|
|
507
|
-
|
|
483
|
+
if (isAllowedByRuleList(context, this.allowedRules)) {
|
|
484
|
+
return true;
|
|
485
|
+
}
|
|
486
|
+
// Check default allowed rules
|
|
487
|
+
return isAllowedByRuleList(context, DEFAULT_ALLOWED_RULES);
|
|
508
488
|
}
|
|
509
489
|
/**
|
|
510
490
|
* Expand a bash command into individual permission rules, filtering out safe commands.
|
|
@@ -580,4 +560,45 @@ export class PermissionManager {
|
|
|
580
560
|
}
|
|
581
561
|
return rules;
|
|
582
562
|
}
|
|
563
|
+
/**
|
|
564
|
+
* Add a persistent permission rule
|
|
565
|
+
* @param rule - The rule to add (e.g., "Bash(ls)")
|
|
566
|
+
*/
|
|
567
|
+
async addPermissionRule(rule) {
|
|
568
|
+
if (!this.workdir) {
|
|
569
|
+
throw new Error("Working directory not set in PermissionManager");
|
|
570
|
+
}
|
|
571
|
+
// 1. Expand rule if it's a Bash command
|
|
572
|
+
let rulesToAdd = [rule];
|
|
573
|
+
const bashMatch = rule.match(/^Bash\((.*)\)$/);
|
|
574
|
+
if (bashMatch) {
|
|
575
|
+
const command = bashMatch[1];
|
|
576
|
+
rulesToAdd = this.expandBashRule(command, this.workdir);
|
|
577
|
+
}
|
|
578
|
+
const configurationService = this.container.get("ConfigurationService");
|
|
579
|
+
for (const ruleToAdd of rulesToAdd) {
|
|
580
|
+
// 2. Update PermissionManager state
|
|
581
|
+
const currentRules = this.getAllowedRules();
|
|
582
|
+
const defaultRules = this.getDefaultAllowedRules();
|
|
583
|
+
if (!currentRules.includes(ruleToAdd) &&
|
|
584
|
+
!defaultRules.includes(ruleToAdd)) {
|
|
585
|
+
this.updateAllowedRules([...currentRules, ruleToAdd]);
|
|
586
|
+
// 3. Persist to settings.local.json
|
|
587
|
+
try {
|
|
588
|
+
if (configurationService) {
|
|
589
|
+
await configurationService.addAllowedRule(this.workdir, ruleToAdd);
|
|
590
|
+
this._logger?.debug("Persistent permission rule added", {
|
|
591
|
+
rule: ruleToAdd,
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
catch (error) {
|
|
596
|
+
this._logger?.error("Failed to persist permission rule", {
|
|
597
|
+
rule: ruleToAdd,
|
|
598
|
+
error: error instanceof Error ? error.message : String(error),
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
583
604
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Container } from "../utils/container.js";
|
|
2
|
+
import type { PermissionMode } from "../types/permissions.js";
|
|
2
3
|
export declare class PlanManager {
|
|
3
4
|
private container;
|
|
4
5
|
private planDir;
|
|
@@ -15,5 +16,10 @@ export declare class PlanManager {
|
|
|
15
16
|
* Returns the directory where plan files are stored
|
|
16
17
|
*/
|
|
17
18
|
getPlanDir(): string;
|
|
19
|
+
/**
|
|
20
|
+
* Handle plan mode transition, generating or clearing plan file path
|
|
21
|
+
* @param mode - The current effective permission mode
|
|
22
|
+
*/
|
|
23
|
+
handlePlanModeTransition(mode: PermissionMode): void;
|
|
18
24
|
}
|
|
19
25
|
//# sourceMappingURL=planManager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planManager.d.ts","sourceRoot":"","sources":["../../src/managers/planManager.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"planManager.d.ts","sourceRoot":"","sources":["../../src/managers/planManager.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAO9D,qBAAa,WAAW;IAIV,OAAO,CAAC,SAAS;IAH7B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,mBAAmB,CAAuB;gBAE9B,SAAS,EAAE,SAAS;IAIxC;;OAEG;IACU,yBAAyB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAC7D,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IA+BF;;OAEG;IACI,UAAU,IAAI,MAAM;IAI3B;;;OAGG;IACI,wBAAwB,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;CAkB5D"}
|
|
@@ -46,4 +46,25 @@ export class PlanManager {
|
|
|
46
46
|
getPlanDir() {
|
|
47
47
|
return this.planDir;
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Handle plan mode transition, generating or clearing plan file path
|
|
51
|
+
* @param mode - The current effective permission mode
|
|
52
|
+
*/
|
|
53
|
+
handlePlanModeTransition(mode) {
|
|
54
|
+
const permissionManager = this.container.get("PermissionManager");
|
|
55
|
+
const messageManager = this.container.get("MessageManager");
|
|
56
|
+
if (mode === "plan") {
|
|
57
|
+
this.getOrGeneratePlanFilePath(messageManager?.getRootSessionId())
|
|
58
|
+
.then(({ path }) => {
|
|
59
|
+
logger?.debug("Plan file path generated", { path });
|
|
60
|
+
permissionManager?.setPlanFilePath(path);
|
|
61
|
+
})
|
|
62
|
+
.catch((error) => {
|
|
63
|
+
logger?.error("Failed to generate plan file path", error);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
permissionManager?.setPlanFilePath(undefined);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
49
70
|
}
|
|
@@ -24,6 +24,10 @@ export declare class SkillManager {
|
|
|
24
24
|
* Get all available skills metadata
|
|
25
25
|
*/
|
|
26
26
|
getAvailableSkills(): SkillMetadata[];
|
|
27
|
+
/**
|
|
28
|
+
* Get metadata for a specific skill by name
|
|
29
|
+
*/
|
|
30
|
+
getSkillMetadata(name: string): SkillMetadata | undefined;
|
|
27
31
|
/**
|
|
28
32
|
* Load a specific skill by name
|
|
29
33
|
* Returns the skill content that was loaded during initialization
|
|
@@ -47,11 +51,12 @@ export declare class SkillManager {
|
|
|
47
51
|
executeSkill(args: SkillToolArgs): Promise<{
|
|
48
52
|
content: string;
|
|
49
53
|
context?: SkillInvocationContext;
|
|
54
|
+
allowedTools?: string[];
|
|
50
55
|
}>;
|
|
51
56
|
/**
|
|
52
|
-
*
|
|
57
|
+
* Process skill content with arguments and bash commands
|
|
53
58
|
*/
|
|
54
|
-
private
|
|
59
|
+
private processSkillContent;
|
|
55
60
|
/**
|
|
56
61
|
* Format available skills list for error messages
|
|
57
62
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skillManager.d.ts","sourceRoot":"","sources":["../../src/managers/skillManager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EACb,KAAK,EAGL,aAAa,EACb,sBAAsB,EACvB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"skillManager.d.ts","sourceRoot":"","sources":["../../src/managers/skillManager.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,mBAAmB,EACnB,aAAa,EACb,KAAK,EAGL,aAAa,EACb,sBAAsB,EACvB,MAAM,mBAAmB,CAAC;AAS3B,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD;;GAEG;AACH,qBAAa,YAAY;IAUrB,OAAO,CAAC,SAAS;IATnB,OAAO,CAAC,kBAAkB,CAAS;IACnC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAS;IAExB,OAAO,CAAC,aAAa,CAAoC;IACzD,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,WAAW,CAAS;gBAGlB,SAAS,EAAE,SAAS,EAC5B,OAAO,GAAE,mBAAwB;IAQnC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAoCjC;;OAEG;IACH,aAAa,IAAI,OAAO;IAIxB;;OAEG;IACH,kBAAkB,IAAI,aAAa,EAAE;IAQrC;;OAEG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAQzD;;;OAGG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;IAgBzD;;OAEG;YACW,cAAc;IAkB5B;;OAEG;YACW,uBAAuB;IA8ErC;;OAEG;YACW,oBAAoB;IAkBlC;;OAEG;IACG,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC;QAC/C,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,sBAAsB,CAAC;QACjC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;KACzB,CAAC;IA4CF;;OAEG;YACW,mBAAmB;IAyBjC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAc7B;;OAEG;IACH,oBAAoB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI;CAe5C"}
|
|
@@ -2,6 +2,8 @@ import { readdir, stat } from "fs/promises";
|
|
|
2
2
|
import { join } from "path";
|
|
3
3
|
import { homedir } from "os";
|
|
4
4
|
import { parseSkillFile, formatSkillError } from "../utils/skillParser.js";
|
|
5
|
+
import { substituteCommandParameters } from "../utils/commandArgumentParser.js";
|
|
6
|
+
import { parseBashCommands, replaceBashCommandsWithOutput, executeBashCommands, } from "../utils/markdownParser.js";
|
|
5
7
|
import { logger } from "../utils/globalLogger.js";
|
|
6
8
|
/**
|
|
7
9
|
* Manages skill discovery and loading
|
|
@@ -64,6 +66,15 @@ export class SkillManager {
|
|
|
64
66
|
}
|
|
65
67
|
return Array.from(this.skillMetadata.values());
|
|
66
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Get metadata for a specific skill by name
|
|
71
|
+
*/
|
|
72
|
+
getSkillMetadata(name) {
|
|
73
|
+
if (!this.initialized) {
|
|
74
|
+
throw new Error("SkillManager not initialized. Call initialize() first.");
|
|
75
|
+
}
|
|
76
|
+
return this.skillMetadata.get(name);
|
|
77
|
+
}
|
|
67
78
|
/**
|
|
68
79
|
* Load a specific skill by name
|
|
69
80
|
* Returns the skill content that was loaded during initialization
|
|
@@ -129,10 +140,7 @@ export class SkillManager {
|
|
|
129
140
|
};
|
|
130
141
|
// Create full skill object with content
|
|
131
142
|
const skill = {
|
|
132
|
-
|
|
133
|
-
description: parsed.skillMetadata.description,
|
|
134
|
-
type: type, // Use the collection type
|
|
135
|
-
skillPath: parsed.skillMetadata.skillPath,
|
|
143
|
+
...skillMetadata,
|
|
136
144
|
content: parsed.content,
|
|
137
145
|
frontmatter: parsed.frontmatter,
|
|
138
146
|
isValid: parsed.isValid,
|
|
@@ -185,8 +193,8 @@ export class SkillManager {
|
|
|
185
193
|
* Execute a skill by name
|
|
186
194
|
*/
|
|
187
195
|
async executeSkill(args) {
|
|
188
|
-
const { skill_name } = args;
|
|
189
|
-
logger?.debug(`Invoking skill: ${skill_name}`);
|
|
196
|
+
const { skill_name, args: skillArgs } = args;
|
|
197
|
+
logger?.debug(`Invoking skill: ${skill_name} with args: ${skillArgs}`);
|
|
190
198
|
try {
|
|
191
199
|
// Load the skill
|
|
192
200
|
const skill = await this.loadSkill(skill_name);
|
|
@@ -201,12 +209,15 @@ export class SkillManager {
|
|
|
201
209
|
content: `❌ **Skill validation failed**:\n\n\`\`\`\n${errorMsg}\n\`\`\``,
|
|
202
210
|
};
|
|
203
211
|
}
|
|
212
|
+
// Process skill content with arguments and bash commands
|
|
213
|
+
const processedContent = await this.processSkillContent(skill, skillArgs || "");
|
|
204
214
|
// Return skill content with context
|
|
205
215
|
return {
|
|
206
|
-
content:
|
|
216
|
+
content: processedContent,
|
|
207
217
|
context: {
|
|
208
218
|
skillName: skill_name,
|
|
209
219
|
},
|
|
220
|
+
allowedTools: skill.allowedTools,
|
|
210
221
|
};
|
|
211
222
|
}
|
|
212
223
|
catch (error) {
|
|
@@ -217,15 +228,23 @@ export class SkillManager {
|
|
|
217
228
|
}
|
|
218
229
|
}
|
|
219
230
|
/**
|
|
220
|
-
*
|
|
231
|
+
* Process skill content with arguments and bash commands
|
|
221
232
|
*/
|
|
222
|
-
|
|
233
|
+
async processSkillContent(skill, argsString) {
|
|
223
234
|
const header = `🧠 **${skill.name}** (${skill.type} skill)\n\n`;
|
|
224
235
|
const description = `*${skill.description}*\n\n`;
|
|
225
236
|
const skillPath = `📁 Skill location: \`${skill.skillPath}\`\n\n`;
|
|
226
237
|
// Extract content after frontmatter
|
|
227
238
|
const contentMatch = skill.content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)$/);
|
|
228
|
-
|
|
239
|
+
let mainContent = contentMatch ? contentMatch[1].trim() : skill.content;
|
|
240
|
+
// 1. Substitute parameters ($1, $ARGUMENTS, etc.)
|
|
241
|
+
mainContent = substituteCommandParameters(mainContent, argsString);
|
|
242
|
+
// 2. Parse and execute bash commands (!`command`)
|
|
243
|
+
const { commands } = parseBashCommands(mainContent);
|
|
244
|
+
if (commands.length > 0) {
|
|
245
|
+
const results = await executeBashCommands(commands, this.workdir);
|
|
246
|
+
mainContent = replaceBashCommandsWithOutput(mainContent, results);
|
|
247
|
+
}
|
|
229
248
|
return header + description + skillPath + mainContent;
|
|
230
249
|
}
|
|
231
250
|
/**
|
|
@@ -250,6 +269,7 @@ export class SkillManager {
|
|
|
250
269
|
description: skill.description,
|
|
251
270
|
type: skill.type,
|
|
252
271
|
skillPath: skill.skillPath,
|
|
272
|
+
allowedTools: skill.allowedTools,
|
|
253
273
|
});
|
|
254
274
|
this.skillContent.set(skill.name, skill);
|
|
255
275
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { SlashCommand, CustomSlashCommand } from "../types/index.js";
|
|
2
2
|
import { Container } from "../utils/container.js";
|
|
3
|
+
import type { SkillMetadata } from "../types/skills.js";
|
|
3
4
|
export interface SlashCommandManagerOptions {
|
|
4
5
|
workdir: string;
|
|
5
6
|
}
|
|
@@ -7,6 +8,7 @@ export declare class SlashCommandManager {
|
|
|
7
8
|
private container;
|
|
8
9
|
private commands;
|
|
9
10
|
private customCommands;
|
|
11
|
+
private skillCommandIds;
|
|
10
12
|
private workdir;
|
|
11
13
|
constructor(container: Container, options: SlashCommandManagerOptions);
|
|
12
14
|
initialize(): void;
|
|
@@ -14,11 +16,16 @@ export declare class SlashCommandManager {
|
|
|
14
16
|
private get aiManager();
|
|
15
17
|
private get backgroundTaskManager();
|
|
16
18
|
private get taskManager();
|
|
19
|
+
private get skillManager();
|
|
17
20
|
private initializeBuiltinCommands;
|
|
18
21
|
/**
|
|
19
22
|
* Load custom commands from filesystem
|
|
20
23
|
*/
|
|
21
24
|
private loadCustomCommands;
|
|
25
|
+
/**
|
|
26
|
+
* Register skills as slash commands
|
|
27
|
+
*/
|
|
28
|
+
registerSkillCommands(skills: SkillMetadata[]): void;
|
|
22
29
|
/**
|
|
23
30
|
* Register commands from a plugin with namespacing
|
|
24
31
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slashCommandManager.d.ts","sourceRoot":"","sources":["../../src/managers/slashCommandManager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAQ1E,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"slashCommandManager.d.ts","sourceRoot":"","sources":["../../src/managers/slashCommandManager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAQ1E,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAQlD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,mBAAmB;IAO5B,OAAO,CAAC,SAAS;IANnB,OAAO,CAAC,QAAQ,CAAmC;IACnD,OAAO,CAAC,cAAc,CAAyC;IAC/D,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,OAAO,CAAS;gBAGd,SAAS,EAAE,SAAS,EAC5B,OAAO,EAAE,0BAA0B;IAK9B,UAAU,IAAI,IAAI;IAKzB,OAAO,KAAK,cAAc,GAEzB;IAED,OAAO,KAAK,SAAS,GAEpB;IAED,OAAO,KAAK,qBAAqB,GAEhC;IAED,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,YAAY,GAEvB;IAED,OAAO,CAAC,yBAAyB;IAoBjC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAyD1B;;OAEG;IACI,qBAAqB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI;IAyD3D;;OAEG;IACI,sBAAsB,CAC3B,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,kBAAkB,EAAE,GAC7B,IAAI;IAwDP;;OAEG;IACI,oBAAoB,IAAI,IAAI;IAWnC;;OAEG;IACI,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAKnD;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACI,WAAW,IAAI,YAAY,EAAE;IAIpC;;OAEG;IACI,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAI9D;;OAEG;IACU,cAAc,CACzB,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC;IAenB;;;OAGG;IACI,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG;QAClD,OAAO,EAAE,OAAO,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf;IAeD;;OAEG;IACI,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI7C;;OAEG;IACI,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAI1E;;OAEG;IACI,iBAAiB,IAAI,kBAAkB,EAAE;IAIhD;;OAEG;YACW,+BAA+B;IAiD7C;;OAEG;IACI,mBAAmB,IAAI,IAAI;CAInC"}
|