@hupan56/wlkj 2.2.4 → 2.2.6
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.
- package/bin/cli.js +532 -532
- package/package.json +28 -28
- package/templates/qoder/hooks/inject-workflow-state.py +117 -117
- package/templates/qoder/hooks/session-start.py +204 -204
- package/templates/qoder/scripts/common/developer.py +231 -161
- package/templates/qoder/scripts/common/paths.py +310 -310
- package/templates/qoder/scripts/common/task_utils.py +392 -392
- package/templates/qoder/scripts/common/terms.py +42 -2
- package/templates/qoder/scripts/init_developer.py +75 -75
- package/templates/qoder/scripts/install_qoderwork.py +367 -367
- package/templates/qoder/scripts/role.py +39 -39
- package/templates/qoder/scripts/search_index.py +123 -5
- package/templates/qoder/scripts/syncgate.py +333 -333
- package/templates/qoder/scripts/team_sync.py +439 -439
- package/templates/qoder/skills/design-review/SKILL.md +25 -25
- package/templates/qoder/skills/prd-generator/SKILL.md +180 -180
- package/templates/qoder/skills/prd-review/SKILL.md +36 -36
- package/templates/qoder/skills/prototype-generator/SKILL.md +141 -141
- package/templates/qoder/skills/spec-coder/SKILL.md +68 -68
- package/templates/qoder/skills/spec-generator/SKILL.md +66 -66
- package/templates/qoder/skills/test-generator/SKILL.md +71 -71
- package/templates/root/AGENTS.md +182 -182
|
@@ -1,161 +1,231 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
QODER Pipeline - 开发者管理工具
|
|
5
|
-
|
|
6
|
-
提供开发者身份的初始化和管理功能:
|
|
7
|
-
- init_developer: 初始化开发者身份, 创建工作空间和日志
|
|
8
|
-
- ensure_developer: 确保开发者已初始化 (未初始化则退出)
|
|
9
|
-
- show_developer_info: 显示开发者信息
|
|
10
|
-
|
|
11
|
-
开发者身份存储在 .qoder/.developer 文件中 (gitignored)
|
|
12
|
-
工作空间在 workspace/members/<developer>/ 目录下 (与 workspace_init.py 一致)
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
from __future__ import annotations
|
|
16
|
-
|
|
17
|
-
import sys
|
|
18
|
-
from datetime import datetime
|
|
19
|
-
from pathlib import Path
|
|
20
|
-
|
|
21
|
-
# 将 scripts 目录加入路径以便导入 common 模块
|
|
22
|
-
import os
|
|
23
|
-
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
24
|
-
|
|
25
|
-
from common.paths import (
|
|
26
|
-
DIR_WORKFLOW,
|
|
27
|
-
FILE_DEVELOPER,
|
|
28
|
-
MEMBERS_DIR,
|
|
29
|
-
get_repo_root,
|
|
30
|
-
get_developer,
|
|
31
|
-
check_developer,
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
# =============================================================================
|
|
36
|
-
# 开发者初始化
|
|
37
|
-
# =============================================================================
|
|
38
|
-
|
|
39
|
-
def write_developer_file(name: str, role: str | None = None,
|
|
40
|
-
repo_root: Path | None = None) -> bool:
|
|
41
|
-
"""写入 .qoder/.developer (规范格式: name=<name>)。"""
|
|
42
|
-
if repo_root is None:
|
|
43
|
-
repo_root = get_repo_root()
|
|
44
|
-
dev_file = repo_root / DIR_WORKFLOW / FILE_DEVELOPER
|
|
45
|
-
lines = [f"name={name}"]
|
|
46
|
-
if role:
|
|
47
|
-
lines.append(f"role={role}")
|
|
48
|
-
lines.append(f"initialized_at={datetime.now().isoformat()}")
|
|
49
|
-
try:
|
|
50
|
-
dev_file.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
51
|
-
return True
|
|
52
|
-
except (OSError, IOError) as e:
|
|
53
|
-
print(f"Error: Failed to create .developer file: {e}", file=sys.stderr)
|
|
54
|
-
return False
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
#
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
print(f"
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
QODER Pipeline - 开发者管理工具
|
|
5
|
+
|
|
6
|
+
提供开发者身份的初始化和管理功能:
|
|
7
|
+
- init_developer: 初始化开发者身份, 创建工作空间和日志
|
|
8
|
+
- ensure_developer: 确保开发者已初始化 (未初始化则退出)
|
|
9
|
+
- show_developer_info: 显示开发者信息
|
|
10
|
+
|
|
11
|
+
开发者身份存储在 .qoder/.developer 文件中 (gitignored)
|
|
12
|
+
工作空间在 workspace/members/<developer>/ 目录下 (与 workspace_init.py 一致)
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import sys
|
|
18
|
+
from datetime import datetime
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
# 将 scripts 目录加入路径以便导入 common 模块
|
|
22
|
+
import os
|
|
23
|
+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
24
|
+
|
|
25
|
+
from common.paths import (
|
|
26
|
+
DIR_WORKFLOW,
|
|
27
|
+
FILE_DEVELOPER,
|
|
28
|
+
MEMBERS_DIR,
|
|
29
|
+
get_repo_root,
|
|
30
|
+
get_developer,
|
|
31
|
+
check_developer,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# =============================================================================
|
|
36
|
+
# 开发者初始化
|
|
37
|
+
# =============================================================================
|
|
38
|
+
|
|
39
|
+
def write_developer_file(name: str, role: str | None = None,
|
|
40
|
+
repo_root: Path | None = None) -> bool:
|
|
41
|
+
"""写入 .qoder/.developer (规范格式: name=<name>)。"""
|
|
42
|
+
if repo_root is None:
|
|
43
|
+
repo_root = get_repo_root()
|
|
44
|
+
dev_file = repo_root / DIR_WORKFLOW / FILE_DEVELOPER
|
|
45
|
+
lines = [f"name={name}"]
|
|
46
|
+
if role:
|
|
47
|
+
lines.append(f"role={role}")
|
|
48
|
+
lines.append(f"initialized_at={datetime.now().isoformat()}")
|
|
49
|
+
try:
|
|
50
|
+
dev_file.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
|
51
|
+
return True
|
|
52
|
+
except (OSError, IOError) as e:
|
|
53
|
+
print(f"Error: Failed to create .developer file: {e}", file=sys.stderr)
|
|
54
|
+
return False
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _detect_git_author() -> str | None:
|
|
58
|
+
"""探测系统 git config 的 user.name <user.email>。git 未装或未配返回 None。"""
|
|
59
|
+
import subprocess
|
|
60
|
+
try:
|
|
61
|
+
rn = subprocess.run(["git", "config", "user.name"],
|
|
62
|
+
capture_output=True, text=True, timeout=5)
|
|
63
|
+
re_ = subprocess.run(["git", "config", "user.email"],
|
|
64
|
+
capture_output=True, text=True, timeout=5)
|
|
65
|
+
if rn.returncode == 0 and re_.returncode == 0:
|
|
66
|
+
gname = rn.stdout.strip()
|
|
67
|
+
gemail = re_.stdout.strip()
|
|
68
|
+
if gname and gemail:
|
|
69
|
+
return f"{gname} <{gemail}>"
|
|
70
|
+
except (FileNotFoundError, OSError, subprocess.SubprocessError):
|
|
71
|
+
pass # git 未装
|
|
72
|
+
return None
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _ensure_git_config(name: str, repo_root: Path) -> None:
|
|
76
|
+
"""确保 git user.name/email 已配置。未配则用 --local 设为 init 的名字。
|
|
77
|
+
|
|
78
|
+
检测顺序: 全局 > local。都没有就提示用户。
|
|
79
|
+
"""
|
|
80
|
+
import subprocess
|
|
81
|
+
# 先看 git 是否可用
|
|
82
|
+
try:
|
|
83
|
+
subprocess.run(["git", "--version"], capture_output=True, timeout=5)
|
|
84
|
+
except (FileNotFoundError, OSError):
|
|
85
|
+
print(" [INFO] git 未安装, 跳过 git 配置 (核心功能不依赖 git)")
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
author = _detect_git_author()
|
|
89
|
+
if author:
|
|
90
|
+
print(f" [OK] git 作者: {author}")
|
|
91
|
+
return
|
|
92
|
+
|
|
93
|
+
# git 未配 user.name/email: 用 init 名字设 local config (不影响全局)
|
|
94
|
+
print(f" [设置] git 未配置 user.name/email, 用你的名字设为 local:")
|
|
95
|
+
fake_email = f"{name}@local"
|
|
96
|
+
try:
|
|
97
|
+
subprocess.run(["git", "config", "--local", "user.name", name],
|
|
98
|
+
cwd=str(repo_root), capture_output=True, timeout=5)
|
|
99
|
+
subprocess.run(["git", "config", "--local", "user.email", fake_email],
|
|
100
|
+
cwd=str(repo_root), capture_output=True, timeout=5)
|
|
101
|
+
print(f" user.name = {name}")
|
|
102
|
+
print(f" user.email = {fake_email}")
|
|
103
|
+
print(f" (仅本仓库生效。如有团队 git 账号, 自行改: git config --local user.email 你的邮箱)")
|
|
104
|
+
except (FileNotFoundError, OSError, subprocess.SubprocessError) as e:
|
|
105
|
+
print(f" [WARN] 设置 git config 失败 (不阻塞): {e}")
|
|
106
|
+
print(f" 请手动跑: git config user.name {name} && git config user.email 你的邮箱")
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def init_developer(name: str, role: str | None = None,
|
|
110
|
+
repo_root: Path | None = None) -> bool:
|
|
111
|
+
"""初始化开发者身份。
|
|
112
|
+
|
|
113
|
+
创建以下内容:
|
|
114
|
+
- .qoder/.developer 文件 (name= / role= / initialized_at=)
|
|
115
|
+
- workspace/members/<name>/{journal,drafts,inbox}/ 目录
|
|
116
|
+
- 初始日志文件 journal/journal-1.md
|
|
117
|
+
- member.json + .signing_key (零信任身份注册, 用于 push 门禁)
|
|
118
|
+
- git user.name/email 检测与配置
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
成功返回 True, 失败返回 False。
|
|
122
|
+
"""
|
|
123
|
+
if not name:
|
|
124
|
+
print("Error: developer name is required", file=sys.stderr)
|
|
125
|
+
return False
|
|
126
|
+
|
|
127
|
+
# 校验名称合法性 (允许字母数字、中文和部分符号)
|
|
128
|
+
if not all(c.isalnum() or c in "-_" for c in name):
|
|
129
|
+
print(f"Error: invalid developer name '{name}' (only alphanumeric, -, _ allowed)", file=sys.stderr)
|
|
130
|
+
return False
|
|
131
|
+
|
|
132
|
+
if repo_root is None:
|
|
133
|
+
repo_root = get_repo_root()
|
|
134
|
+
|
|
135
|
+
# 零信任: 切换身份时清除旧开发者的 current-task 指针
|
|
136
|
+
# (防止 B 在 A 用过的机器上看到 A 的活跃任务, 误操作)
|
|
137
|
+
try:
|
|
138
|
+
from .paths import get_developer, set_current_task
|
|
139
|
+
old_dev = get_developer(repo_root)
|
|
140
|
+
if old_dev and old_dev != name:
|
|
141
|
+
set_current_task(None, repo_root, developer=old_dev)
|
|
142
|
+
print(f"Note: 切换开发者 {old_dev} -> {name}, 已清除 {old_dev} 的活跃任务指针")
|
|
143
|
+
except Exception:
|
|
144
|
+
pass # 清理失败不阻塞初始化
|
|
145
|
+
|
|
146
|
+
# 1. 创建 .developer 文件
|
|
147
|
+
if not write_developer_file(name, role, repo_root):
|
|
148
|
+
return False
|
|
149
|
+
|
|
150
|
+
# 2. 创建个人工作空间 workspace/members/<name>/
|
|
151
|
+
personal = repo_root / "workspace" / "members" / name
|
|
152
|
+
try:
|
|
153
|
+
for sub in ("journal", "drafts", "inbox"):
|
|
154
|
+
(personal / sub).mkdir(parents=True, exist_ok=True)
|
|
155
|
+
except (OSError, IOError) as e:
|
|
156
|
+
print(f"Error: Failed to create workspace directory: {e}", file=sys.stderr)
|
|
157
|
+
return False
|
|
158
|
+
|
|
159
|
+
# 3. 创建初始日志文件
|
|
160
|
+
journal_file = personal / "journal" / "journal-1.md"
|
|
161
|
+
if not journal_file.exists():
|
|
162
|
+
today = datetime.now().strftime("%Y-%m-%d")
|
|
163
|
+
try:
|
|
164
|
+
journal_file.write_text(
|
|
165
|
+
f"# Journal - {name}\n\n> Started: {today}\n\n---\n\n",
|
|
166
|
+
encoding="utf-8"
|
|
167
|
+
)
|
|
168
|
+
except (OSError, IOError) as e:
|
|
169
|
+
print(f"Error: Failed to create journal file: {e}", file=sys.stderr)
|
|
170
|
+
return False
|
|
171
|
+
|
|
172
|
+
# 4. 零信任身份注册 (写 member.json + 签名密钥 + git_author)
|
|
173
|
+
# 这是 push 门禁的前提: 没 member.json → syncgate 拒绝 push
|
|
174
|
+
git_author = _detect_git_author()
|
|
175
|
+
try:
|
|
176
|
+
from common.identity import register_member, IdentityError
|
|
177
|
+
try:
|
|
178
|
+
register_member(name, role or "pm", git_author, repo_root)
|
|
179
|
+
print(f" [OK] 身份注册: member.json + 签名密钥已生成")
|
|
180
|
+
except IdentityError as e:
|
|
181
|
+
print(f" [WARN] 身份注册失败 (不阻塞): {e}")
|
|
182
|
+
except ImportError:
|
|
183
|
+
pass # identity 模块不可用, 跳过 (向后兼容)
|
|
184
|
+
|
|
185
|
+
# 5. 确保 git 配置 (检测 + 自动设 local)
|
|
186
|
+
_ensure_git_config(name, repo_root)
|
|
187
|
+
|
|
188
|
+
print(f"Developer initialized: {name}" + (f" ({role})" if role else ""))
|
|
189
|
+
print(f" Workspace: workspace/members/{name}/")
|
|
190
|
+
print(f" Journal: workspace/members/{name}/journal/journal-1.md")
|
|
191
|
+
return True
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
# =============================================================================
|
|
195
|
+
# 开发者校验
|
|
196
|
+
# =============================================================================
|
|
197
|
+
|
|
198
|
+
def ensure_developer(repo_root: Path | None = None) -> str:
|
|
199
|
+
"""确保开发者已初始化, 未初始化则打印提示并退出。"""
|
|
200
|
+
developer = get_developer(repo_root)
|
|
201
|
+
if not developer:
|
|
202
|
+
print("Error: Developer not initialized.", file=sys.stderr)
|
|
203
|
+
print("Run: python .qoder/scripts/workspace_init.py <your-name>", file=sys.stderr)
|
|
204
|
+
sys.exit(1)
|
|
205
|
+
return developer
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def show_developer_info(repo_root: Path | None = None) -> None:
|
|
209
|
+
"""显示当前开发者信息。"""
|
|
210
|
+
from common.paths import get_developer_info, get_workspace_dir, get_active_journal_file
|
|
211
|
+
|
|
212
|
+
info = get_developer_info(repo_root)
|
|
213
|
+
if not info:
|
|
214
|
+
print("Developer: not initialized")
|
|
215
|
+
print("Run: python .qoder/scripts/workspace_init.py <your-name>")
|
|
216
|
+
return
|
|
217
|
+
|
|
218
|
+
print(f"Developer: {info.get('name', 'unknown')}")
|
|
219
|
+
if info.get('role'):
|
|
220
|
+
print(f"Role: {info['role']}")
|
|
221
|
+
print(f"Initialized: {info.get('initialized_at', 'unknown')}")
|
|
222
|
+
|
|
223
|
+
workspace = get_workspace_dir(repo_root)
|
|
224
|
+
if workspace:
|
|
225
|
+
print(f"Workspace: {workspace}")
|
|
226
|
+
|
|
227
|
+
journal = get_active_journal_file(repo_root)
|
|
228
|
+
if journal:
|
|
229
|
+
from common.paths import count_lines
|
|
230
|
+
lines = count_lines(journal)
|
|
231
|
+
print(f"Active Journal: {journal.name} ({lines} lines)")
|