@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,194 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Nodepath from "node:path";
|
|
4
|
+
import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
|
|
5
|
+
import * as ChildProcess$FrontmanBindings from "@frontman/bindings/src/ChildProcess.res.mjs";
|
|
6
|
+
import * as FrontmanAstro__Cli__Files$FrontmanAiAstro from "./FrontmanAstro__Cli__Files.res.mjs";
|
|
7
|
+
import * as FrontmanAstro__Cli__Style$FrontmanAiAstro from "./FrontmanAstro__Cli__Style.res.mjs";
|
|
8
|
+
import * as FrontmanAstro__Cli__Detect$FrontmanAiAstro from "./FrontmanAstro__Cli__Detect.res.mjs";
|
|
9
|
+
import * as FrontmanAstro__Cli__AutoEdit$FrontmanAiAstro from "./FrontmanAstro__Cli__AutoEdit.res.mjs";
|
|
10
|
+
import * as FrontmanAstro__Cli__Templates$FrontmanAiAstro from "./FrontmanAstro__Cli__Templates.res.mjs";
|
|
11
|
+
|
|
12
|
+
async function installDependencies(projectDir, packageManager, dryRun) {
|
|
13
|
+
let pm = FrontmanAstro__Cli__Detect$FrontmanAiAstro.getPackageManagerCommand(packageManager);
|
|
14
|
+
let args = FrontmanAstro__Cli__Detect$FrontmanAiAstro.getInstallArgs(packageManager, undefined);
|
|
15
|
+
let packages = [
|
|
16
|
+
"@frontman-ai/astro",
|
|
17
|
+
"@astrojs/node"
|
|
18
|
+
];
|
|
19
|
+
let packages$1;
|
|
20
|
+
packages$1 = packageManager === "Deno" ? packages.map(p => "npm:" + p) : packages;
|
|
21
|
+
let cmd = pm + ` ` + args.join(" ") + ` ` + packages$1.join(" ");
|
|
22
|
+
if (dryRun) {
|
|
23
|
+
console.log(` ` + FrontmanAstro__Cli__Style$FrontmanAiAstro.dim(`Would run: ` + cmd));
|
|
24
|
+
return {
|
|
25
|
+
TAG: "Ok",
|
|
26
|
+
_0: undefined
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
console.log(` ` + FrontmanAstro__Cli__Style$FrontmanAiAstro.purple("Installing dependencies with " + pm + "..."));
|
|
30
|
+
let err = await ChildProcess$FrontmanBindings.execWithOptions(cmd, {
|
|
31
|
+
cwd: projectDir
|
|
32
|
+
});
|
|
33
|
+
if (err.TAG === "Ok") {
|
|
34
|
+
console.log(` ` + FrontmanAstro__Cli__Style$FrontmanAiAstro.check + ` Dependencies installed`);
|
|
35
|
+
return {
|
|
36
|
+
TAG: "Ok",
|
|
37
|
+
_0: undefined
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
let err$1 = err._0;
|
|
41
|
+
let stderr = err$1.stderr === "" ? "Unknown error" : err$1.stderr;
|
|
42
|
+
return {
|
|
43
|
+
TAG: "Error",
|
|
44
|
+
_0: `Failed to install dependencies: ` + stderr
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function processFileResult(result, manualSteps) {
|
|
49
|
+
if (result.TAG === "Ok") {
|
|
50
|
+
let fileResult = result._0;
|
|
51
|
+
console.log(FrontmanAstro__Cli__Files$FrontmanAiAstro.formatResult(fileResult));
|
|
52
|
+
if (fileResult.TAG === "ManualEditRequired") {
|
|
53
|
+
manualSteps.push(fileResult.details);
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
TAG: "Ok",
|
|
57
|
+
_0: undefined
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
let msg = result._0;
|
|
61
|
+
console.error(` ` + FrontmanAstro__Cli__Style$FrontmanAiAstro.warn + ` ` + FrontmanAstro__Cli__Style$FrontmanAiAstro.bold("Error:") + ` ` + msg);
|
|
62
|
+
return {
|
|
63
|
+
TAG: "Error",
|
|
64
|
+
_0: msg
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function collectPendingAutoEdits(projectDir, host, info) {
|
|
69
|
+
let pending = [];
|
|
70
|
+
let p = FrontmanAstro__Cli__Files$FrontmanAiAstro.getPendingAutoEdit(info.config, Nodepath.join(projectDir, info.configFileName), info.configFileName, "Config", FrontmanAstro__Cli__Templates$FrontmanAiAstro.ManualInstructions.config(info.configFileName, host));
|
|
71
|
+
if (p !== undefined) {
|
|
72
|
+
pending.push(p);
|
|
73
|
+
}
|
|
74
|
+
let p$1 = FrontmanAstro__Cli__Files$FrontmanAiAstro.getPendingAutoEdit(info.middleware, Nodepath.join(projectDir, info.middlewareFileName), info.middlewareFileName, "Middleware", FrontmanAstro__Cli__Templates$FrontmanAiAstro.ManualInstructions.middleware(info.middlewareFileName, host));
|
|
75
|
+
if (p$1 !== undefined) {
|
|
76
|
+
pending.push(p$1);
|
|
77
|
+
}
|
|
78
|
+
return pending;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function run(options) {
|
|
82
|
+
let projectDir = Stdlib_Option.getOr(options.prefix, process.cwd());
|
|
83
|
+
let host = options.server;
|
|
84
|
+
console.log(FrontmanAstro__Cli__Templates$FrontmanAiAstro.banner());
|
|
85
|
+
console.log(` ` + FrontmanAstro__Cli__Style$FrontmanAiAstro.bullet + ` ` + FrontmanAstro__Cli__Style$FrontmanAiAstro.bold("Server:") + ` ` + host);
|
|
86
|
+
if (options.dryRun) {
|
|
87
|
+
console.log("");
|
|
88
|
+
console.log(FrontmanAstro__Cli__Templates$FrontmanAiAstro.SuccessMessages.dryRunHeader);
|
|
89
|
+
}
|
|
90
|
+
let msg = await FrontmanAstro__Cli__Detect$FrontmanAiAstro.detect(projectDir);
|
|
91
|
+
if (msg.TAG === "Ok") {
|
|
92
|
+
let info = msg._0;
|
|
93
|
+
let version = Stdlib_Option.getOrThrow(info.astroVersion, undefined).raw;
|
|
94
|
+
console.log(` ` + FrontmanAstro__Cli__Style$FrontmanAiAstro.bullet + ` ` + FrontmanAstro__Cli__Style$FrontmanAiAstro.bold("Detected:") + ` Astro ` + version);
|
|
95
|
+
console.log("");
|
|
96
|
+
if (!options.skipDeps) {
|
|
97
|
+
let msg$1 = await installDependencies(projectDir, info.packageManager, options.dryRun);
|
|
98
|
+
if (msg$1.TAG !== "Ok") {
|
|
99
|
+
console.error(` ` + FrontmanAstro__Cli__Style$FrontmanAiAstro.warn + ` ` + msg$1._0);
|
|
100
|
+
}
|
|
101
|
+
console.log("");
|
|
102
|
+
}
|
|
103
|
+
let pendingEdits = collectPendingAutoEdits(projectDir, host, info);
|
|
104
|
+
let match = pendingEdits.length !== 0;
|
|
105
|
+
let match$1 = options.dryRun;
|
|
106
|
+
let shouldAutoEdit;
|
|
107
|
+
if (match && !match$1) {
|
|
108
|
+
let fileNames = pendingEdits.map(p => p.fileName);
|
|
109
|
+
shouldAutoEdit = await FrontmanAstro__Cli__AutoEdit$FrontmanAiAstro.promptUserForAutoEdit(fileNames);
|
|
110
|
+
} else {
|
|
111
|
+
shouldAutoEdit = false;
|
|
112
|
+
}
|
|
113
|
+
let manualSteps = [];
|
|
114
|
+
let configResult = await FrontmanAstro__Cli__Files$FrontmanAiAstro.handleConfig(projectDir, host, info.configFileName, info.config, options.dryRun, shouldAutoEdit);
|
|
115
|
+
let msg$2 = processFileResult(configResult, manualSteps);
|
|
116
|
+
if (msg$2.TAG !== "Ok") {
|
|
117
|
+
return {
|
|
118
|
+
TAG: "Failure",
|
|
119
|
+
_0: msg$2._0
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
let middlewareResult = await FrontmanAstro__Cli__Files$FrontmanAiAstro.handleMiddleware(projectDir, host, info.middlewareFileName, info.middleware, options.dryRun, shouldAutoEdit);
|
|
123
|
+
let msg$3 = processFileResult(middlewareResult, manualSteps);
|
|
124
|
+
if (msg$3.TAG !== "Ok") {
|
|
125
|
+
return {
|
|
126
|
+
TAG: "Failure",
|
|
127
|
+
_0: msg$3._0
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (manualSteps.length !== 0) {
|
|
131
|
+
console.log("");
|
|
132
|
+
console.log(` ` + FrontmanAstro__Cli__Style$FrontmanAiAstro.divider);
|
|
133
|
+
console.log("");
|
|
134
|
+
console.log(` ` + FrontmanAstro__Cli__Style$FrontmanAiAstro.yellowBold("Manual steps required:"));
|
|
135
|
+
console.log("");
|
|
136
|
+
manualSteps.forEach(step => {
|
|
137
|
+
console.log(step);
|
|
138
|
+
});
|
|
139
|
+
console.log("");
|
|
140
|
+
return {
|
|
141
|
+
TAG: "PartialSuccess",
|
|
142
|
+
manualStepsRequired: manualSteps
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
if (!options.dryRun) {
|
|
146
|
+
let devCommand = FrontmanAstro__Cli__Detect$FrontmanAiAstro.getDevCommand(info.packageManager);
|
|
147
|
+
console.log("");
|
|
148
|
+
console.log(` ` + FrontmanAstro__Cli__Style$FrontmanAiAstro.divider);
|
|
149
|
+
console.log(FrontmanAstro__Cli__Templates$FrontmanAiAstro.SuccessMessages.installComplete(devCommand));
|
|
150
|
+
}
|
|
151
|
+
return "Success";
|
|
152
|
+
}
|
|
153
|
+
let msg$4 = msg._0;
|
|
154
|
+
console.error(` ` + FrontmanAstro__Cli__Style$FrontmanAiAstro.warn + ` ` + FrontmanAstro__Cli__Style$FrontmanAiAstro.bold("Error:") + ` ` + msg$4);
|
|
155
|
+
return {
|
|
156
|
+
TAG: "Failure",
|
|
157
|
+
_0: msg$4
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let Bindings;
|
|
162
|
+
|
|
163
|
+
let ChildProcess;
|
|
164
|
+
|
|
165
|
+
let Path;
|
|
166
|
+
|
|
167
|
+
let Process;
|
|
168
|
+
|
|
169
|
+
let AutoEdit;
|
|
170
|
+
|
|
171
|
+
let Detect;
|
|
172
|
+
|
|
173
|
+
let Files;
|
|
174
|
+
|
|
175
|
+
let Templates;
|
|
176
|
+
|
|
177
|
+
let Style;
|
|
178
|
+
|
|
179
|
+
export {
|
|
180
|
+
Bindings,
|
|
181
|
+
ChildProcess,
|
|
182
|
+
Path,
|
|
183
|
+
Process,
|
|
184
|
+
AutoEdit,
|
|
185
|
+
Detect,
|
|
186
|
+
Files,
|
|
187
|
+
Templates,
|
|
188
|
+
Style,
|
|
189
|
+
installDependencies,
|
|
190
|
+
processFileResult,
|
|
191
|
+
collectPendingAutoEdits,
|
|
192
|
+
run,
|
|
193
|
+
}
|
|
194
|
+
/* node:path Not a pure module */
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// ANSI terminal styling for CLI output
|
|
2
|
+
// Brand purple: #985DF7 (primary), #8051CD (secondary)
|
|
3
|
+
|
|
4
|
+
let esc = "\x1b"
|
|
5
|
+
|
|
6
|
+
// Color functions — wrap text with ANSI codes
|
|
7
|
+
let purple = text => `${esc}[38;2;152;93;247m${text}${esc}[0m`
|
|
8
|
+
let purpleBold = text => `${esc}[1;38;2;152;93;247m${text}${esc}[0m`
|
|
9
|
+
let purpleDim = text => `${esc}[38;2;128;81;205m${text}${esc}[0m`
|
|
10
|
+
let green = text => `${esc}[32m${text}${esc}[0m`
|
|
11
|
+
let yellow = text => `${esc}[33m${text}${esc}[0m`
|
|
12
|
+
let yellowBold = text => `${esc}[1;33m${text}${esc}[0m`
|
|
13
|
+
let bold = text => `${esc}[1m${text}${esc}[0m`
|
|
14
|
+
let dim = text => `${esc}[2m${text}${esc}[0m`
|
|
15
|
+
|
|
16
|
+
// Symbols
|
|
17
|
+
let check = green("✔")
|
|
18
|
+
let warn = yellow("⚠")
|
|
19
|
+
let bullet = purple("▸")
|
|
20
|
+
|
|
21
|
+
// Decorative
|
|
22
|
+
let divider = purple("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
let esc = "\x1b";
|
|
5
|
+
|
|
6
|
+
function purple(text) {
|
|
7
|
+
return esc + `[38;2;152;93;247m` + text + esc + `[0m`;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function purpleBold(text) {
|
|
11
|
+
return esc + `[1;38;2;152;93;247m` + text + esc + `[0m`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function purpleDim(text) {
|
|
15
|
+
return esc + `[38;2;128;81;205m` + text + esc + `[0m`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function green(text) {
|
|
19
|
+
return esc + `[32m` + text + esc + `[0m`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function yellow(text) {
|
|
23
|
+
return esc + `[33m` + text + esc + `[0m`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function yellowBold(text) {
|
|
27
|
+
return esc + `[1;33m` + text + esc + `[0m`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function bold(text) {
|
|
31
|
+
return esc + `[1m` + text + esc + `[0m`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function dim(text) {
|
|
35
|
+
return esc + `[2m` + text + esc + `[0m`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let check = green("✔");
|
|
39
|
+
|
|
40
|
+
let warn = yellow("⚠");
|
|
41
|
+
|
|
42
|
+
let bullet = purple("▸");
|
|
43
|
+
|
|
44
|
+
let divider = purple("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
|
45
|
+
|
|
46
|
+
export {
|
|
47
|
+
esc,
|
|
48
|
+
purple,
|
|
49
|
+
purpleBold,
|
|
50
|
+
purpleDim,
|
|
51
|
+
green,
|
|
52
|
+
yellow,
|
|
53
|
+
yellowBold,
|
|
54
|
+
bold,
|
|
55
|
+
dim,
|
|
56
|
+
check,
|
|
57
|
+
warn,
|
|
58
|
+
bullet,
|
|
59
|
+
divider,
|
|
60
|
+
}
|
|
61
|
+
/* check Not a pure module */
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
// Templates for generated files
|
|
2
|
+
module Style = FrontmanAstro__Cli__Style
|
|
3
|
+
|
|
4
|
+
// ASCII art banner for the installer
|
|
5
|
+
let banner = () => {
|
|
6
|
+
let l1 = Style.purpleBold(" ___ _ ")
|
|
7
|
+
let l2 = Style.purpleBold(" | __| _ ___ _ _ | |_ _ __ __ _ _ _ ")
|
|
8
|
+
// Use double-quoted string for the backtick line
|
|
9
|
+
let l3 = Style.purpleBold(" | _| '_/ _ \\ ' \\| _| ' \\/ _` | ' \\ ")
|
|
10
|
+
let l4 = Style.purpleBold(" |_||_| \\___/_||_|\\__|_|_|_\\__,_|_||_|")
|
|
11
|
+
let tagline = Style.purpleDim(" AI that sees your DOM and edits your frontend")
|
|
12
|
+
|
|
13
|
+
`
|
|
14
|
+
${l1}
|
|
15
|
+
${l2}
|
|
16
|
+
${l3}
|
|
17
|
+
${l4}
|
|
18
|
+
|
|
19
|
+
${tagline}
|
|
20
|
+
`
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/middleware.ts template
|
|
24
|
+
let middlewareTemplate = (host: string) =>
|
|
25
|
+
`import { createMiddleware, makeConfig } from '@frontman-ai/astro';
|
|
26
|
+
import { defineMiddleware } from 'astro:middleware';
|
|
27
|
+
|
|
28
|
+
const config = makeConfig({ host: '${host}' });
|
|
29
|
+
const frontman = createMiddleware(config);
|
|
30
|
+
|
|
31
|
+
export const onRequest = defineMiddleware(async (context, next) => {
|
|
32
|
+
return frontman(context, next);
|
|
33
|
+
});
|
|
34
|
+
`
|
|
35
|
+
|
|
36
|
+
// astro.config.mjs template (for clean projects with no existing config)
|
|
37
|
+
let configTemplate = (host: string) => {
|
|
38
|
+
// host is unused in the config template (it's used via makeConfig in middleware),
|
|
39
|
+
// but we accept it to keep the API consistent and for future use
|
|
40
|
+
ignore(host)
|
|
41
|
+
`import { defineConfig } from 'astro/config';
|
|
42
|
+
import node from '@astrojs/node';
|
|
43
|
+
import { frontmanIntegration } from '@frontman-ai/astro/integration';
|
|
44
|
+
|
|
45
|
+
const isProd = process.env.NODE_ENV === 'production';
|
|
46
|
+
|
|
47
|
+
export default defineConfig({
|
|
48
|
+
// SSR needed in dev for Frontman middleware routes
|
|
49
|
+
...(isProd ? {} : { output: 'server', adapter: node({ mode: 'standalone' }) }),
|
|
50
|
+
integrations: [frontmanIntegration()],
|
|
51
|
+
});
|
|
52
|
+
`
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Manual setup instructions (shown in summary when auto-edit is skipped)
|
|
56
|
+
module ManualInstructions = {
|
|
57
|
+
let config = (fileName: string, _host: string) => {
|
|
58
|
+
let h = Style.yellowBold
|
|
59
|
+
let s = Style.purple
|
|
60
|
+
let d = Style.dim
|
|
61
|
+
let b = Style.bold
|
|
62
|
+
let bar = Style.yellow("|")
|
|
63
|
+
|
|
64
|
+
` ${bar}
|
|
65
|
+
${bar} ${h(fileName)} needs manual modification.
|
|
66
|
+
${bar}
|
|
67
|
+
${bar} ${s("1.")} Add imports at the top of the file:
|
|
68
|
+
${bar}
|
|
69
|
+
${bar} ${d("import node from '@astrojs/node';")}
|
|
70
|
+
${bar} ${d("import { frontmanIntegration } from '@frontman-ai/astro/integration';")}
|
|
71
|
+
${bar}
|
|
72
|
+
${bar} ${s("2.")} Add SSR config for dev mode ${d("(needed for middleware routes)")}:
|
|
73
|
+
${bar}
|
|
74
|
+
${bar} ${d("const isProd = process.env.NODE_ENV === 'production';")}
|
|
75
|
+
${bar}
|
|
76
|
+
${bar} ${d("export default defineConfig({")}
|
|
77
|
+
${bar} ${d(" ...(isProd ? {} : { output: 'server', adapter: node({ mode: 'standalone' }) }),")}
|
|
78
|
+
${bar} ${d(" // ... your existing config")}
|
|
79
|
+
${bar} ${d("});")}
|
|
80
|
+
${bar}
|
|
81
|
+
${bar} ${s("3.")} Add ${b("frontmanIntegration()")} to your integrations array:
|
|
82
|
+
${bar}
|
|
83
|
+
${bar} ${d("integrations: [frontmanIntegration(), ...yourExistingIntegrations]")}
|
|
84
|
+
${bar}
|
|
85
|
+
${bar} ${b("Docs:")} ${d("https://frontman.sh/docs/astro")}
|
|
86
|
+
${bar}`
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let middleware = (fileName: string, host: string) => {
|
|
90
|
+
let h = Style.yellowBold
|
|
91
|
+
let s = Style.purple
|
|
92
|
+
let d = Style.dim
|
|
93
|
+
let b = Style.bold
|
|
94
|
+
let bar = Style.yellow("|")
|
|
95
|
+
|
|
96
|
+
` ${bar}
|
|
97
|
+
${bar} ${h(fileName)} needs manual modification.
|
|
98
|
+
${bar}
|
|
99
|
+
${bar} ${s("1.")} Add imports at the top of the file:
|
|
100
|
+
${bar}
|
|
101
|
+
${bar} ${d("import { createMiddleware, makeConfig } from '@frontman-ai/astro';")}
|
|
102
|
+
${bar} ${d("import { defineMiddleware, sequence } from 'astro:middleware';")}
|
|
103
|
+
${bar}
|
|
104
|
+
${bar} ${s("2.")} Create the Frontman middleware instance ${d("(after imports)")}:
|
|
105
|
+
${bar}
|
|
106
|
+
${bar} ${d(`const frontmanConfig = makeConfig({ host: '${host}' });`)}
|
|
107
|
+
${bar} ${d("const frontman = createMiddleware(frontmanConfig);")}
|
|
108
|
+
${bar}
|
|
109
|
+
${bar} ${s("3.")} Combine with your existing middleware using ${b("sequence()")}:
|
|
110
|
+
${bar}
|
|
111
|
+
${bar} ${d("const frontmanMiddleware = defineMiddleware(async (context, next) => {")}
|
|
112
|
+
${bar} ${d(" return frontman(context, next);")}
|
|
113
|
+
${bar} ${d("});")}
|
|
114
|
+
${bar}
|
|
115
|
+
${bar} ${d("export const onRequest = sequence(frontmanMiddleware, yourExistingMiddleware);")}
|
|
116
|
+
${bar}
|
|
117
|
+
${bar} ${b("Docs:")} ${d("https://frontman.sh/docs/astro")}
|
|
118
|
+
${bar}`
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Keep plain-text versions for the LLM system prompt (no ANSI codes)
|
|
123
|
+
module ErrorMessages = {
|
|
124
|
+
let configManualSetup = (fileName: string, _host: string) =>
|
|
125
|
+
`
|
|
126
|
+
${fileName} already exists and requires manual modification.
|
|
127
|
+
|
|
128
|
+
Add the following to your ${fileName}:
|
|
129
|
+
|
|
130
|
+
1. Add imports at the top of the file:
|
|
131
|
+
|
|
132
|
+
import node from '@astrojs/node';
|
|
133
|
+
import { frontmanIntegration } from '@frontman-ai/astro/integration';
|
|
134
|
+
|
|
135
|
+
2. Add SSR config for dev mode (needed for middleware routes):
|
|
136
|
+
|
|
137
|
+
const isProd = process.env.NODE_ENV === 'production';
|
|
138
|
+
|
|
139
|
+
export default defineConfig({
|
|
140
|
+
...(isProd ? {} : { output: 'server', adapter: node({ mode: 'standalone' }) }),
|
|
141
|
+
// ... your existing config
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
3. Add frontmanIntegration() to your integrations array:
|
|
145
|
+
|
|
146
|
+
integrations: [frontmanIntegration(), ...yourExistingIntegrations],
|
|
147
|
+
|
|
148
|
+
For full documentation, see: https://frontman.sh/docs/astro
|
|
149
|
+
`
|
|
150
|
+
|
|
151
|
+
let middlewareManualSetup = (fileName: string, host: string) =>
|
|
152
|
+
`
|
|
153
|
+
${fileName} already exists and requires manual modification.
|
|
154
|
+
|
|
155
|
+
Add the following to your ${fileName}:
|
|
156
|
+
|
|
157
|
+
1. Add imports at the top of the file:
|
|
158
|
+
|
|
159
|
+
import { createMiddleware, makeConfig } from '@frontman-ai/astro';
|
|
160
|
+
import { defineMiddleware, sequence } from 'astro:middleware';
|
|
161
|
+
|
|
162
|
+
2. Create the Frontman middleware instance (after imports):
|
|
163
|
+
|
|
164
|
+
const frontmanConfig = makeConfig({ host: '${host}' });
|
|
165
|
+
const frontman = createMiddleware(frontmanConfig);
|
|
166
|
+
|
|
167
|
+
3. Combine with your existing middleware using sequence():
|
|
168
|
+
|
|
169
|
+
const frontmanMiddleware = defineMiddleware(async (context, next) => {
|
|
170
|
+
return frontman(context, next);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
export const onRequest = sequence(frontmanMiddleware, yourExistingMiddleware);
|
|
174
|
+
|
|
175
|
+
For full documentation, see: https://frontman.sh/docs/astro
|
|
176
|
+
`
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Success messages
|
|
180
|
+
module SuccessMessages = {
|
|
181
|
+
let fileCreated = (fileName: string) =>
|
|
182
|
+
` ${Style.check} Created ${Style.bold(fileName)}`
|
|
183
|
+
|
|
184
|
+
let fileSkipped = (fileName: string) =>
|
|
185
|
+
` ${Style.purple("–")} Skipped ${Style.bold(fileName)} ${Style.dim("(already configured)")}`
|
|
186
|
+
|
|
187
|
+
let hostUpdated = (fileName: string, oldHost: string, newHost: string) =>
|
|
188
|
+
` ${Style.check} Updated ${Style.bold(fileName)} ${Style.dim(`(host: '${oldHost}' -> '${newHost}')`)}`
|
|
189
|
+
|
|
190
|
+
let fileAutoEdited = (fileName: string) =>
|
|
191
|
+
` ${Style.check} Auto-edited ${Style.bold(fileName)} ${Style.dim("(Frontman integrated via AI)")}`
|
|
192
|
+
|
|
193
|
+
let autoEditFailed = (fileName: string, error: string) =>
|
|
194
|
+
` ${Style.warn} Auto-edit failed for ${Style.bold(fileName)}: ${Style.dim(error)}`
|
|
195
|
+
|
|
196
|
+
let manualEditRequired = (fileName: string) =>
|
|
197
|
+
` ${Style.warn} ${Style.bold(fileName)} requires manual setup ${Style.dim("(see details below)")}`
|
|
198
|
+
|
|
199
|
+
let installComplete = (~devCommand: string) => {
|
|
200
|
+
let p = Style.purple
|
|
201
|
+
let pb = Style.purpleBold
|
|
202
|
+
let d = Style.dim
|
|
203
|
+
let pd = Style.purpleDim
|
|
204
|
+
|
|
205
|
+
`
|
|
206
|
+
${pb("Frontman setup complete!")}
|
|
207
|
+
|
|
208
|
+
${pb("Next steps:")}
|
|
209
|
+
${p("1.")} Start your dev server ${d(devCommand)}
|
|
210
|
+
${p("2.")} Open your browser to ${d("http://localhost:4321/frontman")}
|
|
211
|
+
|
|
212
|
+
${p("┌───────────────────────────────────────────────┐")}
|
|
213
|
+
${p("│")} ${p("│")}
|
|
214
|
+
${p("│")} Questions? Comments? Need support? ${p("│")}
|
|
215
|
+
${p("│")} ${p("│")}
|
|
216
|
+
${p("│")} Join us on Discord: ${p("│")}
|
|
217
|
+
${p("│")} ${pd("https://discord.gg/J77jBzMM")} ${p("│")}
|
|
218
|
+
${p("│")} ${p("│")}
|
|
219
|
+
${p("└───────────────────────────────────────────────┘")}
|
|
220
|
+
`
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
let dryRunHeader =
|
|
224
|
+
` ${Style.warn} ${Style.yellowBold("DRY RUN MODE")} ${Style.dim("— No files will be created")}
|
|
225
|
+
`
|
|
226
|
+
}
|