cloudcc-cli 2.3.4 → 2.3.6

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 (244) hide show
  1. package/.claude/settings.json +22 -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 +81 -6
  5. package/bin/cc.js +106 -28
  6. package/bin/index.js +54 -55
  7. package/mcp/cliRunner.js +11 -4
  8. package/mcp/index.js +12 -2
  9. package/mcp/tools/Application Creator/handler.js +1 -1
  10. package/mcp/tools/Approval/handler.js +3 -3
  11. package/mcp/tools/Class Creator/handler.js +2 -2
  12. package/mcp/tools/Class Detail Retriever/handler.js +1 -1
  13. package/mcp/tools/Class Editor Guide/handler.js +1 -1
  14. package/mcp/tools/Class List Retriever/handler.js +1 -1
  15. package/mcp/tools/Class Publisher/handler.js +1 -1
  16. package/mcp/tools/Class Puller/handler.js +1 -1
  17. package/mcp/tools/Client Script Detail Retriever/handler.js +1 -1
  18. package/mcp/tools/Client Script Editor Guide/handler.js +1 -1
  19. package/mcp/tools/Client Script List Retriever/handler.js +1 -1
  20. package/mcp/tools/Client Script Publisher/handler.js +1 -1
  21. package/mcp/tools/Client Script Puller/handler.js +2 -2
  22. package/mcp/tools/CloudCC Development Overview/handler.js +2 -2
  23. package/mcp/tools/Component Creator/handler.js +1 -1
  24. package/mcp/tools/Component Detail Retriever/handler.js +1 -1
  25. package/mcp/tools/Component Editor Guide/handler.js +1 -1
  26. package/mcp/tools/Component List Retriever/handler.js +1 -1
  27. package/mcp/tools/Component Publisher/handler.js +2 -2
  28. package/mcp/tools/Component Puller/handler.js +1 -1
  29. package/mcp/tools/Dev Environment Creator/handler.js +1 -1
  30. package/mcp/tools/Dev Environment Validator/handler.js +1 -1
  31. package/mcp/tools/Developer Key Setup Guide/handler.js +1 -1
  32. package/mcp/tools/JSP Migrator/handler.js +46 -0
  33. package/mcp/tools/Menu Creator/handler.js +1 -1
  34. package/mcp/tools/Object Creator/handler.js +2 -2
  35. package/mcp/tools/Object Fields Creator/handler.js +1 -1
  36. package/mcp/tools/Object Fields Retriever/handler.js +1 -1
  37. package/mcp/tools/Object List Retriever/handler.js +1 -1
  38. package/mcp/tools/Scheduled Class Creator/handler.js +1 -1
  39. package/mcp/tools/Scheduled Class Detail Retriever/handler.js +1 -1
  40. package/mcp/tools/Scheduled Class List Retriever/handler.js +1 -1
  41. package/mcp/tools/Scheduled Class Publisher/handler.js +1 -1
  42. package/mcp/tools/Scheduled Class Puller/handler.js +1 -1
  43. package/mcp/tools/Trigger Creator/handler.js +1 -1
  44. package/mcp/tools/Trigger Detail Retriever/handler.js +1 -1
  45. package/mcp/tools/Trigger Editor Guide/handler.js +1 -1
  46. package/mcp/tools/Trigger List Retriever/handler.js +1 -1
  47. package/mcp/tools/Trigger Publisher/handler.js +1 -1
  48. package/mcp/tools/Trigger Puller/handler.js +1 -1
  49. package/package.json +3 -3
  50. package/src/application/create.js +2 -2
  51. package/src/application/delete.js +2 -2
  52. package/src/application/doc.js +2 -2
  53. package/src/application/docs/devguide.md +25 -25
  54. package/src/application/docs/introduction.md +2 -2
  55. package/src/button/create.js +169 -0
  56. package/src/button/delete.js +35 -0
  57. package/src/button/doc.js +36 -0
  58. package/src/button/docs/devguide.md +133 -0
  59. package/src/button/docs/introduction.md +60 -0
  60. package/src/button/get.js +60 -0
  61. package/src/button/index.js +20 -0
  62. package/src/classes/create.js +1 -1
  63. package/src/classes/delete.js +1 -1
  64. package/src/classes/detail.js +1 -1
  65. package/src/classes/doc.js +2 -2
  66. package/src/classes/docs/devguide.md +21 -21
  67. package/src/classes/docs/introduction.md +0 -20
  68. package/src/classes/get.js +1 -1
  69. package/src/classes/publish.js +1 -1
  70. package/src/classes/pull.js +1 -1
  71. package/src/classes/pullList.js +1 -1
  72. package/src/config/doc.js +2 -2
  73. package/src/config/docs/devguide.md +15 -15
  74. package/src/customPage/create.js +2 -2
  75. package/src/customPage/delete.js +2 -2
  76. package/src/customPage/doc.js +2 -2
  77. package/src/customPage/docs/devguide.md +27 -27
  78. package/src/customPage/get.js +1 -1
  79. package/src/customSetting/create.js +1 -1
  80. package/src/customSetting/delete.js +1 -1
  81. package/src/customSetting/deleteCustomSettingField.js +1 -1
  82. package/src/customSetting/detail.js +1 -1
  83. package/src/customSetting/docs/devguide.md +9 -9
  84. package/src/customSetting/editCustomSettingField.js +1 -1
  85. package/src/customSetting/get.js +1 -1
  86. package/src/customSetting/modify.js +1 -1
  87. package/src/customSetting/saveCustomSettingField.js +1 -1
  88. package/src/fields/delete.js +2 -2
  89. package/src/fields/docs/devguide.md +14 -14
  90. package/src/fields/docs/introduction.md +3 -3
  91. package/src/globalSelectList/create.js +1 -1
  92. package/src/globalSelectList/delete.js +1 -1
  93. package/src/globalSelectList/detail.js +1 -1
  94. package/src/globalSelectList/doc.js +2 -2
  95. package/src/globalSelectList/docs/devguide.md +7 -7
  96. package/src/globalSelectList/get.js +1 -1
  97. package/src/identityProvider/create.js +78 -0
  98. package/src/identityProvider/delete.js +61 -0
  99. package/src/identityProvider/doc.js +46 -0
  100. package/src/identityProvider/docs/devguide.md +107 -0
  101. package/src/identityProvider/docs/introduction.md +31 -0
  102. package/src/identityProvider/download.js +105 -0
  103. package/src/identityProvider/get.js +70 -0
  104. package/src/identityProvider/index.js +12 -0
  105. package/src/menu/create-object.js +2 -2
  106. package/src/menu/create-page.js +2 -2
  107. package/src/menu/create-script.js +2 -2
  108. package/src/menu/create-site.js +2 -2
  109. package/src/menu/create.js +11 -11
  110. package/src/menu/delete.js +2 -2
  111. package/src/menu/doc.js +2 -2
  112. package/src/menu/docs/devguide.md +13 -13
  113. package/src/menu/docs/introduction.md +3 -3
  114. package/src/menu/get.js +1 -1
  115. package/src/object/create.js +2 -2
  116. package/src/object/delete.js +2 -2
  117. package/src/object/docs/devguide.md +11 -11
  118. package/src/pagelayout/create.js +6 -6
  119. package/src/pagelayout/delete.js +4 -4
  120. package/src/pagelayout/doc.js +2 -2
  121. package/src/pagelayout/docs/devguide.md +9 -9
  122. package/src/pagelayout/docs/introduction.md +1 -1
  123. package/src/pagelayout/get.js +4 -4
  124. package/src/permission/add.js +164 -0
  125. package/src/permission/assign.js +84 -0
  126. package/src/permission/docs/devguide.md +238 -0
  127. package/src/permission/docs/introduction.md +200 -0
  128. package/src/permission/get.js +107 -0
  129. package/src/permission/index.js +10 -0
  130. package/src/permission/remove.js +145 -0
  131. package/src/plugin/delete.js +2 -2
  132. package/src/plugin/doc.js +2 -2
  133. package/src/plugin/docs/devguide.md +29 -29
  134. package/src/profile/create.js +5 -5
  135. package/src/profile/delete.js +2 -2
  136. package/src/profile/doc.js +2 -2
  137. package/src/profile/docs/devguide.md +8 -8
  138. package/src/profile/docs/introduction.md +12 -12
  139. package/src/profile/get.js +1 -1
  140. package/src/project/docs/devguide.md +9 -8
  141. package/src/recordType/create.js +1 -1
  142. package/src/recordType/delete.js +1 -1
  143. package/src/recordType/doc.js +2 -2
  144. package/src/recordType/docs/devguide.md +10 -10
  145. package/src/recordType/editInfo.js +1 -1
  146. package/src/recordType/editSave.js +1 -1
  147. package/src/recordType/getList.js +1 -1
  148. package/src/recordType/newInfo.js +1 -1
  149. package/src/recordType/validDelete.js +1 -1
  150. package/src/res.md +1 -1
  151. package/src/role/create.js +6 -6
  152. package/src/role/delete.js +2 -2
  153. package/src/role/doc.js +2 -2
  154. package/src/role/docs/devguide.md +9 -9
  155. package/src/role/docs/introduction.md +13 -13
  156. package/src/role/get.js +1 -1
  157. package/src/scheduleJob/doc.js +1 -1
  158. package/src/scheduleJob/docs/devguide.md +6 -6
  159. package/src/scheduleJob/docs/introduction.md +6 -6
  160. package/src/script/docs/devguide.md +18 -18
  161. package/src/singleSignOn/delete.js +61 -0
  162. package/src/singleSignOn/doc.js +46 -0
  163. package/src/singleSignOn/docs/devguide.md +61 -0
  164. package/src/singleSignOn/docs/introduction.md +3 -0
  165. package/src/singleSignOn/get.js +70 -0
  166. package/src/singleSignOn/index.js +10 -0
  167. package/src/staticResource/count.js +1 -1
  168. package/src/staticResource/create.js +1 -1
  169. package/src/staticResource/delete.js +1 -1
  170. package/src/staticResource/detail.js +1 -1
  171. package/src/staticResource/docs/devguide.md +11 -11
  172. package/src/staticResource/docs/introduction.md +44 -1
  173. package/src/staticResource/get.js +1 -1
  174. package/src/timer/create.js +1 -1
  175. package/src/timer/delete.js +1 -1
  176. package/src/timer/detail.js +1 -1
  177. package/src/timer/doc.js +2 -2
  178. package/src/timer/docs/devguide.md +19 -19
  179. package/src/timer/get.js +1 -1
  180. package/src/timer/publish.js +1 -1
  181. package/src/timer/pull.js +1 -1
  182. package/src/timer/pullList.js +1 -1
  183. package/src/triggers/detail.js +1 -1
  184. package/src/triggers/doc.js +2 -2
  185. package/src/triggers/docs/devguide.md +23 -23
  186. package/src/triggers/get.js +1 -1
  187. package/src/triggers/pullList.js +1 -1
  188. package/src/user/create.js +2 -2
  189. package/src/user/delete.js +2 -2
  190. package/src/user/doc.js +2 -2
  191. package/src/user/docs/devguide.md +13 -13
  192. package/src/user/docs/introduction.md +12 -12
  193. package/src/user/get.js +1 -1
  194. package/src/user/update.js +3 -3
  195. package/src/user/view.js +2 -2
  196. package/src/validationRule/create.js +7 -7
  197. package/src/validationRule/delete.js +2 -2
  198. package/src/validationRule/doc.js +2 -2
  199. package/src/validationRule/docs/devguide.md +7 -7
  200. package/src/validationRule/docs/introduction.md +11 -11
  201. package/src/validationRule/get.js +1 -1
  202. package/src/version/actionHelp.js +25 -0
  203. package/src/version/docs.js +26 -0
  204. package/src/version/doctor.js +25 -0
  205. package/src/version/get.js +1 -1
  206. package/src/version/help.js +48 -0
  207. package/src/version/index.js +9 -2
  208. package/src/version/initHelp.js +13 -0
  209. package/src/version/listModuleCommands.js +241 -0
  210. package/src/version/stats.js +44 -0
  211. package/src/version/uninstall.js +30 -0
  212. package/src/version/update.js +13 -0
  213. package/test/application.cli.test.js +1 -1
  214. package/test/classes.cli.test.js +1 -1
  215. package/test/customSetting.cli.test.js +1 -1
  216. package/test/fields.cli.test.js +2 -2
  217. package/test/globalSelectList.cli.test.js +1 -1
  218. package/test/menu-script.cli.test.js +1 -1
  219. package/test/menu.cli.test.js +1 -1
  220. package/test/object.cli.test.js +1 -1
  221. package/test/plugin.cli.test.js +1 -1
  222. package/test/scheduleJob.cli.test.js +1 -1
  223. package/test/script.cli.test.js +1 -1
  224. package/test/staticResource.cli.test.js +1 -1
  225. package/test/timer.cli.test.js +1 -1
  226. package/test/trigger.cli.test.js +1 -1
  227. package/utils/checkVersion.js +27 -2
  228. package/utils/commandStats.js +94 -0
  229. package/utils/formatReleaseNotes.js +312 -0
  230. package/utils/readmeReleases.js +69 -0
  231. package/.cloudcc-cache.json +0 -54
  232. package/.cursor/skills/cloudcc-cli-dev.zip +0 -0
  233. package/.cursor/skills/cloudcc-dev-usage/SKILL.md +0 -68
  234. package/build/component-cc-cc-dd.common.js +0 -831
  235. package/build/component-cc-cc-dd.common.js.map +0 -1
  236. package/build/component-cc-cc-dd.css +0 -1
  237. package/build/component-cc-cc-dd.umd.js +0 -874
  238. package/build/component-cc-cc-dd.umd.js.map +0 -1
  239. package/build/component-cc-cc-dd.umd.min.js +0 -8
  240. package/build/component-cc-cc-dd.umd.min.js.map +0 -1
  241. package/build/demo.html +0 -1
  242. package/plugins/cc-cc-dd/cc-cc-dd.vue +0 -32
  243. package/plugins/cc-cc-dd/components/HelloWorld.vue +0 -11
  244. package/plugins/cc-cc-dd/config.json +0 -6
