wave-code 0.10.4 → 0.11.1

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.
Files changed (57) hide show
  1. package/dist/acp/agent.d.ts +1 -0
  2. package/dist/acp/agent.d.ts.map +1 -1
  3. package/dist/acp/agent.js +122 -18
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +2 -2
  6. package/dist/components/App.d.ts.map +1 -1
  7. package/dist/components/App.js +4 -4
  8. package/dist/components/BackgroundTaskManager.d.ts.map +1 -1
  9. package/dist/components/BackgroundTaskManager.js +3 -2
  10. package/dist/components/ChatInterface.d.ts.map +1 -1
  11. package/dist/components/ChatInterface.js +2 -1
  12. package/dist/components/ConfirmationDetails.d.ts.map +1 -1
  13. package/dist/components/ConfirmationDetails.js +2 -2
  14. package/dist/components/ConfirmationSelector.d.ts.map +1 -1
  15. package/dist/components/ConfirmationSelector.js +20 -4
  16. package/dist/components/InputBox.d.ts +1 -1
  17. package/dist/components/InputBox.d.ts.map +1 -1
  18. package/dist/components/InputBox.js +1 -2
  19. package/dist/components/MessageList.d.ts +2 -1
  20. package/dist/components/MessageList.d.ts.map +1 -1
  21. package/dist/components/MessageList.js +18 -17
  22. package/dist/constants/commands.d.ts.map +1 -1
  23. package/dist/constants/commands.js +0 -6
  24. package/dist/contexts/useChat.d.ts +3 -2
  25. package/dist/contexts/useChat.d.ts.map +1 -1
  26. package/dist/contexts/useChat.js +32 -28
  27. package/dist/hooks/useInputManager.d.ts.map +1 -1
  28. package/dist/hooks/useInputManager.js +4 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +40 -1
  31. package/dist/managers/inputHandlers.d.ts.map +1 -1
  32. package/dist/managers/inputHandlers.js +7 -8
  33. package/dist/managers/inputReducer.d.ts +2 -3
  34. package/dist/managers/inputReducer.d.ts.map +1 -1
  35. package/dist/managers/inputReducer.js +4 -4
  36. package/dist/print-cli.d.ts.map +1 -1
  37. package/dist/print-cli.js +5 -3
  38. package/dist/types.d.ts +2 -0
  39. package/dist/types.d.ts.map +1 -1
  40. package/package.json +2 -2
  41. package/src/acp/agent.ts +147 -21
  42. package/src/cli.tsx +4 -0
  43. package/src/components/App.tsx +8 -0
  44. package/src/components/BackgroundTaskManager.tsx +17 -1
  45. package/src/components/ChatInterface.tsx +4 -1
  46. package/src/components/ConfirmationDetails.tsx +5 -1
  47. package/src/components/ConfirmationSelector.tsx +18 -4
  48. package/src/components/InputBox.tsx +1 -2
  49. package/src/components/MessageList.tsx +21 -18
  50. package/src/constants/commands.ts +0 -6
  51. package/src/contexts/useChat.tsx +49 -35
  52. package/src/hooks/useInputManager.ts +4 -1
  53. package/src/index.ts +43 -1
  54. package/src/managers/inputHandlers.ts +8 -10
  55. package/src/managers/inputReducer.ts +6 -6
  56. package/src/print-cli.ts +6 -2
  57. package/src/types.ts +2 -0
@@ -18,6 +18,7 @@ export declare class WaveAcpAgent implements AcpAgent {
18
18
  setSessionConfigOption(params: SetSessionConfigOptionRequest): Promise<SetSessionConfigOptionResponse>;
19
19
  prompt(params: PromptRequest): Promise<PromptResponse>;
20
20
  cancel(params: CancelNotification): Promise<void>;
21
+ private getAllowAlwaysName;
21
22
  private handlePermissionRequest;
22
23
  private getToolContentAsync;
23
24
  private getToolContent;
@@ -1 +1 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/acp/agent.ts"],"names":[],"mappings":"AAeA,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,EAEpC,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;IA4B3B,OAAO,CAAC,uBAAuB;YAkBjB,gBAAgB;IASxB,UAAU,IAAI,OAAO,CAAC,kBAAkB,CAAC;IAoBzC,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;IAS5D,sBAAsB,CAC1B,MAAM,EAAE,6BAA6B,GACpC,OAAO,CAAC,8BAA8B,CAAC;IAgBpC,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAiDtD,MAAM,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC;YASzC,uBAAuB;YAgHvB,mBAAmB;IA6EjC,OAAO,CAAC,cAAc;IAqCtB,OAAO,CAAC,gBAAgB;IAmCxB,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,eAAe;CAgMxB"}
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;YAsKvB,mBAAmB;IA6EjC,OAAO,CAAC,cAAc;IA6CtB,OAAO,CAAC,gBAAgB;IAmCxB,OAAO,CAAC,WAAW;IAmBnB,OAAO,CAAC,eAAe;CAgMxB"}
package/dist/acp/agent.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Agent as WaveAgent, listSessions as listWaveSessions, listAllSessions as listAllWaveSessions, deleteSession as deleteWaveSession, truncateContent, } from "wave-agent-sdk";
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
2
  import * as fs from "node:fs/promises";
