conduct-cli 0.5.3__tar.gz → 0.5.4__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 (27) hide show
  1. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/PKG-INFO +1 -1
  2. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/pyproject.toml +1 -1
  3. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli/guard.py +73 -8
  4. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli/main.py +20 -9
  5. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli.egg-info/PKG-INFO +1 -1
  6. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/README.md +0 -0
  7. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/setup.cfg +0 -0
  8. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/setup.py +0 -0
  9. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli/__init__.py +0 -0
  10. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli/api.py +0 -0
  11. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli/guardmcp.py +0 -0
  12. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli/hook_precompact_template.py +0 -0
  13. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli/hook_session_start_template.py +0 -0
  14. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli/hook_stop_template.py +0 -0
  15. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli/hook_template.py +0 -0
  16. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli/mcp_server.py +0 -0
  17. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli/memory.py +0 -0
  18. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli/paxel.py +0 -0
  19. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli.egg-info/SOURCES.txt +0 -0
  20. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli.egg-info/dependency_links.txt +0 -0
  21. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli.egg-info/entry_points.txt +0 -0
  22. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli.egg-info/requires.txt +0 -0
  23. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/src/conduct_cli.egg-info/top_level.txt +0 -0
  24. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/tests/test_guard_policy.py +0 -0
  25. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/tests/test_guard_savings.py +0 -0
  26. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/tests/test_hook_syntax.py +0 -0
  27. {conduct_cli-0.5.3 → conduct_cli-0.5.4}/tests/test_switch.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conduct-cli
3
- Version: 0.5.3
3
+ Version: 0.5.4
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.5.3"
7
+ version = "0.5.4"
8
8
  description = "CLI for Conduct AI — install agents, manage projects, run tests"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -159,6 +159,61 @@ def _install_session_hooks() -> None:
159
159
 
160
160
  # ── Guard config helpers ──────────────────────────────────────────────────────
161
161
 
162
+ _PERSONA_LABELS = {
163
+ "conservative": "Conservative — production-safe, default deny",
164
+ "standard": "Standard — engineering teams, balanced",
165
+ "developer": "Developer — local dev, audit-first",
166
+ }
167
+
168
+
169
+ def _ensure_persona(workspace_id: str, api_key: str, base_url: str) -> str:
170
+ """Prompt for persona if none is set yet. Saves choice to guard config and API.
171
+
172
+ Returns the active persona name. Skips prompt silently if already set.
173
+ """
174
+ cfg = _load_guard_config()
175
+ if cfg.get("persona"):
176
+ return cfg["persona"]
177
+
178
+ print(f"\n{BOLD}Choose a policy persona for your agents:{RESET}")
179
+ choices = list(_PERSONA_LABELS.keys())
180
+ for i, key in enumerate(choices, 1):
181
+ print(f" {i}. {_PERSONA_LABELS[key]}")
182
+
183
+ while True:
184
+ try:
185
+ raw = input(f"\nEnter 1-{len(choices)} [default: 2 — Standard]: ").strip()
186
+ if raw == "":
187
+ raw = "2"
188
+ idx = int(raw) - 1
189
+ if 0 <= idx < len(choices):
190
+ chosen = choices[idx]
191
+ break
192
+ print(f" Enter a number between 1 and {len(choices)}")
193
+ except (ValueError, EOFError):
194
+ chosen = "standard"
195
+ break
196
+
197
+ # Push to API
198
+ try:
199
+ _req(
200
+ "PATCH",
201
+ f"{base_url}/guard/config/persona",
202
+ body={"persona": chosen},
203
+ api_key=api_key,
204
+ )
205
+ except Exception:
206
+ pass # non-fatal — local config still records the choice
207
+
208
+ # Persist locally so we skip the prompt on subsequent syncs
209
+ cfg = _load_guard_config()
210
+ cfg["persona"] = chosen
211
+ _save_guard_config(cfg)
212
+
213
+ print(f" {GREEN}Persona set:{RESET} {chosen.capitalize()}")
214
+ return chosen
215
+
216
+
162
217
  def _load_guard_config() -> dict:
163
218
  if CONFIG_PATH.exists():
164
219
  return json.loads(CONFIG_PATH.read_text())
@@ -484,6 +539,9 @@ def cmd_guard_install(args):
484
539
  except Exception:
485
540
  pass
486
541
 
