onflyt-cli 1.0.1-beta.2 → 1.0.1-beta.3
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.
Potentially problematic release.
This version of onflyt-cli might be problematic. Click here for more details.
- package/dist/App.d.ts +3 -0
- package/dist/App.js +8 -0
- package/dist/commands/credits.d.ts +3 -0
- package/dist/commands/credits.js +101 -0
- package/dist/commands/delete.d.ts +7 -0
- package/dist/commands/delete.js +220 -0
- package/dist/commands/deploy.d.ts +6 -0
- package/dist/commands/deploy.js +715 -0
- package/dist/commands/deployments.d.ts +6 -0
- package/dist/commands/deployments.js +225 -0
- package/dist/commands/help.d.ts +3 -0
- package/dist/commands/help.js +76 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.js +422 -0
- package/dist/commands/login.d.ts +6 -0
- package/dist/commands/login.js +150 -0
- package/dist/commands/logout.d.ts +3 -0
- package/dist/commands/logout.js +19 -0
- package/dist/commands/logs.d.ts +7 -0
- package/dist/commands/logs.js +307 -0
- package/dist/commands/projects.d.ts +3 -0
- package/dist/commands/projects.js +203 -0
- package/dist/commands/rollback.d.ts +6 -0
- package/dist/commands/rollback.js +316 -0
- package/dist/commands/teams.d.ts +3 -0
- package/dist/commands/teams.js +81 -0
- package/dist/commands/whoami.d.ts +3 -0
- package/dist/commands/whoami.js +34 -0
- package/dist/components/Loading.d.ts +13 -0
- package/dist/components/Loading.js +42 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +77 -116
- package/dist/lib/api.d.ts +27 -0
- package/dist/lib/api.js +109 -0
- package/dist/lib/config.d.ts +32 -0
- package/dist/lib/config.js +52 -0
- package/dist/lib/deploy-api.d.ts +97 -0
- package/dist/lib/deploy-api.js +335 -0
- package/dist/lib/deploy.d.ts +36 -0
- package/dist/lib/deploy.js +181 -0
- package/dist/lib/framework.d.ts +27 -0
- package/dist/lib/framework.js +184 -0
- package/dist/lib/git.d.ts +25 -0
- package/dist/lib/git.js +149 -0
- package/dist/lib/scaffold.d.ts +21 -0
- package/dist/lib/scaffold.js +190 -0
- package/dist/shared/frameworks/registry.d.ts +21 -0
- package/dist/shared/frameworks/registry.js +196 -0
- package/dist/shared/index.d.ts +4 -0
- package/dist/shared/index.js +4 -0
- package/dist/shared/limits.d.ts +16 -0
- package/dist/shared/limits.js +44 -0
- package/dist/shared/pricing.d.ts +2 -0
- package/dist/shared/pricing.js +7 -0
- package/dist/shared/templates/registry.d.ts +9 -0
- package/dist/shared/templates/registry.js +47 -0
- package/package.json +2 -3
- package/src/App.tsx +1 -1
- package/src/commands/deploy.tsx +1 -1
- package/src/commands/help.tsx +1 -1
- package/src/commands/init.tsx +1 -1
- package/src/commands/projects.tsx +1 -1
- package/src/components/Loading.tsx +1 -1
- package/src/index.tsx +1 -1
- package/src/lib/deploy-api.ts +3 -3
- package/src/lib/framework.ts +2 -2
- package/src/lib/shared.ts +350 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { FRAMEWORKS as SHARED_FRAMEWORKS, getDefaultOutputDirectory, } from "./shared";
|
|
4
|
+
export const FRAMEWORKS = SHARED_FRAMEWORKS;
|
|
5
|
+
export const FRAMEWORK_LIST = Object.entries(SHARED_FRAMEWORKS).map(([id, config]) => ({
|
|
6
|
+
id,
|
|
7
|
+
name: config.label,
|
|
8
|
+
family: config.family,
|
|
9
|
+
isServer: config.isServer,
|
|
10
|
+
}));
|
|
11
|
+
export class FrameworkDetector {
|
|
12
|
+
cwd;
|
|
13
|
+
constructor(cwd = process.cwd()) {
|
|
14
|
+
this.cwd = cwd;
|
|
15
|
+
}
|
|
16
|
+
detect() {
|
|
17
|
+
if (this.hasFile("next.config.js") ||
|
|
18
|
+
this.hasFile("next.config.mjs") ||
|
|
19
|
+
this.hasFile("next.config.ts")) {
|
|
20
|
+
return this.toFramework("nextjs");
|
|
21
|
+
}
|
|
22
|
+
if (this.hasFile("nuxt.config.ts") || this.hasFile("nuxt.config.js")) {
|
|
23
|
+
return this.toFramework("nuxt");
|
|
24
|
+
}
|
|
25
|
+
if (this.hasFile("package.json")) {
|
|
26
|
+
const pkg = this.readPackageJson();
|
|
27
|
+
if (!pkg)
|
|
28
|
+
return null;
|
|
29
|
+
if (pkg.dependencies?.next || pkg.devDependencies?.next) {
|
|
30
|
+
return this.toFramework("nextjs");
|
|
31
|
+
}
|
|
32
|
+
if (pkg.dependencies?.react || pkg.devDependencies?.react) {
|
|
33
|
+
if (pkg.dependencies?.remix)
|
|
34
|
+
return this.toFramework("remix");
|
|
35
|
+
if (pkg.dependencies?.nuxt || pkg.devDependencies?.nuxt)
|
|
36
|
+
return this.toFramework("nuxt");
|
|
37
|
+
if (pkg.dependencies?.svelte || pkg.devDependencies?.svelte)
|
|
38
|
+
return this.toFramework("svelte");
|
|
39
|
+
if (pkg.dependencies?.angular || pkg.devDependencies?.angular)
|
|
40
|
+
return this.toFramework("angular");
|
|
41
|
+
if (pkg.dependencies?.hono || pkg.devDependencies?.hono)
|
|
42
|
+
return this.toFramework("hono");
|
|
43
|
+
if (pkg.dependencies?.nestjs || pkg.devDependencies?.nestjs)
|
|
44
|
+
return this.toFramework("nestjs");
|
|
45
|
+
return this.toFramework("react");
|
|
46
|
+
}
|
|
47
|
+
if (pkg.dependencies?.vue || pkg.devDependencies?.vue) {
|
|
48
|
+
return this.toFramework("vue");
|
|
49
|
+
}
|
|
50
|
+
if (pkg.dependencies?.express || pkg.devDependencies?.express) {
|
|
51
|
+
return this.toFramework("express");
|
|
52
|
+
}
|
|
53
|
+
if (pkg.dependencies?.fastapi || pkg.devDependencies?.fastapi) {
|
|
54
|
+
return this.toFramework("fastapi");
|
|
55
|
+
}
|
|
56
|
+
if (pkg.dependencies?.django || pkg.devDependencies?.django) {
|
|
57
|
+
return this.toFramework("django");
|
|
58
|
+
}
|
|
59
|
+
if (pkg.dependencies?.flask || pkg.devDependencies?.flask) {
|
|
60
|
+
return this.toFramework("flask");
|
|
61
|
+
}
|
|
62
|
+
if (pkg.dependencies?.hono || pkg.devDependencies?.hono) {
|
|
63
|
+
return this.toFramework("hono");
|
|
64
|
+
}
|
|
65
|
+
if (pkg.dependencies?.nestjs || pkg.devDependencies?.nestjs) {
|
|
66
|
+
return this.toFramework("nestjs");
|
|
67
|
+
}
|
|
68
|
+
if (pkg.scripts?.dev || pkg.scripts?.start) {
|
|
69
|
+
return this.toFramework("node");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (this.hasFile("requirements.txt") || this.hasFile("Pipfile")) {
|
|
73
|
+
const content = this.readFile("requirements.txt") || this.readFile("Pipfile") || "";
|
|
74
|
+
if (content.includes("fastapi"))
|
|
75
|
+
return this.toFramework("fastapi");
|
|
76
|
+
if (content.includes("django"))
|
|
77
|
+
return this.toFramework("django");
|
|
78
|
+
if (content.includes("flask"))
|
|
79
|
+
return this.toFramework("flask");
|
|
80
|
+
return this.toFramework("python");
|
|
81
|
+
}
|
|
82
|
+
if (this.hasFile("go.mod")) {
|
|
83
|
+
return this.toFramework("go");
|
|
84
|
+
}
|
|
85
|
+
if (this.hasFile("Cargo.toml")) {
|
|
86
|
+
return this.toFramework("rust");
|
|
87
|
+
}
|
|
88
|
+
if (this.hasFile("index.html")) {
|
|
89
|
+
return this.toFramework("static");
|
|
90
|
+
}
|
|
91
|
+
if (this.hasFile("Dockerfile")) {
|
|
92
|
+
return this.toFramework("docker");
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
detectOutputDirectory(frameworkId) {
|
|
97
|
+
const lowerId = frameworkId.toLowerCase();
|
|
98
|
+
if (this.hasFile("package.json")) {
|
|
99
|
+
const pkg = this.readPackageJson();
|
|
100
|
+
if (pkg) {
|
|
101
|
+
const scripts = pkg.scripts || {};
|
|
102
|
+
if (scripts.build) {
|
|
103
|
+
if (lowerId === "nextjs") {
|
|
104
|
+
if (this.hasFile(".next"))
|
|
105
|
+
return ".next";
|
|
106
|
+
}
|
|
107
|
+
if (lowerId === "react" || lowerId === "vue" || lowerId === "vite") {
|
|
108
|
+
if (this.hasFile("dist"))
|
|
109
|
+
return "dist";
|
|
110
|
+
if (this.hasFile("build"))
|
|
111
|
+
return "build";
|
|
112
|
+
}
|
|
113
|
+
if (lowerId === "nuxt") {
|
|
114
|
+
if (this.hasFile(".output"))
|
|
115
|
+
return ".output";
|
|
116
|
+
}
|
|
117
|
+
if (lowerId === "svelte") {
|
|
118
|
+
if (this.hasFile("build"))
|
|
119
|
+
return "build";
|
|
120
|
+
if (this.hasFile("dist"))
|
|
121
|
+
return "dist";
|
|
122
|
+
}
|
|
123
|
+
if (lowerId === "astro") {
|
|
124
|
+
if (this.hasFile("dist"))
|
|
125
|
+
return "dist";
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return getDefaultOutputDirectory(lowerId) || null;
|
|
131
|
+
}
|
|
132
|
+
toFramework(id) {
|
|
133
|
+
const config = SHARED_FRAMEWORKS[id.toLowerCase()];
|
|
134
|
+
if (!config) {
|
|
135
|
+
return { id, name: id };
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
id,
|
|
139
|
+
name: config.label,
|
|
140
|
+
buildCommand: config.defaults.buildCommand,
|
|
141
|
+
outputDirectory: config.defaults.outputDirectory,
|
|
142
|
+
installCommand: config.defaults.installCommand,
|
|
143
|
+
startCommand: config.defaults.startCommand,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
hasFile(filename) {
|
|
147
|
+
return existsSync(join(this.cwd, filename));
|
|
148
|
+
}
|
|
149
|
+
readFile(filename) {
|
|
150
|
+
try {
|
|
151
|
+
const path = join(this.cwd, filename);
|
|
152
|
+
if (existsSync(path)) {
|
|
153
|
+
return readFileSync(path, "utf-8");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// ignore
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
readPackageJson() {
|
|
162
|
+
try {
|
|
163
|
+
const content = this.readFile("package.json");
|
|
164
|
+
if (content) {
|
|
165
|
+
return JSON.parse(content);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
// ignore
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
getSuggestions() {
|
|
174
|
+
return Object.entries(SHARED_FRAMEWORKS).map(([id, config]) => ({
|
|
175
|
+
id,
|
|
176
|
+
name: config.label,
|
|
177
|
+
buildCommand: config.defaults.buildCommand,
|
|
178
|
+
outputDirectory: config.defaults.outputDirectory,
|
|
179
|
+
installCommand: config.defaults.installCommand,
|
|
180
|
+
startCommand: config.defaults.startCommand,
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
export { getFramework } from "./shared";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface GitRemote {
|
|
2
|
+
name: string;
|
|
3
|
+
url: string;
|
|
4
|
+
type: "github" | "gitlab" | "other";
|
|
5
|
+
}
|
|
6
|
+
export interface GitInfo {
|
|
7
|
+
isGitRepo: boolean;
|
|
8
|
+
remotes: GitRemote[];
|
|
9
|
+
currentBranch: string;
|
|
10
|
+
rootDir: string;
|
|
11
|
+
}
|
|
12
|
+
export declare class GitDetector {
|
|
13
|
+
private cwd;
|
|
14
|
+
constructor(cwd?: string);
|
|
15
|
+
detect(): Promise<GitInfo>;
|
|
16
|
+
private isGitRepository;
|
|
17
|
+
private getRootDir;
|
|
18
|
+
private getCurrentBranch;
|
|
19
|
+
private getRemotes;
|
|
20
|
+
private detectRemoteType;
|
|
21
|
+
getBranches(): Promise<string[]>;
|
|
22
|
+
getRepoId(): Promise<number | null>;
|
|
23
|
+
static getProjectNameFromRepo(repoUrl: string): string;
|
|
24
|
+
static getOwnerFromRepo(repoUrl: string): string;
|
|
25
|
+
}
|
package/dist/lib/git.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
export class GitDetector {
|
|
3
|
+
cwd;
|
|
4
|
+
constructor(cwd = process.cwd()) {
|
|
5
|
+
this.cwd = cwd;
|
|
6
|
+
}
|
|
7
|
+
async detect() {
|
|
8
|
+
try {
|
|
9
|
+
const isGitRepo = this.isGitRepository();
|
|
10
|
+
if (!isGitRepo) {
|
|
11
|
+
return {
|
|
12
|
+
isGitRepo: false,
|
|
13
|
+
remotes: [],
|
|
14
|
+
currentBranch: "",
|
|
15
|
+
rootDir: this.cwd,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const rootDir = this.getRootDir();
|
|
19
|
+
const remotes = this.getRemotes();
|
|
20
|
+
const currentBranch = this.getCurrentBranch();
|
|
21
|
+
return {
|
|
22
|
+
isGitRepo: true,
|
|
23
|
+
remotes,
|
|
24
|
+
currentBranch,
|
|
25
|
+
rootDir,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return {
|
|
30
|
+
isGitRepo: false,
|
|
31
|
+
remotes: [],
|
|
32
|
+
currentBranch: "",
|
|
33
|
+
rootDir: this.cwd,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
isGitRepository() {
|
|
38
|
+
try {
|
|
39
|
+
execSync("git rev-parse --git-dir", {
|
|
40
|
+
cwd: this.cwd,
|
|
41
|
+
stdio: "ignore",
|
|
42
|
+
});
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
getRootDir() {
|
|
50
|
+
try {
|
|
51
|
+
const root = execSync("git rev-parse --show-toplevel", {
|
|
52
|
+
cwd: this.cwd,
|
|
53
|
+
encoding: "utf-8",
|
|
54
|
+
}).trim();
|
|
55
|
+
return root;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return this.cwd;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
getCurrentBranch() {
|
|
62
|
+
try {
|
|
63
|
+
const branch = execSync("git branch --show-current", {
|
|
64
|
+
cwd: this.cwd,
|
|
65
|
+
encoding: "utf-8",
|
|
66
|
+
}).trim();
|
|
67
|
+
return branch;
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return "";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
getRemotes() {
|
|
74
|
+
try {
|
|
75
|
+
const output = execSync("git remote -v", {
|
|
76
|
+
cwd: this.cwd,
|
|
77
|
+
encoding: "utf-8",
|
|
78
|
+
});
|
|
79
|
+
const remotes = [];
|
|
80
|
+
const lines = output.trim().split("\n");
|
|
81
|
+
for (const line of lines) {
|
|
82
|
+
const match = line.match(/^(\S+)\s+(\S+)\s+\((\w+)\)$/);
|
|
83
|
+
if (match) {
|
|
84
|
+
const [, name, url] = match;
|
|
85
|
+
const type = this.detectRemoteType(url);
|
|
86
|
+
if (!remotes.find((r) => r.name === name)) {
|
|
87
|
+
remotes.push({ name, url, type });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return remotes;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
detectRemoteType(url) {
|
|
98
|
+
if (url.includes("github.com"))
|
|
99
|
+
return "github";
|
|
100
|
+
if (url.includes("gitlab.com"))
|
|
101
|
+
return "gitlab";
|
|
102
|
+
return "other";
|
|
103
|
+
}
|
|
104
|
+
async getBranches() {
|
|
105
|
+
try {
|
|
106
|
+
const output = execSync("git branch -a", {
|
|
107
|
+
cwd: this.cwd,
|
|
108
|
+
encoding: "utf-8",
|
|
109
|
+
});
|
|
110
|
+
return output
|
|
111
|
+
.trim()
|
|
112
|
+
.split("\n")
|
|
113
|
+
.map((b) => b.replace(/^\*?\s*/, "").trim())
|
|
114
|
+
.filter((b) => (b && !b.startsWith("remotes/")) || b.startsWith("remotes/origin/"))
|
|
115
|
+
.map((b) => b.replace(/^remotes\/origin\//, ""));
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async getRepoId() {
|
|
122
|
+
try {
|
|
123
|
+
const output = execSync("git remote get-url origin", {
|
|
124
|
+
cwd: this.cwd,
|
|
125
|
+
encoding: "utf-8",
|
|
126
|
+
}).trim();
|
|
127
|
+
const match = output.match(/git@github\.com:(\d+)\//);
|
|
128
|
+
if (match) {
|
|
129
|
+
return parseInt(match[1], 10);
|
|
130
|
+
}
|
|
131
|
+
const urlMatch = output.match(/github\.com\/[^\/]+\/([^\/\.]+)/);
|
|
132
|
+
if (urlMatch) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
static getProjectNameFromRepo(repoUrl) {
|
|
142
|
+
const match = repoUrl.match(/\/([^\/]+?)(?:\.git)?$/);
|
|
143
|
+
return match ? match[1] : "";
|
|
144
|
+
}
|
|
145
|
+
static getOwnerFromRepo(repoUrl) {
|
|
146
|
+
const match = repoUrl.match(/github\.com\/([^\/]+)\//);
|
|
147
|
+
return match ? match[1] : "";
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface ScaffoldProgress {
|
|
2
|
+
stage: "cloning" | "installing" | "cleaning" | "done";
|
|
3
|
+
message: string;
|
|
4
|
+
progress?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class Scaffold {
|
|
7
|
+
private cwd;
|
|
8
|
+
private onProgress?;
|
|
9
|
+
private tempDir;
|
|
10
|
+
constructor(cwd: string, onProgress?: (p: ScaffoldProgress) => void);
|
|
11
|
+
report(progress: ScaffoldProgress): void;
|
|
12
|
+
cloneTemplate(repoUrl: string, branch?: string): Promise<void>;
|
|
13
|
+
installDependencies(packageManager: string): Promise<void>;
|
|
14
|
+
moveFilesToProject(): Promise<void>;
|
|
15
|
+
cleanup(): void;
|
|
16
|
+
scaffold(repoUrl: string, packageManager: string): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
export declare function isGitInstalled(): boolean;
|
|
19
|
+
export declare function isNodeInstalled(): boolean;
|
|
20
|
+
export declare function initGitRepo(cwd: string, remoteUrl?: string): void;
|
|
21
|
+
export declare function generateProjectId(): string;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { existsSync, mkdirSync, cpSync, rmSync, } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
export class Scaffold {
|
|
5
|
+
cwd;
|
|
6
|
+
onProgress;
|
|
7
|
+
tempDir;
|
|
8
|
+
constructor(cwd, onProgress) {
|
|
9
|
+
this.cwd = cwd;
|
|
10
|
+
this.onProgress = onProgress;
|
|
11
|
+
this.tempDir = join("/tmp", `onflyt-scaffold-${Date.now()}`);
|
|
12
|
+
}
|
|
13
|
+
report(progress) {
|
|
14
|
+
if (this.onProgress) {
|
|
15
|
+
this.onProgress(progress);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async cloneTemplate(repoUrl, branch = "main") {
|
|
19
|
+
this.report({
|
|
20
|
+
stage: "cloning",
|
|
21
|
+
message: "Cloning template...",
|
|
22
|
+
progress: 0,
|
|
23
|
+
});
|
|
24
|
+
try {
|
|
25
|
+
mkdirSync(this.tempDir, { recursive: true });
|
|
26
|
+
const gitUrl = repoUrl.endsWith(".git") ? repoUrl : `${repoUrl}.git`;
|
|
27
|
+
execSync(`git clone --depth 1 --branch ${branch} ${gitUrl} "${this.tempDir}"`, { stdio: "pipe" });
|
|
28
|
+
this.report({
|
|
29
|
+
stage: "cloning",
|
|
30
|
+
message: "Template cloned",
|
|
31
|
+
progress: 100,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
this.cleanup();
|
|
36
|
+
throw new Error(`Failed to clone template: ${error.message}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async installDependencies(packageManager) {
|
|
40
|
+
if (!packageManager || packageManager === "none") {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
this.report({
|
|
44
|
+
stage: "installing",
|
|
45
|
+
message: `Installing dependencies with ${packageManager}...`,
|
|
46
|
+
progress: 0,
|
|
47
|
+
});
|
|
48
|
+
try {
|
|
49
|
+
let installCmd = "";
|
|
50
|
+
switch (packageManager) {
|
|
51
|
+
case "npm":
|
|
52
|
+
installCmd = "npm install";
|
|
53
|
+
break;
|
|
54
|
+
case "yarn":
|
|
55
|
+
installCmd = "yarn install";
|
|
56
|
+
break;
|
|
57
|
+
case "pnpm":
|
|
58
|
+
installCmd = "pnpm install";
|
|
59
|
+
break;
|
|
60
|
+
case "pip":
|
|
61
|
+
installCmd = "pip install -r requirements.txt";
|
|
62
|
+
break;
|
|
63
|
+
case "poetry":
|
|
64
|
+
installCmd = "poetry install";
|
|
65
|
+
break;
|
|
66
|
+
default:
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
execSync(installCmd, {
|
|
70
|
+
cwd: this.tempDir,
|
|
71
|
+
stdio: "inherit",
|
|
72
|
+
});
|
|
73
|
+
this.report({
|
|
74
|
+
stage: "installing",
|
|
75
|
+
message: "Dependencies installed",
|
|
76
|
+
progress: 100,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.error(`Warning: Failed to install dependencies: ${error.message}`);
|
|
81
|
+
console.error("You may need to run the install command manually.");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async moveFilesToProject() {
|
|
85
|
+
this.report({
|
|
86
|
+
stage: "cleaning",
|
|
87
|
+
message: "Preparing project files...",
|
|
88
|
+
progress: 50,
|
|
89
|
+
});
|
|
90
|
+
try {
|
|
91
|
+
const items = [
|
|
92
|
+
"package.json",
|
|
93
|
+
"requirements.txt",
|
|
94
|
+
"src",
|
|
95
|
+
"app",
|
|
96
|
+
"lib",
|
|
97
|
+
"components",
|
|
98
|
+
"pages",
|
|
99
|
+
"routes",
|
|
100
|
+
"api",
|
|
101
|
+
"main.py",
|
|
102
|
+
"index.js",
|
|
103
|
+
"server.js",
|
|
104
|
+
"app.js",
|
|
105
|
+
"main.go",
|
|
106
|
+
"Cargo.toml",
|
|
107
|
+
"go.mod",
|
|
108
|
+
"README.md",
|
|
109
|
+
"next.config.js",
|
|
110
|
+
"next.config.mjs",
|
|
111
|
+
"vite.config.ts",
|
|
112
|
+
"vite.config.js",
|
|
113
|
+
"nuxt.config.ts",
|
|
114
|
+
"pyproject.toml",
|
|
115
|
+
];
|
|
116
|
+
for (const item of items) {
|
|
117
|
+
const srcPath = join(this.tempDir, item);
|
|
118
|
+
const destPath = join(this.cwd, item);
|
|
119
|
+
if (existsSync(srcPath) && !existsSync(destPath)) {
|
|
120
|
+
cpSync(srcPath, destPath, { recursive: true });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
this.report({ stage: "cleaning", message: "Files copied", progress: 90 });
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
console.error(`Warning: Failed to copy some files: ${error.message}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
cleanup() {
|
|
130
|
+
try {
|
|
131
|
+
if (existsSync(this.tempDir)) {
|
|
132
|
+
rmSync(this.tempDir, { recursive: true, force: true });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// Ignore cleanup errors
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async scaffold(repoUrl, packageManager) {
|
|
140
|
+
try {
|
|
141
|
+
await this.cloneTemplate(repoUrl);
|
|
142
|
+
await this.installDependencies(packageManager);
|
|
143
|
+
await this.moveFilesToProject();
|
|
144
|
+
this.cleanup();
|
|
145
|
+
this.report({
|
|
146
|
+
stage: "done",
|
|
147
|
+
message: "Project scaffolded",
|
|
148
|
+
progress: 100,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
this.cleanup();
|
|
153
|
+
throw error;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
export function isGitInstalled() {
|
|
158
|
+
try {
|
|
159
|
+
execSync("git --version", { stdio: "ignore" });
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
export function isNodeInstalled() {
|
|
167
|
+
try {
|
|
168
|
+
execSync("node --version", { stdio: "ignore" });
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
export function initGitRepo(cwd, remoteUrl) {
|
|
176
|
+
try {
|
|
177
|
+
execSync("git init", { cwd, stdio: "pipe" });
|
|
178
|
+
if (remoteUrl) {
|
|
179
|
+
execSync(`git remote add origin ${remoteUrl}`, { cwd, stdio: "pipe" });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
throw new Error(`Failed to init git: ${error.message}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
export function generateProjectId() {
|
|
187
|
+
const timestamp = Date.now().toString(36);
|
|
188
|
+
const random = Math.random().toString(36).substring(2, 8);
|
|
189
|
+
return `${timestamp}-${random}`;
|
|
190
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type FrameworkFamily = "node" | "nixpacks";
|
|
2
|
+
export type DeploymentType = "static" | "container";
|
|
3
|
+
export interface FrameworkDefaults {
|
|
4
|
+
buildCommand?: string;
|
|
5
|
+
installCommand?: string;
|
|
6
|
+
outputDirectory?: string;
|
|
7
|
+
startCommand?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface FrameworkConfig {
|
|
10
|
+
label: string;
|
|
11
|
+
family: FrameworkFamily;
|
|
12
|
+
deploymentType: DeploymentType;
|
|
13
|
+
defaults: FrameworkDefaults;
|
|
14
|
+
isServer: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare const FRAMEWORKS: Record<string, FrameworkConfig>;
|
|
17
|
+
export declare function getFramework(id: string): FrameworkConfig | undefined;
|
|
18
|
+
export declare function getDefaultBuildCommand(frameworkId: string): string | undefined;
|
|
19
|
+
export declare function getDefaultOutputDirectory(frameworkId: string): string | undefined;
|
|
20
|
+
export declare function getDefaultStartCommand(frameworkId: string): string | undefined;
|
|
21
|
+
export declare function getInstallCommand(frameworkId: string, packageManager: string): string;
|