mcp-ticketer 0.1.22__tar.gz → 0.1.23__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 (217) hide show
  1. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/PKG-INFO +1 -1
  2. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/pyproject.toml +1 -1
  3. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/__version__.py +1 -1
  4. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/adapters/aitrackdown.py +15 -14
  5. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/adapters/github.py +21 -20
  6. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/adapters/hybrid.py +13 -12
  7. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/adapters/jira.py +28 -27
  8. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/adapters/linear.py +26 -25
  9. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/cache/memory.py +2 -2
  10. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/cli/main.py +36 -8
  11. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/cli/migrate_config.py +2 -2
  12. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/cli/utils.py +8 -8
  13. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/core/adapter.py +12 -11
  14. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/core/config.py +17 -17
  15. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/core/env_discovery.py +24 -24
  16. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/core/http_client.py +13 -13
  17. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/core/mappers.py +25 -25
  18. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/core/models.py +10 -10
  19. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/core/project_config.py +22 -22
  20. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/core/registry.py +7 -7
  21. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/mcp/server.py +18 -18
  22. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/queue/manager.py +2 -2
  23. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/queue/queue.py +7 -7
  24. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/queue/worker.py +8 -8
  25. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer.egg-info/PKG-INFO +1 -1
  26. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/tests/adapters/test_aitrackdown.py +3 -3
  27. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/tests/test_base_adapter.py +5 -5
  28. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/tests/test_models.py +1 -1
  29. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/tests/test_queue.py +2 -2
  30. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/.dependency_cache +0 -0
  31. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/.mpm_deployment_state +0 -0
  32. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/agent-manager.md +0 -0
  33. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/agentic-coder-optimizer.md +0 -0
  34. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/api_qa.md +0 -0
  35. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/clerk-ops.md +0 -0
  36. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/code_analyzer.md +0 -0
  37. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/content-agent.md +0 -0
  38. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/dart_engineer.md +0 -0
  39. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/data_engineer.md +0 -0
  40. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/documentation.md +0 -0
  41. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/engineer.md +0 -0
  42. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/gcp_ops_agent.md +0 -0
  43. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/golang_engineer.md +0 -0
  44. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/imagemagick.md +0 -0
  45. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/java_engineer.md +0 -0
  46. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/local_ops_agent.md +0 -0
  47. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/memory_manager.md +0 -0
  48. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/nextjs_engineer.md +0 -0
  49. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/ops.md +0 -0
  50. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/php-engineer.md +0 -0
  51. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/product_owner.md +0 -0
  52. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/project_organizer.md +0 -0
  53. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/prompt-engineer.md +0 -0
  54. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/python_engineer.md +0 -0
  55. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/qa.md +0 -0
  56. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/react_engineer.md +0 -0
  57. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/refactoring_engineer.md +0 -0
  58. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/research.md +0 -0
  59. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/ruby-engineer.md +0 -0
  60. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/rust_engineer.md +0 -0
  61. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/security.md +0 -0
  62. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/ticketing.md +0 -0
  63. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/typescript_engineer.md +0 -0
  64. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/vercel_ops_agent.md +0 -0
  65. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/version_control.md +0 -0
  66. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/web_qa.md +0 -0
  67. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/agents/web_ui.md +0 -0
  68. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/mcp.json +0 -0
  69. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude/mcp.local.json +0 -0
  70. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude-mpm/config/project.json +0 -0
  71. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude-mpm/mcp_auto_config_preference.json +0 -0
  72. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude-mpm/memories/README.md +0 -0
  73. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude-mpm/memories/agentic_coder_optimizer_memories.md +0 -0
  74. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude-mpm/memories/documentation_memories.md +0 -0
  75. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude-mpm/memories/engineer_memories.md +0 -0
  76. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude-mpm/memories/ops_memories.md +0 -0
  77. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude-mpm/memories/project_knowledge_memories.md +0 -0
  78. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude-mpm/memories/qa_memories.md +0 -0
  79. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude-mpm/memories/research_memories.md +0 -0
  80. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude-mpm/memories/version-control_memories.md +0 -0
  81. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude-mpm/memories/workflows_memories.md +0 -0
  82. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.claude.json +0 -0
  83. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.coveragerc +0 -0
  84. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.env.example +0 -0
  85. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.github/workflows/docs.yml +0 -0
  86. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.github/workflows/publish.yml +0 -0
  87. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.github/workflows/test.yml +0 -0
  88. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.mcp/config.json +0 -0
  89. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.pre-commit-config.yaml +0 -0
  90. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.python-version +0 -0
  91. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/.readthedocs.yaml +0 -0
  92. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/CHANGELOG.md +0 -0
  93. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/CLAUDE.md +0 -0
  94. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/CLAUDE_DESKTOP_SETUP.md +0 -0
  95. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/CODE_STRUCTURE.md +0 -0
  96. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/CONFIG_RESOLUTION_FIX.md +0 -0
  97. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/CONTRIBUTING.md +0 -0
  98. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/CREDENTIAL_VALIDATION_FIX.md +0 -0
  99. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/ENV_DISCOVERY_COMPLETE.md +0 -0
  100. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/FIX_SUMMARY.md +0 -0
  101. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/HIERARCHY_IMPLEMENTATION_SUMMARY.md +0 -0
  102. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/IMPLEMENTATION_SUMMARY.md +0 -0
  103. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/JIRA_SETUP.md +0 -0
  104. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/LICENSE +0 -0
  105. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/LINEAR_SETUP.md +0 -0
  106. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/MANIFEST.in +0 -0
  107. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/Makefile +0 -0
  108. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/OPTIMIZATION_SUMMARY.md +0 -0
  109. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/PROJECT_INITIALIZATION_SUMMARY.md +0 -0
  110. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/QUEUE_SYSTEM.md +0 -0
  111. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/QUICK_START.md +0 -0
  112. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/README.md +0 -0
  113. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/RELEASE.md +0 -0
  114. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/RELEASING.md +0 -0
  115. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/TEST_COVERAGE_REPORT.md +0 -0
  116. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/TEST_REPORT.md +0 -0
  117. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/TEST_RESULTS_SUMMARY.md +0 -0
  118. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/VERIFICATION_RESULTS.md +0 -0
  119. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/claude-desktop-config.json +0 -0
  120. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/debug_search.py +0 -0
  121. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/debug_test.py +0 -0
  122. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/ADAPTERS.md +0 -0
  123. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/API_REFERENCE.md +0 -0
  124. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/CONFIGURATION.md +0 -0
  125. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/CONFIG_RESOLUTION_FLOW.md +0 -0
  126. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/DEVELOPER_GUIDE.md +0 -0
  127. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/ENV_DISCOVERY.md +0 -0
  128. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/MCP_INTEGRATION.md +0 -0
  129. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/MIGRATION_GUIDE.md +0 -0
  130. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/PROJECT_CONFIG.md +0 -0
  131. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/PR_INTEGRATION.md +0 -0
  132. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/QUICK_START_ENV.md +0 -0
  133. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/USER_GUIDE.md +0 -0
  134. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_archive/README.md +0 -0
  135. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/ADAPTERS.md.txt +0 -0
  136. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/API_REFERENCE.md.txt +0 -0
  137. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/CONFIGURATION.md.txt +0 -0
  138. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/DEVELOPER_GUIDE.md.txt +0 -0
  139. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/MCP_INTEGRATION.md.txt +0 -0
  140. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/MIGRATION_GUIDE.md.txt +0 -0
  141. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/USER_GUIDE.md.txt +0 -0
  142. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/adapters/github.md.txt +0 -0
  143. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/adapters.rst.txt +0 -0
  144. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/api.rst.txt +0 -0
  145. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/cli.rst.txt +0 -0
  146. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/development.rst.txt +0 -0
  147. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/examples.rst.txt +0 -0
  148. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/index.rst.txt +0 -0
  149. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/installation.rst.txt +0 -0
  150. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/_build/_sources/prd/mcp-ticketer-prd.md.txt +0 -0
  151. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/adapters/github.md +0 -0
  152. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/adapters.rst +0 -0
  153. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/api.rst +0 -0
  154. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/cli.rst +0 -0
  155. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/conf.py +0 -0
  156. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/development.rst +0 -0
  157. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/examples.rst +0 -0
  158. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/index.rst +0 -0
  159. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/installation.rst +0 -0
  160. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/prd/mcp-ticketer-prd.md +0 -0
  161. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/docs/requirements.txt +0 -0
  162. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/install.sh +0 -0
  163. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/mcp-ticketer +0 -0
  164. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/mcp-ticketer-server +0 -0
  165. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/mcp_server.sh +0 -0
  166. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/pytest.ini +0 -0
  167. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/requirements-dev.txt +0 -0
  168. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/requirements.txt +0 -0
  169. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/scripts/README.md +0 -0
  170. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/scripts/manage_version.py +0 -0
  171. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/setup.cfg +0 -0
  172. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/setup.py +0 -0
  173. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/__init__.py +0 -0
  174. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/adapters/__init__.py +0 -0
  175. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/cache/__init__.py +0 -0
  176. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/cli/__init__.py +0 -0
  177. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/cli/configure.py +0 -0
  178. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/cli/discover.py +0 -0
  179. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/cli/mcp_configure.py +0 -0
  180. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/cli/queue_commands.py +0 -0
  181. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/core/__init__.py +0 -0
  182. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/mcp/__init__.py +0 -0
  183. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/py.typed +0 -0
  184. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/queue/__init__.py +0 -0
  185. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/queue/__main__.py +0 -0
  186. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer/queue/run_worker.py +0 -0
  187. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer.egg-info/SOURCES.txt +0 -0
  188. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer.egg-info/dependency_links.txt +0 -0
  189. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer.egg-info/entry_points.txt +0 -0
  190. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer.egg-info/not-zip-safe +0 -0
  191. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer.egg-info/requires.txt +0 -0
  192. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/src/mcp_ticketer.egg-info/top_level.txt +0 -0
  193. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test-tickets/tickets/task-20250924002724.json +0 -0
  194. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_all_adapters.py +0 -0
  195. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_api_usage.py +0 -0
  196. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_basic.py +0 -0
  197. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_comprehensive.py +0 -0
  198. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_config_resolution.py +0 -0
  199. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_credential_validation.py +0 -0
  200. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_error_handling.py +0 -0
  201. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_github.py +0 -0
  202. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_github_token.py +0 -0
  203. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_jira.py +0 -0
  204. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_linear.py +0 -0
  205. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_linear_native.py +0 -0
  206. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_linear_teams.py +0 -0
  207. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_mcp_server_qa.py +0 -0
  208. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_optimizations.py +0 -0
  209. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_performance.py +0 -0
  210. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_pr_functionality.py +0 -0
  211. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_queue_system.py +0 -0
  212. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_serve_config.py +0 -0
  213. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/test_set_command.sh +0 -0
  214. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/tests/adapters/__init__.py +0 -0
  215. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/tests/conftest.py +0 -0
  216. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/tests/core/test_env_discovery.py +0 -0
  217. {mcp_ticketer-0.1.22 → mcp_ticketer-0.1.23}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-ticketer
