dsh-engineering-ui 0.0.0-stage → 1.5.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 (122) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +772 -3
  3. package/engineering/plugins/dsh-engineering-ui/cordis.patch.yml +5 -0
  4. package/engineering/plugins/dsh-engineering-ui/icon.svg +14 -0
  5. package/engineering/plugins/dsh-engineering-ui/lib/client.js +8259 -0
  6. package/engineering/plugins/dsh-engineering-ui/lib/defense-sign.js +1552 -0
  7. package/engineering/plugins/dsh-engineering-ui/lib/index.js +5633 -0
  8. package/engineering/plugins/dsh-engineering-ui/lib/job-wait-guard.js +236 -0
  9. package/engineering/plugins/dsh-engineering-ui/lib/mem-guard.js +331 -0
  10. package/engineering/plugins/dsh-engineering-ui/lib/webots.js +114 -0
  11. package/engineering/plugins/dsh-engineering-ui/locale/en.json +6 -0
  12. package/engineering/plugins/dsh-engineering-ui/locale/zh.json +6 -0
  13. package/engineering/plugins/dsh-engineering-ui/preset-engineering.patch.yml +601 -0
  14. package/engineering/skills/assembly-orchestration/SKILL.md +651 -0
  15. package/engineering/skills/cad-workflow/SKILL.md +132 -0
  16. package/engineering/skills/mode-selection/SKILL.md +660 -0
  17. package/engineering/skills/physics-in-loop/SKILL.md +238 -0
  18. package/engineering/skills/physics-in-loop/references/feadocs.md +142 -0
  19. package/engineering/skills/solidworks-bridge/SKILL.md +445 -0
  20. package/engineering/skills/sw-design/SKILL.md +112 -0
  21. package/engineering/skills/sw-design/references/autocad-workflow.md +81 -0
  22. package/engineering/skills/sw-design/references/gbt-drafting.md +71 -0
  23. package/engineering/skills/sw-to-cad/SKILL.md +121 -0
  24. package/engineering/skills/webots-simulation/SKILL.md +58 -0
  25. package/engineering/tools/LICENSE.Auto-SolidWorks +21 -0
  26. package/engineering/tools/_plugin_paths.py +93 -0
  27. package/engineering/tools/_root.py +330 -0
  28. package/engineering/tools/_store.py +446 -0
  29. package/engineering/tools/ac_bridge.py +459 -0
  30. package/engineering/tools/ac_rules.json +21 -0
  31. package/engineering/tools/ac_validate.py +699 -0
  32. package/engineering/tools/ask_user.py +887 -0
  33. package/engineering/tools/build_arm1.py +46 -0
  34. package/engineering/tools/build_assembly.py +94 -0
  35. package/engineering/tools/build_base.py +57 -0
  36. package/engineering/tools/build_housing.py +70 -0
  37. package/engineering/tools/build_structural.py +43 -0
  38. package/engineering/tools/build_transmission.py +69 -0
  39. package/engineering/tools/cadx.lsp +128 -0
  40. package/engineering/tools/choice_contract.py +61 -0
  41. package/engineering/tools/conn_state.py +1671 -0
  42. package/engineering/tools/defense_gate.py +3374 -0
  43. package/engineering/tools/drawing_input.py +314 -0
  44. package/engineering/tools/env_check.py +467 -0
  45. package/engineering/tools/examples/build_axis.py +142 -0
  46. package/engineering/tools/examples/build_cup.py +56 -0
  47. package/engineering/tools/examples/build_plate.py +58 -0
  48. package/engineering/tools/examples/build_sphere.py +30 -0
  49. package/engineering/tools/examples/build_transition_duct.py +381 -0
  50. package/engineering/tools/gate_integrity.py +401 -0
  51. package/engineering/tools/mode2_flow.py +3589 -0
  52. package/engineering/tools/mode_checker.py +77 -0
  53. package/engineering/tools/mode_gate.py +8013 -0
  54. package/engineering/tools/part_registry.py +4266 -0
  55. package/engineering/tools/physics/__init__.py +50 -0
  56. package/engineering/tools/physics/_compat.py +12 -0
  57. package/engineering/tools/physics/design_state.py +142 -0
  58. package/engineering/tools/physics/domain_validator.py +751 -0
  59. package/engineering/tools/physics/fatigue.py +489 -0
  60. package/engineering/tools/physics/fea_solver.py +1163 -0
  61. package/engineering/tools/physics/feapy_solver.py +314 -0
  62. package/engineering/tools/physics/gb_materials.json +1228 -0
  63. package/engineering/tools/physics/geometry_gate.py +337 -0
  64. package/engineering/tools/physics/load_case.py +951 -0
  65. package/engineering/tools/physics/material_db.py +874 -0
  66. package/engineering/tools/physics/mesh_adapter.py +321 -0
  67. package/engineering/tools/physics/refine_rules.py +272 -0
  68. package/engineering/tools/physics/rules/gb_base_rules.json +377 -0
  69. package/engineering/tools/physics/rules/gb_drafting_rules.json +57 -0
  70. package/engineering/tools/physics/rules/gb_electrical_rules.json +25 -0
  71. package/engineering/tools/physics/rules/gb_fasteners_rules.json +73 -0
  72. package/engineering/tools/physics/rules/gb_housing_rules.json +41 -0
  73. package/engineering/tools/physics/rules/gb_manufacturing_rules.json +25 -0
  74. package/engineering/tools/physics/rules/gb_material_verify_rules.json +72 -0
  75. package/engineering/tools/physics/rules/gb_materials_rules.json +377 -0
  76. package/engineering/tools/physics/rules/gb_safety_rules.json +89 -0
  77. package/engineering/tools/physics/rules/gb_springs_rules.json +41 -0
  78. package/engineering/tools/physics/rules/gb_standards_registry.json +1646 -0
  79. package/engineering/tools/physics/rules/gb_structural_rules.json +201 -0
  80. package/engineering/tools/physics/rules/gb_surface_rules.json +25 -0
  81. package/engineering/tools/physics/rules/gb_transmission_rules.json +233 -0
  82. package/engineering/tools/physics/rules/housing_rules.json +48 -0
  83. package/engineering/tools/physics/rules/manifest.json +54 -0
  84. package/engineering/tools/physics/rules/mold_rules.json +48 -0
  85. package/engineering/tools/physics/rules/structural_rules.json +56 -0
  86. package/engineering/tools/physics/rules/transmission_rules.json +48 -0
  87. package/engineering/tools/physics/simulation_report.py +829 -0
  88. package/engineering/tools/physics_bridge.py +2685 -0
  89. package/engineering/tools/profile-manifest.ps1 +72 -0
  90. package/engineering/tools/run_regression.py +109 -0
  91. package/engineering/tools/settings.py +419 -0
  92. package/engineering/tools/solidworks-modeling.md +519 -0
  93. package/engineering/tools/sw_bridge.py +8215 -0
  94. package/engineering/tools/sw_guard.py +1066 -0
  95. package/engineering/tools/sw_surface.py +87 -0
  96. package/engineering/tools/swapi.py +14766 -0
  97. package/engineering/tools/verify_sync.py +218 -0
  98. package/engineering/tools/visual_check.py +2589 -0
  99. package/engineering/tools/webots_env.py +121 -0
  100. package/engineering/tools/webots_mcp/__init__.py +3 -0
  101. package/engineering/tools/webots_mcp/__main__.py +3 -0
  102. package/engineering/tools/webots_mcp/assembly.py +391 -0
  103. package/engineering/tools/webots_mcp/bootstrap.py +55 -0
  104. package/engineering/tools/webots_mcp/controller_worker.py +124 -0
  105. package/engineering/tools/webots_mcp/evidence.py +288 -0
  106. package/engineering/tools/webots_mcp/fake_worker.py +69 -0
  107. package/engineering/tools/webots_mcp/fault_resources.py +121 -0
  108. package/engineering/tools/webots_mcp/host.py +45 -0
  109. package/engineering/tools/webots_mcp/ledger.py +73 -0
  110. package/engineering/tools/webots_mcp/owned_job.py +70 -0
  111. package/engineering/tools/webots_mcp/physical_gate.py +187 -0
  112. package/engineering/tools/webots_mcp/physics.py +152 -0
  113. package/engineering/tools/webots_mcp/pipeline.py +108 -0
  114. package/engineering/tools/webots_mcp/recipes.py +129 -0
  115. package/engineering/tools/webots_mcp/repair.py +132 -0
  116. package/engineering/tools/webots_mcp/repair_trial.py +375 -0
  117. package/engineering/tools/webots_mcp/runtime.py +311 -0
  118. package/engineering/tools/webots_mcp/server.py +217 -0
  119. package/engineering/tools/webots_mcp/sw_export.py +509 -0
  120. package/engineering/tools/webots_mcp/transport.py +156 -0
  121. package/engineering/tools/workflow_gate.py +6134 -0
  122. package/package.json +64 -4
