@hupan56/wlkj 2.7.12 → 3.1.2
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 +1435 -1107
- package/package.json +29 -29
- 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 +161 -161
- package/templates/qoder/commands/optional/wl-report.md +20 -39
- package/templates/qoder/commands/optional/wl-status.md +4 -4
- package/templates/qoder/commands/wl-code.md +2 -2
- package/templates/qoder/commands/wl-design.md +6 -6
- package/templates/qoder/commands/wl-init.md +3 -3
- package/templates/qoder/commands/wl-prd.md +26 -13
- package/templates/qoder/commands/wl-req.md +43 -0
- package/templates/qoder/commands/wl-search.md +78 -47
- package/templates/qoder/commands/wl-task.md +343 -40
- package/templates/qoder/commands/wl-test.md +43 -17
- package/templates/qoder/config.yaml +52 -14
- package/templates/qoder/hooks/post-tool-use.py +181 -0
- package/templates/qoder/hooks/session-start.py +94 -23
- package/templates/qoder/hooks/stop-eval.py +207 -0
- package/templates/qoder/hooks/user-prompt-submit.py +139 -0
- package/templates/qoder/rules/wl-pipeline.md +85 -49
- package/templates/qoder/scripts/README.md +102 -0
- package/templates/qoder/scripts/capability/__init__.py +26 -0
- package/templates/qoder/scripts/capability/__main__.py +72 -0
- package/templates/qoder/scripts/capability/adapters/__init__.py +29 -0
- package/templates/qoder/scripts/capability/adapters/cli.py +316 -0
- package/templates/qoder/scripts/capability/adapters/mcp.py +334 -0
- package/templates/qoder/scripts/capability/adapters/qw.py +271 -0
- package/templates/qoder/scripts/capability/caps/__init__.py +27 -0
- package/templates/qoder/scripts/capability/caps/context.py +36 -0
- package/templates/qoder/scripts/capability/caps/cron.py +50 -0
- package/templates/qoder/scripts/capability/caps/identity.py +43 -0
- package/templates/qoder/scripts/capability/caps/memory.py +71 -0
- package/templates/qoder/scripts/capability/caps/notify.py +41 -0
- package/templates/qoder/scripts/capability/caps/present.py +48 -0
- package/templates/qoder/scripts/capability/caps/repo.py +31 -0
- package/templates/qoder/scripts/capability/caps/sandbox.py +43 -0
- package/templates/qoder/scripts/capability/chain.py +92 -0
- package/templates/qoder/scripts/capability/memory_chain.py +41 -0
- package/templates/qoder/scripts/capability/registry.py +246 -0
- package/templates/qoder/scripts/capability/registry_mcp.py +250 -0
- package/templates/qoder/scripts/capability/smoke_test.py +211 -0
- package/templates/qoder/scripts/capability/smoke_test_report.json +94 -0
- package/templates/qoder/scripts/deployment/setup/__init__.py +11 -0
- package/templates/qoder/scripts/deployment/setup/carriers.py +669 -0
- package/templates/qoder/scripts/deployment/setup/carriers_verify.py +148 -0
- package/templates/qoder/scripts/{init_doctor.py → deployment/setup/init_doctor.py} +100 -39
- package/templates/qoder/scripts/{install_qoderwork.py → deployment/setup/install_qoderwork.py} +48 -30
- package/templates/qoder/scripts/{platform_doctor.py → deployment/setup/platform_doctor.py} +271 -259
- package/templates/qoder/scripts/{repo_root.py → deployment/setup/repo_root.py} +9 -2
- package/templates/qoder/scripts/{setup.py → deployment/setup/setup.py} +143 -14
- package/templates/qoder/scripts/{setup_lanhu.py → deployment/setup/setup_lanhu.py} +979 -963
- package/templates/qoder/scripts/domain/design/__init__.py +0 -0
- package/templates/qoder/scripts/{fill_prototype.py → domain/design/fill_prototype.py} +17 -5
- package/templates/qoder/scripts/{gen_design_doc.py → domain/design/gen_design_doc.py} +406 -394
- package/templates/qoder/scripts/domain/kg/__init__.py +11 -0
- package/templates/qoder/scripts/domain/kg/build/__init__.py +0 -0
- package/templates/qoder/scripts/domain/kg/build/build_entity_registry.py +201 -0
- package/templates/qoder/scripts/domain/kg/build/build_relations.py +132 -0
- package/templates/qoder/scripts/{build_style_index.py → domain/kg/build/build_style_index.py} +50 -15
- package/templates/qoder/scripts/domain/kg/build/build_workflows.py +149 -0
- package/templates/qoder/scripts/{kg_build.py → domain/kg/build/kg_build.py} +685 -612
- package/templates/qoder/scripts/{kg_build_db.py → domain/kg/build/kg_build_db.py} +338 -327
- package/templates/qoder/scripts/{kg_incremental.py → domain/kg/build/kg_incremental.py} +425 -393
- package/templates/qoder/scripts/{learn_aggregate.py → domain/kg/build/learn_aggregate.py} +212 -201
- package/templates/qoder/scripts/domain/kg/extract/__init__.py +0 -0
- package/templates/qoder/scripts/{common → domain/kg/extract}/extract.py +430 -419
- package/templates/qoder/scripts/domain/kg/extract/test_extract.py +115 -0
- package/templates/qoder/scripts/{common → domain/kg/extract}/ts_extract.py +614 -536
- package/templates/qoder/scripts/domain/kg/graph/__init__.py +0 -0
- package/templates/qoder/scripts/{kg_link_db.py → domain/kg/graph/kg_link_db.py} +235 -224
- package/templates/qoder/scripts/domain/kg/graph/kg_semantic.py +683 -0
- package/templates/qoder/scripts/{kg.py → domain/kg/kg.py} +871 -708
- package/templates/qoder/scripts/domain/kg/kg_capabilities.py +182 -0
- package/templates/qoder/scripts/domain/kg/search/__init__.py +0 -0
- package/templates/qoder/scripts/{context_pack.py → domain/kg/search/context_pack.py} +45 -17
- package/templates/qoder/scripts/{enrich_prompt.py → domain/kg/search/enrich_prompt.py} +238 -226
- package/templates/qoder/scripts/domain/kg/search/prefetch.py +384 -0
- package/templates/qoder/scripts/{common → domain/kg/search}/search_engine.py +207 -205
- package/templates/qoder/scripts/{search_index.py → domain/kg/search/search_index.py} +210 -88
- package/templates/qoder/scripts/domain/kg/server/__init__.py +0 -0
- package/templates/qoder/scripts/domain/kg/server/kgd.py +549 -0
- package/templates/qoder/scripts/domain/kg/server/perf_bench.py +197 -0
- package/templates/qoder/scripts/domain/kg/storage/__init__.py +0 -0
- package/templates/qoder/scripts/{kg_duckdb.py → domain/kg/storage/kg_duckdb.py} +70 -45
- package/templates/qoder/scripts/domain/learning/__init__.py +0 -0
- package/templates/qoder/scripts/{learn.py → domain/learning/learn.py} +157 -146
- package/templates/qoder/scripts/domain/report/__init__.py +11 -0
- package/templates/qoder/scripts/{add_session.py → domain/report/add_session.py} +256 -244
- package/templates/qoder/scripts/{export.py → domain/report/export.py} +72 -4
- package/templates/qoder/scripts/{report.py → domain/report/report.py} +292 -281
- package/templates/qoder/scripts/domain/report/report_snapshot.py +261 -0
- package/templates/qoder/scripts/domain/report/role.py +39 -0
- package/templates/qoder/scripts/{status.py → domain/report/status.py} +737 -628
- package/templates/qoder/scripts/domain/report/status_snapshot.py +191 -0
- package/templates/qoder/scripts/domain/requirement/__init__.py +0 -0
- package/templates/qoder/scripts/{archive_prd.py → domain/requirement/archive_prd.py} +389 -377
- package/templates/qoder/scripts/domain/requirement/req.py +228 -0
- package/templates/qoder/scripts/domain/task/__init__.py +11 -0
- package/templates/qoder/scripts/{git_sync.py → domain/task/git_sync.py} +90 -50
- package/templates/qoder/scripts/{syncgate.py → domain/task/syncgate.py} +18 -7
- package/templates/qoder/scripts/domain/task/task.py +229 -0
- package/templates/qoder/scripts/domain/task/task_lifecycle.py +606 -0
- package/templates/qoder/scripts/domain/task/task_query.py +162 -0
- package/templates/qoder/scripts/domain/task/task_relations.py +425 -0
- package/templates/qoder/scripts/{team_sync.py → domain/task/team_sync.py} +101 -23
- package/templates/qoder/scripts/domain/task/zentao_sync.py +370 -0
- package/templates/qoder/scripts/foundation/__init__.py +0 -0
- package/templates/qoder/scripts/foundation/bootstrap.py +145 -0
- package/templates/qoder/scripts/foundation/core/__init__.py +0 -0
- package/templates/qoder/scripts/foundation/core/cmd_registry.py +112 -0
- package/templates/qoder/scripts/foundation/core/config.py +187 -0
- package/templates/qoder/scripts/{common → foundation/core}/paths.py +706 -400
- package/templates/qoder/scripts/foundation/data/__init__.py +0 -0
- package/templates/qoder/scripts/foundation/data/contract.py +317 -0
- package/templates/qoder/scripts/{common → foundation/data}/events.py +2 -2
- package/templates/qoder/scripts/foundation/data/result.py +223 -0
- package/templates/qoder/scripts/{common → foundation/data}/task_utils.py +427 -392
- package/templates/qoder/scripts/foundation/identity/__init__.py +0 -0
- package/templates/qoder/scripts/foundation/identity/check_publish.py +103 -0
- package/templates/qoder/scripts/{common → foundation/identity}/developer.py +239 -238
- package/templates/qoder/scripts/foundation/identity/guard.py +159 -0
- package/templates/qoder/scripts/{common → foundation/identity}/identity.py +132 -9
- package/templates/qoder/scripts/foundation/identity/roles.py +60 -0
- package/templates/qoder/scripts/foundation/integrations/__init__.py +0 -0
- package/templates/qoder/scripts/{common → foundation/integrations}/active_task.py +30 -15
- package/templates/qoder/scripts/{common → foundation/integrations}/feishu.py +11 -10
- package/templates/qoder/scripts/{common → foundation/integrations}/terms.py +3 -3
- package/templates/qoder/scripts/foundation/integrations/zentao_client.py +220 -0
- package/templates/qoder/scripts/foundation/io/__init__.py +0 -0
- package/templates/qoder/scripts/{common → foundation/io}/filelock.py +1 -1
- package/templates/qoder/scripts/{common → foundation/io}/reqid.py +1 -1
- package/templates/qoder/scripts/foundation/protocol/__init__.py +0 -0
- package/templates/qoder/scripts/foundation/protocol/duckdb_conn.py +39 -0
- package/templates/qoder/scripts/foundation/protocol/mcp_base.py +268 -0
- package/templates/qoder/scripts/foundation/utils/__init__.py +0 -0
- package/templates/qoder/scripts/{common → foundation/utils}/eval_api.py +12 -1
- package/templates/qoder/scripts/{common → foundation/utils}/pip_install.py +23 -6
- package/templates/qoder/scripts/{common → foundation/utils}/platform_guard.py +1 -1
- package/templates/qoder/scripts/orchestration/__init__.py +0 -0
- package/templates/qoder/scripts/orchestration/wlkj.py +185 -0
- package/templates/qoder/scripts/protocol/__init__.py +0 -0
- package/templates/qoder/scripts/protocol/browser/README.md +207 -0
- package/templates/qoder/scripts/protocol/browser/SKILL.md +265 -0
- package/templates/qoder/scripts/protocol/browser/config.env +9 -0
- package/templates/qoder/scripts/protocol/browser/references/cdp-api.md +110 -0
- package/templates/qoder/scripts/protocol/browser/references/migration-2.5.3.md +72 -0
- package/templates/qoder/scripts/protocol/browser/references/site-patterns/.gitkeep +0 -0
- package/templates/qoder/scripts/protocol/browser/scripts/browser-discovery.mjs +138 -0
- package/templates/qoder/scripts/protocol/browser/scripts/cdp-proxy.mjs +672 -0
- package/templates/qoder/scripts/protocol/browser/scripts/check-deps.mjs +206 -0
- package/templates/qoder/scripts/protocol/browser/scripts/find-url.mjs +253 -0
- package/templates/qoder/scripts/protocol/browser/scripts/match-site.mjs +46 -0
- package/templates/qoder/scripts/protocol/browser/templates/config.env.template +9 -0
- package/templates/qoder/scripts/protocol/mcp/__init__.py +11 -0
- package/templates/qoder/scripts/protocol/mcp/kg_mcp_server.py +478 -0
- package/templates/qoder/scripts/{lanhu_stdio_wrapper.py → protocol/mcp/lanhu_stdio_wrapper.py} +131 -119
- package/templates/qoder/scripts/protocol/mcp/mcp_doctor.py +548 -0
- package/templates/qoder/scripts/protocol/mcp/mcp_launcher.py +600 -0
- package/templates/qoder/scripts/protocol/mcp/mysql_mcp_server.py +461 -0
- package/templates/qoder/scripts/protocol/mcp/zentao_mcp_server.py +1920 -0
- package/templates/qoder/scripts/protocol/transports/__init__.py +56 -0
- package/templates/qoder/scripts/protocol/transports/base.py +87 -0
- package/templates/qoder/scripts/protocol/transports/cli.py +132 -0
- package/templates/qoder/scripts/protocol/transports/http.py +141 -0
- package/templates/qoder/scripts/protocol/transports/stdio.py +293 -0
- package/templates/qoder/scripts/run_weekly_update.bat +27 -18
- package/templates/qoder/scripts/run_weekly_update.sh +22 -13
- package/templates/qoder/scripts/validation/__init__.py +0 -0
- package/templates/qoder/scripts/validation/eval/__init__.py +0 -0
- package/templates/qoder/scripts/validation/eval/perf-report-2026-06-24.md +139 -0
- package/templates/qoder/scripts/validation/eval/qwork_harness.py +617 -0
- package/templates/qoder/scripts/validation/eval/report-commands.md +220 -0
- package/templates/qoder/scripts/validation/eval/transcript_timing.py +386 -0
- package/templates/qoder/scripts/validation/metrics/__init__.py +0 -0
- package/templates/qoder/scripts/{eval_prd.py → validation/metrics/eval_prd.py} +84 -15
- package/templates/qoder/scripts/validation/metrics/usability_score.py +750 -0
- package/templates/qoder/scripts/validation/test/__init__.py +11 -0
- package/templates/qoder/scripts/validation/test/assertion_gen.py +551 -0
- package/templates/qoder/scripts/{autotest.py → validation/test/autotest.py} +1234 -1751
- package/templates/qoder/scripts/validation/test/autotest_auth.py +109 -0
- package/templates/qoder/scripts/{autotest_batch.py → validation/test/autotest_batch.py} +255 -224
- package/templates/qoder/scripts/validation/test/autotest_data.py +680 -0
- package/templates/qoder/scripts/validation/test/autotest_opencli.py +646 -0
- package/templates/qoder/scripts/{autotest_run.py → validation/test/autotest_run.py} +323 -297
- package/templates/qoder/scripts/validation/test/autotest_webaccess.py +571 -0
- package/templates/qoder/scripts/{benchmark.py → validation/test/benchmark.py} +17 -5
- package/templates/qoder/scripts/{kg_auto_login.py → validation/test/kg_auto_login.py} +208 -196
- package/templates/qoder/scripts/{kg_test_runner.py → validation/test/kg_test_runner.py} +13 -2
- package/templates/qoder/scripts/{page_probe.py → validation/test/page_probe.py} +470 -459
- package/templates/qoder/scripts/validation/test/smoke_all_commands.py +170 -0
- package/templates/qoder/settings.json +23 -2
- package/templates/qoder/skills/design-import/SKILL.md +235 -226
- package/templates/qoder/skills/design-review/SKILL.md +91 -82
- package/templates/qoder/skills/prd-generator/SKILL.md +38 -24
- package/templates/qoder/skills/prd-review/SKILL.md +8 -6
- package/templates/qoder/skills/prototype-generator/SKILL.md +296 -247
- package/templates/qoder/skills/spec-coder/SKILL.md +24 -15
- package/templates/qoder/skills/spec-generator/SKILL.md +24 -12
- package/templates/qoder/skills/test-generator/SKILL.md +9 -7
- package/templates/qoder/skills/wl-code/SKILL.md +25 -13
- package/templates/qoder/skills/wl-commit/SKILL.md +10 -9
- package/templates/qoder/skills/wl-design/SKILL.md +7 -5
- package/templates/qoder/skills/wl-init/SKILL.md +8 -8
- package/templates/qoder/skills/wl-insight/SKILL.md +25 -12
- package/templates/qoder/skills/wl-prd-full/SKILL.md +59 -8
- package/templates/qoder/skills/wl-prd-quick/SKILL.md +7 -7
- package/templates/qoder/skills/wl-prd-review/SKILL.md +18 -6
- package/templates/qoder/skills/wl-report/SKILL.md +27 -25
- package/templates/qoder/skills/wl-search/SKILL.md +151 -80
- package/templates/qoder/skills/wl-spec/SKILL.md +9 -7
- package/templates/qoder/skills/wl-status/SKILL.md +50 -18
- package/templates/qoder/skills/wl-task/SKILL.md +94 -12
- package/templates/qoder/skills/wl-test/SKILL.md +154 -45
- package/templates/qoder/templates/prd-full-template.md +7 -0
- package/templates/root/AGENTS.md +275 -237
- package/templates/root/requirements.txt +3 -0
- package/templates/root//344/275/277/347/224/250/350/257/264/346/230/216.md +3 -3
- package/templates/root//346/226/260/346/211/213/346/214/207/345/215/227.md +2 -2
- 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.py +0 -298
- 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_api_params.py +0 -246
- 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/kg_mcp_server.py +0 -801
- package/templates/qoder/scripts/kg_semantic.py +0 -150
- package/templates/qoder/scripts/mcp_launcher.py +0 -414
- package/templates/qoder/scripts/mysql_mcp_server.py +0 -396
- 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/scripts/zentao_mcp_server.py +0 -424
- package/templates/qoder/skills/prompt-enrich/SKILL.md +0 -90
- /package/templates/qoder/scripts/{common → deployment}/__init__.py +0 -0
- /package/templates/qoder/{skills/prototype-generator/SKILL.md.zcode-79180-2af4721f-f9a6-412c-88db-c0af680d211b.tmp → scripts/domain/__init__.py} +0 -0
- /package/templates/qoder/scripts/{common → domain/kg/graph}/graph_traverse.py +0 -0
- /package/templates/qoder/scripts/{common → domain/kg/server}/repowiki.py +0 -0
- /package/templates/qoder/scripts/{common → foundation/io}/atomicio.py +0 -0
- /package/templates/qoder/scripts/{secure-ls.js → validation/test/secure-ls.js} +0 -0
|
File without changes
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# v3.0 路径自举
|
|
3
|
+
import os as _o, sys as _s
|
|
4
|
+
_f = _o.path.abspath(__file__)
|
|
5
|
+
for _ in range(10):
|
|
6
|
+
_f = _o.path.dirname(_f)
|
|
7
|
+
_cp = _o.path.join(_f, 'foundation')
|
|
8
|
+
if _o.path.isfile(_o.path.join(_cp, 'bootstrap.py')):
|
|
9
|
+
break
|
|
10
|
+
if _cp not in _s.path: _s.path.insert(0, _cp)
|
|
11
|
+
from bootstrap import setup; setup()
|
|
12
|
+
|
|
13
|
+
"""
|
|
14
|
+
check_publish.py - 统一发布前置检查 (guard + contract 双门)
|
|
15
|
+
|
|
16
|
+
把"造了没接"的两个基建真正接入执行链路:
|
|
17
|
+
- guard.py (角色边界): 当前角色能否产出该契约? 越权 → 软提示
|
|
18
|
+
- contract.py (契约校验): 产出文件带不带 @contract 头? 带了是否合规?
|
|
19
|
+
|
|
20
|
+
设计原则 (与 guard/contract 一致):
|
|
21
|
+
- 降级不阻塞: 越权/无契约头/校验警告 → 打印提示但 exit 0 (让用户决定)
|
|
22
|
+
- 只有"硬错误"(契约校验 FAIL) → exit 1, 阻止发布
|
|
23
|
+
- 统一入口: 所有产出型 skill 发布前调这一个脚本, 不用各自接 guard/contract
|
|
24
|
+
|
|
25
|
+
用法:
|
|
26
|
+
python .qoder/scripts/common/check_publish.py <契约类型> <产出文件路径>
|
|
27
|
+
python .qoder/scripts/common/check_publish.py prd workspace/.../REQ-2026-001-xxx.md
|
|
28
|
+
python .qoder/scripts/common/check_publish.py design-spec workspace/.../xxx-design-spec.json
|
|
29
|
+
python .qoder/scripts/common/check_publish.py test-cases workspace/.../xxx-cases.json
|
|
30
|
+
|
|
31
|
+
退出码:
|
|
32
|
+
0 = 通过 (含软警告, 可发布)
|
|
33
|
+
1 = 硬失败 (契约校验 FAIL, 建议不发布)
|
|
34
|
+
2 = 参数错误 / 内部异常
|
|
35
|
+
|
|
36
|
+
输出: 人类可读的检查报告 (角色 + 契约两段)
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
import sys
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def run(contract_type, artifact_path):
|
|
43
|
+
"""跑 guard + contract 双门检查。返回 exit code。"""
|
|
44
|
+
# ============ 门 1: 角色边界 (guard) ============
|
|
45
|
+
# 越权只软提示, 不阻塞 (ensure=False)
|
|
46
|
+
print('--- 角色边界检查 ---')
|
|
47
|
+
try:
|
|
48
|
+
from foundation.identity.guard import check_produce
|
|
49
|
+
gr = check_produce(contract_type)
|
|
50
|
+
if gr.ok and not gr.is_warn:
|
|
51
|
+
print('✓', gr.msg)
|
|
52
|
+
else:
|
|
53
|
+
# 越权 (WARN): 提示但仍可继续
|
|
54
|
+
print(gr.msg)
|
|
55
|
+
if gr.hint:
|
|
56
|
+
print(' →', gr.hint)
|
|
57
|
+
print(' (软提示, 不阻塞发布。若需切换角色: /wl-init)')
|
|
58
|
+
except Exception as e:
|
|
59
|
+
print('⚠️ 角色检查不可用 ({}), 跳过'.format(str(e)[:60]))
|
|
60
|
+
|
|
61
|
+
# ============ 门 2: 契约校验 (contract) ============
|
|
62
|
+
print()
|
|
63
|
+
print('--- 契约校验 ---')
|
|
64
|
+
import os
|
|
65
|
+
if not os.path.isfile(artifact_path):
|
|
66
|
+
print('⚠️ 产出文件不存在: {}'.format(artifact_path))
|
|
67
|
+
print(' (跳过契约校验)')
|
|
68
|
+
return 0
|
|
69
|
+
try:
|
|
70
|
+
from foundation.data.contract import validate_contract
|
|
71
|
+
cr = validate_contract(artifact_path)
|
|
72
|
+
if cr.ok and not cr.is_warn:
|
|
73
|
+
print('✓', cr.msg)
|
|
74
|
+
return 0
|
|
75
|
+
elif cr.is_warn:
|
|
76
|
+
# 警告 (无契约头/字段警告/无schema): 软门禁, 可继续
|
|
77
|
+
print(cr.msg)
|
|
78
|
+
if cr.hint:
|
|
79
|
+
print(' →', cr.hint)
|
|
80
|
+
return 0
|
|
81
|
+
else:
|
|
82
|
+
# FAIL (硬错误): 缺必填/类型错/枚举越界 → 阻止
|
|
83
|
+
print('[FAIL]', cr.msg)
|
|
84
|
+
if cr.hint:
|
|
85
|
+
print(' →', cr.hint)
|
|
86
|
+
print(' (硬失败, 建议修正后再发布)')
|
|
87
|
+
return 1
|
|
88
|
+
except Exception as e:
|
|
89
|
+
print('⚠️ 契约校验异常 ({}), 跳过'.format(str(e)[:60]))
|
|
90
|
+
return 0
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def main():
|
|
94
|
+
if len(sys.argv) < 3:
|
|
95
|
+
print(__doc__)
|
|
96
|
+
return 2
|
|
97
|
+
contract_type = sys.argv[1]
|
|
98
|
+
artifact_path = sys.argv[2]
|
|
99
|
+
return run(contract_type, artifact_path)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
if __name__ == '__main__':
|
|
103
|
+
sys.exit(main())
|
|
@@ -1,238 +1,239 @@
|
|
|
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>/ 目录下
|
|
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
|
|
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 已配置。未配则提示 (绝不自动造假账号)。
|
|
77
|
-
|
|
78
|
-
旧逻辑会塞 name@local 假账号, 与零信任 push 门禁冲突, 已废弃。
|
|
79
|
-
真正的 git 配置由 setup.py configure_git_identity() 在 init 前完成。
|
|
80
|
-
这里只做兜底检测: 如果走到这还没配, 提示用户去配。
|
|
81
|
-
"""
|
|
82
|
-
import subprocess
|
|
83
|
-
# 先看 git 是否可用
|
|
84
|
-
try:
|
|
85
|
-
subprocess.run(["git", "--version"], capture_output=True, timeout=5)
|
|
86
|
-
except (FileNotFoundError, OSError):
|
|
87
|
-
print(" [INFO] git 未安装, 跳过 git 配置 (核心功能不依赖 git)")
|
|
88
|
-
return
|
|
89
|
-
|
|
90
|
-
author = _detect_git_author()
|
|
91
|
-
if author:
|
|
92
|
-
# 检测到疑似假账号也要提示 (虽然配了, 但 push 会被门禁拒)
|
|
93
|
-
if "@local" in author:
|
|
94
|
-
print(f" [WARN] git 作者疑似假账号: {author} (push 门禁会拒绝)")
|
|
95
|
-
print(f" 请重跑 'wlkj init' 配置真实团队 git 账号")
|
|
96
|
-
else:
|
|
97
|
-
print(f" [OK] git 作者: {author}")
|
|
98
|
-
return
|
|
99
|
-
|
|
100
|
-
# git 未配: 不造假, 只提示
|
|
101
|
-
print(f" [WARN] git 未配置 user.name/email")
|
|
102
|
-
print(f" push/commit 会失败。请配置团队 git 账号:")
|
|
103
|
-
print(f" git config --global user.name '你的名字'")
|
|
104
|
-
print(f" git config --global user.email '你的团队邮箱'")
|
|
105
|
-
print(f" 或重跑: wlkj init <你的名字>")
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
def init_developer(name: str, role: str | None = None,
|
|
109
|
-
repo_root: Path | None = None) -> bool:
|
|
110
|
-
"""初始化开发者身份。
|
|
111
|
-
|
|
112
|
-
创建以下内容:
|
|
113
|
-
- .qoder/.developer 文件 (name= / role= / initialized_at=)
|
|
114
|
-
- workspace/members/<name>/{journal,drafts,inbox}/ 目录
|
|
115
|
-
- 初始日志文件 journal/journal-1.md
|
|
116
|
-
- member.json + .signing_key (零信任身份注册, 用于 push 门禁)
|
|
117
|
-
- git user.name/email 检测与配置
|
|
118
|
-
|
|
119
|
-
Returns:
|
|
120
|
-
成功返回 True, 失败返回 False。
|
|
121
|
-
"""
|
|
122
|
-
if not name:
|
|
123
|
-
print("Error: developer name is required", file=sys.stderr)
|
|
124
|
-
return False
|
|
125
|
-
|
|
126
|
-
# 校验名称合法性 (允许字母数字、中文和部分符号)
|
|
127
|
-
if not all(c.isalnum() or c in "-_" for c in name):
|
|
128
|
-
print(f"Error: invalid developer name '{name}' (only alphanumeric, -, _ allowed)", file=sys.stderr)
|
|
129
|
-
return False
|
|
130
|
-
|
|
131
|
-
if repo_root is None:
|
|
132
|
-
repo_root = get_repo_root()
|
|
133
|
-
|
|
134
|
-
# 零信任: 切换身份时清除旧开发者的 current-task 指针
|
|
135
|
-
# (防止 B 在 A 用过的机器上看到 A 的活跃任务, 误操作)
|
|
136
|
-
try:
|
|
137
|
-
from .paths import get_developer, set_current_task
|
|
138
|
-
old_dev = get_developer(repo_root)
|
|
139
|
-
if old_dev and old_dev != name:
|
|
140
|
-
set_current_task(None, repo_root, developer=old_dev)
|
|
141
|
-
print(f"Note: 切换开发者 {old_dev} -> {name}, 已清除 {old_dev} 的活跃任务指针")
|
|
142
|
-
except Exception:
|
|
143
|
-
pass # 清理失败不阻塞初始化
|
|
144
|
-
|
|
145
|
-
# 1. 创建 .developer 文件
|
|
146
|
-
if not write_developer_file(name, role, repo_root):
|
|
147
|
-
return False
|
|
148
|
-
|
|
149
|
-
# 2. 创建个人工作空间 workspace/members/<name>/
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
#
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
#
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
print(f"
|
|
197
|
-
print(f"
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
#
|
|
203
|
-
#
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
print("
|
|
211
|
-
sys.
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
print("
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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>/ 目录下
|
|
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 foundation.core.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 已配置。未配则提示 (绝不自动造假账号)。
|
|
77
|
+
|
|
78
|
+
旧逻辑会塞 name@local 假账号, 与零信任 push 门禁冲突, 已废弃。
|
|
79
|
+
真正的 git 配置由 setup.py configure_git_identity() 在 init 前完成。
|
|
80
|
+
这里只做兜底检测: 如果走到这还没配, 提示用户去配。
|
|
81
|
+
"""
|
|
82
|
+
import subprocess
|
|
83
|
+
# 先看 git 是否可用
|
|
84
|
+
try:
|
|
85
|
+
subprocess.run(["git", "--version"], capture_output=True, timeout=5)
|
|
86
|
+
except (FileNotFoundError, OSError):
|
|
87
|
+
print(" [INFO] git 未安装, 跳过 git 配置 (核心功能不依赖 git)")
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
author = _detect_git_author()
|
|
91
|
+
if author:
|
|
92
|
+
# 检测到疑似假账号也要提示 (虽然配了, 但 push 会被门禁拒)
|
|
93
|
+
if "@local" in author:
|
|
94
|
+
print(f" [WARN] git 作者疑似假账号: {author} (push 门禁会拒绝)")
|
|
95
|
+
print(f" 请重跑 'wlkj init' 配置真实团队 git 账号")
|
|
96
|
+
else:
|
|
97
|
+
print(f" [OK] git 作者: {author}")
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
# git 未配: 不造假, 只提示
|
|
101
|
+
print(f" [WARN] git 未配置 user.name/email")
|
|
102
|
+
print(f" push/commit 会失败。请配置团队 git 账号:")
|
|
103
|
+
print(f" git config --global user.name '你的名字'")
|
|
104
|
+
print(f" git config --global user.email '你的团队邮箱'")
|
|
105
|
+
print(f" 或重跑: wlkj init <你的名字>")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def init_developer(name: str, role: str | None = None,
|
|
109
|
+
repo_root: Path | None = None) -> bool:
|
|
110
|
+
"""初始化开发者身份。
|
|
111
|
+
|
|
112
|
+
创建以下内容:
|
|
113
|
+
- .qoder/.developer 文件 (name= / role= / initialized_at=)
|
|
114
|
+
- workspace/members/<name>/{journal,drafts,inbox}/ 目录
|
|
115
|
+
- 初始日志文件 journal/journal-1.md
|
|
116
|
+
- member.json + .signing_key (零信任身份注册, 用于 push 门禁)
|
|
117
|
+
- git user.name/email 检测与配置
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
成功返回 True, 失败返回 False。
|
|
121
|
+
"""
|
|
122
|
+
if not name:
|
|
123
|
+
print("Error: developer name is required", file=sys.stderr)
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
# 校验名称合法性 (允许字母数字、中文和部分符号)
|
|
127
|
+
if not all(c.isalnum() or c in "-_" for c in name):
|
|
128
|
+
print(f"Error: invalid developer name '{name}' (only alphanumeric, -, _ allowed)", file=sys.stderr)
|
|
129
|
+
return False
|
|
130
|
+
|
|
131
|
+
if repo_root is None:
|
|
132
|
+
repo_root = get_repo_root()
|
|
133
|
+
|
|
134
|
+
# 零信任: 切换身份时清除旧开发者的 current-task 指针
|
|
135
|
+
# (防止 B 在 A 用过的机器上看到 A 的活跃任务, 误操作)
|
|
136
|
+
try:
|
|
137
|
+
from foundation.core.paths import get_developer, set_current_task
|
|
138
|
+
old_dev = get_developer(repo_root)
|
|
139
|
+
if old_dev and old_dev != name:
|
|
140
|
+
set_current_task(None, repo_root, developer=old_dev)
|
|
141
|
+
print(f"Note: 切换开发者 {old_dev} -> {name}, 已清除 {old_dev} 的活跃任务指针")
|
|
142
|
+
except Exception:
|
|
143
|
+
pass # 清理失败不阻塞初始化
|
|
144
|
+
|
|
145
|
+
# 1. 创建 .developer 文件
|
|
146
|
+
if not write_developer_file(name, role, repo_root):
|
|
147
|
+
return False
|
|
148
|
+
|
|
149
|
+
# 2. 创建个人工作空间 workspace/members/<name>/
|
|
150
|
+
# v3.0 M3: 个人目录 = member.json + drafts + outputs + journal + .private
|
|
151
|
+
personal = repo_root / "workspace" / "members" / name
|
|
152
|
+
try:
|
|
153
|
+
for sub in ("journal", "drafts", "outputs", ".private", ".private/secrets"):
|
|
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 foundation.identity.identity import register_member, IdentityError, get_member
|
|
177
|
+
# 修正: 旧 member.json 若是假账号(@local), 且现在 git 配了真账号 → 用真账号覆盖
|
|
178
|
+
# register_member 已有"已注册则只更新 git_author, 密钥不动"的逻辑, 这里只加提示
|
|
179
|
+
existing_member = get_member(name, repo_root)
|
|
180
|
+
if existing_member:
|
|
181
|
+
old_author = existing_member.get("git_author", "")
|
|
182
|
+
if (old_author and "@local" in old_author
|
|
183
|
+
and git_author and "@local" not in git_author):
|
|
184
|
+
print(f" [修正] member.json git_author 从假账号更新为真账号: {git_author}")
|
|
185
|
+
try:
|
|
186
|
+
register_member(name, role or "pm", git_author, repo_root)
|
|
187
|
+
print(f" [OK] 身份注册: member.json + 签名密钥已生成")
|
|
188
|
+
except IdentityError as e:
|
|
189
|
+
print(f" [WARN] 身份注册失败 (不阻塞): {e}")
|
|
190
|
+
except ImportError:
|
|
191
|
+
pass # identity 模块不可用, 跳过 (向后兼容)
|
|
192
|
+
|
|
193
|
+
# 5. 确保 git 配置 (只检测+提示, 不造假; 真账号由 setup.py 在 init 前配好)
|
|
194
|
+
_ensure_git_config(name, repo_root)
|
|
195
|
+
|
|
196
|
+
print(f"Developer initialized: {name}" + (f" ({role})" if role else ""))
|
|
197
|
+
print(f" Workspace: workspace/members/{name}/")
|
|
198
|
+
print(f" Journal: workspace/members/{name}/journal/journal-1.md")
|
|
199
|
+
return True
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
# =============================================================================
|
|
203
|
+
# 开发者校验
|
|
204
|
+
# =============================================================================
|
|
205
|
+
|
|
206
|
+
def ensure_developer(repo_root: Path | None = None) -> str:
|
|
207
|
+
"""确保开发者已初始化, 未初始化则打印提示并退出。"""
|
|
208
|
+
developer = get_developer(repo_root)
|
|
209
|
+
if not developer:
|
|
210
|
+
print("Error: Developer not initialized.", file=sys.stderr)
|
|
211
|
+
print("Run: npx @hupan56/wlkj init <your-name>", file=sys.stderr)
|
|
212
|
+
sys.exit(1)
|
|
213
|
+
return developer
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def show_developer_info(repo_root: Path | None = None) -> None:
|
|
217
|
+
"""显示当前开发者信息。"""
|
|
218
|
+
from foundation.core.paths import get_developer_info, get_workspace_dir, get_active_journal_file
|
|
219
|
+
|
|
220
|
+
info = get_developer_info(repo_root)
|
|
221
|
+
if not info:
|
|
222
|
+
print("Developer: not initialized")
|
|
223
|
+
print("Run: npx @hupan56/wlkj init <your-name>")
|
|
224
|
+
return
|
|
225
|
+
|
|
226
|
+
print(f"Developer: {info.get('name', 'unknown')}")
|
|
227
|
+
if info.get('role'):
|
|
228
|
+
print(f"Role: {info['role']}")
|
|
229
|
+
print(f"Initialized: {info.get('initialized_at', 'unknown')}")
|
|
230
|
+
|
|
231
|
+
workspace = get_workspace_dir(repo_root)
|
|
232
|
+
if workspace:
|
|
233
|
+
print(f"Workspace: {workspace}")
|
|
234
|
+
|
|
235
|
+
journal = get_active_journal_file(repo_root)
|
|
236
|
+
if journal:
|
|
237
|
+
from foundation.core.paths import count_lines
|
|
238
|
+
lines = count_lines(journal)
|
|
239
|
+
print(f"Active Journal: {journal.name} ({lines} lines)")
|