dsh-luxar-embedded
DeepSeek Harness plugin for ESP-IDF and STM32CubeMX embedded development
- Stars
- 0
- Language
- JavaScript
- Created
- Sep 16, 2026
- Updated
- Sep 16, 2026
Introduction
dsh-luxar-embedded
LUXAR 嵌入式固件开发能力 → DeepSeek Harness 插件仓库。当前已实现 ESP32/ESP-IDF, 后续将以独立适配包加入 STM32 支持。
与 F:\LUXAR 完全隔离:这是一个独立 Git 仓库,插件包与测试环境都放这里。
目录结构
dsh-luxar-embedded/
├── packages/
│ ├── dsh-luxar-embedded-core/ # 公共生命周期 owner、Python 网关、数据种子与跨平台稳定契约
│ │ ├── gateway/ # 层 2 Python 网关(FastAPI /health + /rpc)
│ │ └── data-template/ # 公共数据种子(首次启动拷入 DSH 用户数据根)
│ ├── dsh-luxar-espidf/ # 当前 ESP-IDF 适配包(npm 包 + cordis patch + manifest)
│ │ ├── package.json
│ │ ├── cordis.patch.yml # 先激活公共 core,再激活 luxar-espidf 行
│ │ ├── dsh-plugin.json # 自定契约 manifest(暂不对齐 dsh-std)
│ │ ├── lib/ # TS/JS 插件代码(层 1 进程内工具 + 层 2 Python 网关桥)
│ │ └── test/ # 注册面、Loader、回放与网关验证
│ └── dsh-luxar-stm32/ # M0 STM32 骨架、bundle 与项目识别样例
├── scripts/
│ ├── start-test.cmd # 启动隔离测试实例(独立 DSH_HOME + 独立端口)
│ └── setup-plugin-links.cmd # 幂等重建插件可解析所需的两个 junction
├── .dsh/ # 测试实例的独立 DSH_HOME(gitignore,不提交)
└── README.md
命名与平台边界
- 总项目与仓库使用
dsh-luxar-embedded,这里的 embedded 明确表示“嵌入式系统”; - 当前 ESP-IDF 适配包继续使用
dsh-luxar-espidf,保持 3080 安装与 bundle 标识兼容; - STM32 支持将进入独立的
dsh-luxar-stm32包,不把 STM32 逻辑混入 ESP-IDF 包; - 一个工程只激活一个平台适配器;公共 core 用于复用实现,不表示工程同时支持 ESP 与 STM32;
embedding仅用于知识库向量化配置,不再表示插件集成状态。
运行模型(拟定)
- 层 1 · TS 进程内:
luxar_esp_toolchain/luxar_ports/luxar_esp_project_inspect/luxar_esp_project_create/luxar_esp_sdk_probe/luxar_esp_build/luxar_esp_flash(ctx.approval审批门) /luxar_monitor/luxar_logs_analyze/luxar_serial_read - 层 2 · Python 网关:
luxar_font_*/luxar_driver_*/luxar_pdf_read/luxar_knowledge_ingest/luxar_knowledge_search/luxar_chip_spec_draft/luxar_display_verify(保留 LUXAR Python 资产, Python 运行时 = LUXAR venv 解释器 +F:\LUXAR\src库代码的只读引用;数据层与 LUXAR 完全独立,见下文「数据自持」) - 复用 DSH 原生:判断只看功能、不看名字——LUXAR 同功能工具(无论同名与否)不搬、不重建,
直接用 DSH 原生(
workspace.*/agent.*→ fs/str-replace/搜索/todo/ask_user/goal/subagent/approval/jobs/storageDomain);luxar_前缀仅用于 DSH 原生没有对应物的 LUXAR 独有领域工具。
隔离测试实例
见 scripts/start-test.cmd 与仓库根 README 的“测试实例”说明:
- 独立
DSH_HOME(.dsh\),profile/会话/存储与当前C:\Users\41562\.dsh完全隔离; - 独立 web 端口(默认 4080)和层 2 网关端口(默认 18767),不与当前正式 web(3080)及其默认 8766 网关冲突;
- 共享只读运行时
F:\deepseek-harness\node_modules(junction),不重复下载任何包; - 插件加载期抛错只影响测试实例,不会波及正式 web。
M1 起插件已激活(luxar-espidf bundle)。若 .dsh\ 被重建,先跑
scripts\setup-plugin-links.cmd 重建三个本地包入口及 ESP 包内依赖 scope junction,
再 scripts\start-test.cmd --port 4080 启动;插件冒烟测试:
node packages\dsh-luxar-espidf\test\apply.test.mjs。
正式实例(3080)安装形态(M9 修复后)
正式 web GUI(C:\Users\41562\.dsh,3080)与 h3 同构安装。M0 之后 ESP 主插件
依赖公共 owner,因此升级源码时必须同时安装两个包:
dsh-luxar-embedded-core与dsh-luxar-espidf都实拷在profiles\node_modules\;公共包包含 lib/gateway/data-template,ESP 包包含 lib/client/cordis.patch.yml/dsh-plugin.json/package.json;@deepseek-ai/*靠上级profiles\node_modulesscope 解析,无需包内 node_modules);profiles\web\node_modules\dsh-luxar-espidf为 junction → profiles 副本(web 入口);profiles\web\package.json的dsh.profile.bundles含dsh-luxar-espidf;该 bundle 先插入luxar-embedded-core,再插入 ESP host/web/CLI 行,并由 profile patch 启用luxar-espidf-web。
改动插件后需重拷公共 core 和 profiles\node_modules\dsh-luxar-espidf(或改回 junction 联动)
并完整重启 3080 dsh 进程(bundle/client 进程级缓存)。运行时数据根 =
%DSH_HOME%\data\luxar-embedded(正式实例默认为
C:\Users\41562\.dsh\data\luxar-embedded);插件升级或重装不会删除数据。
真实流程测试(自动清理旧实例后启动 + 与模型对话)
隔离实例无 LLM 凭据(与正式 ~\.dsh 完全隔离),需三种方式之一提供
DEEPSEEK_API_KEY(start-test.cmd 自动处理):
- 当前控制台已设
DEEPSEEK_API_KEY→ 直接注入; - 仓库根放
.env.test(gitignored,一行DEEPSEEK_API_KEY=sk-...)→ 自动注入; - 都没有:实例照常启动,打开 http://127.0.0.1:4080 后在 Settings > Models
页粘贴 key(写入该实例自己的
.credentials.yaml,无需重启)。
:: 启动(默认端口 4080;双击 scripts\start-test.cmd 亦可,无参数自动用 4080,
:: 启动失败时窗口停留显示错误,不会一闪而过)
scripts\start-test.cmd --port 4080
CLI(专用 profile,无 GUI)
:: 走专用 CLI profile(不启动 web)
scripts\luxar.cmd toolchain
scripts\luxar.cmd ports
scripts\luxar.cmd inspect F:\proj\hello_world
scripts\luxar.cmd build :: 缺路径时使用当前 DSH 会话工作区
scripts\luxar.cmd build F:\proj [--allow-downloads]
scripts\luxar.cmd monitor COM3 10
scripts\luxar.cmd gateway-info
scripts\luxar.cmd --help
日常开发可完全不依赖 Web:luxar.cmd 由独立 luxar-espidf-cli Loader 行承载,
使用 DSH parseCmdline/appExit,不扫描 ctx.baseUrl,也不调用 process.exit。
CLI、模型工具与设置页调用相同 action;命令失败时脚本保留 dsh 的非零退出码,
适合在 CI 或批处理里直接判定成功/失败。
双击注意事项:dsh 默认监听 3080(正式 GUI 占着会 EADDRINUSE 秒崩),脚本已处理—— 不带
--port时自动补--port 4080。若目标端口已由同一 runtime 的旧dsh --profile web --port <port>测试实例占用,脚本会自动停止旧实例、等待端口释放 后再启动;若占用者不是目标 DSH 测试实例则安全拒绝误杀并退出。其他启动失败仍会 停在错误页(pause)。
浏览器打开 http://127.0.0.1:4080,把测试会话工作区设为
<repo>\.tmp\m2-hello(不要直接修改 ESP-IDF 安装目录中的示例),
然后按 J1 黄金路径依次操作:
调用 luxar_esp_toolchain→ 应返回F:\esp\v6.0.2\esp-idfv6.0.2。调用 luxar_esp_project_inspect 检查当前工程→ 应识别为 ESP-IDF 工程 hello_world。调用 luxar_esp_build 编译当前工程→ 首次构建必须成功。在 main\hello_world_main.c 中临时加入一个明确的 C 编译错误。再次调用 luxar_esp_build→ 构建必须失败,结果包含工程内文件、行号和可读诊断。修复刚才加入的编译错误,然后再次调用 luxar_esp_build→ 必须成功。调用 luxar_ports→ 返回串口列表,从中选择真实开发板串口。调用 luxar_esp_flash 烧录到 <真实串口>→ 第一次在审批框中拒绝,确认没有烧录。- 再次请求
luxar_esp_flash→ 第二次批准,确认烧录成功。 调用 luxar_monitor 采集 <真实串口> 日志 10 秒→ 返回真实设备日志。把刚才采集的日志交给 luxar_logs_analyze→ 返回故障模式分析。
以上模型工具名必须使用 luxar_...;点号形式仅作为旧输入兼容,不再用于测试说明。
工具清单(M1+M2+M3:层 1 全部 + 层 2 Python 网关)
页面 UI(DSH 原生 Settings 卡槽,项目 = 工作区)
web 客户端不再绘制固定浮层。打开 Settings > Plugins:
- LUXAR Embedded · ESP-IDF 原生页签显示工具链、串口终端和层 2 网关;网关不可达时可点“自动启动网关”,也可直接调用任一层 2 工具触发自动拉起;
- 串口终端会话由公共 core 持续持有,不因 Settings 页面刷新、切换或组件重挂载而关闭;再次进入页面会续接活动会话,只有用户点击“关闭”、平台卸载或真实串口/进程错误才结束。原有 Web“串口监控”卡片已删除,模型侧有界
luxar_monitor工具继续保留用于自动诊断和会话回放; - LUXAR Embedded · ESP-IDF 配置与“终端”“Agent 循环”一致,默认以原生下拉卡片收起;展开后可编辑 Embedding、MinerU 和 PDF 参数,并可分别点击“测试连接”:成功在按钮旁显示绿色“连接正常”,失败显示红色“失败”(悬停可看原因);设置通过 DSH
settingsScope持久化。知识库不需要填写路径,固定使用当前%DSH_HOME%\data\luxar-embedded\knowledge.lance; - 界面文案注册
settings.luxar的 zh/en 字典,会随 DSH 语言切换; Embedding API Key与MinerU Token通过remote.credentials写入凭据域,只读取“是否已配置”,不会进入设置响应或普通 JSON RPC 参数;连接测试同样只使用已保存凭据,新输入的密钥或 Token 需先保存。
项目 = DSH 会话工作区:luxar_esp_build / luxar_esp_flash / luxar_esp_project_inspect / luxar_monitor 的 path 都可省略 —— 缺省就是对当前 DSH 工作区操作(与 pwsh/fs 等原生工具同源),显式传绝对路径可覆盖。插件不再记录或展示跨对话的“当前工程”,避免旧目录泄漏到新会话。
数据经服务端 typert Remote 服务 luxar(ctx.remote.luxar.*)+ Connection RPC 通道实时获取,无需对话即可操作。浏览器端交互请开 http://127.0.0.1:4080 实际点击验收。
注意:测试实例要用真实串口/工具链能力,请用普通终端或双击
scripts\start-test.cmd启动(从 Harness Agent 沙箱会话拉起 node 会因沙箱限制出现spawn EPERM,只影响 枚举类子进程,正式使用不受影响)。改动客户端 bundle / 服务端代码后需完整重启 4080 进程(resolveMeta/客户端 bundle 有进程级缓存)。
层 1(进程内,无需额外服务):
| 工具 | 说明 | 审批 |
|---|---|---|
luxar_esp_toolchain | 工具链单一权威解析(configured→env→installer→search) | 无 |
luxar_ports | 串口枚举(PowerShell 合并两类来源) | 无 |
luxar_esp_project_inspect | 工程/CMake/目标芯片只读检查 | 无 |
luxar_esp_project_create | 使用已探测的 ESP-IDF 工具链创建新工程 | 无 |
luxar_esp_sdk_probe | 只读探测 SDK 头文件/API 及近似候选 | 无 |
luxar_esp_build | reconfigure+build 两段式编译;默认禁依赖下载;失败分类+诊断 | 无 |
luxar_esp_flash | 烧录到指定串口 | ask 审批门(tools/pre-execute,无通道自动拒绝) |
luxar_monitor | 有界采集串口日志 + 故障诊断(默认 10s) | 无 |
luxar_logs_analyze | 日志文本 ESP32 故障模式诊断(纯函数) | 无 |
luxar_serial_read | 有界原始串口读取(Windows .NET SerialPort) | 无 |
层 2(经仅监听 loopback 的本地 Python 网关;工具首次调用会自动拉起,通常无需手动启动):
:: 启动层 2 网关(复用 LUXAR venv,默认端口 8766)
scripts\start-gateway.cmd
/rpc 强制使用启动令牌;手工启动脚本会在 %DSH_HOME%\luxar-gateway.token
创建/复用随机令牌,插件调用自动携带。无令牌请求返回 HTTP 401。luxar_pdf_read
只允许读取本次调用的 DSH 会话工作区或显式工程根内的 PDF;luxar_knowledge_ingest
接收调用方提供的正文或结构化知识原子,不自行读取任意文件;
LUXAR_GATEWAY_ALLOWED_ROOTS 仅作为部署者可选的固定追加根,默认没有硬编码仓库路径。工具链与网关
子进程只继承操作系统、Python、ESP-IDF 和明确的非敏感路径变量,不继承模型供应商凭据。
gatewayUrl 默认只接受 http/https 回环地址(127.0.0.1、localhost、::1),
并拒绝凭据、路径、查询和片段;只有插件静态配置显式设置 allowRemoteGateway: true
时才能使用远端网关,面板设置不能自行放宽这条信任边界。
部署脚本也可用进程级 LUXAR_GATEWAY_URL 覆盖生效地址;该值经过相同 URL
校验并优先于持久化设置。仓库的 4080 测试脚本和独立 CLI 默认使用
http://127.0.0.1:18767,避免与 3080 正式实例的 8766 令牌域互相干扰。
luxar_pdf_read 在公共网关内完成允许根校验与 SHA-256 归档,原生 PDF/MinerU
解析固定交给一次性隔离 worker;worker 崩溃、超时或客户端断开只终止本次解析,
不会把长驻网关及其它路由一起拖垮。并发默认限制为 2,worker 基础超时为 120 秒;
启用 MinerU 时会保留其配置超时并增加 15 秒回收余量。
部署者可通过 LUXAR_PDF_MAX_CONCURRENCY(1–8)和
LUXAR_PDF_WORKER_TIMEOUT_SECONDS(5–7200)覆盖。网关 stdout/stderr 与
Python faulthandler 输出写入 %DSH_HOME%\data\luxar-embedded\logs\gateway.log,
达到 2 MiB 后轮转为 gateway.log.1。
Embedding/MinerU 密钥以 credential reference(默认 LUXAR_EMBEDDING_API_KEY、
LUXAR_MINERU_TOKEN)解析。它们只在宿主连接本机回环网关时通过专用请求头交付给对应
handler;即使静态配置允许远端 gatewayUrl,宿主也不会把密钥发往该地址。旧版
storageDomain 中若存在明文密钥,凭据 provider 可写时会一次性迁移并删除旧字段。
自动拉起的网关由公共 dsh-luxar-embedded-core 实例持有:平台适配器卸载不会留下失管句柄;公共 owner 卸载/HMR 会在 Windows 上执行
taskkill /T /F 并等待进程树退出,随后才完成 disposer;DSH 正常退出时也注册了
同步的尽力清理。已知限制:操作系统强制结束、断电或进程被不可捕获信号终止时,
Node 的 exit 回调无法运行,因而不能保证清理;这种异常退出后的残留网关会在下一次
启动时被健康检查识别为既有实例,而不会被新插件实例误认领或误杀。
| 工具 | 说明 | 审批 |
|---|---|---|
luxar_font_extract | 按控制器布局确定性取模,返回可嵌入头文件(只读) | 无 |
luxar_font_export | 取模并写入工程内头文件(写工程,无审批) | 无 |
luxar_driver_search | 本地驱动库词法检索(返回可用清单) | 无 |
luxar_driver_read | 读取驱动完整源码包(sha256 校验) | 无 |
luxar_pdf_read | 工程根 PDF 先按 SHA-256 归档到 %DSH_HOME%\data\luxar-embedded\pdfs,再从稳定副本解析;返回来源与归档路径 | 无 |
luxar_knowledge_ingest | 将调用方提供的正文或知识原子分块后写入共享 LanceDB;使用生效的 Embedding 配置,维度冲突时在写入前失败 | 无 |
luxar_knowledge_search | 使用当前生效 Embedding 配置检索共享 LanceDB,维度必须与非空库一致 | 无 |
luxar_chip_spec_draft | 起草芯片规格 YAML(写 %DSH_HOME%\data\luxar-embedded\chips;已存在拒绝覆盖) | 无 |
luxar_display_verify | 显示自检:重建帧 + 期望 crc32/sha256 比对 + 布局一致性 | 无 |
数据自持(M8):驱动库 / 外部知识库 / 芯片规格 / PDF 归档全部位于当前
%DSH_HOME%\data\luxar-embedded\,与插件安装目录及 F:\LUXAR 数据目录完全隔离。
驱动库由公共包内 data-template\ 种子(样本驱动
sh1106_1p3_landscape)自动初始化;知识库首次启动为空,首次入库时采用当前面板的
Embedding 模式和维度(也可选择 local_hash 离线嵌入);空库可随配置重建向量表并返回
空检索结果,非空库维度冲突则拒绝且不改数据;chips 供规格起草写入;pdfs 使用
完整内容 SHA-256 作为文件名,重复读取同一内容不会重复占用空间,源文件移动或删除后仍可用
工具返回的归档路径重读。原始路径仍属于工具调用参数并进入 DSH 会话记录。升级时会把
旧版 %DSH_HOME%\data\luxar-espidf 与插件 .luxar-data 中缺失的数据复制到新目录,既不覆盖新目录文件,也不删除旧副本。环境变量
LUXAR_DATA_ROOT / LUXAR_DRIVER_LIBRARY_ROOT / LUXAR_KNOWLEDGE_PATH /
LUXAR_CHIP_SPEC_DIR 可覆盖。演示知识库:verify-m3 用 .tmp\m3-knowledge.lance
(384 维,经 LUXAR_KNOWLEDGE_PATH/LUXAR_EMBEDDING_DIMENSIONS 指定)。
pdfs 是稳定原文归档,不是自动扫描的知识库源目录:仅复制 PDF 到该目录不会生成
LanceDB 索引。需要先用 luxar_pdf_read 解析,再把正文或知识原子交给
luxar_knowledge_ingest;luxar_pdf_read 会单独信任自己的归档根,因此归档副本不受
当前会话工作区白名单影响并可在后续会话中重读。
公共发布包的 files 明确包含 gateway/ 与 data-template/,并排除 Python 缓存文件。
分发验收会实际执行 npm pack、干净解包、自动拉起解包后的网关,并检查首次种子初始化,
不是只核对压缩包文件名。
安全探针:node packages\dsh-luxar-espidf\test\verify-security.mjs(恶意串口、无令牌 RPC、
PDF 越界读取、子进程凭据脱敏)。离线验证:node packages\dsh-luxar-espidf\test\apply.test.mjs(19 工具注册面 + 审批门 +
纯函数 + 层 2 端到端 + fail-closed),node packages\dsh-luxar-espidf\test\verify-m2.mjs
(真实构建),node packages\dsh-luxar-espidf\test\verify-m3.mjs(层 2 网关 11 断言)。
Phase 1 定向验证:verify-phase1.mjs(Config、真实 Cordis 卸载、动作校验和进程树清理)、
verify-package-distribution.mjs(打包分发)以及 verify-pdf-timeout.mjs(真实网关长 PDF,
运行约 63 秒)。Phase 2 生命周期验证:verify-phase2.mjs(真实 Cordis 两轮重载、
实例状态隔离、Domain 关闭/重开、两代自有网关进程清理)。
Phase 4 交付验证在插件目录执行 npm run verify:phase4:真实 Cordis Loader 挂载/卸载
实际 host entry、校验发布 manifest、恢复 snapshots/luxar-j1/session.v2.jsonl 的 11 轮
keyless J1 录制会话,并复跑客户端 Loader。npm run verify:typert-matrix 另行下载到系统
临时目录验证最低支持版 @deepseek-ai/dsh-typert-protocol@0.1.0-rc.6 与当前安装版的
公开 Remote/remoteMethods 契约,不改变插件依赖树。插件加载时还会自检全部 LUXAR
Remote 方法;不兼容会在 Loader 阶段直接给出缺失方法。
DSH 当前正式发布/加载入口是 package.json#dsh.bundle.patch。当前安装运行时没有提供可供
实现与校验的权威 dsh-std v0.15 manifest schema,因此 dsh-plugin.json#admission 明确记录
not-aligned 缺口和 2026-09-09 评估日期;在正式 schema 可用前,该文件不是加载依据。