From cc5ad179c5b839dbbdd648d92aa458c2b7952445 Mon Sep 17 00:00:00 2001 From: ykiko Date: Mon, 29 Jun 2026 01:40:39 +0800 Subject: [PATCH 1/7] refactor(server): remove file watcher, daemon/relay/socket modes, rename server to serve - Remove file_watcher_task and fs_event-based file watching (future: periodic stat-based) - Remove Daemon, Relay, Socket server modes; simplify to Pipe + Tcp - Remove run_daemon_mode, run_relay_mode, DaemonConnection, relay_forward - Remove default_socket_path utility - Rename server subcommand to serve, run_server_mode to run_serve_mode - Add --workspace support to serve mode for standalone (no-editor) startup - Rename extension socket mode to tcp, update package.json enum - Update all test files to use "serve" subcommand and "tcp" mode --- .vscode/launch.json | 6 +- docs/en/dev/test-and-debug.md | 8 +- docs/en/guide/editors.md | 8 +- docs/zh/dev/test-and-debug.md | 6 +- docs/zh/guide/editors.md | 8 +- editors/vscode/package.json | 4 +- editors/vscode/src/extension.ts | 6 +- editors/vscode/src/setting.ts | 6 +- editors/zed/src/clice.rs | 2 +- src/clice.cc | 23 +-- src/server/service/agentic.cpp | 45 ----- src/server/service/agentic.h | 2 - src/server/service/master_server.cpp | 176 +----------------- src/server/service/master_server.h | 21 +-- src/support/filesystem.h | 8 - tests/conftest.py | 8 +- tests/integration/agentic/test_agentic.py | 6 +- tests/integration/agentic/test_cli.py | 17 +- .../lifecycle/test_protocol_robustness.py | 2 +- tests/replay.py | 2 +- tests/stress.py | 2 +- 21 files changed, 59 insertions(+), 307 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 924792642..8c296eb05 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,7 +6,7 @@ "request": "launch", "name": "Debug clice", "program": "${workspaceFolder}/build/Debug/bin/clice", - "args": ["server", "--mode", "socket", "--port", "50051"], + "args": ["serve", "--mode", "tcp", "--port", "50051"], "cwd": "${workspaceFolder}" }, { @@ -14,7 +14,7 @@ "request": "launch", "name": "Debug clice (socket, RelWithDebInfo)", "program": "${workspaceFolder}/build/RelWithDebInfo/bin/clice", - "args": ["server", "--mode", "socket", "--port", "50051"], + "args": ["serve", "--mode", "tcp", "--port", "50051"], "cwd": "${workspaceFolder}" }, { @@ -44,7 +44,7 @@ "--extensionDevelopmentPath=${workspaceFolder}/editors/vscode" ], "env": { - "CLICE_MODE": "socket" + "CLICE_MODE": "tcp" }, "outFiles": ["${workspaceFolder}/editors/vscode/dist/**/*.js"], "preLaunchTask": "npm: watch vscode ext" diff --git a/docs/en/dev/test-and-debug.md b/docs/en/dev/test-and-debug.md index 3fab5cd6d..c7d5c2fa6 100644 --- a/docs/en/dev/test-and-debug.md +++ b/docs/en/dev/test-and-debug.md @@ -25,7 +25,7 @@ Equivalent to: ### Integration Tests -End-to-end tests that start a real clice server and communicate via LSP protocol. +End-to-end tests that start a real clice serve and communicate via LSP protocol. ```bash pixi run integration-test # default RelWithDebInfo @@ -82,7 +82,7 @@ Prerequisites outside the pixi env: If you want to attach a debugger to clice, start it in socket mode independently, then connect a client. ```shell -./build/Debug/bin/clice server --mode socket --port 50051 +./build/Debug/bin/clice serve --mode tcp --port 50051 ``` After the server starts, you can connect a client in two ways: @@ -94,7 +94,7 @@ Run a single integration test against the running instance: ```shell pytest -s --log-cli-level=INFO \ tests/integration/lifecycle/test_file_operation.py::test_did_open \ - --mode=socket --port=50051 + --mode=tcp --port=50051 ``` ### Connect via VS Code @@ -108,7 +108,7 @@ Configure the clice extension to connect to your running instance: ```jsonc { "clice.executable": "/path/to/your/clice/executable", - "clice.mode": "socket", + "clice.mode": "tcp", "clice.port": 50051, // Optional: disable clangd if also installed "clangd.path": "", diff --git a/docs/en/guide/editors.md b/docs/en/guide/editors.md index 63991c5da..fbf0a6923 100644 --- a/docs/en/guide/editors.md +++ b/docs/en/guide/editors.md @@ -34,7 +34,7 @@ Add to `~/.config/helix/languages.toml`: ```toml [language-server.clice] command = "clice" -args = ["server"] +args = ["serve"] [[language]] name = "cpp" @@ -53,7 +53,7 @@ With the built-in eglot: (with-eval-after-load 'eglot (add-to-list 'eglot-server-programs '((c-mode c-ts-mode c++-mode c++-ts-mode) - . ("clice" "server")))) + . ("clice" "serve")))) ``` ### Sublime Text @@ -65,7 +65,7 @@ Install the [LSP package](https://packagecontrol.io/packages/LSP), then add to i "clients": { "clice": { "enabled": true, - "command": ["clice", "server"], + "command": ["clice", "serve"], "selector": "source.c | source.c++" } } @@ -80,7 +80,7 @@ Open `Settings → Configure Kate → LSP Client → User Server Settings` and a { "servers": { "c": { - "command": ["clice", "server"], + "command": ["clice", "serve"], "url": "https://github.com/clice-io/clice", "highlightingModeRegex": "^(C|C\\+\\+)$" } diff --git a/docs/zh/dev/test-and-debug.md b/docs/zh/dev/test-and-debug.md index eb80b9208..1180ec4bf 100644 --- a/docs/zh/dev/test-and-debug.md +++ b/docs/zh/dev/test-and-debug.md @@ -82,7 +82,7 @@ pixi 环境之外的依赖: 如果想在 clice 上附加调试器,推荐先以 socket 模式单独启动 clice,然后连接客户端。 ```shell -./build/Debug/bin/clice server --mode socket --port 50051 +./build/Debug/bin/clice serve --mode tcp --port 50051 ``` 服务器启动后,可以通过以下两种方式连接客户端: @@ -94,7 +94,7 @@ pixi 环境之外的依赖: ```shell pytest -s --log-cli-level=INFO \ tests/integration/lifecycle/test_file_operation.py::test_did_open \ - --mode=socket --port=50051 + --mode=tcp --port=50051 ``` ### 通过 VS Code 连接 @@ -108,7 +108,7 @@ pytest -s --log-cli-level=INFO \ ```jsonc { "clice.executable": "/path/to/your/clice/executable", - "clice.mode": "socket", + "clice.mode": "tcp", "clice.port": 50051, // 可选:禁用 clangd "clangd.path": "", diff --git a/docs/zh/guide/editors.md b/docs/zh/guide/editors.md index ae688c544..abbc79b92 100644 --- a/docs/zh/guide/editors.md +++ b/docs/zh/guide/editors.md @@ -34,7 +34,7 @@ Zed 扩展位于 [`editors/zed`](https://github.com/clice-io/clice/tree/main/edi ```toml [language-server.clice] command = "clice" -args = ["server"] +args = ["serve"] [[language]] name = "cpp" @@ -53,7 +53,7 @@ language-servers = ["clice"] (with-eval-after-load 'eglot (add-to-list 'eglot-server-programs '((c-mode c-ts-mode c++-mode c++-ts-mode) - . ("clice" "server")))) + . ("clice" "serve")))) ``` ### Sublime Text @@ -65,7 +65,7 @@ language-servers = ["clice"] "clients": { "clice": { "enabled": true, - "command": ["clice", "server"], + "command": ["clice", "serve"], "selector": "source.c | source.c++" } } @@ -80,7 +80,7 @@ language-servers = ["clice"] { "servers": { "c": { - "command": ["clice", "server"], + "command": ["clice", "serve"], "url": "https://github.com/clice-io/clice", "highlightingModeRegex": "^(C|C\\+\\+)$" } diff --git a/editors/vscode/package.json b/editors/vscode/package.json index d54b43239..d1c2e790c 100644 --- a/editors/vscode/package.json +++ b/editors/vscode/package.json @@ -46,9 +46,9 @@ "default": "pipe", "enum": [ "pipe", - "socket" + "tcp" ], - "description": "How to communicate with clice. pipe or socket. For daily use please use pipe." + "description": "How to communicate with clice. pipe (default) or tcp (debug)." }, "clice.host": { "type": "string", diff --git a/editors/vscode/src/extension.ts b/editors/vscode/src/extension.ts index 5f2bda203..3fd2bbd7c 100644 --- a/editors/vscode/src/extension.ts +++ b/editors/vscode/src/extension.ts @@ -45,12 +45,12 @@ export async function activate(context: ExtensionContext) { } } - let args = ["server"]; + let args = ["serve"]; serverOptions = { run: { command: executable, args: args }, debug: { command: executable, args: args }, }; - } else if (setting.mode === "socket") { + } else if (setting.mode === "tcp") { serverOptions = (): Promise => { return new Promise((resolve, reject) => { const client = new net.Socket(); @@ -66,7 +66,7 @@ export async function activate(context: ExtensionContext) { }); }; } else { - vscode.window.showErrorMessage("Invalid mode, please set the mode to 'pipe' or 'socket'."); + vscode.window.showErrorMessage("Invalid mode, please set the mode to 'pipe' or 'tcp'."); return; } diff --git a/editors/vscode/src/setting.ts b/editors/vscode/src/setting.ts index afac7843a..2abb2677a 100644 --- a/editors/vscode/src/setting.ts +++ b/editors/vscode/src/setting.ts @@ -12,7 +12,7 @@ export function getSetting(): Setting | undefined { const executable = process.env.CLICE_EXECUTABLE || setting.get("executable"); const mode = process.env.CLICE_MODE || setting.get("mode"); - if (mode !== "pipe" && mode !== "socket") { + if (mode !== "pipe" && mode !== "tcp") { vscode.window.showErrorMessage(`Unexpected mode: ${mode}`); return undefined; } @@ -20,8 +20,8 @@ export function getSetting(): Setting | undefined { const host = setting.get("host")!; const port = setting.get("port")!; - if (mode === "socket" && (!host || !port)) { - vscode.window.showErrorMessage("Socket mode requires both host and port to be configured."); + if (mode === "tcp" && (!host || !port)) { + vscode.window.showErrorMessage("TCP mode requires both host and port to be configured."); return undefined; } diff --git a/editors/zed/src/clice.rs b/editors/zed/src/clice.rs index b99505733..68b4249c9 100644 --- a/editors/zed/src/clice.rs +++ b/editors/zed/src/clice.rs @@ -33,7 +33,7 @@ impl zed::Extension for CliceExtension { Ok(zed::Command { command: binary.path, args: vec![ - "server".to_string(), + "serve".to_string(), ], env: Default::default(), }) diff --git a/src/clice.cc b/src/clice.cc index 012d3b4f9..e807a6405 100644 --- a/src/clice.cc +++ b/src/clice.cc @@ -84,30 +84,17 @@ int main(int argc, const char** argv) { int exit_code = 1; - auto server_cmd = deco::cli::command("clice server [OPTIONS]"); - server_cmd + auto serve_cmd = deco::cli::command("clice serve [OPTIONS]"); + serve_cmd .matchAll([&](clice::ServerOptions opts) { if(opts.help) { - clice::print_usage(server_cmd); + clice::print_usage(serve_cmd); exit_code = 0; return; } if(!clice::apply_log_level(opts.log_level.value_or("info"))) return; - using clice::ServerMode; - auto mode = opts.mode.value_or(ServerMode::Pipe); - if(mode == ServerMode::Relay) { - exit_code = clice::run_relay_mode(opts.socket.value_or("")); - } else if(mode == ServerMode::Daemon) { - auto workspace = opts.workspace.value_or(""); - if(workspace.empty()) { - LOG_ERROR("--workspace is required for daemon mode"); - return; - } - exit_code = clice::run_daemon_mode(opts, self_path); - } else { - exit_code = clice::run_server_mode(opts, self_path); - } + exit_code = clice::run_serve_mode(opts, self_path); }) .on_error([](auto err) { LOG_ERROR("{}", err.message); }); @@ -181,7 +168,7 @@ int main(int argc, const char** argv) { clice::print_usage(clice); }; - clice.add({.name = "server", .description = "Start LSP server"}, server_cmd) + clice.add({.name = "serve", .description = "Start LSP server"}, serve_cmd) .add({.name = "query", .description = "Query symbol information from a running server"}, query_cmd) .add({.name = "worker"}, worker_cmd) diff --git a/src/server/service/agentic.cpp b/src/server/service/agentic.cpp index 33fed3c73..6476f852c 100644 --- a/src/server/service/agentic.cpp +++ b/src/server/service/agentic.cpp @@ -5,7 +5,6 @@ #include #include "server/protocol/agentic.h" -#include "support/filesystem.h" #include "support/logging.h" #include "kota/async/async.h" @@ -126,48 +125,4 @@ int run_agentic_mode(const QueryOptions& opts) { return exit_code; } -static kota::task<> relay_forward(kota::ipc::Transport& from, kota::ipc::Transport& to) { - while(true) { - auto msg = co_await from.read_message(); - if(!msg) - break; - co_await to.write_message(*msg); - } - to.close(); -} - -static kota::task<> relay_main(kota::event_loop& loop, int& exit_code, std::string socket_path) { - auto stdio = kota::ipc::StreamTransport::open_stdio(loop); - if(!stdio) { - LOG_ERROR("failed to open stdio transport"); - loop.stop(); - co_return; - } - - auto conn = co_await kota::pipe::connect(socket_path, {}, loop); - if(!conn) { - LOG_ERROR("failed to connect to {}", socket_path); - loop.stop(); - co_return; - } - - auto socket = std::make_unique(std::move(*conn)); - - co_await kota::when_all(relay_forward(**stdio, *socket), relay_forward(*socket, **stdio)); - exit_code = 0; - loop.stop(); -} - -int run_relay_mode(llvm::StringRef socket_path) { - logging::stderr_logger("relay", logging::options); - - auto path = socket_path.empty() ? path::default_socket_path() : socket_path.str(); - - kota::event_loop loop; - int exit_code = 1; - loop.schedule(relay_main(loop, exit_code, std::move(path))); - loop.run(); - return exit_code; -} - } // namespace clice diff --git a/src/server/service/agentic.h b/src/server/service/agentic.h index 8d3926449..806fc8bf3 100644 --- a/src/server/service/agentic.h +++ b/src/server/service/agentic.h @@ -60,6 +60,4 @@ struct QueryOptions { int run_agentic_mode(const QueryOptions& opts); -int run_relay_mode(llvm::StringRef socket_path); - } // namespace clice diff --git a/src/server/service/master_server.cpp b/src/server/service/master_server.cpp index 1ab4e33a5..188fd43ee 100644 --- a/src/server/service/master_server.cpp +++ b/src/server/service/master_server.cpp @@ -1,18 +1,10 @@ #include "server/service/master_server.h" -#include -#include #include #include #include #include -#ifndef _WIN32 -#include -#include -#include -#endif - #include "server/protocol/worker.h" #include "server/service/agent_client.h" #include "server/service/lsp_client.h" @@ -20,7 +12,6 @@ #include "support/logging.h" #include "kota/async/async.h" -#include "kota/async/io/fs_event.h" #include "kota/codec/json/json.h" #include "kota/ipc/codec/json.h" #include "kota/ipc/lsp/protocol.h" @@ -121,42 +112,6 @@ void MasterServer::initialize(llvm::StringRef root) { initialize(); } -kota::task<> MasterServer::file_watcher_task() { - auto watcher = kota::fs_event::create(workspace_root, {}, loop); - if(!watcher) { - LOG_WARN("Failed to start file watcher for {}", workspace_root); - co_return; - } - - LOG_INFO("File watcher started for {}", workspace_root); - - while(true) { - auto changes = co_await watcher->next(); - if(!changes) - break; - - for(auto& change: *changes) { - if(change.type != kota::fs_event::effect::modify && - change.type != kota::fs_event::effect::create) - continue; - - llvm::StringRef file(change.path); - if(file.ends_with("compile_commands.json")) { - LOG_INFO("CDB changed, reloading workspace"); - load_workspace(); - continue; - } - - if(file.ends_with(".cpp") || file.ends_with(".cc") || file.ends_with(".cxx") || - file.ends_with(".c") || file.ends_with(".h") || file.ends_with(".hpp") || - file.ends_with(".hxx") || file.ends_with(".cppm") || file.ends_with(".ixx")) { - auto path_id = workspace.path_pool.intern(file); - on_file_saved(path_id); - } - } - } -} - std::shared_ptr MasterServer::find_session(std::uint32_t path_id) { auto it = sessions.find(path_id); return it != sessions.end() ? it->second : nullptr; @@ -446,18 +401,23 @@ static kota::task<> accept_connections(MasterServer& server, co_await group.join(); } -int run_server_mode(const ServerOptions& opts, const char* self_path) { +int run_serve_mode(const ServerOptions& opts, const char* self_path) { logging::stderr_logger("master", logging::options); auto mode = opts.mode.value_or(ServerMode::Pipe); auto host = opts.host.value_or("127.0.0.1"); auto port = opts.port.value_or(0); auto record = opts.record.value_or(""); + auto ws = opts.workspace.value_or(""); kota::event_loop loop; MasterServer server(loop, self_path); std::list connections; + // Pre-initialize for standalone (no-editor) use; LSP initialize will be rejected. + if(!ws.empty()) + server.initialize(ws); + if(mode == ServerMode::Pipe) { auto transport = kota::ipc::StreamTransport::open_stdio(loop); if(!transport) { @@ -507,7 +467,7 @@ int run_server_mode(const ServerOptions& opts, const char* self_path) { return 0; } - if(mode == ServerMode::Socket) { + if(mode == ServerMode::Tcp) { auto acceptor = kota::tcp::listen(host, port, {}, loop); if(!acceptor) { LOG_ERROR("failed to listen on {}:{}", host, port); @@ -531,126 +491,4 @@ int run_server_mode(const ServerOptions& opts, const char* self_path) { return 1; } -struct DaemonConnection { - std::unique_ptr peer; - std::unique_ptr agent_client; -}; - -static kota::task<> run_daemon_connection(kota::ipc::JsonPeer* peer, - std::list& connections, - std::list::iterator pos) { - co_await peer->run(); - LOG_INFO("Daemon client disconnected"); - connections.erase(pos); -} - -static kota::task<> daemon_accept(MasterServer& server, kota::pipe::acceptor acceptor) { - auto& loop = kota::event_loop::current(); - std::list connections; - kota::task_group<> group(loop); - group.spawn([](MasterServer& server, - kota::pipe::acceptor& acceptor, - std::list& connections, - kota::task_group<>& group) -> kota::task<> { - auto& loop = kota::event_loop::current(); - - while(true) { - auto conn = co_await acceptor.accept(); - if(!conn.has_value()) - break; - - LOG_INFO("Daemon client connected"); - - auto transport = std::make_unique(std::move(*conn)); - auto peer = std::make_unique(loop, std::move(transport)); - auto agent = std::make_unique(server, *peer); - - auto* peer_ptr = peer.get(); - auto it = connections.emplace(connections.end(), - DaemonConnection{ - .peer = std::move(peer), - .agent_client = std::move(agent), - }); - - group.spawn(run_daemon_connection(peer_ptr, connections, it)); - } - }(server, acceptor, connections, group)); - - co_await group.join(); -} - -static kota::task<> resilient_file_watcher(MasterServer& server) { - co_await server.file_watcher_task(); - co_await server.get_shutdown_event().wait(); -} - -static kota::task<> daemon_main(MasterServer& server, - kota::pipe::acceptor acceptor, - bool watch_files) { - if(watch_files) { - co_await kota::when_any(daemon_accept(server, std::move(acceptor)), - resilient_file_watcher(server), - server.get_shutdown_event().wait()); - } else { - co_await kota::when_any(daemon_accept(server, std::move(acceptor)), - server.get_shutdown_event().wait()); - } - co_await server.shutdown_and_cleanup(); -} - -int run_daemon_mode(const ServerOptions& opts, const char* self_path) { - logging::stderr_logger("daemon", logging::options); - - auto sock = opts.socket.value_or(""); - auto socket_path = sock.empty() ? path::default_socket_path() : sock; - auto ws = opts.workspace.value_or(""); - - auto socket_dir = llvm::sys::path::parent_path(socket_path); - if(auto ec = llvm::sys::fs::create_directories(socket_dir)) { - LOG_ERROR("Failed to create socket directory {}: {}", socket_dir, ec.message()); - return 1; - } - - if(llvm::sys::fs::exists(socket_path)) { -#ifndef _WIN32 - int fd = ::socket(AF_UNIX, SOCK_STREAM, 0); - if(fd >= 0) { - struct sockaddr_un addr{}; - addr.sun_family = AF_UNIX; - auto len = std::min(socket_path.size(), sizeof(addr.sun_path) - 1); - std::memcpy(addr.sun_path, socket_path.data(), len); - bool live = ::connect(fd, reinterpret_cast(&addr), sizeof(addr)) == 0; - ::close(fd); - if(live) { - LOG_ERROR("Another daemon is already running on {}", socket_path); - return 1; - } - } -#endif - llvm::sys::fs::remove(socket_path); - } - - kota::event_loop loop; - MasterServer server(loop, self_path); - - bool watch_files = false; - if(!ws.empty()) { - server.initialize(ws); - watch_files = true; - } - - auto acceptor = kota::pipe::listen(socket_path, {}, loop); - if(!acceptor) { - LOG_ERROR("Failed to listen on {}", socket_path); - return 1; - } - - LOG_INFO("Daemon listening on {}", socket_path); - loop.schedule(daemon_main(server, std::move(*acceptor), watch_files)); - loop.run(); - - llvm::sys::fs::remove(socket_path); - return 0; -} - } // namespace clice diff --git a/src/server/service/master_server.h b/src/server/service/master_server.h index c5b8bdfc1..d8c45f48f 100644 --- a/src/server/service/master_server.h +++ b/src/server/service/master_server.h @@ -18,24 +18,24 @@ namespace clice { namespace deco = kota::deco; -enum class ServerMode : std::uint8_t { Pipe, Socket, Relay, Daemon }; +enum class ServerMode : std::uint8_t { Pipe, Tcp }; struct ServerOptions { DecoFlag(names = {"-h", "--help"}, help = "Show help", required = false) help; DecoKV(style = deco::decl::KVStyle::JoinedOrSeparate, - help = "Server mode: pipe (default), socket, relay, or daemon", + help = "Server mode: pipe (default) or tcp (debug)", required = false) mode = ServerMode::Pipe; DecoKV(style = deco::decl::KVStyle::JoinedOrSeparate, - help = "Socket mode address", + help = "TCP listen address", required = false) host = "127.0.0.1"; DecoKV(style = deco::decl::KVStyle::JoinedOrSeparate, - help = "Agentic TCP port (0 = disabled)", + help = "TCP port (pipe mode: agentic only; tcp mode: LSP + agentic)", required = false) port = 0; @@ -45,12 +45,7 @@ struct ServerOptions { record; DecoKV(style = deco::decl::KVStyle::JoinedOrSeparate, - help = "Unix domain socket path (relay/daemon mode)", - required = false) - socket; - - DecoKV(style = deco::decl::KVStyle::JoinedOrSeparate, - help = "Workspace root directory (daemon mode)", + help = "Workspace root directory (optional, skips LSP initialize)", required = false) workspace; @@ -85,7 +80,7 @@ class MasterServer { void initialize(); void initialize(llvm::StringRef root); - kota::task<> file_watcher_task(); + // TODO: add periodic stat-based file watching kota::task<> shutdown_and_cleanup(); std::shared_ptr find_session(std::uint32_t path_id); @@ -131,8 +126,6 @@ class MasterServer { std::string init_options_json; }; -int run_server_mode(const ServerOptions& opts, const char* self_path); - -int run_daemon_mode(const ServerOptions& opts, const char* self_path); +int run_serve_mode(const ServerOptions& opts, const char* self_path); } // namespace clice diff --git a/src/support/filesystem.h b/src/support/filesystem.h index 2b9eae7f3..174a70e38 100644 --- a/src/support/filesystem.h +++ b/src/support/filesystem.h @@ -37,14 +37,6 @@ inline std::string real_path(llvm::StringRef file) { return path.str().str(); } -inline std::string default_socket_path() { - llvm::SmallString<128> home; - if(!llvm::sys::path::home_directory(home)) - return "/tmp/clice.sock"; - llvm::sys::path::append(home, ".clice", "clice.sock"); - return home.str().str(); -} - } // namespace path namespace fs { diff --git a/tests/conftest.py b/tests/conftest.py index 2a2e223c6..9871ef685 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -19,7 +19,7 @@ def pytest_addoption(parser: pytest.Parser) -> None: parser.addoption( "--mode", type=str, - choices=["pipe", "socket"], + choices=["pipe", "tcp"], default="pipe", help="The connection mode to use.", ) @@ -102,7 +102,7 @@ async def client( mode = config.getoption("--mode") host = config.getoption("--host") - cmd = [str(executable), "server", "--mode", mode, "--host", host] + cmd = [str(executable), "serve", "--mode", mode, "--host", host] c = CliceClient() await c.start_io(*cmd) @@ -136,7 +136,7 @@ async def agentic( """Start a server with agentic TCP port, yield (executable, host, port).""" host = "127.0.0.1" port = find_free_port() - cmd = [str(executable), "server", "--host", host, "--port", str(port)] + cmd = [str(executable), "serve", "--host", host, "--port", str(port)] c = CliceClient() await c.start_io(*cmd) @@ -157,7 +157,7 @@ async def agentic( async def make_client(executable: Path, workspace: Path) -> CliceClient: """Spawn a fresh clice server and initialize it. For multi-session tests.""" c = CliceClient() - await c.start_io(str(executable), "server") + await c.start_io(str(executable), "serve") await c.initialize(workspace) return c diff --git a/tests/integration/agentic/test_agentic.py b/tests/integration/agentic/test_agentic.py index 29318951a..073c0007d 100644 --- a/tests/integration/agentic/test_agentic.py +++ b/tests/integration/agentic/test_agentic.py @@ -147,7 +147,7 @@ async def indexed_agentic(request, executable, workspace): host = "127.0.0.1" port = find_free_port() - cmd = [str(executable), "server", "--host", host, "--port", str(port)] + cmd = [str(executable), "serve", "--host", host, "--port", str(port)] c = CliceClient() await c.start_io(*cmd) @@ -427,7 +427,7 @@ async def test_rpc_shutdown(executable, workspace): host = "127.0.0.1" port = find_free_port() - cmd = [str(executable), "server", "--host", host, "--port", str(port)] + cmd = [str(executable), "serve", "--host", host, "--port", str(port)] c = CliceClient() await c.start_io(*cmd) @@ -551,7 +551,7 @@ async def test_shutdown_during_indexing(executable, tmp_path): host = "127.0.0.1" port = find_free_port() - cmd = [str(executable), "server", "--host", host, "--port", str(port)] + cmd = [str(executable), "serve", "--host", host, "--port", str(port)] c = CliceClient() await c.start_io(*cmd) diff --git a/tests/integration/agentic/test_cli.py b/tests/integration/agentic/test_cli.py index 251208e70..627b463f9 100644 --- a/tests/integration/agentic/test_cli.py +++ b/tests/integration/agentic/test_cli.py @@ -35,7 +35,7 @@ async def indexed_server(request, executable, workspace): host = "127.0.0.1" port = find_free_port() - cmd = [str(executable), "server", "--host", host, "--port", str(port)] + cmd = [str(executable), "serve", "--host", host, "--port", str(port)] c = CliceClient() await c.start_io(*cmd) @@ -192,23 +192,13 @@ async def test_cli_status(indexed_server, workspace): # --- Server mode and CLI entry point tests --- -def test_daemon_requires_workspace(executable): - r = subprocess.run( - [str(executable), "server", "--mode", "daemon"], - capture_output=True, - text=True, - timeout=5, - ) - assert r.returncode != 0 - - @pytest.mark.workspace("hello_world") -async def test_socket_mode_connects(executable, workspace): +async def test_tcp_mode_connects(executable, workspace): from tests.conftest import find_free_port, shutdown_client from tests.integration.utils.client import CliceClient port = find_free_port() - cmd = [str(executable), "server", "--mode", "socket", "--port", str(port)] + cmd = [str(executable), "serve", "--mode", "tcp", "--port", str(port)] proc = await asyncio.create_subprocess_exec( *cmd, stdin=asyncio.subprocess.PIPE, @@ -218,7 +208,6 @@ async def test_socket_mode_connects(executable, workspace): try: c = CliceClient() - # Retry until the server starts listening (slow on Debug builds). for _ in range(150): assert proc.returncode is None, "server exited before accepting connections" try: diff --git a/tests/integration/lifecycle/test_protocol_robustness.py b/tests/integration/lifecycle/test_protocol_robustness.py index 50271d7e2..d3d00f29b 100644 --- a/tests/integration/lifecycle/test_protocol_robustness.py +++ b/tests/integration/lifecycle/test_protocol_robustness.py @@ -58,7 +58,7 @@ async def test_initialize_hostile_params(executable, workspace, mode): proc = await asyncio.create_subprocess_exec( str(executable), - "server", + "serve", stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.DEVNULL, diff --git a/tests/replay.py b/tests/replay.py index ba3a369f4..45bd690fb 100644 --- a/tests/replay.py +++ b/tests/replay.py @@ -138,7 +138,7 @@ async def replay_one( proc = await asyncio.create_subprocess_exec( str(clice_bin), - "server", + "serve", env=env, stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE, diff --git a/tests/stress.py b/tests/stress.py index 2c6bd876c..4730f6f71 100644 --- a/tests/stress.py +++ b/tests/stress.py @@ -274,7 +274,7 @@ async def run_stress_test(args): init_options["project"]["min_stateless_worker_count"] = args.min_stateless client = CliceClient() - await client.start_io(str(executable), "server") + await client.start_io(str(executable), "serve") server = getattr(client, "_server", None) start_time = time.monotonic() From 09c903960b348065c9cbfb5f1586686bc77d7c20 Mon Sep 17 00:00:00 2001 From: ykiko Date: Mon, 29 Jun 2026 02:01:47 +0800 Subject: [PATCH 2/7] fix: address review feedback from CodeRabbit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix stale launch.json label (socket → tcp) - Update nvim editor references (server → serve) - Fix docs: "socket mode" → "tcp mode", backtick clice serve - Add socket → tcp compat alias in VS Code extension settings - Validate --port range for tcp mode - Defer server.initialize(ws) until after transport setup succeeds --- .vscode/launch.json | 2 +- docs/en/dev/test-and-debug.md | 8 ++++---- docs/zh/dev/test-and-debug.md | 4 ++-- editors/nvim/doc/clice.lua | 2 +- editors/nvim/tests/e2e.lua | 2 +- editors/vscode/src/setting.ts | 3 ++- src/server/service/master_server.cpp | 16 ++++++++++++---- 7 files changed, 23 insertions(+), 14 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 8c296eb05..8efed19b0 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -12,7 +12,7 @@ { "type": "lldb", "request": "launch", - "name": "Debug clice (socket, RelWithDebInfo)", + "name": "Debug clice (tcp, RelWithDebInfo)", "program": "${workspaceFolder}/build/RelWithDebInfo/bin/clice", "args": ["serve", "--mode", "tcp", "--port", "50051"], "cwd": "${workspaceFolder}" diff --git a/docs/en/dev/test-and-debug.md b/docs/en/dev/test-and-debug.md index c7d5c2fa6..00140cde8 100644 --- a/docs/en/dev/test-and-debug.md +++ b/docs/en/dev/test-and-debug.md @@ -25,7 +25,7 @@ Equivalent to: ### Integration Tests -End-to-end tests that start a real clice serve and communicate via LSP protocol. +End-to-end tests that start a real `clice serve` instance and communicate via LSP protocol. ```bash pixi run integration-test # default RelWithDebInfo @@ -79,7 +79,7 @@ Prerequisites outside the pixi env: ## Debug -If you want to attach a debugger to clice, start it in socket mode independently, then connect a client. +If you want to attach a debugger to clice, start it in tcp mode independently, then connect a client. ```shell ./build/Debug/bin/clice serve --mode tcp --port 50051 @@ -130,6 +130,6 @@ The extension lives in-tree at `editors/vscode/`: 2. Open the **repository root** in VS Code (the launch configurations are in `.vscode/launch.json` at the root). -3. Create `.vscode/settings.json` with the socket config above. +3. Create `.vscode/settings.json` with the tcp config above. -4. Press `F5` and select `VSCode Extension (pipe)` or `VSCode Extension (socket)` to launch an Extension Development Host window. +4. Press `F5` and select `VSCode Extension (pipe)` or `VSCode Extension (tcp)` to launch an Extension Development Host window. diff --git a/docs/zh/dev/test-and-debug.md b/docs/zh/dev/test-and-debug.md index 1180ec4bf..a9df72f01 100644 --- a/docs/zh/dev/test-and-debug.md +++ b/docs/zh/dev/test-and-debug.md @@ -79,7 +79,7 @@ pixi 环境之外的依赖: ## 调试 -如果想在 clice 上附加调试器,推荐先以 socket 模式单独启动 clice,然后连接客户端。 +如果想在 clice 上附加调试器,推荐先以 tcp 模式单独启动 clice,然后连接客户端。 ```shell ./build/Debug/bin/clice serve --mode tcp --port 50051 @@ -130,6 +130,6 @@ pytest -s --log-cli-level=INFO \ 2. 用 VS Code 打开 `editors/vscode`。 -3. 创建上述 socket 配置的 `.vscode/settings.json`。 +3. 创建上述 tcp 配置的 `.vscode/settings.json`。 4. 按 `F5` 启动扩展开发宿主窗口。 diff --git a/editors/nvim/doc/clice.lua b/editors/nvim/doc/clice.lua index b4689f058..e562e65a2 100644 --- a/editors/nvim/doc/clice.lua +++ b/editors/nvim/doc/clice.lua @@ -25,7 +25,7 @@ local clice = { cmd = { 'clice', - 'server', + 'serve', }, } diff --git a/editors/nvim/tests/e2e.lua b/editors/nvim/tests/e2e.lua index 38bb21e8f..5616a0cc0 100644 --- a/editors/nvim/tests/e2e.lua +++ b/editors/nvim/tests/e2e.lua @@ -55,7 +55,7 @@ end local plugin_root = vim.fn.fnamemodify(arg[0], ':p:h:h') local config = dofile(plugin_root .. '/doc/clice.lua') config.name = 'clice' -config.cmd = { clice_path, 'server' } +config.cmd = { clice_path, 'serve' } config.root_dir = fixture_dir local main_file_uri = vim.uri_from_fname(fixture_dir .. '/' .. scenario.file) diff --git a/editors/vscode/src/setting.ts b/editors/vscode/src/setting.ts index 2abb2677a..ae193e058 100644 --- a/editors/vscode/src/setting.ts +++ b/editors/vscode/src/setting.ts @@ -10,7 +10,8 @@ interface Setting { export function getSetting(): Setting | undefined { const setting = vscode.workspace.getConfiguration("clice"); const executable = process.env.CLICE_EXECUTABLE || setting.get("executable"); - const mode = process.env.CLICE_MODE || setting.get("mode"); + const configuredMode = process.env.CLICE_MODE || setting.get("mode"); + const mode = configuredMode === "socket" ? "tcp" : configuredMode; if (mode !== "pipe" && mode !== "tcp") { vscode.window.showErrorMessage(`Unexpected mode: ${mode}`); diff --git a/src/server/service/master_server.cpp b/src/server/service/master_server.cpp index 188fd43ee..643c52990 100644 --- a/src/server/service/master_server.cpp +++ b/src/server/service/master_server.cpp @@ -410,14 +410,15 @@ int run_serve_mode(const ServerOptions& opts, const char* self_path) { auto record = opts.record.value_or(""); auto ws = opts.workspace.value_or(""); + if(mode == ServerMode::Tcp && (port <= 0 || port > 65535)) { + LOG_ERROR("--port must be between 1 and 65535 in tcp mode"); + return 1; + } + kota::event_loop loop; MasterServer server(loop, self_path); std::list connections; - // Pre-initialize for standalone (no-editor) use; LSP initialize will be rejected. - if(!ws.empty()) - server.initialize(ws); - if(mode == ServerMode::Pipe) { auto transport = kota::ipc::StreamTransport::open_stdio(loop); if(!transport) { @@ -425,6 +426,10 @@ int run_serve_mode(const ServerOptions& opts, const char* self_path) { return 1; } + // Pre-initialize for standalone (no-editor) use; LSP initialize will be rejected. + if(!ws.empty()) + server.initialize(ws); + std::unique_ptr final_transport = std::move(*transport); if(!record.empty()) { final_transport = @@ -474,6 +479,9 @@ int run_serve_mode(const ServerOptions& opts, const char* self_path) { return 1; } + if(!ws.empty()) + server.initialize(ws); + LOG_INFO("Listening on {}:{} ...", host, port); loop.schedule([](MasterServer& server, kota::tcp::acceptor acceptor, From 0032aed48f2b517690c75d93d88e690bf1be17d2 Mon Sep 17 00:00:00 2001 From: ykiko Date: Mon, 29 Jun 2026 02:13:26 +0800 Subject: [PATCH 3/7] fix(server): skip LSP registration in tcp+workspace mode When --workspace pre-initializes the server, TCP connections are agentic-only. Don't consume the LSP slot for query clients. --- src/server/service/master_server.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/server/service/master_server.cpp b/src/server/service/master_server.cpp index 643c52990..5d38bea50 100644 --- a/src/server/service/master_server.cpp +++ b/src/server/service/master_server.cpp @@ -482,15 +482,17 @@ int run_serve_mode(const ServerOptions& opts, const char* self_path) { if(!ws.empty()) server.initialize(ws); + bool register_lsp = ws.empty(); LOG_INFO("Listening on {}:{} ...", host, port); loop.schedule([](MasterServer& server, kota::tcp::acceptor acceptor, + bool register_lsp, std::list& connections) -> kota::task<> { co_await kota::when_any( - accept_connections(server, std::move(acceptor), true, connections), + accept_connections(server, std::move(acceptor), register_lsp, connections), server.get_shutdown_event().wait()); co_await server.shutdown_and_cleanup(); - }(server, std::move(*acceptor), connections)); + }(server, std::move(*acceptor), register_lsp, connections)); loop.run(); return 0; } From f8efbbe26afa1078c9ab79cd82e5c1324f0ab855 Mon Sep 17 00:00:00 2001 From: ykiko Date: Mon, 29 Jun 2026 05:44:54 +0800 Subject: [PATCH 4/7] fix(tests): remove unused --mode pytest option The test fixture always uses pipe mode via start_io(). The --mode flag was never properly wired for tcp and would cause hangs. --- tests/conftest.py | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 9871ef685..54b393eba 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -16,25 +16,12 @@ def pytest_addoption(parser: pytest.Parser) -> None: required=False, help="Path to the clice executable.", ) - parser.addoption( - "--mode", - type=str, - choices=["pipe", "tcp"], - default="pipe", - help="The connection mode to use.", - ) parser.addoption( "--host", type=str, default="127.0.0.1", help="The host to connect to (default: 127.0.0.1)", ) - parser.addoption( - "--port", - type=int, - default=50051, - help="The port to connect to", - ) @pytest.fixture(scope="session") @@ -98,11 +85,7 @@ async def client( workspace: Path | None, ): """Spawn clice server, auto-initialize if @pytest.mark.workspace is present.""" - config = request.config - mode = config.getoption("--mode") - host = config.getoption("--host") - - cmd = [str(executable), "serve", "--mode", mode, "--host", host] + cmd = [str(executable), "serve"] c = CliceClient() await c.start_io(*cmd) From 55ef9849ecc3e02e04081995eef1f812180a1bae Mon Sep 17 00:00:00 2001 From: ykiko Date: Mon, 29 Jun 2026 13:47:21 +0800 Subject: [PATCH 5/7] docs: remove stale pytest TCP attach workflow The --mode and --port pytest options were removed since tests always use pipe mode. Remove the corresponding documentation section. --- docs/en/dev/test-and-debug.md | 10 ---------- docs/zh/dev/test-and-debug.md | 10 ---------- 2 files changed, 20 deletions(-) diff --git a/docs/en/dev/test-and-debug.md b/docs/en/dev/test-and-debug.md index 00140cde8..3c693a2a9 100644 --- a/docs/en/dev/test-and-debug.md +++ b/docs/en/dev/test-and-debug.md @@ -87,16 +87,6 @@ If you want to attach a debugger to clice, start it in tcp mode independently, t After the server starts, you can connect a client in two ways: -### Connect via pytest - -Run a single integration test against the running instance: - -```shell -pytest -s --log-cli-level=INFO \ - tests/integration/lifecycle/test_file_operation.py::test_did_open \ - --mode=tcp --port=50051 -``` - ### Connect via VS Code Configure the clice extension to connect to your running instance: diff --git a/docs/zh/dev/test-and-debug.md b/docs/zh/dev/test-and-debug.md index a9df72f01..262aa890e 100644 --- a/docs/zh/dev/test-and-debug.md +++ b/docs/zh/dev/test-and-debug.md @@ -87,16 +87,6 @@ pixi 环境之外的依赖: 服务器启动后,可以通过以下两种方式连接客户端: -### 通过 pytest 连接 - -运行单个集成测试连接到正在运行的 clice 实例: - -```shell -pytest -s --log-cli-level=INFO \ - tests/integration/lifecycle/test_file_operation.py::test_did_open \ - --mode=tcp --port=50051 -``` - ### 通过 VS Code 连接 配置 clice 插件连接到正在运行的实例: From a66491cd3dca9bb735dc51cb78216ae8a6461228 Mon Sep 17 00:00:00 2001 From: ykiko Date: Mon, 29 Jun 2026 13:59:23 +0800 Subject: [PATCH 6/7] docs: update README to use serve subcommand --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 39eb055e9..543eff9fd 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Download the latest binary from the [releases page](https://github.com/clice-io/ | **VS Code** | Install the [clice extension](https://marketplace.visualstudio.com/items?itemName=ykiko.clice-vscode) from the Marketplace | | **Neovim** | Add `editors/nvim` to your runtime path: `vim.opt.rtp:append("/path/to/clice/editors/nvim")` | | **Zed** | Load `editors/zed` as a local extension | -| **Other** | Any LSP client works — point it at `clice server` | +| **Other** | Any LSP client works — point it at `clice serve` | ### Project Setup From 6828c976cb00feb632e3998b12f7082ad0c034fe Mon Sep 17 00:00:00 2001 From: ykiko Date: Mon, 29 Jun 2026 17:05:50 +0800 Subject: [PATCH 7/7] =?UTF-8?q?refactor:=20revert=20socket=E2=86=92tcp=20r?= =?UTF-8?q?ename,=20keep=20original=20mode=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The socket mode name was already established and changing it to tcp introduced unnecessary breaking changes for existing users. --- .vscode/launch.json | 6 +++--- docs/en/dev/test-and-debug.md | 8 ++++---- docs/zh/dev/test-and-debug.md | 8 ++++---- editors/vscode/package.json | 4 ++-- editors/vscode/src/extension.ts | 4 ++-- editors/vscode/src/setting.ts | 9 ++++----- src/server/service/master_server.cpp | 6 +++--- src/server/service/master_server.h | 8 ++++---- tests/conftest.py | 6 ------ tests/integration/agentic/test_cli.py | 4 ++-- 10 files changed, 28 insertions(+), 35 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 8efed19b0..50d3b4989 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,7 +6,7 @@ "request": "launch", "name": "Debug clice", "program": "${workspaceFolder}/build/Debug/bin/clice", - "args": ["serve", "--mode", "tcp", "--port", "50051"], + "args": ["serve", "--mode", "socket", "--port", "50051"], "cwd": "${workspaceFolder}" }, { @@ -14,7 +14,7 @@ "request": "launch", "name": "Debug clice (tcp, RelWithDebInfo)", "program": "${workspaceFolder}/build/RelWithDebInfo/bin/clice", - "args": ["serve", "--mode", "tcp", "--port", "50051"], + "args": ["serve", "--mode", "socket", "--port", "50051"], "cwd": "${workspaceFolder}" }, { @@ -44,7 +44,7 @@ "--extensionDevelopmentPath=${workspaceFolder}/editors/vscode" ], "env": { - "CLICE_MODE": "tcp" + "CLICE_MODE": "socket" }, "outFiles": ["${workspaceFolder}/editors/vscode/dist/**/*.js"], "preLaunchTask": "npm: watch vscode ext" diff --git a/docs/en/dev/test-and-debug.md b/docs/en/dev/test-and-debug.md index 3c693a2a9..8b5df6bfd 100644 --- a/docs/en/dev/test-and-debug.md +++ b/docs/en/dev/test-and-debug.md @@ -79,10 +79,10 @@ Prerequisites outside the pixi env: ## Debug -If you want to attach a debugger to clice, start it in tcp mode independently, then connect a client. +If you want to attach a debugger to clice, start it in socket mode independently, then connect a client. ```shell -./build/Debug/bin/clice serve --mode tcp --port 50051 +./build/Debug/bin/clice serve --mode socket --port 50051 ``` After the server starts, you can connect a client in two ways: @@ -98,7 +98,7 @@ Configure the clice extension to connect to your running instance: ```jsonc { "clice.executable": "/path/to/your/clice/executable", - "clice.mode": "tcp", + "clice.mode": "socket", "clice.port": 50051, // Optional: disable clangd if also installed "clangd.path": "", @@ -122,4 +122,4 @@ The extension lives in-tree at `editors/vscode/`: 3. Create `.vscode/settings.json` with the tcp config above. -4. Press `F5` and select `VSCode Extension (pipe)` or `VSCode Extension (tcp)` to launch an Extension Development Host window. +4. Press `F5` and select `VSCode Extension (pipe)` or `VSCode Extension (socket)` to launch an Extension Development Host window. diff --git a/docs/zh/dev/test-and-debug.md b/docs/zh/dev/test-and-debug.md index 262aa890e..9d5a1cd4f 100644 --- a/docs/zh/dev/test-and-debug.md +++ b/docs/zh/dev/test-and-debug.md @@ -79,10 +79,10 @@ pixi 环境之外的依赖: ## 调试 -如果想在 clice 上附加调试器,推荐先以 tcp 模式单独启动 clice,然后连接客户端。 +如果想在 clice 上附加调试器,推荐先以 socket 模式单独启动 clice,然后连接客户端。 ```shell -./build/Debug/bin/clice serve --mode tcp --port 50051 +./build/Debug/bin/clice serve --mode socket --port 50051 ``` 服务器启动后,可以通过以下两种方式连接客户端: @@ -98,7 +98,7 @@ pixi 环境之外的依赖: ```jsonc { "clice.executable": "/path/to/your/clice/executable", - "clice.mode": "tcp", + "clice.mode": "socket", "clice.port": 50051, // 可选:禁用 clangd "clangd.path": "", @@ -120,6 +120,6 @@ pixi 环境之外的依赖: 2. 用 VS Code 打开 `editors/vscode`。 -3. 创建上述 tcp 配置的 `.vscode/settings.json`。 +3. 创建上述 socket 配置的 `.vscode/settings.json`。 4. 按 `F5` 启动扩展开发宿主窗口。 diff --git a/editors/vscode/package.json b/editors/vscode/package.json index d1c2e790c..d54b43239 100644 --- a/editors/vscode/package.json +++ b/editors/vscode/package.json @@ -46,9 +46,9 @@ "default": "pipe", "enum": [ "pipe", - "tcp" + "socket" ], - "description": "How to communicate with clice. pipe (default) or tcp (debug)." + "description": "How to communicate with clice. pipe or socket. For daily use please use pipe." }, "clice.host": { "type": "string", diff --git a/editors/vscode/src/extension.ts b/editors/vscode/src/extension.ts index 3fd2bbd7c..302608dd9 100644 --- a/editors/vscode/src/extension.ts +++ b/editors/vscode/src/extension.ts @@ -50,7 +50,7 @@ export async function activate(context: ExtensionContext) { run: { command: executable, args: args }, debug: { command: executable, args: args }, }; - } else if (setting.mode === "tcp") { + } else if (setting.mode === "socket") { serverOptions = (): Promise => { return new Promise((resolve, reject) => { const client = new net.Socket(); @@ -66,7 +66,7 @@ export async function activate(context: ExtensionContext) { }); }; } else { - vscode.window.showErrorMessage("Invalid mode, please set the mode to 'pipe' or 'tcp'."); + vscode.window.showErrorMessage("Invalid mode, please set the mode to 'pipe' or 'socket'."); return; } diff --git a/editors/vscode/src/setting.ts b/editors/vscode/src/setting.ts index ae193e058..afac7843a 100644 --- a/editors/vscode/src/setting.ts +++ b/editors/vscode/src/setting.ts @@ -10,10 +10,9 @@ interface Setting { export function getSetting(): Setting | undefined { const setting = vscode.workspace.getConfiguration("clice"); const executable = process.env.CLICE_EXECUTABLE || setting.get("executable"); - const configuredMode = process.env.CLICE_MODE || setting.get("mode"); - const mode = configuredMode === "socket" ? "tcp" : configuredMode; + const mode = process.env.CLICE_MODE || setting.get("mode"); - if (mode !== "pipe" && mode !== "tcp") { + if (mode !== "pipe" && mode !== "socket") { vscode.window.showErrorMessage(`Unexpected mode: ${mode}`); return undefined; } @@ -21,8 +20,8 @@ export function getSetting(): Setting | undefined { const host = setting.get("host")!; const port = setting.get("port")!; - if (mode === "tcp" && (!host || !port)) { - vscode.window.showErrorMessage("TCP mode requires both host and port to be configured."); + if (mode === "socket" && (!host || !port)) { + vscode.window.showErrorMessage("Socket mode requires both host and port to be configured."); return undefined; } diff --git a/src/server/service/master_server.cpp b/src/server/service/master_server.cpp index 5d38bea50..f0178de61 100644 --- a/src/server/service/master_server.cpp +++ b/src/server/service/master_server.cpp @@ -410,8 +410,8 @@ int run_serve_mode(const ServerOptions& opts, const char* self_path) { auto record = opts.record.value_or(""); auto ws = opts.workspace.value_or(""); - if(mode == ServerMode::Tcp && (port <= 0 || port > 65535)) { - LOG_ERROR("--port must be between 1 and 65535 in tcp mode"); + if(mode == ServerMode::Socket && (port <= 0 || port > 65535)) { + LOG_ERROR("--port must be between 1 and 65535 in socket mode"); return 1; } @@ -472,7 +472,7 @@ int run_serve_mode(const ServerOptions& opts, const char* self_path) { return 0; } - if(mode == ServerMode::Tcp) { + if(mode == ServerMode::Socket) { auto acceptor = kota::tcp::listen(host, port, {}, loop); if(!acceptor) { LOG_ERROR("failed to listen on {}:{}", host, port); diff --git a/src/server/service/master_server.h b/src/server/service/master_server.h index d8c45f48f..1f01a52cc 100644 --- a/src/server/service/master_server.h +++ b/src/server/service/master_server.h @@ -18,24 +18,24 @@ namespace clice { namespace deco = kota::deco; -enum class ServerMode : std::uint8_t { Pipe, Tcp }; +enum class ServerMode : std::uint8_t { Pipe, Socket }; struct ServerOptions { DecoFlag(names = {"-h", "--help"}, help = "Show help", required = false) help; DecoKV(style = deco::decl::KVStyle::JoinedOrSeparate, - help = "Server mode: pipe (default) or tcp (debug)", + help = "Server mode: pipe (default) or socket (debug)", required = false) mode = ServerMode::Pipe; DecoKV(style = deco::decl::KVStyle::JoinedOrSeparate, - help = "TCP listen address", + help = "Socket mode address", required = false) host = "127.0.0.1"; DecoKV(style = deco::decl::KVStyle::JoinedOrSeparate, - help = "TCP port (pipe mode: agentic only; tcp mode: LSP + agentic)", + help = "TCP port (pipe mode: agentic only; socket mode: LSP + agentic)", required = false) port = 0; diff --git a/tests/conftest.py b/tests/conftest.py index 54b393eba..5ee4efccb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -16,12 +16,6 @@ def pytest_addoption(parser: pytest.Parser) -> None: required=False, help="Path to the clice executable.", ) - parser.addoption( - "--host", - type=str, - default="127.0.0.1", - help="The host to connect to (default: 127.0.0.1)", - ) @pytest.fixture(scope="session") diff --git a/tests/integration/agentic/test_cli.py b/tests/integration/agentic/test_cli.py index 627b463f9..204353c50 100644 --- a/tests/integration/agentic/test_cli.py +++ b/tests/integration/agentic/test_cli.py @@ -193,12 +193,12 @@ async def test_cli_status(indexed_server, workspace): @pytest.mark.workspace("hello_world") -async def test_tcp_mode_connects(executable, workspace): +async def test_socket_mode_connects(executable, workspace): from tests.conftest import find_free_port, shutdown_client from tests.integration.utils.client import CliceClient port = find_free_port() - cmd = [str(executable), "serve", "--mode", "tcp", "--port", str(port)] + cmd = [str(executable), "serve", "--mode", "socket", "--port", str(port)] proc = await asyncio.create_subprocess_exec( *cmd, stdin=asyncio.subprocess.PIPE,