3
- Version: 0.1.22
3
+ Version: 0.1.23
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>
@@ -148,7 +148,7 @@ extend-exclude = '''
148
148
  '''
149
149
 
150
150
  [tool.ruff]
151
- target-version = "0.1.22"
151
+ target-version = "py39"
152
152
  line-length = 88
153
153
 
154
154
  [tool.ruff.lint]
@@ -1,6 +1,6 @@
1
1
  """Version information for mcp-ticketer package."""
2
2
 
3
- __version__ = "0.1.22"
3
+ __version__ = "0.1.23"
4
4
  __version_info__ = tuple(int(part) for part in __version__.split("."))
5
5
 
6
6
  # Package metadata
@@ -1,9 +1,10 @@
1
1
  """AI-Trackdown adapter implementation."""
2
2
 
3
+ import builtins
3
4
  import json
4
5
  from datetime import datetime
5
6
  from pathlib import Path
6
- from typing import Any, Dict, List, Optional, Union
7
+ from typing import Any, Optional, Union
7
8
 
8
9
  from ..core.adapter import BaseAdapter
9
10
  from ..core.models import Comment, Epic, Priority, SearchQuery, Task, TicketState
@@ -24,7 +25,7 @@ except ImportError:
24
25
  class AITrackdownAdapter(BaseAdapter[Task]):
