aiwcli 0.9.8 → 0.10.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 (116) hide show
  1. package/bin/run.js +5 -2
  2. package/dist/lib/claude-settings-types.d.ts +2 -0
  3. package/dist/templates/CLAUDE.md +3 -3
  4. package/dist/templates/_shared/.claude/settings.json +4 -0
  5. package/dist/templates/_shared/hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  6. package/dist/templates/_shared/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
  7. package/dist/templates/_shared/hooks/__pycache__/context_enforcer.cpython-313.pyc +0 -0
  8. package/dist/templates/_shared/hooks/__pycache__/context_monitor.cpython-313.pyc +0 -0
  9. package/dist/templates/_shared/hooks/__pycache__/file-suggestion.cpython-313.pyc +0 -0
  10. package/dist/templates/_shared/hooks/__pycache__/pre_compact.cpython-313.pyc +0 -0
  11. package/dist/templates/_shared/hooks/__pycache__/session_end.cpython-313.pyc +0 -0
  12. package/dist/templates/_shared/hooks/__pycache__/session_start.cpython-313.pyc +0 -0
  13. package/dist/templates/_shared/hooks/__pycache__/task_create_capture.cpython-313.pyc +0 -0
  14. package/dist/templates/_shared/hooks/__pycache__/task_update_capture.cpython-313.pyc +0 -0
  15. package/dist/templates/_shared/hooks/__pycache__/user_prompt_submit.cpython-313.pyc +0 -0
  16. package/dist/templates/_shared/hooks/archive_plan.py +87 -178
  17. package/dist/templates/_shared/hooks/context_monitor.py +104 -247
  18. package/dist/templates/_shared/hooks/file-suggestion.py +26 -23
  19. package/dist/templates/_shared/hooks/pre_compact.py +47 -32
  20. package/dist/templates/_shared/hooks/session_end.py +103 -60
  21. package/dist/templates/_shared/hooks/session_start.py +110 -81
  22. package/dist/templates/_shared/hooks/task_create_capture.py +26 -50
  23. package/dist/templates/_shared/hooks/task_update_capture.py +42 -115
  24. package/dist/templates/_shared/hooks/user_prompt_submit.py +61 -61
  25. package/dist/templates/_shared/lib/base/__init__.py +16 -0
  26. package/dist/templates/_shared/lib/base/__pycache__/__init__.cpython-313.pyc +0 -0
  27. package/dist/templates/_shared/lib/base/__pycache__/hook_utils.cpython-313.pyc +0 -0
  28. package/dist/templates/_shared/lib/base/__pycache__/inference.cpython-313.pyc +0 -0
  29. package/dist/templates/_shared/lib/base/__pycache__/logger.cpython-313.pyc +0 -0
  30. package/dist/templates/_shared/lib/base/__pycache__/utils.cpython-313.pyc +0 -0
  31. package/dist/templates/_shared/lib/base/hook_utils.py +199 -11
  32. package/dist/templates/_shared/lib/base/inference.py +121 -0
  33. package/dist/templates/_shared/lib/base/logger.py +291 -0
  34. package/dist/templates/_shared/lib/base/utils.py +42 -9
  35. package/dist/templates/_shared/lib/context/__init__.py +72 -80
  36. package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
  37. package/dist/templates/_shared/lib/context/__pycache__/context_formatter.cpython-313.pyc +0 -0
  38. package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
  39. package/dist/templates/_shared/lib/context/__pycache__/context_selector.cpython-313.pyc +0 -0
  40. package/dist/templates/_shared/lib/context/__pycache__/context_store.cpython-313.pyc +0 -0
  41. package/dist/templates/_shared/lib/context/__pycache__/discovery.cpython-313.pyc +0 -0
  42. package/dist/templates/_shared/lib/context/__pycache__/plan_manager.cpython-313.pyc +0 -0
  43. package/dist/templates/_shared/lib/context/__pycache__/task_tracker.cpython-313.pyc +0 -0
  44. package/dist/templates/_shared/lib/context/context_formatter.py +316 -0
  45. package/dist/templates/_shared/lib/context/context_selector.py +491 -0
  46. package/dist/templates/_shared/lib/context/context_store.py +636 -0
  47. package/dist/templates/_shared/lib/context/plan_manager.py +204 -0
  48. package/dist/templates/_shared/lib/context/task_tracker.py +188 -0
  49. package/dist/templates/_shared/lib/handoff/__pycache__/__init__.cpython-313.pyc +0 -0
  50. package/dist/templates/_shared/lib/handoff/__pycache__/document_generator.cpython-313.pyc +0 -0
  51. package/dist/templates/_shared/lib/handoff/document_generator.py +14 -40
  52. package/dist/templates/_shared/lib/templates/README.md +5 -13
  53. package/dist/templates/_shared/lib/templates/__init__.py +2 -6
  54. package/dist/templates/_shared/lib/templates/__pycache__/__init__.cpython-313.pyc +0 -0
  55. package/dist/templates/_shared/lib/templates/__pycache__/formatters.cpython-313.pyc +0 -0
  56. package/dist/templates/_shared/lib/templates/__pycache__/plan_context.cpython-313.pyc +0 -0
  57. package/dist/templates/_shared/lib/templates/plan_context.py +1 -38
  58. package/dist/templates/_shared/scripts/__pycache__/save_handoff.cpython-313.pyc +0 -0
  59. package/dist/templates/_shared/scripts/__pycache__/status_line.cpython-313.pyc +0 -0
  60. package/dist/templates/_shared/scripts/save_handoff.py +39 -19
  61. package/dist/templates/_shared/scripts/status_line.py +701 -0
  62. package/dist/templates/_shared/workflows/handoff.md +9 -3
  63. package/dist/templates/cc-native/.claude/settings.json +41 -8
  64. package/dist/templates/cc-native/CC-NATIVE-README.md +25 -28
  65. package/dist/templates/cc-native/MIGRATION.md +1 -1
  66. package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +14 -39
  67. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +49 -21
  68. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/add_plan_context.cpython-313.pyc +0 -0
  69. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
  70. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/mark_questions_asked.cpython-313.pyc +0 -0
  71. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_accepted.cpython-313.pyc +0 -0
  72. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_questions_early.cpython-313.pyc +0 -0
  73. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/suggest-fresh-perspective.cpython-313.pyc +0 -0
  74. package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.py +57 -55
  75. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +163 -131
  76. package/dist/templates/cc-native/_cc-native/hooks/plan_accepted.py +127 -0
  77. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.py +81 -0
  78. package/dist/templates/cc-native/_cc-native/hooks/suggest-fresh-perspective.py +26 -25
  79. package/dist/templates/cc-native/_cc-native/lib/CLAUDE.md +6 -4
  80. package/dist/templates/cc-native/_cc-native/lib/__pycache__/__init__.cpython-313.pyc +0 -0
  81. package/dist/templates/cc-native/_cc-native/lib/__pycache__/constants.cpython-313.pyc +0 -0
  82. package/dist/templates/cc-native/_cc-native/lib/__pycache__/debug.cpython-313.pyc +0 -0
  83. package/dist/templates/cc-native/_cc-native/lib/__pycache__/orchestrator.cpython-313.pyc +0 -0
  84. package/dist/templates/cc-native/_cc-native/lib/__pycache__/state.cpython-313.pyc +0 -0
  85. package/dist/templates/cc-native/_cc-native/lib/__pycache__/utils.cpython-313.pyc +0 -0
  86. package/dist/templates/cc-native/_cc-native/lib/debug.py +37 -22
  87. package/dist/templates/cc-native/_cc-native/lib/orchestrator.py +34 -29
  88. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/__init__.cpython-313.pyc +0 -0
  89. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
  90. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/base.cpython-313.pyc +0 -0
  91. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/codex.cpython-313.pyc +0 -0
  92. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/gemini.cpython-313.pyc +0 -0
  93. package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +26 -21
  94. package/dist/templates/cc-native/_cc-native/lib/reviewers/codex.py +12 -7
  95. package/dist/templates/cc-native/_cc-native/lib/reviewers/gemini.py +12 -7
  96. package/dist/templates/cc-native/_cc-native/lib/state.py +31 -16
  97. package/dist/templates/cc-native/_cc-native/lib/utils.py +207 -40
  98. package/dist/templates/cc-native/_cc-native/plan-review.config.json +1 -2
  99. package/oclif.manifest.json +1 -1
  100. package/package.json +1 -1
  101. package/dist/templates/_shared/hooks/context_enforcer.py +0 -625
  102. package/dist/templates/_shared/hooks/task_create_atomicity.py +0 -177
  103. package/dist/templates/_shared/lib/context/auto_state.py +0 -167
  104. package/dist/templates/_shared/lib/context/cache.py +0 -444
  105. package/dist/templates/_shared/lib/context/context_extractor.py +0 -115
  106. package/dist/templates/_shared/lib/context/context_manager.py +0 -1057
  107. package/dist/templates/_shared/lib/context/discovery.py +0 -554
  108. package/dist/templates/_shared/lib/context/event_log.py +0 -316
  109. package/dist/templates/_shared/lib/context/plan_archive.py +0 -101
  110. package/dist/templates/_shared/lib/context/task_sync.py +0 -407
  111. package/dist/templates/_shared/lib/templates/persona_questions.py +0 -113
  112. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
  113. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-agent-review.cpython-313.pyc +0 -0
  114. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/test_permission_request.cpython-313.pyc +0 -0
  115. package/dist/templates/cc-native/_cc-native/lib/async_archive.py +0 -68
  116. package/dist/templates/cc-native/_cc-native/lib/atomic_write.py +0 -98
