aiwcli 0.10.3 → 0.11.1

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 (191) 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 +107 -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/git-state.ts +1 -1
  24. package/dist/templates/_shared/lib-ts/base/hook-utils.ts +129 -50
  25. package/dist/templates/_shared/lib-ts/base/inference.ts +28 -21
  26. package/dist/templates/_shared/lib-ts/base/logger.ts +15 -2
  27. package/dist/templates/_shared/lib-ts/base/state-io.ts +9 -7
  28. package/dist/templates/_shared/lib-ts/base/stop-words.ts +131 -131
  29. package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +142 -0
  30. package/dist/templates/_shared/lib-ts/base/utils.ts +69 -69
  31. package/dist/templates/_shared/lib-ts/context/context-formatter.ts +30 -24
  32. package/dist/templates/_shared/lib-ts/context/context-selector.ts +50 -32
  33. package/dist/templates/_shared/lib-ts/context/context-store.ts +76 -48
  34. package/dist/templates/_shared/lib-ts/context/plan-manager.ts +43 -23
  35. package/dist/templates/_shared/lib-ts/context/task-tracker.ts +10 -6
  36. package/dist/templates/_shared/lib-ts/handoff/document-generator.ts +11 -10
  37. package/dist/templates/_shared/lib-ts/handoff/handoff-reader.ts +158 -0
  38. package/dist/templates/_shared/lib-ts/templates/formatters.ts +6 -4
  39. package/dist/templates/_shared/lib-ts/types.ts +68 -55
  40. package/dist/templates/_shared/scripts/resolve_context.ts +24 -0
  41. package/dist/templates/_shared/scripts/resume_handoff.ts +345 -0
  42. package/dist/templates/_shared/scripts/save_handoff.ts +3 -3
  43. package/dist/templates/_shared/scripts/status_line.ts +687 -0
  44. package/dist/templates/cc-native/.claude/settings.json +175 -185
  45. package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +15 -17
  46. package/dist/templates/cc-native/_cc-native/agents/CLAUDE.md +0 -2
  47. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +109 -135
  48. package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.ts +119 -0
  49. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +1027 -0
  50. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +61 -0
  51. package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +156 -0
  52. package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +792 -0
  53. package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +199 -0
  54. package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +144 -0
  55. package/dist/templates/cc-native/_cc-native/lib-ts/config.ts +57 -0
  56. package/dist/templates/cc-native/_cc-native/lib-ts/constants.ts +83 -0
  57. package/dist/templates/cc-native/_cc-native/lib-ts/corroboration.ts +115 -0
  58. package/dist/templates/cc-native/_cc-native/lib-ts/debug.ts +80 -0
  59. package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +120 -0
  60. package/dist/templates/cc-native/_cc-native/lib-ts/json-parser.ts +168 -0
  61. package/dist/templates/cc-native/_cc-native/lib-ts/nul +3 -0
  62. package/dist/templates/cc-native/_cc-native/lib-ts/orchestrator.ts +250 -0
  63. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/agent.ts +275 -0
  64. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/codex.ts +130 -0
  65. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/gemini.ts +107 -0
  66. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/index.ts +10 -0
  67. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/types.ts +23 -0
  68. package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +240 -0
  69. package/dist/templates/cc-native/_cc-native/lib-ts/tsconfig.json +18 -0
  70. package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +385 -0
  71. package/dist/templates/cc-native/_cc-native/lib-ts/verdict.ts +72 -0
  72. package/dist/templates/cc-native/_cc-native/plan-review.config.json +14 -1
  73. package/oclif.manifest.json +1 -1
  74. package/package.json +2 -2
  75. package/dist/templates/_shared/hooks/__init__.py +0 -16
  76. package/dist/templates/_shared/hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  77. package/dist/templates/_shared/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
  78. package/dist/templates/_shared/hooks/__pycache__/context_enforcer.cpython-313.pyc +0 -0
  79. package/dist/templates/_shared/hooks/__pycache__/context_monitor.cpython-313.pyc +0 -0
  80. package/dist/templates/_shared/hooks/__pycache__/file-suggestion.cpython-313.pyc +0 -0
  81. package/dist/templates/_shared/hooks/__pycache__/pre_compact.cpython-313.pyc +0 -0
  82. package/dist/templates/_shared/hooks/__pycache__/session_end.cpython-313.pyc +0 -0
  83. package/dist/templates/_shared/hooks/__pycache__/session_start.cpython-313.pyc +0 -0
  84. package/dist/templates/_shared/hooks/__pycache__/task_create_atomicity.cpython-313.pyc +0 -0
  85. package/dist/templates/_shared/hooks/__pycache__/task_create_capture.cpython-313.pyc +0 -0
  86. package/dist/templates/_shared/hooks/__pycache__/task_update_capture.cpython-313.pyc +0 -0
  87. package/dist/templates/_shared/hooks/__pycache__/user_prompt_submit.cpython-313.pyc +0 -0
  88. package/dist/templates/_shared/hooks/archive_plan.py +0 -177
  89. package/dist/templates/_shared/hooks/context_monitor.py +0 -270
  90. package/dist/templates/_shared/hooks/file-suggestion.py +0 -215
  91. package/dist/templates/_shared/hooks/pre_compact.py +0 -104
  92. package/dist/templates/_shared/hooks/session_end.py +0 -173
  93. package/dist/templates/_shared/hooks/session_start.py +0 -206
  94. package/dist/templates/_shared/hooks/task_create_capture.py +0 -108
  95. package/dist/templates/_shared/hooks/task_update_capture.py +0 -145
  96. package/dist/templates/_shared/hooks/user_prompt_submit.py +0 -139
  97. package/dist/templates/_shared/lib/__init__.py +0 -1
  98. package/dist/templates/_shared/lib/__pycache__/__init__.cpython-313.pyc +0 -0
  99. package/dist/templates/_shared/lib/base/__init__.py +0 -65
  100. package/dist/templates/_shared/lib/base/__pycache__/__init__.cpython-313.pyc +0 -0
  101. package/dist/templates/_shared/lib/base/__pycache__/atomic_write.cpython-313.pyc +0 -0
  102. package/dist/templates/_shared/lib/base/__pycache__/constants.cpython-313.pyc +0 -0
  103. package/dist/templates/_shared/lib/base/__pycache__/hook_utils.cpython-313.pyc +0 -0
  104. package/dist/templates/_shared/lib/base/__pycache__/inference.cpython-313.pyc +0 -0
  105. package/dist/templates/_shared/lib/base/__pycache__/logger.cpython-313.pyc +0 -0
  106. package/dist/templates/_shared/lib/base/__pycache__/stop_words.cpython-313.pyc +0 -0
  107. package/dist/templates/_shared/lib/base/__pycache__/subprocess_utils.cpython-313.pyc +0 -0
  108. package/dist/templates/_shared/lib/base/__pycache__/utils.cpython-313.pyc +0 -0
  109. package/dist/templates/_shared/lib/base/atomic_write.py +0 -180
  110. package/dist/templates/_shared/lib/base/constants.py +0 -358
  111. package/dist/templates/_shared/lib/base/hook_utils.py +0 -339
  112. package/dist/templates/_shared/lib/base/inference.py +0 -307
  113. package/dist/templates/_shared/lib/base/logger.py +0 -305
  114. package/dist/templates/_shared/lib/base/stop_words.py +0 -221
  115. package/dist/templates/_shared/lib/base/subprocess_utils.py +0 -46
  116. package/dist/templates/_shared/lib/base/utils.py +0 -263
  117. package/dist/templates/_shared/lib/context/__init__.py +0 -102
  118. package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
  119. package/dist/templates/_shared/lib/context/__pycache__/cache.cpython-313.pyc +0 -0
  120. package/dist/templates/_shared/lib/context/__pycache__/context_extractor.cpython-313.pyc +0 -0
  121. package/dist/templates/_shared/lib/context/__pycache__/context_formatter.cpython-313.pyc +0 -0
  122. package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
  123. package/dist/templates/_shared/lib/context/__pycache__/context_selector.cpython-313.pyc +0 -0
  124. package/dist/templates/_shared/lib/context/__pycache__/context_store.cpython-313.pyc +0 -0
  125. package/dist/templates/_shared/lib/context/__pycache__/discovery.cpython-313.pyc +0 -0
  126. package/dist/templates/_shared/lib/context/__pycache__/event_log.cpython-313.pyc +0 -0
  127. package/dist/templates/_shared/lib/context/__pycache__/plan_archive.cpython-313.pyc +0 -0
  128. package/dist/templates/_shared/lib/context/__pycache__/plan_manager.cpython-313.pyc +0 -0
  129. package/dist/templates/_shared/lib/context/__pycache__/task_sync.cpython-313.pyc +0 -0
  130. package/dist/templates/_shared/lib/context/__pycache__/task_tracker.cpython-313.pyc +0 -0
  131. package/dist/templates/_shared/lib/context/context_formatter.py +0 -317
  132. package/dist/templates/_shared/lib/context/context_selector.py +0 -508
  133. package/dist/templates/_shared/lib/context/context_store.py +0 -653
  134. package/dist/templates/_shared/lib/context/plan_manager.py +0 -303
  135. package/dist/templates/_shared/lib/context/task_tracker.py +0 -188
  136. package/dist/templates/_shared/lib/handoff/__init__.py +0 -22
  137. package/dist/templates/_shared/lib/handoff/__pycache__/__init__.cpython-313.pyc +0 -0
  138. package/dist/templates/_shared/lib/handoff/__pycache__/document_generator.cpython-313.pyc +0 -0
  139. package/dist/templates/_shared/lib/handoff/document_generator.py +0 -278
  140. package/dist/templates/_shared/lib/templates/README.md +0 -206
  141. package/dist/templates/_shared/lib/templates/__init__.py +0 -36
  142. package/dist/templates/_shared/lib/templates/__pycache__/__init__.cpython-313.pyc +0 -0
  143. package/dist/templates/_shared/lib/templates/__pycache__/formatters.cpython-313.pyc +0 -0
  144. package/dist/templates/_shared/lib/templates/__pycache__/persona_questions.cpython-313.pyc +0 -0
  145. package/dist/templates/_shared/lib/templates/__pycache__/plan_context.cpython-313.pyc +0 -0
  146. package/dist/templates/_shared/lib/templates/formatters.py +0 -146
  147. package/dist/templates/_shared/lib/templates/plan_context.py +0 -73
  148. package/dist/templates/_shared/scripts/__pycache__/save_handoff.cpython-313.pyc +0 -0
  149. package/dist/templates/_shared/scripts/__pycache__/status_line.cpython-313.pyc +0 -0
  150. package/dist/templates/_shared/scripts/save_handoff.py +0 -357
  151. package/dist/templates/_shared/scripts/status_line.py +0 -716
  152. package/dist/templates/cc-native/.claude/commands/cc-native/fresh-perspective.md +0 -8
  153. package/dist/templates/cc-native/.windsurf/workflows/cc-native/fresh-perspective.md +0 -8
  154. package/dist/templates/cc-native/MIGRATION.md +0 -86
  155. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/add_plan_context.cpython-313.pyc +0 -0
  156. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
  157. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/mark_questions_asked.cpython-313.pyc +0 -0
  158. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_accepted.cpython-313.pyc +0 -0
  159. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_questions_early.cpython-313.pyc +0 -0
  160. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/suggest-fresh-perspective.cpython-313.pyc +0 -0
  161. package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.py +0 -130
  162. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +0 -954
  163. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.py +0 -81
  164. package/dist/templates/cc-native/_cc-native/hooks/suggest-fresh-perspective.py +0 -340
  165. package/dist/templates/cc-native/_cc-native/lib/CLAUDE.md +0 -265
  166. package/dist/templates/cc-native/_cc-native/lib/__init__.py +0 -53
  167. package/dist/templates/cc-native/_cc-native/lib/__pycache__/__init__.cpython-313.pyc +0 -0
  168. package/dist/templates/cc-native/_cc-native/lib/__pycache__/atomic_write.cpython-313.pyc +0 -0
  169. package/dist/templates/cc-native/_cc-native/lib/__pycache__/constants.cpython-313.pyc +0 -0
  170. package/dist/templates/cc-native/_cc-native/lib/__pycache__/debug.cpython-313.pyc +0 -0
  171. package/dist/templates/cc-native/_cc-native/lib/__pycache__/orchestrator.cpython-313.pyc +0 -0
  172. package/dist/templates/cc-native/_cc-native/lib/__pycache__/state.cpython-313.pyc +0 -0
  173. package/dist/templates/cc-native/_cc-native/lib/__pycache__/utils.cpython-313.pyc +0 -0
  174. package/dist/templates/cc-native/_cc-native/lib/constants.py +0 -45
  175. package/dist/templates/cc-native/_cc-native/lib/debug.py +0 -139
  176. package/dist/templates/cc-native/_cc-native/lib/orchestrator.py +0 -362
  177. package/dist/templates/cc-native/_cc-native/lib/reviewers/__init__.py +0 -28
  178. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/__init__.cpython-313.pyc +0 -0
  179. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
  180. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/base.cpython-313.pyc +0 -0
  181. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/codex.cpython-313.pyc +0 -0
  182. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/gemini.cpython-313.pyc +0 -0
  183. package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +0 -215
  184. package/dist/templates/cc-native/_cc-native/lib/reviewers/base.py +0 -88
  185. package/dist/templates/cc-native/_cc-native/lib/reviewers/codex.py +0 -124
  186. package/dist/templates/cc-native/_cc-native/lib/reviewers/gemini.py +0 -108
  187. package/dist/templates/cc-native/_cc-native/lib/state.py +0 -268
  188. package/dist/templates/cc-native/_cc-native/lib/utils.py +0 -1071
  189. package/dist/templates/cc-native/_cc-native/scripts/__pycache__/aggregate_agents.cpython-313.pyc +0 -0
  190. package/dist/templates/cc-native/_cc-native/scripts/aggregate_agents.py +0 -168
  191. package/dist/templates/cc-native/_cc-native/workflows/fresh-perspective.md +0 -134