25
26
  """Adapter for AI-Trackdown ticket system."""
26
27
 
27
- def __init__(self, config: Dict[str, Any]):
28
+ def __init__(self, config: dict[str, Any]):
28
29
  """Initialize AI-Trackdown adapter.
29
30
 
30
31
  Args:
@@ -58,7 +59,7 @@ class AITrackdownAdapter(BaseAdapter[Task]):
58
59
  return False, "AITrackdown base_path is required in configuration"
59
60
  return True, ""
60
61
 
61
- def _get_state_mapping(self) -> Dict[TicketState, str]:
62
+ def _get_state_mapping(self) -> dict[TicketState, str]:
62
63
  """Map universal states to AI-Trackdown states."""
63
64
  return {
64
65
  TicketState.OPEN: "open",
@@ -84,7 +85,7 @@ class AITrackdownAdapter(BaseAdapter[Task]):
84
85
  except ValueError:
85
86
  return Priority.MEDIUM
86
87
 
87
- def _task_from_ai_ticket(self, ai_ticket: Dict[str, Any]) -> Task:
88
+ def _task_from_ai_ticket(self, ai_ticket: dict[str, Any]) -> Task:
88
89
  """Convert AI-Trackdown ticket to universal Task."""
89
90
  return Task(
90
91
  id=ai_ticket.get("id"),
@@ -109,7 +110,7 @@ class AITrackdownAdapter(BaseAdapter[Task]):
109
110
  metadata={"ai_trackdown": ai_ticket},
110
111
  )
111
112
 
112
- def _epic_from_ai_ticket(self, ai_ticket: Dict[str, Any]) -> Epic:
113
+ def _epic_from_ai_ticket(self, ai_ticket: dict[str, Any]) -> Epic:
113
114
  """Convert AI-Trackdown ticket to universal Epic."""
114
115
  return Epic(
115
116
  id=ai_ticket.get("id"),
@@ -132,7 +133,7 @@ class AITrackdownAdapter(BaseAdapter[Task]):
132
133
  metadata={"ai_trackdown": ai_ticket},
133
134
  )
134
135
 
135
- def _task_to_ai_ticket(self, task: Task) -> Dict[str, Any]:
136
+ def _task_to_ai_ticket(self, task: Task) -> dict[str, Any]:
136
137
  """Convert universal Task to AI-Trackdown ticket."""
137
138
  # Handle enum values that may be stored as strings due to use_enum_values=True
138
139
  state_value = task.state
@@ -159,7 +160,7 @@ class AITrackdownAdapter(BaseAdapter[Task]):
159
160
  "type": "task",
160
161
  }
161
162
 
162
- def _epic_to_ai_ticket(self, epic: Epic) -> Dict[str, Any]:
163
+ def _epic_to_ai_ticket(self, epic: Epic) -> dict[str, Any]:
163
164
  """Convert universal Epic to AI-Trackdown ticket."""
164
165
  # Handle enum values that may be stored as strings due to use_enum_values=True
165
166
  state_value = epic.state
@@ -184,7 +185,7 @@ class AITrackdownAdapter(BaseAdapter[Task]):
184
185
  "type": "epic",
185
186
  }
186
187
 
187
- def _read_ticket_file(self, ticket_id: str) -> Optional[Dict[str, Any]]:
188
+ def _read_ticket_file(self, ticket_id: str) -> Optional[dict[str, Any]]:
188
189
  """Read ticket from file system."""
189
190
  ticket_file = self.tickets_dir / f"{ticket_id}.json"
190
191
  if ticket_file.exists():
@@ -192,7 +193,7 @@ class AITrackdownAdapter(BaseAdapter[Task]):
192
193
  return json.load(f)
193
194
  return None
194
195
 
195
- def _write_ticket_file(self, ticket_id: str, data: Dict[str, Any]) -> None:
196
+ def _write_ticket_file(self, ticket_id: str, data: dict[str, Any]) -> None:
196
197
  """Write ticket to file system."""
197
198
  ticket_file = self.tickets_dir / f"{ticket_id}.json"
198
199
  with open(ticket_file, "w") as f:
@@ -250,7 +251,7 @@ class AITrackdownAdapter(BaseAdapter[Task]):
250
251
  return None
251
252
 
252
253
  async def update(
253
- self, ticket_id: str, updates: Union[Dict[str, Any], Task]
254
+ self, ticket_id: str, updates: Union[dict[str, Any], Task]
254
255
  ) -> Optional[Task]:
255
256
  """Update a task."""
256
257
  # Read existing ticket
@@ -297,8 +298,8 @@ class AITrackdownAdapter(BaseAdapter[Task]):
297
298
  return False
298
299
 
299
300
  async def list(
300
- self, limit: int = 10, offset: int = 0, filters: Optional[Dict[str, Any]] = None
301
- ) -> List[Task]:
301
+ self, limit: int = 10, offset: int = 0, filters: Optional[dict[str, Any]] = None
302
+ ) -> list[Task]:
302
303
  """List tasks with pagination."""
303
304
  tasks = []
304
305
 
@@ -342,7 +343,7 @@ class AITrackdownAdapter(BaseAdapter[Task]):
342
343
 
343
344
  return tasks
344
345
 
345
- async def search(self, query: SearchQuery) -> List[Task]:
346
+ async def search(self, query: SearchQuery) -> builtins.list[Task]:
346
347
  """Search tasks using query parameters."""
347
348
  filters = {}
348
349
  if query.state:
@@ -410,7 +411,7 @@ class AITrackdownAdapter(BaseAdapter[Task]):
410
411
 
411
412
  async def get_comments(
412
413
  self, ticket_id: str, limit: int = 10, offset: int = 0
413
- ) -> List[Comment]:
414
+ ) -> builtins.list[Comment]:
414
415
  """Get comments for a task."""
415
416
  comments = []
416
417
  comments_dir = self.base_path / "comments"
@@ -1,9 +1,10 @@
1
1
  """GitHub adapter implementation using REST API v3 and GraphQL API v4."""
2
2
 
3
+ import builtins
3
4
  import os
4
5
  import re
5
6
  from datetime import datetime
6
- from typing import Any, Dict, List, Optional
7
+ from typing import Any, Optional
7
8
 
8
9
  import httpx
9
10
 
@@ -135,7 +136,7 @@ class GitHubGraphQLQueries:
135
136
  class GitHubAdapter(BaseAdapter[Task]):
136
137
  """Adapter for GitHub Issues tracking system."""
137
138
 
138
- def __init__(self, config: Dict[str, Any]):
139
+ def __init__(self, config: dict[str, Any]):
139
140
  """Initialize GitHub adapter.
