# -*- coding: utf-8 -*-
"""
Clouvel MCP Server v1.3.0
MCP server that enforces vibe coding process

v1.2 new tools:
- start: Project onboarding + PRD enforcement (Free)
- manager: 8 C-Level managers collaborative feedback (Pro)
- ship: One-click test→verify→evidence generation (Pro)

Free version - For Pro features, see clouvel-pro package
"""

from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent

from .analytics import log_tool_call, get_stats, format_stats
from .tools import (
    # core
    can_code, scan_docs, analyze_docs, init_docs, REQUIRED_DOCS,
    # docs
    get_prd_template, list_templates, write_prd_section, get_prd_guide, get_verify_checklist, get_setup_guide,
    # setup
    init_clouvel, setup_cli,
    # rules (v0.5)
    init_rules, get_rule, add_rule,
    # verify (v0.5)
    verify, gate, handoff,
    # planning (v0.6, v1.3)
    init_planning, save_finding, refresh_goals, update_progress, create_detailed_plan,
    # agents (v0.7)
    spawn_explore, spawn_librarian,
    # hooks (v0.8)
    hook_design, hook_verify,
    # start (Free, v1.2)
    start, quick_start, save_prd,
    # tracking (v1.5)
    record_file, list_files,
    # knowledge (Free, v1.4)
    record_decision, record_location, search_knowledge, get_context, init_knowledge, rebuild_index,
    # manager (Pro, v1.2)
    manager, ask_manager, list_managers, MANAGERS,
    # ship (Pro, v1.2)
    ship, quick_ship, full_ship,
)

# Error Learning tools (Pro feature - separate import)
try:
    from .tools.errors import error_record, error_check, error_learn
    _HAS_ERROR_TOOLS = True
except ImportError:
    _HAS_ERROR_TOOLS = False
    error_record = None
    error_check = None
    error_learn = None
# License module import (use Free stub if Pro version not available)
try:
    from .license import activate_license_cli, get_license_status
except ImportError:
    from .license_free import activate_license_cli, get_license_status
from .version_check import init_version_check, get_cached_update_info, get_update_banner

server = Server("clouvel")

# Version check on server start (processed asynchronously)
_version_check_done = False


# ============================================================
# Tool Definitions (Free - up to v0.8)
# ============================================================