3
3
  import * as path from "node:path";
4
4
  import { logger } from "../utils/logger.js";
@@ -32,6 +32,11 @@ export class WaveAcpAgent {
32
32
  name: "Bypass Permissions",
33
33
  description: "Automatically accept all tool calls",
34
34
  },
35
+ {
36
+ id: "dontAsk",
37
+ name: "Don't Ask",
38
+ description: "Automatically deny restricted tools unless pre-approved",
39
+ },
35
40
  ],
36
41
  };
37
42
  }
@@ -48,6 +53,7 @@ export class WaveAcpAgent {
48
53
  { value: "acceptEdits", name: "Accept Edits" },
49
54
  { value: "plan", name: "Plan" },
50
55
  { value: "bypassPermissions", name: "Bypass Permissions" },
56
+ { value: "dontAsk", name: "Don't Ask" },
51
57
  ],
52
58
  },
53
59
  ];
@@ -74,6 +80,10 @@ export class WaveAcpAgent {
74
80
  list: {},
75
81
  close: {},
76
82
  },
83
+ promptCapabilities: {
84
+ image: true,
85
+ embeddedContext: true,
86
+ },
77
87
  },
78
88
  };
79
89
  }
@@ -86,7 +96,7 @@ export class WaveAcpAgent {
86
96
  const agent = await WaveAgent.create({
87
97
  workdir: cwd,
88
98
  restoreSessionId: sessionId,
89
- stream: false,
99
+ stream: true,
90
100
  canUseTool: (context) => {
91
101
  if (!agentRef.instance) {
92
102
  throw new Error("Agent instance not yet initialized");
@@ -210,27 +220,39 @@ export class WaveAcpAgent {
210
220
  async prompt(params) {
211
221
  const { sessionId, prompt } = params;
212
222
  logger.info(`Received prompt for session ${sessionId}`);
223
+ logger.debug(`Prompt content for session ${sessionId}:`, prompt);
213
224
  const agent = this.agents.get(sessionId);
214
225
  if (!agent) {
215
226
  logger.error(`Session ${sessionId} not found`);
216
227
  throw new Error(`Session ${sessionId} not found`);
217
228
  }
218
229
  // Map ACP prompt to Wave Agent sendMessage
219
- const textContent = prompt
220
- .filter((block) => block.type === "text")
221
- .map((block) => block.text)
222
- .join("\n");
223
- const images = prompt
224
- .filter((block) => block.type === "image")
225
- .map((block) => {
226
- const img = block;
227
- return {
228
- path: `data:${img.mimeType};base64,${img.data}`,
229
- mimeType: img.mimeType,
230
- };
231
- });
230
+ const textBlocks = [];
231
+ const images = [];
232
+ for (const block of prompt) {
233
+ if (block.type === "text") {
234
+ textBlocks.push(block.text);
235
+ }
236
+ else if (block.type === "resource_link") {
237
+ const link = block;
238
+ textBlocks.push(`[${link.name}](${link.uri})`);
239
+ }
240
+ else if (block.type === "resource") {
241
+ const embedded = block;
242
+ textBlocks.push(`[Resource](${embedded.resource.uri})`);
243
+ }
244
+ else if (block.type === "image") {
245
+ const img = block;
246
+ images.push({
247
+ path: img.data.startsWith("data:")
248
+ ? img.data
249
+ : `data:${img.mimeType};base64,${img.data}`,
250
+ mimeType: img.mimeType,
251
+ });
252
+ }
253
+ }
254
+ const textContent = textBlocks.join("");
232
255
  try {
233
- logger.info(`Sending message to agent: ${textContent.substring(0, 50)}...`);
234
256
  await agent.sendMessage(textContent, images.length > 0 ? images : undefined);
235
257
  logger.info(`Message sent successfully for session ${sessionId}`);
236
258
  return {
@@ -256,6 +278,29 @@ export class WaveAcpAgent {
256
278
  agent.abortMessage();
257
279
  }
258
280
  }
281
+ getAllowAlwaysName(context) {
282
+ if (context.toolName === BASH_TOOL_NAME) {
283
+ const command = context.toolInput?.command || "";
284
+ if (command.startsWith("mkdir")) {
285
+ return "Yes, and auto-accept edits";
286
+ }
287
+ if (context.suggestedPrefix) {
288
+ const prefix = context.suggestedPrefix.length > 12
289
+ ? context.suggestedPrefix.substring(0, 9) + "..."
290
+ : context.suggestedPrefix;
291
+ return `Yes, always allow ${prefix}`;
292
+ }
293
+ return "Yes, always allow this command";
294
+ }
295
+ if (context.toolName === EDIT_TOOL_NAME ||
296
+ context.toolName === WRITE_TOOL_NAME) {
297
+ return "Yes, and auto-accept edits";
298
+ }
299
+ if (context.toolName === EXIT_PLAN_MODE_TOOL_NAME) {
300
+ return "Yes, auto-accept edits";
301
+ }
302
+ return "Allow Always";
303
+ }
259
304
  async handlePermissionRequest(sessionId, context) {
260
305
  logger.info(`Handling permission request for ${context.toolName} in session ${sessionId}`);
261
306
  const agent = this.agents.get(sessionId);
@@ -277,7 +322,7 @@ export class WaveAcpAgent {
277
322
  const displayTitle = effectiveName && effectiveCompactParams
278
323
  ? `${effectiveName}: ${effectiveCompactParams}`
279
324
  : effectiveName || "Tool Call";
280
- const options = [
325
+ let options = [
281
326
  {
282
327
  optionId: "allow_once",
283
328
  name: "Allow Once",
@@ -294,6 +339,36 @@ export class WaveAcpAgent {
294
339
  kind: "reject_once",
295
340
  },
296
341
  ];
342
+ if (context.toolName === BASH_TOOL_NAME ||
343
+ context.toolName === EDIT_TOOL_NAME ||
344
+ context.toolName === WRITE_TOOL_NAME) {
345
+ options = [
346
+ {
347
+ optionId: "allow_once",
348
+ name: "Yes, proceed",
349
+ kind: "allow_once",
350
+ },
351
+ {
352
+ optionId: "allow_always",
353
+ name: this.getAllowAlwaysName(context),
354
+ kind: "allow_always",
355
+ },
356
+ ];
357
+ }
358
+ else if (context.toolName === EXIT_PLAN_MODE_TOOL_NAME) {
359
+ options = [
360
+ {
361
+ optionId: "allow_once",
362
+ name: "Yes, manually approve edits",
363
+ kind: "allow_once",
364
+ },
365
+ {
366
+ optionId: "allow_always",
367
+ name: "Yes, auto-accept edits",
368
+ kind: "allow_always",
369
+ },
370
+ ];
371
+ }
297
372
  const content = context.toolName
298
373
  ? await this.getToolContentAsync(context.toolName, context.toolInput, workdir)
299
374
  : undefined;
@@ -324,11 +399,31 @@ export class WaveAcpAgent {
324
399
  logger.info(`User selected permission option: ${selectedOptionId}`);
325
400
  switch (selectedOptionId) {
326
401
  case "allow_always":
402
+ if (context.toolName === BASH_TOOL_NAME) {
403
+ const command = context.toolInput?.command || "";
404
+ const rule = context.suggestedPrefix
405
+ ? `${context.suggestedPrefix}*`
406
+ : command;
407
+ return {
408
+ behavior: "allow",
409
+ newPermissionRule: `${BASH_TOOL_NAME}(${rule})`,
410
+ };
411
+ }
412
+ if (context.toolName === EDIT_TOOL_NAME ||
413
+ context.toolName === WRITE_TOOL_NAME) {
414
+ return {
415
+ behavior: "allow",
416
+ newPermissionMode: "acceptEdits",
417
+ };
418
+ }
327
419
  return {
328
420
  behavior: "allow",
329
- newPermissionRule: `${context.toolName}(*)`,
421
+ newPermissionRule: context.toolName,
330
422
  };
331
423
  case "allow_once":
424
+ if (context.toolName === EXIT_PLAN_MODE_TOOL_NAME) {
425
+ return { behavior: "allow", newPermissionMode: "default" };
426
+ }
332
427
  return { behavior: "allow" };
333
428
  case "reject_once":
334
429
  return { behavior: "deny", message: "Rejected by user" };
@@ -434,6 +529,15 @@ export class WaveAcpAgent {
434
529
  newText: parameters.new_string,
435
530
  });
436
531
  }
532
+ else if (name === EXIT_PLAN_MODE_TOOL_NAME) {
533
+ contents.push({
534
+ type: "content",
535
+ content: {
536
+ type: "text",
537
+ text: parameters.plan_content,
538
+ },
539
+ });
540
+ }
437
541
  }
438
542
  if (shortResult) {
439
543
  contents.push({
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA4DjE"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgEjE"}
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import { App } from "./components/App.js";
4
4
  import { cleanupLogs } from "./utils/logger.js";
5
5
  import { removeWorktree } from "./utils/worktree.js";
6
6
  export async function startCli(options) {
7
- const { restoreSessionId, continueLastSession, bypassPermissions, permissionMode, pluginDirs, tools, worktreeSession, workdir, version, model, } = options;
7
+ const { restoreSessionId, continueLastSession, bypassPermissions, permissionMode, pluginDirs, tools, allowedTools, disallowedTools, worktreeSession, workdir, version, model, } = options;
8
8
  // Continue with ink-based UI for normal mode
9
9
  let shouldRemoveWorktree = false;
10
10
  const handleExit = (shouldRemove) => {
@@ -12,7 +12,7 @@ export async function startCli(options) {
12
12
  unmount();
13
13
  };
14
14
  // Render the application
15
- const { unmount, waitUntilExit } = render(_jsx(App, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, worktreeSession: worktreeSession, workdir: workdir, version: version, model: model, onExit: handleExit }), { exitOnCtrlC: false });
15
+ const { unmount, waitUntilExit } = render(_jsx(App, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, allowedTools: allowedTools, disallowedTools: disallowedTools, worktreeSession: worktreeSession, workdir: workdir, version: version, model: model, onExit: handleExit }), { exitOnCtrlC: false });
16
16
  // Wait for the app to finish unmounting
17
17
  await waitUntilExit();
18
18
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/components/App.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAWxE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,UAAU,QAAS,SAAQ,YAAY;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,MAAM,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAC;CACzC;AA4ID,eAAO,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CA+BlC,CAAC"}
1
+ {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/components/App.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmD,MAAM,OAAO,CAAC;AAWxE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,UAAU,QAAS,SAAQ,YAAY;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,MAAM,EAAE,CAAC,YAAY,EAAE,OAAO,KAAK,IAAI,CAAC;CACzC;AAgJD,eAAO,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CAmClC,CAAC"}
@@ -6,7 +6,7 @@ import { ChatProvider, useChat } from "../contexts/useChat.js";
6
6
  import { AppProvider } from "../contexts/useAppConfig.js";
7
7
  import { WorktreeExitPrompt } from "./WorktreeExitPrompt.js";
8
8
  import { hasUncommittedChanges, hasNewCommits, getDefaultRemoteBranch, } from "wave-agent-sdk";
9
- const AppWithProviders = ({ bypassPermissions, permissionMode, pluginDirs, tools, worktreeSession, workdir, version, model, onExit, }) => {
9
+ const AppWithProviders = ({ bypassPermissions, permissionMode, pluginDirs, tools, allowedTools, disallowedTools, worktreeSession, workdir, version, model, onExit, }) => {
10
10
  const [isExiting, setIsExiting] = useState(false);
11
11
  const [worktreeStatus, setWorktreeStatus] = useState(null);
12
12
  const handleSignal = useCallback(async () => {
@@ -48,7 +48,7 @@ const AppWithProviders = ({ bypassPermissions, permissionMode, pluginDirs, tools
48
48
  if (isExiting && worktreeSession && worktreeStatus) {
49
49
  return (_jsx(WorktreeExitPrompt, { name: worktreeSession.name, path: worktreeSession.path, hasUncommittedChanges: worktreeStatus.hasUncommittedChanges, hasNewCommits: worktreeStatus.hasNewCommits, onKeep: () => onExit(false), onRemove: () => onExit(true), onCancel: () => setIsExiting(false) }));
50
50
  }
51
- return (_jsx(ChatProvider, { bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, workdir: workdir, worktreeSession: worktreeSession, version: version, model: model, children: _jsx(ChatInterfaceWithRemount, {}) }));
51
+ return (_jsx(ChatProvider, { bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, allowedTools: allowedTools, disallowedTools: disallowedTools, workdir: workdir, worktreeSession: worktreeSession, version: version, model: model, children: _jsx(ChatInterfaceWithRemount, {}) }));
52
52
  };
53
53
  const ChatInterfaceWithRemount = () => {
54
54
  const { stdout } = useStdout();
@@ -86,6 +86,6 @@ const ChatInterfaceWithRemount = () => {
86
86
  ]);
87
87
  return _jsx(ChatInterface, {}, remountKey);
88
88
  };
89
- export const App = ({ restoreSessionId, continueLastSession, bypassPermissions, permissionMode, pluginDirs, tools, worktreeSession, workdir, version, model, onExit, }) => {
90
- return (_jsx(AppProvider, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, children: _jsx(AppWithProviders, { bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, worktreeSession: worktreeSession, workdir: workdir, version: version, model: model, onExit: onExit }) }));
89
+ export const App = ({ restoreSessionId, continueLastSession, bypassPermissions, permissionMode, pluginDirs, tools, allowedTools, disallowedTools, worktreeSession, workdir, version, model, onExit, }) => {
90
+ return (_jsx(AppProvider, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, children: _jsx(AppWithProviders, { bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, allowedTools: allowedTools, disallowedTools: disallowedTools, worktreeSession: worktreeSession, workdir: workdir, version: version, model: model, onExit: onExit }) }));
91
91
  };
@@ -1 +1 @@
1
- {"version":3,"file":"BackgroundTaskManager.d.ts","sourceRoot":"","sources":["../../src/components/BackgroundTaskManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAcnD,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CA8TtE,CAAC"}
1
+ {"version":3,"file":"BackgroundTaskManager.d.ts","sourceRoot":"","sources":["../../src/components/BackgroundTaskManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAenD,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CA6UtE,CAAC"}
@@ -20,6 +20,7 @@ export const BackgroundTaskManager = ({ onCancel, }) => {
20
20
  startTime: task.startTime,
21
21
  exitCode: task.exitCode,
22
22
  runtime: task.runtime,
23
+ outputPath: task.outputPath,
23
24
  })));
24
25
  }, [backgroundTasks]);
25
26
  // Load detail output for selected task
@@ -101,7 +102,7 @@ export const BackgroundTaskManager = ({ onCancel, }) => {
101
102
  setViewMode("list");
102
103
  return null;
103
104
  }
104
- return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "cyan", bold: true, children: ["Background Task Details: ", task.id] }) }), _jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Type:" }), " ", task.type] }) }), task.description && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Description:" }), " ", task.description] }) })), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Status:" }), " ", task.status, task.exitCode !== undefined && ` (exit code: ${task.exitCode})`] }) }), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Started:" }), " ", formatTime(task.startTime), task.runtime !== undefined && (_jsxs(Text, { children: [" ", "| ", _jsx(Text, { color: "blue", children: "Runtime:" }), " ", formatDuration(task.runtime)] }))] }) })] }), detailOutput.stdout && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "green", bold: true, children: "OUTPUT (last 10 lines):" }), _jsx(Box, { borderStyle: "single", borderColor: "green", padding: 1, children: _jsx(Text, { children: detailOutput.stdout.split("\n").slice(-10).join("\n") }) })] })), detailOutput.stderr && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "red", bold: true, children: "ERRORS:" }), _jsx(Box, { borderStyle: "single", borderColor: "red", padding: 1, children: _jsx(Text, { color: "red", children: detailOutput.stderr.split("\n").slice(-10).join("\n") }) })] })), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: [task.status === "running" ? "k to stop · " : "", "Esc to go back"] }) })] }));
105
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "cyan", bold: true, children: ["Background Task Details: ", task.id] }) }), _jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Type:" }), " ", task.type] }) }), task.description && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Description:" }), " ", task.description] }) })), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Status:" }), " ", task.status, task.exitCode !== undefined && ` (exit code: ${task.exitCode})`] }) }), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Started:" }), " ", formatTime(task.startTime), task.runtime !== undefined && (_jsxs(Text, { children: [" ", "| ", _jsx(Text, { color: "blue", children: "Runtime:" }), " ", formatDuration(task.runtime)] }))] }) }), task.outputPath && (_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Log File:" }), " ", task.outputPath] }) }))] }), detailOutput.stdout && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "green", bold: true, children: "OUTPUT (last 10 lines):" }), _jsx(Box, { borderStyle: "single", borderColor: "green", padding: 1, children: _jsx(Text, { children: detailOutput.stdout.split("\n").slice(-10).join("\n") }) })] })), detailOutput.stderr && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "red", bold: true, children: "ERRORS:" }), _jsx(Box, { borderStyle: "single", borderColor: "red", padding: 1, children: _jsx(Text, { color: "red", children: detailOutput.stderr.split("\n").slice(-10).join("\n") }) })] })), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: [task.status === "running" ? "k to stop · " : "", "Esc to go back"] }) })] }));
105
106
  }
