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.
- krita_cli-1.0.1/.codex-plugin/agents/pelican-bike-illustrator.md +70 -0
- krita_cli-1.0.1/.codex-plugin/plugin.json +8 -0
- krita_cli-1.0.1/.codex-plugin/skills/pelican-bike-drawing/SKILL.md +125 -0
- krita_cli-1.0.1/.codex-plugin/skills/pelican-bike-drawing/references/pelican-anatomy.md +32 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/.github/workflows/ci.yml +13 -2
- {krita_cli-1.0.0 → krita_cli-1.0.1}/PKG-INFO +22 -6
- {krita_cli-1.0.0 → krita_cli-1.0.1}/README.md +17 -1
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conda-recipe/meta.yaml +2 -1
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/windows_testing_20260406/metadata.json +1 -0
- krita_cli-1.0.1/conductor/tracks/windows_testing_20260406/plan.md +35 -0
- krita_cli-1.0.1/conductor/tracks/windows_testing_20260406/spec.md +31 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks.md +7 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/krita-plugin/kritamcp/__init__.py +61 -15
- krita_cli-1.0.1/notes/pelican-bike-learning-log.md +65 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/pyproject.toml +6 -5
- krita_cli-1.0.1/scripts/windows_preflight.py +125 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_client/client.py +4 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/e2e/conftest.py +41 -0
- krita_cli-1.0.1/tests/e2e/krita_driver.py +296 -0
- krita_cli-1.0.1/tests/e2e/test_krita_live.py +121 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/uv.lock +47 -0
- krita_cli-1.0.0/conductor/tracks/windows_testing_20260406/plan.md +0 -5
- krita_cli-1.0.0/conductor/tracks/windows_testing_20260406/spec.md +0 -24
- {krita_cli-1.0.0 → krita_cli-1.0.1}/.github/skills/krita-mcp.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/.gitignore +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/.pre-commit-config.yaml +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/.python-version +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/LICENSE +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/SECRETS.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/benchmarks/test_rendering.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/cli_command_grouping_20260406/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/cli_command_grouping_20260406/metadata.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/cli_command_grouping_20260406/plan.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/cli_command_grouping_20260406/spec.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/command_history_replay_20260405/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/command_history_replay_20260405/metadata.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/command_history_replay_20260405/plan.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/command_history_replay_20260405/spec.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/e2e_test_infrastructure_20260406/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/e2e_test_infrastructure_20260406/metadata.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/e2e_test_infrastructure_20260406/plan.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/e2e_test_infrastructure_20260406/spec.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/mcp_tool_discovery_20260406/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/mcp_tool_discovery_20260406/metadata.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/mcp_tool_discovery_20260406/plan.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/mcp_tool_discovery_20260406/spec.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/protocol_versioning_v2_20260406/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/protocol_versioning_v2_20260406/metadata.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/protocol_versioning_v2_20260406/plan.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/protocol_versioning_v2_20260406/spec.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/rollback_mechanisms_20260405/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/rollback_mechanisms_20260405/metadata.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/rollback_mechanisms_20260405/plan.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/rollback_mechanisms_20260405/spec.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/security_limits_validation_20260406/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/security_limits_validation_20260406/metadata.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/security_limits_validation_20260406/plan.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/security_limits_validation_20260406/spec.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_advanced_features_20260406/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_advanced_features_20260406/metadata.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_advanced_features_20260406/plan.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_advanced_features_20260406/spec.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_clipping_integration_20260406/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_clipping_integration_20260406/metadata.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_clipping_integration_20260406/plan.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_clipping_integration_20260406/spec.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_persistence_20260406/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_persistence_20260406/metadata.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_persistence_20260406/plan.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_persistence_20260406/spec.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_quality_coverage_20260406/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_quality_coverage_20260406/metadata.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_quality_coverage_20260406/plan.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_quality_coverage_20260406/spec.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_transforms_modifiers_20260406/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_transforms_modifiers_20260406/metadata.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_transforms_modifiers_20260406/plan.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/archive/selection_transforms_modifiers_20260406/spec.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/code_styleguides/python.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/product-guidelines.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/product.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tech-stack.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/implement_batch_operations_endpoint_20260405/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/implement_batch_operations_endpoint_20260405/metadata.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/implement_batch_operations_endpoint_20260405/plan.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/implement_batch_operations_endpoint_20260405/spec.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/performance_benchmarking_ci_20260406/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/performance_benchmarking_ci_20260406/metadata.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/performance_benchmarking_ci_20260406/plan.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/performance_benchmarking_ci_20260406/spec.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/selection_tools_20260406/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/selection_tools_20260406/metadata.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/selection_tools_20260406/plan.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/selection_tools_20260406/spec.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/tracks/windows_testing_20260406/index.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/conductor/workflow.md +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/fix_cli_tests.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/krita-plugin/kritamcp/history_store.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/krita-plugin/kritamcp/payload_validator.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/krita-plugin/kritamcp/rate_limiter.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/krita-plugin/kritamcp/snapshot_store.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/krita-plugin/kritamcp.desktop +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/renovate.json +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/requirements.txt +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/__init__.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/_shared.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/app.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/cli.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/__init__.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/batch.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/brush.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/call.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/canvas.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/color.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/config.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/file_ops.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/health.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/history_cmd.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/introspect.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/layers.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/navigation.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/replay.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/rollback.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/selection.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/commands/stroke.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/config_cmd.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_cli/history.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_client/__init__.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_client/config.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_client/models.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_client/schema.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_mcp/__init__.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/src/krita_mcp/server.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/__init__.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/conftest.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/e2e/__init__.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/e2e/test_e2e.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/e2e/test_e2e_mock.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/__init__.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_api_capabilities.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_batch_cli.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_batch_client.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_cli.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_cli_coverage.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_cli_error_paths.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_cli_full.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_cli_success.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_config_cli.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_config_cmd_cli.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_history_cli.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_history_endpoint.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_introspect_cli.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_layers_cli.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_coverage.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_error_coverage.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_error_result.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_full.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_remaining_tools.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_selection_tools.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_server.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_mcp_success.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_replay_cli.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_rollback.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_rollback_cli.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_security_limits.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_selection_advanced.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_selection_cli_coverage.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_selection_client.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/integration/test_selection_persistence.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/property/__init__.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/property/test_input_sanitization.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/property/test_models.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/property/test_selection.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/test_phase_11.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/__init__.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_batch_models.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_client.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_client_coverage.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_client_internal.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_config.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_config_cmd.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_error_codes.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_history_store.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_mcp_batch.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_mcp_history_tool.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_models.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_payload_validator.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_replay_cmd.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_rollback_client.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_rollback_models.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_schema.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_security_config.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_selection_advanced_models.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_selection_models.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_selection_persistence_models.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_shared_coverage.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_snapshot_store.py +0 -0
- {krita_cli-1.0.0 → krita_cli-1.0.1}/tests/unit/test_type_safety_coverage.py +0 -0
- {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,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
|
|
115
|
+
conda install -y conda-build
|
|
116
|
+
pip install anaconda-client
|
|
112
117
|
conda build conda-recipe/ --output-folder dist/conda
|
|
113
|
-
|
|
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.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: SOTA CLI + MCP server for programmatic painting in Krita
|
|
5
|
-
Project-URL: Homepage, https://github.com/
|
|
6
|
-
Project-URL: Repository, https://github.com/
|
|
7
|
-
Project-URL: Issues, https://github.com/
|
|
8
|
-
Project-URL: Changelog, https://github.com/
|
|
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
|
|
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
|
|
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.
|
|
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:
|
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
2205
|
+
if "pytest" not in sys.modules:
|
|
2165
2206
|
try:
|
|
2166
2207
|
Krita.instance().addExtension(KritaMCPExtension(Krita.instance()))
|
|
2167
|
-
|
|
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
|