@@ -1,305 +0,0 @@
1
- """Unified logging for all hooks and libraries.
2
-
3
- Provides a single logging interface that replaces:
4
- - log_hook_error() from hook_utils.py (error-only, plain text)
5
- - debug.py from cc-native (per-context, plain text)
6
- - eprint() for diagnostic output (stderr-only, no persistence)
7
-
8
- Log format: JSONL (one JSON object per line)
9
- Log location: _output/hook-log.jsonl (global, all sessions)
10
- Filter by session using the "sid" field.
11
-
12
- Environment variables:
13
- - HOOK_LOG_DISABLE=1: Disable all file logging
14
- - HOOK_LOG_LEVEL=warn: Minimum level to log (default: debug)
15
- - HOOK_ERROR_LOG_DISABLE=1: Legacy alias for HOOK_LOG_DISABLE
16
-
17
- Never raises — all errors silently swallowed.
18
- No buffering — each call is one open+write+close.
19
- Stdlib only — json, os, sys, datetime, pathlib.
20
- """
21
-
22
- import json
23
- import os
24
- import sys
25
- from datetime import datetime, timezone
26
- from pathlib import Path
27
- from typing import Any, Dict, Optional
28
-
29
- _LEVELS = {"debug": 0, "info": 1, "warn": 2, "error": 3}
30
-
31
- _MAX_LOG_LINES = 10_000 # Max lines in global log before pruning
32
-
33
- # Module-level context path cache.
34
- # Set once per hook process via set_context_path() or auto-resolved on first use.
35
- _cached_context_path: Optional[Path] = None
36
- _context_resolved: bool = False
37
-
38
- # Module-level session ID cache.
39
- # Set once per hook process via set_session_id().
40
- _cached_session_id: Optional[str] = None
41
-
42
-
43
- def set_session_id(session_id: Optional[str]) -> None:
44
- """Set the session ID for this process. All subsequent log calls include it.
45
-
46
- Args:
47
- session_id: Claude Code session ID (e.g., "a1b2c3d4")
48
- or None to clear.
49
- """
50
- global _cached_session_id
51
- _cached_session_id = session_id
52
-
53
-
54
- def set_context_path(path: Optional[Path]) -> None:
55
- """Set the context path for this process. All subsequent log calls use it.
56
-
57
- Call this once in your hook after resolving the context:
58
- from lib.base.logger import set_context_path
59
- set_context_path(get_context_dir(context_id, project_root))
60
-
61
- Args:
62
- path: Path to context folder (e.g., _output/contexts/<context-id>/)
63
- or None to force global-only logging.
64
- """
65
- global _cached_context_path, _context_resolved
66
- _cached_context_path = path
67
- _context_resolved = True
68
-
69
-
70
- def _auto_resolve_context_path() -> Optional[Path]:
71
- """Try to auto-resolve context path from session_id. Called once per process.
72
-
73
- Uses the context store to look up which context owns this session,
74
- then returns its directory path. Falls back to None (global log).
75
- """
76
- global _cached_context_path, _context_resolved
77
- _context_resolved = True # Don't retry on failure
78
-
79
- try:
80
- from ..context.context_store import get_context_by_session_id
81
- from .constants import get_context_dir
82
-
83
- # Hook input isn't available here, but we can check if a recent
84
- # context dir exists by scanning _output/contexts/ for one that
85
- # has a state.json with a matching session
86
- # This is too expensive for a logger. Instead, rely on set_context_path().
87
- except Exception:
88
- pass
89
-
90
- return None
91
-
92
-
93
- def _get_context_path() -> Optional[Path]:
94
- """Get the cached context path, auto-resolving on first call."""
95
- global _context_resolved
96
- if not _context_resolved:
97
- _auto_resolve_context_path()
98
- return _cached_context_path
99
-
100
-
101
- def _get_min_level() -> int:
102
- """Get minimum log level from environment."""
103
- env = os.environ.get("HOOK_LOG_LEVEL", "debug").lower()
104
- return _LEVELS.get(env, 0)
105
-
106
-
107
- def _is_disabled() -> bool:
108
- """Check if file logging is disabled."""
109
- if os.environ.get("HOOK_LOG_DISABLE") == "1":
110
- return True
111
- if os.environ.get("HOOK_ERROR_LOG_DISABLE") == "1":
112
- return True
113
- return False
114
-
115
-
116
- def _get_project_root() -> Path:
117
- """Get project root from environment or cwd."""
118
- env_dir = os.environ.get("CLAUDE_PROJECT_DIR", "")
119
- return Path(env_dir) if env_dir else Path.cwd()
120
-
121
-
122
- def hook_log(
123
- level: str,
124
- hook_name: str,
125
- message: str,
126
- *,
127
- component: str = "",
128
- data: Any = None,
129
- traceback_str: str = "",
130
- stderr: bool = True,
131
- ) -> None:
132
- """Write a structured log entry to the global hook log.
133
-
134
- All entries go to _output/hook-log.jsonl. Use the "sid" field
135
- (set via set_session_id) to filter by session.
136
-
137
- Args:
138
- level: "debug" | "info" | "warn" | "error"
139
- hook_name: Hook or module name (e.g., "session_end")
140
- message: Log message
141
- component: Sub-component (e.g., "git", "parse")
142
- data: Optional structured data (must be JSON-serializable)
143
- traceback_str: Optional traceback string
144
- stderr: Also write to stderr (default: True)
145
- """
146
- try:
147
- level_lower = level.lower()
148
- level_num = _LEVELS.get(level_lower, 0)
149
-
150
- # Write to stderr if requested
151
- if stderr:
152
- prefix = f"[{hook_name}]"
153
- if component:
154
- prefix = f"[{hook_name}:{component}]"
155
- print(f"{prefix} {message}", file=sys.stderr)
156
- if traceback_str:
157
- print(traceback_str, file=sys.stderr)
158
-
159
- # Check if file logging is enabled
160
- if _is_disabled():
161
- return
162
-
163
- # Check minimum level
164
- if level_num < _get_min_level():
165
- return
166
-
167
- # Build JSONL entry
168
- ts = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3]
169
- entry: Dict[str, Any] = {
170
- "ts": ts,
171
- "level": level_lower,
172
- "hook": hook_name,
173
- "msg": message,
174
- }
175
- if _cached_session_id:
176
- entry["sid"] = _cached_session_id
177
- if component:
178
- entry["component"] = component
179
- if data is not None:
180
- try:
181
- json.dumps(data, default=str) # Validate serializable
182
- entry["data"] = data
183
- except (TypeError, ValueError):
184
- entry["data"] = str(data)
185
- if traceback_str:
186
- entry["tb"] = traceback_str.rstrip()
187
-
188
- line = json.dumps(entry, ensure_ascii=True, default=str) + "\n"
189
-
190
- # Always write to global log
191
- project_root = _get_project_root()
192
- log_path = project_root / "_output" / "hook-log.jsonl"
193
-
194
- log_path.parent.mkdir(parents=True, exist_ok=True)
195
-
196
- # Line-count guard: prune to last _MAX_LOG_LINES
197
- if log_path.exists():
198
- try:
199
- with open(log_path, "r", encoding="utf-8", errors="replace") as f:
200
- existing = f.readlines()
201
- if len(existing) > _MAX_LOG_LINES:
202
- with open(log_path, "w", encoding="utf-8") as f:
203
- f.writelines(existing[-_MAX_LOG_LINES:])
204
- except OSError:
205
- pass
206
-
207
- with open(log_path, "a", encoding="utf-8") as f:
208
- f.write(line)
209
-
210
- except Exception:
211
- pass # Never crash
212
-
213
-
214
- def log_debug(hook_name: str, message: str, **kwargs: Any) -> None:
215
- """Log a debug-level message."""
216
- hook_log("debug", hook_name, message, **kwargs)
217
-
218
-
219
- def log_info(hook_name: str, message: str, **kwargs: Any) -> None:
220
- """Log an info-level message."""
221
- hook_log("info", hook_name, message, **kwargs)
222
-
223
-
224
- def log_warn(hook_name: str, message: str, **kwargs: Any) -> None:
225
- """Log a warn-level message."""
226
- hook_log("warn", hook_name, message, **kwargs)
227
-
228
-
229
- def log_error(hook_name: str, message: str, **kwargs: Any) -> None:
230
- """Log an error-level message."""
231
- hook_log("error", hook_name, message, **kwargs)
232
-
233
-
234
- def log_diagnostic(
235
- hook_name: str,
236
- phase: str,
237
- summary: str,
238
- *,
239
- inputs: Any = None,
240
- decision: Any = None,
241
- reasoning: Any = None,
242
- component: str = "diag",
243
- data: Any = None,
244
- ) -> None:
245
- """Log a structured diagnostic entry at a hook decision point.
246
-
247
- Emits a debug-level JSONL entry with tagged, filterable data.
248
- Use at key decision points: receive (what came in), decide (what was chosen),
249
- result (what happened).
250
-
251
- Args:
252
- hook_name: Hook or module name (e.g., "session_start")
253
- phase: Decision phase — "receive", "decide", or "result"
254
- summary: One-line description (e.g., "source=clear, session=a1b2c3d4")
255
- inputs: Input data relevant to this phase
256
- decision: The decision made (for "decide" phase)
257
- reasoning: Why this decision was made
258
- component: Log component tag (default: "diag")
259
- data: Extra data to merge into the structured entry
260
- """
261
- diag_data: Dict[str, Any] = {"phase": phase}
262
- if inputs is not None:
263
- diag_data["inputs"] = inputs
264
- if decision is not None:
265
- diag_data["decision"] = decision
266
- if reasoning is not None:
267
- diag_data["reasoning"] = reasoning
268
- if data is not None and isinstance(data, dict):
269
- diag_data.update(data)
270
- hook_log(
271
- "debug",
272
- hook_name,
273
- f"[DIAG:{phase}] {summary}",
274
- component=component,
275
- data=diag_data,
276
- )
277
-
278
-
279
- def log_hook_error(
280
- hook_name: str,
281
- error: Exception,
282
- hook_event: str = "unknown",
283
- traceback_str: str = "",
284
- ) -> None:
285
- """Backward-compatible wrapper matching the old hook_utils.log_hook_error signature.
286
-
287
- Delegates to hook_log("error", ...) with the same behavior:
288
- - Message capped at 200 chars, newlines stripped
289
- - Never raises
290
-
291
- Args:
292
- hook_name: Name of the hook
293
- error: The exception that occurred
294
- hook_event: Hook event type (e.g., "PreToolUse")
295
- traceback_str: Optional formatted traceback
296
- """
297
- msg = str(error).replace("\n", " ").replace("\r", "")[:200]
298
- err_type = type(error).__name__
299
- hook_log(
300
- "error",
301
- hook_name,
302
- f"[{hook_event}] {err_type}: {msg}",
303
- traceback_str=traceback_str,
304
- stderr=True,
305
- )
@@ -1,221 +0,0 @@
1
- """Stop words for context ID generation.
2
-
3
- Generated from analysis of 1,424 prompts, context summaries, and plan files.
4
- Words that appear frequently but don't help identify the specific task.
5
-
6
- Categories organized for maintainability. Add new corpus-derived words to
7
- the appropriate category or to "Corpus-derived additions" at the end.
8
-
9
- ACTION VERBS ARE INTENTIONALLY EXCLUDED from this list:
10
- add, fix, update, create, implement, refactor, migrate, debug, remove, change,
11
- move, rename, delete, build, test, deploy, verify, analyze, modify, write, run,
12
- check, replace, save, sync, load, extract, install, refactor, clean, merge, etc.
13
-
14
- These action verbs should REMAIN in context IDs as they identify the task type.
15
- """
16
-
17
- STOP_WORDS = {
18
- # ========================================================================
19
- # ARTICLES
20
- # ========================================================================
21
- 'a', 'an', 'the',
22
-
23
- # ========================================================================
24
- # PREPOSITIONS
25
- # ========================================================================
26
- 'to', 'for', 'in', 'on', 'at', 'by', 'with', 'from', 'of', 'about',
27
- 'into', 'over', 'under', 'between', 'through', 'during', 'before', 'after',
28
- 'above', 'below', 'against', 'among', 'around', 'behind', 'beside', 'besides',
29
- 'beyond', 'down', 'inside', 'outside', 'near', 'off', 'onto', 'out',
30
- 'since', 'toward', 'towards', 'until', 'upon', 'within', 'without',
31
- 'across', 'along', 'via', 'per',
32
-
33
- # ========================================================================
34
- # PRONOUNS
35
- # ========================================================================
36
- # Personal pronouns
37
- 'i', 'you', 'he', 'she', 'it', 'we', 'they',
38
- 'me', 'him', 'her', 'us', 'them',
39
- 'myself', 'yourself', 'himself', 'herself', 'itself', 'ourselves', 'themselves',
40
-
41
- # Possessive pronouns
42
- 'my', 'your', 'his', 'her', 'its', 'our', 'their',
43
- 'mine', 'yours', 'hers', 'ours', 'theirs',
44
-
45
- # Demonstrative pronouns
46
- 'this', 'that', 'these', 'those',
47
-
48
- # Relative pronouns
49
- 'who', 'whom', 'whose', 'which', 'that',
50
-
51
- # Indefinite pronouns
52
- 'someone', 'somebody', 'something', 'anyone', 'anybody', 'anything',
53
- 'everyone', 'everybody', 'everything', 'no one', 'nobody', 'nothing',
54
- 'one', 'ones',
55
-
56
- # ========================================================================
57
- # AUXILIARY/MODAL VERBS
58
- # ========================================================================
59
- 'am', 'is', 'are', 'was', 'were', 'be', 'been', 'being',
60
- 'have', 'has', 'had', 'having',
61
- 'do', 'does', 'did', 'doing', 'done',
62
- 'can', 'could', 'will', 'would', 'shall', 'should', 'may', 'might', 'must',
63
-
64
- # ========================================================================
65
- # CONJUNCTIONS
66
- # ========================================================================
67
- 'and', 'or', 'but', 'nor', 'so', 'yet', 'for',
68
- 'if', 'then', 'else', 'whether', 'unless', 'although', 'though',
69
- 'because', 'since', 'while', 'whereas', 'whenever', 'wherever',
70
-
71
- # ========================================================================
72
- # QUESTION WORDS
73
- # ========================================================================
74
- 'what', 'when', 'where', 'why', 'how',
75
-
76
- # ========================================================================
77
- # ADVERBS OF PLACE/TIME
78
- # ========================================================================
79
- 'here', 'there', 'now', 'then', 'always', 'never', 'often', 'sometimes',
80
- 'already', 'still', 'yet', 'soon', 'later', 'ago', 'today', 'tomorrow',
81
- 'yesterday', 'currently', 'previously', 'recently', 'immediately',
82
- 'finally', 'eventually', 'meanwhile', 'afterwards',
83
-
84
- # ========================================================================
85
- # NEGATION
86
- # ========================================================================
87
- 'no', 'not', 'none', 'never', 'neither', 'nor',
88
- 'don', 'doesn', 'didn', 'won', 'wouldn', 'couldn', 'shouldn',
89
- 'isn', 'aren', 'wasn', 'weren', 'hasn', 'haven', 'hadn',
90
-
91
- # ========================================================================
92
- # QUANTIFIERS
93
- # ========================================================================
94
- 'some', 'any', 'all', 'each', 'every', 'both', 'few', 'more', 'most',
95
- 'many', 'much', 'several', 'other', 'another', 'enough', 'less', 'least',
96
- 'either', 'neither', 'such',
97
-
98
- # ========================================================================
99
- # FILLER/HEDGE WORDS
100
- # ========================================================================
101
- 'just', 'also', 'only', 'really', 'actually', 'basically', 'simply',
102
- 'very', 'quite', 'rather', 'pretty', 'somewhat', 'almost', 'nearly',
103
- 'exactly', 'completely', 'entirely', 'totally', 'absolutely',
104
- 'probably', 'possibly', 'maybe', 'perhaps', 'definitely', 'certainly',
105
- 'apparently', 'obviously', 'clearly', 'literally', 'essentially',
106
-
107
- # ========================================================================
108
- # SPEECH-TO-TEXT FILLERS (STT artifacts from voice input)
109
- # ========================================================================
110
- 'um', 'uh', 'ah', 'oh', 'hmm', 'hm', 'er', 'eh', 'huh',
111
- 'hey', 'hi', 'hello', 'yeah', 'yep', 'yup', 'nah', 'nope',
112
- 'gonna', 'gotta', 'wanna', 'kinda', 'sorta',
113
- 'stuff', 'anyway', 'anyways', 'alright', 'right', 'well',
114
-
115
- # ========================================================================
116
- # COMMON REQUEST PHRASES (from corpus: high frequency in prompts)
117
- # ========================================================================
118
- 'want', 'need', 'help', 'please', 'like', 'let', 'get',
119
- 'think', 'know', 'see', 'try', 'make', 'give', 'take',
120
- 'look', 'looking', 'trying', 'going', 'getting', 'making',
121
-
122
- # ========================================================================
123
- # COMMON NON-ACTION VERBS
124
- # ========================================================================
125
- 'go', 'come', 'put', 'say', 'tell', 'ask', 'find', 'keep',
126
- 'seem', 'appear', 'become', 'remain', 'stay', 'feel', 'show', 'mean',
127
- 'include', 'provide', 'require', 'allow', 'expect', 'cause',
128
- 'follow', 'consider', 'continue', 'start', 'begin', 'end',
129
- 'contain', 'contain', 'contains',
130
-
131
- # ========================================================================
132
- # LINKING/TRANSITION WORDS
133
- # ========================================================================
134
- 'however', 'therefore', 'thus', 'hence', 'otherwise', 'instead',
135
- 'moreover', 'furthermore', 'nevertheless', 'nonetheless', 'accordingly',
136
- 'consequently', 'similarly', 'likewise', 'conversely', 'alternatively',
137
-
138
- # ========================================================================
139
- # CORPUS-DERIVED HIGH-FREQUENCY NOISE (from 1,424 docs analysis)
140
- # ========================================================================
141
- # Words appearing in >10% of documents that don't identify the task
142
-
143
- # File extensions/technical noise (appear in paths, not task descriptors)
144
- 'py', 'md', 'ts', 'json', 'js', 'yaml', 'toml', 'exe', 'bat',
145
-
146
- # Common Claude/coding terms that don't identify specific tasks
147
- 'using', 'used', 'uses',
148
- 'based', 'following',
149
- 'same', 'different', 'specific', 'existing', 'new', 'current', 'first',
150
- 'full', 'complete', 'single', 'multiple', 'simple',
151
- 'needed', 'required', 'provided', 'expected', 'correctly',
152
- 'works', 'working', 'work',
153
-
154
- # Common structural words from plan files
155
- 'step', 'steps', 'phase', 'below', 'above',
156
-
157
- # Query/clarification language (high frequency in prompts)
158
- 'questions', 'question', 'clarification',
159
-
160
- # Overly generic terms
161
- 'thing', 'things', 'way', 'ways', 'kind', 'type', 'types',
162
- 'example', 'examples', 'case', 'cases',
163
- 'part', 'parts', 'point', 'points',
164
- 'time', 'times', 'next', 'last', 'end',
165
- 'set', 'list', 'group', 'item', 'items',
166
-
167
- # ========================================================================
168
- # PROGRAMMING KEYWORDS (code tokens that leak from pasted code)
169
- # ========================================================================
170
- 'self', 'def', 'return', 'import', 'true', 'false', 'none', 'str',
171
- 'const', 'async', 'class', 'assert', 'except', 'dict', 'len', 'args',
172
- 'sys', 'eprint', 'elif', 'lambda', 'yield', 'pass',
173
-
174
- # ========================================================================
175
- # GENERIC ADJECTIVES (non-specific modifiers)
176
- # ========================================================================
177
- 'high', 'low', 'important', 'critical', 'optional', 'manual',
178
- 'real', 'empty', 'stable', 'active', 'proper', 'correct',
179
- 'basic', 'main', 'primary', 'secondary', 'general', 'overall',
180
-
181
- # ========================================================================
182
- # GENERIC TECHNICAL NOUNS (common but non-specific)
183
- # ========================================================================
184
- 'information', 'format', 'status', 'method', 'purpose', 'result',
185
- 'source', 'value', 'option', 'options', 'feature', 'features', 'issue',
186
- 'process', 'version', 'mode', 'state',
187
-
188
- # ========================================================================
189
- # DOCUMENT/CODE STRUCTURE (generic structural terms)
190
- # ========================================================================
191
- 'section', 'lines', 'line', 'folder', 'directory', 'index',
192
- 'level', 'block', 'chunk', 'region', 'header', 'footer',
193
-
194
- # ========================================================================
195
- # FRAGMENT WORDS (artifacts from contractions/tokenization)
196
- # ========================================================================
197
- 're', 'pl', 'aiw', 've', 'll', 'doesn', 't', 's',
198
-
199
- # ========================================================================
200
- # CORPUS-DERIVED SHORT NOISE (2026-02 analysis of 131 docs)
201
- # ========================================================================
202
- # Contractions with punctuation stripped (I'm -> im, etc.)
203
- 'im', 'ive', 'id', 'ill', 'youre', 'youve', 'youll',
204
- 'hes', 'shes', 'weve', 'theyre', 'theyve', 'dont', 'doesnt',
205
- 'didnt', 'wont', 'wouldnt', 'cant', 'couldnt', 'shouldnt', 'isnt',
206
- 'arent', 'wasnt', 'werent', 'hasnt', 'havent', 'hadnt', 'lets',
207
- 'thats', 'whats', 'heres', 'theres', 'whos',
208
-
209
- # Filler/noise from corpus (>10% frequency, non-action)
210
- 'etc', 'up', 'as', 'cc',
211
-
212
- # Number words (common in plans but don't identify task)
213
- 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten',
214
-
215
- # Single letters (artifacts from lists, paths, variables)
216
- 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
217
- 'q', 'r', 'u', 'v', 'w', 'x', 'y', 'z',
218
-
219
- # Short adverbs/fillers from review
220
- 'too', 'yes', 'ok', 'okay',
221
- }
@@ -1,46 +0,0 @@
1
- """Utilities for subprocess calls that invoke Claude Code CLI.
2
-
3
- Provides centralized management of environment flags for internal subprocess calls
4
- (orchestrator, agents, inference) to prevent recursion and unnecessary hook overhead.
5
- """
6
- import os
7
- from typing import Dict
8
-
9
- # Environment variable names - single source of truth
10
- ENV_INTERNAL_CALL = "AIWCLI_INTERNAL_CALL"
11
-
12
-
13
- def get_internal_subprocess_env() -> Dict[str, str]:
14
- """Get environment dict for internal Claude Code subprocess calls.
15
-
16
- This prevents internal subprocess calls (orchestrator, agents, inference)
17
- from triggering hooks that would cause recursion or unnecessary overhead.
18
-
19
- All hooks should check is_internal_call() and return early if True.
20
-
21
- Returns:
22
- Environment dict with AIWCLI_INTERNAL_CALL flag set
23
-
24
- Example:
25
- >>> env = get_internal_subprocess_env()
26
- >>> subprocess.run(['claude', '--agent', 'my-agent'], env=env)
27
- """
28
- env = os.environ.copy()
29
- env[ENV_INTERNAL_CALL] = 'true'
30
- return env
31
-
32
-
33
- def is_internal_call() -> bool:
34
- """Check if current process is an internal subprocess call.
35
-
36
- Hooks should check this at the beginning and return early to avoid
37
- recursion and unnecessary processing for internal subprocess calls.
38
-
39
- Returns:
40
- True if this is an internal call that should skip hooks
41
-
42
- Example:
43
- >>> if is_internal_call():
44
- ... return # Skip hook processing
45
- """
46
- return os.environ.get(ENV_INTERNAL_CALL) == 'true'