conduct-cli 0.7.42__tar.gz → 0.7.44__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 (47) hide show
  1. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/PKG-INFO +1 -1
  2. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/pyproject.toml +1 -1
  3. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/guard.py +73 -57
  4. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli.egg-info/PKG-INFO +1 -1
  5. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/README.md +0 -0
  6. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/setup.cfg +0 -0
  7. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/setup.py +0 -0
  8. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/__init__.py +0 -0
  9. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/api.py +0 -0
  10. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/guardmcp.py +0 -0
  11. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/hooks/__init__.py +0 -0
  12. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/hooks/base.py +0 -0
  13. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/hooks/posttooluse.py +0 -0
  14. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/hooks/precompact.py +0 -0
  15. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/hooks/pretooluse.py +0 -0
  16. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/hooks/session_parser.py +0 -0
  17. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/hooks/session_report_push.py +0 -0
  18. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/hooks/session_start.py +0 -0
  19. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/hooks/stop.py +0 -0
  20. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/log_util.py +0 -0
  21. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/main.py +0 -0
  22. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/mcp_server.py +0 -0
  23. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/memory.py +0 -0
  24. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/paxel.py +0 -0
  25. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli/tool_groups.py +0 -0
  26. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli.egg-info/SOURCES.txt +0 -0
  27. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli.egg-info/dependency_links.txt +0 -0
  28. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli.egg-info/entry_points.txt +0 -0
  29. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli.egg-info/requires.txt +0 -0
  30. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/src/conduct_cli.egg-info/top_level.txt +0 -0
  31. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_advisory_and_hook.py +0 -0
  32. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_api_client.py +0 -0
  33. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_bash_operator_signature.py +0 -0
  34. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_blast_radius.py +0 -0
  35. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_cmd_run.py +0 -0
  36. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_command_word_matcher.py +0 -0
  37. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_drain_daemon_health.py +0 -0
  38. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_guard_policy.py +0 -0
  39. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_guard_savings.py +0 -0
  40. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_hook_dispatch.py +0 -0
  41. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_journal_drain.py +0 -0
  42. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_log_util.py +0 -0
  43. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_proxy_coverage.py +0 -0
  44. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_proxy_env.py +0 -0
  45. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_signed_policy.py +0 -0
  46. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_switch.py +0 -0
  47. {conduct_cli-0.7.42 → conduct_cli-0.7.44}/tests/test_token_lifecycle.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conduct-cli
3
- Version: 0.7.42
3
+ Version: 0.7.44
4
4
  Summary: CLI for Conduct AI — secure, govern, 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.7.42"
7
+ version = "0.7.44"
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" }
@@ -441,7 +441,7 @@ def _register_mcp(workspace_id: str, agent_token: str, api_url: str) -> None:
441
441
 
442
442
  # Cursor global rules — write Guard policies as user rules so they apply across all projects.
443
443
  _patch_cursor_global_rules()
444
- _patch_copilot_instructions()
444
+ _patch_tool_instruction_files(agent_token, api_url)
445
445
 
446
446
 
447
447
  def _patch_claude_desktop_proxy(api_url: str, agent_token: str) -> None:
@@ -501,6 +501,16 @@ def _patch_copilot_mcp(agent_token: str, api_url: str) -> None:
501
501
  print(f" {GREEN}conduct-guard MCP registered in GitHub Copilot (SSE){RESET}")
502
502
 
503
503
 
504
+ _GUARD_RULES_TEXT = (
505
+ "Before executing any shell command, file write, network request, API call, or code change:\n"
506
+ "- Call guard_check (conductguard MCP tool) with the action and parameters.\n"
507
+ "- If BLOCKED: stop immediately and explain the policy rule to the user.\n"
508
+ "- If WARNING: proceed but surface the warning. If ALLOWED: proceed normally.\n"
509
+ "- Never write credentials, API keys, or secrets to files or output.\n"
510
+ "- Never send PII (emails, names, payment data) to external endpoints."
511
+ )
512
+
513
+
504
514
  def _patch_cursor_global_rules() -> None:
