Windows: full test suite + gate auto-discovery for local MCP #54

Open
mind6 wants to merge 6 commits from mind6/2.0-integration into 2.0-integration
mind6 commented 2026-06-21 03:37:49 -07:00 (Migrated from github.com)

Summary

Windows is now usable end-to-end: the full test suite passes, and a local gate REPL is discoverable by a Kaimon MCP server (including Cursor).

Tests (914 passing on Windows / Julia 1.12.6)

  • Gate and service-endpoint subprocess tests use mode=:tcp instead of unsupported ipc://
  • ZMQ socket stress test scaled down to avoid EMFILE on Windows handle limits
  • Config tests use JSON.json(...) so paths like D:\Temp\... are not corrupted
  • Portable subprocess sleep via julia -e sleep(...) instead of Unix sleep
  • Expanded test/Project.toml for julia --project=test

Production: Windows gate auto-discovery

  • serve() defaults to TCP on Windows; localhost gates write sock metadata for file-based discovery
  • Escape backslashes in gate session JSON (project_path was invalid JSON and got deleted on parse)
  • Fix _is_pid_alive on Windows (ps unavailable; trust uv_kill)
  • Discover localhost TCP gates in discover_sessions (skip tcp-* poll bookkeeping only)
  • Align XDG_CACHE_HOME handling between gate and server cache dirs

Manually verified operational flow

  1. Gate REPL: using Kaimon; Kaimon.KaimonGate.serve() → binds tcp://127.0.0.1:<ephemeral> and writes %LOCALAPPDATA%\Kaimon\sock\<session>.json
  2. Server REPL: Kaimon.start!() → ConnectionManager discovers the gate from that sock dir
  3. Cursor MCP: ~/.cursor/mcp.jsonhttp://localhost:<port>/mcp (lax mode, no auth header)
  4. ex tool evaluates code in the connected gate REPL (e.g. df.dates[end]2020-03-31)

Test plan

  • julia --project=test test/runtests.jl — 914 passed on Windows
  • Pkg.test() in lib/KaimonGate — passing (3 IPC-only tests skipped on Windows)
  • Two-REPL flow: serve() + start!(), metadata persists in sock dir, session visible to server
  • Cursor MCP ex reaches gate REPL (eval mirrored in host REPL)
## Summary Windows is now usable end-to-end: the full test suite passes, and a local gate REPL is discoverable by a Kaimon MCP server (including Cursor). **Tests (914 passing on Windows / Julia 1.12.6)** - Gate and service-endpoint subprocess tests use `mode=:tcp` instead of unsupported `ipc://` - ZMQ socket stress test scaled down to avoid `EMFILE` on Windows handle limits - Config tests use `JSON.json(...)` so paths like `D:\Temp\...` are not corrupted - Portable subprocess sleep via `julia -e sleep(...)` instead of Unix `sleep` - Expanded `test/Project.toml` for `julia --project=test` **Production: Windows gate auto-discovery** - `serve()` defaults to TCP on Windows; localhost gates write sock metadata for file-based discovery - Escape backslashes in gate session JSON (`project_path` was invalid JSON and got deleted on parse) - Fix `_is_pid_alive` on Windows (`ps` unavailable; trust `uv_kill`) - Discover localhost TCP gates in `discover_sessions` (skip `tcp-*` poll bookkeeping only) - Align `XDG_CACHE_HOME` handling between gate and server cache dirs **Manually verified operational flow** 1. Gate REPL: `using Kaimon; Kaimon.KaimonGate.serve()` → binds `tcp://127.0.0.1:<ephemeral>` and writes `%LOCALAPPDATA%\Kaimon\sock\<session>.json` 2. Server REPL: `Kaimon.start!()` → ConnectionManager discovers the gate from that sock dir 3. Cursor MCP: `~/.cursor/mcp.json` → `http://localhost:<port>/mcp` (lax mode, no auth header) 4. `ex` tool evaluates code in the connected gate REPL (e.g. `df.dates[end]` → `2020-03-31`) ## Test plan - [x] `julia --project=test test/runtests.jl` — 914 passed on Windows - [x] `Pkg.test()` in `lib/KaimonGate` — passing (3 IPC-only tests skipped on Windows) - [x] Two-REPL flow: `serve()` + `start!()`, metadata persists in sock dir, session visible to server - [x] Cursor MCP `ex` reaches gate REPL (eval mirrored in host REPL)
mind6 (Migrated from github.com) reviewed 2026-06-21 04:53:25 -07:00
kahliburke commented 2026-06-25 22:40:58 -07:00 (Migrated from github.com)

