wave-code 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.
@@ -20,7 +20,6 @@ export declare class WaveAcpAgent implements AcpAgent {
20
20
  cancel(params: CancelNotification): Promise<void>;
21
21
  private getAllowAlwaysName;
22
22
  private handlePermissionRequest;
23
- private getToolContentAsync;
24
23
  private getToolContent;
25
24
  private getToolLocations;
26
25
  private getToolKind;
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/acp/agent.ts"],"names":[],"mappings":"AAmBA,OAAO,EACL,KAAK,KAAK,IAAI,QAAQ,EACtB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EAUzB,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EAClC,KAAK,8BAA8B,EAMpC,MAAM,0BAA0B,CAAC;AAElC,qBAAa,YAAa,YAAW,QAAQ;IAC3C,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,UAAU,CAAsB;gBAE5B,UAAU,EAAE,mBAAmB;IAI3C,OAAO,CAAC,mBAAmB;IAkC3B,OAAO,CAAC,uBAAuB;YAmBjB,gBAAgB;IASxB,UAAU,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAwBzC,YAAY,IAAI,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;YAI5C,WAAW;IAiEnB,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAalE,WAAW,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAWrE,YAAY,CAChB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,oBAAoB,CAAC;IAuB1B,qBAAqB,CACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAc7B,SAAS,CACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAO7B,cAAc,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5D,sBAAsB,CAC1B,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,8BAA8B,CAAC;IAqBpC,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAyDtD,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IASvD,OAAO,CAAC,kBAAkB;YA2BZ,uBAAuB;YAqKvB,mBAAmB;IA6EjC,OAAO,CAAC,cAAc;IA0BtB,OAAO,CAAC,gBAAgB;IAmCxB,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,eAAe;CA+LxB"}
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/acp/agent.ts"],"names":[],"mappings":"AAoBA,OAAO,EACL,KAAK,KAAK,IAAI,QAAQ,EACtB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EAUzB,KAAK,qBAAqB,EAC1B,KAAK,6BAA6B,EAClC,KAAK,8BAA8B,EAMpC,MAAM,0BAA0B,CAAC;AAElC,qBAAa,YAAa,YAAW,QAAQ;IAC3C,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,UAAU,CAAsB;gBAE5B,UAAU,EAAE,mBAAmB;IAI3C,OAAO,CAAC,mBAAmB;IAkC3B,OAAO,CAAC,uBAAuB;YAmBjB,gBAAgB;IASxB,UAAU,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAwBzC,YAAY,IAAI,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;YAI5C,WAAW;IAiEnB,UAAU,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAalE,WAAW,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAWrE,YAAY,CAChB,MAAM,EAAE,mBAAmB,GAC1B,OAAO,CAAC,oBAAoB,CAAC;IAuB1B,qBAAqB,CACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAc7B,SAAS,CACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAO7B,cAAc,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5D,sBAAsB,CAC1B,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,8BAA8B,CAAC;IAqBpC,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAyDtD,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;IASvD,OAAO,CAAC,kBAAkB;YA2BZ,uBAAuB;IA8KrC,OAAO,CAAC,cAAc;IA8FtB,OAAO,CAAC,gBAAgB;IAmCxB,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,eAAe;CAmMxB"}
package/dist/acp/agent.js CHANGED
@@ -1,6 +1,4 @@
1
- import { Agent as WaveAgent, listSessions as listWaveSessions, listAllSessions as listAllWaveSessions, deleteSession as deleteWaveSession, truncateContent, BASH_TOOL_NAME, EDIT_TOOL_NAME, WRITE_TOOL_NAME, EXIT_PLAN_MODE_TOOL_NAME, } from "wave-agent-sdk";
2
- import * as fs from "node:fs/promises";
3
- import * as path from "node:path";
1
+ import { Agent as WaveAgent, listSessions as listWaveSessions, listAllSessions as listAllWaveSessions, deleteSession as deleteWaveSession, truncateContent, BASH_TOOL_NAME, EDIT_TOOL_NAME, WRITE_TOOL_NAME, EXIT_PLAN_MODE_TOOL_NAME, ASK_USER_QUESTION_TOOL_NAME, } from "wave-agent-sdk";
4
2
  import { logger } from "../utils/logger.js";
5
3
  import { AGENT_METHODS, } from "@agentclientprotocol/sdk";
6
4
  export class WaveAcpAgent {
@@ -304,7 +302,6 @@ export class WaveAcpAgent {
304
302
  async handlePermissionRequest(sessionId, context) {
305
303
  logger.info(`Handling permission request for ${context.toolName} in session ${sessionId}`);
306
304
  const agent = this.agents.get(sessionId);
307
- const workdir = agent?.workingDirectory || process.cwd();
308
305
  const toolCallId = context.toolCallId ||
309
306
  "perm-" + Math.random().toString(36).substring(2, 9);
310
307
  let effectiveName = context.toolName;
@@ -369,8 +366,11 @@ export class WaveAcpAgent {
369
366
  },
370
367
  ];
371
368
  }
369
+ else if (context.toolName === ASK_USER_QUESTION_TOOL_NAME) {
370
+ options = [];
371
+ }
372
372
  const content = context.toolName
373
- ? await this.getToolContentAsync(context.toolName, context.toolInput, workdir)
373
+ ? this.getToolContent(context.toolName, context.toolInput, undefined, context.planContent)
374
374
  : undefined;
375
375
  const locations = context.toolName
376
376
  ? this.getToolLocations(context.toolName, context.toolInput)
@@ -395,6 +395,12 @@ export class WaveAcpAgent {
395
395
  if (response.outcome.outcome === "cancelled") {
396
396
  return { behavior: "deny", message: "Cancelled by user" };
397
397
  }
398
+ if (context.toolName === ASK_USER_QUESTION_TOOL_NAME) {
399
+ return {
400
+ behavior: "allow",
401
+ message: response.message,
402
+ };
403
+ }
398
404
  const selectedOptionId = response.outcome.optionId;
399
405
  logger.info(`User selected permission option: ${selectedOptionId}`);
400
406
  switch (selectedOptionId) {
@@ -438,96 +444,81 @@ export class WaveAcpAgent {
438
444
  };
439
445
  }
440
446
  }
441
- async getToolContentAsync(name, parameters, workdir) {
442
- if (!parameters)
443
- return undefined;
444
- if (name === "Write") {
445
- let oldText = null;
446
- try {
447
- const filePath = (parameters.file_path ||
448
- parameters.filePath);
449
- const fullPath = path.isAbsolute(filePath)
450
- ? filePath
451
- : path.join(workdir, filePath);
452
- oldText = await fs.readFile(fullPath, "utf-8");
453
- }
454
- catch {
455
- // File might not exist, which is fine for Write
456
- }
457
- return [
458
- {
459
- type: "diff",
460
- path: (parameters.file_path || parameters.filePath),
461
- oldText,
462
- newText: parameters.content,
463
- },
464
- ];
465
- }
466
- if (name === "Edit") {
467
- let oldText = null;
468
- let newText = null;
469
- try {
470
- const filePath = (parameters.file_path ||
471
- parameters.filePath);
472
- const fullPath = path.isAbsolute(filePath)
473
- ? filePath
474
- : path.join(workdir, filePath);
475
- oldText = await fs.readFile(fullPath, "utf-8");
476
- if (oldText) {
477
- if (parameters.replace_all) {
478
- newText = oldText
479
- .split(parameters.old_string)
480
- .join(parameters.new_string);
481
- }
482
- else {
483
- newText = oldText.replace(parameters.old_string, parameters.new_string);
484
- }
485
- }
486
- }
487
- catch {
488
- logger.error("Failed to read file for Edit diff");
489
- }
490
- if (oldText && newText) {
491
- return [
492
- {
493
- type: "diff",
494
- path: (parameters.file_path || parameters.filePath),
495
- oldText,
496
- newText,
497
- },
498
- ];
499
- }
500
- // Fallback to snippets if file reading fails
501
- return [
502
- {
503
- type: "diff",
504
- path: (parameters.file_path || parameters.filePath),
505
- oldText: parameters.old_string,
506
- newText: parameters.new_string,
507
- },
508
- ];
509
- }
510
- return this.getToolContent(name, parameters);
511
- }
512
- getToolContent(name, parameters) {
447
+ getToolContent(name, parameters, shortResult, planContent) {
513
448
  const contents = [];
514
449
  if (parameters) {
515
- if (name === "Write") {
450
+ if (name === WRITE_TOOL_NAME &&
451
+ typeof parameters.file_path === "string" &&
452
+ typeof parameters.content === "string") {
516
453
  contents.push({
517
454
  type: "diff",
518
- path: (parameters.file_path || parameters.filePath),
455
+ path: parameters.file_path,
519
456
  oldText: null,
520
457
  newText: parameters.content,
521
458
  });
522
459
  }
523
- else if (name === "Edit") {
460
+ else if (name === EDIT_TOOL_NAME &&
461
+ typeof parameters.file_path === "string" &&
462
+ typeof parameters.old_string === "string" &&
463
+ typeof parameters.new_string === "string") {
524
464
  contents.push({
525
465
  type: "diff",
526
- path: (parameters.file_path || parameters.filePath),
466
+ path: parameters.file_path,
527
467
  oldText: parameters.old_string,
528
468
  newText: parameters.new_string,
529
469
  });
530
470
  }
471
+ else if (name === BASH_TOOL_NAME &&
472
+ typeof parameters.command === "string") {
473
+ contents.push({
474
+ type: "content",
475
+ content: {
476
+ type: "text",
477
+ text: "**Command:**\n```bash\n" + parameters.command + "\n```",
478
+ },
479
+ });
480
+ }
481
+ else if (name === EXIT_PLAN_MODE_TOOL_NAME && planContent) {
482
+ contents.push({
483
+ type: "content",
484
+ content: {
485
+ type: "text",
486
+ text: planContent,
487
+ },
488
+ });
489
+ }
490
+ else if (name === ASK_USER_QUESTION_TOOL_NAME &&
491
+ Array.isArray(parameters.questions)) {
492
+ const markdown = parameters.questions
493
+ .map((q, i) => {
494
+ let text = `### Question ${i + 1}\n${q.question}\n`;
495
+ if (Array.isArray(q.options)) {
496
+ text += q.options
497
+ .map((opt) => `- ${opt.label}${opt.description ? `: ${opt.description}` : ""}`)
498
+ .join("\n");
499
+ }
500
+ return text;
501
+ })
502
+ .join("\n\n");
503
+ contents.push({
504
+ type: "content",
505
+ content: {
506
+ type: "text",
507
+ text: markdown,
508
+ },
509
+ });
510
+ }
511
+ }
512
+ if (shortResult) {
513
+ contents.push({
514
+ type: "content",
515
+ content: {
516
+ type: "text",
517
+ text: name === BASH_TOOL_NAME
518
+ ? "```\n" + shortResult + "\n```"
519
+ : shortResult,
520
+ },
521
+ });
531
522
  }
532
523
  return contents.length > 0 ? contents : undefined;
533
524
  }
@@ -640,7 +631,7 @@ export class WaveAcpAgent {
640
631
  }
641
632
  }
642
633
  const content = effectiveName && (parsedParameters || effectiveShortResult)
643
- ? this.getToolContent(effectiveName, parsedParameters)
634
+ ? this.getToolContent(effectiveName, parsedParameters, effectiveShortResult)
644
635
  : undefined;
645
636
  const locations = effectiveName && parsedParameters
646
637
  ? this.getToolLocations(effectiveName, parsedParameters, effectiveStartLineNumber)
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAatE,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAyKjC,CAAC"}
1
+ {"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAatE,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EA0KjC,CAAC"}
@@ -77,5 +77,5 @@ export const ChatInterface = () => {
77
77
  return null;
78
78
  return (_jsxs(Box, { flexDirection: "column", children: [_jsx(MessageList, { messages: displayMessages, isExpanded: isExpanded, forceStatic: isConfirmationVisible && isConfirmationTooTall, version: version, workdir: workdir, model: model, onDynamicBlocksHeightMeasured: handleDynamicBlocksHeightMeasured }), (isLoading || isCommandRunning || isCompressing) &&
79
79
  !isConfirmationVisible &&
80
- !isExpanded && (_jsx(LoadingIndicator, { isLoading: isLoading, isCommandRunning: isCommandRunning, isCompressing: isCompressing, latestTotalTokens: latestTotalTokens })), !isConfirmationVisible && !isExpanded && _jsx(TaskList, {}), isConfirmationVisible && (_jsxs(_Fragment, { children: [_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, isExpanded: isExpanded, onHeightMeasured: handleDetailsHeightMeasured, isStatic: isConfirmationTooTall }), _jsx(ConfirmationSelector, { toolName: confirmingTool.name, toolInput: confirmingTool.input, suggestedPrefix: confirmingTool.suggestedPrefix, hidePersistentOption: confirmingTool.hidePersistentOption, isExpanded: isExpanded, onDecision: wrappedHandleConfirmationDecision, onCancel: handleConfirmationCancel, onAbort: abortMessage, onHeightMeasured: handleSelectorHeightMeasured })] })), !isConfirmationVisible && !isExpanded && (_jsxs(_Fragment, { children: [_jsx(QueuedMessageList, {}), _jsx(InputBox, { isLoading: isLoading, isCommandRunning: isCommandRunning, sendMessage: sendMessage, abortMessage: abortMessage, mcpServers: mcpServers, connectMcpServer: connectMcpServer, disconnectMcpServer: disconnectMcpServer, slashCommands: slashCommands, hasSlashCommand: hasSlashCommand })] }))] }));
80
+ !isExpanded && (_jsx(LoadingIndicator, { isLoading: isLoading, isCommandRunning: isCommandRunning, isCompressing: isCompressing, latestTotalTokens: latestTotalTokens })), !isConfirmationVisible && !isExpanded && _jsx(TaskList, {}), isConfirmationVisible && (_jsxs(_Fragment, { children: [_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, planContent: confirmingTool.planContent, isExpanded: isExpanded, onHeightMeasured: handleDetailsHeightMeasured, isStatic: isConfirmationTooTall }), _jsx(ConfirmationSelector, { toolName: confirmingTool.name, toolInput: confirmingTool.input, suggestedPrefix: confirmingTool.suggestedPrefix, hidePersistentOption: confirmingTool.hidePersistentOption, isExpanded: isExpanded, onDecision: wrappedHandleConfirmationDecision, onCancel: handleConfirmationCancel, onAbort: abortMessage, onHeightMeasured: handleSelectorHeightMeasured })] })), !isConfirmationVisible && !isExpanded && (_jsxs(_Fragment, { children: [_jsx(QueuedMessageList, {}), _jsx(InputBox, { isLoading: isLoading, isCommandRunning: isCommandRunning, sendMessage: sendMessage, abortMessage: abortMessage, mcpServers: mcpServers, connectMcpServer: connectMcpServer, disconnectMcpServer: disconnectMcpServer, slashCommands: slashCommands, hasSlashCommand: hasSlashCommand })] }))] }));
81
81
  };
