meshcode 2.11.19__tar.gz → 2.11.21__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.
- {meshcode-2.11.19 → meshcode-2.11.21}/PKG-INFO +1 -1
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/__init__.py +1 -1
- meshcode-2.11.21/meshcode/atomic_push.py +257 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/server.py +139 -6
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/rpc_allowlist.py +4 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode.egg-info/PKG-INFO +1 -1
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode.egg-info/SOURCES.txt +1 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/pyproject.toml +1 -1
- {meshcode-2.11.19 → meshcode-2.11.21}/README.md +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/__main__.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/_stop_hook_template.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/ascii_art.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/cli.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/comms_v4.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/compat.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/daemon.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/date_parse.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/doctor.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/error_hints.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/exceptions.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/invites.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/launcher.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/launcher_install.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/preferences.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/protocol_handler.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/protocol_v2.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/quickstart.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/run_agent.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/scripts/check_secrets.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/scripts/race_rate_harness.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/secrets.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/self_update.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/setup_clients.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/supervisor.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode/upload.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/comms_v4.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/__init__.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/ascii_art.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/cli.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/comms_v4.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/compat.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/error_hints.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/exceptions.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/invites.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/launcher.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/launcher_install.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/server.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/preferences.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/protocol_v2.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/quickstart.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/run_agent.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/secrets.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/self_update.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/setup_clients.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/supervisor.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/upload.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/scripts/sentinel.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_core.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_cross_agent_messaging.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_esc_deaf_state.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_exceptions.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_mark_read_batch.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_migration_integrity.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_realtime_event_freshness.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_rls_cross_tenant.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_rpc_migrations.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_security_regressions.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_sentinel.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/tests/test_status_enum_coverage.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/__init__.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/ascii_art.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/cli.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/comms_v4.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/compat.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/error_hints.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/exceptions.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/invites.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/launcher.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/launcher_install.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/server.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/preferences.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/protocol_v2.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/quickstart.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/run_agent.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/secrets.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/self_update.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/setup_clients.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/supervisor.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/build/lib/meshcode/upload.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/comms_v4.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/__init__.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/ascii_art.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/cli.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/comms_v4.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/compat.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/error_hints.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/exceptions.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/invites.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/launcher.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/launcher_install.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/server.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/preferences.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/protocol_v2.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/quickstart.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/run_agent.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/secrets.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/self_update.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/setup_clients.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/supervisor.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/meshcode/upload.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/scripts/sentinel.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_core.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_cross_agent_messaging.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_esc_deaf_state.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_exceptions.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_mark_read_batch.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_migration_integrity.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_realtime_event_freshness.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_rls_cross_tenant.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_rpc_migrations.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_security_regressions.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_sentinel.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-noun-wt/tests/test_status_enum_coverage.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/comms_v4.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/__init__.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/ascii_art.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/cli.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/comms_v4.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/compat.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/error_hints.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/exceptions.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/invites.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/launcher.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/launcher_install.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/server.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/preferences.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/protocol_v2.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/quickstart.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/run_agent.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/secrets.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/self_update.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/setup_clients.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/supervisor.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/meshcode/upload.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/scripts/sentinel.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_core.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_cross_agent_messaging.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_esc_deaf_state.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_exceptions.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_mark_read_batch.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_migration_integrity.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_realtime_event_freshness.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_rls_cross_tenant.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_rpc_migrations.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_security_regressions.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_sentinel.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode-tasks-wt/tests/test_status_enum_coverage.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/meshcode.egg-info/top_level.txt +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/setup.cfg +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_auto_update_hardening.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_boot_bug_regression.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_color_truecolor.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_core.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_cross_agent_messaging.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_date_parse.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_doctor.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_epistemic_v1_python_sdk.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_epistemic_v1_stop_conditions.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_esc_deaf_state.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_exceptions.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_init_device_code.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_install_guard.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_lease_sigterm_release.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_mark_read_batch.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_migration_integrity.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_realtime_event_freshness.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_rls_cross_tenant.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_rpc_grants.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_rpc_migrations.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_security_regressions.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_sentinel.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_setup_path.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_sleep_signals.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_status_enum_coverage.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_stay_on_loop_hook.py +0 -0
- {meshcode-2.11.19 → meshcode-2.11.21}/tests/test_wait_open_tasks_contradiction.py +0 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"""Atomic multi-remote git push via GitHub REST API.
|
|
2
|
+
|
|
3
|
+
Implements MESH-IMPROVE-3 (feedback session 5651f137 — 4/4 cycle convergence).
|
|
4
|
+
|
|
5
|
+
MVP scope:
|
|
6
|
+
- strategy='same_tree_sha' only (defer cherry_pick_if_diverged + rest_api_blob_tree to v2)
|
|
7
|
+
- remotes hardcoded to {origin, lovable2} (param accepted but only those valid)
|
|
8
|
+
- idempotency_key: when same key seen twice within 1h, returns cached result
|
|
9
|
+
(avoids double-commit on retry — handles dulwich-shutdown-traceback pattern
|
|
10
|
+
front-2 reported in feedback cycle 2)
|
|
11
|
+
- auth_source: 'git_config' (parse PATs from .git/config) — most agents
|
|
12
|
+
have PATs there per the pattern established 2026-05-20
|
|
13
|
+
|
|
14
|
+
Used by meshcode_atomic_push MCP tool + callable from scripts.
|
|
15
|
+
"""
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import base64
|
|
19
|
+
import json
|
|
20
|
+
import os
|
|
21
|
+
import re
|
|
22
|
+
import time
|
|
23
|
+
import urllib.error
|
|
24
|
+
import urllib.request
|
|
25
|
+
from pathlib import Path
|
|
26
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
27
|
+
|
|
28
|
+
ALLOWED_REMOTES = ("origin", "lovable2")
|
|
29
|
+
_CACHE_TTL_S = 3600
|
|
30
|
+
_DEFAULT_REPO_ROOT = Path("/Users/anfexi/Desktop/meshcode")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _cache_path() -> Path:
|
|
34
|
+
base = Path(os.path.expanduser("~/.meshcode"))
|
|
35
|
+
base.mkdir(parents=True, exist_ok=True)
|
|
36
|
+
return base / "atomic_push_cache.json"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _load_cache() -> Dict[str, Any]:
|
|
40
|
+
p = _cache_path()
|
|
41
|
+
if not p.exists():
|
|
42
|
+
return {}
|
|
43
|
+
try:
|
|
44
|
+
with open(p) as f:
|
|
45
|
+
return json.load(f) or {}
|
|
46
|
+
except Exception:
|
|
47
|
+
return {}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _save_cache(cache: Dict[str, Any]) -> None:
|
|
51
|
+
try:
|
|
52
|
+
with open(_cache_path(), "w") as f:
|
|
53
|
+
json.dump(cache, f)
|
|
54
|
+
except Exception:
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _check_idempotency(key: Optional[str]) -> Optional[Dict[str, Any]]:
|
|
59
|
+
if not key:
|
|
60
|
+
return None
|
|
61
|
+
cache = _load_cache()
|
|
62
|
+
entry = cache.get(key)
|
|
63
|
+
if not entry:
|
|
64
|
+
return None
|
|
65
|
+
if (time.time() - entry.get("ts", 0)) > _CACHE_TTL_S:
|
|
66
|
+
return None
|
|
67
|
+
return entry.get("result")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _store_idempotency(key: Optional[str], result: Dict[str, Any]) -> None:
|
|
71
|
+
if not key:
|
|
72
|
+
return
|
|
73
|
+
cache = _load_cache()
|
|
74
|
+
cache[key] = {"ts": time.time(), "result": result}
|
|
75
|
+
# Prune entries older than TTL
|
|
76
|
+
cutoff = time.time() - _CACHE_TTL_S
|
|
77
|
+
cache = {k: v for k, v in cache.items() if v.get("ts", 0) > cutoff}
|
|
78
|
+
_save_cache(cache)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def parse_git_config(repo_root: Path = _DEFAULT_REPO_ROOT) -> Dict[str, Tuple[str, str, str]]:
|
|
82
|
+
"""Return {remote_alias: (owner, repo, pat)}."""
|
|
83
|
+
cfg_path = repo_root / ".git" / "config"
|
|
84
|
+
if not cfg_path.exists():
|
|
85
|
+
return {}
|
|
86
|
+
cfg = cfg_path.read_text()
|
|
87
|
+
remotes: Dict[str, Tuple[str, str, str]] = {}
|
|
88
|
+
for block in re.split(r"\n(?=\[)", cfg):
|
|
89
|
+
m = re.match(r'\[remote "([^"]+)"\]', block)
|
|
90
|
+
if not m:
|
|
91
|
+
continue
|
|
92
|
+
alias = m.group(1)
|
|
93
|
+
url_m = re.search(r"url\s*=\s*(\S+)", block)
|
|
94
|
+
if not url_m:
|
|
95
|
+
continue
|
|
96
|
+
url = url_m.group(1)
|
|
97
|
+
creds_m = re.match(
|
|
98
|
+
r"https://([^:]+):([^@]+)@github\.com/([^/]+)/([^/]+?)(?:\.git)?$",
|
|
99
|
+
url,
|
|
100
|
+
)
|
|
101
|
+
if not creds_m:
|
|
102
|
+
continue
|
|
103
|
+
_, pat, owner, repo = creds_m.groups()
|
|
104
|
+
remotes[alias] = (owner, repo, pat)
|
|
105
|
+
return remotes
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _api(method: str, url: str, pat: str, data: Any = None) -> Dict[str, Any]:
|
|
109
|
+
req = urllib.request.Request(url, method=method)
|
|
110
|
+
req.add_header("Authorization", f"Bearer {pat}")
|
|
111
|
+
req.add_header("Accept", "application/vnd.github+json")
|
|
112
|
+
req.add_header("X-GitHub-Api-Version", "2022-11-28")
|
|
113
|
+
body = None
|
|
114
|
+
if data is not None:
|
|
115
|
+
body = json.dumps(data).encode()
|
|
116
|
+
req.add_header("Content-Type", "application/json")
|
|
117
|
+
try:
|
|
118
|
+
with urllib.request.urlopen(req, data=body, timeout=30) as r:
|
|
119
|
+
return json.loads(r.read().decode())
|
|
120
|
+
except urllib.error.HTTPError as e:
|
|
121
|
+
msg = e.read().decode()[:300]
|
|
122
|
+
raise RuntimeError(f"{method} {url} -> {e.code}: {msg}") from e
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _push_one_remote(
|
|
126
|
+
owner: str,
|
|
127
|
+
repo: str,
|
|
128
|
+
pat: str,
|
|
129
|
+
branch: str,
|
|
130
|
+
commit_message: str,
|
|
131
|
+
files: List[str],
|
|
132
|
+
repo_root: Path,
|
|
133
|
+
) -> Tuple[str, Dict[str, Any]]:
|
|
134
|
+
base = f"https://api.github.com/repos/{owner}/{repo}"
|
|
135
|
+
ref = _api("GET", f"{base}/git/ref/heads/{branch}", pat)
|
|
136
|
+
head_sha = ref["object"]["sha"]
|
|
137
|
+
base_commit = _api("GET", f"{base}/git/commits/{head_sha}", pat)
|
|
138
|
+
base_tree_sha = base_commit["tree"]["sha"]
|
|
139
|
+
tree_entries = []
|
|
140
|
+
for rel in files:
|
|
141
|
+
p = repo_root / rel
|
|
142
|
+
if not p.exists():
|
|
143
|
+
raise RuntimeError(f"file not found: {p}")
|
|
144
|
+
content = p.read_bytes()
|
|
145
|
+
blob = _api(
|
|
146
|
+
"POST",
|
|
147
|
+
f"{base}/git/blobs",
|
|
148
|
+
pat,
|
|
149
|
+
data={"content": base64.b64encode(content).decode(), "encoding": "base64"},
|
|
150
|
+
)
|
|
151
|
+
tree_entries.append({
|
|
152
|
+
"path": rel,
|
|
153
|
+
"mode": "100644",
|
|
154
|
+
"type": "blob",
|
|
155
|
+
"sha": blob["sha"],
|
|
156
|
+
})
|
|
157
|
+
new_tree = _api(
|
|
158
|
+
"POST",
|
|
159
|
+
f"{base}/git/trees",
|
|
160
|
+
pat,
|
|
161
|
+
data={"base_tree": base_tree_sha, "tree": tree_entries},
|
|
162
|
+
)
|
|
163
|
+
commit = _api(
|
|
164
|
+
"POST",
|
|
165
|
+
f"{base}/git/commits",
|
|
166
|
+
pat,
|
|
167
|
+
data={
|
|
168
|
+
"message": commit_message,
|
|
169
|
+
"tree": new_tree["sha"],
|
|
170
|
+
"parents": [head_sha],
|
|
171
|
+
},
|
|
172
|
+
)
|
|
173
|
+
new_sha = commit["sha"]
|
|
174
|
+
_api(
|
|
175
|
+
"PATCH",
|
|
176
|
+
f"{base}/git/refs/heads/{branch}",
|
|
177
|
+
pat,
|
|
178
|
+
data={"sha": new_sha, "force": False},
|
|
179
|
+
)
|
|
180
|
+
return new_sha, {
|
|
181
|
+
"head_before": head_sha,
|
|
182
|
+
"tree_sha": new_tree["sha"],
|
|
183
|
+
"commit_sha": new_sha,
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def atomic_push(
|
|
188
|
+
commit_message: str,
|
|
189
|
+
files: List[str],
|
|
190
|
+
*,
|
|
191
|
+
branch: str = "main",
|
|
192
|
+
remotes: Optional[List[str]] = None,
|
|
193
|
+
strategy: str = "same_tree_sha",
|
|
194
|
+
idempotency_key: Optional[str] = None,
|
|
195
|
+
repo_root: Path = _DEFAULT_REPO_ROOT,
|
|
196
|
+
) -> Dict[str, Any]:
|
|
197
|
+
"""Push the same blob set to multiple remotes atomically.
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
{
|
|
201
|
+
ok: bool,
|
|
202
|
+
landed: {remote_alias: commit_sha},
|
|
203
|
+
tree_sha_per_remote: {remote_alias: tree_sha},
|
|
204
|
+
drift_detected: bool,
|
|
205
|
+
transport_used: 'github_rest_api',
|
|
206
|
+
cached: bool,
|
|
207
|
+
strategy: str
|
|
208
|
+
}
|
|
209
|
+
"""
|
|
210
|
+
if strategy != "same_tree_sha":
|
|
211
|
+
return {
|
|
212
|
+
"ok": False,
|
|
213
|
+
"error": "unsupported_strategy",
|
|
214
|
+
"hint": f"MVP supports 'same_tree_sha' only; got {strategy!r}",
|
|
215
|
+
}
|
|
216
|
+
remotes = remotes or list(ALLOWED_REMOTES)
|
|
217
|
+
for r in remotes:
|
|
218
|
+
if r not in ALLOWED_REMOTES:
|
|
219
|
+
return {
|
|
220
|
+
"ok": False,
|
|
221
|
+
"error": "unsupported_remote",
|
|
222
|
+
"hint": f"MVP accepts {ALLOWED_REMOTES}; got {r!r}",
|
|
223
|
+
}
|
|
224
|
+
cached = _check_idempotency(idempotency_key)
|
|
225
|
+
if cached is not None:
|
|
226
|
+
cached["cached"] = True
|
|
227
|
+
return cached
|
|
228
|
+
git_remotes = parse_git_config(repo_root)
|
|
229
|
+
missing = [r for r in remotes if r not in git_remotes]
|
|
230
|
+
if missing:
|
|
231
|
+
return {
|
|
232
|
+
"ok": False,
|
|
233
|
+
"error": "git_config_remote_missing",
|
|
234
|
+
"missing": missing,
|
|
235
|
+
"have": list(git_remotes.keys()),
|
|
236
|
+
}
|
|
237
|
+
landed: Dict[str, str] = {}
|
|
238
|
+
tree_sha_per: Dict[str, str] = {}
|
|
239
|
+
for alias in remotes:
|
|
240
|
+
owner, repo, pat = git_remotes[alias]
|
|
241
|
+
sha, meta = _push_one_remote(owner, repo, pat, branch, commit_message, files, repo_root)
|
|
242
|
+
landed[alias] = sha
|
|
243
|
+
tree_sha_per[alias] = meta["tree_sha"]
|
|
244
|
+
tree_shas = list(tree_sha_per.values())
|
|
245
|
+
same_tree = len(set(tree_shas)) == 1
|
|
246
|
+
result = {
|
|
247
|
+
"ok": True,
|
|
248
|
+
"landed": landed,
|
|
249
|
+
"tree_sha_per_remote": tree_sha_per,
|
|
250
|
+
"drift_detected": not same_tree,
|
|
251
|
+
"transport_used": "github_rest_api",
|
|
252
|
+
"cached": False,
|
|
253
|
+
"strategy": strategy,
|
|
254
|
+
"branch": branch,
|
|
255
|
+
}
|
|
256
|
+
_store_idempotency(idempotency_key, result)
|
|
257
|
+
return result
|
|
@@ -5334,6 +5334,8 @@ def meshcode_remember(
|
|
|
5334
5334
|
value: Any,
|
|
5335
5335
|
weight: int = 5,
|
|
5336
5336
|
emotion_tag: Optional[str] = None,
|
|
5337
|
+
scope: str = "agent",
|
|
5338
|
+
promote_from: Optional[str] = None,
|
|
5337
5339
|
) -> Dict[str, Any]:
|
|
5338
5340
|
"""Store a persistent memory (survives restarts). Only for reusable learnings, NOT task data.
|
|
5339
5341
|
|
|
@@ -5341,16 +5343,22 @@ def meshcode_remember(
|
|
|
5341
5343
|
key: Short key (e.g. "team_conventions").
|
|
5342
5344
|
value: Any JSON-serializable value.
|
|
5343
5345
|
weight: 1-10, default 5 (neutral). Higher = ranks higher on recall.
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5346
|
+
emotion_tag: Optional free-form tag.
|
|
5347
|
+
scope: 'agent' (default, per-agent memory) OR 'mesh' (shared across
|
|
5348
|
+
the meshwork; visible to all agents). MESH-IMPROVE-2 (mig 339).
|
|
5349
|
+
On write conflict with an existing mesh value, server records the
|
|
5350
|
+
contradiction; resolve via meshcode_resolve_contradiction.
|
|
5351
|
+
promote_from: when scope='mesh', set this to an existing agent-scope
|
|
5352
|
+
memory key — server lifts that value to mesh-scope without
|
|
5353
|
+
duplicating the data. Caller's `value` arg is ignored when set.
|
|
5348
5354
|
"""
|
|
5349
5355
|
if not key or not key.strip():
|
|
5350
5356
|
return {"error": "key cannot be empty"}
|
|
5351
5357
|
key = key.strip()
|
|
5352
5358
|
if not isinstance(weight, int) or weight < 1 or weight > 10:
|
|
5353
5359
|
return {"error": "weight must be an integer 1..10"}
|
|
5360
|
+
if scope not in ("agent", "mesh"):
|
|
5361
|
+
return {"error": f"scope must be 'agent' or 'mesh', got {scope!r}"}
|
|
5354
5362
|
api_key = _get_api_key()
|
|
5355
5363
|
json_value = value if isinstance(value, (dict, list)) else json.dumps(value)
|
|
5356
5364
|
if isinstance(json_value, str):
|
|
@@ -5358,6 +5366,20 @@ def meshcode_remember(
|
|
|
5358
5366
|
json_value = json.loads(json_value)
|
|
5359
5367
|
except (json.JSONDecodeError, TypeError):
|
|
5360
5368
|
json_value = {"_raw": value}
|
|
5369
|
+
if scope == "mesh":
|
|
5370
|
+
# MESH-IMPROVE-2: mesh-scope write via mig 339 RPC. Surfaces
|
|
5371
|
+
# contradiction metadata in the response when an existing value
|
|
5372
|
+
# differs from the new one.
|
|
5373
|
+
return be.sb_rpc("mc_meshwork_remember", {
|
|
5374
|
+
"p_api_key": api_key,
|
|
5375
|
+
"p_project_id": _PROJECT_ID,
|
|
5376
|
+
"p_key": key,
|
|
5377
|
+
"p_value": json_value,
|
|
5378
|
+
"p_writer_agent": AGENT_NAME,
|
|
5379
|
+
"p_weight": weight,
|
|
5380
|
+
"p_emotion_tag": emotion_tag,
|
|
5381
|
+
"p_promote_from_agent_key": promote_from,
|
|
5382
|
+
})
|
|
5361
5383
|
result = be.sb_rpc("mc_memory_set", {
|
|
5362
5384
|
"p_api_key": api_key,
|
|
5363
5385
|
"p_agent_name": AGENT_NAME,
|
|
@@ -5368,15 +5390,126 @@ def meshcode_remember(
|
|
|
5368
5390
|
"p_weight": weight,
|
|
5369
5391
|
"p_emotion_tag": emotion_tag,
|
|
5370
5392
|
})
|
|
5371
|
-
# Best-effort sync to Obsidian vault (if configured)
|
|
5372
5393
|
if isinstance(result, dict) and result.get("ok"):
|
|
5373
5394
|
try:
|
|
5374
5395
|
_sync_to_obsidian(key, json_value)
|
|
5375
5396
|
except Exception:
|
|
5376
|
-
pass
|
|
5397
|
+
pass
|
|
5377
5398
|
return result
|
|
5378
5399
|
|
|
5379
5400
|
|
|
5401
|
+
@mcp.tool()
|
|
5402
|
+
@with_working_status
|
|
5403
|
+
def meshcode_atomic_push(
|
|
5404
|
+
commit_message: str,
|
|
5405
|
+
files: List[str],
|
|
5406
|
+
branch: str = "main",
|
|
5407
|
+
remotes: Optional[List[str]] = None,
|
|
5408
|
+
idempotency_key: Optional[str] = None,
|
|
5409
|
+
) -> Dict[str, Any]:
|
|
5410
|
+
"""Push same blob set to multiple git remotes atomically (same tree SHA).
|
|
5411
|
+
MESH-IMPROVE-3 (feedback session 5651f137 — 4/4 cycle convergence).
|
|
5412
|
+
|
|
5413
|
+
Args:
|
|
5414
|
+
commit_message: full commit message (multi-line ok).
|
|
5415
|
+
files: list of repo-relative paths to include in the commit.
|
|
5416
|
+
branch: target branch on each remote (default "main").
|
|
5417
|
+
remotes: subset of {"origin","lovable2"}; defaults to both.
|
|
5418
|
+
idempotency_key: if same key seen twice within 1h, returns cached result
|
|
5419
|
+
(avoids double-commit on retry — covers dulwich-shutdown-traceback).
|
|
5420
|
+
|
|
5421
|
+
Returns: {ok, landed:{remote:sha}, tree_sha_per_remote, drift_detected,
|
|
5422
|
+
transport_used:'github_rest_api', cached:bool, strategy, branch}
|
|
5423
|
+
"""
|
|
5424
|
+
if not commit_message or not commit_message.strip():
|
|
5425
|
+
return {"error": "commit_message cannot be empty"}
|
|
5426
|
+
if not files:
|
|
5427
|
+
return {"error": "files list cannot be empty"}
|
|
5428
|
+
try:
|
|
5429
|
+
from meshcode import atomic_push as _ap
|
|
5430
|
+
return _ap.atomic_push(
|
|
5431
|
+
commit_message=commit_message,
|
|
5432
|
+
files=files,
|
|
5433
|
+
branch=branch,
|
|
5434
|
+
remotes=remotes,
|
|
5435
|
+
strategy="same_tree_sha",
|
|
5436
|
+
idempotency_key=idempotency_key,
|
|
5437
|
+
)
|
|
5438
|
+
except Exception as e:
|
|
5439
|
+
return {"error": str(e), "error_type": type(e).__name__}
|
|
5440
|
+
|
|
5441
|
+
|
|
5442
|
+
@mcp.tool()
|
|
5443
|
+
@with_working_status
|
|
5444
|
+
def meshcode_context_budget() -> Dict[str, Any]:
|
|
5445
|
+
"""Self-pacing hint for the agent's reply verbosity.
|
|
5446
|
+
MESH-IMPROVE-10 (feedback session 5651f137).
|
|
5447
|
+
|
|
5448
|
+
Returns: {messages_seen, suggestion: 'short'|'normal'|'verbose',
|
|
5449
|
+
rationale: str}.
|
|
5450
|
+
|
|
5451
|
+
Note: server cannot know the actual conversation token count (Anthropic
|
|
5452
|
+
doesn't expose). Suggestion is derived from proxies the server CAN see —
|
|
5453
|
+
cumulative msg count + recent msg sizes. Treat as a hint, not a hard
|
|
5454
|
+
truth.
|
|
5455
|
+
"""
|
|
5456
|
+
seen = len(_SEEN_MSG_IDS)
|
|
5457
|
+
# Heuristic: <50 msgs = verbose ok; 50-150 = normal; >150 = short
|
|
5458
|
+
if seen < 50:
|
|
5459
|
+
suggestion = "verbose"
|
|
5460
|
+
rationale = "fresh session — full detail is fine"
|
|
5461
|
+
elif seen < 150:
|
|
5462
|
+
suggestion = "normal"
|
|
5463
|
+
rationale = "mid-session — standard verbosity"
|
|
5464
|
+
else:
|
|
5465
|
+
suggestion = "short"
|
|
5466
|
+
rationale = "deep session — prefer tight prose, drop redundant context"
|
|
5467
|
+
return {
|
|
5468
|
+
"ok": True,
|
|
5469
|
+
"messages_seen": seen,
|
|
5470
|
+
"suggestion": suggestion,
|
|
5471
|
+
"rationale": rationale,
|
|
5472
|
+
}
|
|
5473
|
+
|
|
5474
|
+
|
|
5475
|
+
@mcp.tool()
|
|
5476
|
+
@with_working_status
|
|
5477
|
+
def meshcode_recall_mesh(key: str) -> Dict[str, Any]:
|
|
5478
|
+
"""Read a mesh-scoped memory + any open contradictions on it.
|
|
5479
|
+
MESH-IMPROVE-2 (mig 339).
|
|
5480
|
+
"""
|
|
5481
|
+
if not key or not key.strip():
|
|
5482
|
+
return {"error": "key cannot be empty"}
|
|
5483
|
+
return be.sb_rpc("mc_meshwork_recall", {
|
|
5484
|
+
"p_api_key": _get_api_key(),
|
|
5485
|
+
"p_project_id": _PROJECT_ID,
|
|
5486
|
+
"p_key": key.strip(),
|
|
5487
|
+
})
|
|
5488
|
+
|
|
5489
|
+
|
|
5490
|
+
@mcp.tool()
|
|
5491
|
+
@with_working_status
|
|
5492
|
+
def meshcode_resolve_contradiction(key: str, winning_value: Any) -> Dict[str, Any]:
|
|
5493
|
+
"""Pick a winning value for a mesh-scoped memory with open contradictions.
|
|
5494
|
+
Marks every loser as superseded. MESH-IMPROVE-2 (mig 339).
|
|
5495
|
+
"""
|
|
5496
|
+
if not key or not key.strip():
|
|
5497
|
+
return {"error": "key cannot be empty"}
|
|
5498
|
+
json_value = winning_value if isinstance(winning_value, (dict, list)) else json.dumps(winning_value)
|
|
5499
|
+
if isinstance(json_value, str):
|
|
5500
|
+
try:
|
|
5501
|
+
json_value = json.loads(json_value)
|
|
5502
|
+
except (json.JSONDecodeError, TypeError):
|
|
5503
|
+
json_value = {"_raw": winning_value}
|
|
5504
|
+
return be.sb_rpc("mc_meshwork_resolve_contradiction", {
|
|
5505
|
+
"p_api_key": _get_api_key(),
|
|
5506
|
+
"p_project_id": _PROJECT_ID,
|
|
5507
|
+
"p_key": key.strip(),
|
|
5508
|
+
"p_winning_value": json_value,
|
|
5509
|
+
"p_resolver": AGENT_NAME,
|
|
5510
|
+
})
|
|
5511
|
+
|
|
5512
|
+
|
|
5380
5513
|
@mcp.tool()
|
|
5381
5514
|
@with_working_status
|
|
5382
5515
|
def meshcode_recall(key: Optional[str] = None) -> Dict[str, Any]:
|
|
@@ -67,6 +67,10 @@ AGENT_CALLABLE_RPCS = [
|
|
|
67
67
|
"mc_memory_list",
|
|
68
68
|
"mc_memory_search",
|
|
69
69
|
"mc_memory_contradictions",
|
|
70
|
+
# Mesh-scoped memory (mig 339)
|
|
71
|
+
"mc_meshwork_remember",
|
|
72
|
+
"mc_meshwork_recall",
|
|
73
|
+
"mc_meshwork_resolve_contradiction",
|
|
70
74
|
|
|
71
75
|
# ── Decisions / outcomes
|
|
72
76
|
"mc_has_open_decision",
|
|
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
|
{meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/test_backend.py
RENAMED
|
File without changes
|
{meshcode-2.11.19 → meshcode-2.11.21}/meshcode-backend-wt/meshcode/meshcode_mcp/test_realtime.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|