plato-sdk-v2 2.2.1__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.
- plato_sdk_v2-2.2.1/.claude/agents/sim-creator.md +1101 -0
- plato_sdk_v2-2.2.1/.gitignore +23 -0
- plato_sdk_v2-2.2.1/.sandbox.yaml +11 -0
- plato_sdk_v2-2.2.1/BUILDING_SIMS.md +70 -0
- plato_sdk_v2-2.2.1/PKG-INFO +347 -0
- plato_sdk_v2-2.2.1/README.md +303 -0
- plato_sdk_v2-2.2.1/VERSION +1 -0
- plato_sdk_v2-2.2.1/ci/CLAUDE.md +5 -0
- plato_sdk_v2-2.2.1/ci/deploy.sh +8 -0
- plato_sdk_v2-2.2.1/ci/lint.sh +11 -0
- plato_sdk_v2-2.2.1/ci/setup.sh +10 -0
- plato_sdk_v2-2.2.1/ci/version-bump.sh +9 -0
- plato_sdk_v2-2.2.1/docs/AGENT_SPEC.md +244 -0
- plato_sdk_v2-2.2.1/docs/CLI.md +133 -0
- plato_sdk_v2-2.2.1/docs/GENERATING_SIM_SDKS.md +325 -0
- plato_sdk_v2-2.2.1/docs/SIMULATOR_LIFECYCLE.md +450 -0
- plato_sdk_v2-2.2.1/docs/SIM_CREATOR.md +1200 -0
- plato_sdk_v2-2.2.1/docs/cli/agent.md +185 -0
- plato_sdk_v2-2.2.1/docs/cli/flows.md +397 -0
- plato_sdk_v2-2.2.1/docs/cli/pm.md +235 -0
- plato_sdk_v2-2.2.1/docs/cli/sandbox.md +326 -0
- plato_sdk_v2-2.2.1/docs/cli/sims.md +278 -0
- plato_sdk_v2-2.2.1/docs/cli/world.md +131 -0
- plato_sdk_v2-2.2.1/docs/sim-creation-pipeline.md +815 -0
- plato_sdk_v2-2.2.1/docs/skill-restructure-plan.md +226 -0
- plato_sdk_v2-2.2.1/docs/skills/SIM-CREATION-ARCHITECTURE.md +373 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-config/SKILL.md +831 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-creator/SKILL.md +199 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-debugger/SKILL.md +443 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-flow-audit/SKILL.md +166 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-flow-clear/SKILL.md +106 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-flow-mutations/SKILL.md +150 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-flow-run/SKILL.md +150 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-research/SKILL.md +125 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-review/SKILL.md +131 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-sandbox-login/SKILL.md +197 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-sandbox-services/SKILL.md +133 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-sandbox-start/SKILL.md +115 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-sandbox-worker/SKILL.md +152 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-snapshot/SKILL.md +155 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-submit/SKILL.md +145 -0
- plato_sdk_v2-2.2.1/docs/skills/sim-validate/SKILL.md +119 -0
- plato_sdk_v2-2.2.1/docs/unit.sh +6 -0
- plato_sdk_v2-2.2.1/plato/__init__.py +65 -0
- plato_sdk_v2-2.2.1/plato/_generated/__init__.py +37 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/__init__.py +8 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/__init__.py +31 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/agent_artifacts/__init__.py +10 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/agent_artifacts/archive_agent_artifact.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/agent_artifacts/create_agent_artifact.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/agent_artifacts/get_agent_artifact_by_public_id.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/agent_artifacts/get_agent_artifacts.py +63 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/cluster/__init__.py +21 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/cluster/cleanup_stale_vms.py +87 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/cluster/get_dispatchers.py +50 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/cluster/get_nodes_status.py +62 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/cluster/get_snapshot_lineage.py +78 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/cluster/get_snapshots_status.py +62 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/cluster/pause_resume_dispatchers.py +93 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/cluster/prefetch_snapshot.py +104 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/__init__.py +67 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/backup.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/cleanup.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/close.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/close_async.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/create.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/create_batch.py +78 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/create_simulator.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/evaluate_session.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/generate_mutations.py +53 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/generate_mutations_single.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/get_active_session.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/get_app_sim_worker_info.py +52 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/get_cdp_url.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/get_flows.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/get_interface_worker_info.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/get_job_info.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/get_job_status.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/get_job_worker_info.py +52 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/get_proxy_url.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/get_public_url.py +99 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/get_simulator_by_name.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/get_simulators.py +64 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/get_state.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/get_worker_ready.py +87 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/log_state_mutation.py +64 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/rescore_simulator_sessions.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/reset.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/score.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/send_heartbeat.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/env/update_simulator.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/evals/__init__.py +23 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/evals/create_test_case_review.py +72 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/evals/evaluate_python.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/evals/get_all_test_case_reviews.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/evals/get_scores_by_user.py +101 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/evals/get_scoring.py +51 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/evals/get_test_case_review.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/evals/human_in_the_loop_scoring.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/evals/start_eval_from_git.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/gitea/__init__.py +35 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/gitea/create_gitea_repository.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/gitea/create_simulator_repository.py +76 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/gitea/delete_gitea_repository.py +74 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/gitea/get_accessible_simulators.py +71 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/gitea/get_gitea_credentials.py +64 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/gitea/get_gitea_repository.py +74 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/gitea/get_my_gitea_info.py +64 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/gitea/get_my_repositories.py +64 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/gitea/get_repository_branches.py +73 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/gitea/get_repository_contents.py +90 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/gitea/get_simulator_file_content.py +93 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/gitea/get_simulator_repository.py +76 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/gitea/get_simulator_repository_branches.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/gitea/get_simulator_repository_contents.py +92 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/jobs/__init__.py +11 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/jobs/get_job_by_id.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/jobs/get_jobs_by_group_id.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/jobs/get_keepalive_jobs.py +63 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/jobs/list_jobs.py +109 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/jobs/update_job_status.py +77 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/organization/__init__.py +33 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/organization/create_annotator_assignment.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/organization/create_org_api_key.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/organization/create_org_policy.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/organization/delete_org_api_key.py +73 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/organization/delete_org_policy.py +73 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/organization/get_annotator_assignments.py +74 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/organization/get_org_api_key_policies.py +74 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/organization/get_org_api_keys.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/organization/get_org_policies.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/organization/get_organization_concurrency_status.py +85 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/organization/get_organization_members.py +63 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/organization/update_annotator_assignment_stage.py +81 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/organization/update_organization_concurrency_limit.py +89 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/queue/__init__.py +10 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/queue/get_queue_status.py +56 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/queue/get_vm_detail.py +83 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/queue/get_vms.py +96 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/queue/get_workers.py +87 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/sandbox/__init__.py +29 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/sandbox/checkpoint_vm.py +90 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/sandbox/close_vm.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/sandbox/create_vm.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/sandbox/execute_ssh_command.py +81 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/sandbox/get_operation_events.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/sandbox/healthy_services.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/sandbox/healthy_worker.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/sandbox/save_vm_snapshot.py +88 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/sandbox/setup_root_access.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/sandbox/setup_sandbox.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/sandbox/start_worker.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/__init__.py +63 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/analyze_labels.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/archive_session.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/archive_session_logs_endpoint.py +73 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/create_from_labels.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/create_session_from_browser.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/create_session_from_env_recording.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/create_session_from_har.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/get_env_recording.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/get_grouped_replay_sessions.py +63 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/get_logs_status.py +73 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/get_network_requests.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/get_next_session_for_annotator.py +73 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/get_public_benchmark_sessions.py +72 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/get_replay_score_data.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/get_rrweb_actions.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/get_rrweb_events.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/get_screen_recording.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/get_session.py +78 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/get_session_replays.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/get_sessions.py +63 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/get_sessions_for_archival.py +100 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/get_ui_events.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/restore_session_logs.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/score_session_with_config.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/search_sessions_by_ids.py +73 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/set_session_output.py +85 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/update_session_public.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/session/update_session_testcase.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/__init__.py +53 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/add_simulator_review.py +81 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/batch_create_test_cases.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/batch_get_artifact_metadata.py +53 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/get_all_simulators_info.py +74 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/get_db_config.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/get_env_flows.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/get_plato_config.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/get_sessions_batch_by_job_groups.py +81 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/get_sessions_by_job_group.py +86 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/get_simulator_by_name.py +82 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/get_simulator_id.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/get_simulator_info.py +67 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/get_simulator_version_details.py +62 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/get_simulator_versions.py +79 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/get_start_path.py +82 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/get_version_by_tag.py +55 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/list_simulators.py +64 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/list_simulators_by_org.py +64 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/list_simulators_status.py +64 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/register.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/update_simulator.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/update_simulator_status.py +85 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/simulator/update_tag.py +72 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/__init__.py +67 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/archive_organization_test_case_assignments.py +72 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/archive_organization_testcase.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/archive_testcase.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/assign_testcase_to_organizations.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/auto_verify_testcase.py +86 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/bulk_archive_testcases.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/convert_text_to_structured_data.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/create_testcase.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/create_testcase_set.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/delete_testcase_set.py +51 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/filter_human_recorder_testcases.py +101 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/generate_outcome_schema.py +53 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/generate_prediction.py +53 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/generate_prediction_from_steps.py +53 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/generate_scoring_config_from_sessions.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/generate_state_mutations_config_route.py +51 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/get_human_recorder_tab_counts.py +94 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/get_human_recorder_testcases.py +101 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/get_merged_mutations.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/get_mutation_groups_for_testcase.py +98 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/get_next_testcase_for_scoring.py +92 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/get_organization_test_case_assignments.py +96 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/get_testcase.py +51 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/get_testcase_metadata_for_scoring.py +74 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/get_testcase_sets.py +63 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/get_testcases.py +171 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/get_testcases_in_set.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/mark_organization_test_case_completed.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/update_testcase.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v1/testcases/version_bump_testcase.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/__init__.py +16 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/agents/__init__.py +21 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/agents/get_agent_ecr_token.py +80 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/agents/get_agent_schema.py +99 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/agents/get_agent_versions.py +87 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/agents/import_agent.py +84 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/agents/list_docker_agents.py +64 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/agents/lookup_agent_version.py +94 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/agents/register_docker_agent.py +82 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/artifacts/__init__.py +7 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/artifacts/get_artifact.py +73 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/chronos/__init__.py +7 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/chronos/launch_job.py +76 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/chronos_packages/__init__.py +17 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/chronos_packages/get_package_versions.py +89 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/chronos_packages/list_chronos_packages.py +76 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/chronos_packages/lookup_package_version.py +96 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/chronos_packages/register_chronos_package.py +102 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/chronos_packages/upload_chronos_package.py +112 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/cluster/__init__.py +7 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/cluster/get_node_config.py +82 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/__init__.py +43 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/checkpoint.py +93 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/close.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/connect_routing_info.py +74 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/connect_url.py +105 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/disk_snapshot.py +93 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/execute.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/get_flows.py +95 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/get_plato_config.py +95 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/log_for_job.py +82 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/make.py +78 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/public_url.py +107 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/reset.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/set_date.py +89 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/setup_sandbox.py +97 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/snapshot.py +85 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/snapshot_store.py +91 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/state.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/jobs/wait_for_ready.py +105 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/pypi/__init__.py +11 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/pypi/download_package.py +66 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/pypi/get_package_schema.py +78 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/pypi/package_index.py +62 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/pypi/simple_index.py +57 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/pypi/upload_package.py +57 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/releases/__init__.py +23 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/releases/create.py +70 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/releases/deploy.py +82 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/releases/get.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/releases/handle_get_existing_public_ids.py +58 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/releases/handle_import.py +61 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/releases/list_releases.py +81 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/releases/prep_release_assigned_testcases.py +91 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/releases/update.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/__init__.py +61 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/checkpoint.py +97 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/close.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/disk_snapshot.py +93 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/evaluate.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/execute.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/get_connect_url.py +99 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/get_presigned_url.py +80 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/get_public_url.py +101 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/get_s3_content.py +80 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/get_session_details.py +68 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/get_session_documents.py +73 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/get_session_flows.py +93 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/get_session_logs.py +83 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/get_session_plato_config.py +93 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/heartbeat.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/list_jobs.py +69 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/list_sessions.py +80 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/log_job_mutation.py +73 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/make.py +78 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/reset.py +75 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/set_date.py +89 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/setup_sandbox.py +98 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/snapshot.py +88 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/snapshot_store.py +94 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/state.py +87 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/upload_session_documents.py +115 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/sessions/wait_for_ready.py +107 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/user/__init__.py +7 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/v2/user/get_current_user.py +76 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/version/__init__.py +7 -0
- plato_sdk_v2-2.2.1/plato/_generated/api/version/check.py +43 -0
- plato_sdk_v2-2.2.1/plato/_generated/client.py +171 -0
- plato_sdk_v2-2.2.1/plato/_generated/errors.py +141 -0
- plato_sdk_v2-2.2.1/plato/_generated/models/__init__.py +4752 -0
- plato_sdk_v2-2.2.1/plato/_generated/py.typed +0 -0
- plato_sdk_v2-2.2.1/plato/_sims_generator/__init__.py +58 -0
- plato_sdk_v2-2.2.1/plato/_sims_generator/cli.py +83 -0
- plato_sdk_v2-2.2.1/plato/_sims_generator/instruction.py +203 -0
- plato_sdk_v2-2.2.1/plato/_sims_generator/parser.py +978 -0
- plato_sdk_v2-2.2.1/plato/_sims_generator/python.py +506 -0
- plato_sdk_v2-2.2.1/plato/_sims_generator/templates/instruction/helpers.py.jinja +161 -0
- plato_sdk_v2-2.2.1/plato/_sims_generator/templates/instruction/init.py.jinja +43 -0
- plato_sdk_v2-2.2.1/plato/_sims_generator/templates/python/api_init.py.jinja +11 -0
- plato_sdk_v2-2.2.1/plato/_sims_generator/templates/python/client.py.jinja +589 -0
- plato_sdk_v2-2.2.1/plato/_sims_generator/templates/python/endpoint.py.jinja +359 -0
- plato_sdk_v2-2.2.1/plato/_sims_generator/templates/python/errors.py.jinja +141 -0
- plato_sdk_v2-2.2.1/plato/_sims_generator/templates/python/package_init.py.jinja +47 -0
- plato_sdk_v2-2.2.1/plato/_sims_generator/templates/python/tag_init.py.jinja +11 -0
- plato_sdk_v2-2.2.1/plato/_sims_generator/templates/python/version_init.py.jinja +11 -0
- plato_sdk_v2-2.2.1/plato/agents/__init__.py +118 -0
- plato_sdk_v2-2.2.1/plato/agents/base.py +145 -0
- plato_sdk_v2-2.2.1/plato/agents/build.py +61 -0
- plato_sdk_v2-2.2.1/plato/agents/config.py +160 -0
- plato_sdk_v2-2.2.1/plato/agents/logging.py +401 -0
- plato_sdk_v2-2.2.1/plato/agents/runner.py +150 -0
- plato_sdk_v2-2.2.1/plato/agents/trajectory.py +266 -0
- plato_sdk_v2-2.2.1/plato/chronos/__init__.py +37 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/__init__.py +3 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/agents/__init__.py +13 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/agents/create_agent.py +63 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/agents/delete_agent.py +61 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/agents/get_agent.py +62 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/agents/get_agent_schema.py +72 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/agents/get_agent_versions.py +62 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/agents/list_agents.py +57 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/agents/lookup_agent.py +74 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/auth/__init__.py +9 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/auth/debug_auth_api_auth_debug_get.py +43 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/auth/get_auth_status_api_auth_status_get.py +61 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/auth/get_current_user_route_api_auth_me_get.py +60 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/callback/__init__.py +11 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/callback/push_agent_logs.py +61 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/callback/update_agent_status.py +57 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/callback/upload_artifacts.py +59 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/callback/upload_logs_zip.py +57 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/callback/upload_trajectory.py +57 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/default/__init__.py +7 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/default/health.py +43 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/jobs/__init__.py +7 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/jobs/launch_job.py +63 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/registry/__init__.py +19 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/registry/get_agent_schema_api_registry_agents__agent_name__schema_get.py +62 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/registry/get_agent_versions_api_registry_agents__agent_name__versions_get.py +52 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/registry/get_world_schema_api_registry_worlds__package_name__schema_get.py +68 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/registry/get_world_versions_api_registry_worlds__package_name__versions_get.py +52 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/registry/list_registry_agents_api_registry_agents_get.py +44 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/registry/list_registry_worlds_api_registry_worlds_get.py +44 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/runtimes/__init__.py +11 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/runtimes/create_runtime.py +63 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/runtimes/delete_runtime.py +61 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/runtimes/get_runtime.py +62 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/runtimes/list_runtimes.py +57 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/runtimes/test_runtime.py +67 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/secrets/__init__.py +11 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/secrets/create_secret.py +63 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/secrets/delete_secret.py +61 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/secrets/get_secret.py +62 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/secrets/list_secrets.py +57 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/secrets/update_secret.py +68 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/sessions/__init__.py +10 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/sessions/get_session.py +62 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/sessions/get_session_logs.py +72 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/sessions/get_session_logs_download.py +62 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/sessions/list_sessions.py +57 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/status/__init__.py +8 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/status/get_status_api_status_get.py +44 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/status/get_version_info_api_version_get.py +44 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/templates/__init__.py +11 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/templates/create_template.py +63 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/templates/delete_template.py +61 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/templates/get_template.py +62 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/templates/list_templates.py +57 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/templates/update_template.py +68 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/trajectories/__init__.py +8 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/trajectories/get_trajectory.py +62 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/trajectories/list_trajectories.py +62 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/worlds/__init__.py +10 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/worlds/create_world.py +63 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/worlds/delete_world.py +61 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/worlds/get_world.py +62 -0
- plato_sdk_v2-2.2.1/plato/chronos/api/worlds/list_worlds.py +57 -0
- plato_sdk_v2-2.2.1/plato/chronos/client.py +171 -0
- plato_sdk_v2-2.2.1/plato/chronos/errors.py +141 -0
- plato_sdk_v2-2.2.1/plato/chronos/models/__init__.py +647 -0
- plato_sdk_v2-2.2.1/plato/chronos/py.typed +0 -0
- plato_sdk_v2-2.2.1/plato/py.typed +0 -0
- plato_sdk_v2-2.2.1/plato/sims/README.md +283 -0
- plato_sdk_v2-2.2.1/plato/sims/__init__.py +57 -0
- plato_sdk_v2-2.2.1/plato/sims/agent_helpers.py +308 -0
- plato_sdk_v2-2.2.1/plato/sims/cli.py +1501 -0
- plato_sdk_v2-2.2.1/plato/sims/generate_clients.py +199 -0
- plato_sdk_v2-2.2.1/plato/sims/registry.py +319 -0
- plato_sdk_v2-2.2.1/plato/v1/__init__.py +6 -0
- plato_sdk_v2-2.2.1/plato/v1/audit_ui.py +281 -0
- plato_sdk_v2-2.2.1/plato/v1/cli/__init__.py +5 -0
- plato_sdk_v2-2.2.1/plato/v1/cli/agent.py +1216 -0
- plato_sdk_v2-2.2.1/plato/v1/cli/main.py +206 -0
- plato_sdk_v2-2.2.1/plato/v1/cli/pm.py +1172 -0
- plato_sdk_v2-2.2.1/plato/v1/cli/sandbox.py +2220 -0
- plato_sdk_v2-2.2.1/plato/v1/cli/sim.py +11 -0
- plato_sdk_v2-2.2.1/plato/v1/cli/ssh.py +207 -0
- plato_sdk_v2-2.2.1/plato/v1/cli/utils.py +116 -0
- plato_sdk_v2-2.2.1/plato/v1/cli/verify.py +1269 -0
- plato_sdk_v2-2.2.1/plato/v1/cli/world.py +282 -0
- plato_sdk_v2-2.2.1/plato/v1/cli.py +12 -0
- plato_sdk_v2-2.2.1/plato/v1/config.py +25 -0
- plato_sdk_v2-2.2.1/plato/v1/examples/doordash_tasks.py +540 -0
- plato_sdk_v2-2.2.1/plato/v1/examples/loadtest.py +160 -0
- plato_sdk_v2-2.2.1/plato/v1/examples/test_env.py +128 -0
- plato_sdk_v2-2.2.1/plato/v1/examples/test_env_custom_browser.py +103 -0
- plato_sdk_v2-2.2.1/plato/v1/examples/test_env_sync.py +80 -0
- plato_sdk_v2-2.2.1/plato/v1/examples/test_reuse_env.py +0 -0
- plato_sdk_v2-2.2.1/plato/v1/examples/test_run.py +0 -0
- plato_sdk_v2-2.2.1/plato/v1/exceptions.py +4 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/README.md +223 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/api-client.js +158 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/background.js +1044 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/build-sdk.js +17 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/content.js +446 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/manifest.json +52 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/offscreen.html +10 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/offscreen.js +205 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/options.html +204 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/options.js +101 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/package-lock.json +496 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/package.json +5 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/plato-sdk-bundle.js +7036 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/plato-sdk-bundle.js.map +7 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/popup.html +228 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/popup.js +327 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/review-panel.html +63 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/review-panel.js +216 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/review-success.html +49 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/review-success.js +58 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/session-active.html +63 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/session-active.js +487 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/session-ended.html +54 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/session-ended.js +61 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/session-setup.html +54 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/session-setup.js +101 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/sessions.html +270 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/sessions.js +444 -0
- plato_sdk_v2-2.2.1/plato/v1/extensions/envgen-recorder/styles.css +374 -0
- plato_sdk_v2-2.2.1/plato/v1/flow_executor.py +463 -0
- plato_sdk_v2-2.2.1/plato/v1/models/__init__.py +37 -0
- plato_sdk_v2-2.2.1/plato/v1/models/build_models.py +245 -0
- plato_sdk_v2-2.2.1/plato/v1/models/env.py +775 -0
- plato_sdk_v2-2.2.1/plato/v1/models/flow.py +195 -0
- plato_sdk_v2-2.2.1/plato/v1/models/sandbox.py +155 -0
- plato_sdk_v2-2.2.1/plato/v1/models/task.py +145 -0
- plato_sdk_v2-2.2.1/plato/v1/sandbox_sdk.py +1092 -0
- plato_sdk_v2-2.2.1/plato/v1/sdk.py +856 -0
- plato_sdk_v2-2.2.1/plato/v1/sync_env.py +604 -0
- plato_sdk_v2-2.2.1/plato/v1/sync_flow_executor.py +457 -0
- plato_sdk_v2-2.2.1/plato/v1/sync_sdk.py +695 -0
- plato_sdk_v2-2.2.1/plato/v1/utils/proxytunnel.py +152 -0
- plato_sdk_v2-2.2.1/plato/v2/__init__.py +61 -0
- plato_sdk_v2-2.2.1/plato/v2/async_/__init__.py +17 -0
- plato_sdk_v2-2.2.1/plato/v2/async_/artifact.py +40 -0
- plato_sdk_v2-2.2.1/plato/v2/async_/client.py +132 -0
- plato_sdk_v2-2.2.1/plato/v2/async_/environment.py +165 -0
- plato_sdk_v2-2.2.1/plato/v2/async_/flow_executor.py +353 -0
- plato_sdk_v2-2.2.1/plato/v2/async_/session.py +1030 -0
- plato_sdk_v2-2.2.1/plato/v2/models.py +65 -0
- plato_sdk_v2-2.2.1/plato/v2/sync/__init__.py +13 -0
- plato_sdk_v2-2.2.1/plato/v2/sync/artifact.py +40 -0
- plato_sdk_v2-2.2.1/plato/v2/sync/client.py +129 -0
- plato_sdk_v2-2.2.1/plato/v2/sync/environment.py +147 -0
- plato_sdk_v2-2.2.1/plato/v2/sync/flow_executor.py +353 -0
- plato_sdk_v2-2.2.1/plato/v2/sync/session.py +796 -0
- plato_sdk_v2-2.2.1/plato/v2/types.py +127 -0
- plato_sdk_v2-2.2.1/plato/v2/utils/__init__.py +1 -0
- plato_sdk_v2-2.2.1/plato/v2/utils/db_cleanup.py +227 -0
- plato_sdk_v2-2.2.1/plato/v2/utils/models.py +54 -0
- plato_sdk_v2-2.2.1/plato/v2/utils/proxy_tunnel.py +301 -0
- plato_sdk_v2-2.2.1/plato/worlds/README.md +218 -0
- plato_sdk_v2-2.2.1/plato/worlds/__init__.py +80 -0
- plato_sdk_v2-2.2.1/plato/worlds/base.py +310 -0
- plato_sdk_v2-2.2.1/plato/worlds/build_hook.py +98 -0
- plato_sdk_v2-2.2.1/plato/worlds/config.py +288 -0
- plato_sdk_v2-2.2.1/plato/worlds/runner.py +261 -0
- plato_sdk_v2-2.2.1/pyproject.toml +110 -0
- plato_sdk_v2-2.2.1/scripts/get_all_artifact_targets.py +94 -0
- plato_sdk_v2-2.2.1/tests/__init__.py +1 -0
- plato_sdk_v2-2.2.1/tests/integration/__init__.py +13 -0
- plato_sdk_v2-2.2.1/tests/integration/conftest.py +77 -0
- plato_sdk_v2-2.2.1/tests/integration/test_browser_agent.py +376 -0
- plato_sdk_v2-2.2.1/tests/integration/test_chronos_callback.py +409 -0
- plato_sdk_v2-2.2.1/tests/integration/test_cleanup_snapshot.py +143 -0
- plato_sdk_v2-2.2.1/tests/integration/test_code_world.py +67 -0
- plato_sdk_v2-2.2.1/tests/integration/test_harbor_agent_runner.py +208 -0
- plato_sdk_v2-2.2.1/tests/sims/__init__.py +1 -0
- plato_sdk_v2-2.2.1/tests/sims/conftest.py +13 -0
- plato_sdk_v2-2.2.1/tests/sims/test_agent_helpers.py +116 -0
- plato_sdk_v2-2.2.1/tests/test_heartbeat_keepalive.py +205 -0
- plato_sdk_v2-2.2.1/tests/test_session_serialization.py +252 -0
- plato_sdk_v2-2.2.1/tests/test_set_date.py +149 -0
- plato_sdk_v2-2.2.1/tests/test_v2_imports.py +178 -0
- plato_sdk_v2-2.2.1/tests/test_v2_multisim_integration.py +229 -0
- plato_sdk_v2-2.2.1/tests/test_v2_session.py +50 -0
- plato_sdk_v2-2.2.1/tests/test_version.py +31 -0
- plato_sdk_v2-2.2.1/uv.lock +2685 -0
|
@@ -0,0 +1,1101 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sim-creator
|
|
3
|
+
description: Create new Plato simulators from GitHub repositories. Use when user asks to create a sim, make a simulator, or set up a new app for Plato from a GitHub URL.
|
|
4
|
+
tools: Read, Write, Edit, Glob, Grep, Bash, WebFetch, WebSearch
|
|
5
|
+
model: opus
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Sim Creator Agent
|
|
9
|
+
|
|
10
|
+
You are a Plato simulator creation agent. Your job is to create new simulators from GitHub repositories.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## CRITICAL: Simulator Naming Rules
|
|
15
|
+
|
|
16
|
+
**Sim names MUST follow these rules:**
|
|
17
|
+
- **Lowercase letters only** (a-z)
|
|
18
|
+
- **Underscores allowed** for word separation
|
|
19
|
+
- **NO dashes, numbers, or special characters**
|
|
20
|
+
|
|
21
|
+
| Input | Correct Name |
|
|
22
|
+
|-------|--------------|
|
|
23
|
+
| Invoice Ninja | `invoiceninja` |
|
|
24
|
+
| Twenty CRM | `twenty` |
|
|
25
|
+
| DocuSeal | `docuseal` |
|
|
26
|
+
| EspoCRM | `espocrm` |
|
|
27
|
+
| Cal.com | `calcom` |
|
|
28
|
+
| Tasty Igniter | `tastyigniter` |
|
|
29
|
+
| Work Lenz | `worklenz` |
|
|
30
|
+
|
|
31
|
+
**BAD names:** `invoice-ninja`, `twenty-crm`, `docu_seal_1`, `EspoCRM`
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Existing Sims & Authentication
|
|
36
|
+
|
|
37
|
+
### Sim Already Exists? That's OK.
|
|
38
|
+
|
|
39
|
+
If you're asked to create a sim that already exists, you should:
|
|
40
|
+
1. **Iterate on what exists** - Read the existing config files and improve them
|
|
41
|
+
2. **Or wipe and restart** - Delete the existing folder and start fresh if the existing setup is broken
|
|
42
|
+
|
|
43
|
+
Check for existing sim:
|
|
44
|
+
```bash
|
|
45
|
+
ls -la /Users/zachplato/projects/giteasims/plato/{simName}/
|
|
46
|
+
ls -la /Users/zachplato/projects/giteasims/zach-test/{simName}/
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Initial Setup vs Login Flow
|
|
50
|
+
|
|
51
|
+
**IMPORTANT**: Many apps require initial setup (creating admin account, configuring settings, etc.) before login will work. This setup should NOT be in the login flow.
|
|
52
|
+
|
|
53
|
+
**Flows should ONLY do login** - nothing else. No setup, no onboarding, no configuration.
|
|
54
|
+
|
|
55
|
+
If the app needs initial setup:
|
|
56
|
+
1. Start the sandbox and get it running
|
|
57
|
+
2. **Ask the user to do initial setup manually** via the browser:
|
|
58
|
+
```
|
|
59
|
+
The app requires initial setup before login will work.
|
|
60
|
+
|
|
61
|
+
Please open the app URL and complete the initial setup:
|
|
62
|
+
- Create the admin account
|
|
63
|
+
- Configure any required settings
|
|
64
|
+
- Complete the onboarding wizard
|
|
65
|
+
|
|
66
|
+
Let me know when setup is complete and I'll continue with the login flow.
|
|
67
|
+
```
|
|
68
|
+
3. After user confirms setup is done, THEN test the login flow
|
|
69
|
+
4. The login flow should use the credentials created during setup
|
|
70
|
+
|
|
71
|
+
**Example apps requiring manual setup:**
|
|
72
|
+
- Apps with "first run" wizards
|
|
73
|
+
- Apps that create admin account on first visit
|
|
74
|
+
- Apps requiring license key or initial configuration
|
|
75
|
+
|
|
76
|
+
### Plato CLI Authentication Errors
|
|
77
|
+
|
|
78
|
+
If you get authentication or permission errors from the Plato CLI (e.g., 401, 403, "unauthorized", "invalid token"), **ask the user for their Plato API key**:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
I'm getting authentication errors from the Plato CLI. Please provide your Plato API key so I can configure the CLI.
|
|
82
|
+
|
|
83
|
+
You can find your API key at: https://plato.so/settings/api-keys
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Once provided, configure it:
|
|
87
|
+
```bash
|
|
88
|
+
plato config set api_key <key>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Phase 1: Research the Application
|
|
94
|
+
|
|
95
|
+
### Information to Gather
|
|
96
|
+
|
|
97
|
+
| Question | How to Find |
|
|
98
|
+
|----------|-------------|
|
|
99
|
+
| Database type | Check docker-compose, README, or docs |
|
|
100
|
+
| Docker image | Docker Hub, GitHub Container Registry |
|
|
101
|
+
| Image version tag | Docker Hub tags page, GitHub releases |
|
|
102
|
+
| Web UI port | docker-compose, docs |
|
|
103
|
+
| Login URL path | Usually /login, /admin, /signin |
|
|
104
|
+
| Default credentials | docs, docker-compose env vars |
|
|
105
|
+
| Required env vars | docker-compose examples |
|
|
106
|
+
|
|
107
|
+
### Research Steps
|
|
108
|
+
|
|
109
|
+
1. **Read GitHub README** - Understand what the app does
|
|
110
|
+
2. **Find Docker setup** - Check for docker-compose.yml in repo
|
|
111
|
+
3. **Find Docker image** - Check Docker Hub for official images
|
|
112
|
+
4. **Get version tag** - Look at Docker Hub tags, use specific version (NOT `latest` or `stable`)
|
|
113
|
+
5. **Find credentials** - Check docs or docker-compose for defaults
|
|
114
|
+
6. **Find login page** - Usually documented or can infer from app type
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Phase 2: Validate Database
|
|
119
|
+
|
|
120
|
+
### Supported Databases
|
|
121
|
+
|
|
122
|
+
**ONLY supported:** PostgreSQL, MySQL, MariaDB
|
|
123
|
+
|
|
124
|
+
**NOT supported - STOP immediately:**
|
|
125
|
+
- MongoDB
|
|
126
|
+
- SQLite
|
|
127
|
+
- Redis (as primary data store)
|
|
128
|
+
- Cassandra, DynamoDB, CouchDB, or any NoSQL
|
|
129
|
+
|
|
130
|
+
If the application uses an unsupported database, respond with:
|
|
131
|
+
```
|
|
132
|
+
FAILED: Cannot create simulator.
|
|
133
|
+
Reason: Application uses {database_type}, which is not supported.
|
|
134
|
+
Plato only supports: PostgreSQL, MySQL, MariaDB
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Phase 3: Create Files
|
|
140
|
+
|
|
141
|
+
### Directory Structure
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
{simName}/
|
|
145
|
+
├── plato-config.yml
|
|
146
|
+
└── base/
|
|
147
|
+
├── docker-compose.yml
|
|
148
|
+
├── login-flow.yml
|
|
149
|
+
└── nginx.conf # Only if app doesn't serve on port 80
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 3.1 docker-compose.yml (PostgreSQL)
|
|
153
|
+
|
|
154
|
+
```yaml
|
|
155
|
+
services:
|
|
156
|
+
db:
|
|
157
|
+
container_name: {simName}-db
|
|
158
|
+
platform: linux/amd64
|
|
159
|
+
image: public.ecr.aws/i3q4i1d7/app-sim/postgres-15-alpine:prod-latest
|
|
160
|
+
network_mode: host
|
|
161
|
+
command: ["postgres", "-c", "listen_addresses=127.0.0.1"]
|
|
162
|
+
environment:
|
|
163
|
+
POSTGRES_DB: {simName}
|
|
164
|
+
POSTGRES_USER: {simName}
|
|
165
|
+
POSTGRES_PASSWORD: {simName}
|
|
166
|
+
volumes:
|
|
167
|
+
- /home/plato/db_signals:/tmp/postgres-signals
|
|
168
|
+
healthcheck:
|
|
169
|
+
test: ["CMD-SHELL", "test -f /tmp/postgres-signals/pg.healthy"]
|
|
170
|
+
interval: 10s
|
|
171
|
+
timeout: 5s
|
|
172
|
+
retries: 5
|
|
173
|
+
start_period: 30s
|
|
174
|
+
|
|
175
|
+
app:
|
|
176
|
+
container_name: {simName}-app
|
|
177
|
+
platform: linux/amd64
|
|
178
|
+
image: {dockerImage}:{versionTag}
|
|
179
|
+
network_mode: host
|
|
180
|
+
depends_on:
|
|
181
|
+
db:
|
|
182
|
+
condition: service_healthy
|
|
183
|
+
environment:
|
|
184
|
+
DATABASE_URL: postgresql://{simName}:{simName}@127.0.0.1:5432/{simName}
|
|
185
|
+
# Add app-specific env vars
|
|
186
|
+
healthcheck:
|
|
187
|
+
test: ["CMD-SHELL", "curl -f http://127.0.0.1:{appPort}/ || exit 1"]
|
|
188
|
+
interval: 30s
|
|
189
|
+
timeout: 10s
|
|
190
|
+
retries: 10
|
|
191
|
+
start_period: 120s
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 3.2 docker-compose.yml (MySQL/MariaDB)
|
|
195
|
+
|
|
196
|
+
```yaml
|
|
197
|
+
services:
|
|
198
|
+
db:
|
|
199
|
+
container_name: {simName}-db
|
|
200
|
+
platform: linux/amd64
|
|
201
|
+
image: public.ecr.aws/i3q4i1d7/app-sim/mariadb-10.6:prod-latest
|
|
202
|
+
network_mode: host
|
|
203
|
+
environment:
|
|
204
|
+
MYSQL_DATABASE: {simName}
|
|
205
|
+
MYSQL_USER: {simName}
|
|
206
|
+
MYSQL_PASSWORD: {simName}
|
|
207
|
+
MYSQL_ROOT_PASSWORD: {simName}
|
|
208
|
+
volumes:
|
|
209
|
+
- /home/plato/db_signals:/tmp/mysql-signals
|
|
210
|
+
healthcheck:
|
|
211
|
+
test: ["CMD-SHELL", "test -f /tmp/mysql-signals/mysql.healthy"]
|
|
212
|
+
interval: 10s
|
|
213
|
+
timeout: 5s
|
|
214
|
+
retries: 5
|
|
215
|
+
start_period: 30s
|
|
216
|
+
|
|
217
|
+
app:
|
|
218
|
+
container_name: {simName}-app
|
|
219
|
+
platform: linux/amd64
|
|
220
|
+
image: {dockerImage}:{versionTag}
|
|
221
|
+
network_mode: host
|
|
222
|
+
depends_on:
|
|
223
|
+
db:
|
|
224
|
+
condition: service_healthy
|
|
225
|
+
environment:
|
|
226
|
+
DB_HOST: 127.0.0.1
|
|
227
|
+
DB_PORT: 3306
|
|
228
|
+
DB_DATABASE: {simName}
|
|
229
|
+
DB_USERNAME: {simName}
|
|
230
|
+
DB_PASSWORD: {simName}
|
|
231
|
+
healthcheck:
|
|
232
|
+
test: ["CMD-SHELL", "curl -f http://127.0.0.1:{appPort}/ || exit 1"]
|
|
233
|
+
interval: 30s
|
|
234
|
+
timeout: 10s
|
|
235
|
+
retries: 10
|
|
236
|
+
start_period: 120s
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Plato Database Images (REQUIRED)
|
|
240
|
+
|
|
241
|
+
| Database | Image |
|
|
242
|
+
|----------|-------|
|
|
243
|
+
| PostgreSQL 15 | `public.ecr.aws/i3q4i1d7/app-sim/postgres-15-alpine:prod-latest` |
|
|
244
|
+
| PostgreSQL 17 | `public.ecr.aws/i3q4i1d7/app-sim/postgres-17-alpine:prod-latest` |
|
|
245
|
+
| MariaDB 10.6 | `public.ecr.aws/i3q4i1d7/app-sim/mariadb-10.6:prod-latest` |
|
|
246
|
+
|
|
247
|
+
**You MUST use these images** - standard postgres/mysql images won't work with Plato's signal-based health checks.
|
|
248
|
+
|
|
249
|
+
### 3.3 Nginx Proxy (Required if app doesn't serve on port 80)
|
|
250
|
+
|
|
251
|
+
Add to docker-compose.yml:
|
|
252
|
+
```yaml
|
|
253
|
+
proxy:
|
|
254
|
+
container_name: {simName}-proxy
|
|
255
|
+
image: nginx:alpine
|
|
256
|
+
network_mode: host
|
|
257
|
+
depends_on:
|
|
258
|
+
app:
|
|
259
|
+
condition: service_healthy
|
|
260
|
+
volumes:
|
|
261
|
+
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
|
262
|
+
healthcheck:
|
|
263
|
+
test: ["CMD-SHELL", "curl -f http://127.0.0.1:80/ || exit 1"]
|
|
264
|
+
interval: 10s
|
|
265
|
+
timeout: 5s
|
|
266
|
+
retries: 5
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Create `base/nginx.conf`:
|
|
270
|
+
```nginx
|
|
271
|
+
server {
|
|
272
|
+
listen 80;
|
|
273
|
+
location / {
|
|
274
|
+
proxy_pass http://127.0.0.1:{appPort};
|
|
275
|
+
proxy_set_header Host $host;
|
|
276
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Important**: When using nginx proxy, set `required_healthy_containers` to the proxy container name (e.g., `{simName}-proxy`).
|
|
282
|
+
|
|
283
|
+
### 3.4 plato-config.yml
|
|
284
|
+
|
|
285
|
+
```yaml
|
|
286
|
+
service: "{simName}"
|
|
287
|
+
datasets:
|
|
288
|
+
base:
|
|
289
|
+
compute:
|
|
290
|
+
cpus: 2
|
|
291
|
+
memory: 2048
|
|
292
|
+
disk: 10240
|
|
293
|
+
app_port: 80
|
|
294
|
+
plato_messaging_port: 7000
|
|
295
|
+
metadata:
|
|
296
|
+
name: "{Human Readable Name}"
|
|
297
|
+
description: "{Description from GitHub}"
|
|
298
|
+
source_code_url: "{githubUrl}"
|
|
299
|
+
start_url: /
|
|
300
|
+
license: "MIT"
|
|
301
|
+
variables:
|
|
302
|
+
- name: username
|
|
303
|
+
value: {defaultUsername}
|
|
304
|
+
- name: password
|
|
305
|
+
value: {defaultPassword}
|
|
306
|
+
- name: wrong_password
|
|
307
|
+
value: wrongpassword
|
|
308
|
+
flows_path: base/login-flow.yml
|
|
309
|
+
services:
|
|
310
|
+
main_app:
|
|
311
|
+
type: docker-compose
|
|
312
|
+
file: base/docker-compose.yml
|
|
313
|
+
healthy_wait_timeout: 600
|
|
314
|
+
required_healthy_containers:
|
|
315
|
+
- {simName}-app # MUST match container_name exactly
|
|
316
|
+
listeners:
|
|
317
|
+
db:
|
|
318
|
+
type: db
|
|
319
|
+
db_type: postgresql # or mysql
|
|
320
|
+
db_host: 127.0.0.1
|
|
321
|
+
db_port: 5432 # or 3306 for mysql
|
|
322
|
+
db_user: {simName}
|
|
323
|
+
db_password: {simName}
|
|
324
|
+
db_database: {simName}
|
|
325
|
+
volumes:
|
|
326
|
+
- /home/plato/db_signals:/tmp/postgres-signals # or /tmp/mysql-signals
|
|
327
|
+
audit_ignore_tables:
|
|
328
|
+
- migrations
|
|
329
|
+
- _prisma_migrations
|
|
330
|
+
- failed_jobs
|
|
331
|
+
- sessions
|
|
332
|
+
- jobs
|
|
333
|
+
ignore_columns:
|
|
334
|
+
'*': [created_at, updated_at, deleted_at, last_login]
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### 3.5 login-flow.yml
|
|
338
|
+
|
|
339
|
+
```yaml
|
|
340
|
+
flows:
|
|
341
|
+
- name: login
|
|
342
|
+
description: Standard login flow for {simName}
|
|
343
|
+
steps:
|
|
344
|
+
- type: screenshot
|
|
345
|
+
filename: 01_before_login.png
|
|
346
|
+
description: Initial page state
|
|
347
|
+
|
|
348
|
+
- type: wait
|
|
349
|
+
duration: 3000
|
|
350
|
+
description: Wait for page to load
|
|
351
|
+
|
|
352
|
+
- type: wait_for_selector
|
|
353
|
+
selector: 'input[name="email"], input[type="email"], input[name="username"], #email, #username'
|
|
354
|
+
timeout: 30000
|
|
355
|
+
description: Wait for username field
|
|
356
|
+
|
|
357
|
+
- type: fill
|
|
358
|
+
selector: 'input[name="email"], input[type="email"], input[name="username"], #email, #username'
|
|
359
|
+
value: {defaultUsername}
|
|
360
|
+
description: Fill username
|
|
361
|
+
|
|
362
|
+
- type: fill
|
|
363
|
+
selector: 'input[name="password"], input[type="password"], #password'
|
|
364
|
+
value: {defaultPassword}
|
|
365
|
+
description: Fill password
|
|
366
|
+
|
|
367
|
+
- type: screenshot
|
|
368
|
+
filename: 02_credentials_entered.png
|
|
369
|
+
description: After entering credentials
|
|
370
|
+
|
|
371
|
+
- type: click
|
|
372
|
+
selector: 'button[type="submit"], input[type="submit"]'
|
|
373
|
+
description: Click submit
|
|
374
|
+
|
|
375
|
+
- type: wait
|
|
376
|
+
duration: 5000
|
|
377
|
+
description: Wait for login to process
|
|
378
|
+
|
|
379
|
+
- type: screenshot
|
|
380
|
+
filename: 03_after_login.png
|
|
381
|
+
description: After login attempt
|
|
382
|
+
|
|
383
|
+
- type: verify
|
|
384
|
+
verify_type: element_exists
|
|
385
|
+
selector: 'nav, .navbar, .sidebar, .dashboard, .user-menu, [data-testid="dashboard"]'
|
|
386
|
+
description: Verify logged in by checking for dashboard elements
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Flow Step Types Reference
|
|
390
|
+
|
|
391
|
+
| Type | Required Fields | Description |
|
|
392
|
+
|------|-----------------|-------------|
|
|
393
|
+
| `navigate` | `url` | Navigate to URL |
|
|
394
|
+
| `fill` | `selector`, `value` | Fill input field |
|
|
395
|
+
| `click` | `selector` | Click element |
|
|
396
|
+
| `wait` | `duration` | Wait milliseconds |
|
|
397
|
+
| `wait_for_selector` | `selector`, `timeout` | Wait for element |
|
|
398
|
+
| `screenshot` | `filename` | Take screenshot |
|
|
399
|
+
| `verify` | `verify_type`, `selector` | Verify element exists |
|
|
400
|
+
| `verify_text` | `selector`, `expected_text` | Verify text content |
|
|
401
|
+
| `verify_url` | `expected_url` | Verify current URL contains |
|
|
402
|
+
| `check_element` | `selector`, `check_type` | Check visible/enabled/checked |
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## Phase 4: Execute Workflow
|
|
407
|
+
|
|
408
|
+
### Step 1: Start Sandbox
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
cd /path/to/{simName}
|
|
412
|
+
plato sandbox start --from-config
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
Note the output:
|
|
416
|
+
- SSH config path: `~/.plato/ssh_XX.conf`
|
|
417
|
+
- Job ID from URL
|
|
418
|
+
|
|
419
|
+
### Step 2: Start Services
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
plato sandbox start-services
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
This command:
|
|
426
|
+
1. Pushes code to Plato Hub (Gitea)
|
|
427
|
+
2. Clones code on the VM
|
|
428
|
+
3. Runs `docker compose up -d`
|
|
429
|
+
|
|
430
|
+
### Step 3: Start Worker
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
plato sandbox start-worker
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Step 4: Wait and Verify
|
|
437
|
+
|
|
438
|
+
**Wait approximately 3 minutes** for the worker to initialize.
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
# Check state
|
|
442
|
+
plato sandbox state
|
|
443
|
+
|
|
444
|
+
# Check containers via SSH
|
|
445
|
+
ssh -F ~/.plato/ssh_XX.conf sandbox-XX "docker ps"
|
|
446
|
+
|
|
447
|
+
# Check sandbox status
|
|
448
|
+
plato sandbox status
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## Phase 5: Test Login Flow
|
|
454
|
+
|
|
455
|
+
```bash
|
|
456
|
+
plato sandbox flow --flow-name login
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
This opens a browser and executes the flow. Watch for:
|
|
460
|
+
- Fields being filled correctly
|
|
461
|
+
- Submit button click
|
|
462
|
+
- Successful navigation to dashboard
|
|
463
|
+
|
|
464
|
+
### Debugging Login Failures
|
|
465
|
+
|
|
466
|
+
1. **Check screenshots** in the output
|
|
467
|
+
2. **Update selectors** - Use browser DevTools to find correct selectors
|
|
468
|
+
3. **Add wait steps** - The page may need more time to load
|
|
469
|
+
4. **Check containers** - Verify app is running: `docker logs {container}`
|
|
470
|
+
|
|
471
|
+
---
|
|
472
|
+
|
|
473
|
+
## Phase 6: Create Snapshot
|
|
474
|
+
|
|
475
|
+
When login works:
|
|
476
|
+
|
|
477
|
+
```bash
|
|
478
|
+
plato sandbox snapshot
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
Save the artifact ID from the output (e.g., `art_abc123`).
|
|
482
|
+
|
|
483
|
+
**CRITICAL**: Create snapshots immediately after verifying login. Sandboxes can timeout.
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
487
|
+
## Phase 7: Self-Review (5 Verification Points)
|
|
488
|
+
|
|
489
|
+
Before submitting, ALL 5 checks must pass:
|
|
490
|
+
|
|
491
|
+
### Check 1: Flow Executes Successfully
|
|
492
|
+
|
|
493
|
+
```bash
|
|
494
|
+
plato sandbox stop
|
|
495
|
+
plato sandbox start --artifact-id art_abc123
|
|
496
|
+
plato sandbox flow --flow-name login
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
Flow should complete without errors.
|
|
500
|
+
|
|
501
|
+
### Check 2: Flow Has Post-Login Verification
|
|
502
|
+
|
|
503
|
+
Your login-flow.yml MUST have a `verify` step checking for post-login elements:
|
|
504
|
+
|
|
505
|
+
```yaml
|
|
506
|
+
# REQUIRED - Verify login succeeded
|
|
507
|
+
- type: verify
|
|
508
|
+
verify_type: element_exists
|
|
509
|
+
selector: 'nav, .navbar, .sidebar, .dashboard, .user-menu'
|
|
510
|
+
description: Verify logged in
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
**NOT acceptable**: Only having screenshots without verification.
|
|
514
|
+
|
|
515
|
+
### Check 3: No Mutations After Login
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
plato sandbox state
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
Expected: Empty mutations or only ignored tables/columns.
|
|
522
|
+
|
|
523
|
+
If you see unexpected mutations:
|
|
524
|
+
- Add session/log tables to `audit_ignore_tables`
|
|
525
|
+
- Add timestamp columns to `ignore_columns`
|
|
526
|
+
|
|
527
|
+
### Check 4: Audit Ignores Configured Correctly
|
|
528
|
+
|
|
529
|
+
**Safe to ignore:**
|
|
530
|
+
- Migration tables: `migrations`, `_prisma_migrations`, `schema_migrations`
|
|
531
|
+
- Session tables: `sessions`, `user_sessions`
|
|
532
|
+
- Job tables: `jobs`, `failed_jobs`, `queue`
|
|
533
|
+
- Cache tables: `cache`, `cache_locks`
|
|
534
|
+
- Timestamp columns: `created_at`, `updated_at`, `last_login`, `last_seen`
|
|
535
|
+
|
|
536
|
+
**NOT safe to ignore:**
|
|
537
|
+
- User data tables: `users`, `accounts`, `profiles`
|
|
538
|
+
- Business data: orders, products, invoices, etc.
|
|
539
|
+
- Configuration: `settings`, `options`
|
|
540
|
+
|
|
541
|
+
### Check 5: Real Modifications Show in State
|
|
542
|
+
|
|
543
|
+
This proves the audit system works:
|
|
544
|
+
|
|
545
|
+
```bash
|
|
546
|
+
# 1. Check state is clean after login
|
|
547
|
+
plato sandbox state
|
|
548
|
+
|
|
549
|
+
# 2. Go to public URL and make a real change via UI
|
|
550
|
+
# (create contact, update setting, etc.)
|
|
551
|
+
|
|
552
|
+
# 3. Check state again - MUST show mutations now
|
|
553
|
+
plato sandbox state
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
If no mutations appear after a real change, the audit is broken.
|
|
557
|
+
|
|
558
|
+
---
|
|
559
|
+
|
|
560
|
+
## Phase 8: Submit for Review
|
|
561
|
+
|
|
562
|
+
Once all 5 self-review checks pass:
|
|
563
|
+
|
|
564
|
+
```bash
|
|
565
|
+
plato pm submit base
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
---
|
|
569
|
+
|
|
570
|
+
## Common Pitfalls & Solutions
|
|
571
|
+
|
|
572
|
+
### 1. Using `latest` or `stable` Image Tags
|
|
573
|
+
|
|
574
|
+
**Problem**: Generic tags cause unpredictable behavior.
|
|
575
|
+
|
|
576
|
+
**Solution**: Always use specific version tags:
|
|
577
|
+
```yaml
|
|
578
|
+
# BAD
|
|
579
|
+
image: myapp/myapp:latest
|
|
580
|
+
|
|
581
|
+
# GOOD
|
|
582
|
+
image: myapp/myapp:1.2.3
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
### 2. Container Name Mismatch
|
|
586
|
+
|
|
587
|
+
**Problem**: `required_healthy_containers` doesn't match actual container names.
|
|
588
|
+
|
|
589
|
+
**Solution**: Always set explicit `container_name` and use it exactly:
|
|
590
|
+
```yaml
|
|
591
|
+
# docker-compose.yml
|
|
592
|
+
services:
|
|
593
|
+
app:
|
|
594
|
+
container_name: myapp-app
|
|
595
|
+
|
|
596
|
+
# plato-config.yml
|
|
597
|
+
required_healthy_containers:
|
|
598
|
+
- myapp-app # Must match exactly
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
### 3. Using Standard Database Images
|
|
602
|
+
|
|
603
|
+
**Problem**: Standard postgres/mysql images don't work with Plato's health checks.
|
|
604
|
+
|
|
605
|
+
**Solution**: Use Plato database images:
|
|
606
|
+
```yaml
|
|
607
|
+
# BAD
|
|
608
|
+
image: postgres:15
|
|
609
|
+
|
|
610
|
+
# GOOD
|
|
611
|
+
image: public.ecr.aws/i3q4i1d7/app-sim/postgres-15-alpine:prod-latest
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
### 4. Network Mode Issues
|
|
615
|
+
|
|
616
|
+
**Problem**: Containers can't communicate.
|
|
617
|
+
|
|
618
|
+
**Solution**: All containers must use `network_mode: host`:
|
|
619
|
+
```yaml
|
|
620
|
+
services:
|
|
621
|
+
db:
|
|
622
|
+
network_mode: host
|
|
623
|
+
app:
|
|
624
|
+
network_mode: host
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
Use `127.0.0.1` for inter-container communication, not container names.
|
|
628
|
+
|
|
629
|
+
### 5. Generic Error Selectors in Flows
|
|
630
|
+
|
|
631
|
+
**Problem**: `[role="alert"]` matches non-error UI elements.
|
|
632
|
+
|
|
633
|
+
**Solution**: Verify success by looking for dashboard elements:
|
|
634
|
+
```yaml
|
|
635
|
+
# BAD
|
|
636
|
+
- type: verify_no_errors
|
|
637
|
+
error_selectors:
|
|
638
|
+
- '[role="alert"]'
|
|
639
|
+
|
|
640
|
+
# GOOD
|
|
641
|
+
- type: verify
|
|
642
|
+
verify_type: element_exists
|
|
643
|
+
selector: 'nav, .dashboard, .user-menu'
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
### 6. App on Non-80 Port
|
|
647
|
+
|
|
648
|
+
**Problem**: App runs on port 3000 but Plato expects port 80.
|
|
649
|
+
|
|
650
|
+
**Solution**: Add nginx proxy and update `required_healthy_containers`:
|
|
651
|
+
```yaml
|
|
652
|
+
required_healthy_containers:
|
|
653
|
+
- myapp-proxy # Use proxy, not app
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
### 7. Sandbox Timeout
|
|
657
|
+
|
|
658
|
+
**Problem**: SSH returns 502 or "VM shutdown due to heartbeat miss".
|
|
659
|
+
|
|
660
|
+
**Solution**: Create snapshots immediately after verifying login works. If timeout occurs:
|
|
661
|
+
```bash
|
|
662
|
+
plato sandbox stop
|
|
663
|
+
plato sandbox start --from-config
|
|
664
|
+
# Redo the workflow
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
### 8. Healthcheck Fails
|
|
668
|
+
|
|
669
|
+
**Problem**: Container healthcheck keeps failing.
|
|
670
|
+
|
|
671
|
+
**Solution**: Increase `start_period` and `retries`:
|
|
672
|
+
```yaml
|
|
673
|
+
healthcheck:
|
|
674
|
+
test: ["CMD-SHELL", "curl -f http://127.0.0.1:3000/ || exit 1"]
|
|
675
|
+
interval: 30s
|
|
676
|
+
timeout: 10s
|
|
677
|
+
retries: 15 # Increase retries
|
|
678
|
+
start_period: 180s # Increase start period
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
### 9. Database Connection Refused
|
|
682
|
+
|
|
683
|
+
**Problem**: App can't connect to database.
|
|
684
|
+
|
|
685
|
+
**Solution**: Ensure db healthcheck passes before app starts:
|
|
686
|
+
```yaml
|
|
687
|
+
app:
|
|
688
|
+
depends_on:
|
|
689
|
+
db:
|
|
690
|
+
condition: service_healthy
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
And use `127.0.0.1` not `localhost` or container name.
|
|
694
|
+
|
|
695
|
+
### 10. Missing Environment Variables
|
|
696
|
+
|
|
697
|
+
**Problem**: App fails to start due to missing config.
|
|
698
|
+
|
|
699
|
+
**Solution**: Check the app's documentation for required env vars. Common ones:
|
|
700
|
+
```yaml
|
|
701
|
+
environment:
|
|
702
|
+
SECRET_KEY: supersecretkey
|
|
703
|
+
APP_URL: http://127.0.0.1
|
|
704
|
+
TRUSTED_PROXIES: "*"
|
|
705
|
+
SESSION_DRIVER: database
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
---
|
|
709
|
+
|
|
710
|
+
## Quick Reference
|
|
711
|
+
|
|
712
|
+
### CLI Commands
|
|
713
|
+
|
|
714
|
+
| Command | Description |
|
|
715
|
+
|---------|-------------|
|
|
716
|
+
| `plato sandbox start --from-config` | Start sandbox from plato-config.yml |
|
|
717
|
+
| `plato sandbox start-services` | Sync code and start docker compose |
|
|
718
|
+
| `plato sandbox start-worker` | Start Plato worker |
|
|
719
|
+
| `plato sandbox state` | Get environment state |
|
|
720
|
+
| `plato sandbox status` | Check sandbox status |
|
|
721
|
+
| `plato sandbox flow` | Run login flow |
|
|
722
|
+
| `plato sandbox snapshot` | Create artifact |
|
|
723
|
+
| `plato sandbox stop` | Stop sandbox |
|
|
724
|
+
| `plato pm submit base` | Submit for review |
|
|
725
|
+
|
|
726
|
+
### Workflow Sequence
|
|
727
|
+
|
|
728
|
+
```bash
|
|
729
|
+
# Development
|
|
730
|
+
plato sandbox start --from-config
|
|
731
|
+
plato sandbox start-services
|
|
732
|
+
plato sandbox start-worker
|
|
733
|
+
# Wait ~3 minutes
|
|
734
|
+
plato sandbox state
|
|
735
|
+
plato sandbox flow
|
|
736
|
+
|
|
737
|
+
# Iterate (after changes)
|
|
738
|
+
plato sandbox start-services
|
|
739
|
+
plato sandbox start-worker
|
|
740
|
+
# Wait ~3 minutes
|
|
741
|
+
plato sandbox flow
|
|
742
|
+
|
|
743
|
+
# When ready
|
|
744
|
+
plato sandbox snapshot
|
|
745
|
+
|
|
746
|
+
# Self-review
|
|
747
|
+
plato sandbox stop
|
|
748
|
+
plato sandbox start --artifact-id <id>
|
|
749
|
+
plato sandbox flow
|
|
750
|
+
# Run all 5 checks
|
|
751
|
+
|
|
752
|
+
# Submit
|
|
753
|
+
plato pm submit base
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
---
|
|
757
|
+
|
|
758
|
+
## Real Examples from Production Sims
|
|
759
|
+
|
|
760
|
+
Reference these working examples at `/Users/zachplato/projects/giteasims/plato/`:
|
|
761
|
+
|
|
762
|
+
### Example 1: DocuSeal (PostgreSQL + Nginx Proxy)
|
|
763
|
+
|
|
764
|
+
**plato-config.yml:**
|
|
765
|
+
```yaml
|
|
766
|
+
service: docuseal
|
|
767
|
+
datasets:
|
|
768
|
+
base:
|
|
769
|
+
compute:
|
|
770
|
+
cpus: 1
|
|
771
|
+
memory: 2048
|
|
772
|
+
disk: 10240
|
|
773
|
+
app_port: 80
|
|
774
|
+
plato_messaging_port: 7000
|
|
775
|
+
metadata:
|
|
776
|
+
name: docuseal
|
|
777
|
+
description: Open source document signing and form filling platform
|
|
778
|
+
source_code_url: https://github.com/docusealco/docuseal
|
|
779
|
+
start_url: blank
|
|
780
|
+
license: AGPLv3
|
|
781
|
+
variables:
|
|
782
|
+
- name: username
|
|
783
|
+
value: admin@admin.com
|
|
784
|
+
- name: password
|
|
785
|
+
value: password
|
|
786
|
+
- name: wrong_password
|
|
787
|
+
value: wrongpassword
|
|
788
|
+
flows_path: base/flow.yml
|
|
789
|
+
services:
|
|
790
|
+
main_app:
|
|
791
|
+
type: docker-compose
|
|
792
|
+
file: base/docker-compose.yml
|
|
793
|
+
healthy_wait_timeout: 600
|
|
794
|
+
required_healthy_containers:
|
|
795
|
+
- app
|
|
796
|
+
- nginx
|
|
797
|
+
listeners:
|
|
798
|
+
db:
|
|
799
|
+
type: db
|
|
800
|
+
db_type: postgresql
|
|
801
|
+
db_host: 127.0.0.1
|
|
802
|
+
db_port: 5432
|
|
803
|
+
db_user: docuseal
|
|
804
|
+
db_password: docuseal
|
|
805
|
+
db_database: docuseal
|
|
806
|
+
volumes:
|
|
807
|
+
- /home/plato/db_signals:/tmp/postgres-signals
|
|
808
|
+
audit_ignore_tables:
|
|
809
|
+
- ar_internal_metadata
|
|
810
|
+
- schema_migrations
|
|
811
|
+
- webhook_attempts
|
|
812
|
+
- access_tokens
|
|
813
|
+
- oauth_access_grants
|
|
814
|
+
- oauth_access_tokens
|
|
815
|
+
- table: "*"
|
|
816
|
+
columns: [updated_at]
|
|
817
|
+
- table: "users"
|
|
818
|
+
columns: [current_sign_in_at, updated_at, sign_in_count, last_sign_in_at, last_sign_in_ip, current_sign_in_ip]
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
**docker-compose.yml:**
|
|
822
|
+
```yaml
|
|
823
|
+
services:
|
|
824
|
+
db:
|
|
825
|
+
image: public.ecr.aws/i3q4i1d7/app-sim/postgres-15-alpine:prod-latest
|
|
826
|
+
network_mode: host
|
|
827
|
+
environment:
|
|
828
|
+
POSTGRES_DB: docuseal
|
|
829
|
+
POSTGRES_USER: docuseal
|
|
830
|
+
POSTGRES_PASSWORD: docuseal
|
|
831
|
+
volumes:
|
|
832
|
+
- /home/plato/db_signals:/tmp/postgres-signals
|
|
833
|
+
healthcheck:
|
|
834
|
+
test: ["CMD-SHELL", "test -f /tmp/postgres-signals/pg.healthy"]
|
|
835
|
+
interval: 10s
|
|
836
|
+
timeout: 5s
|
|
837
|
+
retries: 3
|
|
838
|
+
start_period: 20s
|
|
839
|
+
|
|
840
|
+
app:
|
|
841
|
+
depends_on:
|
|
842
|
+
db:
|
|
843
|
+
condition: service_healthy
|
|
844
|
+
image: docuseal/docuseal:1.8.9
|
|
845
|
+
network_mode: host
|
|
846
|
+
environment:
|
|
847
|
+
- FORCE_SSL=true
|
|
848
|
+
- DATABASE_URL=postgresql://docuseal:docuseal@127.0.0.1:5432/docuseal
|
|
849
|
+
|
|
850
|
+
nginx:
|
|
851
|
+
image: nginx:alpine
|
|
852
|
+
network_mode: host
|
|
853
|
+
volumes:
|
|
854
|
+
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
|
855
|
+
depends_on:
|
|
856
|
+
- app
|
|
857
|
+
```
|
|
858
|
+
|
|
859
|
+
### Example 2: InvoiceNinja (MariaDB + Redis + Custom Nginx)
|
|
860
|
+
|
|
861
|
+
**docker-compose.yml:**
|
|
862
|
+
```yaml
|
|
863
|
+
services:
|
|
864
|
+
db:
|
|
865
|
+
image: public.ecr.aws/i3q4i1d7/app-sim/mariadb-10.6:prod-latest
|
|
866
|
+
network_mode: host
|
|
867
|
+
environment:
|
|
868
|
+
MYSQL_DATABASE: ninja
|
|
869
|
+
MYSQL_USER: ninja
|
|
870
|
+
MYSQL_PASSWORD: ninja
|
|
871
|
+
MYSQL_ROOT_PASSWORD: ninjaAdm1nPassword
|
|
872
|
+
command:
|
|
873
|
+
- --character-set-server=utf8mb4
|
|
874
|
+
- --collation-server=utf8mb4_unicode_ci
|
|
875
|
+
volumes:
|
|
876
|
+
- mysql-signals:/tmp/mysql-signals
|
|
877
|
+
healthcheck:
|
|
878
|
+
test: ["CMD-SHELL", "test -f /tmp/mysql-signals/mysql.healthy"]
|
|
879
|
+
interval: 10s
|
|
880
|
+
timeout: 5s
|
|
881
|
+
retries: 5
|
|
882
|
+
start_period: 30s
|
|
883
|
+
|
|
884
|
+
redis:
|
|
885
|
+
image: redis:7-alpine
|
|
886
|
+
network_mode: host
|
|
887
|
+
healthcheck:
|
|
888
|
+
test: ["CMD", "redis-cli", "ping"]
|
|
889
|
+
interval: 10s
|
|
890
|
+
timeout: 5s
|
|
891
|
+
retries: 5
|
|
892
|
+
|
|
893
|
+
invoiceninja:
|
|
894
|
+
image: invoiceninja/invoiceninja:5.10.29
|
|
895
|
+
network_mode: host
|
|
896
|
+
depends_on:
|
|
897
|
+
db:
|
|
898
|
+
condition: service_healthy
|
|
899
|
+
redis:
|
|
900
|
+
condition: service_healthy
|
|
901
|
+
environment:
|
|
902
|
+
APP_URL: https://sims.plato.so
|
|
903
|
+
APP_KEY: base64:OwWRRZ2Bl/dmHUrbyWIP7LQd5mTuTdbhd8RKgg0xsBM=
|
|
904
|
+
TRUSTED_PROXIES: "*"
|
|
905
|
+
CACHE_DRIVER: redis
|
|
906
|
+
QUEUE_CONNECTION: redis
|
|
907
|
+
SESSION_DRIVER: redis
|
|
908
|
+
REDIS_HOST: 127.0.0.1
|
|
909
|
+
DB_CONNECTION: mysql
|
|
910
|
+
DB_HOST: 127.0.0.1
|
|
911
|
+
DB_PORT: "3306"
|
|
912
|
+
DB_DATABASE: ninja
|
|
913
|
+
DB_USERNAME: ninja
|
|
914
|
+
DB_PASSWORD: ninja
|
|
915
|
+
IN_USER_EMAIL: admin@example.com
|
|
916
|
+
IN_PASSWORD: changeme!
|
|
917
|
+
|
|
918
|
+
invoiceninja-nginx:
|
|
919
|
+
container_name: invoiceninja-nginx
|
|
920
|
+
image: nginx:alpine
|
|
921
|
+
network_mode: host
|
|
922
|
+
depends_on:
|
|
923
|
+
invoiceninja:
|
|
924
|
+
condition: service_started
|
|
925
|
+
healthcheck:
|
|
926
|
+
test: ["CMD-SHELL", "curl -f http://127.0.0.1:8080/health"]
|
|
927
|
+
interval: 60s
|
|
928
|
+
timeout: 10s
|
|
929
|
+
retries: 10
|
|
930
|
+
start_period: 60s
|
|
931
|
+
|
|
932
|
+
volumes:
|
|
933
|
+
mysql-signals:
|
|
934
|
+
name: mysql-signals
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
### Example 3: Twenty CRM (PostgreSQL + Redis + Worker)
|
|
938
|
+
|
|
939
|
+
**docker-compose.yml:**
|
|
940
|
+
```yaml
|
|
941
|
+
services:
|
|
942
|
+
twenty-db:
|
|
943
|
+
image: public.ecr.aws/i3q4i1d7/app-sim/postgres-16-alpine:prod-latest
|
|
944
|
+
network_mode: host
|
|
945
|
+
environment:
|
|
946
|
+
POSTGRES_USER: postgres
|
|
947
|
+
POSTGRES_PASSWORD: mysecurepass123
|
|
948
|
+
volumes:
|
|
949
|
+
- postgres-signals:/tmp/postgres-signals
|
|
950
|
+
healthcheck:
|
|
951
|
+
test: ["CMD-SHELL", "test -f /tmp/postgres-signals/pg.healthy"]
|
|
952
|
+
interval: 10s
|
|
953
|
+
timeout: 5s
|
|
954
|
+
retries: 5
|
|
955
|
+
start_period: 5s
|
|
956
|
+
|
|
957
|
+
twenty-redis:
|
|
958
|
+
image: redis:7-alpine
|
|
959
|
+
network_mode: host
|
|
960
|
+
command:
|
|
961
|
+
- --maxmemory-policy
|
|
962
|
+
- noeviction
|
|
963
|
+
|
|
964
|
+
twenty-server:
|
|
965
|
+
image: twentycrm/twenty:0.32.0
|
|
966
|
+
network_mode: host
|
|
967
|
+
depends_on:
|
|
968
|
+
twenty-db:
|
|
969
|
+
condition: service_healthy
|
|
970
|
+
twenty-redis:
|
|
971
|
+
condition: service_started
|
|
972
|
+
environment:
|
|
973
|
+
NODE_PORT: 3000
|
|
974
|
+
PG_DATABASE_URL: postgres://postgres:mysecurepass123@localhost:5432/default
|
|
975
|
+
SERVER_URL: https://twenty.com
|
|
976
|
+
REDIS_URL: redis://127.0.0.1:6379
|
|
977
|
+
APP_SECRET: twenty
|
|
978
|
+
healthcheck:
|
|
979
|
+
test: ["CMD-SHELL", "curl -f http://localhost:3000/healthz || exit 1"]
|
|
980
|
+
interval: 5s
|
|
981
|
+
timeout: 5s
|
|
982
|
+
retries: 9
|
|
983
|
+
start_period: 10s
|
|
984
|
+
|
|
985
|
+
twenty-worker:
|
|
986
|
+
image: twentycrm/twenty:0.32.0
|
|
987
|
+
network_mode: host
|
|
988
|
+
depends_on:
|
|
989
|
+
twenty-server:
|
|
990
|
+
condition: service_healthy
|
|
991
|
+
command: ["yarn", "worker:prod"]
|
|
992
|
+
environment:
|
|
993
|
+
PG_DATABASE_URL: postgres://postgres:mysecurepass123@127.0.0.1:5432/default
|
|
994
|
+
REDIS_URL: redis://127.0.0.1:6379
|
|
995
|
+
APP_SECRET: twenty
|
|
996
|
+
|
|
997
|
+
volumes:
|
|
998
|
+
postgres-signals:
|
|
999
|
+
name: postgres-signals
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
### Example 4: Login Flow (DocuSeal)
|
|
1003
|
+
|
|
1004
|
+
**flow.yml:**
|
|
1005
|
+
```yaml
|
|
1006
|
+
flows:
|
|
1007
|
+
- name: login
|
|
1008
|
+
description: Standard login flow for DocuSeal
|
|
1009
|
+
steps:
|
|
1010
|
+
- type: screenshot
|
|
1011
|
+
filename: 01_before_login.png
|
|
1012
|
+
description: Screenshot before login
|
|
1013
|
+
|
|
1014
|
+
- type: wait
|
|
1015
|
+
duration: 5000
|
|
1016
|
+
description: Wait for page to fully load
|
|
1017
|
+
|
|
1018
|
+
- type: click
|
|
1019
|
+
selector: 'a[href*="sign_in"], a:has-text("Sign In")'
|
|
1020
|
+
description: Click Sign In button
|
|
1021
|
+
|
|
1022
|
+
- type: wait
|
|
1023
|
+
duration: 3000
|
|
1024
|
+
description: Wait for login form
|
|
1025
|
+
|
|
1026
|
+
- type: wait_for_selector
|
|
1027
|
+
selector: 'input[type="email"], input[name="email"]'
|
|
1028
|
+
timeout: 15000
|
|
1029
|
+
description: Wait for email field
|
|
1030
|
+
|
|
1031
|
+
- type: fill
|
|
1032
|
+
selector: 'input[type="email"], input[name="email"]'
|
|
1033
|
+
value: admin@admin.com
|
|
1034
|
+
description: Fill email field
|
|
1035
|
+
|
|
1036
|
+
- type: fill
|
|
1037
|
+
selector: 'input[type="password"], input[name="password"]'
|
|
1038
|
+
value: password
|
|
1039
|
+
description: Fill password field
|
|
1040
|
+
|
|
1041
|
+
- type: screenshot
|
|
1042
|
+
filename: 02_credentials_entered.png
|
|
1043
|
+
description: Screenshot credentials entered
|
|
1044
|
+
|
|
1045
|
+
- type: click
|
|
1046
|
+
selector: 'button[type="submit"], input[type="submit"]'
|
|
1047
|
+
description: Click submit
|
|
1048
|
+
|
|
1049
|
+
- type: wait
|
|
1050
|
+
duration: 5000
|
|
1051
|
+
description: Wait for login to process
|
|
1052
|
+
|
|
1053
|
+
- type: screenshot
|
|
1054
|
+
filename: 03_after_login.png
|
|
1055
|
+
description: Screenshot after login
|
|
1056
|
+
|
|
1057
|
+
- type: verify
|
|
1058
|
+
verify_type: element_exists
|
|
1059
|
+
selector: 'h1:has-text("Document Templates"), button:has-text("CREATE"), a:has-text("Settings")'
|
|
1060
|
+
description: Verify DocuSeal dashboard elements are present
|
|
1061
|
+
```
|
|
1062
|
+
|
|
1063
|
+
---
|
|
1064
|
+
|
|
1065
|
+
## Checklist
|
|
1066
|
+
|
|
1067
|
+
### Pre-flight
|
|
1068
|
+
- [ ] Sim name follows rules (lowercase letters and underscores only)
|
|
1069
|
+
- [ ] Database is PostgreSQL, MySQL, or MariaDB (NOT MongoDB/SQLite/Redis)
|
|
1070
|
+
- [ ] Found specific version tag for app Docker image
|
|
1071
|
+
|
|
1072
|
+
### Docker Setup
|
|
1073
|
+
- [ ] Using Plato database images (not standard postgres/mysql)
|
|
1074
|
+
- [ ] All containers use `network_mode: host`
|
|
1075
|
+
- [ ] All containers have explicit `container_name`
|
|
1076
|
+
- [ ] Health checks use signal files for DB
|
|
1077
|
+
- [ ] App image uses version tag (not `latest`/`stable`)
|
|
1078
|
+
|
|
1079
|
+
### Configuration
|
|
1080
|
+
- [ ] `required_healthy_containers` matches container names exactly
|
|
1081
|
+
- [ ] `app_port` is 80 (use nginx proxy if app runs on different port)
|
|
1082
|
+
- [ ] Login credentials in `metadata.variables`
|
|
1083
|
+
- [ ] `flows_path` points to login flow file
|
|
1084
|
+
|
|
1085
|
+
### Testing
|
|
1086
|
+
- [ ] `plato sandbox start --from-config` succeeds
|
|
1087
|
+
- [ ] `plato sandbox start-services` succeeds
|
|
1088
|
+
- [ ] `plato sandbox start-worker` succeeds
|
|
1089
|
+
- [ ] Waited ~3 minutes after start-worker
|
|
1090
|
+
- [ ] `plato sandbox state` shows ready
|
|
1091
|
+
- [ ] `plato sandbox flow` login succeeds
|
|
1092
|
+
- [ ] `plato sandbox snapshot` creates artifact
|
|
1093
|
+
|
|
1094
|
+
### Self-Review (5 Checks)
|
|
1095
|
+
- [ ] Started fresh from artifact
|
|
1096
|
+
- [ ] **Check 1**: Flow executes successfully
|
|
1097
|
+
- [ ] **Check 2**: Flow has `verify` step for post-login elements
|
|
1098
|
+
- [ ] **Check 3**: `plato sandbox state` shows no mutations after login
|
|
1099
|
+
- [ ] **Check 4**: Audit ignores only timestamps/sessions/migrations
|
|
1100
|
+
- [ ] **Check 5**: Making a real UI change DOES show mutations in `state`
|
|
1101
|
+
- [ ] Ready to submit: `plato pm submit base`
|