moai-adk 0.9.0__py3-none-any.whl → 0.9.1__py3-none-any.whl

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.

Potentially problematic release.


This version of moai-adk might be problematic. Click here for more details.

Files changed (30) hide show
  1. moai_adk/cli/commands/update.py +214 -56
  2. moai_adk/core/tags/pre_commit_validator.py +0 -1
  3. moai_adk/core/tags/reporter.py +1 -2
  4. moai_adk/templates/.claude/hooks/alfred/.moai/cache/version-check.json +9 -0
  5. moai_adk/templates/.claude/hooks/alfred/README.md +343 -0
  6. moai_adk/templates/.claude/hooks/alfred/TROUBLESHOOTING.md +471 -0
  7. moai_adk/templates/.claude/hooks/alfred/shared/core/project.py +10 -77
  8. moai_adk/templates/.claude/hooks/alfred/shared/handlers/user.py +19 -0
  9. moai_adk/templates/.github/workflows/tag-report.yml +261 -0
  10. moai_adk/templates/.github/workflows/tag-validation.yml +176 -0
  11. moai_adk/templates/.moai/docs/quick-issue-creation-guide.md +219 -0
  12. moai_adk/templates/.moai/hooks/install.sh +79 -0
  13. moai_adk/templates/.moai/hooks/pre-commit.sh +66 -0
  14. moai_adk/templates/.moai/memory/GITFLOW-PROTECTION-POLICY.md +220 -0
  15. moai_adk/templates/.moai/memory/gitflow-protection-policy.md +30 -140
  16. moai_adk/templates/.moai/memory/spec-metadata.md +356 -0
  17. moai_adk/templates/src/moai_adk/core/__init__.py +5 -0
  18. moai_adk/templates/src/moai_adk/core/tags/__init__.py +86 -0
  19. moai_adk/templates/src/moai_adk/core/tags/ci_validator.py +433 -0
  20. moai_adk/templates/src/moai_adk/core/tags/cli.py +283 -0
  21. moai_adk/templates/src/moai_adk/core/tags/pre_commit_validator.py +354 -0
  22. moai_adk/templates/src/moai_adk/core/tags/reporter.py +956 -0
  23. moai_adk/templates/src/moai_adk/core/tags/validator.py +897 -0
  24. {moai_adk-0.9.0.dist-info → moai_adk-0.9.1.dist-info}/METADATA +69 -333
  25. {moai_adk-0.9.0.dist-info → moai_adk-0.9.1.dist-info}/RECORD +28 -13
  26. moai_adk/templates/.claude/hooks/alfred/core/project.py +0 -750
  27. moai_adk/templates/README.md +0 -256
  28. {moai_adk-0.9.0.dist-info → moai_adk-0.9.1.dist-info}/WHEEL +0 -0
  29. {moai_adk-0.9.0.dist-info → moai_adk-0.9.1.dist-info}/entry_points.txt +0 -0
  30. {moai_adk-0.9.0.dist-info → moai_adk-0.9.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,471 @@
1
+ # Alfred Hooks Troubleshooting Guide
2
+
3
+ This guide helps you diagnose and resolve common issues with MoAI-ADK's Alfred hooks system.
4
+
5
+ ## Quick Diagnosis
6
+
7
+ Run this command to verify hook integrity:
8
+
9
+ ```bash
10
+ # Test hook execution
11
+ echo '{"cwd": "."}' | uv run .claude/hooks/alfred/alfred_hooks.py SessionStart
12
+ ```
13
+
14
+ **Expected output**: JSON with `"continue": true` and a system message
15
+ **If failed**: See error-specific sections below
16
+
17
+ ---
18
+
19
+ ## Error 1: "Hook not found"
20
+
21
+ ### Symptom
22
+ ```
23
+ error: Failed to spawn: `.claude/hooks/alfred/alfred_hooks.py`
24
+ Caused by: No such file or directory (os error 2)
25
+ ```
26
+
27
+ ### Root Causes
28
+ 1. **Project initialized with older MoAI-ADK version** (before hooks system)
29
+ 2. **Hooks directory deleted accidentally**
30
+ 3. **Template copy failed during `/alfred:0-project` initialization**
31
+ 4. **Working directory mismatch** (Claude Code started from wrong directory)
32
+
33
+ ### Solutions
34
+
35
+ #### Solution 1: Update Project (Recommended)
36
+ ```bash
37
+ # Re-run project initialization to restore hooks
38
+ /alfred:0-project
39
+ ```
40
+
41
+ #### Solution 2: Manual Template Copy
42
+ ```bash
43
+ # Copy hooks from MoAI-ADK installation
44
+ python3 -c "
45
+ import moai_adk
46
+ from pathlib import Path
47
+ import shutil
48
+
49
+ template_dir = Path(moai_adk.__file__).parent / 'templates' / '.claude' / 'hooks' / 'alfred'
50
+ target_dir = Path('.claude/hooks/alfred')
51
+ target_dir.parent.mkdir(parents=True, exist_ok=True)
52
+ shutil.copytree(template_dir, target_dir, dirs_exist_ok=True)
53
+ print(f'Copied hooks to {target_dir}')
54
+ "
55
+ ```
56
+
57
+ #### Solution 3: Verify File Existence
58
+ ```bash
59
+ # Check all required files exist
60
+ ls -la .claude/hooks/alfred/
61
+ ls -la .claude/hooks/alfred/handlers/
62
+ ls -la .claude/hooks/alfred/core/
63
+
64
+ # Expected files:
65
+ # .claude/hooks/alfred/alfred_hooks.py
66
+ # .claude/hooks/alfred/handlers/__init__.py
67
+ # .claude/hooks/alfred/handlers/session.py
68
+ # .claude/hooks/alfred/handlers/user.py
69
+ # .claude/hooks/alfred/handlers/tool.py
70
+ # .claude/hooks/alfred/handlers/notification.py
71
+ # .claude/hooks/alfred/core/__init__.py
72
+ # .claude/hooks/alfred/core/project.py
73
+ # .claude/hooks/alfred/core/context.py
74
+ # .claude/hooks/alfred/core/checkpoint.py
75
+ ```
76
+
77
+ ---
78
+
79
+ ## Error 2: "Import error: No module named 'handlers'"
80
+
81
+ ### Symptom
82
+ ```python
83
+ ImportError: No module named 'handlers'
84
+ ModuleNotFoundError: No module named 'core'
85
+ ```
86
+
87
+ ### Root Causes
88
+ 1. **Corrupted hooks directory** (partial copy, missing `__init__.py`)
89
+ 2. **Python path resolution issue** (sys.path manipulation failed)
90
+ 3. **Missing handler/core modules**
91
+
92
+ ### Solutions
93
+
94
+ #### Solution 1: Verify Module Structure
95
+ ```bash
96
+ # Check all __init__.py files exist
97
+ find .claude/hooks/alfred -name "__init__.py"
98
+
99
+ # Expected output:
100
+ # .claude/hooks/alfred/handlers/__init__.py
101
+ # .claude/hooks/alfred/core/__init__.py
102
+ ```
103
+
104
+ #### Solution 2: Test Imports Manually
105
+ ```bash
106
+ cd .claude/hooks/alfred && python3 -c "
107
+ import sys
108
+ from pathlib import Path
109
+ sys.path.insert(0, str(Path.cwd()))
110
+
111
+ from handlers import handle_session_start
112
+ from core import HookResult
113
+ print('✅ Imports successful')
114
+ "
115
+ ```
116
+
117
+ #### Solution 3: Re-initialize Hooks
118
+ ```bash
119
+ # Force re-copy from template
120
+ /alfred:0-project update --force
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Error 3: "Hook execution timeout"
126
+
127
+ ### Symptom
128
+ ```
129
+ Hook timeout after 5 seconds
130
+ ⚠️ Hook execution timeout - continuing without session info
131
+ ```
132
+
133
+ ### Root Causes
134
+ 1. **Slow Git operations** (large repository, many branches)
135
+ 2. **Slow file I/O** (network drive, slow disk)
136
+ 3. **Heavy SPEC counting** (many `.moai/specs/` directories)
137
+ 4. **Subprocess hang** (rare, usually indicates system issue)
138
+
139
+ ### Solutions
140
+
141
+ #### Solution 1: Identify Slow Operations
142
+ ```bash
143
+ # Time hook execution
144
+ time echo '{"cwd": "."}' | uv run .claude/hooks/alfred/alfred_hooks.py SessionStart
145
+
146
+ # If >5 seconds, check:
147
+ # - Git repository size: du -sh .git
148
+ # - SPEC count: find .moai/specs -type d -name "SPEC-*" | wc -l
149
+ # - Disk I/O: iotop (Linux) or sudo fs_usage (macOS)
150
+ ```
151
+
152
+ #### Solution 2: Increase Timeout (Temporary Workaround)
153
+ ```bash
154
+ # Edit alfred_hooks.py line 129
155
+ # Change: signal.alarm(5) # 5 seconds
156
+ # To: signal.alarm(10) # 10 seconds
157
+
158
+ # Location: .claude/hooks/alfred/alfred_hooks.py
159
+ ```
160
+
161
+ **Note**: This is a workaround. File an issue if hooks consistently timeout.
162
+
163
+ #### Solution 3: Disable Slow Features (Not Currently Supported)
164
+ **Future enhancement**: Add `.moai/config.json` option to disable expensive checks:
165
+ ```json
166
+ {
167
+ "hooks": {
168
+ "session_start": {
169
+ "skip_git_info": false,
170
+ "skip_spec_count": false
171
+ }
172
+ }
173
+ }
174
+ ```
175
+
176
+ ---
177
+
178
+ ## Error 4: "JSON parse error"
179
+
180
+ ### Symptom
181
+ ```
182
+ JSON parse error: Expecting value: line 1 column 1 (char 0)
183
+ ```
184
+
185
+ ### Root Causes
186
+ 1. **Empty stdin** (Claude Code passed no payload)
187
+ 2. **Invalid JSON format** (malformed payload)
188
+ 3. **Encoding issues** (non-UTF-8 characters)
189
+
190
+ ### Solutions
191
+
192
+ #### Solution 1: Test with Minimal Payload
193
+ ```bash
194
+ # Empty payload (should work - returns empty dict)
195
+ echo '' | uv run .claude/hooks/alfred/alfred_hooks.py SessionStart
196
+
197
+ # Minimal valid payload
198
+ echo '{"cwd": "."}' | uv run .claude/hooks/alfred/alfred_hooks.py SessionStart
199
+ ```
200
+
201
+ #### Solution 2: Check Claude Code Version
202
+ ```bash
203
+ # Ensure Claude Code is up-to-date
204
+ claude-code --version
205
+
206
+ # Update if needed
207
+ pip install --upgrade claude-code
208
+ ```
209
+
210
+ ---
211
+
212
+ ## Error 5: "Permission denied"
213
+
214
+ ### Symptom
215
+ ```
216
+ PermissionError: [Errno 13] Permission denied: '.claude/hooks/alfred/alfred_hooks.py'
217
+ ```
218
+
219
+ ### Root Causes
220
+ 1. **File not executable** (missing execute permission)
221
+ 2. **Directory permissions** (parent directory not readable)
222
+ 3. **Ownership issues** (file owned by different user)
223
+
224
+ ### Solutions
225
+
226
+ #### Solution 1: Fix Permissions
227
+ ```bash
228
+ # Make executable
229
+ chmod +x .claude/hooks/alfred/alfred_hooks.py
230
+
231
+ # Fix directory permissions
232
+ chmod -R u+rX .claude/hooks/alfred/
233
+ ```
234
+
235
+ #### Solution 2: Check Ownership
236
+ ```bash
237
+ # Check file owner
238
+ ls -l .claude/hooks/alfred/alfred_hooks.py
239
+
240
+ # Change owner if needed (replace USER with your username)
241
+ sudo chown -R USER:USER .claude/hooks/alfred/
242
+ ```
243
+
244
+ ---
245
+
246
+ ## Error 6: "UV environment issues"
247
+
248
+ ### Symptom
249
+ ```
250
+ uv: command not found
251
+ error: failed to create virtualenv
252
+ ```
253
+
254
+ ### Root Causes
255
+ 1. **UV not installed**
256
+ 2. **UV not in PATH**
257
+ 3. **Virtual environment corruption**
258
+
259
+ ### Solutions
260
+
261
+ #### Solution 1: Install/Update UV
262
+ ```bash
263
+ # Install UV
264
+ pip install uv
265
+
266
+ # Or update
267
+ pip install --upgrade uv
268
+
269
+ # Verify
270
+ uv --version
271
+ ```
272
+
273
+ #### Solution 2: Check PATH
274
+ ```bash
275
+ # Find UV installation
276
+ which uv
277
+
278
+ # Add to PATH if needed
279
+ export PATH="$HOME/.local/bin:$PATH"
280
+ ```
281
+
282
+ #### Solution 3: Rebuild Virtual Environment
283
+ ```bash
284
+ # Remove existing environment
285
+ rm -rf .venv
286
+
287
+ # Recreate
288
+ uv venv
289
+ uv sync
290
+ ```
291
+
292
+ ---
293
+
294
+ ## Platform-Specific Issues
295
+
296
+ ### macOS: SIGALRM Not Working
297
+ **Note**: SIGALRM is fully supported on macOS. If timeout protection isn't working:
298
+
299
+ ```bash
300
+ # Verify Python version (3.8+ required)
301
+ python3 --version
302
+
303
+ # Test signal module
304
+ python3 -c "import signal; print(hasattr(signal, 'SIGALRM'))"
305
+ # Expected: True
306
+ ```
307
+
308
+ ### Windows: SIGALRM Not Available
309
+ **Known Limitation**: SIGALRM is not available on Windows.
310
+
311
+ **Workaround**: Hooks must complete in <2 seconds (no timeout protection).
312
+
313
+ **Alternative**: Use threading-based timeout (future enhancement):
314
+ ```python
315
+ import threading
316
+
317
+ def run_with_timeout(func, timeout=5):
318
+ result = []
319
+ def wrapper():
320
+ result.append(func())
321
+
322
+ thread = threading.Thread(target=wrapper)
323
+ thread.start()
324
+ thread.join(timeout)
325
+
326
+ if thread.is_alive():
327
+ raise TimeoutError("Function timeout")
328
+ return result[0]
329
+ ```
330
+
331
+ ### Linux: Signal Conflicts
332
+ If other tools use SIGALRM (rare), hooks may conflict.
333
+
334
+ **Diagnosis**:
335
+ ```bash
336
+ # Check for signal handlers
337
+ python3 -c "
338
+ import signal
339
+ print('Current SIGALRM handler:', signal.getsignal(signal.SIGALRM))
340
+ "
341
+ ```
342
+
343
+ ---
344
+
345
+ ## Advanced Debugging
346
+
347
+ ### Enable Hook Logging
348
+ ```bash
349
+ # Create custom hook wrapper with logging
350
+ cat > .claude/hooks/alfred/debug_hooks.sh <<'EOF'
351
+ #!/bin/bash
352
+ EVENT=$1
353
+ INPUT=$(cat)
354
+
355
+ echo "[$(date)] Event: $EVENT" >> /tmp/alfred_hooks.log
356
+ echo "[$(date)] Input: $INPUT" >> /tmp/alfred_hooks.log
357
+
358
+ OUTPUT=$(echo "$INPUT" | uv run .claude/hooks/alfred/alfred_hooks.py "$EVENT" 2>&1)
359
+ EXIT_CODE=$?
360
+
361
+ echo "[$(date)] Output: $OUTPUT" >> /tmp/alfred_hooks.log
362
+ echo "[$(date)] Exit: $EXIT_CODE" >> /tmp/alfred_hooks.log
363
+
364
+ echo "$OUTPUT"
365
+ exit $EXIT_CODE
366
+ EOF
367
+
368
+ chmod +x .claude/hooks/alfred/debug_hooks.sh
369
+
370
+ # Update settings.json to use debug wrapper
371
+ # "command": "uv run \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/alfred/debug_hooks.sh SessionStart"
372
+ ```
373
+
374
+ ### Monitor Hook Performance
375
+ ```bash
376
+ # Benchmark all hook events
377
+ for event in SessionStart UserPromptSubmit PreToolUse PostToolUse SessionEnd; do
378
+ echo "Testing $event..."
379
+ time echo '{"cwd": "."}' | uv run .claude/hooks/alfred/alfred_hooks.py $event > /dev/null
380
+ done
381
+ ```
382
+
383
+ ### Validate Hook Output Schema
384
+ ```bash
385
+ # Test output format
386
+ OUTPUT=$(echo '{"cwd": "."}' | uv run .claude/hooks/alfred/alfred_hooks.py SessionStart)
387
+
388
+ # Check required fields
389
+ echo "$OUTPUT" | python3 -c "
390
+ import json, sys
391
+ data = json.load(sys.stdin)
392
+ assert 'continue' in data, 'Missing continue field'
393
+ assert isinstance(data['continue'], bool), 'continue must be boolean'
394
+ print('✅ Valid hook output schema')
395
+ "
396
+ ```
397
+
398
+ ---
399
+
400
+ ## Getting Help
401
+
402
+ ### Collect Diagnostic Information
403
+ ```bash
404
+ # Create diagnostic report
405
+ cat > /tmp/hooks_diagnostic.txt <<EOF
406
+ === MoAI-ADK Hooks Diagnostic Report ===
407
+ Date: $(date)
408
+
409
+ === Environment ===
410
+ OS: $(uname -s)
411
+ Python: $(python3 --version)
412
+ UV: $(uv --version 2>&1)
413
+ Claude Code: $(claude-code --version 2>&1)
414
+
415
+ === File Structure ===
416
+ $(find .claude/hooks/alfred -type f 2>&1)
417
+
418
+ === Permissions ===
419
+ $(ls -la .claude/hooks/alfred/ 2>&1)
420
+
421
+ === Hook Test ===
422
+ $(echo '{"cwd": "."}' | uv run .claude/hooks/alfred/alfred_hooks.py SessionStart 2>&1)
423
+
424
+ === Settings ===
425
+ $(cat .claude/settings.json 2>&1 | grep -A 10 "SessionStart")
426
+ EOF
427
+
428
+ cat /tmp/hooks_diagnostic.txt
429
+ ```
430
+
431
+ ### Report Issues
432
+ 1. **GitHub Issues**: https://github.com/modu-ai/moai-adk/issues
433
+ 2. **Include**: Diagnostic report (above) + error message + steps to reproduce
434
+ 3. **Security**: Do NOT include secrets, API keys, or sensitive paths
435
+
436
+ ---
437
+
438
+ ## Preventive Maintenance
439
+
440
+ ### Regular Health Checks
441
+ ```bash
442
+ # Add to .git/hooks/post-merge
443
+ cat > .git/hooks/post-merge <<'EOF'
444
+ #!/bin/bash
445
+ # Verify hooks after pulling updates
446
+ echo '{"cwd": "."}' | uv run .claude/hooks/alfred/alfred_hooks.py SessionStart > /dev/null 2>&1
447
+ if [ $? -ne 0 ]; then
448
+ echo "⚠️ Alfred hooks failed - run /alfred:0-project update"
449
+ fi
450
+ EOF
451
+
452
+ chmod +x .git/hooks/post-merge
453
+ ```
454
+
455
+ ### Keep MoAI-ADK Updated
456
+ ```bash
457
+ # Check version
458
+ python3 -c "import moai_adk; print(moai_adk.__version__)"
459
+
460
+ # Update
461
+ pip install --upgrade moai-adk
462
+
463
+ # Re-initialize project
464
+ /alfred:0-project update
465
+ ```
466
+
467
+ ---
468
+
469
+ **Last Updated**: 2025-10-29
470
+ **Applies To**: MoAI-ADK v0.7.0+
471
+ **Hooks Architecture Version**: Hybrid Modular (9 modules)
@@ -16,58 +16,6 @@ from typing import Any
16
16
  CACHE_DIR_NAME = ".moai/cache"
17
17
 
18
18
 
19
- def find_project_root(start_path: str | Path = ".") -> Path:
20
- """Find MoAI-ADK project root by searching upward for .moai/config.json
21
-
22
- Traverses up the directory tree until it finds .moai/config.json or CLAUDE.md,
23
- which indicates the project root. This ensures cache and other files are
24
- always created in the correct location, regardless of where hooks execute.
25
-
26
- Args:
27
- start_path: Starting directory (default: current directory)
28
-
29
- Returns:
30
- Project root Path. If not found, returns start_path as absolute path.
31
-
32
- Examples:
33
- >>> find_project_root(".")
34
- Path("/Users/user/my-project")
35
- >>> find_project_root(".claude/hooks/alfred")
36
- Path("/Users/user/my-project") # Found root 3 levels up
37
-
38
- Notes:
39
- - Searches for .moai/config.json first (most reliable)
40
- - Falls back to CLAUDE.md if config.json not found
41
- - Max depth: 10 levels up (prevent infinite loop)
42
- - Returns absolute path for consistency
43
-
44
- TDD History:
45
- - RED: 4 test scenarios (root, nested, not found, symlinks)
46
- - GREEN: Minimal upward search with .moai/config.json detection
47
- - REFACTOR: Add CLAUDE.md fallback, max depth limit, absolute path return
48
- """
49
- current = Path(start_path).resolve()
50
- max_depth = 10 # Prevent infinite loop
51
-
52
- for _ in range(max_depth):
53
- # Check for .moai/config.json (primary indicator)
54
- if (current / ".moai" / "config.json").exists():
55
- return current
56
-
57
- # Check for CLAUDE.md (secondary indicator)
58
- if (current / "CLAUDE.md").exists():
59
- return current
60
-
61
- # Move up one level
62
- parent = current.parent
63
- if parent == current: # Reached filesystem root
64
- break
65
- current = parent
66
-
67
- # Not found - return start_path as absolute
68
- return Path(start_path).resolve()
69
-
70
-
71
19
  class TimeoutError(Exception):
72
20
  """Signal-based timeout exception"""
73
21
  pass
@@ -298,7 +246,7 @@ def count_specs(cwd: str) -> dict[str, int]:
298
246
  Counts the number of SPECs with status: completed.
299
247
 
300
248
  Args:
301
- cwd: Project root directory path (or any subdirectory, will search upward)
249
+ cwd: Project root directory path
302
250
 
303
251
  Returns:
304
252
  SPEC progress dictionary. Includes the following keys:
@@ -316,19 +264,15 @@ def count_specs(cwd: str) -> dict[str, int]:
316
264
 
317
265
  Notes:
318
266
  - SPEC File Location: .moai/specs/SPEC-{ID}/spec.md
319
- - Completion condition: Include "status: completed" in YAML front matter
267
+ - Completion condition: Include status: completed in YAML front matter
320
268
  - If parsing fails, the SPEC is considered incomplete.
321
- - Automatically finds project root to locate .moai/specs/
322
269
 
323
270
  TDD History:
324
271
  - RED: 5 items scenario test (0/0, 2/5, 5/5, no directory, parsing error)
325
272
  - GREEN: SPEC search with Path.iterdir(), YAML parsing implementation
326
273
  - REFACTOR: Strengthened exception handling, improved percentage calculation safety
327
- - UPDATE: Add project root detection for consistent path resolution
328
274
  """
329
- # Find project root to ensure we read specs from correct location
330
- project_root = find_project_root(cwd)
331
- specs_dir = project_root / ".moai" / "specs"
275
+ specs_dir = Path(cwd) / ".moai" / "specs"
332
276
 
333
277
  if not specs_dir.exists():
334
278
  return {"completed": 0, "total": 0, "percentage": 0}
@@ -372,7 +316,7 @@ def get_project_language(cwd: str) -> str:
372
316
  """Determine the primary project language (prefers config.json).
373
317
 
374
318
  Args:
375
- cwd: Project root directory (or any subdirectory, will search upward).
319
+ cwd: Project root directory.
376
320
 
377
321
  Returns:
378
322
  Language string in lower-case.
@@ -380,11 +324,8 @@ def get_project_language(cwd: str) -> str:
380
324
  Notes:
381
325
  - Reads ``.moai/config.json`` first for a quick answer.
382
326
  - Falls back to ``detect_language`` if configuration is missing.
383
- - Automatically finds project root to locate .moai/config.json
384
327
  """
385
- # Find project root to ensure we read config from correct location
386
- project_root = find_project_root(cwd)
387
- config_path = project_root / ".moai" / "config.json"
328
+ config_path = Path(cwd) / ".moai" / "config.json"
388
329
  if config_path.exists():
389
330
  try:
390
331
  config = json.loads(config_path.read_text())
@@ -395,8 +336,8 @@ def get_project_language(cwd: str) -> str:
395
336
  # Fall back to detection on parse errors
396
337
  pass
397
338
 
398
- # Fall back to the original language detection routine (use project root)
399
- return detect_language(str(project_root))
339
+ # Fall back to the original language detection routine
340
+ return detect_language(cwd)
400
341
 
401
342
 
402
343
  # @CODE:CONFIG-INTEGRATION-001
@@ -441,9 +382,7 @@ def get_version_check_config(cwd: str) -> dict[str, Any]:
441
382
  "cache_ttl_hours": 24
442
383
  }
443
384
 
444
- # Find project root to ensure we read config from correct location
445
- project_root = find_project_root(cwd)
446
- config_path = project_root / ".moai" / "config.json"
385
+ config_path = Path(cwd) / ".moai" / "config.json"
447
386
  if not config_path.exists():
448
387
  return defaults
449
388
 
@@ -621,13 +560,8 @@ def get_package_version_info(cwd: str = ".") -> dict[str, Any]:
621
560
  # Graceful degradation: skip caching on import errors
622
561
  VersionCache = None
623
562
 
624
- # 1. Find project root (ensure cache is always in correct location)
625
- # This prevents creating .moai/cache in wrong locations when hooks run
626
- # from subdirectories like .claude/hooks/alfred/
627
- project_root = find_project_root(cwd)
628
-
629
- # 2. Initialize cache (skip if VersionCache couldn't be imported)
630
- cache_dir = project_root / CACHE_DIR_NAME
563
+ # 1. Initialize cache (skip if VersionCache couldn't be imported)
564
+ cache_dir = Path(cwd) / CACHE_DIR_NAME
631
565
  version_cache = VersionCache(cache_dir) if VersionCache else None
632
566
 
633
567
  # 2. Get current installed version first (needed for cache validation)
@@ -738,7 +672,6 @@ def get_package_version_info(cwd: str = ".") -> dict[str, Any]:
738
672
 
739
673
 
740
674
  __all__ = [
741
- "find_project_root",
742
675
  "detect_language",
743
676
  "get_git_info",
744
677
  "count_specs",
@@ -4,6 +4,9 @@
4
4
  Handling the UserPromptSubmit event
5
5
  """
6
6
 
7
+ from datetime import datetime
8
+ from pathlib import Path
9
+
7
10
  from core import HookPayload, HookResult
8
11
  from core.context import get_jit_context
9
12
 
@@ -29,11 +32,27 @@ def handle_user_prompt_submit(payload: HookPayload) -> HookResult:
29
32
  - GREEN: Recommend documents by calling get_jit_context()
30
33
  - REFACTOR: Message conditional display (only when there is a file)
31
34
  - UPDATE: Migrated to Claude Code standard Hook schema with snake_case fields
35
+ - FEATURE: Command execution logging for tracking double-run debugging
32
36
  """
33
37
  user_prompt = payload.get("userPrompt", "")
34
38
  cwd = payload.get("cwd", ".")
35
39
  context_files = get_jit_context(user_prompt, cwd)
36
40
 
41
+ # Command execution logging (DEBUG feature for tracking invocations)
42
+ if user_prompt.startswith("/alfred:"):
43
+ try:
44
+ log_dir = Path(cwd) / ".moai" / "logs"
45
+ log_dir.mkdir(parents=True, exist_ok=True)
46
+
47
+ log_file = log_dir / "command-invocations.log"
48
+ timestamp = datetime.now().isoformat()
49
+
50
+ with open(log_file, "a", encoding="utf-8") as f:
51
+ f.write(f"{timestamp} | {user_prompt}\n")
52
+ except Exception:
53
+ # Silently fail if logging fails (don't interrupt main flow)
54
+ pass
55
+
37
56
  system_message = f"📎 Loaded {len(context_files)} context file(s)" if context_files else None
38
57
 
39
58
  return HookResult(system_message=system_message, context_files=context_files)