140
141
 
141
142
  Args:
@@ -192,9 +193,9 @@ class GitHubAdapter(BaseAdapter[Task]):
192
193
  )
193
194
 
194
195
  # Cache for labels and milestones
195
- self._labels_cache: Optional[List[Dict[str, Any]]] = None
196
- self._milestones_cache: Optional[List[Dict[str, Any]]] = None
197
- self._rate_limit: Dict[str, Any] = {}
196
+ self._labels_cache: Optional[list[dict[str, Any]]] = None
197
+ self._milestones_cache: Optional[list[dict[str, Any]]] = None
198
+ self._rate_limit: dict[str, Any] = {}
198
199
 
199
200
  def validate_credentials(self) -> tuple[bool, str]:
200
201
  """Validate that required credentials are present.
@@ -220,7 +221,7 @@ class GitHubAdapter(BaseAdapter[Task]):
220
221
  )
221
222
  return True, ""
222
223
 
223
- def _get_state_mapping(self) -> Dict[TicketState, str]:
224
+ def _get_state_mapping(self) -> dict[TicketState, str]:
224
225
  """Map universal states to GitHub states."""
225
226
  return {
226
227
  TicketState.OPEN: GitHubStateMapping.OPEN,
@@ -237,7 +238,7 @@ class GitHubAdapter(BaseAdapter[Task]):
237
238
  """Get the label name for extended states."""
238
239
  return GitHubStateMapping.STATE_LABELS.get(state)
239
240
 
240
- def _get_priority_from_labels(self, labels: List[str]) -> Priority:
241
+ def _get_priority_from_labels(self, labels: list[str]) -> Priority:
241
242
  """Extract priority from issue labels."""
242
243
  label_names = [label.lower() for label in labels]
243
244
 
@@ -272,7 +273,7 @@ class GitHubAdapter(BaseAdapter[Task]):
272
273
  else f"P{['0', '1', '2', '3'][list(Priority).index(priority)]}"
273
274
  )
274
275
 
275
- def _extract_state_from_issue(self, issue: Dict[str, Any]) -> TicketState:
276
+ def _extract_state_from_issue(self, issue: dict[str, Any]) -> TicketState:
276
277
  """Extract ticket state from GitHub issue data."""
277
278
  # Check if closed
278
279
  if issue["state"] == "closed":
@@ -298,7 +299,7 @@ class GitHubAdapter(BaseAdapter[Task]):
298
299
 
299
300
  return TicketState.OPEN
300
301
 
301
- def _task_from_github_issue(self, issue: Dict[str, Any]) -> Task:
302
+ def _task_from_github_issue(self, issue: dict[str, Any]) -> Task:
302
303
  """Convert GitHub issue to universal Task."""
303
304
  # Extract labels
304
305
  labels = []
@@ -415,8 +416,8 @@ class GitHubAdapter(BaseAdapter[Task]):
415
416
  self._labels_cache.append(response.json())
416
417
 
417
418
  async def _graphql_request(
418
- self, query: str, variables: Dict[str, Any]
419
- ) -> Dict[str, Any]:
419
+ self, query: str, variables: dict[str, Any]
420
+ ) -> dict[str, Any]:
420
421
  """Execute a GraphQL query."""
421
422
  response = await self.client.post(
422
423
  self.graphql_url, json={"query": query, "variables": variables}
@@ -527,7 +528,7 @@ class GitHubAdapter(BaseAdapter[Task]):
527
528
  except httpx.HTTPError:
528
529
  return None
529
530
 
530
- async def update(self, ticket_id: str, updates: Dict[str, Any]) -> Optional[Task]:
531
+ async def update(self, ticket_id: str, updates: dict[str, Any]) -> Optional[Task]:
531
532
  """Update a GitHub issue."""
532
533
  # Validate credentials before attempting operation
533
534
  is_valid, error_message = self.validate_credentials()
@@ -679,8 +680,8 @@ class GitHubAdapter(BaseAdapter[Task]):
679
680
  return False
680
681
 
681
682
  async def list(
682
- self, limit: int = 10, offset: int = 0, filters: Optional[Dict[str, Any]] = None
683
- ) -> List[Task]:
683
+ self, limit: int = 10, offset: int = 0, filters: Optional[dict[str, Any]] = None
684
+ ) -> list[Task]:
684
685
  """List GitHub issues with filters."""
685
686
  # Build query parameters
686
687
  params = {
@@ -743,7 +744,7 @@ class GitHubAdapter(BaseAdapter[Task]):
743
744
 
744
745
  return [self._task_from_github_issue(issue) for issue in issues]
745
746
 
746
- async def search(self, query: SearchQuery) -> List[Task]:
747
+ async def search(self, query: SearchQuery) -> builtins.list[Task]:
747
748
  """Search GitHub issues using advanced search syntax."""
748
749
  # Build GitHub search query
749
750
  search_parts = [f"repo:{self.owner}/{self.repo}", "is:issue"]
@@ -875,7 +876,7 @@ class GitHubAdapter(BaseAdapter[Task]):
875
876
 
876
877
  async def get_comments(
877
878
  self, ticket_id: str, limit: int = 10, offset: int = 0
878
- ) -> List[Comment]:
879
+ ) -> builtins.list[Comment]:
879
880
  """Get comments for a GitHub issue."""
880
881
  try:
881
882
  issue_number = int(ticket_id)
@@ -919,7 +920,7 @@ class GitHubAdapter(BaseAdapter[Task]):
919
920
  except httpx.HTTPError:
920
921
  return []
921
922
 
922
- async def get_rate_limit(self) -> Dict[str, Any]:
923
+ async def get_rate_limit(self) -> dict[str, Any]:
923
924
  """Get current rate limit status."""
924
925
  response = await self.client.get("/rate_limit")
925
926
  response.raise_for_status()
@@ -1006,7 +1007,7 @@ class GitHubAdapter(BaseAdapter[Task]):
1006
1007
 
1007
1008
  async def list_milestones(
1008
1009
  self, state: str = "open", limit: int = 10, offset: int = 0
1009
- ) -> List[Epic]:
1010
+ ) -> builtins.list[Epic]:
1010
1011
  """List GitHub milestones as Epics."""
1011
1012
  params = {
1012
1013
  "state": state,
@@ -1071,7 +1072,7 @@ class GitHubAdapter(BaseAdapter[Task]):
1071
1072
  title: Optional[str] = None,
1072
1073
  body: Optional[str] = None,
1073
1074
  draft: bool = False,
1074
- ) -> Dict[str, Any]:
1075
+ ) -> dict[str, Any]:
1075
1076
  """Create a pull request linked to an issue.
