wave-agent-sdk 0.0.7 → 0.0.10
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/agent.d.ts +105 -24
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +438 -53
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/managers/aiManager.d.ts +18 -7
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +254 -142
- package/dist/managers/backgroundBashManager.d.ts.map +1 -1
- package/dist/managers/backgroundBashManager.js +11 -9
- package/dist/managers/hookManager.d.ts +6 -6
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +81 -39
- package/dist/managers/liveConfigManager.d.ts +95 -0
- package/dist/managers/liveConfigManager.d.ts.map +1 -0
- package/dist/managers/liveConfigManager.js +442 -0
- package/dist/managers/lspManager.d.ts +43 -0
- package/dist/managers/lspManager.d.ts.map +1 -0
- package/dist/managers/lspManager.js +326 -0
- package/dist/managers/messageManager.d.ts +41 -24
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +184 -73
- package/dist/managers/permissionManager.d.ts +66 -0
- package/dist/managers/permissionManager.d.ts.map +1 -0
- package/dist/managers/permissionManager.js +208 -0
- package/dist/managers/skillManager.d.ts +1 -0
- package/dist/managers/skillManager.d.ts.map +1 -1
- package/dist/managers/skillManager.js +2 -1
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +4 -2
- package/dist/managers/subagentManager.d.ts +42 -6
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +213 -62
- package/dist/managers/toolManager.d.ts +38 -1
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +66 -2
- package/dist/services/aiService.d.ts +15 -5
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +446 -77
- package/dist/services/configurationService.d.ts +116 -0
- package/dist/services/configurationService.d.ts.map +1 -0
- package/dist/services/configurationService.js +585 -0
- package/dist/services/fileWatcher.d.ts +69 -0
- package/dist/services/fileWatcher.d.ts.map +1 -0
- package/dist/services/fileWatcher.js +212 -0
- package/dist/services/hook.d.ts +5 -40
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +47 -109
- package/dist/services/jsonlHandler.d.ts +71 -0
- package/dist/services/jsonlHandler.d.ts.map +1 -0
- package/dist/services/jsonlHandler.js +236 -0
- package/dist/services/memory.d.ts.map +1 -1
- package/dist/services/memory.js +33 -11
- package/dist/services/session.d.ts +116 -52
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +415 -143
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +77 -17
- package/dist/tools/deleteFileTool.d.ts.map +1 -1
- package/dist/tools/deleteFileTool.js +27 -1
- package/dist/tools/editTool.d.ts.map +1 -1
- package/dist/tools/editTool.js +33 -8
- package/dist/tools/lspTool.d.ts +6 -0
- package/dist/tools/lspTool.d.ts.map +1 -0
- package/dist/tools/lspTool.js +589 -0
- package/dist/tools/multiEditTool.d.ts.map +1 -1
- package/dist/tools/multiEditTool.js +30 -10
- package/dist/tools/readTool.d.ts.map +1 -1
- package/dist/tools/readTool.js +113 -3
- package/dist/tools/skillTool.js +2 -2
- package/dist/tools/todoWriteTool.d.ts.map +1 -1
- package/dist/tools/todoWriteTool.js +23 -0
- package/dist/tools/types.d.ts +11 -8
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/writeTool.d.ts.map +1 -1
- package/dist/tools/writeTool.js +30 -15
- package/dist/types/commands.d.ts +4 -1
- package/dist/types/commands.d.ts.map +1 -1
- package/dist/types/config.d.ts +4 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/configuration.d.ts +69 -0
- package/dist/types/configuration.d.ts.map +1 -0
- package/dist/types/configuration.js +8 -0
- package/dist/types/core.d.ts +45 -0
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/environment.d.ts +83 -0
- package/dist/types/environment.d.ts.map +1 -0
- package/dist/types/environment.js +21 -0
- package/dist/types/fileSearch.d.ts +5 -0
- package/dist/types/fileSearch.d.ts.map +1 -0
- package/dist/types/fileSearch.js +1 -0
- package/dist/types/hooks.d.ts +18 -3
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +8 -8
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +7 -0
- package/dist/types/lsp.d.ts +90 -0
- package/dist/types/lsp.d.ts.map +1 -0
- package/dist/types/lsp.js +4 -0
- package/dist/types/messaging.d.ts +19 -12
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/permissions.d.ts +35 -0
- package/dist/types/permissions.d.ts.map +1 -0
- package/dist/types/permissions.js +12 -0
- package/dist/types/session.d.ts +15 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +7 -0
- package/dist/types/skills.d.ts +1 -0
- package/dist/types/skills.d.ts.map +1 -1
- package/dist/types/tools.d.ts +35 -0
- package/dist/types/tools.d.ts.map +1 -0
- package/dist/types/tools.js +4 -0
- package/dist/utils/abortUtils.d.ts +34 -0
- package/dist/utils/abortUtils.d.ts.map +1 -0
- package/dist/utils/abortUtils.js +92 -0
- package/dist/utils/bashHistory.d.ts +4 -0
- package/dist/utils/bashHistory.d.ts.map +1 -1
- package/dist/utils/bashHistory.js +48 -30
- package/dist/utils/builtinSubagents.d.ts +7 -0
- package/dist/utils/builtinSubagents.d.ts.map +1 -0
- package/dist/utils/builtinSubagents.js +65 -0
- package/dist/utils/cacheControlUtils.d.ts +96 -0
- package/dist/utils/cacheControlUtils.d.ts.map +1 -0
- package/dist/utils/cacheControlUtils.js +324 -0
- package/dist/utils/commandPathResolver.d.ts +52 -0
- package/dist/utils/commandPathResolver.d.ts.map +1 -0
- package/dist/utils/commandPathResolver.js +145 -0
- package/dist/utils/configPaths.d.ts +85 -0
- package/dist/utils/configPaths.d.ts.map +1 -0
- package/dist/utils/configPaths.js +121 -0
- package/dist/utils/constants.d.ts +1 -13
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +2 -14
- package/dist/utils/convertMessagesForAPI.d.ts +2 -1
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
- package/dist/utils/convertMessagesForAPI.js +39 -18
- package/dist/utils/customCommands.d.ts.map +1 -1
- package/dist/utils/customCommands.js +66 -21
- package/dist/utils/fileSearch.d.ts +14 -0
- package/dist/utils/fileSearch.d.ts.map +1 -0
- package/dist/utils/fileSearch.js +88 -0
- package/dist/utils/fileUtils.d.ts +27 -0
- package/dist/utils/fileUtils.d.ts.map +1 -0
- package/dist/utils/fileUtils.js +145 -0
- package/dist/utils/globalLogger.d.ts +88 -0
- package/dist/utils/globalLogger.d.ts.map +1 -0
- package/dist/utils/globalLogger.js +120 -0
- package/dist/utils/largeOutputHandler.d.ts +15 -0
- package/dist/utils/largeOutputHandler.d.ts.map +1 -0
- package/dist/utils/largeOutputHandler.js +40 -0
- package/dist/utils/markdownParser.d.ts.map +1 -1
- package/dist/utils/markdownParser.js +1 -17
- package/dist/utils/mcpUtils.d.ts.map +1 -1
- package/dist/utils/mcpUtils.js +25 -3
- package/dist/utils/messageOperations.d.ts +20 -18
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +30 -38
- package/dist/utils/pathEncoder.d.ts +108 -0
- package/dist/utils/pathEncoder.d.ts.map +1 -0
- package/dist/utils/pathEncoder.js +279 -0
- package/dist/utils/subagentParser.d.ts +2 -2
- package/dist/utils/subagentParser.d.ts.map +1 -1
- package/dist/utils/subagentParser.js +12 -8
- package/dist/utils/tokenCalculation.d.ts +26 -0
- package/dist/utils/tokenCalculation.d.ts.map +1 -0
- package/dist/utils/tokenCalculation.js +36 -0
- package/dist/utils/tokenEstimator.d.ts +39 -0
- package/dist/utils/tokenEstimator.d.ts.map +1 -0
- package/dist/utils/tokenEstimator.js +55 -0
- package/package.json +6 -6
- package/src/agent.ts +586 -78
- package/src/index.ts +4 -0
- package/src/managers/aiManager.ts +341 -192
- package/src/managers/backgroundBashManager.ts +11 -9
- package/src/managers/hookManager.ts +102 -54
- package/src/managers/liveConfigManager.ts +634 -0
- package/src/managers/lspManager.ts +434 -0
- package/src/managers/messageManager.ts +258 -121
- package/src/managers/permissionManager.ts +276 -0
- package/src/managers/skillManager.ts +3 -1
- package/src/managers/slashCommandManager.ts +5 -3
- package/src/managers/subagentManager.ts +295 -76
- package/src/managers/toolManager.ts +95 -3
- package/src/services/aiService.ts +656 -84
- package/src/services/configurationService.ts +762 -0
- package/src/services/fileWatcher.ts +300 -0
- package/src/services/hook.ts +54 -144
- package/src/services/jsonlHandler.ts +303 -0
- package/src/services/memory.ts +34 -11
- package/src/services/session.ts +522 -173
- package/src/tools/bashTool.ts +94 -20
- package/src/tools/deleteFileTool.ts +38 -1
- package/src/tools/editTool.ts +44 -9
- package/src/tools/lspTool.ts +760 -0
- package/src/tools/multiEditTool.ts +41 -11
- package/src/tools/readTool.ts +127 -3
- package/src/tools/skillTool.ts +2 -2
- package/src/tools/todoWriteTool.ts +33 -1
- package/src/tools/types.ts +15 -9
- package/src/tools/writeTool.ts +43 -16
- package/src/types/commands.ts +6 -1
- package/src/types/config.ts +5 -0
- package/src/types/configuration.ts +73 -0
- package/src/types/core.ts +55 -0
- package/src/types/environment.ts +104 -0
- package/src/types/fileSearch.ts +4 -0
- package/src/types/hooks.ts +32 -16
- package/src/types/index.ts +7 -0
- package/src/types/lsp.ts +96 -0
- package/src/types/messaging.ts +21 -14
- package/src/types/permissions.ts +48 -0
- package/src/types/session.ts +20 -0
- package/src/types/skills.ts +1 -0
- package/src/types/tools.ts +38 -0
- package/src/utils/abortUtils.ts +118 -0
- package/src/utils/bashHistory.ts +55 -31
- package/src/utils/builtinSubagents.ts +71 -0
- package/src/utils/cacheControlUtils.ts +475 -0
- package/src/utils/commandPathResolver.ts +189 -0
- package/src/utils/configPaths.ts +163 -0
- package/src/utils/constants.ts +2 -17
- package/src/utils/convertMessagesForAPI.ts +44 -18
- package/src/utils/customCommands.ts +90 -22
- package/src/utils/fileSearch.ts +107 -0
- package/src/utils/fileUtils.ts +160 -0
- package/src/utils/globalLogger.ts +128 -0
- package/src/utils/largeOutputHandler.ts +55 -0
- package/src/utils/markdownParser.ts +1 -19
- package/src/utils/mcpUtils.ts +34 -3
- package/src/utils/messageOperations.ts +47 -53
- package/src/utils/pathEncoder.ts +394 -0
- package/src/utils/subagentParser.ts +13 -9
- package/src/utils/tokenCalculation.ts +43 -0
- package/src/utils/tokenEstimator.ts +68 -0
- package/dist/utils/configResolver.d.ts +0 -38
- package/dist/utils/configResolver.d.ts.map +0 -1
- package/dist/utils/configResolver.js +0 -106
- package/src/utils/configResolver.ts +0 -142
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Path Utilities
|
|
3
|
+
*
|
|
4
|
+
* Centralized utilities for resolving Wave configuration file paths.
|
|
5
|
+
* Supports both regular settings.json and settings.local.json with proper priority.
|
|
6
|
+
*
|
|
7
|
+
* Priority system:
|
|
8
|
+
* - User configs: ~/.wave/settings.local.json > ~/.wave/settings.json
|
|
9
|
+
* - Project configs: {workdir}/.wave/settings.local.json > {workdir}/.wave/settings.json
|
|
10
|
+
* - Project configs override user configs (existing behavior)
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { join } from "path";
|
|
14
|
+
import { homedir } from "os";
|
|
15
|
+
import { existsSync } from "fs";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get the user-specific configuration file path (legacy function)
|
|
19
|
+
* @deprecated Use getUserConfigPaths() for better priority support
|
|
20
|
+
*/
|
|
21
|
+
export function getUserConfigPath(): string {
|
|
22
|
+
return join(homedir(), ".wave", "settings.json");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get the project-specific configuration file path (legacy function)
|
|
27
|
+
* @deprecated Use getProjectConfigPaths() for better priority support
|
|
28
|
+
*/
|
|
29
|
+
export function getProjectConfigPath(workdir: string): string {
|
|
30
|
+
return join(workdir, ".wave", "settings.json");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Get the user-specific configuration file paths in priority order
|
|
35
|
+
* Returns array with .local.json first, then .json
|
|
36
|
+
*/
|
|
37
|
+
export function getUserConfigPaths(): string[] {
|
|
38
|
+
const baseDir = join(homedir(), ".wave");
|
|
39
|
+
return [join(baseDir, "settings.local.json"), join(baseDir, "settings.json")];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get the project-specific configuration file paths in priority order
|
|
44
|
+
* Returns array with .local.json first, then .json
|
|
45
|
+
*/
|
|
46
|
+
export function getProjectConfigPaths(workdir: string): string[] {
|
|
47
|
+
const baseDir = join(workdir, ".wave");
|
|
48
|
+
return [join(baseDir, "settings.local.json"), join(baseDir, "settings.json")];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get all configuration file paths (user and project) in priority order
|
|
53
|
+
* Useful for comprehensive configuration detection
|
|
54
|
+
*/
|
|
55
|
+
export function getAllConfigPaths(workdir: string): {
|
|
56
|
+
userPaths: string[];
|
|
57
|
+
projectPaths: string[];
|
|
58
|
+
allPaths: string[];
|
|
59
|
+
} {
|
|
60
|
+
const userPaths = getUserConfigPaths();
|
|
61
|
+
const projectPaths = getProjectConfigPaths(workdir);
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
userPaths,
|
|
65
|
+
projectPaths,
|
|
66
|
+
allPaths: [...userPaths, ...projectPaths],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get existing configuration file paths
|
|
72
|
+
* Returns only the paths that actually exist on the filesystem
|
|
73
|
+
*/
|
|
74
|
+
export function getExistingConfigPaths(workdir: string): {
|
|
75
|
+
userPaths: string[];
|
|
76
|
+
projectPaths: string[];
|
|
77
|
+
existingPaths: string[];
|
|
78
|
+
} {
|
|
79
|
+
const allPaths = getAllConfigPaths(workdir);
|
|
80
|
+
|
|
81
|
+
const existingUserPaths = allPaths.userPaths.filter(existsSync);
|
|
82
|
+
const existingProjectPaths = allPaths.projectPaths.filter(existsSync);
|
|
83
|
+
const allExistingPaths = allPaths.allPaths.filter(existsSync);
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
userPaths: existingUserPaths,
|
|
87
|
+
projectPaths: existingProjectPaths,
|
|
88
|
+
existingPaths: allExistingPaths,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get the first existing configuration file path with the specified priority
|
|
94
|
+
* @param paths Array of paths in priority order
|
|
95
|
+
* @returns The first path that exists, or undefined if none exist
|
|
96
|
+
*/
|
|
97
|
+
export function getFirstExistingPath(paths: string[]): string | undefined {
|
|
98
|
+
return paths.find((path) => existsSync(path));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get effective configuration paths (the ones that would actually be used)
|
|
103
|
+
* Returns the highest priority existing path for each category
|
|
104
|
+
*/
|
|
105
|
+
export function getEffectiveConfigPaths(workdir: string): {
|
|
106
|
+
userPath?: string;
|
|
107
|
+
projectPath?: string;
|
|
108
|
+
effectivePath?: string; // The path that takes final precedence
|
|
109
|
+
} {
|
|
110
|
+
const userPaths = getUserConfigPaths();
|
|
111
|
+
const projectPaths = getProjectConfigPaths(workdir);
|
|
112
|
+
|
|
113
|
+
const userPath = getFirstExistingPath(userPaths);
|
|
114
|
+
const projectPath = getFirstExistingPath(projectPaths);
|
|
115
|
+
|
|
116
|
+
// Project path takes precedence over user path if both exist
|
|
117
|
+
const effectivePath = projectPath || userPath;
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
userPath,
|
|
121
|
+
projectPath,
|
|
122
|
+
effectivePath,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Check if any configuration files exist
|
|
128
|
+
*/
|
|
129
|
+
export function hasAnyConfig(workdir: string): boolean {
|
|
130
|
+
const { existingPaths } = getExistingConfigPaths(workdir);
|
|
131
|
+
return existingPaths.length > 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Get configuration information for debugging and monitoring
|
|
136
|
+
*/
|
|
137
|
+
export function getConfigurationInfo(workdir: string): {
|
|
138
|
+
hasUser: boolean;
|
|
139
|
+
hasProject: boolean;
|
|
140
|
+
paths: string[];
|
|
141
|
+
userPaths: string[];
|
|
142
|
+
projectPaths: string[];
|
|
143
|
+
existingPaths: string[];
|
|
144
|
+
effectivePaths: {
|
|
145
|
+
userPath?: string;
|
|
146
|
+
projectPath?: string;
|
|
147
|
+
effectivePath?: string;
|
|
148
|
+
};
|
|
149
|
+
} {
|
|
150
|
+
const allPaths = getAllConfigPaths(workdir);
|
|
151
|
+
const existingPaths = getExistingConfigPaths(workdir);
|
|
152
|
+
const effectivePaths = getEffectiveConfigPaths(workdir);
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
hasUser: existingPaths.userPaths.length > 0,
|
|
156
|
+
hasProject: existingPaths.projectPaths.length > 0,
|
|
157
|
+
paths: allPaths.allPaths,
|
|
158
|
+
userPaths: allPaths.userPaths,
|
|
159
|
+
projectPaths: allPaths.projectPaths,
|
|
160
|
+
existingPaths: existingPaths.existingPaths,
|
|
161
|
+
effectivePaths,
|
|
162
|
+
};
|
|
163
|
+
}
|
package/src/utils/constants.ts
CHANGED
|
@@ -24,24 +24,9 @@ export const ERROR_LOG_DIRECTORY = path.join(DATA_DIRECTORY, "error-logs");
|
|
|
24
24
|
/**
|
|
25
25
|
* User-level memory file path
|
|
26
26
|
*/
|
|
27
|
-
export const USER_MEMORY_FILE = path.join(DATA_DIRECTORY, "
|
|
27
|
+
export const USER_MEMORY_FILE = path.join(DATA_DIRECTORY, "AGENTS.md");
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
30
|
* AI related constants
|
|
31
31
|
*/
|
|
32
|
-
export const DEFAULT_TOKEN_LIMIT =
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* @deprecated These constants are now legacy. Use ModelConfig through Agent constructor instead.
|
|
36
|
-
* They are maintained for backward compatibility with existing code that might still reference them,
|
|
37
|
-
* but the actual AI services now use configuration injection.
|
|
38
|
-
*/
|
|
39
|
-
export const FAST_MODEL_ID = process.env.AIGW_FAST_MODEL || "gemini-2.5-flash";
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* @deprecated These constants are now legacy. Use ModelConfig through Agent constructor instead.
|
|
43
|
-
* They are maintained for backward compatibility with existing code that might still reference them,
|
|
44
|
-
* but the actual AI services now use configuration injection.
|
|
45
|
-
*/
|
|
46
|
-
export const AGENT_MODEL_ID =
|
|
47
|
-
process.env.AIGW_MODEL || "claude-sonnet-4-20250514";
|
|
32
|
+
export const DEFAULT_TOKEN_LIMIT = 96000; // Default token limit
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
ChatCompletionContentPart,
|
|
7
7
|
ChatCompletionMessageParam,
|
|
8
8
|
} from "openai/resources.js";
|
|
9
|
+
import { logger } from "./globalLogger.js";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Safely handle tool call parameters, ensuring a legal JSON string is returned
|
|
@@ -21,15 +22,16 @@ function safeToolArguments(args: string): string {
|
|
|
21
22
|
// Try to parse as JSON to validate format
|
|
22
23
|
JSON.parse(args);
|
|
23
24
|
return args;
|
|
24
|
-
} catch {
|
|
25
|
-
|
|
25
|
+
} catch (error) {
|
|
26
|
+
logger.error(`Invalid tool arguments: ${args}`, error);
|
|
26
27
|
// If not valid JSON, return a fallback empty object
|
|
27
28
|
return "{}";
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
|
-
* Convert message format to API call format, stopping when a compressed message is encountered
|
|
33
|
+
* Convert message format to API call format, stopping when a compressed message is encountered.
|
|
34
|
+
* Messages with no meaningful content or tool calls are filtered out.
|
|
33
35
|
* @param messages Message list
|
|
34
36
|
* @returns Converted API message format list
|
|
35
37
|
*/
|
|
@@ -60,7 +62,7 @@ export function convertMessagesForAPI(
|
|
|
60
62
|
break;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
|
-
// Skip empty assistant messages
|
|
65
|
+
// Skip empty assistant messages (no blocks or all blocks are empty)
|
|
64
66
|
if (message.role === "assistant" && message.blocks.length === 0) {
|
|
65
67
|
continue;
|
|
66
68
|
}
|
|
@@ -75,8 +77,8 @@ export function convertMessagesForAPI(
|
|
|
75
77
|
|
|
76
78
|
if (toolBlocks.length > 0) {
|
|
77
79
|
toolBlocks.forEach((toolBlock) => {
|
|
78
|
-
// Only add completed tool blocks (i.e.,
|
|
79
|
-
if (toolBlock.id &&
|
|
80
|
+
// Only add completed tool blocks (i.e., stage is 'end')
|
|
81
|
+
if (toolBlock.id && toolBlock.stage === "end") {
|
|
80
82
|
completedToolIds.add(toolBlock.id);
|
|
81
83
|
|
|
82
84
|
// Check for image data
|
|
@@ -127,12 +129,17 @@ export function convertMessagesForAPI(
|
|
|
127
129
|
let content = "";
|
|
128
130
|
let tool_calls: ChatCompletionMessageToolCall[] | undefined = undefined;
|
|
129
131
|
|
|
130
|
-
// Construct content from text blocks
|
|
132
|
+
// Construct content from text blocks - filter out empty content
|
|
131
133
|
const textBlocks = message.blocks.filter(
|
|
132
|
-
(block) =>
|
|
134
|
+
(block) =>
|
|
135
|
+
block.type === "text" &&
|
|
136
|
+
block.content &&
|
|
137
|
+
block.content.trim().length > 0,
|
|
133
138
|
);
|
|
134
139
|
if (textBlocks.length > 0) {
|
|
135
|
-
content = textBlocks
|
|
140
|
+
content = textBlocks
|
|
141
|
+
.map((block) => (block.type === "text" ? block.content : ""))
|
|
142
|
+
.join("\n");
|
|
136
143
|
}
|
|
137
144
|
|
|
138
145
|
// Construct tool calls from tool blocks
|
|
@@ -157,12 +164,16 @@ export function convertMessagesForAPI(
|
|
|
157
164
|
}
|
|
158
165
|
}
|
|
159
166
|
|
|
160
|
-
// Construct assistant message - only add if there is content or tool calls
|
|
161
|
-
|
|
167
|
+
// Construct assistant message - only add if there is meaningful content or tool calls
|
|
168
|
+
const hasContent = content && content.trim().length > 0;
|
|
169
|
+
const hasToolCalls = tool_calls && tool_calls.length > 0;
|
|
170
|
+
|
|
171
|
+
if (hasContent || hasToolCalls) {
|
|
162
172
|
const assistantMessage: ChatCompletionMessageParam = {
|
|
163
173
|
role: "assistant",
|
|
164
|
-
content,
|
|
174
|
+
content: hasContent ? content : undefined,
|
|
165
175
|
tool_calls,
|
|
176
|
+
...(message.additionalFields ? { ...message.additionalFields } : {}),
|
|
166
177
|
};
|
|
167
178
|
|
|
168
179
|
recentMessages.unshift(assistantMessage);
|
|
@@ -172,8 +183,12 @@ export function convertMessagesForAPI(
|
|
|
172
183
|
const contentParts: ChatCompletionContentPart[] = [];
|
|
173
184
|
|
|
174
185
|
message.blocks.forEach((block) => {
|
|
175
|
-
// Add text content
|
|
176
|
-
if (
|
|
186
|
+
// Add text content - only if it has meaningful content
|
|
187
|
+
if (
|
|
188
|
+
block.type === "text" &&
|
|
189
|
+
block.content &&
|
|
190
|
+
block.content.trim().length > 0
|
|
191
|
+
) {
|
|
177
192
|
contentParts.push({
|
|
178
193
|
type: "text",
|
|
179
194
|
text: block.customCommandContent || block.content,
|
|
@@ -194,7 +209,7 @@ export function convertMessagesForAPI(
|
|
|
194
209
|
try {
|
|
195
210
|
finalImageUrl = convertImageToBase64(imageUrl);
|
|
196
211
|
} catch (error) {
|
|
197
|
-
|
|
212
|
+
logger.error(
|
|
198
213
|
"Failed to convert image path to base64:",
|
|
199
214
|
imageUrl,
|
|
200
215
|
error,
|
|
@@ -215,11 +230,22 @@ export function convertMessagesForAPI(
|
|
|
215
230
|
}
|
|
216
231
|
});
|
|
217
232
|
|
|
233
|
+
// Only add user message if there is meaningful content
|
|
218
234
|
if (contentParts.length > 0) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
235
|
+
// Filter out empty text parts
|
|
236
|
+
const meaningfulParts = contentParts.filter((part) => {
|
|
237
|
+
if (part.type === "text") {
|
|
238
|
+
return part.text && part.text.trim().length > 0;
|
|
239
|
+
}
|
|
240
|
+
return true; // Keep image parts
|
|
222
241
|
});
|
|
242
|
+
|
|
243
|
+
if (meaningfulParts.length > 0) {
|
|
244
|
+
recentMessages.unshift({
|
|
245
|
+
role: "user",
|
|
246
|
+
content: meaningfulParts,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
223
249
|
}
|
|
224
250
|
}
|
|
225
251
|
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
-
import { existsSync, readdirSync } from "fs";
|
|
1
|
+
import { existsSync, readdirSync, statSync } from "fs";
|
|
2
2
|
import { join, extname, basename } from "path";
|
|
3
3
|
import { homedir } from "os";
|
|
4
4
|
import type { CustomSlashCommand } from "../types/index.js";
|
|
5
5
|
import { parseMarkdownFile } from "./markdownParser.js";
|
|
6
|
+
import {
|
|
7
|
+
generateCommandId,
|
|
8
|
+
getCommandSegments,
|
|
9
|
+
getNamespace,
|
|
10
|
+
getDepth,
|
|
11
|
+
} from "./commandPathResolver.js";
|
|
12
|
+
import { logger } from "./globalLogger.js";
|
|
6
13
|
|
|
7
14
|
/**
|
|
8
15
|
* Get the project-specific commands directory
|
|
@@ -19,43 +26,104 @@ export function getUserCommandsDir(): string {
|
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
/**
|
|
22
|
-
* Scan a directory for markdown command files
|
|
29
|
+
* Scan a directory for markdown command files with nested directory support
|
|
30
|
+
* @param dirPath - Root commands directory path
|
|
31
|
+
* @param maxDepth - Maximum nesting depth to scan (default: 1)
|
|
23
32
|
*/
|
|
24
|
-
function scanCommandsDirectory(
|
|
33
|
+
function scanCommandsDirectory(
|
|
34
|
+
dirPath: string,
|
|
35
|
+
maxDepth: number = 1,
|
|
36
|
+
): CustomSlashCommand[] {
|
|
25
37
|
if (!existsSync(dirPath)) {
|
|
26
38
|
return [];
|
|
27
39
|
}
|
|
28
40
|
|
|
41
|
+
return scanCommandsDirectoryRecursive(dirPath, dirPath, 0, maxDepth);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Recursively scan directory for commands with depth control
|
|
46
|
+
* @param currentPath - Current directory being scanned
|
|
47
|
+
* @param rootPath - Root commands directory (for relative path calculation)
|
|
48
|
+
* @param currentDepth - Current nesting depth
|
|
49
|
+
* @param maxDepth - Maximum allowed depth
|
|
50
|
+
*/
|
|
51
|
+
function scanCommandsDirectoryRecursive(
|
|
52
|
+
currentPath: string,
|
|
53
|
+
rootPath: string,
|
|
54
|
+
currentDepth: number,
|
|
55
|
+
maxDepth: number,
|
|
56
|
+
): CustomSlashCommand[] {
|
|
29
57
|
const commands: CustomSlashCommand[] = [];
|
|
30
58
|
|
|
31
59
|
try {
|
|
32
|
-
const
|
|
60
|
+
const entries = readdirSync(currentPath);
|
|
33
61
|
|
|
34
|
-
for (const
|
|
35
|
-
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
62
|
+
for (const entryName of entries) {
|
|
63
|
+
const fullPath = join(currentPath, entryName);
|
|
38
64
|
|
|
39
|
-
|
|
40
|
-
|
|
65
|
+
let isDirectory = false;
|
|
66
|
+
let isFile = false;
|
|
41
67
|
|
|
42
68
|
try {
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
id: commandName,
|
|
47
|
-
name: commandName,
|
|
48
|
-
description: config?.description, // Use description from frontmatter
|
|
49
|
-
filePath,
|
|
50
|
-
content,
|
|
51
|
-
config,
|
|
52
|
-
});
|
|
69
|
+
const stats = statSync(fullPath);
|
|
70
|
+
isDirectory = stats.isDirectory();
|
|
71
|
+
isFile = stats.isFile();
|
|
53
72
|
} catch (error) {
|
|
54
|
-
|
|
73
|
+
// Skip entries that cannot be stat'd
|
|
74
|
+
logger.warn(`Cannot access ${fullPath}:`, error);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (isDirectory) {
|
|
79
|
+
// Skip subdirectories if we're at max depth
|
|
80
|
+
if (currentDepth >= maxDepth) {
|
|
81
|
+
logger.warn(
|
|
82
|
+
`Skipping directory ${fullPath}: exceeds maximum nesting depth of ${maxDepth}`,
|
|
83
|
+
);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Recursively scan subdirectory
|
|
88
|
+
const nestedCommands = scanCommandsDirectoryRecursive(
|
|
89
|
+
fullPath,
|
|
90
|
+
rootPath,
|
|
91
|
+
currentDepth + 1,
|
|
92
|
+
maxDepth,
|
|
93
|
+
);
|
|
94
|
+
commands.push(...nestedCommands);
|
|
95
|
+
} else if (isFile && extname(entryName) === ".md") {
|
|
96
|
+
// Process markdown file
|
|
97
|
+
try {
|
|
98
|
+
const commandId = generateCommandId(fullPath, rootPath);
|
|
99
|
+
const segments = getCommandSegments(fullPath, rootPath);
|
|
100
|
+
const namespace = getNamespace(segments);
|
|
101
|
+
const depth = getDepth(segments);
|
|
102
|
+
|
|
103
|
+
const { content, config } = parseMarkdownFile(fullPath);
|
|
104
|
+
|
|
105
|
+
commands.push({
|
|
106
|
+
id: commandId,
|
|
107
|
+
name: basename(entryName, ".md"),
|
|
108
|
+
description: config?.description,
|
|
109
|
+
filePath: fullPath,
|
|
110
|
+
content,
|
|
111
|
+
config,
|
|
112
|
+
|
|
113
|
+
// Nested command metadata
|
|
114
|
+
namespace,
|
|
115
|
+
isNested: depth > 0,
|
|
116
|
+
depth,
|
|
117
|
+
segments,
|
|
118
|
+
});
|
|
119
|
+
} catch (error) {
|
|
120
|
+
logger.warn(`Failed to load custom command from ${fullPath}:`, error);
|
|
121
|
+
}
|
|
55
122
|
}
|
|
123
|
+
// Skip non-markdown files silently
|
|
56
124
|
}
|
|
57
125
|
} catch (error) {
|
|
58
|
-
|
|
126
|
+
logger.warn(`Failed to scan commands directory ${currentPath}:`, error);
|
|
59
127
|
}
|
|
60
128
|
|
|
61
129
|
return commands;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { globIterate, type Path } from "glob";
|
|
2
|
+
import { getGlobIgnorePatterns } from "./fileFilter.js";
|
|
3
|
+
import type { FileItem } from "../types/fileSearch.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Convert Path objects to FileItem objects
|
|
7
|
+
*/
|
|
8
|
+
export const convertPathsToFileItems = (paths: Path[]): FileItem[] => {
|
|
9
|
+
return paths.map((pathObj) => ({
|
|
10
|
+
path: pathObj.relative(),
|
|
11
|
+
type: pathObj.isDirectory() ? "directory" : "file",
|
|
12
|
+
}));
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Search files and directories using glob patterns
|
|
17
|
+
*/
|
|
18
|
+
export const searchFiles = async (
|
|
19
|
+
query: string,
|
|
20
|
+
options?: {
|
|
21
|
+
maxResults?: number;
|
|
22
|
+
workingDirectory?: string;
|
|
23
|
+
},
|
|
24
|
+
): Promise<FileItem[]> => {
|
|
25
|
+
const { maxResults = 10, workingDirectory = process.cwd() } = options || {};
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const globOptions: import("glob").GlobOptionsWithFileTypesTrue = {
|
|
29
|
+
ignore: getGlobIgnorePatterns(workingDirectory),
|
|
30
|
+
maxDepth: 10,
|
|
31
|
+
nocase: true, // Case insensitive
|
|
32
|
+
dot: true, // Include hidden files and directories
|
|
33
|
+
cwd: workingDirectory, // Specify search root directory
|
|
34
|
+
withFileTypes: true, // Get Path objects instead of strings
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Build glob patterns based on query
|
|
38
|
+
let patterns: string[] = [];
|
|
39
|
+
|
|
40
|
+
if (!query.trim()) {
|
|
41
|
+
// When query is empty, show some common file types and directories
|
|
42
|
+
patterns = [
|
|
43
|
+
"**/*.{ts,tsx,js,jsx,json,py,java}", // Combine common file extensions
|
|
44
|
+
"*/", // First level directories
|
|
45
|
+
];
|
|
46
|
+
} else {
|
|
47
|
+
// Build multiple glob patterns to support more flexible search
|
|
48
|
+
patterns = [
|
|
49
|
+
// Match files with filenames containing query
|
|
50
|
+
`**/*${query}*`,
|
|
51
|
+
// Match files with query in path (match directory names)
|
|
52
|
+
`**/${query}*/**/*`,
|
|
53
|
+
// Match directory names containing query
|
|
54
|
+
`**/*${query}*/`,
|
|
55
|
+
// Match directories containing query in path
|
|
56
|
+
`**/${query}*/`,
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Collect results until we reach maxResults
|
|
61
|
+
const collectedPaths: Path[] = [];
|
|
62
|
+
const seenPaths = new Set<string>();
|
|
63
|
+
|
|
64
|
+
// Process each pattern sequentially
|
|
65
|
+
for (const pattern of patterns) {
|
|
66
|
+
if (collectedPaths.length >= maxResults) {
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Use globIterate to get results one by one
|
|
71
|
+
const iterator = globIterate(pattern, globOptions) as AsyncGenerator<
|
|
72
|
+
Path,
|
|
73
|
+
void,
|
|
74
|
+
void
|
|
75
|
+
>;
|
|
76
|
+
|
|
77
|
+
for await (const pathObj of iterator) {
|
|
78
|
+
if (collectedPaths.length >= maxResults) {
|
|
79
|
+
// Stop the iterator when we have enough results
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const relativePath = pathObj.relative();
|
|
84
|
+
if (!seenPaths.has(relativePath)) {
|
|
85
|
+
seenPaths.add(relativePath);
|
|
86
|
+
collectedPaths.push(pathObj);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Sort collected paths: directories first, then files
|
|
92
|
+
collectedPaths.sort((a, b) => {
|
|
93
|
+
const aIsDir = a.isDirectory();
|
|
94
|
+
const bIsDir = b.isDirectory();
|
|
95
|
+
if (aIsDir && !bIsDir) return -1;
|
|
96
|
+
if (!aIsDir && bIsDir) return 1;
|
|
97
|
+
return a.relative().localeCompare(b.relative());
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Convert to FileItems
|
|
101
|
+
const fileItems = convertPathsToFileItems(collectedPaths);
|
|
102
|
+
return fileItems;
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error("Glob search error:", error);
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
};
|