stigmergy 1.2.0 → 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 (130) hide show
  1. package/LICENSE +18 -18
  2. package/README.md +31 -211
  3. package/STIGMERGY.md +70 -61
  4. package/docs/MULTI_USER_WIKI_COLLABORATION_SYSTEM.md +523 -0
  5. package/docs/PROJECT_CONSTITUTION.md +433 -433
  6. package/docs/PROJECT_STRUCTURE_CURRENT.md +80 -80
  7. package/docs/PROMPT_BASED_SKILLS_SYSTEM_DESIGN.md +458 -0
  8. package/docs/SKILL_IMPLEMENTATION_CONSTRAINTS_AND_ALIGNMENT.md +423 -0
  9. package/docs/TECHNICAL_FEASIBILITY_ANALYSIS.md +308 -0
  10. package/examples/calculator-example.js +72 -72
  11. package/examples/cline_usage_examples.md +364 -364
  12. package/examples/encryption-example.js +67 -67
  13. package/examples/json-parser-example.js +120 -120
  14. package/examples/json-validation-example.js +64 -64
  15. package/examples/multilingual-hook-demo.js +125 -0
  16. package/examples/rest-client-example.js +52 -52
  17. package/examples/rest_client_example.js +54 -54
  18. package/package.json +38 -20
  19. package/scripts/build.js +74 -74
  20. package/scripts/dependency-analyzer.js +101 -0
  21. package/scripts/generate-cli-docs.js +64 -0
  22. package/scripts/post-deployment-config.js +296 -296
  23. package/scripts/postuninstall.js +46 -0
  24. package/scripts/preinstall-check.js +173 -173
  25. package/scripts/preuninstall.js +75 -0
  26. package/scripts/publish.js +58 -268
  27. package/scripts/run-layered-tests.js +247 -0
  28. package/scripts/safe-install.js +139 -139
  29. package/scripts/simple-publish.js +57 -59
  30. package/src/adapters/claude/install_claude_integration.js +292 -0
  31. package/src/adapters/codebuddy/install_codebuddy_integration.js +349 -0
  32. package/src/adapters/codex/install_codex_integration.js +395 -0
  33. package/src/adapters/copilot/install_copilot_integration.js +716 -0
  34. package/src/adapters/gemini/install_gemini_integration.js +304 -0
  35. package/src/adapters/iflow/install_iflow_integration.js +304 -0
  36. package/src/adapters/qoder/install_qoder_integration.js +1090 -0
  37. package/src/adapters/qwen/install_qwen_integration.js +285 -0
  38. package/src/cli/router.js +562 -39
  39. package/src/core/cache_cleaner.js +82 -59
  40. package/src/core/cli_help_analyzer.js +297 -291
  41. package/src/core/cli_parameter_handler.js +5 -0
  42. package/src/core/cli_tools.js +6 -6
  43. package/src/core/coordination/index.js +2 -2
  44. package/src/core/coordination/nodejs/AdapterManager.js +30 -17
  45. package/src/core/coordination/nodejs/CLCommunication.js +28 -20
  46. package/src/core/coordination/nodejs/CLIIntegrationManager.js +72 -36
  47. package/src/core/coordination/nodejs/HealthChecker.js +13 -14
  48. package/src/core/coordination/nodejs/HookDeploymentManager.js +325 -63
  49. package/src/core/coordination/nodejs/StatisticsCollector.js +6 -6
  50. package/src/core/coordination/nodejs/index.js +29 -11
  51. package/src/core/coordination/nodejs/utils/Logger.js +1 -1
  52. package/src/core/enhanced_installer.js +92 -69
  53. package/src/core/enhanced_uninstaller.js +73 -53
  54. package/src/core/installer.js +815 -294
  55. package/src/core/multilingual/language-pattern-manager.js +172 -0
  56. package/src/core/smart_router.js +141 -26
  57. package/src/core/upgrade_manager.js +91 -46
  58. package/src/data_structures.js +1 -1
  59. package/src/deploy.js +2 -2
  60. package/src/index.js +3 -3
  61. package/src/test/cli-availability-checker.js +194 -0
  62. package/src/test/test-environment.js +289 -0
  63. package/src/utils/helpers.js +2 -2
  64. package/src/utils.js +7 -1
  65. package/test/multilingual/hook-deployment.test.js +91 -0
  66. package/test/multilingual/language-pattern-manager.test.js +140 -0
  67. package/test/multilingual/system-test.js +85 -0
  68. package/test/cache-cleaner-implemented.test.js +0 -328
  69. package/test/cache-cleaner.test.js +0 -390
  70. package/test/calculator.test.js +0 -215
  71. package/test/collision-test.js +0 -26
  72. package/test/comprehensive-enhanced-features.test.js +0 -252
  73. package/test/comprehensive-execution-test.js +0 -428
  74. package/test/conflict-prevention-test.js +0 -95
  75. package/test/cross-cli-detection-test.js +0 -33
  76. package/test/csv-processing-test.js +0 -36
  77. package/test/deploy-hooks-test.js +0 -250
  78. package/test/e2e/claude-cli-test.js +0 -128
  79. package/test/e2e/collaboration-test.js +0 -75
  80. package/test/e2e/comprehensive-test.js +0 -431
  81. package/test/e2e/error-handling-test.js +0 -90
  82. package/test/e2e/individual-tool-test.js +0 -143
  83. package/test/e2e/other-cli-test.js +0 -130
  84. package/test/e2e/qoder-cli-test.js +0 -128
  85. package/test/e2e/run-e2e-tests.js +0 -73
  86. package/test/e2e/test-data.js +0 -88
  87. package/test/e2e/test-utils.js +0 -222
  88. package/test/encryption-simple-test.js +0 -110
  89. package/test/encryption.test.js +0 -129
  90. package/test/enhanced-main-alignment.test.js +0 -298
  91. package/test/enhanced-uninstaller-implemented.test.js +0 -271
  92. package/test/enhanced-uninstaller.test.js +0 -284
  93. package/test/error-handling-test.js +0 -341
  94. package/test/fibonacci.test.js +0 -178
  95. package/test/final-deploy-test.js +0 -221
  96. package/test/final-install-test.js +0 -226
  97. package/test/hash-table-demo.js +0 -33
  98. package/test/hash-table-test.js +0 -26
  99. package/test/hash_table_test.js +0 -114
  100. package/test/hook-system-integration-test.js +0 -307
  101. package/test/iflow-integration-test.js +0 -292
  102. package/test/improved-install-test.js +0 -362
  103. package/test/install-command-test.js +0 -370
  104. package/test/json-parser-test.js +0 -161
  105. package/test/json-validation-test.js +0 -164
  106. package/test/natural-language-skills-test.js +0 -320
  107. package/test/nl-integration-test.js +0 -179
  108. package/test/parameter-parsing-test.js +0 -143
  109. package/test/plugin-deployment-test.js +0 -316
  110. package/test/postinstall-test.js +0 -269
  111. package/test/python-plugins-test.js +0 -259
  112. package/test/real-test.js +0 -435
  113. package/test/remaining-adapters-test.js +0 -256
  114. package/test/rest-client-test.js +0 -56
  115. package/test/rest_client.test.js +0 -85
  116. package/test/safe-installation-cleaner.test.js +0 -343
  117. package/test/simple-iflow-hook-test.js +0 -137
  118. package/test/stigmergy-upgrade-test.js +0 -243
  119. package/test/system-compatibility-test.js +0 -467
  120. package/test/tdd-deploy-fix-test.js +0 -324
  121. package/test/tdd-fixes-test.js +0 -211
  122. package/test/third-party-skills-test.js +0 -321
  123. package/test/tool-selection-integration-test.js +0 -158
  124. package/test/unit/calculator-full.test.js +0 -191
  125. package/test/unit/calculator-simple.test.js +0 -96
  126. package/test/unit/calculator.test.js +0 -97
  127. package/test/unit/cli-scanner.test.js +0 -291
  128. package/test/unit/cli_parameter_handler.test.js +0 -116
  129. package/test/unit/cross-cli-executor.test.js +0 -399
  130. package/test/weather-processor.test.js +0 -104