TOOL_DEFINITIONS = [
    # === Core Tools ===
    Tool(
        name="can_code",
        description="Must call before writing code. Checks document status and determines if coding is allowed.",
        inputSchema={
            "type": "object",
            "properties": {"path": {"type": "string", "description": "Project docs folder path"}},
            "required": ["path"]
        }
    ),
    Tool(
        name="scan_docs",
        description="Scan project docs folder. Returns file list.",
        inputSchema={
            "type": "object",
            "properties": {"path": {"type": "string", "description": "docs folder path"}},
            "required": ["path"]
        }
    ),
    Tool(
        name="analyze_docs",
        description="Analyze docs folder. Check required documents.",
        inputSchema={
            "type": "object",
            "properties": {"path": {"type": "string", "description": "docs folder path"}},
            "required": ["path"]
        }
    ),
    Tool(
        name="init_docs",
        description="Initialize docs folder + generate templates.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "project_name": {"type": "string", "description": "Project name"}
            },
            "required": ["path", "project_name"]
        }
    ),

    # === Docs Tools ===
    Tool(
        name="get_prd_template",
        description="Generate PRD template. Choose template and layout.",
        inputSchema={
            "type": "object",
            "properties": {
                "project_name": {"type": "string", "description": "Project name"},
                "output_path": {"type": "string", "description": "Output path"},
                "template": {"type": "string", "enum": ["web-app", "api", "cli", "generic"], "description": "Template type"},
                "layout": {"type": "string", "enum": ["lite", "standard", "detailed"], "description": "Layout (content amount)"}
            },
            "required": ["project_name", "output_path"]
        }
    ),
    Tool(
        name="list_templates",
        description="List available PRD templates.",
        inputSchema={"type": "object", "properties": {}}
    ),
    Tool(
        name="write_prd_section",
        description="PRD section writing guide.",
        inputSchema={
            "type": "object",
            "properties": {
                "section": {"type": "string", "enum": ["summary", "principles", "input_spec", "output_spec", "errors", "state_machine", "api_endpoints", "db_schema"]},
                "content": {"type": "string", "description": "Section content"}
            },
            "required": ["section"]
        }
    ),
    Tool(name="get_prd_guide", description="PRD writing guide.", inputSchema={"type": "object", "properties": {}}),
    Tool(name="get_verify_checklist", description="Verification checklist.", inputSchema={"type": "object", "properties": {}}),
    Tool(
        name="get_setup_guide",
        description="Installation/setup guide.",
        inputSchema={
            "type": "object",
            "properties": {"platform": {"type": "string", "enum": ["desktop", "code", "vscode", "cursor", "all"]}}
        }
    ),
    Tool(
        name="get_analytics",
        description="Tool usage statistics.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project path"},
                "days": {"type": "integer", "description": "Query period (default: 30 days)"}
            }
        }
    ),

    # === Setup Tools ===
    Tool(
        name="init_clouvel",
        description="Clouvel onboarding. Custom setup after platform selection.",
        inputSchema={
            "type": "object",
            "properties": {"platform": {"type": "string", "enum": ["desktop", "vscode", "cli", "ask"]}}
        }
    ),
    Tool(
        name="setup_cli",
        description="CLI environment setup. Generate hooks, CLAUDE.md, pre-commit.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "level": {"type": "string", "enum": ["remind", "strict", "full"]}
            },
            "required": ["path"]
        }
    ),

    # === Rules Tools (v0.5) ===
    Tool(
        name="init_rules",
        description="v0.5: Initialize rules modularization.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "template": {"type": "string", "enum": ["web", "api", "fullstack", "minimal"]}
            },
            "required": ["path"]
        }
    ),
    Tool(
        name="get_rule",
        description="v0.5: Load rules based on path.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "File path"},
                "context": {"type": "string", "enum": ["coding", "review", "debug", "test"]}
            },
            "required": ["path"]
        }
    ),
    Tool(
        name="add_rule",
        description="v0.5: Add new rule.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "rule_type": {"type": "string", "enum": ["never", "always", "prefer"]},
                "content": {"type": "string", "description": "Rule content"},
                "category": {"type": "string", "enum": ["api", "frontend", "database", "security", "general"]}
            },
            "required": ["path", "rule_type", "content"]
        }
    ),

    # === Verify Tools (v0.5) ===
    Tool(
        name="verify",
        description="v0.5: Context Bias removal verification.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Verification target path"},
                "scope": {"type": "string", "enum": ["file", "feature", "full"]},
                "checklist": {"type": "array", "items": {"type": "string"}}
            },
            "required": ["path"]
        }
    ),
    Tool(
        name="gate",
        description="v0.5: lint -> test -> build automation.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "steps": {"type": "array", "items": {"type": "string"}},
                "fix": {"type": "boolean"}
            },
            "required": ["path"]
        }
    ),
    Tool(
        name="handoff",
        description="v0.5: Record intent.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "feature": {"type": "string", "description": "Completed feature"},
                "decisions": {"type": "string"},
                "warnings": {"type": "string"},
                "next_steps": {"type": "string"}
            },
            "required": ["path", "feature"]
        }
    ),

    # === Planning Tools (v0.6, v1.3) ===
    Tool(
        name="init_planning",
        description="v0.6: Initialize persistent context.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "task": {"type": "string", "description": "Current task"},
                "goals": {"type": "array", "items": {"type": "string"}}
            },
            "required": ["path", "task"]
        }
    ),
    Tool(
        name="plan",
        description="v1.3: Generate detailed execution plan. Synthesize manager feedback to create plan with step-by-step action items, dependencies, and verification points. Can reference previous meeting results via meeting_file. (Pro)",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "task": {"type": "string", "description": "Task to perform"},
                "goals": {"type": "array", "items": {"type": "string"}, "description": "Goals to achieve"},
                "meeting_file": {"type": "string", "description": "Previous meeting file name (e.g., 2026-01-24_14-00_feature.md). If provided, generates plan based on meeting results"}
            },
            "required": ["path", "task"]
        }
    ),
    Tool(
        name="save_finding",
        description="v0.6: Save research findings.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "topic": {"type": "string"},
                "question": {"type": "string"},
                "findings": {"type": "string"},
                "source": {"type": "string"},
                "conclusion": {"type": "string"}
            },
            "required": ["path", "topic", "findings"]
        }
    ),
    Tool(
        name="refresh_goals",
        description="v0.6: Goals reminder.",
        inputSchema={
            "type": "object",
            "properties": {"path": {"type": "string", "description": "Project root path"}},
            "required": ["path"]
        }
    ),
    Tool(
        name="update_progress",
        description="v0.6: Update progress status.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "completed": {"type": "array", "items": {"type": "string"}},
                "in_progress": {"type": "string"},
                "blockers": {"type": "array", "items": {"type": "string"}},
                "next": {"type": "string"}
            },
            "required": ["path"]
        }
    ),

    # === Agent Tools (v0.7) ===
    Tool(
        name="spawn_explore",
        description="v0.7: Exploration specialist agent.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "query": {"type": "string", "description": "Exploration question"},
                "scope": {"type": "string", "enum": ["file", "folder", "project", "deep"]},
                "save_findings": {"type": "boolean"}
            },
            "required": ["path", "query"]
        }
    ),
    Tool(
        name="spawn_librarian",
        description="v0.7: Librarian agent.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "topic": {"type": "string", "description": "Research topic"},
                "type": {"type": "string", "enum": ["library", "api", "migration", "best_practice"]},
                "depth": {"type": "string", "enum": ["quick", "standard", "thorough"]}
            },
            "required": ["path", "topic"]
        }
    ),

    # === Hook Tools (v0.8) ===
    Tool(
        name="hook_design",
        description="v0.8: Create design hook.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "trigger": {"type": "string", "enum": ["pre_code", "pre_feature", "pre_refactor", "pre_api"]},
                "checks": {"type": "array", "items": {"type": "string"}},
                "block_on_fail": {"type": "boolean"}
            },
            "required": ["path", "trigger"]
        }
    ),
    Tool(
        name="hook_verify",
        description="v0.8: Create verification hook.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "trigger": {"type": "string", "enum": ["post_code", "post_feature", "pre_commit", "pre_push"]},
                "steps": {"type": "array", "items": {"type": "string"}},
                "parallel": {"type": "boolean"},
                "continue_on_error": {"type": "boolean"}
            },
            "required": ["path", "trigger"]
        }
    ),

    # === Start Tool (Free, v1.2) ===
    Tool(
        name="start",
        description="Project onboarding. PRD check, auto-detect project type, interactive PRD writing guide. (Free)",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "project_name": {"type": "string", "description": "Project name (optional)"},
                "project_type": {"type": "string", "description": "Force project type (optional)", "enum": ["web-app", "api", "cli", "chrome-ext", "discord-bot", "landing-page", "generic"]}
            },
            "required": ["path"]
        }
    ),
    Tool(
        name="save_prd",
        description="Save PRD content. Save PRD written through conversation with Claude. (Free)",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "content": {"type": "string", "description": "PRD content (markdown)"},
                "project_name": {"type": "string", "description": "Project name (optional)"},
                "project_type": {"type": "string", "description": "Project type (optional)"}
            },
            "required": ["path", "content"]
        }
    ),

    # === Knowledge Base Tools (Pro, v1.4) ===
    Tool(
        name="record_decision",
        description="Record a decision to the knowledge base. Persists across sessions for context recovery. (Pro)",
        inputSchema={
            "type": "object",
            "properties": {
                "category": {"type": "string", "description": "Decision category (architecture, pricing, security, feature, etc.)"},
                "decision": {"type": "string", "description": "The actual decision made"},
                "reasoning": {"type": "string", "description": "Why this decision was made"},
                "alternatives": {"type": "array", "items": {"type": "string"}, "description": "Other options that were considered"},
                "project_name": {"type": "string", "description": "Project name (optional)"},
                "project_path": {"type": "string", "description": "Project path (optional)"}
            },
            "required": ["category", "decision"]
        }
    ),
    Tool(
        name="record_location",
        description="Record a code location to the knowledge base. Track where important code lives. (Pro)",
        inputSchema={
            "type": "object",
            "properties": {
                "name": {"type": "string", "description": "Descriptive name (e.g., 'License validation endpoint')"},
                "repo": {"type": "string", "description": "Repository name (e.g., 'clouvel-workers')"},
                "path": {"type": "string", "description": "File path within repo (e.g., 'src/index.js:42')"},
                "description": {"type": "string", "description": "What this code does"},
                "project_name": {"type": "string", "description": "Project name (optional)"},
                "project_path": {"type": "string", "description": "Project path (optional)"}
            },
            "required": ["name", "repo", "path"]
        }
    ),
    Tool(
        name="search_knowledge",
        description="Search the knowledge base. Find past decisions, locations, and context. (Pro)",
        inputSchema={
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "Search query (FTS5 syntax supported)"},
                "project_name": {"type": "string", "description": "Filter by project (optional)"},
                "limit": {"type": "integer", "description": "Max results (default 20)"}
            },
            "required": ["query"]
        }
    ),
    Tool(
        name="get_context",
        description="Get recent context for a project. Returns recent decisions and code locations. (Pro)",
        inputSchema={
            "type": "object",
            "properties": {
                "project_name": {"type": "string", "description": "Project name"},
                "project_path": {"type": "string", "description": "Project path"},
                "include_decisions": {"type": "boolean", "description": "Include recent decisions (default true)"},
                "include_locations": {"type": "boolean", "description": "Include code locations (default true)"},
                "limit": {"type": "integer", "description": "Max items per category (default 10)"}
            }
        }
    ),
    Tool(
        name="init_knowledge",
        description="Initialize the knowledge base. Creates SQLite database at ~/.clouvel/knowledge.db. (Pro)",
        inputSchema={
            "type": "object",
            "properties": {}
        }
    ),
    Tool(
        name="rebuild_index",
        description="Rebuild the knowledge base search index. Use if search results seem incomplete. (Pro)",
        inputSchema={
            "type": "object",
            "properties": {}
        }
    ),

    # === Tracking Tools (v1.5) ===
    Tool(
        name="record_file",
        description="Record a file creation to .claude/files/created.md. Use this when creating important files that should not be deleted.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "file_path": {"type": "string", "description": "Relative path of the created file"},
                "purpose": {"type": "string", "description": "What this file does"},
                "deletable": {"type": "boolean", "description": "Whether this file can be deleted (default: false)"},
                "session": {"type": "string", "description": "Session name for grouping (optional)"}
            },
            "required": ["path", "file_path", "purpose"]
        }
    ),
    Tool(
        name="list_files",
        description="List all recorded files from .claude/files/created.md.",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"}
            },
            "required": ["path"]
        }
    ),

    # === Manager Tool (Pro, v1.2) ===
    Tool(
        name="manager",
        description="Context-based collaborative feedback from 8 C-Level managers. PM/CTO/QA/CDO/CMO/CFO/CSO/Error. Set use_dynamic=true for natural meeting transcript generation. (Pro)",
        inputSchema={
            "type": "object",
            "properties": {
                "context": {"type": "string", "description": "Content to review (plan, code, questions, etc.)"},
                "mode": {"type": "string", "enum": ["auto", "all", "specific"], "description": "Manager selection mode"},
                "managers": {"type": "array", "items": {"type": "string"}, "description": "Manager list when mode=specific"},
                "include_checklist": {"type": "boolean", "description": "Include checklist"},
                "use_dynamic": {"type": "boolean", "description": "If true, generate natural meeting transcript via Claude API (ANTHROPIC_API_KEY required)"},
                "topic": {"type": "string", "enum": ["auth", "api", "payment", "ui", "feature", "launch", "error", "security", "performance", "maintenance", "design"], "description": "Meeting topic hint (when use_dynamic=true)"}
            },
            "required": ["context"]
        }
    ),
    Tool(
        name="list_managers",
        description="List available managers. (Pro)",
        inputSchema={"type": "object", "properties": {}}
    ),
    Tool(
        name="quick_perspectives",
        description="Quick, lightweight perspective check before coding. Returns key questions from 3-4 relevant managers. Call this BEFORE starting any coding task to surface blind spots. (Free)",
        inputSchema={
            "type": "object",
            "properties": {
                "context": {"type": "string", "description": "What you're about to build/do"},
                "max_managers": {"type": "integer", "description": "Max managers to include (default 4)"},
                "questions_per_manager": {"type": "integer", "description": "Questions per manager (default 2)"}
            },
            "required": ["context"]
        }
    ),

    # === Ship Tool (Pro, v1.2) ===
    Tool(
        name="ship",
        description="One-click test->verify->evidence generation. Sequential execution of lint/typecheck/test/build. (Pro)",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "feature": {"type": "string", "description": "Feature name to verify (optional)"},
                "steps": {"type": "array", "items": {"type": "string"}, "description": "Steps to execute ['lint', 'typecheck', 'test', 'build']"},
                "generate_evidence": {"type": "boolean", "description": "Generate evidence file"},
                "auto_fix": {"type": "boolean", "description": "Attempt auto-fix for lint errors"}
            },
            "required": ["path"]
        }
    ),
    Tool(
        name="quick_ship",
        description="Quick ship - run lint and test only. (Pro)",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "feature": {"type": "string", "description": "Feature name to verify (optional)"}
            },
            "required": ["path"]
        }
    ),
    Tool(
        name="full_ship",
        description="Full ship - all verification steps + auto fix. (Pro)",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "feature": {"type": "string", "description": "Feature name to verify (optional)"}
            },
            "required": ["path"]
        }
    ),

    # === Error Learning Tools (Pro, v1.4) ===
    Tool(
        name="error_record",
        description="5 Whys structured error recording + MD file generation. Root cause analysis when errors occur. (Pro)",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "error_text": {"type": "string", "description": "Error message"},
                "context": {"type": "string", "description": "Error context description"},
                "five_whys": {"type": "array", "items": {"type": "string"}, "description": "5 Whys analysis results"},
                "root_cause": {"type": "string", "description": "Root cause"},
                "solution": {"type": "string", "description": "Solution"},
                "prevention": {"type": "string", "description": "Prevention measures"}
            },
            "required": ["path", "error_text"]
        }
    ),
    Tool(
        name="error_check",
        description="Context-based proactive warning. Check past error patterns before code modification. (Pro)",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "context": {"type": "string", "description": "Current work context"},
                "file_path": {"type": "string", "description": "File path to modify"},
                "operation": {"type": "string", "description": "Operation to perform"}
            },
            "required": ["path", "context"]
        }
    ),
    Tool(
        name="error_learn",
        description="Session analysis + CLAUDE.md auto update. Learn NEVER/ALWAYS rules from error patterns. (Pro)",
        inputSchema={
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "Project root path"},
                "auto_update_claude_md": {"type": "boolean", "description": "Auto update CLAUDE.md"},
                "min_count": {"type": "integer", "description": "Minimum error count for NEVER rule generation"}
            },
            "required": ["path"]
        }
    ),

    # === License Tools ===
    Tool(
        name="activate_license",
        description="Activate license. Supports Polar.sh or test license.",
        inputSchema={
            "type": "object",
            "properties": {
                "license_key": {"type": "string", "description": "License key"}
            },
            "required": ["license_key"]
        }
    ),
    Tool(
        name="license_status",
        description="Check current license status.",
        inputSchema={"type": "object", "properties": {}}
    ),

    # === Pro Guide ===
    Tool(
        name="upgrade_pro",
        description="Clouvel Pro guide. Shovel auto-install, Error Learning, etc.",
        inputSchema={"type": "object", "properties": {}}
    ),
]