@@ -0,0 +1,330 @@
1
+ # -*- coding: utf-8 -*-
2
+ r"""_root.py — 工程模式根目录自动探测(Bug-01 修复)
3
+
4
+ ═══════════════════════════════════════════════════════════════════════════
5
+ 【Bug-01 根因】文档写 `python "<工程模式根目录>\tools\workflow_gate.py"`,
6
+ 但"工程模式根目录"在文档里从未被定义,实测用户按字面理解会指向
7
+ `C:\Users\<user>\.dsh\skills\mode-selection\`(那里只有 SKILL.md),
8
+ 于是第 1 步就 `[Errno 2] No such file or directory`。
9
+
10
+ 【本模块的解法】提供**唯一权威**的根目录解析函数,所有脚本/文档都引用它:
11
+ 解析优先级(从高到低):
12
+ ① 环境变量 `DSH_ENGINEERING_ROOT`(用户/编排显式指定,最高优先)
13
+ ② 从调用方脚本自身位置向上回溯,找到同时含
14
+ `tools/mode_gate.py` 与 `tools/workflow_gate.py` 的目录
15
+ ③ 已知的候选路径(工程仓库根、`.dsh/engineering` 等)
16
+ ④ 当前工作目录向上回溯
17
+
18
+ 另外提供 `find_gate()`:在根目录下定位任意门禁脚本(含 `tools/` 与
19
+ `skills/*/tools/` 两级),解决"脚本被挪到别处"的场景。
20
+
21
+ 【用法】
22
+ from _root import engineering_root, gate_path
23
+ root = engineering_root() # -> ...\engineering
24
+ wg = gate_path("workflow_gate.py") # -> ...\engineering\tools\workflow_gate.py
25
+
26
+ 命令行自检(Bug-01 建议的 find_gate.py 等价物):
27
+ python _root.py # 打印解析结果与全部候选
28
+ python _root.py --json # 机器可读
29
+ """
30
+ from __future__ import annotations
31
+
32
+ import json
33
+ import os
34
+ import sys
35
+
36
+ # ══ 【F-02 修复 · 2026-10-31】UTF-8 输出防护 ═══════════════════════════════
37
+ # 实测缺陷:python _root.py 默认输出中文全乱码(exit 0,乱码被静默吞掉)。
38
+ # 根因:本脚本用 print() 直接输出中文("工程模式根目录"/"门禁脚本"/"(缺失)"),
39
+ # 而 Windows 控制台/pwsh 捕获时默认代码页是 GBK(936);
40
+ # 一旦 stdout 被重定向成管道(AI 工具链里 100% 如此),Python 会按
41
+ # locale 编码(GBK)写出,中文被写坏 —— 且因为 errors 默认是
42
+ # "strict",某些字符还会直接抛 UnicodeEncodeError 把整条命令打断。
43
+ # 其它主工具链(mode_gate.py L34-38 / sw_bridge.py L202-203 /
44
+ # defense_gate.py L2582)都有同样的 reconfigure 防护,
45
+ # 唯独 _root.py 漏了 —— 本修复把它对齐。
46
+ # 写法与 mode_gate.py 保持一致:try/except 包裹,兼容无 reconfigure 属性的
47
+ # 环境(如 stdout 被替换成 StringIO / 老版本 Python)。
48
+ try:
49
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
50
+ sys.stderr.reconfigure(encoding="utf-8", errors="replace")
51
+ except Exception:
52
+ pass
53
+
54
+
55
+ def _utf8_print(text=""):
56
+ """【F-02 修复】以 UTF-8 字节写出,绕开控制台代码页(与 mode_gate.emit 同源)。
57
+
58
+ 为什么 reconfigure 还不够:
59
+ reconfigure 只在 sys.stdout 是可重配置的 TextIOWrapper 时生效;
60
+ 若调用方把 stdout 换成别的对象(测试框架捕获、DSH 插件重定向),
61
+ reconfigure 会静默失败,print() 又回到 locale 编码 → 乱码重现。
62
+ 这里做第二道保险:优先直接写 sys.stdout.buffer 的 UTF-8 字节;
63
+ 没有 buffer 才退回普通 print;再不行退回 ASCII 转义(宁可转义也不乱码)。
64
+ """
65
+ s = str(text)
66
+ try:
67
+ _buf = getattr(sys.stdout, "buffer", None)
68
+ if _buf is not None:
69
+ _buf.write((s + "\n").encode("utf-8", "replace"))
70
+ _buf.flush()
71
+ return
72
+ except Exception:
73
+ pass
74
+ try:
75
+ sys.stdout.write(s + "\n")
76
+ sys.stdout.flush()
77
+ except UnicodeEncodeError:
78
+ # 代码页无法编码中文 → 退回 ASCII 转义(无损,绝不留乱码)
79
+ try:
80
+ sys.stdout.write((s.encode("ascii", "backslashreplace")
81
+ .decode("ascii")) + "\n")
82
+ sys.stdout.flush()
83
+ except Exception:
84
+ pass
85
+
86
+
87
+ # 根目录必须同时包含这些"指纹"文件,才算真的工程模式根目录
88
+ _ROOT_FINGERPRINTS = (
89
+ os.path.join("tools", "mode_gate.py"),
90
+ os.path.join("tools", "workflow_gate.py"),
91
+ )
92
+ # 门禁脚本可能出现的相对位置(相对工程根目录)
93
+ _GATE_SUBDIRS = (
94
+ "tools",
95
+ os.path.join("skills", "mode-selection", "tools"),
96
+ os.path.join("skills", "assembly-orchestration", "tools"),
97
+ )
98
+
99
+ ENV_VAR = "DSH_ENGINEERING_ROOT"
100
+
101
+ # 门禁脚本清单(供 find_gate 校验)
102
+ GATE_SCRIPTS = (
103
+ "mode_gate.py",
104
+ "workflow_gate.py",
105
+ "sw_bridge.py",
106
+ "swapi.py",
107
+ "ask_user.py",
108
+ "physics_bridge.py",
109
+ "ac_validate.py",
110
+ "ac_bridge.py",
111
+ )
112
+
113
+
114
+ def _is_engineering_root(path: str) -> bool:
115
+ """目录是否为工程模式根目录(含全部指纹文件)。"""
116
+ if not path:
117
+ return False
118
+ try:
119
+ if not os.path.isdir(path):
120
+ return False
121
+ return all(os.path.isfile(os.path.join(path, fp)) for fp in _ROOT_FINGERPRINTS)
122
+ except Exception:
123
+ return False
124
+
125
+
126
+ def _walk_up(start: str):
127
+ """从 start 向上逐级产出目录(含 start 本身)。"""
128
+ try:
129
+ cur = os.path.abspath(start)
130
+ except Exception:
131
+ return
132
+ seen = set()
133
+ while cur and cur not in seen:
134
+ seen.add(cur)
135
+ yield cur
136
+ parent = os.path.dirname(cur)
137
+ if parent == cur:
138
+ break
139
+ cur = parent
140
+
141
+
142
+ def _candidate_roots():
143
+ """产出全部候选根目录(按优先级)。"""
144
+ out = []
145
+
146
+ # ① 环境变量
147
+ try:
148
+ env = (os.environ.get(ENV_VAR) or "").strip().strip('"').strip("'")
149
+ if env:
150
+ out.append(env)
151
+ # 环境变量可能指向仓库根(含 engineering/ 子目录)
152
+ out.append(os.path.join(env, "engineering"))
153
+ except Exception:
154
+ pass
155
+
156
+ # ② 调用方脚本自身位置向上回溯
157
+ try:
158
+ here = os.path.dirname(os.path.abspath(__file__))
159
+ for d in _walk_up(here):
160
+ out.append(d)
161
+ except Exception:
162
+ pass
163
+
164
+ # ③ 当前工作目录向上回溯
165
+ try:
166
+ for d in _walk_up(os.getcwd()):
167
+ out.append(d)
168
+ except Exception:
169
+ pass
170
+
171
+ # ④ 常见约定位置
172
+ try:
173
+ home = os.environ.get("USERPROFILE") or os.environ.get("HOME") or ""
174
+ if home:
175
+ out.append(os.path.join(home, ".dsh", "engineering"))
176
+ out.append(os.path.join(home, ".dsh", "skills", "mode-selection"))
177
+ out.append(os.path.join(home, ".dsh"))
178
+ out.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
179
+ except Exception:
180
+ pass
181
+
182
+ # 去重保序
183
+ seen = set()
184
+ uniq = []
185
+ for p in out:
186
+ if not p:
187
+ continue
188
+ try:
189
+ key = os.path.normcase(os.path.abspath(p))
190
+ except Exception:
191
+ continue
192
+ if key in seen:
193
+ continue
194
+ seen.add(key)
195
+ uniq.append(p)
196
+ return uniq
197
+
198
+
199
+ def engineering_root(required: bool = False) -> str | None:
200
+ """解析工程模式根目录。
201
+
202
+ Args:
203
+ required: 为 True 时解析失败直接抛 RuntimeError(附带全部候选),
204
+ 便于脚本尽早失败并给出可操作的错误信息。
205
+ Returns:
206
+ 根目录绝对路径;解析失败返回 None(required=False 时)。
207
+ """
208
+ cands = _candidate_roots()
209
+ for c in cands:
210
+ if _is_engineering_root(c):
211
+ try:
212
+ return os.path.abspath(c)
213
+ except Exception:
214
+ return c
215
+
216
+ # 退化路径:只要能找到 mode_gate.py / workflow_gate.py 所在的 tools/ 目录,
217
+ # 就把它当作"工具目录",其父目录即根目录。这覆盖"指纹文件不全但脚本都在"
218
+ # 的场景(例如用户只拷了 tools/ 目录)。
219
+ for c in cands:
220
+ try:
221
+ if os.path.isfile(os.path.join(c, "mode_gate.py")) and \
222
+ os.path.isfile(os.path.join(c, "workflow_gate.py")):
223
+ return os.path.abspath(os.path.dirname(c))
224
+ except Exception:
225
+ continue
226
+
227
+ if required:
228
+ raise RuntimeError(
229
+ "无法定位工程模式根目录。请设置环境变量 %s 指向包含 tools/ 的目录。\n"
230
+ "已尝试的候选路径:\n - %s" % (ENV_VAR, "\n - ".join(cands))
231
+ )
232
+ return None
233
+
234
+
235
+ def tools_dir(required: bool = False) -> str | None:
236
+ """工程模式的 tools/ 目录(门禁脚本所在处)。"""
237
+ root = engineering_root(required=False)
238
+ if root:
239
+ cand = os.path.join(root, "tools")
240
+ if os.path.isdir(cand):
241
+ return cand
242
+ # 退化:本文件所在目录通常就是 tools/
243
+ here = os.path.dirname(os.path.abspath(__file__))
244
+ if os.path.isfile(os.path.join(here, "mode_gate.py")):
245
+ return here
246
+ if required:
247
+ raise RuntimeError("无法定位工程模式 tools/ 目录,请设置 %s" % ENV_VAR)
248
+ return None
249
+
250
+
251
+ def gate_path(script: str, required: bool = False) -> str | None:
252
+ """定位某个门禁脚本的绝对路径。
253
+
254
+ 搜索顺序:环境变量根 → 工程根 tools/ → 工程根 skills/*/tools/ →
255
+ 本文件所在目录 → 工作目录向上。
256
+ """
257
+ name = os.path.basename(str(script or "").strip())
258
+ if not name:
259
+ return None
260
+
261
+ cands = []
262
+ root = engineering_root(required=False)
263
+ if root:
264
+ for sub in _GATE_SUBDIRS:
265
+ cands.append(os.path.join(root, sub, name))
266
+ here = os.path.dirname(os.path.abspath(__file__))
267
+ cands.append(os.path.join(here, name))
268
+ for d in _walk_up(os.getcwd()):
269
+ cands.append(os.path.join(d, name))
270
+ cands.append(os.path.join(d, "tools", name))
271
+
272
+ for c in cands:
273
+ try:
274
+ if os.path.isfile(c):
275
+ return os.path.abspath(c)
276
+ except Exception:
277
+ continue
278
+ if required:
279
+ raise RuntimeError("找不到门禁脚本 %s(工程模式根目录=%s)" % (name, root))
280
+ return None
281
+
282
+
283
+ def root_report() -> dict:
284
+ """自检报告:解析结果 + 全部候选 + 各候选是否命中。"""
285
+ root = engineering_root(required=False)
286
+ tools = tools_dir(required=False)
287
+ cands = []
288
+ for c in _candidate_roots():
289
+ cands.append({"path": c, "is_root": _is_engineering_root(c)})
290
+ gates = {}
291
+ for s in GATE_SCRIPTS:
292
+ gates[s] = gate_path(s)
293
+ return {
294
+ "ok": bool(root),
295
+ "env_var": ENV_VAR,
296
+ "env_value": os.environ.get(ENV_VAR),
297
+ "engineering_root": root,
298
+ "tools_dir": tools,
299
+ "gate_scripts": gates,
300
+ "missing_gate_scripts": [k for k, v in gates.items() if not v],
301
+ "candidates": cands,
302
+ "hint": (None if root else
303
+ "未找到工程模式根目录。请设置 %s 指向含 tools/ 的目录,例如:\n"
304
+ " setx %s \"<仓库>\\engineering\" (或在当前会话 set %s=...)"
305
+ % (ENV_VAR, ENV_VAR, ENV_VAR)),
306
+ }
307
+
308
+
309
+ def main(argv=None):
310
+ argv = list(sys.argv[1:] if argv is None else argv)
311
+ rep = root_report()
312
+ # 【F-02 修复】全部输出走 _utf8_print,保证中文在任何代码页下都可读
313
+ if "--json" in argv:
314
+ _utf8_print(json.dumps(rep, ensure_ascii=False, indent=2))
315
+ else:
316
+ _utf8_print("工程模式根目录 : %s" % (rep["engineering_root"] or "(未找到)"))
317
+ _utf8_print("tools/ 目录 : %s" % (rep["tools_dir"] or "(未找到)"))
318
+ _utf8_print("环境变量 : %s=%s"
319
+ % (rep["env_var"], rep["env_value"] or "(未设置)"))
320
+ _utf8_print("门禁脚本:")
321
+ for k, v in rep["gate_scripts"].items():
322
+ _utf8_print(" %-20s %s" % (k, v or "(缺失)"))
323
+ if rep["hint"]:
324
+ _utf8_print("")
325
+ _utf8_print(rep["hint"])
326
+ return 0 if rep["ok"] else 1
327
+
328
+
329
+ if __name__ == "__main__":
330
+ sys.exit(main())