gdmcode 0.1.9__tar.gz → 0.1.11__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.
- {gdmcode-0.1.9 → gdmcode-0.1.11}/PKG-INFO +1 -1
- gdmcode-0.1.11/gdmcode/__init__.py +1 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/loop.py +52 -28
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/cli.py +9 -1
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/integrations/mcp_server.py +1 -1
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/permissions.py +38 -7
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/repl.py +5 -2
- {gdmcode-0.1.9 → gdmcode-0.1.11}/pyproject.toml +1 -1
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_loop.py +4 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_permissions.py +22 -0
- gdmcode-0.1.9/gdmcode/__init__.py +0 -1
- {gdmcode-0.1.9 → gdmcode-0.1.11}/.gitignore +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/CONTRIBUTING.md +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/README.md +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/config.toml +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/docs/agentic-runtime-audit.md +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/docs/architecture.md +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/docs/cli-reference.md +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/docs/configuration.md +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/docs/deployment.md +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/docs/plugin-guide.md +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/docs/quick-start.md +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/docs/security-hardening.md +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/_internal/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/_internal/constants.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/_internal/domain_skills.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/commit_classifier.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/context_budget.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/daemon.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/dag_validator.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/debug_loop.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/impact_analyzer.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/impact_graph.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/orchestrator.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/regression_guard.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/review_gate.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/risk_scorer.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/self_healing.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/smart_test_selector.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/system_prompt.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/task_tracker.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/test_validator.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/tool_orchestrator.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/transcript.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/verification_loop.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/work_director.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/agent/worktree_manager.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/artifacts/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/artifacts/artifact_store.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/artifacts/verification_graph.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/auth.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/commands.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/config.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/cost_tracker.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/db/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/db/migrations.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/enterprise/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/enterprise/audit_log.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/enterprise/identity.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/enterprise/rbac.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/enterprise/team_config.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/enterprise/usage_analytics.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/exceptions.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/git_workflow.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/integrations/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/integrations/github_actions.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/integrations/sentry_integration.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/integrations/sentry_server.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/integrations/webhook_security.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/intent_router.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/main.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/memory/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/memory/code_index.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/memory/compressor.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/memory/context_memory.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/memory/continuous_memory.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/memory/conventions.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/memory/db.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/memory/document_index.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/memory/file_cache.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/memory/project_scanner.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/memory/session_store.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/models/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/models/client.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/models/definitions.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/models/router.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/models/schemas.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/remote/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/remote/command_filter.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/remote/models.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/remote/permission_handler.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/remote/phone_ui.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/remote/protocol.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/remote/qr.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/remote/server.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/remote/token_manager.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/remote/tunnel.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/runtime/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/runtime/branch_farm.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/runtime/replay.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/sandbox/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/sandbox/hermetic.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/sandbox/policy.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/sdk/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/sdk/plugin_base.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/sdk/plugin_host.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/sdk/plugin_loader.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/security.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/server/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/server/bridge.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/server/bridge_cli.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/server/bridge_client.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/server/protocol_version.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/session/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/session/event_fanout.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/session/input_broker.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/session/permission_bridge.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/_atomic.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/agent_tools.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/ask_user_tool.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/bash_tool.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/browser_tool.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/browser_tools.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/dep_tools.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/document_reader.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/document_tool.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/document_writer.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/impact_tools.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/playwright_tool.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/quality_tools.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/read_tools.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/result_cache.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/search_tools.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/shell_tools.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/tools/write_tools.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/voice/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/voice/audio_capture.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/voice/audio_playback.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/voice/errors.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/voice/models.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/voice/providers.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/voice/vad.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/gdmcode/voice/voice_loop.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/proxy/Dockerfile +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/proxy/main.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/proxy/requirements.txt +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/remote/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/remote/test_remote_server.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_agent_loop.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_agent_tools.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_api_fallback.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_artifact_store.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_audit_log.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_auth.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_auto_quality.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_autonomy_levels.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_bash_tool.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_batch_api.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_branch_farm.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_bridge.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_bridge_smoke.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_browser_tool_smoke.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_browser_tools.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_btw_queue.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_budget_tracker.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_chrome_extension.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_ci_runner.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_cli_smoke.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_code_index.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_commands.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_compression.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_confidence.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_config.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_continuous_memory.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_convention_drift.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_cost_tracker.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_daemon.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_daemon_stability.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_daemon_watchdog.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_db.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_debate.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_debug_loop.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_debug_loop_smoke.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_dep_tools.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_doctor.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_document_index.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_document_reader.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_document_tool.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_document_writer.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_domain_skills.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_eval_harness.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_event_log.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_failure_taxonomy.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_file_tools.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_git_workflow.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_github_actions.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_health.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_hermetic_sandbox.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_identity_rbac.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_impact_analysis.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_impact_analyzer.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_impact_graph.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_impact_tools.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_injection_gate.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_intent_router.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_leaderboard.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_local_models.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_loop_p3.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_mcp_server.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_memory.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_migrations.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_mock_provider.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_model_config.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_orchestrator.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_package.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_phase2_modules.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_phone_ui.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_playwright_tool.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_plugin_sdk.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_protocol_version.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_provenance.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_proxy_server.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_quality_integration.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_reasoning_toggle.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_redaction.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_regression_collector.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_regression_guard_integration.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_regression_runner.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_repl_smoke.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_replay.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_resilience.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_result_cache.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_review_gate_expanded.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_risk_scorer.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_rollback.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_router.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_router_compressor_conventions.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_router_escalation.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_sandbox.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_scoring.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_search_tools.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_self_healing.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_semantic_edit.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_sentry_integration.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_session_checkpoint.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_session_controller.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_session_restore.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_signal_handling.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_swebench_adapter.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_swebench_runner.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_system_prompt.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_team_config.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_tool_cache.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_tool_orchestrator.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_tool_timeout.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_tools_registry.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_tunnel_qr.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_usage_analytics.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_verification_graph.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_verification_loop.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_voice_loop.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_voice_providers.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_whole_codebase.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/test_work_director.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/voice/__init__.py +0 -0
- {gdmcode-0.1.9 → gdmcode-0.1.11}/tests/voice/test_audio_foundation.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.11"
|
|
@@ -50,33 +50,33 @@ try:
|
|
|
50
50
|
_analytics: "_UsageAnalytics | None" = _UsageAnalytics()
|
|
51
51
|
except Exception: # noqa: BLE001
|
|
52
52
|
_analytics = None
|
|
53
|
-
|
|
54
|
-
try:
|
|
55
|
-
from gdmcode.agent.risk_scorer import score_patch, RiskTier
|
|
56
|
-
_risk_scorer_available = True
|
|
57
|
-
except Exception: # noqa: BLE001
|
|
58
|
-
_risk_scorer_available = False
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def _check_patch_risk(diff, file_paths=None, autonomy_level=2):
|
|
62
|
-
"""Score a patch diff and enforce risk gates based on autonomy level.
|
|
63
|
-
|
|
64
|
-
- CRITICAL (score >= block_threshold) and autonomy_level < 4: raises RuntimeError.
|
|
65
|
-
- HIGH tier and autonomy_level < 3: logs a warning (non-blocking).
|
|
66
|
-
- Always returns the PatchRiskResult (or None if scorer unavailable).
|
|
67
|
-
"""
|
|
68
|
-
if not _risk_scorer_available:
|
|
69
|
-
return None
|
|
70
|
-
result = score_patch(diff, file_paths)
|
|
71
|
-
log.info("patch_risk score=%.3f tier=%s blocked=%s", result.score, result.tier, result.blocked)
|
|
72
|
-
if result.triggered_signals:
|
|
73
|
-
log.debug("patch_risk rationale:\n%s", result.rationale)
|
|
74
|
-
if result.blocked and autonomy_level < 4:
|
|
75
|
-
raise RuntimeError(f"Patch blocked: {result.rationale}")
|
|
76
|
-
if result.tier == RiskTier.HIGH and autonomy_level < 3:
|
|
77
|
-
log.warning("High-risk patch detected (score=%.3f). Review before applying:\n%s",
|
|
78
|
-
result.score, result.rationale)
|
|
79
|
-
return result
|
|
53
|
+
|
|
54
|
+
try:
|
|
55
|
+
from gdmcode.agent.risk_scorer import score_patch, RiskTier
|
|
56
|
+
_risk_scorer_available = True
|
|
57
|
+
except Exception: # noqa: BLE001
|
|
58
|
+
_risk_scorer_available = False
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _check_patch_risk(diff, file_paths=None, autonomy_level=2):
|
|
62
|
+
"""Score a patch diff and enforce risk gates based on autonomy level.
|
|
63
|
+
|
|
64
|
+
- CRITICAL (score >= block_threshold) and autonomy_level < 4: raises RuntimeError.
|
|
65
|
+
- HIGH tier and autonomy_level < 3: logs a warning (non-blocking).
|
|
66
|
+
- Always returns the PatchRiskResult (or None if scorer unavailable).
|
|
67
|
+
"""
|
|
68
|
+
if not _risk_scorer_available:
|
|
69
|
+
return None
|
|
70
|
+
result = score_patch(diff, file_paths)
|
|
71
|
+
log.info("patch_risk score=%.3f tier=%s blocked=%s", result.score, result.tier, result.blocked)
|
|
72
|
+
if result.triggered_signals:
|
|
73
|
+
log.debug("patch_risk rationale:\n%s", result.rationale)
|
|
74
|
+
if result.blocked and autonomy_level < 4:
|
|
75
|
+
raise RuntimeError(f"Patch blocked: {result.rationale}")
|
|
76
|
+
if result.tier == RiskTier.HIGH and autonomy_level < 3:
|
|
77
|
+
log.warning("High-risk patch detected (score=%.3f). Review before applying:\n%s",
|
|
78
|
+
result.score, result.rationale)
|
|
79
|
+
return result
|
|
80
80
|
|
|
81
81
|
def _record_usage(
|
|
82
82
|
session_id: str,
|
|
@@ -505,6 +505,11 @@ class AgentLoop:
|
|
|
505
505
|
self._model = get_model(tier, self._cfg.provider)
|
|
506
506
|
self._model_id = self._model.id
|
|
507
507
|
self._gdm_client = self._make_client()
|
|
508
|
+
yield AgentEvent(
|
|
509
|
+
EventType.THINKING,
|
|
510
|
+
content=f"Using {self._model_id} for this turn.",
|
|
511
|
+
turn=0,
|
|
512
|
+
)
|
|
508
513
|
log.debug(
|
|
509
514
|
"ModelRouter selected tier=%s mode=%s for prompt=%r",
|
|
510
515
|
tier,
|
|
@@ -587,6 +592,14 @@ class AgentLoop:
|
|
|
587
592
|
log.warning("BTW queue drain failed: %s", _btw_exc)
|
|
588
593
|
|
|
589
594
|
tools = self._build_tool_specs()
|
|
595
|
+
yield AgentEvent(
|
|
596
|
+
EventType.THINKING,
|
|
597
|
+
content=(
|
|
598
|
+
"Asking the model to choose the next step"
|
|
599
|
+
+ (f" with {len(tools)} available tools." if tools else ".")
|
|
600
|
+
),
|
|
601
|
+
turn=turn_num,
|
|
602
|
+
)
|
|
590
603
|
try:
|
|
591
604
|
response = self._gdm_client.complete(
|
|
592
605
|
self._transcript.to_messages(),
|
|
@@ -686,6 +699,13 @@ class AgentLoop:
|
|
|
686
699
|
|
|
687
700
|
# Execute tool calls
|
|
688
701
|
if raw_tool_calls:
|
|
702
|
+
tool_names = ", ".join(str(tc.get("function", {}).get("name", "tool")) for tc in raw_tool_calls[:3])
|
|
703
|
+
extra = "" if len(raw_tool_calls) <= 3 else f" (+{len(raw_tool_calls) - 3} more)"
|
|
704
|
+
yield AgentEvent(
|
|
705
|
+
EventType.THINKING,
|
|
706
|
+
content=f"Model selected tool step: {tool_names}{extra}.",
|
|
707
|
+
turn=turn_num,
|
|
708
|
+
)
|
|
689
709
|
# Guard: finish_reason=tool_calls with empty list → infinite loop
|
|
690
710
|
if not msg.tool_calls:
|
|
691
711
|
yield AgentEvent(EventType.ERROR, turn=turn_num,
|
|
@@ -694,6 +714,11 @@ class AgentLoop:
|
|
|
694
714
|
return
|
|
695
715
|
|
|
696
716
|
yield from self._execute_tool_calls(msg.tool_calls, turn_num)
|
|
717
|
+
yield AgentEvent(
|
|
718
|
+
EventType.THINKING,
|
|
719
|
+
content="Feeding tool results back to the model.",
|
|
720
|
+
turn=turn_num,
|
|
721
|
+
)
|
|
697
722
|
continue # loop back to model with tool results
|
|
698
723
|
|
|
699
724
|
# Natural completion
|
|
@@ -1407,4 +1432,3 @@ def write_autonomy_audit(
|
|
|
1407
1432
|
(session_id, time.time(), level, action, json.dumps(details), checkpoint_id),
|
|
1408
1433
|
)
|
|
1409
1434
|
db_conn.commit()
|
|
1410
|
-
|
|
@@ -29,6 +29,7 @@ import shutil
|
|
|
29
29
|
import httpx
|
|
30
30
|
import typer
|
|
31
31
|
from rich.console import Console
|
|
32
|
+
from rich.markup import escape
|
|
32
33
|
|
|
33
34
|
from gdmcode import __version__
|
|
34
35
|
from gdmcode.config import load_config
|
|
@@ -1301,7 +1302,14 @@ def _run_one_shot(cfg: object, prompt: str, *, yes: bool, model_override: str |
|
|
|
1301
1302
|
had_error = False
|
|
1302
1303
|
try:
|
|
1303
1304
|
for event in loop.run(prompt): # type: ignore[union-attr]
|
|
1304
|
-
if event.type == EventType.
|
|
1305
|
+
if event.type == EventType.THINKING:
|
|
1306
|
+
status.stop()
|
|
1307
|
+
snippet = str(event.content or "")[:120]
|
|
1308
|
+
if snippet:
|
|
1309
|
+
console.print(f"[dim cyan]… {snippet}[/dim cyan]")
|
|
1310
|
+
status.start()
|
|
1311
|
+
status.update("[cyan]Working...[/cyan]")
|
|
1312
|
+
elif event.type == EventType.RESPONSE:
|
|
1305
1313
|
status.stop()
|
|
1306
1314
|
console.print(event.content)
|
|
1307
1315
|
elif event.type == EventType.ERROR:
|
|
@@ -51,7 +51,7 @@ _INTERNAL_ERROR = -32603
|
|
|
51
51
|
class MCPServer:
|
|
52
52
|
"""Minimal MCP server with stdio transport."""
|
|
53
53
|
|
|
54
|
-
def __init__(self, name: str = "gdmcode", version: str = "0.1.
|
|
54
|
+
def __init__(self, name: str = "gdmcode", version: str = "0.1.11") -> None:
|
|
55
55
|
self._name = name
|
|
56
56
|
self._version = version
|
|
57
57
|
self._tools: dict[str, MCPTool] = {}
|
|
@@ -14,6 +14,7 @@ Decision hierarchy (first match wins):
|
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
16
|
import logging
|
|
17
|
+
import sys
|
|
17
18
|
from dataclasses import dataclass, field
|
|
18
19
|
from enum import StrEnum
|
|
19
20
|
from typing import TYPE_CHECKING
|
|
@@ -61,6 +62,40 @@ log = logging.getLogger(__name__)
|
|
|
61
62
|
_active_bridge: "PermissionBridge | None" = None
|
|
62
63
|
|
|
63
64
|
|
|
65
|
+
def _read_permission_choice() -> str:
|
|
66
|
+
"""Read a permission choice using plain stdin/stdout.
|
|
67
|
+
|
|
68
|
+
Rich/Prompt.ask can interact poorly with active terminal renderers on some
|
|
69
|
+
Windows shells. A simple flushed line prompt keeps the approval input
|
|
70
|
+
editable and visible.
|
|
71
|
+
"""
|
|
72
|
+
valid = {
|
|
73
|
+
"": "y",
|
|
74
|
+
"y": "y",
|
|
75
|
+
"yes": "y",
|
|
76
|
+
"n": "n",
|
|
77
|
+
"no": "n",
|
|
78
|
+
"s": "session",
|
|
79
|
+
"session": "session",
|
|
80
|
+
"a": "always",
|
|
81
|
+
"always": "always",
|
|
82
|
+
"v": "never",
|
|
83
|
+
"never": "never",
|
|
84
|
+
}
|
|
85
|
+
prompt = "Allow? type y/n/session/always/never and press Enter [y]: "
|
|
86
|
+
while True:
|
|
87
|
+
sys.stdout.write(prompt)
|
|
88
|
+
sys.stdout.flush()
|
|
89
|
+
line = sys.stdin.readline()
|
|
90
|
+
if line == "":
|
|
91
|
+
return "n"
|
|
92
|
+
choice = valid.get(line.strip().lower())
|
|
93
|
+
if choice is not None:
|
|
94
|
+
return choice
|
|
95
|
+
sys.stdout.write("Please enter y, n, session, always, or never.\n")
|
|
96
|
+
sys.stdout.flush()
|
|
97
|
+
|
|
98
|
+
|
|
64
99
|
def set_permission_bridge(bridge: "PermissionBridge") -> None:
|
|
65
100
|
"""Activate a PermissionBridge so _prompt_user() delegates to it."""
|
|
66
101
|
global _active_bridge
|
|
@@ -250,9 +285,9 @@ class PermissionContext:
|
|
|
250
285
|
self._session_allow = self._session_allow | {tool}
|
|
251
286
|
return Decision.ALLOW_SESSION
|
|
252
287
|
|
|
253
|
-
# Rich
|
|
288
|
+
# Rich output only; use plain stdin for the actual answer so terminal
|
|
289
|
+
# input remains editable even after prompt_toolkit/status rendering.
|
|
254
290
|
from rich.console import Console
|
|
255
|
-
from rich.prompt import Prompt
|
|
256
291
|
|
|
257
292
|
console = Console()
|
|
258
293
|
console.print(f"\n[bold yellow]⚠ Permission request[/bold yellow]")
|
|
@@ -261,11 +296,7 @@ class PermissionContext:
|
|
|
261
296
|
import json
|
|
262
297
|
console.print(f"Args: [dim]{json.dumps(args, indent=2)[:400]}[/dim]")
|
|
263
298
|
|
|
264
|
-
choice =
|
|
265
|
-
"Allow?",
|
|
266
|
-
choices=["y", "n", "always", "session", "never"],
|
|
267
|
-
default="y",
|
|
268
|
-
)
|
|
299
|
+
choice = _read_permission_choice()
|
|
269
300
|
|
|
270
301
|
decision_map = {
|
|
271
302
|
"y": Decision.ALLOW_SESSION,
|
|
@@ -177,8 +177,11 @@ def _render_event(event: object, status: Status, console: Console) -> bool:
|
|
|
177
177
|
match ev.type: # type: ignore[union-attr]
|
|
178
178
|
case EventType.THINKING:
|
|
179
179
|
snippet = str(ev.content or "")[:100] # type: ignore[union-attr]
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
status.stop()
|
|
181
|
+
if snippet:
|
|
182
|
+
console.print(f"[dim cyan]… {escape(snippet)}[/dim cyan]")
|
|
183
|
+
status.start()
|
|
184
|
+
status.update("[cyan]Working...[/cyan]")
|
|
182
185
|
case EventType.TOOL_CALL:
|
|
183
186
|
status.stop()
|
|
184
187
|
console.print(f"[yellow][tool] {ev.tool_name}({_fmt_args(ev.args)})[/yellow]") # type: ignore[union-attr]
|
|
@@ -268,6 +268,10 @@ class TestAgentLoop:
|
|
|
268
268
|
|
|
269
269
|
mock_orchestrator.execute.assert_called_once_with("bash", {"command": "ls"}, model_id=loop._model.id)
|
|
270
270
|
event_types = [e.type for e in events]
|
|
271
|
+
thinking = [e.content for e in events if e.type == EventType.THINKING]
|
|
272
|
+
assert any("Asking the model" in content for content in thinking)
|
|
273
|
+
assert any("Model selected tool step: bash" in content for content in thinking)
|
|
274
|
+
assert any("Feeding tool results back" in content for content in thinking)
|
|
271
275
|
assert EventType.TOOL_CALL in event_types
|
|
272
276
|
assert EventType.TOOL_RESULT in event_types
|
|
273
277
|
assert EventType.DONE in event_types
|
|
@@ -104,3 +104,25 @@ def test_non_interactive_denies_unknown(mock_db):
|
|
|
104
104
|
with pytest.raises(ToolPermissionError) as exc_info:
|
|
105
105
|
ctx_ni.check("some_tool", {})
|
|
106
106
|
assert "non-interactive" in str(exc_info.value).lower()
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_plain_permission_prompt_accepts_yes(ctx, monkeypatch):
|
|
110
|
+
monkeypatch.setattr("sys.stdin.readline", lambda: "y\n")
|
|
111
|
+
|
|
112
|
+
assert ctx.check("bash", {"command": "ls -F"}) == Decision.ALLOW_SESSION
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_plain_permission_prompt_denies_no(ctx, monkeypatch):
|
|
116
|
+
monkeypatch.setattr("sys.stdin.readline", lambda: "n\n")
|
|
117
|
+
|
|
118
|
+
with pytest.raises(ToolPermissionError) as exc_info:
|
|
119
|
+
ctx.check("bash", {"command": "ls -F"})
|
|
120
|
+
|
|
121
|
+
assert "denied by user" in str(exc_info.value).lower()
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def test_plain_permission_prompt_reprompts_invalid_choice(ctx, monkeypatch):
|
|
125
|
+
choices = iter(["maybe\n", "always\n"])
|
|
126
|
+
monkeypatch.setattr("sys.stdin.readline", lambda: next(choices))
|
|
127
|
+
|
|
128
|
+
assert ctx.check("bash", {"command": "ls -F"}) == Decision.ALLOW_ALWAYS
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.1.9"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|