mcp-ticketer 0.1.28__tar.gz → 0.1.29__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mcp-ticketer might be problematic. Click here for more details.

Files changed (232) hide show
  1. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/CHANGELOG.md +35 -0
  2. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/PKG-INFO +1 -1
  3. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/__version__.py +1 -1
  4. mcp_ticketer-0.1.29/src/mcp_ticketer/cli/diagnostics.py +492 -0
  5. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/cli/main.py +43 -0
  6. mcp_ticketer-0.1.29/src/mcp_ticketer/cli/simple_health.py +219 -0
  7. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/mcp/server.py +217 -0
  8. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer.egg-info/PKG-INFO +1 -1
  9. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer.egg-info/SOURCES.txt +2 -0
  10. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/.dependency_cache +0 -0
  11. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/.mpm_deployment_state +0 -0
  12. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/agent-manager.md +0 -0
  13. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/agentic-coder-optimizer.md +0 -0
  14. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/api_qa.md +0 -0
  15. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/clerk-ops.md +0 -0
  16. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/code_analyzer.md +0 -0
  17. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/content-agent.md +0 -0
  18. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/dart_engineer.md +0 -0
  19. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/data_engineer.md +0 -0
  20. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/documentation.md +0 -0
  21. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/engineer.md +0 -0
  22. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/gcp_ops_agent.md +0 -0
  23. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/golang_engineer.md +0 -0
  24. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/imagemagick.md +0 -0
  25. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/java_engineer.md +0 -0
  26. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/local_ops_agent.md +0 -0
  27. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/memory_manager.md +0 -0
  28. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/nextjs_engineer.md +0 -0
  29. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/ops.md +0 -0
  30. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/php-engineer.md +0 -0
  31. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/product_owner.md +0 -0
  32. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/project_organizer.md +0 -0
  33. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/prompt-engineer.md +0 -0
  34. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/python_engineer.md +0 -0
  35. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/qa.md +0 -0
  36. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/react_engineer.md +0 -0
  37. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/refactoring_engineer.md +0 -0
  38. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/research.md +0 -0
  39. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/ruby-engineer.md +0 -0
  40. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/rust_engineer.md +0 -0
  41. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/security.md +0 -0
  42. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/ticketing.md +0 -0
  43. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/typescript_engineer.md +0 -0
  44. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/vercel_ops_agent.md +0 -0
  45. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/version_control.md +0 -0
  46. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/web_qa.md +0 -0
  47. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/agents/web_ui.md +0 -0
  48. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/mcp.json +0 -0
  49. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude/mcp.local.json +0 -0
  50. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude-mpm/config/project.json +0 -0
  51. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude-mpm/mcp_auto_config_preference.json +0 -0
  52. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude-mpm/memories/README.md +0 -0
  53. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude-mpm/memories/agentic_coder_optimizer_memories.md +0 -0
  54. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude-mpm/memories/documentation_memories.md +0 -0
  55. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude-mpm/memories/engineer_memories.md +0 -0
  56. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude-mpm/memories/ops_memories.md +0 -0
  57. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude-mpm/memories/project_knowledge_memories.md +0 -0
  58. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude-mpm/memories/qa_memories.md +0 -0
  59. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude-mpm/memories/research_memories.md +0 -0
  60. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude-mpm/memories/version-control_memories.md +0 -0
  61. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude-mpm/memories/workflows_memories.md +0 -0
  62. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.claude.json +0 -0
  63. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.coveragerc +0 -0
  64. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.env.example +0 -0
  65. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.github/workflows/docs.yml +0 -0
  66. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.github/workflows/publish.yml +0 -0
  67. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.github/workflows/test.yml +0 -0
  68. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.mcp/config.json +0 -0
  69. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.pre-commit-config.yaml +0 -0
  70. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.python-version +0 -0
  71. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/.readthedocs.yaml +0 -0
  72. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/CLAUDE.md +0 -0
  73. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/CLAUDE_DESKTOP_SETUP.md +0 -0
  74. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/CODEX_INTEGRATION.md +0 -0
  75. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/CODE_STRUCTURE.md +0 -0
  76. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/CONFIG_RESOLUTION_FIX.md +0 -0
  77. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/CONTRIBUTING.md +0 -0
  78. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/CREDENTIAL_VALIDATION_FIX.md +0 -0
  79. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/ENV_DISCOVERY_COMPLETE.md +0 -0
  80. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/FIX_SUMMARY.md +0 -0
  81. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/HIERARCHY_IMPLEMENTATION_SUMMARY.md +0 -0
  82. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/IMPLEMENTATION_SUMMARY.md +0 -0
  83. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/JIRA_SETUP.md +0 -0
  84. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/LICENSE +0 -0
  85. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/LINEAR_SETUP.md +0 -0
  86. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/MANIFEST.in +0 -0
  87. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/MCP_CONFIGURATION_TEST_REPORT.md +0 -0
  88. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/Makefile +0 -0
  89. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/OPTIMIZATION_SUMMARY.md +0 -0
  90. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/PROJECT_INITIALIZATION_SUMMARY.md +0 -0
  91. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/QUEUE_SYSTEM.md +0 -0
  92. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/QUICK_START.md +0 -0
  93. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/README.md +0 -0
  94. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/RELEASE.md +0 -0
  95. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/RELEASING.md +0 -0
  96. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/SECURITY_SCAN_REPORT_v0.1.24.md +0 -0
  97. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/TEST_COVERAGE_REPORT.md +0 -0
  98. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/TEST_REPORT.md +0 -0
  99. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/TEST_RESULTS_SUMMARY.md +0 -0
  100. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/VERIFICATION_RESULTS.md +0 -0
  101. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/claude-desktop-config.json +0 -0
  102. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/debug_search.py +0 -0
  103. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/debug_test.py +0 -0
  104. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/ADAPTERS.md +0 -0
  105. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/AI_CLIENT_INTEGRATION.md +0 -0
  106. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/API_REFERENCE.md +0 -0
  107. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/CONFIGURATION.md +0 -0
  108. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/CONFIG_RESOLUTION_FLOW.md +0 -0
  109. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/DEVELOPER_GUIDE.md +0 -0
  110. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/ENV_DISCOVERY.md +0 -0
  111. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/MCP_INTEGRATION.md +0 -0
  112. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/MIGRATION_GUIDE.md +0 -0
  113. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/PROJECT_CONFIG.md +0 -0
  114. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/PR_INTEGRATION.md +0 -0
  115. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/QUICK_START_ENV.md +0 -0
  116. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/USER_GUIDE.md +0 -0
  117. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_archive/README.md +0 -0
  118. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/ADAPTERS.md.txt +0 -0
  119. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/API_REFERENCE.md.txt +0 -0
  120. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/CONFIGURATION.md.txt +0 -0
  121. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/DEVELOPER_GUIDE.md.txt +0 -0
  122. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/MCP_INTEGRATION.md.txt +0 -0
  123. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/MIGRATION_GUIDE.md.txt +0 -0
  124. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/USER_GUIDE.md.txt +0 -0
  125. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/adapters/github.md.txt +0 -0
  126. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/adapters.rst.txt +0 -0
  127. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/api.rst.txt +0 -0
  128. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/cli.rst.txt +0 -0
  129. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/development.rst.txt +0 -0
  130. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/examples.rst.txt +0 -0
  131. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/index.rst.txt +0 -0
  132. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/installation.rst.txt +0 -0
  133. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/_build/_sources/prd/mcp-ticketer-prd.md.txt +0 -0
  134. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/adapters/github.md +0 -0
  135. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/adapters.rst +0 -0
  136. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/api.rst +0 -0
  137. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/cli.rst +0 -0
  138. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/conf.py +0 -0
  139. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/development.rst +0 -0
  140. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/examples.rst +0 -0
  141. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/index.rst +0 -0
  142. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/installation.rst +0 -0
  143. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/prd/mcp-ticketer-prd.md +0 -0
  144. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/docs/requirements.txt +0 -0
  145. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/install.sh +0 -0
  146. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/mcp-ticketer +0 -0
  147. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/mcp-ticketer-server +0 -0
  148. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/mcp_server.sh +0 -0
  149. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/pyproject.toml +0 -0
  150. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/pytest.ini +0 -0
  151. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/requirements-dev.txt +0 -0
  152. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/requirements.txt +0 -0
  153. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/scripts/README.md +0 -0
  154. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/scripts/manage_version.py +0 -0
  155. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/setup.cfg +0 -0
  156. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/setup.py +0 -0
  157. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/__init__.py +0 -0
  158. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/adapters/__init__.py +0 -0
  159. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/adapters/aitrackdown.py +0 -0
  160. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/adapters/github.py +0 -0
  161. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/adapters/hybrid.py +0 -0
  162. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/adapters/jira.py +0 -0
  163. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/adapters/linear.py +0 -0
  164. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/cache/__init__.py +0 -0
  165. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/cache/memory.py +0 -0
  166. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/cli/__init__.py +0 -0
  167. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/cli/auggie_configure.py +0 -0
  168. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/cli/codex_configure.py +0 -0
  169. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/cli/configure.py +0 -0
  170. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/cli/discover.py +0 -0
  171. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/cli/gemini_configure.py +0 -0
  172. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/cli/mcp_configure.py +0 -0
  173. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/cli/migrate_config.py +0 -0
  174. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/cli/queue_commands.py +0 -0
  175. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/cli/utils.py +0 -0
  176. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/core/__init__.py +0 -0
  177. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/core/adapter.py +0 -0
  178. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/core/config.py +0 -0
  179. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/core/env_discovery.py +0 -0
  180. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/core/http_client.py +0 -0
  181. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/core/mappers.py +0 -0
  182. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/core/models.py +0 -0
  183. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/core/project_config.py +0 -0
  184. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/core/registry.py +0 -0
  185. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/mcp/__init__.py +0 -0
  186. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/py.typed +0 -0
  187. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/queue/__init__.py +0 -0
  188. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/queue/__main__.py +0 -0
  189. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/queue/health_monitor.py +0 -0
  190. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/queue/manager.py +0 -0
  191. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/queue/queue.py +0 -0
  192. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/queue/run_worker.py +0 -0
  193. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/queue/ticket_registry.py +0 -0
  194. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer/queue/worker.py +0 -0
  195. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer.egg-info/dependency_links.txt +0 -0
  196. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer.egg-info/entry_points.txt +0 -0
  197. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer.egg-info/not-zip-safe +0 -0
  198. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer.egg-info/requires.txt +0 -0
  199. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/src/mcp_ticketer.egg-info/top_level.txt +0 -0
  200. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test-tickets/tickets/task-20250924002724.json +0 -0
  201. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_all_adapters.py +0 -0
  202. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_api_usage.py +0 -0
  203. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_basic.py +0 -0
  204. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_codex_config.py +0 -0
  205. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_comprehensive.py +0 -0
  206. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_config_resolution.py +0 -0
  207. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_credential_validation.py +0 -0
  208. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_error_handling.py +0 -0
  209. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_github.py +0 -0
  210. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_github_token.py +0 -0
  211. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_jira.py +0 -0
  212. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_linear.py +0 -0
  213. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_linear_native.py +0 -0
  214. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_linear_teams.py +0 -0
  215. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_mcp_server_qa.py +0 -0
  216. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_optimizations.py +0 -0
  217. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_performance.py +0 -0
  218. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_pr_functionality.py +0 -0
  219. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_queue_system.py +0 -0
  220. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_serve_config.py +0 -0
  221. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/test_set_command.sh +0 -0
  222. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/tests/adapters/__init__.py +0 -0
  223. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/tests/adapters/test_aitrackdown.py +0 -0
  224. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/tests/conftest.py +0 -0
  225. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/tests/core/test_env_discovery.py +0 -0
  226. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/tests/e2e/test_complete_workflow.py +0 -0
  227. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/tests/e2e/test_hierarchy_validation.py +0 -0
  228. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/tests/e2e/test_state_transitions.py +0 -0
  229. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/tests/test_base_adapter.py +0 -0
  230. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/tests/test_models.py +0 -0
  231. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/tests/test_queue.py +0 -0
  232. {mcp_ticketer-0.1.28 → mcp_ticketer-0.1.29}/tox.ini +0 -0
