@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
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
|
+
# v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
|
|
4
|
+
import os as _o, sys as _s
|
|
5
|
+
_cp = _o.path.join(_o.path.dirname(_o.path.dirname(_o.path.abspath(__file__))), 'common')
|
|
6
|
+
if _cp not in _s.path: _s.path.insert(0, _cp)
|
|
7
|
+
from bootstrap import setup; setup()
|
|
8
|
+
|
|
3
9
|
"""
|
|
4
10
|
QODER Team Sync - 无感 git 同步引擎
|
|
5
11
|
|
|
@@ -49,16 +55,31 @@ PUSH_LOCK = os.path.join(BASE, '.qoder', '.runtime', 'team-sync.lock')
|
|
|
49
55
|
MAX_PUSH_RETRY = 3
|
|
50
56
|
|
|
51
57
|
|
|
52
|
-
def git(*args, check=False):
|
|
53
|
-
"""git 命令包装。git 未安装时返回 rc=127 的伪结果, 不崩溃。
|
|
58
|
+
def git(*args, check=False, timeout=None):
|
|
59
|
+
"""git 命令包装。git 未安装时返回 rc=127 的伪结果, 不崩溃。
|
|
60
|
+
|
|
61
|
+
timeout: 网络/远程操作 (fetch/pull/push/clone) 必须传, 防止认证提示或网络
|
|
62
|
+
挂起导致整个 sync 无限阻塞。本地操作 (add/commit/status/diff) 不需要。
|
|
63
|
+
用法: git('fetch', 'origin', timeout=60)
|
|
64
|
+
"""
|
|
54
65
|
try:
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
kw = dict(cwd=BASE, capture_output=True, text=True, encoding='utf-8', errors='replace')
|
|
67
|
+
if timeout:
|
|
68
|
+
kw['timeout'] = timeout
|
|
69
|
+
r = subprocess.run(['git'] + list(args), **kw)
|
|
57
70
|
except FileNotFoundError:
|
|
58
71
|
# git 未安装 — 返回伪 CompletedProcess, 让上层把"无 git"当"无远端/无仓库"处理
|
|
59
72
|
import types
|
|
60
73
|
r = types.SimpleNamespace(returncode=127, stdout='', stderr='git not installed',
|
|
61
74
|
encoding='utf-8')
|
|
75
|
+
except subprocess.TimeoutExpired:
|
|
76
|
+
# 网络操作超时 (常见: 远程要认证但凭证没缓存 / 网络不通)
|
|
77
|
+
# 返回 rc=124 (与 timeout 命令一致), 不让整个 sync 挂死
|
|
78
|
+
import types
|
|
79
|
+
cmd_hint = ' '.join(args[:3])
|
|
80
|
+
r = types.SimpleNamespace(returncode=124, stdout='',
|
|
81
|
+
stderr='git {} timed out after {}s (网络/认证问题)'.format(cmd_hint, timeout),
|
|
82
|
+
encoding='utf-8')
|
|
62
83
|
if check and r.returncode != 0:
|
|
63
84
|
print('git {} failed: {}'.format(' '.join(args), r.stderr.strip()[:300]))
|
|
64
85
|
return r
|
|
@@ -204,7 +225,8 @@ def _auto_resolve_kg_conflict():
|
|
|
204
225
|
|
|
205
226
|
|
|
206
227
|
def do_pull(quiet=False):
|
|
207
|
-
"""拉取团队最新。安全: autostash
|
|
228
|
+
"""拉取团队最新。安全: autostash 保护未提交改动 + 文件锁防与 push 竞态。"""
|
|
229
|
+
# 前置检查(不需锁): 远程/rebase 状态快速失败, 避免占锁后才发现问题
|
|
208
230
|
if rebase_in_progress():
|
|
209
231
|
print('SYNC_CONFLICT: 仓库处于未完成的 rebase 状态, AI 请先处理 (git rebase --abort 或 --continue)。')
|
|
210
232
|
return 3
|
|
@@ -219,8 +241,31 @@ def do_pull(quiet=False):
|
|
|
219
241
|
print('ERROR: detached HEAD or no branch - AI please check.')
|
|
220
242
|
return 1
|
|
221
243
|
|
|
222
|
-
|
|
244
|
+
# === 文件锁: 与 do_push 互斥。pull --rebase --autostash 会动工作区 + index,
|
|
245
|
+
# 若与锁内的 _stage_scopes_safely (git add) 交叉会产生半 staged 状态。 ===
|
|
246
|
+
os.makedirs(os.path.dirname(PUSH_LOCK), exist_ok=True)
|
|
247
|
+
try:
|
|
248
|
+
lock_ctx = FileLock(PUSH_LOCK, timeout=60, stale_seconds=300)
|
|
249
|
+
lock_ctx.acquire()
|
|
250
|
+
except LockTimeoutError as e:
|
|
251
|
+
print('SYNC_BUSY: 另一个同步正在进行, 等待超时。稍后重试。')
|
|
252
|
+
print(' ' + str(e))
|
|
253
|
+
return 2 # lock contention
|
|
254
|
+
|
|
255
|
+
try:
|
|
256
|
+
return _do_pull_locked(quiet, branch)
|
|
257
|
+
finally:
|
|
258
|
+
lock_ctx.release()
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _do_pull_locked(quiet, branch):
|
|
262
|
+
"""锁内的实际 pull 逻辑。"""
|
|
263
|
+
r = git('pull', '--rebase', '--autostash', 'origin', branch, timeout=90)
|
|
223
264
|
if r.returncode != 0:
|
|
265
|
+
if r.returncode == 124:
|
|
266
|
+
print('Pull 超时 (网络/认证问题): ' + (r.stderr or '').strip()[:150])
|
|
267
|
+
print('检查 git 凭证或团队仓库连通性。继续离线工作, 下次同步自动补推。')
|
|
268
|
+
return 1
|
|
224
269
|
if 'CONFLICT' in (r.stdout + r.stderr) or rebase_in_progress():
|
|
225
270
|
return report_conflict(r.stderr or r.stdout)
|
|
226
271
|
print('Pull failed (network/remote?): ' + (r.stderr or r.stdout).strip()[:200])
|
|
@@ -282,22 +327,25 @@ def _stage_scopes_safely(skip_secret=False):
|
|
|
282
327
|
只 stage SYNC_SCOPES 下、扩展名在 SAFE_EXTENSIONS 里的文件。
|
|
283
328
|
其他文件 (如误放的 .env/.zip/.docx) 被跳过并打印警告。
|
|
284
329
|
|
|
330
|
+
性能: 收集后批量 git add (每批 ~400 个), 避免 N 个文件 = N 次 git 进程 fork。
|
|
331
|
+
50 人团队大改动 (数百文件) 时, 逐文件 add 在 Windows CreateProcess 开销下
|
|
332
|
+
会很慢。批量后 push 阶段从 O(N 次 fork) 降到 O(N/400 次 fork)。
|
|
333
|
+
|
|
285
334
|
Returns:
|
|
286
335
|
(staged_count, skipped_files)
|
|
287
336
|
"""
|
|
288
|
-
|
|
337
|
+
to_add = [] # 待批量 add 的文件 (已收集, 一次性分批 add)
|
|
289
338
|
skipped = []
|
|
290
339
|
for scope in SYNC_SCOPES:
|
|
291
340
|
scope_path = os.path.join(BASE, scope)
|
|
292
341
|
if not os.path.isdir(scope_path):
|
|
293
342
|
continue
|
|
294
343
|
# 用 git ls-files 拿已跟踪的 + git status 拿未跟踪的, 逐个判断扩展名
|
|
295
|
-
# 已跟踪文件:
|
|
344
|
+
# 已跟踪文件: 收集 (它们已经在版本控制, 不可能是新秘密)
|
|
296
345
|
r = git('ls-files', '--', scope)
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
staged += 1
|
|
346
|
+
for f in r.stdout.strip().splitlines():
|
|
347
|
+
if f.strip():
|
|
348
|
+
to_add.append(f)
|
|
301
349
|
# 未跟踪的新文件: 按扩展名过滤
|
|
302
350
|
r = git('status', '--porcelain', '--', scope)
|
|
303
351
|
for line in r.stdout.strip().splitlines():
|
|
@@ -313,17 +361,24 @@ def _stage_scopes_safely(skip_secret=False):
|
|
|
313
361
|
if 'brainstorm-agent' in basename:
|
|
314
362
|
skipped.append(fpath + ' (brainstorm 中间文件, 不提交)')
|
|
315
363
|
elif ext in SAFE_EXTENSIONS:
|
|
316
|
-
|
|
317
|
-
staged += 1
|
|
364
|
+
to_add.append(fpath)
|
|
318
365
|
else:
|
|
319
366
|
skipped.append(fpath)
|
|
320
367
|
elif 'D' not in status:
|
|
321
|
-
# 修改/重命名等 (非删除) —— 已跟踪,
|
|
368
|
+
# 修改/重命名等 (非删除) —— 已跟踪, 收集
|
|
322
369
|
# 重命名格式 "R old -> new", 取 new
|
|
323
370
|
if '->' in fpath:
|
|
324
371
|
fpath = fpath.split('->')[-1].strip().strip('"')
|
|
325
|
-
|
|
326
|
-
|
|
372
|
+
to_add.append(fpath)
|
|
373
|
+
|
|
374
|
+
# 批量 add: 每批最多 400 个文件 (防命令行长度溢出, Windows ~8191 字符限制留余量)
|
|
375
|
+
BATCH = 400
|
|
376
|
+
staged = 0
|
|
377
|
+
for i in range(0, len(to_add), BATCH):
|
|
378
|
+
batch = to_add[i:i + BATCH]
|
|
379
|
+
git('add', '--', *batch)
|
|
380
|
+
staged += len(batch)
|
|
381
|
+
|
|
327
382
|
if skipped:
|
|
328
383
|
print('[gate] 跳过 {} 个非白名单文件 (可能含二进制/秘密, 手动处理):'.format(len(skipped)))
|
|
329
384
|
for s in skipped[:10]:
|
|
@@ -410,7 +465,7 @@ def _do_push_locked(message, dev, skip_eval, skip_secret):
|
|
|
410
465
|
return 1
|
|
411
466
|
|
|
412
467
|
# 5. 检查是否有待推送的提交
|
|
413
|
-
git('fetch', 'origin', branch)
|
|
468
|
+
git('fetch', 'origin', branch, timeout=60)
|
|
414
469
|
r = git('rev-list', '--count', 'origin/{}..HEAD'.format(branch))
|
|
415
470
|
ahead = int(r.stdout.strip() or 0) if r.returncode == 0 else 1
|
|
416
471
|
if ahead == 0:
|
|
@@ -420,7 +475,7 @@ def _do_push_locked(message, dev, skip_eval, skip_secret):
|
|
|
420
475
|
|
|
421
476
|
# 6. pull --rebase + push, 失败重试
|
|
422
477
|
for attempt in range(1, MAX_PUSH_RETRY + 1):
|
|
423
|
-
r = git('pull', '--rebase', '--autostash', 'origin', branch)
|
|
478
|
+
r = git('pull', '--rebase', '--autostash', 'origin', branch, timeout=90)
|
|
424
479
|
if r.returncode != 0:
|
|
425
480
|
# kg.duckdb 二进制冲突: 自动解决 (用户无感)
|
|
426
481
|
_auto_resolve_kg_conflict()
|
|
@@ -437,11 +492,22 @@ def _do_push_locked(message, dev, skip_eval, skip_secret):
|
|
|
437
492
|
return report_conflict(r.stderr or r.stdout)
|
|
438
493
|
# 非冲突的 pull 失败
|
|
439
494
|
print('Pull failed (attempt {}): {}'.format(attempt, (r.stderr or r.stdout).strip()[:150]))
|
|
495
|
+
if r.returncode == 124:
|
|
496
|
+
print(' (网络/认证超时 — 检查 git 凭证或团队仓库连通性)')
|
|
497
|
+
break # 网络挂起重试无意义, 直接退出
|
|
498
|
+
# 连接性失败 (unable to connect / Could not resolve) 重试也是浪费时间,
|
|
499
|
+
# 直接退出让用户离线工作, 别让 50 人团队的弱网用户干等 3 倍时间
|
|
500
|
+
err_txt = (r.stderr or r.stdout or '').lower()
|
|
501
|
+
if any(k in err_txt for k in ('unable to connect', 'could not resolve',
|
|
502
|
+
'connection refused', 'no route to host',
|
|
503
|
+
'network is unreachable', 'timed out')):
|
|
504
|
+
print(' (网络不通 — 产出已本地提交, 下次同步自动补推)')
|
|
505
|
+
break
|
|
440
506
|
if rebase_in_progress():
|
|
441
507
|
git('rebase', '--abort')
|
|
442
508
|
continue
|
|
443
509
|
|
|
444
|
-
r = git('push', 'origin', branch)
|
|
510
|
+
r = git('push', 'origin', branch, timeout=90)
|
|
445
511
|
if r.returncode == 0:
|
|
446
512
|
touch_pull_marker()
|
|
447
513
|
print('Synced to team. (attempt {})'.format(attempt))
|
|
@@ -465,6 +531,13 @@ def _do_push_locked(message, dev, skip_eval, skip_secret):
|
|
|
465
531
|
pass # 埋点失败不阻塞同步
|
|
466
532
|
return 0
|
|
467
533
|
if attempt < MAX_PUSH_RETRY:
|
|
534
|
+
# 网络不通重试无意义, 别让弱网用户干等 (push 超时/连接失败直接退出)
|
|
535
|
+
err_txt = (r.stderr or r.stdout or '').lower()
|
|
536
|
+
if r.returncode == 124 or any(k in err_txt for k in (
|
|
537
|
+
'unable to connect', 'could not resolve', 'connection refused',
|
|
538
|
+
'no route to host', 'network is unreachable', 'timed out')):
|
|
539
|
+
print('Push failed (网络不通): 产出已本地提交, 下次同步自动补推。')
|
|
540
|
+
return 1
|
|
468
541
|
print('Push rejected (someone pushed first?), retrying...')
|
|
469
542
|
|
|
470
543
|
print('Push failed after {} attempts: 产出已本地提交不会丢失, 下次同步自动补推。'.format(MAX_PUSH_RETRY))
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# 子包初始化: 注入 scripts/根 + 所有子包到 sys.path
|
|
2
|
+
# 让跨包 import (旧式不带前缀) 仍可用, 兼容现有代码
|
|
3
|
+
import os as _os, sys as _sys
|
|
4
|
+
_root = _os.path.dirname(_os.path.dirname(_os.path.abspath(__file__)))
|
|
5
|
+
if _root not in _sys.path:
|
|
6
|
+
_sys.path.insert(0, _root)
|
|
7
|
+
# 注入所有子包目录 (兼容旧式 import xxx)
|
|
8
|
+
for _sub in ('kg', 'build', 'test', 'setup', 'io'):
|
|
9
|
+
_subdir = _os.path.join(_root, _sub)
|
|
10
|
+
if _os.path.isdir(_subdir) and _subdir not in _sys.path:
|
|
11
|
+
_sys.path.insert(0, _subdir)
|