aiwcli 0.9.2 → 0.9.5

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 (65) hide show
  1. package/dist/templates/_shared/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
  2. package/dist/templates/_shared/hooks/__pycache__/context_enforcer.cpython-313.pyc +0 -0
  3. package/dist/templates/_shared/hooks/__pycache__/context_monitor.cpython-313.pyc +0 -0
  4. package/dist/templates/_shared/hooks/__pycache__/file-suggestion.cpython-313.pyc +0 -0
  5. package/dist/templates/_shared/hooks/__pycache__/session_start.cpython-313.pyc +0 -0
  6. package/dist/templates/_shared/hooks/__pycache__/task_create_atomicity.cpython-313.pyc +0 -0
  7. package/dist/templates/_shared/hooks/__pycache__/task_create_capture.cpython-313.pyc +0 -0
  8. package/dist/templates/_shared/hooks/__pycache__/task_update_capture.cpython-313.pyc +0 -0
  9. package/dist/templates/_shared/hooks/__pycache__/user_prompt_submit.cpython-313.pyc +0 -0
  10. package/dist/templates/_shared/hooks/archive_plan.py +28 -38
  11. package/dist/templates/_shared/hooks/context_enforcer.py +6 -6
  12. package/dist/templates/_shared/hooks/context_monitor.py +4 -8
  13. package/dist/templates/_shared/hooks/file-suggestion.py +4 -10
  14. package/dist/templates/_shared/hooks/session_start.py +4 -9
  15. package/dist/templates/_shared/hooks/task_create_atomicity.py +90 -84
  16. package/dist/templates/_shared/hooks/task_create_capture.py +83 -146
  17. package/dist/templates/_shared/hooks/task_update_capture.py +116 -167
  18. package/dist/templates/_shared/hooks/user_prompt_submit.py +4 -9
  19. package/dist/templates/_shared/lib/__pycache__/__init__.cpython-313.pyc +0 -0
  20. package/dist/templates/_shared/lib/base/__pycache__/__init__.cpython-313.pyc +0 -0
  21. package/dist/templates/_shared/lib/base/__pycache__/atomic_write.cpython-313.pyc +0 -0
  22. package/dist/templates/_shared/lib/base/__pycache__/constants.cpython-313.pyc +0 -0
  23. package/dist/templates/_shared/lib/base/__pycache__/hook_utils.cpython-313.pyc +0 -0
  24. package/dist/templates/_shared/lib/base/__pycache__/utils.cpython-313.pyc +0 -0
  25. package/dist/templates/_shared/lib/base/hook_utils.py +169 -0
  26. package/dist/templates/_shared/lib/context/__init__.py +9 -0
  27. package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
  28. package/dist/templates/_shared/lib/context/__pycache__/cache.cpython-313.pyc +0 -0
  29. package/dist/templates/_shared/lib/context/__pycache__/context_extractor.cpython-313.pyc +0 -0
  30. package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
  31. package/dist/templates/_shared/lib/context/__pycache__/discovery.cpython-313.pyc +0 -0
  32. package/dist/templates/_shared/lib/context/__pycache__/plan_archive.cpython-313.pyc +0 -0
  33. package/dist/templates/_shared/lib/context/context_extractor.py +115 -0
  34. package/dist/templates/_shared/lib/context/discovery.py +4 -4
  35. package/dist/templates/_shared/lib/templates/__pycache__/__init__.cpython-313.pyc +0 -0
  36. package/dist/templates/_shared/lib/templates/__pycache__/formatters.cpython-313.pyc +0 -0
  37. package/dist/templates/cc-native/.claude/agents/cc-native/ARCHITECT-REVIEWER.md +20 -47
  38. package/dist/templates/cc-native/.claude/agents/cc-native/ASSUMPTION-CHAIN-TRACER.md +25 -203
  39. package/dist/templates/cc-native/.claude/agents/cc-native/CLARITY-AUDITOR.md +24 -75
  40. package/dist/templates/cc-native/.claude/agents/cc-native/COMPLETENESS-CHECKER.md +31 -76
  41. package/dist/templates/cc-native/.claude/agents/cc-native/DEVILS-ADVOCATE.md +25 -188
  42. package/dist/templates/cc-native/.claude/agents/cc-native/DOCUMENTATION-REVIEWER.md +30 -52
  43. package/dist/templates/cc-native/.claude/agents/cc-native/FEASIBILITY-ANALYST.md +26 -62
  44. package/dist/templates/cc-native/.claude/agents/cc-native/FRESH-PERSPECTIVE.md +31 -80
  45. package/dist/templates/cc-native/.claude/agents/cc-native/HANDOFF-READINESS.md +24 -105
  46. package/dist/templates/cc-native/.claude/agents/cc-native/HIDDEN-COMPLEXITY-DETECTOR.md +23 -208
  47. package/dist/templates/cc-native/.claude/agents/cc-native/INCENTIVE-MAPPER.md +25 -199
  48. package/dist/templates/cc-native/.claude/agents/cc-native/PRECEDENT-FINDER.md +35 -205
  49. package/dist/templates/cc-native/.claude/agents/cc-native/REVERSIBILITY-ANALYST.md +26 -176
  50. package/dist/templates/cc-native/.claude/agents/cc-native/RISK-ASSESSOR.md +22 -65
  51. package/dist/templates/cc-native/.claude/agents/cc-native/SECOND-ORDER-ANALYST.md +25 -161
  52. package/dist/templates/cc-native/.claude/agents/cc-native/SIMPLICITY-GUARDIAN.md +28 -58
  53. package/dist/templates/cc-native/.claude/agents/cc-native/SKEPTIC.md +27 -311
  54. package/dist/templates/cc-native/.claude/agents/cc-native/STAKEHOLDER-ADVOCATE.md +22 -73
  55. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/add_plan_context.cpython-313.pyc +0 -0
  56. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
  57. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/suggest-fresh-perspective.cpython-313.pyc +0 -0
  58. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +17 -3
  59. package/dist/templates/cc-native/_cc-native/lib/__pycache__/debug.cpython-313.pyc +0 -0
  60. package/dist/templates/cc-native/_cc-native/lib/debug.py +124 -0
  61. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
  62. package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +33 -1
  63. package/dist/templates/cc-native/_cc-native/plan-review.config.json +1 -1
  64. package/oclif.manifest.json +1 -1
  65. package/package.json +1 -1