106
107
  if (!backgroundTasks) {
107
108
  return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", borderBottom: false, borderLeft: false, borderRight: false, paddingTop: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "Background Tasks" }), _jsx(Text, { children: "Background tasks not available" }), _jsx(Text, { dimColor: true, children: "Press Escape to close" })] }));
@@ -116,7 +117,7 @@ export const BackgroundTaskManager = ({ onCancel, }) => {
116
117
  ? "green"
117
118
  : task.status === "completed"
118
119
  ? "blue"
119
- : "red", children: [" ", "(", task.status, ")"] })] }), isSelected && (_jsx(Box, { marginLeft: 4, flexDirection: "column", children: _jsxs(Text, { color: "gray", dimColor: true, children: ["Started: ", formatTime(task.startTime), task.runtime !== undefined &&
120
+ : "red", children: [" ", "(", task.status, ")"] })] }), isSelected && (_jsx(Box, { marginLeft: 4, flexDirection: "column", children: _jsxs(Text, { color: "gray", dimColor: true, children: [task.outputPath ? (_jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Log File:" }), " ", task.outputPath] })) : (`Started: ${formatTime(task.startTime)}`), task.runtime !== undefined &&
120
121
  ` | Runtime: ${formatDuration(task.runtime)}`, task.exitCode !== undefined && ` | Exit: ${task.exitCode}`] }) }))] }, task.id));
