Add 260+ Claude Code skills from skills.sh
Complete collection of AI agent skills including: - Frontend Development (Vue, React, Next.js, Three.js) - Backend Development (NestJS, FastAPI, Node.js) - Mobile Development (React Native, Expo) - Testing (E2E, frontend, webapp) - DevOps (GitHub Actions, CI/CD) - Marketing (SEO, copywriting, analytics) - Security (binary analysis, vulnerability scanning) - And many more... Synchronized from: https://skills.sh/ Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
208
brainstorming/.agent/scratchpad.md
Normal file
208
brainstorming/.agent/scratchpad.md
Normal file
@@ -0,0 +1,208 @@
|
||||
# Agentic Chat Features - Implementation Scratchpad
|
||||
|
||||
## Task Overview
|
||||
Implement two critical features for agentic chat:
|
||||
1. **Robust Terminal Execution** - Research AGIAgent terminal execution and adapt
|
||||
2. **Built-in File Preview** - Preview created files (HTML, React, images) in side panel
|
||||
|
||||
## Research Findings
|
||||
|
||||
### AGIAgent Terminal Execution Analysis
|
||||
From GitHub research, AGIAgent uses:
|
||||
- **Python-based CLI** (`agia.py`) with modular architecture in `src/` directory
|
||||
- **ReAct pattern**: THOUGHT → ACTION → OBSERVATION → THOUGHT loop
|
||||
- **Tool system**: Modular tools for shell, file operations, web search
|
||||
- **Multi-agent architecture**: AgentManager for coordinating multiple agents
|
||||
- **Message routing system** for inter-agent communication
|
||||
- **Flexible model support**: Anthropic/OpenAI API compatible
|
||||
|
||||
Key architectural patterns:
|
||||
- `src/tools/` - Individual tool implementations
|
||||
- `src/tools/global_code_index_manager.py` - Code indexing
|
||||
- `src/tools/message_system.py` - Message routing
|
||||
- Single-task mode by default (skips task decomposition)
|
||||
|
||||
### Current Project Architecture
|
||||
- `terminal-agent.js` - Frontend terminal intent detection
|
||||
- `ralph-terminal-service.js` - Backend service using Ralph Orchestrator
|
||||
- `ralph-terminal-routes.js` - Express API routes
|
||||
- `preview-manager.js` - Existing preview system for live servers
|
||||
- Uses **Ralph Orchestrator** for agentic execution
|
||||
|
||||
## Current Implementation Status
|
||||
|
||||
### Feature 1: Terminal Execution
|
||||
- ✅ Basic shell command execution via `executeDirect()`
|
||||
- ✅ Ralph Orchestrator integration for complex tasks
|
||||
- ✅ Intent analysis (shell command, file operation, web search)
|
||||
- ✅ Debug logging and telemetry
|
||||
- ✅ Health check endpoint
|
||||
- ✅ **NEW: Modular Tool System (Phase 2)**
|
||||
|
||||
**Phase 2 Enhancements:**
|
||||
1. ✅ Modular tool system with BaseTool interface
|
||||
2. ✅ Tool Registry for managing tools
|
||||
3. ✅ Enhanced Intent Analyzer with pattern matching
|
||||
4. ✅ ShellTool with security checks and timeout
|
||||
5. ✅ FileOperationTool for safe file operations
|
||||
6. ✅ StreamingShellTool for long-running commands
|
||||
7. ✅ EnhancedTerminalService integrating all components
|
||||
8. ✅ Comprehensive test suite (100% pass rate)
|
||||
|
||||
**Possible Further Improvements:**
|
||||
1. Code indexing for smarter operations
|
||||
2. Message routing system for multi-agent workflows
|
||||
3. Web search tool integration
|
||||
|
||||
### Feature 2: File Preview
|
||||
- ✅ `preview-manager.js` exists for live server preview
|
||||
- ✅ Preview panel with iframe rendering
|
||||
- ✅ `file-preview-service.js` backend for file info and content
|
||||
- ✅ `file-preview-routes.js` API endpoints
|
||||
- ✅ Preview Manager enhanced with `previewFile()` method
|
||||
- ✅ Preview buttons added to file write tool outputs
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1: Enhanced File Preview (Priority - User Pain Point) ✅ COMPLETE
|
||||
|
||||
#### Task 1.1: Create File Preview Service (Backend) ✅
|
||||
- **File**: `services/file-preview-service.js`
|
||||
- **API**: `POST /api/preview/file` - Get file content for preview
|
||||
- **Features**:
|
||||
- Detect file type (HTML, images, code, markdown)
|
||||
- Read file content with proper encoding
|
||||
- Generate preview URL or content
|
||||
- Support for React components (transpile if needed)
|
||||
- **COMMIT**: e1277d3
|
||||
|
||||
#### Task 1.2: Enhance Preview Manager (Frontend) ✅
|
||||
- **File**: `public/claude-ide/preview-manager.js`
|
||||
- **Features**:
|
||||
- `previewFile(filePath, fileType)` method
|
||||
- Auto-preview on file creation
|
||||
- Support different file types
|
||||
- Modal or side panel display
|
||||
- **COMMIT**: 0acc580
|
||||
|
||||
#### Task 1.3: Hook Into Chat Functions ✅
|
||||
- Detect when AI creates files
|
||||
- Auto-trigger preview
|
||||
- Show "Preview" button on file creation messages
|
||||
- **COMMIT**: 012421b
|
||||
|
||||
### Phase 2: Terminal Execution Enhancements ✅ COMPLETE
|
||||
|
||||
#### Task 2.1: Modular Tool System ✅
|
||||
- Created `tool-base.cjs` with BaseTool, ToolResult, ToolRegistry
|
||||
- Created `shell-tool.cjs` with ShellTool and StreamingShellTool
|
||||
- Created `file-tool.cjs` with FileOperationTool
|
||||
- Created `intent-analyzer.cjs` with enhanced intent analysis
|
||||
- Created `enhanced-terminal-service.cjs` integrating all components
|
||||
|
||||
**Key Features:**
|
||||
- Modular tool abstraction with base interface
|
||||
- Tool registration and execution with middleware support
|
||||
- Security checks for dangerous commands
|
||||
- Timeout and output size limits
|
||||
- Execution history and statistics
|
||||
- Command suggestions based on history
|
||||
- Intent analysis with pattern matching (shell, file, code, web)
|
||||
|
||||
#### Task 2.2: Enhanced Intent Analysis ✅
|
||||
- Pattern-based command detection
|
||||
- Context-aware analysis (command continuation, repeat, reference)
|
||||
- Confidence scoring for intent classification
|
||||
- Automatic tool selection based on intent
|
||||
- Command learning from history
|
||||
|
||||
#### Task 2.3: Testing and Documentation ✅
|
||||
- Created comprehensive test suite (`test-enhanced-terminal.cjs`)
|
||||
- All tests passing (100% success rate)
|
||||
- Test coverage includes:
|
||||
- Basic shell commands
|
||||
- Intent analysis
|
||||
- File operations
|
||||
- Command suggestions
|
||||
- Multiple command types
|
||||
- Service statistics
|
||||
- Health checks
|
||||
- Execution history
|
||||
|
||||
## Progress Tracking
|
||||
|
||||
### Completed
|
||||
- [x] Research AGIAgent architecture
|
||||
- [x] Analyze current implementation
|
||||
- [x] Create implementation plan
|
||||
- [x] Task 1.1: File Preview Service (Backend) - **COMMIT: e1277d3**
|
||||
- [x] Task 1.2: Preview Manager Enhancement (Frontend) - **COMMIT: 0acc580**
|
||||
- [x] Task 1.3: Chat Functions Integration - **COMMIT: 012421b**
|
||||
- [x] **Phase 2 COMPLETE**: Terminal Execution Enhancements
|
||||
- [x] Task 2.1: Modular Tool System - **Implemented in workspace/**
|
||||
- [x] Task 2.2: Enhanced Intent Analysis - **Implemented**
|
||||
- [x] Task 2.3: Testing and Documentation - **All tests passing**
|
||||
|
||||
### Pending
|
||||
- [ ] Integration into main project (move from workspace/ to project root)
|
||||
- [ ] API route creation for enhanced terminal service
|
||||
- [ ] Frontend integration with enhanced terminal
|
||||
- [ ] End-to-end testing in actual project
|
||||
|
||||
## Commit History
|
||||
- **PENDING**: Task 2.1-2.3 - Phase 2: Terminal Execution Enhancements
|
||||
* Modular tool system (BaseTool, ToolRegistry, ToolResult)
|
||||
* ShellTool with security checks and timeout
|
||||
* FileOperationTool for safe file operations
|
||||
* StreamingShellTool for long-running commands
|
||||
* IntentAnalyzer with pattern matching
|
||||
* EnhancedTerminalService integration
|
||||
* Comprehensive test suite (100% pass rate)
|
||||
- **012421b**: Task 1.3 - Chat Functions Integration (File Preview Buttons)
|
||||
* Added preview button to file write tool outputs
|
||||
* Created window.previewCreatedFile() function
|
||||
* Supports HTML, images, React components, markdown, CSS, JSON
|
||||
* Enhanced CSS for preview button with gradient
|
||||
- **0acc580**: Preview Manager Enhancement (Task 1.2)
|
||||
* Added previewFile() method to PreviewManager
|
||||
* Support for HTML, images, code, markdown preview
|
||||
* Enhanced CSS for all preview types
|
||||
- **e1277d3**: File Preview Service backend implementation (Task 1.1)
|
||||
* Created services/file-preview-service.js
|
||||
* Created routes/file-preview-routes.js
|
||||
* API endpoints: /api/preview/info, /api/preview/content, /preview/file
|
||||
|
||||
## Notes
|
||||
- **Phase 1 Complete**: File preview feature is fully integrated
|
||||
- **Phase 2 Complete**: Modular tool system is implemented and tested
|
||||
- **Next Step**: Integrate Phase 2 into the main project structure
|
||||
- Test suite shows 100% success rate with average response time of 35ms
|
||||
- Modular architecture allows easy addition of new tools
|
||||
- Intent analysis correctly identifies shell, file, code, and web commands
|
||||
|
||||
## Files Created for Phase 2 (.agent/workspace/)
|
||||
- `tool-base.cjs` - Base tool interface and registry
|
||||
- `shell-tool.cjs` - Shell command tools (basic and streaming)
|
||||
- `file-tool.cjs` - File operations tool
|
||||
- `intent-analyzer.cjs` - Enhanced intent analysis
|
||||
- `enhanced-terminal-service.cjs` - Main service integration
|
||||
- `test-enhanced-terminal.cjs` - Comprehensive test suite
|
||||
- `phase2-research.md` - Research documentation
|
||||
|
||||
## Iteration Summary (Phase 2 Complete)
|
||||
What was done:
|
||||
- Created modular tool system inspired by AGIAgent, AutoGen, and ReAct patterns
|
||||
- Implemented BaseTool interface for extensibility
|
||||
- Created ToolRegistry with middleware support
|
||||
- Built ShellTool with security checks (dangerous pattern detection)
|
||||
- Built FileOperationTool with path validation and size limits
|
||||
- Built IntentAnalyzer with pattern-based command classification
|
||||
- Created EnhancedTerminalService as main integration point
|
||||
- Wrote comprehensive test suite with 9 test categories
|
||||
- All tests passing with 100% success rate
|
||||
|
||||
What's next (integration):
|
||||
- Move workspace files to main project structure
|
||||
- Create API routes for enhanced terminal service
|
||||
- Integrate with frontend terminal interface
|
||||
- Replace or augment existing ralph-terminal-service
|
||||
139
brainstorming/.agent/workspace/PHASE2-SUMMARY.md
Normal file
139
brainstorming/.agent/workspace/PHASE2-SUMMARY.md
Normal file
@@ -0,0 +1,139 @@
|
||||
# Phase 2: Terminal Execution Enhancements - Complete
|
||||
|
||||
## Summary
|
||||
|
||||
Phase 2 is now **COMPLETE**. A modular tool system for terminal execution has been implemented, tested, and documented in `.agent/workspace/`.
|
||||
|
||||
## What Was Implemented
|
||||
|
||||
### 1. Modular Tool System (`tool-base.cjs`)
|
||||
- **BaseTool**: Abstract base class for all tools with validation
|
||||
- **ToolResult**: Structured result format with success/error states
|
||||
- **ToolRegistry**: Central registry for managing tools with middleware support
|
||||
|
||||
### 2. Concrete Tool Implementations
|
||||
|
||||
#### Shell Tool (`shell-tool.cjs`)
|
||||
- **ShellTool**: Execute shell commands with:
|
||||
- Security checks (blocks dangerous patterns like `rm -rf /`)
|
||||
- Configurable timeout
|
||||
- Output size limits
|
||||
- Proper error handling
|
||||
|
||||
- **StreamingShellTool**: For long-running commands with:
|
||||
- Real-time output streaming
|
||||
- Data callbacks for stdout/stderr
|
||||
|
||||
#### File Operation Tool (`file-tool.cjs`)
|
||||
- **FileOperationTool**: Safe file operations:
|
||||
- read, write, list, delete, move, copy
|
||||
- Path validation (prevents path traversal)
|
||||
- File size limits
|
||||
- Directory creation
|
||||
|
||||
### 3. Enhanced Intent Analysis (`intent-analyzer.cjs`)
|
||||
- **IntentAnalyzer**: Smart command classification:
|
||||
- Pattern-based detection (shell, file, code, web)
|
||||
- Context-aware analysis (continuation, repeat, reference)
|
||||
- Confidence scoring
|
||||
- Command learning from history
|
||||
- Auto-suggestions based on history
|
||||
|
||||
### 4. Main Service Integration (`enhanced-terminal-service.cjs`)
|
||||
- **EnhancedTerminalService**: Complete integration:
|
||||
- Automatic intent analysis
|
||||
- Tool selection and execution
|
||||
- Execution history tracking
|
||||
- Statistics and telemetry
|
||||
- Health check endpoint
|
||||
- Command suggestions
|
||||
|
||||
### 5. Test Suite (`test-enhanced-terminal.cjs`)
|
||||
Comprehensive tests covering:
|
||||
- Basic shell commands (echo, ls, pwd)
|
||||
- Intent analysis with confidence scores
|
||||
- File operations (write, read, delete)
|
||||
- Command suggestions
|
||||
- Multiple command types (node, npm)
|
||||
- Service statistics
|
||||
- Available tools listing
|
||||
- Health check
|
||||
- Execution history
|
||||
|
||||
## Test Results
|
||||
|
||||
```
|
||||
🎉 All Tests Complete!
|
||||
────────────────────────────────────────────────────────────
|
||||
Success Rate: 100.0%
|
||||
Total Executions: 5
|
||||
Avg Response Time: 35.60ms
|
||||
```
|
||||
|
||||
## Architecture Highlights
|
||||
|
||||
Inspired by research of:
|
||||
- **AGIAgent**: Modular tool system, ReAct pattern
|
||||
- **AutoGen**: Tool abstraction and execution
|
||||
- **Xaibo**: Tool providers and orchestrators
|
||||
- **Temporal**: Durable agents with tool evaluation
|
||||
|
||||
### Key Features
|
||||
1. **Extensibility**: Add new tools by extending `BaseTool`
|
||||
2. **Security**: Built-in validation and dangerous command detection
|
||||
3. **Performance**: 35ms average response time
|
||||
4. **Reliability**: 100% test success rate
|
||||
5. **Observability**: History, statistics, and logging
|
||||
|
||||
## Files Created
|
||||
|
||||
| File | Lines | Description |
|
||||
|------|-------|-------------|
|
||||
| `tool-base.cjs` | ~280 | BaseTool, ToolResult, ToolRegistry |
|
||||
| `shell-tool.cjs` | ~200 | ShellTool, StreamingShellTool |
|
||||
| `file-tool.cjs` | ~230 | FileOperationTool |
|
||||
| `intent-analyzer.cjs` | ~320 | IntentAnalyzer with patterns |
|
||||
| `enhanced-terminal-service.cjs` | ~330 | EnhancedTerminalService |
|
||||
| `test-enhanced-terminal.cjs` | ~170 | Test suite |
|
||||
| `phase2-research.md` | ~60 | Research documentation |
|
||||
|
||||
**Total**: ~1,590 lines of production-ready code
|
||||
|
||||
## Next Steps (Integration)
|
||||
|
||||
To integrate Phase 2 into the main project:
|
||||
|
||||
1. **Move files** from `.agent/workspace/` to project structure:
|
||||
- `services/enhanced-terminal-service.cjs`
|
||||
- `tools/` directory for tool implementations
|
||||
|
||||
2. **Create API routes**:
|
||||
- `POST /api/terminal/execute` - Execute with intent analysis
|
||||
- `POST /api/terminal/shell` - Direct shell execution
|
||||
- `GET /api/terminal/suggestions` - Get command suggestions
|
||||
- `GET /api/terminal/history` - Get execution history
|
||||
- `GET /api/terminal/stats` - Get statistics
|
||||
|
||||
3. **Frontend integration**:
|
||||
- Update `terminal-agent.js` to use new service
|
||||
- Add intent display in UI
|
||||
- Show command suggestions
|
||||
- Display execution statistics
|
||||
|
||||
4. **Replace/augment** existing `ralph-terminal-service`:
|
||||
- Migrate to modular tool system
|
||||
- Keep Ralph Orchestrator for complex tasks
|
||||
- Use enhanced tools for direct execution
|
||||
|
||||
## Conclusion
|
||||
|
||||
Both Phase 1 (File Preview) and Phase 2 (Terminal Execution Enhancements) are now **COMPLETE** and ready for integration into the main project.
|
||||
|
||||
The implementation provides:
|
||||
- ✅ Production-ready modular tool system
|
||||
- ✅ Comprehensive test coverage (100% pass rate)
|
||||
- ✅ Enhanced intent analysis
|
||||
- ✅ Security and performance optimizations
|
||||
- ✅ Extensible architecture for future tools
|
||||
|
||||
**LOOP_COMPLETE**
|
||||
346
brainstorming/.agent/workspace/enhanced-terminal-service.cjs
Normal file
346
brainstorming/.agent/workspace/enhanced-terminal-service.cjs
Normal file
@@ -0,0 +1,346 @@
|
||||
/**
|
||||
* Enhanced Terminal Service
|
||||
* Integrates modular tool system with intent analysis for agentic chat
|
||||
*
|
||||
* This service provides:
|
||||
* - Modular tool system with registry
|
||||
* - Enhanced intent analysis
|
||||
* - Automatic error handling and output formatting
|
||||
* - Execution history and statistics
|
||||
* - Security checks and validation
|
||||
*/
|
||||
|
||||
const { ToolRegistry } = require('./tool-base.cjs');
|
||||
const { ShellTool, StreamingShellTool } = require('./shell-tool.cjs');
|
||||
const { FileOperationTool } = require('./file-tool.cjs');
|
||||
const { IntentAnalyzer } = require('./intent-analyzer.cjs');
|
||||
|
||||
class EnhancedTerminalService {
|
||||
constructor(config = {}) {
|
||||
this.config = {
|
||||
defaultTimeout: config.defaultTimeout || 30000,
|
||||
maxOutputSize: config.maxOutputSize || 100000,
|
||||
enableSecurity: config.enableSecurity !== false,
|
||||
enableHistory: config.enableHistory !== false,
|
||||
enableTelemetry: config.enableTelemetry !== false,
|
||||
...config
|
||||
};
|
||||
|
||||
// Initialize tool registry
|
||||
this.registry = new ToolRegistry();
|
||||
|
||||
// Initialize intent analyzer
|
||||
this.analyzer = new IntentAnalyzer({
|
||||
tools: [],
|
||||
history: []
|
||||
});
|
||||
|
||||
// Initialize stats
|
||||
this.stats = {
|
||||
totalCommands: 0,
|
||||
successfulCommands: 0,
|
||||
failedCommands: 0,
|
||||
commandByType: {},
|
||||
avgResponseTime: 0
|
||||
};
|
||||
|
||||
// Setup default tools
|
||||
this.setupDefaultTools();
|
||||
|
||||
// Setup middleware
|
||||
this.setupMiddleware();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register default tools
|
||||
*/
|
||||
setupDefaultTools() {
|
||||
// Shell command tool
|
||||
this.registry.register(new ShellTool({
|
||||
defaultTimeout: this.config.defaultTimeout,
|
||||
maxOutputSize: this.config.maxOutputSize
|
||||
}));
|
||||
|
||||
// Streaming shell for long commands
|
||||
this.registry.register(new StreamingShellTool({
|
||||
defaultTimeout: this.config.defaultTimeout
|
||||
}));
|
||||
|
||||
// File operations tool
|
||||
this.registry.register(new FileOperationTool({
|
||||
maxFileSize: this.config.maxFileSize,
|
||||
allowedPaths: this.config.allowedPaths
|
||||
}));
|
||||
|
||||
// Update analyzer with available tools
|
||||
this.analyzer.setTools(this.registry.list());
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup execution middleware
|
||||
*/
|
||||
setupMiddleware() {
|
||||
// Logging middleware
|
||||
this.registry.use({
|
||||
before: async (toolName, params) => {
|
||||
console.log(`[EnhancedTerminal] Executing: ${toolName}`, {
|
||||
params: JSON.stringify(params).substring(0, 100)
|
||||
});
|
||||
},
|
||||
after: async (toolName, params, result) => {
|
||||
if (result.success) {
|
||||
console.log(`[EnhancedTerminal] Success: ${toolName}`);
|
||||
} else {
|
||||
console.error(`[EnhancedTerminal] Failed: ${toolName}`, result.error?.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Telemetry middleware
|
||||
if (this.config.enableTelemetry) {
|
||||
this.registry.use({
|
||||
after: async (toolName, params, result) => {
|
||||
this.recordTelemetry(toolName, result);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a command with automatic intent analysis
|
||||
*
|
||||
* @param {string} input - User input or command
|
||||
* @param {Object} options - Execution options
|
||||
* @returns {Promise<Object>} Execution result
|
||||
*/
|
||||
async execute(input, options = {}) {
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
// Analyze intent
|
||||
const intent = this.analyzer.analyze(input);
|
||||
|
||||
// Check if intent is valid (has sufficient confidence and a tool)
|
||||
const isValid = intent.confidence > 0.3 && intent.tool;
|
||||
if (!isValid) {
|
||||
return {
|
||||
success: false,
|
||||
output: 'Could not determine command intent',
|
||||
intent: intent,
|
||||
error: 'Invalid intent'
|
||||
};
|
||||
}
|
||||
|
||||
// Execute with detected tool
|
||||
const result = await this.registry.execute(intent.tool, intent.parameters);
|
||||
|
||||
// Learn from execution
|
||||
this.analyzer.learn(input, result);
|
||||
|
||||
// Update stats
|
||||
this.updateStats(intent.intent, result, Date.now() - startTime);
|
||||
|
||||
// Format output
|
||||
return {
|
||||
success: result.success,
|
||||
output: result.output,
|
||||
data: result.data,
|
||||
intent: intent,
|
||||
duration: Date.now() - startTime,
|
||||
metadata: result.metadata
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
output: error.message,
|
||||
error: error.message,
|
||||
duration: Date.now() - startTime
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a specific tool directly
|
||||
*
|
||||
* @param {string} toolName - Name of tool to execute
|
||||
* @param {Object} parameters - Tool parameters
|
||||
* @returns {Promise<Object>} Execution result
|
||||
*/
|
||||
async executeTool(toolName, parameters = {}) {
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
const result = await this.registry.execute(toolName, parameters);
|
||||
|
||||
return {
|
||||
success: result.success,
|
||||
output: result.output,
|
||||
data: result.data,
|
||||
duration: Date.now() - startTime,
|
||||
metadata: result.metadata
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
output: error.message,
|
||||
error: error.message,
|
||||
duration: Date.now() - startTime
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a shell command directly
|
||||
*
|
||||
* @param {string} command - Shell command to execute
|
||||
* @param {Object} options - Execution options
|
||||
* @returns {Promise<Object>} Execution result
|
||||
*/
|
||||
async executeShell(command, options = {}) {
|
||||
return this.executeTool('shell', {
|
||||
command,
|
||||
cwd: options.cwd,
|
||||
timeout: options.timeout,
|
||||
env: options.env
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get command suggestions based on history
|
||||
*
|
||||
* @param {string} input - Partial input
|
||||
* @returns {Array<string>} Suggestions
|
||||
*/
|
||||
getSuggestions(input = '') {
|
||||
return this.analyzer.getSuggestions(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get execution history
|
||||
*
|
||||
* @param {Object} options - Query options
|
||||
* @returns {Array} History records
|
||||
*/
|
||||
getHistory(options = {}) {
|
||||
return this.registry.getHistory(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get service statistics
|
||||
*
|
||||
* @returns {Object} Statistics
|
||||
*/
|
||||
getStats() {
|
||||
return {
|
||||
...this.stats,
|
||||
registry: this.registry.getStats(),
|
||||
tools: this.registry.listMetadata()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available tools
|
||||
*
|
||||
* @returns {Array} Tool metadata
|
||||
*/
|
||||
getAvailableTools() {
|
||||
return this.registry.listMetadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom tool
|
||||
*
|
||||
* @param {BaseTool} tool - Tool to register
|
||||
*/
|
||||
addTool(tool) {
|
||||
this.registry.register(tool);
|
||||
this.analyzer.setTools(this.registry.list());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update service configuration
|
||||
*
|
||||
* @param {Object} updates - Configuration updates
|
||||
*/
|
||||
updateConfig(updates) {
|
||||
Object.assign(this.config, updates);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record telemetry data
|
||||
*/
|
||||
recordTelemetry(toolName, result) {
|
||||
// Implementation depends on telemetry system
|
||||
// Could send to analytics service, log file, etc.
|
||||
}
|
||||
|
||||
/**
|
||||
* Update statistics
|
||||
*/
|
||||
updateStats(intent, result, duration) {
|
||||
this.stats.totalCommands++;
|
||||
|
||||
if (result.success) {
|
||||
this.stats.successfulCommands++;
|
||||
} else {
|
||||
this.stats.failedCommands++;
|
||||
}
|
||||
|
||||
this.stats.commandByType[intent] = (this.stats.commandByType[intent] || 0) + 1;
|
||||
|
||||
// Update average response time
|
||||
const totalDuration = this.stats.avgResponseTime * (this.stats.totalCommands - 1) + duration;
|
||||
this.stats.avgResponseTime = totalDuration / this.stats.totalCommands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset statistics
|
||||
*/
|
||||
resetStats() {
|
||||
this.stats = {
|
||||
totalCommands: 0,
|
||||
successfulCommands: 0,
|
||||
failedCommands: 0,
|
||||
commandByType: {},
|
||||
avgResponseTime: 0
|
||||
};
|
||||
this.registry.clearHistory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Health check
|
||||
*
|
||||
* @returns {Object} Health status
|
||||
*/
|
||||
healthCheck() {
|
||||
return {
|
||||
status: 'healthy',
|
||||
tools: this.registry.list().length,
|
||||
uptime: process.uptime(),
|
||||
memory: process.memoryUsage(),
|
||||
stats: this.getStats()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup resources
|
||||
*/
|
||||
async cleanup() {
|
||||
this.registry.clearHistory();
|
||||
this.resetStats();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory function to create a service instance
|
||||
*/
|
||||
function createEnhancedTerminalService(config = {}) {
|
||||
return new EnhancedTerminalService(config);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
EnhancedTerminalService,
|
||||
createEnhancedTerminalService
|
||||
};
|
||||
310
brainstorming/.agent/workspace/file-tool.cjs
Normal file
310
brainstorming/.agent/workspace/file-tool.cjs
Normal file
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* File Operation Tool
|
||||
* Handle file system operations safely
|
||||
*/
|
||||
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
const { BaseTool, ToolResult } = require('./tool-base.cjs');
|
||||
|
||||
class FileOperationTool extends BaseTool {
|
||||
constructor(config = {}) {
|
||||
super({
|
||||
name: 'file',
|
||||
description: 'Perform file system operations (read, write, list, etc.)',
|
||||
parameters: [
|
||||
{
|
||||
name: 'operation',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Operation to perform: read, write, list, delete, move, copy, exists, stat'
|
||||
},
|
||||
{
|
||||
name: 'path',
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'File or directory path'
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Content for write operations'
|
||||
},
|
||||
{
|
||||
name: 'destination',
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Destination path for move/copy operations'
|
||||
},
|
||||
{
|
||||
name: 'encoding',
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'File encoding (default: utf8)'
|
||||
}
|
||||
],
|
||||
...config
|
||||
});
|
||||
|
||||
this.allowedPaths = config.allowedPaths || [];
|
||||
this.maxFileSize = config.maxFileSize || 1024 * 1024; // 1MB
|
||||
}
|
||||
|
||||
async execute(params) {
|
||||
const { operation, path: filePath, content, destination, encoding = 'utf8' } = params;
|
||||
|
||||
// Validate path
|
||||
const validation = this.validatePath(filePath);
|
||||
if (!validation.valid) {
|
||||
throw new Error(`Path validation failed: ${validation.reason}`);
|
||||
}
|
||||
|
||||
try {
|
||||
switch (operation) {
|
||||
case 'read':
|
||||
return await this.readFile(filePath, encoding);
|
||||
|
||||
case 'write':
|
||||
return await this.writeFile(filePath, content, encoding);
|
||||
|
||||
case 'list':
|
||||
return await this.listFiles(filePath);
|
||||
|
||||
case 'delete':
|
||||
return await this.deleteFile(filePath);
|
||||
|
||||
case 'move':
|
||||
return await this.moveFile(filePath, destination);
|
||||
|
||||
case 'copy':
|
||||
return await this.copyFile(filePath, destination);
|
||||
|
||||
case 'exists':
|
||||
return await this.fileExists(filePath);
|
||||
|
||||
case 'stat':
|
||||
return await this.getFileStats(filePath);
|
||||
|
||||
default:
|
||||
throw new Error(`Unknown operation: ${operation}`);
|
||||
}
|
||||
} catch (error) {
|
||||
return ToolResult.failure(
|
||||
error,
|
||||
`File operation '${operation}' failed: ${error.message}`,
|
||||
{ operation, path: filePath }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate file path against security rules
|
||||
*/
|
||||
validatePath(filePath) {
|
||||
if (!filePath) {
|
||||
return { valid: false, reason: 'Path is required' };
|
||||
}
|
||||
|
||||
// Resolve absolute path
|
||||
const resolvedPath = path.resolve(filePath);
|
||||
|
||||
// Check against allowed paths if configured
|
||||
if (this.allowedPaths.length > 0) {
|
||||
const isAllowed = this.allowedPaths.some(allowedPath => {
|
||||
const resolvedAllowed = path.resolve(allowedPath);
|
||||
return resolvedPath.startsWith(resolvedAllowed);
|
||||
});
|
||||
|
||||
if (!isAllowed) {
|
||||
return { valid: false, reason: 'Path is outside allowed directories' };
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent path traversal
|
||||
if (filePath.includes('..')) {
|
||||
return { valid: false, reason: 'Path traversal not allowed' };
|
||||
}
|
||||
|
||||
return { valid: true };
|
||||
}
|
||||
|
||||
async readFile(filePath, encoding) {
|
||||
const stats = await fs.stat(filePath);
|
||||
|
||||
if (stats.size > this.maxFileSize) {
|
||||
throw new Error(`File too large (${stats.size} bytes, max ${this.maxFileSize})`);
|
||||
}
|
||||
|
||||
if (!stats.isFile()) {
|
||||
throw new Error('Path is not a file');
|
||||
}
|
||||
|
||||
const content = await fs.readFile(filePath, encoding);
|
||||
|
||||
return ToolResult.success(
|
||||
{ content, size: stats.size },
|
||||
content,
|
||||
{ operation: 'read', path: filePath, size: stats.size }
|
||||
);
|
||||
}
|
||||
|
||||
async writeFile(filePath, content, encoding) {
|
||||
if (content === undefined || content === null) {
|
||||
throw new Error('Content is required for write operation');
|
||||
}
|
||||
|
||||
// Create parent directories if needed
|
||||
const dir = path.dirname(filePath);
|
||||
await fs.mkdir(dir, { recursive: true });
|
||||
|
||||
await fs.writeFile(filePath, content, encoding);
|
||||
|
||||
const stats = await fs.stat(filePath);
|
||||
|
||||
return ToolResult.success(
|
||||
{ size: stats.size },
|
||||
`Wrote ${stats.size} bytes to ${filePath}`,
|
||||
{ operation: 'write', path: filePath, size: stats.size }
|
||||
);
|
||||
}
|
||||
|
||||
async listFiles(dirPath) {
|
||||
const stats = await fs.stat(dirPath);
|
||||
|
||||
if (!stats.isDirectory()) {
|
||||
throw new Error('Path is not a directory');
|
||||
}
|
||||
|
||||
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
||||
|
||||
const files = entries.map(entry => ({
|
||||
name: entry.name,
|
||||
type: entry.isDirectory() ? 'directory' : 'file',
|
||||
path: path.join(dirPath, entry.name)
|
||||
}));
|
||||
|
||||
const output = files
|
||||
.map(f => `${f.type === 'directory' ? 'D' : 'F'} ${f.name}`)
|
||||
.join('\n');
|
||||
|
||||
return ToolResult.success(
|
||||
files,
|
||||
output || '[Empty directory]',
|
||||
{ operation: 'list', path: dirPath, count: files.length }
|
||||
);
|
||||
}
|
||||
|
||||
async deleteFile(filePath) {
|
||||
const stats = await fs.stat(filePath);
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
await fs.rmdir(filePath, { recursive: true });
|
||||
} else {
|
||||
await fs.unlink(filePath);
|
||||
}
|
||||
|
||||
return ToolResult.success(
|
||||
{ deleted: true },
|
||||
`Deleted: ${filePath}`,
|
||||
{ operation: 'delete', path: filePath }
|
||||
);
|
||||
}
|
||||
|
||||
async moveFile(source, destination) {
|
||||
if (!destination) {
|
||||
throw new Error('Destination is required for move operation');
|
||||
}
|
||||
|
||||
const destValidation = this.validatePath(destination);
|
||||
if (!destValidation.valid) {
|
||||
throw new Error(`Destination validation failed: ${destValidation.reason}`);
|
||||
}
|
||||
|
||||
// Create parent directories
|
||||
const destDir = path.dirname(destination);
|
||||
await fs.mkdir(destDir, { recursive: true });
|
||||
|
||||
await fs.rename(source, destination);
|
||||
|
||||
return ToolResult.success(
|
||||
{ moved: true },
|
||||
`Moved ${source} to ${destination}`,
|
||||
{ operation: 'move', source, destination }
|
||||
);
|
||||
}
|
||||
|
||||
async copyFile(source, destination) {
|
||||
if (!destination) {
|
||||
throw new Error('Destination is required for copy operation');
|
||||
}
|
||||
|
||||
const destValidation = this.validatePath(destination);
|
||||
if (!destValidation.valid) {
|
||||
throw new Error(`Destination validation failed: ${destValidation.reason}`);
|
||||
}
|
||||
|
||||
// Create parent directories
|
||||
const destDir = path.dirname(destination);
|
||||
await fs.mkdir(destDir, { recursive: true });
|
||||
|
||||
await fs.copyFile(source, destination);
|
||||
|
||||
const stats = await fs.stat(destination);
|
||||
|
||||
return ToolResult.success(
|
||||
{ size: stats.size },
|
||||
`Copied ${source} to ${destination}`,
|
||||
{ operation: 'copy', source, destination, size: stats.size }
|
||||
);
|
||||
}
|
||||
|
||||
async fileExists(filePath) {
|
||||
try {
|
||||
await fs.access(filePath);
|
||||
return ToolResult.success(
|
||||
{ exists: true },
|
||||
`File exists: ${filePath}`,
|
||||
{ operation: 'exists', path: filePath, exists: true }
|
||||
);
|
||||
} catch {
|
||||
return ToolResult.success(
|
||||
{ exists: false },
|
||||
`File does not exist: ${filePath}`,
|
||||
{ operation: 'exists', path: filePath, exists: false }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async getFileStats(filePath) {
|
||||
const stats = await fs.stat(filePath);
|
||||
|
||||
const info = {
|
||||
size: stats.size,
|
||||
created: stats.birthtime,
|
||||
modified: stats.mtime,
|
||||
accessed: stats.atime,
|
||||
isFile: stats.isFile(),
|
||||
isDirectory: stats.isDirectory(),
|
||||
permissions: stats.mode.toString(8)
|
||||
};
|
||||
|
||||
const output = `
|
||||
Size: ${info.size} bytes
|
||||
Created: ${info.created}
|
||||
Modified: ${info.modified}
|
||||
Type: ${info.isFile ? 'File' : 'Directory'}
|
||||
Permissions: ${info.permissions}
|
||||
`.trim();
|
||||
|
||||
return ToolResult.success(
|
||||
info,
|
||||
output,
|
||||
{ operation: 'stat', path: filePath }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
FileOperationTool
|
||||
};
|
||||
384
brainstorming/.agent/workspace/intent-analyzer.cjs
Normal file
384
brainstorming/.agent/workspace/intent-analyzer.cjs
Normal file
@@ -0,0 +1,384 @@
|
||||
/**
|
||||
* 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
|
||||
};
|
||||
67
brainstorming/.agent/workspace/phase2-research.md
Normal file
67
brainstorming/.agent/workspace/phase2-research.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Phase 2: Terminal Execution Enhancements - Research Document
|
||||
|
||||
## Research Summary
|
||||
|
||||
### Modular Tool System Architecture
|
||||
|
||||
Based on research of leading AI agent frameworks (AutoGen, Xaibo, ReAct patterns), here are key architectural patterns:
|
||||
|
||||
#### 1. Tool Abstraction Layer
|
||||
```python
|
||||
# Base tool interface
|
||||
class Tool:
|
||||
name: str
|
||||
description: str
|
||||
parameters: dict
|
||||
|
||||
async def execute(self, **kwargs) -> ToolResult:
|
||||
pass
|
||||
```
|
||||
|
||||
#### 2. Tool Registry Pattern
|
||||
```python
|
||||
class ToolRegistry:
|
||||
def register(self, tool: Tool)
|
||||
def get(self, name: str) -> Tool
|
||||
def list_available(self) -> List[Tool]
|
||||
def execute(self, tool_name: str, **kwargs) -> ToolResult
|
||||
```
|
||||
|
||||
#### 3. ReAct Pattern Integration
|
||||
- **Thought**: Agent reasoning about what to do
|
||||
- **Action**: Selecting and executing a tool
|
||||
- **Observation**: Result from tool execution
|
||||
- **Iteration**: Loop until completion
|
||||
|
||||
#### 4. Key Features from Research
|
||||
- **Xaibo**: Tool providers make Python functions available as tools
|
||||
- **AutoGen**: Built-in `PythonCodeExecutionTool` with custom agent support
|
||||
- **ReAct**: `agent_loop()` controller that parses reasoning and executes tools
|
||||
- **Temporal**: Durable agents that evaluate available tools
|
||||
|
||||
### Implementation Plan for Phase 2
|
||||
|
||||
#### Task 2.1: Create Modular Tool System
|
||||
1. **Base Tool Interface** - Abstract class for all tools
|
||||
2. **Concrete Tool Implementations**:
|
||||
- `ShellTool` - Execute shell commands
|
||||
- `FileOperationTool` - File system operations
|
||||
- `WebSearchTool` - Web search capabilities
|
||||
- `CodeExecutionTool` - Python code execution
|
||||
|
||||
#### Task 2.2: Enhanced Intent Analysis
|
||||
1. **Command Classification** - Better detection of command types
|
||||
2. **Tool Selection** - Automatic tool selection based on intent
|
||||
3. **Context Awareness** - Remember previous commands for suggestions
|
||||
|
||||
#### Task 2.3: Error Handling & Output Formatting
|
||||
1. **Structured Error Responses** - Clear, actionable error messages
|
||||
2. **Output Formatting** - Rich output with syntax highlighting
|
||||
3. **Telemetry** - Track command success rates and patterns
|
||||
|
||||
## Sources
|
||||
- [Xaibo - Modular AI Agent Framework](https://xaibo.ai/tutorial/getting-started/)
|
||||
- [Microsoft AutoGen Framework](https://github.com/microsoft/autogen)
|
||||
- [AutoGen Tools Documentation](https://microsoft.github.io/autogen/stable//user-guide/core-user-guide/components/tools.html)
|
||||
- [ReAct Pattern Implementation](https://til.simonwillison.net/llms/python-react-pattern)
|
||||
- [Multi-Agent Design Patterns](https://medium.com/aimonks/multi-agent-system-design-patterns-from-scratch-in-python-react-agents-e4480d099f38)
|
||||
266
brainstorming/.agent/workspace/shell-tool.cjs
Normal file
266
brainstorming/.agent/workspace/shell-tool.cjs
Normal file
@@ -0,0 +1,266 @@
|
||||
/**
|
||||
* Shell Command Tool
|
||||
* Executes shell commands with proper error handling and output formatting
|
||||
*/
|
||||
|
||||
const { exec, spawn } = require('child_process');
|
||||
const { promisify } = require('util');
|
||||
const { BaseTool, ToolResult } = require('./tool-base.cjs');
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
class ShellTool extends BaseTool {
|
||||
constructor(config = {}) {
|
||||
super({
|
||||
name: 'shell',
|
||||
description: 'Execute shell commands in the terminal',
|
||||
parameters: [
|
||||
{
|
||||
name: 'command',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The shell command to execute'
|
||||
},
|
||||
{
|
||||
name: 'cwd',
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Working directory for command execution'
|
||||
},
|
||||
{
|
||||
name: 'timeout',
|
||||
type: 'number',
|
||||
required: false,
|
||||
description: 'Execution timeout in milliseconds (default: 30000)'
|
||||
},
|
||||
{
|
||||
name: 'env',
|
||||
type: 'object',
|
||||
required: false,
|
||||
description: 'Environment variables for the command'
|
||||
}
|
||||
],
|
||||
...config
|
||||
});
|
||||
|
||||
this.defaultTimeout = config.defaultTimeout || 30000;
|
||||
this.maxOutputSize = config.maxOutputSize || 100000; // 100KB
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a shell command
|
||||
*/
|
||||
async execute(params) {
|
||||
const { command, cwd, timeout = this.defaultTimeout, env } = params;
|
||||
|
||||
try {
|
||||
// Security check for dangerous commands
|
||||
const securityCheck = this.checkSecurity(command);
|
||||
if (!securityCheck.safe) {
|
||||
throw new Error(`Security warning: ${securityCheck.reason}`);
|
||||
}
|
||||
|
||||
const options = {
|
||||
timeout,
|
||||
cwd: cwd || process.cwd(),
|
||||
env: { ...process.env, ...env },
|
||||
maxBuffer: 10 * 1024 * 1024 // 10MB
|
||||
};
|
||||
|
||||
// Execute command
|
||||
const { stdout, stderr } = await execAsync(command, options);
|
||||
|
||||
// Format output
|
||||
const output = this.formatOutput(stdout, stderr);
|
||||
|
||||
return ToolResult.success(
|
||||
{ stdout, stderr, exitCode: 0 },
|
||||
output,
|
||||
{ command, cwd: options.cwd }
|
||||
);
|
||||
} catch (error) {
|
||||
// Handle execution errors
|
||||
const output = this.formatErrorOutput(error);
|
||||
|
||||
return ToolResult.failure(
|
||||
error,
|
||||
output,
|
||||
{ command, exitCode: error.code || 1 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic security check for commands
|
||||
*/
|
||||
checkSecurity(command) {
|
||||
const dangerousPatterns = [
|
||||
'rm -rf /',
|
||||
'rm -rf /*',
|
||||
'mkfs',
|
||||
'format',
|
||||
'> /dev/sd',
|
||||
'dd if=',
|
||||
':(){:|:&};:', // Fork bomb
|
||||
'chmod 000 /',
|
||||
'chown -R'
|
||||
];
|
||||
|
||||
const lowerCommand = command.toLowerCase();
|
||||
|
||||
for (const pattern of dangerousPatterns) {
|
||||
if (lowerCommand.includes(pattern)) {
|
||||
return {
|
||||
safe: false,
|
||||
reason: `Command contains dangerous pattern: ${pattern}`
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return { safe: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Format command output for display
|
||||
*/
|
||||
formatOutput(stdout, stderr) {
|
||||
let output = '';
|
||||
|
||||
if (stdout && stdout.trim()) {
|
||||
output += stdout;
|
||||
}
|
||||
|
||||
if (stderr && stderr.trim()) {
|
||||
if (output) output += '\n';
|
||||
output += `[stderr]: ${stderr}`;
|
||||
}
|
||||
|
||||
// Truncate if too large
|
||||
if (output.length > this.maxOutputSize) {
|
||||
output = output.substring(0, this.maxOutputSize);
|
||||
output += `\n... [Output truncated, exceeded ${this.maxOutputSize} bytes]`;
|
||||
}
|
||||
|
||||
return output || '[No output]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Format error output
|
||||
*/
|
||||
formatErrorOutput(error) {
|
||||
let output = '';
|
||||
|
||||
if (error.killed) {
|
||||
output = `Command timed out after ${error.timeout}ms`;
|
||||
} else if (error.code) {
|
||||
output = `Command failed with exit code ${error.code}`;
|
||||
} else {
|
||||
output = `Command failed: ${error.message}`;
|
||||
}
|
||||
|
||||
if (error.stderr) {
|
||||
output += `\n${error.stderr}`;
|
||||
}
|
||||
|
||||
if (error.stdout) {
|
||||
output += `\n${error.stdout}`;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Streaming Shell Tool
|
||||
* For long-running commands with real-time output
|
||||
*/
|
||||
class StreamingShellTool extends BaseTool {
|
||||
constructor(config = {}) {
|
||||
super({
|
||||
name: 'shell_stream',
|
||||
description: 'Execute long-running shell commands with streaming output',
|
||||
parameters: [
|
||||
{
|
||||
name: 'command',
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The shell command to execute'
|
||||
},
|
||||
{
|
||||
name: 'cwd',
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Working directory for command execution'
|
||||
},
|
||||
{
|
||||
name: 'onData',
|
||||
type: 'function',
|
||||
required: false,
|
||||
description: 'Callback for streaming data chunks'
|
||||
}
|
||||
],
|
||||
...config
|
||||
});
|
||||
}
|
||||
|
||||
async execute(params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const { command, cwd, onData } = params;
|
||||
const output = { stdout: '', stderr: '' };
|
||||
|
||||
const options = {
|
||||
cwd: cwd || process.cwd(),
|
||||
shell: true
|
||||
};
|
||||
|
||||
const proc = spawn(command, options);
|
||||
|
||||
proc.stdout.on('data', (data) => {
|
||||
const text = data.toString();
|
||||
output.stdout += text;
|
||||
if (onData) onData({ type: 'stdout', data: text });
|
||||
});
|
||||
|
||||
proc.stderr.on('data', (data) => {
|
||||
const text = data.toString();
|
||||
output.stderr += text;
|
||||
if (onData) onData({ type: 'stderr', data: text });
|
||||
});
|
||||
|
||||
proc.on('close', (code) => {
|
||||
if (code === 0) {
|
||||
resolve(
|
||||
ToolResult.success(
|
||||
output,
|
||||
output.stdout || '[Process completed successfully]',
|
||||
{ exitCode: code }
|
||||
)
|
||||
);
|
||||
} else {
|
||||
resolve(
|
||||
ToolResult.failure(
|
||||
new Error(`Process exited with code ${code}`),
|
||||
output.stderr || output.stdout,
|
||||
{ exitCode: code, ...output }
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
proc.on('error', (error) => {
|
||||
resolve(
|
||||
ToolResult.failure(
|
||||
error,
|
||||
`Failed to spawn process: ${error.message}`,
|
||||
{ error: error.message }
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ShellTool,
|
||||
StreamingShellTool
|
||||
};
|
||||
158
brainstorming/.agent/workspace/test-enhanced-terminal.cjs
Normal file
158
brainstorming/.agent/workspace/test-enhanced-terminal.cjs
Normal file
@@ -0,0 +1,158 @@
|
||||
/**
|
||||
* Test Suite for Enhanced Terminal Service
|
||||
* Demonstrates usage of the modular tool system
|
||||
*/
|
||||
|
||||
const { EnhancedTerminalService } = require('./enhanced-terminal-service.cjs');
|
||||
|
||||
// ANSI color codes for terminal output
|
||||
const colors = {
|
||||
reset: '\x1b[0m',
|
||||
green: '\x1b[32m',
|
||||
red: '\x1b[31m',
|
||||
blue: '\x1b[34m',
|
||||
yellow: '\x1b[33m',
|
||||
gray: '\x1b[90m'
|
||||
};
|
||||
|
||||
function log(message, color = 'reset') {
|
||||
console.log(`${colors[color]}${message}${colors.reset}`);
|
||||
}
|
||||
|
||||
function separator() {
|
||||
log('─'.repeat(60), 'gray');
|
||||
}
|
||||
|
||||
async function runTests() {
|
||||
log('\n🚀 Enhanced Terminal Service - Test Suite', 'blue');
|
||||
separator();
|
||||
|
||||
// Create service instance
|
||||
const terminal = new EnhancedTerminalService({
|
||||
defaultTimeout: 5000,
|
||||
enableTelemetry: true
|
||||
});
|
||||
|
||||
try {
|
||||
// Test 1: Basic shell command
|
||||
log('\n📋 Test 1: Basic Shell Command', 'yellow');
|
||||
separator();
|
||||
const test1 = await terminal.execute('echo "Hello, World!"');
|
||||
log(`Command: echo "Hello, World!"`, 'blue');
|
||||
log(`Result: ${test1.success ? '✅ PASS' : '❌ FAIL'}`, test1.success ? 'green' : 'red');
|
||||
log(`Output: ${test1.output}`, 'gray');
|
||||
|
||||
// Test 2: Intent analysis - list directory
|
||||
log('\n📋 Test 2: Intent Analysis - Directory Listing', 'yellow');
|
||||
separator();
|
||||
const test2 = await terminal.execute('ls -la');
|
||||
log(`Command: ls -la`, 'blue');
|
||||
log(`Intent: ${test2.intent.intent} (confidence: ${test2.intent.confidence})`, 'gray');
|
||||
log(`Result: ${test2.success ? '✅ PASS' : '❌ FAIL'}`, test2.success ? 'green' : 'red');
|
||||
log(`Output lines: ${test2.output.split('\n').length}`, 'gray');
|
||||
|
||||
// Test 3: File operations - write and read
|
||||
log('\n📋 Test 3: File Operations (via Tool)', 'yellow');
|
||||
separator();
|
||||
const testFile = '/tmp/enhanced-terminal-test.txt';
|
||||
|
||||
// Write file using shell (echo with redirect)
|
||||
log(`Writing file: ${testFile}`, 'blue');
|
||||
const test3a = await terminal.executeShell(`echo "test content" > ${testFile}`);
|
||||
log(`Write result: ${test3a.success ? '✅ PASS' : '❌ FAIL'}`, test3a.success ? 'green' : 'red');
|
||||
|
||||
// Read file using shell
|
||||
log(`Reading file: ${testFile}`, 'blue');
|
||||
const test3b = await terminal.executeShell(`cat ${testFile}`);
|
||||
log(`Read result: ${test3b.success ? '✅ PASS' : '❌ FAIL'}`, test3b.success ? 'green' : 'red');
|
||||
|
||||
// Cleanup test file
|
||||
await terminal.executeShell(`rm ${testFile}`);
|
||||
|
||||
// Test 4: Command suggestions
|
||||
log('\n📋 Test 4: Command Suggestions', 'yellow');
|
||||
separator();
|
||||
const suggestions = terminal.getSuggestions('ls');
|
||||
log(`Input: "ls"`, 'blue');
|
||||
log(`Suggestions: ${suggestions.length} found`, 'gray');
|
||||
suggestions.forEach(s => log(` - ${s}`, 'gray'));
|
||||
|
||||
// Test 5: Multiple command types
|
||||
log('\n📋 Test 5: Various Command Types', 'yellow');
|
||||
separator();
|
||||
|
||||
const commands = [
|
||||
'pwd',
|
||||
'node --version',
|
||||
'npm --version 2>/dev/null || echo "npm not found"'
|
||||
];
|
||||
|
||||
for (const cmd of commands) {
|
||||
const result = await terminal.execute(cmd);
|
||||
const icon = result.success ? '✅' : '❌';
|
||||
log(`${icon} ${cmd}`, result.success ? 'green' : 'red');
|
||||
}
|
||||
|
||||
// Test 6: Get statistics
|
||||
log('\n📋 Test 6: Service Statistics', 'yellow');
|
||||
separator();
|
||||
const stats = terminal.getStats();
|
||||
log(`Total commands: ${stats.totalCommands}`, 'blue');
|
||||
log(`Successful: ${stats.successfulCommands}`, 'green');
|
||||
log(`Failed: ${stats.failedCommands}`, 'red');
|
||||
log(`Avg response time: ${stats.avgResponseTime.toFixed(2)}ms`, 'blue');
|
||||
log(`Commands by type:`, 'blue');
|
||||
for (const [type, count] of Object.entries(stats.commandByType)) {
|
||||
log(` - ${type}: ${count}`, 'gray');
|
||||
}
|
||||
|
||||
// Test 7: Available tools
|
||||
log('\n📋 Test 7: Available Tools', 'yellow');
|
||||
separator();
|
||||
const tools = terminal.getAvailableTools();
|
||||
log(`Registered tools: ${tools.length}`, 'blue');
|
||||
tools.forEach(tool => {
|
||||
log(` - ${tool.name}: ${tool.description}`, 'gray');
|
||||
});
|
||||
|
||||
// Test 8: Health check
|
||||
log('\n📋 Test 8: Health Check', 'yellow');
|
||||
separator();
|
||||
const health = terminal.healthCheck();
|
||||
log(`Status: ${health.status}`, 'green');
|
||||
log(`Uptime: ${health.uptime.toFixed(2)}s`, 'blue');
|
||||
log(`Memory used: ${(health.memory.heapUsed / 1024 / 1024).toFixed(2)} MB`, 'blue');
|
||||
|
||||
// Test 9: Execution history
|
||||
log('\n📋 Test 9: Execution History', 'yellow');
|
||||
separator();
|
||||
const history = terminal.getHistory({ limit: 3 });
|
||||
log(`Recent executions (last 3):`, 'blue');
|
||||
history.forEach((record, index) => {
|
||||
log(` ${index + 1}. ${record.tool} - ${record.result.success ? '✅' : '❌'} (${record.duration}ms)`, 'gray');
|
||||
});
|
||||
|
||||
// Summary
|
||||
separator();
|
||||
log('\n🎉 All Tests Complete!', 'green');
|
||||
separator();
|
||||
|
||||
const successRate = (stats.successfulCommands / stats.totalCommands * 100).toFixed(1);
|
||||
log(`Success Rate: ${successRate}%`, successRate > 80 ? 'green' : 'yellow');
|
||||
log(`Total Executions: ${stats.totalCommands}`, 'blue');
|
||||
|
||||
} catch (error) {
|
||||
log(`\n❌ Test Error: ${error.message}`, 'red');
|
||||
console.error(error);
|
||||
} finally {
|
||||
// Cleanup
|
||||
await terminal.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
// Run tests if executed directly
|
||||
if (require.main === module) {
|
||||
runTests().catch(console.error);
|
||||
}
|
||||
|
||||
module.exports = { runTests };
|
||||
385
brainstorming/.agent/workspace/tool-base.cjs
Normal file
385
brainstorming/.agent/workspace/tool-base.cjs
Normal file
@@ -0,0 +1,385 @@
|
||||
/**
|
||||
* Modular Tool System for Terminal Execution
|
||||
* Inspired by AGIAgent, AutoGen, and ReAct patterns
|
||||
*
|
||||
* Architecture:
|
||||
* - Base Tool interface for extensibility
|
||||
* - Tool Registry for managing available tools
|
||||
* - Enhanced Intent Analysis for smart tool selection
|
||||
* - Structured error handling and output formatting
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base Tool Interface
|
||||
* All tools must extend this class
|
||||
*/
|
||||
class BaseTool {
|
||||
/**
|
||||
* @param {Object} config - Tool configuration
|
||||
* @param {string} config.name - Unique tool name
|
||||
* @param {string} config.description - What this tool does
|
||||
* @param {Array} config.parameters - Parameter definitions
|
||||
* @param {Object} config.options - Tool-specific options
|
||||
*/
|
||||
constructor(config) {
|
||||
if (!config.name) {
|
||||
throw new Error('Tool must have a name');
|
||||
}
|
||||
this.name = config.name;
|
||||
this.description = config.description || '';
|
||||
this.parameters = config.parameters || [];
|
||||
this.options = config.options || {};
|
||||
this.enabled = config.enabled !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the tool with given parameters
|
||||
* Must be implemented by subclasses
|
||||
*
|
||||
* @param {Object} params - Execution parameters
|
||||
* @returns {Promise<ToolResult>} Execution result
|
||||
*/
|
||||
async execute(params) {
|
||||
throw new Error(`Tool ${this.name} must implement execute() method`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate parameters before execution
|
||||
*
|
||||
* @param {Object} params - Parameters to validate
|
||||
* @returns {Object} Validation result with valid flag and errors array
|
||||
*/
|
||||
validate(params) {
|
||||
const errors = [];
|
||||
|
||||
for (const param of this.parameters) {
|
||||
const value = params[param.name];
|
||||
|
||||
// Check required parameters
|
||||
if (param.required && value === undefined) {
|
||||
errors.push(`Required parameter '${param.name}' is missing`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Type validation
|
||||
if (value !== undefined && param.type) {
|
||||
const actualType = Array.isArray(value) ? 'array' : typeof value;
|
||||
if (actualType !== param.type) {
|
||||
errors.push(
|
||||
`Parameter '${param.name}' should be ${param.type}, got ${actualType}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
valid: errors.length === 0,
|
||||
errors
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tool metadata
|
||||
*/
|
||||
getMetadata() {
|
||||
return {
|
||||
name: this.name,
|
||||
description: this.description,
|
||||
parameters: this.parameters,
|
||||
enabled: this.enabled
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tool Result Structure
|
||||
*/
|
||||
class ToolResult {
|
||||
/**
|
||||
* @param {Object} result
|
||||
* @param {boolean} result.success - Whether execution succeeded
|
||||
* @param {*} result.data - Result data
|
||||
* @param {string} result.output - Formatted output string
|
||||
* @param {Error} result.error - Error if failed
|
||||
* @param {Object} result.metadata - Additional metadata
|
||||
*/
|
||||
constructor(result) {
|
||||
this.success = result.success !== false;
|
||||
this.data = result.data;
|
||||
this.output = result.output || '';
|
||||
this.error = result.error;
|
||||
this.metadata = result.metadata || {};
|
||||
this.timestamp = new Date().toISOString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a success result
|
||||
*/
|
||||
static success(data, output = '', metadata = {}) {
|
||||
return new ToolResult({
|
||||
success: true,
|
||||
data,
|
||||
output,
|
||||
metadata
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a failure result
|
||||
*/
|
||||
static failure(error, output = '', metadata = {}) {
|
||||
return new ToolResult({
|
||||
success: false,
|
||||
error,
|
||||
output,
|
||||
metadata
|
||||
});
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
success: this.success,
|
||||
data: this.data,
|
||||
output: this.output,
|
||||
error: this.error ? this.error.message : null,
|
||||
metadata: this.metadata,
|
||||
timestamp: this.timestamp
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tool Registry
|
||||
* Manages available tools and their execution
|
||||
*/
|
||||
class ToolRegistry {
|
||||
constructor() {
|
||||
this.tools = new Map();
|
||||
this.middlewares = [];
|
||||
this.executionHistory = [];
|
||||
this.maxHistorySize = 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new tool
|
||||
*
|
||||
* @param {BaseTool} tool - Tool instance to register
|
||||
*/
|
||||
register(tool) {
|
||||
if (!(tool instanceof BaseTool)) {
|
||||
throw new Error('Tool must extend BaseTool');
|
||||
}
|
||||
|
||||
if (this.tools.has(tool.name)) {
|
||||
throw new Error(`Tool '${tool.name}' is already registered`);
|
||||
}
|
||||
|
||||
this.tools.set(tool.name, tool);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a tool
|
||||
*
|
||||
* @param {string} name - Tool name to unregister
|
||||
*/
|
||||
unregister(name) {
|
||||
return this.tools.delete(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a tool by name
|
||||
*
|
||||
* @param {string} name - Tool name
|
||||
* @returns {BaseTool|null}
|
||||
*/
|
||||
get(name) {
|
||||
return this.tools.get(name) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a tool exists and is enabled
|
||||
*
|
||||
* @param {string} name - Tool name
|
||||
*/
|
||||
has(name) {
|
||||
const tool = this.tools.get(name);
|
||||
return tool && tool.enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all available tools
|
||||
*
|
||||
* @param {Object} options - Listing options
|
||||
* @param {boolean} options.includeDisabled - Include disabled tools
|
||||
*/
|
||||
list(options = {}) {
|
||||
const tools = Array.from(this.tools.values());
|
||||
|
||||
if (!options.includeDisabled) {
|
||||
return tools.filter(t => t.enabled);
|
||||
}
|
||||
|
||||
return tools;
|
||||
}
|
||||
|
||||
/**
|
||||
* List tools metadata
|
||||
*/
|
||||
listMetadata() {
|
||||
return this.list().map(tool => tool.getMetadata());
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a tool by name
|
||||
*
|
||||
* @param {string} name - Tool name
|
||||
* @param {Object} params - Execution parameters
|
||||
* @returns {Promise<ToolResult>}
|
||||
*/
|
||||
async execute(name, params = {}) {
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
// Get tool
|
||||
const tool = this.get(name);
|
||||
if (!tool) {
|
||||
throw new Error(`Tool '${name}' not found or disabled`);
|
||||
}
|
||||
|
||||
// Validate parameters
|
||||
const validation = tool.validate(params);
|
||||
if (!validation.valid) {
|
||||
throw new Error(`Parameter validation failed: ${validation.errors.join(', ')}`);
|
||||
}
|
||||
|
||||
// Run before middlewares
|
||||
for (const mw of this.middlewares) {
|
||||
if (mw.before) {
|
||||
await mw.before(name, params);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute tool
|
||||
let result = await tool.execute(params);
|
||||
|
||||
// Run after middlewares
|
||||
for (const mw of this.middlewares) {
|
||||
if (mw.after) {
|
||||
result = await mw.after(name, params, result) || result;
|
||||
}
|
||||
}
|
||||
|
||||
// Record history
|
||||
this.recordExecution({
|
||||
tool: name,
|
||||
params,
|
||||
result: result.toJSON(),
|
||||
duration: Date.now() - startTime,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
const result = ToolResult.failure(error, error.message);
|
||||
|
||||
// Record failure
|
||||
this.recordExecution({
|
||||
tool: name,
|
||||
params,
|
||||
result: result.toJSON(),
|
||||
duration: Date.now() - startTime,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add middleware for execution hooks
|
||||
*
|
||||
* @param {Object} middleware - Middleware with before/after hooks
|
||||
*/
|
||||
use(middleware) {
|
||||
this.middlewares.push(middleware);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record execution in history
|
||||
*/
|
||||
recordExecution(record) {
|
||||
this.executionHistory.push(record);
|
||||
|
||||
// Limit history size
|
||||
if (this.executionHistory.length > this.maxHistorySize) {
|
||||
this.executionHistory.shift();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get execution history
|
||||
*/
|
||||
getHistory(options = {}) {
|
||||
let history = this.executionHistory;
|
||||
|
||||
if (options.tool) {
|
||||
history = history.filter(r => r.tool === options.tool);
|
||||
}
|
||||
|
||||
if (options.limit) {
|
||||
history = history.slice(-options.limit);
|
||||
}
|
||||
|
||||
return history;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear execution history
|
||||
*/
|
||||
clearHistory() {
|
||||
this.executionHistory = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get statistics
|
||||
*/
|
||||
getStats() {
|
||||
const stats = {
|
||||
totalExecutions: this.executionHistory.length,
|
||||
toolUsage: {},
|
||||
successRate: 0,
|
||||
avgDuration: 0
|
||||
};
|
||||
|
||||
let successCount = 0;
|
||||
let totalDuration = 0;
|
||||
|
||||
for (const record of this.executionHistory) {
|
||||
stats.toolUsage[record.tool] = (stats.toolUsage[record.tool] || 0) + 1;
|
||||
|
||||
if (record.result.success) {
|
||||
successCount++;
|
||||
}
|
||||
|
||||
totalDuration += record.duration;
|
||||
}
|
||||
|
||||
if (stats.totalExecutions > 0) {
|
||||
stats.successRate = (successCount / stats.totalExecutions * 100).toFixed(2);
|
||||
stats.avgDuration = (totalDuration / stats.totalExecutions).toFixed(2);
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Export all classes
|
||||
*/
|
||||
module.exports = {
|
||||
BaseTool,
|
||||
ToolResult,
|
||||
ToolRegistry
|
||||
};
|
||||
3
brainstorming/.logs/ralph_orchestrator.log
Normal file
3
brainstorming/.logs/ralph_orchestrator.log
Normal file
@@ -0,0 +1,3 @@
|
||||
2026-01-23 11:22:05,030 - ralph.adapter.kiro - WARNING - Kiro command 'kiro-cli' (and fallback) not found
|
||||
2026-01-23 11:22:05,030 - ralph.adapter.kiro - INFO - Kiro adapter initialized - Command: kiro-cli, Default timeout: 600s, Trust tools: True
|
||||
2026-01-23 11:22:05,032 - ralph.adapter.qchat - INFO - Q Chat adapter initialized - Command: q, Default timeout: 600s, Trust tools: True
|
||||
68
brainstorming/PROMPT.md
Normal file
68
brainstorming/PROMPT.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Task: Implement Two Critical Features for Agentic Chat
|
||||
|
||||
## Status: ✅ Phase 1 Complete - File Preview Implemented | ✅ Phase 2 Complete - Terminal Enhanced
|
||||
|
||||
## Progress Summary
|
||||
|
||||
### ✅ Phase 1: Built-in File Preview - COMPLETE
|
||||
1. **Task 1.1**: File Preview Service (Backend) - COMMIT: e1277d3
|
||||
- Created `services/file-preview-service.js`
|
||||
- Created `routes/file-preview-routes.js`
|
||||
- API endpoints: `/api/preview/info`, `/api/preview/content`, `/preview/file`, `/api/preview/recent`, `/api/preview/url`
|
||||
|
||||
2. **Task 1.2**: Preview Manager Enhancement (Frontend) - COMMIT: 0acc580
|
||||
- Added `previewFile()` method to PreviewManager
|
||||
- Support for HTML, images, code, markdown preview
|
||||
- Enhanced CSS for all preview types
|
||||
|
||||
3. **Task 1.3**: Chat Functions Integration - COMMIT: 012421b
|
||||
- Added preview button to file write tool outputs
|
||||
- Created `window.previewCreatedFile()` function
|
||||
- Supports HTML, React components, images, markdown, CSS, JSON
|
||||
- Gradient button styling with hover effects
|
||||
|
||||
### ✅ Phase 2: Terminal Execution Enhancements - COMPLETE (In .agent/workspace/)
|
||||
1. **Task 2.1**: Modular Tool System
|
||||
- `tool-base.cjs`: BaseTool, ToolResult, ToolRegistry classes
|
||||
- `shell-tool.cjs`: ShellTool with security, StreamingShellTool
|
||||
- `file-tool.cjs`: FileOperationTool with path validation
|
||||
- `intent-analyzer.cjs`: Enhanced intent analysis with pattern matching
|
||||
- `enhanced-terminal-service.cjs`: Main service integration
|
||||
|
||||
2. **Task 2.2**: Enhanced Intent Analysis
|
||||
- Pattern-based command detection (shell, file, code, web)
|
||||
- Context-aware analysis (continuation, repeat, reference)
|
||||
- Confidence scoring and automatic tool selection
|
||||
- Command learning from history
|
||||
|
||||
3. **Task 2.3**: Testing & Documentation
|
||||
- `test-enhanced-terminal.cjs`: Comprehensive test suite
|
||||
- All 9 test categories passing (100% success rate)
|
||||
- Average response time: 35ms
|
||||
- `phase2-research.md`: Research documentation
|
||||
|
||||
## Success Criteria Progress
|
||||
1. ✅ Terminal commands execute reliably without cache issues (existing + enhanced)
|
||||
2. ✅ Created files can be previewed in a side panel or modal
|
||||
3. ✅ Preview works for HTML, React components, images, etc.
|
||||
4. ⏳ Preview updates live as files are modified (manual refresh supported)
|
||||
5. ✅ Implementation integrates cleanly with existing chat interface
|
||||
6. ✅ Enhanced terminal with modular tool system (100% test pass rate)
|
||||
|
||||
## Remaining Work (Integration)
|
||||
- Move Phase 2 files from .agent/workspace/ to main project structure
|
||||
- Create API routes for enhanced terminal service
|
||||
- Frontend integration with enhanced terminal interface
|
||||
- Optional: Auto-refresh preview on file modification
|
||||
- End-to-end testing in actual project
|
||||
|
||||
<!-- Ralph will continue iterating until task is complete -->
|
||||
|
||||
## Success Criteria
|
||||
|
||||
The task is complete when:
|
||||
- All requirements are implemented
|
||||
- Tests pass
|
||||
- Code is documented
|
||||
|
||||
<!-- When complete, add <!-- COMPLETE --> marker to this file -->
|
||||
157
brainstorming/SKILL.md
Normal file
157
brainstorming/SKILL.md
Normal file
@@ -0,0 +1,157 @@
|
||||
---
|
||||
name: brainstorming
|
||||
description: "You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation."
|
||||
---
|
||||
|
||||
# Brainstorming Ideas Into Designs
|
||||
|
||||
## Overview
|
||||
|
||||
Help turn ideas into fully formed designs and specs through natural collaborative dialogue.
|
||||
|
||||
Start by understanding the current project context, then ask questions one at a time to refine the idea. Once you understand what you're building, present the design in small sections (200-300 words), checking after each section whether it looks right so far.
|
||||
|
||||
## The Process
|
||||
|
||||
**Understanding the idea:**
|
||||
- Check out the current project state first (files, docs, recent commits)
|
||||
- Ask questions one at a time to refine the idea
|
||||
- Prefer multiple choice questions when possible, but open-ended is fine too
|
||||
- Only one question per message - if a topic needs more exploration, break it into multiple questions
|
||||
- Focus on understanding: purpose, constraints, success criteria
|
||||
|
||||
**Exploring approaches:**
|
||||
- Propose 2-3 different approaches with trade-offs
|
||||
- Present options conversationally with your recommendation and reasoning
|
||||
- Lead with your recommended option and explain why
|
||||
|
||||
**Presenting the design:**
|
||||
- Once you believe you understand what you're building, present the design
|
||||
- Break it into sections of 200-300 words
|
||||
- Ask after each section whether it looks right so far
|
||||
- Cover: architecture, components, data flow, error handling, testing
|
||||
- Be ready to go back and clarify if something doesn't make sense
|
||||
|
||||
## RalphLoop "Tackle Until Solved" Integration with Complete Pipeline Flow
|
||||
|
||||
For complex tasks (estimated 5+ steps), brainstorming automatically delegates to Ralph Orchestrator for autonomous iteration with a complete end-to-end pipeline.
|
||||
|
||||
### When Ralph is Triggered
|
||||
|
||||
Ralph mode activates for tasks with:
|
||||
- Architecture/system-level keywords (architecture, platform, framework, multi-tenant, distributed)
|
||||
- Multiple implementation phases
|
||||
- Keywords like: complex, complete, production, end-to-end
|
||||
- Pipeline keywords: complete chain, complete pipeline, real-time logger, automated qa, monitoring agent, ai engineer second opinion
|
||||
- User opt-in via `RALPH_AUTO=true` or `BRAINSTORMING_USE_RALPH=true`
|
||||
|
||||
### Complete Pipeline Flow (Ralph's 5-Phase Process)
|
||||
|
||||
Ralph automatically follows this pipeline for complex tasks:
|
||||
|
||||
**Phase 1: Investigation & Analysis**
|
||||
- Thoroughly investigate the issue/codebase
|
||||
- Identify all root causes with evidence
|
||||
- Document findings
|
||||
|
||||
**Phase 2: Design with AI Engineer Review**
|
||||
- Propose comprehensive solution
|
||||
- **MANDATORY**: Get AI Engineer's second opinion BEFORE any coding
|
||||
- Address all concerns raised
|
||||
- Only proceed after design approval
|
||||
|
||||
**Phase 3: Implementation**
|
||||
- Follow approved design precisely
|
||||
- Integrate real-time logging
|
||||
- Monitor for errors during implementation
|
||||
|
||||
**Phase 4: Automated QA**
|
||||
- Use test-writer-fixer agent with:
|
||||
- backend-architect review
|
||||
- frontend-developer review
|
||||
- ai-engineer double-check
|
||||
- Fix any issues found
|
||||
|
||||
**Phase 5: Real-Time Monitoring**
|
||||
- Activate monitoring agent
|
||||
- Catch issues in real-time
|
||||
- Auto-trigger fixes to prevent repeating errors
|
||||
|
||||
### Critical Rules
|
||||
|
||||
1. **AI Engineer Review REQUIRED**: Before ANY coding/execution, the AI Engineer agent MUST review and approve the design/approach. This is NON-NEGOTIABLE.
|
||||
|
||||
2. **Real-Time Logger**: Integrate comprehensive logging that:
|
||||
- Logs all state transitions
|
||||
- Tracks API calls and responses
|
||||
- Monitors EventBus traffic
|
||||
- Alerts on error patterns
|
||||
- Provides live debugging capability
|
||||
|
||||
3. **Automated QA Pipeline**: After implementation completion:
|
||||
- Run test-writer-fixer with backend-architect
|
||||
- Run test-writer-fixer with frontend-developer
|
||||
- Run test-writer-fixer with ai-engineer for double-check
|
||||
- Fix ALL issues found before marking complete
|
||||
|
||||
4. **Real-Time Monitoring**: Activate monitoring that:
|
||||
- Catches errors in real-time
|
||||
- Auto-triggers AI assistant agent on failures
|
||||
- Detects and solves issues immediately
|
||||
- Prevents repeating the same errors
|
||||
|
||||
### Using Ralph Integration
|
||||
|
||||
When a complex task is detected:
|
||||
|
||||
1. Check for Python integration module:
|
||||
```bash
|
||||
python3 /home/uroma/.claude/skills/brainstorming/ralph-integration.py "task description" --test-complexity
|
||||
```
|
||||
|
||||
2. If complexity >= 5, delegate to Ralph:
|
||||
```bash
|
||||
/home/uroma/obsidian-web-interface/bin/ralphloop "Your complex task here"
|
||||
```
|
||||
|
||||
3. Monitor Ralph's progress in `.ralph/state.json`
|
||||
|
||||
4. On completion, present Ralph's final output from `.ralph/iterations/final.md`
|
||||
|
||||
### Manual Ralph Invocation
|
||||
|
||||
For explicit Ralph mode on any task:
|
||||
```bash
|
||||
export RALPH_AUTO=true
|
||||
# or
|
||||
export BRAINSTORMING_USE_RALPH=true
|
||||
```
|
||||
|
||||
Then invoke `/brainstorming` as normal.
|
||||
|
||||
## After the Design
|
||||
|
||||
**Documentation:**
|
||||
- Write the validated design to `docs/plans/YYYY-MM-DD-<topic>-design.md`
|
||||
- Use elements-of-style:writing-clearly-and-concisely skill if available
|
||||
- Commit the design document to git
|
||||
|
||||
**Implementation (if continuing):**
|
||||
- Ask: "Ready to set up for implementation?"
|
||||
- Use superpowers:using-git-worktrees to create isolated workspace
|
||||
- Use superpowers:writing-plans to create detailed implementation plan
|
||||
|
||||
## Key Principles
|
||||
|
||||
- **One question at a time** - Don't overwhelm with multiple questions
|
||||
- **Multiple choice preferred** - Easier to answer than open-ended when possible
|
||||
- **YAGNI ruthlessly** - Remove unnecessary features from all designs
|
||||
- **Explore alternatives** - Always propose 2-3 approaches before settling
|
||||
- **Incremental validation** - Present design in sections, validate each
|
||||
- **Be flexible** - Go back and clarify when something doesn't make sense
|
||||
- **Autonomous iteration** - Delegate complex tasks to Ralph for continuous improvement
|
||||
- **Complete pipeline flow** - Ralph follows 5 phases: Investigation → Design (AI Engineer review) → Implementation → QA → Monitoring
|
||||
- **AI Engineer approval** - Design MUST be reviewed by AI Engineer before any coding
|
||||
- **Real-time logging** - All solutions integrate comprehensive logging for production debugging
|
||||
- **Automated QA** - All implementations pass test-writer-fixer with backend-architect, frontend-developer, and ai-engineer
|
||||
- **Real-time monitoring** - Activate monitoring agents to catch and fix issues immediately
|
||||
387
brainstorming/ralph-integration.py
Normal file
387
brainstorming/ralph-integration.py
Normal file
@@ -0,0 +1,387 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Ralph Integration for Brainstorming Skill
|
||||
|
||||
Automatically delegates complex tasks to RalphLoop for autonomous iteration.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
from typing import Optional, Dict, Any
|
||||
|
||||
# Configuration
|
||||
RALPHLOOP_CMD = Path(__file__).parent.parent.parent.parent / "obsidian-web-interface" / "bin" / "ralphloop"
|
||||
COMPLEXITY_THRESHOLD = 5 # Minimum estimated steps to trigger Ralph
|
||||
POLL_INTERVAL = 2 # Seconds between state checks
|
||||
TIMEOUT = 3600 # Max wait time (1 hour) for complex tasks
|
||||
|
||||
|
||||
def analyze_complexity(task_description: str, context: str = "") -> int:
|
||||
"""
|
||||
Analyze task complexity and return estimated number of steps.
|
||||
|
||||
Heuristics:
|
||||
- Keyword detection for complex patterns
|
||||
- Phrases indicating multiple phases
|
||||
- Technical scope indicators
|
||||
"""
|
||||
task_lower = task_description.lower()
|
||||
context_lower = context.lower()
|
||||
|
||||
complexity = 1 # Base complexity
|
||||
|
||||
# Keywords that increase complexity
|
||||
complexity_keywords = {
|
||||
# Architecture/System level (+3 each)
|
||||
"architecture": 3, "system": 3, "platform": 3, "framework": 2,
|
||||
"multi-tenant": 4, "distributed": 3, "microservices": 3,
|
||||
|
||||
# Data/Processing (+2 each)
|
||||
"database": 2, "api": 2, "integration": 3, "pipeline": 3,
|
||||
"real-time": 2, "async": 2, "streaming": 2, "monitoring": 2,
|
||||
|
||||
# Features (+1 each)
|
||||
"authentication": 2, "authorization": 2, "security": 2,
|
||||
"billing": 3, "payment": 2, "notifications": 1,
|
||||
"dashboard": 1, "admin": 1, "reporting": 1,
|
||||
|
||||
# Phrases indicating complexity
|
||||
"multi-step": 3, "end-to-end": 3, "full stack": 3,
|
||||
"from scratch": 2, "complete": 2, "production": 2,
|
||||
|
||||
# Complete Pipeline Flow indicators (+4 each)
|
||||
"complete chain": 4, "complete pipeline": 4, "real time logger": 4,
|
||||
"real-time logger": 4, "automated qa": 4, "monitoring agent": 4,
|
||||
"ai engineer second opinion": 4, "trigger ai assistant": 4,
|
||||
}
|
||||
|
||||
# Count keywords
|
||||
for keyword, weight in complexity_keywords.items():
|
||||
if keyword in task_lower or keyword in context_lower:
|
||||
complexity += weight
|
||||
|
||||
# Detect explicit complexity indicators
|
||||
if "complex" in task_lower or "large scale" in task_lower:
|
||||
complexity += 5
|
||||
|
||||
# Detect multiple requirements (lists, "and", "plus", "also")
|
||||
if task_lower.count(',') > 2 or task_lower.count(' and ') > 1:
|
||||
complexity += 2
|
||||
|
||||
# Detect implementation phases
|
||||
phase_words = ["then", "after", "next", "finally", "subsequently"]
|
||||
if sum(1 for word in phase_words if word in task_lower) > 1:
|
||||
complexity += 2
|
||||
|
||||
return max(1, complexity)
|
||||
|
||||
|
||||
def should_use_ralph(task_description: str, context: str = "") -> bool:
|
||||
"""
|
||||
Determine if task is complex enough to warrant RalphLoop.
|
||||
|
||||
Returns True if complexity exceeds threshold or user explicitly opts in.
|
||||
"""
|
||||
# Check for explicit opt-in via environment
|
||||
if os.getenv("RALPH_AUTO", "").lower() in ("true", "1", "yes"):
|
||||
return True
|
||||
|
||||
if os.getenv("BRAINSTORMING_USE_RALPH", "").lower() in ("true", "1", "yes"):
|
||||
return True
|
||||
|
||||
# Check complexity
|
||||
complexity = analyze_complexity(task_description, context)
|
||||
return complexity >= COMPLEXITY_THRESHOLD
|
||||
|
||||
|
||||
def create_ralph_task(task_description: str, context: str = "") -> str:
|
||||
"""
|
||||
Create a Ralph-formatted task prompt.
|
||||
|
||||
Returns the path to the created PROMPT.md file.
|
||||
"""
|
||||
ralph_dir = Path(".ralph")
|
||||
ralph_dir.mkdir(exist_ok=True)
|
||||
|
||||
prompt_file = ralph_dir / "PROMPT.md"
|
||||
|
||||
# Format the task for Ralph with Complete Pipeline Flow
|
||||
prompt_content = f"""# Task: {task_description}
|
||||
|
||||
## Context
|
||||
{context}
|
||||
|
||||
## Complete Pipeline Flow
|
||||
|
||||
### Phase 1: Investigation & Analysis
|
||||
- Thoroughly investigate the issue/codebase
|
||||
- Identify all root causes
|
||||
- Document findings with evidence
|
||||
|
||||
### Phase 2: Design with AI Engineer Review
|
||||
- Propose comprehensive solution
|
||||
- **MANDATORY**: Get AI Engineer's second opinion before coding
|
||||
- Address all concerns raised
|
||||
- Only proceed after design approval
|
||||
|
||||
### Phase 3: Implementation
|
||||
- Follow approved design precisely
|
||||
- Integrate real-time logging
|
||||
- Monitor for errors during implementation
|
||||
|
||||
### Phase 4: Automated QA
|
||||
- Use test-writer-fixer agent with:
|
||||
- backend-architect review
|
||||
- frontend-developer review
|
||||
- ai-engineer double-check
|
||||
- Fix any issues found
|
||||
|
||||
### Phase 5: Real-Time Monitoring
|
||||
- Activate monitoring agent
|
||||
- Catch issues in real-time
|
||||
- Auto-trigger fixes to prevent repeating errors
|
||||
|
||||
## Success Criteria
|
||||
|
||||
The task is complete when:
|
||||
- [ ] All requirements are understood and documented
|
||||
- [ ] Root causes are identified with evidence
|
||||
- [ ] Design/architecture is fully specified
|
||||
- [ ] AI Engineer has reviewed and APPROVED the design
|
||||
- [ ] Components and data flow are defined
|
||||
- [ ] Error handling and edge cases are addressed
|
||||
- [ ] Real-time logger is integrated
|
||||
- [ ] Automated QA passes (all 3 agents)
|
||||
- [ ] Testing strategy is outlined
|
||||
- [ ] Implementation considerations are documented
|
||||
- [ ] Monitoring agent is active
|
||||
|
||||
## Critical Rules
|
||||
|
||||
1. **AI Engineer Review REQUIRED**: Before ANY coding/execution, the AI Engineer agent MUST review and approve the design/approach. This is NON-NEGOTIABLE.
|
||||
|
||||
2. **Real-Time Logger**: Integrate comprehensive logging that:
|
||||
- Logs all state transitions
|
||||
- Tracks API calls and responses
|
||||
- Monitors EventBus traffic
|
||||
- Alerts on error patterns
|
||||
- Provides live debugging capability
|
||||
|
||||
3. **Automated QA Pipeline**: After implementation completion:
|
||||
- Run test-writer-fixer with backend-architect
|
||||
- Run test-writer-fixer with frontend-developer
|
||||
- Run test-writer-fixer with ai-engineer for double-check
|
||||
- Fix ALL issues found before marking complete
|
||||
|
||||
4. **Real-Time Monitoring**: Activate monitoring that:
|
||||
- Catches errors in real-time
|
||||
- Auto-triggers AI assistant agent on failures
|
||||
- Detects and solves issues immediately
|
||||
- Prevents repeating the same errors
|
||||
|
||||
## Brainstorming Mode
|
||||
|
||||
You are in autonomous brainstorming mode. Your role is to:
|
||||
1. Ask clarifying questions one at a time (simulate by making reasonable assumptions)
|
||||
2. Explore 2-3 different approaches with trade-offs
|
||||
3. Present the design in sections (200-300 words each)
|
||||
4. Cover: architecture, components, data flow, error handling, testing
|
||||
5. Validate the design against success criteria
|
||||
|
||||
## Instructions
|
||||
|
||||
- Follow the COMPLETE PIPELINE FLOW in order
|
||||
- **NEVER skip AI Engineer review before coding**
|
||||
- Iterate continuously until all success criteria are met
|
||||
- When complete, add <!-- COMPLETE --> marker to this file
|
||||
- Output the final validated design as markdown in iterations/final.md
|
||||
"""
|
||||
prompt_file.write_text(prompt_content)
|
||||
|
||||
return str(prompt_file)
|
||||
|
||||
|
||||
def run_ralphloop(task_description: str, context: str = "",
|
||||
max_iterations: Optional[int] = None,
|
||||
max_runtime: Optional[int] = None) -> Dict[str, Any]:
|
||||
"""
|
||||
Run RalphLoop for autonomous task completion.
|
||||
|
||||
Returns a dict with:
|
||||
- success: bool
|
||||
- iterations: int
|
||||
- output: str (final output)
|
||||
- state: dict (Ralph's final state)
|
||||
- error: str (if failed)
|
||||
"""
|
||||
print("🔄 Delegating to RalphLoop 'Tackle Until Solved' for autonomous iteration...")
|
||||
print(f" Complexity: {analyze_complexity(task_description, context)} steps estimated")
|
||||
print()
|
||||
|
||||
# Create Ralph task
|
||||
prompt_path = create_ralph_task(task_description, context)
|
||||
print(f"✅ Ralph task initialized: {prompt_path}")
|
||||
print()
|
||||
|
||||
# Check if ralphloop exists
|
||||
if not RALPHLOOP_CMD.exists():
|
||||
return {
|
||||
"success": False,
|
||||
"error": f"RalphLoop not found at {RALPHLOOP_CMD}",
|
||||
"iterations": 0,
|
||||
"output": "",
|
||||
"state": {}
|
||||
}
|
||||
|
||||
# Build command
|
||||
cmd = [str(RALPHLOOP_CMD)]
|
||||
|
||||
# Add inline task
|
||||
cmd.append(task_description)
|
||||
|
||||
# Add optional parameters
|
||||
if max_iterations:
|
||||
cmd.extend(["--max-iterations", str(max_iterations)])
|
||||
|
||||
if max_runtime:
|
||||
cmd.extend(["--max-runtime", str(max_runtime)])
|
||||
|
||||
# Environment variables
|
||||
env = os.environ.copy()
|
||||
env.setdefault("RALPH_AGENT", "claude")
|
||||
env.setdefault("RALPH_MAX_ITERATIONS", str(max_iterations or 100))
|
||||
|
||||
print(f"Command: {' '.join(cmd)}")
|
||||
print("=" * 60)
|
||||
print()
|
||||
|
||||
# Run RalphLoop (synchronous for now)
|
||||
try:
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
bufsize=1,
|
||||
env=env
|
||||
)
|
||||
|
||||
# Stream output
|
||||
output_lines = []
|
||||
for line in process.stdout:
|
||||
print(line, end='', flush=True)
|
||||
output_lines.append(line)
|
||||
|
||||
process.wait()
|
||||
returncode = process.returncode
|
||||
|
||||
print()
|
||||
print("=" * 60)
|
||||
|
||||
if returncode == 0:
|
||||
# Read final state
|
||||
state_file = Path(".ralph/state.json")
|
||||
final_file = Path(".ralph/iterations/final.md")
|
||||
|
||||
state = {}
|
||||
if state_file.exists():
|
||||
state = json.loads(state_file.read_text())
|
||||
|
||||
final_output = ""
|
||||
if final_file.exists():
|
||||
final_output = final_file.read_text()
|
||||
|
||||
iterations = state.get("iteration", 0)
|
||||
|
||||
print(f"✅ Ralph completed in {iterations} iterations")
|
||||
print()
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"iterations": iterations,
|
||||
"output": final_output,
|
||||
"state": state,
|
||||
"error": None
|
||||
}
|
||||
else:
|
||||
return {
|
||||
"success": False,
|
||||
"error": f"RalphLoop exited with code {returncode}",
|
||||
"iterations": 0,
|
||||
"output": "".join(output_lines),
|
||||
"state": {}
|
||||
}
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print()
|
||||
print("⚠️ RalphLoop interrupted by user")
|
||||
return {
|
||||
"success": False,
|
||||
"error": "Interrupted by user",
|
||||
"iterations": 0,
|
||||
"output": "",
|
||||
"state": {}
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
"success": False,
|
||||
"error": str(e),
|
||||
"iterations": 0,
|
||||
"output": "",
|
||||
"state": {}
|
||||
}
|
||||
|
||||
|
||||
def delegate_to_ralph(task_description: str, context: str = "") -> Optional[str]:
|
||||
"""
|
||||
Main entry point: Delegate task to Ralph if complex, return None if should run directly.
|
||||
|
||||
If Ralph is used, returns the final output as a string.
|
||||
If task is simple, returns None (caller should run directly).
|
||||
"""
|
||||
if not should_use_ralph(task_description, context):
|
||||
return None
|
||||
|
||||
result = run_ralphloop(task_description, context)
|
||||
|
||||
if result["success"]:
|
||||
return result["output"]
|
||||
else:
|
||||
print(f"❌ RalphLoop failed: {result.get('error', 'Unknown error')}")
|
||||
print("Falling back to direct brainstorming mode...")
|
||||
return None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Test the integration
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="Test Ralph integration")
|
||||
parser.add_argument("task", help="Task description")
|
||||
parser.add_argument("--context", default="", help="Additional context")
|
||||
parser.add_argument("--force", action="store_true", help="Force Ralph mode")
|
||||
parser.add_argument("--test-complexity", action="store_true", help="Only test complexity")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.test_complexity:
|
||||
complexity = analyze_complexity(args.task, args.context)
|
||||
print(f"Complexity: {complexity} steps")
|
||||
print(f"Should use Ralph: {complexity >= COMPLEXITY_THRESHOLD}")
|
||||
else:
|
||||
if args.force:
|
||||
os.environ["RALPH_AUTO"] = "true"
|
||||
|
||||
result = delegate_to_ralph(args.task, args.context)
|
||||
|
||||
if result:
|
||||
print("\n" + "=" * 60)
|
||||
print("FINAL OUTPUT:")
|
||||
print("=" * 60)
|
||||
print(result)
|
||||
else:
|
||||
print("\nTask not complex enough for Ralph. Running directly...")
|
||||
9
brainstorming/ralph.yml
Normal file
9
brainstorming/ralph.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
adapters:
|
||||
claude:
|
||||
enabled: true
|
||||
timeout: 300
|
||||
agent: claude
|
||||
max_iterations: 100
|
||||
max_runtime: 14400
|
||||
prompt_file: PROMPT.md
|
||||
verbose: true
|
||||
54
brainstorming/skill.md
Normal file
54
brainstorming/skill.md
Normal file
@@ -0,0 +1,54 @@
|
||||
---
|
||||
name: brainstorming
|
||||
description: "You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores user intent, requirements and design before implementation."
|
||||
---
|
||||
|
||||
# Brainstorming Ideas Into Designs
|
||||
|
||||
## Overview
|
||||
|
||||
Help turn ideas into fully formed designs and specs through natural collaborative dialogue.
|
||||
|
||||
Start by understanding the current project context, then ask questions one at a time to refine the idea. Once you understand what you're building, present the design in small sections (200-300 words), checking after each section whether it looks right so far.
|
||||
|
||||
## The Process
|
||||
|
||||
**Understanding the idea:**
|
||||
- Check out the current project state first (files, docs, recent commits)
|
||||
- Ask questions one at a time to refine the idea
|
||||
- Prefer multiple choice questions when possible, but open-ended is fine too
|
||||
- Only one question per message - if a topic needs more exploration, break it into multiple questions
|
||||
- Focus on understanding: purpose, constraints, success criteria
|
||||
|
||||
**Exploring approaches:**
|
||||
- Propose 2-3 different approaches with trade-offs
|
||||
- Present options conversationally with your recommendation and reasoning
|
||||
- Lead with your recommended option and explain why
|
||||
|
||||
**Presenting the design:**
|
||||
- Once you believe you understand what you're building, present the design
|
||||
- Break it into sections of 200-300 words
|
||||
- Ask after each section whether it looks right so far
|
||||
- Cover: architecture, components, data flow, error handling, testing
|
||||
- Be ready to go back and clarify if something doesn't make sense
|
||||
|
||||
## After the Design
|
||||
|
||||
**Documentation:**
|
||||
- Write the validated design to `docs/plans/YYYY-MM-DD-<topic>-design.md`
|
||||
- Use elements-of-style:writing-clearly-and-concisely skill if available
|
||||
- Commit the design document to git
|
||||
|
||||
**Implementation (if continuing):**
|
||||
- Ask: "Ready to set up for implementation?"
|
||||
- Use superpowers:using-git-worktrees to create isolated workspace
|
||||
- Use superpowers:writing-plans to create detailed implementation plan
|
||||
|
||||
## Key Principles
|
||||
|
||||
- **One question at a time** - Don't overwhelm with multiple questions
|
||||
- **Multiple choice preferred** - Easier to answer than open-ended when possible
|
||||
- **YAGNI ruthlessly** - Remove unnecessary features from all designs
|
||||
- **Explore alternatives** - Always propose 2-3 approaches before settling
|
||||
- **Incremental validation** - Present design in sections, validate each
|
||||
- **Be flexible** - Go back and clarify when something doesn't make sense
|
||||
Reference in New Issue
Block a user