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.
Files changed (59) hide show
  1. package/README.md +32 -17
  2. package/STIGMERGY.md +16 -7
  3. package/docs/MULTI_USER_WIKI_COLLABORATION_SYSTEM.md +523 -0
  4. package/docs/PROMPT_BASED_SKILLS_SYSTEM_DESIGN.md +458 -0
  5. package/docs/SKILL_IMPLEMENTATION_CONSTRAINTS_AND_ALIGNMENT.md +423 -0
  6. package/docs/TECHNICAL_FEASIBILITY_ANALYSIS.md +308 -0
  7. package/examples/multilingual-hook-demo.js +125 -0
  8. package/package.json +14 -17
  9. package/scripts/dependency-analyzer.js +101 -0
  10. package/scripts/generate-cli-docs.js +64 -0
  11. package/scripts/postuninstall.js +46 -0
  12. package/scripts/preuninstall.js +75 -0
  13. package/scripts/run-layered-tests.js +3 -3
  14. package/src/adapters/claude/install_claude_integration.js +17 -17
  15. package/src/adapters/codebuddy/install_codebuddy_integration.js +13 -13
  16. package/src/adapters/codex/install_codex_integration.js +27 -27
  17. package/src/adapters/copilot/install_copilot_integration.js +46 -46
  18. package/src/adapters/gemini/install_gemini_integration.js +10 -10
  19. package/src/adapters/iflow/install_iflow_integration.js +7 -7
  20. package/src/adapters/qoder/install_qoder_integration.js +12 -12
  21. package/src/adapters/qwen/install_qwen_integration.js +17 -17
  22. package/src/auth.js +173 -173
  23. package/src/auth_command.js +208 -208
  24. package/src/calculator.js +313 -313
  25. package/src/cli/router.js +151 -7
  26. package/src/core/cache_cleaner.js +767 -767
  27. package/src/core/cli_help_analyzer.js +680 -680
  28. package/src/core/cli_parameter_handler.js +132 -132
  29. package/src/core/cli_tools.js +89 -89
  30. package/src/core/coordination/index.js +16 -16
  31. package/src/core/coordination/nodejs/AdapterManager.js +102 -102
  32. package/src/core/coordination/nodejs/CLCommunication.js +132 -132
  33. package/src/core/coordination/nodejs/CLIIntegrationManager.js +272 -272
  34. package/src/core/coordination/nodejs/HealthChecker.js +76 -76
  35. package/src/core/coordination/nodejs/HookDeploymentManager.js +463 -274
  36. package/src/core/coordination/nodejs/StatisticsCollector.js +71 -71
  37. package/src/core/coordination/nodejs/index.js +90 -90
  38. package/src/core/coordination/nodejs/utils/Logger.js +29 -29
  39. package/src/core/enhanced_installer.js +479 -479
  40. package/src/core/enhanced_uninstaller.js +638 -638
  41. package/src/core/error_handler.js +406 -406
  42. package/src/core/installer.js +32 -32
  43. package/src/core/memory_manager.js +83 -83
  44. package/src/core/multilingual/language-pattern-manager.js +172 -0
  45. package/src/core/rest_client.js +160 -160
  46. package/src/core/smart_router.js +261 -249
  47. package/src/core/upgrade_manager.js +48 -20
  48. package/src/data_encryption.js +143 -143
  49. package/src/data_structures.js +440 -440
  50. package/src/deploy.js +55 -55
  51. package/src/index.js +30 -30
  52. package/src/test/cli-availability-checker.js +194 -194
  53. package/src/test/test-environment.js +289 -289
  54. package/src/utils/helpers.js +35 -35
  55. package/src/utils.js +921 -921
  56. package/src/weatherProcessor.js +228 -228
  57. package/test/multilingual/hook-deployment.test.js +91 -0
  58. package/test/multilingual/language-pattern-manager.test.js +140 -0
  59. package/test/multilingual/system-test.js +85 -0
@@ -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
+ });