codexspec 0.7.16__tar.gz → 0.7.17__tar.gz

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.
Files changed (102) hide show
  1. {codexspec-0.7.16 → codexspec-0.7.17}/PKG-INFO +1 -1
  2. {codexspec-0.7.16 → codexspec-0.7.17}/pyproject.toml +1 -1
  3. {codexspec-0.7.16 → codexspec-0.7.17}/src/codexspec/__init__.py +120 -1
  4. codexspec-0.7.17/src/codexspec/distill_review/__init__.py +13 -0
  5. codexspec-0.7.17/src/codexspec/distill_review/assets/app.js +938 -0
  6. codexspec-0.7.17/src/codexspec/distill_review/assets/i18n/ar.json +112 -0
  7. codexspec-0.7.17/src/codexspec/distill_review/assets/i18n/de.json +112 -0
  8. codexspec-0.7.17/src/codexspec/distill_review/assets/i18n/en.json +112 -0
  9. codexspec-0.7.17/src/codexspec/distill_review/assets/i18n/es.json +112 -0
  10. codexspec-0.7.17/src/codexspec/distill_review/assets/i18n/fr.json +112 -0
  11. codexspec-0.7.17/src/codexspec/distill_review/assets/i18n/hi.json +112 -0
  12. codexspec-0.7.17/src/codexspec/distill_review/assets/i18n/it.json +112 -0
  13. codexspec-0.7.17/src/codexspec/distill_review/assets/i18n/ja.json +112 -0
  14. codexspec-0.7.17/src/codexspec/distill_review/assets/i18n/ko.json +112 -0
  15. codexspec-0.7.17/src/codexspec/distill_review/assets/i18n/pt.json +112 -0
  16. codexspec-0.7.17/src/codexspec/distill_review/assets/i18n/ru.json +112 -0
  17. codexspec-0.7.17/src/codexspec/distill_review/assets/i18n/zh-CN.json +112 -0
  18. codexspec-0.7.17/src/codexspec/distill_review/assets/i18n/zh-TW.json +112 -0
  19. codexspec-0.7.17/src/codexspec/distill_review/assets/index.html +43 -0
  20. codexspec-0.7.17/src/codexspec/distill_review/assets/styles.css +824 -0
  21. codexspec-0.7.17/src/codexspec/distill_review/domain.py +585 -0
  22. codexspec-0.7.17/src/codexspec/distill_review/lease.py +101 -0
  23. codexspec-0.7.17/src/codexspec/distill_review/models.py +133 -0
  24. codexspec-0.7.17/src/codexspec/distill_review/records.py +399 -0
  25. codexspec-0.7.17/src/codexspec/distill_review/server.py +386 -0
  26. codexspec-0.7.17/src/codexspec/distill_review/session.py +323 -0
  27. codexspec-0.7.17/src/codexspec/distill_review/terminal.py +259 -0
  28. codexspec-0.7.17/src/codexspec/distill_review/transaction.py +932 -0
  29. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/distill.md +48 -4
  30. {codexspec-0.7.16 → codexspec-0.7.17}/.gitignore +0 -0
  31. {codexspec-0.7.16 → codexspec-0.7.17}/LICENSE +0 -0
  32. {codexspec-0.7.16 → codexspec-0.7.17}/README.md +0 -0
  33. {codexspec-0.7.16 → codexspec-0.7.17}/codexspec-icon.svg +0 -0
  34. {codexspec-0.7.16 → codexspec-0.7.17}/codexspec-logo-dark.svg +0 -0
  35. {codexspec-0.7.16 → codexspec-0.7.17}/codexspec-logo-light.svg +0 -0
  36. {codexspec-0.7.16 → codexspec-0.7.17}/scripts/bash/check-i18n-completeness.sh +0 -0
  37. {codexspec-0.7.16 → codexspec-0.7.17}/scripts/bash/check-i18n-structure.sh +0 -0
  38. {codexspec-0.7.16 → codexspec-0.7.17}/scripts/bash/check-prerequisites.sh +0 -0
  39. {codexspec-0.7.16 → codexspec-0.7.17}/scripts/bash/common.sh +0 -0
  40. {codexspec-0.7.16 → codexspec-0.7.17}/scripts/bash/create-new-feature.sh +0 -0
  41. {codexspec-0.7.16 → codexspec-0.7.17}/scripts/bash/review-context.sh +0 -0
  42. {codexspec-0.7.16 → codexspec-0.7.17}/scripts/powershell/check-prerequisites.ps1 +0 -0
  43. {codexspec-0.7.16 → codexspec-0.7.17}/scripts/powershell/common.ps1 +0 -0
  44. {codexspec-0.7.16 → codexspec-0.7.17}/scripts/powershell/create-new-feature.ps1 +0 -0
  45. {codexspec-0.7.16 → codexspec-0.7.17}/scripts/powershell/review-context.ps1 +0 -0
  46. {codexspec-0.7.16 → codexspec-0.7.17}/src/codexspec/automation.py +0 -0
  47. {codexspec-0.7.16 → codexspec-0.7.17}/src/codexspec/blueprint.py +0 -0
  48. {codexspec-0.7.16 → codexspec-0.7.17}/src/codexspec/commands/__init__.py +0 -0
  49. {codexspec-0.7.16 → codexspec-0.7.17}/src/codexspec/commands/installer.py +0 -0
  50. {codexspec-0.7.16 → codexspec-0.7.17}/src/codexspec/i18n.py +0 -0
  51. {codexspec-0.7.16 → codexspec-0.7.17}/src/codexspec/idea.md +0 -0
  52. {codexspec-0.7.16 → codexspec-0.7.17}/src/codexspec/integrations/__init__.py +0 -0
  53. {codexspec-0.7.16 → codexspec-0.7.17}/src/codexspec/integrations/base.py +0 -0
  54. {codexspec-0.7.16 → codexspec-0.7.17}/src/codexspec/integrations/claude.py +0 -0
  55. {codexspec-0.7.16 → codexspec-0.7.17}/src/codexspec/integrations/codex.py +0 -0
  56. {codexspec-0.7.16 → codexspec-0.7.17}/src/codexspec/profile.py +0 -0
  57. {codexspec-0.7.16 → codexspec-0.7.17}/src/codexspec/translator.py +0 -0
  58. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/analyze.md +0 -0
  59. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/auto-dev.md +0 -0
  60. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/blueprint.md +0 -0
  61. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/checklist.md +0 -0
  62. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/clarify.md +0 -0
  63. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/commit-staged.md +0 -0
  64. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/config.md +0 -0
  65. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/constitution.md +0 -0
  66. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/debug.md +0 -0
  67. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/evolve.md +0 -0
  68. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/generate-spec.md +0 -0
  69. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/implement-tasks.md +0 -0
  70. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/onboard.md +0 -0
  71. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/plan-to-tasks.md +0 -0
  72. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/pr.md +0 -0
  73. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/quick.md +0 -0
  74. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/release-notes.md +0 -0
  75. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/reverse-spec.md +0 -0
  76. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/review-code.md +0 -0
  77. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/review-design.md +0 -0
  78. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/review-plan.md +0 -0
  79. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/review-spec.md +0 -0
  80. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/review-tasks.md +0 -0
  81. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/spec-to-design.md +0 -0
  82. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/spec-to-plan.md +0 -0
  83. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/specify.md +0 -0
  84. {codexspec-0.7.16 → codexspec-0.7.17}/templates/commands/tasks-to-issues.md +0 -0
  85. {codexspec-0.7.16 → codexspec-0.7.17}/templates/docs/checklist-template.md +0 -0
  86. {codexspec-0.7.16 → codexspec-0.7.17}/templates/docs/constitution-template.md +0 -0
  87. {codexspec-0.7.16 → codexspec-0.7.17}/templates/docs/design-template.md +0 -0
  88. {codexspec-0.7.16 → codexspec-0.7.17}/templates/docs/plan-template-detailed.md +0 -0
  89. {codexspec-0.7.16 → codexspec-0.7.17}/templates/docs/plan-template-simple.md +0 -0
  90. {codexspec-0.7.16 → codexspec-0.7.17}/templates/docs/requirements-template.md +0 -0
  91. {codexspec-0.7.16 → codexspec-0.7.17}/templates/docs/spec-template-detailed.md +0 -0
  92. {codexspec-0.7.16 → codexspec-0.7.17}/templates/docs/spec-template-simple.md +0 -0
  93. {codexspec-0.7.16 → codexspec-0.7.17}/templates/docs/tasks-template-detailed.md +0 -0
  94. {codexspec-0.7.16 → codexspec-0.7.17}/templates/docs/tasks-template-simple.md +0 -0
  95. {codexspec-0.7.16 → codexspec-0.7.17}/templates/translations/de.json +0 -0
  96. {codexspec-0.7.16 → codexspec-0.7.17}/templates/translations/en.json +0 -0
  97. {codexspec-0.7.16 → codexspec-0.7.17}/templates/translations/es.json +0 -0
  98. {codexspec-0.7.16 → codexspec-0.7.17}/templates/translations/fr.json +0 -0
  99. {codexspec-0.7.16 → codexspec-0.7.17}/templates/translations/ja.json +0 -0
  100. {codexspec-0.7.16 → codexspec-0.7.17}/templates/translations/ko.json +0 -0
  101. {codexspec-0.7.16 → codexspec-0.7.17}/templates/translations/pt-BR.json +0 -0
  102. {codexspec-0.7.16 → codexspec-0.7.17}/templates/translations/zh-CN.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: codexspec
