atdd 0.3.1__py3-none-any.whl → 0.3.3__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.
- atdd/cli.py +6 -2
- atdd/coach/commands/initializer.py +10 -0
- atdd/coach/commands/sync.py +7 -0
- atdd/coach/templates/ATDD.md +29 -0
- atdd/coach/templates/SESSION-TEMPLATE.md +25 -0
- atdd/version_check.py +111 -3
- {atdd-0.3.1.dist-info → atdd-0.3.3.dist-info}/METADATA +1 -1
- {atdd-0.3.1.dist-info → atdd-0.3.3.dist-info}/RECORD +12 -12
- {atdd-0.3.1.dist-info → atdd-0.3.3.dist-info}/WHEEL +0 -0
- {atdd-0.3.1.dist-info → atdd-0.3.3.dist-info}/entry_points.txt +0 -0
- {atdd-0.3.1.dist-info → atdd-0.3.3.dist-info}/licenses/LICENSE +0 -0
- {atdd-0.3.1.dist-info → atdd-0.3.3.dist-info}/top_level.txt +0 -0
atdd/cli.py
CHANGED
|
@@ -45,7 +45,7 @@ from atdd.coach.commands.session import SessionManager
|
|
|
45
45
|
from atdd.coach.commands.sync import AgentConfigSync
|
|
46
46
|
from atdd.coach.commands.gate import ATDDGate
|
|
47
47
|
from atdd.coach.utils.repo import find_repo_root
|
|
48
|
-
from atdd.version_check import print_update_notice
|
|
48
|
+
from atdd.version_check import print_update_notice, print_upgrade_sync_notice
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
class ATDDCoach:
|
|
@@ -436,10 +436,14 @@ Phase descriptions:
|
|
|
436
436
|
|
|
437
437
|
|
|
438
438
|
def cli() -> int:
|
|
439
|
-
"""CLI entry point with version
|
|
439
|
+
"""CLI entry point with version and upgrade checks."""
|
|
440
|
+
# Check if repo needs sync after ATDD upgrade (at startup)
|
|
441
|
+
print_upgrade_sync_notice()
|
|
442
|
+
|
|
440
443
|
try:
|
|
441
444
|
result = main()
|
|
442
445
|
finally:
|
|
446
|
+
# Check for newer versions on PyPI (at end)
|
|
443
447
|
print_update_notice()
|
|
444
448
|
return result
|
|
445
449
|
|
|
@@ -160,11 +160,21 @@ class ProjectInitializer:
|
|
|
160
160
|
print(f"Config already exists: {self.config_file}")
|
|
161
161
|
return
|
|
162
162
|
|
|
163
|
+
# Get installed ATDD version
|
|
164
|
+
try:
|
|
165
|
+
from atdd import __version__
|
|
166
|
+
toolkit_version = __version__
|
|
167
|
+
except ImportError:
|
|
168
|
+
toolkit_version = "0.0.0"
|
|
169
|
+
|
|
163
170
|
config = {
|
|
164
171
|
"version": "1.0",
|
|
165
172
|
"sync": {
|
|
166
173
|
"agents": ["claude"], # Default: only Claude
|
|
167
174
|
},
|
|
175
|
+
"toolkit": {
|
|
176
|
+
"last_version": toolkit_version, # Track installed version
|
|
177
|
+
},
|
|
168
178
|
}
|
|
169
179
|
|
|
170
180
|
with open(self.config_file, "w") as f:
|
atdd/coach/commands/sync.py
CHANGED
|
@@ -115,6 +115,13 @@ class AgentConfigSync:
|
|
|
115
115
|
unchanged_count += 1
|
|
116
116
|
|
|
117
117
|
print(f"\nSync complete: {synced_count} updated, {unchanged_count} unchanged")
|
|
118
|
+
|
|
119
|
+
# Update toolkit.last_version to mark sync complete
|
|
120
|
+
from atdd.version_check import update_toolkit_version
|
|
121
|
+
if update_toolkit_version(self.config_file):
|
|
122
|
+
from atdd import __version__
|
|
123
|
+
print(f"Updated toolkit.last_version to {__version__}")
|
|
124
|
+
|
|
118
125
|
return 0
|
|
119
126
|
|
|
120
127
|
def verify(self) -> int:
|
atdd/coach/templates/ATDD.md
CHANGED
|
@@ -219,6 +219,35 @@ git:
|
|
|
219
219
|
- "GREEN: commit passing implementation"
|
|
220
220
|
- "REFACTOR: commit clean architecture"
|
|
221
221
|
|
|
222
|
+
# Release Gate (MANDATORY - session completion)
|
|
223
|
+
# Every session MUST end with version bump + tag
|
|
224
|
+
release:
|
|
225
|
+
mandatory: true
|
|
226
|
+
|
|
227
|
+
rules:
|
|
228
|
+
- "Tag must match version exactly: v{version}"
|
|
229
|
+
- "No tag without version bump"
|
|
230
|
+
- "No version bump without tag"
|
|
231
|
+
- "Every repo MUST have versioning"
|
|
232
|
+
|
|
233
|
+
change_class:
|
|
234
|
+
PATCH: "bug fixes, docs, refactors, internal changes"
|
|
235
|
+
MINOR: "new feature, new validator, new command, new convention (non-breaking)"
|
|
236
|
+
MAJOR: "breaking API/CLI/schema/convention change or behavior removal"
|
|
237
|
+
|
|
238
|
+
workflow:
|
|
239
|
+
- "Determine change class"
|
|
240
|
+
- "Bump version in version file"
|
|
241
|
+
- "Commit: 'Bump version to {version}'"
|
|
242
|
+
- "Create tag: git tag v{version}"
|
|
243
|
+
- "Push with tags: git push origin {branch} --tags"
|
|
244
|
+
- "Record in Session Log: 'Released: v{version}'"
|
|
245
|
+
|
|
246
|
+
# Consumer repos configure version file location in .atdd/config.yaml:
|
|
247
|
+
# release:
|
|
248
|
+
# version_file: "pyproject.toml" # or package.json, VERSION, etc.
|
|
249
|
+
# tag_prefix: "v"
|
|
250
|
+
|
|
222
251
|
# Agent Coordination (Detailed in action files)
|
|
223
252
|
agents:
|
|
224
253
|
planner:
|
|
@@ -331,6 +331,31 @@ Reference: src/atdd/coach/conventions/session.convention.yaml
|
|
|
331
331
|
|
|
332
332
|
---
|
|
333
333
|
|
|
334
|
+
## Release Gate (MANDATORY)
|
|
335
|
+
|
|
336
|
+
<!--
|
|
337
|
+
Every session MUST end with a version bump + matching git tag.
|
|
338
|
+
|
|
339
|
+
Change Class:
|
|
340
|
+
- PATCH: bug fixes, docs, refactors, internal changes
|
|
341
|
+
- MINOR: new feature, new validator, new command, new convention (non-breaking)
|
|
342
|
+
- MAJOR: breaking API/CLI/schema/convention change or behavior removal
|
|
343
|
+
|
|
344
|
+
Rules:
|
|
345
|
+
- Tag must match version exactly: v{version}
|
|
346
|
+
- No tag without version bump
|
|
347
|
+
- No version bump without tag
|
|
348
|
+
-->
|
|
349
|
+
|
|
350
|
+
- [ ] Determine change class: PATCH / MINOR / MAJOR
|
|
351
|
+
- [ ] Bump version in version file (pyproject.toml, package.json, etc.)
|
|
352
|
+
- [ ] Commit: "Bump version to {version}"
|
|
353
|
+
- [ ] Create tag: `git tag v{version}`
|
|
354
|
+
- [ ] Push with tags: `git push origin {branch} --tags`
|
|
355
|
+
- [ ] Record tag in Session Log: "Released: v{version}"
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
334
359
|
## Notes
|
|
335
360
|
|
|
336
361
|
{Additional context, learnings, or decisions that don't fit elsewhere.}
|
atdd/version_check.py
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Version check for ATDD CLI.
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
Two types of version checks:
|
|
5
|
+
1. PyPI update check - notifies when a newer version is available on PyPI
|
|
6
|
+
2. Repo sync check - notifies when installed version is newer than repo's last_version
|
|
6
7
|
|
|
7
8
|
Cache location: ~/.atdd/version_cache.json
|
|
8
|
-
Disable: Set ATDD_NO_UPDATE_CHECK=1
|
|
9
|
+
Disable PyPI check: Set ATDD_NO_UPDATE_CHECK=1
|
|
10
|
+
Disable sync reminder: Set ATDD_NO_UPGRADE_NOTICE=1
|
|
9
11
|
"""
|
|
10
12
|
import json
|
|
11
13
|
import os
|
|
@@ -16,6 +18,8 @@ from typing import Optional, Tuple
|
|
|
16
18
|
from urllib.request import urlopen
|
|
17
19
|
from urllib.error import URLError
|
|
18
20
|
|
|
21
|
+
import yaml
|
|
22
|
+
|
|
19
23
|
from atdd import __version__
|
|
20
24
|
|
|
21
25
|
# Check once per day (86400 seconds)
|
|
@@ -124,3 +128,107 @@ def print_update_notice() -> None:
|
|
|
124
128
|
print(notice, file=sys.stderr)
|
|
125
129
|
except Exception:
|
|
126
130
|
pass # Never fail the main command due to version check
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# --- Repo sync upgrade check ---
|
|
134
|
+
|
|
135
|
+
def _load_repo_config() -> Tuple[Optional[dict], Optional[Path]]:
|
|
136
|
+
"""
|
|
137
|
+
Load .atdd/config.yaml from current directory.
|
|
138
|
+
|
|
139
|
+
Returns:
|
|
140
|
+
Tuple of (config_dict, config_path) or (None, None) if not found.
|
|
141
|
+
"""
|
|
142
|
+
config_path = Path.cwd() / ".atdd" / "config.yaml"
|
|
143
|
+
if not config_path.exists():
|
|
144
|
+
return None, None
|
|
145
|
+
|
|
146
|
+
try:
|
|
147
|
+
with open(config_path) as f:
|
|
148
|
+
return yaml.safe_load(f) or {}, config_path
|
|
149
|
+
except (yaml.YAMLError, OSError):
|
|
150
|
+
return None, None
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _get_last_toolkit_version(config: dict) -> Optional[str]:
|
|
154
|
+
"""Extract toolkit.last_version from config."""
|
|
155
|
+
toolkit = config.get("toolkit", {})
|
|
156
|
+
return toolkit.get("last_version")
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def check_upgrade_sync_needed() -> Optional[str]:
|
|
160
|
+
"""
|
|
161
|
+
Check if repo needs sync after ATDD upgrade.
|
|
162
|
+
|
|
163
|
+
Compares installed version vs toolkit.last_version in .atdd/config.yaml.
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
Message to display if sync needed, None otherwise.
|
|
167
|
+
"""
|
|
168
|
+
# Respect disable flag
|
|
169
|
+
if os.environ.get("ATDD_NO_UPGRADE_NOTICE", "").lower() in ("1", "true", "yes"):
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
# Skip if running in development
|
|
173
|
+
if __version__ == "0.0.0":
|
|
174
|
+
return None
|
|
175
|
+
|
|
176
|
+
config, config_path = _load_repo_config()
|
|
177
|
+
if config is None:
|
|
178
|
+
# No .atdd/config.yaml - not an ATDD repo or not initialized
|
|
179
|
+
return None
|
|
180
|
+
|
|
181
|
+
last_version = _get_last_toolkit_version(config)
|
|
182
|
+
if last_version is None:
|
|
183
|
+
# First run or old config without toolkit.last_version
|
|
184
|
+
# Treat as needing sync
|
|
185
|
+
return f"ATDD upgraded to {__version__}. Run: atdd sync"
|
|
186
|
+
|
|
187
|
+
# Compare versions
|
|
188
|
+
if _is_newer(__version__, last_version):
|
|
189
|
+
return f"ATDD upgraded ({last_version} → {__version__}). Run: atdd sync"
|
|
190
|
+
|
|
191
|
+
return None
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def update_toolkit_version(config_path: Optional[Path] = None) -> bool:
|
|
195
|
+
"""
|
|
196
|
+
Update toolkit.last_version in .atdd/config.yaml to current installed version.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
config_path: Path to config file. Defaults to .atdd/config.yaml in cwd.
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
True if updated, False otherwise.
|
|
203
|
+
"""
|
|
204
|
+
if config_path is None:
|
|
205
|
+
config_path = Path.cwd() / ".atdd" / "config.yaml"
|
|
206
|
+
|
|
207
|
+
if not config_path.exists():
|
|
208
|
+
return False
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
with open(config_path) as f:
|
|
212
|
+
config = yaml.safe_load(f) or {}
|
|
213
|
+
|
|
214
|
+
# Update toolkit.last_version
|
|
215
|
+
if "toolkit" not in config:
|
|
216
|
+
config["toolkit"] = {}
|
|
217
|
+
config["toolkit"]["last_version"] = __version__
|
|
218
|
+
|
|
219
|
+
with open(config_path, "w") as f:
|
|
220
|
+
yaml.dump(config, f, default_flow_style=False, sort_keys=False)
|
|
221
|
+
|
|
222
|
+
return True
|
|
223
|
+
except (yaml.YAMLError, OSError):
|
|
224
|
+
return False
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def print_upgrade_sync_notice() -> None:
|
|
228
|
+
"""Print upgrade sync notice to stderr if needed."""
|
|
229
|
+
try:
|
|
230
|
+
notice = check_upgrade_sync_needed()
|
|
231
|
+
if notice:
|
|
232
|
+
print(f"\n⚠️ {notice}\n", file=sys.stderr)
|
|
233
|
+
except Exception:
|
|
234
|
+
pass # Never fail the main command
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
atdd/__init__.py,sha256=-S8i9OahH-t9FJkPn6nprxipnjVum3rLeVsCS74T6eY,156
|
|
2
2
|
atdd/__main__.py,sha256=B0sXDQLjFN9GowTlXo4NMWwPZPjDsrT8Frq7DnbdOD8,77
|
|
3
|
-
atdd/cli.py,sha256=
|
|
3
|
+
atdd/cli.py,sha256=IiD7CpLEOSpgldgI55bc540cBGwKug_rUiih41aq5R4,14722
|
|
4
4
|
atdd/conftest.py,sha256=Fj3kIhCETbj2QBCIjySBgdS3stKNRZcZzKTJr7A4LaQ,5300
|
|
5
|
-
atdd/version_check.py,sha256=
|
|
5
|
+
atdd/version_check.py,sha256=BlPcLwzNnm457vWUolB3wMtZEI-fXvpzfm6p8U_j7rc,6684
|
|
6
6
|
atdd/coach/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
atdd/coach/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
8
|
atdd/coach/commands/add_persistence_metadata.py,sha256=xAdeO9k53CIGTBhzNQbWenuzeoWKZimDBR9xBWaA3NU,6887
|
|
@@ -10,13 +10,13 @@ atdd/coach/commands/analyze_migrations.py,sha256=2bLfR7OwicBXAZWB4R3Sm4d5jFe87d0
|
|
|
10
10
|
atdd/coach/commands/consumers.py,sha256=7vTexse8xznXSzNWjPGYuF4iJ8ZWymmOSkpcA6IWyxU,27514
|
|
11
11
|
atdd/coach/commands/gate.py,sha256=_V2GypqoGixTs_kLWxFF3HgEt-Wi2r6Iv0YL75yWrWo,5829
|
|
12
12
|
atdd/coach/commands/infer_governance_status.py,sha256=91-VnI64mOzijc1Cgkmr7cnNCir2-z2ITA2-SGwk3TU,4473
|
|
13
|
-
atdd/coach/commands/initializer.py,sha256=
|
|
13
|
+
atdd/coach/commands/initializer.py,sha256=s7NnITF4c6xGlN6ZJVjyv4a4jxGMjK9OPG1C-OIG55A,6385
|
|
14
14
|
atdd/coach/commands/interface.py,sha256=PPCwICFNN4ddPqucUATIiBrfEkDO66MZbYQkwNu6lm4,40459
|
|
15
15
|
atdd/coach/commands/inventory.py,sha256=Xakb6U3SfnEcR7rhZ0Wg8SK5frg-oPE7C0fCvE-VoH4,20923
|
|
16
16
|
atdd/coach/commands/migration.py,sha256=KlRXXM1O-ZqfwGOWxN5C_gxfTttbXUG_yq9pOLYsGnQ,8119
|
|
17
17
|
atdd/coach/commands/registry.py,sha256=r1QWg841eK6bS4vEbYEviylDCpFkInUVMTsf5h4ArrQ,58344
|
|
18
18
|
atdd/coach/commands/session.py,sha256=MhuWXd5TR6bB3w0t8vANeZx3L476qwLT6EUQMwg-wQA,14268
|
|
19
|
-
atdd/coach/commands/sync.py,sha256=
|
|
19
|
+
atdd/coach/commands/sync.py,sha256=4HNzg8AVaePDwhyBlQcywvNVZDP5NIW8TBsEPbqmJuQ,12545
|
|
20
20
|
atdd/coach/commands/test_interface.py,sha256=a7ut2Hhk0PnQ5LfJZkoQwfkfkVuB5OHA4QBwOS0-jcg,16870
|
|
21
21
|
atdd/coach/commands/test_runner.py,sha256=Lutclc8Qr8BmLBvAYshXAjf8ynUM4eJgHF8GLPa1Usw,3929
|
|
22
22
|
atdd/coach/commands/traceability.py,sha256=SYl0dRB_nQZJKe1IOCHxX193vaxOChVjnh6hcqcSOB0,163581
|
|
@@ -27,8 +27,8 @@ atdd/coach/overlays/__init__.py,sha256=2lMiMSgfLJ3YHLpbzNI5B88AdQxiMEwjIfsWWb8t3
|
|
|
27
27
|
atdd/coach/overlays/claude.md,sha256=33mhpqhmsRhCtdWlU7cMXAJDsaVra9uBBK8URV8OtQA,101
|
|
28
28
|
atdd/coach/schemas/config.schema.json,sha256=xzct7gBoPTIGh3NFPSGtfW0zIiyFdHDZkvjuy1qgAqA,951
|
|
29
29
|
atdd/coach/schemas/manifest.schema.json,sha256=WO13-YF_FgH1awh96khCtk-112b6XSC24anlY3B7GjY,2885
|
|
30
|
-
atdd/coach/templates/ATDD.md,sha256=
|
|
31
|
-
atdd/coach/templates/SESSION-TEMPLATE.md,sha256=
|
|
30
|
+
atdd/coach/templates/ATDD.md,sha256=eHdibGHQ66U5sYUvZFzLmTP3Z9J8P-J6dUzrYbjAd_w,13139
|
|
31
|
+
atdd/coach/templates/SESSION-TEMPLATE.md,sha256=CPrCh279fQzDmgVob24ctH-vvKpUHr2SrJ3RLCiV05o,9898
|
|
32
32
|
atdd/coach/utils/__init__.py,sha256=7Jbo-heJEKSAn6I0s35z_2S4R8qGZ48PL6a2IntcNYg,148
|
|
33
33
|
atdd/coach/utils/repo.py,sha256=9rZeAf1b7-modoTiPZAwtjnoiI8YyHWIZhpqXvkJ7Qo,3104
|
|
34
34
|
atdd/coach/utils/graph/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -181,9 +181,9 @@ atdd/tester/validators/test_red_supabase_layer_structure.py,sha256=26cnzPZAwSFy0
|
|
|
181
181
|
atdd/tester/validators/test_telemetry_structure.py,sha256=hIUnU2WU-8PNIg9EVHe2fnUdIQKIOUm5AWEtCBUXLVk,22467
|
|
182
182
|
atdd/tester/validators/test_typescript_test_naming.py,sha256=E-TyGv_GVlTfsbyuxrtv9sOWSZS_QcpH6rrJFbWoeeU,11280
|
|
183
183
|
atdd/tester/validators/test_typescript_test_structure.py,sha256=eV89SD1RaKtchBZupqhnJmaruoROosf3LwB4Fwe4UJI,2612
|
|
184
|
-
atdd-0.3.
|
|
185
|
-
atdd-0.3.
|
|
186
|
-
atdd-0.3.
|
|
187
|
-
atdd-0.3.
|
|
188
|
-
atdd-0.3.
|
|
189
|
-
atdd-0.3.
|
|
184
|
+
atdd-0.3.3.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
185
|
+
atdd-0.3.3.dist-info/METADATA,sha256=K0LQB_4qxlKQ4o7hmBpSDG2zMRoNVbI4QCUggzEb4ws,7081
|
|
186
|
+
atdd-0.3.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
187
|
+
atdd-0.3.3.dist-info/entry_points.txt,sha256=-C3yrA1WQQfN3iuGmSzPapA5cKVBEYU5Q1HUffSJTbY,38
|
|
188
|
+
atdd-0.3.3.dist-info/top_level.txt,sha256=VKkf6Uiyrm4RS6ULCGM-v8AzYN8K2yg8SMqwJLoO-xs,5
|
|
189
|
+
atdd-0.3.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|