moai-adk 0.3.0__py3-none-any.whl → 0.3.2__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 (38) hide show
  1. moai_adk/__init__.py +1 -1
  2. moai_adk-0.3.2.dist-info/METADATA +1059 -0
  3. {moai_adk-0.3.0.dist-info → moai_adk-0.3.2.dist-info}/RECORD +6 -37
  4. moai_adk/templates/.claude/agents/alfred/cc-manager.md +0 -474
  5. moai_adk/templates/.claude/agents/alfred/code-builder.md +0 -534
  6. moai_adk/templates/.claude/agents/alfred/debug-helper.md +0 -302
  7. moai_adk/templates/.claude/agents/alfred/doc-syncer.md +0 -175
  8. moai_adk/templates/.claude/agents/alfred/git-manager.md +0 -200
  9. moai_adk/templates/.claude/agents/alfred/project-manager.md +0 -152
  10. moai_adk/templates/.claude/agents/alfred/spec-builder.md +0 -256
  11. moai_adk/templates/.claude/agents/alfred/tag-agent.md +0 -247
  12. moai_adk/templates/.claude/agents/alfred/trust-checker.md +0 -332
  13. moai_adk/templates/.claude/commands/alfred/0-project.md +0 -523
  14. moai_adk/templates/.claude/commands/alfred/1-spec.md +0 -531
  15. moai_adk/templates/.claude/commands/alfred/2-build.md +0 -413
  16. moai_adk/templates/.claude/commands/alfred/3-sync.md +0 -552
  17. moai_adk/templates/.claude/hooks/alfred/README.md +0 -238
  18. moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py +0 -165
  19. moai_adk/templates/.claude/hooks/alfred/core/__init__.py +0 -79
  20. moai_adk/templates/.claude/hooks/alfred/core/checkpoint.py +0 -271
  21. moai_adk/templates/.claude/hooks/alfred/core/context.py +0 -110
  22. moai_adk/templates/.claude/hooks/alfred/core/project.py +0 -284
  23. moai_adk/templates/.claude/hooks/alfred/core/tags.py +0 -244
  24. moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py +0 -23
  25. moai_adk/templates/.claude/hooks/alfred/handlers/compact.py +0 -51
  26. moai_adk/templates/.claude/hooks/alfred/handlers/notification.py +0 -25
  27. moai_adk/templates/.claude/hooks/alfred/handlers/session.py +0 -80
  28. moai_adk/templates/.claude/hooks/alfred/handlers/tool.py +0 -71
  29. moai_adk/templates/.claude/hooks/alfred/handlers/user.py +0 -41
  30. moai_adk/templates/.claude/output-styles/alfred/agentic-coding.md +0 -635
  31. moai_adk/templates/.claude/output-styles/alfred/moai-adk-learning.md +0 -691
  32. moai_adk/templates/.claude/output-styles/alfred/study-with-alfred.md +0 -469
  33. moai_adk/templates/.claude/settings.json +0 -135
  34. moai_adk/templates/CLAUDE.md +0 -733
  35. moai_adk-0.3.0.dist-info/METADATA +0 -20
  36. {moai_adk-0.3.0.dist-info → moai_adk-0.3.2.dist-info}/WHEEL +0 -0
  37. {moai_adk-0.3.0.dist-info → moai_adk-0.3.2.dist-info}/entry_points.txt +0 -0
  38. {moai_adk-0.3.0.dist-info → moai_adk-0.3.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,244 +0,0 @@
1
- #!/usr/bin/env python3
2
- """TAG search and verification system
3
-
4
- TAG 검색, 체인 검증, 라이브러리 버전 캐싱
5
- """
6
-
7
- import json
8
- import subprocess
9
- import time
10
- from pathlib import Path
11
-
12
- # TAG search cache: {pattern: (results, mtime_hash, cached_at)}
13
- _tag_cache: dict[str, tuple[list[dict], float, float]] = {}
14
-
15
- # Library version cache: {lib_name: (version, timestamp)}
16
- _lib_version_cache: dict[str, tuple[str, float]] = {}
17
-
18
-
19
- def _get_dir_mtime_hash(paths: list[str]) -> float:
20
- """Calculate a directory-wide mtime hash used for cache invalidation.
21
-
22
- Args:
23
- paths: List of directory paths to inspect.
24
-
25
- Returns:
26
- Highest modification timestamp (float) across all files.
27
-
28
- Notes:
29
- - Any file change bumps the hash and invalidates the cache.
30
- - Missing or inaccessible directories are ignored.
31
- """
32
- max_mtime = 0.0
33
- for path in paths:
34
- path_obj = Path(path)
35
- if not path_obj.exists():
36
- continue
37
-
38
- try:
39
- for file_path in path_obj.rglob("*"):
40
- if file_path.is_file():
41
- max_mtime = max(max_mtime, file_path.stat().st_mtime)
42
- except (OSError, PermissionError):
43
- # Skip directories we cannot read
44
- continue
45
-
46
- return max_mtime
47
-
48
-
49
- def search_tags(pattern: str, scope: list[str] | None = None, cache_ttl: int = 60) -> list[dict]:
50
- """Search TAG markers using an in-memory cache.
51
-
52
- Args:
53
- pattern: Regex pattern (for example ``'@SPEC:AUTH-.*'``).
54
- scope: List of directories to scan. Defaults to specs/src/tests.
55
- cache_ttl: Cache time-to-live in seconds (default 60).
56
-
57
- Returns:
58
- List of matches such as ``{"file": "path", "line": 10, "tag": "...", "content": "..."}``.
59
-
60
- Notes:
61
- - Cache integrity relies on directory mtimes plus TTL.
62
- - Cache hits avoid spawning ``rg`` while misses shell out (≈13ms).
63
- - Uses ``rg --json`` output for structured parsing.
64
- """
65
- if scope is None:
66
- scope = [".moai/specs/", "src/", "tests/"]
67
-
68
- cache_key = f"{pattern}:{':'.join(scope)}"
69
-
70
- current_mtime = _get_dir_mtime_hash(scope)
71
- cache_entry = _tag_cache.get(cache_key)
72
-
73
- # Serve cached results when still valid
74
- if cache_entry:
75
- cached_results, cached_mtime, cached_at = cache_entry
76
- ttl_valid = time.time() - cached_at < cache_ttl
77
-
78
- # Matching mtime and a fresh TTL means we can reuse the cache
79
- if current_mtime == cached_mtime and ttl_valid:
80
- return cached_results
81
-
82
- # Cache miss → invoke ripgrep
83
- cmd = ["rg", pattern, "--json"] + scope
84
-
85
- try:
86
- result = subprocess.run(cmd, capture_output=True, text=True, timeout=5, check=False)
87
- except (subprocess.TimeoutExpired, FileNotFoundError):
88
- # Missing rg or a timeout returns an empty list
89
- return []
90
-
91
- matches = []
92
- for line in result.stdout.strip().split("\n"):
93
- if not line:
94
- continue
95
- try:
96
- data = json.loads(line)
97
- if data.get("type") == "match":
98
- matches.append(
99
- {
100
- "file": data["data"]["path"]["text"],
101
- "line": data["data"]["line_number"],
102
- "tag": data["data"]["lines"]["text"].strip(),
103
- "content": data["data"]["lines"]["text"],
104
- }
105
- )
106
- except (json.JSONDecodeError, KeyError):
107
- # Ignore malformed JSON lines
108
- continue
109
-
110
- # Persist results with the current mtime snapshot
111
- _tag_cache[cache_key] = (matches, _get_dir_mtime_hash(scope), time.time())
112
-
113
- return matches
114
-
115
-
116
- def verify_tag_chain(spec_id: str) -> dict:
117
- """Verify a TAG chain across ``@SPEC`` → ``@TEST`` → ``@CODE``.
118
-
119
- Args:
120
- spec_id: SPEC identifier (for example ``"AUTH-001"``).
121
-
122
- Returns:
123
- Dictionary with keys ``complete``, ``spec``, ``test``, ``code`` and ``orphans``.
124
-
125
- Notes:
126
- - Orphans capture TAGs found in code/tests without a SPEC.
127
- - A chain is complete only when all three categories contain matches.
128
- - Relies on ``search_tags`` so cached scans remain inexpensive.
129
- """
130
- chain = {
131
- "spec": search_tags(f"@SPEC:{spec_id}", [".moai/specs/"]),
132
- "test": search_tags(f"@TEST:{spec_id}", ["tests/"]),
133
- "code": search_tags(f"@CODE:{spec_id}", ["src/"]),
134
- }
135
-
136
- orphans = []
137
- if chain["code"] and not chain["spec"]:
138
- orphans.extend(chain["code"])
139
- if chain["test"] and not chain["spec"]:
140
- orphans.extend(chain["test"])
141
-
142
- return {
143
- "complete": bool(chain["spec"] and chain["test"] and chain["code"]),
144
- **chain,
145
- "orphans": orphans,
146
- }
147
-
148
-
149
- def find_all_tags_by_type(tag_type: str = "SPEC") -> dict:
150
- """Return TAG IDs grouped by domain for the requested type.
151
-
152
- Args:
153
- tag_type: TAG category (``SPEC``, ``TEST``, ``CODE`` or ``DOC``).
154
-
155
- Returns:
156
- Dictionary like ``{"AUTH": ["AUTH-001", "AUTH-002"], ...}``.
157
-
158
- Notes:
159
- - Domain is derived from the ``FOO-123`` prefix.
160
- - Deduplicates repeated matches within the same domain.
161
- - Fetches data via ``search_tags`` so caching still applies.
162
- """
163
- tags = search_tags(f"@{tag_type}:([A-Z]+-[0-9]{{3}})")
164
-
165
- by_domain = {}
166
- for tag in tags:
167
- # @SPEC:AUTH-001 → AUTH
168
- try:
169
- tag_id = tag["tag"].split(":")[1]
170
- domain = "-".join(tag_id.split("-")[:-1])
171
-
172
- if domain not in by_domain:
173
- by_domain[domain] = []
174
- if tag_id not in by_domain[domain]:
175
- by_domain[domain].append(tag_id)
176
- except IndexError:
177
- # 파싱 실패 무시
178
- continue
179
-
180
- return by_domain
181
-
182
-
183
- def suggest_tag_reuse(keyword: str, tag_type: str = "SPEC") -> list[str]:
184
- """Suggest existing TAG IDs that match the supplied keyword.
185
-
186
- Args:
187
- keyword: Keyword used to match domain names (case-insensitive).
188
- tag_type: TAG category (defaults to ``SPEC``).
189
-
190
- Returns:
191
- A list of up to five suggested TAG IDs.
192
-
193
- Notes:
194
- - Encourages reuse to avoid creating duplicate TAGs.
195
- - Performs a simple substring match against domain names.
196
- """
197
- all_tags = find_all_tags_by_type(tag_type)
198
- suggestions = []
199
-
200
- keyword_lower = keyword.lower()
201
- for domain, tag_ids in all_tags.items():
202
- if keyword_lower in domain.lower():
203
- suggestions.extend(tag_ids)
204
-
205
- return suggestions[:5] # Cap results at five
206
-
207
-
208
- def get_library_version(lib_name: str, cache_ttl: int = 86400) -> str | None:
209
- """Get the cached latest stable version for a library.
210
-
211
- Args:
212
- lib_name: Package name (for example ``"fastapi"``).
213
- cache_ttl: Cache TTL in seconds (defaults to 24 hours).
214
-
215
- Returns:
216
- Cached version string or ``None`` when the cache is cold.
217
-
218
- Notes:
219
- - Cache hits skip costly web searches (saves 3–5 seconds).
220
- - Agents should call ``set_library_version`` after fetching live data.
221
- """
222
- # Serve cached value when still within TTL
223
- if lib_name in _lib_version_cache:
224
- cached_version, cached_time = _lib_version_cache[lib_name]
225
- if time.time() - cached_time < cache_ttl:
226
- return cached_version
227
-
228
- # Cache miss → agent needs to perform the web search
229
- return None
230
-
231
-
232
- def set_library_version(lib_name: str, version: str):
233
- """Persist a library version in the cache."""
234
- _lib_version_cache[lib_name] = (version, time.time())
235
-
236
-
237
- __all__ = [
238
- "search_tags",
239
- "verify_tag_chain",
240
- "find_all_tags_by_type",
241
- "suggest_tag_reuse",
242
- "get_library_version",
243
- "set_library_version",
244
- ]
@@ -1,23 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Event handlers for Alfred Hooks
3
-
4
- Claude Code 이벤트 핸들러들
5
- """
6
-
7
- from .compact import handle_pre_compact
8
- from .notification import handle_notification, handle_stop, handle_subagent_stop
9
- from .session import handle_session_end, handle_session_start
10
- from .tool import handle_post_tool_use, handle_pre_tool_use
11
- from .user import handle_user_prompt_submit
12
-
13
- __all__ = [
14
- "handle_session_start",
15
- "handle_session_end",
16
- "handle_user_prompt_submit",
17
- "handle_pre_compact",
18
- "handle_pre_tool_use",
19
- "handle_post_tool_use",
20
- "handle_notification",
21
- "handle_stop",
22
- "handle_subagent_stop",
23
- ]
@@ -1,51 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Context compaction handlers
3
-
4
- PreCompact 이벤트 처리
5
- """
6
-
7
- from core import HookPayload, HookResult
8
-
9
-
10
- def handle_pre_compact(payload: HookPayload) -> HookResult:
11
- """PreCompact 이벤트 핸들러
12
-
13
- 컨텍스트가 70% 이상 차면 새 세션 시작을 제안합니다.
14
- Context Engineering의 Compaction 원칙을 구현합니다.
15
-
16
- Args:
17
- payload: Claude Code 이벤트 페이로드
18
-
19
- Returns:
20
- HookResult(
21
- message=새 세션 시작 제안 메시지,
22
- suggestions=구체적인 액션 제안 리스트
23
- )
24
-
25
- Suggestions:
26
- - /clear 명령으로 새 세션 시작
27
- - /new 명령으로 새 대화 시작
28
- - 핵심 결정사항 요약 후 계속
29
-
30
- Notes:
31
- - Context Engineering: Compaction 원칙 준수
32
- - 토큰 사용량 > 70% 시 자동 호출
33
- - 성능 향상 및 컨텍스트 관리 개선
34
-
35
- TDD History:
36
- - RED: PreCompact 메시지 및 제안 테스트
37
- - GREEN: 고정 메시지 및 제안 리스트 반환
38
- - REFACTOR: 사용자 친화적 메시지 개선
39
- """
40
- suggestions = [
41
- "Use `/clear` to start a fresh session",
42
- "Use `/new` to begin a new conversation",
43
- "Consider summarizing key decisions before continuing",
44
- ]
45
-
46
- message = "💡 Tip: Context is getting large. Consider starting a new session for better performance."
47
-
48
- return HookResult(message=message, suggestions=suggestions)
49
-
50
-
51
- __all__ = ["handle_pre_compact"]
@@ -1,25 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Notification and control handlers
3
-
4
- Notification, Stop, SubagentStop 이벤트 처리
5
- """
6
-
7
- from core import HookPayload, HookResult
8
-
9
-
10
- def handle_notification(payload: HookPayload) -> HookResult:
11
- """Notification 이벤트 핸들러 (기본 구현)"""
12
- return HookResult()
13
-
14
-
15
- def handle_stop(payload: HookPayload) -> HookResult:
16
- """Stop 이벤트 핸들러 (기본 구현)"""
17
- return HookResult()
18
-
19
-
20
- def handle_subagent_stop(payload: HookPayload) -> HookResult:
21
- """SubagentStop 이벤트 핸들러 (기본 구현)"""
22
- return HookResult()
23
-
24
-
25
- __all__ = ["handle_notification", "handle_stop", "handle_subagent_stop"]
@@ -1,80 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Session event handlers
3
-
4
- SessionStart, SessionEnd 이벤트 처리
5
- """
6
-
7
- from core import HookPayload, HookResult
8
- from core.checkpoint import list_checkpoints
9
- from core.project import count_specs, detect_language, get_git_info
10
-
11
-
12
- def handle_session_start(payload: HookPayload) -> HookResult:
13
- """SessionStart 이벤트 핸들러 (Checkpoint 목록 포함)
14
-
15
- Claude Code 세션 시작 시 프로젝트 상태를 요약하여 표시합니다.
16
- 언어, Git 상태, SPEC 진행도, Checkpoint 목록을 한눈에 확인할 수 있습니다.
17
-
18
- Args:
19
- payload: Claude Code 이벤트 페이로드 (cwd 키 필수)
20
-
21
- Returns:
22
- HookResult(message=프로젝트 상태 요약 메시지, systemMessage=사용자 표시용)
23
-
24
- Message Format:
25
- 🚀 MoAI-ADK Session Started
26
- Language: {언어}
27
- Branch: {브랜치} ({커밋 해시})
28
- Changes: {변경 파일 수}
29
- SPEC Progress: {완료}/{전체} ({퍼센트}%)
30
- Checkpoints: {개수} available (최신 3개 표시)
31
-
32
- TDD History:
33
- - RED: 세션 시작 메시지 형식 테스트
34
- - GREEN: helper 함수 조합하여 상태 메시지 생성
35
- - REFACTOR: 메시지 포맷 개선, 가독성 향상, checkpoint 목록 추가
36
-
37
- @TAG:CHECKPOINT-EVENT-001
38
- """
39
- cwd = payload.get("cwd", ".")
40
- language = detect_language(cwd)
41
- git_info = get_git_info(cwd)
42
- specs = count_specs(cwd)
43
- checkpoints = list_checkpoints(cwd, max_count=10)
44
-
45
- branch = git_info.get("branch", "N/A")
46
- commit = git_info.get("commit", "N/A")[:7]
47
- changes = git_info.get("changes", 0)
48
- spec_progress = f"{specs['completed']}/{specs['total']}"
49
-
50
- # systemMessage: 사용자에게 직접 표시
51
- lines = [
52
- "🚀 MoAI-ADK Session Started",
53
- f" Language: {language}",
54
- f" Branch: {branch} ({commit})",
55
- f" Changes: {changes}",
56
- f" SPEC Progress: {spec_progress} ({specs['percentage']}%)",
57
- ]
58
-
59
- # Checkpoint 목록 추가 (최신 3개만 표시)
60
- if checkpoints:
61
- lines.append(f" Checkpoints: {len(checkpoints)} available")
62
- for cp in reversed(checkpoints[-3:]): # 최신 3개
63
- branch_short = cp["branch"].replace("before-", "")
64
- lines.append(f" - {branch_short}")
65
- lines.append(" Restore: /alfred:0-project restore")
66
-
67
- system_message = "\n".join(lines)
68
-
69
- return HookResult(
70
- message=system_message, # Claude 컨텍스트용
71
- systemMessage=system_message, # 사용자 표시용
72
- )
73
-
74
-
75
- def handle_session_end(payload: HookPayload) -> HookResult:
76
- """SessionEnd 이벤트 핸들러 (기본 구현)"""
77
- return HookResult()
78
-
79
-
80
- __all__ = ["handle_session_start", "handle_session_end"]
@@ -1,71 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Tool usage handlers
3
-
4
- PreToolUse, PostToolUse 이벤트 처리
5
- """
6
-
7
- from core import HookPayload, HookResult
8
- from core.checkpoint import create_checkpoint, detect_risky_operation
9
-
10
-
11
- def handle_pre_tool_use(payload: HookPayload) -> HookResult:
12
- """PreToolUse 이벤트 핸들러 (Event-Driven Checkpoint 통합)
13
-
14
- 위험한 작업 전 자동으로 checkpoint를 생성합니다.
15
- Claude Code tool 사용 전에 호출되며, 위험 감지 시 사용자에게 알립니다.
16
-
17
- Args:
18
- payload: Claude Code 이벤트 페이로드
19
- (tool, arguments, cwd 키 포함)
20
-
21
- Returns:
22
- HookResult(
23
- message=checkpoint 생성 알림 (위험 감지 시),
24
- blocked=False (항상 작업 계속 진행)
25
- )
26
-
27
- Checkpoint Triggers:
28
- - Bash: rm -rf, git merge, git reset --hard
29
- - Edit/Write: CLAUDE.md, config.json
30
- - MultiEdit: ≥10 files
31
-
32
- Examples:
33
- Bash tool (rm -rf) 감지:
34
- → "🛡️ Checkpoint created: before-delete-20251015-143000"
35
-
36
- Notes:
37
- - 위험 감지 후에도 blocked=False 반환 (작업 계속)
38
- - Checkpoint 실패 시에도 작업 진행 (무시)
39
- - 투명한 백그라운드 동작
40
-
41
- @TAG:CHECKPOINT-EVENT-001
42
- """
43
- tool_name = payload.get("tool", "")
44
- tool_args = payload.get("arguments", {})
45
- cwd = payload.get("cwd", ".")
46
-
47
- # 위험한 작업 감지
48
- is_risky, operation_type = detect_risky_operation(tool_name, tool_args, cwd)
49
-
50
- # 위험 감지 시 checkpoint 생성
51
- if is_risky:
52
- checkpoint_branch = create_checkpoint(cwd, operation_type)
53
-
54
- if checkpoint_branch != "checkpoint-failed":
55
- message = (
56
- f"🛡️ Checkpoint created: {checkpoint_branch}\n"
57
- f" Operation: {operation_type}\n"
58
- f" Restore: /alfred:0-project restore"
59
- )
60
-
61
- return HookResult(message=message, blocked=False)
62
-
63
- return HookResult(blocked=False)
64
-
65
-
66
- def handle_post_tool_use(payload: HookPayload) -> HookResult:
67
- """PostToolUse 이벤트 핸들러 (기본 구현)"""
68
- return HookResult()
69
-
70
-
71
- __all__ = ["handle_pre_tool_use", "handle_post_tool_use"]
@@ -1,41 +0,0 @@
1
- #!/usr/bin/env python3
2
- """User interaction handlers
3
-
4
- UserPromptSubmit 이벤트 처리
5
- """
6
-
7
- from core import HookPayload, HookResult
8
- from core.context import get_jit_context
9
-
10
-
11
- def handle_user_prompt_submit(payload: HookPayload) -> HookResult:
12
- """UserPromptSubmit 이벤트 핸들러
13
-
14
- 사용자 프롬프트를 분석하여 관련 문서를 자동으로 컨텍스트에 추가합니다.
15
- JIT (Just-in-Time) Retrieval 원칙에 따라 필요한 문서만 로드합니다.
16
-
17
- Args:
18
- payload: Claude Code 이벤트 페이로드
19
- (userPrompt, cwd 키 포함)
20
-
21
- Returns:
22
- HookResult(
23
- message=로드된 파일 수 (또는 None),
24
- contextFiles=추천 문서 경로 리스트
25
- )
26
-
27
- TDD History:
28
- - RED: JIT 문서 로딩 시나리오 테스트
29
- - GREEN: get_jit_context() 호출하여 문서 추천
30
- - REFACTOR: 메시지 조건부 표시 (파일 있을 때만)
31
- """
32
- user_prompt = payload.get("userPrompt", "")
33
- cwd = payload.get("cwd", ".")
34
- context_files = get_jit_context(user_prompt, cwd)
35
-
36
- message = f"📎 Loaded {len(context_files)} context file(s)" if context_files else None
37
-
38
- return HookResult(message=message, contextFiles=context_files)
39
-
40
-
41
- __all__ = ["handle_user_prompt_submit"]