3
- Version: 0.7.16
3
+ Version: 0.7.17
4
4
  Summary: CodexSpec - A Requirements-First SDD toolkit for Claude Code
5
5
  Project-URL: Homepage, https://github.com/Zts0hg/codexspec
6
6
  Project-URL: Repository, https://github.com/Zts0hg/codexspec
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "codexspec"
3
- version = "0.7.16"
3
+ version = "0.7.17"
4
4
  description = "CodexSpec - A Requirements-First SDD toolkit for Claude Code"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -8,8 +8,10 @@ executable specifications that guide AI-assisted implementation.
8
8
 
9
9
  import json
10
10
  import re
11
+ import secrets
11
12
  import subprocess
12
13
  import sys
14
+ import webbrowser
13
15
  from datetime import datetime
14
16
  from pathlib import Path
15
17
  from typing import Optional
@@ -43,6 +45,12 @@ from .commands.installer import (
43
45
  should_update_commands,
44
46
  update_installed_command_frontmatter,
45
47
  )
48
+ from .distill_review.domain import ReviewError, ReviewService
49
+ from .distill_review.lease import ActiveSessionError, ReviewLease
50
+ from .distill_review.server import create_server
51
+ from .distill_review.session import SessionError, SessionStore, ensure_runtime_ignored
52
+ from .distill_review.terminal import localized_error, localized_result, run_text_review, safe_terminal
53
+ from .distill_review.transaction import ProfileTransaction, TransactionError
46
54
  from .i18n import (
47
55
  generate_config_content,
48
56
  get_explicit_language_key,
@@ -58,7 +66,7 @@ from .profile import ensure_profile_scaffold, inject_profile_block
58
66
  from .translator import SUPPORTED_LANGUAGES, translate
59
67
 
60
68
  # Version info
61
- __version__ = "0.7.16"
69
+ __version__ = "0.7.17"
62
70
  __author__ = "CodexSpec Team"
63
71
 
64
72
  # Constitution file path constants
@@ -74,6 +82,97 @@ app = typer.Typer(
74
82
  console = Console()
75
83
 
76
84
 
85
+ @app.command("_distill-review-helper", hidden=True)
86
+ def distill_review_helper(
87
+ project_root: Path = typer.Option(Path("."), "--project-root"),
88
+ mode: str = typer.Option("html", "--mode"),
89
+ manifest: Optional[Path] = typer.Option(None, "--manifest"),
90
+ no_open: bool = typer.Option(False, "--no-open"),
91
+ discard_draft: bool = typer.Option(False, "--discard-draft"),
92
+ ) -> None:
93
+ """Run the deterministic local carrier used by the distill command."""
94
+ root = project_root.resolve()
95
+ language = get_interaction_language(root / ".codexspec" / "config.yml")
96
+ if mode not in {"html", "text"}:
97
+ _review_result(language, {"status": "invalid_input", "error": "invalid_mode"})
98
+ raise typer.Exit(2)
99
+ if not root.is_dir() or not (root / ".codexspec" / "profile").is_dir():
100
+ _review_result(language, {"status": "invalid_input", "error": "invalid_project_root"})
101
+ raise typer.Exit(2)
102
+ store = SessionStore(root)
103
+ lease = ReviewLease(root)
104
+ try:
105
+ lease.acquire({"state": "starting", "mode": mode})
106
+ except ActiveSessionError as exc:
107
+ # Machine output reports the running session, but its capability token and
108
+ # token-bearing URL belong to the session that printed them.
109
+ session = {key: value for key, value in exc.metadata.items() if key not in {"capability", "url"}}
110
+ _review_result(language, {"status": "active_session", "session": session})
111
+ return
112
+ except (AutomationError, SessionError, OSError) as exc:
113
+ _review_result(language, {"status": "invalid_input", "error": str(exc)})
114
+ raise typer.Exit(2) from exc
115
+ server = None
116
+ try:
117
+ try:
118
+ ProfileTransaction.recover(root, store)
119
+ except (TransactionError, SessionError, OSError):
120
+ if not discard_draft:
121
+ raise
122
+ # A failed recovery must not brick the documented escape hatch: an
123
+ # explicit discard abandons the draft and the stuck journal together.
124
+ if discard_draft:
125
+ store.discard()
126
+ store.discard_transaction()
127
+ _review_result(language, {"status": "discarded"})
128
+ return
129
+ draft = store.load()
130
+ service = ReviewService.from_project(
131
+ root,
132
+ manifest_path=manifest,
133
+ draft=draft,
134
+ interaction_language=language,
135
+ )
136
+ except (ReviewError, SessionError, TransactionError, OSError) as exc:
137
+ _review_result(language, {"status": "invalid_input", "error": str(exc)})
138
+ raise typer.Exit(2) from exc
139
+ if not service.records and not service.clusters and not (service.draft.decisions or service.draft.deferred):
140
+ _review_result(language, {"status": "nothing_to_review"})
141
+ return
142
+ try:
143
+ if mode == "text":
144
+ lease.update({"mode": "text"})
145
+ result = run_text_review(service, store)
146
+ typer.echo()
147
+ _machine_json(result)
148
+ return
149
+ token = secrets.token_urlsafe(32)
150
+ server = create_server(service, store, token=token)
151
+ url = f"http://127.0.0.1:{server.server_port}/#token={token}"
152
+ lease.update({"mode": "html", "port": server.server_port, "capability": token, "url": url})
153
+ try:
154
+ opened = False if no_open else webbrowser.open(url)
155
+ except (OSError, webbrowser.Error):
156
+ opened = False
157
+ if not opened:
158
+ typer.echo(url)
159
+ server.timeout = 0.5
160
+ while not server.stop_event.is_set():
161
+ server.handle_request()
162
+ _review_result(language, server.final_result or {"status": "finished"})
163
+ except (ReviewError, SessionError, TransactionError, OSError) as exc:
164
+ failure: dict[str, object] = {"status": "invalid_input", "error": str(exc)}
165
+ if isinstance(exc, TransactionError):
166
+ failure["records"] = exc.records
167
+ failure["failures"] = exc.failures
168
+ _review_result(language, failure)
169
+ raise typer.Exit(2) from exc
170
+ finally:
171
+ if server is not None:
172
+ server.server_close()
173
+ lease.release()
174
+
175
+
77
176
  def get_version() -> str:
78
177
  """Return the current version of codexspec."""
79
178
  return __version__
@@ -192,6 +291,25 @@ def _machine_json(value: object) -> None:
192
291
  sys.stdout.write(json.dumps(value, sort_keys=True, separators=(",", ":")) + "\n")
193
292
 
194
293
 
294
+ def _review_result(language: str, value: dict[str, object]) -> None:
295
+ status = str(value.get("status", "invalid_input"))
296
+ if status in {"invalid_input", "conflict"}:
297
+ raw_records = value.get("records")
298
+ raw_failures = value.get("failures")
299
+ records = [str(item) for item in raw_records] if isinstance(raw_records, list) else None
300
+ failures = [str(item) for item in raw_failures] if isinstance(raw_failures, list) else None
301
+ message = localized_error(
302
+ language,
303
+ str(value.get("error", status)),
304
+ records=records,
305
+ failures=failures,
306
+ )
307
+ else:
308
+ message = localized_result(language, status)
309
+ typer.echo(safe_terminal(message))
310
+ _machine_json(value)
311
+
312
+
195
313
  def _stdin_json() -> dict:
196
314
  try:
197
315
  value = json.loads(sys.stdin.read() or "{}")
@@ -885,6 +1003,7 @@ def init(
885
1003
  # so knowledge distilled later is effective immediately with no re-init and
886
1004
  # no dangling reference. Non-destructive: existing profile files are kept.
887
1005
  ensure_profile_scaffold(target_dir)
1006
+ ensure_runtime_ignored(target_dir, install_managed_file=True)
888
1007
 
889
1008
  # Copy helper scripts based on platform
890
1009
  scripts_source_dir = get_scripts_dir()
@@ -0,0 +1,13 @@
1
+ """Deterministic local review runtime for distilled profile knowledge."""
2
+
3
+ from .domain import ReviewError, ReviewService
4
+ from .records import RecordDocument, RecordError, discover_records, parse_record
5
+
6
+ __all__ = [
7
+ "RecordDocument",
8
+ "RecordError",
9
+ "ReviewError",
10
+ "ReviewService",
11
+ "discover_records",
12
+ "parse_record",
13
+ ]