cloudcc-cli 2.3.7 → 2.3.9

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 (65) hide show
  1. package/.cursor/skills/{cloudcc-cli-dev → dev-guide}/SKILL.md +5 -1
  2. package/README.md +65 -1
  3. package/cloudcc-dev-skill/SKILL.md +78 -0
  4. package/cloudcc-dev-skill/config.json +4 -0
  5. package/mcp/index.js +25 -2
  6. package/mcp/tools/Object Fields Creator/handler.js +149 -3
  7. package/package.json +1 -1
  8. package/src/classes/create.js +10 -0
  9. package/src/fields/buildFieldData.js +692 -0
  10. package/src/fields/create.js +10 -170
  11. package/src/fields/detail.js +37 -0
  12. package/src/fields/docs/devguide.md +168 -44
  13. package/src/fields/docs/introduction.md +2 -0
  14. package/src/fields/fields/A.js +3 -2
  15. package/src/fields/fields/AD.js +4 -2
  16. package/src/fields/fields/B.js +8 -5
  17. package/src/fields/fields/C.js +13 -5
  18. package/src/fields/fields/D.js +4 -4
  19. package/src/fields/fields/E.js +10 -5
  20. package/src/fields/fields/ENC.js +27 -8
  21. package/src/fields/fields/ENCD.js +27 -8
  22. package/src/fields/fields/F.js +4 -4
  23. package/src/fields/fields/FL.js +8 -4
  24. package/src/fields/fields/H.js +4 -4
  25. package/src/fields/fields/IMG.js +23 -5
  26. package/src/fields/fields/J.js +21 -6
  27. package/src/fields/fields/L.js +32 -8
  28. package/src/fields/fields/LT.js +23 -6
  29. package/src/fields/fields/M.js +2 -2
  30. package/src/fields/fields/MR.js +2 -2
  31. package/src/fields/fields/N.js +31 -8
  32. package/src/fields/fields/P.js +13 -5
  33. package/src/fields/fields/Q.js +42 -12
  34. package/src/fields/fields/S.js +19 -7
  35. package/src/fields/fields/SCORE.js +9 -4
  36. package/src/fields/fields/T.js +4 -4
  37. package/src/fields/fields/U.js +18 -5
  38. package/src/fields/fields/X.js +20 -6
  39. package/src/fields/fields/Y.js +17 -4
  40. package/src/fields/index.js +2 -0
  41. package/src/fields/update.js +148 -0
  42. package/test/fields.cli.test.js +3 -1
  43. package/utils/config.js +9 -0
  44. package/utils/utils.js +12 -5
  45. package/.cursor/skills/cloudcc-dev-skill/SKILL.md +0 -71
  46. package/target/classes/com/cloudcc/core/BaseException.class +0 -0
  47. package/target/classes/com/cloudcc/core/BusiException.class +0 -0
  48. package/target/classes/com/cloudcc/core/CCObject.class +0 -0
  49. package/target/classes/com/cloudcc/core/CCSchedule.class +0 -0
  50. package/target/classes/com/cloudcc/core/CCService.class +0 -0
  51. package/target/classes/com/cloudcc/core/CCTrigger.class +0 -0
  52. package/target/classes/com/cloudcc/core/CCTriggerHandler.class +0 -0
  53. package/target/classes/com/cloudcc/core/DevLogger.class +0 -0
  54. package/target/classes/com/cloudcc/core/OperatationEnum.class +0 -0
  55. package/target/classes/com/cloudcc/core/PeakInterf.class +0 -0
  56. package/target/classes/com/cloudcc/core/SendEmail.class +0 -0
  57. package/target/classes/com/cloudcc/core/ServiceResult.class +0 -0
  58. package/target/classes/com/cloudcc/core/StringUtils.class +0 -0
  59. package/target/classes/com/cloudcc/core/TimeUtil.class +0 -0
  60. package/target/classes/com/cloudcc/core/Tool$1.class +0 -0
  61. package/target/classes/com/cloudcc/core/Tool.class +0 -0
  62. package/target/classes/com/cloudcc/core/TriggerInvoker.class +0 -0
  63. package/target/classes/com/cloudcc/core/TriggerMethod.class +0 -0
  64. package/target/classes/com/cloudcc/core/TriggerTimeEnum.class +0 -0
  65. package/target/classes/com/cloudcc/core/UserInfo.class +0 -0
