@frontman-ai/astro 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/README.md +53 -0
- package/dist/cli.js +2744 -0
- package/package.json +66 -0
- package/src/FrontmanAstro.res +20 -0
- package/src/FrontmanAstro.res.mjs +36 -0
- package/src/FrontmanAstro__AstroBindings.res +46 -0
- package/src/FrontmanAstro__AstroBindings.res.mjs +2 -0
- package/src/FrontmanAstro__Config.res +85 -0
- package/src/FrontmanAstro__Config.res.mjs +44 -0
- package/src/FrontmanAstro__Integration.res +35 -0
- package/src/FrontmanAstro__Integration.res.mjs +36 -0
- package/src/FrontmanAstro__Middleware.res +149 -0
- package/src/FrontmanAstro__Middleware.res.mjs +141 -0
- package/src/FrontmanAstro__Server.res +196 -0
- package/src/FrontmanAstro__Server.res.mjs +241 -0
- package/src/FrontmanAstro__ToolRegistry.res +21 -0
- package/src/FrontmanAstro__ToolRegistry.res.mjs +41 -0
- package/src/FrontmanAstro__ToolbarApp.res +50 -0
- package/src/FrontmanAstro__ToolbarApp.res.mjs +39 -0
- package/src/cli/FrontmanAstro__Cli.res +126 -0
- package/src/cli/FrontmanAstro__Cli.res.mjs +180 -0
- package/src/cli/FrontmanAstro__Cli__AutoEdit.res +300 -0
- package/src/cli/FrontmanAstro__Cli__AutoEdit.res.mjs +266 -0
- package/src/cli/FrontmanAstro__Cli__Detect.res +298 -0
- package/src/cli/FrontmanAstro__Cli__Detect.res.mjs +345 -0
- package/src/cli/FrontmanAstro__Cli__Files.res +244 -0
- package/src/cli/FrontmanAstro__Cli__Files.res.mjs +321 -0
- package/src/cli/FrontmanAstro__Cli__Install.res +224 -0
- package/src/cli/FrontmanAstro__Cli__Install.res.mjs +194 -0
- package/src/cli/FrontmanAstro__Cli__Style.res +22 -0
- package/src/cli/FrontmanAstro__Cli__Style.res.mjs +61 -0
- package/src/cli/FrontmanAstro__Cli__Templates.res +226 -0
- package/src/cli/FrontmanAstro__Cli__Templates.res.mjs +237 -0
- package/src/cli/cli.mjs +3 -0
- package/src/tools/FrontmanAstro__Tool__GetPages.res +164 -0
- package/src/tools/FrontmanAstro__Tool__GetPages.res.mjs +180 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Fs from "fs";
|
|
4
|
+
import * as Nodepath from "node:path";
|
|
5
|
+
import * as FrontmanAstro__Cli__AutoEdit$FrontmanAiAstro from "./FrontmanAstro__Cli__AutoEdit.res.mjs";
|
|
6
|
+
import * as FrontmanAstro__Cli__Templates$FrontmanAiAstro from "./FrontmanAstro__Cli__Templates.res.mjs";
|
|
7
|
+
|
|
8
|
+
let hostPattern = /host:\s*['\"]([^'\"]+)['\"]/;
|
|
9
|
+
|
|
10
|
+
let escapeReplacement = (function(str) { return str.replace(/\$/g, '$$$$'); });
|
|
11
|
+
|
|
12
|
+
function updateHostInContent(content, newHost) {
|
|
13
|
+
let safeHost = escapeReplacement(newHost);
|
|
14
|
+
return content.replace(hostPattern, `host: '` + safeHost + `'`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function readFile(path) {
|
|
18
|
+
try {
|
|
19
|
+
return await Fs.promises.readFile(path, "utf8");
|
|
20
|
+
} catch (exn) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function writeFile(path, content) {
|
|
26
|
+
try {
|
|
27
|
+
await Fs.promises.writeFile(path, content, "utf8");
|
|
28
|
+
return {
|
|
29
|
+
TAG: "Ok",
|
|
30
|
+
_0: undefined
|
|
31
|
+
};
|
|
32
|
+
} catch (exn) {
|
|
33
|
+
return {
|
|
34
|
+
TAG: "Error",
|
|
35
|
+
_0: `Failed to write ` + path
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function handleNeedsManualEdit(filePath, fileName, host, fileType, dryRun, autoEdit, manualDetails) {
|
|
41
|
+
if (dryRun) {
|
|
42
|
+
return {
|
|
43
|
+
TAG: "Ok",
|
|
44
|
+
_0: {
|
|
45
|
+
TAG: "ManualEditRequired",
|
|
46
|
+
fileName: fileName,
|
|
47
|
+
details: manualDetails
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
if (!autoEdit) {
|
|
52
|
+
return {
|
|
53
|
+
TAG: "Ok",
|
|
54
|
+
_0: {
|
|
55
|
+
TAG: "ManualEditRequired",
|
|
56
|
+
fileName: fileName,
|
|
57
|
+
details: manualDetails
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
let existingContent = await readFile(filePath);
|
|
62
|
+
if (existingContent === undefined) {
|
|
63
|
+
return {
|
|
64
|
+
TAG: "Ok",
|
|
65
|
+
_0: {
|
|
66
|
+
TAG: "ManualEditRequired",
|
|
67
|
+
fileName: fileName,
|
|
68
|
+
details: manualDetails
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
let name = await FrontmanAstro__Cli__AutoEdit$FrontmanAiAstro.autoEditFile(filePath, fileName, existingContent, fileType, host);
|
|
73
|
+
if (name.TAG === "AutoEdited") {
|
|
74
|
+
return {
|
|
75
|
+
TAG: "Ok",
|
|
76
|
+
_0: {
|
|
77
|
+
TAG: "AutoEdited",
|
|
78
|
+
_0: name._0
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
console.log(FrontmanAstro__Cli__Templates$FrontmanAiAstro.SuccessMessages.autoEditFailed(fileName, name._0));
|
|
83
|
+
console.log(` Falling back to manual instructions.`);
|
|
84
|
+
return {
|
|
85
|
+
TAG: "Ok",
|
|
86
|
+
_0: {
|
|
87
|
+
TAG: "ManualEditRequired",
|
|
88
|
+
fileName: fileName,
|
|
89
|
+
details: manualDetails
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function getPendingAutoEdit(existingFile, filePath, fileName, fileType, manualDetails) {
|
|
95
|
+
if (typeof existingFile !== "object" && existingFile !== "NotFound") {
|
|
96
|
+
return {
|
|
97
|
+
filePath: filePath,
|
|
98
|
+
fileName: fileName,
|
|
99
|
+
fileType: fileType,
|
|
100
|
+
manualDetails: manualDetails
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function handleConfig(projectDir, host, configFileName, existingFile, dryRun, autoEditOpt) {
|
|
106
|
+
let autoEdit = autoEditOpt !== undefined ? autoEditOpt : false;
|
|
107
|
+
let filePath = Nodepath.join(projectDir, configFileName);
|
|
108
|
+
if (typeof existingFile !== "object") {
|
|
109
|
+
if (existingFile !== "NotFound") {
|
|
110
|
+
return await handleNeedsManualEdit(filePath, configFileName, host, "Config", dryRun, autoEdit, FrontmanAstro__Cli__Templates$FrontmanAiAstro.ManualInstructions.config(configFileName, host));
|
|
111
|
+
}
|
|
112
|
+
if (dryRun) {
|
|
113
|
+
return {
|
|
114
|
+
TAG: "Ok",
|
|
115
|
+
_0: {
|
|
116
|
+
TAG: "Created",
|
|
117
|
+
_0: configFileName
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
let content = FrontmanAstro__Cli__Templates$FrontmanAiAstro.configTemplate(host);
|
|
122
|
+
let e = await writeFile(filePath, content);
|
|
123
|
+
if (e.TAG === "Ok") {
|
|
124
|
+
return {
|
|
125
|
+
TAG: "Ok",
|
|
126
|
+
_0: {
|
|
127
|
+
TAG: "Created",
|
|
128
|
+
_0: configFileName
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
} else {
|
|
132
|
+
return {
|
|
133
|
+
TAG: "Error",
|
|
134
|
+
_0: e._0
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
let existingHost = existingFile.host;
|
|
139
|
+
if (existingHost === host || existingHost === "") {
|
|
140
|
+
return {
|
|
141
|
+
TAG: "Ok",
|
|
142
|
+
_0: {
|
|
143
|
+
TAG: "Skipped",
|
|
144
|
+
_0: configFileName
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (dryRun) {
|
|
149
|
+
return {
|
|
150
|
+
TAG: "Ok",
|
|
151
|
+
_0: {
|
|
152
|
+
TAG: "Updated",
|
|
153
|
+
fileName: configFileName,
|
|
154
|
+
oldHost: existingHost,
|
|
155
|
+
newHost: host
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
let content$1 = await readFile(filePath);
|
|
160
|
+
if (content$1 === undefined) {
|
|
161
|
+
return {
|
|
162
|
+
TAG: "Error",
|
|
163
|
+
_0: `Failed to read ` + configFileName
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
let newContent = updateHostInContent(content$1, host);
|
|
167
|
+
let e$1 = await writeFile(filePath, newContent);
|
|
168
|
+
if (e$1.TAG === "Ok") {
|
|
169
|
+
return {
|
|
170
|
+
TAG: "Ok",
|
|
171
|
+
_0: {
|
|
172
|
+
TAG: "Updated",
|
|
173
|
+
fileName: configFileName,
|
|
174
|
+
oldHost: existingHost,
|
|
175
|
+
newHost: host
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
} else {
|
|
179
|
+
return {
|
|
180
|
+
TAG: "Error",
|
|
181
|
+
_0: e$1._0
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async function handleMiddleware(projectDir, host, middlewareFileName, existingFile, dryRun, autoEditOpt) {
|
|
188
|
+
let autoEdit = autoEditOpt !== undefined ? autoEditOpt : false;
|
|
189
|
+
let filePath = Nodepath.join(projectDir, middlewareFileName);
|
|
190
|
+
if (typeof existingFile !== "object") {
|
|
191
|
+
if (existingFile !== "NotFound") {
|
|
192
|
+
return await handleNeedsManualEdit(filePath, middlewareFileName, host, "Middleware", dryRun, autoEdit, FrontmanAstro__Cli__Templates$FrontmanAiAstro.ManualInstructions.middleware(middlewareFileName, host));
|
|
193
|
+
}
|
|
194
|
+
if (dryRun) {
|
|
195
|
+
return {
|
|
196
|
+
TAG: "Ok",
|
|
197
|
+
_0: {
|
|
198
|
+
TAG: "Created",
|
|
199
|
+
_0: middlewareFileName
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
let srcDir = Nodepath.join(projectDir, "src");
|
|
204
|
+
await Fs.promises.mkdir(srcDir, {
|
|
205
|
+
recursive: true
|
|
206
|
+
});
|
|
207
|
+
let content = FrontmanAstro__Cli__Templates$FrontmanAiAstro.middlewareTemplate(host);
|
|
208
|
+
let e = await writeFile(filePath, content);
|
|
209
|
+
if (e.TAG === "Ok") {
|
|
210
|
+
return {
|
|
211
|
+
TAG: "Ok",
|
|
212
|
+
_0: {
|
|
213
|
+
TAG: "Created",
|
|
214
|
+
_0: middlewareFileName
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
} else {
|
|
218
|
+
return {
|
|
219
|
+
TAG: "Error",
|
|
220
|
+
_0: e._0
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
} else {
|
|
224
|
+
let existingHost = existingFile.host;
|
|
225
|
+
if (existingHost === host || existingHost === "") {
|
|
226
|
+
return {
|
|
227
|
+
TAG: "Ok",
|
|
228
|
+
_0: {
|
|
229
|
+
TAG: "Skipped",
|
|
230
|
+
_0: middlewareFileName
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
if (dryRun) {
|
|
235
|
+
return {
|
|
236
|
+
TAG: "Ok",
|
|
237
|
+
_0: {
|
|
238
|
+
TAG: "Updated",
|
|
239
|
+
fileName: middlewareFileName,
|
|
240
|
+
oldHost: existingHost,
|
|
241
|
+
newHost: host
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
let content$1 = await readFile(filePath);
|
|
246
|
+
if (content$1 === undefined) {
|
|
247
|
+
return {
|
|
248
|
+
TAG: "Error",
|
|
249
|
+
_0: `Failed to read ` + middlewareFileName
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
let newContent = updateHostInContent(content$1, host);
|
|
253
|
+
let e$1 = await writeFile(filePath, newContent);
|
|
254
|
+
if (e$1.TAG === "Ok") {
|
|
255
|
+
return {
|
|
256
|
+
TAG: "Ok",
|
|
257
|
+
_0: {
|
|
258
|
+
TAG: "Updated",
|
|
259
|
+
fileName: middlewareFileName,
|
|
260
|
+
oldHost: existingHost,
|
|
261
|
+
newHost: host
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
} else {
|
|
265
|
+
return {
|
|
266
|
+
TAG: "Error",
|
|
267
|
+
_0: e$1._0
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function formatResult(result) {
|
|
274
|
+
switch (result.TAG) {
|
|
275
|
+
case "Created" :
|
|
276
|
+
return FrontmanAstro__Cli__Templates$FrontmanAiAstro.SuccessMessages.fileCreated(result._0);
|
|
277
|
+
case "Updated" :
|
|
278
|
+
return FrontmanAstro__Cli__Templates$FrontmanAiAstro.SuccessMessages.hostUpdated(result.fileName, result.oldHost, result.newHost);
|
|
279
|
+
case "Skipped" :
|
|
280
|
+
return FrontmanAstro__Cli__Templates$FrontmanAiAstro.SuccessMessages.fileSkipped(result._0);
|
|
281
|
+
case "ManualEditRequired" :
|
|
282
|
+
return FrontmanAstro__Cli__Templates$FrontmanAiAstro.SuccessMessages.manualEditRequired(result.fileName);
|
|
283
|
+
case "AutoEdited" :
|
|
284
|
+
return FrontmanAstro__Cli__Templates$FrontmanAiAstro.SuccessMessages.fileAutoEdited(result._0);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
let Bindings;
|
|
289
|
+
|
|
290
|
+
let Fs$1;
|
|
291
|
+
|
|
292
|
+
let Path;
|
|
293
|
+
|
|
294
|
+
let Detect;
|
|
295
|
+
|
|
296
|
+
let Templates;
|
|
297
|
+
|
|
298
|
+
let AutoEdit;
|
|
299
|
+
|
|
300
|
+
let Style;
|
|
301
|
+
|
|
302
|
+
export {
|
|
303
|
+
Bindings,
|
|
304
|
+
Fs$1 as Fs,
|
|
305
|
+
Path,
|
|
306
|
+
Detect,
|
|
307
|
+
Templates,
|
|
308
|
+
AutoEdit,
|
|
309
|
+
Style,
|
|
310
|
+
hostPattern,
|
|
311
|
+
escapeReplacement,
|
|
312
|
+
updateHostInContent,
|
|
313
|
+
readFile,
|
|
314
|
+
writeFile,
|
|
315
|
+
handleNeedsManualEdit,
|
|
316
|
+
getPendingAutoEdit,
|
|
317
|
+
handleConfig,
|
|
318
|
+
handleMiddleware,
|
|
319
|
+
formatResult,
|
|
320
|
+
}
|
|
321
|
+
/* fs Not a pure module */
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
// Install command implementation
|
|
2
|
+
module Bindings = FrontmanBindings
|
|
3
|
+
module ChildProcess = Bindings.ChildProcess
|
|
4
|
+
module Path = Bindings.Path
|
|
5
|
+
module Process = Bindings.Process
|
|
6
|
+
|
|
7
|
+
module AutoEdit = FrontmanAstro__Cli__AutoEdit
|
|
8
|
+
module Detect = FrontmanAstro__Cli__Detect
|
|
9
|
+
module Files = FrontmanAstro__Cli__Files
|
|
10
|
+
module Templates = FrontmanAstro__Cli__Templates
|
|
11
|
+
module Style = FrontmanAstro__Cli__Style
|
|
12
|
+
|
|
13
|
+
type installOptions = {
|
|
14
|
+
server: string,
|
|
15
|
+
prefix: option<string>,
|
|
16
|
+
dryRun: bool,
|
|
17
|
+
skipDeps: bool,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type installResult =
|
|
21
|
+
| Success
|
|
22
|
+
| PartialSuccess({manualStepsRequired: array<string>})
|
|
23
|
+
| Failure(string)
|
|
24
|
+
|
|
25
|
+
// Install dependencies using detected package manager
|
|
26
|
+
let installDependencies = async (
|
|
27
|
+
~projectDir: string,
|
|
28
|
+
~packageManager: Detect.packageManager,
|
|
29
|
+
~dryRun: bool,
|
|
30
|
+
): result<unit, string> => {
|
|
31
|
+
let pm = Detect.getPackageManagerCommand(packageManager)
|
|
32
|
+
let args = Detect.getInstallArgs(packageManager)
|
|
33
|
+
let packages = ["@frontman-ai/astro", "@astrojs/node"]
|
|
34
|
+
// Deno requires npm: prefix for npm packages (otherwise it looks them up on JSR)
|
|
35
|
+
let packages = switch packageManager {
|
|
36
|
+
| Deno => packages->Array.map(p => "npm:" ++ p)
|
|
37
|
+
| _ => packages
|
|
38
|
+
}
|
|
39
|
+
let cmd = `${pm} ${args->Array.join(" ")} ${packages->Array.join(" ")}`
|
|
40
|
+
|
|
41
|
+
switch dryRun {
|
|
42
|
+
| true =>
|
|
43
|
+
Console.log(` ${Style.dim(`Would run: ${cmd}`)}`)
|
|
44
|
+
Ok()
|
|
45
|
+
| false =>
|
|
46
|
+
Console.log(` ${Style.purple("Installing dependencies with " ++ pm ++ "...")}`)
|
|
47
|
+
|
|
48
|
+
switch await ChildProcess.execWithOptions(cmd, {cwd: projectDir}) {
|
|
49
|
+
| Ok(_) =>
|
|
50
|
+
Console.log(` ${Style.check} Dependencies installed`)
|
|
51
|
+
Ok()
|
|
52
|
+
| Error(err) =>
|
|
53
|
+
let stderr = switch err.stderr == "" {
|
|
54
|
+
| true => "Unknown error"
|
|
55
|
+
| false => err.stderr
|
|
56
|
+
}
|
|
57
|
+
Error(`Failed to install dependencies: ${stderr}`)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Helper to process a file result and collect manual steps
|
|
63
|
+
let processFileResult = (
|
|
64
|
+
result: result<Files.fileResult, string>,
|
|
65
|
+
manualSteps: array<string>,
|
|
66
|
+
): result<unit, string> => {
|
|
67
|
+
switch result {
|
|
68
|
+
| Ok(fileResult) =>
|
|
69
|
+
Console.log(Files.formatResult(fileResult))
|
|
70
|
+
switch fileResult {
|
|
71
|
+
| Files.ManualEditRequired({details, _}) => manualSteps->Array.push(details)->ignore
|
|
72
|
+
| _ => ()
|
|
73
|
+
}
|
|
74
|
+
Ok()
|
|
75
|
+
| Error(msg) =>
|
|
76
|
+
Console.error(` ${Style.warn} ${Style.bold("Error:")} ${msg}`)
|
|
77
|
+
Error(msg)
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Collect which files need auto-editing (without prompting the user)
|
|
82
|
+
let collectPendingAutoEdits = (
|
|
83
|
+
~projectDir: string,
|
|
84
|
+
~host: string,
|
|
85
|
+
~info: Detect.projectInfo,
|
|
86
|
+
): array<Files.pendingAutoEdit> => {
|
|
87
|
+
let pending = []
|
|
88
|
+
|
|
89
|
+
// Check astro config
|
|
90
|
+
switch Files.getPendingAutoEdit(
|
|
91
|
+
~existingFile=info.config,
|
|
92
|
+
~filePath=Path.join([projectDir, info.configFileName]),
|
|
93
|
+
~fileName=info.configFileName,
|
|
94
|
+
~fileType=AutoEdit.Config,
|
|
95
|
+
~manualDetails=Templates.ManualInstructions.config(info.configFileName, host),
|
|
96
|
+
) {
|
|
97
|
+
| Some(p) => pending->Array.push(p)->ignore
|
|
98
|
+
| None => ()
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Check middleware
|
|
102
|
+
switch Files.getPendingAutoEdit(
|
|
103
|
+
~existingFile=info.middleware,
|
|
104
|
+
~filePath=Path.join([projectDir, info.middlewareFileName]),
|
|
105
|
+
~fileName=info.middlewareFileName,
|
|
106
|
+
~fileType=AutoEdit.Middleware,
|
|
107
|
+
~manualDetails=Templates.ManualInstructions.middleware(info.middlewareFileName, host),
|
|
108
|
+
) {
|
|
109
|
+
| Some(p) => pending->Array.push(p)->ignore
|
|
110
|
+
| None => ()
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
pending
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Main install function
|
|
117
|
+
let run = async (options: installOptions): installResult => {
|
|
118
|
+
let projectDir = options.prefix->Option.getOr(Process.cwd())
|
|
119
|
+
let host = options.server
|
|
120
|
+
|
|
121
|
+
Console.log(Templates.banner())
|
|
122
|
+
Console.log(` ${Style.bullet} ${Style.bold("Server:")} ${host}`)
|
|
123
|
+
|
|
124
|
+
switch options.dryRun {
|
|
125
|
+
| true =>
|
|
126
|
+
Console.log("")
|
|
127
|
+
Console.log(Templates.SuccessMessages.dryRunHeader)
|
|
128
|
+
| false => ()
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Step 1: Detect project info
|
|
132
|
+
switch await Detect.detect(projectDir) {
|
|
133
|
+
| Error(msg) =>
|
|
134
|
+
Console.error(` ${Style.warn} ${Style.bold("Error:")} ${msg}`)
|
|
135
|
+
Failure(msg)
|
|
136
|
+
|
|
137
|
+
| Ok(info) =>
|
|
138
|
+
let version = (info.astroVersion->Option.getOrThrow).raw
|
|
139
|
+
|
|
140
|
+
Console.log(` ${Style.bullet} ${Style.bold("Detected:")} Astro ${version}`)
|
|
141
|
+
Console.log("")
|
|
142
|
+
|
|
143
|
+
// Step 2: Install dependencies (unless skipped)
|
|
144
|
+
switch options.skipDeps {
|
|
145
|
+
| true => ()
|
|
146
|
+
| false =>
|
|
147
|
+
switch await installDependencies(
|
|
148
|
+
~projectDir,
|
|
149
|
+
~packageManager=info.packageManager,
|
|
150
|
+
~dryRun=options.dryRun,
|
|
151
|
+
) {
|
|
152
|
+
| Error(msg) =>
|
|
153
|
+
Console.error(` ${Style.warn} ${msg}`)
|
|
154
|
+
// Continue anyway - user might have deps already
|
|
155
|
+
()
|
|
156
|
+
| Ok() => ()
|
|
157
|
+
}
|
|
158
|
+
Console.log("")
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Step 3: Collect files needing auto-edit and prompt once (if any)
|
|
162
|
+
let pendingEdits = collectPendingAutoEdits(~projectDir, ~host, ~info)
|
|
163
|
+
let shouldAutoEdit = switch (pendingEdits->Array.length > 0, options.dryRun) {
|
|
164
|
+
| (true, false) =>
|
|
165
|
+
let fileNames = pendingEdits->Array.map(p => p.fileName)
|
|
166
|
+
await AutoEdit.promptUserForAutoEdit(~fileNames)
|
|
167
|
+
| _ => false
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Step 4: Handle files
|
|
171
|
+
let manualSteps = []
|
|
172
|
+
|
|
173
|
+
// Handle astro config
|
|
174
|
+
let configResult = await Files.handleConfig(
|
|
175
|
+
~projectDir,
|
|
176
|
+
~host,
|
|
177
|
+
~configFileName=info.configFileName,
|
|
178
|
+
~existingFile=info.config,
|
|
179
|
+
~dryRun=options.dryRun,
|
|
180
|
+
~autoEdit=shouldAutoEdit,
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
switch processFileResult(configResult, manualSteps) {
|
|
184
|
+
| Error(msg) => Failure(msg)
|
|
185
|
+
| Ok() =>
|
|
186
|
+
// Handle middleware
|
|
187
|
+
let middlewareResult = await Files.handleMiddleware(
|
|
188
|
+
~projectDir,
|
|
189
|
+
~host,
|
|
190
|
+
~middlewareFileName=info.middlewareFileName,
|
|
191
|
+
~existingFile=info.middleware,
|
|
192
|
+
~dryRun=options.dryRun,
|
|
193
|
+
~autoEdit=shouldAutoEdit,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
switch processFileResult(middlewareResult, manualSteps) {
|
|
197
|
+
| Error(msg) => Failure(msg)
|
|
198
|
+
| Ok() =>
|
|
199
|
+
// Summary
|
|
200
|
+
switch manualSteps->Array.length > 0 {
|
|
201
|
+
| true =>
|
|
202
|
+
Console.log("")
|
|
203
|
+
Console.log(` ${Style.divider}`)
|
|
204
|
+
Console.log("")
|
|
205
|
+
Console.log(` ${Style.yellowBold("Manual steps required:")}`)
|
|
206
|
+
Console.log("")
|
|
207
|
+
manualSteps->Array.forEach(step => Console.log(step))
|
|
208
|
+
Console.log("")
|
|
209
|
+
PartialSuccess({manualStepsRequired: manualSteps})
|
|
210
|
+
| false =>
|
|
211
|
+
switch options.dryRun {
|
|
212
|
+
| true => ()
|
|
213
|
+
| false =>
|
|
214
|
+
let devCommand = Detect.getDevCommand(info.packageManager)
|
|
215
|
+
Console.log("")
|
|
216
|
+
Console.log(` ${Style.divider}`)
|
|
217
|
+
Console.log(Templates.SuccessMessages.installComplete(~devCommand))
|
|
218
|
+
}
|
|
219
|
+
Success
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|