@remixmate/cli 0.9.22 → 0.9.23

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 CHANGED
@@ -16,15 +16,27 @@ npm install -g @remixmate/cli && remixmate install
16
16
 
17
17
  `npm install` gives you the `remixmate` binary. `remixmate install` is what makes an
18
18
  agent *discover* the skills on its own: it copies the bundled `skills/` into every
19
- agent home it finds Claude Code (`~/.claude/skills`) and Codex (`$CODEX_HOME/skills`,
20
- default `~/.codex/skills`), which share the same `SKILL.md` format. Restart the agent
19
+ agent home it finds. All of these hosts read the same `SKILL.md` format, so one
20
+ `skills/` directory serves all of them:
21
+
22
+ | Host | User-level | Project-level | Override |
23
+ | --- | --- | --- | --- |
24
+ | Claude Code | `~/.claude/skills` | `./.claude/skills` | `CLAUDE_CONFIG_DIR` |
25
+ | Codex | `~/.codex/skills` | — | `CODEX_HOME` |
26
+ | WorkBuddy | `~/.workbuddy/skills` | `./.workbuddy/skills` | — |
27
+ | CodeBuddy | `~/.codebuddy/skills` | `./.codebuddy/skills` | — |
28
+ | Trae / TraeWork | — | `./.trae/skills` | — |
29
+
30
+ Trae CN and TraeWork CN share `~/.trae-cn` and only define a workspace location (`.trae/skills/<name>/`, per its own built-in
31
+ `skill-creator`), so it is installed per project — a plain `remixmate install` reports
32
+ it and tells you to re-run with `--project` inside the repo. Restart the agent
21
33
  afterwards.
22
34
 
23
35
  ```bash
24
- remixmate install --host codex # only one host
25
- remixmate install --project # ./.claude/skills (Claude Code only)
26
- remixmate install --dir <path> # explicit target
27
- remixmate uninstall # remove exactly what was installed
36
+ remixmate install --host workbuddy # only one host
37
+ remixmate install --project # ./<config-dir>/skills (not Codex — it has none)
38
+ remixmate install --dir <path> # explicit target, for a host not listed above
39
+ remixmate uninstall # remove exactly what was installed
28
40
  ```
29
41
 
30
42
  The install is *managed*, not a `cp -R`: each skills directory gets a
package/README.zh-CN.md CHANGED
@@ -15,15 +15,26 @@ npm install -g @remixmate/cli && remixmate install
15
15
  ```
16
16
 
17
17
  `npm install` 装的是 `remixmate` 这个命令;`remixmate install` 才让 agent **自己发现**
18
- 这些 skill —— 它把内置的 `skills/` 铺进检测到的每个 agent 目录:Claude Code
19
- (`~/.claude/skills`)与 Codex(`$CODEX_HOME/skills`,默认 `~/.codex/skills`),两者
20
- 用的是同一套 `SKILL.md` 格式。装完重启 agent 生效。
18
+ 这些 skill —— 它把内置的 `skills/` 铺进检测到的每个 agent 目录。下面这些宿主用的是
19
+ 同一套 `SKILL.md` 格式,所以一份 `skills/` 全都能喂:
20
+
21
+ | 宿主 | 用户级 | 项目级 | 可用环境变量改位置 |
22
+ | --- | --- | --- | --- |
23
+ | Claude Code | `~/.claude/skills` | `./.claude/skills` | `CLAUDE_CONFIG_DIR` |
24
+ | Codex | `~/.codex/skills` | — | `CODEX_HOME` |
25
+ | WorkBuddy | `~/.workbuddy/skills` | `./.workbuddy/skills` | — |
26
+ | CodeBuddy | `~/.codebuddy/skills` | `./.codebuddy/skills` | — |
27
+ | Trae / TraeWork | — | `./.trae/skills` | — |
28
+
29
+ Trae CN 与 TraeWork CN 共用 `~/.trae-cn`,且只定义了工作区位置(`.trae/skills/<name>/`,依据是它自带的 `skill-creator`),
30
+ 所以只能按项目装 —— 直接跑 `remixmate install` 会提示你进项目目录加 `--project` 重跑。
31
+ 装完重启 agent 生效。
21
32
 
22
33
  ```bash
