yidaconnector 2026.6.11

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 (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +383 -0
  3. package/bin/yida.js +670 -0
  4. package/lib/app/form-navigation.js +58 -0
  5. package/lib/app/get-schema.js +538 -0
  6. package/lib/auth/auth.js +294 -0
  7. package/lib/auth/cdp-browser-login.js +390 -0
  8. package/lib/auth/codex-login.js +71 -0
  9. package/lib/auth/login.js +475 -0
  10. package/lib/auth/org.js +363 -0
  11. package/lib/auth/qr-login.js +1563 -0
  12. package/lib/core/chalk.js +384 -0
  13. package/lib/core/check-update.js +82 -0
  14. package/lib/core/cli-error.js +39 -0
  15. package/lib/core/command-manifest.js +106 -0
  16. package/lib/core/env-cmd.js +545 -0
  17. package/lib/core/env-manager.js +601 -0
  18. package/lib/core/env.js +287 -0
  19. package/lib/core/i18n.js +177 -0
  20. package/lib/core/locales/ar.js +805 -0
  21. package/lib/core/locales/de.js +805 -0
  22. package/lib/core/locales/en.js +1623 -0
  23. package/lib/core/locales/es.js +805 -0
  24. package/lib/core/locales/fr.js +805 -0
  25. package/lib/core/locales/hi.js +805 -0
  26. package/lib/core/locales/ja.js +1197 -0
  27. package/lib/core/locales/ko.js +807 -0
  28. package/lib/core/locales/pt.js +805 -0
  29. package/lib/core/locales/vi.js +805 -0
  30. package/lib/core/locales/zh-HK.js +1233 -0
  31. package/lib/core/locales/zh.js +1584 -0
  32. package/lib/core/query-data.js +781 -0
  33. package/lib/core/redact.js +100 -0
  34. package/lib/core/utils.js +799 -0
  35. package/lib/core/yida-client.js +117 -0
  36. package/package.json +94 -0
  37. package/project/config.json +4 -0
  38. package/project/pages/src/demo-birthday-game.oyd.jsx +832 -0
  39. package/project/pages/src/demo-chip-insight.oyd.jsx +983 -0
  40. package/project/pages/src/demo-compat-smoke.oyd.jsx +58 -0
  41. package/project/pages/src/demo-crm-batch-entry.oyd.jsx +805 -0
  42. package/project/pages/src/demo-crm-dashboard.oyd.jsx +677 -0
  43. package/project/pages/src/demo-future-vision-2026.oyd.jsx +1102 -0
  44. package/project/pages/src/demo-ppt.oyd.jsx +1192 -0
  45. package/project/pages/src/demo-salary-calculator.oyd.jsx +904 -0
  46. package/project/pages/src/yidaconnector-knowledge-doc.oyd.jsx +1714 -0
  47. package/project/prd/demo-birthday-game.md +39 -0
  48. package/project/prd/demo-crm.md +463 -0
  49. package/project/prd/demo-dingtalk-ai-solution-center.md +425 -0
  50. package/project/prd/demo-future-vision-2026.md +78 -0
  51. package/project/prd/demo-salary-calculator.md +101 -0
  52. package/scripts/build-skills-package.js +406 -0
  53. package/scripts/check-syntax.js +59 -0
  54. package/scripts/demo-dws.sh +106 -0
  55. package/scripts/e2e-real/cleanup.js +67 -0
  56. package/scripts/e2e-real/fixtures/form-fields.json +18 -0
  57. package/scripts/e2e-real/full-runner.js +1566 -0
  58. package/scripts/e2e-real/runner.js +293 -0
  59. package/scripts/e2e-real/skill-coverage.js +115 -0
  60. package/scripts/generate-command-docs.js +109 -0
  61. package/scripts/nightly-smoke.js +134 -0
  62. package/scripts/postinstall.js +545 -0
  63. package/scripts/solution-center-runner.js +368 -0
  64. package/scripts/validate-ci.sh +50 -0
  65. package/scripts/validate-command-manifest.js +119 -0
  66. package/scripts/validate-package-size.js +78 -0
  67. package/scripts/validate-skills.js +247 -0
  68. package/scripts/validate-structure.js +66 -0
  69. package/yida-skills/SKILL.md +163 -0
  70. package/yida-skills/references/yida-api.md +1309 -0
  71. package/yida-skills/skills/large-file-write/SKILL.md +91 -0
  72. package/yida-skills/skills/large-file-write/references/write-patterns.md +149 -0
  73. package/yida-skills/skills/large-file-write/scripts/write.js +157 -0
  74. package/yida-skills/skills/yida-data-management/SKILL.md +252 -0
  75. package/yida-skills/skills/yida-data-management/references/api-matrix.md +49 -0
  76. package/yida-skills/skills/yida-data-management/references/data-format-guide.md +159 -0
  77. package/yida-skills/skills/yida-data-management/references/verified-endpoints.md +62 -0
  78. package/yida-skills/skills/yida-login/SKILL.md +159 -0
  79. package/yida-skills/skills/yida-logout/SKILL.md +67 -0
@@ -0,0 +1,545 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * postinstall hook: skills installation + Codex plugin import + welcome guide after `npm install -g yidaconnector`
4
+ *
5
+ * 职责:
6
+ * 1. 清理旧版本遗留的错误安装(~/.xxx/yida-skills/,缺少 skills/ 中间层级)
7
+ * 2. 将 yida-skills/ 安装到各 AI 工具的正确 skills 目录
8
+ * 3. Codex 已安装时,导入本地 Codex 插件,让用户可在 @ 菜单中选择「宜搭」
9
+ * 4. 首次安装欢迎引导
10
+ *
11
+ * 正确的 skills 安装路径(所有工具统一使用 skills/ 子目录):
12
+ * ~/.claude/skills/yida-skills/ ← <package>/yida-skills (copy)
13
+ * ~/.codex/skills/yida-skills/ ← <package>/yida-skills (copy)
14
+ * ~/.opencode/skills/yida-skills/ ← <package>/yida-skills (copy)
15
+ * ~/.aone_copilot/skills/yida-skills/ ← <package>/yida-skills (copy)
16
+ * ~/.cursor/skills/yida-skills/ ← <package>/yida-skills (copy)
17
+ * ~/.qoder/skills/yida-skills/ ← <package>/yida-skills (copy)
18
+ *
19
+ * 悟空(Wukong)通过手动上传技能,不在此安装。
20
+ */
21
+
22
+ 'use strict';
23
+
24
+ const path = require('path');
25
+ const fs = require('fs');
26
+ const os = require('os');
27
+
28
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
29
+ const PACKAGE_JSON = require(path.join(PACKAGE_ROOT, 'package.json'));
30
+ const SKILLS_DIR = path.join(PACKAGE_ROOT, 'yida-skills');
31
+ const HOME_DIR = os.homedir();
32
+ const CODEX_MARKETPLACE_NAME = 'yidaconnector';
33
+ const CODEX_PLUGIN_NAME = 'yidaconnector';
34
+ const CODEX_PLUGIN_LOGO_SVG = '<svg height="200" viewBox="0 0 1024 1024" width="200" xmlns="http://www.w3.org/2000/svg"><g fill="#0089FF"><path d="M966.743 0H57.498A57.197 57.197 0 0 0 .06 57.077v218.07a61.772 61.772 0 0 1 12.042 4.936L348.538 473.83l336.196-193.987a64.421 64.421 0 0 1 87.902 23.36l34.92 60.208a63.94 63.94 0 0 1-23.24 87.54L449.084 643.613v379.905h517.78a57.197 57.197 0 0 0 56.714-56.594V57.077A57.197 57.197 0 0 0 966.743 0z"/><path d="M.663 501.163v465.76a56.715 56.715 0 0 0 16.255 40.34 57.558 57.558 0 0 0 40.58 16.255H252.93V646.141z"/></g></svg>\n';
35
+
36
+ /**
37
+ * Run fn silently — never throws.
38
+ */
39
+ function safeExec(fn) {
40
+ try {
41
+ fn();
42
+ } catch {
43
+ /* ignore */
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Recursively copy a directory, overwriting existing files.
49
+ */
50
+ function copyDirRecursive(src, dest) {
51
+ if (!fs.existsSync(src)) {return;}
52
+ fs.mkdirSync(dest, { recursive: true });
53
+ const entries = fs.readdirSync(src, { withFileTypes: true });
54
+ for (const entry of entries) {
55
+ const srcPath = path.join(src, entry.name);
56
+ const destPath = path.join(dest, entry.name);
57
+ if (entry.isDirectory()) {
58
+ copyDirRecursive(srcPath, destPath);
59
+ } else {
60
+ fs.copyFileSync(srcPath, destPath);
61
+ }
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Write a JSON file with stable formatting.
67
+ */
68
+ function writeJsonFile(filePath, data) {
69
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
70
+ fs.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}\n`, 'utf8');
71
+ }
72
+
73
+ /**
74
+ * Escape a string for TOML output.
75
+ */
76
+ function tomlString(value) {
77
+ return JSON.stringify(value);
78
+ }
79
+
80
+ /**
81
+ * Return an ISO timestamp without milliseconds for compact config churn.
82
+ */
83
+ function nowIsoSeconds() {
84
+ return new Date().toISOString().replace(/\.\d{3}Z$/, 'Z');
85
+ }
86
+
87
+ /**
88
+ * 清理旧版遗留的错误路径(软链接或目录)。
89
+ */
90
+ function cleanupLegacy(dirPath) {
91
+ try {
92
+ const stat = fs.lstatSync(dirPath);
93
+ if (stat.isSymbolicLink()) {
94
+ fs.unlinkSync(dirPath);
95
+ } else if (stat.isDirectory()) {
96
+ fs.rmSync(dirPath, { recursive: true, force: true });
97
+ }
98
+ } catch {
99
+ /* not exists, ok */
100
+ }
101
+ }
102
+
103
+ /**
104
+ * 将 yida-skills 安装到 AI 工具的 skills 目录。
105
+ * 正确路径:~/<tool-config>/skills/yida-skills/
106
+ *
107
+ * 同时清理旧版遗留在根目录的错误安装:~/<tool-config>/yida-skills/
108
+ */
109
+ function installSkillsToTool(toolConfigDir) {
110
+ // 清理旧版遗留在根目录的错误安装(缺少 skills/ 中间层级)
111
+ cleanupLegacy(path.join(toolConfigDir, 'yida-skills'));
112
+
113
+ // 安装到正确路径:~/<tool-config>/skills/yida-skills/
114
+ const skillsDir = path.join(toolConfigDir, 'skills');
115
+ const destPath = path.join(skillsDir, 'yida-skills');
116
+
117
+ fs.mkdirSync(skillsDir, { recursive: true });
118
+
119
+ // 如果已存在,先清理(旧软链接或旧目录)
120
+ cleanupLegacy(destPath);
121
+
122
+ // 复制文件(不用软链接,确保 AI 工具首次扫描就能发现)
123
+ copyDirRecursive(SKILLS_DIR, destPath);
124
+ }
125
+
126
+ /**
127
+ * 构建 Codex 插件 manifest。
128
+ */
129
+ function createCodexPluginManifest() {
130
+ return {
131
+ name: CODEX_PLUGIN_NAME,
132
+ version: PACKAGE_JSON.version,
133
+ description: 'YidaConnector CLI plugin for building and managing Yida low-code apps from Codex.',
134
+ author: {
135
+ name: 'YidaConnector Contributors',
136
+ email: 'yize.shc@gmail.com',
137
+ url: 'https://github.com/bunnyrui/yidaconnector',
138
+ },
139
+ homepage: 'https://github.com/bunnyrui/yidaconnector',
140
+ repository: 'https://github.com/bunnyrui/yidaconnector',
141
+ license: PACKAGE_JSON.license || 'MIT',
142
+ keywords: ['yidaconnector', 'yida', 'low-code', 'aliyun', 'codex'],
143
+ skills: './skills/',
144
+ interface: {
145
+ displayName: '宜搭',
146
+ shortDescription: '通过 YidaConnector CLI 创建和管理宜搭应用、表单、页面与数据',
147
+ longDescription: 'Use YidaConnector from Codex to log in to Yida, create low-code apps, manage forms, publish custom pages, configure permissions, build reports, and query data through the yidaconnector command line.',
148
+ developerName: 'YidaConnector Contributors',
149
+ category: 'Productivity',
150
+ capabilities: ['Interactive', 'Write'],
151
+ websiteURL: 'https://github.com/bunnyrui/yidaconnector',
152
+ privacyPolicyURL: 'https://github.com/bunnyrui/yidaconnector',
153
+ termsOfServiceURL: 'https://github.com/bunnyrui/yidaconnector',
154
+ defaultPrompt: [
155
+ '帮我检查宜搭登录态并初始化项目',
156
+ '帮我创建一个宜搭应用和表单',
157
+ '帮我发布一个宜搭自定义页面',
158
+ ],
159
+ brandColor: '#0089FF',
160
+ composerIcon: './assets/logo.svg',
161
+ logo: './assets/logo.svg',
162
+ },
163
+ mcpServers: './.mcp.json',
164
+ };
165
+ }
166
+
167
+ /**
168
+ * 构建 Codex 插件 MCP 配置。
169
+ */
170
+ function createCodexMcpConfig() {
171
+ return {
172
+ mcpServers: {
173
+ yidaconnector: {
174
+ command: process.execPath,
175
+ args: [
176
+ path.join(PACKAGE_ROOT, 'bin', 'yida.js'),
177
+ 'mcp',
178
+ ],
179
+ cwd: '.',
180
+ },
181
+ },
182
+ };
183
+ }
184
+
185
+ /**
186
+ * 构建 Codex 插件总入口技能。
187
+ */
188
+ function createCodexPluginSkill() {
189
+ return `---
190
+ name: yidaconnector
191
+ description: >
192
+ YidaConnector / 宜搭总入口技能。用户提到宜搭、YidaConnector、Yida、低代码应用、创建应用、创建表单、自定义页面、
193
+ 页面发布、权限、报表、连接器、流程、数据查询或登录态管理时使用。通过 yidaconnector CLI 在 Codex 中操作宜搭平台。
194
+ ---
195
+
196
+ # YidaConnector 宜搭开发总入口
197
+
198
+ ## 目标
199
+
200
+ 使用 \`yidaconnector\` CLI 帮用户在 Codex 中完成宜搭低代码平台操作,包括登录态检查、应用创建、表单管理、自定义页面开发、页面发布、权限配置、报表、连接器、流程和数据查询。
201
+
202
+ ## 首要步骤
203
+
204
+ 在执行任何会创建、修改或发布真实宜搭资源的操作前,先运行只读检查:
205
+
206
+ \`\`\`bash
207
+ yidaconnector env --json
208
+ yidaconnector login --check-only --json
209
+ \`\`\`
210
+
211
+ 如果 \`yidaconnector\` 不存在,先提醒用户需要安装,或在用户同意后执行:
212
+
213
+ \`\`\`bash
214
+ npm install -g yidaconnector@latest
215
+ \`\`\`
216
+
217
+ 若登录态无效,执行:
218
+
219
+ \`\`\`bash
220
+ yidaconnector login --browser
221
+ \`\`\`
222
+
223
+ 登录完成后再次运行 \`yidaconnector login --check-only --json\` 验证缓存写入,再继续真实资源操作。
224
+
225
+ ## Codex Browser 边界
226
+
227
+ Codex App 的 in-app browser / \`@Browser\` 适合打开本地开发服务器、file-backed preview 和无需登录的公开页面,用于截图、点击和检查渲染状态。
228
+
229
+ 不要把 Codex in-app browser 用作宜搭登录 Cookie 来源:它不支持认证流程、登录态页面、普通浏览器 profile 或 Cookie 导出。
230
+
231
+ 需要登录并获得 CLI Cookie 时,优先运行:
232
+
233
+ \`\`\`bash
234
+ yidaconnector login --browser
235
+ \`\`\`
236
+
237
+ \`--browser\` 会打开常规本地浏览器并在登录成功后将 Cookie 写入 YidaConnector 缓存。只有在需要纯浏览器预览或检查公开页面时才使用 \`@Browser\`。
238
+
239
+ 在 Codex 中如果 \`yidaconnector login --codex-poll\` 返回 \`need_corp_selection\`,优先调用 YidaConnector MCP 工具
240
+ \`select_yida_login_organization\`,传入返回值里的 \`session_file\`。该工具会通过 MCP \`elicitation/create\`
241
+ 展示 Codex 原生组织单选控件,并在用户选择后完成 \`yidaconnector login --codex-select\`。
242
+
243
+ ## 工作目录
244
+
245
+ 执行宜搭开发前检查当前工作区是否已有 \`project/\` 目录。没有时运行:
246
+
247
+ \`\`\`bash
248
+ yidaconnector copy
249
+ \`\`\`
250
+
251
+ ## 子技能索引
252
+
253
+ 根据用户意图选择最匹配的子技能,并在执行前读取对应 \`SKILL.md\`:
254
+
255
+ | 意图 | 子技能 |
256
+ | --- | --- |
257
+ | 完整应用开发编排 | \`../yida-app/SKILL.md\` |
258
+ | 登录态管理 | \`../yida-login/SKILL.md\` |
259
+ | 退出登录 / 切换账号 | \`../yida-logout/SKILL.md\` |
260
+ | 创建应用 | \`../yida-create-app/SKILL.md\` |
261
+ | 创建自定义页面 | \`../yida-create-page/SKILL.md\` |
262
+ | 创建 / 更新表单页面 | \`../yida-create-form-page/SKILL.md\` |
263
+ | 创建流程表单 | \`../yida-create-process/SKILL.md\` |
264
+ | 获取单个 / 全部表单 Schema | \`../yida-get-schema/SKILL.md\` |
265
+ | 自定义页面 JSX 开发 | \`../yida-custom-page/SKILL.md\` |
266
+ | 发布自定义页面 | \`../yida-publish-page/SKILL.md\` |
267
+ | 页面公开访问 / 分享配置 | \`../yida-page-config/SKILL.md\` |
268
+ | 表单权限 | \`../yida-form-permission/SKILL.md\` |
269
+ | 数据查询与管理 | \`../yida-data-management/SKILL.md\` |
270
+ | 流程规则 | \`../yida-process-rule/SKILL.md\` |
271
+ | 集成自动化 | \`../yida-integration/SKILL.md\` |
272
+ | HTTP 连接器 | \`../yida-connector/SKILL.md\` |
273
+ | 图表页面 | \`../yida-chart/SKILL.md\` |
274
+ | 原生报表 | \`../yida-report/SKILL.md\` |
275
+ | 公式字段 | \`../yida-formula/SKILL.md\` |
276
+ | 公式静态检查 | \`../yida-formula-evaluate/SKILL.md\` |
277
+ | VOC 反馈整理 | \`../yida-voc/SKILL.md\` |
278
+ | 闪记 / 会议纪要转 PRD | \`../yida-flash-note-to-prd/SKILL.md\` |
279
+
280
+ ## 执行规则
281
+
282
+ - 不要编造 \`appType\`、\`formUuid\`、\`fieldId\`、\`reportId\`;必须从命令输出、缓存或 schema 中读取。
283
+ - 同一命令失败后,根据错误信息检查登录态、组织、参数和字段 ID;不要无修改地连续重试。
284
+ - 自定义页面发布前先运行 \`yidaconnector check-page\` 和 \`yidaconnector compile\`。
285
+ - JSON 配置写入文件后先解析校验,再调用会修改平台资源的命令。
286
+ - 新增用户可见文案或 CLI 行为时,遵循当前 YidaConnector 仓库的 \`AGENTS.md\` 开发规范。
287
+ `;
288
+ }
289
+
290
+ /**
291
+ * 写入 Codex 本地 marketplace。
292
+ */
293
+ function writeCodexMarketplace(marketplaceRoot) {
294
+ writeJsonFile(path.join(marketplaceRoot, '.agents', 'plugins', 'marketplace.json'), {
295
+ name: CODEX_MARKETPLACE_NAME,
296
+ interface: {
297
+ displayName: 'YidaConnector',
298
+ },
299
+ plugins: [
300
+ {
301
+ name: CODEX_PLUGIN_NAME,
302
+ source: {
303
+ source: 'local',
304
+ path: `./plugins/${CODEX_PLUGIN_NAME}`,
305
+ },
306
+ policy: {
307
+ installation: 'INSTALLED_BY_DEFAULT',
308
+ authentication: 'ON_INSTALL',
309
+ },
310
+ category: 'Productivity',
311
+ },
312
+ ],
313
+ });
314
+ }
315
+
316
+ /**
317
+ * 确保 Codex 配置中启用了 YidaConnector marketplace 和插件。
318
+ * 保守策略:只追加缺失 section;如果用户已经手动配置或禁用,不覆盖。
319
+ */
320
+ function ensureCodexConfig(codexDir, marketplaceRoot) {
321
+ const configPath = path.join(codexDir, 'config.toml');
322
+ let config = '';
323
+
324
+ if (fs.existsSync(configPath)) {
325
+ config = fs.readFileSync(configPath, 'utf8');
326
+ }
327
+
328
+ const chunks = [];
329
+ const pluginSection = `[plugins."${CODEX_PLUGIN_NAME}@${CODEX_MARKETPLACE_NAME}"]`;
330
+ const marketplaceSection = `[marketplaces.${CODEX_MARKETPLACE_NAME}]`;
331
+
332
+ if (!config.includes(pluginSection)) {
333
+ chunks.push(`${pluginSection}\nenabled = true`);
334
+ }
335
+
336
+ if (!config.includes(marketplaceSection)) {
337
+ chunks.push(
338
+ `${marketplaceSection}\nlast_updated = ${tomlString(nowIsoSeconds())}\nsource_type = "local"\nsource = ${tomlString(marketplaceRoot)}`,
339
+ );
340
+ }
341
+
342
+ if (chunks.length === 0) {return;}
343
+
344
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
345
+ const prefix = config ? (config.endsWith('\n') ? '\n' : '\n\n') : '';
346
+ fs.writeFileSync(configPath, `${config}${prefix}${chunks.join('\n\n')}\n`, 'utf8');
347
+ }
348
+
349
+ /**
350
+ * 将 YidaConnector 导入为 Codex 本地插件。
351
+ */
352
+ function installCodexPlugin() {
353
+ const codexDir = path.join(HOME_DIR, '.codex');
354
+ if (!fs.existsSync(codexDir)) {return false;}
355
+
356
+ const marketplaceRoot = path.join(HOME_DIR, '.yidaconnector', 'codex-plugin');
357
+ const pluginRoot = path.join(marketplaceRoot, 'plugins', CODEX_PLUGIN_NAME);
358
+
359
+ cleanupLegacy(pluginRoot);
360
+ fs.mkdirSync(path.join(pluginRoot, '.codex-plugin'), { recursive: true });
361
+
362
+ writeJsonFile(
363
+ path.join(pluginRoot, '.codex-plugin', 'plugin.json'),
364
+ createCodexPluginManifest(),
365
+ );
366
+ writeJsonFile(
367
+ path.join(pluginRoot, '.mcp.json'),
368
+ createCodexMcpConfig(),
369
+ );
370
+
371
+ fs.mkdirSync(path.join(pluginRoot, 'assets'), { recursive: true });
372
+ fs.writeFileSync(path.join(pluginRoot, 'assets', 'logo.svg'), CODEX_PLUGIN_LOGO_SVG, 'utf8');
373
+
374
+ copyDirRecursive(path.join(SKILLS_DIR, 'skills'), path.join(pluginRoot, 'skills'));
375
+ copyDirRecursive(path.join(SKILLS_DIR, 'references'), path.join(pluginRoot, 'references'));
376
+
377
+ fs.mkdirSync(path.join(pluginRoot, 'skills', CODEX_PLUGIN_NAME), { recursive: true });
378
+ fs.writeFileSync(
379
+ path.join(pluginRoot, 'skills', CODEX_PLUGIN_NAME, 'SKILL.md'),
380
+ createCodexPluginSkill(),
381
+ 'utf8',
382
+ );
383
+
384
+ writeCodexMarketplace(marketplaceRoot);
385
+ ensureCodexConfig(codexDir, marketplaceRoot);
386
+
387
+ return true;
388
+ }
389
+
390
+ // ── 1. Skills 安装 ───────────────────────────────────────────────────
391
+ // 安装到各 AI 工具的正确 skills 目录(悟空跳过,悟空通过手动上传技能)
392
+
393
+ let codexPluginInstalled = false;
394
+
395
+ // Claude Code — 始终安装(Claude Code 是主要目标用户)
396
+ safeExec(() => {
397
+ installSkillsToTool(path.join(HOME_DIR, '.claude'));
398
+ });
399
+
400
+ // Codex — 仅在已安装时安装 skills,并导入本地插件
401
+ safeExec(() => {
402
+ if (fs.existsSync(path.join(HOME_DIR, '.codex'))) {
403
+ installSkillsToTool(path.join(HOME_DIR, '.codex'));
404
+ codexPluginInstalled = installCodexPlugin();
405
+ }
406
+ });
407
+
408
+ // OpenCode — 仅在已安装时安装
409
+ safeExec(() => {
410
+ if (fs.existsSync(path.join(HOME_DIR, '.opencode'))) {
411
+ installSkillsToTool(path.join(HOME_DIR, '.opencode'));
412
+ }
413
+ });
414
+
415
+ // Aone Copilot — 仅在已安装时安装
416
+ safeExec(() => {
417
+ if (fs.existsSync(path.join(HOME_DIR, '.aone_copilot'))) {
418
+ installSkillsToTool(path.join(HOME_DIR, '.aone_copilot'));
419
+ }
420
+ });
421
+
422
+ // Cursor — 仅在已安装时安装
423
+ safeExec(() => {
424
+ if (fs.existsSync(path.join(HOME_DIR, '.cursor'))) {
425
+ installSkillsToTool(path.join(HOME_DIR, '.cursor'));
426
+ }
427
+ });
428
+
429
+ // Qoder — 仅在已安装时安装
430
+ safeExec(() => {
431
+ if (fs.existsSync(path.join(HOME_DIR, '.qoder'))) {
432
+ installSkillsToTool(path.join(HOME_DIR, '.qoder'));
433
+ }
434
+ });
435
+
436
+ // 悟空(Wukong)— 跳过安装,只清理旧版遗留
437
+ safeExec(() => {
438
+ cleanupLegacy(path.join(HOME_DIR, '.real', 'yida-skills'));
439
+ });
440
+
441
+ // ── 2. 首次安装欢迎引导 ──────────────────────────────────────────────
442
+
443
+ safeExec(() => {
444
+ const FIRST_INSTALL_FLAG = path.join(HOME_DIR, '.yidaconnector', 'installed');
445
+
446
+ const isFirstInstall = !fs.existsSync(FIRST_INSTALL_FLAG);
447
+ if (isFirstInstall) {
448
+ fs.mkdirSync(path.dirname(FIRST_INSTALL_FLAG), { recursive: true });
449
+ fs.writeFileSync(FIRST_INSTALL_FLAG, new Date().toISOString(), 'utf8');
450
+ }
451
+
452
+ printWelcomeGuide(isFirstInstall, codexPluginInstalled);
453
+ });
454
+
455
+ /**
456
+ * 打印欢迎引导信息
457
+ * @param {boolean} isFirstInstall - 是否首次安装
458
+ * @param {boolean} hasCodexPlugin - 是否已导入 Codex 插件
459
+ */
460
+ function printWelcomeGuide(isFirstInstall, hasCodexPlugin) {
461
+ const RESET = '\x1b[0m';
462
+ const BOLD = '\x1b[1m';
463
+ const DIM = '\x1b[2m';
464
+ const CYAN = '\x1b[36m';
465
+ const GREEN = '\x1b[32m';
466
+ const YELLOW = '\x1b[33m';
467
+ const BLUE = '\x1b[34m';
468
+ const MAGENTA = '\x1b[35m';
469
+ const BG_CYAN = '\x1b[46m';
470
+ const WHITE = '\x1b[37m';
471
+
472
+ const SEP = `${DIM}${'─'.repeat(60)}${RESET}`;
473
+
474
+ console.log('');
475
+ console.log(
476
+ `${BG_CYAN}${WHITE}${BOLD} 🎉 欢迎使用 YidaConnector! ${RESET}`,
477
+ );
478
+ console.log(SEP);
479
+
480
+ if (isFirstInstall) {
481
+ console.log(
482
+ `${BOLD}${GREEN} ✅ 安装成功!${RESET} 宜搭 AI 应用开发工具已就绪。`,
483
+ );
484
+ } else {
485
+ console.log(
486
+ `${BOLD}${GREEN} ✅ 更新成功!${RESET} YidaConnector 已升级到最新版本。`,
487
+ );
488
+ }
489
+
490
+ console.log('');
491
+ console.log(`${BOLD}${CYAN} 🚀 开启 AI 问答模式${RESET}`);
492
+ console.log(
493
+ ' 在 Codex / Claude Code / Aone Copilot / Cursor 等 AI 工具中直接对话:',
494
+ );
495
+ console.log('');
496
+
497
+ // 示例 prompt 展示
498
+ const prompts = [
499
+ { icon: '📋', text: '帮我用宜搭创建一个考勤管理系统' },
500
+ { icon: '💰', text: '帮我搭建个人薪资计算器应用' },
501
+ { icon: '🏢', text: '创建一个 CRM 客户管理系统' },
502
+ { icon: '🎂', text: '做一个生日祝福小程序' },
503
+ ];
504
+
505
+ prompts.forEach(({ icon, text }) => {
506
+ console.log(` ${icon} ${YELLOW}「${text}」${RESET}`);
507
+ });
508
+
509
+ console.log('');
510
+ console.log(SEP);
511
+ console.log(`${BOLD}${BLUE} 📖 基础使用步骤${RESET}`);
512
+ console.log('');
513
+ console.log(
514
+ ` ${BOLD}Step 1${RESET} 打开你的 AI 编程工具(Codex / Claude Code / Cursor 等)`,
515
+ );
516
+ console.log(` ${BOLD}Step 2${RESET} 直接用自然语言描述你想要的应用`);
517
+ console.log(
518
+ ` ${BOLD}Step 3${RESET} AI 自动调用 yidaconnector 命令完成创建和发布`,
519
+ );
520
+ console.log(` ${BOLD}Step 4${RESET} 获得可访问的宜搭应用链接 🎉`);
521
+ if (hasCodexPlugin) {
522
+ console.log('');
523
+ console.log(
524
+ ` ${BOLD}${GREEN}Codex 已导入宜搭插件:${RESET}重启 Codex 后可在输入框输入 ${CYAN}@宜搭${RESET}`,
525
+ );
526
+ }
527
+ console.log('');
528
+ console.log(SEP);
529
+ console.log(`${BOLD}${MAGENTA} ⚡ 快捷命令${RESET}`);
530
+ console.log('');
531
+ console.log(
532
+ ` ${CYAN}yidaconnector env${RESET} ${DIM}# 检测当前 AI 工具环境和登录态${RESET}`,
533
+ );
534
+ console.log(
535
+ ` ${CYAN}yidaconnector login${RESET} ${DIM}# 登录宜搭账号${RESET}`,
536
+ );
537
+ console.log(
538
+ ` ${CYAN}yidaconnector --help${RESET} ${DIM}# 查看所有命令${RESET}`,
539
+ );
540
+ console.log('');
541
+ console.log(SEP);
542
+ console.log(` ${DIM}📚 文档:https://github.com/bunnyrui/yidaconnector${RESET}`);
543
+ console.log(` ${DIM}💬 社区:钉钉扫码加入 YidaConnector 社区${RESET}`);
544
+ console.log('');
545
+ }