wave-code 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +120 -0
- package/bin/wave-code.js +16 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +62 -0
- package/dist/components/App.d.ts +8 -0
- package/dist/components/App.d.ts.map +1 -0
- package/dist/components/App.js +10 -0
- package/dist/components/BashHistorySelector.d.ts +10 -0
- package/dist/components/BashHistorySelector.d.ts.map +1 -0
- package/dist/components/BashHistorySelector.js +83 -0
- package/dist/components/BashShellManager.d.ts +6 -0
- package/dist/components/BashShellManager.d.ts.map +1 -0
- package/dist/components/BashShellManager.js +116 -0
- package/dist/components/ChatInterface.d.ts +3 -0
- package/dist/components/ChatInterface.d.ts.map +1 -0
- package/dist/components/ChatInterface.js +31 -0
- package/dist/components/CommandOutputDisplay.d.ts +9 -0
- package/dist/components/CommandOutputDisplay.d.ts.map +1 -0
- package/dist/components/CommandOutputDisplay.js +40 -0
- package/dist/components/CommandSelector.d.ts +11 -0
- package/dist/components/CommandSelector.d.ts.map +1 -0
- package/dist/components/CommandSelector.js +60 -0
- package/dist/components/CompressDisplay.d.ts +9 -0
- package/dist/components/CompressDisplay.d.ts.map +1 -0
- package/dist/components/CompressDisplay.js +17 -0
- package/dist/components/DiffViewer.d.ts +9 -0
- package/dist/components/DiffViewer.d.ts.map +1 -0
- package/dist/components/DiffViewer.js +221 -0
- package/dist/components/FileSelector.d.ts +13 -0
- package/dist/components/FileSelector.d.ts.map +1 -0
- package/dist/components/FileSelector.js +48 -0
- package/dist/components/InputBox.d.ts +23 -0
- package/dist/components/InputBox.d.ts.map +1 -0
- package/dist/components/InputBox.js +124 -0
- package/dist/components/McpManager.d.ts +10 -0
- package/dist/components/McpManager.d.ts.map +1 -0
- package/dist/components/McpManager.js +123 -0
- package/dist/components/MemoryDisplay.d.ts +8 -0
- package/dist/components/MemoryDisplay.d.ts.map +1 -0
- package/dist/components/MemoryDisplay.js +25 -0
- package/dist/components/MemoryTypeSelector.d.ts +8 -0
- package/dist/components/MemoryTypeSelector.d.ts.map +1 -0
- package/dist/components/MemoryTypeSelector.js +38 -0
- package/dist/components/MessageList.d.ts +12 -0
- package/dist/components/MessageList.d.ts.map +1 -0
- package/dist/components/MessageList.js +36 -0
- package/dist/components/ToolResultDisplay.d.ts +9 -0
- package/dist/components/ToolResultDisplay.d.ts.map +1 -0
- package/dist/components/ToolResultDisplay.js +52 -0
- package/dist/contexts/useAppConfig.d.ts +11 -0
- package/dist/contexts/useAppConfig.d.ts.map +1 -0
- package/dist/contexts/useAppConfig.js +13 -0
- package/dist/contexts/useChat.d.ts +36 -0
- package/dist/contexts/useChat.d.ts.map +1 -0
- package/dist/contexts/useChat.js +208 -0
- package/dist/hooks/useBashHistorySelector.d.ts +15 -0
- package/dist/hooks/useBashHistorySelector.d.ts.map +1 -0
- package/dist/hooks/useBashHistorySelector.js +61 -0
- package/dist/hooks/useCommandSelector.d.ts +24 -0
- package/dist/hooks/useCommandSelector.d.ts.map +1 -0
- package/dist/hooks/useCommandSelector.js +98 -0
- package/dist/hooks/useFileSelector.d.ts +16 -0
- package/dist/hooks/useFileSelector.d.ts.map +1 -0
- package/dist/hooks/useFileSelector.js +174 -0
- package/dist/hooks/useImageManager.d.ts +13 -0
- package/dist/hooks/useImageManager.d.ts.map +1 -0
- package/dist/hooks/useImageManager.js +46 -0
- package/dist/hooks/useInputHistory.d.ts +11 -0
- package/dist/hooks/useInputHistory.d.ts.map +1 -0
- package/dist/hooks/useInputHistory.js +64 -0
- package/dist/hooks/useInputKeyboardHandler.d.ts +83 -0
- package/dist/hooks/useInputKeyboardHandler.d.ts.map +1 -0
- package/dist/hooks/useInputKeyboardHandler.js +507 -0
- package/dist/hooks/useInputState.d.ts +14 -0
- package/dist/hooks/useInputState.d.ts.map +1 -0
- package/dist/hooks/useInputState.js +57 -0
- package/dist/hooks/useMemoryTypeSelector.d.ts +9 -0
- package/dist/hooks/useMemoryTypeSelector.d.ts.map +1 -0
- package/dist/hooks/useMemoryTypeSelector.js +27 -0
- package/dist/hooks/usePagination.d.ts +20 -0
- package/dist/hooks/usePagination.d.ts.map +1 -0
- package/dist/hooks/usePagination.js +168 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +91 -0
- package/dist/plain-cli.d.ts +7 -0
- package/dist/plain-cli.d.ts.map +1 -0
- package/dist/plain-cli.js +49 -0
- package/dist/utils/clipboard.d.ts +22 -0
- package/dist/utils/clipboard.d.ts.map +1 -0
- package/dist/utils/clipboard.js +347 -0
- package/dist/utils/constants.d.ts +17 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +18 -0
- package/dist/utils/logger.d.ts +72 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +245 -0
- package/package.json +60 -0
- package/src/cli.tsx +82 -0
- package/src/components/App.tsx +31 -0
- package/src/components/BashHistorySelector.tsx +163 -0
- package/src/components/BashShellManager.tsx +306 -0
- package/src/components/ChatInterface.tsx +88 -0
- package/src/components/CommandOutputDisplay.tsx +81 -0
- package/src/components/CommandSelector.tsx +144 -0
- package/src/components/CompressDisplay.tsx +58 -0
- package/src/components/DiffViewer.tsx +321 -0
- package/src/components/FileSelector.tsx +137 -0
- package/src/components/InputBox.tsx +310 -0
- package/src/components/McpManager.tsx +328 -0
- package/src/components/MemoryDisplay.tsx +62 -0
- package/src/components/MemoryTypeSelector.tsx +96 -0
- package/src/components/MessageList.tsx +215 -0
- package/src/components/ToolResultDisplay.tsx +138 -0
- package/src/contexts/useAppConfig.tsx +32 -0
- package/src/contexts/useChat.tsx +300 -0
- package/src/hooks/useBashHistorySelector.ts +77 -0
- package/src/hooks/useCommandSelector.ts +131 -0
- package/src/hooks/useFileSelector.ts +227 -0
- package/src/hooks/useImageManager.ts +64 -0
- package/src/hooks/useInputHistory.ts +74 -0
- package/src/hooks/useInputKeyboardHandler.ts +778 -0
- package/src/hooks/useInputState.ts +66 -0
- package/src/hooks/useMemoryTypeSelector.ts +40 -0
- package/src/hooks/usePagination.ts +203 -0
- package/src/index.ts +108 -0
- package/src/plain-cli.ts +66 -0
- package/src/utils/clipboard.ts +384 -0
- package/src/utils/constants.ts +22 -0
- package/src/utils/logger.ts +301 -0
package/README.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Wave Code
|
|
2
|
+
|
|
3
|
+
CLI-based code assistant powered by AI, built with React and Ink.
|
|
4
|
+
|
|
5
|
+
This is the frontend UI package of the Wave workspace, providing an interactive command-line interface for AI-powered development assistance.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- Interactive CLI interface built with React and Ink
|
|
10
|
+
- Real-time chat interface with AI assistant
|
|
11
|
+
- File browser and editor integration
|
|
12
|
+
- Command execution and output display
|
|
13
|
+
- Session management and restoration
|
|
14
|
+
- Memory context management
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install wave-code
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Environment Configuration
|
|
23
|
+
|
|
24
|
+
Before use, you need to configure the following environment variables for AI model authentication:
|
|
25
|
+
|
|
26
|
+
### Required Environment Variables
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# AI Gateway access token (required)
|
|
30
|
+
export AIGW_TOKEN="your_token_here"
|
|
31
|
+
|
|
32
|
+
# AI Gateway API URL (required)
|
|
33
|
+
export AIGW_URL="https://your-api-gateway-url.com"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Optional Environment Variables
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Specify AI model (optional, defaults to system configured model)
|
|
40
|
+
export AIGW_MODEL="gemini-2.5-flash"
|
|
41
|
+
|
|
42
|
+
# Specify fast AI model (optional, for quick response scenarios)
|
|
43
|
+
export AIGW_FAST_MODEL="gemini-1.5-flash"
|
|
44
|
+
|
|
45
|
+
# Log level (optional, defaults to info)
|
|
46
|
+
export LOG_LEVEL="debug"
|
|
47
|
+
|
|
48
|
+
# Log file path (optional)
|
|
49
|
+
export LOG_FILE="/path/to/your/logfile.log"
|
|
50
|
+
|
|
51
|
+
# Maximum log file size (optional, defaults to 10MB)
|
|
52
|
+
export LOG_MAX_FILE_SIZE="10485760"
|
|
53
|
+
|
|
54
|
+
# Token limit (optional, defaults to 64000)
|
|
55
|
+
export TOKEN_LIMIT="64000"
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Usage
|
|
60
|
+
|
|
61
|
+
### Full Command
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Start the CLI
|
|
65
|
+
wave-code
|
|
66
|
+
|
|
67
|
+
# Continue from last session
|
|
68
|
+
wave-code --continue
|
|
69
|
+
|
|
70
|
+
# Restore specific session
|
|
71
|
+
wave-code --restore session_id
|
|
72
|
+
|
|
73
|
+
# List available sessions
|
|
74
|
+
wave-code --list-sessions
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Short Command (wave)
|
|
78
|
+
|
|
79
|
+
For convenience, you can also use the shorter `wave` command:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Start the CLI (equivalent to wave-code)
|
|
83
|
+
wave
|
|
84
|
+
|
|
85
|
+
# Continue from last session
|
|
86
|
+
wave --continue
|
|
87
|
+
|
|
88
|
+
# Restore specific session
|
|
89
|
+
wave --restore session_id
|
|
90
|
+
|
|
91
|
+
# List available sessions
|
|
92
|
+
wave --list-sessions
|
|
93
|
+
|
|
94
|
+
# Show help
|
|
95
|
+
wave --help
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
The `wave` command is an alias for `wave-code` and supports all the same options and functionality.
|
|
99
|
+
|
|
100
|
+
## Development
|
|
101
|
+
|
|
102
|
+
This package depends on `wave-agent-sdk` for core functionality including AI services, tools, and utilities.
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Install dependencies
|
|
106
|
+
pnpm install
|
|
107
|
+
|
|
108
|
+
# Start development
|
|
109
|
+
pnpm dev
|
|
110
|
+
|
|
111
|
+
# Build
|
|
112
|
+
pnpm build
|
|
113
|
+
|
|
114
|
+
# Test
|
|
115
|
+
pnpm test
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
MIT
|
package/bin/wave-code.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Import and start the CLI
|
|
4
|
+
import("../dist/index.js")
|
|
5
|
+
.then(async ({ main }) => {
|
|
6
|
+
try {
|
|
7
|
+
await main();
|
|
8
|
+
} catch (err) {
|
|
9
|
+
console.error("Failed to start CLI:", err);
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
})
|
|
13
|
+
.catch((err) => {
|
|
14
|
+
console.error("Failed to import CLI module:", err);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
});
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +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;CAC/B;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAuEjE"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { render } from "ink";
|
|
3
|
+
import { App } from "./components/App.js";
|
|
4
|
+
import { cleanupLogs } from "./utils/logger.js";
|
|
5
|
+
export async function startCli(options) {
|
|
6
|
+
const { restoreSessionId, continueLastSession } = options;
|
|
7
|
+
// 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
|
+
}
|
|
34
|
+
};
|
|
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
|
+
// Render the application
|
|
48
|
+
const { unmount } = render(_jsx(App, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession }));
|
|
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
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
// Return a promise that never resolves to keep the CLI running
|
|
61
|
+
return new Promise(() => { });
|
|
62
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../src/components/App.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAK1B,UAAU,QAAQ;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAUD,eAAO,MAAM,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC,QAAQ,CAYlC,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ChatInterface } from "./ChatInterface.js";
|
|
3
|
+
import { ChatProvider } from "../contexts/useChat.js";
|
|
4
|
+
import { AppProvider } from "../contexts/useAppConfig.js";
|
|
5
|
+
const AppWithProviders = () => {
|
|
6
|
+
return (_jsx(ChatProvider, { children: _jsx(ChatInterface, {}) }));
|
|
7
|
+
};
|
|
8
|
+
export const App = ({ restoreSessionId, continueLastSession, }) => {
|
|
9
|
+
return (_jsx(AppProvider, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, children: _jsx(AppWithProviders, {}) }));
|
|
10
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface BashHistorySelectorProps {
|
|
3
|
+
searchQuery: string;
|
|
4
|
+
workdir: string;
|
|
5
|
+
onSelect: (command: string) => void;
|
|
6
|
+
onExecute: (command: string) => void;
|
|
7
|
+
onCancel: () => void;
|
|
8
|
+
}
|
|
9
|
+
export declare const BashHistorySelector: React.FC<BashHistorySelectorProps>;
|
|
10
|
+
//# sourceMappingURL=BashHistorySelector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BashHistorySelector.d.ts","sourceRoot":"","sources":["../../src/components/BashHistorySelector.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAKnD,MAAM,WAAW,wBAAwB;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAqJlE,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import { Box, Text, useInput } from "ink";
|
|
4
|
+
import { searchBashHistory } from "wave-agent-sdk";
|
|
5
|
+
import { logger } from "../utils/logger.js";
|
|
6
|
+
export const BashHistorySelector = ({ searchQuery, workdir, onSelect, onExecute, onCancel, }) => {
|
|
7
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
8
|
+
const [commands, setCommands] = useState([]);
|
|
9
|
+
// Search bash history
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
const results = searchBashHistory(searchQuery, 10, workdir);
|
|
12
|
+
setCommands(results);
|
|
13
|
+
setSelectedIndex(0);
|
|
14
|
+
logger.debug("Bash history search:", {
|
|
15
|
+
searchQuery,
|
|
16
|
+
workdir,
|
|
17
|
+
resultCount: results.length,
|
|
18
|
+
});
|
|
19
|
+
}, [searchQuery, workdir]);
|
|
20
|
+
useInput((input, key) => {
|
|
21
|
+
logger.debug("BashHistorySelector useInput:", {
|
|
22
|
+
input,
|
|
23
|
+
key,
|
|
24
|
+
commandsLength: commands.length,
|
|
25
|
+
selectedIndex,
|
|
26
|
+
});
|
|
27
|
+
if (key.return) {
|
|
28
|
+
if (commands.length > 0 && selectedIndex < commands.length) {
|
|
29
|
+
const selectedCommand = commands[selectedIndex];
|
|
30
|
+
onExecute(selectedCommand.command);
|
|
31
|
+
}
|
|
32
|
+
else if (commands.length === 0 && searchQuery.trim()) {
|
|
33
|
+
// When no history records match, execute the search query as a new command
|
|
34
|
+
onExecute(searchQuery.trim());
|
|
35
|
+
}
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (key.tab) {
|
|
39
|
+
if (commands.length > 0 && selectedIndex < commands.length) {
|
|
40
|
+
const selectedCommand = commands[selectedIndex];
|
|
41
|
+
onSelect(selectedCommand.command);
|
|
42
|
+
}
|
|
43
|
+
else if (commands.length === 0 && searchQuery.trim()) {
|
|
44
|
+
// When no history records match, insert the search query
|
|
45
|
+
onSelect(searchQuery.trim());
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (key.escape) {
|
|
50
|
+
onCancel();
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (key.upArrow) {
|
|
54
|
+
setSelectedIndex(Math.max(0, selectedIndex - 1));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (key.downArrow) {
|
|
58
|
+
setSelectedIndex(Math.min(commands.length - 1, selectedIndex + 1));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
if (commands.length === 0) {
|
|
63
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", padding: 1, marginBottom: 1, children: [_jsxs(Text, { color: "yellow", children: ["No bash history found ", searchQuery && `for "${searchQuery}"`] }), searchQuery.trim() && (_jsxs(Text, { color: "green", children: ["Press Enter to execute: ", searchQuery] })), searchQuery.trim() && (_jsxs(Text, { color: "blue", children: ["Press Tab to insert: ", searchQuery] })), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] }));
|
|
64
|
+
}
|
|
65
|
+
const formatTimestamp = (timestamp) => {
|
|
66
|
+
const date = new Date(timestamp);
|
|
67
|
+
const now = new Date();
|
|
68
|
+
const diffMs = now.getTime() - date.getTime();
|
|
69
|
+
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
|
|
70
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
71
|
+
if (diffDays > 0) {
|
|
72
|
+
return `${diffDays}d ago`;
|
|
73
|
+
}
|
|
74
|
+
else if (diffHours > 0) {
|
|
75
|
+
return `${diffHours}h ago`;
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
const diffMinutes = Math.floor(diffMs / (1000 * 60));
|
|
79
|
+
return diffMinutes > 0 ? `${diffMinutes}m ago` : "just now";
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "blue", padding: 1, gap: 1, marginBottom: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "blue", bold: true, children: ["Bash History ", searchQuery && `(filtering: "${searchQuery}")`] }) }), commands.map((cmd, index) => (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: index === selectedIndex ? "black" : "white", backgroundColor: index === selectedIndex ? "blue" : undefined, children: cmd.command }), index === selectedIndex && (_jsx(Box, { marginLeft: 4, flexDirection: "column", children: _jsxs(Text, { color: "gray", dimColor: true, children: [formatTimestamp(cmd.timestamp), cmd.workdir !== workdir && ` • in ${cmd.workdir}`] }) }))] }, index))), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: "Use \u2191\u2193 to navigate, Enter to execute, Tab to insert, Escape to cancel" }) })] }));
|
|
83
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BashShellManager.d.ts","sourceRoot":"","sources":["../../src/components/BashShellManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAanD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAgS5D,CAAC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import { Box, Text, useInput } from "ink";
|
|
4
|
+
import { useChat } from "../contexts/useChat.js";
|
|
5
|
+
export const BashShellManager = ({ onCancel, }) => {
|
|
6
|
+
const { backgroundShells, getBackgroundShellOutput, killBackgroundShell } = useChat();
|
|
7
|
+
const [shells, setShells] = useState([]);
|
|
8
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
9
|
+
const [viewMode, setViewMode] = useState("list");
|
|
10
|
+
const [detailShellId, setDetailShellId] = useState(null);
|
|
11
|
+
const [detailOutput, setDetailOutput] = useState(null);
|
|
12
|
+
// Convert backgroundShells to local BashShell format
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
setShells(backgroundShells.map((shell) => ({
|
|
15
|
+
id: shell.id,
|
|
16
|
+
command: shell.command,
|
|
17
|
+
status: shell.status,
|
|
18
|
+
startTime: shell.startTime,
|
|
19
|
+
exitCode: shell.exitCode,
|
|
20
|
+
runtime: shell.runtime,
|
|
21
|
+
})));
|
|
22
|
+
}, [backgroundShells]);
|
|
23
|
+
// Load detail output for selected shell
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (viewMode === "detail" && detailShellId) {
|
|
26
|
+
const output = getBackgroundShellOutput(detailShellId);
|
|
27
|
+
setDetailOutput(output);
|
|
28
|
+
}
|
|
29
|
+
}, [viewMode, detailShellId, getBackgroundShellOutput]);
|
|
30
|
+
const formatDuration = (ms) => {
|
|
31
|
+
if (ms < 1000)
|
|
32
|
+
return `${ms}ms`;
|
|
33
|
+
if (ms < 60000)
|
|
34
|
+
return `${Math.round(ms / 1000)}s`;
|
|
35
|
+
const minutes = Math.floor(ms / 60000);
|
|
36
|
+
const seconds = Math.round((ms % 60000) / 1000);
|
|
37
|
+
return `${minutes}m ${seconds}s`;
|
|
38
|
+
};
|
|
39
|
+
const formatTime = (timestamp) => {
|
|
40
|
+
return new Date(timestamp).toLocaleTimeString();
|
|
41
|
+
};
|
|
42
|
+
const killShell = (shellId) => {
|
|
43
|
+
killBackgroundShell(shellId);
|
|
44
|
+
};
|
|
45
|
+
useInput((input, key) => {
|
|
46
|
+
if (viewMode === "list") {
|
|
47
|
+
// List mode navigation
|
|
48
|
+
if (key.return) {
|
|
49
|
+
if (shells.length > 0 && selectedIndex < shells.length) {
|
|
50
|
+
const selectedShell = shells[selectedIndex];
|
|
51
|
+
setDetailShellId(selectedShell.id);
|
|
52
|
+
setViewMode("detail");
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (key.escape) {
|
|
57
|
+
onCancel();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (key.upArrow) {
|
|
61
|
+
setSelectedIndex(Math.max(0, selectedIndex - 1));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (key.downArrow) {
|
|
65
|
+
setSelectedIndex(Math.min(shells.length - 1, selectedIndex + 1));
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (input === "k" && shells.length > 0 && selectedIndex < shells.length) {
|
|
69
|
+
const selectedShell = shells[selectedIndex];
|
|
70
|
+
if (selectedShell.status === "running") {
|
|
71
|
+
killShell(selectedShell.id);
|
|
72
|
+
}
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else if (viewMode === "detail") {
|
|
77
|
+
// Detail mode navigation
|
|
78
|
+
if (key.escape) {
|
|
79
|
+
setViewMode("list");
|
|
80
|
+
setDetailShellId(null);
|
|
81
|
+
setDetailOutput(null);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (input === "k" && detailShellId) {
|
|
85
|
+
const shell = shells.find((s) => s.id === detailShellId);
|
|
86
|
+
if (shell && shell.status === "running") {
|
|
87
|
+
killShell(detailShellId);
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
if (viewMode === "detail" && detailShellId && detailOutput) {
|
|
94
|
+
const shell = shells.find((s) => s.id === detailShellId);
|
|
95
|
+
if (!shell) {
|
|
96
|
+
setViewMode("list");
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", padding: 1, gap: 1, marginBottom: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "cyan", bold: true, children: ["Background Shell Details: ", shell.id] }) }), _jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Command:" }), " ", shell.command] }) }), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Status:" }), " ", shell.status, shell.exitCode !== undefined &&
|
|
100
|
+
` (exit code: ${shell.exitCode})`] }) }), _jsx(Box, { children: _jsxs(Text, { children: [_jsx(Text, { color: "blue", children: "Started:" }), " ", formatTime(shell.startTime), shell.runtime !== undefined && (_jsxs(Text, { children: [" ", "| ", _jsx(Text, { color: "blue", children: "Runtime:" }), " ", formatDuration(shell.runtime)] }))] }) })] }), detailOutput.stdout && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "green", bold: true, children: "STDOUT (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: "STDERR:" }), _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: [shell.status === "running" ? "k to kill · " : "", "Esc to go back"] }) })] }));
|
|
101
|
+
}
|
|
102
|
+
if (!backgroundShells) {
|
|
103
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", padding: 1, marginBottom: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "Background Bash Shells" }), _jsx(Text, { children: "Background bash shells not available" }), _jsx(Text, { dimColor: true, children: "Press Escape to close" })] }));
|
|
104
|
+
}
|
|
105
|
+
if (shells.length === 0) {
|
|
106
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", padding: 1, marginBottom: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "Background Bash Shells" }), _jsx(Text, { children: "No background shells found" }), _jsx(Text, { dimColor: true, children: "Press Escape to close" })] }));
|
|
107
|
+
}
|
|
108
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", padding: 1, gap: 1, marginBottom: 1, children: [_jsx(Box, { children: _jsx(Text, { color: "cyan", bold: true, children: "Background Bash Shells" }) }), _jsx(Text, { dimColor: true, children: "Select a shell to view details" }), shells.map((shell, index) => (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: index === selectedIndex ? "black" : "white", backgroundColor: index === selectedIndex ? "cyan" : undefined, children: [index === selectedIndex ? "▶ " : " ", index + 1, ".", " ", shell.command.length > 50
|
|
109
|
+
? shell.command.substring(0, 47) + "..."
|
|
110
|
+
: shell.command, _jsxs(Text, { color: shell.status === "running"
|
|
111
|
+
? "green"
|
|
112
|
+
: shell.status === "completed"
|
|
113
|
+
? "blue"
|
|
114
|
+
: "red", children: [" ", "(", shell.status, ")"] })] }), index === selectedIndex && (_jsx(Box, { marginLeft: 4, flexDirection: "column", children: _jsxs(Text, { color: "gray", dimColor: true, children: ["ID: ", shell.id, " | Started: ", formatTime(shell.startTime), shell.runtime !== undefined &&
|
|
115
|
+
` | Runtime: ${formatDuration(shell.runtime)}`, shell.exitCode !== undefined && ` | Exit: ${shell.exitCode}`] }) }))] }, shell.id))), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["\u2191/\u2193 to select \u00B7 Enter to view \u00B7", " ", shells[selectedIndex]?.status === "running" ? "k to kill · " : "", "Esc to close"] }) })] }));
|
|
116
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../src/components/ChatInterface.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAOjD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAgFjC,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useEffect } from "react";
|
|
3
|
+
import { Box } from "ink";
|
|
4
|
+
import { MessageList } from "./MessageList.js";
|
|
5
|
+
import { InputBox } from "./InputBox.js";
|
|
6
|
+
import { useChat } from "../contexts/useChat.js";
|
|
7
|
+
export const ChatInterface = () => {
|
|
8
|
+
const { messages, isLoading, isCommandRunning, userInputHistory, isCompressing, sendMessage, abortMessage, saveMemory, mcpServers, connectMcpServer, disconnectMcpServer, isExpanded, latestTotalTokens, slashCommands, hasSlashCommand, } = useChat();
|
|
9
|
+
// Create a ref to store messages in expanded mode
|
|
10
|
+
const expandedMessagesRef = useRef([]);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
// Only sync when collapsed
|
|
13
|
+
if (!isExpanded) {
|
|
14
|
+
expandedMessagesRef.current = messages.map((message, index) => {
|
|
15
|
+
// If it's the last message, deep copy its blocks
|
|
16
|
+
if (index === messages.length - 1) {
|
|
17
|
+
return {
|
|
18
|
+
...message,
|
|
19
|
+
blocks: message.blocks.map((block) => ({ ...block })),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return message;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}, [isExpanded, messages]);
|
|
26
|
+
return (_jsxs(Box, { flexDirection: "column", height: "100%", children: [_jsx(Box, { flexGrow: 1, flexDirection: "column", paddingX: 1, children: isExpanded ? (
|
|
27
|
+
// Expanded mode uses messages from ref, loading and tokens are hardcoded to false and 0
|
|
28
|
+
_jsx(MessageList, { messages: expandedMessagesRef.current, isLoading: false, isCommandRunning: false, latestTotalTokens: 0, isExpanded: true })) : (
|
|
29
|
+
// Normal mode uses real-time state
|
|
30
|
+
_jsx(MessageList, { messages: messages, isLoading: isLoading, isCommandRunning: isCommandRunning, isCompressing: isCompressing, latestTotalTokens: latestTotalTokens, isExpanded: false })) }), !isExpanded && (_jsx(InputBox, { isLoading: isLoading, isCommandRunning: isCommandRunning, userInputHistory: userInputHistory, sendMessage: sendMessage, abortMessage: abortMessage, saveMemory: saveMemory, mcpServers: mcpServers, connectMcpServer: connectMcpServer, disconnectMcpServer: disconnectMcpServer, slashCommands: slashCommands, hasSlashCommand: hasSlashCommand }))] }));
|
|
31
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { CommandOutputBlock } from "wave-agent-sdk";
|
|
3
|
+
interface CommandOutputDisplayProps {
|
|
4
|
+
block: CommandOutputBlock;
|
|
5
|
+
isExpanded?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const CommandOutputDisplay: React.FC<CommandOutputDisplayProps>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=CommandOutputDisplay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommandOutputDisplay.d.ts","sourceRoot":"","sources":["../../src/components/CommandOutputDisplay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEzD,UAAU,yBAAyB;IACjC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAuEpE,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import { Box, Text } from "ink";
|
|
4
|
+
export const CommandOutputDisplay = ({ block, isExpanded = false, }) => {
|
|
5
|
+
const { command, output, isRunning, exitCode } = block;
|
|
6
|
+
const [isOverflowing, setIsOverflowing] = useState(false);
|
|
7
|
+
const MAX_LINES = 10; // Set maximum display lines
|
|
8
|
+
// Detect if content is overflowing
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
if (output) {
|
|
11
|
+
const lines = output.split("\n");
|
|
12
|
+
setIsOverflowing(!isExpanded && lines.length > MAX_LINES);
|
|
13
|
+
}
|
|
14
|
+
}, [output, isExpanded]);
|
|
15
|
+
const getStatusColor = () => {
|
|
16
|
+
if (isRunning)
|
|
17
|
+
return "yellow";
|
|
18
|
+
if (exitCode === 0)
|
|
19
|
+
return "green";
|
|
20
|
+
if (exitCode !== null && exitCode !== 0)
|
|
21
|
+
return "red";
|
|
22
|
+
return "gray"; // Unknown state
|
|
23
|
+
};
|
|
24
|
+
const getStatusText = () => {
|
|
25
|
+
if (isRunning)
|
|
26
|
+
return "🔄";
|
|
27
|
+
if (exitCode === 0)
|
|
28
|
+
return "✅";
|
|
29
|
+
if (exitCode === 130)
|
|
30
|
+
return "⚠️"; // SIGINT (Ctrl+C)
|
|
31
|
+
if (exitCode !== null && exitCode !== 0)
|
|
32
|
+
return "❌";
|
|
33
|
+
return ""; // Don't display text for unknown state
|
|
34
|
+
};
|
|
35
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: "cyan", children: "$ " }), _jsx(Text, { color: "white", children: command }), _jsxs(Text, { color: getStatusColor(), children: [" ", getStatusText()] })] }), output && (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Box, { paddingLeft: 2, borderLeft: true, borderColor: "gray", flexDirection: "column", height: isExpanded
|
|
36
|
+
? undefined
|
|
37
|
+
: Math.min(output.split("\n").length, MAX_LINES), overflow: "hidden", children: _jsx(Text, { color: "gray", children: isOverflowing
|
|
38
|
+
? output.split("\n").slice(-MAX_LINES).join("\n")
|
|
39
|
+
: output }) }), isOverflowing && (_jsx(Box, { paddingLeft: 2, marginTop: 1, children: _jsxs(Text, { color: "yellow", dimColor: true, children: ["Content truncated (", output.split("\n").length, " lines total, showing last ", MAX_LINES, " lines)"] }) }))] }))] }));
|
|
40
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { SlashCommand } from "wave-agent-sdk";
|
|
3
|
+
export interface CommandSelectorProps {
|
|
4
|
+
searchQuery: string;
|
|
5
|
+
onSelect: (command: string) => void;
|
|
6
|
+
onInsert?: (command: string) => void;
|
|
7
|
+
onCancel: () => void;
|
|
8
|
+
commands?: SlashCommand[];
|
|
9
|
+
}
|
|
10
|
+
export declare const CommandSelector: React.FC<CommandSelectorProps>;
|
|
11
|
+
//# sourceMappingURL=CommandSelector.d.ts.map
|
|
@@ -0,0 +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;AAiBnD,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,CAoH1D,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { Box, Text, useInput } from "ink";
|
|
4
|
+
const AVAILABLE_COMMANDS = [
|
|
5
|
+
{
|
|
6
|
+
id: "bashes",
|
|
7
|
+
name: "bashes",
|
|
8
|
+
description: "View and manage background bash shells",
|
|
9
|
+
handler: () => { }, // Handler here won't be used, actual processing is in the hook
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
id: "mcp",
|
|
13
|
+
name: "mcp",
|
|
14
|
+
description: "View and manage MCP servers",
|
|
15
|
+
handler: () => { }, // Handler here won't be used, actual processing is in the hook
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
export const CommandSelector = ({ searchQuery, onSelect, onInsert, onCancel, commands = [], // Default to empty array
|
|
19
|
+
}) => {
|
|
20
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
21
|
+
// Merge agent commands and local commands
|
|
22
|
+
const allCommands = [...commands, ...AVAILABLE_COMMANDS];
|
|
23
|
+
// Filter command list
|
|
24
|
+
const filteredCommands = allCommands.filter((command) => !searchQuery ||
|
|
25
|
+
command.name.toLowerCase().includes(searchQuery.toLowerCase()));
|
|
26
|
+
useInput((input, key) => {
|
|
27
|
+
if (key.return) {
|
|
28
|
+
if (filteredCommands.length > 0 &&
|
|
29
|
+
selectedIndex < filteredCommands.length) {
|
|
30
|
+
const selectedCommand = filteredCommands[selectedIndex].name;
|
|
31
|
+
onSelect(selectedCommand);
|
|
32
|
+
}
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (key.tab && onInsert) {
|
|
36
|
+
if (filteredCommands.length > 0 &&
|
|
37
|
+
selectedIndex < filteredCommands.length) {
|
|
38
|
+
const selectedCommand = filteredCommands[selectedIndex].name;
|
|
39
|
+
onInsert(selectedCommand);
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (key.escape) {
|
|
44
|
+
onCancel();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (key.upArrow) {
|
|
48
|
+
setSelectedIndex(Math.max(0, selectedIndex - 1));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (key.downArrow) {
|
|
52
|
+
setSelectedIndex(Math.min(filteredCommands.length - 1, selectedIndex + 1));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
if (filteredCommands.length === 0) {
|
|
57
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "yellow", padding: 1, marginBottom: 1, children: [_jsxs(Text, { color: "yellow", children: ["No commands found for \"", searchQuery, "\""] }), _jsx(Text, { dimColor: true, children: "Press Escape to cancel" })] }));
|
|
58
|
+
}
|
|
59
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "magenta", padding: 1, gap: 1, marginBottom: 1, children: [_jsx(Box, { children: _jsxs(Text, { color: "magenta", bold: true, children: ["Command Selector ", searchQuery && `(filtering: "${searchQuery}")`] }) }), filteredCommands.map((command, index) => (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: index === selectedIndex ? "black" : "white", backgroundColor: index === selectedIndex ? "magenta" : undefined, children: [index === selectedIndex ? "▶ " : " ", "/", command.name] }), index === selectedIndex && (_jsx(Box, { marginLeft: 4, children: _jsx(Text, { color: "gray", dimColor: true, children: command.description }) }))] }, command.name))), _jsx(Box, { children: _jsxs(Text, { dimColor: true, children: ["\u2191\u2193 navigate \u2022 Enter execute \u2022 ", onInsert ? "Tab insert • " : "", "Esc cancel"] }) })] }));
|
|
60
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { CompressBlock } from "wave-agent-sdk";
|
|
3
|
+
interface CompressDisplayProps {
|
|
4
|
+
block: CompressBlock;
|
|
5
|
+
isExpanded?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare const CompressDisplay: React.FC<CompressDisplayProps>;
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=CompressDisplay.d.ts.map
|