aiwcli 0.9.1 → 0.9.2

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 (63) hide show
  1. package/dist/templates/_shared/hooks/__pycache__/context_enforcer.cpython-313.pyc +0 -0
  2. package/dist/templates/_shared/hooks/__pycache__/session_start.cpython-313.pyc +0 -0
  3. package/dist/templates/_shared/hooks/__pycache__/task_create_atomicity.cpython-313.pyc +0 -0
  4. package/dist/templates/_shared/hooks/__pycache__/user_prompt_submit.cpython-313.pyc +0 -0
  5. package/dist/templates/_shared/hooks/context_enforcer.py +65 -15
  6. package/dist/templates/_shared/hooks/session_start.py +108 -0
  7. package/dist/templates/_shared/hooks/task_create_atomicity.py +199 -0
  8. package/dist/templates/_shared/hooks/task_create_capture.py +2 -2
  9. package/dist/templates/_shared/hooks/task_update_capture.py +2 -2
  10. package/dist/templates/_shared/hooks/user_prompt_submit.py +58 -13
  11. package/dist/templates/_shared/lib/base/__pycache__/inference.cpython-313.pyc +0 -0
  12. package/dist/templates/_shared/lib/base/__pycache__/stop_words.cpython-313.pyc +0 -0
  13. package/dist/templates/_shared/lib/base/__pycache__/utils.cpython-313.pyc +0 -0
  14. package/dist/templates/_shared/lib/base/inference.py +20 -35
  15. package/dist/templates/_shared/lib/base/stop_words.py +158 -0
  16. package/dist/templates/_shared/lib/base/utils.py +3 -2
  17. package/dist/templates/_shared/lib/context/__init__.py +0 -2
  18. package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
  19. package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
  20. package/dist/templates/_shared/lib/context/__pycache__/task_sync.cpython-313.pyc +0 -0
  21. package/dist/templates/_shared/lib/context/context_manager.py +2 -2
  22. package/dist/templates/_shared/lib/context/task_sync.py +5 -82
  23. package/dist/templates/_shared/lib/templates/__pycache__/persona_questions.cpython-313.pyc +0 -0
  24. package/dist/templates/_shared/lib/templates/__pycache__/plan_context.cpython-313.pyc +0 -0
  25. package/dist/templates/_shared/lib/templates/persona_questions.py +113 -0
  26. package/dist/templates/_shared/lib/templates/plan_context.py +13 -27
  27. package/dist/templates/cc-native/.claude/agents/cc-native/ACCESSIBILITY-TESTER.md +1 -1
  28. package/dist/templates/cc-native/.claude/agents/cc-native/ARCHITECT-REVIEWER.md +1 -1
  29. package/dist/templates/cc-native/.claude/agents/cc-native/ASSUMPTION-CHAIN-TRACER.md +1 -1
  30. package/dist/templates/cc-native/.claude/agents/cc-native/CLARITY-AUDITOR.md +1 -1
  31. package/dist/templates/cc-native/.claude/agents/cc-native/CODE-REVIEWER.md +1 -1
  32. package/dist/templates/cc-native/.claude/agents/cc-native/COMPLETENESS-CHECKER.md +1 -1
  33. package/dist/templates/cc-native/.claude/agents/cc-native/CONTEXT-EXTRACTOR.md +1 -1
  34. package/dist/templates/cc-native/.claude/agents/cc-native/DEVILS-ADVOCATE.md +1 -1
  35. package/dist/templates/cc-native/.claude/agents/cc-native/FEASIBILITY-ANALYST.md +1 -1
  36. package/dist/templates/cc-native/.claude/agents/cc-native/FRESH-PERSPECTIVE.md +1 -1
  37. package/dist/templates/cc-native/.claude/agents/cc-native/HANDOFF-READINESS.md +1 -1
  38. package/dist/templates/cc-native/.claude/agents/cc-native/HIDDEN-COMPLEXITY-DETECTOR.md +1 -1
  39. package/dist/templates/cc-native/.claude/agents/cc-native/INCENTIVE-MAPPER.md +1 -1
  40. package/dist/templates/cc-native/.claude/agents/cc-native/PENETRATION-TESTER.md +1 -1
  41. package/dist/templates/cc-native/.claude/agents/cc-native/PERFORMANCE-ENGINEER.md +1 -1
  42. package/dist/templates/cc-native/.claude/agents/cc-native/PLAN-ORCHESTRATOR.md +1 -1
  43. package/dist/templates/cc-native/.claude/agents/cc-native/PRECEDENT-FINDER.md +1 -1
  44. package/dist/templates/cc-native/.claude/agents/cc-native/REVERSIBILITY-ANALYST.md +1 -1
  45. package/dist/templates/cc-native/.claude/agents/cc-native/RISK-ASSESSOR.md +1 -1
  46. package/dist/templates/cc-native/.claude/agents/cc-native/SECOND-ORDER-ANALYST.md +1 -1
  47. package/dist/templates/cc-native/.claude/agents/cc-native/SIMPLICITY-GUARDIAN.md +1 -1
  48. package/dist/templates/cc-native/.claude/agents/cc-native/SKEPTIC.md +1 -1
  49. package/dist/templates/cc-native/.claude/agents/cc-native/STAKEHOLDER-ADVOCATE.md +1 -1
  50. package/dist/templates/cc-native/.claude/agents/cc-native/TRADE-OFF-ILLUMINATOR.md +1 -1
  51. package/dist/templates/cc-native/.claude/settings.json +21 -0
  52. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +211 -0
  53. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
  54. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +48 -9
  55. package/dist/templates/cc-native/_cc-native/lib/CLAUDE.md +240 -0
  56. package/dist/templates/cc-native/_cc-native/lib/__pycache__/orchestrator.cpython-313.pyc +0 -0
  57. package/dist/templates/cc-native/_cc-native/lib/orchestrator.py +1 -0
  58. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
  59. package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +1 -0
  60. package/dist/templates/cc-native/_cc-native/plan-review.config.json +6 -0
  61. package/oclif.manifest.json +1 -1
  62. package/package.json +1 -1
  63. package/dist/templates/cc-native/_cc-native/docs/PERMISSION_REQUEST_VERIFICATION.md +0 -147