121
122
  }) }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["\u2191/\u2193 to select \u00B7 Enter to view \u00B7", " ", tasks[selectedIndex]?.status === "running" ? "k to stop · " : "", "Esc to close"] }) })] }));
122
123
  };
@@ -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,EAuKjC,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"}
@@ -17,6 +17,7 @@ export const ChatInterface = () => {
17
17
  const [isConfirmationTooTall, setIsConfirmationTooTall] = useState(false);
18
18
  const { messages, isLoading, isCommandRunning, isCompressing, sendMessage, abortMessage, mcpServers, connectMcpServer, disconnectMcpServer, isExpanded, sessionId, latestTotalTokens, slashCommands, hasSlashCommand, isConfirmationVisible, confirmingTool, handleConfirmationDecision, handleConfirmationCancel: originalHandleConfirmationCancel, setWasLastDetailsTooTall, version, workdir, getModelConfig, } = useChat();
19
19
  const model = getModelConfig().model;
20
+ const displayMessages = messages;
20
21
  const handleDetailsHeightMeasured = useCallback((height) => {
21
22
  setDetailsHeight(height);
22
23
  }, []);
@@ -74,7 +75,7 @@ export const ChatInterface = () => {
74
75
  ]);
75
76
  if (!sessionId)
76
77
  return null;
