# =============================================================================
# Import Linter Configuration
# =============================================================================
# Enforces architectural boundaries between modules to maintain clean layering.
# Run with: lint-imports
# =============================================================================

[importlinter]
root_packages = 
    mcp_coder
    tests
root_package_paths = 
    src
    .
# Enable checking of third-party/external package imports
include_external_packages = True

# -----------------------------------------------------------------------------
# Contract: Layered Architecture
# -----------------------------------------------------------------------------
# Ensures dependencies flow downward through the architecture:
#   cli -> workflows -> llm -> utils -> config
#
# Why this matters:
# - Prevents circular dependencies between modules
# - Keeps the CLI as a thin presentation layer
# - Ensures workflows orchestrate but don't leak into infrastructure
# - Maintains utils as reusable, independent components
#
# -----------------------------------------------------------------------------
[importlinter:contract:layered_architecture]
name = Layered Architecture
type = layers
layers =
    mcp_coder.cli | mcp_coder.icoder
    mcp_coder.workflows
    mcp_coder.checks
    mcp_coder.workflow_utils
    mcp_coder.llm | mcp_coder.prompt_manager
    mcp_coder.utils | mcp_coder.mcp_tools_py
    mcp_coder.config | mcp_coder.constants
ignore_imports =
    mcp_coder.cli.commands.icoder -> mcp_coder.icoder.ui.app
    mcp_coder.cli.commands.icoder -> mcp_coder.icoder.services.llm_service
    mcp_coder.cli.commands.icoder -> mcp_coder.icoder.core.app_core
    mcp_coder.cli.commands.icoder -> mcp_coder.icoder.core.event_log
    mcp_coder.cli.commands.icoder -> mcp_coder.icoder.env_setup
    mcp_coder.cli.commands.icoder -> mcp_coder.icoder.core.command_registry
    mcp_coder.cli.commands.icoder -> mcp_coder.icoder.skills

# -----------------------------------------------------------------------------
# Contract: External Service Integrations Independence
# -----------------------------------------------------------------------------
# GitHub and Jenkins integrations should not depend on each other.
# They are separate external services with independent APIs.
#
# Why this matters:
# - Allows using one service without the other
# - Keeps external service integrations focused
# - Easier to add new integrations without entangling existing ones
# -----------------------------------------------------------------------------
[importlinter:contract:external_services]
name = External Service Integrations Independence
type = independence
modules =
    mcp_coder.utils.github_operations
    mcp_coder.utils.jenkins_operations

# -----------------------------------------------------------------------------
# Contract: Git Operations Local Independence
# -----------------------------------------------------------------------------
# Local git operations should not depend on remote service integrations.
# Git operations work with the local repository only.
#
# Why this matters:
# - Keeps git operations usable offline
# - Maintains clear separation between local and remote operations
# - Allows testing git operations without network mocking
# -----------------------------------------------------------------------------
[importlinter:contract:git_local]
name = Git Operations Local Independence
type = forbidden
source_modules =
    mcp_coder.utils.git_operations
forbidden_modules =
    mcp_coder.utils.github_operations
    mcp_coder.utils.jenkins_operations

# -----------------------------------------------------------------------------
# Contract: Git Operations Internal Layering
# -----------------------------------------------------------------------------
# Enforces the internal layering within git_operations:
# - Orchestration layer (workflows) can import from any git_operations module
# - Command modules (branches, remotes, commits, staging, file_tracking, diffs)
#   can import from branch_queries, parent_branch_detection, repository_status, and core
# - Reader sub-modules (branch_queries, parent_branch_detection) depend on repository_status and core
# - No imports between modules in the same layer
#
# Architecture:
#   Layer 0: workflows (orchestration)
#   Layer 1: branches | remotes | commits | staging | file_tracking | diffs
#   Layer 2: branch_queries | parent_branch_detection (depend on repository_status)
#   Layer 3: repository_status (foundational read-only checks)
#   Layer 4: core
#
# Note on sub-layers (Layer 2/3): When splitting a large module (e.g. readers.py)
# into smaller files, the split modules may depend on each other. Use sub-layers
# to model this: put the dependency (repository_status) on a lower layer than its
# consumers (branch_queries, parent_branch_detection). Pipe (|) enforces
# independence between siblings; separate lines enforce direction.
# -----------------------------------------------------------------------------
[importlinter:contract:git_operations_internal_layering]
name = Git Operations Internal Layering
type = layers
layers =
    mcp_coder.utils.git_operations.workflows
    mcp_coder.utils.git_operations.branches | mcp_coder.utils.git_operations.remotes | mcp_coder.utils.git_operations.commits | mcp_coder.utils.git_operations.staging | mcp_coder.utils.git_operations.file_tracking | mcp_coder.utils.git_operations.diffs
    mcp_coder.utils.git_operations.branch_queries | mcp_coder.utils.git_operations.parent_branch_detection
    mcp_coder.utils.git_operations.repository_status
    mcp_coder.utils.git_operations.core

