openyida 2026.4.2-beta.8 → 2026.4.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 +9 -0
- package/lib/core/copy.js +64 -28
- package/lib/core/doctor.js +1 -1
- package/lib/core/env.js +1 -1
- package/lib/core/locales/ar.js +1 -0
- package/lib/core/locales/de.js +1 -0
- package/lib/core/locales/en.js +1 -0
- package/lib/core/locales/es.js +1 -0
- package/lib/core/locales/fr.js +1 -0
- package/lib/core/locales/hi.js +1 -0
- package/lib/core/locales/ja.js +1 -0
- package/lib/core/locales/ko.js +1 -0
- package/lib/core/locales/pt.js +1 -0
- package/lib/core/locales/vi.js +1 -0
- package/lib/core/locales/zh-TW.js +1 -0
- package/lib/core/locales/zh.js +1 -0
- package/lib/core/utils.js +2 -1
- package/package.json +1 -1
- package/project/pages/src/demo-birthday-game.js +0 -1
- package/scripts/postinstall.js +56 -92
- package/yida-skills/SKILL.md +4 -6
- package/yida-skills/skills/yida-chart/SKILL.md +1 -2
- package/yida-skills/skills/yida-custom-page/SKILL.md +37 -0
- package/yida-skills/skills/yida-flash-note-to-prd/SKILL.md +1 -5
- package/yida-skills/skills/yida-formula/SKILL.md +1 -3
- package/yida-skills/skills/yida-login/SKILL.md +0 -2
- package/yida-skills/skills/yida-ppt-slider/SKILL.md +1 -4
- package/yida-skills/skills/yida-report/SKILL.md +1 -4
package/README.md
CHANGED
|
@@ -31,6 +31,15 @@ npm install -g openyida
|
|
|
31
31
|
|
|
32
32
|
**Zero config, works out of the box.** After installation, just chat in Claude Code / OpenCode / Aone Copilot:
|
|
33
33
|
|
|
34
|
+
### Wukong Installation
|
|
35
|
+
|
|
36
|
+
Wukong uses manual skill package installation instead of npm:
|
|
37
|
+
|
|
38
|
+
1. Download the latest skill package (`.zip`) from [GitHub Releases](https://github.com/openyida/openyida/releases)
|
|
39
|
+
2. Open Wukong → **Skill Center** → **Upload Skill**, then select the downloaded package
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
34
43
|
```
|
|
35
44
|
Build me an IPD system on Yida to manage the full chip production workflow
|
|
36
45
|
Help me set up a CRM
|
package/lib/core/copy.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* copy.js - 复制 project 工作目录模板 /
|
|
2
|
+
* copy.js - 复制 project 工作目录模板 / 复制 yida-skills 到当前 AI 工具环境
|
|
3
3
|
*
|
|
4
4
|
* 用法:
|
|
5
5
|
* openyida copy → 复制 project/ 目录模板(默认,合并模式)
|
|
6
6
|
* openyida copy --force → 复制 project/ 目录模板(强制覆盖,先清空目标目录)
|
|
7
|
-
* openyida copy -skills →
|
|
8
|
-
*
|
|
7
|
+
* openyida copy -skills → 复制 yida-skills/ 到当前 AI 工具的 skills 目录
|
|
8
|
+
* 悟空环境下:删除已有 yida-skills/(悟空通过手动上传技能)
|
|
9
9
|
* openyida copy -project → 复制 project/ 目录模板(与默认行为相同,显式指定)
|
|
10
10
|
* openyida copy -project --force → 复制 project/ 目录模板(强制覆盖)
|
|
11
11
|
*
|
|
@@ -17,12 +17,8 @@
|
|
|
17
17
|
*
|
|
18
18
|
* project/ 合并模式(默认):已存在的文件强制覆盖,目标目录中多余的文件保留不动
|
|
19
19
|
* project/ 强制模式(--force):先清空目标目录,再完整复制
|
|
20
|
-
* yida-skills
|
|
21
|
-
* yida-skills
|
|
22
|
-
*
|
|
23
|
-
* Windows 兼容说明:
|
|
24
|
-
* - 软链接在 Windows 上需要管理员权限或开发者模式,失败时自动降级为目录复制
|
|
25
|
-
* - 路径分隔符统一使用 path.join 处理
|
|
20
|
+
* yida-skills/(非悟空):复制到 <cwd>/yida-skills/,如目标已存在则先清理
|
|
21
|
+
* yida-skills/(悟空):删除已有软链或目录(悟空通过手动上传技能,不需要复制)
|
|
26
22
|
*/
|
|
27
23
|
|
|
28
24
|
'use strict';
|
|
@@ -194,7 +190,7 @@ function resolveDestBaseFromEnv(activeToolName, activeProjectRoot, envResults) {
|
|
|
194
190
|
if (isWukong) {
|
|
195
191
|
return activeProjectRoot
|
|
196
192
|
? path.dirname(activeProjectRoot)
|
|
197
|
-
: path.join(os.homedir(), '.real', 'workspace');
|
|
193
|
+
: path.join(process.env.AGENT_WORK_ROOT || path.join(os.homedir(), '.real'), 'workspace');
|
|
198
194
|
}
|
|
199
195
|
|
|
200
196
|
if (activeToolName) {
|
|
@@ -274,19 +270,30 @@ function run() {
|
|
|
274
270
|
const results = [];
|
|
275
271
|
|
|
276
272
|
if (shouldCopyProject) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
273
|
+
// 检查 destBase 是否为空目录:
|
|
274
|
+
// - 空目录(如悟空新工作区)→ 直接把 project/ 内容铺进 destBase,不创建 project/ 这层
|
|
275
|
+
// - 非空目录(已有其他文件)→ 复制整个 project/ 目录(含目录本身)
|
|
276
|
+
const destBaseEntries = fs.existsSync(destBase)
|
|
277
|
+
? fs.readdirSync(destBase).filter((name) => name !== '.DS_Store')
|
|
278
|
+
: [];
|
|
279
|
+
const isDestBaseEmpty = destBaseEntries.length === 0;
|
|
280
|
+
|
|
281
|
+
const projectDestDir = isDestBaseEmpty
|
|
282
|
+
? destBase
|
|
283
|
+
: path.join(destBase, 'project');
|
|
284
|
+
|
|
285
|
+
if (isDestBaseEmpty) {
|
|
286
|
+
console.log(t('copy.dest_empty_flatten'));
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const count = copyItem('project/', packageProjectDir, projectDestDir, isForce);
|
|
290
|
+
results.push({ label: 'project/', dest: projectDestDir, count, type: 'copy' });
|
|
284
291
|
}
|
|
285
292
|
|
|
286
293
|
if (shouldLinkSkills) {
|
|
287
|
-
const destSkillsLink = path.join(destBase, 'yida-skills');
|
|
288
294
|
if (isWukong) {
|
|
289
|
-
//
|
|
295
|
+
// 悟空环境:删除已有软链或目录,不安装(悟空手动上传技能)
|
|
296
|
+
const destSkillsLink = path.join(destBase, 'yida-skills');
|
|
290
297
|
console.log(t('copy.wukong_skills_cleanup'));
|
|
291
298
|
const removed = removeSkillsLink(destSkillsLink);
|
|
292
299
|
results.push({
|
|
@@ -296,15 +303,44 @@ function run() {
|
|
|
296
303
|
type: 'wukong-cleanup'
|
|
297
304
|
});
|
|
298
305
|
} else {
|
|
299
|
-
//
|
|
300
|
-
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
306
|
+
// 其他环境:复制到 AI 工具配置目录的 skills/yida-skills/
|
|
307
|
+
// 目标路径:~/<tool-config>/skills/yida-skills/(与 postinstall 保持一致)
|
|
308
|
+
const activeResult = envResults.find((r) => r.isActive);
|
|
309
|
+
const toolConfigDir = activeResult
|
|
310
|
+
? path.join(os.homedir(), activeResult.dirName)
|
|
311
|
+
: null;
|
|
312
|
+
|
|
313
|
+
if (toolConfigDir) {
|
|
314
|
+
const skillsDir = path.join(toolConfigDir, 'skills');
|
|
315
|
+
const destSkillsDest = path.join(skillsDir, 'yida-skills');
|
|
316
|
+
|
|
317
|
+
// 清理旧版遗留在根目录的错误安装
|
|
318
|
+
removeSkillsLink(path.join(toolConfigDir, 'yida-skills'));
|
|
319
|
+
|
|
320
|
+
// 清理已有的 skills/yida-skills/(旧软链或旧目录)
|
|
321
|
+
removeSkillsLink(destSkillsDest);
|
|
322
|
+
|
|
323
|
+
// 复制文件
|
|
324
|
+
fs.mkdirSync(skillsDir, { recursive: true });
|
|
325
|
+
const count = mergeCopyDir(packageYidaSkillsDir, destSkillsDest);
|
|
326
|
+
results.push({
|
|
327
|
+
label: 'yida-skills/',
|
|
328
|
+
dest: destSkillsDest,
|
|
329
|
+
count,
|
|
330
|
+
type: 'copy'
|
|
331
|
+
});
|
|
332
|
+
} else {
|
|
333
|
+
// 未检测到 AI 工具,复制到当前目录下
|
|
334
|
+
const destSkillsDest = path.join(destBase, 'yida-skills');
|
|
335
|
+
removeSkillsLink(destSkillsDest);
|
|
336
|
+
const count = mergeCopyDir(packageYidaSkillsDir, destSkillsDest);
|
|
337
|
+
results.push({
|
|
338
|
+
label: 'yida-skills/',
|
|
339
|
+
dest: destSkillsDest,
|
|
340
|
+
count,
|
|
341
|
+
type: 'copy'
|
|
342
|
+
});
|
|
343
|
+
}
|
|
308
344
|
}
|
|
309
345
|
}
|
|
310
346
|
|
package/lib/core/doctor.js
CHANGED
package/lib/core/env.js
CHANGED
|
@@ -55,7 +55,7 @@ function detectEnvironment() {
|
|
|
55
55
|
const isActive = activeTool && activeTool.dirName === dirName;
|
|
56
56
|
// path.join 在 Windows 上自动使用反斜杠,兼容所有平台
|
|
57
57
|
const workspaceRoot = isWukong
|
|
58
|
-
? path.join(home, '.real', 'workspace', 'project')
|
|
58
|
+
? path.join(process.env.AGENT_WORK_ROOT || path.join(home, '.real'), 'workspace', 'project')
|
|
59
59
|
: cwdProject;
|
|
60
60
|
const hasProject = fs.existsSync(workspaceRoot);
|
|
61
61
|
|
package/lib/core/locales/ar.js
CHANGED
|
@@ -203,6 +203,7 @@ module.exports = {
|
|
|
203
203
|
title: ' openyida copy - تهيئة دليل عمل Yida',
|
|
204
204
|
package_root: '\n📦 جذر الحزمة: {0}',
|
|
205
205
|
dest_root: '🤖 الدليل الهدف: {0}',
|
|
206
|
+
dest_empty_flatten: '📂 الدليل الهدف فارغ، سيتم نسخ محتويات project/ مباشرةً (بدون إنشاء مجلد project/ فرعي)',
|
|
206
207
|
force_mode: '⚠️ وضع --force: سيتم مسح الدليل الهدف قبل النسخ',
|
|
207
208
|
no_package: '\n❌ لم يتم العثور على دليل حزمة openyida',
|
|
208
209
|
no_package_hint1: ' تأكد من تثبيت openyida بشكل عام:',
|
package/lib/core/locales/de.js
CHANGED
|
@@ -203,6 +203,7 @@ module.exports = {
|
|
|
203
203
|
title: ' openyida copy - Yida-Arbeitsverzeichnis initialisieren',
|
|
204
204
|
package_root: '\n📦 Paketstamm: {0}',
|
|
205
205
|
dest_root: '🤖 Zielverzeichnis: {0}',
|
|
206
|
+
dest_empty_flatten: '📂 Zielverzeichnis ist leer, project/-Inhalte werden direkt hineinkopiert (kein project/-Unterverzeichnis)',
|
|
206
207
|
force_mode: '⚠️ --force-Modus: Zielverzeichnis wird vor dem Kopieren geleert',
|
|
207
208
|
no_package: '\n❌ openyida-Paketverzeichnis nicht gefunden',
|
|
208
209
|
no_package_hint1: ' Stellen Sie sicher, dass openyida global installiert ist:',
|
package/lib/core/locales/en.js
CHANGED
|
@@ -575,6 +575,7 @@ Examples:
|
|
|
575
575
|
package_root: '\n📦 Package root: {0}',
|
|
576
576
|
dest_base: '🤖 Target root: {0}',
|
|
577
577
|
dest_root: '🤖 Target root: {0}',
|
|
578
|
+
dest_empty_flatten: '📂 Target directory is empty, flattening project/ contents directly into it (no project/ subdirectory)',
|
|
578
579
|
force_mode: '⚠️ --force mode: target directory will be cleared before copying',
|
|
579
580
|
no_package: '\n❌ openyida package directory not found',
|
|
580
581
|
no_package_hint1: ' Please ensure openyida is installed globally:',
|
package/lib/core/locales/es.js
CHANGED
|
@@ -203,6 +203,7 @@ module.exports = {
|
|
|
203
203
|
title: ' openyida copy - Inicializar directorio de trabajo Yida',
|
|
204
204
|
package_root: '\n📦 Raíz del paquete: {0}',
|
|
205
205
|
dest_root: '🤖 Directorio destino: {0}',
|
|
206
|
+
dest_empty_flatten: '📂 El directorio destino está vacío, los contenidos de project/ se copiarán directamente (sin crear subdirectorio project/)',
|
|
206
207
|
force_mode: '⚠️ Modo --force: el directorio destino será vaciado antes de copiar',
|
|
207
208
|
no_package: '\n❌ Directorio del paquete openyida no encontrado',
|
|
208
209
|
no_package_hint1: ' Asegúrese de que openyida esté instalado globalmente:',
|
package/lib/core/locales/fr.js
CHANGED
|
@@ -203,6 +203,7 @@ module.exports = {
|
|
|
203
203
|
title: ' openyida copy - Initialisation du répertoire de travail Yida',
|
|
204
204
|
package_root: '\n📦 Racine du package : {0}',
|
|
205
205
|
dest_root: '🤖 Répertoire cible : {0}',
|
|
206
|
+
dest_empty_flatten: '📂 Le répertoire cible est vide, les contenus de project/ seront copiés directement (sans créer de sous-répertoire project/)',
|
|
206
207
|
force_mode: '⚠️ Mode --force : le répertoire cible sera vidé avant la copie',
|
|
207
208
|
no_package: '\n❌ Répertoire du package openyida introuvable',
|
|
208
209
|
no_package_hint1: " Vérifiez qu'openyida est installé globalement :",
|
package/lib/core/locales/hi.js
CHANGED
|
@@ -203,6 +203,7 @@ module.exports = {
|
|
|
203
203
|
title: ' openyida copy - Yida कार्य निर्देशिका प्रारंभ करें',
|
|
204
204
|
package_root: '\n📦 पैकेज रूट: {0}',
|
|
205
205
|
dest_root: '🤖 लक्ष्य निर्देशिका: {0}',
|
|
206
|
+
dest_empty_flatten: '📂 लक्ष्य निर्देशिका खाली है, project/ की सामग्री सीधे कॉपी की जाएगी (project/ उपनिर्देशिका नहीं बनेगी)',
|
|
206
207
|
force_mode: '⚠️ --force मोड: कॉपी करने से पहले लक्ष्य निर्देशिका साफ की जाएगी',
|
|
207
208
|
no_package: '\n❌ openyida पैकेज निर्देशिका नहीं मिली',
|
|
208
209
|
no_package_hint1: ' सुनिश्चित करें कि openyida वैश्विक रूप से स्थापित है:',
|
package/lib/core/locales/ja.js
CHANGED
|
@@ -560,6 +560,7 @@ openyida - Yida CLI ツール
|
|
|
560
560
|
package_root: '\n📦 パッケージルート: {0}',
|
|
561
561
|
dest_base: '🤖 ターゲットルート: {0}',
|
|
562
562
|
dest_root: '🤖 ターゲットルート: {0}',
|
|
563
|
+
dest_empty_flatten: '📂 ターゲットディレクトリが空のため、project/ の内容を直接コピーします(project/ サブディレクトリは作成しません)',
|
|
563
564
|
force_mode: '⚠️ --force モード:ターゲットディレクトリをクリアしてからコピーします',
|
|
564
565
|
no_package: '\n❌ openyida パッケージディレクトリが見つかりません',
|
|
565
566
|
no_package_hint1: ' openyida がグローバルにインストールされていることを確認してください:',
|
package/lib/core/locales/ko.js
CHANGED
|
@@ -206,6 +206,7 @@ module.exports = {
|
|
|
206
206
|
title: ' openyida copy - Yida 작업 디렉토리 초기화',
|
|
207
207
|
package_root: '\n📦 패키지 루트: {0}',
|
|
208
208
|
dest_root: '🤖 대상 루트: {0}',
|
|
209
|
+
dest_empty_flatten: '📂 대상 디렉토리가 비어 있어 project/ 내용을 직접 복사합니다 (project/ 하위 디렉토리 생성 안 함)',
|
|
209
210
|
force_mode: '⚠️ --force 모드: 대상 디렉토리를 초기화 후 복사합니다',
|
|
210
211
|
no_package: '\n❌ openyida 패키지 디렉토리를 찾을 수 없습니다',
|
|
211
212
|
no_package_hint1: ' openyida가 전역으로 설치되어 있는지 확인하세요:',
|
package/lib/core/locales/pt.js
CHANGED
|
@@ -203,6 +203,7 @@ module.exports = {
|
|
|
203
203
|
title: ' openyida copy - Inicializar diretório de trabalho Yida',
|
|
204
204
|
package_root: '\n📦 Raiz do pacote: {0}',
|
|
205
205
|
dest_root: '🤖 Diretório destino: {0}',
|
|
206
|
+
dest_empty_flatten: '📂 O diretório destino está vazio, os conteúdos de project/ serão copiados diretamente (sem criar subdiretório project/)',
|
|
206
207
|
force_mode: '⚠️ Modo --force: o diretório destino será esvaziado antes de copiar',
|
|
207
208
|
no_package: '\n❌ Diretório do pacote openyida não encontrado',
|
|
208
209
|
no_package_hint1: ' Certifique-se de que o openyida está instalado globalmente:',
|
package/lib/core/locales/vi.js
CHANGED
|
@@ -203,6 +203,7 @@ module.exports = {
|
|
|
203
203
|
title: ' openyida copy - Khởi tạo thư mục làm việc Yida',
|
|
204
204
|
package_root: '\n📦 Thư mục gốc gói: {0}',
|
|
205
205
|
dest_root: '🤖 Thư mục đích: {0}',
|
|
206
|
+
dest_empty_flatten: '📂 Thư mục đích trống, nội dung project/ sẽ được sao chép trực tiếp (không tạo thư mục con project/)',
|
|
206
207
|
force_mode: '⚠️ Chế độ --force: thư mục đích sẽ được xóa trước khi sao chép',
|
|
207
208
|
no_package: '\n❌ Không tìm thấy thư mục gói openyida',
|
|
208
209
|
no_package_hint1: ' Hãy đảm bảo openyida đã được cài đặt toàn cục:',
|
|
@@ -469,6 +469,7 @@ openyida - 宜搭命令列工具
|
|
|
469
469
|
package_root: '\n📦 套件根目錄:{0}',
|
|
470
470
|
dest_base: '🤖 目標根目錄:{0}',
|
|
471
471
|
dest_root: '🤖 目標根目錄:{0}',
|
|
472
|
+
dest_empty_flatten: '📂 目標目錄為空,將 project/ 內容直接鋪入(不建立 project/ 子目錄)',
|
|
472
473
|
force_mode: '⚠️ --force 模式:目標目錄將被清空後重新複製',
|
|
473
474
|
no_package: '\n❌ 未找到 openyida 安裝套件目錄',
|
|
474
475
|
no_package_hint1: ' 請確認 openyida 已正確全域安裝:',
|
package/lib/core/locales/zh.js
CHANGED
|
@@ -531,6 +531,7 @@ openyida - 宜搭命令行工具
|
|
|
531
531
|
package_root: '\n📦 包根目录: {0}',
|
|
532
532
|
dest_base: '🤖 目标根目录: {0}',
|
|
533
533
|
dest_root: '🤖 目标根目录: {0}',
|
|
534
|
+
dest_empty_flatten: '📂 目标目录为空,将 project/ 内容直接铺入(不创建 project/ 子目录)',
|
|
534
535
|
force_mode: '⚠️ --force 模式:目标目录将被清空后重新复制',
|
|
535
536
|
no_package: '\n❌ 未找到 openyida 安装包目录',
|
|
536
537
|
no_package_hint1: ' 请确认 openyida 已正确全局安装:',
|
package/lib/core/utils.js
CHANGED
|
@@ -82,12 +82,13 @@ function detectActiveTool() {
|
|
|
82
82
|
|
|
83
83
|
// 悟空(Wukong)
|
|
84
84
|
// Windows 路径可能使用反斜杠,需同时兼容正斜杠和反斜杠
|
|
85
|
+
// AGENT_WORK_ROOT 指向 ~/.real/users/user-{uuid}/,workspace 在其下的 workspace/ 子目录
|
|
85
86
|
if (env.AGENT_WORK_ROOT && (env.AGENT_WORK_ROOT.includes('.real') || env.AGENT_WORK_ROOT.includes(path.join('.real')))) {
|
|
86
87
|
return {
|
|
87
88
|
tool: 'wukong',
|
|
88
89
|
displayName: '悟空(Wukong)',
|
|
89
90
|
dirName: '.real',
|
|
90
|
-
workspaceRoot: path.join(
|
|
91
|
+
workspaceRoot: path.join(env.AGENT_WORK_ROOT, 'workspace', 'project'),
|
|
91
92
|
};
|
|
92
93
|
}
|
|
93
94
|
|
package/package.json
CHANGED
package/scripts/postinstall.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* postinstall hook:
|
|
3
|
+
* postinstall hook: skills installation + welcome guide after `npm install -g openyida`
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* 职责:
|
|
6
|
+
* 1. 清理旧版本遗留的错误安装(~/.xxx/yida-skills/,缺少 skills/ 中间层级)
|
|
7
|
+
* 2. 将 yida-skills/ 安装到各 AI 工具的正确 skills 目录
|
|
8
|
+
* 3. 首次安装欢迎引导
|
|
7
9
|
*
|
|
8
|
-
*
|
|
10
|
+
* 正确的 skills 安装路径(所有工具统一使用 skills/ 子目录):
|
|
11
|
+
* ~/.claude/skills/yida-skills/ ← <package>/yida-skills (copy)
|
|
12
|
+
* ~/.opencode/skills/yida-skills/ ← <package>/yida-skills (copy)
|
|
13
|
+
* ~/.aone_copilot/skills/yida-skills/ ← <package>/yida-skills (copy)
|
|
14
|
+
* ~/.cursor/skills/yida-skills/ ← <package>/yida-skills (copy)
|
|
15
|
+
* ~/.qoder/skills/yida-skills/ ← <package>/yida-skills (copy)
|
|
9
16
|
*
|
|
10
|
-
*
|
|
11
|
-
* ~/.claude/yida-skills → <package>/yida-skills
|
|
12
|
-
* ~/.opencode/yida-skills → <package>/yida-skills
|
|
13
|
-
* ~/.aone_copilot/yida-skills → <package>/yida-skills
|
|
14
|
-
* ~/.cursor/yida-skills → <package>/yida-skills
|
|
15
|
-
* ~/.qoder/yida-skills → <package>/yida-skills
|
|
16
|
-
* ~/.real/yida-skills → <package>/yida-skills (Wukong)
|
|
17
|
+
* 悟空(Wukong)通过手动上传技能,不在此安装。
|
|
17
18
|
*/
|
|
18
19
|
|
|
19
20
|
'use strict';
|
|
@@ -37,15 +38,6 @@ function safeExec(fn) {
|
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
|
|
40
|
-
/**
|
|
41
|
-
* Ensure a directory exists (mkdir -p).
|
|
42
|
-
*/
|
|
43
|
-
function ensureDir(dirPath) {
|
|
44
|
-
if (!fs.existsSync(dirPath)) {
|
|
45
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
41
|
/**
|
|
50
42
|
* Recursively copy a directory, overwriting existing files.
|
|
51
43
|
*/
|
|
@@ -65,114 +57,86 @@ function copyDirRecursive(src, dest) {
|
|
|
65
57
|
}
|
|
66
58
|
|
|
67
59
|
/**
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* Uses file copy instead of symlink to ensure AI tools can always
|
|
71
|
-
* discover skills on the first run (fixes #186).
|
|
72
|
-
*
|
|
73
|
-
* - If an old symlink exists → remove it first, then copy.
|
|
74
|
-
* - If a real directory exists → remove and do a clean copy.
|
|
60
|
+
* 清理旧版遗留的错误路径(软链接或目录)。
|
|
75
61
|
*/
|
|
76
|
-
function
|
|
77
|
-
const destPath = path.join(ideConfigDir, 'yida-skills');
|
|
78
|
-
|
|
79
|
-
ensureDir(ideConfigDir);
|
|
80
|
-
|
|
81
|
-
let existingStat = null;
|
|
62
|
+
function cleanupLegacy(dirPath) {
|
|
82
63
|
try {
|
|
83
|
-
|
|
64
|
+
const stat = fs.lstatSync(dirPath);
|
|
65
|
+
if (stat.isSymbolicLink()) {
|
|
66
|
+
fs.unlinkSync(dirPath);
|
|
67
|
+
} else if (stat.isDirectory()) {
|
|
68
|
+
fs.rmSync(dirPath, { recursive: true, force: true });
|
|
69
|
+
}
|
|
84
70
|
} catch {
|
|
85
|
-
/*
|
|
71
|
+
/* not exists, ok */
|
|
86
72
|
}
|
|
73
|
+
}
|
|
87
74
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
75
|
+
/**
|
|
76
|
+
* 将 yida-skills 安装到 AI 工具的 skills 目录。
|
|
77
|
+
* 正确路径:~/<tool-config>/skills/yida-skills/
|
|
78
|
+
*
|
|
79
|
+
* 同时清理旧版遗留在根目录的错误安装:~/<tool-config>/yida-skills/
|
|
80
|
+
*/
|
|
81
|
+
function installSkillsToTool(toolConfigDir) {
|
|
82
|
+
// 清理旧版遗留在根目录的错误安装(缺少 skills/ 中间层级)
|
|
83
|
+
cleanupLegacy(path.join(toolConfigDir, 'yida-skills'));
|
|
84
|
+
|
|
85
|
+
// 安装到正确路径:~/<tool-config>/skills/yida-skills/
|
|
86
|
+
const skillsDir = path.join(toolConfigDir, 'skills');
|
|
87
|
+
const destPath = path.join(skillsDir, 'yida-skills');
|
|
96
88
|
|
|
89
|
+
fs.mkdirSync(skillsDir, { recursive: true });
|
|
90
|
+
|
|
91
|
+
// 如果已存在,先清理(旧软链接或旧目录)
|
|
92
|
+
cleanupLegacy(destPath);
|
|
93
|
+
|
|
94
|
+
// 复制文件(不用软链接,确保 AI 工具首次扫描就能发现)
|
|
97
95
|
copyDirRecursive(SKILLS_DIR, destPath);
|
|
98
96
|
}
|
|
99
97
|
|
|
100
|
-
// ── 1. Skills
|
|
98
|
+
// ── 1. Skills 安装 ───────────────────────────────────────────────────
|
|
99
|
+
// 安装到各 AI 工具的正确 skills 目录(悟空跳过,悟空通过手动上传技能)
|
|
101
100
|
|
|
102
|
-
// Claude Code
|
|
101
|
+
// Claude Code — 始终安装(Claude Code 是主要目标用户)
|
|
103
102
|
safeExec(() => {
|
|
104
|
-
|
|
103
|
+
installSkillsToTool(path.join(HOME_DIR, '.claude'));
|
|
105
104
|
});
|
|
106
105
|
|
|
107
|
-
// OpenCode
|
|
106
|
+
// OpenCode — 仅在已安装时安装
|
|
108
107
|
safeExec(() => {
|
|
109
108
|
if (fs.existsSync(path.join(HOME_DIR, '.opencode'))) {
|
|
110
|
-
|
|
109
|
+
installSkillsToTool(path.join(HOME_DIR, '.opencode'));
|
|
111
110
|
}
|
|
112
111
|
});
|
|
113
112
|
|
|
114
|
-
// Aone Copilot
|
|
113
|
+
// Aone Copilot — 仅在已安装时安装
|
|
115
114
|
safeExec(() => {
|
|
116
115
|
if (fs.existsSync(path.join(HOME_DIR, '.aone_copilot'))) {
|
|
117
|
-
|
|
116
|
+
installSkillsToTool(path.join(HOME_DIR, '.aone_copilot'));
|
|
118
117
|
}
|
|
119
118
|
});
|
|
120
119
|
|
|
121
|
-
// Cursor
|
|
120
|
+
// Cursor — 仅在已安装时安装
|
|
122
121
|
safeExec(() => {
|
|
123
122
|
if (fs.existsSync(path.join(HOME_DIR, '.cursor'))) {
|
|
124
|
-
|
|
123
|
+
installSkillsToTool(path.join(HOME_DIR, '.cursor'));
|
|
125
124
|
}
|
|
126
125
|
});
|
|
127
126
|
|
|
128
|
-
// Qoder
|
|
127
|
+
// Qoder — 仅在已安装时安装
|
|
129
128
|
safeExec(() => {
|
|
130
129
|
if (fs.existsSync(path.join(HOME_DIR, '.qoder'))) {
|
|
131
|
-
|
|
130
|
+
installSkillsToTool(path.join(HOME_DIR, '.qoder'));
|
|
132
131
|
}
|
|
133
132
|
});
|
|
134
133
|
|
|
135
|
-
//
|
|
136
|
-
|
|
134
|
+
// 悟空(Wukong)— 跳过安装,只清理旧版遗留
|
|
137
135
|
safeExec(() => {
|
|
138
|
-
|
|
139
|
-
installSkills(path.join(HOME_DIR, '.real'));
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
// ── 3. Chromium 按需安装 ─────────────────────────────────────────────
|
|
144
|
-
|
|
145
|
-
safeExec(() => {
|
|
146
|
-
const { execSync } = require('child_process');
|
|
147
|
-
|
|
148
|
-
let chromiumPath = null;
|
|
149
|
-
try {
|
|
150
|
-
// 通过 playwright 内置 API 获取 Chromium 可执行文件路径
|
|
151
|
-
const { chromium } = require('playwright');
|
|
152
|
-
chromiumPath = chromium.executablePath();
|
|
153
|
-
} catch {
|
|
154
|
-
// playwright 未安装或 API 不可用,跳过
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (chromiumPath && fs.existsSync(chromiumPath)) {
|
|
159
|
-
// Chromium 已存在,无需重复安装
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
console.log('\n 🌐 正在安装 Chromium 浏览器(首次安装需要下载,请稍候)...');
|
|
164
|
-
try {
|
|
165
|
-
execSync('npx playwright install chromium', {
|
|
166
|
-
stdio: 'inherit',
|
|
167
|
-
timeout: 300_000, // 5 分钟超时
|
|
168
|
-
});
|
|
169
|
-
console.log(' ✅ Chromium 安装完成!\n');
|
|
170
|
-
} catch {
|
|
171
|
-
console.warn(' ⚠️ Chromium 安装失败,可手动执行:npx playwright install chromium\n');
|
|
172
|
-
}
|
|
136
|
+
cleanupLegacy(path.join(HOME_DIR, '.real', 'yida-skills'));
|
|
173
137
|
});
|
|
174
138
|
|
|
175
|
-
// ──
|
|
139
|
+
// ── 2. 首次安装欢迎引导 ──────────────────────────────────────────────
|
|
176
140
|
|
|
177
141
|
safeExec(() => {
|
|
178
142
|
const FIRST_INSTALL_FLAG = path.join(HOME_DIR, '.openyida', 'installed');
|
package/yida-skills/SKILL.md
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yida-skills
|
|
3
|
-
description:
|
|
4
|
-
宜搭低代码平台 AI 开发入口。一句话生成完整应用:创建应用、表单设计、自定义页面、流程配置、数据管理。
|
|
5
|
-
当用户提到"宜搭"、"yida"、"低代码"、"创建应用"、"创建表单"、"发布页面"、"搭建"、"系统"、"应用"时触发。
|
|
3
|
+
description: "宜搭低代码平台 AI 开发入口。一句话生成完整应用:创建应用、表单设计、自定义页面、流程配置、数据管理。当用户提到「宜搭」「yida」「低代码」「创建应用」「创建表单」「发布页面」「搭建」「系统」「应用」时触发。"
|
|
6
4
|
metadata:
|
|
7
|
-
version: 2026.04.02
|
|
5
|
+
version: 2026.04.02
|
|
8
6
|
---
|
|
9
7
|
|
|
10
8
|
# 宜搭 AI 应用开发指南
|
|
@@ -30,10 +28,10 @@ metadata:
|
|
|
30
28
|
## ⚡ 首要步骤(每次必须先执行)
|
|
31
29
|
|
|
32
30
|
```bash
|
|
33
|
-
# 1. 确保 openyida
|
|
31
|
+
# 1. 确保 openyida 已安装(未安装则自动安装,已安装则跳过)
|
|
34
32
|
openyida -v 2>/dev/null || npm install -g openyida@latest
|
|
35
33
|
|
|
36
|
-
# 2.
|
|
34
|
+
# 2. 一键诊断并自动修复:环境检测 + project 目录初始化
|
|
37
35
|
openyida doctor --fix
|
|
38
36
|
```
|
|
39
37
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yida-chart
|
|
3
|
-
description:
|
|
4
|
-
宜搭 ECharts 高级报表技能。通过 ECharts + 自定义页面 JSX 实现高度定制化、更美观的数据可视化报表。本技能不负责创建宜搭原生报表(标准报表由 yida-report 技能负责),但 ECharts 报表必须依赖宜搭原生报表的 getDataAsync.json 或 getCacheData.json 接口获取聚合数据,禁止前端聚合(当前仅支持单表数据源,暂不支持多表关联)。数据源获取方式:若用户已有原生报表,直接读取其信息作为数据源;若用户没有原生报表,则先调用 yida-report 技能创建原生报表作为数据源。当用户提供了已有报表 URL(如 https://www.aliwork.com/APP_XXX/admin/REPORT-XXX)时,解析现有报表 Schema 提取数据源参数,基于该数据源创建 ECharts 自定义页面(输出始终是 ECharts 自定义页面,而非优化后的原生报表)。当用户提到"更美观"、"高级"、"定制化"、"ECharts"、"echarts"、"Dashboard 大屏"、"数据大屏"等关键词,或用户提供了报表 URL 要求优化时,使用此技能。普通的"报表"、"统计"等需求默认由 yida-report 技能处理。
|
|
3
|
+
description: "宜搭 ECharts 高级报表技能。通过 ECharts + 自定义页面 JSX 实现高度定制化、更美观的数据可视化报表。本技能不负责创建宜搭原生报表(标准报表由 yida-report 技能负责),但 ECharts 报表必须依赖宜搭原生报表的 getDataAsync.json 或 getCacheData.json 接口获取聚合数据,禁止前端聚合。当用户提到「更美观」「高级」「定制化」「ECharts」「echarts」「Dashboard 大屏」「数据大屏」等关键词,或用户提供了报表 URL 要求优化时,使用此技能。普通的「报表」「统计」等需求默认由 yida-report 技能处理。"
|
|
5
4
|
---
|
|
6
5
|
|
|
7
6
|
# 宜搭 ECharts 高级报表技能
|
|
@@ -301,6 +301,43 @@ this.forceUpdate();
|
|
|
301
301
|
|
|
302
302
|
> **生成代码时的自检清单**:检查 `renderJsx` 中所有 `onClick`、`onChange`、`onSubmit` 等事件属性,确保每一个都是 `(e) => { this.xxx(e) }` 形式,不存在任何 `onClick={this.xxx}` 的写法。
|
|
303
303
|
|
|
304
|
+
// ❌ 错误③:在 .map(function(){}) 普通函数回调中使用箭头函数事件处理器,this 已在 function 回调里丢失,箭头函数捕获的 this 是 undefined!
|
|
305
|
+
export function renderJsx() {
|
|
306
|
+
return (
|
|
307
|
+
<div>
|
|
308
|
+
{quickBtns.map(function(btn, idx) {
|
|
309
|
+
return (
|
|
310
|
+
<button
|
|
311
|
+
key={idx}
|
|
312
|
+
onClick={(e) => { this.goToForm(btn.form); }} // ❌ this 是 undefined,运行时报错
|
|
313
|
+
>
|
|
314
|
+
{btn.label}
|
|
315
|
+
</button>
|
|
316
|
+
);
|
|
317
|
+
})}
|
|
318
|
+
</div>
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// ✅ 正确:.map() 回调必须使用箭头函数,确保 this 正确捕获
|
|
323
|
+
export function renderJsx() {
|
|
324
|
+
return (
|
|
325
|
+
<div>
|
|
326
|
+
{quickBtns.map((btn, idx) => (
|
|
327
|
+
<button
|
|
328
|
+
key={idx}
|
|
329
|
+
onClick={(e) => { this.goToForm(btn.form); }} // ✅ 箭头函数回调 + 箭头函数事件处理器,this 正确
|
|
330
|
+
>
|
|
331
|
+
{btn.label}
|
|
332
|
+
</button>
|
|
333
|
+
))}
|
|
334
|
+
</div>
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
> **补充自检项**:检查 `renderJsx` 中所有 `.map()`、`.filter()`、`.forEach()` 等数组方法的回调,确保全部使用**箭头函数**形式 `(item) => ...`,不存在任何 `.map(function(item) {...})` 的写法,否则回调内部的 `this` 会丢失。
|
|
340
|
+
|
|
304
341
|
3. **输入法组合输入处理**:使用 `_isComposing` 标记配合 `compositionstart` / `compositionend` 事件,正确处理中文输入法的组合输入状态,避免输入过程中触发提交
|
|
305
342
|
4. **定时器清理**:在 `didUnmount` 中必须清理所有通过 `setInterval` / `setTimeout` 创建的定时器,防止内存泄漏
|
|
306
343
|
5. **错误处理**:所有 API 调用(`this.utils.yida.*`、`fetch`)必须使用 `.catch()` 处理异常,并通过 `this.utils.toast({ title: message, type: 'error' })` 向用户展示错误提示
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yida-flash-note-to-prd
|
|
3
|
-
description:
|
|
4
|
-
钉钉闪记转高质量 Prompt 技能。将钉钉闪记(会议录音转文字的会议纪要、AI 听记图文纪要)自动识别并转化为
|
|
5
|
-
高质量的结构化 prompt,输出到 prd/ 目录,可直接驱动后续宜搭应用开发流程。
|
|
6
|
-
支持文本、图片、闪记链接等多种输入方式。
|
|
7
|
-
当用户发送闪记内容(文本或图片)、提到"闪记"、"会议纪要"、"会议记录"等关键词时,自动触发此技能。
|
|
3
|
+
description: "钉钉闪记转高质量 Prompt 技能。将钉钉闪记(会议录音转文字的会议纪要、AI 听记图文纪要)自动识别并转化为高质量的结构化 prompt,输出到 prd/ 目录,可直接驱动后续宜搭应用开发流程。支持文本、图片、闪记链接等多种输入方式。当用户发送闪记内容(文本或图片)、提到「闪记」「会议纪要」「会议记录」等关键词时,自动触发此技能。"
|
|
8
4
|
---
|
|
9
5
|
|
|
10
6
|
# 钉钉闪记转高质量 Prompt 技能
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yida-ppt-slider
|
|
3
|
-
description:
|
|
4
|
-
宜搭自定义页面 PPT 幻灯片开发指南。用于在宜搭平台上创建全屏演示文稿式的幻灯片页面,
|
|
5
|
-
支持键盘翻页、移动端适配、演讲笔控制等功能。
|
|
6
|
-
适用于技术分享、产品路演、培训课件等场景。
|
|
3
|
+
description: "宜搭自定义页面 PPT 幻灯片开发指南。用于在宜搭平台上创建全屏演示文稿式的幻灯片页面,支持键盘翻页、移动端适配、演讲笔控制等功能。适用于技术分享、产品路演、培训课件等场景。"
|
|
7
4
|
---
|
|
8
5
|
|
|
9
6
|
# 宜搭 PPT 幻灯片开发指南
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yida-report
|
|
3
|
-
description:
|
|
4
|
-
宜搭原生报表技能,用于创建宜搭平台内置的原生报表页面(vc-yida-report 组件库),支持 16 种开箱即用的图表/表格/筛选器组件,通过 openyida create-report 命令生成报表 Schema 并发布。
|
|
5
|
-
本技能定位:创建宜搭原生报表(作为数据源),普通的「报表」「统计」需求默认使用本技能。
|
|
6
|
-
如需更美观的 ECharts 自定义可视化大屏,请使用 yida-chart 技能(依赖本技能创建的原生报表作为数据源)。
|
|
3
|
+
description: "宜搭原生报表技能,用于创建宜搭平台内置的原生报表页面(vc-yida-report 组件库),支持 16 种开箱即用的图表/表格/筛选器组件,通过 openyida create-report 命令生成报表 Schema 并发布。本技能定位:创建宜搭原生报表(作为数据源),普通的「报表」「统计」需求默认使用本技能。如需更美观的 ECharts 自定义可视化大屏,请使用 yida-chart 技能(依赖本技能创建的原生报表作为数据源)。"
|
|
7
4
|
---
|
|
8
5
|
|
|
9
6
|
# 宜搭原生报表 + ECharts 自定义看板 技能文档
|