wave-agent-sdk 0.0.8 → 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 +92 -23
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +340 -137
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/managers/aiManager.d.ts +14 -36
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +74 -77
- package/dist/managers/backgroundBashManager.d.ts.map +1 -1
- package/dist/managers/backgroundBashManager.js +4 -3
- package/dist/managers/hookManager.d.ts +3 -8
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +39 -29
- package/dist/managers/liveConfigManager.d.ts +55 -18
- package/dist/managers/liveConfigManager.d.ts.map +1 -1
- package/dist/managers/liveConfigManager.js +372 -90
- 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 +8 -16
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +52 -74
- 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 +0 -1
- package/dist/managers/subagentManager.d.ts +8 -23
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +97 -117
- 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 +3 -1
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +123 -30
- 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.map +1 -1
- package/dist/services/fileWatcher.js +5 -6
- package/dist/services/hook.d.ts +7 -124
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +46 -458
- package/dist/services/jsonlHandler.d.ts +24 -15
- package/dist/services/jsonlHandler.d.ts.map +1 -1
- package/dist/services/jsonlHandler.js +67 -88
- package/dist/services/memory.d.ts +0 -9
- package/dist/services/memory.d.ts.map +1 -1
- package/dist/services/memory.js +2 -49
- package/dist/services/session.d.ts +82 -33
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +275 -181
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +72 -13
- package/dist/tools/deleteFileTool.d.ts.map +1 -1
- package/dist/tools/deleteFileTool.js +25 -0
- package/dist/tools/editTool.d.ts.map +1 -1
- package/dist/tools/editTool.js +30 -6
- 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 +26 -7
- package/dist/tools/readTool.d.ts.map +1 -1
- package/dist/tools/readTool.js +111 -2
- 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 +25 -9
- package/dist/types/commands.d.ts +0 -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 +10 -0
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/environment.d.ts +41 -0
- package/dist/types/environment.d.ts.map +1 -1
- 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 +11 -2
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +1 -7
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +5 -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 +6 -11
- 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 +1 -6
- package/dist/types/session.d.ts.map +1 -1
- 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 +21 -4
- 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 +8 -33
- package/dist/utils/cacheControlUtils.d.ts.map +1 -1
- package/dist/utils/cacheControlUtils.js +83 -126
- package/dist/utils/constants.d.ts +0 -12
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +1 -13
- package/dist/utils/convertMessagesForAPI.d.ts +2 -1
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
- package/dist/utils/convertMessagesForAPI.js +33 -14
- 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 +14 -2
- package/dist/utils/fileUtils.d.ts.map +1 -1
- package/dist/utils/fileUtils.js +101 -17
- package/dist/utils/globalLogger.d.ts +0 -14
- package/dist/utils/globalLogger.d.ts.map +1 -1
- package/dist/utils/globalLogger.js +0 -16
- 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/messageOperations.d.ts +1 -11
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +7 -24
- package/dist/utils/pathEncoder.d.ts +4 -0
- package/dist/utils/pathEncoder.d.ts.map +1 -1
- package/dist/utils/pathEncoder.js +16 -9
- package/dist/utils/subagentParser.d.ts +2 -2
- package/dist/utils/subagentParser.d.ts.map +1 -1
- package/dist/utils/subagentParser.js +10 -7
- 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 +5 -8
- package/src/agent.ts +460 -216
- package/src/index.ts +2 -0
- package/src/managers/aiManager.ts +107 -111
- package/src/managers/backgroundBashManager.ts +4 -3
- package/src/managers/hookManager.ts +44 -39
- package/src/managers/liveConfigManager.ts +524 -138
- package/src/managers/lspManager.ts +434 -0
- package/src/managers/messageManager.ts +73 -103
- package/src/managers/permissionManager.ts +276 -0
- package/src/managers/skillManager.ts +3 -1
- package/src/managers/slashCommandManager.ts +1 -2
- package/src/managers/subagentManager.ts +116 -159
- package/src/managers/toolManager.ts +95 -3
- package/src/services/aiService.ts +207 -26
- package/src/services/configurationService.ts +762 -0
- package/src/services/fileWatcher.ts +5 -6
- package/src/services/hook.ts +50 -631
- package/src/services/jsonlHandler.ts +84 -100
- package/src/services/memory.ts +2 -59
- package/src/services/session.ts +338 -213
- package/src/tools/bashTool.ts +89 -16
- package/src/tools/deleteFileTool.ts +36 -0
- package/src/tools/editTool.ts +41 -7
- package/src/tools/lspTool.ts +760 -0
- package/src/tools/multiEditTool.ts +37 -8
- package/src/tools/readTool.ts +125 -2
- 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 +36 -10
- package/src/types/commands.ts +0 -1
- package/src/types/config.ts +5 -0
- package/src/types/configuration.ts +73 -0
- package/src/types/core.ts +11 -0
- package/src/types/environment.ts +44 -0
- package/src/types/fileSearch.ts +4 -0
- package/src/types/hooks.ts +14 -11
- package/src/types/index.ts +5 -0
- package/src/types/lsp.ts +96 -0
- package/src/types/messaging.ts +8 -13
- package/src/types/permissions.ts +48 -0
- package/src/types/session.ts +3 -8
- 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 +28 -4
- package/src/utils/builtinSubagents.ts +71 -0
- package/src/utils/cacheControlUtils.ts +106 -171
- package/src/utils/constants.ts +1 -16
- package/src/utils/convertMessagesForAPI.ts +38 -14
- package/src/utils/fileSearch.ts +107 -0
- package/src/utils/fileUtils.ts +114 -19
- package/src/utils/globalLogger.ts +0 -17
- package/src/utils/largeOutputHandler.ts +55 -0
- package/src/utils/markdownParser.ts +1 -19
- package/src/utils/messageOperations.ts +7 -35
- package/src/utils/pathEncoder.ts +24 -9
- package/src/utils/subagentParser.ts +11 -8
- package/src/utils/tokenEstimator.ts +68 -0
- package/dist/constants/events.d.ts +0 -28
- package/dist/constants/events.d.ts.map +0 -1
- package/dist/constants/events.js +0 -27
- package/dist/services/configurationWatcher.d.ts +0 -120
- package/dist/services/configurationWatcher.d.ts.map +0 -1
- package/dist/services/configurationWatcher.js +0 -439
- package/dist/services/memoryStore.d.ts +0 -81
- package/dist/services/memoryStore.d.ts.map +0 -1
- package/dist/services/memoryStore.js +0 -200
- package/dist/types/memoryStore.d.ts +0 -82
- package/dist/types/memoryStore.d.ts.map +0 -1
- package/dist/types/memoryStore.js +0 -7
- package/dist/utils/configResolver.d.ts +0 -65
- package/dist/utils/configResolver.d.ts.map +0 -1
- package/dist/utils/configResolver.js +0 -210
- package/src/constants/events.ts +0 -38
- package/src/services/configurationWatcher.ts +0 -622
- package/src/services/memoryStore.ts +0 -279
- package/src/types/memoryStore.ts +0 -94
- package/src/utils/configResolver.ts +0 -302
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Service
|
|
3
|
+
*
|
|
4
|
+
* Centralized service for loading, validating, and managing Wave configuration files.
|
|
5
|
+
* Replaces distributed configuration logic previously embedded in hook.ts.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, existsSync, promises as fs } from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import { isValidHookEvent } from "../types/hooks.js";
|
|
10
|
+
import { getAllConfigPaths, getExistingConfigPaths, getUserConfigPaths, getProjectConfigPaths, } from "../utils/configPaths.js";
|
|
11
|
+
import { isValidEnvironmentVars, } from "../types/environment.js";
|
|
12
|
+
import { ConfigurationError, CONFIG_ERRORS, } from "../types/index.js";
|
|
13
|
+
import { DEFAULT_TOKEN_LIMIT } from "../utils/constants.js";
|
|
14
|
+
/**
|
|
15
|
+
* Default ConfigurationService implementation
|
|
16
|
+
*
|
|
17
|
+
* Provides centralized configuration loading, validation, and management.
|
|
18
|
+
* Extracted from distributed logic in hook.ts with improved error handling.
|
|
19
|
+
*/
|
|
20
|
+
export class ConfigurationService {
|
|
21
|
+
constructor() {
|
|
22
|
+
this.currentConfiguration = null;
|
|
23
|
+
this.env = {};
|
|
24
|
+
}
|
|
25
|
+
// Core loading operations
|
|
26
|
+
/**
|
|
27
|
+
* Load and merge configuration with comprehensive validation
|
|
28
|
+
*/
|
|
29
|
+
async loadMergedConfiguration(workdir) {
|
|
30
|
+
try {
|
|
31
|
+
const userConfigPaths = getUserConfigPaths();
|
|
32
|
+
const projectConfigPaths = getProjectConfigPaths(workdir);
|
|
33
|
+
// Use the merged configuration function (this loads user and project configs internally)
|
|
34
|
+
const mergedConfig = loadMergedWaveConfig(workdir);
|
|
35
|
+
// Track loading context for better error messages by checking which files exist
|
|
36
|
+
const loadingContext = [];
|
|
37
|
+
const userPath = userConfigPaths.find((path) => existsSync(path));
|
|
38
|
+
if (userPath) {
|
|
39
|
+
loadingContext.push(`user config from ${userPath}`);
|
|
40
|
+
}
|
|
41
|
+
const projectPath = projectConfigPaths.find((path) => existsSync(path));
|
|
42
|
+
if (projectPath) {
|
|
43
|
+
loadingContext.push(`project config from ${projectPath}`);
|
|
44
|
+
}
|
|
45
|
+
if (!mergedConfig) {
|
|
46
|
+
const message = loadingContext.length > 0
|
|
47
|
+
? `No valid configuration found despite attempting to load: ${loadingContext.join(", ")}`
|
|
48
|
+
: "No configuration files found in user or project directories";
|
|
49
|
+
return {
|
|
50
|
+
configuration: null,
|
|
51
|
+
success: true, // No config is valid
|
|
52
|
+
warnings: [message],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
// Comprehensive validation
|
|
56
|
+
const validation = this.validateConfiguration(mergedConfig);
|
|
57
|
+
if (!validation.isValid) {
|
|
58
|
+
const sourcePaths = loadingContext.join(" and ");
|
|
59
|
+
return {
|
|
60
|
+
configuration: null,
|
|
61
|
+
success: false,
|
|
62
|
+
error: `Merged configuration validation failed (sources: ${sourcePaths}): ${validation.errors.join(", ")}`,
|
|
63
|
+
warnings: validation.warnings,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
// Success case
|
|
67
|
+
this.currentConfiguration = mergedConfig;
|
|
68
|
+
// Set environment variables if present in the merged config
|
|
69
|
+
if (mergedConfig.env) {
|
|
70
|
+
this.setEnvironmentVars(mergedConfig.env);
|
|
71
|
+
}
|
|
72
|
+
const sourcePaths = loadingContext.join(" and ");
|
|
73
|
+
return {
|
|
74
|
+
configuration: mergedConfig,
|
|
75
|
+
success: true,
|
|
76
|
+
sourcePath: sourcePaths || "merged configuration",
|
|
77
|
+
warnings: validation.warnings,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
return {
|
|
82
|
+
configuration: null,
|
|
83
|
+
success: false,
|
|
84
|
+
error: `Failed to load merged configuration from ${workdir}: ${error.message}`,
|
|
85
|
+
warnings: [],
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Validation operations
|
|
90
|
+
/**
|
|
91
|
+
* Validate configuration object structure and values
|
|
92
|
+
*/
|
|
93
|
+
validateConfiguration(config) {
|
|
94
|
+
const result = {
|
|
95
|
+
isValid: true,
|
|
96
|
+
errors: [],
|
|
97
|
+
warnings: [],
|
|
98
|
+
};
|
|
99
|
+
// Validate basic structure
|
|
100
|
+
if (!config || typeof config !== "object") {
|
|
101
|
+
result.isValid = false;
|
|
102
|
+
result.errors.push("Configuration must be a valid object");
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
// Validate hooks if present
|
|
106
|
+
if (config.hooks !== undefined) {
|
|
107
|
+
if (typeof config.hooks !== "object" || config.hooks === null) {
|
|
108
|
+
result.isValid = false;
|
|
109
|
+
result.errors.push("Hooks configuration must be an object");
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
for (const [event, eventConfigs] of Object.entries(config.hooks)) {
|
|
113
|
+
if (!isValidHookEvent(event)) {
|
|
114
|
+
result.warnings.push(`Unknown hook event: ${event}`);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (!Array.isArray(eventConfigs)) {
|
|
118
|
+
result.isValid = false;
|
|
119
|
+
result.errors.push(`Hook event '${event}' must be an array`);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
// Validate individual hook configurations
|
|
123
|
+
for (let i = 0; i < eventConfigs.length; i++) {
|
|
124
|
+
const hookConfig = eventConfigs[i];
|
|
125
|
+
if (!hookConfig || typeof hookConfig !== "object") {
|
|
126
|
+
result.isValid = false;
|
|
127
|
+
result.errors.push(`Hook configuration ${i} for event '${event}' must be an object`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Validate environment variables if present
|
|
134
|
+
if (config.env !== undefined) {
|
|
135
|
+
const envValidation = validateEnvironmentConfig(config.env);
|
|
136
|
+
if (!envValidation.isValid) {
|
|
137
|
+
result.isValid = false;
|
|
138
|
+
result.errors.push(...envValidation.errors);
|
|
139
|
+
}
|
|
140
|
+
result.warnings.push(...envValidation.warnings);
|
|
141
|
+
}
|
|
142
|
+
// Validate defaultMode if present
|
|
143
|
+
if (config.defaultMode !== undefined) {
|
|
144
|
+
if (config.defaultMode !== "default" &&
|
|
145
|
+
config.defaultMode !== "bypassPermissions" &&
|
|
146
|
+
config.defaultMode !== "acceptEdits") {
|
|
147
|
+
result.isValid = false;
|
|
148
|
+
result.errors.push(`Invalid defaultMode: "${config.defaultMode}". Must be "default", "bypassPermissions" or "acceptEdits"`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Validate permissions if present
|
|
152
|
+
if (config.permissions !== undefined) {
|
|
153
|
+
if (typeof config.permissions !== "object" ||
|
|
154
|
+
config.permissions === null) {
|
|
155
|
+
result.isValid = false;
|
|
156
|
+
result.errors.push("Permissions configuration must be an object");
|
|
157
|
+
}
|
|
158
|
+
else if (config.permissions.allow !== undefined) {
|
|
159
|
+
if (!Array.isArray(config.permissions.allow)) {
|
|
160
|
+
result.isValid = false;
|
|
161
|
+
result.errors.push("Permissions allow must be an array of strings");
|
|
162
|
+
}
|
|
163
|
+
else if (!config.permissions.allow.every((rule) => typeof rule === "string")) {
|
|
164
|
+
result.isValid = false;
|
|
165
|
+
result.errors.push("All permission rules must be strings");
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return result;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Validate configuration file without loading
|
|
173
|
+
*/
|
|
174
|
+
validateConfigurationFile(filePath) {
|
|
175
|
+
const result = {
|
|
176
|
+
isValid: true,
|
|
177
|
+
errors: [],
|
|
178
|
+
warnings: [],
|
|
179
|
+
};
|
|
180
|
+
if (!existsSync(filePath)) {
|
|
181
|
+
result.isValid = false;
|
|
182
|
+
result.errors.push(`Configuration file not found: ${filePath}`);
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
const content = readFileSync(filePath, "utf-8");
|
|
187
|
+
const config = JSON.parse(content);
|
|
188
|
+
// Use the main validation method
|
|
189
|
+
const configValidation = this.validateConfiguration(config);
|
|
190
|
+
result.isValid = configValidation.isValid;
|
|
191
|
+
result.errors = configValidation.errors;
|
|
192
|
+
result.warnings = configValidation.warnings;
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
result.isValid = false;
|
|
196
|
+
if (error instanceof SyntaxError) {
|
|
197
|
+
result.errors.push(`Invalid JSON syntax in ${filePath}: ${error.message}`);
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
result.errors.push(`Error reading configuration file ${filePath}: ${error.message}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
205
|
+
// Utility operations
|
|
206
|
+
/**
|
|
207
|
+
* Get currently loaded configuration
|
|
208
|
+
*/
|
|
209
|
+
getCurrentConfiguration() {
|
|
210
|
+
return this.currentConfiguration;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Set environment variables from configuration
|
|
214
|
+
* This replaces direct process.env modification
|
|
215
|
+
*/
|
|
216
|
+
setEnvironmentVars(env) {
|
|
217
|
+
this.env = { ...env };
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Get current environment variables
|
|
221
|
+
*/
|
|
222
|
+
getEnvironmentVars() {
|
|
223
|
+
return { ...this.env };
|
|
224
|
+
}
|
|
225
|
+
// =============================================================================
|
|
226
|
+
// Configuration Resolution Methods (merged from configResolver.ts)
|
|
227
|
+
// =============================================================================
|
|
228
|
+
/**
|
|
229
|
+
* Resolves gateway configuration from constructor args and environment
|
|
230
|
+
* Resolution priority: options > env (from settings.json) > process.env > error
|
|
231
|
+
* @param apiKey - API key from constructor (optional)
|
|
232
|
+
* @param baseURL - Base URL from constructor (optional)
|
|
233
|
+
* @param defaultHeaders - HTTP headers from constructor (optional)
|
|
234
|
+
* @param fetchOptions - Fetch options from constructor (optional)
|
|
235
|
+
* @param fetch - Custom fetch implementation from constructor (optional)
|
|
236
|
+
* @returns Resolved gateway configuration
|
|
237
|
+
* @throws ConfigurationError if required configuration is missing after fallbacks
|
|
238
|
+
*/
|
|
239
|
+
resolveGatewayConfig(apiKey, baseURL, defaultHeaders, fetchOptions, fetch) {
|
|
240
|
+
// Resolve API key: constructor > env (settings.json) > process.env
|
|
241
|
+
// Note: Explicitly provided empty strings should be treated as invalid, not fall back to env
|
|
242
|
+
let resolvedApiKey;
|
|
243
|
+
if (apiKey !== undefined) {
|
|
244
|
+
resolvedApiKey = apiKey;
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
resolvedApiKey = this.env.AIGW_TOKEN || process.env.AIGW_TOKEN || "";
|
|
248
|
+
}
|
|
249
|
+
if (!resolvedApiKey && apiKey === undefined) {
|
|
250
|
+
throw new ConfigurationError(CONFIG_ERRORS.MISSING_API_KEY, "apiKey", {
|
|
251
|
+
constructor: apiKey,
|
|
252
|
+
environment: process.env.AIGW_TOKEN,
|
|
253
|
+
settings: this.env.AIGW_TOKEN,
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
if (resolvedApiKey.trim() === "") {
|
|
257
|
+
throw new ConfigurationError(CONFIG_ERRORS.EMPTY_API_KEY, "apiKey", resolvedApiKey);
|
|
258
|
+
}
|
|
259
|
+
// Resolve base URL: constructor > env (settings.json) > process.env
|
|
260
|
+
// Note: Explicitly provided empty strings should be treated as invalid, not fall back to env
|
|
261
|
+
let resolvedBaseURL;
|
|
262
|
+
if (baseURL !== undefined) {
|
|
263
|
+
resolvedBaseURL = baseURL;
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
resolvedBaseURL = this.env.AIGW_URL || process.env.AIGW_URL || "";
|
|
267
|
+
}
|
|
268
|
+
if (!resolvedBaseURL && baseURL === undefined) {
|
|
269
|
+
throw new ConfigurationError(CONFIG_ERRORS.MISSING_BASE_URL, "baseURL", {
|
|
270
|
+
constructor: baseURL,
|
|
271
|
+
environment: process.env.AIGW_URL,
|
|
272
|
+
settings: this.env.AIGW_URL,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
if (resolvedBaseURL.trim() === "") {
|
|
276
|
+
throw new ConfigurationError(CONFIG_ERRORS.EMPTY_BASE_URL, "baseURL", resolvedBaseURL);
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
apiKey: resolvedApiKey,
|
|
280
|
+
baseURL: resolvedBaseURL,
|
|
281
|
+
defaultHeaders,
|
|
282
|
+
fetchOptions,
|
|
283
|
+
fetch,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Resolves model configuration with fallbacks
|
|
288
|
+
* Resolution priority: options > env (from settings.json) > process.env > default
|
|
289
|
+
* @param agentModel - Agent model from constructor (optional)
|
|
290
|
+
* @param fastModel - Fast model from constructor (optional)
|
|
291
|
+
* @returns Resolved model configuration with defaults
|
|
292
|
+
*/
|
|
293
|
+
resolveModelConfig(agentModel, fastModel) {
|
|
294
|
+
// Default values as per data-model.md
|
|
295
|
+
const DEFAULT_AGENT_MODEL = "claude-sonnet-4-20250514";
|
|
296
|
+
const DEFAULT_FAST_MODEL = "gemini-2.5-flash";
|
|
297
|
+
// Resolve agent model: constructor > env (settings.json) > process.env > default
|
|
298
|
+
const resolvedAgentModel = agentModel ||
|
|
299
|
+
this.env.AIGW_MODEL ||
|
|
300
|
+
process.env.AIGW_MODEL ||
|
|
301
|
+
DEFAULT_AGENT_MODEL;
|
|
302
|
+
// Resolve fast model: constructor > env (settings.json) > process.env > default
|
|
303
|
+
const resolvedFastModel = fastModel ||
|
|
304
|
+
this.env.AIGW_FAST_MODEL ||
|
|
305
|
+
process.env.AIGW_FAST_MODEL ||
|
|
306
|
+
DEFAULT_FAST_MODEL;
|
|
307
|
+
return {
|
|
308
|
+
agentModel: resolvedAgentModel,
|
|
309
|
+
fastModel: resolvedFastModel,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Resolves token limit with fallbacks
|
|
314
|
+
* Resolution priority: options > env (from settings.json) > process.env > default
|
|
315
|
+
* @param constructorLimit - Token limit from constructor (optional)
|
|
316
|
+
* @returns Resolved token limit
|
|
317
|
+
*/
|
|
318
|
+
resolveTokenLimit(constructorLimit) {
|
|
319
|
+
// If constructor value provided, use it
|
|
320
|
+
if (constructorLimit !== undefined) {
|
|
321
|
+
return constructorLimit;
|
|
322
|
+
}
|
|
323
|
+
// Try env (settings.json) first, then process.env
|
|
324
|
+
const envTokenLimit = this.env.TOKEN_LIMIT || process.env.TOKEN_LIMIT;
|
|
325
|
+
if (envTokenLimit) {
|
|
326
|
+
const parsed = parseInt(envTokenLimit, 10);
|
|
327
|
+
if (!isNaN(parsed)) {
|
|
328
|
+
return parsed;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
// Use default
|
|
332
|
+
return DEFAULT_TOKEN_LIMIT;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Resolve all configuration file paths
|
|
336
|
+
*/
|
|
337
|
+
getConfigurationPaths(workdir) {
|
|
338
|
+
const allPaths = getAllConfigPaths(workdir);
|
|
339
|
+
const existingPaths = getExistingConfigPaths(workdir);
|
|
340
|
+
return {
|
|
341
|
+
userPaths: allPaths.userPaths,
|
|
342
|
+
projectPaths: allPaths.projectPaths,
|
|
343
|
+
allPaths: allPaths.allPaths,
|
|
344
|
+
existingPaths: existingPaths.existingPaths,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
/**
|
|
348
|
+
* Add a permission rule to the project's settings.local.json
|
|
349
|
+
*/
|
|
350
|
+
async addAllowedRule(workdir, rule) {
|
|
351
|
+
const localConfigPath = path.join(workdir, ".wave", "settings.local.json");
|
|
352
|
+
// Ensure .wave directory exists
|
|
353
|
+
const waveDir = path.join(workdir, ".wave");
|
|
354
|
+
if (!existsSync(waveDir)) {
|
|
355
|
+
await fs.mkdir(waveDir, { recursive: true });
|
|
356
|
+
}
|
|
357
|
+
let config = {};
|
|
358
|
+
if (existsSync(localConfigPath)) {
|
|
359
|
+
try {
|
|
360
|
+
const content = await fs.readFile(localConfigPath, "utf-8");
|
|
361
|
+
config = JSON.parse(content);
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
// If file is corrupted, start with empty config
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
if (!config.permissions) {
|
|
368
|
+
config.permissions = {};
|
|
369
|
+
}
|
|
370
|
+
if (!config.permissions.allow) {
|
|
371
|
+
config.permissions.allow = [];
|
|
372
|
+
}
|
|
373
|
+
if (!config.permissions.allow.includes(rule)) {
|
|
374
|
+
config.permissions.allow.push(rule);
|
|
375
|
+
await fs.writeFile(localConfigPath, JSON.stringify(config, null, 2), "utf-8");
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// =============================================================================
|
|
380
|
+
// Extracted Configuration Functions
|
|
381
|
+
// =============================================================================
|
|
382
|
+
/**
|
|
383
|
+
* Validate environment variable configuration
|
|
384
|
+
*/
|
|
385
|
+
export function validateEnvironmentConfig(env, configPath) {
|
|
386
|
+
const result = {
|
|
387
|
+
isValid: true,
|
|
388
|
+
errors: [],
|
|
389
|
+
warnings: [],
|
|
390
|
+
};
|
|
391
|
+
// Check if env is defined
|
|
392
|
+
if (env === undefined || env === null) {
|
|
393
|
+
return result; // undefined/null env is valid (means no env vars)
|
|
394
|
+
}
|
|
395
|
+
// Validate that env is a Record<string, string>
|
|
396
|
+
if (!isValidEnvironmentVars(env)) {
|
|
397
|
+
result.isValid = false;
|
|
398
|
+
result.errors.push(`Invalid env field format${configPath ? ` in ${configPath}` : ""}. Environment variables must be a Record<string, string>.`);
|
|
399
|
+
return result;
|
|
400
|
+
}
|
|
401
|
+
// Additional validation for environment variable names
|
|
402
|
+
const envVars = env;
|
|
403
|
+
for (const [key, value] of Object.entries(envVars)) {
|
|
404
|
+
// Check for valid environment variable naming convention
|
|
405
|
+
if (!/^[A-Z_][A-Z0-9_]*$/i.test(key)) {
|
|
406
|
+
result.warnings.push(`Environment variable '${key}' does not follow standard naming convention (alphanumeric and underscores only).`);
|
|
407
|
+
}
|
|
408
|
+
// Check for empty values
|
|
409
|
+
if (value === "") {
|
|
410
|
+
result.warnings.push(`Environment variable '${key}' has an empty value.`);
|
|
411
|
+
}
|
|
412
|
+
// Check for reserved variable names that might cause conflicts
|
|
413
|
+
const reservedNames = [
|
|
414
|
+
"PATH",
|
|
415
|
+
"HOME",
|
|
416
|
+
"USER",
|
|
417
|
+
"PWD",
|
|
418
|
+
"SHELL",
|
|
419
|
+
"TERM",
|
|
420
|
+
"NODE_ENV",
|
|
421
|
+
];
|
|
422
|
+
if (reservedNames.includes(key.toUpperCase())) {
|
|
423
|
+
result.warnings.push(`Environment variable '${key}' overrides a system variable, which may cause unexpected behavior.`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return result;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Merge environment configurations with project taking precedence over user
|
|
430
|
+
*/
|
|
431
|
+
export function mergeEnvironmentConfig(userEnv, projectEnv, options = {}) {
|
|
432
|
+
const userVars = userEnv || {};
|
|
433
|
+
const projectVars = projectEnv || {};
|
|
434
|
+
const mergedVars = {};
|
|
435
|
+
const conflicts = [];
|
|
436
|
+
// Start with user environment variables
|
|
437
|
+
Object.assign(mergedVars, userVars);
|
|
438
|
+
// Override with project environment variables and track conflicts
|
|
439
|
+
for (const [key, projectValue] of Object.entries(projectVars)) {
|
|
440
|
+
const userValue = userVars[key];
|
|
441
|
+
if (userValue !== undefined &&
|
|
442
|
+
userValue !== projectValue &&
|
|
443
|
+
options.includeConflictWarnings !== false) {
|
|
444
|
+
// Conflict detected - project value takes precedence
|
|
445
|
+
conflicts.push({
|
|
446
|
+
key,
|
|
447
|
+
userValue,
|
|
448
|
+
projectValue,
|
|
449
|
+
resolvedValue: projectValue,
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
mergedVars[key] = projectValue;
|
|
453
|
+
}
|
|
454
|
+
return {
|
|
455
|
+
userVars,
|
|
456
|
+
projectVars,
|
|
457
|
+
mergedVars,
|
|
458
|
+
conflicts,
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Load Wave configuration from a JSON file
|
|
463
|
+
* Supports both hooks and environment variables with proper validation
|
|
464
|
+
*/
|
|
465
|
+
export function loadWaveConfigFromFile(filePath) {
|
|
466
|
+
if (!existsSync(filePath)) {
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
try {
|
|
470
|
+
const content = readFileSync(filePath, "utf-8");
|
|
471
|
+
const config = JSON.parse(content);
|
|
472
|
+
// Validate basic structure
|
|
473
|
+
if (!config || typeof config !== "object") {
|
|
474
|
+
throw new Error(`Invalid configuration structure in ${filePath}`);
|
|
475
|
+
}
|
|
476
|
+
// Validate environment variables if present
|
|
477
|
+
if (config.env !== undefined) {
|
|
478
|
+
const envValidation = validateEnvironmentConfig(config.env, filePath);
|
|
479
|
+
if (!envValidation.isValid) {
|
|
480
|
+
throw new Error(`Environment variable validation failed in ${filePath}: ${envValidation.errors.join(", ")}`);
|
|
481
|
+
}
|
|
482
|
+
// Log warnings if any
|
|
483
|
+
if (envValidation.warnings.length > 0) {
|
|
484
|
+
console.warn(`Environment variable warnings in ${filePath}:\n- ${envValidation.warnings.join("\n- ")}`);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
return {
|
|
488
|
+
hooks: config.hooks || undefined,
|
|
489
|
+
env: config.env || undefined,
|
|
490
|
+
defaultMode: config.defaultMode,
|
|
491
|
+
permissions: config.permissions || undefined,
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
catch (error) {
|
|
495
|
+
if (error instanceof SyntaxError) {
|
|
496
|
+
throw new Error(`Invalid JSON syntax in ${filePath}: ${error.message}`);
|
|
497
|
+
}
|
|
498
|
+
// Re-throw validation errors and other errors as-is
|
|
499
|
+
throw error;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Load Wave configuration from multiple file paths in priority order
|
|
504
|
+
* Returns the first valid configuration found, or null if none exist
|
|
505
|
+
*/
|
|
506
|
+
export function loadWaveConfigFromFiles(filePaths) {
|
|
507
|
+
for (const filePath of filePaths) {
|
|
508
|
+
const config = loadWaveConfigFromFile(filePath);
|
|
509
|
+
if (config !== null) {
|
|
510
|
+
return config;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
return null;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Load user-specific Wave configuration
|
|
517
|
+
* Checks .local.json first, then falls back to .json
|
|
518
|
+
*/
|
|
519
|
+
export function loadUserWaveConfig() {
|
|
520
|
+
return loadWaveConfigFromFiles(getUserConfigPaths());
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Load project-specific Wave configuration
|
|
524
|
+
* Checks .local.json first, then falls back to .json
|
|
525
|
+
*/
|
|
526
|
+
export function loadProjectWaveConfig(workdir) {
|
|
527
|
+
return loadWaveConfigFromFiles(getProjectConfigPaths(workdir));
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Load and merge Wave configuration from both user and project sources
|
|
531
|
+
* Project configuration takes precedence over user configuration
|
|
532
|
+
* Checks .local.json files first, then falls back to .json files
|
|
533
|
+
*/
|
|
534
|
+
export function loadMergedWaveConfig(workdir) {
|
|
535
|
+
const userConfig = loadUserWaveConfig();
|
|
536
|
+
const projectConfig = loadProjectWaveConfig(workdir);
|
|
537
|
+
// No configuration found
|
|
538
|
+
if (!userConfig && !projectConfig) {
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
541
|
+
// Only one configuration found
|
|
542
|
+
if (!userConfig)
|
|
543
|
+
return projectConfig;
|
|
544
|
+
if (!projectConfig)
|
|
545
|
+
return userConfig;
|
|
546
|
+
// Merge configurations (project overrides user)
|
|
547
|
+
const mergedHooks = {};
|
|
548
|
+
// Merge environment variables using the new mergeEnvironmentConfig function
|
|
549
|
+
const environmentContext = mergeEnvironmentConfig(userConfig.env, projectConfig.env, { includeConflictWarnings: true });
|
|
550
|
+
// Log environment variable conflicts if any
|
|
551
|
+
if (environmentContext.conflicts.length > 0) {
|
|
552
|
+
console.warn(`Environment variable conflicts detected (project values take precedence):\n${environmentContext.conflicts
|
|
553
|
+
.map((conflict) => `- ${conflict.key}: "${conflict.userValue}" → "${conflict.projectValue}"`)
|
|
554
|
+
.join("\n")}`);
|
|
555
|
+
}
|
|
556
|
+
// Merge hooks (combine arrays, project configs come after user configs)
|
|
557
|
+
const allEvents = new Set([
|
|
558
|
+
...Object.keys(userConfig.hooks || {}),
|
|
559
|
+
...Object.keys(projectConfig.hooks || {}),
|
|
560
|
+
]);
|
|
561
|
+
for (const event of allEvents) {
|
|
562
|
+
if (!isValidHookEvent(event))
|
|
563
|
+
continue;
|
|
564
|
+
const userEventConfigs = userConfig.hooks?.[event] || [];
|
|
565
|
+
const projectEventConfigs = projectConfig.hooks?.[event] || [];
|
|
566
|
+
// Project configurations take precedence
|
|
567
|
+
mergedHooks[event] = [...userEventConfigs, ...projectEventConfigs];
|
|
568
|
+
}
|
|
569
|
+
// Merge permissions (combine allow arrays)
|
|
570
|
+
const mergedPermissions = {};
|
|
571
|
+
const userAllow = userConfig.permissions?.allow || [];
|
|
572
|
+
const projectAllow = projectConfig.permissions?.allow || [];
|
|
573
|
+
if (userAllow.length > 0 || projectAllow.length > 0) {
|
|
574
|
+
mergedPermissions.allow = [...new Set([...userAllow, ...projectAllow])];
|
|
575
|
+
}
|
|
576
|
+
return {
|
|
577
|
+
hooks: Object.keys(mergedHooks).length > 0 ? mergedHooks : undefined,
|
|
578
|
+
env: Object.keys(environmentContext.mergedVars).length > 0
|
|
579
|
+
? environmentContext.mergedVars
|
|
580
|
+
: undefined,
|
|
581
|
+
// Project defaultMode takes precedence over user defaultMode
|
|
582
|
+
defaultMode: projectConfig.defaultMode ?? userConfig.defaultMode,
|
|
583
|
+
permissions: Object.keys(mergedPermissions).length > 0 ? mergedPermissions : undefined,
|
|
584
|
+
};
|
|
585
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fileWatcher.d.ts","sourceRoot":"","sources":["../../src/services/fileWatcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"fileWatcher.d.ts","sourceRoot":"","sources":["../../src/services/fileWatcher.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,cAAc,CAAC;CAC5B;AAaD,qBAAa,kBAAmB,SAAQ,YAAY;IAClD,OAAO,CAAC,QAAQ,CAA4C;IAC5D,OAAO,CAAC,aAAa,CAAmC;IACxD,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEZ,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAahE;;;OAGG;IACG,SAAS,CACb,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GACxC,OAAO,CAAC,IAAI,CAAC;IA+BhB;;;OAGG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB9C;;;OAGG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI;IA0BxD;;;OAGG;IACH,qBAAqB,IAAI,iBAAiB,EAAE;IAM5C;;;OAGG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG,IAAI;IAStD;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAUhB,iBAAiB;IAkD/B,OAAO,CAAC,wBAAwB;IA4BhC,OAAO,CAAC,eAAe;CA8BxB"}
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as chokidar from "chokidar";
|
|
8
8
|
import { EventEmitter } from "events";
|
|
9
|
-
import { FILE_WATCHER_EVENTS } from "../constants/events.js";
|
|
10
9
|
export class FileWatcherService extends EventEmitter {
|
|
11
10
|
constructor(logger, config) {
|
|
12
11
|
super();
|
|
@@ -92,7 +91,7 @@ export class FileWatcherService extends EventEmitter {
|
|
|
92
91
|
lastError: entry.lastError,
|
|
93
92
|
lastEvent: entry.lastEvent > 0
|
|
94
93
|
? {
|
|
95
|
-
type:
|
|
94
|
+
type: "change",
|
|
96
95
|
path: entry.path,
|
|
97
96
|
timestamp: entry.lastEvent,
|
|
98
97
|
}
|
|
@@ -173,14 +172,14 @@ export class FileWatcherService extends EventEmitter {
|
|
|
173
172
|
setupGlobalWatcherEvents() {
|
|
174
173
|
if (!this.globalWatcher)
|
|
175
174
|
return;
|
|
176
|
-
this.globalWatcher.on(
|
|
177
|
-
this.handleFileEvent(
|
|
175
|
+
this.globalWatcher.on("change", (filePath, stats) => {
|
|
176
|
+
this.handleFileEvent("change", filePath, stats);
|
|
178
177
|
});
|
|
179
178
|
this.globalWatcher.on("add", (filePath, stats) => {
|
|
180
|
-
this.handleFileEvent(
|
|
179
|
+
this.handleFileEvent("create", filePath, stats);
|
|
181
180
|
});
|
|
182
181
|
this.globalWatcher.on("unlink", (filePath) => {
|
|
183
|
-
this.handleFileEvent(
|
|
182
|
+
this.handleFileEvent("delete", filePath);
|
|
184
183
|
});
|
|
185
184
|
this.globalWatcher.on("error", (err) => {
|
|
186
185
|
const error = err instanceof Error ? err : new Error(String(err));
|