From 57064c79d33961204e475ea0b9f935e581332191 Mon Sep 17 00:00:00 2001 From: Boris Batkin Date: Sat, 29 Aug 2026 03:16:35 -0700 Subject: [PATCH] mcp setup: configure a worktree on the source tree's cmake generator, bound the build setup.das passed no -G, so every bootstrapped worktree landed on the platform default - Unix Makefiles on macOS/Linux - while the tree it was cloned from runs Ninja. source_tree_generator() reads CMAKE_GENERATOR from the running tree's build/CMakeCache.txt and passes it through; platform default when that tree has no configured build. The daslang build now runs --parallel at hardware threads instead of the generator default (serial on Makefiles). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01FkBKGJisiiHXEgSsGjpqLm --- skills/mcp_tools.md | 2 +- utils/mcp/setup.das | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/skills/mcp_tools.md b/skills/mcp_tools.md index 9e2447385d..032e92e07a 100644 --- a/skills/mcp_tools.md +++ b/skills/mcp_tools.md @@ -74,7 +74,7 @@ The daslang MCP server (`utils/mcp/main.das`) exposes compiler diagnostics, prog **Configuration.** Configure `.mcp.json` with `"command"` pointing at the daslang binary (`bin/daslang` on Windows MSVC, `build/daslang` on Linux/macOS, `bin/daslang` for the installed SDK), `"args": ["utils/mcp/main.das"]`. See `utils/mcp/README.md` for details and Claude Code permissions. -**Fresh checkouts / worktrees.** `.mcp.json`, `sgconfig.yml`, `bin/`, and the tree-sitter grammar lib are all gitignored, so a new `git worktree add` (or clone) has no daslang MCP at all. Bootstrap it with `daslang utils/mcp/setup.das -- --root ` - it builds a worktree-local binary (+ grammar), copies the platform `sgconfig.yml`, and merges a `daslang` entry into `.mcp.json` (adds no new secrets; existing servers, including any secret env blocks, are preserved as-is). `--no-build` skips the build. Restart the session to pick it up. +**Fresh checkouts / worktrees.** `.mcp.json`, `sgconfig.yml`, `bin/`, and the tree-sitter grammar lib are all gitignored, so a new `git worktree add` (or clone) has no daslang MCP at all. Bootstrap it with `daslang utils/mcp/setup.das -- --root ` - it configures `build/` on the cmake generator of the tree running the setup (platform default when that tree has no `build/CMakeCache.txt`), builds a worktree-local binary (+ grammar), copies the platform `sgconfig.yml`, and merges a `daslang` entry into `.mcp.json` (adds no new secrets; existing servers, including any secret env blocks, are preserved as-is). `--no-build` skips the build. Restart the session to pick it up. **`"defer_loading": false` (repo-only).** The repo's `.mcp.json` sets this on the `daslang` server entry so tool schemas load at session start instead of being deferred (deferred = caller has to `ToolSearch select:` before each first call). When the harness honors the flag, this removes the per-call ToolSearch friction. When it doesn't, the flag is harmless and tools fall back to the deferred path; CLAUDE.md's "MCP-first search" rule documents that workflow. diff --git a/utils/mcp/setup.das b/utils/mcp/setup.das index 25271399cc..3c97812d77 100644 --- a/utils/mcp/setup.das +++ b/utils/mcp/setup.das @@ -2,6 +2,9 @@ options gen2 require daslib/clargs require daslib/fio +require daslib/strings_boost +require strings +require jobque // daslang MCP worktree bootstrap. // @@ -72,11 +75,30 @@ def shell_unsafe(s : string) : bool { // flag only takes effect on the INITIAL configure — a build/ that already has a // CMakeCache keeps its cached OPENSSL_ROOT_DIR (wipe build/ to change it). This // tool targets fresh worktrees, so that's the common case. +//! The cmake generator of the tree running this setup (`build/CMakeCache.txt` under +//! `get_das_root()`), or "" when that tree has no configured build. A worktree configured +//! with the platform default lands on Unix Makefiles, whose `cmake --build --parallel` +//! is unbounded `make -j`; matching the source tree keeps a bootstrapped worktree on the +//! generator the box already builds with. +def source_tree_generator : string { + let cache = path_join(get_das_root(), path_join("build", "CMakeCache.txt")) + if (!fexist(cache)) return "" + let key = "CMAKE_GENERATOR:INTERNAL=" + for (line in fread(cache) |> split("\n")) { + if (starts_with(line, key)) return strip(slice(line, length(key), length(line))) + } + return "" +} + def build_worktree(root, openssl_dir : string) : bool { let build_dir = path_join(root, "build") if (!fexist(path_join(build_dir, "CMakeCache.txt"))) { - print("Configuring CMake in {build_dir} ...\n") var cfg_cmd = "cmake -S \"{root}\" -B \"{build_dir}\" -DCMAKE_BUILD_TYPE=Release" + let gen = source_tree_generator() + if (!empty(gen) && !shell_unsafe(gen)) { + cfg_cmd += " -G \"{gen}\"" + } + print("Configuring CMake in {build_dir} (generator: {empty(gen) ? "platform default" : gen}) ...\n") if (!empty(openssl_dir)) { cfg_cmd += " -DOPENSSL_ROOT_DIR=\"{to_generic_path(openssl_dir)}\"" } @@ -87,7 +109,7 @@ def build_worktree(root, openssl_dir : string) : bool { } } print("Building daslang (this can take a while) ...\n") - let rc = run_visible("cmake --build \"{build_dir}\" --target daslang --config Release") + let rc = run_visible("cmake --build \"{build_dir}\" --target daslang --config Release --parallel {get_total_hw_threads()}") if (rc != 0) { print("ERROR: building daslang failed (exit {rc})\n") return false