@server.list_tools()
async def list_tools() -> list[Tool]:
    return TOOL_DEFINITIONS


# ============================================================
# Tool Handlers
# ============================================================

TOOL_HANDLERS = {
    # Core
    "can_code": lambda args: can_code(args.get("path", "")),
    "scan_docs": lambda args: scan_docs(args.get("path", "")),
    "analyze_docs": lambda args: analyze_docs(args.get("path", "")),
    "init_docs": lambda args: init_docs(args.get("path", ""), args.get("project_name", "")),

    # Docs
    "get_prd_template": lambda args: get_prd_template(args.get("project_name", ""), args.get("output_path", ""), args.get("template", "generic"), args.get("layout", "standard")),
    "list_templates": lambda args: list_templates(),
    "write_prd_section": lambda args: write_prd_section(args.get("section", ""), args.get("content", "")),
    "get_prd_guide": lambda args: get_prd_guide(),
    "get_verify_checklist": lambda args: get_verify_checklist(),
    "get_setup_guide": lambda args: get_setup_guide(args.get("platform", "all")),

    # Setup
    "init_clouvel": lambda args: init_clouvel(args.get("platform", "ask")),
    "setup_cli": lambda args: setup_cli(args.get("path", ""), args.get("level", "remind")),

    # Rules (v0.5)
    "init_rules": lambda args: init_rules(args.get("path", ""), args.get("template", "minimal")),
    "get_rule": lambda args: get_rule(args.get("path", ""), args.get("context", "coding")),
    "add_rule": lambda args: add_rule(args.get("path", ""), args.get("rule_type", "always"), args.get("content", ""), args.get("category", "general")),

    # Verify (v0.5)
    "verify": lambda args: verify(args.get("path", ""), args.get("scope", "file"), args.get("checklist", [])),
    "gate": lambda args: gate(args.get("path", ""), args.get("steps", ["lint", "test", "build"]), args.get("fix", False)),
    "handoff": lambda args: handoff(args.get("path", ""), args.get("feature", ""), args.get("decisions", ""), args.get("warnings", ""), args.get("next_steps", "")),

    # Planning (v0.6, v1.3)
    "init_planning": lambda args: init_planning(args.get("path", ""), args.get("task", ""), args.get("goals", [])),
    "plan": lambda args: create_detailed_plan(args.get("path", ""), args.get("task", ""), args.get("goals", []), meeting_file=args.get("meeting_file")),
    "save_finding": lambda args: save_finding(args.get("path", ""), args.get("topic", ""), args.get("question", ""), args.get("findings", ""), args.get("source", ""), args.get("conclusion", "")),
    "refresh_goals": lambda args: refresh_goals(args.get("path", "")),
    "update_progress": lambda args: update_progress(args.get("path", ""), args.get("completed", []), args.get("in_progress", ""), args.get("blockers", []), args.get("next", "")),

    # Agents (v0.7)
    "spawn_explore": lambda args: spawn_explore(args.get("path", ""), args.get("query", ""), args.get("scope", "project"), args.get("save_findings", True)),
    "spawn_librarian": lambda args: spawn_librarian(args.get("path", ""), args.get("topic", ""), args.get("type", "library"), args.get("depth", "standard")),

    # Hooks (v0.8)
    "hook_design": lambda args: hook_design(args.get("path", ""), args.get("trigger", "pre_code"), args.get("checks", []), args.get("block_on_fail", True)),
    "hook_verify": lambda args: hook_verify(args.get("path", ""), args.get("trigger", "post_code"), args.get("steps", ["lint", "test", "build"]), args.get("parallel", False), args.get("continue_on_error", False)),

    # Start (Free, v1.2)
    "start": lambda args: _wrap_start(args),
    "save_prd": lambda args: _wrap_save_prd(args),

    # Knowledge (Free, v1.4)
    "record_decision": lambda args: _wrap_record_decision(args),
    "record_location": lambda args: _wrap_record_location(args),
    "search_knowledge": lambda args: _wrap_search_knowledge(args),
    "get_context": lambda args: _wrap_get_context(args),
    "init_knowledge": lambda args: _wrap_init_knowledge(),
    "rebuild_index": lambda args: _wrap_rebuild_index(),

    # Tracking (v1.5)
    "record_file": lambda args: _wrap_record_file(args),
    "list_files": lambda args: _wrap_list_files(args),

    # Manager (Pro, v1.2)
    "manager": lambda args: _wrap_manager(args),
    "list_managers": lambda args: _wrap_list_managers(),
    "quick_perspectives": lambda args: _wrap_quick_perspectives(args),

    # Ship (Pro, v1.2)
    "ship": lambda args: _wrap_ship(args),
    "quick_ship": lambda args: _wrap_quick_ship(args),
    "full_ship": lambda args: _wrap_full_ship(args),

    # Error Learning (Pro, v1.4)
    "error_record": lambda args: _wrap_error_record(args),
    "error_check": lambda args: _wrap_error_check(args),
    "error_learn": lambda args: _wrap_error_learn(args),

    # License
    "activate_license": lambda args: _wrap_activate_license(args),
    "license_status": lambda args: _wrap_license_status(),

    # Pro 안내
    "upgrade_pro": lambda args: _upgrade_pro(),
}


