@seeed-studio/solution-cli 0.2.0 → 0.3.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.
- package/README.md +101 -48
- package/bin/cli.js +6 -0
- package/catalog/client-config.json +10 -0
- package/catalog/knowledge-core.json +1395 -57
- package/docs/cli-guide.md +264 -0
- package/lib/agent.js +6 -0
- package/lib/knowledge.js +217 -28
- package/package.json +4 -1
- package/skills/sensecraft/SKILL.md +16 -0
- package/skills/sensecraft/references/consult-and-select.md +86 -22
- package/skills/sensecraft/references/device-management.md +94 -0
- package/skills/sensecraft/references/hardware-bom.md +16 -16
- package/skills/sensecraft/references/secondary-development.md +87 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
# SenseCraft Solution CLI 使用与集成全景指南
|
|
2
|
+
*(SenseCraft Solution CLI & AI Agent Skill Guide)*
|
|
3
|
+
|
|
4
|
+
> **定位**:本文档专门面向**方案架构师、现场应用工程师 (FAE)、嵌入式开发者以及 AI Agent (Claude Code / Codex / Antigravity / Work Buddy)**,系统性说明 `@seeed-studio/solution-cli` 的独特应用场景、安装流程、各功能指令的具体使用方式以及核心产出物。
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 目录
|
|
9
|
+
|
|
10
|
+
1. [独特使用场景与核心价值](#1-独特使用场景与核心价值)
|
|
11
|
+
2. [安装与 Agent 技能挂载](#2-安装与-agent-技能挂载)
|
|
12
|
+
3. [核心功能、使用方法与具体产出](#3-核心功能使用方法与具体产出)
|
|
13
|
+
- [场景一:方案探索与工况诊断 (Hub Search)](#场景一方案探索与工况诊断-hub-search)
|
|
14
|
+
- [场景二:硬件产品规格与配件防呆评估 (Product & BOM)](#场景二硬件产品规格与配件防呆评估-product--bom)
|
|
15
|
+
- [场景三:设备状态感知与参数热修改 (Device Management)](#场景三设备状态感知与参数热修改-device-management)
|
|
16
|
+
- [场景四:自研模型替换与本地二次开发 (Secondary Dev)](#场景四自研模型替换与本地二次开发-secondary-dev)
|
|
17
|
+
4. [双轨运行机制:在线直连与离线托底](#4-双轨运行机制在线直连与离线托底)
|
|
18
|
+
5. [常见问题与环境自检 (Doctor)](#5-常见问题与环境自检-doctor)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 1. 独特使用场景与核心价值
|
|
23
|
+
|
|
24
|
+
在传统边缘物联网与 AI 项目落地过程中,开发者通常面临以下痛点:
|
|
25
|
+
- **方案选型盲目**:不清楚现场环境(集中还是分散、有无现有监控摄像头、有无市电)对硬件架构的致命影响;
|
|
26
|
+
- **配件采购踩坑**:工控机买回后发现电源电压不符(如 12V 误插 19V 算力板)、DC 插头尺寸不对(5.5x2.1mm 插不进 5.5x2.5mm)、M.2 接口插槽类型搞混(Key-M 固态插不进 Key-E Wi-Fi 槽);
|
|
27
|
+
- **参数变更成本高**:改个 MQTT Broker 地址或算法置信度阈值就需要重新编译镜像或重装整套系统;
|
|
28
|
+
- **AI Agent 缺乏边缘硬件感知**:纯大模型对话缺乏真实物理世界的接口约束,容易凭空编造不存在的硬件型号或非官方链接。
|
|
29
|
+
|
|
30
|
+
`@seeed-studio/solution-cli` 正是为解决这一系列问题而生,它具有三大独特角色:
|
|
31
|
+
1. **方案专家的现场诊断仪**:内置各大行业工况诊断知识库,不仅能搜方案,还能直接指导工程师向客户提出决定成本与物理拓扑的“黄金追问”;
|
|
32
|
+
2. **硬件采购防呆中枢**:内置物理规格匹配引擎,自动核算【必需配件】与【可选配件】,从源头阻断硬件返工;
|
|
33
|
+
3. **AI Agent 的物理世界触手**:一键将 SenseCraft Skill 注入到主流 AI Agent 宿主中,让 Agent 具备从方案咨询、BOM 选型到现场部署、参数热更的全生命周期驱动能力。
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 2. 安装与 Agent 技能挂载
|
|
38
|
+
|
|
39
|
+
### 2.1 一键免安装即时调用 (推荐)
|
|
40
|
+
无需全局安装,利用 `npx` 即可随时调用:
|
|
41
|
+
```bash
|
|
42
|
+
# 查看帮助与版本
|
|
43
|
+
npx @seeed-studio/solution-cli --help
|
|
44
|
+
|
|
45
|
+
# 交互式扫描并为本机所有 Agent 安装技能
|
|
46
|
+
npx @seeed-studio/solution-cli install
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### 2.2 全局安装
|
|
50
|
+
```bash
|
|
51
|
+
npm install -g @seeed-studio/solution-cli
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 2.3 跨 Agent 平台技能挂载
|
|
55
|
+
执行 `solution-cli install` 时,工具会自动检测本机存在的 Agent 宿主环境,并将 `sensecraft` Skill 和全套参考手册安全复制到对应目录:
|
|
56
|
+
|
|
57
|
+
| Agent 宿主平台 | 技能默认配置路径 | 支持能力 |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| **Claude Code** | `~/.claude/skills/sensecraft` | 完整方案咨询、工况诊断、BOM 生成、现场部署 |
|
|
60
|
+
| **Codex (OpenAI)** | `~/.agents/skills/sensecraft` 或 `~/.codex/skills/sensecraft` | 代码审查、参数重构、二次开发自动化 |
|
|
61
|
+
| **Google Antigravity (AGY)** | `~/.gemini/config/skills/sensecraft` | 端到端自主诊断、多 Agent 协同实施 |
|
|
62
|
+
| **Work Buddy / Workbody** | `~/.workbuddy/skills/sensecraft` | 桌面端交互、方案展示、一键部署联动 |
|
|
63
|
+
| **CodeBuddy** | `~/.codebuddy/skills/sensecraft` | 代码库配对开发与自研模型构建 |
|
|
64
|
+
|
|
65
|
+
**非交互式多选安装示例**:
|
|
66
|
+
```bash
|
|
67
|
+
# 同时为 Claude Code 和 Google Antigravity 部署技能,不弹窗确认
|
|
68
|
+
solution-cli install --agent claude,antigravity -y
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 3. 核心功能、使用方法与具体产出
|
|
74
|
+
|
|
75
|
+
### 场景一:方案探索与工况诊断 (Hub Search)
|
|
76
|
+
|
|
77
|
+
当工程师或客户提出模糊需求(如“想在农田做微气象监测”、“工厂产线想做划痕检测”)时使用。
|
|
78
|
+
|
|
79
|
+
#### 1. 执行命令
|
|
80
|
+
```bash
|
|
81
|
+
# 人类工程师阅读模式 (格式化终端高亮)
|
|
82
|
+
solution-cli hub search "农业"
|
|
83
|
+
|
|
84
|
+
# AI Agent 消费模式 (标准 JSON 格式的 Catalog DTO)
|
|
85
|
+
solution-cli hub search "跌倒检测" --json
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
#### 2. 产出物内容 (What it Outputs)
|
|
89
|
+
运行该命令可产出 4 项关键资产:
|
|
90
|
+
1. **方案业务说明与技术架构**:解释为何适合在端侧运行、本地处理延迟、数据不出本地的隐私保障;
|
|
91
|
+
2. **静默商业闭环出口**:自动为该方案生成带有安全追踪标记(`utm_source=sensecraft_agent`)的官方落地页与开发 Wiki;
|
|
92
|
+
3. **官方开源仓库地址**:提供官方维护的 GitHub 源码仓库,为二次开发预留出口;
|
|
93
|
+
4. **现场工况诊断提问指引 (Diagnostic Playbook)**:直接给出当前场景下**必须向客户确认的 2~3 个核心工况问题**及其背后的技术决断理由。
|
|
94
|
+
|
|
95
|
+
#### 3. 产出示例 (以“农业”搜索为例)
|
|
96
|
+
```text
|
|
97
|
+
🔍 Solutions Hub Search Results for "农业" (typesense):
|
|
98
|
+
|
|
99
|
+
1. [Reference Design] 农业环境监测可部署方案 | LoRaWAN 自建看板 (agri_env_monitor)
|
|
100
|
+
把 SenseCAP 土壤与空气传感器接到 Home Assistant 看板上,支持本地私有 ChirpStack 运行,断网可用。
|
|
101
|
+
预设模式: cloud, tts_local, chirpstack_local
|
|
102
|
+
现场工况诊断提问指引:
|
|
103
|
+
• 监测区域是集中式连栋温室大棚(百米级),还是大面积户外大田/果园(数公里级)?
|
|
104
|
+
(决断考量: 大棚内百米级可采用 RS485 总线;广域大田推荐 LoRaWAN 远距无线,配 SenseCAP M2 网关)
|
|
105
|
+
• 现场测点是否有 220V 市电供电,还是需要野外太阳能板/锂电池长续航供电?
|
|
106
|
+
(决断考量: 市电支持持续高频数据上报;无市电需选配支持休眠唤醒的超低功耗无线传感器)
|
|
107
|
+
• 需要监测哪些核心指标?仅空气温湿度,还是包括土壤剖面水肥墒情(水分/EC/pH)?
|
|
108
|
+
(决断考量: 决定是配置多合一微气象站,还是选配工业级土壤三参数探头与变送器)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
### 场景二:硬件产品规格与配件防呆评估 (Product & BOM)
|
|
114
|
+
|
|
115
|
+
当确定了方案,需要进入商务采购阶段、给客户出具设备清单时使用。
|
|
116
|
+
|
|
117
|
+
#### 1. 执行命令
|
|
118
|
+
```bash
|
|
119
|
+
# 1. 查询产品族详情与物理规格
|
|
120
|
+
solution-cli product query recomputer_j40 --json
|
|
121
|
+
|
|
122
|
+
# 2. 评估该产品族所需的官方配件与兼容性
|
|
123
|
+
solution-cli product accessories recomputer_j40 --json
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
#### 2. 产出物内容 (What it Outputs)
|
|
127
|
+
1. **精确分类的 BOM 清单**:
|
|
128
|
+
- **【必需配件 (REQUIRED)】**:没有该配件主机无法开机或无法运行(如专属电源适配器),附带选型理由;
|
|
129
|
+
- **【可选配件 (OPTIONAL)】**:根据工况选择的外设(如 NVMe 固态硬盘、Wi-Fi 模组、导轨安装卡扣、射频天线);
|
|
130
|
+
2. **物理兼容性安全评级**:
|
|
131
|
+
- `VERIFIED`(通过):电压、引脚、尺寸完全匹配;
|
|
132
|
+
- `REQUIRES_ADAPTER`(需转接):如 M.2 2242 规格装入 2280 卡槽需加铜柱;
|
|
133
|
+
- `INCOMPATIBLE`(不兼容/危险):严禁搭配,防止烧毁板卡。
|
|
134
|
+
|
|
135
|
+
#### 3. 产出示例 (以 reComputer J40 为例)
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"family_id": "recomputer_j40",
|
|
139
|
+
"physical_spec": {
|
|
140
|
+
"power_input": {
|
|
141
|
+
"connector": "dc_jack_5.5x2.5",
|
|
142
|
+
"voltage_v": 19.0,
|
|
143
|
+
"min_current_a": 4.74,
|
|
144
|
+
"polarity": "center_positive"
|
|
145
|
+
},
|
|
146
|
+
"m2_slots": [
|
|
147
|
+
{"key": "M", "size": "2280", "interface": "PCIe Gen4 x4 NVMe"},
|
|
148
|
+
{"key": "E", "size": "2230", "interface": "WiFi/BT"}
|
|
149
|
+
]
|
|
150
|
+
},
|
|
151
|
+
"accessories": {
|
|
152
|
+
"required": [
|
|
153
|
+
{
|
|
154
|
+
"sku": "313080684",
|
|
155
|
+
"name": "19V 4.74A 电源适配器 (5.5x2.5mm)",
|
|
156
|
+
"category": "REQUIRED",
|
|
157
|
+
"compatibility": { "status": "VERIFIED" },
|
|
158
|
+
"url": "https://www.seeedstudio.com/Power-Adapter-19V-4-74A-p-5573.html?utm_source=sensecraft_agent..."
|
|
159
|
+
}
|
|
160
|
+
],
|
|
161
|
+
"optional": [
|
|
162
|
+
{
|
|
163
|
+
"sku": "110991734",
|
|
164
|
+
"name": "M.2 2280 NVMe SSD 512GB",
|
|
165
|
+
"category": "OPTIONAL",
|
|
166
|
+
"compatibility": { "status": "VERIFIED" }
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
### 场景三:设备状态感知与参数热修改 (Device Management)
|
|
176
|
+
|
|
177
|
+
当方案已经在现场或测试架部署完毕,需要调整运行参数(如更换 MQTT Broker、调整告警置信度阈值)时使用。
|
|
178
|
+
|
|
179
|
+
#### 1. 核心流程与接口
|
|
180
|
+
系统支持**无需重新编译、无需重装整套系统**的零重启参数热修改:
|
|
181
|
+
1. **查询当前设备活跃部署**:
|
|
182
|
+
`GET http://<host>:5823/api/device-management/active`
|
|
183
|
+
2. **查询可修改参数**:
|
|
184
|
+
`GET http://<host>:5823/api/docker-devices/local/config/<solution_id>`
|
|
185
|
+
检查参数字段中的 `reconfigurable: true` 标记。
|
|
186
|
+
3. **提交热更新**:
|
|
187
|
+
`PUT http://<host>:5823/api/docker-devices/local/config/<solution_id>`
|
|
188
|
+
传入目标键值,容器环境无感热加载生效。
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
### 场景四:自研模型替换与本地二次开发 (Secondary Dev)
|
|
193
|
+
|
|
194
|
+
当官方自带的模型无法满足客户特殊工况(如需要自研模型、特殊缺陷检测、修改前端大屏 UI)时使用。
|
|
195
|
+
|
|
196
|
+
#### 1. 开发闭环步骤
|
|
197
|
+
1. **克隆源码**:
|
|
198
|
+
从 `solution-cli hub search` 返回的 `repo_url` 将源码克隆到本地用户工作区:
|
|
199
|
+
```bash
|
|
200
|
+
git clone https://github.com/suharvest/sensecraft-solutions.git ./my-solutions
|
|
201
|
+
```
|
|
202
|
+
2. **端侧模型转换 (以 Jetson Orin 为例)**:
|
|
203
|
+
在设备上使用 TensorRT 将自定义 ONNX 导出为 Engine:
|
|
204
|
+
```bash
|
|
205
|
+
/usr/src/tensorrt/bin/trtexec --onnx=my_model.onnx --saveEngine=my_model.engine --fp16
|
|
206
|
+
```
|
|
207
|
+
3. **覆盖挂载配置**:
|
|
208
|
+
在方案目录创建 `docker-compose.override.yml` 将本地自研模型映射进容器中。
|
|
209
|
+
4. **驱动本地快速联调**:
|
|
210
|
+
使用 `--solutions-dir` 参数,强制底层引擎加载本地修改版方案,彻底不碰官方缓存:
|
|
211
|
+
```bash
|
|
212
|
+
sensecraft-engine deploy --solution fall_detection --solutions-dir ./my-solutions/solutions
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## 4. 双轨运行机制:在线直连与离线托底
|
|
218
|
+
|
|
219
|
+
为了保证在各类严苛现场环境下均能稳定运行,CLI 实现了智能双轨架构:
|
|
220
|
+
|
|
221
|
+
```mermaid
|
|
222
|
+
flowchart TD
|
|
223
|
+
RunCmd["用户 / Agent 触发 CLI 命令"] --> NetCheck{"检查网络与凭证"}
|
|
224
|
+
NetCheck -- "有外网且含烘焙配置" --> Typesense["直连 Seeed Typesense 云端搜索集群"]
|
|
225
|
+
Typesense -- "返回最新上线方案与配件" --> Done["输出 Catalog DTO"]
|
|
226
|
+
NetCheck -- "纯内网 / 无凭证 / 超时" --> LocalCore["无感降级: 读取 catalog/knowledge-core.json"]
|
|
227
|
+
LocalCore -- "331 KB 本地知识库 (18场景/39方案/119硬件)" --> Done
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
1. **在线实时模式 (Online Live)**:
|
|
231
|
+
- 采用安全方案 B 在构建发布期烘焙了公开的只读 Search-Only 凭证;
|
|
232
|
+
- 自动直连 `https://rel-search.seeedstudio.com`,实时获取最新的方案、Wiki、案例及商城 SKU;
|
|
233
|
+
2. **离线安全托底 (Offline Resilience)**:
|
|
234
|
+
- 打包了全量预生成的 `catalog/knowledge-core.json`(331 KB);
|
|
235
|
+
- 在军工、内网、无公网或云端响应超过 2.5 秒时,**自动毫秒级无感降级到本地内核**,工况诊断、BOM 评估与离线部署 100% 正常可用。
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## 5. 常见问题与环境自检 (Doctor)
|
|
240
|
+
|
|
241
|
+
### 1. 运行自检工具
|
|
242
|
+
在部署前或遇到环境异常时,执行:
|
|
243
|
+
```bash
|
|
244
|
+
solution-cli doctor
|
|
245
|
+
```
|
|
246
|
+
工具将逐项检测并给出修复指引:
|
|
247
|
+
- `OS Platform`: 确认宿主机操作系统及架构是否支持;
|
|
248
|
+
- `Docker Daemon`: 确认 Docker 服务是否正常运行;
|
|
249
|
+
- `Serial / Dialout Permissions`: 确认串口访问权限;
|
|
250
|
+
- `SenseCraft Engine`: 确认底座引擎完整性与版本;
|
|
251
|
+
- `Ledger Integrity`: 校验技能安装账本状态。
|
|
252
|
+
|
|
253
|
+
### 2. 状态查询
|
|
254
|
+
```bash
|
|
255
|
+
solution-cli status
|
|
256
|
+
```
|
|
257
|
+
实时查看当前 Engine 所在路径、安装版本、本地 Content 方案缓存数量以及各大 Agent 的配置状态。
|
|
258
|
+
|
|
259
|
+
### 3. 干净卸载
|
|
260
|
+
如需从某个 Agent 中移除 SenseCraft 技能:
|
|
261
|
+
```bash
|
|
262
|
+
solution-cli uninstall --agent claude,antigravity
|
|
263
|
+
```
|
|
264
|
+
工具将依据安装账本(`~/.sensecraft/skills-ledger.json`)仅删除工具自身写入的文件,绝不误删用户自定义创建的技能。
|
package/lib/agent.js
CHANGED
|
@@ -54,6 +54,12 @@ export function getKnownAgents() {
|
|
|
54
54
|
}
|
|
55
55
|
return path.join(home, '.codebuddy', 'skills');
|
|
56
56
|
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
id: 'antigravity',
|
|
60
|
+
name: 'Google Antigravity (AGY)',
|
|
61
|
+
homeDirs: [path.join(home, '.gemini', 'config'), path.join(home, '.gemini', 'antigravity-cli')],
|
|
62
|
+
getSkillsDir: () => path.join(home, '.gemini', 'config', 'skills')
|
|
57
63
|
}
|
|
58
64
|
];
|
|
59
65
|
}
|
package/lib/knowledge.js
CHANGED
|
@@ -12,6 +12,44 @@ const DATA_FILE = path.join(__dirname, '..', 'catalog', 'knowledge-core.json');
|
|
|
12
12
|
|
|
13
13
|
let cachedKnowledgeCore = null;
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Appends UTM tracking parameters to a URL while preserving existing query parameters.
|
|
17
|
+
*
|
|
18
|
+
* @param {string} urlStr - Target URL
|
|
19
|
+
* @param {Object} utmParams
|
|
20
|
+
* @param {string} [utmParams.source='sensecraft_agent']
|
|
21
|
+
* @param {string} [utmParams.medium='solution_consult']
|
|
22
|
+
* @param {string} [utmParams.campaign='']
|
|
23
|
+
* @param {string} [utmParams.content='']
|
|
24
|
+
* @returns {string} URL with appended UTM parameters
|
|
25
|
+
*/
|
|
26
|
+
export function appendUtm(urlStr, {
|
|
27
|
+
source = 'sensecraft_agent',
|
|
28
|
+
medium = 'solution_consult',
|
|
29
|
+
campaign = '',
|
|
30
|
+
content = '',
|
|
31
|
+
} = {}) {
|
|
32
|
+
if (!urlStr || typeof urlStr !== 'string') return urlStr || '';
|
|
33
|
+
try {
|
|
34
|
+
const url = new URL(urlStr);
|
|
35
|
+
if (!url.searchParams.has('utm_source') && source) {
|
|
36
|
+
url.searchParams.set('utm_source', source);
|
|
37
|
+
}
|
|
38
|
+
if (!url.searchParams.has('utm_medium') && medium) {
|
|
39
|
+
url.searchParams.set('utm_medium', medium);
|
|
40
|
+
}
|
|
41
|
+
if (!url.searchParams.has('utm_campaign') && campaign) {
|
|
42
|
+
url.searchParams.set('utm_campaign', campaign);
|
|
43
|
+
}
|
|
44
|
+
if (!url.searchParams.has('utm_content') && content) {
|
|
45
|
+
url.searchParams.set('utm_content', content);
|
|
46
|
+
}
|
|
47
|
+
return url.toString();
|
|
48
|
+
} catch {
|
|
49
|
+
return urlStr;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
15
53
|
/**
|
|
16
54
|
* Loads the bundled offline knowledge core file.
|
|
17
55
|
*
|
|
@@ -62,6 +100,28 @@ function fetchJson(urlStr, headers = {}, timeoutMs = 2500) {
|
|
|
62
100
|
});
|
|
63
101
|
}
|
|
64
102
|
|
|
103
|
+
const CONFIG_FILE = path.resolve(__dirname, '../catalog/client-config.json');
|
|
104
|
+
let cachedClientConfig = null;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Loads build-time baked client configuration if present.
|
|
108
|
+
*
|
|
109
|
+
* @returns {Object|null}
|
|
110
|
+
*/
|
|
111
|
+
export function loadClientConfig() {
|
|
112
|
+
if (cachedClientConfig) return cachedClientConfig;
|
|
113
|
+
try {
|
|
114
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
115
|
+
const raw = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
116
|
+
cachedClientConfig = JSON.parse(raw);
|
|
117
|
+
return cachedClientConfig;
|
|
118
|
+
}
|
|
119
|
+
} catch {
|
|
120
|
+
// Graceful fallback if missing or invalid
|
|
121
|
+
}
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
|
|
65
125
|
/**
|
|
66
126
|
* Searches Seeed Solutions Hub scenarios and reference designs.
|
|
67
127
|
*
|
|
@@ -73,34 +133,125 @@ function fetchJson(urlStr, headers = {}, timeoutMs = 2500) {
|
|
|
73
133
|
*/
|
|
74
134
|
export async function searchHub({ query = '', locale = 'zh', limit = 5 } = {}) {
|
|
75
135
|
const qLower = (query || '').toLowerCase().trim();
|
|
76
|
-
const
|
|
77
|
-
const host = process.env.TYPESENSE_HOST || 'https://rel-search.seeedstudio.com';
|
|
136
|
+
const clientConfig = loadClientConfig();
|
|
137
|
+
const host = process.env.TYPESENSE_HOST || clientConfig?.typesense?.host || 'https://rel-search.seeedstudio.com';
|
|
138
|
+
const keySolution = process.env.TYPESENSE_SEARCH_KEY_SOLUTION || process.env.TYPESENSE_SEARCH_KEY || clientConfig?.typesense?.search_key_solution;
|
|
139
|
+
const keyRefDesign = process.env.TYPESENSE_SEARCH_KEY_REFERENCE_DESIGN || process.env.TYPESENSE_SEARCH_KEY || clientConfig?.typesense?.search_key_reference_design;
|
|
78
140
|
|
|
79
|
-
// Attempt online Typesense search if
|
|
80
|
-
if (
|
|
141
|
+
// Attempt online Typesense search if keys are provided and not explicitly running offline
|
|
142
|
+
if ((keySolution || keyRefDesign) && !process.env.SENSECRAFT_OFFLINE_ONLY) {
|
|
81
143
|
try {
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
144
|
+
const core = loadKnowledgeCore();
|
|
145
|
+
const onlinePromises = [];
|
|
146
|
+
|
|
147
|
+
if (keySolution) {
|
|
148
|
+
const solUrl = `${host}/collections/Solution/documents/search?q=${encodeURIComponent(query)}&query_by=title_zh_hans,title_en,excerpt_zh_hans,excerpt_en,display_tags_zh_hans&per_page=${limit}`;
|
|
149
|
+
onlinePromises.push(
|
|
150
|
+
fetchJson(solUrl, { 'X-TYPESENSE-API-KEY': keySolution }, 2500)
|
|
151
|
+
.then((data) => ({ type: 'scenario', hits: data?.hits || [] }))
|
|
152
|
+
.catch(() => ({ type: 'scenario', hits: [] }))
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (keyRefDesign) {
|
|
157
|
+
const rdUrl = `${host}/collections/reference_design/documents/search?q=${encodeURIComponent(query)}&query_by=name_zh_hans,name_en,summary_zh_hans,summary_en,tags&per_page=${limit}`;
|
|
158
|
+
onlinePromises.push(
|
|
159
|
+
fetchJson(rdUrl, { 'X-TYPESENSE-API-KEY': keyRefDesign }, 2500)
|
|
160
|
+
.then((data) => ({ type: 'reference_design', hits: data?.hits || [] }))
|
|
161
|
+
.catch(() => ({ type: 'reference_design', hits: [] }))
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const results = await Promise.all(onlinePromises);
|
|
166
|
+
const onlineRecords = [];
|
|
167
|
+
|
|
168
|
+
for (const res of results) {
|
|
169
|
+
if (res.type === 'scenario') {
|
|
170
|
+
for (const hit of res.hits) {
|
|
171
|
+
const doc = hit.document || {};
|
|
172
|
+
const docId = doc.id || doc.slug;
|
|
173
|
+
const title = locale === 'en'
|
|
174
|
+
? (doc.title_en || doc.title_zh_hans || docId)
|
|
175
|
+
: (doc.title_zh_hans || doc.title_en || docId);
|
|
176
|
+
const summary = locale === 'en'
|
|
177
|
+
? (doc.excerpt_en || doc.seo_description_en || doc.excerpt_zh_hans || '')
|
|
178
|
+
: (doc.excerpt_zh_hans || doc.seo_description_zh_hans || doc.excerpt_en || '');
|
|
179
|
+
const tags = (locale === 'en' ? doc.display_tags_en : doc.display_tags_zh_hans) || doc.display_tags || [];
|
|
180
|
+
const pb = core.diagnostic_playbooks?.[docId] || doc.diagnostic_playbook || null;
|
|
181
|
+
|
|
182
|
+
onlineRecords.push({
|
|
183
|
+
type: 'scenario',
|
|
184
|
+
id: docId,
|
|
185
|
+
title,
|
|
186
|
+
summary,
|
|
187
|
+
tags,
|
|
188
|
+
family_ids: doc.family_ids || [],
|
|
189
|
+
reference_designs: doc.reference_designs || [],
|
|
190
|
+
landing_url: appendUtm(`https://www.seeedstudio.com/solutions/${docId}`, {
|
|
191
|
+
source: 'sensecraft_agent',
|
|
192
|
+
medium: 'solution_consult',
|
|
193
|
+
campaign: docId,
|
|
194
|
+
content: 'scenario_landing',
|
|
195
|
+
}),
|
|
196
|
+
repo_url: '',
|
|
197
|
+
diagnostic_playbook: pb,
|
|
198
|
+
source: 'typesense',
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
} else if (res.type === 'reference_design') {
|
|
202
|
+
for (const hit of res.hits) {
|
|
203
|
+
const doc = hit.document || {};
|
|
204
|
+
const docId = doc.id;
|
|
205
|
+
const title = locale === 'en'
|
|
206
|
+
? (doc.name_en || doc.name_zh_hans || docId)
|
|
207
|
+
: (doc.name_zh_hans || doc.name_en || docId);
|
|
208
|
+
const summary = locale === 'en'
|
|
209
|
+
? (doc.summary_en || doc.tagline_en || doc.summary_zh_hans || '')
|
|
210
|
+
: (doc.summary_zh_hans || doc.tagline_zh_hans || doc.summary_en || '');
|
|
211
|
+
|
|
212
|
+
let pb = doc.diagnostic_playbook || null;
|
|
213
|
+
if (!pb) {
|
|
214
|
+
for (const sc of core.scenarios || []) {
|
|
215
|
+
if ((sc.reference_designs || []).includes(docId)) {
|
|
216
|
+
pb = sc.diagnostic_playbook || core.diagnostic_playbooks?.[sc.id] || null;
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
onlineRecords.push({
|
|
223
|
+
type: 'reference_design',
|
|
224
|
+
id: docId,
|
|
225
|
+
title,
|
|
226
|
+
summary,
|
|
227
|
+
presets: doc.presets || [],
|
|
228
|
+
landing_url: appendUtm(`https://www.seeedstudio.com/solutions/reference-designs/${docId}`, {
|
|
229
|
+
source: 'sensecraft_agent',
|
|
230
|
+
medium: 'solution_consult',
|
|
231
|
+
campaign: docId,
|
|
232
|
+
content: 'solution_landing',
|
|
233
|
+
}),
|
|
234
|
+
wiki_url: doc.wiki_url ? appendUtm(doc.wiki_url, {
|
|
235
|
+
source: 'sensecraft_agent',
|
|
236
|
+
medium: 'tech_wiki',
|
|
237
|
+
campaign: docId,
|
|
238
|
+
}) : '',
|
|
239
|
+
repo_url: doc.repo_url || `https://github.com/suharvest/sensecraft-solutions/tree/main/solutions/${docId}`,
|
|
240
|
+
diagnostic_playbook: pb,
|
|
241
|
+
source: 'typesense',
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (onlineRecords.length > 0) {
|
|
97
248
|
return createCatalogDto({
|
|
98
249
|
source: 'typesense',
|
|
99
250
|
freshness: 'FRESH',
|
|
100
|
-
records:
|
|
251
|
+
records: onlineRecords.slice(0, limit),
|
|
101
252
|
});
|
|
102
253
|
}
|
|
103
|
-
} catch
|
|
254
|
+
} catch {
|
|
104
255
|
// Graceful fallback to offline core with notice
|
|
105
256
|
}
|
|
106
257
|
}
|
|
@@ -133,6 +284,14 @@ export async function searchHub({ query = '', locale = 'zh', limit = 5 } = {}) {
|
|
|
133
284
|
tags: s.tags || [],
|
|
134
285
|
family_ids: s.family_ids || [],
|
|
135
286
|
reference_designs: s.reference_designs || [],
|
|
287
|
+
landing_url: appendUtm(s.landing_url || `https://www.seeedstudio.com/solutions/${s.id}`, {
|
|
288
|
+
source: 'sensecraft_agent',
|
|
289
|
+
medium: 'solution_consult',
|
|
290
|
+
campaign: s.id,
|
|
291
|
+
content: 'scenario_landing',
|
|
292
|
+
}),
|
|
293
|
+
repo_url: s.repo_url || '',
|
|
294
|
+
diagnostic_playbook: s.diagnostic_playbook || null,
|
|
136
295
|
score,
|
|
137
296
|
});
|
|
138
297
|
}
|
|
@@ -156,7 +315,19 @@ export async function searchHub({ query = '', locale = 'zh', limit = 5 } = {}) {
|
|
|
156
315
|
title: rd.title?.[locale] || rd.title?.zh || rd.title?.en || rd.id,
|
|
157
316
|
summary: rd.summary?.[locale] || rd.summary?.zh || rd.summary?.en || '',
|
|
158
317
|
presets: rd.presets || [],
|
|
159
|
-
|
|
318
|
+
landing_url: appendUtm(rd.landing_url || `https://www.seeedstudio.com/solutions/reference-designs/${rd.id}`, {
|
|
319
|
+
source: 'sensecraft_agent',
|
|
320
|
+
medium: 'solution_consult',
|
|
321
|
+
campaign: rd.id,
|
|
322
|
+
content: 'solution_landing',
|
|
323
|
+
}),
|
|
324
|
+
wiki_url: rd.wiki_url ? appendUtm(rd.wiki_url, {
|
|
325
|
+
source: 'sensecraft_agent',
|
|
326
|
+
medium: 'tech_wiki',
|
|
327
|
+
campaign: rd.id,
|
|
328
|
+
}) : '',
|
|
329
|
+
repo_url: rd.repo_url || `https://github.com/suharvest/sensecraft-solutions/tree/main/solutions/${rd.id}`,
|
|
330
|
+
diagnostic_playbook: rd.diagnostic_playbook || null,
|
|
160
331
|
score,
|
|
161
332
|
});
|
|
162
333
|
}
|
|
@@ -172,9 +343,9 @@ export async function searchHub({ query = '', locale = 'zh', limit = 5 } = {}) {
|
|
|
172
343
|
source: 'bundled_manifest',
|
|
173
344
|
freshness: 'FRESH',
|
|
174
345
|
records: combined,
|
|
175
|
-
warnings:
|
|
176
|
-
? ['Online Typesense request timed out
|
|
177
|
-
: ['No Typesense API key configured. Displaying verified local catalog.'],
|
|
346
|
+
warnings: (keySolution || keyRefDesign)
|
|
347
|
+
? ['Online Typesense request timed out or returned no hits. Displaying verified local catalog.']
|
|
348
|
+
: ['No Typesense API key configured or baked. Displaying verified local catalog.'],
|
|
178
349
|
});
|
|
179
350
|
}
|
|
180
351
|
|
|
@@ -208,7 +379,15 @@ export function queryProductFamily(familyId, { locale = 'zh' } = {}) {
|
|
|
208
379
|
default_sku: family.default_sku,
|
|
209
380
|
regions: family.regions || [],
|
|
210
381
|
skus_count: (family.skus || []).length,
|
|
211
|
-
skus: (family.skus || []).slice(0, 10)
|
|
382
|
+
skus: (family.skus || []).slice(0, 10).map((s) => ({
|
|
383
|
+
...s,
|
|
384
|
+
url: appendUtm(s.url, {
|
|
385
|
+
source: 'sensecraft_agent',
|
|
386
|
+
medium: 'bom_recommendation',
|
|
387
|
+
campaign: family.id,
|
|
388
|
+
content: `sku_${s.sku}`,
|
|
389
|
+
}),
|
|
390
|
+
})),
|
|
212
391
|
physical_spec: family.physical_spec || null,
|
|
213
392
|
required_accessories_count: (family.required_accessories || []).length,
|
|
214
393
|
optional_accessories_count: (family.optional_accessories || []).length,
|
|
@@ -248,7 +427,12 @@ export function queryAccessories(familyId, { sku = null, locale = 'zh' } = {}) {
|
|
|
248
427
|
id: acc.id,
|
|
249
428
|
name: acc.name,
|
|
250
429
|
sku: acc.sku,
|
|
251
|
-
url: acc.url,
|
|
430
|
+
url: appendUtm(acc.url, {
|
|
431
|
+
source: 'sensecraft_agent',
|
|
432
|
+
medium: 'bom_recommendation',
|
|
433
|
+
campaign: family.id,
|
|
434
|
+
content: `required_${acc.id}`,
|
|
435
|
+
}),
|
|
252
436
|
qty: acc.qty || 1,
|
|
253
437
|
reason: acc.reason || 'Required for standard operation',
|
|
254
438
|
applies_when: acc.applies_when || null,
|
|
@@ -268,7 +452,12 @@ export function queryAccessories(familyId, { sku = null, locale = 'zh' } = {}) {
|
|
|
268
452
|
id: acc.id,
|
|
269
453
|
name: acc.name,
|
|
270
454
|
sku: acc.sku,
|
|
271
|
-
url: acc.url,
|
|
455
|
+
url: appendUtm(acc.url, {
|
|
456
|
+
source: 'sensecraft_agent',
|
|
457
|
+
medium: 'bom_recommendation',
|
|
458
|
+
campaign: family.id,
|
|
459
|
+
content: `optional_${acc.id}`,
|
|
460
|
+
}),
|
|
272
461
|
type: acc.type || 'peripheral',
|
|
273
462
|
compatibility: {
|
|
274
463
|
is_compatible: comp.isCompatible,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seeed-studio/solution-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Zero-friction installer and CLI runner for SenseCraft Engine and AI Agent Skills (Work Buddy, Claude Code, Codex, CodeBuddy)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/installer.js",
|
|
@@ -19,9 +19,12 @@
|
|
|
19
19
|
"lib",
|
|
20
20
|
"catalog",
|
|
21
21
|
"skills",
|
|
22
|
+
"docs",
|
|
22
23
|
"README.md"
|
|
23
24
|
],
|
|
24
25
|
"scripts": {
|
|
26
|
+
"build": "node scripts/bake-client-config.mjs",
|
|
27
|
+
"prepack": "node scripts/bake-client-config.mjs",
|
|
25
28
|
"test": "node --test tests/cli.test.mjs",
|
|
26
29
|
"install:self": "node bin/cli.js install",
|
|
27
30
|
"status": "node bin/cli.js status",
|
|
@@ -17,6 +17,8 @@ Do NOT read all reference files at once. Determine the user's workflow state and
|
|
|
17
17
|
| **PROCUREMENT / VERIFY_BOM**<br>“买什么硬件?”、“J4012 需要配什么配件?” | `references/hardware-bom.md` | `solution-cli product accessories <id> --json` | **DO NOT fabricate** third-party SKUs or prices. Always distinguish REQUIRED vs OPTIONAL accessories. |
|
|
18
18
|
| **ONBOARDING / PRECHECK**<br>“设备到了,插上了网线/USB”、“环境自检” | `references/diagnose.md` | `solution-cli doctor` / `sensecraft-engine device scan` | Freeze hardware requirements into DeploymentLockfile before proceeding to apply. |
|
|
19
19
|
| **DEPLOYING / APPLY**<br>“开始安装”、“部署 fall_detection” | `references/deploy.md` | `sensecraft-engine deploy --solution <id>` | **DEPLOYMENT CRITICAL SECTION**: Zero external commercial queries allowed during apply. |
|
|
20
|
+
| **MANAGE / RECONFIG**<br>“改一下 MQTT 地址”、“查看已安装应用”、“重启服务”、“修改配置” | `references/device-management.md` | `curl BASE/api/docker-devices/local/config/<id>` | **Check before write**: Only alter `reconfigurable: true` fields; check current value before modifying. |
|
|
21
|
+
| **CUSTOMIZE / SECONDARY_DEV**<br>“我想改源码”、“换成自研模型”、“改前端看板”、“GitHub 仓库” | `references/secondary-development.md` | `git clone <repo_url>` / `sensecraft-engine --solutions-dir` | **Never edit cached content**: Clone to user workspace, pair-program, test locally with `--solutions-dir`. |
|
|
20
22
|
| **TROUBLESHOOTING**<br>“部署报错”、“黑屏”、“无视频流” | `references/error-catalog.md` | `sensecraft-engine logs` / `solution-cli product verify-compatibility` | Max 3 fix-and-retry rounds. Follow local auto-patching rule. |
|
|
21
23
|
|
|
22
24
|
Capabilities that need the **SenseCraft Solution desktop app** (editing a
|
|
@@ -86,6 +88,20 @@ daemon is a host prerequisite, not evidence that a deployment has passed.
|
|
|
86
88
|
6. **Temp files:** keep request bodies and scratch files in the current
|
|
87
89
|
working directory under `./.sensecraft-work/`, never in `/tmp`. Remove the
|
|
88
90
|
directory when the task ends, also after a failure.
|
|
91
|
+
7. **Conversational tone & soft referral:** Agent is an IoT domain expert and
|
|
92
|
+
answers technical, business, hardware, and configuration questions directly
|
|
93
|
+
and thoroughly using local knowledge and tools. Do NOT dump raw link lists
|
|
94
|
+
or write pushy sales pitches. External links (`landing_url`, `wiki_url`,
|
|
95
|
+
product purchase URLs, `repo_url`) must be smoothly integrated as
|
|
96
|
+
supplemental reading / procurement / code exploration. All URLs generated by
|
|
97
|
+
`solution-cli` automatically carry silent UTM parameters
|
|
98
|
+
(`utm_source=sensecraft_agent`) for analytics attribution.
|
|
99
|
+
8. **Proactive diagnosis & domain-specific questioning:** During solution consultation,
|
|
100
|
+
Agent must avoid one-way monologues. Proactively inspect the `diagnostic_playbook`
|
|
101
|
+
returned by `solution-cli hub search` (or cross-reference `references/consult-and-select.md` §3).
|
|
102
|
+
Ask 2–3 targeted domain questions explaining the engineering rationale (topology,
|
|
103
|
+
asset reuse, power/cabling, inspection speed/materials) to help the user converge
|
|
104
|
+
on the optimal hardware architecture and budget.
|
|
89
105
|
|
|
90
106
|
## Step 0 — Install the engine and the solutions (every task)
|
|
91
107
|
|