1076
1077
 
1077
1078
  Args:
@@ -1246,7 +1247,7 @@ Fixes #{issue_number}
1246
1247
  self,
1247
1248
  ticket_id: str,
1248
1249
  pr_url: str,
1249
- ) -> Dict[str, Any]:
1250
+ ) -> dict[str, Any]:
1250
1251
  """Link an existing pull request to a ticket.
1251
1252
 
1252
1253
  Args:
@@ -4,10 +4,11 @@ This adapter enables synchronization across multiple ticketing systems
4
4
  (Linear, JIRA, GitHub, AITrackdown) with configurable sync strategies.
5
5
  """
6
6
 
7
+ import builtins
7
8
  import json
8
9
  import logging
9
10
  from pathlib import Path
10
- from typing import Any, Dict, List, Optional
11
+ from typing import Any, Optional
11
12
 
12
13
  from ..core.adapter import BaseAdapter
13
14
  from ..core.models import Comment, Epic, SearchQuery, Task, TicketState
@@ -27,7 +28,7 @@ class HybridAdapter(BaseAdapter):
27
28
  Maintains mapping between ticket IDs across different systems.
28
29
  """
29
30
 
30
- def __init__(self, config: Dict[str, Any]):
31
+ def __init__(self, config: dict[str, Any]):
31
32
  """Initialize hybrid adapter.
