Conversation
Guidelines for plugin-code dev to add CODE_EXECUTION_STATUS provider to enable better progress tracking when used with plugin-orchestrator. Co-authored-by: Cursor <cursoragent@cursor.com>
Major feature addition transforming plugin-code into a comprehensive AI coding toolkit. ## New AI Agent System - AgentRegistry service for managing multiple coding agents - Native agent: Uses elizaOS LLM + file actions (always available) - CLI agents: Claude Code, Cursor, Aider, Codex, OpenCode - Auto-detection of installed CLI tools - CODE_MODE setting: auto | native | cli ## New Actions - CODE: Universal entry point using best available agent - CLAUDE_CODE, CURSOR, AIDER, CODEX, OPENCODE: Direct agent access - DETECT_AGENTS: List available coding agents - VIEW_LESSONS: Show failure history - SHOW_STATS: Show agent performance metrics ## Learning & Stats (PRR Features) - LessonsService: Track failures and learn patterns - StatsService: Monitor agent performance over time - On-disk persistence in .plugin-code/ directory ## Providers (Dynamic Multi-Resolution) - CODE_HELP: Usage instructions for agent guidance - CODE_SETTINGS: Current configuration (non-sensitive) - CODE_EXECUTION_STATUS: Real-time execution tracking for orchestrator - CODE_AGENTS: Agent availability (3 resolutions) - CODE_LESSONS: Failure history (3 resolutions) - CODE_STATS: Performance metrics (3 resolutions) ## Progressive Enhancement - Integrates with plugin-workspace for active workspace path - Delegates git operations to plugin-git when available - GIT action suggests using plugin-git for better auth/security ## Why These Changes - Unified entry point (CODE) simplifies user experience - Multiple agents give flexibility and fallback options - Learning from failures improves over time - Execution tracking enables smart orchestrator integration - Multi-resolution providers balance context vs token usage Co-authored-by: Cursor <cursoragent@cursor.com>
WalkthroughThis PR adds a multi-agent code toolkit: multiple CLI/native coding agents, an AgentRegistry for discovery/selection, execution tracking and CODE_EXECUTION_STATUS providers, lessons and stats persistence services, workspace management docs, new provider surfaces, many agent actions, and a refactored plugin init that wires services and providers at startup. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Action as CODE Action
participant Registry as AgentRegistry
participant Tracker as ExecutionTrackerService
participant Agent as ICodingAgent
participant Coder as CoderService
User->>Action: invoke CODE action (prompt)
Action->>Registry: query available agents / CODE_MODE
Registry-->>Action: selected agent
Action->>Tracker: startExecution(conversationId, agent)
Action->>Agent: execute(prompt, projectPath, conversationId)
Agent->>Coder: check status / read/write files
Agent->>Agent: run CLI or LLM prompt
Agent-->>Action: return AgentResult (success, modifiedFiles, output)
Action->>Tracker: recordFileWrite / recordFileRead / updatePhase
Action->>Tracker: completeExecution(conversationId, success)
Action-->>User: return result and modified files
sequenceDiagram
participant Plugin
participant Runtime
participant Registry as AgentRegistry
participant Detection as CLI Detection
participant Native as NativeAgent
Plugin->>Registry: getInstance()
Plugin->>Registry: register(Native)
Plugin->>Detection: detect CLI agents (claude, cursor, aider...)
Detection-->>Plugin: availability results
Plugin->>Registry: registerAgentWithDetection(name, agent, cliCmd)
Registry-->>Plugin: registration stored (isAvailable flag)
Plugin->>Runtime: register ExecutionTrackerService, LessonsService, StatsService
Plugin-->>Runtime: initialization complete
Estimated code review effort🎯 5 (Critical) | ⏱️ ~110 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Major feature addition transforming plugin-code into a comprehensive AI coding toolkit. ## New AI Agent System - AgentRegistry service for managing multiple coding agents - Native agent: Uses elizaOS LLM + file actions (always available) - CLI agents: Claude Code, Cursor, Aider, Codex, OpenCode - Auto-detection of installed CLI tools - CODE_MODE setting: auto | native | cli ## New Actions - CODE: Universal entry point using best available agent - CLAUDE_CODE, CURSOR, AIDER, CODEX, OPENCODE: Direct agent access - DETECT_AGENTS: List available coding agents - VIEW_LESSONS: Show failure history - SHOW_STATS: Show agent performance metrics ## Learning & Stats (PRR Features) - LessonsService: Track failures and learn patterns - StatsService: Monitor agent performance over time - On-disk persistence in .plugin-code/ directory ## Providers (Dynamic Multi-Resolution) - CODE_HELP: Usage instructions for agent guidance - CODE_SETTINGS: Current configuration (non-sensitive) - CODE_EXECUTION_STATUS: Real-time execution tracking for orchestrator - CODE_AGENTS: Agent availability (3 resolutions) - CODE_LESSONS: Failure history (3 resolutions) - CODE_STATS: Performance metrics (3 resolutions) ## Progressive Enhancement - Integrates with plugin-workspace for active workspace path - Delegates git operations to plugin-git when available - GIT action suggests using plugin-git for better auth/security ## Why These Changes - Unified entry point (CODE) simplifies user experience - Multiple agents give flexibility and fallback options - Learning from failures improves over time - Execution tracking enables smart orchestrator integration - Multi-resolution providers balance context vs token usage Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Pull request overview
This PR brings AI coding agent backend support to plugin-code, transforming it from a simple file operations toolkit into a comprehensive AI-assisted coding platform. The PR adds support for multiple AI coding agents (Native, Claude Code, Cursor, Aider, Codex, OpenCode) with centralized registry management, execution tracking, performance statistics, and failure learning capabilities.
Changes:
- Adds 6 AI coding agent implementations (Native agent using elizaOS LLM, plus 5 CLI-based agents)
- Implements AgentRegistry service for centralized agent management and discovery
- Adds ExecutionTrackerService for real-time execution status tracking (orchestrator integration)
- Adds StatsService and LessonsService for performance tracking and failure learning
- Introduces 14 new actions (CODE action as main entry point, specific agent actions, stats/lessons actions)
- Adds 13 new dynamic providers with multi-resolution context (overview, default, full)
- Enhances CoderService with progressive workspace integration support
Reviewed changes
Copilot reviewed 43 out of 43 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| src/types/execution.ts | New execution status types for tracking agent progress and actions |
| src/types/index.ts | Exports new execution types |
| src/services/executionTracker.service.ts | Tracks code execution status per conversation with phase, progress, file activity |
| src/services/stats.service.ts | Tracks agent performance statistics, stores to .plugin-code/stats.json |
| src/services/lessons.service.ts | Records coding failures for learning, stores to .plugin-code/lessons.json |
| src/services/agentRegistry.service.ts | Singleton registry for agent discovery, registration, and selection |
| src/services/coderService.ts | Enhanced with optional workspace integration support via getAllowedDirectory |
| src/services/agents/*.agent.ts | 6 agent implementations (Native, ClaudeCode, Cursor, Aider, Codex, OpenCode) |
| src/services/agents/utils.ts | Shared utilities for CLI execution, binary detection, error classification |
| src/services/agents/index.ts | Exports all agents and utilities |
| src/actions/agents/*.ts | 7 new actions: CODE (main), CLAUDE_CODE, CURSOR, AIDER, CODEX, OPENCODE, DETECT_AGENTS |
| src/actions/prr/*.ts | 2 new actions: VIEW_LESSONS, SHOW_STATS for performance review |
| src/actions/index.ts | Exports all new actions |
| src/actions/git.ts | Enhanced with plugin-git integration hints and progressive enhancement |
| src/actions/editFile.ts | Minor formatting cleanup |
| src/providers/executionStatus.provider.ts | 3-resolution provider for execution status (orchestrator visibility) |
| src/providers/agents.providers.ts | 3-resolution provider for agent availability |
| src/providers/lessons.providers.ts | 3-resolution provider for failure history |
| src/providers/stats.providers.ts | 3-resolution provider for performance stats |
| src/providers/help.provider.ts | Usage instructions provider |
| src/providers/settings.provider.ts | Configuration status provider |
| src/providers/index.ts | Exports all providers |
| src/interfaces/ICodingAgent.ts | Core interface for coding agents, minor formatting fix |
| src/index.ts | Plugin initialization with agent registration and comprehensive exports |
| src/utils/pathUtils.ts | Minor formatting cleanup |
| package.json | Adds uuid dependency (unused), adds ELIZA_WORKSPACES_ROOT setting |
| README.md | Comprehensive documentation update covering new features |
| ORCHESTRATOR_INTEGRATION.md | Integration guidelines for plugin-orchestrator |
| WORKSPACES.md | Workspace management documentation (misplaced - not part of this PR) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private static instance: AgentRegistry; | ||
| private agents: Map<string, AgentRegistration> = new Map(); | ||
|
|
||
| private constructor() { } |
There was a problem hiding this comment.
The empty space in the constructor creates inconsistent code style. While not functionally harmful, it's better to either remove the space or use proper formatting.
| private constructor() { } | |
| private constructor() {} |
|
|
||
| // Get CODE_MODE setting | ||
| const mode = (runtime.getSetting('CODE_MODE') as string) || 'auto'; | ||
| const conversationId = message.roomId; |
There was a problem hiding this comment.
The conversationId is directly assigned from message.roomId which could be undefined. This could cause issues in downstream services that expect a string. Consider providing a fallback value similar to how it's done in NativeCoderAgent line 71: const conversationId = params.conversationId || 'default' or use message.roomId ?? runtime.agentId.
| const conversationId = message.roomId; | |
| const conversationId = message.roomId ?? runtime.agentId; |
| return { success: false, error: 'Claude Code not available' }; | ||
| } | ||
|
|
||
| const conversationId = message.roomId; |
There was a problem hiding this comment.
Same issue as in the CODE action: message.roomId could be undefined, leading to potential runtime errors. Use a fallback value like message.roomId ?? runtime.agentId to ensure conversationId is always a string.
| const conversationId = message.roomId; | |
| const conversationId = message.roomId ?? runtime.agentId; |
| return { success: false, error: 'Aider not available' }; | ||
| } | ||
|
|
||
| const conversationId = message.roomId; |
There was a problem hiding this comment.
Same issue as in other agent actions: message.roomId could be undefined. Use a fallback value like message.roomId ?? runtime.agentId.
| const conversationId = message.roomId; | |
| const conversationId = message.roomId ?? runtime.agentId; |
| return { success: false, error: 'Codex not available' }; | ||
| } | ||
|
|
||
| const conversationId = message.roomId; |
There was a problem hiding this comment.
Same issue as in other agent actions: message.roomId could be undefined. Use a fallback value like message.roomId ?? runtime.agentId.
| const conversationId = message.roomId; | |
| const conversationId = message.roomId ?? runtime.agentId; |
| # Workspace Management in plugin-code | ||
|
|
||
| ## Overview | ||
|
|
||
| The workspace system provides a managed directory structure for working with any codebase - git repos, archives, or local projects. Similar to GitHub Codespaces or Replit, it handles cloning, extracting, and organizing projects in a secure, isolated manner. | ||
|
|
||
| ## Architecture | ||
|
|
||
| ``` | ||
| ~/.eliza-workspaces/ | ||
| ├── .metadata/ | ||
| │ ├── workspaces.json # Registry of all workspaces | ||
| │ └── <workspace-id>.json # Per-workspace metadata (future) | ||
| ├── facebook-react/ # Cloned from git | ||
| ├── my-python-project/ # Extracted from zip | ||
| ├── local-experiment/ # Created locally | ||
| └── nextjs-app-2025/ # Another project | ||
| ``` | ||
|
|
||
| ## Key Features | ||
|
|
||
| ### 🌐 Multiple Source Types | ||
| - **Git Clone**: Clone any repository from GitHub, GitLab, Bitbucket, etc. | ||
| - **Archive Import**: Extract from .zip or .tar.gz URLs | ||
| - **Local Creation**: Create empty workspace for new projects | ||
| - **Future**: Symlink support for development mode | ||
|
|
||
| ### 🔒 Security Model | ||
| - Each conversation/session is locked to ONE active workspace at a time | ||
| - `CODER_ALLOWED_DIRECTORY` automatically set to active workspace path | ||
| - All file/shell operations restricted to current workspace | ||
| - Parent directory (`~/.eliza-workspaces/`) cannot be accessed by agents | ||
|
|
||
| ### 📊 Auto-Detection | ||
| Workspaces automatically detect: | ||
| - **Languages**: JavaScript, TypeScript, Python, Rust, Go | ||
| - **Frameworks**: React, Next.js, Vue, ElizaOS | ||
| - **Package Managers**: bun, npm, yarn, pnpm, cargo, go, pip | ||
|
|
||
| ## Configuration | ||
|
|
||
| ### Environment Variables | ||
|
|
||
| ```bash | ||
| # Workspace root directory (optional - defaults shown) | ||
| ELIZA_WORKSPACES_ROOT=~/.eliza-workspaces | ||
|
|
||
| # Strict mode - enforce workspace directory constraint | ||
| # When true, CODER_ALLOWED_DIRECTORY must be inside workspaces root | ||
| ELIZA_WORKSPACES_STRICT=false | ||
|
|
||
| # Legacy config still works | ||
| CODER_ENABLED=true | ||
| CODER_ALLOWED_DIRECTORY=/path/to/project # Auto-set from active workspace | ||
| ``` | ||
|
|
||
| ### Character File | ||
|
|
||
| ```json | ||
| { | ||
| "plugins": ["@elizaos/plugin-code"], | ||
| "settings": { | ||
| "CODER_ENABLED": true, | ||
| "ELIZA_WORKSPACES_ROOT": "~/.eliza-workspaces" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Usage | ||
|
|
||
| ### Creating Workspaces | ||
|
|
||
| **From Git Repository:** | ||
| ``` | ||
| "Clone https://github.com/facebook/react" | ||
| "Clone the Next.js repo from GitHub" | ||
| "Import https://github.com/user/repo branch develop" | ||
| ``` | ||
|
|
||
| **From Archive:** | ||
| ``` | ||
| "Import project from https://example.com/project.zip" | ||
| "Extract this archive: https://example.com/app.tar.gz" | ||
| ``` | ||
|
|
||
| **Local Workspace:** | ||
| ``` | ||
| "Create local workspace named my-project" | ||
| "Create a new workspace called test-app" | ||
| ``` | ||
|
|
||
| ### Managing Workspaces | ||
|
|
||
| **List All Workspaces:** | ||
| ``` | ||
| "Show me all workspaces" | ||
| "List workspaces" | ||
| ``` | ||
|
|
||
| **Switch Workspace:** | ||
| ``` | ||
| "Switch to workspace react" | ||
| "Use the my-project workspace" | ||
| ``` | ||
|
|
||
| **Delete Workspace:** | ||
| ``` | ||
| "Delete workspace old-project yes delete" | ||
| "Remove workspace test yes delete" | ||
| ``` | ||
|
|
||
| ⚠️ **Note**: Deletion requires explicit "yes delete" confirmation | ||
|
|
||
| ### Working with Files | ||
|
|
||
| Once a workspace is active, all existing file operations work within that workspace: | ||
|
|
||
| ``` | ||
| "Read the package.json file" | ||
| "List files in src/" | ||
| "Edit app.js and change..." | ||
| "Run npm install" | ||
| ``` | ||
|
|
||
| ## Integration with CoderService | ||
|
|
||
| The `CoderService` automatically integrates with `WorkspaceService`: | ||
|
|
||
| ```typescript | ||
| // CoderService checks for active workspace first | ||
| getAllowedDirectory(conversationId) { | ||
| const workspaceService = runtime.getService('workspace'); | ||
| const activeWorkspace = workspaceService.getActiveWorkspace(conversationId); | ||
|
|
||
| if (activeWorkspace) { | ||
| return activeWorkspace.path; // Use workspace path | ||
| } | ||
|
|
||
| return this.coderConfig.allowedDirectory; // Fallback to config | ||
| } | ||
| ``` | ||
|
|
||
| ## Actions Reference | ||
|
|
||
| ### CREATE_WORKSPACE | ||
| Creates a new workspace from various sources. | ||
|
|
||
| **Triggers:** `CLONE_REPO`, `IMPORT_PROJECT`, `NEW_WORKSPACE`, `SETUP_PROJECT` | ||
|
|
||
| **Examples:** | ||
| - `"Clone https://github.com/facebook/react"` | ||
| - `"Create workspace from https://example.com/project.zip"` | ||
| - `"Create local workspace named my-project"` | ||
|
|
||
| ### LIST_WORKSPACES | ||
| Lists all available workspaces with details. | ||
|
|
||
| **Triggers:** `SHOW_WORKSPACES`, `WORKSPACES`, `LIST_PROJECTS` | ||
|
|
||
| **Shows:** | ||
| - Workspace name and path | ||
| - Source (git URL, archive URL, or local) | ||
| - Framework and language detection | ||
| - Last accessed time | ||
| - Active status | ||
|
|
||
| ### SWITCH_WORKSPACE | ||
| Switches to a different workspace. | ||
|
|
||
| **Triggers:** `USE_WORKSPACE`, `CHANGE_WORKSPACE`, `ACTIVATE_WORKSPACE` | ||
|
|
||
| **Example:** `"Switch to workspace react"` | ||
|
|
||
| ### DELETE_WORKSPACE | ||
| Permanently deletes a workspace. | ||
|
|
||
| **Triggers:** `REMOVE_WORKSPACE`, `DESTROY_WORKSPACE` | ||
|
|
||
| **Example:** `"Delete workspace old-project yes delete"` | ||
|
|
||
| ⚠️ **Requires confirmation**: Must include "yes delete" in the request | ||
|
|
||
| ## Providers | ||
|
|
||
| ### WORKSPACE_STATUS | ||
| Provides information about the current workspace state. | ||
|
|
||
| **Includes:** | ||
| - Active workspace name and path | ||
| - Source information (git/archive/local) | ||
| - Detected framework and languages | ||
| - Package manager | ||
| - List of other available workspaces | ||
|
|
||
| **Used by:** Agent prompts to understand current working context | ||
|
|
||
| ## API Reference | ||
|
|
||
| ### WorkspaceService | ||
|
|
||
| ```typescript | ||
| // Create workspace from git | ||
| const workspace = await workspaceService.createFromGit(repoUrl, { | ||
| branch: 'main', // optional | ||
| name: 'my-repo' // optional | ||
| }); | ||
|
|
||
| // Create from archive | ||
| const workspace = await workspaceService.createFromArchive(archiveUrl, { | ||
| name: 'my-project' // optional | ||
| }); | ||
|
|
||
| // Create local workspace | ||
| const workspace = await workspaceService.createLocal('project-name'); | ||
|
|
||
| // Get active workspace | ||
| const workspace = workspaceService.getActiveWorkspace(conversationId); | ||
|
|
||
| // Set active workspace | ||
| await workspaceService.setActiveWorkspace(conversationId, workspaceId); | ||
|
|
||
| // List all workspaces | ||
| const workspaces = workspaceService.listWorkspaces(); | ||
|
|
||
| // Delete workspace | ||
| await workspaceService.deleteWorkspace(workspaceId); | ||
| ``` | ||
|
|
||
| ## Workspace Data Structure | ||
|
|
||
| ```typescript | ||
| interface Workspace { | ||
| id: string; // Unique UUID | ||
| name: string; // Display name | ||
| path: string; // Absolute filesystem path | ||
| source: { | ||
| type: 'git' | 'zip' | 'local' | 'symlink'; | ||
| url?: string; // Original source URL | ||
| branch?: string; // Git branch (if git) | ||
| commit?: string; // Git commit hash (if git) | ||
| }; | ||
| created: Date; | ||
| lastAccessed: Date; | ||
| active: boolean; // Currently active? | ||
| metadata: { | ||
| language?: string[]; // Detected languages | ||
| framework?: string; // Detected framework | ||
| packageManager?: string; // Detected package manager | ||
| }; | ||
| } | ||
| ``` | ||
|
|
||
| ## Migration from Existing Setup | ||
|
|
||
| If you're currently using `CODER_ALLOWED_DIRECTORY`: | ||
|
|
||
| **Option 1: Keep Existing Behavior** | ||
| ```bash | ||
| # Don't set ELIZA_WORKSPACES_ROOT - continues using CODER_ALLOWED_DIRECTORY | ||
| CODER_ENABLED=true | ||
| CODER_ALLOWED_DIRECTORY=/path/to/my/project | ||
| ``` | ||
|
|
||
| **Option 2: Migrate to Workspaces** | ||
| ```bash | ||
| # Set workspaces root | ||
| ELIZA_WORKSPACES_ROOT=~/.eliza-workspaces | ||
|
|
||
| # Create workspace from existing project (symlink coming soon) | ||
| # For now: copy or clone project into ~/.eliza-workspaces/ | ||
| cp -r /path/to/my/project ~/.eliza-workspaces/my-project | ||
| ``` | ||
|
|
||
| Then in chat: `"Switch to workspace my-project"` | ||
|
|
||
| ## Future Enhancements | ||
|
|
||
| - **Symlink Support**: Link to existing directories without copying | ||
| - **Workspace Templates**: Pre-configured project templates | ||
| - **Collaborative Workspaces**: Share workspace state across agents | ||
| - **Automatic Cleanup**: Archive old/unused workspaces | ||
| - **Git Integration**: Auto-update, branch management, PR creation | ||
| - **Resource Limits**: Disk space quotas per workspace | ||
| - **Workspace Snapshots**: Save/restore workspace state | ||
|
|
||
| ## Examples | ||
|
|
||
| ### Complete Workflow | ||
|
|
||
| ``` | ||
| User: "Clone the React repository" | ||
| Agent: 🔄 Cloning repository from https://github.com/facebook/react... | ||
| Agent: ✅ Workspace created and activated! | ||
| **react** | ||
| 📂 Path: `~/.eliza-workspaces/react` | ||
| 🔗 Source: git (https://github.com/facebook/react) | ||
| 🎯 Framework: React | ||
| 📝 Languages: javascript, typescript | ||
| 📦 Package Manager: yarn | ||
|
|
||
| User: "List all files in src/" | ||
| Agent: [Lists React source files...] | ||
|
|
||
| User: "Run yarn install" | ||
| Agent: [Executes yarn install in workspace...] | ||
|
|
||
| User: "Switch to my other project" | ||
| Agent: [Shows list of workspaces...] | ||
|
|
||
| User: "Create a new workspace called test-app" | ||
| Agent: 📁 Creating local workspace "test-app"... | ||
| Agent: ✅ Workspace created! | ||
|
|
||
| User: "Create index.js with hello world" | ||
| Agent: [Creates file in test-app workspace...] | ||
| ``` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Workspace Not Found | ||
| ``` | ||
| Error: Workspace "xyz" not found | ||
| ``` | ||
| **Solution**: Run `"List workspaces"` to see available workspaces | ||
|
|
||
| ### Git Clone Failed | ||
| ``` | ||
| Error: Failed to clone repository | ||
| ``` | ||
| **Common causes:** | ||
| - Invalid URL | ||
| - Private repository without authentication | ||
| - Network issues | ||
|
|
||
| **Solution**: Ensure URL is public or configure Git credentials | ||
|
|
||
| ### Out of Disk Space | ||
| ``` | ||
| Error: ENOSPC: no space left on device | ||
| ``` | ||
| **Solution**: Delete unused workspaces: | ||
| ``` | ||
| "Delete workspace old-project yes delete" | ||
| ``` | ||
|
|
||
| ### Path Access Denied | ||
| ``` | ||
| Error: Cannot access path outside allowed directory | ||
| ``` | ||
| **Explanation**: Security feature - all operations restricted to active workspace | ||
|
|
||
| **Solution**: Ensure you're working within the current workspace or switch workspaces | ||
|
|
||
| ## Security Considerations | ||
|
|
||
| 1. **Directory Isolation**: Agents cannot access files outside active workspace | ||
| 2. **Parent Directory Protection**: `~/.eliza-workspaces/` root is not accessible | ||
| 3. **Command Restrictions**: All `CODER_FORBIDDEN_COMMANDS` still apply | ||
| 4. **Git Authentication**: Credentials should be configured at OS level, not in agent | ||
| 5. **Archive Sources**: Only download from trusted URLs | ||
|
|
||
| ## Best Practices | ||
|
|
||
| 1. **Naming**: Use descriptive, lowercase names with hyphens | ||
| 2. **Organization**: Group related workspaces by project/client | ||
| 3. **Cleanup**: Regularly delete unused workspaces | ||
| 4. **Git Repos**: Prefer cloning over uploading archives for better version control | ||
| 5. **Large Files**: Avoid workspaces with >1GB of files (performance) | ||
|
|
||
| ## Comparison to Other Tools | ||
|
|
||
| | Feature | Eliza Workspaces | GitHub Codespaces | Replit | VS Code Dev Containers | | ||
| |---------|------------------|-------------------|--------|------------------------| | ||
| | **Chat Interface** | ✅ | ❌ | ❌ | ❌ | | ||
| | **Git Clone** | ✅ | ✅ | ✅ | ✅ | | ||
| | **Archive Import** | ✅ | ❌ | ✅ | ❌ | | ||
| | **Local Creation** | ✅ | ❌ | ✅ | ✅ | | ||
| | **Auto-Detection** | ✅ | ✅ | ✅ | ✅ | | ||
| | **Multi-Workspace** | ✅ | ✅ | ✅ | ❌ | | ||
| | **Offline Mode** | ✅ | ❌ | ❌ | ✅ | | ||
| | **AI Coding Agents** | ✅ | ❌ | ❌ | ❌ | | ||
|
|
||
| --- | ||
|
|
||
| **Need Help?** Ask your agent: | ||
| - `"How do workspaces work?"` | ||
| - `"Show me workspace commands"` | ||
| - `"What workspace am I in?"` |
There was a problem hiding this comment.
The WORKSPACES.md file appears to describe workspace management functionality that is not part of this PR. The file mentions "WorkspaceService" and workspace-related actions (CREATE_WORKSPACE, LIST_WORKSPACES, etc.) which are not included in the changes. This documentation file seems misplaced and should either be removed or moved to the correct PR/repository.
| return { success: false, error: 'Cursor not available' }; | ||
| } | ||
|
|
||
| const conversationId = message.roomId; |
There was a problem hiding this comment.
Same issue as in other agent actions: message.roomId could be undefined. Use a fallback value like message.roomId ?? runtime.agentId.
| const conversationId = message.roomId; | |
| const conversationId = message.roomId ?? runtime.agentId; |
| // Get project root from CoderService | ||
| const coderService = runtime.getService<CoderService>('coder'); | ||
| if (coderService) { | ||
| const projectRoot = coderService.getAllowedDirectory(); |
There was a problem hiding this comment.
The getAllowedDirectory() method signature was changed to accept an optional conversationId parameter, but this call doesn't provide it. This could cause issues if workspace integration is active since the method may return the wrong directory. Consider passing a conversationId or using a method that doesn't require workspace context for initialization.
| } | ||
|
|
||
| async execute(params: ExecuteParams, runtime: IAgentRuntime): Promise<AgentResult> { | ||
| const taskId = params.conversationId || 'unknown'; |
There was a problem hiding this comment.
Unused variable taskId.
| const taskId = params.conversationId || 'unknown'; |
| // Force native agent | ||
| const nativeReg = registry.get('native'); | ||
| if (nativeReg?.isAvailable) { | ||
| agentName = 'native'; |
There was a problem hiding this comment.
The value assigned to agentName here is unused.
There was a problem hiding this comment.
Actionable comments posted: 16
🤖 Fix all issues with AI agents
In `@ORCHESTRATOR_INTEGRATION.md`:
- Around line 29-202: Replace the old CoderService examples with the actual
ExecutionTrackerService API: in the codeExecutionStatusProvider sample and agent
snippets, get the service via
runtime.getService<ExecutionTrackerService>('executionTracker') and call the
real methods (e.g., getExecutionStatus / updateExecutionStatus) rather than
coderService.getExecutionStatus/updateStatus; switch phase/string values to the
real ExecutionPhase enums (including starting, completing, error) instead of
'idle'|'planning'|'reading'|'writing'|'verifying'; replace nullable/legacy
fields with the actual ExecutionStatus shape from src/types/execution.ts
(include actionHistory instead of recentActions, adjust timing/identifier fields
to match the type), and update NativeCoderAgent.execute and
ClaudeCodeAgent.execute examples to call
ExecutionTrackerService.updateExecutionStatus with the new phase values and
actionHistory updates when parsing CLI output.
- Around line 238-243: The Markdown table separator row in
ORCHESTRATOR_INTEGRATION.md is missing spaces around the pipe characters which
violates markdownlint MD060; update the separator row between the header and
body so each pipe has a single space before and after it (i.e., change
"|---------------|-------------|" to use " | " spacing consistent with the
header and rows), ensuring the separator aligns with the header columns for the
table shown under the "Without Status | With Status" heading.
In `@README.md`:
- Around line 145-168: Update the ASCII art fenced code blocks in README.md to
include a language identifier (use "text") to satisfy markdownlint MD040;
specifically add ```text at the start of the CODE_MODE diagram and the
plugin-code diagram (the blocks containing the "User: 'fix the bug in utils.ts'
... Check CODE_MODE" flow and the "plugin-code ├── Services ..." tree) so both
diagrams declare a language instead of bare ``` fences.
- Around line 37-54: The markdown tables in README (e.g., rows with headers like
CODER_ENABLED, CODER_ALLOWED_DIRECTORY and CODE_MODE, CODE_CLAUDE_MODEL, etc.)
have inconsistent pipe spacing triggering MD060; update each table to use a
consistent pipe-spacing style (for example, single space before and after each
cell delimiter) across all tables (including the sections you noted and the ones
at lines ~76-105, 110-123, 131-142) by normalizing the pipe spacing or running
the project's markdown formatter so every cell follows the same " | cell | "
pattern.
In `@src/providers/executionStatus.provider.ts`:
- Around line 87-97: The forEach callbacks on status.filesRead and
status.filesWritten currently use concise arrow expressions that implicitly
return the result of lines.push(...) which triggers the Biome lint error; change
those callbacks to use block bodies (or replace with a for...of loop) and call
lines.push(...) as a statement (no return value) so the callback does not return
anything—update the two occurrences that iterate over status.filesRead and
status.filesWritten and ensure you still push the same formatted strings (e.g.,
` - ${f}`) into the lines array.
In `@src/services/agentRegistry.service.ts`:
- Around line 326-356: The parseAgentFromInput function builds one giant
alternation regex from all aliases which can lead to ReDoS; fix it by avoiding
the combined alternation: iterate each agent (this.agents) and then each
name/alias, escape the alias (as already done), and construct/test a small
per-name RegExp like
`\\b(?:using|with|via|in|on)\\s+(?:the\\s+)?${escapedName}(?:\\s+agent)?\\b` or,
even safer, perform tokenized string checks (split lowerText into words and
verify a preposition token precedes the candidate name) instead of one large
regex; additionally, add validation when registering aliases (reject very long
strings or disallow unescaped regex metacharacters) in the registration code to
prevent attacker-controlled patterns from entering the registry.
In `@src/services/agents/aider.agent.ts`:
- Around line 143-145: The call to classifyError(output) in the failure branch
is unused; either remove it or surface its return value: capture const
classification = classifyError(output) and include it in the failure handling
(for example append classification to the logger.error message or set an error
variable used downstream), or simply delete the classifyError(output) invocation
if classification isn't needed; update the block around result.exitCode,
classifyError, and logger.error to reflect the chosen approach (use
classifyError’s return value in the log or remove the call).
In `@src/services/agents/codex.agent.ts`:
- Around line 50-54: The regex literals in isCursorPositionError are flagged by
Biome for control characters; replace the literal regexes with RegExp
constructors using escaped string patterns to preserve behavior. Specifically,
change the ANSI-strip and control-char replaces to use new RegExp(...) with the
same patterns and 'g' flag (e.g., pattern for "\x1b\[[0-9;]*[a-zA-Z]" and for
"[\x00-\x1f]" expressed as escaped strings) and replace the final test regex
with new
RegExp('cursor.{0,10}position.{0,10}could.{0,10}not.{0,10}be.{0,10}read', 'i')
so lint noControlCharactersInRegex is satisfied while keeping function
isCursorPositionError's behavior unchanged.
In `@src/services/agents/opencode.agent.ts`:
- Around line 134-138: The returned result in opencode.agent.ts currently always
sets modifiedFiles: [] which misreports edits; update the function that returns
this object in opencode.agent.ts so modifiedFiles is either removed until
implemented or populated from git (e.g., capture changed paths via a git
diff/name-only call or a library like simple-git) and include those paths in the
modifiedFiles array before returning the result object; locate the return block
that emits success, modifiedFiles, output and replace the empty array with the
computed file list (or omit the key entirely).
- Around line 78-80: The debug/info logs in OpenCodeAgent are printing raw
prompt content (logger.info and logger.debug in the method that executes tasks),
which risks leaking secrets; change the logging in the OpenCodeAgent execution
method to avoid printing the raw params.prompt — instead log non-sensitive
metadata such as prompt length, a fixed mask or a one-way hash (e.g., SHA256) of
the prompt, and context like params.projectPath and task id; update the
logger.debug call that currently uses params.prompt.substring(...) to emit only
the safe summary/hash or "prompt redacted" so no plaintext prompt is written to
logs.
- Around line 101-118: The current invocation builds args and calls
execCommand(OPENCODE_BINARY, args, { stdin: params.prompt }) which is wrong for
OpenCode: change the args to include the "run" subcommand and pass the prompt as
a positional argument (after "--" or as the last arg) instead of via stdin
(replace use of stdin param), and ensure the model value (from params.model or
runtime.getSetting('CODE_OPENCODE_MODEL')) is normalized to the required
provider/model format before pushing it as "--model"; update usage of
OPENCODE_BINARY, args, execCommand, params.prompt, params.model, and
isValidModelName to implement these changes.
In `@src/services/coderService.ts`:
- Around line 327-333: searchInDirectory is using
this.coderConfig.allowedDirectory to compute relative file paths, causing
inconsistency when a workspace is active because
resolveWithin/getAllowedDirectory(conversationId) uses the dynamic allowed dir;
update the code so the dynamic allowed directory from
getAllowedDirectory(conversationId) is used for relative paths instead of
this.coderConfig.allowedDirectory—either compute allowedDir once in searchFiles
(via getAllowedDirectory) and pass it into searchInDirectory, or change
searchInDirectory to accept a conversationId and call getAllowedDirectory
itself; adjust references to allowedDir when building results (path.relative) to
use the dynamic value and keep resolveWithin, searchFiles, searchInDirectory,
and getAllowedDirectory consistent.
In `@src/services/lessons.service.ts`:
- Around line 244-251: The toCSV() export currently escapes double quotes but
leaves newlines (and potentially CRLF) inside lesson.error which can break CSV
rows; update the error normalization in toCSV (referencing toCSV(),
this.lessons, and lesson.error) to first replace CR and LF (e.g.,
.replace(/\r?\n/g, ' ')), then escape quotes (.replace(/"/g, '""')), then
substring to 100 chars, and continue wrapping the field in quotes as already
done so CSV rows remain intact even when errors contain newlines or commas.
- Around line 78-88: The initialize method can silently leave storagePath empty
if CoderService isn't available; modify initialize( runtime: IAgentRuntime ) so
that when runtime.getService<CoderService>('coder') returns undefined you emit a
visible warning (e.g., this.logger.warn(...) or console.warn(...)) and set a
safe fallback storagePath (for example path.join(process.cwd(), '.plugin-code',
'lessons.json')) before calling this.load(); keep references to initialize,
IAgentRuntime, getService, CoderService, storagePath and load so the change is
easy to locate.
In `@WORKSPACES.md`:
- Around line 372-382: The comparison table starting with the header "| Feature
| Eliza Workspaces | GitHub Codespaces | Replit | VS Code Dev Containers |" has
inconsistent pipe spacing and triggers MD060; normalize the table by aligning
the pipe characters and cell padding to your project's markdown table style
(e.g., ensure a single space after and before each pipe or run your markdown
formatter), making the header, separator row, and all data rows follow the same
column padding so markdownlint no longer reports MD060.
- Around line 73-91: Add language identifiers ("text") to the three fenced code
blocks under the headings "From Git Repository", "From Archive", and "Local
Workspace" so markdownlint MD040 is satisfied; update the opening fences for
each unlabeled block to use ```text (the blocks containing the repository
clone/import examples, the archive import/extract examples, and the local
workspace creation examples).
🧹 Nitpick comments (19)
src/types/execution.ts (1)
92-98: Consider documentingprogressModevalues.The
progressModefield has'auto' | 'manual'options. While Line 12 mentions that "Progress is calculated from files read/written" (implying 'auto' behavior), it would be helpful to document what 'manual' mode does or when it should be used.src/services/coderService.ts (1)
42-67: Good progressive enhancement pattern.The workspace integration is well-documented and correctly falls back when unavailable. Consider adding a trace-level log in the catch block to aid debugging when workspace service lookup fails unexpectedly.
Minor: Line 55 uses
anytype forworkspaceService. If a shared interface exists for the workspace service, using it would improve type safety.🔧 Optional: Add trace logging for debugging
} catch { - // plugin-workspace not available, fall back to config + // plugin-workspace not available, fall back to config + logger.trace({ src: 'plugin:code' }, 'plugin-workspace not available, using config directory'); }src/services/stats.service.ts (1)
50-52: Serialize saves to avoid overlapping writes and I/O churn.
recordAttempt()awaitssave()on every call; concurrent calls can interleave writes and overwrite newer data. Consider a simple save queue to serialize writes (or debounce if you want batching).🔧 Suggested refactor (serialized saves)
private stats: Map<string, AgentStats> = new Map(); private storagePath: string = ''; private loaded = false; + private saveQueue: Promise<void> = Promise.resolve(); @@ this.stats.set(agent, existing); - await this.save(); + this.saveQueue = this.saveQueue.then(() => this.save()); + await this.saveQueue;Also applies to: 148-173
src/services/executionTracker.service.ts (2)
56-68: Return defensive copies fromgetStatusto avoid external mutation.Shallow copies leave
filesRead,filesWritten, andactionHistoryshared with internal state.🧯 Defensive copy
- return { ...status }; + return { + ...status, + filesRead: [...status.filesRead], + filesWritten: [...status.filesWritten], + actionHistory: status.actionHistory.map((a) => ({ ...a })), + };
360-367: Handle Windows path separators inshortenPath.Using only
'/'misses Windows paths; split on both separators.🪟 Cross‑platform path split
- const parts = filePath.split('/'); + const parts = filePath.split(/[\\/]/);src/actions/agents/code.ts (1)
84-88: Add a fallback conversationId for non‑room contexts.If
message.roomIdis undefined (e.g., system‑initiated calls), tracking and directory lookup can break.🧭 Safer conversationId
- const conversationId = message.roomId; + const conversationId = message.roomId ?? runtime.agentId;src/providers/executionStatus.provider.ts (1)
24-35: Escape CSV fields to avoid malformed output.Descriptions or file paths can contain quotes, commas, or newlines.
🧾 Safer CSV encoding
function formatHistoryAsCsv(actions: ExecutionAction[]): string { if (actions.length === 0) return 'No actions recorded'; const header = 'type,description,file,success,timestamp'; + const escape = (value: string) => + `"${value.replace(/"/g, '""').replace(/\r?\n/g, ' ')}"`; const rows = actions.map((a) => { const file = a.file || ''; const time = new Date(a.timestamp).toISOString(); - return `${a.type},"${a.description}",${file},${a.success},${time}`; + return `${a.type},${escape(a.description)},${escape(file)},${a.success},${time}`; });src/actions/agents/aider.ts (1)
26-94: Consider extracting shared agent action logic.This handler is nearly identical to
cursorAction(and likely other agent actions in this PR). The common pattern includes:
- Get coderService and validate availability
- Check agent availability from registry
- Extract and validate prompt
- Build ExecuteParams and execute
- Handle success/failure with callbacks
A shared factory or helper function could reduce duplication and ensure consistency across all agent actions.
♻️ Example: Agent action factory pattern
// In a shared helper file, e.g., src/actions/agents/createAgentAction.ts function createAgentAction(agentName: string, config: { displayName: string; installHint: string; similes: string[]; }): Action { return { name: agentName.toUpperCase(), description: `Execute coding task with ${config.displayName}. Use when user says "use ${agentName}".`, similes: config.similes, validate: async (_runtime) => { const registry = AgentRegistry.getInstance(); return registry.get(agentName)?.isAvailable ?? false; }, handler: async (runtime, message, _state, _options, callback) => { // ... shared handler logic with agentName parameterized }, }; } // Usage: export const aiderAction = createAgentAction('aider', { displayName: 'Aider CLI', installHint: 'pip install aider-chat', similes: ['use aider', 'aider', 'with aider', 'using aider'], });src/providers/settings.provider.ts (1)
28-28: Specify radix forparseInt.Although modern JavaScript defaults to base 10 for numeric strings, explicitly specifying the radix improves clarity and avoids potential issues with strings that might be interpreted differently.
♻️ Suggested fix
- const timeoutMs = parseInt(runtime.getSetting('CODER_TIMEOUT_MS') as string) || 300000; + const timeoutMs = parseInt(runtime.getSetting('CODER_TIMEOUT_MS') as string, 10) || 300000;src/actions/agents/claudeCode.ts (1)
26-96: Consider extracting shared handler logic into a reusable helper.The handler implementation is nearly identical to
opencode.ts(and likely other agent actions). The only differences are:
- Agent name string ('claude-code' vs 'opencode')
- Error message text
- Action name in return value
This pattern could be consolidated into a factory function to reduce duplication.
♻️ Example helper function
// In a shared file like agents/helpers.ts export function createAgentHandler(agentName: string, displayName: string, installUrl?: string) { return async (runtime, message, _state, _options, callback) => { const registry = AgentRegistry.getInstance(); const coderService = runtime.getService<CoderService>('coder'); if (!coderService) { await callback({ text: 'CoderService not available.' }); return { success: false, error: 'CoderService not available' }; } const reg = registry.get(agentName); if (!reg?.isAvailable) { const msg = installUrl ? `${displayName} CLI not available. Install from: ${installUrl}` : `${displayName} CLI not available.`; await callback({ text: msg }); return { success: false, error: `${displayName} not available` }; } // ... rest of shared logic }; }src/services/agents/claudeCode.agent.ts (1)
186-194: Unused return value fromclassifyError().
classifyError(output)is called but its return value is discarded. IfclassifyErroris intended only for logging/side effects, this is fine. Otherwise, consider using the classified error type to provide more specific error messages to users.♻️ Potential enhancement
if (result.exitCode !== 0) { - classifyError(output); + const errorType = classifyError(output); logger.error(`[ClaudeCodeAgent] Failed with exit code: ${result.exitCode}`); return { success: false, - error: result.stderr || 'Claude Code execution failed', + error: result.stderr || `Claude Code execution failed (${errorType})`, output, }; }src/services/index.ts (1)
16-30: Minor inconsistency:writePromptFileandcleanupPromptFileare not re-exported.The
src/services/agents/index.tsexportswritePromptFileandcleanupPromptFile, but they're not included in the re-exports here. If these utilities are intended for external use, consider adding them for API consistency.♻️ Add missing exports if needed
export { NativeCoderAgent, ClaudeCodeAgent, CursorAgent, AiderAgent, CodexAgent, OpenCodeAgent, execCommand, commandExists, findAvailableBinary, isValidModelName, + writePromptFile, + cleanupPromptFile, classifyError, createFixPrompt, } from './agents/index.ts';src/actions/prr/viewLessons.ts (1)
44-49: Regex may not capture all intended search patterns.The regex
/(?:search|find|for)\s+["']?([^"']+)["']?/icaptures text after "search", "find", or "for", but theforkeyword alone is too generic and may cause false positives (e.g., "show lessons for today" would extract "today" as search keyword). Additionally, the pattern doesn't handle cases like "search for X" well since "for" would match before "search for" gets a chance.Consider refining the pattern or documenting the expected input format.
💡 Suggested refinement
- const searchMatch = messageText.match(/(?:search|find|for)\s+["']?([^"']+)["']?/i); + const searchMatch = messageText.match(/(?:search|find)\s+(?:for\s+)?["']?([^"']+)["']?/i);src/services/agents/cursor.agent.ts (1)
84-114: Consider logging the actual error when authentication check fails.When
checkStatuscatches an error during themodelscommand, it only returns the message but doesn't log it. For debugging purposes, logging the actual error would be helpful.📝 Suggested improvement
} catch (error: unknown) { const err = error as Error; + logger.debug(`[CursorAgent] Auth check failed: ${err.message}`); return { ready: false, error: `Failed to check auth: ${err.message}` }; }src/services/agents/aider.agent.ts (1)
55-82: Duplicate API key checks betweencheckStatusandexecute.The API key validation logic (lines 65-73) is duplicated in
execute(lines 98-106). Consider extracting this to a private helper method to improve maintainability.src/services/agents/native.agent.ts (2)
114-123: Whitespace trimming on file content may alter intended formatting.Line 115 trims the content with
.trim(), which could remove intentional leading/trailing whitespace or newlines in source files. For code files, trailing newlines are often required by linters (e.g., POSIX compliance). Consider preserving the original content or only trimming leading/trailing blank lines.💡 Preserve trailing newline
while ((match = FILE_BLOCK_REGEX.exec(response.text)) !== null) { const filePath = match[1].trim(); - const content = match[2].trim(); + // Trim leading whitespace but preserve trailing newline for POSIX compliance + const content = match[2].replace(/^\s*\n/, '').replace(/\s*$/, '\n'); if (filePath && content) {
153-161: Partial success returnssuccess: truebut error details may be lost.When errors occur but some files succeed (lines 163-167), the function logs a warning but continues to return
success: true(line 172). The error details are only appended to theoutputstring. Consider returningsuccess: falsewithmodifiedFilespopulated, or adding awarningsfield toAgentResultfor better error visibility.src/index.ts (1)
180-219: Async agent registration results are awaited but not checked.The
registerAgentWithDetectioncalls are awaited but their boolean return values (indicating CLI availability) are not used. Consider logging which CLI agents were detected vs not found for better observability during startup.💡 Log detection results
- await registerAgentWithDetection('claude-code', new ClaudeCodeAgent(), 'claude', { + const claudeAvailable = await registerAgentWithDetection('claude-code', new ClaudeCodeAgent(), 'claude', { displayName: 'Claude Code', isRecommended: true, isStable: true, description: "Anthropic's official Claude Code CLI", aliases: ['claude', 'claude-code', 'anthropic'], }); + if (!claudeAvailable) { + logger.debug('[plugin-code] Claude Code CLI not found'); + }src/services/lessons.service.ts (1)
154-155: Lesson ID generation has low collision resistance.The ID format
L${Date.now()}-${Math.random().toString(36).substring(2, 8)}uses only 6 random characters (~31 bits of entropy). While sufficient for most use cases, rapid sequential failures within the same millisecond could theoretically collide. Consider using a longer random suffix or a UUID.
| ### Proposed: `CODE_EXECUTION_STATUS` Provider | ||
|
|
||
| ```typescript | ||
| /** | ||
| * Provider that exposes current coding execution status. | ||
| * | ||
| * WHY: Orchestrator needs visibility into CODE action execution | ||
| * to make better progress estimates and detect stalemate. | ||
| */ | ||
| export const codeExecutionStatusProvider: Provider = { | ||
| name: 'CODE_EXECUTION_STATUS', | ||
| description: 'Current status of coding agent execution', | ||
|
|
||
| get: async (runtime: IAgentRuntime, message: Memory, state?: State) => { | ||
| const coderService = runtime.getService<CoderService>('coder'); | ||
| if (!coderService) { | ||
| return { | ||
| text: 'Coder service not available', | ||
| values: { available: false }, | ||
| }; | ||
| } | ||
|
|
||
| const status = coderService.getExecutionStatus(); | ||
|
|
||
| return { | ||
| text: formatStatus(status), | ||
| values: { | ||
| // Is a coding task currently running? | ||
| isExecuting: status.isExecuting, | ||
|
|
||
| // Which agent is being used? | ||
| agent: status.agent, // 'claude-code', 'cursor', 'native', etc. | ||
|
|
||
| // Current phase | ||
| phase: status.phase, // 'idle', 'planning', 'reading', 'writing', 'verifying' | ||
|
|
||
| // Files being worked on | ||
| currentFile: status.currentFile, | ||
| filesRead: status.filesRead, | ||
| filesWritten: status.filesWritten, | ||
|
|
||
| // Progress estimate (0-100) | ||
| progress: status.progress, | ||
|
|
||
| // Time elapsed | ||
| startedAt: status.startedAt, | ||
| elapsedMs: status.elapsedMs, | ||
|
|
||
| // Last action taken | ||
| lastAction: status.lastAction, | ||
| }, | ||
| data: status, | ||
| }; | ||
| }, | ||
| }; | ||
| ``` | ||
|
|
||
| ### What CoderService Needs to Track | ||
|
|
||
| ```typescript | ||
| interface ExecutionStatus { | ||
| // Execution state | ||
| isExecuting: boolean; | ||
| agent: string | null; | ||
| conversationId: string | null; | ||
|
|
||
| // Phase tracking | ||
| phase: 'idle' | 'planning' | 'reading' | 'writing' | 'verifying'; | ||
|
|
||
| // File tracking | ||
| currentFile: string | null; | ||
| filesRead: string[]; | ||
| filesWritten: string[]; | ||
|
|
||
| // Progress | ||
| progress: number; // 0-100 estimate | ||
|
|
||
| // Timing | ||
| startedAt: number | null; | ||
| elapsedMs: number; | ||
|
|
||
| // History (last few actions for context) | ||
| lastAction: string | null; | ||
| recentActions: string[]; | ||
| } | ||
| ``` | ||
|
|
||
| ### How Agents Update Status | ||
|
|
||
| Each agent implementation should call status updates: | ||
|
|
||
| ```typescript | ||
| // In NativeCoderAgent.execute(): | ||
| async execute(params: ExecuteParams, runtime: IAgentRuntime): Promise<AgentResult> { | ||
| const coderService = runtime.getService<CoderService>('coder'); | ||
|
|
||
| // Start | ||
| coderService.updateStatus({ | ||
| isExecuting: true, | ||
| agent: 'native', | ||
| phase: 'planning', | ||
| progress: 10, | ||
| }); | ||
|
|
||
| // Reading files | ||
| coderService.updateStatus({ | ||
| phase: 'reading', | ||
| currentFile: 'src/auth.ts', | ||
| progress: 30, | ||
| }); | ||
|
|
||
| // Writing | ||
| coderService.updateStatus({ | ||
| phase: 'writing', | ||
| currentFile: 'src/auth.ts', | ||
| filesWritten: ['src/auth.ts'], | ||
| progress: 70, | ||
| }); | ||
|
|
||
| // Done | ||
| coderService.updateStatus({ | ||
| isExecuting: false, | ||
| phase: 'idle', | ||
| progress: 100, | ||
| }); | ||
|
|
||
| return result; | ||
| } | ||
| ``` | ||
|
|
||
| ### For CLI Agents (claude, cursor, etc.) | ||
|
|
||
| CLI agents can update status based on output parsing: | ||
|
|
||
| ```typescript | ||
| // In ClaudeCodeAgent.execute(): | ||
| async execute(params: ExecuteParams, runtime: IAgentRuntime): Promise<AgentResult> { | ||
| const coderService = runtime.getService<CoderService>('coder'); | ||
|
|
||
| coderService.updateStatus({ | ||
| isExecuting: true, | ||
| agent: 'claude-code', | ||
| phase: 'planning', | ||
| }); | ||
|
|
||
| // Stream CLI output and parse for status updates | ||
| const process = spawn('claude', [...]); | ||
|
|
||
| process.stdout.on('data', (data) => { | ||
| const output = data.toString(); | ||
|
|
||
| // Parse for file operations | ||
| if (output.includes('Reading')) { | ||
| const file = parseFileName(output); | ||
| coderService.updateStatus({ | ||
| phase: 'reading', | ||
| currentFile: file, | ||
| filesRead: [...status.filesRead, file], | ||
| }); | ||
| } | ||
|
|
||
| if (output.includes('Writing')) { | ||
| const file = parseFileName(output); | ||
| coderService.updateStatus({ | ||
| phase: 'writing', | ||
| currentFile: file, | ||
| filesWritten: [...status.filesWritten, file], | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| // ... | ||
| } | ||
| ``` |
There was a problem hiding this comment.
Align the examples with the actual ExecutionTrackerService and ExecutionStatus types.
The doc samples use CoderService.updateStatus() / coderService.getExecutionStatus() and an older interface shape (nullable fields, missing phases/actionHistory). The implementation now uses ExecutionTrackerService plus ExecutionPhase values like starting, completing, and error, and actionHistory in ExecutionStatus. Please update the snippets and field lists to match src/services/executionTracker.service.ts and src/types/execution.ts so integrators aren’t misled.
🤖 Prompt for AI Agents
In `@ORCHESTRATOR_INTEGRATION.md` around lines 29 - 202, Replace the old
CoderService examples with the actual ExecutionTrackerService API: in the
codeExecutionStatusProvider sample and agent snippets, get the service via
runtime.getService<ExecutionTrackerService>('executionTracker') and call the
real methods (e.g., getExecutionStatus / updateExecutionStatus) rather than
coderService.getExecutionStatus/updateStatus; switch phase/string values to the
real ExecutionPhase enums (including starting, completing, error) instead of
'idle'|'planning'|'reading'|'writing'|'verifying'; replace nullable/legacy
fields with the actual ExecutionStatus shape from src/types/execution.ts
(include actionHistory instead of recentActions, adjust timing/identifier fields
to match the type), and update NativeCoderAgent.execute and
ClaudeCodeAgent.execute examples to call
ExecutionTrackerService.updateExecutionStatus with the new phase values and
actionHistory updates when parsing CLI output.
| | Without Status | With Status | | ||
| |---------------|-------------| | ||
| | "CODE succeeded" | "CODE succeeded: wrote 3 files in 12s using claude-code" | | ||
| | Progress: guess | Progress: based on files read/written | | ||
| | Stalemate: after 3 failures | Stalemate: detect stuck at "reading" phase | | ||
| | User sees: "Running..." | User sees: "Writing src/auth.ts..." | |
There was a problem hiding this comment.
Fix table pipe spacing to satisfy markdownlint MD060.
The separator row is missing spaces around pipes.
🧹 Table separator formatting
-|---------------|-------------|
+| ------------- | ----------- |📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| | Without Status | With Status | | |
| |---------------|-------------| | |
| | "CODE succeeded" | "CODE succeeded: wrote 3 files in 12s using claude-code" | | |
| | Progress: guess | Progress: based on files read/written | | |
| | Stalemate: after 3 failures | Stalemate: detect stuck at "reading" phase | | |
| | User sees: "Running..." | User sees: "Writing src/auth.ts..." | | |
| | Without Status | With Status | | |
| | ------------- | ----------- | | |
| | "CODE succeeded" | "CODE succeeded: wrote 3 files in 12s using claude-code" | | |
| | Progress: guess | Progress: based on files read/written | | |
| | Stalemate: after 3 failures | Stalemate: detect stuck at "reading" phase | | |
| | User sees: "Running..." | User sees: "Writing src/auth.ts..." | |
🧰 Tools
🪛 markdownlint-cli2 (0.20.0)
[warning] 239-239: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 239-239: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 239-239: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 239-239: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
🤖 Prompt for AI Agents
In `@ORCHESTRATOR_INTEGRATION.md` around lines 238 - 243, The Markdown table
separator row in ORCHESTRATOR_INTEGRATION.md is missing spaces around the pipe
characters which violates markdownlint MD060; update the separator row between
the header and body so each pipe has a single space before and after it (i.e.,
change "|---------------|-------------|" to use " | " spacing consistent with
the header and rows), ensuring the separator aligns with the header columns for
the table shown under the "Without Status | With Status" heading.
| | Variable | Description | Required | Default | | ||
| |----------|-------------|----------|---------| | ||
| | `CODER_ENABLED` | Enable/disable the plugin | No | `false` | | ||
| | `CODER_ALLOWED_DIRECTORY` | Directory for operations | Yes | `process.cwd()` | | ||
| | `CODER_TIMEOUT` | Command timeout (ms) | No | `30000` | | ||
| | `CODER_FORBIDDEN_COMMANDS` | Additional forbidden commands (comma-separated) | No | - | | ||
| | `CODER_FORBIDDEN_COMMANDS` | Additional forbidden commands | No | - | | ||
|
|
||
| ### AI Agent Settings | ||
|
|
||
| | Variable | Description | Values | Default | | ||
| |----------|-------------|--------|---------| | ||
| | `CODE_MODE` | Agent selection mode | `auto`, `native`, `cli` | `auto` | | ||
| | `CODE_CLAUDE_MODEL` | Model for Claude Code | Model name | - | | ||
| | `CODE_CURSOR_MODEL` | Model for Cursor | Model name | - | | ||
| | `CODE_AIDER_MODEL` | Model for Aider | Provider/model | - | | ||
| | `CODE_CODEX_MODEL` | Model for Codex | Model name | - | | ||
| | `CODE_OPENCODE_MODEL` | Model for OpenCode | Model name | - | | ||
|
|
There was a problem hiding this comment.
Normalize table pipe spacing to satisfy MD060.
markdownlint flags table column style inconsistencies across the README tables. Please normalize pipe spacing to the configured style (or run your markdown formatter).
Also applies to: 76-105, 110-123, 131-142
🧰 Tools
🪛 markdownlint-cli2 (0.20.0)
[warning] 38-38: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 38-38: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 38-38: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 38-38: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 38-38: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 38-38: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 38-38: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 38-38: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 47-47: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 47-47: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 47-47: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 47-47: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 47-47: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 47-47: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 47-47: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 47-47: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
🤖 Prompt for AI Agents
In `@README.md` around lines 37 - 54, The markdown tables in README (e.g., rows
with headers like CODER_ENABLED, CODER_ALLOWED_DIRECTORY and CODE_MODE,
CODE_CLAUDE_MODEL, etc.) have inconsistent pipe spacing triggering MD060; update
each table to use a consistent pipe-spacing style (for example, single space
before and after each cell delimiter) across all tables (including the sections
you noted and the ones at lines ~76-105, 110-123, 131-142) by normalizing the
pipe spacing or running the project's markdown formatter so every cell follows
the same " | cell | " pattern.
| ## How CODE_MODE Works | ||
|
|
||
| ``` | ||
| User: "fix the bug in utils.ts" | ||
| | | ||
| v | ||
| CODE action | ||
| | | ||
| v | ||
| Check CODE_MODE | ||
| | | ||
| +---+---+ | ||
| | | | ||
| auto native/cli | ||
| | | | ||
| v v | ||
| Prefer CLI → Native fallback | ||
| | | ||
| v | ||
| Execute with selected agent | ||
| | | ||
| v | ||
| Return result (success/failure) | ||
| ``` |
There was a problem hiding this comment.
Add language identifiers to the ASCII diagrams.
markdownlint (MD040) requires fenced blocks to declare a language; text works well for diagrams.
💡 Suggested fix
-```
+```text
User: "fix the bug in utils.ts"
|
v
CODE action
|
v
Check CODE_MODE
|
+---+---+
| |
auto native/cli
| |
v v
Prefer CLI → Native fallback
|
v
Execute with selected agent
|
v
Return result (success/failure)- +text
plugin-code
├── Services
│ ├── CoderService # File ops, shell, working directory
│ ├── AgentRegistry # Manages all coding agents
│ ├── ExecutionTrackerService # Tracks execution status per conversation
│ ├── LessonsService # Tracks failures
│ └── StatsService # Tracks performance
├── Agents
│ ├── NativeCoderAgent # elizaOS LLM + file actions
│ ├── ClaudeCodeAgent # Claude Code CLI
│ ├── CursorAgent # Cursor Agent CLI
│ ├── AiderAgent # Aider CLI
│ ├── CodexAgent # Codex CLI
│ └── OpenCodeAgent # OpenCode CLI
├── Actions
│ ├── File ops # read, write, edit, etc.
│ ├── Agent actions # CODE, CLAUDE_CODE, etc.
│ └── PRR actions # VIEW_LESSONS, SHOW_STATS
└── Providers
├── coderStatusProvider # Core status
├── help.provider # Usage instructions
├── settings.provider # Configuration
├── executionStatus.provider # 3 resolutions (for orchestrator)
├── agents.providers # 3 resolutions
├── lessons.providers # 3 resolutions
└── stats.providers # 3 resolutions
</details>
Also applies to: 190-217
<details>
<summary>🧰 Tools</summary>
<details>
<summary>🪛 markdownlint-cli2 (0.20.0)</summary>
[warning] 147-147: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
</details>
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
In @README.md around lines 145 - 168, Update the ASCII art fenced code blocks in
README.md to include a language identifier (use "text") to satisfy markdownlint
MD040; specifically add text at the start of the CODE_MODE diagram and the plugin-code diagram (the blocks containing the "User: 'fix the bug in utils.ts' ... Check CODE_MODE" flow and the "plugin-code ├── Services ..." tree) so both diagrams declare a language instead of bare fences.
</details>
<!-- fingerprinting:phantom:poseidon:eagle -->
<!-- This is an auto-generated comment by CodeRabbit -->
| if (status.filesRead.length > 0) { | ||
| lines.push(''); | ||
| lines.push('**Files Read:**'); | ||
| status.filesRead.forEach((f) => lines.push(` - ${f}`)); | ||
| } | ||
|
|
||
| if (status.filesWritten.length > 0) { | ||
| lines.push(''); | ||
| lines.push('**Files Written:**'); | ||
| status.filesWritten.forEach((f) => lines.push(` - ${f}`)); | ||
| } |
There was a problem hiding this comment.
Fix Biome error: forEach callbacks must not return values.
The current arrow expression returns lines.push(...), triggering the lint error.
✅ Lint‑safe loop bodies
- status.filesRead.forEach((f) => lines.push(` - ${f}`));
+ status.filesRead.forEach((f) => {
+ lines.push(` - ${f}`);
+ });
...
- status.filesWritten.forEach((f) => lines.push(` - ${f}`));
+ status.filesWritten.forEach((f) => {
+ lines.push(` - ${f}`);
+ });📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (status.filesRead.length > 0) { | |
| lines.push(''); | |
| lines.push('**Files Read:**'); | |
| status.filesRead.forEach((f) => lines.push(` - ${f}`)); | |
| } | |
| if (status.filesWritten.length > 0) { | |
| lines.push(''); | |
| lines.push('**Files Written:**'); | |
| status.filesWritten.forEach((f) => lines.push(` - ${f}`)); | |
| } | |
| if (status.filesRead.length > 0) { | |
| lines.push(''); | |
| lines.push('**Files Read:**'); | |
| status.filesRead.forEach((f) => { | |
| lines.push(` - ${f}`); | |
| }); | |
| } | |
| if (status.filesWritten.length > 0) { | |
| lines.push(''); | |
| lines.push('**Files Written:**'); | |
| status.filesWritten.forEach((f) => { | |
| lines.push(` - ${f}`); | |
| }); | |
| } |
🧰 Tools
🪛 Biome (2.3.13)
[error] 90-90: This callback passed to forEach() iterable method should not return a value.
Either remove this return or remove the returned value.
(lint/suspicious/useIterableCallbackReturn)
[error] 96-96: This callback passed to forEach() iterable method should not return a value.
Either remove this return or remove the returned value.
(lint/suspicious/useIterableCallbackReturn)
🤖 Prompt for AI Agents
In `@src/providers/executionStatus.provider.ts` around lines 87 - 97, The forEach
callbacks on status.filesRead and status.filesWritten currently use concise
arrow expressions that implicitly return the result of lines.push(...) which
triggers the Biome lint error; change those callbacks to use block bodies (or
replace with a for...of loop) and call lines.push(...) as a statement (no return
value) so the callback does not return anything—update the two occurrences that
iterate over status.filesRead and status.filesWritten and ensure you still push
the same formatted strings (e.g., ` - ${f}`) into the lines array.
| const allowedDir = this.coderConfig.allowedDirectory; // Use base config for search | ||
| for (let i = 0; i < lines.length; i++) { | ||
| if (matches.length >= maxMatches) break; | ||
| const line = lines[i] ?? ''; | ||
| if (!line.toLowerCase().includes(needleLower)) continue; | ||
| matches.push({ | ||
| file: path.relative(this.coderConfig.allowedDirectory, full), | ||
| file: path.relative(allowedDir, full), |
There was a problem hiding this comment.
Potential path inconsistency when workspace is active.
searchInDirectory uses this.coderConfig.allowedDirectory (the static base config) for computing relative file paths in results, while resolveWithin uses the dynamic getAllowedDirectory(conversationId).
If a workspace is active, search results will show paths relative to the base config directory rather than the active workspace, which could be confusing to users. Consider using the same dynamic directory for consistency, or document that search results always use the base config path.
🔧 Suggested fix for path consistency
private async searchInDirectory(
dir: string,
needleLower: string,
matches: Array<{ file: string; line: number; content: string }>,
- maxMatches: number
+ maxMatches: number,
+ allowedDir: string
): Promise<void> {
// ...
- const allowedDir = this.coderConfig.allowedDirectory; // Use base config for search
for (let i = 0; i < lines.length; i++) {Then pass allowedDir from searchFiles:
- await this.searchInDirectory(resolved.fullPath, needle.toLowerCase(), matches, limit);
+ const allowedDir = this.getAllowedDirectory(conversationId);
+ await this.searchInDirectory(resolved.fullPath, needle.toLowerCase(), matches, limit, allowedDir);🤖 Prompt for AI Agents
In `@src/services/coderService.ts` around lines 327 - 333, searchInDirectory is
using this.coderConfig.allowedDirectory to compute relative file paths, causing
inconsistency when a workspace is active because
resolveWithin/getAllowedDirectory(conversationId) uses the dynamic allowed dir;
update the code so the dynamic allowed directory from
getAllowedDirectory(conversationId) is used for relative paths instead of
this.coderConfig.allowedDirectory—either compute allowedDir once in searchFiles
(via getAllowedDirectory) and pass it into searchInDirectory, or change
searchInDirectory to accept a conversationId and call getAllowedDirectory
itself; adjust references to allowedDir when building results (path.relative) to
use the dynamic value and keep resolveWithin, searchFiles, searchInDirectory,
and getAllowedDirectory consistent.
| private async initialize(runtime: IAgentRuntime): Promise<void> { | ||
| // Get project root from CoderService | ||
| const coderService = runtime.getService<CoderService>('coder'); | ||
| if (coderService) { | ||
| const projectRoot = coderService.getAllowedDirectory(); | ||
| this.storagePath = path.join(projectRoot, '.plugin-code', 'lessons.json'); | ||
| } | ||
|
|
||
| // Load existing lessons if file exists | ||
| await this.load(); | ||
| } |
There was a problem hiding this comment.
Service initialization may fail silently if CoderService is not yet started.
The initialize method depends on CoderService being available via runtime.getService('coder'). If CoderService starts after LessonsService (service ordering), storagePath remains empty and lessons won't persist. Consider adding a warning log when CoderService is unavailable.
🔧 Suggested improvement
private async initialize(runtime: IAgentRuntime): Promise<void> {
// Get project root from CoderService
const coderService = runtime.getService<CoderService>('coder');
if (coderService) {
const projectRoot = coderService.getAllowedDirectory();
this.storagePath = path.join(projectRoot, '.plugin-code', 'lessons.json');
+ } else {
+ logger.warn('[LessonsService] CoderService not available - lessons will not persist to disk');
}
// Load existing lessons if file exists
await this.load();
}🤖 Prompt for AI Agents
In `@src/services/lessons.service.ts` around lines 78 - 88, The initialize method
can silently leave storagePath empty if CoderService isn't available; modify
initialize( runtime: IAgentRuntime ) so that when
runtime.getService<CoderService>('coder') returns undefined you emit a visible
warning (e.g., this.logger.warn(...) or console.warn(...)) and set a safe
fallback storagePath (for example path.join(process.cwd(), '.plugin-code',
'lessons.json')) before calling this.load(); keep references to initialize,
IAgentRuntime, getService, CoderService, storagePath and load so the change is
easy to locate.
| toCSV(): string { | ||
| const lines = ['id,timestamp,agent,error']; | ||
| for (const lesson of this.lessons.slice(-50)) { | ||
| // Last 50 for CSV | ||
| const error = lesson.error.replace(/"/g, '""').substring(0, 100); | ||
| lines.push(`${lesson.id},${lesson.timestamp},${lesson.agent},"${error}"`); | ||
| } | ||
| return lines.join('\n'); |
There was a problem hiding this comment.
CSV export doesn't escape commas in error messages.
The toCSV method escapes double quotes but doesn't handle commas within the error field. If an error message contains a comma, it will break CSV parsing.
🔧 Wrap error field in quotes regardless of content
The current code already wraps the error in quotes, which handles commas. However, newlines in error messages could still break CSV rows. Consider also replacing newlines:
toCSV(): string {
const lines = ['id,timestamp,agent,error'];
for (const lesson of this.lessons.slice(-50)) {
// Last 50 for CSV
- const error = lesson.error.replace(/"/g, '""').substring(0, 100);
+ const error = lesson.error.replace(/"/g, '""').replace(/[\r\n]+/g, ' ').substring(0, 100);
lines.push(`${lesson.id},${lesson.timestamp},${lesson.agent},"${error}"`);
}
return lines.join('\n');
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| toCSV(): string { | |
| const lines = ['id,timestamp,agent,error']; | |
| for (const lesson of this.lessons.slice(-50)) { | |
| // Last 50 for CSV | |
| const error = lesson.error.replace(/"/g, '""').substring(0, 100); | |
| lines.push(`${lesson.id},${lesson.timestamp},${lesson.agent},"${error}"`); | |
| } | |
| return lines.join('\n'); | |
| toCSV(): string { | |
| const lines = ['id,timestamp,agent,error']; | |
| for (const lesson of this.lessons.slice(-50)) { | |
| // Last 50 for CSV | |
| const error = lesson.error.replace(/"/g, '""').replace(/[\r\n]+/g, ' ').substring(0, 100); | |
| lines.push(`${lesson.id},${lesson.timestamp},${lesson.agent},"${error}"`); | |
| } | |
| return lines.join('\n'); | |
| } |
🤖 Prompt for AI Agents
In `@src/services/lessons.service.ts` around lines 244 - 251, The toCSV() export
currently escapes double quotes but leaves newlines (and potentially CRLF)
inside lesson.error which can break CSV rows; update the error normalization in
toCSV (referencing toCSV(), this.lessons, and lesson.error) to first replace CR
and LF (e.g., .replace(/\r?\n/g, ' ')), then escape quotes (.replace(/"/g,
'""')), then substring to 100 chars, and continue wrapping the field in quotes
as already done so CSV rows remain intact even when errors contain newlines or
commas.
| **From Git Repository:** | ||
| ``` | ||
| "Clone https://github.com/facebook/react" | ||
| "Clone the Next.js repo from GitHub" | ||
| "Import https://github.com/user/repo branch develop" | ||
| ``` | ||
|
|
||
| **From Archive:** | ||
| ``` | ||
| "Import project from https://example.com/project.zip" | ||
| "Extract this archive: https://example.com/app.tar.gz" | ||
| ``` | ||
|
|
||
| **Local Workspace:** | ||
| ``` | ||
| "Create local workspace named my-project" | ||
| "Create a new workspace called test-app" | ||
| ``` | ||
|
|
There was a problem hiding this comment.
Add language identifiers to fenced example blocks.
markdownlint (MD040) flags fenced blocks without a language tag. Use text for prompt examples (and apply similarly to other unlabeled fences in this doc).
💡 Suggested fix
-```
+```text
"Clone https://github.com/facebook/react"
"Clone the Next.js repo from GitHub"
"Import https://github.com/user/repo branch develop"- +text
"Import project from https://example.com/project.zip"
"Extract this archive: https://example.com/app.tar.gz"
-```
+```text
"Create local workspace named my-project"
"Create a new workspace called test-app"
🧰 Tools
🪛 markdownlint-cli2 (0.20.0)
[warning] 77-77: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 77-77: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 77-77: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 77-77: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 77-77: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 77-77: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 90-90: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 90-90: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 90-90: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 90-90: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
[warning] 90-90: Table column style
Table pipe is missing space to the right for style "compact"
(MD060, table-column-style)
[warning] 90-90: Table column style
Table pipe is missing space to the left for style "compact"
(MD060, table-column-style)
🤖 Prompt for AI Agents
In `@WORKSPACES.md` around lines 73 - 91, Add language identifiers ("text") to the
three fenced code blocks under the headings "From Git Repository", "From
Archive", and "Local Workspace" so markdownlint MD040 is satisfied; update the
opening fences for each unlabeled block to use ```text (the blocks containing
the repository clone/import examples, the archive import/extract examples, and
the local workspace creation examples).
| | Feature | Eliza Workspaces | GitHub Codespaces | Replit | VS Code Dev Containers | | ||
| |---------|------------------|-------------------|--------|------------------------| | ||
| | **Chat Interface** | ✅ | ❌ | ❌ | ❌ | | ||
| | **Git Clone** | ✅ | ✅ | ✅ | ✅ | | ||
| | **Archive Import** | ✅ | ❌ | ✅ | ❌ | | ||
| | **Local Creation** | ✅ | ❌ | ✅ | ✅ | | ||
| | **Auto-Detection** | ✅ | ✅ | ✅ | ✅ | | ||
| | **Multi-Workspace** | ✅ | ✅ | ✅ | ❌ | | ||
| | **Offline Mode** | ✅ | ❌ | ❌ | ✅ | | ||
| | **AI Coding Agents** | ✅ | ❌ | ❌ | ❌ | | ||
|
|
There was a problem hiding this comment.
Normalize table pipe spacing to satisfy MD060.
markdownlint reports table column style issues in the comparison table; align spacing to your configured table style (or run your markdown formatter).
🤖 Prompt for AI Agents
In `@WORKSPACES.md` around lines 372 - 382, The comparison table starting with the
header "| Feature | Eliza Workspaces | GitHub Codespaces | Replit | VS Code Dev
Containers |" has inconsistent pipe spacing and triggers MD060; normalize the
table by aligning the pipe characters and cell padding to your project's
markdown table style (e.g., ensure a single space after and before each pipe or
run your markdown formatter), making the header, separator row, and all data
rows follow the same column padding so markdownlint no longer reports MD060.
Resolved conflict in WORKSPACES.md between local and remote branches. Both added the file with same content but different capitalization. Kept correct capitalization: elizaOS (not ElizaOS). Co-authored-by: Cursor <cursoragent@cursor.com>
- description: "elizaos" → "elizaOS" (lowercase eliza, capital OS) - pluginType: "elizaos:plugin" → "elizaOS:plugin" Per project style guide, the correct capitalization is "elizaOS" not "elizaos". Co-authored-by: Cursor <cursoragent@cursor.com>
Summary by CodeRabbit
New Features
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.