Thanks for this — the Windows end-to-end work is great, and the JSON-escaping fix in particular is a real bug squashed.

I reviewed and tested it on macOS:

  • Merges cleanly into the current 2.0-integration (the branch has moved a fair bit since you based off it — grep_code, the routing/roots work, etc.). After merging, the main suite and the KaimonGate suite are green (incl. your new metadata JSON escapes backslashes test, and CURVE 66/66). The only red I saw were a couple of pre-existing flakes (a Gate.progress @test_nowarn and the ZMQ-stress subprocess test, both pass in isolation) — nothing from your changes.
  • Could you rebase onto current 2.0-integration when you re-test? It merges without conflicts on my end.

On the discover_sessions change vs #50 — I dug into this since #50 was a nasty one. Good news: it does not reintroduce the original #50. The poll/reconnect markers connect_tcp! writes all use sid tcp-<host>-<port>, which your startswith(session_id, "tcp-") && continue still skips. 👍

I did find two smaller refinements for the new localhost-TCP discovery path, which I've pushed as a single commit on top of your head on branch pr54-50-hardening (cherry-pick 59a9b9f, or apply the diff below):

  1. Apply the already-tracked/same-PID dedup to localhost TCP too. Right now it's gated session_mode != :tcp, so an already-connected localhost TCP gate isn't skipped — each discovery cycle re-emits it and discover_sessions treats it as a "restart", causing repeated reconnect attempts.
  2. Attach the local auth token to discovered localhost TCP gates (env KAIMON_GATE_TOKEN → global-config api key, mirroring connect_tcp!). A localhost gate shares this machine's config; presenting the token authenticates an auth-required gate and is ignored by a lax one — instead of failing tokenless every cycle.
+function _resolve_local_gate_token()
+    tok = get(ENV, "KAIMON_GATE_TOKEN", "")
+    isempty(tok) || return tok
+    try
+        config = load_global_config()
+        if config.mode != :lax && !isempty(config.api_keys)
+            return first(config.api_keys)
+        end
+    catch
+    end
+    return ""
+end
@@ discover_sessions, TCP branch @@
-        if session_mode != :tcp && haskey(known_id_pids, session_id) && known_id_pids[session_id] == pid
+        if haskey(known_id_pids, session_id) && known_id_pids[session_id] == pid
             continue
         end
@@ conn construction @@
             server_pubkey = server_pubkey,
+            auth_token = session_mode == :tcp ? _resolve_local_gate_token() : "",

Those discovery/TCP testsets pass for me (83 total: stale-session, TCP auth, ephemeral+auth, poll backoff, PID refresh + localhost reaping).

Since I can't validate Windows here: could you fold in pr54-50-hardening, rebase onto current 2.0-integration, and re-run on Windows + the full suite? Once that's green we can merge. Thanks again!