32
33
 
33
34
  Args:
@@ -40,7 +41,7 @@ class HybridAdapter(BaseAdapter):
40
41
  """
41
42
  super().__init__(config)
42
43
 
43
- self.adapters: Dict[str, BaseAdapter] = {}
44
+ self.adapters: dict[str, BaseAdapter] = {}
44
45
  self.primary_adapter_name = config.get("primary_adapter")
45
46
  self.sync_strategy = config.get("sync_strategy", "primary_source")
46
47
 
@@ -70,12 +71,12 @@ class HybridAdapter(BaseAdapter):
70
71
  )
71
72
  self.id_mapping = self._load_mapping()
72
73
 
73
- def _get_state_mapping(self) -> Dict[TicketState, str]:
74
+ def _get_state_mapping(self) -> dict[TicketState, str]:
74
75
  """Get state mapping from primary adapter."""
75
76
  primary = self.adapters[self.primary_adapter_name]
76
77
  return primary._get_state_mapping()
77
78
 
78
- def _load_mapping(self) -> Dict[str, Dict[str, str]]:
79
+ def _load_mapping(self) -> dict[str, dict[str, str]]:
79
80
  """Load ID mapping from file.
80
81
 
81
82
  Mapping format:
@@ -207,7 +208,7 @@ class HybridAdapter(BaseAdapter):
207
208
  return primary_ticket
208
209
 
209
210
  def _add_cross_references(
210
- self, ticket: Task | Epic, results: List[tuple[str, Task | Epic]]
211
+ self, ticket: Task | Epic, results: list[tuple[str, Task | Epic]]
211
212
  ) -> None:
212
213
  """Add cross-references to ticket description.
213
214
 
@@ -253,7 +254,7 @@ class HybridAdapter(BaseAdapter):
253
254
  return await primary.read(ticket_id)
254
255
 
255
256
  async def update(
256
- self, ticket_id: str, updates: Dict[str, Any]
257
+ self, ticket_id: str, updates: dict[str, Any]
257
258
  ) -> Optional[Task | Epic]:
258
259
  """Update ticket across all adapters.
259
260
 
@@ -358,8 +359,8 @@ class HybridAdapter(BaseAdapter):
358
359
  return success_count > 0
359
360
 
360
361
  async def list(
361
- self, limit: int = 10, offset: int = 0, filters: Optional[Dict[str, Any]] = None
362
- ) -> List[Task | Epic]:
362
+ self, limit: int = 10, offset: int = 0, filters: Optional[dict[str, Any]] = None
363
+ ) -> list[Task | Epic]:
363
364
  """List tickets from primary adapter.
364
365
 
365
366
  Args:
@@ -374,7 +375,7 @@ class HybridAdapter(BaseAdapter):
374
375
  primary = self.adapters[self.primary_adapter_name]
375
376
  return await primary.list(limit, offset, filters)
376
377
 
377
- async def search(self, query: SearchQuery) -> List[Task | Epic]:
378
+ async def search(self, query: SearchQuery) -> builtins.list[Task | Epic]:
378
379
  """Search tickets in primary adapter.
379
380
 
380
381
  Args:
@@ -488,7 +489,7 @@ class HybridAdapter(BaseAdapter):
488
489
 
