moai-adk 0.3.7__py3-none-any.whl → 0.3.10__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: moai-adk
3
- Version: 0.3.7
3
+ Version: 0.3.10
4
4
  Summary: MoAI Agentic Development Kit - SPEC-First TDD with Alfred SuperAgent
5
5
  Project-URL: Homepage, https://github.com/modu-ai/moai-adk
6
6
  Project-URL: Repository, https://github.com/modu-ai/moai-adk
@@ -603,7 +603,6 @@ src/todo/routes.py # @CODE:TODO-001:API
603
603
  "created_at": "2025-10-17T10:00:00Z"
604
604
  }
605
605
  ```
606
- ```
607
606
 
608
607
  ---
609
608
 
@@ -772,22 +771,6 @@ git pull origin develop
772
771
 
773
772
  ---
774
773
 
775
- ### 시나리오 3: Release 준비
776
-
777
- ```bash
778
- # 표준 방식 (권장):
779
- git checkout develop
780
- gh pr create --base main --head develop --title "Release v1.0.0"
781
-
782
- # 직접 push 방식 (허용):
783
- git checkout develop
784
- git push origin main # ⚠️ Advisory 경고 표시되지만 진행됨
785
- git tag -a v1.0.0 -m "Release v1.0.0"
786
- git push origin v1.0.0
787
- ```
788
-
789
- ---
790
-
791
774
  ## ■ AI 모델 선택 가이드
792
775
 
793
776
  MoAI-ADK는 **Haiku 4.5**와 **Sonnet 4.5** 두 가지 AI 모델을 전략적으로 활용하여 **최적의 성능과 비용 효율**을 제공합니다.
@@ -1,11 +1,11 @@
1
- moai_adk/__init__.py,sha256=vT0ZCxBa_qTqD2oiAZji7pvzfmKXLg_6HC3de1Tkzmo,216
1
+ moai_adk/__init__.py,sha256=zdXpTUQ-OHC67YgbzBHiGqxEvmfizRXENDKBpasoYjE,216
2
2
  moai_adk/__main__.py,sha256=FUUtsqo_NkeY3VR35EjPPtkP3vPkUqRraE30TXMGFL4,2502
3
3
  moai_adk/cli/__init__.py,sha256=tidIaJnd4Pje_5QYRq7OvRRst4T3kaPlkw5QcPQ3l1Y,135
4
4
  moai_adk/cli/main.py,sha256=mHACHi27AP2N7fg7zhzOo1tlF1Jrlw1_AcbxMfpGLVE,306
5
5
  moai_adk/cli/commands/__init__.py,sha256=Gq_obgREC-eFpiYB3IEpYywWj0dy4N0eEbw6q7NxrKs,490
6
6
  moai_adk/cli/commands/backup.py,sha256=Hzf3zc7NhfChAJu2OTN_0xARtUbNaB32fmPczchbrC4,1652
7
7
  moai_adk/cli/commands/doctor.py,sha256=R4Cf9Jqwww1ng36u2SHTh6x0VdmnvaT7G9KVKJRX7N4,6623
8
- moai_adk/cli/commands/init.py,sha256=LhmmrpQh2Wofe0QfMpuZI-DJvtTNzOM5n11NwO9A-cM,10907
8
+ moai_adk/cli/commands/init.py,sha256=dVdBNuCBuwWu-8JBXW8XLX2Acr_6BVa4VsI2I3PP7nA,10409
9
9
  moai_adk/cli/commands/restore.py,sha256=nIhFR9PUQ-XuxZApONVyN77x2lWCjNhn0orL94YD0xs,2691
10
10
  moai_adk/cli/commands/status.py,sha256=YJhh7RoKnumxY0_ho7FWTWm5Nxh2jTnH9aSsapdLhyo,2277
11
11
  moai_adk/cli/commands/update.py,sha256=aoYSR6Nz70sI-KNnkeD_9nZg4CHo5DJkmstnVfoTbrk,5979
@@ -35,10 +35,11 @@ moai_adk/core/template/backup.py,sha256=R187b3ZGQU5f-vQ-iBSFx0aIqbNHJAHODC4ODc3S
35
35
  moai_adk/core/template/config.py,sha256=UbDxqJ-yohwLW3Yzx_6-0RmjCxNRFqzw6bRIC2bS5-w,2712
36
36
  moai_adk/core/template/languages.py,sha256=waeyA_MFy217bV9IiILc2gofG9RM9JhD-kdVGRyJzFk,1648
37
37
  moai_adk/core/template/merger.py,sha256=dvKobOW4vXz-7GWKJpZFYxCMtR-LszcJZYbYFTL3XY0,4049