def _check_version_once():
    """Check version on first call (lazy initialization)"""
    global _version_check_done
    if not _version_check_done:
        try:
            init_version_check()
        except Exception:
            pass
        _version_check_done = True


async def _wrap_start(args: dict) -> list[TextContent]:
    """start tool wrapper"""
    result = start(
        args.get("path", ""),
        args.get("project_name", ""),
        args.get("project_type", "")
    )

    if isinstance(result, dict):
        # Project type info
        ptype = result.get("project_type", {})
        type_info = f"**Type**: {ptype.get('description', 'N/A')} ({ptype.get('type', 'generic')}) - Confidence {ptype.get('confidence', 0)}%"

        output = f"""# 🚀 Start

**Status**: {result.get('status', 'UNKNOWN')}
**Project**: {result.get('project_name', 'N/A')}
{type_info}

{result.get('message', '')}
"""

        # PRD writing guide (when status is NEED_PRD)
        if result.get("status") == "NEED_PRD" and result.get("prd_guide"):
            guide = result["prd_guide"]
            output += guide.get("instruction", "")

        # Next steps
        output += "\n## Next Steps\n"
        for step in result.get('next_steps', []):
            output += f"- {step}\n"

        # Created files
        if result.get('created_files'):
            output += "\n## Created Files\n"
            for f in result['created_files']:
                output += f"- {f}\n"

        return [TextContent(type="text", text=output)]
    return [TextContent(type="text", text=str(result))]


async def _wrap_save_prd(args: dict) -> list[TextContent]:
    """save_prd tool wrapper"""
    result = save_prd(
        args.get("path", ""),
        args.get("content", ""),
        args.get("project_name", ""),
        args.get("project_type", "")
    )

    if isinstance(result, dict):
        output = f"""# 📝 Save PRD

**Status**: {result.get('status', 'UNKNOWN')}
**Path**: {result.get('prd_path', 'N/A')}

{result.get('message', '')}
"""
        if result.get('next_steps'):
            output += "\n## Next Steps\n"
            for step in result['next_steps']:
                output += f"- {step}\n"

        return [TextContent(type="text", text=output)]
    return [TextContent(type="text", text=str(result))]


# === Knowledge Base Wrappers (Free, v1.4) ===

async def _wrap_record_decision(args: dict) -> list[TextContent]:
    """record_decision tool wrapper"""
    result = await record_decision(
        category=args.get("category", "general"),
        decision=args.get("decision", ""),
        reasoning=args.get("reasoning"),
        alternatives=args.get("alternatives"),
        project_name=args.get("project_name"),
        project_path=args.get("project_path")
    )

    if result.get("status") == "recorded":
        output = f"""# ✅ Decision Recorded

**ID**: {result.get('decision_id')}
**Category**: {result.get('category')}
**Project**: {result.get('project_id', 'global')}

Decision saved to knowledge base. Use `search_knowledge` to retrieve later.
"""
    else:
        output = f"""# ❌ Error Recording Decision

{result.get('error', 'Unknown error')}
"""
    return [TextContent(type="text", text=output)]


