wave-code 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/cli.d.ts +2 -4
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +24 -52
  4. package/dist/components/App.d.ts +3 -4
  5. package/dist/components/App.d.ts.map +1 -1
  6. package/dist/components/App.js +49 -6
  7. package/dist/components/BackgroundTaskManager.d.ts.map +1 -1
  8. package/dist/components/BackgroundTaskManager.js +12 -20
  9. package/dist/components/BangDisplay.d.ts +9 -0
  10. package/dist/components/BangDisplay.d.ts.map +1 -0
  11. package/dist/components/{CommandOutputDisplay.js → BangDisplay.js} +1 -1
  12. package/dist/components/ChatInterface.d.ts.map +1 -1
  13. package/dist/components/ChatInterface.js +3 -2
  14. package/dist/components/CommandSelector.d.ts.map +1 -1
  15. package/dist/components/CommandSelector.js +18 -2
  16. package/dist/components/ConfirmationSelector.d.ts.map +1 -1
  17. package/dist/components/ConfirmationSelector.js +105 -8
  18. package/dist/components/HelpView.d.ts.map +1 -1
  19. package/dist/components/HelpView.js +2 -0
  20. package/dist/components/HistorySearch.d.ts.map +1 -1
  21. package/dist/components/HistorySearch.js +19 -25
  22. package/dist/components/InputBox.d.ts.map +1 -1
  23. package/dist/components/InputBox.js +9 -3
  24. package/dist/components/MarketplaceAddForm.d.ts.map +1 -1
  25. package/dist/components/MarketplaceAddForm.js +13 -6
  26. package/dist/components/MarketplaceDetail.d.ts.map +1 -1
  27. package/dist/components/MarketplaceDetail.js +8 -3
  28. package/dist/components/MessageBlockItem.js +2 -2
  29. package/dist/components/MessageList.d.ts +4 -1
  30. package/dist/components/MessageList.d.ts.map +1 -1
  31. package/dist/components/MessageList.js +15 -8
  32. package/dist/components/PluginDetail.d.ts.map +1 -1
  33. package/dist/components/PluginDetail.js +14 -3
  34. package/dist/components/PluginManagerShell.d.ts.map +1 -1
  35. package/dist/components/PluginManagerShell.js +3 -3
  36. package/dist/components/PluginManagerTypes.d.ts +2 -0
  37. package/dist/components/PluginManagerTypes.d.ts.map +1 -1
  38. package/dist/components/SessionSelector.d.ts.map +1 -1
  39. package/dist/components/SessionSelector.js +10 -13
  40. package/dist/components/StatusCommand.d.ts +6 -0
  41. package/dist/components/StatusCommand.d.ts.map +1 -0
  42. package/dist/components/StatusCommand.js +28 -0
  43. package/dist/components/WorktreeExitPrompt.d.ts +13 -0
  44. package/dist/components/WorktreeExitPrompt.d.ts.map +1 -0
  45. package/dist/components/WorktreeExitPrompt.js +26 -0
  46. package/dist/contexts/useChat.d.ts +9 -5
  47. package/dist/contexts/useChat.d.ts.map +1 -1
  48. package/dist/contexts/useChat.js +38 -8
  49. package/dist/contracts/status.d.ts +8 -0
  50. package/dist/contracts/status.d.ts.map +1 -0
  51. package/dist/contracts/status.js +1 -0
  52. package/dist/hooks/useInputManager.d.ts +2 -0
  53. package/dist/hooks/useInputManager.d.ts.map +1 -1
  54. package/dist/hooks/useInputManager.js +12 -0
  55. package/dist/hooks/usePluginManager.d.ts.map +1 -1
  56. package/dist/hooks/usePluginManager.js +41 -13
  57. package/dist/hooks/useTasks.js +2 -2
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +53 -4
  60. package/dist/managers/InputManager.d.ts +6 -0
  61. package/dist/managers/InputManager.d.ts.map +1 -1
  62. package/dist/managers/InputManager.js +32 -13
  63. package/dist/print-cli.d.ts +2 -4
  64. package/dist/print-cli.d.ts.map +1 -1
  65. package/dist/print-cli.js +31 -2
  66. package/dist/session-selector-cli.d.ts +3 -1
  67. package/dist/session-selector-cli.d.ts.map +1 -1
  68. package/dist/session-selector-cli.js +2 -2
  69. package/dist/types.d.ts +11 -0
  70. package/dist/types.d.ts.map +1 -0
  71. package/dist/types.js +1 -0
  72. package/dist/utils/worktree.d.ts +23 -0
  73. package/dist/utils/worktree.d.ts.map +1 -0
  74. package/dist/utils/worktree.js +135 -0
  75. package/package.json +2 -2
  76. package/src/cli.tsx +36 -59
  77. package/src/components/App.tsx +99 -11
  78. package/src/components/BackgroundTaskManager.tsx +12 -20
  79. package/src/components/{CommandOutputDisplay.tsx → BangDisplay.tsx} +4 -4
  80. package/src/components/ChatInterface.tsx +8 -0
  81. package/src/components/CommandSelector.tsx +18 -1
  82. package/src/components/ConfirmationSelector.tsx +118 -9
  83. package/src/components/HelpView.tsx +2 -0
  84. package/src/components/HistorySearch.tsx +25 -30
  85. package/src/components/InputBox.tsx +11 -1
  86. package/src/components/MarketplaceAddForm.tsx +21 -8
  87. package/src/components/MarketplaceDetail.tsx +19 -4
  88. package/src/components/MessageBlockItem.tsx +3 -3
  89. package/src/components/MessageList.tsx +47 -23
  90. package/src/components/PluginDetail.tsx +30 -6
  91. package/src/components/PluginManagerShell.tsx +24 -6
  92. package/src/components/PluginManagerTypes.ts +2 -0
  93. package/src/components/SessionSelector.tsx +38 -24
  94. package/src/components/StatusCommand.tsx +94 -0
  95. package/src/components/WorktreeExitPrompt.tsx +86 -0
  96. package/src/contexts/useChat.tsx +57 -13
  97. package/src/contracts/status.ts +7 -0
  98. package/src/hooks/useInputManager.ts +12 -0
  99. package/src/hooks/usePluginManager.ts +47 -13
  100. package/src/hooks/useTasks.ts +2 -2
  101. package/src/index.ts +71 -12
  102. package/src/managers/InputManager.ts +37 -15
  103. package/src/print-cli.ts +48 -5
  104. package/src/session-selector-cli.tsx +6 -2
  105. package/src/types.ts +11 -0
  106. package/src/utils/worktree.ts +164 -0
  107. package/dist/components/CommandOutputDisplay.d.ts +0 -9
  108. package/dist/components/CommandOutputDisplay.d.ts.map +0 -1
