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
|
@@ -32,9 +32,33 @@ import {
|
|
|
32
32
|
LS_TOOL_NAME,
|
|
33
33
|
} from "../constants/tools.js";
|
|
34
34
|
import { Container } from "../utils/container.js";
|
|
35
|
+
import { ConfigurationService } from "../services/configurationService.js";
|
|
35
36
|
|
|
36
37
|
const SAFE_COMMANDS = ["cd", "ls", "pwd", "true", "false"];
|
|
37
38
|
|
|
39
|
+
const DEFAULT_ALLOWED_RULES = [
|
|
40
|
+
"Bash(git status*)",
|
|
41
|
+
"Bash(git diff*)",
|
|
42
|
+
"Bash(git log*)",
|
|
43
|
+
"Bash(git show*)",
|
|
44
|
+
"Bash(git branch*)",
|
|
45
|
+
"Bash(git tag*)",
|
|
46
|
+
"Bash(git remote*)",
|
|
47
|
+
"Bash(git ls-files*)",
|
|
48
|
+
"Bash(git rev-parse*)",
|
|
49
|
+
"Bash(git config --list*)",
|
|
50
|
+
"Bash(git config -l*)",
|
|
51
|
+
"Bash(git cat-file*)",
|
|
52
|
+
"Bash(git count-objects*)",
|
|
53
|
+
"Bash(echo*)",
|
|
54
|
+
"Bash(which*)",
|
|
55
|
+
"Bash(type*)",
|
|
56
|
+
"Bash(hostname*)",
|
|
57
|
+
"Bash(whoami*)",
|
|
58
|
+
"Bash(date*)",
|
|
59
|
+
"Bash(uptime*)",
|
|
60
|
+
];
|
|
61
|
+
|
|
38
62
|
import { logger } from "../utils/globalLogger.js";
|
|
39
63
|
|
|
40
64
|
export interface PermissionManagerOptions {
|
|
@@ -93,10 +117,6 @@ export class PermissionManager {
|
|
|
93
117
|
updateConfiguredDefaultMode(defaultMode?: PermissionMode): void {
|
|
94
118
|
const oldEffectiveMode = this.getCurrentEffectiveMode();
|
|
95
119
|
|
|
96
|
-
logger?.debug("Updating configured default permission mode", {
|
|
97
|
-
previous: this.configuredDefaultMode,
|
|
98
|
-
new: defaultMode,
|
|
99
|
-
});
|
|
100
120
|
this.configuredDefaultMode = defaultMode;
|
|
101
121
|
|
|
102
122
|
const newEffectiveMode = this.getCurrentEffectiveMode();
|
|
@@ -104,31 +124,49 @@ export class PermissionManager {
|
|
|
104
124
|
oldEffectiveMode !== newEffectiveMode &&
|
|
105
125
|
this.onConfiguredDefaultModeChange
|
|
106
126
|
) {
|
|
107
|
-
logger?.debug(
|
|
108
|
-
"Effective permission mode changed due to configuration update",
|
|
109
|
-
{
|
|
110
|
-
oldMode: oldEffectiveMode,
|
|
111
|
-
newMode: newEffectiveMode,
|
|
112
|
-
},
|
|
113
|
-
);
|
|
114
127
|
this.onConfiguredDefaultModeChange(newEffectiveMode);
|
|
115
128
|
}
|
|
116
129
|
}
|
|
117
130
|
|
|
118
131
|
/**
|
|
119
|
-
* Get
|
|
132
|
+
* Get the configured default mode
|
|
133
|
+
*/
|
|
134
|
+
public getConfiguredDefaultMode(): PermissionMode | undefined {
|
|
135
|
+
return this.configuredDefaultMode;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Get all currently allowed rules (user-defined)
|
|
120
140
|
*/
|
|
121
141
|
public getAllowedRules(): string[] {
|
|
122
142
|
return [...this.allowedRules];
|
|
123
143
|
}
|
|
124
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Get all currently denied rules
|
|
147
|
+
*/
|
|
148
|
+
public getDeniedRules(): string[] {
|
|
149
|
+
return [...this.deniedRules];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Get all additional directories
|
|
154
|
+
*/
|
|
155
|
+
public getAdditionalDirectories(): string[] {
|
|
156
|
+
return [...this.additionalDirectories];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get all default allowed rules
|
|
161
|
+
*/
|
|
162
|
+
public getDefaultAllowedRules(): string[] {
|
|
163
|
+
return [...DEFAULT_ALLOWED_RULES];
|
|
164
|
+
}
|
|
165
|
+
|
|
125
166
|
/**
|
|
126
167
|
* Update the allowed rules (e.g., when configuration reloads)
|
|
127
168
|
*/
|
|
128
169
|
updateAllowedRules(rules: string[]): void {
|
|
129
|
-
logger?.debug("Updating allowed permission rules", {
|
|
130
|
-
count: rules.length,
|
|
131
|
-
});
|
|
132
170
|
this.allowedRules = rules;
|
|
133
171
|
}
|
|
134
172
|
|
|
@@ -136,9 +174,6 @@ export class PermissionManager {
|
|
|
136
174
|
* Update the denied rules (e.g., when configuration reloads)
|
|
137
175
|
*/
|
|
138
176
|
updateDeniedRules(rules: string[]): void {
|
|
139
|
-
logger?.debug("Updating denied permission rules", {
|
|
140
|
-
count: rules.length,
|
|
141
|
-
});
|
|
142
177
|
this.deniedRules = rules;
|
|
143
178
|
}
|
|
144
179
|
|
|
@@ -146,10 +181,6 @@ export class PermissionManager {
|
|
|
146
181
|
* Add temporary rules for the current session
|
|
147
182
|
*/
|
|
148
183
|
public addTemporaryRules(rules: string[]): void {
|
|
149
|
-
logger?.debug("Adding temporary permission rules", {
|
|
150
|
-
count: rules.length,
|
|
151
|
-
rules,
|
|
152
|
-
});
|
|
153
184
|
this.temporaryRules.push(...rules);
|
|
154
185
|
}
|
|
155
186
|
|
|
@@ -157,7 +188,6 @@ export class PermissionManager {
|
|
|
157
188
|
* Clear all temporary rules
|
|
158
189
|
*/
|
|
159
190
|
public clearTemporaryRules(): void {
|
|
160
|
-
logger?.debug("Clearing temporary permission rules");
|
|
161
191
|
this.temporaryRules = [];
|
|
162
192
|
}
|
|
163
193
|
|
|
@@ -165,9 +195,6 @@ export class PermissionManager {
|
|
|
165
195
|
* Update the additional directories (e.g., when configuration reloads)
|
|
166
196
|
*/
|
|
167
197
|
updateAdditionalDirectories(directories: string[]): void {
|
|
168
|
-
logger?.debug("Updating additional directories", {
|
|
169
|
-
count: directories.length,
|
|
170
|
-
});
|
|
171
198
|
this.additionalDirectories = directories.map((dir) => {
|
|
172
199
|
if (this.workdir && !path.isAbsolute(dir)) {
|
|
173
200
|
return path.resolve(this.workdir, dir);
|
|
@@ -180,9 +207,6 @@ export class PermissionManager {
|
|
|
180
207
|
* Update the working directory
|
|
181
208
|
*/
|
|
182
209
|
updateWorkdir(workdir: string): void {
|
|
183
|
-
logger?.debug("Updating working directory", {
|
|
184
|
-
workdir,
|
|
185
|
-
});
|
|
186
210
|
this.workdir = workdir;
|
|
187
211
|
}
|
|
188
212
|
|
|
@@ -190,7 +214,6 @@ export class PermissionManager {
|
|
|
190
214
|
* Set the current plan file path
|
|
191
215
|
*/
|
|
192
216
|
public setPlanFilePath(path: string | undefined): void {
|
|
193
|
-
logger?.debug("Setting plan file path", { path });
|
|
194
217
|
this.planFilePath = path;
|
|
195
218
|
}
|
|
196
219
|
|
|
@@ -228,12 +251,6 @@ export class PermissionManager {
|
|
|
228
251
|
}
|
|
229
252
|
}
|
|
230
253
|
|
|
231
|
-
logger?.debug("Path is outside Safe Zone", {
|
|
232
|
-
absolutePath,
|
|
233
|
-
workdir: effectiveWorkdir,
|
|
234
|
-
additionalDirectories: this.additionalDirectories,
|
|
235
|
-
});
|
|
236
|
-
|
|
237
254
|
return { isInside: false, resolvedPath: absolutePath };
|
|
238
255
|
}
|
|
239
256
|
|
|
@@ -252,23 +269,15 @@ export class PermissionManager {
|
|
|
252
269
|
): PermissionMode {
|
|
253
270
|
// CLI override takes highest precedence
|
|
254
271
|
if (cliPermissionMode !== undefined) {
|
|
255
|
-
logger?.debug("Using CLI permission mode override", {
|
|
256
|
-
cliMode: cliPermissionMode,
|
|
257
|
-
configuredDefault: this.configuredDefaultMode,
|
|
258
|
-
});
|
|
259
272
|
return cliPermissionMode;
|
|
260
273
|
}
|
|
261
274
|
|
|
262
275
|
// Use configured default mode if available
|
|
263
276
|
if (this.configuredDefaultMode !== undefined) {
|
|
264
|
-
logger?.debug("Using configured default permission mode", {
|
|
265
|
-
configuredDefault: this.configuredDefaultMode,
|
|
266
|
-
});
|
|
267
277
|
return this.configuredDefaultMode;
|
|
268
278
|
}
|
|
269
279
|
|
|
270
280
|
// Fall back to system default
|
|
271
|
-
logger?.debug("Using system default permission mode");
|
|
272
281
|
return "default";
|
|
273
282
|
}
|
|
274
283
|
|
|
@@ -279,12 +288,6 @@ export class PermissionManager {
|
|
|
279
288
|
async checkPermission(
|
|
280
289
|
context: ToolPermissionContext,
|
|
281
290
|
): Promise<PermissionDecision> {
|
|
282
|
-
logger?.debug("Checking permission for tool", {
|
|
283
|
-
toolName: context.toolName,
|
|
284
|
-
permissionMode: context.permissionMode,
|
|
285
|
-
hasCallback: !!context.canUseToolCallback,
|
|
286
|
-
});
|
|
287
|
-
|
|
288
291
|
// 0. Check denied rules first - Deny always takes precedence
|
|
289
292
|
for (const rule of this.deniedRules) {
|
|
290
293
|
if (this.matchesRule(context, rule)) {
|
|
@@ -301,9 +304,6 @@ export class PermissionManager {
|
|
|
301
304
|
|
|
302
305
|
// 1. If bypassPermissions mode, always allow
|
|
303
306
|
if (context.permissionMode === "bypassPermissions") {
|
|
304
|
-
logger?.debug("Permission bypassed for tool", {
|
|
305
|
-
toolName: context.toolName,
|
|
306
|
-
});
|
|
307
307
|
return { behavior: "allow" };
|
|
308
308
|
}
|
|
309
309
|
|
|
@@ -331,12 +331,6 @@ export class PermissionManager {
|
|
|
331
331
|
);
|
|
332
332
|
// Fall through to normal permission check flow to trigger confirmation prompt
|
|
333
333
|
} else {
|
|
334
|
-
logger?.debug(
|
|
335
|
-
"Permission automatically accepted for tool in acceptEdits mode",
|
|
336
|
-
{
|
|
337
|
-
toolName: context.toolName,
|
|
338
|
-
},
|
|
339
|
-
);
|
|
340
334
|
return { behavior: "allow" };
|
|
341
335
|
}
|
|
342
336
|
}
|
|
@@ -345,9 +339,6 @@ export class PermissionManager {
|
|
|
345
339
|
|
|
346
340
|
// 1.2 Check if tool call is allowed by persistent or temporary rules
|
|
347
341
|
if (this.isAllowedByRule(context)) {
|
|
348
|
-
logger?.debug("Permission allowed by persistent rule", {
|
|
349
|
-
toolName: context.toolName,
|
|
350
|
-
});
|
|
351
342
|
return { behavior: "allow" };
|
|
352
343
|
}
|
|
353
344
|
|
|
@@ -362,10 +353,6 @@ export class PermissionManager {
|
|
|
362
353
|
const absolutePlanPath = path.resolve(this.planFilePath);
|
|
363
354
|
|
|
364
355
|
if (absoluteTargetPath === absolutePlanPath) {
|
|
365
|
-
logger?.debug("Allowing write to plan file in plan mode", {
|
|
366
|
-
toolName: context.toolName,
|
|
367
|
-
targetPath,
|
|
368
|
-
});
|
|
369
356
|
return { behavior: "allow" };
|
|
370
357
|
}
|
|
371
358
|
}
|
|
@@ -379,23 +366,19 @@ export class PermissionManager {
|
|
|
379
366
|
|
|
380
367
|
// 2. If not a restricted tool, always allow
|
|
381
368
|
if (!this.isRestrictedTool(context.toolName)) {
|
|
382
|
-
logger?.debug("Tool is not restricted, allowing", {
|
|
383
|
-
toolName: context.toolName,
|
|
384
|
-
});
|
|
385
369
|
return { behavior: "allow" };
|
|
386
370
|
}
|
|
387
371
|
|
|
388
372
|
// 3. If custom callback provided, call it and return result
|
|
389
373
|
if (context.canUseToolCallback) {
|
|
390
374
|
try {
|
|
391
|
-
logger?.debug("Calling custom permission callback for tool", {
|
|
392
|
-
toolName: context.toolName,
|
|
393
|
-
});
|
|
394
375
|
const decision = await context.canUseToolCallback(context);
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
376
|
+
if (decision.behavior !== "allow") {
|
|
377
|
+
logger?.debug("Custom callback returned decision", {
|
|
378
|
+
toolName: context.toolName,
|
|
379
|
+
decision,
|
|
380
|
+
});
|
|
381
|
+
}
|
|
399
382
|
return decision;
|
|
400
383
|
} catch (error) {
|
|
401
384
|
const errorMessage =
|
|
@@ -429,14 +412,7 @@ export class PermissionManager {
|
|
|
429
412
|
* Determine if a tool requires permission checks based on its name
|
|
430
413
|
*/
|
|
431
414
|
isRestrictedTool(toolName: string): boolean {
|
|
432
|
-
|
|
433
|
-
toolName,
|
|
434
|
-
);
|
|
435
|
-
logger?.debug("Checking if tool is restricted", {
|
|
436
|
-
toolName,
|
|
437
|
-
isRestricted,
|
|
438
|
-
});
|
|
439
|
-
return isRestricted;
|
|
415
|
+
return (RESTRICTED_TOOLS as readonly string[]).includes(toolName);
|
|
440
416
|
}
|
|
441
417
|
|
|
442
418
|
/**
|
|
@@ -521,14 +497,6 @@ export class PermissionManager {
|
|
|
521
497
|
}
|
|
522
498
|
}
|
|
523
499
|
|
|
524
|
-
logger?.debug("Created permission context", {
|
|
525
|
-
toolName,
|
|
526
|
-
permissionMode,
|
|
527
|
-
hasCallback: !!callback,
|
|
528
|
-
hasToolInput: !!toolInput,
|
|
529
|
-
suggestedPrefix,
|
|
530
|
-
});
|
|
531
|
-
|
|
532
500
|
return context;
|
|
533
501
|
}
|
|
534
502
|
|
|
@@ -562,8 +530,9 @@ export class PermissionManager {
|
|
|
562
530
|
const regexPattern = pattern
|
|
563
531
|
.replace(/[.+^${}()|[\]\\?]/g, "\\$&") // Escape regex special chars including ?
|
|
564
532
|
.replace(/\*/g, ".*"); // Replace * with .*
|
|
565
|
-
const regex = new RegExp(`^${regexPattern}
|
|
566
|
-
|
|
533
|
+
const regex = new RegExp(`^${regexPattern}$`, "s");
|
|
534
|
+
const matched = regex.test(processedPart);
|
|
535
|
+
return matched;
|
|
567
536
|
}
|
|
568
537
|
|
|
569
538
|
// Handle path-based rules (e.g., "Read(**/*.env)")
|
|
@@ -649,9 +618,9 @@ export class PermissionManager {
|
|
|
649
618
|
...ctx,
|
|
650
619
|
toolInput: { ...ctx.toolInput, command: processedPart },
|
|
651
620
|
};
|
|
652
|
-
const allowedByRule = rules.some((rule) =>
|
|
653
|
-
this.matchesRule(partContext, rule)
|
|
654
|
-
);
|
|
621
|
+
const allowedByRule = rules.some((rule) => {
|
|
622
|
+
return this.matchesRule(partContext, rule);
|
|
623
|
+
});
|
|
655
624
|
|
|
656
625
|
if (allowedByRule) return true;
|
|
657
626
|
|
|
@@ -669,7 +638,12 @@ export class PermissionManager {
|
|
|
669
638
|
}
|
|
670
639
|
|
|
671
640
|
// Check persistent allowed rules
|
|
672
|
-
|
|
641
|
+
if (isAllowedByRuleList(context, this.allowedRules)) {
|
|
642
|
+
return true;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Check default allowed rules
|
|
646
|
+
return isAllowedByRuleList(context, DEFAULT_ALLOWED_RULES);
|
|
673
647
|
}
|
|
674
648
|
|
|
675
649
|
/**
|
|
@@ -761,4 +735,53 @@ export class PermissionManager {
|
|
|
761
735
|
|
|
762
736
|
return rules;
|
|
763
737
|
}
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Add a persistent permission rule
|
|
741
|
+
* @param rule - The rule to add (e.g., "Bash(ls)")
|
|
742
|
+
*/
|
|
743
|
+
public async addPermissionRule(rule: string): Promise<void> {
|
|
744
|
+
if (!this.workdir) {
|
|
745
|
+
throw new Error("Working directory not set in PermissionManager");
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// 1. Expand rule if it's a Bash command
|
|
749
|
+
let rulesToAdd = [rule];
|
|
750
|
+
const bashMatch = rule.match(/^Bash\((.*)\)$/);
|
|
751
|
+
if (bashMatch) {
|
|
752
|
+
const command = bashMatch[1];
|
|
753
|
+
rulesToAdd = this.expandBashRule(command, this.workdir);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
const configurationService = this.container.get<ConfigurationService>(
|
|
757
|
+
"ConfigurationService",
|
|
758
|
+
);
|
|
759
|
+
|
|
760
|
+
for (const ruleToAdd of rulesToAdd) {
|
|
761
|
+
// 2. Update PermissionManager state
|
|
762
|
+
const currentRules = this.getAllowedRules();
|
|
763
|
+
const defaultRules = this.getDefaultAllowedRules();
|
|
764
|
+
if (
|
|
765
|
+
!currentRules.includes(ruleToAdd) &&
|
|
766
|
+
!defaultRules.includes(ruleToAdd)
|
|
767
|
+
) {
|
|
768
|
+
this.updateAllowedRules([...currentRules, ruleToAdd]);
|
|
769
|
+
|
|
770
|
+
// 3. Persist to settings.local.json
|
|
771
|
+
try {
|
|
772
|
+
if (configurationService) {
|
|
773
|
+
await configurationService.addAllowedRule(this.workdir, ruleToAdd);
|
|
774
|
+
this._logger?.debug("Persistent permission rule added", {
|
|
775
|
+
rule: ruleToAdd,
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
} catch (error) {
|
|
779
|
+
this._logger?.error("Failed to persist permission rule", {
|
|
780
|
+
rule: ruleToAdd,
|
|
781
|
+
error: error instanceof Error ? error.message : String(error),
|
|
782
|
+
});
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
764
787
|
}
|
|
@@ -4,6 +4,9 @@ import os from "node:os";
|
|
|
4
4
|
import { generateRandomName } from "../utils/nameGenerator.js";
|
|
5
5
|
|
|
6
6
|
import { Container } from "../utils/container.js";
|
|
7
|
+
import { MessageManager } from "./messageManager.js";
|
|
8
|
+
import { PermissionManager } from "./permissionManager.js";
|
|
9
|
+
import type { PermissionMode } from "../types/permissions.js";
|
|
7
10
|
|
|
8
11
|
/**
|
|
9
12
|
* Manages plan files for plan mode
|
|
@@ -61,4 +64,27 @@ export class PlanManager {
|
|
|
61
64
|
public getPlanDir(): string {
|
|
62
65
|
return this.planDir;
|
|
63
66
|
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Handle plan mode transition, generating or clearing plan file path
|
|
70
|
+
* @param mode - The current effective permission mode
|
|
71
|
+
*/
|
|
72
|
+
public handlePlanModeTransition(mode: PermissionMode): void {
|
|
73
|
+
const permissionManager =
|
|
74
|
+
this.container.get<PermissionManager>("PermissionManager");
|
|
75
|
+
const messageManager = this.container.get<MessageManager>("MessageManager");
|
|
76
|
+
|
|
77
|
+
if (mode === "plan") {
|
|
78
|
+
this.getOrGeneratePlanFilePath(messageManager?.getRootSessionId())
|
|
79
|
+
.then(({ path }) => {
|
|
80
|
+
logger?.debug("Plan file path generated", { path });
|
|
81
|
+
permissionManager?.setPlanFilePath(path);
|
|
82
|
+
})
|
|
83
|
+
.catch((error) => {
|
|
84
|
+
logger?.error("Failed to generate plan file path", error);
|
|
85
|
+
});
|
|
86
|
+
} else {
|
|
87
|
+
permissionManager?.setPlanFilePath(undefined);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
64
90
|
}
|
|
@@ -11,6 +11,12 @@ import type {
|
|
|
11
11
|
SkillInvocationContext,
|
|
12
12
|
} from "../types/index.js";
|
|
13
13
|
import { parseSkillFile, formatSkillError } from "../utils/skillParser.js";
|
|
14
|
+
import { substituteCommandParameters } from "../utils/commandArgumentParser.js";
|
|
15
|
+
import {
|
|
16
|
+
parseBashCommands,
|
|
17
|
+
replaceBashCommandsWithOutput,
|
|
18
|
+
executeBashCommands,
|
|
19
|
+
} from "../utils/markdownParser.js";
|
|
14
20
|
|
|
15
21
|
import { Container } from "../utils/container.js";
|
|
16
22
|
import { logger } from "../utils/globalLogger.js";
|
|
@@ -94,6 +100,17 @@ export class SkillManager {
|
|
|
94
100
|
return Array.from(this.skillMetadata.values());
|
|
95
101
|
}
|
|
96
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Get metadata for a specific skill by name
|
|
105
|
+
*/
|
|
106
|
+
getSkillMetadata(name: string): SkillMetadata | undefined {
|
|
107
|
+
if (!this.initialized) {
|
|
108
|
+
throw new Error("SkillManager not initialized. Call initialize() first.");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return this.skillMetadata.get(name);
|
|
112
|
+
}
|
|
113
|
+
|
|
97
114
|
/**
|
|
98
115
|
* Load a specific skill by name
|
|
99
116
|
* Returns the skill content that was loaded during initialization
|
|
@@ -176,17 +193,14 @@ export class SkillManager {
|
|
|
176
193
|
|
|
177
194
|
if (parsed.isValid) {
|
|
178
195
|
// Override the skill type with the collection type
|
|
179
|
-
const skillMetadata = {
|
|
196
|
+
const skillMetadata: SkillMetadata = {
|
|
180
197
|
...parsed.skillMetadata,
|
|
181
198
|
type,
|
|
182
199
|
};
|
|
183
200
|
|
|
184
201
|
// Create full skill object with content
|
|
185
202
|
const skill: Skill = {
|
|
186
|
-
|
|
187
|
-
description: parsed.skillMetadata.description,
|
|
188
|
-
type: type, // Use the collection type
|
|
189
|
-
skillPath: parsed.skillMetadata.skillPath,
|
|
203
|
+
...skillMetadata,
|
|
190
204
|
content: parsed.content,
|
|
191
205
|
frontmatter: parsed.frontmatter,
|
|
192
206
|
isValid: parsed.isValid,
|
|
@@ -243,12 +257,14 @@ export class SkillManager {
|
|
|
243
257
|
/**
|
|
244
258
|
* Execute a skill by name
|
|
245
259
|
*/
|
|
246
|
-
async executeSkill(
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
260
|
+
async executeSkill(args: SkillToolArgs): Promise<{
|
|
261
|
+
content: string;
|
|
262
|
+
context?: SkillInvocationContext;
|
|
263
|
+
allowedTools?: string[];
|
|
264
|
+
}> {
|
|
265
|
+
const { skill_name, args: skillArgs } = args;
|
|
250
266
|
|
|
251
|
-
logger?.debug(`Invoking skill: ${skill_name}`);
|
|
267
|
+
logger?.debug(`Invoking skill: ${skill_name} with args: ${skillArgs}`);
|
|
252
268
|
|
|
253
269
|
try {
|
|
254
270
|
// Load the skill
|
|
@@ -267,12 +283,19 @@ export class SkillManager {
|
|
|
267
283
|
};
|
|
268
284
|
}
|
|
269
285
|
|
|
286
|
+
// Process skill content with arguments and bash commands
|
|
287
|
+
const processedContent = await this.processSkillContent(
|
|
288
|
+
skill,
|
|
289
|
+
skillArgs || "",
|
|
290
|
+
);
|
|
291
|
+
|
|
270
292
|
// Return skill content with context
|
|
271
293
|
return {
|
|
272
|
-
content:
|
|
294
|
+
content: processedContent,
|
|
273
295
|
context: {
|
|
274
296
|
skillName: skill_name,
|
|
275
297
|
},
|
|
298
|
+
allowedTools: skill.allowedTools,
|
|
276
299
|
};
|
|
277
300
|
} catch (error) {
|
|
278
301
|
logger?.error(`Failed to execute skill '${skill_name}':`, error);
|
|
@@ -283,16 +306,29 @@ export class SkillManager {
|
|
|
283
306
|
}
|
|
284
307
|
|
|
285
308
|
/**
|
|
286
|
-
*
|
|
309
|
+
* Process skill content with arguments and bash commands
|
|
287
310
|
*/
|
|
288
|
-
private
|
|
311
|
+
private async processSkillContent(
|
|
312
|
+
skill: Skill,
|
|
313
|
+
argsString: string,
|
|
314
|
+
): Promise<string> {
|
|
289
315
|
const header = `🧠 **${skill.name}** (${skill.type} skill)\n\n`;
|
|
290
316
|
const description = `*${skill.description}*\n\n`;
|
|
291
317
|
const skillPath = `📁 Skill location: \`${skill.skillPath}\`\n\n`;
|
|
292
318
|
|
|
293
319
|
// Extract content after frontmatter
|
|
294
320
|
const contentMatch = skill.content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)$/);
|
|
295
|
-
|
|
321
|
+
let mainContent = contentMatch ? contentMatch[1].trim() : skill.content;
|
|
322
|
+
|
|
323
|
+
// 1. Substitute parameters ($1, $ARGUMENTS, etc.)
|
|
324
|
+
mainContent = substituteCommandParameters(mainContent, argsString);
|
|
325
|
+
|
|
326
|
+
// 2. Parse and execute bash commands (!`command`)
|
|
327
|
+
const { commands } = parseBashCommands(mainContent);
|
|
328
|
+
if (commands.length > 0) {
|
|
329
|
+
const results = await executeBashCommands(commands, this.workdir);
|
|
330
|
+
mainContent = replaceBashCommandsWithOutput(mainContent, results);
|
|
331
|
+
}
|
|
296
332
|
|
|
297
333
|
return header + description + skillPath + mainContent;
|
|
298
334
|
}
|
|
@@ -324,6 +360,7 @@ export class SkillManager {
|
|
|
324
360
|
description: skill.description,
|
|
325
361
|
type: skill.type,
|
|
326
362
|
skillPath: skill.skillPath,
|
|
363
|
+
allowedTools: skill.allowedTools,
|
|
327
364
|
});
|
|
328
365
|
this.skillContent.set(skill.name, skill);
|
|
329
366
|
}
|