77
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(MessageList, { messages: messages, isExpanded: isExpanded, forceStatic: isConfirmationVisible && isConfirmationTooTall, version: version, workdir: workdir, model: model, onDynamicBlocksHeightMeasured: handleDynamicBlocksHeightMeasured }), (isLoading || isCommandRunning || isCompressing) &&
78
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(MessageList, { messages: displayMessages, isExpanded: isExpanded, forceStatic: isConfirmationVisible && isConfirmationTooTall, isFinished: !isLoading && !isCommandRunning && !isCompressing, version: version, workdir: workdir, model: model, onDynamicBlocksHeightMeasured: handleDynamicBlocksHeightMeasured }), (isLoading || isCommandRunning || isCompressing) &&
78
79
  !isConfirmationVisible &&
79
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
81
  };
@@ -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,CA0DlE,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,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,5 +1,5 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { useLayoutEffect, useRef } from "react";
2
+ import React, { useLayoutEffect, useRef } from "react";
3
3
  import { Box, Text, useStdout, measureElement, Static } from "ink";
4
4
  import { BASH_TOOL_NAME, EDIT_TOOL_NAME, WRITE_TOOL_NAME, EXIT_PLAN_MODE_TOOL_NAME, ASK_USER_QUESTION_TOOL_NAME, } from "wave-agent-sdk";
