aiwcli 0.10.3 → 0.11.0

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 (189) hide show
  1. package/bin/run.js +1 -1
  2. package/dist/commands/clear.js +28 -131
  3. package/dist/commands/init/index.js +3 -3
  4. package/dist/lib/gitignore-manager.d.ts +32 -0
  5. package/dist/lib/gitignore-manager.js +141 -2
  6. package/dist/templates/CLAUDE.md +8 -8
  7. package/dist/templates/_shared/.claude/commands/handoff-resume.md +64 -0
  8. package/dist/templates/_shared/.claude/commands/handoff.md +16 -10
  9. package/dist/templates/_shared/.claude/settings.json +7 -7
  10. package/dist/templates/_shared/hooks-ts/_utils/git-state.ts +2 -0
  11. package/dist/templates/_shared/hooks-ts/archive_plan.ts +159 -0
  12. package/dist/templates/_shared/hooks-ts/context_monitor.ts +147 -0
  13. package/dist/templates/_shared/hooks-ts/file-suggestion.ts +130 -0
  14. package/dist/templates/_shared/hooks-ts/pre_compact.ts +49 -0
  15. package/dist/templates/_shared/hooks-ts/session_end.ts +104 -0
  16. package/dist/templates/_shared/hooks-ts/session_start.ts +144 -0
  17. package/dist/templates/_shared/hooks-ts/task_create_capture.ts +48 -0
  18. package/dist/templates/_shared/hooks-ts/task_update_capture.ts +74 -0
  19. package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +83 -0
  20. package/dist/templates/_shared/lib-ts/CLAUDE.md +318 -0
  21. package/dist/templates/_shared/lib-ts/base/atomic-write.ts +12 -12
  22. package/dist/templates/_shared/lib-ts/base/constants.ts +22 -15
  23. package/dist/templates/_shared/lib-ts/base/hook-utils.ts +129 -50
  24. package/dist/templates/_shared/lib-ts/base/inference.ts +28 -21
  25. package/dist/templates/_shared/lib-ts/base/logger.ts +31 -15
  26. package/dist/templates/_shared/lib-ts/base/state-io.ts +9 -7
  27. package/dist/templates/_shared/lib-ts/base/stop-words.ts +131 -131
  28. package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +139 -0
  29. package/dist/templates/_shared/lib-ts/base/utils.ts +69 -69
  30. package/dist/templates/_shared/lib-ts/context/context-formatter.ts +30 -24
  31. package/dist/templates/_shared/lib-ts/context/context-selector.ts +50 -32
  32. package/dist/templates/_shared/lib-ts/context/context-store.ts +76 -48
  33. package/dist/templates/_shared/lib-ts/context/plan-manager.ts +61 -37
  34. package/dist/templates/_shared/lib-ts/context/task-tracker.ts +10 -6
  35. package/dist/templates/_shared/lib-ts/handoff/document-generator.ts +11 -10
  36. package/dist/templates/_shared/lib-ts/handoff/handoff-reader.ts +159 -0
  37. package/dist/templates/_shared/lib-ts/templates/formatters.ts +6 -4
  38. package/dist/templates/_shared/lib-ts/types.ts +68 -55
  39. package/dist/templates/_shared/scripts/resolve_context.ts +24 -0
  40. package/dist/templates/_shared/scripts/resume_handoff.ts +321 -0
  41. package/dist/templates/_shared/scripts/save_handoff.ts +21 -21
  42. package/dist/templates/_shared/scripts/status_line.ts +733 -0
  43. package/dist/templates/cc-native/.claude/settings.json +175 -185
  44. package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +15 -17
  45. package/dist/templates/cc-native/_cc-native/agents/CLAUDE.md +0 -2
  46. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +109 -135
  47. package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.ts +119 -0
  48. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +921 -0
  49. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +61 -0
  50. package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +157 -0
  51. package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +709 -0
  52. package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +199 -0
  53. package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +124 -0
  54. package/dist/templates/cc-native/_cc-native/lib-ts/config.ts +57 -0
  55. package/dist/templates/cc-native/_cc-native/lib-ts/constants.ts +83 -0
  56. package/dist/templates/cc-native/_cc-native/lib-ts/debug.ts +80 -0
  57. package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +119 -0
  58. package/dist/templates/cc-native/_cc-native/lib-ts/json-parser.ts +162 -0
  59. package/dist/templates/cc-native/_cc-native/lib-ts/nul +3 -0
  60. package/dist/templates/cc-native/_cc-native/lib-ts/orchestrator.ts +249 -0
  61. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/agent.ts +155 -0
  62. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/codex.ts +130 -0
  63. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/gemini.ts +106 -0
  64. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/index.ts +10 -0
  65. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/types.ts +23 -0
  66. package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +243 -0
  67. package/dist/templates/cc-native/_cc-native/lib-ts/tsconfig.json +18 -0
  68. package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +310 -0
  69. package/dist/templates/cc-native/_cc-native/lib-ts/verdict.ts +72 -0
  70. package/dist/templates/cc-native/_cc-native/plan-review.config.json +1 -9
  71. package/oclif.manifest.json +1 -1
  72. package/package.json +1 -1
  73. package/dist/templates/_shared/hooks/__init__.py +0 -16
  74. package/dist/templates/_shared/hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  75. package/dist/templates/_shared/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
  76. package/dist/templates/_shared/hooks/__pycache__/context_enforcer.cpython-313.pyc +0 -0
  77. package/dist/templates/_shared/hooks/__pycache__/context_monitor.cpython-313.pyc +0 -0
  78. package/dist/templates/_shared/hooks/__pycache__/file-suggestion.cpython-313.pyc +0 -0
  79. package/dist/templates/_shared/hooks/__pycache__/pre_compact.cpython-313.pyc +0 -0
  80. package/dist/templates/_shared/hooks/__pycache__/session_end.cpython-313.pyc +0 -0
  81. package/dist/templates/_shared/hooks/__pycache__/session_start.cpython-313.pyc +0 -0
  82. package/dist/templates/_shared/hooks/__pycache__/task_create_atomicity.cpython-313.pyc +0 -0
  83. package/dist/templates/_shared/hooks/__pycache__/task_create_capture.cpython-313.pyc +0 -0
  84. package/dist/templates/_shared/hooks/__pycache__/task_update_capture.cpython-313.pyc +0 -0
  85. package/dist/templates/_shared/hooks/__pycache__/user_prompt_submit.cpython-313.pyc +0 -0
  86. package/dist/templates/_shared/hooks/archive_plan.py +0 -177
  87. package/dist/templates/_shared/hooks/context_monitor.py +0 -270
  88. package/dist/templates/_shared/hooks/file-suggestion.py +0 -215
  89. package/dist/templates/_shared/hooks/pre_compact.py +0 -104
  90. package/dist/templates/_shared/hooks/session_end.py +0 -173
  91. package/dist/templates/_shared/hooks/session_start.py +0 -206
  92. package/dist/templates/_shared/hooks/task_create_capture.py +0 -108
  93. package/dist/templates/_shared/hooks/task_update_capture.py +0 -145
  94. package/dist/templates/_shared/hooks/user_prompt_submit.py +0 -139
  95. package/dist/templates/_shared/lib/__init__.py +0 -1
  96. package/dist/templates/_shared/lib/__pycache__/__init__.cpython-313.pyc +0 -0
  97. package/dist/templates/_shared/lib/base/__init__.py +0 -65
  98. package/dist/templates/_shared/lib/base/__pycache__/__init__.cpython-313.pyc +0 -0
  99. package/dist/templates/_shared/lib/base/__pycache__/atomic_write.cpython-313.pyc +0 -0
  100. package/dist/templates/_shared/lib/base/__pycache__/constants.cpython-313.pyc +0 -0
  101. package/dist/templates/_shared/lib/base/__pycache__/hook_utils.cpython-313.pyc +0 -0
  102. package/dist/templates/_shared/lib/base/__pycache__/inference.cpython-313.pyc +0 -0
  103. package/dist/templates/_shared/lib/base/__pycache__/logger.cpython-313.pyc +0 -0
  104. package/dist/templates/_shared/lib/base/__pycache__/stop_words.cpython-313.pyc +0 -0
  105. package/dist/templates/_shared/lib/base/__pycache__/subprocess_utils.cpython-313.pyc +0 -0
  106. package/dist/templates/_shared/lib/base/__pycache__/utils.cpython-313.pyc +0 -0
  107. package/dist/templates/_shared/lib/base/atomic_write.py +0 -180
  108. package/dist/templates/_shared/lib/base/constants.py +0 -358
  109. package/dist/templates/_shared/lib/base/hook_utils.py +0 -339
  110. package/dist/templates/_shared/lib/base/inference.py +0 -307
  111. package/dist/templates/_shared/lib/base/logger.py +0 -305
  112. package/dist/templates/_shared/lib/base/stop_words.py +0 -221
  113. package/dist/templates/_shared/lib/base/subprocess_utils.py +0 -46
  114. package/dist/templates/_shared/lib/base/utils.py +0 -263
  115. package/dist/templates/_shared/lib/context/__init__.py +0 -102
  116. package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
  117. package/dist/templates/_shared/lib/context/__pycache__/cache.cpython-313.pyc +0 -0
  118. package/dist/templates/_shared/lib/context/__pycache__/context_extractor.cpython-313.pyc +0 -0
  119. package/dist/templates/_shared/lib/context/__pycache__/context_formatter.cpython-313.pyc +0 -0
  120. package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
  121. package/dist/templates/_shared/lib/context/__pycache__/context_selector.cpython-313.pyc +0 -0
  122. package/dist/templates/_shared/lib/context/__pycache__/context_store.cpython-313.pyc +0 -0
  123. package/dist/templates/_shared/lib/context/__pycache__/discovery.cpython-313.pyc +0 -0
  124. package/dist/templates/_shared/lib/context/__pycache__/event_log.cpython-313.pyc +0 -0
  125. package/dist/templates/_shared/lib/context/__pycache__/plan_archive.cpython-313.pyc +0 -0
  126. package/dist/templates/_shared/lib/context/__pycache__/plan_manager.cpython-313.pyc +0 -0
  127. package/dist/templates/_shared/lib/context/__pycache__/task_sync.cpython-313.pyc +0 -0
  128. package/dist/templates/_shared/lib/context/__pycache__/task_tracker.cpython-313.pyc +0 -0
  129. package/dist/templates/_shared/lib/context/context_formatter.py +0 -317
  130. package/dist/templates/_shared/lib/context/context_selector.py +0 -508
  131. package/dist/templates/_shared/lib/context/context_store.py +0 -653
  132. package/dist/templates/_shared/lib/context/plan_manager.py +0 -303
  133. package/dist/templates/_shared/lib/context/task_tracker.py +0 -188
  134. package/dist/templates/_shared/lib/handoff/__init__.py +0 -22
  135. package/dist/templates/_shared/lib/handoff/__pycache__/__init__.cpython-313.pyc +0 -0
  136. package/dist/templates/_shared/lib/handoff/__pycache__/document_generator.cpython-313.pyc +0 -0
  137. package/dist/templates/_shared/lib/handoff/document_generator.py +0 -278
  138. package/dist/templates/_shared/lib/templates/README.md +0 -206
  139. package/dist/templates/_shared/lib/templates/__init__.py +0 -36
  140. package/dist/templates/_shared/lib/templates/__pycache__/__init__.cpython-313.pyc +0 -0
  141. package/dist/templates/_shared/lib/templates/__pycache__/formatters.cpython-313.pyc +0 -0
  142. package/dist/templates/_shared/lib/templates/__pycache__/persona_questions.cpython-313.pyc +0 -0
  143. package/dist/templates/_shared/lib/templates/__pycache__/plan_context.cpython-313.pyc +0 -0
  144. package/dist/templates/_shared/lib/templates/formatters.py +0 -146
  145. package/dist/templates/_shared/lib/templates/plan_context.py +0 -73
  146. package/dist/templates/_shared/scripts/__pycache__/save_handoff.cpython-313.pyc +0 -0
  147. package/dist/templates/_shared/scripts/__pycache__/status_line.cpython-313.pyc +0 -0
  148. package/dist/templates/_shared/scripts/save_handoff.py +0 -357
  149. package/dist/templates/_shared/scripts/status_line.py +0 -716
  150. package/dist/templates/cc-native/.claude/commands/cc-native/fresh-perspective.md +0 -8
  151. package/dist/templates/cc-native/.windsurf/workflows/cc-native/fresh-perspective.md +0 -8
  152. package/dist/templates/cc-native/MIGRATION.md +0 -86
  153. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/add_plan_context.cpython-313.pyc +0 -0
  154. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
  155. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/mark_questions_asked.cpython-313.pyc +0 -0
  156. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_accepted.cpython-313.pyc +0 -0
  157. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_questions_early.cpython-313.pyc +0 -0
  158. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/suggest-fresh-perspective.cpython-313.pyc +0 -0
  159. package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.py +0 -130
  160. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +0 -954
  161. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.py +0 -81
  162. package/dist/templates/cc-native/_cc-native/hooks/suggest-fresh-perspective.py +0 -340
  163. package/dist/templates/cc-native/_cc-native/lib/CLAUDE.md +0 -265
  164. package/dist/templates/cc-native/_cc-native/lib/__init__.py +0 -53
  165. package/dist/templates/cc-native/_cc-native/lib/__pycache__/__init__.cpython-313.pyc +0 -0
  166. package/dist/templates/cc-native/_cc-native/lib/__pycache__/atomic_write.cpython-313.pyc +0 -0
  167. package/dist/templates/cc-native/_cc-native/lib/__pycache__/constants.cpython-313.pyc +0 -0
  168. package/dist/templates/cc-native/_cc-native/lib/__pycache__/debug.cpython-313.pyc +0 -0
  169. package/dist/templates/cc-native/_cc-native/lib/__pycache__/orchestrator.cpython-313.pyc +0 -0
  170. package/dist/templates/cc-native/_cc-native/lib/__pycache__/state.cpython-313.pyc +0 -0
  171. package/dist/templates/cc-native/_cc-native/lib/__pycache__/utils.cpython-313.pyc +0 -0
  172. package/dist/templates/cc-native/_cc-native/lib/constants.py +0 -45
  173. package/dist/templates/cc-native/_cc-native/lib/debug.py +0 -139
  174. package/dist/templates/cc-native/_cc-native/lib/orchestrator.py +0 -362
  175. package/dist/templates/cc-native/_cc-native/lib/reviewers/__init__.py +0 -28
  176. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/__init__.cpython-313.pyc +0 -0
  177. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
  178. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/base.cpython-313.pyc +0 -0
  179. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/codex.cpython-313.pyc +0 -0
  180. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/gemini.cpython-313.pyc +0 -0
  181. package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +0 -215
  182. package/dist/templates/cc-native/_cc-native/lib/reviewers/base.py +0 -88
  183. package/dist/templates/cc-native/_cc-native/lib/reviewers/codex.py +0 -124
  184. package/dist/templates/cc-native/_cc-native/lib/reviewers/gemini.py +0 -108
  185. package/dist/templates/cc-native/_cc-native/lib/state.py +0 -268
  186. package/dist/templates/cc-native/_cc-native/lib/utils.py +0 -1071
  187. package/dist/templates/cc-native/_cc-native/scripts/__pycache__/aggregate_agents.cpython-313.pyc +0 -0
  188. package/dist/templates/cc-native/_cc-native/scripts/aggregate_agents.py +0 -168
  189. package/dist/templates/cc-native/_cc-native/workflows/fresh-perspective.md +0 -134