@@ -2,6 +2,7 @@ import React from "react";
2
2
  export interface ConfirmationDetailsProps {
3
3
  toolName: string;
4
4
  toolInput?: Record<string, unknown>;
5
+ planContent?: string;
5
6
  isExpanded?: boolean;
6
7
  onHeightMeasured?: (height: number) => void;
7
8
  isStatic?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmationDetails.d.ts","sourceRoot":"","sources":["../../src/components/ConfirmationDetails.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkC,MAAM,OAAO,CAAC;AAqCvD,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA8DlE,CAAC"}
1
+ {"version":3,"file":"ConfirmationDetails.d.ts","sourceRoot":"","sources":["../../src/components/ConfirmationDetails.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkC,MAAM,OAAO,CAAC;AAqCvD,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA4DlE,CAAC"}
@@ -24,7 +24,7 @@ const getActionDescription = (toolName, toolInput) => {
24
24
  return "Execute operation";
25
25
  }
26
26
  };
27
- export const ConfirmationDetails = ({ toolName, toolInput, isExpanded = false, onHeightMeasured, isStatic = false, }) => {
27
+ export const ConfirmationDetails = ({ toolName, toolInput, planContent, isExpanded = false, onHeightMeasured, isStatic = false, }) => {
28
28
  const { stdout } = useStdout();
29
29
  const boxRef = useRef(null);
30
30
  const startLineNumber = toolInput?.startLineNumber ??
@@ -37,7 +37,7 @@ export const ConfirmationDetails = ({ toolName, toolInput, isExpanded = false, o
37
37
  }, [stdout?.rows, onHeightMeasured, toolInput, isExpanded]);
38
38
  const content = (_jsxs(Box, { ref: boxRef, flexDirection: "column", borderStyle: "single", borderColor: "yellow", borderBottom: false, borderLeft: false, borderRight: false, children: [_jsxs(Text, { color: "yellow", bold: true, children: ["Tool: ", toolName] }), _jsx(Text, { color: "yellow", children: getActionDescription(toolName, toolInput) }), _jsx(DiffDisplay, { toolName: toolName, parameters: JSON.stringify(toolInput), startLineNumber: startLineNumber }), toolName !== ASK_USER_QUESTION_TOOL_NAME &&
39
39
  toolName === EXIT_PLAN_MODE_TOOL_NAME &&
40
- !!toolInput?.plan_content && (_jsx(PlanDisplay, { plan: toolInput.plan_content, isExpanded: isExpanded }))] }));
40
+ !!planContent && (_jsx(PlanDisplay, { plan: planContent, isExpanded: isExpanded }))] }));
41
41
  if (isStatic) {
42
42
  return (_jsx(Static, { items: [1], children: (item) => _jsx(React.Fragment, { children: content }, item) }));
43
43
  }
