listpage_cli 0.0.295 → 0.0.297

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 (30) hide show
  1. package/bin/adapters/cli-interaction.js +4 -15
  2. package/bin/adapters/dockerode-client.js +295 -0
  3. package/bin/app/parse-args.js +86 -0
  4. package/bin/cli.js +5 -1
  5. package/bin/commands/deploy-project-command.js +17 -2
  6. package/bin/commands/release-project-command.js +24 -0
  7. package/bin/ports/release-project-command.js +2 -0
  8. package/bin/services/{artifact-validator.js → build-artifact-validator.js} +2 -2
  9. package/bin/services/config-loader.js +11 -3
  10. package/bin/services/config-value-utils.js +44 -0
  11. package/bin/services/deploy-project-service.js +303 -150
  12. package/bin/services/filesystem-capability-service.js +0 -5
  13. package/bin/services/init-service.js +0 -7
  14. package/bin/services/release-project-service.js +239 -0
  15. package/bin/types/deploy-config.js +2 -0
  16. package/package.json +6 -4
  17. package/templates/backend-template/package.json.tmpl +1 -1
  18. package/templates/backend-template/tsconfig.build.json +12 -2
  19. package/templates/frontend-template/package.json.tmpl +2 -2
  20. package/templates/rush-template/listpage.config.json.tmpl +89 -0
  21. package/bin/copy.js +0 -40
  22. package/bin/prompts.js +0 -170
  23. package/templates/package-app-template/.gitignore.tmpl +0 -28
  24. package/templates/package-app-template/README.md +0 -33
  25. package/templates/package-app-template/package.json +0 -27
  26. package/templates/package-app-template/src/build.ts +0 -6
  27. package/templates/package-app-template/src/config.ts.tmpl +0 -45
  28. package/templates/package-app-template/src/package.ts +0 -5
  29. package/templates/package-app-template/src/publish.ts +0 -6
  30. package/templates/package-app-template/tsconfig.json +0 -25
