From 8c8538b0e83a2f57d00597d7c5b853777fd55c63 Mon Sep 17 00:00:00 2001 From: tmoonlight Date: Sun, 27 Sep 2026 17:21:59 +0800 Subject: [PATCH 1/8] =?UTF-8?q?refactor20260927(layers/P2-03):=20=E5=B9=B3?= =?UTF-8?q?=E5=8F=B0=E4=BB=B6=E4=B8=8E=20pty=20=E7=BA=AF=E6=90=AC=E8=BF=81?= =?UTF-8?q?=E5=88=B0=20src/platform=E3=80=81src/pty=20=E5=8F=8A=20tests=20?= =?UTF-8?q?=E9=95=9C=E5=83=8F=20[mechanical]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按 scripts/refactor/src_layout_map.tsv 中 phase=P2-03 的 61 行 git mv(45 个 src 文件 + src/web/pty/ 整目录 9 个文件 + 15 条 tests 镜像行 17 个文件),共 71 个文件,全部 R100: - src/utils/{clipboard,open_url,power_inhibitor}.* -> src/platform/;utils 的 terminal_* 与 upgrade/console.hpp -> src/platform/terminal/ - hooks/hook_runner.* -> platform/process/process_runner.*;lsp/lsp_process.* -> platform/process/piped_process.*;lsp/lsp_which.* -> platform/process/which.*;daemon/platform{.hpp,_posix.cpp,_windows.cpp} -> platform/process/os_process* - desktop/locale.* -> platform/;desktop 的 folder_picker / context_picker / open_in_explorer / notifications* / custom_toast* / strings -> platform/native_ui/ - src/web/pty/ -> src/pty/;tests/web/pty/ -> tests/pty/;14 个测试 -> tests/platform/ 验证:git diff --cached -M100% --name-status 71 行全部 R100;本提交不改任何文件内容,include 改写与 CMake 在后续提交。 --- src/{utils => platform}/clipboard.cpp | 0 src/{utils => platform}/clipboard.hpp | 0 src/{desktop => platform}/locale.cpp | 0 src/{desktop => platform}/locale.hpp | 0 src/{desktop => platform/native_ui}/context_picker.cpp | 0 src/{desktop => platform/native_ui}/context_picker.hpp | 0 src/{desktop => platform/native_ui}/custom_toast.cpp | 0 src/{desktop => platform/native_ui}/custom_toast.hpp | 0 src/{desktop => platform/native_ui}/custom_toast_win.cpp | 0 src/{desktop => platform/native_ui}/folder_picker.hpp | 0 src/{desktop => platform/native_ui}/folder_picker_mac.mm | 0 src/{desktop => platform/native_ui}/folder_picker_win.cpp | 0 src/{desktop => platform/native_ui}/notifications.cpp | 0 src/{desktop => platform/native_ui}/notifications.hpp | 0 src/{desktop => platform/native_ui}/notifications_backend.hpp | 0 src/{desktop => platform/native_ui}/notifications_mac.mm | 0 src/{desktop => platform/native_ui}/notifications_stub.cpp | 0 src/{desktop => platform/native_ui}/notifications_win.cpp | 0 src/{desktop => platform/native_ui}/open_in_explorer.cpp | 0 src/{desktop => platform/native_ui}/open_in_explorer.hpp | 0 src/{desktop => platform/native_ui}/strings.cpp | 0 src/{desktop => platform/native_ui}/strings.hpp | 0 src/{utils => platform}/open_url.cpp | 0 src/{utils => platform}/open_url.hpp | 0 src/{utils => platform}/power_inhibitor.cpp | 0 src/{utils => platform}/power_inhibitor.hpp | 0 src/{daemon/platform.hpp => platform/process/os_process.hpp} | 0 .../platform_posix.cpp => platform/process/os_process_posix.cpp} | 0 .../process/os_process_windows.cpp} | 0 src/{lsp/lsp_process.cpp => platform/process/piped_process.cpp} | 0 src/{lsp/lsp_process.hpp => platform/process/piped_process.hpp} | 0 .../hook_runner.cpp => platform/process/process_runner.cpp} | 0 .../hook_runner.hpp => platform/process/process_runner.hpp} | 0 src/{lsp/lsp_which.cpp => platform/process/which.cpp} | 0 src/{lsp/lsp_which.hpp => platform/process/which.hpp} | 0 src/{upgrade => platform/terminal}/console.hpp | 0 src/{utils => platform/terminal}/terminal_capability.cpp | 0 src/{utils => platform/terminal}/terminal_capability.hpp | 0 src/{utils => platform/terminal}/terminal_input.hpp | 0 src/{utils => platform/terminal}/terminal_theme_detect.cpp | 0 src/{utils => platform/terminal}/terminal_theme_detect.hpp | 0 src/{utils => platform/terminal}/terminal_theme_detect_posix.cpp | 0 src/{utils => platform/terminal}/terminal_theme_detect_win.cpp | 0 src/{utils => platform/terminal}/terminal_title.cpp | 0 src/{utils => platform/terminal}/terminal_title.hpp | 0 src/{web => }/pty/pty_backend.hpp | 0 src/{web => }/pty/pty_backend_posix.cpp | 0 src/{web => }/pty/pty_backend_win.cpp | 0 src/{web => }/pty/pty_session_registry.cpp | 0 src/{web => }/pty/pty_session_registry.hpp | 0 src/{web => }/pty/pty_shell.cpp | 0 src/{web => }/pty/winpty_agent_embedded.hpp | 0 src/{web => }/pty/winpty_agent_location.cpp | 0 src/{web => }/pty/winpty_agent_location.hpp | 0 tests/{utils => platform}/clipboard_test.cpp | 0 tests/{desktop => platform}/custom_toast_layout_test.cpp | 0 tests/{hooks => platform}/hook_runner_test.cpp | 0 tests/{desktop => platform}/locale_test.cpp | 0 tests/{lsp => platform}/lsp_which_test.cpp | 0 tests/{desktop => platform}/notifications_native_test.cpp | 0 tests/{desktop => platform}/notifications_test.cpp | 0 tests/{desktop => platform}/open_in_explorer_test.cpp | 0 tests/{utils => platform}/open_url_test.cpp | 0 tests/{utils => platform}/power_inhibitor_test.cpp | 0 tests/{desktop => platform}/strings_test.cpp | 0 tests/{utils => platform}/terminal_capability_test.cpp | 0 tests/{utils => platform}/terminal_theme_detect_test.cpp | 0 tests/{utils => platform}/terminal_title_test.cpp | 0 tests/{web => }/pty/pty_backend_test.cpp | 0 tests/{web => }/pty/pty_session_registry_test.cpp | 0 tests/{web => }/pty/winpty_spike_test.cpp | 0 71 files changed, 0 insertions(+), 0 deletions(-) rename src/{utils => platform}/clipboard.cpp (100%) rename src/{utils => platform}/clipboard.hpp (100%) rename src/{desktop => platform}/locale.cpp (100%) rename src/{desktop => platform}/locale.hpp (100%) rename src/{desktop => platform/native_ui}/context_picker.cpp (100%) rename src/{desktop => platform/native_ui}/context_picker.hpp (100%) rename src/{desktop => platform/native_ui}/custom_toast.cpp (100%) rename src/{desktop => platform/native_ui}/custom_toast.hpp (100%) rename src/{desktop => platform/native_ui}/custom_toast_win.cpp (100%) rename src/{desktop => platform/native_ui}/folder_picker.hpp (100%) rename src/{desktop => platform/native_ui}/folder_picker_mac.mm (100%) rename src/{desktop => platform/native_ui}/folder_picker_win.cpp (100%) rename src/{desktop => platform/native_ui}/notifications.cpp (100%) rename src/{desktop => platform/native_ui}/notifications.hpp (100%) rename src/{desktop => platform/native_ui}/notifications_backend.hpp (100%) rename src/{desktop => platform/native_ui}/notifications_mac.mm (100%) rename src/{desktop => platform/native_ui}/notifications_stub.cpp (100%) rename src/{desktop => platform/native_ui}/notifications_win.cpp (100%) rename src/{desktop => platform/native_ui}/open_in_explorer.cpp (100%) rename src/{desktop => platform/native_ui}/open_in_explorer.hpp (100%) rename src/{desktop => platform/native_ui}/strings.cpp (100%) rename src/{desktop => platform/native_ui}/strings.hpp (100%) rename src/{utils => platform}/open_url.cpp (100%) rename src/{utils => platform}/open_url.hpp (100%) rename src/{utils => platform}/power_inhibitor.cpp (100%) rename src/{utils => platform}/power_inhibitor.hpp (100%) rename src/{daemon/platform.hpp => platform/process/os_process.hpp} (100%) rename src/{daemon/platform_posix.cpp => platform/process/os_process_posix.cpp} (100%) rename src/{daemon/platform_windows.cpp => platform/process/os_process_windows.cpp} (100%) rename src/{lsp/lsp_process.cpp => platform/process/piped_process.cpp} (100%) rename src/{lsp/lsp_process.hpp => platform/process/piped_process.hpp} (100%) rename src/{hooks/hook_runner.cpp => platform/process/process_runner.cpp} (100%) rename src/{hooks/hook_runner.hpp => platform/process/process_runner.hpp} (100%) rename src/{lsp/lsp_which.cpp => platform/process/which.cpp} (100%) rename src/{lsp/lsp_which.hpp => platform/process/which.hpp} (100%) rename src/{upgrade => platform/terminal}/console.hpp (100%) rename src/{utils => platform/terminal}/terminal_capability.cpp (100%) rename src/{utils => platform/terminal}/terminal_capability.hpp (100%) rename src/{utils => platform/terminal}/terminal_input.hpp (100%) rename src/{utils => platform/terminal}/terminal_theme_detect.cpp (100%) rename src/{utils => platform/terminal}/terminal_theme_detect.hpp (100%) rename src/{utils => platform/terminal}/terminal_theme_detect_posix.cpp (100%) rename src/{utils => platform/terminal}/terminal_theme_detect_win.cpp (100%) rename src/{utils => platform/terminal}/terminal_title.cpp (100%) rename src/{utils => platform/terminal}/terminal_title.hpp (100%) rename src/{web => }/pty/pty_backend.hpp (100%) rename src/{web => }/pty/pty_backend_posix.cpp (100%) rename src/{web => }/pty/pty_backend_win.cpp (100%) rename src/{web => }/pty/pty_session_registry.cpp (100%) rename src/{web => }/pty/pty_session_registry.hpp (100%) rename src/{web => }/pty/pty_shell.cpp (100%) rename src/{web => }/pty/winpty_agent_embedded.hpp (100%) rename src/{web => }/pty/winpty_agent_location.cpp (100%) rename src/{web => }/pty/winpty_agent_location.hpp (100%) rename tests/{utils => platform}/clipboard_test.cpp (100%) rename tests/{desktop => platform}/custom_toast_layout_test.cpp (100%) rename tests/{hooks => platform}/hook_runner_test.cpp (100%) rename tests/{desktop => platform}/locale_test.cpp (100%) rename tests/{lsp => platform}/lsp_which_test.cpp (100%) rename tests/{desktop => platform}/notifications_native_test.cpp (100%) rename tests/{desktop => platform}/notifications_test.cpp (100%) rename tests/{desktop => platform}/open_in_explorer_test.cpp (100%) rename tests/{utils => platform}/open_url_test.cpp (100%) rename tests/{utils => platform}/power_inhibitor_test.cpp (100%) rename tests/{desktop => platform}/strings_test.cpp (100%) rename tests/{utils => platform}/terminal_capability_test.cpp (100%) rename tests/{utils => platform}/terminal_theme_detect_test.cpp (100%) rename tests/{utils => platform}/terminal_title_test.cpp (100%) rename tests/{web => }/pty/pty_backend_test.cpp (100%) rename tests/{web => }/pty/pty_session_registry_test.cpp (100%) rename tests/{web => }/pty/winpty_spike_test.cpp (100%) diff --git a/src/utils/clipboard.cpp b/src/platform/clipboard.cpp similarity index 100% rename from src/utils/clipboard.cpp rename to src/platform/clipboard.cpp diff --git a/src/utils/clipboard.hpp b/src/platform/clipboard.hpp similarity index 100% rename from src/utils/clipboard.hpp rename to src/platform/clipboard.hpp diff --git a/src/desktop/locale.cpp b/src/platform/locale.cpp similarity index 100% rename from src/desktop/locale.cpp rename to src/platform/locale.cpp diff --git a/src/desktop/locale.hpp b/src/platform/locale.hpp similarity index 100% rename from src/desktop/locale.hpp rename to src/platform/locale.hpp diff --git a/src/desktop/context_picker.cpp b/src/platform/native_ui/context_picker.cpp similarity index 100% rename from src/desktop/context_picker.cpp rename to src/platform/native_ui/context_picker.cpp diff --git a/src/desktop/context_picker.hpp b/src/platform/native_ui/context_picker.hpp similarity index 100% rename from src/desktop/context_picker.hpp rename to src/platform/native_ui/context_picker.hpp diff --git a/src/desktop/custom_toast.cpp b/src/platform/native_ui/custom_toast.cpp similarity index 100% rename from src/desktop/custom_toast.cpp rename to src/platform/native_ui/custom_toast.cpp diff --git a/src/desktop/custom_toast.hpp b/src/platform/native_ui/custom_toast.hpp similarity index 100% rename from src/desktop/custom_toast.hpp rename to src/platform/native_ui/custom_toast.hpp diff --git a/src/desktop/custom_toast_win.cpp b/src/platform/native_ui/custom_toast_win.cpp similarity index 100% rename from src/desktop/custom_toast_win.cpp rename to src/platform/native_ui/custom_toast_win.cpp diff --git a/src/desktop/folder_picker.hpp b/src/platform/native_ui/folder_picker.hpp similarity index 100% rename from src/desktop/folder_picker.hpp rename to src/platform/native_ui/folder_picker.hpp diff --git a/src/desktop/folder_picker_mac.mm b/src/platform/native_ui/folder_picker_mac.mm similarity index 100% rename from src/desktop/folder_picker_mac.mm rename to src/platform/native_ui/folder_picker_mac.mm diff --git a/src/desktop/folder_picker_win.cpp b/src/platform/native_ui/folder_picker_win.cpp similarity index 100% rename from src/desktop/folder_picker_win.cpp rename to src/platform/native_ui/folder_picker_win.cpp diff --git a/src/desktop/notifications.cpp b/src/platform/native_ui/notifications.cpp similarity index 100% rename from src/desktop/notifications.cpp rename to src/platform/native_ui/notifications.cpp diff --git a/src/desktop/notifications.hpp b/src/platform/native_ui/notifications.hpp similarity index 100% rename from src/desktop/notifications.hpp rename to src/platform/native_ui/notifications.hpp diff --git a/src/desktop/notifications_backend.hpp b/src/platform/native_ui/notifications_backend.hpp similarity index 100% rename from src/desktop/notifications_backend.hpp rename to src/platform/native_ui/notifications_backend.hpp diff --git a/src/desktop/notifications_mac.mm b/src/platform/native_ui/notifications_mac.mm similarity index 100% rename from src/desktop/notifications_mac.mm rename to src/platform/native_ui/notifications_mac.mm diff --git a/src/desktop/notifications_stub.cpp b/src/platform/native_ui/notifications_stub.cpp similarity index 100% rename from src/desktop/notifications_stub.cpp rename to src/platform/native_ui/notifications_stub.cpp diff --git a/src/desktop/notifications_win.cpp b/src/platform/native_ui/notifications_win.cpp similarity index 100% rename from src/desktop/notifications_win.cpp rename to src/platform/native_ui/notifications_win.cpp diff --git a/src/desktop/open_in_explorer.cpp b/src/platform/native_ui/open_in_explorer.cpp similarity index 100% rename from src/desktop/open_in_explorer.cpp rename to src/platform/native_ui/open_in_explorer.cpp diff --git a/src/desktop/open_in_explorer.hpp b/src/platform/native_ui/open_in_explorer.hpp similarity index 100% rename from src/desktop/open_in_explorer.hpp rename to src/platform/native_ui/open_in_explorer.hpp diff --git a/src/desktop/strings.cpp b/src/platform/native_ui/strings.cpp similarity index 100% rename from src/desktop/strings.cpp rename to src/platform/native_ui/strings.cpp diff --git a/src/desktop/strings.hpp b/src/platform/native_ui/strings.hpp similarity index 100% rename from src/desktop/strings.hpp rename to src/platform/native_ui/strings.hpp diff --git a/src/utils/open_url.cpp b/src/platform/open_url.cpp similarity index 100% rename from src/utils/open_url.cpp rename to src/platform/open_url.cpp diff --git a/src/utils/open_url.hpp b/src/platform/open_url.hpp similarity index 100% rename from src/utils/open_url.hpp rename to src/platform/open_url.hpp diff --git a/src/utils/power_inhibitor.cpp b/src/platform/power_inhibitor.cpp similarity index 100% rename from src/utils/power_inhibitor.cpp rename to src/platform/power_inhibitor.cpp diff --git a/src/utils/power_inhibitor.hpp b/src/platform/power_inhibitor.hpp similarity index 100% rename from src/utils/power_inhibitor.hpp rename to src/platform/power_inhibitor.hpp diff --git a/src/daemon/platform.hpp b/src/platform/process/os_process.hpp similarity index 100% rename from src/daemon/platform.hpp rename to src/platform/process/os_process.hpp diff --git a/src/daemon/platform_posix.cpp b/src/platform/process/os_process_posix.cpp similarity index 100% rename from src/daemon/platform_posix.cpp rename to src/platform/process/os_process_posix.cpp diff --git a/src/daemon/platform_windows.cpp b/src/platform/process/os_process_windows.cpp similarity index 100% rename from src/daemon/platform_windows.cpp rename to src/platform/process/os_process_windows.cpp diff --git a/src/lsp/lsp_process.cpp b/src/platform/process/piped_process.cpp similarity index 100% rename from src/lsp/lsp_process.cpp rename to src/platform/process/piped_process.cpp diff --git a/src/lsp/lsp_process.hpp b/src/platform/process/piped_process.hpp similarity index 100% rename from src/lsp/lsp_process.hpp rename to src/platform/process/piped_process.hpp diff --git a/src/hooks/hook_runner.cpp b/src/platform/process/process_runner.cpp similarity index 100% rename from src/hooks/hook_runner.cpp rename to src/platform/process/process_runner.cpp diff --git a/src/hooks/hook_runner.hpp b/src/platform/process/process_runner.hpp similarity index 100% rename from src/hooks/hook_runner.hpp rename to src/platform/process/process_runner.hpp diff --git a/src/lsp/lsp_which.cpp b/src/platform/process/which.cpp similarity index 100% rename from src/lsp/lsp_which.cpp rename to src/platform/process/which.cpp diff --git a/src/lsp/lsp_which.hpp b/src/platform/process/which.hpp similarity index 100% rename from src/lsp/lsp_which.hpp rename to src/platform/process/which.hpp diff --git a/src/upgrade/console.hpp b/src/platform/terminal/console.hpp similarity index 100% rename from src/upgrade/console.hpp rename to src/platform/terminal/console.hpp diff --git a/src/utils/terminal_capability.cpp b/src/platform/terminal/terminal_capability.cpp similarity index 100% rename from src/utils/terminal_capability.cpp rename to src/platform/terminal/terminal_capability.cpp diff --git a/src/utils/terminal_capability.hpp b/src/platform/terminal/terminal_capability.hpp similarity index 100% rename from src/utils/terminal_capability.hpp rename to src/platform/terminal/terminal_capability.hpp diff --git a/src/utils/terminal_input.hpp b/src/platform/terminal/terminal_input.hpp similarity index 100% rename from src/utils/terminal_input.hpp rename to src/platform/terminal/terminal_input.hpp diff --git a/src/utils/terminal_theme_detect.cpp b/src/platform/terminal/terminal_theme_detect.cpp similarity index 100% rename from src/utils/terminal_theme_detect.cpp rename to src/platform/terminal/terminal_theme_detect.cpp diff --git a/src/utils/terminal_theme_detect.hpp b/src/platform/terminal/terminal_theme_detect.hpp similarity index 100% rename from src/utils/terminal_theme_detect.hpp rename to src/platform/terminal/terminal_theme_detect.hpp diff --git a/src/utils/terminal_theme_detect_posix.cpp b/src/platform/terminal/terminal_theme_detect_posix.cpp similarity index 100% rename from src/utils/terminal_theme_detect_posix.cpp rename to src/platform/terminal/terminal_theme_detect_posix.cpp diff --git a/src/utils/terminal_theme_detect_win.cpp b/src/platform/terminal/terminal_theme_detect_win.cpp similarity index 100% rename from src/utils/terminal_theme_detect_win.cpp rename to src/platform/terminal/terminal_theme_detect_win.cpp diff --git a/src/utils/terminal_title.cpp b/src/platform/terminal/terminal_title.cpp similarity index 100% rename from src/utils/terminal_title.cpp rename to src/platform/terminal/terminal_title.cpp diff --git a/src/utils/terminal_title.hpp b/src/platform/terminal/terminal_title.hpp similarity index 100% rename from src/utils/terminal_title.hpp rename to src/platform/terminal/terminal_title.hpp diff --git a/src/web/pty/pty_backend.hpp b/src/pty/pty_backend.hpp similarity index 100% rename from src/web/pty/pty_backend.hpp rename to src/pty/pty_backend.hpp diff --git a/src/web/pty/pty_backend_posix.cpp b/src/pty/pty_backend_posix.cpp similarity index 100% rename from src/web/pty/pty_backend_posix.cpp rename to src/pty/pty_backend_posix.cpp diff --git a/src/web/pty/pty_backend_win.cpp b/src/pty/pty_backend_win.cpp similarity index 100% rename from src/web/pty/pty_backend_win.cpp rename to src/pty/pty_backend_win.cpp diff --git a/src/web/pty/pty_session_registry.cpp b/src/pty/pty_session_registry.cpp similarity index 100% rename from src/web/pty/pty_session_registry.cpp rename to src/pty/pty_session_registry.cpp diff --git a/src/web/pty/pty_session_registry.hpp b/src/pty/pty_session_registry.hpp similarity index 100% rename from src/web/pty/pty_session_registry.hpp rename to src/pty/pty_session_registry.hpp diff --git a/src/web/pty/pty_shell.cpp b/src/pty/pty_shell.cpp similarity index 100% rename from src/web/pty/pty_shell.cpp rename to src/pty/pty_shell.cpp diff --git a/src/web/pty/winpty_agent_embedded.hpp b/src/pty/winpty_agent_embedded.hpp similarity index 100% rename from src/web/pty/winpty_agent_embedded.hpp rename to src/pty/winpty_agent_embedded.hpp diff --git a/src/web/pty/winpty_agent_location.cpp b/src/pty/winpty_agent_location.cpp similarity index 100% rename from src/web/pty/winpty_agent_location.cpp rename to src/pty/winpty_agent_location.cpp diff --git a/src/web/pty/winpty_agent_location.hpp b/src/pty/winpty_agent_location.hpp similarity index 100% rename from src/web/pty/winpty_agent_location.hpp rename to src/pty/winpty_agent_location.hpp diff --git a/tests/utils/clipboard_test.cpp b/tests/platform/clipboard_test.cpp similarity index 100% rename from tests/utils/clipboard_test.cpp rename to tests/platform/clipboard_test.cpp diff --git a/tests/desktop/custom_toast_layout_test.cpp b/tests/platform/custom_toast_layout_test.cpp similarity index 100% rename from tests/desktop/custom_toast_layout_test.cpp rename to tests/platform/custom_toast_layout_test.cpp diff --git a/tests/hooks/hook_runner_test.cpp b/tests/platform/hook_runner_test.cpp similarity index 100% rename from tests/hooks/hook_runner_test.cpp rename to tests/platform/hook_runner_test.cpp diff --git a/tests/desktop/locale_test.cpp b/tests/platform/locale_test.cpp similarity index 100% rename from tests/desktop/locale_test.cpp rename to tests/platform/locale_test.cpp diff --git a/tests/lsp/lsp_which_test.cpp b/tests/platform/lsp_which_test.cpp similarity index 100% rename from tests/lsp/lsp_which_test.cpp rename to tests/platform/lsp_which_test.cpp diff --git a/tests/desktop/notifications_native_test.cpp b/tests/platform/notifications_native_test.cpp similarity index 100% rename from tests/desktop/notifications_native_test.cpp rename to tests/platform/notifications_native_test.cpp diff --git a/tests/desktop/notifications_test.cpp b/tests/platform/notifications_test.cpp similarity index 100% rename from tests/desktop/notifications_test.cpp rename to tests/platform/notifications_test.cpp diff --git a/tests/desktop/open_in_explorer_test.cpp b/tests/platform/open_in_explorer_test.cpp similarity index 100% rename from tests/desktop/open_in_explorer_test.cpp rename to tests/platform/open_in_explorer_test.cpp diff --git a/tests/utils/open_url_test.cpp b/tests/platform/open_url_test.cpp similarity index 100% rename from tests/utils/open_url_test.cpp rename to tests/platform/open_url_test.cpp diff --git a/tests/utils/power_inhibitor_test.cpp b/tests/platform/power_inhibitor_test.cpp similarity index 100% rename from tests/utils/power_inhibitor_test.cpp rename to tests/platform/power_inhibitor_test.cpp diff --git a/tests/desktop/strings_test.cpp b/tests/platform/strings_test.cpp similarity index 100% rename from tests/desktop/strings_test.cpp rename to tests/platform/strings_test.cpp diff --git a/tests/utils/terminal_capability_test.cpp b/tests/platform/terminal_capability_test.cpp similarity index 100% rename from tests/utils/terminal_capability_test.cpp rename to tests/platform/terminal_capability_test.cpp diff --git a/tests/utils/terminal_theme_detect_test.cpp b/tests/platform/terminal_theme_detect_test.cpp similarity index 100% rename from tests/utils/terminal_theme_detect_test.cpp rename to tests/platform/terminal_theme_detect_test.cpp diff --git a/tests/utils/terminal_title_test.cpp b/tests/platform/terminal_title_test.cpp similarity index 100% rename from tests/utils/terminal_title_test.cpp rename to tests/platform/terminal_title_test.cpp diff --git a/tests/web/pty/pty_backend_test.cpp b/tests/pty/pty_backend_test.cpp similarity index 100% rename from tests/web/pty/pty_backend_test.cpp rename to tests/pty/pty_backend_test.cpp diff --git a/tests/web/pty/pty_session_registry_test.cpp b/tests/pty/pty_session_registry_test.cpp similarity index 100% rename from tests/web/pty/pty_session_registry_test.cpp rename to tests/pty/pty_session_registry_test.cpp diff --git a/tests/web/pty/winpty_spike_test.cpp b/tests/pty/winpty_spike_test.cpp similarity index 100% rename from tests/web/pty/winpty_spike_test.cpp rename to tests/pty/winpty_spike_test.cpp From bb94c967934cf3c355a143435bc2b292a917275f Mon Sep 17 00:00:00 2001 From: tmoonlight Date: Sun, 27 Sep 2026 17:22:20 +0800 Subject: [PATCH 2/8] =?UTF-8?q?refactor20260927(layers/P2-03):=20include?= =?UTF-8?q?=20=E6=94=B9=E6=8C=87=20platform/=20=E4=B8=8E=20pty/=20?= =?UTF-8?q?=E6=96=B0=E8=B7=AF=E5=BE=84(normalize=5Fincludes=20=E8=BE=93?= =?UTF-8?q?=E5=87=BA)[mechanical]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit python scripts/refactor/normalize_includes.py --scope src:50 文件 76 行;--scope tests:30 文件 31 行。全部是引号内路径的整体替换(旧模块根形式或同目录裸名 -> platform/... 或 pty/...),其它字节不动。 验证:两个范围 --check 均 exit 0、changed_lines 0;git diff --numstat 每个文件增加 = 删除,-U0 补丁里 +/- 行全部是 #include 行。搬走文件内部指回旧目录的裸名 include(14 行,如 platform/clipboard.cpp 的 base64.hpp)工具无法解析,在下一提交手工改。 --- src/channels/bridge.cpp | 4 ++-- src/channels/bridge.hpp | 2 +- src/channels/runtime.cpp | 2 +- src/channels/setup.cpp | 4 ++-- src/commands/builtin_commands.cpp | 2 +- src/commands/configure.cpp | 2 +- src/commands/configure_catalog.cpp | 2 +- src/commands/desktop_command.cpp | 2 +- src/daemon/cli.cpp | 2 +- src/daemon/runtime_files.cpp | 2 +- src/daemon/worker.cpp | 14 +++++++------- src/desktop/agent_browser_host.cpp | 2 +- src/desktop/agent_browser_host_mac.mm | 2 +- src/desktop/context_items.cpp | 2 +- src/desktop/daemon_pool.cpp | 2 +- src/desktop/desktop_about.cpp | 2 +- src/desktop/linux_desktop.cpp | 2 +- src/desktop/linux_desktop.hpp | 2 +- src/desktop/main.cpp | 16 ++++++++-------- src/desktop/startup_progress.cpp | 2 +- src/desktop/tray_menu_layout.hpp | 2 +- src/desktop/web_host.hpp | 2 +- src/environment/data_dir_migration.cpp | 2 +- src/environment/shell_command_line.cpp | 2 +- src/environment/terminal_resolver.cpp | 2 +- src/environment/terminal_resolver.hpp | 2 +- src/environment/toolchains.cpp | 2 +- src/headless/headless_runner.cpp | 2 +- src/hooks/hook_manager.hpp | 2 +- src/hooks/hook_runtime.hpp | 2 +- src/lsp/lsp_client.hpp | 2 +- src/lsp/lsp_server_registry.hpp | 4 ++-- src/main.cpp | 14 +++++++------- src/remote_control/channel_plugin.hpp | 2 +- src/session/session_auto_title.cpp | 2 +- src/session/session_registry.cpp | 2 +- src/session/session_title_generator.cpp | 4 ++-- src/session/session_writer_lease.hpp | 2 +- src/tool/agent_browser/cdp_client.cpp | 2 +- src/tool/grep_tool.cpp | 2 +- src/tui/channels_setup.cpp | 4 ++-- src/tui/chat_file_link.cpp | 2 +- src/tui/chat_file_link.hpp | 2 +- src/tui/render_mode.hpp | 2 +- src/tui/settings/settings_center.cpp | 2 +- src/upgrade/apply.cpp | 2 +- src/upgrade/upgrade.cpp | 2 +- src/web/remote_web_proxy.cpp | 2 +- src/web/server_impl.hpp | 6 +++--- src/worktree/worktree_manager.cpp | 2 +- tests/channels/setup_test.cpp | 2 +- tests/daemon/runtime_files_test.cpp | 2 +- tests/desktop/daemon_pool_test.cpp | 2 +- .../desktop/helpers/macos_notification_smoke.mm | 2 +- tests/desktop/helpers/upgrade_restart_smoke.cpp | 2 +- tests/lsp/lsp_server_registry_test.cpp | 2 +- tests/platform/clipboard_test.cpp | 2 +- tests/platform/custom_toast_layout_test.cpp | 2 +- tests/platform/hook_runner_test.cpp | 2 +- tests/platform/locale_test.cpp | 2 +- tests/platform/lsp_which_test.cpp | 2 +- tests/platform/notifications_native_test.cpp | 2 +- tests/platform/notifications_test.cpp | 2 +- tests/platform/open_in_explorer_test.cpp | 2 +- tests/platform/open_url_test.cpp | 2 +- tests/platform/power_inhibitor_test.cpp | 2 +- tests/platform/strings_test.cpp | 2 +- tests/platform/terminal_capability_test.cpp | 2 +- tests/platform/terminal_theme_detect_test.cpp | 2 +- tests/platform/terminal_title_test.cpp | 2 +- tests/pty/pty_backend_test.cpp | 2 +- tests/pty/pty_session_registry_test.cpp | 4 ++-- tests/pty/winpty_spike_test.cpp | 2 +- tests/session/session_registry_test.cpp | 2 +- tests/session/session_title_test.cpp | 2 +- tests/session/session_writer_lease_test.cpp | 2 +- tests/skills/default_skill_seeder_test.cpp | 2 +- tests/web/helpers/remote_web_proxy_child.cpp | 2 +- tests/web/remote_web_proxy_test.cpp | 2 +- tests/web/web_server_smoke_test.cpp | 2 +- 80 files changed, 107 insertions(+), 107 deletions(-) diff --git a/src/channels/bridge.cpp b/src/channels/bridge.cpp index bc67e5207..267a830d8 100644 --- a/src/channels/bridge.cpp +++ b/src/channels/bridge.cpp @@ -1,8 +1,8 @@ #include "bridge.hpp" -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "utils/utf8_path.hpp" #include "utils/atomic_file.hpp" -#include "lsp/lsp_which.hpp" +#include "platform/process/which.hpp" #include #include diff --git a/src/channels/bridge.hpp b/src/channels/bridge.hpp index 617a7d30c..2491eb37f 100644 --- a/src/channels/bridge.hpp +++ b/src/channels/bridge.hpp @@ -1,7 +1,7 @@ #pragma once #include "state.hpp" -#include "lsp/lsp_process.hpp" +#include "platform/process/piped_process.hpp" #include #include #include diff --git a/src/channels/runtime.cpp b/src/channels/runtime.cpp index ee272c40a..2ff6723f5 100644 --- a/src/channels/runtime.cpp +++ b/src/channels/runtime.cpp @@ -1,6 +1,6 @@ #include "runtime.hpp" #include "config/config.hpp" -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "remote_control/remote_control_service.hpp" #include "utils/atomic_file.hpp" #include "utils/logger.hpp" diff --git a/src/channels/setup.cpp b/src/channels/setup.cpp index e4412659c..9eff5468d 100644 --- a/src/channels/setup.cpp +++ b/src/channels/setup.cpp @@ -1,7 +1,7 @@ #include "setup.hpp" #include "runtime.hpp" -#include "hooks/hook_runner.hpp" -#include "lsp/lsp_which.hpp" +#include "platform/process/process_runner.hpp" +#include "platform/process/which.hpp" #include "remote_control/rc_session_navigation.hpp" #include "remote_control/remote_control_service.hpp" #include "utils/utf8_path.hpp" diff --git a/src/commands/builtin_commands.cpp b/src/commands/builtin_commands.cpp index 23a8a67b7..aa897573d 100644 --- a/src/commands/builtin_commands.cpp +++ b/src/commands/builtin_commands.cpp @@ -32,7 +32,7 @@ #include "session/session_rewind.hpp" #include "session/thread_goal_store.hpp" #include "utils/logger.hpp" -#include "utils/terminal_title.hpp" +#include "platform/terminal/terminal_title.hpp" #include "utils/utf8_path.hpp" #include "version.hpp" #include diff --git a/src/commands/configure.cpp b/src/commands/configure.cpp index 36289403b..73ec6b262 100644 --- a/src/commands/configure.cpp +++ b/src/commands/configure.cpp @@ -10,7 +10,7 @@ #include "provider/builtin_model_catalog.hpp" #include "utils/logger.hpp" #include "utils/models_dev_catalog.hpp" -#include "utils/terminal_input.hpp" +#include "platform/terminal/terminal_input.hpp" #include #include diff --git a/src/commands/configure_catalog.cpp b/src/commands/configure_catalog.cpp index e72e33a3a..73b605a0f 100644 --- a/src/commands/configure_catalog.cpp +++ b/src/commands/configure_catalog.cpp @@ -3,7 +3,7 @@ #include "configure_picker.hpp" #include "provider/builtin_model_catalog.hpp" #include "utils/encoding.hpp" -#include "utils/terminal_input.hpp" +#include "platform/terminal/terminal_input.hpp" #include #include diff --git a/src/commands/desktop_command.cpp b/src/commands/desktop_command.cpp index a3b991d03..d800e1e11 100644 --- a/src/commands/desktop_command.cpp +++ b/src/commands/desktop_command.cpp @@ -1,7 +1,7 @@ #include "desktop_command.hpp" #include "command_registry.hpp" -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "utils/utf8_path.hpp" #include diff --git a/src/daemon/cli.cpp b/src/daemon/cli.cpp index 92d707e0e..85a4a4255 100644 --- a/src/daemon/cli.cpp +++ b/src/daemon/cli.cpp @@ -1,7 +1,7 @@ #include "environment/bootstrap.hpp" #include "cli.hpp" -#include "platform.hpp" +#include "platform/process/os_process.hpp" #include "runtime_files.hpp" #include "startup_diagnostics.hpp" #include "worker.hpp" diff --git a/src/daemon/runtime_files.cpp b/src/daemon/runtime_files.cpp index 52369ed7e..ffe2d3cfd 100644 --- a/src/daemon/runtime_files.cpp +++ b/src/daemon/runtime_files.cpp @@ -5,7 +5,7 @@ #include "utils/constants.hpp" #include "utils/logger.hpp" #include "utils/utf8_path.hpp" -#include "platform.hpp" +#include "platform/process/os_process.hpp" #include diff --git a/src/daemon/worker.cpp b/src/daemon/worker.cpp index e1f631300..89e359d93 100644 --- a/src/daemon/worker.cpp +++ b/src/daemon/worker.cpp @@ -2,11 +2,11 @@ #include "channels/runtime.hpp" #include "session/session_serializer.hpp" -#include "desktop/folder_picker.hpp" -#include "desktop/context_picker.hpp" +#include "platform/native_ui/folder_picker.hpp" +#include "platform/native_ui/context_picker.hpp" #include "environment/terminal_runtime.hpp" #include "desktop/daemon_protocol.hpp" -#include "desktop/open_in_explorer.hpp" +#include "platform/native_ui/open_in_explorer.hpp" #include "version.hpp" #include "tool/spawn_subagent_tool.hpp" #include "tool/thread_tools.hpp" @@ -17,7 +17,7 @@ #include "guid.hpp" #include "heartbeat.hpp" #include "mcp_runtime.hpp" -#include "platform.hpp" +#include "platform/process/os_process.hpp" #include "runtime_files.hpp" #include "provider/cwd_model_override.hpp" #include "provider/copilot_provider.hpp" @@ -28,7 +28,7 @@ #include "hooks/hook_config.hpp" #include "hooks/hook_manager.hpp" #include "hooks/hook_payload.hpp" -#include "hooks/hook_runner.hpp" +#include "platform/process/process_runner.hpp" #include "loop/loop_scheduler.hpp" #include "loop/loop_store.hpp" #include "session/local_session_client.hpp" @@ -65,11 +65,11 @@ #include "utils/logger.hpp" #include "utils/joining_thread.hpp" #include "utils/paths.hpp" -#include "utils/power_inhibitor.hpp" +#include "platform/power_inhibitor.hpp" #include "utils/token.hpp" #include "utils/utf8_path.hpp" #include "web/auth.hpp" -#include "web/pty/pty_session_registry.hpp" +#include "pty/pty_session_registry.hpp" #include "web/remote_web.hpp" #include "web/remote_web_proxy.hpp" #include "web/server.hpp" diff --git a/src/desktop/agent_browser_host.cpp b/src/desktop/agent_browser_host.cpp index c0246a597..9b1bad5eb 100644 --- a/src/desktop/agent_browser_host.cpp +++ b/src/desktop/agent_browser_host.cpp @@ -4,7 +4,7 @@ #include "agent_browser_runtime.hpp" #include "window_chrome.hpp" -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "utils/encoding.hpp" #include "utils/logger.hpp" #include "utils/token.hpp" diff --git a/src/desktop/agent_browser_host_mac.mm b/src/desktop/agent_browser_host_mac.mm index ad5c23f43..5b5fc750e 100644 --- a/src/desktop/agent_browser_host_mac.mm +++ b/src/desktop/agent_browser_host_mac.mm @@ -5,7 +5,7 @@ #include "agent_browser_navigation_state.hpp" #include "agent_browser_runtime.hpp" -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "utils/atomic_file.hpp" #include "utils/base64.hpp" #include "utils/logger.hpp" diff --git a/src/desktop/context_items.cpp b/src/desktop/context_items.cpp index f8e5bcccb..92b267c89 100644 --- a/src/desktop/context_items.cpp +++ b/src/desktop/context_items.cpp @@ -2,7 +2,7 @@ #include "utils/utf8_path.hpp" #include "utils/base64.hpp" -#include "utils/clipboard.hpp" +#include "platform/clipboard.hpp" #include "utils/uuid.hpp" #include diff --git a/src/desktop/daemon_pool.cpp b/src/desktop/daemon_pool.cpp index 0c360d5c4..f0bbd6a48 100644 --- a/src/desktop/daemon_pool.cpp +++ b/src/desktop/daemon_pool.cpp @@ -1,7 +1,7 @@ #include "daemon_pool.hpp" #include "daemon/guid.hpp" -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "daemon/runtime_files.hpp" #include "daemon_protocol.hpp" #include "utils/constants.hpp" diff --git a/src/desktop/desktop_about.cpp b/src/desktop/desktop_about.cpp index 1efdc9182..d0257250b 100644 --- a/src/desktop/desktop_about.cpp +++ b/src/desktop/desktop_about.cpp @@ -1,5 +1,5 @@ #include "desktop_about.hpp" -#include "strings.hpp" +#include "platform/native_ui/strings.hpp" #include "utils/encoding.hpp" diff --git a/src/desktop/linux_desktop.cpp b/src/desktop/linux_desktop.cpp index 8fde846e9..c658db3f9 100644 --- a/src/desktop/linux_desktop.cpp +++ b/src/desktop/linux_desktop.cpp @@ -1,6 +1,6 @@ #include "linux_desktop.hpp" -#include "strings.hpp" +#include "platform/native_ui/strings.hpp" #include diff --git a/src/desktop/linux_desktop.hpp b/src/desktop/linux_desktop.hpp index b46106163..091e30841 100644 --- a/src/desktop/linux_desktop.hpp +++ b/src/desktop/linux_desktop.hpp @@ -1,6 +1,6 @@ #pragma once -#include "folder_picker.hpp" +#include "platform/native_ui/folder_picker.hpp" #include "window_size.hpp" namespace acecode::desktop { diff --git a/src/desktop/main.cpp b/src/desktop/main.cpp index 6185c94b8..bf8ed019b 100644 --- a/src/desktop/main.cpp +++ b/src/desktop/main.cpp @@ -17,23 +17,23 @@ #include "agent_browser_host.hpp" #include "agent_browser_runtime.hpp" #include "context_items.hpp" -#include "context_picker.hpp" +#include "platform/native_ui/context_picker.hpp" #include "desktop_about.hpp" #include "desktop_restart.hpp" #include "dpi_win.hpp" #include "edge_app_launcher.hpp" #include "external_url.hpp" -#include "folder_picker.hpp" -#include "locale.hpp" -#include "notifications.hpp" +#include "platform/native_ui/folder_picker.hpp" +#include "platform/locale.hpp" +#include "platform/native_ui/notifications.hpp" #include "open_request.hpp" -#include "open_in_explorer.hpp" +#include "platform/native_ui/open_in_explorer.hpp" #include "pick_active.hpp" #include "single_instance.hpp" #include "instance_startup.hpp" #include "splash_screen.hpp" #include "startup_progress.hpp" -#include "strings.hpp" +#include "platform/native_ui/strings.hpp" #include "taskbar_badge.hpp" #include "tray_menu_bridge.hpp" #include "tray_icon_win.hpp" @@ -47,9 +47,9 @@ #endif #include "config/config.hpp" -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "daemon/runtime_files.hpp" -#include "utils/clipboard.hpp" +#include "platform/clipboard.hpp" #include "utils/base64.hpp" #include "utils/cwd_hash.hpp" #include "utils/encoding.hpp" diff --git a/src/desktop/startup_progress.cpp b/src/desktop/startup_progress.cpp index 4b12ccbc6..9681cf4af 100644 --- a/src/desktop/startup_progress.cpp +++ b/src/desktop/startup_progress.cpp @@ -1,6 +1,6 @@ #include "startup_progress.hpp" -#include "locale.hpp" +#include "platform/locale.hpp" #include diff --git a/src/desktop/tray_menu_layout.hpp b/src/desktop/tray_menu_layout.hpp index 41319a611..128b44984 100644 --- a/src/desktop/tray_menu_layout.hpp +++ b/src/desktop/tray_menu_layout.hpp @@ -10,7 +10,7 @@ // 设计:openspec/changes/enhance-desktop-tray-menu/design.md 决策 3 + 6。 #include "tray_icon_win.hpp" -#include "strings.hpp" +#include "platform/native_ui/strings.hpp" #include #include diff --git a/src/desktop/web_host.hpp b/src/desktop/web_host.hpp index 82d9cf5eb..2bc3baf37 100644 --- a/src/desktop/web_host.hpp +++ b/src/desktop/web_host.hpp @@ -15,7 +15,7 @@ #include #include #include -#include "utils/clipboard.hpp" +#include "platform/clipboard.hpp" namespace acecode::desktop { diff --git a/src/environment/data_dir_migration.cpp b/src/environment/data_dir_migration.cpp index c35a2ec19..c33fb2795 100644 --- a/src/environment/data_dir_migration.cpp +++ b/src/environment/data_dir_migration.cpp @@ -5,7 +5,7 @@ #include "utils/utf8_path.hpp" #include "utils/uuid.hpp" #include "utils/state_file.hpp" -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include #include diff --git a/src/environment/shell_command_line.cpp b/src/environment/shell_command_line.cpp index df13dff67..45cac2e59 100644 --- a/src/environment/shell_command_line.cpp +++ b/src/environment/shell_command_line.cpp @@ -1,7 +1,7 @@ #include "shell_command_line.hpp" #include "utils/base64.hpp" -#include "web/pty/pty_backend.hpp" +#include "pty/pty_backend.hpp" #include diff --git a/src/environment/terminal_resolver.cpp b/src/environment/terminal_resolver.cpp index cdcc1ce76..42e8fd969 100644 --- a/src/environment/terminal_resolver.cpp +++ b/src/environment/terminal_resolver.cpp @@ -1,7 +1,7 @@ #include "terminal_resolver.hpp" #include "hooks/hook_config.hpp" -#include "hooks/hook_runner.hpp" +#include "platform/process/process_runner.hpp" #include "utils/logger.hpp" #include diff --git a/src/environment/terminal_resolver.hpp b/src/environment/terminal_resolver.hpp index 345edbfa7..542c45632 100644 --- a/src/environment/terminal_resolver.hpp +++ b/src/environment/terminal_resolver.hpp @@ -14,7 +14,7 @@ #include "shell_command_line.hpp" #include "config/config.hpp" -#include "web/pty/pty_backend.hpp" +#include "pty/pty_backend.hpp" #include #include diff --git a/src/environment/toolchains.cpp b/src/environment/toolchains.cpp index 6e55936ad..b186d8029 100644 --- a/src/environment/toolchains.cpp +++ b/src/environment/toolchains.cpp @@ -1,6 +1,6 @@ #include "toolchains.hpp" -#include "lsp/lsp_which.hpp" +#include "platform/process/which.hpp" #include "utils/encoding.hpp" #include "utils/logger.hpp" #include "utils/utf8_path.hpp" diff --git a/src/headless/headless_runner.cpp b/src/headless/headless_runner.cpp index 8610318d2..fe034f2bf 100644 --- a/src/headless/headless_runner.cpp +++ b/src/headless/headless_runner.cpp @@ -36,7 +36,7 @@ #include "tool/web_search/runtime.hpp" #include "utils/logger.hpp" #include "utils/paths.hpp" -#include "utils/power_inhibitor.hpp" +#include "platform/power_inhibitor.hpp" #include "utils/utf8_path.hpp" #include "web/handlers/skill_command_expander.hpp" diff --git a/src/hooks/hook_manager.hpp b/src/hooks/hook_manager.hpp index e9a5ff6ae..052973c01 100644 --- a/src/hooks/hook_manager.hpp +++ b/src/hooks/hook_manager.hpp @@ -3,7 +3,7 @@ #include "hook_config.hpp" #include "hook_registry.hpp" #include "hook_runtime.hpp" -#include "hook_runner.hpp" +#include "platform/process/process_runner.hpp" #include #include diff --git a/src/hooks/hook_runtime.hpp b/src/hooks/hook_runtime.hpp index 78835d29f..b6b191b4e 100644 --- a/src/hooks/hook_runtime.hpp +++ b/src/hooks/hook_runtime.hpp @@ -1,7 +1,7 @@ #pragma once #include "hook_registry.hpp" -#include "hook_runner.hpp" +#include "platform/process/process_runner.hpp" #include #include diff --git a/src/lsp/lsp_client.hpp b/src/lsp/lsp_client.hpp index a2684bc06..786c1ff05 100644 --- a/src/lsp/lsp_client.hpp +++ b/src/lsp/lsp_client.hpp @@ -6,7 +6,7 @@ // condvar 等应答;server→client 请求在 reader 线程内同步应答(全部是 // 轻量纯计算)。所有可变状态由 state_mu_ 保护;stdin 写由 write_mu_ 串行。 -#include "lsp_process.hpp" +#include "platform/process/piped_process.hpp" #include #include diff --git a/src/lsp/lsp_server_registry.hpp b/src/lsp/lsp_server_registry.hpp index 54ada975e..dd13236b0 100644 --- a/src/lsp/lsp_server_registry.hpp +++ b/src/lsp/lsp_server_registry.hpp @@ -7,8 +7,8 @@ // 对应条目对齐(v1 收录 clangd / typescript-language-server / pyright / // gopls / rust-analyzer)。 -#include "lsp_process.hpp" -#include "lsp_which.hpp" +#include "platform/process/piped_process.hpp" +#include "platform/process/which.hpp" #include "config/config.hpp" #include diff --git a/src/main.cpp b/src/main.cpp index 54883dac7..0773081b0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -50,7 +50,7 @@ #include "headless/headless_runner.hpp" #include "channels/command.hpp" #include "utils/encoding.hpp" -#include "utils/power_inhibitor.hpp" +#include "platform/power_inhibitor.hpp" #include "network/proxy_resolver.hpp" #include "remote_control/remote_control_service.hpp" #include "provider/provider_factory.hpp" @@ -120,7 +120,7 @@ #include "commands/builtin_commands.hpp" #include "commands/compact.hpp" #include "commands/resume_state_sync.hpp" -#include "desktop/notifications.hpp" +#include "platform/native_ui/notifications.hpp" #include "utils/token_tracker.hpp" #include "markdown/markdown_formatter.hpp" #include "session/session_manager.hpp" @@ -145,8 +145,8 @@ #include "tui/ask_question_view.hpp" #include "tui/picker_scroll.hpp" #include "tui/render_mode_factory.hpp" -#include "utils/terminal_capability.hpp" -#include "utils/open_url.hpp" +#include "platform/terminal/terminal_capability.hpp" +#include "platform/open_url.hpp" #include "utils/state_file.hpp" #include "tui/slash_dropdown.hpp" #include "tui/path_reference_dropdown.hpp" @@ -169,7 +169,7 @@ #include "tui/settings/settings_center.hpp" #include "tui/tui_helpers.hpp" #include "tui/vertical_scroll.hpp" -#include "utils/terminal_theme_detect.hpp" +#include "platform/terminal/terminal_theme_detect.hpp" #include "tui/subagent_host.hpp" #include "tui/terminal_key_event.hpp" #include "tool/spawn_subagent_tool.hpp" @@ -178,9 +178,9 @@ #include "tui/message_render_cache.hpp" #include "tui/ctrl_c_exit.hpp" #include "utils/base64.hpp" -#include "utils/clipboard.hpp" +#include "platform/clipboard.hpp" #include "utils/drag_scroll.hpp" -#include "utils/terminal_title.hpp" +#include "platform/terminal/terminal_title.hpp" #include "utils/text_input_ops.hpp" #include "session/attachment_store.hpp" #include "session/session_storage.hpp" diff --git a/src/remote_control/channel_plugin.hpp b/src/remote_control/channel_plugin.hpp index acf298519..8ee294ac9 100644 --- a/src/remote_control/channel_plugin.hpp +++ b/src/remote_control/channel_plugin.hpp @@ -1,7 +1,7 @@ #pragma once #include "hooks/hook_config.hpp" -#include "hooks/hook_runner.hpp" +#include "platform/process/process_runner.hpp" #include #include diff --git a/src/session/session_auto_title.cpp b/src/session/session_auto_title.cpp index cc8341ed7..d17074e9b 100644 --- a/src/session/session_auto_title.cpp +++ b/src/session/session_auto_title.cpp @@ -1,7 +1,7 @@ #include "session_auto_title.hpp" #include "session_title_generator.hpp" -#include "desktop/locale.hpp" +#include "platform/locale.hpp" #include "provider/copilot_provider.hpp" #include "provider/cwd_model_override.hpp" #include "provider/model_resolver.hpp" diff --git a/src/session/session_registry.cpp b/src/session/session_registry.cpp index a13ca24e9..297979654 100644 --- a/src/session/session_registry.cpp +++ b/src/session/session_registry.cpp @@ -27,7 +27,7 @@ #include "worktree/worktree_manager.hpp" #include "utils/logger.hpp" #include "utils/cwd_hash.hpp" -#include "utils/power_inhibitor.hpp" +#include "platform/power_inhibitor.hpp" #include "utils/utf8_path.hpp" #include diff --git a/src/session/session_title_generator.cpp b/src/session/session_title_generator.cpp index 21d3c62eb..c3529b797 100644 --- a/src/session/session_title_generator.cpp +++ b/src/session/session_title_generator.cpp @@ -1,8 +1,8 @@ #include "session_title_generator.hpp" -#include "desktop/locale.hpp" +#include "platform/locale.hpp" #include "utils/encoding.hpp" -#include "utils/terminal_title.hpp" +#include "platform/terminal/terminal_title.hpp" #include #include diff --git a/src/session/session_writer_lease.hpp b/src/session/session_writer_lease.hpp index 9419c32f8..629c44e44 100644 --- a/src/session/session_writer_lease.hpp +++ b/src/session/session_writer_lease.hpp @@ -1,6 +1,6 @@ #pragma once -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include #include diff --git a/src/tool/agent_browser/cdp_client.cpp b/src/tool/agent_browser/cdp_client.cpp index 1d119d8c6..17ba68d06 100644 --- a/src/tool/agent_browser/cdp_client.cpp +++ b/src/tool/agent_browser/cdp_client.cpp @@ -1,6 +1,6 @@ #include "cdp_client.hpp" -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "desktop/agent_browser_runtime.hpp" #include "utils/encoding.hpp" diff --git a/src/tool/grep_tool.cpp b/src/tool/grep_tool.cpp index baf09f444..cb711046a 100644 --- a/src/tool/grep_tool.cpp +++ b/src/tool/grep_tool.cpp @@ -1,6 +1,6 @@ #include "grep_tool.hpp" -#include "hooks/hook_runner.hpp" +#include "platform/process/process_runner.hpp" #include "worktree/worktree_manager.hpp" #include "utils/encoding.hpp" #include "utils/utf8_path.hpp" diff --git a/src/tui/channels_setup.cpp b/src/tui/channels_setup.cpp index 1d68d0b9e..a8e9f3b65 100644 --- a/src/tui/channels_setup.cpp +++ b/src/tui/channels_setup.cpp @@ -2,8 +2,8 @@ #include "theme_palette.hpp" #include "terminal_key_event.hpp" #include "config/config.hpp" -#include "desktop/locale.hpp" -#include "utils/open_url.hpp" +#include "platform/locale.hpp" +#include "platform/open_url.hpp" #include #include #include diff --git a/src/tui/chat_file_link.cpp b/src/tui/chat_file_link.cpp index 23c03925f..2537c7382 100644 --- a/src/tui/chat_file_link.cpp +++ b/src/tui/chat_file_link.cpp @@ -1,6 +1,6 @@ #include "chat_file_link.hpp" -#include "utils/open_url.hpp" +#include "platform/open_url.hpp" #include "utils/utf8_path.hpp" #include diff --git a/src/tui/chat_file_link.hpp b/src/tui/chat_file_link.hpp index 533475ff5..165f99ef9 100644 --- a/src/tui/chat_file_link.hpp +++ b/src/tui/chat_file_link.hpp @@ -1,6 +1,6 @@ #pragma once -#include "desktop/open_in_explorer.hpp" +#include "platform/native_ui/open_in_explorer.hpp" #include #include diff --git a/src/tui/render_mode.hpp b/src/tui/render_mode.hpp index b63b62ec9..5fb96470d 100644 --- a/src/tui/render_mode.hpp +++ b/src/tui/render_mode.hpp @@ -16,7 +16,7 @@ // alt_screen_mode == "auto" → AltScreen(默认一开始撑满全屏) #include "config/config.hpp" -#include "utils/terminal_capability.hpp" +#include "platform/terminal/terminal_capability.hpp" namespace acecode::tui { diff --git a/src/tui/settings/settings_center.cpp b/src/tui/settings/settings_center.cpp index 1768ad98f..88cf9f14a 100644 --- a/src/tui/settings/settings_center.cpp +++ b/src/tui/settings/settings_center.cpp @@ -14,7 +14,7 @@ #include "provider/auth/github_auth.hpp" #include "session/session_storage.hpp" #include "session/session_usage_ledger.hpp" -#include "utils/clipboard.hpp" +#include "platform/clipboard.hpp" #include "utils/utf8_path.hpp" #include "tui/theme_palette.hpp" #include "tui/terminal_key_event.hpp" diff --git a/src/upgrade/apply.cpp b/src/upgrade/apply.cpp index fb96a0851..54d35734b 100644 --- a/src/upgrade/apply.cpp +++ b/src/upgrade/apply.cpp @@ -1,7 +1,7 @@ #include "apply.hpp" #include "executable_version.hpp" -#include "console.hpp" +#include "platform/terminal/console.hpp" #include "diagnostics.hpp" #include "package.hpp" #include "config/config.hpp" diff --git a/src/upgrade/upgrade.cpp b/src/upgrade/upgrade.cpp index 9f46d96a0..b9b9c3cc6 100644 --- a/src/upgrade/upgrade.cpp +++ b/src/upgrade/upgrade.cpp @@ -2,7 +2,7 @@ #include "apply.hpp" #include "check.hpp" -#include "console.hpp" +#include "platform/terminal/console.hpp" #include "diagnostics.hpp" #include "executable_version.hpp" #include "http.hpp" diff --git a/src/web/remote_web_proxy.cpp b/src/web/remote_web_proxy.cpp index 5cb4cbb3c..86875c88c 100644 --- a/src/web/remote_web_proxy.cpp +++ b/src/web/remote_web_proxy.cpp @@ -1,6 +1,6 @@ #include "remote_web_proxy.hpp" -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "utils/atomic_file.hpp" #include "utils/encoding.hpp" #include "utils/utf8_path.hpp" diff --git a/src/web/server_impl.hpp b/src/web/server_impl.hpp index aa7d46f45..f0fab513a 100644 --- a/src/web/server_impl.hpp +++ b/src/web/server_impl.hpp @@ -37,7 +37,7 @@ #include "session/todo_state.hpp" #include "session/session_usage_ledger.hpp" #include "session/session_writer_lease.hpp" -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "skills/skill_registry.hpp" #include "experts/expert_registry.hpp" #include "skills/skill_metadata.hpp" @@ -48,7 +48,7 @@ #include "utils/logger.hpp" #include "utils/base64.hpp" #include "utils/cwd_hash.hpp" -#include "utils/terminal_title.hpp" +#include "platform/terminal/terminal_title.hpp" #include "web/handlers/files_handler.hpp" #include "web/handlers/fork_handler.hpp" #include "web/handlers/history_handler.hpp" @@ -65,7 +65,7 @@ #include "web/handlers/skills_handler.hpp" #include "skills/skill_init.hpp" #include "message_payload.hpp" -#include "web/pty/pty_session_registry.hpp" +#include "pty/pty_session_registry.hpp" #include "version.hpp" // Crow 头一定在 ASIO_STANDALONE PUBLIC 定义之后才 include。CMakeLists.txt 已 diff --git a/src/worktree/worktree_manager.cpp b/src/worktree/worktree_manager.cpp index 4f34e8747..52bed369e 100644 --- a/src/worktree/worktree_manager.cpp +++ b/src/worktree/worktree_manager.cpp @@ -1,7 +1,7 @@ #include "worktree_manager.hpp" #include "hooks/hook_config.hpp" -#include "hooks/hook_runner.hpp" +#include "platform/process/process_runner.hpp" #include "utils/logger.hpp" #include "utils/utf8_path.hpp" diff --git a/tests/channels/setup_test.cpp b/tests/channels/setup_test.cpp index 416acdb0e..3d9d8ce83 100644 --- a/tests/channels/setup_test.cpp +++ b/tests/channels/setup_test.cpp @@ -1,7 +1,7 @@ #include "channels/setup.hpp" #include "channels/bridge.hpp" #include "channels/runtime.hpp" -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "test_support/channels/test_support.hpp" #include #include diff --git a/tests/daemon/runtime_files_test.cpp b/tests/daemon/runtime_files_test.cpp index 4ae9f5777..dba8c4bf5 100644 --- a/tests/daemon/runtime_files_test.cpp +++ b/tests/daemon/runtime_files_test.cpp @@ -1,6 +1,6 @@ #include -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "daemon/runtime_files.hpp" #include diff --git a/tests/desktop/daemon_pool_test.cpp b/tests/desktop/daemon_pool_test.cpp index de7a67e71..f623665c9 100644 --- a/tests/desktop/daemon_pool_test.cpp +++ b/tests/desktop/daemon_pool_test.cpp @@ -5,7 +5,7 @@ #include -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "daemon/runtime_files.hpp" #include "desktop/daemon_pool.hpp" #include "desktop/daemon_supervisor.hpp" diff --git a/tests/desktop/helpers/macos_notification_smoke.mm b/tests/desktop/helpers/macos_notification_smoke.mm index b41244646..718be3a27 100644 --- a/tests/desktop/helpers/macos_notification_smoke.mm +++ b/tests/desktop/helpers/macos_notification_smoke.mm @@ -1,6 +1,6 @@ #import -#include "desktop/notifications.hpp" +#include "platform/native_ui/notifications.hpp" #include #include diff --git a/tests/desktop/helpers/upgrade_restart_smoke.cpp b/tests/desktop/helpers/upgrade_restart_smoke.cpp index 933cca51c..28e6e801a 100644 --- a/tests/desktop/helpers/upgrade_restart_smoke.cpp +++ b/tests/desktop/helpers/upgrade_restart_smoke.cpp @@ -1,6 +1,6 @@ // Opt-in runtime regression with an old packaged daemon and the new daemon. // The caller supplies an isolated USERPROFILE/HOME and temporary run directory. -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "daemon/runtime_files.hpp" #include "desktop/daemon_pool.hpp" #include "desktop/daemon_protocol.hpp" diff --git a/tests/lsp/lsp_server_registry_test.cpp b/tests/lsp/lsp_server_registry_test.cpp index 211572821..4a4ead97f 100644 --- a/tests/lsp/lsp_server_registry_test.cpp +++ b/tests/lsp/lsp_server_registry_test.cpp @@ -12,7 +12,7 @@ #include -#include "lsp/lsp_process.hpp" +#include "platform/process/piped_process.hpp" #include "lsp/lsp_server_registry.hpp" #include diff --git a/tests/platform/clipboard_test.cpp b/tests/platform/clipboard_test.cpp index 9934870d7..489ca93a3 100644 --- a/tests/platform/clipboard_test.cpp +++ b/tests/platform/clipboard_test.cpp @@ -1,6 +1,6 @@ #include -#include "utils/clipboard.hpp" +#include "platform/clipboard.hpp" #include diff --git a/tests/platform/custom_toast_layout_test.cpp b/tests/platform/custom_toast_layout_test.cpp index 01c1870ec..09e69e5b7 100644 --- a/tests/platform/custom_toast_layout_test.cpp +++ b/tests/platform/custom_toast_layout_test.cpp @@ -5,7 +5,7 @@ #include -#include "desktop/custom_toast.hpp" +#include "platform/native_ui/custom_toast.hpp" #include diff --git a/tests/platform/hook_runner_test.cpp b/tests/platform/hook_runner_test.cpp index 4ac440215..e6cf6702c 100644 --- a/tests/platform/hook_runner_test.cpp +++ b/tests/platform/hook_runner_test.cpp @@ -1,7 +1,7 @@ #include #include "hooks/hook_manager.hpp" -#include "hooks/hook_runner.hpp" +#include "platform/process/process_runner.hpp" #include #include diff --git a/tests/platform/locale_test.cpp b/tests/platform/locale_test.cpp index 267f926df..b4dc9583e 100644 --- a/tests/platform/locale_test.cpp +++ b/tests/platform/locale_test.cpp @@ -1,4 +1,4 @@ -#include "desktop/locale.hpp" +#include "platform/locale.hpp" #include diff --git a/tests/platform/lsp_which_test.cpp b/tests/platform/lsp_which_test.cpp index c142c4da2..7e89c9bb1 100644 --- a/tests/platform/lsp_which_test.cpp +++ b/tests/platform/lsp_which_test.cpp @@ -14,7 +14,7 @@ #include -#include "lsp/lsp_which.hpp" +#include "platform/process/which.hpp" #include #include diff --git a/tests/platform/notifications_native_test.cpp b/tests/platform/notifications_native_test.cpp index c57aa424d..6fa22fffe 100644 --- a/tests/platform/notifications_native_test.cpp +++ b/tests/platform/notifications_native_test.cpp @@ -1,4 +1,4 @@ -#include "desktop/notifications.hpp" +#include "platform/native_ui/notifications.hpp" #include #include diff --git a/tests/platform/notifications_test.cpp b/tests/platform/notifications_test.cpp index e8a657b09..531b61a49 100644 --- a/tests/platform/notifications_test.cpp +++ b/tests/platform/notifications_test.cpp @@ -7,7 +7,7 @@ #include -#include "desktop/notifications.hpp" +#include "platform/native_ui/notifications.hpp" using namespace acecode::desktop; diff --git a/tests/platform/open_in_explorer_test.cpp b/tests/platform/open_in_explorer_test.cpp index c8249b667..bbfe15aee 100644 --- a/tests/platform/open_in_explorer_test.cpp +++ b/tests/platform/open_in_explorer_test.cpp @@ -1,6 +1,6 @@ #include -#include "desktop/open_in_explorer.hpp" +#include "platform/native_ui/open_in_explorer.hpp" #include #include diff --git a/tests/platform/open_url_test.cpp b/tests/platform/open_url_test.cpp index 0bed59e7a..0ec210aa9 100644 --- a/tests/platform/open_url_test.cpp +++ b/tests/platform/open_url_test.cpp @@ -7,7 +7,7 @@ #include -#include "utils/open_url.hpp" +#include "platform/open_url.hpp" #include diff --git a/tests/platform/power_inhibitor_test.cpp b/tests/platform/power_inhibitor_test.cpp index 5296beac1..f94f9bcb2 100644 --- a/tests/platform/power_inhibitor_test.cpp +++ b/tests/platform/power_inhibitor_test.cpp @@ -1,4 +1,4 @@ -#include "utils/power_inhibitor.hpp" +#include "platform/power_inhibitor.hpp" #include diff --git a/tests/platform/strings_test.cpp b/tests/platform/strings_test.cpp index 68132058e..cb9b8140f 100644 --- a/tests/platform/strings_test.cpp +++ b/tests/platform/strings_test.cpp @@ -1,4 +1,4 @@ -#include "desktop/strings.hpp" +#include "platform/native_ui/strings.hpp" #include diff --git a/tests/platform/terminal_capability_test.cpp b/tests/platform/terminal_capability_test.cpp index 8ee054e93..ac636d696 100644 --- a/tests/platform/terminal_capability_test.cpp +++ b/tests/platform/terminal_capability_test.cpp @@ -13,7 +13,7 @@ #include -#include "utils/terminal_capability.hpp" +#include "platform/terminal/terminal_capability.hpp" #include #include diff --git a/tests/platform/terminal_theme_detect_test.cpp b/tests/platform/terminal_theme_detect_test.cpp index b0522977c..d8ff9c9ab 100644 --- a/tests/platform/terminal_theme_detect_test.cpp +++ b/tests/platform/terminal_theme_detect_test.cpp @@ -3,7 +3,7 @@ #include -#include "utils/terminal_theme_detect.hpp" +#include "platform/terminal/terminal_theme_detect.hpp" #include #include diff --git a/tests/platform/terminal_title_test.cpp b/tests/platform/terminal_title_test.cpp index 99ef518dd..2b14477d1 100644 --- a/tests/platform/terminal_title_test.cpp +++ b/tests/platform/terminal_title_test.cpp @@ -7,7 +7,7 @@ #include -#include "utils/terminal_title.hpp" +#include "platform/terminal/terminal_title.hpp" #include "utils/encoding.hpp" #include diff --git a/tests/pty/pty_backend_test.cpp b/tests/pty/pty_backend_test.cpp index aacc151a6..54028618f 100644 --- a/tests/pty/pty_backend_test.cpp +++ b/tests/pty/pty_backend_test.cpp @@ -9,7 +9,7 @@ #include -#include "web/pty/pty_backend.hpp" +#include "pty/pty_backend.hpp" #include "utils/encoding.hpp" #include diff --git a/tests/pty/pty_session_registry_test.cpp b/tests/pty/pty_session_registry_test.cpp index af16e54b7..b88f3afcd 100644 --- a/tests/pty/pty_session_registry_test.cpp +++ b/tests/pty/pty_session_registry_test.cpp @@ -9,8 +9,8 @@ #include -#include "web/pty/pty_backend.hpp" -#include "web/pty/pty_session_registry.hpp" +#include "pty/pty_backend.hpp" +#include "pty/pty_session_registry.hpp" #include diff --git a/tests/pty/winpty_spike_test.cpp b/tests/pty/winpty_spike_test.cpp index 147903f2a..cb7b1cd7c 100644 --- a/tests/pty/winpty_spike_test.cpp +++ b/tests/pty/winpty_spike_test.cpp @@ -22,7 +22,7 @@ #include #include -#include "web/pty/winpty_agent_location.hpp" +#include "pty/winpty_agent_location.hpp" namespace { diff --git a/tests/session/session_registry_test.cpp b/tests/session/session_registry_test.cpp index 5744e8ec9..80d59b2af 100644 --- a/tests/session/session_registry_test.cpp +++ b/tests/session/session_registry_test.cpp @@ -28,7 +28,7 @@ #include "tool/goal_tool.hpp" #include "tool/tool_executor.hpp" #include "utils/cwd_hash.hpp" -#include "utils/power_inhibitor.hpp" +#include "platform/power_inhibitor.hpp" #include #include diff --git a/tests/session/session_title_test.cpp b/tests/session/session_title_test.cpp index a4b748035..16236aaab 100644 --- a/tests/session/session_title_test.cpp +++ b/tests/session/session_title_test.cpp @@ -1,6 +1,6 @@ #include -#include "desktop/locale.hpp" +#include "platform/locale.hpp" #include "session/session_manager.hpp" #include "session/session_auto_title.hpp" #include "session/session_storage.hpp" diff --git a/tests/session/session_writer_lease_test.cpp b/tests/session/session_writer_lease_test.cpp index 4b5ec5d1e..dfbee9d48 100644 --- a/tests/session/session_writer_lease_test.cpp +++ b/tests/session/session_writer_lease_test.cpp @@ -1,6 +1,6 @@ #include -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "session/session_writer_lease.hpp" #include diff --git a/tests/skills/default_skill_seeder_test.cpp b/tests/skills/default_skill_seeder_test.cpp index a3c4047f0..3a26f8ff2 100644 --- a/tests/skills/default_skill_seeder_test.cpp +++ b/tests/skills/default_skill_seeder_test.cpp @@ -3,7 +3,7 @@ #include "test_support/repo_root.hpp" #include "experts/expert_registry.hpp" #include "hooks/hook_registry.hpp" -#include "hooks/hook_runner.hpp" +#include "platform/process/process_runner.hpp" #include "utils/sha256.hpp" #include diff --git a/tests/web/helpers/remote_web_proxy_child.cpp b/tests/web/helpers/remote_web_proxy_child.cpp index 46585db84..5a0907d14 100644 --- a/tests/web/helpers/remote_web_proxy_child.cpp +++ b/tests/web/helpers/remote_web_proxy_child.cpp @@ -1,4 +1,4 @@ -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "web/remote_web_proxy.hpp" #include diff --git a/tests/web/remote_web_proxy_test.cpp b/tests/web/remote_web_proxy_test.cpp index 87e6187d9..fa71d861b 100644 --- a/tests/web/remote_web_proxy_test.cpp +++ b/tests/web/remote_web_proxy_test.cpp @@ -1,4 +1,4 @@ -#include "daemon/platform.hpp" +#include "platform/process/os_process.hpp" #include "utils/encoding.hpp" #include "web/remote_web_proxy.hpp" diff --git a/tests/web/web_server_smoke_test.cpp b/tests/web/web_server_smoke_test.cpp index f6d4245ee..a292bb5e5 100644 --- a/tests/web/web_server_smoke_test.cpp +++ b/tests/web/web_server_smoke_test.cpp @@ -25,7 +25,7 @@ #include "security/audit_log.hpp" #include "environment/data_dir_migration.hpp" #include "environment/terminal_runtime.hpp" -#include "web/pty/pty_session_registry.hpp" +#include "pty/pty_session_registry.hpp" #include "environment/toolchains.hpp" #include "config/config_recovery.hpp" #include "config/saved_models.hpp" From de834f51fb6da8ca94334ac5a460bb02da484428 Mon Sep 17 00:00:00 2001 From: tmoonlight Date: Sun, 27 Sep 2026 17:40:10 +0800 Subject: [PATCH 3/8] =?UTF-8?q?refactor20260927(layers/P2-03):=20ProcessSp?= =?UTF-8?q?ec=20/=20PipedProcess=20/=20which=20=E4=B8=AD=E6=80=A7=E5=91=BD?= =?UTF-8?q?=E5=90=8D=E3=80=81CMake=20=E6=B8=85=E5=8D=95=E4=B8=8E=E8=BD=AC?= =?UTF-8?q?=E5=8F=91=E5=A4=B4=E3=80=81=E6=96=87=E6=A1=A3=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 内容修改(与前两个 [mechanical] 提交分开): - platform/process/process_runner.hpp 定义 platform::ProcessSpec(原 hooks/hook_config.hpp 的 HookCommandSpec),不再 include hooks;hooks/hook_config.hpp 改为 `using HookCommandSpec = platform::ProcessSpec;`,hooks 内部与 tests/hooks 沿用旧名;hooks 之外的调用点(grep_tool、worktree_manager、terminal_resolver、channels/setup、daemon/worker、remote_control/channel_plugin 及对应测试)改用 platform::ProcessSpec。run_hook_* 函数名暂不改。 - platform/process/piped_process.* 改为 acecode::platform 的 PipedProcess / SpawnOptions,platform/process/which.* 改为 acecode::platform;新增 lsp/lsp_platform_aliases.hpp 保留 lsp::LspProcess / LspSpawnOptions / FileExistsFn / which / which_in / quote_windows_arg 别名,lsp_client.hpp 与 lsp_server_registry.hpp 改 include 它;channels(bridge / runtime / setup)、environment/toolchains 与 test_support/channels 直接改用 platform:: 名字(layout-map §6「P2-03 起 bridge/setup 改用 platform/process」)。 - os_process*(原 daemon/platform*)与 terminal/console.hpp(原 upgrade/console.hpp)只搬位置,命名空间 acecode::daemon / acecode::upgrade 暂留,头注释说明。 - 搬走文件里指回旧目录的 14 行裸名 include 手工改为模块根形式(clipboard.cpp 的 base64/encoding、logger.hpp ×5、strings.cpp 的 locale、4 个自包含头名)。 - CMakeLists.txt:ACECODE_NATIVE_BRIDGE_SUPPORT_SOURCES 的 11 行、ACECODE_NOTIFICATION_BACKEND_SOURCES 2 行、target_sources 的 2 处 notifications_win/stub、2 处注释;cmake/acecode_source_paths.cmake 的 winpty_agent_location 与两个 .mm;cmake/acecode_winpty.cmake 注释。P2-04 的 runtime_files / agent_browser_runtime / open_request / workspace_registry 四行未动。 - 20 个 2 行转发头留在旧路径(utils 7、upgrade 1、hooks 1、lsp 2、daemon 1、desktop 8),src/layers.tsv 登记 20 条 exception(rule R1,R2,owner Claude-p2-03,expires 2026-10-15)。src/web/pty/ 的 4 个头**不留转发头**:新模块名 pty 与旧子目录同名,src/web/ 下的 `"pty/x.hpp"` 会先命中转发头,MSVC 又按父包含者目录把转发头里的 include 解析回它自己(#pragma once 后为空),routes_environment.cpp 实测 C2027 未定义 PtySessionRegistry;lint 亦判 R8 歧义。web 内三个使用方、worker.cpp 与 tests 已全部改写。 - 文档路径:CLAUDE.md(Desktop Shell / Mouse+Clipboard / ConsoleDock / Windows 弹框 / LSP 段)、AGENT.md、tests/README.md、docs/localization.md、docs/desktop-shell/multi-workspace.md、docs/plan/reviews/theme-management-001-web.md、docs/string-utilities-refactor.md、docs/help-source/group6.py(经 build_help.py 重新生成 sources.json,其余生成物无 diff)、tests/cpp_source_paths.json(desktop/context_picker.cpp 的值);搬走的测试与 open_url.hpp 的头注释路径同步。 验证:全新目录 build-p2(Ninja + MSVC 2022 Release,BUILD_TESTING=ON,ACECODE_BUILD_DESKTOP=ON)构建 acecode / acecode-desktop / acecode_unit_tests 通过,acecode-desktop.exe 的 link 行只有 acecode_desktop_support.lib + acecode_native_bridge_support.lib;check_layers --enforce-parent-includes 161 -> 160(消失的边:hook_runner.hpp -> hook_config.hpp 的 base->domain);normalize_includes --check src/tests exit 0;check_doc_paths 85 -> 85;check_file_size / check_ownership --strict exit 0。完整记录见 verification/P2-03-platform-and-pty.md。 --- AGENT.md | 2 +- CLAUDE.md | 20 +++++------ CMakeLists.txt | 34 +++++++++---------- cmake/acecode_source_paths.cmake | 6 ++-- cmake/acecode_winpty.cmake | 2 +- docs/desktop-shell/multi-workspace.md | 2 +- docs/help-source/group6.py | 2 +- docs/help-source/sources.json | 2 +- docs/localization.md | 2 +- docs/plan/reviews/theme-management-001-web.md | 2 +- docs/string-utilities-refactor.md | 8 ++--- src/channels/bridge.cpp | 10 +++--- src/channels/bridge.hpp | 4 +-- src/channels/runtime.hpp | 2 +- src/channels/setup.cpp | 6 ++-- src/channels/setup.hpp | 2 +- src/daemon/platform.hpp | 2 ++ src/daemon/worker.cpp | 2 +- src/desktop/context_picker.hpp | 2 ++ src/desktop/custom_toast.hpp | 2 ++ src/desktop/folder_picker.hpp | 2 ++ src/desktop/locale.hpp | 2 ++ src/desktop/notifications.hpp | 2 ++ src/desktop/notifications_backend.hpp | 2 ++ src/desktop/open_in_explorer.hpp | 2 ++ src/desktop/strings.hpp | 2 ++ src/environment/terminal_resolver.cpp | 2 +- src/environment/toolchains.cpp | 4 +-- src/environment/toolchains.hpp | 4 +-- src/hooks/hook_config.hpp | 11 +++--- src/hooks/hook_runner.hpp | 2 ++ src/layers.tsv | 20 +++++++++++ src/lsp/lsp_client.hpp | 2 +- src/lsp/lsp_platform_aliases.hpp | 20 +++++++++++ src/lsp/lsp_process.hpp | 2 ++ src/lsp/lsp_server_registry.hpp | 3 +- src/lsp/lsp_which.hpp | 2 ++ src/platform/clipboard.cpp | 4 +-- src/platform/native_ui/strings.cpp | 2 +- src/platform/open_url.hpp | 2 +- src/platform/power_inhibitor.cpp | 2 +- src/platform/process/os_process.hpp | 5 +++ src/platform/process/os_process_posix.cpp | 4 +-- src/platform/process/os_process_windows.cpp | 4 +-- src/platform/process/piped_process.cpp | 22 ++++++------ src/platform/process/piped_process.hpp | 26 +++++++------- src/platform/process/process_runner.cpp | 12 +++---- src/platform/process/process_runner.hpp | 22 ++++++++++-- src/platform/process/which.cpp | 6 ++-- src/platform/process/which.hpp | 8 +++-- src/platform/terminal/terminal_capability.cpp | 2 +- .../terminal/terminal_theme_detect.cpp | 2 +- .../terminal/terminal_theme_detect_posix.cpp | 2 +- .../terminal/terminal_theme_detect_win.cpp | 2 +- src/remote_control/channel_plugin.cpp | 6 ++-- src/remote_control/channel_plugin.hpp | 2 +- src/tool/grep_tool.cpp | 8 ++--- src/upgrade/console.hpp | 2 ++ src/utils/clipboard.hpp | 2 ++ src/utils/open_url.hpp | 2 ++ src/utils/power_inhibitor.hpp | 2 ++ src/utils/terminal_capability.hpp | 2 ++ src/utils/terminal_input.hpp | 2 ++ src/utils/terminal_theme_detect.hpp | 2 ++ src/utils/terminal_title.hpp | 2 ++ src/worktree/worktree_manager.cpp | 2 +- tests/README.md | 2 +- .../commands/remote_control_command_test.cpp | 2 +- tests/cpp_source_paths.json | 2 +- tests/platform/hook_runner_test.cpp | 12 +++---- tests/platform/lsp_which_test.cpp | 6 ++-- tests/platform/open_url_test.cpp | 2 +- tests/platform/terminal_capability_test.cpp | 2 +- tests/platform/terminal_title_test.cpp | 2 +- tests/pty/pty_backend_test.cpp | 2 +- tests/pty/pty_session_registry_test.cpp | 2 +- tests/remote_control/channel_plugin_test.cpp | 24 ++++++------- .../session_channel_binder_test.cpp | 2 +- tests/test_support/channels/test_support.hpp | 2 +- 79 files changed, 262 insertions(+), 159 deletions(-) create mode 100644 src/daemon/platform.hpp create mode 100644 src/desktop/context_picker.hpp create mode 100644 src/desktop/custom_toast.hpp create mode 100644 src/desktop/folder_picker.hpp create mode 100644 src/desktop/locale.hpp create mode 100644 src/desktop/notifications.hpp create mode 100644 src/desktop/notifications_backend.hpp create mode 100644 src/desktop/open_in_explorer.hpp create mode 100644 src/desktop/strings.hpp create mode 100644 src/hooks/hook_runner.hpp create mode 100644 src/lsp/lsp_platform_aliases.hpp create mode 100644 src/lsp/lsp_process.hpp create mode 100644 src/lsp/lsp_which.hpp create mode 100644 src/upgrade/console.hpp create mode 100644 src/utils/clipboard.hpp create mode 100644 src/utils/open_url.hpp create mode 100644 src/utils/power_inhibitor.hpp create mode 100644 src/utils/terminal_capability.hpp create mode 100644 src/utils/terminal_input.hpp create mode 100644 src/utils/terminal_theme_detect.hpp create mode 100644 src/utils/terminal_title.hpp diff --git a/AGENT.md b/AGENT.md index 29a535e06..d68d7c501 100644 --- a/AGENT.md +++ b/AGENT.md @@ -159,7 +159,7 @@ On Linux desktop builds, install the WebKitGTK development package before config Permission modes live in `src/permissions.hpp`: `Default` (prompt writes/exec), `AcceptEdits` (auto-allow file writes, still prompt shell), `Yolo` (auto-allow tools), and `Plan` (explore / write only the active plan file). Memory writes stay path-locked even under broader modes. Non-loopback `--dangerous` is rejected. -Other shared subsystems that are easy to miss: `src/gitinfo/` (prompt + REST git snapshots), `src/hooks/` (Codex-compatible lifecycle hooks), `src/web/pty/` (console dock; `/api/pty` and `/ws/pty` are loopback-only), `src/loop/` (scheduled loop tasks), `src/experts/`, and `src/remote_control/`. +Other shared subsystems that are easy to miss: `src/gitinfo/` (prompt + REST git snapshots), `src/hooks/` (Codex-compatible lifecycle hooks), `src/pty/` (console dock, formerly the `web/pty/` subdirectory; `/api/pty` and `/ws/pty` are loopback-only), `src/loop/` (scheduled loop tasks), `src/experts/`, and `src/remote_control/`. ## Test And Build Structure diff --git a/CLAUDE.md b/CLAUDE.md index 1a8eaf351..cbbc2d529 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -310,7 +310,7 @@ Key modules: - `workspace_registry`: persisted workspace list and names. - `daemon_pool`: per-workspace daemon process management. - `web_host`: native webview wrapper and bridge binding. -- `tray_icon_win` and `notifications_win`: Windows tray and notification integration. +- `tray_icon_win` and `notifications_win`: Windows tray and notification integration (`notifications*` and `custom_toast*` now live in `src/platform/native_ui/`, refactor20260927 P2-03). - `custom_toast_win` and `notification_backend_policy`: the self-drawn toast fallback and the backend decision it hangs off. Detailed behavior is in [docs/desktop-shell/multi-workspace.md](docs/desktop-shell/multi-workspace.md). @@ -460,7 +460,7 @@ transcript 里的 tool_call 行渲染为 ` ● ToolName(args)`(与 user `>` / as ### Mouse Input + Clipboard -FTXUI mouse tracking is enabled by default — wheel scrolls `chat_focus_index` by ±1 (same `scroll_chat()` helper as ArrowUp/Down). Some terminals intercept native click-and-drag selection; Shift+drag is the universal bypass. FTXUI's drag-select drives a built-in selection styled blue/white; right-click with a non-empty selection writes OSC 52 (`ESC ] 52 ; c ; ESC \`) using `src/utils/base64.hpp`, then flashes `Copied N bytes to clipboard` (auto-cleared ~2s via `status_line_clear_at`). Right-click with no selection and Ctrl+V both read text from the system clipboard via `src/utils/clipboard.*` and feed the existing paste-normalization path; on Linux this requires `wl-paste`, `xclip`, or `xsel`. Inside tmux, set `set -g set-clipboard on` or the OSC 52 copy path is consumed. +FTXUI mouse tracking is enabled by default — wheel scrolls `chat_focus_index` by ±1 (same `scroll_chat()` helper as ArrowUp/Down). Some terminals intercept native click-and-drag selection; Shift+drag is the universal bypass. FTXUI's drag-select drives a built-in selection styled blue/white; right-click with a non-empty selection writes OSC 52 (`ESC ] 52 ; c ; ESC \`) using `src/utils/base64.hpp`, then flashes `Copied N bytes to clipboard` (auto-cleared ~2s via `status_line_clear_at`). Right-click with no selection and Ctrl+V both read text from the system clipboard via `src/platform/clipboard.*` and feed the existing paste-normalization path; on Linux this requires `wl-paste`, `xclip`, or `xsel`. Inside tmux, set `set -g set-clipboard on` or the OSC 52 copy path is consumed. ### Legacy terminal fallback @@ -574,13 +574,13 @@ handler 实现在 `src/web/handlers/{fork,models,history,skills,files}_handler.{ `acecode-desktop.exe`(`-DACECODE_BUILD_DESKTOP=ON` 编出)是个 webview/webview 壳,默认管 N 个 daemon 子进程 — 每 workspace 一个独立 daemon(独立 loopback 端口 + 独立 token + 独立 Job Object)。daemon 内部代码零改动:每个 daemon 进程仍只服务自己的 `current_path()`,通过 `lpCurrentDirectory` 在 `CreateProcess` 时落地。 -关键模块(全在 `src/desktop/`): +关键模块(除注明外全在 `src/desktop/`;refactor20260927 P2-03 起 locale、folder_picker / context_picker / open_in_explorer / notifications* / custom_toast* / strings 下沉到 `src/platform/` 与 `src/platform/native_ui/`): - `workspace_registry.{hpp,cpp}` — 扫 `.acecode/projects//workspace.json`(`{cwd, name}`),默认命名 = `fs::path(cwd).filename()`,行内重命名走 `set_name` 原子写。 - `daemon_pool.{hpp,cpp}` — `unordered_map`,per-key condvar 串行化同 hash 并发 activate;`stop_all` best-effort。`IDaemonSupervisor` 虚基类便于单测 mock。 - `pick_active.{hpp,cpp}` — 启动选 active workspace 的纯函数:`state.json::last_active_workspace_hash` → process cwd 的 hash → registry 第一项 → 空。 -- `folder_picker_win.cpp` — `IFileOpenDialog` + `FOS_PICKFOLDERS`,COM STA。 +- `platform/native_ui/folder_picker_win.cpp` — `IFileOpenDialog` + `FOS_PICKFOLDERS`,COM STA。 - `web_host.{hpp,cpp}` — webview 包装,暴露 `bind/eval/init_script/native_window`,debug=true 默认开 F12 DevTools。 -- `tray_icon_win.{hpp,cpp}` / `notifications_win.{hpp,cpp}` / `tray_menu_layout.hpp` — 系统托盘 + OS 气泡通知。tray 注册 hidden **真实顶层** window(WS_POPUP+WS_EX_TOOLWINDOW,无 WS_VISIBLE;**不能用 HWND_MESSAGE** —— message-only 窗口没有前台资格,SetForegroundWindow 静默失败,TrackPopupMenu 菜单会被置顶任务栏挡住且 click-away 不消失;KB135788 配方 = SetForegroundWindow 前置 + 菜单后 PostMessage(WM_NULL)),WndProc 接 `Shell_NotifyIcon` 回调消息(`NIN_BALLOONUSERCLICK` / `WM_LBUTTONUP` / `WM_LBUTTONDBLCLK` / `WM_RBUTTONUP`);通知用 `Shell_NotifyIconW(NIM_MODIFY, NIF_INFO)` piggyback 在同一图标上。`init_tray_icon` → `init_notifications(tray_hwnd)`,顺序不能反。V1 仅气泡,V2 计划接 WinRT ToastNotificationManager(需 AUMID + 开始菜单 .lnk + cppwinrt)。托盘图标走 `LoadImageW(IMAGE_ICON, SM_CXSMICON, SM_CYSMICON)` 直接挑 .ico 内 16×16 frame(`enhance-desktop-tray-menu`)。右键菜单走 Codex 风格(Pinned / Recent + More 子菜单 / 新建会话 / 打开 ACECode / 退出),layout 由 `tray_menu_layout.hpp::compute_menu_layout(payload)` 纯函数算 ID 编码 — 1..49 固定项 / 100..199 pinned / 200..299 recent 顶层 / 300..399 More 子菜单。 +- `tray_icon_win.{hpp,cpp}` / `platform/native_ui/notifications{.hpp,_win.cpp}` / `tray_menu_layout.hpp` — 系统托盘 + OS 气泡通知。tray 注册 hidden **真实顶层** window(WS_POPUP+WS_EX_TOOLWINDOW,无 WS_VISIBLE;**不能用 HWND_MESSAGE** —— message-only 窗口没有前台资格,SetForegroundWindow 静默失败,TrackPopupMenu 菜单会被置顶任务栏挡住且 click-away 不消失;KB135788 配方 = SetForegroundWindow 前置 + 菜单后 PostMessage(WM_NULL)),WndProc 接 `Shell_NotifyIcon` 回调消息(`NIN_BALLOONUSERCLICK` / `WM_LBUTTONUP` / `WM_LBUTTONDBLCLK` / `WM_RBUTTONUP`);通知用 `Shell_NotifyIconW(NIM_MODIFY, NIF_INFO)` piggyback 在同一图标上。`init_tray_icon` → `init_notifications(tray_hwnd)`,顺序不能反。V1 仅气泡,V2 计划接 WinRT ToastNotificationManager(需 AUMID + 开始菜单 .lnk + cppwinrt)。托盘图标走 `LoadImageW(IMAGE_ICON, SM_CXSMICON, SM_CYSMICON)` 直接挑 .ico 内 16×16 frame(`enhance-desktop-tray-menu`)。右键菜单走 Codex 风格(Pinned / Recent + More 子菜单 / 新建会话 / 打开 ACECode / 退出),layout 由 `tray_menu_layout.hpp::compute_menu_layout(payload)` 纯函数算 ID 编码 — 1..49 固定项 / 100..199 pinned / 200..299 recent 顶层 / 300..399 More 子菜单。 - 关窗(× / Alt+F4 / `aceDesktop_closeWindow`)默认隐藏到托盘(`config.desktop.close_to_tray`,默认 true);设为 false 回到旧的关窗即退出。真正退出走托盘 "退出" 菜单 → `WebHost::request_quit()` 派 `WM_USER+0x10` 绕过 close_request_handler;`web_host_close_policy.hpp` 的 `dispatch_wm_close` / `dispatch_request_quit` 是纯函数,unit test 可覆盖派发不变量。 - 全局单例(per-user):`single_instance.{hpp,cpp,_win.cpp,_posix.cpp}`。`wWinMain` 第一件事 `SingleInstance::try_acquire()`,失败 → `focus_existing_instance()` 拉前已有窗口再 exit(0)。Windows 走 `CreateMutexW(L"Local\\ACECode-Desktop-Singleton-v1")` + `RegisterWindowMessageW(L"ACECode_FocusExistingInstance_v1")` + `PostMessageW`,host_window_proc 收到该 msg 时 `ShowWindow + SetForegroundWindow`。POSIX 端 `flock` 在 `~/.acecode/run/acecode-desktop.lock` 拿独占锁(Linux/macOS 桌面壳落地时复用);窗口拉前在 POSIX 上 v1 stub 返 false,等 D-Bus / NSDistributedNotificationCenter 接入再补。 - `main.cpp::wWinMain` — 串起所有,quit 时写 `last_active_workspace_hash` + `pool.stop_all()` + `shutdown_notifications()` + `shutdown_tray_icon()`。 @@ -603,7 +603,7 @@ JS↔C++ bridge(同进程,webview `bind`,无 HTTP): 切换 workspace 走**整页 navigate**(对设计稿 D6"无重载切换"的合理偏离):跨 loopback 端口 fetch 受 CORS 拦截,整页 navigate 让 origin 跟着切。代价是滚动 / 弹窗状态丢失,但 input box 清空 / 消息列表替换符合 spec。后续若加 `Access-Control-Allow-Origin: http://127.0.0.1:*` 可恢复无重载。 -**webapp 兼容模式**(WebView2 不可用或 `--webapp`):`main.cpp::run_browser_fallback` 用外部浏览器打开 `?ace_webapp=1` —— Edge `--app`(`launch_edge_app`)优先,失败退到系统默认浏览器(`open_external_url`)。**关键**:不再用 `WaitForSingleObject(msedge)` 当生命周期(Chromium single-instance 转交会让被等的进程瞬间退出 → daemon 被 `stop_all` 提前杀 → Edge 窗口连不上 → 白屏)。改为托盘 + Win32 消息循环托住进程,daemon 全程存活;Edge `--app` 这条额外挂 watcher 线程(`WaitForMultipleObjects(msedge, stop_event)`)实现关窗即退出。`launch_edge_app` 每次启动用一个 PID 唯一的干净 `edge-app-profile/u` 子目录(开机清旧的)杜绝转交 —— 代价是该兜底路径下 Edge profile 的 localStorage(主题/布局偏好)不跨启动持久。前端 `lib/desktopShellMode.js` 在 mount 前把该参数固化到 sessionStorage(`ace.webappCompat`,App 内多处 replaceState 会抹 query,只靠 URL 会丢)并设 `window.__ACECODE_WEBAPP_COMPAT__`;`DesktopContextMenu` 的门控 = `isDesktopShell() || isWebappCompat()`,即兼容模式照常出自定义右键菜单(普通浏览器直连仍保留原生右键)。bridge 依赖项的降级:「在资源管理器中打开/显示」走 `POST /api/open-in-explorer` REST 兜底;剪贴板走 `navigator.clipboard`(loopback 是 secure context);「检查」(DevTools) 仅 debug 且兼容模式不可用。选目录对话框由 daemon 进程弹出(无前台权),`folder_picker_win.cpp` 用 owner=GetForegroundWindow + #32770/pid 匹配的 TOPMOST 脉冲 + AttachThreadInput 组合置前;mac 在 runModal 前升 activation policy 到 Accessory + activate + NSModalPanelWindowLevel;Linux zenity/kdialog 受 WM 焦点防抢限制,无可靠通用解(future: xdg-desktop-portal FileChooser)。 +**webapp 兼容模式**(WebView2 不可用或 `--webapp`):`main.cpp::run_browser_fallback` 用外部浏览器打开 `?ace_webapp=1` —— Edge `--app`(`launch_edge_app`)优先,失败退到系统默认浏览器(`open_external_url`)。**关键**:不再用 `WaitForSingleObject(msedge)` 当生命周期(Chromium single-instance 转交会让被等的进程瞬间退出 → daemon 被 `stop_all` 提前杀 → Edge 窗口连不上 → 白屏)。改为托盘 + Win32 消息循环托住进程,daemon 全程存活;Edge `--app` 这条额外挂 watcher 线程(`WaitForMultipleObjects(msedge, stop_event)`)实现关窗即退出。`launch_edge_app` 每次启动用一个 PID 唯一的干净 `edge-app-profile/u` 子目录(开机清旧的)杜绝转交 —— 代价是该兜底路径下 Edge profile 的 localStorage(主题/布局偏好)不跨启动持久。前端 `lib/desktopShellMode.js` 在 mount 前把该参数固化到 sessionStorage(`ace.webappCompat`,App 内多处 replaceState 会抹 query,只靠 URL 会丢)并设 `window.__ACECODE_WEBAPP_COMPAT__`;`DesktopContextMenu` 的门控 = `isDesktopShell() || isWebappCompat()`,即兼容模式照常出自定义右键菜单(普通浏览器直连仍保留原生右键)。bridge 依赖项的降级:「在资源管理器中打开/显示」走 `POST /api/open-in-explorer` REST 兜底;剪贴板走 `navigator.clipboard`(loopback 是 secure context);「检查」(DevTools) 仅 debug 且兼容模式不可用。选目录对话框由 daemon 进程弹出(无前台权),`platform/native_ui/folder_picker_win.cpp` 用 owner=GetForegroundWindow + #32770/pid 匹配的 TOPMOST 脉冲 + AttachThreadInput 组合置前;mac 在 runModal 前升 activation policy 到 Accessory + activate + NSModalPanelWindowLevel;Linux zenity/kdialog 受 WM 焦点防抢限制,无可靠通用解(future: xdg-desktop-portal FileChooser)。 设计文档:`docs/desktop-shell/design.md` + `docs/desktop-shell/multi-workspace.md`,change:`openspec/changes/add-desktop-multi-workspace/`。 @@ -639,7 +639,7 @@ JS↔C++ bridge(同进程,webview `bind`,无 HTTP): `add-console-dock`:TopBar `>_` 按钮(icon `terminal` = TerminalReadWrite.svg)或 ``Ctrl+` `` toggle 主内容列底部的终端停靠区(横跨 ChatView+SidePanel,不动 Sidebar/TopBar)。前端 xterm.js(`@xterm/xterm` + `@xterm/addon-fit`,bundle +~190KB gzip);多 tab(+ 新建 / 逐 tab × 杀会话 / 整体收起保活);顶边拖高(`clampDockHeight`,[120, 视口 80%]);偏好 `acecode.consoleDock.v1` `{open, height}`。纯函数层 `web/src/lib/consoleDock.js`(tab 状态机/帧分流/退避/URL,Node 单测)。**xterm 聚焦时 ``Ctrl+` `` 靠 `attachCustomKeyEventHandler` 放行冒泡** — 删掉它快捷键在终端内失灵。 -daemon 侧 `src/web/pty/`:`PtyBackend` 四实现 — **ConPty**(1809+,GetProcAddress 探测;读循环必须 PeekNamedPipe 轮询,`ClosePseudoConsole` 后管道不保证断,阻塞 ReadFile 永不返回)/ **Winpty**(<1809 完整 TTY;winpty 0.4.3 经 FetchContent + `cmake/acecode_winpty.cmake` 自写包装,**不编上游 AgentLocation.cc**,由 `winpty_agent_location.cpp` 提供可覆盖的 `findAgentProgram()`;agent.exe 310KB 嵌入二进制(bin2cpp),首次使用释放到 `/bin/`)/ **Pipe**(兜底,无 TTY 语义,前端显示"兼容模式")/ **PosixPty**(forkpty,Linux ``/macOS ``)。`PtySessionRegistry`:2MB 缓冲 + 字节游标续传、`0x00`+JSON 控制帧、16 会话上限、kill 必须锁外(join 读线程回抢 mu_)。路由 `/api/pty` + `/ws/pty/?cursor=N` **loopback 硬限制**(token 不豁免);WS 的 id/cursor 经 Crow `onaccept` 的 `void** userdata` 传递(onopen 拿不到 route 参数)。config `console.shell` 覆盖 shell(默认 `%COMSPEC%`/`$SHELL` — cmd 优先于 powershell 是用户决策,与 bash_tool 一致)。协议文档 docs/daemon-api.md §7。 +daemon 侧 `src/pty/`(原 web 模块下的 `web/pty/` 子目录,refactor20260927 P2-03 下沉为 base 层模块;`routes_pty.cpp` 留在 web):`PtyBackend` 四实现 — **ConPty**(1809+,GetProcAddress 探测;读循环必须 PeekNamedPipe 轮询,`ClosePseudoConsole` 后管道不保证断,阻塞 ReadFile 永不返回)/ **Winpty**(<1809 完整 TTY;winpty 0.4.3 经 FetchContent + `cmake/acecode_winpty.cmake` 自写包装,**不编上游 AgentLocation.cc**,由 `winpty_agent_location.cpp` 提供可覆盖的 `findAgentProgram()`;agent.exe 310KB 嵌入二进制(bin2cpp),首次使用释放到 `/bin/`)/ **Pipe**(兜底,无 TTY 语义,前端显示"兼容模式")/ **PosixPty**(forkpty,Linux ``/macOS ``)。`PtySessionRegistry`:2MB 缓冲 + 字节游标续传、`0x00`+JSON 控制帧、16 会话上限、kill 必须锁外(join 读线程回抢 mu_)。路由 `/api/pty` + `/ws/pty/?cursor=N` **loopback 硬限制**(token 不豁免);WS 的 id/cursor 经 Crow `onaccept` 的 `void** userdata` 传递(onopen 拿不到 route 参数)。config `console.shell` 覆盖 shell(默认 `%COMSPEC%`/`$SHELL` — cmd 优先于 powershell 是用户决策,与 bash_tool 一致)。协议文档 docs/daemon-api.md §7。 **ConPTY 必踩坑**:pseudoconsole 子进程的 std 句柄仍按老规则从父进程 PEB 复制 — daemon 被 desktop 以 `CREATE_NO_WINDOW` + NUL std 启动时,cmd 复制到无效 stdin → 读 EOF → 秒退 code 0(实测复现)。修复 = spawn 时 `STARTF_USESTDHANDLES` + 三个 NULL 句柄(node-pty 同款),console 子进程初始化回退绑定 conpty console。该修复同时治好了单测 harness 内的同根伪影(最初误判为受限 Job 杀 conhost);`pty_backend_test.cpp` 的环境探针防御性保留。 @@ -647,7 +647,7 @@ daemon 侧 `src/web/pty/`:`PtyBackend` 四实现 — **ConPty**(1809+,GetProcAdd 问题:一批 Win10 机器上 WinToast 的 `initialize()` / `showToast()` 全返回成功,弹框却永远不出现 —— AUMID 的开始菜单快捷方式没建成、通知被系统/单应用/组策略关掉、或被"优化"工具停了通知平台。这些都读不出错误码,单靠返回值永远发现不了。 -**三层结构**(全部在 `src/desktop/`): +**三层结构**(`notification_backend_policy` 在 `src/desktop/`,其余两层自 refactor20260927 P2-03 起在 `src/platform/native_ui/`): 1. `notification_backend_policy.{hpp,cpp}` — 纯判定表。输入 `NotificationBackendPreference`(config `desktop.notifications.backend` = `auto`(默认)/ `system` / `custom`)+ `SystemToastSignals`(platform_supported / toasts_enabled_globally / app_toasts_enabled / policy_disabled / runtime_delivery_failed),输出 `System | Custom | None` + reason 文案。`auto` 任一信号变坏就转自绘;`system` 是显式选择,不可用时返回 `None` 而**不是**偷偷换成自绘;`custom` 无条件自绘。 2. `notifications_win.cpp` — 路由 + 注册表探测(`PushNotifications\ToastEnabled`、`Notifications\Settings\\Enabled`、两条 policy 键的 HKCU/HKLM)。WinToast 代码整体收进 `#ifdef ACECODE_HAS_WINTOAST`,**该文件现在在所有 WIN32 构建里编译**(MinGW/WinLibs 不再退化成 no-op stub,自绘渲染只吃 Win32+GDI)。运行期降级是粘性的:`showToast` 返回 <0 或 `toastFailed()` 回调(WinRT 线程,所以用 `std::atomic` 不用锁)置位后重新判定并改走自绘。 3. `custom_toast.{hpp,cpp}` + `custom_toast_win.cpp` — 自绘渲染,抄 Electron 的 `win32_desktop_notifications`(MIT):隐藏 controller 窗口持 15ms 动画 timer,工作区右下角一摞 `WS_EX_LAYERED|WS_EX_NOACTIVATE|WS_EX_TOPMOST` 的 `WS_POPUP`,GDI 画进内存 DC 后 `UpdateLayeredWindow(Indirect)` 推给合成器;宽度 ease-in(源点同步左移 = 从屏幕边缘滑出)、alpha ease-out、栈塌陷动画三条曲线。 @@ -658,7 +658,7 @@ daemon 侧 `src/web/pty/`:`PtyBackend` 四实现 — **ConPty**(1809+,GetProcAdd 其它必知细节:controller 窗口**不能用 HWND_MESSAGE**(收不到 `WM_SETTINGCHANGE`/`WM_DISPLAYCHANGE` 广播,重锚失效,同 tray 的坑);渲染线程起手 `SetThreadDpiAwarenessContext(-4)`(动态取址,按 HANDLE 定型以兼容 MinGW 老头文件),这样终端进程不用改进程级 DPI 感知也能画清楚;鼠标悬停期间**冻结整摞**不回收空位(否则卡片滑到光标下,点击会落到另一条通知上);`shutdown()` 若发现自己就跑在渲染线程上(点击回调里拆通知)就 detach 而不是 join,否则自锁。 -纯逻辑(缓动曲线、栈偏移、工作区锚定、DPI 缩放、判定表)在 `tests/desktop/custom_toast_layout_test.cpp` + `notification_backend_policy_test.cpp` 里跨平台跑;GDI 渲染只能靠 `notifications_native_test.cpp` 里 `ACECODE_RUN_NOTIFICATION_SMOKE=1` 门控的两条手动冒烟(系统 toast 一条、强制 `backend=custom` 一条)。 +纯逻辑(缓动曲线、栈偏移、工作区锚定、DPI 缩放、判定表)在 `tests/platform/custom_toast_layout_test.cpp` + `notification_backend_policy_test.cpp` 里跨平台跑;GDI 渲染只能靠 `tests/platform/notifications_native_test.cpp` 里 `ACECODE_RUN_NOTIFICATION_SMOKE=1` 门控的两条手动冒烟(系统 toast 一条、强制 `backend=custom` 一条)。 ### Proxy / 抓包 @@ -703,7 +703,7 @@ The existing region detector still probes DuckDuckGo once at startup through `Pr 2. **编辑后诊断注入**:file_edit / file_write 成功落盘后 `lsp::append_diagnostics_block`(`src/lsp/lsp_diagnostics.cpp`)—— touch + 等 document 诊断(5s 总超时、150ms push debounce、50ms 粒度轮询 abort),把 **ERROR 级**诊断以 `` 块(≤20 条)附加到工具输出。未初始化 / disabled / 无匹配 server 零延迟。WARN 以下刻意不透出(避免模型跑偏修风格)。 3. **状态表面**:`/lsp` 双端命令(TUI builtin_commands + daemon `execute_builtin_command` 白名单 + Web 斜杠下拉,三处文本共用 `dispatch_lsp_subcommand`);TUI 侧边栏有连接时渲染 LSP 节(走 `connected_snapshot()`,廉价锁拷贝;完整 `status_snapshot()` 含 which 探测只给 /lsp 用)。 -结构:`lsp_frame`(分帧纯状态机)→ `lsp_process`(spawn;**Windows 上 argv[0] 为 .cmd/.bat 时自动经 `cmd.exe /d /c`**,npm shim 必需;探测走 `lsp_which` 的 PATHEXT 逻辑)→ `lsp_client`(reader 线程 + pending map;push/pull 双通道诊断缓存,key 经 `lsp_uri::normalize_path_key` 归一 —— **clangd 会把盘符改小写回推,不归一就永远等不到诊断**)→ `lsp_server_registry`(内置 clangd/typescript-language-server/pyright/gopls/rust-analyzer 定义 + config 合并;root markers 对照 opencode server.ts;ts 需向上找到 `node_modules/typescript/lib/tsserver.js` 否则跳过;rust-analyzer 无 Cargo.toml 判不适用)→ `lsp_service`((server_id,root) 客户端池、per-key slot 锁单飞、broken 集合本进程内不重试)→ 进程级单例 `lsp::init/shutdown/service()`(web_search runtime 同套路;main.cpp 与 worker.cpp 各接一次,退出路径在 mcp shutdown 之后调 `lsp::shutdown()`)。 +结构:`lsp_frame`(分帧纯状态机)→ `platform/process/piped_process`(原 `lsp_process`,P2-03 下沉到 platform,lsp 侧经 `lsp/lsp_platform_aliases.hpp` 保留 `LspProcess` / `LspSpawnOptions` 别名;spawn;**Windows 上 argv[0] 为 .cmd/.bat 时自动经 `cmd.exe /d /c`**,npm shim 必需;探测走 `platform/process/which`(原 `lsp_which`)的 PATHEXT 逻辑)→ `lsp_client`(reader 线程 + pending map;push/pull 双通道诊断缓存,key 经 `lsp_uri::normalize_path_key` 归一 —— **clangd 会把盘符改小写回推,不归一就永远等不到诊断**)→ `lsp_server_registry`(内置 clangd/typescript-language-server/pyright/gopls/rust-analyzer 定义 + config 合并;root markers 对照 opencode server.ts;ts 需向上找到 `node_modules/typescript/lib/tsserver.js` 否则跳过;rust-analyzer 无 Cargo.toml 判不适用)→ `lsp_service`((server_id,root) 客户端池、per-key slot 锁单飞、broken 集合本进程内不重试)→ 进程级单例 `lsp::init/shutdown/service()`(web_search runtime 同套路;main.cpp 与 worker.cpp 各接一次,退出路径在 mcp shutdown 之后调 `lsp::shutdown()`)。 **workspace 边界两条铁律**(2026-07-08 线上排障后立的,回归测试在 `tests/lsp/lsp_service_test.cpp`):(1) 所有查询/诊断入口按**调用传入的 session_cwd**(`ToolContext::cwd`)判 workspace 边界,空串才回退进程 init cwd —— daemon 单进程经 routes_workspaces 服务多 workspace 会话后,进程 cwd ≠ 会话 cwd,只认进程 cwd 会让其它 workspace 的文件恒报 "No LSP server available"、server 永不 spawn;(2) 边界比较/root 探测/slot key/URI 全部先 `weakly_canonical` 归一 —— 用户目录是 junction 时(实测 `C:\Users\x` → `N:\Users\x`),lsp 工具入口 canonical 过、诊断注入路径没 canonical 过,两形态前缀互不匹配,表现为「编辑后诊断能连上 server,查询却报无 server」。 diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d637c3a2..8d6c94e78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -223,26 +223,26 @@ set(ACECODE_NATIVE_BRIDGE_SUPPORT_SOURCES ${CMAKE_SOURCE_DIR}/src/config/request_headers.cpp ${CMAKE_SOURCE_DIR}/src/config/saved_models.cpp ${CMAKE_SOURCE_DIR}/src/provider/builtin_model_catalog.cpp - ${CMAKE_SOURCE_DIR}/src/daemon/platform_posix.cpp - ${CMAKE_SOURCE_DIR}/src/daemon/platform_windows.cpp + ${CMAKE_SOURCE_DIR}/src/platform/process/os_process_posix.cpp + ${CMAKE_SOURCE_DIR}/src/platform/process/os_process_windows.cpp ${CMAKE_SOURCE_DIR}/src/daemon/runtime_files.cpp - ${CMAKE_SOURCE_DIR}/src/desktop/custom_toast.cpp - ${CMAKE_SOURCE_DIR}/src/desktop/custom_toast_win.cpp + ${CMAKE_SOURCE_DIR}/src/platform/native_ui/custom_toast.cpp + ${CMAKE_SOURCE_DIR}/src/platform/native_ui/custom_toast_win.cpp ${CMAKE_SOURCE_DIR}/src/desktop/agent_browser_navigation_state.cpp ${CMAKE_SOURCE_DIR}/src/desktop/agent_browser_page_directory.cpp ${CMAKE_SOURCE_DIR}/src/desktop/agent_browser_runtime.cpp ${CMAKE_SOURCE_DIR}/src/desktop/context_items.cpp - ${CMAKE_SOURCE_DIR}/src/desktop/context_picker.cpp - ${CMAKE_SOURCE_DIR}/src/desktop/folder_picker_win.cpp - ${CMAKE_SOURCE_DIR}/src/desktop/locale.cpp - ${CMAKE_SOURCE_DIR}/src/desktop/notifications.cpp + ${CMAKE_SOURCE_DIR}/src/platform/native_ui/context_picker.cpp + ${CMAKE_SOURCE_DIR}/src/platform/native_ui/folder_picker_win.cpp + ${CMAKE_SOURCE_DIR}/src/platform/locale.cpp + ${CMAKE_SOURCE_DIR}/src/platform/native_ui/notifications.cpp ${CMAKE_SOURCE_DIR}/src/desktop/open_request.cpp - ${CMAKE_SOURCE_DIR}/src/desktop/open_in_explorer.cpp + ${CMAKE_SOURCE_DIR}/src/platform/native_ui/open_in_explorer.cpp ${CMAKE_SOURCE_DIR}/src/desktop/startup_progress.cpp - ${CMAKE_SOURCE_DIR}/src/desktop/strings.cpp + ${CMAKE_SOURCE_DIR}/src/platform/native_ui/strings.cpp ${CMAKE_SOURCE_DIR}/src/desktop/workspace_registry.cpp ${CMAKE_SOURCE_DIR}/src/utils/append_file.cpp - ${CMAKE_SOURCE_DIR}/src/utils/clipboard.cpp + ${CMAKE_SOURCE_DIR}/src/platform/clipboard.cpp ${CMAKE_SOURCE_DIR}/src/utils/cwd_hash.cpp ${CMAKE_SOURCE_DIR}/src/utils/encoding.cpp ${CMAKE_SOURCE_DIR}/src/utils/model_capabilities.cpp @@ -285,8 +285,8 @@ set(ACECODE_DESKTOP_BINARY_ONLY_SOURCES ${ACECODE_DESKTOP_WEB_HOST_SOURCE} ) set(ACECODE_NOTIFICATION_BACKEND_SOURCES - ${CMAKE_SOURCE_DIR}/src/desktop/notifications_win.cpp - ${CMAKE_SOURCE_DIR}/src/desktop/notifications_stub.cpp + ${CMAKE_SOURCE_DIR}/src/platform/native_ui/notifications_win.cpp + ${CMAKE_SOURCE_DIR}/src/platform/native_ui/notifications_stub.cpp ) foreach(_source_list IN ITEMS ACECODE_NATIVE_BRIDGE_SUPPORT_SOURCES ACECODE_DESKTOP_SUPPORT_SOURCES @@ -402,11 +402,11 @@ elseif(WIN32) ) # Windows notifications use the self-drawn layered toast (Win32 + GDI only). target_sources(acecode_native_bridge_support PRIVATE - ${CMAKE_SOURCE_DIR}/src/desktop/notifications_win.cpp + ${CMAKE_SOURCE_DIR}/src/platform/native_ui/notifications_win.cpp ) else() target_sources(acecode_native_bridge_support PRIVATE - ${CMAKE_SOURCE_DIR}/src/desktop/notifications_stub.cpp + ${CMAKE_SOURCE_DIR}/src/platform/native_ui/notifications_stub.cpp ) endif() @@ -491,13 +491,13 @@ endif() if(WIN32) # ws2_32: src/desktop/daemon_supervisor.cpp 用 winsock 探测端口连通性。 # mswsock: standalone Asio IOCP uses AcceptEx/GetAcceptExSockaddrs. - # ole32/shell32/user32: src/desktop/folder_picker_win.cpp 的 COM + IFileOpenDialog + owner/foreground handling。 + # ole32/shell32/user32: src/platform/native_ui/folder_picker_win.cpp 的 COM + IFileOpenDialog + owner/foreground handling。 target_link_libraries(acecode_testable PUBLIC bcrypt advapi32 winhttp ws2_32 mswsock iphlpapi ole32 shell32 user32) # winpty 客户端库(< 1809 的 PTY 兜底,cmake/acecode_winpty.cmake)。 target_link_libraries(acecode_testable PUBLIC winpty_static) endif() if(UNIX AND NOT APPLE) - # forkpty(src/web/pty/pty_backend_posix.cpp)。glibc 2.34+ 已并入 libc, + # forkpty(src/pty/pty_backend_posix.cpp)。glibc 2.34+ 已并入 libc, # 老 glibc / musl 仍需显式链 util;find_library 找不到就交给 libc。 find_library(ACECODE_LIBUTIL util) if(ACECODE_LIBUTIL) diff --git a/cmake/acecode_source_paths.cmake b/cmake/acecode_source_paths.cmake index d4c45a2fd..362c4ca3c 100644 --- a/cmake/acecode_source_paths.cmake +++ b/cmake/acecode_source_paths.cmake @@ -2,7 +2,7 @@ set(ACECODE_MAIN_SOURCE "${CMAKE_SOURCE_DIR}/src/main.cpp") set(ACECODE_UPGRADE_MANIFEST_SOURCE "${CMAKE_SOURCE_DIR}/src/upgrade/manifest.cpp") set(ACECODE_CHANNEL_BRIDGE_SOURCE "${CMAKE_SOURCE_DIR}/src/channels/bridge.cpp") -set(ACECODE_WINPTY_AGENT_LOCATION_SOURCE "${CMAKE_SOURCE_DIR}/src/web/pty/winpty_agent_location.cpp") +set(ACECODE_WINPTY_AGENT_LOCATION_SOURCE "${CMAKE_SOURCE_DIR}/src/pty/winpty_agent_location.cpp") set(ACECODE_DEEPIN_WINDOW_EFFECTS_SOURCE "${CMAKE_SOURCE_DIR}/src/desktop/deepin_window_effects.cpp") set(ACECODE_DESKTOP_MAIN_SOURCE "${CMAKE_SOURCE_DIR}/src/desktop/main.cpp") set(ACECODE_DESKTOP_SPLASH_SOURCE "${CMAKE_SOURCE_DIR}/src/desktop/splash_screen.cpp") @@ -29,8 +29,8 @@ set(ACECODE_COMPUTER_USE_MAC_SOURCES ${CMAKE_SOURCE_DIR}/src/computer_use/macos_input.mm ${CMAKE_SOURCE_DIR}/src/computer_use/macos_pointer.mm) set(ACECODE_NATIVE_BRIDGE_MAC_SOURCES - ${CMAKE_SOURCE_DIR}/src/desktop/folder_picker_mac.mm - ${CMAKE_SOURCE_DIR}/src/desktop/notifications_mac.mm) + ${CMAKE_SOURCE_DIR}/src/platform/native_ui/folder_picker_mac.mm + ${CMAKE_SOURCE_DIR}/src/platform/native_ui/notifications_mac.mm) set(ACECODE_DESKTOP_OBJCXX_SOURCES ${CMAKE_SOURCE_DIR}/src/desktop/tray_icon_win.cpp ${ACECODE_DESKTOP_WEB_HOST_SOURCE}) diff --git a/cmake/acecode_winpty.cmake b/cmake/acecode_winpty.cmake index d523b3269..7718de4a6 100644 --- a/cmake/acecode_winpty.cmake +++ b/cmake/acecode_winpty.cmake @@ -10,7 +10,7 @@ # # 与上游的两处刻意偏离: # 1. 不编译上游 libwinpty/AgentLocation.cc,由 -# src/web/pty/winpty_agent_location.cpp 提供同签名 findAgentProgram(), +# src/pty/winpty_agent_location.cpp 提供同签名 findAgentProgram(), # 支持进程级 agent 路径覆盖(上游硬编码"当前模块同目录",静态链接时 # 即 acecode.exe 同目录 — 安装目录通常不可写,无法释放 agent)。 # 2. WINPTY_API 静态适配:上游只有 dllexport/dllimport 两态。对库与 diff --git a/docs/desktop-shell/multi-workspace.md b/docs/desktop-shell/multi-workspace.md index 1c609d9fb..a5cac90fc 100644 --- a/docs/desktop-shell/multi-workspace.md +++ b/docs/desktop-shell/multi-workspace.md @@ -66,7 +66,7 @@ daemon slot 已启动,并向 daemon `POST /api/workspaces` 注册 cwd,返回同 | `src/desktop/workspace_registry.{hpp,cpp}` | 扫盘 / 读写 `workspace.json` / 默认命名 | | `src/desktop/daemon_pool.{hpp,cpp}` | 通用进程池;Desktop 当前只使用 `__shared_daemon__/default` slot | | `src/desktop/daemon_supervisor.{hpp,cpp}` | 单 daemon 子进程托管(spawn / probe / stop / Job Object)。提了 `IDaemonSupervisor` 虚基类便于单测 mock | -| `src/desktop/folder_picker_win.cpp` | `IFileOpenDialog` 包装 | +| `src/platform/native_ui/folder_picker_win.cpp` | `IFileOpenDialog` 包装 | | `src/desktop/pick_active.{hpp,cpp}` | 启动时挑哪个 workspace 当 active 的纯函数 | | `src/desktop/web_host.{hpp,cpp}` | webview/webview wrapper,暴露 `bind` / `eval` / `native_window` | | `src/desktop/main.cpp` | wWinMain 入口,串起所有 | diff --git a/docs/help-source/group6.py b/docs/help-source/group6.py index da965d441..5f56b5099 100644 --- a/docs/help-source/group6.py +++ b/docs/help-source/group6.py @@ -28,7 +28,7 @@ section("update", "更新失败或仍显示旧版", '''

