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,249 +1,261 @@
1
- const CLIHelpAnalyzer = require('./cli_help_analyzer');
2
- const { CLI_TOOLS, validateCLITool } = require('./cli_tools');
3
- const { errorHandler } = require('./error_handler');
4
-
5
- class SmartRouter {
6
- constructor() {
7
- this.tools = CLI_TOOLS;
8
- try {
9
- this.analyzer = new CLIHelpAnalyzer();
10
- this.analyzer.setCLITools(this.tools);
11
- } catch (error) {
12
- errorHandler.logError(error, 'ERROR', 'SmartRouter.constructor');
13
- throw error;
14
- }
15
- this.routeKeywords = [
16
- 'use',
17
- 'help',
18
- 'please',
19
- 'write',
20
- 'generate',
21
- 'explain',
22
- 'analyze',
23
- 'translate',
24
- 'article',
25
- ];
26
- this.defaultTool = 'claude';
27
- // Track recently failed tools to avoid repeated analysis attempts
28
- this.recentFailures = new Map();
29
- }
30
-
31
- /**
32
- * Initialize the smart router
33
- */
34
- async initialize() {
35
- await this.analyzer.initialize();
36
- }
37
-
38
- /**
39
- * Check if input should be routed to a specific CLI tool
40
- */
41
- shouldRoute(userInput) {
42
- return this.routeKeywords.some((keyword) =>
43
- userInput.toLowerCase().includes(keyword.toLowerCase()),
44
- );
45
- }
46
-
47
- /**
48
- * Perform smart routing based on user input and CLI patterns
49
- * Optimized to reduce unnecessary error messages and improve performance
50
- * Prioritizes exact tool name matches over keyword matches
51
- */
52
- async smartRoute(userInput) {
53
- const input = userInput.trim();
54
- const inputLower = input.toLowerCase();
55
-
56
- // First, check for exact tool name matches (higher priority)
57
- for (const [toolName, _] of Object.entries(this.tools)) {
58
- try {
59
- // Validate tool configuration
60
- validateCLITool(toolName);
61
-
62
- if (inputLower.includes(toolName)) {
63
- // Extract clean parameters when the tool name itself is mentioned
64
- const cleanInput = input
65
- .replace(new RegExp(`.*${toolName}\\s*`, 'gi'), '')
66
- .replace(/^(use|please|help|using|with)\s*/i, '')
67
- .trim();
68
- return { tool: toolName, prompt: cleanInput };
69
- }
70
- } catch (error) {
71
- // Only log error if it's a real issue, not just a missing pattern
72
- if (
73
- error.message &&
74
- !error.message.includes('no such file or directory')
75
- ) {
76
- await errorHandler.logError(
77
- error,
78
- 'WARN',
79
- `SmartRouter.smartRoute.${toolName}`,
80
- );
81
- }
82
- // Continue with next tool
83
- continue;
84
- }
85
- }
86
-
87
- // Then check for keyword matches (lower priority)
88
- // Only analyze tools that are likely to match to reduce overhead
89
- const potentialMatches = [];
90
- for (const [toolName, _] of Object.entries(this.tools)) {
91
- // Quick check: if the input is very short, only analyze a few key tools
92
- if (input.length < 20) {
93
- // For short inputs, only analyze commonly used tools
94
- const commonTools = ['claude', 'gemini', 'qwen'];
95
- if (!commonTools.includes(toolName)) {
96
- continue;
97
- }
98
- }
99
-
100
- // Add tool to potential matches for detailed analysis
101
- potentialMatches.push(toolName);
102
- }
103
-
104
- // Analyze potential matches
105
- for (const toolName of potentialMatches) {
106
- try {
107
- // Validate tool configuration
108
- validateCLITool(toolName);
109
-
110
- // Get CLI pattern for this tool - with optimized caching
111
- let cliPattern = await this.getOptimizedCLIPattern(toolName);
112
-
113
- // Check if input contains any of the tool's keywords or subcommands
114
- const keywords = this.extractKeywords(toolName, cliPattern);
115
- for (const keyword of keywords) {
116
- // Skip the tool name itself since we already checked for exact matches
117
- if (
118
- keyword.toLowerCase() !== toolName.toLowerCase() &&
119
- inputLower.includes(keyword.toLowerCase())
120
- ) {
121
- // Extract clean parameters
122
- const cleanInput = input
123
- .replace(new RegExp(`.*${keyword}\\s*`, 'gi'), '')
124
- .replace(/^(use|please|help|using|with)\s*/i, '')
125
- .trim();
126
- return { tool: toolName, prompt: cleanInput };
127
- }
128
- }
129
- } catch (error) {
130
- // Only log error if it's a real issue, not just a missing pattern
131
- if (
132
- error.message &&
133
- !error.message.includes('no such file or directory')
134
- ) {
135
- await errorHandler.logError(
136
- error,
137
- 'WARN',
138
- `SmartRouter.smartRoute.${toolName}`,
139
- );
140
- }
141
- // Continue with next tool
142
- continue;
143
- }
144
- }
145
-
146
- // Default routing
147
- const cleanInput = input
148
- .replace(/^(use|please|help|using|with)\s*/i, '')
149
- .trim();
150
- return { tool: this.defaultTool, prompt: cleanInput };
151
- }
152
-
153
- /**
154
- * Get CLI pattern with optimized error handling to reduce noise
155
- */
156
- async getOptimizedCLIPattern(toolName) {
157
- try {
158
- // Quick check for missing tools to avoid unnecessary analysis
159
- const config = await this.analyzer.loadPersistentConfig();
160
- const failedAttempt = config.failedAttempts[toolName];
161
-
162
- // If there was a recent failure (less than 1 hour ago), skip analysis entirely
163
- if (failedAttempt && this.isRecentFailure(failedAttempt.timestamp)) {
164
- if (process.env.DEBUG === 'true') {
165
- console.log(
166
- `[INFO] Skipping analysis for ${toolName} due to recent failure`,
167
- );
168
- }
169
- // Return cached analysis if available, otherwise null
170
- const cached = await this.analyzer.getCachedAnalysis(toolName);
171
- return cached || null;
172
- }
173
-
174
- const cached = await this.analyzer.getCachedAnalysis(toolName);
175
-
176
- if (cached && !this.analyzer.isCacheExpired(cached.timestamp)) {
177
- return cached;
178
- }
179
-
180
- // Analyze CLI if no cache or failure is old
181
- return await this.analyzer.analyzeCLI(toolName);
182
- } catch (error) {
183
- // Only log serious errors, suppress file not found errors
184
- if (
185
- error.message &&
186
- !error.message.includes('ENOENT') &&
187
- !error.message.includes('no such file or directory')
188
- ) {
189
- console.warn(`[WARN] Unable to get help information for ${toolName}`);
190
- }
191
- return null;
192
- }
193
- }
194
-
195
- /**
196
- * Check if failure timestamp is recent (less than 1 hour)
197
- */
198
- isRecentFailure(timestamp) {
199
- const failureTime = new Date(timestamp);
200
- const now = new Date();
201
- const hoursDiff = (now - failureTime) / (1000 * 60 * 60);
202
- return hoursDiff < 1; // Recent if less than 1 hour
203
- }
204
-
205
- /**
206
- * Extract keywords for a tool from its CLI patterns
207
- */
208
- extractKeywords(toolName, cliPattern) {
209
- const keywords = [toolName];
210
-
211
- // Add tool-specific keywords
212
- const toolSpecificKeywords = {
213
- claude: ['claude', 'anthropic'],
214
- gemini: ['gemini', 'google'],
215
- qwen: ['qwen', 'alibaba', 'tongyi'],
216
- iflow: ['iflow', 'workflow', 'intelligent'],
217
- qodercli: ['qoder', 'code'], // 'code' is specifically for qodercli only
218
- codebuddy: ['codebuddy', 'buddy', 'assistant'],
219
- copilot: ['copilot', 'github', 'gh'],
220
- codex: ['codex', 'openai', 'gpt'], // Remove 'code' from here to avoid conflicts
221
- };
222
-
223
- if (toolSpecificKeywords[toolName]) {
224
- keywords.push(...toolSpecificKeywords[toolName]);
225
- }
226
-
227
- // Add subcommands from CLI pattern if available
228
- if (cliPattern && cliPattern.patterns && cliPattern.patterns.subcommands) {
229
- cliPattern.patterns.subcommands.forEach((subcommand) => {
230
- if (subcommand.name) {
231
- keywords.push(subcommand.name);
232
- }
233
- });
234
- }
235
-
236
- // Add commands from CLI pattern if available
237
- if (cliPattern && cliPattern.patterns && cliPattern.patterns.commands) {
238
- cliPattern.patterns.commands.forEach((command) => {
239
- if (command.name && command.name !== toolName) {
240
- keywords.push(command.name);
241
- }
242
- });
243
- }
244
-
245
- return [...new Set(keywords)]; // Remove duplicates
246
- }
247
- }
248
-
249
- module.exports = SmartRouter;
1
+ const CLIHelpAnalyzer = require('./cli_help_analyzer');
2
+ const { CLI_TOOLS, validateCLITool } = require('./cli_tools');
3
+ const { errorHandler } = require('./error_handler');
4
+
5
+ class SmartRouter {
6
+ constructor() {
7
+ this.tools = CLI_TOOLS;
8
+ try {
9
+ this.analyzer = new CLIHelpAnalyzer();
10
+ this.analyzer.setCLITools(this.tools);
11
+ } catch (error) {
12
+ errorHandler.logError(error, 'ERROR', 'SmartRouter.constructor');
13
+ throw error;
14
+ }
15
+ this.routeKeywords = [
16
+ 'use',
17
+ 'help',
18
+ 'please',
19
+ 'write',
20
+ 'generate',
21
+ 'explain',
22
+ 'analyze',
23
+ 'translate',
24
+ 'article',
25
+ ];
26
+ this.defaultTool = 'claude';
27
+ // Track recently failed tools to avoid repeated analysis attempts
28
+ this.recentFailures = new Map();
29
+ }
30
+
31
+ /**
32
+ * Initialize the smart router
33
+ */
34
+ async initialize() {
35
+ await this.analyzer.initialize();
36
+ }
37
+
38
+ /**
39
+ * Check if input should be routed to a specific CLI tool
40
+ */
41
+ shouldRoute(userInput) {
42
+ if (!userInput || typeof userInput !== 'string') {
43
+ return false;
44
+ }
45
+
46
+ const input = userInput.toLowerCase().trim();
47
+
48
+ // Check for route keywords
49
+ const routePatterns = [
50
+ 'use', 'using', 'with',
51
+ 'help', 'please', 'assist',
52
+ 'write', 'generate', 'explain', 'analyze',
53
+ 'translate', 'article', 'create', 'code'
54
+ ];
55
+
56
+ return routePatterns.some(pattern => input.includes(pattern));
57
+ }
58
+
59
+ /**
60
+ * Perform smart routing based on user input and CLI patterns
61
+ * Optimized to reduce unnecessary error messages and improve performance
62
+ * Prioritizes exact tool name matches over keyword matches
63
+ */
64
+ async smartRoute(userInput) {
65
+ const input = userInput.trim();
66
+ const inputLower = input.toLowerCase();
67
+
68
+ // First, check for exact tool name matches (higher priority)
69
+ for (const [toolName, _] of Object.entries(this.tools)) {
70
+ try {
71
+ // Validate tool configuration
72
+ validateCLITool(toolName);
73
+
74
+ if (inputLower.includes(toolName)) {
75
+ // Extract clean parameters when the tool name itself is mentioned
76
+ const cleanInput = input
77
+ .replace(new RegExp(`.*${toolName}\\s*`, 'gi'), '')
78
+ .replace(/^(use|please|help|using|with)\s*/i, '')
79
+ .trim();
80
+ return { tool: toolName, prompt: cleanInput };
81
+ }
82
+ } catch (error) {
83
+ // Only log error if it's a real issue, not just a missing pattern
84
+ if (
85
+ error.message &&
86
+ !error.message.includes('no such file or directory')
87
+ ) {
88
+ await errorHandler.logError(
89
+ error,
90
+ 'WARN',
91
+ `SmartRouter.smartRoute.${toolName}`,
92
+ );
93
+ }
94
+ // Continue with next tool
95
+ continue;
96
+ }
97
+ }
98
+
99
+ // Then check for keyword matches (lower priority)
100
+ // Only analyze tools that are likely to match to reduce overhead
101
+ const potentialMatches = [];
102
+ for (const [toolName, _] of Object.entries(this.tools)) {
103
+ // Quick check: if the input is very short, only analyze a few key tools
104
+ if (input.length < 20) {
105
+ // For short inputs, only analyze commonly used tools
106
+ const commonTools = ['claude', 'gemini', 'qwen'];
107
+ if (!commonTools.includes(toolName)) {
108
+ continue;
109
+ }
110
+ }
111
+
112
+ // Add tool to potential matches for detailed analysis
113
+ potentialMatches.push(toolName);
114
+ }
115
+
116
+ // Analyze potential matches
117
+ for (const toolName of potentialMatches) {
118
+ try {
119
+ // Validate tool configuration
120
+ validateCLITool(toolName);
121
+
122
+ // Get CLI pattern for this tool - with optimized caching
123
+ let cliPattern = await this.getOptimizedCLIPattern(toolName);
124
+
125
+ // Check if input contains any of the tool's keywords or subcommands
126
+ const keywords = this.extractKeywords(toolName, cliPattern);
127
+ for (const keyword of keywords) {
128
+ // Skip the tool name itself since we already checked for exact matches
129
+ if (
130
+ keyword.toLowerCase() !== toolName.toLowerCase() &&
131
+ inputLower.includes(keyword.toLowerCase())
132
+ ) {
133
+ // Extract clean parameters
134
+ const cleanInput = input
135
+ .replace(new RegExp(`.*${keyword}\\s*`, 'gi'), '')
136
+ .replace(/^(use|please|help|using|with)\s*/i, '')
137
+ .trim();
138
+ return { tool: toolName, prompt: cleanInput };
139
+ }
140
+ }
141
+ } catch (error) {
142
+ // Only log error if it's a real issue, not just a missing pattern
143
+ if (
144
+ error.message &&
145
+ !error.message.includes('no such file or directory')
146
+ ) {
147
+ await errorHandler.logError(
148
+ error,
149
+ 'WARN',
150
+ `SmartRouter.smartRoute.${toolName}`,
151
+ );
152
+ }
153
+ // Continue with next tool
154
+ continue;
155
+ }
156
+ }
157
+
158
+ // Default routing
159
+ const cleanInput = input
160
+ .replace(/^(use|please|help|using|with)\s*/i, '')
161
+ .trim();
162
+ return { tool: this.defaultTool, prompt: cleanInput };
163
+ }
164
+
165
+ /**
166
+ * Get CLI pattern with optimized error handling to reduce noise
167
+ */
168
+ async getOptimizedCLIPattern(toolName) {
169
+ try {
170
+ // Quick check for missing tools to avoid unnecessary analysis
171
+ const config = await this.analyzer.loadPersistentConfig();
172
+ const failedAttempt = config.failedAttempts[toolName];
173
+
174
+ // If there was a recent failure (less than 1 hour ago), skip analysis entirely
175
+ if (failedAttempt && this.isRecentFailure(failedAttempt.timestamp)) {
176
+ if (process.env.DEBUG === 'true') {
177
+ console.log(
178
+ `[INFO] Skipping analysis for ${toolName} due to recent failure`,
179
+ );
180
+ }
181
+ // Return cached analysis if available, otherwise null
182
+ const cached = await this.analyzer.getCachedAnalysis(toolName);
183
+ return cached || null;
184
+ }
185
+
186
+ const cached = await this.analyzer.getCachedAnalysis(toolName);
187
+
188
+ if (cached && !this.analyzer.isCacheExpired(cached.timestamp)) {
189
+ return cached;
190
+ }
191
+
192
+ // Analyze CLI if no cache or failure is old
193
+ return await this.analyzer.analyzeCLI(toolName);
194
+ } catch (error) {
195
+ // Only log serious errors, suppress file not found errors
196
+ if (
197
+ error.message &&
198
+ !error.message.includes('ENOENT') &&
199
+ !error.message.includes('no such file or directory')
200
+ ) {
201
+ console.warn(`[WARN] Unable to get help information for ${toolName}`);
202
+ }
203
+ return null;
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Check if failure timestamp is recent (less than 1 hour)
209
+ */
210
+ isRecentFailure(timestamp) {
211
+ const failureTime = new Date(timestamp);
212
+ const now = new Date();
213
+ const hoursDiff = (now - failureTime) / (1000 * 60 * 60);
214
+ return hoursDiff < 1; // Recent if less than 1 hour
215
+ }
216
+
217
+ /**
218
+ * Extract keywords for a tool from its CLI patterns
219
+ */
220
+ extractKeywords(toolName, cliPattern) {
221
+ const keywords = [toolName];
222
+
223
+ // Add tool-specific keywords
224
+ const toolSpecificKeywords = {
225
+ claude: ['claude', 'anthropic'],
226
+ gemini: ['gemini', 'google'],
227
+ qwen: ['qwen', 'alibaba', 'tongyi'],
228
+ iflow: ['iflow', 'workflow', 'intelligent'],
229
+ qodercli: ['qoder', 'code'], // 'code' is specifically for qodercli only
230
+ codebuddy: ['codebuddy', 'buddy', 'assistant'],
231
+ copilot: ['copilot', 'github', 'gh'],
232
+ codex: ['codex', 'openai', 'gpt'], // Remove 'code' from here to avoid conflicts
233
+ };
234
+
235
+ if (toolSpecificKeywords[toolName]) {
236
+ keywords.push(...toolSpecificKeywords[toolName]);
237
+ }
238
+
239
+ // Add subcommands from CLI pattern if available
240
+ if (cliPattern && cliPattern.patterns && cliPattern.patterns.subcommands) {
241
+ cliPattern.patterns.subcommands.forEach((subcommand) => {
242
+ if (subcommand.name) {
243
+ keywords.push(subcommand.name);
244
+ }
245
+ });
246
+ }
247
+
248
+ // Add commands from CLI pattern if available
249
+ if (cliPattern && cliPattern.patterns && cliPattern.patterns.commands) {
250
+ cliPattern.patterns.commands.forEach((command) => {
251
+ if (command.name && command.name !== toolName) {
252
+ keywords.push(command.name);
253
+ }
254
+ });
255
+ }
256
+
257
+ return [...new Set(keywords)]; // Remove duplicates
258
+ }
259
+ }
260
+
261
+ module.exports = SmartRouter;