ソースを参照

fix(env): clone 后缺失 Runtime\Contracts 导致扩展加载失败(剥掉 exe 内嵌契约的回归)

exe 不再内嵌契约后,运行时契约的唯一来源是 build\Runtime\Contracts\,而该目录属
运行时数据被 .gitignore 忽略 —— clone / 干净检出下来就是空的。它不会让编译失败,
只在启动后表现为告警"契约目录不存在"乃至 TypeLoadException,属典型静默坑。

补齐两道防线:

- StageRuntimeContracts (AfterTargets=Build)
  从随源码入库的 build\lib\ 自动就位契约程序集。干净检出后第一次 Build 即完备,
  无需手工拷贝,也无需联网。

- tools\ensure-env.ps1(环境自检脚本)
  逐项报告 MSBuild / 宿主 exe / lib 依赖 / 运行时契约,缺啥说啥,能补的顺手补;
  退出码 0=环境完备,1=存在无法自动补齐的缺失(并逐条列出)。
  注意:必须以 UTF-8 with BOM 保存 —— PS 5.1 读取无 BOM 的 .ps1 时按 ANSI(GBK)
  解析中文,会把输出变成乱码。

干净检出实测:40 个文件 → ensure-env(或一次 msbuild)→ 启动 TeamPLT.exe,
日志"[契约] 契约包已加载:1 个程序集 / 58 个契约接口",扩展与品牌驱动均正常登记,
零告警零异常。
王硕 1 週間 前
親
コミット
958851acca

+ 93 - 23
index.json