@@ -0,0 +1,239 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runReleaseProjectFlow = runReleaseProjectFlow;
4
+ const command_result_1 = require("../domain/command-result");
5
+ const config_loader_1 = require("./config-loader");
6
+ const command_runner_1 = require("./command-runner");
7
+ const build_artifact_validator_1 = require("./build-artifact-validator");
8
+ const config_value_utils_1 = require("./config-value-utils");
9
+ const RELEASE_STAGE = "release";
10
+ const CONFIG_ERROR_CODE_MAP = {
11
+ CONFIG_NOT_FOUND: "E_CONFIG_NOT_FOUND",
12
+ CONFIG_READ_FAILED: "E_CONFIG_READ_FAILED",
13
+ CONFIG_INVALID_JSON: "E_CONFIG_INVALID_JSON",
14
+ CONFIG_REQUIRED_FIELD_MISSING: "E_CONFIG_REQUIRED_FIELD_MISSING",
15
+ };
16
+ async function runReleaseProjectFlow(deps) {
17
+ const projectRoot = deps.fs.cwd();
18
+ const configPath = (0, config_loader_1.getDefaultConfigPath)(projectRoot, deps.fs.join);
19
+ let configResult;
20
+ try {
21
+ configResult = (0, config_loader_1.loadProjectConfig)({
22
+ readText: deps.fs.readText,
23
+ }, configPath);
24
+ }
25
+ catch (error) {
26
+ if (error instanceof config_loader_1.ConfigLoaderError) {
27
+ return (0, command_result_1.commandError)(error.message, CONFIG_ERROR_CODE_MAP[error.code], 1);
28
+ }
29
+ const message = error instanceof Error ? error.message : String(error);
30
+ return (0, command_result_1.commandError)(message, command_result_1.COMMAND_ERROR_CODES.invalidPath, 1);
31
+ }
32
+ let executionInput;
33
+ try {
34
+ executionInput = parseReleaseInput(projectRoot, configResult.config, deps.fs.resolve, deps.cliOverrides);
35
+ }
36
+ catch (error) {
37
+ const message = error instanceof Error ? error.message : String(error);
38
+ return (0, command_result_1.commandError)(`[${RELEASE_STAGE}] 发布配置无效: ${message}`, "E_CONFIG_REQUIRED_FIELD_MISSING", 1);
39
+ }
40
+ const validator = (0, build_artifact_validator_1.createBuildArtifactValidator)({
41
+ resolve: deps.fs.resolve,
42
+ exists: deps.fs.exists,
43
+ isDirectory: deps.fs.isDirectory,
44
+ readDir: deps.fs.readDir,
45
+ });
46
+ const validationResult = validator({
47
+ outputDir: executionInput.outputDir,
48
+ requiredRelativePaths: collectRequiredArtifacts(configResult.config),
49
+ });
50
+ if (!validationResult.ok) {
51
+ const message = validationResult.issues.map((issue) => issue.message).join("; ");
52
+ return (0, command_result_1.commandError)(message, command_result_1.COMMAND_ERROR_CODES.executionFailed, 1);
53
+ }
54
+ if (deps.executeRelease) {
55
+ try {
56
+ const result = await deps.executeRelease({
57
+ projectRoot,
58
+ configPath: configResult.configPath,
59
+ config: configResult.config,
60
+ outputDir: executionInput.outputDir,
61
+ remoteImage: executionInput.remoteImage,
62
+ docker: executionInput.docker,
63
+ });
64
+ return normalizeReleaseResult(result);
65
+ }
66
+ catch (error) {
67
+ return (0, command_result_1.commandError)(formatReleaseThrownError(error), command_result_1.COMMAND_ERROR_CODES.executionFailed, getNonZeroExitCode(error));
68
+ }
69
+ }
70
+ const commandRunner = deps.createRunner
71
+ ? deps.createRunner()
72
+ : (0, command_runner_1.createCommandRunner)({ stage: RELEASE_STAGE });
73
+ return runDockerRelease(commandRunner, executionInput);
74
+ }
75
+ function parseReleaseInput(projectRoot, config, resolve, cliOverrides) {
76
+ const typedConfig = config;
77
+ const dockerRaw = (0, config_value_utils_1.asObject)(typedConfig.docker, "docker");
78
+ const registry = (0, config_value_utils_1.asObject)(dockerRaw.registry, "docker.registry");
79
+ const build = ((0, config_value_utils_1.asOptionalObject)(dockerRaw.build) ?? {});
80
+ const releaseProfiles = ((0, config_value_utils_1.asOptionalObject)(dockerRaw.releaseProfiles) ??
81
+ {});
82
+ const profile = cliOverrides?.profile?.trim() || "dev";
83
+ const profileConfig = (0, config_value_utils_1.asOptionalObject)(releaseProfiles[profile]);
84
+ const imageName = (0, config_value_utils_1.asRequiredString)(dockerRaw.imageName ?? dockerRaw.appName, "docker.imageName/appName");
85
+ const imageTag = resolveImageTag(cliOverrides?.tag, (0, config_value_utils_1.asOptionalString)(profileConfig?.tag), (0, config_value_utils_1.asOptionalString)(dockerRaw.imageTag));
86
+ const registryUrl = (0, config_value_utils_1.asRequiredString)(registry.url, "docker.registry.url");
87
+ const registryNamespace = (0, config_value_utils_1.asOptionalString)(registry.namespace);
88
+ const username = (0, config_value_utils_1.asRequiredString)(registry.username, "docker.registry.username");
89
+ const password = (0, config_value_utils_1.asOptionalString)(registry.password);
90
+ const profileBuild = ((0, config_value_utils_1.asOptionalObject)(profileConfig?.buildOverrides) ??
91
+ {});
92
+ const platform = cliOverrides?.platform ??
93
+ (0, config_value_utils_1.asOptionalString)(profileBuild.platform) ??
94
+ (0, config_value_utils_1.asOptionalString)(build.platform);
95
+ const outputDir = resolve(projectRoot, ".listpage", "output");
96
+ const repositoryPath = registryNamespace && registryNamespace !== ""
97
+ ? `${registryNamespace}/${imageName}`
98
+ : imageName;
99
+ return {
100
+ outputDir,
101
+ remoteImage: `${registryUrl}/${repositoryPath}:${imageTag}`,
102
+ docker: {
103
+ imageName,
104
+ imageTag,
105
+ registryUrl,
106
+ registryNamespace,
107
+ username,
108
+ password,
109
+ platform,
110
+ },
111
+ };
112
+ }
113
+ function resolveImageTag(cliTag, profileTag, fallbackTag) {
114
+ const normalizedCli = cliTag?.trim();
115
+ if (normalizedCli) {
116
+ return normalizedCli;
117
+ }
118
+ if (profileTag && profileTag.trim() !== "") {
119
+ return profileTag;
120
+ }
121
+ if (fallbackTag && fallbackTag.trim() !== "") {
122
+ return fallbackTag;
123
+ }
124
+ throw new Error("缺少字段: docker.releaseProfiles.<profile>.tag");
125
+ }
126
+ function collectRequiredArtifacts(config) {
127
+ const required = new Set(["Dockerfile"]);
128
+ const artifacts = (0, config_value_utils_1.asOptionalObject)(config.artifacts);
129
+ const frontend = artifacts?.frontend ?? config.frontend;
130
+ if (Array.isArray(frontend)) {
131
+ for (const item of frontend) {
132
+ if (!item || typeof item !== "object" || Array.isArray(item)) {
133
+ continue;
134
+ }
135
+ const record = item;
136
+ const packageSubDir = (0, config_value_utils_1.asOptionalString)(record.packageSubDir) ?? "public";
137
+ const artifactAlias = (0, config_value_utils_1.asOptionalString)(record.artifactAlias) ?? "dist";
138
+ required.add(`${packageSubDir}/${artifactAlias}`);
139
+ }
140
+ }
141
+ const backendRaw = artifacts?.backend ?? config.backend;
142
+ if (backendRaw && typeof backendRaw === "object" && !Array.isArray(backendRaw)) {
143
+ const backend = backendRaw;
144
+ const packageSubDir = (0, config_value_utils_1.asOptionalString)(backend.packageSubDir) ?? "server";
145
+ const artifactAlias = (0, config_value_utils_1.asOptionalString)(backend.artifactAlias) ?? "dist";
146
+ required.add(`${packageSubDir}/${artifactAlias}`);
147
+ }
148
+ return [...required];
149
+ }
150
+ async function runDockerRelease(runner, input) {
151
+ const { docker } = input;
152
+ const localImage = `${docker.imageName}:${docker.imageTag}`;
153
+ const loginArgs = docker.password
154
+ ? [
155
+ "login",
156
+ `--username=${docker.username}`,
157
+ `--password=${docker.password}`,
158
+ docker.registryUrl,
159
+ ]
160
+ : [
161
+ "login",
162
+ `--username=${docker.username}`,
163
+ "--password-stdin",
164
+ docker.registryUrl,
165
+ ];
166
+ const buildArgs = [
167
+ "buildx",
168
+ "build",
169
+ ...(docker.platform ? ["--platform", docker.platform] : []),
170
+ "-t",
171
+ localImage,
172
+ ".",
173
+ ];
174
+ const stageCommands = [
175
+ { stage: "login", args: loginArgs, cwd: input.outputDir },
176
+ { stage: "build", args: buildArgs, cwd: input.outputDir },
177
+ {
178
+ stage: "tag",
179
+ args: ["tag", localImage, input.remoteImage],
180
+ cwd: input.outputDir,
181
+ },
182
+ {
183
+ stage: "push",
184
+ args: ["push", input.remoteImage],
185
+ cwd: input.outputDir,
186
+ },
187
+ ];
188
+ try {
189
+ for (const command of stageCommands) {
190
+ const result = await runner({
191
+ command: "docker",
192
+ args: command.args,
193
+ cwd: command.cwd,
194
+ });
195
+ if (result.exitCode !== 0) {
196
+ return (0, command_result_1.commandError)(`[${RELEASE_STAGE}][${command.stage}] Docker 命令执行失败: docker ${command.args.join(" ")} (exit=${result.exitCode})`, command_result_1.COMMAND_ERROR_CODES.executionFailed, result.exitCode);
197
+ }
198
+ }
199
+ }
200
+ catch (error) {
201
+ if (error instanceof command_runner_1.ExecutionError) {
202
+ return (0, command_result_1.commandError)(`[${RELEASE_STAGE}] ${error.message}`, command_result_1.COMMAND_ERROR_CODES.executionFailed, error.exitCode);
203
+ }
204
+ const message = error instanceof Error ? error.message : String(error);
205
+ return (0, command_result_1.commandError)(`[${RELEASE_STAGE}] 发布命令执行异常: ${message}`, command_result_1.COMMAND_ERROR_CODES.executionFailed, 1);
206
+ }
207
+ return (0, command_result_1.commandOk)(`[${RELEASE_STAGE}] 发布完成: ${input.remoteImage}\n` +
208
+ `[${RELEASE_STAGE}] 运行示例: docker run -d -p 3000:3000 --name ${docker.imageName}-container ${input.remoteImage}`);
209
+ }
210
+ function normalizeReleaseResult(result) {
211
+ if (result.ok) {
212
+ if (result.exitCode === 0) {
213
+ return result;
214
+ }
215
+ return (0, command_result_1.commandError)(`[${RELEASE_STAGE}] 发布执行器返回成功但退出码非零 (exit=${result.exitCode})`, command_result_1.COMMAND_ERROR_CODES.executionFailed, result.exitCode);
216
+ }
217
+ if (result.exitCode !== 0) {
218
+ return result;
219
+ }
220
+ return (0, command_result_1.commandError)(result.message ??
221
+ `[${RELEASE_STAGE}] 发布执行器返回失败但退出码为 0`, result.errorCode ?? command_result_1.COMMAND_ERROR_CODES.executionFailed, 1);
222
+ }
223
+ function formatReleaseThrownError(error) {
224
+ const message = error instanceof Error ? error.message : String(error);
225
+ return `[${RELEASE_STAGE}] 发布执行异常: ${message}`;
226
+ }
227
+ function getNonZeroExitCode(error) {
228
+ if (!error || typeof error !== "object") {
229
+ return 1;
230
+ }
231
+ const candidate = error;
232
+ if (typeof candidate.exitCode === "number" && candidate.exitCode !== 0) {
233
+ return candidate.exitCode;
234
+ }
235
+ if (typeof candidate.status === "number" && candidate.status !== 0) {
236
+ return candidate.status;
237
+ }
238
+ return 1;
239
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "listpage_cli",
3
- "version": "0.0.295",
3
+ "version": "0.0.297",
4
4
  "private": false,
5
5
  "bin": {
6
6
  "listpage_cli": "bin/cli.js"
@@ -10,7 +10,7 @@
10
10
  "build:tests": "tsc -p tsconfig.tests.json",
11
11
  "test:unit": "npm run build:tests && node --test .tmp-tests/tests/unit/**/*.test.js",
12
12
  "test:integration": "npm run build && npm run build:tests && node --test .tmp-tests/tests/integration/**/*.test.js",
13
- "test:story-1-1": "npm run test:unit && npm run test:integration",
13
+ "test:integration:deploy-live": "npm run build && npm run build:tests && node --test .tmp-tests/tests/integration/deploy-project.live.integration.test.js",
14
14
  "prepublishOnly": "npm run build",
15
15
  "start": "node bin/cli.js init",
16
16
  "test": "node bin/cli.js --help"
@@ -20,10 +20,12 @@
20
20
  "templates"
21
21
  ],
22
22
  "devDependencies": {
23
- "typescript": "^5.6.2",
24
- "@types/node": "^22.8.6"
23
+ "@types/node": "^22.8.6",
24
+ "typescript": "^5.6.2"
25
25
  },
26
26
  "dependencies": {
27
+ "@types/dockerode": "^4.0.1",
28
+ "dockerode": "^4.0.9",
27
29
  "enquirer": "^2.4.1"
28
30
  }
29
31
  }
