From 877ba64de8001f58bd7121622cdee0fad900eddb Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Sat, 10 Jan 2026 00:45:46 +0000 Subject: [PATCH] Introduce AutoMetabuilder core components and workflow packages: - Implement core components: CLI argument parsing, environment loading, GitHub service creation, and logging configuration. - Add support for OpenAI client setup and model resolution. - Develop SDLC context loader from GitHub and repository files. - Implement workflow context and engine builders. - Introduce major workflow packages: `game_tick_loop` and `contextual_iterative_loop`. - Update localization files with new package descriptions and labels. - Streamline web navigation by loading items from a dedicated JSON file. --- .gitignore | 7 +- .pylint_cache/src_1.stats | Bin 3089 -> 0 bytes .pylint_cache_run/src_1.stats | Bin 11354 -> 0 bytes Dockerfile => backend/Dockerfile | 2 +- {src => backend}/autometabuilder/__init__.py | 0 .../autometabuilder/app_runner.py | 0 .../autometabuilder/callable_loader.py | 0 {src => backend}/autometabuilder/cli_args.py | 0 .../autometabuilder/context_loader.py | 0 .../autometabuilder/docker_utils.py | 0 .../autometabuilder/env_loader.py | 0 .../autometabuilder/github_integration.py | 0 .../autometabuilder/github_service.py | 0 .../autometabuilder/integrations/__init__.py | 0 .../integrations/notifications.py | 0 .../autometabuilder/logging_config.py | 0 {src => backend}/autometabuilder/main.py | 0 .../autometabuilder/messages_en.json | 0 .../autometabuilder/messages_es.json | 0 .../autometabuilder/messages_fr.json | 0 .../autometabuilder/messages_nl.json | 0 .../autometabuilder/messages_pirate.json | 0 .../autometabuilder/metadata.json | 0 .../autometabuilder/metadata_loader.py | 0 .../autometabuilder/model_resolver.py | 0 .../autometabuilder/openai_client.py | 0 .../autometabuilder/openai_factory.py | 0 .../autometabuilder/plugin_loader.py | 0 .../autometabuilder/plugins/__init__.py | 0 .../autometabuilder/plugins/hello.py | 0 .../autometabuilder/prompt_loader.py | 0 .../autometabuilder/roadmap_utils.py | 0 .../autometabuilder/tool_map_builder.py | 0 .../autometabuilder/tool_policies.json | 0 .../autometabuilder/tool_policy_loader.py | 0 .../autometabuilder/tool_registry.json | 0 .../autometabuilder/tool_registry_loader.py | 0 {src => backend}/autometabuilder/tools.json | 0 .../autometabuilder/tools/__init__.py | 0 .../autometabuilder/tools/edit_file.py | 0 .../autometabuilder/tools/list_files.py | 0 .../autometabuilder/tools/read_file.py | 0 .../autometabuilder/tools/run_docker_task.py | 0 .../autometabuilder/tools/run_lint.py | 0 .../autometabuilder/tools/run_tests.py | 0 .../autometabuilder/tools/write_file.py | 0 .../autometabuilder/tools_loader.py | 0 .../autometabuilder/web/__init__.py | 0 backend/autometabuilder/web/data.py | 240 ++++ .../autometabuilder/web/navigation_items.json | 0 backend/autometabuilder/web/server.py | 237 ++++ .../autometabuilder/web/ui_assets.json | 0 .../autometabuilder/workflow.json | 0 .../autometabuilder/workflow/__init__.py | 0 .../autometabuilder/workflow/engine.py | 0 .../workflow/input_resolver.py | 0 .../autometabuilder/workflow/loop_executor.py | 0 .../autometabuilder/workflow/node_executor.py | 0 .../autometabuilder/workflow/plugin_loader.py | 0 .../autometabuilder/workflow/plugin_map.json | 0 .../workflow/plugin_registry.py | 0 .../workflow/plugins/core_ai_request.py | 0 .../plugins/core_append_context_message.py | 0 .../plugins/core_append_tool_results.py | 0 .../plugins/core_append_user_instruction.py | 0 .../workflow/plugins/core_load_context.py | 0 .../workflow/plugins/core_run_tool_calls.py | 0 .../workflow/plugins/core_seed_messages.py | 0 .../workflow/plugins/tools_create_branch.py | 0 .../plugins/tools_create_pull_request.py | 0 .../workflow/plugins/tools_list_files.py | 0 .../workflow/plugins/tools_read_file.py | 0 .../workflow/plugins/tools_run_lint.py | 0 .../workflow/plugins/tools_run_tests.py | 0 .../plugins/utils_branch_condition.py | 0 .../workflow/plugins/utils_filter_list.py | 0 .../workflow/plugins/utils_map_list.py | 0 .../workflow/plugins/utils_not.py | 0 .../workflow/plugins/utils_reduce_list.py | 0 .../autometabuilder/workflow/runtime.py | 0 .../workflow/tool_calls_handler.py | 0 .../autometabuilder/workflow/tool_runner.py | 0 .../autometabuilder/workflow/value_helpers.py | 0 .../autometabuilder/workflow_config_loader.py | 0 .../workflow_context_builder.py | 0 .../workflow_engine_builder.py | 0 .../workflow_packages/blank.json | 0 .../contextual_iterative_loop.json | 0 .../workflow_packages/game_tick_loop.json | 0 .../workflow_packages/iterative_loop.json | 0 .../plan_execute_summarize.json | 0 .../workflow_packages/repo_scan_context.json | 0 .../workflow_packages/single_pass.json | 0 .../workflow_packages/testing_triangle.json | 0 env_example => backend/env_example | 0 poetry.lock => backend/poetry.lock | 0 prompt.yml => backend/prompt.yml | 0 pyproject.toml => backend/pyproject.toml | 7 +- .../docker-compose.yml | 4 +- frontend/.eslintrc.json | 6 + frontend/components/layout/PageLayout.tsx | 26 + frontend/components/layout/Sidebar.tsx | 31 + .../components/sections/DashboardSection.tsx | 78 ++ .../components/sections/PromptSection.tsx | 38 + .../components/sections/SettingsSection.tsx | 65 + .../sections/TranslationsSection.tsx | 105 ++ .../components/sections/WorkflowSection.tsx | 61 + frontend/next-env.d.ts | 2 + frontend/package.json | 24 + frontend/pages/_app.tsx | 6 + frontend/pages/index.tsx | 115 ++ frontend/styles/_variables.scss | 16 + frontend/styles/globals.scss | 301 +++++ frontend/tsconfig.json | 19 + src/autometabuilder/web/server.py | 504 -------- src/autometabuilder/web/static/css/main.css | 1103 ----------------- .../web/static/css/workflow_palette.css | 55 - .../web/static/js/app_context.js | 43 - src/autometabuilder/web/static/js/index.js | 16 - .../web/static/js/plugin_registry.js | 29 - .../web/static/js/plugins/choices_manager.js | 66 - .../web/static/js/plugins/form_validator.js | 21 - .../static/js/plugins/navigation_loader.js | 66 - .../static/js/plugins/navigation_manager.js | 73 -- .../web/static/js/plugins/prompt_builder.js | 72 -- .../web/static/js/plugins/run_mode_toggle.js | 24 - .../web/static/js/plugins/status_poller.js | 86 -- .../web/static/js/plugins/theme_manager.js | 45 - .../js/plugins/translation_editor_actions.js | 81 -- .../js/plugins/translation_editor_base.js | 27 - .../js/plugins/translation_editor_network.js | 86 -- .../js/plugins/translation_editor_render.js | 72 -- .../web/static/js/plugins/workflow_builder.js | 32 - .../web/static/js/plugins/workflow_palette.js | 10 - .../static/js/plugins/workflow_templates.js | 90 -- .../web/static/js/plugins/workflow_toggle.js | 25 - .../web/static/js/services/toast.js | 37 - .../static/js/workflow/workflow_builder.js | 51 - .../js/workflow/workflow_canvas_renderer.js | 38 - .../js/workflow/workflow_field_renderer.js | 94 -- .../js/workflow/workflow_loop_renderer.js | 35 - .../static/js/workflow/workflow_mutations.js | 70 -- .../js/workflow/workflow_node_events.js | 74 -- .../js/workflow/workflow_node_renderer.js | 36 - .../js/workflow/workflow_node_template.js | 57 - .../static/js/workflow/workflow_palette.js | 99 -- .../js/workflow/workflow_plugin_options.js | 18 - .../web/static/js/workflow/workflow_state.js | 57 - .../web/static/js/workflow/workflow_utils.js | 20 - src/autometabuilder/web/templates/base.html | 49 - .../components/atoms/helper_text.html | 6 - .../web/templates/components/atoms/icon.html | 4 - .../templates/components/atoms/nav_link.html | 6 - .../web/templates/components/atoms/pill.html | 4 - .../components/atoms/section_header.html | 9 - .../templates/components/molecules/card.html | 19 - .../components/molecules/empty_state.html | 10 - .../components/molecules/sidebar_nav.html | 10 - .../components/organisms/callout.html | 14 - .../organisms/dashboard_bot_control.html | 54 - .../components/organisms/dashboard_logs.html | 14 - .../organisms/dashboard_status.html | 32 - .../components/organisms/prompt_builder.html | 71 -- .../components/organisms/prompt_guidance.html | 21 - .../organisms/settings_api_keys.html | 31 - .../organisms/settings_configuration.html | 39 - .../components/organisms/settings_other.html | 44 - .../organisms/settings_web_access.html | 26 - .../components/organisms/sidebar.html | 12 - .../components/organisms/sidebar_footer.html | 12 - .../components/organisms/sidebar_header.html | 6 - .../organisms/translations_editor.html | 62 - .../organisms/translations_languages.html | 48 - .../organisms/workflow_palette.html | 16 - .../organisms/workflow_templates.html | 30 - .../components/sections/choice_card.html | 13 - .../sections/dashboard_section.html | 22 - .../components/sections/prompt_chip.html | 5 - .../components/sections/prompt_section.html | 20 - .../components/sections/prompt_step.html | 21 - .../components/sections/settings_section.html | 30 - .../sections/translations_section.html | 20 - .../components/sections/workflow_section.html | 45 - src/autometabuilder/web/templates/index.html | 25 - 184 files changed, 1381 insertions(+), 4171 deletions(-) delete mode 100644 .pylint_cache/src_1.stats delete mode 100644 .pylint_cache_run/src_1.stats rename Dockerfile => backend/Dockerfile (97%) rename {src => backend}/autometabuilder/__init__.py (100%) rename {src => backend}/autometabuilder/app_runner.py (100%) rename {src => backend}/autometabuilder/callable_loader.py (100%) rename {src => backend}/autometabuilder/cli_args.py (100%) rename {src => backend}/autometabuilder/context_loader.py (100%) rename {src => backend}/autometabuilder/docker_utils.py (100%) rename {src => backend}/autometabuilder/env_loader.py (100%) rename {src => backend}/autometabuilder/github_integration.py (100%) rename {src => backend}/autometabuilder/github_service.py (100%) rename {src => backend}/autometabuilder/integrations/__init__.py (100%) rename {src => backend}/autometabuilder/integrations/notifications.py (100%) rename {src => backend}/autometabuilder/logging_config.py (100%) rename {src => backend}/autometabuilder/main.py (100%) rename {src => backend}/autometabuilder/messages_en.json (100%) rename {src => backend}/autometabuilder/messages_es.json (100%) rename {src => backend}/autometabuilder/messages_fr.json (100%) rename {src => backend}/autometabuilder/messages_nl.json (100%) rename {src => backend}/autometabuilder/messages_pirate.json (100%) rename {src => backend}/autometabuilder/metadata.json (100%) rename {src => backend}/autometabuilder/metadata_loader.py (100%) rename {src => backend}/autometabuilder/model_resolver.py (100%) rename {src => backend}/autometabuilder/openai_client.py (100%) rename {src => backend}/autometabuilder/openai_factory.py (100%) rename {src => backend}/autometabuilder/plugin_loader.py (100%) rename {src => backend}/autometabuilder/plugins/__init__.py (100%) rename {src => backend}/autometabuilder/plugins/hello.py (100%) rename {src => backend}/autometabuilder/prompt_loader.py (100%) rename {src => backend}/autometabuilder/roadmap_utils.py (100%) rename {src => backend}/autometabuilder/tool_map_builder.py (100%) rename {src => backend}/autometabuilder/tool_policies.json (100%) rename {src => backend}/autometabuilder/tool_policy_loader.py (100%) rename {src => backend}/autometabuilder/tool_registry.json (100%) rename {src => backend}/autometabuilder/tool_registry_loader.py (100%) rename {src => backend}/autometabuilder/tools.json (100%) rename {src => backend}/autometabuilder/tools/__init__.py (100%) rename {src => backend}/autometabuilder/tools/edit_file.py (100%) rename {src => backend}/autometabuilder/tools/list_files.py (100%) rename {src => backend}/autometabuilder/tools/read_file.py (100%) rename {src => backend}/autometabuilder/tools/run_docker_task.py (100%) rename {src => backend}/autometabuilder/tools/run_lint.py (100%) rename {src => backend}/autometabuilder/tools/run_tests.py (100%) rename {src => backend}/autometabuilder/tools/write_file.py (100%) rename {src => backend}/autometabuilder/tools_loader.py (100%) rename {src => backend}/autometabuilder/web/__init__.py (100%) create mode 100644 backend/autometabuilder/web/data.py rename {src => backend}/autometabuilder/web/navigation_items.json (100%) create mode 100644 backend/autometabuilder/web/server.py rename {src => backend}/autometabuilder/web/ui_assets.json (100%) rename {src => backend}/autometabuilder/workflow.json (100%) rename {src => backend}/autometabuilder/workflow/__init__.py (100%) rename {src => backend}/autometabuilder/workflow/engine.py (100%) rename {src => backend}/autometabuilder/workflow/input_resolver.py (100%) rename {src => backend}/autometabuilder/workflow/loop_executor.py (100%) rename {src => backend}/autometabuilder/workflow/node_executor.py (100%) rename {src => backend}/autometabuilder/workflow/plugin_loader.py (100%) rename {src => backend}/autometabuilder/workflow/plugin_map.json (100%) rename {src => backend}/autometabuilder/workflow/plugin_registry.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/core_ai_request.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/core_append_context_message.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/core_append_tool_results.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/core_append_user_instruction.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/core_load_context.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/core_run_tool_calls.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/core_seed_messages.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/tools_create_branch.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/tools_create_pull_request.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/tools_list_files.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/tools_read_file.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/tools_run_lint.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/tools_run_tests.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/utils_branch_condition.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/utils_filter_list.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/utils_map_list.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/utils_not.py (100%) rename {src => backend}/autometabuilder/workflow/plugins/utils_reduce_list.py (100%) rename {src => backend}/autometabuilder/workflow/runtime.py (100%) rename {src => backend}/autometabuilder/workflow/tool_calls_handler.py (100%) rename {src => backend}/autometabuilder/workflow/tool_runner.py (100%) rename {src => backend}/autometabuilder/workflow/value_helpers.py (100%) rename {src => backend}/autometabuilder/workflow_config_loader.py (100%) rename {src => backend}/autometabuilder/workflow_context_builder.py (100%) rename {src => backend}/autometabuilder/workflow_engine_builder.py (100%) rename {src => backend}/autometabuilder/workflow_packages/blank.json (100%) rename {src => backend}/autometabuilder/workflow_packages/contextual_iterative_loop.json (100%) rename {src => backend}/autometabuilder/workflow_packages/game_tick_loop.json (100%) rename {src => backend}/autometabuilder/workflow_packages/iterative_loop.json (100%) rename {src => backend}/autometabuilder/workflow_packages/plan_execute_summarize.json (100%) rename {src => backend}/autometabuilder/workflow_packages/repo_scan_context.json (100%) rename {src => backend}/autometabuilder/workflow_packages/single_pass.json (100%) rename {src => backend}/autometabuilder/workflow_packages/testing_triangle.json (100%) rename env_example => backend/env_example (100%) rename poetry.lock => backend/poetry.lock (100%) rename prompt.yml => backend/prompt.yml (100%) rename pyproject.toml => backend/pyproject.toml (81%) rename docker-compose.yml => deploy/docker-compose.yml (73%) create mode 100644 frontend/.eslintrc.json create mode 100644 frontend/components/layout/PageLayout.tsx create mode 100644 frontend/components/layout/Sidebar.tsx create mode 100644 frontend/components/sections/DashboardSection.tsx create mode 100644 frontend/components/sections/PromptSection.tsx create mode 100644 frontend/components/sections/SettingsSection.tsx create mode 100644 frontend/components/sections/TranslationsSection.tsx create mode 100644 frontend/components/sections/WorkflowSection.tsx create mode 100644 frontend/next-env.d.ts create mode 100644 frontend/package.json create mode 100644 frontend/pages/_app.tsx create mode 100644 frontend/pages/index.tsx create mode 100644 frontend/styles/_variables.scss create mode 100644 frontend/styles/globals.scss create mode 100644 frontend/tsconfig.json delete mode 100644 src/autometabuilder/web/server.py delete mode 100644 src/autometabuilder/web/static/css/main.css delete mode 100644 src/autometabuilder/web/static/css/workflow_palette.css delete mode 100644 src/autometabuilder/web/static/js/app_context.js delete mode 100644 src/autometabuilder/web/static/js/index.js delete mode 100644 src/autometabuilder/web/static/js/plugin_registry.js delete mode 100644 src/autometabuilder/web/static/js/plugins/choices_manager.js delete mode 100644 src/autometabuilder/web/static/js/plugins/form_validator.js delete mode 100644 src/autometabuilder/web/static/js/plugins/navigation_loader.js delete mode 100644 src/autometabuilder/web/static/js/plugins/navigation_manager.js delete mode 100644 src/autometabuilder/web/static/js/plugins/prompt_builder.js delete mode 100644 src/autometabuilder/web/static/js/plugins/run_mode_toggle.js delete mode 100644 src/autometabuilder/web/static/js/plugins/status_poller.js delete mode 100644 src/autometabuilder/web/static/js/plugins/theme_manager.js delete mode 100644 src/autometabuilder/web/static/js/plugins/translation_editor_actions.js delete mode 100644 src/autometabuilder/web/static/js/plugins/translation_editor_base.js delete mode 100644 src/autometabuilder/web/static/js/plugins/translation_editor_network.js delete mode 100644 src/autometabuilder/web/static/js/plugins/translation_editor_render.js delete mode 100644 src/autometabuilder/web/static/js/plugins/workflow_builder.js delete mode 100644 src/autometabuilder/web/static/js/plugins/workflow_palette.js delete mode 100644 src/autometabuilder/web/static/js/plugins/workflow_templates.js delete mode 100644 src/autometabuilder/web/static/js/plugins/workflow_toggle.js delete mode 100644 src/autometabuilder/web/static/js/services/toast.js delete mode 100644 src/autometabuilder/web/static/js/workflow/workflow_builder.js delete mode 100644 src/autometabuilder/web/static/js/workflow/workflow_canvas_renderer.js delete mode 100644 src/autometabuilder/web/static/js/workflow/workflow_field_renderer.js delete mode 100644 src/autometabuilder/web/static/js/workflow/workflow_loop_renderer.js delete mode 100644 src/autometabuilder/web/static/js/workflow/workflow_mutations.js delete mode 100644 src/autometabuilder/web/static/js/workflow/workflow_node_events.js delete mode 100644 src/autometabuilder/web/static/js/workflow/workflow_node_renderer.js delete mode 100644 src/autometabuilder/web/static/js/workflow/workflow_node_template.js delete mode 100644 src/autometabuilder/web/static/js/workflow/workflow_palette.js delete mode 100644 src/autometabuilder/web/static/js/workflow/workflow_plugin_options.js delete mode 100644 src/autometabuilder/web/static/js/workflow/workflow_state.js delete mode 100644 src/autometabuilder/web/static/js/workflow/workflow_utils.js delete mode 100644 src/autometabuilder/web/templates/base.html delete mode 100644 src/autometabuilder/web/templates/components/atoms/helper_text.html delete mode 100644 src/autometabuilder/web/templates/components/atoms/icon.html delete mode 100644 src/autometabuilder/web/templates/components/atoms/nav_link.html delete mode 100644 src/autometabuilder/web/templates/components/atoms/pill.html delete mode 100644 src/autometabuilder/web/templates/components/atoms/section_header.html delete mode 100644 src/autometabuilder/web/templates/components/molecules/card.html delete mode 100644 src/autometabuilder/web/templates/components/molecules/empty_state.html delete mode 100644 src/autometabuilder/web/templates/components/molecules/sidebar_nav.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/callout.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/dashboard_bot_control.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/dashboard_logs.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/dashboard_status.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/prompt_builder.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/prompt_guidance.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/settings_api_keys.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/settings_configuration.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/settings_other.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/settings_web_access.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/sidebar.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/sidebar_footer.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/sidebar_header.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/translations_editor.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/translations_languages.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/workflow_palette.html delete mode 100644 src/autometabuilder/web/templates/components/organisms/workflow_templates.html delete mode 100644 src/autometabuilder/web/templates/components/sections/choice_card.html delete mode 100644 src/autometabuilder/web/templates/components/sections/dashboard_section.html delete mode 100644 src/autometabuilder/web/templates/components/sections/prompt_chip.html delete mode 100644 src/autometabuilder/web/templates/components/sections/prompt_section.html delete mode 100644 src/autometabuilder/web/templates/components/sections/prompt_step.html delete mode 100644 src/autometabuilder/web/templates/components/sections/settings_section.html delete mode 100644 src/autometabuilder/web/templates/components/sections/translations_section.html delete mode 100644 src/autometabuilder/web/templates/components/sections/workflow_section.html delete mode 100644 src/autometabuilder/web/templates/index.html diff --git a/.gitignore b/.gitignore index 2fb4031..a036bc1 100644 --- a/.gitignore +++ b/.gitignore @@ -114,7 +114,7 @@ celerybeat.pid *.sage.py # Environments -.env +backend/.env .venv env/ venv/ @@ -154,3 +154,8 @@ cmake-build-*/ # VS Code .vscode/ +frontend/.next/ +frontend/node_modules/ +frontend/.env.local +frontend/.env.development.local +frontend/.env.production.local diff --git a/.pylint_cache/src_1.stats b/.pylint_cache/src_1.stats deleted file mode 100644 index 36012ce2bcd2a9b1caaeec4b6de4a8085e1dd84b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3089 zcmb7GOK&SR6mEK(rs?}dDZPD!3st$OlM1nb1q&n=S12GMSh5&7GtP|F8GG;}B@57H z$HEeoZh&9H58$8hQ#i+-Nt0<>XrxhWpYxrU?eF+?^Y`WT1^2Uu#VBK3ca3J5>f(?} zrHNK!yY`ivedlIx#xH*v|1|!2Ow3aw%US~up9BoB7 z3Q@rNMpIl{^J|gd%E6lDXwkMAhY;wHI4dgy!z0ZEN6>Okbt+;%6tT&isTELVr0*v! zJt`_}yC9O}s-O`f)=P;tg;#Ck0?8P`APpon3UhB1b6o#IGS2ZM2Gu0n`I$g&Kk zNu?A%(*e;WLmx|w4+IWYBpr}QdwCm+Nvi_2ZiwWJC(h}MX)hfiJK$r$5+ez^=?oZz z3eluTy@m8Se8=#ez;_DY8GId#{E!$epfsd!SQb;+4MWD64#N_YX3gjl?3lrZRNru!Og2L15bZ0B;z3 zQin@H;+zyS_?0>MBk#Ub#}}DN7+3Z3JyQ95Ayg((nq{I)p)n_fXAe~1hW4M}{-~Y- z!WET6Dofv&HQ%_0pWz<9W$bw!J+*mHDZ+=3+TlX80gK#uc60$}dETZ55LD9`yNuUR zB^bZm(~>Z_e@SqYGEG%MBDnGI*bTgsffgdj1YV?FdyjNbAHFY zHG9y<;}OswBU<3y3L;{X6u75tchM5u^-)j}88E^#doo!rgkp#x*{sIaL?aUs$pE!z zw+uIm#uLSHZ`&T_Oeq&#NoE0@bRX!rcWMvN%z)kmh3RK33Ovh!wT9ijk&t1)@(1x&iD{$Ee?>OF{HOExY3HmSU6z7AqB=-vfD`}`jFQYMK$am zk}+t?z__q);BsR$Rc?2L+pznFBg4WTL(-H-B8EiK>v3thQV!rG1keXq!YNSrqCFje zSGQScUl?8Aw1(X%i|G@95DYXE5z`QTXfYhyQj{Z!e^egjj_m5i=xC;AFmv0IGB_T@b3eeQF*@6FSlrZ}f{HczV}aHsM9 zJdKiQu2Li#r}pkVH6Vm5PY4f(ggP@0FXmaQ9L{KdG*5GyMy_VA|HJ9bP`6XN{7=)< zk=)w#m==`BZ~|HRELj?nJR8HFrsubIQ&UbNrbk^#wH&$S3lywWg1e>VSis`YL(`9M z?Xm#VgjKe-YRBUa`G4AC8PMa+uT*-B;7gUKux|;u*R^J`#HmKrGIfork1rQ8u6KaBFx01jssX)pG1}Q~* zl?VxnMff0^z_uqc8W{N{9}6o-fOEIDQv=C>1OZKwB1`w zw|eL4c5lttb;E%t+>;up65oHDy%SJb0F?%)Gz~P-?`y4n6hsRuZ?1m*=XLrA82j@srhfNdu|{!g diff --git a/.pylint_cache_run/src_1.stats b/.pylint_cache_run/src_1.stats deleted file mode 100644 index c211c30e00dfaa2169fde9adf6faa092a48a1995..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11354 zcmbta>u=n~5tn4ik}TPBEW>sDlwH5lgr_)tq)D41MFJScHAq{3DUc5YkK8+M#3NZg zbXI}1HS%?fUXcrme(t}~Kdv*gySyX0e5f@b_(;yo&dkot&i;1)y7m2+@2$~4aWg&( zc$f|Hj0foef3hUaoGe|4z2DH&D|-5F@y?sYH;ZRtcjS0>=uBBkk2_8>$)_yL7Q;2M z>10`gKekQ+Cr$C!fs4Ov{J=+f#_-*qeCI}CN^D!|*M`{TA*jGk9g?y$&OdQm(PRSiV#_IL(SKhG zs3{O9(KOEN0Q6u<3;%9|0x)pKUiT27ET}6GTMC6pKMSEs>sf&jC*Tf&w!<55)tsgbY=PqU=IB1c9s7*Hy$S{!msYErWW zlhT9Y&~3{_DWR4VXiM6g{Ylk^S(KcNgJ`CLx?9k;)T35XASP@m^HlH~s?m;Qt>u-f z4Jk`bx!YFGt~3ZxVJQphS<5u2fT(EzWt|0f!qO->ZOzP0sll^0H&TjrhlHBYTUAjk zJnfzZm0(Y+%*AxF5E7mBh)h-IYic-gY$tgbwz|WT?x$RZbXX ze9T>1_;s3@mOq@7tz0~)3e&N14!6`MwvYj#k@0C$vaUn#q2jwSLXR6}Urp<~MBcB{GjQ;X#LJ>_$#0e{RHZ1b8$s*d<4{X{}> zvX`;ZB34D%NBzVqN6Um{X&%4^xLIW-`+28qlm{IgG@~|d=h|ed!07g@l$kKthIecc z&npsL3v<;&%j2Gw<7^?O(Bey_WcTz-yIn9mgXSl3Lf7vW`*BZ2mDo5BuvhE~S*3G# zy`k+aP7|Oi6b3CCzb%Vcw`-+P+?-%wwMbN9+E>kldASSav0bRDFdue0R;no{3M-h$ z2|a1fD%{%xqEYLVid98daVZ&krWV`P6xFr^6h;3}nfD=Q5{|vH>W&J@wEg7EpQa9kObasiMt9gvc~eA zMNlcgAJoDxhMVFtVuu!3X9W=geiy|pEl|Unt0EtWeI7!y%RLLh)x~f_{D4p6D9NlS z&rvB$f<@ZHj}!upokd6W#&7cmV!jHe$q3xnMg)fwGA& z5#Zf+0UlP6_wGtq0Pf8I1Uy5Utt^tba4s&(07?~V{&$GECu!nV3;i)D5~RmPSs27; z3-P#_Py@Y0_mPQC7tUitK%yyzQ8d*kU zn+Gl-zeLtU1lcY4(&M&m42U_T=Kp>YH@I{u&MaHXZ75$>Bt(70W* zvT{0#%1MOn?knvziT)R+p=<7=ofpM6;>5JEBkq9T2B1E^S?<7X!G!+WU zttt_I+~1PYc8{2U-HTbOXXrLbMn6}UWXS%CxQ%I4#!rdv9h0Ugv<%-j%Pd2xMEAfX z6M(j33A7Q-XGR(YQWrIf0>!-VZPtifLZuUT8$@^9V>D>>_2FACh2WSS;aZ zqUpDE)sP$F{m`U%p^5gKOqlY*+K*EPV}WAOn9o|rEX{$@{N*74iF@8EPMc6{d5Fgx zsjDZDL}r{PO7xYJEuy?_QUZ^I>8mk3mMOQggCO#EO~Q&vq48lZ;Pip0jpStS&dn9TDp4`z-5D-R+f z`@B`Q_SkB{ts;RW=I6b{P&^QLK%20XSXK_#uiRRJ|!nn^{XnaQHK}JdMi+SmCmTQnk%}ifYRn- z-(!e0!$y#+i#@etvt`*{z!t`TJQo+GpXl)^$dHeNmuZ?a{qmZ6`CCBNey@NvWC!{y z8QeH!;~zqn3MeP1bNsu1_qLm36AsWnasxO##)vl~rF8))IyY%h!0+$hFxb zQr$sU)U2J^ua+D=cx}d3PUh91jj>uTiCSV~tXA7?&Cr-?mBmTZZ;u^-++t48U(Ll^ z>KRH{8Uy+U#S=A$FW2-JxcwI+EC?W=`gEv2A$rGML_G_(tHn1s&IM3ZmPL?PoA?s& zL88CKakq20X%i)(9&9%a9QVXdy%Tz4&&Ac^&48{k%CX_Yw#QRo^)z9l^DC$FXx8`s zzx?lf=KsV0XIq7lO~-1moEXxwypEANGlK_8m=jU`WnMo%Sncozr4El+-uU0n#ktO* z(cCw4Q48_aZh%Dpd!CD{9$Y!an;mdGjEFEDu8G5NWY<0bYIqZFIknJZuM8c3cev{xz=eaW!_RZEpNF6e-O2^z6%Sml3?Bf=8j!33$yN@B(=RKR zUiRVA%b)Og_ieGAo^UvLrn|O#64kZAacuG8(}&mpHrSl~=j(6Q*Vcw>U;i2YTWU5M F{1=C+UKjuX diff --git a/Dockerfile b/backend/Dockerfile similarity index 97% rename from Dockerfile rename to backend/Dockerfile index a5c2977..14c44a6 100644 --- a/Dockerfile +++ b/backend/Dockerfile @@ -13,7 +13,7 @@ RUN apt-get update && apt-get install -y \ RUN pip install poetry # Copy the current directory contents into the container at /app -COPY . /app +COPY .. /app # Install project dependencies RUN poetry config virtualenvs.create false \ diff --git a/src/autometabuilder/__init__.py b/backend/autometabuilder/__init__.py similarity index 100% rename from src/autometabuilder/__init__.py rename to backend/autometabuilder/__init__.py diff --git a/src/autometabuilder/app_runner.py b/backend/autometabuilder/app_runner.py similarity index 100% rename from src/autometabuilder/app_runner.py rename to backend/autometabuilder/app_runner.py diff --git a/src/autometabuilder/callable_loader.py b/backend/autometabuilder/callable_loader.py similarity index 100% rename from src/autometabuilder/callable_loader.py rename to backend/autometabuilder/callable_loader.py diff --git a/src/autometabuilder/cli_args.py b/backend/autometabuilder/cli_args.py similarity index 100% rename from src/autometabuilder/cli_args.py rename to backend/autometabuilder/cli_args.py diff --git a/src/autometabuilder/context_loader.py b/backend/autometabuilder/context_loader.py similarity index 100% rename from src/autometabuilder/context_loader.py rename to backend/autometabuilder/context_loader.py diff --git a/src/autometabuilder/docker_utils.py b/backend/autometabuilder/docker_utils.py similarity index 100% rename from src/autometabuilder/docker_utils.py rename to backend/autometabuilder/docker_utils.py diff --git a/src/autometabuilder/env_loader.py b/backend/autometabuilder/env_loader.py similarity index 100% rename from src/autometabuilder/env_loader.py rename to backend/autometabuilder/env_loader.py diff --git a/src/autometabuilder/github_integration.py b/backend/autometabuilder/github_integration.py similarity index 100% rename from src/autometabuilder/github_integration.py rename to backend/autometabuilder/github_integration.py diff --git a/src/autometabuilder/github_service.py b/backend/autometabuilder/github_service.py similarity index 100% rename from src/autometabuilder/github_service.py rename to backend/autometabuilder/github_service.py diff --git a/src/autometabuilder/integrations/__init__.py b/backend/autometabuilder/integrations/__init__.py similarity index 100% rename from src/autometabuilder/integrations/__init__.py rename to backend/autometabuilder/integrations/__init__.py diff --git a/src/autometabuilder/integrations/notifications.py b/backend/autometabuilder/integrations/notifications.py similarity index 100% rename from src/autometabuilder/integrations/notifications.py rename to backend/autometabuilder/integrations/notifications.py diff --git a/src/autometabuilder/logging_config.py b/backend/autometabuilder/logging_config.py similarity index 100% rename from src/autometabuilder/logging_config.py rename to backend/autometabuilder/logging_config.py diff --git a/src/autometabuilder/main.py b/backend/autometabuilder/main.py similarity index 100% rename from src/autometabuilder/main.py rename to backend/autometabuilder/main.py diff --git a/src/autometabuilder/messages_en.json b/backend/autometabuilder/messages_en.json similarity index 100% rename from src/autometabuilder/messages_en.json rename to backend/autometabuilder/messages_en.json diff --git a/src/autometabuilder/messages_es.json b/backend/autometabuilder/messages_es.json similarity index 100% rename from src/autometabuilder/messages_es.json rename to backend/autometabuilder/messages_es.json diff --git a/src/autometabuilder/messages_fr.json b/backend/autometabuilder/messages_fr.json similarity index 100% rename from src/autometabuilder/messages_fr.json rename to backend/autometabuilder/messages_fr.json diff --git a/src/autometabuilder/messages_nl.json b/backend/autometabuilder/messages_nl.json similarity index 100% rename from src/autometabuilder/messages_nl.json rename to backend/autometabuilder/messages_nl.json diff --git a/src/autometabuilder/messages_pirate.json b/backend/autometabuilder/messages_pirate.json similarity index 100% rename from src/autometabuilder/messages_pirate.json rename to backend/autometabuilder/messages_pirate.json diff --git a/src/autometabuilder/metadata.json b/backend/autometabuilder/metadata.json similarity index 100% rename from src/autometabuilder/metadata.json rename to backend/autometabuilder/metadata.json diff --git a/src/autometabuilder/metadata_loader.py b/backend/autometabuilder/metadata_loader.py similarity index 100% rename from src/autometabuilder/metadata_loader.py rename to backend/autometabuilder/metadata_loader.py diff --git a/src/autometabuilder/model_resolver.py b/backend/autometabuilder/model_resolver.py similarity index 100% rename from src/autometabuilder/model_resolver.py rename to backend/autometabuilder/model_resolver.py diff --git a/src/autometabuilder/openai_client.py b/backend/autometabuilder/openai_client.py similarity index 100% rename from src/autometabuilder/openai_client.py rename to backend/autometabuilder/openai_client.py diff --git a/src/autometabuilder/openai_factory.py b/backend/autometabuilder/openai_factory.py similarity index 100% rename from src/autometabuilder/openai_factory.py rename to backend/autometabuilder/openai_factory.py diff --git a/src/autometabuilder/plugin_loader.py b/backend/autometabuilder/plugin_loader.py similarity index 100% rename from src/autometabuilder/plugin_loader.py rename to backend/autometabuilder/plugin_loader.py diff --git a/src/autometabuilder/plugins/__init__.py b/backend/autometabuilder/plugins/__init__.py similarity index 100% rename from src/autometabuilder/plugins/__init__.py rename to backend/autometabuilder/plugins/__init__.py diff --git a/src/autometabuilder/plugins/hello.py b/backend/autometabuilder/plugins/hello.py similarity index 100% rename from src/autometabuilder/plugins/hello.py rename to backend/autometabuilder/plugins/hello.py diff --git a/src/autometabuilder/prompt_loader.py b/backend/autometabuilder/prompt_loader.py similarity index 100% rename from src/autometabuilder/prompt_loader.py rename to backend/autometabuilder/prompt_loader.py diff --git a/src/autometabuilder/roadmap_utils.py b/backend/autometabuilder/roadmap_utils.py similarity index 100% rename from src/autometabuilder/roadmap_utils.py rename to backend/autometabuilder/roadmap_utils.py diff --git a/src/autometabuilder/tool_map_builder.py b/backend/autometabuilder/tool_map_builder.py similarity index 100% rename from src/autometabuilder/tool_map_builder.py rename to backend/autometabuilder/tool_map_builder.py diff --git a/src/autometabuilder/tool_policies.json b/backend/autometabuilder/tool_policies.json similarity index 100% rename from src/autometabuilder/tool_policies.json rename to backend/autometabuilder/tool_policies.json diff --git a/src/autometabuilder/tool_policy_loader.py b/backend/autometabuilder/tool_policy_loader.py similarity index 100% rename from src/autometabuilder/tool_policy_loader.py rename to backend/autometabuilder/tool_policy_loader.py diff --git a/src/autometabuilder/tool_registry.json b/backend/autometabuilder/tool_registry.json similarity index 100% rename from src/autometabuilder/tool_registry.json rename to backend/autometabuilder/tool_registry.json diff --git a/src/autometabuilder/tool_registry_loader.py b/backend/autometabuilder/tool_registry_loader.py similarity index 100% rename from src/autometabuilder/tool_registry_loader.py rename to backend/autometabuilder/tool_registry_loader.py diff --git a/src/autometabuilder/tools.json b/backend/autometabuilder/tools.json similarity index 100% rename from src/autometabuilder/tools.json rename to backend/autometabuilder/tools.json diff --git a/src/autometabuilder/tools/__init__.py b/backend/autometabuilder/tools/__init__.py similarity index 100% rename from src/autometabuilder/tools/__init__.py rename to backend/autometabuilder/tools/__init__.py diff --git a/src/autometabuilder/tools/edit_file.py b/backend/autometabuilder/tools/edit_file.py similarity index 100% rename from src/autometabuilder/tools/edit_file.py rename to backend/autometabuilder/tools/edit_file.py diff --git a/src/autometabuilder/tools/list_files.py b/backend/autometabuilder/tools/list_files.py similarity index 100% rename from src/autometabuilder/tools/list_files.py rename to backend/autometabuilder/tools/list_files.py diff --git a/src/autometabuilder/tools/read_file.py b/backend/autometabuilder/tools/read_file.py similarity index 100% rename from src/autometabuilder/tools/read_file.py rename to backend/autometabuilder/tools/read_file.py diff --git a/src/autometabuilder/tools/run_docker_task.py b/backend/autometabuilder/tools/run_docker_task.py similarity index 100% rename from src/autometabuilder/tools/run_docker_task.py rename to backend/autometabuilder/tools/run_docker_task.py diff --git a/src/autometabuilder/tools/run_lint.py b/backend/autometabuilder/tools/run_lint.py similarity index 100% rename from src/autometabuilder/tools/run_lint.py rename to backend/autometabuilder/tools/run_lint.py diff --git a/src/autometabuilder/tools/run_tests.py b/backend/autometabuilder/tools/run_tests.py similarity index 100% rename from src/autometabuilder/tools/run_tests.py rename to backend/autometabuilder/tools/run_tests.py diff --git a/src/autometabuilder/tools/write_file.py b/backend/autometabuilder/tools/write_file.py similarity index 100% rename from src/autometabuilder/tools/write_file.py rename to backend/autometabuilder/tools/write_file.py diff --git a/src/autometabuilder/tools_loader.py b/backend/autometabuilder/tools_loader.py similarity index 100% rename from src/autometabuilder/tools_loader.py rename to backend/autometabuilder/tools_loader.py diff --git a/src/autometabuilder/web/__init__.py b/backend/autometabuilder/web/__init__.py similarity index 100% rename from src/autometabuilder/web/__init__.py rename to backend/autometabuilder/web/__init__.py diff --git a/backend/autometabuilder/web/data.py b/backend/autometabuilder/web/data.py new file mode 100644 index 0000000..c54dd35 --- /dev/null +++ b/backend/autometabuilder/web/data.py @@ -0,0 +1,240 @@ +"""Helpers for loading metadata, translations, and workflow assets.""" +from __future__ import annotations + +import json +import os +import shutil +from pathlib import Path +from typing import Any, Dict, Iterable, List, Optional + +PACKAGE_ROOT = Path(__file__).resolve().parents[1] +REPO_ROOT = PACKAGE_ROOT.parent.parent +LOG_FILE = REPO_ROOT / "autometabuilder.log" + + +def _read_json(path: Path) -> Dict[str, Any]: + if not path.exists(): + return {} + try: + return json.loads(path.read_text(encoding="utf-8")) + except json.JSONDecodeError: + return {} + + +def build_prompt_yaml(system_content: str | None, user_content: str | None, model: str | None) -> str: + def indent_block(text: str | None) -> str: + if not text: + return "" + return "\n ".join(line.rstrip() for line in text.splitlines()) + + model_value = model or "openai/gpt-4o" + system_block = indent_block(system_content) + user_block = indent_block(user_content) + return f\"\"\"messages: + - role: system + content: >- + {system_block} + - role: user + content: >- + {user_block} +model: {model_value} +\"\"\" + + +def load_metadata() -> Dict[str, Any]: + metadata_path = PACKAGE_ROOT / "metadata.json" + return _read_json(metadata_path) + + +def write_metadata(metadata: Dict[str, Any]) -> None: + path = PACKAGE_ROOT / "metadata.json" + path.write_text(json.dumps(metadata, indent=2, ensure_ascii=False), encoding="utf-8") + + +def get_messages_map(metadata: Optional[Dict[str, Any]] = None) -> Dict[str, str]: + metadata = metadata or load_metadata() + return metadata.get("messages", {}) + + +def load_translation(lang: str) -> Dict[str, Any]: + messages_map = get_messages_map() + target = messages_map.get(lang) + if not target: + return {} + return _read_json(PACKAGE_ROOT / target) + + +def list_translations() -> Dict[str, str]: + messages_map = get_messages_map() + if messages_map: + return messages_map + # falling back to files on disk + fallback = {} + for candidate in PACKAGE_ROOT.glob("messages_*.json"): + name = candidate.name + language = name.removeprefix("messages_").removesuffix(".json") + fallback[language] = name + return fallback + + +def get_ui_messages(lang: str) -> Dict[str, Any]: + messages_map = get_messages_map() + base_name = messages_map.get("en", "messages_en.json") + base = _read_json(PACKAGE_ROOT / base_name) + localized = _read_json(PACKAGE_ROOT / messages_map.get(lang, base_name)) + merged = dict(base) + merged.update(localized) + merged["__lang"] = lang + return merged + + +def get_prompt_content() -> str: + path = Path(os.environ.get("PROMPT_PATH", "prompt.yml")) + if path.is_file(): + return path.read_text(encoding="utf-8") + return "" + + +def write_prompt(content: str) -> None: + path = Path(os.environ.get("PROMPT_PATH", "prompt.yml")) + path.write_text(content or "", encoding="utf-8") + + +def get_workflow_content() -> str: + metadata = load_metadata() + workflow_name = metadata.get("workflow_path", "workflow.json") + workflow_path = PACKAGE_ROOT / workflow_name + if workflow_path.exists(): + return workflow_path.read_text(encoding="utf-8") + return "" + + +def write_workflow(content: str) -> None: + metadata = load_metadata() + workflow_name = metadata.get("workflow_path", "workflow.json") + workflow_path = PACKAGE_ROOT / workflow_name + workflow_path.write_text(content or "", encoding="utf-8") + + +def get_navigation_items() -> List[Dict[str, Any]]: + nav_path = PACKAGE_ROOT / "web" / "navigation_items.json" + nav = _read_json(nav_path) + if isinstance(nav, list): + return nav + return [] + + +def get_workflow_packages_dir() -> Path: + metadata = load_metadata() + packages_name = metadata.get("workflow_packages_path", "workflow_packages") + return PACKAGE_ROOT / packages_name + + +def load_workflow_packages() -> List[Dict[str, Any]]: + packages_dir = get_workflow_packages_dir() + if not packages_dir.exists(): + return [] + packages: List[Dict[str, Any]] = [] + for file in sorted(packages_dir.iterdir()): + if file.suffix != ".json": + continue + data = _read_json(file) + if not isinstance(data, dict): + continue + pkg_id = data.get("id") or file.stem + data["id"] = pkg_id + data.setdefault("workflow", {"nodes": []}) + packages.append(data) + return packages + + +def summarize_workflow_packages(packages: Iterable[Dict[str, Any]]) -> List[Dict[str, Any]]: + summary = [] + for pkg in packages: + summary.append( + { + "id": pkg["id"], + "label": pkg.get("label") or pkg["id"], + "description": pkg.get("description", ""), + "tags": pkg.get("tags", []), + } + ) + return summary + + +def get_env_vars() -> Dict[str, str]: + env_path = Path(".env") + if not env_path.exists(): + return {} + result: Dict[str, str] = {} + for raw in env_path.read_text(encoding="utf-8").splitlines(): + line = raw.strip() + if not line or line.startswith("#"): + continue + if "=" not in line: + continue + key, value = line.split("=", 1) + value = value.strip().strip("'\"") + result[key.strip()] = value + return result + + +def persist_env_vars(updates: Dict[str, str]) -> None: + from dotenv import set_key + + env_path = Path(".env") + env_path.touch(exist_ok=True) + for key, value in updates.items(): + set_key(env_path, key, value) + + +def get_recent_logs(lines: int = 50) -> str: + if not LOG_FILE.exists(): + return "" + with LOG_FILE.open("r", encoding="utf-8") as handle: + content = handle.readlines() + return "".join(content[-lines:]) + + +def create_translation(lang: str) -> bool: + messages_map = get_messages_map() + if lang in messages_map: + return False + base = messages_map.get("en", "messages_en.json") + base_file = PACKAGE_ROOT / base + if not base_file.exists(): + return False + target_name = f"messages_{lang}.json" + target_path = PACKAGE_ROOT / target_name + shutil.copy(base_file, target_path) + messages_map[lang] = target_name + metadata = load_metadata() + metadata["messages"] = messages_map + write_metadata(metadata) + return True + + +def delete_translation(lang: str) -> bool: + if lang == "en": + return False + messages_map = get_messages_map() + if lang not in messages_map: + return False + target = PACKAGE_ROOT / messages_map[lang] + if target.exists(): + target.unlink() + del messages_map[lang] + metadata = load_metadata() + metadata["messages"] = messages_map + write_metadata(metadata) + return True + + +def update_translation(lang: str, payload: Dict[str, Any]) -> bool: + messages_map = get_messages_map() + if lang not in messages_map: + return False + payload_content = payload.get("content", {}) + target_path = PACKAGE_ROOT / messages_map[lang] + target_path.write_text(json.dumps(payload_content, indent=2, ensure_ascii=False), encoding="utf-8") + return True diff --git a/src/autometabuilder/web/navigation_items.json b/backend/autometabuilder/web/navigation_items.json similarity index 100% rename from src/autometabuilder/web/navigation_items.json rename to backend/autometabuilder/web/navigation_items.json diff --git a/backend/autometabuilder/web/server.py b/backend/autometabuilder/web/server.py new file mode 100644 index 0000000..236f311 --- /dev/null +++ b/backend/autometabuilder/web/server.py @@ -0,0 +1,237 @@ +"""Flask-based API surface that replaces the legacy FastAPI frontend.""" +from __future__ import annotations + +import os +import subprocess +import sys +import threading +import time +from typing import Dict + +from flask import Flask, request + +from ..roadmap_utils import is_mvp_reached +from .data import ( + build_prompt_yaml, + create_translation, + delete_translation, + get_env_vars, + get_navigation_items, + get_prompt_content, + get_recent_logs, + get_ui_messages, + get_workflow_content, + list_translations, + load_metadata, + load_translation, + load_workflow_packages, + persist_env_vars, + summarize_workflow_packages, + update_translation, + write_prompt, + write_workflow, +) + +app = Flask(__name__) +app.config["JSON_SORT_KEYS"] = False + +bot_process = None +mock_running = False +current_run_config: Dict[str, object] = {} + + +def _reset_run_state() -> None: + global bot_process, current_run_config + bot_process = None + current_run_config = {} + + +def run_bot_task(mode: str, iterations: int, yolo: bool, stop_at_mvp: bool) -> None: + global bot_process, mock_running, current_run_config + current_run_config = { + "mode": mode, + "iterations": iterations, + "yolo": yolo, + "stop_at_mvp": stop_at_mvp, + } + + if os.environ.get("MOCK_WEB_UI") == "true": + mock_running = True + time.sleep(5) + mock_running = False + _reset_run_state() + return + + try: + cmd = [sys.executable, "-m", "autometabuilder.main"] + if yolo: + cmd.append("--yolo") + if mode == "once": + cmd.append("--once") + if mode == "iterations" and iterations > 1: + for _ in range(iterations): + if stop_at_mvp and is_mvp_reached(): + break + bot_process = subprocess.Popen(cmd + ["--once"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + bot_process.wait() + else: + bot_process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + bot_process.wait() + finally: + _reset_run_state() + + +def start_bot(mode: str = "once", iterations: int = 1, yolo: bool = True, stop_at_mvp: bool = False) -> bool: + if bot_process is not None or mock_running: + return False + thread = threading.Thread(target=run_bot_task, args=(mode, iterations, yolo, stop_at_mvp), daemon=True) + thread.start() + return True + + +def build_context() -> Dict[str, object]: + lang = os.environ.get("APP_LANG", "en") + metadata = load_metadata() + packages = load_workflow_packages() + return { + "logs": get_recent_logs(), + "env_vars": get_env_vars(), + "translations": list_translations(), + "metadata": metadata, + "navigation": get_navigation_items(), + "prompt_content": get_prompt_content(), + "workflow_content": get_workflow_content(), + "workflow_packages": summarize_workflow_packages(packages), + "workflow_packages_raw": packages, + "messages": get_ui_messages(lang), + "lang": lang, + "status": { + "is_running": bot_process is not None or mock_running, + "mvp_reached": is_mvp_reached(), + "config": current_run_config, + }, + } + + +@app.route("/api/context") +def api_context() -> tuple[Dict[str, object], int]: + return build_context(), 200 + + +@app.route("/api/run", methods=["POST"]) +def api_run() -> tuple[Dict[str, object], int]: + payload = request.get_json(silent=True) or {} + mode = payload.get("mode", "once") + iterations = int(payload.get("iterations", 1)) + yolo = bool(payload.get("yolo", True)) + stop_at_mvp = bool(payload.get("stop_at_mvp", False)) + started = start_bot(mode, iterations, yolo, stop_at_mvp) + return {"started": started}, 202 if started else 409 + + +@app.route("/api/prompt", methods=["POST"]) +def api_prompt() -> tuple[Dict[str, str], int]: + payload = request.get_json(force=True) + content = payload.get("content") + system = payload.get("system_content") + user = payload.get("user_content") + model = payload.get("model") + mode = payload.get("prompt_mode", "builder") + if mode == "raw" and content is not None: + write_prompt(content) + else: + write_prompt(build_prompt_yaml(system, user, model)) + return {"status": "ok"}, 200 + + +@app.route("/api/workflow", methods=["POST"]) +def api_workflow() -> tuple[Dict[str, str], int]: + payload = request.get_json(force=True) + write_workflow(payload.get("content", "")) + return {"status": "saved"}, 200 + + +@app.route("/api/settings", methods=["POST"]) +def api_settings() -> tuple[Dict[str, str], int]: + payload = request.get_json(force=True) or {} + entries = payload.get("env", {}) or {} + persist_env_vars(entries) + return {"status": "ok"}, 200 + + +@app.route("/api/status") +def api_status() -> tuple[Dict[str, object], int]: + return build_context()["status"], 200 + + +@app.route("/api/logs") +def api_logs() -> tuple[Dict[str, str], int]: + return {"logs": get_recent_logs()}, 200 + + +@app.route("/api/translation-options") +def api_translation_options() -> tuple[Dict[str, Dict[str, str]], int]: + return {"translations": list_translations()}, 200 + + +@app.route("/api/translations", methods=["POST"]) +def api_create_translation() -> tuple[Dict[str, str], int]: + payload = request.get_json(force=True) + lang = payload.get("lang") + if not lang: + return {"error": "lang required"}, 400 + ok = create_translation(lang) + return ({"created": ok}, 201 if ok else 400) + + +@app.route("/api/translations/", methods=["GET"]) +def api_get_translation(lang: str) -> tuple[Dict[str, object], int]: + if lang not in load_metadata().get("messages", {}): + return {"error": "translation not found"}, 404 + return {"lang": lang, "content": load_translation(lang)}, 200 + + +@app.route("/api/translations/", methods=["PUT"]) +def api_update_translation(lang: str) -> tuple[Dict[str, str], int]: + payload = request.get_json(force=True) + updated = update_translation(lang, payload) + if not updated: + return {"error": "unable to update"}, 400 + return {"status": "saved"}, 200 + + +@app.route("/api/translations/", methods=["DELETE"]) +def api_delete_translation(lang: str) -> tuple[Dict[str, str], int]: + deleted = delete_translation(lang) + if not deleted: + return {"error": "cannot delete"}, 400 + return {"deleted": True}, 200 + + +@app.route("/api/navigation") +def api_navigation() -> tuple[Dict[str, object], int]: + return {"items": get_navigation_items()}, 200 + + +@app.route("/api/workflow/plugins") +def api_workflow_plugins() -> tuple[Dict[str, object], int]: + return {"plugins": load_metadata().get("workflow_plugins", {})}, 200 + + +@app.route("/api/workflow/packages") +def api_workflow_packages() -> tuple[Dict[str, object], int]: + packages = load_workflow_packages() + return {"packages": summarize_workflow_packages(packages)}, 200 + + +@app.route("/api/workflow/packages/") +def api_get_workflow_package(package_id: str) -> tuple[Dict[str, object], int]: + packages = load_workflow_packages() + for pkg in packages: + if pkg.get("id") == package_id: + return pkg, 200 + return {"error": "package not found"}, 404 + + +def start_web_ui(host: str = "0.0.0.0", port: int = 8000) -> None: + app.run(host=host, port=port) diff --git a/src/autometabuilder/web/ui_assets.json b/backend/autometabuilder/web/ui_assets.json similarity index 100% rename from src/autometabuilder/web/ui_assets.json rename to backend/autometabuilder/web/ui_assets.json diff --git a/src/autometabuilder/workflow.json b/backend/autometabuilder/workflow.json similarity index 100% rename from src/autometabuilder/workflow.json rename to backend/autometabuilder/workflow.json diff --git a/src/autometabuilder/workflow/__init__.py b/backend/autometabuilder/workflow/__init__.py similarity index 100% rename from src/autometabuilder/workflow/__init__.py rename to backend/autometabuilder/workflow/__init__.py diff --git a/src/autometabuilder/workflow/engine.py b/backend/autometabuilder/workflow/engine.py similarity index 100% rename from src/autometabuilder/workflow/engine.py rename to backend/autometabuilder/workflow/engine.py diff --git a/src/autometabuilder/workflow/input_resolver.py b/backend/autometabuilder/workflow/input_resolver.py similarity index 100% rename from src/autometabuilder/workflow/input_resolver.py rename to backend/autometabuilder/workflow/input_resolver.py diff --git a/src/autometabuilder/workflow/loop_executor.py b/backend/autometabuilder/workflow/loop_executor.py similarity index 100% rename from src/autometabuilder/workflow/loop_executor.py rename to backend/autometabuilder/workflow/loop_executor.py diff --git a/src/autometabuilder/workflow/node_executor.py b/backend/autometabuilder/workflow/node_executor.py similarity index 100% rename from src/autometabuilder/workflow/node_executor.py rename to backend/autometabuilder/workflow/node_executor.py diff --git a/src/autometabuilder/workflow/plugin_loader.py b/backend/autometabuilder/workflow/plugin_loader.py similarity index 100% rename from src/autometabuilder/workflow/plugin_loader.py rename to backend/autometabuilder/workflow/plugin_loader.py diff --git a/src/autometabuilder/workflow/plugin_map.json b/backend/autometabuilder/workflow/plugin_map.json similarity index 100% rename from src/autometabuilder/workflow/plugin_map.json rename to backend/autometabuilder/workflow/plugin_map.json diff --git a/src/autometabuilder/workflow/plugin_registry.py b/backend/autometabuilder/workflow/plugin_registry.py similarity index 100% rename from src/autometabuilder/workflow/plugin_registry.py rename to backend/autometabuilder/workflow/plugin_registry.py diff --git a/src/autometabuilder/workflow/plugins/core_ai_request.py b/backend/autometabuilder/workflow/plugins/core_ai_request.py similarity index 100% rename from src/autometabuilder/workflow/plugins/core_ai_request.py rename to backend/autometabuilder/workflow/plugins/core_ai_request.py diff --git a/src/autometabuilder/workflow/plugins/core_append_context_message.py b/backend/autometabuilder/workflow/plugins/core_append_context_message.py similarity index 100% rename from src/autometabuilder/workflow/plugins/core_append_context_message.py rename to backend/autometabuilder/workflow/plugins/core_append_context_message.py diff --git a/src/autometabuilder/workflow/plugins/core_append_tool_results.py b/backend/autometabuilder/workflow/plugins/core_append_tool_results.py similarity index 100% rename from src/autometabuilder/workflow/plugins/core_append_tool_results.py rename to backend/autometabuilder/workflow/plugins/core_append_tool_results.py diff --git a/src/autometabuilder/workflow/plugins/core_append_user_instruction.py b/backend/autometabuilder/workflow/plugins/core_append_user_instruction.py similarity index 100% rename from src/autometabuilder/workflow/plugins/core_append_user_instruction.py rename to backend/autometabuilder/workflow/plugins/core_append_user_instruction.py diff --git a/src/autometabuilder/workflow/plugins/core_load_context.py b/backend/autometabuilder/workflow/plugins/core_load_context.py similarity index 100% rename from src/autometabuilder/workflow/plugins/core_load_context.py rename to backend/autometabuilder/workflow/plugins/core_load_context.py diff --git a/src/autometabuilder/workflow/plugins/core_run_tool_calls.py b/backend/autometabuilder/workflow/plugins/core_run_tool_calls.py similarity index 100% rename from src/autometabuilder/workflow/plugins/core_run_tool_calls.py rename to backend/autometabuilder/workflow/plugins/core_run_tool_calls.py diff --git a/src/autometabuilder/workflow/plugins/core_seed_messages.py b/backend/autometabuilder/workflow/plugins/core_seed_messages.py similarity index 100% rename from src/autometabuilder/workflow/plugins/core_seed_messages.py rename to backend/autometabuilder/workflow/plugins/core_seed_messages.py diff --git a/src/autometabuilder/workflow/plugins/tools_create_branch.py b/backend/autometabuilder/workflow/plugins/tools_create_branch.py similarity index 100% rename from src/autometabuilder/workflow/plugins/tools_create_branch.py rename to backend/autometabuilder/workflow/plugins/tools_create_branch.py diff --git a/src/autometabuilder/workflow/plugins/tools_create_pull_request.py b/backend/autometabuilder/workflow/plugins/tools_create_pull_request.py similarity index 100% rename from src/autometabuilder/workflow/plugins/tools_create_pull_request.py rename to backend/autometabuilder/workflow/plugins/tools_create_pull_request.py diff --git a/src/autometabuilder/workflow/plugins/tools_list_files.py b/backend/autometabuilder/workflow/plugins/tools_list_files.py similarity index 100% rename from src/autometabuilder/workflow/plugins/tools_list_files.py rename to backend/autometabuilder/workflow/plugins/tools_list_files.py diff --git a/src/autometabuilder/workflow/plugins/tools_read_file.py b/backend/autometabuilder/workflow/plugins/tools_read_file.py similarity index 100% rename from src/autometabuilder/workflow/plugins/tools_read_file.py rename to backend/autometabuilder/workflow/plugins/tools_read_file.py diff --git a/src/autometabuilder/workflow/plugins/tools_run_lint.py b/backend/autometabuilder/workflow/plugins/tools_run_lint.py similarity index 100% rename from src/autometabuilder/workflow/plugins/tools_run_lint.py rename to backend/autometabuilder/workflow/plugins/tools_run_lint.py diff --git a/src/autometabuilder/workflow/plugins/tools_run_tests.py b/backend/autometabuilder/workflow/plugins/tools_run_tests.py similarity index 100% rename from src/autometabuilder/workflow/plugins/tools_run_tests.py rename to backend/autometabuilder/workflow/plugins/tools_run_tests.py diff --git a/src/autometabuilder/workflow/plugins/utils_branch_condition.py b/backend/autometabuilder/workflow/plugins/utils_branch_condition.py similarity index 100% rename from src/autometabuilder/workflow/plugins/utils_branch_condition.py rename to backend/autometabuilder/workflow/plugins/utils_branch_condition.py diff --git a/src/autometabuilder/workflow/plugins/utils_filter_list.py b/backend/autometabuilder/workflow/plugins/utils_filter_list.py similarity index 100% rename from src/autometabuilder/workflow/plugins/utils_filter_list.py rename to backend/autometabuilder/workflow/plugins/utils_filter_list.py diff --git a/src/autometabuilder/workflow/plugins/utils_map_list.py b/backend/autometabuilder/workflow/plugins/utils_map_list.py similarity index 100% rename from src/autometabuilder/workflow/plugins/utils_map_list.py rename to backend/autometabuilder/workflow/plugins/utils_map_list.py diff --git a/src/autometabuilder/workflow/plugins/utils_not.py b/backend/autometabuilder/workflow/plugins/utils_not.py similarity index 100% rename from src/autometabuilder/workflow/plugins/utils_not.py rename to backend/autometabuilder/workflow/plugins/utils_not.py diff --git a/src/autometabuilder/workflow/plugins/utils_reduce_list.py b/backend/autometabuilder/workflow/plugins/utils_reduce_list.py similarity index 100% rename from src/autometabuilder/workflow/plugins/utils_reduce_list.py rename to backend/autometabuilder/workflow/plugins/utils_reduce_list.py diff --git a/src/autometabuilder/workflow/runtime.py b/backend/autometabuilder/workflow/runtime.py similarity index 100% rename from src/autometabuilder/workflow/runtime.py rename to backend/autometabuilder/workflow/runtime.py diff --git a/src/autometabuilder/workflow/tool_calls_handler.py b/backend/autometabuilder/workflow/tool_calls_handler.py similarity index 100% rename from src/autometabuilder/workflow/tool_calls_handler.py rename to backend/autometabuilder/workflow/tool_calls_handler.py diff --git a/src/autometabuilder/workflow/tool_runner.py b/backend/autometabuilder/workflow/tool_runner.py similarity index 100% rename from src/autometabuilder/workflow/tool_runner.py rename to backend/autometabuilder/workflow/tool_runner.py diff --git a/src/autometabuilder/workflow/value_helpers.py b/backend/autometabuilder/workflow/value_helpers.py similarity index 100% rename from src/autometabuilder/workflow/value_helpers.py rename to backend/autometabuilder/workflow/value_helpers.py diff --git a/src/autometabuilder/workflow_config_loader.py b/backend/autometabuilder/workflow_config_loader.py similarity index 100% rename from src/autometabuilder/workflow_config_loader.py rename to backend/autometabuilder/workflow_config_loader.py diff --git a/src/autometabuilder/workflow_context_builder.py b/backend/autometabuilder/workflow_context_builder.py similarity index 100% rename from src/autometabuilder/workflow_context_builder.py rename to backend/autometabuilder/workflow_context_builder.py diff --git a/src/autometabuilder/workflow_engine_builder.py b/backend/autometabuilder/workflow_engine_builder.py similarity index 100% rename from src/autometabuilder/workflow_engine_builder.py rename to backend/autometabuilder/workflow_engine_builder.py diff --git a/src/autometabuilder/workflow_packages/blank.json b/backend/autometabuilder/workflow_packages/blank.json similarity index 100% rename from src/autometabuilder/workflow_packages/blank.json rename to backend/autometabuilder/workflow_packages/blank.json diff --git a/src/autometabuilder/workflow_packages/contextual_iterative_loop.json b/backend/autometabuilder/workflow_packages/contextual_iterative_loop.json similarity index 100% rename from src/autometabuilder/workflow_packages/contextual_iterative_loop.json rename to backend/autometabuilder/workflow_packages/contextual_iterative_loop.json diff --git a/src/autometabuilder/workflow_packages/game_tick_loop.json b/backend/autometabuilder/workflow_packages/game_tick_loop.json similarity index 100% rename from src/autometabuilder/workflow_packages/game_tick_loop.json rename to backend/autometabuilder/workflow_packages/game_tick_loop.json diff --git a/src/autometabuilder/workflow_packages/iterative_loop.json b/backend/autometabuilder/workflow_packages/iterative_loop.json similarity index 100% rename from src/autometabuilder/workflow_packages/iterative_loop.json rename to backend/autometabuilder/workflow_packages/iterative_loop.json diff --git a/src/autometabuilder/workflow_packages/plan_execute_summarize.json b/backend/autometabuilder/workflow_packages/plan_execute_summarize.json similarity index 100% rename from src/autometabuilder/workflow_packages/plan_execute_summarize.json rename to backend/autometabuilder/workflow_packages/plan_execute_summarize.json diff --git a/src/autometabuilder/workflow_packages/repo_scan_context.json b/backend/autometabuilder/workflow_packages/repo_scan_context.json similarity index 100% rename from src/autometabuilder/workflow_packages/repo_scan_context.json rename to backend/autometabuilder/workflow_packages/repo_scan_context.json diff --git a/src/autometabuilder/workflow_packages/single_pass.json b/backend/autometabuilder/workflow_packages/single_pass.json similarity index 100% rename from src/autometabuilder/workflow_packages/single_pass.json rename to backend/autometabuilder/workflow_packages/single_pass.json diff --git a/src/autometabuilder/workflow_packages/testing_triangle.json b/backend/autometabuilder/workflow_packages/testing_triangle.json similarity index 100% rename from src/autometabuilder/workflow_packages/testing_triangle.json rename to backend/autometabuilder/workflow_packages/testing_triangle.json diff --git a/env_example b/backend/env_example similarity index 100% rename from env_example rename to backend/env_example diff --git a/poetry.lock b/backend/poetry.lock similarity index 100% rename from poetry.lock rename to backend/poetry.lock diff --git a/prompt.yml b/backend/prompt.yml similarity index 100% rename from prompt.yml rename to backend/prompt.yml diff --git a/pyproject.toml b/backend/pyproject.toml similarity index 81% rename from pyproject.toml rename to backend/pyproject.toml index 1e05ada..43c8b78 100644 --- a/pyproject.toml +++ b/backend/pyproject.toml @@ -4,7 +4,7 @@ version = "0.1.0" description = "AutoMetabuilder" authors = ["Your Name "] readme = "README.md" -packages = [{include = "autometabuilder", from = "src"}] +packages = [{include = "autometabuilder", from = "backend"}] [tool.poetry.dependencies] python = "^3.10" @@ -14,12 +14,9 @@ python-dotenv = "^1.0.0" openai = "^1.0.0" PyGithub = "^2.1.1" tenacity = "^9.1.2" -fastapi = "^0.128.0" -uvicorn = "^0.40.0" -jinja2 = "^3.1.6" +flask = "^2.3.3" slack-sdk = "^3.39.0" discord-py = "^2.6.4" -python-multipart = "^0.0.21" [build-system] requires = ["poetry-core"] diff --git a/docker-compose.yml b/deploy/docker-compose.yml similarity index 73% rename from docker-compose.yml rename to deploy/docker-compose.yml index cb6b21d..ad4cfe1 100644 --- a/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -1,8 +1,8 @@ services: autometabuilder: - build: . + build: .. env_file: - - .env + - ../backend/.env volumes: - .:/app stdin_open: true diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json new file mode 100644 index 0000000..5fb860c --- /dev/null +++ b/frontend/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "next/core-web-vitals", + "rules": { + "react/react-in-jsx-scope": "off" + } +} diff --git a/frontend/components/layout/PageLayout.tsx b/frontend/components/layout/PageLayout.tsx new file mode 100644 index 0000000..2d12ba1 --- /dev/null +++ b/frontend/components/layout/PageLayout.tsx @@ -0,0 +1,26 @@ +import { ReactNode } from "react"; +import { NavigationItem } from "../../lib/types"; +import Sidebar from "./Sidebar"; + +type PageLayoutProps = { + navItems: NavigationItem[]; + section: string; + onSectionChange: (section: string) => void; + t: (key: string, fallback?: string) => string; + children: ReactNode; +}; + +export default function PageLayout({ navItems, section, onSectionChange, t, children }: PageLayoutProps) { + return ( +
+ +
+
+

