conduct-cli 0.4.71__tar.gz → 0.4.72__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.
Files changed (26) hide show
  1. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/PKG-INFO +2 -2
  2. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/pyproject.toml +2 -2
  3. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/src/conduct_cli/guard.py +139 -0
  4. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/src/conduct_cli.egg-info/PKG-INFO +2 -2
  5. conduct_cli-0.4.72/src/conduct_cli.egg-info/requires.txt +3 -0
  6. conduct_cli-0.4.71/src/conduct_cli.egg-info/requires.txt +0 -3
  7. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/README.md +0 -0
  8. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/setup.cfg +0 -0
  9. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/setup.py +0 -0
  10. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/src/conduct_cli/__init__.py +0 -0
  11. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/src/conduct_cli/api.py +0 -0
  12. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/src/conduct_cli/guardmcp.py +0 -0
  13. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/src/conduct_cli/hook_precompact_template.py +0 -0
  14. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/src/conduct_cli/hook_session_start_template.py +0 -0
  15. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/src/conduct_cli/hook_template.py +0 -0
  16. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/src/conduct_cli/main.py +0 -0
  17. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/src/conduct_cli/mcp_server.py +0 -0
  18. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/src/conduct_cli/memory.py +0 -0
  19. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/src/conduct_cli.egg-info/SOURCES.txt +0 -0
  20. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/src/conduct_cli.egg-info/dependency_links.txt +0 -0
  21. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/src/conduct_cli.egg-info/entry_points.txt +0 -0
  22. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/src/conduct_cli.egg-info/top_level.txt +0 -0
  23. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/tests/test_guard_policy.py +0 -0
  24. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/tests/test_guard_savings.py +0 -0
  25. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/tests/test_hook_syntax.py +0 -0
  26. {conduct_cli-0.4.71 → conduct_cli-0.4.72}/tests/test_switch.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conduct-cli
3
- Version: 0.4.71
3
+ Version: 0.4.72
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
@@ -22,7 +22,7 @@ Requires-Python: >=3.9
22
22
  Description-Content-Type: text/markdown
23
23
  Requires-Dist: pyyaml>=6.0
24
24
  Requires-Dist: rich>=13.0
25
- Requires-Dist: agent-booster[watch]>=0.2.22
25
+ Requires-Dist: agent-booster[watch]>=0.2.23
26
26
 
27
27
  # conduct-cli
28
28
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "conduct-cli"
7
- version = "0.4.71"
7
+ version = "0.4.72"
8
8
  description = "CLI for Conduct AI — install agents, manage projects, run tests"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -23,7 +23,7 @@ classifiers = [
23
23
  "Programming Language :: Python :: 3.12",
24
24
  "Topic :: Software Development :: Libraries :: Application Frameworks",
25
25
  ]
26
- dependencies = ["pyyaml>=6.0", "rich>=13.0", "agent-booster[watch]>=0.2.22"]
26
+ dependencies = ["pyyaml>=6.0", "rich>=13.0", "agent-booster[watch]>=0.2.23"]
27
27
 
28
28
  [project.urls]
29
29
  Homepage = "https://conductai.ai"
@@ -740,6 +740,9 @@ def cmd_guard_sync(args):
740
740
  pass
741
741
  print(f" {GREEN}Hook script updated{RESET}")
742
742
 
743
+ # Auto-init Agent Booster if installed but not yet set up in this project
744
+ _ensure_booster(Path.cwd())
745
+
743
746
  # Capture savings from RTK and Agent Booster
744
747
  _report_savings(cfg, base_url, api_key)
745
748
 
@@ -752,6 +755,48 @@ def cmd_guard_sync(args):
752
755
  print(f"\n{BOLD}Policy refreshed ({rule_count} rule(s)).{RESET}")
753
756
 
754
757
 