@@ -1,35 +1,65 @@
1
1
  /**
2
- * 选项列表(多选)字段(Q)配置模板
2
+ * 选项列表(多选)字段(Q)配置模板(与 `L` 类似,另含 `visibleLines`、`showalloptions`)
3
+ * @param {string} useGlobalSelect 是否使用全局选项列表:`"0"` 否,`"1"` 是
4
+ * @param {string} edittype 选择样式,写入 `obj.edittype`:`radio` 或 `select`(多选常见为 `select`)
5
+ * @param {string} isPicklistSorted 是否按字母排序:`"0"` 否,`"1"` 是
6
+ * @param {string} defPl 是否将第一个值作为默认值:`"0"` 否,`"1"` 是
7
+ * @param {string} globalSelectId 全局选项列表 id(`useGlobalSelect` 为 `"1"` 时使用)
8
+ * @param {string} visibleLines 下拉最多展示几行选项,写入 `obj.visibleLines`
9
+ * @param {string} showalloptions 是否显示所有选项:`"0"` 否,`"1"` 是,写入 `obj.showalloptions`
3
10
  */
4
- module.exports = function (objid, nameLabel, apiname, ptext, profileList) {
11
+ module.exports = function (
12
+ objid,
13
+ nameLabel,
14
+ apiname,
15
+ ptext,
16
+ helps = "",
17
+ defaultValue = "",
18
+ profileList,
19
+ useGlobalSelect = "0",
20
+ edittype = "select",
21
+ isPicklistSorted = "0",
22
+ defPl = "0",
23
+ globalSelectId = "",
24
+ visibleLines = "4",
25
+ showalloptions = "0"
26
+ ) {
27
+ const ugs = useGlobalSelect === "1" ? "1" : "0";
28
+ const et = edittype === "radio" ? "radio" : "select";
29
+ const sorted = isPicklistSorted === "1" ? "1" : "0";
30
+ const dp = defPl === "1" ? "1" : "0";
31
+ const gid = ugs === "1" ? String(globalSelectId || "").trim() : "";
32
+ const vl = String(visibleLines || "4").trim() || "4";
33
+ const sao = showalloptions === "1" ? "1" : "0";
5
34
  return {
6
- "objid": objid,
7
35
  "obj": {
8
36
  "id": "",
9
37
  "nameLabel": nameLabel,
10
38
  "apiname": apiname,
11
39
  "schemefieldLength": "255",
12
- "edittype": "select",
13
- "visibleLines": "4",
14
- "showalloptions": "0",
40
+ "edittype": et,
41
+ "visibleLines": vl,
42
+ "showalloptions": sao,
15
43
  "renderstyle": "1",
16
44
  "remark": "",
17
- "helps": ""
45
+ "helps": helps !== undefined && helps !== null ? String(helps) : "",
46
+ "defaultValue": defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : ""
18
47
  },
48
+ "objid": objid,
19
49
  "dtype": "Q:选项列表(多选)",
20
50
  "fdtype": "Q",
21
51
  "ischecked": "false",
22
- "useGlobalSelect": "0",
23
- "globalSelectId": "province",
52
+ "useGlobalSelect": ugs,
53
+ "globalSelectId": gid,
24
54
  "ptext": ptext,
25
- "isPicklistSorted": "0",
26
- "defPl": "1",
55
+ "isPicklistSorted": sorted,
56
+ "defPl": dp,
27
57
  "iscover": "",
28
58
  "formulaText": "",
29
59
  "profileFieldJson": profileList.map(profile => ({
30
60
  "profileId": profile.id,
31
61
  "visible": "true",
32
62
  "readonly": "false"
33
- })),
63
+ }))
34
64
  }
