codexspec 0.4.2__tar.gz → 0.4.4__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 (61) hide show
  1. {codexspec-0.4.2 → codexspec-0.4.4}/PKG-INFO +3 -1
  2. {codexspec-0.4.2 → codexspec-0.4.4}/pyproject.toml +3 -1
  3. {codexspec-0.4.2 → codexspec-0.4.4}/scripts/python/claude_monitor.py +62 -7
  4. codexspec-0.4.4/scripts/python/notify_telegram.py +741 -0
  5. codexspec-0.4.4/scripts/python/tests/__init__.py +1 -0
  6. codexspec-0.4.4/scripts/python/tests/test_notify.py +960 -0
  7. {codexspec-0.4.2 → codexspec-0.4.4}/src/codexspec/__init__.py +78 -66
  8. {codexspec-0.4.2 → codexspec-0.4.4}/src/codexspec/i18n.py +25 -0
  9. {codexspec-0.4.2 → codexspec-0.4.4}/src/codexspec/translator.py +185 -0
  10. codexspec-0.4.4/templates/translations/en.json +74 -0
  11. {codexspec-0.4.2 → codexspec-0.4.4}/templates/translations/ja.json +51 -0
  12. codexspec-0.4.4/templates/translations/ko.json +139 -0
  13. codexspec-0.4.4/templates/translations/zh-CN.json +139 -0
  14. codexspec-0.4.2/scripts/python/notify_telegram.py +0 -282
  15. codexspec-0.4.2/templates/translations/ko.json +0 -69
  16. codexspec-0.4.2/templates/translations/zh-CN.json +0 -69
  17. {codexspec-0.4.2 → codexspec-0.4.4}/.gitignore +0 -0
  18. {codexspec-0.4.2 → codexspec-0.4.4}/LICENSE +0 -0
  19. {codexspec-0.4.2 → codexspec-0.4.4}/README.md +0 -0
  20. {codexspec-0.4.2 → codexspec-0.4.4}/scripts/bash/check-i18n-completeness.sh +0 -0
  21. {codexspec-0.4.2 → codexspec-0.4.4}/scripts/bash/check-i18n-structure.sh +0 -0
  22. {codexspec-0.4.2 → codexspec-0.4.4}/scripts/bash/check-prerequisites.sh +0 -0
  23. {codexspec-0.4.2 → codexspec-0.4.4}/scripts/bash/common.sh +0 -0
  24. {codexspec-0.4.2 → codexspec-0.4.4}/scripts/bash/create-new-feature.sh +0 -0
  25. {codexspec-0.4.2 → codexspec-0.4.4}/scripts/powershell/check-prerequisites.ps1 +0 -0
  26. {codexspec-0.4.2 → codexspec-0.4.4}/scripts/powershell/common.ps1 +0 -0
  27. {codexspec-0.4.2 → codexspec-0.4.4}/scripts/powershell/create-new-feature.ps1 +0 -0
  28. {codexspec-0.4.2 → codexspec-0.4.4}/scripts/python/README.md +0 -0
  29. {codexspec-0.4.2 → codexspec-0.4.4}/src/codexspec/commands/__init__.py +0 -0
  30. {codexspec-0.4.2 → codexspec-0.4.4}/src/codexspec/commands/installer.py +0 -0
  31. {codexspec-0.4.2 → codexspec-0.4.4}/src/codexspec/idea.md +0 -0
  32. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/analyze.md +0 -0
  33. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/check-i18n-semantics.md +0 -0
  34. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/checklist.md +0 -0
  35. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/clarify.md +0 -0
  36. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/commit-staged.md +0 -0
  37. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/commit.md +0 -0
  38. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/constitution.md +0 -0
  39. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/generate-spec.md +0 -0
  40. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/implement-tasks.md +0 -0
  41. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/plan-to-tasks.md +0 -0
  42. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/pr.md +0 -0
  43. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/review-plan.md +0 -0
  44. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/review-spec.md +0 -0
  45. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/review-tasks.md +0 -0
  46. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/spec-to-plan.md +0 -0
  47. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/specify.md +0 -0
  48. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/tasks-to-issues.md +0 -0
  49. {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/translate-docs.md +0 -0
  50. {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/checklist-template.md +0 -0
  51. {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/constitution-template.md +0 -0
  52. {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/plan-template-detailed.md +0 -0
  53. {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/plan-template-simple.md +0 -0
  54. {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/spec-template-detailed.md +0 -0
  55. {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/spec-template-simple.md +0 -0
  56. {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/tasks-template-detailed.md +0 -0
  57. {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/tasks-template-simple.md +0 -0
  58. {codexspec-0.4.2 → codexspec-0.4.4}/templates/translations/de.json +0 -0
  59. {codexspec-0.4.2 → codexspec-0.4.4}/templates/translations/es.json +0 -0
  60. {codexspec-0.4.2 → codexspec-0.4.4}/templates/translations/fr.json +0 -0
  61. {codexspec-0.4.2 → codexspec-0.4.4}/templates/translations/pt-BR.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: codexspec
3
- Version: 0.4.2
3
+ Version: 0.4.4
4
4
  Summary: CodexSpec - A Spec-Driven Development (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
@@ -25,9 +25,11 @@ Requires-Python: >=3.11
25
25
  Requires-Dist: httpx>=0.25.0
26
26
  Requires-Dist: packaging>=23.0
27
27
  Requires-Dist: platformdirs>=4.0.0
28
+ Requires-Dist: python-dotenv>=1.0.0
28
29
  Requires-Dist: pyyaml>=6.0
29
30
  Requires-Dist: rich>=13.0.0
30
31
  Requires-Dist: typer>=0.9.0
32
+ Requires-Dist: watchdog>=4.0.0
31
33
  Provides-Extra: dev
32
34
  Requires-Dist: pre-commit>=3.0.0; extra == 'dev'
33
35
  Requires-Dist: pytest-cov>=4.0; extra == 'dev'
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "codexspec"
3
- version = "0.4.2"
3
+ version = "0.4.4"
4
4
  description = "CodexSpec - A Spec-Driven Development (SDD) toolkit for Claude Code"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -30,6 +30,8 @@ dependencies = [
30
30
  "platformdirs>=4.0.0",
31
31
  "pyyaml>=6.0",
32
32
  "packaging>=23.0",
33
+ "python-dotenv>=1.0.0",
34
+ "watchdog>=4.0.0",
33
35
  ]
34
36
 
35
37
  [project.urls]
@@ -5,13 +5,58 @@ Claude Code Session Monitor
5
5
  """
6
6
 
7
7
  import argparse
8
+ import atexit
8
9
  import json
10
+ import os
11
+ import sys
9
12
  import time
10
13
  from dataclasses import dataclass, field
11
14
  from enum import Enum
12
15
  from pathlib import Path
13
16
  from typing import Any, Optional
14
17
 
18
+ # 单实例锁文件
19
+ PID_FILE = Path("/tmp/claude_monitor.pid")
20
+
21
+
22
+ def _is_process_running(pid: int) -> bool:
23
+ """检查进程是否存在(跨平台,支持 macOS)"""
24
+ try:
25
+ os.kill(pid, 0) # 信号 0 不会真的杀死进程
26
+ return True
27
+ except OSError:
28
+ return False
29
+ except ValueError:
30
+ return False
31
+
32
+
33
+ def _check_single_instance() -> None:
34
+ """确保只有一个实例运行"""
35
+ if PID_FILE.exists():
36
+ try:
37
+ old_pid = int(PID_FILE.read_text().strip())
38
+ if _is_process_running(old_pid):
39
+ print(f"[ERROR] Another instance is running (PID: {old_pid})", file=sys.stderr)
40
+ print(f"[ERROR] Run 'kill {old_pid}' to stop it, or remove {PID_FILE} if stale", file=sys.stderr)
41
+ sys.exit(1)
42
+ except (ValueError, PermissionError):
43
+ pass # PID 文件损坏或无法读取,继续
44
+
45
+ # 写入当前 PID
46
+ PID_FILE.write_text(str(os.getpid()))
47
+
48
+
49
+ def _cleanup_pid_file() -> None:
50
+ """清理 PID 文件"""
51
+ try:
52
+ if PID_FILE.exists():
53
+ current_pid = int(PID_FILE.read_text().strip())
54
+ if current_pid == os.getpid():
55
+ PID_FILE.unlink()
56
+ except (ValueError, PermissionError):
57
+ pass
58
+
59
+
15
60
  try:
16
61
  from watchdog.events import FileSystemEventHandler
17
62
  from watchdog.observers import Observer
@@ -137,9 +182,7 @@ class StateDetector:
137
182
  error_info = StateDetector._extract_error(message)
138
183
  if error_info and stop_reason not in StateDetector.STOP_REASONS_COMPLETE:
139
184
  # 有错误且不是正常完成
140
- if stop_reason in ("refusal", "error") or (
141
- stop_reason not in StateDetector.STOP_REASONS_COMPLETE
142
- ):
185
+ if stop_reason in ("refusal", "error") or (stop_reason not in StateDetector.STOP_REASONS_COMPLETE):
143
186
  return SessionStatus.ERROR_STOP, None, [], error_info
144
187
 
145
188
  # 5. 任务完成
@@ -203,7 +246,15 @@ class StateDetector:
203
246
  continue
204
247
 
205
248
  input_data = item.get("input", {})
206
- options_data = input_data.get("options", [])
249
+
250
+ # 修复:Claude API 的 AskUserQuestion 将问题放在 input.questions 数组中
251
+ questions_data = input_data.get("questions", [])
252
+ if not questions_data:
253
+ return None
254
+
255
+ # 取第一个问题(当前实现只支持单问题)
256
+ first_question = questions_data[0]
257
+ options_data = first_question.get("options", [])
207
258
 
208
259
  options = [
209
260
  QuestionOption(
@@ -214,10 +265,10 @@ class StateDetector:
214
265
  ]
215
266
 
216
267
  return QuestionInfo(
217
- question=input_data.get("question", ""),
218
- header=input_data.get("header", ""),
268
+ question=first_question.get("question", ""),
269
+ header=first_question.get("header", ""),
219
270
  options=options,
220
- multi_select=input_data.get("multiSelect", False),
271
+ multi_select=first_question.get("multiSelect", False),
221
272
  )
222
273
 
223
274
  return None
@@ -844,6 +895,10 @@ def list_projects():
844
895
 
845
896
 
846
897
  def main():
898
+ # 确保只有一个实例运行
899
+ atexit.register(_cleanup_pid_file)
900
+ _check_single_instance()
901
+
847
902
  parser = argparse.ArgumentParser(
848
903
  description="Monitor Claude Code sessions and output content when execution completes",
849
904
  formatter_class=argparse.RawDescriptionHelpFormatter,