moai-adk 0.9.0__py3-none-any.whl → 0.15.0__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.
- moai_adk/cli/commands/init.py +14 -2
- moai_adk/cli/commands/update.py +214 -56
- moai_adk/core/issue_creator.py +2 -2
- moai_adk/core/project/detector.py +201 -12
- moai_adk/core/project/initializer.py +62 -1
- moai_adk/core/project/phase_executor.py +48 -6
- moai_adk/core/tags/ci_validator.py +34 -4
- moai_adk/core/tags/pre_commit_validator.py +40 -2
- moai_adk/core/tags/reporter.py +2 -3
- moai_adk/core/tags/validator.py +1 -1
- moai_adk/core/template_engine.py +20 -5
- moai_adk/templates/.claude/agents/alfred/backend-expert.md +319 -0
- moai_adk/templates/.claude/agents/alfred/devops-expert.md +464 -0
- moai_adk/templates/.claude/agents/alfred/doc-syncer.md +1 -1
- moai_adk/templates/.claude/agents/alfred/frontend-expert.md +357 -0
- moai_adk/templates/.claude/agents/alfred/git-manager.md +2 -2
- moai_adk/templates/.claude/agents/alfred/implementation-planner.md +76 -3
- moai_adk/templates/.claude/agents/alfred/project-manager.md +49 -10
- moai_adk/templates/.claude/agents/alfred/quality-gate.md +3 -3
- moai_adk/templates/.claude/agents/alfred/spec-builder.md +108 -3
- moai_adk/templates/.claude/agents/alfred/tag-agent.md +74 -0
- moai_adk/templates/.claude/agents/alfred/tdd-implementer.md +107 -5
- moai_adk/templates/.claude/agents/alfred/trust-checker.md +2 -2
- moai_adk/templates/.claude/agents/alfred/ui-ux-expert.md +571 -0
- moai_adk/templates/.claude/commands/alfred/0-project.md +465 -129
- moai_adk/templates/.claude/commands/alfred/1-plan.md +139 -65
- moai_adk/templates/.claude/commands/alfred/2-run.md +214 -50
- moai_adk/templates/.claude/commands/alfred/3-sync.md +372 -46
- moai_adk/templates/.claude/commands/alfred/9-feedback.md +1 -1
- moai_adk/templates/.claude/hooks/alfred/core/project.py +25 -27
- moai_adk/templates/.claude/hooks/alfred/core/timeout.py +136 -0
- moai_adk/templates/.claude/hooks/alfred/core/ttl_cache.py +108 -0
- moai_adk/templates/.claude/hooks/alfred/core/version_cache.py +4 -4
- moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +29 -0
- moai_adk/templates/.claude/hooks/alfred/post_tool__log_changes.py +11 -19
- moai_adk/templates/.claude/hooks/alfred/pre_tool__auto_checkpoint.py +11 -19
- moai_adk/templates/.claude/hooks/alfred/session_end__cleanup.py +11 -19
- moai_adk/templates/.claude/hooks/alfred/session_start__show_project_info.py +10 -18
- moai_adk/templates/.claude/hooks/alfred/shared/core/__init__.py +2 -2
- moai_adk/templates/.claude/hooks/alfred/shared/core/checkpoint.py +3 -3
- moai_adk/templates/.claude/hooks/alfred/shared/core/context.py +5 -5
- moai_adk/templates/.claude/hooks/alfred/shared/core/project.py +40 -41
- moai_adk/templates/.claude/hooks/alfred/shared/core/tags.py +55 -23
- moai_adk/templates/.claude/hooks/alfred/shared/core/version_cache.py +4 -4
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/notification.py +132 -3
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/session.py +9 -10
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/tool.py +3 -6
- moai_adk/templates/.claude/hooks/alfred/shared/handlers/user.py +19 -0
- moai_adk/templates/.claude/hooks/alfred/user_prompt__jit_load_docs.py +14 -22
- moai_adk/templates/.claude/hooks/alfred/utils/__init__.py +1 -0
- moai_adk/templates/.claude/hooks/alfred/utils/timeout.py +161 -0
- moai_adk/templates/.claude/settings.json +5 -5
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/SKILL.md +70 -0
- moai_adk/templates/.claude/skills/moai-alfred-agent-guide/examples.md +62 -0
- moai_adk/templates/{.moai/memory/CLAUDE-AGENTS-GUIDE.md → .claude/skills/moai-alfred-agent-guide/reference.md} +34 -0
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/SKILL.md +56 -0
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/examples.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-config-schema/reference.md +444 -0
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/SKILL.md +62 -0
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/examples.md +28 -0
- moai_adk/templates/.claude/skills/moai-alfred-context-budget/reference.md +405 -0
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/SKILL.md +51 -0
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/examples.md +355 -0
- moai_adk/templates/.claude/skills/moai-alfred-dev-guide/reference.md +239 -0
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/SKILL.md +323 -0
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/examples.md +286 -0
- moai_adk/templates/.claude/skills/moai-alfred-expertise-detection/reference.md +126 -0
- moai_adk/templates/.claude/skills/moai-alfred-gitflow-policy/SKILL.md +74 -0
- moai_adk/templates/.claude/skills/moai-alfred-gitflow-policy/examples.md +4 -0
- moai_adk/templates/.claude/skills/moai-alfred-gitflow-policy/reference.md +269 -0
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/SKILL.md +19 -0
- moai_adk/templates/.claude/skills/moai-alfred-issue-labels/examples.md +4 -0
- moai_adk/templates/.claude/skills/moai-alfred-persona-roles/SKILL.md +198 -0
- moai_adk/templates/.claude/skills/moai-alfred-persona-roles/examples.md +431 -0
- moai_adk/templates/.claude/skills/moai-alfred-persona-roles/reference.md +141 -0
- moai_adk/templates/.claude/skills/moai-alfred-practices/SKILL.md +89 -0
- moai_adk/templates/.claude/skills/moai-alfred-practices/examples.md +122 -0
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/SKILL.md +508 -0
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/examples.md +481 -0
- moai_adk/templates/.claude/skills/moai-alfred-proactive-suggestions/reference.md +100 -0
- moai_adk/templates/.claude/skills/moai-alfred-reporting/SKILL.md +273 -0
- moai_adk/templates/.claude/skills/moai-alfred-rules/SKILL.md +77 -0
- moai_adk/templates/.claude/skills/moai-alfred-rules/examples.md +265 -0
- moai_adk/templates/.claude/skills/moai-alfred-session-state/SKILL.md +19 -0
- moai_adk/templates/.claude/skills/moai-alfred-session-state/examples.md +4 -0
- moai_adk/templates/.claude/skills/moai-alfred-session-state/reference.md +84 -0
- moai_adk/templates/.claude/skills/{moai-spec-authoring → moai-alfred-spec-authoring}/SKILL.md +5 -5
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-extended/SKILL.md +115 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-extended/examples.md +4 -0
- moai_adk/templates/.claude/skills/moai-alfred-spec-metadata-extended/reference.md +348 -0
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/SKILL.md +19 -0
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/examples.md +4 -0
- moai_adk/templates/.claude/skills/moai-alfred-todowrite-pattern/reference.md +211 -0
- moai_adk/templates/.claude/skills/moai-alfred-workflow/SKILL.md +288 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-descriptions/SKILL.md +19 -0
- moai_adk/templates/.claude/skills/moai-cc-skill-descriptions/examples.md +4 -0
- moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/SKILL.md +3 -3
- moai_adk/templates/.claude/skills/moai-design-systems/SKILL.md +802 -0
- moai_adk/templates/.claude/skills/moai-design-systems/examples.md +1238 -0
- moai_adk/templates/.claude/skills/moai-design-systems/reference.md +673 -0
- moai_adk/templates/.claude/skills/moai-domain-frontend/SKILL.md +17 -13
- moai_adk/templates/.claude/skills/moai-lang-go/SKILL.md +15 -12
- moai_adk/templates/.claude/skills/moai-lang-java/SKILL.md +14 -12
- moai_adk/templates/.claude/skills/moai-lang-php/SKILL.md +14 -11
- moai_adk/templates/.claude/skills/moai-lang-python/SKILL.md +10 -8
- moai_adk/templates/.claude/skills/moai-lang-rust/SKILL.md +15 -12
- moai_adk/templates/.claude/skills/moai-lang-scala/SKILL.md +13 -11
- moai_adk/templates/.claude/skills/moai-lang-typescript/SKILL.md +16 -10
- moai_adk/templates/.claude/skills/moai-project-documentation.md +622 -0
- moai_adk/templates/.git-hooks/pre-push +143 -0
- moai_adk/templates/.github/workflows/c-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/cpp-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/csharp-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/dart-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/go-tag-validation.yml +130 -0
- moai_adk/templates/.github/workflows/java-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/javascript-tag-validation.yml +135 -0
- moai_adk/templates/.github/workflows/kotlin-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/moai-gitflow.yml +182 -25
- moai_adk/templates/.github/workflows/moai-release-pipeline.yml +35 -29
- moai_adk/templates/.github/workflows/php-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/python-tag-validation.yml +118 -0
- moai_adk/templates/.github/workflows/release.yml +76 -7
- moai_adk/templates/.github/workflows/ruby-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/rust-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/shell-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/spec-issue-sync.yml +208 -41
- moai_adk/templates/.github/workflows/swift-tag-validation.yml +11 -0
- moai_adk/templates/.github/workflows/tag-report.yml +269 -0
- moai_adk/templates/.github/workflows/tag-validation.yml +186 -0
- moai_adk/templates/.github/workflows/typescript-tag-validation.yml +154 -0
- moai_adk/templates/.moai/config.json +3 -1
- moai_adk/templates/CLAUDE.md +940 -45
- moai_adk/templates/workflows/go-tag-validation.yml +30 -0
- moai_adk/templates/workflows/javascript-tag-validation.yml +41 -0
- moai_adk/templates/workflows/python-tag-validation.yml +42 -0
- moai_adk/templates/workflows/typescript-tag-validation.yml +31 -0
- moai_adk/utils/banner.py +5 -5
- {moai_adk-0.9.0.dist-info → moai_adk-0.15.0.dist-info}/METADATA +1166 -455
- {moai_adk-0.9.0.dist-info → moai_adk-0.15.0.dist-info}/RECORD +169 -109
- moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py +0 -209
- moai_adk/templates/.claude/hooks/alfred/notification__handle_events.py +0 -102
- moai_adk/templates/.claude/hooks/alfred/stop__handle_interrupt.py +0 -102
- moai_adk/templates/.claude/hooks/alfred/subagent_stop__handle_subagent_end.py +0 -102
- moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +0 -640
- moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +0 -696
- moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +0 -474
- moai_adk/templates/.github/ISSUE_TEMPLATE/spec.yml +0 -176
- moai_adk/templates/.github/PULL_REQUEST_TEMPLATE.md +0 -69
- moai_adk/templates/.moai/memory/DEVELOPMENT-GUIDE.md +0 -344
- moai_adk/templates/.moai/memory/SPEC-METADATA.md +0 -356
- moai_adk/templates/.moai/memory/gitflow-protection-policy.md +0 -330
- moai_adk/templates/.moai/project/product.md +0 -161
- moai_adk/templates/.moai/project/structure.md +0 -156
- moai_adk/templates/.moai/project/tech.md +0 -227
- moai_adk/templates/README.md +0 -256
- moai_adk/templates/__init__.py +0 -2
- /moai_adk/templates/{.moai/memory/ISSUE-LABEL-MAPPING.md → .claude/skills/moai-alfred-issue-labels/reference.md} +0 -0
- /moai_adk/templates/{.moai/memory/CLAUDE-PRACTICES.md → .claude/skills/moai-alfred-practices/reference.md} +0 -0
- /moai_adk/templates/{.moai/memory/CLAUDE-RULES.md → .claude/skills/moai-alfred-rules/reference.md} +0 -0
- /moai_adk/templates/.claude/skills/{moai-spec-authoring → moai-alfred-spec-authoring}/README.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-spec-authoring → moai-alfred-spec-authoring}/examples/validate-spec.sh +0 -0
- /moai_adk/templates/.claude/skills/{moai-spec-authoring → moai-alfred-spec-authoring}/examples.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-spec-authoring → moai-alfred-spec-authoring}/reference.md +0 -0
- /moai_adk/templates/{.moai/memory/SKILLS-DESCRIPTION-POLICY.md → .claude/skills/moai-cc-skill-descriptions/reference.md} +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/CHECKLIST.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/EXAMPLES.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/INTERACTIVE-DISCOVERY.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/METADATA.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/PARALLEL-ANALYSIS-REPORT.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/PYTHON-VERSION-MATRIX.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/SKILL-FACTORY-WORKFLOW.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/SKILL-UPDATE-ADVISOR.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/STEP-BY-STEP-GUIDE.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/STRUCTURE.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/WEB-RESEARCH.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/reference.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/scripts/generate-structure.sh +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/scripts/validate-skill.sh +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/templates/SKILL_TEMPLATE.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/templates/examples-template.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/templates/reference-template.md +0 -0
- /moai_adk/templates/.claude/skills/{moai-skill-factory → moai-cc-skill-factory}/templates/scripts-template.sh +0 -0
- {moai_adk-0.9.0.dist-info → moai_adk-0.15.0.dist-info}/WHEEL +0 -0
- {moai_adk-0.9.0.dist-info → moai_adk-0.15.0.dist-info}/entry_points.txt +0 -0
- {moai_adk-0.9.0.dist-info → moai_adk-0.15.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# @CODE:HOOKS-REFACTOR-001 | SPEC: SPEC-HOOKS-REFACTOR-001.md
|
|
3
|
-
"""Alfred Hooks - Main entry point for MoAI-ADK Claude Code Hooks
|
|
4
|
-
|
|
5
|
-
A main entry point that routes Claude Code events to the appropriate handlers.
|
|
6
|
-
|
|
7
|
-
🏗️ Architecture:
|
|
8
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
9
|
-
│ alfred_hooks.py (Router) │
|
|
10
|
-
├─────────────────────────────────────────────────────────────┤
|
|
11
|
-
│ - CLI argument parsing │
|
|
12
|
-
│ - JSON I/O (stdin/stdout) │
|
|
13
|
-
│ - Event routing to handlers │
|
|
14
|
-
└─────────────────────────────────────────────────────────────┘
|
|
15
|
-
▼
|
|
16
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
17
|
-
│ handlers/ (Event Handlers) │
|
|
18
|
-
├─────────────────────────────────────────────────────────────┤
|
|
19
|
-
│ - session.py: SessionStart, SessionEnd │
|
|
20
|
-
│ - user.py: UserPromptSubmit │
|
|
21
|
-
│ - tool.py: PreToolUse, PostToolUse │
|
|
22
|
-
│ - notification.py: Notification, Stop, SubagentStop │
|
|
23
|
-
└─────────────────────────────────────────────────────────────┘
|
|
24
|
-
▼
|
|
25
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
26
|
-
│ core/ (Business Logic) │
|
|
27
|
-
├─────────────────────────────────────────────────────────────┤
|
|
28
|
-
│ - project.py: Language detection, Git info, SPEC progress │
|
|
29
|
-
│ - context.py: JIT Retrieval, workflow context │
|
|
30
|
-
│ - checkpoint.py: Event-Driven Checkpoint system │
|
|
31
|
-
│ - tags.py: TAG search/verification, library version cache │
|
|
32
|
-
└─────────────────────────────────────────────────────────────┘
|
|
33
|
-
|
|
34
|
-
🛠️ Usage:
|
|
35
|
-
python alfred_hooks.py <event_name> < payload.json
|
|
36
|
-
|
|
37
|
-
📣 Supported Events:
|
|
38
|
-
- SessionStart: Start Session (display project status)
|
|
39
|
-
- UserPromptSubmit: Prompt submission (JIT document loading)
|
|
40
|
-
- PreToolUse: Before using the tool (automatically creates checkpoint)
|
|
41
|
-
- SessionEnd, PostToolUse, Notification, Stop, SubagentStop
|
|
42
|
-
|
|
43
|
-
🚦 Exit Codes:
|
|
44
|
-
- 0: Success
|
|
45
|
-
- 1: Error (no arguments, JSON parsing failure, exception thrown)
|
|
46
|
-
|
|
47
|
-
🧪 TDD History:
|
|
48
|
-
- RED: Module separation design, event routing test
|
|
49
|
-
- GREEN: 1233 LOC → 9 items Module separation implementation (SRP compliance)
|
|
50
|
-
- REFACTOR: Import optimization, enhanced error handling
|
|
51
|
-
|
|
52
|
-
Setup sys.path for package imports
|
|
53
|
-
"""
|
|
54
|
-
|
|
55
|
-
import json
|
|
56
|
-
import signal
|
|
57
|
-
import sys
|
|
58
|
-
from pathlib import Path
|
|
59
|
-
from typing import Any
|
|
60
|
-
|
|
61
|
-
from core import HookResult
|
|
62
|
-
from handlers import (
|
|
63
|
-
handle_notification,
|
|
64
|
-
handle_post_tool_use,
|
|
65
|
-
handle_pre_tool_use,
|
|
66
|
-
handle_session_end,
|
|
67
|
-
handle_session_start,
|
|
68
|
-
handle_stop,
|
|
69
|
-
handle_subagent_stop,
|
|
70
|
-
handle_user_prompt_submit,
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
# Add the hooks directory to sys.path to enable package imports
|
|
74
|
-
HOOKS_DIR = Path(__file__).parent
|
|
75
|
-
if str(HOOKS_DIR) not in sys.path:
|
|
76
|
-
sys.path.insert(0, str(HOOKS_DIR))
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
class HookTimeoutError(Exception):
|
|
80
|
-
"""Hook execution timeout exception"""
|
|
81
|
-
pass
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def _hook_timeout_handler(signum, frame):
|
|
85
|
-
"""Signal handler for global hook timeout"""
|
|
86
|
-
raise HookTimeoutError("Hook execution exceeded 5-second timeout")
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def main() -> None:
|
|
90
|
-
"""Main entry point - Claude Code Hook script with GLOBAL TIMEOUT PROTECTION
|
|
91
|
-
|
|
92
|
-
Receives the event name as a CLI argument and reads the JSON payload through stdin.
|
|
93
|
-
Calls the handler appropriate for the event and outputs the results to stdout as JSON.
|
|
94
|
-
Enforces a 5-second global timeout to prevent subprocess hangs from freezing Claude Code.
|
|
95
|
-
|
|
96
|
-
🛠️ Usage:
|
|
97
|
-
python alfred_hooks.py <event_name> < payload.json
|
|
98
|
-
|
|
99
|
-
📣 Supported Events:
|
|
100
|
-
- SessionStart: Start Session (display project status)
|
|
101
|
-
- UserPromptSubmit: Prompt submission (JIT document loading)
|
|
102
|
-
- SessionEnd, PreToolUse, PostToolUse, Notification, Stop, SubagentStop
|
|
103
|
-
|
|
104
|
-
🚦 Exit Codes:
|
|
105
|
-
- 0: Success
|
|
106
|
-
- 1: Error (timeout, no arguments, JSON parsing failure, exception thrown)
|
|
107
|
-
|
|
108
|
-
📝 Examples:
|
|
109
|
-
$ echo '{"cwd": "."}' | python alfred_hooks.py SessionStart
|
|
110
|
-
{"message": "🚀 MoAI-ADK Session Started\\n...", ...}
|
|
111
|
-
|
|
112
|
-
🗒️ Notes:
|
|
113
|
-
- Claude Code is automatically called (no need for direct user execution)
|
|
114
|
-
- JSON I/O processing through stdin/stdout
|
|
115
|
-
- Print error message to stderr
|
|
116
|
-
- UserPromptSubmit uses a special output schema (hookEventName + additionalContext)
|
|
117
|
-
- CRITICAL: 5-second global timeout prevents Claude Code freeze on subprocess hang
|
|
118
|
-
|
|
119
|
-
🧪 TDD History:
|
|
120
|
-
- RED: Event routing, JSON I/O, error handling testing
|
|
121
|
-
- GREEN: Handler map-based routing implementation
|
|
122
|
-
- REFACTOR: Error message clarification, exit code standardization, UserPromptSubmit schema separation
|
|
123
|
-
- HOTFIX: Added global SIGALRM timeout to prevent subprocess hang (Issue #66)
|
|
124
|
-
|
|
125
|
-
@TAG:HOOKS-TIMEOUT-001
|
|
126
|
-
"""
|
|
127
|
-
# Set global 5-second timeout for entire hook execution
|
|
128
|
-
signal.signal(signal.SIGALRM, _hook_timeout_handler)
|
|
129
|
-
signal.alarm(5)
|
|
130
|
-
|
|
131
|
-
try:
|
|
132
|
-
# Check for event argument
|
|
133
|
-
if len(sys.argv) < 2:
|
|
134
|
-
print("Usage: alfred_hooks.py <event>", file=sys.stderr)
|
|
135
|
-
sys.exit(1)
|
|
136
|
-
|
|
137
|
-
event_name = sys.argv[1]
|
|
138
|
-
|
|
139
|
-
try:
|
|
140
|
-
# Read JSON from stdin
|
|
141
|
-
input_data = sys.stdin.read()
|
|
142
|
-
# Handle empty stdin gracefully (return empty dict)
|
|
143
|
-
if not input_data or not input_data.strip():
|
|
144
|
-
data = {}
|
|
145
|
-
else:
|
|
146
|
-
data = json.loads(input_data)
|
|
147
|
-
|
|
148
|
-
cwd = data.get("cwd", ".")
|
|
149
|
-
|
|
150
|
-
# Route to appropriate handler
|
|
151
|
-
handlers = {
|
|
152
|
-
"SessionStart": handle_session_start,
|
|
153
|
-
"UserPromptSubmit": handle_user_prompt_submit,
|
|
154
|
-
"SessionEnd": handle_session_end,
|
|
155
|
-
"PreToolUse": handle_pre_tool_use,
|
|
156
|
-
"PostToolUse": handle_post_tool_use,
|
|
157
|
-
"Notification": handle_notification,
|
|
158
|
-
"Stop": handle_stop,
|
|
159
|
-
"SubagentStop": handle_subagent_stop,
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
handler = handlers.get(event_name)
|
|
163
|
-
result = handler({"cwd": cwd, **data}) if handler else HookResult()
|
|
164
|
-
|
|
165
|
-
# Output Hook result as JSON
|
|
166
|
-
# Note: UserPromptSubmit uses to_user_prompt_submit_dict() for special schema
|
|
167
|
-
if event_name == "UserPromptSubmit":
|
|
168
|
-
print(json.dumps(result.to_user_prompt_submit_dict()))
|
|
169
|
-
else:
|
|
170
|
-
print(json.dumps(result.to_dict()))
|
|
171
|
-
|
|
172
|
-
sys.exit(0)
|
|
173
|
-
|
|
174
|
-
except json.JSONDecodeError as e:
|
|
175
|
-
# Return valid Hook response even on JSON parse error
|
|
176
|
-
error_response: dict[str, Any] = {
|
|
177
|
-
"continue": True,
|
|
178
|
-
"hookSpecificOutput": {"error": f"JSON parse error: {e}"}
|
|
179
|
-
}
|
|
180
|
-
print(json.dumps(error_response))
|
|
181
|
-
print(f"JSON parse error: {e}", file=sys.stderr)
|
|
182
|
-
sys.exit(1)
|
|
183
|
-
except Exception as e:
|
|
184
|
-
# Return valid Hook response even on unexpected error
|
|
185
|
-
error_response: dict[str, Any] = {
|
|
186
|
-
"continue": True,
|
|
187
|
-
"hookSpecificOutput": {"error": f"Hook error: {e}"}
|
|
188
|
-
}
|
|
189
|
-
print(json.dumps(error_response))
|
|
190
|
-
print(f"Unexpected error: {e}", file=sys.stderr)
|
|
191
|
-
sys.exit(1)
|
|
192
|
-
|
|
193
|
-
except HookTimeoutError:
|
|
194
|
-
# CRITICAL: Hook took too long - return minimal valid response to prevent Claude Code freeze
|
|
195
|
-
timeout_response: dict[str, Any] = {
|
|
196
|
-
"continue": True,
|
|
197
|
-
"systemMessage": "⚠️ Hook execution timeout - continuing without session info"
|
|
198
|
-
}
|
|
199
|
-
print(json.dumps(timeout_response))
|
|
200
|
-
print("Hook timeout after 5 seconds", file=sys.stderr)
|
|
201
|
-
sys.exit(1)
|
|
202
|
-
|
|
203
|
-
finally:
|
|
204
|
-
# Always cancel the alarm to prevent signal leakage
|
|
205
|
-
signal.alarm(0)
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if __name__ == "__main__":
|
|
209
|
-
main()
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# @CODE:HOOKS-CLARITY-001 | SPEC: Individual hook files for better UX
|
|
3
|
-
"""Notification Hook: Handle System Notifications
|
|
4
|
-
|
|
5
|
-
Claude Code Event: Notification
|
|
6
|
-
Purpose: Process system notifications and alerts from Claude Code
|
|
7
|
-
Execution: Triggered when Claude Code sends notification events
|
|
8
|
-
|
|
9
|
-
Output: Continue execution (currently a stub for future enhancements)
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
import json
|
|
13
|
-
import signal
|
|
14
|
-
import sys
|
|
15
|
-
from pathlib import Path
|
|
16
|
-
from typing import Any
|
|
17
|
-
|
|
18
|
-
# Setup import path for shared modules
|
|
19
|
-
HOOKS_DIR = Path(__file__).parent
|
|
20
|
-
SHARED_DIR = HOOKS_DIR / "shared"
|
|
21
|
-
if str(SHARED_DIR) not in sys.path:
|
|
22
|
-
sys.path.insert(0, str(SHARED_DIR))
|
|
23
|
-
|
|
24
|
-
from handlers import handle_notification
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class HookTimeoutError(Exception):
|
|
28
|
-
"""Hook execution timeout exception"""
|
|
29
|
-
pass
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def _timeout_handler(signum, frame):
|
|
33
|
-
"""Signal handler for 5-second timeout"""
|
|
34
|
-
raise HookTimeoutError("Hook execution exceeded 5-second timeout")
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def main() -> None:
|
|
38
|
-
"""Main entry point for Notification hook
|
|
39
|
-
|
|
40
|
-
Currently a stub for future functionality:
|
|
41
|
-
- Filter and categorize notifications
|
|
42
|
-
- Send alerts to external systems (Slack, email)
|
|
43
|
-
- Log important events
|
|
44
|
-
- Trigger automated responses
|
|
45
|
-
|
|
46
|
-
Exit Codes:
|
|
47
|
-
0: Success
|
|
48
|
-
1: Error (timeout, JSON parse failure, handler exception)
|
|
49
|
-
"""
|
|
50
|
-
# Set 5-second timeout
|
|
51
|
-
signal.signal(signal.SIGALRM, _timeout_handler)
|
|
52
|
-
signal.alarm(5)
|
|
53
|
-
|
|
54
|
-
try:
|
|
55
|
-
# Read JSON payload from stdin
|
|
56
|
-
input_data = sys.stdin.read()
|
|
57
|
-
data = json.loads(input_data) if input_data.strip() else {}
|
|
58
|
-
|
|
59
|
-
# Call handler
|
|
60
|
-
result = handle_notification(data)
|
|
61
|
-
|
|
62
|
-
# Output result as JSON
|
|
63
|
-
print(json.dumps(result.to_dict()))
|
|
64
|
-
sys.exit(0)
|
|
65
|
-
|
|
66
|
-
except HookTimeoutError:
|
|
67
|
-
# Timeout - return minimal valid response
|
|
68
|
-
timeout_response: dict[str, Any] = {
|
|
69
|
-
"continue": True,
|
|
70
|
-
"systemMessage": "⚠️ Notification handler timeout"
|
|
71
|
-
}
|
|
72
|
-
print(json.dumps(timeout_response))
|
|
73
|
-
print("Notification hook timeout after 5 seconds", file=sys.stderr)
|
|
74
|
-
sys.exit(1)
|
|
75
|
-
|
|
76
|
-
except json.JSONDecodeError as e:
|
|
77
|
-
# JSON parse error
|
|
78
|
-
error_response: dict[str, Any] = {
|
|
79
|
-
"continue": True,
|
|
80
|
-
"hookSpecificOutput": {"error": f"JSON parse error: {e}"}
|
|
81
|
-
}
|
|
82
|
-
print(json.dumps(error_response))
|
|
83
|
-
print(f"Notification JSON parse error: {e}", file=sys.stderr)
|
|
84
|
-
sys.exit(1)
|
|
85
|
-
|
|
86
|
-
except Exception as e:
|
|
87
|
-
# Unexpected error
|
|
88
|
-
error_response: dict[str, Any] = {
|
|
89
|
-
"continue": True,
|
|
90
|
-
"hookSpecificOutput": {"error": f"Notification error: {e}"}
|
|
91
|
-
}
|
|
92
|
-
print(json.dumps(error_response))
|
|
93
|
-
print(f"Notification unexpected error: {e}", file=sys.stderr)
|
|
94
|
-
sys.exit(1)
|
|
95
|
-
|
|
96
|
-
finally:
|
|
97
|
-
# Always cancel alarm
|
|
98
|
-
signal.alarm(0)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if __name__ == "__main__":
|
|
102
|
-
main()
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# @CODE:HOOKS-CLARITY-001 | SPEC: Individual hook files for better UX
|
|
3
|
-
"""Stop Hook: Handle Execution Interruption
|
|
4
|
-
|
|
5
|
-
Claude Code Event: Stop
|
|
6
|
-
Purpose: Handle graceful shutdown when execution is interrupted by user
|
|
7
|
-
Execution: Triggered when user stops Claude Code execution (Ctrl+C, stop button)
|
|
8
|
-
|
|
9
|
-
Output: Continue execution (currently a stub for future enhancements)
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
import json
|
|
13
|
-
import signal
|
|
14
|
-
import sys
|
|
15
|
-
from pathlib import Path
|
|
16
|
-
from typing import Any
|
|
17
|
-
|
|
18
|
-
# Setup import path for shared modules
|
|
19
|
-
HOOKS_DIR = Path(__file__).parent
|
|
20
|
-
SHARED_DIR = HOOKS_DIR / "shared"
|
|
21
|
-
if str(SHARED_DIR) not in sys.path:
|
|
22
|
-
sys.path.insert(0, str(SHARED_DIR))
|
|
23
|
-
|
|
24
|
-
from handlers import handle_stop
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class HookTimeoutError(Exception):
|
|
28
|
-
"""Hook execution timeout exception"""
|
|
29
|
-
pass
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def _timeout_handler(signum, frame):
|
|
33
|
-
"""Signal handler for 5-second timeout"""
|
|
34
|
-
raise HookTimeoutError("Hook execution exceeded 5-second timeout")
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def main() -> None:
|
|
38
|
-
"""Main entry point for Stop hook
|
|
39
|
-
|
|
40
|
-
Currently a stub for future functionality:
|
|
41
|
-
- Save partial work before interruption
|
|
42
|
-
- Create recovery checkpoint
|
|
43
|
-
- Log interruption reason and context
|
|
44
|
-
- Notify external systems of stop event
|
|
45
|
-
|
|
46
|
-
Exit Codes:
|
|
47
|
-
0: Success
|
|
48
|
-
1: Error (timeout, JSON parse failure, handler exception)
|
|
49
|
-
"""
|
|
50
|
-
# Set 5-second timeout
|
|
51
|
-
signal.signal(signal.SIGALRM, _timeout_handler)
|
|
52
|
-
signal.alarm(5)
|
|
53
|
-
|
|
54
|
-
try:
|
|
55
|
-
# Read JSON payload from stdin
|
|
56
|
-
input_data = sys.stdin.read()
|
|
57
|
-
data = json.loads(input_data) if input_data.strip() else {}
|
|
58
|
-
|
|
59
|
-
# Call handler
|
|
60
|
-
result = handle_stop(data)
|
|
61
|
-
|
|
62
|
-
# Output result as JSON
|
|
63
|
-
print(json.dumps(result.to_dict()))
|
|
64
|
-
sys.exit(0)
|
|
65
|
-
|
|
66
|
-
except HookTimeoutError:
|
|
67
|
-
# Timeout - return minimal valid response
|
|
68
|
-
timeout_response: dict[str, Any] = {
|
|
69
|
-
"continue": True,
|
|
70
|
-
"systemMessage": "⚠️ Stop handler timeout"
|
|
71
|
-
}
|
|
72
|
-
print(json.dumps(timeout_response))
|
|
73
|
-
print("Stop hook timeout after 5 seconds", file=sys.stderr)
|
|
74
|
-
sys.exit(1)
|
|
75
|
-
|
|
76
|
-
except json.JSONDecodeError as e:
|
|
77
|
-
# JSON parse error
|
|
78
|
-
error_response: dict[str, Any] = {
|
|
79
|
-
"continue": True,
|
|
80
|
-
"hookSpecificOutput": {"error": f"JSON parse error: {e}"}
|
|
81
|
-
}
|
|
82
|
-
print(json.dumps(error_response))
|
|
83
|
-
print(f"Stop JSON parse error: {e}", file=sys.stderr)
|
|
84
|
-
sys.exit(1)
|
|
85
|
-
|
|
86
|
-
except Exception as e:
|
|
87
|
-
# Unexpected error
|
|
88
|
-
error_response: dict[str, Any] = {
|
|
89
|
-
"continue": True,
|
|
90
|
-
"hookSpecificOutput": {"error": f"Stop error: {e}"}
|
|
91
|
-
}
|
|
92
|
-
print(json.dumps(error_response))
|
|
93
|
-
print(f"Stop unexpected error: {e}", file=sys.stderr)
|
|
94
|
-
sys.exit(1)
|
|
95
|
-
|
|
96
|
-
finally:
|
|
97
|
-
# Always cancel alarm
|
|
98
|
-
signal.alarm(0)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if __name__ == "__main__":
|
|
102
|
-
main()
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# @CODE:HOOKS-CLARITY-001 | SPEC: Individual hook files for better UX
|
|
3
|
-
"""SubagentStop Hook: Handle Sub-agent Termination
|
|
4
|
-
|
|
5
|
-
Claude Code Event: SubagentStop
|
|
6
|
-
Purpose: Handle cleanup when a sub-agent execution completes or is terminated
|
|
7
|
-
Execution: Triggered when Task tool completes (sub-agent finishes)
|
|
8
|
-
|
|
9
|
-
Output: Continue execution (currently a stub for future enhancements)
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
import json
|
|
13
|
-
import signal
|
|
14
|
-
import sys
|
|
15
|
-
from pathlib import Path
|
|
16
|
-
from typing import Any
|
|
17
|
-
|
|
18
|
-
# Setup import path for shared modules
|
|
19
|
-
HOOKS_DIR = Path(__file__).parent
|
|
20
|
-
SHARED_DIR = HOOKS_DIR / "shared"
|
|
21
|
-
if str(SHARED_DIR) not in sys.path:
|
|
22
|
-
sys.path.insert(0, str(SHARED_DIR))
|
|
23
|
-
|
|
24
|
-
from handlers import handle_subagent_stop
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class HookTimeoutError(Exception):
|
|
28
|
-
"""Hook execution timeout exception"""
|
|
29
|
-
pass
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def _timeout_handler(signum, frame):
|
|
33
|
-
"""Signal handler for 5-second timeout"""
|
|
34
|
-
raise HookTimeoutError("Hook execution exceeded 5-second timeout")
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def main() -> None:
|
|
38
|
-
"""Main entry point for SubagentStop hook
|
|
39
|
-
|
|
40
|
-
Currently a stub for future functionality:
|
|
41
|
-
- Collect sub-agent execution metrics
|
|
42
|
-
- Log sub-agent results and errors
|
|
43
|
-
- Update workflow state based on sub-agent outcome
|
|
44
|
-
- Trigger follow-up actions based on results
|
|
45
|
-
|
|
46
|
-
Exit Codes:
|
|
47
|
-
0: Success
|
|
48
|
-
1: Error (timeout, JSON parse failure, handler exception)
|
|
49
|
-
"""
|
|
50
|
-
# Set 5-second timeout
|
|
51
|
-
signal.signal(signal.SIGALRM, _timeout_handler)
|
|
52
|
-
signal.alarm(5)
|
|
53
|
-
|
|
54
|
-
try:
|
|
55
|
-
# Read JSON payload from stdin
|
|
56
|
-
input_data = sys.stdin.read()
|
|
57
|
-
data = json.loads(input_data) if input_data.strip() else {}
|
|
58
|
-
|
|
59
|
-
# Call handler
|
|
60
|
-
result = handle_subagent_stop(data)
|
|
61
|
-
|
|
62
|
-
# Output result as JSON
|
|
63
|
-
print(json.dumps(result.to_dict()))
|
|
64
|
-
sys.exit(0)
|
|
65
|
-
|
|
66
|
-
except HookTimeoutError:
|
|
67
|
-
# Timeout - return minimal valid response
|
|
68
|
-
timeout_response: dict[str, Any] = {
|
|
69
|
-
"continue": True,
|
|
70
|
-
"systemMessage": "⚠️ SubagentStop handler timeout"
|
|
71
|
-
}
|
|
72
|
-
print(json.dumps(timeout_response))
|
|
73
|
-
print("SubagentStop hook timeout after 5 seconds", file=sys.stderr)
|
|
74
|
-
sys.exit(1)
|
|
75
|
-
|
|
76
|
-
except json.JSONDecodeError as e:
|
|
77
|
-
# JSON parse error
|
|
78
|
-
error_response: dict[str, Any] = {
|
|
79
|
-
"continue": True,
|
|
80
|
-
"hookSpecificOutput": {"error": f"JSON parse error: {e}"}
|
|
81
|
-
}
|
|
82
|
-
print(json.dumps(error_response))
|
|
83
|
-
print(f"SubagentStop JSON parse error: {e}", file=sys.stderr)
|
|
84
|
-
sys.exit(1)
|
|
85
|
-
|
|
86
|
-
except Exception as e:
|
|
87
|
-
# Unexpected error
|
|
88
|
-
error_response: dict[str, Any] = {
|
|
89
|
-
"continue": True,
|
|
90
|
-
"hookSpecificOutput": {"error": f"SubagentStop error: {e}"}
|
|
91
|
-
}
|
|
92
|
-
print(json.dumps(error_response))
|
|
93
|
-
print(f"SubagentStop unexpected error: {e}", file=sys.stderr)
|
|
94
|
-
sys.exit(1)
|
|
95
|
-
|
|
96
|
-
finally:
|
|
97
|
-
# Always cancel alarm
|
|
98
|
-
signal.alarm(0)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
if __name__ == "__main__":
|
|
102
|
-
main()
|