openyida 2026.8.26 → 2026.8.27-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.
Files changed (38) hide show
  1. package/README.md +11 -27
  2. package/bin/yida.js +12 -78
  3. package/lib/app/builder-ai-source.js +0 -2
  4. package/lib/asset/ai-image.js +1 -1
  5. package/lib/core/browser-handoff.js +1 -1
  6. package/lib/core/check-update.js +66 -21
  7. package/lib/core/command-manifest.js +0 -18
  8. package/lib/core/copy.js +37 -76
  9. package/lib/core/doctor.js +0 -1
  10. package/lib/core/env-cmd.js +0 -10
  11. package/lib/core/env.js +2 -10
  12. package/lib/core/locales/en.js +7 -11
  13. package/lib/core/locales/zh.js +7 -11
  14. package/lib/core/update.js +324 -15
  15. package/lib/core/utils.js +58 -115
  16. package/lib/report/chart-builder.js +26 -0
  17. package/lib/report/data-model.js +44 -48
  18. package/lib/report/field-utils.js +47 -3
  19. package/package.json +2 -9
  20. package/scripts/postinstall.js +2 -17
  21. package/yida-skills/references/task-retrospective.md +1 -1
  22. package/yida-skills/skills/yida-form-detail/SKILL.md +0 -1
  23. package/yida-skills/skills/yida-report/references/schema-builder-details.md +1 -1
  24. package/docs/capabilities.md +0 -222
  25. package/scripts/build-skills-package.js +0 -513
  26. package/scripts/check-release-risks.js +0 -254
  27. package/scripts/check-syntax.js +0 -112
  28. package/scripts/demo-dws.sh +0 -106
  29. package/scripts/generate-command-docs.js +0 -155
  30. package/scripts/i18n-baseline.json +0 -72
  31. package/scripts/nightly-smoke.js +0 -116
  32. package/scripts/solution-center-runner.js +0 -368
  33. package/scripts/validate-ci.sh +0 -64
  34. package/scripts/validate-command-manifest.js +0 -403
  35. package/scripts/validate-i18n.js +0 -227
  36. package/scripts/validate-package-size.js +0 -109
  37. package/scripts/validate-skills.js +0 -608
  38. package/scripts/validate-structure.js +0 -81
package/README.md CHANGED
@@ -50,6 +50,10 @@ npm install -g openyida
50
50
 
51
51
  OpenYida requires Node.js 18 or later. The package exposes both `openyida` and `yida` commands.
52
52
 
53
+ For npm global installations, OpenYida checks the npm registry before a normal command at most once every 24 hours. When a newer version is available, it installs that exact version and then reruns the original command. This behavior is identical whether the local command is launched from a terminal, Codex, Claude Code, or Qoder. Managed cloud Agent runtimes are excluded before any cache access, registry request, or npm invocation.
54
+
55
+ Set `OPENYIDA_NO_AUTO_UPDATE=1` to disable automatic updates. `OPENYIDA_AUTO_UPDATE_SECS` can override the check interval for development and testing. The explicit `openyida update` command remains available.
56
+
53
57
  If Codex is already installed, OpenYida also imports a local Codex plugin during postinstall. Restart Codex after installation, then type `@宜搭` or `@openyida` in the composer to attach the OpenYida context.
54
58
 
55
59
  ### 2. Check Your Environment
@@ -105,21 +109,7 @@ Build an IPD workflow for chip production, including approval nodes and dashboar
105
109
  Generate a public landing page and publish it to my Yida app.
106
110
  ```
107
111
 
108
- The agent can then call OpenYida commands to create the application, generate source files, publish pages, and return the final Yida URLs. In Codex, QwenWork, QoderWork, Qoder, and Wukong environments, successful creation and publish commands also include a browser handoff so the agent can open the resulting Yida page in the in-app browser. Use `--open` to force this handoff or `--no-open` to suppress it.
109
-
110
- ## Wukong Installation
111
-
112
- Wukong uses manual skill package installation instead of npm:
113
-
114
- 1. Download the latest `.zip` skill package from [GitHub Releases](https://github.com/openyida/openyida/releases).
115
- 2. Open Wukong.
116
- 3. Go to **Skill Center** > **Upload Skill** and select the downloaded package.
117
-
118
- For Wukong terminal work, make sure its bundled Node.js path is active before running `node`, `npm`, or `npx` commands:
119
-
120
- ```bash
121
- export PATH="$HOME/.real/.bin/node/bin:$PATH"
122
- ```
112
+ The agent can then call OpenYida commands to create the application, generate source files, publish pages, and return the final Yida URLs. In Codex, QwenWork, Qoder, Qoder IDE, and QoderWork environments, successful creation and publish commands also include a browser handoff so the agent can open the resulting Yida page in the in-app browser. Use `--open` to force this handoff or `--no-open` to suppress it.
123
113
 
124
114
  ## Supported AI Coding Tools
125
115
 
@@ -128,14 +118,13 @@ export PATH="$HOME/.real/.bin/node/bin:$PATH"
128
118
  | [Codex](https://openai.com/codex/) | Full support |
129
119
  | [Claude Code](https://claude.ai/code) | Full support |
130
120
  | [MuleRun](https://mulerun.com) | Full support |
131
- | [Aone Copilot](https://copilot.code.alibaba-inc.com) | Full support |
132
121
  | [OpenCode](https://opencode.ai) | Full support |
133
122
  | [Cursor](https://cursor.com/) | Full support |
134
123
  | [Visual Studio Code](https://code.visualstudio.com/) | Full support |
135
124
  | QwenWork(千问办公) | Full support |
136
- | [QoderWork](https://qoder.com) | Full support |
137
- | [Qoder](https://qoder.com) | Full support |
138
- | [Wukong](https://dingtalk.com/wukong) | Full support |
125
+ | [Qoder](https://qoder.com/download) | Full support |
126
+ | [Qoder IDE](https://qoder.com/ide) | Full support |
127
+ | [QoderWork](https://qoder.com/download) | Full support |
139
128
 
140
129
  ## How It Works
141
130
 
@@ -320,8 +309,6 @@ OPENYIDA_E2E=1 npm run eval:all -- --skill yida-dashboard --screenshot
320
309
  # whitelist. Use the Node version you start it with, so run `nvm use 20` first.
321
310
  npm run eval:dashboard # http://127.0.0.1:4500
322
311
 
323
- # You can also run eval directly via the CLI:
324
- openyida eval --mode comprehensive --skill yida-dashboard
325
312
  ```
326
313
 
327
314
  Configuration precedence is `CLI flag > env (OPENYIDA_EVAL_*) > scripts/eval/eval.config.json > defaults`.
@@ -501,7 +488,6 @@ Run `openyida --help` or `openyida <command> --help` for detailed usage.
501
488
  | `openyida copy [--force]` | Copy project working directory |
502
489
  | `openyida sample [--list]` | Output code samples/templates |
503
490
  | `openyida doctor [--fix]` | Environment diagnostics & auto-fix |
504
- | `openyida eval --mode <mode> [--skill <name>] [--runs N]` | Multi-dimensional skill evaluation (doc quality, routing accuracy, safety, etc.) |
505
491
  | `openyida db-seq-fix [--fix]` | Detect and repair PostgreSQL sequence drift |
506
492
  | `openyida formula evaluate <formula\|file> [--schema file]` | Static-check Yida formula syntax and field refs |
507
493
  | `openyida update` | Check and update to latest version |
@@ -545,22 +531,20 @@ Form field definitions can include `alias` or `componentAlias` to populate Yida
545
531
 
546
532
  ## Agent Skills
547
533
 
548
- The `yida-skills/` directory is the source skill library used by OpenYida during development. Release assets for Wukong are generated by `npm run build:skills`: the expanded package is written to `dist/skills/openyida/`, and the upload-ready zip is written to `openyida-skills.zip`.
534
+ The `yida-skills/` directory is the source skill library used by OpenYida during development and distributed with the npm package.
549
535
 
550
536
  | Path | Purpose |
551
537
  |------|---------|
552
538
  | `yida-skills/SKILL.md` | Entry point and skill index |
553
539
  | `yida-skills/skills/` | Self-contained sub-skills for app, form, process, page, data, and integration work |
554
540
  | `yida-skills/references/` | Shared Yida API, model API, and query-condition references |
555
- | `dist/skills/openyida/` | Generated Wukong upload package root; contains one root `SKILL.md` and reference-only subskill docs |
556
- | `openyida-skills.zip` | Generated Wukong upload package; upload this file in Wukong |
557
541
 
558
542
  When OpenYida is used inside a supported AI coding environment, these skills help the agent choose the right command sequence and file conventions.
559
543
 
560
- For Wukong manual import, upload the generated `openyida-skills.zip`. The package follows Wukong's custom skill rules: folder name and `frontmatter.name` are both `openyida`, root frontmatter only contains `name` and `description`, and long references live under `references/`.
561
-
562
544
  For QwenWork, use the same user-level global skills layout as QoderWork: `~/.qwenworkcn/skills/yida-skills/`. Skip QwenWork setup when `~/.qwenworkcn` is not present.
563
545
 
546
+ Qoder and Qoder IDE share the user-level `~/.qoder/skills/yida-skills/` directory. QoderWork remains a separate product and uses `~/.qoderwork/skills/yida-skills/`.
547
+
564
548
  For Codex, `npm install -g openyida` additionally creates a local plugin marketplace under `~/.openyida/codex-plugin` and enables `openyida@openyida` in `~/.codex/config.toml` when Codex is detected. This makes OpenYida show up in Codex's `@` plugin menu as **宜搭** after Codex reloads.
565
549
 
566
550
  ## Examples
package/bin/yida.js CHANGED
@@ -20,77 +20,6 @@ const command = process.argv[2];
20
20
  const args = process.argv.slice(3);
21
21
  const rawArgs = process.argv.slice(3);
22
22
 
23
- function isAgentEnvironment(env) {
24
- return !!(
25
- env.CODEX_SHELL ||
26
- env.CODEX_CI ||
27
- env.CODEX_THREAD_ID ||
28
- env.CODEX_HOME ||
29
- env.CLAUDE_CODE ||
30
- env.CLAUDE_CODE_ENTRYPOINT ||
31
- env.MULERUN_CHAT_ID ||
32
- env.MULE_DATA_DIR ||
33
- env.MULE_WORKSPACE_DIR ||
34
- env.OPENCODE ||
35
- env.OPENCODE_CLIENT ||
36
- env.QODER_IDE ||
37
- env.QODER_AGENT ||
38
- env.QODERCLI_INTEGRATION_MODE ||
39
- env.QODER_WORK_INTEGRATION_PRODUCT ||
40
- env.QWENWORK_INTEGRATION_MODE ||
41
- env.QWENWORKCN_INTEGRATION_MODE ||
42
- env.QWENWORK ||
43
- env.QWENWORK_CLIENT ||
44
- env.QWENWORK_WORKSPACE_DIR ||
45
- env.QWENWORK_SANDBOX_ID ||
46
- env.QWENWORK_PREVIEW_URL ||
47
- env.QWENWORK_VNC_URL ||
48
- (env.AGENT_PLATFORM || '').toLowerCase().includes('qwenwork') ||
49
- env.CURSOR_TRACE_ID ||
50
- env.AGENT_WORK_ROOT ||
51
- env.OPENYIDA_AGENT_MODE ||
52
- (env.__CFBundleIdentifier || '').toLowerCase().includes('codex') ||
53
- (env.__CFBundleIdentifier || '').toLowerCase().includes('qoder') ||
54
- (env.__CFBundleIdentifier || '').toLowerCase().includes('qwenwork') ||
55
- (env.__CFBundleIdentifier || '').toLowerCase().includes('qwen-work')
56
- );
57
- }
58
-
59
- function shouldRunUpdateCheck() {
60
- if (process.env.OPENYIDA_SKIP_UPDATE_CHECK || process.env.NO_UPDATE_NOTIFIER) {
61
- return false;
62
- }
63
- if (process.env.CI || isAgentEnvironment(process.env)) {
64
- return false;
65
- }
66
- if (!process.stderr.isTTY) {
67
- return false;
68
- }
69
- if (!command || command === '--help' || command === '-h' || command === '--version' || command === '-v') {
70
- return false;
71
- }
72
- if (args.includes('--help') || args.includes('-h')) {
73
- return false;
74
- }
75
- if (command === 'commands' || command === 'agent-capabilities' || command === 'mcp') {
76
- return false;
77
- }
78
- if (args.includes('--json') || args.includes('--check-only')) {
79
- return false;
80
- }
81
- return true;
82
- }
83
-
84
- function maybeCheckForUpdate() {
85
- if (!shouldRunUpdateCheck()) {
86
- return;
87
- }
88
- const { checkUpdate } = require('../lib/core/check-update');
89
- checkUpdate(currentVersion).catch(() => {});
90
- }
91
-
92
- maybeCheckForUpdate();
93
-
94
23
  function shouldUseEnvManagement(argsList) {
95
24
  const subCommand = argsList[0];
96
25
  return !!subCommand && subCommand !== '--json';
@@ -369,7 +298,6 @@ const UNSUPPORTED_LEGACY_LOGIN_FLAGS = new Set([
369
298
  '--browser',
370
299
  '--codex',
371
300
  '--qoder',
372
- '--wukong',
373
301
  ]);
374
302
 
375
303
  function findUnsupportedLegacyLoginFlag(...argLists) {
@@ -598,6 +526,18 @@ async function main() {
598
526
  applyQuietFlag();
599
527
  applyGlobalEnvironmentFlags();
600
528
 
529
+ const { maybeAutoUpdate } = require('../lib/core/update');
530
+ const updateResult = await maybeAutoUpdate({
531
+ currentVersion,
532
+ command,
533
+ args,
534
+ argv: process.argv,
535
+ });
536
+ if (updateResult.reexecuted) {
537
+ process.exitCode = updateResult.exitCode;
538
+ return;
539
+ }
540
+
601
541
  if (!command || command === '--help' || command === '-h') {
602
542
  handleFirstRunGuide();
603
543
  printHelp();
@@ -1258,12 +1198,6 @@ async function main() {
1258
1198
  break;
1259
1199
  }
1260
1200
 
1261
- case 'eval': {
1262
- const { main: evalMain } = require('../scripts/eval/runner');
1263
- await evalMain(args);
1264
- break;
1265
- }
1266
-
1267
1201
  default: {
1268
1202
  throwUnknownCommand(command, args);
1269
1203
  }
@@ -9,12 +9,10 @@ const SUPPORTED_BUILDER_AI_SOURCES = new Set([
9
9
  'qwenwork',
10
10
  'qoderwork',
11
11
  'qoder',
12
- 'wukong',
13
12
  'mulerun',
14
13
  'claude-code',
15
14
  'opencode',
16
15
  'cursor',
17
- 'aone-copilot',
18
16
  ]);
19
17
 
20
18
  function normalizeBuilderAiSource(source) {
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * 因此本模块不假装能生成图片,而是:
9
9
  * 1. 诚实地检测「是否存在内置图片生成能力」(目前恒为 false);
10
- * 2. 把「生成/寻找素材」这件事交回给正在驱动本 CLI 的智能体(Claude/悟空等),
10
+ * 2. 把「生成/寻找素材」这件事交回给正在驱动本 CLI 的智能体(Claude/Codex 等),
11
11
  * 由 skill 文档引导它:能自己生成就生成,否则去免费素材库搜真实图片;
12
12
  * 3. 提供推荐的免费/可商用素材库清单与使用纪律,供 skill / agent 参考。
13
13
  *
@@ -2,7 +2,7 @@
2
2
 
3
3
  const { detectActiveTool } = require('./utils');
4
4
 
5
- const BROWSER_TOOLS = ['codex', 'qwenwork', 'qoderwork', 'qoder', 'wukong'];
5
+ const BROWSER_TOOLS = ['codex', 'qwenwork', 'qoderwork', 'qoder'];
6
6
 
7
7
  function parseOpenOption(args) {
8
8
  let mode = null;
@@ -1,8 +1,7 @@
1
1
  /**
2
2
  * check-update.js - openyida 版本更新检查
3
3
  *
4
- * 向 npm registry 查询最新版本,有新版本时打印提示。
5
- * 全程异步,不阻塞主命令流程。
4
+ * 向 npm registry 查询 latest dist-tag,并提供 SemVer 比较。
6
5
  */
7
6
 
8
7
  'use strict';
@@ -32,32 +31,71 @@ function fetchLatestVersion() {
32
31
  });
33
32
  req.on('error', () => resolve(null));
34
33
  req.on('timeout', () => { req.destroy(); resolve(null); });
35
- req.on('socket', (socket) => {
36
- if (socket && typeof socket.unref === 'function') {
37
- socket.unref();
38
- }
39
- });
40
- if (typeof req.unref === 'function') {
41
- req.unref();
42
- }
43
34
  });
44
35
  }
45
36
 
46
37
  /**
47
38
  * 比较版本号,返回 latestVersion 是否比 currentVersion 更新。
48
- * 支持 semver 格式(major.minor.patch),pre-release 标签(如 -beta.1)会被忽略,
49
- * 仅比较数字部分。
39
+ * 实现 SemVer 2.0.0 的优先级规则,构建元数据不参与比较。
50
40
  */
51
41
  function isNewer(currentVersion, latestVersion) {
52
- // 截取 '-' 前的纯数字版本部分,兼容 pre-release 格式(如 1.2.3-beta.1)
53
- const parseStableVersion = (v) => (v || '').split('-')[0];
54
- const parseParts = (v) => parseStableVersion(v).split('.').map((n) => parseInt(n, 10) || 0);
55
- const [cMajor, cMinor, cPatch] = parseParts(currentVersion);
56
- const [lMajor, lMinor, lPatch] = parseParts(latestVersion);
42
+ const current = parseSemver(currentVersion);
43
+ const latest = parseSemver(latestVersion);
44
+ if (!current || !latest) {return false;}
57
45
 
58
- if (lMajor !== cMajor) {return lMajor > cMajor;}
59
- if (lMinor !== cMinor) {return lMinor > cMinor;}
60
- return lPatch > cPatch;
46
+ for (const key of ['major', 'minor', 'patch']) {
47
+ const compared = compareNumericIdentifier(latest[key], current[key]);
48
+ if (compared !== 0) {return compared > 0;}
49
+ }
50
+
51
+ return comparePrerelease(latest.prerelease, current.prerelease) > 0;
52
+ }
53
+
54
+ function parseSemver(version) {
55
+ if (typeof version !== 'string') {return null;}
56
+ const match = version.trim().match(
57
+ /^(?:v)?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/
58
+ );
59
+ if (!match) {return null;}
60
+ return {
61
+ major: match[1],
62
+ minor: match[2],
63
+ patch: match[3],
64
+ prerelease: match[4] ? match[4].split('.') : [],
65
+ };
66
+ }
67
+
68
+ function comparePrerelease(left, right) {
69
+ if (left.length === 0 || right.length === 0) {
70
+ if (left.length === right.length) {return 0;}
71
+ return left.length === 0 ? 1 : -1;
72
+ }
73
+
74
+ const length = Math.max(left.length, right.length);
75
+ for (let i = 0; i < length; i++) {
76
+ if (left[i] === undefined) {return -1;}
77
+ if (right[i] === undefined) {return 1;}
78
+ if (left[i] === right[i]) {continue;}
79
+
80
+ const leftNumeric = /^\d+$/.test(left[i]);
81
+ const rightNumeric = /^\d+$/.test(right[i]);
82
+ if (leftNumeric && rightNumeric) {
83
+ return compareNumericIdentifier(left[i], right[i]);
84
+ }
85
+ if (leftNumeric !== rightNumeric) {
86
+ return leftNumeric ? -1 : 1;
87
+ }
88
+ return left[i] > right[i] ? 1 : -1;
89
+ }
90
+ return 0;
91
+ }
92
+
93
+ function compareNumericIdentifier(left, right) {
94
+ if (left.length !== right.length) {
95
+ return left.length > right.length ? 1 : -1;
96
+ }
97
+ if (left === right) {return 0;}
98
+ return left > right ? 1 : -1;
61
99
  }
62
100
 
63
101
  /**
@@ -79,4 +117,11 @@ async function checkUpdate(currentVersion) {
79
117
  }
80
118
  }
81
119
 
82
- module.exports = { checkUpdate, isNewer, fetchLatestVersion };
120
+ module.exports = {
121
+ checkUpdate,
122
+ isNewer,
123
+ fetchLatestVersion,
124
+ parseSemver,
125
+ comparePrerelease,
126
+ compareNumericIdentifier,
127
+ };
@@ -387,13 +387,6 @@ const COMMAND_SIDE_EFFECTS = new Map([
387
387
  'update',
388
388
  ], sideEffect('local_write')),
389
389
 
390
- ...sideEffectEntries([
391
- 'eval',
392
- ], sideEffect('mixed', {
393
- read_actions: ['doc-quality', 'coverage', 'routing', 'safety', 'comprehensive', 'baseline', 'pipeline'],
394
- mutating_actions: ['e2e', 'generate'],
395
- })),
396
-
397
390
  ...sideEffectEntries([
398
391
  'app-list',
399
392
  'connector.detail',
@@ -666,13 +659,6 @@ const COMMAND_PERMISSIONS = new Map([
666
659
  }],
667
660
  })],
668
661
 
669
- ...permissionEntries([
670
- 'eval',
671
- ], actionDependentPermission({
672
- preauthorized_actions: ['doc-quality', 'coverage', 'routing', 'safety', 'comprehensive', 'baseline', 'pipeline'],
673
- ask_actions: ['e2e', 'generate'],
674
- })),
675
-
676
662
  ...permissionEntries([
677
663
  'add-validation',
678
664
  'app-online',
@@ -1298,10 +1284,6 @@ const COMMAND_GROUPS = [
1298
1284
  command('copy', ['copy'], 'copy [--force]', 'help.cmd_copy', { requiresLogin: false }),
1299
1285
  command('sample', ['sample'], 'sample [--list]', 'help.cmd_sample', { requiresLogin: false }),
1300
1286
  command('doctor', ['doctor'], 'doctor [--fix]', 'help.cmd_doctor', { requiresLogin: false }),
1301
- command('eval', ['eval'], 'eval --mode <mode> [--skill <name>] [--runs N]', 'help.cmd_eval', {
1302
- requiresLogin: false,
1303
- output: 'text|json',
1304
- }),
1305
1287
  command('db-seq-fix', ['db-seq-fix'], 'db-seq-fix [--fix]', 'help.cmd_db_seq_fix'),
1306
1288
  command('formula.evaluate', ['formula', 'evaluate'], 'formula evaluate <formula|file> [--schema file]', 'help.cmd_formula_evaluate', {
1307
1289
  requiresLogin: false,
package/lib/core/copy.js CHANGED
@@ -5,20 +5,17 @@
5
5
  * openyida copy → 复制 project/ 目录模板(默认,合并模式)
6
6
  * openyida copy --force → 复制 project/ 目录模板(强制覆盖,先清空目标目录)
7
7
  * openyida copy -skills → 复制 yida-skills/ 到当前 AI 工具的 skills 目录
8
- * 悟空环境下:删除已有 yida-skills/(悟空通过手动上传技能)
9
8
  * openyida copy -project → 复制 project/ 目录模板(与默认行为相同,显式指定)
10
9
  * openyida copy -project --force → 复制 project/ 目录模板(强制覆盖)
11
10
  *
12
11
  * 目标策略:
13
- * - 悟空(Wukong):复制/链接到 ~/.real/workspace/(专属 workspace,路径固定)
14
- * - 其他 AI 工具:复制/链接到当前工程目录(process.cwd())下
12
+ * - 复制/链接到当前工程目录(process.cwd())或宿主显式提供的工作区
15
13
  *
16
14
  * 源路径:npm 全局安装包根目录(通过 require.resolve 定位)
17
15
  *
18
16
  * project/ 合并模式(默认):已存在的文件强制覆盖,目标目录中多余的文件保留不动
19
17
  * project/ 强制模式(--force):先清空目标目录,再完整复制
20
- * yida-skills/(非悟空):复制到 <cwd>/yida-skills/,如目标已存在则先清理
21
- * yida-skills/(悟空):删除已有软链或目录(悟空通过手动上传技能,不需要复制)
18
+ * yida-skills/:复制到宿主的 skills 目录,如目标已存在则先清理
22
19
  */
23
20
 
24
21
  'use strict';
@@ -173,8 +170,7 @@ function ensureProjectWorkspaceDirs(projectDir) {
173
170
  }
174
171
 
175
172
  /**
176
- * 删除已有的 yida-skills 软链接或目录(悟空环境专用)。
177
- * 悟空通过手动上传技能,不需要软链,执行 -skills 时只做清理。
173
+ * 删除已有的 yida-skills 软链接或目录。
178
174
  * 使用 lstatSync 而非 existsSync,可以检测到悬空软链(目标不存在但链接本身存在)。
179
175
  * @returns {boolean} 是否执行了删除操作
180
176
  */
@@ -184,7 +180,6 @@ function removeSkillsLink(destLink) {
184
180
  stats = fs.lstatSync(destLink);
185
181
  } catch {
186
182
  // 路径不存在(包括悬空软链也不存在的情况)
187
- console.log(t('copy.wukong_skills_not_found', destLink));
188
183
  return false;
189
184
  }
190
185
 
@@ -217,20 +212,9 @@ function removeSkillsLink(destLink) {
217
212
  */
218
213
  function resolveDestBaseFromEnv(activeToolName, activeProjectRoot, envResults, options = {}) {
219
214
  const activeResult = envResults.find((r) => r.displayName === activeToolName);
220
- const isWukong = (activeResult && activeResult.dirName === '.real') ||
221
- (options.activeTool && options.activeTool.tool === 'wukong');
222
215
  const runtimeSource = (options.activeTool && options.activeTool.workspaceRootSource) ||
223
216
  (activeResult && activeResult.workspaceRootSource);
224
217
 
225
- if (isWukong) {
226
- if (activeProjectRoot) {
227
- return path.basename(activeProjectRoot) === 'project'
228
- ? path.dirname(activeProjectRoot)
229
- : activeProjectRoot;
230
- }
231
- return process.env.AGENT_WORK_ROOT || path.join(os.homedir(), '.real', 'workspace');
232
- }
233
-
234
218
  if (
235
219
  (activeResult || options.activeTool) &&
236
220
  activeProjectRoot &&
@@ -292,7 +276,6 @@ function run(args = process.argv.slice(3)) {
292
276
  label('Package', packageRoot, { stderr: false });
293
277
 
294
278
  // 2. 确定目标根目录(检测 AI 工具环境)
295
- // 同时获取 isWukong 标志,避免后续重复调用 detectEnvironment()
296
279
  const {
297
280
  activeTool,
298
281
  activeToolName,
@@ -302,9 +285,6 @@ function run(args = process.argv.slice(3)) {
302
285
  const runtimeOptions = activeTool ? { activeTool } : {};
303
286
  const projectResolution = resolveProjectRoot(runtimeOptions);
304
287
  const activeProjectRoot = projectResolution.projectRoot || detectedProjectRoot;
305
- const activeEnvResult = envResults.find((r) => r.isActive);
306
- const isWukong = (activeEnvResult && activeEnvResult.dirName === '.real') ||
307
- (activeTool && activeTool.tool === 'wukong');
308
288
  const destBase = resolveDestBaseFromEnv(activeToolName, activeProjectRoot, envResults, {
309
289
  allowCurrentDir: isForce,
310
290
  activeTool,
@@ -315,9 +295,7 @@ function run(args = process.argv.slice(3)) {
315
295
  }
316
296
 
317
297
  // 3. 确定要复制/链接的内容
318
- // - 指定了 -skills
319
- // 悟空环境:删除已有的 yida-skills/ 软链(悟空手动上传技能,不需要软链)
320
- // 其他环境:创建 yida-skills/ 软链接(如果存在实际目录则先删除)
298
+ // - 指定了 -skills:复制到 AI 工具可发现的 skills 目录
321
299
  // - 指定了 -project:只复制 project/
322
300
  // - 两者都没指定(默认):只复制 project/
323
301
  // - 两者都指定:同时处理两项
@@ -329,14 +307,13 @@ function run(args = process.argv.slice(3)) {
329
307
 
330
308
  if (shouldCopyProject) {
331
309
  // 检查 destBase 是否为空目录:
332
- // - 空目录(如悟空新工作区)→ 直接把 project/ 内容铺进 destBase,不创建 project/ 这层
310
+ // - 空目录 直接把 project/ 内容铺进 destBase,不创建 project/ 这层
333
311
  // - 非空目录(已有其他文件)→ 复制整个 project/ 目录(含目录本身)
334
312
  const destBaseEntries = fs.existsSync(destBase)
335
313
  ? fs.readdirSync(destBase).filter((name) => name !== '.DS_Store')
336
314
  : [];
337
315
  const isDestBaseEmpty = destBaseEntries.length === 0;
338
- const shouldUseProjectRootDirectly = !isWukong &&
339
- isExplicitRuntimeWorkspaceSource(projectResolution.source);
316
+ const shouldUseProjectRootDirectly = isExplicitRuntimeWorkspaceSource(projectResolution.source);
340
317
 
341
318
  const projectDestDir = (isDestBaseEmpty || shouldUseProjectRootDirectly)
342
319
  ? destBase
@@ -355,54 +332,41 @@ function run(args = process.argv.slice(3)) {
355
332
  }
356
333
 
357
334
  if (shouldLinkSkills) {
358
- if (isWukong) {
359
- // 悟空环境:删除已有软链或目录,不安装(悟空手动上传技能)
360
- const destSkillsLink = path.join(destBase, 'yida-skills');
361
- console.log(t('copy.wukong_skills_cleanup'));
362
- const removed = removeSkillsLink(destSkillsLink);
335
+ // 复制到 AI 工具配置目录的 skills/yida-skills/;
336
+ // 若宿主用户级目录不可写,按 capabilities 诊断降级到工作区可发现目录。
337
+ const activeResult = envResults.find((r) => r.isActive);
338
+ const skillsDiagnostics = buildSkillsDiagnostics({ ...runtimeOptions, projectResolution });
339
+ const selectedSkills = skillsDiagnostics.selected;
340
+
341
+ if (selectedSkills && selectedSkills.path) {
342
+ // 清理旧版遗留在根目录的错误安装
343
+ if (activeResult && selectedSkills.scope === 'user') {
344
+ removeSkillsLink(path.join(os.homedir(), activeResult.dirName, 'yida-skills'));
345
+ }
346
+
347
+ // 清理已有的 skills/yida-skills/(旧软链或旧目录)
348
+ removeSkillsLink(selectedSkills.path);
349
+
350
+ // 复制文件
351
+ fs.mkdirSync(path.dirname(selectedSkills.path), { recursive: true });
352
+ const count = mergeCopyDir(packageYidaSkillsDir, selectedSkills.path);
363
353
  results.push({
364
354
  label: 'yida-skills/',
365
- dest: destSkillsLink,
366
- count: removed ? 1 : 0,
367
- type: 'wukong-cleanup'
355
+ dest: selectedSkills.path,
356
+ count,
357
+ type: selectedSkills.workspace_only ? 'copy-workspace' : 'copy'
368
358
  });
369
359
  } else {
370
- // 其他环境:复制到 AI 工具配置目录的 skills/yida-skills/;
371
- // 若宿主用户级目录不可写,按 capabilities 诊断降级到工作区可发现目录。
372
- const activeResult = envResults.find((r) => r.isActive);
373
- const skillsDiagnostics = buildSkillsDiagnostics({ ...runtimeOptions, projectResolution });
374
- const selectedSkills = skillsDiagnostics.selected;
375
-
376
- if (selectedSkills && selectedSkills.path) {
377
- // 清理旧版遗留在根目录的错误安装
378
- if (activeResult && selectedSkills.scope === 'user') {
379
- removeSkillsLink(path.join(os.homedir(), activeResult.dirName, 'yida-skills'));
380
- }
381
-
382
- // 清理已有的 skills/yida-skills/(旧软链或旧目录)
383
- removeSkillsLink(selectedSkills.path);
384
-
385
- // 复制文件
386
- fs.mkdirSync(path.dirname(selectedSkills.path), { recursive: true });
387
- const count = mergeCopyDir(packageYidaSkillsDir, selectedSkills.path);
388
- results.push({
389
- label: 'yida-skills/',
390
- dest: selectedSkills.path,
391
- count,
392
- type: selectedSkills.workspace_only ? 'copy-workspace' : 'copy'
393
- });
394
- } else {
395
- // 未检测到 AI 工具,复制到当前目录下
396
- const destSkillsDest = path.join(destBase, 'yida-skills');
397
- removeSkillsLink(destSkillsDest);
398
- const count = mergeCopyDir(packageYidaSkillsDir, destSkillsDest);
399
- results.push({
400
- label: 'yida-skills/',
401
- dest: destSkillsDest,
402
- count,
403
- type: 'copy'
404
- });
405
- }
360
+ // 未检测到 AI 工具,复制到当前目录下
361
+ const destSkillsDest = path.join(destBase, 'yida-skills');
362
+ removeSkillsLink(destSkillsDest);
363
+ const count = mergeCopyDir(packageYidaSkillsDir, destSkillsDest);
364
+ results.push({
365
+ label: 'yida-skills/',
366
+ dest: destSkillsDest,
367
+ count,
368
+ type: 'copy'
369
+ });
406
370
  }
407
371
  }
408
372
 
@@ -423,9 +387,6 @@ function run(args = process.argv.slice(3)) {
423
387
  results.forEach((r) => {
424
388
  if (r.type === 'symlink') {
425
389
  listItem(`${c.cyan}${r.label.padEnd(14)}${c.reset} ${c.dim}→${c.reset} ${r.dest} ${c.dim}(${t('copy.symlink_label')})${c.reset}`, { stderr: false });
426
- } else if (r.type === 'wukong-cleanup') {
427
- const statusText = r.count > 0 ? t('copy.wukong_skills_cleaned') : t('copy.wukong_skills_not_found', r.dest);
428
- listItem(`${c.cyan}${r.label.padEnd(14)}${c.reset} ${c.dim}→${c.reset} ${r.dest} ${c.dim}(${statusText})${c.reset}`, { stderr: false });
429
390
  } else {
430
391
  listItem(`${c.cyan}${r.label.padEnd(14)}${c.reset} ${c.dim}→${c.reset} ${r.dest} ${c.dim}(${t('copy.files_count', r.count)})${c.reset}`, { stderr: false });
431
392
  }
@@ -351,7 +351,6 @@ class VersionChecker {
351
351
  const skillPaths = [
352
352
  path.join(this.projectRoot, 'yida-skills', 'SKILL.md'),
353
353
  path.join(require('os').homedir(), '.claude', 'yida-skills', 'SKILL.md'),
354
- path.join(require('os').homedir(), '.aone_copilot', 'yida-skills', 'SKILL.md'),
355
354
  ];
356
355
  for (const skillPath of skillPaths) {
357
356
  if (!fs.existsSync(skillPath)) {continue;}
@@ -112,16 +112,6 @@ function detectSetupRecommendation() {
112
112
  return 'intl';
113
113
  }
114
114
 
115
- let activeTool = null;
116
- try {
117
- activeTool = require('./utils').detectActiveTool();
118
- } catch {
119
- activeTool = null;
120
- }
121
- if (activeTool && activeTool.tool === 'wukong') {
122
- return 'intl';
123
- }
124
-
125
115
  return 'public';
126
116
  }
127
117