From 4b09ce30966f06350cb15cd54b3d80484fece88c Mon Sep 17 00:00:00 2001 From: Linghong Date: Tue, 16 Jun 2026 17:31:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=20Editor=20Agent=20Mock=20Ag?= =?UTF-8?q?ent=20P1=20=E6=94=B6=E5=B0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 接入 Web Project 契约、SpacetimeDB 表与 api-server 控制面 新增 Mock Agent、静态构建 runner 与独立预览网关 补齐 /editor/agent 前端页面、服务客户端和 SSE 订阅 修复 sandbox 预览资源跨域加载并补充并发保护 接入本地 dev 预览端口漂移与服务身份初始化 更新 P1 技术方案、验收清单和 Hermes 共享记忆 --- .hermes/shared-memory/development-workflow.md | 4 +- .hermes/shared-memory/pitfalls.md | 8 + .../SKILL.md | 27 +- docs/README.md | 2 +- docs/planning/README.md | 1 + ...itorAgentMockAgentP1可执行开发计划-2026-06-15.md | 641 +++++++ ...】EditorAgentMockAgentP1落地计划-2026-06-15.md | 46 +- ...案】WebProjectRunnerP1实现补充-2026-06-15.md | 61 + ...例】AIWeb工程静态预览MVP验收清单-2026-06-13.md | 6 + ...】server-rs与SpacetimeDB数据契约-2026-05-15.md | 20 + ...发运维】本地开发验证与生产运维-2026-05-15.md | 5 +- packages/shared/src/contracts/webProject.ts | 110 ++ packages/shared/src/index.ts | 1 + scripts/dev-stack-port-utils.mjs | 6 +- scripts/dev-stack-port-utils.test.ts | 7 +- scripts/dev.mjs | 417 ++++- scripts/dev.test.ts | 208 ++- server-rs/Cargo.lock | 10 + server-rs/Cargo.toml | 2 + server-rs/crates/api-server/Cargo.toml | 1 + server-rs/crates/api-server/src/app.rs | 1 + server-rs/crates/api-server/src/config.rs | 59 + .../crates/api-server/src/editor_project.rs | 15 +- .../src/external_generation_worker.rs | 1 + server-rs/crates/api-server/src/main.rs | 39 + server-rs/crates/api-server/src/modules.rs | 1 + .../api-server/src/modules/editor_project.rs | 8 +- .../api-server/src/modules/web_project.rs | 72 + server-rs/crates/api-server/src/state.rs | 92 +- .../crates/api-server/src/web_project.rs | 1091 +++++++++++ .../api-server/src/web_project_mock_agent.rs | 248 +++ .../src/web_project_preview_gateway.rs | 283 +++ .../src/generated_asset_sheets/alpha.rs | 21 +- server-rs/crates/shared-contracts/src/lib.rs | 1 + .../shared-contracts/src/web_project.rs | 139 ++ .../spacetime-client/src/editor_project.rs | 78 +- server-rs/crates/spacetime-client/src/lib.rs | 21 +- .../crates/spacetime-client/src/mapper.rs | 41 +- .../src/mapper/editor_project.rs | 6 +- .../src/mapper/web_project.rs | 383 ++++ .../spacetime-client/src/module_bindings.rs | 175 +- .../module_bindings/accept_quest_reducer.rs | 16 +- .../acknowledge_quest_completion_reducer.rs | 16 +- ...n_disable_profile_redeem_code_procedure.rs | 16 +- ...n_disable_profile_task_config_procedure.rs | 16 +- ...min_list_profile_invite_codes_procedure.rs | 16 +- ...ist_profile_recharge_products_procedure.rs | 16 +- ...min_list_profile_redeem_codes_procedure.rs | 16 +- ...min_list_profile_task_configs_procedure.rs | 16 +- .../admin_list_work_visibility_procedure.rs | 16 +- .../admin_update_work_visibility_procedure.rs | 16 +- ...in_upsert_profile_invite_code_procedure.rs | 16 +- ...sert_profile_recharge_product_procedure.rs | 16 +- ...in_upsert_profile_redeem_code_procedure.rs | 16 +- ...in_upsert_profile_task_config_procedure.rs | 16 +- ...vance_puzzle_clear_next_level_procedure.rs | 16 +- .../advance_puzzle_next_level_procedure.rs | 16 +- ...pend_ai_text_chunk_and_return_procedure.rs | 16 +- ...l_novel_runtime_history_entry_procedure.rs | 16 +- ...ssion_ledger_entry_and_return_procedure.rs | 16 +- ...hapter_progression_ledger_entry_reducer.rs | 16 +- .../apply_inventory_mutation_reducer.rs | 16 +- .../apply_quest_signal_reducer.rs | 16 +- ...i_result_reference_and_return_procedure.rs | 16 +- ...e_database_migration_operator_procedure.rs | 16 +- ..._web_project_service_identity_procedure.rs | 62 + ...egin_story_session_and_return_procedure.rs | 16 +- .../begin_story_session_reducer.rs | 16 +- ...t_object_to_entity_and_return_procedure.rs | 16 +- .../bind_asset_object_to_entity_reducer.rs | 16 +- .../cancel_ai_task_and_return_procedure.rs | 16 +- .../checkpoint_wooden_fish_run_procedure.rs | 16 +- ...al_generation_jobs_and_return_procedure.rs | 16 +- ...rofile_task_reward_and_return_procedure.rs | 16 +- ...uzzle_background_compile_task_procedure.rs | 16 +- ...m_puzzle_work_point_incentive_procedure.rs | 16 +- ...abase_migration_import_chunks_procedure.rs | 16 +- ...orm_browse_history_and_return_procedure.rs | 16 +- .../click_match_3_d_item_procedure.rs | 16 +- .../compile_big_fish_draft_procedure.rs | 16 +- ...ustom_world_published_profile_procedure.rs | 16 +- .../compile_jump_hop_draft_procedure.rs | 16 +- .../compile_match_3_d_draft_procedure.rs | 16 +- .../compile_puzzle_agent_draft_procedure.rs | 16 +- .../compile_puzzle_clear_draft_procedure.rs | 16 +- .../compile_square_hole_draft_procedure.rs | 16 +- ...ile_visual_novel_work_profile_procedure.rs | 16 +- .../compile_wooden_fish_draft_procedure.rs | 16 +- .../complete_ai_stage_and_return_procedure.rs | 16 +- .../complete_ai_task_and_return_procedure.rs | 16 +- ...nal_generation_job_and_return_procedure.rs | 16 +- ...nfirm_asset_object_and_return_procedure.rs | 16 +- .../confirm_asset_object_reducer.rs | 16 +- ...file_wallet_points_and_return_procedure.rs | 16 +- .../continue_story_and_return_procedure.rs | 16 +- .../module_bindings/continue_story_reducer.rs | 16 +- .../create_ai_task_and_return_procedure.rs | 16 +- .../module_bindings/create_ai_task_reducer.rs | 16 +- .../create_bark_battle_draft_procedure.rs | 16 +- ...reate_battle_state_and_return_procedure.rs | 16 +- .../create_battle_state_reducer.rs | 16 +- .../create_big_fish_session_procedure.rs | 16 +- ...te_custom_world_agent_session_procedure.rs | 16 +- ...reate_editor_asset_and_return_procedure.rs | 16 +- ...ditor_asset_folder_and_return_procedure.rs | 16 +- ...ate_editor_project_and_return_procedure.rs | 16 +- ...r_project_resource_and_return_procedure.rs | 16 +- ...create_jump_hop_agent_session_procedure.rs | 16 +- ...reate_match_3_d_agent_session_procedure.rs | 16 +- ...ile_recharge_order_and_return_procedure.rs | 16 +- .../create_puzzle_agent_session_procedure.rs | 16 +- ...te_puzzle_clear_agent_session_procedure.rs | 16 +- ...ate_square_hole_agent_session_procedure.rs | 16 +- ...te_visual_novel_agent_session_procedure.rs | 16 +- ...create_web_project_and_return_procedure.rs | 59 + ...ject_preview_build_and_return_procedure.rs | 62 + ...ate_wooden_fish_agent_session_procedure.rs | 16 +- .../delete_bark_battle_work_procedure.rs | 16 +- .../delete_big_fish_work_procedure.rs | 16 +- ...te_custom_world_agent_session_procedure.rs | 16 +- ...stom_world_profile_and_return_procedure.rs | 16 +- ...elete_editor_asset_and_return_procedure.rs | 16 +- ...ditor_asset_folder_and_return_procedure.rs | 16 +- ...ete_editor_project_and_return_procedure.rs | 16 +- .../delete_jump_hop_work_procedure.rs | 16 +- .../delete_match_3_d_work_procedure.rs | 16 +- .../delete_puzzle_work_procedure.rs | 16 +- ...e_runtime_snapshot_and_return_procedure.rs | 16 +- .../delete_square_hole_work_procedure.rs | 16 +- .../delete_visual_novel_work_procedure.rs | 16 +- .../delete_wooden_fish_work_procedure.rs | 16 +- .../drag_puzzle_piece_or_group_procedure.rs | 16 +- .../drop_square_hole_shape_procedure.rs | 16 +- ...nal_generation_job_and_return_procedure.rs | 16 +- ...alytics_date_dimension_for_date_reducer.rs | 16 +- ...ute_custom_world_agent_action_procedure.rs | 16 +- ...th_store_snapshot_from_tables_procedure.rs | 16 +- ...rt_database_migration_to_file_procedure.rs | 16 +- .../fail_ai_task_and_return_procedure.rs | 16 +- ...nal_generation_job_and_return_procedure.rs | 16 +- ...e_big_fish_agent_message_turn_procedure.rs | 16 +- ...stom_world_agent_message_turn_procedure.rs | 16 +- ..._match_3_d_agent_message_turn_procedure.rs | 16 +- ...ize_puzzle_agent_message_turn_procedure.rs | 16 +- ...quare_hole_agent_message_turn_procedure.rs | 16 +- ...sual_novel_agent_message_turn_procedure.rs | 16 +- .../finish_bark_battle_run_procedure.rs | 16 +- .../finish_match_3_d_time_up_procedure.rs | 16 +- .../finish_square_hole_time_up_procedure.rs | 16 +- .../finish_wooden_fish_run_procedure.rs | 16 +- .../generate_big_fish_asset_procedure.rs | 16 +- .../get_bark_battle_run_procedure.rs | 16 +- ...et_bark_battle_runtime_config_procedure.rs | 16 +- .../get_battle_state_procedure.rs | 16 +- .../get_big_fish_run_procedure.rs | 16 +- .../get_big_fish_session_procedure.rs | 16 +- .../get_chapter_progression_procedure.rs | 16 +- .../get_creation_entry_config_procedure.rs | 16 +- ...ustom_world_agent_card_detail_procedure.rs | 16 +- ..._custom_world_agent_operation_procedure.rs | 16 +- ...et_custom_world_agent_session_procedure.rs | 16 +- ..._world_gallery_detail_by_code_procedure.rs | 16 +- ...t_custom_world_gallery_detail_procedure.rs | 16 +- ...t_custom_world_library_detail_procedure.rs | 16 +- ...itor_asset_library_and_return_procedure.rs | 16 +- ...get_editor_project_and_return_procedure.rs | 16 +- ...nal_generation_job_and_return_procedure.rs | 16 +- ...ration_queue_stats_and_return_procedure.rs | 16 +- .../get_jump_hop_agent_session_procedure.rs | 16 +- .../get_jump_hop_leaderboard_procedure.rs | 16 +- .../get_jump_hop_run_procedure.rs | 16 +- .../get_jump_hop_work_profile_procedure.rs | 16 +- .../get_match_3_d_agent_session_procedure.rs | 16 +- .../get_match_3_d_run_procedure.rs | 16 +- .../get_match_3_d_work_detail_procedure.rs | 16 +- ...player_progression_or_default_procedure.rs | 16 +- .../get_profile_dashboard_procedure.rs | 16 +- .../get_profile_play_stats_procedure.rs | 16 +- .../get_profile_recharge_center_procedure.rs | 16 +- ...ile_recharge_order_and_return_procedure.rs | 16 +- ...rofile_referral_invite_center_procedure.rs | 16 +- .../get_profile_task_center_procedure.rs | 16 +- .../get_puzzle_agent_session_procedure.rs | 16 +- ...et_puzzle_clear_agent_session_procedure.rs | 16 +- .../get_puzzle_clear_runtime_run_procedure.rs | 16 +- ...get_puzzle_clear_work_profile_procedure.rs | 16 +- .../get_puzzle_gallery_detail_procedure.rs | 16 +- .../get_puzzle_run_procedure.rs | 16 +- .../get_puzzle_work_detail_procedure.rs | 16 +- ...ent_editor_project_and_return_procedure.rs | 16 +- .../get_runtime_inventory_state_procedure.rs | 16 +- ...et_runtime_setting_or_default_procedure.rs | 16 +- .../get_runtime_snapshot_procedure.rs | 16 +- ...get_square_hole_agent_session_procedure.rs | 16 +- .../get_square_hole_run_procedure.rs | 16 +- .../get_square_hole_work_detail_procedure.rs | 16 +- .../get_story_session_state_procedure.rs | 16 +- ...et_visual_novel_agent_session_procedure.rs | 16 +- .../get_visual_novel_run_procedure.rs | 16 +- .../get_visual_novel_work_detail_procedure.rs | 16 +- .../get_web_project_and_return_procedure.rs | 59 + ...ject_preview_build_and_return_procedure.rs | 59 + ...iew_build_by_token_and_return_procedure.rs | 62 + ...b_project_snapshot_and_return_procedure.rs | 59 + ...get_wooden_fish_agent_session_procedure.rs | 16 +- .../get_wooden_fish_run_procedure.rs | 16 +- .../get_wooden_fish_work_profile_procedure.rs | 16 +- ...er_registration_wallet_reward_procedure.rs | 16 +- ...ression_experience_and_return_procedure.rs | 16 +- ...t_player_progression_experience_reducer.rs | 16 +- ...port_auth_store_snapshot_json_procedure.rs | 16 +- ...atabase_migration_from_chunks_procedure.rs | 16 +- ..._database_migration_from_file_procedure.rs | 16 +- ...ation_incremental_from_chunks_procedure.rs | 16 +- ...gration_incremental_from_file_procedure.rs | 16 +- .../jump_hop_jump_procedure.rs | 16 +- ...list_asset_history_and_return_procedure.rs | 16 +- .../list_big_fish_works_procedure.rs | 16 +- ..._custom_world_gallery_entries_procedure.rs | 16 +- .../list_custom_world_profiles_procedure.rs | 16 +- .../list_custom_world_works_procedure.rs | 16 +- ...st_editor_projects_and_return_procedure.rs | 16 +- .../list_jump_hop_works_procedure.rs | 16 +- .../list_match_3_d_works_procedure.rs | 16 +- .../list_platform_browse_history_procedure.rs | 16 +- .../list_profile_save_archives_procedure.rs | 16 +- .../list_profile_wallet_ledger_procedure.rs | 16 +- .../list_puzzle_clear_works_procedure.rs | 16 +- .../list_puzzle_gallery_procedure.rs | 16 +- .../list_puzzle_works_procedure.rs | 16 +- .../list_square_hole_works_procedure.rs | 16 +- ..._visual_novel_runtime_history_procedure.rs | 16 +- .../list_visual_novel_works_procedure.rs | 16 +- .../list_wooden_fish_works_procedure.rs | 16 +- ...echarge_order_paid_and_return_procedure.rs | 16 +- ...rk_puzzle_clear_level_time_up_procedure.rs | 16 +- ...uzzle_draft_generation_failed_procedure.rs | 16 +- ...uzzle_level_generation_failed_procedure.rs | 16 +- .../public_work_play_daily_stat_table.rs | 2 +- .../publish_bark_battle_work_procedure.rs | 16 +- .../publish_big_fish_game_procedure.rs | 16 +- ...stom_world_profile_and_return_procedure.rs | 16 +- .../publish_custom_world_profile_reducer.rs | 16 +- .../publish_custom_world_world_procedure.rs | 16 +- .../publish_jump_hop_work_procedure.rs | 16 +- .../publish_match_3_d_work_procedure.rs | 16 +- .../publish_puzzle_clear_work_procedure.rs | 16 +- .../publish_puzzle_work_procedure.rs | 16 +- .../publish_square_hole_work_procedure.rs | 16 +- .../publish_visual_novel_work_procedure.rs | 16 +- .../publish_wooden_fish_work_procedure.rs | 16 +- ...tabase_migration_import_chunk_procedure.rs | 16 +- .../puzzle_clear_gallery_view_table.rs | 2 +- .../puzzle_clear_work_profile_table.rs | 2 +- .../query_analytics_metric_procedure.rs | 16 +- .../record_big_fish_like_procedure.rs | 16 +- .../record_big_fish_play_procedure.rs | 16 +- ...ord_custom_world_profile_like_procedure.rs | 16 +- ...ord_custom_world_profile_play_procedure.rs | 16 +- ...gin_tracking_event_and_return_procedure.rs | 16 +- .../record_puzzle_work_like_procedure.rs | 16 +- ...ord_tracking_event_and_return_procedure.rs | 16 +- ...rd_tracking_events_and_return_procedure.rs | 16 +- ...rd_visual_novel_runtime_event_procedure.rs | 16 +- ..._profile_referral_invite_code_procedure.rs | 16 +- .../redeem_profile_reward_code_procedure.rs | 16 +- ...file_wallet_points_and_return_procedure.rs | 16 +- ...uzzle_background_compile_task_procedure.rs | 16 +- .../remix_big_fish_work_procedure.rs | 16 +- .../remix_custom_world_profile_procedure.rs | 16 +- .../remix_puzzle_work_procedure.rs | 16 +- ...ame_editor_project_and_return_procedure.rs | 16 +- ...neration_job_lease_and_return_procedure.rs | 16 +- ...olve_combat_action_and_return_procedure.rs | 16 +- .../resolve_combat_action_reducer.rs | 16 +- ...battle_interaction_and_return_procedure.rs | 16 +- ...ve_npc_interaction_and_return_procedure.rs | 16 +- .../resolve_npc_interaction_reducer.rs | 16 +- ..._npc_social_action_and_return_procedure.rs | 16 +- .../resolve_npc_social_action_reducer.rs | 16 +- ...easure_interaction_and_return_procedure.rs | 16 +- .../resolve_treasure_interaction_reducer.rs | 16 +- .../restart_jump_hop_run_procedure.rs | 16 +- .../restart_match_3_d_run_procedure.rs | 16 +- .../restart_square_hole_run_procedure.rs | 16 +- ...ofile_save_archive_and_return_procedure.rs | 16 +- .../retry_puzzle_clear_level_run_procedure.rs | 16 +- ...e_database_migration_operator_procedure.rs | 16 +- ..._web_project_service_identity_procedure.rs | 59 + ...tor_project_layout_and_return_procedure.rs | 16 +- .../save_puzzle_form_draft_procedure.rs | 16 +- .../save_puzzle_generated_images_procedure.rs | 16 +- .../save_puzzle_ui_background_procedure.rs | 16 +- ...b_project_snapshot_and_return_procedure.rs | 59 + .../seed_analytics_date_dimensions_reducer.rs | 16 +- .../select_puzzle_cover_image_procedure.rs | 16 +- .../square_hole_agent_message_table.rs | 2 +- .../square_hole_agent_session_table.rs | 2 +- .../module_bindings/start_ai_task_reducer.rs | 16 +- .../start_ai_task_stage_reducer.rs | 16 +- .../start_bark_battle_run_procedure.rs | 16 +- .../start_big_fish_run_procedure.rs | 16 +- .../start_jump_hop_run_procedure.rs | 16 +- .../start_match_3_d_run_procedure.rs | 16 +- ...tart_puzzle_clear_runtime_run_procedure.rs | 16 +- .../start_puzzle_run_procedure.rs | 16 +- .../start_square_hole_run_procedure.rs | 16 +- .../start_visual_novel_run_procedure.rs | 16 +- .../start_wooden_fish_run_procedure.rs | 16 +- .../stop_match_3_d_run_procedure.rs | 16 +- .../stop_square_hole_run_procedure.rs | 16 +- .../submit_big_fish_input_procedure.rs | 16 +- .../submit_big_fish_message_procedure.rs | 16 +- ...it_custom_world_agent_message_procedure.rs | 16 +- ...ubmit_match_3_d_agent_message_procedure.rs | 16 +- ...t_profile_feedback_and_return_procedure.rs | 16 +- .../submit_puzzle_agent_message_procedure.rs | 16 +- ...bmit_puzzle_leaderboard_entry_procedure.rs | 16 +- ...mit_square_hole_agent_message_procedure.rs | 16 +- ...it_visual_novel_agent_message_procedure.rs | 16 +- .../swap_puzzle_clear_cards_procedure.rs | 16 +- .../swap_puzzle_pieces_procedure.rs | 16 +- .../module_bindings/turn_in_quest_reducer.rs | 16 +- ...stom_world_profile_and_return_procedure.rs | 16 +- .../unpublish_custom_world_profile_reducer.rs | 16 +- ...date_bark_battle_draft_config_procedure.rs | 16 +- ...pdate_editor_asset_and_return_procedure.rs | 16 +- ...ditor_asset_folder_and_return_procedure.rs | 16 +- .../update_jump_hop_work_procedure.rs | 16 +- .../update_match_3_d_work_procedure.rs | 16 +- .../update_puzzle_clear_work_procedure.rs | 16 +- .../update_puzzle_run_pause_procedure.rs | 16 +- .../update_puzzle_work_procedure.rs | 16 +- .../update_square_hole_work_procedure.rs | 16 +- .../update_visual_novel_work_procedure.rs | 16 +- ...ject_preview_build_and_return_procedure.rs | 62 + .../update_wooden_fish_work_procedure.rs | 16 +- ...hapter_progression_and_return_procedure.rs | 16 +- .../upsert_chapter_progression_reducer.rs | 16 +- ...on_entry_event_banners_config_procedure.rs | 16 +- ...rt_creation_entry_type_config_procedure.rs | 16 +- ...orld_agent_operation_progress_procedure.rs | 16 +- ...stom_world_profile_and_return_procedure.rs | 16 +- .../upsert_custom_world_profile_reducer.rs | 16 +- .../upsert_npc_state_and_return_procedure.rs | 16 +- .../upsert_npc_state_reducer.rs | 16 +- ...orm_browse_history_and_return_procedure.rs | 16 +- ...ublic_work_interaction_config_procedure.rs | 16 +- ...rt_runtime_setting_and_return_procedure.rs | 16 +- ...t_runtime_snapshot_and_return_procedure.rs | 16 +- ...ert_visual_novel_run_snapshot_procedure.rs | 16 +- .../use_puzzle_runtime_prop_procedure.rs | 16 +- .../visual_novel_gallery_view_table.rs | 2 +- .../visual_novel_work_profile_table.rs | 2 +- .../web_project_create_input_type.rs | 22 + .../web_project_file_snapshot_type.rs | 19 + .../web_project_get_input_type.rs | 16 + ...project_preview_build_create_input_type.rs | 19 + ...eb_project_preview_build_get_input_type.rs | 16 + ...ect_preview_build_procedure_result_type.rs | 21 + .../web_project_preview_build_row_type.rs | 96 + ...web_project_preview_build_snapshot_type.rs | 28 + .../web_project_preview_build_table.rs | 165 ++ ...ject_preview_build_token_get_input_type.rs | 15 + ...project_preview_build_update_input_type.rs | 25 + .../web_project_procedure_result_type.rs | 19 + .../web_project_project_snapshot_type.rs | 22 + ...t_service_identity_authorize_input_type.rs | 17 + ..._service_identity_procedure_result_type.rs | 17 + ...ject_service_identity_revoke_input_type.rs | 15 + .../web_project_service_identity_table.rs | 169 ++ .../web_project_service_identity_type.rs | 58 + .../web_project_snapshot_get_input_type.rs | 17 + ..._project_snapshot_procedure_result_type.rs | 21 + .../web_project_snapshot_row_type.rs | 77 + .../web_project_snapshot_save_input_type.rs | 24 + .../web_project_snapshot_table.rs | 161 ++ .../web_project_snapshot_type.rs | 25 + .../src/module_bindings/web_project_table.rs | 159 ++ .../src/module_bindings/web_project_type.rs | 75 + .../wooden_fish_agent_session_table.rs | 2 +- .../spacetime-client/src/web_project.rs | 193 ++ .../src/editor_project_storage.rs | 38 +- server-rs/crates/spacetime-module/src/lib.rs | 3 + .../crates/spacetime-module/src/migration.rs | 5 + .../spacetime-module/src/web_project.rs | 1152 ++++++++++++ .../crates/web-project-runner/Cargo.toml | 10 + .../crates/web-project-runner/src/lib.rs | 1136 ++++++++++++ .../crates/web-project-runner/src/main.rs | 12 + .../react-vite-ts-static/package-lock.json | 1589 +++++++++++++++++ .../react-vite-ts-static/package.json | 14 + src/App.tsx | 5 +- .../agent/WebProjectAgentEditorPage.test.tsx | 363 ++++ .../agent/WebProjectAgentEditorPage.tsx | 949 ++++++++++ .../agent/webProjectAgentViewModel.test.ts | 128 ++ .../editor/agent/webProjectAgentViewModel.ts | 134 ++ .../PlatformEntryFlowShellImpl.tsx | 28 +- .../platform-entry/platformEntryTypes.ts | 1 + .../platformSelectionStageModel.ts | 1 + src/routing/appPageRoutes.ts | 1 + .../web-project/webProjectClient.test.ts | 221 +++ src/services/web-project/webProjectClient.ts | 139 ++ .../web-project/webProjectSse.test.ts | 105 ++ src/services/web-project/webProjectSse.ts | 126 ++ 404 files changed, 14886 insertions(+), 2497 deletions(-) create mode 100644 docs/planning/【开发计划】EditorAgentMockAgentP1可执行开发计划-2026-06-15.md create mode 100644 docs/technical/【技术方案】WebProjectRunnerP1实现补充-2026-06-15.md create mode 100644 packages/shared/src/contracts/webProject.ts create mode 100644 server-rs/crates/api-server/src/modules/web_project.rs create mode 100644 server-rs/crates/api-server/src/web_project.rs create mode 100644 server-rs/crates/api-server/src/web_project_mock_agent.rs create mode 100644 server-rs/crates/api-server/src/web_project_preview_gateway.rs create mode 100644 server-rs/crates/shared-contracts/src/web_project.rs create mode 100644 server-rs/crates/spacetime-client/src/mapper/web_project.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/authorize_web_project_service_identity_procedure.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/create_web_project_and_return_procedure.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/create_web_project_preview_build_and_return_procedure.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/get_web_project_and_return_procedure.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/get_web_project_preview_build_and_return_procedure.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/get_web_project_preview_build_by_token_and_return_procedure.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/get_web_project_snapshot_and_return_procedure.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/revoke_web_project_service_identity_procedure.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/save_web_project_snapshot_and_return_procedure.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/update_web_project_preview_build_and_return_procedure.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_create_input_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_file_snapshot_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_get_input_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_preview_build_create_input_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_preview_build_get_input_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_preview_build_procedure_result_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_preview_build_row_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_preview_build_snapshot_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_preview_build_table.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_preview_build_token_get_input_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_preview_build_update_input_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_procedure_result_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_project_snapshot_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_service_identity_authorize_input_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_service_identity_procedure_result_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_service_identity_revoke_input_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_service_identity_table.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_service_identity_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_snapshot_get_input_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_snapshot_procedure_result_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_snapshot_row_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_snapshot_save_input_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_snapshot_table.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_snapshot_type.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_table.rs create mode 100644 server-rs/crates/spacetime-client/src/module_bindings/web_project_type.rs create mode 100644 server-rs/crates/spacetime-client/src/web_project.rs create mode 100644 server-rs/crates/spacetime-module/src/web_project.rs create mode 100644 server-rs/crates/web-project-runner/Cargo.toml create mode 100644 server-rs/crates/web-project-runner/src/lib.rs create mode 100644 server-rs/crates/web-project-runner/src/main.rs create mode 100644 server-rs/crates/web-project-runner/templates/react-vite-ts-static/package-lock.json create mode 100644 server-rs/crates/web-project-runner/templates/react-vite-ts-static/package.json create mode 100644 src/components/editor/agent/WebProjectAgentEditorPage.test.tsx create mode 100644 src/components/editor/agent/WebProjectAgentEditorPage.tsx create mode 100644 src/components/editor/agent/webProjectAgentViewModel.test.ts create mode 100644 src/components/editor/agent/webProjectAgentViewModel.ts create mode 100644 src/services/web-project/webProjectClient.test.ts create mode 100644 src/services/web-project/webProjectClient.ts create mode 100644 src/services/web-project/webProjectSse.test.ts create mode 100644 src/services/web-project/webProjectSse.ts diff --git a/.hermes/shared-memory/development-workflow.md b/.hermes/shared-memory/development-workflow.md index ca86734c..c782c838 100644 --- a/.hermes/shared-memory/development-workflow.md +++ b/.hermes/shared-memory/development-workflow.md @@ -50,7 +50,7 @@ npm install npm run dev ``` -Linux 多用户共享同一台机器开发时,本地 dev 脚本会为当前 Linux 用户分配一个固定端口段并写入系统级注册表 `/var/tmp/genarrative-dev-port-ranges/registry.json`,自动分配从 `10000-10099` 开始,每段 100 个端口,四个 dev 服务依次使用 `start` 到 `start + 3`。可用 `GENARRATIVE_DEV_PORT_RANGE` 或 `npm run dev -- --port-range` 手动指定端口段用于特殊场景;注册表会阻止不同用户使用相同或重叠段,并让同一用户后续启动继续复用自己已占用的固定段。该机制只在 Linux 生效,Windows 仍沿用原有端口探测与漂移逻辑。 +Linux 多用户共享同一台机器开发时,本地 dev 脚本会为当前 Linux 用户分配一个固定端口段并写入系统级注册表 `/var/tmp/genarrative-dev-port-ranges/registry.json`,自动分配从 `10000-10099` 开始,每段 100 个端口,主站、api-server、SpacetimeDB、后台和 Web Project preview gateway 依次使用 `start` 到 `start + 4`。可用 `GENARRATIVE_DEV_PORT_RANGE` 或 `npm run dev -- --port-range` 手动指定端口段用于特殊场景;注册表会阻止不同用户使用相同或重叠段,并让同一用户后续启动继续复用自己已占用的固定段。该机制只在 Linux 生效,Windows 仍沿用原有端口探测与漂移逻辑。 本地 `npm run dev`、`npm run dev:spacetime` 和 `npm run dev:api-server` 会在 Rust 子进程环境中绕过项目默认 `sccache` wrapper,避免损坏的本机 cache daemon 阻断 `spacetime publish` 或 `api-server` 启动;显式设置的非 sccache 自定义 wrapper 会被保留。生产 / Jenkins 构建仍按流水线自身的 sccache 策略执行。 @@ -61,7 +61,7 @@ Linux 多用户共享同一台机器开发时,本地 dev 脚本会为当前 Li - 主站 Vite - 后台 Vite -`npm run dev` 和单模块 `dev:*` 命令会更新根目录 `.app/dev-stack.json`,记录四个本地服务的 pid、端口、URL、启动状态和当前命令。该目录只作本机运行态观测,不提交 Git。 +`npm run dev` 和单模块 `dev:*` 命令会更新根目录 `.app/dev-stack.json`,记录 `spacetime`、`api-server`、`web`、`admin-web` 和 `web-project-preview` 的 pid、端口、URL、启动状态和当前命令。该目录只作本机运行态观测,不提交 Git。 开启自动刷新: diff --git a/.hermes/shared-memory/pitfalls.md b/.hermes/shared-memory/pitfalls.md index eb41f0e5..06270869 100644 --- a/.hermes/shared-memory/pitfalls.md +++ b/.hermes/shared-memory/pitfalls.md @@ -2254,3 +2254,11 @@ - 处理:租约持有 `Arc` 并实现 `Drop` 统一复位槽位/归还连接;槽位改 `AtomicBool` CAS 抢占,删除自旋循环(持有 permit 必然命中空闲槽位)。任何新的"显式归还"资源在 async 取消语义下都要先想 Drop 兜底。 - 验证:`cargo test -p spacetime-client --manifest-path server-rs/Cargo.toml --lib`(`dropped_lease_releases_slot_and_permit`、`acquire_times_out_at_pool_acquire_when_pool_is_busy`)。 - 关联:`server-rs/crates/spacetime-client/src/lib.rs`、`docs/【后端架构】SpacetimeDB连接池租约Drop兜底与取消安全-2026-06-11.md`。 + +## Web Project preview sandbox 资源响应必须带 CORS + +- 现象:`/editor/agent` 的 preview iframe 已切到独立 `http://127.0.0.1:3104/p//`,但 iframe 内 JS / CSS 模块加载失败,浏览器控制台提示 origin `null` 被 CORS 拦截,按钮点击 smoke 看不到预览内容。 +- 原因:P1 iframe 按安全边界只允许 `sandbox="allow-scripts"`,不加 `allow-same-origin`;浏览器会把 iframe 文档放进 opaque origin,模块脚本和样式再从 preview gateway 加载时需要资源响应显式允许跨域。 +- 处理:preview gateway 服务 artifact 的成功响应统一带 `Access-Control-Allow-Origin: *`,但仍保留独立 origin、`sandbox="allow-scripts"` 和 CSP `connect-src 'none'`,不要为了修加载问题放宽 iframe sandbox。 +- 验证:`cargo test -p api-server web_project --manifest-path server-rs/Cargo.toml`,并用浏览器 smoke 确认 iframe 中计数按钮从 `已点击 0 次` 变为 `已点击 1 次`。 +- 关联:`server-rs/crates/api-server/src/web_project_preview_gateway.rs`、`docs/technical/【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md`。 diff --git a/.hermes/skills/genarrative-dev-stack-port-routing/SKILL.md b/.hermes/skills/genarrative-dev-stack-port-routing/SKILL.md index f2262353..93845d69 100644 --- a/.hermes/skills/genarrative-dev-stack-port-routing/SKILL.md +++ b/.hermes/skills/genarrative-dev-stack-port-routing/SKILL.md @@ -13,7 +13,7 @@ metadata: # Genarrative 本地 dev 启动端口与代理目标串联流程 -用于维护 Genarrative 本地开发栈启动脚本,重点覆盖 `npm run dev` 与四个 `dev:*` 单模块命令的端口检查、端口漂移和后续流程目标传递。 +用于维护 Genarrative 本地开发栈启动脚本,重点覆盖 `npm run dev` 与四个 `dev:*` 单模块命令的端口检查、端口漂移和后续流程目标传递;完整栈当前包含五个服务端口。 ## 适用场景 @@ -31,26 +31,27 @@ metadata: 2. Rust `api-server`:`8082`,健康检查为 `http://127.0.0.1:/healthz`。 3. SpacetimeDB standalone:`3101`,健康检查为 `http://127.0.0.1:/v1/ping`。 4. 后台 Vite:`3102`,后台地址为 `http://127.0.0.1:/admin/`。 +5. Web Project preview gateway:`3104`,预览地址由 `api-server` 签发为 `http://127.0.0.1:/p//`。 端口不可用时,脚本会从优先端口开始向后寻找可用端口。后续流程必须以解析后的实际端口为准,不能继续使用默认端口。 -Linux 多用户并发开发时,`GENARRATIVE_DEV_PORT_RANGE` 或 `--port-range` 会先向系统级注册表 `/var/tmp/genarrative-dev-port-ranges/registry.json` 申请一个端口段,再把该段映射为 `web = start`、`api = start + 1`、`spacetime = start + 2`、`adminWeb = start + 3`。注册表锁文件是 `/var/tmp/genarrative-dev-port-ranges/registry.lock`,可通过 `GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR` 覆盖目录。自动分配从 `10000-10099` 起,每次占用 100 个端口块,后续块按 `10100-10199`、`10200-10299` 递增;当前口径是“一个用户固定占用一个段,后续启动继续复用这段并在段内漂移”;该注册表只在 Linux 上生效;Windows 继续沿用原有端口探测、漂移和复用逻辑,不读系统级注册表。 +Linux 多用户并发开发时,`GENARRATIVE_DEV_PORT_RANGE` 或 `--port-range` 会先向系统级注册表 `/var/tmp/genarrative-dev-port-ranges/registry.json` 申请一个端口段,再把该段映射为 `web = start`、`api = start + 1`、`spacetime = start + 2`、`adminWeb = start + 3`、`webProjectPreview = start + 4`。注册表锁文件是 `/var/tmp/genarrative-dev-port-ranges/registry.lock`,可通过 `GENARRATIVE_DEV_PORT_RANGE_REGISTRY_DIR` 覆盖目录。自动分配从 `10000-10099` 起,每次占用 100 个端口块,后续块按 `10100-10199`、`10200-10299` 递增;当前口径是“一个用户固定占用一个段,后续启动继续复用这段并在段内漂移”;该注册表只在 Linux 上生效;Windows 继续沿用原有端口探测、漂移和复用逻辑,不读系统级注册表。 ## 实现入口 - `package.json` - - `dev`:执行 `node scripts/dev.mjs`,启动完整四模块。 + - `dev`:执行 `node scripts/dev.mjs`,启动完整栈的五个服务端口。 - `dev:spacetime` / `dev:api-server` / `dev:web` / `dev:admin-web`:执行 `node scripts/dev.mjs `。 - `scripts/dev-stack-port-utils.mjs` - `isPortAvailable(...)`:探测端口是否可监听。 - `findAvailablePort(...)`:从优先端口向后寻找可用端口,`0` 表示申请临时端口。 - - `resolveDevStackPorts(...)`:一次性解析 SpacetimeDB、api-server、主站 Vite、后台 Vite 端口,并避免本次解析结果互相冲突。 + - `resolveDevStackPorts(...)`:一次性解析 SpacetimeDB、api-server、主站 Vite、后台 Vite、Web Project preview gateway 端口,并避免本次解析结果互相冲突。 - Linux 注册表分配:`reserveLinuxDevPortRange(...)` / `releaseLinuxDevPortRange(...)`,仅在 Linux 上启用系统级端口段登记与用户段复用,自动分配从 `10000-10099` 起。 - - CLI 模式:`node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:3101 api:127.0.0.1:8082 web:0.0.0.0:3000 adminWeb:127.0.0.1:3102`。 + - CLI 模式:`node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:3101 api:127.0.0.1:8082 web:0.0.0.0:3000 adminWeb:127.0.0.1:3102 webProjectPreview:127.0.0.1:3104`。 - `scripts/dev.mjs` - 解析 CLI 参数后统一计算 client host、端口、`SPACETIME_SERVER`、`RUST_SERVER_TARGET`。 - - 完整栈按 SpacetimeDB、publish、api-server、主站 Vite、后台 Vite 顺序启动。 - - Linux 下会先申请系统级端口段并把它映射成四个 dev 端口;自动分配从 `10000-10099` 起,Windows 则直接沿用原有参数解析与端口漂移逻辑。 + - 完整栈按 SpacetimeDB、publish、api-server、主站 Vite、后台 Vite 顺序启动;Web Project preview gateway 是 `api-server` 内嵌的独立监听端口。 + - Linux 下会先申请系统级端口段并把它映射成五个 dev 端口;自动分配从 `10000-10099` 起,Windows 则直接沿用原有参数解析与端口漂移逻辑。 - 单模块命令复用同一套参数和 env 解析。 ## 必须保持的传递链路 @@ -63,8 +64,9 @@ Linux 多用户并发开发时,`GENARRATIVE_DEV_PORT_RANGE` 或 `--port-range` 4. api-server 健康检查:`wait_for_api_server "${RUST_SERVER_TARGET}/healthz" ...`。 5. 主站 Vite:`RUST_SERVER_TARGET`、`GENARRATIVE_RUNTIME_SERVER_TARGET`、`ADMIN_WEB_TARGET`、`ADMIN_WEB_PORT`、`--port=${WEB_PORT}`、`--host=${WEB_HOST}`。 6. 后台 Vite:`ADMIN_API_TARGET`、`GENARRATIVE_API_TARGET`、`GENARRATIVE_API_PORT`、`--port=${ADMIN_WEB_PORT}`。 -7. 控制台日志:`[dev:ports]` 和 `[dev] web/admin web/api-server/spacetime` 必须显示最终实际地址。 -8. Linux 端口段注册:`[dev] port-range:` 与 `[dev] port-range-registry:` 只在 Linux 输出,Windows 不应依赖系统级注册表。 +7. Web Project preview gateway:`GENARRATIVE_WEB_PROJECT_PREVIEW_HOST`、`GENARRATIVE_WEB_PROJECT_PREVIEW_PORT`、`GENARRATIVE_WEB_PROJECT_PREVIEW_PUBLIC_BASE_URL`、`GENARRATIVE_WEB_PROJECT_PREVIEW_FRAME_ANCESTORS`。 +8. 控制台日志:`[dev:ports]` 和 `[dev] web/admin web/api-server/spacetime` 必须显示最终实际地址。 +9. Linux 端口段注册:`[dev] port-range:` 与 `[dev] port-range-registry:` 只在 Linux 输出,Windows 不应依赖系统级注册表。 如果只改了其中一段,通常会出现:浏览器打开的前端可用,但 `/api/*` 代理到旧端口;后台页面可用但后台 API 失败;SpacetimeDB 启动在新端口但 publish 仍发往旧端口。 @@ -91,14 +93,15 @@ Linux 多用户并发开发时,`GENARRATIVE_DEV_PORT_RANGE` 或 `--port-range` node --check scripts/dev.mjs npm run test -- scripts/dev-stack-port-utils.test.ts npm run check:encoding -node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:0 api:127.0.0.1:0 web:0.0.0.0:0 adminWeb:127.0.0.1:0 +npm run test -- scripts/dev.test.ts scripts/dev-stack-port-utils.test.ts --reporter verbose +node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:0 api:127.0.0.1:0 web:0.0.0.0:0 adminWeb:127.0.0.1:0 webProjectPreview:127.0.0.1:0 ``` 端口冲突回归测试建议: 1. 用测试或临时 Node server 占用某个优先端口。 2. 调用 `findAvailablePort`,断言结果大于被占用端口。 -3. 调用 `resolveDevStackPorts`,断言四个结果互不相同。 +3. 调用 `resolveDevStackPorts`,断言五个结果互不相同。 4. 如果实际启动完整栈,观察控制台: - `[dev:ports] ... 不可用,改用 ...` - `[dev] api-server: http://...:` @@ -121,7 +124,7 @@ node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:0 ap - [ ] 端口工具有测试覆盖端口被占用和多端口互斥解析。 - [ ] Linux 注册表分配、同用户复用固定段并继续漂移、自动分配从 `10000-10099` 起、Windows bypass 都有测试覆盖。 - [ ] `scripts/dev.mjs` 通过 `node --check`。 -- [ ] `npm run dev` 的 SpacetimeDB、publish、api-server、主站 Vite、后台 Vite 都使用实际端口。 +- [ ] `npm run dev` 的 SpacetimeDB、publish、api-server、主站 Vite、后台 Vite、Web Project preview gateway 都使用实际端口。 - [ ] `npm run dev:web` 在主站端口不可用时能切换到可用端口。 - [ ] 文档同步更新 `docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md`。 - [ ] 长期踩坑同步更新 `.hermes/shared-memory/pitfalls.md`。 diff --git a/docs/README.md b/docs/README.md index 45aec037..fe216f9e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -21,7 +21,7 @@ 微信小程序虚拟支付接入、`wechat_mp_virtual` 渠道、`wx.requestVirtualPayment` 承接页和后端签名配置见 [【技术方案】微信虚拟支付接入-2026-05-26.md](./%E3%80%90%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88%E3%80%91%E5%BE%AE%E4%BF%A1%E8%99%9A%E6%8B%9F%E6%94%AF%E4%BB%98%E6%8E%A5%E5%85%A5-2026-05-26.md)。 -`/editor/agent` 浏览器内 AI Web 工程编辑器的静态 SPA 沙箱预览 MVP,采用“平台编辑器壳 + api-server 控制面 + 独立 runner worker + 独立预览域”四层结构;技术方案、威胁模型和验收清单见 [【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md](./technical/【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md)、[【安全模型】AIWeb工程Runner与预览隔离威胁模型-2026-06-13.md](./technical/【安全模型】AIWeb工程Runner与预览隔离威胁模型-2026-06-13.md) 和 [【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md](./technical/【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md)。P1 先用确定性 mock Agent 生成结构化 patch、真实打通项目 / 快照 / 构建 / artifact / 预览闭环,落地拆分见 [【技术方案】EditorAgentMockAgentP1落地计划-2026-06-15.md](./technical/【技术方案】EditorAgentMockAgentP1落地计划-2026-06-15.md)。 +`/editor/agent` 浏览器内 AI Web 工程编辑器的静态 SPA 沙箱预览 MVP,采用“平台编辑器壳 + api-server 控制面 + 独立 runner worker + 独立预览域”四层结构;技术方案、威胁模型和验收清单见 [【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md](./technical/【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md)、[【安全模型】AIWeb工程Runner与预览隔离威胁模型-2026-06-13.md](./technical/【安全模型】AIWeb工程Runner与预览隔离威胁模型-2026-06-13.md) 和 [【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md](./technical/【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md)。P1 先用确定性 mock Agent 生成结构化 patch、真实打通项目 / 快照 / 构建 / artifact / 预览闭环,落地拆分见 [【技术方案】EditorAgentMockAgentP1落地计划-2026-06-15.md](./technical/【技术方案】EditorAgentMockAgentP1落地计划-2026-06-15.md),可执行开发计划见 [【开发计划】EditorAgentMockAgentP1可执行开发计划-2026-06-15.md](./planning/【开发计划】EditorAgentMockAgentP1可执行开发计划-2026-06-15.md)。 `/editor/canvas` 图片画布编辑器的画布素材 ZIP 导出能力,入口放在右上角标题栏下载图标内,第一版采用前端 JSZip 打包画布中有效图层引用的上传图、生成图和修改结果,方案见 [【前端架构】图片画布素材导出方案-2026-06-15.md](./technical/【前端架构】图片画布素材导出方案-2026-06-15.md)。 diff --git a/docs/planning/README.md b/docs/planning/README.md index 81a119cc..a97874e0 100644 --- a/docs/planning/README.md +++ b/docs/planning/README.md @@ -5,6 +5,7 @@ ## 当前计划 - [【玩法创作】创作流程统一总计划-2026-05-30.md](./【玩法创作】创作流程统一总计划-2026-05-30.md):创作入口、统一创作页、统一生成页、结果页、发布、作品架、广场和运行态的阶段计划、进度记录、并行波次和可直接派发的任务包。 +- [【开发计划】EditorAgentMockAgentP1可执行开发计划-2026-06-15.md](./【开发计划】EditorAgentMockAgentP1可执行开发计划-2026-06-15.md):`/editor/agent` Mock Agent P1 的可执行波次、任务包、验收门禁和覆盖矩阵,完整承接技术落地计划。 ## 维护规则 diff --git a/docs/planning/【开发计划】EditorAgentMockAgentP1可执行开发计划-2026-06-15.md b/docs/planning/【开发计划】EditorAgentMockAgentP1可执行开发计划-2026-06-15.md new file mode 100644 index 00000000..3f047864 --- /dev/null +++ b/docs/planning/【开发计划】EditorAgentMockAgentP1可执行开发计划-2026-06-15.md @@ -0,0 +1,641 @@ +# Editor Agent Mock Agent P1 可执行开发计划 + +更新时间:`2026-06-15` + +## 计划定位 + +本文是 [【技术方案】EditorAgentMockAgentP1落地计划-2026-06-15.md](../technical/【技术方案】EditorAgentMockAgentP1落地计划-2026-06-15.md) 的可执行拆解版。目标不是重写技术方案,而是把 P1 的所有能力、边界、安全约束、任务拆分、验证命令和验收场景拆成可以派发、可以并行、可以逐项打勾的开发计划。 + +P1 只交付确定性 mock Agent 的最小纵切: + +```text +/editor/agent 输入 mock 指令 + -> api-server mock Agent 生成结构化 patch + -> patch 校验并保存新 snapshot + -> 创建 preview build + -> runner 静态构建固定模板 + -> 产出 immutable artifact + -> preview gateway 签发独立预览 URL + -> 前端 iframe 切换预览 +``` + +P1 完成后,真实 Agent 仍后置到 P2+;后续只替换“需求文本 -> 结构化 patch”的来源,不推翻项目、快照、构建、artifact 和预览主链路。 + +## 硬边界 + +以下边界是 P1 开发门禁,任一项不能为了赶进度绕过: + +- 不接真实 LLM / Agent。 +- 不接 LangChain-Rust / `platform-agent`。 +- 不开放任意 npm 依赖安装。 +- 不执行 AI 自定义 `package.json` scripts。 +- 不做 HMR、长驻 dev server、WebSocket 代理、终端 shell、后端服务和任意端口代理。 +- 不做 Web project 作品化发布。 +- 不做完整 lease / controller / worker 持久任务队列;P1 可一次性触发 runner,但 runner 必须独立于 api-server 执行。 +- 不做主站同源预览;开发态也必须独立端口 / origin。 +- 不把 AI 生成工程写入当前仓库源码目录。 +- 不把平台 access token、用户 cookie、SpacetimeDB、OSS 写权限、LLM provider 密钥暴露给 runner 或 preview 页面。 + +## 总体执行顺序 + +P1 分 6 个开发波次。每个波次都有可退出标准,前一波次未通过时不得进入依赖它的联调。 + +| 波次 | 覆盖任务 | 目标 | 可并行性 | +| --- | --- | --- | --- | +| Wave 0 | 准备与基线 | 确认文档、现状、路由和测试入口 | 独立 | +| Wave 1 | P1-01、P1-02 | 契约、DTO、SpacetimeDB 表和 facade 闭合 | DTO 与表可并行,最终统一 | +| Wave 2 | P1-03、P1-04 | api-server 控制面和 mock Agent 闭合 | 与 runner 原型部分并行 | +| Wave 3 | P1-05、P1-06 | 独立 runner、artifact、preview gateway 闭合 | runner 与 gateway 可并行 | +| Wave 4 | P1-07 | `/editor/agent` 前端页面和 SSE 接入 | 依赖 API 契约,可先 mock client | +| Wave 5 | P1-08 | 自动化、安全验收、浏览器 smoke 和文档回填 | 贯穿执行,最终收口 | + +## Wave 0:准备与基线 + +目标:在编码前消除落点歧义,确认本轮只实现 P1。 + +执行项: + +- [x] 阅读并以本文档、P1 落地计划、AIWeb 沙箱预览方案、威胁模型和 MVP 验收清单作为实现依据。 +- [x] 确认当前后端路线仍为 `server-rs + Axum + SpacetimeDB`,旧 `server-node` / Express / PostgreSQL 只作历史参考。 +- [x] 扫描现有 `/editor`、`/editor/canvas`、SSE、api-server route module、SpacetimeDB 表目录和 `spacetime-client` facade 写法。 +- [x] 确认新增 Markdown 只放 `docs/` 或 `.hermes/` 可提交内容,不写入个人路径、密钥、会话记录。 +- [x] 确认 P1 不需要新增玩法入口,不走新增玩法 skill;`/editor/agent` 属于 Web 工程编辑器入口。 + +退出条件: + +- [x] 已列出将复用的现有路由挂载方式、SSE client、api-server module 注册方式和 SpacetimeDB schema guard。 +- [x] 无未决产品问题阻塞 P1 纵切。 + +## Wave 1:契约、DTO 与 SpacetimeDB 持久化 + +### P1-01 契约与 DTO + +主要落点: + +- `server-rs/crates/shared-contracts` +- `packages/shared` + +交付物: + +- [x] 新增或扩展 Rust DTO:`WebProject`、`WebProjectSnapshot`、`WebProjectFile`、`WebProjectPatch`、`WebProjectPatchOperation`、`WebProjectPreviewBuild`、`WebProjectPreviewBuildEvent`、`MockAgentTurnRequest`、`MockAgentTurnResponse`。 +- [x] 新增或扩展 TypeScript DTO,字段名与 Rust 契约保持同名语义。 +- [x] 固化 `templateKey = react-vite-ts-static`。 +- [x] 固化 `buildStatus = queued | running | succeeded | failed | cancelled | expired | stale`。 +- [x] 明确 `previewUrl` 只由后端返回,前端不得自行拼接。 +- [x] 在契约注释中写清路径、内容、大小和依赖限制。 + +必须覆盖的字段: + +- [x] `projectId`:不可枚举字符串 ID。 +- [x] `ownerUserId`:项目归属用户。 +- [x] `templateKey`:固定模板。 +- [x] `activeSnapshotId`:当前编辑快照。 +- [x] `activePreviewBuildId`:当前成功预览构建。 +- [x] `files`:P1 允许小型文本源码和少量静态资源。 +- [x] `patchSummary`:mock Agent 或用户编辑摘要。 +- [x] `buildStatus`:构建状态枚举。 +- [x] `previewUrl`:后端签发的独立预览 URL。 + +路径与内容校验规则必须进入 DTO 文档和后端校验实现: + +- [x] 只允许相对路径。 +- [x] 拒绝绝对路径。 +- [x] 拒绝 `..`。 +- [x] 拒绝 `.env`、`.npmrc`、`.git`、`.ssh`。 +- [x] 拒绝符号链接语义。 +- [x] 限制目录深度、单文件大小、snapshot 总大小。 +- [x] P1 只允许文本源码和少量静态资源。 +- [x] P1 可编辑范围限定为 `src/App.tsx`、`src/App.css`、`src/components/**`、`src/assets/**` 与 `public/**`;固定模板控制文件不进入用户 snapshot。 +- [x] `package.json` 不是事实源;新增依赖和 scripts 在 P1 拒绝或忽略。 + +退出条件: + +- [x] Rust / TypeScript 契约字段和状态枚举一致。 +- [x] DTO 单测或类型测试覆盖状态枚举、patch operation 和危险路径样例。 +- [x] 前端 client 可以只依赖 `packages/shared` 类型完成编译。 + +### P1-02 SpacetimeDB 表与 procedure/facade + +主要落点: + +- `server-rs/crates/spacetime-module/src/web_project.rs` +- `server-rs/crates/spacetime-module/src/lib.rs` +- `server-rs/crates/spacetime-module/src/migration.rs` +- `server-rs/crates/spacetime-client/src/mapper/web_project.rs` +- `server-rs/crates/spacetime-client/src/web_project.rs` + +新增表: + +- [x] `web_project` +- [x] `web_project_snapshot` +- [x] `web_project_preview_build` +- [x] `web_project_service_identity` + +`web_project` 字段: + +- [x] `project_id` +- [x] `owner_user_id` +- [x] `title` +- [x] `template_key` +- [x] `active_snapshot_id` +- [x] `active_preview_build_id` +- [x] `created_at` +- [x] `updated_at` + +`web_project_snapshot` 字段: + +- [x] `snapshot_id` +- [x] `project_id` +- [x] `owner_user_id` +- [x] `parent_snapshot_id` +- [x] `template_key` +- [x] `files_json` +- [x] `patch_summary` +- [x] `created_by` +- [x] `created_at` + +`web_project_preview_build` 字段: + +- [x] `job_id` +- [x] `project_id` +- [x] `snapshot_id` +- [x] `owner_user_id` +- [x] `status` +- [x] `logs_json` +- [x] `artifact_id` +- [x] `preview_token_id` +- [x] `preview_url` +- [x] `error_summary` +- [x] `created_at` +- [x] `started_at` +- [x] `finished_at` +- [x] `updated_at` + +SpacetimeDB 执行规则: + +- [x] 表结构使用仓库现有 Rust SpacetimeDB 2.x 写法,不使用旧 API。 +- [x] `web_project` procedure 先用 `ctx.sender()` 校验服务身份 allowlist,再信任 api-server 从登录态代传的业务 `owner_user_id`,前端不得传 owner。 +- [x] 领域规则不写到前端;事务编排留在 `spacetime-module`。 +- [x] 后端访问统一经 `spacetime-client` facade,不在 api-server 绕过 facade。 +- [x] 表目录、`migration.rs` 和生成 bindings 同步更新;`web_project_service_identity` 已明确不随普通业务迁移包导入导出。 +- [x] 如果后续给已有表新增字段,字段必须放在结构体最后并设置明确默认值;需要改名或改类型时先确认迁移计划。 + +最小 procedure / facade 能力: + +- [x] 创建固定模板项目。 +- [x] 读取项目。 +- [x] 读取 active snapshot。 +- [x] 保存 snapshot。 +- [x] 创建 preview build。 +- [x] 更新 build 状态和日志。 +- [x] 成功构建后,在 active snapshot 匹配时推进 `active_preview_build_id`。 +- [x] failed / cancelled / expired / stale 不覆盖 active preview。 + +退出条件: + +- [x] 能通过 facade 创建项目、保存 snapshot、记录 build。 +- [ ] 状态机保护 active preview 的后端定向单测未在本轮验证清单中出现;当前代码路径已落地,需后续补 `spacetime-module` / `api-server` 定向测试或集成测试。 +- [x] 执行 `npm run spacetime:generate`,生成 bindings 已随 Web Project schema / procedure 更新;后续变更 schema 时仍需复跑。 +- [x] 执行 `npm run check:spacetime-schema`。 + +## Wave 2:api-server 控制面与 mock Agent + +### P1-03 api-server Web Project 模块 + +主要落点: + +- `server-rs/crates/api-server/src/web_project.rs` +- `server-rs/crates/api-server/src/modules/web_project.rs` +- `server-rs/crates/api-server/src/app.rs` 或现有 module 注册入口 + +P1 API: + +- [x] `POST /api/creation/web-project/projects` +- [x] `GET /api/creation/web-project/projects/{projectId}` +- [x] `GET /api/creation/web-project/projects/{projectId}/snapshot` +- [x] `PATCH /api/creation/web-project/projects/{projectId}/files` +- [x] `POST /api/creation/web-project/projects/{projectId}/mock-agent-turns` +- [x] `POST /api/runtime/web-project/projects/{projectId}/preview-builds` +- [x] `GET /api/runtime/web-project/preview-builds/{jobId}` +- [x] `GET /api/runtime/web-project/preview-builds/{jobId}/events` + +控制面职责: + +- [x] 鉴权并校验 project owner。 +- [x] 创建固定模板项目。 +- [x] 读取 active snapshot。 +- [x] 校验用户编辑和 mock patch。 +- [x] 保存新 snapshot。 +- [x] 创建 preview build。 +- [x] 触发 P1 runner 构建,但 api-server 不执行 `npm` / `vite` / 用户工程代码。 +- [x] 记录构建日志和状态。 +- [x] 构建成功后签发 preview URL。 +- [x] 构建失败时保留上一版 active preview。 + +SSE 口径: + +- [x] `/events` 外部契约保持 SSE。 +- [x] 复用 `src/services/sseStream.ts` 可消费的事件格式。 +- [x] 事件类型覆盖 `queued`、`running`、`log`、`succeeded`、`failed`、`cancelled`、`expired`、`stale`。 +- [x] P1 可先用 api-server 内存广播或短轮询兼容,但返回契约必须保持可迁移到持久 job。 + +退出条件: + +- [x] API handler 只做 BFF / 控制面编排,不执行工程代码。 +- [x] 所有项目、snapshot、build 读取和写入都有 owner 校验。 +- [ ] API 单测覆盖鉴权、owner mismatch、危险 patch、失败不覆盖 active preview:当前主线已通过 `cargo check -p api-server` 和前端 / runner 自动化,后端 API 定向单测不在本轮已验证命令中,保留待补。 + +### P1-04 mock Agent + +主要落点: + +- `server-rs/crates/api-server/src/web_project_mock_agent.rs` + +输入契约: + +```json +{ + "prompt": "做一个蓝色计数按钮页面", + "baseSnapshotId": "snapshot_xxx" +} +``` + +输出契约: + +```json +{ + "snapshot": "...", + "patch": { + "operations": [ + { + "type": "updateFile", + "path": "src/App.tsx", + "content": "..." + } + ] + }, + "summary": "更新首页计数按钮示例" +} +``` + +mock 指令族: + +- [x] `计数` / `按钮`:生成带计数按钮的 React 页面。 +- [x] `卡片` / `列表`:生成卡片列表页面。 +- [x] `蓝色` / `绿色` / `粉色`:调整 CSS 主题色。 +- [x] `破坏构建`:生成 TypeScript 编译错误,用于验收失败保留上一版预览。 +- [x] 其它输入:只更新标题和说明文案,避免 mock 分支过多。 + +强制规则: + +- [x] mock Agent 确定性、可测试。 +- [x] mock Agent 只能返回结构化 patch。 +- [x] mock Agent 输出必须经过统一 `validate_web_project_patch(...)`。 +- [x] mock Agent 不得直接写表。 +- [x] mock Agent 不得绕过 path、大小、敏感文件、依赖和 scripts 校验。 + +退出条件: + +- [x] mock 指令族单测全部通过。 +- [x] 破坏构建场景能生成稳定失败源码。 +- [x] 危险 patch 样例被统一校验拒绝。 + +## Wave 3:runner、artifact 与 preview gateway + +### P1-05 P1 runner + +主要落点: + +- `server-rs/crates/web-project-runner` + +P1 runner 形态: + +- [x] 可以先采用“一次性 runner 进程”。 +- [x] 不做持久 worker 队列。 +- [x] 执行面必须独立于 api-server、主站源码目录和预览域。 +- [x] api-server 只传递 job 身份和最小任务能力。 + +runner 输入: + +- [x] `jobId` +- [x] `projectId` +- [x] `snapshotId` +- [x] snapshot files 包。 +- [x] artifact root 配置键或受控 artifact 写入能力。 + +runner 输入禁止携带: + +- [x] runner 命令。 +- [x] 构建参数。 +- [x] 工作区路径。 +- [x] artifact 输出路径。 +- [x] 用户自定义 registry / proxy / lockfile 策略。 + +runner 步骤: + +- [x] 创建任务级临时目录。 +- [x] 用 runner 内置模板或 runner 管理的只读模板缓存写入固定 React / Vite / TypeScript 模板。 +- [x] 规范化 snapshot 文件路径,写入前确认最终路径仍在任务临时目录内。 +- [x] 忽略或重写用户 `package.json` 的危险字段。 +- [x] 使用环境变量白名单启动子进程,清空平台密钥、`.env`、token、代理和私有 registry 配置。 +- [x] 执行平台固定命令清单。 +- [ ] 限制 CPU、内存、磁盘、进程数、打开文件数、构建时间、日志长度、单文件大小和 artifact 大小:当前已有限制构建时间、日志长度、单文件大小和 snapshot 大小;CPU / 内存 / 进程数 / 打开文件数 / 磁盘配额仍属于后续部署层或 P2 门禁。 +- [x] 成功后把 `dist/` 复制到 immutable artifact 目录。 +- [x] artifact 目录由 runner 配置计算,不接受请求指定。 +- [x] 失败时返回错误摘要和日志片段,日志需脱敏并避免完整宿主路径。 +- [x] 清理临时目录。 + +允许的构建命令只能来自平台常量,使用 argv 方式执行,不经 shell、不拼接字符串、不执行用户传入命令: + +```text +npm ci --ignore-scripts --offline --no-audit --fund=false +npm exec --offline -- vite build +``` + +依赖与网络策略: + +- [x] P1 默认离线使用 runner 管理的模板依赖缓存。 +- [ ] 如果离线缓存不足,只能访问平台受控 npm registry mirror,并由 runner 写入受控 `.npmrc`:P1 当前保持 `npm ci --offline`,mirror 接入未启用。 +- [x] 用户 snapshot 中的 `.npmrc`、registry、proxy、`package-lock.json` 篡改和新增依赖必须拒绝或重写。 +- [x] 禁止复用当前仓库的 `node_modules`、源码目录或本机全局 npm cache 作为 runner 工作区输入。 +- [ ] P1 构建期默认 deny all 网络:当前命令为 offline,但进程级网络 deny-all 未在代码层验证,保留后续部署门禁。 +- [ ] 只在使用平台受控 registry mirror 或资产只读签名域时开放精确白名单:mirror / 资产白名单未在本轮落地。 +- [ ] 必须阻断 RFC1918 内网、云 metadata 地址、api-server 管理端口、SpacetimeDB、生产数据库、Docker daemon:需后续容器 / sandbox 网络策略验证。 +- [ ] 必须覆盖 HTTP redirect 和 DNS rebinding 到内网:需后续网络白名单实现后验证。 + +退出条件: + +- [x] 固定模板可成功构建并生成 immutable artifact。 +- [x] `破坏构建` 能稳定失败并返回可读错误摘要。 +- [x] runner 日志不泄露平台密钥、OSS 写签名、完整宿主路径和环境变量 dump。 +- [x] runner 工作区逃逸、危险 path 和请求指定 artifact root 的测试通过。 + +### P1-06 Preview Gateway + +主要落点: + +- `api-server` 独立 listener / 端口 / vhost / origin,或独立 runner/gateway 模块。 + +开发态 preview URL: + +```text +http://127.0.0.1:/p// +``` + +生产形态: + +```text +https://sandbox.genarrative.world/p// +``` + +gateway 必须: + +- [x] 校验 token。 +- [x] 绑定 owner / project / snapshot / artifact。 +- [x] 禁止 path traversal。 +- [x] MIME 类型按白名单输出。 +- [x] `index.html` fallback 只在 artifact 根内生效。 +- [x] token 过期或 artifact 删除后返回确定错误。 +- [x] 输出 CSP,默认 `connect-src 'none'`。 +- [x] 禁用 Service Worker 和持久缓存。 +- [x] 不向预览页注入平台 access token、用户 cookie、SpacetimeDB、OSS 写权限或 LLM provider 密钥。 +- [x] 服务静态 artifact 的入口必须是独立 listener / 端口 / vhost / origin。 +- [x] 不得把 preview artifact 挂到主站同源路径下。 + +前端 iframe sandbox: + +```text +sandbox="allow-scripts" +``` + +P1 不允许增加: + +- [x] `allow-same-origin` +- [x] `allow-downloads` +- [x] `allow-popups` +- [x] `allow-top-navigation` + +退出条件: + +- [x] 预览 origin 与主站 origin 不同。 +- [ ] path traversal、错误 MIME、旧 token、过期 token、artifact 删除、跨租户访问测试通过:代码路径已实现,后端 gateway 定向测试 / 浏览器 smoke 未在本轮已验证命令中出现。 +- [x] iframe sandbox 和 CSP 检查通过:前端 iframe 仅使用 `sandbox="allow-scripts"`;preview gateway 保持 `connect-src 'none'`,并通过 `GENARRATIVE_WEB_PROJECT_PREVIEW_FRAME_ANCESTORS` 显式允许平台编辑器宿主嵌入。 + +## Wave 4:前端 `/editor/agent` + +### P1-07 页面、client 与状态恢复 + +主要落点: + +- `src/components/editor/agent/WebProjectAgentEditorPage.tsx` +- `src/components/editor/agent/WebProjectAgentEditorPage.test.tsx` +- `src/components/editor/agent/webProjectAgentViewModel.ts` +- `src/services/web-project/webProjectClient.ts` +- `src/services/web-project/webProjectSse.ts` +- `src/services/web-project/webProjectClient.test.ts` + +入口路由: + +- [x] `/editor/agent` + +桌面布局: + +- [x] 左侧文件树。 +- [x] 中间代码编辑区,P1 可先用 `