@@ -48,8 +48,9 @@ export interface ChatContextType {
48
48
  input?: Record<string, unknown>;
49
49
  suggestedPrefix?: string;
50
50
  hidePersistentOption?: boolean;
51
+ planContent?: string;
51
52
  };
52
- showConfirmation: (toolName: string, toolInput?: Record<string, unknown>, suggestedPrefix?: string, hidePersistentOption?: boolean) => Promise<PermissionDecision>;
53
+ showConfirmation: (toolName: string, toolInput?: Record<string, unknown>, suggestedPrefix?: string, hidePersistentOption?: boolean, planContent?: string) => Promise<PermissionDecision>;
53
54
  hideConfirmation: () => void;
54
55
  handleConfirmationDecision: (decision: PermissionDecision) => void;
55
56
  handleConfirmationCancel: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/contexts/useChat.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useChat.d.ts","sourceRoot":"","sources":["../../src/contexts/useChat.tsx"],"names":[],"mappings":"AAAA,OAAO,KAON,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EACV,OAAO,EACP,eAAe,EACf,cAAc,EACd,IAAI,EACJ,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACf,MAAM,gBAAgB,CAAC;AAWxB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IAEvB,UAAU,EAAE,OAAO,CAAC;IACpB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,oBAAoB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,cAAc,EAAE,KAAK,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QACnD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACtC,CAAC,CAAC;IAEH,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,CACX,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,EAClD,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KACjC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAE1B,UAAU,EAAE,eAAe,EAAE,CAAC;IAC9B,gBAAgB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3D,mBAAmB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAE9D,eAAe,EAAE,cAAc,EAAE,CAAC;IAElC,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,uBAAuB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK;QAC3C,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,GAAG,IAAI,CAAC;IACT,kBAAkB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAEhD,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;IAEhD,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5C,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE7C,cAAc,EAAE,cAAc,CAAC;IAC/B,iBAAiB,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAElD,qBAAqB,EAAE,OAAO,CAAC;IAC/B,cAAc,CAAC,EAAE;QACf,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;QAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,gBAAgB,EAAE,CAChB,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,eAAe,CAAC,EAAE,MAAM,EACxB,oBAAoB,CAAC,EAAE,OAAO,EAC9B,WAAW,CAAC,EAAE,MAAM,KACjB,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACjC,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,0BAA0B,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACnE,wBAAwB,EAAE,MAAM,IAAI,CAAC;IAErC,qBAAqB,EAAE,MAAM,IAAI,CAAC;IAElC,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,oBAAoB,EAAE,MAAM,OAAO,CAAC;QAClC,QAAQ,EAAE,OAAO,EAAE,CAAC;QACpB,UAAU,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC,CAAC;IACH,qBAAqB,EAAE,MAAM,CAAC;IAC9B,wBAAwB,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IAEvE,gBAAgB,EAAE,MAAM,OAAO,gBAAgB,EAAE,aAAa,CAAC;IAC/D,cAAc,EAAE,MAAM,OAAO,gBAAgB,EAAE,WAAW,CAAC;IAC3D,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,eAAO,MAAM,OAAO,uBAMnB,CAAC;AAEF,MAAM,WAAW,iBAAkB,SAAQ,YAAY;IACrD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA+kBpD,CAAC"}
