cloudcc-cli 2.3.3 → 2.3.5

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 (85) hide show
  1. package/.claude/settings.json +28 -1
  2. package/.cursor/skills/cloudcc-cli-dev/SKILL.md +175 -0
  3. package/.cursor/skills/cloudcc-dev-skill/SKILL.md +71 -0
  4. package/README.md +65 -7
  5. package/bin/cc.js +106 -28
  6. package/bin/index.js +54 -53
  7. package/mcp/cliRunner.js +11 -4
  8. package/mcp/index.js +12 -2
  9. package/mcp/tools/CloudCC Development Overview/handler.js +1 -1
  10. package/mcp/tools/JSP Migrator/handler.js +46 -0
  11. package/package.json +4 -5
  12. package/src/button/create.js +169 -0
  13. package/src/button/delete.js +35 -0
  14. package/src/button/doc.js +36 -0
  15. package/src/button/docs/devguide.md +133 -0
  16. package/src/button/docs/introduction.md +60 -0
  17. package/src/button/get.js +60 -0
  18. package/src/button/index.js +20 -0
  19. package/src/classes/docs/introduction.md +0 -20
  20. package/src/fields/create.js +12 -0
  21. package/src/identityProvider/create.js +78 -0
  22. package/src/identityProvider/delete.js +61 -0
  23. package/src/identityProvider/doc.js +46 -0
  24. package/src/identityProvider/docs/devguide.md +107 -0
  25. package/src/identityProvider/docs/introduction.md +31 -0
  26. package/src/identityProvider/download.js +105 -0
  27. package/src/identityProvider/get.js +70 -0
  28. package/src/identityProvider/index.js +12 -0
  29. package/src/menu/create-object.js +1 -0
  30. package/src/menu/create-page.js +1 -0
  31. package/src/menu/create-script.js +1 -0
  32. package/src/menu/create-site.js +1 -0
  33. package/src/object/create.js +2 -1
  34. package/src/object/docs/devguide.md +1 -5
  35. package/src/permission/add.js +164 -0
  36. package/src/permission/assign.js +84 -0
  37. package/src/permission/docs/devguide.md +238 -0
  38. package/src/permission/docs/introduction.md +200 -0
  39. package/src/permission/get.js +107 -0
  40. package/src/permission/index.js +10 -0
  41. package/src/permission/remove.js +145 -0
  42. package/src/project/docs/devguide.md +7 -6
  43. package/src/role/create.js +2 -1
  44. package/src/role/delete.js +1 -0
  45. package/src/singleSignOn/delete.js +61 -0
  46. package/src/singleSignOn/doc.js +46 -0
  47. package/src/singleSignOn/docs/devguide.md +61 -0
  48. package/src/singleSignOn/docs/introduction.md +3 -0
  49. package/src/singleSignOn/get.js +70 -0
  50. package/src/singleSignOn/index.js +10 -0
  51. package/src/staticResource/docs/introduction.md +44 -1
  52. package/src/user/create.js +502 -19
  53. package/src/validationRule/create.js +153 -0
  54. package/src/validationRule/delete.js +60 -0
  55. package/src/validationRule/doc.js +46 -0
  56. package/src/validationRule/docs/devguide.md +76 -0
  57. package/src/validationRule/docs/introduction.md +122 -0
  58. package/src/validationRule/get.js +47 -0
  59. package/src/validationRule/index.js +10 -0
  60. package/src/version/actionHelp.js +25 -0
  61. package/src/version/docs.js +26 -0
  62. package/src/version/doctor.js +25 -0
  63. package/src/version/get.js +7 -1
  64. package/src/version/help.js +47 -0
  65. package/src/version/index.js +9 -2
  66. package/src/version/initHelp.js +13 -0
  67. package/src/version/listModuleCommands.js +241 -0
  68. package/src/version/stats.js +44 -0
  69. package/src/version/uninstall.js +30 -0
  70. package/src/version/update.js +13 -0
  71. package/utils/checkVersion.js +31 -2
  72. package/utils/commandStats.js +94 -0
  73. package/utils/formatReleaseNotes.js +312 -0
  74. package/utils/readmeReleases.js +69 -0
  75. package/.cloudcc-cache.json +0 -38
  76. package/.cursor/skills/cloudcc-cli-dev.zip +0 -0
  77. package/.cursor/skills/cloudcc-cli-usage/SKILL.md +0 -68
  78. package/build/component-CCPlugin1774500425584.common.js +0 -831
  79. package/build/component-CCPlugin1774500425584.common.js.map +0 -1
  80. package/build/component-CCPlugin1774500425584.css +0 -1
  81. package/build/component-CCPlugin1774500425584.umd.js +0 -874
  82. package/build/component-CCPlugin1774500425584.umd.js.map +0 -1
  83. package/build/component-CCPlugin1774500425584.umd.min.js +0 -8
  84. package/build/component-CCPlugin1774500425584.umd.min.js.map +0 -1
  85. package/build/demo.html +0 -1