@@ -1,177 +0,0 @@
1
- #!/usr/bin/env python3
2
- """PreToolUse hook for TaskCreate - assesses atomicity and forkability via inference.
3
-
4
- Ensures tasks contain sufficient self-contained context for independent execution,
5
- especially when delegated to subagents with zero conversation history.
6
-
7
- Non-blocking: Warns but allows creation even if atomicity is poor.
8
- """
9
-
10
- import json
11
- import sys
12
- from pathlib import Path
13
-
14
- # Path setup
15
- SCRIPT_DIR = Path(__file__).resolve().parent
16
- SHARED_LIB = SCRIPT_DIR.parent / "lib"
17
- sys.path.insert(0, str(SHARED_LIB.parent))
18
-
19
- from lib.base.hook_utils import (
20
- load_hook_input,
21
- validate_hook_event,
22
- get_tool_input,
23
- safe_hook_main,
24
- run_hook,
25
- )
26
- from lib.base.utils import eprint
27
- from lib.base.subprocess_utils import is_internal_call
28
- from lib.base.inference import inference
29
-
30
- # Prompt engineered per Prompting/Standards.md:
31
- # - Markdown-only (no XML)
32
- # - Positive framing (tell what TO do)
33
- # - 1-3 clear examples matching desired output
34
- # - Direct imperative instructions
35
- # - Explicit JSON output format
36
-
37
- ASSESSMENT_SYSTEM_PROMPT = """Assess whether a task description is self-contained enough for a subagent with zero conversation history to execute it.
38
-
39
- ## What Makes a Good Task
40
-
41
- A well-specified task includes:
42
- - Explicit file paths: "Edit src/utils/parser.py"
43
- - Specific function/component names: "Modify validate_input()"
44
- - Clear expected behavior: "Return 404 when user not found"
45
- - Concrete error context: "TypeError on line 45 when input is None"
46
-
47
- ## What Makes a Poor Task
48
-
49
- Watch for context-dependent references:
50
- - Dangling references: "the file above", "as discussed", "this bug"
51
- - Vague actions: "fix the bug", "update it", "finish the work"
52
- - Pronouns without antecedents: "it", "they", "the issue"
53
- - Missing specifics: which file? what function? what behavior?
54
-
55
- ## Examples
56
-
57
- **Atomic** — Subject: "Fix null pointer in user lookup"
58
- Description: "In src/services/user.py, get_user_by_id() raises TypeError when user_id is None. Add null check at line 23 to return None instead of calling database.query()."
59
- Why: file path, function, error, fix location, expected behavior.
60
-
61
- **Not atomic** — Subject: "Fix the bug"
62
- Description: "The issue we discussed earlier needs to be resolved"
63
- Why: no file, no function, no error details, references conversation history.
64
-
65
- **Partially atomic** — Subject: "Add validation to form"
66
- Description: "Add email validation to the signup form. Return error if invalid."
67
- Why: missing which file, what validation rules, where to display error.
68
-
69
- ## Output
70
-
71
- Respond with JSON only:
72
- {"atomic": true/false, "forkable": true/false, "issues": ["issue 1", "issue 2"], "recommendation": "actionable suggestion or 'Well-specified'"}"""
73
-
74
- ASSESSMENT_USER_TEMPLATE = """**Subject:** {subject}
75
- **Description:** {description}
76
-
77
- Could a subagent with zero conversation history execute this task?"""
78
-
79
-
80
- @safe_hook_main("task_create_atomicity")
81
- def main() -> int:
82
- # Skip internal calls (prevents recursion from orchestrator/inference)
83
- if is_internal_call():
84
- return 0
85
-
86
- # Load and validate hook input
87
- payload = load_hook_input()
88
- if not payload:
89
- return 0
90
-
91
- # Only process TaskCreate
92
- if not validate_hook_event(payload, "PreToolUse", "TaskCreate"):
93
- return 0
94
-
95
- tool_input = get_tool_input(payload)
96
- if not tool_input:
97
- return 0
98
-
99
- subject = tool_input.get("subject", "")
100
- description = tool_input.get("description", "")
101
-
102
- # Skip very short tasks (likely intentionally brief or simple acknowledgments)
103
- if len(description.strip()) < 15:
104
- return 0
105
-
106
- # Call inference to assess atomicity and forkability
107
- result = inference(
108
- system_prompt=ASSESSMENT_SYSTEM_PROMPT,
109
- user_prompt=ASSESSMENT_USER_TEMPLATE.format(
110
- subject=subject,
111
- description=description
112
- ),
113
- level="fast", # Use Haiku for minimal latency (~1-2s)
114
- timeout=12, # Allow up to 12s for inference
115
- )
116
-
117
- if not result.success:
118
- eprint(f"[task_create_atomicity] Inference failed: {result.error}")
119
- return 0 # Non-blocking on failure
120
-
121
- # Parse JSON response
122
- try:
123
- # Handle potential markdown code blocks in response
124
- output = result.output.strip()
125
- if output.startswith("```"):
126
- # Extract JSON from code block
127
- lines = output.split("\n")
128
- json_lines = []
129
- in_block = False
130
- for line in lines:
131
- if line.startswith("```") and not in_block:
132
- in_block = True
133
- continue
134
- elif line.startswith("```") and in_block:
135
- break
136
- elif in_block:
137
- json_lines.append(line)
138
- output = "\n".join(json_lines)
139
-
140
- assessment = json.loads(output)
141
- except json.JSONDecodeError:
142
- eprint(f"[task_create_atomicity] Failed to parse inference response: {result.output[:100]}")
143
- return 0
144
-
145
- # Extract assessment fields
146
- atomic = assessment.get("atomic", True)
147
- forkable = assessment.get("forkable", True)
148
- issues = assessment.get("issues", [])
149
- recommendation = assessment.get("recommendation", "")
150
-
151
- # Build context message based on assessment
152
- if atomic and forkable:
153
- context_msg = "Task assessment: well-specified and ready for delegation."
154
- else:
155
- # Constructive guidance — what to add, not what's wrong
156
- issues_text = "\n".join(f"- {issue}" for issue in issues) if issues else ""
157
-
158
- context_msg = f"""**Enrich this task for subagent delegation**
159
-
160
- A subagent receiving this task will have no conversation history. To make it actionable:
161
-
162
- {issues_text}
163
-
164
- **Suggested enrichment:** {recommendation}"""
165
-
166
- # Output hook response with additionalContext
167
- out = {
168
- "hookSpecificOutput": {
169
- "additionalContext": context_msg
170
- }
171
- }
172
- print(json.dumps(out, ensure_ascii=False))
173
- return 0
174
-
175
-
176
- if __name__ == "__main__":
177
- run_hook(main)
@@ -1,167 +0,0 @@
1
- """Auto-state save/load module for session handoff.
2
-
3
- Captures structural session state (git state, transcript path, mode)
4
- for zero-friction session restoration. Does NOT capture Claude's
5
- subjective state — that comes from the manual /handoff flow.
6
-
7
- Auto-state file: _output/contexts/{context_id}/auto-state.json
8
- Overwritten each save. This is a cache — if corrupted, system degrades gracefully.
9
- """
10
- import json
11
- import subprocess
12
- from pathlib import Path
13
- from typing import Any, Dict, Optional
14
-
15
- from ..base.atomic_write import atomic_write
16
- from ..base.constants import get_auto_state_path, get_context_dir
17
- from ..base.utils import eprint, now_iso
18
-
19
-
20
- AUTO_STATE_VERSION = 1
21
-
22
-
23
- def capture_git_state(project_root: Path = None) -> Dict[str, Any]:
24
- """
25
- Capture current git state for auto-state snapshot.
26
-
27
- Returns:
28
- Dict with branch, uncommitted_files, last_commit_short.
29
- Empty dict on failure (non-git repo, git not available).
30
- """
31
- if project_root is None:
32
- project_root = Path.cwd()
33
-
34
- cwd = str(project_root)
35
-
36
- try:
37
- # Get current branch
38
- branch_result = subprocess.run(
39
- ["git", "rev-parse", "--abbrev-ref", "HEAD"],
40
- capture_output=True, text=True, timeout=5, cwd=cwd
41
- )
42
- branch = branch_result.stdout.strip() if branch_result.returncode == 0 else "unknown"
43
-
44
- # Get uncommitted files (modified + untracked, limited)
45
- status_result = subprocess.run(
46
- ["git", "status", "--porcelain", "--short"],
47
- capture_output=True, text=True, timeout=5, cwd=cwd
48
- )
49
- uncommitted = []
50
- if status_result.returncode == 0:
51
- for line in status_result.stdout.strip().splitlines()[:20]:
52
- # Format: "XY filename" — extract just filename
53
- if len(line) > 3:
54
- uncommitted.append(line[3:].strip())
55
-
56
- # Get last commit short hash + message
57
- log_result = subprocess.run(
58
- ["git", "log", "-1", "--oneline"],
59
- capture_output=True, text=True, timeout=5, cwd=cwd
60
- )
61
- last_commit = log_result.stdout.strip() if log_result.returncode == 0 else ""
62
-
63
- return {
64
- "branch": branch,
65
- "uncommitted_files": uncommitted,
66
- "last_commit_short": last_commit,
67
- }
68
- except (subprocess.TimeoutExpired, FileNotFoundError, OSError) as e:
69
- eprint(f"[auto_state] Git capture failed: {e}")
70
- return {}
71
-
72
-
73
- def save_auto_state(
74
- context_id: str,
75
- session_id: str,
76
- save_reason: str,
77
- project_root: Path = None,
78
- in_flight_mode: str = "none",
79
- plan_path: Optional[str] = None,
80
- handoff_path: Optional[str] = None,
81
- transcript_path: Optional[str] = None,
82
- ) -> bool:
83
- """
84
- Save auto-state.json for a context.
85
-
86
- Captures structural state for session restoration. Overwrites
87
- any existing auto-state file.
88
-
89
- Args:
90
- context_id: Context identifier
91
- session_id: Current session ID
92
- save_reason: Why state was saved (session_end, pre_compact, progressive)
93
- project_root: Project root directory
94
- in_flight_mode: Current in-flight mode (none, planning, implementing, etc.)
95
- plan_path: Path to active plan file (if any)
96
- handoff_path: Path to latest handoff (if any)
97
- transcript_path: Path to transcript file (if available)
98
-
99
- Returns:
100
- True if saved successfully
101
- """
102
- auto_state_path = get_auto_state_path(context_id, project_root)
103
-
104
- # Ensure parent directory exists
105
- auto_state_path.parent.mkdir(parents=True, exist_ok=True)
106
-
107
- git_state = capture_git_state(project_root)
108
-
109
- state = {
110
- "version": AUTO_STATE_VERSION,
111
- "context_id": context_id,
112
- "session_id": session_id,
113
- "saved_at": now_iso(),
114
- "save_reason": save_reason,
115
- "in_flight_mode": in_flight_mode,
116
- "plan_path": plan_path,
117
- "latest_handoff_path": handoff_path,
118
- "git_state": git_state,
119
- "transcript_path": transcript_path,
120
- }
121
-
122
- try:
123
- content = json.dumps(state, indent=2, ensure_ascii=False)
124
- success, error = atomic_write(auto_state_path, content)
125
- if success:
126
- eprint(f"[auto_state] Saved auto-state for {context_id} (reason: {save_reason})")
127
- return True
128
- else:
129
- eprint(f"[auto_state] Failed to save: {error}")
130
- return False
131
- except Exception as e:
132
- eprint(f"[auto_state] Error saving auto-state: {e}")
133
- return False
134
-
135
-
136
- def load_auto_state(context_id: str, project_root: Path = None) -> Optional[Dict[str, Any]]:
137
- """
138
- Load auto-state.json for a context.
139
-
140
- Returns None if file doesn't exist or is corrupted.
141
- Graceful degradation — callers should handle None.
142
-
143
- Args:
144
- context_id: Context identifier
145
- project_root: Project root directory
146
-
147
- Returns:
148
- Auto-state dict or None
149
- """
150
- auto_state_path = get_auto_state_path(context_id, project_root)
151
-
152
- if not auto_state_path.exists():
153
- return None
154
-
155
- try:
156
- content = auto_state_path.read_text(encoding="utf-8")
157
- state = json.loads(content)
158
-
159
- # Version check
160
- if state.get("version") != AUTO_STATE_VERSION:
161
- eprint(f"[auto_state] Version mismatch: expected {AUTO_STATE_VERSION}, got {state.get('version')}")
162
- return None
163
-
164
- return state
165
- except (json.JSONDecodeError, UnicodeDecodeError, OSError) as e:
166
- eprint(f"[auto_state] Failed to load auto-state: {e}")
167
- return None