# -----------------------------------------------------------------------------
# Contract: Jenkins Operations Independence
# -----------------------------------------------------------------------------
# Jenkins operations should not depend on git or github operations.
# Jenkins is a CI/CD service that works via its own API.
#
# Why this matters:
# - Jenkins integration can be used/tested independently
# - Prevents coupling between unrelated external services
# - Keeps the jenkins module focused on CI/CD concerns only
# -----------------------------------------------------------------------------
[importlinter:contract:jenkins_independence]
name = Jenkins Operations Independence
type = forbidden
source_modules =
    mcp_coder.utils.jenkins_operations
forbidden_modules =
    mcp_coder.utils.git_operations
    mcp_coder.utils.github_operations

# -----------------------------------------------------------------------------
# Contract: MLflow Logger No Import Cycles
# -----------------------------------------------------------------------------
# Prevents mlflow_logger from importing modules that depend on it.
# Used by: logging_utils (LLM metrics), prompt (conversations).
# -----------------------------------------------------------------------------
[importlinter:contract:mlflow_logger_no_cycles]
name = MLflow Logger No Import Cycles
type = forbidden
source_modules =
    mcp_coder.llm.mlflow_logger
forbidden_modules =
    mcp_coder.llm.providers.claude.logging_utils
    mcp_coder.cli.commands.prompt


# =============================================================================
# THIRD-PARTY LIBRARY ISOLATION CONTRACTS
# =============================================================================
# These contracts ensure that specific third-party libraries are only used
# by the modules that are responsible for integrating with them.
#
# Why this matters:
# - Prevents library-specific code from spreading across the codebase
# - Makes it easier to swap out libraries (e.g., PyGithub -> ghapi)
# - Keeps external API knowledge contained in dedicated modules
# - Simplifies testing by limiting where mocking is needed
# =============================================================================

# -----------------------------------------------------------------------------
# Contract: GitHub Library Isolation
# -----------------------------------------------------------------------------
# The 'github' package (PyGithub) should only be imported by github_operations.
# All other modules must use github_operations as an abstraction layer.
#
# Syntax: mcp_coder.** means "all submodules recursively"
#         ignore_imports allows specific exceptions using wildcards
# -----------------------------------------------------------------------------
[importlinter:contract:github_library_isolation]
name = GitHub Library Isolation
type = forbidden
# source_modules: which modules are checked (mcp_coder = all production code)
source_modules =
    mcp_coder
# forbidden_modules: which external packages are forbidden
forbidden_modules =
    github
# ignore_imports: exceptions - github_operations.** can import github
ignore_imports =
    mcp_coder.utils.github_operations.** -> github

# -----------------------------------------------------------------------------
# Contract: GitPython Library Isolation
# -----------------------------------------------------------------------------
# The 'git' package (GitPython) should only be imported by git_operations.
# Other modules should use git_operations as an abstraction layer.
# -----------------------------------------------------------------------------
[importlinter:contract:git_library_isolation]
name = GitPython Library Isolation
type = forbidden
source_modules =
    mcp_coder
forbidden_modules =
    git
ignore_imports =
    mcp_coder.utils.git_operations.** -> git

# -----------------------------------------------------------------------------
# Contract: Jenkins Library Isolation
# -----------------------------------------------------------------------------
# The 'jenkins' package (python-jenkins) should only be used by jenkins_operations.
# -----------------------------------------------------------------------------
[importlinter:contract:jenkins_library_isolation]
name = Jenkins Library Isolation
type = forbidden
source_modules =
    mcp_coder
forbidden_modules =
    jenkins
ignore_imports =
    mcp_coder.utils.jenkins_operations.** -> jenkins

# -----------------------------------------------------------------------------
# Contract: Claude Code SDK Isolation
# -----------------------------------------------------------------------------
# The 'claude_code_sdk' should only be used by llm.providers.claude.
# -----------------------------------------------------------------------------
[importlinter:contract:claude_sdk_isolation]
name = Claude Code SDK Isolation
type = forbidden
source_modules =
    mcp_coder
forbidden_modules =
    claude_code_sdk
ignore_imports =
    mcp_coder.llm.providers.claude.** -> claude_code_sdk

# -----------------------------------------------------------------------------
# Contract: LangChain Library Isolation
# -----------------------------------------------------------------------------
# langchain_core, langchain_openai, langchain_google_genai are optional
# dependencies. Only the langchain provider package may import them.
# Same pattern as claude_sdk_isolation.
# -----------------------------------------------------------------------------
[importlinter:contract:langchain_library_isolation]
name = LangChain Library Isolation
type = forbidden
source_modules =
    mcp_coder