async def _wrap_record_location(args: dict) -> list[TextContent]:
    """record_location tool wrapper"""
    result = await record_location(
        name=args.get("name", ""),
        repo=args.get("repo", ""),
        path=args.get("path", ""),
        description=args.get("description"),
        project_name=args.get("project_name"),
        project_path=args.get("project_path")
    )

    if result.get("status") == "recorded":
        output = f"""# ✅ Location Recorded

**ID**: {result.get('location_id')}
**Name**: {result.get('name')}
**Repo**: {result.get('repo')}
**Path**: {result.get('path')}

Location saved to knowledge base.
"""
    else:
        output = f"""# ❌ Error Recording Location

{result.get('error', 'Unknown error')}
"""
    return [TextContent(type="text", text=output)]


async def _wrap_search_knowledge(args: dict) -> list[TextContent]:
    """search_knowledge tool wrapper"""
    result = await search_knowledge(
        query=args.get("query", ""),
        project_name=args.get("project_name"),
        limit=args.get("limit", 20)
    )

    if result.get("status") == "success":
        output = f"""# 🔍 Knowledge Search Results

**Query**: {result.get('query')}
**Found**: {result.get('count')} results

"""
        for item in result.get("results", []):
            output += f"""## [{item['type'].upper()}] ID: {item['id']}
{item['content'][:200]}{'...' if len(item['content']) > 200 else ''}

---
"""
        if not result.get("results"):
            output += "_No results found._\n"
    else:
        output = f"""# ❌ Search Error

{result.get('error', 'Unknown error')}
"""
    return [TextContent(type="text", text=output)]


async def _wrap_get_context(args: dict) -> list[TextContent]:
    """get_context tool wrapper"""
    result = await get_context(
        project_name=args.get("project_name"),
        project_path=args.get("project_path"),
        include_decisions=args.get("include_decisions", True),
        include_locations=args.get("include_locations", True),
        limit=args.get("limit", 10)
    )

    if result.get("status") == "success":
        output = f"""# 📋 Project Context

**Project ID**: {result.get('project_id', 'global')}

"""
        if result.get("decisions"):
            output += "## Recent Decisions\n\n"
            for d in result["decisions"]:
                output += f"- **[{d.get('category', 'general')}]** {d.get('decision', '')[:100]}\n"
            output += "\n"

        if result.get("locations"):
            output += "## Code Locations\n\n"
            for loc in result["locations"]:
                output += f"- **{loc.get('name', '')}**: `{loc.get('repo', '')}/{loc.get('path', '')}`\n"
            output += "\n"

        if not result.get("decisions") and not result.get("locations"):
            output += "_No context recorded yet. Use `record_decision` and `record_location` to add context._\n"
    else:
        output = f"""# ❌ Error Getting Context

{result.get('error', 'Unknown error')}
"""
    return [TextContent(type="text", text=output)]


async def _wrap_init_knowledge() -> list[TextContent]:
    """init_knowledge tool wrapper"""
    result = await init_knowledge()

    if result.get("status") == "initialized":
        output = f"""# ✅ Knowledge Base Initialized

**Database**: {result.get('db_path')}

{result.get('message', '')}

## Available Commands
- `record_decision` - Record a decision
- `record_location` - Record a code location
- `search_knowledge` - Search past knowledge
- `get_context` - Get recent context
"""
    else:
        output = f"""# ❌ Initialization Error

{result.get('error', 'Unknown error')}
"""
    return [TextContent(type="text", text=output)]


async def _wrap_rebuild_index() -> list[TextContent]:
    """rebuild_index tool wrapper"""
    result = await rebuild_index()

    if result.get("status") == "rebuilt":
        output = f"""# ✅ Search Index Rebuilt

**Indexed Items**: {result.get('indexed_count')}

{result.get('message', '')}
"""
    else:
        output = f"""# ❌ Rebuild Error

{result.get('error', 'Unknown error')}
"""
    return [TextContent(type="text", text=output)]


# === Tracking Wrappers (v1.5) ===

async def _wrap_record_file(args: dict) -> list[TextContent]:
    """record_file tool wrapper"""
    return await record_file(
        path=args.get("path", "."),
        file_path=args.get("file_path", ""),
        purpose=args.get("purpose", ""),
        deletable=args.get("deletable", False),
        session=args.get("session", None)
    )


async def _wrap_list_files(args: dict) -> list[TextContent]:
    """list_files tool wrapper"""
    return await list_files(path=args.get("path", "."))


async def _wrap_manager(args: dict) -> list[TextContent]:
    """manager tool wrapper"""
    use_dynamic = args.get("use_dynamic", False)
    context = args.get("context", "")
    topic = args.get("topic", None)

    meeting_output = None
    participants = []

    # Dynamic meeting transcript generation mode
    if use_dynamic:
        try:
            from .tools.manager.generator import generate_meeting_sync
            import os

            # Guess project path (use current working directory)
            project_path = os.getcwd()

            meeting_output = generate_meeting_sync(
                context=context,
                topic=topic,
                project_path=project_path,
                auto_log=True
            )
            participants = ["PM", "CTO", "QA", "CDO", "CMO", "CFO", "CSO"]  # Dynamic uses all
        except ImportError:
            return [TextContent(type="text", text="anthropic package required: pip install anthropic")]
        except Exception as e:
            # Fallback to existing method if API key missing or error
            meeting_output = f"Dynamic meeting generation failed: {e}\n\nProceeding with existing method."

    # Existing static feedback (if dynamic failed or not requested)
    if meeting_output is None or "failed" in meeting_output:
        result = manager(
            context=context,
            mode=args.get("mode", "auto"),
            managers=args.get("managers", None),
            include_checklist=args.get("include_checklist", True)
        )
        if isinstance(result, dict) and result.get("formatted_output"):
            meeting_output = result["formatted_output"]
            participants = result.get("selected_managers", ["PM", "CTO", "QA"])
        else:
            meeting_output = str(result)

    # Auto-record meeting to Knowledge Base
    _auto_record_meeting(context, topic, participants, meeting_output)

    return [TextContent(type="text", text=meeting_output)]


def _auto_record_meeting(context: str, topic: str, participants: list, output: str):
    """Automatically record meeting to Knowledge Base."""
    try:
        from .db.knowledge import record_meeting, record_decision, get_or_create_project
        import os

        # Get project from current directory
        project_path = os.getcwd()
        project_name = os.path.basename(project_path)
        project_id = get_or_create_project(project_name, project_path)

        # Record meeting
        contributions = {}
        for p in participants:
            # Extract contribution from output if possible
            contributions[p] = f"Participated in {topic or 'general'} discussion"

        meeting_id = record_meeting(
            topic=topic or "manager_review",
            participants=participants,
            contributions=contributions,
            project_id=project_id
        )

        # Try to extract and record decisions from output
        _extract_and_record_decisions(output, project_id, meeting_id)

    except Exception:
        # Silently fail - don't break manager output
        pass


