@hupan56/wlkj 2.0.0 → 2.0.1
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
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hupan56/wlkj",
|
|
3
|
-
"version": "2.0.
|
|
4
|
-
"description": "AI
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"description": "AI Product R&D Workflow - PRD/Prototype/Search/Task/Report",
|
|
5
5
|
"bin": { "wlkj": "./bin/cli.js" },
|
|
6
6
|
"files": ["bin/", "templates/"],
|
|
7
7
|
"keywords": ["workflow", "ai", "prd", "pipeline", "qoder", "product", "team"],
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"publishConfig": { "access": "public" },
|
|
10
10
|
"engines": { "node": ">=16" }
|
|
11
|
-
}
|
|
11
|
+
}
|
|
@@ -21,6 +21,7 @@ Usage:
|
|
|
21
21
|
import os
|
|
22
22
|
import sys
|
|
23
23
|
import json
|
|
24
|
+
import time
|
|
24
25
|
|
|
25
26
|
# UTF-8 stdio (防御性: stdout 被捕获时不崩溃)
|
|
26
27
|
try:
|
|
@@ -71,6 +72,53 @@ def plat_filter(files, target):
|
|
|
71
72
|
return [f for f in files if target.lower() in f.lower()]
|
|
72
73
|
|
|
73
74
|
|
|
75
|
+
def _cache_key(query, platform, page_type):
|
|
76
|
+
"""生成缓存 key: query|platform|type|索引mtime 指纹。
|
|
77
|
+
|
|
78
|
+
索引文件没变就命中缓存, 变了自动失效。
|
|
79
|
+
"""
|
|
80
|
+
import hashlib
|
|
81
|
+
# 取 3 个主要索引的 mtime 作为指纹
|
|
82
|
+
mtime_str = ''
|
|
83
|
+
for idx_file in ['keyword-index.json', 'api-index.json', 'prd-index.json']:
|
|
84
|
+
p = os.path.join(INDEX_DIR, idx_file)
|
|
85
|
+
if os.path.isfile(p):
|
|
86
|
+
mtime_str += '%d_' % os.path.getmtime(p)
|
|
87
|
+
raw = '{}|{}|{}|{}'.format(query, platform or '', page_type or '', mtime_str)
|
|
88
|
+
return hashlib.md5(raw.encode('utf-8')).hexdigest()[:16]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _try_cache(key):
|
|
92
|
+
"""读缓存命中则返回内容, 未命中返回 None。"""
|
|
93
|
+
cache_path = os.path.join(BASE, '.qoder', '.runtime', 'ctx-cache-%s.md' % key)
|
|
94
|
+
if not os.path.isfile(cache_path):
|
|
95
|
+
return None
|
|
96
|
+
try:
|
|
97
|
+
# 缓存 24 小时有效 (防 mtime 精度问题)
|
|
98
|
+
age = time.time() - os.path.getmtime(cache_path)
|
|
99
|
+
if age > 86400:
|
|
100
|
+
return None
|
|
101
|
+
with open(cache_path, encoding='utf-8') as f:
|
|
102
|
+
return f.read()
|
|
103
|
+
except OSError:
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _save_cache(key, content):
|
|
108
|
+
"""写缓存 (best-effort, 失败不阻塞)。"""
|
|
109
|
+
try:
|
|
110
|
+
cache_dir = os.path.join(BASE, '.qoder', '.runtime')
|
|
111
|
+
os.makedirs(cache_dir, exist_ok=True)
|
|
112
|
+
cache_path = os.path.join(cache_dir, 'ctx-cache-%s.md' % key)
|
|
113
|
+
# 原子写
|
|
114
|
+
tmp = cache_path + '.tmp'
|
|
115
|
+
with open(tmp, 'w', encoding='utf-8') as f:
|
|
116
|
+
f.write(content)
|
|
117
|
+
os.replace(tmp, cache_path)
|
|
118
|
+
except OSError:
|
|
119
|
+
pass
|
|
120
|
+
|
|
121
|
+
|
|
74
122
|
def main():
|
|
75
123
|
args = sys.argv[1:]
|
|
76
124
|
platform = None
|
|
@@ -88,6 +136,30 @@ def main():
|
|
|
88
136
|
return 1
|
|
89
137
|
query = args[0]
|
|
90
138
|
|
|
139
|
+
# 结果缓存: 同 query+platform+索引未变 → 直接返回 (470ms → <10ms)
|
|
140
|
+
cache_key = _cache_key(query, platform, page_type)
|
|
141
|
+
cached = _try_cache(cache_key)
|
|
142
|
+
if cached is not None:
|
|
143
|
+
print(cached, end='')
|
|
144
|
+
return 0
|
|
145
|
+
|
|
146
|
+
# 缓存未命中, 正常计算, 末尾写入缓存
|
|
147
|
+
import io
|
|
148
|
+
old_stdout = sys.stdout
|
|
149
|
+
sys.stdout = buf = io.StringIO()
|
|
150
|
+
try:
|
|
151
|
+
_compute_and_print(query, platform, page_type)
|
|
152
|
+
finally:
|
|
153
|
+
sys.stdout = old_stdout
|
|
154
|
+
output = buf.getvalue()
|
|
155
|
+
print(output, end='')
|
|
156
|
+
_save_cache(cache_key, output)
|
|
157
|
+
return 0
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _compute_and_print(query, platform, page_type):
|
|
161
|
+
"""实际的 context_pack 计算 (原 main 逻辑)。"""
|
|
162
|
+
|
|
91
163
|
targets = []
|
|
92
164
|
if platform and platform.lower() not in ('both', '两端'):
|
|
93
165
|
targets = [PLATFORM_MAP.get(platform.lower(), platform)]
|
|
@@ -189,8 +261,6 @@ def main():
|
|
|
189
261
|
for w in wikis:
|
|
190
262
|
print('- ' + w)
|
|
191
263
|
|
|
192
|
-
return 0
|
|
193
|
-
|
|
194
264
|
|
|
195
265
|
if __name__ == '__main__':
|
|
196
266
|
sys.exit(main())
|