wave-agent-sdk 0.11.3 → 0.11.5
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/managers/backgroundTaskManager.js +3 -3
- package/dist/managers/mcpManager.d.ts.map +1 -1
- package/dist/managers/mcpManager.js +4 -1
- package/dist/managers/permissionManager.d.ts +1 -1
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +37 -4
- package/dist/tools/exitPlanMode.d.ts.map +1 -1
- package/dist/tools/exitPlanMode.js +1 -3
- package/dist/types/permissions.d.ts +2 -0
- package/dist/types/permissions.d.ts.map +1 -1
- package/dist/utils/bashParser.d.ts +4 -0
- package/dist/utils/bashParser.d.ts.map +1 -1
- package/dist/utils/bashParser.js +11 -0
- package/package.json +1 -1
- package/src/managers/backgroundTaskManager.ts +3 -3
- package/src/managers/mcpManager.ts +4 -1
- package/src/managers/permissionManager.ts +40 -2
- package/src/tools/exitPlanMode.ts +2 -3
- package/src/types/permissions.ts +2 -0
- package/src/utils/bashParser.ts +13 -0
|
@@ -16,7 +16,7 @@ export class BackgroundTaskManager {
|
|
|
16
16
|
this.callbacks.onBackgroundTasksChange?.(Array.from(this.tasks.values()));
|
|
17
17
|
}
|
|
18
18
|
generateId() {
|
|
19
|
-
return `task_${this.nextId++}`;
|
|
19
|
+
return `task_${process.pid}_${this.nextId++}`;
|
|
20
20
|
}
|
|
21
21
|
addTask(task) {
|
|
22
22
|
this.tasks.set(task.id, task);
|
|
@@ -41,7 +41,7 @@ export class BackgroundTaskManager {
|
|
|
41
41
|
});
|
|
42
42
|
// Create log file
|
|
43
43
|
const logPath = path.join(os.tmpdir(), `wave-task-${id}.log`);
|
|
44
|
-
const logStream = fs.createWriteStream(logPath, { flags: "
|
|
44
|
+
const logStream = fs.createWriteStream(logPath, { flags: "w" });
|
|
45
45
|
const shell = {
|
|
46
46
|
id,
|
|
47
47
|
type: "shell",
|
|
@@ -156,7 +156,7 @@ export class BackgroundTaskManager {
|
|
|
156
156
|
const startTime = Date.now();
|
|
157
157
|
// Create log file
|
|
158
158
|
const logPath = path.join(os.tmpdir(), `wave-task-${id}.log`);
|
|
159
|
-
const logStream = fs.createWriteStream(logPath, { flags: "
|
|
159
|
+
const logStream = fs.createWriteStream(logPath, { flags: "w" });
|
|
160
160
|
// Write initial output to log file
|
|
161
161
|
if (initialStdout) {
|
|
162
162
|
logStream.write(stripAnsiColors(initialStdout));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcpManager.d.ts","sourceRoot":"","sources":["../../src/managers/mcpManager.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAEjE,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EACV,MAAM,EACN,eAAe,EACf,SAAS,EACT,OAAO,EACP,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAQ3B,MAAM,WAAW,mBAAmB;IAClC,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;CACxD;AAID,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,UAAU;IASnB,OAAO,CAAC,SAAS;IARnB,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,OAAO,CAA2C;IAC1D,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,SAAS,CAAsB;gBAG7B,SAAS,EAAE,SAAS,EAC5B,OAAO,GAAE,iBAAsB;IAKjC;;OAEG;IACG,UAAU,CACd,OAAO,EAAE,MAAM,EACf,WAAW,GAAE,OAAe,GAC3B,OAAO,CAAC,IAAI,CAAC;IAwCV,kBAAkB,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAO/C,UAAU,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IA0CvC,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAWrD,SAAS,IAAI,SAAS,GAAG,IAAI;IAI7B,aAAa,IAAI,eAAe,EAAE;IAIlC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAIpD,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IASzE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO;IAyBzD,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAgB7B,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"mcpManager.d.ts","sourceRoot":"","sources":["../../src/managers/mcpManager.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAEjE,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EACV,MAAM,EACN,eAAe,EACf,SAAS,EACT,OAAO,EACP,eAAe,EAChB,MAAM,mBAAmB,CAAC;AAQ3B,MAAM,WAAW,mBAAmB;IAClC,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;CACxD;AAID,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,UAAU;IASnB,OAAO,CAAC,SAAS;IARnB,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,OAAO,CAA2C;IAC1D,OAAO,CAAC,WAAW,CAAyC;IAC5D,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,SAAS,CAAsB;gBAG7B,SAAS,EAAE,SAAS,EAC5B,OAAO,GAAE,iBAAsB;IAKjC;;OAEG;IACG,UAAU,CACd,OAAO,EAAE,MAAM,EACf,WAAW,GAAE,OAAe,GAC3B,OAAO,CAAC,IAAI,CAAC;IAwCV,kBAAkB,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAO/C,UAAU,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IA0CvC,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;IAWrD,SAAS,IAAI,SAAS,GAAG,IAAI;IAI7B,aAAa,IAAI,eAAe,EAAE;IAIlC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAIpD,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI;IASzE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO;IAyBzD,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAgB7B,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA+F7C,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA2BtD,oBAAoB,IAAI,OAAO,EAAE;IAW3B,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,MAAM,CAAC,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACtD,CAAC;YAsDY,uBAAuB;IA8D/B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B;;OAEG;IACH,iBAAiB,IAAI,UAAU,EAAE;IA6BjC;;OAEG;IACH,iBAAiB,IAAI,0BAA0B,EAAE;IAIjD;;OAEG;IACG,wBAAwB,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC;IActB;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAcjC"}
|
|
@@ -168,7 +168,10 @@ export class McpManager {
|
|
|
168
168
|
const transport = new StdioClientTransport({
|
|
169
169
|
command: server.config.command,
|
|
170
170
|
args: server.config.args || [],
|
|
171
|
-
env:
|
|
171
|
+
env: {
|
|
172
|
+
...process.env,
|
|
173
|
+
...(server.config.env || {}),
|
|
174
|
+
},
|
|
172
175
|
cwd: this.workdir, // Use the agent's workdir as the process working directory
|
|
173
176
|
});
|
|
174
177
|
// Create client
|
|
@@ -145,7 +145,7 @@ export declare class PermissionManager {
|
|
|
145
145
|
/**
|
|
146
146
|
* Helper method to create a permission context for CLI integration
|
|
147
147
|
*/
|
|
148
|
-
createContext(toolName: string, permissionMode: PermissionMode, callback?: PermissionCallback, toolInput?: Record<string, unknown>, toolCallId?: string): ToolPermissionContext;
|
|
148
|
+
createContext(toolName: string, permissionMode: PermissionMode, callback?: PermissionCallback, toolInput?: Record<string, unknown>, toolCallId?: string, planContent?: string): ToolPermissionContext;
|
|
149
149
|
/**
|
|
150
150
|
* Check if a tool call matches a specific permission rule
|
|
151
151
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissionManager.d.ts","sourceRoot":"","sources":["../../src/managers/permissionManager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EACV,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,cAAc,EACf,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"permissionManager.d.ts","sourceRoot":"","sources":["../../src/managers/permissionManager.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import path from "node:path";
|
|
9
9
|
import { minimatch } from "minimatch";
|
|
10
10
|
import { RESTRICTED_TOOLS } from "../types/permissions.js";
|
|
11
|
-
import { splitBashCommand, stripEnvVars, stripRedirections, hasWriteRedirections, getSmartPrefix, DANGEROUS_COMMANDS, } from "../utils/bashParser.js";
|
|
11
|
+
import { splitBashCommand, stripEnvVars, stripRedirections, hasWriteRedirections, isBashWriteRedirect, getSmartPrefix, DANGEROUS_COMMANDS, } from "../utils/bashParser.js";
|
|
12
12
|
import { isPathInside } from "../utils/pathSafety.js";
|
|
13
13
|
import { BASH_TOOL_NAME, EDIT_TOOL_NAME, WRITE_TOOL_NAME, READ_TOOL_NAME, } from "../constants/tools.js";
|
|
14
14
|
const SAFE_COMMANDS = [
|
|
@@ -23,6 +23,7 @@ const SAFE_COMMANDS = [
|
|
|
23
23
|
"head",
|
|
24
24
|
"tail",
|
|
25
25
|
"wc",
|
|
26
|
+
"sleep",
|
|
26
27
|
];
|
|
27
28
|
const DEFAULT_ALLOWED_RULES = [
|
|
28
29
|
"Bash(git status*)",
|
|
@@ -63,6 +64,7 @@ const DEFAULT_ALLOWED_RULES = [
|
|
|
63
64
|
"Bash(head*)",
|
|
64
65
|
"Bash(tail*)",
|
|
65
66
|
"Bash(wc*)",
|
|
67
|
+
"Bash(sleep*)",
|
|
66
68
|
];
|
|
67
69
|
import { logger } from "../utils/globalLogger.js";
|
|
68
70
|
export class PermissionManager {
|
|
@@ -264,6 +266,34 @@ export class PermissionManager {
|
|
|
264
266
|
* Called by individual tools after validation/diff, before real operation
|
|
265
267
|
*/
|
|
266
268
|
async checkPermission(context) {
|
|
269
|
+
// 0. Intercept Bash file writing operations
|
|
270
|
+
if (context.toolName === BASH_TOOL_NAME && context.toolInput?.command) {
|
|
271
|
+
const command = String(context.toolInput.command);
|
|
272
|
+
if (isBashWriteRedirect(command)) {
|
|
273
|
+
// Check if this specific command is explicitly allowed by a rule that includes redirection
|
|
274
|
+
const isExplicitlyAllowed = [
|
|
275
|
+
...this.instanceAllowedRules,
|
|
276
|
+
...this.temporaryRules,
|
|
277
|
+
...this.allowedRules,
|
|
278
|
+
...DEFAULT_ALLOWED_RULES,
|
|
279
|
+
].some((rule) => {
|
|
280
|
+
if (rule.startsWith("Bash(") && rule.endsWith(")")) {
|
|
281
|
+
const pattern = rule.substring(5, rule.length - 1);
|
|
282
|
+
// If the pattern itself has write redirections, we check if it matches
|
|
283
|
+
if (hasWriteRedirections(pattern)) {
|
|
284
|
+
return this.matchesRule(context, rule);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return false;
|
|
288
|
+
});
|
|
289
|
+
if (!isExplicitlyAllowed) {
|
|
290
|
+
return {
|
|
291
|
+
behavior: "deny",
|
|
292
|
+
message: "Bash-based file writing operations (e.g., using '>', '>>', or 'cat <<EOF > file') are not allowed. Please use the dedicated 'Write' or 'Edit' tools instead for file modifications.",
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
267
297
|
// 0. Check instance-specific denied rules first - Deny always takes precedence
|
|
268
298
|
for (const rule of this.instanceDeniedRules) {
|
|
269
299
|
if (this.matchesRule(context, rule)) {
|
|
@@ -463,7 +493,7 @@ export class PermissionManager {
|
|
|
463
493
|
/**
|
|
464
494
|
* Helper method to create a permission context for CLI integration
|
|
465
495
|
*/
|
|
466
|
-
createContext(toolName, permissionMode, callback, toolInput, toolCallId) {
|
|
496
|
+
createContext(toolName, permissionMode, callback, toolInput, toolCallId, planContent) {
|
|
467
497
|
let suggestedPrefix;
|
|
468
498
|
if (toolName === BASH_TOOL_NAME && toolInput?.command) {
|
|
469
499
|
const command = String(toolInput.command);
|
|
@@ -484,6 +514,7 @@ export class PermissionManager {
|
|
|
484
514
|
toolInput,
|
|
485
515
|
suggestedPrefix,
|
|
486
516
|
toolCallId,
|
|
517
|
+
planContent,
|
|
487
518
|
};
|
|
488
519
|
// Set hidePersistentOption for out-of-bounds file operations
|
|
489
520
|
const fileTools = [EDIT_TOOL_NAME, WRITE_TOOL_NAME];
|
|
@@ -626,7 +657,8 @@ export class PermissionManager {
|
|
|
626
657
|
cmd === "cat" ||
|
|
627
658
|
cmd === "head" ||
|
|
628
659
|
cmd === "tail" ||
|
|
629
|
-
cmd === "wc"
|
|
660
|
+
cmd === "wc" ||
|
|
661
|
+
cmd === "sleep") {
|
|
630
662
|
return true;
|
|
631
663
|
}
|
|
632
664
|
if (workdir) {
|
|
@@ -714,7 +746,8 @@ export class PermissionManager {
|
|
|
714
746
|
cmd === "cat" ||
|
|
715
747
|
cmd === "head" ||
|
|
716
748
|
cmd === "tail" ||
|
|
717
|
-
cmd === "wc"
|
|
749
|
+
cmd === "wc" ||
|
|
750
|
+
cmd === "sleep") {
|
|
718
751
|
isSafe = true;
|
|
719
752
|
}
|
|
720
753
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exitPlanMode.d.ts","sourceRoot":"","sources":["../../src/tools/exitPlanMode.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAItE;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,
|
|
1
|
+
{"version":3,"file":"exitPlanMode.d.ts","sourceRoot":"","sources":["../../src/tools/exitPlanMode.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAItE;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,UAoH9B,CAAC"}
|
|
@@ -73,9 +73,7 @@ Ensure your plan is complete and unambiguous:
|
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
75
|
// Permission check triggers the 3-option UI
|
|
76
|
-
const permissionContext = context.permissionManager.createContext(EXIT_PLAN_MODE_TOOL_NAME, context.permissionMode || "plan", context.canUseToolCallback, {
|
|
77
|
-
plan_content: planContent,
|
|
78
|
-
}, context.toolCallId);
|
|
76
|
+
const permissionContext = context.permissionManager.createContext(EXIT_PLAN_MODE_TOOL_NAME, context.permissionMode || "plan", context.canUseToolCallback, {}, context.toolCallId, planContent);
|
|
79
77
|
const permissionResult = await context.permissionManager.checkPermission(permissionContext);
|
|
80
78
|
if (permissionResult.behavior === "deny") {
|
|
81
79
|
if (permissionResult.message === OPERATION_CANCELLED_BY_USER) {
|
|
@@ -36,6 +36,8 @@ export interface ToolPermissionContext {
|
|
|
36
36
|
hidePersistentOption?: boolean;
|
|
37
37
|
/** The ID of the tool call that triggered this permission request */
|
|
38
38
|
toolCallId?: string;
|
|
39
|
+
/** The content of the plan being exited from */
|
|
40
|
+
planContent?: string;
|
|
39
41
|
}
|
|
40
42
|
/** List of tools that require permission checks in default mode */
|
|
41
43
|
export declare const RESTRICTED_TOOLS: readonly ["Edit", "Bash", "Write", "ExitPlanMode", "AskUserQuestion"];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/types/permissions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AASpB,oCAAoC;AACpC,MAAM,MAAM,cAAc,GACtB,SAAS,GACT,mBAAmB,GACnB,aAAa,GACb,MAAM,GACN,SAAS,CAAC;AAEd,mCAAmC;AACnC,MAAM,WAAW,kBAAkB;IACjC,6CAA6C;IAC7C,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,iBAAiB,CAAC,EAAE,cAAc,CAAC;IACnC,2CAA2C;IAC3C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yEAAyE;IACzE,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,oDAAoD;AACpD,MAAM,MAAM,kBAAkB,GAAG,CAC/B,OAAO,EAAE,qBAAqB,KAC3B,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAEjC,mDAAmD;AACnD,MAAM,WAAW,qBAAqB;IACpC,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,cAAc,EAAE,cAAc,CAAC;IAC/B,6CAA6C;IAC7C,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,yCAAyC;IACzC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2FAA2F;IAC3F,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["../../src/types/permissions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AASpB,oCAAoC;AACpC,MAAM,MAAM,cAAc,GACtB,SAAS,GACT,mBAAmB,GACnB,aAAa,GACb,MAAM,GACN,SAAS,CAAC;AAEd,mCAAmC;AACnC,MAAM,WAAW,kBAAkB;IACjC,6CAA6C;IAC7C,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,iBAAiB,CAAC,EAAE,cAAc,CAAC;IACnC,2CAA2C;IAC3C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,yEAAyE;IACzE,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,oDAAoD;AACpD,MAAM,MAAM,kBAAkB,GAAG,CAC/B,OAAO,EAAE,qBAAqB,KAC3B,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAEjC,mDAAmD;AACnD,MAAM,WAAW,qBAAqB;IACpC,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,cAAc,EAAE,cAAc,CAAC;IAC/B,6CAA6C;IAC7C,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,yCAAyC;IACzC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,2FAA2F;IAC3F,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,mEAAmE;AACnE,eAAO,MAAM,gBAAgB,uEAMnB,CAAC;AAEX,qCAAqC;AACrC,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/D,eAAO,MAAM,2BAA2B,gCAAgC,CAAC;AAEzE,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,CAAC"}
|
|
@@ -15,6 +15,10 @@ export declare function stripRedirections(command: string): string;
|
|
|
15
15
|
* Checks if a bash command contains any write redirections (>, >>, &>, 2>, >|).
|
|
16
16
|
*/
|
|
17
17
|
export declare function hasWriteRedirections(command: string): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Alias for hasWriteRedirections, used for semantic clarity in permission checks.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isBashWriteRedirect(command: string): boolean;
|
|
18
22
|
/**
|
|
19
23
|
* Blacklist of dangerous commands that should not be safely prefix-matched
|
|
20
24
|
* and should not have persistent permissions.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bashParser.d.ts","sourceRoot":"","sources":["../../src/utils/bashParser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAmH1D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA2CpD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAuHzD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,
|
|
1
|
+
{"version":3,"file":"bashParser.d.ts","sourceRoot":"","sources":["../../src/utils/bashParser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAmH1D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA2CpD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAuHzD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAkG7D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,UAa9B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA8L7D"}
|
package/dist/utils/bashParser.js
CHANGED
|
@@ -350,11 +350,22 @@ export function hasWriteRedirections(command) {
|
|
|
350
350
|
i = k - 1; // Move the main loop index to the end of the target
|
|
351
351
|
continue;
|
|
352
352
|
}
|
|
353
|
+
// Ignore file descriptor redirections like 2>&1, >&2, etc.
|
|
354
|
+
if (target.startsWith("&") && /^\d+$/.test(target.substring(1))) {
|
|
355
|
+
i = k - 1;
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
353
358
|
return true;
|
|
354
359
|
}
|
|
355
360
|
}
|
|
356
361
|
return false;
|
|
357
362
|
}
|
|
363
|
+
/**
|
|
364
|
+
* Alias for hasWriteRedirections, used for semantic clarity in permission checks.
|
|
365
|
+
*/
|
|
366
|
+
export function isBashWriteRedirect(command) {
|
|
367
|
+
return hasWriteRedirections(command);
|
|
368
|
+
}
|
|
358
369
|
/**
|
|
359
370
|
* Blacklist of dangerous commands that should not be safely prefix-matched
|
|
360
371
|
* and should not have persistent permissions.
|
package/package.json
CHANGED
|
@@ -35,7 +35,7 @@ export class BackgroundTaskManager {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
public generateId(): string {
|
|
38
|
-
return `task_${this.nextId++}`;
|
|
38
|
+
return `task_${process.pid}_${this.nextId++}`;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
public addTask(task: BackgroundTask): void {
|
|
@@ -69,7 +69,7 @@ export class BackgroundTaskManager {
|
|
|
69
69
|
|
|
70
70
|
// Create log file
|
|
71
71
|
const logPath = path.join(os.tmpdir(), `wave-task-${id}.log`);
|
|
72
|
-
const logStream = fs.createWriteStream(logPath, { flags: "
|
|
72
|
+
const logStream = fs.createWriteStream(logPath, { flags: "w" });
|
|
73
73
|
|
|
74
74
|
const shell: BackgroundShell = {
|
|
75
75
|
id,
|
|
@@ -198,7 +198,7 @@ export class BackgroundTaskManager {
|
|
|
198
198
|
|
|
199
199
|
// Create log file
|
|
200
200
|
const logPath = path.join(os.tmpdir(), `wave-task-${id}.log`);
|
|
201
|
-
const logStream = fs.createWriteStream(logPath, { flags: "
|
|
201
|
+
const logStream = fs.createWriteStream(logPath, { flags: "w" });
|
|
202
202
|
|
|
203
203
|
// Write initial output to log file
|
|
204
204
|
if (initialStdout) {
|
|
@@ -228,7 +228,10 @@ export class McpManager {
|
|
|
228
228
|
const transport = new StdioClientTransport({
|
|
229
229
|
command: server.config.command,
|
|
230
230
|
args: server.config.args || [],
|
|
231
|
-
env:
|
|
231
|
+
env: {
|
|
232
|
+
...(process.env as Record<string, string>),
|
|
233
|
+
...(server.config.env || {}),
|
|
234
|
+
},
|
|
232
235
|
cwd: this.workdir, // Use the agent's workdir as the process working directory
|
|
233
236
|
});
|
|
234
237
|
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
stripEnvVars,
|
|
22
22
|
stripRedirections,
|
|
23
23
|
hasWriteRedirections,
|
|
24
|
+
isBashWriteRedirect,
|
|
24
25
|
getSmartPrefix,
|
|
25
26
|
DANGEROUS_COMMANDS,
|
|
26
27
|
} from "../utils/bashParser.js";
|
|
@@ -46,6 +47,7 @@ const SAFE_COMMANDS = [
|
|
|
46
47
|
"head",
|
|
47
48
|
"tail",
|
|
48
49
|
"wc",
|
|
50
|
+
"sleep",
|
|
49
51
|
];
|
|
50
52
|
|
|
51
53
|
const DEFAULT_ALLOWED_RULES = [
|
|
@@ -87,6 +89,7 @@ const DEFAULT_ALLOWED_RULES = [
|
|
|
87
89
|
"Bash(head*)",
|
|
88
90
|
"Bash(tail*)",
|
|
89
91
|
"Bash(wc*)",
|
|
92
|
+
"Bash(sleep*)",
|
|
90
93
|
];
|
|
91
94
|
|
|
92
95
|
import { logger } from "../utils/globalLogger.js";
|
|
@@ -367,6 +370,37 @@ export class PermissionManager {
|
|
|
367
370
|
async checkPermission(
|
|
368
371
|
context: ToolPermissionContext,
|
|
369
372
|
): Promise<PermissionDecision> {
|
|
373
|
+
// 0. Intercept Bash file writing operations
|
|
374
|
+
if (context.toolName === BASH_TOOL_NAME && context.toolInput?.command) {
|
|
375
|
+
const command = String(context.toolInput.command);
|
|
376
|
+
if (isBashWriteRedirect(command)) {
|
|
377
|
+
// Check if this specific command is explicitly allowed by a rule that includes redirection
|
|
378
|
+
const isExplicitlyAllowed = [
|
|
379
|
+
...this.instanceAllowedRules,
|
|
380
|
+
...this.temporaryRules,
|
|
381
|
+
...this.allowedRules,
|
|
382
|
+
...DEFAULT_ALLOWED_RULES,
|
|
383
|
+
].some((rule) => {
|
|
384
|
+
if (rule.startsWith("Bash(") && rule.endsWith(")")) {
|
|
385
|
+
const pattern = rule.substring(5, rule.length - 1);
|
|
386
|
+
// If the pattern itself has write redirections, we check if it matches
|
|
387
|
+
if (hasWriteRedirections(pattern)) {
|
|
388
|
+
return this.matchesRule(context, rule);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return false;
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
if (!isExplicitlyAllowed) {
|
|
395
|
+
return {
|
|
396
|
+
behavior: "deny",
|
|
397
|
+
message:
|
|
398
|
+
"Bash-based file writing operations (e.g., using '>', '>>', or 'cat <<EOF > file') are not allowed. Please use the dedicated 'Write' or 'Edit' tools instead for file modifications.",
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
370
404
|
// 0. Check instance-specific denied rules first - Deny always takes precedence
|
|
371
405
|
for (const rule of this.instanceDeniedRules) {
|
|
372
406
|
if (this.matchesRule(context, rule)) {
|
|
@@ -616,6 +650,7 @@ export class PermissionManager {
|
|
|
616
650
|
callback?: PermissionCallback,
|
|
617
651
|
toolInput?: Record<string, unknown>,
|
|
618
652
|
toolCallId?: string,
|
|
653
|
+
planContent?: string,
|
|
619
654
|
): ToolPermissionContext {
|
|
620
655
|
let suggestedPrefix: string | undefined;
|
|
621
656
|
if (toolName === BASH_TOOL_NAME && toolInput?.command) {
|
|
@@ -637,6 +672,7 @@ export class PermissionManager {
|
|
|
637
672
|
toolInput,
|
|
638
673
|
suggestedPrefix,
|
|
639
674
|
toolCallId,
|
|
675
|
+
planContent,
|
|
640
676
|
};
|
|
641
677
|
|
|
642
678
|
// Set hidePersistentOption for out-of-bounds file operations
|
|
@@ -814,7 +850,8 @@ export class PermissionManager {
|
|
|
814
850
|
cmd === "cat" ||
|
|
815
851
|
cmd === "head" ||
|
|
816
852
|
cmd === "tail" ||
|
|
817
|
-
cmd === "wc"
|
|
853
|
+
cmd === "wc" ||
|
|
854
|
+
cmd === "sleep"
|
|
818
855
|
) {
|
|
819
856
|
return true;
|
|
820
857
|
}
|
|
@@ -927,7 +964,8 @@ export class PermissionManager {
|
|
|
927
964
|
cmd === "cat" ||
|
|
928
965
|
cmd === "head" ||
|
|
929
966
|
cmd === "tail" ||
|
|
930
|
-
cmd === "wc"
|
|
967
|
+
cmd === "wc" ||
|
|
968
|
+
cmd === "sleep"
|
|
931
969
|
) {
|
|
932
970
|
isSafe = true;
|
|
933
971
|
} else {
|
|
@@ -85,10 +85,9 @@ Ensure your plan is complete and unambiguous:
|
|
|
85
85
|
EXIT_PLAN_MODE_TOOL_NAME,
|
|
86
86
|
context.permissionMode || "plan",
|
|
87
87
|
context.canUseToolCallback,
|
|
88
|
-
{
|
|
89
|
-
plan_content: planContent,
|
|
90
|
-
},
|
|
88
|
+
{},
|
|
91
89
|
context.toolCallId,
|
|
90
|
+
planContent,
|
|
92
91
|
);
|
|
93
92
|
|
|
94
93
|
const permissionResult =
|
package/src/types/permissions.ts
CHANGED
|
@@ -59,6 +59,8 @@ export interface ToolPermissionContext {
|
|
|
59
59
|
hidePersistentOption?: boolean;
|
|
60
60
|
/** The ID of the tool call that triggered this permission request */
|
|
61
61
|
toolCallId?: string;
|
|
62
|
+
/** The content of the plan being exited from */
|
|
63
|
+
planContent?: string;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
/** List of tools that require permission checks in default mode */
|
package/src/utils/bashParser.ts
CHANGED
|
@@ -381,6 +381,12 @@ export function hasWriteRedirections(command: string): boolean {
|
|
|
381
381
|
continue;
|
|
382
382
|
}
|
|
383
383
|
|
|
384
|
+
// Ignore file descriptor redirections like 2>&1, >&2, etc.
|
|
385
|
+
if (target.startsWith("&") && /^\d+$/.test(target.substring(1))) {
|
|
386
|
+
i = k - 1;
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
|
|
384
390
|
return true;
|
|
385
391
|
}
|
|
386
392
|
}
|
|
@@ -388,6 +394,13 @@ export function hasWriteRedirections(command: string): boolean {
|
|
|
388
394
|
return false;
|
|
389
395
|
}
|
|
390
396
|
|
|
397
|
+
/**
|
|
398
|
+
* Alias for hasWriteRedirections, used for semantic clarity in permission checks.
|
|
399
|
+
*/
|
|
400
|
+
export function isBashWriteRedirect(command: string): boolean {
|
|
401
|
+
return hasWriteRedirections(command);
|
|
402
|
+
}
|
|
403
|
+
|
|
391
404
|
/**
|
|
392
405
|
* Blacklist of dangerous commands that should not be safely prefix-matched
|
|
393
406
|
* and should not have persistent permissions.
|