polyforge-cli 0.1.0
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/LICENSE +21 -0
- package/README.md +65 -0
- package/dist/commands/create.js +46 -0
- package/dist/commands/doctor.js +136 -0
- package/dist/commands/list.js +32 -0
- package/dist/core/git.js +25 -0
- package/dist/core/installer.js +64 -0
- package/dist/core/prompts.js +147 -0
- package/dist/core/renderer.js +175 -0
- package/dist/core/validator.js +86 -0
- package/dist/index.js +47 -0
- package/dist/templates/backend/go-gin/apps/api/Makefile +10 -0
- package/dist/templates/backend/go-gin/apps/api/cmd/server/main.go +29 -0
- package/dist/templates/backend/go-gin/apps/api/go.mod +5 -0
- package/dist/templates/backend/go-gin/apps/api/internal/config/config.go +22 -0
- package/dist/templates/backend/go-gin/apps/api/internal/handler/health.go +27 -0
- package/dist/templates/backend/go-gin/apps/api/internal/handler/helpers.go +8 -0
- package/dist/templates/backend/go-gin/apps/api/internal/handler/ping.go +15 -0
- package/dist/templates/backend/go-gin/apps/api/internal/middleware/logger.go +18 -0
- package/dist/templates/backend/go-gin/apps/api/internal/middleware/recovery.go +23 -0
- package/dist/templates/backend/go-gin/apps/api/internal/middleware/trace.go +28 -0
- package/dist/templates/backend/go-gin/apps/api/internal/repository/ping.go +11 -0
- package/dist/templates/backend/go-gin/apps/api/internal/service/ping.go +17 -0
- package/dist/templates/backend/go-gin/apps/api/pkg/response/response.go +35 -0
- package/dist/templates/backend/go-gin/apps/api/pkg/response/response_test.go +21 -0
- package/dist/templates/backend/springboot/apps/api/pom.xml +44 -0
- package/dist/templates/backend/springboot/apps/api/src/main/java/com/scaffold/api/Application.java +11 -0
- package/dist/templates/backend/springboot/apps/api/src/main/java/com/scaffold/api/common/ApiResponse.java +19 -0
- package/dist/templates/backend/springboot/apps/api/src/main/java/com/scaffold/api/common/GlobalExceptionHandler.java +22 -0
- package/dist/templates/backend/springboot/apps/api/src/main/java/com/scaffold/api/common/TraceIdHolder.java +19 -0
- package/dist/templates/backend/springboot/apps/api/src/main/java/com/scaffold/api/config/TraceIdFilter.java +38 -0
- package/dist/templates/backend/springboot/apps/api/src/main/java/com/scaffold/api/controller/HealthController.java +17 -0
- package/dist/templates/backend/springboot/apps/api/src/main/java/com/scaffold/api/controller/PingController.java +23 -0
- package/dist/templates/backend/springboot/apps/api/src/main/java/com/scaffold/api/repository/PingRepository.java +10 -0
- package/dist/templates/backend/springboot/apps/api/src/main/java/com/scaffold/api/service/PingService.java +17 -0
- package/dist/templates/backend/springboot/apps/api/src/main/resources/application-dev.yml +2 -0
- package/dist/templates/backend/springboot/apps/api/src/main/resources/application-prod.yml +2 -0
- package/dist/templates/backend/springboot/apps/api/src/main/resources/application-test.yml +2 -0
- package/dist/templates/backend/springboot/apps/api/src/main/resources/application.yml +8 -0
- package/dist/templates/backend/springboot/apps/api/src/test/java/com/scaffold/api/ApplicationTests.java +12 -0
- package/dist/templates/base/.env.example +5 -0
- package/dist/templates/base/docs/ARCHITECTURE.md +9 -0
- package/dist/templates/base/infra/scripts/build.sh +39 -0
- package/dist/templates/base/infra/scripts/check.sh +58 -0
- package/dist/templates/base/infra/scripts/dev.sh +32 -0
- package/dist/templates/base/infra/scripts/test.sh +41 -0
- package/dist/templates/base/package.json +11 -0
- package/dist/templates/data/mongodb/infra/data/mongodb/README.md +4 -0
- package/dist/templates/data/mysql/infra/data/mysql/README.md +4 -0
- package/dist/templates/data/mysql/infra/data/mysql/schema.sql +5 -0
- package/dist/templates/data/postgresql/infra/data/postgresql/README.md +4 -0
- package/dist/templates/data/postgresql/infra/data/postgresql/schema.sql +5 -0
- package/dist/templates/data/redis/infra/data/redis/README.md +4 -0
- package/dist/templates/data/sqlite/infra/data/sqlite/README.md +4 -0
- package/dist/templates/frontend/react/apps/web/.env.example +4 -0
- package/dist/templates/frontend/react/apps/web/index.html +12 -0
- package/dist/templates/frontend/react/apps/web/package.json +23 -0
- package/dist/templates/frontend/react/apps/web/src/App.test.tsx +7 -0
- package/dist/templates/frontend/react/apps/web/src/App.tsx +59 -0
- package/dist/templates/frontend/react/apps/web/src/api/client.ts +20 -0
- package/dist/templates/frontend/react/apps/web/src/api/request.ts +104 -0
- package/dist/templates/frontend/react/apps/web/src/api/services/api.ts +15 -0
- package/dist/templates/frontend/react/apps/web/src/api/services/bff.ts +11 -0
- package/dist/templates/frontend/react/apps/web/src/main.tsx +9 -0
- package/dist/templates/frontend/react/apps/web/tsconfig.json +12 -0
- package/dist/templates/frontend/react/apps/web/vite.config.ts +22 -0
- package/dist/templates/frontend/vue/apps/web/.env.example +4 -0
- package/dist/templates/frontend/vue/apps/web/index.html +12 -0
- package/dist/templates/frontend/vue/apps/web/package.json +20 -0
- package/dist/templates/frontend/vue/apps/web/src/App.test.ts +7 -0
- package/dist/templates/frontend/vue/apps/web/src/App.vue +59 -0
- package/dist/templates/frontend/vue/apps/web/src/api/client.ts +20 -0
- package/dist/templates/frontend/vue/apps/web/src/api/request.ts +104 -0
- package/dist/templates/frontend/vue/apps/web/src/api/services/api.ts +15 -0
- package/dist/templates/frontend/vue/apps/web/src/api/services/bff.ts +11 -0
- package/dist/templates/frontend/vue/apps/web/src/env.d.ts +3 -0
- package/dist/templates/frontend/vue/apps/web/src/main.ts +4 -0
- package/dist/templates/frontend/vue/apps/web/tsconfig.json +11 -0
- package/dist/templates/frontend/vue/apps/web/vite.config.ts +22 -0
- package/dist/templates/modules/auth-center/apps/auth-center/.env.example +3 -0
- package/dist/templates/modules/auth-center/apps/auth-center/README.md +5 -0
- package/dist/templates/modules/auth-center/apps/auth-center/package.json +14 -0
- package/dist/templates/modules/auth-center/apps/auth-center/server.js +21 -0
- package/dist/templates/modules/cache-redis/infra/cache/README.md +5 -0
- package/dist/templates/modules/cache-redis/infra/cache/policies.md +5 -0
- package/dist/templates/modules/gateway-bff/apps/gateway-bff/README.md +5 -0
- package/dist/templates/modules/gateway-bff/apps/gateway-bff/package.json +13 -0
- package/dist/templates/modules/gateway-bff/apps/gateway-bff/server.js +17 -0
- package/dist/templates/modules/grpc-service/apps/grpc-service/README.md +5 -0
- package/dist/templates/modules/grpc-service/contracts/proto/greeter.proto +17 -0
- package/dist/templates/modules/grpc-service/infra/scripts/gen-proto.sh +9 -0
- package/dist/templates/modules/mq/infra/mq/README.md +5 -0
- package/dist/templates/modules/mq/infra/mq/kafka-topics.md +5 -0
- package/dist/templates/modules/mq/infra/mq/nats-subjects.md +4 -0
- package/dist/templates/modules/mq/infra/mq/rabbitmq-exchanges.md +5 -0
- package/dist/templates/modules/observability/infra/observability/README.md +5 -0
- package/dist/templates/modules/observability/infra/observability/grafana/README.md +3 -0
- package/dist/templates/modules/observability/infra/observability/otel-collector.yaml +15 -0
- package/dist/templates/modules/observability/infra/observability/prometheus/prometheus.yml +7 -0
- package/dist/templates/modules/python-ai/apps/python-ai/README.md +5 -0
- package/dist/templates/modules/python-ai/apps/python-ai/app/main.py +27 -0
- package/dist/templates/modules/python-ai/apps/python-ai/requirements.txt +2 -0
- package/dist/templates/modules/python-ai/apps/python-ai/scripts/batch_infer.py +6 -0
- package/dist/templates/modules/python-worker/apps/worker-python/README.md +5 -0
- package/dist/templates/modules/python-worker/apps/worker-python/requirements.txt +1 -0
- package/dist/templates/modules/python-worker/apps/worker-python/tasks/sample_task.py +6 -0
- package/dist/templates/modules/python-worker/apps/worker-python/tests/test_worker.py +13 -0
- package/dist/templates/modules/python-worker/apps/worker-python/worker.py +10 -0
- package/dist/templates/modules/worker-go/apps/worker-go/README.md +5 -0
- package/dist/templates/modules/worker-go/apps/worker-go/cmd/worker/main.go +16 -0
- package/dist/templates/modules/worker-go/apps/worker-go/go.mod +3 -0
- package/dist/templates/modules/worker-go/apps/worker-go/internal/tasks/heartbeat.go +7 -0
- package/dist/types/config.js +18 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# PolyForge Scaffold CLI
|
|
2
|
+
|
|
3
|
+
PolyForge is a hybrid full-stack scaffold CLI for `go-gin` and `springboot`.
|
|
4
|
+
CLI command remains `scaffold`.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
# one-off run
|
|
10
|
+
npx polyforge-cli@latest list
|
|
11
|
+
|
|
12
|
+
# global install
|
|
13
|
+
npm i -g polyforge-cli
|
|
14
|
+
scaffold list
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Commands
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm run build
|
|
21
|
+
node dist/index.js doctor
|
|
22
|
+
node dist/index.js create my-app
|
|
23
|
+
node dist/index.js list
|
|
24
|
+
npm run smoke:e2e
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### create options
|
|
28
|
+
|
|
29
|
+
- `--frontend <react|vue|none>`
|
|
30
|
+
- `--backend <go-gin|springboot>`
|
|
31
|
+
- `--modules <python-worker,worker-go,gateway-bff,python-ai,grpc-service,mq,cache-redis,observability,auth-center>`
|
|
32
|
+
- `--data <mysql,postgresql,redis,sqlite,mongodb,none>`
|
|
33
|
+
- `--pm <pnpm|npm|yarn>`
|
|
34
|
+
- `--install`
|
|
35
|
+
- `--git`
|
|
36
|
+
- `--docker`
|
|
37
|
+
- `--yes`
|
|
38
|
+
|
|
39
|
+
### doctor options
|
|
40
|
+
|
|
41
|
+
- `--backend <go-gin|springboot>`
|
|
42
|
+
- `--modules <python-worker,worker-go,gateway-bff,python-ai,grpc-service,mq,cache-redis,observability,auth-center>`
|
|
43
|
+
- `--data <mysql,postgresql,redis,sqlite,mongodb,none>`
|
|
44
|
+
|
|
45
|
+
## Development
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm run lint
|
|
49
|
+
npm run test
|
|
50
|
+
npm run build
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Publish To npm
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
npm login
|
|
57
|
+
npm publish
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Frontend Auto-Wiring
|
|
61
|
+
|
|
62
|
+
- React/Vue templates include `.env.example` with API/BFF base URLs.
|
|
63
|
+
- Vite dev server proxy routes `/api` -> backend API and `/bff` -> gateway-bff.
|
|
64
|
+
- Frontend page includes demo requests for `/api/v1/ping` and `/bff/ping` with `X-Trace-Id`.
|
|
65
|
+
- Frontend templates include `src/api/request.ts` (timeout/retry/error mapping), `src/api/services/*`, and `src/api/client.ts`.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runCreate = runCreate;
|
|
4
|
+
const prompts_1 = require("../core/prompts");
|
|
5
|
+
const renderer_1 = require("../core/renderer");
|
|
6
|
+
const validator_1 = require("../core/validator");
|
|
7
|
+
const installer_1 = require("../core/installer");
|
|
8
|
+
const git_1 = require("../core/git");
|
|
9
|
+
function printResolvedConfigSummary(options, config) {
|
|
10
|
+
const defaulted = [];
|
|
11
|
+
if (options.frontend === undefined)
|
|
12
|
+
defaulted.push(`frontend=${config.frontend}`);
|
|
13
|
+
if (options.backend === undefined)
|
|
14
|
+
defaulted.push(`backend=${config.backendMain}`);
|
|
15
|
+
if (options.modules === undefined)
|
|
16
|
+
defaulted.push(`modules=${config.extraModules.join(",") || "none"}`);
|
|
17
|
+
if (options.data === undefined)
|
|
18
|
+
defaulted.push(`data=${config.dataModules.join(",")}`);
|
|
19
|
+
if (options.pm === undefined)
|
|
20
|
+
defaulted.push(`pm=${config.packageManager}`);
|
|
21
|
+
if (options.install === undefined)
|
|
22
|
+
defaulted.push(`install=${String(config.installDeps)}`);
|
|
23
|
+
if (options.git === undefined)
|
|
24
|
+
defaulted.push(`git=${String(config.initGit)}`);
|
|
25
|
+
if (options.docker === undefined)
|
|
26
|
+
defaulted.push(`docker=${String(config.docker)}`);
|
|
27
|
+
if (options.yes && defaulted.length > 0) {
|
|
28
|
+
console.log(`[scaffold] --yes defaults applied: ${defaulted.join(" | ")}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async function runCreate(projectName, options) {
|
|
32
|
+
const config = await (0, prompts_1.resolveCreateConfig)(projectName, options);
|
|
33
|
+
printResolvedConfigSummary(options, config);
|
|
34
|
+
const validation = (0, validator_1.validateConfig)(config);
|
|
35
|
+
if (!validation.valid) {
|
|
36
|
+
throw new Error(`Invalid configuration:\n- ${validation.errors.join("\n- ")}`);
|
|
37
|
+
}
|
|
38
|
+
for (const warning of validation.warnings) {
|
|
39
|
+
console.warn(`[warning] ${warning}`);
|
|
40
|
+
}
|
|
41
|
+
await (0, renderer_1.renderProject)(config);
|
|
42
|
+
await (0, installer_1.maybeInstallDeps)(config);
|
|
43
|
+
await (0, git_1.maybeInitGit)(config);
|
|
44
|
+
console.log(`[scaffold] project created: ${config.targetDir}`);
|
|
45
|
+
console.log("[scaffold] next: cd <project> && npm run check && npm run dev");
|
|
46
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildDoctorAdvice = buildDoctorAdvice;
|
|
4
|
+
exports.runDoctor = runDoctor;
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
const config_1 = require("../types/config");
|
|
7
|
+
const validator_1 = require("../core/validator");
|
|
8
|
+
function check(name, cmd, args) {
|
|
9
|
+
const res = (0, child_process_1.spawnSync)(cmd, args, { encoding: "utf8" });
|
|
10
|
+
if (res.status === 0) {
|
|
11
|
+
return {
|
|
12
|
+
name,
|
|
13
|
+
ok: true,
|
|
14
|
+
output: (res.stdout || res.stderr || "ok").trim(),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
return {
|
|
18
|
+
name,
|
|
19
|
+
ok: false,
|
|
20
|
+
output: (res.stderr || res.stdout || "missing").trim(),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function parseTargets(options) {
|
|
24
|
+
const backend = options.backend && config_1.BACKENDS.includes(options.backend) ? options.backend : undefined;
|
|
25
|
+
const modules = (0, validator_1.parseCsv)(options.modules).filter((item) => config_1.EXTRA_MODULES.includes(item));
|
|
26
|
+
const data = (0, validator_1.parseCsv)(options.data).filter((item) => config_1.DATA_MODULES.includes(item));
|
|
27
|
+
return { backend, modules, data };
|
|
28
|
+
}
|
|
29
|
+
function has(checks, name) {
|
|
30
|
+
return checks[name]?.ok ?? false;
|
|
31
|
+
}
|
|
32
|
+
function buildDoctorAdvice(checks, options) {
|
|
33
|
+
const targets = parseTargets(options);
|
|
34
|
+
const advice = [];
|
|
35
|
+
if (targets.backend === "go-gin") {
|
|
36
|
+
advice.push(has(checks, "go")
|
|
37
|
+
? { label: "go-gin", status: "ok", detail: "Go toolchain detected." }
|
|
38
|
+
: { label: "go-gin", status: "warn", detail: "Install Go 1.22+ for go-gin templates." });
|
|
39
|
+
}
|
|
40
|
+
if (targets.backend === "springboot") {
|
|
41
|
+
advice.push(has(checks, "java")
|
|
42
|
+
? { label: "springboot", status: "ok", detail: "Java runtime detected." }
|
|
43
|
+
: { label: "springboot", status: "warn", detail: "Install JDK 17+ for Spring Boot templates." });
|
|
44
|
+
advice.push(has(checks, "mvn")
|
|
45
|
+
? { label: "maven", status: "ok", detail: "Maven detected." }
|
|
46
|
+
: { label: "maven", status: "warn", detail: "Install Maven 3.9+ to run spring build/test." });
|
|
47
|
+
}
|
|
48
|
+
if (targets.modules.includes("python-worker")) {
|
|
49
|
+
advice.push(has(checks, "python3")
|
|
50
|
+
? { label: "python-worker", status: "ok", detail: "Python 3 runtime detected." }
|
|
51
|
+
: { label: "python-worker", status: "warn", detail: "Install Python 3.10+ for worker module." });
|
|
52
|
+
}
|
|
53
|
+
if (targets.modules.includes("worker-go")) {
|
|
54
|
+
advice.push(has(checks, "go")
|
|
55
|
+
? { label: "worker-go", status: "ok", detail: "Go toolchain detected for worker-go module." }
|
|
56
|
+
: { label: "worker-go", status: "warn", detail: "Install Go 1.22+ for worker-go module." });
|
|
57
|
+
}
|
|
58
|
+
if (targets.modules.includes("gateway-bff")) {
|
|
59
|
+
advice.push(has(checks, "node") && has(checks, "npm")
|
|
60
|
+
? { label: "gateway-bff", status: "ok", detail: "Node.js and npm detected for gateway-bff." }
|
|
61
|
+
: { label: "gateway-bff", status: "warn", detail: "Install Node.js 18+ and npm for gateway-bff module." });
|
|
62
|
+
}
|
|
63
|
+
if (targets.modules.includes("python-ai")) {
|
|
64
|
+
advice.push(has(checks, "python3")
|
|
65
|
+
? { label: "python-ai", status: "ok", detail: "Python detected for python-ai module." }
|
|
66
|
+
: { label: "python-ai", status: "warn", detail: "Install Python 3.10+ for python-ai module." });
|
|
67
|
+
}
|
|
68
|
+
if (targets.modules.includes("grpc-service")) {
|
|
69
|
+
advice.push(has(checks, "protoc")
|
|
70
|
+
? { label: "grpc-service", status: "ok", detail: "protoc detected for gRPC contract generation." }
|
|
71
|
+
: { label: "grpc-service", status: "warn", detail: "Install protoc for gRPC code generation." });
|
|
72
|
+
}
|
|
73
|
+
if (targets.modules.includes("mq")) {
|
|
74
|
+
advice.push(has(checks, "docker")
|
|
75
|
+
? { label: "mq", status: "ok", detail: "Docker detected for local MQ brokers." }
|
|
76
|
+
: { label: "mq", status: "warn", detail: "Install Docker to run Kafka/RabbitMQ/NATS locally." });
|
|
77
|
+
}
|
|
78
|
+
if (targets.modules.includes("cache-redis")) {
|
|
79
|
+
advice.push(has(checks, "docker")
|
|
80
|
+
? { label: "cache-redis", status: "ok", detail: "Docker detected for local Redis cache service." }
|
|
81
|
+
: { label: "cache-redis", status: "warn", detail: "Install Docker or run Redis manually." });
|
|
82
|
+
}
|
|
83
|
+
if (targets.modules.includes("observability")) {
|
|
84
|
+
advice.push(has(checks, "docker")
|
|
85
|
+
? { label: "observability", status: "ok", detail: "Docker detected for Prometheus/Grafana stack." }
|
|
86
|
+
: { label: "observability", status: "warn", detail: "Install Docker for local observability stack." });
|
|
87
|
+
}
|
|
88
|
+
if (targets.modules.includes("auth-center")) {
|
|
89
|
+
advice.push({
|
|
90
|
+
label: "auth-center",
|
|
91
|
+
status: "ok",
|
|
92
|
+
detail: "Remember to configure JWT secrets and OAuth clients before production.",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (targets.data.some((item) => item !== "none")) {
|
|
96
|
+
advice.push(has(checks, "docker")
|
|
97
|
+
? { label: "data-services", status: "ok", detail: "Docker detected for local DB/cache containers." }
|
|
98
|
+
: { label: "data-services", status: "warn", detail: "Docker not found; run data services manually or install Docker Desktop." });
|
|
99
|
+
}
|
|
100
|
+
return advice;
|
|
101
|
+
}
|
|
102
|
+
async function runDoctor(options = {}) {
|
|
103
|
+
const checksList = [
|
|
104
|
+
check("node", "node", ["-v"]),
|
|
105
|
+
check("npm", "npm", ["-v"]),
|
|
106
|
+
check("go", "go", ["version"]),
|
|
107
|
+
check("java", "java", ["-version"]),
|
|
108
|
+
check("mvn", "mvn", ["-v"]),
|
|
109
|
+
check("python3", "python3", ["--version"]),
|
|
110
|
+
check("git", "git", ["--version"]),
|
|
111
|
+
check("docker", "docker", ["--version"]),
|
|
112
|
+
check("protoc", "protoc", ["--version"]),
|
|
113
|
+
];
|
|
114
|
+
const checks = Object.fromEntries(checksList.map((item) => [item.name, item]));
|
|
115
|
+
let failed = 0;
|
|
116
|
+
for (const item of checksList) {
|
|
117
|
+
if (!item.ok)
|
|
118
|
+
failed += 1;
|
|
119
|
+
const status = item.ok ? "OK" : "MISSING";
|
|
120
|
+
console.log(`${status.padEnd(8)} ${item.name.padEnd(8)} ${item.output.split("\n")[0]}`);
|
|
121
|
+
}
|
|
122
|
+
const advices = buildDoctorAdvice(checks, options);
|
|
123
|
+
if (advices.length > 0) {
|
|
124
|
+
console.log("\nTargeted Advice:");
|
|
125
|
+
for (const advice of advices) {
|
|
126
|
+
const tag = advice.status === "ok" ? "OK" : "WARN";
|
|
127
|
+
console.log(`- ${tag} ${advice.label}: ${advice.detail}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (failed > 0) {
|
|
131
|
+
console.log(`\ndoctor finished with ${failed} missing tools`);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
console.log("\ndoctor finished: all required tools found");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runList = runList;
|
|
4
|
+
const config_1 = require("../types/config");
|
|
5
|
+
const validator_1 = require("../core/validator");
|
|
6
|
+
function join(items) {
|
|
7
|
+
return items.join(", ");
|
|
8
|
+
}
|
|
9
|
+
async function runList() {
|
|
10
|
+
console.log("PolyForge Scaffold Options");
|
|
11
|
+
console.log("");
|
|
12
|
+
console.log(`frontend: ${join(config_1.FRONTENDS)}`);
|
|
13
|
+
console.log(`backend: ${join(config_1.BACKENDS)}`);
|
|
14
|
+
console.log(`modules: ${join(config_1.EXTRA_MODULES)}`);
|
|
15
|
+
console.log(`data: ${join(config_1.DATA_MODULES)}`);
|
|
16
|
+
console.log(`packageManager: ${join(config_1.PACKAGE_MANAGERS)}`);
|
|
17
|
+
console.log("");
|
|
18
|
+
console.log("Defaults (--yes):");
|
|
19
|
+
console.log(`- frontend=${validator_1.DEFAULTS.frontend}`);
|
|
20
|
+
console.log(`- backend=${validator_1.DEFAULTS.backendMain}`);
|
|
21
|
+
console.log(`- modules=${validator_1.DEFAULTS.extraModules.join(",") || "none"}`);
|
|
22
|
+
console.log(`- data=${validator_1.DEFAULTS.dataModules.join(",")}`);
|
|
23
|
+
console.log(`- pm=${validator_1.DEFAULTS.packageManager}`);
|
|
24
|
+
console.log(`- install=${String(validator_1.DEFAULTS.installDeps)}`);
|
|
25
|
+
console.log(`- git=${String(validator_1.DEFAULTS.initGit)}`);
|
|
26
|
+
console.log(`- docker=${String(validator_1.DEFAULTS.docker)}`);
|
|
27
|
+
console.log("");
|
|
28
|
+
console.log("Rules:");
|
|
29
|
+
console.log("- data=none is mutually exclusive with other data modules");
|
|
30
|
+
console.log("- data modules can be combined (example: mysql,redis)");
|
|
31
|
+
console.log("- backend main stack is limited to go-gin and springboot");
|
|
32
|
+
}
|
package/dist/core/git.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.maybeInitGit = maybeInitGit;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
function run(cmd, args, cwd) {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const child = (0, child_process_1.spawn)(cmd, args, { cwd, stdio: "ignore" });
|
|
8
|
+
child.on("close", (code) => {
|
|
9
|
+
if (code === 0)
|
|
10
|
+
resolve();
|
|
11
|
+
else
|
|
12
|
+
reject(new Error(`${cmd} ${args.join(" ")} failed with code ${code}`));
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
async function maybeInitGit(config) {
|
|
17
|
+
if (!config.initGit)
|
|
18
|
+
return;
|
|
19
|
+
try {
|
|
20
|
+
await run("git", ["init"], config.targetDir);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
console.warn("[scaffold] skip git init (git unavailable)");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
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.maybeInstallDeps = maybeInstallDeps;
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const fs_1 = require("fs");
|
|
10
|
+
function run(cmd, args, cwd) {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
const child = (0, child_process_1.spawn)(cmd, args, { cwd, stdio: "inherit", shell: process.platform === "win32" });
|
|
13
|
+
child.on("close", (code) => {
|
|
14
|
+
if (code === 0)
|
|
15
|
+
resolve();
|
|
16
|
+
else
|
|
17
|
+
reject(new Error(`${cmd} ${args.join(" ")} failed with code ${code}`));
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
async function maybeInstallDeps(config) {
|
|
22
|
+
if (!config.installDeps)
|
|
23
|
+
return;
|
|
24
|
+
if (config.frontend !== "none") {
|
|
25
|
+
const webDir = path_1.default.join(config.targetDir, "apps", "web");
|
|
26
|
+
if ((0, fs_1.existsSync)(path_1.default.join(webDir, "package.json"))) {
|
|
27
|
+
await run(config.packageManager, ["install"], webDir);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (config.extraModules.includes("python-worker")) {
|
|
31
|
+
const pyDir = path_1.default.join(config.targetDir, "apps", "worker-python");
|
|
32
|
+
if ((0, fs_1.existsSync)(path_1.default.join(pyDir, "requirements.txt"))) {
|
|
33
|
+
try {
|
|
34
|
+
await run("python3", ["-m", "pip", "install", "-r", "requirements.txt"], pyDir);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
console.warn("[scaffold] skip python dependency install (python3/pip unavailable)");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (config.extraModules.includes("gateway-bff")) {
|
|
42
|
+
const bffDir = path_1.default.join(config.targetDir, "apps", "gateway-bff");
|
|
43
|
+
if ((0, fs_1.existsSync)(path_1.default.join(bffDir, "package.json"))) {
|
|
44
|
+
await run(config.packageManager, ["install"], bffDir);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (config.extraModules.includes("auth-center")) {
|
|
48
|
+
const authDir = path_1.default.join(config.targetDir, "apps", "auth-center");
|
|
49
|
+
if ((0, fs_1.existsSync)(path_1.default.join(authDir, "package.json"))) {
|
|
50
|
+
await run(config.packageManager, ["install"], authDir);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (config.extraModules.includes("python-ai")) {
|
|
54
|
+
const pyAiDir = path_1.default.join(config.targetDir, "apps", "python-ai");
|
|
55
|
+
if ((0, fs_1.existsSync)(path_1.default.join(pyAiDir, "requirements.txt"))) {
|
|
56
|
+
try {
|
|
57
|
+
await run("python3", ["-m", "pip", "install", "-r", "requirements.txt"], pyAiDir);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
console.warn("[scaffold] skip python-ai dependency install (python3/pip unavailable)");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
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.resolveCreateConfig = resolveCreateConfig;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const prompts_1 = __importDefault(require("prompts"));
|
|
9
|
+
const config_1 = require("../types/config");
|
|
10
|
+
const validator_1 = require("./validator");
|
|
11
|
+
async function resolveCreateConfig(projectName, options) {
|
|
12
|
+
const targetDir = path_1.default.resolve(options.targetDir ?? process.cwd(), projectName);
|
|
13
|
+
const rawModuleInputs = (0, validator_1.parseCsv)(options.modules);
|
|
14
|
+
const rawDataInputs = (0, validator_1.parseCsv)(options.data);
|
|
15
|
+
const invalidModules = rawModuleInputs.filter((item) => !config_1.EXTRA_MODULES.includes(item));
|
|
16
|
+
const invalidDataModules = rawDataInputs.filter((item) => !config_1.DATA_MODULES.includes(item));
|
|
17
|
+
if (invalidModules.length > 0) {
|
|
18
|
+
throw new Error(`unsupported modules: ${invalidModules.join(", ")}`);
|
|
19
|
+
}
|
|
20
|
+
if (invalidDataModules.length > 0) {
|
|
21
|
+
throw new Error(`unsupported data modules: ${invalidDataModules.join(", ")}`);
|
|
22
|
+
}
|
|
23
|
+
const cliModules = (0, validator_1.parseExtraModules)(options.modules);
|
|
24
|
+
const cliDataModules = (0, validator_1.parseDataModules)(options.data);
|
|
25
|
+
const initial = {
|
|
26
|
+
projectName,
|
|
27
|
+
frontend: options.frontend,
|
|
28
|
+
backendMain: options.backend,
|
|
29
|
+
extraModules: cliModules.length > 0 ? cliModules : undefined,
|
|
30
|
+
dataModules: cliDataModules.length > 0 ? cliDataModules : undefined,
|
|
31
|
+
packageManager: options.pm,
|
|
32
|
+
installDeps: options.install,
|
|
33
|
+
initGit: options.git,
|
|
34
|
+
docker: options.docker,
|
|
35
|
+
targetDir,
|
|
36
|
+
};
|
|
37
|
+
let prompted = {};
|
|
38
|
+
if (!options.yes) {
|
|
39
|
+
prompted = await askMissing(initial);
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
projectName,
|
|
43
|
+
targetDir,
|
|
44
|
+
frontend: initial.frontend ?? prompted.frontend ?? validator_1.DEFAULTS.frontend,
|
|
45
|
+
backendMain: initial.backendMain ?? prompted.backendMain ?? validator_1.DEFAULTS.backendMain,
|
|
46
|
+
extraModules: initial.extraModules ?? prompted.extraModules ?? validator_1.DEFAULTS.extraModules,
|
|
47
|
+
dataModules: initial.dataModules ?? prompted.dataModules ?? validator_1.DEFAULTS.dataModules,
|
|
48
|
+
packageManager: initial.packageManager ?? prompted.packageManager ?? validator_1.DEFAULTS.packageManager,
|
|
49
|
+
installDeps: initial.installDeps ?? prompted.installDeps ?? validator_1.DEFAULTS.installDeps,
|
|
50
|
+
initGit: initial.initGit ?? prompted.initGit ?? validator_1.DEFAULTS.initGit,
|
|
51
|
+
docker: initial.docker ?? prompted.docker ?? validator_1.DEFAULTS.docker,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async function askMissing(initial) {
|
|
55
|
+
const res = await (0, prompts_1.default)([
|
|
56
|
+
{
|
|
57
|
+
type: initial.frontend ? null : "select",
|
|
58
|
+
name: "frontend",
|
|
59
|
+
message: "Select frontend",
|
|
60
|
+
choices: [
|
|
61
|
+
{ title: "react", value: "react" },
|
|
62
|
+
{ title: "vue", value: "vue" },
|
|
63
|
+
{ title: "none", value: "none" },
|
|
64
|
+
],
|
|
65
|
+
initial: 0,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
type: initial.backendMain ? null : "select",
|
|
69
|
+
name: "backendMain",
|
|
70
|
+
message: "Select backend",
|
|
71
|
+
choices: [
|
|
72
|
+
{ title: "go-gin", value: "go-gin" },
|
|
73
|
+
{ title: "springboot", value: "springboot" },
|
|
74
|
+
],
|
|
75
|
+
initial: 0,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
type: initial.extraModules ? null : "multiselect",
|
|
79
|
+
name: "extraModules",
|
|
80
|
+
message: "Select extra modules",
|
|
81
|
+
choices: [
|
|
82
|
+
{ title: "python-worker", value: "python-worker" },
|
|
83
|
+
{ title: "worker-go", value: "worker-go" },
|
|
84
|
+
{ title: "gateway-bff", value: "gateway-bff" },
|
|
85
|
+
{ title: "python-ai", value: "python-ai" },
|
|
86
|
+
{ title: "grpc-service", value: "grpc-service" },
|
|
87
|
+
{ title: "mq", value: "mq" },
|
|
88
|
+
{ title: "cache-redis", value: "cache-redis" },
|
|
89
|
+
{ title: "observability", value: "observability" },
|
|
90
|
+
{ title: "auth-center", value: "auth-center" },
|
|
91
|
+
],
|
|
92
|
+
hint: "Space to select",
|
|
93
|
+
min: 0,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
type: initial.dataModules ? null : "multiselect",
|
|
97
|
+
name: "dataModules",
|
|
98
|
+
message: "Select data modules",
|
|
99
|
+
choices: [
|
|
100
|
+
{ title: "mysql", value: "mysql" },
|
|
101
|
+
{ title: "postgresql", value: "postgresql" },
|
|
102
|
+
{ title: "redis", value: "redis" },
|
|
103
|
+
{ title: "sqlite", value: "sqlite" },
|
|
104
|
+
{ title: "mongodb", value: "mongodb" },
|
|
105
|
+
{ title: "none", value: "none" },
|
|
106
|
+
],
|
|
107
|
+
min: 1,
|
|
108
|
+
hint: "none cannot combine with others",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
type: initial.packageManager ? null : "select",
|
|
112
|
+
name: "packageManager",
|
|
113
|
+
message: "Select package manager",
|
|
114
|
+
choices: [
|
|
115
|
+
{ title: "pnpm", value: "pnpm" },
|
|
116
|
+
{ title: "npm", value: "npm" },
|
|
117
|
+
{ title: "yarn", value: "yarn" },
|
|
118
|
+
],
|
|
119
|
+
initial: 1,
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
type: initial.installDeps !== undefined ? null : "toggle",
|
|
123
|
+
name: "installDeps",
|
|
124
|
+
message: "Install dependencies now?",
|
|
125
|
+
initial: false,
|
|
126
|
+
active: "yes",
|
|
127
|
+
inactive: "no",
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
type: initial.initGit !== undefined ? null : "toggle",
|
|
131
|
+
name: "initGit",
|
|
132
|
+
message: "Initialize git?",
|
|
133
|
+
initial: false,
|
|
134
|
+
active: "yes",
|
|
135
|
+
inactive: "no",
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
type: initial.docker !== undefined ? null : "toggle",
|
|
139
|
+
name: "docker",
|
|
140
|
+
message: "Generate docker baseline config?",
|
|
141
|
+
initial: false,
|
|
142
|
+
active: "yes",
|
|
143
|
+
inactive: "no",
|
|
144
|
+
},
|
|
145
|
+
]);
|
|
146
|
+
return res;
|
|
147
|
+
}
|