38
- moai_adk/core/template/processor.py,sha256=uhSEBvAbZtdWyeLJ7I2IuDpla0MUNI0eM04yTV1ktd0,16687
38
+ moai_adk/core/template/processor.py,sha256=_EklBt3jFay235vREsYPNMoDHEM5xAgW3JIGM52jPc8,16179
39
39
  moai_adk/templates/.gitignore,sha256=6VNKResdDpyaii3cmJA4pOLwK2PhYARIWkUODYtKyxg,310
40
+ moai_adk/templates/CLAUDE.md,sha256=xANecTF739Bh2aJX7nExWQcS2Yc_G8jk2HEVZKlmJOo,27286
40
41
  moai_adk/templates/__init__.py,sha256=9YY0tDkKbDFCdUB7rJFtGq0CZbF2ftVSKF573iw0KJc,99
41
- moai_adk/templates/.claude/settings.json,sha256=NvNbDQrbiN806Vv1i8msca9VcIGQBTvzTiiwPhYQpMY,2873
42
+ moai_adk/templates/.claude/settings.json,sha256=-wa_uzvkUc2nE91VJhCAMv5Xrw-gwEW4-f61yhC-olk,2518
42
43
  moai_adk/templates/.claude/agents/alfred/cc-manager.md,sha256=xP3V7QAI-08ga6hhF3J4fXbgiHUM08bJbT2nfE52Bq4,13883
43
44
  moai_adk/templates/.claude/agents/alfred/debug-helper.md,sha256=1Sxz6tBHa-oCoTmwjEZ8ix2OMbjTsOpWUOekQKftlF8,5249
44
45
  moai_adk/templates/.claude/agents/alfred/doc-syncer.md,sha256=kLwLvI-5oRjEG6fSlq8CwwsH3TbqrAY-OWZDcS_3IMo,6223
@@ -51,16 +52,15 @@ moai_adk/templates/.claude/agents/alfred/tag-agent.md,sha256=FGa-BuOl64XEp0fJbQJ
51
52
  moai_adk/templates/.claude/agents/alfred/tdd-implementer.md,sha256=oeJimFgfRuJqBpBT8DE6-n7StIgPFjopYbxxavJSqPM,8544
52
53
  moai_adk/templates/.claude/agents/alfred/trust-checker.md,sha256=eIwFumcJfr66jWdAuWJ5LITHfzzsRBaITGD7iz8EYH4,11647
53
54
  moai_adk/templates/.claude/commands/alfred/0-project.md,sha256=6a19UVvi6BV6mX0312WbQJyN4nsKB7pggTlLgtxwcFM,17831
54
- moai_adk/templates/.claude/commands/alfred/1-spec.md,sha256=b972C0B7VU6P8eQZxKdn72ikwJ_f7HZZPi-IMtnKky4,20268
55
- moai_adk/templates/.claude/commands/alfred/2-build.md,sha256=iATuR8W3taOe83QY2E4SmHxKCvE790WOIgF765mlr4w,17322
56
- moai_adk/templates/.claude/commands/alfred/3-sync.md,sha256=hkL33VXE_e-2xD2R35LFBi_fcCmulkMgFBIPgNLmVgk,19493
55
+ moai_adk/templates/.claude/commands/alfred/1-spec.md,sha256=dpaOJWxK2zjU2wI7uvVfY16SDyGzN-HsUcIepPO8sCM,20365
56
+ moai_adk/templates/.claude/commands/alfred/2-build.md,sha256=cEvXk9gadL2twrkDf3p2w8lzrCt3JkMUx-T0MtnLN7U,17429
57
+ moai_adk/templates/.claude/commands/alfred/3-sync.md,sha256=5rYopDYzJHKEG400CuHoSWP5xBppcZNTFCu2GlFNVs0,19610
57
58
  moai_adk/templates/.claude/hooks/alfred/README.md,sha256=1E_nUaFj_50UTXIfFnkNLTy4qZHCs_R3gzhBoekf4Pk,6823
58
59
  moai_adk/templates/.claude/hooks/alfred/alfred_hooks.py,sha256=vffNW0u2RXZ_jG3EzIggxEv23fDuh2qtU7oF7PZIW6A,6943
59
- moai_adk/templates/.claude/hooks/alfred/core/__init__.py,sha256=No6VZOruX83zHq48SGcOJiza6HIut9VtsVkevaaFT88,2490
60
+ moai_adk/templates/.claude/hooks/alfred/core/__init__.py,sha256=5sHy-OPaGxBXizSRaEBeydm8U3MW1ANWxSB_36m0hz4,2775
60
61
  moai_adk/templates/.claude/hooks/alfred/core/checkpoint.py,sha256=vAm5hEqXUT2frkXFSrJf2W6uOd24Bi7O0Qr51ll51Jw,8543
61
- moai_adk/templates/.claude/hooks/alfred/core/context.py,sha256=0FBagGq9cvYFqmjl8eZvDL9g5KAh1KvTvHpQMvtR6v4,3410
62
+ moai_adk/templates/.claude/hooks/alfred/core/context.py,sha256=-PHNNktkULYL9jpIjDqpBgTNYqFo7O1QdrPbgbe52rk,2155
62
63
  moai_adk/templates/.claude/hooks/alfred/core/project.py,sha256=h7s2D0e5zn0BKu3GReMVH93ojKOTkF6yyLWNnoJI6-0,9103
