krita-cli 1.0.0__tar.gz → 1.0.1__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.
Files changed (200) hide show
  1. krita_cli-1.0.1/.codex-plugin/agents/pelican-bike-illustrator.md +70 -0
  2. krita_cli-1.0.1/.codex-plugin/plugin.json +8 -0
  3. krita_cli-1.0.1/.codex-plugin/skills/pelican-bike-drawing/SKILL.md +125 -0
  4. krita_cli-1.0.1/.codex-plugin/skills/pelican-bike-drawing/references/pelican-anatomy.md +32 -0
  5. {krita_cli-1.0.0 → krita_cli-1.0.1}/.github/workflows/ci.yml +13 -2
  6. {krita_cli-1.0.0 → krita_cli-1.0.1}/PKG-INFO +22 -6
  7. {krita_cli-1.0.0 → krita_cli-1.0.1}/README.md +17 -1
  8. {krita_cli-1.0.0 → krita_cli-1.0.1}/conda-recipe/meta.yaml +2 -1
  9. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/windows_testing_20260406/metadata.json +1 -0
  10. krita_cli-1.0.1/conductor/tracks/windows_testing_20260406/plan.md +35 -0
  11. krita_cli-1.0.1/conductor/tracks/windows_testing_20260406/spec.md +31 -0
  12. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks.md +7 -0
  13. {krita_cli-1.0.0 → krita_cli-1.0.1}/krita-plugin/kritamcp/__init__.py +61 -15
  14. krita_cli-1.0.1/notes/pelican-bike-learning-log.md +65 -0
  15. {krita_cli-1.0.0 → krita_cli-1.0.1}/pyproject.toml +6 -5
  16. krita_cli-1.0.1/scripts/windows_preflight.py +125 -0
  17. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_client/client.py +4 -0
  18. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/e2e/conftest.py +41 -0
  19. krita_cli-1.0.1/tests/e2e/krita_driver.py +296 -0
  20. krita_cli-1.0.1/tests/e2e/test_krita_live.py +121 -0
  21. {krita_cli-1.0.0 → krita_cli-1.0.1}/uv.lock +47 -0
  22. krita_cli-1.0.0/conductor/tracks/windows_testing_20260406/plan.md +0 -5
  23. krita_cli-1.0.0/conductor/tracks/windows_testing_20260406/spec.md +0 -24
  24. {krita_cli-1.0.0 → krita_cli-1.0.1}/.github/skills/krita-mcp.md +0 -0
  25. {krita_cli-1.0.0 → krita_cli-1.0.1}/.gitignore +0 -0
  26. {krita_cli-1.0.0 → krita_cli-1.0.1}/.pre-commit-config.yaml +0 -0
  27. {krita_cli-1.0.0 → krita_cli-1.0.1}/.python-version +0 -0
  28. {krita_cli-1.0.0 → krita_cli-1.0.1}/LICENSE +0 -0
  29. {krita_cli-1.0.0 → krita_cli-1.0.1}/SECRETS.md +0 -0
  30. {krita_cli-1.0.0 → krita_cli-1.0.1}/benchmarks/test_rendering.py +0 -0
  31. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/cli_command_grouping_20260406/index.md +0 -0
  32. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/cli_command_grouping_20260406/metadata.json +0 -0
  33. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/cli_command_grouping_20260406/plan.md +0 -0
  34. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/cli_command_grouping_20260406/spec.md +0 -0
  35. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/command_history_replay_20260405/index.md +0 -0
  36. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/command_history_replay_20260405/metadata.json +0 -0
  37. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/command_history_replay_20260405/plan.md +0 -0
  38. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/command_history_replay_20260405/spec.md +0 -0
  39. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/e2e_test_infrastructure_20260406/index.md +0 -0
  40. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/e2e_test_infrastructure_20260406/metadata.json +0 -0
  41. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/e2e_test_infrastructure_20260406/plan.md +0 -0
  42. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/e2e_test_infrastructure_20260406/spec.md +0 -0
  43. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/mcp_tool_discovery_20260406/index.md +0 -0
  44. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/mcp_tool_discovery_20260406/metadata.json +0 -0
  45. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/mcp_tool_discovery_20260406/plan.md +0 -0
  46. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/mcp_tool_discovery_20260406/spec.md +0 -0
  47. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/protocol_versioning_v2_20260406/index.md +0 -0
  48. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/protocol_versioning_v2_20260406/metadata.json +0 -0
  49. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/protocol_versioning_v2_20260406/plan.md +0 -0
  50. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/protocol_versioning_v2_20260406/spec.md +0 -0
  51. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/rollback_mechanisms_20260405/index.md +0 -0
  52. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/rollback_mechanisms_20260405/metadata.json +0 -0
  53. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/rollback_mechanisms_20260405/plan.md +0 -0
  54. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/rollback_mechanisms_20260405/spec.md +0 -0
  55. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/security_limits_validation_20260406/index.md +0 -0
  56. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/security_limits_validation_20260406/metadata.json +0 -0
  57. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/security_limits_validation_20260406/plan.md +0 -0
  58. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/security_limits_validation_20260406/spec.md +0 -0
  59. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_advanced_features_20260406/index.md +0 -0
  60. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_advanced_features_20260406/metadata.json +0 -0
  61. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_advanced_features_20260406/plan.md +0 -0
  62. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_advanced_features_20260406/spec.md +0 -0
  63. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_clipping_integration_20260406/index.md +0 -0
  64. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_clipping_integration_20260406/metadata.json +0 -0
  65. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_clipping_integration_20260406/plan.md +0 -0
  66. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_clipping_integration_20260406/spec.md +0 -0
  67. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_persistence_20260406/index.md +0 -0
  68. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_persistence_20260406/metadata.json +0 -0
  69. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_persistence_20260406/plan.md +0 -0
  70. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_persistence_20260406/spec.md +0 -0
  71. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_quality_coverage_20260406/index.md +0 -0
  72. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_quality_coverage_20260406/metadata.json +0 -0
  73. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_quality_coverage_20260406/plan.md +0 -0
  74. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_quality_coverage_20260406/spec.md +0 -0
  75. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_transforms_modifiers_20260406/index.md +0 -0
  76. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_transforms_modifiers_20260406/metadata.json +0 -0
  77. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_transforms_modifiers_20260406/plan.md +0 -0
  78. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_transforms_modifiers_20260406/spec.md +0 -0
  79. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/code_styleguides/python.md +0 -0
  80. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/index.md +0 -0
  81. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/product-guidelines.md +0 -0
  82. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/product.md +0 -0
  83. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tech-stack.md +0 -0
  84. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/implement_batch_operations_endpoint_20260405/index.md +0 -0
  85. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/implement_batch_operations_endpoint_20260405/metadata.json +0 -0
  86. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/implement_batch_operations_endpoint_20260405/plan.md +0 -0
  87. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/implement_batch_operations_endpoint_20260405/spec.md +0 -0
  88. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/performance_benchmarking_ci_20260406/index.md +0 -0
  89. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/performance_benchmarking_ci_20260406/metadata.json +0 -0
  90. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/performance_benchmarking_ci_20260406/plan.md +0 -0
  91. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/performance_benchmarking_ci_20260406/spec.md +0 -0
  92. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/selection_tools_20260406/index.md +0 -0
  93. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/selection_tools_20260406/metadata.json +0 -0
  94. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/selection_tools_20260406/plan.md +0 -0
  95. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/selection_tools_20260406/spec.md +0 -0
  96. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/windows_testing_20260406/index.md +0 -0
  97. {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/workflow.md +0 -0
  98. {krita_cli-1.0.0 → krita_cli-1.0.1}/fix_cli_tests.py +0 -0
  99. {krita_cli-1.0.0 → krita_cli-1.0.1}/krita-plugin/kritamcp/history_store.py +0 -0
  100. {krita_cli-1.0.0 → krita_cli-1.0.1}/krita-plugin/kritamcp/payload_validator.py +0 -0
  101. {krita_cli-1.0.0 → krita_cli-1.0.1}/krita-plugin/kritamcp/rate_limiter.py +0 -0
  102. {krita_cli-1.0.0 → krita_cli-1.0.1}/krita-plugin/kritamcp/snapshot_store.py +0 -0
  103. {krita_cli-1.0.0 → krita_cli-1.0.1}/krita-plugin/kritamcp.desktop +0 -0
  104. {krita_cli-1.0.0 → krita_cli-1.0.1}/renovate.json +0 -0
  105. {krita_cli-1.0.0 → krita_cli-1.0.1}/requirements.txt +0 -0
  106. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/__init__.py +0 -0
  107. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/_shared.py +0 -0
  108. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/app.py +0 -0
  109. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/cli.py +0 -0
  110. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/__init__.py +0 -0
  111. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/batch.py +0 -0
  112. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/brush.py +0 -0
  113. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/call.py +0 -0
  114. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/canvas.py +0 -0
  115. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/color.py +0 -0
  116. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/config.py +0 -0
  117. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/file_ops.py +0 -0
  118. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/health.py +0 -0
  119. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/history_cmd.py +0 -0
  120. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/introspect.py +0 -0
  121. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/layers.py +0 -0
  122. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/navigation.py +0 -0
  123. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/replay.py +0 -0
  124. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/rollback.py +0 -0
  125. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/selection.py +0 -0
  126. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/stroke.py +0 -0
  127. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/config_cmd.py +0 -0
  128. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/history.py +0 -0
  129. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_client/__init__.py +0 -0
  130. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_client/config.py +0 -0
  131. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_client/models.py +0 -0
  132. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_client/schema.py +0 -0
  133. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_mcp/__init__.py +0 -0
  134. {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_mcp/server.py +0 -0
  135. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/__init__.py +0 -0
  136. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/conftest.py +0 -0
  137. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/e2e/__init__.py +0 -0
  138. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/e2e/test_e2e.py +0 -0
  139. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/e2e/test_e2e_mock.py +0 -0
  140. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/__init__.py +0 -0
  141. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_api_capabilities.py +0 -0
  142. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_batch_cli.py +0 -0
  143. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_batch_client.py +0 -0
  144. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_cli.py +0 -0
  145. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_cli_coverage.py +0 -0
  146. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_cli_error_paths.py +0 -0
  147. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_cli_full.py +0 -0
  148. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_cli_success.py +0 -0
  149. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_config_cli.py +0 -0
  150. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_config_cmd_cli.py +0 -0
  151. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_history_cli.py +0 -0
  152. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_history_endpoint.py +0 -0
  153. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_introspect_cli.py +0 -0
  154. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_layers_cli.py +0 -0
  155. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_coverage.py +0 -0
  156. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_error_coverage.py +0 -0
  157. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_error_result.py +0 -0
  158. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_full.py +0 -0
  159. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_remaining_tools.py +0 -0
  160. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_selection_tools.py +0 -0
  161. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_server.py +0 -0
  162. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_success.py +0 -0
  163. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_replay_cli.py +0 -0
  164. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_rollback.py +0 -0
  165. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_rollback_cli.py +0 -0
  166. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_security_limits.py +0 -0
  167. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_selection_advanced.py +0 -0
  168. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_selection_cli_coverage.py +0 -0
  169. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_selection_client.py +0 -0
  170. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_selection_persistence.py +0 -0
  171. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/property/__init__.py +0 -0
  172. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/property/test_input_sanitization.py +0 -0
  173. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/property/test_models.py +0 -0
  174. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/property/test_selection.py +0 -0
  175. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/test_phase_11.py +0 -0
  176. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/__init__.py +0 -0
  177. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_batch_models.py +0 -0
  178. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_client.py +0 -0
  179. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_client_coverage.py +0 -0
  180. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_client_internal.py +0 -0
  181. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_config.py +0 -0
  182. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_config_cmd.py +0 -0
  183. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_error_codes.py +0 -0
  184. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_history_store.py +0 -0
  185. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_mcp_batch.py +0 -0
  186. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_mcp_history_tool.py +0 -0
  187. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_models.py +0 -0
  188. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_payload_validator.py +0 -0
  189. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_replay_cmd.py +0 -0
  190. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_rollback_client.py +0 -0
  191. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_rollback_models.py +0 -0
  192. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_schema.py +0 -0
  193. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_security_config.py +0 -0
  194. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_selection_advanced_models.py +0 -0
  195. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_selection_models.py +0 -0
  196. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_selection_persistence_models.py +0 -0
  197. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_shared_coverage.py +0 -0
  198. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_snapshot_store.py +0 -0
  199. {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_type_safety_coverage.py +0 -0
  200. {krita_cli-1.0.0 → krita_cli-1.0.1}/types/krita/__init__.pyi +0 -0
@@ -0,0 +1,70 @@
1
+ ---
2
+ name: pelican-bike-illustrator
3
+ description: |-
4
+ This skill should be used when the user asks to "draw a pelican on a bike", "turn pelican reference photos into a drawing", "fix a rough Krita sketch", or "build a reference-based animal illustration plan". Examples:
5
+
6
+ <example>
7
+ Context: The user wants a playful bird illustration and has provided pelican photos.
8
+ user: "Draw me a pelican on a bike."
9
+ assistant: "Use the pelican-bike-illustrator agent to collect references, extract the silhouette, and produce a concise Krita batch plan before painting."
10
+ </example>
11
+
12
+ <example>
13
+ Context: The user is unhappy with a rough first pass and wants a better result.
14
+ user: "That drawing is bad. Use pictures of pelicans and do it properly."
15
+ assistant: "Use the pelican-bike-illustrator agent to review references, identify the broken proportions, and rebuild the composition from larger shapes."
16
+ </example>
17
+
18
+ <example>
19
+ Context: The user is asking whether tracing or copying would help.
20
+ user: "Should we trace a pelican reference or copy the shape more directly?"
21
+ assistant: "Use the pelican-bike-illustrator agent to permit structural tracing from user-owned or open-licensed references, but not style copying."
22
+ </example>
23
+ model: inherit
24
+ color: magenta
25
+ tools: ["Read", "Write", "Grep", "Bash"]
26
+ ---
27
+
28
+ You are a reference-driven Krita illustration agent for animal-and-vehicle drawings.
29
+
30
+ Your job is to turn pelican reference images into a new illustration that reads clearly at thumbnail size and remains original.
31
+
32
+ **Core responsibilities**
33
+
34
+ 1. Inspect reference images for structure, proportion, silhouette, and pose.
35
+ 2. Separate subject anatomy from stylistic treatment.
36
+ 3. Decide when structural tracing is useful and when it is not.
37
+ 4. Build or revise Krita CLI batch commands that favor readability over detail.
38
+ 5. Export versioned outputs and compare them against the references.
39
+
40
+ **Working rules**
41
+
42
+ - Use user-provided, public-domain, or clearly licensed references when tracing.
43
+ - Treat tracing as an anatomy and placement aid, not as a substitute for drawing.
44
+ - Do not copy a living artist's style. Preserve only high-level energy such as bold shapes or playful proportions.
45
+ - Prefer large shapes, strong contrast, and simple geometry when the image must be understood quickly.
46
+ - If the bike is unclear, strengthen the wheel/frame separation before adding more detail.
47
+
48
+ **Analysis process**
49
+
50
+ 1. Review the reference notes and identify the pelican's main masses.
51
+ 2. Identify what makes the image read as a bike: wheels, frame, saddle, and handlebar geometry.
52
+ 3. Draft a shape-first composition plan.
53
+ 4. If a drawing already exists, diagnose why it reads poorly: silhouette, overlap, proportion, contrast, or complexity.
54
+ 5. Produce the smallest useful batch of changes.
55
+ 6. Export a versioned image and compare the result against the references.
56
+
57
+ **Output format**
58
+
59
+ When asked to draw, return:
60
+
61
+ - a short plan,
62
+ - the key visual corrections,
63
+ - the Krita CLI/batch commands or file edits required,
64
+ - a brief note on what to check after export.
65
+
66
+ **Edge cases**
67
+
68
+ - If references are missing, ask for one or choose open-licensed images first.
69
+ - If the source is a living artist's style request, convert it into a high-level mood description instead of copying the style.
70
+ - If the first pass is unreadable, simplify the geometry and increase separation between body, wheels, and frame.
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "pelican-bike-drawing",
3
+ "interface": {
4
+ "displayName": "Pelican Bike Drawing"
5
+ },
6
+ "version": "0.1.0",
7
+ "description": "Reference-driven Krita drawing workflow for pelicans on bicycles."
8
+ }
@@ -0,0 +1,125 @@
1
+ ---
2
+ name: pelican-bike-drawing
3
+ description: This skill should be used when the user asks to "draw a pelican on a bike", "sketch a bird on a bicycle", "use pelican reference photos", "trace a bird reference for Krita", or "improve a rough animal drawing with references".
4
+ version: "0.8.8"
5
+ ---
6
+
7
+ # Pelican Bike Drawing
8
+
9
+ Use this skill to turn reference images into a clean Krita illustration of a pelican on a bicycle. Keep the result original, readable, and simple enough to work well in a CLI-driven drawing workflow.
10
+
11
+ ## Core Approach
12
+
13
+ Start with references before drawing anything.
14
+
15
+ 1. Gather 2 to 4 references that show the subject clearly.
16
+ 2. Prefer user-provided images, public-domain images, or clearly licensed stock photos.
17
+ 3. Extract the subject structure before thinking about style.
18
+ 4. Build the drawing from broad shapes first, then add details.
19
+ 5. Export a versioned result and review it against the references.
20
+
21
+ ## What To Look For In Pelican References
22
+
23
+ Identify the parts that matter most for a readable silhouette:
24
+
25
+ - A large rounded body.
26
+ - A high-set head with a small eye.
27
+ - A long horizontal beak with a visible pouch.
28
+ - A short neck and a smooth body transition.
29
+ - Thin legs that can hang below the body.
30
+ - Strong contrast between body mass and the narrow beak.
31
+
32
+ When the subject is on a bike, keep the bicycle clearly separate from the bird:
33
+
34
+ - Make both wheels obvious.
35
+ - Leave enough space for the frame to read as a triangle or bar system.
36
+ - Keep the pelican body perched above the frame, not merged into it.
37
+ - Use thick, simple frame strokes instead of tiny mechanical detail.
38
+
39
+ ## When Tracing Is Worth Considering
40
+
41
+ Use tracing only for structure and proportion.
42
+
43
+ - Trace silhouettes, body masses, and the bike geometry when the goal is accurate placement.
44
+ - Trace only from images that are user-owned, user-provided, or clearly open licensed.
45
+ - Avoid copying copyrighted artwork or imitating a living artist's style.
46
+ - Convert traced structure into a new drawing instead of reproducing the source image.
47
+
48
+ Treat tracing as an anatomy shortcut, not as a final look.
49
+
50
+ ## Suggested Workflow
51
+
52
+ 1. Collect references and isolate the most useful one or two views.
53
+ 2. Note the main geometry: body oval, head circle, beak rectangle, wheel circles, frame bars.
54
+ 3. Draft the composition as simple shapes on a fresh canvas.
55
+ 4. Check the image at thumbnail size.
56
+ 5. If the bike is unclear, thicken the frame and simplify the body overlap.
57
+ 6. If the pelican is unclear, enlarge the beak, raise the head, and separate the neck from the torso.
58
+ 7. Export the canvas with a versioned filename.
59
+ 8. Compare the export against the references and decide what to fix next.
60
+
61
+ ## Krita CLI Findings
62
+
63
+ These are workflow-specific lessons from the actual pelican-on-bike iteration history in this repo.
64
+
65
+ - The `draw_shape` `line` primitive survives export more reliably than freehand `stroke` for bike frames.
66
+ - If the bike must read instantly, spend the command budget on frame clarity before adding extra bird detail.
67
+ - The plugin batch limit is 50 commands, so reserve duplicates only for the lines that matter most.
68
+ - When a line needs to read thicker, duplicate it with a 1 to 2 pixel offset instead of assuming brush strokes will export cleanly.
69
+ - Keep the pelican body high enough that the top tube, seat tube, and down tube are still visible underneath.
70
+ - Treat the beak and pouch as separate shape systems: a yellow beak block plus orange pouch lines reads better than one generic orange stroke.
71
+ - Test exports often. A composition that seems correct in the command plan can still fail visually in the PNG.
72
+ - Once the frame is readable, the next quality gain comes from proportion: compact frame geometry and a believable seat/handlebar relationship look better than simply adding more lines.
73
+ - The legs should terminate clearly on pedals; if they overshoot or bend too loosely, the rider pose becomes the weakest part of the image.
74
+ - Small asymmetry helps. Even in a minimal drawing, offset pedal heights and slightly different leg paths make the rider read as posed instead of pinned in place.
75
+ - After pose, the next improvement is contour hierarchy. A second neck or pouch contour can make the head-to-body transition feel more anatomical without forcing a more detailed style.
76
+ - Keep that contour hierarchy simple. A pair of clean long contours reads better than several shorter neck segments once the composition is already working.
77
+ - Head scale and beak length need restraint. Once the rider pose is working, slightly smaller head mass and a shorter beak can make the bird feel more unified instead of top-heavy.
78
+ - When the proportions are already close, one strategic connector contour at the highest-value join can improve the drawing more than another full silhouette rewrite.
79
+ - After the head/body join is working, controlled overlap becomes the next lever. Lowering the upper mass slightly can make the pelican feel seated on the bike instead of floating, but only if the top tube and frame triangle remain readable.
80
+ - Once overlap is working, the next gains are often micro-adjustments. Small changes to head attitude and exact foot landing can improve the sense of intention more than any additional contour.
81
+ - After micro-adjustments, look for calmness. A slightly lower upper mass and a quieter head position can make the drawing feel more settled without adding any new features.
82
+ - After calmness is working, the next lever is character, not structure. Tiny changes to facial proportion or a single tail gesture can add personality without destabilizing the silhouette.
83
+ - After character is working, proportion restraint becomes the next lever again. Small reductions in head or beak mass can make the bird feel cleaner and less blunt without changing the pose.
84
+ - After restraint, look for elegance rather than reduction for its own sake. Slightly cleaner spacing around the face can make the bird feel more refined without making it smaller in every direction.
85
+ - After elegance, look for poise. Tiny shifts in head position and face spacing can change the bird's demeanor without asking the composition to do anything structurally different.
86
+ - After poise, look for coherence. Slightly tighter alignment between the head, eye, and beak can make the face feel more unified without changing the perch or bike.
87
+
88
+ ## Failure Review
89
+
90
+ When a drawing looks bad, diagnose the failure before redrawing:
91
+
92
+ - If it looks like a blob, the silhouette is too merged.
93
+ - If it looks like a bird but not a pelican, the beak is too short or too generic.
94
+ - If it looks like a pelican but not a bike, the wheels and frame are too weak.
95
+ - If it looks stiff, the pose is too symmetrical.
96
+ - If it looks overworked, remove detail and return to larger shapes.
97
+
98
+ ## Version-Specific Lessons
99
+
100
+ - `version1` / `final`: the bird and bike read as disconnected objects and the bicycle structure is too weak.
101
+ - `v3`: stronger body and wheel mass, but the bike frame is still buried under the pelican.
102
+ - `v4`: frame geometry exists in the command plan, but the body overlap still prevents fast readability.
103
+ - `v5`: better composition separation, but it still relies too much on primitives that do not survive export well enough.
104
+ - `v6`: first structurally successful pass because the bike moved to explicit line shapes.
105
+ - `v7`: improved `v6` by thickening the most important frame edges and preserving clearer separation between pelican, seat, and frame.
106
+ - `v8`: refined the geometry rather than just the thickness, using a tighter frame and cleaner seat/handlebar placement for a more coherent bike.
107
+ - `v9`: kept the compact `v8` geometry but improved the riding pose with more asymmetric leg placement.
108
+ - `v10`: kept the `v9` pose and added a clearer neck/pouch contour so the pelican reads as a bird with anatomy rather than a body plus a separate head.
109
+ - `v11`: simplified the neck/pouch treatment from `v10`, proving that cleaner long contours beat fussier segmented ones for this style.
110
+ - `v12`: refined scale rather than structure, showing that a slightly smaller head and shorter beak can improve unity without changing the working composition.
111
+ - `v13`: showed that once the body, head, and bike already work, a single deliberate connector contour can improve head-to-body integration better than another large redraw.
112
+ - `v14`: showed that a slightly lower, more perched body placement can improve the rider read, provided the bike frame still stays visible underneath.
113
+ - `v15`: showed that, after the perch is working, tiny refinements to head attitude and pedal contact can produce a cleaner, more intentional rider read without changing the overall composition.
114
+ - `v16`: showed that tiny placement changes can also affect mood; a calmer head and slightly more settled body placement made the rider feel less twitchy while preserving the same simple structure.
115
+ - `v17`: showed that, after calmness is established, very small face and tail adjustments can add character while keeping the same stable bike and body arrangement.
116
+ - `v18`: showed that character can then be tightened through restraint; a slightly smaller head/beak relationship made the pelican feel cleaner without needing any new detail.
117
+ - `v19`: showed that restraint can become elegance; slightly cleaner head and beak spacing made the bird feel more refined without changing the bike or perch.
118
+ - `v20`: showed that elegance can then become poise; tiny head-placement changes made the pelican feel more self-possessed while preserving the same stable setup.
119
+ - `v21`: showed that poise can be tightened into coherence; a slightly tighter head, eye, and beak relationship made the face feel more unified while preserving the same calm baseline.
120
+
121
+ ## Additional Resources
122
+
123
+ ### Reference Notes
124
+
125
+ - `references/pelican-anatomy.md` - Pelican shape notes, reference checklist, and license-safe usage guidance.
@@ -0,0 +1,32 @@
1
+ # Pelican Anatomy Notes
2
+
3
+ Use these notes as a quick structure checklist before drawing.
4
+
5
+ ## Visual Anchors
6
+
7
+ - Pelicans read best as a body-first silhouette with a long beak.
8
+ - The head usually sits high above the torso.
9
+ - The body is broad and rounded, not narrow.
10
+ - The bill pouch is a major visual cue; if it disappears, the bird becomes generic.
11
+ - Legs are thin relative to the body and should not compete with the torso.
12
+
13
+ ## Composition Notes For A Bike Pose
14
+
15
+ - Keep the wheels large enough to read instantly.
16
+ - Keep the bike frame simple and geometric.
17
+ - Let the bird occupy most of the upper mass.
18
+ - Avoid tiny spokes and mechanical clutter unless the user explicitly wants detail.
19
+ - Use overlap intentionally so the bird appears seated on the bike rather than floating above it.
20
+
21
+ ## Reference Usage
22
+
23
+ - Prefer user-provided, public-domain, or clearly licensed photos.
24
+ - Use reference images to understand proportion, pose, and silhouette.
25
+ - Treat tracing as a structural aid only.
26
+ - Redraw the result as a new illustration instead of copying the source photo.
27
+
28
+ ## Useful Reference Sources
29
+
30
+ - Wikimedia Commons pelican photo: https://commons.wikimedia.org/wiki/File:Pelican.(Pelecanus_conspicillatus)_(14244840947).jpg
31
+ - Unsplash side-profile pelican photo: https://unsplash.com/photos/a-pelican-with-a-small-fish-in-its-beak-FusF5pjKLmQ
32
+ - Wikipedia pelican anatomy notes: https://en.wikipedia.org/wiki/Dalmatian_pelican
@@ -91,6 +91,8 @@ jobs:
91
91
  path: dist/
92
92
  - name: Publish to PyPI
93
93
  uses: pypa/gh-action-pypi-publish@release/v1
94
+ with:
95
+ skip-existing: true
94
96
 
95
97
  publish-conda:
96
98
  name: Publish to Conda
@@ -107,7 +109,16 @@ jobs:
107
109
  channels: conda-forge,defaults
108
110
  - name: Build and Upload to Anaconda
109
111
  shell: bash -l {0}
112
+ env:
113
+ ANACONDA_API_TOKEN: ${{ secrets.ANACONDA_API_TOKEN }}
110
114
  run: |
111
- conda install -y anaconda-client conda-build
115
+ conda install -y conda-build
116
+ pip install anaconda-client
112
117
  conda build conda-recipe/ --output-folder dist/conda
113
- anaconda -t ${{ secrets.ANACONDA_API_TOKEN }} upload dist/conda/noarch/krita-cli-*.tar.bz2 --force
118
+ PKG_FILE=$(find dist/conda -name "krita-cli-*.tar.bz2" -o -name "krita-cli-*.conda" | head -n 1)
119
+ if [ -z "$PKG_FILE" ]; then
120
+ echo "No package file found!"
121
+ exit 1
122
+ fi
123
+ echo "Uploading $PKG_FILE"
124
+ anaconda upload "$PKG_FILE" --force
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: krita-cli
3
- Version: 1.0.0
3
+ Version: 1.0.1
4
4
  Summary: SOTA CLI + MCP server for programmatic painting in Krita
5
- Project-URL: Homepage, https://github.com/github/krita-cli
6
- Project-URL: Repository, https://github.com/github/krita-cli
7
- Project-URL: Issues, https://github.com/github/krita-cli/issues
8
- Project-URL: Changelog, https://github.com/github/krita-cli/blob/master/CHANGELOG.md
5
+ Project-URL: Homepage, https://github.com/edithatogo/krita-cli
6
+ Project-URL: Repository, https://github.com/edithatogo/krita-cli
7
+ Project-URL: Issues, https://github.com/edithatogo/krita-cli/issues
8
+ Project-URL: Changelog, https://github.com/edithatogo/krita-cli/blob/master/CHANGELOG.md
9
9
  Author: Krita MCP Contributors
10
10
  License-Expression: MIT
11
11
  License-File: LICENSE
@@ -39,7 +39,7 @@ This subproject provides the core implementation of the Krita-MCP ecosystem, inc
39
39
 
40
40
  ## 🛠️ Components
41
41
 
42
- 1. **Krita Plugin** (`krita-plugin/`) — A Python plugin for Krita that exposes a thread-safe HTTP server on `localhost:5678`.
42
+ 1. **Krita Plugin** (`krita-plugin/`) — A Python plugin for Krita that exposes a thread-safe HTTP server on `localhost` using the configured port (default `5678`).
43
43
  2. **MCP Server** (`src/krita_mcp/`) — A FastMCP server exposing 40+ painting and manipulation tools.
44
44
  3. **Krita CLI** (`src/krita_cli/`) — A Typer-based command line interface for human operators.
45
45
  4. **Krita Client** (`src/krita_client/`) — A reusable, fully-typed Python library for Krita automation.
@@ -60,6 +60,22 @@ Enable **"Krita MCP Bridge"** in Krita (Configure Krita → Python Plugin Manage
60
60
  uv sync
61
61
  ```
62
62
 
63
+ ### 3. Windows Validation Checklist
64
+ Before debugging the plugin, make sure the local Python runtime is healthy:
65
+
66
+ 1. `python -c "import ssl, ctypes"` must succeed.
67
+ 2. `python scripts/windows_preflight.py` should report a clean Windows setup.
68
+ 3. `uv run pytest tests/e2e/test_e2e_mock.py` should pass without Krita.
69
+ 4. The plugin files must exist under `%APPDATA%\krita\pykrita\kritamcp\`.
70
+ 5. Krita must be restarted after enabling **Krita MCP Bridge** in the Plugin Manager.
71
+ 6. The plugin should expose `http://127.0.0.1:<configured-port>/health` once Krita finishes loading.
72
+
73
+ If Krita starts but `/health` never appears, check the diagnostic artifacts in your home directory:
74
+ - `~/kritamcp_startup.log`
75
+ - `~/kritamcp_diag.log`
76
+
77
+ If those logs are missing entirely, the plugin likely was not enabled or did not load during startup.
78
+
63
79
  ## 🔧 CLI Commands
64
80
 
65
81
  The `krita` CLI is grouped into logical subcommands:
@@ -6,7 +6,7 @@ This subproject provides the core implementation of the Krita-MCP ecosystem, inc
6
6
 
7
7
  ## 🛠️ Components
8
8
 
9
- 1. **Krita Plugin** (`krita-plugin/`) — A Python plugin for Krita that exposes a thread-safe HTTP server on `localhost:5678`.
9
+ 1. **Krita Plugin** (`krita-plugin/`) — A Python plugin for Krita that exposes a thread-safe HTTP server on `localhost` using the configured port (default `5678`).
10
10
  2. **MCP Server** (`src/krita_mcp/`) — A FastMCP server exposing 40+ painting and manipulation tools.
11
11
  3. **Krita CLI** (`src/krita_cli/`) — A Typer-based command line interface for human operators.
12
12
  4. **Krita Client** (`src/krita_client/`) — A reusable, fully-typed Python library for Krita automation.
@@ -27,6 +27,22 @@ Enable **"Krita MCP Bridge"** in Krita (Configure Krita → Python Plugin Manage
27
27
  uv sync
28
28
  ```
29
29
 
30
+ ### 3. Windows Validation Checklist
31
+ Before debugging the plugin, make sure the local Python runtime is healthy:
32
+
33
+ 1. `python -c "import ssl, ctypes"` must succeed.
34
+ 2. `python scripts/windows_preflight.py` should report a clean Windows setup.
35
+ 3. `uv run pytest tests/e2e/test_e2e_mock.py` should pass without Krita.
36
+ 4. The plugin files must exist under `%APPDATA%\krita\pykrita\kritamcp\`.
37
+ 5. Krita must be restarted after enabling **Krita MCP Bridge** in the Plugin Manager.
38
+ 6. The plugin should expose `http://127.0.0.1:<configured-port>/health` once Krita finishes loading.
39
+
40
+ If Krita starts but `/health` never appears, check the diagnostic artifacts in your home directory:
41
+ - `~/kritamcp_startup.log`
42
+ - `~/kritamcp_diag.log`
43
+
44
+ If those logs are missing entirely, the plugin likely was not enabled or did not load during startup.
45
+
30
46
  ## 🔧 CLI Commands
31
47
 
32
48
  The `krita` CLI is grouped into logical subcommands:
@@ -1,5 +1,5 @@
1
1
  {% set name = 'krita-cli' %}
2
- {% set version = '1.0.0' %}
2
+ {% set version = '1.0.1' %}
3
3
 
4
4
  package:
5
5
  name: {{ name|lower }}
@@ -9,6 +9,7 @@ source:
9
9
  path: ..
10
10
 
11
11
  build:
12
+ noarch: python
12
13
  number: 0
13
14
  script: {{ PYTHON }} -m pip install . --no-deps -vv
14
15
  entry_points:
@@ -2,6 +2,7 @@
2
2
  "track_id": "windows_testing_20260406",
3
3
  "created_at": "2026-04-06",
4
4
  "status": "pending",
5
+ "updated_at": "2026-04-18T00:00:00Z",
5
6
  "phase": "12",
6
7
  "priority": "medium"
7
8
  }
@@ -0,0 +1,35 @@
1
+ # Implementation Plan: Windows Krita Validation & Plugin-Load Reliability
2
+
3
+ ## Phase 1: Runtime Preflight
4
+ - Detect broken Windows Python runtimes before collection by importing native modules that fail in the current venv (`ssl`, `ctypes`).
5
+ - Add a stdlib-only setup sanity check (`scripts/windows_preflight.py`) that explains how to repair the environment when the local interpreter is broken.
6
+ - Keep the preflight separate from the main test suite so the failure mode is obvious.
7
+
8
+ ## Phase 2: CLI and MCP Validation
9
+ - Verify the CLI imports and runs on a healthy Windows Python runtime.
10
+ - Verify the MCP client/server packages import cleanly on the same runtime.
11
+ - Keep the mock E2E suite as the default fallback for repo validation.
12
+
13
+ ## Phase 3: Plugin Deployment and Enablement Diagnostics
14
+ - Verify the Krita plugin is copied into `%APPDATA%\krita\pykrita\` with both the `.desktop` file and the `kritamcp/` package.
15
+ - Surface a clear message when Krita is running but `/health` never appears.
16
+ - Distinguish between:
17
+ - plugin files missing or copied to the wrong location,
18
+ - plugin present but not enabled in Krita's Python Plugin Manager,
19
+ - plugin loaded but failing during import/startup,
20
+ - or a config/port mismatch.
21
+
22
+ ## Phase 4: Live Krita Smoke Validation
23
+ - Keep a live Krita driver for Windows that launches Krita, opens a canvas, and waits for the HTTP health endpoint.
24
+ - Exercise a minimal live smoke path: health, new canvas, one paint action, and one export or batch action.
25
+ - Capture the existing startup log and diagnostic script outputs as the canonical troubleshooting path.
26
+
27
+ ## Phase 5: Documentation and Registry Updates
28
+ - Update the Windows setup guide so the required workflow is explicit:
29
+ - healthy Python runtime,
30
+ - `uv sync`,
31
+ - copy plugin files,
32
+ - enable `Krita MCP Bridge`,
33
+ - restart Krita,
34
+ - verify `/health`.
35
+ - Keep `krita-mcp/conductor/tracks.md` and the parent Conductor index pointed at this track so future debugging stays in one place.
@@ -0,0 +1,31 @@
1
+ # Track Specification: Windows Krita Validation & Plugin-Load Reliability
2
+
3
+ ## Problem Statement
4
+
5
+ The Windows path for Krita MCP is not fully validated end to end. The project has a broken local Python runtime in the validation environment, the plugin files can be copied into `%APPDATA%\krita\pykrita`, and Krita can still fail to expose the HTTP server. That means the failure mode is ambiguous: the plugin may be missing, disabled in Krita's Plugin Manager, failing during import/startup, or simply bound to the wrong port.
6
+
7
+ Without a dedicated Windows track, the repo cannot reliably distinguish:
8
+
9
+ 1. a broken Python/CLI/MCP environment,
10
+ 2. a correct install with the plugin disabled,
11
+ 3. a plugin startup/import failure,
12
+ 4. or a valid live Krita session where the health endpoint is reachable.
13
+
14
+ ## Requirements
15
+
16
+ 1. **Runtime Preflight** - Add a fast validation step that detects broken native Python dependencies before test collection. The known failure mode is `_ssl` / `_ctypes` import failure in the project venv.
17
+ 2. **CLI and MCP Validation** - Verify the CLI and MCP packages import and run on a healthy Windows Python runtime.
18
+ 3. **Plugin Deployment Check** - Verify the Krita plugin files are copied into `%APPDATA%\krita\pykrita\` with the expected `.desktop` file and package layout.
19
+ 4. **Enablement Diagnostics** - When Krita is running but `/health` is unavailable, report whether the likely issue is plugin disablement, import/startup failure, or a port/config mismatch.
20
+ 5. **Live Krita Smoke** - Keep a real Windows Krita smoke suite that exercises health, canvas creation, one paint action, and one export/batch path.
21
+ 6. **Mock E2E Coverage** - Keep the mock server E2E path as the default repo-level fallback so validation still runs without Krita.
22
+ 7. **Setup Docs** - Document the required Windows workflow: healthy Python runtime, `uv sync`, plugin copy target, Plugin Manager enablement, restart, and health verification.
23
+
24
+ ## Acceptance Criteria
25
+
26
+ - [ ] A Windows preflight fails early when native Python imports are broken.
27
+ - [ ] CLI and MCP tests run on a healthy Windows runtime.
28
+ - [ ] The plugin install target and enablement step are documented clearly.
29
+ - [ ] Live Krita failures distinguish disablement from startup/import failure.
30
+ - [ ] Mock E2E continues to run without a real Krita session.
31
+ - [ ] Windows setup guidance explains how to verify `/health` end to end.
@@ -9,6 +9,13 @@ This file tracks all major tracks for the project. Each track has its own detail
9
9
  - [x] **Track: Selection Tools**
10
10
  *Link: [./tracks/selection_tools_20260406/](./tracks/selection_tools_20260406/)*
11
11
 
12
+ - [ ] **Track: Windows Krita Validation & Plugin-Load Reliability**
13
+ *Link: [./tracks/windows_testing_20260406/](./tracks/windows_testing_20260406/)*
14
+ - Runtime preflight for broken Windows Python installs
15
+ - CLI and MCP validation on a healthy runtime
16
+ - Krita plugin deployment and enablement diagnostics
17
+ - Live Krita smoke validation and troubleshooting
18
+
12
19
  **Archived Tracks:**
13
20
  - [x] ~~Rollback Mechanisms~~ → [archive/rollback_mechanisms_20260405/](./archive/rollback_mechanisms_20260405/)
14
21
  - [x] ~~Command History & Replay~~ → [archive/command_history_replay_20260405/](./archive/command_history_replay_20260405/)
@@ -23,18 +23,46 @@ import os
23
23
  import sys
24
24
  import threading
25
25
  import uuid
26
- from http.server import BaseHTTPRequestHandler, HTTPServer
26
+ from http.server import BaseHTTPRequestHandler, HTTPServer, ThreadingHTTPServer
27
27
  from typing import Any
28
+ from urllib.parse import urlparse
29
+
30
+ try:
31
+ with open(os.path.expanduser("~/kritamcp_startup.log"), "a") as _f:
32
+ import datetime as _dt
33
+ _f.write(f"[{_dt.datetime.now().isoformat()}] kritamcp import begin as {__name__} (Python {sys.version})\n")
34
+ except Exception:
35
+ pass
28
36
 
29
37
  from krita import *
30
- from PyQt5.QtCore import QThread, QTimer, QPolygon, QPoint
31
- from PyQt5.QtGui import QColor
38
+ from PyQt5.QtCore import QThread, QTimer, QPoint
39
+ from PyQt5.QtGui import QColor, QPolygon
32
40
 
33
41
  from kritamcp.history_store import CommandHistoryStore
34
42
  from kritamcp.payload_validator import validate_payload_size, MAX_PAYLOAD_SIZE
35
43
  from kritamcp.rate_limiter import RateLimiter
36
44
  from kritamcp.snapshot_store import BatchSnapshotStore
37
45
 
46
+ # -- Startup diagnostics (file log so failures are visible outside Krita) ----
47
+ _DIAG_LOG = os.path.expanduser("~/kritamcp_startup.log")
48
+ def _log_diag(message: str) -> None:
49
+ try:
50
+ with open(_DIAG_LOG, "a") as _f:
51
+ import datetime as _dt
52
+ _f.write(f"[{_dt.datetime.now().isoformat()}] {message}\n")
53
+ except Exception:
54
+ pass
55
+
56
+
57
+ def _expand_user_path(path: str) -> str:
58
+ """Expand user and environment markers in a filesystem path."""
59
+ return os.path.expandvars(os.path.expanduser(path))
60
+
61
+ try:
62
+ _log_diag(f"kritamcp module loaded as {__name__} (Python {sys.version})")
63
+ except Exception:
64
+ pass
65
+
38
66
  # Try to import numpy for accelerated rendering
39
67
  try:
40
68
  import numpy as np
@@ -284,11 +312,14 @@ class ServerThread(QThread):
284
312
 
285
313
  def run(self) -> None:
286
314
  try:
287
- self.server = HTTPServer(("localhost", self.port), PaintRequestHandler)
315
+ _log_diag(f"HTTP server thread starting on port {self.port}")
316
+ self.server = ThreadingHTTPServer(("localhost", self.port), PaintRequestHandler)
288
317
  logger.info("HTTP server started on port %d", self.port)
318
+ _log_diag(f"HTTP server started on port {self.port}")
289
319
  self.server.serve_forever()
290
320
  except OSError as exc:
291
321
  logger.error("Failed to start HTTP server on port %d: %s", self.port, exc)
322
+ _log_diag(f"HTTP server failed on port {self.port}: {exc}")
292
323
 
293
324
  def stop(self) -> None:
294
325
  if self.server:
@@ -303,6 +334,7 @@ class KritaMCPExtension(Extension):
303
334
  """Main Krita extension class."""
304
335
 
305
336
  def __init__(self, parent: Any) -> None:
337
+ _log_diag("KritaMCPExtension.__init__ begin")
306
338
  super().__init__(parent)
307
339
  self.server_thread: ServerThread | None = None
308
340
  self.timer: QTimer | None = None
@@ -316,6 +348,9 @@ class KritaMCPExtension(Extension):
316
348
  # Load configuration
317
349
  self.config_path = os.path.expanduser("~/.kritamcp_config.json")
318
350
  self.load_config()
351
+ _log_diag("KritaMCPExtension.__init__ after load_config")
352
+ self._ensure_runtime_started()
353
+ _log_diag("KritaMCPExtension.__init__ end")
319
354
 
320
355
  def _detect_capabilities(self) -> dict[str, bool]:
321
356
  """Detect which selection APIs are available in this Krita version."""
@@ -348,9 +383,10 @@ class KritaMCPExtension(Extension):
348
383
  # Add Krita API version info
349
384
  try:
350
385
  from krita import Krita
351
- krita_version_str = Krita.version()
386
+ krita_instance = Krita.instance()
387
+ krita_version_str = krita_instance.version() if krita_instance else Krita.version()
352
388
  capabilities["krita_version"] = krita_version_str
353
- except (AttributeError, ImportError):
389
+ except (AttributeError, ImportError, TypeError):
354
390
  capabilities["krita_version"] = "unknown"
355
391
 
356
392
  return capabilities
@@ -386,9 +422,7 @@ class KritaMCPExtension(Extension):
386
422
  with open(krita_cli_config, encoding="utf-8") as f:
387
423
  config = json.load(f)
388
424
  SERVER_PORT = config.get("port", SERVER_PORT)
389
- CANVAS_OUTPUT_DIR = config.get(
390
- "canvas_output_dir", os.path.expanduser(config.get("canvas_output_dir", CANVAS_OUTPUT_DIR))
391
- )
425
+ CANVAS_OUTPUT_DIR = _expand_user_path(config.get("canvas_output_dir", CANVAS_OUTPUT_DIR))
392
426
  MAX_CANVAS_DIM = config.get("max_canvas_dim", MAX_CANVAS_DIM)
393
427
  MAX_BATCH_SIZE = config.get("max_batch_size", MAX_BATCH_SIZE)
394
428
  MAX_LAYERS = config.get("max_layers", MAX_LAYERS)
@@ -403,22 +437,29 @@ class KritaMCPExtension(Extension):
403
437
  with open(self.config_path, encoding="utf-8") as f:
404
438
  config = json.load(f)
405
439
  SERVER_PORT = config.get("port", SERVER_PORT)
406
- CANVAS_OUTPUT_DIR = config.get(
407
- "output_dir", os.path.expanduser(config.get("output_dir", CANVAS_OUTPUT_DIR))
408
- )
440
+ CANVAS_OUTPUT_DIR = _expand_user_path(config.get("output_dir", CANVAS_OUTPUT_DIR))
409
441
  MAX_CANVAS_DIM = config.get("max_canvas_dim", MAX_CANVAS_DIM)
410
442
  logger.info("Loaded config from %s", self.config_path)
411
443
  except Exception as e:
412
444
  logger.error("Failed to load config from %s: %s", self.config_path, e)
413
445
 
414
446
  def setup(self) -> None:
415
- pass
447
+ self._ensure_runtime_started()
416
448
 
417
449
  def createActions(self, window: Any) -> None:
418
450
  """Called when a new window is created."""
451
+ self._ensure_runtime_started()
452
+
453
+ def call(self, action: str, params: dict[str, Any] | None = None) -> dict[str, Any]:
454
+ """Backward-compatible generic dispatcher used by the live tests."""
455
+ return self.handle_command(action, params or {})
456
+
457
+ def _ensure_runtime_started(self) -> None:
458
+ """Start background runtime pieces once, regardless of Krita's callback order."""
419
459
  os.makedirs(CANVAS_OUTPUT_DIR, exist_ok=True)
420
460
 
421
461
  if self.server_thread is None:
462
+ _log_diag(f"Requested HTTP server startup on port {SERVER_PORT}")
422
463
  self.server_thread = ServerThread(SERVER_PORT)
423
464
  self.server_thread.start()
424
465
 
@@ -2161,9 +2202,14 @@ class KritaMCPExtension(Extension):
2161
2202
 
2162
2203
 
2163
2204
  # Register the extension
2164
- if __name__ != "builtins" and "pytest" not in sys.modules:
2205
+ if "pytest" not in sys.modules:
2165
2206
  try:
2166
2207
  Krita.instance().addExtension(KritaMCPExtension(Krita.instance()))
2167
- except (NameError, AttributeError):
2208
+ _log_diag("Krita.instance().addExtension completed")
2209
+ except (NameError, AttributeError) as exc:
2168
2210
  # Krita not defined or instance() not available
2211
+ _log_diag(f"Extension registration unavailable: {exc}")
2212
+ pass
2213
+ except Exception as exc:
2214
+ _log_diag(f"Extension registration failed: {exc}")
2169
2215
  pass