758
+ def _ensure_booster(root: Path) -> None:
759
+ """Auto-init and background-index booster if installed but not yet set up."""
760
+ import shutil
761
+ import subprocess
762
+
763
+ if not shutil.which("booster"):
764
+ return # not installed — conduct-cli 0.4.71+ installs it, but may not be on PATH yet
765
+
766
+ db_path = root / ".booster" / "symbols.db"
767
+ hooks_path = root / ".claude" / "hooks" / "booster-gate.py"
768
+
769
+ # Init (writes hook scripts + wires settings.json) — fast, idempotent
770
+ if not hooks_path.exists():
771
+ try:
772
+ subprocess.run(["booster", "init", "--yes"], capture_output=True, timeout=15, cwd=str(root))
773
+ print(f" {GREEN}Agent Booster:{RESET} hooks installed")
774
+ except Exception:
775
+ return
776
+
777
+ # Index in background — may take 10-60s on large repos, never blocks sync
778
+ if not db_path.exists():
779
+ try:
780
+ subprocess.Popen(
781
+ ["booster", "index", "--embed"],
782
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
783
+ cwd=str(root),
784
+ )
785
+ print(f" {GREEN}Agent Booster:{RESET} indexing in background (Read/Grep intercept active shortly)")
786
+ except Exception:
787
+ pass
788
+ else:
789
+ symbols_count = 0
790
+ try:
791
+ import sqlite3
792
+ conn = sqlite3.connect(str(db_path))
793
+ symbols_count = conn.execute("SELECT COUNT(*) FROM symbols").fetchone()[0]
794
+ conn.close()
795
+ except Exception:
796
+ pass
797
+ print(f" {GREEN}Agent Booster:{RESET} {symbols_count} symbols indexed — Read/Grep intercept active")
798
+
799
+
755
800
  def _report_savings(cfg: dict, base_url: str, api_key: str) -> None:
756
801
  import subprocess
757
802
 
@@ -1054,9 +1099,101 @@ def register_guard_parser(sub):
1054
1099
  help="Time window: 1h, 24h, 7d, 30d (default: 24h)",
1055
1100
  )
1056
1101
 
1102
+ # conduct guard booster-status
1103
+ guard_sub.add_parser("booster-status", help="Verify Agent Booster intercept is active for this project")
1104
+
1057
1105
  return guard_p, guard_sub
1058
1106
 
1059
1107
 