检查更新源是否可访问、磁盘空间是否足够,以及目标程序是否被正在运行的进程锁定。保留错误输出,确认启动路径后按原安装方式重试更新,避免同时维护多个互相覆盖的副本。

更新命令成功后,重新打开目标应用并核对版本。桌面启动器与配套 daemon 应来自同一套安装包;不要只替换其中一个程序来测试正式安装。

配置错误触发自动回滚时,先查看回滚提示与备份位置,修复目标字段。卸载通常不等于清除所有个人数据;按更新与卸载选择是否保留模型和历史。

''', figure("TS-01", "安装或更新错误的有效截图", "截取完整错误文字、目标安装包或版本信息和发生时间;避免只截一个没有上下文的失败图标。")) -], ["src/daemon/cli.cpp", "docs/daemon-api.md", "docs/user-manual.md", "src/desktop/strings.cpp"]), +], ["src/daemon/cli.cpp", "docs/daemon-api.md", "docs/user-manual.md", "src/platform/native_ui/strings.cpp"]), "troubleshoot-models": page("按服务商、预设、实际端点和错误类别逐项检查,避免把所有失败都归因于模型本身。", [ section("fields", "先核对连接的四项信息", diff --git a/docs/help-source/sources.json b/docs/help-source/sources.json index 77cec214f..07a78a629 100644 --- a/docs/help-source/sources.json +++ b/docs/help-source/sources.json @@ -380,7 +380,7 @@ "src/daemon/cli.cpp", "docs/daemon-api.md", "docs/user-manual.md", - "src/desktop/strings.cpp" + "src/platform/native_ui/strings.cpp" ] }, { diff --git a/docs/localization.md b/docs/localization.md index 2e3f52490..e6a6ee1c3 100644 --- a/docs/localization.md +++ b/docs/localization.md @@ -56,7 +56,7 @@ Do not pass opaque values to `tr()` or interpolate them into a source string tha ## Native Desktop strings -Native-only fixed text uses the typed catalog in `src/desktop/strings.hpp` and `strings.cpp`. Add a `DesktopStringId`, add entries at the matching position in both locale arrays, and cover both locales in `tests/desktop`. Session/workspace titles and diagnostic details must remain opaque even when their surrounding native labels are localized. +Native-only fixed text uses the typed catalog in `src/platform/native_ui/strings.hpp` and `strings.cpp`. Add a `DesktopStringId`, add entries at the matching position in both locale arrays, and cover both locales in `tests/platform`. Session/workspace titles and diagnostic details must remain opaque even when their surrounding native labels are localized. The process-wide native locale is selected before startup UI and updated by `aceDesktop_applyLocale`. The bridge changes presentation state only; the daemon API remains the sole runtime writer of `config.json`. diff --git a/docs/plan/reviews/theme-management-001-web.md b/docs/plan/reviews/theme-management-001-web.md index fb99525fd..0357d79c2 100644 --- a/docs/plan/reviews/theme-management-001-web.md +++ b/docs/plan/reviews/theme-management-001-web.md @@ -83,7 +83,7 @@ C++ 存储已有独立审查,本报告只读取必要的接口状态依据并 - ZIP 下载在 `routes_themes.cpp:126` 起复用经过校验的作业资源,添加 `application/zip`、UTF-8 百分号编码 attachment 文件名、`private, no-store` 和 `nosniff`,成功后才响应文件。无任意目标路径参数,也不把鉴权凭据放入下载 URL。 - 删除在 `routes_themes.cpp:146` 起先持有 `app_config_mu`,确认该时刻当前主题,仅在需要回退时持久化 blue。save_config 抛出时恢复 `before.web_ui`,把失败交回 store 的隔离回滚;返回的 ui_preferences 取自同一锁下的实际配置。删除非当前主题不替换选择。 - `src/web/routes/routes_misc.cpp:2291` 把 ai/EVA 安装检查放入 config 锁内,再检查 store,和删除采用同样的锁顺序。因此删除后排队到达的旧 ID 写入不能重新持久化已删主题;与 Web 队列的旧快照过滤相互衔接。 -- `src/desktop/folder_picker_win.cpp:247` 起按建议文件名 `.zip` 切换单一 ZIP filter/default extension;mac `folder_picker_mac.mm:89` 起切换到 zip,且保留 `allowsOtherFileTypes = NO`。两者其它导出保留原有 Markdown 分支。新增中英文类型/标题/错误枚举与 strings catalog 顺序对应,未改变共享保存接口的路径来源。 +- `src/platform/native_ui/folder_picker_win.cpp:247` 起按建议文件名 `.zip` 切换单一 ZIP filter/default extension;mac `folder_picker_mac.mm:89` 起切换到 zip,且保留 `allowsOtherFileTypes = NO`。两者其它导出保留原有 Markdown 分支。新增中英文类型/标题/错误枚举与 strings catalog 顺序对应,未改变共享保存接口的路径来源。 - `cleanup_pending:true` 和新的 `cleanup_message` 描述提交后的隔离缓存清理延迟。Web 以 deleted 为成功依据并显示本地化待清理提示,不会因该附加字段恢复卡片。 独立读取 `build/theme-export-tests-20260912.xml` 和 `.log`:60 项全部通过,0 failure/error/skipped/disabled;其中 4 个新增真实 HTTP 用例覆盖内置保护、注入 destination 拒绝、原生能力缺失、鉴权 ZIP 头、取消选择不打包、原生保存、删除当前主题持久化 blue、旧偏好写入拒绝、配置写入失败后的文件/偏好回滚。另有 DesktopStrings 的完整 catalog 和 ZIP 文案断言通过。本复核未重复运行这 60 项。 diff --git a/docs/string-utilities-refactor.md b/docs/string-utilities-refactor.md index a750f821a..ce25d59e0 100644 --- a/docs/string-utilities-refactor.md +++ b/docs/string-utilities-refactor.md @@ -35,10 +35,10 @@ | 各自直接调 Win32 转换 API(`MultiByteToWideChar` / `WideCharToMultiByte`)的文件 | 9 个 | | 绕过入口、直接把 `.string()` 交给 C 接口的残留 | 本次修掉 2 处,apply/main 仍有少量 | -9 个直接调 Win32 转换的文件:`daemon/service_win.cpp`、`desktop/context_picker.cpp`、 -`desktop/folder_picker_win.cpp`、`desktop/splash_screen.cpp`、 +9 个直接调 Win32 转换的文件:`daemon/service_win.cpp`、`platform/native_ui/context_picker.cpp`、 +`platform/native_ui/folder_picker_win.cpp`、`desktop/splash_screen.cpp`、 `network/proxy_resolver_win.cpp`、`utils/cwd_hash.cpp`、`utils/encoding.cpp`、 -`utils/terminal_title.cpp`、`utils/text_file_buffer.cpp`。 +`platform/terminal/terminal_title.cpp`、`utils/text_file_buffer.cpp`。 ### 第二层:基础字符串处理 @@ -150,7 +150,7 @@ code review 规则,而不是假装正则能全覆盖。 业务特例,强行收敛只会让它更难读。 - **不做 `string_view` 全面改造** —— 改动面大、收益小,不在本次范围内。 - **不做文案集中 / i18n** —— 那是另一条线:C++ 侧有 750 处硬编码中文,而 - `src/desktop/strings.cpp` 已有成熟机制(enum ID + zh-CN/en-US 双目录 + + `src/platform/native_ui/strings.cpp` 已有成熟机制(enum ID + zh-CN/en-US 双目录 + `static_assert` 等长 + locale 解析与运行时切换),覆盖 52 条。若要做,方向是把 desktop 那套提升为全局 `acecode::strings`,而不是新造。参见 [localization.md](localization.md)。 diff --git a/src/channels/bridge.cpp b/src/channels/bridge.cpp index 267a830d8..98a10452a 100644 --- a/src/channels/bridge.cpp +++ b/src/channels/bridge.cpp @@ -19,7 +19,7 @@ namespace acecode::channels { struct Bridge::Impl { - lsp::LspProcess process; + platform::PipedProcess process; mutable std::mutex mu; std::condition_variable cv; std::thread reader, writer; @@ -92,7 +92,7 @@ struct Bridge::Impl { }; Bridge::Bridge() : impl_(std::make_unique()) {} Bridge::~Bridge() { stop(); } -void Bridge::start(const lsp::LspSpawnOptions& options) { +void Bridge::start(const platform::SpawnOptions& options) { stop(); auto& b = *impl_; std::string error; @@ -109,7 +109,7 @@ void Bridge::stop() { } b.fail("WhatsApp bridge stopped"); // Kill first, join readers/writers, then close handles. Never race a pipe - // handle mutation against an in-flight LspProcess read/write. + // handle mutation against an in-flight PipedProcess read/write. b.process.kill_child(); if (b.writer.joinable()) b.writer.join(); if (b.reader.joinable()) b.reader.join(); @@ -188,11 +188,11 @@ bool whatsapp_dependencies_ready(const std::filesystem::path& installed) { return !required.empty(); } catch (...) { return false; } } -lsp::LspSpawnOptions whatsapp_bridge_options(const std::filesystem::path& directory) { +platform::SpawnOptions whatsapp_bridge_options(const std::filesystem::path& directory) { const auto installed = prepare_whatsapp_bridge(directory); if (!whatsapp_dependencies_ready(installed)) throw std::runtime_error("WhatsApp dependencies missing or outdated. Run acecode channels to install them automatically."); - const auto node = lsp::which("node"); + const auto node = platform::which("node"); if (!node) throw std::runtime_error("Node.js 22+ is required on PATH for WhatsApp"); return {{*node, path_to_utf8(installed / "bridge.mjs"), "--state-dir", path_to_utf8(directory)}, path_to_utf8(installed), {}}; } diff --git a/src/channels/bridge.hpp b/src/channels/bridge.hpp index 2491eb37f..7fa63bc4e 100644 --- a/src/channels/bridge.hpp +++ b/src/channels/bridge.hpp @@ -14,7 +14,7 @@ class Bridge { public: Bridge(); ~Bridge(); - void start(const lsp::LspSpawnOptions& options); + void start(const platform::SpawnOptions& options); void stop(); bool running() const; Json request(const std::string& method, const Json& params, @@ -31,5 +31,5 @@ class Bridge { std::filesystem::path find_whatsapp_bridge(); std::filesystem::path prepare_whatsapp_bridge(const std::filesystem::path& state_directory); bool whatsapp_dependencies_ready(const std::filesystem::path& bridge_directory); -lsp::LspSpawnOptions whatsapp_bridge_options(const std::filesystem::path& state_directory); +platform::SpawnOptions whatsapp_bridge_options(const std::filesystem::path& state_directory); } // namespace acecode::channels diff --git a/src/channels/runtime.hpp b/src/channels/runtime.hpp index 65ba3adb2..557a36c10 100644 --- a/src/channels/runtime.hpp +++ b/src/channels/runtime.hpp @@ -9,7 +9,7 @@ namespace acecode::channels { class Runtime { public: - using SpawnOptions = std::function; + using SpawnOptions = std::function; explicit Runtime(GatewayDeps deps, std::filesystem::path directory = {}, SpawnOptions spawn = {}); ~Runtime(); void start(); diff --git a/src/channels/setup.cpp b/src/channels/setup.cpp index 9eff5468d..a262bc6b4 100644 --- a/src/channels/setup.cpp +++ b/src/channels/setup.cpp @@ -46,7 +46,7 @@ bool supported_node_version(const std::string& version) { void install_whatsapp_dependencies(const std::filesystem::path& directory, const std::atomic& cancelled, const SetupProgress& progress) { - const auto node = lsp::which("node"); + const auto node = platform::which("node"); if (!node) throw std::runtime_error("Node.js 22+ was not found. Install Node.js, then retry."); HookProcessOptions options; options.timeout_ms = 5000; options.abort_flag = &cancelled; @@ -57,12 +57,12 @@ void install_whatsapp_dependencies(const std::filesystem::path& directory, throw std::runtime_error("Node.js 22+ is required. Update Node.js, then retry."); const auto installed = prepare_whatsapp_bridge(directory); if (whatsapp_dependencies_ready(installed)) return; - const auto npm = lsp::which("npm"); + const auto npm = platform::which("npm"); if (!npm) throw std::runtime_error("npm was not found. Install Node.js with npm, then retry."); if (progress) progress({SetupPhase::Installing}); options.timeout_ms = 300000; options.max_stdout_bytes = 8192; options.max_stderr_bytes = 8192; - HookCommandSpec install{*npm, {"ci", "--omit=dev", "--no-fund", "--no-audit", "--progress=false"}}; + platform::ProcessSpec install{*npm, {"ci", "--omit=dev", "--no-fund", "--no-audit", "--progress=false"}}; #ifdef _WIN32 const auto cli = path_from_utf8(*npm).parent_path() / "node_modules/npm/bin/npm-cli.js"; if (!std::filesystem::is_regular_file(cli)) diff --git a/src/channels/setup.hpp b/src/channels/setup.hpp index 37109ddd5..fcb203ced 100644 --- a/src/channels/setup.hpp +++ b/src/channels/setup.hpp @@ -33,7 +33,7 @@ struct SetupDependencies { std::chrono::milliseconds pairing_timeout{std::chrono::minutes(5)}; }; SetupDependencies default_setup_dependencies(std::filesystem::path directory = {}, - std::function spawn = {}); + std::function spawn = {}); // Runs off the UI thread. Existing configuration survives cancellation/failure. void run_setup(const std::vector& contacts, SetupDependencies deps, const std::atomic& cancelled, const SetupProgress& progress); diff --git a/src/daemon/platform.hpp b/src/daemon/platform.hpp new file mode 100644 index 000000000..a9783245a --- /dev/null +++ b/src/daemon/platform.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/process/os_process.hpp" diff --git a/src/daemon/worker.cpp b/src/daemon/worker.cpp index 89e359d93..b02088f31 100644 --- a/src/daemon/worker.cpp +++ b/src/daemon/worker.cpp @@ -803,7 +803,7 @@ int run_worker(const WorkerOptions& opts, const AppConfig& cfg) { const std::string connector_id = connector.id; connector_first_start_threads.threads.emplace_back( [hook, connector_id, &server]() { - acecode::HookCommandSpec cmd; + acecode::platform::ProcessSpec cmd; cmd.command = hook.command; cmd.args = hook.args; const acecode::HookProcessResult result = diff --git a/src/desktop/context_picker.hpp b/src/desktop/context_picker.hpp new file mode 100644 index 000000000..2e05527cf --- /dev/null +++ b/src/desktop/context_picker.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/native_ui/context_picker.hpp" diff --git a/src/desktop/custom_toast.hpp b/src/desktop/custom_toast.hpp new file mode 100644 index 000000000..2a32ef5f6 --- /dev/null +++ b/src/desktop/custom_toast.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/native_ui/custom_toast.hpp" diff --git a/src/desktop/folder_picker.hpp b/src/desktop/folder_picker.hpp new file mode 100644 index 000000000..3b0c91897 --- /dev/null +++ b/src/desktop/folder_picker.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/native_ui/folder_picker.hpp" diff --git a/src/desktop/locale.hpp b/src/desktop/locale.hpp new file mode 100644 index 000000000..b5a135d61 --- /dev/null +++ b/src/desktop/locale.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/locale.hpp" diff --git a/src/desktop/notifications.hpp b/src/desktop/notifications.hpp new file mode 100644 index 000000000..9beafb98d --- /dev/null +++ b/src/desktop/notifications.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/native_ui/notifications.hpp" diff --git a/src/desktop/notifications_backend.hpp b/src/desktop/notifications_backend.hpp new file mode 100644 index 000000000..c4c060f4f --- /dev/null +++ b/src/desktop/notifications_backend.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/native_ui/notifications_backend.hpp" diff --git a/src/desktop/open_in_explorer.hpp b/src/desktop/open_in_explorer.hpp new file mode 100644 index 000000000..cb8730f5e --- /dev/null +++ b/src/desktop/open_in_explorer.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/native_ui/open_in_explorer.hpp" diff --git a/src/desktop/strings.hpp b/src/desktop/strings.hpp new file mode 100644 index 000000000..56219685e --- /dev/null +++ b/src/desktop/strings.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/native_ui/strings.hpp" diff --git a/src/environment/terminal_resolver.cpp b/src/environment/terminal_resolver.cpp index 42e8fd969..b0135fbb0 100644 --- a/src/environment/terminal_resolver.cpp +++ b/src/environment/terminal_resolver.cpp @@ -26,7 +26,7 @@ LaunchProbe default_launch_probe(int timeout_ms) { return [timeout_ms](const std::string& program, const std::vector& args) { LaunchProbeResult out; - HookCommandSpec spec; + platform::ProcessSpec spec; spec.command = program; spec.args = args; HookProcessOptions options; diff --git a/src/environment/toolchains.cpp b/src/environment/toolchains.cpp index b186d8029..13853a3ea 100644 --- a/src/environment/toolchains.cpp +++ b/src/environment/toolchains.cpp @@ -88,7 +88,7 @@ ToolchainDetection detect_toolchains() { const std::vector extensions; #endif return detect_toolchains([&](const std::string& command) { - return lsp::which_in(command, directories, extensions, [](const std::string& file) { + return platform::which_in(command, directories, extensions, [](const std::string& file) { if (is_windows_app_execution_alias(file)) return false; std::error_code ec; if (!std::filesystem::is_regular_file(path_from_utf8(file), ec) || ec) return false; @@ -113,7 +113,7 @@ std::string find_toolchain_anchor_in_dir(const std::string& id, const std::strin return std::filesystem::is_regular_file(path_from_utf8(path), ec) && !ec; }; for (const auto& anchor : toolchain_anchor_commands(id)) { - if (auto hit = lsp::which_in(anchor, {dir}, pathext, exists)) return *hit; + if (auto hit = platform::which_in(anchor, {dir}, pathext, exists)) return *hit; } return {}; } diff --git a/src/environment/toolchains.hpp b/src/environment/toolchains.hpp index 7e130624d..4fc86f854 100644 --- a/src/environment/toolchains.hpp +++ b/src/environment/toolchains.hpp @@ -7,7 +7,7 @@ // 生成点(bash 工具、MCP stdio、hooks、LSP、控制台 PTY、worktree git)的办法 —— // 它们都直接继承 daemon 的环境,而 cpp-mcp 的 stdio transport 根本不暴露 env。 // -// 探测走 lsp::which(PATHEXT 感知),排除 Windows 商店的 app-execution alias 占位 +// 探测走 platform::which(PATHEXT 感知),排除 Windows 商店的 app-execution alias 占位 // 程序(WindowsApps\python.exe 只是个打开商店的桩,退出码 9009)。 #include "config/config.hpp" @@ -38,7 +38,7 @@ struct ToolchainDetection { }; ToolchainDetection detect_toolchains(const WhichFn& which); -ToolchainDetection detect_toolchains(); // lsp::which +ToolchainDetection detect_toolchains(); // platform::which // 在指定目录里找该工具链的锚点可执行文件(设置页状态显示用);找不到返回空串。 std::string find_toolchain_anchor_in_dir(const std::string& id, const std::string& dir); diff --git a/src/hooks/hook_config.hpp b/src/hooks/hook_config.hpp index 70ff85ebe..57331db89 100644 --- a/src/hooks/hook_config.hpp +++ b/src/hooks/hook_config.hpp @@ -1,5 +1,7 @@ #pragma once +#include "platform/process/process_runner.hpp" + #include #include #include @@ -24,12 +26,9 @@ enum class HookPlatform { Mac = 2, }; -struct HookCommandSpec { - std::string command; - std::vector args; - - bool valid() const { return !command.empty(); } -}; +// 命令规格本体已随进程运行器下沉到 platform/process/process_runner.hpp +// (refactor20260927 P2-03);hooks 内部与既有调用点沿用这个别名。 +using HookCommandSpec = platform::ProcessSpec; struct HookDefinition { std::string id; diff --git a/src/hooks/hook_runner.hpp b/src/hooks/hook_runner.hpp new file mode 100644 index 000000000..a6bcb2513 --- /dev/null +++ b/src/hooks/hook_runner.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/process/process_runner.hpp" diff --git a/src/layers.tsv b/src/layers.tsv index f25b8f614..0519a83ca 100644 --- a/src/layers.tsv +++ b/src/layers.tsv @@ -130,3 +130,23 @@ ownership_allow src/base/utils/joining_thread.hpp 1 R15:std_thread JoiningThre ownership_allow src/base/utils/joining_thread.hpp 1 R15:std_thread JoiningThreadGroup ownership/P2-01 C8 legacy worker group owner; P2-01 ownership_allow src/base/utils/abandonable_call.cpp 1 R15:std_thread abandonable_detail::start_owned_work ownership/P2-01 C8 owned abandonable worker; P2-01 ownership_allow src/base/utils/abandonable_call.cpp 1 R15:detach abandonable_detail::start_owned_work ownership/P2-01 C8 detached worker owns captured lifetime; P2-01 +exception src/base/utils/clipboard.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/clipboard.hpp; delete with the P3-02 freeze move +exception src/base/utils/open_url.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/open_url.hpp; delete with the P3-02 freeze move +exception src/base/utils/power_inhibitor.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/power_inhibitor.hpp; delete with the P3-02 freeze move +exception src/base/utils/terminal_capability.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/terminal/terminal_capability.hpp; delete with the P3-02 freeze move +exception src/base/utils/terminal_theme_detect.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/terminal/terminal_theme_detect.hpp; delete with the P3-02 freeze move +exception src/base/utils/terminal_title.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/terminal/terminal_title.hpp; delete with the P3-02 freeze move +exception src/base/utils/terminal_input.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/terminal/terminal_input.hpp; delete with the P3-02 freeze move +exception src/adapters/upgrade/console.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/terminal/console.hpp; delete with the P3-02 freeze move +exception src/domain/hooks/hook_runner.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/process/process_runner.hpp; delete with the P3-02 freeze move +exception src/adapters/lsp/lsp_process.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/process/piped_process.hpp; delete with the P3-02 freeze move +exception src/adapters/lsp/lsp_which.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/process/which.hpp; delete with the P3-02 freeze move +exception src/apps/daemon/platform.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/process/os_process.hpp; delete with the P3-02 freeze move +exception src/apps/desktop/locale.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/locale.hpp; delete with the P3-02 freeze move +exception src/apps/desktop/folder_picker.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/native_ui/folder_picker.hpp; delete with the P3-02 freeze move +exception src/apps/desktop/context_picker.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/native_ui/context_picker.hpp; delete with the P3-02 freeze move +exception src/apps/desktop/open_in_explorer.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/native_ui/open_in_explorer.hpp; delete with the P3-02 freeze move +exception src/apps/desktop/notifications.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/native_ui/notifications.hpp; delete with the P3-02 freeze move +exception src/apps/desktop/notifications_backend.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/native_ui/notifications_backend.hpp; delete with the P3-02 freeze move +exception src/apps/desktop/custom_toast.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/native_ui/custom_toast.hpp; delete with the P3-02 freeze move +exception src/apps/desktop/strings.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/native_ui/strings.hpp; delete with the P3-02 freeze move diff --git a/src/lsp/lsp_client.hpp b/src/lsp/lsp_client.hpp index 786c1ff05..b90f5f46c 100644 --- a/src/lsp/lsp_client.hpp +++ b/src/lsp/lsp_client.hpp @@ -6,7 +6,7 @@ // condvar 等应答;server→client 请求在 reader 线程内同步应答(全部是 // 轻量纯计算)。所有可变状态由 state_mu_ 保护;stdin 写由 write_mu_ 串行。 -#include "platform/process/piped_process.hpp" +#include "lsp_platform_aliases.hpp" #include #include diff --git a/src/lsp/lsp_platform_aliases.hpp b/src/lsp/lsp_platform_aliases.hpp new file mode 100644 index 000000000..10ad71fe8 --- /dev/null +++ b/src/lsp/lsp_platform_aliases.hpp @@ -0,0 +1,20 @@ +#pragma once + +// lsp 侧对 platform/process 原语的兼容别名(refactor20260927 P2-03)。 +// 子进程 spawn(原 lsp_process 的 LspProcess / LspSpawnOptions)与 PATH 探测 +// (原 lsp_which)已下沉到 platform/process,这里保留原来的 lsp:: 名字, +// lsp 内部调用点逐步改用 platform:: 名字;lsp 之外的新代码直接用 platform::。 + +#include "platform/process/piped_process.hpp" +#include "platform/process/which.hpp" + +namespace acecode::lsp { + +using LspProcess = platform::PipedProcess; +using LspSpawnOptions = platform::SpawnOptions; +using FileExistsFn = platform::FileExistsFn; +using platform::quote_windows_arg; +using platform::which; +using platform::which_in; + +} // namespace acecode::lsp diff --git a/src/lsp/lsp_process.hpp b/src/lsp/lsp_process.hpp new file mode 100644 index 000000000..628a55543 --- /dev/null +++ b/src/lsp/lsp_process.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/process/piped_process.hpp" diff --git a/src/lsp/lsp_server_registry.hpp b/src/lsp/lsp_server_registry.hpp index dd13236b0..651c910ad 100644 --- a/src/lsp/lsp_server_registry.hpp +++ b/src/lsp/lsp_server_registry.hpp @@ -7,8 +7,7 @@ // 对应条目对齐(v1 收录 clangd / typescript-language-server / pyright / // gopls / rust-analyzer)。 -#include "platform/process/piped_process.hpp" -#include "platform/process/which.hpp" +#include "lsp_platform_aliases.hpp" #include "config/config.hpp" #include diff --git a/src/lsp/lsp_which.hpp b/src/lsp/lsp_which.hpp new file mode 100644 index 000000000..5dd0d33ea --- /dev/null +++ b/src/lsp/lsp_which.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/process/which.hpp" diff --git a/src/platform/clipboard.cpp b/src/platform/clipboard.cpp index 45a027ba1..74956e65b 100644 --- a/src/platform/clipboard.cpp +++ b/src/platform/clipboard.cpp @@ -1,7 +1,7 @@ #include "clipboard.hpp" -#include "base64.hpp" -#include "encoding.hpp" +#include "utils/base64.hpp" +#include "utils/encoding.hpp" #include #include diff --git a/src/platform/native_ui/strings.cpp b/src/platform/native_ui/strings.cpp index 76dc5b577..b30251165 100644 --- a/src/platform/native_ui/strings.cpp +++ b/src/platform/native_ui/strings.cpp @@ -1,6 +1,6 @@ #include "strings.hpp" -#include "locale.hpp" +#include "platform/locale.hpp" #include #include diff --git a/src/platform/open_url.hpp b/src/platform/open_url.hpp index af1898a92..02f25c5d3 100644 --- a/src/platform/open_url.hpp +++ b/src/platform/open_url.hpp @@ -8,7 +8,7 @@ // - 默认 launcher 不经 shell(POSIX fork+execlp / Windows ShellExecuteW), // URL 原样作参数传递,无 shell 注入面;POSIX 子进程由专用 waiter 回收。 // -// 可注入 launcher 便于单测(见 tests/utils/open_url_test.cpp)。 +// 可注入 launcher 便于单测(见 tests/platform/open_url_test.cpp)。 #include #include diff --git a/src/platform/power_inhibitor.cpp b/src/platform/power_inhibitor.cpp index c3e76de12..b699c57f8 100644 --- a/src/platform/power_inhibitor.cpp +++ b/src/platform/power_inhibitor.cpp @@ -1,6 +1,6 @@ #include "power_inhibitor.hpp" -#include "logger.hpp" +#include "utils/logger.hpp" #include #include diff --git a/src/platform/process/os_process.hpp b/src/platform/process/os_process.hpp index 8e2ad5c66..3f5281eb5 100644 --- a/src/platform/process/os_process.hpp +++ b/src/platform/process/os_process.hpp @@ -1,5 +1,10 @@ #pragma once +// 操作系统进程原语(原 daemon/platform.hpp,refactor20260927 P2-03 下沉到 +// platform/process):当前 pid、脱离式 spawn、存活探测、终止、可执行文件路径。 +// 命名空间暂保留 acecode::daemon,约 20 个调用点(daemon / desktop / session / +// web / channels)逐步改名,本次只搬文件位置与 include。 + #include #include #include diff --git a/src/platform/process/os_process_posix.cpp b/src/platform/process/os_process_posix.cpp index 8e027bdab..53ee4ef00 100644 --- a/src/platform/process/os_process_posix.cpp +++ b/src/platform/process/os_process_posix.cpp @@ -1,9 +1,9 @@ // POSIX implementation of the daemon process abstraction. The whole file is -// guarded so it compiles to nothing on Windows; src/daemon/platform_windows.cpp +// guarded so it compiles to nothing on Windows; src/platform/process/os_process_windows.cpp // is the symmetric file. #ifndef _WIN32 -#include "platform.hpp" +#include "os_process.hpp" #include "utils/logger.hpp" diff --git a/src/platform/process/os_process_windows.cpp b/src/platform/process/os_process_windows.cpp index bd5d4e9c2..ad27c1b51 100644 --- a/src/platform/process/os_process_windows.cpp +++ b/src/platform/process/os_process_windows.cpp @@ -1,9 +1,9 @@ // Windows implementation of the daemon process abstraction. Symmetric with -// src/daemon/platform_posix.cpp; the entire file is guarded so it compiles +// src/platform/process/os_process_posix.cpp; the entire file is guarded so it compiles // to nothing on POSIX. #ifdef _WIN32 -#include "platform.hpp" +#include "os_process.hpp" #include "utils/logger.hpp" diff --git a/src/platform/process/piped_process.cpp b/src/platform/process/piped_process.cpp index 2e040e47e..82f7402bc 100644 --- a/src/platform/process/piped_process.cpp +++ b/src/platform/process/piped_process.cpp @@ -1,4 +1,4 @@ -#include "lsp_process.hpp" +#include "piped_process.hpp" #include "utils/logger.hpp" #include "utils/utf8_path.hpp" @@ -27,7 +27,7 @@ #include #endif -namespace acecode::lsp { +namespace acecode::platform { namespace { #ifdef _WIN32 @@ -150,11 +150,11 @@ std::string quote_windows_arg(const std::string& arg) { return out; } -LspProcess::~LspProcess() { +PipedProcess::~PipedProcess() { terminate(); } -bool LspProcess::start(const LspSpawnOptions& opts, std::string* error) { +bool PipedProcess::start(const SpawnOptions& opts, std::string* error) { if (opts.argv.empty()) { if (error) *error = "empty argv"; return false; @@ -331,7 +331,7 @@ bool LspProcess::start(const LspSpawnOptions& opts, std::string* error) { #endif } -long LspProcess::read_stdout(char* buf, std::size_t len) { +long PipedProcess::read_stdout(char* buf, std::size_t len) { #ifdef _WIN32 if (!stdout_read_) return 0; DWORD bytes_read = 0; @@ -354,7 +354,7 @@ long LspProcess::read_stdout(char* buf, std::size_t len) { #endif } -bool LspProcess::write_stdin(const char* data, std::size_t len, std::string* error) { +bool PipedProcess::write_stdin(const char* data, std::size_t len, std::string* error) { #ifdef _WIN32 if (!stdin_write_) { if (error) *error = "stdin closed"; @@ -390,7 +390,7 @@ bool LspProcess::write_stdin(const char* data, std::size_t len, std::string* err #endif } -void LspProcess::close_stdin() { +void PipedProcess::close_stdin() { #ifdef _WIN32 close_handle(stdin_write_); #else @@ -398,7 +398,7 @@ void LspProcess::close_stdin() { #endif } -bool LspProcess::wait_exit(int timeout_ms) { +bool PipedProcess::wait_exit(int timeout_ms) { #ifdef _WIN32 if (!process_handle_) return true; return WaitForSingleObject(static_cast(process_handle_), @@ -420,7 +420,7 @@ bool LspProcess::wait_exit(int timeout_ms) { #endif } -void LspProcess::kill_child() { +void PipedProcess::kill_child() { #ifdef _WIN32 if (process_handle_) TerminateProcess(static_cast(process_handle_), 0); #else @@ -428,7 +428,7 @@ void LspProcess::kill_child() { #endif } -void LspProcess::terminate() { +void PipedProcess::terminate() { #ifdef _WIN32 if (process_handle_) { TerminateProcess(static_cast(process_handle_), 0); @@ -453,4 +453,4 @@ void LspProcess::terminate() { started_ = false; } -} // namespace acecode::lsp +} // namespace acecode::platform diff --git a/src/platform/process/piped_process.hpp b/src/platform/process/piped_process.hpp index 300c16491..b6f33e31a 100644 --- a/src/platform/process/piped_process.hpp +++ b/src/platform/process/piped_process.hpp @@ -1,8 +1,10 @@ #pragma once -// LSP server 子进程:spawn(stdio 管道接管 stdin/stdout,stderr 丢弃)、 -// 阻塞读 stdout、带锁写 stdin、优雅/强制停止。架构与 -// provider/codex/codex_app_server_client 的进程段同源,差异: +// 带 stdio 管道的子进程(原 lsp/lsp_process 的 LspProcess,refactor20260927 +// P2-03 下沉到 platform/process;lsp 侧经 lsp/lsp_platform_aliases.hpp 保留 +// Lsp 前缀的别名)。LSP server 与 WhatsApp bridge 都用它:spawn(stdio 管道 +// 接管 stdin/stdout,stderr 丢弃)、阻塞读 stdout、带锁写 stdin、优雅/强制停止。 +// 架构与 provider/codex/codex_app_server_client 的进程段同源,差异: // - argv 向量 + cwd + 追加环境变量(server 定义与 config 都可注入 env) // - Windows 上 argv[0] 为 .cmd/.bat 时自动经 cmd.exe /d /c 执行 // (CreateProcess 不能直接执行批处理;npm 全局命令都是 .cmd shim) @@ -12,9 +14,9 @@ #include #include -namespace acecode::lsp { +namespace acecode::platform { -struct LspSpawnOptions { +struct SpawnOptions { // argv[0] = 可执行文件(建议为 which() 解析出的完整路径)。 std::vector argv; std::string cwd; // UTF-8;空 = 继承父进程 cwd @@ -25,14 +27,14 @@ struct LspSpawnOptions { // 暴露为自由函数以便单测。POSIX 上不使用。 std::string quote_windows_arg(const std::string& arg); -class LspProcess { +class PipedProcess { public: - LspProcess() = default; - ~LspProcess(); - LspProcess(const LspProcess&) = delete; - LspProcess& operator=(const LspProcess&) = delete; + PipedProcess() = default; + ~PipedProcess(); + PipedProcess(const PipedProcess&) = delete; + PipedProcess& operator=(const PipedProcess&) = delete; - bool start(const LspSpawnOptions& opts, std::string* error); + bool start(const SpawnOptions& opts, std::string* error); // 阻塞读 stdout。>0 = 读到的字节数;0 = EOF(子进程退出/管道关闭); // <0 = 读错误。只允许单一 reader 线程调用。 @@ -64,4 +66,4 @@ class LspProcess { bool started_ = false; }; -} // namespace acecode::lsp +} // namespace acecode::platform diff --git a/src/platform/process/process_runner.cpp b/src/platform/process/process_runner.cpp index 5592a2655..7018cb86a 100644 --- a/src/platform/process/process_runner.cpp +++ b/src/platform/process/process_runner.cpp @@ -1,4 +1,4 @@ -#include "hook_runner.hpp" +#include "process_runner.hpp" #include "utils/encoding.hpp" #include "utils/utf8_path.hpp" @@ -116,7 +116,7 @@ bool append_capped(std::string& out, return true; } -std::vector make_argv(const HookCommandSpec& command) { +std::vector make_argv(const platform::ProcessSpec& command) { std::vector argv; argv.reserve(command.args.size() + 1); argv.push_back(command.command); @@ -270,7 +270,7 @@ std::string resolve_hook_command_path(const std::string& command) { } static HookProcessResult run_hook_process_impl( - const HookCommandSpec& command, + const platform::ProcessSpec& command, const std::string& stdin_text, const std::string& cwd, const HookProcessOptions& options, @@ -773,7 +773,7 @@ static HookProcessResult run_hook_process_impl( #endif } -HookProcessResult run_hook_process(const HookCommandSpec& command, +HookProcessResult run_hook_process(const platform::ProcessSpec& command, const std::string& stdin_text, int timeout_ms, const std::string& cwd) { @@ -783,7 +783,7 @@ HookProcessResult run_hook_process(const HookCommandSpec& command, command, stdin_text, cwd, options, HookEnvironment{}, nullptr); } -HookProcessResult run_hook_process(const HookCommandSpec& command, +HookProcessResult run_hook_process(const platform::ProcessSpec& command, const std::string& stdin_text, const std::string& cwd, const HookProcessOptions& options) { @@ -796,7 +796,7 @@ HookProcessResult run_hook_shell_command(const std::string& command, int timeout_ms, const std::string& cwd, const HookEnvironment& environment) { - HookCommandSpec spec; + platform::ProcessSpec spec; #ifdef _WIN32 const char* comspec = std::getenv("COMSPEC"); spec.command = (comspec && *comspec) ? std::string(comspec) : std::string("cmd.exe"); diff --git a/src/platform/process/process_runner.hpp b/src/platform/process/process_runner.hpp index 17b0add1e..e13952b81 100644 --- a/src/platform/process/process_runner.hpp +++ b/src/platform/process/process_runner.hpp @@ -1,12 +1,28 @@ #pragma once -#include "hook_config.hpp" +// 通用子进程运行器(原 hooks/hook_runner,refactor20260927 P2-03 下沉到 +// platform/process)。hooks、grep 工具、worktree git 调用、channels 安装、 +// 终端探测都经这里 spawn 子进程;函数名暂保留 run_hook_* 形式,调用点逐步改名。 #include #include #include #include #include +#include + +namespace acecode::platform { + +// 子进程调用规格:可执行文件 + 参数向量。原为 hooks/hook_config.hpp 的 +// HookCommandSpec;hooks 侧保留同名别名,既有调用点不必改。 +struct ProcessSpec { + std::string command; + std::vector args; + + bool valid() const { return !command.empty(); } +}; + +} // namespace acecode::platform namespace acecode { @@ -49,12 +65,12 @@ struct HookProcessOptions { std::string resolve_hook_command_path(const std::string& command); -HookProcessResult run_hook_process(const HookCommandSpec& command, +HookProcessResult run_hook_process(const platform::ProcessSpec& command, const std::string& stdin_text, int timeout_ms, const std::string& cwd); -HookProcessResult run_hook_process(const HookCommandSpec& command, +HookProcessResult run_hook_process(const platform::ProcessSpec& command, const std::string& stdin_text, const std::string& cwd, const HookProcessOptions& options); diff --git a/src/platform/process/which.cpp b/src/platform/process/which.cpp index baa60e2af..5924fd99b 100644 --- a/src/platform/process/which.cpp +++ b/src/platform/process/which.cpp @@ -1,4 +1,4 @@ -#include "lsp_which.hpp" +#include "which.hpp" #include "utils/utf8_path.hpp" @@ -19,7 +19,7 @@ #include #endif -namespace acecode::lsp { +namespace acecode::platform { namespace { namespace fs = std::filesystem; @@ -153,4 +153,4 @@ std::optional which(const std::string& command) { return which_in(command, path_dirs, pathext, real_file_exists_executable); } -} // namespace acecode::lsp +} // namespace acecode::platform diff --git a/src/platform/process/which.hpp b/src/platform/process/which.hpp index a57e187fb..f2a6d7422 100644 --- a/src/platform/process/which.hpp +++ b/src/platform/process/which.hpp @@ -1,6 +1,8 @@ #pragma once -// PATH 上探测可执行文件。LSP server 只在探测命中时才会被启用,探测不到 +// PATH 上探测可执行文件(原 lsp/lsp_which,refactor20260927 P2-03 下沉到 +// platform/process;lsp 侧经 lsp/lsp_platform_aliases.hpp 保留 lsp:: 别名)。 +// LSP server / node / npm / 工具链都只在探测命中时才会被启用,探测不到 // 静默跳过 —— 所以这里的语义必须和真实 spawn 一致:Windows 按 PATHEXT // 尝试 .exe/.cmd/.bat 等扩展(npm 全局命令是 .cmd shim),POSIX 检查 // 可执行位。核心逻辑抽成可注入探针的纯函数,便于单测不依赖真实 PATH。 @@ -10,7 +12,7 @@ #include #include -namespace acecode::lsp { +namespace acecode::platform { // 文件存在性探针(true = 存在且是常规文件)。测试注入假文件系统。 using FileExistsFn = std::function; @@ -27,4 +29,4 @@ std::optional which_in(const std::string& command, // 生产入口:读取真实 PATH / PATHEXT / 文件系统。找不到返回 nullopt。 std::optional which(const std::string& command); -} // namespace acecode::lsp +} // namespace acecode::platform diff --git a/src/platform/terminal/terminal_capability.cpp b/src/platform/terminal/terminal_capability.cpp index a892b7e12..264b5ace8 100644 --- a/src/platform/terminal/terminal_capability.cpp +++ b/src/platform/terminal/terminal_capability.cpp @@ -1,6 +1,6 @@ #include "terminal_capability.hpp" -#include "logger.hpp" +#include "utils/logger.hpp" #include diff --git a/src/platform/terminal/terminal_theme_detect.cpp b/src/platform/terminal/terminal_theme_detect.cpp index 28719660e..8c210e0b2 100644 --- a/src/platform/terminal/terminal_theme_detect.cpp +++ b/src/platform/terminal/terminal_theme_detect.cpp @@ -1,6 +1,6 @@ #include "terminal_theme_detect.hpp" -#include "logger.hpp" +#include "utils/logger.hpp" #include #include diff --git a/src/platform/terminal/terminal_theme_detect_posix.cpp b/src/platform/terminal/terminal_theme_detect_posix.cpp index bd35b9ae2..82b538aa8 100644 --- a/src/platform/terminal/terminal_theme_detect_posix.cpp +++ b/src/platform/terminal/terminal_theme_detect_posix.cpp @@ -1,7 +1,7 @@ #ifndef _WIN32 #include "terminal_theme_detect.hpp" -#include "logger.hpp" +#include "utils/logger.hpp" #include #include diff --git a/src/platform/terminal/terminal_theme_detect_win.cpp b/src/platform/terminal/terminal_theme_detect_win.cpp index b16afa3fa..52b450528 100644 --- a/src/platform/terminal/terminal_theme_detect_win.cpp +++ b/src/platform/terminal/terminal_theme_detect_win.cpp @@ -1,7 +1,7 @@ #ifdef _WIN32 #include "terminal_theme_detect.hpp" -#include "logger.hpp" +#include "utils/logger.hpp" #ifndef NOMINMAX #define NOMINMAX diff --git a/src/remote_control/channel_plugin.cpp b/src/remote_control/channel_plugin.cpp index 78f83222f..3b02ade85 100644 --- a/src/remote_control/channel_plugin.cpp +++ b/src/remote_control/channel_plugin.cpp @@ -310,7 +310,7 @@ ChannelPluginHost::ChannelPluginHost(Runner runner) } ChannelPluginHost::Runner ChannelPluginHost::default_runner() { - return [](const HookCommandSpec& command, + return [](const platform::ProcessSpec& command, const std::string& stdin_text, int timeout_ms, const std::string& cwd) { @@ -327,7 +327,7 @@ ChannelPluginActivationResult ChannelPluginHost::activate( ChannelPluginActivationResult activation; if (!validate_stdio_manifest(manifest, error)) return activation; - HookCommandSpec command{manifest.command, manifest.args}; + platform::ProcessSpec command{manifest.command, manifest.args}; const std::string stdin_text = channel_activation_request_to_json(request).dump() + "\n"; HookProcessResult result = runner_(command, stdin_text, effective_timeout_ms(manifest, timeout_ms), manifest.cwd); @@ -395,7 +395,7 @@ bool ChannelPluginHost::deactivate(const ChannelPluginManifest& manifest, return fail(std::move(internal_error)); } - HookCommandSpec command{manifest.command, manifest.args}; + platform::ProcessSpec command{manifest.command, manifest.args}; const std::string stdin_text = channel_deactivation_request_to_json(session_id, binding_token).dump() + "\n"; HookProcessResult result; diff --git a/src/remote_control/channel_plugin.hpp b/src/remote_control/channel_plugin.hpp index 8ee294ac9..19c0b890a 100644 --- a/src/remote_control/channel_plugin.hpp +++ b/src/remote_control/channel_plugin.hpp @@ -71,7 +71,7 @@ bool parse_channel_plugin_status_json(const nlohmann::json& j, class ChannelPluginHost { public: - using Runner = std::function; diff --git a/src/tool/grep_tool.cpp b/src/tool/grep_tool.cpp index cb711046a..2c765293b 100644 --- a/src/tool/grep_tool.cpp +++ b/src/tool/grep_tool.cpp @@ -180,7 +180,7 @@ IgnoreProbeResult probe_explicit_ignored_directory( const std::string relative_text = path_to_utf8_generic(relative); if (relative_text.rfind("../", 0) == 0 || relative_text == "..") return probe; - HookCommandSpec command; + platform::ProcessSpec command; command.command = "git"; command.args = { "--no-pager", "check-ignore", "--no-index", "-q", "--", @@ -200,13 +200,13 @@ IgnoreProbeResult probe_explicit_ignored_directory( return probe; } -HookCommandSpec make_git_grep_command( +platform::ProcessSpec make_git_grep_command( const std::string& pattern, const std::string& include_pattern, const std::filesystem::path& search_root, bool path_is_file, bool explicit_directory_is_ignored) { - HookCommandSpec command; + platform::ProcessSpec command; command.command = "git"; command.args = {"--no-pager", "grep", "--no-index"}; if (path_is_file || explicit_directory_is_ignored) { @@ -392,7 +392,7 @@ ToolResult execute_grep(const std::string& arguments_json, const ToolContext& ct explicit_directory_is_ignored = probe.ignored; } - const HookCommandSpec command = make_git_grep_command( + const platform::ProcessSpec command = make_git_grep_command( pattern, include_pattern, search_root, path_is_file, explicit_directory_is_ignored); const auto elapsed_ms = std::chrono::duration_cast( diff --git a/src/upgrade/console.hpp b/src/upgrade/console.hpp new file mode 100644 index 000000000..185b71219 --- /dev/null +++ b/src/upgrade/console.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/terminal/console.hpp" diff --git a/src/utils/clipboard.hpp b/src/utils/clipboard.hpp new file mode 100644 index 000000000..863f1a602 --- /dev/null +++ b/src/utils/clipboard.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/clipboard.hpp" diff --git a/src/utils/open_url.hpp b/src/utils/open_url.hpp new file mode 100644 index 000000000..5f6ea3ab8 --- /dev/null +++ b/src/utils/open_url.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/open_url.hpp" diff --git a/src/utils/power_inhibitor.hpp b/src/utils/power_inhibitor.hpp new file mode 100644 index 000000000..52a565c85 --- /dev/null +++ b/src/utils/power_inhibitor.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/power_inhibitor.hpp" diff --git a/src/utils/terminal_capability.hpp b/src/utils/terminal_capability.hpp new file mode 100644 index 000000000..665f1af55 --- /dev/null +++ b/src/utils/terminal_capability.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/terminal/terminal_capability.hpp" diff --git a/src/utils/terminal_input.hpp b/src/utils/terminal_input.hpp new file mode 100644 index 000000000..167b10f8f --- /dev/null +++ b/src/utils/terminal_input.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/terminal/terminal_input.hpp" diff --git a/src/utils/terminal_theme_detect.hpp b/src/utils/terminal_theme_detect.hpp new file mode 100644 index 000000000..ebed99370 --- /dev/null +++ b/src/utils/terminal_theme_detect.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/terminal/terminal_theme_detect.hpp" diff --git a/src/utils/terminal_title.hpp b/src/utils/terminal_title.hpp new file mode 100644 index 000000000..042f925ab --- /dev/null +++ b/src/utils/terminal_title.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "platform/terminal/terminal_title.hpp" diff --git a/src/worktree/worktree_manager.cpp b/src/worktree/worktree_manager.cpp index 52bed369e..537bb8420 100644 --- a/src/worktree/worktree_manager.cpp +++ b/src/worktree/worktree_manager.cpp @@ -101,7 +101,7 @@ GitResult run_git(const std::vector& args, int timeout_ms, bool no_prompt, bool preserve_stdout_nuls) { - HookCommandSpec spec; + platform::ProcessSpec spec; spec.command = "git"; spec.args = args; diff --git a/tests/README.md b/tests/README.md index cef1f1ba5..39840b2fe 100644 --- a/tests/README.md +++ b/tests/README.md @@ -16,7 +16,7 @@ Test files live at `tests//_test.cpp`: | Production source | Test file | |--------------------------------------|------------------------------------------------| -| `src/utils/terminal_title.cpp` | `tests/utils/terminal_title_test.cpp` | +| `src/platform/terminal/terminal_title.cpp` | `tests/platform/terminal_title_test.cpp` | | `src/session/session_storage.cpp` | `tests/session/session_storage_test.cpp` | | `src/permissions.hpp` | `tests/permissions_test.cpp` | diff --git a/tests/commands/remote_control_command_test.cpp b/tests/commands/remote_control_command_test.cpp index 9793ddcc3..702507ee0 100644 --- a/tests/commands/remote_control_command_test.cpp +++ b/tests/commands/remote_control_command_test.cpp @@ -141,7 +141,7 @@ TEST(RemoteControlCommand, manifest.command = "chat-channel.exe"; const std::string token = "binding-secret-for-ui"; acecode::rc::ChannelPluginHost host( - [&](const acecode::HookCommandSpec&, const std::string&, int, + [&](const acecode::platform::ProcessSpec&, const std::string&, int, const std::string&) { acecode::HookProcessResult result; result.started = true; diff --git a/tests/cpp_source_paths.json b/tests/cpp_source_paths.json index bd1b225e9..fd11323a6 100644 --- a/tests/cpp_source_paths.json +++ b/tests/cpp_source_paths.json @@ -8,7 +8,7 @@ "desktop/agent_browser_page_directory.hpp": "src/desktop/agent_browser_page_directory.hpp", "desktop/agent_browser_runtime.cpp": "src/desktop/agent_browser_runtime.cpp", "desktop/agent_browser_runtime.hpp": "src/desktop/agent_browser_runtime.hpp", - "desktop/context_picker.cpp": "src/desktop/context_picker.cpp", + "desktop/context_picker.cpp": "src/platform/native_ui/context_picker.cpp", "desktop/main.cpp": "src/desktop/main.cpp", "desktop/splash_screen.cpp": "src/desktop/splash_screen.cpp", "desktop/startup_progress.hpp": "src/desktop/startup_progress.hpp", diff --git a/tests/platform/hook_runner_test.cpp b/tests/platform/hook_runner_test.cpp index e6cf6702c..eb4f4b0f1 100644 --- a/tests/platform/hook_runner_test.cpp +++ b/tests/platform/hook_runner_test.cpp @@ -12,7 +12,7 @@ #include TEST(HookRunner, SendsPayloadOnStdinWithZeroTimeoutAsInfinite) { - acecode::HookCommandSpec cmd; + acecode::platform::ProcessSpec cmd; #ifdef _WIN32 cmd.command = "cmd.exe"; cmd.args = {"/c", "more"}; @@ -61,7 +61,7 @@ TEST(HookRunner, ShellCommandReceivesExactEnvironmentOverride) { } TEST(HookRunner, PositiveTimeoutTerminatesLongRunningHook) { - acecode::HookCommandSpec cmd; + acecode::platform::ProcessSpec cmd; #ifdef _WIN32 cmd.command = "cmd.exe"; cmd.args = {"/c", "ping -n 3 127.0.0.1 > nul"}; @@ -76,7 +76,7 @@ TEST(HookRunner, PositiveTimeoutTerminatesLongRunningHook) { } TEST(HookRunner, BoundedOptionsAbortLongRunningProcess) { - acecode::HookCommandSpec cmd; + acecode::platform::ProcessSpec cmd; #ifdef _WIN32 cmd.command = "cmd.exe"; cmd.args = {"/d", "/s", "/c", "ping -n 6 127.0.0.1 > nul"}; @@ -108,7 +108,7 @@ TEST(HookRunner, BoundedOptionsAbortLongRunningProcess) { } TEST(HookRunner, BoundedOptionsStopAtStdoutLineLimit) { - acecode::HookCommandSpec cmd; + acecode::platform::ProcessSpec cmd; #ifdef _WIN32 cmd.command = "powershell.exe"; cmd.args = {"-NoLogo", "-NoProfile", "-NonInteractive", "-Command", @@ -143,7 +143,7 @@ TEST(HookRunner, BoundedOptionsStopAtStdoutLineLimit) { } TEST(HookRunner, BoundedOptionsCapStdoutWithoutProtocolMarker) { - acecode::HookCommandSpec cmd; + acecode::platform::ProcessSpec cmd; #ifdef _WIN32 cmd.command = "cmd.exe"; cmd.args = {"/d", "/s", "/c", " events_seen; std::vector cwd_seen; acecode::HookManager manager(std::move(cfg), - [&](const acecode::HookCommandSpec& command, + [&](const acecode::platform::ProcessSpec& command, const std::string& stdin_text, int timeout_ms, const std::string& cwd) -> acecode::HookProcessResult { diff --git a/tests/platform/lsp_which_test.cpp b/tests/platform/lsp_which_test.cpp index 7e89c9bb1..9f87642e2 100644 --- a/tests/platform/lsp_which_test.cpp +++ b/tests/platform/lsp_which_test.cpp @@ -1,4 +1,4 @@ -// 覆盖 src/lsp/lsp_which.{hpp,cpp}:PATH 可执行探测的纯逻辑核心 which_in()。 +// 覆盖 src/platform/process/which.{hpp,cpp}(原 src/lsp/lsp_which):PATH 可执行探测的纯逻辑核心 which_in()。 // // LSP server 只在探测命中时启用,探测语义必须与真实 spawn 一致 —— // 尤其 Windows 上 npm 全局命令是 .cmd shim,漏掉 PATHEXT 拼接会导致 @@ -21,14 +21,14 @@ #include #include -using acecode::lsp::which_in; +using acecode::platform::which_in; namespace { // 真实文件系统在 Windows 上大小写不敏感、'/'与'\\'等价;fake 探针把两者 // 都归一(全小写 + '/'),否则 PATHEXT 大写扩展(.CMD)拼出的候选永远 // 匹配不上小写测试数据 —— 这不是产线语义,是测试替身该抹平的差异。 -acecode::lsp::FileExistsFn fake_fs(std::set files) { +acecode::platform::FileExistsFn fake_fs(std::set files) { auto canon = [](std::string p) { std::replace(p.begin(), p.end(), '\\', '/'); std::transform(p.begin(), p.end(), p.begin(), [](unsigned char c) { diff --git a/tests/platform/open_url_test.cpp b/tests/platform/open_url_test.cpp index 0ec210aa9..782a35d3e 100644 --- a/tests/platform/open_url_test.cpp +++ b/tests/platform/open_url_test.cpp @@ -1,4 +1,4 @@ -// 覆盖 src/utils/open_url.cpp 的 URL 打开(add-tui-hyperlinks 5.1/5.4)。 +// 覆盖 src/platform/open_url.cpp 的 URL 打开(add-tui-hyperlinks 5.1/5.4)。 // // 关键保证: // - 仅 http/https 放行;控制字符(ESC 注入)/前导空白/其它 scheme 拒绝; diff --git a/tests/platform/terminal_capability_test.cpp b/tests/platform/terminal_capability_test.cpp index ac636d696..30d9402f2 100644 --- a/tests/platform/terminal_capability_test.cpp +++ b/tests/platform/terminal_capability_test.cpp @@ -1,4 +1,4 @@ -// 覆盖 src/utils/terminal_capability.cpp 中 +// 覆盖 src/platform/terminal/terminal_capability.cpp 中 // detect_terminal_capabilities_with() 的纯函数行为。所有 case 走依赖注入, // 不依赖真实 getenv 或 RtlGetVersion,跨平台稳定。 // diff --git a/tests/platform/terminal_title_test.cpp b/tests/platform/terminal_title_test.cpp index 2b14477d1..f3374bfc9 100644 --- a/tests/platform/terminal_title_test.cpp +++ b/tests/platform/terminal_title_test.cpp @@ -1,4 +1,4 @@ -// 覆盖 src/utils/terminal_title.cpp 的 sanitize_title: +// 覆盖 src/platform/terminal/terminal_title.cpp 的 sanitize_title: // - 合法 ASCII / UTF-8 必须原样通过 // - 任何 C0 控制字符(含换行/制表)必须被拒绝 // - 超长输入必须按 UTF-8 边界安全截断,不留半字符 diff --git a/tests/pty/pty_backend_test.cpp b/tests/pty/pty_backend_test.cpp index 54028618f..eb37f9394 100644 --- a/tests/pty/pty_backend_test.cpp +++ b/tests/pty/pty_backend_test.cpp @@ -1,4 +1,4 @@ -// 覆盖 src/web/pty/ 的后端抽象(openspec/changes/add-console-dock 任务 2.x): +// 覆盖 src/pty/ 的后端抽象(openspec/changes/add-console-dock 任务 2.x): // - resolve_console_shell 纯函数(配置覆盖 / 平台默认) // - pty_backend_kind_name 协议字符串稳定性(进 /api/health 与 session info, // 前端依赖这些字面量做降级提示判断,改名即破坏协议) diff --git a/tests/pty/pty_session_registry_test.cpp b/tests/pty/pty_session_registry_test.cpp index b88f3afcd..d14c423f1 100644 --- a/tests/pty/pty_session_registry_test.cpp +++ b/tests/pty/pty_session_registry_test.cpp @@ -1,4 +1,4 @@ -// 覆盖 src/web/pty/pty_session_registry.{hpp,cpp} +// 覆盖 src/pty/pty_session_registry.{hpp,cpp} // (openspec/changes/add-console-dock 任务 3.5,specs/console-pty-backend): // - 控制帧编码(0x00 前缀,前端按首字节分流,编错即前端把 JSON 当 VT 渲染) // - 缓冲游标续传:cursor=N 重连补发 N 之后的字节、溢出丢最旧、cursor 控制帧 diff --git a/tests/remote_control/channel_plugin_test.cpp b/tests/remote_control/channel_plugin_test.cpp index 3487c3b44..390a7407e 100644 --- a/tests/remote_control/channel_plugin_test.cpp +++ b/tests/remote_control/channel_plugin_test.cpp @@ -8,7 +8,7 @@ #include #include -using acecode::HookCommandSpec; +using acecode::platform::ProcessSpec; using acecode::HookProcessResult; using acecode::rc::ChannelActivationRequest; using acecode::rc::ChannelPluginHost; @@ -165,10 +165,10 @@ TEST(ChannelPluginHost, ActivatesAndAcceptsAlreadyRunningRuntime) { manifest.cwd = "C:/plugins/chat"; std::string seen_stdin; - HookCommandSpec seen_command; + ProcessSpec seen_command; int seen_timeout = 0; std::string seen_cwd; - ChannelPluginHost host([&](const HookCommandSpec& command, + ChannelPluginHost host([&](const ProcessSpec& command, const std::string& stdin_text, int timeout_ms, const std::string& cwd) { @@ -214,7 +214,7 @@ TEST(ChannelPluginHost, ReportsPluginFailure) { manifest.name = "chat"; manifest.command = "chat-channel.exe"; - ChannelPluginHost host([](const HookCommandSpec&, + ChannelPluginHost host([](const ProcessSpec&, const std::string&, int, const std::string&) { @@ -243,7 +243,7 @@ TEST(ChannelPluginHost, DeactivationEchoesCurrentBindingToken) { manifest.command = "chat-channel.exe"; std::vector requests; - ChannelPluginHost host([&](const HookCommandSpec&, + ChannelPluginHost host([&](const ProcessSpec&, const std::string& stdin_text, int, const std::string&) { @@ -296,7 +296,7 @@ TEST(ChannelPluginHost, RedactsBindingTokenFromDeactivationFailures) { }; expect_redacted( - [&](const HookCommandSpec&, const std::string&, int, + [&](const ProcessSpec&, const std::string&, int, const std::string&) { HookProcessResult result; result.error = "runner launch rejected token " + token; @@ -305,7 +305,7 @@ TEST(ChannelPluginHost, RedactsBindingTokenFromDeactivationFailures) { "runner launch rejected"); expect_redacted( - [&](const HookCommandSpec&, const std::string&, int, + [&](const ProcessSpec&, const std::string&, int, const std::string&) { HookProcessResult result; result.started = true; @@ -316,7 +316,7 @@ TEST(ChannelPluginHost, RedactsBindingTokenFromDeactivationFailures) { "stderr rejected"); expect_redacted( - [](const HookCommandSpec&, const std::string& stdin_text, int, + [](const ProcessSpec&, const std::string& stdin_text, int, const std::string&) { HookProcessResult result; result.started = true; @@ -327,7 +327,7 @@ TEST(ChannelPluginHost, RedactsBindingTokenFromDeactivationFailures) { "channel.deactivate"); expect_redacted( - [&](const HookCommandSpec&, const std::string&, int, + [&](const ProcessSpec&, const std::string&, int, const std::string&) { HookProcessResult result; result.started = true; @@ -343,7 +343,7 @@ TEST(ChannelPluginHost, RedactsBindingTokenFromDeactivationFailures) { "status rejected"); expect_redacted( - [&](const HookCommandSpec&, const std::string&, int, + [&](const ProcessSpec&, const std::string&, int, const std::string&) -> HookProcessResult { throw std::runtime_error( "runner exception echoed token " + token); @@ -351,7 +351,7 @@ TEST(ChannelPluginHost, RedactsBindingTokenFromDeactivationFailures) { "runner exception echoed"); expect_redacted( - [&](const HookCommandSpec&, const std::string&, int, + [&](const ProcessSpec&, const std::string&, int, const std::string&) { HookProcessResult result; result.started = true; @@ -372,7 +372,7 @@ TEST(ChannelPluginHost, PreservesLegacyDeactivationDiagnostic) { manifest.command = "chat-channel.exe"; ChannelPluginHost host( - [](const HookCommandSpec&, const std::string&, int, + [](const ProcessSpec&, const std::string&, int, const std::string&) { HookProcessResult result; result.error = "legacy detach rejected: retry manually"; diff --git a/tests/remote_control/session_channel_binder_test.cpp b/tests/remote_control/session_channel_binder_test.cpp index 1682ef3e6..b84cb077f 100644 --- a/tests/remote_control/session_channel_binder_test.cpp +++ b/tests/remote_control/session_channel_binder_test.cpp @@ -571,7 +571,7 @@ struct RunnerLog { acecode::rc::ChannelPluginHost::Runner make_fake_runner( std::shared_ptr log, std::string outbound_url) { return [log = std::move(log), outbound_url = std::move(outbound_url)]( - const acecode::HookCommandSpec&, const std::string& stdin_text, + const acecode::platform::ProcessSpec&, const std::string& stdin_text, int, const std::string&) { acecode::HookProcessResult result; result.started = true; diff --git a/tests/test_support/channels/test_support.hpp b/tests/test_support/channels/test_support.hpp index d902aecbf..0addba0b4 100644 --- a/tests/test_support/channels/test_support.hpp +++ b/tests/test_support/channels/test_support.hpp @@ -89,7 +89,7 @@ inline std::filesystem::path temporary(const std::string& suffix) { // 之后不再与它同目录:按 __FILE__ 同目录定位会指向不存在的脚本,node 立刻退出,10 个 // Channel* 用例全部报「WhatsApp bridge exited」。改为从仓库根定位(P0-05 的约定), // 夹具与 helper 头各自搬家都不受影响。 -inline lsp::LspSpawnOptions fake_bridge(const std::filesystem::path&) { +inline platform::SpawnOptions fake_bridge(const std::filesystem::path&) { const auto script = acecode::test_support::find_repo_root(__FILE__) / "tests" / "channels" / "fake_bridge.mjs"; return {{"node", path_to_utf8(script)}, {}, {}}; } From be02de476838cbf712f885c2ad4c7532f396322a Mon Sep 17 00:00:00 2001 From: tmoonlight Date: Sun, 27 Sep 2026 17:40:53 +0800 Subject: [PATCH 4/8] =?UTF-8?q?refactor20260927(layers/P2-03):=20validate?= =?UTF-8?q?=5Fmap=20=E8=AF=86=E5=88=AB=20P2=20=E8=BD=AC=E5=8F=91=E5=A4=B4;?= =?UTF-8?q?migrate=5Fbranch=20--check=20=E7=94=A8=E4=BE=8B=E7=9A=84?= =?UTF-8?q?=E5=A4=B9=E5=85=B7=E4=B8=8D=E7=BB=A7=E6=89=BF=E8=BF=87=E6=B8=A1?= =?UTF-8?q?=E6=9C=9F=20exception=20=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 两处工具修正,都是 P2 转发头登记后才暴露的: - validate_map.py:旧路径上的 2 行转发头与搬走的文件经映射表落到同一最终路径,原碰撞检查把它报成「case-insensitive destination collision」,--strict 直接失败(P2-03 实测 24 项)。现在按内容识别转发头(恰为 `#pragma once` + 一行 include,且该 include 解析到的文件与自己同目标),列进报告的 forwarding_headers 而不计入碰撞;旧路径上若是一份真实内容的重复文件仍报碰撞。inspect() 新增可选 root 参数,migrate_branch 的纯清单调用不传 root 时行为不变。 - tests/test_migrate_branch.py::test_check_enforces_final_layout_lint_ownership_seed_and_paths_without_writing 把仓库真实的 src/layers.tsv 原样拷进「最终布局」夹具,而 --check 按 strict 语义要求 exceptions 表为空,P2 登记的每条转发头 exception 都变成一条 R13,用例随 P2 分支进度失败。夹具改为只取 exception 之外的行。 验证:scripts/refactor/tests 新增 test_p2_forwarding_header_is_not_a_destination_collision(正例 / 无 root / 非转发头的重复文件三段);unittest discover 全量通过;本树 validate_map --strict exit 0,forwarding_headers 20 项。 --- scripts/refactor/tests/test_guards.py | 24 +++++++++++ scripts/refactor/tests/test_migrate_branch.py | 9 +++- scripts/refactor/validate_map.py | 41 ++++++++++++++++--- 3 files changed, 68 insertions(+), 6 deletions(-) diff --git a/scripts/refactor/tests/test_guards.py b/scripts/refactor/tests/test_guards.py index 2fc2c7d41..2b4305421 100644 --- a/scripts/refactor/tests/test_guards.py +++ b/scripts/refactor/tests/test_guards.py @@ -264,6 +264,30 @@ def test_map_rejects_collisions_and_unsafe_prefixes(self): self.assertTrue(any("collision" in f["message"] for f in report["findings"])) self.assertEqual("src/tool_preamble/a.cpp", mapping.translate("src/tool_preamble/a.cpp")) + def test_p2_forwarding_header_is_not_a_destination_collision(self): + # 触发场景:P2 把 src/utils/clipboard.hpp 搬到过渡目录 src/platform/,旧路径按设计留 2 行转发头。 + # 两个文件经映射表都落到 src/base/platform/clipboard.hpp,旧的碰撞检查会把转发头当成 + # 「大小写折叠后写到同一目标」的第二个源,validate_map --strict 直接报错。 + # 期望:内容恰为 `#pragma once` + 一行 include、且 include 解析到的文件与自己同目标的旧头 + # 被识别为转发头,列进 forwarding_headers 而不是 findings;旧路径上若是一份真实内容的 + # 重复文件(不是转发头),仍然报碰撞,搬迁时不能静默覆盖。 + mapping = LayoutMap([ + {"old_path": "src/utils/clipboard.hpp", "new_path": "src/base/platform/clipboard.hpp", "kind": "move", "phase": "P2-03"}, + {"old_path": "src/utils/", "new_path": "src/base/utils/", "kind": "move", "phase": "P3"}, + {"old_path": "src/platform/", "new_path": "src/base/platform/", "kind": "move", "phase": "P3"}, + ]) + self.write("src/platform/clipboard.hpp", b"#pragma once\r\nnamespace acecode::platform { bool copy(); }\r\n") + self.write("src/utils/clipboard.hpp", b'#pragma once\n#include "platform/clipboard.hpp"\n') + report = validate_map(self.files, mapping, root=self.root) + self.assertFalse([f for f in report["findings"] if "collision" in f["message"]], report["findings"]) + self.assertEqual([{"path": "src/utils/clipboard.hpp", "target": "src/platform/clipboard.hpp", "destination": "src/base/platform/clipboard.hpp"}], report["forwarding_headers"]) + # 没有仓库根(migrate_branch 的纯清单调用)时不读文件内容,行为与改动前相同:仍按碰撞报告。 + self.assertTrue(any("collision" in f["message"] for f in validate_map(self.files, mapping)["findings"])) + self.write("src/utils/clipboard.hpp", b"#pragma once\n#include \"platform/clipboard.hpp\"\nnamespace acecode { int extra; }\n") + report = validate_map(self.files, mapping, root=self.root) + self.assertTrue(any("collision" in f["message"] for f in report["findings"])) + self.assertEqual([], report["forwarding_headers"]) + def test_line_partition_detects_loss_duplication_and_wrong_destination(self): # 拆分后丢行、重叠映射或目标内容不符都不能用“已映射”蒙混通过。 self.write("src/original.cpp", b"one\r\ntwo\nthree\n") diff --git a/scripts/refactor/tests/test_migrate_branch.py b/scripts/refactor/tests/test_migrate_branch.py index 65a7be705..7ede52bfc 100644 --- a/scripts/refactor/tests/test_migrate_branch.py +++ b/scripts/refactor/tests/test_migrate_branch.py @@ -353,7 +353,14 @@ def test_check_enforces_final_layout_lint_ownership_seed_and_paths_without_writi self.write("README.md", b"Final source: src/base/utils/file.cpp\n") self.write("src/base/utils/file.cpp", b"// final fixture\n") for path in ("src/layers.tsv", "scripts/layers/ownership_baseline.json", "scripts/layers/size_baseline.txt", "scripts/refactor/src_layout_map.tsv"): - self.write(path, (HERE.parent.parent / path).read_bytes()) + data = (HERE.parent.parent / path).read_bytes() + if path == "src/layers.tsv": + # 本用例模拟的是冻结后的最终布局,--check 按 strict 语义要求 exceptions 表为空(P4-01)。 + # P2 期间仓库真实的 layers.tsv 会登记转发头 exception 行(冻结日到期删除),原样拷进 + # 夹具会让每一行都变成 R13「strict mode requires an empty exceptions table」, + # 用例就随 P2 分支的进度失败,而不是在检查 --check 自身。夹具只取过渡期之外的行。 + data = b"".join(line for line in data.splitlines(keepends=True) if not line.startswith(b"exception\t")) + self.write(path, data) self.commit("complete final fixture") before = git(self.root, "status", "--porcelain=v1") report = check(self.root, self.map) diff --git a/scripts/refactor/validate_map.py b/scripts/refactor/validate_map.py index 994c9f15d..e65925be6 100644 --- a/scripts/refactor/validate_map.py +++ b/scripts/refactor/validate_map.py @@ -5,14 +5,41 @@ import argparse from collections import defaultdict from pathlib import Path, PurePosixPath +import re -from layout import LayoutMap, load_policy, read_tsv +from layout import IncludeIndex, LayoutMap, load_policy, read_tsv from repo_files import emit_json, repo_root, tracked_files +# P2 forwarding header: exactly `#pragma once` plus one quoted include (design.md +# "迁移机制"). It stays at the old path until the P3-02 freeze deletes it. +FORWARDING_HEADER = re.compile(rb'\A#pragma once\r?\n[ \t]*#[ \t]*include[ \t]*"([^"\r\n]+)"[ \t]*\r?\n?\Z') -def inspect(files: list[str], mapping: LayoutMap, policy=None) -> dict: - findings, dormant = [], [] + +def forwarding_target(root: Path | None, path: str, mapping: LayoutMap, index: IncludeIndex) -> str | None: + """Return the relocated file a P2 forwarding stub points at, or None. + + A stub is recognised by content, not by name: the old header holds only the + two forwarding lines and its include resolves to exactly one other tracked + file which the map sends to the same final destination. Both files therefore + describe one relocated header, so the pair is not a destination collision. + """ + if root is None or not path.startswith("src/") or not path.endswith((".hpp", ".h")): + return None + match = FORWARDING_HEADER.match((root / path).read_bytes()) + if not match: + return None + targets = index.resolve(path, match[1].decode("utf-8", "replace")) + if len(targets) != 1 or targets[0] == path or targets[0].startswith("@generated/"): + return None + if mapping.translate(targets[0]) != mapping.translate(path): + return None + return targets[0] + + +def inspect(files: list[str], mapping: LayoutMap, policy=None, root: Path | None = None) -> dict: + findings, dormant, forwarding = [], [], [] destinations, basenames = defaultdict(list), defaultdict(list) + index = IncludeIndex(files, aliases=mapping) keys = set() for row in mapping.rows: old, new, kind = row["old_path"], row["new_path"], row["kind"] @@ -37,6 +64,10 @@ def inspect(files: list[str], mapping: LayoutMap, policy=None) -> dict: destination = mapping.translate(path) if destination is None: continue + target = forwarding_target(root, path, mapping, index) + if target is not None: + forwarding.append({"path": path, "target": target, "destination": destination}) + continue destinations[destination.casefold()].append(path) if path.startswith("src/"): basenames[PurePosixPath(destination).name.casefold()].append(destination) @@ -45,7 +76,7 @@ def inspect(files: list[str], mapping: LayoutMap, policy=None) -> dict: for destination, sources in destinations.items(): if len(sources) > 1: findings.append({"destination": destination, "sources": sources, "message": "case-insensitive destination collision"}) - return {"schema": 1, "mapped_files": sum(mapping.translate(p) != p for p in files), "findings": findings, "planned_or_obsolete_rows": dormant, "duplicate_basenames": {name: sorted(set(paths)) for name, paths in sorted(basenames.items()) if len(set(paths)) > 1}} + return {"schema": 1, "mapped_files": sum(mapping.translate(p) != p for p in files), "findings": findings, "forwarding_headers": forwarding, "planned_or_obsolete_rows": dormant, "duplicate_basenames": {name: sorted(set(paths)) for name, paths in sorted(basenames.items()) if len(set(paths)) > 1}} def main() -> int: @@ -56,7 +87,7 @@ def main() -> int: parser.add_argument("--output") args = parser.parse_args() root = repo_root(args.repo) - report = inspect(tracked_files(root), LayoutMap(read_tsv(root / args.map)), load_policy(root)) + report = inspect(tracked_files(root), LayoutMap(read_tsv(root / args.map)), load_policy(root), root) emit_json(report, args.output) return int(args.strict and bool(report["findings"])) From c69f91c697934eab8d36343798a2071fd7a1506a Mon Sep 17 00:00:00 2001 From: tmoonlight Date: Sun, 27 Sep 2026 21:10:59 +0800 Subject: [PATCH 5/8] =?UTF-8?q?refactor20260927(layers/P2-03):=20=E6=8C=89?= =?UTF-8?q?=20D24=20=E5=88=A0=E9=99=A4=2020=20=E4=B8=AA=E8=BD=AC=E5=8F=91?= =?UTF-8?q?=E5=A4=B4=E4=B8=8E=20layers.tsv=20=E7=9A=84=20exception=20?= =?UTF-8?q?=E8=A1=8C,=E5=9B=9E=E9=80=80=E8=BD=AC=E5=8F=91=E5=A4=B4?= =?UTF-8?q?=E8=AF=86=E5=88=AB=E7=9A=84=E5=B7=A5=E5=85=B7=E6=94=B9=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主代理 2026-09-27 决策 D24:P2 各任务不在旧路径留 2 行转发头、不往 layers.tsv 加 exception 行 —— 映射表的精确行会把转发头与已搬走的真文件映射到同一最终路径,validate_map --strict 与 migrate_branch --check 都报 destination collision;include 改写已由 normalize_includes(本树)与 migrate_branch --apply-map(遗留分支)按映射表完成,转发头没有独立价值。 - 删除 de834f51 加的 20 个转发头(utils 7、upgrade 1、hooks 1、lsp 2、daemon 1、desktop 8);搬走的 .hpp 旧路径不再留任何文件。src/web/pty/ 本来就没留(见 de834f51 说明)。 - src/layers.tsv 删掉 20 条 exception 行,恢复到 master 的内容。 - 回退 be02de47:validate_map 的转发头识别与 test_migrate_branch 夹具改动都是为转发头服务的,D24 之后无需保留;scripts/refactor 与 master 完全一致。 验证:全仓 grep 旧路径 include 0 处;check_layers --enforce-parent-includes 160(161 - 1);validate_map --strict exit 0;normalize_includes --check src/tests exit 0;check_doc_paths 85;check_file_size / check_ownership --strict exit 0。 --- scripts/refactor/tests/test_guards.py | 24 ----------- scripts/refactor/tests/test_migrate_branch.py | 9 +--- scripts/refactor/validate_map.py | 41 +++---------------- src/daemon/platform.hpp | 2 - src/desktop/context_picker.hpp | 2 - src/desktop/custom_toast.hpp | 2 - src/desktop/folder_picker.hpp | 2 - src/desktop/locale.hpp | 2 - src/desktop/notifications.hpp | 2 - src/desktop/notifications_backend.hpp | 2 - src/desktop/open_in_explorer.hpp | 2 - src/desktop/strings.hpp | 2 - src/hooks/hook_runner.hpp | 2 - src/layers.tsv | 20 --------- src/lsp/lsp_process.hpp | 2 - src/lsp/lsp_which.hpp | 2 - src/upgrade/console.hpp | 2 - src/utils/clipboard.hpp | 2 - src/utils/open_url.hpp | 2 - src/utils/power_inhibitor.hpp | 2 - src/utils/terminal_capability.hpp | 2 - src/utils/terminal_input.hpp | 2 - src/utils/terminal_theme_detect.hpp | 2 - src/utils/terminal_title.hpp | 2 - 24 files changed, 6 insertions(+), 128 deletions(-) delete mode 100644 src/daemon/platform.hpp delete mode 100644 src/desktop/context_picker.hpp delete mode 100644 src/desktop/custom_toast.hpp delete mode 100644 src/desktop/folder_picker.hpp delete mode 100644 src/desktop/locale.hpp delete mode 100644 src/desktop/notifications.hpp delete mode 100644 src/desktop/notifications_backend.hpp delete mode 100644 src/desktop/open_in_explorer.hpp delete mode 100644 src/desktop/strings.hpp delete mode 100644 src/hooks/hook_runner.hpp delete mode 100644 src/lsp/lsp_process.hpp delete mode 100644 src/lsp/lsp_which.hpp delete mode 100644 src/upgrade/console.hpp delete mode 100644 src/utils/clipboard.hpp delete mode 100644 src/utils/open_url.hpp delete mode 100644 src/utils/power_inhibitor.hpp delete mode 100644 src/utils/terminal_capability.hpp delete mode 100644 src/utils/terminal_input.hpp delete mode 100644 src/utils/terminal_theme_detect.hpp delete mode 100644 src/utils/terminal_title.hpp diff --git a/scripts/refactor/tests/test_guards.py b/scripts/refactor/tests/test_guards.py index 2b4305421..2fc2c7d41 100644 --- a/scripts/refactor/tests/test_guards.py +++ b/scripts/refactor/tests/test_guards.py @@ -264,30 +264,6 @@ def test_map_rejects_collisions_and_unsafe_prefixes(self): self.assertTrue(any("collision" in f["message"] for f in report["findings"])) self.assertEqual("src/tool_preamble/a.cpp", mapping.translate("src/tool_preamble/a.cpp")) - def test_p2_forwarding_header_is_not_a_destination_collision(self): - # 触发场景:P2 把 src/utils/clipboard.hpp 搬到过渡目录 src/platform/,旧路径按设计留 2 行转发头。 - # 两个文件经映射表都落到 src/base/platform/clipboard.hpp,旧的碰撞检查会把转发头当成 - # 「大小写折叠后写到同一目标」的第二个源,validate_map --strict 直接报错。 - # 期望:内容恰为 `#pragma once` + 一行 include、且 include 解析到的文件与自己同目标的旧头 - # 被识别为转发头,列进 forwarding_headers 而不是 findings;旧路径上若是一份真实内容的 - # 重复文件(不是转发头),仍然报碰撞,搬迁时不能静默覆盖。 - mapping = LayoutMap([ - {"old_path": "src/utils/clipboard.hpp", "new_path": "src/base/platform/clipboard.hpp", "kind": "move", "phase": "P2-03"}, - {"old_path": "src/utils/", "new_path": "src/base/utils/", "kind": "move", "phase": "P3"}, - {"old_path": "src/platform/", "new_path": "src/base/platform/", "kind": "move", "phase": "P3"}, - ]) - self.write("src/platform/clipboard.hpp", b"#pragma once\r\nnamespace acecode::platform { bool copy(); }\r\n") - self.write("src/utils/clipboard.hpp", b'#pragma once\n#include "platform/clipboard.hpp"\n') - report = validate_map(self.files, mapping, root=self.root) - self.assertFalse([f for f in report["findings"] if "collision" in f["message"]], report["findings"]) - self.assertEqual([{"path": "src/utils/clipboard.hpp", "target": "src/platform/clipboard.hpp", "destination": "src/base/platform/clipboard.hpp"}], report["forwarding_headers"]) - # 没有仓库根(migrate_branch 的纯清单调用)时不读文件内容,行为与改动前相同:仍按碰撞报告。 - self.assertTrue(any("collision" in f["message"] for f in validate_map(self.files, mapping)["findings"])) - self.write("src/utils/clipboard.hpp", b"#pragma once\n#include \"platform/clipboard.hpp\"\nnamespace acecode { int extra; }\n") - report = validate_map(self.files, mapping, root=self.root) - self.assertTrue(any("collision" in f["message"] for f in report["findings"])) - self.assertEqual([], report["forwarding_headers"]) - def test_line_partition_detects_loss_duplication_and_wrong_destination(self): # 拆分后丢行、重叠映射或目标内容不符都不能用“已映射”蒙混通过。 self.write("src/original.cpp", b"one\r\ntwo\nthree\n") diff --git a/scripts/refactor/tests/test_migrate_branch.py b/scripts/refactor/tests/test_migrate_branch.py index 7ede52bfc..65a7be705 100644 --- a/scripts/refactor/tests/test_migrate_branch.py +++ b/scripts/refactor/tests/test_migrate_branch.py @@ -353,14 +353,7 @@ def test_check_enforces_final_layout_lint_ownership_seed_and_paths_without_writi self.write("README.md", b"Final source: src/base/utils/file.cpp\n") self.write("src/base/utils/file.cpp", b"// final fixture\n") for path in ("src/layers.tsv", "scripts/layers/ownership_baseline.json", "scripts/layers/size_baseline.txt", "scripts/refactor/src_layout_map.tsv"): - data = (HERE.parent.parent / path).read_bytes() - if path == "src/layers.tsv": - # 本用例模拟的是冻结后的最终布局,--check 按 strict 语义要求 exceptions 表为空(P4-01)。 - # P2 期间仓库真实的 layers.tsv 会登记转发头 exception 行(冻结日到期删除),原样拷进 - # 夹具会让每一行都变成 R13「strict mode requires an empty exceptions table」, - # 用例就随 P2 分支的进度失败,而不是在检查 --check 自身。夹具只取过渡期之外的行。 - data = b"".join(line for line in data.splitlines(keepends=True) if not line.startswith(b"exception\t")) - self.write(path, data) + self.write(path, (HERE.parent.parent / path).read_bytes()) self.commit("complete final fixture") before = git(self.root, "status", "--porcelain=v1") report = check(self.root, self.map) diff --git a/scripts/refactor/validate_map.py b/scripts/refactor/validate_map.py index e65925be6..994c9f15d 100644 --- a/scripts/refactor/validate_map.py +++ b/scripts/refactor/validate_map.py @@ -5,41 +5,14 @@ import argparse from collections import defaultdict from pathlib import Path, PurePosixPath -import re -from layout import IncludeIndex, LayoutMap, load_policy, read_tsv +from layout import LayoutMap, load_policy, read_tsv from repo_files import emit_json, repo_root, tracked_files -# P2 forwarding header: exactly `#pragma once` plus one quoted include (design.md -# "迁移机制"). It stays at the old path until the P3-02 freeze deletes it. -FORWARDING_HEADER = re.compile(rb'\A#pragma once\r?\n[ \t]*#[ \t]*include[ \t]*"([^"\r\n]+)"[ \t]*\r?\n?\Z') - -def forwarding_target(root: Path | None, path: str, mapping: LayoutMap, index: IncludeIndex) -> str | None: - """Return the relocated file a P2 forwarding stub points at, or None. - - A stub is recognised by content, not by name: the old header holds only the - two forwarding lines and its include resolves to exactly one other tracked - file which the map sends to the same final destination. Both files therefore - describe one relocated header, so the pair is not a destination collision. - """ - if root is None or not path.startswith("src/") or not path.endswith((".hpp", ".h")): - return None - match = FORWARDING_HEADER.match((root / path).read_bytes()) - if not match: - return None - targets = index.resolve(path, match[1].decode("utf-8", "replace")) - if len(targets) != 1 or targets[0] == path or targets[0].startswith("@generated/"): - return None - if mapping.translate(targets[0]) != mapping.translate(path): - return None - return targets[0] - - -def inspect(files: list[str], mapping: LayoutMap, policy=None, root: Path | None = None) -> dict: - findings, dormant, forwarding = [], [], [] +def inspect(files: list[str], mapping: LayoutMap, policy=None) -> dict: + findings, dormant = [], [] destinations, basenames = defaultdict(list), defaultdict(list) - index = IncludeIndex(files, aliases=mapping) keys = set() for row in mapping.rows: old, new, kind = row["old_path"], row["new_path"], row["kind"] @@ -64,10 +37,6 @@ def inspect(files: list[str], mapping: LayoutMap, policy=None, root: Path | None destination = mapping.translate(path) if destination is None: continue - target = forwarding_target(root, path, mapping, index) - if target is not None: - forwarding.append({"path": path, "target": target, "destination": destination}) - continue destinations[destination.casefold()].append(path) if path.startswith("src/"): basenames[PurePosixPath(destination).name.casefold()].append(destination) @@ -76,7 +45,7 @@ def inspect(files: list[str], mapping: LayoutMap, policy=None, root: Path | None for destination, sources in destinations.items(): if len(sources) > 1: findings.append({"destination": destination, "sources": sources, "message": "case-insensitive destination collision"}) - return {"schema": 1, "mapped_files": sum(mapping.translate(p) != p for p in files), "findings": findings, "forwarding_headers": forwarding, "planned_or_obsolete_rows": dormant, "duplicate_basenames": {name: sorted(set(paths)) for name, paths in sorted(basenames.items()) if len(set(paths)) > 1}} + return {"schema": 1, "mapped_files": sum(mapping.translate(p) != p for p in files), "findings": findings, "planned_or_obsolete_rows": dormant, "duplicate_basenames": {name: sorted(set(paths)) for name, paths in sorted(basenames.items()) if len(set(paths)) > 1}} def main() -> int: @@ -87,7 +56,7 @@ def main() -> int: parser.add_argument("--output") args = parser.parse_args() root = repo_root(args.repo) - report = inspect(tracked_files(root), LayoutMap(read_tsv(root / args.map)), load_policy(root), root) + report = inspect(tracked_files(root), LayoutMap(read_tsv(root / args.map)), load_policy(root)) emit_json(report, args.output) return int(args.strict and bool(report["findings"])) diff --git a/src/daemon/platform.hpp b/src/daemon/platform.hpp deleted file mode 100644 index a9783245a..000000000 --- a/src/daemon/platform.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/process/os_process.hpp" diff --git a/src/desktop/context_picker.hpp b/src/desktop/context_picker.hpp deleted file mode 100644 index 2e05527cf..000000000 --- a/src/desktop/context_picker.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/native_ui/context_picker.hpp" diff --git a/src/desktop/custom_toast.hpp b/src/desktop/custom_toast.hpp deleted file mode 100644 index 2a32ef5f6..000000000 --- a/src/desktop/custom_toast.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/native_ui/custom_toast.hpp" diff --git a/src/desktop/folder_picker.hpp b/src/desktop/folder_picker.hpp deleted file mode 100644 index 3b0c91897..000000000 --- a/src/desktop/folder_picker.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/native_ui/folder_picker.hpp" diff --git a/src/desktop/locale.hpp b/src/desktop/locale.hpp deleted file mode 100644 index b5a135d61..000000000 --- a/src/desktop/locale.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/locale.hpp" diff --git a/src/desktop/notifications.hpp b/src/desktop/notifications.hpp deleted file mode 100644 index 9beafb98d..000000000 --- a/src/desktop/notifications.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/native_ui/notifications.hpp" diff --git a/src/desktop/notifications_backend.hpp b/src/desktop/notifications_backend.hpp deleted file mode 100644 index c4c060f4f..000000000 --- a/src/desktop/notifications_backend.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/native_ui/notifications_backend.hpp" diff --git a/src/desktop/open_in_explorer.hpp b/src/desktop/open_in_explorer.hpp deleted file mode 100644 index cb8730f5e..000000000 --- a/src/desktop/open_in_explorer.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/native_ui/open_in_explorer.hpp" diff --git a/src/desktop/strings.hpp b/src/desktop/strings.hpp deleted file mode 100644 index 56219685e..000000000 --- a/src/desktop/strings.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/native_ui/strings.hpp" diff --git a/src/hooks/hook_runner.hpp b/src/hooks/hook_runner.hpp deleted file mode 100644 index a6bcb2513..000000000 --- a/src/hooks/hook_runner.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/process/process_runner.hpp" diff --git a/src/layers.tsv b/src/layers.tsv index 0519a83ca..f25b8f614 100644 --- a/src/layers.tsv +++ b/src/layers.tsv @@ -130,23 +130,3 @@ ownership_allow src/base/utils/joining_thread.hpp 1 R15:std_thread JoiningThre ownership_allow src/base/utils/joining_thread.hpp 1 R15:std_thread JoiningThreadGroup ownership/P2-01 C8 legacy worker group owner; P2-01 ownership_allow src/base/utils/abandonable_call.cpp 1 R15:std_thread abandonable_detail::start_owned_work ownership/P2-01 C8 owned abandonable worker; P2-01 ownership_allow src/base/utils/abandonable_call.cpp 1 R15:detach abandonable_detail::start_owned_work ownership/P2-01 C8 detached worker owns captured lifetime; P2-01 -exception src/base/utils/clipboard.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/clipboard.hpp; delete with the P3-02 freeze move -exception src/base/utils/open_url.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/open_url.hpp; delete with the P3-02 freeze move -exception src/base/utils/power_inhibitor.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/power_inhibitor.hpp; delete with the P3-02 freeze move -exception src/base/utils/terminal_capability.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/terminal/terminal_capability.hpp; delete with the P3-02 freeze move -exception src/base/utils/terminal_theme_detect.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/terminal/terminal_theme_detect.hpp; delete with the P3-02 freeze move -exception src/base/utils/terminal_title.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/terminal/terminal_title.hpp; delete with the P3-02 freeze move -exception src/base/utils/terminal_input.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/terminal/terminal_input.hpp; delete with the P3-02 freeze move -exception src/adapters/upgrade/console.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/terminal/console.hpp; delete with the P3-02 freeze move -exception src/domain/hooks/hook_runner.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/process/process_runner.hpp; delete with the P3-02 freeze move -exception src/adapters/lsp/lsp_process.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/process/piped_process.hpp; delete with the P3-02 freeze move -exception src/adapters/lsp/lsp_which.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/process/which.hpp; delete with the P3-02 freeze move -exception src/apps/daemon/platform.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/process/os_process.hpp; delete with the P3-02 freeze move -exception src/apps/desktop/locale.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/locale.hpp; delete with the P3-02 freeze move -exception src/apps/desktop/folder_picker.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/native_ui/folder_picker.hpp; delete with the P3-02 freeze move -exception src/apps/desktop/context_picker.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/native_ui/context_picker.hpp; delete with the P3-02 freeze move -exception src/apps/desktop/open_in_explorer.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/native_ui/open_in_explorer.hpp; delete with the P3-02 freeze move -exception src/apps/desktop/notifications.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/native_ui/notifications.hpp; delete with the P3-02 freeze move -exception src/apps/desktop/notifications_backend.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/native_ui/notifications_backend.hpp; delete with the P3-02 freeze move -exception src/apps/desktop/custom_toast.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/native_ui/custom_toast.hpp; delete with the P3-02 freeze move -exception src/apps/desktop/strings.hpp R1,R2 platform Claude-p2-03 2026-10-15 P2-03 forwarding header -> src/platform/native_ui/strings.hpp; delete with the P3-02 freeze move diff --git a/src/lsp/lsp_process.hpp b/src/lsp/lsp_process.hpp deleted file mode 100644 index 628a55543..000000000 --- a/src/lsp/lsp_process.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/process/piped_process.hpp" diff --git a/src/lsp/lsp_which.hpp b/src/lsp/lsp_which.hpp deleted file mode 100644 index 5dd0d33ea..000000000 --- a/src/lsp/lsp_which.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/process/which.hpp" diff --git a/src/upgrade/console.hpp b/src/upgrade/console.hpp deleted file mode 100644 index 185b71219..000000000 --- a/src/upgrade/console.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/terminal/console.hpp" diff --git a/src/utils/clipboard.hpp b/src/utils/clipboard.hpp deleted file mode 100644 index 863f1a602..000000000 --- a/src/utils/clipboard.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/clipboard.hpp" diff --git a/src/utils/open_url.hpp b/src/utils/open_url.hpp deleted file mode 100644 index 5f6ea3ab8..000000000 --- a/src/utils/open_url.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/open_url.hpp" diff --git a/src/utils/power_inhibitor.hpp b/src/utils/power_inhibitor.hpp deleted file mode 100644 index 52a565c85..000000000 --- a/src/utils/power_inhibitor.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/power_inhibitor.hpp" diff --git a/src/utils/terminal_capability.hpp b/src/utils/terminal_capability.hpp deleted file mode 100644 index 665f1af55..000000000 --- a/src/utils/terminal_capability.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/terminal/terminal_capability.hpp" diff --git a/src/utils/terminal_input.hpp b/src/utils/terminal_input.hpp deleted file mode 100644 index 167b10f8f..000000000 --- a/src/utils/terminal_input.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/terminal/terminal_input.hpp" diff --git a/src/utils/terminal_theme_detect.hpp b/src/utils/terminal_theme_detect.hpp deleted file mode 100644 index ebed99370..000000000 --- a/src/utils/terminal_theme_detect.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/terminal/terminal_theme_detect.hpp" diff --git a/src/utils/terminal_title.hpp b/src/utils/terminal_title.hpp deleted file mode 100644 index 042f925ab..000000000 --- a/src/utils/terminal_title.hpp +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "platform/terminal/terminal_title.hpp" From 7ebbe8a47063998541dc2c09a1ec29e4e0fb099f Mon Sep 17 00:00:00 2001 From: tmoonlight Date: Sun, 27 Sep 2026 21:14:31 +0800 Subject: [PATCH 6/8] =?UTF-8?q?refactor20260927(layers/P2-03):=20=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E8=AE=B0=E5=BD=95=20verification/P2-03-platform-and-p?= =?UTF-8?q?ty.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 提交表、§7.2 P2 闸门逐项、内容修改说明(ProcessSpec / PipedProcess / which、CMake、文档)、D24 备案、本机 Windows 全新目录 build-p2 的构建 / 冒烟目标 / desktop 不链 testable / 目标快照对照 / 全量单测 5115-5114-9-0 / pty 三后端用例 / Web 控制台停靠区 ConPTY 冒烟、lint 161 -> 160 与工具结果、遗留事项。 --- .../verification/P2-03-platform-and-pty.md | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 openspec/changes/refactor20260927-restructure-src-layers/verification/P2-03-platform-and-pty.md diff --git a/openspec/changes/refactor20260927-restructure-src-layers/verification/P2-03-platform-and-pty.md b/openspec/changes/refactor20260927-restructure-src-layers/verification/P2-03-platform-and-pty.md new file mode 100644 index 000000000..ec49228c6 --- /dev/null +++ b/openspec/changes/refactor20260927-restructure-src-layers/verification/P2-03-platform-and-pty.md @@ -0,0 +1,104 @@ +# P2-03 平台件下沉到 `platform/` 与 `pty/` 验证记录 + +认领 Claude-p2-03,2026-09-27(`fdb91d1f`)。分支 `refactor20260927/P2-03`,基于 master `4b6ce35c`(含主代理为 P2 补的 normalize_includes 过渡目录解析),中途按主代理要求合入一次 master(`bf1ef7db`,快照工具的对象路径换算)。搬迁清单 = `scripts/refactor/src_layout_map.tsv` 中 phase 为 P2-03 的 61 行(45 个 src 文件 + `src/web/pty/` 整目录 9 个文件 + 15 条 tests 行 17 个文件),与 layout-map.md §2 / tasks.md 3.2 一致。**按主代理 2026-09-27 的决策 D24,旧路径不留转发头、`layers.tsv` 不加 exception 行**;中途加过的 20 个转发头与 20 条 exception 已在 `c69f91c6` 删除,最终树里 `scripts/` 与 `src/layers.tsv` 与 master 逐字节相同。 + +| 提交 | 内容 | +|---|---| +| `8c8538b0` [mechanical] | 71 个文件 `git mv`,全部 R100,0 行内容改动:`utils/{clipboard,open_url,power_inhibitor}.*` → `src/platform/`;`utils/terminal_*` 与 `upgrade/console.hpp` → `src/platform/terminal/`;`hooks/hook_runner.*` → `platform/process/process_runner.*`;`lsp/lsp_process.*` → `platform/process/piped_process.*`;`lsp/lsp_which.*` → `platform/process/which.*`;`daemon/platform{.hpp,_posix.cpp,_windows.cpp}` → `platform/process/os_process*`;`desktop/locale.*` → `src/platform/`;desktop 的 folder_picker / context_picker / open_in_explorer / notifications* / custom_toast* / strings → `platform/native_ui/`;`src/web/pty/` → `src/pty/`;14 个测试 → `tests/platform/`,`tests/web/pty/` → `tests/pty/` | +| `bb94c967` [mechanical] | `normalize_includes.py --scope src`(50 文件 76 行)与 `--scope tests`(30 文件 31 行)的输出,只改引号内路径;`--check` 两个范围 exit 0;numstat 107/107,`-U0` 补丁里 +/- 行全部是 `#include` 行 | +| `de834f51` | 内容修改:`platform::ProcessSpec`(hooks 留 `using HookCommandSpec`)、`platform::PipedProcess` / `SpawnOptions` / `which`(lsp 留别名头 `lsp/lsp_platform_aliases.hpp`,channels / environment 直接改用 platform 名)、搬走文件里 14 行指回旧目录的裸名 include、CMake 清单、文档路径;当时还加了 20 个转发头与 exception 行(已被 `c69f91c6` 撤掉)。细节见第 2 节 | +| `a92c0e4e` | 合入 origin/master(`bf1ef7db`) | +| `be02de47` | 为转发头做的两处工具修正(validate_map 识别转发头、migrate_branch 用例夹具),D24 之后无需保留,`c69f91c6` 已整体回退 | +| `c69f91c6` | D24:删除 20 个转发头与 20 条 exception 行,回退 `be02de47`;`scripts/` 与 `src/layers.tsv` 恢复与 master 相同 | + +净 diff(`origin/master..HEAD`):160 个文件;37 个纯 R100 + 34 个 R070–R099(搬走后又改了 include / 命名空间 / 注释的文件,搬迁本身在 `8c8538b0` 里是 R100)+ 88 个 M + 1 个 A(`src/lsp/lsp_platform_aliases.hpp`)。 + +## 1. §7.2「P2(每个 PR)」闸门逐项 + +| 闸门 | 结论 | 证据 | +|---|---|---| +| lint 违规数下降 | 满足(161 → 160) | `check_layers.py --enforce-parent-includes`:R1 18 → 17,其余规则计数不变(R8 119 / R9 10 / R2 6 / R3 5 / R5 1 / R10 1 / R14 1);消失的边是 `src/hooks/hook_runner.hpp:3 → hook_config.hpp`(base → domain),由 `ProcessSpec` 下沉切断;无新增 finding;`exceptions_used` 0。只降 1 的原因见第 4 节 | +| 转发头已登记 | D24 改为不留 | 搬走的 .hpp 旧路径不留任何文件,`layers.tsv` 无 exception 行;全仓 grep 旧路径 include(`utils/clipboard.hpp`、`hooks/hook_runner.hpp`、`lsp/lsp_process.hpp`、`daemon/platform.hpp`、`desktop/strings.hpp`、`web/pty/…` 等 24 个头)0 处 | +| 按映射换算后每个文件所属的 target 不变 | 满足 | 第 3 节:`--reverse-map --compare` 对参照快照 59 target / 3529 元组,target 0 增 0 减,元组 0 减,唯一新增是 `acecode_testable` 里的新头 `src/lsp/lsp_platform_aliases.hpp`(File API 把 GLOB 到的头也列进 target 源清单);没有任何编译单元换 target | +| 测试已随源文件移动 | 满足 | 17 个测试文件按 map 的 15 条 tests 行 R100 移动(`tests/platform/` 14 个、`tests/pty/` 3 个);GLOB `*_test.cpp` 自动收进 `acecode_unit_tests`,用例清单不变(第 3 节) | +| 三平台构建通过 | Windows 本机满足;mac / Linux 待 CI | 全新目录 `build-p2`(第 3 节)。改动的 `.mm` 只是路径(`acecode_source_paths.cmake` 的 `ACECODE_NATIVE_BRIDGE_MAC_SOURCES`),`acecode_require_sources` 在 Windows configure 时也校验这两个路径存在;`os_process_posix.cpp` / `terminal_theme_detect_posix.cpp` / `pty_backend_posix.cpp` 只改了 include 行。建议主代理合入后 dispatch 一次 refactor-matrix | +| 用例清单不变 | 满足 | 第 3.1 节:`tests` 5115、`ctest_names` 5119、SKIP 9 条与参照逐条相同,0 增 0 减 | +| `migrate_branch.py --check --layout current` | 按约定记录,非零 | `success=false`(P2 未完成),输出存 `N:/Users/shao/acecode-p2-03-verify/migrate-check.json` | + +## 2. 内容修改说明 + +### 2.1 process_runner(原 hooks/hook_runner) + +- `HookCommandSpec` 的本体原来定义在 `hooks/hook_config.hpp`,`hook_runner.hpp` 为它 include 整个 hook_config —— 这正是基线里那条 `base -> domain` 的 R1。现在 `platform/process/process_runner.hpp` 自己定义 `acecode::platform::ProcessSpec`(command + args + `valid()`,聚合类型,`{cmd, {args}}` 初始化照旧),`hooks/hook_config.hpp` 改为 `using HookCommandSpec = platform::ProcessSpec;`。hooks 内部(hook_config / hook_manager / hook_registry / hook_runtime)与 `tests/hooks/*` 沿用旧名,不改。 +- hooks 之外原本只经 `hook_runner.hpp` 拿到 `HookCommandSpec` 的调用点改用 `platform::ProcessSpec`(它们不再间接 include hook_config):`tool/grep_tool.cpp`(4)、`worktree/worktree_manager.cpp`、`environment/terminal_resolver.cpp`、`channels/setup.cpp`、`daemon/worker.cpp`、`remote_control/channel_plugin.{hpp,cpp}`(Runner 签名 + 3 处),以及 `tests/remote_control/channel_plugin_test.cpp`(12)、`tests/commands/remote_control_command_test.cpp`、`tests/remote_control/session_channel_binder_test.cpp`、`tests/platform/hook_runner_test.cpp`(6)。只换类型名,不改任何断言。 +- `HookProcessResult` / `HookProcessOptions` / `HookEnvironment` / `run_hook_process` / `run_hook_shell_command` / `resolve_hook_command_path` 名字与 `namespace acecode` 暂不动(简报只要求 ProcessSpec),头注释说明;调用点 60+,留作后续。 + +### 2.2 piped_process / which(原 lsp/lsp_process、lsp/lsp_which) + +- `LspProcess` → `platform::PipedProcess`,`LspSpawnOptions` → `platform::SpawnOptions`,`quote_windows_arg` / `FileExistsFn` / `which_in` / `which` 只换命名空间 `acecode::lsp` → `acecode::platform`。 +- 新头 `src/lsp/lsp_platform_aliases.hpp`(真实文件,随 lsp 模块走)保留 `lsp::LspProcess` / `LspSpawnOptions` / `FileExistsFn` / `quote_windows_arg` / `which` / `which_in` 别名;`lsp_client.hpp` 与 `lsp_server_registry.hpp` 改 include 它,lsp 内部调用点(lsp_client / lsp_server_registry / lsp_service、`tests/lsp/lsp_server_registry_test.cpp`)一处不改。 +- lsp 之外按 layout-map §6「P2-03 起 bridge/setup 改用 platform/process」直接改用 platform 名:`channels/bridge.{hpp,cpp}`、`channels/runtime.hpp`、`channels/setup.{hpp,cpp}`、`environment/toolchains.{hpp,cpp}`、`tests/test_support/channels/test_support.hpp`、`tests/platform/lsp_which_test.cpp`(using 声明与头注释)。grep 确认 lsp 之外不再有 `lsp::LspProcess` / `lsp::LspSpawnOptions` / `lsp::which`。 + +### 2.3 只搬位置的部分 + +- `os_process*`(原 daemon/platform*):函数与 `namespace acecode::daemon` 不变(简报允许),头注释写明约 20 个调用点(daemon / desktop / session / web / channels / tests)逐步改名。P2-04 正在搬 `daemon/runtime_files.cpp`(它调 `daemon::current_pid`),现在改命名空间会让两个分支在同一批调用点上撞车。 +- `platform/terminal/console.hpp`(原 upgrade/console.hpp):`namespace acecode::upgrade` 不变,只有 `upgrade/apply.cpp`、`upgrade/upgrade.cpp` 两个使用方。 +- desktop 的 native_ui 件与 locale:命名空间 `acecode::desktop` 不变。 +- 搬走文件里指回旧目录的裸名 include 工具无法解析(简报里「也会被改成模块根形式」这一句实测不成立,P2-02 的工具修正只解决「指向搬走文件」的方向),14 行手工改:`platform/clipboard.cpp` 的 `base64.hpp` / `encoding.hpp` → `utils/...`,`power_inhibitor.cpp`、`terminal_capability.cpp`、`terminal_theme_detect{,_posix,_win}.cpp` 的 `logger.hpp` → `utils/logger.hpp`,`native_ui/strings.cpp` 的 `locale.hpp` → `platform/locale.hpp`,`os_process_{posix,windows}.cpp` 的 `platform.hpp` → `os_process.hpp`,`process_runner.cpp` / `piped_process.cpp` / `which.cpp` 的自包含头名,`process_runner.hpp` 删掉 `hook_config.hpp`。改完 `check_layers` 的 14 项「unresolved project include」全部消失。 +- CMake:`CMakeLists.txt` 的 `ACECODE_NATIVE_BRIDGE_SUPPORT_SOURCES` 11 行(os_process_posix / os_process_windows / custom_toast / custom_toast_win / context_picker / folder_picker_win / locale / notifications / open_in_explorer / strings / clipboard)、`ACECODE_NOTIFICATION_BACKEND_SOURCES` 2 行、`target_sources(acecode_native_bridge_support …)` 的 notifications_win / notifications_stub 两处、两条注释;`cmake/acecode_source_paths.cmake` 的 `ACECODE_WINPTY_AGENT_LOCATION_SOURCE`(即任务点名的 `acecode_winpty.cmake:64` 那条引用,P0-04 已收成共用变量)与 `ACECODE_NATIVE_BRIDGE_MAC_SOURCES` 两个 `.mm`;`cmake/acecode_winpty.cmake` 一条注释。P2-04 的 runtime_files / agent_browser_runtime / open_request / workspace_registry 四行没碰(与它们交错,合入时会有文本冲突,按「合入串行」处理)。`cmake/deepin/CMakeLists.txt` 与 `tests/CMakeLists.txt` 没有引用搬走的文件。configure 时 `acecode_require_sources` 护栏全部通过。 +- 文档与路径表:CLAUDE.md(Desktop Shell 关键模块列表、Mouse+Clipboard 的 `src/platform/clipboard.*`、ConsoleDock 的 `src/pty/`、Windows 弹框三层结构的归属、LSP 结构里 `platform/process/piped_process` / `which`)、AGENT.md、`tests/README.md` 镜像表、`docs/localization.md`、`docs/desktop-shell/multi-workspace.md`、`docs/plan/reviews/theme-management-001-web.md`、`docs/string-utilities-refactor.md`、`docs/help-source/group6.py`(改后跑 `build_help.py`,生成物只有 `sources.json` 一行 diff,其余 html 无变化)、`tests/cpp_source_paths.json`(`desktop/context_picker.cpp` 键的值改为新路径,键名不动;`node web/src/lib/previewWorkbenchArchitecture.test.js` 全部 pass);搬走的测试与 `open_url.hpp` 的头注释里的旧路径同步。`check_doc_paths` 85 → 85(开工前本树实测 85,不是简报里的 84;差异来自 P2-02 合入 master 之后,不是本任务引入),无新增失效路径。注意「原 `src/web/pty/`」这种带 `src/` 的旧路径写进文档会被 checker 算失效,改成不带前缀的写法。 + +### 2.4 转发头的实测结论(供 D24 备案) + +D24 之前按简报留过 20 + 4 个 2 行转发头,两条实测结论值得留档: + +- `src/web/pty/` 的 4 个转发头会让构建失败:新模块名 `pty` 与旧子目录同名,`src/web/server_impl.hpp:68` 的规范写法 `#include "pty/pty_session_registry.hpp"` 被 MSVC 先按包含者目录命中转发头,转发头里同名的 include 又被按**父包含者**目录解析回它自己,`#pragma once` 之后什么也不包含 —— `routes_environment.cpp` 实测 `C2027 未定义类型 acecode::PtySessionRegistry`;lint 同时报 R8「ambiguous include」。这就是 design.md D1 说的「MSVC 按父包含者目录查找造成的平台差异」。 +- 其它 20 个转发头能编译,但 `validate_map --strict` 报 20 项 destination collision(与 D24 的理由一致);lint 把转发头按精确行映射到目的模块,转发头指向真身是模块内边,不产生 R1/R2,exception 行只是登记簿。 + +现在两类都不存在,问题随之消失。 + +## 3. 本机验证(Windows 11,全新目录 `build-p2`) + +Ninja + MSVC 2022 Release,`BUILD_TESTING=ON`,`ACECODE_BUILD_DESKTOP=ON`,x64-windows-static,只读复用 `N:/Users/shao/acecode/build/vcpkg_installed`;configure 前写 File API query。删转发头之后重新 configure + build 一次(GLOB 重扫),快照取自最终树。 + +| 步骤 | 结果 | +|---|---| +| configure | 通过(`acecode_assert_known_roots` / `acecode_require_sources` 全部通过) | +| `cmake --build --target acecode acecode-desktop acecode_unit_tests` | 通过(1020 步;2 条告警都是既有的:`xutility` C4244、`tests/sandbox/exec_rules_test.cpp:153` C4129)。第一次带 pty 转发头的构建失败于 `routes_environment.cpp` C2027(2.4) | +| 冒烟目标 `computer_use_native_smoke computer_use_broker_smoke agent_browser_host_smoke agent_browser_pointer_demo acecode_upgrade_restart_smoke` | 通过(`smoke build exit=0`) | +| desktop 不链 acecode_testable | `build-p2/build.ninja` 里 `build acecode-desktop.exe:` 的 LINK_LIBRARIES 只有 `acecode_desktop_support.lib acecode_native_bridge_support.lib` + vcpkg 的 cpr / libcurl / zlib + 系统库,`acecode_testable` 出现 0 次 | +| 目标快照 vs `N:/Users/shao/acecode-p2-shared/master-windows-targets.json`(`--map … --reverse-map --compare`,master `bf1ef7db` 的工具) | 59 target / 3530 元组 vs 参照 59 / 3529:target 0 增 0 减;元组 25 减 26 增。25 减 + 25 增全部是 `nlohmann_json.natvis` 的环境差异(参照来自主检出,vcpkg_installed 在其源根之下记成 `build/vcpkg_installed/...`,worktree 里是源根之外的绝对路径 `N:/Users/shao/acecode/build/...`;把这一个前缀归一后 25 对逐条相同,与 P1-01 记录同类);natvis 之外 **removed 0,added 1** = `acecode_testable` 的新头 `src/lsp/lsp_platform_aliases.hpp`。14 个搬走的 `.cpp` 在 acecode / acecode_unit_tests / concurrent_session_writer / remote_web_proxy_test_child / state_file_claim_worker 五个消费目标里的对象路径经 `bf1ef7db` 的换算逐条对上。`compare_snapshots.py --allowed-addition src/lsp/lsp_platform_aliases.hpp`:targets 0 增 0 减,`authorized_added` = 该头 1 条,`unexpected_removed` / `unexpected_added` 各 25 条全是 natvis(报告存 `N:/Users/shao/acecode-p2-03-verify/compare-snapshots.json`) | +| 全量单测(隔离 HOME / TEMP 于 `N:\acecode-p2-03-iso`) | **5115 列出 / 5114 执行 / 9 SKIP / 0 失败**,`ctest_names` 5119(`gtest_inventory.py --run`,exit 0);与简报给的参照(5115 / 5114 / 9 / 0)相同,`ComputerUsePointerOverlay.*` / `DesktopSingleInstance.*` 本次都没抖 | +| 用例清单(`compare_snapshots.py --gtest-before master-windows-gtest.json --gtest-after gtest.json`) | `tests_added` 0 / `tests_removed` 0;`ctest` 5119 = 5119;SKIP 集合 9 条逐条相同(ChannelBridge.RealBridge… / ChannelSetup.RealDependency… / ImageGenerationNetworkSmoke ×2 / NativeNotifications.OptInDeliversSelfDrawnToast / RssSearchBackendLive… / SessionReplayRealJsonl.UserSessionDbcoding5_2026_04_26 / SystemPromptTest.PosixPromptStaysCleanOfWindowsGuidance / Utf8PathTest.ExtendedLengthPathIsIdentityOnPosix);失败集合两边都为空 | +| `tests/pty/` 的三种后端 | `PtyBackendSpawnTest.ConPtyEchoRoundTripAndExit` OK(268 ms,未触发其 GTEST_SKIP)、`PipeFallbackEchoRoundTripAndExit` OK、`KillRunningSessionIsIdempotent` OK、`WinptySpikeTest.SpawnCmdEchoRoundTripAndResize` OK(真实 spawn cmd + 回显 + resize,139 ms)、`MissingAgentOverrideFailsCleanly` OK、`PtySessionRegistryTest.*` 10 条 OK、`PtyBackendDetectTest.ModernWindowsPrefersConPty` OK(摘自 `gtest-run.log`) | +| Web 控制台停靠区冒烟 | `build-p2/acecode.exe daemon --foreground --port=54676 --run-dir=N:\acecode-p2-03-iso\run`(隔离 HOME,无模型配置),日志 `console backend=conpty shell="C:\Program Files\PowerShell\7\pwsh.exe"`;内置浏览器打开 `http://127.0.0.1:54676/`,点顶栏「打开控制台 (Ctrl+`)」,停靠区开出 pwsh 标签(日志 `[pty] created session pty-1 … backend=conpty`),输入 `echo p2-03-conpty-smoke` 回显 `p2-03-conpty-smoke` 并出新提示符。winpty:本机 Win11 `detect_pty_backend()` 恒选 ConPTY,没有运行期开关,winpty 路径以上面两条 `WinptySpikeTest` 覆盖 | + +### 3.1 搬走模块相关用例 + +按用例名前缀在清单里核对,117 条全部执行、0 失败、无 SKIP:TerminalCapability 14、ClipboardTest 11、NativeNotifications 11(其中 `OptInDeliversSelfDrawnToast` 是既有的环境 SKIP)、HookRunner 10、PtySessionRegistryTest 10、ConsoleShellCatalogTest 9、LspWhich 6、OpenUrl 6、CustomToast* 23、DesktopLocale 4、DesktopStrings 4、PtyBackendSpawnTest 3、PtyShellResolveTest 2、WinptySpikeTest 2、PtyBackendDetectTest 1、PtyBackendKindNameTest 1。 + +## 4. lint 与工具 + +| 项目 | 开工前(本树 `4b6ce35c`) | 完成后 | +|---|---|---| +| 分层违规总数(`check_layers.py --enforce-parent-includes`) | 161 | **160**(R1 18 → 17,其它不变;`include_edges` 2654 → 2655,多的 1 条是 `lsp_platform_aliases.hpp`) | +| `normalize_includes --check` src / tests | exit 0 | exit 0 | +| `check_doc_paths` findings | 85 | 85 | +| `check_file_size --strict` / `check_ownership --strict` | exit 0 | exit 0(两个基线都按最终规范路径记账,搬迁后 `custom_toast_win.cpp` 1230 行等条目照常命中) | +| `validate_map --strict` | exit 0 | exit 0(findings 0;P2-03 的 61 行不再出现在 `planned_or_obsolete_rows`) | +| `unittest discover scripts/refactor/tests` | 71 通过 | 72 通过(+ master `bf1ef7db` 的对象路径用例;本分支对 `scripts/` 无改动) | + +新模块的出边(按 `IncludeIndex` 实测):`platform → platform` 19 个头、`platform → utils` 4 个头(`base64` / `encoding` / `logger` / `utf8_path`)、`pty → pty` 4 个头、`pty → utils` 4 个头(`encoding` / `logger` / `paths` / `utf8_path`),没有任何指向 platform / pty 之外更高层的边。任务行点名的「utils → desktop / utils → daemon 反向边」在基线里本来就被映射表提前归入 platform 而不计违规(lint 按映射表给文件定模块),所以报告里看不到它们「消失」;真正消失的是 hooks 的 `hook_runner.hpp → hook_config.hpp`。 + +## 5. 触碰到的不变量(§7.3) + +- 9「构建边界」:acecode-desktop 不链 acecode_testable(第 3 节 link 行);`ACECODE_DEEPIN` / `ACECODE_CHANNEL_ASSET_DIR` 所在文件没动;`.mm` 的 OBJCXX 属性与 REMOVE_ITEM 只改路径;每个文件所属 target 不变(快照);冒烟目标可构建。 +- 其它条目(prompt cache、provider 出口、工具名映射、审批门、单写者、锁序、PA、路径)本任务不触碰对应代码;守护测试随全量单测运行(0 失败)。 + +## 6. 遗留与需要主代理决定的事项 + +1. `os_process.hpp` 仍是 `namespace acecode::daemon`,`console.hpp` 仍是 `acecode::upgrade`,`run_hook_*` 函数名未改 —— 简报允许,建议在 P2-04 合入后再统一改名,避免与它搬的 `runtime_files.cpp` 撞车。 +2. 目标快照对照里唯一的「增」是新头 `src/lsp/lsp_platform_aliases.hpp`(`acecode_testable`,File API 把 GLOB 到的头也列进源清单);`compare_snapshots.py` 用 `--allowed-addition src/lsp/lsp_platform_aliases.hpp` 即可归为授权新增,是否登记进 D23 名单由主代理定。 +3. `CMakeLists.txt` 的 `ACECODE_NATIVE_BRIDGE_SUPPORT_SOURCES` 与 P2-04 的四行交错,合入第二个分支时会有文本冲突,按行合并即可(两边都只改自己的行)。 +4. mac / Linux 构建未在本机验证(只有路径改动 + 两个 `.mm` 路径经 `acecode_require_sources` 校验),建议合入后 dispatch refactor-matrix。 +5. 简报「搬走文件内部指回旧目录的裸名 include 也会被 normalize 改成模块根形式」实测不成立(2.3),后续 P2 任务要预留手工改这类 include 的步骤,或者给 `IncludeIndex.resolve` 补上「按映射表反查包含者的旧目录」这一步。 From 5f33ff6fadba3aebbcf81a2082f02668b5e87940 Mon Sep 17 00:00:00 2001 From: tmoonlight Date: Sun, 27 Sep 2026 21:42:18 +0800 Subject: [PATCH 7/8] =?UTF-8?q?refactor20260927(layers/P2-03):=20=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E8=AE=B0=E5=BD=95=E8=BF=BD=E5=8A=A0=E5=90=88=E5=85=A5?= =?UTF-8?q?=E5=89=8D=E5=A4=8D=E9=AA=8C(=E5=90=88=E5=85=A5=20master=202cedc?= =?UTF-8?q?0d1=20=E4=B9=8B=E5=90=8E:=E6=9E=84=E5=BB=BA=20/=20=E5=85=A8?= =?UTF-8?q?=E9=87=8F=E5=8D=95=E6=B5=8B=205115-5114-9-0=20/=20=E5=BF=AB?= =?UTF-8?q?=E7=85=A7=E5=AF=B9=E7=85=A7=20removed=200=20/=20lint=20152)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 参照快照是 P2-02 合入后 master 原样采集的,P2-02 的文件仍在过渡目录,而 --reverse-map 会把本树里同样的过渡路径反查回 G0 旧路径;把参照用同一个 translate_for_comparison(reverse=True) 换算到旧路径坐标系后再比:removed 0,added 只有 src/lsp/lsp_platform_aliases.hpp。 --- .../verification/P2-03-platform-and-pty.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/openspec/changes/refactor20260927-restructure-src-layers/verification/P2-03-platform-and-pty.md b/openspec/changes/refactor20260927-restructure-src-layers/verification/P2-03-platform-and-pty.md index ec49228c6..029f5c675 100644 --- a/openspec/changes/refactor20260927-restructure-src-layers/verification/P2-03-platform-and-pty.md +++ b/openspec/changes/refactor20260927-restructure-src-layers/verification/P2-03-platform-and-pty.md @@ -102,3 +102,21 @@ Ninja + MSVC 2022 Release,`BUILD_TESTING=ON`,`ACECODE_BUILD_DESKTOP=ON`,x64-wind 3. `CMakeLists.txt` 的 `ACECODE_NATIVE_BRIDGE_SUPPORT_SOURCES` 与 P2-04 的四行交错,合入第二个分支时会有文本冲突,按行合并即可(两边都只改自己的行)。 4. mac / Linux 构建未在本机验证(只有路径改动 + 两个 `.mm` 路径经 `acecode_require_sources` 校验),建议合入后 dispatch refactor-matrix。 5. 简报「搬走文件内部指回旧目录的裸名 include 也会被 normalize 改成模块根形式」实测不成立(2.3),后续 P2 任务要预留手工改这类 include 的步骤,或者给 `IncludeIndex.resolve` 补上「按映射表反查包含者的旧目录」这一步。 + +## 7. 合入前复验(§6.4,2026-09-27 合入最新 master 之后) + +`git merge origin/master` → `2cedc0d1`,无冲突(master 含 P2-02 `94938fa4`、两个 Mermaid PR、P2-05 认领 `aeb5e50a`、工具提交 `fd8668e5`)。全部命令限定在 `N:/Users/shao/acecode-p2-03`。 + +| 项目 | 结果 | +|---|---| +| `normalize_includes.py --check --scope src` / `--scope tests`(`fd8668e5` 之后的工具) | 均 exit 0、changed_lines 0、errors 0 —— 新工具对本分支手工改过的 14 行与其它任何 include 都没有新的改写意见 | +| `check_layers.py --enforce-parent-includes` | **152**(P2-02 合入后 master 为 153,本任务再降 1:`hook_runner.hpp → hook_config.hpp`);R1 12 / R2 4 / R3 4 / R5 1 / R8 119 / R9 10 / R10 1 / R14 1;`exceptions_used` 0 | +| `validate_map --strict` / `check_doc_paths` / `check_file_size --strict` / `check_ownership --strict` | exit 0 / 85(不变)/ exit 0 / exit 0 | +| `unittest discover scripts/refactor/tests` | 全部通过(exit 0;本分支对 `scripts/` 无改动) | +| `build-p2` 增量重建 `acecode acecode-desktop acecode_unit_tests`(413 个编译单元因 P2-02 的搬迁重编)+ 5 个冒烟目标 | 全部通过,0 条告警;`acecode-desktop.exe` 的 link 行 `acecode_testable` 仍为 0 次 | +| 全量单测(隔离 HOME / TEMP) | **5115 列出 / 5114 执行 / 9 SKIP / 0 失败**,ctest 5119;与新参照 `master-windows-gtest.json` 逐条相同(tests 0 增 0 减,SKIP 9 条相同,失败两边为空) | +| 目标快照 vs 新参照 `master-windows-targets.json`(P2-02 合入后 master 原样采集,59 / 3572) | 本树 59 target / 3573 元组。**直接用 `--reverse-map --compare` 会多出 42 减 / 43 增**:参照是原样采集的,P2-02 的 5 个 .cpp / 7 个 .hpp / 5 个测试仍记在过渡目录(`src/llm/…`、`src/utils/diff_utils.cpp`),而 `--reverse-map` 把本树里这些同样的过渡路径反查回了 G0 旧路径(`src/tool/…`、`src/provider/llm_provider.hpp`),两边坐标系不一致,差异全是 P2-02 的文件,与本任务无关。把参照也用 master 版工具的同一个 `translate_for_comparison(reverse=True)` 换算到旧路径坐标系(42 个 source 被改写,存 `N:/Users/shao/acecode-p2-03-verify/master-windows-targets.reverse-mapped.json`)后再比:target 0 增 0 减;元组 **removed 0**(natvis 之外),**added 只有 `acecode_testable` 的 `src/lsp/lsp_platform_aliases.hpp`**;25 减 / 25 增的 `nlohmann_json.natvis` 仍是 vcpkg 路径环境差异(前缀归一后逐条相同)。`compare_snapshots.py --before <换算后参照> --after … --allowed-addition src/lsp/lsp_platform_aliases.hpp`:`authorized_added` 1 条,`unexpected_removed` / `unexpected_added` 各 25 条全是 natvis,targets 无增减 | + +主代理决定的记录:命名空间与 `run_hook_*` 函数名保持现状,后续任务统一;`src/lsp/lsp_platform_aliases.hpp` 作为 P2-03 新增文件登记于此,不进 D23 名单;`ACECODE_NATIVE_BRIDGE_SUPPORT_SOURCES` 与 P2-04 的交错由后合入的 P2-04 处理;mac / Linux 由主代理在合入后 dispatch refactor-matrix;搬走文件里裸名 include 的回查已由 `fd8668e5` 修好(本分支的 14 行是在它之前手工改的,新工具复核 0 diff)。 + +给后续 P2 任务的提示:参照快照若是原样采集(含前序 P2 任务的过渡路径),对照前要把参照也做一次 `reverse` 换算,或者采集参照时就带 `--map --reverse-map`;否则前序任务搬过的每个文件都会在对照里成对出现。 From 460773c5a887daf72f7c51fcac8b388629564dea Mon Sep 17 00:00:00 2001 From: tmoonlight Date: Mon, 28 Sep 2026 01:16:26 +0800 Subject: [PATCH 8/8] =?UTF-8?q?refactor20260927(layers/P2-03):=20=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E5=9B=9B=E5=B9=B3=E5=8F=B0=E6=9E=84=E5=BB=BA=E4=B8=8E?= =?UTF-8?q?=E6=B8=85=E5=8D=95=E5=A4=8D=E6=A0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../verification/P2-03-platform-and-pty.md | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/openspec/changes/refactor20260927-restructure-src-layers/verification/P2-03-platform-and-pty.md b/openspec/changes/refactor20260927-restructure-src-layers/verification/P2-03-platform-and-pty.md index 029f5c675..49f439efb 100644 --- a/openspec/changes/refactor20260927-restructure-src-layers/verification/P2-03-platform-and-pty.md +++ b/openspec/changes/refactor20260927-restructure-src-layers/verification/P2-03-platform-and-pty.md @@ -120,3 +120,24 @@ Ninja + MSVC 2022 Release,`BUILD_TESTING=ON`,`ACECODE_BUILD_DESKTOP=ON`,x64-wind 主代理决定的记录:命名空间与 `run_hook_*` 函数名保持现状,后续任务统一;`src/lsp/lsp_platform_aliases.hpp` 作为 P2-03 新增文件登记于此,不进 D23 名单;`ACECODE_NATIVE_BRIDGE_SUPPORT_SOURCES` 与 P2-04 的交错由后合入的 P2-04 处理;mac / Linux 由主代理在合入后 dispatch refactor-matrix;搬走文件里裸名 include 的回查已由 `fd8668e5` 修好(本分支的 14 行是在它之前手工改的,新工具复核 0 diff)。 给后续 P2 任务的提示:参照快照若是原样采集(含前序 P2 任务的过渡路径),对照前要把参照也做一次 `reverse` 换算,或者采集参照时就带 `--map --reverse-map`;否则前序任务搬过的每个文件都会在对照里成对出现。 + +## 8. Codex 接手复核(2026-09-28) + +已将最新 master `0c0e37cb` 合入分支为 `2001f210300bb840b3656eebeb84cd04bbfb8d3a`。与此前已验证的 `5f33ff6f` 比较,`src/`、`tests/`、`CMakeLists.txt`、`cmake/` 均无差异。原本机全量测试和 ConPTY / winpty 实际进程验证仍对应相同 C++ 源码。 + +[refactor-matrix 36332585400](https://github.com/tmoonlight/acecode/actions/runs/36332585400) 对该完整提交号进行全新配置、构建和清单采集,四个平台构建均通过。产物下载到仓库外 `N:/Users/shao/AppData/Local/Temp/codex-refactor20260928/ci/p2-03/`,逐平台复核如下: + +| 平台 | target / 编译元组 | 列出 / 执行 / SKIP / 失败 | +|---|---|---| +| Windows x64 | 59 / 3573 | 5115 / 5108 / 10 / 4 | +| Linux x64 | 50 / 3487 | 5035 / 5026 / 16 / 0 | +| macOS arm64 | 57 / 3632 | 5040 / 5033 / 14 / 11 | +| Deepin x64 | 13 / 1373 | 不启用测试 | + +相对 post-p0,目标增减与既有元组删除均为 0;三个测试平台各增加 44 个元组,Deepin 增加 20 个,其中前序 P2-02 分别占 43 / 19,本任务只有已登记的 `lsp_platform_aliases.hpp` 1 条。新增元组沿用所属目标的既有编译属性。P2-03 没有新 GoogleTest 用例或新增 SKIP。 + +原始 CTest 参数化名称含运行时指针 / 对象字节,不作逐字节等值声明;本次核对 GoogleTest suite / case 集合、CTest 注册数量和 SKIP 用例集合,均无增删。快照比较在两侧统一使用 `translate_for_comparison(reverse=True)`,所有既有目标依赖和编译属性保持。 + +Deepin artifact 的 `source_revision` 因容器 Git 的 `dubious ownership` 报错为空。已从同一 build job 的 checkout 日志核对完整提交号,与传入的不可变 `source_ref` 一致;没有把空字段当作来源验证通过。Deepin 按原矩阵约定只构建 CLI / Desktop,不运行单测。 + +矩阵是基线采集工作流,其成功状态不代表所有断言通过。Windows 的失败未超出 post-p0 基线;macOS 的 10 项既有失败仍在,另有 `OpenAiProviderErrorRecovery.SseKeepaliveCommentsDoNotTriggerRetry`,这项已在 P1 验收及 P2-02 记录为既有时序抖动。本次保留其失败,没有删除用例、增加 SKIP 或修改断言。Linux 完整测试为 0 失败。