meshcode 2.11.107__tar.gz → 2.11.108__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.107 → meshcode-2.11.108}/PKG-INFO +1 -1
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/__init__.py +1 -1
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/hostd.py +78 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/meshcode_mcp/server.py +2 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/protocol_handler.py +141 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/run_agent.py +15 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/setup_clients.py +5 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode.egg-info/PKG-INFO +1 -1
- meshcode-2.11.108/meshcode.egg-info/SOURCES.txt +97 -0
- meshcode-2.11.108/meshcode.egg-info/top_level.txt +1 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/pyproject.toml +2 -2
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_wait_open_tasks_contradiction.py +3 -2
- meshcode-2.11.107/meshcode/cli.py +0 -42
- meshcode-2.11.107/meshcode/compat.py +0 -174
- meshcode-2.11.107/meshcode/error_hints.py +0 -74
- meshcode-2.11.107/meshcode/exceptions.py +0 -52
- meshcode-2.11.107/meshcode/invites.py +0 -406
- meshcode-2.11.107/meshcode/launcher.py +0 -353
- meshcode-2.11.107/meshcode/launcher_install.py +0 -414
- meshcode-2.11.107/meshcode/meshcode_mcp/__init__.py +0 -22
- meshcode-2.11.107/meshcode/meshcode_mcp/__main__.py +0 -62
- meshcode-2.11.107/meshcode/meshcode_mcp/test_backend.py +0 -86
- meshcode-2.11.107/meshcode/meshcode_mcp/test_realtime.py +0 -95
- meshcode-2.11.107/meshcode/meshcode_mcp/test_server_wrapper.py +0 -117
- meshcode-2.11.107/meshcode/preferences.py +0 -260
- meshcode-2.11.107/meshcode/protocol_v2.py +0 -129
- meshcode-2.11.107/meshcode/secrets.py +0 -365
- meshcode-2.11.107/meshcode/supervisor.py +0 -186
- meshcode-2.11.107/meshcode/upload.py +0 -125
- meshcode-2.11.107/meshcode-backend-wt/comms_v4.py +0 -1941
- meshcode-2.11.107/meshcode-backend-wt/meshcode/__init__.py +0 -82
- meshcode-2.11.107/meshcode-backend-wt/meshcode/ascii_art.py +0 -638
- meshcode-2.11.107/meshcode-backend-wt/meshcode/comms_v4.py +0 -3563
- meshcode-2.11.107/meshcode-backend-wt/meshcode/meshcode_mcp/backend.py +0 -1261
- meshcode-2.11.107/meshcode-backend-wt/meshcode/meshcode_mcp/realtime.py +0 -460
- meshcode-2.11.107/meshcode-backend-wt/meshcode/meshcode_mcp/server.py +0 -4117
- meshcode-2.11.107/meshcode-backend-wt/meshcode/quickstart.py +0 -148
- meshcode-2.11.107/meshcode-backend-wt/meshcode/run_agent.py +0 -958
- meshcode-2.11.107/meshcode-backend-wt/meshcode/self_update.py +0 -345
- meshcode-2.11.107/meshcode-backend-wt/meshcode/setup_clients.py +0 -926
- meshcode-2.11.107/meshcode-backend-wt/scripts/sentinel.py +0 -257
- meshcode-2.11.107/meshcode-backend-wt/tests/test_rpc_migrations.py +0 -387
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/__init__.py +0 -82
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/ascii_art.py +0 -638
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/cli.py +0 -42
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/comms_v4.py +0 -3563
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/compat.py +0 -174
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/error_hints.py +0 -74
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/exceptions.py +0 -52
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/invites.py +0 -406
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/launcher.py +0 -353
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/launcher_install.py +0 -414
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__init__.py +0 -22
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/__main__.py +0 -62
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/backend.py +0 -1261
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/realtime.py +0 -460
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/server.py +0 -4117
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_backend.py +0 -86
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_realtime.py +0 -95
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/meshcode_mcp/test_server_wrapper.py +0 -117
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/preferences.py +0 -260
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/protocol_v2.py +0 -129
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/quickstart.py +0 -148
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/run_agent.py +0 -958
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/secrets.py +0 -365
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/self_update.py +0 -345
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/setup_clients.py +0 -926
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/supervisor.py +0 -186
- meshcode-2.11.107/meshcode-noun-wt/build/lib/meshcode/upload.py +0 -125
- meshcode-2.11.107/meshcode-noun-wt/comms_v4.py +0 -1941
- meshcode-2.11.107/meshcode-noun-wt/meshcode/__init__.py +0 -82
- meshcode-2.11.107/meshcode-noun-wt/meshcode/ascii_art.py +0 -638
- meshcode-2.11.107/meshcode-noun-wt/meshcode/cli.py +0 -42
- meshcode-2.11.107/meshcode-noun-wt/meshcode/comms_v4.py +0 -3563
- meshcode-2.11.107/meshcode-noun-wt/meshcode/compat.py +0 -174
- meshcode-2.11.107/meshcode-noun-wt/meshcode/error_hints.py +0 -74
- meshcode-2.11.107/meshcode-noun-wt/meshcode/exceptions.py +0 -52
- meshcode-2.11.107/meshcode-noun-wt/meshcode/invites.py +0 -406
- meshcode-2.11.107/meshcode-noun-wt/meshcode/launcher.py +0 -353
- meshcode-2.11.107/meshcode-noun-wt/meshcode/launcher_install.py +0 -414
- meshcode-2.11.107/meshcode-noun-wt/meshcode/meshcode_mcp/__init__.py +0 -22
- meshcode-2.11.107/meshcode-noun-wt/meshcode/meshcode_mcp/__main__.py +0 -62
- meshcode-2.11.107/meshcode-noun-wt/meshcode/meshcode_mcp/backend.py +0 -1261
- meshcode-2.11.107/meshcode-noun-wt/meshcode/meshcode_mcp/realtime.py +0 -460
- meshcode-2.11.107/meshcode-noun-wt/meshcode/meshcode_mcp/server.py +0 -4117
- meshcode-2.11.107/meshcode-noun-wt/meshcode/meshcode_mcp/test_backend.py +0 -86
- meshcode-2.11.107/meshcode-noun-wt/meshcode/meshcode_mcp/test_realtime.py +0 -95
- meshcode-2.11.107/meshcode-noun-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -117
- meshcode-2.11.107/meshcode-noun-wt/meshcode/preferences.py +0 -260
- meshcode-2.11.107/meshcode-noun-wt/meshcode/protocol_v2.py +0 -129
- meshcode-2.11.107/meshcode-noun-wt/meshcode/quickstart.py +0 -148
- meshcode-2.11.107/meshcode-noun-wt/meshcode/run_agent.py +0 -958
- meshcode-2.11.107/meshcode-noun-wt/meshcode/secrets.py +0 -365
- meshcode-2.11.107/meshcode-noun-wt/meshcode/self_update.py +0 -345
- meshcode-2.11.107/meshcode-noun-wt/meshcode/setup_clients.py +0 -926
- meshcode-2.11.107/meshcode-noun-wt/meshcode/supervisor.py +0 -186
- meshcode-2.11.107/meshcode-noun-wt/meshcode/upload.py +0 -125
- meshcode-2.11.107/meshcode-noun-wt/scripts/sentinel.py +0 -257
- meshcode-2.11.107/meshcode-noun-wt/tests/test_core.py +0 -216
- meshcode-2.11.107/meshcode-noun-wt/tests/test_cross_agent_messaging.py +0 -366
- meshcode-2.11.107/meshcode-noun-wt/tests/test_esc_deaf_state.py +0 -361
- meshcode-2.11.107/meshcode-noun-wt/tests/test_exceptions.py +0 -107
- meshcode-2.11.107/meshcode-noun-wt/tests/test_mark_read_batch.py +0 -200
- meshcode-2.11.107/meshcode-noun-wt/tests/test_migration_integrity.py +0 -176
- meshcode-2.11.107/meshcode-noun-wt/tests/test_realtime_event_freshness.py +0 -236
- meshcode-2.11.107/meshcode-noun-wt/tests/test_rls_cross_tenant.py +0 -255
- meshcode-2.11.107/meshcode-noun-wt/tests/test_rpc_migrations.py +0 -387
- meshcode-2.11.107/meshcode-noun-wt/tests/test_security_regressions.py +0 -171
- meshcode-2.11.107/meshcode-noun-wt/tests/test_sentinel.py +0 -148
- meshcode-2.11.107/meshcode-noun-wt/tests/test_status_enum_coverage.py +0 -231
- meshcode-2.11.107/meshcode-tasks-wt/comms_v4.py +0 -1941
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/__init__.py +0 -82
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/ascii_art.py +0 -638
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/cli.py +0 -42
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/comms_v4.py +0 -3563
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/compat.py +0 -174
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/error_hints.py +0 -74
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/exceptions.py +0 -52
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/invites.py +0 -406
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/launcher.py +0 -353
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/launcher_install.py +0 -414
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/meshcode_mcp/__init__.py +0 -22
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/meshcode_mcp/__main__.py +0 -62
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/meshcode_mcp/backend.py +0 -1261
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/meshcode_mcp/realtime.py +0 -460
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/meshcode_mcp/server.py +0 -4117
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/meshcode_mcp/test_backend.py +0 -86
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/meshcode_mcp/test_realtime.py +0 -95
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/meshcode_mcp/test_server_wrapper.py +0 -117
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/preferences.py +0 -260
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/protocol_v2.py +0 -129
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/quickstart.py +0 -148
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/run_agent.py +0 -958
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/secrets.py +0 -365
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/self_update.py +0 -345
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/setup_clients.py +0 -926
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/supervisor.py +0 -186
- meshcode-2.11.107/meshcode-tasks-wt/meshcode/upload.py +0 -125
- meshcode-2.11.107/meshcode-tasks-wt/scripts/sentinel.py +0 -257
- meshcode-2.11.107/meshcode-tasks-wt/tests/test_core.py +0 -216
- meshcode-2.11.107/meshcode-tasks-wt/tests/test_cross_agent_messaging.py +0 -366
- meshcode-2.11.107/meshcode-tasks-wt/tests/test_esc_deaf_state.py +0 -361
- meshcode-2.11.107/meshcode-tasks-wt/tests/test_exceptions.py +0 -107
- meshcode-2.11.107/meshcode-tasks-wt/tests/test_mark_read_batch.py +0 -200
- meshcode-2.11.107/meshcode-tasks-wt/tests/test_migration_integrity.py +0 -176
- meshcode-2.11.107/meshcode-tasks-wt/tests/test_realtime_event_freshness.py +0 -236
- meshcode-2.11.107/meshcode-tasks-wt/tests/test_rls_cross_tenant.py +0 -255
- meshcode-2.11.107/meshcode-tasks-wt/tests/test_rpc_migrations.py +0 -387
- meshcode-2.11.107/meshcode-tasks-wt/tests/test_security_regressions.py +0 -171
- meshcode-2.11.107/meshcode-tasks-wt/tests/test_sentinel.py +0 -148
- meshcode-2.11.107/meshcode-tasks-wt/tests/test_status_enum_coverage.py +0 -231
- meshcode-2.11.107/meshcode.egg-info/PKG-INFO 2 +0 -460
- meshcode-2.11.107/meshcode.egg-info/SOURCES 2.txt +0 -239
- meshcode-2.11.107/meshcode.egg-info/SOURCES.txt +0 -253
- meshcode-2.11.107/meshcode.egg-info/dependency_links 2.txt +0 -1
- meshcode-2.11.107/meshcode.egg-info/entry_points 2.txt +0 -3
- meshcode-2.11.107/meshcode.egg-info/requires 2.txt +0 -13
- meshcode-2.11.107/meshcode.egg-info/top_level 2.txt +0 -4
- meshcode-2.11.107/meshcode.egg-info/top_level.txt +0 -4
- meshcode-2.11.107/tests/test_core.py +0 -216
- meshcode-2.11.107/tests/test_cross_agent_messaging.py +0 -366
- meshcode-2.11.107/tests/test_esc_deaf_state.py +0 -361
- meshcode-2.11.107/tests/test_exceptions.py +0 -107
- meshcode-2.11.107/tests/test_mark_read_batch.py +0 -200
- meshcode-2.11.107/tests/test_migration_integrity.py +0 -176
- meshcode-2.11.107/tests/test_realtime_event_freshness.py +0 -236
- meshcode-2.11.107/tests/test_rls_cross_tenant.py +0 -255
- meshcode-2.11.107/tests/test_security_regressions.py +0 -171
- meshcode-2.11.107/tests/test_sentinel.py +0 -148
- meshcode-2.11.107/tests/test_status_enum_coverage.py +0 -231
- {meshcode-2.11.107 → meshcode-2.11.108}/README.md +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/__main__.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/_session_handoff_template 2.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/_session_handoff_template 3.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/_session_handoff_template.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/_stop_hook_template.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/ascii_art.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/atomic_push.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/claude_update 2.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/claude_update 3.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/claude_update.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/cli.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/comms_v4.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/compat.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/daemon.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/date_parse.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/doctor.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/error_hints.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/exceptions.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/hostd 2.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/invites.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/launcher.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/launcher_install.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/meshcode_mcp/sleep_signals.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/meshcode_mcp/test_boot_timing.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/meshcode_mcp/test_install_guard.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/meshcode_mcp/test_prefs_claude_version.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/meshcode_mcp/test_server_wrapper.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/preferences.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/protocol_v2.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/quickstart.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/rpc_allowlist.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/scripts/check_secrets.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/scripts/race_rate_harness.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/secrets.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/self_update.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/supervisor.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/up 2.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode/up.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/meshcode/upload.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/setup.cfg +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_auto_update_hardening.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_autonomous_closegap_1.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_autonomous_closegap_2.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_autonomous_closegap_3.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_autonomous_prompt_inject 2.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_autonomous_prompt_inject 3.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_autonomous_prompt_inject.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_boot_bug_regression.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_color_truecolor.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/tests/test_core.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/tests/test_cross_agent_messaging.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_date_parse.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_doctor.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_epistemic_v1_python_sdk.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_epistemic_v1_stop_conditions.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/tests/test_esc_deaf_state.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/tests/test_exceptions.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_file_upload.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_init_device_code.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_install_guard.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_lease_sigterm_release.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/tests/test_mark_read_batch.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_marketplace_ratings.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/tests/test_migration_integrity.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/tests/test_realtime_event_freshness.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/tests/test_rls_cross_tenant.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_rpc_grants.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_rpc_migrations.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_run_agent_dry_run.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_run_agent_no_server_import.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/tests/test_security_regressions.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_self_update_user_site.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/tests/test_sentinel.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_setup_path.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_sleep_signals.py +0 -0
- {meshcode-2.11.107/meshcode-backend-wt → meshcode-2.11.108}/tests/test_status_enum_coverage.py +0 -0
- {meshcode-2.11.107 → meshcode-2.11.108}/tests/test_stay_on_loop_hook.py +0 -0
|
@@ -503,6 +503,48 @@ def _do_respawns(api_key: str, host_id: str) -> int:
|
|
|
503
503
|
# only guard; for crash respawns it's a harmless backstop (the server
|
|
504
504
|
# rate-limit at mig404 is stricter and trips first).
|
|
505
505
|
_target = f"{proj}/{agent}"
|
|
506
|
+
# CONVERGENCE GUARD (451d33a0) — recycle fast-path ONLY. Stops the env-mismatch
|
|
507
|
+
# recycle-RESPAWN storm the version-recycle guard can't see (see _recycle_blocked).
|
|
508
|
+
# Counts consecutive recycle-respawns of this target; at _RECYREC_MAX within the
|
|
509
|
+
# window it blocks relaunch + alerts once, instead of storming terminals forever.
|
|
510
|
+
if _is_recycle:
|
|
511
|
+
_rst = _load_state()
|
|
512
|
+
_rblk = _recycle_blocked(_rst, _target)
|
|
513
|
+
if _rblk:
|
|
514
|
+
_log(f"SKIP recycle-respawn {_target}: BLOCKED ({_rblk}) — non-converging recycle; "
|
|
515
|
+
f"holding relaunch (auto-retry after {_RECYREC_BLOCK_TTL_S}s or a manual Start).")
|
|
516
|
+
continue
|
|
517
|
+
_now = time.time()
|
|
518
|
+
_rrall = dict(_rst.get("recyrespawn") or {})
|
|
519
|
+
_rr = dict(_rrall.get(_target) or {})
|
|
520
|
+
if _rr.get("last_ts") and (_now - float(_rr["last_ts"])) <= _RECYREC_WINDOW_S:
|
|
521
|
+
_rr["count"] = int(_rr.get("count", 0)) + 1
|
|
522
|
+
else:
|
|
523
|
+
_rr = {"count": 1} # window elapsed (converged/idle) -> fresh count, clears any stale block
|
|
524
|
+
_rr["last_ts"] = _now
|
|
525
|
+
if _rr["count"] >= _RECYREC_MAX:
|
|
526
|
+
_rr["blocked_ts"] = _now
|
|
527
|
+
_rr["reason"] = "recycle_no_converge"
|
|
528
|
+
_rrall[_target] = _rr
|
|
529
|
+
_rst["recyrespawn"] = _rrall
|
|
530
|
+
_save_state(_rst)
|
|
531
|
+
_log(f"RECYCLE-STUCK {_target}: {_rr['count']} recycle-respawns in <={_RECYREC_WINDOW_S}s "
|
|
532
|
+
f"without converging — spawn env likely older than hostd; align it "
|
|
533
|
+
f"(e.g. ~/meshcode-env/bin/pip install -U meshcode==<disk>). BLOCKING recycle-respawns "
|
|
534
|
+
f"for {_RECYREC_BLOCK_TTL_S}s. [recycle_blocked_reason=recycle_no_converge]")
|
|
535
|
+
try: # stop the dashboard's eternal 'launching…' spinner (same pattern as the breaker)
|
|
536
|
+
_rpc("mc_resolve_launch", {
|
|
537
|
+
"p_api_key": api_key, "p_project_id": c.get("project_id"), "p_agent": agent,
|
|
538
|
+
"p_status": "failed", "p_reason": "recycle_no_converge",
|
|
539
|
+
"p_detail": "recycle keeps relaunching without converging — this agent's MCP env is "
|
|
540
|
+
"older than the host; align it (pip install -U meshcode==<host version>), "
|
|
541
|
+
"then Start again"})
|
|
542
|
+
except Exception:
|
|
543
|
+
pass
|
|
544
|
+
continue
|
|
545
|
+
_rrall[_target] = _rr
|
|
546
|
+
_rst["recyrespawn"] = _rrall
|
|
547
|
+
_save_state(_rst)
|
|
506
548
|
_ok, _burst, _why = _spawn_rate_ok(_target)
|
|
507
549
|
if not _ok:
|
|
508
550
|
_log(f"SKIP {'recycle-' if _is_recycle else ''}respawn {_target}: rate-limited ({_why})")
|
|
@@ -591,6 +633,40 @@ def _save_state(st: dict) -> None:
|
|
|
591
633
|
pass
|
|
592
634
|
|
|
593
635
|
|
|
636
|
+
# ------------------------------------------------------------------
|
|
637
|
+
# Recycle non-convergence guard (451d33a0). The env-mismatch storm is a recycle-
|
|
638
|
+
# RESPAWN loop (log: "RECYCLE-RESPAWN <agent> (stale 15-37s, count=0)" every
|
|
639
|
+
# ~15-37s) that the version-recycle guard in _do_version_recycles can NOT see —
|
|
640
|
+
# that guard sits on the version-recycle REQUEST path and its counter only
|
|
641
|
+
# advances on a successful mc_request_recycle, so when a recycle is already
|
|
642
|
+
# pending (requested=False) the counter stays 0 and never trips. This guard sits
|
|
643
|
+
# on the recycle fast-path itself: if a target recycle-respawns _RECYREC_MAX times
|
|
644
|
+
# within _RECYREC_WINDOW_S without converging, STOP relaunching it + alert once
|
|
645
|
+
# (env mismatch) instead of storming terminals forever. Self-heals — the block
|
|
646
|
+
# lifts after _RECYREC_BLOCK_TTL_S (one clean retry; re-blocks if it storms again),
|
|
647
|
+
# and the counter resets the moment the target stops re-qualifying (converged).
|
|
648
|
+
_RECYREC_MAX = _env_int("MESHCODE_RECYREC_MAX", 3, 2) # recycle-respawns before non-converge
|
|
649
|
+
_RECYREC_WINDOW_S = _env_int("MESHCODE_RECYREC_WINDOW_SEC", 120, 30) # consecutive-respawn counting window
|
|
650
|
+
_RECYREC_BLOCK_TTL_S = _env_int("MESHCODE_RECYREC_BLOCK_TTL_SEC", 600, 60) # block duration before a retry
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
def _recycle_blocked(st, target, now=None):
|
|
654
|
+
"""Shared guard consulted by BOTH _do_respawns (skip the recycle fast-path)
|
|
655
|
+
and _do_version_recycles (don't version-recycle a non-converging target).
|
|
656
|
+
Returns a reason string while `target` is blocked, else None. The block
|
|
657
|
+
auto-expires after _RECYREC_BLOCK_TTL_S so a fixed env gets one clean retry."""
|
|
658
|
+
now = now if now is not None else time.time()
|
|
659
|
+
rec = (st.get("recyrespawn") or {}).get(target) or {}
|
|
660
|
+
bts = rec.get("blocked_ts")
|
|
661
|
+
if bts:
|
|
662
|
+
try:
|
|
663
|
+
if (now - float(bts)) < _RECYREC_BLOCK_TTL_S:
|
|
664
|
+
return rec.get("reason") or "recycle_no_converge"
|
|
665
|
+
except (TypeError, ValueError):
|
|
666
|
+
return None
|
|
667
|
+
return None
|
|
668
|
+
|
|
669
|
+
|
|
594
670
|
def _spawn_rate_ok(target: str):
|
|
595
671
|
"""Anti-spam circuit breaker. Returns (ok, tripped_burst, reason).
|
|
596
672
|
|
|
@@ -1442,6 +1518,8 @@ def _do_version_recycles(api_key: str, host_id: str) -> int:
|
|
|
1442
1518
|
proj, agent = a.get("project_name"), a.get("name")
|
|
1443
1519
|
if not proj or not agent:
|
|
1444
1520
|
continue
|
|
1521
|
+
if _recycle_blocked(st, f"{proj}/{agent}", now):
|
|
1522
|
+
continue # 451d33a0 unify: already blocked as a non-converging recycle — don't also version-recycle it
|
|
1445
1523
|
key = f"verrec/{a.get('project_id')}/{agent}"
|
|
1446
1524
|
if now - float(st.get(key, 0) or 0) < 1800:
|
|
1447
1525
|
continue # rate-limit: <=1 version-recycle per agent / 30min (no recycle-storm)
|
|
@@ -1731,6 +1731,8 @@ def _build_instructions() -> str:
|
|
|
1731
1731
|
|
|
1732
1732
|
RULES: MCP tools only. Tasks > messages. Messages <100 tokens (long → task). No empty acks, JSON only. Thread via in_reply_to. sensitive=True for secrets. Sync vs async: for turn-based/shared-state work (chess, lock-step, "who goes first"), use meshcode_call (sync RPC, 30s) — async meshcode_send crosses ~50%/turn between same-model agents and yields-pongs.
|
|
1733
1733
|
|
|
1734
|
+
REPLY TO HUMANS VIA THE MESH, NOT THE TERMINAL (product default, Samuel 2026-06-04): when you answer a human (sammybenu/Samuel/ian/fis), you MUST meshcode_send to the mesh. The human watches the DASHBOARD — your Claude Code terminal text and your thinking are INVISIBLE to them, so a terminal-only reply reads as silence ("¿por qué no me contestas?" even while you "answered"). meshcode_send is the ONLY channel they see. To humans write plain prose in THEIR language (Spanish for Samuel), never JSON; JSON-only is for agent↔agent.
|
|
1735
|
+
|
|
1734
1736
|
CLOSE TASKS IMMEDIATELY (#2 rule, sammybenu 2026-05-22T21:06Z): every time you finish/ship/deliver work for a claimed task, call meshcode_task_complete BEFORE re-entering wait. NO "I'll close it after one more thing." NO leaving claimed tasks lingering in_progress while you do something else — that creates phantom in-progress on the dashboard and the human gets angry. If the work needs human review, set requires_approval=true at task_create OR call meshcode_task_complete (it routes to in_review if reviewer set). The mesh dashboard reflects mc_tasks.status in real-time; stale in_progress = lying to the human.
|
|
1735
1737
|
|
|
1736
1738
|
WORK ASSIGNED TASKS IMMEDIATELY (#3 rule): when meshcode_wait returns pending_tasks or auto_started_task, your NEXT action MUST be to work that task. Do NOT re-enter wait, do NOT ask "what should I do" — the task description tells you. Sequence: read task description → execute the work → meshcode_task_complete → meshcode_wait (which surfaces the next task). One by one until the queue is empty.
|
|
@@ -17,15 +17,125 @@ from __future__ import annotations
|
|
|
17
17
|
import json
|
|
18
18
|
import os
|
|
19
19
|
import platform
|
|
20
|
+
import re
|
|
20
21
|
import shlex
|
|
21
22
|
import shutil
|
|
22
23
|
import subprocess
|
|
23
24
|
import sys
|
|
25
|
+
import time
|
|
24
26
|
import urllib.parse
|
|
25
27
|
from pathlib import Path
|
|
26
28
|
from typing import Iterable, Optional
|
|
27
29
|
|
|
28
30
|
|
|
31
|
+
# SECURITY (audit P1-4 RCE/DoS): agent names get interpolated into the platform
|
|
32
|
+
# shell / cmd.exe launch string below. shlex.quote is POSIX-only and does NOT
|
|
33
|
+
# neutralize cmd.exe metacharacters, so a name like `x" & calc & "` would break
|
|
34
|
+
# out of the quoting on Windows (cmd /k) and execute arbitrary code. Real agent
|
|
35
|
+
# names are always plain identifiers — hard-reject anything else at the boundary.
|
|
36
|
+
# Hardened allowlist (chief@mesh-dev spec):
|
|
37
|
+
# - first char [A-Za-z0-9_] -> NO leading dash, so `-rf` / `--version` can't be
|
|
38
|
+
# read as a flag/arg if the name ever reaches a bare positional (arg-injection)
|
|
39
|
+
# - then [A-Za-z0-9_-]{0,63} -> total length 1..64, capping the 300-char-name DoS
|
|
40
|
+
# - anchor with \Z, not $ -> in Python `$` also matches just before a trailing
|
|
41
|
+
# newline, so `name\n` would slip through `^...$`. \Z = absolute end of string.
|
|
42
|
+
_VALID_AGENT_NAME = re.compile(r"^[A-Za-z0-9_][A-Za-z0-9_-]{0,63}\Z")
|
|
43
|
+
|
|
44
|
+
# Launch-storm control (audit P1: each "Launch All" click spawns a terminal per
|
|
45
|
+
# agent UNCONDITIONALLY; repeat clicks storm the desktop with dup terminals).
|
|
46
|
+
# Two dedup layers + a hard cap:
|
|
47
|
+
# (1) heartbeat liveness — skip agents already running (best-effort, network)
|
|
48
|
+
# (2) local cooldown file — per-agent last-spawn ts; covers the spawn->first-
|
|
49
|
+
# heartbeat gap where (1) is blind, and absorbs rapid repeat-clicks. No
|
|
50
|
+
# network, so it is the always-on backstop.
|
|
51
|
+
_MAX_BATCH = 32 # hard cap: agents spawned / call
|
|
52
|
+
_LAUNCH_COOLDOWN_S = 30 # min seconds between same-agent spawns
|
|
53
|
+
_LIVE_HEARTBEAT_S = 20 # heartbeat age < this = agent live
|
|
54
|
+
_COOLDOWN_FILE = Path.home() / ".meshcode" / "launch_cooldown.json"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def is_valid_agent_name(name: str) -> bool:
|
|
58
|
+
"""Shared allowlist gate — True iff `name` is a safe agent identifier.
|
|
59
|
+
|
|
60
|
+
Single source of truth for the launch path AND `meshcode run` (run_agent),
|
|
61
|
+
so the RCE/DoS boundary can't drift between callers.
|
|
62
|
+
"""
|
|
63
|
+
return bool(name) and bool(_VALID_AGENT_NAME.match(name))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _read_cooldowns() -> dict:
|
|
67
|
+
try:
|
|
68
|
+
return json.loads(_COOLDOWN_FILE.read_text(encoding="utf-8")) or {}
|
|
69
|
+
except Exception:
|
|
70
|
+
return {}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _record_spawn(name: str, now: Optional[float] = None) -> None:
|
|
74
|
+
"""Stamp `name`'s last-spawn ts in the cooldown file (best-effort, atomic)."""
|
|
75
|
+
try:
|
|
76
|
+
data = _read_cooldowns()
|
|
77
|
+
data[name] = now if now is not None else time.time()
|
|
78
|
+
_COOLDOWN_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
79
|
+
tmp = _COOLDOWN_FILE.with_suffix(".json.tmp")
|
|
80
|
+
tmp.write_text(json.dumps(data), encoding="utf-8")
|
|
81
|
+
tmp.replace(_COOLDOWN_FILE)
|
|
82
|
+
except Exception:
|
|
83
|
+
pass
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _in_cooldown(name: str, cooldowns: dict, now: float) -> bool:
|
|
87
|
+
try:
|
|
88
|
+
return (now - float(cooldowns.get(name, 0))) < _LAUNCH_COOLDOWN_S
|
|
89
|
+
except (TypeError, ValueError):
|
|
90
|
+
return False
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def live_agent_names(names: Iterable[str], project: Optional[str] = None) -> set:
|
|
94
|
+
"""Best-effort set of `names` whose mc_agents heartbeat is fresh (<20s).
|
|
95
|
+
|
|
96
|
+
Shared liveness primitive for the dedup lane (co-owned w/ chief@mesh-dev).
|
|
97
|
+
Network + creds required; ANY failure (offline, no api_key, project
|
|
98
|
+
unresolved, RPC error) returns an EMPTY set so a legitimate launch is never
|
|
99
|
+
blocked — the cooldown file is the always-on backstop. NB: the meshcode://
|
|
100
|
+
launch URL carries no project today, so resolution falls back to
|
|
101
|
+
MESHCODE_PROJECT env; pass `project` explicitly for reliable liveness.
|
|
102
|
+
"""
|
|
103
|
+
wanted = {n for n in names if is_valid_agent_name(n)}
|
|
104
|
+
if not wanted:
|
|
105
|
+
return set()
|
|
106
|
+
try:
|
|
107
|
+
import importlib
|
|
108
|
+
cv = importlib.import_module("meshcode.comms_v4")
|
|
109
|
+
api_key = cv._load_api_key_for_cli()
|
|
110
|
+
proj = project or os.environ.get("MESHCODE_PROJECT")
|
|
111
|
+
if not api_key or not proj:
|
|
112
|
+
return set()
|
|
113
|
+
pid = cv.get_project_id(proj)
|
|
114
|
+
if not pid:
|
|
115
|
+
return set()
|
|
116
|
+
r = cv.sb_rpc("mc_get_agents", {"p_api_key": api_key, "p_project_id": pid,
|
|
117
|
+
"p_agent_name": None, "p_select": None,
|
|
118
|
+
"p_limit": None})
|
|
119
|
+
agents = (r or {}).get("agents") or []
|
|
120
|
+
from datetime import datetime, timezone
|
|
121
|
+
now = datetime.now(timezone.utc)
|
|
122
|
+
live = set()
|
|
123
|
+
for a in agents:
|
|
124
|
+
nm = a.get("name")
|
|
125
|
+
ts = a.get("last_heartbeat")
|
|
126
|
+
if nm not in wanted or not ts:
|
|
127
|
+
continue
|
|
128
|
+
try:
|
|
129
|
+
dt = datetime.fromisoformat(str(ts).replace("Z", "+00:00"))
|
|
130
|
+
if (now - dt).total_seconds() < _LIVE_HEARTBEAT_S:
|
|
131
|
+
live.add(nm)
|
|
132
|
+
except Exception:
|
|
133
|
+
continue
|
|
134
|
+
return live
|
|
135
|
+
except Exception:
|
|
136
|
+
return set()
|
|
137
|
+
|
|
138
|
+
|
|
29
139
|
# ============================================================
|
|
30
140
|
# Per-OS terminal spawn
|
|
31
141
|
# ============================================================
|
|
@@ -165,7 +275,37 @@ def cmd_launch_batch(agent_names: Iterable[str]) -> int:
|
|
|
165
275
|
# Resolve `meshcode` binary path (CLI wrapper installed by pip).
|
|
166
276
|
mc_bin = shutil.which("meshcode") or "meshcode"
|
|
167
277
|
|
|
278
|
+
# RATE LIMIT: hard-cap the batch so a crafted `agents=` list can't spawn an
|
|
279
|
+
# unbounded number of terminals (DoS). Excess is reported, never launched.
|
|
280
|
+
if len(names) > _MAX_BATCH:
|
|
281
|
+
for name in names[_MAX_BATCH:]:
|
|
282
|
+
skipped.append({"agent": name, "reason": f"batch cap {_MAX_BATCH} exceeded"})
|
|
283
|
+
names = names[:_MAX_BATCH]
|
|
284
|
+
|
|
285
|
+
# DEDUP inputs computed ONCE for the whole batch: live set (heartbeat) +
|
|
286
|
+
# cooldown snapshot. `now` is shared so all spawns in this call stamp the
|
|
287
|
+
# same instant.
|
|
288
|
+
live = live_agent_names(names)
|
|
289
|
+
cooldowns = _read_cooldowns()
|
|
290
|
+
now = time.time()
|
|
291
|
+
|
|
168
292
|
for name in names:
|
|
293
|
+
# SECURITY (audit P1-4 RCE/DoS): reject any name that isn't a plain agent
|
|
294
|
+
# identifier BEFORE it reaches the shell/cmd.exe launch string below.
|
|
295
|
+
if not is_valid_agent_name(name):
|
|
296
|
+
skipped.append({"agent": name,
|
|
297
|
+
"reason": "invalid agent name (allowlist ^[A-Za-z0-9_][A-Za-z0-9_-]{0,63}$)"})
|
|
298
|
+
continue
|
|
299
|
+
# DEDUP 1: agent already running (fresh heartbeat) -> don't double-spawn.
|
|
300
|
+
if name in live:
|
|
301
|
+
skipped.append({"agent": name, "reason": "already live (heartbeat <20s)"})
|
|
302
|
+
continue
|
|
303
|
+
# DEDUP 2: spawned within the cooldown window -> absorbs repeat-clicks and
|
|
304
|
+
# the spawn->first-heartbeat gap that layer 1 cannot see.
|
|
305
|
+
if _in_cooldown(name, cooldowns, now):
|
|
306
|
+
skipped.append({"agent": name,
|
|
307
|
+
"reason": f"cooldown {_LAUNCH_COOLDOWN_S}s (recently launched)"})
|
|
308
|
+
continue
|
|
169
309
|
# PER-PLATFORM quoting (mesh-core FIX2): cmd.exe wants double-quotes, not POSIX shlex
|
|
170
310
|
# single-quotes (cmd.exe passes single-quotes through literally -> file-not-found).
|
|
171
311
|
if sys.platform == "win32":
|
|
@@ -175,6 +315,7 @@ def cmd_launch_batch(agent_names: Iterable[str]) -> int:
|
|
|
175
315
|
ok, info = _spawn_terminal(cmd)
|
|
176
316
|
if ok:
|
|
177
317
|
launched.append(name)
|
|
318
|
+
_record_spawn(name, now)
|
|
178
319
|
else:
|
|
179
320
|
skipped.append({"agent": name, "reason": info})
|
|
180
321
|
|
|
@@ -695,6 +695,21 @@ def run(agent: str, project: Optional[str] = None, editor_override: Optional[str
|
|
|
695
695
|
boot path flips mc_agents.autonomous_mode=true at register time.
|
|
696
696
|
Task f248d98e Phase 1 (no-DDL subset).
|
|
697
697
|
"""
|
|
698
|
+
# SECURITY (audit P1-4): the agent name flows into workspace path lookups and
|
|
699
|
+
# a child editor/`claude` launch. Reject anything that isn't a plain agent
|
|
700
|
+
# identifier (esp. a leading dash, which a child tool could read as a flag) —
|
|
701
|
+
# belt-and-suspenders with the launch-batch allowlist (shared source of truth).
|
|
702
|
+
try:
|
|
703
|
+
from meshcode.protocol_handler import is_valid_agent_name as _ok_name
|
|
704
|
+
except Exception:
|
|
705
|
+
import re as _re
|
|
706
|
+
_ok_name = lambda n: bool(n) and bool(
|
|
707
|
+
_re.match(r"^[A-Za-z0-9_][A-Za-z0-9_-]{0,63}\Z", str(n)))
|
|
708
|
+
if not _ok_name(agent):
|
|
709
|
+
print(json.dumps({"ok": False, "error": f"invalid agent name: {agent!r}",
|
|
710
|
+
"error_code": "invalid_agent_name"}))
|
|
711
|
+
return 1
|
|
712
|
+
|
|
698
713
|
# Propagate autonomous flag to the editor + MCP child via env var.
|
|
699
714
|
if autonomous:
|
|
700
715
|
os.environ["MESHCODE_AUTONOMOUS"] = "1"
|
|
@@ -1333,6 +1333,11 @@ If `meshcode_wait()` times out, call it again with a 2× longer timeout (cap 180
|
|
|
1333
1333
|
- Tasks > messages. Use `meshcode_task_create / task_claim / task_complete`
|
|
1334
1334
|
for trackable work. Keep messages <100 tokens (signals only).
|
|
1335
1335
|
- No empty acks. JSON reports only.
|
|
1336
|
+
- **Reply to humans via the mesh, NOT the terminal** (product default): when you
|
|
1337
|
+
answer a human (Samuel/sammybenu/ian/fis), `meshcode_send` to the mesh. The
|
|
1338
|
+
human watches the DASHBOARD — your Claude Code terminal text + thinking are
|
|
1339
|
+
invisible to them, so a terminal-only reply reads as silence. Write plain prose
|
|
1340
|
+
in their language (Spanish for Samuel), never JSON — JSON is for agent↔agent.
|
|
1336
1341
|
- Threading: pass `in_reply_to`.
|
|
1337
1342
|
- Sync vs async: for turn-based or shared-state coordination (chess, single-writer
|
|
1338
1343
|
doc, lock-step handoffs, "who goes first" decisions), prefer
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
meshcode/__init__.py
|
|
4
|
+
meshcode/__main__.py
|
|
5
|
+
meshcode/_session_handoff_template 2.py
|
|
6
|
+
meshcode/_session_handoff_template 3.py
|
|
7
|
+
meshcode/_session_handoff_template.py
|
|
8
|
+
meshcode/_stop_hook_template.py
|
|
9
|
+
meshcode/ascii_art.py
|
|
10
|
+
meshcode/atomic_push.py
|
|
11
|
+
meshcode/claude_update 2.py
|
|
12
|
+
meshcode/claude_update 3.py
|
|
13
|
+
meshcode/claude_update.py
|
|
14
|
+
meshcode/cli.py
|
|
15
|
+
meshcode/comms_v4.py
|
|
16
|
+
meshcode/compat.py
|
|
17
|
+
meshcode/daemon.py
|
|
18
|
+
meshcode/date_parse.py
|
|
19
|
+
meshcode/doctor.py
|
|
20
|
+
meshcode/error_hints.py
|
|
21
|
+
meshcode/exceptions.py
|
|
22
|
+
meshcode/hostd 2.py
|
|
23
|
+
meshcode/hostd.py
|
|
24
|
+
meshcode/invites.py
|
|
25
|
+
meshcode/launcher.py
|
|
26
|
+
meshcode/launcher_install.py
|
|
27
|
+
meshcode/preferences.py
|
|
28
|
+
meshcode/protocol_handler.py
|
|
29
|
+
meshcode/protocol_v2.py
|
|
30
|
+
meshcode/quickstart.py
|
|
31
|
+
meshcode/rpc_allowlist.py
|
|
32
|
+
meshcode/run_agent.py
|
|
33
|
+
meshcode/secrets.py
|
|
34
|
+
meshcode/self_update.py
|
|
35
|
+
meshcode/setup_clients.py
|
|
36
|
+
meshcode/supervisor.py
|
|
37
|
+
meshcode/up 2.py
|
|
38
|
+
meshcode/up.py
|
|
39
|
+
meshcode/upload.py
|
|
40
|
+
meshcode.egg-info/PKG-INFO
|
|
41
|
+
meshcode.egg-info/SOURCES.txt
|
|
42
|
+
meshcode.egg-info/dependency_links.txt
|
|
43
|
+
meshcode.egg-info/entry_points.txt
|
|
44
|
+
meshcode.egg-info/requires.txt
|
|
45
|
+
meshcode.egg-info/top_level.txt
|
|
46
|
+
meshcode/meshcode_mcp/__init__.py
|
|
47
|
+
meshcode/meshcode_mcp/__main__.py
|
|
48
|
+
meshcode/meshcode_mcp/backend.py
|
|
49
|
+
meshcode/meshcode_mcp/realtime.py
|
|
50
|
+
meshcode/meshcode_mcp/server.py
|
|
51
|
+
meshcode/meshcode_mcp/sleep_signals.py
|
|
52
|
+
meshcode/meshcode_mcp/test_backend.py
|
|
53
|
+
meshcode/meshcode_mcp/test_boot_timing.py
|
|
54
|
+
meshcode/meshcode_mcp/test_install_guard.py
|
|
55
|
+
meshcode/meshcode_mcp/test_prefs_claude_version.py
|
|
56
|
+
meshcode/meshcode_mcp/test_realtime.py
|
|
57
|
+
meshcode/meshcode_mcp/test_server_wrapper.py
|
|
58
|
+
meshcode/scripts/check_secrets.py
|
|
59
|
+
meshcode/scripts/race_rate_harness.py
|
|
60
|
+
tests/test_auto_update_hardening.py
|
|
61
|
+
tests/test_autonomous_closegap_1.py
|
|
62
|
+
tests/test_autonomous_closegap_2.py
|
|
63
|
+
tests/test_autonomous_closegap_3.py
|
|
64
|
+
tests/test_autonomous_prompt_inject 2.py
|
|
65
|
+
tests/test_autonomous_prompt_inject 3.py
|
|
66
|
+
tests/test_autonomous_prompt_inject.py
|
|
67
|
+
tests/test_boot_bug_regression.py
|
|
68
|
+
tests/test_color_truecolor.py
|
|
69
|
+
tests/test_core.py
|
|
70
|
+
tests/test_cross_agent_messaging.py
|
|
71
|
+
tests/test_date_parse.py
|
|
72
|
+
tests/test_doctor.py
|
|
73
|
+
tests/test_epistemic_v1_python_sdk.py
|
|
74
|
+
tests/test_epistemic_v1_stop_conditions.py
|
|
75
|
+
tests/test_esc_deaf_state.py
|
|
76
|
+
tests/test_exceptions.py
|
|
77
|
+
tests/test_file_upload.py
|
|
78
|
+
tests/test_init_device_code.py
|
|
79
|
+
tests/test_install_guard.py
|
|
80
|
+
tests/test_lease_sigterm_release.py
|
|
81
|
+
tests/test_mark_read_batch.py
|
|
82
|
+
tests/test_marketplace_ratings.py
|
|
83
|
+
tests/test_migration_integrity.py
|
|
84
|
+
tests/test_realtime_event_freshness.py
|
|
85
|
+
tests/test_rls_cross_tenant.py
|
|
86
|
+
tests/test_rpc_grants.py
|
|
87
|
+
tests/test_rpc_migrations.py
|
|
88
|
+
tests/test_run_agent_dry_run.py
|
|
89
|
+
tests/test_run_agent_no_server_import.py
|
|
90
|
+
tests/test_security_regressions.py
|
|
91
|
+
tests/test_self_update_user_site.py
|
|
92
|
+
tests/test_sentinel.py
|
|
93
|
+
tests/test_setup_path.py
|
|
94
|
+
tests/test_sleep_signals.py
|
|
95
|
+
tests/test_status_enum_coverage.py
|
|
96
|
+
tests/test_stay_on_loop_hook.py
|
|
97
|
+
tests/test_wait_open_tasks_contradiction.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
meshcode
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "meshcode"
|
|
7
|
-
version = "2.11.
|
|
7
|
+
version = "2.11.108"
|
|
8
8
|
description = "Real-time communication between AI agents — Supabase-backed CLI"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -47,7 +47,7 @@ testpaths = ["tests"]
|
|
|
47
47
|
addopts = "--durations=10 --durations-min=0.5 -v --tb=short"
|
|
48
48
|
|
|
49
49
|
[tool.setuptools.packages.find]
|
|
50
|
-
include = ["meshcode
|
|
50
|
+
include = ["meshcode", "meshcode.*"]
|
|
51
51
|
|
|
52
52
|
[tool.setuptools.package-data]
|
|
53
53
|
meshcode = ["comms_v4.py"]
|
|
@@ -74,8 +74,9 @@ class TestWaitContradictionFix(unittest.TestCase):
|
|
|
74
74
|
# Look for the count_pending check inside meshcode_wait.
|
|
75
75
|
wait_def_idx = self.source.find("async def meshcode_wait")
|
|
76
76
|
self.assertGreater(wait_def_idx, 0)
|
|
77
|
-
#
|
|
78
|
-
|
|
77
|
+
# 8000 chars covers the function body comfortably (grew after the
|
|
78
|
+
# CHAT-DELIVERY-FIX which adds an unread-priority guard before task_pull).
|
|
79
|
+
wait_body = self.source[wait_def_idx:wait_def_idx + 8000]
|
|
79
80
|
self.assertIn("count_pending", wait_body,
|
|
80
81
|
"messages-block-wait path must still call count_pending")
|
|
81
82
|
self.assertIn("read_inbox", wait_body,
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""MeshCode CLI entry point for pip install."""
|
|
3
|
-
import sys
|
|
4
|
-
import os
|
|
5
|
-
|
|
6
|
-
# Force UTF-8 on stdout/stderr for Windows terminals (cp1252 default crashes
|
|
7
|
-
# on emojis, em-dashes, and any non-ASCII output the CLI prints).
|
|
8
|
-
# Python 3.7+ supports reconfigure(); older versions get a no-op.
|
|
9
|
-
try:
|
|
10
|
-
if hasattr(sys.stdout, "reconfigure"):
|
|
11
|
-
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
12
|
-
if hasattr(sys.stderr, "reconfigure"):
|
|
13
|
-
sys.stderr.reconfigure(encoding="utf-8", errors="replace")
|
|
14
|
-
except Exception:
|
|
15
|
-
pass
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def main():
|
|
19
|
-
"""Entry point that delegates to comms_v4.py within the package."""
|
|
20
|
-
# Find comms_v4.py — first in package dir, then in repo root
|
|
21
|
-
pkg_dir = os.path.dirname(os.path.abspath(__file__))
|
|
22
|
-
repo_root = os.path.dirname(pkg_dir)
|
|
23
|
-
|
|
24
|
-
for candidate in [
|
|
25
|
-
os.path.join(pkg_dir, "comms_v4.py"),
|
|
26
|
-
os.path.join(repo_root, "comms_v4.py"),
|
|
27
|
-
]:
|
|
28
|
-
if os.path.exists(candidate):
|
|
29
|
-
sys.argv[0] = candidate
|
|
30
|
-
# Set __name__ and __file__ for the script
|
|
31
|
-
globs = {"__name__": "__main__", "__file__": candidate}
|
|
32
|
-
# Force UTF-8 on Windows (cp1252 default crashes on non-ASCII)
|
|
33
|
-
with open(candidate, encoding="utf-8") as f:
|
|
34
|
-
exec(compile(f.read(), candidate, "exec"), globs)
|
|
35
|
-
return
|
|
36
|
-
|
|
37
|
-
print("[meshcode] ERROR: comms_v4.py not found. Reinstall: pip install meshcode")
|
|
38
|
-
sys.exit(1)
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if __name__ == "__main__":
|
|
42
|
-
main()
|