def _extract_and_record_decisions(output: str, project_id: str, meeting_id: str):
    """Extract decisions from meeting output and record them."""
    try:
        from .db.knowledge import record_decision
        import re

        # Look for action items or decisions in output
        # Pattern: "| # | 담당 | 작업 |" table or "- **[category]** decision" format
        lines = output.split('\n')
        for line in lines:
            # Match action item table rows: "| 1 | PM | Task description |"
            table_match = re.match(r'\|\s*\d+\s*\|\s*[^\|]+\s*\|\s*([^\|]+)\s*\|', line)
            if table_match:
                decision_text = table_match.group(1).strip()
                if decision_text and len(decision_text) > 10:
                    record_decision(
                        category="action_item",
                        decision=decision_text[:200],
                        project_id=project_id,
                        meeting_id=meeting_id
                    )

    except Exception:
        pass


async def _wrap_list_managers() -> list[TextContent]:
    """list_managers tool wrapper"""
    managers_list = list_managers()
    output = "# 👔 Available Managers (8)\n\n"
    for m in managers_list:
        output += f"- **{m['emoji']} {m['key']}** ({m['title']}): {m['focus']}\n"
    return [TextContent(type="text", text=output)]


async def _wrap_quick_perspectives(args: dict) -> list[TextContent]:
    """quick_perspectives tool wrapper"""
    from .tools.manager import quick_perspectives
    result = quick_perspectives(
        context=args.get("context", ""),
        max_managers=args.get("max_managers", 4),
        questions_per_manager=args.get("questions_per_manager", 2)
    )
    if isinstance(result, dict) and result.get("formatted_output"):
        return [TextContent(type="text", text=result["formatted_output"])]
    return [TextContent(type="text", text=str(result))]


async def _wrap_ship(args: dict) -> list[TextContent]:
    """ship tool wrapper"""
    result = ship(
        path=args.get("path", ""),
        feature=args.get("feature", ""),
        steps=args.get("steps", None),
        generate_evidence=args.get("generate_evidence", True),
        auto_fix=args.get("auto_fix", False)
    )
    if isinstance(result, dict) and result.get("formatted_output"):
        return [TextContent(type="text", text=result["formatted_output"])]
    return [TextContent(type="text", text=str(result))]


async def _wrap_quick_ship(args: dict) -> list[TextContent]:
    """quick_ship tool wrapper"""
    result = quick_ship(
        path=args.get("path", ""),
        feature=args.get("feature", "")
    )
    if isinstance(result, dict) and result.get("formatted_output"):
        return [TextContent(type="text", text=result["formatted_output"])]
    return [TextContent(type="text", text=str(result))]


async def _wrap_full_ship(args: dict) -> list[TextContent]:
    """full_ship tool wrapper"""
    result = full_ship(
        path=args.get("path", ""),
        feature=args.get("feature", "")
    )
    if isinstance(result, dict) and result.get("formatted_output"):
        return [TextContent(type="text", text=result["formatted_output"])]
    return [TextContent(type="text", text=str(result))]


async def _wrap_error_record(args: dict) -> list[TextContent]:
    """error_record tool wrapper"""
    if not _HAS_ERROR_TOOLS or error_record is None:
        return [TextContent(type="text", text="""
# Clouvel Pro Feature

Error Learning requires a Pro license.

## Purchase
https://polar.sh/clouvel
""")]
    return await error_record(
        path=args.get("path", ""),
        error_text=args.get("error_text", ""),
        context=args.get("context", ""),
        five_whys=args.get("five_whys", None),
        root_cause=args.get("root_cause", ""),
        solution=args.get("solution", ""),
        prevention=args.get("prevention", "")
    )


async def _wrap_error_check(args: dict) -> list[TextContent]:
    """error_check tool wrapper"""
    if not _HAS_ERROR_TOOLS or error_check is None:
        return [TextContent(type="text", text="""
# Clouvel Pro Feature

Error Learning requires a Pro license.

## Purchase
https://polar.sh/clouvel
""")]
    return await error_check(
        path=args.get("path", ""),
        context=args.get("context", ""),
        file_path=args.get("file_path", ""),
        operation=args.get("operation", "")
    )


async def _wrap_error_learn(args: dict) -> list[TextContent]:
    """error_learn tool wrapper"""
    if not _HAS_ERROR_TOOLS or error_learn is None:
        return [TextContent(type="text", text="""
# Clouvel Pro Feature

Error Learning requires a Pro license.

## Purchase
https://polar.sh/clouvel
""")]
    return await error_learn(
        path=args.get("path", ""),
        auto_update_claude_md=args.get("auto_update_claude_md", True),
        min_count=args.get("min_count", 2)
    )


async def _wrap_activate_license(args: dict) -> list[TextContent]:
    """activate_license tool wrapper"""
    license_key = args.get("license_key", "")
    if not license_key:
        return [TextContent(type="text", text="""
# ❌ Please enter license key

## Usage
```
activate_license(license_key="YOUR-LICENSE-KEY")
```

## Purchase
https://polar.sh/clouvel
""")]

    result = activate_license_cli(license_key)

    if result.get("success"):
        tier_info = result.get("tier_info", {})
        machine_id = result.get("machine_id", "unknown")
        product = result.get("product", "Clouvel Pro")

        # Test license extra info
        extra_info = ""
        if result.get("test_license"):
            expires_at = result.get("expires_at", "")
            expires_in_days = result.get("expires_in_days", 7)
            extra_info = f"""
## ⚠️ Test License
- **Expires**: {expires_at}
- **Days remaining**: {expires_in_days}
"""

        return [TextContent(type="text", text=f"""
# ✅ License Activated

## Info
- **Tier**: {tier_info.get('name', 'Unknown')}
- **Product**: {product}
- **Machine**: `{machine_id[:8]}...`
{extra_info}
## 🔒 Machine Binding

This license is bound to the current machine.
- Personal: Can only be used on 1 machine
- Team: Can be used on up to 10 machines
- Enterprise: Unlimited machines

To use on another machine, deactivate the existing machine or upgrade to a higher tier.
""")]
    else:
        return [TextContent(type="text", text=f"""
# ❌ License Activation Failed

{result.get('message', 'Unknown error')}

## Checklist
- Verify license key is correct
- Check network connection
- Check activation limit (Personal: 1)

## Purchase
https://polar.sh/clouvel
""")]


