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.
@@ -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: "a" });
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: "a" });
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;IA4F7C,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"}
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: server.config.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":"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"}
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,UAqH9B,CAAC"}
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;CACrB;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"}
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,CA4F7D;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,UAa9B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA8L7D"}
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"}
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-agent-sdk",
3
- "version": "0.11.3",
3
+ "version": "0.11.5",
4
4
  "description": "SDK for building AI-powered development tools and agents",
5
5
  "keywords": [
6
6
  "ai",
@@ -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: "a" });
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: "a" });
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: server.config.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 =
@@ -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 */
@@ -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.