@seeed-studio/solution-cli 0.3.0 → 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 +35 -15
- package/bin/cli.js +104 -38
- package/bin/runner.js +1 -1
- package/catalog/knowledge-core.json +666 -144
- package/docs/cli-guide.md +58 -17
- package/lib/agent.js +5 -5
- package/lib/detector.js +3 -3
- package/lib/downloader.js +85 -21
- package/lib/installer.js +88 -53
- package/lib/knowledge.js +141 -17
- package/lib/ledger.js +1 -1
- package/package.json +3 -6
- package/skills/{sensecraft → solution-cli}/SKILL.md +40 -14
- package/skills/{sensecraft → solution-cli}/references/consult-and-select.md +4 -0
- package/skills/{sensecraft → solution-cli}/references/device-management.md +45 -13
- package/skills/{sensecraft → solution-cli}/references/diagnose.md +1 -1
- package/skills/{sensecraft → solution-cli}/references/secondary-development.md +2 -5
- /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/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/verify.md +0 -0
package/README.md
CHANGED
|
@@ -10,26 +10,46 @@ Compatible with **Claude Code, Codex, Google Antigravity (AGY), Work Buddy, and
|
|
|
10
10
|
|
|
11
11
|
## 1. Quick Start & Agent Installation
|
|
12
12
|
|
|
13
|
-
Install the underlying engine and configure the AI Agent Skill with
|
|
13
|
+
Install the underlying engine and configure the AI Agent Skill with one command:
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
npx -y @seeed-studio/solution-cli@latest install --agent workbuddy -y
|
|
17
|
+
```
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
npx @seeed-studio/solution-cli install
|
|
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
|
+
|
|
28
|
+
The same command is safe to repeat. It checks the signed stable Engine release,
|
|
29
|
+
reuses an equal or newer local Engine, and upgrades an older one. Existing
|
|
30
|
+
modified or unregistered skills and protected symlinks are preserved. Use
|
|
31
|
+
`--agent claude,antigravity` to select agents, or `--engine-path <path>` to pin
|
|
32
|
+
a valid Engine binary. `--force` re-downloads an equal or older Engine and
|
|
33
|
+
overwrites existing skill files, including user modifications; use it only when
|
|
34
|
+
that overwrite is intended. Protected external symlinks are not followed, and
|
|
35
|
+
it never downgrades a newer discovered Engine.
|
|
36
|
+
|
|
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
|
|
39
|
+
Engine or skills; an offline host must use a valid explicit local Engine path.
|
|
40
|
+
|
|
41
|
+
The interactive form remains available when prompts are wanted:
|
|
21
42
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
solution-cli install -y
|
|
43
|
+
```bash
|
|
44
|
+
npx -y @seeed-studio/solution-cli@latest install
|
|
25
45
|
```
|
|
26
46
|
|
|
27
47
|
### Supported AI Agent Harnesses
|
|
28
|
-
- **Claude Code**: `~/.claude/skills/
|
|
29
|
-
- **Codex / OpenAI**: `~/.agents/skills/
|
|
30
|
-
- **Google Antigravity (AGY)**: `~/.gemini/config/skills/
|
|
31
|
-
- **Work Buddy / Workbody**: `~/.workbuddy/skills/
|
|
32
|
-
- **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`
|
|
33
53
|
|
|
34
54
|
---
|
|
35
55
|
|
|
@@ -45,7 +65,7 @@ The `solution-cli` provides unified commands for discovery, BOM calculation, dev
|
|
|
45
65
|
| `solution-cli install [--agent <agents>] [-y]` | Inspect host environment, download/verify engine, and install Agent skills. |
|
|
46
66
|
| `solution-cli status` | Inspect installed engine binary, content cache, and configured agent skills. |
|
|
47
67
|
| `solution-cli doctor` | Run pre-flight diagnostics (OS, Docker daemon, serial permissions, PATH, ledger). |
|
|
48
|
-
| `solution-cli uninstall [--agent <agents>]` | Cleanly remove
|
|
68
|
+
| `solution-cli uninstall [--agent <agents>]` | Cleanly remove Solution CLI skills using the installation ledger. |
|
|
49
69
|
| `sensecraft-engine <subcommand>` | Direct proxy to the underlying high-performance Rust execution engine. |
|
|
50
70
|
|
|
51
71
|
---
|
|
@@ -110,7 +130,7 @@ Once installed, your AI Agent gains deep domain knowledge as an Edge IoT Solutio
|
|
|
110
130
|
> 1. 提供方案对应的官方 GitHub 开源仓库地址;
|
|
111
131
|
> 2. 指导用户克隆到本地工作区;
|
|
112
132
|
> 3. 指导通过 TensorRT `trtexec` 完成端侧引擎转换,并在 `docker-compose.override.yml` 中挂载自定义模型;
|
|
113
|
-
> 4. 使用 `sensecraft-engine deploy --solutions-dir ./solutions` 进行本地快速调测。
|
|
133
|
+
> 4. 使用 `sensecraft-engine deploy <id> --solutions-dir ./solutions` 进行本地快速调测。
|
|
114
134
|
|
|
115
135
|
---
|
|
116
136
|
|
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
|
|
@@ -42,7 +41,7 @@ Options:
|
|
|
42
41
|
-y, --yes Accept default detected selections non-interactively
|
|
43
42
|
--dry-run Simulate operations without making changes to filesystem
|
|
44
43
|
--skip-content Skip pulling IoT solution packages from CDN
|
|
45
|
-
--force
|
|
44
|
+
--force Re-download equal/older stable Engine and overwrite existing skill files, including local modifications; never downgrade a newer local Engine
|
|
46
45
|
--json Output machine-readable JSON (supported by all query/diagnostic commands)
|
|
47
46
|
--locale <zh|en> Language for hub and product results (default: zh)
|
|
48
47
|
--limit <num> Maximum results for search (default: 5)
|
|
@@ -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
|
|