489
490
  async def get_comments(
490
491
  self, ticket_id: str, limit: int = 10, offset: int = 0
491
- ) -> List[Comment]:
492
+ ) -> builtins.list[Comment]:
492
493
  """Get comments from primary adapter.
493
494
 
494
495
  Args:
@@ -520,7 +521,7 @@ class HybridAdapter(BaseAdapter):
520
521
  except Exception as e:
521
522
  logger.error(f"Error closing adapter: {e}")
522
523
 
523
- async def sync_status(self) -> Dict[str, Any]:
524
+ async def sync_status(self) -> dict[str, Any]:
524
525
  """Get synchronization status across all adapters.
525
526
 
526
527
  Returns:
@@ -1,11 +1,12 @@
1
1
  """JIRA adapter implementation using REST API v3."""
2
2
 
3
3
  import asyncio
4
+ import builtins
4
5
  import logging
5
6
  import os
6
7
  from datetime import datetime
7
8
  from enum import Enum
8
- from typing import Any, Dict, List, Optional, Union
9
+ from typing import Any, Optional, Union
9
10
 
10
11
  import httpx
11
12
  from httpx import AsyncClient, HTTPStatusError, TimeoutException
@@ -42,7 +43,7 @@ class JiraPriority(str, Enum):
42
43
  class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
43
44
  """Adapter for JIRA using REST API v3."""
44
45
 
45
- def __init__(self, config: Dict[str, Any]):
46
+ def __init__(self, config: dict[str, Any]):
46
47
  """Initialize JIRA adapter.
47
48
 
48
49
  Args:
@@ -93,10 +94,10 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
93
94
  }
94
95
 
95
96
  # Cache for workflow states and transitions
96
- self._workflow_cache: Dict[str, Any] = {}
97
- self._priority_cache: List[Dict[str, Any]] = []
98
- self._issue_types_cache: Dict[str, Any] = {}
99
- self._custom_fields_cache: Dict[str, Any] = {}
97
+ self._workflow_cache: dict[str, Any] = {}
98
+ self._priority_cache: list[dict[str, Any]] = []
99
+ self._issue_types_cache: dict[str, Any] = {}
100
+ self._custom_fields_cache: dict[str, Any] = {}
100
101
 
101
102
  def validate_credentials(self) -> tuple[bool, str]:
102
103
  """Validate that required credentials are present.
@@ -122,7 +123,7 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
122
123
  )
123
124
  return True, ""
124
125
 
125
- def _get_state_mapping(self) -> Dict[TicketState, str]:
126
+ def _get_state_mapping(self) -> dict[TicketState, str]:
126
127
  """Map universal states to common JIRA workflow states."""
127
128
  return {
128
129
  TicketState.OPEN: "To Do",
@@ -148,10 +149,10 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
148
149
  self,
149
150
  method: str,
150
151
  endpoint: str,
151
- data: Optional[Dict[str, Any]] = None,
152
- params: Optional[Dict[str, Any]] = None,
152
+ data: Optional[dict[str, Any]] = None,
153
+ params: Optional[dict[str, Any]] = None,
153
154
  retry_count: int = 0,
154
- ) -> Dict[str, Any]:
155
+ ) -> dict[str, Any]:
155
156
  """Make HTTP request to JIRA API with retry logic.
156
157
 
157
158
  Args:
@@ -207,7 +208,7 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
207
208
  )
208
209
  raise e
209
210
 
210
- async def _get_priorities(self) -> List[Dict[str, Any]]:
211
+ async def _get_priorities(self) -> list[dict[str, Any]]:
211
212
  """Get available priorities from JIRA."""
212
213
  if not self._priority_cache:
213
214
  self._priority_cache = await self._make_request("GET", "priority")
@@ -215,7 +216,7 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
215
216
 
216
217
  async def _get_issue_types(
217
218
  self, project_key: Optional[str] = None
218
- ) -> List[Dict[str, Any]]:
219
+ ) -> list[dict[str, Any]]:
219
220
  """Get available issue types for a project."""
220
221
  key = project_key or self.project_key
221
222
  if key not in self._issue_types_cache:
@@ -223,12 +224,12 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
223
224
  self._issue_types_cache[key] = data.get("issueTypes", [])
224
225
  return self._issue_types_cache[key]
225
226
 
226
- async def _get_transitions(self, issue_key: str) -> List[Dict[str, Any]]:
227
+ async def _get_transitions(self, issue_key: str) -> list[dict[str, Any]]:
227
228
  """Get available transitions for an issue."""
228
229
  data = await self._make_request("GET", f"issue/{issue_key}/transitions")
229
230
  return data.get("transitions", [])
230
231
 
231
- async def _get_custom_fields(self) -> Dict[str, str]:
232
+ async def _get_custom_fields(self) -> dict[str, str]:
232
233
  """Get custom field definitions."""
233
234
  if not self._custom_fields_cache:
234
235
  fields = await self._make_request("GET", "field")
@@ -274,7 +275,7 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
274
275
 
275
276
  return "\n".join(lines)
276
277
 
277
- def _convert_to_adf(self, text: str) -> Dict[str, Any]:
278
+ def _convert_to_adf(self, text: str) -> dict[str, Any]:
278
279
  """Convert plain text to Atlassian Document Format (ADF).