@@ -0,0 +1,289 @@
1
+ /**
2
+ * Test Environment Isolation
3
+ * Creates isolated environment for testing without affecting user setup
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const os = require('os');
9
+ const { spawn } = require('child_process');
10
+
11
+ class TestEnvironment {
12
+ constructor(name = 'stigmergy-test') {
13
+ this.name = name;
14
+ this.baseDir = path.join(os.tmpdir(), name);
15
+ this.originalEnv = { ...process.env };
16
+ this.isSetup = false;
17
+ }
18
+
19
+ /**
20
+ * Setup isolated test environment
21
+ * @param {Object} options - Setup options
22
+ */
23
+ async setup(options = {}) {
24
+ const { clean = true } = options;
25
+
26
+ // Create base directory
27
+ if (clean && fs.existsSync(this.baseDir)) {
28
+ await this.cleanup();
29
+ }
30
+ fs.mkdirSync(this.baseDir, { recursive: true });
31
+
32
+ // Setup home directory
33
+ this.testHome = path.join(this.baseDir, 'home');
34
+ fs.mkdirSync(this.testHome, { recursive: true });
35
+
36
+ // Setup test configuration directories
37
+ this.configDirs = {
38
+ stigmergy: path.join(this.testHome, '.stigmergy'),
39
+ claude: path.join(this.testHome, '.claude'),
40
+ gemini: path.join(this.testHome, '.gemini'),
41
+ qwen: path.join(this.testHome, '.qwen'),
42
+ // Add more as needed
43
+ };
44
+
45
+ Object.values(this.configDirs).forEach(dir => {
46
+ fs.mkdirSync(dir, { recursive: true });
47
+ });
48
+
49
+ // Modify environment variables
50
+ process.env.HOME = this.testHome;
51
+ process.env.USERPROFILE = this.testHome; // Windows
52
+ process.env.PATH = this.createSafePath();
53
+
54
+ this.isSetup = true;
55
+ }
56
+
57
+ /**
58
+ * Create safe PATH with essential tools only
59
+ * @returns {string} Safe PATH
60
+ */
61
+ createSafePath() {
62
+ const essentialPaths = [
63
+ '/usr/bin',
64
+ '/usr/local/bin',
65
+ path.join(process.env.ProgramFiles || '', 'Git', 'bin'),
66
+ path.join(process.env.ProgramFiles || '', 'nodejs'),
67
+ ].filter(p => p && fs.existsSync(p));
68
+
69
+ return essentialPaths.join(path.delimiter);
70
+ }
71
+
72
+ /**
73
+ * Setup mock CLI tools for testing
74
+ * @param {Object} mockTools - Map of tool name to mock implementation
75
+ */
76
+ async setupMockCLIs(mockTools = {}) {
77
+ const mockBinDir = path.join(this.testHome, 'bin');
78
+ fs.mkdirSync(mockBinDir, { recursive: true });
79
+
80
+ // Add mock bin directory to PATH
81
+ process.env.PATH = `${mockBinDir}${path.delimiter}${process.env.PATH}`;
82
+
83
+ for (const [toolName, behavior] of Object.entries(mockTools)) {
84
+ await this.createMockCLI(toolName, behavior, mockBinDir);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Create a mock CLI tool
90
+ * @param {string} name - Tool name
91
+ * @param {Object} behavior - Mock behavior
92
+ * @param {string} binDir - Binary directory
93
+ */
94
+ async createMockCLI(name, behavior, binDir) {
95
+ const script = this.generateMockScript(name, behavior);
96
+ const scriptPath = path.join(binDir, name);
97
+
98
+ if (process.platform === 'win32') {
99
+ // Windows batch file
100
+ const batPath = scriptPath + '.cmd';
101
+ fs.writeFileSync(batPath, `@echo off\n${script}\n`, 'utf8');
102
+ // Make executable
103
+ fs.chmodSync(batPath, '755');
104
+ } else {
105
+ // Unix shell script
106
+ fs.writeFileSync(scriptPath, `#!/bin/bash\n${script}\n`, 'utf8');
107
+ // Make executable
108
+ fs.chmodSync(scriptPath, '755');
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Generate mock script content
114
+ * @param {string} toolName - Tool name
115
+ * @param {Object} behavior - Mock behavior definition
116
+ * @returns {string} Script content
117
+ */
118
+ generateMockScript(toolName, behavior) {
119
+ const defaultBehavior = {
120
+ version: `${toolName} version 1.0.0-mock`,
121
+ success: true,
122
+ delay: 0,
123
+ output: `Mock ${toolName} executed successfully`
124
+ };
125
+
126
+ const config = { ...defaultBehavior, ...behavior };
127
+
128
+ let script = '';
129
+ if (config.delay > 0) {
130
+ script += `sleep ${config.delay}\n`;
131
+ }
132
+
133
+ // Handle version command
134
+ script += 'if echo "$*" | grep -q "\\-\\-version\\|-v"; then\n';
135
+ script += ` echo "${config.version}"\n`;
136
+ script += ' exit 0\n';
137
+ script += 'fi\n';
138
+
139
+ // Handle help command
140
+ script += 'if echo "$*" | grep -q "\\-\\-help\\|-h"; then\n';
141
+ script += ` echo "Mock ${toolName} help"\n`;
142
+ script += ` echo "Usage: ${toolName} [options]"\n`;
143
+ script += ' exit 0\n';
144
+ script += 'fi\n';
145
+
146
+ // Handle prompt flag
147
+ script += 'PROMPT=""\n';
148
+ script += 'for arg in "$@"; do\n';
149
+ script += ' if [[ "$arg" == "-p" ]]; then\n';
150
+ script += ' PROMPT="$1"\n';
151
+ script += ' shift\n';
152
+ script += ' fi\n';
153
+ script += ' shift\n';
154
+ script += 'done\n';
155
+
156
+ // Generate response
157
+ script += 'if [ -n "$PROMPT" ]; then\n';
158
+ script += ' echo "Mock response for: $PROMPT"\n';
159
+ script += ` echo "${config.output}"\n`;
160
+ script += 'else\n';
161
+ script += ` echo "${config.output}"\n`;
162
+ script += 'fi\n';
163
+
164
+ // Handle success/failure
165
+ script += config.success ? 'exit 0\n' : 'exit 1\n';
166
+
167
+ return script;
168
+ }
169
+
170
+ /**
171
+ * Execute command in isolated environment
172
+ * @param {string} command - Command to execute
173
+ * @param {Array} args - Command arguments
174
+ * @param {Object} options - Execution options
175
+ * @returns {Promise<Object>} Execution result
176
+ */
177
+ async execute(command, args = [], options = {}) {
178
+ if (!this.isSetup) {
179
+ throw new Error('Test environment not setup. Call setup() first.');
180
+ }
181
+
182
+ return new Promise((resolve) => {
183
+ let stdout = '';
184
+ let stderr = '';
185
+
186
+ const child = spawn(command, args, {
187
+ stdio: ['ignore', 'pipe', 'pipe'],
188
+ shell: true,
189
+ env: process.env, // Use modified environment
190
+ ...options
191
+ });
192
+
193
+ child.stdout?.on('data', (data) => {
194
+ stdout += data.toString();
195
+ });
196
+
197
+ child.stderr?.on('data', (data) => {
198
+ stderr += data.toString();
199
+ });
200
+
201
+ child.on('close', (code) => {
202
+ resolve({
203
+ success: code === 0,
204
+ stdout,
205
+ stderr,
206
+ exitCode: code
207
+ });
208
+ });
209
+
210
+ child.on('error', (error) => {
211
+ resolve({
212
+ success: false,
213
+ stdout,
214
+ stderr,
215
+ error: error.message
216
+ });
217
+ });
218
+ });
219
+ }
220
+
221
+ /**
222
+ * Create test data in environment
223
+ * @param {Object} testData - Test data structure
224
+ */
225
+ createTestData(testData = {}) {
226
+ for (const [filePath, content] of Object.entries(testData)) {
227
+ const fullPath = path.join(this.testHome, filePath);
228
+ const dir = path.dirname(fullPath);
229
+
230
+ // Create directory if it doesn't exist
231
+ if (!fs.existsSync(dir)) {
232
+ fs.mkdirSync(dir, { recursive: true });
233
+ }
234
+
235
+ // Write file
236
+ if (typeof content === 'object') {
237
+ fs.writeFileSync(fullPath, JSON.stringify(content, null, 2), 'utf8');
238
+ } else {
239
+ fs.writeFileSync(fullPath, content, 'utf8');
240
+ }
241
+ }
242
+ }
243
+
244
+ /**
245
+ * Restore original environment
246
+ */
247
+ restore() {
248
+ if (!this.isSetup) return;
249
+
250
+ // Restore environment variables
251
+ Object.keys(this.originalEnv).forEach(key => {
252
+ process.env[key] = this.originalEnv[key];
253
+ });
254
+
255
+ // Remove any additions
256
+ const addedKeys = Object.keys(process.env).filter(key => !this.originalEnv.hasOwnProperty(key));
257
+ addedKeys.forEach(key => {
258
+ delete process.env[key];
259
+ });
260
+
261
+ this.isSetup = false;
262
+ }
263
+
264
+ /**
265
+ * Cleanup test environment
266
+ */
267
+ async cleanup() {
268
+ this.restore();
269
+
270
+ try {
271
+ if (fs.existsSync(this.baseDir)) {
272
+ fs.rmSync(this.baseDir, { recursive: true, force: true });
273
+ }
274
+ } catch (error) {
275
+ console.warn(`Warning: Could not cleanup test directory: ${error.message}`);
276
+ }
277
+ }
278
+
279
+ /**
280
+ * Get path in test environment
281
+ * @param {...string} parts - Path parts
282
+ * @returns {string} Full path in test environment
283
+ */
284
+ getPath(...parts) {
285
+ return path.join(this.testHome, ...parts);
286
+ }
287
+ }
288
+
289
+ module.exports = TestEnvironment;
@@ -31,5 +31,5 @@ function isAuthenticated() {
31
31
 
32
32
  module.exports = {
33
33
  maxOfTwo,
34
- isAuthenticated
35
- };
34
+ isAuthenticated,
35
+ };
package/src/utils.js CHANGED
@@ -678,6 +678,12 @@ async function executeCommand(command, args = [], options = {}) {
678
678
 
679
679
  const child = spawn(command, args, opts);
680
680
 
681
+ // Add debug logging for Windows command execution
682
+ if (process.platform === 'win32' && process.env.DEBUG === 'true') {
683
+ console.log(`[DEBUG] Spawned process with command: ${command}`);
684
+ console.log(`[DEBUG] Spawned process with args: ${JSON.stringify(args)}`);
685
+ }
686
+
681
687
  let stdout = '';
682
688
  let stderr = '';
683
689
 
@@ -912,4 +918,4 @@ module.exports = {
912
918
  encryptData,
913
919
  decryptData,
914
920
  generateKey,
915
- };
921
+ };
@@ -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
+ });
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Simple test to verify the multilingual hook system works
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ console.log('Testing Multilingual Hook System...\n');
11
+
12
+ // Check if required files exist
13
+ const requiredFiles = [
14
+ '../../src/core/multilingual/language-pattern-manager.js',
15
+ '../../.qoder/specs/multilingual-hook-system/language-patterns/english.js',
16
+ '../../.qoder/specs/multilingual-hook-system/language-patterns/chinese.js',
17
+ '../../.qoder/specs/multilingual-hook-system/language-patterns/japanese.js',
18
+ '../../.qoder/specs/multilingual-hook-system/language-patterns/korean.js',
19
+ '../../.qoder/specs/multilingual-hook-system/language-patterns/german.js',
20
+ '../../.qoder/specs/multilingual-hook-system/language-patterns/french.js',
21
+ '../../.qoder/specs/multilingual-hook-system/language-patterns/spanish.js',
22
+ '../../.qoder/specs/multilingual-hook-system/language-patterns/italian.js',
23
+ '../../.qoder/specs/multilingual-hook-system/language-patterns/portuguese.js',
24
+ '../../.qoder/specs/multilingual-hook-system/language-patterns/russian.js',
25
+ '../../.qoder/specs/multilingual-hook-system/language-patterns/arabic.js',
26
+ '../../.qoder/specs/multilingual-hook-system/language-patterns/turkish.js'
27
+ ];
28
+
29
+ let allFilesExist = true;
30
+
31
+ requiredFiles.forEach(file => {
32
+ const fullPath = path.join(__dirname, file);
33
+ if (fs.existsSync(fullPath)) {
34
+ console.log(`✓ ${file} exists`);
35
+ } else {
36
+ console.log(`✗ ${file} missing`);
37
+ allFilesExist = false;
38
+ }
39
+ });
40
+
41
+ if (allFilesExist) {
42
+ console.log('\n✓ All required files are present');
43
+
44
+ // Try to load the LanguagePatternManager
45
+ try {
46
+ const LanguagePatternManager = require('../../src/core/multilingual/language-pattern-manager');
47
+ const manager = new LanguagePatternManager();
48
+
49
+ console.log('✓ LanguagePatternManager loaded successfully');
50
+
51
+ // Test English pattern matching
52
+ const englishResult = manager.detectCrossCLIRequest('use claude to write code');
53
+ if (englishResult && englishResult.targetCLI === 'claude') {
54
+ console.log('✓ English pattern matching works');
55
+ } else {
56
+ console.log('✗ English pattern matching failed');
57
+ }
58
+
59
+ // Test Chinese pattern matching
60
+ const chineseResult = manager.detectCrossCLIRequest('请用copilot帮我创建React组件');
61
+ if (chineseResult && chineseResult.targetCLI === 'copilot') {
62
+ console.log('✓ Chinese pattern matching works');
63
+ } else {
64
+ console.log('✗ Chinese pattern matching failed');
65
+ }
66
+
67
+ // Test Japanese pattern matching
68
+ const japaneseResult = manager.detectCrossCLIRequest('claudeを使ってコードを書いて関数を作成');
69
+ if (japaneseResult && japaneseResult.targetCLI === 'claude') {
70
+ console.log('✓ Japanese pattern matching works');
71
+ } else {
72
+ console.log('✗ Japanese pattern matching failed');
73
+ }
74
+
75
+ console.log('\n🎉 Multilingual Hook System is ready!');
76
+ console.log('\nTo deploy multilingual hooks, run:');
77
+ console.log(' stigmergy deploy');
78
+
79
+ } catch (error) {
80
+ console.log(`✗ Failed to load LanguagePatternManager: ${error.message}`);
81
+ }
82
+ } else {
83
+ console.log('\n✗ Some required files are missing');
84
+ process.exit(1);
85
+ }