# Python 图形节点

- 下文 MDTODO 来源属于遗留节点合同；恢复相关任务前按 `$unidesk-tasktree` 迁移。

## 当前权威来源

- HWLAB 源码：YAML 选中的 v0.3 源工作区内 `tools/hwlab-node.py`。
- 应用形态：单文件 Python/tkinter 图形应用：
  - 包含 Windows 托盘和自动重连；
  - 包含日志轮转和自更新。
- 本地状态：`%USERPROFILE%\.hwlab\config.json`、`state.json`、`logs\hwlab-node.log`、`update\`。
- 默认公共入口：`https://hwlab.pikapython.com`。
- 更新元数据：`GET /v1/hwlab-node/update?platform=windows&channel=stable&current=<version>`。
- 发布文件：`GET /v1/hwlab-node/download/hwlab-node.py`；替换前校验元数据给出的 SHA。
- 节点传输：主动出站连接 `wss://<origin>/v1/hwpod-node/ws`，完成注册和心跳。
- 节点操作合同：`hwpod-node-ops-v1`。

不要把版本号或 SHA 写入长期指令。每次操作从选中的运行面/源码重新读取。

## 桌面配置

- 当前应用配置：
  - 暴露 `serverUrl`、`nodeId` 和 `autoConnect`；
  - 暴露更新设置和日志设置；
  - 有意不接受 CLI 参数或 `HWLAB_*` 环境变量。

- Windows 原生解释器规则：

  - 从拥有 `%USERPROFILE%\.hwlab` 和托盘的同一交互登录上下文解析 `python.exe`；
  - 把选中的解释器路径写入权威节点配置/启动声明；
  - 使用 `python --version`、`Get-Command python` 和 tkinter 导入作为发现证据；
  - WSL `/usr/bin/python`、SSH 侧辅助解释器或隐藏服务账号不能作为运行时。

- 平台声明拥有：

  - 节点/通道和唯一 nodeId；
  - HWPOD 资源与能力绑定；
  - 允许的工作区根目录；
  - WebSocket/认证 Secret 来源引用；
  - 受管登录/启动策略；
  - Windows 解释器路径/版本和交互用户；
  - 项目管理 MDTODO 来源。
- 本地配置边界：
  - 只表达操作者偏好。

## 状态证据

### 状态采集命令

```powershell
$root = Join-Path $HOME ".hwlab"
[ordered]@{
  home = $HOME
  configExists = Test-Path (Join-Path $root "config.json")
  stateExists = Test-Path (Join-Path $root "state.json")
  logExists = Test-Path (Join-Path $root "logs\hwlab-node.log")
  interactiveShell = (Get-Process explorer -ErrorAction SilentlyContinue | Measure-Object).Count
} | ConvertTo-Json -Compress
```

- 配置和运行证据规则：

  - 只在需要时读取配置字段；
  - 对未来可能出现的 Secret 字段脱敏；
  - 注册/运行证据优先使用云端结果：
    - `node.health` 和 `node.version`；
    - `node.inventory` 和 `node.diagnostics`。

## 受控部署

- 部署入口：

  - 必须属于 YAML-first UniDesk CLI 命令族；
  - 不得由操作者手工拼接步骤；
  - 命令族必须提供有界的规划、状态和显式确认应用动作；
  - 命令族必须满足下列要求。

- 命令族要求：
  - 从权威 YAML/配置引用解析：
    - 节点/通道和 Windows 路由；
    - 交互用户、pythonPath 和运行目录；
    - 文件/更新入口、nodeId 和 SecretRefs；
    - 允许的工作区根和登录自启动策略；
  - 拒绝没有可解析且可达 `trans` 路由的目标；
  - 仅在 CLI 传输适配器内部使用 `trans`；
  - 写入前校验下载文件的 SHA；
  - 保证应用幂等，并报告：
    - 写入文件指纹和配置指纹；
    - 解释器版本和启动注册；
    - 进程/注册表状态和脱敏阻塞项；
  - 避免把图形应用作为短 SSH/trans 请求的子进程启动；
  - 保持交互式 Windows 用户会话：
    - 确保界面/托盘可见；
    - 区分“已安装”和“界面可见且已注册”。

- 命令族不存在时：

  - 只允许只读发现；
  - 人工下载只属于诊断；
  - 远端 PowerShell 写文件只属于诊断；
  - 临时计划任务和直接启动进程只属于诊断；
  - 上述操作都不是部署证据。

## 每次必须检查的缺口

- 必须检查选中的源码/版本，不得假设最新发布文件已经解决以下事项：

- 默认 nodeId 可能仍然绑定 D601。
- 工作区操作可能接受请求提供的绝对路径，但没有配置允许列表或包含性检查。
- 即使 cloud-api 支持 token，WebSocket 注册也可能仍然缺少节点凭据。
- 实际能力可能落后于云端合同，尤其是 apply-patch、UART 写入/JSON-RPC、Keil 和结构化阻塞项。
- 图形窗口关闭到托盘不等于登录持久化；非交互会话中的计划任务可能隐藏界面/托盘。
- 另一个任务、启动项或运行目录中可能仍有旧 Bun 运行器活动。

- 缺口处置：
  - 每个缺口必须分别暴露；
  - 不得增加本地兜底路径掩盖问题。

## 旧运行器漂移

- 旧运行器证据：

  - `bun.exe tools\hwpod-node.ts connect`；
  - 旧 IP/端口云端地址；
  - `hwpod-node-runtime`；
  - 旧计划任务名。

- 停止旧运行器前：

  - 比较 nodeId、云端地址、资源绑定和活动硬件任务；
  - 可能中断硬件操作的变更必须有明确维护窗口；
  - 变更必须遵循 `$unidesk-daddev` 流程。