63
- moai_adk/templates/.claude/hooks/alfred/core/tags.py,sha256=QAT7Oh8eupawGiZnaYDEcPhdlm1LGyzVF-Hv6SKZ_5g,7711
64
64
  moai_adk/templates/.claude/hooks/alfred/handlers/__init__.py,sha256=mk1FQFj5V3rxyV1BQbd8bZE9R-IK4nanj61oO7jhbdw,577
65
65
  moai_adk/templates/.claude/hooks/alfred/handlers/notification.py,sha256=MjwaCRSbK4f-YvRC9CG4Rg8dhQir1gzPqF02x9O_4Gc,655
66
66
  moai_adk/templates/.claude/hooks/alfred/handlers/session.py,sha256=6zz0uJ3cYtnY8gXtoP0cRf6LmmQUfggLWIJduokd-Jw,2783
@@ -76,14 +76,14 @@ moai_adk/templates/.moai/hooks/pre-push.sample,sha256=zpQOWHxpV_XjTAnyp1dTrM39Iz
76
76
  moai_adk/templates/.moai/memory/development-guide.md,sha256=YMepw_MT0-YDK6rQlKvWOULAMGtPDH-WJA6wIYiSMwU,14717
77
77
  moai_adk/templates/.moai/memory/gitflow-protection-policy.md,sha256=xmRXA9erdH4EgpRdd0inKGat6HEZ8HP-4BQthjLyoZ4,6529
78
78
  moai_adk/templates/.moai/memory/spec-metadata.md,sha256=EZ_GMCG-yRwvvCotD6oSGR350hg090fodQkxPuWNYso,7350
79
- moai_adk/templates/.moai/project/product.md,sha256=Aglyj5iaasCW9nNB3gqFPoBslnzS5hXg_1n_QZQa15U,3661
80
- moai_adk/templates/.moai/project/structure.md,sha256=bAImWQG01zH1EOd7F94rd87b_P6JlOCH-MGmCuS-Lxs,4985
81
- moai_adk/templates/.moai/project/tech.md,sha256=devxbvmgTG3_1x3dYNPHtje2gU1aJ403luztHK0DRhI,5854
79
+ moai_adk/templates/.moai/project/product.md,sha256=ClDlG1q7P8aX4cjroXLUZIQGd2wBZt6xD-w9RXMOYfk,5731
80
+ moai_adk/templates/.moai/project/structure.md,sha256=jesU7Om-fZANmj0NdgiU_oY0aT7102QWwuYy7Q-drKA,5180
81
+ moai_adk/templates/.moai/project/tech.md,sha256=1BgkApeFqQCq6TPriGiev02G9niVx23cEA2RH-28dtw,6049
82
82
  moai_adk/utils/__init__.py,sha256=fv-UwHv8r4-eedwRnDA9hFjo5QSZYXjctKDyE7XF10g,220
83
83
  moai_adk/utils/banner.py,sha256=TmZyJKXOnJpdbdn6NZDJC6a4hm051QudEvOfiKQhvI8,1873
84
84
  moai_adk/utils/logger.py,sha256=jYCWKvcN-tX17hZ-e2IPuHATwkQBFc_I1dd5fUTWxmY,5059
85
- moai_adk-0.3.7.dist-info/METADATA,sha256=yojcfUIOeuNslQh-HSPEvIdTW_XWDi2cL8cATt-FjD8,50289
86
- moai_adk-0.3.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
87
- moai_adk-0.3.7.dist-info/entry_points.txt,sha256=P9no1794UipqH72LP-ltdyfVd_MeB1WKJY_6-JQgV3U,52
88
- moai_adk-0.3.7.dist-info/licenses/LICENSE,sha256=M1M2b07fWcSWRM6_P3wbZKndZvyfHyYk_Wu9bS8F7o8,1069
89
- moai_adk-0.3.7.dist-info/RECORD,,
85
+ moai_adk-0.3.10.dist-info/METADATA,sha256=xJtnrnXZna5oSyjS0kZa4SRTbf-H0APs7cSYXvhoHdk,49933
86
+ moai_adk-0.3.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
87
+ moai_adk-0.3.10.dist-info/entry_points.txt,sha256=P9no1794UipqH72LP-ltdyfVd_MeB1WKJY_6-JQgV3U,52
88
+ moai_adk-0.3.10.dist-info/licenses/LICENSE,sha256=M1M2b07fWcSWRM6_P3wbZKndZvyfHyYk_Wu9bS8F7o8,1069
89
+ moai_adk-0.3.10.dist-info/RECORD,,
@@ -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
- ]