list_modules lists what a require can reach; the watchdog's --stdio front replaces the MCP python supervisor - #3987
Merged
Merged
Conversation
…ess registered - a module with a file name was compiled from das and is not one - the daslib files under the das root instead of the cwd, and the require paths descriptors registered (module/path, from for_each_registered_native_path), which the tool never showed; with project_root or load_modules the listing comes from an eager child (-ignore-manifest, the new eager argv flag), since a deferred C++ module is not a registered one until something requires it; the pretend root gains a second module folder whose descriptor registers the tree's UnitTest C++ module and a require path of its own, and test_tools proves list_modules, find_symbol and compile_check see both under project_root, with a plain and an eager child run of the consumer; tests/lsp gains the same fixture through validate.das with -project_root; the mcp roadmap's fixture item closes
…cess is the client's newline-delimited JSON-RPC pipe and the child is the server - initialize and ping answered locally so the client connects before any child exists, the first tools request spawning the child, in --cwd, with the client's initialize replayed, one request forwarded at a time, a child that died before delivery respawned with the request re-sent once and one that died while answering reported instead, since a re-sent tool call could run twice; the child's non-JSON stdout is logged as child_noise and carried in that error; the log goes to its file only, since stdout is the protocol, and its child_started and child_exited spell their keys as the supervisor's do; one child lifetime per tick, so the exe host's loop and the interpreter host's loop both serve it; mcp_supervisor.py goes, and setup.das writes .mcp.json itself - the watchdog exe beside the binary when built, the interpreter host otherwise, the vcvars launcher as the child on Windows - preserving every other server, the entry's defer_loading and the das-herd shim, and moving the old file aside until the new one is in place; the utils/REVIEW.das ban on an exe form of mcp and lsp stays, since both still run interpreted under a supervisor, and says so; utils/watchdog/REVIEW.das is a new gate holding the README's event list to what the folder emits; stdio_front.das joins the watchdog's install list; tests/watchdog/test_stdio_front.das drives a scripted session through both hosts from a directory that is not the tree, the server's own initialize result as the front's, a tool catalog longer than one fgets chunk, the server's shutdown tool as the death and the next call as the respawn; utils/mcp/test_setup.das drives the .mcp.json rewrite into scratch roots; the LSP endpoint's port to the same shape is ledgered in utils/lsp/ROADMAP.md with the protocol test as its acceptance test
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
utils/watchdog/stdio_front.das unconditionally deletes JsonValue? values that can be null, which risks runtime errors during protocol noise handling.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR updates the daslang MCP tooling so list_modules reflects what require can actually reach (including registered require paths and project-root descriptors), and replaces the Python MCP stdio supervisor with a native bin/watchdog --stdio front that lazily spawns/respawns the MCP server.
Changes:
- Extend
list_modulesto report builtin C++ modules, daslib modules, and registered require paths; addproject_root/load_modulessupport via an eager subtool run. - Add watchdog
--stdiomode (StdioFront) to act as the JSON-RPC pipe, spawning/respawning the MCP server and answeringinitialize/pinglocally. - Update setup/docs/tests/install rules to use the watchdog front and remove
utils/mcp/mcp_supervisor.py.
File summaries
| File | Description |
|---|---|
| utils/watchdog/watchdog.das | Adds --stdio flag plumbing to the watchdog config. |
| utils/watchdog/stdio_front.das | Implements the stdio JSON-RPC front that spawns/respawns the MCP server. |
| utils/watchdog/REVIEW.md | Updates review contract for logging/event naming across supervisor + stdio front. |
| utils/watchdog/REVIEW.das | Adds a review gate verifying emitted log events match the README list. |
| utils/watchdog/README.md | Documents --stdio behavior and expands log event/field descriptions. |
| utils/watchdog/main.das | Routes --stdio to the front and integrates front lifecycle into host entrypoints. |
| utils/REVIEW.das | Updates supervised-tools/internal-reference exemptions after removing Python supervisor. |
| utils/mcp/tools/list_modules.das | Expands module listing and adds eager subtool path for project-root scanning. |
| utils/mcp/tools/common.das | Adds eager option to subtool argv/run helper to force -ignore-manifest. |
| utils/mcp/tests/_pretend_root/probe_consumer.das | Adds a consumer script fixture for project_root resolution tests. |
| utils/mcp/tests/_pretend_root/modules/dasUnitTest/daslib/hello.das | Adds a fixture module providing a symbol via a registered native path. |
| utils/mcp/tests/_pretend_root/modules/dasUnitTest/.das_module | Adds a descriptor fixture registering a C++ module + require path under project_root. |
| utils/mcp/test_tools.das | Adds coverage for new list_modules semantics and project_root behavior. |
| utils/mcp/test_setup.das | Adds tests for .mcp.json emission/merge/move-aside behavior without Python. |
| utils/mcp/subtools/list_modules.das | Adds subprocess entrypoint used for eager list_modules scanning. |
| utils/mcp/setup.das | Writes .mcp.json entries that spawn watchdog --stdio instead of Python supervisor. |
| utils/mcp/ROADMAP.md | Updates follow-ups after adding the project_root fixture and watchdog front. |
| utils/mcp/REVIEW.md | Updates install/listing guidance now that .mcp.json is written by setup.das. |
| utils/mcp/registry_das.das | Updates tool schema/handler to accept project_root and load_modules. |
| utils/mcp/README.md | Documents watchdog-front .mcp.json shape and updated restart/ignore-manifest guidance. |
| utils/mcp/mcp_supervisor.py | Removes Python-based MCP stdio supervisor. |
| utils/lsp/ROADMAP.md | Updates references/plan to align with watchdog-front approach and new helper naming. |
| utils/CMakeLists.txt | Updates commentary about supervised tools now that MCP uses watchdog front. |
| tests/watchdog/test_stdio_front.das | Adds end-to-end tests for watchdog --stdio behavior and respawn semantics. |
| tests/README.md | Adds entries for new tests/lsp/ and tests/watchdog/ test files. |
| tests/lsp/test_lsp_project_root.das | Adds test verifying LSP validate subtool respects -project_root descriptors. |
| skills/mcp_tools.md | Updates MCP skill docs for watchdog-front config and restart semantics. |
| CMakeLists.txt | Installs stdio_front.das and removes mcp_supervisor.py from installed MCP files. |
| ci/smoke_test_bundle.sh | Adjusts internal-reference exclusions from mcp_supervisor.py to setup.das. |
| .codex/config.toml.example | Updates example MCP server config to use bin/watchdog --stdio. |
Review details
Suppressed comments (1)
utils/watchdog/stdio_front.das:158
read_jsonmay return null for a non-JSON line, but this block deletesjsunconditionally. Guard the delete so noise lines don’t risk a null delete.
var js = read_json(line, err)
let ok = js != null
unsafe {
delete js
}
if (ok) return line
- Files reviewed: 30/30 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Behavior change:
.mcp.jsonentries written byutils/mcp/setup.dasnow spawnbin/watchdog --stdioinstead ofmcp_supervisor.py- re-run setup on a tree to pick it up.Why. The MCP
list_modulestool answered from the server's own compile and missed most of what arequirecan reach, and the two Python supervisors duplicated what the watchdog already does in daslang.What changes.
list_moduleslists the C++ modules the binary carries, the daslib modules by file, and every registered require path;project_rootruns it in a subtool with that root's manifest loaded eagerly.--stdio: it answersinitializeandpingitself, spawns the server on the firsttools/*call in--cwd, forwards one request at a time, and respawns a child that died before a request was delivered.utils/mcp/setup.daswrites the watchdog front into a tree's.mcp.json(the daslang binary as the program on Unix, the.cmdwrapper on Windows) and a dasherd entry when that tool exists;mcp_supervisor.pyis deleted.utils/lsp/ROADMAP.mdwithtest_lsp_protocol.dasas its acceptance test.utils/watchdog/REVIEW.dasis a new gate: everyeventthe folder emits is in the README's list, and every listed one is emitted.Observable behavior.
list_moduleson this tree: a handful of modules -> 32 C++ modules, 156 daslib modules, 307 require paths, with ajsonform.list_moduleswithproject_root: ignored -> that root's.das_moduledescriptors and their daslib files are in the listing.bin/watchdog --stdio, no Python; the server dying mid-session -> the next call respawns it unseen..mcp.jsonrewrite bysetup.das: the old file removed before the new one lands -> moved aside and restored when the replacement fails.--stdio:child_startedcarries the command,child_exitedcarriescodeandanswered, andchild_noise/client_noisecarry a non-JSON line.Where to look.
utils/watchdog/stdio_front.das(the one-child-per-tick loop and the respawn rule),utils/mcp/tools/list_modules.das,utils/mcp/setup.das(front_command,emit_mcp_config).Validation, claims, ledger
Validation
tests/watchdog/test_stdio_front.dasdrives the front through both hosts from a temp directory; the exe arm skips wherebin/watchdogis not built (CI lanes that build onlydaslang).stdio_front.dasinstall line and the unguarded.mcp.jsonreplacement, both fixed here; the second ran on the fixed tip.utils/mcp/test_setup.dasdrivesemit_mcp_configinto scratch roots: a fresh file, a merge that keeps another server anddefer_loading, the dasherd entry, two refused non-object files, and a move-aside that cannot happen (the old file stays, the new one waits in.tmp).tests/watchdog/test_stdio_front.dasalso compares the front'sinitializeresult with the server's own, and pulls the tool catalog through the front, which is longer than onefgetschunk; truncating the front's line reader hangs that round.Claims - stated, not tested
.mcp.jsonshape (cmd.exe /c daslang-mcp-msvc.cmdas the front's--program) is written bysetup.dasbut not exercised on a Windows box in this PR; a break shows as the MCP server failing to connect aftersetup.dason Windows.setup.dasreporting failure with.mcp.jsongone and.mcp.json.bakpresent.initialize, so no test distinguishes a dead replay.Not done
utils/lsp/lsp_supervisor.py) stays Python; its port to the watchdog is ledgered inutils/lsp/ROADMAP.md.-exetarget for the front's--program(utils/mcp/ROADMAP.md).