@@ -68,13 +68,14 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
68
68
  }, 100);
69
69
  }, [setTasks]);
70
70
  // Permission confirmation methods with queue support
71
- const showConfirmation = useCallback(async (toolName, toolInput, suggestedPrefix, hidePersistentOption) => {
71
+ const showConfirmation = useCallback(async (toolName, toolInput, suggestedPrefix, hidePersistentOption, planContent) => {
72
72
  return new Promise((resolve, reject) => {
73
73
  const queueItem = {
74
74
  toolName,
75
75
  toolInput,
76
76
  suggestedPrefix,
77
77
  hidePersistentOption,
78
+ planContent,
78
79
  resolver: resolve,
79
80
  reject,
80
81
  };
@@ -132,7 +133,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
132
133
  ? undefined
133
134
  : async (context) => {
134
135
  try {
135
- return await showConfirmation(context.toolName, context.toolInput, context.suggestedPrefix, context.hidePersistentOption);
136
+ return await showConfirmation(context.toolName, context.toolInput, context.suggestedPrefix, context.hidePersistentOption, context.planContent);
136
137
  }
137
138
  catch {
138
139
  // If confirmation was cancelled or failed, deny the operation
@@ -323,6 +324,7 @@ export const ChatProvider = ({ children, bypassPermissions, permissionMode: init
323
324
  input: next.toolInput,
324
325
  suggestedPrefix: next.suggestedPrefix,
325
326
  hidePersistentOption: next.hidePersistentOption,
327
+ planContent: next.planContent,
326
328
  });
327
329
  setIsConfirmationVisible(true);
328
330
  setConfirmationQueue((prev) => prev.slice(1));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-code",
3
- "version": "0.11.3",
3
+ "version": "0.11.5",
4
4
  "description": "CLI-based code assistant powered by AI, built with React and Ink",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,7 +29,7 @@
29
29
  "README.md"
30
30
  ],
31
31
  "dependencies": {
32
- "@agentclientprotocol/sdk": "0.17.0",
32
+ "@agentclientprotocol/sdk": "0.17.1",
33
33
  "chalk": "^5.6.2",
34
34
  "diff": "^8.0.2",
35
35
  "glob": "^13.0.0",
@@ -41,7 +41,7 @@
41
41
  "react-dom": "19.2.4",
42
42
  "yargs": "^17.7.2",
43
43
  "zod": "^3.23.8",
44
- "wave-agent-sdk": "0.11.3"
44
+ "wave-agent-sdk": "0.11.5"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@types/react": "^19.1.8",
package/src/acp/agent.ts CHANGED
@@ -13,9 +13,10 @@ import {
13
13
  EDIT_TOOL_NAME,
14
14
  WRITE_TOOL_NAME,
15
15
  EXIT_PLAN_MODE_TOOL_NAME,
16
+ ASK_USER_QUESTION_TOOL_NAME,
17
+ AskUserQuestion,
18
+ AskUserQuestionOption,
16
19
  } from "wave-agent-sdk";
17
- import * as fs from "node:fs/promises";
18
- import * as path from "node:path";
19
20
  import { logger } from "../utils/logger.js";
20
21
  import {
21
22
  type Agent as AcpAgent,
@@ -427,7 +428,6 @@ export class WaveAcpAgent implements AcpAgent {
427
428
  );
428
429
 
429
430
  const agent = this.agents.get(sessionId);
430
- const workdir = agent?.workingDirectory || process.cwd();
431
431
 
432
432
  const toolCallId =
433
433
  context.toolCallId ||
@@ -502,13 +502,16 @@ export class WaveAcpAgent implements AcpAgent {
502
502
  kind: "allow_always",
503
503
  },
504
504
  ];
505
+ } else if (context.toolName === ASK_USER_QUESTION_TOOL_NAME) {
506
+ options = [];
505
507
  }
506
508
 
507
509
  const content = context.toolName
508
- ? await this.getToolContentAsync(
510
+ ? this.getToolContent(
509
511
  context.toolName,
510
512
  context.toolInput,
511
- workdir,
513
+ undefined,
514
+ context.planContent,
512
515
  )
513
516
  : undefined;
514
517
  const locations = context.toolName
@@ -537,6 +540,13 @@ export class WaveAcpAgent implements AcpAgent {
537
540
  return { behavior: "deny", message: "Cancelled by user" };
538
541
  }
539
542
 
543
+ if (context.toolName === ASK_USER_QUESTION_TOOL_NAME) {
544
+ return {
545
+ behavior: "allow",
546
+ message: (response as unknown as { message?: string }).message,
547
+ };
548
+ }
549
+
540
550
  const selectedOptionId = response.outcome.optionId;
541
551
  logger.info(`User selected permission option: ${selectedOptionId}`);
542
552
 
@@ -583,106 +593,97 @@ export class WaveAcpAgent implements AcpAgent {
583
593
  }
584
594
  }
585
595
 
586
- private async getToolContentAsync(
587
- name: string,
588
- parameters: Record<string, unknown> | undefined,
589
- workdir: string,
590
- ): Promise<ToolCallContent[] | undefined> {
591
- if (!parameters) return undefined;
592
- if (name === "Write") {
593
- let oldText: string | null = null;
594
- try {
595
- const filePath = (parameters.file_path ||
596
- parameters.filePath) as string;
597
- const fullPath = path.isAbsolute(filePath)
598
- ? filePath
599
- : path.join(workdir, filePath);
600
- oldText = await fs.readFile(fullPath, "utf-8");
601
- } catch {
602
- // File might not exist, which is fine for Write
603
- }
604
- return [
605
- {
606
- type: "diff",
607
- path: (parameters.file_path || parameters.filePath) as string,
608
- oldText,
609
- newText: parameters.content as string,
610
- },
611
- ];
612
- }
613
- if (name === "Edit") {
614
- let oldText: string | null = null;
615
- let newText: string | null = null;
616
- try {
617
- const filePath = (parameters.file_path ||
618
- parameters.filePath) as string;
619
- const fullPath = path.isAbsolute(filePath)
620
- ? filePath
621
- : path.join(workdir, filePath);
622
- oldText = await fs.readFile(fullPath, "utf-8");
623
- if (oldText) {
624
- if (parameters.replace_all) {
625
- newText = oldText
626
- .split(parameters.old_string as string)
627
- .join(parameters.new_string as string);
628
- } else {
629
- newText = oldText.replace(
630
- parameters.old_string as string,
631
- parameters.new_string as string,
632
- );
633
- }
634
- }
635
- } catch {
636
- logger.error("Failed to read file for Edit diff");
637
- }
638
-
639
- if (oldText && newText) {
640
- return [
641
- {
642
- type: "diff",
643
- path: (parameters.file_path || parameters.filePath) as string,
644
- oldText,
645
- newText,
646
- },
647
- ];
648
- }
649
-
650
- // Fallback to snippets if file reading fails
651
- return [
652
- {
653
- type: "diff",
654
- path: (parameters.file_path || parameters.filePath) as string,
655
- oldText: parameters.old_string as string,
656
- newText: parameters.new_string as string,
657
- },
658
- ];
659
- }
660
- return this.getToolContent(name, parameters);
661
- }
662
-
663
596
  private getToolContent(
664
597
  name: string,
665
598
  parameters: Record<string, unknown> | undefined,
599
+ shortResult: string | undefined,
600
+ planContent?: string,
666
601
  ): ToolCallContent[] | undefined {
667
602
  const contents: ToolCallContent[] = [];
668
603
  if (parameters) {
669
- if (name === "Write") {
604
+ if (
605
+ name === WRITE_TOOL_NAME &&
606
+ typeof parameters.file_path === "string" &&
607
+ typeof parameters.content === "string"
608
+ ) {
670
609
  contents.push({
671
610
  type: "diff",
672
- path: (parameters.file_path || parameters.filePath) as string,
611
+ path: parameters.file_path,
673
612
  oldText: null,
674
- newText: parameters.content as string,
613
+ newText: parameters.content,
675
614
  });
676
- } else if (name === "Edit") {
615
+ } else if (
616
+ name === EDIT_TOOL_NAME &&
617
+ typeof parameters.file_path === "string" &&
618
+ typeof parameters.old_string === "string" &&
619
+ typeof parameters.new_string === "string"
620
+ ) {
677
621
  contents.push({
678
622
  type: "diff",
679
- path: (parameters.file_path || parameters.filePath) as string,
680
- oldText: parameters.old_string as string,
681
- newText: parameters.new_string as string,
623
+ path: parameters.file_path,
624
+ oldText: parameters.old_string,
625
+ newText: parameters.new_string,
626
+ });
627
+ } else if (
628
+ name === BASH_TOOL_NAME &&
629
+ typeof parameters.command === "string"
630
+ ) {
631
+ contents.push({
632
+ type: "content",
633
+ content: {
634
+ type: "text",
635
+ text: "**Command:**\n```bash\n" + parameters.command + "\n```",
636
+ },
637
+ });
638
+ } else if (name === EXIT_PLAN_MODE_TOOL_NAME && planContent) {
639
+ contents.push({
640
+ type: "content",
641
+ content: {
642
+ type: "text",
643
+ text: planContent,
644
+ },
645
+ });
646
+ } else if (
647
+ name === ASK_USER_QUESTION_TOOL_NAME &&
648
+ Array.isArray(parameters.questions)
649
+ ) {
650
+ const markdown = (parameters.questions as AskUserQuestion[])
651
+ .map((q, i) => {
652
+ let text = `### Question ${i + 1}\n${q.question}\n`;
653
+ if (Array.isArray(q.options)) {
654
+ text += q.options
655
+ .map(
656
+ (opt: AskUserQuestionOption) =>
657
+ `- ${opt.label}${opt.description ? `: ${opt.description}` : ""}`,
658
+ )
659
+ .join("\n");
660
+ }
661
+ return text;
662
+ })
663
+ .join("\n\n");
664
+ contents.push({
665
+ type: "content",
666
+ content: {
667
+ type: "text",
668
+ text: markdown,
669
+ },
682
670
  });
683
671
  }
684
672
  }
685
673
 
674
+ if (shortResult) {
675
+ contents.push({
676
+ type: "content",
677
+ content: {
678
+ type: "text",
679
+ text:
680
+ name === BASH_TOOL_NAME
681
+ ? "```\n" + shortResult + "\n```"
682
+ : shortResult,
683
+ },
684
+ });
685
+ }
686
+
686
687
  return contents.length > 0 ? contents : undefined;
687
688
  }
688
689
 
@@ -828,7 +829,11 @@ export class WaveAcpAgent implements AcpAgent {
828
829
 
829
830
  const content =
830
831
  effectiveName && (parsedParameters || effectiveShortResult)
831
- ? this.getToolContent(effectiveName, parsedParameters)
832
+ ? this.getToolContent(
833
+ effectiveName,
834
+ parsedParameters,
835
+ effectiveShortResult,
836
+ )
832
837
  : undefined;
833
838
  const locations =
834
839
  effectiveName && parsedParameters
@@ -144,6 +144,7 @@ export const ChatInterface: React.FC = () => {
144
144
  <ConfirmationDetails
145
145
  toolName={confirmingTool!.name}
146
146
  toolInput={confirmingTool!.input}
147
+ planContent={confirmingTool!.planContent}
147
148
  isExpanded={isExpanded}
148
149
  onHeightMeasured={handleDetailsHeightMeasured}
149
150
  isStatic={isConfirmationTooTall}
@@ -38,6 +38,7 @@ const getActionDescription = (
38
38
  export interface ConfirmationDetailsProps {
39
39
  toolName: string;
40
40
  toolInput?: Record<string, unknown>;
41
+ planContent?: string;
41
42
  isExpanded?: boolean;
42
43
  onHeightMeasured?: (height: number) => void;
43
44
  isStatic?: boolean;
@@ -46,6 +47,7 @@ export interface ConfirmationDetailsProps {
46
47
  export const ConfirmationDetails: React.FC<ConfirmationDetailsProps> = ({
47
48
  toolName,
48
49
  toolInput,
50
+ planContent,
49
51
  isExpanded = false,
50
52
  onHeightMeasured,
51
53
  isStatic = false,
@@ -87,11 +89,8 @@ export const ConfirmationDetails: React.FC<ConfirmationDetailsProps> = ({
87
89
 
88
90
  {toolName !== ASK_USER_QUESTION_TOOL_NAME &&
89
91
  toolName === EXIT_PLAN_MODE_TOOL_NAME &&
90
- !!toolInput?.plan_content && (
91
- <PlanDisplay
92
- plan={toolInput.plan_content as string}
93
- isExpanded={isExpanded}
94
- />
92
+ !!planContent && (
93
+ <PlanDisplay plan={planContent} isExpanded={isExpanded} />
95
94
  )}
96
95
  </Box>
97
96
  );
@@ -84,12 +84,14 @@ export interface ChatContextType {
84
84
  input?: Record<string, unknown>;
85
85
  suggestedPrefix?: string;
86
86
  hidePersistentOption?: boolean;
87
+ planContent?: string;
87
88
  };
88
89
  showConfirmation: (
89
90
  toolName: string,
90
91
  toolInput?: Record<string, unknown>,
91
92
  suggestedPrefix?: string,
92
93
  hidePersistentOption?: boolean,
94
+ planContent?: string,
93
95
  ) => Promise<PermissionDecision>;
94
96
  hideConfirmation: () => void;
95
97
  handleConfirmationDecision: (decision: PermissionDecision) => void;
@@ -202,6 +204,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
202
204
  input?: Record<string, unknown>;
203
205
  suggestedPrefix?: string;
204
206
  hidePersistentOption?: boolean;
207
+ planContent?: string;
205
208
  }
206
209
  | undefined
207
210
  >();
@@ -211,6 +214,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
211
214
  toolInput?: Record<string, unknown>;
212
215
  suggestedPrefix?: string;
213
216
  hidePersistentOption?: boolean;
217
+ planContent?: string;
214
218
  resolver: (decision: PermissionDecision) => void;
215
219
  reject: () => void;
216
220
  }>
@@ -220,6 +224,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
220
224
  toolInput?: Record<string, unknown>;
221
225
  suggestedPrefix?: string;
222
226
  hidePersistentOption?: boolean;
227
+ planContent?: string;
223
228
  resolver: (decision: PermissionDecision) => void;
224
229
  reject: () => void;
225
230
  } | null>(null);
@@ -256,6 +261,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
256
261
  toolInput?: Record<string, unknown>,
257
262
  suggestedPrefix?: string,
258
263
  hidePersistentOption?: boolean,
264
+ planContent?: string,
259
265
  ): Promise<PermissionDecision> => {
260
266
  return new Promise<PermissionDecision>((resolve, reject) => {
261
267
  const queueItem = {
@@ -263,6 +269,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
263
269
  toolInput,
264
270
  suggestedPrefix,
265
271
  hidePersistentOption,
272
+ planContent,
266
273
  resolver: resolve,
267
274
  reject,
268
275
  };
@@ -335,6 +342,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
335
342
  context.toolInput,
336
343
  context.suggestedPrefix,
337
344
  context.hidePersistentOption,
345
+ context.planContent,
338
346
  );
339
347
  } catch {
340
348
  // If confirmation was cancelled or failed, deny the operation
@@ -554,6 +562,7 @@ export const ChatProvider: React.FC<ChatProviderProps> = ({
554
562
  input: next.toolInput,
555
563
  suggestedPrefix: next.suggestedPrefix,
556
564
  hidePersistentOption: next.hidePersistentOption,
565
+ planContent: next.planContent,
557
566
  });
558
567
  setIsConfirmationVisible(true);
559
568
  setConfirmationQueue((prev) => prev.slice(1));