505
515
  """Write ConductGuard policy rules into Cursor's global user rules setting.
506
516
 
@@ -509,16 +519,7 @@ def _patch_cursor_global_rules() -> None:
509
519
  This is soft enforcement (prompt-level), not structural like Claude Code hooks,
510
520
  but ensures Guard policies are visible to the model across all Cursor projects.
511
521
  """
512
- GUARD_RULES = (
513
- "# ConductGuard — team AI policies (managed by conduct guard sync)\n"
514
- "- ALWAYS call guard_check (via conductguard MCP) before running shell commands, "
515
- "reading or writing files, accessing external APIs, or modifying code.\n"
516
- "- NEVER write credentials, API keys, or secrets to files or output.\n"
517
- "- NEVER send PII (emails, names, SSNs, payment data) to external endpoints.\n"
518
- "- If guard_check returns BLOCKED: stop and explain the policy rule to the user.\n"
519
- "- If guard_check returns WARNING: proceed but surface the warning.\n"
520
- "- These rules are enforced by your team's ConductGuard policy. Do not bypass them."
521
- )
522
+ GUARD_RULES = _GUARD_RULES_TEXT
522
523
 
523
524
  candidates = [
524
525
  Path.home() / "Library" / "Application Support" / "Cursor" / "User" / "settings.json",
@@ -541,59 +542,74 @@ def _patch_cursor_global_rules() -> None:
541
542
  print(f" {GREEN}Cursor global rules updated with ConductGuard policy{RESET}")
542
543
 
543
544
 
544
- def _patch_copilot_instructions() -> None:
545
- """Write ConductGuard enforcement instructions into .github/copilot-instructions.md.
545
+ def _patch_tool_instruction_files(agent_token: str, api_url: str) -> None:
546
+ """Write ConductGuard policy block into instruction files for all AI tools.
546
547
 
547
- Copilot injects this file into every conversation automatically — soft hooks
548
- for tools that don't support PreToolUse/PostToolUse interception.
549
- Written to the current repo root if a .github/ dir exists, and to ~/
550
- as a global fallback.
548
+ Targets:
549
+ CLAUDE.md — Claude Code + Claude Desktop
550
+ .github/copilot-instructions.md — Copilot + VS Code
551
+ AGENTS.md — Codex CLI + Codex Desktop
552
+ .cursorrules — Cursor
553
+ .windsurfrules — Windsurf
554
+
555
+ Merge strategy (never clobbers existing content):
556
+ First sync : appends block between <!-- ConductGuard --> markers
557
+ Re-sync : replaces only the block, leaves surrounding content untouched
551
558
  """
552
- GUARD_BLOCK = (
553
- "<!-- ConductGuard — managed by conduct guard sync, do not edit this block -->\n"
554
- "## ConductGuard Policy\n"
555
- "Before executing any shell command, file write, network request, API call, or code change:\n"
556
- "- Call `guard_check` (conductguard MCP tool) with the action and parameters.\n"
557
- "- If BLOCKED: stop immediately and explain the policy rule to the user.\n"
558
- "- If WARNING: proceed but surface the warning.\n"
559
- "- If ALLOWED: proceed normally.\n"
560
- "Never write credentials, API keys, or secrets to files or output.\n"
561
- "Never send PII (emails, names, payment data) to external endpoints.\n"
562
- "<!-- /ConductGuard -->"
563
- )
559
+ import re as _re
560
+
561
+ MARKER_START = "<!-- ConductGuard — managed by conduct guard sync -->"
562
+ MARKER_END = "<!-- /ConductGuard -->"
563
+ GUARD_RULES = _GUARD_RULES_TEXT
564
564
 
565
- candidates: list[Path] = []
566
- # Repo-level: walk up from cwd to find .github/
567
- cwd = Path.cwd()
568
- for parent in [cwd, *cwd.parents]:
569
- gh = parent / ".github"
570
- if gh.is_dir():
571
- candidates.append(gh / "copilot-instructions.md")
565
+ # Pull team instructions from API (non-fatal)
566
+ team_content = ""
567
+ try:
568
+ resp = _req("GET", f"{api_url}/team-os/instructions", token=agent_token)
569
+ team_content = (resp.get("content") or "").strip()
570
+ except Exception:
571
+ pass
572
+
573
+ parts = [MARKER_START, "## ConductGuard Policy"]
574
+ if team_content:
575
+ parts.append(team_content)
576
+ parts.append(GUARD_RULES)
577
+ parts.append(MARKER_END)
578
+ guard_block = "\n".join(parts)
579
+
580
+ repo_root: Path | None = None
581
+ for parent in [Path.cwd(), *Path.cwd().parents]:
582
+ if (parent / ".git").exists() or (parent / ".github").is_dir():
583
+ repo_root = parent
572
584
  break
573
- # Global fallback
574
- candidates.append(Path.home() / ".github" / "copilot-instructions.md")
575
585
 
576
- wrote_any = False
577
- for path in candidates:
586
+ # (repo path, global fallback, label)
587
+ targets = [
588
+ (repo_root / "CLAUDE.md" if repo_root else None, Path.home() / "CLAUDE.md", "CLAUDE.md"),
589
+ (repo_root / ".github" / "copilot-instructions.md" if repo_root else None, Path.home() / ".github" / "copilot-instructions.md", "Copilot instructions"),
590
+ (repo_root / "AGENTS.md" if repo_root else None, Path.home() / ".codex" / "instructions.md", "AGENTS.md"),
591
+ (repo_root / ".cursorrules" if repo_root else None, Path.home() / ".cursor" / "rules" / "conduct.md", ".cursorrules"),
592
+ (repo_root / ".windsurfrules" if repo_root else None, Path.home() / ".windsurf"/ "rules" / "conduct.md", ".windsurfrules"),
593
+ ]
594
+ pattern = _re.compile(_re.escape(MARKER_START) + r".*?" + _re.escape(MARKER_END), _re.DOTALL)
595
+
596
+ for repo_path, global_path, label in targets:
597
+ path = repo_path if (repo_path and repo_path.exists()) else global_path
598
+ if not path.exists() and repo_path:
599
+ path = repo_path
578
600
  path.parent.mkdir(parents=True, exist_ok=True)
579
601
  existing = path.read_text() if path.exists() else ""
580
- if "<!-- ConductGuard" in existing:
581
- print(f" {GRAY}Copilot instructions already contain ConductGuard policy ({path}){RESET}")
582
- wrote_any = True
583
- continue
584
- updated = (existing.rstrip() + "\n\n" + GUARD_BLOCK).lstrip()
585
- path.write_text(updated)
586
- print(f" {GREEN}Copilot instructions updated with ConductGuard policy ({path}){RESET}")
587
- wrote_any = True
588
- break # repo-level wins; skip global if repo found
589
-
590
- if not wrote_any:
591
- # No .github/ dir found anywhere — write global
592
- global_path = Path.home() / ".github" / "copilot-instructions.md"
593
- global_path.parent.mkdir(parents=True, exist_ok=True)
594
- global_path.write_text(GUARD_BLOCK)
595
- print(f" {GREEN}Copilot instructions written ({global_path}){RESET}")
596
-
602
+ if MARKER_START in existing:
603
+ updated = pattern.sub(guard_block, existing)
604
+ if updated == existing:
605
+ print(f" {GRAY}{label} already up to date{RESET}")
606
+ else:
607
+ path.write_text(updated)
608
+ print(f" {GREEN}{label} updated{RESET}")
609
+ else:
610
+ sep = "\n\n" if existing.strip() else ""
611
+ path.write_text((existing.rstrip() + sep + guard_block + "\n").lstrip())
612
+ print(f" {GREEN}{label} — ConductGuard block added{RESET}")
597
613
 
598
614
  def _install_codex_hook(hook_path: Path) -> None:
599
615
  """Register PreToolUse and PostToolUse hooks in ~/.codex/hooks.json."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: conduct-cli
3
- Version: 0.7.42
3
+ Version: 0.7.44
4
4
  Summary: CLI for Conduct AI — secure, govern, 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