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.
- {codexspec-0.4.2 → codexspec-0.4.4}/PKG-INFO +3 -1
- {codexspec-0.4.2 → codexspec-0.4.4}/pyproject.toml +3 -1
- {codexspec-0.4.2 → codexspec-0.4.4}/scripts/python/claude_monitor.py +62 -7
- codexspec-0.4.4/scripts/python/notify_telegram.py +741 -0
- codexspec-0.4.4/scripts/python/tests/__init__.py +1 -0
- codexspec-0.4.4/scripts/python/tests/test_notify.py +960 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/src/codexspec/__init__.py +78 -66
- {codexspec-0.4.2 → codexspec-0.4.4}/src/codexspec/i18n.py +25 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/src/codexspec/translator.py +185 -0
- codexspec-0.4.4/templates/translations/en.json +74 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/translations/ja.json +51 -0
- codexspec-0.4.4/templates/translations/ko.json +139 -0
- codexspec-0.4.4/templates/translations/zh-CN.json +139 -0
- codexspec-0.4.2/scripts/python/notify_telegram.py +0 -282
- codexspec-0.4.2/templates/translations/ko.json +0 -69
- codexspec-0.4.2/templates/translations/zh-CN.json +0 -69
- {codexspec-0.4.2 → codexspec-0.4.4}/.gitignore +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/LICENSE +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/README.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/scripts/bash/check-i18n-completeness.sh +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/scripts/bash/check-i18n-structure.sh +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/scripts/bash/check-prerequisites.sh +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/scripts/bash/common.sh +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/scripts/bash/create-new-feature.sh +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/scripts/powershell/check-prerequisites.ps1 +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/scripts/powershell/common.ps1 +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/scripts/powershell/create-new-feature.ps1 +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/scripts/python/README.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/src/codexspec/commands/__init__.py +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/src/codexspec/commands/installer.py +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/src/codexspec/idea.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/analyze.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/check-i18n-semantics.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/checklist.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/clarify.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/commit-staged.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/commit.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/constitution.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/generate-spec.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/implement-tasks.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/plan-to-tasks.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/pr.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/review-plan.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/review-spec.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/review-tasks.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/spec-to-plan.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/specify.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/tasks-to-issues.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/commands/translate-docs.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/checklist-template.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/constitution-template.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/plan-template-detailed.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/plan-template-simple.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/spec-template-detailed.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/spec-template-simple.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/tasks-template-detailed.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/docs/tasks-template-simple.md +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/translations/de.json +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/translations/es.json +0 -0
- {codexspec-0.4.2 → codexspec-0.4.4}/templates/translations/fr.json +0 -0
- {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.
|
|
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.
|
|
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
|
-
|
|
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=
|
|
218
|
-
header=
|
|
268
|
+
question=first_question.get("question", ""),
|
|
269
|
+
header=first_question.get("header", ""),
|
|
219
270
|
options=options,
|
|
220
|
-
multi_select=
|
|
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,
|