forbidden_modules =
    langchain_core
    langchain_openai
    langchain_google_genai
    langchain_anthropic
ignore_imports =
    mcp_coder.llm.providers.langchain -> langchain_core
    mcp_coder.llm.providers.langchain.** -> langchain_core
    mcp_coder.llm.providers.langchain.** -> langchain_openai
    mcp_coder.llm.providers.langchain.** -> langchain_google_genai
    mcp_coder.llm.providers.langchain.** -> langchain_anthropic

# -----------------------------------------------------------------------------
# Contract: LangChain Vendor SDK Isolation
# -----------------------------------------------------------------------------
# The raw vendor SDKs (openai, google.genai, anthropic) are transitive
# dependencies of the langchain extras. Only the langchain provider package
# may import them (for model-listing on NOT_FOUND errors in _models.py).
# Same boundary as the LangChain wrapper libraries above.
# -----------------------------------------------------------------------------
[importlinter:contract:langchain_vendor_sdk_isolation]
name = LangChain Vendor SDK Isolation
type = forbidden
source_modules =
    mcp_coder
forbidden_modules =
    openai
    anthropic
ignore_imports =
    mcp_coder.llm.providers.langchain.** -> openai
    mcp_coder.llm.providers.langchain.** -> anthropic

# -----------------------------------------------------------------------------
# Contract: Pyperclip Library Isolation
# -----------------------------------------------------------------------------
# The 'pyperclip' package should only be used by utils.clipboard.
# -----------------------------------------------------------------------------
[importlinter:contract:pyperclip_isolation]
name = Pyperclip Library Isolation
type = forbidden
source_modules =
    mcp_coder
forbidden_modules =
    pyperclip
ignore_imports =
    mcp_coder.utils.clipboard -> pyperclip

# -----------------------------------------------------------------------------
# Contract: MCP Tools Py Isolation
# -----------------------------------------------------------------------------
# The 'mcp_tools_py' external package should only be used by mcp_tools_py module.
# -----------------------------------------------------------------------------
[importlinter:contract:mcp_checker_isolation]
name = MCP Tools Py Isolation
type = forbidden
source_modules =
    mcp_coder
forbidden_modules =
    mcp_tools_py
ignore_imports =
    mcp_coder.mcp_tools_py -> mcp_tools_py

# -----------------------------------------------------------------------------
# Contract: Requests Library Isolation
# -----------------------------------------------------------------------------
# The 'requests' library should only be used in github_operations.
# -----------------------------------------------------------------------------
[importlinter:contract:requests_library_isolation]
name = Requests Library Isolation
type = forbidden
source_modules =
    mcp_coder
forbidden_modules =
    requests
ignore_imports =
    mcp_coder.utils.github_operations.** -> requests
    mcp_coder.utils.jenkins_operations.client -> requests

# -----------------------------------------------------------------------------
# Contract: Structlog Library Isolation
# -----------------------------------------------------------------------------
# The 'structlog' library should only be used by log_utils.
# Other modules should use log_utils for logging setup.
# -----------------------------------------------------------------------------
[importlinter:contract:structlog_isolation]
name = Structlog Library Isolation
type = forbidden
source_modules =
    mcp_coder
forbidden_modules =
    structlog
ignore_imports =
    mcp_coder.utils.log_utils -> structlog

# -----------------------------------------------------------------------------
# Contract: Python JSON Logger Isolation
# -----------------------------------------------------------------------------
# The 'pythonjsonlogger' should only be used by log_utils.
# -----------------------------------------------------------------------------
[importlinter:contract:jsonlogger_isolation]
name = Python JSON Logger Isolation
type = forbidden
source_modules =
    mcp_coder
forbidden_modules =
    pythonjsonlogger
ignore_imports =
    mcp_coder.utils.log_utils -> pythonjsonlogger

# -----------------------------------------------------------------------------
# Contract: Black Library Isolation
# -----------------------------------------------------------------------------
# Only mcp-tools-py should import black directly; guard against future
# direct imports in mcp_coder.
# -----------------------------------------------------------------------------
[importlinter:contract:black_isolation]
name = Black Library Isolation
type = forbidden
source_modules =
    mcp_coder
forbidden_modules =
    black

# -----------------------------------------------------------------------------
# Contract: Isort Library Isolation
# -----------------------------------------------------------------------------
# Only mcp-tools-py should import isort directly; guard against future
# direct imports in mcp_coder.
# -----------------------------------------------------------------------------
[importlinter:contract:isort_isolation]
name = Isort Library Isolation
type = forbidden
source_modules =
    mcp_coder
forbidden_modules =
    isort


