@seeed-studio/solution-cli 0.3.1 → 0.3.2
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 +18 -10
- package/bin/cli.js +103 -37
- package/bin/runner.js +1 -1
- package/docs/cli-guide.md +40 -12
- package/lib/agent.js +5 -5
- package/lib/detector.js +3 -3
- package/lib/installer.js +39 -11
- package/lib/ledger.js +1 -1
- package/package.json +3 -6
- package/skills/{sensecraft → solution-cli}/SKILL.md +22 -9
- package/skills/{sensecraft → solution-cli}/references/consult-and-select.md +4 -0
- /package/skills/{sensecraft → solution-cli}/references/app-only.md +0 -0
- /package/skills/{sensecraft → solution-cli}/references/deploy.md +0 -0
- /package/skills/{sensecraft → solution-cli}/references/device-management.md +0 -0
- /package/skills/{sensecraft → solution-cli}/references/diagnose.md +0 -0
- /package/skills/{sensecraft → solution-cli}/references/error-catalog.md +0 -0
- /package/skills/{sensecraft → solution-cli}/references/hardware-bom.md +0 -0
- /package/skills/{sensecraft → solution-cli}/references/offline.md +0 -0
- /package/skills/{sensecraft → solution-cli}/references/secondary-development.md +0 -0
- /package/skills/{sensecraft → solution-cli}/references/verify.md +0 -0
package/README.md
CHANGED
|
@@ -13,9 +13,18 @@ Compatible with **Claude Code, Codex, Google Antigravity (AGY), Work Buddy, and
|
|
|
13
13
|
Install the underlying engine and configure the AI Agent Skill with one command:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
npx -y @seeed-studio/solution-cli@latest install -y
|
|
16
|
+
npx -y @seeed-studio/solution-cli@latest install --agent workbuddy -y
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
+
This example targets WorkBuddy explicitly. Replace `workbuddy` with the current
|
|
20
|
+
Agent ID for another host. Use `npx -y @seeed-studio/solution-cli@latest install`
|
|
21
|
+
for the interactive form: when one or more Agents are detected, pressing Enter
|
|
22
|
+
selects all detected Agents, while entering the corresponding number selects one
|
|
23
|
+
host. In non-interactive mode, `install -y` without `--agent` also selects all
|
|
24
|
+
detected Agents when any are detected. If none are detected, these defaults still
|
|
25
|
+
use the CLI's default target set; pass `--agent <agent-id>` to control the scope
|
|
26
|
+
explicitly.
|
|
27
|
+
|
|
19
28
|
The same command is safe to repeat. It checks the signed stable Engine release,
|
|
20
29
|
reuses an equal or newer local Engine, and upgrades an older one. Existing
|
|
21
30
|
modified or unregistered skills and protected symlinks are preserved. Use
|
|
@@ -25,9 +34,8 @@ overwrites existing skill files, including user modifications; use it only when
|
|
|
25
34
|
that overwrite is intended. Protected external symlinks are not followed, and
|
|
26
35
|
it never downgrades a newer discovered Engine.
|
|
27
36
|
|
|
28
|
-
Automatic reuse/upgrade rules start with solution-cli 0.3.1
|
|
29
|
-
|
|
30
|
-
publication. A latest release or signature failure stops before changing the
|
|
37
|
+
Automatic reuse/upgrade rules start with publicly published solution-cli 0.3.1.
|
|
38
|
+
A latest release or signature failure stops before changing the
|
|
31
39
|
Engine or skills; an offline host must use a valid explicit local Engine path.
|
|
32
40
|
|
|
33
41
|
The interactive form remains available when prompts are wanted:
|
|
@@ -37,11 +45,11 @@ npx -y @seeed-studio/solution-cli@latest install
|
|
|
37
45
|
```
|
|
38
46
|
|
|
39
47
|
### Supported AI Agent Harnesses
|
|
40
|
-
- **Claude Code**: `~/.claude/skills/
|
|
41
|
-
- **Codex / OpenAI**: `~/.agents/skills/
|
|
42
|
-
- **Google Antigravity (AGY)**: `~/.gemini/config/skills/
|
|
43
|
-
- **Work Buddy / Workbody**: `~/.workbuddy/skills/
|
|
44
|
-
- **CodeBuddy**: `~/.codebuddy/skills/
|
|
48
|
+
- **Claude Code**: `~/.claude/skills/solution-cli`
|
|
49
|
+
- **Codex / OpenAI**: `~/.agents/skills/solution-cli` or `~/.codex/skills/solution-cli`
|
|
50
|
+
- **Google Antigravity (AGY)**: `~/.gemini/config/skills/solution-cli`
|
|
51
|
+
- **Work Buddy / Workbody**: `~/.workbuddy/skills/solution-cli`
|
|
52
|
+
- **CodeBuddy**: `~/.codebuddy/skills/solution-cli`
|
|
45
53
|
|
|
46
54
|
---
|
|
47
55
|
|
|
@@ -57,7 +65,7 @@ The `solution-cli` provides unified commands for discovery, BOM calculation, dev
|
|
|
57
65
|
| `solution-cli install [--agent <agents>] [-y]` | Inspect host environment, download/verify engine, and install Agent skills. |
|
|
58
66
|
| `solution-cli status` | Inspect installed engine binary, content cache, and configured agent skills. |
|
|
59
67
|
| `solution-cli doctor` | Run pre-flight diagnostics (OS, Docker daemon, serial permissions, PATH, ledger). |
|
|
60
|
-
| `solution-cli uninstall [--agent <agents>]` | Cleanly remove
|
|
68
|
+
| `solution-cli uninstall [--agent <agents>]` | Cleanly remove Solution CLI skills using the installation ledger. |
|
|
61
69
|
| `sensecraft-engine <subcommand>` | Direct proxy to the underlying high-performance Rust execution engine. |
|
|
62
70
|
|
|
63
71
|
---
|
package/bin/cli.js
CHANGED
|
@@ -15,18 +15,17 @@ const command = args[0] || 'install';
|
|
|
15
15
|
|
|
16
16
|
function printHelp() {
|
|
17
17
|
console.log(`
|
|
18
|
-
|
|
18
|
+
Solution CLI & Agent Skill Toolset (${pkg.name})
|
|
19
19
|
|
|
20
20
|
Usage:
|
|
21
21
|
npx @seeed-studio/solution-cli [command] [options]
|
|
22
22
|
solution-cli [command] [options]
|
|
23
|
-
sensecraft-solution-cli [command] [options]
|
|
24
23
|
|
|
25
24
|
Commands:
|
|
26
25
|
install Inspect environment, verify/download engine, and configure AI Agent skills (default)
|
|
27
26
|
status Display current engine, solution content, and agent skills status
|
|
28
27
|
doctor Diagnose environment (platform, permissions, docker, PATH, ledger)
|
|
29
|
-
uninstall Cleanly remove
|
|
28
|
+
uninstall Cleanly remove Solution CLI skills from specified agent(s)
|
|
30
29
|
hub Search scenarios and reference designs from Seeed Solution Hub
|
|
31
30
|
Usage: solution-cli hub search <keyword> [--limit 5] [--locale zh|en] [--json]
|
|
32
31
|
product Query product families, SKUs, and verified accessories
|
|
@@ -58,7 +57,15 @@ Examples:
|
|
|
58
57
|
`);
|
|
59
58
|
}
|
|
60
59
|
|
|
60
|
+
class CliArgumentError extends Error {
|
|
61
|
+
constructor(message) {
|
|
62
|
+
super(message);
|
|
63
|
+
this.name = 'CliArgumentError';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
61
67
|
function parseFlags(rawArgs) {
|
|
68
|
+
const usedFlags = new Set();
|
|
62
69
|
const flags = {
|
|
63
70
|
agent: null,
|
|
64
71
|
yes: false,
|
|
@@ -75,62 +82,121 @@ function parseFlags(rawArgs) {
|
|
|
75
82
|
solution: null,
|
|
76
83
|
version: '1.0.0',
|
|
77
84
|
hardware: null,
|
|
85
|
+
positionals: [],
|
|
86
|
+
usedFlags,
|
|
78
87
|
};
|
|
79
88
|
|
|
80
89
|
for (let i = 0; i < rawArgs.length; i++) {
|
|
81
90
|
const a = rawArgs[i];
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
91
|
+
const valueFlag = (name, setter) => {
|
|
92
|
+
const inlinePrefix = `${name}=`;
|
|
93
|
+
if (a.startsWith(inlinePrefix)) {
|
|
94
|
+
const value = a.slice(inlinePrefix.length);
|
|
95
|
+
if (!value) throw new CliArgumentError(`${name} requires a value`);
|
|
96
|
+
usedFlags.add(name);
|
|
97
|
+
setter(value);
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
if (a === name) {
|
|
101
|
+
const value = rawArgs[i + 1];
|
|
102
|
+
if (!value || value.startsWith('-')) {
|
|
103
|
+
throw new CliArgumentError(`${name} requires a value`);
|
|
104
|
+
}
|
|
105
|
+
usedFlags.add(name);
|
|
106
|
+
setter(value);
|
|
107
|
+
i += 1;
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
return false;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
if (valueFlag('--agent', value => { flags.agent = value; })) {
|
|
86
114
|
} else if (a === '-y' || a === '--yes') {
|
|
115
|
+
usedFlags.add('--yes');
|
|
87
116
|
flags.yes = true;
|
|
88
117
|
} else if (a === '--dry-run') {
|
|
118
|
+
usedFlags.add('--dry-run');
|
|
89
119
|
flags.dryRun = true;
|
|
90
120
|
} else if (a === '--skip-content') {
|
|
121
|
+
usedFlags.add('--skip-content');
|
|
91
122
|
flags.skipContent = true;
|
|
92
123
|
} else if (a === '--force') {
|
|
124
|
+
usedFlags.add('--force');
|
|
93
125
|
flags.force = true;
|
|
94
126
|
} else if (a === '--json') {
|
|
127
|
+
usedFlags.add('--json');
|
|
95
128
|
flags.json = true;
|
|
96
|
-
} else if (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
flags.
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
} else if (
|
|
105
|
-
|
|
106
|
-
} else if (
|
|
107
|
-
|
|
108
|
-
} else if (
|
|
109
|
-
|
|
110
|
-
} else if (a
|
|
111
|
-
|
|
112
|
-
} else
|
|
113
|
-
flags.
|
|
129
|
+
} else if (valueFlag('--engine-path', value => { flags.enginePath = value; })) {
|
|
130
|
+
} else if (valueFlag('--limit', value => {
|
|
131
|
+
if (!/^[1-9]\d*$/.test(value)) throw new CliArgumentError('--limit requires a positive integer');
|
|
132
|
+
const limit = Number(value);
|
|
133
|
+
if (!Number.isSafeInteger(limit)) throw new CliArgumentError('--limit is too large');
|
|
134
|
+
flags.limit = limit;
|
|
135
|
+
})) {
|
|
136
|
+
} else if (valueFlag('--locale', value => { flags.locale = value; })) {
|
|
137
|
+
} else if (valueFlag('--sku', value => { flags.sku = value; })) {
|
|
138
|
+
} else if (valueFlag('--host', value => { flags.host = value; })) {
|
|
139
|
+
} else if (valueFlag('--accessory', value => { flags.accessory = value; })) {
|
|
140
|
+
} else if (valueFlag('--solution', value => { flags.solution = value; })) {
|
|
141
|
+
} else if (valueFlag('--version', value => { flags.version = value; })) {
|
|
142
|
+
} else if (valueFlag('--hardware', value => { flags.hardware = value; })) {
|
|
143
|
+
} else if (a.startsWith('-')) {
|
|
144
|
+
throw new CliArgumentError(`Unknown option "${a}"`);
|
|
145
|
+
} else {
|
|
146
|
+
flags.positionals.push(a);
|
|
114
147
|
}
|
|
115
148
|
}
|
|
116
149
|
|
|
117
150
|
return flags;
|
|
118
151
|
}
|
|
119
152
|
|
|
120
|
-
|
|
121
|
-
|
|
153
|
+
function validatePositionals(command, positionals) {
|
|
154
|
+
if (['install', 'uninstall', 'status', 'doctor'].includes(command) && positionals.length > 0) {
|
|
155
|
+
throw new CliArgumentError(`${command} does not accept positional arguments`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
122
158
|
|
|
123
|
-
|
|
159
|
+
function validateCommandFlags(command, flags) {
|
|
160
|
+
const allowed = {
|
|
161
|
+
install: ['--agent', '--yes', '--dry-run', '--skip-content', '--force', '--engine-path'],
|
|
162
|
+
uninstall: ['--agent', '--dry-run', '--force'],
|
|
163
|
+
status: ['--json'],
|
|
164
|
+
doctor: ['--json'],
|
|
165
|
+
hub: ['--json', '--locale', '--limit'],
|
|
166
|
+
product: ['--json', '--locale', '--sku', '--host', '--accessory'],
|
|
167
|
+
lockfile: ['--json', '--solution', '--version', '--hardware'],
|
|
168
|
+
help: [],
|
|
169
|
+
};
|
|
170
|
+
const supported = allowed[command];
|
|
171
|
+
if (!supported) return;
|
|
172
|
+
for (const flag of flags.usedFlags) {
|
|
173
|
+
if (!supported.includes(flag)) {
|
|
174
|
+
throw new CliArgumentError(`${flag} is not supported for ${command}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async function main() {
|
|
180
|
+
if (args.some(a => a === '--help' || a === '-h')) {
|
|
124
181
|
printHelp();
|
|
125
|
-
|
|
182
|
+
return;
|
|
126
183
|
}
|
|
127
184
|
|
|
128
185
|
if (command === '--version' || command === '-v') {
|
|
129
186
|
console.log(pkg.version);
|
|
130
|
-
|
|
187
|
+
return;
|
|
131
188
|
}
|
|
132
189
|
|
|
133
190
|
try {
|
|
191
|
+
const flags = parseFlags(args.slice(1));
|
|
192
|
+
validatePositionals(command, flags.positionals);
|
|
193
|
+
validateCommandFlags(command, flags);
|
|
194
|
+
|
|
195
|
+
if (command === 'help') {
|
|
196
|
+
printHelp();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
134
200
|
switch (command) {
|
|
135
201
|
case 'install':
|
|
136
202
|
await runInstall(flags);
|
|
@@ -145,7 +211,7 @@ async function main() {
|
|
|
145
211
|
if (flags.json) {
|
|
146
212
|
console.log(JSON.stringify(report, null, 2));
|
|
147
213
|
} else {
|
|
148
|
-
console.log('\n🩺
|
|
214
|
+
console.log('\n🩺 Solution CLI Doctor Environment Report:\n');
|
|
149
215
|
report.checks.forEach(c => {
|
|
150
216
|
const symbol = c.status === 'ok' ? '\x1b[32m✔\x1b[0m' : c.status === 'warn' ? '\x1b[33m⚠️\x1b[0m' : '\x1b[31m✖\x1b[0m';
|
|
151
217
|
console.log(` ${symbol} ${c.title}`);
|
|
@@ -161,12 +227,12 @@ async function main() {
|
|
|
161
227
|
break;
|
|
162
228
|
|
|
163
229
|
case 'hub': {
|
|
164
|
-
const sub =
|
|
230
|
+
const sub = flags.positionals[0] || 'search';
|
|
165
231
|
if (sub !== 'search') {
|
|
166
232
|
console.error(`Unknown hub action "${sub}". Supported: "solution-cli hub search <keyword>"`);
|
|
167
233
|
process.exit(1);
|
|
168
234
|
}
|
|
169
|
-
const query =
|
|
235
|
+
const query = flags.positionals.slice(1).join(' ');
|
|
170
236
|
const dto = await searchHub({ query, locale: flags.locale, limit: flags.limit });
|
|
171
237
|
if (flags.json) {
|
|
172
238
|
console.log(JSON.stringify(dto, null, 2));
|
|
@@ -200,8 +266,8 @@ async function main() {
|
|
|
200
266
|
}
|
|
201
267
|
|
|
202
268
|
case 'product': {
|
|
203
|
-
const sub =
|
|
204
|
-
const familyId =
|
|
269
|
+
const sub = flags.positionals[0] || 'query';
|
|
270
|
+
const familyId = flags.positionals[1] || flags.host;
|
|
205
271
|
|
|
206
272
|
if (sub === 'query') {
|
|
207
273
|
if (!familyId) {
|
|
@@ -296,7 +362,7 @@ async function main() {
|
|
|
296
362
|
}
|
|
297
363
|
|
|
298
364
|
case 'lockfile': {
|
|
299
|
-
const sub =
|
|
365
|
+
const sub = flags.positionals[0] || 'create';
|
|
300
366
|
if (sub !== 'create') {
|
|
301
367
|
console.error(`Unknown lockfile action "${sub}". Supported: "solution-cli lockfile create"`);
|
|
302
368
|
process.exit(1);
|
|
@@ -326,7 +392,7 @@ async function main() {
|
|
|
326
392
|
}
|
|
327
393
|
} catch (err) {
|
|
328
394
|
console.error(`\n\x1b[31mError:\x1b[0m ${err.message}\n`);
|
|
329
|
-
process.
|
|
395
|
+
process.exitCode = err instanceof CliArgumentError ? 2 : 1;
|
|
330
396
|
}
|
|
331
397
|
}
|
|
332
398
|
|
package/bin/runner.js
CHANGED
|
@@ -8,7 +8,7 @@ const binPath = getConfiguredEnginePath();
|
|
|
8
8
|
|
|
9
9
|
if (!fs.existsSync(binPath) || !isExecutable(binPath)) {
|
|
10
10
|
console.error(`\x1b[31mError:\x1b[0m SenseCraft Engine binary not found at "${binPath}".`);
|
|
11
|
-
console.error('Please run "npx
|
|
11
|
+
console.error('Please run "npx -y --package=@seeed-studio/solution-cli@latest solution-cli install --agent <agent-id>" first to provision the engine.\n');
|
|
12
12
|
process.exit(1);
|
|
13
13
|
}
|
|
14
14
|
|
package/docs/cli-guide.md
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
`@seeed-studio/solution-cli` 正是为解决这一系列问题而生,它具有三大独特角色:
|
|
31
31
|
1. **方案专家的现场诊断仪**:内置各大行业工况诊断知识库,不仅能搜方案,还能直接指导工程师向客户提出决定成本与物理拓扑的“黄金追问”;
|
|
32
32
|
2. **硬件采购防呆中枢**:内置物理规格匹配引擎,自动核算【必需配件】与【可选配件】,从源头阻断硬件返工;
|
|
33
|
-
3. **AI Agent 的物理世界触手**:一键将
|
|
33
|
+
3. **AI Agent 的物理世界触手**:一键将 solution-cli Skill 注入到主流 AI Agent 宿主中,让 Agent 具备从方案咨询、BOM 选型到现场部署、参数热更的全生命周期驱动能力。
|
|
34
34
|
|
|
35
35
|
---
|
|
36
36
|
|
|
@@ -39,9 +39,16 @@
|
|
|
39
39
|
### 2.1 一键免安装即时调用 (推荐)
|
|
40
40
|
无需全局安装,安装或按需升级 Engine 与 Agent Skill 使用同一条命令:
|
|
41
41
|
```bash
|
|
42
|
-
npx -y @seeed-studio/solution-cli@latest install -y
|
|
42
|
+
npx -y @seeed-studio/solution-cli@latest install --agent workbuddy -y
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
+
上面的示例明确安装到 WorkBuddy。其他宿主将 `workbuddy` 替换为当前实际的
|
|
46
|
+
Agent ID。需要交互选择时使用 `npx -y @seeed-studio/solution-cli@latest install`;
|
|
47
|
+
检测到一个或多个 Agent 时,直接回车默认选择全部已检测的 Agent,输入对应序号
|
|
48
|
+
选择指定宿主。非交互模式下,`install -y` 未提供 `--agent` 且检测到 Agent 时也会
|
|
49
|
+
选择全部已检测的 Agent。未检测到 Agent 时,这些默认仍使用 CLI 的默认目标集合;
|
|
50
|
+
需要明确控制范围时请提供 `--agent <agent-id>`。
|
|
51
|
+
|
|
45
52
|
首次安装和重复执行都会检查签名稳定版 Engine:本机已有相同或更新版本
|
|
46
53
|
时复用,版本较旧时升级。普通安装保留用户修改、未登记的 Skill 文件和受
|
|
47
54
|
保护的符号链接。需要指定宿主时追加 `--agent claude,antigravity`;需要固
|
|
@@ -49,31 +56,52 @@ npx -y @seeed-studio/solution-cli@latest install -y
|
|
|
49
56
|
或较旧版本并覆盖已有 Skill 文件(包括用户修改),请只在有意覆盖时使用;
|
|
50
57
|
受保护的外部符号链接不会追写,也不能降级更新的本机 Engine。
|
|
51
58
|
|
|
52
|
-
自动复用/升级规则自 solution-cli 0.3.1
|
|
53
|
-
这些规则尚未上线。本次验证时 0.3.1 待发布。latest 检查或签名校验失败会在
|
|
59
|
+
自动复用/升级规则自 solution-cli 0.3.1 起生效;该版本已公开发布。latest 检查或签名校验失败会在
|
|
54
60
|
修改 Engine、指针或 Skill 前停止;离线时请提供有效的 `--engine-path`。
|
|
55
61
|
|
|
56
62
|
The same command handles a fresh install and a user-requested upgrade. It checks
|
|
57
63
|
the signed stable Engine, reuses an equal/newer local version, preserves modified
|
|
58
64
|
skills, and stops before writes on latest/signature failure. Automatic reuse and
|
|
59
|
-
upgrade rules start with solution-cli 0.3.1
|
|
60
|
-
|
|
65
|
+
upgrade rules start with publicly published solution-cli 0.3.1. The example
|
|
66
|
+
targets WorkBuddy with `--agent workbuddy`; replace it with the current Agent ID
|
|
67
|
+
for another host. Use `npx -y @seeed-studio/solution-cli@latest install` for the
|
|
68
|
+
interactive form: when one or more Agents are detected, pressing Enter selects
|
|
69
|
+
all detected Agents, while entering a number selects one host. In non-interactive
|
|
70
|
+
mode, `install -y` without `--agent` also selects all detected Agents when any
|
|
71
|
+
are detected. If none are detected, these defaults still use the CLI's default
|
|
72
|
+
target set; pass `--agent <agent-id>` to control the scope explicitly.
|
|
61
73
|
|
|
62
74
|
### 2.2 全局安装
|
|
63
75
|
```bash
|
|
64
76
|
npm install -g @seeed-studio/solution-cli
|
|
77
|
+
solution-cli install --agent workbuddy -y
|
|
65
78
|
```
|
|
66
79
|
|
|
80
|
+
全局安装后的挂载规则相同:示例明确选择 WorkBuddy;其他宿主请将
|
|
81
|
+
`workbuddy` 替换为当前实际 Agent ID。交互执行 `solution-cli install` 时,
|
|
82
|
+
检测到一个或多个 Agent 后直接回车选择全部已检测的 Agent,输入对应序号选择指定
|
|
83
|
+
宿主;非交互执行 `solution-cli install -y` 且未提供 `--agent` 时,检测到 Agent
|
|
84
|
+
也会选择全部已检测的 Agent。未检测到 Agent 时,这些默认仍使用 CLI 的默认目标集合;
|
|
85
|
+
需要明确控制范围时请提供 `--agent <agent-id>`。
|
|
86
|
+
|
|
87
|
+
The global command targets WorkBuddy explicitly. Replace `workbuddy` with the
|
|
88
|
+
current Agent ID for another host. Interactive `solution-cli install` selects all
|
|
89
|
+
detected Agents on Enter when any are detected, or one host by number;
|
|
90
|
+
non-interactive `solution-cli install -y` without `--agent` also selects all
|
|
91
|
+
detected Agents when any are detected. If none are detected, these defaults still
|
|
92
|
+
use the CLI's default target set; pass `--agent <agent-id>` to control the scope
|
|
93
|
+
explicitly.
|
|
94
|
+
|
|
67
95
|
### 2.3 跨 Agent 平台技能挂载
|
|
68
|
-
执行 `solution-cli install` 时,工具会自动检测本机存在的 Agent 宿主环境,并将 `
|
|
96
|
+
执行 `solution-cli install` 时,工具会自动检测本机存在的 Agent 宿主环境,并将 `solution-cli` Skill 和全套参考手册安全复制到对应目录:
|
|
69
97
|
|
|
70
98
|
| Agent 宿主平台 | 技能默认配置路径 | 支持能力 |
|
|
71
99
|
|---|---|---|
|
|
72
|
-
| **Claude Code** | `~/.claude/skills/
|
|
73
|
-
| **Codex (OpenAI)** | `~/.agents/skills/
|
|
74
|
-
| **Google Antigravity (AGY)** | `~/.gemini/config/skills/
|
|
75
|
-
| **Work Buddy / Workbody** | `~/.workbuddy/skills/
|
|
76
|
-
| **CodeBuddy** | `~/.codebuddy/skills/
|
|
100
|
+
| **Claude Code** | `~/.claude/skills/solution-cli` | 完整方案咨询、工况诊断、BOM 生成、现场部署 |
|
|
101
|
+
| **Codex (OpenAI)** | `~/.agents/skills/solution-cli` 或 `~/.codex/skills/solution-cli` | 代码审查、参数重构、二次开发自动化 |
|
|
102
|
+
| **Google Antigravity (AGY)** | `~/.gemini/config/skills/solution-cli` | 端到端自主诊断、多 Agent 协同实施 |
|
|
103
|
+
| **Work Buddy / Workbody** | `~/.workbuddy/skills/solution-cli` | 桌面端交互、方案展示、一键部署联动 |
|
|
104
|
+
| **CodeBuddy** | `~/.codebuddy/skills/solution-cli` | 代码库配对开发与自研模型构建 |
|
|
77
105
|
|
|
78
106
|
**非交互式多选安装示例**:
|
|
79
107
|
```bash
|
package/lib/agent.js
CHANGED
|
@@ -15,8 +15,8 @@ export function getKnownAgents() {
|
|
|
15
15
|
// Check where an existing installation might already be
|
|
16
16
|
const p1 = path.join(home, '.workbuddy', 'skills');
|
|
17
17
|
const p2 = path.join(home, '.workbody', 'skills');
|
|
18
|
-
if (fs.existsSync(path.join(p1, '
|
|
19
|
-
if (fs.existsSync(path.join(p2, '
|
|
18
|
+
if (fs.existsSync(path.join(p1, 'solution-cli', 'SKILL.md'))) return p1;
|
|
19
|
+
if (fs.existsSync(path.join(p2, 'solution-cli', 'SKILL.md'))) return p2;
|
|
20
20
|
if (fs.existsSync(path.join(home, '.workbuddy'))) return p1;
|
|
21
21
|
if (fs.existsSync(path.join(home, '.workbody'))) return p2;
|
|
22
22
|
return p1;
|
|
@@ -36,8 +36,8 @@ export function getKnownAgents() {
|
|
|
36
36
|
// Honor existing installation first to avoid path drift (Codex Medium 13)
|
|
37
37
|
const pAgents = path.join(home, '.agents', 'skills');
|
|
38
38
|
const pCodex = path.join(home, '.codex', 'skills');
|
|
39
|
-
if (fs.existsSync(path.join(pAgents, '
|
|
40
|
-
if (fs.existsSync(path.join(pCodex, '
|
|
39
|
+
if (fs.existsSync(path.join(pAgents, 'solution-cli', 'SKILL.md'))) return pAgents;
|
|
40
|
+
if (fs.existsSync(path.join(pCodex, 'solution-cli', 'SKILL.md'))) return pCodex;
|
|
41
41
|
// Default to .agents/skills if .agents exists, otherwise .codex/skills if .codex exists
|
|
42
42
|
if (fs.existsSync(path.join(home, '.agents'))) return pAgents;
|
|
43
43
|
if (fs.existsSync(path.join(home, '.codex'))) return pCodex;
|
|
@@ -69,7 +69,7 @@ export function scanLocalAgents() {
|
|
|
69
69
|
return agents.map(a => {
|
|
70
70
|
const skillsDir = a.getSkillsDir();
|
|
71
71
|
const detected = a.homeDirs.some(dir => fs.existsSync(dir)) || fs.existsSync(skillsDir);
|
|
72
|
-
const installed = fs.existsSync(path.join(skillsDir, '
|
|
72
|
+
const installed = fs.existsSync(path.join(skillsDir, 'solution-cli', 'SKILL.md'));
|
|
73
73
|
return {
|
|
74
74
|
...a,
|
|
75
75
|
detected,
|
package/lib/detector.js
CHANGED
|
@@ -226,7 +226,7 @@ export function detectDesktopApp() {
|
|
|
226
226
|
appPath: appBase,
|
|
227
227
|
binPath: path.join(appBase, 'Contents', 'MacOS', 'sensecraft-engine'),
|
|
228
228
|
solutionsPath: path.join(appBase, 'Contents', 'Resources', '_up_', 'sensecraft-solutions', 'solutions'),
|
|
229
|
-
skillsPath: path.join(appBase, 'Contents', 'Resources', '_up_', 'sensecraft-solutions', 'skills', '
|
|
229
|
+
skillsPath: path.join(appBase, 'Contents', 'Resources', '_up_', 'sensecraft-solutions', 'skills', 'solution-cli')
|
|
230
230
|
});
|
|
231
231
|
const cacheBin = path.join(
|
|
232
232
|
os.homedir(),
|
|
@@ -258,7 +258,7 @@ export function detectDesktopApp() {
|
|
|
258
258
|
appPath,
|
|
259
259
|
binPath: path.join(appPath, 'resources', 'bin', 'sensecraft-engine.exe'),
|
|
260
260
|
solutionsPath: path.join(appPath, 'resources', 'sensecraft-solutions', 'solutions'),
|
|
261
|
-
skillsPath: path.join(appPath, 'resources', 'sensecraft-solutions', 'skills', '
|
|
261
|
+
skillsPath: path.join(appPath, 'resources', 'sensecraft-solutions', 'skills', 'solution-cli')
|
|
262
262
|
});
|
|
263
263
|
}
|
|
264
264
|
}
|
|
@@ -271,7 +271,7 @@ export function detectDesktopApp() {
|
|
|
271
271
|
appPath,
|
|
272
272
|
binPath: path.join(appPath, 'sensecraft-engine'),
|
|
273
273
|
solutionsPath: path.join(appPath, 'sensecraft-solutions', 'solutions'),
|
|
274
|
-
skillsPath: path.join(appPath, 'skills', '
|
|
274
|
+
skillsPath: path.join(appPath, 'skills', 'solution-cli')
|
|
275
275
|
});
|
|
276
276
|
}
|
|
277
277
|
}
|
package/lib/installer.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from './platform.js';
|
|
11
11
|
import { detectExistingEngine, detectDesktopApp, verifyEngineBinary, compareSemver } from './detector.js';
|
|
12
12
|
import { downloadEngine, fetchManifest, validateReleaseManifest, pullSolutionContent } from './downloader.js';
|
|
13
|
-
import { scanLocalAgents, promptAgentSelection } from './agent.js';
|
|
13
|
+
import { getKnownAgents, scanLocalAgents, promptAgentSelection } from './agent.js';
|
|
14
14
|
import {
|
|
15
15
|
recordInstallation,
|
|
16
16
|
removeInstallation,
|
|
@@ -22,7 +22,31 @@ import {
|
|
|
22
22
|
|
|
23
23
|
const __filename = fileURLToPath(import.meta.url);
|
|
24
24
|
const __dirname = path.dirname(__filename);
|
|
25
|
-
const
|
|
25
|
+
const SKILL_DIR_NAME = 'solution-cli';
|
|
26
|
+
const LEGACY_SKILL_DIR_NAME = 'sensecraft';
|
|
27
|
+
const BUNDLED_SKILLS_SRC = path.resolve(__dirname, '..', 'skills', SKILL_DIR_NAME);
|
|
28
|
+
|
|
29
|
+
function assertCanonicalSkillState(ledger, agents) {
|
|
30
|
+
const allAgents = agents;
|
|
31
|
+
const errors = [];
|
|
32
|
+
|
|
33
|
+
for (const agent of allAgents) {
|
|
34
|
+
const skillsDir = agent.skillsDir || agent.getSkillsDir();
|
|
35
|
+
const expectedTarget = path.resolve(path.join(skillsDir, SKILL_DIR_NAME));
|
|
36
|
+
const legacySkill = path.join(skillsDir, LEGACY_SKILL_DIR_NAME, 'SKILL.md');
|
|
37
|
+
if (fs.lstatSync(legacySkill, { throwIfNoEntry: false })) {
|
|
38
|
+
errors.push(`${agent.id} still has legacy skill at ${legacySkill}; run uninstall --agent ${agent.id} before installing solution-cli. If the file is untracked or remains after uninstall because it was modified, back it up and retire the legacy skill directory before retrying; user files are not removed automatically.`);
|
|
39
|
+
}
|
|
40
|
+
const record = ledger.installations?.[agent.id];
|
|
41
|
+
if (record && path.resolve(record.target_dir) !== expectedTarget) {
|
|
42
|
+
errors.push(`${agent.id} is managed at legacy target ${record.target_dir}; run uninstall --agent ${agent.id} before installing solution-cli`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (errors.length > 0) {
|
|
47
|
+
throw new Error(`Legacy SenseCraft skill state blocks canonical solution-cli installation:\n- ${errors.join('\n- ')}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
26
50
|
|
|
27
51
|
export async function runInstall(options = {}) {
|
|
28
52
|
const {
|
|
@@ -36,7 +60,7 @@ export async function runInstall(options = {}) {
|
|
|
36
60
|
} = options;
|
|
37
61
|
|
|
38
62
|
logger('\x1b[1m\x1b[34m====================================================\x1b[0m');
|
|
39
|
-
logger('\x1b[1m\x1b[34m
|
|
63
|
+
logger('\x1b[1m\x1b[34m Solution CLI Installer \x1b[0m');
|
|
40
64
|
logger('\x1b[1m\x1b[34m====================================================\x1b[0m\n');
|
|
41
65
|
|
|
42
66
|
const platform = getPlatformInfo();
|
|
@@ -53,6 +77,9 @@ export async function runInstall(options = {}) {
|
|
|
53
77
|
return { success: true, engineBin: null, installedAgents: [] };
|
|
54
78
|
}
|
|
55
79
|
|
|
80
|
+
// Validate ownership and legacy targets before engine selection or pointer/download writes.
|
|
81
|
+
assertCanonicalSkillState(loadLedger(), selectedAgents);
|
|
82
|
+
|
|
56
83
|
// --- Step 1: Detect & Verify Engine Candidate ---
|
|
57
84
|
logger('🔍 Phase 1: Inspecting host environment for existing Engine/App...');
|
|
58
85
|
let engineBin = null;
|
|
@@ -135,9 +162,10 @@ export async function runInstall(options = {}) {
|
|
|
135
162
|
|
|
136
163
|
runWithLock(() => {
|
|
137
164
|
const ledger = dryRun ? { installations: {} } : loadLedger();
|
|
165
|
+
assertCanonicalSkillState(ledger, selectedAgents);
|
|
138
166
|
|
|
139
167
|
for (const a of selectedAgents) {
|
|
140
|
-
const destDir = path.resolve(path.join(a.skillsDir,
|
|
168
|
+
const destDir = path.resolve(path.join(a.skillsDir, SKILL_DIR_NAME));
|
|
141
169
|
logger(`\nConfiguring ${a.name} at: ${destDir}...`);
|
|
142
170
|
|
|
143
171
|
if (dryRun) {
|
|
@@ -161,7 +189,7 @@ export async function runInstall(options = {}) {
|
|
|
161
189
|
const preservedStat = fs.lstatSync(preservedSkillPath, { throwIfNoEntry: false });
|
|
162
190
|
if (preservedStat && !preservedStat.isSymbolicLink()) {
|
|
163
191
|
const preservedSkill = fs.readFileSync(preservedSkillPath, 'utf8');
|
|
164
|
-
const oldPathMatch = preservedSkill.match(/\*\*
|
|
192
|
+
const oldPathMatch = preservedSkill.match(/\*\*Solution CLI Runtime\*\*:[\s\S]*?full absolute path: `"([^"]+)"/);
|
|
165
193
|
const normalizePath = value => path.normalize(value.replaceAll('\\', '/'));
|
|
166
194
|
if (oldPathMatch && normalizePath(oldPathMatch[1]) !== normalizePath(engineBin)) {
|
|
167
195
|
logger(` ⚠️ Preserved user-modified SKILL.md still contains its previous Engine path; user text was not rewritten.`);
|
|
@@ -178,9 +206,9 @@ export async function runInstall(options = {}) {
|
|
|
178
206
|
if (skillStat && !skillStat.isSymbolicLink()) {
|
|
179
207
|
let content = fs.readFileSync(skillMdPath, 'utf8');
|
|
180
208
|
const escapedBinPath = engineBin.replace(/\\/g, '/');
|
|
181
|
-
const instructionBlock = `\n> **
|
|
209
|
+
const instructionBlock = `\n> **Solution CLI Runtime**: Engine operations such as \`device\`, \`deploy\`, and \`logs\` must use the full absolute path: \`"${escapedBinPath}" <subcommand>\`. Use \`solution-cli\` for catalog and product queries; if it is not on $PATH, invoke \`npx -y --package=@seeed-studio/solution-cli@latest solution-cli <args>\`.\n\n`;
|
|
182
210
|
|
|
183
|
-
if (!content.includes('
|
|
211
|
+
if (!content.includes('**Solution CLI Runtime**:')) {
|
|
184
212
|
content = content.replace(/(---[\s\S]*?---\n)/, `$1${instructionBlock}`);
|
|
185
213
|
fs.writeFileSync(skillMdPath, content, 'utf8');
|
|
186
214
|
}
|
|
@@ -189,7 +217,7 @@ export async function runInstall(options = {}) {
|
|
|
189
217
|
}
|
|
190
218
|
|
|
191
219
|
// Write installation marker safely without following external symlinks (Codex P2)
|
|
192
|
-
const markerPath = path.join(destDir, '.installed-by-
|
|
220
|
+
const markerPath = path.join(destDir, '.installed-by-solution-cli');
|
|
193
221
|
if (isSafePathInside(markerPath, destDir)) {
|
|
194
222
|
const markerStat = fs.lstatSync(markerPath, { throwIfNoEntry: false });
|
|
195
223
|
if (markerStat && markerStat.isSymbolicLink()) {
|
|
@@ -210,7 +238,7 @@ export async function runInstall(options = {}) {
|
|
|
210
238
|
});
|
|
211
239
|
|
|
212
240
|
logger('\n\x1b[1m\x1b[32m====================================================\x1b[0m');
|
|
213
|
-
logger('\x1b[1m\x1b[32m 🎉
|
|
241
|
+
logger('\x1b[1m\x1b[32m 🎉 Solution CLI Setup Completed Successfully! \x1b[0m');
|
|
214
242
|
logger('\x1b[1m\x1b[32m====================================================\x1b[0m');
|
|
215
243
|
logger(`\n🔧 Engine Binary: ${engineBin}`);
|
|
216
244
|
logger(`🤖 Configured Agents:`);
|
|
@@ -262,7 +290,7 @@ export function runStatus(options = {}) {
|
|
|
262
290
|
return statusObj;
|
|
263
291
|
}
|
|
264
292
|
|
|
265
|
-
logger('\n📊
|
|
293
|
+
logger('\n📊 Solution CLI System Status:\n');
|
|
266
294
|
logger(` Engine Binary: ${binPath}`);
|
|
267
295
|
logger(` Engine Version: ${engineCheck.version || 'Not installed'} (${engineCheck.valid ? 'Valid' : 'Invalid'})`);
|
|
268
296
|
logger(` Deployers Available: ${engineCheck.deployers?.length || 0}`);
|
|
@@ -286,7 +314,7 @@ export function runUninstall(options = {}) {
|
|
|
286
314
|
const installedIds = Object.keys(ledger.installations || {});
|
|
287
315
|
|
|
288
316
|
if (installedIds.length === 0) {
|
|
289
|
-
logger('No managed
|
|
317
|
+
logger('No managed Solution CLI skills are currently recorded in the ledger.');
|
|
290
318
|
return;
|
|
291
319
|
}
|
|
292
320
|
|
package/lib/ledger.js
CHANGED
|
@@ -246,7 +246,7 @@ export function removeInstallation(agentId, options = {}) {
|
|
|
246
246
|
}
|
|
247
247
|
|
|
248
248
|
// Remove marker file
|
|
249
|
-
const marker = path.join(targetDir, '.installed-by-
|
|
249
|
+
const marker = path.join(targetDir, '.installed-by-solution-cli');
|
|
250
250
|
if (fs.existsSync(marker) && isSafePathInside(marker, targetDir)) {
|
|
251
251
|
actions.push({ file: marker, action: 'delete_marker' });
|
|
252
252
|
if (!dryRun) {
|
package/package.json
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seeed-studio/solution-cli",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.2",
|
|
4
|
+
"description": "Installer for the Rust deployment engine and Solution CLI Agent skills (Work Buddy, Claude Code, Codex, CodeBuddy)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/installer.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"solution-cli": "bin/cli.js",
|
|
9
|
-
"sensecraft-
|
|
10
|
-
"sensecraft": "bin/cli.js",
|
|
11
|
-
"sensecraft-engine": "bin/runner.js",
|
|
12
|
-
"sensecraft-skill": "bin/cli.js"
|
|
9
|
+
"sensecraft-engine": "bin/runner.js"
|
|
13
10
|
},
|
|
14
11
|
"publishConfig": {
|
|
15
12
|
"access": "public"
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
3
|
-
description:
|
|
2
|
+
name: solution-cli
|
|
3
|
+
description: 用于客户询盘、客户需求、方案选型、我们能提供什么、怎么回复客户等边缘/IoT 方案咨询,涵盖智慧农业、跌倒检测、楼宇温控、恒温器、传感器及相关硬件。Use for customer inquiries, requirements analysis, solution selection, proposal guidance, edge IoT deployments, hardware compatibility, deployment, and troubleshooting. First search the SenseCraft solution catalog with `solution-cli`; do not trigger for general business writing, generic proposal drafting, or unrelated coding.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# Solution CLI
|
|
7
7
|
|
|
8
|
-
This skill drives the `sensecraft-engine` execution engine and `solution-cli` toolset. It operates across the complete lifecycle: **Solution Consultation ➔ Hardware & Accessory BOM Selection ➔ Local Deployment ➔ Self-Healing Diagnostics**.
|
|
8
|
+
This skill drives the `sensecraft-engine` execution engine and `solution-cli` toolset. It operates across the complete lifecycle: **Solution Consultation ➔ Hardware & Accessory BOM Selection ➔ Local Deployment ➔ Self-Healing Diagnostics**. For Engine-only operations, use the injected absolute Engine path. If the wrapper is not on `PATH`, invoke the CLI as `npx -y --package=@seeed-studio/solution-cli@latest solution-cli <args>`. Keep catalog queries such as `hub` and `product` on `solution-cli`; do not forward them to the Engine.
|
|
9
9
|
|
|
10
10
|
## Workflow Routing & Progressive Disclosure
|
|
11
11
|
|
|
@@ -126,11 +126,25 @@ daemon is a host prerequisite, not evidence that a deployment has passed.
|
|
|
126
126
|
reinstall, use the same solution-cli command; do not reinstall on every
|
|
127
127
|
deployment:
|
|
128
128
|
|
|
129
|
-
**Recommended (Zero-friction via solution-cli,
|
|
129
|
+
**Recommended (Zero-friction via solution-cli, target the current Agent explicitly)**:
|
|
130
130
|
```bash
|
|
131
|
-
npx -y @seeed-studio/solution-cli@latest install -y
|
|
131
|
+
npx -y @seeed-studio/solution-cli@latest install --agent <current-agent-id> -y
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
+
Fill `<current-agent-id>` with the actual host ID: `workbuddy`, `claude`,
|
|
135
|
+
`codex`, `codebuddy`, or `antigravity`. The WorkBuddy example is:
|
|
136
|
+
```bash
|
|
137
|
+
npx -y @seeed-studio/solution-cli@latest install --agent workbuddy -y
|
|
138
|
+
```
|
|
139
|
+
An AI agent must use its current host ID; Codex must not hardcode WorkBuddy.
|
|
140
|
+
Use `npx -y @seeed-studio/solution-cli@latest install` for interactive
|
|
141
|
+
selection. When one or more Agents are detected, pressing Enter selects all
|
|
142
|
+
detected Agents; entering the matching number selects one host. In
|
|
143
|
+
non-interactive mode, `install -y` without `--agent` also selects all detected
|
|
144
|
+
Agents when any are detected. If none are detected, these defaults still use
|
|
145
|
+
the CLI's default target set; pass `--agent <agent-id>` to control the scope
|
|
146
|
+
explicitly.
|
|
147
|
+
|
|
134
148
|
The command checks the signed stable Engine on fresh and repeat runs, reuses
|
|
135
149
|
an equal or newer local version, and upgrades an older one. It preserves
|
|
136
150
|
modified/unregistered skills and protected symlinks. Add `--agent ...` for an
|
|
@@ -138,9 +152,8 @@ daemon is a host prerequisite, not evidence that a deployment has passed.
|
|
|
138
152
|
`--force` can re-download equal/older versions and overwrite existing skill
|
|
139
153
|
files, including user modifications; use it only when that overwrite is
|
|
140
154
|
intended. Protected external symlinks are not followed, and it never
|
|
141
|
-
downgrades a newer discovered Engine. Automatic upgrade rules start with
|
|
142
|
-
solution-cli 0.3.1
|
|
143
|
-
At this verification, 0.3.1 is pending publication. Latest/signature failure
|
|
155
|
+
downgrades a newer discovered Engine. Automatic reuse/upgrade rules start with
|
|
156
|
+
publicly published solution-cli 0.3.1. Latest/signature failure
|
|
144
157
|
stops before writes; offline use requires a valid explicit local Engine path.
|
|
145
158
|
|
|
146
159
|
**Fallback (Standalone shell script when Node.js is not present)**:
|
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
| **建筑能耗 / 暖通** | 楼宇能耗、电表、水表、空调节能、HVAC, energy retrofit | `building-energy-retrofit` | `building_energy_management` |
|
|
19
19
|
| **室内外定位 / 资产** | 蓝牙信标、资产定位、人员卡片、防丢、GNSS, tracker, beacon, T1000 | `indoor-outdoor-positioning` | `indoor_positioning_ble_lorawan` |
|
|
20
20
|
|
|
21
|
+
客户询盘、客户需求分析、方案选型、如何回复客户或“我们能提供什么”也属于咨询路由;涉及楼宇温控、恒温器、温度/湿度/空气质量传感器等需求时,先用客户原话和关键技术词搜索方案库。若搜不到匹配结果,明确说明官方方案库缺少现成能力,再给出需定制验证的边界;不要把通用 IoT 能力编造成已有的 thermostat 硬件或现成方案。
|
|
22
|
+
|
|
21
23
|
---
|
|
22
24
|
|
|
23
25
|
## 2. 工具调用标准动作
|
|
@@ -27,6 +29,8 @@
|
|
|
27
29
|
```bash
|
|
28
30
|
solution-cli hub search "<用户关键词>" --limit 5 --json
|
|
29
31
|
```
|
|
32
|
+
- **咨询顺序**:先用用户原话和同义技术词查询,再根据返回的场景与 `diagnostic_playbook` 拆解需求;向用户确认点位、协议、供电、通信、控制闭环和预算等关键参数后,给出可提供的方案、硬件方向和缺口说明。
|
|
33
|
+
- **交付边界**:咨询阶段只做检索、需求澄清和方案建议,不自动执行 `deploy`;用户确认硬件和部署目标后,再转入硬件校验或部署流程。
|
|
30
34
|
- **输出结果说明**:
|
|
31
35
|
- `Scenario`:业务场景、痛点、成效、官方场景落地页(`landing_url`);
|
|
32
36
|
- `Reference Design`:技术路线、预设模式 presets、开发 wiki(`wiki_url`)、官方方案落地页(`landing_url`)、源码仓库(`repo_url`);
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|