conduct-cli 0.4.32__tar.gz → 0.4.34__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.4.32 → conduct_cli-0.4.34}/PKG-INFO +1 -1
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/pyproject.toml +1 -1
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/src/conduct_cli/guard.py +41 -5
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/src/conduct_cli/main.py +5 -3
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/src/conduct_cli.egg-info/PKG-INFO +1 -1
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/README.md +0 -0
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/setup.cfg +0 -0
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/setup.py +0 -0
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/src/conduct_cli/__init__.py +0 -0
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/src/conduct_cli/api.py +0 -0
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/src/conduct_cli/guardmcp.py +0 -0
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/src/conduct_cli/mcp_server.py +0 -0
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/src/conduct_cli.egg-info/SOURCES.txt +0 -0
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/src/conduct_cli.egg-info/dependency_links.txt +0 -0
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/src/conduct_cli.egg-info/entry_points.txt +0 -0
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/src/conduct_cli.egg-info/requires.txt +0 -0
- {conduct_cli-0.4.32 → conduct_cli-0.4.34}/src/conduct_cli.egg-info/top_level.txt +0 -0
|
@@ -31,11 +31,44 @@ import time
|
|
|
31
31
|
import urllib.request
|
|
32
32
|
from pathlib import Path
|
|
33
33
|
|
|
34
|
-
GUARD_DIR
|
|
35
|
-
POLICY_PATH
|
|
36
|
-
CONFIG_PATH
|
|
37
|
-
BUDGET_CACHE_PATH
|
|
38
|
-
BUDGET_CACHE_TTL
|
|
34
|
+
GUARD_DIR = Path.home() / ".conductguard"
|
|
35
|
+
POLICY_PATH = GUARD_DIR / "policy.json"
|
|
36
|
+
CONFIG_PATH = GUARD_DIR / "config.json"
|
|
37
|
+
BUDGET_CACHE_PATH = GUARD_DIR / "budget_cache.json"
|
|
38
|
+
BUDGET_CACHE_TTL = 300 # 5 minutes
|
|
39
|
+
VERSION_CACHE_PATH = GUARD_DIR / "version_cache.json"
|
|
40
|
+
VERSION_CACHE_TTL = 60 # 1 minute — matches server poll window
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _maybe_sync_policy():
|
|
44
|
+
"""Check server policy version once per minute; re-download if stale. Never raises."""
|
|
45
|
+
try:
|
|
46
|
+
cfg = json.loads(CONFIG_PATH.read_text()) if CONFIG_PATH.exists() else {}
|
|
47
|
+
workspace_id = cfg.get("workspace_id")
|
|
48
|
+
api_key = cfg.get("api_key", "")
|
|
49
|
+
api_url = cfg.get("api_url", "https://api.conductai.ai").rstrip("/")
|
|
50
|
+
if not workspace_id:
|
|
51
|
+
return
|
|
52
|
+
# Check cache TTL
|
|
53
|
+
if VERSION_CACHE_PATH.exists():
|
|
54
|
+
cache = json.loads(VERSION_CACHE_PATH.read_text())
|
|
55
|
+
if time.time() - cache.get("ts", 0) < VERSION_CACHE_TTL:
|
|
56
|
+
return
|
|
57
|
+
# Fetch current version from server
|
|
58
|
+
url = f"{api_url}/guard/policies/sync?workspace_id={workspace_id}"
|
|
59
|
+
req = urllib.request.Request(url, headers={"Authorization": f"Bearer {api_key}"} if api_key else {})
|
|
60
|
+
with urllib.request.urlopen(req, timeout=2) as resp:
|
|
61
|
+
remote = json.loads(resp.read())
|
|
62
|
+
remote_version = remote.get("version", "")
|
|
63
|
+
# Compare to local
|
|
64
|
+
local_version = ""
|
|
65
|
+
if POLICY_PATH.exists():
|
|
66
|
+
local_version = json.loads(POLICY_PATH.read_text()).get("version", "")
|
|
67
|
+
if remote_version != local_version:
|
|
68
|
+
POLICY_PATH.write_text(json.dumps(remote, indent=2))
|
|
69
|
+
VERSION_CACHE_PATH.write_text(json.dumps({"ts": time.time(), "version": remote_version}))
|
|
70
|
+
except Exception:
|
|
71
|
+
pass # Never block a tool call due to sync failure
|
|
39
72
|
|
|
40
73
|
|
|
41
74
|
def _load_budget_cache():
|
|
@@ -366,6 +399,9 @@ def main():
|
|
|
366
399
|
except Exception:
|
|
367
400
|
sys.exit(0)
|
|
368
401
|
|
|
402
|
+
# Policy version check (cached 60s) — auto-syncs if server version differs
|
|
403
|
+
_maybe_sync_policy()
|
|
404
|
+
|
|
369
405
|
# Hard budget cap (cached 5 min)
|
|
370
406
|
hard_blocked, reason = _load_budget_cache()
|
|
371
407
|
if hard_blocked is None:
|
|
@@ -218,7 +218,7 @@ def _write_codex_mcp_config() -> bool:
|
|
|
218
218
|
content = config_path.read_text() if config_path.exists() else ""
|
|
219
219
|
if "conduct-mcp" in content:
|
|
220
220
|
return True
|
|
221
|
-
mcp_block = '\n[
|
|
221
|
+
mcp_block = '\n[mcp_servers.conduct]\ncommand = "conduct-mcp"\nargs = []\n'
|
|
222
222
|
config_path.write_text(content + mcp_block)
|
|
223
223
|
return True
|
|
224
224
|
except Exception:
|
|
@@ -1487,7 +1487,8 @@ def main():
|
|
|
1487
1487
|
elif args.command == "projects":
|
|
1488
1488
|
cmd_projects(args)
|
|
1489
1489
|
elif args.command == "create":
|
|
1490
|
-
|
|
1490
|
+
create_args = getattr(args, "create_args", None)
|
|
1491
|
+
if create_args:
|
|
1491
1492
|
cmd_create(args)
|
|
1492
1493
|
else:
|
|
1493
1494
|
create_p.print_help()
|
|
@@ -1496,7 +1497,8 @@ def main():
|
|
|
1496
1497
|
elif args.command == "install":
|
|
1497
1498
|
cmd_install(args)
|
|
1498
1499
|
elif args.command == "delete":
|
|
1499
|
-
|
|
1500
|
+
delete_args = getattr(args, "delete_args", None)
|
|
1501
|
+
if delete_args:
|
|
1500
1502
|
cmd_delete(args)
|
|
1501
1503
|
else:
|
|
1502
1504
|
delete_p.print_help()
|
|
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
|