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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conduct-cli
3
- Version: 0.4.32
3
+ Version: 0.4.34
4
4
  Summary: CLI for Conduct AI — install agents, manage projects, run tests
5
5
  Author-email: Conduct AI <hello@conductai.ai>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "conduct-cli"
7
- version = "0.4.32"
7
+ version = "0.4.34"
8
8
  description = "CLI for Conduct AI — install agents, manage projects, run tests"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -31,11 +31,44 @@ import time
31
31
  import urllib.request
32
32
  from pathlib import Path
33
33
 
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
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[[mcp_servers]]\nname = "conduct"\ncommand = "conduct-mcp"\nargs = []\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
- if getattr(args, "create_type", None) == "project":
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
- if getattr(args, "delete_type", None) == "project":
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()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conduct-cli
3
- Version: 0.4.32
3
+ Version: 0.4.34
4
4
  Summary: CLI for Conduct AI — install agents, manage projects, run tests
5
5
  Author-email: Conduct AI <hello@conductai.ai>
6
6
  License: MIT
File without changes
File without changes
File without changes