35
65
  }
@@ -1,7 +1,19 @@
1
1
  /**
2
2
  * 文本字段(S)配置模板
3
3
  */
4
- module.exports = function (objid, nameLabel, apiname, profileList) {
4
+ module.exports = function (
5
+ objid,
6
+ nameLabel,
7
+ apiname,
8
+ schemefieldLength,
9
+ helps,
10
+ isrepeat,
11
+ casesensitive,
12
+ placeholder,
13
+ defaultValue,
14
+ profileList
15
+ ) {
16
+ const length = schemefieldLength ? String(schemefieldLength) : "255";
5
17
  return {
6
18
  "objid": objid,
7
19
  "obj": {
@@ -9,12 +21,12 @@ module.exports = function (objid, nameLabel, apiname, profileList) {
9
21
  "nameLabel": nameLabel,
10
22
  "apiname": apiname,
11
23
  "remark": "",
12
- "helps": "",
13
- "schemefieldLength": "255",
14
- "isrepeat": "true",
15
- "casesensitive": "",
16
- "placeholder": "",
17
- "defaultValue": ""
24
+ "helps": helps ? String(helps) : "",
25
+ "schemefieldLength": length,
26
+ "isrepeat": isrepeat !== undefined ? String(isrepeat) : "true",
27
+ "casesensitive": casesensitive ? String(casesensitive) : "",
28
+ "placeholder": placeholder ? String(placeholder) : "",
29
+ "defaultValue": defaultValue ? String(defaultValue) : ""
18
30
  },
19
31
  "dtype": "S:文本",
20
32
  "fdtype": "S",
@@ -1,7 +1,12 @@
1
1
  /**
2
2
  * 评分字段(SCORE)配置模板
3
+ * schemefieldLength:最大评分,控制星星图标个数;平台允许 1~100,默认 10
3
4
  */
4
- module.exports = function (objid, nameLabel, apiname, profileList) {
5
+ module.exports = function (objid, nameLabel, apiname, helps = "", defaultValue = "", schemefieldLength = "10", profileList) {
6
+ const len =
7
+ schemefieldLength !== undefined && schemefieldLength !== null && String(schemefieldLength).trim() !== ""
8
+ ? String(schemefieldLength).trim()
9
+ : "10";
5
10
  return {
6
11
  "objid": objid,
7
12
  "obj": {
@@ -9,9 +14,9 @@ module.exports = function (objid, nameLabel, apiname, profileList) {
9
14
  "nameLabel": nameLabel,
10
15
  "apiname": apiname,
11
16
  "remark": "",
12
- "helps": "",
13
- "schemefieldLength": "10",
14
- "defaultValue": ""
17
+ "helps": helps !== undefined && helps !== null ? String(helps) : "",
18
+ "schemefieldLength": len,
19
+ "defaultValue": defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : ""
15
20
  },
16
21
  "dtype": "SCORE:评分",
17
22
  "fdtype": "SCORE",
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * 时间字段(T)配置模板
3
3
  */
4
- module.exports = function (objid, nameLabel, apiname, profileList) {
4
+ module.exports = function (objid, nameLabel, apiname, helps = "", defaultValue = "", profileList) {
5
5
  return {
6
6
  "objid": objid,
7
7
  "obj": {
8
8
  "id": "",
9
9
  "nameLabel": nameLabel,
10
10
  "apiname": apiname,
11
- "schemefieldLength": "255",
12
11
  "remark": "",
13
- "helps": "",
14
- "defaultValue": ""
12
+ "helps": helps !== undefined && helps !== null ? String(helps) : "",
13
+ "schemefieldLength": "20",
14
+ "defaultValue": defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : ""
15
15
  },
16
16
  "dtype": "T:时间",
17
17
  "fdtype": "T",
@@ -1,18 +1,31 @@
1
1
  /**
2
2
  * URL字段(U)配置模板
3
3
  */
4
- module.exports = function (objid, nameLabel, apiname, profileList) {
4
+ module.exports = function (objid, nameLabel, apiname, helps, edittype, defaultValue, profileList) {
5
+ const openMode = edittype && String(edittype).trim() !== ""
6
+ ? String(edittype).trim()
7
+ : "_blank";
8
+ const safeEdittype = openMode === "_self" ? "_self" : "_blank";
5
9
  return {
10
+ // 对象ID
6
11
  "objid": objid,
7
12
  "obj": {
13
+ // 字段ID
8
14
  "id": "",
15
+ // 字段名称
9
16
  "nameLabel": nameLabel,
17
+ // 字段API名称
10
18
  "apiname": apiname,
19
+ // 字段备注
11
20
  "remark": "",
12
- "helps": "",
13
- "edittype": "_blank",
14
- "schemefieldLength": "255",
15
- "defaultValue": ""
21
+ // 字段帮助
22
+ "helps": helps !== undefined && helps !== null ? String(helps) : "",
23
+ // 最大输入长度(字符)
24
+ "schemefieldLength": "2000",
25
+ // URL打开方式: _blank 新窗口打开, _self 当前窗口打开
26
+ "edittype": safeEdittype,
27
+ // 默认值
28
+ "defaultValue": defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : ""
16
29
  },
17
30
  "dtype": "U:URL",
18
31
  "fdtype": "U",
@@ -1,7 +1,21 @@
1
1
  /**
2
- * 文本区字段(X)配置模板
2
+ * 文本区字段(X)配置模板(多行文本,schemefieldLength 为最大字符数,常见上限 4000)
3
3
  */
4
- module.exports = function (objid, nameLabel, apiname, profileList) {
4
+ module.exports = function (
5
+ objid,
6
+ nameLabel,
7
+ apiname,
8
+ helps = "",
9
+ defaultValue = "",
10
+ schemefieldLength = "4000",
11
+ placeholder = "",
12
+ profileList
13
+ ) {
14
+ const len =
15
+ schemefieldLength !== undefined && schemefieldLength !== null && String(schemefieldLength).trim() !== ""
16
+ ? String(schemefieldLength).trim()
17
+ : "4000";
18
+ const ph = placeholder !== undefined && placeholder !== null ? String(placeholder) : "";
5
19
  return {
6
20
  "objid": objid,
7
21
  "obj": {
@@ -9,10 +23,10 @@ module.exports = function (objid, nameLabel, apiname, profileList) {
9
23
  "nameLabel": nameLabel,
10
24
  "apiname": apiname,
11
25
  "remark": "",
12
- "helps": "",
13
- "defaultValue": "",
14
- "schemefieldLength": "255",
15
- "placeholder": ""
26
+ "helps": helps !== undefined && helps !== null ? String(helps) : "",
27
+ "defaultValue": defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : "",
28
+ "schemefieldLength": len,
29
+ "placeholder": ph
16
30
  },
17
31
  "dtype": "X",
18
32
  "fdtype": "X",
@@ -1,7 +1,21 @@
1
1
  /**
2
2
  * 查找关系字段(Y)配置模板
3
+ * @param {string} lookupObjDefaultField 搜索辅助字段(`obj.lookupObjDefaultField`);搜索时用于展示,可为 API 名字段等
3
4
  */
4
- module.exports = function (objid, nameLabel, apiname, lookupObj, profileList) {
5
+ module.exports = function (
6
+ objid,
7
+ nameLabel,
8
+ apiname,
9
+ lookupObj,
10
+ helps = "",
11
+ defaultValue = "",
12
+ profileList,
13
+ lookupObjDefaultField = ""
14
+ ) {
15
+ const ldf =
16
+ lookupObjDefaultField !== undefined && lookupObjDefaultField !== null
17
+ ? String(lookupObjDefaultField).trim()
18
+ : "";
5
19
  return {
6
20
  "objid": objid,
7
21
  "obj": {
@@ -10,11 +24,10 @@ module.exports = function (objid, nameLabel, apiname, lookupObj, profileList) {
10
24
  "apiname": apiname,
11
25
  "schemefieldLength": "255",
12
26
  "remark": "",
13
- "helps": "",
27
+ "helps": helps !== undefined && helps !== null ? String(helps) : "",
14
28
  "lookupObj": lookupObj,
15
- "defaultValue": "",
16
29
  "childrelationName": nameLabel,
17
- "lookupObjDefaultField": ""
30
+ "lookupObjDefaultField": ldf
18
31
  },
19
32
  "dtype": "Y:查找关系",
20
33
  "fdtype": "Y",
@@ -1,6 +1,8 @@
1
1
  const cc = {}
2
2
  cc.get = require("./get")
3
+ cc.detail = require("./detail")
3
4
  cc.create = require("./create")
5
+ cc.update = require("./update")
4
6
  cc.delete = require("./delete")
5
7
  cc.doc = require("./doc")
6
8
 
@@ -0,0 +1,148 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const { postClass } = require("../../utils/http")
4
+ const { getPackageJson } = require("../../utils/config");
5
+ const chalk = require('chalk')
6
+ const { buildFieldData } = require("./buildFieldData");
7
+
8
+ /**
9
+ * 在 object/custom-objects 与 object/standard-objects 中按对象 id 查找 objprefix(供 queryField 使用)
10
+ */
11
+ function findObjPrefixForObjId(projectPath, objid) {
12
+ if (!objid || String(objid).trim() === "") return null;
13
+ const roots = [
14
+ path.join(path.resolve(projectPath), "object/custom-objects"),
15
+ path.join(path.resolve(projectPath), "object/standard-objects"),
16
+ ];
17
+ for (const dir of roots) {
18
+ if (!fs.existsSync(dir)) continue;
19
+ let files;
20
+ try {
21
+ files = fs.readdirSync(dir);
22
+ } catch (_) {
23
+ continue;
24
+ }
25
+ for (const f of files) {
26
+ if (!f.endsWith(".json")) continue;
27
+ const fp = path.join(dir, f);
28
+ try {
29
+ const j = JSON.parse(fs.readFileSync(fp, "utf8"));
30
+ if (j && j.id === objid && j.objprefix) return String(j.objprefix).trim();
31
+ } catch (_) {}
32
+ }
33
+ }
34
+ return null;
35
+ }
36
+
37
+ /**
38
+ * saveField 需要与平台上已有字段一致的元数据(如 datafieldRef、schemetableId)。
39
+ * 在发起 saveField 前,用 queryField 拉取当前字段并合并进 payload。
40
+ */
41
+ async function mergeUpdatePayloadFromServer(config, projectPath, fieldId, objid, fieldData) {
42
+ const prefix = findObjPrefixForObjId(projectPath, objid);
43
+ if (!prefix) {
44
+ console.error(
45
+ chalk.yellow(
46
+ "⚠ cloudcc update fields: 未在 object/custom-objects 或 object/standard-objects 中找到 objid=" +
47
+ objid +
48
+ " 的 objprefix;请先执行 cloudcc get object 同步对象清单后再试。"
49
+ )
50
+ );
51
+ if (fieldData.obj) fieldData.obj.schemetableId = String(objid).trim();
52
+ return;
53
+ }
54
+ const res = await postClass(
55
+ config.setupSvc + "/api/fieldSetup/queryField",
56
+ { prefix },
57
+ config.accessToken
58
+ );
59
+ if (!res || !res.result || !res.data) return;
60
+ const pool = [...(res.data.stdFields || []), ...(res.data.cusFields || [])];
61
+ const raw = pool.find((f) => f && f.id === fieldId);
62
+ if (!fieldData.obj) return;
63
+ fieldData.obj.schemetableId = String(objid).trim();
64
+ if (raw && raw.datafieldRef) fieldData.obj.datafieldRef = String(raw.datafieldRef);
65
+ if (raw && (raw.schemefieldName || raw.apiname)) {
66
+ fieldData.obj.apiname = String(raw.schemefieldName || raw.apiname);
67
+ }
68
+ if (raw && Array.isArray(raw.profileFieldJson) && raw.profileFieldJson.length > 0) {
69
+ fieldData.profileFieldJson = raw.profileFieldJson;
70
+ }
71
+ if (fieldData.layoutIds === undefined) fieldData.layoutIds = "";
72
+ }
73
+
74
+ /**
75
+ * create 使用 save,简档为 profileId + visible + readonly;saveField 需 profileid + permission。
76
+ */
77
+ function normalizeProfileFieldJsonForSaveField(fieldData) {
78
+ if (!fieldData || !Array.isArray(fieldData.profileFieldJson)) return;
79
+ fieldData.profileFieldJson = fieldData.profileFieldJson
80
+ .map((row) => {
81
+ const pid = row.profileid || row.profileId;
82
+ if (!pid) return null;
83
+ if (row.permission != null && String(row.permission) !== "") {
84
+ return { profileid: String(pid), permission: String(row.permission) };
85
+ }
86
+ return { profileid: String(pid), permission: "1,0" };
87
+ })
88
+ .filter(Boolean);
89
+ }
90
+
91
+ /**
92
+ * 更新字段(与 create 共用同一套 payload 与类型分支;区别在于必须设置 `obj.id` 为字段 ID,且不请求 layout 绑定)
93
+ * @param {Array} argvs - 命令行参数数组
94
+ * @param {string} argvs[2] projectPath
95
+ * @param {string} argvs[3] fieldId(平台字段 id)
96
+ * @param {string} argvs[4] fieldType
97
+ * @param {string} argvs[5] objid
98
+ * @param {string} argvs[6] nameLabel
99
+ * @param {string} argvs[7] remark(与 create 相比各类型可选参数整体下标 +1)
100
+ * @returns {Promise<boolean>}
101
+ */
102
+ async function update(argvs) {
103
+ try {
104
+ let projectPath = argvs[2];
105
+ const fieldId = argvs[3];
106
+ if (!fieldId || String(fieldId).trim() === "") {
107
+ throw new Error("Missing field id: argvs[3] (field id from platform)");
108
+ }
109
+ const config = await getPackageJson(projectPath);
110
+ let nameLabel = argvs[6];
111
+ let remarkText = argvs[7];
112
+ if (!remarkText) remarkText = "auto created by cloudcc-cli ai agent";
113
+ console.error(chalk.blue('\nUpdating field ' + nameLabel + ' (id=' + fieldId + ')...'));
114
+ let fieldData = await buildFieldData(argvs, { shift: 1 });
115
+ if (!fieldData) {
116
+ throw new Error("Unsupported or unknown fieldType for update");
117
+ }
118
+ if (fieldData.obj) fieldData.obj.id = String(fieldId).trim();
119
+ if (fieldData && fieldData.obj) fieldData.obj.remark = remarkText;
120
+ if (fieldData) fieldData.remark = remarkText;
121
+
122
+ const objid = argvs[5];
123
+ await mergeUpdatePayloadFromServer(config, projectPath, fieldId, objid, fieldData);
124
+ normalizeProfileFieldJsonForSaveField(fieldData);
125
+
126
+ const result = await postClass(
127
+ config.setupSvc + "/api/fieldSetup/saveField",
128
+ fieldData,
129
+ config.accessToken
130
+ );
131
+
132
+ if (result && result.result) {
133
+ const okId = result.data && (typeof result.data === "string" || typeof result.data === "number")
134
+ ? result.data
135
+ : (result.data && result.data.id) || fieldId;
136
+ console.error(chalk.green('✓ Field updated successfully! ID: ' + okId));
137
+ return true;
138
+ } else {
139
+ console.error(chalk.yellow('⚠ Field update completed with warnings: ' + (result && result.returnInfo)));
140
+ return false;
141
+ }
142
+ } catch (error) {
143
+ console.error(chalk.red("Failed to update field: "), error.message || error);
144
+ return false;
145
+ }
146
+ }
147
+
148
+ module.exports = update;
@@ -21,6 +21,7 @@ test("字段管理流程:获取对象列表→create 字段→get 字段列表
21
21
  let objId = null;
22
22
  let objName = null;
23
23
  const fieldLabel = `AutoField_${Date.now()}`;
24
+ const fieldRemark = `AutoFieldRemark_${Date.now()}`;
24
25
  let fieldId = null;
25
26
 
26
27
  t.test("1) 获取对象列表(取第一个对象的 id 和 objprefix)", async () => {
@@ -45,7 +46,8 @@ test("字段管理流程:获取对象列表→create 字段→get 字段列表
45
46
  t.test("2) create 创建一个文本字段(S)", async () => {
46
47
  assert.ok(objId, "需要对象 id");
47
48
  // create fields 调用约定:cloudcc create fields <path> <fieldType> <objid> <nameLabel> [...]
48
- const { stdout, stderr } = await runCc(["create", "fields", repoRoot, "S", objId, fieldLabel]);
49
+ // 统一规则:argvs[6] 作为 remark
50
+ const { stdout, stderr } = await runCc(["create", "fields", repoRoot, "S", objId, fieldLabel, fieldRemark]);
49
51
  // create fields 会通过 console.error 输出创建结果(见 src/fields/create.js)
50
52
  assert.match(
51
53
  `${stdout}\n${stderr}`,
package/utils/config.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const fs = require("fs");
2
2
  const path = require("path");
3
+ const chalk = require("chalk");
3
4
  // 引入解密函数
4
5
  const { getDevConsoleConfig, decryptCloudCCDevInfo } = require("./utils");
5
6
  const { readCache } = require("./cache")
@@ -54,6 +55,14 @@ async function getPackageJson3(projectPath = process.cwd()) {
54
55
  config = { ...decryptedInfo, ...config }
55
56
  config.CloudCCDev = "";
56
57
  config = await getDevConsoleConfig(projectPath, config)
58
+ } else {
59
+ console.error(
60
+ chalk.yellow(
61
+ "cloudcc-cli: CloudCCDev could not be decrypted or is empty (invalid base64/JSON). " +
62
+ "Fix cloudcc-cli.config.js or use explicit fields / v2-style config; falling back to other config sources."
63
+ )
64
+ );
65
+ return null;
57
66
  }
58
67
  } else {
59
68
  config = null;
package/utils/utils.js CHANGED
@@ -164,13 +164,20 @@ async function getDevConsoleConfig(projectPath = process.cwd(), config) {
164
164
  }
165
165
  */
166
166
  function decryptCloudCCDevInfo(encryptedData) {
167
+ if (encryptedData == null || typeof encryptedData !== "string" || !String(encryptedData).trim()) {
168
+ return null;
169
+ }
167
170
  try {
168
- const binaryData = new Uint8Array(Buffer.from(encryptedData, 'base64'));
171
+ const binaryData = new Uint8Array(Buffer.from(encryptedData, "base64"));
169
172
  const decoder = new TextDecoder();
170
- const jsonString = decoder.decode(binaryData);
171
- return JSON.parse(jsonString);
172
- } catch (error) {
173
- console.error(error);
173
+ const jsonString = decoder.decode(binaryData).trim();
174
+ if (!jsonString) {
175
+ return null;
176
+ }
177
+ const parsed = JSON.parse(jsonString);
178
+ return typeof parsed === "object" && parsed !== null ? parsed : null;
179
+ } catch (_e) {
180
+ // Invalid base64, truncated blob, or non-JSON — typical when CloudCCDev is missing / placeholder
174
181
  return null;
175
182
  }
176
183
  }
@@ -1,71 +0,0 @@
1
- ---
2
- name: cloudcc-dev-skill
3
- description: CloudCC CRM 二次开发设计,实现工具 。用于在设计方案和实际开发时使用,优先通过各模块的 `cloudcc doc <module> introduction` 与 `cloudcc doc <module> devguide` 获取文档。用户提到 CloudCC、cloudcc-cli、`cloudcc doc`、模块文档、设计方案、开发文档、项目初始化、开发环境、对象、字段、菜单、应用、类、定时类、触发器、自定义组件、自定义页面、自定义设置、客户端脚本、静态资源 时应优先使用。
4
- ---
5
-
6
- # CloudCC CLI skill
7
-
8
- - 使用前必须检查npm全局包,是否安装了cloudcc-cli ,如果没有,那么先全局安装 npm
9
- i -g cloudcc-cli@latest
10
-
11
- ## 模块命令
12
-
13
- ### 基础与环境
14
-
15
- - 开发环境设置:`cloudcc doc project introduction`、`cloudcc doc project devguide`
16
- - 开发环境密钥配置:`cloudcc doc config devguide`
17
-
18
- ### 元数据与模型设计
19
-
20
- - 对象:`cloudcc doc object introduction`、`cloudcc doc object devguide`
21
- - 对象字段:`cloudcc doc fields introduction`、`cloudcc doc fields devguide`
22
- - 对象记录类型:`cloudcc doc recordType introduction`、`cloudcc doc recordType devguide`
23
- - 全局选项列表:`cloudcc doc globalSelectList introduction`、`cloudcc doc globalSelectList devguide`
24
-
25
- ### 权限与组织管理
26
-
27
- - 用户:`cloudcc doc user introduction`、`cloudcc doc user devguide`
28
- - 角色:`cloudcc doc role introduction`、`cloudcc doc role devguide`
29
- - 简档:`cloudcc doc profile introduction`、`cloudcc doc profile devguide`
30
-
31
- ### 业务扩展(后端)
32
-
33
- - 后端类:`cloudcc doc classes introduction`、`cloudcc doc classes devguide`
34
- - 触发器:`cloudcc doc triggers introduction`、`cloudcc doc triggers devguide`
35
- - 定时类:`cloudcc doc timer introduction`、`cloudcc doc timer devguide`
36
- - 定时作业:`cloudcc doc scheduleJob introduction`、`cloudcc doc scheduleJob devguide`
37
-
38
- ### 业务扩展(前端)
39
-
40
- - 自定义组件:`cloudcc doc plugin introduction`、`cloudcc doc plugin devguide`
41
- - 自定义页面:`cloudcc doc customPage introduction`、`cloudcc doc customPage devguide`
42
- - 客户端脚本:`cloudcc doc script introduction`、`cloudcc doc script devguide`
43
- - 静态资源:`cloudcc doc staticResource introduction`、`cloudcc doc staticResource devguide`
44
-
45
- ### 平台配置与导航
46
-
47
- - 菜单:`cloudcc doc menu introduction`、`cloudcc doc menu devguide`
48
- - 应用:`cloudcc doc application introduction`、`cloudcc doc application devguide`
49
- - 自定义设置:`cloudcc doc customSetting introduction`、`cloudcc doc customSetting devguide`
50
-
51
- ## 使用场景
52
-
53
- ### 1. 快速了解CloudCC CRM每个模块的定义信息
54
-
55
- - 比如做方案设计、实现设计、模块选型时,优先调用每个模块的`introduction`文档。
56
- - 命令格式:`cloudcc doc <module> introduction`
57
- - 目标:先理解模块定位、适用场景、能力边界。
58
-
59
- ### 2. 要了解某个CloudCC CRM 环境状态
60
-
61
- - 先创建模版项目`cloudcc create project demo`
62
- - 配置开发者密钥
63
- - 调用每个模块的 `devguide`
64
- 文档,命令格式:`cloudcc doc <module> devguide`,了解如何查询系统数据
65
-
66
- ### 3. 要进行二开实施
67
-
68
- - 先创建模版项目`cloudcc create project demo`
69
- - 配置开发者密钥
70
- - 调用每个模块的 `devguide`
71
- 文档,命令格式:`cloudcc doc <module> devguide`,了解如何创建,修改数据