23
- remixmate install --host codex # 只装某一个宿主
24
- remixmate install --project # 装到 ./.claude/skills(仅 Claude Code)
25
- remixmate install --dir <path> # 指定目录
26
- remixmate uninstall # 按装机记录精确卸载
34
+ remixmate install --host workbuddy # 只装某一个宿主
35
+ remixmate install --project # 装到 ./<配置目录>/skills(Codex 没有项目级目录)
36
+ remixmate install --dir <path> # 指定目录,用于上表之外的宿主
37
+ remixmate uninstall # 按装机记录精确卸载
27
38
  ```
28
39
 
29
40
  这里的安装是**受管**的,不是 `cp -R`:每个 skills 目录下会写一份
package/dist/doctor.js CHANGED
@@ -166,7 +166,9 @@ export async function runDoctor(opts = {}) {
166
166
  if (!opts.skipNetwork)
167
167
  checks.push(await checkBackend(apiBaseUrl));
168
168
  for (const c of checks) {
169
- process.stdout.write(`${ICON[c.status]} ${padDisplay(c.name, 14)}${c.detail}\n`);
169
+ // 16 而不是 14:宿主检查名最长是「WorkBuddy skill」,窄一格就会把那两行的
170
+ // detail 列顶出去,报告看起来像是漏了对齐。
171
+ process.stdout.write(`${ICON[c.status]} ${padDisplay(c.name, 16)}${c.detail}\n`);
170
172
  }
171
173
  const failed = checks.filter((c) => c.status === 'fail');
172
174
  if (failed.length === 0) {
package/dist/install.d.ts CHANGED
@@ -21,18 +21,22 @@
21
21
  */
22
22
  export declare const INSTALL_VERB = "install";
23
23
  export declare const UNINSTALL_VERB = "uninstall";
24
- export type HostId = 'claude' | 'codex';
24
+ export type HostId = 'claude' | 'codex' | 'workbuddy' | 'codebuddy' | 'trae';
25
25
  interface Host {
26
26
  id: HostId | 'custom';
27
27
  label: string;
28
28
  /** skill 的父目录 —— 安装写到 <skillsDir>/<skill-name>/。 */
29
29
  skillsDir: string;
30
30
  }
31
+ /** 已检测到、且**有用户级位置**的宿主。 */
32
+ export declare function detectHosts(): Host[];
31
33
  /**
32
- * 检测「这台机器上用了哪些 agent」。判据是配置根目录存在,而不是 skills/ 存在 ——
33
- * 从没装过 skill 的用户 skills/ 本来就没有,那恰恰是最需要装的人。
34
+ * 检测到了、但只能项目级安装的宿主(当前只有 Trae)。
35
+ *
36
+ * 单独拎出来是为了别把它们**静默**跳过:用户装了 Trae 却在全局 install 的输出里
37
+ * 完全看不到它,只会以为这个 CLI 不支持 —— 正是这次 WorkBuddy 的翻车方式。
34
38
  */
35
- export declare function detectHosts(): Host[];
39
+ export declare function projectOnlyHosts(): HostId[];
36
40
  export declare function installUsage(): void;
37
41
  export declare function uninstallUsage(): void;
38
42
  export declare function runInstall(argv: string[]): number;
package/dist/install.js CHANGED
@@ -34,27 +34,118 @@ const PKG_ROOT = path.resolve(__dirname, '..');
34
34
  const RECEIPT = '.remixmate-install.json';
35
35
  const PACKAGE_NAME = '@remixmate/cli';
36
36
  /**
37
- * 宿主的配置根目录。两个 agent 都允许用环境变量改位置,检测必须跟着走 ——
38
- * 否则把 CODEX_HOME 指到别处的用户会看到「未检测到 Codex」。
37
+ * 支持的 agent 宿主。
38
+ *
39
+ * 共同点是 skill 的格式:`<某个目录>/skills/<name>/SKILL.md`,frontmatter 都是
40
+ * name + description —— 一份 skills/ 能喂给所有宿主。这张表记的是各家把那个「某个
41
+ * 目录」放在哪、能不能被环境变量改、有没有用户级 / 项目级。
42
+ *
43
+ * 每一条的依据:
44
+ * - Claude Code / Codex:各自的官方安装位置(Codex 见其内置 skill-installer,
45
+ * 原话是装到 $CODEX_HOME/skills)。
46
+ * - WorkBuddy / CodeBuddy:WorkBuddy 内置的 find-skills skill 给了两条路径,
47
+ * 它按 __CFBundleIdentifier 区分。这里不做那个区分 —— 检测到哪个装哪个,
48
+ * 两个都在就都装,比猜「当前跑在哪个客户端里」稳。
49
+ * - Trae:内置的 skill-creator skill 只给了一个位置 —— 工作区的
50
+ * `.trae/skills/<name>/`。注意它的应用数据目录叫 ~/.trae-cn(国内版),
51
+ * 跟 skill 目录名 .trae 不是一个东西,而且 ~/.trae-cn/skills 并不存在。
52
+ * 没有任何证据表明存在用户级位置,所以 userDirName 留空:Trae 只能项目级装。
53
+ */
54
+ const HOSTS = [
55
+ {
56
+ id: 'claude',
57
+ label: 'Claude Code',
58
+ detectDirNames: ['.claude'],
59
+ homeEnv: 'CLAUDE_CONFIG_DIR',
60
+ userDirName: '.claude',
61
+ projectDirName: '.claude',
62
+ },
63
+ {
64
+ id: 'codex',
65
+ label: 'Codex',
66
+ detectDirNames: ['.codex'],
67
+ homeEnv: 'CODEX_HOME',
68
+ userDirName: '.codex',
69
+ },
70
+ {
71
+ id: 'workbuddy',
72
+ label: 'WorkBuddy',
73
+ detectDirNames: ['.workbuddy'],
74
+ userDirName: '.workbuddy',
75
+ projectDirName: '.workbuddy',
76
+ },
77
+ {
78
+ id: 'codebuddy',
79
+ label: 'CodeBuddy',
80
+ detectDirNames: ['.codebuddy'],
81
+ userDirName: '.codebuddy',
82
+ projectDirName: '.codebuddy',
83
+ },
84
+ {
85
+ id: 'trae',
86
+ // Trae CN 与 TraeWork CN(安装出来叫 TRAE SOLO CN.app,bundle id cn.trae.solo.app)
87
+ // 共用 ~/.trae-cn —— 后者的内置 skill(dynamic-ui 等)就躺在那底下的
88
+ // builtin/*/skills/,所以一条 host 覆盖两个客户端。
89
+ label: 'Trae / TraeWork',
90
+ detectDirNames: ['.trae-cn', '.trae'],
91
+ projectDirName: '.trae',
92
+ },
93
+ ];
94
+ const HOST_IDS = HOSTS.map((h) => h.id);
95
+ function spec(id) {
96
+ return HOSTS.find((h) => h.id === id);
97
+ }
98
+ /**
99
+ * 用户级 skills 目录;宿主没有用户级位置时返回 null。声明了环境变量的宿主要跟着
100
+ * 变量走 —— 否则把 CODEX_HOME 指到别处的用户会看到「未检测到 Codex」。
39
101
  */
40
- function hostHome(id) {
41
- return id === 'claude'
42
- ? process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude')
43
- : process.env.CODEX_HOME || path.join(os.homedir(), '.codex');
102
+ function userSkillsDir(id) {
103
+ const h = spec(id);
104
+ if (!h.userDirName)
105
+ return null;
106
+ const override = h.homeEnv ? process.env[h.homeEnv] : undefined;
107
+ return path.join(override || path.join(os.homedir(), h.userDirName), 'skills');
108
+ }
109
+ /** 检测用的候选目录 —— 存在任意一个就算这台机器上装了这个 agent。 */
110
+ function detectDirs(id) {
111
+ const h = spec(id);
112
+ const override = h.homeEnv ? process.env[h.homeEnv] : undefined;
113
+ if (override)
114
+ return [override];
115
+ return h.detectDirNames.map((d) => path.join(os.homedir(), d));
116
+ }
117
+ function isInstalled(id) {
118
+ return detectDirs(id).some((d) => existsSync(d));
44
119
  }
45
- const HOST_LABEL = {
46
- claude: 'Claude Code',
47
- codex: 'Codex',
48
- };
49
120
  function hostOf(id) {
50
- return { id, label: HOST_LABEL[id], skillsDir: path.join(hostHome(id), 'skills') };
121
+ const dir = userSkillsDir(id);
122
+ return dir ? { id, label: spec(id).label, skillsDir: dir } : null;
123
+ }
124
+ /** 项目级安装目标:当前目录下的 ./<projectDirName>/skills。 */
125
+ function projectHostOf(id) {
126
+ const h = spec(id);
127
+ if (!h.projectDirName)
128
+ return null;
129
+ return {
130
+ id,
131
+ label: `${h.label}(项目级)`,
132
+ skillsDir: path.join(process.cwd(), h.projectDirName, 'skills'),
133
+ };
134
+ }
135
+ /** 已检测到、且**有用户级位置**的宿主。 */
136
+ export function detectHosts() {
137
+ return HOST_IDS.filter(isInstalled)
138
+ .map(hostOf)
139
+ .filter((h) => h !== null);
51
140
  }
52
141
  /**
53
- * 检测「这台机器上用了哪些 agent」。判据是配置根目录存在,而不是 skills/ 存在 ——
54
- * 从没装过 skill 的用户 skills/ 本来就没有,那恰恰是最需要装的人。
142
+ * 检测到了、但只能项目级安装的宿主(当前只有 Trae)。
143
+ *
144
+ * 单独拎出来是为了别把它们**静默**跳过:用户装了 Trae 却在全局 install 的输出里
145
+ * 完全看不到它,只会以为这个 CLI 不支持 —— 正是这次 WorkBuddy 的翻车方式。
55
146
  */
56
- export function detectHosts() {
57
- return ['claude', 'codex'].filter((id) => existsSync(hostHome(id))).map(hostOf);
147
+ export function projectOnlyHosts() {
148
+ return HOST_IDS.filter((id) => isInstalled(id) && !spec(id).userDirName);
58
149
  }
59
150
  function packageVersion() {
60
151
  try {
@@ -91,9 +182,11 @@ function readReceipt(skillsDir) {
91
182
  return null;
92
183
  }
93
184
  }
185
+ const nonNull = (h) => h !== null;
94
186
  function parseArgs(argv, verb) {
95
187
  const out = { hosts: [], force: false, help: false };
96
188
  const picked = [];
189
+ let all = false;
97
190
  let dir = '';
98
191
  let project = false;
99
192
  for (let i = 0; i < argv.length; i++) {
@@ -105,12 +198,14 @@ function parseArgs(argv, verb) {
105
198
  switch (key) {
106
199
  case '--host': {
107
200
  const v = next();
201
+ // `all` 是「所有**适用**的宿主」,不是「表里每一行」—— 展开成后者会让
202
+ // `--host all` 撞上 Trae 这种只有项目级的宿主而整条命令失败。
108
203
  if (v === 'all')
109
- picked.push('claude', 'codex');
110
- else if (v === 'claude' || v === 'codex')
204
+ all = true;
205
+ else if (HOST_IDS.includes(v))
111
206
  picked.push(v);
112
207
  else {
113
- out.unknown = `--host ${v}`;
208
+ out.error = `未知参数: --host ${v}`;
114
209
  return out;
115
210
  }
116
211
  break;
@@ -129,35 +224,64 @@ function parseArgs(argv, verb) {
129
224
  out.help = true;
130
225
  return out;
131
226
  default:
132
- out.unknown = a;
227
+ out.error = `未知参数: ${a}`;
133
228
  return out;
134
229
  }
135
230
  }
136
231
  if (dir) {
137
232
  out.hosts = [{ id: 'custom', label: '自定义目录', skillsDir: path.resolve(dir) }];
233
+ return out;
138
234
  }
139
- else if (project) {
140
- // 只有 Claude Code 有项目级 skill 目录。Codex 的官方安装位置只有
141
- // $CODEX_HOME/skills(见其内置 skill-installer),没有项目级约定,不臆造一个。
142
- out.hosts = [{ id: 'claude', label: 'Claude Code(项目级)', skillsDir: path.join(process.cwd(), '.claude', 'skills') }];
235
+ if (project) {
236
+ // Codex 的官方安装位置只有 $CODEX_HOME/skills(见其内置 skill-installer),
237
+ // 没有项目级约定,不臆造一个 —— 点名 --host codex --project 直接报错,
238
+ // 不声不响装到一个宿主永远不会读的目录才是最糟的。
239
+ const chosen = all
240
+ ? HOST_IDS.filter((id) => spec(id).projectDirName)
241
+ : picked.length > 0
242
+ ? [...new Set(picked)]
243
+ : HOST_IDS.filter((id) => isInstalled(id) && spec(id).projectDirName);
244
+ const unsupported = chosen.filter((id) => !spec(id).projectDirName);
245
+ if (unsupported.length > 0) {
246
+ out.error = `${unsupported.map((id) => spec(id).label).join('、')} 没有项目级 skill 目录,不能和 --project 一起用`;
247
+ return out;
248
+ }
249
+ out.hosts = chosen.map(projectHostOf).filter(nonNull);
250
+ return out;
251
+ }
252
+ if (all) {
253
+ out.hosts = HOST_IDS.map(hostOf).filter(nonNull);
254
+ return out;
143
255
  }
144
- else if (picked.length > 0) {
145
- out.hosts = [...new Set(picked)].map(hostOf);
256
+ if (picked.length > 0) {
257
+ const chosen = [...new Set(picked)];
258
+ // 点名了一个只有项目级的宿主(Trae)却没给 --project:报错而不是默默装到别处。
259
+ const userless = chosen.filter((id) => !spec(id).userDirName);
260
+ if (userless.length > 0) {
261
+ out.error =
262
+ `${userless.map((id) => spec(id).label).join('、')} 只有项目级 skill 目录 —— ` +
263
+ '进到项目根目录后加 --project 重跑。';
264
+ return out;
265
+ }
266
+ out.hosts = chosen.map(hostOf).filter(nonNull);
146
267
  }
147
268
  else {
148
- out.hosts = verb === UNINSTALL_VERB ? ['claude', 'codex'].map(hostOf) : detectHosts();
269
+ // 卸载时不做检测:配置目录可能已经随 agent 一起被删掉,而我们铺出去的副本还在。
270
+ out.hosts = verb === UNINSTALL_VERB ? HOST_IDS.map(hostOf).filter(nonNull) : detectHosts();
149
271
  }
150
272
  return out;
151
273
  }
152
274
  export function installUsage() {
153
275
  process.stdout.write('Usage: remixmate install [options]\n' +
154
276
  '\n' +
155
- '把本包自带的 skill 装进已检测到的 agent 宿主,让它们能自动发现这些能力\n' +
156
- '(Claude Code: ~/.claude/skills,Codex: ~/.codex/skills)。重复运行即升级。\n' +
277
+ '把本包自带的 skill 装进已检测到的 agent 宿主,让它们能自动发现这些能力。\n' +
278
+ '重复运行即升级。支持的宿主:\n' +
279
+ HOSTS.map((h) => ` ${padDisplay(h.label, 14)}${h.userDirName ? `~/${h.userDirName}/skills` : '(仅项目级)'}${h.projectDirName ? ` 项目级 ./${h.projectDirName}/skills` : ''}\n`).join('') +
157
280
  '\n' +
158
281
  'Options:\n' +
159
- ' --host <claude|codex|all> 只装指定宿主(默认:装到所有检测到的宿主)\n' +
160
- ' --project 装到当前目录 ./.claude/skills(仅 Claude Code)\n' +
282
+ ` --host <${HOST_IDS.join('|')}|all>\n` +
283
+ ' 只装指定宿主(默认:装到所有检测到的宿主)\n' +
284
+ ' --project 装到当前目录 ./<配置目录>/skills(Codex 不支持)\n' +
161
285
  ' --dir <path> 自定义 skills 父目录(覆盖上面两者)\n' +
162
286
  ' --force 覆盖同名的、非本 CLI 安装的 skill 目录\n');
163
287
  }
@@ -167,7 +291,8 @@ export function uninstallUsage() {
167
291
  '按装机回执删除本 CLI 装过的 skill —— 只删回执里列出的目录,不碰其它 skill。\n' +
168
292
  '\n' +
169
293
  'Options:\n' +
170
- ' --host <claude|codex|all> 只卸载指定宿主(默认:两个宿主都查)\n' +
294
+ ` --host <${HOST_IDS.join('|')}|all>\n` +
295
+ ' 只卸载指定宿主(默认:所有宿主都查)\n' +
171
296
  ' --project 卸载当前目录 ./.claude/skills 下的安装\n' +
172
297
  ' --dir <path> 自定义 skills 父目录\n');
173
298
  }
@@ -210,8 +335,8 @@ export function runInstall(argv) {
210
335
  installUsage();
211
336
  return EXIT.OK;
212
337
  }
213
- if (opts.unknown) {
214
- process.stderr.write(`❌ 未知参数: ${opts.unknown}\n`);
338
+ if (opts.error) {
339
+ process.stderr.write(`❌ ${opts.error}\n`);
215
340
  installUsage();
216
341
  return EXIT.USAGE;
217
342
  }
@@ -220,10 +345,17 @@ export function runInstall(argv) {
220
345
  process.stderr.write(`❌ 包内没有可安装的 skill(${SKILLS_DIR})\n`);
221
346
  return EXIT.ERROR;
222
347
  }
348
+ const projectOnly = projectOnlyHosts();
223
349
  if (opts.hosts.length === 0) {
224
- process.stderr.write('❌ 没有检测到任何 agent 宿主。找过这两个位置:\n' +
225
- ` Claude Code ${hostHome('claude')}\n` +
226
- ` Codex ${hostHome('codex')}\n` +
350
+ // 只检测到项目级宿主(比如只装了 Trae)时,这不是「没检测到」,而是「装法不同」。
351
+ if (projectOnly.length > 0) {
352
+ process.stderr.write(`❌ 只检测到 ${projectOnly.map((id) => spec(id).label).join('')},` +
353
+ '它只有项目级 skill 目录。\n' +
354
+ ' 进到项目根目录后运行:remixmate install --project\n');
355
+ return EXIT.USAGE;
356
+ }
357
+ process.stderr.write('❌ 没有检测到任何 agent 宿主。找过这些位置:\n' +
358
+ HOST_IDS.map((id) => ` ${padDisplay(spec(id).label, 14)}${detectDirs(id).join('、')}\n`).join('') +
227
359
  ' 先把 agent 装好再重跑,或用 --dir <path> 指定目录。\n');
228
360
  return EXIT.USAGE;
229
361
  }
@@ -240,6 +372,11 @@ export function runInstall(argv) {
240
372
  }
241
373
  if (failures > 0)
242
374
  return EXIT.ERROR;
375
+ // 检测到了但这一轮装不了的宿主要说出来 —— 静默跳过会让用户以为不支持。
376
+ if (projectOnly.length > 0 && !opts.hosts.some((h) => projectOnly.includes(h.id))) {
377
+ process.stdout.write(`\nℹ️ 还检测到 ${projectOnly.map((id) => spec(id).label).join('、')},` +
378
+ '它只有项目级 skill 目录 —— 在项目根目录里运行 remixmate install --project 即可。\n');
379
+ }
243
380
  process.stdout.write('\n重启 agent 后即可生效。升级后重跑 remixmate install 覆盖即可。\n');
244
381
  return EXIT.OK;
245
382
  }
@@ -249,8 +386,8 @@ export function runUninstall(argv) {
249
386
  uninstallUsage();
250
387
  return EXIT.OK;
251
388
  }
252
- if (opts.unknown) {
253
- process.stderr.write(`❌ 未知参数: ${opts.unknown}\n`);
389
+ if (opts.error) {
390
+ process.stderr.write(`❌ ${opts.error}\n`);
254
391
  uninstallUsage();
255
392
  return EXIT.USAGE;
256
393
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "version": "0.9.22",
4
- "generatedAt": "2026-09-06T10:24:59.463Z",
3
+ "version": "0.9.23",
4
+ "generatedAt": "2026-09-06T12:35:46.901Z",
5
5
  "skills": [
6
6
  {
7
7
  "id": "export-jianying",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remixmate/cli",
3
- "version": "0.9.22",
3
+ "version": "0.9.23",
4
4
  "description": "AI media generation skills for Claude Code / Codex — 12 skills covering image, video, voice, digital human, web screenshot, web recording, script, template registry, rendering, Jianying export, and video deconstruction.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",