- Created skills/ directory - Moved 272 skills to skills/ subfolder - Kept agents/ at root level - Kept installation scripts and docs at root level Repository structure: - skills/ - All 272 skills from skills.sh - agents/ - Agent definitions - *.sh, *.ps1 - Installation scripts - README.md, etc. - Documentation Co-Authored-By: Claude <noreply@anthropic.com>
385 lines
9.2 KiB
JavaScript
385 lines
9.2 KiB
JavaScript
/**
|
|
* Enhanced Intent Analyzer
|
|
* Analyzes user input to determine intent and select appropriate tools
|
|
* Inspired by ReAct pattern and agent intent analysis
|
|
*/
|
|
|
|
class IntentAnalyzer {
|
|
constructor(config = {}) {
|
|
this.tools = config.tools || [];
|
|
this.history = config.history || [];
|
|
this.patterns = this.loadPatterns();
|
|
this.context = {
|
|
previousCommands: [],
|
|
currentDirectory: process.cwd(),
|
|
preferences: {}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Load command patterns for intent detection
|
|
*/
|
|
loadPatterns() {
|
|
return {
|
|
// Shell command patterns
|
|
shell: [
|
|
/^(ls|ll|la|dir)\b/,
|
|
/^(cd|pwd)\b/,
|
|
/^(cat|less|more|head|tail)\b/,
|
|
/^(echo|printf)\b/,
|
|
/^(grep|rg|ag|ack)\b/,
|
|
/^(find|locate)\b/,
|
|
/^(npm|yarn|pnpm|pip|pip3|cargo|go)\b/,
|
|
/^(git|gh)\b/,
|
|
/^(curl|wget)\b/,
|
|
/^(ssh|scp|rsync)\b/,
|
|
/^(docker|podman)\b/,
|
|
/^(node|python|python3|ruby|bash|sh|zsh)\s/,
|
|
/^(make|cmake|ninja)\b/,
|
|
/^(test|npm test|pytest)\b/,
|
|
/^(build|npm build|webpack|vite)\b/
|
|
],
|
|
|
|
// File operation patterns
|
|
file: [
|
|
/^(read|open|view|show)\s+(?:file\s+)?['"]?[\w\-./]/,
|
|
/^(write|create|save)\s+(?:file\s+)?['"]?[\w\-./]/,
|
|
/^(delete|remove|rm)\s+(?:file\s+)?['"]?[\w\-./]/,
|
|
/^(copy|cp|move|mv)\s+(?:file\s+)?['"]?[\w\-./]/,
|
|
/^(list|ls|dir)\s+(?:files?\s+)?(?:in\s+)?['"]?[\w\-./]/,
|
|
/\.(txt|md|js|ts|py|html|css|json|yaml|yml|xml)$/,
|
|
/^edit\s+['"]?[\w\-./]/
|
|
],
|
|
|
|
// Code execution patterns
|
|
code: [
|
|
/^run\s+(?:code|script|python|node)\b/,
|
|
/^execute\s+(?:code|python|javascript)\b/,
|
|
/^eval\b/,
|
|
/^(python|python3|node)\s+-c/,
|
|
/^(python|python3|node)\s+\S+\.py$/
|
|
],
|
|
|
|
// Web search patterns
|
|
web: [
|
|
/^(search|google|bing)\b/,
|
|
/^(lookup|find)\s+(?:on\s+(?:web|google|internet))/,
|
|
/^what\s+is\b/,
|
|
/^how\s+to\b/,
|
|
/^explain\b/
|
|
]
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Register available tools
|
|
*/
|
|
setTools(tools) {
|
|
this.tools = tools;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Update context
|
|
*/
|
|
updateContext(updates) {
|
|
Object.assign(this.context, updates);
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Analyze input and determine intent
|
|
*
|
|
* @param {string} input - User input
|
|
* @returns {IntentResult} Analysis result
|
|
*/
|
|
analyze(input) {
|
|
const trimmed = input.trim();
|
|
|
|
// Check for empty input
|
|
if (!trimmed) {
|
|
return {
|
|
intent: 'unknown',
|
|
confidence: 0,
|
|
tool: null,
|
|
parameters: {},
|
|
reasoning: 'Empty input'
|
|
};
|
|
}
|
|
|
|
// Analyze patterns
|
|
const patternResult = this.analyzePatterns(trimmed);
|
|
if (patternResult.confidence > 0.7) {
|
|
return patternResult;
|
|
}
|
|
|
|
// Analyze keywords
|
|
const keywordResult = this.analyzeKeywords(trimmed);
|
|
if (keywordResult.confidence > 0.5) {
|
|
return keywordResult;
|
|
}
|
|
|
|
// Use context/history
|
|
const contextResult = this.analyzeContext(trimmed);
|
|
if (contextResult.confidence > 0.4) {
|
|
return contextResult;
|
|
}
|
|
|
|
// Default to shell command
|
|
return {
|
|
intent: 'shell',
|
|
confidence: 0.3,
|
|
tool: 'shell',
|
|
parameters: { command: trimmed },
|
|
reasoning: 'Default to shell execution'
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Analyze based on known patterns
|
|
*/
|
|
analyzePatterns(input) {
|
|
const lower = input.toLowerCase();
|
|
|
|
for (const [intent, patterns] of Object.entries(this.patterns)) {
|
|
for (const pattern of patterns) {
|
|
if (pattern.test(input)) {
|
|
return this.buildIntentResult(intent, input, 0.9, 'Pattern match');
|
|
}
|
|
}
|
|
}
|
|
|
|
return { confidence: 0 };
|
|
}
|
|
|
|
/**
|
|
* Analyze based on keywords
|
|
*/
|
|
analyzeKeywords(input) {
|
|
const keywords = {
|
|
shell: ['execute', 'run', 'command', 'terminal', 'shell', 'bash'],
|
|
file: ['file', 'folder', 'directory', 'read', 'write', 'create'],
|
|
code: ['code', 'script', 'function', 'class'],
|
|
web: ['search', 'find', 'google', 'lookup', 'internet', 'web']
|
|
};
|
|
|
|
const lower = input.toLowerCase();
|
|
let bestMatch = { intent: null, score: 0 };
|
|
|
|
for (const [intent, kwList] of Object.entries(keywords)) {
|
|
const score = kwList.reduce((acc, kw) => {
|
|
return acc + (lower.includes(kw) ? 1 : 0);
|
|
}, 0);
|
|
|
|
if (score > bestMatch.score) {
|
|
bestMatch = { intent, score };
|
|
}
|
|
}
|
|
|
|
if (bestMatch.score > 0) {
|
|
const confidence = Math.min(0.6, bestMatch.score * 0.2);
|
|
return this.buildIntentResult(bestMatch.intent, input, confidence, 'Keyword match');
|
|
}
|
|
|
|
return { confidence: 0 };
|
|
}
|
|
|
|
/**
|
|
* Analyze based on context and history
|
|
*/
|
|
analyzeContext(input) {
|
|
// Check if this is a continuation
|
|
const lastCommand = this.context.previousCommands[
|
|
this.context.previousCommands.length - 1
|
|
];
|
|
|
|
if (lastCommand) {
|
|
// Continuation of previous command
|
|
if (input.startsWith('&&') || input.startsWith('||') || input.startsWith('|')) {
|
|
return {
|
|
intent: 'shell',
|
|
confidence: 0.8,
|
|
tool: 'shell',
|
|
parameters: { command: `${lastCommand.command} ${input}` },
|
|
reasoning: 'Command continuation'
|
|
};
|
|
}
|
|
|
|
// Repeat previous command
|
|
if (input === '!!' || input === 'again') {
|
|
return {
|
|
intent: lastCommand.intent,
|
|
confidence: 0.7,
|
|
tool: lastCommand.tool,
|
|
parameters: lastCommand.parameters,
|
|
reasoning: 'Repeat previous command'
|
|
};
|
|
}
|
|
|
|
// Reference to previous output
|
|
if (input.includes('previous') || input.includes('last')) {
|
|
return {
|
|
intent: lastCommand.intent,
|
|
confidence: 0.6,
|
|
tool: lastCommand.tool,
|
|
parameters: lastCommand.parameters,
|
|
reasoning: 'Reference to previous command'
|
|
};
|
|
}
|
|
}
|
|
|
|
return { confidence: 0 };
|
|
}
|
|
|
|
/**
|
|
* Build intent result based on detected intent
|
|
*/
|
|
buildIntentResult(intent, input, confidence, reasoning) {
|
|
const toolMap = {
|
|
shell: 'shell',
|
|
file: 'file',
|
|
code: 'shell', // Code execution uses shell
|
|
web: 'web_search' // Hypothetical web tool
|
|
};
|
|
|
|
const parameters = this.extractParameters(intent, input);
|
|
|
|
return {
|
|
intent,
|
|
confidence,
|
|
tool: toolMap[intent] || 'shell',
|
|
parameters,
|
|
reasoning
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Extract parameters based on intent
|
|
*/
|
|
extractParameters(intent, input) {
|
|
switch (intent) {
|
|
case 'shell':
|
|
return { command: input };
|
|
|
|
case 'file':
|
|
return this.extractFileParameters(input);
|
|
|
|
case 'code':
|
|
return { command: input };
|
|
|
|
case 'web':
|
|
return { query: input.replace(/^(search|google|bing)\s+/i, '') };
|
|
|
|
default:
|
|
return { command: input };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extract file operation parameters
|
|
*/
|
|
extractFileParameters(input) {
|
|
const lower = input.toLowerCase();
|
|
|
|
// Detect operation
|
|
let operation = 'read';
|
|
if (lower.startsWith('write') || lower.startsWith('create') || lower.startsWith('save')) {
|
|
operation = 'write';
|
|
} else if (lower.startsWith('delete') || lower.startsWith('remove')) {
|
|
operation = 'delete';
|
|
} else if (lower.startsWith('copy') || lower.startsWith('cp')) {
|
|
operation = 'copy';
|
|
} else if (lower.startsWith('move') || lower.startsWith('mv')) {
|
|
operation = 'move';
|
|
} else if (lower.startsWith('list') || lower.startsWith('ls')) {
|
|
operation = 'list';
|
|
}
|
|
|
|
// Extract path
|
|
const pathMatch = input.match(/['"]?([\w\-./\\]+)['"]?/);
|
|
const path = pathMatch ? pathMatch[1] : '';
|
|
|
|
return { operation, path };
|
|
}
|
|
|
|
/**
|
|
* Get suggestions based on context
|
|
*/
|
|
getSuggestions(input) {
|
|
const suggestions = [];
|
|
|
|
// Command history suggestions
|
|
if (input.length > 0) {
|
|
const matching = this.context.previousCommands
|
|
.filter(cmd => cmd.command && cmd.command.startsWith(input))
|
|
.slice(0, 5)
|
|
.map(cmd => cmd.command);
|
|
|
|
suggestions.push(...matching);
|
|
}
|
|
|
|
// Common commands
|
|
if (!input) {
|
|
suggestions.push(
|
|
'ls -la',
|
|
'pwd',
|
|
'git status',
|
|
'npm install',
|
|
'npm test'
|
|
);
|
|
}
|
|
|
|
return suggestions;
|
|
}
|
|
|
|
/**
|
|
* Learn from executed commands
|
|
*/
|
|
learn(command, result) {
|
|
this.context.previousCommands.push({
|
|
command,
|
|
result,
|
|
timestamp: Date.now()
|
|
});
|
|
|
|
// Keep only last 100 commands
|
|
if (this.context.previousCommands.length > 100) {
|
|
this.context.previousCommands.shift();
|
|
}
|
|
|
|
return this;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Intent Result Structure
|
|
*/
|
|
class IntentResult {
|
|
constructor(result) {
|
|
this.intent = result.intent || 'unknown';
|
|
this.confidence = result.confidence || 0;
|
|
this.tool = result.tool || null;
|
|
this.parameters = result.parameters || {};
|
|
this.reasoning = result.reasoning || '';
|
|
}
|
|
|
|
isValid() {
|
|
return this.confidence > 0.3 && this.tool;
|
|
}
|
|
|
|
toJSON() {
|
|
return {
|
|
intent: this.intent,
|
|
confidence: this.confidence,
|
|
tool: this.tool,
|
|
parameters: this.parameters,
|
|
reasoning: this.reasoning
|
|
};
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
IntentAnalyzer,
|
|
IntentResult
|
|
};
|