# -----------------------------------------------------------------------------
# Contract: Textual Library Isolation
# -----------------------------------------------------------------------------
# The 'textual' library should only be used by icoder.ui.
# Other modules must not depend on the TUI framework directly.
# -----------------------------------------------------------------------------
[importlinter:contract:textual_library_isolation]
name = Textual Library Isolation
type = forbidden
source_modules =
    mcp_coder
forbidden_modules =
    textual
ignore_imports =
    mcp_coder.icoder.ui.** -> textual

# =============================================================================
# TEST MODULE CONTRACTS
# =============================================================================
# These contracts enforce that:
# - Source modules never import from tests (no test dependencies in production)
# - Test modules remain isolated from each other (test independence)
# - Unit tests focus on their target module (test focus)
# =============================================================================

# -----------------------------------------------------------------------------
# Contract: Source Code Independence from Tests
# -----------------------------------------------------------------------------
# Production code should never import from test modules.
# This prevents test code from leaking into production.
#
# Why this matters:
# - Tests are not deployed to production
# - Prevents accidental test dependencies in release builds
# - Keeps production code independent and testable
# -----------------------------------------------------------------------------
[importlinter:contract:no_test_imports_in_source]
name = Source Code Independence from Tests
type = forbidden
source_modules =
    mcp_coder
forbidden_modules =
    tests

# -----------------------------------------------------------------------------
# Contract: Test Module Independence
# -----------------------------------------------------------------------------
# Test directories should not import from each other.
# Each test module should be independent and self-contained.
#
# Why this matters:
# - Prevents test interdependencies that make debugging harder
# - Allows running test subsets without failures from missing test imports
# - Keeps test modules focused on their target
#
# Note: tests.conftest is allowed as shared fixtures, but direct cross-imports
#       between test subdirectories should be avoided.
# -----------------------------------------------------------------------------
[importlinter:contract:test_module_independence]
name = Test Module Independence
type = independence
modules =
    tests.cli
    tests.llm
    tests.utils
    tests.workflows
    tests.workflow_utils
    tests.checks
    tests.icoder
# Allowed: Importing shared fixtures from tests.utils.conftest
# TODO: Refactor to use pytest's conftest discovery instead of explicit imports
ignore_imports =
    tests.workflows.test_create_pr_integration -> tests.utils.conftest
    tests.cli.commands.test_define_labels -> tests.utils.conftest

# -----------------------------------------------------------------------------
# Contract: CLI Tests Focus (commented - has violations)
# -----------------------------------------------------------------------------
# CLI tests should primarily import from mcp_coder.cli and shared test fixtures.
# They should not reach deep into other modules.
#
# Why this matters:
# - Keeps CLI tests focused on CLI behavior
# - Prevents CLI tests from becoming integration tests
# - Makes test failures easier to diagnose
#
# Note: Commented out because tests currently import widely for fixtures.
#       Enable after refactoring tests to use proper mocking.
# -----------------------------------------------------------------------------
# [importlinter:contract:cli_test_focus]
# name = CLI Tests Focus
# type = forbidden
# source_modules =
#     tests.cli
# forbidden_modules =
#     mcp_coder.workflows
#     mcp_coder.llm.providers

# -----------------------------------------------------------------------------
# Contract: Utils Tests Should Not Import Application Layer (commented - has violations)
# -----------------------------------------------------------------------------
# Utils tests should test infrastructure without depending on application logic.
#
# Why this matters:
# - Utils are infrastructure, tested independently
# - Application layer changes shouldn't break utils tests
# - Enforces proper layering even in tests
# -----------------------------------------------------------------------------
# [importlinter:contract:utils_test_layering]
# name = Utils Tests Layering
# type = forbidden
# source_modules =
#     tests.utils
# forbidden_modules =
#     mcp_coder.cli
#     mcp_coder.workflows


# -----------------------------------------------------------------------------
# Contract: Subprocess Library Isolation
# -----------------------------------------------------------------------------
# The 'subprocess' module should only be used by subprocess_runner.
# All other modules must use subprocess_runner as an abstraction layer.
# This is the first library isolation contract enforced in tests as well.
# -----------------------------------------------------------------------------
[importlinter:contract:subprocess_isolation]
name = Subprocess Library Isolation
type = forbidden
source_modules =
    mcp_coder
    tests
forbidden_modules =
    subprocess
ignore_imports =
    mcp_coder.utils.subprocess_runner -> subprocess
    mcp_coder.utils.subprocess_streaming -> subprocess
    tests.utils.test_subprocess_runner -> subprocess
    tests.utils.test_subprocess_runner_real -> subprocess
    mcp_coder.utils.mcp_verification -> subprocess
    tests.utils.test_mcp_verification -> subprocess