5
5
  import { DiffDisplay } from "./DiffDisplay.js";
@@ -39,7 +39,7 @@ export const ConfirmationDetails = ({ toolName, toolInput, isExpanded = false, o
39
39
  toolName === EXIT_PLAN_MODE_TOOL_NAME &&
40
40
  !!toolInput?.plan_content && (_jsx(PlanDisplay, { plan: toolInput.plan_content, isExpanded: isExpanded }))] }));
41
41
  if (isStatic) {
42
- return _jsx(Static, { items: [1], children: () => content });
42
+ return (_jsx(Static, { items: [1], children: (item) => _jsx(React.Fragment, { children: content }, item) }));
43
43
  }
44
44
  return content;
45
45
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmationSelector.d.ts","sourceRoot":"","sources":["../../src/components/ConfirmationSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuD,MAAM,OAAO,CAAC;AAE5E,OAAO,KAAK,EAAE,kBAAkB,EAAwB,MAAM,gBAAgB,CAAC;AAgB/E,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACnD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AASD,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CA6mBpE,CAAC"}
1
+ {"version":3,"file":"ConfirmationSelector.d.ts","sourceRoot":"","sources":["../../src/components/ConfirmationSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuD,MAAM,OAAO,CAAC;AAE5E,OAAO,KAAK,EAAE,kBAAkB,EAAwB,MAAM,gBAAgB,CAAC;AAgB/E,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACnD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AASD,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CA2nBpE,CAAC"}
@@ -49,11 +49,18 @@ export const ConfirmationSelector = ({ toolName, toolInput, suggestedPrefix, hid
49
49
  return "Yes, auto-accept edits";
50
50
  }
51
51
  if (toolName === BASH_TOOL_NAME) {
52
+ const command = toolInput?.command || "";
53
+ if (command.trim().startsWith("mkdir")) {
54
+ return "Yes, and auto-accept edits";
55
+ }
52
56
  if (suggestedPrefix) {
53
57
  return `Yes, and don't ask again for: ${suggestedPrefix}`;
54
58
  }
55
59
  return "Yes, and don't ask again for this command in this workdir";
56
60
  }
61
+ if (toolName.startsWith("mcp__")) {
62
+ return `Yes, and don't ask again for: ${toolName}`;
63
+ }
57
64
  return "Yes, and auto-accept edits";
58
65
  };
59
66
  useInput((input, key) => {
@@ -292,10 +299,19 @@ export const ConfirmationSelector = ({ toolName, toolInput, suggestedPrefix, hid
292
299
  }
293
300
  else if (state.selectedOption === "auto") {
294
301
  if (toolName === BASH_TOOL_NAME) {
295
- const rule = suggestedPrefix
296
- ? `Bash(${suggestedPrefix}*)`
297
- : `Bash(${toolInput?.command})`;
298
- onDecision({ behavior: "allow", newPermissionRule: rule });
302
+ const command = toolInput?.command || "";
303
+ if (command.trim().startsWith("mkdir")) {
304
+ onDecision({ behavior: "allow", newPermissionMode: "acceptEdits" });
305
+ }
306
+ else {
307
+ const rule = suggestedPrefix
308
+ ? `Bash(${suggestedPrefix}*)`
309
+ : `Bash(${toolInput?.command})`;
310
+ onDecision({ behavior: "allow", newPermissionRule: rule });
311
+ }
312
+ }
313
+ else if (toolName.startsWith("mcp__")) {
314
+ onDecision({ behavior: "allow", newPermissionRule: toolName });
299
315
  }
300
316
  else {
301
317
  onDecision({ behavior: "allow", newPermissionMode: "acceptEdits" });
@@ -9,7 +9,7 @@ export interface InputBoxProps {
9
9
  sendMessage?: (message: string, images?: Array<{
10
10
  path: string;
11
11
  mimeType: string;
12
- }>) => void;
12
+ }>, longTextMap?: Record<string, string>) => void;
13
13
  abortMessage?: () => void;
14
14
  mcpServers?: McpServerStatus[];
15
15
  connectMcpServer?: (serverName: string) => Promise<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAezC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEpE,eAAO,MAAM,sBAAsB,mDACe,CAAC;AAEnD,eAAO,MAAM,6BAA6B,QAGzC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CACZ,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,KAC/C,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAE1B,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,mBAAmB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAE/D,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAClD;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAgP5C,CAAC"}
1
+ {"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAezC,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEpE,eAAO,MAAM,sBAAsB,mDACe,CAAC;AAEnD,eAAO,MAAM,6BAA6B,QAGzC,CAAC;AAEF,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,CACZ,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,IAAI,CAAC;IACV,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAE1B,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;IAC/B,gBAAgB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5D,mBAAmB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAE/D,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAClD;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA8O5C,CAAC"}
@@ -16,7 +16,7 @@ import { useChat } from "../contexts/useChat.js";
16
16
  export const INPUT_PLACEHOLDER_TEXT = "Type your message (use /help for more info)...";
17
17
  export const INPUT_PLACEHOLDER_TEXT_PREFIX = INPUT_PLACEHOLDER_TEXT.substring(0, 10);
18
18
  export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mcpServers = [], connectMcpServer = async () => false, disconnectMcpServer = async () => false, slashCommands = [], hasSlashCommand = () => false, }) => {
19
- const { permissionMode: chatPermissionMode, setPermissionMode: setChatPermissionMode, handleRewindSelect, backgroundCurrentTask, messages, getFullMessageThread, clearMessages, sessionId, workingDirectory, } = useChat();
19
+ const { permissionMode: chatPermissionMode, setPermissionMode: setChatPermissionMode, handleRewindSelect, backgroundCurrentTask, messages, getFullMessageThread, sessionId, workingDirectory, } = useChat();
20
20
  // Input manager with all input state and functionality (including images)
21
21
  const { inputText, cursorPosition,
22
22
  // Image management
@@ -40,7 +40,6 @@ export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mc
40
40
  onAbortMessage: abortMessage,
41
41
  onBackgroundCurrentTask: backgroundCurrentTask,
42
42
  onPermissionModeChange: setChatPermissionMode,
43
- onClearMessages: clearMessages,
44
43
  sessionId,
45
44
  workdir: workingDirectory,
46
45
  getFullMessageThread,
@@ -4,10 +4,11 @@ export interface MessageListProps {
4
4
  messages: Message[];
5
5
  isExpanded?: boolean;
6
6
  forceStatic?: boolean;
7
+ isFinished?: boolean;
7
8
  version?: string;
8
9
  workdir?: string;
9
10
  model?: string;
10
11
  onDynamicBlocksHeightMeasured?: (height: number) => void;
11
12
  }
12
- export declare const MessageList: React.MemoExoticComponent<({ messages, isExpanded, forceStatic, version, workdir, model, onDynamicBlocksHeightMeasured, }: MessageListProps) => import("react/jsx-runtime").JSX.Element>;
13
+ export declare const MessageList: React.MemoExoticComponent<({ messages, isExpanded, forceStatic, isFinished, version, workdir, model, onDynamicBlocksHeightMeasured, }: MessageListProps) => import("react/jsx-runtime").JSX.Element>;
13
14
  //# sourceMappingURL=MessageList.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../src/components/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkC,MAAM,OAAO,CAAC;AAGvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAG9C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6BAA6B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1D;AAED,eAAO,MAAM,WAAW,6HASnB,gBAAgB,6CA8GpB,CAAC"}
1
+ {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../src/components/MessageList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkC,MAAM,OAAO,CAAC;AAGvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAG9C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6BAA6B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CAC1D;AAED,eAAO,MAAM,WAAW,yIAUnB,gBAAgB,6CA+GpB,CAAC"}
@@ -3,22 +3,16 @@ import React, { useLayoutEffect, useRef } from "react";
3
3
  import os from "os";
4
4
  import { Box, Text, Static, measureElement } from "ink";
5
5
  import { MessageBlockItem } from "./MessageBlockItem.js";
6
- export const MessageList = React.memo(({ messages, isExpanded = false, forceStatic = false, version, workdir, model, onDynamicBlocksHeightMeasured, }) => {
6
+ export const MessageList = React.memo(({ messages, isExpanded = false, forceStatic = false, isFinished = false, version, workdir, model, onDynamicBlocksHeightMeasured, }) => {
7
7
  const welcomeMessage = (_jsxs(Box, { flexDirection: "column", paddingTop: 1, children: [_jsxs(Text, { color: "gray", children: ["WAVE", version ? ` v${version}` : "", model ? ` • ${model}` : ""] }), workdir && (_jsx(Text, { color: "gray", wrap: "truncate-middle", children: workdir.replace(os.homedir(), "~") }))] }));
8
- // Limit messages when expanded to prevent long rendering times
9
- const maxExpandedMessages = 20;
10
- const shouldLimitMessages = isExpanded && messages.length > maxExpandedMessages;
11
- const displayMessages = shouldLimitMessages
12
- ? messages.slice(-maxExpandedMessages)
13
- : messages;
8
+ // Limit messages to prevent long rendering times
9
+ const maxMessages = 10;
14
10
  // Flatten messages into blocks with metadata
15
- const allBlocks = displayMessages.flatMap((message, index) => {
16
- const messageIndex = shouldLimitMessages
17
- ? messages.length - maxExpandedMessages + index
18
- : index;
11
+ const allBlocks = messages.flatMap((message, messageIndex) => {
19
12
  return message.blocks.map((block, blockIndex) => ({
20
13
  block,
21
14
  message,
15
+ messageIndex,
22
16
  isLastMessage: messageIndex === messages.length - 1,
23
17
  // Unique key for each block to help Static component
24
18
  key: `${message.id}-${blockIndex}`,
@@ -26,11 +20,8 @@ export const MessageList = React.memo(({ messages, isExpanded = false, forceStat
26
20
  });
27
21
  // Determine which blocks are static vs dynamic
28
22
  const blocksWithStatus = allBlocks.map((item) => {
29
- const { block, isLastMessage } = item;
30
- const isDynamic = !forceStatic &&
31
- isLastMessage &&
32
- ((block.type === "tool" && block.stage !== "end") ||
33
- (block.type === "bang" && block.isRunning));
23
+ const { isLastMessage } = item;
24
+ const isDynamic = !forceStatic && !isFinished && isLastMessage;
34
25
  return { ...item, isDynamic };
35
26
  });
36
27
  const staticBlocks = blocksWithStatus.filter((b) => !b.isDynamic);
@@ -46,13 +37,23 @@ export const MessageList = React.memo(({ messages, isExpanded = false, forceStat
46
37
  }
47
38
  }, [dynamicBlocks, isExpanded, onDynamicBlocksHeightMeasured]);
48
39
  const staticItems = [
49
- { isWelcome: true, key: "welcome", block: undefined, message: undefined },
40
+ {
41
+ isWelcome: true,
42
+ key: "welcome",
43
+ block: undefined,
44
+ message: undefined,
45
+ messageIndex: -1,
46
+ },
50
47
  ...staticBlocks.map((b) => ({ ...b, isWelcome: false })),
51
48
  ];
52
49
  return (_jsxs(Box, { flexDirection: "column", paddingBottom: 1, children: [staticItems.length > 0 && (_jsx(Static, { items: staticItems, children: (item) => {
53
50
  if (item.isWelcome) {
54
51
  return (_jsx(React.Fragment, { children: welcomeMessage }, item.key));
55
52
  }
53
+ if (messages.length > maxMessages &&
54
+ item.messageIndex < messages.length - maxMessages) {
55
+ return null;
56
+ }
56
57
  return (_jsx(MessageBlockItem, { block: item.block, message: item.message, isExpanded: isExpanded, paddingTop: 1 }, item.key));
57
58
  } })), dynamicBlocks.length > 0 && (_jsx(Box, { ref: dynamicBlocksRef, flexDirection: "column", children: dynamicBlocks.map((item) => (_jsx(MessageBlockItem, { block: item.block, message: item.message, isExpanded: isExpanded, paddingTop: 1 }, item.key))) }))] }));
58
59
  });
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/constants/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,eAAO,MAAM,kBAAkB,EAAE,YAAY,EA4C5C,CAAC"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/constants/commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,eAAO,MAAM,kBAAkB,EAAE,YAAY,EAsC5C,CAAC"}
@@ -1,10 +1,4 @@
1
1
  export const AVAILABLE_COMMANDS = [
2
- {
3
- id: "clear",
4
- name: "clear",
5
- description: "Clear the chat session and terminal",
6
- handler: () => { }, // Handler here won't be used, actual processing is in the hook
7
- },
8
2
  {
9
3
  id: "tasks",
10
4
  name: "tasks",
@@ -15,15 +15,15 @@ export interface ChatContextType {
15
15
  path: string;
16
16
  mimeType: string;
17
17
  }>;
18
+ longTextMap?: Record<string, string>;
18
19
  }>;
19
20
  sessionId: string;
20
21
  sendMessage: (content: string, images?: Array<{
21
22
  path: string;
22
23
  mimeType: string;
23
- }>) => Promise<void>;
24
+ }>, longTextMap?: Record<string, string>) => Promise<void>;
24
25
  abortMessage: () => void;
25
26
  latestTotalTokens: number;
26
- clearMessages: () => void;
27
27
  mcpServers: McpServerStatus[];
28
28
  connectMcpServer: (serverName: string) => Promise<boolean>;
29
29
  disconnectMcpServer: (serverName: string) => Promise<boolean>;
@@ -33,6 +33,7 @@ export interface ChatContextType {
33
33
  stdout: string;
34
34
  stderr: string;
35
35
  status: string;
36
+ outputPath?: string;
36
37
  } | null;
37
38
  stopBackgroundTask: (taskId: string) => boolean;
38
39
  slashCommands: SlashCommand[];