1108
+ def cmd_guard_booster_status(args):
1109
+ """Show whether booster is intercepting Read/Grep in this project."""
1110
+ import shutil, sqlite3, subprocess
1111
+
1112
+ root = Path.cwd()
1113
+ db_path = root / ".booster" / "symbols.db"
1114
+ hooks_path = root / ".claude" / "hooks" / "booster-gate.py"
1115
+ settings_p = root / ".claude" / "settings.json"
1116
+
1117
+ booster_bin = shutil.which("booster")
1118
+ print(f"\n{BOLD}Agent Booster intercept status — {root.name}{RESET}\n")
1119
+
1120
+ # 1. Binary
1121
+ if booster_bin:
1122
+ print(f" {GREEN}✓{RESET} booster installed ({booster_bin})")
1123
+ else:
1124
+ print(f" {RED}✗{RESET} booster not found on PATH — run: pip install agent-booster")
1125
+ return
1126
+
1127
+ # 2. Hook scripts written
1128
+ if hooks_path.exists():
1129
+ print(f" {GREEN}✓{RESET} hook scripts present (.claude/hooks/booster-gate.py)")
1130
+ else:
1131
+ print(f" {RED}✗{RESET} hook scripts missing — run: conduct guard sync")
1132
+
1133
+ # 3. Wired in settings.json
1134
+ wired = False
1135
+ if settings_p.exists():
1136
+ import json as _json
1137
+ s = _json.loads(settings_p.read_text())
1138
+ for h in s.get("hooks", {}).get("PreToolUse", []):
1139
+ if h.get("matcher") == "Read":
1140
+ wired = True
1141
+ break
1142
+ if wired:
1143
+ print(f" {GREEN}✓{RESET} Read hook wired in .claude/settings.json")
1144
+ else:
1145
+ print(f" {RED}✗{RESET} Read hook NOT in .claude/settings.json — run: conduct guard sync")
1146
+
1147
+ # 4. Index
1148
+ if db_path.exists():
1149
+ try:
1150
+ conn = sqlite3.connect(str(db_path))
1151
+ count = conn.execute("SELECT COUNT(*) FROM symbols").fetchone()[0]
1152
+ files = conn.execute("SELECT COUNT(DISTINCT file) FROM symbols").fetchone()[0]
1153
+ conn.close()
1154
+ print(f" {GREEN}✓{RESET} symbols.db — {count} symbols across {files} files")
1155
+ except Exception:
1156
+ print(f" {YELLOW}?{RESET} symbols.db exists but could not be read")
1157
+ else:
1158
+ print(f" {RED}✗{RESET} symbols.db missing — Read calls fall through unintercepted")
1159
+ print(f" run: booster index --embed (or: conduct guard sync to trigger it)")
1160
+ return
1161
+
1162
+ # 5. Live intercept test — try reading a known file and check if smart-read fires
1163
+ print(f"\n {BOLD}Live intercept test:{RESET}")
1164
+ try:
1165
+ import tempfile, json as _json
1166
+ # Pick the first indexed file
1167
+ conn = sqlite3.connect(str(db_path))
1168
+ row = conn.execute("SELECT file FROM symbols LIMIT 1").fetchone()
1169
+ conn.close()
1170
+ if row:
1171
+ # Prefer a .py/.ts file — more likely to have symbols and trigger smart-read
1172
+ conn = sqlite3.connect(str(db_path))
1173
+ src = conn.execute(
1174
+ "SELECT file FROM symbols WHERE file LIKE '%.py' OR file LIKE '%.ts' LIMIT 1"
1175
+ ).fetchone() or row
1176
+ conn.close()
1177
+ test_file = str(root / src[0])
1178
+ payload = _json.dumps({"tool_name": "Read", "tool_input": {"file_path": test_file}})
1179
+ r = subprocess.run(
1180
+ ["python3", str(hooks_path)],
1181
+ input=payload, capture_output=True, text=True, timeout=10,
1182
+ )
1183
+ if r.returncode == 2:
1184
+ lines = r.stdout.strip().splitlines()
1185
+ print(f" {GREEN}✓{RESET} Read intercepted → smart-read fired ({len(lines)} lines returned)")
1186
+ print(f" tested on: {row[0]}")
1187
+ elif r.returncode == 0:
1188
+ print(f" {YELLOW}~{RESET} Hook ran but passed through (file may not have symbols)")
1189
+ else:
1190
+ print(f" {RED}✗{RESET} Hook errored (exit {r.returncode})")
1191
+ except Exception as e:
1192
+ print(f" {YELLOW}?{RESET} Could not run live test: {e}")
1193
+
1194
+ print()
1195
+
1196
+
1060
1197
  def dispatch_guard(args, guard_p):
1061
1198
  """Dispatch to the correct guard handler. Called from main()."""
1062
1199
  guard_command = getattr(args, "guard_command", None)
@@ -1068,6 +1205,8 @@ def dispatch_guard(args, guard_p):
1068
1205
  cmd_guard_savings(args)
1069
1206
  elif guard_command == "audit":
1070
1207
  cmd_guard_audit(args)
1208
+ elif guard_command == "booster-status":
1209
+ cmd_guard_booster_status(args)
1071
1210
  else:
1072
1211
  guard_p.print_help()
1073
1212
  sys.exit(1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conduct-cli
3
- Version: 0.4.71
3
+ Version: 0.4.72
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
@@ -22,7 +22,7 @@ Requires-Python: >=3.9
22
22
  Description-Content-Type: text/markdown
23
23
  Requires-Dist: pyyaml>=6.0
24
24
  Requires-Dist: rich>=13.0
25
- Requires-Dist: agent-booster[watch]>=0.2.22
25
+ Requires-Dist: agent-booster[watch]>=0.2.23
26
26
 
27
27
  # conduct-cli
28
28
 
@@ -0,0 +1,3 @@
1
+ pyyaml>=6.0
2
+ rich>=13.0
3
+ agent-booster[watch]>=0.2.23
@@ -1,3 +0,0 @@
1
- pyyaml>=6.0
2
- rich>=13.0
3
- agent-booster[watch]>=0.2.22
File without changes
File without changes
File without changes