openyida 0.1.2 → 1.0.0-beta.0

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 (61) hide show
  1. package/README.md +68 -38
  2. package/bin/yida.js +164 -761
  3. package/lib/babel-transform/index.js +244 -0
  4. package/lib/babel-transform/jsx-utils.js +89 -0
  5. package/lib/check-update.js +72 -0
  6. package/lib/copy.js +258 -0
  7. package/lib/create-app.js +174 -0
  8. package/lib/create-form.js +2244 -0
  9. package/lib/create-page.js +89 -0
  10. package/lib/env.js +164 -0
  11. package/lib/get-page-config.js +102 -0
  12. package/lib/get-schema.js +76 -0
  13. package/lib/login.js +323 -0
  14. package/lib/publish.js +610 -0
  15. package/lib/save-share-config.js +268 -0
  16. package/lib/update-form-config.js +237 -0
  17. package/lib/utils.js +443 -0
  18. package/lib/verify-short-url.js +279 -0
  19. package/package.json +20 -7
  20. package/project/.cache/demo-schema.json +2353 -0
  21. package/project/pages/src/demo-birthday-game.js +833 -0
  22. package/project/pages/src/demo-future-vision-2026.js +1102 -0
  23. package/project/pages/src/demo-salary-calculator.js +904 -0
  24. package/project/prd/demo-birthday-game.md +39 -0
  25. package/project/prd/demo-future-vision-2026.md +78 -0
  26. package/project/prd/demo-salary-calculator.md +101 -0
  27. package/scripts/postinstall.js +114 -0
  28. package/yida-skills/SKILL.md +273 -0
  29. package/yida-skills/reference/association-form-field.md +469 -0
  30. package/yida-skills/reference/employee-field.md +17 -0
  31. package/yida-skills/reference/model-api.md +73 -0
  32. package/yida-skills/reference/serial-number-field.md +132 -0
  33. package/yida-skills/reference/yida-api.md +1208 -0
  34. package/yida-skills/skills/yida-app/SKILL.md +394 -0
  35. package/yida-skills/skills/yida-create-app/SKILL.md +158 -0
  36. package/yida-skills/skills/yida-create-form-page/SKILL.md +598 -0
  37. package/yida-skills/skills/yida-create-page/SKILL.md +103 -0
  38. package/yida-skills/skills/yida-custom-page/SKILL.md +533 -0
  39. package/yida-skills/skills/yida-get-schema/SKILL.md +90 -0
  40. package/yida-skills/skills/yida-login/SKILL.md +200 -0
  41. package/yida-skills/skills/yida-logout/SKILL.md +58 -0
  42. package/yida-skills/skills/yida-page-config/SKILL.md +261 -0
  43. package/yida-skills/skills/yida-publish-page/SKILL.md +113 -0
  44. package/.eslintrc.json +0 -25
  45. package/.github/workflows/ci.yml +0 -123
  46. package/.github/workflows/publish.yml +0 -105
  47. package/.github/workflows/update-contributors.yml +0 -151
  48. package/.openclaw/skills/yida-issue/SKILL.md +0 -27
  49. package/.openclaw/skills/yida-issue/scripts/create-issue.js +0 -317
  50. package/CLAUDE.md +0 -168
  51. package/CONTRIBUTING.md +0 -59
  52. package/install-skills.ps1 +0 -162
  53. package/install-skills.sh +0 -175
  54. package/pages/dist/.gitkeep +0 -0
  55. package/pages/src/.gitkeep +0 -0
  56. package/prd/salary-calculator.md +0 -15
  57. package/tests/cli.test.js +0 -930
  58. package/tests/install.test.js +0 -277
  59. package/tests/yida-issue.test.js +0 -314
  60. /package/{config.json → project/config.json} +0 -0
  61. /package/{.cache → project/pages/dist}/.gitkeep +0 -0
