@hupan56/wlkj 2.7.11 → 3.0.0
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 +375 -78
- package/package.json +29 -29
- package/templates/.qoder/.runtime/ctx-cache-5660152f1d6dd819.md +23 -0
- package/templates/.qoder/.runtime/ctx-cache-afdce0dac06b25b0.md +23 -0
- package/templates/.qoder/.runtime/search-cache-eae7644e7b122f35.txt +1 -0
- package/templates/.qoder/learning/eval-history.jsonl +28 -0
- package/templates/data/index/wiki-index.json +8 -0
- package/templates/qoder/agents/insight-planning.md +1 -1
- package/templates/qoder/agents/insight-research.md +28 -15
- package/templates/qoder/commands/optional/wl-insight.md +159 -161
- package/templates/qoder/commands/optional/wl-report.md +4 -4
- package/templates/qoder/commands/optional/wl-status.md +2 -2
- package/templates/qoder/commands/wl-code.md +2 -2
- package/templates/qoder/commands/wl-design.md +2 -2
- package/templates/qoder/commands/wl-init.md +3 -3
- package/templates/qoder/commands/wl-prd.md +2 -2
- package/templates/qoder/commands/wl-req.md +43 -0
- package/templates/qoder/commands/wl-search.md +8 -8
- package/templates/qoder/commands/wl-task.md +17 -17
- package/templates/qoder/commands/wl-test.md +41 -15
- package/templates/qoder/config.yaml +17 -1
- package/templates/qoder/hooks/session-start.py +12 -22
- package/templates/qoder/nul +4 -0
- package/templates/qoder/rules/wl-pipeline.md +22 -48
- package/templates/qoder/scripts/README.md +139 -0
- package/templates/qoder/scripts/common/autotest_auth.py +109 -0
- package/templates/qoder/scripts/common/bootstrap.py +145 -0
- package/templates/qoder/scripts/common/check_publish.py +98 -0
- package/templates/qoder/scripts/common/cmd_registry.py +112 -0
- package/templates/qoder/scripts/common/config.py +187 -0
- package/templates/qoder/scripts/common/contract.py +317 -0
- package/templates/qoder/scripts/common/developer.py +2 -1
- package/templates/qoder/scripts/common/feishu.py +10 -9
- package/templates/qoder/scripts/common/guard.py +159 -0
- package/templates/qoder/scripts/common/identity.py +121 -2
- package/templates/qoder/scripts/common/kg_capabilities.py +182 -0
- package/templates/qoder/scripts/common/mcp_base.py +268 -0
- package/templates/qoder/scripts/common/paths.py +187 -1
- package/templates/qoder/scripts/common/result.py +223 -0
- package/templates/qoder/scripts/common/roles.py +60 -0
- package/templates/qoder/scripts/common/task_utils.py +21 -9
- package/templates/qoder/scripts/common/test_extract.py +115 -0
- package/templates/qoder/scripts/kg/__init__.py +11 -0
- package/templates/qoder/scripts/kg/build_entity_registry.py +196 -0
- package/templates/qoder/scripts/kg/build_relations.py +127 -0
- package/templates/qoder/scripts/{build_style_index.py → kg/build_style_index.py} +39 -10
- package/templates/qoder/scripts/kg/build_workflows.py +144 -0
- package/templates/qoder/scripts/{context_pack.py → kg/context_pack.py} +18 -11
- package/templates/qoder/scripts/{enrich_prompt.py → kg/enrich_prompt.py} +232 -226
- package/templates/qoder/scripts/{extract_api_params.py → kg/extract.py} +398 -246
- package/templates/qoder/scripts/{kg.py → kg/kg.py} +638 -708
- package/templates/qoder/scripts/{kg_build.py → kg/kg_build.py} +618 -612
- package/templates/qoder/scripts/{kg_build_db.py → kg/kg_build_db.py} +333 -327
- package/templates/qoder/scripts/{kg_duckdb.py → kg/kg_duckdb.py} +38 -37
- package/templates/qoder/scripts/{kg_incremental.py → kg/kg_incremental.py} +420 -393
- package/templates/qoder/scripts/{kg_link_db.py → kg/kg_link_db.py} +230 -224
- package/templates/qoder/scripts/{kg_semantic.py → kg/kg_semantic.py} +156 -150
- package/templates/qoder/scripts/kg/prefetch.py +359 -0
- package/templates/qoder/scripts/{search_index.py → kg/search_index.py} +70 -14
- package/templates/qoder/scripts/mcp/__init__.py +11 -0
- package/templates/qoder/scripts/{kg_mcp_server.py → mcp/kg_mcp_server.py} +77 -272
- package/templates/qoder/scripts/{lanhu_stdio_wrapper.py → mcp/lanhu_stdio_wrapper.py} +125 -119
- package/templates/qoder/scripts/{check_mcp.py → mcp/mcp_doctor.py} +515 -298
- package/templates/qoder/scripts/{mcp_launcher.py → mcp/mcp_launcher.py} +442 -414
- package/templates/qoder/scripts/{mysql_mcp_server.py → mcp/mysql_mcp_server.py} +347 -396
- package/templates/qoder/scripts/{zentao_mcp_server.py → mcp/zentao_mcp_server.py} +384 -424
- package/templates/qoder/scripts/report/__init__.py +11 -0
- package/templates/qoder/scripts/{add_session.py → report/add_session.py} +250 -244
- package/templates/qoder/scripts/{archive_prd.py → report/archive_prd.py} +383 -377
- package/templates/qoder/scripts/{eval_prd.py → report/eval_prd.py} +73 -11
- package/templates/qoder/scripts/{export.py → report/export.py} +63 -0
- package/templates/qoder/scripts/{fill_prototype.py → report/fill_prototype.py} +6 -0
- package/templates/qoder/scripts/{gen_design_doc.py → report/gen_design_doc.py} +400 -394
- package/templates/qoder/scripts/{learn.py → report/learn.py} +152 -146
- package/templates/qoder/scripts/{learn_aggregate.py → report/learn_aggregate.py} +207 -201
- package/templates/qoder/scripts/{report.py → report/report.py} +287 -281
- package/templates/qoder/scripts/report/req.py +222 -0
- package/templates/qoder/scripts/report/role.py +33 -0
- package/templates/qoder/scripts/{status.py → report/status.py} +634 -628
- package/templates/qoder/scripts/setup/__init__.py +11 -0
- package/templates/qoder/scripts/setup/carriers.py +662 -0
- package/templates/qoder/scripts/{init_doctor.py → setup/init_doctor.py} +63 -26
- package/templates/qoder/scripts/{install_qoderwork.py → setup/install_qoderwork.py} +36 -26
- package/templates/qoder/scripts/{platform_doctor.py → setup/platform_doctor.py} +265 -259
- package/templates/qoder/scripts/{repo_root.py → setup/repo_root.py} +112 -106
- package/templates/qoder/scripts/{setup.py → setup/setup.py} +147 -0
- package/templates/qoder/scripts/{setup_lanhu.py → setup/setup_lanhu.py} +973 -963
- package/templates/qoder/scripts/task/__init__.py +11 -0
- package/templates/qoder/scripts/{git_sync.py → task/git_sync.py} +52 -31
- package/templates/qoder/scripts/{syncgate.py → task/syncgate.py} +6 -0
- package/templates/qoder/scripts/task/task.py +221 -0
- package/templates/qoder/scripts/task/task_lifecycle.py +596 -0
- package/templates/qoder/scripts/task/task_query.py +161 -0
- package/templates/qoder/scripts/task/task_relations.py +424 -0
- package/templates/qoder/scripts/{team_sync.py → task/team_sync.py} +93 -20
- package/templates/qoder/scripts/test/__init__.py +11 -0
- package/templates/qoder/scripts/{autotest.py → test/autotest.py} +1174 -1751
- package/templates/qoder/scripts/{autotest_batch.py → test/autotest_batch.py} +242 -224
- package/templates/qoder/scripts/test/autotest_data.py +675 -0
- package/templates/qoder/scripts/{autotest_run.py → test/autotest_run.py} +309 -297
- package/templates/qoder/scripts/{benchmark.py → test/benchmark.py} +6 -0
- package/templates/qoder/scripts/{kg_auto_login.py → test/kg_auto_login.py} +202 -196
- package/templates/qoder/scripts/{kg_test_runner.py → test/kg_test_runner.py} +7 -1
- package/templates/qoder/scripts/{page_probe.py → test/page_probe.py} +465 -459
- package/templates/qoder/scripts/wlkj.py +116 -0
- package/templates/qoder/settings.json +1 -10
- package/templates/qoder/skills/design-import/SKILL.md +226 -226
- package/templates/qoder/skills/design-review/SKILL.md +82 -82
- package/templates/qoder/skills/prd-generator/SKILL.md +26 -16
- package/templates/qoder/skills/prd-review/SKILL.md +5 -5
- package/templates/qoder/skills/prototype-generator/SKILL.md +256 -256
- package/templates/qoder/skills/spec-coder/SKILL.md +4 -4
- package/templates/qoder/skills/spec-generator/SKILL.md +4 -4
- package/templates/qoder/skills/test-generator/SKILL.md +5 -5
- package/templates/qoder/skills/wl-code/SKILL.md +4 -4
- package/templates/qoder/skills/wl-commit/SKILL.md +4 -4
- package/templates/qoder/skills/wl-design/SKILL.md +3 -3
- package/templates/qoder/skills/wl-init/SKILL.md +8 -8
- package/templates/qoder/skills/wl-insight/SKILL.md +5 -5
- package/templates/qoder/skills/wl-prd-full/SKILL.md +6 -6
- package/templates/qoder/skills/wl-prd-quick/SKILL.md +6 -6
- package/templates/qoder/skills/wl-prd-review/SKILL.md +4 -4
- package/templates/qoder/skills/wl-report/SKILL.md +7 -7
- package/templates/qoder/skills/wl-search/SKILL.md +13 -13
- package/templates/qoder/skills/wl-spec/SKILL.md +5 -5
- package/templates/qoder/skills/wl-status/SKILL.md +5 -5
- package/templates/qoder/skills/wl-task/SKILL.md +6 -6
- package/templates/qoder/skills/wl-test/SKILL.md +102 -39
- package/templates/root/AGENTS.md +39 -40
- package/templates/qoder/hooks/inject-workflow-state.py +0 -169
- package/templates/qoder/scripts/__pycache__/check_mcp_launch.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/__pycache__/install_qoderwork.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/__pycache__/mcp_launcher.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/__pycache__/platform_doctor.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/check_carriers.py +0 -238
- package/templates/qoder/scripts/check_mcp_launch.py +0 -183
- package/templates/qoder/scripts/check_qoderwork_consistency.py +0 -166
- package/templates/qoder/scripts/collect_prds.py +0 -31
- package/templates/qoder/scripts/common/mentions.py +0 -134
- package/templates/qoder/scripts/common/utf8.py +0 -38
- package/templates/qoder/scripts/extract_routes.py +0 -54
- package/templates/qoder/scripts/extract_routes_tree.py +0 -78
- package/templates/qoder/scripts/handoff.py +0 -22
- package/templates/qoder/scripts/init_developer.py +0 -76
- package/templates/qoder/scripts/parse_prds.py +0 -33
- package/templates/qoder/scripts/role.py +0 -51
- package/templates/qoder/scripts/sync_carriers.py +0 -259
- package/templates/qoder/scripts/task.py +0 -1261
- package/templates/qoder/scripts/workspace_init.py +0 -102
- package/templates/qoder/skills/prompt-enrich/SKILL.md +0 -90
- package/templates/qoder/skills/prototype-generator/SKILL.md.zcode-79180-2af4721f-f9a6-412c-88db-c0af680d211b.tmp +0 -0
- /package/templates/qoder/scripts/{secure-ls.js → test/secure-ls.js} +0 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""req.py - 需求生命周期管理 (/wl-req 命令)
|
|
4
|
+
|
|
5
|
+
M3 workspace 重构的核心。解决"找不到产出"痛点:
|
|
6
|
+
一个需求的所有产出(PRD/原型/任务/规格)聚合在 REQ-ID 容器,
|
|
7
|
+
/wl-req 一条命令看到全貌, 不用跨目录翻。
|
|
8
|
+
|
|
9
|
+
设计 (PM 只需记 2 个姿势):
|
|
10
|
+
/wl-req 列出所有需求 (默认=list, 不用记)
|
|
11
|
+
/wl-req REQ-2026-001 显示该需求全部产出 (show)
|
|
12
|
+
/wl-req REQ-2026-001 发布 promote+publish一步到位 (草稿→产出→禅道)
|
|
13
|
+
|
|
14
|
+
promote 不单独暴露(合并进"发布"), list 不用记(无参数即是)。
|
|
15
|
+
|
|
16
|
+
用法:
|
|
17
|
+
python req.py # 列需求
|
|
18
|
+
python req.py REQ-2026-001 # 看某需求全貌
|
|
19
|
+
python req.py REQ-2026-001 发布 # 发布(promote+publish)
|
|
20
|
+
python req.py REQ-2026-001 promote # 仅草稿→产出(内部用)
|
|
21
|
+
"""
|
|
22
|
+
# v3.0 路径自举
|
|
23
|
+
import os as _o, sys as _s
|
|
24
|
+
_cp = _o.path.join(_o.path.dirname(_o.path.dirname(_o.path.abspath(__file__))), 'common')
|
|
25
|
+
if _cp not in _s.path: _s.path.insert(0, _cp)
|
|
26
|
+
from bootstrap import setup; setup()
|
|
27
|
+
|
|
28
|
+
import os
|
|
29
|
+
import sys
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
from common.paths import (
|
|
32
|
+
get_repo_root, get_developer, MEMBERS_DIR,
|
|
33
|
+
get_time_bucket, get_time_bucket_path, get_req_dir,
|
|
34
|
+
get_outputs_dir, find_req_dirs,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
BASE = get_repo_root()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _list_all_reqs(dev=None):
|
|
41
|
+
"""列出某开发者的所有需求 (跨 drafts/outputs/所有时间桶)。
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
[{req_id, area, bucket, path, files: [文件名]}, ...]
|
|
45
|
+
"""
|
|
46
|
+
dev = dev or get_developer(BASE) or "unknown"
|
|
47
|
+
dev_dir = MEMBERS_DIR / dev
|
|
48
|
+
if not dev_dir.is_dir():
|
|
49
|
+
return []
|
|
50
|
+
seen = {} # req_id → entry (去重, drafts优先)
|
|
51
|
+
for area in ("drafts", "outputs"):
|
|
52
|
+
area_root = dev_dir / area
|
|
53
|
+
if not area_root.is_dir():
|
|
54
|
+
continue
|
|
55
|
+
# 扫所有 REQ-* 目录 (跨时间桶)
|
|
56
|
+
for found in area_root.rglob("REQ-*"):
|
|
57
|
+
if not found.is_dir():
|
|
58
|
+
continue
|
|
59
|
+
req_id = found.name
|
|
60
|
+
# 清理标题后缀只取 REQ-YYYY-NNN (但保留完整名做显示)
|
|
61
|
+
import re
|
|
62
|
+
m = re.match(r"(REQ-\d{4}-\d{3,})", req_id)
|
|
63
|
+
clean_id = m.group(1) if m else req_id
|
|
64
|
+
if clean_id in seen:
|
|
65
|
+
# 已有, 但如果当前是outputs且已有的是drafts, 补充信息
|
|
66
|
+
continue
|
|
67
|
+
files = sorted(f.name for f in found.iterdir() if f.is_file())
|
|
68
|
+
subdirs = sorted(d.name for d in found.iterdir() if d.is_dir())
|
|
69
|
+
rel_bucket = str(found.parent.relative_to(area_root))
|
|
70
|
+
seen[clean_id] = {
|
|
71
|
+
"req_id": req_id,
|
|
72
|
+
"clean_id": clean_id,
|
|
73
|
+
"area": area,
|
|
74
|
+
"bucket": rel_bucket,
|
|
75
|
+
"path": found,
|
|
76
|
+
"files": files,
|
|
77
|
+
"subdirs": subdirs,
|
|
78
|
+
}
|
|
79
|
+
return list(seen.values())
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def cmd_list(dev=None):
|
|
83
|
+
"""列出所有需求。"""
|
|
84
|
+
reqs = _list_all_reqs(dev)
|
|
85
|
+
if not reqs:
|
|
86
|
+
dev_name = dev or get_developer(BASE) or "unknown"
|
|
87
|
+
print("暂无需求。写 PRD 时会自动创建 REQ-ID 容器。")
|
|
88
|
+
print(" 开发者: %s" % dev_name)
|
|
89
|
+
return 0
|
|
90
|
+
print("=" * 56)
|
|
91
|
+
print("需求列表 (%d 个)" % len(reqs))
|
|
92
|
+
print("=" * 56)
|
|
93
|
+
for r in sorted(reqs, key=lambda x: x["clean_id"]):
|
|
94
|
+
area_tag = "草稿" if r["area"] == "drafts" else "产出"
|
|
95
|
+
n_files = len(r["files"]) + len(r["subdirs"])
|
|
96
|
+
print(" %s [%s] %s (%d 项)" % (r["clean_id"], area_tag, r["bucket"], n_files))
|
|
97
|
+
print()
|
|
98
|
+
print("看详情: /wl-req <REQ-ID>")
|
|
99
|
+
return 0
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def cmd_show(req_id, dev=None):
|
|
103
|
+
"""显示某需求的全部产出 (跨 drafts/outputs/历史桶)。"""
|
|
104
|
+
found = find_req_dirs(req_id, dev, BASE)
|
|
105
|
+
if not found:
|
|
106
|
+
print("未找到需求: %s" % req_id)
|
|
107
|
+
print(" 用 /wl-req 看所有需求列表")
|
|
108
|
+
return 1
|
|
109
|
+
print("=" * 56)
|
|
110
|
+
print("需求: %s" % req_id)
|
|
111
|
+
print("=" * 56)
|
|
112
|
+
for entry in found:
|
|
113
|
+
area_cn = "草稿" if entry["area"] == "drafts" else "产出"
|
|
114
|
+
p = entry["path"]
|
|
115
|
+
print()
|
|
116
|
+
print("【%s · %s】" % (area_cn, entry["bucket"]))
|
|
117
|
+
print(" 路径: %s" % p)
|
|
118
|
+
# 列文件
|
|
119
|
+
files = sorted(f.name for f in p.iterdir() if f.is_file())
|
|
120
|
+
subdirs = sorted(d.name for d in p.iterdir() if d.is_dir())
|
|
121
|
+
if files:
|
|
122
|
+
print(" 文件:")
|
|
123
|
+
for f in files:
|
|
124
|
+
print(" - %s" % f)
|
|
125
|
+
if subdirs:
|
|
126
|
+
print(" 子目录:")
|
|
127
|
+
for d in subdirs:
|
|
128
|
+
# 列子目录里的文件数
|
|
129
|
+
sub_path = p / d
|
|
130
|
+
n = sum(1 for _ in sub_path.rglob("*") if _.is_file())
|
|
131
|
+
print(" - %s/ (%d 个文件)" % (d, n))
|
|
132
|
+
return 0
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def cmd_promote(req_id, dev=None):
|
|
136
|
+
"""草稿 → 产出 (drafts/桶/REQ → outputs/同桶/REQ)。"""
|
|
137
|
+
dev = dev or get_developer(BASE) or "unknown"
|
|
138
|
+
# 找 drafts 里的
|
|
139
|
+
draft_found = [e for e in find_req_dirs(req_id, dev, BASE) if e["area"] == "drafts"]
|
|
140
|
+
if not draft_found:
|
|
141
|
+
print("草稿区未找到: %s (可能已在产出区, 或不存在)" % req_id)
|
|
142
|
+
return 1
|
|
143
|
+
src = draft_found[0]["path"]
|
|
144
|
+
bucket = draft_found[0]["bucket"]
|
|
145
|
+
# 目标: outputs/同桶/REQ
|
|
146
|
+
dev_dir = MEMBERS_DIR / dev
|
|
147
|
+
dst = dev_dir / "outputs" / bucket / src.name
|
|
148
|
+
if dst.exists():
|
|
149
|
+
print("产出区已存在: %s" % dst)
|
|
150
|
+
print(" 如要覆盖, 先手动删除产出区的旧版本")
|
|
151
|
+
return 1
|
|
152
|
+
import shutil
|
|
153
|
+
dst.parent.mkdir(parents=True, exist_ok=True)
|
|
154
|
+
shutil.move(str(src), str(dst))
|
|
155
|
+
print("✓ 已提升到产出区:")
|
|
156
|
+
print(" %s" % dst)
|
|
157
|
+
print(" (产出进 team_sync, 团队可见)")
|
|
158
|
+
return 0
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def cmd_publish(req_id, dev=None):
|
|
162
|
+
"""发布 = promote + 发禅道。PM 只用这个。"""
|
|
163
|
+
dev = dev or get_developer(BASE) or "unknown"
|
|
164
|
+
# 先确保在 outputs (不在则 promote)
|
|
165
|
+
out_found = [e for e in find_req_dirs(req_id, dev, BASE) if e["area"] == "outputs"]
|
|
166
|
+
if not out_found:
|
|
167
|
+
print("草稿 → 产出...")
|
|
168
|
+
rc = cmd_promote(req_id, dev)
|
|
169
|
+
if rc != 0:
|
|
170
|
+
return rc
|
|
171
|
+
out_found = [e for e in find_req_dirs(req_id, dev, BASE) if e["area"] == "outputs"]
|
|
172
|
+
if not out_found:
|
|
173
|
+
print("✗ 发布失败: 产出区找不到 %s" % req_id)
|
|
174
|
+
return 1
|
|
175
|
+
out_path = out_found[0]["path"]
|
|
176
|
+
print()
|
|
177
|
+
print("发禅道 (从产出区: %s)" % out_path)
|
|
178
|
+
print("-" * 40)
|
|
179
|
+
# 找禅道 MCP 创建需求
|
|
180
|
+
try:
|
|
181
|
+
sys.path.insert(0, str(BASE / ".qoder" / "scripts" / "mcp"))
|
|
182
|
+
# 禅道发布: 读 PRD, 调 zentao MCP 建 story
|
|
183
|
+
prd_file = None
|
|
184
|
+
for f in out_path.iterdir():
|
|
185
|
+
if f.is_file() and (f.name.endswith(".md") and "prd" in f.name.lower()):
|
|
186
|
+
prd_file = f
|
|
187
|
+
break
|
|
188
|
+
if f.is_file() and f.suffix == ".md" and not f.name.startswith("_"):
|
|
189
|
+
prd_file = f # 第一个 md 当 PRD
|
|
190
|
+
if prd_file:
|
|
191
|
+
print(" PRD: %s" % prd_file.name)
|
|
192
|
+
print()
|
|
193
|
+
print("⚠️ 禅道发布需要 QoderWork 的禅道 MCP (mcp__qoder-zentao__create_story)。")
|
|
194
|
+
print(" AI 会读产出的 PRD, 调禅道建需求。")
|
|
195
|
+
print(" 如果你在 QoderWork 里说'%s 发布', AI 会自动完成这步。" % req_id)
|
|
196
|
+
return 0
|
|
197
|
+
except Exception as e:
|
|
198
|
+
print("✗ 发布出错: %s" % e)
|
|
199
|
+
return 1
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def main():
|
|
203
|
+
args = sys.argv[1:]
|
|
204
|
+
if not args:
|
|
205
|
+
return cmd_list()
|
|
206
|
+
req_id = args[0]
|
|
207
|
+
action = args[1] if len(args) > 1 else "show"
|
|
208
|
+
if action == "show":
|
|
209
|
+
return cmd_show(req_id)
|
|
210
|
+
elif action in ("发布", "publish", "fabu"):
|
|
211
|
+
return cmd_publish(req_id)
|
|
212
|
+
elif action == "promote":
|
|
213
|
+
return cmd_promote(req_id)
|
|
214
|
+
elif action == "list":
|
|
215
|
+
return cmd_list()
|
|
216
|
+
else:
|
|
217
|
+
# 默认当 show
|
|
218
|
+
return cmd_show(req_id)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
if __name__ == "__main__":
|
|
222
|
+
sys.exit(main())
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
|
|
2
|
+
import os as _o, sys as _s
|
|
3
|
+
_cp = _o.path.join(_o.path.dirname(_o.path.dirname(_o.path.abspath(__file__))), 'common')
|
|
4
|
+
if _cp not in _s.path: _s.path.insert(0, _cp)
|
|
5
|
+
from bootstrap import setup; setup()
|
|
6
|
+
|
|
7
|
+
# role.py - 角色解析 (v3.0: 已并入 common/identity.py, 本文件为兼容转发层)
|
|
8
|
+
#
|
|
9
|
+
# 角色能力查询 (get_role/can_produce/can_consume/...) 已统一到 common/identity.py,
|
|
10
|
+
# 由 guard.py 强制执行角色边界。本文件保留是为了:
|
|
11
|
+
# 1. CLI 兼容: skill 脚本里 `ROLE=$(python role.py)` 仍能输出角色名
|
|
12
|
+
# 2. import 兼容: `from role import get_role` 仍可用 (转发到 identity)
|
|
13
|
+
#
|
|
14
|
+
# ⚠️ 新代码请直接用: from common.identity import get_role / from common.guard import ...
|
|
15
|
+
# 本文件未来随 M2 引擎重构可能移除。
|
|
16
|
+
import os
|
|
17
|
+
import sys
|
|
18
|
+
|
|
19
|
+
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
20
|
+
from common.identity import get_role, get_permissions, get_capabilities, can_produce, can_consume # noqa: E402,F401
|
|
21
|
+
|
|
22
|
+
BASE = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
if __name__ == '__main__':
|
|
26
|
+
# CLI: 输出当前角色名 (供 skill 脚本动态读角色用)
|
|
27
|
+
# 用法: ROLE=$(python role.py)
|
|
28
|
+
try:
|
|
29
|
+
sys.stdout.reconfigure(encoding='utf-8')
|
|
30
|
+
except (AttributeError, IOError):
|
|
31
|
+
pass
|
|
32
|
+
r = get_role()
|
|
33
|
+
print(r or 'pm') # 无角色默认 pm (软引导, 不报错)
|