zrb 1.0.0a16__py3-none-any.whl → 1.0.0a20__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zrb/__init__.py +5 -0
- zrb/__main__.py +3 -0
- zrb/builtin/__init__.py +2 -2
- zrb/builtin/git.py +10 -2
- zrb/builtin/git_subtree.py +4 -0
- zrb/builtin/llm/tool/rag.py +2 -2
- zrb/builtin/project/add/fastapp/fastapp_input.py +16 -0
- zrb/builtin/project/add/fastapp/fastapp_task.py +78 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/.flake8 +3 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/create_column_task.py +14 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_task.py +128 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +213 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/any_client_method.py +27 -0
- zrb/builtin/project/add/{fastapp_template/_zrb/entity/module_template → fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module}/service/my_entity/my_entity_usecase.py +9 -10
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module/service/my_entity/repository/factory.py +13 -0
- zrb/builtin/project/add/{fastapp_template/_zrb/entity/module_template → fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module}/service/my_entity/repository/my_entity_db_repository.py +14 -9
- zrb/builtin/project/add/{fastapp_template/_zrb/entity/module_template → fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/module/my_module}/service/my_entity/repository/my_entity_repository.py +6 -7
- zrb/builtin/project/add/{fastapp_template/_zrb/entity/schema.template.py → fastapp/fastapp_template/my_app_name/_zrb/entity/template/app_template/schema/my_entity.py} +8 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/format_task.py +17 -0
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/_zrb/input.py +1 -4
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_task.py +85 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +154 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/any_client.py +7 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/api_client.py +6 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/direct_client.py +6 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/client/factory.py +9 -0
- zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/migration/env.py +2 -4
- zrb/builtin/project/add/{fastapp_template/module/auth → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/migration/script.py.mako +1 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/route.py +33 -0
- zrb/builtin/project/add/{fastapp_template/_zrb/main.py → fastapp/fastapp_template/my_app_name/_zrb/task.py} +12 -14
- zrb/builtin/project/add/{fastapp_template/_zrb/helper.py → fastapp/fastapp_template/my_app_name/_zrb/util.py} +1 -1
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/_zrb/venv_task.py +1 -1
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/app.py +2 -2
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/base_db_repository.py +1 -1
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/base_usecase.py +19 -6
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/db_engine.py +1 -1
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/config.py +1 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/main.py +7 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/migrate.py +3 -0
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/client/any_client.py +10 -4
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/api_client.py +7 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/direct_client.py +6 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/client/factory.py +9 -0
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/migration/env.py +2 -4
- zrb/builtin/project/add/{fastapp_template/module/gateway → fastapp/fastapp_template/my_app_name/module/auth}/migration/script.py.mako +1 -0
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/migration_metadata.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/route.py +37 -0
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/service/user/repository/user_db_repository.py +13 -7
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository.py +42 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/repository/user_repository_factory.py +13 -0
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/service/user/user_usecase.py +13 -12
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/user_usecase_factory.py +6 -0
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/gateway/migration/env.py +2 -4
- zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/module/gateway}/migration/script.py.mako +1 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/route.py +37 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/subroute/auth.py +44 -0
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/requirements.txt +1 -1
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/schema/permission.py +8 -0
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/schema/role.py +8 -0
- zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/schema/user.py +8 -0
- zrb/builtin/project/add/fastapp/fastapp_util.py +46 -0
- zrb/builtin/project/create/{create.py → project_task.py} +1 -1
- zrb/builtin/python.py +4 -1
- zrb/builtin/setup/asdf/asdf_helper.py +4 -8
- zrb/builtin/setup/tmux/tmux.py +7 -12
- zrb/builtin/todo.py +42 -26
- zrb/callback/callback.py +0 -1
- zrb/cmd/cmd_val.py +2 -2
- zrb/config.py +18 -0
- zrb/content_transformer/content_transformer.py +8 -7
- zrb/context/any_context.py +6 -6
- zrb/group/group.py +0 -1
- zrb/input/any_input.py +4 -0
- zrb/input/base_input.py +17 -5
- zrb/input/bool_input.py +1 -1
- zrb/input/float_input.py +2 -2
- zrb/input/int_input.py +1 -1
- zrb/input/option_input.py +2 -2
- zrb/input/password_input.py +2 -2
- zrb/input/text_input.py +6 -6
- zrb/runner/cli.py +9 -35
- zrb/runner/common_util.py +31 -0
- zrb/runner/web_app.py +169 -46
- zrb/runner/web_config.py +288 -0
- zrb/runner/web_controller/error_page/controller.py +27 -0
- zrb/runner/web_controller/error_page/view.html +33 -0
- zrb/runner/web_controller/group_info_page/controller.py +40 -0
- zrb/runner/web_controller/group_info_page/view.html +36 -0
- zrb/runner/web_controller/home_page/controller.py +14 -57
- zrb/runner/web_controller/home_page/view.html +29 -20
- zrb/runner/web_controller/login_page/controller.py +25 -0
- zrb/runner/web_controller/login_page/view.html +50 -0
- zrb/runner/web_controller/logout_page/controller.py +26 -0
- zrb/runner/web_controller/logout_page/view.html +40 -0
- zrb/runner/web_controller/{task_ui → session_page}/controller.py +36 -34
- zrb/runner/web_controller/{task_ui → session_page}/partial/input.html +1 -1
- zrb/runner/web_controller/session_page/view.html +91 -0
- zrb/runner/web_controller/static/common.css +11 -0
- zrb/runner/web_controller/static/login/event.js +33 -0
- zrb/runner/web_controller/static/logout/event.js +20 -0
- zrb/runner/web_controller/static/pico.min.css +1 -1
- zrb/runner/web_controller/static/session/common-util.js +63 -0
- zrb/runner/web_controller/static/session/current-session.js +164 -0
- zrb/runner/web_controller/static/session/event.js +120 -0
- zrb/runner/web_controller/static/session/past-session.js +138 -0
- zrb/runner/web_util.py +53 -0
- zrb/session_state_logger/any_session_state_logger.py +0 -1
- zrb/session_state_logger/file_session_state_logger.py +4 -8
- zrb/task/base_trigger.py +0 -1
- zrb/task/cmd_task.py +1 -1
- zrb/task/llm_task.py +3 -6
- zrb/task/make_task.py +0 -1
- zrb/task/scaffolder.py +18 -4
- zrb/task/scheduler.py +0 -1
- zrb/util/cmd/command.py +0 -1
- zrb/util/codemod/{add_code_to_class.py → append_code_to_class.py} +4 -4
- zrb/util/codemod/{add_code_to_function.py → append_code_to_function.py} +5 -3
- zrb/util/codemod/{add_code_to_method.py → append_code_to_method.py} +3 -3
- zrb/util/codemod/{add_key_to_dict.py → append_key_to_dict.py} +1 -1
- zrb/util/codemod/{add_param_to_function_call.py → append_param_to_function_call.py} +1 -1
- zrb/util/codemod/{add_code_to_module.py → prepend_code_to_module.py} +2 -2
- zrb/util/codemod/{add_parent_to_class.py → prepend_parent_to_class.py} +1 -1
- zrb/util/codemod/{add_property_to_class.py → prepend_property_to_class.py} +1 -1
- zrb/util/file.py +18 -0
- zrb/util/git_subtree.py +3 -4
- zrb/util/todo.py +105 -24
- zrb/xcom/xcom.py +0 -1
- {zrb-1.0.0a16.dist-info → zrb-1.0.0a20.dist-info}/METADATA +3 -2
- zrb-1.0.0a20.dist-info/RECORD +243 -0
- zrb/builtin/project/add/fastapp.py +0 -87
- zrb/builtin/project/add/fastapp_template/_zrb/column/create_column_task.py +0 -11
- zrb/builtin/project/add/fastapp_template/_zrb/entity/create_entity_task.py +0 -196
- zrb/builtin/project/add/fastapp_template/_zrb/entity/module_template/service/my_entity/repository/factory.py +0 -13
- zrb/builtin/project/add/fastapp_template/_zrb/module/create_module_task.py +0 -136
- zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/any_client.py +0 -27
- zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/api_client.py +0 -6
- zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/direct_client.py +0 -6
- zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/client/factory.py +0 -9
- zrb/builtin/project/add/fastapp_template/_zrb/module/module_template/route.py +0 -19
- zrb/builtin/project/add/fastapp_template/main.py +0 -7
- zrb/builtin/project/add/fastapp_template/migrate.py +0 -3
- zrb/builtin/project/add/fastapp_template/module/auth/client/api_client.py +0 -7
- zrb/builtin/project/add/fastapp_template/module/auth/client/direct_client.py +0 -6
- zrb/builtin/project/add/fastapp_template/module/auth/client/factory.py +0 -9
- zrb/builtin/project/add/fastapp_template/module/auth/migration/versions/3093c7336477_add_user_table.py +0 -37
- zrb/builtin/project/add/fastapp_template/module/auth/route.py +0 -22
- zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/factory.py +0 -13
- zrb/builtin/project/add/fastapp_template/module/auth/service/user/repository/user_repository.py +0 -34
- zrb/builtin/project/add/fastapp_template/module/gateway/route.py +0 -27
- zrb/runner/web_controller/group_info_ui/controller.py +0 -91
- zrb/runner/web_controller/group_info_ui/partial/group_info.html +0 -2
- zrb/runner/web_controller/group_info_ui/partial/group_li.html +0 -1
- zrb/runner/web_controller/group_info_ui/partial/task_info.html +0 -2
- zrb/runner/web_controller/group_info_ui/partial/task_li.html +0 -1
- zrb/runner/web_controller/group_info_ui/view.html +0 -31
- zrb/runner/web_controller/home_page/partial/group_info.html +0 -2
- zrb/runner/web_controller/home_page/partial/group_li.html +0 -1
- zrb/runner/web_controller/home_page/partial/task_info.html +0 -2
- zrb/runner/web_controller/home_page/partial/task_li.html +0 -1
- zrb/runner/web_controller/task_ui/partial/common-util.js +0 -37
- zrb/runner/web_controller/task_ui/partial/main.js +0 -195
- zrb/runner/web_controller/task_ui/partial/show-existing-session.js +0 -97
- zrb/runner/web_controller/task_ui/partial/visualize-history.js +0 -104
- zrb/runner/web_controller/task_ui/view.html +0 -87
- zrb-1.0.0a16.dist-info/RECORD +0 -231
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/.gitignore +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/README.md +0 -0
- /zrb/builtin/project/add/{__init__.py → fastapp/fastapp_template/my_app_name/__init__.py} +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/_zrb/config.py +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/_zrb/group.py +0 -0
- /zrb/builtin/project/add/{fastapp_template/__init__.py → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/gateway/subroute/my_module.py} +0 -0
- /zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/alembic.ini +0 -0
- /zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/migration/README +0 -0
- /zrb/builtin/project/add/{fastapp_template/module/gateway → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/migration/versions/.gitkeep +0 -0
- /zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/migration_metadata.py +0 -0
- /zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module}/service/__init__.py +0 -0
- /zrb/builtin/project/add/{fastapp_template/_zrb/module/run_module.template.py → fastapp/fastapp_template/my_app_name/_zrb/module/template/module_task_definition.py} +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/__init__.py +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/error.py +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/common/schema.py +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/__init__.py +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/alembic.ini +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/migration/README +0 -0
- /zrb/builtin/project/add/{fastapp_template/_zrb/module/module_template → fastapp/fastapp_template/my_app_name/module/auth}/migration/versions/3093c7336477_add_user_table.py +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/service/__init__.py +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/auth/service/user/__init__.py +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/gateway/alembic.ini +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/gateway/migration/README +0 -0
- /zrb/builtin/project/add/{fastapp_template/module/auth/service/user/repository/__init__.py → fastapp/fastapp_template/my_app_name/module/gateway/migration/versions/.gitkeep} +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/module/gateway/migration_metadata.py +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/schema/__init__.py +0 -0
- /zrb/builtin/project/add/{fastapp_template → fastapp/fastapp_template/my_app_name}/template.env +0 -0
- /zrb/runner/web_controller/{group_info_ui → group_info_page}/__init__.py +0 -0
- /zrb/runner/web_controller/{task_ui → session_page}/__init__.py +0 -0
- {zrb-1.0.0a16.dist-info → zrb-1.0.0a20.dist-info}/WHEEL +0 -0
- {zrb-1.0.0a16.dist-info → zrb-1.0.0a20.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,120 @@
|
|
1
|
+
window.addEventListener("load", async function () {
|
2
|
+
// Get current session
|
3
|
+
if (cfg.SESSION_NAME != "") {
|
4
|
+
CURRENT_SESSION.pollCurrentSession();
|
5
|
+
}
|
6
|
+
// set maxStartDate to today
|
7
|
+
const tomorrow = new Date();
|
8
|
+
tomorrow.setDate(tomorrow.getDate() + 1); // Move to the next day
|
9
|
+
tomorrow.setHours(0, 0, 0, 0);
|
10
|
+
const formattedTomorrow = UTIL.toLocalDateInputValue(tomorrow);
|
11
|
+
const maxStartAtInput = document.getElementById("max-start-at-input");
|
12
|
+
maxStartAtInput.value = formattedTomorrow;
|
13
|
+
// set minStartDate to yesterday
|
14
|
+
const today = new Date();
|
15
|
+
today.setHours(0, 0, 0, 0); // Set time to 00:00:00
|
16
|
+
const formattedToday = UTIL.toLocalDateInputValue(today);
|
17
|
+
const minStartAtInput = document.getElementById("min-start-at-input");
|
18
|
+
minStartAtInput.value = formattedToday;
|
19
|
+
// Update session
|
20
|
+
PAST_SESSION.pollPastSession();
|
21
|
+
});
|
22
|
+
|
23
|
+
|
24
|
+
const submitTaskForm = document.getElementById("submit-task-form");
|
25
|
+
submitTaskForm.addEventListener("input", async function(event) {
|
26
|
+
const currentInput = event.target;
|
27
|
+
const inputs = Array.from(submitTaskForm.querySelectorAll("input[name]"));
|
28
|
+
const inputMap = {};
|
29
|
+
const fixedInputNames = [];
|
30
|
+
for (const input of inputs) {
|
31
|
+
fixedInputNames.push(input.name);
|
32
|
+
if (input === currentInput) {
|
33
|
+
inputMap[input.name] = currentInput.value;
|
34
|
+
break;
|
35
|
+
} else {
|
36
|
+
inputMap[input.name] = input.value;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
const queryString = new URLSearchParams(
|
40
|
+
{query: JSON.stringify(inputMap)}
|
41
|
+
).toString();
|
42
|
+
try {
|
43
|
+
// Send the AJAX request
|
44
|
+
const response = await fetch(`${cfg.INPUT_API_URL}?${queryString}`, {
|
45
|
+
method: "GET",
|
46
|
+
headers: {
|
47
|
+
"Content-Type": "application/json"
|
48
|
+
},
|
49
|
+
});
|
50
|
+
if (response.ok) {
|
51
|
+
const data = await response.json();
|
52
|
+
// Update the values of all subsequent inputs based on the response
|
53
|
+
Object.entries(data).forEach(([key, value]) => {
|
54
|
+
if (fixedInputNames.includes(key)) {
|
55
|
+
return;
|
56
|
+
}
|
57
|
+
const input = submitTaskForm.querySelector(`[name="${key}"]`);
|
58
|
+
input.value = value;
|
59
|
+
});
|
60
|
+
} else {
|
61
|
+
console.error("Failed to fetch updated values:", response.statusText);
|
62
|
+
}
|
63
|
+
} catch (error) {
|
64
|
+
console.error("Error during fetch:", error);
|
65
|
+
}
|
66
|
+
})
|
67
|
+
|
68
|
+
|
69
|
+
function openPastSessionDialog(event) {
|
70
|
+
event.preventDefault();
|
71
|
+
const dialog = document.getElementById("past-session-dialog")
|
72
|
+
dialog.showModal();
|
73
|
+
}
|
74
|
+
|
75
|
+
|
76
|
+
function closePastSessionDialog(event) {
|
77
|
+
event.preventDefault();
|
78
|
+
const dialog = document.getElementById("past-session-dialog")
|
79
|
+
dialog.close();
|
80
|
+
}
|
81
|
+
|
82
|
+
|
83
|
+
async function submitNewSessionForm(event) {
|
84
|
+
// Prevent the form from submitting the traditional way
|
85
|
+
event.preventDefault();
|
86
|
+
// Select the form
|
87
|
+
const form = document.getElementById("submit-task-form");
|
88
|
+
// Initialize an empty object to hold form data
|
89
|
+
const formData = {};
|
90
|
+
// Iterate through each input in the form
|
91
|
+
Array.from(form.elements).forEach(element => {
|
92
|
+
// Only include inputs with a name attribute and ignore buttons
|
93
|
+
if (element.name && (element.type !== "button" && element.type !== "submit")) {
|
94
|
+
formData[element.name] = element.value;
|
95
|
+
}
|
96
|
+
});
|
97
|
+
// Convert formData to JSON
|
98
|
+
const jsonData = JSON.stringify(formData);
|
99
|
+
try {
|
100
|
+
// Send the AJAX request
|
101
|
+
const response = await fetch(cfg.SESSION_API_URL, {
|
102
|
+
method: "POST",
|
103
|
+
headers: {
|
104
|
+
"Content-Type": "application/json"
|
105
|
+
},
|
106
|
+
body: jsonData
|
107
|
+
});
|
108
|
+
if (response.ok) {
|
109
|
+
const data = await response.json();
|
110
|
+
cfg.SESSION_NAME = data.session_name;
|
111
|
+
history.pushState(null, "", `${cfg.CURRENT_URL}${cfg.SESSION_NAME}`);
|
112
|
+
await PAST_SESSION.getAndRenderPastSession(0);
|
113
|
+
await CURRENT_SESSION.pollCurrentSession();
|
114
|
+
} else {
|
115
|
+
console.error("Error:", response);
|
116
|
+
}
|
117
|
+
} catch (error) {
|
118
|
+
console.error("Error:", error);
|
119
|
+
}
|
120
|
+
}
|
@@ -0,0 +1,138 @@
|
|
1
|
+
const PAST_SESSION = {
|
2
|
+
|
3
|
+
async pollPastSession() {
|
4
|
+
while (true) {
|
5
|
+
await this.getAndRenderPastSession(cfg.PAGE);
|
6
|
+
await UTIL.delay(5000);
|
7
|
+
}
|
8
|
+
},
|
9
|
+
|
10
|
+
async getAndRenderPastSession(page) {
|
11
|
+
cfg.PAGE=page
|
12
|
+
const minStartAtInput = document.getElementById("min-start-at-input");
|
13
|
+
const minStartAt = UTIL.formatDate(minStartAtInput.value);
|
14
|
+
const maxStartAtInput = document.getElementById("max-start-at-input");
|
15
|
+
const maxStartAt = UTIL.formatDate(maxStartAtInput.value);
|
16
|
+
const queryString = new URLSearchParams({
|
17
|
+
page: page,
|
18
|
+
from: minStartAt,
|
19
|
+
to: maxStartAt,
|
20
|
+
}).toString();
|
21
|
+
try {
|
22
|
+
// Send the AJAX request
|
23
|
+
const response = await fetch(`${cfg.SESSION_API_URL}list?${queryString}`, {
|
24
|
+
method: "GET",
|
25
|
+
headers: {
|
26
|
+
"Content-Type": "application/json"
|
27
|
+
},
|
28
|
+
});
|
29
|
+
if (response.ok) {
|
30
|
+
const {total, data} = await response.json();
|
31
|
+
this.showPastSession(page, total, data);
|
32
|
+
} else {
|
33
|
+
console.error("Error:", response);
|
34
|
+
}
|
35
|
+
} catch (error) {
|
36
|
+
console.error("Error:", error);
|
37
|
+
}
|
38
|
+
},
|
39
|
+
|
40
|
+
showPastSession(page, total, data) {
|
41
|
+
const ul = document.getElementById("past-session-ul");
|
42
|
+
ul.innerHTML = ''; // Clear existing content
|
43
|
+
data.forEach(item => {
|
44
|
+
const taskStatus = item.task_status[item.main_task_name];
|
45
|
+
const finalStatus = UTIL.getFinalTaskStatus(taskStatus);
|
46
|
+
const finalColor = UTIL.getFinalColor(finalStatus);
|
47
|
+
const taskHistories = taskStatus.history;
|
48
|
+
const taskStartTime = taskHistories.length > 0 ? taskHistories[0].time : ""
|
49
|
+
const li = document.createElement('li');
|
50
|
+
const a = document.createElement('a');
|
51
|
+
const dateSpan = document.createElement('span');
|
52
|
+
const statusSpan = document.createElement('span');
|
53
|
+
a.textContent = item.name;
|
54
|
+
a.target = '_blank';
|
55
|
+
a.href = `${cfg.UI_URL}${item.name}`;
|
56
|
+
li.appendChild(a);
|
57
|
+
statusSpan.style.marginLeft = "10px";
|
58
|
+
statusSpan.style.display = 'inline-block';
|
59
|
+
statusSpan.style.width = '15px';
|
60
|
+
statusSpan.style.height = '15px';
|
61
|
+
statusSpan.style.borderRadius = '50%';
|
62
|
+
statusSpan.style.border = '2px solid black';
|
63
|
+
statusSpan.style.backgroundColor = finalColor;
|
64
|
+
li.appendChild(statusSpan);
|
65
|
+
dateSpan.style.marginLeft = "10px";
|
66
|
+
dateSpan.textContent = taskStartTime;
|
67
|
+
li.appendChild(dateSpan);
|
68
|
+
ul.appendChild(li);
|
69
|
+
});
|
70
|
+
const paginationUl = document.getElementById("past-session-pagination-ul");
|
71
|
+
paginationUl.innerHTML = ''; // Clear previous pagination
|
72
|
+
|
73
|
+
const totalPages = Math.ceil(total / 10); // Calculate total pages based on page size
|
74
|
+
const maxPagesToShow = 5; // Number of pages to display around the current page
|
75
|
+
const halfMaxPages = Math.floor(maxPagesToShow / 2);
|
76
|
+
|
77
|
+
// Add first page and previous controls
|
78
|
+
if (page > 0) {
|
79
|
+
paginationUl.appendChild(this.createPageLink("⟪", 0)); // Go to first page
|
80
|
+
paginationUl.appendChild(this.createPageLink("⟨", page - 1)); // Go to previous page
|
81
|
+
}
|
82
|
+
|
83
|
+
let startPage = Math.max(0, page - halfMaxPages);
|
84
|
+
let endPage = Math.min(totalPages - 1, page + halfMaxPages);
|
85
|
+
|
86
|
+
if (page <= halfMaxPages) {
|
87
|
+
endPage = Math.min(totalPages - 1, maxPagesToShow - 1);
|
88
|
+
} else if (page + halfMaxPages >= totalPages) {
|
89
|
+
startPage = Math.max(0, totalPages - maxPagesToShow);
|
90
|
+
}
|
91
|
+
|
92
|
+
if (startPage > 1) {
|
93
|
+
paginationUl.appendChild(this.createEllipsis());
|
94
|
+
}
|
95
|
+
|
96
|
+
// Add page links within the calculated range
|
97
|
+
for (let i = startPage; i <= endPage; i++) {
|
98
|
+
if (i === page) {
|
99
|
+
const pageLi = document.createElement('li');
|
100
|
+
pageLi.textContent = i + 1;
|
101
|
+
paginationUl.append(pageLi)
|
102
|
+
} else {
|
103
|
+
paginationUl.appendChild(this.createPageLink(i + 1, i))
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
// Add ellipsis after the end page if needed
|
108
|
+
if (endPage < totalPages - 2) {
|
109
|
+
paginationUl.appendChild(this.createEllipsis());
|
110
|
+
}
|
111
|
+
|
112
|
+
// Add next and last page controls
|
113
|
+
if (page < totalPages - 1) {
|
114
|
+
paginationUl.appendChild(this.createPageLink("⟩", page + 1)); // Go to next page
|
115
|
+
paginationUl.appendChild(this.createPageLink("⟫", totalPages - 1)); // Go to last page
|
116
|
+
}
|
117
|
+
},
|
118
|
+
|
119
|
+
createPageLink(text, page) {
|
120
|
+
const li = document.createElement('li');
|
121
|
+
const link = document.createElement('a');
|
122
|
+
link.textContent = text;
|
123
|
+
link.href = '#';
|
124
|
+
link.onclick = (e) => {
|
125
|
+
e.preventDefault();
|
126
|
+
this.getAndRenderPastSession(page);
|
127
|
+
};
|
128
|
+
li.appendChild(link);
|
129
|
+
return li;
|
130
|
+
},
|
131
|
+
|
132
|
+
createEllipsis() {
|
133
|
+
const li = document.createElement('li');
|
134
|
+
li.textContent = '...';
|
135
|
+
return li;
|
136
|
+
},
|
137
|
+
|
138
|
+
}
|
zrb/runner/web_util.py
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
from pydantic import BaseModel
|
2
2
|
|
3
|
+
from zrb.group.any_group import AnyGroup
|
4
|
+
from zrb.runner.web_config import User
|
5
|
+
from zrb.task.any_task import AnyTask
|
6
|
+
from zrb.util.group import get_non_empty_subgroups, get_subtasks
|
7
|
+
|
3
8
|
|
4
9
|
class NewSessionResponse(BaseModel):
|
5
10
|
session_name: str
|
@@ -14,3 +19,51 @@ def node_path_to_url(args: list[str]) -> str:
|
|
14
19
|
pruned_args = [part for part in args if part.strip() != ""]
|
15
20
|
stripped_url = "/".join(pruned_args)
|
16
21
|
return f"/{stripped_url}/"
|
22
|
+
|
23
|
+
|
24
|
+
def get_html_auth_link(user: User) -> str:
|
25
|
+
if user.is_guest and user.is_super_admin:
|
26
|
+
return f"Hi, {user.username}"
|
27
|
+
if user.is_guest:
|
28
|
+
return f'Hi, {user.username} <a href="/login">Login 🔑</a>'
|
29
|
+
return f'Hi, {user.username} <a href="/logout">Logout 🚪</a>'
|
30
|
+
|
31
|
+
|
32
|
+
def get_html_subtask_info(user: User, parent_url: str, parent_group: AnyGroup) -> str:
|
33
|
+
subtasks = get_subtasks(parent_group, web_only=True)
|
34
|
+
task_li = "\n".join(
|
35
|
+
[
|
36
|
+
get_html_task_li(parent_url, alias, subtask)
|
37
|
+
for alias, subtask in subtasks.items()
|
38
|
+
if user.can_access_task(subtask)
|
39
|
+
]
|
40
|
+
)
|
41
|
+
if task_li.strip() == "":
|
42
|
+
return ""
|
43
|
+
return f"<h5>Tasks</h5><ul>{task_li}</ul>"
|
44
|
+
|
45
|
+
|
46
|
+
def get_html_task_li(parent_url: str, alias: str, task: AnyTask) -> str:
|
47
|
+
if not parent_url.endswith("/"):
|
48
|
+
parent_url += "/"
|
49
|
+
return f'<li><a href="{parent_url}{alias}">{alias}</a> {task.description}</li>'
|
50
|
+
|
51
|
+
|
52
|
+
def get_html_subgroup_info(user: User, parent_url: str, parent_group: AnyGroup) -> str:
|
53
|
+
subgroups = get_non_empty_subgroups(parent_group, web_only=True)
|
54
|
+
group_li = "\n".join(
|
55
|
+
[
|
56
|
+
get_html_group_li(parent_url, alias, subgroup)
|
57
|
+
for alias, subgroup in subgroups.items()
|
58
|
+
if user.can_access_group(subgroup)
|
59
|
+
]
|
60
|
+
)
|
61
|
+
if group_li.strip() == "":
|
62
|
+
return ""
|
63
|
+
return f"<h5>Groups</h5><ul>{group_li}</ul>"
|
64
|
+
|
65
|
+
|
66
|
+
def get_html_group_li(parent_url: str, alias: str, group: AnyGroup) -> str:
|
67
|
+
if not parent_url.endswith("/"):
|
68
|
+
parent_url += "/"
|
69
|
+
return f'<li><a href="{parent_url}{alias}">{alias}</a> {group.description}</li>'
|
@@ -3,10 +3,10 @@ import os
|
|
3
3
|
|
4
4
|
from zrb.session_state_log.session_state_log import SessionStateLog, SessionStateLogList
|
5
5
|
from zrb.session_state_logger.any_session_state_logger import AnySessionStateLogger
|
6
|
+
from zrb.util.file import read_file, write_file
|
6
7
|
|
7
8
|
|
8
9
|
class FileSessionStateLogger(AnySessionStateLogger):
|
9
|
-
|
10
10
|
def __init__(self, session_log_dir: str):
|
11
11
|
self._session_log_dir = session_log_dir
|
12
12
|
|
@@ -15,20 +15,16 @@ class FileSessionStateLogger(AnySessionStateLogger):
|
|
15
15
|
session_dir_path = os.path.dirname(session_file_path)
|
16
16
|
if not os.path.isdir(session_dir_path):
|
17
17
|
os.makedirs(session_dir_path, exist_ok=True)
|
18
|
-
|
19
|
-
f.write(session_log.model_dump_json())
|
18
|
+
write_file(session_file_path, session_log.model_dump_json())
|
20
19
|
start_time = session_log.start_time
|
21
20
|
if start_time == "":
|
22
21
|
return
|
23
22
|
timeline_dir_path = self._get_timeline_dir_path(session_log)
|
24
|
-
os.
|
25
|
-
with open(os.path.join(timeline_dir_path, session_log.name), "w"):
|
26
|
-
pass
|
23
|
+
write_file(os.path.join(timeline_dir_path, session_log.name), "")
|
27
24
|
|
28
25
|
def read(self, session_name: str) -> SessionStateLog:
|
29
26
|
session_file_path = self._get_session_file_path(session_name)
|
30
|
-
|
31
|
-
return SessionStateLog.model_validate_json(f.read())
|
27
|
+
return SessionStateLog.model_validate_json(read_file(session_file_path))
|
32
28
|
|
33
29
|
def list(
|
34
30
|
self,
|
zrb/task/base_trigger.py
CHANGED
zrb/task/cmd_task.py
CHANGED
@@ -132,7 +132,7 @@ class CmdTask(BaseTask):
|
|
132
132
|
if return_code != 0:
|
133
133
|
ctx.log_error(f"Exit status: {return_code}")
|
134
134
|
raise Exception(
|
135
|
-
f"Process {self._name} exited ({return_code}): {cmd_result.
|
135
|
+
f"Process {self._name} exited ({return_code}): {cmd_result.error}"
|
136
136
|
)
|
137
137
|
ctx.log_info(f"Exit status: {return_code}")
|
138
138
|
return cmd_result
|
zrb/task/llm_task.py
CHANGED
@@ -15,6 +15,7 @@ from zrb.task.any_task import AnyTask
|
|
15
15
|
from zrb.task.base_task import BaseTask
|
16
16
|
from zrb.util.attr import get_str_attr
|
17
17
|
from zrb.util.cli.style import stylize_faint
|
18
|
+
from zrb.util.file import read_file, write_file
|
18
19
|
from zrb.util.llm.tool import callable_to_tool_schema
|
19
20
|
|
20
21
|
ListOfDict = list[dict[str, Any]]
|
@@ -32,7 +33,6 @@ def scratchpad(thought: str) -> str:
|
|
32
33
|
|
33
34
|
|
34
35
|
class LLMTask(BaseTask):
|
35
|
-
|
36
36
|
def __init__(
|
37
37
|
self,
|
38
38
|
name: str,
|
@@ -171,9 +171,7 @@ class LLMTask(BaseTask):
|
|
171
171
|
messages.append(tool_call_message)
|
172
172
|
continue
|
173
173
|
if history_file != "":
|
174
|
-
|
175
|
-
with open(history_file, "w") as f:
|
176
|
-
f.write(json.dumps(messages, indent=2))
|
174
|
+
write_file(history_file, json.dumps(messages, indent=2))
|
177
175
|
return response_message.content
|
178
176
|
|
179
177
|
def _get_model(self, ctx: AnyContext) -> str:
|
@@ -211,8 +209,7 @@ class LLMTask(BaseTask):
|
|
211
209
|
and history_file != ""
|
212
210
|
and os.path.isfile(history_file)
|
213
211
|
):
|
214
|
-
|
215
|
-
return json.loads(f.read())
|
212
|
+
return json.loads(read_file(history_file))
|
216
213
|
return self._history
|
217
214
|
|
218
215
|
def _get_history_file(self, ctx: AnyContext) -> str:
|
zrb/task/make_task.py
CHANGED
zrb/task/scaffolder.py
CHANGED
@@ -30,9 +30,11 @@ class Scaffolder(BaseTask):
|
|
30
30
|
destination_path: StrAttr | None = None,
|
31
31
|
render_destination_path: bool = True,
|
32
32
|
transform_path: TransformConfig = {},
|
33
|
+
render_transform_path: bool = True,
|
33
34
|
transform_content: (
|
34
35
|
list[AnyContentTransformer] | AnyContentTransformer | TransformConfig
|
35
36
|
) = [],
|
37
|
+
render_transform_content: bool = True,
|
36
38
|
execute_condition: BoolAttr = True,
|
37
39
|
retries: int = 2,
|
38
40
|
retry_period: float = 0,
|
@@ -70,7 +72,9 @@ class Scaffolder(BaseTask):
|
|
70
72
|
self._destination_path = destination_path
|
71
73
|
self._render_destination_path = render_destination_path
|
72
74
|
self._content_transformers = transform_content
|
75
|
+
self._render_content_transformers = render_transform_content
|
73
76
|
self._path_transformer = transform_path
|
77
|
+
self._render_path_transformer = render_transform_path
|
74
78
|
|
75
79
|
def _get_source_path(self, ctx: AnyContext) -> str:
|
76
80
|
return get_str_attr(ctx, self._source_path, "", auto_render=True)
|
@@ -80,9 +84,17 @@ class Scaffolder(BaseTask):
|
|
80
84
|
|
81
85
|
def _get_content_transformers(self) -> list[AnyContentTransformer]:
|
82
86
|
if callable(self._content_transformers):
|
83
|
-
return [
|
87
|
+
return [
|
88
|
+
ContentTransformer(match=".*", transform=self._content_transformers)
|
89
|
+
]
|
84
90
|
if isinstance(self._content_transformers, dict):
|
85
|
-
return [
|
91
|
+
return [
|
92
|
+
ContentTransformer(
|
93
|
+
match=".*",
|
94
|
+
transform=self._content_transformers,
|
95
|
+
auto_render=self._render_content_transformers,
|
96
|
+
)
|
97
|
+
]
|
86
98
|
if isinstance(self._content_transformers, AnyContentTransformer):
|
87
99
|
return [self._content_transformers]
|
88
100
|
return self._content_transformers
|
@@ -117,17 +129,19 @@ class Scaffolder(BaseTask):
|
|
117
129
|
dest_file = os.path.join(
|
118
130
|
dest_dir, self._transform_path(ctx, file_name)
|
119
131
|
)
|
132
|
+
ctx.log_info(f"Copying {src_file} to {dest_file}")
|
120
133
|
shutil.copy2(src_file, dest_file)
|
121
|
-
ctx.log_info(f"Copied {src_file} to {dest_file}")
|
122
134
|
else:
|
135
|
+
ctx.log_info(f"Copying {source_path} to {destination_path}")
|
123
136
|
shutil.copy2(source_path, destination_path)
|
124
|
-
ctx.log_info(f"Copied {source_path} to {destination_path}")
|
125
137
|
|
126
138
|
def _transform_path(self, ctx: AnyContext, file_path: str):
|
127
139
|
if callable(self._path_transformer):
|
128
140
|
return self._path_transformer(ctx, file_path)
|
129
141
|
new_file_path = file_path
|
130
142
|
for keyword, replacement in self._path_transformer.items():
|
143
|
+
if self._render_path_transformer:
|
144
|
+
replacement = ctx.render(replacement)
|
131
145
|
new_file_path = new_file_path.replace(keyword, replacement)
|
132
146
|
return new_file_path
|
133
147
|
|
zrb/task/scheduler.py
CHANGED
zrb/util/cmd/command.py
CHANGED
@@ -4,7 +4,7 @@ import libcst as cst
|
|
4
4
|
class ClassCodeAdder(cst.CSTTransformer):
|
5
5
|
def __init__(self, class_name: str, new_code: str):
|
6
6
|
self.class_name = class_name
|
7
|
-
self.new_code = cst.
|
7
|
+
self.new_code = cst.parse_module(new_code).body
|
8
8
|
self.class_found = False
|
9
9
|
|
10
10
|
def leave_ClassDef(
|
@@ -15,17 +15,17 @@ class ClassCodeAdder(cst.CSTTransformer):
|
|
15
15
|
self.class_found = True
|
16
16
|
# Add the method to the class body
|
17
17
|
new_body = updated_node.body.with_changes(
|
18
|
-
body=updated_node.body.body + (self.new_code
|
18
|
+
body=updated_node.body.body + tuple(self.new_code)
|
19
19
|
)
|
20
20
|
return updated_node.with_changes(body=new_body)
|
21
21
|
return updated_node
|
22
22
|
|
23
23
|
|
24
|
-
def
|
24
|
+
def append_code_to_class(original_code: str, class_name: str, new_code: str) -> str:
|
25
25
|
# Parse the original code into a module
|
26
26
|
module = cst.parse_module(original_code)
|
27
27
|
# Initialize transformer with the class name and method code
|
28
|
-
transformer = ClassCodeAdder(class_name,
|
28
|
+
transformer = ClassCodeAdder(class_name, new_code)
|
29
29
|
# Apply the transformation
|
30
30
|
modified_module = module.visit(transformer)
|
31
31
|
# Check if the class was found
|
@@ -5,7 +5,7 @@ class FunctionCodeAdder(cst.CSTTransformer):
|
|
5
5
|
def __init__(self, function_name: str, new_code: str):
|
6
6
|
self.function_name = function_name
|
7
7
|
# Use parse_module to handle multiple statements
|
8
|
-
self.new_code = cst.
|
8
|
+
self.new_code = cst.parse_module(new_code).body
|
9
9
|
self.function_found = False
|
10
10
|
|
11
11
|
def leave_FunctionDef(
|
@@ -16,13 +16,15 @@ class FunctionCodeAdder(cst.CSTTransformer):
|
|
16
16
|
self.function_found = True
|
17
17
|
# Add the method to the class body
|
18
18
|
new_body = updated_node.body.with_changes(
|
19
|
-
body=updated_node.body.body + (self.new_code
|
19
|
+
body=updated_node.body.body + tuple(self.new_code)
|
20
20
|
)
|
21
21
|
return updated_node.with_changes(body=new_body)
|
22
22
|
return updated_node
|
23
23
|
|
24
24
|
|
25
|
-
def
|
25
|
+
def append_code_to_function(
|
26
|
+
original_code: str, function_name: str, new_code: str
|
27
|
+
) -> str:
|
26
28
|
# Parse the original code into a module
|
27
29
|
module = cst.parse_module(original_code)
|
28
30
|
# Initialize the transformer with the necessary information
|
@@ -6,7 +6,7 @@ class MethodCodeAdder(cst.CSTTransformer):
|
|
6
6
|
self.class_name = class_name
|
7
7
|
self.method_name = method_name
|
8
8
|
# Use parse_module to handle multiple statements
|
9
|
-
self.new_code = cst.
|
9
|
+
self.new_code = cst.parse_module(new_code).body
|
10
10
|
self.class_found = False
|
11
11
|
self.method_found = False
|
12
12
|
|
@@ -27,7 +27,7 @@ class MethodCodeAdder(cst.CSTTransformer):
|
|
27
27
|
):
|
28
28
|
# Modify the target function by adding the new code
|
29
29
|
body_with_new_code = item.body.with_changes(
|
30
|
-
body=item.body.body + (self.new_code
|
30
|
+
body=item.body.body + tuple(self.new_code) # Add the new code
|
31
31
|
)
|
32
32
|
new_body.append(item.with_changes(body=body_with_new_code))
|
33
33
|
self.method_found = True
|
@@ -37,7 +37,7 @@ class MethodCodeAdder(cst.CSTTransformer):
|
|
37
37
|
return updated_node
|
38
38
|
|
39
39
|
|
40
|
-
def
|
40
|
+
def append_code_to_method(
|
41
41
|
original_code: str, class_name: str, function_name: str, new_code: str
|
42
42
|
) -> str:
|
43
43
|
# Parse the original code into a module
|
@@ -21,7 +21,7 @@ class FunctionCallParamAdder(cst.CSTTransformer):
|
|
21
21
|
return updated_node
|
22
22
|
|
23
23
|
|
24
|
-
def
|
24
|
+
def append_param_to_function_call(
|
25
25
|
original_code: str, func_name: str, new_param: str
|
26
26
|
) -> str:
|
27
27
|
# Parse the original code into a module
|
@@ -1,5 +1,5 @@
|
|
1
|
-
def
|
2
|
-
lines =
|
1
|
+
def prepend_code_to_module(original_code: str, new_code: str) -> str:
|
2
|
+
lines = original_code.splitlines()
|
3
3
|
last_import_index = -1
|
4
4
|
for i, line in enumerate(lines):
|
5
5
|
stripped_line = line.strip()
|
zrb/util/file.py
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
|
4
|
+
def read_file(file_path: str, replace_map: dict[str, str] = {}) -> str:
|
5
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
6
|
+
content = f.read()
|
7
|
+
for key, val in replace_map.items():
|
8
|
+
content = content.replace(key, val)
|
9
|
+
return content
|
10
|
+
|
11
|
+
|
12
|
+
def write_file(file_path: str, content: str | list[str]):
|
13
|
+
if isinstance(content, list):
|
14
|
+
content = "\n".join([line for line in content if line is not None])
|
15
|
+
dir_path = os.path.dirname(file_path)
|
16
|
+
os.makedirs(dir_path, exist_ok=True)
|
17
|
+
with open(file_path, "w") as f:
|
18
|
+
f.write(content.strip())
|