@@ -1,215 +0,0 @@
1
- """
2
- CC-Native Agent Reviewer Module.
3
-
4
- Runs Claude Code agents to review plans.
5
- """
6
-
7
- import json
8
- import shutil
9
- import subprocess
10
- import sys
11
- from pathlib import Path
12
- from typing import Any, Dict, Optional
13
-
14
- # Import from parent lib
15
- _lib_dir = Path(__file__).resolve().parent.parent
16
- sys.path.insert(0, str(_lib_dir))
17
-
18
- from utils import ReviewerResult, parse_json_maybe, coerce_to_review
19
- from debug import debug_log, debug_raw
20
- from .base import AgentConfig, AGENT_REVIEW_PROMPT_PREFIX
21
-
22
- # Import logger
23
- _shared_logger = Path(__file__).resolve().parent.parent.parent.parent / "_shared" / "lib"
24
- sys.path.insert(0, str(_shared_logger))
25
- from base.logger import log_debug, log_info, log_warn, log_error
26
-
27
- # Import shared subprocess utilities
28
- _shared_lib = Path(__file__).resolve().parent.parent.parent.parent / "_shared" / "lib" / "base"
29
- sys.path.insert(0, str(_shared_lib))
30
- from subprocess_utils import get_internal_subprocess_env
31
-
32
-
33
- def _parse_claude_output(raw: str) -> Optional[Dict[str, Any]]:
34
- """Parse Claude CLI JSON output, handling various formats.
35
-
36
- Claude CLI can output in several formats:
37
- - Direct structured_output dict
38
- - Assistant message with StructuredOutput tool use
39
- - List of events with assistant messages
40
-
41
- Args:
42
- raw: Raw stdout from Claude CLI
43
-
44
- Returns:
45
- Parsed JSON dict or None if parsing failed
46
- """
47
- try:
48
- result = json.loads(raw)
49
- if isinstance(result, dict):
50
- if "structured_output" in result:
51
- log_debug("agent", "Found structured_output in root dict", component="parse")
52
- return result["structured_output"]
53
- if result.get("type") == "assistant":
54
- message = result.get("message", {})
55
- content = message.get("content", [])
56
- for item in content:
57
- if isinstance(item, dict) and item.get("name") == "StructuredOutput":
58
- log_debug("agent", "Found StructuredOutput in assistant message content", component="parse")
59
- return item.get("input", {})
60
- log_debug("agent", "Assistant message found but no StructuredOutput tool use in content", component="parse")
61
- elif isinstance(result, list):
62
- log_debug("agent", f"Received list of {len(result)} events, searching for assistant message", component="parse")
63
- for i, event in enumerate(result):
64
- if not isinstance(event, dict):
65
- continue
66
- if event.get("type") == "assistant":
67
- message = event.get("message", {})
68
- content = message.get("content", [])
69
- for item in content:
70
- if isinstance(item, dict) and item.get("name") == "StructuredOutput":
71
- log_debug("agent", f"Found StructuredOutput in event[{i}] assistant message", component="parse")
72
- return item.get("input", {})
73
- log_debug("agent", "No StructuredOutput found in any assistant message in event list", component="parse")
74
- except json.JSONDecodeError as e:
75
- log_warn("agent", f"JSON decode error: {e}", component="parse")
76
- except Exception as e:
77
- log_error("agent", f"Unexpected error during structured parsing: {e}", component="parse")
78
-
79
- # Fallback to heuristic extraction with required field validation
80
- log_debug("agent", "No structured output found, falling back to heuristic JSON extraction", component="parse")
81
- return parse_json_maybe(raw, require_fields=["verdict", "summary"])
82
-
83
-
84
- def run_agent_review(
85
- plan: str,
86
- agent: AgentConfig,
87
- schema: Dict[str, Any],
88
- timeout: int,
89
- context_path: Optional[Path] = None,
90
- session_name: str = "unknown",
91
- ) -> ReviewerResult:
92
- """Run a single Claude Code agent to review the plan.
93
-
94
- Args:
95
- plan: The plan content to review
96
- agent: Agent configuration (name, model, etc.)
97
- schema: JSON schema for the review output
98
- timeout: Timeout in seconds
99
- context_path: Optional path to context folder for debug logging
100
- session_name: Session name for debug logging
101
-
102
- Returns:
103
- ReviewerResult with the review output
104
- """
105
- claude_path = shutil.which("claude")
106
- if claude_path is None:
107
- log_warn(agent.name, "Claude CLI not found on PATH")
108
- return ReviewerResult(
109
- name=agent.name,
110
- ok=False,
111
- verdict="skip",
112
- data={},
113
- raw="",
114
- err="claude CLI not found on PATH",
115
- )
116
-
117
- log_debug(agent.name, f"Found Claude CLI at: {claude_path}")
118
-
119
- # User prompt - direct instruction to call StructuredOutput immediately
120
- prompt = f"""IMMEDIATELY call StructuredOutput with your review of the plan below.
121
- Do NOT output any text before calling StructuredOutput.
122
-
123
- PLAN:
124
- <<<
125
- {plan}
126
- >>>
127
- """
128
-
129
- schema_json = json.dumps(schema, ensure_ascii=False)
130
-
131
- # Build command args - use --system-prompt with the markdown body as persona
132
- cmd_args = [
133
- claude_path,
134
- "-p", # Enable print mode to read prompt from stdin
135
- "--model", agent.model,
136
- "--output-format", "json",
137
- "--json-schema", schema_json,
138
- "--max-turns", "3", # Allow buffer for tool call + result (usually completes in 2)
139
- "--setting-sources", "", # Disable user/project settings to avoid PAI context interference
140
- ]
141
-
142
- # Add system prompt: prefix with single-turn instructions, then agent's persona
143
- if agent.system_prompt:
144
- full_prompt = AGENT_REVIEW_PROMPT_PREFIX + "\n\n---\n\n" + agent.system_prompt
145
- cmd_args.extend(["--system-prompt", full_prompt])
146
-
147
- log_info(agent.name, f"Running with model: {agent.model}, timeout: {timeout}s")
148
-
149
- # Get environment for internal subprocess (bypasses hooks)
150
- env = get_internal_subprocess_env()
151
-
152
- try:
153
- p = subprocess.run(
154
- cmd_args,
155
- input=prompt,
156
- text=True,
157
- capture_output=True,
158
- timeout=timeout,
159
- encoding="utf-8",
160
- errors="replace",
161
- env=env,
162
- )
163
- except subprocess.TimeoutExpired:
164
- log_warn(agent.name, f"TIMEOUT after {timeout}s")
165
- return ReviewerResult(agent.name, False, "error", {}, "", f"{agent.name} timed out after {timeout}s")
166
- except Exception as ex:
167
- log_error(agent.name, f"Exception: {ex}")
168
- return ReviewerResult(agent.name, False, "error", {}, "", f"{agent.name} failed to run: {ex}")
169
-
170
- log_debug(agent.name, f"Exit code: {p.returncode}")
171
- log_debug(agent.name, f"stdout length: {len(p.stdout or '')} chars")
172
- if p.stderr:
173
- log_debug(agent.name, f"stderr: {p.stderr[:500]}")
174
-
175
- raw = (p.stdout or "").strip()
176
- err = (p.stderr or "").strip()
177
-
178
- # Debug logging - capture full raw output for diagnosis
179
- if context_path:
180
- debug_raw(context_path, session_name, f"agent:{agent.name}", "stdout", raw)
181
- if err:
182
- debug_raw(context_path, session_name, f"agent:{agent.name}", "stderr", err)
183
- debug_log(context_path, session_name, f"agent:{agent.name}", "subprocess_info", {
184
- "exit_code": p.returncode,
185
- "stdout_len": len(raw),
186
- "stderr_len": len(err),
187
- "model": agent.model,
188
- "timeout": timeout,
189
- })
190
-
191
- if raw:
192
- log_debug(agent.name, f"stdout preview: {raw[:500]}")
193
-
194
- obj = _parse_claude_output(raw)
195
-
196
- # Debug logging - capture parsed result details
197
- if context_path:
198
- debug_log(context_path, session_name, f"agent:{agent.name}", "parsed_result", {
199
- "parsed_keys": list(obj.keys()) if obj else None,
200
- "verdict": obj.get("verdict") if obj else None,
201
- "has_summary": bool(obj.get("summary")) if obj else False,
202
- "summary_preview": (obj.get("summary", "")[:200] + "...") if obj and obj.get("summary") and len(obj.get("summary", "")) > 200 else (obj.get("summary") if obj else None),
203
- "issues_count": len(obj.get("issues", [])) if obj else 0,
204
- "missing_sections_count": len(obj.get("missing_sections", [])) if obj else 0,
205
- "questions_count": len(obj.get("questions", [])) if obj else 0,
206
- })
207
-
208
- if obj:
209
- log_info(agent.name, f"Parsed JSON successfully, verdict: {obj.get('verdict', 'N/A')}")
210
- else:
211
- log_warn(agent.name, "Failed to parse JSON from output")
212
-
213
- ok, verdict, norm = coerce_to_review(obj, "Retry or check agent configuration.")
214
-
215
- return ReviewerResult(agent.name, ok, verdict, norm, raw, err)
@@ -1,88 +0,0 @@
1
- """
2
- CC-Native Reviewers Base Module.
3
-
4
- Provides shared constants and types for plan reviewers.
5
- """
6
-
7
- import sys
8
- from dataclasses import dataclass, field
9
- from pathlib import Path
10
- from typing import Any, Dict, List
11
-
12
- # Import from parent lib
13
- _lib_dir = Path(__file__).resolve().parent.parent
14
- sys.path.insert(0, str(_lib_dir))
15
-
16
- from utils import ReviewerResult, REVIEW_SCHEMA
17
-
18
- # Re-export for convenience
19
- __all__ = [
20
- "ReviewerResult",
21
- "REVIEW_SCHEMA",
22
- "REVIEW_PROMPT_PREFIX",
23
- "AGENT_REVIEW_PROMPT_PREFIX",
24
- "AgentConfig",
25
- "OrchestratorConfig",
26
- ]
27
-
28
-
29
- # ---------------------------
30
- # Agent Configuration
31
- # ---------------------------
32
-
33
- @dataclass
34
- class AgentConfig:
35
- """Configuration for a Claude Code review agent."""
36
- name: str
37
- model: str = "sonnet"
38
- focus: str = ""
39
- enabled: bool = True
40
- categories: List[str] = field(default_factory=lambda: ["code"])
41
- description: str = ""
42
- system_prompt: str = "" # Markdown body content for --system-prompt
43
-
44
-
45
- @dataclass
46
- class OrchestratorConfig:
47
- """Configuration for the plan orchestrator."""
48
- enabled: bool = True
49
- model: str = "haiku"
50
- timeout: int = 30
51
-
52
-
53
- # ---------------------------
54
- # Shared Review Prompt Text
55
- # ---------------------------
56
-
57
- REVIEW_PROMPT_PREFIX = """You are a senior staff software engineer acting as a strict plan reviewer.
58
-
59
- Review the PLAN below. Focus on:
60
- - missing steps, unclear assumptions, edge cases
61
- - security/privacy concerns
62
- - testing/rollout/rollback completeness
63
- - operational concerns (observability, failure modes)
64
- """
65
-
66
- AGENT_REVIEW_PROMPT_PREFIX = """# SINGLE-TURN PLAN REVIEW
67
-
68
- ## CRITICAL: ONE TURN ONLY
69
- You have exactly ONE response to complete this review. Do NOT attempt multi-step workflows, context queries, or phased analysis. Analyze the plan and output your review immediately.
70
-
71
- ## YOUR TASK
72
- Review the plan below from your area of expertise. Then call StructuredOutput with your assessment.
73
-
74
- ## REQUIRED OUTPUT (all fields must have content)
75
- Call StructuredOutput with:
76
- - **verdict**: "pass" (no concerns), "warn" (some concerns), or "fail" (critical issues)
77
- - **summary**: 2-3 sentences with your overall assessment and key findings (REQUIRED)
78
- - **issues**: Array of concerns found. Format each as:
79
- {"severity": "high/medium/low", "category": "...", "issue": "...", "suggested_fix": "..."}
80
- - **missing_sections**: Topics the plan should address but doesn't
81
- - **questions**: Things that need clarification before implementation
82
-
83
- ## IMPORTANT RULES
84
- 1. A "warn" verdict MUST include at least one issue explaining why
85
- 2. Summary MUST explain your reasoning, not just "looks good" or empty
86
- 3. Focus on your expertise area (architecture, security, performance, etc.)
87
- 4. Output StructuredOutput NOW - no other tools, no questions, no delays
88
- """
@@ -1,124 +0,0 @@
1
- """
2
- CC-Native Codex Reviewer Module.
3
-
4
- Runs Codex CLI to review plans.
5
- """
6
-
7
- import json
8
- import shutil
9
- import subprocess
10
- import sys
11
- import tempfile
12
- from pathlib import Path
13
- from typing import Any, Dict
14
-
15
- # Import from parent lib
16
- _lib_dir = Path(__file__).resolve().parent.parent
17
- sys.path.insert(0, str(_lib_dir))
18
-
19
- from utils import ReviewerResult, parse_json_maybe, coerce_to_review
20
- from .base import REVIEW_PROMPT_PREFIX
21
-
22
- # Import logger
23
- _shared_logger = Path(__file__).resolve().parent.parent.parent.parent / "_shared" / "lib"
24
- sys.path.insert(0, str(_shared_logger))
25
- from base.logger import log_debug, log_info, log_warn, log_error
26
-
27
-
28
- def run_codex_review(
29
- plan: str,
30
- schema: Dict[str, Any],
31
- settings: Dict[str, Any],
32
- ) -> ReviewerResult:
33
- """Run Codex CLI to review the plan.
34
-
35
- Args:
36
- plan: The plan content to review
37
- schema: JSON schema for the review output
38
- settings: Codex reviewer settings (timeout, model)
39
-
40
- Returns:
41
- ReviewerResult with the review output
42
- """
43
- codex_settings = settings.get("reviewers", {}).get("codex", {})
44
- timeout = codex_settings.get("timeout", 120)
45
- model = codex_settings.get("model", "")
46
-
47
- codex_path = shutil.which("codex")
48
- if codex_path is None:
49
- log_warn("codex", "CLI not found on PATH")
50
- return ReviewerResult(
51
- name="codex",
52
- ok=False,
53
- verdict="skip",
54
- data={},
55
- raw="",
56
- err="codex CLI not found on PATH",
57
- )
58
-
59
- log_debug("codex", f"Found CLI at: {codex_path}")
60
-
61
- prompt = f"""{REVIEW_PROMPT_PREFIX}
62
- Return ONLY a JSON object that matches this JSON Schema:
63
- {json.dumps(schema, ensure_ascii=False)}
64
-
65
- PLAN:
66
- <<<
67
- {plan}
68
- >>>
69
- """
70
-
71
- with tempfile.TemporaryDirectory() as td:
72
- td_path = Path(td)
73
- schema_path = td_path / "schema.json"
74
- out_path = td_path / "codex_review.json"
75
-
76
- schema_path.write_text(json.dumps(schema, indent=2), encoding="utf-8")
77
-
78
- cmd = [
79
- codex_path,
80
- "exec",
81
- "--full-auto",
82
- "--sandbox",
83
- "read-only",
84
- "--output-schema",
85
- str(schema_path),
86
- "-o",
87
- str(out_path),
88
- "-",
89
- ]
90
-
91
- if model:
92
- cmd.insert(2, "--model")
93
- cmd.insert(3, model)
94
-
95
- log_debug("codex", f"Running command: {' '.join(cmd)}")
96
-
97
- try:
98
- p = subprocess.run(
99
- cmd,
100
- input=prompt,
101
- text=True,
102
- capture_output=True,
103
- timeout=timeout,
104
- encoding='utf-8',
105
- errors='replace',
106
- )
107
- except subprocess.TimeoutExpired:
108
- log_warn("codex", f"TIMEOUT after {timeout}s")
109
- return ReviewerResult("codex", False, "error", {}, "", f"codex timed out after {timeout}s")
110
- except Exception as ex:
111
- log_error("codex", f"Exception: {ex}")
112
- return ReviewerResult("codex", False, "error", {}, "", f"codex failed to run: {ex}")
113
-
114
- log_debug("codex", f"Exit code: {p.returncode}")
115
-
116
- raw = ""
117
- if out_path.exists():
118
- raw = out_path.read_text(encoding="utf-8", errors="replace")
119
-
120
- obj = parse_json_maybe(raw) or parse_json_maybe(p.stdout)
121
- ok, verdict, norm = coerce_to_review(obj, "Retry or check CLI auth/config.")
122
-
123
- err = (p.stderr or "").strip()
124
- return ReviewerResult("codex", ok, verdict, norm, raw or p.stdout, err)
@@ -1,108 +0,0 @@
1
- """
2
- CC-Native Gemini Reviewer Module.
3
-
4
- Runs Gemini CLI to review plans.
5
- """
6
-
7
- import json
8
- import shutil
9
- import subprocess
10
- import sys
11
- from pathlib import Path
12
- from typing import Any, Dict
13
-
14
- # Import from parent lib
15
- _lib_dir = Path(__file__).resolve().parent.parent
16
- sys.path.insert(0, str(_lib_dir))
17
-
18
- from utils import ReviewerResult, parse_json_maybe, coerce_to_review
19
-
20
- # Import logger
21
- _shared_logger = Path(__file__).resolve().parent.parent.parent.parent / "_shared" / "lib"
22
- sys.path.insert(0, str(_shared_logger))
23
- from base.logger import log_debug, log_info, log_warn, log_error
24
-
25
-
26
- def run_gemini_review(
27
- plan: str,
28
- schema: Dict[str, Any],
29
- settings: Dict[str, Any],
30
- ) -> ReviewerResult:
31
- """Run Gemini CLI to review the plan.
32
-
33
- Args:
34
- plan: The plan content to review
35
- schema: JSON schema for the review output
36
- settings: Gemini reviewer settings (timeout, model)
37
-
38
- Returns:
39
- ReviewerResult with the review output
40
- """
41
- gemini_settings = settings.get("reviewers", {}).get("gemini", {})
42
- timeout = gemini_settings.get("timeout", 120)
43
- model = gemini_settings.get("model", "")
44
-
45
- gemini_path = shutil.which("gemini")
46
- if gemini_path is None:
47
- log_warn("gemini", "CLI not found on PATH")
48
- return ReviewerResult(
49
- name="gemini",
50
- ok=False,
51
- verdict="skip",
52
- data={},
53
- raw="",
54
- err="gemini CLI not found on PATH",
55
- )
56
-
57
- log_debug("gemini", f"Found CLI at: {gemini_path}")
58
-
59
- instruction = f"""
60
-
61
- Review the PLAN above as a senior staff software engineer. Focus on:
62
- - missing steps, unclear assumptions, edge cases
63
- - security/privacy concerns
64
- - testing/rollout/rollback completeness
65
- - operational concerns (observability, failure modes)
66
-
67
- Return ONLY a JSON object that matches this JSON Schema (no markdown, no code fences):
68
- {json.dumps(schema, ensure_ascii=False)}
69
- """
70
-
71
- cmd = [
72
- gemini_path,
73
- "-y", # YOLO mode - auto-approve all actions
74
- "-p",
75
- instruction,
76
- ]
77
-
78
- if model:
79
- cmd.extend(["--model", model])
80
-
81
- log_debug("gemini", "Running command: gemini -y -p <instruction>")
82
-
83
- try:
84
- p = subprocess.run(
85
- cmd,
86
- input=plan,
87
- text=True,
88
- capture_output=True,
89
- timeout=timeout,
90
- encoding='utf-8',
91
- errors='replace',
92
- )
93
- except subprocess.TimeoutExpired:
94
- log_warn("gemini", f"TIMEOUT after {timeout}s")
95
- return ReviewerResult("gemini", False, "error", {}, "", f"gemini timed out after {timeout}s")
96
- except Exception as ex:
97
- log_error("gemini", f"Exception: {ex}")
98
- return ReviewerResult("gemini", False, "error", {}, "", f"gemini failed to run: {ex}")
99
-
100
- log_debug("gemini", f"Exit code: {p.returncode}")
101
-
102
- raw = (p.stdout or "").strip()
103
- err = (p.stderr or "").strip()
104
-
105
- obj = parse_json_maybe(raw)
106
- ok, verdict, norm = coerce_to_review(obj, "Retry or check CLI auth/config.")
107
-
108
- return ReviewerResult("gemini", ok, verdict, norm, raw, err)