@@ -1,6 +1,6 @@
 {
     "schemaVersion":  1,
-    "generatedAt":  "2026-09-25T07:10:10Z",
+    "generatedAt":  "2026-09-25T07:48:55Z",
     "packages":  [
                      {
                          "id":  "Plugins.Camera.Ahua",
@@ -110,15 +110,15 @@
                      {
                          "id":  "Plugins.Plc.Mitsubishi",
                          "name":  "三菱 PLC",
-                         "version":  "1.0.0",
+                         "version":  "1.0.1",
                          "publisher":  "TeamAAS",
                          "kind":  "extension",
                          "host":  "communication",
                          "description":  "三菱 MC 协议 PLC 通讯驱动(HslCommunication):通讯扩展子插件,直接导出 IPlcDriverProvider,按需安装。",
                          "notes":  "首次收录",
-                         "downloadUrl":  "packages/communication/Plugins.Plc.Mitsubishi/Plugins.Plc.Mitsubishi-1.0.0.zip",
-                         "sha256":  "9e3d511d96c8b1bdae5720375b39cca5f662f0f113b0a9008c0943bdb5168287",
-                         "size":  2000905,
+                         "downloadUrl":  "packages/communication/Plugins.Plc.Mitsubishi/Plugins.Plc.Mitsubishi-1.0.1.zip",
+                         "sha256":  "8d5c4453276a2b7d4a2850d383f341bcceb74402e2c1f89797443e767514410c",
+                         "size":  1910962,
                          "references":  [
                                             "TeamPLT.SDK",
                                             "TeamPLT.Contracts",
@@ -130,9 +130,18 @@
                                       "x64"
                                   ],
                          "dependencies":  [
-
+                                              "TeamPLT.Contracts"
                                           ],
                          "versions":  [
+                                          {
+                                              "version":  "1.0.1",
+                                              "downloadUrl":  "packages/communication/Plugins.Plc.Mitsubishi/Plugins.Plc.Mitsubishi-1.0.1.zip",
+                                              "sha256":  "8d5c4453276a2b7d4a2850d383f341bcceb74402e2c1f89797443e767514410c",
+                                              "size":  1910962,
+                                              "releasedAt":  "2026-09-25",
+                                              "status":  "stable",
+                                              "notes":  "首次收录"
+                                          },
                                           {
                                               "version":  "1.0.0",
                                               "downloadUrl":  "packages/communication/Plugins.Plc.Mitsubishi/Plugins.Plc.Mitsubishi-1.0.0.zip",
@@ -147,15 +156,15 @@
                      {
                          "id":  "Plugins.Plc.OpcUa",
                          "name":  "OPC UA 客户端",
-                         "version":  "1.0.0",
+                         "version":  "1.0.1",
                          "publisher":  "TeamAAS",
                          "kind":  "extension",
                          "host":  "communication",
                          "description":  "OPC UA 客户端驱动(OPC Foundation UA-.NETStandard:匿名身份 / SecurityPolicy=None):通讯扩展子插件,直接导出 IPlcDriverProvider,按需安装。",
                          "notes":  "首次收录",
-                         "downloadUrl":  "packages/communication/Plugins.Plc.OpcUa/Plugins.Plc.OpcUa-1.0.0.zip",
-                         "sha256":  "b1fee0479492f72887b491ad9bdd087fb83ee72a22b54a2fbcfc7f37990d640f",
-                         "size":  6941520,
+                         "downloadUrl":  "packages/communication/Plugins.Plc.OpcUa/Plugins.Plc.OpcUa-1.0.1.zip",
+                         "sha256":  "0d6454de80066c10feb05671216f7810fead479d00c6615ceb6fa5bd4a8f7cc6",
+                         "size":  6947668,
                          "references":  [
                                             "TeamPLT.SDK",
                                             "TeamPLT.Contracts"
@@ -166,9 +175,18 @@
                                       "x64"
                                   ],
                          "dependencies":  [
-
+                                              "TeamPLT.Contracts"
                                           ],
                          "versions":  [
+                                          {
+                                              "version":  "1.0.1",
+                                              "downloadUrl":  "packages/communication/Plugins.Plc.OpcUa/Plugins.Plc.OpcUa-1.0.1.zip",
+                                              "sha256":  "0d6454de80066c10feb05671216f7810fead479d00c6615ceb6fa5bd4a8f7cc6",
+                                              "size":  6947668,
+                                              "releasedAt":  "2026-09-25",
+                                              "status":  "stable",
+                                              "notes":  "首次收录"
+                                          },
                                           {
                                               "version":  "1.0.0",
                                               "downloadUrl":  "packages/communication/Plugins.Plc.OpcUa/Plugins.Plc.OpcUa-1.0.0.zip",
@@ -183,15 +201,15 @@
                      {
                          "id":  "Plugins.Plc.Siemens",
                          "name":  "西门子 PLC",
-                         "version":  "1.0.0",
+                         "version":  "1.0.1",
                          "publisher":  "TeamAAS",
                          "kind":  "extension",
                          "host":  "communication",
                          "description":  "西门子 S7 协议 PLC 通讯驱动(HslCommunication):通讯扩展子插件,直接导出 IPlcDriverProvider,按需安装。",
                          "notes":  "首次收录",
-                         "downloadUrl":  "packages/communication/Plugins.Plc.Siemens/Plugins.Plc.Siemens-1.0.0.zip",
-                         "sha256":  "93d8ef4bc1d4b5f4b72c7cf5bd37bfc2a46944700e58804671a08b14569b188b",
-                         "size":  2000141,
+                         "downloadUrl":  "packages/communication/Plugins.Plc.Siemens/Plugins.Plc.Siemens-1.0.1.zip",
+                         "sha256":  "2d30538e6fdaa8c436d0f82a3b92d33903acd5a688a0c2e085ac8da63441c2d3",
+                         "size":  1910181,
                          "references":  [
                                             "TeamPLT.SDK",
                                             "TeamPLT.Contracts",
@@ -203,9 +221,18 @@
                                       "x64"
                                   ],
                          "dependencies":  [
-
+                                              "TeamPLT.Contracts"
                                           ],
                          "versions":  [
+                                          {
+                                              "version":  "1.0.1",
+                                              "downloadUrl":  "packages/communication/Plugins.Plc.Siemens/Plugins.Plc.Siemens-1.0.1.zip",
+                                              "sha256":  "2d30538e6fdaa8c436d0f82a3b92d33903acd5a688a0c2e085ac8da63441c2d3",
+                                              "size":  1910181,
+                                              "releasedAt":  "2026-09-25",
+                                              "status":  "stable",
+                                              "notes":  "首次收录"
+                                          },
                                           {
                                               "version":  "1.0.0",
                                               "downloadUrl":  "packages/communication/Plugins.Plc.Siemens/Plugins.Plc.Siemens-1.0.0.zip",
@@ -328,19 +355,18 @@
                      {
                          "id":  "Ext.Communication",
                          "name":  "通讯",
-                         "version":  "1.0.1",
+                         "version":  "1.0.2",
                          "publisher":  "TeamAAS",
                          "kind":  "extension",
                          "host":  "platform",
                          "description":  "通讯模块:TCP 客户端/服务器、UDP、串口透传与 Modbus TCP 设备管理、地址读写、状态监视(含仿真 PLC;其他品牌 PLC 由独立插件经 IPlcDriverRegistry 接入)。",
                          "notes":  "• TCP 客户端/服务器、UDP、串口透传\n• Modbus TCP 设备管理、地址读写与状态监视\n• 内置仿真 PLC,其他品牌经 IPlcDriverRegistry 插件接入",
-                         "downloadUrl":  "packages/platform/Ext.Communication/Ext.Communication-1.0.1.zip",
-                         "sha256":  "76e8e122d8b0c0555df4f995b33cff853e1ab889aeefa203aebb01ea0c93cc49",
-                         "size":  2233758,
+                         "downloadUrl":  "packages/platform/Ext.Communication/Ext.Communication-1.0.2.zip",
+                         "sha256":  "bfaee76cfcb6ceb003ebe30c3109f3ac5c4cf2c00dae7190a80f093a74f5455d",
+                         "size":  2143855,
                          "references":  [
                                             "TeamPLT.SDK",
-                                            "TeamPLT.Contracts",
-                                            "TeamAAS.Base.Contracts"
+                                            "TeamPLT.Contracts"
                                         ],
                          "targetFramework":  "net48",
                          "requiresHost":  "TeamPLT>=2.1.0",
@@ -348,9 +374,18 @@
                                       "x64"
                                   ],
                          "dependencies":  [
-                                              "TeamAAS.Base.Contracts"
+                                              "TeamPLT.Contracts"
                                           ],
                          "versions":  [
+                                          {
+                                              "version":  "1.0.2",
+                                              "downloadUrl":  "packages/platform/Ext.Communication/Ext.Communication-1.0.2.zip",
+                                              "sha256":  "bfaee76cfcb6ceb003ebe30c3109f3ac5c4cf2c00dae7190a80f093a74f5455d",
+                                              "size":  2143855,
+                                              "releasedAt":  "2026-09-25",
+                                              "status":  "stable",
+                                              "notes":  "• TCP 客户端/服务器、UDP、串口透传\n• Modbus TCP 设备管理、地址读写与状态监视\n• 内置仿真 PLC,其他品牌经 IPlcDriverRegistry 插件接入"
+                                          },
                                           {
                                               "version":  "1.0.1",
                                               "downloadUrl":  "packages/platform/Ext.Communication/Ext.Communication-1.0.1.zip",
@@ -517,6 +552,41 @@
                                               "notes":  "• 产品栏 / 画面区 / 生产统计卡 + 运行日志面板(实时 ILogStream)\n• 关于命令与帮助菜单"
                                           }
                                       ]
+                     },
+                     {
+                         "id":  "TeamPLT.Contracts",
+                         "name":  "平台契约层",
+                         "version":  "1.0.0",
+                         "publisher":  "TeamAAS",
+                         "kind":  "contract",
+                         "host":  "platform",
+                         "description":  "平台领域契约程序集(TeamPLT.Contracts.dll)的正规发布通道。契约全进程唯一,由 ContractRegistry 从 Runtime\\Contracts\\ 统一加载;扩展工程引用时必须 Private=false,不得把副本拷进自己的目录。平台 exe 不再内嵌契约,故全新环境靠安装本包(或出厂自愈副本)补齐。",
+                         "notes":  "契约层独立发布:更新它不必重编平台 exe。运行期 dll 被 CLR 锁定时会暂存 .pending,重启后生效。",
+                         "downloadUrl":  "packages/contracts/TeamPLT.Contracts/TeamPLT.Contracts-1.0.0.zip",
+                         "sha256":  "705e066cb0d4fbed911633a246de6f4a8ab680679c6f89c35bb735f497e67c4a",
+                         "size":  16139,
+                         "references":  [
+
+                                        ],
+                         "targetFramework":  "net48",
+                         "requiresHost":  "TeamPLT>=2.1.0",
+                         "arch":  [
+                                      "x64"
+                                  ],
+                         "dependencies":  [
+
+                                          ],
+                         "versions":  [
+                                          {
+                                              "version":  "1.0.0",
+                                              "downloadUrl":  "packages/contracts/TeamPLT.Contracts/TeamPLT.Contracts-1.0.0.zip",
+                                              "sha256":  "705e066cb0d4fbed911633a246de6f4a8ab680679c6f89c35bb735f497e67c4a",
+                                              "size":  16139,
+                                              "releasedAt":  "2026-09-25",
+                                              "status":  "stable",
+                                              "notes":  "契约层独立发布:更新它不必重编平台 exe。运行期 dll 被 CLR 锁定时会暂存 .pending,重启后生效。"
+                                          }
+                                      ]
                      }
                  ]
 }

BIN
packages/communication/Plugins.Plc.Mitsubishi/Plugins.Plc.Mitsubishi-1.0.1.zip


BIN
packages/communication/Plugins.Plc.OpcUa/Plugins.Plc.OpcUa-1.0.1.zip


BIN
packages/communication/Plugins.Plc.Siemens/Plugins.Plc.Siemens-1.0.1.zip


BIN
packages/contracts/TeamPLT.Contracts/TeamPLT.Contracts-1.0.0.zip


BIN
packages/platform/Ext.Communication/Ext.Communication-1.0.2.zip


+ 20 - 2
regen-index.ps1

@@ -142,12 +142,30 @@ $sha.Dispose()
 #   若同 id 各版本各占一条,平台按 id 取一条展示 —— 表现为"版本下拉只有最新一版",
 #   旧版本永远选不到。这里按 id 归并,并把顶层字段对齐到最高版本。
 # ---------------------------------------------------------------------------
+function Get-VersionKey([string]$v) {
+    $parsed = $null
+    if ([version]::TryParse($v, [ref]$parsed)) { return $parsed }
+    return [version]'0.0'
+}
+
 $byId = [ordered]@{}
 foreach ($e in $entries) {
     $id = [string]$e.id
     if ($byId.Contains($id)) {
-        $byId[$id].versions = @($byId[$id].versions) + @($e.versions)
-        if (-not $byId[$id].notes -and $e.notes) { $byId[$id].notes = $e.notes }
+        $cur = $byId[$id]
+        $mergedVersions = @($cur.versions) + @($e.versions)
+
+        # 顶层字段必须对齐到"更高的版本",而不是沿用先遇到的那条。
+        # dependencies / references / kind / description 等各版本可能不同 ——
+        # 例如 1.0.0 依赖后来废弃的契约包,1.0.1 改依赖新契约包。
+        # 若顶层留在旧版(文件序通常旧版在前),平台按 id 读到的就是旧依赖,
+        # 表现为"明明装了新版,却提示旧依赖未安装"。故版本更高时整体替换,再挂回累计版本列表。
+        if ((Get-VersionKey $e.version) -gt (Get-VersionKey $cur.version)) {
+            $cur = $e.PSObject.Copy()
+        }
+        $cur.versions = $mergedVersions
+        if (-not $cur.notes -and $e.notes) { $cur.notes = $e.notes }
+        $byId[$id] = $cur
     } else {
         $byId[$id] = $e
     }