frontpage-host 0.1.3 → 0.1.5
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/AGENTS.md +22 -0
- package/dist/bin.js +6 -0
- package/dist/commands/extensions.js +15 -1
- package/dist/commands/fonts.d.ts +1 -0
- package/dist/commands/fonts.js +71 -0
- package/dist/commands/modules.js +18 -1
- package/dist/commands/search.js +58 -8
- package/dist/commands/tokens.d.ts +1 -0
- package/dist/commands/tokens.js +64 -0
- package/dist/completions/generate.js +11 -5
- package/dist/registry.d.ts +1 -1
- package/dist/registry.js +110 -12
- package/llms.txt +5 -1
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -92,6 +92,27 @@ Rules:
|
|
|
92
92
|
7. Prefer reviewing the subdomain after push; only use `deploy wait` if you need to block until a build finishes.
|
|
93
93
|
8. The **UI / canvas agent does not use this CLI** — it edits the live tip in-process. Only CLI checkouts need `pull`.
|
|
94
94
|
|
|
95
|
+
## Site contract (Astro)
|
|
96
|
+
|
|
97
|
+
Sites are Astro 6 + Tailwind v4. More detail: `frontpage help site-building` or https://frontpage.host/developers/site-building
|
|
98
|
+
|
|
99
|
+
1. **Every page** wraps content in `<BaseLayout title="…" description="…">` (import from `src/layouts/BaseLayout.astro`).
|
|
100
|
+
2. **`src/config/site.ts`** — keep `pages` (path registry) and `nav` in sync when adding/renaming/deleting page files. Tab title comes from BaseLayout, not the `pages` map label.
|
|
101
|
+
3. **One file per URL** for similar page sets (services, guides, …). Do not default to `getStaticPaths()` over `src/data/*.ts`. Blog/news → `frontpage articles`, not a hand-rolled catalog.
|
|
102
|
+
4. **No backends / databases / fake forms or checkout.** Real forms use `<form data-fp-form="slug">` + `frontpage modules`. Refuse or use modules for payments.
|
|
103
|
+
5. **Tokens** in `src/config/tokens.ts` — keep required color/font/spacing/radii keys; style via CSS variables / token Tailwind. Setting a font token is not enough — apply `font-sans` / `font-serif` / `font-display`. Browse fonts with `frontpage fonts`; set one token with `frontpage tokens set --group … --key … --value …` (CAS like push). Module how-tos: `frontpage modules docs <key>` / `frontpage extensions docs <key>`.
|
|
104
|
+
6. **Shared chrome** — prefer `src/components/Header.astro` + `Footer.astro` (or `chrome: { managed: true }` in `site.ts`).
|
|
105
|
+
7. **404** — customize `src/pages/404.astro` if needed; keep `frontpage:404` meta; never register `/404` in `nav`/`pages`.
|
|
106
|
+
8. **Platform-owned paths** stay off-limits (BaseLayout overlay, module/extension shells, `package.json`, …). Customer layouts like `DocsLayout` / `GuideLayout` are OK.
|
|
107
|
+
|
|
108
|
+
## Modules & articles
|
|
109
|
+
|
|
110
|
+
- Forms: `data-fp-form` markup in pages + `frontpage modules` for enable/config. No submit JS / honeypot / `action`.
|
|
111
|
+
- Articles: `frontpage articles …` for lifecycle; bodies via sync under `content/` or `articles content get|set`. Section landing is an owned `src/pages/<section>/index.astro`.
|
|
112
|
+
- Migrate a folder into Articles: prefer `frontpage prompt "migrate … into articles"` — do not invent a mass delete+write migration.
|
|
113
|
+
- Extensions: `frontpage extensions`; if LOCKED on plan, do not fake charts/etc.
|
|
114
|
+
- Media in markup: `/__media/uploads/<slug>/…` from `frontpage media` (not raw blob URLs).
|
|
115
|
+
|
|
95
116
|
## Agent prompt loop
|
|
96
117
|
|
|
97
118
|
```bash
|
|
@@ -194,6 +215,7 @@ Safe default after finishing work: summarize what changed and give the staging U
|
|
|
194
215
|
frontpage help
|
|
195
216
|
frontpage help --json
|
|
196
217
|
frontpage help sync
|
|
218
|
+
frontpage help site-building
|
|
197
219
|
frontpage help agent
|
|
198
220
|
frontpage doctor --json
|
|
199
221
|
```
|
package/dist/bin.js
CHANGED
|
@@ -29,6 +29,8 @@ import { runSeo } from "./commands/seo.js";
|
|
|
29
29
|
import { runArticles } from "./commands/articles.js";
|
|
30
30
|
import { runSettings } from "./commands/settings.js";
|
|
31
31
|
import { runEdit } from "./commands/edit.js";
|
|
32
|
+
import { runFonts } from "./commands/fonts.js";
|
|
33
|
+
import { runTokens } from "./commands/tokens.js";
|
|
32
34
|
import { runHistory } from "./commands/history.js";
|
|
33
35
|
import { runRevert } from "./commands/revert.js";
|
|
34
36
|
import { runCompletion } from "./commands/completion.js";
|
|
@@ -110,6 +112,10 @@ async function main() {
|
|
|
110
112
|
return runSettings(args);
|
|
111
113
|
case "edit":
|
|
112
114
|
return runEdit(args);
|
|
115
|
+
case "fonts":
|
|
116
|
+
return runFonts(args);
|
|
117
|
+
case "tokens":
|
|
118
|
+
return runTokens(args);
|
|
113
119
|
case "history":
|
|
114
120
|
return runHistory(args);
|
|
115
121
|
case "revert":
|
|
@@ -23,6 +23,20 @@ export async function runExtensions(args) {
|
|
|
23
23
|
}
|
|
24
24
|
return EXIT_OK;
|
|
25
25
|
}
|
|
26
|
+
if (sub === "docs" || sub === "doc") {
|
|
27
|
+
const key = rest[1];
|
|
28
|
+
if (!key) {
|
|
29
|
+
console.error("Usage: frontpage extensions docs <key> [--site <slug>]");
|
|
30
|
+
return EXIT_USAGE;
|
|
31
|
+
}
|
|
32
|
+
const data = await v1Get(`/api/v1/sites/${encodeURIComponent(slug)}/extensions/${encodeURIComponent(key)}`);
|
|
33
|
+
console.log(`# ${data.key} (${data.name}) [${data.state}]`);
|
|
34
|
+
if (data.note)
|
|
35
|
+
console.log(data.note);
|
|
36
|
+
console.log("");
|
|
37
|
+
console.log(data.docs);
|
|
38
|
+
return EXIT_OK;
|
|
39
|
+
}
|
|
26
40
|
if (sub === "enable" || sub === "disable" || sub === "config") {
|
|
27
41
|
const key = rest[1];
|
|
28
42
|
if (!key) {
|
|
@@ -50,7 +64,7 @@ export async function runExtensions(args) {
|
|
|
50
64
|
console.log(JSON.stringify(data, null, 2));
|
|
51
65
|
return EXIT_OK;
|
|
52
66
|
}
|
|
53
|
-
console.error("Usage: frontpage extensions [list|enable|disable|config] …");
|
|
67
|
+
console.error("Usage: frontpage extensions [list|docs|enable|disable|config] …");
|
|
54
68
|
return EXIT_USAGE;
|
|
55
69
|
}
|
|
56
70
|
catch (err) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runFonts(args: string[]): Promise<number>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { EXIT_OK, EXIT_USAGE, exitCodeForError, v1Get } from "../http/client.js";
|
|
2
|
+
import { emitErr, emitOk, isJson } from "../runtime.js";
|
|
3
|
+
function takeFlag(rest, name) {
|
|
4
|
+
const i = rest.indexOf(name);
|
|
5
|
+
if (i === -1)
|
|
6
|
+
return undefined;
|
|
7
|
+
const v = rest[i + 1];
|
|
8
|
+
rest.splice(i, 2);
|
|
9
|
+
return v;
|
|
10
|
+
}
|
|
11
|
+
function hasFlag(rest, name) {
|
|
12
|
+
const i = rest.indexOf(name);
|
|
13
|
+
if (i === -1)
|
|
14
|
+
return false;
|
|
15
|
+
rest.splice(i, 1);
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
export async function runFonts(args) {
|
|
19
|
+
try {
|
|
20
|
+
const work = [...args];
|
|
21
|
+
let sub = work[0];
|
|
22
|
+
if (sub === "list" || sub === "search" || sub === "ls") {
|
|
23
|
+
work.shift();
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
sub = "list";
|
|
27
|
+
}
|
|
28
|
+
const slot = takeFlag(work, "--slot");
|
|
29
|
+
const query = takeFlag(work, "--query") ??
|
|
30
|
+
(sub === "search" ? work.shift() : undefined) ??
|
|
31
|
+
(work[0] && !work[0].startsWith("-") ? work.shift() : undefined);
|
|
32
|
+
const variableOnly = hasFlag(work, "--variable-only");
|
|
33
|
+
const limit = takeFlag(work, "--limit");
|
|
34
|
+
const offset = takeFlag(work, "--offset");
|
|
35
|
+
if (sub === "search" && !query) {
|
|
36
|
+
console.error("Usage: frontpage fonts search <query> [--slot …] [--variable-only] [--limit N]");
|
|
37
|
+
return EXIT_USAGE;
|
|
38
|
+
}
|
|
39
|
+
const q = new URLSearchParams();
|
|
40
|
+
if (slot)
|
|
41
|
+
q.set("slot", slot);
|
|
42
|
+
if (query)
|
|
43
|
+
q.set("query", query);
|
|
44
|
+
if (variableOnly)
|
|
45
|
+
q.set("variableOnly", "true");
|
|
46
|
+
if (limit)
|
|
47
|
+
q.set("limit", limit);
|
|
48
|
+
if (offset)
|
|
49
|
+
q.set("offset", offset);
|
|
50
|
+
const path = `/api/v1/fonts${q.toString() ? `?${q.toString()}` : ""}`;
|
|
51
|
+
const data = await v1Get(path);
|
|
52
|
+
if (isJson()) {
|
|
53
|
+
emitOk("fonts", data);
|
|
54
|
+
return EXIT_OK;
|
|
55
|
+
}
|
|
56
|
+
for (const f of data.fonts ?? []) {
|
|
57
|
+
const varMark = f.variable ? "var" : " ";
|
|
58
|
+
console.log(`${f.slot.padEnd(8)} ${varMark} ${f.family.padEnd(28)} ${f.value}`);
|
|
59
|
+
}
|
|
60
|
+
console.log(`(${data.returned}/${data.total} fonts${data.hasMore ? "; more available" : ""})`);
|
|
61
|
+
if (data.hint)
|
|
62
|
+
console.error(data.hint);
|
|
63
|
+
return EXIT_OK;
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
if (isJson())
|
|
67
|
+
return emitErr("fonts", err);
|
|
68
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
69
|
+
return exitCodeForError(err);
|
|
70
|
+
}
|
|
71
|
+
}
|
package/dist/commands/modules.js
CHANGED
|
@@ -19,6 +19,23 @@ export async function runModules(args) {
|
|
|
19
19
|
}
|
|
20
20
|
return EXIT_OK;
|
|
21
21
|
}
|
|
22
|
+
if (sub === "docs" || sub === "doc") {
|
|
23
|
+
const key = rest[1];
|
|
24
|
+
if (!key) {
|
|
25
|
+
console.error("Usage: frontpage modules docs <key> [--instance <id>] [--site <slug>]");
|
|
26
|
+
return EXIT_USAGE;
|
|
27
|
+
}
|
|
28
|
+
const work = rest.slice(2);
|
|
29
|
+
const instanceId = takeFlag(work, "--instance");
|
|
30
|
+
const q = instanceId ? `?instanceId=${encodeURIComponent(instanceId)}` : "";
|
|
31
|
+
const data = await v1Get(`/api/v1/sites/${encodeURIComponent(slug)}/modules/${encodeURIComponent(key)}${q}`);
|
|
32
|
+
console.log(`# ${data.key} (${data.status})`);
|
|
33
|
+
if (data.note)
|
|
34
|
+
console.log(data.note);
|
|
35
|
+
console.log("");
|
|
36
|
+
console.log(data.docs);
|
|
37
|
+
return EXIT_OK;
|
|
38
|
+
}
|
|
22
39
|
if (sub === "enable" || sub === "disable" || sub === "archive" || sub === "config") {
|
|
23
40
|
const key = rest[1];
|
|
24
41
|
if (!key) {
|
|
@@ -46,7 +63,7 @@ export async function runModules(args) {
|
|
|
46
63
|
console.log(JSON.stringify(data, null, 2));
|
|
47
64
|
return EXIT_OK;
|
|
48
65
|
}
|
|
49
|
-
console.error("Usage: frontpage modules [list|enable|disable|archive|config] …");
|
|
66
|
+
console.error("Usage: frontpage modules [list|docs|enable|disable|archive|config] …");
|
|
50
67
|
return EXIT_USAGE;
|
|
51
68
|
}
|
|
52
69
|
catch (err) {
|
package/dist/commands/search.js
CHANGED
|
@@ -1,29 +1,79 @@
|
|
|
1
1
|
import { resolveSlug } from "../site.js";
|
|
2
2
|
import { EXIT_OK, EXIT_USAGE, exitCodeForError, v1Get } from "../http/client.js";
|
|
3
|
+
import { emitErr, emitOk, isJson } from "../runtime.js";
|
|
4
|
+
function takeFlag(rest, name) {
|
|
5
|
+
const i = rest.indexOf(name);
|
|
6
|
+
if (i === -1)
|
|
7
|
+
return undefined;
|
|
8
|
+
const v = rest[i + 1];
|
|
9
|
+
rest.splice(i, 2);
|
|
10
|
+
return v;
|
|
11
|
+
}
|
|
12
|
+
function hasFlag(rest, name) {
|
|
13
|
+
const i = rest.indexOf(name);
|
|
14
|
+
if (i === -1)
|
|
15
|
+
return false;
|
|
16
|
+
rest.splice(i, 1);
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
3
19
|
export async function runSearch(args) {
|
|
4
20
|
try {
|
|
5
21
|
const { slug, rest } = await resolveSlug(args);
|
|
6
|
-
const
|
|
22
|
+
const work = [...rest];
|
|
23
|
+
const regex = hasFlag(work, "--regex");
|
|
24
|
+
const caseSensitive = hasFlag(work, "--case-sensitive");
|
|
25
|
+
const wholeWord = hasFlag(work, "--whole-word");
|
|
26
|
+
const filesOnly = hasFlag(work, "--files-only");
|
|
27
|
+
const contextLines = takeFlag(work, "--context-lines");
|
|
28
|
+
const maxResults = takeFlag(work, "--max-results");
|
|
29
|
+
const pattern = work[0];
|
|
7
30
|
if (!pattern) {
|
|
8
|
-
console.error("Usage: frontpage search <pattern> [--site <slug>]");
|
|
31
|
+
console.error("Usage: frontpage search <pattern> [path] [--regex] [--case-sensitive] [--whole-word] [--files-only] [--context-lines N] [--max-results N] [--site <slug>]");
|
|
9
32
|
return EXIT_USAGE;
|
|
10
33
|
}
|
|
34
|
+
const pathFilter = work[1] && !work[1].startsWith("-") ? work[1] : undefined;
|
|
11
35
|
const q = new URLSearchParams({ pattern });
|
|
12
|
-
const pathFilter = rest[1];
|
|
13
36
|
if (pathFilter)
|
|
14
37
|
q.set("path", pathFilter);
|
|
38
|
+
if (regex)
|
|
39
|
+
q.set("regex", "true");
|
|
40
|
+
if (caseSensitive)
|
|
41
|
+
q.set("caseSensitive", "true");
|
|
42
|
+
if (wholeWord)
|
|
43
|
+
q.set("wholeWord", "true");
|
|
44
|
+
if (filesOnly)
|
|
45
|
+
q.set("filesOnly", "true");
|
|
46
|
+
if (contextLines)
|
|
47
|
+
q.set("contextLines", contextLines);
|
|
48
|
+
if (maxResults)
|
|
49
|
+
q.set("maxResults", maxResults);
|
|
15
50
|
const data = await v1Get(`/api/v1/sites/${encodeURIComponent(slug)}/search?${q.toString()}`);
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
51
|
+
if (isJson()) {
|
|
52
|
+
emitOk("search", data);
|
|
53
|
+
return EXIT_OK;
|
|
54
|
+
}
|
|
55
|
+
if (filesOnly || data.filesOnly) {
|
|
56
|
+
const files = data.files ?? [];
|
|
57
|
+
for (const f of files)
|
|
58
|
+
console.log(f);
|
|
59
|
+
if (files.length === 0)
|
|
60
|
+
console.error("(no matches)");
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
const matches = data.matches ?? [];
|
|
64
|
+
for (const m of matches) {
|
|
65
|
+
console.log(`${m.file}:${m.lineNumber}: ${m.line}`);
|
|
66
|
+
}
|
|
67
|
+
if (matches.length === 0)
|
|
68
|
+
console.error("(no matches)");
|
|
19
69
|
}
|
|
20
|
-
if (matches.length === 0)
|
|
21
|
-
console.error("(no matches)");
|
|
22
70
|
if (data.truncated || data.scanTruncated)
|
|
23
71
|
console.error("# results truncated");
|
|
24
72
|
return EXIT_OK;
|
|
25
73
|
}
|
|
26
74
|
catch (err) {
|
|
75
|
+
if (isJson())
|
|
76
|
+
return emitErr("search", err);
|
|
27
77
|
console.error(err instanceof Error ? err.message : String(err));
|
|
28
78
|
return exitCodeForError(err);
|
|
29
79
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runTokens(args: string[]): Promise<number>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { resolveSlug } from "../site.js";
|
|
2
|
+
import { EXIT_OK, EXIT_USAGE, exitCodeForError, v1Post } from "../http/client.js";
|
|
3
|
+
import { readState, writeState } from "../state/frontpage-state.js";
|
|
4
|
+
import { emitErr, emitOk, emitUsage, isJson } from "../runtime.js";
|
|
5
|
+
function takeFlag(rest, name) {
|
|
6
|
+
const i = rest.indexOf(name);
|
|
7
|
+
if (i === -1)
|
|
8
|
+
return undefined;
|
|
9
|
+
const v = rest[i + 1];
|
|
10
|
+
rest.splice(i, 2);
|
|
11
|
+
return v;
|
|
12
|
+
}
|
|
13
|
+
export async function runTokens(args) {
|
|
14
|
+
try {
|
|
15
|
+
const { slug, rest } = await resolveSlug(args);
|
|
16
|
+
const sub = rest[0];
|
|
17
|
+
if (sub !== "set") {
|
|
18
|
+
console.error("Usage: frontpage tokens set --group <colors|fonts|spacing|radii|article> --key <name> --value <…> [--site <slug>]");
|
|
19
|
+
return EXIT_USAGE;
|
|
20
|
+
}
|
|
21
|
+
const work = rest.slice(1);
|
|
22
|
+
const group = takeFlag(work, "--group");
|
|
23
|
+
const key = takeFlag(work, "--key");
|
|
24
|
+
const value = takeFlag(work, "--value");
|
|
25
|
+
if (!group || !key || value === undefined) {
|
|
26
|
+
return emitUsage("tokens", "Usage: frontpage tokens set --group <…> --key <…> --value <…> [--site <slug>]", EXIT_USAGE);
|
|
27
|
+
}
|
|
28
|
+
const cwd = process.cwd();
|
|
29
|
+
const state = await readState(cwd);
|
|
30
|
+
if (!state.baseCommitSha) {
|
|
31
|
+
return emitUsage("tokens", "No baseCommitSha in .frontpage/state.json. Run: frontpage pull", EXIT_USAGE);
|
|
32
|
+
}
|
|
33
|
+
const data = await v1Post(`/api/v1/sites/${encodeURIComponent(slug)}/tokens`, {
|
|
34
|
+
group,
|
|
35
|
+
key,
|
|
36
|
+
value,
|
|
37
|
+
baseCommitSha: state.baseCommitSha,
|
|
38
|
+
expectedHeadSha: state.baseCommitSha,
|
|
39
|
+
});
|
|
40
|
+
if (data.commitSha) {
|
|
41
|
+
await writeState({ ...state, slug, baseCommitSha: data.commitSha }, cwd);
|
|
42
|
+
}
|
|
43
|
+
if (isJson()) {
|
|
44
|
+
emitOk("tokens", { slug, ...data });
|
|
45
|
+
return EXIT_OK;
|
|
46
|
+
}
|
|
47
|
+
if (!data.changed) {
|
|
48
|
+
console.log(`No change (${group}.${key} already set).`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
console.log(`Set ${group}.${key} → ${data.commitSha}`);
|
|
52
|
+
console.log("Updated .frontpage/state.json baseCommitSha");
|
|
53
|
+
}
|
|
54
|
+
if (data.warning)
|
|
55
|
+
console.error(`Warning: ${data.warning}`);
|
|
56
|
+
return EXIT_OK;
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
if (isJson())
|
|
60
|
+
return emitErr("tokens", err);
|
|
61
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
62
|
+
return exitCodeForError(err);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
@@ -14,15 +14,17 @@ _frontpage_completions() {
|
|
|
14
14
|
fi
|
|
15
15
|
local cmd="\${COMP_WORDS[1]}"
|
|
16
16
|
case "\${cmd}" in
|
|
17
|
-
help) COMPREPLY=( $(compgen -W "\${cmds} quickstart auth sync agent content history isolation exit-codes" -- "\${cur}") ) ;;
|
|
17
|
+
help) COMPREPLY=( $(compgen -W "\${cmds} quickstart auth sync site-building agent content history isolation exit-codes" -- "\${cur}") ) ;;
|
|
18
18
|
completion) COMPREPLY=( $(compgen -W "bash zsh fish" -- "\${cur}") ) ;;
|
|
19
19
|
runs) COMPREPLY=( $(compgen -W "list current wait cancel retry get" -- "\${cur}") ) ;;
|
|
20
20
|
deploy) COMPREPLY=( $(compgen -W "wait" -- "\${cur}") ) ;;
|
|
21
21
|
media) COMPREPLY=( $(compgen -W "list upload" -- "\${cur}") ) ;;
|
|
22
|
+
fonts) COMPREPLY=( $(compgen -W "list search" -- "\${cur}") ) ;;
|
|
23
|
+
tokens) COMPREPLY=( $(compgen -W "set" -- "\${cur}") ) ;;
|
|
22
24
|
seo|settings) COMPREPLY=( $(compgen -W "get set" -- "\${cur}") ) ;;
|
|
23
25
|
articles) COMPREPLY=( $(compgen -W "list content create-section create-article set-draft" -- "\${cur}") ) ;;
|
|
24
|
-
modules) COMPREPLY=( $(compgen -W "list enable disable archive config" -- "\${cur}") ) ;;
|
|
25
|
-
extensions) COMPREPLY=( $(compgen -W "list enable disable config" -- "\${cur}") ) ;;
|
|
26
|
+
modules) COMPREPLY=( $(compgen -W "list docs enable disable archive config" -- "\${cur}") ) ;;
|
|
27
|
+
extensions) COMPREPLY=( $(compgen -W "list docs enable disable config" -- "\${cur}") ) ;;
|
|
26
28
|
*) COMPREPLY=( $(compgen -W "--site --help --json --quiet --yes" -- "\${cur}") ) ;;
|
|
27
29
|
esac
|
|
28
30
|
}
|
|
@@ -45,8 +47,10 @@ _frontpage() {
|
|
|
45
47
|
runs) _values 'subcommand' current wait cancel retry get ;;
|
|
46
48
|
deploy) _values 'subcommand' wait ;;
|
|
47
49
|
media) _values 'subcommand' list upload ;;
|
|
50
|
+
fonts) _values 'subcommand' list search ;;
|
|
51
|
+
tokens) _values 'subcommand' set ;;
|
|
48
52
|
seo|settings) _values 'subcommand' get set ;;
|
|
49
|
-
modules|extensions) _values 'subcommand' list enable disable config ;;
|
|
53
|
+
modules|extensions) _values 'subcommand' list docs enable disable config ;;
|
|
50
54
|
esac
|
|
51
55
|
;;
|
|
52
56
|
esac
|
|
@@ -63,8 +67,10 @@ export function generateFishCompletion() {
|
|
|
63
67
|
`complete -c frontpage -n "__fish_seen_subcommand_from runs" -a "current wait cancel retry get"`,
|
|
64
68
|
`complete -c frontpage -n "__fish_seen_subcommand_from deploy" -a "wait"`,
|
|
65
69
|
`complete -c frontpage -n "__fish_seen_subcommand_from media" -a "list upload"`,
|
|
70
|
+
`complete -c frontpage -n "__fish_seen_subcommand_from fonts" -a "list search"`,
|
|
71
|
+
`complete -c frontpage -n "__fish_seen_subcommand_from tokens" -a "set"`,
|
|
66
72
|
`complete -c frontpage -n "__fish_seen_subcommand_from seo settings" -a "get set"`,
|
|
67
|
-
`complete -c frontpage -n "__fish_seen_subcommand_from modules extensions" -a "list enable disable config"`,
|
|
73
|
+
`complete -c frontpage -n "__fish_seen_subcommand_from modules extensions" -a "list docs enable disable config"`,
|
|
68
74
|
`complete -c frontpage -l site -d "Site subdomain slug"`,
|
|
69
75
|
];
|
|
70
76
|
return `${lines.join("\n")}\n`;
|
package/dist/registry.d.ts
CHANGED
|
@@ -14,6 +14,6 @@ export type CommandDef = {
|
|
|
14
14
|
seeAlso?: string[];
|
|
15
15
|
};
|
|
16
16
|
export declare const COMMANDS: readonly CommandDef[];
|
|
17
|
-
export declare const TOPIC_NAMES: readonly ["quickstart", "auth", "sync", "agent", "content", "history", "isolation", "exit-codes"];
|
|
17
|
+
export declare const TOPIC_NAMES: readonly ["quickstart", "auth", "sync", "site-building", "agent", "content", "history", "isolation", "exit-codes"];
|
|
18
18
|
export declare const TOPICS: Record<string, string>;
|
|
19
19
|
export declare function findCommand(name: string): CommandDef | undefined;
|
package/dist/registry.js
CHANGED
|
@@ -7,8 +7,24 @@ export const COMMANDS = [
|
|
|
7
7
|
name: "help",
|
|
8
8
|
summary: "Show available commands",
|
|
9
9
|
usage: "frontpage help [command|topic] [--json]",
|
|
10
|
-
topics: [
|
|
11
|
-
|
|
10
|
+
topics: [
|
|
11
|
+
"auth",
|
|
12
|
+
"sync",
|
|
13
|
+
"site-building",
|
|
14
|
+
"agent",
|
|
15
|
+
"content",
|
|
16
|
+
"history",
|
|
17
|
+
"isolation",
|
|
18
|
+
"exit-codes",
|
|
19
|
+
"quickstart",
|
|
20
|
+
],
|
|
21
|
+
examples: [
|
|
22
|
+
"frontpage help",
|
|
23
|
+
"frontpage help sync",
|
|
24
|
+
"frontpage help site-building",
|
|
25
|
+
"frontpage help push",
|
|
26
|
+
"frontpage help --json",
|
|
27
|
+
],
|
|
12
28
|
},
|
|
13
29
|
{
|
|
14
30
|
name: "login",
|
|
@@ -110,8 +126,47 @@ export const COMMANDS = [
|
|
|
110
126
|
{
|
|
111
127
|
name: "search",
|
|
112
128
|
summary: "Search remote text files",
|
|
113
|
-
usage: "frontpage search <pattern> [path] [--site <slug>]",
|
|
129
|
+
usage: "frontpage search <pattern> [path] [--regex] [--case-sensitive] [--whole-word] [--files-only] [--context-lines N] [--max-results N] [--site <slug>] [--json]",
|
|
114
130
|
topics: ["sync"],
|
|
131
|
+
flags: [
|
|
132
|
+
"--regex",
|
|
133
|
+
"--case-sensitive",
|
|
134
|
+
"--whole-word",
|
|
135
|
+
"--files-only",
|
|
136
|
+
"--context-lines <n>",
|
|
137
|
+
"--max-results <n>",
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
name: "fonts",
|
|
142
|
+
summary: "Browse or search the self-hosted font catalog",
|
|
143
|
+
usage: "frontpage fonts [list|search] [--slot sans|serif|mono|display] [--query …] [--variable-only] [--limit N] [--offset N] [--json]",
|
|
144
|
+
topics: ["site-building", "content"],
|
|
145
|
+
examples: [
|
|
146
|
+
"frontpage fonts --slot serif",
|
|
147
|
+
'frontpage fonts search "elegant script"',
|
|
148
|
+
"frontpage fonts --query Cinzel --json",
|
|
149
|
+
],
|
|
150
|
+
flags: [
|
|
151
|
+
"Use the exact `value` string in tokens.fonts.* (via frontpage tokens set or push)",
|
|
152
|
+
"No --site required — catalog is account/platform scoped",
|
|
153
|
+
],
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
name: "tokens",
|
|
157
|
+
summary: "Set a single design token surgically (CAS + active-run)",
|
|
158
|
+
usage: "frontpage tokens set --group <colors|fonts|spacing|radii|article> --key <name> --value <…> [--site <slug>] [--json]",
|
|
159
|
+
topics: ["site-building", "content"],
|
|
160
|
+
examples: [
|
|
161
|
+
'frontpage tokens set --group fonts --key sans --value "\\"Inter Variable\\", system-ui, sans-serif"',
|
|
162
|
+
],
|
|
163
|
+
dangers: [
|
|
164
|
+
"Requires prior pull (baseCommitSha)",
|
|
165
|
+
"Refused while an agent run is active (exit 3)",
|
|
166
|
+
"CAS fail if remote tip moved (exit 3) — pull and retry",
|
|
167
|
+
"Off-catalog font values warn but do not block",
|
|
168
|
+
],
|
|
169
|
+
seeAlso: ["fonts", "pull", "push"],
|
|
115
170
|
},
|
|
116
171
|
{
|
|
117
172
|
name: "status",
|
|
@@ -203,16 +258,18 @@ export const COMMANDS = [
|
|
|
203
258
|
},
|
|
204
259
|
{
|
|
205
260
|
name: "modules",
|
|
206
|
-
summary: "List or mutate modules (secret masks only)",
|
|
207
|
-
usage: "frontpage modules [list|enable|disable|archive|config] <key> [--instance <id>] [--config '{…}'] [--site <slug>]",
|
|
261
|
+
summary: "List, read docs, or mutate modules (secret masks only)",
|
|
262
|
+
usage: "frontpage modules [list|docs|enable|disable|archive|config] <key> [--instance <id>] [--config '{…}'] [--site <slug>]",
|
|
208
263
|
topics: ["agent", "content"],
|
|
264
|
+
examples: ["frontpage modules docs forms", "frontpage modules list"],
|
|
209
265
|
dangers: ["Secret values are never returned — masks only"],
|
|
210
266
|
},
|
|
211
267
|
{
|
|
212
268
|
name: "extensions",
|
|
213
|
-
summary: "List or mutate extensions (no secret values)",
|
|
214
|
-
usage: "frontpage extensions [list|enable|disable|config] <key> [--config '{…}'] [--site <slug>]",
|
|
269
|
+
summary: "List, read docs, or mutate extensions (no secret values)",
|
|
270
|
+
usage: "frontpage extensions [list|docs|enable|disable|config] <key> [--config '{…}'] [--site <slug>]",
|
|
215
271
|
topics: ["agent", "content"],
|
|
272
|
+
examples: ["frontpage extensions docs charts"],
|
|
216
273
|
},
|
|
217
274
|
{
|
|
218
275
|
name: "media",
|
|
@@ -291,6 +348,7 @@ export const TOPIC_NAMES = [
|
|
|
291
348
|
"quickstart",
|
|
292
349
|
"auth",
|
|
293
350
|
"sync",
|
|
351
|
+
"site-building",
|
|
294
352
|
"agent",
|
|
295
353
|
"content",
|
|
296
354
|
"history",
|
|
@@ -315,8 +373,8 @@ export const TOPICS = {
|
|
|
315
373
|
|
|
316
374
|
Staging is the subdomain. There is no separate staging-deploy step for agents.
|
|
317
375
|
Never publish/unpublish unless the user explicitly asks.
|
|
318
|
-
Agents: read AGENTS.md
|
|
319
|
-
More: frontpage help auth | sync | agent | content | history | isolation | exit-codes`,
|
|
376
|
+
Agents: read AGENTS.md + frontpage help site-building; use --json for structured I/O.
|
|
377
|
+
More: frontpage help auth | sync | site-building | agent | content | history | isolation | exit-codes`,
|
|
320
378
|
auth: `Authentication
|
|
321
379
|
1. Create a key in the Frontpage editor: profile menu → Developers
|
|
322
380
|
2. frontpage login
|
|
@@ -335,7 +393,7 @@ export const TOPICS = {
|
|
|
335
393
|
frontpage push [--message …] # uploads allowlisted files; CAS + active-run guard
|
|
336
394
|
frontpage ls [prefix]
|
|
337
395
|
frontpage cat <path>
|
|
338
|
-
frontpage search <pattern>
|
|
396
|
+
frontpage search <pattern> [path] [--regex] [--case-sensitive] [--whole-word] [--files-only]
|
|
339
397
|
frontpage open # opens https://<slug>.frontpage.host/ (--prod is a no-op stub)
|
|
340
398
|
|
|
341
399
|
Local state: .frontpage/state.json { slug, baseCommitSha }
|
|
@@ -353,6 +411,40 @@ export const TOPICS = {
|
|
|
353
411
|
- No separate "deploy to staging" step for agents — review the subdomain after the build.
|
|
354
412
|
- frontpage deploy wait only waits for an in-flight build; it is NOT go-live.
|
|
355
413
|
- frontpage publish promotes staging → production (custom domain). Never publish unless asked.`,
|
|
414
|
+
"site-building": `Site building (Astro contract)
|
|
415
|
+
Stack: Astro 6 + Tailwind v4. Pages in src/pages/. Every page wraps <BaseLayout title description>.
|
|
416
|
+
Control files: src/config/tokens.ts (design tokens), src/config/site.ts (title, nav, pages map, seo).
|
|
417
|
+
|
|
418
|
+
Pages map:
|
|
419
|
+
- Add/rename/delete a page file ⇒ update pages (+ nav if needed) in the SAME change set.
|
|
420
|
+
- Real title/description live on <BaseLayout>, not as authority in the pages map.
|
|
421
|
+
- One discrete .astro file per URL for similar sets (services, guides…). Do NOT default to
|
|
422
|
+
getStaticPaths() over src/data/*.ts. Blog/news → frontpage articles.
|
|
423
|
+
|
|
424
|
+
Hard fences:
|
|
425
|
+
- No API routes, serverless backends, or databases.
|
|
426
|
+
- No fake lead forms / checkout / card fields — use data-fp-* modules + frontpage modules, or refuse.
|
|
427
|
+
- Platform-owned paths are not syncable (BaseLayout overlay, module/extension shells, package.json…).
|
|
428
|
+
- Customer layouts (DocsLayout, GuideLayout, …) are fine when site-owned.
|
|
429
|
+
|
|
430
|
+
Tokens & fonts:
|
|
431
|
+
- Keep required colors/fonts/spacing/radii keys; style via CSS variables / token Tailwind.
|
|
432
|
+
- Setting fonts.sans is not enough — apply font-sans / font-serif / font-display on elements.
|
|
433
|
+
- Browse fonts: frontpage fonts [--slot serif] [--query elegant] — use the exact value string.
|
|
434
|
+
- Surgical token edit: frontpage tokens set --group fonts --key sans --value "…" (CAS like push).
|
|
435
|
+
|
|
436
|
+
Chrome / SEO / 404:
|
|
437
|
+
- Prefer src/components/Header.astro + Footer.astro (or chrome: { managed: true } in site.ts).
|
|
438
|
+
- seo block in site.ts + frontpage seo get|set; customize 404.astro but keep frontpage:404 meta;
|
|
439
|
+
never put /404 in nav or pages. robots/sitemap are platform-managed.
|
|
440
|
+
|
|
441
|
+
Modules & articles (short):
|
|
442
|
+
- Forms: <form data-fp-form="slug"> with named inputs; no action/onsubmit/honeypot.
|
|
443
|
+
- Articles: frontpage articles …; migrate folders via frontpage prompt (don't invent mass delete+write).
|
|
444
|
+
- Media in markup: /__media/uploads/<slug>/… from frontpage media (not raw blob URLs).
|
|
445
|
+
|
|
446
|
+
Full guide: https://frontpage.host/developers/site-building
|
|
447
|
+
See also: frontpage help sync | content | AGENTS.md`,
|
|
356
448
|
agent: `Agent + publish
|
|
357
449
|
frontpage prompt "make the hero shorter"
|
|
358
450
|
frontpage runs # latest + active
|
|
@@ -376,13 +468,19 @@ export const TOPICS = {
|
|
|
376
468
|
frontpage inbox [leads|subscribers|orders|…] [--mark-read] [--csv]
|
|
377
469
|
frontpage seo get|set --path /
|
|
378
470
|
frontpage articles list|content|create-section|create-article|set-draft|…
|
|
379
|
-
frontpage
|
|
380
|
-
frontpage
|
|
471
|
+
frontpage fonts [list|search] [--slot …] [--query …]
|
|
472
|
+
frontpage tokens set --group … --key … --value …
|
|
473
|
+
frontpage modules list|docs|enable|disable|archive|config <key>
|
|
474
|
+
frontpage extensions list|docs|enable|disable|config <key>
|
|
381
475
|
frontpage settings get|set
|
|
382
476
|
frontpage edit --path / --old "…" --new "…"
|
|
383
477
|
|
|
478
|
+
Real forms (file sync): <form data-fp-form="slug"> + named inputs — no action/onsubmit/honeypot.
|
|
479
|
+
Do not fake payments/checkout. LOCKED extensions → do not fake; say plan required.
|
|
480
|
+
Migrate pages → articles: prefer frontpage prompt "migrate …" over mass delete+write.
|
|
384
481
|
edit uses click-edit (exact single occurrence), not push / gated-write.
|
|
385
482
|
Module OAuth and secret values are not exposed via the CLI.
|
|
483
|
+
Site contract: frontpage help site-building · https://frontpage.host/developers/site-building
|
|
386
484
|
Domains, billing, members, and site delete are out of v1.`,
|
|
387
485
|
history: `History
|
|
388
486
|
frontpage history [--limit 20] [--page 1]
|
package/llms.txt
CHANGED
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
- Package: frontpage-host (npm). Binary: frontpage. Do NOT install npm package "frontpage".
|
|
4
4
|
- Docs in this package: README.md, AGENTS.md (agent operating manual).
|
|
5
5
|
- Introspect: frontpage help | frontpage help --json | frontpage help <topic|command>
|
|
6
|
-
- Topics: quickstart, auth, sync, agent, content, history, isolation, exit-codes
|
|
6
|
+
- Topics: quickstart, auth, sync, site-building, agent, content, history, isolation, exit-codes
|
|
7
|
+
- Site building: frontpage help site-building — Astro pages map, BaseLayout, tokens, no backends/fake forms
|
|
8
|
+
- Fonts: frontpage fonts [--slot] [--query] — use exact value; tokens: frontpage tokens set --group --key --value (CAS)
|
|
9
|
+
- Module/extension docs: frontpage modules docs <key> | frontpage extensions docs <key>
|
|
10
|
+
- Search flags: --regex --case-sensitive --whole-word --files-only --context-lines --max-results
|
|
7
11
|
- Auth: mint fp_live_ key in Frontpage UI (Developers); frontpage login KEY or FRONTPAGE_API_KEY
|
|
8
12
|
- Site id: subdomain only (frontpage use <subdomain>). Not custom domains.
|
|
9
13
|
- Staging: https://<subdomain>.frontpage.host — push/prompt/edit update staging; no separate staging deploy step for agents
|