multi-agent-platform 0.1.0__tar.gz → 0.2.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.
- {multi_agent_platform-0.1.0/multi_agent_platform.egg-info → multi_agent_platform-0.2.0}/PKG-INFO +22 -3
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/README.md +21 -2
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/commands/project.py +65 -0
- multi_agent_platform-0.2.0/cli/commands/sync.py +169 -0
- multi_agent_platform-0.2.0/cli/local_cache.py +255 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/main.py +2 -0
- multi_agent_platform-0.2.0/cli/project_export.py +356 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0/multi_agent_platform.egg-info}/PKG-INFO +22 -3
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/multi_agent_platform.egg-info/SOURCES.txt +5 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/pyproject.toml +1 -1
- multi_agent_platform-0.2.0/tests/test_local_cache.py +409 -0
- multi_agent_platform-0.2.0/tests/test_project_export.py +311 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/LICENSE +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/__init__.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/action_item_escalation.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/agent_client.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/bridge_state.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/commands/__init__.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/commands/action.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/commands/agent.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/commands/audit.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/commands/docs.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/commands/experiment.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/commands/feedback.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/commands/notification.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/commands/persona.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/commands/runtime.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/commands/topic.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/e2e_collab.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/git_checkpoint.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/host_worker_types.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/map_command_client.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/participant_worker.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/reviewer_worker.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/runtime/__init__.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/runtime/run_lock.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/runtime_chat.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/session_wake_log.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/simple_waker.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/table_render.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/wake_backend.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/cli/worker_cycle_log.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/multi_agent_platform.egg-info/dependency_links.txt +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/multi_agent_platform.egg-info/entry_points.txt +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/multi_agent_platform.egg-info/requires.txt +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/multi_agent_platform.egg-info/top_level.txt +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_client/__init__.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_client/bootstrap.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_client/client.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_client/config.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_client/errors.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_client/exceptions.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_client/plan_evidence.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_client/project_config.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_client/result_template.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_client/testing.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_mcp/__init__.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_mcp/_utils.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_mcp/auth.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_mcp/config.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_mcp/context.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_mcp/main.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_mcp/server.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_mcp/session.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_sdk/__init__.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_sdk/evidence.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_types/__init__.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_types/enums.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/sdk/python/map_types/schemas.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/__init__.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/__version__.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/api/__init__.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/api/action_items.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/api/agents.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/api/audit.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/api/background_tasks.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/api/common.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/api/deps.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/api/experiments.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/api/feedback.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/api/notifications.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/api/projects.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/api/router.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/api/status.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/api/topics.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/api/webhooks.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/auth/__init__.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/auth/experiment_access.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/config.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/db/__init__.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/db/base.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/db/deadlock_retry.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/db/session.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/domain/__init__.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/domain/encrypted_types.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/domain/models.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/domain/schemas.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/domain/state_machine.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/domain/topic_ack_constants.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/main.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/scripts/__init__.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/scripts/migrate_notification_unique.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/scripts/purge_audit_pollution.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/__init__.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/_lookups.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/acceptance_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/action_item_migration_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/action_item_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/agent_work_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/archive_lint_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/audit_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/auth.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/comment_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/errors.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/escalation_resolver.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/evidence_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/experiment_capabilities_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/inbound_event_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/lock_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/log_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/mention_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/notification_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/notification_stream.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/permissions.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/persona_activity_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/phase_owner_resolver.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/phase_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/plan_marker_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/plan_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/platform_feedback_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/project_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/project_status_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/review_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/secret_encryption.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/similarity_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/sse_event_schemas.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/status_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/template_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/text_utils.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/thread_activity.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/todo_persona_filter.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/todo_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/topic_ack_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/topic_action_item_ops.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/topic_comment_kind.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/topic_comment_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/topic_helpers.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/topic_lifecycle_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/topic_progress_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/topic_resolve_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/topic_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/topic_work_item_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/server/services/webhook_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/setup.cfg +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_18a64691_linkage.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_a2_action_item_cascade.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_accept_result_verdict.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_action_items.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_agent_client.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_agent_work.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_agents_list.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_arch_map_sdk_evidence.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_archive_lint_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_audit_admin_cli.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_audit_admin_filter.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_auth.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_auth_experiment_access.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_authz_cross_persona_capability.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_authz_pr3_creator_gating_extended.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_b_acceptance.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_b_action_item_stale.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_b_action_item_wake_endpoints.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_b_action_item_wake_stale.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_b_action_item_wake_stale_notifications.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_b_waker_should_wake_action_item.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_bridge_state.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_cleanup_audit_log_no_commit.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_cleanup_exp_b_paging_seven_endpoints.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_cleanup_exp_b_paging_unified_limit.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_clear_action_template.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_cli.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_cli_error_envelope.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_cli_evidence_contract.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_cli_format_priority.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_cli_n2_hard_cutover.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_cli_schema_discovery.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_cli_status.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_cli_template_contract.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_cli_work_deprecation.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_cross_persona_call_audit.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_deadlock_retry.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_docs_inventory.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_fast_gate_whitelist_complete.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_mypy_strict_agent_work_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_mypy_strict_agents.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_mypy_strict_experiment_capabilities_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_mypy_strict_experiments_projects.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_mypy_strict_mention_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_mypy_strict_notification_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_mypy_strict_phase_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_mypy_strict_project_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_mypy_strict_todo_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_mypy_strict_topic_comment_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_mypy_strict_topic_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_mypy_strict_topic_work_item_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_mypy_strict_topics.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_typing_extensions_clean.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_uv_lock.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_eng_version_single_source.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_error_codes_cli.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_error_envelope_and_file_options.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_escalation_resolver.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_escalation_target_endpoint.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_evidence_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_experiment_capabilities.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_experiment_capabilities_whitelist.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_experiment_lock_fuzz.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_experiment_lock_notifications.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_experiment_lock_unit.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_experiments.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_feedback.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_feedback_admin_cli.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_field_rename_alias.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_git_checkpoint.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_inbound_event_rejection.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_log_create_response.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_m2_flow.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_m3_flow.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_map_sdk_skeleton.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_mcp.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_mcp_http.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_mention_code_skip_unit.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_mentions.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_notification_bulk_filter.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_notification_service_v09.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_notification_stream.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_notification_upsert_pr2.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_notifications.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_participant_worker_claude_agent.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_perf_count_sql_fixture.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_perf_experiment_bundle_verdict_n_plus_one.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_perf_experiment_summary_bulk.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_perf_topic_comments_bulk.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_perf_work_hotpath_bulk.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_persona_activity.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_persona_compare_partition.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_phase_owner_orm_validation.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_phase_owner_resolver.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_plan_evidence_parser.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_plan_marker_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_plan_revise_auto_archive.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_plan_validate_cli.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_project_config.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_project_status.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_projects.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_rebutted_plan_continues_e2e.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_register_agent_body_model.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_reject_result_misuse.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_resolve_item_sdk_contract.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_resolve_item_status.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_result_template_parser.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_review_already_archived.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_review_archived_metadata.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_review_eligibility.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_review_item_mutation_audit.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_review_item_state_closed_migration.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_review_list_archived_filter.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_review_substitute_and_withdraw.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_review_verdict_alias.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_reviewer_worker_claude_agent.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_runtime_chat.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_same_second_host_reply.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_same_second_trio.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_sdk.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_sdk_exceptions.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_server_lock_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_session_wake_log.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_similarity_api_contract.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_similarity_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_simple_waker.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_simple_waker_pr3_dedup.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_simple_waker_reviewer_filter.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_sse_acceptance.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_sse_isolation.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_sse_schema_overlap.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_state_machine.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_state_machine_recovery_hint.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_systemd_install.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_template_api_contract.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_template_service.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_todos.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_topic_notifications.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_topic_progress.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_topic_read_cursor.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_topic_work_items.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_topics.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_waker_phase1_acceptance.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_webhook_secret_encryption.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_webhooks_audit.py +0 -0
- {multi_agent_platform-0.1.0 → multi_agent_platform-0.2.0}/tests/test_work_summary.py +0 -0
{multi_agent_platform-0.1.0/multi_agent_platform.egg-info → multi_agent_platform-0.2.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: multi-agent-platform
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Multi-Agent experiment collaboration platform
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/quantaeye/multi-agent-platform
|
|
@@ -45,8 +45,20 @@ Dynamic: license-file
|
|
|
45
45
|
|
|
46
46
|
# Multi-Agent Platform (MAP)
|
|
47
47
|
|
|
48
|
+
[](https://pypi.org/project/multi-agent-platform/)
|
|
49
|
+
[](https://pypi.org/project/multi-agent-platform/)
|
|
50
|
+
[](https://github.com/quantaeye/multi-agent-platform/blob/main/LICENSE)
|
|
51
|
+
|
|
48
52
|
多 Agent 实验协作平台:以话题为中心,管理实验计划、评审讨论、执行日志与项目状态。
|
|
49
53
|
|
|
54
|
+
## 安装
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install multi-agent-platform
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
安装后即可使用 `map` CLI 和 `map-server` 命令。详见 [Quick Start 指南](docs/QUICKSTART.md)。
|
|
61
|
+
|
|
50
62
|
**新用户?** 一键启动:`./scripts/quickstart.sh`,或阅读 [Quick Start 指南](docs/QUICKSTART.md)。
|
|
51
63
|
|
|
52
64
|
## 文档
|
|
@@ -138,7 +150,10 @@ map --persona host todos
|
|
|
138
150
|
## 快速开始
|
|
139
151
|
|
|
140
152
|
```bash
|
|
141
|
-
#
|
|
153
|
+
# 从 PyPI 安装(用户)
|
|
154
|
+
pip install multi-agent-platform
|
|
155
|
+
|
|
156
|
+
# 或从源码开发安装(贡献者)
|
|
142
157
|
pip install -e ".[dev]"
|
|
143
158
|
|
|
144
159
|
# 运行数据库迁移
|
|
@@ -273,7 +288,7 @@ python -c "from map_client import MAPClient; print(MAPClient.from_env().get_me()
|
|
|
273
288
|
## MCP(IDE Agent)
|
|
274
289
|
|
|
275
290
|
```bash
|
|
276
|
-
pip install -
|
|
291
|
+
pip install "multi-agent-platform[mcp]"
|
|
277
292
|
export MAP_TOKEN=<your-token>
|
|
278
293
|
|
|
279
294
|
# stdio — Cursor 本地子进程(默认)
|
|
@@ -296,3 +311,7 @@ map-mcp --transport streamable-http --host 0.0.0.0 --port 8080
|
|
|
296
311
|
## 后续
|
|
297
312
|
|
|
298
313
|
v0.3–v0.6 与 v0.7 P3(CLI archive)已落地;当前主线为 **agent-runtime**(simple-waker 默认 + PersonaAgentClient;legacy runtime-waker 启动路径已退役,模块保留为 re-export 兼容层)。待推进项见 [docs/status-md-v10.md](docs/status-md-v10.md) 与 [架构文档](docs/ARCHITECTURE.md)。
|
|
314
|
+
|
|
315
|
+
## License
|
|
316
|
+
|
|
317
|
+
[MIT](LICENSE)
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
# Multi-Agent Platform (MAP)
|
|
2
2
|
|
|
3
|
+
[](https://pypi.org/project/multi-agent-platform/)
|
|
4
|
+
[](https://pypi.org/project/multi-agent-platform/)
|
|
5
|
+
[](https://github.com/quantaeye/multi-agent-platform/blob/main/LICENSE)
|
|
6
|
+
|
|
3
7
|
多 Agent 实验协作平台:以话题为中心,管理实验计划、评审讨论、执行日志与项目状态。
|
|
4
8
|
|
|
9
|
+
## 安装
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install multi-agent-platform
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
安装后即可使用 `map` CLI 和 `map-server` 命令。详见 [Quick Start 指南](docs/QUICKSTART.md)。
|
|
16
|
+
|
|
5
17
|
**新用户?** 一键启动:`./scripts/quickstart.sh`,或阅读 [Quick Start 指南](docs/QUICKSTART.md)。
|
|
6
18
|
|
|
7
19
|
## 文档
|
|
@@ -93,7 +105,10 @@ map --persona host todos
|
|
|
93
105
|
## 快速开始
|
|
94
106
|
|
|
95
107
|
```bash
|
|
96
|
-
#
|
|
108
|
+
# 从 PyPI 安装(用户)
|
|
109
|
+
pip install multi-agent-platform
|
|
110
|
+
|
|
111
|
+
# 或从源码开发安装(贡献者)
|
|
97
112
|
pip install -e ".[dev]"
|
|
98
113
|
|
|
99
114
|
# 运行数据库迁移
|
|
@@ -228,7 +243,7 @@ python -c "from map_client import MAPClient; print(MAPClient.from_env().get_me()
|
|
|
228
243
|
## MCP(IDE Agent)
|
|
229
244
|
|
|
230
245
|
```bash
|
|
231
|
-
pip install -
|
|
246
|
+
pip install "multi-agent-platform[mcp]"
|
|
232
247
|
export MAP_TOKEN=<your-token>
|
|
233
248
|
|
|
234
249
|
# stdio — Cursor 本地子进程(默认)
|
|
@@ -251,3 +266,7 @@ map-mcp --transport streamable-http --host 0.0.0.0 --port 8080
|
|
|
251
266
|
## 后续
|
|
252
267
|
|
|
253
268
|
v0.3–v0.6 与 v0.7 P3(CLI archive)已落地;当前主线为 **agent-runtime**(simple-waker 默认 + PersonaAgentClient;legacy runtime-waker 启动路径已退役,模块保留为 re-export 兼容层)。待推进项见 [docs/status-md-v10.md](docs/status-md-v10.md) 与 [架构文档](docs/ARCHITECTURE.md)。
|
|
269
|
+
|
|
270
|
+
## License
|
|
271
|
+
|
|
272
|
+
[MIT](LICENSE)
|
|
@@ -85,3 +85,68 @@ def project_status_show(
|
|
|
85
85
|
lambda c: c.get_project_status_version(_resolve_project(c, project, project_key), version)
|
|
86
86
|
)
|
|
87
87
|
|
|
88
|
+
|
|
89
|
+
@project_app.command("export")
|
|
90
|
+
def project_export(
|
|
91
|
+
output_dir: Path = typer.Option(
|
|
92
|
+
None,
|
|
93
|
+
"--output-dir",
|
|
94
|
+
"-o",
|
|
95
|
+
help="Output directory (default: .map/history/)",
|
|
96
|
+
),
|
|
97
|
+
include_archived: bool = typer.Option(
|
|
98
|
+
True,
|
|
99
|
+
"--include-archived/--no-archived",
|
|
100
|
+
help="Include archived topics and experiments (default: yes)",
|
|
101
|
+
),
|
|
102
|
+
project: uuid.UUID | None = typer.Option(None, "--project"),
|
|
103
|
+
project_key: str | None = typer.Option(None, "--project-key"),
|
|
104
|
+
) -> None:
|
|
105
|
+
"""Export project history (topics, experiments, decisions) to local Markdown.
|
|
106
|
+
|
|
107
|
+
The export is a read-only snapshot suitable for committing to Git,
|
|
108
|
+
so that topic discussions and experiment records travel with the code.
|
|
109
|
+
|
|
110
|
+
\b
|
|
111
|
+
Layout:
|
|
112
|
+
<output_dir>/
|
|
113
|
+
INDEX.md # Browseable index
|
|
114
|
+
topics/<slug>.md # One file per topic (with comments + decision)
|
|
115
|
+
experiments/<slug>.md # One file per experiment (with plans + reviews + logs)
|
|
116
|
+
|
|
117
|
+
\b
|
|
118
|
+
Examples:
|
|
119
|
+
map project export # Export to .map/history/
|
|
120
|
+
map project export -o ./docs/history # Custom output directory
|
|
121
|
+
map project export --no-archived # Skip archived items
|
|
122
|
+
"""
|
|
123
|
+
from cli.main import _resolve_project, _run # lazy: avoid cycle
|
|
124
|
+
from cli.project_export import export_project_history
|
|
125
|
+
|
|
126
|
+
if output_dir is None:
|
|
127
|
+
from cli.main import find_map_dir, _cli_options
|
|
128
|
+
map_dir = find_map_dir(_cli_options.get("project_root"))
|
|
129
|
+
if map_dir is not None:
|
|
130
|
+
output_dir = map_dir / "history"
|
|
131
|
+
else:
|
|
132
|
+
output_dir = Path(".map") / "history"
|
|
133
|
+
|
|
134
|
+
def action(c: MAPClient):
|
|
135
|
+
pid = _resolve_project(c, project, project_key)
|
|
136
|
+
result_dir = export_project_history(
|
|
137
|
+
c,
|
|
138
|
+
pid,
|
|
139
|
+
output_dir,
|
|
140
|
+
include_archived=include_archived,
|
|
141
|
+
)
|
|
142
|
+
# Count files for feedback
|
|
143
|
+
topic_files = list((result_dir / "topics").glob("*.md"))
|
|
144
|
+
exp_files = list((result_dir / "experiments").glob("*.md"))
|
|
145
|
+
typer.echo(
|
|
146
|
+
f"Exported {len(topic_files)} topic(s) and {len(exp_files)} experiment(s) "
|
|
147
|
+
f"to {result_dir}/"
|
|
148
|
+
)
|
|
149
|
+
return None
|
|
150
|
+
|
|
151
|
+
_run(action)
|
|
152
|
+
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""``map sync ...`` sub-app — local cache sync commands.
|
|
2
|
+
|
|
3
|
+
Commands:
|
|
4
|
+
map sync pull — Pull project data from remote server to local cache
|
|
5
|
+
map sync status — Show sync status (last pull time, cached counts)
|
|
6
|
+
map sync topics — List cached topics (offline, from local cache)
|
|
7
|
+
map sync topic — Show a cached topic by ID (offline, from local cache)
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import uuid
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
import typer
|
|
16
|
+
from map_client.client import MAPClient
|
|
17
|
+
|
|
18
|
+
sync_app = typer.Typer(help="Local cache sync commands (offline browsing)")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _require_cache_session():
|
|
22
|
+
"""Open the local cache DB, exiting with a helpful hint if .map/ is missing."""
|
|
23
|
+
from cli.main import find_map_dir, _cli_options
|
|
24
|
+
from cli.local_cache import init_cache, get_cache_path
|
|
25
|
+
|
|
26
|
+
map_dir = find_map_dir(_cli_options.get("project_root"))
|
|
27
|
+
if map_dir is None:
|
|
28
|
+
typer.echo("Error: .map/ directory not found. Run `map bootstrap` first.", err=True)
|
|
29
|
+
raise typer.Exit(1)
|
|
30
|
+
db_path = get_cache_path(map_dir)
|
|
31
|
+
return map_dir, db_path, init_cache(db_path)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@sync_app.command("pull")
|
|
35
|
+
def sync_pull(
|
|
36
|
+
project: uuid.UUID | None = typer.Option(None, "--project"),
|
|
37
|
+
project_key: str | None = typer.Option(None, "--project-key"),
|
|
38
|
+
include_archived: bool = typer.Option(
|
|
39
|
+
True,
|
|
40
|
+
"--include-archived/--no-archived",
|
|
41
|
+
help="Include archived items (default: yes)",
|
|
42
|
+
),
|
|
43
|
+
) -> None:
|
|
44
|
+
"""Pull project data from remote server into local cache (.map/cache.db).
|
|
45
|
+
|
|
46
|
+
After pulling, you can browse topics and experiments offline using
|
|
47
|
+
`map sync topics` and `map sync topic --id <uuid>`.
|
|
48
|
+
"""
|
|
49
|
+
from cli.main import _resolve_project, _run
|
|
50
|
+
from cli.local_cache import pull_project_to_cache
|
|
51
|
+
|
|
52
|
+
map_dir, db_path, session = _require_cache_session()
|
|
53
|
+
|
|
54
|
+
def action(c: MAPClient):
|
|
55
|
+
pid = _resolve_project(c, project, project_key)
|
|
56
|
+
# Resolve project_key for sync_meta bookkeeping
|
|
57
|
+
from map_client.config import load_config
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
pk = project_key or load_config().get("project_key") or ""
|
|
61
|
+
except Exception:
|
|
62
|
+
pk = project_key or ""
|
|
63
|
+
|
|
64
|
+
result = pull_project_to_cache(
|
|
65
|
+
session, c, pid, pk, include_archived=include_archived,
|
|
66
|
+
)
|
|
67
|
+
typer.echo(
|
|
68
|
+
f"Pulled {result['topics']} topic(s) and {result['experiments']} experiment(s) "
|
|
69
|
+
f"to {db_path}"
|
|
70
|
+
)
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
try:
|
|
74
|
+
_run(action)
|
|
75
|
+
finally:
|
|
76
|
+
session.close()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@sync_app.command("status")
|
|
80
|
+
def sync_status(
|
|
81
|
+
project: uuid.UUID | None = typer.Option(None, "--project"),
|
|
82
|
+
) -> None:
|
|
83
|
+
"""Show local cache sync status."""
|
|
84
|
+
from cli.local_cache import get_sync_status
|
|
85
|
+
|
|
86
|
+
_, db_path, session = _require_cache_session()
|
|
87
|
+
if not db_path.exists():
|
|
88
|
+
typer.echo("No local cache found. Run `map sync pull` first.")
|
|
89
|
+
return
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
statuses = get_sync_status(session, project)
|
|
93
|
+
if not statuses:
|
|
94
|
+
typer.echo("No sync records found. Run `map sync pull` first.")
|
|
95
|
+
return
|
|
96
|
+
for s in statuses:
|
|
97
|
+
typer.echo(f"Project: {s['project_key']} ({s['project_id']})")
|
|
98
|
+
typer.echo(f" Last pull: {s['last_pull_at']}")
|
|
99
|
+
typer.echo(f" Topics: {s['topic_count']}, Experiments: {s['experiment_count']}")
|
|
100
|
+
finally:
|
|
101
|
+
session.close()
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@sync_app.command("topics")
|
|
105
|
+
def sync_topics(
|
|
106
|
+
project: uuid.UUID | None = typer.Option(None, "--project"),
|
|
107
|
+
project_key: str | None = typer.Option(None, "--project-key"),
|
|
108
|
+
) -> None:
|
|
109
|
+
"""List cached topics from local cache (offline)."""
|
|
110
|
+
from cli.local_cache import get_sync_status, list_cached_topics
|
|
111
|
+
|
|
112
|
+
_, db_path, session = _require_cache_session()
|
|
113
|
+
if not db_path.exists():
|
|
114
|
+
typer.echo("No local cache found. Run `map sync pull` first.")
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
# If project_id not given, try to find it from sync_meta
|
|
119
|
+
if project is None:
|
|
120
|
+
statuses = get_sync_status(session)
|
|
121
|
+
if not statuses:
|
|
122
|
+
typer.echo("No cached projects. Run `map sync pull` first.")
|
|
123
|
+
return
|
|
124
|
+
# Use first project (or match by project_key)
|
|
125
|
+
if project_key:
|
|
126
|
+
for s in statuses:
|
|
127
|
+
if s["project_key"] == project_key:
|
|
128
|
+
project = uuid.UUID(s["project_id"])
|
|
129
|
+
break
|
|
130
|
+
if project is None and len(statuses) == 1:
|
|
131
|
+
project = uuid.UUID(statuses[0]["project_id"])
|
|
132
|
+
if project is None:
|
|
133
|
+
typer.echo("Multiple projects cached. Specify --project or --project-key.")
|
|
134
|
+
for s in statuses:
|
|
135
|
+
typer.echo(f" {s['project_key']} ({s['project_id']})")
|
|
136
|
+
return
|
|
137
|
+
|
|
138
|
+
topics = list_cached_topics(session, project)
|
|
139
|
+
if not topics:
|
|
140
|
+
typer.echo("No cached topics. Run `map sync pull` first.")
|
|
141
|
+
return
|
|
142
|
+
typer.echo(f"{'ID':<36} {'Status':<12} {'Title'}")
|
|
143
|
+
typer.echo("-" * 80)
|
|
144
|
+
for t in topics:
|
|
145
|
+
typer.echo(f"{t['id']:<36} {t['status']:<12} {t['title']}")
|
|
146
|
+
finally:
|
|
147
|
+
session.close()
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@sync_app.command("topic")
|
|
151
|
+
def sync_topic(
|
|
152
|
+
topic_id: uuid.UUID = typer.Option(..., "--id", help="Topic UUID"),
|
|
153
|
+
) -> None:
|
|
154
|
+
"""Show a cached topic from local cache (offline)."""
|
|
155
|
+
from cli.local_cache import get_cached_topic
|
|
156
|
+
|
|
157
|
+
_, db_path, session = _require_cache_session()
|
|
158
|
+
if not db_path.exists():
|
|
159
|
+
typer.echo("No local cache found. Run `map sync pull` first.")
|
|
160
|
+
return
|
|
161
|
+
|
|
162
|
+
try:
|
|
163
|
+
topic = get_cached_topic(session, topic_id)
|
|
164
|
+
if topic is None:
|
|
165
|
+
typer.echo(f"Topic {topic_id} not found in local cache.")
|
|
166
|
+
return
|
|
167
|
+
typer.echo(json.dumps(topic["data"], indent=2, default=str, ensure_ascii=False))
|
|
168
|
+
finally:
|
|
169
|
+
session.close()
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"""Local SQLite cache for MAP project data — Plan A (read-only sync).
|
|
2
|
+
|
|
3
|
+
This module provides a lightweight local cache that stores JSON snapshots
|
|
4
|
+
of topics, experiments, and decisions pulled from a remote MAP server.
|
|
5
|
+
The cache lives at ``.map/cache.db`` and enables offline browsing of
|
|
6
|
+
project history.
|
|
7
|
+
|
|
8
|
+
Architecture::
|
|
9
|
+
|
|
10
|
+
Remote MAP Server Local .map/cache.db
|
|
11
|
+
┌──────────────────┐ ┌────────────────────┐
|
|
12
|
+
│ PostgreSQL / │ ── pull ──> │ sync_meta │
|
|
13
|
+
│ SQLite │ (JSON) │ cached_topics │
|
|
14
|
+
│ │ │ cached_experiments │
|
|
15
|
+
└──────────────────┘ └────────────────────┘
|
|
16
|
+
|
|
17
|
+
Design choices:
|
|
18
|
+
- JSON blob storage (not full ORM) — keeps the cache schema-agnostic
|
|
19
|
+
and immune to server-side model changes
|
|
20
|
+
- Upsert by UUID — repeated pulls update in place
|
|
21
|
+
- ``sync_meta`` tracks last-pull timestamp per project for delta sync
|
|
22
|
+
"""
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import json
|
|
26
|
+
import uuid
|
|
27
|
+
from datetime import datetime, timezone
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
from typing import Any
|
|
30
|
+
|
|
31
|
+
from sqlalchemy import (
|
|
32
|
+
Column,
|
|
33
|
+
DateTime,
|
|
34
|
+
String,
|
|
35
|
+
Text,
|
|
36
|
+
create_engine,
|
|
37
|
+
text,
|
|
38
|
+
)
|
|
39
|
+
from sqlalchemy.orm import DeclarativeBase, Session, sessionmaker
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class Base(DeclarativeBase):
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class SyncMeta(Base):
|
|
47
|
+
"""Tracks last-sync timestamp per project."""
|
|
48
|
+
|
|
49
|
+
__tablename__ = "sync_meta"
|
|
50
|
+
|
|
51
|
+
project_id = Column(String(36), primary_key=True) # UUID as string
|
|
52
|
+
project_key = Column(String(64), nullable=False)
|
|
53
|
+
last_pull_at = Column(DateTime(timezone=True), nullable=False)
|
|
54
|
+
topic_count = Column(String(10), default="0")
|
|
55
|
+
experiment_count = Column(String(10), default="0")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class CachedTopic(Base):
|
|
59
|
+
"""A topic snapshot stored as JSON blob."""
|
|
60
|
+
|
|
61
|
+
__tablename__ = "cached_topics"
|
|
62
|
+
|
|
63
|
+
id = Column(String(36), primary_key=True) # UUID as string
|
|
64
|
+
project_id = Column(String(36), nullable=False, index=True)
|
|
65
|
+
title = Column(String(512), nullable=False)
|
|
66
|
+
status = Column(String(32), nullable=False)
|
|
67
|
+
data_json = Column(Text, nullable=False) # Full TopicRead as JSON
|
|
68
|
+
pulled_at = Column(DateTime(timezone=True), nullable=False)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class CachedExperiment(Base):
|
|
72
|
+
"""An experiment snapshot stored as JSON blob."""
|
|
73
|
+
|
|
74
|
+
__tablename__ = "cached_experiments"
|
|
75
|
+
|
|
76
|
+
id = Column(String(36), primary_key=True) # UUID as string
|
|
77
|
+
project_id = Column(String(36), nullable=False, index=True)
|
|
78
|
+
title = Column(String(512), nullable=False)
|
|
79
|
+
phase = Column(String(32), nullable=False)
|
|
80
|
+
data_json = Column(Text, nullable=False) # Full ExperimentBundleRead as JSON
|
|
81
|
+
pulled_at = Column(DateTime(timezone=True), nullable=False)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def get_cache_path(map_dir: Path) -> Path:
|
|
85
|
+
"""Return the cache database path inside ``.map/``."""
|
|
86
|
+
return map_dir / "cache.db"
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def init_cache(db_path: Path) -> Session:
|
|
90
|
+
"""Initialize (or open) the local cache database and return a session."""
|
|
91
|
+
engine = create_engine(f"sqlite:///{db_path}", connect_args={"check_same_thread": False})
|
|
92
|
+
Base.metadata.create_all(engine)
|
|
93
|
+
SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False)
|
|
94
|
+
return SessionLocal()
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def pull_project_to_cache(
|
|
98
|
+
session: Session,
|
|
99
|
+
client: Any, # MAPClient
|
|
100
|
+
project_id: uuid.UUID,
|
|
101
|
+
project_key: str,
|
|
102
|
+
*,
|
|
103
|
+
include_archived: bool = True,
|
|
104
|
+
) -> dict[str, int]:
|
|
105
|
+
"""Pull all topics and experiments from remote server into local cache.
|
|
106
|
+
|
|
107
|
+
Returns a dict with ``topics``, ``experiments`` counts.
|
|
108
|
+
"""
|
|
109
|
+
now = datetime.now(timezone.utc)
|
|
110
|
+
pid_str = str(project_id)
|
|
111
|
+
|
|
112
|
+
# --- Pull topics ---
|
|
113
|
+
topic_count = 0
|
|
114
|
+
page = 1
|
|
115
|
+
while True:
|
|
116
|
+
batch = client.list_topics(
|
|
117
|
+
project_id,
|
|
118
|
+
page=page,
|
|
119
|
+
page_size=100,
|
|
120
|
+
include_archived=include_archived,
|
|
121
|
+
)
|
|
122
|
+
if not batch:
|
|
123
|
+
break
|
|
124
|
+
for summary in batch:
|
|
125
|
+
topic = client.get_topic(summary.id)
|
|
126
|
+
topic_json = topic.model_dump(mode="json") if hasattr(topic, "model_dump") else _to_dict(topic)
|
|
127
|
+
# Upsert
|
|
128
|
+
existing = session.get(CachedTopic, str(topic.id))
|
|
129
|
+
if existing:
|
|
130
|
+
existing.title = topic.title
|
|
131
|
+
existing.status = str(topic.status.value if hasattr(topic.status, "value") else topic.status)
|
|
132
|
+
existing.data_json = json.dumps(topic_json, default=str, ensure_ascii=False)
|
|
133
|
+
existing.pulled_at = now
|
|
134
|
+
else:
|
|
135
|
+
session.add(CachedTopic(
|
|
136
|
+
id=str(topic.id),
|
|
137
|
+
project_id=pid_str,
|
|
138
|
+
title=topic.title,
|
|
139
|
+
status=str(topic.status.value if hasattr(topic.status, "value") else topic.status),
|
|
140
|
+
data_json=json.dumps(topic_json, default=str, ensure_ascii=False),
|
|
141
|
+
pulled_at=now,
|
|
142
|
+
))
|
|
143
|
+
topic_count += 1
|
|
144
|
+
if len(batch) < 100:
|
|
145
|
+
break
|
|
146
|
+
page += 1
|
|
147
|
+
|
|
148
|
+
# --- Pull experiments ---
|
|
149
|
+
experiment_count = 0
|
|
150
|
+
page = 1
|
|
151
|
+
while True:
|
|
152
|
+
batch = client.list_experiments(
|
|
153
|
+
project_id,
|
|
154
|
+
page=page,
|
|
155
|
+
page_size=100,
|
|
156
|
+
include_archived=include_archived,
|
|
157
|
+
)
|
|
158
|
+
if not batch:
|
|
159
|
+
break
|
|
160
|
+
for summary in batch:
|
|
161
|
+
bundle = client.get_experiment_bundle(summary.id)
|
|
162
|
+
bundle_json = bundle.model_dump(mode="json") if hasattr(bundle, "model_dump") else _to_dict(bundle)
|
|
163
|
+
exp = bundle.experiment if hasattr(bundle, "experiment") else bundle
|
|
164
|
+
phase_val = str(exp.phase.value if hasattr(exp.phase, "value") else exp.phase)
|
|
165
|
+
# Upsert
|
|
166
|
+
existing = session.get(CachedExperiment, str(exp.id))
|
|
167
|
+
if existing:
|
|
168
|
+
existing.title = exp.title
|
|
169
|
+
existing.phase = phase_val
|
|
170
|
+
existing.data_json = json.dumps(bundle_json, default=str, ensure_ascii=False)
|
|
171
|
+
existing.pulled_at = now
|
|
172
|
+
else:
|
|
173
|
+
session.add(CachedExperiment(
|
|
174
|
+
id=str(exp.id),
|
|
175
|
+
project_id=pid_str,
|
|
176
|
+
title=exp.title,
|
|
177
|
+
phase=phase_val,
|
|
178
|
+
data_json=json.dumps(bundle_json, default=str, ensure_ascii=False),
|
|
179
|
+
pulled_at=now,
|
|
180
|
+
))
|
|
181
|
+
experiment_count += 1
|
|
182
|
+
if len(batch) < 100:
|
|
183
|
+
break
|
|
184
|
+
page += 1
|
|
185
|
+
|
|
186
|
+
# --- Update sync_meta ---
|
|
187
|
+
meta = session.get(SyncMeta, pid_str)
|
|
188
|
+
if meta:
|
|
189
|
+
meta.last_pull_at = now
|
|
190
|
+
meta.topic_count = str(topic_count)
|
|
191
|
+
meta.experiment_count = str(experiment_count)
|
|
192
|
+
meta.project_key = project_key
|
|
193
|
+
else:
|
|
194
|
+
session.add(SyncMeta(
|
|
195
|
+
project_id=pid_str,
|
|
196
|
+
project_key=project_key,
|
|
197
|
+
last_pull_at=now,
|
|
198
|
+
topic_count=str(topic_count),
|
|
199
|
+
experiment_count=str(experiment_count),
|
|
200
|
+
))
|
|
201
|
+
|
|
202
|
+
session.commit()
|
|
203
|
+
return {"topics": topic_count, "experiments": experiment_count}
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def get_sync_status(session: Session, project_id: uuid.UUID | None = None) -> list[dict[str, Any]]:
|
|
207
|
+
"""Return sync status for all projects (or a specific one)."""
|
|
208
|
+
query = session.query(SyncMeta)
|
|
209
|
+
if project_id is not None:
|
|
210
|
+
query = query.filter(SyncMeta.project_id == str(project_id))
|
|
211
|
+
results = []
|
|
212
|
+
for meta in query.all():
|
|
213
|
+
results.append({
|
|
214
|
+
"project_id": meta.project_id,
|
|
215
|
+
"project_key": meta.project_key,
|
|
216
|
+
"last_pull_at": meta.last_pull_at.isoformat() if meta.last_pull_at else None,
|
|
217
|
+
"topic_count": int(meta.topic_count or "0"),
|
|
218
|
+
"experiment_count": int(meta.experiment_count or "0"),
|
|
219
|
+
})
|
|
220
|
+
return results
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def list_cached_topics(session: Session, project_id: uuid.UUID) -> list[dict[str, Any]]:
|
|
224
|
+
"""List cached topics (lightweight metadata, no JSON blob)."""
|
|
225
|
+
rows = session.query(CachedTopic).filter(CachedTopic.project_id == str(project_id)).all()
|
|
226
|
+
return [
|
|
227
|
+
{
|
|
228
|
+
"id": r.id,
|
|
229
|
+
"title": r.title,
|
|
230
|
+
"status": r.status,
|
|
231
|
+
"pulled_at": r.pulled_at.isoformat() if r.pulled_at else None,
|
|
232
|
+
}
|
|
233
|
+
for r in rows
|
|
234
|
+
]
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def get_cached_topic(session: Session, topic_id: uuid.UUID) -> dict[str, Any] | None:
|
|
238
|
+
"""Get a single cached topic with full JSON data."""
|
|
239
|
+
row = session.get(CachedTopic, str(topic_id))
|
|
240
|
+
if row is None:
|
|
241
|
+
return None
|
|
242
|
+
return {
|
|
243
|
+
"id": row.id,
|
|
244
|
+
"title": row.title,
|
|
245
|
+
"status": row.status,
|
|
246
|
+
"data": json.loads(row.data_json) if row.data_json else None,
|
|
247
|
+
"pulled_at": row.pulled_at.isoformat() if row.pulled_at else None,
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _to_dict(obj: Any) -> dict[str, Any]:
|
|
252
|
+
"""Fallback serialization for non-Pydantic objects."""
|
|
253
|
+
if hasattr(obj, "__dict__"):
|
|
254
|
+
return {k: v for k, v in obj.__dict__.items() if not k.startswith("_")}
|
|
255
|
+
return {"value": str(obj)}
|
|
@@ -39,6 +39,7 @@ from cli.commands.notification import inbound_event_app, notification_app
|
|
|
39
39
|
from cli.commands.persona import persona_app
|
|
40
40
|
from cli.commands.project import project_app
|
|
41
41
|
from cli.commands.runtime import runtime_app
|
|
42
|
+
from cli.commands.sync import sync_app
|
|
42
43
|
from cli.commands.topic import mention_app, todo_app, topic_app
|
|
43
44
|
from cli.e2e_collab import e2e_app
|
|
44
45
|
from server.domain.models import AgentRole
|
|
@@ -63,6 +64,7 @@ app.add_typer(action_app, name="action")
|
|
|
63
64
|
app.add_typer(feedback_app, name="feedback")
|
|
64
65
|
app.add_typer(docs_app, name="docs")
|
|
65
66
|
app.add_typer(e2e_app, name="e2e")
|
|
67
|
+
app.add_typer(sync_app, name="sync")
|
|
66
68
|
|
|
67
69
|
_transport: httpx.BaseTransport | None = None
|
|
68
70
|
_cli_options: dict[str, Any] = {"persona": None, "project_root": None, "format": "yaml"}
|