@@ -3,7 +3,7 @@ name: context-extractor
3
3
  description: Extracts abstracted problem context from conversation for fresh perspective analysis. Strips implementation details, preserves problem essence.
4
4
  model: haiku
5
5
  focus: context abstraction
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -3,7 +3,7 @@ name: devils-advocate
3
3
  description: Takes the contrarian position and pushes logic to uncomfortable extremes. If a plan can't survive its antithesis, it's not robust. This agent asks "what if the exact opposite is true?"
4
4
  model: sonnet
5
5
  focus: contrarian analysis and reductio ad absurdum
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -3,7 +3,7 @@ name: feasibility-analyst
3
3
  description: Evaluates whether plans are achievable given available resources, time, expertise, and technical constraints. Identifies gaps between what's planned and what's realistically possible.
4
4
  model: sonnet
5
5
  focus: resource constraints and technical viability
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -3,7 +3,7 @@ name: fresh-perspective
3
3
  description: Provides unbiased problem-solving perspective without code context. Analyzes from first principles to combat code-anchored thinking.
4
4
  model: sonnet
5
5
  focus: first-principles problem analysis
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -3,7 +3,7 @@ name: handoff-readiness
3
3
  description: Tests whether plans contain sufficient context for execution by a fresh context window with zero prior knowledge. Simulates receiving the plan cold and identifies every point where clarification would be needed—because that question can never be answered. Detects undefined references, missing big-picture goals, implicit assumptions, and context-dependent gaps.
4
4
  model: sonnet
5
5
  focus: fresh context execution readiness
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -3,7 +3,7 @@ name: hidden-complexity-detector
3
3
  description: Surfaces understated difficulty and implementation nightmares hiding behind simple-sounding requirements. Simple plans hide complex reality. This agent asks "what makes this harder than it sounds?"
4
4
  model: sonnet
5
5
  focus: understated complexity and hidden difficulty
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -3,7 +3,7 @@ name: incentive-mapper
3
3
  description: Examines who wins, who loses, and whether incentives align with desired outcomes. Plans fail when people's motivations don't match goals. This agent asks "who benefits from this being true?"
4
4
  model: sonnet
5
5
  focus: incentive alignment and motivation structures
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -3,7 +3,7 @@ name: penetration-tester
3
3
  description: Expert penetration tester specializing in ethical hacking, vulnerability assessment, and security testing. Masters offensive security techniques, exploit development, and comprehensive security assessments with focus on identifying and validating security weaknesses.
