listpage_cli 0.0.293 → 0.0.295
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/bin/adapters/cli-interaction.js +172 -0
- package/bin/adapters/node-fs-adapter.js +109 -0
- package/bin/app/dispatch.js +15 -0
- package/bin/app/execute.js +33 -0
- package/bin/app/parse-args.js +39 -0
- package/bin/cli.js +61 -75
- package/bin/commands/build-project-command.js +9 -0
- package/bin/commands/deploy-project-command.js +9 -0
- package/bin/commands/init-command.js +9 -0
- package/bin/commands/install-skill-command.js +9 -0
- package/bin/copy.js +14 -126
- package/bin/domain/command-result.js +34 -0
- package/bin/domain/interaction-result.js +14 -0
- package/bin/domain/package-name.js +12 -0
- package/bin/ports/build-project-command.js +2 -0
- package/bin/ports/deploy-project-command.js +2 -0
- package/bin/ports/filesystem-capability.js +2 -0
- package/bin/ports/fs-port.js +22 -0
- package/bin/ports/init-command.js +2 -0
- package/bin/ports/install-skill-command.js +2 -0
- package/bin/prompts.js +105 -16
- package/bin/services/artifact-validator.js +47 -0
- package/bin/services/build-project-service.js +190 -0
- package/bin/services/command-runner.js +45 -0
- package/bin/services/config-loader.js +113 -0
- package/bin/services/deploy-project-service.js +237 -0
- package/bin/services/filesystem-capability-service.js +137 -0
- package/bin/services/init-service.js +64 -0
- package/bin/services/install-skill-service.js +34 -0
- package/bin/shared/json-with-comments.js +9 -0
- package/package.json +6 -4
- package/templates/backend-template/package.json.tmpl +1 -1
- package/templates/frontend-template/package.json.tmpl +2 -2
- package/templates/package-app-template/package.json +1 -1
- package/templates/skills-template/listpage/examples.md +565 -0
- package/skills/listpage/examples.md +0 -243
- package/templates/rush-template/docs/ListPage-AI/347/224/237/346/210/220/350/247/204/350/214/203.md +0 -305
- /package/{skills → templates/skills-template}/listpage/SKILL.md +0 -0
- /package/{skills → templates/skills-template}/listpage/api.md +0 -0
package/bin/copy.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.copyRushTemplate = copyRushTemplate;
|
|
7
4
|
exports.updateRushJsonProjects = updateRushJsonProjects;
|
|
@@ -11,142 +8,33 @@ exports.copyDeployScriptTemplate = copyDeployScriptTemplate;
|
|
|
11
8
|
exports.ensureDir = ensureDir;
|
|
12
9
|
exports.isDirEmpty = isDirEmpty;
|
|
13
10
|
exports.copySkillDir = copySkillDir;
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
11
|
+
const node_fs_adapter_1 = require("./adapters/node-fs-adapter");
|
|
12
|
+
const filesystem_capability_service_1 = require("./services/filesystem-capability-service");
|
|
13
|
+
const fsAdapter = (0, node_fs_adapter_1.createNodeFsAdapter)();
|
|
14
|
+
const filesystemCapability = (0, filesystem_capability_service_1.createFilesystemCapabilityService)(fsAdapter, {
|
|
15
|
+
templateRootDir: fsAdapter.resolve(__dirname, "..", "templates"),
|
|
16
|
+
});
|
|
18
17
|
function copyRushTemplate(targetDir, vars) {
|
|
19
|
-
|
|
20
|
-
copyDir(source, targetDir, vars);
|
|
18
|
+
filesystemCapability.copyRushTemplate(targetDir, vars);
|
|
21
19
|
}
|
|
22
20
|
function updateRushJsonProjects(filepath, feAppName, beAppName) {
|
|
23
|
-
|
|
24
|
-
if (feAppName) {
|
|
25
|
-
projects.push({
|
|
26
|
-
packageName: (0, utils_1.composePkgName)(feAppName),
|
|
27
|
-
projectFolder: `apps/${feAppName}`,
|
|
28
|
-
reviewCategory: "production",
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
if (beAppName) {
|
|
32
|
-
const pkg = (0, utils_1.composePkgName)(beAppName);
|
|
33
|
-
projects.push({
|
|
34
|
-
packageName: pkg,
|
|
35
|
-
projectFolder: `servers/${beAppName}`,
|
|
36
|
-
reviewCategory: "production",
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
const content = (0, fs_1.readFileSync)(filepath, "utf8");
|
|
40
|
-
const json = (0, utils_1.readJsonWithComments)(content);
|
|
41
|
-
json.projects = projects;
|
|
42
|
-
(0, fs_1.writeFileSync)(filepath, JSON.stringify(json, null, 2), { encoding: "utf-8" });
|
|
21
|
+
filesystemCapability.updateRushJsonProjects(filepath, feAppName, beAppName);
|
|
43
22
|
}
|
|
44
23
|
function copyFrontendTemplate(targetDir, vars) {
|
|
45
|
-
|
|
46
|
-
targetDir = path_1.default.join(targetDir, `apps/${appName}`);
|
|
47
|
-
const source = getTemplateDir("frontend");
|
|
48
|
-
copyDir(source, targetDir, vars);
|
|
24
|
+
filesystemCapability.copyFrontendTemplate(targetDir, vars);
|
|
49
25
|
}
|
|
50
26
|
function copyBackendTemplate(targetDir, vars) {
|
|
51
|
-
|
|
52
|
-
targetDir = path_1.default.join(targetDir, `servers/${appName}`);
|
|
53
|
-
const source = getTemplateDir("backend");
|
|
54
|
-
copyDir(source, targetDir, vars);
|
|
27
|
+
filesystemCapability.copyBackendTemplate(targetDir, vars);
|
|
55
28
|
}
|
|
56
29
|
function copyDeployScriptTemplate(targetDir, vars) {
|
|
57
|
-
|
|
58
|
-
const source = getTemplateDir("package-app");
|
|
59
|
-
copyDir(source, targetDir, vars);
|
|
60
|
-
}
|
|
61
|
-
function getTemplateDir(type) {
|
|
62
|
-
return path_1.default.join(__dirname, "..", "templates", `${type}-template`);
|
|
63
|
-
}
|
|
64
|
-
function copyDir(source, destination, vars) {
|
|
65
|
-
ensureDir(destination);
|
|
66
|
-
const files = (0, fs_1.readdirSync)(source);
|
|
67
|
-
files.forEach((file) => {
|
|
68
|
-
const s = path_1.default.join(source, file);
|
|
69
|
-
const d = path_1.default.join(destination, file);
|
|
70
|
-
const stat = (0, fs_1.statSync)(s);
|
|
71
|
-
if (stat.isDirectory()) {
|
|
72
|
-
copyDir(s, d, vars);
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
ensureDir(path_1.default.dirname(d));
|
|
76
|
-
const isTmpl = file.endsWith(".tmpl");
|
|
77
|
-
// 正常文件直接复制
|
|
78
|
-
if (!isTmpl) {
|
|
79
|
-
(0, fs_1.copyFileSync)(s, d);
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
// 模板文件替换变量后复制
|
|
83
|
-
const template = (0, fs_1.readFileSync)(s, "utf8");
|
|
84
|
-
const content = compileTemplateContent(template, vars);
|
|
85
|
-
(0, fs_1.writeFileSync)(d.slice(0, -5), content, { encoding: "utf-8" });
|
|
86
|
-
}
|
|
87
|
-
});
|
|
30
|
+
filesystemCapability.copyDeployScriptTemplate(targetDir, vars);
|
|
88
31
|
}
|
|
89
32
|
function ensureDir(dir) {
|
|
90
|
-
|
|
91
|
-
(0, fs_1.mkdirSync)(dir, { recursive: true });
|
|
92
|
-
}
|
|
93
|
-
function compileTemplateContent(str, vars) {
|
|
94
|
-
let out = str;
|
|
95
|
-
for (const [k, v] of Object.entries(vars)) {
|
|
96
|
-
const re = new RegExp(`__${k}__`, "g");
|
|
97
|
-
out = out.replace(re, v);
|
|
98
|
-
}
|
|
99
|
-
return out;
|
|
33
|
+
fsAdapter.ensureDir(dir);
|
|
100
34
|
}
|
|
101
35
|
function isDirEmpty(dir) {
|
|
102
|
-
return
|
|
36
|
+
return filesystemCapability.isDirEmpty(dir);
|
|
103
37
|
}
|
|
104
38
|
function copySkillDir(sourceDir, targetDir) {
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
function syncDirWithRename(source, destination) {
|
|
108
|
-
ensureDir(destination);
|
|
109
|
-
const items = (0, fs_1.readdirSync)(source);
|
|
110
|
-
items.forEach((name) => {
|
|
111
|
-
const s = path_1.default.join(source, name);
|
|
112
|
-
const d = path_1.default.join(destination, name);
|
|
113
|
-
const sStat = (0, fs_1.statSync)(s);
|
|
114
|
-
if (sStat.isDirectory()) {
|
|
115
|
-
if ((0, fs_1.existsSync)(d)) {
|
|
116
|
-
const dStat = (0, fs_1.statSync)(d);
|
|
117
|
-
if (!dStat.isDirectory()) {
|
|
118
|
-
const copyPath = getCopyPath(d);
|
|
119
|
-
(0, fs_1.renameSync)(d, copyPath);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
ensureDir(d);
|
|
123
|
-
syncDirWithRename(s, d);
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
ensureDir(path_1.default.dirname(d));
|
|
127
|
-
if ((0, fs_1.existsSync)(d)) {
|
|
128
|
-
const dStat = (0, fs_1.statSync)(d);
|
|
129
|
-
if (dStat.isFile()) {
|
|
130
|
-
const copyPath = getCopyPath(d);
|
|
131
|
-
(0, fs_1.renameSync)(d, copyPath);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
(0, fs_1.copyFileSync)(s, d);
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
function getCopyPath(filePath) {
|
|
139
|
-
const dir = path_1.default.dirname(filePath);
|
|
140
|
-
const ext = path_1.default.extname(filePath);
|
|
141
|
-
const base = path_1.default.basename(filePath, ext);
|
|
142
|
-
let candidate = path_1.default.join(dir, `${base} copy${ext}`);
|
|
143
|
-
if (!(0, fs_1.existsSync)(candidate))
|
|
144
|
-
return candidate;
|
|
145
|
-
let i = 2;
|
|
146
|
-
while (true) {
|
|
147
|
-
candidate = path_1.default.join(dir, `${base} copy (${i})${ext}`);
|
|
148
|
-
if (!(0, fs_1.existsSync)(candidate))
|
|
149
|
-
return candidate;
|
|
150
|
-
i++;
|
|
151
|
-
}
|
|
39
|
+
filesystemCapability.copySkillDir(sourceDir, targetDir);
|
|
152
40
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.COMMAND_ERROR_CODES = void 0;
|
|
4
|
+
exports.commandOk = commandOk;
|
|
5
|
+
exports.commandError = commandError;
|
|
6
|
+
exports.isCommandResult = isCommandResult;
|
|
7
|
+
exports.COMMAND_ERROR_CODES = {
|
|
8
|
+
unknownCommand: "E_UNKNOWN_COMMAND",
|
|
9
|
+
handlerNotFound: "E_HANDLER_NOT_FOUND",
|
|
10
|
+
invalidCommandResult: "E_INVALID_COMMAND_RESULT",
|
|
11
|
+
userCancelled: "E_USER_CANCELLED",
|
|
12
|
+
invalidInteraction: "E_INVALID_INTERACTION",
|
|
13
|
+
unexpectedError: "E_UNEXPECTED_ERROR",
|
|
14
|
+
skillNotFound: "E_SKILL_NOT_FOUND",
|
|
15
|
+
invalidPath: "E_INVALID_PATH",
|
|
16
|
+
fsOperationFailed: "E_FS_OPERATION_FAILED",
|
|
17
|
+
executionFailed: "E_EXECUTION_FAILED",
|
|
18
|
+
};
|
|
19
|
+
function commandOk(message) {
|
|
20
|
+
return { ok: true, exitCode: 0, message };
|
|
21
|
+
}
|
|
22
|
+
function commandError(message, errorCode, exitCode = 1) {
|
|
23
|
+
return { ok: false, exitCode, message, errorCode };
|
|
24
|
+
}
|
|
25
|
+
function isCommandResult(value) {
|
|
26
|
+
if (!value || typeof value !== "object") {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
const candidate = value;
|
|
30
|
+
return (typeof candidate.ok === "boolean" &&
|
|
31
|
+
typeof candidate.exitCode === "number" &&
|
|
32
|
+
(candidate.message === undefined || typeof candidate.message === "string") &&
|
|
33
|
+
(candidate.errorCode === undefined || typeof candidate.errorCode === "string"));
|
|
34
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.interactionValue = interactionValue;
|
|
4
|
+
exports.interactionCancelled = interactionCancelled;
|
|
5
|
+
exports.interactionInvalid = interactionInvalid;
|
|
6
|
+
function interactionValue(value) {
|
|
7
|
+
return { status: "value", value };
|
|
8
|
+
}
|
|
9
|
+
function interactionCancelled() {
|
|
10
|
+
return { status: "cancelled" };
|
|
11
|
+
}
|
|
12
|
+
function interactionInvalid(reason) {
|
|
13
|
+
return { status: "invalid", reason };
|
|
14
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.composePkgName = composePkgName;
|
|
4
|
+
function composePkgName(name) {
|
|
5
|
+
return safePkgName(name);
|
|
6
|
+
}
|
|
7
|
+
function safePkgName(name) {
|
|
8
|
+
return name
|
|
9
|
+
.toLowerCase()
|
|
10
|
+
.replace(/\s+/g, "-")
|
|
11
|
+
.replace(/[^a-z0-9-_.]/g, "-");
|
|
12
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FsPortError = exports.FS_PORT_ERROR_CODES = void 0;
|
|
4
|
+
exports.FS_PORT_ERROR_CODES = {
|
|
5
|
+
invalidPath: "E_INVALID_PATH",
|
|
6
|
+
permissionDenied: "E_FS_PERMISSION_DENIED",
|
|
7
|
+
notFound: "E_FS_NOT_FOUND",
|
|
8
|
+
operationFailed: "E_FS_OPERATION_FAILED",
|
|
9
|
+
};
|
|
10
|
+
class FsPortError extends Error {
|
|
11
|
+
constructor(code, operation, targetPath, message, cause) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "FsPortError";
|
|
14
|
+
this.code = code;
|
|
15
|
+
this.operation = operation;
|
|
16
|
+
this.targetPath = targetPath;
|
|
17
|
+
if (cause !== undefined) {
|
|
18
|
+
this.cause = cause;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.FsPortError = FsPortError;
|
package/bin/prompts.js
CHANGED
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runPrompt = runPrompt;
|
|
6
7
|
exports.askRushQuestions = askRushQuestions;
|
|
7
8
|
exports.askProjectPath = askProjectPath;
|
|
8
9
|
exports.askOverwrite = askOverwrite;
|
|
@@ -12,60 +13,148 @@ exports.printVersion = printVersion;
|
|
|
12
13
|
const enquirer_1 = require("enquirer");
|
|
13
14
|
const fs_1 = require("fs");
|
|
14
15
|
const path_1 = __importDefault(require("path"));
|
|
16
|
+
const interaction_result_1 = require("./domain/interaction-result");
|
|
17
|
+
let promptTestScript = null;
|
|
18
|
+
let promptTestScriptIndex = 0;
|
|
19
|
+
function getTestPromptMode() {
|
|
20
|
+
const mode = process.env.LISTPAGE_CLI_PROMPT_TEST_MODE;
|
|
21
|
+
if (mode === "cancel" || mode === "invalid") {
|
|
22
|
+
return mode;
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
function getNextScriptedPromptResult() {
|
|
27
|
+
if (promptTestScript === null) {
|
|
28
|
+
const raw = process.env.LISTPAGE_CLI_PROMPT_TEST_SCRIPT;
|
|
29
|
+
if (!raw) {
|
|
30
|
+
promptTestScript = [];
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const parsed = JSON.parse(raw);
|
|
35
|
+
if (Array.isArray(parsed)) {
|
|
36
|
+
promptTestScript = parsed;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
promptTestScript = [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
promptTestScript = [];
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const next = promptTestScript[promptTestScriptIndex];
|
|
47
|
+
promptTestScriptIndex += 1;
|
|
48
|
+
return next;
|
|
49
|
+
}
|
|
50
|
+
function isCancelError(error) {
|
|
51
|
+
if (!(error instanceof Error)) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const normalized = error.message.toLowerCase();
|
|
55
|
+
return (normalized.includes("cancel") ||
|
|
56
|
+
normalized.includes("aborted") ||
|
|
57
|
+
normalized.includes("interrupted"));
|
|
58
|
+
}
|
|
59
|
+
async function runPrompt(options, runner = enquirer_1.prompt) {
|
|
60
|
+
const testMode = getTestPromptMode();
|
|
61
|
+
if (testMode === "cancel") {
|
|
62
|
+
return (0, interaction_result_1.interactionCancelled)();
|
|
63
|
+
}
|
|
64
|
+
if (testMode === "invalid") {
|
|
65
|
+
return (0, interaction_result_1.interactionInvalid)("测试模式: 模拟无效输入");
|
|
66
|
+
}
|
|
67
|
+
const scripted = getNextScriptedPromptResult();
|
|
68
|
+
if (scripted !== undefined) {
|
|
69
|
+
if (scripted === "cancel") {
|
|
70
|
+
return (0, interaction_result_1.interactionCancelled)();
|
|
71
|
+
}
|
|
72
|
+
if (scripted === "invalid") {
|
|
73
|
+
return (0, interaction_result_1.interactionInvalid)("测试脚本: 模拟无效输入");
|
|
74
|
+
}
|
|
75
|
+
return (0, interaction_result_1.interactionValue)(scripted);
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const value = (await runner(options));
|
|
79
|
+
return (0, interaction_result_1.interactionValue)(value);
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (isCancelError(error)) {
|
|
83
|
+
return (0, interaction_result_1.interactionCancelled)();
|
|
84
|
+
}
|
|
85
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
86
|
+
return (0, interaction_result_1.interactionInvalid)(reason);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
15
89
|
async function askRushQuestions() {
|
|
16
|
-
const
|
|
90
|
+
const frontend = await runPrompt({
|
|
17
91
|
type: "input",
|
|
18
92
|
name: "name",
|
|
19
93
|
message: "请输入前端项目名称,为空表示不创建前端项目",
|
|
20
94
|
initial: "",
|
|
21
95
|
});
|
|
22
|
-
|
|
96
|
+
if (frontend.status !== "value") {
|
|
97
|
+
return frontend;
|
|
98
|
+
}
|
|
99
|
+
const backend = await runPrompt({
|
|
23
100
|
type: "input",
|
|
24
101
|
name: "name",
|
|
25
102
|
message: "请输入后端项目名称,为空表示不创建后端项目",
|
|
26
103
|
initial: "",
|
|
27
104
|
});
|
|
28
|
-
|
|
105
|
+
if (backend.status !== "value") {
|
|
106
|
+
return backend;
|
|
107
|
+
}
|
|
108
|
+
return (0, interaction_result_1.interactionValue)({
|
|
109
|
+
frontendName: frontend.value.name,
|
|
110
|
+
backendName: backend.value.name,
|
|
111
|
+
});
|
|
29
112
|
}
|
|
30
113
|
async function askProjectPath() {
|
|
31
|
-
const
|
|
114
|
+
const result = await runPrompt({
|
|
32
115
|
type: "input",
|
|
33
116
|
name: "path",
|
|
34
117
|
message: "请填写项目名称或路径,如果填.表示直接把项目放到当前目录下",
|
|
35
118
|
initial: ".",
|
|
36
119
|
});
|
|
37
|
-
|
|
38
|
-
|
|
120
|
+
if (result.status !== "value") {
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
const p = (result.value.path || ".").trim();
|
|
124
|
+
return (0, interaction_result_1.interactionValue)(p || ".");
|
|
39
125
|
}
|
|
40
126
|
async function askOverwrite() {
|
|
41
|
-
const
|
|
127
|
+
const result = await runPrompt({
|
|
42
128
|
type: "confirm",
|
|
43
129
|
name: "ok",
|
|
44
130
|
message: "目标目录非空,是否覆盖?",
|
|
45
131
|
initial: false,
|
|
46
132
|
});
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
process.exit(1);
|
|
133
|
+
if (result.status !== "value") {
|
|
134
|
+
return result;
|
|
50
135
|
}
|
|
136
|
+
return (0, interaction_result_1.interactionValue)(result.value.ok);
|
|
51
137
|
}
|
|
52
138
|
async function askInstallDeployScript() {
|
|
53
|
-
const
|
|
139
|
+
const result = await runPrompt({
|
|
54
140
|
type: "confirm",
|
|
55
141
|
name: "ok",
|
|
56
142
|
message: "是否添加部署脚本?这个脚本允许你可以帮你快速构建docker镜像,并发布到阿里云等环境,但是需要本机有docker环境。",
|
|
57
143
|
initial: false,
|
|
58
144
|
});
|
|
59
|
-
|
|
145
|
+
if (result.status !== "value") {
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
return (0, interaction_result_1.interactionValue)(result.value.ok);
|
|
60
149
|
}
|
|
61
150
|
function printHelp() {
|
|
62
151
|
const h = [
|
|
63
152
|
"用法: listpage_cli init",
|
|
64
153
|
"说明: 进入中文引导式交互,按提示填写即可",
|
|
65
|
-
"用法: listpage_cli
|
|
66
|
-
"说明:
|
|
67
|
-
"用法: listpage_cli
|
|
68
|
-
"说明:
|
|
154
|
+
"用法: listpage_cli install-skill [skillName] [--project]",
|
|
155
|
+
"说明: 安装技能到 Cursor。默认 skillName 为 test,安装到当前命令执行目录的 .cursor/skills/",
|
|
156
|
+
"用法: listpage_cli build-project",
|
|
157
|
+
"说明: 非交互校验当前目录是否为有效项目根(需存在 listpage.config.json)",
|
|
69
158
|
].join("\n");
|
|
70
159
|
console.log(h);
|
|
71
160
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createArtifactValidator = createArtifactValidator;
|
|
4
|
+
const ARTIFACT_STAGE = "artifact";
|
|
5
|
+
function createArtifactValidator(fs) {
|
|
6
|
+
return (expectation) => {
|
|
7
|
+
const issues = [];
|
|
8
|
+
if (!fs.exists(expectation.outputDir)) {
|
|
9
|
+
issues.push({
|
|
10
|
+
stage: ARTIFACT_STAGE,
|
|
11
|
+
message: `[${ARTIFACT_STAGE}] 构建产物目录不存在: ${expectation.outputDir}`,
|
|
12
|
+
});
|
|
13
|
+
return { ok: false, issues };
|
|
14
|
+
}
|
|
15
|
+
if (!fs.isDirectory(expectation.outputDir)) {
|
|
16
|
+
issues.push({
|
|
17
|
+
stage: ARTIFACT_STAGE,
|
|
18
|
+
message: `[${ARTIFACT_STAGE}] 构建产物路径不是目录: ${expectation.outputDir}`,
|
|
19
|
+
});
|
|
20
|
+
return { ok: false, issues };
|
|
21
|
+
}
|
|
22
|
+
const rootEntries = fs.readDir(expectation.outputDir);
|
|
23
|
+
if (rootEntries.length === 0) {
|
|
24
|
+
issues.push({
|
|
25
|
+
stage: ARTIFACT_STAGE,
|
|
26
|
+
message: `[${ARTIFACT_STAGE}] 构建产物目录为空: ${expectation.outputDir}`,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
for (const relativePath of expectation.requiredRelativePaths) {
|
|
30
|
+
const normalized = relativePath.trim();
|
|
31
|
+
if (!normalized) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const absolutePath = fs.resolve(expectation.outputDir, normalized);
|
|
35
|
+
if (!fs.exists(absolutePath)) {
|
|
36
|
+
issues.push({
|
|
37
|
+
stage: ARTIFACT_STAGE,
|
|
38
|
+
message: `[${ARTIFACT_STAGE}] 缺少必需产物: ${normalized} (base=${expectation.outputDir})`,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
ok: issues.length === 0,
|
|
44
|
+
issues,
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
}
|