279
280
 
280
281
  ADF is required for JIRA Cloud description fields.
@@ -308,7 +309,7 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
308
309
  return mapping.get(priority, JiraPriority.MEDIUM)
309
310
 
310
311
  def _map_priority_from_jira(
311
- self, jira_priority: Optional[Dict[str, Any]]
312
+ self, jira_priority: Optional[dict[str, Any]]
312
313
  ) -> Priority:
313
314
  """Map JIRA priority to universal priority."""
314
315
  if not jira_priority:
@@ -325,7 +326,7 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
325
326
  else:
326
327
  return Priority.MEDIUM
327
328
 
328
- def _map_state_from_jira(self, status: Dict[str, Any]) -> TicketState:
329
+ def _map_state_from_jira(self, status: dict[str, Any]) -> TicketState:
329
330
  """Map JIRA status to universal state."""
330
331
  if not status:
331
332
  return TicketState.OPEN
@@ -359,7 +360,7 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
359
360
  else:
360
361
  return TicketState.OPEN
361
362
 
362
- def _issue_to_ticket(self, issue: Dict[str, Any]) -> Union[Epic, Task]:
363
+ def _issue_to_ticket(self, issue: dict[str, Any]) -> Union[Epic, Task]:
363
364
  """Convert JIRA issue to universal ticket model."""
364
365
  fields = issue.get("fields", {})
365
366
 
@@ -443,7 +444,7 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
443
444
 
444
445
  def _ticket_to_issue_fields(
445
446
  self, ticket: Union[Epic, Task], issue_type: Optional[str] = None
446
- ) -> Dict[str, Any]:
447
+ ) -> dict[str, Any]:
447
448
  """Convert universal ticket to JIRA issue fields."""
448
449
  # Convert description to ADF format for JIRA Cloud
449
450
  description = (
@@ -526,7 +527,7 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
526
527
  raise
527
528
 
528
529
  async def update(
529
- self, ticket_id: str, updates: Dict[str, Any]
530
+ self, ticket_id: str, updates: dict[str, Any]
530
531
  ) -> Optional[Union[Epic, Task]]:
531
532
  """Update a JIRA issue."""
532
533
  # Validate credentials before attempting operation
@@ -584,8 +585,8 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
584
585
  raise
585
586
 
586
587
  async def list(
587
- self, limit: int = 10, offset: int = 0, filters: Optional[Dict[str, Any]] = None
588
- ) -> List[Union[Epic, Task]]:
588
+ self, limit: int = 10, offset: int = 0, filters: Optional[dict[str, Any]] = None
589
+ ) -> list[Union[Epic, Task]]:
589
590
  """List JIRA issues with pagination."""
590
591
  # Build JQL query
591
592
  jql_parts = []
@@ -624,7 +625,7 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
624
625
  issues = data.get("issues", [])
625
626
  return [self._issue_to_ticket(issue) for issue in issues]
626
627
 
627
- async def search(self, query: SearchQuery) -> List[Union[Epic, Task]]:
628
+ async def search(self, query: SearchQuery) -> builtins.list[Union[Epic, Task]]:
628
629
  """Search JIRA issues using JQL."""
629
630
  # Build JQL query
630
631
  jql_parts = []
@@ -749,7 +750,7 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
749
750
 
750
751
  async def get_comments(
751
752
  self, ticket_id: str, limit: int = 10, offset: int = 0
752
- ) -> List[Comment]:
753
+ ) -> builtins.list[Comment]:
753
754
  """Get comments for a JIRA issue."""
754
755
  # Fetch issue with comments
755
756
  params = {"expand": "comments", "fields": "comment"}
@@ -785,7 +786,7 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
785
786
 
786
787
  async def get_project_info(
787
788
  self, project_key: Optional[str] = None
788
- ) -> Dict[str, Any]:
789
+ ) -> dict[str, Any]:
789
790
  """Get JIRA project information including workflows and fields."""
790
791
  key = project_key or self.project_key
791
792
  if not key:
@@ -805,7 +806,7 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
805
806
  "custom_fields": custom_fields,
806
807
  }
807
808
 
808
- async def execute_jql(self, jql: str, limit: int = 50) -> List[Union[Epic, Task]]:
809
+ async def execute_jql(self, jql: str, limit: int = 50) -> builtins.list[Union[Epic, Task]]:
809
810
  """Execute a raw JQL query.
810
811
 
811
812
  Args:
@@ -830,7 +831,7 @@ class JiraAdapter(BaseAdapter[Union[Epic, Task]]):
830
831
  issues = data.get("issues", [])
831
832
  return [self._issue_to_ticket(issue) for issue in issues]
832
833
 
833
- async def get_sprints(self, board_id: Optional[int] = None) -> List[Dict[str, Any]]:
834
+ async def get_sprints(self, board_id: Optional[int] = None) -> builtins.list[dict[str, Any]]:
834
835
  """Get active sprints for a board (requires JIRA Software).
835
836
 
836
837
  Args: