openyida 2026.4.2-beta.9 → 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 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 工作目录模板 / 创建 yida-skills 软链接到当前 AI 工具环境
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 → 创建 yida-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
- const count = copyItem(
278
- 'project/',
279
- packageProjectDir,
280
- path.join(destBase, 'project'),
281
- isForce
282
- );
283
- results.push({ label: 'project/', dest: path.join(destBase, 'project'), count, type: 'copy' });
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
- console.log(t('copy.creating_symlink'));
301
- const success = createSymlink(packageYidaSkillsDir, destSkillsLink);
302
- results.push({
303
- label: 'yida-skills/',
304
- dest: destSkillsLink,
305
- count: success ? 1 : 0,
306
- type: 'symlink'
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
 
@@ -718,7 +718,7 @@ class FixEngine {
718
718
  case 'init-project': {
719
719
  try {
720
720
  const copy = require('./copy');
721
- await copy([]);
721
+ await copy.run([]);
722
722
  return {
723
723
  id: issue.id,
724
724
  fixed: true,
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
 
@@ -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 بشكل عام:',
@@ -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:',
@@ -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:',
@@ -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:',
@@ -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 :",
@@ -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 वैश्विक रूप से स्थापित है:',
@@ -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 がグローバルにインストールされていることを確認してください:',
@@ -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가 전역으로 설치되어 있는지 확인하세요:',
@@ -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:',
@@ -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 已正確全域安裝:',
@@ -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(home, '.real', 'workspace', 'project'),
91
+ workspaceRoot: path.join(env.AGENT_WORK_ROOT, 'workspace', 'project'),
91
92
  };
92
93
  }
93
94
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openyida",
3
- "version": "2026.04.02-beta.9",
3
+ "version": "2026.04.02",
4
4
  "description": "OpenYida CLI - 宜搭低代码 AI 开发工具(安装即用,零配置)",
5
5
  "bin": {
6
6
  "openyida": "./bin/yida.js",
@@ -233,7 +233,6 @@ export function requestMicrophone() {
233
233
  // 开始检测吹气
234
234
  self.startBlowDetection();
235
235
  }).catch(function(err) {
236
- console.log('麦克风权限被拒绝:', err);
237
236
  _customState.micPermission = 'denied';
238
237
  // 即使麦克风失败,用户仍可以点击蜡烛
239
238
  });
@@ -1,19 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * postinstall hook: auto-configure IDE integration after `npm install -g openyida`
3
+ * postinstall hook: skills installation + welcome guide after `npm install -g openyida`
4
4
  *
5
- * Copies the yida-skills/ folder into each AI tool's config directory.
6
- * Each tool discovers the skill pack by scanning its own config directory.
5
+ * 职责:
6
+ * 1. 清理旧版本遗留的错误安装(~/.xxx/yida-skills/,缺少 skills/ 中间层级)
7
+ * 2. 将 yida-skills/ 安装到各 AI 工具的正确 skills 目录
8
+ * 3. 首次安装欢迎引导
7
9
  *
8
- * Supported tools: Claude Code / OpenCode / Aone Copilot / Cursor / Qoder / Wukong
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
- * Symlink layout (no extra "skills/" subdirectory needed):
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,82 +57,86 @@ function copyDirRecursive(src, dest) {
65
57
  }
66
58
 
67
59
  /**
68
- * Install yida-skills by copying files into `ideConfigDir`.
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 installSkills(ideConfigDir) {
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
- existingStat = fs.lstatSync(destPath);
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
- /* does not exist, will create */
71
+ /* not exists, ok */
86
72
  }
73
+ }
87
74
 
88
- if (existingStat) {
89
- if (existingStat.isSymbolicLink()) {
90
- // Remove old symlink left by previous versions
91
- fs.unlinkSync(destPath);
92
- } else {
93
- fs.rmSync(destPath, { recursive: true, force: true });
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'));
96
84
 
85
+ // 安装到正确路径:~/<tool-config>/skills/yida-skills/
86
+ const skillsDir = path.join(toolConfigDir, 'skills');
87
+ const destPath = path.join(skillsDir, 'yida-skills');
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 installation (copy to each tool's config root) ─────────
98
+ // ── 1. Skills 安装 ───────────────────────────────────────────────────
99
+ // 安装到各 AI 工具的正确 skills 目录(悟空跳过,悟空通过手动上传技能)
101
100
 
102
- // Claude Code
101
+ // Claude Code — 始终安装(Claude Code 是主要目标用户)
103
102
  safeExec(() => {
104
- installSkills(path.join(HOME_DIR, '.claude'));
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
- installSkills(path.join(HOME_DIR, '.opencode'));
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
- installSkills(path.join(HOME_DIR, '.aone_copilot'));
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
- installSkills(path.join(HOME_DIR, '.cursor'));
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
- installSkills(path.join(HOME_DIR, '.qoder'));
130
+ installSkillsToTool(path.join(HOME_DIR, '.qoder'));
132
131
  }
133
132
  });
134
133
 
135
- // ── 2. Wukong integration ─────────────────────────────────────────────
136
-
134
+ // 悟空(Wukong)— 跳过安装,只清理旧版遗留
137
135
  safeExec(() => {
138
- if (fs.existsSync(path.join(HOME_DIR, '.real'))) {
139
- installSkills(path.join(HOME_DIR, '.real'));
140
- }
136
+ cleanupLegacy(path.join(HOME_DIR, '.real', 'yida-skills'));
141
137
  });
142
138
 
143
- // ── 3. 首次安装欢迎引导 ──────────────────────────────────────────────
139
+ // ── 2. 首次安装欢迎引导 ──────────────────────────────────────────────
144
140
 
145
141
  safeExec(() => {
146
142
  const FIRST_INSTALL_FLAG = path.join(HOME_DIR, '.openyida', 'installed');
@@ -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-beta.9
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. 一键诊断并自动修复:版本升级 + 环境检测 + project 目录初始化
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,8 +1,6 @@
1
1
  ---
2
2
  name: yida-formula
3
- description: >
4
- 宜搭公式编写规范。提供公式语法规则、字段引用方式、函数分类速查和常见场景示例。
5
- 当用户需要了解宜搭公式怎么写、有哪些函数可用、如何在字段中配置公式时,使用此技能。
3
+ description: "宜搭公式编写规范。提供公式语法规则、字段引用方式、函数分类速查和常见场景示例。当用户需要了解宜搭公式怎么写、有哪些函数可用、如何在字段中配置公式时,使用此技能。"
6
4
  ---
7
5
 
8
6
  # 宜搭公式编写规范
@@ -29,8 +29,6 @@ description: 宜搭登录态管理。扫码登录,Cookie 持久化到 .cache/c
29
29
 
30
30
  ## 命令
31
31
 
32
- ### 标准环境
33
-
34
32
  ```bash
35
33
  openyida login
36
34
  ```
@@ -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 自定义看板 技能文档