Initial commit: Better Claude Config
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
import json, tempfile, shutil
|
||||
from pathlib import Path
|
||||
import bcc_core as c
|
||||
|
||||
tmp = Path(tempfile.mkdtemp())
|
||||
ok = []
|
||||
|
||||
def check(name, cond):
|
||||
ok.append(cond)
|
||||
print(("PASS" if cond else "FAIL"), "-", name)
|
||||
|
||||
# ---- 1. discovery (monkeypatch the base dir) ----
|
||||
base = tmp / "AppSupport"
|
||||
for d in ("Claude", "Claude-Work", "NotClaude"):
|
||||
(base / d).mkdir(parents=True)
|
||||
(base / "Claude" / c.CONFIG_FILENAME).write_text("{}")
|
||||
# Claude-Work has no config yet; NotClaude shouldn't match
|
||||
c.app_support_base = lambda: base
|
||||
profs = c.discover_profiles()
|
||||
labels = sorted(p.label for p in profs)
|
||||
check("discovers Claude + Claude-Work, not NotClaude", labels == ["Claude", "Claude-Work"])
|
||||
check("flags missing config file", any(p.label=="Claude-Work" and not p.config_exists for p in profs))
|
||||
|
||||
# ---- 2. write preserves OTHER keys + order, only touches mcpServers ----
|
||||
cfgpath = tmp / "real.json"
|
||||
original = {
|
||||
"globalShortcut": "Cmd+Shift+Space",
|
||||
"mcpServers": {"old": {"command": "node", "args": ["x.js"]}},
|
||||
"someOtherTool": {"keep": True},
|
||||
}
|
||||
cfgpath.write_text(json.dumps(original, indent=2))
|
||||
cfg = c.load_config(cfgpath)
|
||||
servers = c.extract_servers(cfg)
|
||||
# add a new one, disable the old one
|
||||
servers.append(c.ServerEntry("brave", {"command": "npx", "args": ["-y", "@x/brave"]}, True))
|
||||
servers[0].enabled = False
|
||||
c.apply_servers(cfg, servers)
|
||||
c.write_config(cfgpath, cfg)
|
||||
written = json.loads(cfgpath.read_text())
|
||||
keys = list(written.keys())
|
||||
check("preserved globalShortcut", written.get("globalShortcut") == "Cmd+Shift+Space")
|
||||
check("preserved someOtherTool", written.get("someOtherTool") == {"keep": True})
|
||||
check("disabled server parked in _disabledMcpServers", "old" in written.get("_disabledMcpServers", {}))
|
||||
check("enabled server in mcpServers", "brave" in written.get("mcpServers", {}))
|
||||
check("old not in active mcpServers", "old" not in written.get("mcpServers", {}))
|
||||
check("key order kept (globalShortcut before mcpServers)", keys.index("globalShortcut") < keys.index("mcpServers"))
|
||||
check("backup created", (cfgpath.parent / c.BACKUP_DIRNAME).is_dir() and any((cfgpath.parent / c.BACKUP_DIRNAME).iterdir()))
|
||||
|
||||
# ---- 3. paste parser, all shapes ----
|
||||
full = '{"mcpServers": {"a": {"command": "node", "args": ["a.js"]}}}'
|
||||
check("parse full config shape", list(c.parse_pasted_json(full)) == ["a"])
|
||||
inner = '{"b": {"command": "uvx", "args": ["mcp-server-git"]}}'
|
||||
check("parse inner block shape", list(c.parse_pasted_json(inner)) == ["b"])
|
||||
bare = '{"command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]}'
|
||||
parsed = c.parse_pasted_json(bare)
|
||||
check("parse bare server + suggests name 'filesystem'", "filesystem" in parsed)
|
||||
remote = '{"url": "https://mcp.asana.com/sse"}'
|
||||
check("parse remote, suggests host name", "mcp" in c.parse_pasted_json(remote))
|
||||
try:
|
||||
c.parse_pasted_json('{"junk": 5}')
|
||||
check("rejects junk", False)
|
||||
except ValueError:
|
||||
check("rejects junk", True)
|
||||
|
||||
# ---- 4. validation ----
|
||||
bad = [c.ServerEntry("", {"command": "x"}, True),
|
||||
c.ServerEntry("dup", {"command": "x"}, True),
|
||||
c.ServerEntry("dup", {"command": "x"}, True),
|
||||
c.ServerEntry("r", {"url": ""}, True),
|
||||
c.ServerEntry("nocmd", {"command": ""}, True)]
|
||||
probs = c.validate_servers(bad)
|
||||
check("validation catches empty name", any("empty name" in p for p in probs))
|
||||
check("validation catches duplicate", any("Duplicate" in p for p in probs))
|
||||
check("validation catches missing url", any("no URL" in p for p in probs))
|
||||
check("validation catches missing command", any("no command" in p for p in probs))
|
||||
check("valid set passes clean", c.validate_servers([c.ServerEntry("good", {"command":"node"}, True)]) == [])
|
||||
|
||||
# ---- 5. dependency check (python3 exists; bogusxyz does not) ----
|
||||
r_ok = c.check_dependency({"command": "python3"})
|
||||
check("dep check finds python3", r_ok["status"] == "ok")
|
||||
r_missing = c.check_dependency({"command": "definitely-not-real-binary-xyz"})
|
||||
check("dep check flags missing", r_missing["status"] == "missing")
|
||||
r_remote = c.check_dependency({"url": "https://example.com/mcp"})
|
||||
check("dep check marks remote", r_remote["status"] == "remote")
|
||||
# windows-style wrapper: cmd /c npx ... -> should look past cmd to npx
|
||||
r_wrap = c.check_dependency({"command": "cmd", "args": ["/c", "definitely-not-real-xyz", "foo"]})
|
||||
check("dep check sees through shell wrapper", "definitely-not-real-xyz" in r_wrap["label"])
|
||||
|
||||
print()
|
||||
print(f"{sum(ok)}/{len(ok)} passed")
|
||||
shutil.rmtree(tmp)
|
||||
Reference in New Issue
Block a user