4
4
  model: sonnet
5
5
  focus: security vulnerabilities and attack vectors
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -3,7 +3,7 @@ name: performance-engineer
3
3
  description: Expert performance engineer specializing in system optimization, bottleneck identification, and scalability engineering. Masters performance testing, profiling, and tuning across applications, databases, and infrastructure with focus on achieving optimal response times and resource efficiency.
4
4
  model: sonnet
5
5
  focus: performance bottlenecks and optimization
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -3,7 +3,7 @@ name: plan-orchestrator
3
3
  description: Intelligent plan analyzer that determines complexity and routes to appropriate reviewers. Uses fast inference to minimize latency while maximizing review accuracy through targeted agent selection.
4
4
  model: haiku
5
5
  focus: plan complexity analysis and agent routing
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - orchestration
9
9
  tools: Read, Glob, Grep
@@ -3,7 +3,7 @@ name: precedent-finder
3
3
  description: Pattern-matches to historical precedents and their results. History predicts plan outcomes. This agent asks "when has this been tried before, and what happened?"
4
4
  model: sonnet
5
5
  focus: historical patterns and precedent analysis
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -3,7 +3,7 @@ name: reversibility-analyst
3
3
  description: Identifies one-way doors, lock-in, and path dependencies that foreclose future options. Some decisions close doors permanently. This agent asks "can you undo this if you're wrong?"
4
4
  model: sonnet
5
5
  focus: one-way doors and irreversible decisions
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -3,7 +3,7 @@ name: risk-assessor
3
3
  description: Identifies potential failure modes, external dependencies, reversibility concerns, and mitigation strategies. Focuses on what could go wrong and how to prepare for it.
4
4
  model: sonnet
5
5
  focus: failure modes and mitigation strategies
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -3,7 +3,7 @@ name: second-order-analyst
3
3
  description: Traces consequences 2-3 steps beyond immediate effects. Plans that look safe in isolation often trigger cascading failures. This agent maps the domino chain and asks "what breaks downstream?"
4
4
  model: sonnet
5
5
  focus: cascading effects and downstream consequences
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -3,7 +3,7 @@ name: simplicity-guardian
3
3
  description: Detects over-engineering, unnecessary complexity, scope creep, premature abstraction, and YAGNI violations. Advocates for the simplest solution that meets requirements.
4
4
  model: sonnet
5
5
  focus: complexity reduction and scope control
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -3,7 +3,7 @@ name: skeptic
3
3
  description: Adversarial reviewer specializing in problem-solution alignment and assumption validation. Questions whether the plan solves the right problem, challenges hidden assumptions, and identifies over-engineering. Uses Socratic questioning to surface fundamental flaws.
4
4
  model: sonnet
5
5
  focus: problem-solution alignment and assumption validation
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -3,7 +3,7 @@ name: stakeholder-advocate
3
3
  description: Ensures plans actually serve user and business needs, not just technical elegance. Evaluates who benefits, who bears costs, and whether the plan aligns with stakeholder priorities.
4
4
  model: sonnet
5
5
  focus: user value and business alignment
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - design
@@ -3,7 +3,7 @@ name: trade-off-illuminator
3
3
  description: Forces explicit acknowledgment of what's being sacrificed. Every decision has a price. Plans hide their costs. This agent drags hidden trade-offs into the light and asks "what are you giving up?"
4
4
  model: sonnet
5
5
  focus: hidden costs and sacrificed alternatives
6
- enabled: true
6
+ enabled: false
7
7
  categories:
8
8
  - code
9
9
  - infrastructure
@@ -18,6 +18,17 @@
18
18
  }
19
19
  },
