@hupan56/wlkj 3.1.6 → 3.1.7
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/package.json +28 -28
- package/templates/qoder/commands/wl-req.md +1 -0
- package/templates/qoder/scripts/domain/design/gen_design_doc.py +18 -6
- package/templates/qoder/scripts/domain/kg/build/learn_aggregate.py +13 -14
- package/templates/qoder/scripts/domain/kg/search/search_index.py +36 -0
- package/templates/qoder/scripts/domain/task/zentao_sync.py +3 -3
package/package.json
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@hupan56/wlkj",
|
|
3
|
-
"version": "3.1.
|
|
4
|
-
"description": "AI Product R&D Workflow - PRD/Prototype/Search/Task/Report",
|
|
5
|
-
"bin": {
|
|
6
|
-
"wlkj": "bin/cli.js"
|
|
7
|
-
},
|
|
8
|
-
"files": [
|
|
9
|
-
"bin/",
|
|
10
|
-
"templates/",
|
|
11
|
-
"MAC-VERIFY.md"
|
|
12
|
-
],
|
|
13
|
-
"keywords": [
|
|
14
|
-
"workflow",
|
|
15
|
-
"ai",
|
|
16
|
-
"prd",
|
|
17
|
-
"pipeline",
|
|
18
|
-
"qoder",
|
|
19
|
-
"product",
|
|
20
|
-
"team"
|
|
21
|
-
],
|
|
22
|
-
"license": "MIT",
|
|
23
|
-
"publishConfig": {
|
|
24
|
-
"access": "public"
|
|
25
|
-
},
|
|
26
|
-
"engines": {
|
|
27
|
-
"node": ">=16"
|
|
28
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@hupan56/wlkj",
|
|
3
|
+
"version": "3.1.7",
|
|
4
|
+
"description": "AI Product R&D Workflow - PRD/Prototype/Search/Task/Report",
|
|
5
|
+
"bin": {
|
|
6
|
+
"wlkj": "bin/cli.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/",
|
|
10
|
+
"templates/",
|
|
11
|
+
"MAC-VERIFY.md"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"workflow",
|
|
15
|
+
"ai",
|
|
16
|
+
"prd",
|
|
17
|
+
"pipeline",
|
|
18
|
+
"qoder",
|
|
19
|
+
"product",
|
|
20
|
+
"team"
|
|
21
|
+
],
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=16"
|
|
28
|
+
}
|
|
29
29
|
}
|
|
@@ -10,7 +10,7 @@ for _ in range(10):
|
|
|
10
10
|
break
|
|
11
11
|
if _cp not in _s.path: _s.path.insert(0, _cp)
|
|
12
12
|
from bootstrap import setup; setup()
|
|
13
|
-
from foundation.core.paths import get_repo_root
|
|
13
|
+
from foundation.core.paths import get_repo_root
|
|
14
14
|
|
|
15
15
|
"""
|
|
16
16
|
gen_design_doc.py - 自动生成 DESIGN.md (给 AI 的设计系统说明书)
|
|
@@ -43,7 +43,7 @@ except (AttributeError, TypeError, OSError, IOError):
|
|
|
43
43
|
except Exception:
|
|
44
44
|
pass
|
|
45
45
|
|
|
46
|
-
BASE = get_repo_root()
|
|
46
|
+
BASE = get_repo_root()
|
|
47
47
|
INDEX_DIR = os.path.join(BASE, 'data', 'index')
|
|
48
48
|
OUTPUT_DIR = os.path.join(BASE, 'data', 'design')
|
|
49
49
|
|
|
@@ -269,8 +269,14 @@ def gen_design_doc():
|
|
|
269
269
|
lines.append(f'- `{field_name}` -> {title} (used {count}x)')
|
|
270
270
|
lines.append('')
|
|
271
271
|
|
|
272
|
-
# ========== 4.5 Feature Modules (from prd-features.json) ==========
|
|
273
|
-
|
|
272
|
+
# ========== 4.5 Feature Modules (from prd-features.json, DuckDB-backed) ==========
|
|
273
|
+
# prd-features.json 文件不存在, 真实数据在 DuckDB entities(FEATURE 行)。
|
|
274
|
+
# 用 search_index.load_index 走 DuckDB (load_json 只读文件, 永远返回 {})。
|
|
275
|
+
try:
|
|
276
|
+
from domain.kg.search.search_index import load_index as _load_idx
|
|
277
|
+
pf = _load_idx('prd-features.json') or {}
|
|
278
|
+
except Exception:
|
|
279
|
+
pf = load_json('prd-features.json')
|
|
274
280
|
features = pf.get('features', {}) if isinstance(pf, dict) else {}
|
|
275
281
|
if features:
|
|
276
282
|
lines.append('## 4.5 Feature Modules (系统有哪些功能模块)')
|
|
@@ -288,8 +294,14 @@ def gen_design_doc():
|
|
|
288
294
|
lines.append(f' - 标杆页面: {sample_pages}')
|
|
289
295
|
lines.append('')
|
|
290
296
|
|
|
291
|
-
# ========== 4.6 Real Buttons (from entity-registry.json) ==========
|
|
292
|
-
|
|
297
|
+
# ========== 4.6 Real Buttons (from entity-registry.json, DuckDB-backed) ==========
|
|
298
|
+
# entity-registry.json 文件不存在, 真实数据在 DuckDB entities(BUTTON 行, 2675 个)。
|
|
299
|
+
# 用 search_index.load_index 走 DuckDB (load_json 只读文件, 永远返回 {} → 按钮段永远空)。
|
|
300
|
+
try:
|
|
301
|
+
from domain.kg.search.search_index import load_index as _load_idx
|
|
302
|
+
er = _load_idx('entity-registry.json') or {}
|
|
303
|
+
except Exception:
|
|
304
|
+
er = load_json('entity-registry.json')
|
|
293
305
|
entities = er.get('entities', {}) if isinstance(er, dict) else {}
|
|
294
306
|
button_samples = []
|
|
295
307
|
for eid, info in list(entities.items())[:500]:
|
|
@@ -1,17 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
"""learn_aggregate.py - 团队学习聚合 (同构 kg_build.py)
|
|
3
3
|
|
|
4
|
-
# v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
|
|
5
|
-
import os as _o, sys as _s
|
|
6
|
-
_f = _o.path.abspath(__file__)
|
|
7
|
-
for _ in range(10):
|
|
8
|
-
_f = _o.path.dirname(_f)
|
|
9
|
-
_cp = _o.path.join(_f, 'foundation')
|
|
10
|
-
if _o.path.isfile(_o.path.join(_cp, 'bootstrap.py')):
|
|
11
|
-
break
|
|
12
|
-
if _cp not in _s.path: _s.path.insert(0, _cp)
|
|
13
|
-
from bootstrap import setup; setup()
|
|
14
|
-
|
|
15
4
|
扫所有人的 workspace/members/{dev}/journal/feedback.jsonl
|
|
16
5
|
→ 增量写入 kg.duckdb 的 learning_events 表 (团队单一真源)
|
|
17
6
|
|
|
@@ -26,6 +15,19 @@ from bootstrap import setup; setup()
|
|
|
26
15
|
python learn_aggregate.py # 增量
|
|
27
16
|
python learn_aggregate.py --rebuild # 全量重建
|
|
28
17
|
"""
|
|
18
|
+
# v3.0 路径自举: 引导到 foundation/bootstrap, 统一 sys.path 逻辑
|
|
19
|
+
# ⚠ 必须在 module docstring 之外! 旧版把这块包进 docstring → bootstrap 永不执行
|
|
20
|
+
# → from foundation... ModuleNotFoundError → 学习聚合全链路死。
|
|
21
|
+
import os as _o, sys as _s
|
|
22
|
+
_f = _o.path.abspath(__file__)
|
|
23
|
+
for _ in range(10):
|
|
24
|
+
_f = _o.path.dirname(_f)
|
|
25
|
+
_cp = _o.path.join(_f, 'foundation')
|
|
26
|
+
if _o.path.isfile(_o.path.join(_cp, 'bootstrap.py')):
|
|
27
|
+
break
|
|
28
|
+
if _cp not in _s.path: _s.path.insert(0, _cp)
|
|
29
|
+
from bootstrap import setup; setup()
|
|
30
|
+
|
|
29
31
|
import os
|
|
30
32
|
import sys
|
|
31
33
|
import json
|
|
@@ -33,9 +35,6 @@ import hashlib
|
|
|
33
35
|
import time
|
|
34
36
|
from datetime import datetime
|
|
35
37
|
|
|
36
|
-
SCRIPTS = os.path.dirname(os.path.abspath(__file__))
|
|
37
|
-
sys.path.insert(0, SCRIPTS)
|
|
38
|
-
|
|
39
38
|
from foundation.core.paths import MEMBERS_DIR
|
|
40
39
|
from domain.kg.storage.kg_duckdb import get_db, init_schema # v3.0: kg_duckdb 已迁入 kg/ 子包
|
|
41
40
|
|
|
@@ -258,6 +258,42 @@ def _duckdb_load(filename):
|
|
|
258
258
|
result[proj] = {'files': vf or 0, 'classes': 0, 'apis': 0}
|
|
259
259
|
return result if result else None
|
|
260
260
|
|
|
261
|
+
elif filename == 'entity-registry.json':
|
|
262
|
+
# 实体注册表 (fill_prototype 取真实按钮文案 / gen_design_doc 取按钮样本)。
|
|
263
|
+
# 真实数据在 DuckDB entities 表 (6131 行: BUTTON/ENDPOINT/FEATURE/...),
|
|
264
|
+
# 不再有 entity-registry.json 文件 (kg.py 注释: 通常不存在)。
|
|
265
|
+
# 重建为 {'entities': {id: {'type':..., 'canonical':..., 'cn':..., 'properties': props}}}
|
|
266
|
+
# 消费方 extract_real_buttons 读 entities[eid]['properties']['button_text']。
|
|
267
|
+
def _entity_loader(con):
|
|
268
|
+
rows = con.execute("SELECT id, type, canonical, cn, props FROM entities").fetchall()
|
|
269
|
+
result = {'entities': {}}
|
|
270
|
+
for eid, etype, canon, cn, props in rows:
|
|
271
|
+
try:
|
|
272
|
+
props_d = json.loads(props) if props else {}
|
|
273
|
+
except Exception:
|
|
274
|
+
props_d = {}
|
|
275
|
+
result['entities'][eid] = {
|
|
276
|
+
'type': etype, 'canonical': canon, 'cn': cn or '',
|
|
277
|
+
'properties': props_d,
|
|
278
|
+
}
|
|
279
|
+
return result if result['entities'] else None
|
|
280
|
+
return _load_with_pickle_cache(con, 'entity-registry', _entity_loader)
|
|
281
|
+
|
|
282
|
+
elif filename == 'prd-features.json':
|
|
283
|
+
# 从 entities 表 FEATURE 行重建 (prd-features.json 文件不存在)。
|
|
284
|
+
# gen_design_doc 取 feature 模块样本。结构: {'features': {canonical: {'cn':..., 'properties':...}}}
|
|
285
|
+
def _feature_loader(con):
|
|
286
|
+
rows = con.execute("SELECT id, canonical, cn, props FROM entities WHERE type='FEATURE'").fetchall()
|
|
287
|
+
result = {'features': {}}
|
|
288
|
+
for eid, canon, cn, props in rows:
|
|
289
|
+
try:
|
|
290
|
+
props_d = json.loads(props) if props else {}
|
|
291
|
+
except Exception:
|
|
292
|
+
props_d = {}
|
|
293
|
+
result['features'][canon or eid] = {'cn': cn or '', 'id': eid, 'properties': props_d}
|
|
294
|
+
return result if result['features'] else None
|
|
295
|
+
return _load_with_pickle_cache(con, 'prd-features', _feature_loader)
|
|
296
|
+
|
|
261
297
|
except Exception:
|
|
262
298
|
return None
|
|
263
299
|
return None
|
|
@@ -24,10 +24,10 @@ import os
|
|
|
24
24
|
import sys
|
|
25
25
|
|
|
26
26
|
# ── 路径自举: 让脚本能独立运行 (复用 bootstrap 模式) ──
|
|
27
|
-
#
|
|
28
|
-
#
|
|
27
|
+
# 本脚本在 scripts/domain/task/ 下 (scripts 下 2 级), dirname 两次才到 scripts/。
|
|
28
|
+
# 旧版只 dirname 一次 → _SCRIPTS=scripts/domain/ → 找不到 foundation → 整个 zentao CLI 同步死。
|
|
29
29
|
_HERE = os.path.dirname(os.path.abspath(__file__))
|
|
30
|
-
_SCRIPTS = os.path.dirname(_HERE)
|
|
30
|
+
_SCRIPTS = os.path.dirname(os.path.dirname(_HERE)) # .qoder/scripts (上两级)
|
|
31
31
|
_COMMON = os.path.join(_SCRIPTS, 'foundation')
|
|
32
32
|
for _p in (_SCRIPTS, _COMMON):
|
|
33
33
|
if _p not in sys.path:
|