@@ -25,7 +25,7 @@
25
25
  "class-transformer": "^0.5.1",
26
26
  "class-validator": "~0.14.2",
27
27
  "rxjs": "^7.8.1",
28
- "listpage-next-nest": "~0.0.295"
28
+ "listpage-next-nest": "~0.0.297"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@nestjs/schematics": "^11.0.0",
@@ -1,4 +1,14 @@
1
1
  {
2
2
  "extends": "./tsconfig.json",
3
- "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4
- }
3
+ "compilerOptions": {
4
+ "rootDir": "src",
5
+ "incremental": false
6
+ },
7
+ "exclude": [
8
+ "node_modules",
9
+ "test",
10
+ "**/*spec.ts",
11
+ "prisma",
12
+ "prisma.config.ts"
13
+ ]
14
+ }
@@ -12,7 +12,7 @@
12
12
  "dependencies": {
13
13
  "react": "^19.2.0",
14
14
  "react-dom": "^19.2.0",
15
- "listpage-next": "~0.0.295",
15
+ "listpage-next": "~0.0.297",
16
16
  "react-router-dom": ">=6.0.0",
17
17
  "@ant-design/v5-patch-for-react-19": "~1.0.3",
18
18
  "ahooks": "^3.9.5",
@@ -23,7 +23,7 @@
23
23
  "styled-components": "^6.1.19",
24
24
  "mobx": "~6.15.0",
25
25
  "@ant-design/icons": "~6.0.2",
26
- "listpage-components": "~0.0.295",
26
+ "listpage-components": "~0.0.297",
27
27
  "lucide-react": "~0.575.0"
28
28
  "mobx-react-lite": "~4.1.1"
29
29
  },
