@titanpl/cli 2.0.0 → 2.0.2
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/README.md +17 -17
- package/index.js +160 -160
- package/package.json +5 -5
- package/src/commands/build.js +5 -5
- package/src/commands/dev.js +12 -5
- package/src/commands/init.js +196 -182
- package/src/commands/migrate.js +124 -106
- package/src/commands/start.js +4 -4
- package/src/commands/update.js +90 -90
- package/src/engine.js +152 -143
package/src/commands/init.js
CHANGED
|
@@ -1,182 +1,196 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { fileURLToPath } from 'url';
|
|
4
|
-
import {
|
|
5
|
-
import prompts from 'prompts';
|
|
6
|
-
import chalk from 'chalk';
|
|
7
|
-
|
|
8
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
-
const __dirname = path.dirname(__filename);
|
|
10
|
-
|
|
11
|
-
export function copyDir(src, dest, excludes = []) {
|
|
12
|
-
fs.mkdirSync(dest, { recursive: true });
|
|
13
|
-
|
|
14
|
-
for (const file of fs.readdirSync(src)) {
|
|
15
|
-
if (excludes.includes(file)) continue;
|
|
16
|
-
|
|
17
|
-
const srcPath = path.join(src, file);
|
|
18
|
-
const destPath = path.join(dest, file);
|
|
19
|
-
|
|
20
|
-
if (fs.lstatSync(srcPath).isDirectory()) {
|
|
21
|
-
copyDir(srcPath, destPath, excludes);
|
|
22
|
-
} else {
|
|
23
|
-
fs.copyFileSync(srcPath, destPath);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export async function initCommand(projectName, templateName) {
|
|
29
|
-
let projName = projectName;
|
|
30
|
-
|
|
31
|
-
if (!projName) {
|
|
32
|
-
const res = await prompts({
|
|
33
|
-
type: 'text',
|
|
34
|
-
name: 'name',
|
|
35
|
-
message: 'Project name:',
|
|
36
|
-
initial: 'my-titan-app'
|
|
37
|
-
});
|
|
38
|
-
projName = res.name;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (!projName) {
|
|
42
|
-
console.log(chalk.red("✖ Initialization cancelled."));
|
|
43
|
-
process.exit(1);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
let selectedTemplate = templateName;
|
|
47
|
-
|
|
48
|
-
if (!selectedTemplate) {
|
|
49
|
-
const langRes = await prompts({
|
|
50
|
-
type: 'select',
|
|
51
|
-
name: 'value',
|
|
52
|
-
message: 'Select language:',
|
|
53
|
-
choices: [
|
|
54
|
-
{ title: 'JavaScript', value: 'js' },
|
|
55
|
-
{ title: 'TypeScript', value: 'ts' },
|
|
56
|
-
],
|
|
57
|
-
initial: 0
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
if (!langRes.value) {
|
|
61
|
-
console.log(chalk.red("✖ Operation cancelled."));
|
|
62
|
-
process.exit(1);
|
|
63
|
-
}
|
|
64
|
-
const lang = langRes.value;
|
|
65
|
-
|
|
66
|
-
const archRes = await prompts({
|
|
67
|
-
type: 'select',
|
|
68
|
-
name: 'value',
|
|
69
|
-
message: 'Select template:',
|
|
70
|
-
choices: [
|
|
71
|
-
{
|
|
72
|
-
title: `Standard (${lang.toUpperCase()})`,
|
|
73
|
-
description: `Standard Titan app with ${lang.toUpperCase()} actions`,
|
|
74
|
-
value: 'standard'
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
title: `Rust + ${lang.toUpperCase()} (Hybrid)`,
|
|
78
|
-
description: `High-performance Rust actions + ${lang.toUpperCase()} flexibility`,
|
|
79
|
-
value: 'hybrid'
|
|
80
|
-
}
|
|
81
|
-
],
|
|
82
|
-
initial: 0
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
if (!archRes.value) {
|
|
86
|
-
console.log(chalk.red("✖ Operation cancelled."));
|
|
87
|
-
process.exit(1);
|
|
88
|
-
}
|
|
89
|
-
const arch = archRes.value;
|
|
90
|
-
|
|
91
|
-
if (lang === 'js') {
|
|
92
|
-
selectedTemplate = arch === 'standard' ? 'js' : 'rust-js';
|
|
93
|
-
} else {
|
|
94
|
-
selectedTemplate = arch === 'standard' ? 'ts' : 'rust-ts';
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const target = path.resolve(process.cwd(), projName);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
process.
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { execSync } from 'child_process';
|
|
5
|
+
import prompts from 'prompts';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
10
|
+
|
|
11
|
+
export function copyDir(src, dest, excludes = []) {
|
|
12
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
13
|
+
|
|
14
|
+
for (const file of fs.readdirSync(src)) {
|
|
15
|
+
if (excludes.includes(file)) continue;
|
|
16
|
+
|
|
17
|
+
const srcPath = path.join(src, file);
|
|
18
|
+
const destPath = path.join(dest, file);
|
|
19
|
+
|
|
20
|
+
if (fs.lstatSync(srcPath).isDirectory()) {
|
|
21
|
+
copyDir(srcPath, destPath, excludes);
|
|
22
|
+
} else {
|
|
23
|
+
fs.copyFileSync(srcPath, destPath);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export async function initCommand(projectName, templateName) {
|
|
29
|
+
let projName = projectName;
|
|
30
|
+
|
|
31
|
+
if (!projName) {
|
|
32
|
+
const res = await prompts({
|
|
33
|
+
type: 'text',
|
|
34
|
+
name: 'name',
|
|
35
|
+
message: 'Project name:',
|
|
36
|
+
initial: 'my-titan-app'
|
|
37
|
+
});
|
|
38
|
+
projName = res.name;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!projName) {
|
|
42
|
+
console.log(chalk.red("✖ Initialization cancelled."));
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let selectedTemplate = templateName;
|
|
47
|
+
|
|
48
|
+
if (!selectedTemplate) {
|
|
49
|
+
const langRes = await prompts({
|
|
50
|
+
type: 'select',
|
|
51
|
+
name: 'value',
|
|
52
|
+
message: 'Select language:',
|
|
53
|
+
choices: [
|
|
54
|
+
{ title: 'JavaScript', value: 'js' },
|
|
55
|
+
{ title: 'TypeScript', value: 'ts' },
|
|
56
|
+
],
|
|
57
|
+
initial: 0
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (!langRes.value) {
|
|
61
|
+
console.log(chalk.red("✖ Operation cancelled."));
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
const lang = langRes.value;
|
|
65
|
+
|
|
66
|
+
const archRes = await prompts({
|
|
67
|
+
type: 'select',
|
|
68
|
+
name: 'value',
|
|
69
|
+
message: 'Select template:',
|
|
70
|
+
choices: [
|
|
71
|
+
{
|
|
72
|
+
title: `Standard (${lang.toUpperCase()})`,
|
|
73
|
+
description: `Standard Titan app with ${lang.toUpperCase()} actions`,
|
|
74
|
+
value: 'standard'
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
title: `Rust + ${lang.toUpperCase()} (Hybrid)`,
|
|
78
|
+
description: `High-performance Rust actions + ${lang.toUpperCase()} flexibility`,
|
|
79
|
+
value: 'hybrid'
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
initial: 0
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
if (!archRes.value) {
|
|
86
|
+
console.log(chalk.red("✖ Operation cancelled."));
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
const arch = archRes.value;
|
|
90
|
+
|
|
91
|
+
if (lang === 'js') {
|
|
92
|
+
selectedTemplate = arch === 'standard' ? 'js' : 'rust-js';
|
|
93
|
+
} else {
|
|
94
|
+
selectedTemplate = arch === 'standard' ? 'ts' : 'rust-ts';
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const target = path.resolve(process.cwd(), projName);
|
|
99
|
+
let templateDir = path.resolve(__dirname, '..', '..', '..', '..', 'templates', selectedTemplate);
|
|
100
|
+
let commonDir = path.resolve(__dirname, '..', '..', '..', '..', 'templates', 'common');
|
|
101
|
+
|
|
102
|
+
// Robust monorepo/fallback template search: look upwards from cwd
|
|
103
|
+
if (!fs.existsSync(templateDir) || !fs.existsSync(commonDir)) {
|
|
104
|
+
let searchDir = process.cwd();
|
|
105
|
+
while (searchDir !== path.parse(searchDir).root) {
|
|
106
|
+
const potentialTemplateDir = path.join(searchDir, 'templates', selectedTemplate);
|
|
107
|
+
const potentialCommonDir = path.join(searchDir, 'templates', 'common');
|
|
108
|
+
if (fs.existsSync(potentialTemplateDir) && fs.existsSync(potentialCommonDir)) {
|
|
109
|
+
templateDir = potentialTemplateDir;
|
|
110
|
+
commonDir = potentialCommonDir;
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
const sdkPotentialTemplateDir = path.join(searchDir, 'titanpl-sdk', 'templates', selectedTemplate);
|
|
114
|
+
const sdkPotentialCommonDir = path.join(searchDir, 'titanpl-sdk', 'templates', 'common');
|
|
115
|
+
if (fs.existsSync(sdkPotentialTemplateDir) && fs.existsSync(sdkPotentialCommonDir)) {
|
|
116
|
+
templateDir = sdkPotentialTemplateDir;
|
|
117
|
+
commonDir = sdkPotentialCommonDir;
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
searchDir = path.dirname(searchDir);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!fs.existsSync(templateDir) || !fs.existsSync(commonDir)) {
|
|
125
|
+
console.log(chalk.red(`✖ Error finding template paths. Are you in a valid Titan monorepo?`));
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (fs.existsSync(target)) {
|
|
130
|
+
console.log(chalk.red(`✖ Directory '${projName}' already exists.`));
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
console.log(chalk.cyan(`\n→ Creating new Titan project in '${projName}'...\n`));
|
|
135
|
+
|
|
136
|
+
// 1. Copy common
|
|
137
|
+
copyDir(commonDir, target);
|
|
138
|
+
|
|
139
|
+
// 2. Copy specific template
|
|
140
|
+
copyDir(templateDir, target);
|
|
141
|
+
|
|
142
|
+
// 3. Dotfiles and Template Remapping
|
|
143
|
+
const remapping = {
|
|
144
|
+
"_gitignore": ".gitignore",
|
|
145
|
+
"_dockerignore": ".dockerignore",
|
|
146
|
+
"_titan.json": "titan.json",
|
|
147
|
+
".env": ".env"
|
|
148
|
+
};
|
|
149
|
+
for (const [srcName, destName] of Object.entries(remapping)) {
|
|
150
|
+
const src = path.join(target, srcName);
|
|
151
|
+
const dest = path.join(target, destName);
|
|
152
|
+
if (fs.existsSync(src)) {
|
|
153
|
+
fs.renameSync(src, dest);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Recursive template substitution
|
|
158
|
+
const substitute = (dir) => {
|
|
159
|
+
for (const file of fs.readdirSync(dir)) {
|
|
160
|
+
const fullPath = path.join(dir, file);
|
|
161
|
+
if (fs.lstatSync(fullPath).isDirectory()) {
|
|
162
|
+
if (file !== "node_modules" && file !== ".git" && file !== "target") {
|
|
163
|
+
substitute(fullPath);
|
|
164
|
+
}
|
|
165
|
+
} else {
|
|
166
|
+
// Only process text files
|
|
167
|
+
const ext = path.extname(file).toLowerCase();
|
|
168
|
+
const textExts = ['.js', '.ts', '.json', '.md', '.txt', '.rs', '.toml', '.html', '.css', '.d.ts'];
|
|
169
|
+
if (textExts.includes(ext) || file === ".env" || file === "Dockerfile") {
|
|
170
|
+
let content = fs.readFileSync(fullPath, 'utf8');
|
|
171
|
+
let changed = false;
|
|
172
|
+
if (content.includes("{{name}}")) {
|
|
173
|
+
content = content.replace(/{{name}}/g, projName);
|
|
174
|
+
changed = true;
|
|
175
|
+
}
|
|
176
|
+
if (content.includes("{{native_name}}")) {
|
|
177
|
+
content = content.replace(/{{native_name}}/g, projName.replace(/-/g, '_'));
|
|
178
|
+
changed = true;
|
|
179
|
+
}
|
|
180
|
+
if (changed) {
|
|
181
|
+
fs.writeFileSync(fullPath, content);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
substitute(target);
|
|
188
|
+
|
|
189
|
+
console.log(chalk.gray(` Installing dependencies...`));
|
|
190
|
+
|
|
191
|
+
execSync('npm install', { cwd: target, stdio: 'inherit' });
|
|
192
|
+
|
|
193
|
+
console.log(chalk.green(`\n✔ Project '${projName}' created successfully!\n`));
|
|
194
|
+
console.log(chalk.yellow(` cd ${projName}`));
|
|
195
|
+
console.log(chalk.yellow(` npm run dev\n`));
|
|
196
|
+
}
|
package/src/commands/migrate.js
CHANGED
|
@@ -1,106 +1,124 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (pkg.scripts.
|
|
45
|
-
pkg.scripts.
|
|
46
|
-
modified = true;
|
|
47
|
-
}
|
|
48
|
-
if (pkg.scripts.
|
|
49
|
-
pkg.scripts.
|
|
50
|
-
modified = true;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
export async function migrateCommand() {
|
|
9
|
+
const root = process.cwd();
|
|
10
|
+
console.log(`\n🔍 Checking project for legacy Titan architecture...`);
|
|
11
|
+
|
|
12
|
+
const serverDir = path.join(root, 'server');
|
|
13
|
+
const titanDir = path.join(root, 'titan');
|
|
14
|
+
const pkgPath = path.join(root, 'package.json');
|
|
15
|
+
|
|
16
|
+
if (!fs.existsSync(serverDir) && !fs.existsSync(titanDir)) {
|
|
17
|
+
console.log(`✅ This project is already using the modern Titan runtime architecture.`);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log(`\n⚠️ Legacy server architecture detected. Migrating to runtime-first model...`);
|
|
22
|
+
|
|
23
|
+
// 1. Delete server/
|
|
24
|
+
if (fs.existsSync(serverDir)) {
|
|
25
|
+
console.log(` Deleting legacy server/ folder...`);
|
|
26
|
+
fs.rmSync(serverDir, { recursive: true, force: true });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// 2. Delete titan/ folder
|
|
30
|
+
if (fs.existsSync(titanDir)) {
|
|
31
|
+
console.log(` Deleting legacy titan/ runtime folder...`);
|
|
32
|
+
fs.rmSync(titanDir, { recursive: true, force: true });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 3. Update package.json
|
|
36
|
+
if (fs.existsSync(pkgPath)) {
|
|
37
|
+
console.log(` Updating package.json...`);
|
|
38
|
+
try {
|
|
39
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
40
|
+
let modified = false;
|
|
41
|
+
|
|
42
|
+
// Update scripts
|
|
43
|
+
if (pkg.scripts) {
|
|
44
|
+
if (pkg.scripts.build && pkg.scripts.build.includes('cd server')) {
|
|
45
|
+
pkg.scripts.build = "titan build";
|
|
46
|
+
modified = true;
|
|
47
|
+
}
|
|
48
|
+
if (pkg.scripts.start && pkg.scripts.start.includes('cd server')) {
|
|
49
|
+
pkg.scripts.start = "titan start";
|
|
50
|
+
modified = true;
|
|
51
|
+
}
|
|
52
|
+
if (pkg.scripts.dev && pkg.scripts.dev.includes('titan/dev.js')) {
|
|
53
|
+
pkg.scripts.dev = "titan dev";
|
|
54
|
+
modified = true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Add / fix dependencies — ensure correct @titanpl/ scope
|
|
59
|
+
pkg.dependencies = pkg.dependencies || {};
|
|
60
|
+
|
|
61
|
+
// Remove any stale old-scope packages (@titan/ typo) that may exist
|
|
62
|
+
const stalePackages = ['@titanp/native', '@titan/route', '@titan/cli', '@titan/packet'];
|
|
63
|
+
for (const stale of stalePackages) {
|
|
64
|
+
if (pkg.dependencies[stale]) {
|
|
65
|
+
delete pkg.dependencies[stale];
|
|
66
|
+
modified = true;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const requiredDeps = {
|
|
71
|
+
'@titanpl/cli': 'latest',
|
|
72
|
+
'@titanpl/route': 'latest',
|
|
73
|
+
'@titanpl/native': 'latest',
|
|
74
|
+
'@titanpl/packet': 'latest',
|
|
75
|
+
};
|
|
76
|
+
for (const [dep, version] of Object.entries(requiredDeps)) {
|
|
77
|
+
if (!pkg.dependencies[dep]) {
|
|
78
|
+
pkg.dependencies[dep] = version;
|
|
79
|
+
modified = true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (modified) {
|
|
84
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
|
|
85
|
+
}
|
|
86
|
+
} catch (e) {
|
|
87
|
+
console.log(` ⚠️ Failed to update package.json automatically. Please do it manually.`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 4. Synchronize Dockerfile and other common files
|
|
92
|
+
try {
|
|
93
|
+
const commonDir = path.resolve(__dirname, '..', '..', '..', '..', 'templates', 'common');
|
|
94
|
+
if (fs.existsSync(commonDir)) {
|
|
95
|
+
const filesToSync = [
|
|
96
|
+
['Dockerfile', 'Dockerfile'],
|
|
97
|
+
['_dockerignore', '.dockerignore'],
|
|
98
|
+
['_gitignore', '.gitignore'],
|
|
99
|
+
['app/t.native.d.ts', 'app/t.native.d.ts'],
|
|
100
|
+
['app/t.native.js', 'app/t.native.js']
|
|
101
|
+
];
|
|
102
|
+
|
|
103
|
+
for (const [srcRel, destRel] of filesToSync) {
|
|
104
|
+
const src = path.join(commonDir, srcRel);
|
|
105
|
+
const dest = path.join(root, destRel);
|
|
106
|
+
if (fs.existsSync(src)) {
|
|
107
|
+
// Create parent dir if needed
|
|
108
|
+
const parent = path.dirname(dest);
|
|
109
|
+
if (!fs.existsSync(parent)) {
|
|
110
|
+
fs.mkdirSync(parent, { recursive: true });
|
|
111
|
+
}
|
|
112
|
+
fs.copyFileSync(src, dest);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
console.log(` Synchronized Dockerfiles and native definitions.`);
|
|
116
|
+
}
|
|
117
|
+
} catch (e) {
|
|
118
|
+
console.log(` ⚠️ Failed to synchronize common template files.`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
console.log(`\n🎉 Migration complete!`);
|
|
122
|
+
console.log(` Please run 'npm install' to fetch the new dependencies.`);
|
|
123
|
+
console.log(` Then run 'titan dev' to start your application.\n`);
|
|
124
|
+
}
|
package/src/commands/start.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { startEngine } from "../engine.js";
|
|
2
|
-
|
|
3
|
-
export function startCommand() {
|
|
4
|
-
startEngine(false);
|
|
1
|
+
import { startEngine } from "../engine.js";
|
|
2
|
+
|
|
3
|
+
export function startCommand() {
|
|
4
|
+
startEngine(false);
|
|
5
5
|
}
|