542
+ # Persona selection — prompt once, skip if already chosen
543
+ _ensure_persona(workspace_id, api_key, server)
544
+
487
545
  # Persist guard config — include api_key so CLI commands can authenticate
488
546
  import time as _time
489
547
  _save_guard_config({
@@ -655,15 +713,19 @@ def _report_tools_to_server() -> None:
655
713
  "hook_registered": False,
656
714
  })
657
715
 
658
- vscode_candidates = [
659
- home / "Library" / "Application Support" / "Code" / "User" / "settings.json",
660
- home / ".config" / "Code" / "User" / "settings.json",
661
- home / ".vscode" / "settings.json",
662
- ]
663
- vscode_settings = next((p for p in vscode_candidates if p.exists()), None)
664
- if vscode_settings:
716
+ vscode_ext_dir = home / ".vscode" / "extensions"
717
+ copilot_installed = vscode_ext_dir.exists() and any(
718
+ p.name.startswith("github.copilot") for p in vscode_ext_dir.iterdir() if p.is_dir()
719
+ )
720
+ if copilot_installed:
721
+ vscode_candidates = [
722
+ home / "Library" / "Application Support" / "Code" / "User" / "settings.json",
723
+ home / ".config" / "Code" / "User" / "settings.json",
724
+ home / ".vscode" / "settings.json",
725
+ ]
726
+ vscode_settings = next((p for p in vscode_candidates if p.exists()), None)
665
727
  try:
666
- d = json.loads(vscode_settings.read_text())
728
+ d = json.loads(vscode_settings.read_text()) if vscode_settings else {}
667
729
  mcp_reg = "conduct" in d.get("mcp", {}).get("servers", {})
668
730
  except Exception:
669
731
  mcp_reg = False
@@ -718,6 +780,9 @@ def cmd_guard_sync(args):
718
780
  api_key = cfg.get("api_key", "")
719
781
  base_url = _api_url(cfg)
720
782
 
783
+ # Persona selection — prompt once, skip if already chosen
784
+ _ensure_persona(workspace_id, api_key, base_url)
785
+
721
786
  print(f"Syncing policy…")
722
787
 
723
788
  try:
@@ -302,16 +302,21 @@ def _detect_ai_tools() -> list:
302
302
  "hook_registered": False, # Windsurf uses MCP only
303
303
  })
304
304
 
305
- # VS Code (Copilot)
306
- vscode_settings_candidates = [
307
- home / "Library" / "Application Support" / "Code" / "User" / "settings.json",
308
- home / ".config" / "Code" / "User" / "settings.json",
309
- home / ".vscode" / "settings.json",
310
- ]
311
- vscode_settings = next((p for p in vscode_settings_candidates if p.exists()), None)
312
- if vscode_settings:
305
+ # VS Code (Copilot) — only report if Copilot extension is actually installed
306
+ vscode_ext_dir = home / ".vscode" / "extensions"
307
+ copilot_installed = vscode_ext_dir.exists() and any(
308
+ p.name.startswith("github.copilot") for p in vscode_ext_dir.iterdir()
309
+ if p.is_dir()
310
+ )
311
+ if copilot_installed:
312
+ vscode_settings_candidates = [
313
+ home / "Library" / "Application Support" / "Code" / "User" / "settings.json",
314
+ home / ".config" / "Code" / "User" / "settings.json",
315
+ home / ".vscode" / "settings.json",
316
+ ]
317
+ vscode_settings = next((p for p in vscode_settings_candidates if p.exists()), None)
313
318
  try:
314
- d = json.loads(vscode_settings.read_text())
319
+ d = json.loads(vscode_settings.read_text()) if vscode_settings else {}
315
320
  mcp_reg = "conduct" in d.get("mcp", {}).get("servers", {})
316
321
  except Exception:
317
322
  mcp_reg = False
@@ -409,6 +414,12 @@ def cmd_mcp_install(args):
409
414
  if uncovered:
410
415
  print(f"{YELLOW} Not covered: {', '.join(uncovered)} — run: conduct mcp install{RESET}")
411
416
 
417
+ # Push updated coverage to Guard so the dashboard reflects the new state immediately
418
+ try:
419
+ _report_tool_coverage()
420
+ except Exception:
421
+ pass
422
+
412
423
 
413
424
  def cmd_login(args):
414
425
  server = args.server
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conduct-cli
3
- Version: 0.5.3
3
+ Version: 0.5.4
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