stigmergy 1.3.1-beta → 1.3.1

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.
@@ -1,402 +1,402 @@
1
- /**
2
- * Enhanced CLI Parameter Handler with Agent/Skill Support and Multi-Mode Retry
3
- *
4
- * This module extends the basic CLI parameter handling with:
5
- * 1. TWO-STAGE agent and skill detection (fast pre-check + detailed matching)
6
- * 2. Multiple parameter format support with retry mechanism
7
- * 3. Fallback strategies for different CLI tools
8
- *
9
- * OPTIMIZATION: Stage 1 (quickDetectMention) avoids cache I/O if no keywords found
10
- *
11
- * 📚 参考文档:
12
- * - CLI Help Analyzer 重构:REFACTORING_CLI_HELP_ANALYZER.md
13
- *
14
- * 🔗 依赖关系:
15
- * - 依赖 CLIHelpAnalyzer 的 getCLIPattern() 方法
16
- * - 重构后调用方式保持不变,完全向后兼容
17
- */
18
-
19
- const CLIHelpAnalyzer = require('./cli_help_analyzer');
20
- const { CLI_TOOLS } = require('./cli_tools');
21
- const LocalSkillScanner = require('./local_skill_scanner');
22
-
23
- class EnhancedCLIParameterHandler {
24
- constructor() {
25
- this.analyzer = new CLIHelpAnalyzer();
26
- this.skillScanner = new LocalSkillScanner();
27
- this.retryHistory = new Map(); // Track failed parameter formats
28
- }
29
-
30
- /**
31
- * Initialize the analyzer
32
- */
33
- async initialize() {
34
- await this.analyzer.initialize();
35
- // Note: skillScanner is initialized lazily (only when needed)
36
- }
37
-
38
- /**
39
- * Generate optimized arguments with agent/skill support and retry capability
40
- *
41
- * OPTIMIZED FLOW:
42
- * 1. Stage 1: Quick keyword detection (<1ms, no I/O)
43
- * - No keywords? Skip all skill/agent processing
44
- * - Has keywords? Proceed to Stage 2
45
- * 2. Stage 2: Load cache and detailed matching
46
- * - Load skills/agents from cache
47
- * - Perform precise matching
48
- * 3. Generate parameters based on CLI type
49
- *
50
- * @param {string} toolName - Name of the CLI tool
51
- * @param {string} prompt - User prompt
52
- * @param {Object} options - Options
53
- * @param {number} options.maxRetries - Maximum number of format retries (default: 3)
54
- * @param {boolean} options.enableAgentSkillOptimization - Enable agent/skill optimization (default: true)
55
- * @param {Array} options.preferredFormats - Preferred parameter formats to try first
56
- * @returns {Promise<Object>} Result with arguments, format used, and optimization info
57
- */
58
- async generateArgumentsWithRetry(toolName, prompt, options = {}) {
59
- const {
60
- maxRetries = 3,
61
- enableAgentSkillOptimization = true,
62
- preferredFormats = null
63
- } = options;
64
-
65
- await this.initialize();
66
-
67
- // === STAGE 1: Quick Pre-Check (Fast, No I/O) ===
68
- let detectedMentions = { hasAgent: false, hasSkill: false, confidence: 0 };
69
- let optimizationApplied = false;
70
- let optimizedPrompt = prompt;
71
- let skillMatches = [];
72
- let agentMatches = [];
73
-
74
- if (enableAgentSkillOptimization) {
75
- // Fast keyword detection (<1ms)
76
- const quickDetection = this.skillScanner.quickDetectMention(prompt);
77
-
78
- if (!quickDetection.shouldLoadCache) {
79
- // No agent/skill keywords detected - skip all skill/agent processing
80
- if (process.env.DEBUG === 'true') {
81
- console.log(`[AGENT/SKILL] No keywords detected, skipping skill/agent processing`);
82
- }
83
- } else {
84
- // Keywords detected - proceed to Stage 2
85
- if (process.env.DEBUG === 'true') {
86
- console.log(`[AGENT/SKILL] Stage 1: Keywords detected (agent=${quickDetection.hasAgentKeyword}, skill=${quickDetection.hasSkillKeyword})`);
87
- }
88
-
89
- // === STAGE 2: Load Cache and Detailed Matching ===
90
- await this.skillScanner.initialize(); // Load cache
91
-
92
- // Get detailed matches using CLIHelpAnalyzer
93
- detectedMentions = this.analyzer.detectAgentSkillMentions(prompt, toolName);
94
-
95
- // Get local skill/agent matches
96
- skillMatches = this.skillScanner.matchSkills(prompt, toolName);
97
- agentMatches = this.skillScanner.matchAgents(prompt, toolName);
98
-
99
- // Combine detection results
100
- if (skillMatches.length > 0 || agentMatches.length > 0) {
101
- detectedMentions.hasSkill = detectedMentions.hasSkill || skillMatches.length > 0;
102
- detectedMentions.hasAgent = detectedMentions.hasAgent || agentMatches.length > 0;
103
- detectedMentions.confidence = Math.min(1.0, detectedMentions.confidence + 0.2);
104
- }
105
-
106
- // Optimize prompt if matches found
107
- if (detectedMentions.hasAgent || detectedMentions.hasSkill) {
108
- optimizedPrompt = this.analyzer.optimizePromptForCLI(prompt, toolName, detectedMentions);
109
- optimizationApplied = (optimizedPrompt !== prompt);
110
-
111
- if (process.env.DEBUG === 'true') {
112
- console.log(`[AGENT/SKILL] Stage 2: Detailed matching complete`);
113
- console.log(`[AGENT/SKILL] Skill matches: ${skillMatches.length}, Agent matches: ${agentMatches.length}`);
114
- if (optimizationApplied) {
115
- console.log(`[AGENT/SKILL] Original: ${prompt}`);
116
- console.log(`[AGENT/SKILL] Optimized: ${optimizedPrompt}`);
117
- }
118
- }
119
- }
120
- }
121
- }
122
-
123
- // Step 3: Get parameter formats to try (in priority order)
124
- const formatsToTry = await this.getParameterFormats(toolName, preferredFormats, detectedMentions);
125
-
126
- // Step 4: Try each format until one succeeds (or return first for non-execution context)
127
- const results = {
128
- toolName,
129
- originalPrompt: prompt,
130
- optimizedPrompt,
131
- optimizationApplied,
132
- detectedMentions,
133
- formats: []
134
- };
135
-
136
- for (let i = 0; i < Math.min(formatsToTry.length, maxRetries); i++) {
137
- const format = formatsToTry[i];
138
- const args = this.generateArgumentsForFormat(toolName, optimizedPrompt, format);
139
-
140
- results.formats.push({
141
- format: format.name,
142
- args,
143
- priority: format.priority,
144
- attempted: true
145
- });
146
-
147
- // For non-execution context, return all formats
148
- // For execution, the caller should handle retry
149
- }
150
-
151
- // Select the best format based on priority and detection
152
- const selectedFormat = this.selectBestFormat(results.formats, detectedMentions);
153
- results.selectedFormat = selectedFormat;
154
- results.arguments = selectedFormat.args;
155
-
156
- return results;
157
- }
158
-
159
- /**
160
- * Get parameter formats to try for a specific tool
161
- *
162
- * @param {string} toolName - Name of the CLI tool
163
- * @param {Array} preferredFormats - User-preferred formats
164
- * @param {Object} detectedMentions - Detected agent/skill mentions
165
- * @returns {Promise<Array>} Array of format objects to try
166
- */
167
- async getParameterFormats(toolName, preferredFormats, detectedMentions) {
168
- const formats = [];
169
-
170
- // Get CLI pattern from analyzer
171
- const cliPattern = await this.analyzer.getCLIPattern(toolName);
172
- const enhancedPattern = this.analyzer.enhancedPatterns[toolName];
173
-
174
- if (process.env.DEBUG === 'true') {
175
- console.log(`[PARAM_FORMAT] Getting formats for ${toolName}`);
176
- console.log(`[PARAM_FORMAT] cliPattern exists: ${!!cliPattern}`);
177
- if (cliPattern && cliPattern.commandStructure) {
178
- console.log(`[PARAM_FORMAT] executionPattern: ${cliPattern.commandStructure.executionPattern}`);
179
- console.log(`[PARAM_FORMAT] nonInteractiveFlag: ${cliPattern.commandStructure.nonInteractiveFlag}`);
180
- }
181
- }
182
-
183
- // Define format priority based on tool characteristics
184
- if (enhancedPattern) {
185
- // Use enhanced pattern information
186
- if (enhancedPattern.positionalArgs) {
187
- // Check if CLI has flag-based non-interactive execution
188
- // For tools like Kode that have flag-based execution, don't use positional args
189
- const hasFlagBasedExecution = cliPattern?.commandStructure?.executionPattern === 'flag-based' &&
190
- cliPattern?.commandStructure?.nonInteractiveFlag;
191
-
192
- if (!hasFlagBasedExecution) {
193
- // Qwen, Copilot, etc. support positional arguments
194
- formats.push({
195
- name: 'positional',
196
- priority: enhancedPattern.positionalArgs ? 10 : 5,
197
- description: 'Positional arguments (natural language)',
198
- template: (prompt) => [prompt]
199
- });
200
- }
201
- }
202
-
203
- if (enhancedPattern.naturalLanguageSupport) {
204
- // CLIs with good natural language support
205
- formats.push({
206
- name: 'prompt-flag',
207
- priority: 8,
208
- description: 'Standard -p flag',
209
- template: (prompt) => ['-p', `"${prompt}"`]
210
- });
211
- }
212
-
213
- if (enhancedPattern.skillPrefixRequired) {
214
- // CodeBuddy requires skill: prefix
215
- formats.push({
216
- name: 'skill-prefix',
217
- priority: 9,
218
- description: 'Skill prefix with -y flag',
219
- template: (prompt) => ['-y', '-p', `"${prompt}"`]
220
- });
221
- }
222
- }
223
-
224
- // Add standard formats based on CLI pattern analysis
225
- if (cliPattern && cliPattern.commandStructure) {
226
- const structure = cliPattern.commandStructure;
227
-
228
- if (structure.promptFlag) {
229
- formats.push({
230
- name: 'detected-prompt-flag',
231
- priority: 7,
232
- description: `Detected prompt flag: ${structure.promptFlag}`,
233
- template: (prompt) => [structure.promptFlag, `"${prompt}"`]
234
- });
235
- }
236
-
237
- if (structure.executionPattern === 'argument-based') {
238
- formats.push({
239
- name: 'argument-based',
240
- priority: 6,
241
- description: 'Argument-based execution',
242
- template: (prompt) => [`"${prompt}"`]
243
- });
244
- }
245
-
246
- if (structure.executionPattern === 'subcommand-based') {
247
- // For tools like Codex that need subcommand
248
- formats.push({
249
- name: 'subcommand-exec',
250
- priority: 7,
251
- description: 'Subcommand-based with exec',
252
- template: (prompt) => ['exec', '-p', `"${prompt}"`]
253
- });
254
- }
255
-
256
- if (structure.executionPattern === 'flag-based') {
257
- // For tools like Kode that use flag-based execution (e.g., --print)
258
- if (structure.nonInteractiveFlag) {
259
- formats.push({
260
- name: 'flag-based-non-interactive',
261
- priority: 9,
262
- description: `Flag-based non-interactive: ${structure.nonInteractiveFlag}`,
263
- template: (prompt) => [structure.nonInteractiveFlag, `"${prompt}"`]
264
- });
265
- }
266
- }
267
- }
268
-
269
- // Add fallback formats
270
- formats.push({
271
- name: 'standard-p-flag',
272
- priority: 4,
273
- description: 'Standard -p flag (fallback)',
274
- template: (prompt) => ['-p', `"${prompt}"`]
275
- });
276
-
277
- // Filter out failed formats from retry history
278
- const failedFormats = this.retryHistory.get(toolName) || new Set();
279
- const validFormats = formats.filter(f => !failedFormats.has(f.name));
280
-
281
- if (process.env.DEBUG === 'true') {
282
- console.log(`[PARAM_FORMAT] Total formats: ${formats.length}`);
283
- formats.forEach(f => {
284
- console.log(`[PARAM_FORMAT] - ${f.name} (priority: ${f.priority}): ${f.description}`);
285
- });
286
- console.log(`[PARAM_FORMAT] Valid formats: ${validFormats.length}`);
287
- }
288
-
289
- // If all formats failed, clear history and try again
290
- if (validFormats.length === 0) {
291
- if (process.env.DEBUG === 'true') {
292
- console.log(`[RETRY] All formats failed for ${toolName}, clearing retry history`);
293
- }
294
- this.retryHistory.delete(toolName);
295
- return formats;
296
- }
297
-
298
- // Sort by priority (descending)
299
- return validFormats.sort((a, b) => b.priority - a.priority);
300
- }
301
-
302
- /**
303
- * Generate arguments for a specific format
304
- *
305
- * @param {string} toolName - Name of the CLI tool
306
- * @param {string} prompt - Optimized prompt
307
- * @param {Object} format - Format object
308
- * @returns {Array} Arguments array
309
- */
310
- generateArgumentsForFormat(toolName, prompt, format) {
311
- try {
312
- return format.template(prompt);
313
- } catch (error) {
314
- if (process.env.DEBUG === 'true') {
315
- console.log(`[ERROR] Failed to generate args for format ${format.name}:`, error.message);
316
- }
317
- // Fallback to standard format
318
- return ['-p', `"${prompt}"`];
319
- }
320
- }
321
-
322
- /**
323
- * Select the best format from available options
324
- *
325
- * @param {Array} formats - Available formats
326
- * @param {Object} detectedMentions - Detected agent/skill mentions
327
- * @returns {Object} Selected format
328
- */
329
- selectBestFormat(formats, detectedMentions) {
330
- // Prioritize formats based on detection
331
- if (detectedMentions.hasSkill || detectedMentions.hasAgent) {
332
- // For agent/skill requests, prefer formats with higher priority
333
- const skillOptimizedFormats = formats.filter(f => f.priority >= 8);
334
- if (skillOptimizedFormats.length > 0) {
335
- return skillOptimizedFormats[0];
336
- }
337
- }
338
-
339
- // Return highest priority format
340
- return formats[0] || {
341
- name: 'fallback',
342
- priority: 1,
343
- args: ['-p', '"{prompt}"'],
344
- description: 'Fallback format'
345
- };
346
- }
347
-
348
- /**
349
- * Record a failed format for a tool
350
- *
351
- * @param {string} toolName - Name of the CLI tool
352
- * @param {string} formatName - Name of the failed format
353
- */
354
- recordFailedFormat(toolName, formatName) {
355
- if (!this.retryHistory.has(toolName)) {
356
- this.retryHistory.set(toolName, new Set());
357
- }
358
- this.retryHistory.get(toolName).add(formatName);
359
-
360
- if (process.env.DEBUG === 'true') {
361
- console.log(`[RETRY] Recorded failed format ${formatName} for ${toolName}`);
362
- console.log(`[RETRY] Failed formats:`, Array.from(this.retryHistory.get(toolName)));
363
- }
364
- }
365
-
366
- /**
367
- * Clear retry history for a tool
368
- *
369
- * @param {string} toolName - Name of the CLI tool
370
- */
371
- clearRetryHistory(toolName) {
372
- this.retryHistory.delete(toolName);
373
-
374
- if (process.env.DEBUG === 'true') {
375
- console.log(`[RETRY] Cleared retry history for ${toolName}`);
376
- }
377
- }
378
-
379
- /**
380
- * Get compatibility score for a tool with the given prompt
381
- *
382
- * @param {string} toolName - Name of the CLI tool
383
- * @param {string} prompt - User prompt
384
- * @returns {Object} Compatibility score and reasons
385
- */
386
- getCompatibilityScore(toolName, prompt) {
387
- return this.analyzer.getAgentSkillCompatibilityScore(toolName, prompt);
388
- }
389
-
390
- /**
391
- * Generate optimized call command for a tool
392
- *
393
- * @param {string} toolName - Name of the CLI tool
394
- * @param {string} prompt - User prompt
395
- * @returns {Object|null} Optimized call command
396
- */
397
- generateOptimizedCall(toolName, prompt) {
398
- return this.analyzer.generateOptimizedCall(toolName, prompt);
399
- }
400
- }
401
-
402
- module.exports = EnhancedCLIParameterHandler;
1
+ /**
2
+ * Enhanced CLI Parameter Handler with Agent/Skill Support and Multi-Mode Retry
3
+ *
4
+ * This module extends the basic CLI parameter handling with:
5
+ * 1. TWO-STAGE agent and skill detection (fast pre-check + detailed matching)
6
+ * 2. Multiple parameter format support with retry mechanism
7
+ * 3. Fallback strategies for different CLI tools
8
+ *
9
+ * OPTIMIZATION: Stage 1 (quickDetectMention) avoids cache I/O if no keywords found
10
+ *
11
+ * 📚 参考文档:
12
+ * - CLI Help Analyzer 重构:REFACTORING_CLI_HELP_ANALYZER.md
13
+ *
14
+ * 🔗 依赖关系:
15
+ * - 依赖 CLIHelpAnalyzer 的 getCLIPattern() 方法
16
+ * - 重构后调用方式保持不变,完全向后兼容
17
+ */
18
+
19
+ const CLIHelpAnalyzer = require('./cli_help_analyzer');
20
+ const { CLI_TOOLS } = require('./cli_tools');
21
+ const LocalSkillScanner = require('./local_skill_scanner');
22
+
23
+ class EnhancedCLIParameterHandler {
24
+ constructor() {
25
+ this.analyzer = new CLIHelpAnalyzer();
26
+ this.skillScanner = new LocalSkillScanner();
27
+ this.retryHistory = new Map(); // Track failed parameter formats
28
+ }
29
+
30
+ /**
31
+ * Initialize the analyzer
32
+ */
33
+ async initialize() {
34
+ await this.analyzer.initialize();
35
+ // Note: skillScanner is initialized lazily (only when needed)
36
+ }
37
+
38
+ /**
39
+ * Generate optimized arguments with agent/skill support and retry capability
40
+ *
41
+ * OPTIMIZED FLOW:
42
+ * 1. Stage 1: Quick keyword detection (<1ms, no I/O)
43
+ * - No keywords? Skip all skill/agent processing
44
+ * - Has keywords? Proceed to Stage 2
45
+ * 2. Stage 2: Load cache and detailed matching
46
+ * - Load skills/agents from cache
47
+ * - Perform precise matching
48
+ * 3. Generate parameters based on CLI type
49
+ *
50
+ * @param {string} toolName - Name of the CLI tool
51
+ * @param {string} prompt - User prompt
52
+ * @param {Object} options - Options
53
+ * @param {number} options.maxRetries - Maximum number of format retries (default: 3)
54
+ * @param {boolean} options.enableAgentSkillOptimization - Enable agent/skill optimization (default: true)
55
+ * @param {Array} options.preferredFormats - Preferred parameter formats to try first
56
+ * @returns {Promise<Object>} Result with arguments, format used, and optimization info
57
+ */
58
+ async generateArgumentsWithRetry(toolName, prompt, options = {}) {
59
+ const {
60
+ maxRetries = 3,
61
+ enableAgentSkillOptimization = true,
62
+ preferredFormats = null
63
+ } = options;
64
+
65
+ await this.initialize();
66
+
67
+ // === STAGE 1: Quick Pre-Check (Fast, No I/O) ===
68
+ let detectedMentions = { hasAgent: false, hasSkill: false, confidence: 0 };
69
+ let optimizationApplied = false;
70
+ let optimizedPrompt = prompt;
71
+ let skillMatches = [];
72
+ let agentMatches = [];
73
+
74
+ if (enableAgentSkillOptimization) {
75
+ // Fast keyword detection (<1ms)
76
+ const quickDetection = this.skillScanner.quickDetectMention(prompt);
77
+
78
+ if (!quickDetection.shouldLoadCache) {
79
+ // No agent/skill keywords detected - skip all skill/agent processing
80
+ if (process.env.DEBUG === 'true') {
81
+ console.log(`[AGENT/SKILL] No keywords detected, skipping skill/agent processing`);
82
+ }
83
+ } else {
84
+ // Keywords detected - proceed to Stage 2
85
+ if (process.env.DEBUG === 'true') {
86
+ console.log(`[AGENT/SKILL] Stage 1: Keywords detected (agent=${quickDetection.hasAgentKeyword}, skill=${quickDetection.hasSkillKeyword})`);
87
+ }
88
+
89
+ // === STAGE 2: Load Cache and Detailed Matching ===
90
+ await this.skillScanner.initialize(); // Load cache
91
+
92
+ // Get detailed matches using CLIHelpAnalyzer
93
+ detectedMentions = this.analyzer.detectAgentSkillMentions(prompt, toolName);
94
+
95
+ // Get local skill/agent matches
96
+ skillMatches = this.skillScanner.matchSkills(prompt, toolName);
97
+ agentMatches = this.skillScanner.matchAgents(prompt, toolName);
98
+
99
+ // Combine detection results
100
+ if (skillMatches.length > 0 || agentMatches.length > 0) {
101
+ detectedMentions.hasSkill = detectedMentions.hasSkill || skillMatches.length > 0;
102
+ detectedMentions.hasAgent = detectedMentions.hasAgent || agentMatches.length > 0;
103
+ detectedMentions.confidence = Math.min(1.0, detectedMentions.confidence + 0.2);
104
+ }
105
+
106
+ // Optimize prompt if matches found
107
+ if (detectedMentions.hasAgent || detectedMentions.hasSkill) {
108
+ optimizedPrompt = this.analyzer.optimizePromptForCLI(prompt, toolName, detectedMentions);
109
+ optimizationApplied = (optimizedPrompt !== prompt);
110
+
111
+ if (process.env.DEBUG === 'true') {
112
+ console.log(`[AGENT/SKILL] Stage 2: Detailed matching complete`);
113
+ console.log(`[AGENT/SKILL] Skill matches: ${skillMatches.length}, Agent matches: ${agentMatches.length}`);
114
+ if (optimizationApplied) {
115
+ console.log(`[AGENT/SKILL] Original: ${prompt}`);
116
+ console.log(`[AGENT/SKILL] Optimized: ${optimizedPrompt}`);
117
+ }
118
+ }
119
+ }
120
+ }
121
+ }
122
+
123
+ // Step 3: Get parameter formats to try (in priority order)
124
+ const formatsToTry = await this.getParameterFormats(toolName, preferredFormats, detectedMentions);
125
+
126
+ // Step 4: Try each format until one succeeds (or return first for non-execution context)
127
+ const results = {
128
+ toolName,
129
+ originalPrompt: prompt,
130
+ optimizedPrompt,
131
+ optimizationApplied,
132
+ detectedMentions,
133
+ formats: []
134
+ };
135
+
136
+ for (let i = 0; i < Math.min(formatsToTry.length, maxRetries); i++) {
137
+ const format = formatsToTry[i];
138
+ const args = this.generateArgumentsForFormat(toolName, optimizedPrompt, format);
139
+
140
+ results.formats.push({
141
+ format: format.name,
142
+ args,
143
+ priority: format.priority,
144
+ attempted: true
145
+ });
146
+
147
+ // For non-execution context, return all formats
148
+ // For execution, the caller should handle retry
149
+ }
150
+
151
+ // Select the best format based on priority and detection
152
+ const selectedFormat = this.selectBestFormat(results.formats, detectedMentions);
153
+ results.selectedFormat = selectedFormat;
154
+ results.arguments = selectedFormat.args;
155
+
156
+ return results;
157
+ }
158
+
159
+ /**
160
+ * Get parameter formats to try for a specific tool
161
+ *
162
+ * @param {string} toolName - Name of the CLI tool
163
+ * @param {Array} preferredFormats - User-preferred formats
164
+ * @param {Object} detectedMentions - Detected agent/skill mentions
165
+ * @returns {Promise<Array>} Array of format objects to try
166
+ */
167
+ async getParameterFormats(toolName, preferredFormats, detectedMentions) {
168
+ const formats = [];
169
+
170
+ // Get CLI pattern from analyzer
171
+ const cliPattern = await this.analyzer.getCLIPattern(toolName);
172
+ const enhancedPattern = this.analyzer.enhancedPatterns[toolName];
173
+
174
+ if (process.env.DEBUG === 'true') {
175
+ console.log(`[PARAM_FORMAT] Getting formats for ${toolName}`);
176
+ console.log(`[PARAM_FORMAT] cliPattern exists: ${!!cliPattern}`);
177
+ if (cliPattern && cliPattern.commandStructure) {
178
+ console.log(`[PARAM_FORMAT] executionPattern: ${cliPattern.commandStructure.executionPattern}`);
179
+ console.log(`[PARAM_FORMAT] nonInteractiveFlag: ${cliPattern.commandStructure.nonInteractiveFlag}`);
180
+ }
181
+ }
182
+
183
+ // Define format priority based on tool characteristics
184
+ if (enhancedPattern) {
185
+ // Use enhanced pattern information
186
+ if (enhancedPattern.positionalArgs) {
187
+ // Check if CLI has flag-based non-interactive execution
188
+ // For tools like Kode that have flag-based execution, don't use positional args
189
+ const hasFlagBasedExecution = cliPattern?.commandStructure?.executionPattern === 'flag-based' &&
190
+ cliPattern?.commandStructure?.nonInteractiveFlag;
191
+
192
+ if (!hasFlagBasedExecution) {
193
+ // Qwen, Copilot, etc. support positional arguments
194
+ formats.push({
195
+ name: 'positional',
196
+ priority: enhancedPattern.positionalArgs ? 10 : 5,
197
+ description: 'Positional arguments (natural language)',
198
+ template: (prompt) => [prompt]
199
+ });
200
+ }
201
+ }
202
+
203
+ if (enhancedPattern.naturalLanguageSupport) {
204
+ // CLIs with good natural language support
205
+ formats.push({
206
+ name: 'prompt-flag',
207
+ priority: 8,
208
+ description: 'Standard -p flag',
209
+ template: (prompt) => ['-p', `"${prompt}"`]
210
+ });
211
+ }
212
+
213
+ if (enhancedPattern.skillPrefixRequired) {
214
+ // CodeBuddy requires skill: prefix
215
+ formats.push({
216
+ name: 'skill-prefix',
217
+ priority: 9,
218
+ description: 'Skill prefix with -y flag',
219
+ template: (prompt) => ['-y', '-p', `"${prompt}"`]
220
+ });
221
+ }
222
+ }
223
+
224
+ // Add standard formats based on CLI pattern analysis
225
+ if (cliPattern && cliPattern.commandStructure) {
226
+ const structure = cliPattern.commandStructure;
227
+
228
+ if (structure.promptFlag) {
229
+ formats.push({
230
+ name: 'detected-prompt-flag',
231
+ priority: 7,
232
+ description: `Detected prompt flag: ${structure.promptFlag}`,
233
+ template: (prompt) => [structure.promptFlag, `"${prompt}"`]
234
+ });
235
+ }
236
+
237
+ if (structure.executionPattern === 'argument-based') {
238
+ formats.push({
239
+ name: 'argument-based',
240
+ priority: 6,
241
+ description: 'Argument-based execution',
242
+ template: (prompt) => [`"${prompt}"`]
243
+ });
244
+ }
245
+
246
+ if (structure.executionPattern === 'subcommand-based') {
247
+ // For tools like Codex that need subcommand
248
+ formats.push({
249
+ name: 'subcommand-exec',
250
+ priority: 7,
251
+ description: 'Subcommand-based with exec',
252
+ template: (prompt) => ['exec', '-p', `"${prompt}"`]
253
+ });
254
+ }
255
+
256
+ if (structure.executionPattern === 'flag-based') {
257
+ // For tools like Kode that use flag-based execution (e.g., --print)
258
+ if (structure.nonInteractiveFlag) {
259
+ formats.push({
260
+ name: 'flag-based-non-interactive',
261
+ priority: 9,
262
+ description: `Flag-based non-interactive: ${structure.nonInteractiveFlag}`,
263
+ template: (prompt) => [structure.nonInteractiveFlag, `"${prompt}"`]
264
+ });
265
+ }
266
+ }
267
+ }
268
+
269
+ // Add fallback formats
270
+ formats.push({
271
+ name: 'standard-p-flag',
272
+ priority: 4,
273
+ description: 'Standard -p flag (fallback)',
274
+ template: (prompt) => ['-p', `"${prompt}"`]
275
+ });
276
+
277
+ // Filter out failed formats from retry history
278
+ const failedFormats = this.retryHistory.get(toolName) || new Set();
279
+ const validFormats = formats.filter(f => !failedFormats.has(f.name));
280
+
281
+ if (process.env.DEBUG === 'true') {
282
+ console.log(`[PARAM_FORMAT] Total formats: ${formats.length}`);
283
+ formats.forEach(f => {
284
+ console.log(`[PARAM_FORMAT] - ${f.name} (priority: ${f.priority}): ${f.description}`);
285
+ });
286
+ console.log(`[PARAM_FORMAT] Valid formats: ${validFormats.length}`);
287
+ }
288
+
289
+ // If all formats failed, clear history and try again
290
+ if (validFormats.length === 0) {
291
+ if (process.env.DEBUG === 'true') {
292
+ console.log(`[RETRY] All formats failed for ${toolName}, clearing retry history`);
293
+ }
294
+ this.retryHistory.delete(toolName);
295
+ return formats;
296
+ }
297
+
298
+ // Sort by priority (descending)
299
+ return validFormats.sort((a, b) => b.priority - a.priority);
300
+ }
301
+
302
+ /**
303
+ * Generate arguments for a specific format
304
+ *
305
+ * @param {string} toolName - Name of the CLI tool
306
+ * @param {string} prompt - Optimized prompt
307
+ * @param {Object} format - Format object
308
+ * @returns {Array} Arguments array
309
+ */
310
+ generateArgumentsForFormat(toolName, prompt, format) {
311
+ try {
312
+ return format.template(prompt);
313
+ } catch (error) {
314
+ if (process.env.DEBUG === 'true') {
315
+ console.log(`[ERROR] Failed to generate args for format ${format.name}:`, error.message);
316
+ }
317
+ // Fallback to standard format
318
+ return ['-p', `"${prompt}"`];
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Select the best format from available options
324
+ *
325
+ * @param {Array} formats - Available formats
326
+ * @param {Object} detectedMentions - Detected agent/skill mentions
327
+ * @returns {Object} Selected format
328
+ */
329
+ selectBestFormat(formats, detectedMentions) {
330
+ // Prioritize formats based on detection
331
+ if (detectedMentions.hasSkill || detectedMentions.hasAgent) {
332
+ // For agent/skill requests, prefer formats with higher priority
333
+ const skillOptimizedFormats = formats.filter(f => f.priority >= 8);
334
+ if (skillOptimizedFormats.length > 0) {
335
+ return skillOptimizedFormats[0];
336
+ }
337
+ }
338
+
339
+ // Return highest priority format
340
+ return formats[0] || {
341
+ name: 'fallback',
342
+ priority: 1,
343
+ args: ['-p', '"{prompt}"'],
344
+ description: 'Fallback format'
345
+ };
346
+ }
347
+
348
+ /**
349
+ * Record a failed format for a tool
350
+ *
351
+ * @param {string} toolName - Name of the CLI tool
352
+ * @param {string} formatName - Name of the failed format
353
+ */
354
+ recordFailedFormat(toolName, formatName) {
355
+ if (!this.retryHistory.has(toolName)) {
356
+ this.retryHistory.set(toolName, new Set());
357
+ }
358
+ this.retryHistory.get(toolName).add(formatName);
359
+
360
+ if (process.env.DEBUG === 'true') {
361
+ console.log(`[RETRY] Recorded failed format ${formatName} for ${toolName}`);
362
+ console.log(`[RETRY] Failed formats:`, Array.from(this.retryHistory.get(toolName)));
363
+ }
364
+ }
365
+
366
+ /**
367
+ * Clear retry history for a tool
368
+ *
369
+ * @param {string} toolName - Name of the CLI tool
370
+ */
371
+ clearRetryHistory(toolName) {
372
+ this.retryHistory.delete(toolName);
373
+
374
+ if (process.env.DEBUG === 'true') {
375
+ console.log(`[RETRY] Cleared retry history for ${toolName}`);
376
+ }
377
+ }
378
+
379
+ /**
380
+ * Get compatibility score for a tool with the given prompt
381
+ *
382
+ * @param {string} toolName - Name of the CLI tool
383
+ * @param {string} prompt - User prompt
384
+ * @returns {Object} Compatibility score and reasons
385
+ */
386
+ getCompatibilityScore(toolName, prompt) {
387
+ return this.analyzer.getAgentSkillCompatibilityScore(toolName, prompt);
388
+ }
389
+
390
+ /**
391
+ * Generate optimized call command for a tool
392
+ *
393
+ * @param {string} toolName - Name of the CLI tool
394
+ * @param {string} prompt - User prompt
395
+ * @returns {Object|null} Optimized call command
396
+ */
397
+ generateOptimizedCall(toolName, prompt) {
398
+ return this.analyzer.generateOptimizedCall(toolName, prompt);
399
+ }
400
+ }
401
+
402
+ module.exports = EnhancedCLIParameterHandler;