Thanks for this — the Windows end-to-end work is great, and the JSON-escaping fix in particular is a real bug squashed. I reviewed and tested it on macOS: - **Merges cleanly into the current `2.0-integration`** (the branch has moved a fair bit since you based off it — grep_code, the routing/roots work, etc.). After merging, the **main suite and the KaimonGate suite are green** (incl. your new `metadata JSON escapes backslashes` test, and CURVE 66/66). The only red I saw were a couple of pre-existing flakes (a `Gate.progress` `@test_nowarn` and the ZMQ-stress subprocess test, both pass in isolation) — nothing from your changes. - Could you **rebase onto current `2.0-integration`** when you re-test? It merges without conflicts on my end. **On the `discover_sessions` change vs #50** — I dug into this since #50 was a nasty one. Good news: it does **not** reintroduce the original #50. The poll/reconnect markers `connect_tcp!` writes all use sid `tcp-<host>-<port>`, which your `startswith(session_id, "tcp-") && continue` still skips. 👍 I did find two smaller refinements for the new localhost-TCP discovery path, which I've pushed as a single commit on top of your head on branch **`pr54-50-hardening`** (cherry-pick `59a9b9f`, or apply the diff below): 1. **Apply the already-tracked/same-PID dedup to localhost TCP too.** Right now it's gated `session_mode != :tcp`, so an already-connected localhost TCP gate isn't skipped — each discovery cycle re-emits it and `discover_sessions` treats it as a "restart", causing repeated reconnect attempts. 2. **Attach the local auth token to discovered localhost TCP gates** (env `KAIMON_GATE_TOKEN` → global-config api key, mirroring `connect_tcp!`). A localhost gate shares this machine's config; presenting the token authenticates an auth-required gate and is ignored by a lax one — instead of failing tokenless every cycle. ```diff +function _resolve_local_gate_token() + tok = get(ENV, "KAIMON_GATE_TOKEN", "") + isempty(tok) || return tok + try + config = load_global_config() + if config.mode != :lax && !isempty(config.api_keys) + return first(config.api_keys) + end + catch + end + return "" +end @@ discover_sessions, TCP branch @@ - if session_mode != :tcp && haskey(known_id_pids, session_id) && known_id_pids[session_id] == pid + if haskey(known_id_pids, session_id) && known_id_pids[session_id] == pid continue end @@ conn construction @@ server_pubkey = server_pubkey, + auth_token = session_mode == :tcp ? _resolve_local_gate_token() : "", ``` Those discovery/TCP testsets pass for me (83 total: stale-session, TCP auth, ephemeral+auth, poll backoff, PID refresh + localhost reaping). Since I can't validate Windows here: could you **fold in `pr54-50-hardening`, rebase onto current `2.0-integration`, and re-run on Windows + the full suite**? Once that's green we can merge. Thanks again!
mind6 commented 2026-07-15 05:57:38 -07:00 (Migrated from github.com)

Sorry for the delayed response. pr54-50-hardening tests pass on windows. I believe the branch is already based on 2.0-integration.

Are you interested in setting up CI with a Windows server?

Sorry for the delayed response. **pr54-50-hardening** tests pass on windows. I believe the branch is already based on **2.0-integration**. Are you interested in setting up CI with a Windows server?
mind6 commented 2026-07-15 06:10:16 -07:00 (Migrated from github.com)

I'm not sure what's going on with these merge conflicts. It seems there was Windows specific work different from what's in my PR.

I'm not sure what's going on with these merge conflicts. It seems there was Windows specific work different from what's in my PR.
kahliburke commented 2026-07-15 21:28:50 -07:00 (Migrated from github.com)

@mind6 Hey since you last did this the 2.0 release has happened, we've done a couple windows fixes along the way and will probably have some more. You should align your changes with the main branch now.

@mind6 Hey since you last did this the 2.0 release has happened, we've done a couple windows fixes along the way and will probably have some more. You should align your changes with the main branch now.
This pull request has changes conflicting with the target branch.
  • lib/KaimonGate/src/gate_protocol.jl
  • lib/KaimonGate/src/gate_serve.jl
  • src/gate_client_discovery.jl
  • test/Project.toml
  • test/tui_analytics_tests.jl
View command line instructions

Manual merge helper

Use this merge commit message when completing the merge manually.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin mind6/2.0-integration:mind6/2.0-integration
git switch mind6/2.0-integration

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch 2.0-integration
git merge --no-ff mind6/2.0-integration
git switch mind6/2.0-integration
git rebase 2.0-integration
git switch 2.0-integration
git merge --ff-only mind6/2.0-integration
git switch mind6/2.0-integration
git rebase 2.0-integration
git switch 2.0-integration
git merge --no-ff mind6/2.0-integration
git switch 2.0-integration
git merge --squash mind6/2.0-integration
git switch 2.0-integration
git merge --ff-only mind6/2.0-integration
git switch 2.0-integration
git merge mind6/2.0-integration
git push origin 2.0-integration
Sign in to join this conversation.
No description provided.