@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.
Files changed (152) hide show
  1. package/bin/cli.js +375 -78
  2. package/package.json +29 -29
  3. package/templates/.qoder/.runtime/ctx-cache-5660152f1d6dd819.md +23 -0
  4. package/templates/.qoder/.runtime/ctx-cache-afdce0dac06b25b0.md +23 -0
  5. package/templates/.qoder/.runtime/search-cache-eae7644e7b122f35.txt +1 -0
  6. package/templates/.qoder/learning/eval-history.jsonl +28 -0
  7. package/templates/data/index/wiki-index.json +8 -0
  8. package/templates/qoder/agents/insight-planning.md +1 -1
  9. package/templates/qoder/agents/insight-research.md +28 -15
  10. package/templates/qoder/commands/optional/wl-insight.md +159 -161
  11. package/templates/qoder/commands/optional/wl-report.md +4 -4
  12. package/templates/qoder/commands/optional/wl-status.md +2 -2
  13. package/templates/qoder/commands/wl-code.md +2 -2
  14. package/templates/qoder/commands/wl-design.md +2 -2
  15. package/templates/qoder/commands/wl-init.md +3 -3
  16. package/templates/qoder/commands/wl-prd.md +2 -2
  17. package/templates/qoder/commands/wl-req.md +43 -0
  18. package/templates/qoder/commands/wl-search.md +8 -8
  19. package/templates/qoder/commands/wl-task.md +17 -17
  20. package/templates/qoder/commands/wl-test.md +41 -15
  21. package/templates/qoder/config.yaml +17 -1
  22. package/templates/qoder/hooks/session-start.py +12 -22
  23. package/templates/qoder/nul +4 -0
  24. package/templates/qoder/rules/wl-pipeline.md +22 -48
  25. package/templates/qoder/scripts/README.md +139 -0
  26. package/templates/qoder/scripts/common/autotest_auth.py +109 -0
  27. package/templates/qoder/scripts/common/bootstrap.py +145 -0
  28. package/templates/qoder/scripts/common/check_publish.py +98 -0
  29. package/templates/qoder/scripts/common/cmd_registry.py +112 -0
  30. package/templates/qoder/scripts/common/config.py +187 -0
  31. package/templates/qoder/scripts/common/contract.py +317 -0
  32. package/templates/qoder/scripts/common/developer.py +2 -1
  33. package/templates/qoder/scripts/common/feishu.py +10 -9
  34. package/templates/qoder/scripts/common/guard.py +159 -0
  35. package/templates/qoder/scripts/common/identity.py +121 -2
  36. package/templates/qoder/scripts/common/kg_capabilities.py +182 -0
  37. package/templates/qoder/scripts/common/mcp_base.py +268 -0
  38. package/templates/qoder/scripts/common/paths.py +187 -1
  39. package/templates/qoder/scripts/common/result.py +223 -0
  40. package/templates/qoder/scripts/common/roles.py +60 -0
  41. package/templates/qoder/scripts/common/task_utils.py +21 -9
  42. package/templates/qoder/scripts/common/test_extract.py +115 -0
  43. package/templates/qoder/scripts/kg/__init__.py +11 -0
  44. package/templates/qoder/scripts/kg/build_entity_registry.py +196 -0
  45. package/templates/qoder/scripts/kg/build_relations.py +127 -0
  46. package/templates/qoder/scripts/{build_style_index.py → kg/build_style_index.py} +39 -10
  47. package/templates/qoder/scripts/kg/build_workflows.py +144 -0
  48. package/templates/qoder/scripts/{context_pack.py → kg/context_pack.py} +18 -11
  49. package/templates/qoder/scripts/{enrich_prompt.py → kg/enrich_prompt.py} +232 -226
  50. package/templates/qoder/scripts/{extract_api_params.py → kg/extract.py} +398 -246
  51. package/templates/qoder/scripts/{kg.py → kg/kg.py} +638 -708
  52. package/templates/qoder/scripts/{kg_build.py → kg/kg_build.py} +618 -612
  53. package/templates/qoder/scripts/{kg_build_db.py → kg/kg_build_db.py} +333 -327
  54. package/templates/qoder/scripts/{kg_duckdb.py → kg/kg_duckdb.py} +38 -37
  55. package/templates/qoder/scripts/{kg_incremental.py → kg/kg_incremental.py} +420 -393
  56. package/templates/qoder/scripts/{kg_link_db.py → kg/kg_link_db.py} +230 -224
  57. package/templates/qoder/scripts/{kg_semantic.py → kg/kg_semantic.py} +156 -150
  58. package/templates/qoder/scripts/kg/prefetch.py +359 -0
  59. package/templates/qoder/scripts/{search_index.py → kg/search_index.py} +70 -14
  60. package/templates/qoder/scripts/mcp/__init__.py +11 -0
  61. package/templates/qoder/scripts/{kg_mcp_server.py → mcp/kg_mcp_server.py} +77 -272
  62. package/templates/qoder/scripts/{lanhu_stdio_wrapper.py → mcp/lanhu_stdio_wrapper.py} +125 -119
  63. package/templates/qoder/scripts/{check_mcp.py → mcp/mcp_doctor.py} +515 -298
  64. package/templates/qoder/scripts/{mcp_launcher.py → mcp/mcp_launcher.py} +442 -414
  65. package/templates/qoder/scripts/{mysql_mcp_server.py → mcp/mysql_mcp_server.py} +347 -396
  66. package/templates/qoder/scripts/{zentao_mcp_server.py → mcp/zentao_mcp_server.py} +384 -424
  67. package/templates/qoder/scripts/report/__init__.py +11 -0
  68. package/templates/qoder/scripts/{add_session.py → report/add_session.py} +250 -244
  69. package/templates/qoder/scripts/{archive_prd.py → report/archive_prd.py} +383 -377
  70. package/templates/qoder/scripts/{eval_prd.py → report/eval_prd.py} +73 -11
  71. package/templates/qoder/scripts/{export.py → report/export.py} +63 -0
  72. package/templates/qoder/scripts/{fill_prototype.py → report/fill_prototype.py} +6 -0
  73. package/templates/qoder/scripts/{gen_design_doc.py → report/gen_design_doc.py} +400 -394
  74. package/templates/qoder/scripts/{learn.py → report/learn.py} +152 -146
  75. package/templates/qoder/scripts/{learn_aggregate.py → report/learn_aggregate.py} +207 -201
  76. package/templates/qoder/scripts/{report.py → report/report.py} +287 -281
  77. package/templates/qoder/scripts/report/req.py +222 -0
  78. package/templates/qoder/scripts/report/role.py +33 -0
  79. package/templates/qoder/scripts/{status.py → report/status.py} +634 -628
  80. package/templates/qoder/scripts/setup/__init__.py +11 -0
  81. package/templates/qoder/scripts/setup/carriers.py +662 -0
  82. package/templates/qoder/scripts/{init_doctor.py → setup/init_doctor.py} +63 -26
  83. package/templates/qoder/scripts/{install_qoderwork.py → setup/install_qoderwork.py} +36 -26
  84. package/templates/qoder/scripts/{platform_doctor.py → setup/platform_doctor.py} +265 -259
  85. package/templates/qoder/scripts/{repo_root.py → setup/repo_root.py} +112 -106
  86. package/templates/qoder/scripts/{setup.py → setup/setup.py} +147 -0
  87. package/templates/qoder/scripts/{setup_lanhu.py → setup/setup_lanhu.py} +973 -963
  88. package/templates/qoder/scripts/task/__init__.py +11 -0
  89. package/templates/qoder/scripts/{git_sync.py → task/git_sync.py} +52 -31
  90. package/templates/qoder/scripts/{syncgate.py → task/syncgate.py} +6 -0
  91. package/templates/qoder/scripts/task/task.py +221 -0
  92. package/templates/qoder/scripts/task/task_lifecycle.py +596 -0
  93. package/templates/qoder/scripts/task/task_query.py +161 -0
  94. package/templates/qoder/scripts/task/task_relations.py +424 -0
  95. package/templates/qoder/scripts/{team_sync.py → task/team_sync.py} +93 -20
  96. package/templates/qoder/scripts/test/__init__.py +11 -0
  97. package/templates/qoder/scripts/{autotest.py → test/autotest.py} +1174 -1751
  98. package/templates/qoder/scripts/{autotest_batch.py → test/autotest_batch.py} +242 -224
  99. package/templates/qoder/scripts/test/autotest_data.py +675 -0
  100. package/templates/qoder/scripts/{autotest_run.py → test/autotest_run.py} +309 -297
  101. package/templates/qoder/scripts/{benchmark.py → test/benchmark.py} +6 -0
  102. package/templates/qoder/scripts/{kg_auto_login.py → test/kg_auto_login.py} +202 -196
  103. package/templates/qoder/scripts/{kg_test_runner.py → test/kg_test_runner.py} +7 -1
  104. package/templates/qoder/scripts/{page_probe.py → test/page_probe.py} +465 -459
  105. package/templates/qoder/scripts/wlkj.py +116 -0
  106. package/templates/qoder/settings.json +1 -10
  107. package/templates/qoder/skills/design-import/SKILL.md +226 -226
  108. package/templates/qoder/skills/design-review/SKILL.md +82 -82
  109. package/templates/qoder/skills/prd-generator/SKILL.md +26 -16
  110. package/templates/qoder/skills/prd-review/SKILL.md +5 -5
  111. package/templates/qoder/skills/prototype-generator/SKILL.md +256 -256
  112. package/templates/qoder/skills/spec-coder/SKILL.md +4 -4
  113. package/templates/qoder/skills/spec-generator/SKILL.md +4 -4
  114. package/templates/qoder/skills/test-generator/SKILL.md +5 -5
  115. package/templates/qoder/skills/wl-code/SKILL.md +4 -4
  116. package/templates/qoder/skills/wl-commit/SKILL.md +4 -4
  117. package/templates/qoder/skills/wl-design/SKILL.md +3 -3
  118. package/templates/qoder/skills/wl-init/SKILL.md +8 -8
  119. package/templates/qoder/skills/wl-insight/SKILL.md +5 -5
  120. package/templates/qoder/skills/wl-prd-full/SKILL.md +6 -6
  121. package/templates/qoder/skills/wl-prd-quick/SKILL.md +6 -6
  122. package/templates/qoder/skills/wl-prd-review/SKILL.md +4 -4
  123. package/templates/qoder/skills/wl-report/SKILL.md +7 -7
  124. package/templates/qoder/skills/wl-search/SKILL.md +13 -13
  125. package/templates/qoder/skills/wl-spec/SKILL.md +5 -5
  126. package/templates/qoder/skills/wl-status/SKILL.md +5 -5
  127. package/templates/qoder/skills/wl-task/SKILL.md +6 -6
  128. package/templates/qoder/skills/wl-test/SKILL.md +102 -39
  129. package/templates/root/AGENTS.md +39 -40
  130. package/templates/qoder/hooks/inject-workflow-state.py +0 -169
  131. package/templates/qoder/scripts/__pycache__/check_mcp_launch.cpython-39.pyc +0 -0
  132. package/templates/qoder/scripts/__pycache__/install_qoderwork.cpython-39.pyc +0 -0
  133. package/templates/qoder/scripts/__pycache__/mcp_launcher.cpython-39.pyc +0 -0
  134. package/templates/qoder/scripts/__pycache__/platform_doctor.cpython-39.pyc +0 -0
  135. package/templates/qoder/scripts/check_carriers.py +0 -238
  136. package/templates/qoder/scripts/check_mcp_launch.py +0 -183
  137. package/templates/qoder/scripts/check_qoderwork_consistency.py +0 -166
  138. package/templates/qoder/scripts/collect_prds.py +0 -31
  139. package/templates/qoder/scripts/common/mentions.py +0 -134
  140. package/templates/qoder/scripts/common/utf8.py +0 -38
  141. package/templates/qoder/scripts/extract_routes.py +0 -54
  142. package/templates/qoder/scripts/extract_routes_tree.py +0 -78
  143. package/templates/qoder/scripts/handoff.py +0 -22
  144. package/templates/qoder/scripts/init_developer.py +0 -76
  145. package/templates/qoder/scripts/parse_prds.py +0 -33
  146. package/templates/qoder/scripts/role.py +0 -51
  147. package/templates/qoder/scripts/sync_carriers.py +0 -259
  148. package/templates/qoder/scripts/task.py +0 -1261
  149. package/templates/qoder/scripts/workspace_init.py +0 -102
  150. package/templates/qoder/skills/prompt-enrich/SKILL.md +0 -90
  151. package/templates/qoder/skills/prototype-generator/SKILL.md.zcode-79180-2af4721f-f9a6-412c-88db-c0af680d211b.tmp +0 -0
  152. /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
- r = subprocess.run(['git'] + list(args), cwd=BASE, capture_output=True,
56
- text=True, encoding='utf-8', errors='replace')
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
- r = git('pull', '--rebase', '--autostash', 'origin', branch)
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
- staged = 0
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
- # 已跟踪文件: 直接 add (它们已经在版本控制, 不可能是新秘密)
344
+ # 已跟踪文件: 收集 (它们已经在版本控制, 不可能是新秘密)
296
345
  r = git('ls-files', '--', scope)
297
- tracked = [f for f in r.stdout.strip().splitlines() if f.strip()]
298
- for f in tracked:
299
- git('add', '--', f)
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
- git('add', '--', fpath)
317
- staged += 1
364
+ to_add.append(fpath)
318
365
  else:
319
366
  skipped.append(fpath)
320
367
  elif 'D' not in status:
321
- # 修改/重命名等 (非删除) —— 已跟踪, 直接 add
368
+ # 修改/重命名等 (非删除) —— 已跟踪, 收集
322
369
  # 重命名格式 "R old -> new", 取 new
323
370
  if '->' in fpath:
324
371
  fpath = fpath.split('->')[-1].strip().strip('"')
325
- git('add', '--', fpath)
326
- staged += 1
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)