@@ -12,7 +12,7 @@ function quoteArg(value) {
12
12
  }
13
13
 
14
14
  async function runCc(args) {
15
- const cmd = `npx --prefix "${repoRoot}" cc ${args.map(quoteArg).join(" ")}`;
15
+ const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
16
16
  return execAsync(cmd, { cwd: repoRoot });
17
17
  }
18
18
 
@@ -44,7 +44,7 @@ test("字段管理流程:获取对象列表→create 字段→get 字段列表
44
44
 
45
45
  t.test("2) create 创建一个文本字段(S)", async () => {
46
46
  assert.ok(objId, "需要对象 id");
47
- // create fields 调用约定:cc create fields <path> <fieldType> <objid> <nameLabel> [...]
47
+ // create fields 调用约定:cloudcc create fields <path> <fieldType> <objid> <nameLabel> [...]
48
48
  const { stdout, stderr } = await runCc(["create", "fields", repoRoot, "S", objId, fieldLabel]);
49
49
  // create fields 会通过 console.error 输出创建结果(见 src/fields/create.js)
50
50
  assert.match(
@@ -12,7 +12,7 @@ function quoteArg(value) {
12
12
  }
13
13
 
14
14
  async function runCc(args) {
15
- const cmd = `npx --prefix "${repoRoot}" cc ${args.map(quoteArg).join(" ")}`;
15
+ const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
16
16
  return execAsync(cmd, { cwd: repoRoot });
17
17
  }
18
18
 
@@ -12,7 +12,7 @@ function quoteArg(value) {
12
12
  }
13
13
 
14
14
  async function runCc(args) {
15
- const cmd = `npx --prefix "${repoRoot}" cc ${args.map(quoteArg).join(" ")}`;
15
+ const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
16
16
  return execAsync(cmd, { cwd: repoRoot });
17
17
  }
18
18
 
@@ -12,7 +12,7 @@ function quoteArg(value) {
12
12
  }
13
13
 
14
14
  async function runCc(args) {
15
- const cmd = `npx --prefix "${repoRoot}" cc ${args.map(quoteArg).join(" ")}`;
15
+ const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
16
16
  return execAsync(cmd, { cwd: repoRoot });
17
17
  }
18
18
 
@@ -12,7 +12,7 @@ function quoteArg(value) {
12
12
  }
13
13
 
14
14
  async function runCc(args) {
15
- const cmd = `npx --prefix "${repoRoot}" cc ${args.map(quoteArg).join(" ")}`;
15
+ const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
16
16
  return execAsync(cmd, { cwd: repoRoot });
17
17
  }
18
18
 
@@ -14,7 +14,7 @@ function quoteArg(value) {
14
14
  }
15
15
 
16
16
  async function runCc(args) {
17
- const cmd = `npx --prefix "${repoRoot}" cc ${args.map(quoteArg).join(" ")}`;
17
+ const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
18
18
  return execAsync(cmd, { cwd: repoRoot });
19
19
  }
20
20
 
@@ -12,7 +12,7 @@ function quoteArg(value) {
12
12
  }
13
13
 
14
14
  async function runCc(args) {
15
- const cmd = `npx --prefix "${repoRoot}" cc ${args.map(quoteArg).join(" ")}`;
15
+ const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
16
16
  return execAsync(cmd, { cwd: repoRoot });
17
17
  }
18
18
 
@@ -14,7 +14,7 @@ function quoteArg(value) {
14
14
  }
15
15
 
16
16
  async function runCc(args) {
17
- const cmd = `npx --prefix "${repoRoot}" cc ${args.map(quoteArg).join(" ")}`;
17
+ const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
18
18
  return execAsync(cmd, { cwd: repoRoot });
19
19
  }
20
20
 
@@ -12,7 +12,7 @@ function quoteArg(value) {
12
12
  }
13
13
 
14
14
  async function runCc(args) {
15
- const cmd = `npx --prefix "${repoRoot}" cc ${args.map(quoteArg).join(" ")}`;
15
+ const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
16
16
  return execAsync(cmd, { cwd: repoRoot });
17
17
  }
18
18
 
@@ -14,7 +14,7 @@ function quoteArg(value) {
14
14
  }
15
15
 
16
16
  async function runCc(args) {
17
- const cmd = `npx --prefix "${repoRoot}" cc ${args.map(quoteArg).join(" ")}`;
17
+ const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
18
18
  return execAsync(cmd, { cwd: repoRoot });
19
19
  }
20
20
 
@@ -14,7 +14,7 @@ function quoteArg(value) {
14
14
  }
15
15
 
16
16
  async function runCc(args) {
17
- const cmd = `npx --prefix "${repoRoot}" cc ${args.map(quoteArg).join(" ")}`;
17
+ const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
18
18
  return execAsync(cmd, { cwd: repoRoot });
19
19
  }
20
20
 
@@ -5,6 +5,12 @@ const chalk = require("chalk")
5
5
  const { readCache, writeCache } = require("./cache")
6
6
  const fs = require('fs');
7
7
  const path = require('path');
8
+ const {
9
+ semverCompare,
10
+ getReleasesBetween,
11
+ defaultReadmePath,
12
+ } = require("./readmeReleases");
13
+ const { printReleaseNotesBlocks } = require("./formatReleaseNotes");
8
14
 
9
15
  function checkNpmVersion() {
10
16
  let currentVersion = Number(config.version.replace(/\./g, ""));
@@ -31,7 +37,9 @@ function checkNpmVersion() {
31
37
  console.error(' ' + chalk.yellow('★') + ' Published At : ' + chalk.gray(formattedTime));
32
38
  console.error(' ' + chalk.magenta('★') + ' Developer Docs : ' + chalk.cyan('https://help.cloudcc.cn/'));
33
39
  console.error(' ' + chalk.magenta('★') + ' Changelog : ' + chalk.cyan('https://www.npmjs.com/package/cloudcc-cli'));
34
- console.error(' ' + chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
40
+ console.error(' ' + chalk.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━'));
41
+
42
+ printReadmeReleaseNotesIfUpgradeNeeded(config.version, onlineVersion);
35
43
 
36
44
  if (onlineVersionNum - currentVersion > 0) {
37
45
  return onlineVersion;
@@ -39,6 +47,23 @@ function checkNpmVersion() {
39
47
  return null;
40
48
  }
41
49
 
50
+ /**
51
+ * Prints README `# ReleaseV*` sections only when the registry has a **newer** version than local:
52
+ * all release blocks from current (exclusive) through latest (inclusive). If already up to date,
53
+ * prints nothing (changelog link remains in the version panel above).
54
+ */
55
+ function printReadmeReleaseNotesIfUpgradeNeeded(currentVersion, latestVersion) {
56
+ if (semverCompare(latestVersion, currentVersion) <= 0) {
57
+ return;
58
+ }
59
+ const readmePath = defaultReadmePath();
60
+ const blocks = getReleasesBetween(readmePath, currentVersion, latestVersion);
61
+ if (blocks.length === 0) {
62
+ return;
63
+ }
64
+ printReleaseNotesBlocks(blocks, console.error);
65
+ }
66
+
42
67
 
43
68
  function askUpdate() {
44
69
  console.error();
@@ -154,4 +179,4 @@ function checkAndReplaceJar(projectPath = process.cwd()) {
154
179
  }
155
180
  }
156
181
 
157
- module.exports = { checkUpdate };
182
+ module.exports = { checkUpdate, checkNpmVersion, update };
@@ -0,0 +1,94 @@
1
+ const fs = require("fs")
2
+ const path = require("path")
3
+ const os = require("os")
4
+
5
+ /**
6
+ * 默认开启:在 ~/.cloudcc-cli/command-stats.json 累计调用次数;
7
+ * 键为人类可读形式,如 `cloudcc doc classes`、`cloudcc get brief`。
8
+ * 设 `CLOUDCC_CLI_STATS=0` / `false` / `off` 可关闭。
9
+ */
10
+ function isEnabled() {
11
+ const v = process.env.CLOUDCC_CLI_STATS
12
+ if (v == null || String(v).trim() === "") return true
13
+ const s = String(v).trim().toLowerCase()
14
+ if (s === "0" || s === "false" || s === "no" || s === "off") return false
15
+ return true
16
+ }
17
+
18
+ function statsFilePath() {
19
+ return path.join(os.homedir(), ".cloudcc-cli", "command-stats.json")
20
+ }
21
+
22
+ /**
23
+ * @param {string} action 第一参数(或全局标志如 -v、--help)
24
+ * @param {string} resource 第二参数;无第二段时用 "_";子帮助用 "_help";action 级 -h 用 "-h"
25
+ */
26
+ function formatRecordKey(action, resource) {
27
+ const res = resource == null || resource === "" ? "_" : String(resource)
28
+ if (res === "_") {
29
+ if (
30
+ action === "-v" ||
31
+ action === "--v" ||
32
+ action === "-version" ||
33
+ action === "--version"
34
+ ) {
35
+ return "cloudcc --version"
36
+ }
37
+ if (action === "-h" || action === "--h" || action === "--help") {
38
+ return "cloudcc --help"
39
+ }
40
+ return `cloudcc ${action}`
41
+ }
42
+ if (res === "_help") {
43
+ return `cloudcc ${action} --help`
44
+ }
45
+ if (res === "-h" || res === "--help") {
46
+ return `cloudcc ${action} -h`
47
+ }
48
+ return `cloudcc ${action} ${res}`
49
+ }
50
+
51
+ /**
52
+ * @param {string} action 第一参数,如 get、doc、create
53
+ * @param {string} resource 第二参数;无第二段时用 "_"(全局子命令)
54
+ */
55
+ function record(action, resource) {
56
+ if (!isEnabled()) return
57
+ if (!action || typeof action !== "string") return
58
+ const res = resource == null || resource === "" ? "_" : String(resource)
59
+ const key = formatRecordKey(action, res)
60
+ try {
61
+ const file = statsFilePath()
62
+ const dir = path.dirname(file)
63
+ if (!fs.existsSync(dir)) {
64
+ fs.mkdirSync(dir, { recursive: true })
65
+ }
66
+ let data = { version: 1, counts: {}, updatedAt: null }
67
+ if (fs.existsSync(file)) {
68
+ data = JSON.parse(fs.readFileSync(file, "utf8"))
69
+ if (!data.counts || typeof data.counts !== "object") data.counts = {}
70
+ }
71
+ data.counts[key] = (data.counts[key] || 0) + 1
72
+ data.updatedAt = new Date().toISOString()
73
+ fs.writeFileSync(file, JSON.stringify(data, null, 2), "utf8")
74
+ } catch (_e) {
75
+ // 统计失败不影响 CLI
76
+ }
77
+ }
78
+
79
+ function readStats() {
80
+ try {
81
+ const file = statsFilePath()
82
+ if (fs.existsSync(file)) {
83
+ return JSON.parse(fs.readFileSync(file, "utf8"))
84
+ }
85
+ } catch (_e) {}
86
+ return { version: 1, counts: {}, updatedAt: null }
87
+ }
88
+
89
+ module.exports = {
90
+ isEnabled,
91
+ record,
92
+ readStats,
93
+ statsFilePath,
94
+ }
@@ -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
+ }