aiwcli 0.9.5 → 0.9.7
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.
- package/dist/commands/init/index.d.ts +0 -8
- package/dist/commands/init/index.js +5 -35
- package/dist/lib/index.d.ts +3 -4
- package/dist/lib/index.js +3 -5
- package/dist/lib/settings-hierarchy.js +5 -16
- package/dist/lib/template-installer.d.ts +9 -0
- package/dist/lib/template-installer.js +3 -14
- package/dist/lib/template-merger.js +1 -12
- package/dist/lib/windsurf-hooks-hierarchy.js +2 -13
- package/dist/templates/_shared/hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/context_enforcer.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/context_monitor.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/file-suggestion.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/session_start.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/task_create_atomicity.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/task_create_capture.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/task_update_capture.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/__pycache__/user_prompt_submit.cpython-313.pyc +0 -0
- package/dist/templates/_shared/hooks/context_enforcer.py +18 -68
- package/dist/templates/_shared/hooks/user_prompt_submit.py +1 -1
- package/dist/templates/_shared/lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/atomic_write.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/constants.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/hook_utils.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/inference.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/stop_words.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/subprocess_utils.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/__pycache__/utils.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/base/hook_utils.py +0 -24
- package/dist/templates/_shared/lib/base/stop_words.py +55 -0
- package/dist/templates/_shared/lib/base/utils.py +5 -20
- package/dist/templates/_shared/lib/context/__init__.py +0 -8
- package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/cache.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/context_extractor.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/discovery.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/event_log.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/plan_archive.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/__pycache__/task_sync.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/context/plan_archive.py +0 -146
- package/dist/templates/_shared/lib/templates/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/templates/__pycache__/formatters.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/templates/__pycache__/persona_questions.cpython-313.pyc +0 -0
- package/dist/templates/_shared/lib/templates/__pycache__/plan_context.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/.claude/settings.json +12 -12
- package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/ACCESSIBILITY-TESTER.md +0 -1
- package/dist/templates/cc-native/_cc-native/agents/CLAUDE.md +56 -0
- package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/CODE-REVIEWER.md +0 -1
- package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/CONTEXT-EXTRACTOR.md +0 -1
- package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/PENETRATION-TESTER.md +0 -1
- package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/PERFORMANCE-ENGINEER.md +0 -1
- package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/PLAN-ORCHESTRATOR.md +0 -1
- package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/TRADE-OFF-ILLUMINATOR.md +0 -1
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/add_plan_context.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/__pycache__/suggest-fresh-perspective.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.py +1 -6
- package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +10 -11
- package/dist/templates/cc-native/_cc-native/lib/__init__.py +0 -4
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/atomic_write.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/constants.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/debug.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/orchestrator.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/state.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/__pycache__/utils.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/orchestrator.py +36 -18
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/base.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/codex.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/gemini.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +13 -9
- package/dist/templates/cc-native/_cc-native/lib/reviewers/base.py +1 -2
- package/dist/templates/cc-native/_cc-native/lib/state.py +11 -9
- package/dist/templates/cc-native/_cc-native/lib/utils.py +23 -106
- package/dist/templates/cc-native/_cc-native/plan-review.config.json +2 -4
- package/dist/templates/cc-native/_cc-native/scripts/__pycache__/aggregate_agents.cpython-313.pyc +0 -0
- package/dist/templates/cc-native/_cc-native/scripts/aggregate_agents.py +25 -8
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/ARCHITECT-REVIEWER.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/ASSUMPTION-CHAIN-TRACER.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/CLARITY-AUDITOR.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/COMPLETENESS-CHECKER.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/DEVILS-ADVOCATE.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/DOCUMENTATION-REVIEWER.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/FEASIBILITY-ANALYST.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/FRESH-PERSPECTIVE.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/HANDOFF-READINESS.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/HIDDEN-COMPLEXITY-DETECTOR.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/INCENTIVE-MAPPER.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/PRECEDENT-FINDER.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/REVERSIBILITY-ANALYST.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/RISK-ASSESSOR.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/SECOND-ORDER-ANALYST.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/SIMPLICITY-GUARDIAN.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/SKEPTIC.md +0 -0
- /package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/STAKEHOLDER-ADVOCATE.md +0 -0
|
@@ -129,7 +129,7 @@ def run_orchestrator(
|
|
|
129
129
|
Args:
|
|
130
130
|
plan: The plan content to analyze
|
|
131
131
|
agent_library: List of available agents
|
|
132
|
-
config: Orchestrator configuration (model, timeout
|
|
132
|
+
config: Orchestrator configuration (model, timeout)
|
|
133
133
|
settings: Agent review settings (agentSelection, complexityCategories)
|
|
134
134
|
|
|
135
135
|
Returns:
|
|
@@ -154,9 +154,11 @@ def run_orchestrator(
|
|
|
154
154
|
|
|
155
155
|
eprint(f"[orchestrator] Found Claude CLI at: {claude_path}")
|
|
156
156
|
|
|
157
|
-
# Build agent list for prompt
|
|
157
|
+
# Build agent list for prompt with rich descriptions
|
|
158
158
|
agent_list = "\n".join([
|
|
159
|
-
f"- {a.name}
|
|
159
|
+
f"- {a.name} [{', '.join(a.categories)}]\n"
|
|
160
|
+
f" Focus: {a.focus}\n"
|
|
161
|
+
f" Expertise: {a.description}"
|
|
160
162
|
for a in agent_library if a.enabled
|
|
161
163
|
])
|
|
162
164
|
category_list = "/".join(categories)
|
|
@@ -164,43 +166,48 @@ def run_orchestrator(
|
|
|
164
166
|
medium_range = f"{selection.get('medium', {}).get('min', 1)}-{selection.get('medium', {}).get('max', 2)}"
|
|
165
167
|
high_range = f"{selection.get('high', {}).get('min', 2)}-{selection.get('high', {}).get('max', 4)}"
|
|
166
168
|
|
|
167
|
-
|
|
169
|
+
# System prompt with orchestrator instructions
|
|
170
|
+
system_prompt = """You are a plan orchestrator for code review. Your job is to analyze plans and select appropriate reviewer agents.
|
|
168
171
|
|
|
169
|
-
You
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
172
|
+
You MUST call StructuredOutput immediately with your analysis. Do NOT ask questions or use any other tools.
|
|
173
|
+
|
|
174
|
+
When selecting agents:
|
|
175
|
+
- Match agent expertise to plan requirements
|
|
176
|
+
- Consider what each agent specializes in
|
|
177
|
+
- Only select agents whose categories match the plan category
|
|
178
|
+
- Fewer agents for simple plans, more for complex plans"""
|
|
179
|
+
|
|
180
|
+
# User prompt with plan and agent list
|
|
181
|
+
prompt = f"""Analyze this plan and select appropriate reviewer agents.
|
|
173
182
|
|
|
174
183
|
Available agents:
|
|
175
184
|
{agent_list}
|
|
176
185
|
|
|
177
|
-
|
|
178
|
-
- simple complexity = {simple_range} agents
|
|
186
|
+
Selection rules:
|
|
187
|
+
- simple complexity = {simple_range} agents
|
|
179
188
|
- medium complexity = {medium_range} agents
|
|
180
189
|
- high complexity = {high_range} agents
|
|
181
|
-
- Only select agents whose categories match the plan category
|
|
190
|
+
- Only select agents whose categories match the plan category ({category_list})
|
|
182
191
|
- Non-technical plans (life, business) typically need 0 code-focused agents
|
|
183
192
|
|
|
184
|
-
Analyze and call StructuredOutput with your decision now.
|
|
185
|
-
|
|
186
193
|
PLAN:
|
|
187
194
|
<<<
|
|
188
195
|
{plan}
|
|
189
196
|
>>>
|
|
190
|
-
|
|
197
|
+
|
|
198
|
+
Call StructuredOutput now with: complexity, category, selectedAgents, reasoning"""
|
|
191
199
|
|
|
192
200
|
schema_json = json.dumps(ORCHESTRATOR_SCHEMA, ensure_ascii=False)
|
|
193
201
|
|
|
194
202
|
cmd_args = [
|
|
195
203
|
claude_path,
|
|
196
204
|
"-p", # Enable print mode to read prompt from stdin
|
|
197
|
-
"--agent", "plan-orchestrator",
|
|
198
205
|
"--model", config.model,
|
|
199
|
-
"--permission-mode", "bypassPermissions",
|
|
200
206
|
"--output-format", "json",
|
|
201
|
-
"--max-turns", str(config.max_turns),
|
|
202
207
|
"--json-schema", schema_json,
|
|
203
|
-
"--
|
|
208
|
+
"--max-turns", "3", # Single-turn with buffer for tool call + result
|
|
209
|
+
"--setting-sources", "", # Disable PAI context interference
|
|
210
|
+
"--system-prompt", system_prompt,
|
|
204
211
|
]
|
|
205
212
|
|
|
206
213
|
eprint(f"[orchestrator] Running with model: {config.model}, timeout: {config.timeout}s")
|
|
@@ -245,6 +252,17 @@ PLAN:
|
|
|
245
252
|
eprint(f"[orchestrator] stderr: {p.stderr[:300]}")
|
|
246
253
|
|
|
247
254
|
obj = _parse_claude_output(raw)
|
|
255
|
+
|
|
256
|
+
# Debug logging to diagnose empty selectedAgents issue
|
|
257
|
+
eprint(f"[orchestrator:debug] Raw output length: {len(raw)} chars")
|
|
258
|
+
if raw:
|
|
259
|
+
eprint(f"[orchestrator:debug] Raw output (first 500 chars): {raw[:500]}")
|
|
260
|
+
eprint(f"[orchestrator:debug] Parsed obj: {obj}")
|
|
261
|
+
if obj:
|
|
262
|
+
eprint(f"[orchestrator:debug] obj keys: {list(obj.keys())}")
|
|
263
|
+
eprint(f"[orchestrator:debug] selectedAgents value: {obj.get('selectedAgents', 'MISSING')}")
|
|
264
|
+
eprint(f"[orchestrator:debug] reasoning value: {obj.get('reasoning', 'MISSING')}")
|
|
265
|
+
|
|
248
266
|
if not obj:
|
|
249
267
|
eprint("[orchestrator] Failed to parse output, falling back to medium complexity")
|
|
250
268
|
return OrchestratorResult(
|
package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/__init__.cpython-313.pyc
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/gemini.cpython-313.pyc
CHANGED
|
Binary file
|
|
@@ -81,7 +81,6 @@ def run_agent_review(
|
|
|
81
81
|
agent: AgentConfig,
|
|
82
82
|
schema: Dict[str, Any],
|
|
83
83
|
timeout: int,
|
|
84
|
-
max_turns: int = 3,
|
|
85
84
|
context_path: Optional[Path] = None,
|
|
86
85
|
session_name: str = "unknown",
|
|
87
86
|
) -> ReviewerResult:
|
|
@@ -92,7 +91,6 @@ def run_agent_review(
|
|
|
92
91
|
agent: Agent configuration (name, model, etc.)
|
|
93
92
|
schema: JSON schema for the review output
|
|
94
93
|
timeout: Timeout in seconds
|
|
95
|
-
max_turns: Maximum agent turns
|
|
96
94
|
context_path: Optional path to context folder for debug logging
|
|
97
95
|
session_name: Session name for debug logging
|
|
98
96
|
|
|
@@ -113,7 +111,9 @@ def run_agent_review(
|
|
|
113
111
|
|
|
114
112
|
eprint(f"[{agent.name}] Found Claude CLI at: {claude_path}")
|
|
115
113
|
|
|
116
|
-
prompt
|
|
114
|
+
# User prompt - direct instruction to call StructuredOutput immediately
|
|
115
|
+
prompt = f"""IMMEDIATELY call StructuredOutput with your review of the plan below.
|
|
116
|
+
Do NOT output any text before calling StructuredOutput.
|
|
117
117
|
|
|
118
118
|
PLAN:
|
|
119
119
|
<<<
|
|
@@ -122,19 +122,24 @@ PLAN:
|
|
|
122
122
|
"""
|
|
123
123
|
|
|
124
124
|
schema_json = json.dumps(schema, ensure_ascii=False)
|
|
125
|
+
|
|
126
|
+
# Build command args - use --system-prompt with the markdown body as persona
|
|
125
127
|
cmd_args = [
|
|
126
128
|
claude_path,
|
|
127
129
|
"-p", # Enable print mode to read prompt from stdin
|
|
128
|
-
"--agent", agent.name,
|
|
129
130
|
"--model", agent.model,
|
|
130
|
-
"--permission-mode", "plan",
|
|
131
131
|
"--output-format", "json",
|
|
132
|
-
"--max-turns", str(max_turns),
|
|
133
132
|
"--json-schema", schema_json,
|
|
134
|
-
"--
|
|
133
|
+
"--max-turns", "3", # Allow buffer for tool call + result (usually completes in 2)
|
|
134
|
+
"--setting-sources", "", # Disable user/project settings to avoid PAI context interference
|
|
135
135
|
]
|
|
136
136
|
|
|
137
|
-
|
|
137
|
+
# Add system prompt: prefix with single-turn instructions, then agent's persona
|
|
138
|
+
if agent.system_prompt:
|
|
139
|
+
full_prompt = AGENT_REVIEW_PROMPT_PREFIX + "\n\n---\n\n" + agent.system_prompt
|
|
140
|
+
cmd_args.extend(["--system-prompt", full_prompt])
|
|
141
|
+
|
|
142
|
+
eprint(f"[{agent.name}] Running with model: {agent.model}, timeout: {timeout}s")
|
|
138
143
|
|
|
139
144
|
# Get environment for internal subprocess (bypasses hooks)
|
|
140
145
|
env = get_internal_subprocess_env()
|
|
@@ -176,7 +181,6 @@ PLAN:
|
|
|
176
181
|
"stderr_len": len(err),
|
|
177
182
|
"model": agent.model,
|
|
178
183
|
"timeout": timeout,
|
|
179
|
-
"max_turns": max_turns,
|
|
180
184
|
})
|
|
181
185
|
|
|
182
186
|
if raw:
|
|
@@ -39,7 +39,7 @@ class AgentConfig:
|
|
|
39
39
|
enabled: bool = True
|
|
40
40
|
categories: List[str] = field(default_factory=lambda: ["code"])
|
|
41
41
|
description: str = ""
|
|
42
|
-
|
|
42
|
+
system_prompt: str = "" # Markdown body content for --system-prompt
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
@dataclass
|
|
@@ -48,7 +48,6 @@ class OrchestratorConfig:
|
|
|
48
48
|
enabled: bool = True
|
|
49
49
|
model: str = "haiku"
|
|
50
50
|
timeout: int = 30
|
|
51
|
-
max_turns: int = 3
|
|
52
51
|
|
|
53
52
|
|
|
54
53
|
# ---------------------------
|
|
@@ -21,6 +21,17 @@ except ImportError:
|
|
|
21
21
|
from constants import validate_plan_path, PLANS_DIR
|
|
22
22
|
from atomic_write import atomic_write
|
|
23
23
|
|
|
24
|
+
# Import canonical eprint from shared lib
|
|
25
|
+
try:
|
|
26
|
+
from ...lib.base.utils import eprint
|
|
27
|
+
except ImportError:
|
|
28
|
+
# Fallback for direct execution
|
|
29
|
+
import sys as _sys
|
|
30
|
+
from pathlib import Path as _Path
|
|
31
|
+
_shared_lib = _Path(__file__).resolve().parent.parent.parent / "_shared" / "lib"
|
|
32
|
+
_sys.path.insert(0, str(_shared_lib))
|
|
33
|
+
from base.utils import eprint
|
|
34
|
+
|
|
24
35
|
|
|
25
36
|
# ---------------------------
|
|
26
37
|
# Constants
|
|
@@ -35,15 +46,6 @@ DEFAULT_REVIEW_ITERATIONS: Dict[str, int] = {
|
|
|
35
46
|
}
|
|
36
47
|
|
|
37
48
|
|
|
38
|
-
# ---------------------------
|
|
39
|
-
# Utilities
|
|
40
|
-
# ---------------------------
|
|
41
|
-
|
|
42
|
-
def eprint(*args: Any) -> None:
|
|
43
|
-
"""Print to stderr."""
|
|
44
|
-
print(*args, file=sys.stderr)
|
|
45
|
-
|
|
46
|
-
|
|
47
49
|
# ---------------------------
|
|
48
50
|
# State File Management
|
|
49
51
|
# ---------------------------
|
|
@@ -29,6 +29,29 @@ except ImportError:
|
|
|
29
29
|
from atomic_write import atomic_write
|
|
30
30
|
from constants import ENABLE_ROBUST_PLAN_WRITES
|
|
31
31
|
|
|
32
|
+
# Import canonical utilities from shared lib (with Windows bug fixes)
|
|
33
|
+
try:
|
|
34
|
+
from ...lib.base.utils import (
|
|
35
|
+
eprint,
|
|
36
|
+
now_local,
|
|
37
|
+
project_dir,
|
|
38
|
+
sanitize_filename,
|
|
39
|
+
sanitize_title,
|
|
40
|
+
)
|
|
41
|
+
except ImportError:
|
|
42
|
+
# Fallback for direct execution
|
|
43
|
+
import sys
|
|
44
|
+
from pathlib import Path
|
|
45
|
+
_shared_lib = Path(__file__).resolve().parent.parent.parent / "_shared" / "lib"
|
|
46
|
+
sys.path.insert(0, str(_shared_lib))
|
|
47
|
+
from base.utils import (
|
|
48
|
+
eprint,
|
|
49
|
+
now_local,
|
|
50
|
+
project_dir,
|
|
51
|
+
sanitize_filename,
|
|
52
|
+
sanitize_title,
|
|
53
|
+
)
|
|
54
|
+
|
|
32
55
|
|
|
33
56
|
# ---------------------------
|
|
34
57
|
# Constants
|
|
@@ -87,68 +110,6 @@ class ReviewerResult:
|
|
|
87
110
|
err: str
|
|
88
111
|
|
|
89
112
|
|
|
90
|
-
# ---------------------------
|
|
91
|
-
# Core utilities
|
|
92
|
-
# ---------------------------
|
|
93
|
-
|
|
94
|
-
def eprint(*args: Any) -> None:
|
|
95
|
-
"""Print to stderr."""
|
|
96
|
-
print(*args, file=sys.stderr)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
def now_local() -> datetime:
|
|
100
|
-
"""Get current local datetime."""
|
|
101
|
-
return datetime.now()
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def project_dir(payload: Dict[str, Any]) -> Path:
|
|
105
|
-
"""Get project directory from payload or environment."""
|
|
106
|
-
p = os.environ.get("CLAUDE_PROJECT_DIR") or payload.get("cwd") or os.getcwd()
|
|
107
|
-
return Path(p)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def sanitize_filename(s: str, max_len: int = 32) -> str:
|
|
111
|
-
"""Sanitize string for use in filename."""
|
|
112
|
-
s = re.sub(r"[^A-Za-z0-9._-]+", "_", s)
|
|
113
|
-
return s.strip("._-")[:max_len] or "unknown"
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
def sanitize_title(s: str, max_len: int = 50) -> str:
|
|
117
|
-
"""Sanitize title for use in filename (with space-to-dash conversion)."""
|
|
118
|
-
s = s.replace(' ', '-')
|
|
119
|
-
s = re.sub(r"[^A-Za-z0-9._-]+", "_", s)
|
|
120
|
-
s = re.sub(r"[-_]+", "-", s)
|
|
121
|
-
return s.strip("._-")[:max_len] or "unknown"
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
def extract_plan_title(plan: str) -> Optional[str]:
|
|
125
|
-
"""Extract title from '# Plan: <title>' line in plan content."""
|
|
126
|
-
for line in plan.split('\n'):
|
|
127
|
-
line = line.strip()
|
|
128
|
-
if line.startswith('# Plan:'):
|
|
129
|
-
title = line[7:].strip()
|
|
130
|
-
return title if title else None
|
|
131
|
-
return None
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def extract_task_from_context(plan: str) -> Optional[str]:
|
|
135
|
-
"""Extract Task from Evaluation Context section as fallback title."""
|
|
136
|
-
# Look for **Task**: ... or **Task Summary**: ... patterns
|
|
137
|
-
patterns = [
|
|
138
|
-
r'\*\*Task\*\*:\s*(.+?)(?:\n|$)',
|
|
139
|
-
r'\*\*Task Summary\*\*:\s*(.+?)(?:\n|$)',
|
|
140
|
-
]
|
|
141
|
-
for pattern in patterns:
|
|
142
|
-
match = re.search(pattern, plan)
|
|
143
|
-
if match:
|
|
144
|
-
task = match.group(1).strip()
|
|
145
|
-
# Truncate to reasonable title length
|
|
146
|
-
if len(task) > 50:
|
|
147
|
-
task = task[:47] + "..."
|
|
148
|
-
return task
|
|
149
|
-
return None
|
|
150
|
-
|
|
151
|
-
|
|
152
113
|
# ---------------------------
|
|
153
114
|
# Plan hash deduplication
|
|
154
115
|
# ---------------------------
|
|
@@ -398,50 +359,6 @@ def get_state_path_from_plan(plan_path: str) -> Path:
|
|
|
398
359
|
return plan_file.with_suffix('.state.json')
|
|
399
360
|
|
|
400
361
|
|
|
401
|
-
def load_state(plan_path: str) -> Optional[Dict[str, Any]]:
|
|
402
|
-
"""Load state file for this plan if it exists."""
|
|
403
|
-
state_file = get_state_path_from_plan(plan_path)
|
|
404
|
-
|
|
405
|
-
if not state_file.exists():
|
|
406
|
-
return None
|
|
407
|
-
|
|
408
|
-
try:
|
|
409
|
-
return json.loads(state_file.read_text(encoding="utf-8"))
|
|
410
|
-
except Exception as e:
|
|
411
|
-
eprint(f"[utils] Failed to read state file: {e}")
|
|
412
|
-
return None
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
def save_state(plan_path: str, state: Dict[str, Any]) -> bool:
|
|
416
|
-
"""Save state file for this plan.
|
|
417
|
-
|
|
418
|
-
Returns True on success, False on failure.
|
|
419
|
-
"""
|
|
420
|
-
state_file = get_state_path_from_plan(plan_path)
|
|
421
|
-
try:
|
|
422
|
-
state_file.write_text(json.dumps(state, indent=2), encoding="utf-8")
|
|
423
|
-
return True
|
|
424
|
-
except Exception as e:
|
|
425
|
-
eprint(f"[utils] Failed to save state file: {e}")
|
|
426
|
-
return False
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
def delete_state(plan_path: str) -> bool:
|
|
430
|
-
"""Delete state file after successful archive.
|
|
431
|
-
|
|
432
|
-
Returns True if deleted or didn't exist, False on error.
|
|
433
|
-
"""
|
|
434
|
-
state_file = get_state_path_from_plan(plan_path)
|
|
435
|
-
try:
|
|
436
|
-
if state_file.exists():
|
|
437
|
-
state_file.unlink()
|
|
438
|
-
eprint(f"[utils] Deleted state file: {state_file}")
|
|
439
|
-
return True
|
|
440
|
-
except Exception as e:
|
|
441
|
-
eprint(f"[utils] Warning: failed to delete state file: {e}")
|
|
442
|
-
return False
|
|
443
|
-
|
|
444
|
-
|
|
445
362
|
def format_review_markdown(
|
|
446
363
|
results: List[ReviewerResult],
|
|
447
364
|
overall: str,
|
|
@@ -22,14 +22,12 @@
|
|
|
22
22
|
},
|
|
23
23
|
"agentReview": {
|
|
24
24
|
"enabled": true,
|
|
25
|
-
"timeout":
|
|
25
|
+
"timeout": 180,
|
|
26
26
|
"blockOnFail": true,
|
|
27
|
-
"maxTurns": 2,
|
|
28
27
|
"orchestrator": {
|
|
29
28
|
"enabled": true,
|
|
30
29
|
"model": "haiku",
|
|
31
|
-
"timeout": 30
|
|
32
|
-
"maxTurns": 6
|
|
30
|
+
"timeout": 30
|
|
33
31
|
},
|
|
34
32
|
"legacyMode": false,
|
|
35
33
|
"mandatoryAgents": ["handoff-readiness", "clarity-auditor", "skeptic"],
|
package/dist/templates/cc-native/_cc-native/scripts/__pycache__/aggregate_agents.cpython-313.pyc
CHANGED
|
Binary file
|
|
@@ -93,16 +93,31 @@ def extract_frontmatter(content: str) -> dict[str, Any] | None:
|
|
|
93
93
|
return None
|
|
94
94
|
|
|
95
95
|
|
|
96
|
+
def extract_body(content: str) -> str:
|
|
97
|
+
"""Extract markdown body (after frontmatter) from content.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
content: Raw markdown file content
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Markdown body content (everything after the closing ---)
|
|
104
|
+
"""
|
|
105
|
+
match = re.match(r'^---\s*\n.*?\n---\s*\n(.*)$', content, re.DOTALL)
|
|
106
|
+
if match:
|
|
107
|
+
return match.group(1).strip()
|
|
108
|
+
return content.strip()
|
|
109
|
+
|
|
110
|
+
|
|
96
111
|
def aggregate_agents(agents_dir: Path | None = None) -> list[dict[str, Any]]:
|
|
97
112
|
"""Read all agent files and return aggregated metadata.
|
|
98
|
-
|
|
113
|
+
|
|
99
114
|
Scans the agents directory for .md files, extracts frontmatter from each,
|
|
100
115
|
and returns a list of agent configurations.
|
|
101
|
-
|
|
116
|
+
|
|
102
117
|
Args:
|
|
103
118
|
agents_dir: Path to agents directory. If None, uses default
|
|
104
|
-
|
|
105
|
-
|
|
119
|
+
_cc-native/agents/ relative to this script.
|
|
120
|
+
|
|
106
121
|
Returns:
|
|
107
122
|
List of agent configuration dicts with fields:
|
|
108
123
|
- name: Agent identifier (lowercase)
|
|
@@ -111,14 +126,14 @@ def aggregate_agents(agents_dir: Path | None = None) -> list[dict[str, Any]]:
|
|
|
111
126
|
- focus: Brief focus for orchestrator
|
|
112
127
|
- enabled: Whether agent is available
|
|
113
128
|
- categories: Work categories for filtering
|
|
114
|
-
-
|
|
129
|
+
- system_prompt: Full markdown body (persona content)
|
|
115
130
|
"""
|
|
116
131
|
if agents_dir is None:
|
|
117
|
-
# Default to
|
|
132
|
+
# Default to _cc-native/agents/ relative to this script's location
|
|
118
133
|
# Script is at: _cc-native/scripts/aggregate_agents.py
|
|
119
|
-
# Agents are at:
|
|
134
|
+
# Agents are at: _cc-native/agents/
|
|
120
135
|
script_dir = Path(__file__).parent
|
|
121
|
-
agents_dir = script_dir.parent
|
|
136
|
+
agents_dir = script_dir.parent / "agents"
|
|
122
137
|
|
|
123
138
|
agents = []
|
|
124
139
|
|
|
@@ -135,6 +150,8 @@ def aggregate_agents(agents_dir: Path | None = None) -> list[dict[str, Any]]:
|
|
|
135
150
|
frontmatter["categories"] = ["code"]
|
|
136
151
|
elif isinstance(frontmatter["categories"], str):
|
|
137
152
|
frontmatter["categories"] = [frontmatter["categories"]]
|
|
153
|
+
# Extract markdown body as system_prompt
|
|
154
|
+
frontmatter["system_prompt"] = extract_body(content)
|
|
138
155
|
agents.append(frontmatter)
|
|
139
156
|
except Exception:
|
|
140
157
|
# Skip files that can't be read or parsed
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
/package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/CLARITY-AUDITOR.md
RENAMED
|
File without changes
|
|
File without changes
|
/package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/DEVILS-ADVOCATE.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/INCENTIVE-MAPPER.md
RENAMED
|
File without changes
|
/package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/PRECEDENT-FINDER.md
RENAMED
|
File without changes
|
|
File without changes
|
/package/dist/templates/cc-native/{.claude/agents/cc-native → _cc-native/agents}/RISK-ASSESSOR.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|