@@ -0,0 +1,312 @@
1
+ const chalk = require("chalk")
2
+
3
+ const BAR = "─"
4
+ const W = 40
5
+ const RIGHT_MARGIN = 2
6
+
7
+ function getColumns() {
8
+ const c = process.stdout.columns
9
+ return typeof c === "number" && c > 20 ? c : 80
10
+ }
11
+
12
+ /**
13
+ * Split on spaces but keep `` `...` `` segments intact (never break inside backticks).
14
+ */
15
+ function splitWordsRespectingBackticks(text) {
16
+ const out = []
17
+ let i = 0
18
+ while (i < text.length) {
19
+ while (i < text.length && text[i] === " ") i++
20
+ if (i >= text.length) break
21
+ if (text[i] === "`") {
22
+ const j = text.indexOf("`", i + 1)
23
+ if (j === -1) {
24
+ out.push(text.slice(i))
25
+ break
26
+ }
27
+ out.push(text.slice(i, j + 1))
28
+ i = j + 1
29
+ } else {
30
+ const j = text.indexOf(" ", i)
31
+ if (j === -1) {
32
+ out.push(text.slice(i))
33
+ break
34
+ }
35
+ out.push(text.slice(i, j))
36
+ i = j
37
+ }
38
+ }
39
+ return out
40
+ }
41
+
42
+ /**
43
+ * Plain-text word wrap. `firstMax` / `contMax` are max **characters** per line (content only).
44
+ */
45
+ function wordWrapPlain(text, firstMax, contMax) {
46
+ const words = splitWordsRespectingBackticks(text)
47
+ const lines = []
48
+ let useMax = firstMax
49
+ let line = ""
50
+
51
+ function hardBreakWord(w) {
52
+ let rest = w
53
+ while (rest.length > useMax) {
54
+ lines.push(rest.slice(0, useMax))
55
+ rest = rest.slice(useMax)
56
+ useMax = contMax
57
+ }
58
+ line = rest
59
+ }
60
+
61
+ for (const w of words) {
62
+ if (w.length > useMax) {
63
+ if (line) {
64
+ lines.push(line)
65
+ line = ""
66
+ }
67
+ if (w.startsWith("`")) {
68
+ lines.push(w)
69
+ useMax = contMax
70
+ continue
71
+ }
72
+ hardBreakWord(w)
73
+ useMax = contMax
74
+ continue
75
+ }
76
+ const tryLine = line ? `${line} ${w}` : w
77
+ if (tryLine.length <= useMax) {
78
+ line = tryLine
79
+ } else {
80
+ if (line) lines.push(line)
81
+ line = w
82
+ useMax = contMax
83
+ }
84
+ }
85
+ if (line) lines.push(line)
86
+ return lines
87
+ }
88
+
89
+ /**
90
+ * Keep `(alias for` + `` `code` `` on the same wrapped line when possible (readability).
91
+ */
92
+ function mergeAliasForWithNextLine(lines) {
93
+ const out = []
94
+ let i = 0
95
+ while (i < lines.length) {
96
+ let chunk = lines[i]
97
+ while (
98
+ i + 1 < lines.length &&
99
+ /\bfor\s*$/.test(chunk.trimEnd()) &&
100
+ lines[i + 1].trimStart().startsWith("`")
101
+ ) {
102
+ i += 1
103
+ chunk += " " + lines[i]
104
+ }
105
+ out.push(chunk)
106
+ i += 1
107
+ }
108
+ return out
109
+ }
110
+
111
+ /**
112
+ * If a wrap boundary split inside a `` `...` `` pair, merge lines until backticks balance.
113
+ */
114
+ function mergeBrokenBacktickLines(lines) {
115
+ const out = []
116
+ let i = 0
117
+ while (i < lines.length) {
118
+ let chunk = lines[i]
119
+ let cnt = (chunk.match(/`/g) || []).length
120
+ while (cnt % 2 === 1 && i + 1 < lines.length) {
121
+ i += 1
122
+ chunk += " " + lines[i]
123
+ cnt = (chunk.match(/`/g) || []).length
124
+ }
125
+ out.push(chunk)
126
+ i += 1
127
+ }
128
+ return out
129
+ }
130
+
131
+ /**
132
+ * Backtick segments → cyan; rest uses `baseStyle` (default gray).
133
+ */
134
+ function styleInlineCode(str, baseStyle) {
135
+ const base = baseStyle || ((s) => chalk.white(s))
136
+ const parts = str.split(/(`[^`]*`)/g)
137
+ return parts
138
+ .map((p) => {
139
+ if (p.startsWith("`") && p.endsWith("`") && p.length >= 2) {
140
+ return chalk.cyan.bold(p.slice(1, -1))
141
+ }
142
+ return base(p)
143
+ })
144
+ .join("")
145
+ }
146
+
147
+ /**
148
+ * Bullet + wrapped text; continuation lines align with text after "● ".
149
+ */
150
+ function printWrappedBullet(pad, text, stream) {
151
+ const cols = getColumns()
152
+ const bulletStr = "● "
153
+ const contPad = pad + " "
154
+ const firstMax = Math.max(24, cols - pad.length - bulletStr.length - RIGHT_MARGIN)
155
+ const contMax = Math.max(24, cols - contPad.length - RIGHT_MARGIN)
156
+
157
+ const plainLines = mergeBrokenBacktickLines(
158
+ mergeAliasForWithNextLine(wordWrapPlain(text, firstMax, contMax))
159
+ )
160
+ plainLines.forEach((plain, i) => {
161
+ const styled = styleInlineCode(plain, (s) => chalk.white(s))
162
+ if (i === 0) {
163
+ stream(pad + chalk.greenBright(bulletStr) + styled)
164
+ } else {
165
+ stream(contPad + styled)
166
+ }
167
+ })
168
+ }
169
+
170
+ /**
171
+ * @param {string} line raw line (may have leading indent for nested bullets)
172
+ * @param {string} baseIndent e.g. two spaces
173
+ */
174
+ function formatReleaseLine(line, baseIndent) {
175
+ const trimmedEnd = line.replace(/\s+$/, "")
176
+ const t = trimmedEnd.trim()
177
+ if (t === "") {
178
+ return null
179
+ }
180
+
181
+ const rel = /^# ReleaseV(\d+\.\d+\.\d+)\s*$/.exec(t)
182
+ if (rel) {
183
+ return (
184
+ baseIndent +
185
+ chalk.bold.cyan("▸ ") +
186
+ chalk.bold.white("Release ") +
187
+ chalk.bold.greenBright("v" + rel[1])
188
+ )
189
+ }
190
+
191
+ const h4 = /^####\s+(.+)$/.exec(t)
192
+ if (h4) {
193
+ return (
194
+ baseIndent +
195
+ " " +
196
+ chalk.bold.magenta("▼ ") +
197
+ chalk.bold.white(h4[1].trim())
198
+ )
199
+ }
200
+
201
+ return baseIndent + " " + styleInlineCode(t, (s) => chalk.gray(s))
202
+ }
203
+
204
+ /**
205
+ * Wrap long `#### Key: value` lines (value part).
206
+ */
207
+ function printWrappedMeta(baseIndent, key, val, stream) {
208
+ const cols = getColumns()
209
+ const pad = baseIndent + " "
210
+ const labelChars = `${key}: `.length
211
+ const firstPrefix = pad + chalk.cyan(key) + chalk.dim(": ")
212
+ if (!val.length) {
213
+ stream(firstPrefix)
214
+ return
215
+ }
216
+ const firstMax = Math.max(24, cols - pad.length - labelChars - RIGHT_MARGIN)
217
+ const contPad = pad + " ".repeat(labelChars)
218
+ const contMax = Math.max(24, cols - contPad.length - RIGHT_MARGIN)
219
+
220
+ const lines = mergeBrokenBacktickLines(
221
+ wordWrapPlain(val, firstMax, contMax)
222
+ )
223
+ lines.forEach((plain, i) => {
224
+ const styled = chalk.greenBright(plain)
225
+ if (i === 0) {
226
+ stream(firstPrefix + styled)
227
+ } else {
228
+ stream(contPad + styled)
229
+ }
230
+ })
231
+ }
232
+
233
+ /**
234
+ * @param {string} body
235
+ * @param {function} stream default console.error
236
+ * @param {string} baseIndent
237
+ */
238
+ function printReleaseNotesBody(body, stream = console.error, baseIndent = " ") {
239
+ const lines = body.split("\n")
240
+ for (const line of lines) {
241
+ const trimmedEnd = line.replace(/\s+$/, "")
242
+ const t = trimmedEnd.trim()
243
+ if (t === "") {
244
+ stream("")
245
+ continue
246
+ }
247
+
248
+ const bullet = /^(\s*)-\s+(.*)$/.exec(line)
249
+ if (bullet) {
250
+ const ws = bullet[1].length
251
+ const pad = baseIndent + " ".repeat(2 + ws)
252
+ printWrappedBullet(pad, bullet[2], stream)
253
+ continue
254
+ }
255
+
256
+ const meta = /^####\s+([^:]+):\s*(.*)$/.exec(t)
257
+ if (meta) {
258
+ const key = meta[1].trim()
259
+ const val = meta[2].trim()
260
+ printWrappedMeta(baseIndent, key, val, stream)
261
+ continue
262
+ }
263
+
264
+ const out = formatReleaseLine(line, baseIndent)
265
+ if (out === null) stream("")
266
+ else stream(out)
267
+ }
268
+ }
269
+
270
+ /**
271
+ * @param {{ body: string }[]} blocks
272
+ * @param {function} stream
273
+ */
274
+ function printReleaseNotesBlocks(blocks, stream = console.error) {
275
+ if (!blocks || blocks.length === 0) return
276
+
277
+ stream("")
278
+ stream(
279
+ " " + chalk.bold.cyan("Release notes ") + chalk.gray.dim("(README.md)")
280
+ )
281
+ stream(
282
+ " " +
283
+ chalk.cyan.dim("╭") +
284
+ chalk.gray(BAR.repeat(W)) +
285
+ chalk.cyan.dim("╮")
286
+ )
287
+
288
+ for (let i = 0; i < blocks.length; i++) {
289
+ if (i > 0) {
290
+ stream("")
291
+ stream(" " + chalk.dim(" · · · · · · · · · ·"))
292
+ }
293
+ stream("")
294
+ printReleaseNotesBody(blocks[i].body, stream, " ")
295
+ }
296
+
297
+ stream(
298
+ " " +
299
+ chalk.cyan.dim("╰") +
300
+ chalk.gray(BAR.repeat(W)) +
301
+ chalk.cyan.dim("╯")
302
+ )
303
+ stream("")
304
+ }
305
+
306
+ module.exports = {
307
+ formatReleaseLine,
308
+ printReleaseNotesBody,
309
+ printReleaseNotesBlocks,
310
+ styleInlineCode,
311
+ wordWrapPlain,
312
+ }
@@ -0,0 +1,69 @@
1
+ const fs = require("fs")
2
+ const path = require("path")
3
+
4
+ function semverCompare(a, b) {
5
+ const pa = String(a)
6
+ .split(".")
7
+ .map((n) => parseInt(n, 10) || 0)
8
+ const pb = String(b)
9
+ .split(".")
10
+ .map((n) => parseInt(n, 10) || 0)
11
+ const len = Math.max(pa.length, pb.length)
12
+ for (let i = 0; i < len; i++) {
13
+ const da = pa[i] || 0
14
+ const db = pb[i] || 0
15
+ if (da !== db) return da > db ? 1 : -1
16
+ }
17
+ return 0
18
+ }
19
+
20
+ /**
21
+ * @param {string} readmePath
22
+ * @returns {{ version: string, body: string }[]}
23
+ */
24
+ function parseReadmeReleases(readmePath) {
25
+ if (!fs.existsSync(readmePath)) return []
26
+ const content = fs.readFileSync(readmePath, "utf8")
27
+ const re = /^# ReleaseV(\d+\.\d+\.\d+)\s*$/gm
28
+ const matches = []
29
+ let m
30
+ while ((m = re.exec(content)) !== null) {
31
+ matches.push({ version: m[1], start: m.index })
32
+ }
33
+ matches.sort((a, b) => a.start - b.start)
34
+ const out = []
35
+ for (let i = 0; i < matches.length; i++) {
36
+ const end = i + 1 < matches.length ? matches[i + 1].start : content.length
37
+ const body = content.slice(matches[i].start, end).trim()
38
+ out.push({ version: matches[i].version, body })
39
+ }
40
+ return out
41
+ }
42
+
43
+ function getReleaseForExact(readmePath, version) {
44
+ return parseReadmeReleases(readmePath).find((r) => r.version === version) || null
45
+ }
46
+
47
+ /**
48
+ * Versions strictly after `current` and up to and including `latest` (per README sections).
49
+ */
50
+ function getReleasesBetween(readmePath, current, latest) {
51
+ return parseReadmeReleases(readmePath)
52
+ .filter(
53
+ (r) =>
54
+ semverCompare(r.version, current) > 0 && semverCompare(r.version, latest) <= 0
55
+ )
56
+ .sort((a, b) => semverCompare(b.version, a.version))
57
+ }
58
+
59
+ function defaultReadmePath() {
60
+ return path.join(__dirname, "..", "README.md")
61
+ }
62
+
63
+ module.exports = {
64
+ semverCompare,
65
+ parseReadmeReleases,
66
+ getReleaseForExact,
67
+ getReleasesBetween,
68
+ defaultReadmePath,
69
+ }
@@ -1,38 +0,0 @@
1
- {
2
- "version_check": {
3
- "timestamp": 1774496967311
4
- },
5
- "oFKfA8V9DXIcs1l2EIe6tGNOd": {
6
- "username": "junsales@demo.com",
7
- "baseUrl": "https://solution.lightning.cloudcc.cn/ccdomaingateway",
8
- "setupSvc": "https://solution.lightning.cloudcc.cn/ccdomaingateway/setup",
9
- "orgId": "orgb5bc93c891c40ceac",
10
- "clientId": "halqHvw6tDXVCfWxeY9GOLxdp",
11
- "version": "public",
12
- "openSecretKey": "10634880-6b3c-4238-a4ef-83177b27ca33",
13
- "safetyMark": "oFKfA8V9DXIcs1l2EIe6tGNOd",
14
- "CloudCCDev": "",
15
- "apiSvc": "https://solution.lightning.cloudcc.cn/ccdomaingateway/apisvc",
16
- "accessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjbG91ZGNjIiwibG9naW5OYW1lIjoianVuc2FsZXNAZGVtby5jb20iLCJiaW5kaW5nIjoiYzkyMDY3OTgtYTk0ZC00YzllLThhMzMtODYyMDM5OTY5ODNhIiwiQ2xpZW50SWQiOiJoYWxxSHZ3NnREWFZDZld4ZVk5R09MeGRwIiwiZXhwIjoxNzc0NjY5NzEzLCJvcmdJZCI6Im9yZ2I1YmM5M2M4OTFjNDBjZWFjIn0.y3siaeaE2LjPNljocJgC7QuotdtPN2Ty1uZQbuxCm8s",
17
- "secretKey": "5c91aef5bc2740c49ab97831385036",
18
- "pluginToken": "unified202625474e701",
19
- "timestamp": 1774496913700
20
- },
21
- "QVOllKTKhnm5oHp49tCsSHvHg": {
22
- "username": "appstore@cloudcc.cn",
23
- "baseUrl": "https://yundong.lightning.cloudcc.cn/ccdomaingateway",
24
- "setupSvc": "https://yundong.lightning.cloudcc.cn/ccdomaingateway/setup",
25
- "orgId": "org9697882320dc71f28",
26
- "clientId": "bIA1IXRHl28hBkaQdiwQ63hZZ",
27
- "version": "public",
28
- "openSecretKey": "15bba2de-e6e7-42dc-9d7c-f9b157cd0ddb",
29
- "CloudCCDev": "",
30
- "safetyMark": "QVOllKTKhnm5oHp49tCsSHvHg",
31
- "buildVersion": "v2",
32
- "apiSvc": "https://yundong.lightning.cloudcc.cn/ccdomaingateway/apisvc",
33
- "accessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJjbG91ZGNjIiwibG9naW5OYW1lIjoiYXBwc3RvcmVAY2xvdWRjYy5jbiIsImJpbmRpbmciOiI2OGE3YTEyNi0yNTFkLTQxYjctOWY2MC00ZDRkYWEwZmIwMzEiLCJDbGllbnRJZCI6ImJJQTFJWFJIbDI4aEJrYVFkaXdRNjNoWloiLCJleHAiOjE3NzQ2NzQzNDksIm9yZ0lkIjoib3JnOTY5Nzg4MjMyMGRjNzFmMjgifQ.JtebE5jXCssV_N0JBrqDbgDK9qSSGmKMR4J5NZ4w2Oo",
34
- "secretKey": "d99313b4298544bc8ca1ee7459227b",
35
- "pluginToken": "unified20267d70bae69",
36
- "timestamp": 1774501550129
37
- }
38
- }
Binary file
@@ -1,68 +0,0 @@
1
- ---
2
- name: cloudcc-cli-usage
3
- description: CloudCC CRM 二次开发 CLI 文档检索技能。用于在设计方案和实际开发时,优先通过各模块的 `cc doc <module> introduction` 与 `cc doc <module> devguide` 获取文档。用户提到 CloudCC、cloudcc-cli、`cc doc`、模块文档、设计方案、开发文档、项目初始化、开发环境、对象、字段、菜单、应用、类、定时类、触发器、自定义组件、自定义页面、自定义设置、客户端脚本、静态资源 时应优先使用。
4
- ---
5
-
6
- # CloudCC CLI Usage
7
-
8
- ## 使用场景
9
-
10
- ### 1. 设计实现方案时
11
-
12
- - 当用户要做方案设计、实现设计、模块选型时,优先调用每个模块的
13
- `introduction`文档。
14
- - 命令格式:`cc doc <module> introduction`
15
- - 目标:先理解模块定位、适用场景、能力边界。
16
- - 然后编写详细的设计文档,包括对象,字段等。
17
-
18
- ### 2. 开发实现时
19
-
20
- - 当用户进入实际开发阶段时,优先调用每个模块的 `devguide` 文档。
21
- - 命令格式:`cc doc <module> devguide`
22
- - 目标:先获取模块的开发说明、实现方式和注意事项。
23
-
24
- ## 开发流程
25
-
26
- 1. 先调用
27
- `cc doc project devguide`,完成开发环境搭建、模板项目创建、密钥配置等准备工作。
28
- 2. 再根据开发需要,调用对应模块的 `devguide` 文档。
29
-
30
- ## 模块命令(按仓库现状)
31
-
32
- ### 基础与环境
33
-
34
- - 项目与环境:`cc doc project introduction`、`cc doc project devguide`
35
- - CLI 配置:`cc doc config devguide`
36
-
37
- ### 元数据与模型设计
38
-
39
- - 对象:`cc doc object introduction`、`cc doc object devguide`
40
- - 字段:`cc doc fields introduction`、`cc doc fields devguide`
41
- - 记录类型:`cc doc recordType introduction`、`cc doc recordType devguide`
42
- - 全局选项列表:`cc doc globalSelectList introduction`、`cc doc globalSelectList devguide`
43
-
44
- ### 权限与组织管理
45
-
46
- - 用户:`cc doc user introduction`、`cc doc user devguide`
47
- - 角色:`cc doc role introduction`、`cc doc role devguide`
48
- - 简档:`cc doc profile introduction`、`cc doc profile devguide`
49
-
50
- ### 业务扩展(后端)
51
-
52
- - 后端类:`cc doc classes introduction`、`cc doc classes devguide`
53
- - 触发器:`cc doc triggers introduction`、`cc doc triggers devguide`
54
- - 定时类:`cc doc timer introduction`、`cc doc timer devguide`
55
- - 定时作业:`cc doc scheduleJob introduction`、`cc doc scheduleJob devguide`
56
-
57
- ### 业务扩展(前端)
58
-
59
- - 自定义组件:`cc doc plugin introduction`、`cc doc plugin devguide`
60
- - 自定义页面:`cc doc customPage introduction`、`cc doc customPage devguide`
61
- - 客户端脚本:`cc doc script introduction`、`cc doc script devguide`
62
- - 静态资源:`cc doc staticResource introduction`、`cc doc staticResource devguide`
63
-
64
- ### 平台配置与导航
65
-
66
- - 菜单:`cc doc menu introduction`、`cc doc menu devguide`
67
- - 应用:`cc doc application introduction`、`cc doc application devguide`
68
- - 自定义设置:`cc doc customSetting introduction`、`cc doc customSetting devguide`