async def _wrap_license_status() -> list[TextContent]:
    """license_status tool wrapper"""
    result = get_license_status()

    if not result.get("has_license"):
        return [TextContent(type="text", text=f"""
# 📋 License Status

**Status**: ❌ Not activated

{result.get('message', '')}

## How to activate
```
activate_license(license_key="YOUR-LICENSE-KEY")
```

## Purchase
https://polar.sh/clouvel
""")]

    tier_info = result.get("tier_info", {})
    machine_id = result.get("machine_id", "unknown")
    activated_at = result.get("activated_at", "N/A")
    days = result.get("days_since_activation", 0)
    premium_unlocked = result.get("premium_unlocked", False)
    remaining = result.get("premium_unlock_remaining", 0)

    unlock_status = "✅ Unlocked" if premium_unlocked else f"⏳ {remaining} days remaining"

    return [TextContent(type="text", text=f"""
# 📋 License Status

**Status**: ✅ Activated

## Info
- **Tier**: {tier_info.get('name', 'Unknown')} ({tier_info.get('price', '?')})
- **Machine**: `{machine_id[:8]}...`
- **Activated at**: {activated_at[:19] if len(activated_at) > 19 else activated_at}
- **Days since activation**: {days}
- **Premium features**: {unlock_status}
""")]


async def _upgrade_pro() -> list[TextContent]:
    """Pro upgrade guide"""
    return [TextContent(type="text", text="""
# Clouvel Pro

For more powerful features, check out Clouvel Pro.

## Pro Features

### Shovel Auto-Install
- Auto-generate `.claude/` workflow structure
- Slash commands (/start, /plan, /gate...)
- Config files + templates

### Error Learning
- Auto-classify error patterns
- Auto-generate prevention rules
- Log file monitoring

### Command Sync
- Shovel command updates

## Pricing

| Tier | Price | Users |
|------|-------|-------|
| Personal | $29 | 1 |
| Team | $79 | 10 |
| Enterprise | $199 | Unlimited |

## Purchase

https://polar.sh/clouvel

## Install

```bash
pip install clouvel-pro
```
""")]


@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    global _version_check_done

    # 첫 호출 시 버전 체크 (어떤 도구든)
    if not _version_check_done:
        _check_version_once()

    # Analytics 기록
    project_path = arguments.get("path", None)
    if name != "get_analytics":
        try:
            log_tool_call(name, success=True, project_path=project_path)
        except Exception:
            pass

    # get_analytics 특별 처리
    if name == "get_analytics":
        return await _get_analytics(arguments.get("path", None), arguments.get("days", 30))

    # 핸들러 실행
    handler = TOOL_HANDLERS.get(name)
    if handler:
        result = await handler(arguments)

        # 첫 호출이고 업데이트 있으면 배너 추가
        update_info = get_cached_update_info()
        if update_info and update_info.get("update_available"):
            banner = get_update_banner()
            if banner and result and len(result) > 0:
                # 첫 번째 결과에 배너 prepend
                original_text = result[0].text if hasattr(result[0], 'text') else str(result[0])
                result[0] = TextContent(type="text", text=banner + "\n" + original_text)
                # 배너는 한 번만 표시
                update_info["update_available"] = False

        return result

    return [TextContent(type="text", text=f"Unknown tool: {name}")]


async def _get_analytics(path: str, days: int) -> list[TextContent]:
    """Tool usage statistics"""
    stats = get_stats(days=days, project_path=path)
    return [TextContent(type="text", text=format_stats(stats))]


# ============================================================
# Server Entry Points
# ============================================================

async def run_server():
    async with stdio_server() as (read_stream, write_stream):
        await server.run(read_stream, write_stream, server.create_initialization_options())


def _run_setup(global_only: bool = False, hooks: bool = False) -> str:
    """B0: clouvel setup - install forced invocation mechanism"""
    import subprocess
    import os
    from pathlib import Path

    results = []

    # --hooks: Install pre-commit hooks in current project
    if hooks:
        git_hooks_dir = Path(".git/hooks")
        if git_hooks_dir.exists():
            pre_commit = git_hooks_dir / "pre-commit"
            pre_commit_content = '''#!/bin/bash
# Clouvel pre-commit hook (v1.5)
# 1. PRD check
# 2. Record files check (files/created.md, status/current.md)
# 3. Sensitive files check

# === PRD Check ===
DOCS_DIR="./docs"
if ! ls "$DOCS_DIR"/*[Pp][Rr][Dd]* 1> /dev/null 2>&1; then
    echo "[Clouvel] BLOCKED: No PRD document found."
    echo "Please create docs/PRD.md first."
    exit 1
fi

# === Record Files Check (v1.5) ===
if [ ! -f ".claude/files/created.md" ]; then
    echo ""
    echo "========================================"
    echo "[Clouvel] BLOCKED: files/created.md missing"
    echo "========================================"
    echo ""
    echo "No file creation record found."
    echo "Fix: Create .claude/files/created.md before commit"
    echo ""
    exit 1
fi

if [ ! -f ".claude/status/current.md" ]; then
    echo ""
    echo "========================================"
    echo "[Clouvel] BLOCKED: status/current.md missing"
    echo "========================================"
    echo ""
    echo "No work status record found."
    echo "Fix: Create .claude/status/current.md before commit"
    echo ""
    exit 1
fi

# === Security Check (sensitive files) ===
SENSITIVE_PATTERNS="(marketing|strategy|pricing|server_pro|_pro\\.py|\\.key$|\\.secret$|credentials|password)"

SENSITIVE_FILES=$(git diff --cached --name-only | grep -iE "$SENSITIVE_PATTERNS" 2>/dev/null)

if [ -n "$SENSITIVE_FILES" ]; then
    echo ""
    echo "========================================"
    echo "[Clouvel] SECURITY BLOCK: Sensitive files detected!"
    echo "========================================"
    echo ""
    echo "Cannot commit these files:"
    echo "$SENSITIVE_FILES" | while read -r file; do
        echo "  ❌ $file"
    done
    echo ""
    echo "Fix: git reset HEAD <filename>"
    echo "Skip: git commit --no-verify (not recommended)"
    echo ""
    exit 1
fi

echo "[Clouvel] All checks passed. ✓"
'''
            pre_commit.write_text(pre_commit_content, encoding='utf-8')
            try:
                os.chmod(pre_commit, 0o755)
            except:
                pass
            results.append(f"[OK] Pre-commit hook installed: {pre_commit}")
            return "\n".join(results)
        else:
            return "[ERROR] .git/hooks not found. Run from git repository root."

    # 1. Add rules to global CLAUDE.md
    if os.name == 'nt':  # Windows
        claude_dir = Path.home() / ".claude"
    else:  # Mac/Linux
        claude_dir = Path.home() / ".claude"

    claude_dir.mkdir(parents=True, exist_ok=True)
    claude_md_path = claude_dir / "CLAUDE.md"

    clouvel_rule = """
## Clouvel Rules (Auto-generated)

**Must call clouvel's `can_code` tool before writing code.**

- Always call `can_code` tool before writing code (Edit/Write)
- Pass the project's docs folder path as the path argument
- If BLOCK appears, do not write code, guide user to write documentation
- If PASS appears, proceed with coding
- WARN is a recommendation, can proceed but suggest adding recommended docs

"""

    marker = "## Clouvel Rules"
    marker_ko = "## Clouvel 규칙"

    if claude_md_path.exists():
        content = claude_md_path.read_text(encoding='utf-8')
        if marker in content or marker_ko in content:
            results.append("[OK] Global CLAUDE.md: Clouvel rules already exist")
        else:
            # Append to existing content
            new_content = content.rstrip() + "\n\n---\n" + clouvel_rule
            claude_md_path.write_text(new_content, encoding='utf-8')
            results.append(f"[OK] Global CLAUDE.md: Rules added ({claude_md_path})")
    else:
        # Create new
        initial_content = f"# Claude Code Global Settings\n\n> Auto-generated by clouvel setup\n\n---\n{clouvel_rule}"
        claude_md_path.write_text(initial_content, encoding='utf-8')
        results.append(f"[OK] Global CLAUDE.md: Created ({claude_md_path})")

    # 2. Register MCP server (only when not global_only)
    if not global_only:
        try:
            # First check existing registration
            check_result = subprocess.run(
                ["claude", "mcp", "list"],
                capture_output=True,
                text=True,
                timeout=10
            )

            if "clouvel" in check_result.stdout:
                results.append("[OK] MCP Server: Already registered")
            else:
                # Register
                add_result = subprocess.run(
                    ["claude", "mcp", "add", "clouvel", "-s", "user", "--", "clouvel"],
                    capture_output=True,
                    text=True,
                    timeout=30
                )

                if add_result.returncode == 0:
                    results.append("[OK] MCP Server: Registration complete")
                else:
                    results.append(f"[WARN] MCP Server: Registration failed - {add_result.stderr.strip()}")
                    results.append("   Manual registration: claude mcp add clouvel -s user -- clouvel")
        except FileNotFoundError:
            results.append("[WARN] MCP Server: claude command not found")
            results.append("   Please install Claude Code and try again")
        except subprocess.TimeoutExpired:
            results.append("[WARN] MCP Server: Timeout")
            results.append("   Manual registration: claude mcp add clouvel -s user -- clouvel")
        except Exception as e:
            results.append(f"[WARN] MCP Server: Error - {str(e)}")
            results.append("   Manual registration: claude mcp add clouvel -s user -- clouvel")

    # Output results
    output = """
================================================================
                    Clouvel Setup Complete
================================================================

"""
    output += "\n".join(results)
    output += """

----------------------------------------------------------------

## How It Works

1. Run Claude Code
2. Request "Build a login feature"
3. Claude automatically calls can_code first
4. No PRD -> [BLOCK] BLOCK (coding blocked)
5. PRD exists -> [OK] PASS (proceed with coding)

## Test

```bash
# Test in a folder without PRD
mkdir test-project && cd test-project
claude
> "Write some code"
# -> Verify BLOCK message
```

----------------------------------------------------------------
"""

    return output