@@ -0,0 +1,89 @@
1
+ /**
2
+ * create-page.js - 宜搭自定义页面创建命令
3
+ *
4
+ * 用法:yidacli create-page <appType> "<pageName>"
5
+ */
6
+
7
+ "use strict";
8
+
9
+ const querystring = require("querystring");
10
+ const {
11
+ loadCookieData,
12
+ triggerLogin,
13
+ resolveBaseUrl,
14
+ httpPost,
15
+ requestWithAutoLogin,
16
+ } = require("./utils");
17
+
18
+ async function run(args) {
19
+ if (args.length < 2) {
20
+ console.error('用法: yidacli create-page <appType> "<pageName>"');
21
+ console.error('示例: yidacli create-page "APP_XXX" "游戏主页"');
22
+ process.exit(1);
23
+ }
24
+
25
+ const appType = args[0];
26
+ const pageName = args[1];
27
+
28
+ console.error("=".repeat(50));
29
+ console.error(" yidacli create-page - 宜搭自定义页面创建工具");
30
+ console.error("=".repeat(50));
31
+ console.error(`\n 应用 ID: ${appType}`);
32
+ console.error(` 页面名称: ${pageName}`);
33
+
34
+ // Step 1: 读取登录态
35
+ console.error("\n🔑 Step 1: 读取登录态");
36
+ let cookieData = loadCookieData();
37
+ if (!cookieData) {
38
+ console.error(" ⚠️ 未找到本地登录态,触发登录...");
39
+ cookieData = triggerLogin();
40
+ }
41
+
42
+ const authRef = {
43
+ csrfToken: cookieData.csrf_token,
44
+ cookies: cookieData.cookies,
45
+ baseUrl: resolveBaseUrl(cookieData),
46
+ cookieData,
47
+ };
48
+ console.error(` ✅ 登录态已就绪(${authRef.baseUrl})`);
49
+
50
+ // Step 2: 创建自定义页面
51
+ console.error("\n📄 Step 2: 创建自定义页面\n");
52
+ console.error(" 发送 saveFormSchemaInfo 请求...");
53
+
54
+ const response = await requestWithAutoLogin((auth) => {
55
+ const postData = querystring.stringify({
56
+ _csrf_token: auth.csrfToken,
57
+ formType: "display",
58
+ title: JSON.stringify({ zh_CN: pageName, en_US: pageName, type: "i18n" }),
59
+ });
60
+ return httpPost(
61
+ auth.baseUrl,
62
+ `/dingtalk/web/${appType}/query/formdesign/saveFormSchemaInfo.json`,
63
+ postData,
64
+ auth.cookies
65
+ );
66
+ }, authRef);
67
+
68
+ // 输出结果
69
+ console.error("\n" + "=".repeat(50));
70
+ if (response && response.success && response.content) {
71
+ const pageId = response.content.formUuid || response.content;
72
+ const pageUrl = `${authRef.baseUrl}/${appType}/workbench/${pageId}`;
73
+
74
+ console.error(" ✅ 页面创建成功!");
75
+ console.error(` pageId: ${pageId}`);
76
+ console.error(` 访问地址: ${pageUrl}`);
77
+ console.error("=".repeat(50));
78
+
79
+ console.log(JSON.stringify({ success: true, pageId, pageName, appType, url: pageUrl }));
80
+ } else {
81
+ const errorMsg = response ? response.errorMsg || "未知错误" : "请求失败";
82
+ console.error(` ❌ 创建失败: ${errorMsg}`);
83
+ console.error("=".repeat(50));
84
+ console.log(JSON.stringify({ success: false, error: errorMsg }));
85
+ process.exit(1);
86
+ }
87
+ }
88
+
89
+ module.exports = { run };
package/lib/env.js ADDED
@@ -0,0 +1,164 @@
1
+ /**
2
+ * env.js - 宜搭 CLI 环境检测
3
+ *
4
+ * 通过环境变量 + 文件特征检测当前运行环境,并输出环境信息。
5
+ */
6
+
7
+ "use strict";
8
+
9
+ const fs = require("fs");
10
+ const path = require("path");
11
+ const os = require("os");
12
+ const { detectActiveTool, loadCookieData, resolveBaseUrl, extractInfoFromCookies } = require("./utils");
13
+
14
+ const home = os.homedir();
15
+
16
+ /**
17
+ * 获取所有已安装的 AI 工具列表(用于展示)。
18
+ * 不判断当前是否活跃,只判断是否安装过。
19
+ *
20
+ * @returns {Array} 已安装工具列表
21
+ */
22
+ function getInstalledTools() {
23
+ const tools = [
24
+ { dirName: ".real", displayName: "悟空(Wukong)" },
25
+ { dirName: ".opencode", displayName: "OpenCode" },
26
+ { dirName: ".claudecode", displayName: "Claude Code" },
27
+ { dirName: ".aone_copilot", displayName: "Aone Copilot" },
28
+ { dirName: ".cursor", displayName: "Cursor" },
29
+ { dirName: ".qoder", displayName: "Qoder" },
30
+ { dirName: ".iflow", displayName: "iFlow" },
31
+ ];
32
+
33
+ return tools.filter(({ dirName }) => {
34
+ return fs.existsSync(path.join(home, dirName));
35
+ });
36
+ }
37
+
38
+ /**
39
+ * 检测当前 AI 工具环境。
40
+ * 返回当前活跃工具信息和所有已安装工具列表。
41
+ */
42
+ function detectEnvironment() {
43
+ const activeTool = detectActiveTool();
44
+ const installedTools = getInstalledTools();
45
+ const cwdProject = path.join(process.cwd(), "project");
46
+
47
+ // 构建结果列表
48
+ const results = installedTools.map(({ dirName, displayName }) => {
49
+ const isWukong = dirName === ".real";
50
+ const isActive = activeTool && activeTool.dirName === dirName;
51
+ const workspaceRoot = isWukong
52
+ ? path.join(home, ".real", "workspace", "project")
53
+ : cwdProject;
54
+ const hasProject = fs.existsSync(workspaceRoot);
55
+
56
+ return {
57
+ displayName,
58
+ dirName,
59
+ isActive: !!isActive,
60
+ hasProject,
61
+ workspaceRoot,
62
+ };
63
+ });
64
+
65
+ // 当前生效环境
66
+ const activeToolName = activeTool ? activeTool.displayName : null;
67
+ const activeProjectRoot = activeTool ? activeTool.workspaceRoot : null;
68
+
69
+ return { activeToolName, activeProjectRoot, results };
70
+ }
71
+ /**
72
+ * 检测登录态信息。
73
+ */
74
+ function detectLoginStatus(projectRoot) {
75
+ const cookieData = loadCookieData(projectRoot);
76
+ if (!cookieData || !cookieData.cookies) {
77
+ return { loggedIn: false, csrfToken: null, corpId: null, userId: null, baseUrl: null };
78
+ }
79
+
80
+ const { csrfToken, corpId, userId } = extractInfoFromCookies(cookieData.cookies);
81
+ const baseUrl = resolveBaseUrl(cookieData);
82
+
83
+ return { loggedIn: !!csrfToken, csrfToken, corpId, userId, baseUrl };
84
+ }
85
+
86
+ /**
87
+ * 执行环境检测并打印结果。
88
+ */
89
+ function run() {
90
+ const SEP = "=".repeat(55);
91
+ console.log(SEP);
92
+ console.log(" yidacli env - 环境检测");
93
+ console.log(SEP);
94
+
95
+ // ── 系统信息 ──────────────────────────────────────
96
+ console.log("\n📋 系统信息");
97
+ console.log(` 操作系统: ${process.platform} (${os.arch()})`);
98
+ console.log(` Node.js: ${process.version}`);
99
+ console.log(` 主目录: ${os.homedir()}`);
100
+ console.log(` 工作目录: ${process.cwd()}`);
101
+
102
+ // ── AI 工具检测 ────────────────────────────────────
103
+ console.log("\n🤖 AI 工具检测");
104
+ const { activeToolName, activeProjectRoot, results } = detectEnvironment();
105
+
106
+ if (results.length === 0) {
107
+ console.log(" ⚠️ 未检测到任何已知 AI 工具");
108
+ } else {
109
+ for (const { displayName, isActive, hasProject, workspaceRoot } of results) {
110
+ let icon, note;
111
+ if (isActive && hasProject) {
112
+ icon = "✅";
113
+ note = "← 当前活跃,项目已就绪";
114
+ } else if (isActive && !hasProject) {
115
+ icon = "🟡";
116
+ note = "← 当前活跃,但无 project 工作目录";
117
+ } else if (!isActive && hasProject) {
118
+ icon = "⬜";
119
+ note = "(已安装,项目存在,但未活跃)";
120
+ } else {
121
+ icon = "⬜";
122
+ note = "(已安装,未活跃)";
123
+ }
124
+ console.log(` ${icon} ${displayName.padEnd(18)} ${note}`);
125
+ }
126
+ }
127
+
128
+ // ── 当前生效环境 ───────────────────────────────────
129
+ console.log("\n🎯 当前生效环境");
130
+ if (activeToolName && activeProjectRoot) {
131
+ console.log(` AI 工具: ${activeToolName}`);
132
+ console.log(` 项目根目录: ${activeProjectRoot}`);
133
+ } else {
134
+ const activeOnly = results.filter((r) => r.isActive);
135
+ if (activeOnly.length > 0) {
136
+ console.log(` AI 工具: ${activeOnly.map((r) => r.displayName).join(", ")} (活跃,但无 project 工作目录)`);
137
+ } else {
138
+ console.log(` AI 工具: 未检测到活跃工具`);
139
+ }
140
+ console.log(` 项目根目录: ${process.cwd()} (fallback)`);
141
+ }
142
+
143
+ // ── 登录态检测 ─────────────────────────────────────
144
+ console.log("\n🔐 登录态检测");
145
+ // 修复:检查 activeProjectRoot 是否存在,与 login.js 的 findProjectRoot() 行为保持一致
146
+ const projectRoot = (activeProjectRoot && fs.existsSync(activeProjectRoot))
147
+ ? activeProjectRoot
148
+ : process.cwd();
149
+ const loginStatus = detectLoginStatus(projectRoot);
150
+
151
+ if (loginStatus.loggedIn) {
152
+ console.log(` 状态: ✅ 已登录`);
153
+ console.log(` 域名: ${loginStatus.baseUrl}`);
154
+ console.log(` 组织 ID: ${loginStatus.corpId || "(未知)"}`);
155
+ console.log(` 用户 ID: ${loginStatus.userId || "(未知)"}`);
156
+ console.log(` csrf_token: ${loginStatus.csrfToken.slice(0, 16)}...`);
157
+ } else {
158
+ console.log(` 状态: ❌ 未登录(运行 yidacli login 进行登录)`);
159
+ }
160
+
161
+ console.log("\n" + SEP);
162
+ }
163
+
164
+ module.exports = { run, detectEnvironment, detectLoginStatus };
@@ -0,0 +1,102 @@
1
+ /**
2
+ * get-page-config.js - 宜搭页面公开访问/分享配置查询命令
3
+ *
4
+ * 用法:yidacli get-page-config <appType> <formUuid>
5
+ */
6
+
7
+ "use strict";
8
+
9
+ const querystring = require("querystring");
10
+ const {
11
+ loadCookieData,
12
+ triggerLogin,
13
+ refreshCsrfToken,
14
+ resolveBaseUrl,
15
+ httpPost,
16
+ requestWithAutoLogin,
17
+ } = require("./utils");
18
+
19
+ function parseArgs() {
20
+ const args = process.argv.slice(2);
21
+ if (args.length < 2) {
22
+ console.error("用法: yidacli get-page-config <appType> <formUuid>");
23
+ console.error('示例: yidacli get-page-config APP_XXX FORM-XXX');
24
+ process.exit(1);
25
+ }
26
+ return { appType: args[0], formUuid: args[1] };
27
+ }
28
+
29
+ async function main() {
30
+ const { appType, formUuid } = parseArgs();
31
+
32
+ console.error("=".repeat(50));
33
+ console.error(" get-page-config - 宜搭页面配置查询工具");
34
+ console.error("=".repeat(50));
35
+ console.error(`\n 应用 ID: ${appType}`);
36
+ console.error(` 表单 UUID: ${formUuid}`);
37
+
38
+ // Step 1: 读取登录态
39
+ console.error("\n🔑 Step 1: 读取登录态");
40
+ let cookieData = loadCookieData();
41
+ if (!cookieData) {
42
+ console.error(" ⚠️ 未找到本地登录态,触发登录...");
43
+ cookieData = triggerLogin();
44
+ }
45
+
46
+ const authRef = {
47
+ csrfToken: cookieData.csrf_token,
48
+ cookies: cookieData.cookies,
49
+ baseUrl: resolveBaseUrl(cookieData),
50
+ cookieData,
51
+ };
52
+ console.error(` ✅ 登录态已就绪(${authRef.baseUrl})`);
53
+
54
+ // Step 2: 查询分享配置
55
+ console.error("\n🔍 Step 2: 查询页面配置");
56
+ console.error(" 发送 getShareConfig 请求...");
57
+
58
+ const shareConfig = await requestWithAutoLogin((auth) => {
59
+ const postData = querystring.stringify({
60
+ _api: "Share.getShareConfig",
61
+ _csrf_token: auth.csrfToken,
62
+ _locale_time_zone_offset: "28800000",
63
+ formUuid,
64
+ });
65
+ return httpPost(
66
+ auth.baseUrl,
67
+ `/dingtalk/web/${appType}/query/formdesign/getShareConfig.json`,
68
+ postData,
69
+ auth.cookies
70
+ );
71
+ }, authRef);
72
+
73
+ // 输出结果
74
+ console.error("\n" + "=".repeat(50));
75
+ if (shareConfig && shareConfig.success !== false && !shareConfig.__needLogin && !shareConfig.__csrfExpired) {
76
+ const content = shareConfig.content || {};
77
+ const result = {
78
+ isOpen: content.isOpen === "y",
79
+ openUrl: content.openUrl || null,
80
+ shareUrl: content.shareUrl || null,
81
+ };
82
+
83
+ console.error(" ✅ 查询成功!");
84
+ console.error("=".repeat(50));
85
+
86
+ if (result.openUrl) console.error(` 公开访问: ${authRef.baseUrl}${result.openUrl}`);
87
+ if (result.shareUrl) console.error(` 组织内分享: ${authRef.baseUrl}${result.shareUrl}`);
88
+ if (!result.openUrl && !result.shareUrl) console.error(" (暂未配置公开访问或分享链接)");
89
+
90
+ console.log(JSON.stringify(result, null, 2));
91
+ } else {
92
+ const errorMsg = shareConfig ? shareConfig.errorMsg || "未知错误" : "请求失败";
93
+ console.error(` ❌ 查询失败: ${errorMsg}`);
94
+ console.error("=".repeat(50));
95
+ process.exit(1);
96
+ }
97
+ }
98
+
99
+ main().catch((error) => {
100
+ console.error(`\n❌ 查询异常: ${error.message}`);
101
+ process.exit(1);
102
+ });
@@ -0,0 +1,76 @@
1
+ /**
2
+ * get-schema.js - 宜搭表单 Schema 获取命令
3
+ *
4
+ * 用法:yidacli get-schema <appType> <formUuid>
5
+ */
6
+
7
+ "use strict";
8
+
9
+ const {
10
+ loadCookieData,
11
+ triggerLogin,
12
+ resolveBaseUrl,
13
+ httpGet,
14
+ requestWithAutoLogin,
15
+ } = require("./utils");
16
+
17
+ async function run(args) {
18
+ if (args.length < 2) {
19
+ console.error("用法: yidacli get-schema <appType> <formUuid>");
20
+ console.error('示例: yidacli get-schema "APP_XXX" "FORM-XXX"');
21
+ process.exit(1);
22
+ }
23
+
24
+ const appType = args[0];
25
+ const formUuid = args[1];
26
+
27
+ console.error("=".repeat(50));
28
+ console.error(" yidacli get-schema - 宜搭表单 Schema 获取工具");
29
+ console.error("=".repeat(50));
30
+ console.error(`\n 应用 ID: ${appType}`);
31
+ console.error(` 表单 UUID: ${formUuid}`);
32
+
33
+ // Step 1: 读取登录态
34
+ console.error("\n🔑 Step 1: 读取登录态");
35
+ let cookieData = loadCookieData();
36
+ if (!cookieData) {
37
+ console.error(" ⚠️ 未找到本地登录态,触发登录...");
38
+ cookieData = triggerLogin();
39
+ }
40
+
41
+ const authRef = {
42
+ csrfToken: cookieData.csrf_token,
43
+ cookies: cookieData.cookies,
44
+ baseUrl: resolveBaseUrl(cookieData),
45
+ cookieData,
46
+ };
47
+ console.error(` ✅ 登录态已就绪(${authRef.baseUrl})`);
48
+
49
+ // Step 2: 获取表单 Schema
50
+ console.error("\n📄 Step 2: 获取表单 Schema");
51
+ console.error(" 发送 getFormSchema 请求...");
52
+
53
+ const result = await requestWithAutoLogin((auth) => {
54
+ return httpGet(
55
+ auth.baseUrl,
56
+ `/alibaba/web/${appType}/_view/query/formdesign/getFormSchema.json`,
57
+ { formUuid, schemaVersion: "V5" },
58
+ auth.cookies
59
+ );
60
+ }, authRef);
61
+
62
+ // 输出结果
63
+ console.error("\n" + "=".repeat(50));
64
+ if (result && result.success !== false && !result.__needLogin && !result.__csrfExpired) {
65
+ console.error(" ✅ Schema 获取成功!");
66
+ console.error("=".repeat(50));
67
+ console.log(JSON.stringify(result, null, 2));
68
+ } else {
69
+ const errorMsg = result ? result.errorMsg || "未知错误" : "请求失败";
70
+ console.error(` ❌ 获取 Schema 失败: ${errorMsg}`);
71
+ console.error("=".repeat(50));
72
+ process.exit(1);
73
+ }
74
+ }
75
+
76
+ module.exports = { run };