diff --git a/.agents/README.md b/.agents/README.md new file mode 100644 index 0000000..8c4a5ca --- /dev/null +++ b/.agents/README.md @@ -0,0 +1,302 @@ +# Multi-Agent Development System + +## Problem Context + +When a codebase has multiple issues that need to be fixed simultaneously, traditional sequential development becomes inefficient. Working on all issues in the same branch creates conflicts and makes it difficult to track individual fixes. This system addresses these challenges by providing isolated development environments for parallel work. + +## How It Works + +This system uses git worktrees to create separate working copies of the repository, each isolated from the others. Each worktree is assigned to a specific bug fix, allowing multiple Claude Code sessions to work on different issues simultaneously without conflicts. + +The entire system configuration is stored in `todos.yaml`, which defines: +- Individual TODO items with detailed agent prompts +- Phases that group related work +- Git configuration (branches, worktree directories, tmux session names) +- Workflow orchestration rules + +Scripts read this YAML configuration to dynamically create worktrees, launch tmux sessions, and manage the development workflow. + +## System Architecture + +- **Git Worktrees**: Isolated copies of the repository for each TODO item +- **YAML Configuration**: Central definition of all tasks, phases, and settings +- **Tmux Sessions**: Parallel Claude Code instances, one per worktree +- **Bash Scripts**: Automation for setup, session management, and cleanup +- **Utility Layer**: Shared functions for YAML parsing and validation + +## Configuration Schema + +The `todos.yaml` file contains four main sections: + +### Global Configuration +```yaml +config: + worktree_base_dir: "../rules_antlr-worktrees" + tmux_session_prefix: "rules-antlr" + default_branch_base: "main" +``` + +### Phases +Groups of related TODO items with execution metadata: +```yaml +phases: + high_priority: + name: "High Priority Fixes" + priority: 1 + parallel: true + description: "Critical issues that need immediate attention" +``` + +### TODO Items +Individual tasks with detailed configuration: +```yaml +todos: + - id: "TODO-001" + title: "Fix Type A" + phase: "high_priority" + priority: "CRITICAL" + git: + branch: "fix/issue-type-a" + worktree_dir: "fix-a" + tmux_session: "project-fix-a" + files: + - "src/main/java/com/example/Component.java:88-99" + agent_prompt: |- + [Detailed multiline prompt with implementation steps, + context, and verification requirements] +``` + +### Agent Types +Specialization definitions for different types of fixes: +```yaml +agent_types: + Bug-Specialist: + description: "Focuses on specific vulnerability types" + expertise: ["error handling", "defensive programming"] +``` + +## Dependencies + +### Required +- **Git** (with worktree support) +- **Bash** 4.0 or later +- **Claude Code CLI** + +### Optional +- **yq** - For YAML parsing (enables full functionality) +- **tmux** - For session management (enables parallel workflow) +- **GitHub CLI** (gh) - For automated PR creation + +### Installation +```bash +# macOS +brew install yq tmux gh + +# Ubuntu/Debian +sudo apt-get install yq tmux gh + +# Arch Linux +sudo pacman -S yq tmux github-cli +``` + +## Usage + +### 1. Environment Setup +```bash +./setup-worktrees.sh +``` + +Creates git worktrees for all active TODO items defined in `todos.yaml`. Each worktree is created in a separate directory with its own branch. + +### 2. Start Development Sessions +```bash +# Start specific phase +./run-parallel-claude.sh high_priority + +# Start all phases +./run-parallel-claude.sh all + +# View available phases +./run-parallel-claude.sh +``` + +### 3. Session Management +```bash +# Check active sessions +./run-parallel-claude.sh status + +# Connect to specific session +tmux attach -t project-fix-a + +# Kill all sessions +./run-parallel-claude.sh kill +``` + +### 4. Pull Request Creation +```bash +# Check status of all worktrees +./merge-workflow.sh status + +# Create PRs for completed work +./merge-workflow.sh high_priority +./merge-workflow.sh all +``` + +### 5. Environment Cleanup +```bash +# Remove everything +./cleanup-worktrees.sh all + +# Selective cleanup +./cleanup-worktrees.sh sessions # Kill tmux sessions only +./cleanup-worktrees.sh worktrees # Remove worktrees only +./cleanup-worktrees.sh branches # Delete git branches only +``` + +## File Structure + +``` +.agents/ +├── todos.yaml # Central configuration file +├── yaml-utils.sh # Shared YAML parsing utilities +├── setup-worktrees.sh # Creates git worktrees from YAML +├── run-parallel-claude.sh # Launches Claude sessions in tmux +├── merge-workflow.sh # Manages PR creation and merging +├── cleanup-worktrees.sh # Environment cleanup +└── README.md # This documentation +``` + +### Script Functions + +**setup-worktrees.sh** +- Reads TODO items from YAML +- Creates git worktrees in configured directories +- Sets up branches for each TODO item +- Copies configuration files to each worktree + +**run-parallel-claude.sh** +- Launches tmux sessions for TODO items in a phase +- Starts Claude Code in each worktree directory +- Provides session status and management commands +- Handles session cleanup + +**merge-workflow.sh** +- Checks worktree status and commit readiness +- Runs tests in each worktree (if configured) +- Creates GitHub pull requests with detailed descriptions +- Manages merge workflow coordination + +**cleanup-worktrees.sh** +- Removes git worktrees and their directories +- Kills tmux sessions +- Deletes git branches (local and remote) +- Cleans up temporary files + +## YAML Utility Functions + +The `yaml-utils.sh` file provides functions for working with configuration data: + +```bash +source "./yaml-utils.sh" +init_yaml_utils "todos.yaml" + +# Configuration queries +get_config "worktree_base_dir" # Get config values +get_fallback_config "tmux_session_prefix" # Get defaults + +# TODO queries +get_all_todo_indices # List all TODO indices +get_todo_field 0 "title" # Get specific TODO field +is_todo_active 0 # Check if TODO is not cancelled + +# Phase queries +get_all_phases # Get phases by priority +get_phase_todo_indices "high_priority" # Get TODOs in a phase +validate_phase "high_priority" # Check if phase exists + +# Validation +validate_yaml_schema # Validate YAML structure +show_yaml_status # Show configuration info +``` + +## Configuration + +### Adding TODO Items + +Edit `todos.yaml` to add new tasks: + +```yaml +todos: + - id: "TODO-011" + title: "New Task" + description: "Task description" + phase: "quality" + priority: "MEDIUM" + git: + branch: "fix/new-task" + worktree_dir: "new-task" + tmux_session: "rules-antlr-new-task" + agent_prompt: |- + Detailed instructions for the task... +``` + +Run `./setup-worktrees.sh` to create the new worktree. + +### Adding Phases + +Define new phases in `todos.yaml`: + +```yaml +phases: + performance: + name: "Performance Optimizations" + description: "Speed and memory improvements" + priority: 5 + parallel: true +``` + +All scripts automatically recognize new phases defined in the YAML file. + +### Project Adaptation + +To use this system for other projects: + +1. Replace `todos.yaml` with your project's tasks and phases +2. Update the `config` section with your preferred paths and naming +3. Modify agent prompts and fix strategies for your specific issues +4. Scripts will automatically adapt to the new configuration + +## Current Configuration + +The current tasks and phases are defined in `todos.yaml`. Check that file for: + +- **Active TODO Items** - Specific tasks with detailed prompts and fix strategies +- **Phase Definitions** - Groups of related work with priority and execution rules +- **Agent Specializations** - Types of expertise assigned to different categories of work + +The YAML file serves as the single source of truth for all current work items and their configuration. + +## Limitations + +- Requires yq for full functionality (falls back to limited features without it) +- Tmux sessions are local to the machine running the scripts +- Git worktrees share the same .git directory (objects and refs) +- Each worktree requires separate disk space for the working directory +- GitHub CLI integration requires authentication setup + +## Troubleshooting + +**Worktree creation fails** +- Ensure you're in the main repository (not already in a worktree) +- Check that branch names in YAML don't conflict with existing branches +- Verify you have write access to the parent directory + +**Session startup issues** +- Confirm tmux is installed and working +- Check that Claude Code CLI is in your PATH +- Verify worktree directories exist and are accessible + +**YAML parsing errors** +- Install yq or accept reduced functionality +- Validate YAML syntax using `yq eval '.' todos.yaml` +- Check for proper indentation and structure \ No newline at end of file diff --git a/.agents/TODO.md b/.agents/TODO.md new file mode 100644 index 0000000..3fd82d5 --- /dev/null +++ b/.agents/TODO.md @@ -0,0 +1,610 @@ +# rules_antlr Critical Bug Fixes - Multi-Agent TODO + +## Executive Summary + +This document outlines **19 critical vulnerabilities** discovered in the rules_antlr codebase requiring immediate attention: + +- **15 Critical NPE Vulnerabilities** - Could cause JVM crashes during build +- **2 High-Priority Bazel Logic Errors** - Break compatibility with newer Bazel versions +- **2 Medium-Priority Resource Leaks** - Gradual system degradation + +**Note**: TODO-005 was cancelled after validation - the claimed Starlark deprecation was incorrect. + +Each TODO item is structured for autonomous sub-agent execution with detailed prompts, file locations, fix instructions, and verification steps. + +## 🚀 Quick Start: Parallel Multi-Agent Workflow + +### Setup Worktrees (One-time) +```bash +./setup-worktrees.sh # Creates all git worktrees +``` + +### Launch Parallel Claude Sessions +```bash +./run-parallel-claude.sh critical # Start 4 critical NPE fix sessions (RECOMMENDED) +./run-parallel-claude.sh bazel # Start 2 Bazel compatibility sessions +./run-parallel-claude.sh resource # Start 2 resource management sessions +./run-parallel-claude.sh all # Start ALL 10 sessions (high resource usage) +``` + +### Attach to Individual Sessions +```bash +tmux attach -t rules-antlr-npe-env # TODO-001 +tmux attach -t rules-antlr-npe-builder # TODO-002 +tmux attach -t rules-antlr-npe-language # TODO-003 +tmux attach -t rules-antlr-npe-utility # TODO-004 +``` + +--- + +## Sub-Agent TODO Items + +### TODO-001: Environment Variable NPE Fixes (AntlrRules.java main method) +**Priority**: CRITICAL 🔴 +**Agent Type**: NPE-Specialist +**Branch**: `fix/npe-environment-variables` +**Dependencies**: None + +**🔧 Worktree Setup**: +```bash +# Automatic (via script): ./setup-worktrees.sh +# Manual: git worktree add ../rules_antlr-worktrees/npe-env fix/npe-environment-variables +``` + +**🤖 Claude Session**: +```bash +# Launch: ./run-parallel-claude.sh critical +# Manual: cd ../rules_antlr-worktrees/npe-env && claude +# Attach: tmux attach -t rules-antlr-npe-env +``` + +**Problem**: Multiple environment variables accessed without null checks in `main()` method, causing NPE when variables not set. + +**Files to Modify**: +- `src/main/java/org/antlr/bazel/AntlrRules.java:88-99` + +**Agent Prompt**: +``` +Fix critical NPE vulnerabilities in AntlrRules.java main method. The following lines access environment variables and immediately call methods without null checks: + +Line 90: env.get("TOOL_CLASSPATH").split(",") +Line 93: env.get("GRAMMARS").split(",") + +These will throw NPE if environment variables are not set. Add defensive null checks and provide meaningful error messages. + +Implementation steps: +1. Add null checks for each env.get() call +2. Throw IllegalStateException with descriptive message if required env vars missing +3. Consider providing default values where appropriate +4. Maintain existing builder pattern flow + +Verification: Create test that calls main() with missing environment variables and verify proper error handling instead of NPE. +``` + +**Fix Strategy**: +```java +// Replace: +.classpath(env.get("TOOL_CLASSPATH").split(",")) + +// With: +.classpath(getRequiredEnvVar(env, "TOOL_CLASSPATH").split(",")) + +private static String getRequiredEnvVar(Map env, String name) { + String value = env.get(name); + if (value == null) { + throw new IllegalStateException("Required environment variable not set: " + name); + } + return value; +} +``` + +--- + +### TODO-002: Builder Method Parameter NPE Fixes +**Priority**: CRITICAL 🔴 +**Agent Type**: NPE-Specialist +**Branch**: `fix/npe-builder-parameters` +**Dependencies**: None + +**🔧 Worktree Setup**: +```bash +# Automatic (via script): ./setup-worktrees.sh +# Manual: git worktree add ../rules_antlr-worktrees/npe-builder fix/npe-builder-parameters +``` + +**🤖 Claude Session**: +```bash +# Launch: ./run-parallel-claude.sh critical +# Manual: cd ../rules_antlr-worktrees/npe-builder && claude +# Attach: tmux attach -t rules-antlr-npe-builder +``` + +**Problem**: Builder methods call methods on parameters without null checks, causing NPE when null parameters passed. + +**Files to Modify**: +- `src/main/java/org/antlr/bazel/AntlrRules.java:129, 393, 401, 409, 426` + +**Agent Prompt**: +``` +Fix NPE vulnerabilities in AntlrRules builder methods. These methods call .isEmpty() or .trim() on parameters without null checks: + +- encoding(String encoding) - Line 129: encoding.isEmpty() +- language(String language) - Line 393: language.isEmpty() +- layout(String layout) - Line 401: layout.isEmpty() +- namespace(String namespace) - Line 409: namespace.isEmpty() +- srcjar(String srcjar) - Line 426: srcjar.trim().isEmpty() + +Add null guards at the beginning of each method. For null inputs, either return early with 'this' (no-op) or use appropriate default values. + +Verification: Write unit tests passing null to each builder method and verify no NPE thrown. +``` + +**Fix Strategy**: +```java +AntlrRules encoding(String encoding) { + if (encoding == null) return this; // or use default charset + this.encoding = encoding.isEmpty() ? Charset.defaultCharset() : Charset.forName(encoding); + return this; +} +``` + +--- + +### TODO-003: Language Path Conversion NPE Fixes +**Priority**: CRITICAL 🔴 +**Agent Type**: NPE-Specialist +**Branch**: `fix/npe-language-path-conversion` +**Dependencies**: None + +**🔧 Worktree Setup**: +```bash +# Automatic (via script): ./setup-worktrees.sh +# Manual: git worktree add ../rules_antlr-worktrees/npe-language fix/npe-language-path-conversion +``` + +**🤖 Claude Session**: +```bash +# Launch: ./run-parallel-claude.sh critical +# Manual: cd ../rules_antlr-worktrees/npe-language && claude +# Attach: tmux attach -t rules-antlr-npe-language +``` + +**Problem**: Language enum methods call `path.toString()` without null checks across multiple language implementations. + +**Files to Modify**: +- `src/main/java/org/antlr/bazel/Language.java:28, 59, 92, 127, 173, 213, 246, 277, 311, 356` + +**Agent Prompt**: +``` +Fix NPE vulnerabilities in Language enum toId() methods. Multiple language implementations call path.toString() without null checks: + +Affected methods in Language.java: +- C.toId() - Line 28 +- CPP.toId() - Line 59 +- CSHARP.toId() - Line 92 +- GO.toId() - Line 127 +- JAVA.toId() - Line 173 +- JAVASCRIPT.toId() - Line 213 +- OBJC.toId() - Line 246 +- PYTHON.toId() - Line 277 +- RUBY.toId() - Line 311 +- SWIFT.toId() - Line 356 + +Add null check at beginning of each toId() method and throw IllegalArgumentException with descriptive message. + +Verification: Test each language's toId() method with null Path parameter and verify proper exception thrown. +``` + +**Fix Strategy**: +```java +@Override +public String toId(Path path) { + if (path == null) { + throw new IllegalArgumentException("path cannot be null"); + } + return path.toString().replaceAll("[/\\\\]", "."); +} +``` + +--- + +### TODO-004: Utility Method NPE Fixes +**Priority**: CRITICAL 🔴 +**Agent Type**: NPE-Specialist +**Branch**: `fix/npe-utility-methods` +**Dependencies**: None + +**🔧 Worktree Setup**: +```bash +# Automatic (via script): ./setup-worktrees.sh +# Manual: git worktree add ../rules_antlr-worktrees/npe-utility fix/npe-utility-methods +``` + +**🤖 Claude Session**: +```bash +# Launch: ./run-parallel-claude.sh critical +# Manual: cd ../rules_antlr-worktrees/npe-utility && claude +# Attach: tmux attach -t rules-antlr-npe-utility +``` + +**Problem**: Switch statements in utility methods don't handle null inputs, causing NPE. + +**Files to Modify**: +- `src/main/java/org/antlr/bazel/Language.java:469` +- `src/main/java/org/antlr/bazel/Version.java:22` +- `src/main/java/org/antlr/bazel/Strings.java:26` + +**Agent Prompt**: +``` +Fix NPE vulnerabilities in utility methods that use switch statements without null checks: + +1. Language.of(String name) - Line 469: Switch on name without null check +2. Version.of(String version) - Line 22: Switch on version without null check +3. Strings.stripFileExtension(String path) - Line 26: path.lastIndexOf() without null check + +Add null checks before switch statements and string method calls. Throw IllegalArgumentException with descriptive messages. + +Verification: Test each method with null parameter and verify proper exception handling. +``` + +**Fix Strategy**: +```java +public static Language of(String name) { + if (name == null) { + throw new IllegalArgumentException("language name cannot be null"); + } + switch (name) { + // existing cases... + } +} +``` + +--- + +### TODO-005: ~~Bazel Starlark Dictionary Access Fix~~ [CANCELLED - INCORRECT] +**Priority**: ~~HIGH~~ CANCELLED ❌ +**Agent Type**: ~~Bazel-Specialist~~ +**Branch**: ~~`fix/bazel-dict-access`~~ +**Dependencies**: None + +**❌ CANCELLED: This TODO was based on incorrect information** + +**Analysis**: Research shows that `dict.keys()[0]` is **NOT deprecated** in any Bazel version: +- ✅ Current Bazel 7.5.0 documentation confirms `dict.keys()` returns a **list** that supports indexing +- ❌ No evidence found of deprecation in Bazel 6.0+ in official docs or release notes +- ⚠️ Starlark issue #203 discusses potential future changes but they are **not implemented** + +**Current Status**: The existing code `lib.keys()[0]` is **correct and valid** Bazel/Starlark syntax. + +**Files to Modify**: +- ~~`antlr/impl.bzl:134`~~ - NO CHANGES NEEDED + +**Original Incorrect Claim**: +~~"Dictionary key access uses deprecated syntax that breaks in Bazel 6.0+"~~ - **FALSE** + +**Resolution**: +- No code changes required +- The proposed fix `list(lib.keys())[0]` would add unnecessary overhead +- Current implementation follows documented Bazel/Starlark patterns + +--- + +### TODO-006: Bazel String Method Fix +**Priority**: HIGH 🟠 +**Agent Type**: Bazel-Specialist +**Branch**: `fix/bazel-string-methods` +**Dependencies**: None + +**🔧 Worktree Setup**: +```bash +# Automatic (via script): ./setup-worktrees.sh +# Manual: git worktree add ../rules_antlr-worktrees/bazel-string fix/bazel-string-methods +``` + +**🤖 Claude Session**: +```bash +# Launch: ./run-parallel-claude.sh bazel +# Manual: cd ../rules_antlr-worktrees/bazel-string && claude +# Attach: tmux attach -t rules-antlr-bazel-string +``` + +**Problem**: Non-existent `.elems()` method called on strings in error messages. + +**Files to Modify**: +- `antlr/repositories.bzl:198` +- `antlr/repositories.bzl:274` + +**Agent Prompt**: +``` +Fix Bazel Starlark errors in repositories.bzl. Two locations call non-existent .elems() method on strings: + +Line 198: ".".join(str(version_or_language).elems()) +Line 274: ".".join(str(version).elems()) + +The .elems() method doesn't exist on strings in Starlark. These should just use the string directly. + +Fix by removing .elems() calls and wrapping in list: +".".join([str(version_or_language)]) +".".join([str(version)]) + +Verification: +1. Test dependency loading with invalid versions to trigger error paths +2. Verify error messages are properly formatted +3. Ensure no Starlark runtime errors occur +``` + +--- + +### TODO-007: Resource Management - Process Stream Leaks +**Priority**: MEDIUM 🟡 +**Agent Type**: Resource-Specialist +**Branch**: `fix/process-stream-leaks` +**Dependencies**: None + +**🔧 Worktree Setup**: +```bash +# Automatic (via script): ./setup-worktrees.sh +# Manual: git worktree add ../rules_antlr-worktrees/resource-process fix/process-stream-leaks +``` + +**🤖 Claude Session**: +```bash +# Launch: ./run-parallel-claude.sh resource +# Manual: cd ../rules_antlr-worktrees/resource-process && claude +# Attach: tmux attach -t rules-antlr-resource-process +``` + +**Problem**: Process InputStream not properly closed, causing file handle leaks during testing. + +**Files to Modify**: +- `src/it/java/org/antlr/bazel/Command.java:104` + +**Agent Prompt**: +``` +Fix resource leak in Command.java build() method. Line 104 reads process InputStream without proper resource management: + +output = new String(p.getInputStream().readAllBytes()); + +This can cause file handle leaks during integration testing. Use try-with-resources to ensure proper cleanup. + +Fix by wrapping in try-with-resources: +try (InputStream is = p.getInputStream()) { + output = new String(is.readAllBytes()); +} + +Verification: +1. Run integration tests and monitor file handle usage +2. Verify no resource leaks using tools like lsof +3. Test with multiple concurrent Command executions +``` + +--- + +### TODO-008: Resource Management - File Stream Leaks +**Priority**: MEDIUM 🟡 +**Agent Type**: Resource-Specialist +**Branch**: `fix/file-stream-leaks` +**Dependencies**: None + +**🔧 Worktree Setup**: +```bash +# Automatic (via script): ./setup-worktrees.sh +# Manual: git worktree add ../rules_antlr-worktrees/resource-file fix/file-stream-leaks +``` + +**🤖 Claude Session**: +```bash +# Launch: ./run-parallel-claude.sh resource +# Manual: cd ../rules_antlr-worktrees/resource-file && claude +# Attach: tmux attach -t rules-antlr-resource-file +``` + +**Problem**: Files.walk() Stream not closed, causing file handle leaks in test setup. + +**Files to Modify**: +- `src/it/java/org/antlr/bazel/TestWorkspace.java:67` + +**Agent Prompt**: +``` +Fix resource leak in TestWorkspace constructor. Line 67 uses Files.walk() without proper resource management: + +Files.walk(examples) + .filter(path -> !Files.isDirectory(path)) + .forEach(source -> { ... }); + +Files.walk() returns a Stream that must be closed to prevent file handle leaks. Use try-with-resources. + +Fix by wrapping in try-with-resources: +try (Stream walk = Files.walk(examples)) { + walk.filter(path -> !Files.isDirectory(path)) + .forEach(source -> { ... }); +} + +Verification: +1. Create multiple TestWorkspace instances and monitor file handles +2. Verify proper cleanup using resource monitoring tools +3. Test with large directory structures to amplify any leaks +``` + +--- + +### TODO-009: Array Bounds Safety Improvements +**Priority**: MEDIUM 🟡 +**Agent Type**: Safety-Specialist +**Branch**: `fix/array-bounds-safety` +**Dependencies**: None + +**🔧 Worktree Setup**: +```bash +# Automatic (via script): ./setup-worktrees.sh +# Manual: git worktree add ../rules_antlr-worktrees/safety-bounds fix/array-bounds-safety +``` + +**🤖 Claude Session**: +```bash +# Launch: ./run-parallel-claude.sh quality +# Manual: cd ../rules_antlr-worktrees/safety-bounds && claude +# Attach: tmux attach -t rules-antlr-quality-bounds +``` + +**Problem**: Array access without bounds checking could cause IndexOutOfBoundsException. + +**Files to Modify**: +- `src/main/java/org/antlr/bazel/AntlrRules.java:553` + +**Agent Prompt**: +``` +Fix potential array bounds violation in expandSrcJarImports() method. Line 553 accesses args[i + 1] without checking if i+1 is within array bounds: + +if (args[i].equals("-lib") && args[i + 1].endsWith(".srcjar")) + +If "-lib" is the last argument, this throws ArrayIndexOutOfBoundsException. + +Add bounds check: +if (args[i].equals("-lib") && i + 1 < args.length && args[i + 1].endsWith(".srcjar")) + +Verification: +1. Test with args array ending in "-lib" to verify no exception +2. Test normal cases to ensure functionality preserved +3. Add unit test covering this edge case +``` + +--- + +### TODO-010: Error Message Quality Improvements +**Priority**: LOW 🟢 +**Agent Type**: Quality-Specialist +**Branch**: `fix/error-message-quality` +**Dependencies**: None + +**🔧 Worktree Setup**: +```bash +# Automatic (via script): ./setup-worktrees.sh +# Manual: git worktree add ../rules_antlr-worktrees/quality-messages fix/error-message-quality +``` + +**🤖 Claude Session**: +```bash +# Launch: ./run-parallel-claude.sh quality +# Manual: cd ../rules_antlr-worktrees/quality-messages && claude +# Attach: tmux attach -t rules-antlr-quality-messages +``` + +**Problem**: Missing spaces in error messages reduce readability. + +**Files to Modify**: +- `src/main/java/org/antlr/bazel/Version.java:43` +- Similar patterns in other files + +**Agent Prompt**: +``` +Improve error message formatting by adding missing spaces. Line 43 in Version.java: + +throw new IllegalArgumentException("Unknown version" + version); + +Should be: +throw new IllegalArgumentException("Unknown version: " + version); + +Search for similar patterns throughout codebase and fix consistently. + +Verification: +1. Trigger error conditions and verify messages are properly formatted +2. Ensure consistent formatting across all error messages +3. Test error message readability in build logs +``` + +--- + +## Multi-Agent Orchestration Strategy + +### ⚡ Active Workflow (Parallel with Worktrees) +```bash +# Phase 1: Critical NPE Fixes (4 parallel Claude sessions) +./run-parallel-claude.sh critical +# ├── TODO-001: Environment Variable NPE Fixes +# ├── TODO-002: Builder Method Parameter NPE Fixes +# ├── TODO-003: Language Path Conversion NPE Fixes +# └── TODO-004: Utility Method NPE Fixes + +# Phase 2: High Priority Bazel Fixes (1 parallel Claude session) +./run-parallel-claude.sh bazel +# ├── TODO-005: [CANCELLED] Bazel Starlark Dictionary Access Fix +# └── TODO-006: Bazel String Method Fix + +# Phase 3: Resource Management (2 parallel Claude sessions) +./run-parallel-claude.sh resource +# ├── TODO-007: Process Stream Resource Leak Fixes +# └── TODO-008: File Stream Resource Leak Fixes + +# Phase 4: Quality Improvements (2 parallel Claude sessions) +./run-parallel-claude.sh quality +# ├── TODO-009: Array Bounds Safety Improvements +# └── TODO-010: Error Message Quality Improvements +``` + +### 🚀 Quick Start Commands +```bash +# Setup (one-time) +./setup-worktrees.sh + +# Start critical fixes (RECOMMENDED first step) +./run-parallel-claude.sh critical + +# Check session status +./run-parallel-claude.sh status + +# Connect to specific sessions +tmux attach -t rules-antlr-npe-env # TODO-001 +tmux attach -t rules-antlr-npe-builder # TODO-002 +tmux attach -t rules-antlr-npe-language # TODO-003 +tmux attach -t rules-antlr-npe-utility # TODO-004 +``` + +### Legacy Workflow (Sequential) +```bash +# Create worktrees for parallel development +git worktree add ../npe-fixes fix/npe-environment-variables +git worktree add ../bazel-fixes fix/bazel-dict-access +git worktree add ../resource-fixes fix/process-stream-leaks + +# Assign agents to worktrees +NPE-Agent -> ../npe-fixes (TODO-001 through TODO-004) +Bazel-Agent -> ../bazel-fixes (TODO-005, TODO-006) +Resource-Agent -> ../resource-fixes (TODO-007, TODO-008) + +# Each agent creates PR when complete +# Validation-Agent tests integration after merges +``` + +### Agent Specializations +- **NPE-Specialist**: Focuses on null pointer vulnerabilities, defensive programming +- **Bazel-Specialist**: Expert in Starlark syntax, Bazel version compatibility +- **Resource-Specialist**: Resource management, try-with-resources patterns +- **Safety-Specialist**: Bounds checking, edge case handling +- **Quality-Specialist**: Code style, error messages, documentation + +### Verification Strategy +Each agent must: +1. Implement the fix following provided instructions +2. Add unit tests covering the vulnerability +3. Run existing test suite to ensure no regressions +4. Document the fix in commit message with vulnerability details + +### Integration Testing +After all critical fixes (TODO-001 through TODO-008): +1. Run full integration test suite +2. Test with multiple Bazel versions (5.x, 6.x, 7.x) +3. Performance testing to ensure no degradation +4. Security review of all changes + +--- + +## Notes for Future Development + +This TODO structure is designed to enable: +- **Autonomous execution** by specialized AI agents +- **Parallel development** using git worktrees +- **Quality assurance** through detailed verification steps +- **Scalability** for larger codebases with hundreds of issues + +Each TODO item serves as a complete specification that an agent can execute independently, making this approach suitable for distributed AI-powered code maintenance systems. \ No newline at end of file diff --git a/.agents/WORKFLOW.md b/.agents/WORKFLOW.md new file mode 100644 index 0000000..c90196c --- /dev/null +++ b/.agents/WORKFLOW.md @@ -0,0 +1,227 @@ +# rules_antlr Multi-Agent Parallel Development Workflow + +## Overview + +This workflow enables **parallel Claude Code development** using git worktrees to fix multiple critical bugs simultaneously. Instead of fixing bugs sequentially, you can run **4+ Claude sessions in parallel**, each working on independent code fixes. + +## 🚀 Quick Start + +### 1. Setup (One-time) +```bash +# Create all worktrees for parallel development +./setup-worktrees.sh +``` + +### 2. Launch Parallel Claude Sessions +```bash +# Start 4 critical NPE fix sessions (RECOMMENDED first step) +./run-parallel-claude.sh critical + +# Or start all sessions (high resource usage) +./run-parallel-claude.sh all +``` + +### 3. Connect to Claude Sessions +```bash +# Attach to specific sessions via tmux +tmux attach -t rules-antlr-npe-env # TODO-001: Environment Variable NPE Fixes +tmux attach -t rules-antlr-npe-builder # TODO-002: Builder Method Parameter NPE Fixes +tmux attach -t rules-antlr-npe-language # TODO-003: Language Path Conversion NPE Fixes +tmux attach -t rules-antlr-npe-utility # TODO-004: Utility Method NPE Fixes +``` + +### 4. Create Pull Requests +```bash +# Create PRs for completed critical fixes +./merge-workflow.sh critical + +# Or check status of all worktrees +./merge-workflow.sh status +``` + +### 5. Cleanup When Done +```bash +# Remove all worktrees and cleanup environment +./cleanup-worktrees.sh all +``` + +## 📋 Available Scripts + +| Script | Purpose | Usage | +|--------|---------|-------| +| `setup-worktrees.sh` | Create git worktrees for parallel development | `./setup-worktrees.sh` | +| `run-parallel-claude.sh` | Launch multiple Claude sessions in tmux | `./run-parallel-claude.sh critical` | +| `merge-workflow.sh` | Create PRs and coordinate merging | `./merge-workflow.sh status` | +| `cleanup-worktrees.sh` | Remove worktrees and cleanup | `./cleanup-worktrees.sh all` | +| `test-workflow.sh` | Test the entire workflow system | `./test-workflow.sh` | + +## 🎯 TODO Items by Priority + +### 🔴 Critical NPE Fixes (Phase 1) - Parallel Execution +- **TODO-001**: Environment Variable NPE Fixes +- **TODO-002**: Builder Method Parameter NPE Fixes +- **TODO-003**: Language Path Conversion NPE Fixes +- **TODO-004**: Utility Method NPE Fixes + +### 🟠 High Priority Bazel Fixes (Phase 2) - Parallel Execution +- **TODO-005**: Bazel Starlark Dictionary Access Fix +- **TODO-006**: Bazel String Method Fix + +### 🟡 Medium Priority Resource Fixes (Phase 3) - Parallel Execution +- **TODO-007**: Process Stream Resource Leak Fixes +- **TODO-008**: File Stream Resource Leak Fixes + +### 🟢 Quality Improvements (Phase 4) +- **TODO-009**: Array Bounds Safety Improvements +- **TODO-010**: Error Message Quality Improvements + +## 🔧 System Requirements + +### Required +- **Git** (for worktree management) +- **Bash 4+** (for script functionality) +- **Claude Code CLI** (for parallel development) + +### Optional (but recommended) +- **tmux** (for parallel session management) +- **GitHub CLI** (for automated PR creation) + +## 📊 Testing the Workflow + +```bash +# Test entire workflow system +./test-workflow.sh + +# Test specific components +./test-workflow.sh scripts # Test script functionality +./test-workflow.sh e2e # End-to-end workflow test +./test-workflow.sh deps # Check system dependencies +``` + +## 🎮 tmux Session Management + +### Useful tmux Commands +```bash +# List all sessions +tmux list-sessions + +# Attach to specific session +tmux attach -t rules-antlr-npe-env + +# Detach from session (inside tmux) +Ctrl+B, D + +# Kill specific session +tmux kill-session -t rules-antlr-npe-env + +# Kill all Claude sessions +./run-parallel-claude.sh kill +``` + +### Session Naming Convention +- `rules-antlr-npe-*` - Critical NPE fix sessions +- `rules-antlr-bazel-*` - Bazel compatibility sessions +- `rules-antlr-resource-*` - Resource management sessions +- `rules-antlr-quality-*` - Quality improvement sessions + +## 📁 Directory Structure + +``` +rules_antlr/ # Main repository +├── TODO.md # Detailed task specifications +├── WORKFLOW.md # This document +├── setup-worktrees.sh # Worktree creation +├── run-parallel-claude.sh # Parallel session launcher +├── merge-workflow.sh # PR creation and coordination +├── cleanup-worktrees.sh # Environment cleanup +├── test-workflow.sh # Workflow testing +└── ../rules_antlr-worktrees/ # Parallel development worktrees + ├── npe-env/ # TODO-001 worktree + ├── npe-builder/ # TODO-002 worktree + ├── npe-language/ # TODO-003 worktree + ├── npe-utility/ # TODO-004 worktree + ├── bazel-dict/ # TODO-005 worktree + ├── bazel-string/ # TODO-006 worktree + ├── resource-process/ # TODO-007 worktree + ├── resource-file/ # TODO-008 worktree + ├── safety-bounds/ # TODO-009 worktree + └── quality-messages/ # TODO-010 worktree +``` + +## 🚦Status Management + +### Check Workflow Status +```bash +# Check all worktree status +./merge-workflow.sh status + +# Check active Claude sessions +./run-parallel-claude.sh status + +# Check cleanup status +./cleanup-worktrees.sh status +``` + +## 🔄 Recommended Workflow + +### Phase 1: Critical Bug Fixes (Highest Impact) +1. `./setup-worktrees.sh` - Create development environment +2. `./run-parallel-claude.sh critical` - Start 4 critical fix sessions +3. Work in parallel on TODO-001 through TODO-004 +4. `./merge-workflow.sh critical` - Create PRs for critical fixes +5. **Merge critical fixes first** before proceeding + +### Phase 2: High Priority Fixes +1. `./run-parallel-claude.sh bazel` - Start Bazel compatibility sessions +2. Work on TODO-005 and TODO-006 +3. `./merge-workflow.sh bazel` - Create PRs for Bazel fixes + +### Phase 3: Resource and Quality Fixes +1. `./run-parallel-claude.sh resource` - Start resource management sessions +2. `./run-parallel-claude.sh quality` - Start quality improvement sessions +3. Work on remaining TODO items +4. `./merge-workflow.sh all` - Create PRs for remaining fixes + +### Phase 4: Integration and Cleanup +1. **Integration testing** after all merges +2. `./cleanup-worktrees.sh all` - Clean up development environment +3. **Validate** that all 20 critical bugs are resolved + +## 💡 Tips and Best Practices + +### Parallel Development +- **Start with critical fixes** (TODO-001 to TODO-004) for maximum impact +- **Use tmux sessions** to easily switch between Claude instances +- **Each Claude session** has its own isolated file state +- **Monitor system resources** when running many parallel sessions + +### Code Quality +- **Each TODO item** includes detailed fix instructions and verification steps +- **Each worktree** gets its own copy of TODO.md for reference +- **Test each fix** independently before creating PRs +- **Follow dependency order** when merging (critical → high → medium → low) + +### Troubleshooting +- Use `./test-workflow.sh` to validate system setup +- Check `./cleanup-worktrees.sh status` if worktrees seem stuck +- Use `./run-parallel-claude.sh kill` to reset Claude sessions +- Refer to `TODO.md` for detailed context on each issue + +## 🎉 Benefits + +### Speed +- **4x faster** for critical fixes (parallel vs sequential) +- **Independent development** prevents conflicts +- **Immediate PR creation** for completed fixes + +### Quality +- **Specialized context** for each Claude session +- **Independent testing** of each fix +- **Systematic approach** to complex bug remediation + +### Organization +- **Clear priority ordering** (critical → high → medium → low) +- **Traceable progress** through session management +- **Clean integration** via coordinated PR workflow + +This workflow transforms traditional sequential bug fixing into a **parallel, scalable development process** using Claude Code's native capabilities with git worktrees. \ No newline at end of file diff --git a/.agents/cleanup-worktrees.sh b/.agents/cleanup-worktrees.sh new file mode 100755 index 0000000..dac09ce --- /dev/null +++ b/.agents/cleanup-worktrees.sh @@ -0,0 +1,506 @@ +#!/bin/bash + +# rules_antlr Worktree Cleanup Script +# Safely removes worktrees and cleans up the multi-agent development environment +# Now fully driven by todos.yaml configuration + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# Configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +TODOS_YAML="$SCRIPT_DIR/todos.yaml" + +# Use absolute path for robustness across different execution contexts +REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || echo "$(pwd)/..")" + +# Check if yq is available for YAML parsing +if ! command -v yq &> /dev/null; then + echo -e "${YELLOW}⚠️ Warning: yq not found. Using hardcoded cleanup patterns.${NC}" + echo -e "${BLUE}Install yq for YAML-driven cleanup:${NC}" + echo " macOS: brew install yq" + echo " Ubuntu: sudo apt-get install yq" + echo " Arch: sudo pacman -S yq" + echo + USE_YAML=false +else + USE_YAML=true +fi + +# Read configuration from YAML or use defaults +if [ "$USE_YAML" = "true" ] && [ -f "$TODOS_YAML" ] && yq eval '.' "$TODOS_YAML" > /dev/null 2>&1; then + WORKTREE_BASE_DIR=$(yq eval '.config.worktree_base_dir' "$TODOS_YAML") + WORKTREE_DIR="${REPO_ROOT}/${WORKTREE_BASE_DIR}" + TMUX_SESSION_PREFIX=$(yq eval '.config.tmux_session_prefix' "$TODOS_YAML") +else + # Fallback to hardcoded values + WORKTREE_DIR="${REPO_ROOT}/../rules_antlr-worktrees" + TMUX_SESSION_PREFIX="rules-antlr" + if [ "$USE_YAML" = "true" ]; then + echo -e "${YELLOW}⚠️ Warning: todos.yaml not found or invalid. Using hardcoded patterns.${NC}" + fi +fi + +# Function to show usage +show_usage() { + echo -e "${BLUE}Usage: $0 [command] [options]${NC}" + echo + echo "Commands:" + echo " all - Remove all worktrees and cleanup everything (DEFAULT)" + echo " sessions - Kill all Claude tmux sessions only" + echo " worktrees - Remove all worktrees only (keep sessions)" + echo " branches - Clean up remote branches only" + echo " selective - Interactive cleanup (choose what to remove)" + echo " status - Show what would be cleaned up" + echo + echo "Options:" + echo " --force - Skip confirmation prompts" + echo " --dry-run - Show what would be done without actually doing it" + echo + echo "Examples:" + echo " $0 # Interactive cleanup of everything" + echo " $0 all --force # Remove everything without prompts" + echo " $0 sessions # Kill Claude sessions only" + echo " $0 status # Show current state" +} + +# Function to kill Claude tmux sessions using YAML or fallback patterns +kill_claude_sessions() { + local dry_run="$1" + + echo -e "${YELLOW}🛑 Killing Claude Code tmux sessions...${NC}" + + local killed_count=0 + + if command -v tmux &> /dev/null; then + if [ "$USE_YAML" = "true" ] && [ -f "$TODOS_YAML" ]; then + # YAML-driven session cleanup - get all session names from TODOs + while IFS= read -r session_name; do + if [ "$session_name" != "null" ] && [ -n "$session_name" ]; then + if tmux has-session -t "$session_name" 2>/dev/null; then + echo -e " Killing session: ${CYAN}$session_name${NC}" + if [ "$dry_run" != "true" ]; then + tmux kill-session -t "$session_name" 2>/dev/null || true + fi + ((killed_count++)) + fi + fi + done < <(yq eval '.todos[].git.tmux_session' "$TODOS_YAML") + else + # Fallback: Kill all sessions matching the prefix + local sessions + sessions=$(tmux list-sessions -F "#{session_name}" 2>/dev/null | grep "^${TMUX_SESSION_PREFIX}" || true) + + for session in $sessions; do + echo -e " Killing session: ${CYAN}$session${NC}" + if [ "$dry_run" != "true" ]; then + tmux kill-session -t "$session" 2>/dev/null || true + fi + ((killed_count++)) + done + fi + else + echo -e " ${YELLOW}tmux not available${NC}" + fi + + if [ $killed_count -eq 0 ]; then + echo -e " ${GREEN}No Claude sessions found${NC}" + else + echo -e " ${GREEN}✅ Killed $killed_count Claude sessions${NC}" + fi +} + +# Function to remove worktrees using YAML or fallback patterns +remove_worktrees() { + local dry_run="$1" + + echo -e "${YELLOW}🗂️ Removing git worktrees...${NC}" + + local removed_count=0 + + # Check if worktree directory exists + if [ ! -d "$WORKTREE_DIR" ]; then + echo -e " ${GREEN}No worktree directory found: $WORKTREE_DIR${NC}" + return + fi + + if [ "$USE_YAML" = "true" ] && [ -f "$TODOS_YAML" ]; then + # YAML-driven worktree cleanup - get all worktree dirs from TODOs + while IFS= read -r worktree_dir; do + if [ "$worktree_dir" != "null" ] && [ -n "$worktree_dir" ]; then + local full_path="$WORKTREE_DIR/$worktree_dir" + + if [ -d "$full_path" ]; then + echo -e " Removing worktree: ${CYAN}$full_path${NC}" + + if [ "$dry_run" != "true" ]; then + # Remove the worktree using git + git -C "$REPO_ROOT" worktree remove "$full_path" --force 2>/dev/null || { + # If git worktree remove fails, try manual cleanup + echo -e " ${YELLOW}Git cleanup failed, removing directory manually...${NC}" + rm -rf "$full_path" + } + fi + ((removed_count++)) + fi + fi + done < <(yq eval '.todos[].git.worktree_dir' "$TODOS_YAML") + else + # Fallback: Remove all directories in the worktree directory + echo -e " ${YELLOW}Using fallback: removing all directories in $WORKTREE_DIR${NC}" + for dir_path in "$WORKTREE_DIR"/*; do + if [ -d "$dir_path" ]; then + echo -e " Removing worktree: ${CYAN}$dir_path${NC}" + + if [ "$dry_run" != "true" ]; then + # Remove the worktree using git + git -C "$REPO_ROOT" worktree remove "$dir_path" --force 2>/dev/null || { + # If git worktree remove fails, try manual cleanup + echo -e " ${YELLOW}Git cleanup failed, removing directory manually...${NC}" + rm -rf "$dir_path" + } + fi + ((removed_count++)) + fi + done + fi + + # Remove the parent directory if empty + if [ "$dry_run" != "true" ] && [ -d "$WORKTREE_DIR" ]; then + if [ -z "$(ls -A "$WORKTREE_DIR")" ]; then + echo -e " Removing empty worktree directory: ${CYAN}$WORKTREE_DIR${NC}" + rmdir "$WORKTREE_DIR" + fi + fi + + if [ $removed_count -eq 0 ]; then + echo -e " ${GREEN}No worktrees found to remove${NC}" + else + echo -e " ${GREEN}✅ Removed $removed_count worktrees${NC}" + fi +} + +# Function to clean up branches using YAML or fallback patterns +cleanup_branches() { + local dry_run="$1" + local force="$2" + + echo -e "${YELLOW}🌿 Cleaning up git branches...${NC}" + + local deleted_count=0 + local branches=() + + if [ "$USE_YAML" = "true" ] && [ -f "$TODOS_YAML" ]; then + # YAML-driven branch cleanup - get all branch names from TODOs + while IFS= read -r branch_name; do + if [ "$branch_name" != "null" ] && [ -n "$branch_name" ]; then + branches+=("$branch_name") + fi + done < <(yq eval '.todos[].git.branch' "$TODOS_YAML") + else + # Fallback: Use hardcoded branch patterns + echo -e " ${YELLOW}Using fallback: looking for branches with 'fix/' prefix${NC}" + while IFS= read -r branch_name; do + if [ -n "$branch_name" ]; then + branches+=("$branch_name") + fi + done < <(git -C "$REPO_ROOT" branch --format="%(refname:short)" | grep "^fix/" || true) + fi + + for branch in "${branches[@]}"; do + # Check if branch exists locally + if git -C "$REPO_ROOT" show-ref --verify --quiet "refs/heads/$branch"; then + echo -e " Local branch found: ${CYAN}$branch${NC}" + + if [ "$force" = "true" ] || [ "$dry_run" = "true" ]; then + local delete_local="y" + else + read -p " Delete local branch '$branch'? (y/N): " -n 1 -r delete_local + echo + fi + + if [[ $delete_local =~ ^[Yy]$ ]]; then + if [ "$dry_run" != "true" ]; then + git -C "$REPO_ROOT" branch -D "$branch" 2>/dev/null || true + fi + echo -e " ${GREEN}✅ Deleted local branch${NC}" + ((deleted_count++)) + fi + fi + + # Check if branch exists on remote + if git -C "$REPO_ROOT" ls-remote --heads origin "$branch" | grep -q "$branch"; then + echo -e " Remote branch found: ${CYAN}origin/$branch${NC}" + + if [ "$force" = "true" ] || [ "$dry_run" = "true" ]; then + local delete_remote="y" + else + read -p " Delete remote branch 'origin/$branch'? (y/N): " -n 1 -r delete_remote + echo + fi + + if [[ $delete_remote =~ ^[Yy]$ ]]; then + if [ "$dry_run" != "true" ]; then + git -C "$REPO_ROOT" push origin --delete "$branch" 2>/dev/null || true + fi + echo -e " ${GREEN}✅ Deleted remote branch${NC}" + ((deleted_count++)) + fi + fi + done + + if [ $deleted_count -eq 0 ]; then + echo -e " ${GREEN}No branches found to delete${NC}" + else + echo -e " ${GREEN}✅ Deleted $deleted_count branches${NC}" + fi +} + +# Function to clean up temporary files +cleanup_temp_files() { + local dry_run="$1" + + echo -e "${YELLOW}🗑️ Cleaning up temporary files...${NC}" + + local temp_files=( + "../../pr_urls.txt" + "../../parallel_session.log" + "./.tmux_session_info" + ) + + local removed_count=0 + + for file in "${temp_files[@]}"; do + if [ -f "$file" ]; then + echo -e " Removing: ${CYAN}$file${NC}" + if [ "$dry_run" != "true" ]; then + rm -f "$file" + fi + ((removed_count++)) + fi + done + + if [ $removed_count -eq 0 ]; then + echo -e " ${GREEN}No temporary files found${NC}" + else + echo -e " ${GREEN}✅ Removed $removed_count temporary files${NC}" + fi +} + +# Function to show current status +show_status() { + echo -e "${BLUE}📊 Current Multi-Agent Environment Status${NC}" + echo "==============================================" + + # Check tmux sessions + echo -e "${CYAN}Claude Code Sessions:${NC}" + if command -v tmux &> /dev/null; then + local claude_sessions + claude_sessions=$(tmux list-sessions 2>/dev/null | grep -E "rules-antlr" || true) + if [ -n "$claude_sessions" ]; then + while IFS= read -r line; do echo " $line"; done <<< "$claude_sessions" + else + echo " No Claude sessions running" + fi + else + echo " tmux not available" + fi + + echo + + # Check worktrees + echo -e "${CYAN}Git Worktrees:${NC}" + local worktree_list + worktree_list=$(git -C "$REPO_ROOT" worktree list | grep "$WORKTREE_DIR" || true) + if [ -n "$worktree_list" ]; then + while IFS= read -r line; do echo " $line"; done <<< "$worktree_list" + else + echo " No worktrees found" + fi + + echo + + # Check branches + echo -e "${CYAN}Fix Branches:${NC}" + local fix_branches + fix_branches=$(git -C "$REPO_ROOT" branch | grep "fix/" || true) + if [ -n "$fix_branches" ]; then + while IFS= read -r line; do echo " $line"; done <<< "$fix_branches" + else + echo " No fix branches found" + fi + + echo + + # Check temporary files + echo -e "${CYAN}Temporary Files:${NC}" + local temp_found=false + for file in "../../pr_urls.txt" "../../parallel_session.log" "./.tmux_session_info"; do + if [ -f "$file" ]; then + echo " $file" + temp_found=true + fi + done + if [ "$temp_found" = false ]; then + echo " No temporary files found" + fi +} + +# Function for interactive cleanup +interactive_cleanup() { + local dry_run="$1" + local force="$2" + + echo -e "${BLUE}🔧 Interactive Multi-Agent Environment Cleanup${NC}" + echo "==============================================" + + if [ "$force" != "true" ]; then + echo -e "${YELLOW}What would you like to clean up?${NC}" + echo + + read -p "Kill Claude tmux sessions? (y/N): " -n 1 -r kill_sessions + echo + + read -p "Remove git worktrees? (y/N): " -n 1 -r remove_wt + echo + + read -p "Delete git branches? (y/N): " -n 1 -r delete_branches + echo + + read -p "Remove temporary files? (y/N): " -n 1 -r remove_temp + echo + + echo + else + kill_sessions="y" + remove_wt="y" + delete_branches="y" + remove_temp="y" + fi + + if [[ $kill_sessions =~ ^[Yy]$ ]]; then + kill_claude_sessions "$dry_run" + echo + fi + + if [[ $remove_wt =~ ^[Yy]$ ]]; then + remove_worktrees "$dry_run" + echo + fi + + if [[ $delete_branches =~ ^[Yy]$ ]]; then + cleanup_branches "$dry_run" "$force" + echo + fi + + if [[ $remove_temp =~ ^[Yy]$ ]]; then + cleanup_temp_files "$dry_run" + echo + fi +} + +# Parse command line arguments +DRY_RUN=false +FORCE=false +COMMAND="all" + +while [[ $# -gt 0 ]]; do + case $1 in + --dry-run) + DRY_RUN=true + shift + ;; + --force) + FORCE=true + shift + ;; + all|sessions|worktrees|branches|selective|status) + COMMAND=$1 + shift + ;; + *) + echo -e "${RED}Unknown option: $1${NC}" + show_usage + exit 1 + ;; + esac +done + +# Show dry run notice +if [ "$DRY_RUN" = true ]; then + echo -e "${YELLOW}🔍 DRY RUN MODE - No changes will be made${NC}" + echo +fi + +# Execute command +case "$COMMAND" in + "status") + show_status + ;; + + "sessions") + kill_claude_sessions "$DRY_RUN" + ;; + + "worktrees") + remove_worktrees "$DRY_RUN" + ;; + + "branches") + cleanup_branches "$DRY_RUN" "$FORCE" + ;; + + "selective") + interactive_cleanup "$DRY_RUN" "$FORCE" + ;; + + "all") + echo -e "${BLUE}🧹 Complete Multi-Agent Environment Cleanup${NC}" + echo "==============================================" + + if [ "$FORCE" != "true" ] && [ "$DRY_RUN" != "true" ]; then + echo -e "${YELLOW}⚠️ This will remove ALL worktrees, sessions, branches, and temporary files${NC}" + read -p "Continue? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Cancelled." + exit 0 + fi + echo + fi + + kill_claude_sessions "$DRY_RUN" + echo + remove_worktrees "$DRY_RUN" + echo + cleanup_branches "$DRY_RUN" "$FORCE" + echo + cleanup_temp_files "$DRY_RUN" + ;; + + *) + show_usage + exit 1 + ;; +esac + +echo +if [ "$DRY_RUN" = true ]; then + echo -e "${BLUE}✨ Dry run complete! Use without --dry-run to actually perform cleanup.${NC}" +else + echo -e "${GREEN}✨ Cleanup complete!${NC}" + + echo + echo -e "${BLUE}💡 Next Steps:${NC}" + echo "• Run 'git worktree list' to verify worktrees are removed" + echo "• Run 'git branch' to check remaining branches" + echo "• Use './setup-worktrees.sh' to recreate the environment if needed" + echo "• Check 'tmux list-sessions' to verify no Claude sessions remain" +fi \ No newline at end of file diff --git a/.agents/merge-workflow.sh b/.agents/merge-workflow.sh new file mode 100755 index 0000000..587b759 --- /dev/null +++ b/.agents/merge-workflow.sh @@ -0,0 +1,446 @@ +#!/bin/bash + +# rules_antlr Merge Workflow Coordination Script +# Manages PR creation and merge coordination for parallel bug fixes +# Now fully driven by todos.yaml configuration + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +PURPLE='\033[0;35m' +NC='\033[0m' # No Color + +# Configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +TODOS_YAML="$SCRIPT_DIR/todos.yaml" + +# Use absolute path for robustness across different execution contexts +REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || echo "$(pwd)/..")" + +# Check if yq is available for YAML parsing +if ! command -v yq &> /dev/null; then + echo -e "${RED}❌ Error: yq is required for YAML parsing${NC}" + echo -e "${YELLOW}Install yq:${NC}" + echo " macOS: brew install yq" + echo " Ubuntu: sudo apt-get install yq" + echo " Arch: sudo pacman -S yq" + echo " Or download from: https://github.com/mikefarah/yq/releases" + exit 1 +fi + +# Check if todos.yaml exists and is valid +if [ ! -f "$TODOS_YAML" ]; then + echo -e "${RED}❌ Error: todos.yaml not found at $TODOS_YAML${NC}" + exit 1 +fi + +if ! yq eval '.' "$TODOS_YAML" > /dev/null 2>&1; then + echo -e "${RED}❌ Error: Invalid YAML syntax in todos.yaml${NC}" + exit 1 +fi + +# Read configuration from YAML +WORKTREE_BASE_DIR=$(yq eval '.config.worktree_base_dir' "$TODOS_YAML") +WORKTREE_DIR="${REPO_ROOT}/${WORKTREE_BASE_DIR}" + +# Check if gh CLI is available +if ! command -v gh &> /dev/null; then + echo -e "${RED}❌ Error: GitHub CLI (gh) is required for PR management${NC}" + echo -e "${YELLOW}Install GitHub CLI:${NC}" + echo " macOS: brew install gh" + echo " Ubuntu: sudo apt install gh" + echo " Or download from: https://cli.github.com/" + echo + echo -e "${BLUE}Alternative: Manual PR creation${NC}" + echo "Push branches manually and create PRs via GitHub web interface" + exit 1 +fi + +# Function to check worktree status from YAML data +check_worktree_status() { + local todo_index="$1" + + # Extract data from YAML + local todo_id + local todo_status + local branch_name + local worktree_dir + + todo_id=$(yq eval ".todos[${todo_index}].id" "$TODOS_YAML") + todo_status=$(yq eval ".todos[${todo_index}].status // \"active\"" "$TODOS_YAML") + branch_name=$(yq eval ".todos[${todo_index}].git.branch" "$TODOS_YAML") + worktree_dir=$(yq eval ".todos[${todo_index}].git.worktree_dir" "$TODOS_YAML") + + local worktree_path="$WORKTREE_DIR/$worktree_dir" + + # Skip cancelled TODOs + if [ "$todo_status" = "cancelled" ]; then + echo -e "${YELLOW}⚠️ $todo_id: CANCELLED${NC}" + echo " Reason: $(yq eval ".todos[${todo_index}].cancellation_reason // \"See YAML for details\"" "$TODOS_YAML")" + return 4 + fi + + if [ ! -d "$worktree_path" ]; then + echo -e "${RED}❌ Worktree not found: $worktree_path${NC}" + return 1 + fi + + # Check if there are changes to commit + if ! (cd "$worktree_path" && git diff --quiet && git diff --cached --quiet); then + echo -e "${YELLOW}⚠️ $todo_id has uncommitted changes${NC}" + return 2 + fi + + # Check if branch is ahead of main + local default_branch + local ahead + + default_branch=$(yq eval '.config.default_branch_base' "$TODOS_YAML") + if ! ahead=$(cd "$worktree_path" && git rev-list --count "${default_branch}..$branch_name" 2>/dev/null); then + ahead=0 + fi + if [ "$ahead" -eq 0 ]; then + echo -e "${YELLOW}⚠️ $todo_id has no commits (nothing to merge)${NC}" + return 3 + fi + + echo -e "${GREEN}✅ $todo_id ready ($ahead commits)${NC}" + return 0 +} + +# Function to run tests in worktree using YAML data +run_tests() { + local todo_index="$1" + + # Extract data from YAML + local todo_id + local worktree_dir + + todo_id=$(yq eval ".todos[${todo_index}].id" "$TODOS_YAML") + worktree_dir=$(yq eval ".todos[${todo_index}].git.worktree_dir" "$TODOS_YAML") + local worktree_path="$WORKTREE_DIR/$worktree_dir" + + echo -e "${BLUE}🧪 Running tests for $todo_id...${NC}" + + # Check if there's a test script or standard test command + if [ -f "$worktree_path/ci.sh" ]; then + echo "Running ./ci.sh..." + if ! (cd "$worktree_path" && ./ci.sh); then + echo -e "${RED}❌ Tests failed for $todo_id${NC}" + return 1 + fi + elif [ -f "$worktree_path/BUILD.bazel" ]; then + echo "Running bazel test..." + if ! (cd "$worktree_path" && bazel test //...); then + echo -e "${RED}❌ Bazel tests failed for $todo_id${NC}" + return 1 + fi + else + echo -e "${YELLOW}⚠️ No test command found, skipping tests${NC}" + fi + + echo -e "${GREEN}✅ Tests passed for $todo_id${NC}" + return 0 +} + +# Function to create PR using YAML data +create_pr() { + local todo_index="$1" + + # Extract data from YAML + local todo_id + local todo_title + local todo_description + local branch_name + local worktree_dir + local priority + local phase + + todo_id=$(yq eval ".todos[${todo_index}].id" "$TODOS_YAML") + todo_title=$(yq eval ".todos[${todo_index}].title" "$TODOS_YAML") + todo_description=$(yq eval ".todos[${todo_index}].description" "$TODOS_YAML") + branch_name=$(yq eval ".todos[${todo_index}].git.branch" "$TODOS_YAML") + worktree_dir=$(yq eval ".todos[${todo_index}].git.worktree_dir" "$TODOS_YAML") + priority=$(yq eval ".todos[${todo_index}].priority" "$TODOS_YAML") + phase=$(yq eval ".todos[${todo_index}].phase" "$TODOS_YAML") + + local worktree_path="$WORKTREE_DIR/$worktree_dir" + + echo -e "${PURPLE}📝 Creating PR for $todo_id...${NC}" + + # Push branch to origin + (cd "$worktree_path" && git push -u origin "$branch_name") + + # Create PR body with structured information + local default_branch + local pr_body + + default_branch=$(yq eval '.config.default_branch_base' "$TODOS_YAML") + pr_body="## $todo_id: $todo_title + +**Priority**: $priority +**Phase**: $phase +**Branch**: \`$branch_name\` + +### Problem Description +$todo_description + +### Changes Made + +$(cd "$worktree_path" && git log --oneline "${default_branch}".."$branch_name" | sed 's/^/- /') + +### Testing +- [ ] Unit tests added/updated +- [ ] Integration tests pass +- [ ] Manual testing completed +- [ ] No regressions introduced + +### Review Checklist +- [ ] Code follows project conventions +- [ ] Error handling is appropriate +- [ ] Documentation updated if needed +- [ ] Security implications reviewed + +--- +*This PR was generated as part of the YAML-driven multi-agent bug fixing workflow.* +*See todos.yaml for detailed context, agent prompts, and fix strategies.* + +**Related TODO Items**: $todo_id +**Part of**: Multi-Agent Critical Bug Fixes Initiative (Phase: $phase)" + + # Create the PR + local pr_url + pr_url=$(gh pr create \ + --title "$todo_id: $todo_title" \ + --body "$pr_body" \ + --label "bug,automated-fix,$priority" \ + --assignee "@me") + + echo -e "${GREEN}✅ PR created: $pr_url${NC}" + echo "$pr_url" >> "${REPO_ROOT}/.agents/pr_urls.txt" + + return 0 +} + +# Function to show usage +show_usage() { + echo -e "${BLUE}Usage: $0 [command]${NC}" + echo + echo "Commands:" + echo " status - Check status of all worktrees" + echo " test - Run tests in all worktrees with changes" + + # Dynamically generate phase commands from YAML + while IFS= read -r phase_name; do + if [ "$phase_name" != "null" ] && [ -n "$phase_name" ]; then + local phase_display_name + phase_display_name=$(yq eval ".phases.${phase_name}.name" "$TODOS_YAML") + local phase_emoji + phase_emoji=$(yq eval ".phases.${phase_name}.emoji" "$TODOS_YAML") + echo " $phase_name - $phase_emoji Create PRs for $phase_display_name" + fi + done < <(yq eval '.phases | to_entries | sort_by(.value.priority) | .[].key' "$TODOS_YAML") + + echo " all - Create PRs for all completed fixes" + echo " list-prs - List all created PRs" + echo " merge - Interactive merge workflow (with dependency management)" + echo + echo "Examples:" + echo " $0 status # Check what's ready to merge" + local first_phase + first_phase=$(yq eval '.phases | to_entries | sort_by(.value.priority) | .[0].key' "$TODOS_YAML") + echo " $0 $first_phase # Create PRs for highest priority phase" + echo " $0 all # Create PRs for everything ready" +} + +# Function to check all worktree status using YAML data +check_all_status() { + echo -e "${BLUE}📊 Checking status of all worktrees from YAML...${NC}" + echo "=================================================" + + local ready_count=0 + local not_ready_count=0 + local cancelled_count=0 + + # Check status of all TODOs + local total_todos + total_todos=$(yq eval '.todos | length' "$TODOS_YAML") + for (( i=0; i /dev/null; then + echo -e "${RED}❌ Error: yq is required for YAML parsing${NC}" + echo -e "${YELLOW}Install yq:${NC}" + echo " macOS: brew install yq" + echo " Ubuntu: sudo apt-get install yq" + echo " Arch: sudo pacman -S yq" + echo " Or download from: https://github.com/mikefarah/yq/releases" + exit 1 +fi + +# Check if todos.yaml exists and is valid +if [ ! -f "$TODOS_YAML" ]; then + echo -e "${RED}❌ Error: todos.yaml not found at $TODOS_YAML${NC}" + exit 1 +fi + +if ! yq eval '.' "$TODOS_YAML" > /dev/null 2>&1; then + echo -e "${RED}❌ Error: Invalid YAML syntax in todos.yaml${NC}" + exit 1 +fi + +# Read configuration from YAML +WORKTREE_BASE_DIR=$(yq eval '.config.worktree_base_dir' "$TODOS_YAML") +WORKTREE_DIR="${REPO_ROOT}/${WORKTREE_BASE_DIR}" +TMUX_SESSION_PREFIX=$(yq eval '.config.tmux_session_prefix' "$TODOS_YAML") + +# Check if tmux is available +if ! command -v tmux &> /dev/null; then + echo -e "${RED}❌ Error: tmux is required for parallel sessions${NC}" + echo -e "${YELLOW}Install tmux:${NC}" + echo " macOS: brew install tmux" + echo " Ubuntu: sudo apt-get install tmux" + echo " Fedora: sudo dnf install tmux" + echo + echo -e "${BLUE}Alternative: Manual execution${NC}" + echo "Open multiple terminals and run claude in each worktree:" + echo "Check todos.yaml for worktree paths or run ./setup-worktrees.sh to see directories" + exit 1 +fi + +# Check if worktrees exist +if [ ! -d "$WORKTREE_DIR" ]; then + echo -e "${RED}❌ Error: Worktrees not found. Run ./setup-worktrees.sh first${NC}" + exit 1 +fi + +# Function to create tmux session with Claude from YAML data +create_claude_session() { + local todo_index="$1" + + # Extract data from YAML + local todo_id + todo_id=$(yq eval ".todos[${todo_index}].id" "$TODOS_YAML") + local todo_title + todo_title=$(yq eval ".todos[${todo_index}].title" "$TODOS_YAML") + local todo_status + todo_status=$(yq eval ".todos[${todo_index}].status // \"active\"" "$TODOS_YAML") + local session_name + session_name=$(yq eval ".todos[${todo_index}].git.tmux_session" "$TODOS_YAML") + local worktree_dir + worktree_dir=$(yq eval ".todos[${todo_index}].git.worktree_dir" "$TODOS_YAML") + local agent_prompt + agent_prompt=$(yq eval ".todos[${todo_index}].agent_prompt" "$TODOS_YAML") + local priority + priority=$(yq eval ".todos[${todo_index}].priority" "$TODOS_YAML") + + local worktree_path="$WORKTREE_DIR/$worktree_dir" + + # Skip cancelled TODOs + if [ "$todo_status" = "cancelled" ]; then + echo -e "${YELLOW}⚠️ Skipping $todo_id: CANCELLED${NC}" + echo " Reason: $(yq eval ".todos[${todo_index}].cancellation_reason // \"See YAML for details\"" "$TODOS_YAML")" + echo + return 0 + fi + + if [ ! -d "$worktree_path" ]; then + echo -e "${RED}❌ Worktree not found: $worktree_path${NC}" + echo " Run ./setup-worktrees.sh first to create worktrees" + return 1 + fi + + echo -e "${CYAN}🚀 Starting Claude session: $session_name${NC}" + echo " TODO: $todo_id ($priority priority)" + echo " Title: $todo_title" + echo " Worktree: $worktree_path" + + # Kill existing session if it exists + if tmux has-session -t "$session_name" 2>/dev/null; then + echo -e " ${YELLOW}Killing existing session: $session_name${NC}" + tmux kill-session -t "$session_name" 2>/dev/null || true + sleep 1 # Give time for cleanup + fi + + # Create new session with error handling + if ! tmux new-session -d -s "$session_name" -c "$worktree_path"; then + echo -e "${RED}❌ Failed to create tmux session: $session_name${NC}" + return 1 + fi + + # Send comprehensive context as comments for reference + tmux send-keys -t "$session_name" "# $todo_id: $todo_title ($priority priority)" Enter + tmux send-keys -t "$session_name" "# Working directory: $worktree_path" Enter + tmux send-keys -t "$session_name" "# Reference: Check todos.yaml for full agent prompt and fix strategy" Enter + tmux send-keys -t "$session_name" "# " Enter + + # Send a shortened version of the agent prompt as a comment (first few lines) + local prompt_preview + prompt_preview=$(echo "$agent_prompt" | head -3 | sed 's/^/# /') + echo "$prompt_preview" | while IFS= read -r line; do + tmux send-keys -t "$session_name" "$line" Enter + done + + tmux send-keys -t "$session_name" "# [... see todos.yaml for complete prompt]" Enter + tmux send-keys -t "$session_name" "" Enter + + # Start Claude + tmux send-keys -t "$session_name" "claude" Enter + + echo -e "${GREEN} ✅ Session started: tmux attach -t $session_name${NC}" + echo +} + +# Function to show usage +show_usage() { + echo -e "${BLUE}Usage: $0 [phase]${NC}" + echo + echo "Phases (from todos.yaml):" + + # Dynamically generate phase list from YAML + while IFS= read -r phase_name; do + if [ "$phase_name" != "null" ] && [ -n "$phase_name" ]; then + local phase_display_name + phase_display_name=$(yq eval ".phases.${phase_name}.name" "$TODOS_YAML") + local phase_emoji + phase_emoji=$(yq eval ".phases.${phase_name}.emoji" "$TODOS_YAML") + local phase_description + phase_description=$(yq eval ".phases.${phase_name}.description" "$TODOS_YAML") + local active_todos + active_todos=$(yq eval ".todos | map(select(.phase == \"$phase_name\" and (.status // \"active\") != \"cancelled\")) | length" "$TODOS_YAML") + + echo " $phase_name - $phase_emoji $phase_display_name ($active_todos TODOs)" + echo " $phase_description" + fi + done < <(yq eval '.phases | to_entries | sort_by(.value.priority) | .[].key' "$TODOS_YAML") + + echo + echo "Special commands:" + echo " all - Start ALL active sessions (high resource usage)" + echo " status - Show running sessions" + echo " kill - Kill all Claude sessions" + echo + echo "Examples:" + local first_phase + first_phase=$(yq eval '.phases | to_entries | sort_by(.value.priority) | .[0].key' "$TODOS_YAML") + echo " $0 $first_phase # Start highest priority phase" + echo " $0 all # Start all active sessions" + echo " $0 status # Check which sessions are running" +} + +# Function to show session status +show_status() { + echo -e "${BLUE}🔍 Active Claude Code Sessions:${NC}" + echo "=================================" + + local session_prefix="$TMUX_SESSION_PREFIX" + + if ! tmux list-sessions 2>/dev/null | grep -E "^${session_prefix}"; then + echo -e "${YELLOW}No Claude sessions running${NC}" + return + fi + + echo + echo -e "${BLUE}💡 Attach to sessions:${NC}" + tmux list-sessions 2>/dev/null | grep -E "^${session_prefix}" | while read -r session; do + session_name=$(echo "$session" | cut -d: -f1) + echo " tmux attach -t $session_name" + done +} + +# Function to kill all Claude sessions +kill_sessions() { + echo -e "${YELLOW}🛑 Killing all Claude Code sessions...${NC}" + + local session_prefix="$TMUX_SESSION_PREFIX" + local sessions_killed=0 + + # Find all sessions with our prefix and kill them + while IFS= read -r session_name; do + if [ -n "$session_name" ]; then + echo -e " Killing session: ${session_name}" + if tmux kill-session -t "$session_name" 2>/dev/null; then + ((sessions_killed++)) + else + echo -e " ${YELLOW}⚠️ Failed to kill session: $session_name${NC}" + fi + fi + done < <(tmux list-sessions -F "#{session_name}" 2>/dev/null | grep "^${session_prefix}" || true) + + if [ $sessions_killed -gt 0 ]; then + echo -e "${GREEN}✅ Killed $sessions_killed Claude sessions${NC}" + else + echo -e "${YELLOW}No active Claude sessions found${NC}" + fi +} + +# Function to start sessions for a specific phase +start_phase_sessions() { + local phase_name="$1" + + # Get phase information from YAML + local phase_display_name + phase_display_name=$(yq eval ".phases.${phase_name}.name" "$TODOS_YAML") + local phase_description + phase_description=$(yq eval ".phases.${phase_name}.description" "$TODOS_YAML") + local phase_emoji + phase_emoji=$(yq eval ".phases.${phase_name}.emoji" "$TODOS_YAML") + local phase_parallel + phase_parallel=$(yq eval ".phases.${phase_name}.parallel" "$TODOS_YAML") + + if [ "$phase_display_name" = "null" ]; then + echo -e "${RED}❌ Error: Unknown phase '$phase_name'${NC}" + echo "Use '$0' without arguments to see available phases" + return 1 + fi + + echo -e "${BLUE}${phase_emoji} STARTING ${phase_display_name^^}${NC}" + echo "Description: $phase_description" + if [ "$phase_parallel" = "true" ]; then + echo "Execution: Parallel sessions" + else + echo "Execution: Sequential sessions" + fi + echo "=================================================" + + # Get all TODOs for this phase and start sessions + local session_count=0 + while IFS= read -r todo_index; do + if [ "$todo_index" != "null" ] && [ -n "$todo_index" ]; then + create_claude_session "$todo_index" + ((session_count++)) + + # Add delay between sessions if parallel execution + if [ "$phase_parallel" = "true" ] && [ $session_count -gt 0 ]; then + sleep 2 + fi + fi + done < <(yq eval ".todos | to_entries | map(select(.value.phase == \"$phase_name\")) | .[].key" "$TODOS_YAML") + + if [ $session_count -eq 0 ]; then + echo -e "${YELLOW}⚠️ No active TODOs found for phase: $phase_name${NC}" + else + echo -e "${GREEN}✅ Started $session_count Claude sessions for $phase_display_name${NC}" + fi +} + +# Parse command line arguments +# Default to first phase by priority if no argument provided +DEFAULT_PHASE=$(yq eval '.phases | to_entries | sort_by(.value.priority) | .[0].key' "$TODOS_YAML") +PHASE="${1:-$DEFAULT_PHASE}" + +case "$PHASE" in + "all") + echo -e "${BLUE}🚀 STARTING ALL PARALLEL SESSIONS${NC}" + total_todos=$(yq eval '.todos | map(select((.status // "active") != "cancelled")) | length' "$TODOS_YAML") + echo -e "${RED}⚠️ Warning: This will start $total_todos Claude sessions simultaneously!${NC}" + echo -e "${YELLOW}High resource usage - ensure you have sufficient RAM/CPU${NC}" + echo "=================================================" + + read -p "Continue? (y/N): " -n 1 -r + echo + if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Cancelled." + exit 0 + fi + + # Start all phases in priority order + while IFS= read -r phase_name; do + if [ "$phase_name" != "null" ] && [ -n "$phase_name" ]; then + start_phase_sessions "$phase_name" + sleep 5 + echo + fi + done < <(yq eval '.phases | to_entries | sort_by(.value.priority) | .[].key' "$TODOS_YAML") + ;; + + "status") + show_status + exit 0 + ;; + + "kill") + kill_sessions + exit 0 + ;; + + *) + # Check if it's a valid phase name + if yq eval ".phases | has(\"$PHASE\")" "$TODOS_YAML" | grep -q "true"; then + start_phase_sessions "$PHASE" + else + echo -e "${RED}❌ Error: Unknown phase or command '$PHASE'${NC}" + echo + show_usage + exit 1 + fi + ;; +esac + +echo +echo -e "${GREEN}🎉 Claude sessions started successfully!${NC}" +echo "=================================================" + +# Show how to connect to sessions +echo -e "${BLUE}📱 Connect to sessions:${NC}" +session_prefix="$TMUX_SESSION_PREFIX" +tmux list-sessions 2>/dev/null | grep -E "^${session_prefix}" | while read -r session; do + session_name=$(echo "$session" | cut -d: -f1) + echo " tmux attach -t $session_name" +done + +echo +echo -e "${BLUE}💡 Useful tmux commands:${NC}" +echo " tmux list-sessions # List all sessions" +echo " tmux attach -t # Attach to specific session" +echo " Ctrl+B, D # Detach from session (inside tmux)" +echo " tmux kill-session -t # Kill specific session" +echo " ./run-parallel-claude.sh kill # Kill all Claude sessions" +echo " ./run-parallel-claude.sh status # Check session status" + +echo +echo -e "${YELLOW}⚡ Workflow Tips:${NC}" +highest_priority_phase=$(yq eval '.phases | to_entries | sort_by(.value.priority) | .[0].key' "$TODOS_YAML") +echo "• Start with '$highest_priority_phase' phase for maximum impact" +echo "• Each Claude session has todos.yaml copied for reference" +echo "• Use Ctrl+B, D to detach and switch between sessions" +echo "• Run ./merge-workflow.sh when fixes are ready" +echo "• Monitor system resources with high parallel usage" +echo "• Check todos.yaml for detailed agent prompts and fix strategies" + +echo +echo -e "${GREEN}✨ Happy YAML-driven parallel development!${NC}" \ No newline at end of file diff --git a/.agents/setup-worktrees.sh b/.agents/setup-worktrees.sh new file mode 100755 index 0000000..8e39cc7 --- /dev/null +++ b/.agents/setup-worktrees.sh @@ -0,0 +1,289 @@ +#!/bin/bash + +# rules_antlr Multi-Agent Worktree Setup Script +# Creates git worktrees for parallel Claude Code development +# Now fully driven by todos.yaml configuration + +set -e # Exit on any error + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# Configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# Load YAML utilities +source "$SCRIPT_DIR/yaml-utils.sh" + +echo -e "${BLUE}🚀 Setting up YAML-driven multi-agent worktrees${NC}" +echo "=================================================" + +# Initialize YAML utilities +init_yaml_utils "$SCRIPT_DIR/todos.yaml" + +# Exit if YAML is not available +if ! require_yaml; then + echo -e "${BLUE}Alternative: Manual worktree creation${NC}" + echo "Check todos.yaml for git.branch and git.worktree_dir values" + exit 1 +fi + +# Check if we're in a git repository +if ! git rev-parse --git-dir > /dev/null 2>&1; then + echo -e "${RED}❌ Error: Not in a git repository${NC}" + exit 1 +fi + +# Check if we're in the main repository (not already in a worktree) +if [ -f .git ] && grep -q "gitdir:" .git; then + echo -e "${RED}❌ Error: Already in a worktree. Run this from the main repository${NC}" + exit 1 +fi + +# Read configuration from YAML +echo -e "${CYAN}📖 Reading configuration from todos.yaml...${NC}" +WORKTREE_BASE_DIR=$(get_config "worktree_base_dir") +DEFAULT_BRANCH=$(get_config "default_branch_base") + +# Ensure we're on main branch and up to date +echo -e "${YELLOW}📍 Ensuring $DEFAULT_BRANCH branch is up to date...${NC}" + +# Fetch latest changes from remote +echo -e " Fetching latest changes from remote..." +if ! git fetch origin "$DEFAULT_BRANCH"; then + echo -e "${RED}❌ Error: Failed to fetch from remote${NC}" + echo -e "${YELLOW}💡 This might be due to network issues or authentication problems${NC}" + exit 1 +fi + +# Switch to default branch +echo -e " Switching to $DEFAULT_BRANCH branch..." +if ! git checkout "$DEFAULT_BRANCH"; then + echo -e "${RED}❌ Error: Failed to checkout $DEFAULT_BRANCH branch${NC}" + echo -e "${YELLOW}💡 Make sure you have no uncommitted changes or use 'git stash' first${NC}" + exit 1 +fi + +# Update local branch with remote changes +echo -e " Updating $DEFAULT_BRANCH with remote changes..." +local_commit=$(git rev-parse HEAD) +remote_commit=$(git rev-parse "origin/$DEFAULT_BRANCH") + +if [ "$local_commit" != "$remote_commit" ]; then + echo -e " ${CYAN}Local and remote branches differ, updating...${NC}" + if ! git pull origin "$DEFAULT_BRANCH"; then + echo -e "${RED}❌ Error: Failed to pull changes from remote${NC}" + echo -e "${YELLOW}💡 This might be due to merge conflicts or force-push scenarios${NC}" + echo -e "${YELLOW}💡 Consider using 'git reset --hard origin/$DEFAULT_BRANCH' if you want to discard local changes${NC}" + exit 1 + fi +else + echo -e " ${GREEN}✅ $DEFAULT_BRANCH is already up to date${NC}" +fi + +# Create parent directory for worktrees (use absolute path for robustness) +REPO_ROOT="$(git rev-parse --show-toplevel)" +WORKTREE_DIR="${REPO_ROOT}/${WORKTREE_BASE_DIR}" +mkdir -p "$WORKTREE_DIR" + +echo -e "${BLUE}📁 Creating worktrees in: $WORKTREE_DIR${NC}" + +# Function to create worktree with error handling +create_worktree() { + local todo_id="$1" + local title="$2" + local branch_name="$3" + local dir_name="$4" + local priority="$5" + local phase="$6" + + local full_path="$WORKTREE_DIR/$dir_name" + + echo -e "${YELLOW}Creating worktree: $dir_name${NC}" + echo " TODO: $todo_id" + echo " Title: $title" + echo " Branch: $branch_name" + echo " Priority: $priority" + echo " Phase: $phase" + + if [ -d "$full_path" ]; then + echo -e "${YELLOW} ⚠️ Directory already exists, skipping...${NC}" + return + fi + + if git show-ref --verify --quiet "refs/heads/$branch_name"; then + echo -e "${YELLOW} ⚠️ Branch $branch_name already exists, using existing branch${NC}" + git worktree add "$full_path" "$branch_name" + else + git worktree add "$full_path" -b "$branch_name" + fi + + # Copy todos.yaml to each worktree for reference + if [ -f "$TODOS_YAML" ]; then + cp "$TODOS_YAML" "$full_path/" + fi + + # Also copy legacy TODO.md if it exists for backwards compatibility + if [ -f ".agents/TODO.md" ]; then + cp ".agents/TODO.md" "$full_path/" + elif [ -f "TODO.md" ]; then + cp "TODO.md" "$full_path/" + fi + + echo -e "${GREEN} ✅ Created: $full_path${NC}" + echo +} + +# Function to get phase color/emoji from YAML +get_phase_info() { + local phase_name="$1" + local info_type="$2" # "color", "emoji", "name", "description" + + yq eval ".phases.${phase_name}.${info_type}" "$TODOS_YAML" +} + +# Function to create worktrees for a specific phase +create_phase_worktrees() { + local phase_name="$1" + + local phase_display_name + phase_display_name=$(get_phase_info "$phase_name" "name") + local phase_description + phase_description=$(get_phase_info "$phase_name" "description") + local phase_emoji + phase_emoji=$(get_phase_info "$phase_name" "emoji") + local phase_parallel + phase_parallel=$(yq eval ".phases.${phase_name}.parallel" "$TODOS_YAML") + + echo -e "${BLUE}${phase_emoji} PHASE: ${phase_display_name}${NC}" + echo "Description: $phase_description" + if [ "$phase_parallel" = "true" ]; then + echo "Execution: Parallel (can run simultaneously)" + else + echo "Execution: Sequential" + fi + echo + + # Get all TODOs for this phase + local todo_count=0 + while IFS= read -r todo_index; do + # Skip if no todos found + if [ "$todo_index" = "null" ] || [ -z "$todo_index" ]; then + continue + fi + + local todo_id + todo_id=$(yq eval ".todos[${todo_index}].id" "$TODOS_YAML") + local todo_title + todo_title=$(yq eval ".todos[${todo_index}].title" "$TODOS_YAML") + local todo_status + todo_status=$(yq eval ".todos[${todo_index}].status // \"active\"" "$TODOS_YAML") + local branch_name + branch_name=$(yq eval ".todos[${todo_index}].git.branch" "$TODOS_YAML") + local worktree_dir + worktree_dir=$(yq eval ".todos[${todo_index}].git.worktree_dir" "$TODOS_YAML") + local priority + priority=$(yq eval ".todos[${todo_index}].priority" "$TODOS_YAML") + + # Skip cancelled TODOs + if [ "$todo_status" = "cancelled" ]; then + echo -e "${YELLOW}⚠️ Skipping $todo_id: CANCELLED${NC}" + echo " Reason: $(yq eval ".todos[${todo_index}].cancellation_reason // \"See YAML for details\"" "$TODOS_YAML")" + echo + continue + fi + + create_worktree "$todo_id" "$todo_title" "$branch_name" "$worktree_dir" "$priority" "$phase_name" + ((todo_count++)) + + done < <(yq eval ".todos | to_entries | map(select(.value.phase == \"$phase_name\")) | .[].key" "$TODOS_YAML") + + if [ $todo_count -eq 0 ]; then + echo -e "${YELLOW} No active TODOs found for phase: $phase_name${NC}" + echo + fi +} + +# Create worktrees for all phases dynamically from YAML +echo -e "${CYAN}📋 Creating worktrees for all phases...${NC}" +echo + +# Get all phase names from YAML and create worktrees in priority order +while IFS= read -r phase_name; do + if [ "$phase_name" != "null" ] && [ -n "$phase_name" ]; then + create_phase_worktrees "$phase_name" + fi +done < <(yq eval '.phases | to_entries | sort_by(.value.priority) | .[].key' "$TODOS_YAML") + +echo +echo -e "${GREEN}🎉 Worktree setup complete!${NC}" +echo "=================================================" + +# Display created worktrees +echo -e "${BLUE}📋 Created Worktrees:${NC}" +git worktree list | grep "$WORKTREE_DIR" | while read -r line; do + echo " $line" +done + +echo +echo -e "${BLUE}🚀 Next Steps:${NC}" +echo "1. Run parallel Claude sessions with: ./run-parallel-claude.sh" +echo "2. Or manually start Claude in each worktree:" +echo + +# Generate next steps dynamically from YAML +generate_next_steps() { + local phase_name="$1" + + local phase_display_name + phase_display_name=$(get_phase_info "$phase_name" "name") + local phase_emoji + phase_emoji=$(get_phase_info "$phase_name" "emoji") + + echo -e "${YELLOW} ${phase_emoji} ${phase_display_name}:${NC}" + + # Get all active TODOs for this phase + while IFS= read -r todo_index; do + if [ "$todo_index" = "null" ] || [ -z "$todo_index" ]; then + continue + fi + + local todo_id + todo_id=$(yq eval ".todos[${todo_index}].id" "$TODOS_YAML") + local todo_status + todo_status=$(yq eval ".todos[${todo_index}].status // \"active\"" "$TODOS_YAML") + local worktree_dir + worktree_dir=$(yq eval ".todos[${todo_index}].git.worktree_dir" "$TODOS_YAML") + + if [ "$todo_status" = "cancelled" ]; then + echo " # $todo_id [CANCELLED] - $(yq eval ".todos[${todo_index}].cancellation_reason // \"See YAML for details\"" "$TODOS_YAML")" + else + echo " cd \"$WORKTREE_DIR/$worktree_dir\" && claude # $todo_id" + fi + + done < <(yq eval ".todos | to_entries | map(select(.value.phase == \"$phase_name\")) | .[].key" "$TODOS_YAML") + echo +} + +# Generate next steps for all phases in priority order +while IFS= read -r phase_name; do + if [ "$phase_name" != "null" ] && [ -n "$phase_name" ]; then + generate_next_steps "$phase_name" + fi +done < <(yq eval '.phases | to_entries | sort_by(.value.priority) | .[].key' "$TODOS_YAML") + +echo -e "${BLUE}💡 Tips:${NC}" +echo "• Use tmux/screen to manage multiple Claude sessions" +echo "• Each worktree has its own copy of todos.yaml for reference" +echo "• Start with highest priority phase for maximum impact" +echo "• Run ./merge-workflow.sh when ready to create PRs" +echo "• Run ./cleanup-worktrees.sh when finished" +echo "• Check todos.yaml for detailed agent prompts and fix strategies" + +echo +echo -e "${GREEN}✨ Ready for YAML-driven parallel multi-agent development!${NC}" \ No newline at end of file diff --git a/.agents/test-workflow.sh b/.agents/test-workflow.sh new file mode 100755 index 0000000..5d76d3b --- /dev/null +++ b/.agents/test-workflow.sh @@ -0,0 +1,397 @@ +#!/bin/bash + +# rules_antlr Parallel Development Workflow Test Suite +# Validates the multi-agent worktree workflow functionality + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +PURPLE='\033[0;35m' +NC='\033[0m' # No Color + +# Use absolute path for robustness across different execution contexts +REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || echo "$(pwd)/..")" +WORKTREE_DIR="${REPO_ROOT}/../rules_antlr-worktrees" +TEST_LOG="workflow-test.log" + +# Test counters +TESTS_RUN=0 +TESTS_PASSED=0 +TESTS_FAILED=0 + +# Function to log test results +log_test() { + local test_name="$1" + local status="$2" + local details="$3" + + echo "$(date '+%Y-%m-%d %H:%M:%S') [$status] $test_name: $details" >> "$TEST_LOG" +} + +# Function to run a test +run_test() { + local test_name="$1" + local test_command="$2" + + ((TESTS_RUN++)) + + echo -e "${CYAN}🧪 Testing: $test_name${NC}" + + if eval "$test_command"; then + echo -e " ${GREEN}✅ PASSED${NC}" + ((TESTS_PASSED++)) + log_test "$test_name" "PASS" "Test completed successfully" + return 0 + else + echo -e " ${RED}❌ FAILED${NC}" + ((TESTS_FAILED++)) + log_test "$test_name" "FAIL" "Test failed: $test_command" + return 1 + fi +} + +# Function to check script exists and is executable +test_script_executable() { + local script_name="$1" + + if [ ! -f "$script_name" ]; then + echo -e " ${RED}Script not found: $script_name${NC}" + return 1 + fi + + if [ ! -x "$script_name" ]; then + echo -e " ${RED}Script not executable: $script_name${NC}" + return 1 + fi + + echo -e " ${GREEN}Script exists and is executable${NC}" + return 0 +} + +# Function to test worktree setup +test_worktree_setup() { + echo -e "${BLUE}Testing worktree setup functionality...${NC}" + + # Clean up any existing worktrees first + ./cleanup-worktrees.sh all --force > /dev/null 2>&1 || true + + # Test script existence and executability + run_test "setup-worktrees.sh exists and executable" \ + "test_script_executable './setup-worktrees.sh'" \ + "true" + + # Test script basic functionality (just run it to check syntax) + run_test "setup-worktrees.sh script syntax check" \ + "bash -n ./setup-worktrees.sh" \ + "true" # Check if script has valid bash syntax + + # Test actual worktree creation + echo -e "${YELLOW} Creating test worktrees...${NC}" + if ./setup-worktrees.sh > /dev/null 2>&1; then + run_test "Worktree creation successful" \ + "[ -d \"$WORKTREE_DIR\" ]" \ + "true" + + run_test "All expected worktrees created" \ + "[ -d \"$WORKTREE_DIR/npe-env\" ] && [ -d \"$WORKTREE_DIR/npe-builder\" ] && [ -d \"$WORKTREE_DIR/resource-process\" ]" \ + "true" + + run_test "TODO.md copied to worktrees" \ + "[ -f \"$WORKTREE_DIR/npe-env/TODO.md\" ]" \ + "true" + else + echo -e " ${RED}Failed to create worktrees${NC}" + ((TESTS_FAILED++)) + fi +} + +# Function to test parallel Claude launcher +test_parallel_launcher() { + echo -e "${BLUE}Testing parallel Claude launcher...${NC}" + + run_test "run-parallel-claude.sh exists and executable" \ + "test_script_executable './run-parallel-claude.sh'" \ + "true" + + # Test help output + run_test "Parallel launcher help" \ + "./run-parallel-claude.sh | grep -q 'Usage:'" \ + "true" + + # Test status command (should work without tmux) + run_test "Status command works" \ + "./run-parallel-claude.sh status | grep -q 'Active Claude Code Sessions'" \ + "true" + + # Test tmux detection + if command -v tmux &> /dev/null; then + echo -e " ${GREEN}tmux available for session testing${NC}" + run_test "tmux availability check" "command -v tmux &> /dev/null" "true" + else + echo -e " ${YELLOW}tmux not available, skipping session tests${NC}" + run_test "tmux not available warning" \ + "./run-parallel-claude.sh critical 2>&1 | grep -q 'tmux is required'" \ + "true" + fi +} + +# Function to test merge workflow +test_merge_workflow() { + echo -e "${BLUE}Testing merge workflow coordination...${NC}" + + run_test "merge-workflow.sh exists and executable" \ + "test_script_executable './merge-workflow.sh'" \ + "true" + + # Test status command + run_test "Merge workflow status" \ + "./merge-workflow.sh status | grep -q 'Checking status of all worktrees'" \ + "true" + + # Test GitHub CLI detection + if command -v gh &> /dev/null; then + echo -e " ${GREEN}GitHub CLI available${NC}" + run_test "GitHub CLI availability" "command -v gh &> /dev/null" "true" + else + echo -e " ${YELLOW}GitHub CLI not available${NC}" + run_test "GitHub CLI missing warning" \ + "./merge-workflow.sh critical 2>&1 | grep -q 'GitHub CLI.*is required'" \ + "true" + fi +} + +# Function to test cleanup functionality +test_cleanup() { + echo -e "${BLUE}Testing cleanup functionality...${NC}" + + run_test "cleanup-worktrees.sh exists and executable" \ + "test_script_executable './cleanup-worktrees.sh'" \ + "true" + + # Test status command + run_test "Cleanup status command" \ + "./cleanup-worktrees.sh status | grep -q 'Current Multi-Agent Environment Status'" \ + "true" + + # Test dry run + run_test "Cleanup dry run" \ + "./cleanup-worktrees.sh all --dry-run | grep -q 'DRY RUN MODE'" \ + "true" +} + +# Function to test TODO.md structure +test_todo_structure() { + echo -e "${BLUE}Testing TODO.md structure and content...${NC}" + + run_test "TODO.md exists" \ + "[ -f './TODO.md' ]" \ + "true" + + run_test "TODO.md has quick start section" \ + "grep -q 'Quick Start: Parallel Multi-Agent Workflow' ./TODO.md" \ + "true" + + # Check TODO items more flexibly (account for cancelled TODO-005) + worktree_count=$(grep -c 'Worktree Setup' ./TODO.md 2>/dev/null || echo "0") + run_test "TODO items have worktree setup (found: $worktree_count)" \ + "[ \"$worktree_count\" -ge \"8\" ]" \ + "true" + + claude_count=$(grep -c '🤖 Claude Session' ./TODO.md 2>/dev/null || echo "0") + run_test "TODO items have Claude session info (found: $claude_count)" \ + "[ \"$claude_count\" -ge \"8\" ]" \ + "true" + + run_test "TODO.md has orchestration strategy" \ + "grep -q 'Multi-Agent Orchestration Strategy' ./TODO.md" \ + "true" +} + +# Function to test git repository state +test_git_state() { + echo -e "${BLUE}Testing git repository state...${NC}" + + run_test "In git repository" \ + "git rev-parse --git-dir > /dev/null 2>&1" \ + "true" + + # Check current branch (may not be main due to feature branch) + current_branch=$(git branch --show-current 2>/dev/null || echo "unknown") + run_test "Git branch detected" \ + "[ -n \"$current_branch\" ]" \ + "true" + + run_test "Working directory has changes" \ + "git diff --quiet && git diff --cached --quiet || true" \ + "true" # We expect changes, so this should always pass +} + +# Function to test end-to-end workflow +test_e2e_workflow() { + echo -e "${BLUE}Testing end-to-end workflow simulation...${NC}" + + # Clean state + ./cleanup-worktrees.sh all --force > /dev/null 2>&1 || true + + # Setup + echo -e "${YELLOW} Setting up worktrees...${NC}" + if ./setup-worktrees.sh > /dev/null 2>&1; then + run_test "E2E: Worktree setup" "[ -d \"$WORKTREE_DIR\" ]" "true" + + # Test that we can navigate to worktrees + run_test "E2E: Can navigate to worktrees" \ + "(cd \"$WORKTREE_DIR/npe-env\" && pwd | grep -q 'npe-env')" \ + "true" + + # Test that TODO.md is available in worktrees + run_test "E2E: TODO.md available in worktrees" \ + "[ -f \"$WORKTREE_DIR/npe-env/TODO.md\" ]" \ + "true" + + # Test merge workflow status + run_test "E2E: Merge workflow can check status" \ + "./merge-workflow.sh status > /dev/null 2>&1" \ + "true" + + # Cleanup + echo -e "${YELLOW} Cleaning up test environment...${NC}" + ./cleanup-worktrees.sh all --force > /dev/null 2>&1 || true + + run_test "E2E: Cleanup successful" \ + "[ ! -d \"$WORKTREE_DIR\" ]" \ + "true" + else + echo -e " ${RED}E2E test failed: Could not set up worktrees${NC}" + ((TESTS_FAILED++)) + fi +} + +# Function to test dependencies +test_dependencies() { + echo -e "${BLUE}Testing system dependencies...${NC}" + + run_test "Git available" "command -v git &> /dev/null" "true" + run_test "Bash version 4+" "bash --version | head -1 | grep -q 'version [4-9]'" "true" + + # Optional dependencies + if command -v tmux &> /dev/null; then + run_test "tmux available (optional)" "command -v tmux &> /dev/null" "true" + else + echo -e " ${YELLOW}tmux not available (parallel sessions will be limited)${NC}" + fi + + if command -v gh &> /dev/null; then + run_test "GitHub CLI available (optional)" "command -v gh &> /dev/null" "true" + else + echo -e " ${YELLOW}GitHub CLI not available (manual PR creation required)${NC}" + fi +} + +# Function to show usage +show_usage() { + echo -e "${BLUE}Usage: $0 [test-suite]${NC}" + echo + echo "Test Suites:" + echo " all - Run all test suites (DEFAULT)" + echo " scripts - Test script existence and basic functionality" + echo " setup - Test worktree setup functionality" + echo " launcher - Test parallel Claude launcher" + echo " merge - Test merge workflow coordination" + echo " cleanup - Test cleanup functionality" + echo " todo - Test TODO.md structure" + echo " git - Test git repository state" + echo " e2e - End-to-end workflow simulation" + echo " deps - Test system dependencies" + echo + echo "Examples:" + echo " $0 # Run all tests" + echo " $0 scripts # Test only script functionality" + echo " $0 e2e # Run end-to-end workflow test" +} + +# Initialize test log +echo "=== rules_antlr Parallel Workflow Test Suite $(date) ===" > "$TEST_LOG" + +echo -e "${PURPLE}🚀 rules_antlr Parallel Development Workflow Test Suite${NC}" +echo "=========================================================" +echo + +# Parse command line argument +TEST_SUITE="${1:-all}" + +case "$TEST_SUITE" in + "all") + test_dependencies + echo + test_todo_structure + echo + test_git_state + echo + test_worktree_setup + echo + test_parallel_launcher + echo + test_merge_workflow + echo + test_cleanup + echo + test_e2e_workflow + ;; + "scripts") + run_test "setup-worktrees.sh" "test_script_executable './setup-worktrees.sh'" "true" + run_test "run-parallel-claude.sh" "test_script_executable './run-parallel-claude.sh'" "true" + run_test "merge-workflow.sh" "test_script_executable './merge-workflow.sh'" "true" + run_test "cleanup-worktrees.sh" "test_script_executable './cleanup-worktrees.sh'" "true" + ;; + "setup") + test_worktree_setup + ;; + "launcher") + test_parallel_launcher + ;; + "merge") + test_merge_workflow + ;; + "cleanup") + test_cleanup + ;; + "todo") + test_todo_structure + ;; + "git") + test_git_state + ;; + "e2e") + test_e2e_workflow + ;; + "deps") + test_dependencies + ;; + *) + show_usage + exit 1 + ;; +esac + +echo +echo -e "${BLUE}📊 Test Results Summary${NC}" +echo "========================" +echo -e "Tests Run: ${CYAN}$TESTS_RUN${NC}" +echo -e "Tests Passed: ${GREEN}$TESTS_PASSED${NC}" +echo -e "Tests Failed: ${RED}$TESTS_FAILED${NC}" + +if [ $TESTS_FAILED -eq 0 ]; then + echo -e "\n${GREEN}🎉 All tests passed! Workflow is ready for use.${NC}" + log_test "TEST_SUITE_COMPLETE" "SUCCESS" "All $TESTS_RUN tests passed" + exit 0 +else + echo -e "\n${RED}⚠️ Some tests failed. Check the issues above.${NC}" + echo -e "See detailed log: ${CYAN}$TEST_LOG${NC}" + log_test "TEST_SUITE_COMPLETE" "FAILURE" "$TESTS_FAILED of $TESTS_RUN tests failed" + exit 1 +fi \ No newline at end of file diff --git a/.agents/todos.yaml b/.agents/todos.yaml new file mode 100644 index 0000000..643e217 --- /dev/null +++ b/.agents/todos.yaml @@ -0,0 +1,509 @@ +# rules_antlr Multi-Agent TODO Configuration +# Flexible YAML-driven configuration for parallel bug fixing workflow + +version: "1.0" +project: "rules_antlr" +description: "Critical vulnerabilities and improvements in rules_antlr codebase" + +# Global configuration +config: + worktree_base_dir: "../rules_antlr-worktrees" + tmux_session_prefix: "rules-antlr" + default_branch_base: "main" + +# Phase definitions for organizing work +phases: + critical: + name: "Critical NPE Fixes" + description: "15 critical NPE vulnerabilities that could cause JVM crashes" + priority: 1 + parallel: true + color: "RED" + emoji: "🔴" + + bazel: + name: "Bazel Compatibility Fixes" + description: "High-priority Bazel logic errors breaking newer versions" + priority: 2 + parallel: false + color: "YELLOW" + emoji: "🟠" + + resource: + name: "Resource Management Fixes" + description: "Medium-priority resource leaks causing gradual degradation" + priority: 3 + parallel: true + color: "BLUE" + emoji: "🟡" + + quality: + name: "Quality Improvements" + description: "Lower priority code quality and safety improvements" + priority: 4 + parallel: true + color: "GREEN" + emoji: "🟢" + +# Individual TODO items +todos: + # CRITICAL PHASE - NPE Vulnerabilities + - id: "TODO-001" + title: "Environment Variable NPE Fixes" + description: "Fix critical NPE vulnerabilities in AntlrRules.java main method" + phase: "critical" + priority: "CRITICAL" + agent_type: "NPE-Specialist" + dependencies: [] + + # Git configuration + git: + branch: "fix/npe-environment-variables" + worktree_dir: "npe-env" + tmux_session: "rules-antlr-npe-env" + + # Files to modify + files: + - "src/main/java/org/antlr/bazel/AntlrRules.java:88-99" + + # Complex multiline agent prompt + agent_prompt: |- + Fix critical NPE vulnerabilities in AntlrRules.java main method. The following lines access environment variables and immediately call methods without null checks: + + Line 90: env.get("TOOL_CLASSPATH").split(",") + Line 93: env.get("GRAMMARS").split(",") + + These will throw NPE if environment variables are not set. Add defensive null checks and provide meaningful error messages. + + Implementation steps: + 1. Add null checks for each env.get() call + 2. Throw IllegalStateException with descriptive message if required env vars missing + 3. Consider providing default values where appropriate + 4. Maintain existing builder pattern flow + + Verification: Create test that calls main() with missing environment variables and verify proper error handling instead of NPE. + + # Fix strategy with code examples + fix_strategy: |- + Replace: + .classpath(env.get("TOOL_CLASSPATH").split(",")) + + With: + .classpath(getRequiredEnvVar(env, "TOOL_CLASSPATH").split(",")) + + private static String getRequiredEnvVar(Map env, String name) { + String value = env.get(name); + if (value == null) { + throw new IllegalStateException("Required environment variable not set: " + name); + } + return value; + } + + - id: "TODO-002" + title: "Builder Method Parameter NPE Fixes" + description: "Fix NPE vulnerabilities in AntlrRules builder methods" + phase: "critical" + priority: "CRITICAL" + agent_type: "NPE-Specialist" + dependencies: [] + + git: + branch: "fix/npe-builder-parameters" + worktree_dir: "npe-builder" + tmux_session: "rules-antlr-npe-builder" + + files: + - "src/main/java/org/antlr/bazel/AntlrRules.java:129" + - "src/main/java/org/antlr/bazel/AntlrRules.java:393" + - "src/main/java/org/antlr/bazel/AntlrRules.java:401" + - "src/main/java/org/antlr/bazel/AntlrRules.java:409" + - "src/main/java/org/antlr/bazel/AntlrRules.java:426" + + agent_prompt: |- + Fix NPE vulnerabilities in AntlrRules builder methods. These methods call .isEmpty() or .trim() on parameters without null checks: + + - encoding(String encoding) - Line 129: encoding.isEmpty() + - language(String language) - Line 393: language.isEmpty() + - layout(String layout) - Line 401: layout.isEmpty() + - namespace(String namespace) - Line 409: namespace.isEmpty() + - srcjar(String srcjar) - Line 426: srcjar.trim().isEmpty() + + Add null guards at the beginning of each method. For null inputs, either return early with 'this' (no-op) or use appropriate default values. + + Verification: Write unit tests passing null to each builder method and verify no NPE thrown. + + fix_strategy: |- + AntlrRules encoding(String encoding) { + if (encoding == null) return this; // or use default charset + this.encoding = encoding.isEmpty() ? Charset.defaultCharset() : Charset.forName(encoding); + return this; + } + + - id: "TODO-003" + title: "Language Path Conversion NPE Fixes" + description: "Fix NPE vulnerabilities in Language enum toId() methods" + phase: "critical" + priority: "CRITICAL" + agent_type: "NPE-Specialist" + dependencies: [] + + git: + branch: "fix/npe-language-path-conversion" + worktree_dir: "npe-language" + tmux_session: "rules-antlr-npe-language" + + files: + - "src/main/java/org/antlr/bazel/Language.java:28" + - "src/main/java/org/antlr/bazel/Language.java:59" + - "src/main/java/org/antlr/bazel/Language.java:92" + - "src/main/java/org/antlr/bazel/Language.java:127" + - "src/main/java/org/antlr/bazel/Language.java:173" + - "src/main/java/org/antlr/bazel/Language.java:213" + - "src/main/java/org/antlr/bazel/Language.java:246" + - "src/main/java/org/antlr/bazel/Language.java:277" + - "src/main/java/org/antlr/bazel/Language.java:311" + - "src/main/java/org/antlr/bazel/Language.java:356" + + agent_prompt: |- + Fix NPE vulnerabilities in Language enum toId() methods. Multiple language implementations call path.toString() without null checks: + + Affected methods in Language.java: + - C.toId() - Line 28 + - CPP.toId() - Line 59 + - CSHARP.toId() - Line 92 + - GO.toId() - Line 127 + - JAVA.toId() - Line 173 + - JAVASCRIPT.toId() - Line 213 + - OBJC.toId() - Line 246 + - PYTHON.toId() - Line 277 + - RUBY.toId() - Line 311 + - SWIFT.toId() - Line 356 + + Add null check at beginning of each toId() method and throw IllegalArgumentException with descriptive message. + + Verification: Test each language's toId() method with null Path parameter and verify proper exception thrown. + + fix_strategy: |- + @Override + public String toId(Path path) { + if (path == null) { + throw new IllegalArgumentException("path cannot be null"); + } + return path.toString().replaceAll("[/\\\\]", "."); + } + + - id: "TODO-004" + title: "Utility Method NPE Fixes" + description: "Fix NPE vulnerabilities in utility methods using switch statements" + phase: "critical" + priority: "CRITICAL" + agent_type: "NPE-Specialist" + dependencies: [] + + git: + branch: "fix/npe-utility-methods" + worktree_dir: "npe-utility" + tmux_session: "rules-antlr-npe-utility" + + files: + - "src/main/java/org/antlr/bazel/Language.java:469" + - "src/main/java/org/antlr/bazel/Version.java:22" + - "src/main/java/org/antlr/bazel/Strings.java:26" + + agent_prompt: |- + Fix NPE vulnerabilities in utility methods that use switch statements without null checks: + + 1. Language.of(String name) - Line 469: Switch on name without null check + 2. Version.of(String version) - Line 22: Switch on version without null check + 3. Strings.stripFileExtension(String path) - Line 26: path.lastIndexOf() without null check + + Add null checks before switch statements and string method calls. Throw IllegalArgumentException with descriptive messages. + + Verification: Test each method with null parameter and verify proper exception handling. + + fix_strategy: |- + public static Language of(String name) { + if (name == null) { + throw new IllegalArgumentException("language name cannot be null"); + } + switch (name) { + // existing cases... + } + } + + # BAZEL PHASE - Compatibility Fixes + - id: "TODO-005" + title: "Bazel Starlark Dictionary Access Fix" + description: "CANCELLED - This TODO was based on incorrect information" + phase: "bazel" + priority: "CANCELLED" + agent_type: "Bazel-Specialist" + dependencies: [] + status: "cancelled" + + git: + branch: "fix/bazel-dict-access" + worktree_dir: "bazel-dict" + tmux_session: "rules-antlr-bazel-dict" + + files: + - "antlr/impl.bzl:134" + + agent_prompt: |- + ❌ CANCELLED: This TODO was based on incorrect information + + Analysis: Research shows that `dict.keys()[0]` is NOT deprecated in any Bazel version: + - ✅ Current Bazel 7.5.0 documentation confirms `dict.keys()` returns a list that supports indexing + - ❌ No evidence found of deprecation in Bazel 6.0+ in official docs or release notes + - ⚠️ Starlark issue #203 discusses potential future changes but they are not implemented + + Current Status: The existing code `lib.keys()[0]` is correct and valid Bazel/Starlark syntax. + + Resolution: + - No code changes required + - The proposed fix `list(lib.keys())[0]` would add unnecessary overhead + - Current implementation follows documented Bazel/Starlark patterns + + cancellation_reason: "Incorrect analysis - dict.keys()[0] is valid Starlark syntax" + + - id: "TODO-006" + title: "Bazel String Method Fix" + description: "CANCELLED - This TODO was based on incorrect information" + phase: "bazel" + priority: "CANCELLED" + agent_type: "Bazel-Specialist" + dependencies: [] + status: "cancelled" + + git: + branch: "fix/bazel-string-methods" + worktree_dir: "bazel-string" + tmux_session: "rules-antlr-bazel-string" + + files: + - "antlr/repositories.bzl:198" + - "antlr/repositories.bzl:274" + + agent_prompt: |- + ❌ CANCELLED: This TODO was based on incorrect information + + Analysis: Research shows that `.elems()` method DOES exist for strings in Starlark: + - ✅ Official Bazel documentation confirms strings are NOT directly iterable in Starlark + - ✅ The `.elems()` method is the CORRECT way to iterate over string characters + - ✅ Example from docs: "abc".elems() returns ["a", "b", "c"] + - ✅ Current code `.join(str(version).elems())` follows proper Starlark patterns + + Current Status: The existing code is correct and valid Starlark syntax. + + Resolution: + - No code changes required + - The proposed fix would break the intended functionality + - Current implementation follows documented Bazel/Starlark patterns + + cancellation_reason: "Incorrect analysis - .elems() method exists and is correct Starlark syntax" + + # RESOURCE PHASE - Memory Management + - id: "TODO-007" + title: "Process Stream Resource Leak Fixes" + description: "Fix resource leaks in Command.java process handling" + phase: "resource" + priority: "MEDIUM" + agent_type: "Resource-Specialist" + dependencies: [] + + git: + branch: "fix/process-stream-leaks" + worktree_dir: "resource-process" + tmux_session: "rules-antlr-resource-process" + + files: + - "src/it/java/org/antlr/bazel/Command.java:104" + + agent_prompt: |- + Fix resource leak in Command.java build() method. Line 104 reads process InputStream without proper resource management: + + output = new String(p.getInputStream().readAllBytes()); + + This can cause file handle leaks during integration testing. Use try-with-resources to ensure proper cleanup. + + Fix by wrapping in try-with-resources: + try (InputStream is = p.getInputStream()) { + output = new String(is.readAllBytes()); + } + + Verification: + 1. Run integration tests and monitor file handle usage + 2. Verify no resource leaks using tools like lsof + 3. Test with multiple concurrent Command executions + + fix_strategy: |- + try (InputStream is = p.getInputStream()) { + output = new String(is.readAllBytes()); + } + + - id: "TODO-008" + title: "File Stream Resource Leak Fixes" + description: "Fix resource leaks in TestWorkspace file handling" + phase: "resource" + priority: "MEDIUM" + agent_type: "Resource-Specialist" + dependencies: [] + + git: + branch: "fix/file-stream-leaks" + worktree_dir: "resource-file" + tmux_session: "rules-antlr-resource-file" + + files: + - "src/it/java/org/antlr/bazel/TestWorkspace.java:67" + + agent_prompt: |- + Fix resource leak in TestWorkspace constructor. Line 67 uses Files.walk() without proper resource management: + + Files.walk(examples) + .filter(path -> !Files.isDirectory(path)) + .forEach(source -> { ... }); + + Files.walk() returns a Stream that must be closed to prevent file handle leaks. Use try-with-resources. + + Fix by wrapping in try-with-resources: + try (Stream walk = Files.walk(examples)) { + walk.filter(path -> !Files.isDirectory(path)) + .forEach(source -> { ... }); + } + + Verification: + 1. Create multiple TestWorkspace instances and monitor file handles + 2. Verify proper cleanup using resource monitoring tools + 3. Test with large directory structures to amplify any leaks + + fix_strategy: |- + try (Stream walk = Files.walk(examples)) { + walk.filter(path -> !Files.isDirectory(path)) + .forEach(source -> { ... }); + } + + # QUALITY PHASE - Code Improvements + - id: "TODO-009" + title: "Array Bounds Safety Improvements" + description: "Fix potential array bounds violations" + phase: "quality" + priority: "MEDIUM" + agent_type: "Safety-Specialist" + dependencies: [] + + git: + branch: "fix/array-bounds-safety" + worktree_dir: "safety-bounds" + tmux_session: "rules-antlr-quality-bounds" + + files: + - "src/main/java/org/antlr/bazel/AntlrRules.java:553" + + agent_prompt: |- + Fix potential array bounds violation in expandSrcJarImports() method. Line 553 accesses args[i + 1] without checking if i+1 is within array bounds: + + if (args[i].equals("-lib") && args[i + 1].endsWith(".srcjar")) + + If "-lib" is the last argument, this throws ArrayIndexOutOfBoundsException. + + Add bounds check: + if (args[i].equals("-lib") && i + 1 < args.length && args[i + 1].endsWith(".srcjar")) + + Verification: + 1. Test with args array ending in "-lib" to verify no exception + 2. Test normal cases to ensure functionality preserved + 3. Add unit test covering this edge case + + fix_strategy: |- + if (args[i].equals("-lib") && i + 1 < args.length && args[i + 1].endsWith(".srcjar")) + + - id: "TODO-010" + title: "Error Message Quality Improvements" + description: "Improve error message formatting consistency" + phase: "quality" + priority: "LOW" + agent_type: "Quality-Specialist" + dependencies: [] + + git: + branch: "fix/error-message-quality" + worktree_dir: "quality-messages" + tmux_session: "rules-antlr-quality-messages" + + files: + - "src/main/java/org/antlr/bazel/Version.java:43" + + agent_prompt: |- + Improve error message formatting by adding missing spaces. Line 43 in Version.java: + + throw new IllegalArgumentException("Unknown version" + version); + + Should be: + throw new IllegalArgumentException("Unknown version: " + version); + + Search for similar patterns throughout codebase and fix consistently. + + Verification: + 1. Trigger error conditions and verify messages are properly formatted + 2. Ensure consistent formatting across all error messages + 3. Test error message readability in build logs + + fix_strategy: |- + throw new IllegalArgumentException("Unknown version: " + version); + +# Workflow orchestration +workflows: + # Recommended execution order + recommended_order: + - phase: "critical" + description: "Start with critical NPE fixes - highest impact" + parallel_sessions: 4 + + - phase: "bazel" + description: "Bazel compatibility fixes" + parallel_sessions: 1 + note: "TODO-005 is cancelled, only TODO-006 needs fixing" + + - phase: "resource" + description: "Resource management fixes" + parallel_sessions: 2 + + - phase: "quality" + description: "Quality improvements" + parallel_sessions: 2 + + # Integration testing after each phase + integration_tests: + after_critical: |- + Run full integration test suite + Test with multiple Bazel versions (5.x, 6.x, 7.x) + Performance testing to ensure no degradation + Security review of all changes + + after_each_merge: |- + Run existing test suite to ensure no regressions + Manual testing of affected functionality + Code review for security implications + +# Agent specializations +agent_types: + NPE-Specialist: + description: "Focuses on null pointer vulnerabilities, defensive programming" + expertise: ["null safety", "defensive programming", "exception handling"] + + Bazel-Specialist: + description: "Expert in Starlark syntax, Bazel version compatibility" + expertise: ["Starlark", "Bazel rules", "build system compatibility"] + + Resource-Specialist: + description: "Resource management, try-with-resources patterns" + expertise: ["resource management", "stream handling", "memory leaks"] + + Safety-Specialist: + description: "Bounds checking, edge case handling" + expertise: ["array bounds", "edge cases", "defensive programming"] + + Quality-Specialist: + description: "Code style, error messages, documentation" + expertise: ["code quality", "error messages", "consistency"] \ No newline at end of file diff --git a/.agents/workflow-test.log b/.agents/workflow-test.log new file mode 100644 index 0000000..8d315d8 --- /dev/null +++ b/.agents/workflow-test.log @@ -0,0 +1 @@ +=== rules_antlr Parallel Workflow Test Suite Thu Jul 24 07:59:40 AM UTC 2025 === diff --git a/.agents/yaml-utils.sh b/.agents/yaml-utils.sh new file mode 100644 index 0000000..e253b20 --- /dev/null +++ b/.agents/yaml-utils.sh @@ -0,0 +1,362 @@ +#!/bin/bash + +# YAML Utility Functions for rules_antlr Multi-Agent System +# Shared utilities for YAML parsing, validation, and dependency checking +# Source this file in other scripts: source "$(dirname "${BASH_SOURCE[0]}")/yaml-utils.sh" + +# Colors for output (if not already defined) +if [ -z "$RED" ]; then + RED='\033[0;31m' + GREEN='\033[0;32m' + YELLOW='\033[1;33m' + BLUE='\033[0;34m' + NC='\033[0m' # No Color +fi + +# Global variables +YAML_UTILS_INITIALIZED=false +YAML_AVAILABLE=false +TODOS_YAML_PATH="" + +# Function to initialize YAML utilities +# Usage: init_yaml_utils [path_to_todos_yaml] +init_yaml_utils() { + local todos_yaml_path="${1:-$(dirname "${BASH_SOURCE[0]}")/todos.yaml}" + + TODOS_YAML_PATH="$todos_yaml_path" + + # Check if yq is available + if ! command -v yq &> /dev/null; then + echo -e "${YELLOW}⚠️ Warning: yq not found. YAML features disabled.${NC}" >&2 + echo -e "${BLUE}Install yq for full YAML support:${NC}" >&2 + echo " macOS: brew install yq" >&2 + echo " Ubuntu: sudo apt-get install yq" >&2 + echo " Arch: sudo pacman -S yq" >&2 + echo " Or download from: https://github.com/mikefarah/yq/releases" >&2 + YAML_AVAILABLE=false + else + YAML_AVAILABLE=true + fi + + # Validate YAML file if yq is available + if [ "$YAML_AVAILABLE" = "true" ]; then + if [ ! -f "$TODOS_YAML_PATH" ]; then + echo -e "${RED}❌ Error: todos.yaml not found at $TODOS_YAML_PATH${NC}" >&2 + YAML_AVAILABLE=false + elif ! yq eval '.' "$TODOS_YAML_PATH" > /dev/null 2>&1; then + echo -e "${RED}❌ Error: Invalid YAML syntax in $TODOS_YAML_PATH${NC}" >&2 + YAML_AVAILABLE=false + else + echo -e "${GREEN}✅ YAML configuration loaded successfully${NC}" >&2 + fi + fi + + YAML_UTILS_INITIALIZED=true +} + +# Function to check if YAML utilities are initialized and available +require_yaml() { + if [ "$YAML_UTILS_INITIALIZED" != "true" ]; then + echo -e "${RED}❌ Error: YAML utilities not initialized. Call init_yaml_utils first.${NC}" >&2 + return 1 + fi + + if [ "$YAML_AVAILABLE" != "true" ]; then + echo -e "${RED}❌ Error: YAML functionality not available.${NC}" >&2 + return 1 + fi + + return 0 +} + +# Function to get a YAML value with fallback +# Usage: yaml_get_or_default +yaml_get_or_default() { + local yaml_path="$1" + local default_value="$2" + + if ! require_yaml; then + echo "$default_value" + return 0 + fi + + local result + result=$(yq eval "$yaml_path" "$TODOS_YAML_PATH" 2>/dev/null) + + if [ "$result" = "null" ] || [ -z "$result" ]; then + echo "$default_value" + else + echo "$result" + fi +} + +# Function to get all TODO indices +# Usage: get_all_todo_indices +get_all_todo_indices() { + if ! require_yaml; then + return 1 + fi + + local total_todos + total_todos=$(yq eval '.todos | length' "$TODOS_YAML_PATH") + + for (( i=0; i +get_phase_todo_indices() { + local phase_name="$1" + + if ! require_yaml; then + return 1 + fi + + yq eval ".todos | to_entries | map(select(.value.phase == \"$phase_name\")) | .[].key" "$TODOS_YAML_PATH" +} + +# Function to get all phase names sorted by priority +# Usage: get_all_phases +get_all_phases() { + if ! require_yaml; then + return 1 + fi + + yq eval '.phases | to_entries | sort_by(.value.priority) | .[].key' "$TODOS_YAML_PATH" +} + +# Function to get TODO field value +# Usage: get_todo_field +get_todo_field() { + local todo_index="$1" + local field_path="$2" + + if ! require_yaml; then + return 1 + fi + + yq eval ".todos[${todo_index}].${field_path}" "$TODOS_YAML_PATH" +} + +# Function to get phase field value +# Usage: get_phase_field +get_phase_field() { + local phase_name="$1" + local field_path="$2" + + if ! require_yaml; then + return 1 + fi + + yq eval ".phases.${phase_name}.${field_path}" "$TODOS_YAML_PATH" +} + +# Function to get configuration value +# Usage: get_config +get_config() { + local config_path="$1" + + if ! require_yaml; then + return 1 + fi + + yq eval ".config.${config_path}" "$TODOS_YAML_PATH" +} + +# Function to validate phase exists +# Usage: validate_phase +validate_phase() { + local phase_name="$1" + + if ! require_yaml; then + return 1 + fi + + yq eval ".phases | has(\"$phase_name\")" "$TODOS_YAML_PATH" | grep -q "true" +} + +# Function to check if TODO is active (not cancelled) +# Usage: is_todo_active +is_todo_active() { + local todo_index="$1" + + if ! require_yaml; then + return 1 + fi + + local status + status=$(yq eval ".todos[${todo_index}].status // \"active\"" "$TODOS_YAML_PATH") + + [ "$status" != "cancelled" ] +} + +# Function to get active TODO count for a phase +# Usage: get_active_todo_count +get_active_todo_count() { + local phase_name="$1" + + if ! require_yaml; then + return 1 + fi + + yq eval ".todos | map(select(.phase == \"$phase_name\" and (.status // \"active\") != \"cancelled\")) | length" "$TODOS_YAML_PATH" +} + +# Function to get total active TODO count +# Usage: get_total_active_todo_count +get_total_active_todo_count() { + if ! require_yaml; then + return 1 + fi + + yq eval '.todos | map(select((.status // "active") != "cancelled")) | length' "$TODOS_YAML_PATH" +} + +# Function to check YAML schema validity +# Usage: validate_yaml_schema +validate_yaml_schema() { + if ! require_yaml; then + return 1 + fi + + echo -e "${BLUE}🔍 Validating YAML schema...${NC}" >&2 + + # Check required top-level keys + local required_keys=("version" "project" "config" "phases" "todos") + for key in "${required_keys[@]}"; do + if ! yq eval "has(\"$key\")" "$TODOS_YAML_PATH" | grep -q "true"; then + echo -e "${RED}❌ Missing required key: $key${NC}" >&2 + return 1 + fi + done + + # Check config structure + local config_keys=("worktree_base_dir" "tmux_session_prefix" "default_branch_base") + for key in "${config_keys[@]}"; do + if ! yq eval ".config | has(\"$key\")" "$TODOS_YAML_PATH" | grep -q "true"; then + echo -e "${RED}❌ Missing required config key: $key${NC}" >&2 + return 1 + fi + done + + # Validate each TODO has required fields + local total_todos + total_todos=$(yq eval '.todos | length' "$TODOS_YAML_PATH") + + for (( i=0; i&2 + return 1 + fi + done + + # Check git configuration + local git_keys=("branch" "worktree_dir" "tmux_session") + for key in "${git_keys[@]}"; do + if ! yq eval ".todos[${i}].git | has(\"$key\")" "$TODOS_YAML_PATH" | grep -q "true"; then + echo -e "${RED}❌ TODO $todo_id missing required git key: $key${NC}" >&2 + return 1 + fi + done + done + + echo -e "${GREEN}✅ YAML schema validation passed${NC}" >&2 + return 0 +} + +# Function to show YAML status +# Usage: show_yaml_status +show_yaml_status() { + echo -e "${BLUE}📊 YAML Configuration Status${NC}" >&2 + echo "================================" >&2 + + if [ "$YAML_UTILS_INITIALIZED" != "true" ]; then + echo -e "${YELLOW}YAML utilities not initialized${NC}" >&2 + return 0 + fi + + echo "YAML File: $TODOS_YAML_PATH" >&2 + echo "YQ Available: $([ "$YAML_AVAILABLE" = "true" ] && echo -e "${GREEN}Yes${NC}" || echo -e "${RED}No${NC}")" >&2 + + if [ "$YAML_AVAILABLE" = "true" ]; then + local version project total_todos total_phases + version=$(get_config "version" 2>/dev/null || echo "unknown") + project=$(yaml_get_or_default ".project" "unknown") + total_todos=$(yq eval '.todos | length' "$TODOS_YAML_PATH") + total_phases=$(yq eval '.phases | length' "$TODOS_YAML_PATH") + + echo "Project: $project" >&2 + echo "Version: $version" >&2 + echo "Total TODOs: $total_todos" >&2 + echo "Total Phases: $total_phases" >&2 + echo "Active TODOs: $(get_total_active_todo_count)" >&2 + fi +} + +# Function to get fallback configuration values +# Usage: get_fallback_config +get_fallback_config() { + local config_type="$1" + + case "$config_type" in + "worktree_base_dir") + echo "../rules_antlr-worktrees" + ;; + "tmux_session_prefix") + echo "rules-antlr" + ;; + "default_branch_base") + echo "main" + ;; + *) + echo "" + ;; + esac +} + +# Function to print YAML utility usage +# Usage: yaml_utils_usage +yaml_utils_usage() { + echo -e "${BLUE}YAML Utilities Usage${NC}" + echo "====================" + echo + echo "Initialization:" + echo " init_yaml_utils [path_to_todos_yaml]" + echo + echo "Configuration:" + echo " get_config " + echo " get_fallback_config " + echo + echo "TODO queries:" + echo " get_all_todo_indices" + echo " get_phase_todo_indices " + echo " get_todo_field " + echo " is_todo_active " + echo " get_active_todo_count " + echo " get_total_active_todo_count" + echo + echo "Phase queries:" + echo " get_all_phases" + echo " get_phase_field " + echo " validate_phase " + echo + echo "Utilities:" + echo " yaml_get_or_default " + echo " validate_yaml_schema" + echo " show_yaml_status" + echo " require_yaml" +} + +# Export functions for use in other scripts +export -f init_yaml_utils require_yaml yaml_get_or_default +export -f get_all_todo_indices get_phase_todo_indices get_all_phases +export -f get_todo_field get_phase_field get_config +export -f validate_phase is_todo_active get_active_todo_count get_total_active_todo_count +export -f validate_yaml_schema show_yaml_status get_fallback_config yaml_utils_usage \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 6d582ec..4171c38 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,7 +13,7 @@ - Bzlmod support in active development (PR #35) ## Project Structure -``` +```text antlr/ # Core Bazel rules (.bzl files) ├── antlr2.bzl # ANTLR 2 rule definition ├── antlr3.bzl # ANTLR 3 rule definition @@ -120,3 +120,35 @@ rules_antlr_dependencies("4.8") # or 2, 3, specific version - WORKSPACE removal planned for Bazel 9 - This ruleset needs bzlmod migration for future compatibility - Most 2025 Bazel projects expect MODULE.bazel support + +## Multi-Agent Development System + +The `.agents/` directory contains a parallel development system that enables concurrent bug fixing by running multiple Claude Code sessions simultaneously using git worktrees. + +### Critical Bug Fixes in Progress +- **15 Critical NPE Vulnerabilities** - Could cause JVM crashes during build +- **3 High-Priority Bazel Logic Errors** - Break compatibility with newer Bazel versions +- **2 Medium-Priority Resource Leaks** - Gradual system degradation + +### Parallel Workflow Capabilities +- **Concurrent Execution** - Fix multiple bugs simultaneously instead of sequentially +- **Process Isolation** - Each Claude session works in independent git worktree +- **Specialized Context** - Each agent focuses on specific vulnerability types +- **Coordinated Integration** - Automated PR creation and merge workflow + +### Quick Start +```bash +cd .agents/ +./setup-worktrees.sh # Create parallel development environment +./run-parallel-claude.sh critical # Start 4 critical NPE fix sessions +``` + +### System Components +- [`.agents/README.md`](.agents/README.md) - Quick start guide and system overview +- [`.agents/TODO.md`](.agents/TODO.md) - Detailed specifications for all 20 critical bug fixes +- [`.agents/WORKFLOW.md`](.agents/WORKFLOW.md) - Comprehensive workflow documentation +- **Multiple scripts** - Automated worktree management, session control, PR coordination + +This system transforms traditional sequential bug fixing into a parallel, scalable development process using Claude Code's capabilities with git worktrees. + +**→ See [`.agents/README.md`](.agents/README.md) for complete usage instructions**