stigmergy 1.2.6 → 1.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -17
- package/STIGMERGY.md +16 -7
- package/docs/MULTI_USER_WIKI_COLLABORATION_SYSTEM.md +523 -0
- package/docs/PROMPT_BASED_SKILLS_SYSTEM_DESIGN.md +458 -0
- package/docs/SKILL_IMPLEMENTATION_CONSTRAINTS_AND_ALIGNMENT.md +423 -0
- package/docs/TECHNICAL_FEASIBILITY_ANALYSIS.md +308 -0
- package/examples/multilingual-hook-demo.js +125 -0
- package/package.json +14 -17
- package/scripts/dependency-analyzer.js +101 -0
- package/scripts/generate-cli-docs.js +64 -0
- package/scripts/postuninstall.js +46 -0
- package/scripts/preuninstall.js +75 -0
- package/scripts/run-layered-tests.js +3 -3
- package/src/adapters/claude/install_claude_integration.js +17 -17
- package/src/adapters/codebuddy/install_codebuddy_integration.js +13 -13
- package/src/adapters/codex/install_codex_integration.js +27 -27
- package/src/adapters/copilot/install_copilot_integration.js +46 -46
- package/src/adapters/gemini/install_gemini_integration.js +10 -10
- package/src/adapters/iflow/install_iflow_integration.js +7 -7
- package/src/adapters/qoder/install_qoder_integration.js +12 -12
- package/src/adapters/qwen/install_qwen_integration.js +17 -17
- package/src/auth.js +173 -173
- package/src/auth_command.js +208 -208
- package/src/calculator.js +313 -313
- package/src/cli/router.js +151 -7
- package/src/core/cache_cleaner.js +767 -767
- package/src/core/cli_help_analyzer.js +680 -680
- package/src/core/cli_parameter_handler.js +132 -132
- package/src/core/cli_tools.js +89 -89
- package/src/core/coordination/index.js +16 -16
- package/src/core/coordination/nodejs/AdapterManager.js +102 -102
- package/src/core/coordination/nodejs/CLCommunication.js +132 -132
- package/src/core/coordination/nodejs/CLIIntegrationManager.js +272 -272
- package/src/core/coordination/nodejs/HealthChecker.js +76 -76
- package/src/core/coordination/nodejs/HookDeploymentManager.js +463 -274
- package/src/core/coordination/nodejs/StatisticsCollector.js +71 -71
- package/src/core/coordination/nodejs/index.js +90 -90
- package/src/core/coordination/nodejs/utils/Logger.js +29 -29
- package/src/core/enhanced_installer.js +479 -479
- package/src/core/enhanced_uninstaller.js +638 -638
- package/src/core/error_handler.js +406 -406
- package/src/core/installer.js +32 -32
- package/src/core/memory_manager.js +83 -83
- package/src/core/multilingual/language-pattern-manager.js +172 -0
- package/src/core/rest_client.js +160 -160
- package/src/core/smart_router.js +261 -249
- package/src/core/upgrade_manager.js +48 -20
- package/src/data_encryption.js +143 -143
- package/src/data_structures.js +440 -440
- package/src/deploy.js +55 -55
- package/src/index.js +30 -30
- package/src/test/cli-availability-checker.js +194 -194
- package/src/test/test-environment.js +289 -289
- package/src/utils/helpers.js +35 -35
- package/src/utils.js +921 -921
- package/src/weatherProcessor.js +228 -228
- package/test/multilingual/hook-deployment.test.js +91 -0
- package/test/multilingual/language-pattern-manager.test.js +140 -0
- package/test/multilingual/system-test.js +85 -0
package/src/weatherProcessor.js
CHANGED
|
@@ -1,228 +1,228 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Weather Data Processing Module
|
|
3
|
-
*
|
|
4
|
-
* This module provides functions for processing weather data from various sources
|
|
5
|
-
* and converting it into standardized formats for analysis and display.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Process raw weather data and generate standardized output
|
|
10
|
-
* @param {Object} rawData - Raw weather data from API or sensor
|
|
11
|
-
* @param {Object} options - Processing options
|
|
12
|
-
* @param {string} options.unit - Temperature unit ('celsius', 'fahrenheit', 'kelvin')
|
|
13
|
-
* @param {boolean} options.includeForecasts - Whether to include forecast data
|
|
14
|
-
* @param {number} options.forecastDays - Number of forecast days to include (1-7)
|
|
15
|
-
* @returns {Object} Processed weather data with standardized format
|
|
16
|
-
* @throws {Error} If input data is invalid or missing required fields
|
|
17
|
-
*/
|
|
18
|
-
function processWeatherData(rawData, options = {}) {
|
|
19
|
-
// Validate input
|
|
20
|
-
if (!rawData || typeof rawData !== 'object') {
|
|
21
|
-
throw new Error('Invalid weather data: must be an object');
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Default options
|
|
25
|
-
const opts = {
|
|
26
|
-
unit: 'celsius',
|
|
27
|
-
includeForecasts: false,
|
|
28
|
-
forecastDays: 5,
|
|
29
|
-
...options,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
// Validate options
|
|
33
|
-
if (!['celsius', 'fahrenheit', 'kelvin'].includes(opts.unit)) {
|
|
34
|
-
throw new Error(
|
|
35
|
-
'Invalid unit: must be "celsius", "fahrenheit", or "kelvin"',
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (opts.forecastDays < 1 || opts.forecastDays > 7) {
|
|
40
|
-
throw new Error('Invalid forecastDays: must be between 1 and 7');
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Process current weather data
|
|
44
|
-
const processedData = {
|
|
45
|
-
timestamp: new Date().toISOString(),
|
|
46
|
-
location: _extractLocation(rawData),
|
|
47
|
-
current: _processCurrentWeather(rawData.current || rawData, opts.unit),
|
|
48
|
-
forecasts: opts.includeForecasts
|
|
49
|
-
? _processForecastData(rawData.forecast || [], opts)
|
|
50
|
-
: [],
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
return processedData;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Extract location information from raw data
|
|
58
|
-
* @param {Object} data - Raw weather data
|
|
59
|
-
* @returns {Object} Location information
|
|
60
|
-
*/
|
|
61
|
-
function _extractLocation(data) {
|
|
62
|
-
// Handle various location formats from different APIs
|
|
63
|
-
if (data.location) {
|
|
64
|
-
return {
|
|
65
|
-
name: data.location.name || data.location.city || 'Unknown',
|
|
66
|
-
country: data.location.country || '',
|
|
67
|
-
coordinates: {
|
|
68
|
-
lat: data.location.lat || data.location.latitude || 0,
|
|
69
|
-
lon: data.location.lon || data.location.longitude || 0,
|
|
70
|
-
},
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (data.city) {
|
|
75
|
-
return {
|
|
76
|
-
name: data.city.name || data.city,
|
|
77
|
-
country: data.city.country || '',
|
|
78
|
-
coordinates: {
|
|
79
|
-
lat: data.city.coord?.lat || data.city.latitude || 0,
|
|
80
|
-
lon: data.city.coord?.lon || data.city.longitude || 0,
|
|
81
|
-
},
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
name: 'Unknown',
|
|
87
|
-
country: '',
|
|
88
|
-
coordinates: { lat: 0, lon: 0 },
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Process current weather data
|
|
94
|
-
* @param {Object} current - Current weather data
|
|
95
|
-
* @param {string} unit - Temperature unit
|
|
96
|
-
* @returns {Object} Processed current weather data
|
|
97
|
-
*/
|
|
98
|
-
function _processCurrentWeather(current, unit) {
|
|
99
|
-
if (!current) {
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Convert temperature to requested unit
|
|
104
|
-
const temp = _convertTemperature(
|
|
105
|
-
current.temp || current.temperature || 0,
|
|
106
|
-
'kelvin',
|
|
107
|
-
unit,
|
|
108
|
-
);
|
|
109
|
-
const feelsLike = _convertTemperature(
|
|
110
|
-
current.feels_like || current.feelsLike || temp,
|
|
111
|
-
'kelvin',
|
|
112
|
-
unit,
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
temperature: {
|
|
117
|
-
value: temp,
|
|
118
|
-
unit: unit,
|
|
119
|
-
feelsLike: feelsLike,
|
|
120
|
-
},
|
|
121
|
-
humidity: current.humidity || current.humididy || 0,
|
|
122
|
-
pressure: current.pressure || 0,
|
|
123
|
-
wind: {
|
|
124
|
-
speed: current.wind_speed || current.windSpeed || 0,
|
|
125
|
-
direction: current.wind_deg || current.windDirection || 0,
|
|
126
|
-
},
|
|
127
|
-
visibility: current.visibility || 0,
|
|
128
|
-
cloudiness: current.clouds || current.cloudiness || 0,
|
|
129
|
-
description:
|
|
130
|
-
current.description || current.weather?.[0]?.description || 'Unknown',
|
|
131
|
-
icon: current.icon || current.weather?.[0]?.icon || '',
|
|
132
|
-
};
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Process forecast data
|
|
137
|
-
* @param {Array} forecasts - Array of forecast data
|
|
138
|
-
* @param {Object} options - Processing options
|
|
139
|
-
* @returns {Array} Processed forecast data
|
|
140
|
-
*/
|
|
141
|
-
function _processForecastData(forecasts, options) {
|
|
142
|
-
if (!Array.isArray(forecasts)) {
|
|
143
|
-
return [];
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Limit forecasts to requested number of days
|
|
147
|
-
const limitedForecasts = forecasts.slice(0, options.forecastDays);
|
|
148
|
-
|
|
149
|
-
return limitedForecasts.map((forecast) => {
|
|
150
|
-
const date = forecast.dt
|
|
151
|
-
? new Date(forecast.dt * 1000).toISOString().split('T')[0]
|
|
152
|
-
: forecast.date || new Date().toISOString().split('T')[0];
|
|
153
|
-
|
|
154
|
-
return {
|
|
155
|
-
date: date,
|
|
156
|
-
temperature: {
|
|
157
|
-
min: _convertTemperature(
|
|
158
|
-
forecast.temp?.min || forecast.min_temp || 0,
|
|
159
|
-
'kelvin',
|
|
160
|
-
options.unit,
|
|
161
|
-
),
|
|
162
|
-
max: _convertTemperature(
|
|
163
|
-
forecast.temp?.max || forecast.max_temp || 0,
|
|
164
|
-
'kelvin',
|
|
165
|
-
options.unit,
|
|
166
|
-
),
|
|
167
|
-
unit: options.unit,
|
|
168
|
-
},
|
|
169
|
-
humidity: forecast.humidity || 0,
|
|
170
|
-
pressure: forecast.pressure || 0,
|
|
171
|
-
wind: {
|
|
172
|
-
speed: forecast.wind_speed || forecast.windSpeed || 0,
|
|
173
|
-
direction: forecast.wind_deg || forecast.windDirection || 0,
|
|
174
|
-
},
|
|
175
|
-
precipitation: {
|
|
176
|
-
probability: forecast.pop || forecast.precipitation_probability || 0,
|
|
177
|
-
amount: forecast.rain || forecast.snow || 0,
|
|
178
|
-
},
|
|
179
|
-
description:
|
|
180
|
-
forecast.weather?.[0]?.description || forecast.description || 'Unknown',
|
|
181
|
-
};
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Convert temperature between units
|
|
187
|
-
* @param {number} value - Temperature value
|
|
188
|
-
* @param {string} fromUnit - Source unit ('celsius', 'fahrenheit', 'kelvin')
|
|
189
|
-
* @param {string} toUnit - Target unit ('celsius', 'fahrenheit', 'kelvin')
|
|
190
|
-
* @returns {number} Converted temperature value
|
|
191
|
-
*/
|
|
192
|
-
function _convertTemperature(value, fromUnit, toUnit) {
|
|
193
|
-
if (fromUnit === toUnit) {
|
|
194
|
-
return value;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Convert to Celsius first
|
|
198
|
-
let celsius;
|
|
199
|
-
switch (fromUnit) {
|
|
200
|
-
case 'celsius':
|
|
201
|
-
celsius = value;
|
|
202
|
-
break;
|
|
203
|
-
case 'fahrenheit':
|
|
204
|
-
celsius = ((value - 32) * 5) / 9;
|
|
205
|
-
break;
|
|
206
|
-
case 'kelvin':
|
|
207
|
-
celsius = value - 273.15;
|
|
208
|
-
break;
|
|
209
|
-
default:
|
|
210
|
-
celsius = value;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Convert from Celsius to target unit
|
|
214
|
-
switch (toUnit) {
|
|
215
|
-
case 'celsius':
|
|
216
|
-
return celsius;
|
|
217
|
-
case 'fahrenheit':
|
|
218
|
-
return (celsius * 9) / 5 + 32;
|
|
219
|
-
case 'kelvin':
|
|
220
|
-
return celsius + 273.15;
|
|
221
|
-
default:
|
|
222
|
-
return celsius;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
module.exports = {
|
|
227
|
-
processWeatherData,
|
|
228
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Weather Data Processing Module
|
|
3
|
+
*
|
|
4
|
+
* This module provides functions for processing weather data from various sources
|
|
5
|
+
* and converting it into standardized formats for analysis and display.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Process raw weather data and generate standardized output
|
|
10
|
+
* @param {Object} rawData - Raw weather data from API or sensor
|
|
11
|
+
* @param {Object} options - Processing options
|
|
12
|
+
* @param {string} options.unit - Temperature unit ('celsius', 'fahrenheit', 'kelvin')
|
|
13
|
+
* @param {boolean} options.includeForecasts - Whether to include forecast data
|
|
14
|
+
* @param {number} options.forecastDays - Number of forecast days to include (1-7)
|
|
15
|
+
* @returns {Object} Processed weather data with standardized format
|
|
16
|
+
* @throws {Error} If input data is invalid or missing required fields
|
|
17
|
+
*/
|
|
18
|
+
function processWeatherData(rawData, options = {}) {
|
|
19
|
+
// Validate input
|
|
20
|
+
if (!rawData || typeof rawData !== 'object') {
|
|
21
|
+
throw new Error('Invalid weather data: must be an object');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Default options
|
|
25
|
+
const opts = {
|
|
26
|
+
unit: 'celsius',
|
|
27
|
+
includeForecasts: false,
|
|
28
|
+
forecastDays: 5,
|
|
29
|
+
...options,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Validate options
|
|
33
|
+
if (!['celsius', 'fahrenheit', 'kelvin'].includes(opts.unit)) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
'Invalid unit: must be "celsius", "fahrenheit", or "kelvin"',
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (opts.forecastDays < 1 || opts.forecastDays > 7) {
|
|
40
|
+
throw new Error('Invalid forecastDays: must be between 1 and 7');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Process current weather data
|
|
44
|
+
const processedData = {
|
|
45
|
+
timestamp: new Date().toISOString(),
|
|
46
|
+
location: _extractLocation(rawData),
|
|
47
|
+
current: _processCurrentWeather(rawData.current || rawData, opts.unit),
|
|
48
|
+
forecasts: opts.includeForecasts
|
|
49
|
+
? _processForecastData(rawData.forecast || [], opts)
|
|
50
|
+
: [],
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return processedData;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Extract location information from raw data
|
|
58
|
+
* @param {Object} data - Raw weather data
|
|
59
|
+
* @returns {Object} Location information
|
|
60
|
+
*/
|
|
61
|
+
function _extractLocation(data) {
|
|
62
|
+
// Handle various location formats from different APIs
|
|
63
|
+
if (data.location) {
|
|
64
|
+
return {
|
|
65
|
+
name: data.location.name || data.location.city || 'Unknown',
|
|
66
|
+
country: data.location.country || '',
|
|
67
|
+
coordinates: {
|
|
68
|
+
lat: data.location.lat || data.location.latitude || 0,
|
|
69
|
+
lon: data.location.lon || data.location.longitude || 0,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (data.city) {
|
|
75
|
+
return {
|
|
76
|
+
name: data.city.name || data.city,
|
|
77
|
+
country: data.city.country || '',
|
|
78
|
+
coordinates: {
|
|
79
|
+
lat: data.city.coord?.lat || data.city.latitude || 0,
|
|
80
|
+
lon: data.city.coord?.lon || data.city.longitude || 0,
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
name: 'Unknown',
|
|
87
|
+
country: '',
|
|
88
|
+
coordinates: { lat: 0, lon: 0 },
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Process current weather data
|
|
94
|
+
* @param {Object} current - Current weather data
|
|
95
|
+
* @param {string} unit - Temperature unit
|
|
96
|
+
* @returns {Object} Processed current weather data
|
|
97
|
+
*/
|
|
98
|
+
function _processCurrentWeather(current, unit) {
|
|
99
|
+
if (!current) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Convert temperature to requested unit
|
|
104
|
+
const temp = _convertTemperature(
|
|
105
|
+
current.temp || current.temperature || 0,
|
|
106
|
+
'kelvin',
|
|
107
|
+
unit,
|
|
108
|
+
);
|
|
109
|
+
const feelsLike = _convertTemperature(
|
|
110
|
+
current.feels_like || current.feelsLike || temp,
|
|
111
|
+
'kelvin',
|
|
112
|
+
unit,
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
temperature: {
|
|
117
|
+
value: temp,
|
|
118
|
+
unit: unit,
|
|
119
|
+
feelsLike: feelsLike,
|
|
120
|
+
},
|
|
121
|
+
humidity: current.humidity || current.humididy || 0,
|
|
122
|
+
pressure: current.pressure || 0,
|
|
123
|
+
wind: {
|
|
124
|
+
speed: current.wind_speed || current.windSpeed || 0,
|
|
125
|
+
direction: current.wind_deg || current.windDirection || 0,
|
|
126
|
+
},
|
|
127
|
+
visibility: current.visibility || 0,
|
|
128
|
+
cloudiness: current.clouds || current.cloudiness || 0,
|
|
129
|
+
description:
|
|
130
|
+
current.description || current.weather?.[0]?.description || 'Unknown',
|
|
131
|
+
icon: current.icon || current.weather?.[0]?.icon || '',
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Process forecast data
|
|
137
|
+
* @param {Array} forecasts - Array of forecast data
|
|
138
|
+
* @param {Object} options - Processing options
|
|
139
|
+
* @returns {Array} Processed forecast data
|
|
140
|
+
*/
|
|
141
|
+
function _processForecastData(forecasts, options) {
|
|
142
|
+
if (!Array.isArray(forecasts)) {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Limit forecasts to requested number of days
|
|
147
|
+
const limitedForecasts = forecasts.slice(0, options.forecastDays);
|
|
148
|
+
|
|
149
|
+
return limitedForecasts.map((forecast) => {
|
|
150
|
+
const date = forecast.dt
|
|
151
|
+
? new Date(forecast.dt * 1000).toISOString().split('T')[0]
|
|
152
|
+
: forecast.date || new Date().toISOString().split('T')[0];
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
date: date,
|
|
156
|
+
temperature: {
|
|
157
|
+
min: _convertTemperature(
|
|
158
|
+
forecast.temp?.min || forecast.min_temp || 0,
|
|
159
|
+
'kelvin',
|
|
160
|
+
options.unit,
|
|
161
|
+
),
|
|
162
|
+
max: _convertTemperature(
|
|
163
|
+
forecast.temp?.max || forecast.max_temp || 0,
|
|
164
|
+
'kelvin',
|
|
165
|
+
options.unit,
|
|
166
|
+
),
|
|
167
|
+
unit: options.unit,
|
|
168
|
+
},
|
|
169
|
+
humidity: forecast.humidity || 0,
|
|
170
|
+
pressure: forecast.pressure || 0,
|
|
171
|
+
wind: {
|
|
172
|
+
speed: forecast.wind_speed || forecast.windSpeed || 0,
|
|
173
|
+
direction: forecast.wind_deg || forecast.windDirection || 0,
|
|
174
|
+
},
|
|
175
|
+
precipitation: {
|
|
176
|
+
probability: forecast.pop || forecast.precipitation_probability || 0,
|
|
177
|
+
amount: forecast.rain || forecast.snow || 0,
|
|
178
|
+
},
|
|
179
|
+
description:
|
|
180
|
+
forecast.weather?.[0]?.description || forecast.description || 'Unknown',
|
|
181
|
+
};
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Convert temperature between units
|
|
187
|
+
* @param {number} value - Temperature value
|
|
188
|
+
* @param {string} fromUnit - Source unit ('celsius', 'fahrenheit', 'kelvin')
|
|
189
|
+
* @param {string} toUnit - Target unit ('celsius', 'fahrenheit', 'kelvin')
|
|
190
|
+
* @returns {number} Converted temperature value
|
|
191
|
+
*/
|
|
192
|
+
function _convertTemperature(value, fromUnit, toUnit) {
|
|
193
|
+
if (fromUnit === toUnit) {
|
|
194
|
+
return value;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Convert to Celsius first
|
|
198
|
+
let celsius;
|
|
199
|
+
switch (fromUnit) {
|
|
200
|
+
case 'celsius':
|
|
201
|
+
celsius = value;
|
|
202
|
+
break;
|
|
203
|
+
case 'fahrenheit':
|
|
204
|
+
celsius = ((value - 32) * 5) / 9;
|
|
205
|
+
break;
|
|
206
|
+
case 'kelvin':
|
|
207
|
+
celsius = value - 273.15;
|
|
208
|
+
break;
|
|
209
|
+
default:
|
|
210
|
+
celsius = value;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Convert from Celsius to target unit
|
|
214
|
+
switch (toUnit) {
|
|
215
|
+
case 'celsius':
|
|
216
|
+
return celsius;
|
|
217
|
+
case 'fahrenheit':
|
|
218
|
+
return (celsius * 9) / 5 + 32;
|
|
219
|
+
case 'kelvin':
|
|
220
|
+
return celsius + 273.15;
|
|
221
|
+
default:
|
|
222
|
+
return celsius;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
module.exports = {
|
|
227
|
+
processWeatherData,
|
|
228
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// test/multilingual/hook-deployment.test.js
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const HookDeploymentManager = require('../../src/core/coordination/nodejs/HookDeploymentManager');
|
|
7
|
+
|
|
8
|
+
describe('HookDeploymentManager Multilingual Support', () => {
|
|
9
|
+
let deploymentManager;
|
|
10
|
+
let tempDir;
|
|
11
|
+
|
|
12
|
+
beforeAll(() => {
|
|
13
|
+
// Create a temporary directory for testing
|
|
14
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'stigmergy-test-'));
|
|
15
|
+
deploymentManager = new HookDeploymentManager();
|
|
16
|
+
deploymentManager.deploymentDir = tempDir;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
afterAll(() => {
|
|
20
|
+
// Clean up temporary directory
|
|
21
|
+
if (fs.existsSync(tempDir)) {
|
|
22
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('should initialize deployment manager', async () => {
|
|
27
|
+
await expect(deploymentManager.initialize()).resolves.toBeUndefined();
|
|
28
|
+
expect(fs.existsSync(tempDir)).toBe(true);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('should deploy hooks with multilingual support', async () => {
|
|
32
|
+
const cliName = 'claude';
|
|
33
|
+
const result = await deploymentManager.deployHooksForCLI(cliName);
|
|
34
|
+
expect(result).toBe(true);
|
|
35
|
+
|
|
36
|
+
// Check that the hook file was created
|
|
37
|
+
const hookDir = path.join(tempDir, cliName);
|
|
38
|
+
const hookFile = path.join(hookDir, `${cliName}_nodejs_hook.js`);
|
|
39
|
+
const configFile = path.join(hookDir, 'config.json');
|
|
40
|
+
|
|
41
|
+
expect(fs.existsSync(hookDir)).toBe(true);
|
|
42
|
+
expect(fs.existsSync(hookFile)).toBe(true);
|
|
43
|
+
expect(fs.existsSync(configFile)).toBe(true);
|
|
44
|
+
|
|
45
|
+
// Check that the hook file contains multilingual support
|
|
46
|
+
const hookContent = fs.readFileSync(hookFile, 'utf8');
|
|
47
|
+
expect(hookContent).toContain('LanguagePatternManager');
|
|
48
|
+
expect(hookContent).toContain('detectCrossCLIRequest');
|
|
49
|
+
|
|
50
|
+
// Check that the hook file contains patterns for multiple languages
|
|
51
|
+
expect(hookContent).toContain('请用');
|
|
52
|
+
expect(hookContent).toContain('使って');
|
|
53
|
+
expect(hookContent).toContain('benutze');
|
|
54
|
+
expect(hookContent).toContain('utilise');
|
|
55
|
+
expect(hookContent).toContain('usa');
|
|
56
|
+
expect(hookContent).toContain('usa'); // Italian
|
|
57
|
+
expect(hookContent).toContain('use'); // Portuguese
|
|
58
|
+
expect(hookContent).toContain('используй'); // Russian
|
|
59
|
+
expect(hookContent).toContain('استخدم'); // Arabic
|
|
60
|
+
expect(hookContent).toContain('kullanarak'); // Turkish
|
|
61
|
+
expect(hookContent).toContain('utiliser'); // French
|
|
62
|
+
expect(hookContent).toContain('usar'); // Spanish
|
|
63
|
+
expect(hookContent).toContain('utilizzare'); // Italian
|
|
64
|
+
expect(hookContent).toContain('verwenden'); // German
|
|
65
|
+
expect(hookContent).toContain('使う'); // Japanese
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('should validate hook deployment', async () => {
|
|
69
|
+
const cliName = 'gemini';
|
|
70
|
+
await deploymentManager.deployHooksForCLI(cliName);
|
|
71
|
+
|
|
72
|
+
const validationResult = await deploymentManager.validateHookDeployment(cliName);
|
|
73
|
+
expect(validationResult.valid).toBe(true);
|
|
74
|
+
expect(validationResult.message).toBe('Hook deployment is valid');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('should list deployed hooks', async () => {
|
|
78
|
+
const hooks = await deploymentManager.listDeployedHooks();
|
|
79
|
+
expect(Array.isArray(hooks)).toBe(true);
|
|
80
|
+
expect(hooks.length).toBeGreaterThanOrEqual(1);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('should undeploy hooks', async () => {
|
|
84
|
+
const cliName = 'claude';
|
|
85
|
+
const result = await deploymentManager.undeployHooksForCLI(cliName);
|
|
86
|
+
expect(result).toBe(true);
|
|
87
|
+
|
|
88
|
+
const hookDir = path.join(tempDir, cliName);
|
|
89
|
+
expect(fs.existsSync(hookDir)).toBe(false);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// test/multilingual/language-pattern-manager.test.js
|
|
2
|
+
|
|
3
|
+
const LanguagePatternManager = require('../../src/core/multilingual/language-pattern-manager');
|
|
4
|
+
|
|
5
|
+
describe('LanguagePatternManager', () => {
|
|
6
|
+
let manager;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
manager = new LanguagePatternManager();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test('should load language patterns correctly', () => {
|
|
13
|
+
expect(manager.languagePatterns).toBeDefined();
|
|
14
|
+
expect(Object.keys(manager.languagePatterns).length).toBeGreaterThan(0);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('should detect English patterns', () => {
|
|
18
|
+
const result = manager.detectCrossCLIRequest('use claude to write code');
|
|
19
|
+
expect(result).toBeDefined();
|
|
20
|
+
expect(result.targetCLI).toBe('claude');
|
|
21
|
+
expect(result.task).toBe('write code');
|
|
22
|
+
expect(result.language).toBe('en');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('should detect Chinese patterns', () => {
|
|
26
|
+
const result = manager.detectCrossCLIRequest('请用copilot帮我创建React组件');
|
|
27
|
+
expect(result).toBeDefined();
|
|
28
|
+
expect(result.targetCLI).toBe('copilot');
|
|
29
|
+
expect(result.task).toBe('创建React组件');
|
|
30
|
+
expect(result.language).toBe('zh');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('should detect Japanese patterns', () => {
|
|
34
|
+
const result = manager.detectCrossCLIRequest('claudeを使ってコードを書いて関数を作成');
|
|
35
|
+
expect(result).toBeDefined();
|
|
36
|
+
expect(result.targetCLI).toBe('claude');
|
|
37
|
+
expect(result.task).toBe('関数を作成');
|
|
38
|
+
expect(result.language).toBe('ja');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('should detect Korean patterns', () => {
|
|
42
|
+
const result = manager.detectCrossCLIRequest('claude로 코드 작성해 줘함수를 만들어');
|
|
43
|
+
expect(result).toBeDefined();
|
|
44
|
+
expect(result.targetCLI).toBe('claude');
|
|
45
|
+
expect(result.task).toBe('함수를 만들어');
|
|
46
|
+
expect(result.language).toBe('ko');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('should detect German patterns', () => {
|
|
50
|
+
const result = manager.detectCrossCLIRequest('benutze claude um code zu schreiben');
|
|
51
|
+
expect(result).toBeDefined();
|
|
52
|
+
expect(result.targetCLI).toBe('claude');
|
|
53
|
+
expect(result.task).toBe('code zu schreiben');
|
|
54
|
+
expect(result.language).toBe('de');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('should detect French patterns', () => {
|
|
58
|
+
const result = manager.detectCrossCLIRequest('utilise claude pour écrire du code');
|
|
59
|
+
expect(result).toBeDefined();
|
|
60
|
+
expect(result.targetCLI).toBe('claude');
|
|
61
|
+
expect(result.task).toBe('écrire du code');
|
|
62
|
+
expect(result.language).toBe('fr');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('should detect Spanish patterns', () => {
|
|
66
|
+
const result = manager.detectCrossCLIRequest('usa claude para escribir código');
|
|
67
|
+
expect(result).toBeDefined();
|
|
68
|
+
expect(result.targetCLI).toBe('claude');
|
|
69
|
+
expect(result.task).toBe('escribir código');
|
|
70
|
+
expect(result.language).toBe('es');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('should detect Italian patterns', () => {
|
|
74
|
+
const result = manager.detectCrossCLIRequest('usa claude per scrivere codice');
|
|
75
|
+
expect(result).toBeDefined();
|
|
76
|
+
expect(result.targetCLI).toBe('claude');
|
|
77
|
+
expect(result.task).toBe('scrivere codice');
|
|
78
|
+
expect(result.language).toBe('it');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('should detect Portuguese patterns', () => {
|
|
82
|
+
const result = manager.detectCrossCLIRequest('use claude para escrever código');
|
|
83
|
+
expect(result).toBeDefined();
|
|
84
|
+
expect(result.targetCLI).toBe('claude');
|
|
85
|
+
expect(result.task).toBe('escrever código');
|
|
86
|
+
expect(result.language).toBe('pt');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test('should detect Russian patterns', () => {
|
|
90
|
+
const result = manager.detectCrossCLIRequest('используй claude чтобы написать код');
|
|
91
|
+
expect(result).toBeDefined();
|
|
92
|
+
expect(result.targetCLI).toBe('claude');
|
|
93
|
+
expect(result.task).toBe('написать код');
|
|
94
|
+
expect(result.language).toBe('ru');
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
test('should detect Arabic patterns', () => {
|
|
98
|
+
const result = manager.detectCrossCLIRequest('استخدم claude لكتابة الكود');
|
|
99
|
+
expect(result).toBeDefined();
|
|
100
|
+
expect(result.targetCLI).toBe('claude');
|
|
101
|
+
expect(result.task).toBe('كتابة الكود');
|
|
102
|
+
expect(result.language).toBe('ar');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('should detect Turkish patterns', () => {
|
|
106
|
+
const result = manager.detectCrossCLIRequest('claude kullanarak kod yaz bir fonksiyon');
|
|
107
|
+
expect(result).toBeDefined();
|
|
108
|
+
expect(result.targetCLI).toBe('claude');
|
|
109
|
+
expect(result.task).toBe('kod yaz bir fonksiyon');
|
|
110
|
+
expect(result.language).toBe('tr');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('should return null for unsupported CLI tools', () => {
|
|
114
|
+
const result = manager.detectCrossCLIRequest('use nonexistenttool to do something');
|
|
115
|
+
expect(result).toBeNull();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('should return null for non-cross-CLI requests', () => {
|
|
119
|
+
const result = manager.detectCrossCLIRequest('just a regular prompt');
|
|
120
|
+
expect(result).toBeNull();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test('should get patterns for specific language', () => {
|
|
124
|
+
const patterns = manager.getPatterns('en');
|
|
125
|
+
expect(Array.isArray(patterns)).toBe(true);
|
|
126
|
+
expect(patterns.length).toBeGreaterThan(0);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('should get all patterns', () => {
|
|
130
|
+
const allPatterns = manager.getAllPatterns();
|
|
131
|
+
expect(allPatterns).toBeDefined();
|
|
132
|
+
expect(Object.keys(allPatterns).length).toBeGreaterThan(0);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test('should detect language from environment', () => {
|
|
136
|
+
const language = manager.detectLanguage();
|
|
137
|
+
expect(typeof language).toBe('string');
|
|
138
|
+
expect(language.length).toBeGreaterThan(0);
|
|
139
|
+
});
|
|
140
|
+
});
|