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.
- package/.claude/settings.json +22 -1
- package/.cursor/skills/cloudcc-cli-dev/SKILL.md +175 -0
- package/.cursor/skills/cloudcc-dev-skill/SKILL.md +71 -0
- package/README.md +81 -6
- package/bin/cc.js +106 -28
- package/bin/index.js +54 -55
- package/mcp/cliRunner.js +11 -4
- package/mcp/index.js +12 -2
- package/mcp/tools/Application Creator/handler.js +1 -1
- package/mcp/tools/Approval/handler.js +3 -3
- package/mcp/tools/Class Creator/handler.js +2 -2
- package/mcp/tools/Class Detail Retriever/handler.js +1 -1
- package/mcp/tools/Class Editor Guide/handler.js +1 -1
- package/mcp/tools/Class List Retriever/handler.js +1 -1
- package/mcp/tools/Class Publisher/handler.js +1 -1
- package/mcp/tools/Class Puller/handler.js +1 -1
- package/mcp/tools/Client Script Detail Retriever/handler.js +1 -1
- package/mcp/tools/Client Script Editor Guide/handler.js +1 -1
- package/mcp/tools/Client Script List Retriever/handler.js +1 -1
- package/mcp/tools/Client Script Publisher/handler.js +1 -1
- package/mcp/tools/Client Script Puller/handler.js +2 -2
- package/mcp/tools/CloudCC Development Overview/handler.js +2 -2
- package/mcp/tools/Component Creator/handler.js +1 -1
- package/mcp/tools/Component Detail Retriever/handler.js +1 -1
- package/mcp/tools/Component Editor Guide/handler.js +1 -1
- package/mcp/tools/Component List Retriever/handler.js +1 -1
- package/mcp/tools/Component Publisher/handler.js +2 -2
- package/mcp/tools/Component Puller/handler.js +1 -1
- package/mcp/tools/Dev Environment Creator/handler.js +1 -1
- package/mcp/tools/Dev Environment Validator/handler.js +1 -1
- package/mcp/tools/Developer Key Setup Guide/handler.js +1 -1
- package/mcp/tools/JSP Migrator/handler.js +46 -0
- package/mcp/tools/Menu Creator/handler.js +1 -1
- package/mcp/tools/Object Creator/handler.js +2 -2
- package/mcp/tools/Object Fields Creator/handler.js +1 -1
- package/mcp/tools/Object Fields Retriever/handler.js +1 -1
- package/mcp/tools/Object List Retriever/handler.js +1 -1
- package/mcp/tools/Scheduled Class Creator/handler.js +1 -1
- package/mcp/tools/Scheduled Class Detail Retriever/handler.js +1 -1
- package/mcp/tools/Scheduled Class List Retriever/handler.js +1 -1
- package/mcp/tools/Scheduled Class Publisher/handler.js +1 -1
- package/mcp/tools/Scheduled Class Puller/handler.js +1 -1
- package/mcp/tools/Trigger Creator/handler.js +1 -1
- package/mcp/tools/Trigger Detail Retriever/handler.js +1 -1
- package/mcp/tools/Trigger Editor Guide/handler.js +1 -1
- package/mcp/tools/Trigger List Retriever/handler.js +1 -1
- package/mcp/tools/Trigger Publisher/handler.js +1 -1
- package/mcp/tools/Trigger Puller/handler.js +1 -1
- package/package.json +3 -3
- package/src/application/create.js +2 -2
- package/src/application/delete.js +2 -2
- package/src/application/doc.js +2 -2
- package/src/application/docs/devguide.md +25 -25
- package/src/application/docs/introduction.md +2 -2
- package/src/button/create.js +169 -0
- package/src/button/delete.js +35 -0
- package/src/button/doc.js +36 -0
- package/src/button/docs/devguide.md +133 -0
- package/src/button/docs/introduction.md +60 -0
- package/src/button/get.js +60 -0
- package/src/button/index.js +20 -0
- package/src/classes/create.js +1 -1
- package/src/classes/delete.js +1 -1
- package/src/classes/detail.js +1 -1
- package/src/classes/doc.js +2 -2
- package/src/classes/docs/devguide.md +21 -21
- package/src/classes/docs/introduction.md +0 -20
- package/src/classes/get.js +1 -1
- package/src/classes/publish.js +1 -1
- package/src/classes/pull.js +1 -1
- package/src/classes/pullList.js +1 -1
- package/src/config/doc.js +2 -2
- package/src/config/docs/devguide.md +15 -15
- package/src/customPage/create.js +2 -2
- package/src/customPage/delete.js +2 -2
- package/src/customPage/doc.js +2 -2
- package/src/customPage/docs/devguide.md +27 -27
- package/src/customPage/get.js +1 -1
- package/src/customSetting/create.js +1 -1
- package/src/customSetting/delete.js +1 -1
- package/src/customSetting/deleteCustomSettingField.js +1 -1
- package/src/customSetting/detail.js +1 -1
- package/src/customSetting/docs/devguide.md +9 -9
- package/src/customSetting/editCustomSettingField.js +1 -1
- package/src/customSetting/get.js +1 -1
- package/src/customSetting/modify.js +1 -1
- package/src/customSetting/saveCustomSettingField.js +1 -1
- package/src/fields/delete.js +2 -2
- package/src/fields/docs/devguide.md +14 -14
- package/src/fields/docs/introduction.md +3 -3
- package/src/globalSelectList/create.js +1 -1
- package/src/globalSelectList/delete.js +1 -1
- package/src/globalSelectList/detail.js +1 -1
- package/src/globalSelectList/doc.js +2 -2
- package/src/globalSelectList/docs/devguide.md +7 -7
- package/src/globalSelectList/get.js +1 -1
- package/src/identityProvider/create.js +78 -0
- package/src/identityProvider/delete.js +61 -0
- package/src/identityProvider/doc.js +46 -0
- package/src/identityProvider/docs/devguide.md +107 -0
- package/src/identityProvider/docs/introduction.md +31 -0
- package/src/identityProvider/download.js +105 -0
- package/src/identityProvider/get.js +70 -0
- package/src/identityProvider/index.js +12 -0
- package/src/menu/create-object.js +2 -2
- package/src/menu/create-page.js +2 -2
- package/src/menu/create-script.js +2 -2
- package/src/menu/create-site.js +2 -2
- package/src/menu/create.js +11 -11
- package/src/menu/delete.js +2 -2
- package/src/menu/doc.js +2 -2
- package/src/menu/docs/devguide.md +13 -13
- package/src/menu/docs/introduction.md +3 -3
- package/src/menu/get.js +1 -1
- package/src/object/create.js +2 -2
- package/src/object/delete.js +2 -2
- package/src/object/docs/devguide.md +11 -11
- package/src/pagelayout/create.js +6 -6
- package/src/pagelayout/delete.js +4 -4
- package/src/pagelayout/doc.js +2 -2
- package/src/pagelayout/docs/devguide.md +9 -9
- package/src/pagelayout/docs/introduction.md +1 -1
- package/src/pagelayout/get.js +4 -4
- package/src/permission/add.js +164 -0
- package/src/permission/assign.js +84 -0
- package/src/permission/docs/devguide.md +238 -0
- package/src/permission/docs/introduction.md +200 -0
- package/src/permission/get.js +107 -0
- package/src/permission/index.js +10 -0
- package/src/permission/remove.js +145 -0
- package/src/plugin/delete.js +2 -2
- package/src/plugin/doc.js +2 -2
- package/src/plugin/docs/devguide.md +29 -29
- package/src/profile/create.js +5 -5
- package/src/profile/delete.js +2 -2
- package/src/profile/doc.js +2 -2
- package/src/profile/docs/devguide.md +8 -8
- package/src/profile/docs/introduction.md +12 -12
- package/src/profile/get.js +1 -1
- package/src/project/docs/devguide.md +9 -8
- package/src/recordType/create.js +1 -1
- package/src/recordType/delete.js +1 -1
- package/src/recordType/doc.js +2 -2
- package/src/recordType/docs/devguide.md +10 -10
- package/src/recordType/editInfo.js +1 -1
- package/src/recordType/editSave.js +1 -1
- package/src/recordType/getList.js +1 -1
- package/src/recordType/newInfo.js +1 -1
- package/src/recordType/validDelete.js +1 -1
- package/src/res.md +1 -1
- package/src/role/create.js +6 -6
- package/src/role/delete.js +2 -2
- package/src/role/doc.js +2 -2
- package/src/role/docs/devguide.md +9 -9
- package/src/role/docs/introduction.md +13 -13
- package/src/role/get.js +1 -1
- package/src/scheduleJob/doc.js +1 -1
- package/src/scheduleJob/docs/devguide.md +6 -6
- package/src/scheduleJob/docs/introduction.md +6 -6
- package/src/script/docs/devguide.md +18 -18
- package/src/singleSignOn/delete.js +61 -0
- package/src/singleSignOn/doc.js +46 -0
- package/src/singleSignOn/docs/devguide.md +61 -0
- package/src/singleSignOn/docs/introduction.md +3 -0
- package/src/singleSignOn/get.js +70 -0
- package/src/singleSignOn/index.js +10 -0
- package/src/staticResource/count.js +1 -1
- package/src/staticResource/create.js +1 -1
- package/src/staticResource/delete.js +1 -1
- package/src/staticResource/detail.js +1 -1
- package/src/staticResource/docs/devguide.md +11 -11
- package/src/staticResource/docs/introduction.md +44 -1
- package/src/staticResource/get.js +1 -1
- package/src/timer/create.js +1 -1
- package/src/timer/delete.js +1 -1
- package/src/timer/detail.js +1 -1
- package/src/timer/doc.js +2 -2
- package/src/timer/docs/devguide.md +19 -19
- package/src/timer/get.js +1 -1
- package/src/timer/publish.js +1 -1
- package/src/timer/pull.js +1 -1
- package/src/timer/pullList.js +1 -1
- package/src/triggers/detail.js +1 -1
- package/src/triggers/doc.js +2 -2
- package/src/triggers/docs/devguide.md +23 -23
- package/src/triggers/get.js +1 -1
- package/src/triggers/pullList.js +1 -1
- package/src/user/create.js +2 -2
- package/src/user/delete.js +2 -2
- package/src/user/doc.js +2 -2
- package/src/user/docs/devguide.md +13 -13
- package/src/user/docs/introduction.md +12 -12
- package/src/user/get.js +1 -1
- package/src/user/update.js +3 -3
- package/src/user/view.js +2 -2
- package/src/validationRule/create.js +7 -7
- package/src/validationRule/delete.js +2 -2
- package/src/validationRule/doc.js +2 -2
- package/src/validationRule/docs/devguide.md +7 -7
- package/src/validationRule/docs/introduction.md +11 -11
- package/src/validationRule/get.js +1 -1
- package/src/version/actionHelp.js +25 -0
- package/src/version/docs.js +26 -0
- package/src/version/doctor.js +25 -0
- package/src/version/get.js +1 -1
- package/src/version/help.js +48 -0
- package/src/version/index.js +9 -2
- package/src/version/initHelp.js +13 -0
- package/src/version/listModuleCommands.js +241 -0
- package/src/version/stats.js +44 -0
- package/src/version/uninstall.js +30 -0
- package/src/version/update.js +13 -0
- package/test/application.cli.test.js +1 -1
- package/test/classes.cli.test.js +1 -1
- package/test/customSetting.cli.test.js +1 -1
- package/test/fields.cli.test.js +2 -2
- package/test/globalSelectList.cli.test.js +1 -1
- package/test/menu-script.cli.test.js +1 -1
- package/test/menu.cli.test.js +1 -1
- package/test/object.cli.test.js +1 -1
- package/test/plugin.cli.test.js +1 -1
- package/test/scheduleJob.cli.test.js +1 -1
- package/test/script.cli.test.js +1 -1
- package/test/staticResource.cli.test.js +1 -1
- package/test/timer.cli.test.js +1 -1
- package/test/trigger.cli.test.js +1 -1
- package/utils/checkVersion.js +27 -2
- package/utils/commandStats.js +94 -0
- package/utils/formatReleaseNotes.js +312 -0
- package/utils/readmeReleases.js +69 -0
- package/.cloudcc-cache.json +0 -54
- package/.cursor/skills/cloudcc-cli-dev.zip +0 -0
- package/.cursor/skills/cloudcc-dev-usage/SKILL.md +0 -68
- package/build/component-cc-cc-dd.common.js +0 -831
- package/build/component-cc-cc-dd.common.js.map +0 -1
- package/build/component-cc-cc-dd.css +0 -1
- package/build/component-cc-cc-dd.umd.js +0 -874
- package/build/component-cc-cc-dd.umd.js.map +0 -1
- package/build/component-cc-cc-dd.umd.min.js +0 -8
- package/build/component-cc-cc-dd.umd.min.js.map +0 -1
- package/build/demo.html +0 -1
- package/plugins/cc-cc-dd/cc-cc-dd.vue +0 -32
- package/plugins/cc-cc-dd/components/HelloWorld.vue +0 -11
- package/plugins/cc-cc-dd/config.json +0 -6
package/test/fields.cli.test.js
CHANGED
|
@@ -12,7 +12,7 @@ function quoteArg(value) {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
async function runCc(args) {
|
|
15
|
-
const cmd = `npx --prefix "${repoRoot}"
|
|
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 调用约定:
|
|
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}"
|
|
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}"
|
|
15
|
+
const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
|
|
16
16
|
return execAsync(cmd, { cwd: repoRoot });
|
|
17
17
|
}
|
|
18
18
|
|
package/test/menu.cli.test.js
CHANGED
|
@@ -12,7 +12,7 @@ function quoteArg(value) {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
async function runCc(args) {
|
|
15
|
-
const cmd = `npx --prefix "${repoRoot}"
|
|
15
|
+
const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
|
|
16
16
|
return execAsync(cmd, { cwd: repoRoot });
|
|
17
17
|
}
|
|
18
18
|
|
package/test/object.cli.test.js
CHANGED
|
@@ -12,7 +12,7 @@ function quoteArg(value) {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
async function runCc(args) {
|
|
15
|
-
const cmd = `npx --prefix "${repoRoot}"
|
|
15
|
+
const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
|
|
16
16
|
return execAsync(cmd, { cwd: repoRoot });
|
|
17
17
|
}
|
|
18
18
|
|
package/test/plugin.cli.test.js
CHANGED
|
@@ -14,7 +14,7 @@ function quoteArg(value) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
async function runCc(args) {
|
|
17
|
-
const cmd = `npx --prefix "${repoRoot}"
|
|
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}"
|
|
15
|
+
const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
|
|
16
16
|
return execAsync(cmd, { cwd: repoRoot });
|
|
17
17
|
}
|
|
18
18
|
|
package/test/script.cli.test.js
CHANGED
|
@@ -14,7 +14,7 @@ function quoteArg(value) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
async function runCc(args) {
|
|
17
|
-
const cmd = `npx --prefix "${repoRoot}"
|
|
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}"
|
|
15
|
+
const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
|
|
16
16
|
return execAsync(cmd, { cwd: repoRoot });
|
|
17
17
|
}
|
|
18
18
|
|
package/test/timer.cli.test.js
CHANGED
|
@@ -14,7 +14,7 @@ function quoteArg(value) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
async function runCc(args) {
|
|
17
|
-
const cmd = `npx --prefix "${repoRoot}"
|
|
17
|
+
const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
|
|
18
18
|
return execAsync(cmd, { cwd: repoRoot });
|
|
19
19
|
}
|
|
20
20
|
|
package/test/trigger.cli.test.js
CHANGED
|
@@ -14,7 +14,7 @@ function quoteArg(value) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
async function runCc(args) {
|
|
17
|
-
const cmd = `npx --prefix "${repoRoot}"
|
|
17
|
+
const cmd = `npx --prefix "${repoRoot}" cloudcc ${args.map(quoteArg).join(" ")}`;
|
|
18
18
|
return execAsync(cmd, { cwd: repoRoot });
|
|
19
19
|
}
|
|
20
20
|
|
package/utils/checkVersion.js
CHANGED
|
@@ -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('
|
|
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
|
+
}
|