@@ -0,0 +1,169 @@
1
+ """Common utilities for hook scripts.
2
+
3
+ Provides standardized boilerplate for:
4
+ - Path setup for imports
5
+ - JSON parsing from stdin
6
+ - Hook payload validation
7
+ - Error handling decorators
8
+ """
9
+
10
+ import json
11
+ import sys
12
+ from functools import wraps
13
+ from pathlib import Path
14
+ from typing import Any, Callable, Dict, Optional, TypeVar
15
+
16
+ from .utils import eprint
17
+
18
+ # Type variable for generic decorators
19
+ F = TypeVar('F', bound=Callable[..., Any])
20
+
21
+
22
+ def setup_hook_paths() -> Path:
23
+ """
24
+ Setup import paths for hooks.
25
+
26
+ Call this at module level in hook scripts to ensure
27
+ the shared lib directory is in sys.path.
28
+
29
+ Returns:
30
+ Path to the lib directory
31
+
32
+ Example:
33
+ SCRIPT_DIR = Path(__file__).resolve().parent
34
+ SHARED_LIB = SCRIPT_DIR.parent / "lib"
35
+ sys.path.insert(0, str(SHARED_LIB.parent))
36
+ """
37
+ # This function exists mainly for documentation
38
+ # Actual path setup must happen at module level before imports
39
+ hook_dir = Path(__file__).resolve().parent.parent.parent / "hooks"
40
+ lib_dir = hook_dir.parent / "lib"
41
+ if str(lib_dir.parent) not in sys.path:
42
+ sys.path.insert(0, str(lib_dir.parent))
43
+ return lib_dir
44
+
45
+
46
+ def load_hook_input() -> Optional[Dict[str, Any]]:
47
+ """
48
+ Load and parse JSON from stdin.
49
+
50
+ Returns:
51
+ Parsed JSON dict, or None if stdin is empty or invalid JSON
52
+ """
53
+ try:
54
+ input_data = sys.stdin.read().strip()
55
+ if not input_data:
56
+ return None
57
+ return json.loads(input_data)
58
+ except json.JSONDecodeError:
59
+ return None
60
+
61
+
62
+ def validate_hook_event(
63
+ payload: Dict[str, Any],
64
+ expected_event: str,
65
+ expected_tool: Optional[str] = None
66
+ ) -> bool:
67
+ """
68
+ Validate hook event type and optional tool name.
69
+
70
+ Args:
71
+ payload: Hook payload from stdin
72
+ expected_event: Expected hook_event_name (e.g., "PostToolUse", "PreToolUse")
73
+ expected_tool: Optional expected tool_name (e.g., "TaskCreate")
74
+
75
+ Returns:
76
+ True if payload matches expected event/tool, False otherwise
77
+ """
78
+ if payload.get("hook_event_name") != expected_event:
79
+ return False
80
+ if expected_tool and payload.get("tool_name") != expected_tool:
81
+ return False
82
+ return True
83
+
84
+
85
+ def get_tool_input(payload: Dict[str, Any]) -> Optional[Dict[str, Any]]:
86
+ """
87
+ Extract and validate tool_input from payload.
88
+
89
+ Args:
90
+ payload: Hook payload from stdin
91
+
92
+ Returns:
93
+ tool_input dict, or None if missing/invalid
94
+ """
95
+ tool_input = payload.get("tool_input", {})
96
+ return tool_input if isinstance(tool_input, dict) else None
97
+
98
+
99
+ def check_skip_persistence(payload: Dict[str, Any], hook_name: str = "hook") -> bool:
100
+ """
101
+ Check if persistence should be skipped based on metadata flags.
102
+
103
+ Args:
104
+ payload: Hook payload from stdin
105
+ hook_name: Name of hook for logging
106
+
107
+ Returns:
108
+ True if skip_persistence flag is set, False otherwise
109
+ """
110
+ tool_input = get_tool_input(payload)
111
+ if not tool_input:
112
+ return False
113
+
114
+ metadata = tool_input.get("metadata", {})
115
+ if isinstance(metadata, dict) and metadata.get("skip_persistence"):
116
+ eprint(f"[{hook_name}] Skipping persistence (skip_persistence flag set)")
117
+ return True
118
+ return False
119
+
120
+
121
+ def safe_hook_main(hook_name: str) -> Callable[[F], F]:
122
+ """
123
+ Decorator for hook main functions with standard error handling.
124
+
125
+ Catches exceptions, logs them to stderr, and returns 0 (non-blocking).
126
+
127
+ Args:
128
+ hook_name: Name of hook for error messages
129
+
130
+ Returns:
131
+ Decorator function
132
+
133
+ Example:
134
+ @safe_hook_main("my_hook")
135
+ def main() -> int:
136
+ # ... hook logic ...
137
+ return 0
138
+ """
139
+ def decorator(func: F) -> F:
140
+ @wraps(func)
141
+ def wrapper(*args, **kwargs):
142
+ try:
143
+ return func(*args, **kwargs)
144
+ except json.JSONDecodeError as e:
145
+ eprint(f"[{hook_name}] JSON decode error: {e}")
146
+ return 0
147
+ except Exception as e:
148
+ eprint(f"[{hook_name}] Unexpected error: {e}")
149
+ import traceback
150
+ eprint(traceback.format_exc())
151
+ return 0
152
+ return wrapper # type: ignore
153
+ return decorator
154
+
155
+
156
+ def run_hook(main_func: Callable[[], int]) -> None:
157
+ """
158
+ Standard hook entry point wrapper.
159
+
160
+ Calls main function and exits with its return code.
161
+
162
+ Args:
163
+ main_func: Hook main function that returns exit code
164
+
165
+ Example:
166
+ if __name__ == "__main__":
167
+ run_hook(main)
168
+ """
169
+ raise SystemExit(main_func())
@@ -37,6 +37,7 @@ from .discovery import (
37
37
  format_implementation_continuation,
38
38
  format_context_picker_prompt,
39
39
  format_ready_for_new_work,
40
+ format_relative_time,
40
41
  )
