conduct-cli 0.7.46__tar.gz → 0.7.48__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/PKG-INFO +1 -1
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/pyproject.toml +1 -1
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/guard.py +44 -23
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli.egg-info/PKG-INFO +1 -1
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/README.md +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/setup.cfg +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/setup.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/__init__.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/api.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/guardmcp.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/hooks/__init__.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/hooks/base.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/hooks/posttooluse.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/hooks/precompact.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/hooks/pretooluse.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/hooks/session_parser.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/hooks/session_report_push.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/hooks/session_start.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/hooks/stop.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/log_util.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/main.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/mcp_server.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/memory.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/paxel.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli/tool_groups.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli.egg-info/SOURCES.txt +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli.egg-info/dependency_links.txt +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli.egg-info/entry_points.txt +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli.egg-info/requires.txt +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/src/conduct_cli.egg-info/top_level.txt +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_advisory_and_hook.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_api_client.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_bash_operator_signature.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_blast_radius.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_cmd_run.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_command_word_matcher.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_drain_daemon_health.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_guard_policy.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_guard_savings.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_hook_dispatch.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_instruction_files.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_journal_drain.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_log_util.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_proxy_coverage.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_proxy_env.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_signed_policy.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_switch.py +0 -0
- {conduct_cli-0.7.46 → conduct_cli-0.7.48}/tests/test_token_lifecycle.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "conduct-cli"
|
|
7
|
-
version = "0.7.
|
|
7
|
+
version = "0.7.48"
|
|
8
8
|
description = "CLI for Conduct AI — secure, govern, install agents, manage projects, run tests"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -474,31 +474,51 @@ def _patch_claude_desktop_proxy(api_url: str, agent_token: str) -> None:
|
|
|
474
474
|
|
|
475
475
|
|
|
476
476
|
def _patch_copilot_mcp(agent_token: str, api_url: str) -> None:
|
|
477
|
-
"""Keep ~/.copilot/mcp-config.json in sync with current agent token.
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
the way Claude Code / Cursor can, so we write the SSE entry with a fresh token.
|
|
481
|
-
"""
|
|
482
|
-
cfg_path = Path.home() / ".copilot" / "mcp-config.json"
|
|
483
|
-
if not cfg_path.exists():
|
|
484
|
-
return
|
|
485
|
-
try:
|
|
486
|
-
cfg = json.loads(cfg_path.read_text())
|
|
487
|
-
except (json.JSONDecodeError, OSError):
|
|
488
|
-
cfg = {}
|
|
489
|
-
mcp = cfg.setdefault("mcpServers", {})
|
|
490
|
-
entry = {
|
|
477
|
+
"""Keep ~/.copilot/mcp-config.json and any .mcp.json in cwd in sync with current agent token."""
|
|
478
|
+
import shutil
|
|
479
|
+
sse_entry = {
|
|
491
480
|
"type": "sse",
|
|
492
481
|
"url": f"{api_url}/guard/mcp",
|
|
493
482
|
"headers": {"Authorization": f"Bearer {agent_token}"},
|
|
494
483
|
"tools": ["**"],
|
|
495
484
|
}
|
|
496
|
-
if
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
485
|
+
booster_entry = {"command": "booster", "args": ["serve"]} if shutil.which("booster") else None
|
|
486
|
+
|
|
487
|
+
# ~/.copilot/mcp-config.json (global Copilot config)
|
|
488
|
+
global_path = Path.home() / ".copilot" / "mcp-config.json"
|
|
489
|
+
if global_path.exists():
|
|
490
|
+
_write_mcp_file(global_path, "conduct-guard", sse_entry, booster_entry, "GitHub Copilot (global)")
|
|
491
|
+
|
|
492
|
+
# .mcp.json in cwd (project-level, picked up by VS Code Copilot)
|
|
493
|
+
local_path = Path.cwd() / ".mcp.json"
|
|
494
|
+
if local_path.exists():
|
|
495
|
+
_write_mcp_file(local_path, "conduct-guard", sse_entry, booster_entry, "GitHub Copilot (.mcp.json)")
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
def _write_mcp_file(
|
|
499
|
+
cfg_path: Path,
|
|
500
|
+
guard_key: str,
|
|
501
|
+
sse_entry: dict,
|
|
502
|
+
booster_entry: dict | None,
|
|
503
|
+
label: str,
|
|
504
|
+
) -> None:
|
|
505
|
+
try:
|
|
506
|
+
cfg = json.loads(cfg_path.read_text())
|
|
507
|
+
except (json.JSONDecodeError, OSError):
|
|
508
|
+
cfg = {}
|
|
509
|
+
mcp = cfg.setdefault("mcpServers", {})
|
|
510
|
+
changed = False
|
|
511
|
+
if mcp.get(guard_key) != sse_entry:
|
|
512
|
+
mcp[guard_key] = sse_entry
|
|
513
|
+
changed = True
|
|
514
|
+
print(f" {GREEN}conduct-guard MCP registered in {label}{RESET}")
|
|
515
|
+
else:
|
|
516
|
+
print(f" {GRAY}conduct-guard MCP already registered in {label}{RESET}")
|
|
517
|
+
if booster_entry and mcp.get("agent-booster") != booster_entry:
|
|
518
|
+
mcp["agent-booster"] = booster_entry
|
|
519
|
+
changed = True
|
|
520
|
+
if changed:
|
|
521
|
+
cfg_path.write_text(json.dumps(cfg, indent=2))
|
|
502
522
|
|
|
503
523
|
|
|
504
524
|
_GUARD_RULES_TEXT = (
|
|
@@ -1084,7 +1104,7 @@ def _detect_ai_tools() -> list[dict]:
|
|
|
1084
1104
|
def _check_json_mcp(path: Path) -> bool:
|
|
1085
1105
|
try:
|
|
1086
1106
|
d = json.loads(path.read_text()) if path.exists() else {}
|
|
1087
|
-
return "conduct" in d.get("mcpServers", {})
|
|
1107
|
+
return any("conduct" in k for k in d.get("mcpServers", {}))
|
|
1088
1108
|
except Exception:
|
|
1089
1109
|
return False
|
|
1090
1110
|
|
|
@@ -1191,7 +1211,7 @@ def _detect_ai_tools() -> list[dict]:
|
|
|
1191
1211
|
vscode_settings = next((p for p in vscode_candidates if p.exists()), None)
|
|
1192
1212
|
try:
|
|
1193
1213
|
d = json.loads(vscode_settings.read_text()) if vscode_settings else {}
|
|
1194
|
-
mcp_reg = "conduct" in d.get("mcp", {}).get("servers", {})
|
|
1214
|
+
mcp_reg = any("conduct" in k for k in d.get("mcp", {}).get("servers", {}))
|
|
1195
1215
|
except Exception:
|
|
1196
1216
|
mcp_reg = False
|
|
1197
1217
|
# Also check ~/.copilot/mcp-config.json (SSE entry written by guard sync)
|
|
@@ -2321,7 +2341,7 @@ def _discover_config_agents() -> list[tuple]:
|
|
|
2321
2341
|
return "conduct" in text and "mcp_servers" in text
|
|
2322
2342
|
import json as _j
|
|
2323
2343
|
d = _j.loads(text)
|
|
2324
|
-
return "conduct" in d.get("mcpServers", {})
|
|
2344
|
+
return any("conduct" in k for k in d.get("mcpServers", {}))
|
|
2325
2345
|
except Exception:
|
|
2326
2346
|
return False
|
|
2327
2347
|
|
|
@@ -2347,6 +2367,7 @@ def _discover_config_agents() -> list[tuple]:
|
|
|
2347
2367
|
("codex", home / ".codex", home / ".codex" / "config.toml", "mcp"),
|
|
2348
2368
|
("cursor", home / ".cursor", home / ".cursor" / "mcp.json", "mcp"),
|
|
2349
2369
|
("windsurf", home / ".codeium" / "windsurf", home / ".codeium" / "windsurf" / "mcp_config.json", "mcp"),
|
|
2370
|
+
("copilot", home / ".copilot", home / ".copilot" / "mcp-config.json", "mcp"),
|
|
2350
2371
|
]
|
|
2351
2372
|
for name, check_dir, config_path, _ in TOOLS:
|
|
2352
2373
|
if check_dir.exists():
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|