mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-02-01 23:13:36 +00:00
feat: move autocoder runtime files into .autocoder/ subdirectory
Add centralized path resolution module (autocoder_paths.py) that consolidates all autocoder-generated file paths behind a dual-path strategy: check .autocoder/X first, fall back to root-level X for backward compatibility, default to .autocoder/X for new projects. Key changes: - New autocoder_paths.py with dual-path resolution for features.db, assistant.db, lock files, settings, prompts dir, and progress cache - migrate_project_layout() safely moves old-layout projects to new layout with SQLite WAL flush and integrity verification - Updated 22 files to delegate path construction to autocoder_paths - Reset/delete logic cleans both old and new file locations - Orphan lock cleanup checks both locations per project - Migration called automatically at agent start in autonomous_agent_demo.py - Updated markdown commands/skills to reference .autocoder/prompts/ - CLAUDE.md documentation updated with new project structure Files at project root that remain unchanged: - CLAUDE.md (Claude SDK reads from cwd via setting_sources=["project"]) - app_spec.txt root copy (agent templates reference it via cat) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,7 @@ from typing import Awaitable, Callable, Literal, Set
|
||||
import psutil
|
||||
|
||||
from registry import list_registered_projects
|
||||
from security import extract_commands, get_effective_commands, is_command_allowed
|
||||
from server.utils.process_utils import kill_process_tree
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -114,7 +115,8 @@ class DevServerProcessManager:
|
||||
self._callbacks_lock = threading.Lock()
|
||||
|
||||
# Lock file to prevent multiple instances (stored in project directory)
|
||||
self.lock_file = self.project_dir / ".devserver.lock"
|
||||
from autocoder_paths import get_devserver_lock_path
|
||||
self.lock_file = get_devserver_lock_path(self.project_dir)
|
||||
|
||||
@property
|
||||
def status(self) -> Literal["stopped", "running", "crashed"]:
|
||||
@@ -304,6 +306,20 @@ class DevServerProcessManager:
|
||||
if not self.project_dir.exists():
|
||||
return False, f"Project directory does not exist: {self.project_dir}"
|
||||
|
||||
# Defense-in-depth: validate command against security allowlist
|
||||
commands = extract_commands(command)
|
||||
if not commands:
|
||||
return False, "Could not parse command for security validation"
|
||||
|
||||
allowed_commands, blocked_commands = get_effective_commands(self.project_dir)
|
||||
for cmd in commands:
|
||||
if cmd in blocked_commands:
|
||||
logger.warning("Blocked dev server command '%s' (in blocklist) for %s", cmd, self.project_name)
|
||||
return False, f"Command '{cmd}' is blocked and cannot be used as a dev server command"
|
||||
if not is_command_allowed(cmd, allowed_commands):
|
||||
logger.warning("Rejected dev server command '%s' (not in allowlist) for %s", cmd, self.project_name)
|
||||
return False, f"Command '{cmd}' is not in the allowed commands list"
|
||||
|
||||
self._command = command
|
||||
self._detected_url = None # Reset URL detection
|
||||
|
||||
@@ -487,8 +503,18 @@ def cleanup_orphaned_devserver_locks() -> int:
|
||||
if not project_path.exists():
|
||||
continue
|
||||
|
||||
lock_file = project_path / ".devserver.lock"
|
||||
if not lock_file.exists():
|
||||
# Check both legacy and new locations for lock files
|
||||
from autocoder_paths import get_autocoder_dir
|
||||
lock_locations = [
|
||||
project_path / ".devserver.lock",
|
||||
get_autocoder_dir(project_path) / ".devserver.lock",
|
||||
]
|
||||
lock_file = None
|
||||
for candidate in lock_locations:
|
||||
if candidate.exists():
|
||||
lock_file = candidate
|
||||
break
|
||||
if lock_file is None:
|
||||
continue
|
||||
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user