@@ -0,0 +1,89 @@
1
+ {
2
+ "artifacts": {
3
+ "frontend": [
4
+ {
5
+ "projectDir": "apps/__FRONTEND_NAME__",
6
+ "packageSubDir": "public",
7
+ "buildArtifactDirName": "dist",
8
+ "artifactAlias": "__APP_NAME__"
9
+ }
10
+ ],
11
+ "backend": {
12
+ "projectDir": "servers/__BACKEND_NAME__",
13
+ "packageSubDir": ".",
14
+ "buildArtifactDirName": "dist",
15
+ "artifactAlias": "dist"
16
+ },
17
+ "copyFiles": [
18
+ {
19
+ "source": "servers/__BACKEND_NAME__/prisma",
20
+ "dest": "prisma"
21
+ },
22
+ {
23
+ "source": "servers/__BACKEND_NAME__/Dockerfile",
24
+ "dest": "Dockerfile"
25
+ },
26
+ {
27
+ "source": "servers/__BACKEND_NAME__/package.json",
28
+ "dest": "package.json"
29
+ }
30
+ ]
31
+ },
32
+ "docker": {
33
+ "imageName": "__APP_NAME__",
34
+ "registry": {
35
+ "url": "registry.cn-hangzhou.aliyuncs.com",
36
+ "namespace": "",
37
+ "username": "",
38
+ "password": ""
39
+ },
40
+ "build": {
41
+ "platform": "linux/amd64"
42
+ },
43
+ "releaseProfiles": {
44
+ "dev": {
45
+ "tag": "0.0.1",
46
+ "envFile": "env/.dev"
47
+ },
48
+ "test": {
49
+ "tag": "0.0.1-test",
50
+ "containerOverrides": {
51
+ "env": {
52
+ "NODE_ENV": "test"
53
+ }
54
+ }
55
+ },
56
+ "online": {
57
+ "tag": "0.0.1-prod",
58
+ "buildOverrides": {
59
+ "platform": "linux/amd64"
60
+ },
61
+ "containerOverrides": {
62
+ "env": {
63
+ "NODE_ENV": "production"
64
+ }
65
+ }
66
+ }
67
+ },
68
+ "remote": {
69
+ "socketPath": "/var/run/docker.sock",
70
+ "host": "localhost",
71
+ "port": 2376,
72
+ "protocol": "https",
73
+ "tls": {
74
+ "ca": "",
75
+ "cert": "",
76
+ "key": ""
77
+ }
78
+ },
79
+ "container": {
80
+ "name": "__APP_NAME__",
81
+ "ports": ["3000:3000/tcp"],
82
+ "envFile": "env/.dev",
83
+ "env": {
84
+ "NODE_ENV": "development"
85
+ },
86
+ "volumes": []
87
+ }
88
+ }
89
+ }
package/bin/copy.js DELETED
@@ -1,40 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.copyRushTemplate = copyRushTemplate;
4
- exports.updateRushJsonProjects = updateRushJsonProjects;
5
- exports.copyFrontendTemplate = copyFrontendTemplate;
6
- exports.copyBackendTemplate = copyBackendTemplate;
7
- exports.copyDeployScriptTemplate = copyDeployScriptTemplate;
8
- exports.ensureDir = ensureDir;
9
- exports.isDirEmpty = isDirEmpty;
10
- exports.copySkillDir = copySkillDir;
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
- });
17
- function copyRushTemplate(targetDir, vars) {
18
- filesystemCapability.copyRushTemplate(targetDir, vars);
19
- }
20
- function updateRushJsonProjects(filepath, feAppName, beAppName) {
21
- filesystemCapability.updateRushJsonProjects(filepath, feAppName, beAppName);
22
- }
23
- function copyFrontendTemplate(targetDir, vars) {
24
- filesystemCapability.copyFrontendTemplate(targetDir, vars);
25
- }
26
- function copyBackendTemplate(targetDir, vars) {
27
- filesystemCapability.copyBackendTemplate(targetDir, vars);
28
- }
29
- function copyDeployScriptTemplate(targetDir, vars) {
30
- filesystemCapability.copyDeployScriptTemplate(targetDir, vars);
31
- }
32
- function ensureDir(dir) {
33
- fsAdapter.ensureDir(dir);
34
- }
35
- function isDirEmpty(dir) {
36
- return filesystemCapability.isDirEmpty(dir);
37
- }
38
- function copySkillDir(sourceDir, targetDir) {
39
- filesystemCapability.copySkillDir(sourceDir, targetDir);
40
- }
package/bin/prompts.js DELETED
@@ -1,170 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.runPrompt = runPrompt;
7
- exports.askRushQuestions = askRushQuestions;
8
- exports.askProjectPath = askProjectPath;
9
- exports.askOverwrite = askOverwrite;
10
- exports.askInstallDeployScript = askInstallDeployScript;
11
- exports.printHelp = printHelp;
12
- exports.printVersion = printVersion;
13
- const enquirer_1 = require("enquirer");
14
- const fs_1 = require("fs");
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
- }
89
- async function askRushQuestions() {
90
- const frontend = await runPrompt({
91
- type: "input",
92
- name: "name",
93
- message: "请输入前端项目名称,为空表示不创建前端项目",
94
- initial: "",
95
- });
96
- if (frontend.status !== "value") {
97
- return frontend;
98
- }
99
- const backend = await runPrompt({
100
- type: "input",
101
- name: "name",
102
- message: "请输入后端项目名称,为空表示不创建后端项目",
103
- initial: "",
104
- });
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
- });
112
- }
113
- async function askProjectPath() {
114
- const result = await runPrompt({
115
- type: "input",
116
- name: "path",
117
- message: "请填写项目名称或路径,如果填.表示直接把项目放到当前目录下",
118
- initial: ".",
119
- });
120
- if (result.status !== "value") {
121
- return result;
122
- }
123
- const p = (result.value.path || ".").trim();
124
- return (0, interaction_result_1.interactionValue)(p || ".");
125
- }
126
- async function askOverwrite() {
127
- const result = await runPrompt({
128
- type: "confirm",
129
- name: "ok",
130
- message: "目标目录非空,是否覆盖?",
131
- initial: false,
132
- });
133
- if (result.status !== "value") {
134
- return result;
135
- }
136
- return (0, interaction_result_1.interactionValue)(result.value.ok);
137
- }
138
- async function askInstallDeployScript() {
139
- const result = await runPrompt({
140
- type: "confirm",
141
- name: "ok",
142
- message: "是否添加部署脚本?这个脚本允许你可以帮你快速构建docker镜像,并发布到阿里云等环境,但是需要本机有docker环境。",
143
- initial: false,
144
- });
145
- if (result.status !== "value") {
146
- return result;
147
- }
148
- return (0, interaction_result_1.interactionValue)(result.value.ok);
149
- }
150
- function printHelp() {
151
- const h = [
152
- "用法: listpage_cli init",
153
- "说明: 进入中文引导式交互,按提示填写即可",
154
- "用法: listpage_cli install-skill [skillName] [--project]",
155
- "说明: 安装技能到 Cursor。默认 skillName 为 test,安装到当前命令执行目录的 .cursor/skills/",
156
- "用法: listpage_cli build-project",
157
- "说明: 非交互校验当前目录是否为有效项目根(需存在 listpage.config.json)",
158
- ].join("\n");
159
- console.log(h);
160
- }
161
- function printVersion() {
162
- try {
163
- const p = path_1.default.join(__dirname, "..", "package.json");
164
- const pkg = JSON.parse((0, fs_1.readFileSync)(p, "utf8"));
165
- console.log(pkg.version || "");
166
- }
167
- catch {
168
- console.log("");
169
- }
170
- }
@@ -1,28 +0,0 @@
1
- # Dependencies
2
- node_modules/
3
- npm-debug.log*
4
- yarn-debug.log*
5
- yarn-error.log*
6
-
7
- # Build outputs
8
- dist/
9
- build/
10
- temp/
11
- output/
12
-
13
- # Package files
14
- *.zip
15
- *.tar.gz
16
-
17
- # IDE
18
- .vscode/
19
- .idea/
20
- *.swp
21
- *.swo
22
-
23
- # OS
24
- .DS_Store
25
- Thumbs.db
26
-
27
- # Logs
28
- *.log
@@ -1,33 +0,0 @@
1
- ## 内网部署方案
2
-
3
- ### 步骤一:源码构建
4
-
5
- `npm run build`
6
-
7
- 此时会将前后端的代码打包在`output`目录下
8
-
9
- ### 步骤二:修改 prisma 连接 url
10
-
11
- 修改`output/prisma/schema.prisma`文件中的`datasource db`的`url`为内网的 url
12
-
13
- ### 步骤三:内网环境仿真
14
-
15
- 修改 dockerfile 中的基础镜像
16
-
17
- ### 步骤四:带依赖的源码导出
18
-
19
- `npm run package`
20
-
21
- 此时会根据 dockerfile 中的基础镜像,将`output`目录下的代码和依赖导出到`output`目录下,比如 `docker-app-xxxxxx.tar.gz`
22
-
23
- ### 步骤五:内网部署
24
-
25
- 将导出的`docker-app-xxxxxx.tar.gz`文件上传到内网的服务器上,比如 `/opt/docker-app-xxxxxx.tar.gz`
26
-
27
- 然后解压源码:
28
-
29
- `tar -zxvf docker-app-xxxxxx.tar.gz`
30
-
31
- ### 步骤六:启动服务
32
-
33
- 进入到 dist 目录下, node main.js