def main():
    import sys
    import asyncio
    import argparse
    from pathlib import Path

    parser = argparse.ArgumentParser(description="Clouvel - Vibe coding process enforcement tool")
    subparsers = parser.add_subparsers(dest="command")

    # init command
    init_parser = subparsers.add_parser("init", help="Initialize project")
    init_parser.add_argument("-p", "--path", default=".", help="Project path")
    init_parser.add_argument("-l", "--level", choices=["remind", "strict", "full"], default="strict")

    # setup command (B0) - legacy, install recommended
    setup_parser = subparsers.add_parser("setup", help="Install Clouvel forced invocation mechanism (global)")
    setup_parser.add_argument("--global-only", action="store_true", help="Configure CLAUDE.md only (exclude MCP registration)")
    setup_parser.add_argument("--hooks", action="store_true", help="Install pre-commit hooks for record enforcement")

    # install command (new, recommended)
    install_parser = subparsers.add_parser("install", help="Install Clouvel MCP server (recommended)")
    install_parser.add_argument("--platform", choices=["auto", "code", "desktop", "cursor", "all"], default="auto", help="Target platform for installation")
    install_parser.add_argument("--force", action="store_true", help="Reinstall even if already installed")

    # activate command (license activation)
    activate_parser = subparsers.add_parser("activate", help="Activate license")
    activate_parser.add_argument("license_key", help="License key")

    # status command (license status)
    status_parser = subparsers.add_parser("status", help="Check license status")

    # deactivate command (license deactivation)
    deactivate_parser = subparsers.add_parser("deactivate", help="Deactivate license (delete local cache)")

    args = parser.parse_args()

    if args.command == "init":
        from .tools.setup import setup_cli as sync_setup
        import asyncio
        result = asyncio.run(sync_setup(args.path, args.level))
        print(result[0].text)
    elif args.command == "setup":
        result = _run_setup(
            global_only=args.global_only if hasattr(args, 'global_only') else False,
            hooks=args.hooks if hasattr(args, 'hooks') else False
        )
        print(result)
    elif args.command == "install":
        from .tools.install import run_install
        result = run_install(
            platform=args.platform if hasattr(args, 'platform') else "auto",
            force=args.force if hasattr(args, 'force') else False
        )
        print(result)
    elif args.command == "activate":
        try:
            from .license import activate_license_cli
        except ImportError:
            from .license_free import activate_license_cli
        result = activate_license_cli(args.license_key)
        if result["success"]:
            print(f"""
================================================================
              Clouvel Pro License Activated
================================================================

{result['message']}

Tier: {result.get('tier_info', {}).get('name', 'Unknown')}
Machine: {result.get('machine_id', 'Unknown')[:8]}...
Product: {result.get('product', 'Clouvel Pro')}

----------------------------------------------------------------
Premium features will be available 7 days after activation.
Check status with 'clouvel status'.
================================================================
""")
        else:
            print(result["message"])
            sys.exit(1)
    elif args.command == "status":
        try:
            from .license import get_license_status
        except ImportError:
            from .license_free import get_license_status
        result = get_license_status()
        if result.get("has_license"):
            tier_info = result.get("tier_info", {})
            unlock_status = "✅ Unlocked" if result.get("premium_unlocked") else f"⏳ {result.get('premium_unlock_remaining', '?')} days remaining"
            print(f"""
================================================================
                   Clouvel License Status
================================================================

Status: ✅ Activated
Tier: {tier_info.get('name', 'Unknown')} ({tier_info.get('price', '?')})
Machine: {result.get('machine_id', 'Unknown')[:8]}...

Activated at: {result.get('activated_at', 'N/A')[:19]}
Days since activation: {result.get('days_since_activation', 0)}
Premium features: {unlock_status}

================================================================
""")
        else:
            print(f"""
================================================================
                   Clouvel License Status
================================================================

Status: ❌ Not activated

{result.get('message', '')}

Purchase: https://polar.sh/clouvel
================================================================
""")
    elif args.command == "deactivate":
        try:
            from .license import deactivate_license_cli
        except ImportError:
            from .license_free import deactivate_license_cli
        result = deactivate_license_cli()
        print(result["message"])
        if not result["success"]:
            sys.exit(1)
    else:
        asyncio.run(run_server())


if __name__ == "__main__":
    main()
