cloudcc-cli 2.3.8 → 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 (59) hide show
  1. package/.cursor/skills/{cloudcc-cli-dev → dev-guide}/SKILL.md +5 -1
  2. package/README.md +52 -1
  3. package/mcp/index.js +25 -2
  4. package/mcp/tools/Object Fields Creator/handler.js +149 -3
  5. package/package.json +1 -1
  6. package/src/fields/buildFieldData.js +692 -0
  7. package/src/fields/create.js +10 -170
  8. package/src/fields/detail.js +37 -0
  9. package/src/fields/docs/devguide.md +168 -44
  10. package/src/fields/docs/introduction.md +2 -0
  11. package/src/fields/fields/A.js +3 -2
  12. package/src/fields/fields/AD.js +4 -2
  13. package/src/fields/fields/B.js +8 -5
  14. package/src/fields/fields/C.js +13 -5
  15. package/src/fields/fields/D.js +4 -4
  16. package/src/fields/fields/E.js +10 -5
  17. package/src/fields/fields/ENC.js +27 -8
  18. package/src/fields/fields/ENCD.js +27 -8
  19. package/src/fields/fields/F.js +4 -4
  20. package/src/fields/fields/FL.js +8 -4
  21. package/src/fields/fields/H.js +4 -4
  22. package/src/fields/fields/IMG.js +23 -5
  23. package/src/fields/fields/J.js +21 -6
  24. package/src/fields/fields/L.js +32 -8
  25. package/src/fields/fields/LT.js +23 -6
  26. package/src/fields/fields/M.js +2 -2
  27. package/src/fields/fields/MR.js +2 -2
  28. package/src/fields/fields/N.js +31 -8
  29. package/src/fields/fields/P.js +13 -5
  30. package/src/fields/fields/Q.js +42 -12
  31. package/src/fields/fields/S.js +19 -7
  32. package/src/fields/fields/SCORE.js +9 -4
  33. package/src/fields/fields/T.js +4 -4
  34. package/src/fields/fields/U.js +18 -5
  35. package/src/fields/fields/X.js +20 -6
  36. package/src/fields/fields/Y.js +17 -4
  37. package/src/fields/index.js +2 -0
  38. package/src/fields/update.js +148 -0
  39. package/test/fields.cli.test.js +3 -1
  40. package/target/classes/com/cloudcc/core/BaseException.class +0 -0
  41. package/target/classes/com/cloudcc/core/BusiException.class +0 -0
  42. package/target/classes/com/cloudcc/core/CCObject.class +0 -0
  43. package/target/classes/com/cloudcc/core/CCSchedule.class +0 -0
  44. package/target/classes/com/cloudcc/core/CCService.class +0 -0
  45. package/target/classes/com/cloudcc/core/CCTrigger.class +0 -0
  46. package/target/classes/com/cloudcc/core/CCTriggerHandler.class +0 -0
  47. package/target/classes/com/cloudcc/core/DevLogger.class +0 -0
  48. package/target/classes/com/cloudcc/core/OperatationEnum.class +0 -0
  49. package/target/classes/com/cloudcc/core/PeakInterf.class +0 -0
  50. package/target/classes/com/cloudcc/core/SendEmail.class +0 -0
  51. package/target/classes/com/cloudcc/core/ServiceResult.class +0 -0
  52. package/target/classes/com/cloudcc/core/StringUtils.class +0 -0
  53. package/target/classes/com/cloudcc/core/TimeUtil.class +0 -0
  54. package/target/classes/com/cloudcc/core/Tool$1.class +0 -0
  55. package/target/classes/com/cloudcc/core/Tool.class +0 -0
  56. package/target/classes/com/cloudcc/core/TriggerInvoker.class +0 -0
  57. package/target/classes/com/cloudcc/core/TriggerMethod.class +0 -0
  58. package/target/classes/com/cloudcc/core/TriggerTimeEnum.class +0 -0
  59. 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}`,