wave-code 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +69 -95
- package/dist/components/MemoryDisplay.js +1 -1
- package/dist/components/MemoryTypeSelector.js +1 -1
- package/dist/components/MessageList.d.ts.map +1 -1
- package/dist/components/MessageList.js +2 -1
- package/dist/components/SubagentBlock.d.ts +1 -1
- package/dist/components/SubagentBlock.d.ts.map +1 -1
- package/dist/components/SubagentBlock.js +12 -2
- package/dist/components/ToolResultDisplay.js +1 -1
- package/dist/contexts/useChat.d.ts +2 -1
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +18 -0
- package/dist/hooks/useInputManager.d.ts +91 -0
- package/dist/hooks/useInputManager.d.ts.map +1 -0
- package/dist/hooks/useInputManager.js +319 -0
- package/dist/index.js +9 -9
- package/dist/managers/InputManager.d.ts +169 -0
- package/dist/managers/InputManager.d.ts.map +1 -0
- package/dist/managers/InputManager.js +806 -0
- package/dist/print-cli.d.ts +7 -0
- package/dist/print-cli.d.ts.map +1 -0
- package/dist/{plain-cli.js → print-cli.js} +21 -2
- package/dist/utils/constants.d.ts +1 -1
- package/dist/utils/constants.js +1 -1
- package/dist/utils/fileSearch.d.ts +20 -0
- package/dist/utils/fileSearch.d.ts.map +1 -0
- package/dist/utils/fileSearch.js +102 -0
- package/dist/utils/logger.js +3 -3
- package/dist/utils/usageSummary.d.ts +27 -0
- package/dist/utils/usageSummary.d.ts.map +1 -0
- package/dist/utils/usageSummary.js +82 -0
- package/package.json +2 -2
- package/src/components/InputBox.tsx +114 -153
- package/src/components/MemoryDisplay.tsx +1 -1
- package/src/components/MemoryTypeSelector.tsx +1 -1
- package/src/components/MessageList.tsx +14 -10
- package/src/components/SubagentBlock.tsx +14 -3
- package/src/components/ToolResultDisplay.tsx +1 -1
- package/src/contexts/useChat.tsx +23 -0
- package/src/hooks/useInputManager.ts +443 -0
- package/src/index.ts +9 -9
- package/src/managers/InputManager.ts +1102 -0
- package/src/{plain-cli.ts → print-cli.ts} +21 -3
- package/src/utils/constants.ts +1 -1
- package/src/utils/fileSearch.ts +133 -0
- package/src/utils/logger.ts +3 -3
- package/src/utils/usageSummary.ts +125 -0
- package/dist/hooks/useBashHistorySelector.d.ts +0 -15
- package/dist/hooks/useBashHistorySelector.d.ts.map +0 -1
- package/dist/hooks/useBashHistorySelector.js +0 -61
- package/dist/hooks/useCommandSelector.d.ts +0 -24
- package/dist/hooks/useCommandSelector.d.ts.map +0 -1
- package/dist/hooks/useCommandSelector.js +0 -98
- package/dist/hooks/useFileSelector.d.ts +0 -16
- package/dist/hooks/useFileSelector.d.ts.map +0 -1
- package/dist/hooks/useFileSelector.js +0 -174
- package/dist/hooks/useImageManager.d.ts +0 -13
- package/dist/hooks/useImageManager.d.ts.map +0 -1
- package/dist/hooks/useImageManager.js +0 -46
- package/dist/hooks/useInputHistory.d.ts +0 -11
- package/dist/hooks/useInputHistory.d.ts.map +0 -1
- package/dist/hooks/useInputHistory.js +0 -64
- package/dist/hooks/useInputKeyboardHandler.d.ts +0 -83
- package/dist/hooks/useInputKeyboardHandler.d.ts.map +0 -1
- package/dist/hooks/useInputKeyboardHandler.js +0 -507
- package/dist/hooks/useInputState.d.ts +0 -14
- package/dist/hooks/useInputState.d.ts.map +0 -1
- package/dist/hooks/useInputState.js +0 -57
- package/dist/hooks/useMemoryTypeSelector.d.ts +0 -9
- package/dist/hooks/useMemoryTypeSelector.d.ts.map +0 -1
- package/dist/hooks/useMemoryTypeSelector.js +0 -27
- package/dist/plain-cli.d.ts +0 -7
- package/dist/plain-cli.d.ts.map +0 -1
- package/src/hooks/useBashHistorySelector.ts +0 -77
- package/src/hooks/useCommandSelector.ts +0 -131
- package/src/hooks/useFileSelector.ts +0 -227
- package/src/hooks/useImageManager.ts +0 -64
- package/src/hooks/useInputHistory.ts +0 -74
- package/src/hooks/useInputKeyboardHandler.ts +0 -778
- package/src/hooks/useInputState.ts +0 -66
- package/src/hooks/useMemoryTypeSelector.ts +0 -40
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { Agent, AgentCallbacks } from "wave-agent-sdk";
|
|
2
2
|
import { logger } from "./utils/logger.js";
|
|
3
|
+
import { displayUsageSummary } from "./utils/usageSummary.js";
|
|
3
4
|
|
|
4
|
-
export interface
|
|
5
|
+
export interface PrintCliOptions {
|
|
5
6
|
restoreSessionId?: string;
|
|
6
7
|
continueLastSession?: boolean;
|
|
7
8
|
message?: string;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
export async function
|
|
11
|
+
export async function startPrintCli(options: PrintCliOptions): Promise<void> {
|
|
11
12
|
const { restoreSessionId, continueLastSession, message } = options;
|
|
12
13
|
|
|
13
14
|
if (
|
|
@@ -16,7 +17,7 @@ export async function startPlainCli(options: PlainCliOptions): Promise<void> {
|
|
|
16
17
|
!restoreSessionId
|
|
17
18
|
) {
|
|
18
19
|
console.error(
|
|
19
|
-
"
|
|
20
|
+
"Print mode requires a message: use --print 'your message' or -p 'your message'",
|
|
20
21
|
);
|
|
21
22
|
process.exit(1);
|
|
22
23
|
}
|
|
@@ -47,12 +48,29 @@ export async function startPlainCli(options: PlainCliOptions): Promise<void> {
|
|
|
47
48
|
await agent.sendMessage(message);
|
|
48
49
|
}
|
|
49
50
|
|
|
51
|
+
// Display usage summary before exit
|
|
52
|
+
try {
|
|
53
|
+
const usages = agent.usages;
|
|
54
|
+
const sessionFilePath = agent.sessionFilePath;
|
|
55
|
+
displayUsageSummary(usages, sessionFilePath);
|
|
56
|
+
} catch {
|
|
57
|
+
// Silently ignore usage summary errors
|
|
58
|
+
}
|
|
59
|
+
|
|
50
60
|
// Destroy agent and exit after sendMessage completes
|
|
51
61
|
agent.destroy();
|
|
52
62
|
process.exit(0);
|
|
53
63
|
} catch (error) {
|
|
54
64
|
console.error("Failed to send message:", error);
|
|
55
65
|
if (agent!) {
|
|
66
|
+
// Display usage summary even on error
|
|
67
|
+
try {
|
|
68
|
+
const usages = agent.usages;
|
|
69
|
+
const sessionFilePath = agent.sessionFilePath;
|
|
70
|
+
displayUsageSummary(usages, sessionFilePath);
|
|
71
|
+
} catch {
|
|
72
|
+
// Silently ignore usage summary errors
|
|
73
|
+
}
|
|
56
74
|
agent.destroy();
|
|
57
75
|
}
|
|
58
76
|
process.exit(1);
|
package/src/utils/constants.ts
CHANGED
|
@@ -19,4 +19,4 @@ export const LOG_FILE = path.join(DATA_DIRECTORY, "app.log");
|
|
|
19
19
|
/**
|
|
20
20
|
* Pagination related constants
|
|
21
21
|
*/
|
|
22
|
-
export const MESSAGES_PER_PAGE =
|
|
22
|
+
export const MESSAGES_PER_PAGE = 15; // Number of messages displayed per page
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { glob } from "glob";
|
|
2
|
+
import { getGlobIgnorePatterns } from "wave-agent-sdk";
|
|
3
|
+
import * as fs from "fs";
|
|
4
|
+
import * as path from "path";
|
|
5
|
+
|
|
6
|
+
export interface FileItem {
|
|
7
|
+
path: string;
|
|
8
|
+
type: "file" | "directory";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Check if path is a directory
|
|
13
|
+
*/
|
|
14
|
+
export const isDirectory = (filePath: string): boolean => {
|
|
15
|
+
try {
|
|
16
|
+
const fullPath = path.isAbsolute(filePath)
|
|
17
|
+
? filePath
|
|
18
|
+
: path.join(process.cwd(), filePath);
|
|
19
|
+
return fs.statSync(fullPath).isDirectory();
|
|
20
|
+
} catch {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Convert string paths to FileItem objects
|
|
27
|
+
*/
|
|
28
|
+
export const convertToFileItems = (paths: string[]): FileItem[] => {
|
|
29
|
+
return paths.map((filePath) => ({
|
|
30
|
+
path: filePath,
|
|
31
|
+
type: isDirectory(filePath) ? "directory" : "file",
|
|
32
|
+
}));
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Search files and directories using glob patterns
|
|
37
|
+
*/
|
|
38
|
+
export const searchFiles = async (
|
|
39
|
+
query: string,
|
|
40
|
+
options?: {
|
|
41
|
+
maxResults?: number;
|
|
42
|
+
workingDirectory?: string;
|
|
43
|
+
},
|
|
44
|
+
): Promise<FileItem[]> => {
|
|
45
|
+
const { maxResults = 10, workingDirectory = process.cwd() } = options || {};
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
let files: string[] = [];
|
|
49
|
+
let directories: string[] = [];
|
|
50
|
+
|
|
51
|
+
const globOptions = {
|
|
52
|
+
ignore: getGlobIgnorePatterns(workingDirectory),
|
|
53
|
+
maxDepth: 10,
|
|
54
|
+
nocase: true, // Case insensitive
|
|
55
|
+
dot: true, // Include hidden files and directories
|
|
56
|
+
cwd: workingDirectory, // Specify search root directory
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
if (!query.trim()) {
|
|
60
|
+
// When query is empty, show some common file types and directories
|
|
61
|
+
const commonPatterns = [
|
|
62
|
+
"**/*.ts",
|
|
63
|
+
"**/*.tsx",
|
|
64
|
+
"**/*.js",
|
|
65
|
+
"**/*.jsx",
|
|
66
|
+
"**/*.json",
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
// Search files
|
|
70
|
+
const filePromises = commonPatterns.map((pattern) =>
|
|
71
|
+
glob(pattern, { ...globOptions, nodir: true }),
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
// Search directories (only search first level to avoid too many results)
|
|
75
|
+
const dirPromises = [glob("*/", { ...globOptions, maxDepth: 1 })];
|
|
76
|
+
|
|
77
|
+
const fileResults = await Promise.all(filePromises);
|
|
78
|
+
const dirResults = await Promise.all(dirPromises);
|
|
79
|
+
|
|
80
|
+
files = fileResults.flat();
|
|
81
|
+
directories = dirResults.flat().map((dir) => {
|
|
82
|
+
// glob returns string type paths, remove trailing slash
|
|
83
|
+
return String(dir).replace(/\/$/, "");
|
|
84
|
+
});
|
|
85
|
+
} else {
|
|
86
|
+
// Build multiple glob patterns to support more flexible search
|
|
87
|
+
const filePatterns = [
|
|
88
|
+
// Match files with filenames containing query
|
|
89
|
+
`**/*${query}*`,
|
|
90
|
+
// Match files with query in path (match directory names)
|
|
91
|
+
`**/${query}*/**/*`,
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
const dirPatterns = [
|
|
95
|
+
// Match directory names containing query
|
|
96
|
+
`**/*${query}*/`,
|
|
97
|
+
// Match directories containing query in path
|
|
98
|
+
`**/${query}*/`,
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
// Search files
|
|
102
|
+
const filePromises = filePatterns.map((pattern) =>
|
|
103
|
+
glob(pattern, { ...globOptions, nodir: true }),
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
// Search directories
|
|
107
|
+
const dirPromises = dirPatterns.map((pattern) =>
|
|
108
|
+
glob(pattern, { ...globOptions, nodir: false }),
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const fileResults = await Promise.all(filePromises);
|
|
112
|
+
const dirResults = await Promise.all(dirPromises);
|
|
113
|
+
|
|
114
|
+
files = fileResults.flat();
|
|
115
|
+
directories = dirResults.flat().map((dir) => {
|
|
116
|
+
// glob returns string type paths, remove trailing slash
|
|
117
|
+
return String(dir).replace(/\/$/, "");
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Deduplicate and merge files and directories
|
|
122
|
+
const uniqueFiles = Array.from(new Set(files));
|
|
123
|
+
const uniqueDirectories = Array.from(new Set(directories));
|
|
124
|
+
const allPaths = [...uniqueDirectories, ...uniqueFiles]; // Directories first
|
|
125
|
+
|
|
126
|
+
// Limit to maximum results and convert to FileItem
|
|
127
|
+
const fileItems = convertToFileItems(allPaths.slice(0, maxResults));
|
|
128
|
+
return fileItems;
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.error("Glob search error:", error);
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
};
|
package/src/utils/logger.ts
CHANGED
|
@@ -264,7 +264,7 @@ const truncateLogFileIfNeeded = (config: LogCleanupConfig): void => {
|
|
|
264
264
|
|
|
265
265
|
// Record truncation operation
|
|
266
266
|
const removedLines = lines.length - keepLines;
|
|
267
|
-
logger.
|
|
267
|
+
logger.debug(
|
|
268
268
|
`Log file truncated: removed ${removedLines} lines, kept last ${keepLines} lines`,
|
|
269
269
|
);
|
|
270
270
|
}
|
|
@@ -289,7 +289,7 @@ export const cleanupLogs = async (
|
|
|
289
289
|
|
|
290
290
|
const config = { ...getCleanupConfig(), ...customConfig };
|
|
291
291
|
|
|
292
|
-
logger.
|
|
292
|
+
logger.debug("Starting log cleanup...", {
|
|
293
293
|
maxFileSize: config.maxFileSize,
|
|
294
294
|
keepLines: config.keepLines,
|
|
295
295
|
});
|
|
@@ -297,5 +297,5 @@ export const cleanupLogs = async (
|
|
|
297
297
|
// Truncate current log file (if needed)
|
|
298
298
|
truncateLogFileIfNeeded(config);
|
|
299
299
|
|
|
300
|
-
logger.
|
|
300
|
+
logger.debug("Log cleanup completed");
|
|
301
301
|
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { Usage } from "wave-agent-sdk";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Token summary by model
|
|
5
|
+
*/
|
|
6
|
+
export interface TokenSummary {
|
|
7
|
+
model: string;
|
|
8
|
+
prompt_tokens: number;
|
|
9
|
+
completion_tokens: number;
|
|
10
|
+
total_tokens: number;
|
|
11
|
+
operations: {
|
|
12
|
+
agent_calls: number;
|
|
13
|
+
compressions: number;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Calculate token usage summary by model from usage array
|
|
19
|
+
* @param usages Array of usage data from agent operations
|
|
20
|
+
* @returns Array of token summaries grouped by model
|
|
21
|
+
*/
|
|
22
|
+
export function calculateTokenSummary(
|
|
23
|
+
usages: Usage[],
|
|
24
|
+
): Record<string, TokenSummary> {
|
|
25
|
+
const summaryMap = new Map<string, TokenSummary>();
|
|
26
|
+
|
|
27
|
+
for (const usage of usages) {
|
|
28
|
+
const model = usage.model || "unknown";
|
|
29
|
+
|
|
30
|
+
if (!summaryMap.has(model)) {
|
|
31
|
+
summaryMap.set(model, {
|
|
32
|
+
model,
|
|
33
|
+
prompt_tokens: 0,
|
|
34
|
+
completion_tokens: 0,
|
|
35
|
+
total_tokens: 0,
|
|
36
|
+
operations: {
|
|
37
|
+
agent_calls: 0,
|
|
38
|
+
compressions: 0,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const summary = summaryMap.get(model)!;
|
|
44
|
+
summary.prompt_tokens += usage.prompt_tokens;
|
|
45
|
+
summary.completion_tokens += usage.completion_tokens;
|
|
46
|
+
summary.total_tokens += usage.total_tokens;
|
|
47
|
+
|
|
48
|
+
// Track operation types
|
|
49
|
+
if (usage.operation_type === "agent") {
|
|
50
|
+
summary.operations.agent_calls += 1;
|
|
51
|
+
} else if (usage.operation_type === "compress") {
|
|
52
|
+
summary.operations.compressions += 1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Convert Map to Record and sort by total tokens
|
|
57
|
+
const result: Record<string, TokenSummary> = {};
|
|
58
|
+
const sortedEntries = Array.from(summaryMap.entries()).sort(
|
|
59
|
+
(a, b) => b[1].total_tokens - a[1].total_tokens,
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
for (const [model, summary] of sortedEntries) {
|
|
63
|
+
result[model] = summary;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Display usage summary in a formatted way
|
|
71
|
+
* @param usages Array of usage data from agent operations
|
|
72
|
+
* @param sessionFilePath Optional session file path to display
|
|
73
|
+
*/
|
|
74
|
+
export function displayUsageSummary(
|
|
75
|
+
usages: Usage[],
|
|
76
|
+
sessionFilePath?: string,
|
|
77
|
+
): void {
|
|
78
|
+
if (usages.length === 0) {
|
|
79
|
+
return; // No usage data to display
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const summaries = calculateTokenSummary(usages);
|
|
83
|
+
|
|
84
|
+
console.log("\nToken Usage Summary:");
|
|
85
|
+
console.log("==================");
|
|
86
|
+
|
|
87
|
+
if (sessionFilePath) {
|
|
88
|
+
console.log(`Session: ${sessionFilePath}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let totalPrompt = 0;
|
|
92
|
+
let totalCompletion = 0;
|
|
93
|
+
let totalTokens = 0;
|
|
94
|
+
let totalAgentCalls = 0;
|
|
95
|
+
let totalCompressions = 0;
|
|
96
|
+
|
|
97
|
+
for (const [, summary] of Object.entries(summaries)) {
|
|
98
|
+
console.log(`Model: ${summary.model}`);
|
|
99
|
+
console.log(` Prompt tokens: ${summary.prompt_tokens.toLocaleString()}`);
|
|
100
|
+
console.log(
|
|
101
|
+
` Completion tokens: ${summary.completion_tokens.toLocaleString()}`,
|
|
102
|
+
);
|
|
103
|
+
console.log(` Total tokens: ${summary.total_tokens.toLocaleString()}`);
|
|
104
|
+
console.log(
|
|
105
|
+
` Operations: ${summary.operations.agent_calls} agent calls, ${summary.operations.compressions} compressions`,
|
|
106
|
+
);
|
|
107
|
+
console.log();
|
|
108
|
+
|
|
109
|
+
totalPrompt += summary.prompt_tokens;
|
|
110
|
+
totalCompletion += summary.completion_tokens;
|
|
111
|
+
totalTokens += summary.total_tokens;
|
|
112
|
+
totalAgentCalls += summary.operations.agent_calls;
|
|
113
|
+
totalCompressions += summary.operations.compressions;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (Object.keys(summaries).length > 1) {
|
|
117
|
+
console.log("Overall Total:");
|
|
118
|
+
console.log(` Prompt tokens: ${totalPrompt.toLocaleString()}`);
|
|
119
|
+
console.log(` Completion tokens: ${totalCompletion.toLocaleString()}`);
|
|
120
|
+
console.log(` Total tokens: ${totalTokens.toLocaleString()}`);
|
|
121
|
+
console.log(
|
|
122
|
+
` Operations: ${totalAgentCalls} agent calls, ${totalCompressions} compressions`,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export declare const useBashHistorySelector: () => {
|
|
2
|
-
showBashHistorySelector: boolean;
|
|
3
|
-
bashHistorySearchQuery: string;
|
|
4
|
-
activateBashHistorySelector: (position: number) => void;
|
|
5
|
-
handleBashHistorySelect: (command: string, inputText: string, cursorPosition: number) => {
|
|
6
|
-
newInput: string;
|
|
7
|
-
newCursorPosition: number;
|
|
8
|
-
};
|
|
9
|
-
handleBashHistoryExecute: (command: string) => string;
|
|
10
|
-
handleCancelBashHistorySelect: () => void;
|
|
11
|
-
updateBashHistorySearchQuery: (query: string) => void;
|
|
12
|
-
checkForExclamationDeletion: (cursorPosition: number) => boolean;
|
|
13
|
-
exclamationPosition: number;
|
|
14
|
-
};
|
|
15
|
-
//# sourceMappingURL=useBashHistorySelector.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useBashHistorySelector.d.ts","sourceRoot":"","sources":["../../src/hooks/useBashHistorySelector.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,sBAAsB;;;4CAK0B,MAAM;uCAOrD,MAAM,aAAa,MAAM,kBAAkB,MAAM;;;;wCAyBN,MAAM;;0CAOJ,MAAM;kDAK5C,MAAM;;CAyB1B,CAAC"}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { useState, useCallback } from "react";
|
|
2
|
-
export const useBashHistorySelector = () => {
|
|
3
|
-
const [showBashHistorySelector, setShowBashHistorySelector] = useState(false);
|
|
4
|
-
const [exclamationPosition, setExclamationPosition] = useState(-1);
|
|
5
|
-
const [bashHistorySearchQuery, setBashHistorySearchQuery] = useState("");
|
|
6
|
-
const activateBashHistorySelector = useCallback((position) => {
|
|
7
|
-
setShowBashHistorySelector(true);
|
|
8
|
-
setExclamationPosition(position);
|
|
9
|
-
setBashHistorySearchQuery("");
|
|
10
|
-
}, []);
|
|
11
|
-
const handleBashHistorySelect = useCallback((command, inputText, cursorPosition) => {
|
|
12
|
-
if (exclamationPosition >= 0) {
|
|
13
|
-
// Replace ! and search query with selected command
|
|
14
|
-
const beforeExclamation = inputText.substring(0, exclamationPosition);
|
|
15
|
-
const afterQuery = inputText.substring(cursorPosition);
|
|
16
|
-
const newInput = beforeExclamation + `!${command}` + afterQuery;
|
|
17
|
-
const newCursorPosition = beforeExclamation.length + command.length + 1;
|
|
18
|
-
setShowBashHistorySelector(false);
|
|
19
|
-
setExclamationPosition(-1);
|
|
20
|
-
setBashHistorySearchQuery("");
|
|
21
|
-
return { newInput, newCursorPosition };
|
|
22
|
-
}
|
|
23
|
-
return { newInput: inputText, newCursorPosition: cursorPosition };
|
|
24
|
-
}, [exclamationPosition]);
|
|
25
|
-
const handleCancelBashHistorySelect = useCallback(() => {
|
|
26
|
-
setShowBashHistorySelector(false);
|
|
27
|
-
setExclamationPosition(-1);
|
|
28
|
-
setBashHistorySearchQuery("");
|
|
29
|
-
}, []);
|
|
30
|
-
const handleBashHistoryExecute = useCallback((command) => {
|
|
31
|
-
setShowBashHistorySelector(false);
|
|
32
|
-
setExclamationPosition(-1);
|
|
33
|
-
setBashHistorySearchQuery("");
|
|
34
|
-
return command; // Return command to execute
|
|
35
|
-
}, []);
|
|
36
|
-
const updateBashHistorySearchQuery = useCallback((query) => {
|
|
37
|
-
setBashHistorySearchQuery(query);
|
|
38
|
-
}, []);
|
|
39
|
-
const checkForExclamationDeletion = useCallback((cursorPosition) => {
|
|
40
|
-
if (showBashHistorySelector && cursorPosition <= exclamationPosition) {
|
|
41
|
-
handleCancelBashHistorySelect();
|
|
42
|
-
return true;
|
|
43
|
-
}
|
|
44
|
-
return false;
|
|
45
|
-
}, [
|
|
46
|
-
showBashHistorySelector,
|
|
47
|
-
exclamationPosition,
|
|
48
|
-
handleCancelBashHistorySelect,
|
|
49
|
-
]);
|
|
50
|
-
return {
|
|
51
|
-
showBashHistorySelector,
|
|
52
|
-
bashHistorySearchQuery,
|
|
53
|
-
activateBashHistorySelector,
|
|
54
|
-
handleBashHistorySelect,
|
|
55
|
-
handleBashHistoryExecute,
|
|
56
|
-
handleCancelBashHistorySelect,
|
|
57
|
-
updateBashHistorySearchQuery,
|
|
58
|
-
checkForExclamationDeletion,
|
|
59
|
-
exclamationPosition,
|
|
60
|
-
};
|
|
61
|
-
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export interface UseCommandSelectorParams {
|
|
2
|
-
onShowBashManager?: () => void;
|
|
3
|
-
onShowMcpManager?: () => void;
|
|
4
|
-
sendMessage?: (content: string) => Promise<void>;
|
|
5
|
-
hasSlashCommand?: (commandId: string) => boolean;
|
|
6
|
-
}
|
|
7
|
-
export declare const useCommandSelector: ({ onShowBashManager, onShowMcpManager, sendMessage, hasSlashCommand, }: UseCommandSelectorParams) => {
|
|
8
|
-
showCommandSelector: boolean;
|
|
9
|
-
commandSearchQuery: string;
|
|
10
|
-
activateCommandSelector: (position: number) => void;
|
|
11
|
-
handleCommandSelect: (command: string, inputText: string, cursorPosition: number) => {
|
|
12
|
-
newInput: string;
|
|
13
|
-
newCursorPosition: number;
|
|
14
|
-
};
|
|
15
|
-
handleCommandInsert: (command: string, inputText: string, cursorPosition: number) => {
|
|
16
|
-
newInput: string;
|
|
17
|
-
newCursorPosition: number;
|
|
18
|
-
};
|
|
19
|
-
handleCancelCommandSelect: () => void;
|
|
20
|
-
updateCommandSearchQuery: (query: string) => void;
|
|
21
|
-
checkForSlashDeletion: (cursorPosition: number) => boolean;
|
|
22
|
-
slashPosition: number;
|
|
23
|
-
};
|
|
24
|
-
//# sourceMappingURL=useCommandSelector.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useCommandSelector.d.ts","sourceRoot":"","sources":["../../src/hooks/useCommandSelector.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,wBAAwB;IACvC,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC/B,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;CAClD;AAED,eAAO,MAAM,kBAAkB,GAAI,wEAKhC,wBAAwB;;;wCAK8B,MAAM;mCA2BjD,MAAM,aAAa,MAAM,kBAAkB,MAAM;;;;mCApBjD,MAAM,aAAa,MAAM,kBAAkB,MAAM;;;;;sCA8ER,MAAM;4CAKxC,MAAM;;CAqB1B,CAAC"}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { useState, useCallback } from "react";
|
|
2
|
-
export const useCommandSelector = ({ onShowBashManager, onShowMcpManager, sendMessage, hasSlashCommand, }) => {
|
|
3
|
-
const [showCommandSelector, setShowCommandSelector] = useState(false);
|
|
4
|
-
const [slashPosition, setSlashPosition] = useState(-1);
|
|
5
|
-
const [commandSearchQuery, setCommandSearchQuery] = useState("");
|
|
6
|
-
const activateCommandSelector = useCallback((position) => {
|
|
7
|
-
setShowCommandSelector(true);
|
|
8
|
-
setSlashPosition(position);
|
|
9
|
-
setCommandSearchQuery("");
|
|
10
|
-
}, []);
|
|
11
|
-
const handleCommandInsert = useCallback((command, inputText, cursorPosition) => {
|
|
12
|
-
if (slashPosition >= 0) {
|
|
13
|
-
// Replace content from / to current cursor position with /command_name + space
|
|
14
|
-
const beforeSlash = inputText.substring(0, slashPosition);
|
|
15
|
-
const afterQuery = inputText.substring(cursorPosition);
|
|
16
|
-
const newInput = beforeSlash + `/${command} ` + afterQuery;
|
|
17
|
-
const newCursorPosition = beforeSlash.length + command.length + 2; // +2 for "/" and " "
|
|
18
|
-
setShowCommandSelector(false);
|
|
19
|
-
setSlashPosition(-1);
|
|
20
|
-
setCommandSearchQuery("");
|
|
21
|
-
return { newInput, newCursorPosition };
|
|
22
|
-
}
|
|
23
|
-
return { newInput: inputText, newCursorPosition: cursorPosition };
|
|
24
|
-
}, [slashPosition]);
|
|
25
|
-
const handleCommandSelect = useCallback((command, inputText, cursorPosition) => {
|
|
26
|
-
if (slashPosition >= 0) {
|
|
27
|
-
// Replace command part, keep other content
|
|
28
|
-
const beforeSlash = inputText.substring(0, slashPosition);
|
|
29
|
-
const afterQuery = inputText.substring(cursorPosition);
|
|
30
|
-
const newInput = beforeSlash + afterQuery;
|
|
31
|
-
const newCursorPosition = beforeSlash.length;
|
|
32
|
-
// Execute command asynchronously
|
|
33
|
-
(async () => {
|
|
34
|
-
// First check if it's an agent command
|
|
35
|
-
let commandExecuted = false;
|
|
36
|
-
if (sendMessage && hasSlashCommand && hasSlashCommand(command)) {
|
|
37
|
-
// Execute complete command (replace partial input with complete command name)
|
|
38
|
-
const fullCommand = `/${command}`;
|
|
39
|
-
try {
|
|
40
|
-
await sendMessage(fullCommand);
|
|
41
|
-
commandExecuted = true;
|
|
42
|
-
}
|
|
43
|
-
catch (error) {
|
|
44
|
-
console.error("Failed to execute slash command:", error);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
// If not an agent command or execution failed, check local commands
|
|
48
|
-
if (!commandExecuted) {
|
|
49
|
-
if (command === "bashes" && onShowBashManager) {
|
|
50
|
-
onShowBashManager();
|
|
51
|
-
commandExecuted = true;
|
|
52
|
-
}
|
|
53
|
-
else if (command === "mcp" && onShowMcpManager) {
|
|
54
|
-
onShowMcpManager();
|
|
55
|
-
commandExecuted = true;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
})();
|
|
59
|
-
setShowCommandSelector(false);
|
|
60
|
-
setSlashPosition(-1);
|
|
61
|
-
setCommandSearchQuery("");
|
|
62
|
-
return { newInput, newCursorPosition };
|
|
63
|
-
}
|
|
64
|
-
return { newInput: inputText, newCursorPosition: cursorPosition };
|
|
65
|
-
}, [
|
|
66
|
-
slashPosition,
|
|
67
|
-
onShowBashManager,
|
|
68
|
-
onShowMcpManager,
|
|
69
|
-
sendMessage,
|
|
70
|
-
hasSlashCommand,
|
|
71
|
-
]);
|
|
72
|
-
const handleCancelCommandSelect = useCallback(() => {
|
|
73
|
-
setShowCommandSelector(false);
|
|
74
|
-
setSlashPosition(-1);
|
|
75
|
-
setCommandSearchQuery("");
|
|
76
|
-
}, []);
|
|
77
|
-
const updateCommandSearchQuery = useCallback((query) => {
|
|
78
|
-
setCommandSearchQuery(query);
|
|
79
|
-
}, []);
|
|
80
|
-
const checkForSlashDeletion = useCallback((cursorPosition) => {
|
|
81
|
-
if (showCommandSelector && cursorPosition <= slashPosition) {
|
|
82
|
-
handleCancelCommandSelect();
|
|
83
|
-
return true;
|
|
84
|
-
}
|
|
85
|
-
return false;
|
|
86
|
-
}, [showCommandSelector, slashPosition, handleCancelCommandSelect]);
|
|
87
|
-
return {
|
|
88
|
-
showCommandSelector,
|
|
89
|
-
commandSearchQuery,
|
|
90
|
-
activateCommandSelector,
|
|
91
|
-
handleCommandSelect,
|
|
92
|
-
handleCommandInsert,
|
|
93
|
-
handleCancelCommandSelect,
|
|
94
|
-
updateCommandSearchQuery,
|
|
95
|
-
checkForSlashDeletion,
|
|
96
|
-
slashPosition,
|
|
97
|
-
};
|
|
98
|
-
};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { FileItem } from "../components/FileSelector.js";
|
|
2
|
-
export declare const useFileSelector: () => {
|
|
3
|
-
showFileSelector: boolean;
|
|
4
|
-
filteredFiles: FileItem[];
|
|
5
|
-
searchQuery: string;
|
|
6
|
-
activateFileSelector: (position: number) => void;
|
|
7
|
-
handleFileSelect: (filePath: string, inputText: string, cursorPosition: number) => {
|
|
8
|
-
newInput: string;
|
|
9
|
-
newCursorPosition: number;
|
|
10
|
-
};
|
|
11
|
-
handleCancelFileSelect: () => void;
|
|
12
|
-
updateSearchQuery: (query: string) => void;
|
|
13
|
-
checkForAtDeletion: (cursorPosition: number) => boolean;
|
|
14
|
-
atPosition: number;
|
|
15
|
-
};
|
|
16
|
-
//# sourceMappingURL=useFileSelector.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useFileSelector.d.ts","sourceRoot":"","sources":["../../src/hooks/useFileSelector.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAEzD,eAAO,MAAM,eAAe;;;;qCA2Jb,MAAM;iCAWN,MAAM,aAAa,MAAM,kBAAkB,MAAM;;;;;+BA2BhB,MAAM;yCAKjC,MAAM;;CAqB1B,CAAC"}
|