{t("ui.app.title", "AutoMetabuilder Dashboard")}

+

{t("ui.dashboard.subtitle", "Control the bot and monitor system activity")}

+
+
{children}
+
+
+ ); +} diff --git a/frontend/components/layout/Sidebar.tsx b/frontend/components/layout/Sidebar.tsx new file mode 100644 index 0000000..bdf360e --- /dev/null +++ b/frontend/components/layout/Sidebar.tsx @@ -0,0 +1,31 @@ +import { NavigationItem } from "../../lib/types"; + +type SidebarProps = { + items: NavigationItem[]; + selected: string; + onSelect: (section: string) => void; + t: (key: string, fallback?: string) => string; +}; + +export default function Sidebar({ items, selected, onSelect, t }: SidebarProps) { + return ( + + ); +} diff --git a/frontend/components/sections/DashboardSection.tsx b/frontend/components/sections/DashboardSection.tsx new file mode 100644 index 0000000..dab4a32 --- /dev/null +++ b/frontend/components/sections/DashboardSection.tsx @@ -0,0 +1,78 @@ +import { useState } from "react"; +import { UIStatus } from "../../lib/types"; + +type DashboardSectionProps = { + status: UIStatus; + logs: string; + onRun: (payload: { mode?: string; iterations?: number; yolo?: boolean; stop_at_mvp?: boolean }) => Promise; + t: (key: string, fallback?: string) => string; +}; + +export default function DashboardSection({ status, logs, onRun, t }: DashboardSectionProps) { + const [mode, setMode] = useState("once"); + const [iterations, setIterations] = useState(1); + const [yolo, setYolo] = useState(true); + const [stopAtMvp, setStopAtMvp] = useState(false); + const [feedback, setFeedback] = useState(""); + + const handleRun = async () => { + setFeedback(t("ui.dashboard.status.bot_label", "Bot Status") + " — submitting"); + try { + await onRun({ mode, iterations, yolo, stop_at_mvp: stopAtMvp }); + setFeedback(t("ui.dashboard.start_bot", "Start Bot") + " " + t("ui.dashboard.status.running", "Running")); + } catch (error) { + console.error(error); + setFeedback(t("ui.dashboard.status.idle", "Idle")); + } + }; + + return ( +
+
+

{t("ui.dashboard.title", "Dashboard")}

+

{t("ui.dashboard.subtitle", "Control the bot and monitor system activity")}

+
+
+
+

{t("ui.dashboard.bot_control", "Bot Control")}

+
+ + + +
+ {mode === "iterations" && ( + + )} + + +

+ {status.is_running ? t("ui.dashboard.status.running", "Running") : t("ui.dashboard.status.idle", "Idle")} •{" "} + {status.mvp_reached ? t("ui.dashboard.status.mvp_reached", "Reached") : t("ui.dashboard.status.mvp_progress", "In Progress")} +

+

{feedback}

+
+
+

{t("ui.dashboard.logs.title", "Recent Logs")}

+
{logs.slice(-1200) || t("ui.dashboard.status.idle", "Idle")}
+
+
+
+ ); +} diff --git a/frontend/components/sections/PromptSection.tsx b/frontend/components/sections/PromptSection.tsx new file mode 100644 index 0000000..7474377 --- /dev/null +++ b/frontend/components/sections/PromptSection.tsx @@ -0,0 +1,38 @@ +import { useEffect, useState } from "react"; + +type PromptSectionProps = { + content: string; + onSave: (content: string) => Promise; + t: (key: string, fallback?: string) => string; +}; + +export default function PromptSection({ content, onSave, t }: PromptSectionProps) { + const [draft, setDraft] = useState(content); + const [message, setMessage] = useState(""); + + useEffect(() => { + setDraft(content); + }, [content]); + + const handleSave = async () => { + await onSave(draft); + setMessage(t("ui.prompt.save", "Save Prompt")); + setTimeout(() => setMessage(""), 2000); + }; + + return ( +
+
+

{t("ui.prompt.title", "Prompt Builder")}

+

{t("ui.prompt.subtitle", "Shape how the assistant thinks, speaks, and decides")}

+
+ - `; - } else if (type === 'number') { - inputHtml = ` - - `; - } else { - inputHtml = ` - - `; - } - - return ` -
- - ${inputHtml} -
- `; - }).join(''); - }; - - const renderNodeFields = (pluginDef, node) => { - const { t, escapeHtml } = window.AMBWorkflowUtils || {}; - const inputs = pluginDef.inputs || {}; - const outputs = pluginDef.outputs || {}; - const inputFields = renderFieldGroup(inputs, node.inputs || {}, 'inputs'); - const outputFields = renderFieldGroup(outputs, node.outputs || {}, 'outputs'); - - return ` -
-
${escapeHtml ? escapeHtml(t?.('ui.workflow.inputs_label', 'Inputs')) : t?.('ui.workflow.inputs_label', 'Inputs')}
- ${inputFields || `

${escapeHtml ? escapeHtml(t?.('ui.workflow.no_inputs', 'No inputs')) : t?.('ui.workflow.no_inputs', 'No inputs')}

`} -
-
-
${escapeHtml ? escapeHtml(t?.('ui.workflow.outputs_label', 'Outputs')) : t?.('ui.workflow.outputs_label', 'Outputs')}
- ${outputFields || `

${escapeHtml ? escapeHtml(t?.('ui.workflow.no_outputs', 'No outputs')) : t?.('ui.workflow.no_outputs', 'No outputs')}

`} -
- `; - }; - - window.AMBWorkflowFieldRenderer = { - renderFieldGroup, - renderNodeFields - }; -})(); diff --git a/src/autometabuilder/web/static/js/workflow/workflow_loop_renderer.js b/src/autometabuilder/web/static/js/workflow/workflow_loop_renderer.js deleted file mode 100644 index a4446ed..0000000 --- a/src/autometabuilder/web/static/js/workflow/workflow_loop_renderer.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * AutoMetabuilder - Workflow Loop Renderer - */ -(() => { - const attach = ({ node, nodeCard, level, renderNodes, pluginDefs, rerender }) => { - if (node.type !== 'control.loop') return; - const { t, escapeHtml } = window.AMBWorkflowUtils || {}; - const mutations = window.AMBWorkflowMutations; - - const bodyContainer = document.createElement('div'); - bodyContainer.className = 'amb-workflow-node-nested'; - bodyContainer.innerHTML = ` -
- ${escapeHtml ? escapeHtml(t?.('ui.workflow.loop_body_label', 'Loop Body')) : t?.('ui.workflow.loop_body_label', 'Loop Body')} -
- `; - - const bodyNodes = Array.isArray(node.body) ? node.body : []; - node.body = bodyNodes; - renderNodes(bodyNodes, bodyContainer, level + 1); - - const addNestedBtn = document.createElement('button'); - addNestedBtn.className = 'btn btn-sm btn-outline-primary'; - addNestedBtn.innerHTML = ` ${escapeHtml ? escapeHtml(t?.('ui.workflow.add_loop_node', 'Add Node to Loop')) : t?.('ui.workflow.add_loop_node', 'Add Node to Loop')}`; - addNestedBtn.onclick = () => { - mutations?.addNode(bodyNodes, pluginDefs); - rerender(); - }; - bodyContainer.appendChild(addNestedBtn); - - nodeCard.appendChild(bodyContainer); - }; - - window.AMBWorkflowLoopRenderer = { attach }; -})(); diff --git a/src/autometabuilder/web/static/js/workflow/workflow_mutations.js b/src/autometabuilder/web/static/js/workflow/workflow_mutations.js deleted file mode 100644 index c129768..0000000 --- a/src/autometabuilder/web/static/js/workflow/workflow_mutations.js +++ /dev/null @@ -1,70 +0,0 @@ -/** - * AutoMetabuilder - Workflow Mutations - */ -(() => { - const buildDefaultFields = (definitions) => { - const result = {}; - Object.entries(definitions || {}).forEach(([name, def]) => { - if (def.default !== undefined && def.default !== '') { - result[name] = def.default; - } - }); - return result; - }; - - const updateNodeType = (node, newType, pluginDefinitions) => { - node.type = newType; - const def = pluginDefinitions[newType] || {}; - node.inputs = buildDefaultFields(def.inputs); - node.outputs = buildDefaultFields(def.outputs); - if (newType === 'control.loop') { - node.body = Array.isArray(node.body) ? node.body : []; - } else { - delete node.body; - } - }; - - const generateNodeId = (type, nodes) => { - const base = type ? type.split('.').pop() : 'node'; - const existing = new Set((nodes || []).map(node => node.id)); - let counter = (nodes || []).length + 1; - let candidate = `${base}_${counter}`; - while (existing.has(candidate)) { - counter += 1; - candidate = `${base}_${counter}`; - } - return candidate; - }; - - const addNode = (targetArray, pluginDefinitions, typeOverride = '') => { - const types = Object.keys(pluginDefinitions); - const defaultType = types[0] || ''; - const nextType = pluginDefinitions[typeOverride] ? typeOverride : defaultType; - const node = { - id: generateNodeId(nextType, targetArray), - type: nextType, - inputs: buildDefaultFields(pluginDefinitions[nextType]?.inputs), - outputs: buildDefaultFields(pluginDefinitions[nextType]?.outputs) - }; - targetArray.push(node); - }; - - const moveNode = (nodes, idx, dir) => { - const target = idx + dir; - if (target < 0 || target >= nodes.length) return; - [nodes[idx], nodes[target]] = [nodes[target], nodes[idx]]; - }; - - const removeNode = (nodes, idx) => { - nodes.splice(idx, 1); - }; - - window.AMBWorkflowMutations = { - buildDefaultFields, - updateNodeType, - generateNodeId, - addNode, - moveNode, - removeNode - }; -})(); diff --git a/src/autometabuilder/web/static/js/workflow/workflow_node_events.js b/src/autometabuilder/web/static/js/workflow/workflow_node_events.js deleted file mode 100644 index 030719b..0000000 --- a/src/autometabuilder/web/static/js/workflow/workflow_node_events.js +++ /dev/null @@ -1,74 +0,0 @@ -/** - * AutoMetabuilder - Workflow Node Events - */ -(() => { - const bindFieldUpdates = (nodeCard, node) => { - nodeCard.querySelectorAll('[data-field-name]').forEach(fieldEl => { - const fieldName = fieldEl.dataset.fieldName; - const fieldType = fieldEl.dataset.fieldType || 'text'; - const fieldGroup = fieldEl.dataset.fieldGroup || 'inputs'; - const target = fieldGroup === 'outputs' ? 'outputs' : 'inputs'; - - const updateValue = () => { - let newValue = fieldEl.value; - if (fieldType === 'checkbox') { - newValue = fieldEl.checked; - } else if (fieldType === 'number') { - newValue = fieldEl.value === '' ? '' : Number(fieldEl.value); - } - - if (!node[target]) node[target] = {}; - node[target][fieldName] = newValue; - if (newValue === '' || newValue === null) { - delete node[target][fieldName]; - } - window.AMBWorkflowState?.sync?.(); - }; - - if (fieldType === 'checkbox') { - fieldEl.addEventListener('change', updateValue); - } else { - fieldEl.addEventListener('input', updateValue); - } - }); - }; - - const bind = ({ nodeCard, node, nodes, nodeIdx, pluginDefs, rerender }) => { - const mutations = window.AMBWorkflowMutations; - - nodeCard.querySelector('.amb-workflow-node-id').addEventListener('input', event => { - node.id = event.target.value; - window.AMBWorkflowState?.sync?.(); - }); - - nodeCard.querySelector('.amb-workflow-node-type').addEventListener('change', event => { - mutations?.updateNodeType(node, event.target.value, pluginDefs); - rerender(); - }); - - nodeCard.querySelector('[data-action="move-up"]').addEventListener('click', () => { - mutations?.moveNode(nodes, nodeIdx, -1); - rerender(); - }); - nodeCard.querySelector('[data-action="move-down"]').addEventListener('click', () => { - mutations?.moveNode(nodes, nodeIdx, 1); - rerender(); - }); - nodeCard.querySelector('[data-action="remove"]').addEventListener('click', () => { - mutations?.removeNode(nodes, nodeIdx); - rerender(); - }); - - nodeCard.querySelector('.amb-workflow-node-when').addEventListener('input', event => { - node.when = event.target.value; - if (!node.when) { - delete node.when; - } - window.AMBWorkflowState?.sync?.(); - }); - - bindFieldUpdates(nodeCard, node); - }; - - window.AMBWorkflowNodeEvents = { bind }; -})(); diff --git a/src/autometabuilder/web/static/js/workflow/workflow_node_renderer.js b/src/autometabuilder/web/static/js/workflow/workflow_node_renderer.js deleted file mode 100644 index 97c5581..0000000 --- a/src/autometabuilder/web/static/js/workflow/workflow_node_renderer.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * AutoMetabuilder - Workflow Node Renderer - */ -(() => { - const renderNodes = (nodes, container, level) => { - const pluginDefs = window.AMBWorkflowState?.state?.pluginDefinitions || {}; - const pluginOptions = window.AMBWorkflowPluginOptions?.render; - const fieldRenderer = window.AMBWorkflowFieldRenderer?.renderNodeFields; - const template = window.AMBWorkflowNodeTemplate?.build; - const bindEvents = window.AMBWorkflowNodeEvents?.bind; - const attachLoop = window.AMBWorkflowLoopRenderer?.attach; - const rerender = () => window.AMBWorkflowCanvasRenderer?.render?.(); - - nodes.forEach((node, nodeIdx) => { - const nodeCard = document.createElement('div'); - nodeCard.className = 'amb-workflow-node mb-3'; - nodeCard.style.marginLeft = level ? `${level * 24}px` : '0'; - - const pluginDef = pluginDefs[node.type] || {}; - nodeCard.innerHTML = template?.({ - node, - nodeIdx, - isFirst: nodeIdx === 0, - isLast: nodeIdx === nodes.length - 1, - pluginOptionsHtml: pluginOptions ? pluginOptions(node.type) : '', - fieldHtml: fieldRenderer ? fieldRenderer(pluginDef, node) : '' - }) || ''; - - bindEvents?.({ nodeCard, node, nodes, nodeIdx, pluginDefs, rerender }); - attachLoop?.({ node, nodeCard, level, renderNodes, pluginDefs, rerender }); - container.appendChild(nodeCard); - }); - }; - - window.AMBWorkflowNodeRenderer = { renderNodes }; -})(); diff --git a/src/autometabuilder/web/static/js/workflow/workflow_node_template.js b/src/autometabuilder/web/static/js/workflow/workflow_node_template.js deleted file mode 100644 index 8259690..0000000 --- a/src/autometabuilder/web/static/js/workflow/workflow_node_template.js +++ /dev/null @@ -1,57 +0,0 @@ -/** - * AutoMetabuilder - Workflow Node Template - */ -(() => { - const build = ({ node, nodeIdx, isFirst, isLast, pluginOptionsHtml, fieldHtml }) => { - const { t, format, escapeHtml } = window.AMBWorkflowUtils || {}; - const nodeLabel = format?.(t?.('ui.workflow.node_label', 'Node {number}'), { number: nodeIdx + 1 }); - const safeNodeLabel = escapeHtml ? escapeHtml(nodeLabel) : nodeLabel; - const safeId = escapeHtml ? escapeHtml(node.id || '') : (node.id || ''); - const safeWhen = escapeHtml ? escapeHtml(node.when || '') : (node.when || ''); - const nodeIdLabel = t?.('ui.workflow.node_id_label', 'Node ID'); - const runWhenLabel = t?.('ui.workflow.run_when_label', 'Run when'); - const runWhenPlaceholder = t?.('ui.workflow.run_when_placeholder', '$flag_key'); - const moveUpLabel = t?.('ui.workflow.move_up', 'Move up'); - const moveDownLabel = t?.('ui.workflow.move_down', 'Move down'); - const deleteLabel = t?.('ui.workflow.delete_node', 'Delete node'); - - return ` -
-
- ${safeNodeLabel} - - -
-
- - - -
-
-
- - -
-
- ${fieldHtml} -
- `; - }; - - window.AMBWorkflowNodeTemplate = { build }; -})(); diff --git a/src/autometabuilder/web/static/js/workflow/workflow_palette.js b/src/autometabuilder/web/static/js/workflow/workflow_palette.js deleted file mode 100644 index ef69674..0000000 --- a/src/autometabuilder/web/static/js/workflow/workflow_palette.js +++ /dev/null @@ -1,99 +0,0 @@ -(() => { - const state = { - container: null, - searchInput: null, - list: null, - filter: '', - ready: false, - loading: false - }; - const getGroupKey = (type) => (type || '').split('.')[0] || 'other'; - const buildEntries = (definitions, t) => Object.entries(definitions || {}).map(([key, def]) => ({ key, label: t?.(def.label || '', def.label || key) || key, group: getGroupKey(key), search: `${key} ${t?.(def.label || '', def.label || key) || key}`.toLowerCase() })); - const loadDefinitions = async () => { - if (state.loading) return; - state.loading = true; - try { - const response = await fetch('/api/workflow/plugins', { credentials: 'include', headers: window.AMBContext?.authHeaders || {} }); - if (response.ok) { - window.AMBWorkflowState?.setPlugins?.(await response.json()); - } - } catch (error) { - console.error('Workflow palette fetch failed', error); - } - state.loading = false; - render(); - }; - const render = () => { - const { t, escapeHtml } = window.AMBWorkflowUtils || {}; - const definitions = window.AMBWorkflowState?.state?.pluginDefinitions || {}; - if (!state.list) return; - if (!Object.keys(definitions).length) { - if (!state.loading) { - loadDefinitions(); - } - const loadingText = t?.('ui.workflow.palette.loading', 'Loading nodes...'); - state.list.innerHTML = `

${escapeHtml ? escapeHtml(loadingText) : loadingText}

`; - return; - } - const term = state.filter.toLowerCase(); - const entries = buildEntries(definitions, t).filter(entry => !term || entry.search.includes(term)); - if (!entries.length) { - state.list.innerHTML = `

${escapeHtml ? escapeHtml(t?.('ui.workflow.palette.empty', 'No matching nodes.')) : t?.('ui.workflow.palette.empty', 'No matching nodes.')}

`; - return; - } - const grouped = entries.reduce((acc, entry) => { - const group = entry.group || 'other'; - acc[group] = acc[group] || []; - acc[group].push(entry); - return acc; - }, {}); - const groupNames = Object.keys(grouped).sort((a, b) => (a === 'other') - (b === 'other') || a.localeCompare(b)); - const groupsHtml = groupNames.map(group => { - const groupLabelKey = `ui.workflow.palette.group.${group}`; - const groupLabel = t?.(groupLabelKey, group) || group; - const items = grouped[group].map(entry => { - const safeLabel = escapeHtml ? escapeHtml(entry.label) : entry.label; - const safeKey = escapeHtml ? escapeHtml(entry.key) : entry.key; - return ` - - `; - }).join(''); - return ` -
-
${escapeHtml ? escapeHtml(groupLabel) : groupLabel}
-
${items}
-
- `; - }).join(''); - state.list.innerHTML = groupsHtml; - }; - const init = () => { - if (state.ready) { - render(); - return; - } - state.container = document.getElementById('workflow-palette'); - state.searchInput = document.getElementById('workflow-palette-search'); - state.list = document.getElementById('workflow-palette-list'); - if (!state.container || !state.searchInput || !state.list) return; - state.searchInput.addEventListener('input', (event) => { - state.filter = event.target.value || ''; - render(); - }); - state.list.addEventListener('click', (event) => { - const target = event.target.closest('.amb-workflow-palette-item'); - if (!target) return; - const nodeType = target.dataset.nodeType; - const workflowState = window.AMBWorkflowState?.state; - if (!workflowState || !nodeType) return; - window.AMBWorkflowMutations?.addNode(workflowState.workflow.nodes, workflowState.pluginDefinitions, nodeType); - window.AMBWorkflowCanvasRenderer?.render?.(); - }); - state.ready = true; - render(); - }; - window.AMBWorkflowPalette = { init, render }; -})(); diff --git a/src/autometabuilder/web/static/js/workflow/workflow_plugin_options.js b/src/autometabuilder/web/static/js/workflow/workflow_plugin_options.js deleted file mode 100644 index fbd5190..0000000 --- a/src/autometabuilder/web/static/js/workflow/workflow_plugin_options.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * AutoMetabuilder - Workflow Plugin Options - */ -(() => { - const render = (selectedType) => { - const { t, escapeHtml } = window.AMBWorkflowUtils || {}; - const definitions = window.AMBWorkflowState?.state?.pluginDefinitions || {}; - return Object.entries(definitions).map(([type, def]) => { - const label = t?.(def.label || '', def.label || type); - const safeLabel = escapeHtml ? escapeHtml(label) : label; - const safeType = escapeHtml ? escapeHtml(type) : type; - const selected = type === selectedType ? 'selected' : ''; - return ``; - }).join(''); - }; - - window.AMBWorkflowPluginOptions = { render }; -})(); diff --git a/src/autometabuilder/web/static/js/workflow/workflow_state.js b/src/autometabuilder/web/static/js/workflow/workflow_state.js deleted file mode 100644 index 2fa6535..0000000 --- a/src/autometabuilder/web/static/js/workflow/workflow_state.js +++ /dev/null @@ -1,57 +0,0 @@ -/** - * AutoMetabuilder - Workflow State - */ -(() => { - const state = { - workflow: { nodes: [] }, - pluginDefinitions: {}, - container: null, - textarea: null - }; - - const setElements = (containerId, textareaId) => { - state.container = document.getElementById(containerId); - state.textarea = document.getElementById(textareaId); - }; - - const setPlugins = (pluginDefinitions) => { - state.pluginDefinitions = pluginDefinitions || {}; - }; - - const setWorkflow = (workflow) => { - if (workflow && Array.isArray(workflow.nodes)) { - state.workflow = workflow; - } else { - state.workflow = { nodes: [] }; - } - }; - - const loadFromTextarea = () => { - if (!state.textarea) { - setWorkflow({ nodes: [] }); - return; - } - try { - const parsed = JSON.parse(state.textarea.value || '{}'); - setWorkflow(parsed); - } catch (error) { - console.error('Failed to parse workflow JSON', error); - setWorkflow({ nodes: [] }); - } - }; - - const sync = () => { - if (state.textarea) { - state.textarea.value = JSON.stringify(state.workflow, null, 2); - } - }; - - window.AMBWorkflowState = { - state, - setElements, - setPlugins, - setWorkflow, - loadFromTextarea, - sync - }; -})(); diff --git a/src/autometabuilder/web/static/js/workflow/workflow_utils.js b/src/autometabuilder/web/static/js/workflow/workflow_utils.js deleted file mode 100644 index b53ea1c..0000000 --- a/src/autometabuilder/web/static/js/workflow/workflow_utils.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * AutoMetabuilder - Workflow Utils - */ -(() => { - const t = (key, fallback = '') => window.AMBContext?.t?.(key, fallback) || fallback || key; - const format = (text, values = {}) => text.replace(/\{(\w+)\}/g, (_, name) => values[name] ?? ''); - - const escapeHtml = (text) => { - if (text === null || text === undefined) return ''; - const div = document.createElement('div'); - div.textContent = String(text); - return div.innerHTML; - }; - - window.AMBWorkflowUtils = { - t, - format, - escapeHtml - }; -})(); diff --git a/src/autometabuilder/web/templates/base.html b/src/autometabuilder/web/templates/base.html deleted file mode 100644 index 4eac1b3..0000000 --- a/src/autometabuilder/web/templates/base.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - {% block title %}{{ t('ui.app.title', 'AutoMetabuilder Dashboard') }}{% endblock %} - - - - - - - - - - - - {% set core_styles = ui_assets.get('core_styles', ['/static/css/main.css']) if ui_assets else ['/static/css/main.css'] %} - {% for style in core_styles %} - - {% endfor %} - - {% block head %}{% endblock %} - - - {% from "components/organisms/sidebar.html" import sidebar %} - {{ sidebar([], t('ui.app.name', 'AutoMetabuilder'), username, t('ui.theme_toggle', 'Toggle theme')) }} - - -
- {% block content %}{% endblock %} -
- - - - - - - - {% set core_scripts = ui_assets.get('core_scripts', []) if ui_assets else [] %} - {% for script in core_scripts %} - - {% endfor %} - - {% block scripts %}{% endblock %} - - - - diff --git a/src/autometabuilder/web/templates/components/atoms/helper_text.html b/src/autometabuilder/web/templates/components/atoms/helper_text.html deleted file mode 100644 index 9dd126c..0000000 --- a/src/autometabuilder/web/templates/components/atoms/helper_text.html +++ /dev/null @@ -1,6 +0,0 @@ -{# Helper text for form fields. #} -{% macro helper_text(text) -%} -{% if text %} -

{{ text }}

-{% endif %} -{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/atoms/icon.html b/src/autometabuilder/web/templates/components/atoms/icon.html deleted file mode 100644 index 2a7e4ad..0000000 --- a/src/autometabuilder/web/templates/components/atoms/icon.html +++ /dev/null @@ -1,4 +0,0 @@ -{# Atomic UI primitive for Jinja2 templates. #} -{% macro icon(name, extra_class='') -%} - -{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/atoms/nav_link.html b/src/autometabuilder/web/templates/components/atoms/nav_link.html deleted file mode 100644 index 6543546..0000000 --- a/src/autometabuilder/web/templates/components/atoms/nav_link.html +++ /dev/null @@ -1,6 +0,0 @@ -{# Sidebar navigation link macro. #} -{% macro nav_link(section, icon_name, label, is_active=False) -%} - - {{ label }} - -{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/atoms/pill.html b/src/autometabuilder/web/templates/components/atoms/pill.html deleted file mode 100644 index a921916..0000000 --- a/src/autometabuilder/web/templates/components/atoms/pill.html +++ /dev/null @@ -1,4 +0,0 @@ -{# Pill label. #} -{% macro pill(text, tone='neutral') -%} -{{ text }} -{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/atoms/section_header.html b/src/autometabuilder/web/templates/components/atoms/section_header.html deleted file mode 100644 index 60b81a1..0000000 --- a/src/autometabuilder/web/templates/components/atoms/section_header.html +++ /dev/null @@ -1,9 +0,0 @@ -{# Section header macro. #} -{% macro section_header(title, subtitle='') -%} -
-

{{ title }}

- {% if subtitle %} -

{{ subtitle }}

- {% endif %} -
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/molecules/card.html b/src/autometabuilder/web/templates/components/molecules/card.html deleted file mode 100644 index 1d2f1d4..0000000 --- a/src/autometabuilder/web/templates/components/molecules/card.html +++ /dev/null @@ -1,19 +0,0 @@ -{# Card component. #} -{% from "components/atoms/icon.html" import icon %} - -{% macro card(title, icon_name=None, actions_html='') -%} -
-
-
- {% if icon_name %}{{ icon(icon_name) }}{% endif %} - {{ title }} -
- {% if actions_html %} -
{{ actions_html | safe }}
- {% endif %} -
-
- {{ caller() }} -
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/molecules/empty_state.html b/src/autometabuilder/web/templates/components/molecules/empty_state.html deleted file mode 100644 index 4d69d3d..0000000 --- a/src/autometabuilder/web/templates/components/molecules/empty_state.html +++ /dev/null @@ -1,10 +0,0 @@ -{# Empty state component. #} -{% from "components/atoms/icon.html" import icon %} - -{% macro empty_state(icon_name, title, body) -%} -
- {{ icon(icon_name, 'amb-empty-icon') }} -
{{ title }}
-

{{ body }}

-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/molecules/sidebar_nav.html b/src/autometabuilder/web/templates/components/molecules/sidebar_nav.html deleted file mode 100644 index 4a724da..0000000 --- a/src/autometabuilder/web/templates/components/molecules/sidebar_nav.html +++ /dev/null @@ -1,10 +0,0 @@ -{# Sidebar navigation list macro. #} -{% from "components/atoms/nav_link.html" import nav_link %} - -{% macro sidebar_nav(items) -%} - -{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/callout.html b/src/autometabuilder/web/templates/components/organisms/callout.html deleted file mode 100644 index ccfae0e..0000000 --- a/src/autometabuilder/web/templates/components/organisms/callout.html +++ /dev/null @@ -1,14 +0,0 @@ -{# Callout component. #} -{% from "components/atoms/icon.html" import icon %} - -{% macro callout(title, body, tone='info', icon_name='info-circle') -%} -
-
- {{ icon(icon_name) }} -
-
- {{ title }} -

{{ body }}

-
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/dashboard_bot_control.html b/src/autometabuilder/web/templates/components/organisms/dashboard_bot_control.html deleted file mode 100644 index fd989b0..0000000 --- a/src/autometabuilder/web/templates/components/organisms/dashboard_bot_control.html +++ /dev/null @@ -1,54 +0,0 @@ -{# Dashboard bot control card macro. #} -{% from "components/sections/choice_card.html" import choice_card %} - -{% macro dashboard_bot_control() -%} -
-
-
{{ t('ui.dashboard.bot_control', 'Bot Control') }}
-
-
-
-
- -
- {% set iterations_extra %} - - {% endset %} - - {{ choice_card('mode-once', 'once', '1-circle', t('ui.dashboard.run.single.title', 'Single Iteration'), t('ui.dashboard.run.single.desc', 'One full pass through the workflow.'), True) }} - {{ choice_card('mode-iterations', 'iterations', 'arrow-repeat', t('ui.dashboard.run.repeat.title', 'Repeat'), t('ui.dashboard.run.repeat.desc', 'Run a fixed number of cycles.'), False, iterations_extra) }} - {{ choice_card('mode-yolo', 'yolo', 'infinity', t('ui.dashboard.run.yolo.title', 'YOLO'), t('ui.dashboard.run.yolo.desc', 'Keep iterating until you stop it.')) }} -
-
- -
- -
-
- - -
-
- - -
-
-
- - -
-
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/dashboard_logs.html b/src/autometabuilder/web/templates/components/organisms/dashboard_logs.html deleted file mode 100644 index cee70d4..0000000 --- a/src/autometabuilder/web/templates/components/organisms/dashboard_logs.html +++ /dev/null @@ -1,14 +0,0 @@ -{# Dashboard logs card macro. #} -{% macro dashboard_logs() -%} -
-
-
{{ t('ui.dashboard.logs.title', 'Recent Logs') }}
- -
-
-
{{ logs }}
-
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/dashboard_status.html b/src/autometabuilder/web/templates/components/organisms/dashboard_status.html deleted file mode 100644 index a8eafc0..0000000 --- a/src/autometabuilder/web/templates/components/organisms/dashboard_status.html +++ /dev/null @@ -1,32 +0,0 @@ -{# Dashboard status card macro. #} -{% macro dashboard_status() -%} -
-
-
{{ t('ui.dashboard.status.title', 'Status') }}
-
-
-
-
- {{ t('ui.dashboard.status.bot_label', 'Bot Status') }} -
- - {% if is_running %}{{ t('ui.dashboard.status.running', 'Running') }}{% else %}{{ t('ui.dashboard.status.idle', 'Idle') }}{% endif %} -
-
-
- {{ t('ui.dashboard.status.mvp_label', 'MVP Milestone') }} - - {% if mvp_reached %} - {{ t('ui.dashboard.status.mvp_reached', 'Reached') }} - {% else %} - {{ t('ui.dashboard.status.mvp_progress', 'In Progress') }} - {% endif %} - -
-
-
-
-
-
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/prompt_builder.html b/src/autometabuilder/web/templates/components/organisms/prompt_builder.html deleted file mode 100644 index a74680e..0000000 --- a/src/autometabuilder/web/templates/components/organisms/prompt_builder.html +++ /dev/null @@ -1,71 +0,0 @@ -{# Prompt builder card macro. #} -{% from "components/atoms/helper_text.html" import helper_text %} -{% from "components/molecules/card.html" import card %} -{% from "components/sections/prompt_step.html" import prompt_step %} - -{% macro prompt_builder() -%} -{% call card(t('ui.prompt.card.title', 'Prompt Builder'), "chat-square-text") %} -
- -
- {% set system_chips = [ - {'target': 'system-prompt', 'snippet': t('ui.prompt.chip.senior.snippet', 'You are a senior software engineer focused on correctness and clarity.'), 'label': t('ui.prompt.chip.senior.label', 'Senior engineer')}, - {'target': 'system-prompt', 'snippet': t('ui.prompt.chip.ask.snippet', 'Ask clarifying questions before making risky changes.'), 'label': t('ui.prompt.chip.ask.label', 'Ask questions')}, - {'target': 'system-prompt', 'snippet': t('ui.prompt.chip.minimal.snippet', 'Prefer minimal diffs and explain trade-offs.'), 'label': t('ui.prompt.chip.minimal.label', 'Minimal diffs')} - ] %} - {{ prompt_step(1, - t('ui.prompt.step1.title', 'Define the assistant'), - t('ui.prompt.step1.desc', 'Describe who the assistant is and how it should behave.'), - 'system-prompt', - 'system_content', - t('ui.prompt.step1.placeholder', 'You are a senior software engineer who prefers small, safe changes.'), - (prompt_content | extract_system_content), - 6, - system_chips - ) }} - - {% set user_chips = [ - {'target': 'user-prompt', 'snippet': t('ui.prompt.chip.ux.snippet', 'Focus on UX polish, and avoid major refactors.'), 'label': t('ui.prompt.chip.ux.label', 'UX polish')}, - {'target': 'user-prompt', 'snippet': t('ui.prompt.chip.tests.snippet', 'Add tests when possible, but avoid heavy scaffolding.'), 'label': t('ui.prompt.chip.tests.label', 'Add tests')}, - {'target': 'user-prompt', 'snippet': t('ui.prompt.chip.summarize.snippet', 'Summarize changes and suggest next steps.'), 'label': t('ui.prompt.chip.summarize.label', 'Summarize')} - ] %} - {{ prompt_step(2, - t('ui.prompt.step2.title', 'Give the mission'), - t('ui.prompt.step2.desc', 'Explain what the bot should accomplish right now.'), - 'user-prompt', - 'user_content', - t('ui.prompt.step2.placeholder', 'Review the repo, improve the UI, and summarize what changed.'), - (prompt_content | extract_user_content), - 5, - user_chips - ) }} - -
- - {{ helper_text(t('ui.prompt.model.desc', 'Pick the balance of quality and speed that fits the task.')) }} - -
-
- -
- - {{ helper_text(t('ui.prompt.raw.desc', 'Edit the full YAML only if you need fine control.')) }} - -
- -
- - -
-
-{% endcall %} -{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/prompt_guidance.html b/src/autometabuilder/web/templates/components/organisms/prompt_guidance.html deleted file mode 100644 index c9cbedd..0000000 --- a/src/autometabuilder/web/templates/components/organisms/prompt_guidance.html +++ /dev/null @@ -1,21 +0,0 @@ -{# Prompt guidance card macro. #} -{% from "components/molecules/card.html" import card %} - -{% macro prompt_guidance() -%} -{% call card(t('ui.prompt.guidance.title', 'Guidance'), "lightbulb") %} -
-
- {{ t('ui.prompt.guidance.keep_human.title', 'Keep it human') }} -

{{ t('ui.prompt.guidance.keep_human.desc', 'Write instructions the way you would brief a teammate.') }}

-
-
- {{ t('ui.prompt.guidance.be_specific.title', 'Be specific') }} -

{{ t('ui.prompt.guidance.be_specific.desc', 'Mention constraints like time, scope, or testing expectations.') }}

-
-
- {{ t('ui.prompt.guidance.raw.title', 'Use advanced YAML sparingly') }} -

{{ t('ui.prompt.guidance.raw.desc', 'Only switch to raw YAML if you need full control.') }}

-
-
-{% endcall %} -{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/settings_api_keys.html b/src/autometabuilder/web/templates/components/organisms/settings_api_keys.html deleted file mode 100644 index 1d30df9..0000000 --- a/src/autometabuilder/web/templates/components/organisms/settings_api_keys.html +++ /dev/null @@ -1,31 +0,0 @@ -{# Settings API keys card macro. #} -{% macro settings_api_keys() -%} -{% set settings_desc = metadata.get('settings_descriptions', {}) %} -
-
-
{{ t('ui.settings.api_keys', 'API Keys') }}
-
-
- {% for key in ['GITHUB_TOKEN', 'OPENAI_API_KEY', 'LITELLM_API_KEY'] %} - {% set desc = settings_desc.get(key, {}) %} - {% set desc_label = desc.get('label', key) %} - {% set desc_text = desc.get('description', '') %} - {% set desc_placeholder = desc.get('placeholder', '') %} -
- - {% if desc_text %} -

{{ t(desc_text, desc_text) }}

- {% endif %} - -
- {% endfor %} -
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/settings_configuration.html b/src/autometabuilder/web/templates/components/organisms/settings_configuration.html deleted file mode 100644 index e1db53f..0000000 --- a/src/autometabuilder/web/templates/components/organisms/settings_configuration.html +++ /dev/null @@ -1,39 +0,0 @@ -{# Settings configuration card macro. #} -{% macro settings_configuration() -%} -{% set settings_desc = metadata.get('settings_descriptions', {}) %} -
-
-
{{ t('ui.settings.configuration', 'Configuration') }}
-
-
- {% for key in ['GITHUB_REPOSITORY', 'LOG_LEVEL', 'APP_LANG', 'PROMPT_PATH'] %} - {% set desc = settings_desc.get(key, {}) %} - {% set desc_label = desc.get('label', key) %} - {% set desc_text = desc.get('description', '') %} - {% set desc_placeholder = desc.get('placeholder', '') %} - {% set option_labels = desc.get('option_labels', []) %} -
- - {% if desc_text %} -

{{ t(desc_text, desc_text) }}

- {% endif %} - {% if desc.get('type') == 'select' %} - - {% else %} - - {% endif %} -
- {% endfor %} -
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/settings_other.html b/src/autometabuilder/web/templates/components/organisms/settings_other.html deleted file mode 100644 index 75dfa09..0000000 --- a/src/autometabuilder/web/templates/components/organisms/settings_other.html +++ /dev/null @@ -1,44 +0,0 @@ -{# Settings other settings card macro. #} -{% macro settings_other() -%} -{% set settings_desc = metadata.get('settings_descriptions', {}) %} -{% set known_keys = ['GITHUB_TOKEN', 'OPENAI_API_KEY', 'LITELLM_API_KEY', 'GITHUB_REPOSITORY', 'LOG_LEVEL', 'APP_LANG', 'PROMPT_PATH', 'WEB_USER', 'WEB_PASSWORD'] %} -
-
-
{{ t('ui.settings.other', 'Other Settings') }}
-
-
-
- {% for key, value in env_vars.items() %} - {% if key not in known_keys %} -
-
- {% set desc = settings_desc.get(key, {}) %} - {% set desc_label = desc.get('label', key) %} - {% set desc_text = desc.get('description', t('ui.settings.custom_default_desc', 'Custom environment setting. Add a description in metadata.json to show it here.')) %} - -

{{ t(desc_text, desc_text) }}

- -
-
- {% endif %} - {% endfor %} -
-
- -

{{ t('ui.settings.add.desc', 'Use uppercase keys with underscores, like API_TIMEOUT.') }}

-
- - -
-
-
-
-
- -
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/settings_web_access.html b/src/autometabuilder/web/templates/components/organisms/settings_web_access.html deleted file mode 100644 index 1027bd7..0000000 --- a/src/autometabuilder/web/templates/components/organisms/settings_web_access.html +++ /dev/null @@ -1,26 +0,0 @@ -{# Settings web access card macro. #} -{% macro settings_web_access() -%} -{% set settings_desc = metadata.get('settings_descriptions', {}) %} -
-
-
{{ t('ui.settings.web_access', 'Web UI Access') }}
-
-
- {% for key in ['WEB_USER', 'WEB_PASSWORD'] %} - {% set desc = settings_desc.get(key, {}) %} - {% set desc_label = desc.get('label', key) %} - {% set desc_text = desc.get('description', '') %} -
- - {% if desc_text %} -

{{ t(desc_text, desc_text) }}

- {% endif %} - -
- {% endfor %} -
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/sidebar.html b/src/autometabuilder/web/templates/components/organisms/sidebar.html deleted file mode 100644 index d8c0ef5..0000000 --- a/src/autometabuilder/web/templates/components/organisms/sidebar.html +++ /dev/null @@ -1,12 +0,0 @@ -{# Sidebar macro. #} -{% from "components/organisms/sidebar_header.html" import sidebar_header %} -{% from "components/molecules/sidebar_nav.html" import sidebar_nav %} -{% from "components/organisms/sidebar_footer.html" import sidebar_footer %} - -{% macro sidebar(nav_items, app_name, username, toggle_title) -%} - -{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/sidebar_footer.html b/src/autometabuilder/web/templates/components/organisms/sidebar_footer.html deleted file mode 100644 index 891cd89..0000000 --- a/src/autometabuilder/web/templates/components/organisms/sidebar_footer.html +++ /dev/null @@ -1,12 +0,0 @@ -{# Sidebar footer macro. #} -{% macro sidebar_footer(username, toggle_title) -%} - -{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/sidebar_header.html b/src/autometabuilder/web/templates/components/organisms/sidebar_header.html deleted file mode 100644 index 5ee546d..0000000 --- a/src/autometabuilder/web/templates/components/organisms/sidebar_header.html +++ /dev/null @@ -1,6 +0,0 @@ -{# Sidebar header macro. #} -{% macro sidebar_header(app_name) -%} -
-
{{ app_name }}
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/translations_editor.html b/src/autometabuilder/web/templates/components/organisms/translations_editor.html deleted file mode 100644 index c497245..0000000 --- a/src/autometabuilder/web/templates/components/organisms/translations_editor.html +++ /dev/null @@ -1,62 +0,0 @@ -{# Translations editor card macro. #} -{% from "components/molecules/empty_state.html" import empty_state %} - -{% macro translations_editor() -%} -
-
-
{{ t('ui.translations.editor.title', 'Translation Editor') }}
- -
-
-
- {{ empty_state("translate", t('ui.translations.empty.title', 'Pick a language'), t('ui.translations.empty.body', 'Select a language from the list to start editing translations.')) }} -
- -
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/translations_languages.html b/src/autometabuilder/web/templates/components/organisms/translations_languages.html deleted file mode 100644 index e3d7017..0000000 --- a/src/autometabuilder/web/templates/components/organisms/translations_languages.html +++ /dev/null @@ -1,48 +0,0 @@ -{# Translations languages card macro. #} -{% macro translations_languages() -%} -
-
-
{{ t('ui.translations.languages', 'Languages') }}
-
-
-
- {% for lang, file in translations.items() %} -
-
- -
- {{ lang.upper() }} - {{ file }} -
-
-
- - {% if lang != 'en' %} - - {% endif %} -
-
- {% endfor %} -
-
- -
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/workflow_palette.html b/src/autometabuilder/web/templates/components/organisms/workflow_palette.html deleted file mode 100644 index 4bf5572..0000000 --- a/src/autometabuilder/web/templates/components/organisms/workflow_palette.html +++ /dev/null @@ -1,16 +0,0 @@ -{# Workflow palette card macro. #} -{% macro workflow_palette() -%} -
-
-
{{ t('ui.workflow.palette.title', 'Node Palette') }}
-
-
- - -
-

{{ t('ui.workflow.palette.loading', 'Loading nodes...') }}

-
-
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/organisms/workflow_templates.html b/src/autometabuilder/web/templates/components/organisms/workflow_templates.html deleted file mode 100644 index b7d643f..0000000 --- a/src/autometabuilder/web/templates/components/organisms/workflow_templates.html +++ /dev/null @@ -1,30 +0,0 @@ -{# Workflow templates card macro. #} -{% macro workflow_templates() -%} -
-
-
{{ t('ui.workflow.templates.title', 'Workflow Templates') }}
-
-
-
-
- - -
-
-
- {{ t('ui.workflow.templates.description_placeholder', 'Choose a template to preview what it does.') }} -
-
-
- -
-
-
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/sections/choice_card.html b/src/autometabuilder/web/templates/components/sections/choice_card.html deleted file mode 100644 index 026482c..0000000 --- a/src/autometabuilder/web/templates/components/sections/choice_card.html +++ /dev/null @@ -1,13 +0,0 @@ -{# Choice card macro. #} -{% macro choice_card(id, value, icon_name, title, description, checked=False, extra_html='') -%} - -{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/sections/dashboard_section.html b/src/autometabuilder/web/templates/components/sections/dashboard_section.html deleted file mode 100644 index 4158a52..0000000 --- a/src/autometabuilder/web/templates/components/sections/dashboard_section.html +++ /dev/null @@ -1,22 +0,0 @@ -{# Dashboard section macro. #} -{% from "components/atoms/section_header.html" import section_header %} -{% from "components/organisms/dashboard_bot_control.html" import dashboard_bot_control with context %} -{% from "components/organisms/dashboard_status.html" import dashboard_status with context %} -{% from "components/organisms/dashboard_logs.html" import dashboard_logs with context %} - -{% macro dashboard_section() -%} -
- {{ section_header(t('ui.dashboard.title', 'Dashboard'), t('ui.dashboard.subtitle', 'Control the bot and monitor system activity')) }} - -
-
- {{ dashboard_bot_control() }} - {{ dashboard_status() }} -
- -
- {{ dashboard_logs() }} -
-
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/sections/prompt_chip.html b/src/autometabuilder/web/templates/components/sections/prompt_chip.html deleted file mode 100644 index 884afb7..0000000 --- a/src/autometabuilder/web/templates/components/sections/prompt_chip.html +++ /dev/null @@ -1,5 +0,0 @@ -{# Prompt chip macro. #} -{% macro prompt_chip(target_id, snippet, label) -%} - -{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/sections/prompt_section.html b/src/autometabuilder/web/templates/components/sections/prompt_section.html deleted file mode 100644 index db037a1..0000000 --- a/src/autometabuilder/web/templates/components/sections/prompt_section.html +++ /dev/null @@ -1,20 +0,0 @@ -{# Prompt section macro. #} -{% from "components/atoms/section_header.html" import section_header %} -{% from "components/organisms/prompt_builder.html" import prompt_builder with context %} -{% from "components/organisms/prompt_guidance.html" import prompt_guidance with context %} - -{% macro prompt_section() -%} -
- {{ section_header(t('ui.prompt.title', 'Prompt Builder'), t('ui.prompt.subtitle', 'Shape how the assistant thinks, speaks, and decides')) }} - -
-
- {{ prompt_builder() }} -
- -
- {{ prompt_guidance() }} -
-
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/sections/prompt_step.html b/src/autometabuilder/web/templates/components/sections/prompt_step.html deleted file mode 100644 index c6ce78e..0000000 --- a/src/autometabuilder/web/templates/components/sections/prompt_step.html +++ /dev/null @@ -1,21 +0,0 @@ -{# Prompt step macro. #} -{% from "components/atoms/helper_text.html" import helper_text %} -{% from "components/sections/prompt_chip.html" import prompt_chip %} - -{% macro prompt_step(step_number, title, description, textarea_id, name, placeholder, value, rows=5, chips=[]) -%} -
-
- {{ step_number }} {{ title }} -
- {{ helper_text(description) }} - - {% if chips %} -
- {% for chip in chips %} - {{ prompt_chip(chip.target, chip.snippet, chip.label) }} - {% endfor %} -
- {% endif %} -
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/sections/settings_section.html b/src/autometabuilder/web/templates/components/sections/settings_section.html deleted file mode 100644 index 99d63c4..0000000 --- a/src/autometabuilder/web/templates/components/sections/settings_section.html +++ /dev/null @@ -1,30 +0,0 @@ -{# Settings section macro. #} -{% from "components/atoms/section_header.html" import section_header %} -{% from "components/organisms/callout.html" import callout %} -{% from "components/organisms/settings_api_keys.html" import settings_api_keys with context %} -{% from "components/organisms/settings_configuration.html" import settings_configuration with context %} -{% from "components/organisms/settings_web_access.html" import settings_web_access with context %} -{% from "components/organisms/settings_other.html" import settings_other with context %} - -{% macro settings_section() -%} -
- {{ section_header(t('ui.settings.title', 'Settings'), t('ui.settings.subtitle', 'Configure services, security, and environment preferences')) }} - - {{ callout(t('ui.settings.callout.title', 'Human-friendly settings'), t('ui.settings.callout.body', 'Each field explains what it does. Add descriptions in metadata.json to keep custom settings readable for everyone.'), "info", "info-circle") }} - -
-
-
- {{ settings_api_keys() }} -
- -
- {{ settings_configuration() }} - {{ settings_web_access() }} -
-
- - {{ settings_other() }} -
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/sections/translations_section.html b/src/autometabuilder/web/templates/components/sections/translations_section.html deleted file mode 100644 index e33fd7c..0000000 --- a/src/autometabuilder/web/templates/components/sections/translations_section.html +++ /dev/null @@ -1,20 +0,0 @@ -{# Translations section macro. #} -{% from "components/atoms/section_header.html" import section_header %} -{% from "components/organisms/translations_languages.html" import translations_languages with context %} -{% from "components/organisms/translations_editor.html" import translations_editor with context %} - -{% macro translations_section() -%} -
- {{ section_header(t('ui.translations.title', 'Translations'), t('ui.translations.subtitle', 'Create, edit, and maintain language files for bot messages')) }} - -
-
- {{ translations_languages() }} -
- -
- {{ translations_editor() }} -
-
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/components/sections/workflow_section.html b/src/autometabuilder/web/templates/components/sections/workflow_section.html deleted file mode 100644 index 5bb0a8f..0000000 --- a/src/autometabuilder/web/templates/components/sections/workflow_section.html +++ /dev/null @@ -1,45 +0,0 @@ -{# Workflow section macro. #} -{% from "components/atoms/section_header.html" import section_header %} -{% from "components/organisms/workflow_templates.html" import workflow_templates with context %} -{% from "components/organisms/workflow_palette.html" import workflow_palette with context %} - -{% macro workflow_section() -%} -
- {{ section_header(t('ui.workflow.title', 'Workflow Builder'), t('ui.workflow.subtitle', "Design the bot's task execution pipeline")) }} - - {{ workflow_templates() }} - -
-
- {{ workflow_palette() }} -
-
-
-
-
{{ t('ui.workflow.card.title', 'Tasks & Steps') }}
-
- -
-
-
-
- -
-
- -
- -
-
-
-
-
-
-
-{%- endmacro %} diff --git a/src/autometabuilder/web/templates/index.html b/src/autometabuilder/web/templates/index.html deleted file mode 100644 index 2571431..0000000 --- a/src/autometabuilder/web/templates/index.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends "base.html" %} -{% from "components/sections/dashboard_section.html" import dashboard_section with context %} -{% from "components/sections/workflow_section.html" import workflow_section with context %} -{% from "components/sections/prompt_section.html" import prompt_section with context %} -{% from "components/sections/settings_section.html" import settings_section with context %} -{% from "components/sections/translations_section.html" import translations_section with context %} - -{% block content %} -{{ dashboard_section() }} -{{ workflow_section() }} -{{ prompt_section() }} -{{ settings_section() }} -{{ translations_section() }} -{% endblock %} - -{% block scripts %} -{% set workflow_scripts = ui_assets.get('workflow_scripts', []) if ui_assets else [] %} -{% for script in workflow_scripts %} - -{% endfor %} -{% set page_scripts = ui_assets.get('page_scripts', []) if ui_assets else [] %} -{% for script in page_scripts %} - -{% endfor %} -{% endblock %}