swarph-cli 0.35.0__tar.gz → 0.37.0__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.
- {swarph_cli-0.35.0/src/swarph_cli.egg-info → swarph_cli-0.37.0}/PKG-INFO +1 -1
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/pyproject.toml +1 -1
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/__init__.py +1 -1
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/board.py +6 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/memory_sync.py +14 -55
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/spawn.py +94 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0/src/swarph_cli.egg-info}/PKG-INFO +1 -1
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli.egg-info/SOURCES.txt +1 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_brain_ask_command.py +1 -1
- swarph_cli-0.37.0/tests/test_memory_sync_membrane.py +94 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_watchdog.py +1 -1
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/LICENSE +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/README.md +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/setup.cfg +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/capture/__init__.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/capture/harden.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/capture/lineage.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/capture/liveness.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/capture/manifest.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/capture/paths.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/capture/verify.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/cell.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/chain_token.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/_display.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/_gateway_client.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/brain.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/brain_ask.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/cell.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/channel.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/codegraph.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/event.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/gateway.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/highlight.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/hooks.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/install_multiplexer.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/lane.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/mcp_server.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/memory.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/mesh.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/okf_links.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/onboard.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/schedule.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/service.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/timeline.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/delivery_queue.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/gateway/__init__.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/gateway/feature_registry.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/gateway/lanes_control.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/gateway/schema.sql +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/gateway/server.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/gateway/services_control.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/main.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/multiplexer.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/service/__init__.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/service/app.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/service/providers.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/session_bridge.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/stall_alert.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/systemd/swarph-watchdog.service +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli/systemd/swarph-watchdog.timer +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_artifact_add.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_board_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_brain_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_caller_meta_guard.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_capture_lineage.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_capture_liveness.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_capture_manifest.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_capture_paths.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_capture_security.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_cell_command_dispatch.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_cell_harden.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_cell_loader.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_cell_verify.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_chain_token.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_channel_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_channel_post.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_claude_tmux_template.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_codegraph_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_codegraph_mcp.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_compress_caller_convention.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_daemon_delivery.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_delivery_queue.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_display_sanitize.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_event_emit.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_gateway_brain.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_gateway_client.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_gateway_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_highlight_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_hooks_activity_marker.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_hooks_add.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_hooks_bundle.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_import_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_init_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_install_hook.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_install_multiplexer_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_lane_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_main.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_mcp_server.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_memory_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_memory_gateway.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_mesh_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_mesh_inbox_mark_read.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_mesh_inbox_sanitize.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_mesh_sidecar_wake_survives_read.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_meta_edge_identity.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_multiplexer.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_okf_links.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_onboard_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_providers_isolation.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_repl_caller_convention.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_schedule_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_security.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_service_app.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_service_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_service_providers.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_session_bridge_inject.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_session_bridge_probe.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_session_bridge_resolve.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_session_path_role_gate.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_spawn_base_hoist.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_spawn_live_pin.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_spawn_mitosis_lineage.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_spawn_tmux_session.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_spawn_windows_relaunch.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_stall_alert.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_timeline_command.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_version_consistency.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_watchdog_emit_health.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_watchdog_install_flags.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_watchdog_model_rung.py +0 -0
- {swarph_cli-0.35.0 → swarph_cli-0.37.0}/tests/test_watchdog_stale_peers.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.37.0
|
|
4
4
|
Summary: The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, session `import`, and a stranded-session `watchdog`.
|
|
5
5
|
Author: Pierre Samson, Claude Opus
|
|
6
6
|
License: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "swarph-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.37.0"
|
|
8
8
|
description = "The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, session `import`, and a stranded-session `watchdog`."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -167,6 +167,9 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
167
167
|
ck.add_argument("--json", action="store_true"); _add_common(ck)
|
|
168
168
|
cn = cards.add_parser("assign", help="set a card's assignee")
|
|
169
169
|
cn.add_argument("id", type=int); cn.add_argument("assignee"); cn.add_argument("--json", action="store_true"); _add_common(cn)
|
|
170
|
+
cr = cards.add_parser("ready", help="flag a card ready-to-advance (move_ready) for the orchestrator")
|
|
171
|
+
cr.add_argument("id", type=int); cr.add_argument("--clear", action="store_true", help="unset move_ready")
|
|
172
|
+
cr.add_argument("--json", action="store_true"); _add_common(cr)
|
|
170
173
|
return p
|
|
171
174
|
|
|
172
175
|
|
|
@@ -232,6 +235,9 @@ def run_board(argv: list[str]) -> int:
|
|
|
232
235
|
if args.command == "assign":
|
|
233
236
|
st, d = _patch_json(f"{gw}/board/cards/{args.id}", {"actor": self_name, "assignee": args.assignee}, token)
|
|
234
237
|
return _out(st, d, lambda x: f"card #{x.get('id')} assignee -> {x.get('assignee')}", aj)
|
|
238
|
+
if args.command == "ready":
|
|
239
|
+
st, d = _patch_json(f"{gw}/board/cards/{args.id}", {"actor": self_name, "move_ready": not args.clear}, token)
|
|
240
|
+
return _out(st, d, lambda x: f"card #{x.get('id')} move_ready -> {x.get('move_ready')}", aj)
|
|
235
241
|
if args.command == "link":
|
|
236
242
|
gst, gcard = _http_get_json(f"{gw}/board/cards/{args.id}", token)
|
|
237
243
|
if not (gst and 200 <= gst < 300):
|
|
@@ -10,6 +10,7 @@ from pathlib import Path
|
|
|
10
10
|
from typing import Optional
|
|
11
11
|
|
|
12
12
|
from swarph_cli.cell import Cell, load_cell, CellError
|
|
13
|
+
from swarph_cli.commands.spawn import MEMBRANES
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
def get_memory_repo_path(cell: Cell) -> Path:
|
|
@@ -19,44 +20,13 @@ def get_memory_repo_path(cell: Cell) -> Path:
|
|
|
19
20
|
|
|
20
21
|
def _get_files_to_sync(cell: Cell) -> list[tuple[str, Path]]:
|
|
21
22
|
files_to_sync = []
|
|
22
|
-
|
|
23
|
-
# Common
|
|
23
|
+
# Common (provider-agnostic)
|
|
24
24
|
if (cell.cwd / "CURRENT_TASK.md").exists():
|
|
25
25
|
files_to_sync.append(("CURRENT_TASK.md", cell.cwd / "CURRENT_TASK.md"))
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
mem_dir = Path.home() / ".claude"
|
|
31
|
-
if (mem_dir / "MEMORY.md").exists():
|
|
32
|
-
files_to_sync.append(("MEMORY.md", mem_dir / "MEMORY.md"))
|
|
33
|
-
for p in mem_dir.glob("memory/*.md"):
|
|
34
|
-
files_to_sync.append((f"memory/{p.name}", p))
|
|
35
|
-
if (mem_dir / "inbox-cursor").exists():
|
|
36
|
-
files_to_sync.append(("inbox-cursor", mem_dir / "inbox-cursor"))
|
|
37
|
-
|
|
38
|
-
elif cell.provider == "codex":
|
|
39
|
-
if (cell.cwd / "AGENTS.md").exists():
|
|
40
|
-
files_to_sync.append(("AGENTS.md", cell.cwd / "AGENTS.md"))
|
|
41
|
-
|
|
42
|
-
elif cell.provider == "antigravity":
|
|
43
|
-
if (cell.cwd / "GEMINI.md").exists():
|
|
44
|
-
files_to_sync.append(("GEMINI.md", cell.cwd / "GEMINI.md"))
|
|
45
|
-
if (cell.cwd / "inbox-cursor.json").exists():
|
|
46
|
-
files_to_sync.append(("inbox-cursor.json", cell.cwd / "inbox-cursor.json"))
|
|
47
|
-
|
|
48
|
-
gemini_tmp = Path.home() / ".gemini" / "tmp"
|
|
49
|
-
if gemini_tmp.is_dir():
|
|
50
|
-
for proj_dir in gemini_tmp.iterdir():
|
|
51
|
-
if proj_dir.is_dir():
|
|
52
|
-
for p in proj_dir.glob("memory/*.md"):
|
|
53
|
-
rel = f"tmp/{proj_dir.name}/memory/{p.name}"
|
|
54
|
-
files_to_sync.append((rel, p))
|
|
55
|
-
|
|
56
|
-
history_proj = Path.home() / ".gemini" / "history" / ".project_root"
|
|
57
|
-
if history_proj.exists():
|
|
58
|
-
files_to_sync.append(("history/.project_root", history_proj))
|
|
59
|
-
|
|
26
|
+
# Provider-specific memory lives in the membrane (non-discriminatory dispatch)
|
|
27
|
+
membrane = MEMBRANES.get(cell.provider)
|
|
28
|
+
if membrane is not None:
|
|
29
|
+
files_to_sync += membrane.memory_sync_files(cell)
|
|
60
30
|
return files_to_sync
|
|
61
31
|
|
|
62
32
|
|
|
@@ -110,21 +80,15 @@ def perform_restore(cell: Cell) -> Optional[str]:
|
|
|
110
80
|
continue
|
|
111
81
|
|
|
112
82
|
rel = src.relative_to(repo_dir)
|
|
113
|
-
|
|
83
|
+
|
|
114
84
|
dest = None
|
|
115
85
|
if rel.parts[0] in ("CURRENT_TASK.md", "CLAUDE.md", "AGENTS.md", "GEMINI.md", "inbox-cursor.json"):
|
|
116
86
|
dest = cell.cwd / rel
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
dest = Path.home() / ".claude" / "inbox-cursor"
|
|
123
|
-
elif cell.provider == "antigravity" and rel.parts[0] == "tmp":
|
|
124
|
-
dest = Path.home() / ".gemini" / rel
|
|
125
|
-
elif cell.provider == "antigravity" and rel.parts[0] == "history":
|
|
126
|
-
dest = Path.home() / ".gemini" / rel
|
|
127
|
-
|
|
87
|
+
else:
|
|
88
|
+
membrane = MEMBRANES.get(cell.provider)
|
|
89
|
+
if membrane is not None:
|
|
90
|
+
dest = membrane.memory_restore_dest(rel.parts, cell)
|
|
91
|
+
|
|
128
92
|
if dest:
|
|
129
93
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
130
94
|
shutil.copy2(src, dest)
|
|
@@ -168,13 +132,8 @@ def run_memory_sync(argv: list[str]) -> int:
|
|
|
168
132
|
pass
|
|
169
133
|
|
|
170
134
|
# EMPTY-GUARD check
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
guard_file = cell.cwd / "CLAUDE.md"
|
|
174
|
-
elif cell.provider == "codex":
|
|
175
|
-
guard_file = cell.cwd / "AGENTS.md"
|
|
176
|
-
elif cell.provider == "antigravity":
|
|
177
|
-
guard_file = cell.cwd / "GEMINI.md"
|
|
135
|
+
membrane = MEMBRANES.get(cell.provider)
|
|
136
|
+
guard_file = membrane.memory_guard_file(cell) if membrane is not None else None
|
|
178
137
|
|
|
179
138
|
if guard_file and (not guard_file.exists() or guard_file.stat().st_size == 0):
|
|
180
139
|
print(f"[auto_sync] {datetime.datetime.now(datetime.timezone.utc).strftime('%FT%TZ')} SAFETY: {guard_file} missing or empty — skipping sync", file=sys.stderr)
|
|
@@ -1246,6 +1246,22 @@ class ProviderMembrane:
|
|
|
1246
1246
|
"""chdir + env setup + exec-replace. Only returns on exec failure."""
|
|
1247
1247
|
raise NotImplementedError
|
|
1248
1248
|
|
|
1249
|
+
def memory_sync_files(self, cell) -> list:
|
|
1250
|
+
"""Provider-specific memory files to snapshot: (repo-relative, source-abs)
|
|
1251
|
+
pairs. Base = none; each provider declares its own. The COMMON files
|
|
1252
|
+
(CURRENT_TASK.md) are handled provider-agnostically in memory_sync."""
|
|
1253
|
+
return []
|
|
1254
|
+
|
|
1255
|
+
def memory_restore_dest(self, rel_parts, cell):
|
|
1256
|
+
"""Where a provider-specific repo-relative path restores to (None = not
|
|
1257
|
+
mine; the common cwd files are restored by memory_sync)."""
|
|
1258
|
+
return None
|
|
1259
|
+
|
|
1260
|
+
def memory_guard_file(self, cell):
|
|
1261
|
+
"""The empty-guard file whose emptiness means 'skip sync' (None = no
|
|
1262
|
+
guard, always sync)."""
|
|
1263
|
+
return None
|
|
1264
|
+
|
|
1249
1265
|
|
|
1250
1266
|
class ClaudeMembrane(ProviderMembrane):
|
|
1251
1267
|
name = "claude"
|
|
@@ -1361,6 +1377,31 @@ class ClaudeMembrane(ProviderMembrane):
|
|
|
1361
1377
|
return 1
|
|
1362
1378
|
return 0 # unreachable on POSIX (execve replaces); keeps type checker happy
|
|
1363
1379
|
|
|
1380
|
+
def memory_sync_files(self, cell) -> list:
|
|
1381
|
+
files = []
|
|
1382
|
+
if (cell.cwd / "CLAUDE.md").exists():
|
|
1383
|
+
files.append(("CLAUDE.md", cell.cwd / "CLAUDE.md"))
|
|
1384
|
+
mem_dir = Path.home() / ".claude"
|
|
1385
|
+
if (mem_dir / "MEMORY.md").exists():
|
|
1386
|
+
files.append(("MEMORY.md", mem_dir / "MEMORY.md"))
|
|
1387
|
+
for p in mem_dir.glob("memory/*.md"):
|
|
1388
|
+
files.append((f"memory/{p.name}", p))
|
|
1389
|
+
if (mem_dir / "inbox-cursor").exists():
|
|
1390
|
+
files.append(("inbox-cursor", mem_dir / "inbox-cursor"))
|
|
1391
|
+
return files
|
|
1392
|
+
|
|
1393
|
+
def memory_restore_dest(self, rel_parts, cell):
|
|
1394
|
+
if rel_parts[0] == "MEMORY.md":
|
|
1395
|
+
return Path.home() / ".claude" / "MEMORY.md"
|
|
1396
|
+
if rel_parts[0] == "memory":
|
|
1397
|
+
return Path.home() / ".claude" / Path(*rel_parts)
|
|
1398
|
+
if rel_parts[0] == "inbox-cursor":
|
|
1399
|
+
return Path.home() / ".claude" / "inbox-cursor"
|
|
1400
|
+
return None
|
|
1401
|
+
|
|
1402
|
+
def memory_guard_file(self, cell):
|
|
1403
|
+
return cell.cwd / "CLAUDE.md"
|
|
1404
|
+
|
|
1364
1405
|
|
|
1365
1406
|
class CodexMembrane(ProviderMembrane):
|
|
1366
1407
|
name = "codex"
|
|
@@ -1395,6 +1436,15 @@ class CodexMembrane(ProviderMembrane):
|
|
|
1395
1436
|
return 1
|
|
1396
1437
|
return 0 # unreachable, keeps type checker happy
|
|
1397
1438
|
|
|
1439
|
+
def memory_sync_files(self, cell) -> list:
|
|
1440
|
+
files = []
|
|
1441
|
+
if (cell.cwd / "AGENTS.md").exists():
|
|
1442
|
+
files.append(("AGENTS.md", cell.cwd / "AGENTS.md"))
|
|
1443
|
+
return files
|
|
1444
|
+
|
|
1445
|
+
def memory_guard_file(self, cell):
|
|
1446
|
+
return cell.cwd / "AGENTS.md"
|
|
1447
|
+
|
|
1398
1448
|
|
|
1399
1449
|
class AntigravityMembrane(ProviderMembrane):
|
|
1400
1450
|
name = "antigravity"
|
|
@@ -1436,6 +1486,31 @@ class AntigravityMembrane(ProviderMembrane):
|
|
|
1436
1486
|
return 1
|
|
1437
1487
|
return 0 # unreachable, keeps type checker happy
|
|
1438
1488
|
|
|
1489
|
+
def memory_sync_files(self, cell) -> list:
|
|
1490
|
+
files = []
|
|
1491
|
+
if (cell.cwd / "GEMINI.md").exists():
|
|
1492
|
+
files.append(("GEMINI.md", cell.cwd / "GEMINI.md"))
|
|
1493
|
+
if (cell.cwd / "inbox-cursor.json").exists():
|
|
1494
|
+
files.append(("inbox-cursor.json", cell.cwd / "inbox-cursor.json"))
|
|
1495
|
+
gemini_tmp = Path.home() / ".gemini" / "tmp"
|
|
1496
|
+
if gemini_tmp.is_dir():
|
|
1497
|
+
for proj_dir in gemini_tmp.iterdir():
|
|
1498
|
+
if proj_dir.is_dir():
|
|
1499
|
+
for p in proj_dir.glob("memory/*.md"):
|
|
1500
|
+
files.append((f"tmp/{proj_dir.name}/memory/{p.name}", p))
|
|
1501
|
+
history_proj = Path.home() / ".gemini" / "history" / ".project_root"
|
|
1502
|
+
if history_proj.exists():
|
|
1503
|
+
files.append(("history/.project_root", history_proj))
|
|
1504
|
+
return files
|
|
1505
|
+
|
|
1506
|
+
def memory_restore_dest(self, rel_parts, cell):
|
|
1507
|
+
if rel_parts[0] in ("tmp", "history"):
|
|
1508
|
+
return Path.home() / ".gemini" / Path(*rel_parts)
|
|
1509
|
+
return None
|
|
1510
|
+
|
|
1511
|
+
def memory_guard_file(self, cell):
|
|
1512
|
+
return cell.cwd / "GEMINI.md"
|
|
1513
|
+
|
|
1439
1514
|
|
|
1440
1515
|
class GrokMembrane(ProviderMembrane):
|
|
1441
1516
|
"""Local ``grok`` CLI as a durable swarph CELL ($0 OIDC / subscription).
|
|
@@ -1514,6 +1589,25 @@ class GrokMembrane(ProviderMembrane):
|
|
|
1514
1589
|
return 1
|
|
1515
1590
|
return 0 # unreachable on POSIX (execve replaces); keeps type checker happy
|
|
1516
1591
|
|
|
1592
|
+
def memory_sync_files(self, cell) -> list:
|
|
1593
|
+
# Grok cells run under an isolated HOME (_GROK_CELL_HOME_SUBDIR); memory
|
|
1594
|
+
# lives at <cell_home>/.grok/memory/**/*.md.
|
|
1595
|
+
files = []
|
|
1596
|
+
mem_dir = cell.cwd / _GROK_CELL_HOME_SUBDIR / ".grok" / "memory"
|
|
1597
|
+
if mem_dir.is_dir():
|
|
1598
|
+
for p in mem_dir.rglob("*.md"):
|
|
1599
|
+
files.append((f"grok-memory/{p.relative_to(mem_dir).as_posix()}", p))
|
|
1600
|
+
return files
|
|
1601
|
+
|
|
1602
|
+
def memory_restore_dest(self, rel_parts, cell):
|
|
1603
|
+
if rel_parts[0] == "grok-memory":
|
|
1604
|
+
return (cell.cwd / _GROK_CELL_HOME_SUBDIR / ".grok" / "memory"
|
|
1605
|
+
/ Path(*rel_parts[1:]))
|
|
1606
|
+
return None
|
|
1607
|
+
|
|
1608
|
+
def memory_guard_file(self, cell):
|
|
1609
|
+
return None # grok has no cwd project-doc; always-sync
|
|
1610
|
+
|
|
1517
1611
|
|
|
1518
1612
|
MEMBRANES: dict[str, ProviderMembrane] = {
|
|
1519
1613
|
"claude": ClaudeMembrane(),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.37.0
|
|
4
4
|
Summary: The `swarph` binary — a multi-LLM CLI and mesh-gateway client + bundled server (`swarph gateway`): one-shot prompts across providers, interactive `chat`, multi-provider `spawn` (claude/codex/antigravity via a ProviderMembrane with subprocess billing-scrub), `mesh` send/inbox/register, `brain-ask` over the swarph-brain (gbrain) semantic memory, git-backed `assisted_memory`, session `import`, and a stranded-session `watchdog`.
|
|
5
5
|
Author: Pierre Samson, Claude Opus
|
|
6
6
|
License: MIT
|
|
@@ -139,6 +139,7 @@ tests/test_mcp_server.py
|
|
|
139
139
|
tests/test_memory_command.py
|
|
140
140
|
tests/test_memory_gateway.py
|
|
141
141
|
tests/test_memory_sync.py
|
|
142
|
+
tests/test_memory_sync_membrane.py
|
|
142
143
|
tests/test_mesh_command.py
|
|
143
144
|
tests/test_mesh_inbox_mark_read.py
|
|
144
145
|
tests/test_mesh_inbox_sanitize.py
|
|
@@ -17,7 +17,7 @@ from swarph_cli.commands import brain_ask as ba
|
|
|
17
17
|
|
|
18
18
|
def test_version_is_0_33_0():
|
|
19
19
|
import swarph_cli
|
|
20
|
-
assert swarph_cli.__version__ == "0.
|
|
20
|
+
assert swarph_cli.__version__ == "0.37.0"
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
# --- request / response plumbing -------------------------------------------
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import types
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from swarph_cli.commands import spawn
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _cell(tmp_path):
|
|
8
|
+
return types.SimpleNamespace(cwd=tmp_path, provider="x")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_base_membrane_returns_empty(tmp_path):
|
|
12
|
+
m = spawn.ProviderMembrane()
|
|
13
|
+
assert m.memory_sync_files(_cell(tmp_path)) == []
|
|
14
|
+
assert m.memory_restore_dest(("anything",), _cell(tmp_path)) is None
|
|
15
|
+
assert m.memory_guard_file(_cell(tmp_path)) is None
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_claude_membrane_files_and_dests(tmp_path, monkeypatch):
|
|
19
|
+
home = tmp_path / "home"; (home / ".claude" / "memory").mkdir(parents=True)
|
|
20
|
+
(home / ".claude" / "MEMORY.md").write_text("m")
|
|
21
|
+
(home / ".claude" / "memory" / "a.md").write_text("a")
|
|
22
|
+
(home / ".claude" / "inbox-cursor").write_text("c")
|
|
23
|
+
cwd = tmp_path / "cwd"; cwd.mkdir(); (cwd / "CLAUDE.md").write_text("C")
|
|
24
|
+
monkeypatch.setattr(Path, "home", staticmethod(lambda: home))
|
|
25
|
+
m = spawn.MEMBRANES["claude"]
|
|
26
|
+
rels = {r for r, _ in m.memory_sync_files(types.SimpleNamespace(cwd=cwd, provider="claude"))}
|
|
27
|
+
assert rels == {"CLAUDE.md", "MEMORY.md", "memory/a.md", "inbox-cursor"}
|
|
28
|
+
assert m.memory_restore_dest(("MEMORY.md",), None) == home / ".claude" / "MEMORY.md"
|
|
29
|
+
assert m.memory_restore_dest(("memory", "a.md"), None) == home / ".claude" / "memory" / "a.md"
|
|
30
|
+
assert m.memory_restore_dest(("CLAUDE.md",), None) is None # CLAUDE.md restores via common cwd path
|
|
31
|
+
assert m.memory_guard_file(types.SimpleNamespace(cwd=cwd, provider="claude")) == cwd / "CLAUDE.md"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_codex_membrane(tmp_path):
|
|
35
|
+
cwd = tmp_path; (cwd / "AGENTS.md").write_text("A")
|
|
36
|
+
m = spawn.MEMBRANES["codex"]
|
|
37
|
+
assert {r for r, _ in m.memory_sync_files(types.SimpleNamespace(cwd=cwd, provider="codex"))} == {"AGENTS.md"}
|
|
38
|
+
assert m.memory_restore_dest(("AGENTS.md",), None) is None
|
|
39
|
+
assert m.memory_guard_file(types.SimpleNamespace(cwd=cwd, provider="codex")) == cwd / "AGENTS.md"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_antigravity_restore_dest(tmp_path, monkeypatch):
|
|
43
|
+
home = tmp_path / "home"; monkeypatch.setattr(Path, "home", staticmethod(lambda: home))
|
|
44
|
+
m = spawn.MEMBRANES["antigravity"]
|
|
45
|
+
assert m.memory_restore_dest(("tmp", "proj", "memory", "x.md"), None) == home / ".gemini" / "tmp" / "proj" / "memory" / "x.md"
|
|
46
|
+
assert m.memory_restore_dest(("history", ".project_root"), None) == home / ".gemini" / "history" / ".project_root"
|
|
47
|
+
assert m.memory_restore_dest(("GEMINI.md",), None) is None # common cwd path
|
|
48
|
+
c = tmp_path; (c / "GEMINI.md").write_text("G")
|
|
49
|
+
assert m.memory_guard_file(types.SimpleNamespace(cwd=c, provider="antigravity")) == c / "GEMINI.md"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_grok_membrane_isolated_home(tmp_path):
|
|
53
|
+
cwd = tmp_path
|
|
54
|
+
mem = cwd / spawn._GROK_CELL_HOME_SUBDIR / ".grok" / "memory" / "proj"
|
|
55
|
+
mem.mkdir(parents=True)
|
|
56
|
+
(cwd / spawn._GROK_CELL_HOME_SUBDIR / ".grok" / "memory" / "MEMORY.md").write_text("m")
|
|
57
|
+
(mem / "MEMORY.md").write_text("p")
|
|
58
|
+
m = spawn.MEMBRANES["grok"]
|
|
59
|
+
files = m.memory_sync_files(types.SimpleNamespace(cwd=cwd, provider="grok"))
|
|
60
|
+
rels = {r for r, _ in files}
|
|
61
|
+
assert rels == {"grok-memory/MEMORY.md", "grok-memory/proj/MEMORY.md"}
|
|
62
|
+
# Verify no backslashes in keys (cross-OS restore safety)
|
|
63
|
+
assert all("\\" not in r for r, _ in files)
|
|
64
|
+
assert m.memory_restore_dest(("grok-memory", "proj", "MEMORY.md"), types.SimpleNamespace(cwd=cwd, provider="grok")) \
|
|
65
|
+
== cwd / spawn._GROK_CELL_HOME_SUBDIR / ".grok" / "memory" / "proj" / "MEMORY.md"
|
|
66
|
+
assert m.memory_guard_file(types.SimpleNamespace(cwd=cwd, provider="grok")) is None # no cwd doc
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# Tests for memory_sync.py dispatch (Task 2)
|
|
70
|
+
from swarph_cli.commands import memory_sync
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_get_files_to_sync_dispatches_to_membrane(tmp_path):
|
|
74
|
+
cwd = tmp_path; (cwd / "CURRENT_TASK.md").write_text("t"); (cwd / "AGENTS.md").write_text("A")
|
|
75
|
+
cell = types.SimpleNamespace(cwd=cwd, provider="codex")
|
|
76
|
+
rels = {r for r, _ in memory_sync._get_files_to_sync(cell)}
|
|
77
|
+
assert rels == {"CURRENT_TASK.md", "AGENTS.md"} # common + codex membrane
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_get_files_unknown_provider_is_common_only(tmp_path):
|
|
81
|
+
cwd = tmp_path; (cwd / "CURRENT_TASK.md").write_text("t")
|
|
82
|
+
cell = types.SimpleNamespace(cwd=cwd, provider="nonesuch")
|
|
83
|
+
assert {r for r, _ in memory_sync._get_files_to_sync(cell)} == {"CURRENT_TASK.md"}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_grok_roundtrip_sync_then_restore_dest(tmp_path):
|
|
87
|
+
cwd = tmp_path
|
|
88
|
+
mem = cwd / spawn._GROK_CELL_HOME_SUBDIR / ".grok" / "memory"
|
|
89
|
+
mem.mkdir(parents=True); (mem / "MEMORY.md").write_text("m")
|
|
90
|
+
cell = types.SimpleNamespace(cwd=cwd, provider="grok")
|
|
91
|
+
files = memory_sync._get_files_to_sync(cell)
|
|
92
|
+
rel = next(r for r, _ in files if r.startswith("grok-memory"))
|
|
93
|
+
dest = spawn.MEMBRANES["grok"].memory_restore_dest(tuple(Path(rel).parts), cell)
|
|
94
|
+
assert dest == mem / "MEMORY.md" # snapshot rel round-trips to the isolated-HOME source
|
|
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
|
|
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
|