@@ -6,6 +6,41 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.1.29] - 2025-10-24
10
+
11
+ ### Added
12
+ - **Comprehensive Diagnostics System**: Complete health monitoring and self-diagnosis capabilities
13
+ - `mcp-ticketer health`: Quick system health check command
14
+ - `mcp-ticketer diagnose`: Comprehensive system diagnostics with detailed analysis
15
+ - `system_health` MCP tool: AI agents can perform quick health checks
16
+ - `system_diagnose` MCP tool: AI agents can run comprehensive diagnostics
17
+ - **Intelligent Fallback System**: Graceful degradation when dependencies are missing
18
+ - Simple health checks that work without heavy dependencies
19
+ - Automatic fallback to lightweight diagnostics when full system fails
20
+ - Import protection for missing optional dependencies
21
+ - **Multi-Component Analysis**:
22
+ - Configuration validation and adapter testing
23
+ - Queue system health monitoring with failure rate analysis
24
+ - Environment variable detection and validation
25
+ - Installation verification and version checking
26
+ - Performance metrics and response time analysis
27
+ - **Rich Output Formats**:
28
+ - Colorized terminal output with status indicators
29
+ - JSON export for automation and integration
30
+ - File output for reporting and analysis
31
+ - Progressive disclosure (health → diagnose)
32
+ - **Exit Code Standards**: Proper exit codes for CI/CD integration (0=healthy, 1=critical, 2=warnings)
33
+
34
+ ### Enhanced
35
+ - **MCP Server**: Added two new diagnostic tools for AI agent integration
36
+ - **Error Handling**: Improved graceful handling of missing dependencies and failed components
37
+ - **User Experience**: Clear, actionable recommendations for resolving detected issues
38
+
39
+ ### Fixed
40
+ - **System Visibility**: Addresses the "60% failure rate" issue by providing comprehensive system monitoring
41
+ - **AI Agent Troubleshooting**: AI agents can now self-diagnose and identify system issues
42
+ - **Dependency Resilience**: System remains functional even when optional dependencies are missing
43
+
9
44
  ### Added