20
20
  "hooks": {
21
+ "SessionStart": [
22
+ {
23
+ "hooks": [
24
+ {
25
+ "type": "command",
26
+ "command": "python .aiwcli/_shared/hooks/session_start.py",
27
+ "timeout": 5000
28
+ }
29
+ ]
30
+ }
31
+ ],
21
32
  "UserPromptSubmit": [
22
33
  {
23
34
  "hooks": [
@@ -94,6 +105,16 @@
94
105
  }
95
106
  ],
96
107
  "PreToolUse": [
108
+ {
109
+ "matcher": "TaskCreate",
110
+ "hooks": [
111
+ {
112
+ "type": "command",
113
+ "command": "python .aiwcli/_shared/hooks/task_create_atomicity.py",
114
+ "timeout": 15000
115
+ }
116
+ ]
117
+ },
97
118
  {
98
119
  "matcher": "Write",
99
120
  "hooks": [
@@ -0,0 +1,211 @@
1
+ # CC-Native Hooks Development Guide
2
+
3
+ > **Keep this document updated.** When you solve an issue related to hooks, add the solution to the relevant section and log it in the Changelog. This document should grow with discovered patterns and fixes—don't wait to be asked.
4
+
5
+ ---
6
+
7
+ ## Quick Reference
8
+
9
+ | Hook | Trigger | Purpose |
10
+ |------|---------|---------|
11
+ | `cc-native-plan-review.py` | PreToolUse: ExitPlanMode | Review plans before user approval |
12
+ | `add_plan_context.py` | PostToolUse: EnterPlanMode | Add context when entering plan mode |
13
+ | `suggest-fresh-perspective.py` | PostToolUse | Suggest fresh perspective workflow |
14
+
15
+ ---
16
+
17
+ ## Import Pattern
18
+
19
+ Hooks run from arbitrary working directories. Always set up sys.path explicitly.
20
+
21
+ ```python
22
+ # CORRECT - works in hook context
23
+ from pathlib import Path
24
+ import sys
25
+
26
+ _lib = Path(__file__).parent.parent / "lib"
27
+ sys.path.insert(0, str(_lib))
28
+
29
+ # For shared library access
30
+ _shared = Path(__file__).parent.parent.parent / "_shared"
31
+ sys.path.insert(0, str(_shared))
32
+
33
+ from utils import eprint, ReviewerResult
34
+ from lib.base.subprocess_utils import is_internal_call
35
+ ```
36
+
37
+ ```python
38
+ # WRONG - relative imports fail in hook context
39
+ from ..lib import utils # ModuleNotFoundError
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Internal Call Detection
45
+
46
+ Hooks can be invoked recursively when spawning subprocesses (agents, orchestrator). Always check and skip:
47
+
48
+ ```python
49
+ def main() -> int:
50
+ # FIRST LINE of main - before any other logic
51
+ if is_internal_call():
52
+ return 0 # Skip for subprocess calls
53
+
54
+ # Rest of hook logic...
55
+ ```
56
+
57
+ Without this check, the hook runs multiple times per plan review, causing duplicate reviews and state corruption.
58
+
59
+ ---
60
+
61
+ ## Hook Output Format
62
+
63
+ Claude Code hooks return JSON to stdout. The format is specific to each hook type.
64
+
65
+ ### PreToolUse Output
66
+
67
+ ```python
68
+ # CORRECT - current API format
69
+ import json
70
+
71
+ out = {
72
+ "hookSpecificOutput": {
73
+ "hookEventName": "PreToolUse",
74
+ "additionalContext": "Information for Claude to see...",
75
+ }
76
+ }
77
+
78
+ # To block the tool call:
79
+ out["hookSpecificOutput"]["permissionDecision"] = "deny"
80
+ out["hookSpecificOutput"]["permissionDecisionReason"] = "Reason shown to Claude"
81
+
82
+ print(json.dumps(out, ensure_ascii=False))
83
+ ```
84
+
85
+ ```python
86
+ # WRONG - old format, silently ignored
87
+ {"decision": "block", "reason": "..."} # Does nothing
88
+ {"continue": False, "message": "..."} # Does nothing
89
+ ```
90
+
91
+ **Key insight:** The old `decision`/`reason` format fails silently. If your hook isn't affecting Claude's behavior, check the output format first.
92
+
93
+ ---
94
+
95
+ ## Debugging Output
96
+
97
+ Hooks communicate via stdout (JSON) and stderr (logs). Use them correctly:
98
+
99
+ ```python
100
+ # CORRECT - logs go to stderr, visible in terminal
101
+ def eprint(*args):
102
+ print(*args, file=sys.stderr)
103
+
104
+ eprint("[hook-name] Starting hook...")
105
+ eprint(f"[hook-name] Found {len(items)} items")
106
+ ```
107
+
108
+ ```python
109
+ # WRONG - print() goes to stdout, corrupts JSON output
110
+ print("Debug info") # Breaks JSON parsing
111
+ print(json.dumps(output)) # Now invalid because of previous print
112
+ ```
113
+
114
+ ---
115
+
116
+ ## Context System Integration
117
+
118
+ Plan review hooks integrate with the shared context system for state management:
119
+
120
+ ```python
121
+ from lib.context.context_manager import (
122
+ get_context_by_session_id,
123
+ get_all_in_flight_contexts,
124
+ )
125
+ from lib.base.constants import get_context_reviews_dir
126
+
127
+ # Find active context
128
+ context = get_context_by_session_id(session_id, project_root)
129
+ if not context:
130
+ # Fallback: find single planning context
131
+ in_flight = get_all_in_flight_contexts(project_root)
132
+ planning = [c for c in in_flight if c.in_flight and c.in_flight.mode == "planning"]
133
+ if len(planning) == 1:
134
+ context = planning[0]
135
+
136
+ # Get reviews directory for this context
137
+ reviews_dir = get_context_reviews_dir(context.id, project_root)
138
+ ```
139
+
140
+ If context isn't found, add diagnostic logging:
141
+
142
+ ```python
143
+ eprint(f"[hook] Session ID: {session_id}")
144
+ eprint(f"[hook] In-flight contexts: {len(in_flight)}")
145
+ eprint(f"[hook] Modes: {[c.in_flight.mode for c in in_flight]}")
146
+ ```
147
+
148
+ ---
149
+
150
+ ## Error Handling
151
+
152
+ Hooks should fail gracefully - a broken hook shouldn't break the user's workflow:
153
+
154
+ ```python
155
+ def main() -> int:
156
+ try:
157
+ # Hook logic...
158
+ return 0
159
+ except Exception as e:
160
+ eprint(f"[hook-name] Error: {e}")
161
+ # Return 0 to not block the user
162
+ return 0
163
+
164
+ if __name__ == "__main__":
165
+ try:
166
+ raise SystemExit(main())
167
+ except Exception as e:
168
+ import traceback
169
+ eprint(f"[hook-name] FATAL: {e}")
170
+ traceback.print_exc(file=sys.stderr)
171
+ # Still exit 0 to not block - or exit 1 if blocking is intentional
172
+ raise SystemExit(0)
173
+ ```
174
+
175
+ Use `sys.exit(1)` only for intentional blocking (e.g., `blockOnFail: true` configured).
176
+
177
+ ---
178
+
179
+ ## DO NOT
180
+
181
+ These are reminders based on past issues. Not enforcement rules.
182
+
183
+ - **Don't modify hook output format** without verifying the current Claude Code hook API (it changes between versions)
184
+ - **Don't use `sys.exit(1)`** for non-fatal errors - it blocks the user's workflow
185
+ - **Don't forget template sync** after modifying hooks in `.aiwcli/` - changes should also go to `packages/cli/src/templates/cc-native/`
186
+ - **Don't use `print()`** for anything except the final JSON output
187
+ - **Don't assume session_id format** - it can be UUID, path-like, or other formats
188
+ - **Don't skip `is_internal_call()` check** - recursive hook execution causes state corruption
189
+ - **Don't hardcode paths** - use `Path(__file__)` and environment variables
190
+
191
+ ---
192
+
193
+ ## Verification After Changes
194
+
195
+ Always validate Python syntax after editing hooks:
196
+
197
+ ```bash
198
+ python -m py_compile packages/cli/src/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py
199
+ ```
200
+
201
+ Hooks fail silently on syntax errors - this catches them before they reach production.
202
+
203
+ ---
204
+
205
+ ## Changelog
206
+
207
+ <!-- Add dated entries as new issues are discovered -->
208
+
209
+ | Date | Change |
210
+ |------|--------|
211
+ | 2026-02-03 | Initial creation |
@@ -29,6 +29,7 @@ Output: _output/cc-native/plans/{YYYY-MM-DD}/{slug}/reviews/
29
29
 
30
30
  import json
31
31
  import os
32
+ import random
32
33
  import sys
33
34
  from concurrent.futures import ThreadPoolExecutor, as_completed
34
35
  from datetime import datetime
@@ -522,7 +523,9 @@ def main() -> int:
522
523
  gemini_enabled = plan_review_enabled and reviewers_config.get("gemini", {}).get("enabled", False)
523
524
 
524
525
  agent_library = load_agent_library(base, agent_settings) if agent_review_enabled else []
525
- enabled_agents = [a for a in agent_library if a.enabled]
526
+ # Load all agents regardless of enabled status - enabled:false only prevents
527
+ # Claude Code auto-suggestion, not plan-review usage
528
+ enabled_agents = agent_library
526
529
  timeout = agent_settings.get("timeout", 120)
527
530
  legacy_mode = agent_settings.get("legacyMode", False)
528
531
 
@@ -585,19 +588,42 @@ def main() -> int:
585
588
 
586
589
  selected_agents: List[AgentConfig] = []
587
590
 
591
+ # Load mandatory and fallback config
592
+ mandatory_names = set(agent_settings.get("mandatoryAgents", [
593
+ "handoff-readiness", "clarity-auditor", "skeptic"
594
+ ]))
595
+ fallback_by_complexity = agent_settings.get("fallbackByComplexity", {
596
+ "simple": 0, "medium": 5, "high": 9
597
+ })
598
+
588
599
  if enabled_agents:
600
+ # Split into mandatory and non-mandatory pools
601
+ mandatory_agents = [a for a in enabled_agents if a.name in mandatory_names]
602
+ non_mandatory = [a for a in enabled_agents if a.name not in mandatory_names]
603
+
604
+ eprint(f"[cc-native-plan-review] Mandatory agents: {[a.name for a in mandatory_agents]}")
605
+ eprint(f"[cc-native-plan-review] Non-mandatory pool: {len(non_mandatory)} agents")
606
+
589
607
  if orch_result and not legacy_mode:
590
- # Use orchestrator result from phase 1
591
608
  detected_complexity = orch_result.complexity
592
609
 
593
- selected_names = set(orch_result.selected_agents)
594
- selected_agents = [a for a in enabled_agents if a.name in selected_names]
610
+ # Get orchestrator's additional selections (excluding mandatory since they always run)
611
+ orch_selected_names = set(orch_result.selected_agents) - mandatory_names
612
+ orch_selected = [a for a in non_mandatory if a.name in orch_selected_names]
595
613
 
596
- if not selected_agents and selected_names:
597
- eprint(f"[cc-native-plan-review] Warning: orchestrator selected unknown agents: {selected_names}")
598
- selected_agents = [a for a in enabled_agents if orch_result.category in a.categories]
614
+ eprint(f"[cc-native-plan-review] Orchestrator selected (non-mandatory): {[a.name for a in orch_selected]}")
599
615
 
600
- eprint(f"[cc-native-plan-review] Orchestrator selected: {[a.name for a in selected_agents]}")
616
+ # Random fallback if orchestrator selected zero additional agents
617
+ if not orch_selected and non_mandatory:
618
+ fallback_count = fallback_by_complexity.get(detected_complexity, 5)
619
+ fallback_count = min(fallback_count, len(non_mandatory))
620
+ if fallback_count > 0:
621
+ orch_selected = random.sample(non_mandatory, fallback_count)
622
+ eprint(f"[cc-native-plan-review] Random fallback ({detected_complexity}): {[a.name for a in orch_selected]}")
623
+
624
+ # Combine: mandatory + orchestrator/fallback selection
625
+ selected_agents = mandatory_agents + orch_selected
626
+ eprint(f"[cc-native-plan-review] Final selection: {len(selected_agents)} agents ({len(mandatory_agents)} mandatory + {len(orch_selected)} additional)")
601
627
  else:
602
628
  eprint("[cc-native-plan-review] Running in legacy mode (all enabled agents)")
603
629
  selected_agents = enabled_agents
@@ -764,4 +790,17 @@ def main() -> int:
764
790
 
765
791
 
766
792
  if __name__ == "__main__":
767
- raise SystemExit(main())
793
+ try:
794
+ raise SystemExit(main())
795
+ except Exception as e:
796
+ import traceback
797
+ print(f"[cc-native-plan-review] FATAL ERROR: {e}", file=sys.stderr)
798
+ traceback.print_exc(file=sys.stderr)
799
+ # Output error to Claude via hook format so it's visible
800
+ print(json.dumps({
801
+ "hookSpecificOutput": {
802
+ "hookEventName": "PreToolUse",
803
+ "additionalContext": f"**CC-Native Plan Review Hook Error**\n\nThe hook encountered an error:\n```\n{traceback.format_exc()}\n```\n\nPlease report this issue.",
804
+ }
805
+ }))
806
+ raise SystemExit(1)