cloudcc-cli 2.3.1 → 2.3.3

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 (232) hide show
  1. package/.claude/settings.json +25 -0
  2. package/.cloudcc-cache.json +21 -4
  3. package/.cursor/skills/cloudcc-cli-dev.zip +0 -0
  4. package/.cursor/skills/cloudcc-cli-usage/SKILL.md +68 -0
  5. package/README.md +22 -0
  6. package/bin/cc.js +13 -8
  7. package/bin/index.js +9 -2
  8. package/bin/mcp.js +1 -1
  9. package/build/component-CCPlugin1774500425584.common.js +831 -0
  10. package/build/component-CCPlugin1774500425584.common.js.map +1 -0
  11. package/build/component-CCPlugin1774500425584.css +1 -0
  12. package/build/component-CCPlugin1774500425584.umd.js +874 -0
  13. package/build/component-CCPlugin1774500425584.umd.js.map +1 -0
  14. package/build/component-CCPlugin1774500425584.umd.min.js +8 -0
  15. package/build/component-CCPlugin1774500425584.umd.min.js.map +1 -0
  16. package/build/demo.html +1 -0
  17. package/{src/mcp → mcp}/tools/Class Editor Guide/handler.js +12 -4
  18. package/{src/mcp → mcp}/tools/Component Editor Guide/handler.js +15 -14
  19. package/{src/mcp → mcp}/tools/Trigger Editor Guide/handler.js +8 -2
  20. package/package.json +3 -2
  21. package/src/application/doc.js +46 -0
  22. package/src/application/docs/devguide.md +173 -0
  23. package/src/application/docs/introduction.md +81 -0
  24. package/src/application/index.js +1 -0
  25. package/src/brief/get.js +1 -1
  26. package/src/classes/create.js +6 -1
  27. package/src/classes/delete.js +7 -1
  28. package/src/classes/detail.js +8 -1
  29. package/src/classes/doc.js +49 -472
  30. package/src/classes/docs/devguide.md +541 -0
  31. package/src/classes/get.js +9 -2
  32. package/src/classes/index.js +2 -1
  33. package/src/classes/publish.js +6 -1
  34. package/src/classes/pull.js +6 -1
  35. package/src/classes/pullList.js +6 -3
  36. package/src/config/doc.js +31 -0
  37. package/src/config/docs/devguide.md +100 -0
  38. package/src/config/index.js +5 -0
  39. package/src/customPage/create.js +52 -19
  40. package/src/customPage/doc.js +46 -0
  41. package/src/customPage/docs/devguide.md +200 -0
  42. package/{.cursor/skills/cloudcc-cli-dev/docs//350/207/252/345/256/232/344/271/211/351/241/265/351/235/242.md → src/customPage/docs/introduction.md} +1 -5
  43. package/src/customPage/index.js +1 -0
  44. package/src/customSetting/create.js +9 -0
  45. package/src/customSetting/delete.js +10 -1
  46. package/src/customSetting/deleteCustomSettingField.js +43 -0
  47. package/src/customSetting/detail.js +10 -1
  48. package/src/customSetting/doc.js +22 -179
  49. package/src/customSetting/docs/devguide.md +181 -0
  50. package/src/customSetting/docs/introduction.md +3 -0
  51. package/src/customSetting/editCustomSettingField.js +34 -0
  52. package/src/customSetting/get.js +9 -0
  53. package/src/customSetting/index.js +6 -1
  54. package/src/customSetting/modify.js +30 -0
  55. package/src/customSetting/saveCustomSettingField.js +46 -0
  56. package/src/fields/doc.js +45 -0
  57. package/src/fields/docs/devguide.md +224 -0
  58. package/src/fields/docs/introduction.md +217 -0
  59. package/src/fields/index.js +1 -0
  60. package/src/globalSelectList/create.js +51 -0
  61. package/src/globalSelectList/delete.js +56 -0
  62. package/src/globalSelectList/detail.js +45 -0
  63. package/src/globalSelectList/doc.js +52 -0
  64. package/src/globalSelectList/docs/devguide.md +153 -0
  65. package/src/globalSelectList/docs/introduction.md +82 -0
  66. package/src/globalSelectList/get.js +31 -0
  67. package/src/globalSelectList/index.js +16 -0
  68. package/src/menu/create-page.js +43 -6
  69. package/src/menu/create-script.js +67 -19
  70. package/src/menu/doc.js +57 -0
  71. package/src/menu/docs/devguide.md +129 -0
  72. package/src/menu/docs/introduction.md +99 -0
  73. package/src/menu/index.js +1 -0
  74. package/src/menu/validator.js +80 -0
  75. package/src/object/doc.js +45 -0
  76. package/src/object/docs/devguide.md +112 -0
  77. package/src/object/docs/introduction.md +187 -0
  78. package/src/object/get.js +1 -23
  79. package/src/object/index.js +1 -0
  80. package/src/pagelayout/create.js +123 -0
  81. package/src/pagelayout/delete.js +57 -0
  82. package/src/pagelayout/doc.js +46 -0
  83. package/src/pagelayout/docs/devguide.md +83 -0
  84. package/src/pagelayout/docs/introduction.md +44 -0
  85. package/src/pagelayout/get.js +46 -0
  86. package/src/pagelayout/index.js +10 -0
  87. package/src/plugin/doc.js +43 -863
  88. package/src/plugin/docs/devguide.md +996 -0
  89. package/src/profile/create.js +108 -0
  90. package/src/profile/delete.js +59 -0
  91. package/src/profile/doc.js +46 -0
  92. package/src/profile/docs/devguide.md +77 -0
  93. package/src/profile/docs/introduction.md +123 -0
  94. package/src/profile/get.js +55 -0
  95. package/src/profile/index.js +14 -0
  96. package/src/project/doc.js +39 -372
  97. package/src/project/docs/devguide.md +359 -0
  98. package/src/project/docs/introduction.md +3 -0
  99. package/src/recordType/create.js +77 -0
  100. package/src/recordType/delete.js +52 -0
  101. package/src/recordType/doc.js +36 -0
  102. package/src/recordType/docs/devguide.md +160 -0
  103. package/src/recordType/docs/introduction.md +53 -0
  104. package/src/recordType/editInfo.js +39 -0
  105. package/src/recordType/editSave.js +47 -0
  106. package/src/recordType/getList.js +31 -0
  107. package/src/recordType/index.js +16 -3
  108. package/src/recordType/newInfo.js +39 -0
  109. package/src/recordType/validDelete.js +91 -0
  110. package/src/res.md +66 -0
  111. package/src/role/create.js +153 -0
  112. package/src/role/delete.js +59 -0
  113. package/src/role/doc.js +46 -0
  114. package/src/role/docs/devguide.md +81 -0
  115. package/src/role/docs/introduction.md +124 -0
  116. package/src/role/get.js +57 -0
  117. package/src/role/index.js +10 -0
  118. package/src/scheduleJob/doc.js +49 -0
  119. package/src/scheduleJob/docs/devguide.md +79 -0
  120. package/src/scheduleJob/docs/introduction.md +101 -0
  121. package/src/scheduleJob/index.js +5 -0
  122. package/src/script/delete.js +112 -0
  123. package/src/script/doc.js +31 -245
  124. package/src/script/docs/devguide.md +290 -0
  125. package/src/script/docs/introduction.md +48 -0
  126. package/src/script/index.js +1 -0
  127. package/src/staticResource/count.js +31 -10
  128. package/src/staticResource/create.js +97 -0
  129. package/src/staticResource/delete.js +30 -8
  130. package/src/staticResource/detail.js +32 -10
  131. package/src/staticResource/doc.js +21 -88
  132. package/src/staticResource/docs/devguide.md +157 -0
  133. package/src/staticResource/docs/introduction.md +3 -0
  134. package/src/staticResource/get.js +31 -8
  135. package/src/staticResource/index.js +2 -1
  136. package/src/timer/create.js +6 -1
  137. package/src/timer/delete.js +7 -1
  138. package/src/timer/detail.js +5 -5
  139. package/src/timer/doc.js +57 -0
  140. package/{.cursor/skills/cloudcc-cli-dev/docs/cloudcc/345/256/232/346/227/266/344/275/234/344/270/232.md → src/timer/docs/devguide.md} +83 -1
  141. package/src/timer/get.js +7 -1
  142. package/src/timer/index.js +3 -1
  143. package/src/timer/publish.js +6 -1
  144. package/src/timer/pull.js +6 -1
  145. package/src/timer/pullList.js +5 -3
  146. package/src/triggers/detail.js +5 -5
  147. package/src/triggers/doc.js +49 -364
  148. package/src/triggers/docs/devguide.md +442 -0
  149. package/src/triggers/get.js +7 -3
  150. package/src/triggers/index.js +1 -4
  151. package/src/triggers/pullList.js +7 -7
  152. package/src/user/create.js +50 -0
  153. package/src/user/delete.js +59 -0
  154. package/src/user/doc.js +46 -0
  155. package/src/user/docs/devguide.md +122 -0
  156. package/src/user/docs/introduction.md +124 -0
  157. package/src/user/get.js +112 -0
  158. package/src/user/index.js +12 -0
  159. package/src/user/update.js +96 -0
  160. package/src/user/view.js +60 -0
  161. package/test/classes.cli.test.js +7 -4
  162. package/test/customPage.cli.test.js +96 -0
  163. package/test/globalSelectList.cli.test.js +94 -0
  164. package/test/menu-script.cli.test.js +147 -0
  165. package/test/menu.cli.test.js +8 -1
  166. package/test/plugin.cli.test.js +5 -3
  167. package/test/timer.cli.test.js +15 -8
  168. package/test/trigger.cli.test.js +5 -3
  169. package/.cursor/skills/cloudcc-cli-dev/BACKEND_CLASS.md +0 -111
  170. package/.cursor/skills/cloudcc-cli-dev/BACKEND_SCHEDULE.md +0 -152
  171. package/.cursor/skills/cloudcc-cli-dev/BACKEND_TRIGGER.md +0 -150
  172. package/.cursor/skills/cloudcc-cli-dev/CLI_CHEATSHEET.md +0 -372
  173. package/.cursor/skills/cloudcc-cli-dev/CUSTOM-SETTING-API.md +0 -62
  174. package/.cursor/skills/cloudcc-cli-dev/INSTALL_AND_BOOTSTRAP.md +0 -62
  175. package/.cursor/skills/cloudcc-cli-dev/OBJECTS_AND_FIELDS.md +0 -214
  176. package/.cursor/skills/cloudcc-cli-dev/REQUIREMENTS_BREAKDOWN.md +0 -113
  177. package/.cursor/skills/cloudcc-cli-dev/SKILL.md +0 -66
  178. package/.cursor/skills/cloudcc-cli-dev/STATIC-RESOURCE-API.md +0 -60
  179. package/.cursor/skills/cloudcc-cli-dev/VUE_CUSTOM_COMPONENT.md +0 -151
  180. package/.cursor/skills/cloudcc-cli-dev/VUE_CUSTOM_PAGE.md +0 -216
  181. package/src/approval/approve.js +0 -105
  182. package/src/approval/get.js +0 -245
  183. package/src/approval/index.js +0 -11
  184. package/src/approval/reject.js +0 -105
  185. package/src/plugin/readme.md +0 -7
  186. /package/{src/mcp → mcp}/cliRunner.js +0 -0
  187. /package/{src/mcp → mcp}/index.js +0 -0
  188. /package/{src/mcp → mcp}/readme.md +0 -0
  189. /package/{src/mcp → mcp}/tools/Application Creator/handler.js +0 -0
  190. /package/{src/mcp → mcp}/tools/Approval/handler.js +0 -0
  191. /package/{src/mcp → mcp}/tools/Class Creator/handler.js +0 -0
  192. /package/{src/mcp → mcp}/tools/Class Detail Retriever/handler.js +0 -0
  193. /package/{src/mcp → mcp}/tools/Class List Retriever/handler.js +0 -0
  194. /package/{src/mcp → mcp}/tools/Class Publisher/handler.js +0 -0
  195. /package/{src/mcp → mcp}/tools/Class Puller/handler.js +0 -0
  196. /package/{src/mcp → mcp}/tools/Client Script Detail Retriever/handler.js +0 -0
  197. /package/{src/mcp → mcp}/tools/Client Script Editor Guide/handler.js +0 -0
  198. /package/{src/mcp → mcp}/tools/Client Script List Retriever/handler.js +0 -0
  199. /package/{src/mcp → mcp}/tools/Client Script Publisher/handler.js +0 -0
  200. /package/{src/mcp → mcp}/tools/Client Script Puller/handler.js +0 -0
  201. /package/{src/mcp → mcp}/tools/CloudCC Development Overview/handler.js +0 -0
  202. /package/{src/mcp → mcp}/tools/Component Creator/handler.js +0 -0
  203. /package/{src/mcp → mcp}/tools/Component Detail Retriever/handler.js +0 -0
  204. /package/{src/mcp → mcp}/tools/Component List Retriever/handler.js +0 -0
  205. /package/{src/mcp → mcp}/tools/Component Publisher/handler.js +0 -0
  206. /package/{src/mcp → mcp}/tools/Component Puller/handler.js +0 -0
  207. /package/{src/mcp → mcp}/tools/Dev Environment Creator/fetcher.js +0 -0
  208. /package/{src/mcp → mcp}/tools/Dev Environment Creator/handler.js +0 -0
  209. /package/{src/mcp → mcp}/tools/Dev Environment Validator/handler.js +0 -0
  210. /package/{src/mcp → mcp}/tools/Developer Key Setup Guide/fetcher.js +0 -0
  211. /package/{src/mcp → mcp}/tools/Developer Key Setup Guide/handler.js +0 -0
  212. /package/{src/mcp → mcp}/tools/JSP Migrator/handler.js +0 -0
  213. /package/{src/mcp → mcp}/tools/Menu Creator/handler.js +0 -0
  214. /package/{src/mcp → mcp}/tools/Object Creator/handler.js +0 -0
  215. /package/{src/mcp → mcp}/tools/Object Fields Creator/handler.js +0 -0
  216. /package/{src/mcp → mcp}/tools/Object Fields Retriever/handler.js +0 -0
  217. /package/{src/mcp → mcp}/tools/Object List Retriever/handler.js +0 -0
  218. /package/{src/mcp → mcp}/tools/Scheduled Class Creator/handler.js +0 -0
  219. /package/{src/mcp → mcp}/tools/Scheduled Class Detail Retriever/handler.js +0 -0
  220. /package/{src/mcp → mcp}/tools/Scheduled Class List Retriever/handler.js +0 -0
  221. /package/{src/mcp → mcp}/tools/Scheduled Class Publisher/handler.js +0 -0
  222. /package/{src/mcp → mcp}/tools/Scheduled Class Puller/handler.js +0 -0
  223. /package/{src/mcp → mcp}/tools/Trigger Creator/handler.js +0 -0
  224. /package/{src/mcp → mcp}/tools/Trigger Detail Retriever/handler.js +0 -0
  225. /package/{src/mcp → mcp}/tools/Trigger List Retriever/handler.js +0 -0
  226. /package/{src/mcp → mcp}/tools/Trigger Publisher/handler.js +0 -0
  227. /package/{src/mcp → mcp}/tools/Trigger Puller/handler.js +0 -0
  228. /package/{src/mcp → mcp}/tools/index.js +0 -0
  229. /package/{.cursor/skills/cloudcc-cli-dev/docs//350/207/252/345/256/232/344/271/211/347/261/273.md" → src/classes/docs/introduction.md} +0 -0
  230. /package/{.cursor/skills/cloudcc-cli-dev/docs/CloudCC/350/207/252/345/256/232/344/271/211/347/273/204/344/273/266/344/275/277/347/224/250/350/257/264/346/230/216.md" → src/plugin/docs/introduction.md} +0 -0
  231. /package/{.cursor/skills/cloudcc-cli-dev/docs/cloudcc/345/256/232/346/227/266/347/261/273.md" → src/timer/docs/introduction.md} +0 -0
  232. /package/{.cursor/skills/cloudcc-cli-dev/docs//350/247/246/345/217/221/345/231/250/347/261/273.md" → src/triggers/docs/introduction.md} +0 -0
@@ -0,0 +1,94 @@
1
+ const test = require("node:test");
2
+ const assert = require("node:assert/strict");
3
+ const { exec } = require("node:child_process");
4
+ const { promisify } = require("node:util");
5
+ const path = require("node:path");
6
+
7
+ const execAsync = promisify(exec);
8
+ const repoRoot = path.resolve(__dirname, "..");
9
+
10
+ function quoteArg(value) {
11
+ return `'${String(value).replace(/'/g, `'\\''`)}'`;
12
+ }
13
+
14
+ async function runCc(args) {
15
+ const cmd = `npx --prefix "${repoRoot}" cc ${args.map(quoteArg).join(" ")}`;
16
+ return execAsync(cmd, { cwd: repoRoot });
17
+ }
18
+
19
+ test("全局选项列表", async (t) => {
20
+ const ts = Date.now();
21
+ const label = `TestGSL${ts}`;
22
+ const name = `test_gsl_${ts}`;
23
+ let createdId = null;
24
+
25
+ await t.test("1) 获取 doc(globalSelectList introduction / devguide)", async () => {
26
+ const intro = await runCc(["doc", "globalSelectList", "introduction"]);
27
+ assert.match(intro.stdout, /全局选项列表/);
28
+
29
+ const devguide = await runCc(["doc", "globalSelectList", "devguide"]);
30
+ assert.match(devguide.stdout, /全局选项列表/);
31
+ });
32
+
33
+ await t.test("2) 获取全局选项列表(get)", async () => {
34
+ const { stdout } = await runCc(["get", "globalSelectList", repoRoot]);
35
+ const list = JSON.parse(stdout.trim());
36
+ assert.ok(Array.isArray(list), "get globalSelectList 应返回数组");
37
+ assert.ok(list.length >= 0, "列表长度应为非负整数");
38
+ });
39
+
40
+ await t.test("3) 新建全局选项列表(create)", async () => {
41
+ const body = encodeURI(
42
+ JSON.stringify({
43
+ label,
44
+ name,
45
+ description: "cli test 自动创建",
46
+ ptext: "选项A\r\n选项B\r\n选项C",
47
+ isPicklistSorted: "0",
48
+ isFirstDefault: "1",
49
+ })
50
+ );
51
+ const { stderr } = await runCc(["create", "globalSelectList", repoRoot, body]);
52
+ assert.match(stderr, /Success|created/i, "create 应输出成功信息");
53
+
54
+ // 从列表中找到刚创建的记录,取得 id
55
+ const { stdout } = await runCc(["get", "globalSelectList", repoRoot]);
56
+ const list = JSON.parse(stdout.trim());
57
+ const found = list.find((item) => item.name === name || item.label === label);
58
+ assert.ok(found, "新建后 get 列表中应能找到该记录");
59
+ createdId = found.id;
60
+ assert.ok(createdId, "新建记录应有 id");
61
+ });
62
+
63
+ await t.test("4) 获取详情(detail)", async () => {
64
+ assert.ok(createdId, "detail 测试需要 createdId");
65
+ const { stdout } = await runCc(["detail", "globalSelectList", repoRoot, createdId]);
66
+ const result = JSON.parse(stdout.trim());
67
+
68
+ assert.ok(result.globalSelect, "detail 应返回 globalSelect 字段");
69
+ assert.equal(result.globalSelect.id, createdId, "detail.globalSelect.id 应与请求 id 一致");
70
+ assert.ok(result.globalSelect.label, "detail.globalSelect 应包含 label");
71
+ assert.ok(result.globalSelect.name, "detail.globalSelect 应包含 name");
72
+
73
+ assert.ok(Array.isArray(result.enabledList), "detail 应返回 enabledList 数组");
74
+ assert.ok(result.enabledList.length >= 3, "enabledList 应包含新建时填写的 3 个选项");
75
+
76
+ assert.ok(Array.isArray(result.disabledList), "detail 应返回 disabledList 数组");
77
+ assert.ok(Array.isArray(result.useList), "detail 应返回 useList 数组");
78
+ });
79
+
80
+ await t.test("5) 删除全局选项列表(delete)", async () => {
81
+ assert.ok(createdId, "delete 测试需要 createdId");
82
+ const { stdout, stderr } = await runCc(["delete", "globalSelectList", repoRoot, createdId]);
83
+ const out = `${stdout}\n${stderr}`.trim();
84
+ assert.match(out, /Success|deleted/i, "delete 应输出成功信息");
85
+ });
86
+
87
+ await t.test("6) 删除后 get 列表中不再包含该记录", async () => {
88
+ assert.ok(createdId, "验证删除需要 createdId");
89
+ const { stdout } = await runCc(["get", "globalSelectList", repoRoot]);
90
+ const list = JSON.parse(stdout.trim());
91
+ const found = list.find((item) => item.id === createdId);
92
+ assert.equal(found, undefined, "删除后列表中不应再包含已删除记录");
93
+ });
94
+ });
@@ -0,0 +1,147 @@
1
+ const test = require("node:test");
2
+ const assert = require("node:assert/strict");
3
+ const path = require("node:path");
4
+ const { exec } = require("node:child_process");
5
+ const { promisify } = require("node:util");
6
+
7
+ const execAsync = promisify(exec);
8
+ const repoRoot = path.resolve(__dirname, "..");
9
+
10
+ function quoteArg(value) {
11
+ return `'${String(value).replace(/'/g, `'\\''`)}'`;
12
+ }
13
+
14
+ async function runCc(args) {
15
+ const cmd = `npx --prefix "${repoRoot}" cc ${args.map(quoteArg).join(" ")}`;
16
+ return execAsync(cmd, { cwd: repoRoot });
17
+ }
18
+
19
+ test("自定义脚本菜单管理流程:doc→创建脚本菜单→查询列表→删除", async (t) => {
20
+ const tabName = `CC测试脚本菜单_${Date.now()}`;
21
+ // pname 必须以字母开头,只能包含字母、数字、下划线
22
+ const pname = `test_script_menu_${Date.now()}`;
23
+ const functioncode = "ccc.alert('Hello from test');";
24
+ let menuId = null;
25
+
26
+ await t.test("0) 获取 doc(menu devguide 包含脚本菜单说明)", async () => {
27
+ const { stdout } = await runCc(["doc", "menu", "devguide"]);
28
+ assert.match(stdout, /脚本|script|functioncode/i, "devguide 应包含脚本菜单相关说明");
29
+ });
30
+
31
+ await t.test("1) 创建自定义脚本菜单(仅必需参数)", async () => {
32
+ const { stdout, stderr } = await runCc([
33
+ "create", "menu", "script",
34
+ repoRoot,
35
+ tabName,
36
+ pname
37
+ ]);
38
+ const out = `${stdout}\n${stderr}`.trim();
39
+ assert.match(out, /Success|成功/i, "create menu script 应输出成功信息");
40
+ assert.match(out, /console\.log\("hello"\)/i, "默认脚本内容应为 console.log(\"hello\")");
41
+ });
42
+
43
+ await t.test("2) 查询菜单列表(get menu)并匹配刚创建的脚本菜单", async () => {
44
+ const { stdout } = await runCc(["get", "menu", repoRoot]);
45
+ const list = JSON.parse(stdout.trim());
46
+ assert.ok(Array.isArray(list), "get menu 应返回数组");
47
+
48
+ // 脚本菜单可能在 scriptlist 中,也可能在合并后的列表中
49
+ const allMenus = Array.isArray(list) ? list : [];
50
+ const hit = allMenus.find((item) =>
51
+ item.tabName === tabName ||
52
+ item.tabLabel === tabName ||
53
+ item.label === tabName ||
54
+ item.name === tabName ||
55
+ item.pname === pname
56
+ );
57
+
58
+ if (!hit) {
59
+ console.error("[menu-script-test] 未在菜单列表定位到刚创建的脚本菜单,跳过删除步骤");
60
+ return;
61
+ }
62
+ menuId = hit.id;
63
+ assert.ok(menuId, "命中菜单应包含 id");
64
+ console.error(`\n[menu-script-test] 找到脚本菜单: ${hit.tabName || hit.label} (id=${menuId})`);
65
+ });
66
+
67
+ await t.test("3) 删除脚本菜单(delete menu)", async () => {
68
+ if (!menuId) {
69
+ console.error("[menu-script-test] 无 menuId,跳过 delete menu");
70
+ return;
71
+ }
72
+ const { stdout, stderr } = await runCc(["delete", "menu", repoRoot, menuId]);
73
+ const out = `${stdout}\n${stderr}`.trim();
74
+ assert.match(out, /Success|成功/i, "delete menu 应输出成功信息");
75
+ });
76
+ });
77
+
78
+ test("自定义脚本菜单完整参数测试", async (t) => {
79
+ const tabName = `CC脚本菜单完整_${Date.now()}`;
80
+ const pname = `full_test_menu_${Date.now()}`;
81
+ const functioncode = "console.log('Custom script executed'); ccc.alert('Done');";
82
+ const tabStyle = "cloudtab150";
83
+ const mobileimg = "cloudcc05";
84
+ let menuId = null;
85
+
86
+ await t.test("1) 创建带完整参数的脚本菜单", async () => {
87
+ const { stdout, stderr } = await runCc([
88
+ "create", "menu", "script",
89
+ repoRoot,
90
+ tabName,
91
+ pname,
92
+ functioncode,
93
+ tabStyle,
94
+ mobileimg
95
+ ]);
96
+ const out = `${stdout}\n${stderr}`.trim();
97
+ assert.match(out, /Success|成功/i, "带完整参数的 create menu script 应成功");
98
+ assert.match(out, /Custom script executed/, "应包含自定义脚本内容");
99
+ });
100
+
101
+ await t.test("2) 查询并清理", async () => {
102
+ const { stdout } = await runCc(["get", "menu", repoRoot]);
103
+ const list = JSON.parse(stdout.trim());
104
+ const hit = list.find((item) => item.tabName === tabName || item.pname === pname);
105
+ if (hit && hit.id) {
106
+ menuId = hit.id;
107
+ await runCc(["delete", "menu", repoRoot, menuId]);
108
+ console.error(`[menu-script-test] 已清理测试菜单: ${tabName}`);
109
+ }
110
+ });
111
+ });
112
+
113
+ test("自定义脚本菜单参数验证测试", async (t) => {
114
+ await t.test("1) 缺少 tabName 参数应返回错误", async () => {
115
+ await assert.rejects(
116
+ () => runCc(["create", "menu", "script", repoRoot]),
117
+ /Error|缺少|required/i,
118
+ "缺少必需参数时应报错"
119
+ );
120
+ });
121
+
122
+ await t.test("2) 自动生成 pname(当未提供时)", async () => {
123
+ const autoTabName = `AutoPnameTest_${Date.now()}`;
124
+ const { stdout, stderr } = await runCc([
125
+ "create", "menu", "script",
126
+ repoRoot,
127
+ autoTabName
128
+ // 不提供 pname,测试自动生成逻辑
129
+ ]);
130
+ const out = `${stdout}\n${stderr}`.trim();
131
+ // 由于 pname 是必需的,这里应该提示自动生成或报错
132
+ // 根据代码逻辑,如果不提供 pname 会尝试用 tabName 生成
133
+ console.error(`[menu-script-test] 自动生成测试输出: ${out.substring(0, 200)}`);
134
+
135
+ // 清理:查询并删除
136
+ try {
137
+ const { stdout: listOut } = await runCc(["get", "menu", repoRoot]);
138
+ const list = JSON.parse(listOut.trim());
139
+ const hit = list.find((item) => item.tabName === autoTabName);
140
+ if (hit && hit.id) {
141
+ await runCc(["delete", "menu", repoRoot, hit.id]);
142
+ }
143
+ } catch (e) {
144
+ // 忽略清理错误
145
+ }
146
+ });
147
+ });
@@ -16,12 +16,19 @@ async function runCc(args) {
16
16
  return execAsync(cmd, { cwd: repoRoot });
17
17
  }
18
18
 
19
- test("菜单管理流程:获取对象列表→create menu object", async (t) => {
19
+ test("菜单管理流程:doc→获取对象列表→create menu object", async (t) => {
20
20
  let objectId = null;
21
21
  let objectName = null;
22
22
  const tabName = `CC测试菜单Tab_${Date.now()}`;
23
23
  let menuId = null;
24
24
 
25
+ await t.test("0) 获取 doc(menu introduction / devguide)", async () => {
26
+ const intro = await runCc(["doc", "menu", "introduction"]);
27
+ assert.match(intro.stdout, /菜单/);
28
+ const dev = await runCc(["doc", "menu", "devguide"]);
29
+ assert.match(dev.stdout, /菜单/);
30
+ });
31
+
25
32
  await t.test("1) 获取自定义对象列表(取第一个自定义对象 id 用于创建菜单)", async () => {
26
33
  const { stdout } = await runCc(["get", "object", repoRoot, "custom"]);
27
34
  const list = JSON.parse(stdout.trim());
@@ -39,9 +39,11 @@ test("组件管理流程:创建→doc→发布→拉取→详情→列表→
39
39
  assert.ok(config.component && config.component.includes(pluginName));
40
40
  });
41
41
 
42
- t.test("2) 获取 doc(plugin overview)", async () => {
43
- const { stdout } = await runCc(["doc", "plugin", "overview"]);
44
- assert.ok(stdout.length > 0, "doc plugin 应有输出");
42
+ t.test("2) 获取 doc(plugin introduction / devguide)", async () => {
43
+ const intro = await runCc(["doc", "plugin", "introduction"]);
44
+ assert.match(intro.stdout, /自定义组件/);
45
+ const dev = await runCc(["doc", "plugin", "devguide"]);
46
+ assert.match(dev.stdout, /自定义组件/);
45
47
  });
46
48
 
47
49
  t.test("3) 发布组件(publish:以输出判断成功)", async () => {
@@ -18,7 +18,7 @@ async function runCc(args) {
18
18
  return execAsync(cmd, { cwd: repoRoot });
19
19
  }
20
20
 
21
- test("定时任务管理流程:创建→发布→拉取→线上详情→列表→批量拉取→delete→清空 schedule 文件夹", async (t) => {
21
+ test("定时任务管理流程:创建→doc→发布→拉取→线上详情→列表→批量拉取→delete→清空 schedule 文件夹", async (t) => {
22
22
  const timerName = `CCTimer${Date.now()}`;
23
23
  const timerDir = path.join(scheduleRoot, timerName);
24
24
  const configPath = path.join(timerDir, "config.json");
@@ -37,14 +37,21 @@ test("定时任务管理流程:创建→发布→拉取→线上详情→列
37
37
  assert.equal(config.name, timerName);
38
38
  });
39
39
 
40
- t.test("2) 发布定时任务(publish,写回 config.id)", async () => {
40
+ t.test("2) 获取 doc(timer introduction / devguide)", async () => {
41
+ const intro = await runCc(["doc", "timer", "introduction"]);
42
+ assert.match(intro.stdout, /定时类/);
43
+ const dev = await runCc(["doc", "timer", "devguide"]);
44
+ assert.match(dev.stdout, /定时/);
45
+ });
46
+
47
+ t.test("3) 发布定时任务(publish,写回 config.id)", async () => {
41
48
  await runCc(["publish", "timer", timerName]);
42
49
  const configAfterPublish = JSON.parse(fs.readFileSync(configPath, "utf8"));
43
50
  publishedId = configAfterPublish.id || null;
44
51
  assert.ok(publishedId, "publish 后应写入 config.id");
45
52
  });
46
53
 
47
- t.test("3) 拉取定时任务(pull:覆盖 SOURCE 区域)", async () => {
54
+ t.test("4) 拉取定时任务(pull:覆盖 SOURCE 区域)", async () => {
48
55
  const localJava = fs.readFileSync(javaPath, "utf8");
49
56
  const modifiedJava = localJava.replace(
50
57
  /\/\/ @SOURCE_CONTENT_START[\s\S]*?\/\/ @SOURCE_CONTENT_END/,
@@ -57,12 +64,12 @@ test("定时任务管理流程:创建→发布→拉取→线上详情→列
57
64
  assert.ok(!javaAfterPull.includes("LOCAL_ONLY"), "pull 后应使用远端源码替换本地标记内容");
58
65
  });
59
66
 
60
- t.test("4) 查询线上定时任务详情(detail:仅使用 id)", async () => {
67
+ t.test("5) 查询线上定时任务详情(detail:仅使用 id)", async () => {
61
68
  assert.ok(publishedId, "发布后应有 publishedId");
62
69
  await assert.doesNotReject(() => runCc(["detail", "timer", "", publishedId]));
63
70
  });
64
71
 
65
- t.test("5) get 获取线上定时任务列表(取前2个 id)", async () => {
72
+ t.test("6) get 获取线上定时任务列表(取前2个 id)", async () => {
66
73
  const listQuery = encodeURI(
67
74
  JSON.stringify({
68
75
  shownum: "2000",
@@ -80,7 +87,7 @@ test("定时任务管理流程:创建→发布→拉取→线上详情→列
80
87
  assert.ok(topIds.length >= 1, "线上定时任务列表至少应包含 1 个 id");
81
88
  });
82
89
 
83
- t.test("6) 批量拉取前2个定时任务(pullList)", async () => {
90
+ t.test("7) 批量拉取前2个定时任务(pullList)", async () => {
84
91
  assert.ok(topIds.length >= 1, "pullList 需要至少 1 个线上定时任务 id");
85
92
  const beforeCount = fs.existsSync(scheduleRoot)
86
93
  ? fs.readdirSync(scheduleRoot).filter((n) => fs.statSync(path.join(scheduleRoot, n)).isDirectory()).length
@@ -96,13 +103,13 @@ test("定时任务管理流程:创建→发布→拉取→线上详情→列
96
103
  assert.ok(afterCount >= beforeCount, "pullList 之后 schedule 目录应存在/可用");
97
104
  });
98
105
 
99
- t.test("7) 删除当前创建定时类(delete timer)", async () => {
106
+ t.test("8) 删除当前创建定时类(delete timer)", async () => {
100
107
  const { stdout, stderr } = await runCc(["delete", "timer", timerName, repoRoot]);
101
108
  const out = `${stdout}\n${stderr}`.trim();
102
109
  assert.match(out, /Success|成功/i, "delete timer 应输出成功信息");
103
110
  });
104
111
 
105
- t.test("8) 清空 schedule 文件夹", async () => {
112
+ t.test("9) 清空 schedule 文件夹", async () => {
106
113
  if (fs.existsSync(scheduleRoot)) {
107
114
  fs.rmSync(scheduleRoot, { recursive: true, force: true });
108
115
  }
@@ -65,9 +65,11 @@ test("触发器管理流程:获取对象→创建→doc→发布→拉取→
65
65
  assert.equal(config.triggerTime, triggerTime);
66
66
  });
67
67
 
68
- t.test("3) 获取 doc(triggers overview)", async () => {
69
- const { stdout } = await runCc(["doc", "triggers", "overview"]);
70
- assert.match(stdout, /触发器|CCTrigger|编辑指南/i);
68
+ t.test("3) 获取 doc(triggers introduction / devguide)", async () => {
69
+ const intro = await runCc(["doc", "triggers", "introduction"]);
70
+ assert.match(intro.stdout, /触发器/);
71
+ const dev = await runCc(["doc", "triggers", "devguide"]);
72
+ assert.match(dev.stdout, /触发器/);
71
73
  });
72
74
 
73
75
  t.test("4) 发布触发器(publish,写回 config.id)", async () => {
@@ -1,111 +0,0 @@
1
- ## 自定义类(Class)
2
-
3
- ## 覆盖范围
4
-
5
- 本篇聚焦 CloudCC 后端 Java 自定义类(通过 `cc` 命令):
6
-
7
- - 创建类骨架
8
- - 拉取线上源码片段
9
- - 发布本地源码片段
10
- - 列表、详情与按 ID 生成本地工程
11
-
12
- ---
13
-
14
- ## 目录结构(以本仓库约定为准)
15
-
16
- - `classes/{ClassName}/...`
17
-
18
- ---
19
-
20
- ## 生成文件说明
21
-
22
- 当执行 `cc create classes <ClassName>` 后,通常会在项目根目录生成:
23
-
24
- - `classes/<ClassName>/<ClassName>.java`:主类文件
25
- - `classes/<ClassName>/<ClassName>Test.java`:测试桩文件(便于本地跑 main)
26
- - `classes/<ClassName>/config.json`:记录 `name`、`version`,以及首次 `publish` 成功后写入的 `id`
27
-
28
- `<ClassName>.java` 的 Java 包名为 `package classes.<ClassName>;`
29
-
30
- ---
31
-
32
- ## 源码同步边界(必须理解)
33
-
34
- 该项目使用“片段同步”策略:
35
-
36
- - 自定义类只会拉取/发布 `@SOURCE_CONTENT_START` 与 `@SOURCE_CONTENT_END` 之间的内容。
37
-
38
- 这意味着:
39
-
40
- - 片段外可保留模板、import、类结构等。
41
- - 片段内仅放可发布逻辑,不放本地临时调试代码。
42
-
43
- ---
44
-
45
- ## 创建
46
-
47
- ```bash
48
- # 在项目根目录执行
49
- cc create classes <ClassName>
50
- ```
51
-
52
- ## 拉取 / 发布
53
-
54
- ```bash
55
- cc pull classes <ClassName>
56
- cc publish classes <ClassName>
57
- ```
58
-
59
- ### `pull` 前置条件
60
-
61
- - `pull` 会读取 `classes/<ClassName>/config.json` 里的 `id`
62
- - 如果本地 `config.json` 没有 `id`(通常表示从未 `publish` 过),会提示 “Class ID is not exist, please publish first”
63
-
64
- ### `publish` 行为
65
-
66
- - `publish` 会从 `<ClassName>.java` 中提取 `@SOURCE_CONTENT_START` 与 `@SOURCE_CONTENT_END` 之间的源码作为 `source` 上传
67
- - 首次发布成功后,会把云端返回的 `id` 写回本地 `config.json`
68
-
69
- ---
70
-
71
- ## 获取 / 详情 / 批量拉取 / 删除
72
-
73
- ```bash
74
- # 列出(可选:传入 encodeURI(JSON.stringify({...})) 查询体;不传则用默认分页参数)
75
- cc get classes <encodedJson>
76
-
77
- # 详情:优先本地读取;当没有本地信息或未发布时,再通过 id 查云端
78
- cc detail classes <ClassName> <ClassId>
79
-
80
- # 批量拉取:根据云端 id 生成本地 classes/<ClassName>/ 目录
81
- cc pullList classes <ClassId> <ProjectRoot>
82
- ```
83
-
84
- 说明:
85
-
86
- - `detail`/`pull` 等命令在本地优先;只要你本地 `classes/<ClassName>/config.json` 已包含 `id`,就可以按 id 查并拉取源码。
87
-
88
- ---
89
-
90
- ## 删除类
91
-
92
- ```bash
93
- # 传类名(优先读取 classes/<ClassName>/config.json 中的 id)
94
- cc delete classes <ClassName> [projectPath]
95
-
96
- # 或直接传类 id
97
- cc delete classes <ClassId> [projectPath]
98
- ```
99
-
100
- ⚠️ **警告:删除操作不可逆,请谨慎使用。**
101
-
102
- ---
103
-
104
- ## 推荐工作流(AI 执行顺序)
105
-
106
- 1. 通过对象/字段工具确认数据结构(必要时先建对象字段)
107
- 2. 创建类骨架(`create`)
108
- 3. 拉取线上版本(`pull`)对齐基线(如是增量改造)
109
- 4. 编写片段内业务逻辑(注意幂等、异常兜底)
110
- 5. 发布(`publish`)
111
- 6. 回归验证:单条调用、跨模块调用(触发器/定时类/组件等)与异常分支
@@ -1,152 +0,0 @@
1
- # 定时作业管理(Scheduled Class / Timer)
2
-
3
- 定时作业是 CloudCC 后台设置中的功能,依赖二开中的定时类,用于定时执行任务的 Java 类。
4
-
5
- 本篇涵盖:
6
- - **定时类开发**:通过 `cc` 命令创建/拉取/发布定时类代码
7
- - **定时作业管理**:通过 `cc` 命令查询/详情/删除线上定时作业
8
-
9
- ---
10
-
11
- ## 覆盖范围
12
-
13
- 本篇聚焦 CloudCC 后端 Java 定时类(通过 `cc` 命令):
14
-
15
- - 创建定时类骨架
16
- - 拉取线上源码片段
17
- - 发布本地源码片段
18
- - 列表、详情与按 ID 批量落地
19
-
20
- ---
21
-
22
- ## 目录结构(以本仓库约定为准)
23
-
24
- - `schedule/{ScheduleName}/...`
25
-
26
- ---
27
-
28
- ## 核心说明
29
-
30
- 定时类在平台上对应"定时作业"类代码,本地由 `src/timer` 实现。CLI 上 `schedule` 与 `timer` 完全等价(同一模块),任选其一即可。
31
-
32
- ### 目录与 Java 约定
33
-
34
- - **路径**:`schedule/<ScheduleName>/`
35
- - **文件**:
36
- - `<ScheduleName>.java`:`package schedule.<ScheduleName>`,类 `extends CCSchedule`,业务逻辑写在无参构造函数中。
37
- - `config.json`:至少包含 `name`、`version`;首次发布成功后会写入云端返回的 `id`,供后续拉取使用。
38
-
39
- ### 片段同步
40
-
41
- - 推荐在构造函数体内使用 `// @SOURCE_CONTENT_START` 与 `// @SOURCE_CONTENT_END` 包裹可同步逻辑。
42
- - **发布**:有标记时只上传标记之间源码;无标记时会把整文件作为 `source` 提交。
43
- - **拉取**:有标记时只替换标记区间;无标记时用接口返回的 `tsource` 覆盖整个 `.java` 文件。
44
-
45
- ---
46
-
47
- ## 创建 / 发布 / 拉取
48
-
49
- ```bash
50
- # 在项目根目录执行(schedule 可换成 timer)
51
- cc create schedule <ScheduleName>
52
- cc publish schedule <ScheduleName>
53
- cc pull schedule <ScheduleName>
54
- ```
55
-
56
- **重要:`pull` 前置条件**
57
-
58
- - `config.json` 中必须已有 `id`(通常需先 `publish` 成功一次)。否则会出现 "Schedule ID is not exist, please publish first" 类提示。
59
-
60
- ---
61
-
62
- ## 列表 / 详情 / 按 ID 生成本地工程
63
-
64
- ```bash
65
- # 列表(可选:传 encodeURI(JSON.stringify({...})) 查询体;不传用默认分页)
66
- cc get schedule
67
-
68
- # 详情:优先按本地 schedule/<name>/ 读取;仅查云端可传 id(name 置空)
69
- cc detail schedule <ScheduleName> <ScheduleId>
70
-
71
- # 按云端 id 拉取并在指定项目下生成 schedule/<name>/
72
- cc pullList schedule <ScheduleId> <ProjectRoot>
73
- ```
74
-
75
- **说明**:`get` / `detail` / `pullList` 同样支持将子命令中的 `schedule` 写成 `timer`。
76
-
77
- ---
78
-
79
- ## 推荐工作流(AI 执行顺序)
80
-
81
- 1. 通过对象/字段工具确认数据结构(必要时先建对象字段)
82
- 2. 创建定时类骨架(create)
83
- 3. 拉取线上版本(pull)对齐基线(如是增量改造)
84
- 4. 编写片段内业务逻辑(注意幂等、异常兜底)
85
- 5. 发布(publish)
86
- 6. 回归验证:单条、批量、跨天、异常分支
87
-
88
- ---
89
-
90
- ## 删除定时类
91
-
92
- ```bash
93
- # 传定时类名(优先读取 schedule/<name>/config.json 中的 id)
94
- cc delete schedule <ScheduleName> [projectPath]
95
-
96
- # 或直接传定时类 id
97
- cc delete schedule <ScheduleId> [projectPath]
98
- ```
99
-
100
- ⚠️ **警告:删除操作不可逆,请谨慎使用。**
101
-
102
- ---
103
-
104
- ## 定时作业(scheduleJob)命令化管理
105
-
106
- 当前已提供 `scheduleJob` 类型,可通过 CLI 管理定时作业配置(执行计划):
107
-
108
- ```bash
109
- # 查询定时作业列表(可选条件)
110
- cc get scheduleJob <projectPath> [encodedCondJson]
111
-
112
- # 查询定时作业详情
113
- cc detail scheduleJob <jobId> [projectPath]
114
-
115
- # 删除定时作业
116
- cc delete scheduleJob <jobId> [projectPath]
117
- ```
118
-
119
- 说明:
120
-
121
- - `scheduleJob` 管理的是“定时作业配置”,不是定时类源码。
122
- - 删除定时作业后,定时类代码仍可能存在;只是该执行计划被移除。
123
-
124
- ---
125
-
126
- ## 注意事项
127
-
128
- 1. **片段同步**:只编辑 `// @SOURCE_CONTENT_START` ~ `// @SOURCE_CONTENT_END` 之间的代码。
129
- 2. **命名规范**:定时类名遵循 Java 大驼峰命名。
130
- 3. **幂等与异常**:定时任务要可重复执行,并做好异常兜底和日志。
131
- 4. **pull 前置条件**:必须先 `publish` 成功一次,`config.json` 中有 `id` 才能 `pull`。
132
- 5. **权限要求**:需要对应系统管理权限(定时类/定时作业管理)。
133
-
134
- ---
135
-
136
- ## 完整工作流程(cc 命令)
137
-
138
- ```bash
139
- # 1) 开发定时类
140
- cc create schedule MyTimer
141
- cc pull schedule MyTimer
142
- # ...编辑代码...
143
- cc publish schedule MyTimer
144
-
145
- # 2) 运维查询定时作业
146
- cc get scheduleJob .
147
- cc detail scheduleJob <jobId> .
148
-
149
- # 3) 必要时删除
150
- cc delete schedule MyTimer .
151
- cc delete scheduleJob <jobId> .
152
- ```