fix: consolidate auth error handling and fix start.bat credential check

This commit addresses issues found during review of PRs #12 and #28:

## PR #12 (Auth Error Handling) Fixes

- Create shared auth.py module with centralized AUTH_ERROR_PATTERNS,
  is_auth_error(), and print_auth_error_help() functions
- Fix start.bat to use directory check instead of outdated
  .credentials.json file check (matching start.sh behavior)
- Update process_manager.py to import from shared auth module
- Update start.py to import from shared auth module
- Update documentation comments in autonomous_agent_demo.py and
  client.py to remove references to deprecated .credentials.json

## PR #28 (Feature Management) Improvements

- Add _priority_lock threading lock to feature_mcp.py to prevent
  race conditions when multiple features are created simultaneously
- Apply lock to feature_create, feature_create_bulk, and feature_skip
- Add checkAndSendTimeoutRef cleanup in useAssistantChat.ts to
  prevent memory leaks on component unmount
- Clear currentAssistantMessageRef on response_done

## Code Quality

- All Python files pass ruff linting
- All security tests pass (91/91)
- UI passes ESLint and TypeScript compilation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Auto
2026-01-10 12:19:32 +02:00
parent cd82a4cf46
commit a0f7e72361
10 changed files with 430 additions and 170 deletions

View File

@@ -21,6 +21,7 @@ Tools:
import json
import os
import sys
import threading
from contextlib import asynccontextmanager
from pathlib import Path
from typing import Annotated
@@ -82,6 +83,9 @@ class BulkCreateInput(BaseModel):
_session_maker = None
_engine = None
# Lock for priority assignment to prevent race conditions
_priority_lock = threading.Lock()
@asynccontextmanager
async def server_lifespan(server: FastMCP):
@@ -269,13 +273,16 @@ def feature_skip(
old_priority = feature.priority
# Get max priority and set this feature to max + 1
max_priority_result = session.query(Feature.priority).order_by(Feature.priority.desc()).first()
new_priority = (max_priority_result[0] + 1) if max_priority_result else 1
# Use lock to prevent race condition in priority assignment
with _priority_lock:
# Get max priority and set this feature to max + 1
max_priority_result = session.query(Feature.priority).order_by(Feature.priority.desc()).first()
new_priority = (max_priority_result[0] + 1) if max_priority_result else 1
feature.priority = new_priority
feature.in_progress = False
session.commit()
feature.priority = new_priority
feature.in_progress = False
session.commit()
session.refresh(feature)
return json.dumps({
@@ -381,30 +388,32 @@ def feature_create_bulk(
"""
session = get_session()
try:
# Get the starting priority
max_priority_result = session.query(Feature.priority).order_by(Feature.priority.desc()).first()
start_priority = (max_priority_result[0] + 1) if max_priority_result else 1
# Use lock to prevent race condition in priority assignment
with _priority_lock:
# Get the starting priority
max_priority_result = session.query(Feature.priority).order_by(Feature.priority.desc()).first()
start_priority = (max_priority_result[0] + 1) if max_priority_result else 1
created_count = 0
for i, feature_data in enumerate(features):
# Validate required fields
if not all(key in feature_data for key in ["category", "name", "description", "steps"]):
return json.dumps({
"error": f"Feature at index {i} missing required fields (category, name, description, steps)"
})
created_count = 0
for i, feature_data in enumerate(features):
# Validate required fields
if not all(key in feature_data for key in ["category", "name", "description", "steps"]):
return json.dumps({
"error": f"Feature at index {i} missing required fields (category, name, description, steps)"
})
db_feature = Feature(
priority=start_priority + i,
category=feature_data["category"],
name=feature_data["name"],
description=feature_data["description"],
steps=feature_data["steps"],
passes=False,
)
session.add(db_feature)
created_count += 1
db_feature = Feature(
priority=start_priority + i,
category=feature_data["category"],
name=feature_data["name"],
description=feature_data["description"],
steps=feature_data["steps"],
passes=False,
)
session.add(db_feature)
created_count += 1
session.commit()
session.commit()
return json.dumps({"created": created_count}, indent=2)
except Exception as e:
@@ -437,20 +446,23 @@ def feature_create(
"""
session = get_session()
try:
# Get the next priority
max_priority_result = session.query(Feature.priority).order_by(Feature.priority.desc()).first()
next_priority = (max_priority_result[0] + 1) if max_priority_result else 1
# Use lock to prevent race condition in priority assignment
with _priority_lock:
# Get the next priority
max_priority_result = session.query(Feature.priority).order_by(Feature.priority.desc()).first()
next_priority = (max_priority_result[0] + 1) if max_priority_result else 1
db_feature = Feature(
priority=next_priority,
category=category,
name=name,
description=description,
steps=steps,
passes=False,
)
session.add(db_feature)
session.commit()
db_feature = Feature(
priority=next_priority,
category=category,
name=name,
description=description,
steps=steps,
passes=False,
)
session.add(db_feature)
session.commit()
session.refresh(db_feature)
return json.dumps({