package/dist/cli.d.ts CHANGED
@@ -1,9 +1,7 @@
1
- export interface CliOptions {
1
+ import { BaseAppProps } from "./types.js";
2
+ export interface CliOptions extends BaseAppProps {
2
3
  restoreSessionId?: string;
3
4
  continueLastSession?: boolean;
4
- bypassPermissions?: boolean;
5
- pluginDirs?: string[];
6
- tools?: string[];
7
5
  }
8
6
  export declare function startCli(options: CliOptions): Promise<void>;
9
7
  //# sourceMappingURL=cli.d.ts.map
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,UAAU;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgFjE"}
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,CA0DjE"}
package/dist/cli.js CHANGED
@@ -2,61 +2,33 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { render } from "ink";
3
3
  import { App } from "./components/App.js";
4
4
  import { cleanupLogs } from "./utils/logger.js";
5
+ import { removeWorktree } from "./utils/worktree.js";
5
6
  export async function startCli(options) {
6
- const { restoreSessionId, continueLastSession, bypassPermissions, pluginDirs, tools, } = options;
7
+ const { restoreSessionId, continueLastSession, bypassPermissions, pluginDirs, tools, worktreeSession, workdir, version, model, } = options;
7
8
  // Continue with ink-based UI for normal mode
8
- // Global cleanup tracker
9
- let isCleaningUp = false;
10
- let appUnmounted = false;
11
- const cleanup = async () => {
12
- if (isCleaningUp)
13
- return;
14
- isCleaningUp = true;
15
- console.log("\nShutting down gracefully...");
16
- try {
17
- // Clean up old log files
18
- await cleanupLogs().catch((error) => {
19
- console.warn("Failed to cleanup old logs:", error);
20
- });
21
- // Unmount the React app to trigger cleanup
22
- if (!appUnmounted) {
23
- unmount();
24
- appUnmounted = true;
25
- // Give React time to cleanup
26
- await new Promise((resolve) => setTimeout(resolve, 100));
27
- }
28
- process.exit(0);
29
- }
30
- catch (error) {
31
- console.error("Error during cleanup:", error);
32
- process.exit(1);
33
- }
9
+ let shouldRemoveWorktree = false;
10
+ const handleExit = (shouldRemove) => {
11
+ shouldRemoveWorktree = shouldRemove;
12
+ unmount();
34
13
  };
35
- // Handle process signals
36
- process.on("SIGINT", cleanup);
37
- process.on("SIGTERM", cleanup);
38
- // Handle uncaught exceptions
39
- process.on("uncaughtException", (error) => {
40
- console.error("Uncaught exception:", error);
41
- cleanup();
42
- });
43
- process.on("unhandledRejection", (reason, promise) => {
44
- console.error("Unhandled rejection at:", promise, "reason:", reason);
45
- cleanup();
46
- });
47
14
  // Render the application
48
- const { unmount } = render(_jsx(App, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, bypassPermissions: bypassPermissions, pluginDirs: pluginDirs, tools: tools }));
49
- // Store unmount function for cleanup when process exits normally
50
- process.on("exit", () => {
51
- if (!appUnmounted) {
52
- try {
53
- unmount();
54
- }
55
- catch {
56
- // Ignore errors during unmount
57
- }
15
+ const { unmount, waitUntilExit } = render(_jsx(App, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, bypassPermissions: bypassPermissions, pluginDirs: pluginDirs, tools: tools, worktreeSession: worktreeSession, workdir: workdir, version: version, model: model, onExit: handleExit }), { exitOnCtrlC: false });
16
+ // Wait for the app to finish unmounting
17
+ await waitUntilExit();
18
+ try {
19
+ // Clean up old log files
20
+ await cleanupLogs().catch((error) => {
21
+ console.warn("Failed to cleanup old logs:", error);
22
+ });
23
+ // Cleanup worktree if requested
24
+ if (shouldRemoveWorktree && worktreeSession) {
25
+ process.chdir(worktreeSession.repoRoot);
26
+ removeWorktree(worktreeSession);
58
27
  }
59
- });
60
- // Return a promise that never resolves to keep the CLI running
61
- return new Promise(() => { });
28
+ process.exit(0);
29
+ }
30
+ catch (error) {
31
+ console.error("Error during cleanup:", error);
32
+ process.exit(1);
33
+ }
62
34
  }
@@ -1,10 +1,9 @@
1
1
  import React from "react";
2
- interface AppProps {
2
+ import { BaseAppProps } from "../types.js";
3
+ interface AppProps extends BaseAppProps {
3
4
  restoreSessionId?: string;
4
5
  continueLastSession?: boolean;
5
- bypassPermissions?: boolean;
6
- pluginDirs?: string[];
7
- tools?: string[];
6
+ onExit: (shouldRemove: boolean) => void;
8
7
  }
9
8
  export declare const App: React.FC<AppProps>;
10
9
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/components/App.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAM3D,UAAU,QAAQ;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAiED,eAAO,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CAmBlC,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;AA0ID,eAAO,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CA6BlC,CAAC"}
@@ -1,11 +1,54 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useState, useEffect, useRef } from "react";
3
- import { useStdout } from "ink";
2
+ import { useState, useEffect, useRef, useCallback } from "react";
3
+ import { useStdout, useInput } from "ink";
4
4
  import { ChatInterface } from "./ChatInterface.js";
5
5
  import { ChatProvider, useChat } from "../contexts/useChat.js";
6
6
  import { AppProvider } from "../contexts/useAppConfig.js";
7
- const AppWithProviders = ({ bypassPermissions, pluginDirs, tools }) => {
8
- return (_jsx(ChatProvider, { bypassPermissions: bypassPermissions, pluginDirs: pluginDirs, tools: tools, children: _jsx(ChatInterfaceWithRemount, {}) }));
7
+ import { WorktreeExitPrompt } from "./WorktreeExitPrompt.js";
8
+ import { hasUncommittedChanges, hasNewCommits, getDefaultRemoteBranch, } from "wave-agent-sdk";
9
+ const AppWithProviders = ({ bypassPermissions, pluginDirs, tools, worktreeSession, workdir, version, model, onExit, }) => {
10
+ const [isExiting, setIsExiting] = useState(false);
11
+ const [worktreeStatus, setWorktreeStatus] = useState(null);
12
+ const handleSignal = useCallback(async () => {
13
+ if (worktreeSession) {
14
+ const cwd = workdir || worktreeSession.path;
15
+ const baseBranch = getDefaultRemoteBranch(cwd);
16
+ const hasChanges = hasUncommittedChanges(cwd);
17
+ const hasCommits = hasNewCommits(cwd, baseBranch);
18
+ if (hasChanges || hasCommits) {
19
+ setWorktreeStatus({
20
+ hasUncommittedChanges: hasChanges,
21
+ hasNewCommits: hasCommits,
22
+ });
23
+ setIsExiting(true);
24
+ }
25
+ else {
26
+ onExit(true);
27
+ }
28
+ }
29
+ else {
30
+ onExit(false);
31
+ }
32
+ }, [worktreeSession, workdir, onExit]);
33
+ useInput((input, key) => {
34
+ if (input === "c" && key.ctrl) {
35
+ handleSignal();
36
+ }
37
+ });
38
+ useEffect(() => {
39
+ const onSigInt = () => handleSignal();
40
+ const onSigTerm = () => handleSignal();
41
+ process.on("SIGINT", onSigInt);
42
+ process.on("SIGTERM", onSigTerm);
43
+ return () => {
44
+ process.off("SIGINT", onSigInt);
45
+ process.off("SIGTERM", onSigTerm);
46
+ };
47
+ }, [handleSignal]);
48
+ if (isExiting && worktreeSession && worktreeStatus) {
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
+ }
51
+ return (_jsx(ChatProvider, { bypassPermissions: bypassPermissions, pluginDirs: pluginDirs, tools: tools, workdir: workdir, worktreeSession: worktreeSession, version: version, model: model, children: _jsx(ChatInterfaceWithRemount, {}) }));
9
52
  };
10
53
  const ChatInterfaceWithRemount = () => {
11
54
  const { stdout } = useStdout();
@@ -43,6 +86,6 @@ const ChatInterfaceWithRemount = () => {
43
86
  ]);
44
87
  return _jsx(ChatInterface, {}, remountKey);
45
88
  };
46
- export const App = ({ restoreSessionId, continueLastSession, bypassPermissions, pluginDirs, tools, }) => {
47
- return (_jsx(AppProvider, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, children: _jsx(AppWithProviders, { bypassPermissions: bypassPermissions, pluginDirs: pluginDirs, tools: tools }) }));
89
+ export const App = ({ restoreSessionId, continueLastSession, bypassPermissions, pluginDirs, tools, worktreeSession, workdir, version, model, onExit, }) => {
90
+ return (_jsx(AppProvider, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, children: _jsx(AppWithProviders, { bypassPermissions: bypassPermissions, pluginDirs: pluginDirs, tools: tools, worktreeSession: worktreeSession, workdir: workdir, version: version, model: model, onExit: onExit }) }));
48
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,CAsUtE,CAAC"}
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"}
@@ -51,14 +51,11 @@ export const BackgroundTaskManager = ({ onCancel, }) => {
51
51
  if (viewMode === "list") {
52
52
  // List mode navigation
53
53
  if (key.return) {
54
- setSelectedIndex((prev) => {
55
- if (tasks.length > 0 && prev < tasks.length) {
56
- const selectedTask = tasks[prev];
57
- setDetailTaskId(selectedTask.id);
58
- setViewMode("detail");
59
- }
60
- return prev;
61
- });
54
+ if (tasks.length > 0 && selectedIndex < tasks.length) {
55
+ const selectedTask = tasks[selectedIndex];
56
+ setDetailTaskId(selectedTask.id);
57
+ setViewMode("detail");
58
+ }
62
59
  return;
63
60
  }
64
61
  if (key.escape) {
@@ -66,23 +63,18 @@ export const BackgroundTaskManager = ({ onCancel, }) => {
66
63
  return;
67
64
  }
68
65
  if (key.upArrow) {
69
- setSelectedIndex((prev) => Math.max(0, prev - 1));
66
+ setSelectedIndex(Math.max(0, selectedIndex - 1));
70
67
  return;
71
68
  }
72
69
  if (key.downArrow) {
73
- setSelectedIndex((prev) => Math.min(tasks.length - 1, prev + 1));
70
+ setSelectedIndex(Math.min(tasks.length - 1, selectedIndex + 1));
74
71
  return;
75
72
  }
76
- if (input === "k") {
77
- setSelectedIndex((prev) => {
78
- if (tasks.length > 0 && prev < tasks.length) {
79
- const selectedTask = tasks[prev];
80
- if (selectedTask.status === "running") {
81
- stopTask(selectedTask.id);
82
- }
83
- }
84
- return prev;
85
- });
73
+ if (input === "k" && tasks.length > 0 && selectedIndex < tasks.length) {
74
+ const selectedTask = tasks[selectedIndex];
75
+ if (selectedTask.status === "running") {
76
+ stopTask(selectedTask.id);
77
+ }
86
78
  return;
87
79
  }
88
80
  }
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ import type { BangBlock } from "wave-agent-sdk";
3
+ interface BangDisplayProps {
4
+ block: BangBlock;
5
+ isExpanded?: boolean;
6
+ }
7
+ export declare const BangDisplay: React.FC<BangDisplayProps>;
8
+ export {};
9
+ //# sourceMappingURL=BangDisplay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BangDisplay.d.ts","sourceRoot":"","sources":["../../src/components/BangDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,UAAU,gBAAgB;IACxB,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAiDlD,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState, useEffect } from "react";
3
3
  import { Box, Text } from "ink";
4
- export const CommandOutputDisplay = ({ block, isExpanded = false, }) => {
4
+ export const BangDisplay = ({ block, isExpanded = false, }) => {
5
5
  const { command, output, isRunning, exitCode } = block;
6
6
  const [isOverflowing, setIsOverflowing] = useState(false);
7
7
  const MAX_LINES = 3; // Set maximum display lines
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAYtE,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAqIjC,CAAC"}
1
+ {"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAYtE,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EA6IjC,CAAC"}
@@ -13,7 +13,8 @@ export const ChatInterface = () => {
13
13
  const [detailsHeight, setDetailsHeight] = useState(0);
14
14
  const [selectorHeight, setSelectorHeight] = useState(0);
15
15
  const [isConfirmationTooTall, setIsConfirmationTooTall] = useState(false);
16
- const { messages, isLoading, isCommandRunning, isCompressing, sendMessage, abortMessage, mcpServers, connectMcpServer, disconnectMcpServer, isExpanded, sessionId, latestTotalTokens, slashCommands, hasSlashCommand, isConfirmationVisible, confirmingTool, handleConfirmationDecision, handleConfirmationCancel: originalHandleConfirmationCancel, setWasLastDetailsTooTall, } = useChat();
16
+ 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();
17
+ const model = getModelConfig().model;
17
18
  const handleDetailsHeightMeasured = useCallback((height) => {
18
19
  setDetailsHeight(height);
19
20
  }, []);
@@ -54,7 +55,7 @@ export const ChatInterface = () => {
54
55
  ]);
55
56
  if (!sessionId)
56
57
  return null;
57
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(MessageList, { messages: messages, isExpanded: isExpanded, hideDynamicBlocks: isConfirmationVisible }), (isLoading || isCommandRunning || isCompressing) &&
58
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(MessageList, { messages: messages, isExpanded: isExpanded, hideDynamicBlocks: isConfirmationVisible, version: version, workdir: workdir, model: model }), (isLoading || isCommandRunning || isCompressing) &&
58
59
  !isConfirmationVisible &&
59
60
  !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 && (_jsx(InputBox, { isLoading: isLoading, isCommandRunning: isCommandRunning, sendMessage: sendMessage, abortMessage: abortMessage, mcpServers: mcpServers, connectMcpServer: connectMcpServer, disconnectMcpServer: disconnectMcpServer, slashCommands: slashCommands, hasSlashCommand: hasSlashCommand }))] }));
60
61
  };
@@ -1 +1 @@
1
- {"version":3,"file":"CommandSelector.d.ts","sourceRoot":"","sources":["../../src/components/CommandSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AA8BnD,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA0I1D,CAAC"}
1
+ {"version":3,"file":"CommandSelector.d.ts","sourceRoot":"","sources":["../../src/components/CommandSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AA0CnD,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,YAAY,EAAE,CAAC;CAC3B;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA+I1D,CAAC"}
@@ -1,7 +1,13 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { useState } from "react";
2
+ import React, { useState } from "react";
3
3
  import { Box, Text, useInput } from "ink";
4
4
  const AVAILABLE_COMMANDS = [
5
+ {
6
+ id: "clear",
7
+ name: "clear",
8
+ description: "Clear the chat session and terminal",
9
+ handler: () => { }, // Handler here won't be used, actual processing is in the hook
10
+ },
5
11
  {
6
12
  id: "tasks",
7
13
  name: "tasks",
@@ -26,13 +32,23 @@ const AVAILABLE_COMMANDS = [
26
32
  description: "Show help and key bindings",
27
33
  handler: () => { }, // Handler here won't be used, actual processing is in the hook
28
34
  },
35
+ {
36
+ id: "status",
37
+ name: "status",
38
+ description: "Show agent status and configuration",
39
+ handler: () => { }, // Handler here won't be used, actual processing is in the hook
40
+ },
29
41
  ];
30
42
  export const CommandSelector = ({ searchQuery, onSelect, onInsert, onCancel, commands = [], // Default to empty array
31
43
  }) => {
32
44
  const MAX_VISIBLE_ITEMS = 3;
33
45
  const [selectedIndex, setSelectedIndex] = useState(0);
46
+ // Reset selected index when search query changes
47
+ React.useEffect(() => {
48
+ setSelectedIndex(0);
49
+ }, [searchQuery]);
34
50
  // Merge agent commands and local commands
35
- const allCommands = [...commands, ...AVAILABLE_COMMANDS];
51
+ const allCommands = [...AVAILABLE_COMMANDS, ...commands];
36
52
  // Filter command list
37
53
  const filteredCommands = allCommands.filter((command) => !searchQuery ||
38
54
  command.id.toLowerCase().includes(searchQuery.toLowerCase()));
@@ -1 +1 @@
1
- {"version":3,"file":"ConfirmationSelector.d.ts","sourceRoot":"","sources":["../../src/components/ConfirmationSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4C,MAAM,OAAO,CAAC;AAEjE,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,CAsfpE,CAAC"}
1
+ {"version":3,"file":"ConfirmationSelector.d.ts","sourceRoot":"","sources":["../../src/components/ConfirmationSelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4C,MAAM,OAAO,CAAC;AAEjE,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,CAmmBpE,CAAC"}
@@ -32,6 +32,7 @@ export const ConfirmationSelector = ({ toolName, toolInput, suggestedPrefix, hid
32
32
  userAnswers: {},
33
33
  otherText: "",
34
34
  otherCursorPosition: 0,
35
+ savedStates: {},
35
36
  });
36
37
  const questions = toolInput?.questions || [];
37
38
  const currentQuestion = questions[questionState.currentQuestionIndex];
@@ -87,24 +88,72 @@ export const ConfirmationSelector = ({ toolName, toolInput, suggestedPrefix, hid
87
88
  [currentQuestion.question]: answer,
88
89
  };
89
90
  if (prev.currentQuestionIndex < questions.length - 1) {
90
- return {
91
- ...prev,
92
- currentQuestionIndex: prev.currentQuestionIndex + 1,
91
+ const nextIndex = prev.currentQuestionIndex + 1;
92
+ const savedStates = {
93
+ ...prev.savedStates,
94
+ [prev.currentQuestionIndex]: {
95
+ selectedOptionIndex: prev.selectedOptionIndex,
96
+ selectedOptionIndices: prev.selectedOptionIndices,
97
+ otherText: prev.otherText,
98
+ otherCursorPosition: prev.otherCursorPosition,
99
+ },
100
+ };
101
+ const nextState = savedStates[nextIndex] || {
93
102
  selectedOptionIndex: 0,
94
103
  selectedOptionIndices: new Set(),
95
- userAnswers: newAnswers,
96
104
  otherText: "",
97
105
  otherCursorPosition: 0,
98
106
  };
107
+ return {
108
+ ...prev,
109
+ currentQuestionIndex: nextIndex,
110
+ ...nextState,
111
+ userAnswers: newAnswers,
112
+ savedStates,
113
+ };
99
114
  }
100
115
  else {
116
+ const finalAnswers = { ...newAnswers };
117
+ // Also collect from savedStates for any questions that were skipped via Tab
118
+ for (const [idxStr, s] of Object.entries(prev.savedStates)) {
119
+ const idx = parseInt(idxStr);
120
+ const q = questions[idx];
121
+ if (q && !finalAnswers[q.question]) {
122
+ const opts = [...q.options, { label: "Other" }];
123
+ let a = "";
124
+ if (q.multiSelect) {
125
+ const selectedLabels = Array.from(s.selectedOptionIndices)
126
+ .filter((i) => i < q.options.length)
127
+ .map((i) => q.options[i].label);
128
+ const isOtherChecked = s.selectedOptionIndices.has(opts.length - 1);
129
+ if (isOtherChecked && s.otherText.trim()) {
130
+ selectedLabels.push(s.otherText.trim());
131
+ }
132
+ a = selectedLabels.join(", ");
133
+ }
134
+ else {
135
+ if (s.selectedOptionIndex === opts.length - 1) {
136
+ a = s.otherText.trim();
137
+ }
138
+ else {
139
+ a = opts[s.selectedOptionIndex].label;
140
+ }
141
+ }
142
+ if (a)
143
+ finalAnswers[q.question] = a;
144
+ }
145
+ }
146
+ // Only submit if all questions have been answered
147
+ const allAnswered = questions.every((q) => finalAnswers[q.question]);
148
+ if (!allAnswered)
149
+ return prev;
101
150
  onDecision({
102
151
  behavior: "allow",
103
- message: JSON.stringify(newAnswers),
152
+ message: JSON.stringify(finalAnswers),
104
153
  });
105
154
  return {
106
155
  ...prev,
107
- userAnswers: newAnswers,
156
+ userAnswers: finalAnswers,
108
157
  };
109
158
  }
110
159
  });
@@ -144,6 +193,40 @@ export const ConfirmationSelector = ({ toolName, toolInput, suggestedPrefix, hid
144
193
  }));
145
194
  return;
146
195
  }
196
+ if (key.tab) {
197
+ setQuestionState((prev) => {
198
+ const direction = key.shift ? -1 : 1;
199
+ let nextIndex = prev.currentQuestionIndex + direction;
200
+ if (nextIndex < 0)
201
+ nextIndex = questions.length - 1;
202
+ if (nextIndex >= questions.length)
203
+ nextIndex = 0;
204
+ if (nextIndex === prev.currentQuestionIndex)
205
+ return prev;
206
+ const savedStates = {
207
+ ...prev.savedStates,
208
+ [prev.currentQuestionIndex]: {
209
+ selectedOptionIndex: prev.selectedOptionIndex,
210
+ selectedOptionIndices: prev.selectedOptionIndices,
211
+ otherText: prev.otherText,
212
+ otherCursorPosition: prev.otherCursorPosition,
213
+ },
214
+ };
215
+ const nextState = savedStates[nextIndex] || {
216
+ selectedOptionIndex: 0,
217
+ selectedOptionIndices: new Set(),
218
+ otherText: "",
219
+ otherCursorPosition: 0,
220
+ };
221
+ return {
222
+ ...prev,
223
+ currentQuestionIndex: nextIndex,
224
+ ...nextState,
225
+ savedStates,
226
+ };
227
+ });
228
+ return;
229
+ }
147
230
  setQuestionState((prev) => {
148
231
  const isOtherFocused = prev.selectedOptionIndex === options.length - 1;
149
232
  if (isOtherFocused) {
@@ -258,6 +341,20 @@ export const ConfirmationSelector = ({ toolName, toolInput, suggestedPrefix, hid
258
341
  }
259
342
  return;
260
343
  }
344
+ if (key.tab) {
345
+ const currentIndex = availableOptions.indexOf(state.selectedOption);
346
+ const direction = key.shift ? -1 : 1;
347
+ let nextIndex = currentIndex + direction;
348
+ if (nextIndex < 0)
349
+ nextIndex = availableOptions.length - 1;
350
+ if (nextIndex >= availableOptions.length)
351
+ nextIndex = 0;
352
+ setState((prev) => ({
353
+ ...prev,
354
+ selectedOption: availableOptions[nextIndex],
355
+ }));
356
+ return;
357
+ }
261
358
  if (input && !key.ctrl && !key.meta && !("alt" in key && key.alt)) {
262
359
  setState((prev) => {
263
360
  const nextText = prev.alternativeText.slice(0, prev.alternativeCursorPosition) +
@@ -306,8 +403,8 @@ export const ConfirmationSelector = ({ toolName, toolInput, suggestedPrefix, hid
306
403
  ? "[x] "
307
404
  : "[ ] "
308
405
  : "", option.label, option.description ? ` - ${option.description}` : "", isOther && isSelected && (_jsxs(Text, { children: [":", " ", questionState.otherText ? (_jsxs(_Fragment, { children: [questionState.otherText.slice(0, questionState.otherCursorPosition), _jsx(Text, { backgroundColor: "white", color: "black", children: questionState.otherText[questionState.otherCursorPosition] || " " }), questionState.otherText.slice(questionState.otherCursorPosition + 1)] })) : (_jsx(Text, { color: "gray", dimColor: true, children: "[Type your answer...]" }))] }))] }) }, index));
309
- }) }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["Question ", questionState.currentQuestionIndex + 1, " of", " ", questions.length, " \u2022", currentQuestion.multiSelect ? " Space to toggle •" : "", " Use \u2191\u2193 to navigate \u2022 Enter to confirm"] }) })] })), toolName !== ASK_USER_QUESTION_TOOL_NAME && !isExpanded && (_jsxs(_Fragment, { children: [_jsx(Box, { marginTop: 1, children: _jsx(Text, { children: "Do you want to proceed?" }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [toolName === EXIT_PLAN_MODE_TOOL_NAME && (_jsx(Box, { children: _jsxs(Text, { color: state.selectedOption === "clear" ? "black" : "white", backgroundColor: state.selectedOption === "clear" ? "yellow" : undefined, bold: state.selectedOption === "clear", children: [state.selectedOption === "clear" ? "> " : " ", "Yes, clear context and auto-accept edits"] }) }, "clear-option")), _jsx(Box, { children: _jsxs(Text, { color: state.selectedOption === "allow" ? "black" : "white", backgroundColor: state.selectedOption === "allow" ? "yellow" : undefined, bold: state.selectedOption === "allow", children: [state.selectedOption === "allow" ? "> " : " ", toolName === EXIT_PLAN_MODE_TOOL_NAME
406
+ }) }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["Question ", questionState.currentQuestionIndex + 1, " of", " ", questions.length, " \u2022", currentQuestion.multiSelect ? " Space to toggle •" : "", " Use \u2191\u2193 or Tab to navigate \u2022 Enter to confirm"] }) })] })), toolName !== ASK_USER_QUESTION_TOOL_NAME && !isExpanded && (_jsxs(_Fragment, { children: [_jsx(Box, { marginTop: 1, children: _jsx(Text, { children: "Do you want to proceed?" }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [toolName === EXIT_PLAN_MODE_TOOL_NAME && (_jsx(Box, { children: _jsxs(Text, { color: state.selectedOption === "clear" ? "black" : "white", backgroundColor: state.selectedOption === "clear" ? "yellow" : undefined, bold: state.selectedOption === "clear", children: [state.selectedOption === "clear" ? "> " : " ", "Yes, clear context and auto-accept edits"] }) }, "clear-option")), _jsx(Box, { children: _jsxs(Text, { color: state.selectedOption === "allow" ? "black" : "white", backgroundColor: state.selectedOption === "allow" ? "yellow" : undefined, bold: state.selectedOption === "allow", children: [state.selectedOption === "allow" ? "> " : " ", toolName === EXIT_PLAN_MODE_TOOL_NAME
310
407
  ? "Yes, manually approve edits"
311
- : "Yes, proceed"] }) }, "allow-option"), !hidePersistentOption && (_jsx(Box, { children: _jsxs(Text, { color: state.selectedOption === "auto" ? "black" : "white", backgroundColor: state.selectedOption === "auto" ? "yellow" : undefined, bold: state.selectedOption === "auto", children: [state.selectedOption === "auto" ? "> " : " ", getAutoOptionText()] }) }, "auto-option")), _jsx(Box, { children: _jsxs(Text, { color: state.selectedOption === "alternative" ? "black" : "white", backgroundColor: state.selectedOption === "alternative" ? "yellow" : undefined, bold: state.selectedOption === "alternative", children: [state.selectedOption === "alternative" ? "> " : " ", showPlaceholder ? (_jsx(Text, { color: "gray", dimColor: true, children: placeholderText })) : (_jsx(Text, { children: state.alternativeText ? (_jsxs(_Fragment, { children: [state.alternativeText.slice(0, state.alternativeCursorPosition), _jsx(Text, { backgroundColor: "white", color: "black", children: state.alternativeText[state.alternativeCursorPosition] || " " }), state.alternativeText.slice(state.alternativeCursorPosition + 1)] })) : ("Type here to tell Wave what to change") }))] }) }, "alternative-option")] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Use \u2191\u2193 to navigate \u2022 ESC to cancel" }) })] }))] }));
408
+ : "Yes, proceed"] }) }, "allow-option"), !hidePersistentOption && (_jsx(Box, { children: _jsxs(Text, { color: state.selectedOption === "auto" ? "black" : "white", backgroundColor: state.selectedOption === "auto" ? "yellow" : undefined, bold: state.selectedOption === "auto", children: [state.selectedOption === "auto" ? "> " : " ", getAutoOptionText()] }) }, "auto-option")), _jsx(Box, { children: _jsxs(Text, { color: state.selectedOption === "alternative" ? "black" : "white", backgroundColor: state.selectedOption === "alternative" ? "yellow" : undefined, bold: state.selectedOption === "alternative", children: [state.selectedOption === "alternative" ? "> " : " ", showPlaceholder ? (_jsx(Text, { color: "gray", dimColor: true, children: placeholderText })) : (_jsx(Text, { children: state.alternativeText ? (_jsxs(_Fragment, { children: [state.alternativeText.slice(0, state.alternativeCursorPosition), _jsx(Text, { backgroundColor: "white", color: "black", children: state.alternativeText[state.alternativeCursorPosition] || " " }), state.alternativeText.slice(state.alternativeCursorPosition + 1)] })) : ("Type here to tell Wave what to change") }))] }) }, "alternative-option")] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Use \u2191\u2193 or Tab to navigate \u2022 ESC to cancel" }) })] }))] }));
312
409
  };
313
410
  ConfirmationSelector.displayName = "ConfirmationSelector";
@@ -1 +1 @@
1
- {"version":3,"file":"HelpView.d.ts","sourceRoot":"","sources":["../../src/components/HelpView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAmD5C,CAAC"}
1
+ {"version":3,"file":"HelpView.d.ts","sourceRoot":"","sources":["../../src/components/HelpView.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAqD5C,CAAC"}
@@ -15,6 +15,8 @@ export const HelpView = ({ onCancel }) => {
15
15
  { key: "Ctrl+B", description: "Background current task" },
16
16
  { key: "Ctrl+V", description: "Paste image" },
17
17
  { key: "Shift+Tab", description: "Cycle permission mode" },
18
+ { key: "/status", description: "Show agent status and configuration" },
19
+ { key: "/clear", description: "Clear the chat session and terminal" },
18
20
  {
19
21
  key: "Esc",
20
22
  description: "Interrupt AI or command / Cancel selector / Close help",
@@ -1 +1 @@
1
- {"version":3,"file":"HistorySearch.d.ts","sourceRoot":"","sources":["../../src/components/HistorySearch.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAuKtD,CAAC"}
1
+ {"version":3,"file":"HistorySearch.d.ts","sourceRoot":"","sources":["../../src/components/HistorySearch.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAInD,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAkKtD,CAAC"}
@@ -1,33 +1,34 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { useState, useEffect } from "react";
2
+ import React, { useState, useEffect } from "react";
3
3
  import { Box, Text, useInput } from "ink";
4
4
  import { PromptHistoryManager } from "wave-agent-sdk";
5
5
  export const HistorySearch = ({ searchQuery, onSelect, onCancel, }) => {
6
6
  const MAX_VISIBLE_ITEMS = 5;
7
- const [state, setState] = useState({
8
- selectedIndex: 0,
9
- entries: [],
10
- });
7
+ const [selectedIndex, setSelectedIndex] = useState(0);
8
+ const [entries, setEntries] = useState([]);
9
+ const entriesRef = React.useRef([]);
10
+ const selectedIndexRef = React.useRef(0);
11
+ useEffect(() => {
12
+ entriesRef.current = entries;
13
+ }, [entries]);
14
+ useEffect(() => {
15
+ selectedIndexRef.current = selectedIndex;
16
+ }, [selectedIndex]);
11
17
  useEffect(() => {
12
18
  const fetchHistory = async () => {
13
19
  const results = await PromptHistoryManager.searchHistory(searchQuery);
14
20
  const limitedResults = results.slice(0, 20);
15
- setState({
16
- entries: limitedResults,
17
- selectedIndex: 0,
18
- });
21
+ setEntries(limitedResults); // Limit to 20 results
22
+ setSelectedIndex(0);
19
23
  };
20
24
  fetchHistory();
21
25
  }, [searchQuery]);
22
26
  useInput((input, key) => {
23
27
  if (key.return) {
24
- setState((prev) => {
25
- if (prev.entries.length > 0 &&
26
- prev.selectedIndex < prev.entries.length) {
27
- onSelect(prev.entries[prev.selectedIndex].prompt);
28
- }
29
- return prev;
30
- });
28
+ if (entriesRef.current.length > 0 &&
29
+ selectedIndexRef.current < entriesRef.current.length) {
30
+ onSelect(entriesRef.current[selectedIndexRef.current].prompt);
31
+ }
31
32
  return;
32
33
  }
33
34
  if (key.escape) {
@@ -35,21 +36,14 @@ export const HistorySearch = ({ searchQuery, onSelect, onCancel, }) => {
35
36
  return;
36
37
  }
37
38
  if (key.upArrow) {
38
- setState((prev) => ({
39
- ...prev,
40
- selectedIndex: Math.max(0, prev.selectedIndex - 1),
41
- }));
39
+ setSelectedIndex((prev) => Math.max(0, prev - 1));
42
40
  return;
43
41
  }
44
42
  if (key.downArrow) {
45
- setState((prev) => ({
46
- ...prev,
47
- selectedIndex: Math.min(prev.entries.length - 1, prev.selectedIndex + 1),
48
- }));
43
+ setSelectedIndex((prev) => Math.min(entriesRef.current.length - 1, prev + 1));
49
44
  return;
50
45
  }
51
46
  });
52
- const { entries, selectedIndex } = state;
53
47
  if (entries.length === 0) {
54
48
  return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", borderBottom: false, borderLeft: false, borderRight: false, children: [_jsxs(Text, { color: "yellow", children: ["No history found ", searchQuery && `for "${searchQuery}"`] }), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] }));
55
49
  }
@@ -1 +1 @@
1
- {"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAazC,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,CAuN5C,CAAC"}
1
+ {"version":3,"file":"InputBox.d.ts","sourceRoot":"","sources":["../../src/components/InputBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAczC,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,CAgO5C,CAAC"}