frontpage-host 0.1.4 → 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 CHANGED
@@ -100,7 +100,7 @@ Sites are Astro 6 + Tailwind v4. More detail: `frontpage help site-building` or
100
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
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
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`. No CLI font catalog yet; use existing tokens or `frontpage prompt`.
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
104
  6. **Shared chrome** — prefer `src/components/Header.astro` + `Footer.astro` (or `chrome: { managed: true }` in `site.ts`).
105
105
  7. **404** — customize `src/pages/404.astro` if needed; keep `frontpage:404` meta; never register `/404` in `nav`/`pages`.
106
106
  8. **Platform-owned paths** stay off-limits (BaseLayout overlay, module/extension shells, `package.json`, …). Customer layouts like `DocsLayout` / `GuideLayout` are OK.
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
+ }
@@ -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) {
@@ -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 pattern = rest[0];
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
- const matches = data.matches ?? [];
17
- for (const m of matches) {
18
- console.log(`${m.file}:${m.lineNumber}: ${m.line}`);
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
+ }
@@ -19,10 +19,12 @@ _frontpage_completions() {
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.js CHANGED
@@ -126,8 +126,47 @@ export const COMMANDS = [
126
126
  {
127
127
  name: "search",
128
128
  summary: "Search remote text files",
129
- 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]",
130
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"],
131
170
  },
132
171
  {
133
172
  name: "status",
@@ -219,16 +258,18 @@ export const COMMANDS = [
219
258
  },
220
259
  {
221
260
  name: "modules",
222
- summary: "List or mutate modules (secret masks only)",
223
- 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>]",
224
263
  topics: ["agent", "content"],
264
+ examples: ["frontpage modules docs forms", "frontpage modules list"],
225
265
  dangers: ["Secret values are never returned — masks only"],
226
266
  },
227
267
  {
228
268
  name: "extensions",
229
- summary: "List or mutate extensions (no secret values)",
230
- 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>]",
231
271
  topics: ["agent", "content"],
272
+ examples: ["frontpage extensions docs charts"],
232
273
  },
233
274
  {
234
275
  name: "media",
@@ -352,7 +393,7 @@ export const TOPICS = {
352
393
  frontpage push [--message …] # uploads allowlisted files; CAS + active-run guard
353
394
  frontpage ls [prefix]
354
395
  frontpage cat <path>
355
- frontpage search <pattern>
396
+ frontpage search <pattern> [path] [--regex] [--case-sensitive] [--whole-word] [--files-only]
356
397
  frontpage open # opens https://<slug>.frontpage.host/ (--prod is a no-op stub)
357
398
 
358
399
  Local state: .frontpage/state.json { slug, baseCommitSha }
@@ -389,7 +430,8 @@ export const TOPICS = {
389
430
  Tokens & fonts:
390
431
  - Keep required colors/fonts/spacing/radii keys; style via CSS variables / token Tailwind.
391
432
  - Setting fonts.sans is not enough — apply font-sans / font-serif / font-display on elements.
392
- - No frontpage fonts catalog command yet; read tokens.ts or frontpage prompt.
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).
393
435
 
394
436
  Chrome / SEO / 404:
395
437
  - Prefer src/components/Header.astro + Footer.astro (or chrome: { managed: true } in site.ts).
@@ -426,8 +468,10 @@ export const TOPICS = {
426
468
  frontpage inbox [leads|subscribers|orders|…] [--mark-read] [--csv]
427
469
  frontpage seo get|set --path /
428
470
  frontpage articles list|content|create-section|create-article|set-draft|…
429
- frontpage modules enable|disable|archive|config <key>
430
- frontpage extensions enable|disable|config <key>
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>
431
475
  frontpage settings get|set
432
476
  frontpage edit --path / --old "…" --new "…"
433
477
 
package/llms.txt CHANGED
@@ -5,6 +5,9 @@
5
5
  - Introspect: frontpage help | frontpage help --json | frontpage help <topic|command>
6
6
  - Topics: quickstart, auth, sync, site-building, agent, content, history, isolation, exit-codes
7
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
8
11
  - Auth: mint fp_live_ key in Frontpage UI (Developers); frontpage login KEY or FRONTPAGE_API_KEY
9
12
  - Site id: subdomain only (frontpage use <subdomain>). Not custom domains.
10
13
  - Staging: https://<subdomain>.frontpage.host — push/prompt/edit update staging; no separate staging deploy step for agents
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frontpage-host",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Frontpage CLI — manage your site from the terminal",
5
5
  "type": "module",
6
6
  "bin": {