10
45
  - WebSocket support for real-time updates
11
46
  - Custom ticket templates
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-ticketer
3
- Version: 0.1.28
3
+ Version: 0.1.29
4
4
  Summary: Universal ticket management interface for AI agents with MCP support
5
5
  Author-email: MCP Ticketer Team <support@mcp-ticketer.io>
6
6
  Maintainer-email: MCP Ticketer Team <support@mcp-ticketer.io>
@@ -1,6 +1,6 @@
1
1
  """Version information for mcp-ticketer package."""
2
2
 
3
- __version__ = "0.1.28"
3
+ __version__ = "0.1.29"
4
4
  __version_info__ = tuple(int(part) for part in __version__.split("."))
5
5
 
6
6
  # Package metadata
@@ -0,0 +1,492 @@
1
+ """Comprehensive diagnostics and self-diagnosis functionality for MCP Ticketer."""
2
+
3
+ import asyncio
4
+ import json
5
+ import logging
6
+ import os
7
+ import sys
8
+ from datetime import datetime, timedelta
9
+ from pathlib import Path
10
+ from typing import Any, Dict, List, Optional, Tuple
11
+
12
+ import typer
13
+ from rich.console import Console
14
+ from rich.panel import Panel
15
+ from rich.table import Table
16
+ from rich.text import Text
17
+
18
+ try:
19
+ from ..core.config import get_config
20
+ except ImportError:
21
+ # Fallback for missing dependencies
22
+ def get_config():
23
+ raise ImportError("Configuration system not available")
24
+
25
+ try:
26
+ from ..core.registry import AdapterRegistry
27
+ except ImportError:
28
+ AdapterRegistry = None
29
+
30
+ try:
31
+ from ..queue.manager import QueueManager
32
+ except ImportError:
33
+ QueueManager = None
34
+
35
+ console = Console()
36
+ logger = logging.getLogger(__name__)
37
+
38
+
39
+ class SystemDiagnostics:
40
+ """Comprehensive system diagnostics and health reporting."""
41
+
42
+ def __init__(self):
43
+ try:
44
+ self.config = get_config()
45
+ except Exception as e:
46
+ self.config = None
47
+ console.print(f"⚠️ Could not load configuration: {e}")
48
+
49
+ try:
50
+ self.queue_manager = QueueManager() if QueueManager else None
51
+ except Exception as e:
52
+ self.queue_manager = None
53
+ console.print(f"⚠️ Could not initialize queue manager: {e}")
54
+
55
+ self.issues = []
56
+ self.warnings = []
57
+ self.successes = []
58
+
59
+ async def run_full_diagnosis(self) -> Dict[str, Any]:
60
+ """Run complete system diagnosis and return detailed report."""
61
+ console.print("\n🔍 [bold blue]MCP Ticketer System Diagnosis[/bold blue]")
62
+ console.print("=" * 60)
63
+
64
+ report = {
65
+ "timestamp": datetime.now().isoformat(),
66
+ "version": self._get_version(),
67
+ "system_info": self._get_system_info(),
68
+ "configuration": await self._diagnose_configuration(),
69
+ "adapters": await self._diagnose_adapters(),
70
+ "queue_system": await self._diagnose_queue_system(),
71
+ "recent_logs": await self._analyze_recent_logs(),
72
+ "performance": await self._analyze_performance(),
73
+ "recommendations": self._generate_recommendations(),
74
+ }
75
+
76
+ self._display_diagnosis_summary(report)
77
+ return report
78
+
79
+ def _get_version(self) -> str:
80
+ """Get current version information."""
81
+ try:
82
+ from ..__version__ import __version__
83
+ return __version__
84
+ except ImportError:
85
+ return "unknown"
86
+
87
+ def _get_system_info(self) -> Dict[str, Any]:
88
+ """Gather system information."""
89
+ return {
90
+ "python_version": sys.version,
91
+ "platform": sys.platform,
92
+ "working_directory": str(Path.cwd()),
93
+ "config_path": str(self.config.config_file) if hasattr(self.config, 'config_file') else "unknown",
94
+ }
95
+
96
+ async def _diagnose_configuration(self) -> Dict[str, Any]:
97
+ """Diagnose configuration issues."""
98
+ console.print("\n📋 [yellow]Configuration Analysis[/yellow]")
99
+
100
+ config_status = {
101
+ "status": "healthy",
102
+ "adapters_configured": 0,
103
+ "default_adapter": None,
104
+ "issues": [],
105
+ }
106
+
107
+ if not self.config:
108
+ issue = "Configuration system not available"
109
+ config_status["issues"].append(issue)
110
+ config_status["status"] = "critical"
111
+ self.issues.append(issue)
112
+ console.print(f"❌ {issue}")
113
+ return config_status
114
+
115
+ try:
116
+ # Check adapter configurations
117
+ adapters = self.config.get_enabled_adapters()
118
+ config_status["adapters_configured"] = len(adapters)
119
+ config_status["default_adapter"] = self.config.default_adapter
120
+
121
+ if not adapters:
122
+ issue = "No adapters configured"
123
+ config_status["issues"].append(issue)
124
+ config_status["status"] = "critical"
125
+ self.issues.append(issue)
126
+ console.print(f"❌ {issue}")
127
+ else:
128
+ console.print(f"✅ {len(adapters)} adapter(s) configured")
129
+
130
+ # Check each adapter configuration
131
+ for name, adapter_config in adapters.items():
132
+ try:
133
+ adapter_class = AdapterRegistry.get_adapter(adapter_config.type.value)
134
+ adapter = adapter_class(adapter_config.dict())
135
+
136
+ # Test adapter validation if available
137
+ if hasattr(adapter, 'validate_credentials'):
138
+ is_valid, error = adapter.validate_credentials()
139
+ if is_valid:
140
+ console.print(f"✅ {name}: credentials valid")
141
+ self.successes.append(f"{name} adapter configured correctly")
142
+ else:
143
+ issue = f"{name}: credential validation failed - {error}"
144
+ config_status["issues"].append(issue)
145
+ self.warnings.append(issue)
146
+ console.print(f"⚠️ {issue}")
147
+ else:
148
+ console.print(f"ℹ️ {name}: no credential validation available")
149
+
150
+ except Exception as e:
151
+ issue = f"{name}: configuration error - {str(e)}"
152
+ config_status["issues"].append(issue)
153
+ self.issues.append(issue)
154
+ console.print(f"❌ {issue}")
155
+
156
+ except Exception as e:
157
+ issue = f"Configuration loading failed: {str(e)}"
158
+ config_status["issues"].append(issue)
159
+ config_status["status"] = "critical"
160
+ self.issues.append(issue)
161
+ console.print(f"❌ {issue}")
162
+
163
+ return config_status
164
+
165
+ async def _diagnose_adapters(self) -> Dict[str, Any]:
166
+ """Diagnose adapter functionality."""
167
+ console.print("\n🔌 [yellow]Adapter Diagnosis[/yellow]")
168
+
169
+ adapter_status = {
170
+ "total_adapters": 0,
171
+ "healthy_adapters": 0,
172
+ "failed_adapters": 0,
173
+ "adapter_details": {},
174
+ }
175
+
176
+ try:
177
+ adapters = self.config.get_enabled_adapters()
178
+ adapter_status["total_adapters"] = len(adapters)
179
+
180
+ for name, adapter_config in adapters.items():
181
+ details = {
182
+ "type": adapter_config.type.value,
183
+ "status": "unknown",
184
+ "last_test": None,
185
+ "error": None,
186
+ }
187
+
188
+ try:
189
+ adapter_class = AdapterRegistry.get_adapter(adapter_config.type.value)
190
+ adapter = adapter_class(adapter_config.dict())
191
+
192
+ # Test basic adapter functionality
193
+ test_start = datetime.now()
194
+
195
+ # Try to list tickets (non-destructive test)
196
+ try:
197
+ await adapter.list(limit=1)
198
+ details["status"] = "healthy"
199
+ details["last_test"] = test_start.isoformat()
200
+ adapter_status["healthy_adapters"] += 1
201
+ console.print(f"✅ {name}: operational")
202
+ except Exception as e:
203
+ details["status"] = "failed"
204
+ details["error"] = str(e)
205
+ adapter_status["failed_adapters"] += 1
206
+ issue = f"{name}: functionality test failed - {str(e)}"
207
+ self.issues.append(issue)
208
+ console.print(f"❌ {issue}")
209
+
210
+ except Exception as e:
211
+ details["status"] = "failed"
212
+ details["error"] = str(e)
213
+ adapter_status["failed_adapters"] += 1
214
+ issue = f"{name}: initialization failed - {str(e)}"
215
+ self.issues.append(issue)
216
+ console.print(f"❌ {issue}")
217
+
218
+ adapter_status["adapter_details"][name] = details
219
+
220
+ except Exception as e:
221
+ issue = f"Adapter diagnosis failed: {str(e)}"
222
+ self.issues.append(issue)
223
+ console.print(f"❌ {issue}")
224
+
225
+ return adapter_status
226
+
227
+ async def _diagnose_queue_system(self) -> Dict[str, Any]:
228
+ """Diagnose queue system health."""
229
+ console.print("\n⚡ [yellow]Queue System Diagnosis[/yellow]")
230
+
231
+ queue_status = {
232
+ "worker_running": False,
233
+ "worker_pid": None,
234
+ "queue_stats": {},
235
+ "recent_failures": [],
236
+ "failure_rate": 0.0,
237
+ "health_score": 0,
238
+ }
239
+
240
+ try:
241
+ # Check worker status
242
+ worker_status = self.queue_manager.get_worker_status()
243
+ queue_status["worker_running"] = worker_status.get("running", False)
244
+ queue_status["worker_pid"] = worker_status.get("pid")
245
+
246
+ if queue_status["worker_running"]:
247
+ console.print(f"✅ Queue worker running (PID: {queue_status['worker_pid']})")
248
+ self.successes.append("Queue worker is running")
249
+ else:
250
+ issue = "Queue worker not running"
251
+ self.issues.append(issue)
252
+ console.print(f"❌ {issue}")
253
+
254
+ # Get queue statistics
255
+ stats = self.queue_manager.get_queue_stats()
256
+ queue_status["queue_stats"] = stats
257
+
258
+ total_items = stats.get("total", 0)
259
+ failed_items = stats.get("failed", 0)
260
+
261
+ if total_items > 0:
262
+ failure_rate = (failed_items / total_items) * 100
263
+ queue_status["failure_rate"] = failure_rate
264
+
265
+ if failure_rate > 50:
266
+ issue = f"High failure rate: {failure_rate:.1f}% ({failed_items}/{total_items})"
267
+ self.issues.append(issue)
268
+ console.print(f"❌ {issue}")
269
+ elif failure_rate > 20:
270
+ warning = f"Elevated failure rate: {failure_rate:.1f}% ({failed_items}/{total_items})"
271
+ self.warnings.append(warning)
272
+ console.print(f"⚠️ {warning}")
273
+ else:
274
+ console.print(f"✅ Queue failure rate: {failure_rate:.1f}% ({failed_items}/{total_items})")
275
+
276
+ # Calculate health score
277
+ health_score = 100
278
+ if not queue_status["worker_running"]:
279
+ health_score -= 50
280
+ health_score -= min(queue_status["failure_rate"], 50)
281
+ queue_status["health_score"] = max(0, health_score)
282
+
283
+ console.print(f"📊 Queue health score: {queue_status['health_score']}/100")
284
+
285
+ except Exception as e:
286
+ issue = f"Queue system diagnosis failed: {str(e)}"
287
+ self.issues.append(issue)
288
+ console.print(f"❌ {issue}")
289
+
290
+ return queue_status
291
+
292
+ async def _analyze_recent_logs(self) -> Dict[str, Any]:
293
+ """Analyze recent log entries for issues."""
294
+ console.print("\n📝 [yellow]Recent Log Analysis[/yellow]")
295
+
296
+ log_analysis = {
297
+ "log_files_found": [],
298
+ "recent_errors": [],
299
+ "recent_warnings": [],
300
+ "patterns": {},
301
+ }
302
+
303
+ try:
304
+ # Look for common log locations
305
+ log_paths = [
306
+ Path.home() / ".mcp-ticketer" / "logs",
307
+ Path.cwd() / ".mcp-ticketer" / "logs",
308
+ Path("/var/log/mcp-ticketer"),
309
+ ]
310
+
311
+ for log_path in log_paths:
312
+ if log_path.exists():
313
+ log_analysis["log_files_found"].append(str(log_path))
314
+ await self._analyze_log_directory(log_path, log_analysis)
315
+
316
+ if not log_analysis["log_files_found"]:
317
+ console.print("ℹ️ No log files found in standard locations")
318
+ else:
319
+ console.print(f"✅ Found logs in {len(log_analysis['log_files_found'])} location(s)")
320
+
321
+ except Exception as e:
322
+ issue = f"Log analysis failed: {str(e)}"
323
+ self.issues.append(issue)
324
+ console.print(f"❌ {issue}")
325
+
326
+ return log_analysis
327
+
328
+ async def _analyze_log_directory(self, log_path: Path, log_analysis: Dict[str, Any]):
329
+ """Analyze logs in a specific directory."""
330
+ try:
331
+ for log_file in log_path.glob("*.log"):
332
+ if log_file.stat().st_mtime > (datetime.now() - timedelta(hours=24)).timestamp():
333
+ await self._parse_log_file(log_file, log_analysis)
334
+ except Exception as e:
335
+ self.warnings.append(f"Could not analyze logs in {log_path}: {str(e)}")
336
+
337
+ async def _parse_log_file(self, log_file: Path, log_analysis: Dict[str, Any]):
338
+ """Parse individual log file for issues."""
339
+ try:
340
+ with open(log_file, 'r') as f:
341
+ lines = f.readlines()[-100:] # Last 100 lines
342
+
343
+ for line in lines:
344
+ if "ERROR" in line:
345
+ log_analysis["recent_errors"].append(line.strip())
346
+ elif "WARNING" in line:
347
+ log_analysis["recent_warnings"].append(line.strip())
348
+
349
+ except Exception as e:
350
+ self.warnings.append(f"Could not parse {log_file}: {str(e)}")
351
+
352
+ async def _analyze_performance(self) -> Dict[str, Any]:
353
+ """Analyze system performance metrics."""
354
+ console.print("\n⚡ [yellow]Performance Analysis[/yellow]")
355
+
356
+ performance = {
357
+ "response_times": {},
358
+ "throughput": {},
359
+ "resource_usage": {},
360
+ }
361
+
362
+ try:
363
+ # Test basic operations performance
364
+ start_time = datetime.now()
365
+
366
+ # Test configuration loading
367
+ config_start = datetime.now()
368
+ _ = get_config()
369
+ config_time = (datetime.now() - config_start).total_seconds()
370
+ performance["response_times"]["config_load"] = config_time
371
+
372
+ if config_time > 1.0:
373
+ self.warnings.append(f"Slow configuration loading: {config_time:.2f}s")
374
+
375
+ console.print(f"📊 Configuration load time: {config_time:.3f}s")
376
+
377
+ except Exception as e:
378
+ issue = f"Performance analysis failed: {str(e)}"
379
+ self.issues.append(issue)
380
+ console.print(f"❌ {issue}")
381
+
382
+ return performance
383
+
384
+ def _generate_recommendations(self) -> List[str]:
385
+ """Generate actionable recommendations based on diagnosis."""
386
+ recommendations = []
387
+
388
+ if self.issues:
389
+ recommendations.append("🚨 Critical issues detected - immediate attention required")
390
+
391
+ if any("Queue worker not running" in issue for issue in self.issues):
392
+ recommendations.append("• Restart queue worker: mcp-ticketer queue worker restart")
393
+
394
+ if any("failure rate" in issue.lower() for issue in self.issues):
395
+ recommendations.append("• Check queue system logs for error patterns")
396
+ recommendations.append("• Consider clearing failed queue items: mcp-ticketer queue clear --failed")
397
+
398
+ if any("No adapters configured" in issue for issue in self.issues):
399
+ recommendations.append("• Configure at least one adapter: mcp-ticketer init-aitrackdown")
400
+
401
+ if self.warnings:
402
+ recommendations.append("⚠️ Warnings detected - monitoring recommended")
403
+
404
+ if not self.issues and not self.warnings:
405
+ recommendations.append("✅ System appears healthy - no immediate action required")
406
+
407
+ return recommendations
408
+
409
+ def _display_diagnosis_summary(self, report: Dict[str, Any]):
410
+ """Display a comprehensive diagnosis summary."""
411
+ console.print("\n" + "=" * 60)
412
+ console.print("📋 [bold green]DIAGNOSIS SUMMARY[/bold green]")
413
+ console.print("=" * 60)
414
+
415
+ # Overall health status
416
+ if self.issues:
417
+ status_color = "red"
418
+ status_text = "CRITICAL"
419
+ status_icon = "🚨"
420
+ elif self.warnings:
421
+ status_color = "yellow"
422
+ status_text = "WARNING"
423
+ status_icon = "⚠️"
424
+ else:
425
+ status_color = "green"
426
+ status_text = "HEALTHY"
427
+ status_icon = "✅"
428
+
429
+ console.print(f"\n{status_icon} [bold {status_color}]System Status: {status_text}[/bold {status_color}]")
430
+
431
+ # Statistics
432
+ stats_table = Table(show_header=True, header_style="bold blue")
433
+ stats_table.add_column("Component")
434
+ stats_table.add_column("Status")
435
+ stats_table.add_column("Details")
436
+
437
+ # Add component statuses
438
+ config_status = "✅ OK" if not any("configuration" in issue.lower() for issue in self.issues) else "❌ FAILED"
439
+ stats_table.add_row("Configuration", config_status, f"{report['configuration']['adapters_configured']} adapters")
440
+
441
+ queue_health = report['queue_system']['health_score']
442
+ queue_status = "✅ OK" if queue_health > 80 else "⚠️ DEGRADED" if queue_health > 50 else "❌ FAILED"
443
+ stats_table.add_row("Queue System", queue_status, f"{queue_health}/100 health score")
444
+
445
+ adapter_stats = report['adapters']
446
+ adapter_status = "✅ OK" if adapter_stats['failed_adapters'] == 0 else "❌ FAILED"
447
+ stats_table.add_row("Adapters", adapter_status, f"{adapter_stats['healthy_adapters']}/{adapter_stats['total_adapters']} healthy")
448
+
449
+ console.print(stats_table)
450
+
451
+ # Issues and recommendations
452
+ if self.issues:
453
+ console.print(f"\n🚨 [bold red]Critical Issues ({len(self.issues)}):[/bold red]")
454
+ for issue in self.issues:
455
+ console.print(f" • {issue}")
456
+
457
+ if self.warnings:
458
+ console.print(f"\n⚠️ [bold yellow]Warnings ({len(self.warnings)}):[/bold yellow]")
459
+ for warning in self.warnings:
460
+ console.print(f" • {warning}")
461
+
462
+ if report['recommendations']:
463
+ console.print(f"\n💡 [bold blue]Recommendations:[/bold blue]")
464
+ for rec in report['recommendations']:
465
+ console.print(f" {rec}")
466
+
467
+ console.print(f"\n📊 [bold]Summary:[/bold] {len(self.successes)} successes, {len(self.warnings)} warnings, {len(self.issues)} critical issues")
468
+
469
+
470
+ async def run_diagnostics(
471
+ output_file: Optional[str] = None,
472
+ json_output: bool = False,
473
+ ) -> None:
474
+ """Run comprehensive system diagnostics."""
475
+ diagnostics = SystemDiagnostics()
476
+ report = await diagnostics.run_full_diagnosis()
477
+
478
+ if output_file:
479
+ with open(output_file, 'w') as f:
480
+ json.dump(report, f, indent=2)
481
+ console.print(f"\n📄 Full report saved to: {output_file}")
482
+
483
+ if json_output:
484
+ console.print("\n" + json.dumps(report, indent=2))
485
+
486
+ # Return exit code based on issues
487
+ if diagnostics.issues:
488
+ raise typer.Exit(1) # Critical issues found
489
+ elif diagnostics.warnings:
490
+ raise typer.Exit(2) # Warnings found
491
+ else:
492
+ raise typer.Exit(0) # All good
@@ -22,6 +22,7 @@ from ..queue.ticket_registry import TicketRegistry
22
22
  # Import adapters module to trigger registration
