-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Part of: #648
Part of: #EPIC_TBD
[Conversation Reference: "Story 4: File Management Operations from CLI Remote Mode - User Story: As a developer using CLI with remote server, I want to create, edit, and delete files in remote repositories, so that I can manage codebase files without leaving the command line."]
Story Overview
Objective: Enable file CRUD operations from CLI when connected to a remote CIDX server, with optimistic locking to prevent concurrent edit conflicts.
User Value: Developers can create, modify, and delete files in remote repositories directly from the CLI, maintaining their workflow without switching to web interfaces or separate tools.
Acceptance Criteria Summary: File create/edit/delete operations work with optimistic locking (content hash), support --dry-run for safety, and provide clear conflict detection.
Acceptance Criteria
AC1: Create File Operation
Scenario: Create a new file in remote repository
Given the user is connected to a remote CIDX server
And has an activated repository
When the user runs "cidx files create src/new_module.py --repository my-repo --content 'def hello(): pass'"
Then the file is created in the repository
And the CLI displays the created file path and content hash
And supports reading content from stdin or --content-file flagTechnical Requirements:
- Create FileAPIClient.create_file() method
- Support --content flag for inline content
- Support --content-file flag to read from local file
- Support reading from stdin (piped input)
- Return content_hash for subsequent edits
- Validate file doesn't already exist
AC2: Edit File Operation with Optimistic Locking
Scenario: Edit an existing file with conflict detection
Given the user is connected to a remote CIDX server
And wants to edit a file in an activated repository
When the user runs "cidx files edit src/auth.py --repository my-repo --old-string 'old_func' --new-string 'new_func' --content-hash abc123"
Then the edit is applied if content_hash matches current file state
And the CLI displays the updated content_hash
And if hash mismatch, displays conflict error with current file stateTechnical Requirements:
- Create FileAPIClient.edit_file() method
- Require --content-hash for optimistic locking
- Support --old-string and --new-string for replacement
- Support --replace-all flag for multiple occurrences
- Return new content_hash after edit
- Clear conflict detection and reporting
AC3: Delete File Operation
Scenario: Delete a file from remote repository
Given the user is connected to a remote CIDX server
And has an activated repository
When the user runs "cidx files delete src/old_module.py --repository my-repo"
Then the file is deleted from the repository
And CLI displays confirmation message
And supports optional --content-hash for safety validationTechnical Requirements:
- Create FileAPIClient.delete_file() method
- Support optional --content-hash for safety
- Require confirmation (--yes flag to skip)
- Handle file not found gracefully
- Provide undo guidance in confirmation
AC4: Get File Content with Hash
Scenario: Read file content and get current hash
Given the user is connected to a remote CIDX server
When the user runs "cidx files get src/auth.py --repository my-repo"
Then the CLI displays file content
And shows current content_hash for use in edit operations
And supports --hash-only flag to just get hash
And supports pagination with --offset and --limit for large filesTechnical Requirements:
- Create FileAPIClient.get_file() method (may reuse existing)
- Display content_hash in output
- Support --hash-only flag
- Support --offset and --limit for pagination
- Handle binary files appropriately
AC5: Dry-Run Mode for Safety
Scenario: Preview operations before execution
Given the user wants to verify an operation before executing
When the user runs "cidx files edit ... --dry-run"
Then the CLI displays what would happen without making changes
And shows the diff that would result from the edit
And indicates "DRY RUN - no changes made"Technical Requirements:
- Implement --dry-run flag for all write operations
- Display preview of changes for edit operations
- Show confirmation prompt summary
- Exit with success status (0) for dry-run
AC6: Concurrent Edit Conflict Handling
Scenario: Detect and report concurrent edit conflicts
Given user A has read file with hash abc123
And user B has since edited the file (new hash def456)
When user A runs edit with --content-hash abc123
Then the CLI displays "Conflict: File has been modified"
And shows diff between expected and current content
And provides current hash for retry
And suggests workflow to resolveTechnical Requirements:
- Detect hash mismatch from API response
- Display informative conflict message
- Show current file content or diff
- Provide current hash for retry
- Suggest resolution workflow
Implementation Status
Progress Tracking:
- Core implementation complete
- Unit tests passing (X/Y tests)
- Integration tests passing (X/Y tests)
- E2E tests passing (X/Y tests)
- Code review approved
- Manual E2E testing completed by Claude Code
- Documentation updated
Completion: 0/7 tasks complete (0%)
Technical Implementation Details
Component Structure
src/code_indexer/client/
file_api_client.py # FileAPIClient class
- create_file()
- edit_file()
- delete_file()
- get_file() # May reuse existing
src/code_indexer/cli/commands/
files.py # New files command group
Command Group Structure
@cli.group()
def files():
"""File operations for remote repositories"""
pass
@files.command()
@requires_mode(remote=True)
@click.option('--repository', '-r', required=True)
@click.option('--content', help='Inline content')
@click.option('--content-file', type=click.Path(exists=True), help='Read content from file')
@click.option('--json', 'output_json', is_flag=True)
def create(file_path, repository, content, content_file, output_json):
"""Create a new file"""
if content_file:
content = Path(content_file).read_text()
elif not content:
content = sys.stdin.read()
client = get_file_api_client()
result = client.create_file(repository, file_path, content)
# Format and display
@files.command()
@requires_mode(remote=True)
@click.option('--repository', '-r', required=True)
@click.option('--old-string', required=True)
@click.option('--new-string', required=True)
@click.option('--content-hash', required=True)
@click.option('--replace-all', is_flag=True)
@click.option('--dry-run', is_flag=True)
def edit(file_path, repository, old_string, new_string, content_hash, replace_all, dry_run):
"""Edit an existing file using string replacement"""
passAPI Client Pattern
class FileAPIClient:
def __init__(self, remote_client: CIDXRemoteAPIClient):
self.client = remote_client
async def create_file(
self,
repository: str,
file_path: str,
content: str
) -> FileOperationResult:
response = await self.client.post(
f"/api/v1/files/{repository}/create",
json={"file_path": file_path, "content": content}
)
return FileOperationResult(**response)
async def edit_file(
self,
repository: str,
file_path: str,
old_string: str,
new_string: str,
content_hash: str,
replace_all: bool = False
) -> FileOperationResult:
response = await self.client.post(
f"/api/v1/files/{repository}/edit",
json={
"file_path": file_path,
"old_string": old_string,
"new_string": new_string,
"content_hash": content_hash,
"replace_all": replace_all
}
)
return FileOperationResult(**response)Content Hash Workflow
1. Read file: cidx files get src/auth.py --repository my-repo
-> Returns content + content_hash: "abc123def..."
2. Edit file: cidx files edit src/auth.py --old-string "old" --new-string "new" --content-hash "abc123def..." --repository my-repo
-> If hash matches: Edit succeeds, returns new hash
-> If hash mismatch: Conflict error with current hash
3. Continue with new hash for subsequent edits
Testing Requirements
Unit Test Coverage
- FileAPIClient.create_file() sends correct payload
- FileAPIClient.edit_file() includes content_hash
- FileAPIClient.delete_file() handles confirmation
- Content hash validation works correctly
- --dry-run prevents actual changes
Integration Test Coverage
- Create file appears in repository
- Edit file changes content correctly
- Delete file removes from repository
- Hash mismatch triggers conflict error
- Concurrent edit scenario detected
E2E Test Coverage
- Complete workflow: create -> edit -> delete
- Conflict detection with simulated concurrent edit
- Dry-run shows preview without changes
- Large file pagination works
Performance Requirements
Response Time Targets
- Create/edit small files (<1MB): <2 seconds
- Delete operations: <1 second
- Get file content: Proportional to size
- Hash calculation: Instant (done on server)
Resource Requirements
- Memory: Proportional to file size
- Network: File content transferred
- CPU: Minimal (hash calculation on server)
Error Handling Specifications
User-Friendly Error Messages
Error: File already exists at 'src/new_module.py'
Suggestion: Use 'cidx files edit' to modify existing file
Error: Conflict - File has been modified since your last read
Expected hash: abc123...
Current hash: def456...
Suggestion: Run 'cidx files get src/auth.py' to get current content and hash
Error: File not found: 'src/missing.py'
Repository: my-repo
Suggestion: Check file path or use 'cidx files create' for new files
Error: old_string not found in file
Search string: 'function_name'
Suggestion: Verify the exact string including whitespace
Recovery Guidance
- File exists: Suggest edit instead of create
- Hash mismatch: Provide current hash and suggest re-read
- File not found: Suggest checking path or creating
- String not found: Show file content for verification
Definition of Done
Functional Completion
- Create file operation works
- Edit file operation works with optimistic locking
- Delete file operation works with confirmation
- Get file operation provides content hash
- Dry-run mode works for all write operations
- Conflict detection and reporting works
Quality Validation
- >90% test coverage achieved
- All tests passing (unit, integration, E2E)
- Code review approved
- Manual testing validated with evidence
- Performance benchmarks met
Integration Readiness
- Story delivers working, deployable software
- Full vertical slice implemented
- No broken functionality
- Documentation complete
Story Points: Medium (4 main operations)
Priority: High (essential for remote development)
Dependencies: Story 1 (Mode Detection)
Success Metric: File CRUD operations work with proper conflict detection