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:
Mitsu
2025-12-27 16:33:26 +01:00
committed by GitHub
parent d51f45621b
commit 9d43abedde
27 changed files with 21 additions and 545 deletions
-62
View File
@@ -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",
]
+4 -21
View File
@@ -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))
+4 -8
View File
@@ -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.")
+2 -5
View File
@@ -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
-168
View File
@@ -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())
+1 -28
View File
@@ -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(
+1 -17
View File
@@ -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.
+1 -4
View File
@@ -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,
+1 -2
View File
@@ -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/
+2 -5
View File
@@ -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)
-1
View File
@@ -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)
-13
View File
@@ -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"
-12
View File
@@ -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(
-40
View File
@@ -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."""