meltygui 0.1.0__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.
- meltygui/__init__.py +107 -0
- meltygui/accounts/__init__.py +0 -0
- meltygui/accounts/internet_accounts.py +1355 -0
- meltygui/chat/__init__.py +91 -0
- meltygui/chat/activity.py +75 -0
- meltygui/chat/backends.py +36 -0
- meltygui/chat/chat_interface.py +732 -0
- meltygui/chat/chat_proxy.py +352 -0
- meltygui/chat/codex_proxy.py +592 -0
- meltygui/chat/codex_settings.py +100 -0
- meltygui/chat/codex_transport.py +60 -0
- meltygui/chat/command_parser.py +204 -0
- meltygui/chat/images.py +227 -0
- meltygui/chat/messages.py +417 -0
- meltygui/chat/metadata.py +139 -0
- meltygui/chat/writer_locks.py +64 -0
- meltygui/code/__init__.py +0 -0
- meltygui/code/basic_converters.py +533 -0
- meltygui/code/chain_converters.py +2111 -0
- meltygui/code/code_checks.py +2209 -0
- meltygui/code/core_syntax.py +1430 -0
- meltygui/code/file_converters.py +1933 -0
- meltygui/code/fileref.py +702 -0
- meltygui/code/hotswap_guard.py +144 -0
- meltygui/code/libcst_conversion.py +9724 -0
- meltygui/code/live_instrument.py +392 -0
- meltygui/code/live_view.py +2490 -0
- meltygui/code/melty_scan.py +2684 -0
- meltygui/code/new_codecs.py +1255 -0
- meltygui/code/new_converters.py +3017 -0
- meltygui/code/project_code.py +278 -0
- meltygui/code/source_context.py +63 -0
- meltygui/code/symbol_roster.py +1588 -0
- meltygui/code/syntax_check.py +34 -0
- meltygui/code/syntax_check_worker.py +114 -0
- meltygui/completion/__init__.py +0 -0
- meltygui/completion/fim.py +1232 -0
- meltygui/completion/fim_context.py +481 -0
- meltygui/completion/providers/__init__.py +0 -0
- meltygui/completion/providers/anthropic_oauth.py +446 -0
- meltygui/completion/providers/anthropic_requests.py +69 -0
- meltygui/completion/providers/claude.py +203 -0
- meltygui/completion/providers/claude_usage.py +499 -0
- meltygui/completion/providers/codex_accounts.py +180 -0
- meltygui/completion/providers/copilot.py +617 -0
- meltygui/completion/providers/oauth_popup.py +220 -0
- meltygui/completion/providers/ollama.py +320 -0
- meltygui/completion/providers/profiles.py +23 -0
- meltygui/core/README.md +88 -0
- meltygui/core/__init__.py +1 -0
- meltygui/core/automation/__init__.py +1 -0
- meltygui/core/automation/action_core.py +153 -0
- meltygui/core/automation/collection_action.py +45 -0
- meltygui/core/automation/mcp_eval.py +167 -0
- meltygui/core/automation/mcp_hotswap.py +107 -0
- meltygui/core/automation/mcp_query.py +552 -0
- meltygui/core/automation/mcp_server.py +657 -0
- meltygui/core/automation/orchestration_core.py +2636 -0
- meltygui/core/automation/query_core.py +124 -0
- meltygui/core/automation/search_core.py +26 -0
- meltygui/core/automation/selector_core.py +340 -0
- meltygui/core/automation/value_core.py +1752 -0
- meltygui/core/cache/__init__.py +1 -0
- meltygui/core/cache/cache_diagnostics.py +0 -0
- meltygui/core/cache/invalidation_decoration.py +153 -0
- meltygui/core/cache/invalidation_tracker.py +43 -0
- meltygui/core/cache/tile_cache.py +5968 -0
- meltygui/core/conversion/__init__.py +1 -0
- meltygui/core/conversion/bubbling.py +599 -0
- meltygui/core/conversion/cache_tree.py +188 -0
- meltygui/core/conversion/chain.py +113 -0
- meltygui/core/conversion/converter_register.py +145 -0
- meltygui/core/conversion/data_decoration.py +67 -0
- meltygui/core/conversion/dict_conversion.py +1815 -0
- meltygui/core/conversion/dict_conversion_util.py +177 -0
- meltygui/core/conversion/dynamic_obj.py +89 -0
- meltygui/core/conversion/graph_compare.py +183 -0
- meltygui/core/conversion/load_save_v2.py +1032 -0
- meltygui/core/conversion/missing_saved_class.py +39 -0
- meltygui/core/conversion/path_finder.py +606 -0
- meltygui/core/conversion/render_host.py +1083 -0
- meltygui/core/core_render.py +6537 -0
- meltygui/core/definition_hotswap.py +231 -0
- meltygui/core/diagnostics/__init__.py +1 -0
- meltygui/core/diagnostics/attribute_churn.py +38 -0
- meltygui/core/diagnostics/fps_counter.py +39 -0
- meltygui/core/diagnostics/gpu_frame_timer.py +103 -0
- meltygui/core/diagnostics/inspection_core.py +169 -0
- meltygui/core/diagnostics/monitor_core.py +105 -0
- meltygui/core/diagnostics/notifications.py +706 -0
- meltygui/core/diagnostics/perf_trace.py +281 -0
- meltygui/core/diagnostics/profile_decoration.py +88 -0
- meltygui/core/diagnostics/resize_trace.py +62 -0
- meltygui/core/diagnostics/screenshot_core.py +247 -0
- meltygui/core/diagnostics/session_status.py +98 -0
- meltygui/core/diagnostics/trace_core.py +445 -0
- meltygui/core/files/__init__.py +1 -0
- meltygui/core/files/file_core.py +208 -0
- meltygui/core/files/file_explorer_core.py +104 -0
- meltygui/core/files/file_tree_core.py +198 -0
- meltygui/core/files/file_watch_core.py +43 -0
- meltygui/core/files/import_graph_core.py +43 -0
- meltygui/core/files/metadata_core.py +51 -0
- meltygui/core/graphics/__init__.py +1 -0
- meltygui/core/graphics/cuda_context_core.py +166 -0
- meltygui/core/graphics/cuda_interop_core.py +136 -0
- meltygui/core/graphics/cuda_kernel_core.py +91 -0
- meltygui/core/graphics/framebuffer_recorder.py +337 -0
- meltygui/core/graphics/gl_state.py +658 -0
- meltygui/core/graphics/lut_core.py +52 -0
- meltygui/core/graphics/overlay_renderer.py +984 -0
- meltygui/core/graphics/scene_target.py +180 -0
- meltygui/core/graphics/screenshot.py +439 -0
- meltygui/core/graphics/shader_func.py +478 -0
- meltygui/core/graphics/tensor_core.py +45 -0
- meltygui/core/graphics/text_texture.py +329 -0
- meltygui/core/graphics/wayland_color.py +635 -0
- meltygui/core/input/__init__.py +1 -0
- meltygui/core/input/collision.py +165 -0
- meltygui/core/input/drag_drop_core.py +1525 -0
- meltygui/core/input/hypr_left_drag.py +323 -0
- meltygui/core/input/input_core.py +245 -0
- meltygui/core/input/input_handler.py +1101 -0
- meltygui/core/input/mouse_cursor.py +355 -0
- meltygui/core/input/pynput_backend.py +1054 -0
- meltygui/core/input/space_mouse.py +338 -0
- meltygui/core/input/touchpad_backend.py +393 -0
- meltygui/core/input/view_selection.py +177 -0
- meltygui/core/layout/__init__.py +1 -0
- meltygui/core/layout/column_core.py +2153 -0
- meltygui/core/layout/cursor_core.py +161 -0
- meltygui/core/layout/dropdown_core.py +278 -0
- meltygui/core/layout/edge_constraints.py +155 -0
- meltygui/core/layout/grid_core.py +117 -0
- meltygui/core/layout/header_core.py +23 -0
- meltygui/core/layout/header_runtime.py +67 -0
- meltygui/core/layout/layout_core.py +87 -0
- meltygui/core/layout/tile_manager_core.py +591 -0
- meltygui/core/melty.py +6726 -0
- meltygui/core/module_map.json +896 -0
- meltygui/core/module_names.py +19 -0
- meltygui/core/rendering/__init__.py +1 -0
- meltygui/core/rendering/core_decoration.py +431 -0
- meltygui/core/rendering/core_render_helpers.py +328 -0
- meltygui/core/rendering/func_metadata.py +398 -0
- meltygui/core/rendering/mode.py +818 -0
- meltygui/core/rendering/mode_defaults.py +41 -0
- meltygui/core/rendering/modes.py +136 -0
- meltygui/core/rendering/parameter_core.py +1665 -0
- meltygui/core/rendering/render_dispatch.py +1891 -0
- meltygui/core/rendering/render_funcs.py +273 -0
- meltygui/core/rendering/shaped.py +312 -0
- meltygui/core/rendering/window_decoration.py +25 -0
- meltygui/core/runtime/__init__.py +1 -0
- meltygui/core/runtime/app.py +735 -0
- meltygui/core/runtime/app_session.py +140 -0
- meltygui/core/runtime/background.py +564 -0
- meltygui/core/runtime/extensions.py +53 -0
- meltygui/core/runtime/gc_manager.py +1163 -0
- meltygui/core/runtime/lifecycle.py +21 -0
- meltygui/core/runtime/paths.py +27 -0
- meltygui/core/runtime/settings.py +14 -0
- meltygui/core/runtime/singleton.py +16 -0
- meltygui/core/runtime/thread_safe_bool.py +24 -0
- meltygui/core/runtime/thread_signal.py +30 -0
- meltygui/core/runtime/toggles.py +3115 -0
- meltygui/core/services/__init__.py +1 -0
- meltygui/core/services/account_core.py +10 -0
- meltygui/core/services/chat_core.py +19 -0
- meltygui/core/services/claude_terminal_core.py +346 -0
- meltygui/core/services/terminal_core.py +458 -0
- meltygui/core/services/terminal_runtime.py +78 -0
- meltygui/core/styling/__init__.py +1 -0
- meltygui/core/styling/color_core.py +46 -0
- meltygui/core/styling/fonts.py +639 -0
- meltygui/core/styling/global_style.py +338 -0
- meltygui/core/styling/style.py +198 -0
- meltygui/core/styling/style_core.py +522 -0
- meltygui/core/styling/warm_start.py +149 -0
- meltygui/core/windowing/__init__.py +1 -0
- meltygui/core/windowing/backends/PYIMGUI_LICENSE +28 -0
- meltygui/core/windowing/backends/__init__.py +1 -0
- meltygui/core/windowing/backends/imgui_renderer.py +138 -0
- meltygui/core/windowing/backends/native_wayland.py +850 -0
- meltygui/core/windowing/backends/protocols/xdg-decoration-unstable-v1.xml +156 -0
- meltygui/core/windowing/backends/protocols/xdg-shell.xml +1420 -0
- meltygui/core/windowing/backends/wayland_protocol.py +101 -0
- meltygui/core/windowing/dock_core.py +182 -0
- meltygui/core/windowing/frame_geometry.py +42 -0
- meltygui/core/windowing/geometry_feed.py +864 -0
- meltygui/core/windowing/glfw_utils.py +1343 -0
- meltygui/core/windowing/os_frame.py +1552 -0
- meltygui/core/windowing/surface.py +643 -0
- meltygui/core/windowing/titlebar.py +1560 -0
- meltygui/core/windowing/titlebar_buttons.py +281 -0
- meltygui/core/windowing/wayland_move.py +932 -0
- meltygui/core/windowing/window_api.py +62 -0
- meltygui/core/windowing/window_constants.py +339 -0
- meltygui/core/windowing/window_visibility.py +162 -0
- meltygui/debug/__init__.py +0 -0
- meltygui/debug/app_view_utils.py +9 -0
- meltygui/editor/__init__.py +0 -0
- meltygui/editor/bash_syntax.py +30 -0
- meltygui/editor/code_line_fast.py +152 -0
- meltygui/editor/diff.py +139 -0
- meltygui/editor/external_changes.py +159 -0
- meltygui/editor/file_header.py +41 -0
- meltygui/editor/live_usage.py +169 -0
- meltygui/editor/live_view_views.py +1803 -0
- meltygui/editor/pending_save.py +1351 -0
- meltygui/editor/roster_tints.py +547 -0
- meltygui/editor/source_preview.py +16 -0
- meltygui/editor/source_tools.py +10 -0
- meltygui/editor/source_ui.py +70 -0
- meltygui/editor/spell_check.py +77 -0
- meltygui/editor/text_editor.py +9076 -0
- meltygui/editor/usage_picker.py +538 -0
- meltygui/events/__init__.py +0 -0
- meltygui/events/example.py +118 -0
- meltygui/examples/__init__.py +0 -0
- meltygui/examples/columns_demo.py +33 -0
- meltygui/examples/columns_window_demo.py +60 -0
- meltygui/examples/context_menu_demo.py +24 -0
- meltygui/examples/context_menu_window_demo.py +49 -0
- meltygui/examples/gui_playground.py +127 -0
- meltygui/examples/live_view_playground.py +256 -0
- meltygui/examples/lora.py +43 -0
- meltygui/examples/lora_data.py +59 -0
- meltygui/examples/lora_policies.py +67 -0
- meltygui/examples/mode_demo.py +49 -0
- meltygui/examples/modifies_demo.py +119 -0
- meltygui/examples/scalar_policies.py +60 -0
- meltygui/examples/style_layouts.py +149 -0
- meltygui/examples/tile_manager_demo.py +74 -0
- meltygui/examples/tint_demo.py +160 -0
- meltygui/examples/tint_functions.py +56 -0
- meltygui/examples/trace_demo.py +88 -0
- meltygui/examples/two_windows.py +36 -0
- meltygui/files/__init__.py +0 -0
- meltygui/files/fast_file_explorer.py +439 -0
- meltygui/gnome_extension/lsd-window-geometry@latent-descent/extension.js +237 -0
- meltygui/gnome_extension/lsd-window-geometry@latent-descent/lsd-window-geometry@latent-descent.iml +9 -0
- meltygui/gnome_extension/lsd-window-geometry@latent-descent/metadata.json +7 -0
- meltygui/graphics/__init__.py +6 -0
- meltygui/graphics/base.py +85 -0
- meltygui/graphics/examples.py +507 -0
- meltygui/graphics/executor.py +520 -0
- meltygui/graphics/filter.py +667 -0
- meltygui/graphics/filter.pyi +856 -0
- meltygui/graphics/generate_stubs.py +22 -0
- meltygui/graphics/registry.py +203 -0
- meltygui/graphics/shader_compiler.py +155 -0
- meltygui/graphics/shaders.py +1302 -0
- meltygui/graphics/stub_generator.py +250 -0
- meltygui/graphics/texture_manager.py +170 -0
- meltygui/graphics/texture_min_max.py +295 -0
- meltygui/hdr_color.py +757 -0
- meltygui/image_load.py +308 -0
- meltygui/model/__init__.py +1 -0
- meltygui/model/account_model.py +142 -0
- meltygui/model/camera_model.py +159 -0
- meltygui/model/chat_model.py +86 -0
- meltygui/model/code_model.py +62 -0
- meltygui/model/code_proxy_model.py +876 -0
- meltygui/model/collection_model.py +41 -0
- meltygui/model/color_model.py +127 -0
- meltygui/model/cuda_tensor_model.py +36 -0
- meltygui/model/cuda_texture_model.py +149 -0
- meltygui/model/dropdown_model.py +137 -0
- meltygui/model/file_metadata_model.py +73 -0
- meltygui/model/file_model.py +289 -0
- meltygui/model/format_model.py +390 -0
- meltygui/model/graph_model.py +98 -0
- meltygui/model/icon_model.py +1024 -0
- meltygui/model/import_graph_model.py +468 -0
- meltygui/model/layout_model.py +15 -0
- meltygui/model/lut_model.py +266 -0
- meltygui/model/search_model.py +173 -0
- meltygui/model/tensor_model.py +402 -0
- meltygui/model/terminal_model.py +329 -0
- meltygui/model/texture_model.py +146 -0
- meltygui/model/tile_model.py +24 -0
- meltygui/model/trace_model.py +198 -0
- meltygui/model/trace_report_model.py +146 -0
- meltygui/models/__init__.py +0 -0
- meltygui/models/file_meta.py +613 -0
- meltygui/models/function_console.py +184 -0
- meltygui/models/orchestration.py +48 -0
- meltygui/pbr.py +1576 -0
- meltygui/png_unfilter.c +49 -0
- meltygui/resources/JetBrainsMono-Regular.ttf +0 -0
- meltygui/resources/THIRD_PARTY_NOTICES.md +21 -0
- meltygui/resources/dejavu/DejaVuSans-Bold.ttf +0 -0
- meltygui/resources/dejavu/DejaVuSans-ExtraLight.ttf +0 -0
- meltygui/resources/dejavu/DejaVuSans.ttf +0 -0
- meltygui/resources/dejavu/LICENSE.txt +78 -0
- meltygui/resources/fontawesome-LICENSE.txt +121 -0
- meltygui/resources/fontawesome-webfont.ttf +0 -0
- meltygui/resources/hdri/studio_small_09_1k.hdr +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Bold.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-ExtraBold.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-ExtraLight.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Light.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Medium.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-SemiBold.ttf +0 -0
- meltygui/resources/jetbrains-weights/JetBrainsMono-Thin.ttf +0 -0
- meltygui/resources/jetbrains-weights/OFL.txt +93 -0
- meltygui/resources/jetbrains-weights/README.md +2 -0
- meltygui/state/__init__.py +0 -0
- meltygui/state/account_state.py +22 -0
- meltygui/state/animation_state.py +97 -0
- meltygui/state/annotation_state.py +22 -0
- meltygui/state/chat_state.py +36 -0
- meltygui/state/code_state.py +10 -0
- meltygui/state/core_enums.py +59 -0
- meltygui/state/core_markers.py +115 -0
- meltygui/state/core_undo.py +1075 -0
- meltygui/state/file_state.py +75 -0
- meltygui/state/graph_state.py +26 -0
- meltygui/state/inspection_state.py +47 -0
- meltygui/state/menu_state.py +10 -0
- meltygui/state/model_enums.py +11 -0
- meltygui/state/new_core_model.py +2394 -0
- meltygui/state/orchestration_state.py +14 -0
- meltygui/state/query_state.py +24 -0
- meltygui/state/tensor_state.py +10 -0
- meltygui/state/terminal_state.py +23 -0
- meltygui/state/trace_state.py +32 -0
- meltygui/state/voxel_state.py +12 -0
- meltygui/text_index.py +816 -0
- meltygui/utils/__init__.py +0 -0
- meltygui/utils/jump_to_code.py +344 -0
- meltygui/utils/pkl_inspect.py +90 -0
- meltygui/utils/render_utils.py +1419 -0
- meltygui/view/__init__.py +1 -0
- meltygui/view/account_view.py +524 -0
- meltygui/view/action_view.py +73 -0
- meltygui/view/chat_decoration_view.py +112 -0
- meltygui/view/chat_view.py +1703 -0
- meltygui/view/code_view.py +2677 -0
- meltygui/view/collection_view.py +1185 -0
- meltygui/view/color_view.py +824 -0
- meltygui/view/control_view.py +559 -0
- meltygui/view/decoration_view.py +439 -0
- meltygui/view/diagnostic_view.py +177 -0
- meltygui/view/dropdown_view.py +1082 -0
- meltygui/view/file_view.py +1599 -0
- meltygui/view/graph_cuda_view.py +105 -0
- meltygui/view/graph_view.py +882 -0
- meltygui/view/header_view.py +848 -0
- meltygui/view/input_view.py +238 -0
- meltygui/view/inspection_view.py +1783 -0
- meltygui/view/layout_view.py +596 -0
- meltygui/view/lut_view.py +45 -0
- meltygui/view/menu_view.py +212 -0
- meltygui/view/orchestration_view.py +658 -0
- meltygui/view/query_view.py +118 -0
- meltygui/view/search_view.py +342 -0
- meltygui/view/tab_view.py +258 -0
- meltygui/view/tensor_view.py +430 -0
- meltygui/view/terminal_view.py +355 -0
- meltygui/view/text_view.py +8031 -0
- meltygui/view/texture_view.py +480 -0
- meltygui/view/tile_view.py +38 -0
- meltygui/view/trace_view.py +923 -0
- meltygui/view/voxel_cuda_view.py +824 -0
- meltygui/view/voxel_view.py +1860 -0
- meltygui/view/window_view.py +111 -0
- meltygui-0.1.0.dist-info/METADATA +143 -0
- meltygui-0.1.0.dist-info/RECORD +372 -0
- meltygui-0.1.0.dist-info/WHEEL +4 -0
- meltygui-0.1.0.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""Actions window — renders Toggles' sibling Actions class (toggles.py), the
|
|
2
|
+
general-purpose stash for app triggers ("New file", "New Render Function").
|
|
3
|
+
|
|
4
|
+
Also registers the "Actions" global-search category: every function on the
|
|
5
|
+
Actions class is a hit, and activating one pops up the ActionRunner window —
|
|
6
|
+
its parameters (seeded from the function signature) as editable rows plus a
|
|
7
|
+
Run button that calls the function."""
|
|
8
|
+
|
|
9
|
+
import inspect
|
|
10
|
+
import types
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
import meltygui_imgui as imgui
|
|
14
|
+
|
|
15
|
+
from meltygui.core.melty import Melty
|
|
16
|
+
from meltygui.core.rendering.modes import Modes
|
|
17
|
+
from meltygui.core.diagnostics.notifications import notify
|
|
18
|
+
from meltygui.core.runtime.toggles import Actions
|
|
19
|
+
from meltygui.core.windowing.glfw_utils import request_render
|
|
20
|
+
from meltygui.core.core_render import render_func
|
|
21
|
+
from meltygui.core.rendering.core_decoration import Core
|
|
22
|
+
from meltygui.core.rendering.core_decoration import defaults
|
|
23
|
+
from meltygui.core.rendering.window_decoration import window
|
|
24
|
+
from meltygui.editor.source_ui import SearchHit
|
|
25
|
+
from meltygui.editor.source_ui import _category_tint
|
|
26
|
+
from meltygui.core.runtime.extensions import jump_to_symbol as _jump_to_symbol_def
|
|
27
|
+
from meltygui.core.rendering.render_dispatch import draw_any
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _action_funcs():
|
|
31
|
+
"""(name, function, icon) for every public function on Actions, definition
|
|
32
|
+
order. Reads vars() live each call so a hotswapped/added action shows up
|
|
33
|
+
without any cache to invalidate. The icon is the @defaults(icon=...)
|
|
34
|
+
registration — keyed by whatever object @defaults decorated, which is the
|
|
35
|
+
staticmethod wrapper when it sits outside @staticmethod and the raw
|
|
36
|
+
function when inside, so both keys are tried."""
|
|
37
|
+
out = []
|
|
38
|
+
for name, member in vars(Actions).items():
|
|
39
|
+
if name.startswith("_"):
|
|
40
|
+
continue
|
|
41
|
+
fn = member.__func__ if isinstance(member, (staticmethod, classmethod)) else member
|
|
42
|
+
if not isinstance(fn, types.FunctionType):
|
|
43
|
+
continue
|
|
44
|
+
icon = None
|
|
45
|
+
for key in (member, fn):
|
|
46
|
+
icon = Melty.default_kwargs_by_type.get(key, {}).get("icon")
|
|
47
|
+
if icon:
|
|
48
|
+
break
|
|
49
|
+
out.append((name, fn, icon))
|
|
50
|
+
return out
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _sig_label(name, fn):
|
|
54
|
+
"""`new_render_func(name='draw_other')` — the search-row label, so a hit
|
|
55
|
+
shows what inputs the runner will ask for."""
|
|
56
|
+
parts = []
|
|
57
|
+
for pname, p in inspect.signature(fn).parameters.items():
|
|
58
|
+
if p.default is not inspect.Parameter.empty:
|
|
59
|
+
parts.append(f"{pname}={p.default!r}")
|
|
60
|
+
else:
|
|
61
|
+
parts.append(pname)
|
|
62
|
+
return f"{name}({', '.join(parts)})"
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _seed_params(fn):
|
|
66
|
+
"""Initial editable values for a function's parameters: the signature
|
|
67
|
+
default where there is one, a fresh instance of the annotation type
|
|
68
|
+
otherwise (str -> "", int -> 0, ...), else an empty string."""
|
|
69
|
+
params = {}
|
|
70
|
+
for pname, p in inspect.signature(fn).parameters.items():
|
|
71
|
+
if p.default is not inspect.Parameter.empty:
|
|
72
|
+
params[pname] = p.default
|
|
73
|
+
elif isinstance(p.annotation, type):
|
|
74
|
+
try:
|
|
75
|
+
params[pname] = p.annotation()
|
|
76
|
+
except Exception:
|
|
77
|
+
params[pname] = ""
|
|
78
|
+
else:
|
|
79
|
+
params[pname] = ""
|
|
80
|
+
return params
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def activate_action(fn):
|
|
84
|
+
"""A search hit's activation: an action with parameters opens the
|
|
85
|
+
ActionRunner to fill them in; a parameterless one (screenshot,
|
|
86
|
+
claude_terminal) just RUNS — there is nothing to ask, and a popup with
|
|
87
|
+
only a Run button was a dead click."""
|
|
88
|
+
if not inspect.signature(fn).parameters:
|
|
89
|
+
try:
|
|
90
|
+
result = fn()
|
|
91
|
+
except Exception as e:
|
|
92
|
+
notify(f"Actions.{fn.__name__} failed: {e}", tag="actions")
|
|
93
|
+
else:
|
|
94
|
+
notify(f"Actions.{fn.__name__} -> {result!r}" if result is not None
|
|
95
|
+
else f"Actions.{fn.__name__} ran", tag="actions")
|
|
96
|
+
request_render()
|
|
97
|
+
return
|
|
98
|
+
open_action_runner(fn)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def open_action_runner(fn):
|
|
102
|
+
"""Point the ActionRunner window at `fn` and summon it next to the search
|
|
103
|
+
window (the same come-to-you placement window hits use)."""
|
|
104
|
+
ActionRunner.action = fn
|
|
105
|
+
ActionRunner.params = _seed_params(fn)
|
|
106
|
+
ActionRunner._focus_requested = True
|
|
107
|
+
ds = Core.melty.open_window("ActionRunner")
|
|
108
|
+
if ds is not None:
|
|
109
|
+
gs = Core.melty.find_window("GlobalSearch")
|
|
110
|
+
if gs is not None and gs.abs_left is not None:
|
|
111
|
+
Core.melty.summon_window(ds, gs.abs_left, gs.abs_top)
|
|
112
|
+
Core.melty.focused_ds = ds
|
|
113
|
+
# The action and params changed outside the window's body - a cached
|
|
114
|
+
# blit would keep showing the previous action.
|
|
115
|
+
ds.invalidate()
|
|
116
|
+
request_render()
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _close_action_runner():
|
|
120
|
+
"""Close the runner and release any text focus a param field holds — the
|
|
121
|
+
shared exit for the title-row X, Esc (draw_main's root handler) and a
|
|
122
|
+
successful run."""
|
|
123
|
+
win = Core.melty.find_window("ActionRunner")
|
|
124
|
+
if win is not None:
|
|
125
|
+
win.closed = True
|
|
126
|
+
Core.melty.text_focused_ds = None
|
|
127
|
+
request_render()
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _run_action(input_value):
|
|
131
|
+
"""Call the runner's action with the edited params. A successful run
|
|
132
|
+
closes the window; an error keeps it up (with a notification) so the
|
|
133
|
+
inputs can be fixed."""
|
|
134
|
+
fn = input_value.action
|
|
135
|
+
try:
|
|
136
|
+
result = fn(**dict(input_value.params))
|
|
137
|
+
except Exception as e:
|
|
138
|
+
notify(f"Actions.{fn.__name__} failed: {e}", tag="actions")
|
|
139
|
+
else:
|
|
140
|
+
notify(f"Actions.{fn.__name__} -> {result!r}" if result is not None
|
|
141
|
+
else f"Actions.{fn.__name__} ran", tag="actions")
|
|
142
|
+
_close_action_runner()
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
from meltygui.view.action_view import draw_action_runner
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@window(view_func=draw_action_runner, mode=Modes.WINDOW_AUTO_FIT, always_on_top=True)
|
|
149
|
+
@defaults(tint=(0.92, 0.58, 0.25))
|
|
150
|
+
class ActionRunner:
|
|
151
|
+
action = None # the Actions function the window is parameterizing
|
|
152
|
+
params = {} # name -> value being edited, seeded from the signature
|
|
153
|
+
_focus_requested = False # one-shot: focus the first str param next frame
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class OperationType(Enum):
|
|
5
|
+
COPY = 'copy'
|
|
6
|
+
MOVE = 'move'
|
|
7
|
+
ADD = 'add'
|
|
8
|
+
DELETE = 'delete'
|
|
9
|
+
NAME_CHANGE = 'name_change'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CollectionAction:
|
|
13
|
+
def __init__(self,
|
|
14
|
+
target_unique=None,
|
|
15
|
+
source_unique=None,
|
|
16
|
+
target_tag=None,
|
|
17
|
+
target_key=None,
|
|
18
|
+
source_key=None,
|
|
19
|
+
source_collection=None,
|
|
20
|
+
target_collection=None,
|
|
21
|
+
operation=OperationType.MOVE):
|
|
22
|
+
self.target_unique = target_unique
|
|
23
|
+
self.target_key = target_key
|
|
24
|
+
self.target_tag = target_tag
|
|
25
|
+
self.target_collection = target_collection
|
|
26
|
+
self.target_draw_state = None
|
|
27
|
+
|
|
28
|
+
self.source_unique = source_unique
|
|
29
|
+
self.source_key = source_key
|
|
30
|
+
self.source_collection = source_collection
|
|
31
|
+
self.source_draw_state = None
|
|
32
|
+
|
|
33
|
+
self.operation = operation
|
|
34
|
+
self.class_move = False
|
|
35
|
+
self.target_class = None
|
|
36
|
+
|
|
37
|
+
def print(self):
|
|
38
|
+
print(f"CollectionAction: op {self.operation}\n"
|
|
39
|
+
f"source_key {self.source_key}\n"
|
|
40
|
+
f"source_unique {self.source_unique}\n"
|
|
41
|
+
f"target_key {self.target_key}\n"
|
|
42
|
+
f"target_unique {self.target_unique}\n"
|
|
43
|
+
f"target_tag {self.target_tag}\n"
|
|
44
|
+
f"source collection {type(self.source_collection).__name__}\n"
|
|
45
|
+
f"target collection {type(self.target_collection).__name__}")
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"""Evaluate Python in the live launcher process via MCP.
|
|
2
|
+
|
|
3
|
+
When a studio session is running the snippet runs on the render thread (GL
|
|
4
|
+
context current, safe to read/poke Melty + imgui state) via a post_frame
|
|
5
|
+
hand-off, mirroring screenshot.py; otherwise it runs inline on the caller's
|
|
6
|
+
thread (fine for pure-Python inspection of launcher/server state).
|
|
7
|
+
|
|
8
|
+
`Melty` and `server`/`model_server` are pre-bound; import anything else you
|
|
9
|
+
need. A trailing expression's repr is returned alongside captured stdout/stderr.
|
|
10
|
+
|
|
11
|
+
This is arbitrary in-process code execution — intended for inspecting and
|
|
12
|
+
poking live state while iterating.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import threading
|
|
16
|
+
|
|
17
|
+
_pending = []
|
|
18
|
+
_lock = threading.Lock()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _build_namespace(extra=None):
|
|
22
|
+
ns = {"__builtins__": __builtins__}
|
|
23
|
+
try:
|
|
24
|
+
from meltygui.core.melty import Melty
|
|
25
|
+
ns["Melty"] = Melty
|
|
26
|
+
# Conveniences reachable from Melty: the studio (vis) and the root
|
|
27
|
+
# AppModel (vis.root). Everything here derives from Melty.
|
|
28
|
+
vis = getattr(Melty, "vis", None)
|
|
29
|
+
if vis is not None:
|
|
30
|
+
ns["vis"] = vis
|
|
31
|
+
root = getattr(vis, "root", None)
|
|
32
|
+
if root is not None:
|
|
33
|
+
ns["app"] = root
|
|
34
|
+
ns["root"] = root
|
|
35
|
+
except Exception:
|
|
36
|
+
pass
|
|
37
|
+
if extra:
|
|
38
|
+
ns.update(extra)
|
|
39
|
+
return ns
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _run_code(code, extra=None):
|
|
43
|
+
"""Execute `code`, returning (stdout_text, result_repr_or_None, error_or_None).
|
|
44
|
+
|
|
45
|
+
Tries to evaluate it as a single expression first (to capture a value);
|
|
46
|
+
falls back to exec for statements.
|
|
47
|
+
"""
|
|
48
|
+
import io
|
|
49
|
+
import contextlib
|
|
50
|
+
import traceback
|
|
51
|
+
|
|
52
|
+
ns = _build_namespace(extra)
|
|
53
|
+
buf = io.StringIO()
|
|
54
|
+
result = None
|
|
55
|
+
error = None
|
|
56
|
+
with contextlib.redirect_stdout(buf), contextlib.redirect_stderr(buf):
|
|
57
|
+
try:
|
|
58
|
+
try:
|
|
59
|
+
compiled = compile(code, "<eval_python>", "eval")
|
|
60
|
+
except SyntaxError:
|
|
61
|
+
compiled = None
|
|
62
|
+
if compiled is not None:
|
|
63
|
+
value = eval(compiled, ns)
|
|
64
|
+
if value is not None:
|
|
65
|
+
result = repr(value)
|
|
66
|
+
else:
|
|
67
|
+
exec(compile(code, "<eval_python>", "exec"), ns)
|
|
68
|
+
except Exception:
|
|
69
|
+
error = traceback.format_exc()
|
|
70
|
+
return buf.getvalue(), result, error
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def request_eval(code, model_server, timeout=10.0):
|
|
74
|
+
"""Run `code` and return formatted text (where it ran + stdout + result/error)."""
|
|
75
|
+
extra = {"server": model_server, "model_server": model_server}
|
|
76
|
+
|
|
77
|
+
studio_running = False
|
|
78
|
+
try:
|
|
79
|
+
studio_running = model_server._studio_running()
|
|
80
|
+
except Exception:
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
if not studio_running:
|
|
84
|
+
out, result, error = _run_code(code, extra)
|
|
85
|
+
return _format(out, result, error, where="launcher thread (no studio)")
|
|
86
|
+
|
|
87
|
+
req = {"code": code, "extra": extra, "event": threading.Event(),
|
|
88
|
+
"out": "", "result": None, "error": None}
|
|
89
|
+
with _lock:
|
|
90
|
+
_pending.append(req)
|
|
91
|
+
try:
|
|
92
|
+
from meltygui.core.windowing.glfw_utils import request_render
|
|
93
|
+
request_render() # force a frame so the request is served soon
|
|
94
|
+
except Exception:
|
|
95
|
+
pass
|
|
96
|
+
|
|
97
|
+
if not req["event"].wait(timeout):
|
|
98
|
+
with _lock:
|
|
99
|
+
if req in _pending:
|
|
100
|
+
_pending.remove(req)
|
|
101
|
+
return f"timed out after {timeout:.0f}s waiting for the render thread"
|
|
102
|
+
return _format(req["out"], req["result"], req["error"], where="render thread")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def request_call(fn, model_server, timeout=10.0):
|
|
106
|
+
"""Run the no-arg callable `fn` on the render thread (inline when no
|
|
107
|
+
studio is running) and return `(result, error_text)`. The typed MCP
|
|
108
|
+
query tools (mcp_query.py) ride this instead of eval_python's source
|
|
109
|
+
string: same queue, same post_frame drain, a Python value back."""
|
|
110
|
+
import traceback
|
|
111
|
+
studio_running = False
|
|
112
|
+
try:
|
|
113
|
+
studio_running = model_server._studio_running()
|
|
114
|
+
except Exception:
|
|
115
|
+
pass
|
|
116
|
+
if not studio_running:
|
|
117
|
+
try:
|
|
118
|
+
return fn(), None
|
|
119
|
+
except Exception:
|
|
120
|
+
return None, traceback.format_exc()
|
|
121
|
+
|
|
122
|
+
req = {"fn": fn, "event": threading.Event(), "result": None, "error": None}
|
|
123
|
+
with _lock:
|
|
124
|
+
_pending.append(req)
|
|
125
|
+
try:
|
|
126
|
+
from meltygui.core.windowing.glfw_utils import request_render
|
|
127
|
+
request_render()
|
|
128
|
+
except Exception:
|
|
129
|
+
pass
|
|
130
|
+
if not req["event"].wait(timeout):
|
|
131
|
+
with _lock:
|
|
132
|
+
if req in _pending:
|
|
133
|
+
_pending.remove(req)
|
|
134
|
+
return None, f"timed out after {timeout:.0f}s waiting for the render thread"
|
|
135
|
+
return req["result"], req["error"]
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def process_evals():
|
|
139
|
+
"""Run pending eval requests on the render thread. Call from post_frame."""
|
|
140
|
+
import traceback
|
|
141
|
+
with _lock:
|
|
142
|
+
if not _pending:
|
|
143
|
+
return
|
|
144
|
+
reqs = _pending[:]
|
|
145
|
+
_pending.clear()
|
|
146
|
+
for req in reqs:
|
|
147
|
+
if "fn" in req:
|
|
148
|
+
try:
|
|
149
|
+
req["result"] = req["fn"]()
|
|
150
|
+
except Exception:
|
|
151
|
+
req["error"] = traceback.format_exc()
|
|
152
|
+
else:
|
|
153
|
+
req["out"], req["result"], req["error"] = _run_code(req["code"], req["extra"])
|
|
154
|
+
req["event"].set()
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _format(out, result, error, where):
|
|
158
|
+
parts = [f"[ran on {where}]"]
|
|
159
|
+
if out.strip():
|
|
160
|
+
parts.append("stdout:\n" + out.rstrip())
|
|
161
|
+
if result is not None:
|
|
162
|
+
parts.append("result: " + result)
|
|
163
|
+
if error:
|
|
164
|
+
parts.append("error:\n" + error.rstrip())
|
|
165
|
+
if len(parts) == 1:
|
|
166
|
+
parts.append("(no output)")
|
|
167
|
+
return "\n".join(parts)
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""Hotswap a project source file into the running process, for the MCP server.
|
|
2
|
+
|
|
3
|
+
Lets an MCP caller apply code edits to a live studio without a full restart. It
|
|
4
|
+
reuses the editor's hotswap machinery rather than re-implementing it:
|
|
5
|
+
|
|
6
|
+
* ``_recompile_module`` (file_converters.py) compiles the new source and patches
|
|
7
|
+
every function/class in the module **in place** — existing references (imported
|
|
8
|
+
names, live instances) keep working because their ``__code__`` is overwritten
|
|
9
|
+
rather than the objects being replaced.
|
|
10
|
+
* It registers a rollback with ``hotswap_guard``, so a swap that compiles cleanly
|
|
11
|
+
but throws at runtime is auto-reverted by the render loop's except hook.
|
|
12
|
+
* ``is_editable_source`` is the same fail-closed gate the editor uses — only paths
|
|
13
|
+
inside the project tree are ever compiled or written.
|
|
14
|
+
|
|
15
|
+
The launcher (which hosts the MCP server) runs the studio in-process, so the
|
|
16
|
+
studio's modules live in this process's ``sys.modules`` and can be patched from
|
|
17
|
+
the MCP server thread — the same off-render-thread path the editor's background
|
|
18
|
+
recompile already uses.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
import sys
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _resolve_module(path):
|
|
26
|
+
"""Find the live module object loaded from `path` (resolved), or None."""
|
|
27
|
+
target = Path(path).resolve()
|
|
28
|
+
for mod in list(sys.modules.values()):
|
|
29
|
+
f = getattr(mod, "__file__", None)
|
|
30
|
+
if not f:
|
|
31
|
+
continue
|
|
32
|
+
try:
|
|
33
|
+
if Path(f).resolve() == target:
|
|
34
|
+
return mod
|
|
35
|
+
except (OSError, ValueError):
|
|
36
|
+
continue
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def hotswap_file(path, source=None):
|
|
41
|
+
"""Recompile `path`'s module into the running process and return a status line.
|
|
42
|
+
|
|
43
|
+
If `source` is None, the file's current on-disk contents are reloaded. If
|
|
44
|
+
`source` is given, it is hotswapped first and persisted to disk only after a
|
|
45
|
+
clean compile, so a syntax error never leaves broken code on disk.
|
|
46
|
+
"""
|
|
47
|
+
# Imported lazily: this module is loaded by the MCP server, which must not
|
|
48
|
+
# drag in the (imgui-heavy) editor stack unless a hotswap is actually asked for.
|
|
49
|
+
from meltygui.code.file_converters import _recompile_module
|
|
50
|
+
from meltygui.code.fileref import is_editable_source
|
|
51
|
+
from meltygui.code.libcst_conversion import invalidate_usage_cache
|
|
52
|
+
|
|
53
|
+
p = Path(path).resolve()
|
|
54
|
+
if not is_editable_source(p):
|
|
55
|
+
return f"refusing to hotswap source outside the project tree: {p}"
|
|
56
|
+
if source is None and not p.exists():
|
|
57
|
+
return f"no such file: {p}"
|
|
58
|
+
|
|
59
|
+
module = _resolve_module(p)
|
|
60
|
+
if module is None:
|
|
61
|
+
return (f"no live module is loaded from {p} — nothing to hotswap. "
|
|
62
|
+
f"(The file must already be imported in the running process.)")
|
|
63
|
+
|
|
64
|
+
provided = source is not None
|
|
65
|
+
if not provided:
|
|
66
|
+
try:
|
|
67
|
+
source = p.read_text(encoding="utf-8")
|
|
68
|
+
except Exception as e:
|
|
69
|
+
return f"could not read {p}: {e}"
|
|
70
|
+
|
|
71
|
+
# Swap the live module from the in-memory source first; only touch disk on
|
|
72
|
+
# success. _recompile_module RAISES on a syntax error (compile() in its
|
|
73
|
+
# try) and RETURNS the exception on an exec-time error - handle both.
|
|
74
|
+
try:
|
|
75
|
+
err = _recompile_module(module, source, str(p))
|
|
76
|
+
except Exception as e:
|
|
77
|
+
err = e
|
|
78
|
+
if err is not None:
|
|
79
|
+
return (f"hotswap FAILED for {module.__name__} ({p.name}): "
|
|
80
|
+
f"{type(err).__name__}: {err} — live module unchanged, disk unchanged")
|
|
81
|
+
|
|
82
|
+
if provided:
|
|
83
|
+
try:
|
|
84
|
+
p.write_text(source, encoding="utf-8")
|
|
85
|
+
except Exception as e:
|
|
86
|
+
return (f"hotswapped {module.__name__} live, but FAILED to persist to disk: {e} "
|
|
87
|
+
f"— change will be lost on restart")
|
|
88
|
+
|
|
89
|
+
# Refresh the line caches in BOTH paths - a from-disk reload means the file
|
|
90
|
+
# was just changed by an external editor, so linecache may still hold the
|
|
91
|
+
# pre-save content. Stale lines make getsourcelines-based span resolution
|
|
92
|
+
# (and thus the in-process editor's next save) splice at wrong offsets.
|
|
93
|
+
invalidate_usage_cache(p)
|
|
94
|
+
import linecache
|
|
95
|
+
linecache.checkcache(str(p))
|
|
96
|
+
|
|
97
|
+
# Wake the render loop so the new code runs on the next frame.
|
|
98
|
+
try:
|
|
99
|
+
from meltygui.core.windowing.glfw_utils import request_render
|
|
100
|
+
request_render()
|
|
101
|
+
except Exception:
|
|
102
|
+
pass
|
|
103
|
+
|
|
104
|
+
verb = "applied + saved to disk" if provided else "reloaded from disk"
|
|
105
|
+
return (f"hotswapped {module.__name__} ({p.name}) — {verb}. "
|
|
106
|
+
f"Every function/class in the file was patched in place; a runtime "
|
|
107
|
+
f"error will auto-revert it via the hotswap guard.")
|