23
23
  import mcp_ticketer.adapters # noqa: F401
24
24
  from .configure import configure_wizard, set_adapter_config, show_current_config
25
+ from .diagnostics import run_diagnostics
25
26
  from .discover import app as discover_app
26
27
  from .migrate_config import migrate_config_command
27
28
  from .queue_commands import app as queue_app
@@ -1260,6 +1261,48 @@ app.add_typer(queue_app, name="queue")
1260
1261
  # Add discover command to main app
1261
1262
  app.add_typer(discover_app, name="discover")
1262
1263
 
1264
+ # Add diagnostics command
1265
+ @app.command()
1266
+ def diagnose(
1267
+ output_file: Optional[str] = typer.Option(None, "--output", "-o", help="Save full report to file"),
1268
+ json_output: bool = typer.Option(False, "--json", help="Output report in JSON format"),
1269
+ simple: bool = typer.Option(False, "--simple", help="Use simple diagnostics (no heavy dependencies)"),
1270
+ ) -> None:
1271
+ """Run comprehensive system diagnostics and health check."""
1272
+ if simple:
1273
+ from .simple_health import simple_diagnose
1274
+ report = simple_diagnose()
1275
+ if output_file:
1276
+ import json
1277
+ with open(output_file, 'w') as f:
1278
+ json.dump(report, f, indent=2)
1279
+ console.print(f"\n📄 Report saved to: {output_file}")
1280
+ if json_output:
1281
+ import json
1282
+ console.print("\n" + json.dumps(report, indent=2))
1283
+ if report["issues"]:
1284
+ raise typer.Exit(1)
1285
+ else:
1286
+ try:
1287
+ asyncio.run(run_diagnostics(output_file=output_file, json_output=json_output))
1288
+ except Exception as e:
1289
+ console.print(f"⚠️ Full diagnostics failed: {e}")
1290
+ console.print("🔄 Falling back to simple diagnostics...")
1291
+ from .simple_health import simple_diagnose
1292
+ report = simple_diagnose()
1293
+ if report["issues"]:
1294
+ raise typer.Exit(1)
1295
+
1296
+
1297
+ @app.command()
1298
+ def health() -> None:
1299
+ """Quick health check - shows system status summary."""
1300
+ from .simple_health import simple_health_check
1301
+
1302
+ result = simple_health_check()
1303
+ if result != 0:
1304
+ raise typer.Exit(result)
1305
+
1263
1306
  # Create MCP configuration command group
1264
1307
  mcp_app = typer.Typer(
1265
1308
  name="mcp",