tirtc-device-builder 0.8.1 → 0.9.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/.codex-plugin/plugin.json +1 -1
- package/CHANGELOG.md +9 -0
- package/README.md +51 -16
- package/bin/agent-clients.js +141 -0
- package/bin/setup-esp32.js +43 -17
- package/bin/tirtc-device-builder.js +42 -17
- package/package.json +6 -2
- package/skills/tirtc-esp32-builder/USAGE.md +8 -7
- package/skills/tirtc-esp32-builder/VERSION +1 -1
- package/skills/tirtc-esp32-builder/assets/developer-intake-prompt.md +1 -1
- package/skills/tirtc-esp32-builder/assets/lckfb-szpi-esp32s3-portable-prompt.md +10 -8
- package/skills/tirtc-esp32-builder/references/environment.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
This project follows Semantic Versioning.
|
|
4
4
|
|
|
5
|
+
## 0.9.0
|
|
6
|
+
|
|
7
|
+
- Add native Skill-directory installation for Codex, Claude Code, OpenCode,
|
|
8
|
+
Gemini CLI, GitHub Copilot, Qwen Code, Windsurf Cascade, Cline, and Kiro.
|
|
9
|
+
- Add `--client` support to both `install` and the resumable `setup` workflow,
|
|
10
|
+
plus a `clients` command that reports resolved user directories.
|
|
11
|
+
- Keep one portable `SKILL.md` and supporting resource tree across clients,
|
|
12
|
+
while preserving explicit replacement and hardware-operation approvals.
|
|
13
|
+
|
|
5
14
|
## 0.8.1
|
|
6
15
|
|
|
7
16
|
- Separate rapid `idf.py flash` iteration from portable evidence-bundle export,
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# TiRTC Device Builder
|
|
2
2
|
|
|
3
|
-
TiRTC Device Builder 用于把 ESP32-S3/ESP32-P4 开发板接入 TiRTC。输入可以只有开发板型号,也可以包含原理图、BSP、引脚表和外设示例。安装后的
|
|
3
|
+
TiRTC Device Builder 用于把 ESP32-S3/ESP32-P4 开发板接入 TiRTC。输入可以只有开发板型号,也可以包含原理图、BSP、引脚表和外设示例。安装后的 Agent Skill 会先检查环境、整理有依据的硬件事实,再生成或移植独立的 ESP-IDF 工程并完成板级适配和编译。烧录和实机验证只有在开发者明确给出目标串口并授权后才会执行。
|
|
4
4
|
|
|
5
5
|
当前仓库提供一个 Skill:
|
|
6
6
|
|
|
@@ -43,9 +43,15 @@ npm --version
|
|
|
43
43
|
npx --yes tirtc-device-builder@latest setup esp32 --install
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
+
默认安装到 Codex。使用其他客户端时增加 `--client`,例如:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npx --yes tirtc-device-builder@latest setup esp32 --install --client qwen-code
|
|
50
|
+
```
|
|
51
|
+
|
|
46
52
|
这条命令会:
|
|
47
53
|
|
|
48
|
-
- 把 `tirtc-esp32-builder`
|
|
54
|
+
- 把 `tirtc-esp32-builder` 安装到所选 Agent 客户端的 Skill 目录;
|
|
49
55
|
- 下载 ESP32 Device Kit 并校验 SHA-256;
|
|
50
56
|
- 复用当前可用的 ESP-IDF 5.5.x,找不到时安装 ESP-IDF 5.5.4;
|
|
51
57
|
- 安装 Espressif 管理的 ESP32-S3 工具链;
|
|
@@ -59,21 +65,21 @@ npx --yes tirtc-device-builder@latest setup esp32 --install
|
|
|
59
65
|
```text
|
|
60
66
|
OVERALL: PASS
|
|
61
67
|
SETUP: READY
|
|
62
|
-
Start a new Codex session
|
|
68
|
+
Start a new Codex session, then ask it to use tirtc-esp32-builder.
|
|
63
69
|
```
|
|
64
70
|
|
|
65
71
|
如果看到 `OVERALL: NEEDS_SETUP`、`MISS` 或 `FAIL`,先看[常见问题](#常见问题)。
|
|
66
72
|
|
|
67
|
-
### 3. 重新打开
|
|
73
|
+
### 3. 重新打开 Agent 客户端
|
|
68
74
|
|
|
69
|
-
Skill
|
|
75
|
+
Skill 通常在 Agent 会话启动时被发现。安装完成后,关闭当前会话,再打开一个新会话。
|
|
70
76
|
|
|
71
|
-
### 4. 把板卡和目标告诉
|
|
77
|
+
### 4. 把板卡和目标告诉 Agent
|
|
72
78
|
|
|
73
79
|
把你已经掌握的信息填进下面的提示词即可,不用先查齐所有硬件参数。先指定工作区根目录,本地路径尽量相对工作区填写;不确定的内容写“未知”。可直接复制的版本见[开发板接入提示词](skills/tirtc-esp32-builder/assets/developer-intake-prompt.md)。
|
|
74
80
|
|
|
75
81
|
```text
|
|
76
|
-
请使用
|
|
82
|
+
请使用 tirtc-esp32-builder Skill 完成这块开发板的 TiRTC 移植。
|
|
77
83
|
|
|
78
84
|
开发板:
|
|
79
85
|
- 厂商、完整型号、PCB/硬件版本:<填写>
|
|
@@ -339,25 +345,52 @@ tirtc-device-builder setup esp32 --install
|
|
|
339
345
|
|
|
340
346
|
安装命令是 `npm install`,不要写成 `npm --install`。
|
|
341
347
|
|
|
342
|
-
只执行 `npm install --global tirtc-device-builder` 会安装 CLI,不会准备完整开发环境。随后还要运行 `setup esp32 --install`,由它安装
|
|
348
|
+
只执行 `npm install --global tirtc-device-builder` 会安装 CLI,不会准备完整开发环境。随后还要运行 `setup esp32 --install`,由它安装 Agent Skill、下载 Device Kit,并在需要时安装 ESP-IDF。npm 包没有 `preinstall`、`install` 或 `postinstall` 生命周期脚本,因此不会在安装 CLI 时改动这些目录。
|
|
343
349
|
|
|
344
350
|
安装公开包不需要执行 `npm login`;这个命令只和维护者发布新版本有关。
|
|
345
351
|
|
|
346
352
|
### 只安装 Skill
|
|
347
353
|
|
|
348
|
-
如果 ESP-IDF 和 Device Kit 已经由团队统一准备,可以只复制
|
|
354
|
+
如果 ESP-IDF 和 Device Kit 已经由团队统一准备,可以只复制 Agent Skill:
|
|
349
355
|
|
|
350
356
|
```bash
|
|
351
357
|
npx --yes tirtc-device-builder@latest install esp32
|
|
358
|
+
npx --yes tirtc-device-builder@latest install esp32 --client gemini
|
|
352
359
|
```
|
|
353
360
|
|
|
354
361
|
这条命令不安装 ESP-IDF,也不下载 Device Kit。完整的新用户环境仍建议使用 `setup esp32 --install`。
|
|
355
362
|
|
|
363
|
+
### 支持的 Agent 客户端
|
|
364
|
+
|
|
365
|
+
同一个 `tirtc-esp32-builder` Skill 会完整复制到所选客户端的原生目录,不维护客户端专用的内容副本。先用下面的命令查看当前机器解析出的目录:
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
npx --yes tirtc-device-builder@latest clients
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
| `--client` | 客户端 | 默认 Skill 根目录 |
|
|
372
|
+
|---|---|---|
|
|
373
|
+
| `codex` | Codex(默认) | `${CODEX_HOME:-~/.codex}/skills` |
|
|
374
|
+
| `claude-code` | Claude Code | `~/.claude/skills` |
|
|
375
|
+
| `opencode` | OpenCode | `${XDG_CONFIG_HOME:-~/.config}/opencode/skills` |
|
|
376
|
+
| `gemini` | Gemini CLI | `~/.gemini/skills` |
|
|
377
|
+
| `copilot` | GitHub Copilot | `~/.copilot/skills` |
|
|
378
|
+
| `qwen-code` | Qwen Code | `~/.qwen/skills` |
|
|
379
|
+
| `windsurf` | Windsurf Cascade | `~/.codeium/windsurf/skills` |
|
|
380
|
+
| `cline` | Cline | `~/.cline/skills` |
|
|
381
|
+
| `kiro` | Kiro | `~/.kiro/skills` |
|
|
382
|
+
|
|
383
|
+
也可以使用 `claude`、`gemini-cli`、`github-copilot`、`qwen`、`cascade`、`kiro-cli` 等别名。`--skills-dir` 的优先级高于默认目录,适合项目级安装或客户端使用非默认配置目录的情况。
|
|
384
|
+
|
|
385
|
+
`--client` 只选择 Skill 的安装目录和提示文案,不绑定模型服务。DeepSeek、Qwen、GLM、Kimi、OpenAI 或 Claude 等模型仍在对应客户端中配置;只要客户端能发现 Skill 并允许文件、终端等所需工具,就继续使用同一份工作流。
|
|
386
|
+
|
|
387
|
+
Cline 当前还需要在 `Settings → Features → Enable Skills` 中启用实验性 Skills 功能;安装器不会修改客户端自身的权限或功能开关。
|
|
388
|
+
|
|
356
389
|
### 默认目录
|
|
357
390
|
|
|
358
391
|
| 内容 | 默认位置 |
|
|
359
392
|
|---|---|
|
|
360
|
-
|
|
|
393
|
+
| Agent Skill | 上表中所选目录下的 `tirtc-esp32-builder` |
|
|
361
394
|
| 托管根目录 | `~/.tirtc-device-builder` |
|
|
362
395
|
| Device Kit | `~/.tirtc-device-builder/kits/esp32s3/1.1.1` |
|
|
363
396
|
| ESP-IDF | `~/.tirtc-device-builder/esp-idf-v5.5.4` |
|
|
@@ -436,6 +469,7 @@ npx --yes tirtc-device-builder@latest setup esp32
|
|
|
436
469
|
```bash
|
|
437
470
|
npx --yes tirtc-device-builder@latest --help
|
|
438
471
|
npx --yes tirtc-device-builder@latest list
|
|
472
|
+
npx --yes tirtc-device-builder@latest clients
|
|
439
473
|
npx --yes tirtc-device-builder@latest setup esp32 --help
|
|
440
474
|
```
|
|
441
475
|
|
|
@@ -759,15 +793,16 @@ npx --yes tirtc-device-builder@latest setup esp32 --install \
|
|
|
759
793
|
|
|
760
794
|
如果指定目录已存在但内容不完整或版本错误,安装器会拒绝覆盖。换一个空的新路径,或先人工备份原目录。
|
|
761
795
|
|
|
762
|
-
### 安装完成后
|
|
796
|
+
### 安装完成后 Agent 客户端找不到 Skill
|
|
763
797
|
|
|
764
|
-
关闭当前
|
|
798
|
+
关闭当前 Agent 会话并重新打开。先查看客户端目录,再检查对应文件是否存在:
|
|
765
799
|
|
|
766
800
|
```bash
|
|
767
|
-
|
|
801
|
+
npx --yes tirtc-device-builder@latest clients
|
|
802
|
+
ls -l <skills-dir>/tirtc-esp32-builder/SKILL.md
|
|
768
803
|
```
|
|
769
804
|
|
|
770
|
-
|
|
805
|
+
确认安装和启动的是同一个客户端,例如 Qwen Code 要使用 `--client qwen-code`。设置过 `CODEX_HOME`、`XDG_CONFIG_HOME` 或 `--skills-dir` 时,要检查对应目录。项目级目录由客户端自身规则决定,可以用 `--skills-dir` 显式指定。
|
|
771
806
|
|
|
772
807
|
### 已有 Skill,安装器拒绝覆盖
|
|
773
808
|
|
|
@@ -926,8 +961,8 @@ metadata 中的版本、标签、上游 commit 和期望 SHA-256 必须与本地
|
|
|
926
961
|
|
|
927
962
|
```bash
|
|
928
963
|
npm test
|
|
929
|
-
git tag -a v0.
|
|
930
|
-
git push origin v0.
|
|
964
|
+
git tag -a v0.9.0 -m "v0.9.0"
|
|
965
|
+
git push origin v0.9.0
|
|
931
966
|
```
|
|
932
967
|
|
|
933
968
|
不要重复发布已经存在的 npm 版本。版本变化同步更新 `package.json`、`.codex-plugin/plugin.json` 和发布说明。
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
|
|
4
|
+
export const DEFAULT_AGENT_CLIENT = "codex";
|
|
5
|
+
|
|
6
|
+
const CLIENTS = [
|
|
7
|
+
{
|
|
8
|
+
id: "codex",
|
|
9
|
+
displayName: "Codex",
|
|
10
|
+
aliases: ["codex"],
|
|
11
|
+
skillsDir(environment, home) {
|
|
12
|
+
const codexHome = environment.CODEX_HOME
|
|
13
|
+
? resolve(environment.CODEX_HOME)
|
|
14
|
+
: join(home, ".codex");
|
|
15
|
+
return join(codexHome, "skills");
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
id: "claude-code",
|
|
20
|
+
displayName: "Claude Code",
|
|
21
|
+
aliases: ["claude-code", "claude"],
|
|
22
|
+
skillsDir(_environment, home) {
|
|
23
|
+
return join(home, ".claude", "skills");
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: "opencode",
|
|
28
|
+
displayName: "OpenCode",
|
|
29
|
+
aliases: ["opencode", "open-code"],
|
|
30
|
+
skillsDir(environment, home) {
|
|
31
|
+
const configHome = environment.XDG_CONFIG_HOME
|
|
32
|
+
? resolve(environment.XDG_CONFIG_HOME)
|
|
33
|
+
: join(home, ".config");
|
|
34
|
+
return join(configHome, "opencode", "skills");
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: "gemini",
|
|
39
|
+
displayName: "Gemini CLI",
|
|
40
|
+
aliases: ["gemini", "gemini-cli"],
|
|
41
|
+
skillsDir(_environment, home) {
|
|
42
|
+
return join(home, ".gemini", "skills");
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "copilot",
|
|
47
|
+
displayName: "GitHub Copilot",
|
|
48
|
+
aliases: ["copilot", "github-copilot"],
|
|
49
|
+
skillsDir(_environment, home) {
|
|
50
|
+
return join(home, ".copilot", "skills");
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "qwen-code",
|
|
55
|
+
displayName: "Qwen Code",
|
|
56
|
+
aliases: ["qwen-code", "qwen"],
|
|
57
|
+
skillsDir(_environment, home) {
|
|
58
|
+
return join(home, ".qwen", "skills");
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "windsurf",
|
|
63
|
+
displayName: "Windsurf Cascade",
|
|
64
|
+
aliases: ["windsurf", "cascade"],
|
|
65
|
+
skillsDir(_environment, home) {
|
|
66
|
+
return join(home, ".codeium", "windsurf", "skills");
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: "cline",
|
|
71
|
+
displayName: "Cline",
|
|
72
|
+
aliases: ["cline"],
|
|
73
|
+
activationNote:
|
|
74
|
+
"Cline may require Settings > Features > Enable Skills before discovery.",
|
|
75
|
+
skillsDir(_environment, home) {
|
|
76
|
+
return join(home, ".cline", "skills");
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
id: "kiro",
|
|
81
|
+
displayName: "Kiro",
|
|
82
|
+
aliases: ["kiro", "kiro-cli"],
|
|
83
|
+
skillsDir(_environment, home) {
|
|
84
|
+
return join(home, ".kiro", "skills");
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
const CLIENT_BY_ALIAS = new Map(
|
|
90
|
+
CLIENTS.flatMap((client) =>
|
|
91
|
+
client.aliases.map((alias) => [alias, client]),
|
|
92
|
+
),
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
function userHome(environment) {
|
|
96
|
+
if (process.platform === "win32") {
|
|
97
|
+
if (environment.USERPROFILE) {
|
|
98
|
+
return resolve(environment.USERPROFILE);
|
|
99
|
+
}
|
|
100
|
+
if (environment.HOMEDRIVE && environment.HOMEPATH) {
|
|
101
|
+
return resolve(`${environment.HOMEDRIVE}${environment.HOMEPATH}`);
|
|
102
|
+
}
|
|
103
|
+
} else if (environment.HOME) {
|
|
104
|
+
return resolve(environment.HOME);
|
|
105
|
+
}
|
|
106
|
+
return homedir();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function listAgentClients() {
|
|
110
|
+
return CLIENTS;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function resolveAgentClient(identifier) {
|
|
114
|
+
return CLIENT_BY_ALIAS.get(String(identifier).trim().toLowerCase()) ?? null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function requireAgentClient(identifier) {
|
|
118
|
+
const client = resolveAgentClient(identifier);
|
|
119
|
+
if (!client) {
|
|
120
|
+
throw new Error(
|
|
121
|
+
`unsupported client: ${identifier}; supported clients: ${CLIENTS.map((item) => item.id).join(", ")}`,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
return client;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function defaultSkillsDir(client, environment = process.env) {
|
|
128
|
+
const resolvedClient =
|
|
129
|
+
typeof client === "string" ? requireAgentClient(client) : client;
|
|
130
|
+
return resolvedClient.skillsDir(environment, userHome(environment));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function clientSessionHint(client, skillName) {
|
|
134
|
+
const lines = [
|
|
135
|
+
`Start a new ${client.displayName} session, then ask it to use ${skillName}.`,
|
|
136
|
+
];
|
|
137
|
+
if (client.activationNote) {
|
|
138
|
+
lines.push(client.activationNote);
|
|
139
|
+
}
|
|
140
|
+
return lines.join("\n");
|
|
141
|
+
}
|
package/bin/setup-esp32.js
CHANGED
|
@@ -10,6 +10,13 @@ import {
|
|
|
10
10
|
} from "node:fs";
|
|
11
11
|
import { homedir } from "node:os";
|
|
12
12
|
import { delimiter, dirname, join, resolve } from "node:path";
|
|
13
|
+
import {
|
|
14
|
+
clientSessionHint,
|
|
15
|
+
DEFAULT_AGENT_CLIENT,
|
|
16
|
+
defaultSkillsDir,
|
|
17
|
+
listAgentClients,
|
|
18
|
+
requireAgentClient,
|
|
19
|
+
} from "./agent-clients.js";
|
|
13
20
|
import { ESP32_KIT } from "./esp32-kit-metadata.js";
|
|
14
21
|
|
|
15
22
|
const EXPECTED_IDF_LINE = "5.5";
|
|
@@ -43,10 +50,10 @@ function setupRootFrom(environment) {
|
|
|
43
50
|
);
|
|
44
51
|
}
|
|
45
52
|
|
|
46
|
-
function takeValue(args, index, option) {
|
|
53
|
+
function takeValue(args, index, option, kind = "a path") {
|
|
47
54
|
const value = args[index + 1];
|
|
48
55
|
if (!value || value.startsWith("--")) {
|
|
49
|
-
throw new Error(`${option} requires
|
|
56
|
+
throw new Error(`${option} requires ${kind}`);
|
|
50
57
|
}
|
|
51
58
|
return value;
|
|
52
59
|
}
|
|
@@ -54,13 +61,15 @@ function takeValue(args, index, option) {
|
|
|
54
61
|
export function parseSetupOptions(args, defaults = {}) {
|
|
55
62
|
const environment = defaults.environment ?? process.env;
|
|
56
63
|
const options = {
|
|
64
|
+
client:
|
|
65
|
+
defaults.client ?? requireAgentClient(DEFAULT_AGENT_CLIENT),
|
|
57
66
|
forceSkill: false,
|
|
58
67
|
help: false,
|
|
59
68
|
idfDir: null,
|
|
60
69
|
install: false,
|
|
61
70
|
kitArchive: null,
|
|
62
71
|
rootDir: setupRootFrom(environment),
|
|
63
|
-
skillsDir:
|
|
72
|
+
skillsDir: null,
|
|
64
73
|
thingConnectRoot: null,
|
|
65
74
|
};
|
|
66
75
|
|
|
@@ -78,6 +87,13 @@ export function parseSetupOptions(args, defaults = {}) {
|
|
|
78
87
|
options.forceSkill = true;
|
|
79
88
|
continue;
|
|
80
89
|
}
|
|
90
|
+
if (argument === "--client") {
|
|
91
|
+
options.client = requireAgentClient(
|
|
92
|
+
takeValue(args, index, argument, "a name"),
|
|
93
|
+
);
|
|
94
|
+
index += 1;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
81
97
|
if (
|
|
82
98
|
argument === "--root" ||
|
|
83
99
|
argument === "--skills-dir" ||
|
|
@@ -103,9 +119,7 @@ export function parseSetupOptions(args, defaults = {}) {
|
|
|
103
119
|
throw new Error(`unknown setup option: ${argument}`);
|
|
104
120
|
}
|
|
105
121
|
|
|
106
|
-
|
|
107
|
-
throw new Error("setup requires a default skills directory");
|
|
108
|
-
}
|
|
122
|
+
options.skillsDir ??= defaultSkillsDir(options.client, environment);
|
|
109
123
|
if (options.forceSkill && !options.install) {
|
|
110
124
|
throw new Error("--force-skill requires --install");
|
|
111
125
|
}
|
|
@@ -123,8 +137,9 @@ Usage:
|
|
|
123
137
|
|
|
124
138
|
Options:
|
|
125
139
|
--install Install missing user-space components
|
|
140
|
+
--client <name> Agent client (default: codex)
|
|
126
141
|
--root <path> Managed files (default: ~/.tirtc-device-builder)
|
|
127
|
-
--skills-dir <path>
|
|
142
|
+
--skills-dir <path> Override the selected client's Skill directory
|
|
128
143
|
--thing-connect-root <path> Reuse an existing Device Kit or legacy workspace
|
|
129
144
|
--kit-archive <path> Install from a local verified Kit archive
|
|
130
145
|
--idf-dir <path> Reuse or install ESP-IDF at this path
|
|
@@ -133,12 +148,13 @@ Options:
|
|
|
133
148
|
|
|
134
149
|
Examples:
|
|
135
150
|
npx tirtc-device-builder setup esp32
|
|
136
|
-
npx tirtc-device-builder setup esp32 --install
|
|
151
|
+
npx tirtc-device-builder setup esp32 --install --client gemini
|
|
137
152
|
npx tirtc-device-builder setup esp32 --install --root /opt/tirtc-dev
|
|
138
153
|
|
|
139
154
|
Check mode is read-only. --install downloads the pinned ESP32 Device Kit,
|
|
140
155
|
may clone ESP-IDF v5.5.4, runs Espressif's user-space tool installer, and
|
|
141
|
-
installs the
|
|
156
|
+
installs the Agent Skill. It does not run sudo or edit shell profiles.
|
|
157
|
+
Supported clients: ${listAgentClients().map((client) => client.id).join(", ")}.`);
|
|
142
158
|
}
|
|
143
159
|
|
|
144
160
|
function printCheck(status, name, detail) {
|
|
@@ -420,6 +436,7 @@ function writeManagedEnvironment(context, packageVersion) {
|
|
|
420
436
|
device_kit_version: context.deviceKit.version,
|
|
421
437
|
device_kit_root: context.thingConnectRoot,
|
|
422
438
|
thing_connect_root: context.thingConnectRoot,
|
|
439
|
+
client: context.client.id,
|
|
423
440
|
skills_dir: context.skillsDir,
|
|
424
441
|
};
|
|
425
442
|
writeAtomic(
|
|
@@ -542,6 +559,7 @@ function setupContext(options, runtime) {
|
|
|
542
559
|
const skillVersion = readSkillVersion(skillTarget);
|
|
543
560
|
return {
|
|
544
561
|
activeIdf: active,
|
|
562
|
+
client: options.client,
|
|
545
563
|
configPath,
|
|
546
564
|
idf,
|
|
547
565
|
idfDir,
|
|
@@ -569,8 +587,8 @@ function printState(context, runtime) {
|
|
|
569
587
|
printCheck("INFO", "setup root", context.rootDir);
|
|
570
588
|
printCheck(
|
|
571
589
|
context.skillReady ? "PASS" : "MISS",
|
|
572
|
-
"
|
|
573
|
-
`${context.skillTarget} (version ${
|
|
590
|
+
"Agent Skill",
|
|
591
|
+
`${context.client.displayName}: ${context.skillTarget} (version ${
|
|
574
592
|
context.skillVersion || "missing"
|
|
575
593
|
}; expected ${runtime.packageVersion})`,
|
|
576
594
|
);
|
|
@@ -639,13 +657,13 @@ function installSkill(options, context, runtime) {
|
|
|
639
657
|
const present = existsSync(join(context.skillTarget, "SKILL.md"));
|
|
640
658
|
if (present && context.skillReady && !options.forceSkill) {
|
|
641
659
|
console.log(
|
|
642
|
-
`SKIP
|
|
660
|
+
`SKIP ${context.client.displayName} Skill ${runtime.packageVersion} already exists: ${context.skillTarget}`,
|
|
643
661
|
);
|
|
644
662
|
return;
|
|
645
663
|
}
|
|
646
664
|
if (present && !options.forceSkill) {
|
|
647
665
|
throw new Error(
|
|
648
|
-
|
|
666
|
+
`${context.client.displayName} Skill at ${context.skillTarget} has version ${
|
|
649
667
|
context.skillVersion || "missing"
|
|
650
668
|
}, expected ${runtime.packageVersion}; rerun with --force-skill to replace it`,
|
|
651
669
|
);
|
|
@@ -654,6 +672,8 @@ function installSkill(options, context, runtime) {
|
|
|
654
672
|
runtime.cliPath,
|
|
655
673
|
"install",
|
|
656
674
|
runtime.platform.name,
|
|
675
|
+
"--client",
|
|
676
|
+
context.client.id,
|
|
657
677
|
"--skills-dir",
|
|
658
678
|
options.skillsDir,
|
|
659
679
|
];
|
|
@@ -830,8 +850,8 @@ export function runEsp32Setup(args, input) {
|
|
|
830
850
|
let options;
|
|
831
851
|
try {
|
|
832
852
|
options = parseSetupOptions(args, {
|
|
853
|
+
client: input.defaultClient,
|
|
833
854
|
environment: runtime.environment,
|
|
834
|
-
skillsDir: input.defaultSkillsDir,
|
|
835
855
|
});
|
|
836
856
|
} catch (error) {
|
|
837
857
|
console.error(
|
|
@@ -849,8 +869,12 @@ export function runEsp32Setup(args, input) {
|
|
|
849
869
|
if (!options.install) {
|
|
850
870
|
if (!isReady(context)) {
|
|
851
871
|
console.log("OVERALL: NEEDS_SETUP");
|
|
872
|
+
const clientOption =
|
|
873
|
+
context.client.id === "codex"
|
|
874
|
+
? ""
|
|
875
|
+
: ` --client ${context.client.id}`;
|
|
852
876
|
console.log(
|
|
853
|
-
`NEXT: npx tirtc-device-builder@${runtime.packageVersion} setup esp32 --install`,
|
|
877
|
+
`NEXT: npx tirtc-device-builder@${runtime.packageVersion} setup esp32 --install${clientOption}`,
|
|
854
878
|
);
|
|
855
879
|
return 1;
|
|
856
880
|
}
|
|
@@ -867,7 +891,9 @@ export function runEsp32Setup(args, input) {
|
|
|
867
891
|
return 1;
|
|
868
892
|
}
|
|
869
893
|
console.log("INSTALL PLAN:");
|
|
870
|
-
console.log(
|
|
894
|
+
console.log(
|
|
895
|
+
` Skill: ${context.skillTarget} (${context.client.displayName})`,
|
|
896
|
+
);
|
|
871
897
|
console.log(` Device Kit: ${context.thingConnectRoot} (${ESP32_KIT.version})`);
|
|
872
898
|
console.log(` ESP-IDF: ${context.idfDir} (${PINNED_IDF_VERSION})`);
|
|
873
899
|
console.log(` IDF tools: ${context.idfToolsPath || "existing default"}`);
|
|
@@ -917,6 +943,6 @@ export function runEsp32Setup(args, input) {
|
|
|
917
943
|
}
|
|
918
944
|
console.log("SETUP: READY");
|
|
919
945
|
console.log(`Environment helper: ${join(context.rootDir, "env.sh")}`);
|
|
920
|
-
console.log(
|
|
946
|
+
console.log(clientSessionHint(context.client, runtime.platform.skill));
|
|
921
947
|
return 0;
|
|
922
948
|
}
|
|
@@ -9,9 +9,15 @@ import {
|
|
|
9
9
|
renameSync,
|
|
10
10
|
rmSync,
|
|
11
11
|
} from "node:fs";
|
|
12
|
-
import { homedir } from "node:os";
|
|
13
12
|
import { dirname, join, resolve } from "node:path";
|
|
14
13
|
import { fileURLToPath } from "node:url";
|
|
14
|
+
import {
|
|
15
|
+
clientSessionHint,
|
|
16
|
+
DEFAULT_AGENT_CLIENT,
|
|
17
|
+
defaultSkillsDir,
|
|
18
|
+
listAgentClients,
|
|
19
|
+
requireAgentClient,
|
|
20
|
+
} from "./agent-clients.js";
|
|
15
21
|
import { runEsp32Setup } from "./setup-esp32.js";
|
|
16
22
|
|
|
17
23
|
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
@@ -35,7 +41,8 @@ function printHelp() {
|
|
|
35
41
|
|
|
36
42
|
Usage:
|
|
37
43
|
tirtc-device-builder list
|
|
38
|
-
tirtc-device-builder
|
|
44
|
+
tirtc-device-builder clients
|
|
45
|
+
tirtc-device-builder install <platform> [--client <name>] [--skills-dir <path>] [--force]
|
|
39
46
|
tirtc-device-builder setup <platform> [setup options]
|
|
40
47
|
tirtc-device-builder doctor <platform> [doctor options]
|
|
41
48
|
tirtc-device-builder boards <platform> <list|validate|match|init-identity|candidate> [options]
|
|
@@ -46,15 +53,18 @@ Platforms:
|
|
|
46
53
|
|
|
47
54
|
Examples:
|
|
48
55
|
npx tirtc-device-builder install esp32
|
|
56
|
+
npx tirtc-device-builder install esp32 --client qwen-code
|
|
49
57
|
npx tirtc-device-builder setup esp32
|
|
50
|
-
npx tirtc-device-builder setup esp32 --install
|
|
58
|
+
npx tirtc-device-builder setup esp32 --install --client gemini
|
|
51
59
|
npx tirtc-device-builder install esp32 --skills-dir /absolute/path/skills
|
|
52
60
|
npx tirtc-device-builder doctor esp32 --project /absolute/path/project
|
|
53
61
|
npx tirtc-device-builder boards esp32 match --identity ./board-identity.json
|
|
54
62
|
|
|
55
|
-
Install defaults to
|
|
56
|
-
|
|
57
|
-
|
|
63
|
+
Install defaults to the selected client's user Skill directory; Codex is the
|
|
64
|
+
default client. Run "clients" to list supported names and resolved directories.
|
|
65
|
+
Existing skills are preserved unless --force is explicitly supplied. Setup
|
|
66
|
+
checks are read-only; setup --install installs missing user-space components
|
|
67
|
+
without running sudo.`);
|
|
58
68
|
}
|
|
59
69
|
|
|
60
70
|
function fail(message) {
|
|
@@ -71,17 +81,11 @@ function resolvePlatform(identifier) {
|
|
|
71
81
|
return null;
|
|
72
82
|
}
|
|
73
83
|
|
|
74
|
-
function defaultSkillsDir() {
|
|
75
|
-
const codexHome = process.env.CODEX_HOME
|
|
76
|
-
? resolve(process.env.CODEX_HOME)
|
|
77
|
-
: join(homedir(), ".codex");
|
|
78
|
-
return join(codexHome, "skills");
|
|
79
|
-
}
|
|
80
|
-
|
|
81
84
|
function parseInstallOptions(args) {
|
|
82
85
|
const options = {
|
|
86
|
+
client: requireAgentClient(DEFAULT_AGENT_CLIENT),
|
|
83
87
|
force: false,
|
|
84
|
-
skillsDir:
|
|
88
|
+
skillsDir: null,
|
|
85
89
|
};
|
|
86
90
|
|
|
87
91
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -90,6 +94,15 @@ function parseInstallOptions(args) {
|
|
|
90
94
|
options.force = true;
|
|
91
95
|
continue;
|
|
92
96
|
}
|
|
97
|
+
if (argument === "--client") {
|
|
98
|
+
const value = args[index + 1];
|
|
99
|
+
if (!value || value.startsWith("--")) {
|
|
100
|
+
throw new Error("--client requires a name");
|
|
101
|
+
}
|
|
102
|
+
options.client = requireAgentClient(value);
|
|
103
|
+
index += 1;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
93
106
|
if (argument === "--skills-dir") {
|
|
94
107
|
const value = args[index + 1];
|
|
95
108
|
if (!value || value.startsWith("--")) {
|
|
@@ -102,6 +115,7 @@ function parseInstallOptions(args) {
|
|
|
102
115
|
throw new Error(`unknown install option: ${argument}`);
|
|
103
116
|
}
|
|
104
117
|
|
|
118
|
+
options.skillsDir ??= defaultSkillsDir(options.client);
|
|
105
119
|
return options;
|
|
106
120
|
}
|
|
107
121
|
|
|
@@ -151,8 +165,10 @@ function installSkill(platform, options) {
|
|
|
151
165
|
if (movedExisting && existsSync(backup)) {
|
|
152
166
|
rmSync(backup, { force: true, recursive: true });
|
|
153
167
|
}
|
|
154
|
-
console.log(
|
|
155
|
-
|
|
168
|
+
console.log(
|
|
169
|
+
`Installed ${platform.skill} ${PACKAGE.version} for ${options.client.displayName} to ${target}`,
|
|
170
|
+
);
|
|
171
|
+
console.log(clientSessionHint(options.client, platform.skill));
|
|
156
172
|
}
|
|
157
173
|
|
|
158
174
|
function runDoctor(platform, args) {
|
|
@@ -214,6 +230,15 @@ function main(args) {
|
|
|
214
230
|
}
|
|
215
231
|
return 0;
|
|
216
232
|
}
|
|
233
|
+
if (args[0] === "clients") {
|
|
234
|
+
for (const client of listAgentClients()) {
|
|
235
|
+
const marker = client.id === DEFAULT_AGENT_CLIENT ? " (default)" : "";
|
|
236
|
+
console.log(
|
|
237
|
+
`${client.id}\t${client.displayName}${marker}\t${defaultSkillsDir(client)}`,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
return 0;
|
|
241
|
+
}
|
|
217
242
|
|
|
218
243
|
const [command, identifier, ...rest] = args;
|
|
219
244
|
if (
|
|
@@ -244,7 +269,7 @@ function main(args) {
|
|
|
244
269
|
}
|
|
245
270
|
return runEsp32Setup(rest, {
|
|
246
271
|
cliPath: fileURLToPath(import.meta.url),
|
|
247
|
-
|
|
272
|
+
defaultClient: requireAgentClient(DEFAULT_AGENT_CLIENT),
|
|
248
273
|
packageRoot: PACKAGE_ROOT,
|
|
249
274
|
packageVersion: PACKAGE.version,
|
|
250
275
|
platform,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tirtc-device-builder",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Install and run TiRTC device-development
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "Install and run TiRTC device-development Agent Skills across popular coding clients.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "TangeAI",
|
|
@@ -30,6 +30,10 @@
|
|
|
30
30
|
},
|
|
31
31
|
"keywords": [
|
|
32
32
|
"codex",
|
|
33
|
+
"agent-skills",
|
|
34
|
+
"claude-code",
|
|
35
|
+
"gemini-cli",
|
|
36
|
+
"qwen-code",
|
|
33
37
|
"skill",
|
|
34
38
|
"tirtc",
|
|
35
39
|
"esp32",
|
|
@@ -5,14 +5,15 @@
|
|
|
5
5
|
```bash
|
|
6
6
|
npx tirtc-device-builder@latest setup esp32
|
|
7
7
|
npx tirtc-device-builder@latest setup esp32 --install
|
|
8
|
+
npx tirtc-device-builder@latest clients
|
|
8
9
|
```
|
|
9
10
|
|
|
10
|
-
第一条命令只检查;第二条命令自动安装用户目录内缺失的 Skill、带校验的 ESP32 Device Kit、ESP-IDF 5.5.4 和 ESP32-S3 工具链,最后复跑 Doctor。它不执行 `sudo`,也不修改 shell
|
|
11
|
+
第一条命令只检查;第二条命令自动安装用户目录内缺失的 Skill、带校验的 ESP32 Device Kit、ESP-IDF 5.5.4 和 ESP32-S3 工具链,最后复跑 Doctor。它不执行 `sudo`,也不修改 shell 配置。默认客户端是 Codex;Gemini CLI、GitHub Copilot、Qwen Code、Windsurf、Cline、Kiro、Claude Code 和 OpenCode 可通过 `--client <name>` 选择,第三条命令会列出名称和实际安装目录。安装完成后重新启动所选 Agent 客户端。
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
安装后可直接要求 Agent 使用该 Skill:
|
|
13
14
|
|
|
14
15
|
```text
|
|
15
|
-
|
|
16
|
+
请使用 tirtc-esp32-builder Skill。
|
|
16
17
|
|
|
17
18
|
开发板:<厂商、完整型号、PCB 版本>
|
|
18
19
|
资料与实物对应:<是/否/未知>
|
|
@@ -48,24 +49,24 @@ printf '%s\n' "$TIRTC_THING_CONNECT_ROOT"
|
|
|
48
49
|
只有板卡型号:
|
|
49
50
|
|
|
50
51
|
```text
|
|
51
|
-
|
|
52
|
+
请使用 tirtc-esp32-builder Skill 分析 <厂商> <型号> <硬件版本>,目标是 H5 实时视频、talkback 和 AI 对讲。先输出缺失资料与能力结论。
|
|
52
53
|
```
|
|
53
54
|
|
|
54
55
|
提供本地资料:
|
|
55
56
|
|
|
56
57
|
```text
|
|
57
|
-
|
|
58
|
+
请使用 tirtc-esp32-builder Skill、原理图 /path/board.pdf、BSP /path/vendor-project 和一键安装的 Device Kit,为该板生成 TiRTC H5/AI/CALL/VOIP ESP-IDF 工程并编译;AI/CALL/VOIP 必须通过 AEC 门禁。
|
|
58
59
|
```
|
|
59
60
|
|
|
60
61
|
完整实机流程:
|
|
61
62
|
|
|
62
63
|
```text
|
|
63
|
-
|
|
64
|
+
请使用 tirtc-esp32-builder Skill 和 /path/hardware-ir.json 生成工程,编译后烧录到 /dev/ttyACM0,验证绑定、H5 和 AI,并生成 TIRTC_PORTING_REPORT.md。
|
|
64
65
|
```
|
|
65
66
|
|
|
66
67
|
## ESP-IDF 环境检查
|
|
67
68
|
|
|
68
|
-
将 `<skill-dir>`
|
|
69
|
+
将 `<skill-dir>` 替换为 `clients` 命令显示的 Skill 根目录下的 `tirtc-esp32-builder`,例如 `~/.qwen/skills/tirtc-esp32-builder`。
|
|
69
70
|
|
|
70
71
|
生成工程前检查工作区和开发环境:
|
|
71
72
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.9.0
|
|
@@ -1,28 +1,30 @@
|
|
|
1
|
-
|
|
1
|
+
请使用 tirtc-esp32-builder Skill。
|
|
2
2
|
|
|
3
3
|
请在当前工作区完成一次立创·实战派 ESP32-S3 的 ThingConnect TiRTC clean-room L-1/L0/L1 接入验证。
|
|
4
4
|
|
|
5
5
|
这是 Skill、提示词和开发板资料的独立有效性测试。允许访问外网。
|
|
6
6
|
|
|
7
|
-
前置条件(必须由开发者在启动本次
|
|
7
|
+
前置条件(必须由开发者在启动本次 Agent 会话前完成,不属于本提示词内的操作):
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
10
|
+
export TIRTC_AGENT_CLIENT=codex
|
|
11
|
+
npx --yes tirtc-device-builder@0.9.0 setup esp32 --install \
|
|
12
|
+
--client "$TIRTC_AGENT_CLIENT" --force-skill
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
把 `TIRTC_AGENT_CLIENT` 改为 `clients` 命令列出的目标客户端名称。该命令只允许在当前用户目录安装固定版本的 Skill、managed ESP32 Device Kit、ESP-IDF 和工具链;禁止 sudo、系统级包变更和修改 shell profile。安装完成后,开发者必须关闭原 Agent 会话,再从本 clean-room 工作区启动一个新会话,然后粘贴本提示词。
|
|
14
16
|
|
|
15
17
|
本轮第一步先只读运行:
|
|
16
18
|
|
|
17
19
|
```bash
|
|
18
|
-
npx --yes tirtc-device-builder@0.
|
|
19
|
-
npx --yes tirtc-device-builder@0.
|
|
20
|
+
npx --yes tirtc-device-builder@0.9.0 --version
|
|
21
|
+
npx --yes tirtc-device-builder@0.9.0 setup esp32 --client "$TIRTC_AGENT_CLIENT"
|
|
20
22
|
```
|
|
21
23
|
|
|
22
|
-
必须根据命令的实际输出和本机文件确认:npm 包为 0.
|
|
24
|
+
必须根据命令的实际输出和本机文件确认:npm 包为 0.9.0、已安装 Skill 的 `VERSION` 为 0.9.0、所选 Device Kit 的 `manifest.json` 中 `kit_version` 为 1.1.1,并且 Doctor 对 `--expected-kit 1.1.1` 输出 `OVERALL: PASS`。Plugin manifest 不属于这种 npm 安装方式的运行时前置条件,不得把不可访问的 Plugin 版本当作阻塞项。如果版本不一致、Skill 是在当前会话启动后才安装,或环境检查未通过,停止并报告前置条件不成立;不要在当前会话中替换 Skill 后继续生成工程。
|
|
23
25
|
|
|
24
26
|
工作区与 clean-room 边界:
|
|
25
|
-
- 将启动
|
|
27
|
+
- 将启动 Agent 客户端时的当前目录定义为 `WORKSPACE_ROOT`。
|
|
26
28
|
- 所有工程输入和输出必须位于 `WORKSPACE_ROOT`。
|
|
27
29
|
- 不得读取 `WORKSPACE_ROOT` 之外的项目、兄弟目录、父目录项目、备份、旧构建、日志、报告或 artifact。
|
|
28
30
|
- 如果目标输出目录已经存在,停止并报告 clean-room 条件不成立;不要读取、覆盖或删除该目录。
|
|
@@ -37,7 +37,7 @@ Add `--project <generated-project>` after generation so the doctor can compare `
|
|
|
37
37
|
|
|
38
38
|
The automatic setup downloads a versioned minimal Kit instead of cloning the ThingConnect server repository. A managed Kit is ready only when its generator and SDK files exist and `manifest.json` declares the exact pinned `kit_version`. A stale environment or managed configuration that points at an older Kit is ignored in favor of the current versioned managed path. The setup configuration records the version read from that manifest; it never substitutes the desired version for the actual one.
|
|
39
39
|
|
|
40
|
-
The installed Skill has its own `<skill-dir>/VERSION` marker. Setup requires it to equal the npm package version and reports both values. Replacing a missing or mismatched marker requires the explicit `--install --force-skill` flow and a new
|
|
40
|
+
The installed Skill has its own `<skill-dir>/VERSION` marker. Setup requires it to equal the npm package version and reports both values. Replacing a missing or mismatched marker requires the explicit `--install --force-skill` flow and a new session in the selected Agent client.
|
|
41
41
|
|
|
42
42
|
For an explicitly selected legacy workspace, omit `--expected-kit`; otherwise resolve the generation root in this order:
|
|
43
43
|
|