refactor: remove deprecated code across backend and frontend (#348)
## Backend - Delete `agents/auto_claude_tools.py` (compatibility shim) - Delete `implementation_plan/main.py` (compatibility shim) - Remove `--dev` flag and `dev_mode` parameter from: - cli/main.py, cli/utils.py, cli/spec_commands.py - runners/spec_runner.py - spec/pipeline/models.py, orchestrator.py - spec/complexity.py - Remove `ClaudeSimilarityDetector` class from batch_issues.py - Remove unused `self.detector` alias ## Frontend - Remove `PROJECT_UPDATE_AUTOBUILD` IPC channel - Remove `updateProjectAutoBuild` from: - project-handlers.ts (IPC handler) - project-api.ts (preload API) - project-store.ts (store function) - project-mock.ts (mock) - Remove deprecated `appendOutput`/`clearOutputBuffer` from terminal-store - Update useTerminalEvents to use terminalBufferManager directly - Remove deprecated "Update Auto Claude" dialog from Sidebar - Remove `handleUpdate` from useProjectSettings hook ## Tests - Remove `test_dev_mode_param_ignored` test
This commit is contained in:
@@ -1,62 +0,0 @@
|
||||
"""
|
||||
Custom MCP Tools for Auto-Claude Agents
|
||||
========================================
|
||||
|
||||
DEPRECATED: This module is now a compatibility shim.
|
||||
Please import from the tools_pkg package instead:
|
||||
|
||||
from agents.tools_pkg import create_auto_claude_mcp_server, get_allowed_tools
|
||||
|
||||
This file remains for backward compatibility with existing imports.
|
||||
All functionality has been moved to the tools_pkg package for better
|
||||
organization and maintainability.
|
||||
"""
|
||||
|
||||
# Import everything from the package to maintain backward compatibility
|
||||
# Use try/except to handle both relative and absolute imports
|
||||
try:
|
||||
from .tools_pkg import (
|
||||
ELECTRON_TOOLS,
|
||||
TOOL_GET_BUILD_PROGRESS,
|
||||
TOOL_GET_SESSION_CONTEXT,
|
||||
TOOL_RECORD_DISCOVERY,
|
||||
TOOL_RECORD_GOTCHA,
|
||||
TOOL_UPDATE_QA_STATUS,
|
||||
TOOL_UPDATE_SUBTASK_STATUS,
|
||||
create_auto_claude_mcp_server,
|
||||
get_allowed_tools,
|
||||
is_electron_mcp_enabled,
|
||||
is_tools_available,
|
||||
)
|
||||
except ImportError:
|
||||
# Fallback for direct execution - import from tools_pkg directly
|
||||
from tools_pkg import (
|
||||
ELECTRON_TOOLS,
|
||||
TOOL_GET_BUILD_PROGRESS,
|
||||
TOOL_GET_SESSION_CONTEXT,
|
||||
TOOL_RECORD_DISCOVERY,
|
||||
TOOL_RECORD_GOTCHA,
|
||||
TOOL_UPDATE_QA_STATUS,
|
||||
TOOL_UPDATE_SUBTASK_STATUS,
|
||||
create_auto_claude_mcp_server,
|
||||
get_allowed_tools,
|
||||
is_electron_mcp_enabled,
|
||||
is_tools_available,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
# Main API
|
||||
"create_auto_claude_mcp_server",
|
||||
"get_allowed_tools",
|
||||
"is_tools_available",
|
||||
# Tool name constants
|
||||
"TOOL_UPDATE_SUBTASK_STATUS",
|
||||
"TOOL_GET_BUILD_PROGRESS",
|
||||
"TOOL_RECORD_DISCOVERY",
|
||||
"TOOL_RECORD_GOTCHA",
|
||||
"TOOL_GET_SESSION_CONTEXT",
|
||||
"TOOL_UPDATE_QA_STATUS",
|
||||
# Electron MCP
|
||||
"ELECTRON_TOOLS",
|
||||
"is_electron_mcp_enabled",
|
||||
]
|
||||
@@ -15,10 +15,6 @@ _PARENT_DIR = Path(__file__).parent.parent
|
||||
if str(_PARENT_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(_PARENT_DIR))
|
||||
|
||||
from ui import (
|
||||
Icons,
|
||||
icon,
|
||||
)
|
||||
|
||||
from .batch_commands import (
|
||||
handle_batch_cleanup_command,
|
||||
@@ -201,13 +197,6 @@ Environment Variables:
|
||||
help="Show human review/approval status for a spec",
|
||||
)
|
||||
|
||||
# Dev mode (deprecated)
|
||||
parser.add_argument(
|
||||
"--dev",
|
||||
action="store_true",
|
||||
help="[Deprecated] No longer has any effect - kept for compatibility",
|
||||
)
|
||||
|
||||
# Non-interactive mode (for UI/automation)
|
||||
parser.add_argument(
|
||||
"--auto-continue",
|
||||
@@ -290,16 +279,10 @@ def main() -> None:
|
||||
# Get model (with env var fallback)
|
||||
model = args.model or os.environ.get("AUTO_BUILD_MODEL", DEFAULT_MODEL)
|
||||
|
||||
# Note: --dev flag is deprecated but kept for API compatibility
|
||||
if args.dev:
|
||||
print(
|
||||
f"\n{icon(Icons.GEAR)} Note: --dev flag is deprecated. All specs now use .auto-claude/specs/\n"
|
||||
)
|
||||
|
||||
# Handle --list command
|
||||
if args.list:
|
||||
print_banner()
|
||||
print_specs_list(project_dir, args.dev)
|
||||
print_specs_list(project_dir)
|
||||
return
|
||||
|
||||
# Handle --list-worktrees command
|
||||
@@ -337,14 +320,14 @@ def main() -> None:
|
||||
sys.exit(1)
|
||||
|
||||
# Find the spec
|
||||
debug("run.py", "Finding spec", spec_identifier=args.spec, dev_mode=args.dev)
|
||||
spec_dir = find_spec(project_dir, args.spec, args.dev)
|
||||
debug("run.py", "Finding spec", spec_identifier=args.spec)
|
||||
spec_dir = find_spec(project_dir, args.spec)
|
||||
if not spec_dir:
|
||||
debug_error("run.py", "Spec not found", spec=args.spec)
|
||||
print_banner()
|
||||
print(f"\nError: Spec '{args.spec}' not found")
|
||||
print("\nAvailable specs:")
|
||||
print_specs_list(project_dir, args.dev)
|
||||
print_specs_list(project_dir)
|
||||
sys.exit(1)
|
||||
|
||||
debug_success("run.py", "Spec found", spec_dir=str(spec_dir))
|
||||
|
||||
@@ -19,18 +19,17 @@ from workspace import get_existing_build_worktree
|
||||
from .utils import get_specs_dir
|
||||
|
||||
|
||||
def list_specs(project_dir: Path, dev_mode: bool = False) -> list[dict]:
|
||||
def list_specs(project_dir: Path) -> list[dict]:
|
||||
"""
|
||||
List all specs in the project.
|
||||
|
||||
Args:
|
||||
project_dir: Project root directory
|
||||
dev_mode: If True, use dev/auto-claude/specs/
|
||||
|
||||
Returns:
|
||||
List of spec info dicts with keys: number, name, path, status, progress
|
||||
"""
|
||||
specs_dir = get_specs_dir(project_dir, dev_mode)
|
||||
specs_dir = get_specs_dir(project_dir)
|
||||
specs = []
|
||||
|
||||
if not specs_dir.exists():
|
||||
@@ -93,19 +92,16 @@ def list_specs(project_dir: Path, dev_mode: bool = False) -> list[dict]:
|
||||
return specs
|
||||
|
||||
|
||||
def print_specs_list(
|
||||
project_dir: Path, dev_mode: bool = False, auto_create: bool = True
|
||||
) -> None:
|
||||
def print_specs_list(project_dir: Path, auto_create: bool = True) -> None:
|
||||
"""Print a formatted list of all specs.
|
||||
|
||||
Args:
|
||||
project_dir: Project root directory
|
||||
dev_mode: If True, use dev/auto-claude/specs/
|
||||
auto_create: If True and no specs exist, automatically launch spec creation
|
||||
"""
|
||||
import subprocess
|
||||
|
||||
specs = list_specs(project_dir, dev_mode)
|
||||
specs = list_specs(project_dir)
|
||||
|
||||
if not specs:
|
||||
print("\nNo specs found.")
|
||||
|
||||
@@ -54,21 +54,18 @@ def setup_environment() -> Path:
|
||||
return script_dir
|
||||
|
||||
|
||||
def find_spec(
|
||||
project_dir: Path, spec_identifier: str, dev_mode: bool = False
|
||||
) -> Path | None:
|
||||
def find_spec(project_dir: Path, spec_identifier: str) -> Path | None:
|
||||
"""
|
||||
Find a spec by number or full name.
|
||||
|
||||
Args:
|
||||
project_dir: Project root directory
|
||||
spec_identifier: Either "001" or "001-feature-name"
|
||||
dev_mode: If True, use dev/auto-claude/specs/
|
||||
|
||||
Returns:
|
||||
Path to spec folder, or None if not found
|
||||
"""
|
||||
specs_dir = get_specs_dir(project_dir, dev_mode)
|
||||
specs_dir = get_specs_dir(project_dir)
|
||||
|
||||
if specs_dir.exists():
|
||||
# Try exact match first
|
||||
|
||||
@@ -1,168 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Implementation Plan Manager
|
||||
============================
|
||||
|
||||
DEPRECATED: This module is now a compatibility shim. The implementation has been
|
||||
refactored into the implementation_plan/ package for better modularity.
|
||||
|
||||
Please import from the package directly:
|
||||
from implementation_plan import ImplementationPlan, Subtask, Phase, etc.
|
||||
|
||||
This file re-exports all public APIs for backwards compatibility.
|
||||
|
||||
Core data structures and utilities for subtask-based implementation plans.
|
||||
Replaces the test-centric feature_list.json with implementation_plan.json.
|
||||
|
||||
The key insight: Tests verify outcomes, but SUBTASKS define implementation steps.
|
||||
For complex multi-service features, implementation order matters.
|
||||
|
||||
Workflow Types:
|
||||
- feature: Standard multi-service feature (phases = services)
|
||||
- refactor: Migration/refactor work (phases = stages: add, migrate, remove)
|
||||
- investigation: Bug hunting (phases = investigate, hypothesize, fix)
|
||||
- migration: Data migration (phases = prepare, test, execute, cleanup)
|
||||
- simple: Single-service enhancement (minimal overhead)
|
||||
"""
|
||||
|
||||
# Re-export everything from the implementation_plan package
|
||||
from implementation_plan import (
|
||||
Chunk,
|
||||
ChunkStatus,
|
||||
ImplementationPlan,
|
||||
Phase,
|
||||
PhaseType,
|
||||
Subtask,
|
||||
SubtaskStatus,
|
||||
Verification,
|
||||
VerificationType,
|
||||
WorkflowType,
|
||||
create_feature_plan,
|
||||
create_investigation_plan,
|
||||
create_refactor_plan,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
# Enums
|
||||
"WorkflowType",
|
||||
"PhaseType",
|
||||
"SubtaskStatus",
|
||||
"VerificationType",
|
||||
# Models
|
||||
"Verification",
|
||||
"Subtask",
|
||||
"Phase",
|
||||
"ImplementationPlan",
|
||||
# Factories
|
||||
"create_feature_plan",
|
||||
"create_investigation_plan",
|
||||
"create_refactor_plan",
|
||||
# Backwards compatibility
|
||||
"Chunk",
|
||||
"ChunkStatus",
|
||||
]
|
||||
|
||||
|
||||
# CLI for testing
|
||||
if __name__ == "__main__":
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python implementation_plan.py <plan.json>")
|
||||
print(" python implementation_plan.py --demo")
|
||||
sys.exit(1)
|
||||
|
||||
if sys.argv[1] == "--demo":
|
||||
# Create a demo plan
|
||||
plan = create_feature_plan(
|
||||
feature="Avatar Upload with Processing",
|
||||
services=["backend", "worker", "frontend"],
|
||||
phases_config=[
|
||||
{
|
||||
"name": "Backend Foundation",
|
||||
"parallel_safe": True,
|
||||
"subtasks": [
|
||||
{
|
||||
"id": "avatar-model",
|
||||
"service": "backend",
|
||||
"description": "Add avatar fields to User model",
|
||||
"files_to_modify": ["app/models/user.py"],
|
||||
"files_to_create": ["migrations/add_avatar.py"],
|
||||
"verification": {
|
||||
"type": "command",
|
||||
"run": "flask db upgrade",
|
||||
},
|
||||
},
|
||||
{
|
||||
"id": "avatar-endpoint",
|
||||
"service": "backend",
|
||||
"description": "POST /api/users/avatar endpoint",
|
||||
"files_to_modify": ["app/routes/users.py"],
|
||||
"patterns_from": ["app/routes/profile.py"],
|
||||
"verification": {
|
||||
"type": "api",
|
||||
"method": "POST",
|
||||
"url": "/api/users/avatar",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Worker Pipeline",
|
||||
"depends_on": [1],
|
||||
"subtasks": [
|
||||
{
|
||||
"id": "image-task",
|
||||
"service": "worker",
|
||||
"description": "Celery task for image processing",
|
||||
"files_to_create": ["app/tasks/images.py"],
|
||||
"patterns_from": ["app/tasks/reports.py"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Frontend",
|
||||
"depends_on": [1],
|
||||
"subtasks": [
|
||||
{
|
||||
"id": "avatar-component",
|
||||
"service": "frontend",
|
||||
"description": "AvatarUpload React component",
|
||||
"files_to_create": ["src/components/AvatarUpload.tsx"],
|
||||
"patterns_from": ["src/components/FileUpload.tsx"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "Integration",
|
||||
"depends_on": [2, 3],
|
||||
"type": "integration",
|
||||
"subtasks": [
|
||||
{
|
||||
"id": "e2e-wiring",
|
||||
"all_services": True,
|
||||
"description": "Connect frontend → backend → worker",
|
||||
"verification": {
|
||||
"type": "browser",
|
||||
"scenario": "Upload → Process → Display",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
)
|
||||
plan.final_acceptance = [
|
||||
"User can upload avatar from profile page",
|
||||
"Avatar is automatically resized",
|
||||
"Large/invalid files show error",
|
||||
]
|
||||
|
||||
print(json.dumps(plan.to_dict(), indent=2))
|
||||
print("\n---\n")
|
||||
print(plan.get_status_summary())
|
||||
else:
|
||||
# Load and display existing plan
|
||||
plan = ImplementationPlan.load(Path(sys.argv[1]))
|
||||
print(plan.get_status_summary())
|
||||
@@ -240,30 +240,6 @@ Respond with JSON only:
|
||||
return response_text
|
||||
|
||||
|
||||
# Keep old class for backwards compatibility but mark as deprecated
|
||||
class ClaudeSimilarityDetector(ClaudeBatchAnalyzer):
|
||||
"""DEPRECATED: Use ClaudeBatchAnalyzer instead."""
|
||||
|
||||
async def compare_issues(
|
||||
self,
|
||||
repo: str,
|
||||
issue_a: dict[str, Any],
|
||||
issue_b: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
"""DEPRECATED: Pairwise comparison. Use analyze_and_batch_issues instead."""
|
||||
logger.warning("ClaudeSimilarityDetector.compare_issues is deprecated")
|
||||
# Simple fallback for any code still using this
|
||||
return {
|
||||
"is_similar": False,
|
||||
"overall_score": 0.0,
|
||||
"reasoning": "DEPRECATED: Use ClaudeBatchAnalyzer.analyze_and_batch_issues",
|
||||
}
|
||||
|
||||
async def precompute_embeddings(self, repo: str, issues: list[dict]) -> int:
|
||||
"""No-op for compatibility."""
|
||||
return 0
|
||||
|
||||
|
||||
class BatchStatus(str, Enum):
|
||||
"""Status of an issue batch."""
|
||||
|
||||
@@ -446,12 +422,9 @@ class IssueBatcher:
|
||||
self.max_batch_size = max_batch_size
|
||||
self.validate_batches_enabled = validate_batches
|
||||
|
||||
# Initialize Claude batch analyzer (replaces pairwise similarity detector)
|
||||
# Initialize Claude batch analyzer
|
||||
self.analyzer = ClaudeBatchAnalyzer(project_dir=self.project_dir)
|
||||
|
||||
# Keep detector for backwards compatibility (deprecated)
|
||||
self.detector = self.analyzer
|
||||
|
||||
# Initialize batch validator (uses Claude SDK with OAuth token)
|
||||
self.validator = (
|
||||
BatchValidator(
|
||||
|
||||
@@ -95,7 +95,7 @@ from debug import debug, debug_error, debug_section, debug_success
|
||||
from phase_config import resolve_model_id
|
||||
from review import ReviewState
|
||||
from spec import SpecOrchestrator
|
||||
from ui import Icons, highlight, icon, muted, print_section, print_status
|
||||
from ui import Icons, highlight, muted, print_section, print_status
|
||||
|
||||
|
||||
def main():
|
||||
@@ -177,11 +177,6 @@ Examples:
|
||||
action="store_true",
|
||||
help="Use heuristic complexity assessment instead of AI (faster but less accurate)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dev",
|
||||
action="store_true",
|
||||
help="[Deprecated] No longer has any effect - kept for compatibility",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-build",
|
||||
action="store_true",
|
||||
@@ -236,12 +231,6 @@ Examples:
|
||||
project_dir = parent
|
||||
break
|
||||
|
||||
# Note: --dev flag is deprecated but kept for API compatibility
|
||||
if args.dev:
|
||||
print(
|
||||
f"\n{icon(Icons.GEAR)} Note: --dev flag is deprecated. All specs now go to .auto-claude/specs/\n"
|
||||
)
|
||||
|
||||
# Resolve model shorthand to full model ID
|
||||
resolved_model = resolve_model_id(args.model)
|
||||
|
||||
@@ -267,7 +256,6 @@ Examples:
|
||||
thinking_level=args.thinking_level,
|
||||
complexity_override=args.complexity,
|
||||
use_ai_assessment=not args.no_ai_assessment,
|
||||
dev_mode=args.dev,
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -330,10 +318,6 @@ Examples:
|
||||
"--auto-continue", # Non-interactive mode for chained execution
|
||||
]
|
||||
|
||||
# Pass through dev mode
|
||||
if args.dev:
|
||||
run_cmd.append("--dev")
|
||||
|
||||
# Note: Model configuration for subsequent phases (planning, coding, qa)
|
||||
# is read from task_metadata.json by run.py, so we don't pass it here.
|
||||
# This allows per-phase configuration when using Auto profile.
|
||||
|
||||
@@ -435,9 +435,7 @@ async def run_ai_complexity_assessment(
|
||||
return None
|
||||
|
||||
|
||||
def save_assessment(
|
||||
spec_dir: Path, assessment: ComplexityAssessment, dev_mode: bool = False
|
||||
) -> Path:
|
||||
def save_assessment(spec_dir: Path, assessment: ComplexityAssessment) -> Path:
|
||||
"""Save complexity assessment to file."""
|
||||
assessment_file = spec_dir / "complexity_assessment.json"
|
||||
phases = assessment.phases_to_run()
|
||||
@@ -456,7 +454,6 @@ def save_assessment(
|
||||
"phases_to_run": phases,
|
||||
"needs_research": assessment.needs_research,
|
||||
"needs_self_critique": assessment.needs_self_critique,
|
||||
"dev_mode": dev_mode,
|
||||
"created_at": datetime.now().isoformat(),
|
||||
},
|
||||
f,
|
||||
|
||||
@@ -21,7 +21,7 @@ if TYPE_CHECKING:
|
||||
from core.workspace.models import SpecNumberLock
|
||||
|
||||
|
||||
def get_specs_dir(project_dir: Path, dev_mode: bool = False) -> Path:
|
||||
def get_specs_dir(project_dir: Path) -> Path:
|
||||
"""Get the specs directory path.
|
||||
|
||||
IMPORTANT: Only .auto-claude/ is considered an "installed" auto-claude.
|
||||
@@ -32,7 +32,6 @@ def get_specs_dir(project_dir: Path, dev_mode: bool = False) -> Path:
|
||||
|
||||
Args:
|
||||
project_dir: The project root directory
|
||||
dev_mode: Deprecated, kept for API compatibility. Has no effect.
|
||||
|
||||
Returns:
|
||||
Path to the specs directory within .auto-claude/
|
||||
|
||||
@@ -61,7 +61,6 @@ class SpecOrchestrator:
|
||||
thinking_level: str = "medium", # Thinking level for extended thinking
|
||||
complexity_override: str | None = None, # Force a specific complexity
|
||||
use_ai_assessment: bool = True, # Use AI for complexity assessment (vs heuristics)
|
||||
dev_mode: bool = False, # Dev mode: specs in gitignored folder, code changes to auto-claude/
|
||||
):
|
||||
"""Initialize the spec orchestrator.
|
||||
|
||||
@@ -74,7 +73,6 @@ class SpecOrchestrator:
|
||||
thinking_level: Thinking level (none, low, medium, high, ultrathink)
|
||||
complexity_override: Force a specific complexity level
|
||||
use_ai_assessment: Whether to use AI for complexity assessment
|
||||
dev_mode: Deprecated, kept for API compatibility
|
||||
"""
|
||||
self.project_dir = Path(project_dir)
|
||||
self.task_description = task_description
|
||||
@@ -82,10 +80,9 @@ class SpecOrchestrator:
|
||||
self.thinking_level = thinking_level
|
||||
self.complexity_override = complexity_override
|
||||
self.use_ai_assessment = use_ai_assessment
|
||||
self.dev_mode = dev_mode
|
||||
|
||||
# Get the appropriate specs directory (within the project)
|
||||
self.specs_dir = get_specs_dir(self.project_dir, dev_mode)
|
||||
self.specs_dir = get_specs_dir(self.project_dir)
|
||||
|
||||
# Clean up orphaned pending folders before creating new spec
|
||||
cleanup_orphaned_pending_folders(self.specs_dir)
|
||||
@@ -462,7 +459,7 @@ class SpecOrchestrator:
|
||||
|
||||
# Save assessment
|
||||
if not assessment_file.exists():
|
||||
complexity.save_assessment(self.spec_dir, self.assessment, self.dev_mode)
|
||||
complexity.save_assessment(self.spec_dir, self.assessment)
|
||||
|
||||
return phases.PhaseResult(
|
||||
"complexity_assessment", True, [str(assessment_file)], [], 0
|
||||
|
||||
@@ -319,29 +319,6 @@ export function registerProjectHandlers(
|
||||
}
|
||||
);
|
||||
|
||||
// PROJECT_UPDATE_AUTOBUILD is deprecated - .auto-claude only contains data, no code to update
|
||||
// Kept for API compatibility, returns success immediately
|
||||
ipcMain.handle(
|
||||
IPC_CHANNELS.PROJECT_UPDATE_AUTOBUILD,
|
||||
async (_, projectId: string): Promise<IPCResult<InitializationResult>> => {
|
||||
try {
|
||||
const project = projectStore.getProject(projectId);
|
||||
if (!project) {
|
||||
return { success: false, error: 'Project not found' };
|
||||
}
|
||||
|
||||
// Nothing to update - .auto-claude only contains data directories
|
||||
// The framework runs from the source repo
|
||||
return { success: true, data: { success: true } };
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// PROJECT_CHECK_VERSION now just checks if project is initialized
|
||||
// Version tracking for .auto-claude is removed since it only contains data
|
||||
ipcMain.handle(
|
||||
|
||||
@@ -31,7 +31,6 @@ export interface ProjectAPI {
|
||||
settings: Partial<ProjectSettings>
|
||||
) => Promise<IPCResult>;
|
||||
initializeProject: (projectId: string) => Promise<IPCResult<InitializationResult>>;
|
||||
updateProjectAutoBuild: (projectId: string) => Promise<IPCResult<InitializationResult>>;
|
||||
checkProjectVersion: (projectId: string) => Promise<IPCResult<AutoBuildVersionInfo>>;
|
||||
|
||||
// Tab State (persisted in main process for reliability)
|
||||
@@ -155,9 +154,6 @@ export const createProjectAPI = (): ProjectAPI => ({
|
||||
initializeProject: (projectId: string): Promise<IPCResult<InitializationResult>> =>
|
||||
ipcRenderer.invoke(IPC_CHANNELS.PROJECT_INITIALIZE, projectId),
|
||||
|
||||
updateProjectAutoBuild: (projectId: string): Promise<IPCResult<InitializationResult>> =>
|
||||
ipcRenderer.invoke(IPC_CHANNELS.PROJECT_UPDATE_AUTOBUILD, projectId),
|
||||
|
||||
checkProjectVersion: (projectId: string): Promise<IPCResult<AutoBuildVersionInfo>> =>
|
||||
ipcRenderer.invoke(IPC_CHANNELS.PROJECT_CHECK_VERSION, projectId),
|
||||
|
||||
|
||||
@@ -40,9 +40,7 @@ import { cn } from '../lib/utils';
|
||||
import {
|
||||
useProjectStore,
|
||||
removeProject,
|
||||
initializeProject,
|
||||
checkProjectVersion,
|
||||
updateProjectAutoBuild
|
||||
initializeProject
|
||||
} from '../stores/project-store';
|
||||
import { useSettingsStore } from '../stores/settings-store';
|
||||
import { AddProjectModal } from './AddProjectModal';
|
||||
@@ -96,11 +94,9 @@ export function Sidebar({
|
||||
|
||||
const [showAddProjectModal, setShowAddProjectModal] = useState(false);
|
||||
const [showInitDialog, setShowInitDialog] = useState(false);
|
||||
const [showUpdateDialog, setShowUpdateDialog] = useState(false);
|
||||
const [showGitSetupModal, setShowGitSetupModal] = useState(false);
|
||||
const [gitStatus, setGitStatus] = useState<GitStatus | null>(null);
|
||||
const [pendingProject, setPendingProject] = useState<Project | null>(null);
|
||||
const [_versionInfo, setVersionInfo] = useState<AutoBuildVersionInfo | null>(null);
|
||||
const [isInitializing, setIsInitializing] = useState(false);
|
||||
|
||||
const selectedProject = projects.find((p) => p.id === selectedProjectId);
|
||||
@@ -140,20 +136,6 @@ export function Sidebar({
|
||||
return () => window.removeEventListener('keydown', handleKeyDown);
|
||||
}, [selectedProjectId, onViewChange]);
|
||||
|
||||
// Check for updates when project changes
|
||||
useEffect(() => {
|
||||
const checkUpdates = async () => {
|
||||
if (selectedProjectId && settings.autoUpdateAutoBuild) {
|
||||
const info = await checkProjectVersion(selectedProjectId);
|
||||
if (info?.updateAvailable) {
|
||||
setVersionInfo(info);
|
||||
setShowUpdateDialog(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
checkUpdates();
|
||||
}, [selectedProjectId, settings.autoUpdateAutoBuild]);
|
||||
|
||||
// Check git status when project changes
|
||||
useEffect(() => {
|
||||
const checkGit = async () => {
|
||||
@@ -211,26 +193,6 @@ export function Sidebar({
|
||||
setPendingProject(null);
|
||||
};
|
||||
|
||||
const _handleUpdate = async () => {
|
||||
if (!selectedProjectId) return;
|
||||
|
||||
setIsInitializing(true);
|
||||
try {
|
||||
const result = await updateProjectAutoBuild(selectedProjectId);
|
||||
if (result?.success) {
|
||||
setShowUpdateDialog(false);
|
||||
setVersionInfo(null);
|
||||
}
|
||||
} finally {
|
||||
setIsInitializing(false);
|
||||
}
|
||||
};
|
||||
|
||||
const _handleSkipUpdate = () => {
|
||||
setShowUpdateDialog(false);
|
||||
setVersionInfo(null);
|
||||
};
|
||||
|
||||
const handleGitInitialized = async () => {
|
||||
// Refresh git status after initialization
|
||||
if (selectedProject) {
|
||||
@@ -439,26 +401,6 @@ export function Sidebar({
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Update Auto Claude Dialog - Deprecated, updateAvailable is always false now */}
|
||||
<Dialog open={showUpdateDialog} onOpenChange={setShowUpdateDialog}>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center gap-2">
|
||||
<RefreshCw className="h-5 w-5" />
|
||||
{t('dialogs:update.title')}
|
||||
</DialogTitle>
|
||||
<DialogDescription>
|
||||
{t('dialogs:update.projectInitialized')}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => setShowUpdateDialog(false)}>
|
||||
{t('common:buttons.close')}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
{/* Add Project Modal */}
|
||||
<AddProjectModal
|
||||
open={showAddProjectModal}
|
||||
|
||||
@@ -31,7 +31,6 @@ interface GeneralSettingsProps {
|
||||
isCheckingVersion: boolean;
|
||||
isUpdating: boolean;
|
||||
handleInitialize: () => Promise<void>;
|
||||
handleUpdate: () => Promise<void>;
|
||||
}
|
||||
|
||||
export function GeneralSettings({
|
||||
@@ -41,8 +40,7 @@ export function GeneralSettings({
|
||||
versionInfo,
|
||||
isCheckingVersion,
|
||||
isUpdating,
|
||||
handleInitialize,
|
||||
handleUpdate: _handleUpdate
|
||||
handleInitialize
|
||||
}: GeneralSettingsProps) {
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -2,8 +2,7 @@ import { useState, useEffect } from 'react';
|
||||
import {
|
||||
updateProjectSettings,
|
||||
checkProjectVersion,
|
||||
initializeProject,
|
||||
updateProjectAutoBuild
|
||||
initializeProject
|
||||
} from '../../../stores/project-store';
|
||||
import { checkGitHubConnection as checkGitHubConnectionGlobal } from '../../../stores/github';
|
||||
import type {
|
||||
@@ -68,7 +67,6 @@ export interface UseProjectSettingsReturn {
|
||||
|
||||
// Actions
|
||||
handleInitialize: () => Promise<void>;
|
||||
handleUpdate: () => Promise<void>;
|
||||
handleSaveEnv: () => Promise<void>;
|
||||
handleClaudeSetup: () => Promise<void>;
|
||||
handleSave: (onClose: () => void) => Promise<void>;
|
||||
@@ -262,24 +260,6 @@ export function useProjectSettings(
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdate = async () => {
|
||||
setIsUpdating(true);
|
||||
setError(null);
|
||||
try {
|
||||
const result = await updateProjectAutoBuild(project.id);
|
||||
if (result?.success) {
|
||||
const info = await checkProjectVersion(project.id);
|
||||
setVersionInfo(info);
|
||||
} else {
|
||||
setError(result?.error || 'Failed to update');
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Unknown error');
|
||||
} finally {
|
||||
setIsUpdating(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSaveEnv = async () => {
|
||||
if (!envConfig) return;
|
||||
|
||||
@@ -397,7 +377,6 @@ export function useProjectSettings(
|
||||
linearConnectionStatus,
|
||||
isCheckingLinear,
|
||||
handleInitialize,
|
||||
handleUpdate,
|
||||
handleSaveEnv,
|
||||
handleClaudeSetup,
|
||||
handleSave
|
||||
|
||||
@@ -100,7 +100,6 @@ function ProjectSettingsContentInner({
|
||||
linearConnectionStatus,
|
||||
isCheckingLinear,
|
||||
handleInitialize,
|
||||
handleUpdate,
|
||||
handleClaudeSetup,
|
||||
error
|
||||
} = hook;
|
||||
@@ -146,7 +145,6 @@ function ProjectSettingsContentInner({
|
||||
linearConnectionStatus={linearConnectionStatus}
|
||||
isCheckingLinear={isCheckingLinear}
|
||||
handleInitialize={handleInitialize}
|
||||
handleUpdate={handleUpdate}
|
||||
handleClaudeSetup={handleClaudeSetup}
|
||||
onOpenLinearImport={() => setShowLinearImportModal(true)}
|
||||
/>
|
||||
|
||||
@@ -35,7 +35,6 @@ interface SectionRouterProps {
|
||||
linearConnectionStatus: LinearSyncStatus | null;
|
||||
isCheckingLinear: boolean;
|
||||
handleInitialize: () => Promise<void>;
|
||||
handleUpdate: () => Promise<void>;
|
||||
handleClaudeSetup: () => Promise<void>;
|
||||
onOpenLinearImport: () => void;
|
||||
}
|
||||
@@ -71,7 +70,6 @@ export function SectionRouter({
|
||||
linearConnectionStatus,
|
||||
isCheckingLinear,
|
||||
handleInitialize,
|
||||
handleUpdate,
|
||||
handleClaudeSetup,
|
||||
onOpenLinearImport
|
||||
}: SectionRouterProps) {
|
||||
@@ -90,7 +88,6 @@ export function SectionRouter({
|
||||
isCheckingVersion={isCheckingVersion}
|
||||
isUpdating={isUpdating}
|
||||
handleInitialize={handleInitialize}
|
||||
handleUpdate={handleUpdate}
|
||||
/>
|
||||
</SettingsSection>
|
||||
);
|
||||
|
||||
@@ -47,7 +47,6 @@ export function createHookProxy(
|
||||
get linearConnectionStatus() { return hookRef.current.linearConnectionStatus; },
|
||||
get isCheckingLinear() { return hookRef.current.isCheckingLinear; },
|
||||
get handleInitialize() { return hookRef.current.handleInitialize; },
|
||||
get handleUpdate() { return hookRef.current.handleUpdate; },
|
||||
get handleSaveEnv() { return hookRef.current.handleSaveEnv; },
|
||||
get handleClaudeSetup() { return hookRef.current.handleClaudeSetup; },
|
||||
get handleSave() { return hookRef.current.handleSave; },
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useTerminalStore } from '../../stores/terminal-store';
|
||||
import { terminalBufferManager } from '../../lib/terminal-buffer-manager';
|
||||
|
||||
interface UseTerminalEventsOptions {
|
||||
terminalId: string;
|
||||
@@ -20,7 +21,7 @@ export function useTerminalEvents({
|
||||
useEffect(() => {
|
||||
const cleanup = window.electronAPI.onTerminalOutput((id, data) => {
|
||||
if (id === terminalId) {
|
||||
useTerminalStore.getState().appendOutput(terminalId, data);
|
||||
terminalBufferManager.append(terminalId, data);
|
||||
onOutput?.(data);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -33,11 +33,6 @@ export const projectMock = {
|
||||
data: { success: true, version: '1.0.0', wasUpdate: false }
|
||||
}),
|
||||
|
||||
updateProjectAutoBuild: async () => ({
|
||||
success: true,
|
||||
data: { success: true, version: '1.0.0', wasUpdate: true }
|
||||
}),
|
||||
|
||||
checkProjectVersion: async () => ({
|
||||
success: true,
|
||||
data: {
|
||||
|
||||
@@ -453,24 +453,3 @@ export async function initializeProject(
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update auto-claude in a project
|
||||
*/
|
||||
export async function updateProjectAutoBuild(
|
||||
projectId: string
|
||||
): Promise<InitializationResult | null> {
|
||||
const store = useProjectStore.getState();
|
||||
|
||||
try {
|
||||
const result = await window.electronAPI.updateProjectAutoBuild(projectId);
|
||||
if (result.success && result.data) {
|
||||
return result.data;
|
||||
}
|
||||
store.setError(result.error || 'Failed to update auto-claude');
|
||||
return null;
|
||||
} catch (error) {
|
||||
store.setError(error instanceof Error ? error.message : 'Unknown error');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,8 +45,6 @@ interface TerminalState {
|
||||
setClaudeMode: (id: string, isClaudeMode: boolean) => void;
|
||||
setClaudeSessionId: (id: string, sessionId: string) => void;
|
||||
setAssociatedTask: (id: string, taskId: string | undefined) => void;
|
||||
appendOutput: (id: string, data: string) => void;
|
||||
clearOutputBuffer: (id: string) => void;
|
||||
clearAllTerminals: () => void;
|
||||
setHasRestoredSessions: (value: boolean) => void;
|
||||
|
||||
@@ -187,18 +185,6 @@ export const useTerminalStore = create<TerminalState>((set, get) => ({
|
||||
}));
|
||||
},
|
||||
|
||||
// DEPRECATED: Use terminalBufferManager.append() directly
|
||||
// Kept for backward compatibility, but does NOT trigger React re-renders
|
||||
appendOutput: (id: string, data: string) => {
|
||||
terminalBufferManager.append(id, data);
|
||||
// No React state update - this is the key performance improvement!
|
||||
},
|
||||
|
||||
// DEPRECATED: Use terminalBufferManager.clear() directly
|
||||
clearOutputBuffer: (id: string) => {
|
||||
terminalBufferManager.clear(id);
|
||||
},
|
||||
|
||||
clearAllTerminals: () => {
|
||||
set({ terminals: [], activeTerminalId: null, hasRestoredSessions: false });
|
||||
},
|
||||
|
||||
@@ -10,7 +10,6 @@ export const IPC_CHANNELS = {
|
||||
PROJECT_LIST: 'project:list',
|
||||
PROJECT_UPDATE_SETTINGS: 'project:updateSettings',
|
||||
PROJECT_INITIALIZE: 'project:initialize',
|
||||
PROJECT_UPDATE_AUTOBUILD: 'project:updateAutoBuild',
|
||||
PROJECT_CHECK_VERSION: 'project:checkVersion',
|
||||
|
||||
// Tab state operations (persisted in main process)
|
||||
|
||||
@@ -123,7 +123,6 @@ export interface ElectronAPI {
|
||||
getProjects: () => Promise<IPCResult<Project[]>>;
|
||||
updateProjectSettings: (projectId: string, settings: Partial<ProjectSettings>) => Promise<IPCResult>;
|
||||
initializeProject: (projectId: string) => Promise<IPCResult<InitializationResult>>;
|
||||
updateProjectAutoBuild: (projectId: string) => Promise<IPCResult<InitializationResult>>;
|
||||
checkProjectVersion: (projectId: string) => Promise<IPCResult<AutoBuildVersionInfo>>;
|
||||
|
||||
// Tab State (persisted in main process for reliability)
|
||||
|
||||
@@ -303,19 +303,6 @@ class TestElectronToolScoping:
|
||||
class TestSubtaskTerminology:
|
||||
"""Verify subtask terminology is used consistently."""
|
||||
|
||||
def test_implementation_plan_uses_subtask_class(self):
|
||||
"""Implementation plan uses Subtask class."""
|
||||
impl_plan_path = Path(__file__).parent.parent / "apps" / "backend" / "implementation_plan" / "main.py"
|
||||
content = impl_plan_path.read_text()
|
||||
|
||||
# Check that it re-exports or imports Subtask and SubtaskStatus
|
||||
assert "Subtask" in content, (
|
||||
"implementation_plan/main.py should reference 'Subtask'"
|
||||
)
|
||||
assert "SubtaskStatus" in content, (
|
||||
"implementation_plan/main.py should reference SubtaskStatus enum"
|
||||
)
|
||||
|
||||
def test_progress_uses_subtask_terminology(self):
|
||||
"""Progress module uses subtask terminology."""
|
||||
progress_path = Path(__file__).parent.parent / "apps" / "backend" / "core" / "progress.py"
|
||||
|
||||
@@ -587,18 +587,6 @@ class TestSaveAssessment:
|
||||
assert "phases_to_run" in data
|
||||
assert "discovery" in data["phases_to_run"]
|
||||
|
||||
def test_saves_dev_mode_flag(self, spec_dir: Path):
|
||||
"""Saves dev_mode flag in output."""
|
||||
assessment = ComplexityAssessment(
|
||||
complexity=Complexity.STANDARD,
|
||||
confidence=0.8,
|
||||
)
|
||||
|
||||
save_assessment(spec_dir, assessment, dev_mode=True)
|
||||
data = json.loads((spec_dir / "complexity_assessment.json").read_text())
|
||||
|
||||
assert data["dev_mode"] is True
|
||||
|
||||
def test_saves_timestamp(self, spec_dir: Path):
|
||||
"""Saves created_at timestamp."""
|
||||
assessment = ComplexityAssessment(
|
||||
|
||||
@@ -122,17 +122,6 @@ class TestGetSpecsDir:
|
||||
|
||||
mock_init.assert_called_once_with(temp_dir)
|
||||
|
||||
def test_dev_mode_param_ignored(self, temp_dir: Path):
|
||||
"""dev_mode parameter is deprecated and ignored."""
|
||||
with patch('spec.pipeline.init_auto_claude_dir') as mock_init:
|
||||
mock_init.return_value = (temp_dir / ".auto-claude", False)
|
||||
|
||||
result1 = get_specs_dir(temp_dir, dev_mode=False)
|
||||
result2 = get_specs_dir(temp_dir, dev_mode=True)
|
||||
|
||||
assert result1 == result2
|
||||
|
||||
|
||||
class TestSpecOrchestratorInit:
|
||||
"""Tests for SpecOrchestrator initialization."""
|
||||
|
||||
@@ -574,35 +563,6 @@ class TestComplexityOverride:
|
||||
assert orchestrator.use_ai_assessment is False
|
||||
|
||||
|
||||
class TestSpecOrchestratorDevMode:
|
||||
"""Tests for dev mode configuration."""
|
||||
|
||||
def test_default_dev_mode_false(self, temp_dir: Path):
|
||||
"""Dev mode is False by default."""
|
||||
with patch('spec.pipeline.init_auto_claude_dir') as mock_init:
|
||||
mock_init.return_value = (temp_dir / ".auto-claude", False)
|
||||
specs_dir = temp_dir / ".auto-claude" / "specs"
|
||||
specs_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
orchestrator = SpecOrchestrator(project_dir=temp_dir)
|
||||
|
||||
assert orchestrator.dev_mode is False
|
||||
|
||||
def test_enable_dev_mode(self, temp_dir: Path):
|
||||
"""Can enable dev mode."""
|
||||
with patch('spec.pipeline.init_auto_claude_dir') as mock_init:
|
||||
mock_init.return_value = (temp_dir / ".auto-claude", False)
|
||||
specs_dir = temp_dir / ".auto-claude" / "specs"
|
||||
specs_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
orchestrator = SpecOrchestrator(
|
||||
project_dir=temp_dir,
|
||||
dev_mode=True,
|
||||
)
|
||||
|
||||
assert orchestrator.dev_mode is True
|
||||
|
||||
|
||||
class TestSpecOrchestratorValidator:
|
||||
"""Tests for SpecValidator integration."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user