41
42
  from .task_sync import (
42
43
  generate_task_summary,
@@ -54,6 +55,10 @@ from .plan_archive import (
54
55
  mark_plan_implementation_started,
55
56
  mark_plan_completed,
56
57
  )
58
+ from .context_extractor import (
59
+ extract_context_id,
60
+ extract_context_id_for_session,
61
+ )
57
62
 
58
63
  __all__ = [
59
64
  # Data Classes
@@ -92,6 +97,7 @@ __all__ = [
92
97
  "format_implementation_continuation",
93
98
  "format_context_picker_prompt",
94
99
  "format_ready_for_new_work",
100
+ "format_relative_time",
95
101
  # Task Sync
96
102
  "generate_task_summary",
97
103
  "record_session_start",
@@ -106,4 +112,7 @@ __all__ = [
106
112
  "create_context_from_plan",
107
113
  "mark_plan_implementation_started",
108
114
  "mark_plan_completed",
115
+ # Context Extractor
116
+ "extract_context_id",
117
+ "extract_context_id_for_session",
109
118
  ]
@@ -0,0 +1,115 @@
1
+ """Context ID extraction from hook payloads.
2
+
3
+ Centralizes the logic for determining which context a hook operation
4
+ belongs to, using multiple fallback strategies.
5
+ """
6
+
7
+ from pathlib import Path
8
+ from typing import Any, Dict, Optional
9
+
10
+ from .context_manager import get_context_by_session_id, get_all_contexts
11
+ from ..base.utils import eprint
12
+
13
+
14
+ def extract_context_id(
15
+ tool_input: Dict[str, Any],
16
+ project_root: Path,
17
+ session_id: Optional[str] = None,
18
+ hook_name: str = "hook",
19
+ check_persistent_id: bool = False
20
+ ) -> Optional[str]:
21
+ """
22
+ Extract context ID from tool input with multiple fallback strategies.
23
+
24
+ Order of precedence:
25
+ 1. metadata.context field (explicit context specification)
26
+ 2. Session ID lookup (session bound to context)
27
+ 3. persistent_id parsing (if check_persistent_id=True, for TaskCreate)
28
+ 4. Single active context fallback
29
+
30
+ Args:
31
+ tool_input: Tool input dict from hook payload
32
+ project_root: Project root directory
33
+ session_id: Optional session ID from hook payload
34
+ hook_name: Name of calling hook for log messages
35
+ check_persistent_id: Whether to check persistent_id for context hint
36
+ (used by task_create_capture for ID format parsing)
37
+
38
+ Returns:
39
+ Context ID string, or None if context cannot be determined
40
+ """
41
+ # 1. Check metadata.context field (explicit)
42
+ metadata = tool_input.get("metadata", {})
43
+ if isinstance(metadata, dict):
44
+ context = metadata.get("context")
45
+ if context:
46
+ return context
47
+
48
+ # 2. Check session ID (session may be bound to a context)
49
+ if session_id:
50
+ try:
51
+ session_context = get_context_by_session_id(session_id, project_root)
52
+ if session_context:
53
+ eprint(f"[{hook_name}] Found context via session_id: {session_context.id}")
54
+ return session_context.id
55
+ except Exception as e:
56
+ eprint(f"[{hook_name}] Failed to lookup context by session: {e}")
57
+
58
+ # 3. Check persistent_id for context hint (task_create only)
59
+ # Format: "context-id-task-N" or similar
60
+ if check_persistent_id and isinstance(metadata, dict):
61
+ persistent_id = metadata.get("persistent_id", "")
62
+ if persistent_id and "-" in persistent_id:
63
+ parts = persistent_id.split("-")
64
+ if len(parts) >= 2:
65
+ # Reconstruct context ID (everything before last two parts)
66
+ context_parts = parts[:-2] if len(parts) > 2 else parts[:1]
67
+ potential_id = "-".join(context_parts)
68
+ if potential_id:
69
+ return potential_id
70
+
71
+ # 4. Check for single active context (fallback)
72
+ try:
73
+ contexts = get_all_contexts(status="active", project_root=project_root)
74
+ if len(contexts) == 1:
75
+ return contexts[0].id
76
+ except Exception as e:
77
+ eprint(f"[{hook_name}] Failed to get active contexts: {e}")
78
+
79
+ return None
80
+
81
+
82
+ def extract_context_id_for_session(
83
+ session_id: str,
84
+ project_root: Path,
85
+ hook_name: str = "hook"
86
+ ) -> Optional[str]:
87
+ """
88
+ Find context that matches this session_id.
89
+
90
+ Simpler variant for hooks that only need session-based lookup.
91
+
92
+ Args:
93
+ session_id: Session ID to match
94
+ project_root: Project root directory
95
+ hook_name: Name of calling hook for log messages
96
+
97
+ Returns:
98
+ Context ID or None if not found
99
+ """
100
+ contexts = get_all_contexts(status="active", project_root=project_root)
101
+
102
+ # Primary strategy: Find context with matching session_id
103
+ for ctx in contexts:
104
+ if ctx.in_flight and ctx.in_flight.session_ids and session_id in ctx.in_flight.session_ids:
105
+ eprint(f"[{hook_name}] Found context by session: {ctx.id}")
106
+ return ctx.id
107
+
108
+ # Fallback: If only one context is planning, assume it's the one
109
+ planning_contexts = [c for c in contexts if c.in_flight and c.in_flight.mode == "planning"]
110
+ if len(planning_contexts) == 1:
111
+ eprint(f"[{hook_name}] Fallback: Single planning context: {planning_contexts[0].id}")
112
+ return planning_contexts[0].id
113
+
114
+ eprint(f"[{hook_name}] Could not find context for session {session_id}")
115
+ return None
@@ -105,7 +105,7 @@ def format_context_list(contexts: List[Context]) -> str:
105
105
 
106
106
  for i, ctx in enumerate(contexts, 1):
107
107
  # Format last active time
108
- time_str = _format_relative_time(ctx.last_active)
108
+ time_str = format_relative_time(ctx.last_active)
109
109
 
110
110
  # Build status indicator
111
111
  status_indicator = ""
@@ -314,7 +314,7 @@ def format_context_selection_required(contexts: List[Context]) -> str:
314
314
  ]
315
315
 
316
316
  for i, ctx in enumerate(contexts, 1):
317
- time_str = _format_relative_time(ctx.last_active)
317
+ time_str = format_relative_time(ctx.last_active)
318
318
 
319
319
  # Add status indicator for in-flight work
320
320
  status = ""
@@ -345,7 +345,7 @@ def format_active_context_reminder(context: Context) -> str:
345
345
  Returns:
346
346
  Formatted system reminder
347
347
  """
348
- time_str = _format_relative_time(context.last_active)
348
+ time_str = format_relative_time(context.last_active)
349
349
 
350
350
  # Build mode display
351
351
  mode_display = "Active"
@@ -392,7 +392,7 @@ def format_context_created(context: Context) -> str:
392
392
  return "\n".join(lines)
393
393
 
394
394
 
395
- def _format_relative_time(iso_timestamp: Optional[str]) -> str:
395
+ def format_relative_time(iso_timestamp: Optional[str]) -> str:
396
396
  """
397
397
  Format ISO timestamp as relative time string.
398
398
 
@@ -8,14 +8,13 @@ categories:
8
8
  - code
9
9
  - infrastructure
10
10
  - design
11
- tools: Read, Write, Edit, Bash, Glob, Grep
12
11
  ---
13
12
 
14
- ## Role
13
+ # Architect Reviewer - Plan Review Agent
15
14
 
16
- Senior architecture reviewer with expertise in evaluating system designs, architectural decisions, and technology choices. Focus on design patterns, scalability assessment, integration strategies, and technical debt analysis with emphasis on building sustainable, evolvable systems.
15
+ Senior architecture reviewer evaluating system designs, architectural decisions, and technology choices.
17
16
 
18
- ## Review Focus
17
+ ## Your Expertise
19
18
 
20
19
  ### 1. Design Patterns & Structure
21
20
  Component boundaries, service contracts, dependency management, coupling/cohesion balance, appropriate pattern selection (microservices, event-driven, layered), and domain-driven design alignment.
@@ -26,50 +25,24 @@ Horizontal/vertical scaling readiness, data partitioning strategy, caching layer
26
25
  ### 3. Technical Debt & Evolution
27
26
  Architecture smells, technology obsolescence risks, complexity metrics, maintenance burden assessment, modernization path clarity, and reversibility of decisions.
28
27
 
29
- ## Output Format
28
+ ## CRITICAL: Single-Turn Review
30
29
 
31
- **Example 1: Design Pattern Issue**
32
- ```
33
- HIGH: Tight coupling between OrderService and PaymentService
34
- - Location: services/order.ts imports payment internals directly
35
- - Issue: Changes to PaymentService internal implementation will break OrderService
36
- - Fix: Define PaymentGateway interface in shared contracts, inject implementation
37
- ```
30
+ When reviewing a plan, you MUST:
31
+ 1. Analyze the plan content provided directly (do NOT use Read, Write, Edit, Bash, Glob, Grep, or any tools)
32
+ 2. Call StructuredOutput IMMEDIATELY with your assessment
33
+ 3. Complete your entire review in ONE response
38
34
 
39
- **Example 2: Scalability Concern**
40
- ```
41
- MEDIUM: Single-threaded processing bottleneck in data pipeline
42
- - Location: workers/etl-processor.ts
43
- - Issue: Sequential processing limits throughput to ~100 records/sec
44
- - Fix: Implement worker pool pattern or use message queue for parallel processing
45
- ```
35
+ Do NOT:
36
+ - Query context managers or external systems
37
+ - Read files from the codebase
38
+ - Request architecture documentation
39
+ - Ask follow-up questions
46
40
 
47
- ## Process
41
+ ## Required Output
48
42
 
49
- 1. Review architectural documentation and codebase structure
50
- 2. Evaluate design decisions against stated requirements and constraints
51
- 3. Assess scalability headroom and evolution flexibility
52
- 4. Provide strategic recommendations with trade-off analysis
53
-
54
- ## Communication Protocol
55
-
56
- Request architecture context when starting:
57
- ```json
58
- {
59
- "requesting_agent": "architect-reviewer",
60
- "request_type": "get_architecture_context",
61
- "payload": {
62
- "query": "Architecture context needed: system purpose, scale requirements, constraints, and evolution plans."
63
- }
64
- }
65
- ```
66
-
67
- ## Review Completion
68
-
69
- Report findings structured by impact (architectural → systemic → local) with:
70
- - Component/service references
71
- - Clear problem description with trade-off analysis
72
- - Recommended approach with alternatives considered
73
- - Migration path if changes required
74
-
75
- Prioritize long-term sustainability, scalability, and maintainability while providing pragmatic recommendations that balance ideal architecture with practical constraints.
43
+ Call StructuredOutput with exactly these fields:
44
+ - **verdict**: "pass" (architecturally sound), "warn" (some concerns), or "fail" (critical architectural issues)
45
+ - **summary**: 2-3 sentences explaining your architectural assessment (minimum 20 characters)
46
+ - **issues**: Array of architectural concerns, each with: severity (high/medium/low), category (e.g., "coupling", "scalability", "tech-debt"), issue description, suggested_fix
47
+ - **missing_sections**: Architectural considerations the plan should address but doesn't
48
+ - **questions**: Design decisions that need clarification before implementation