Get effective allowed and blocked commands after hierarchy resolution. Hierarchy (highest to lowest priority): 1. BLOCKED_COMMANDS (hardcoded) - always blocked 2. Org blocked_commands - cannot be unblocked 3. Org allowed_commands - adds to global 4. Project allowed_commands
(project_dir: Optional[Path])
| 735 | |
| 736 | |
| 737 | def get_effective_commands(project_dir: Optional[Path]) -> tuple[set[str], set[str]]: |
| 738 | """ |
| 739 | Get effective allowed and blocked commands after hierarchy resolution. |
| 740 | |
| 741 | Hierarchy (highest to lowest priority): |
| 742 | 1. BLOCKED_COMMANDS (hardcoded) - always blocked |
| 743 | 2. Org blocked_commands - cannot be unblocked |
| 744 | 3. Org allowed_commands - adds to global |
| 745 | 4. Project allowed_commands - adds to global + org |
| 746 | |
| 747 | Args: |
| 748 | project_dir: Path to the project directory, or None |
| 749 | |
| 750 | Returns: |
| 751 | Tuple of (allowed_commands, blocked_commands) |
| 752 | """ |
| 753 | # Start with global allowed commands |
| 754 | allowed = ALLOWED_COMMANDS.copy() |
| 755 | blocked = BLOCKED_COMMANDS.copy() |
| 756 | |
| 757 | # Add dangerous commands to blocked (Phase 3 will add approval flow) |
| 758 | blocked |= DANGEROUS_COMMANDS |
| 759 | |
| 760 | # Load org config and apply |
| 761 | org_config = load_org_config() |
| 762 | if org_config: |
| 763 | # Add org-level blocked commands (cannot be overridden) |
| 764 | org_blocked = org_config.get("blocked_commands", []) |
| 765 | blocked |= set(org_blocked) |
| 766 | |
| 767 | # Add org-level allowed commands |
| 768 | for cmd_config in org_config.get("allowed_commands", []): |
| 769 | if isinstance(cmd_config, dict) and "name" in cmd_config: |
| 770 | allowed.add(cmd_config["name"]) |
| 771 | |
| 772 | # Load project config and apply |
| 773 | if project_dir: |
| 774 | project_config = load_project_commands(project_dir) |
| 775 | if project_config: |
| 776 | # Add project-specific commands |
| 777 | for cmd_config in project_config.get("commands", []): |
| 778 | valid, error = validate_project_command(cmd_config) |
| 779 | if valid: |
| 780 | allowed.add(cmd_config["name"]) |
| 781 | |
| 782 | # Remove blocked commands from allowed (blocklist takes precedence) |
| 783 | allowed -= blocked |
| 784 | |
| 785 | return allowed, blocked |
| 786 | |
| 787 | |
| 788 | def get_project_allowed_commands(project_dir: Optional[Path]) -> set[str]: |