frontpage-host 0.3.16 → 0.3.18

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
@@ -121,7 +121,7 @@ Sites are Astro 6 + Tailwind v4. More detail: `frontpage help site-building` or
121
121
  - Forms: `data-fp-form` markup in pages + `frontpage modules` for enable/config. No submit JS / honeypot / `action`. Do not put a CRM webhook or token in HTML.
122
122
  - Connect-once modules: Store Stripe connect is `frontpage payments connect`. `--no-open` for CI. `request-setup` remains valid when you want the **editor amber bar** instead. Payments and Store share one Stripe account. Pause Payments through its availability action; generic module writes cannot bypass invoice/recurring stop rules. Auto-active modules (forms/callbar/…) need markup, not request-setup. Typed settings: `frontpage modules callbar|forms|booking|signups get|set` (forms set needs `--instance`; do not target `default`). Form destinations (HubSpot / Pipedrive / Privyr): connect once, then attach each form. `frontpage modules forms destinations|connect-destination|attach-destination|detach-destination|remove-destination --yes|request-destination-setup`. Token write is **admin**; `request-destination-setup` lights the editor amber bar (**editor** key). Do not use `request-setup forms` for a CRM (no-op). Connecting does not attach every form. Privyr: paste the Incoming Webhook URL from Automations → Lead Sources → Webhooks (`https://www.privyr.com/api/v1/incoming-leads/…`), not a token and not Outgoing Webhooks. HubSpot: Development → Keys → Service keys or Development → Legacy apps → Auth → Show token. Pipedrive: profile → Company settings → Personal preferences → API. Full docs: https://frontpage.host/developers/modules#forms-destinations. `frontpage modules <key>` prints that key's CLI usage (exit 2). Index: https://frontpage.host/developers/modules. Store: https://frontpage.host/developers/store
123
123
  - Google reviews: platform nodes only (`data-fp-google-reviews` / `data-fp-google-ask` + required `data-fp-requires="google_reviews"`). `data-layout` is `feed` (default), `badge`, or `link`. Never invent stars, quotes, a 1–10, or a Maps URL. Do not pick a Place ID via Autocomplete and do not write `placeId` through `modules config`. Owner-supplied Place ID / Maps URL: `frontpage modules google_reviews connect --place-id …` or `--maps-url …` (server resolves + seeds). Curation: `list-reviews`, `hide --id`, `show --id`, `set-stars`, `set-sort`, `set-weight`, `reset-weights`, `refresh`, `disconnect`. Usage: `frontpage modules google_reviews`. Docs: https://frontpage.host/developers/modules/google-reviews. Ask-widget scores: `frontpage inbox google_reviews`.
124
- - 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`.
124
+ - Articles needs no setup. `frontpage articles create-section --label "Blog" --route blog` creates an active section. Use `archive-section --section blog` / `restore-section --section blog` to turn it off / on. Draft articles stay unpublished. Bodies use sync under `content/` or `articles content get|set`. The section landing is an owned `src/pages/<section>/index.astro`. Frontpage manages article routing; do not read or edit the managed routing file.
125
125
  - Migrate a folder into Articles: prefer `frontpage prompt "migrate … into articles"` — do not invent a mass delete+write migration.
126
126
  - Extensions: `frontpage extensions`; if LOCKED on plan, do not fake charts/etc.
127
127
  - Media: `frontpage media upload <file>` — images/PDF ≤25 MB, video (MP4/WebM/MOV) ≤50 MB, SVG/text ≤4 MB (sanitizing proxy). Human output prints `sitePath:` first (use that in markup — never raw blob hosts), then optional `url:`. Optional `?w=` on rasters only. **Text/CSV** uploads are inline only — **not** added to the media library and **cannot** be linked via `/__media` (`media upload --json` omits full `content`; use `inbox … --csv` for submission exports).
@@ -282,7 +282,7 @@ AI Support Agent team guidance: administrators may set `guidanceEmail` through t
282
282
 
283
283
  ## Emails workspace workflows
284
284
 
285
- Campaign timing uses the existing `mail save --file` and `mail campaign preview|send|get` commands. Read [MAIL.md, Campaign scheduling](./MAIL.md#campaign-scheduling) before using it. Save document.scheduledAt as a future ISO timestamp with an explicit timezone, null for Send now, or omit to retain it. Saving never confirms sending; overdue drafts remain drafts. Read settings for the business timezone. Review the post-save content timestamp, exact audience, eligible count and saved schedule before campaign send with a stable requestKey. Confirmed groups/filters resolve once, and normal delivery restrictions remain. The owner agent uses save_mail_editor then manage_people area:campaign; MCP uses save_mail_editor and campaign.preview/send/get. Direct saved-email sends cannot bypass a dated campaign. Reuse exact requests after uncertain responses.
285
+ Campaign timing uses the existing `mail save --file` and `mail campaign preview|send|get|unschedule|reschedule` commands. Read [MAIL.md, Campaign scheduling](./MAIL.md#campaign-scheduling) before using it. Save document.scheduledAt as a future ISO timestamp with an explicit timezone, null for Send now, or omit to retain it. Saving never confirms sending; overdue drafts remain drafts. Use document.scheduleLocal:{dateTime,timeZone} for local YYYY-MM-DDTHH:mm plus IANA timezone; the server converts it. ISO scheduledAt remains supported. Do not supply both. Review the post-save content timestamp, exact audience, eligible count and saved schedule before campaign send with a stable requestKey. Confirmed groups/filters resolve once, and normal delivery restrictions remain. The owner agent uses save_mail_editor then manage_people area:campaign; MCP uses save_mail_editor and campaign.preview/send/get. Direct saved-email sends cannot bypass a dated campaign. Reuse exact requests after uncertain responses. Before queueing, unschedule cancels a scheduled email to Draft, keeping its email/audience; reschedule changes only time and retains confirmed recipients/content. Both require documentUpdatedAt from a fresh get and a stable requestKey. Reschedule accepts scheduleLocal or scheduledAt. Read MAIL.md for examples.
286
286
 
287
287
  See [MAIL.md](./MAIL.md) for the complete save contract, reusable people picker directory, saved campaign recipients, Off-series enrollment and resume timing, all sender settings/null resets, suppression rules, Sent queries and details, and retry-safe examples. `frontpage mail save --file save.json` saves template and pending series together; it never sends. New series default On; existing series retain their saved state. Save email steps before enrolling anyone. Check the returned series status before attaching it to a rule; an Off series holds enrollment until turned On. `frontpage mail people` reads the same site-scoped directory as the workspace. Use `frontpage help mail --json` for current commands and flags. No new CLI binary, API namespace or migration command is required. Hosted guides and article help must be updated through the Frontpage CLI.
288
288
 
package/MAIL.md CHANGED
@@ -111,13 +111,15 @@ The workspace, CLI, owner agent and MCP use the same saved campaign and confirma
111
111
  | Save draft, audience and timing | `mail save --file draft.json` | `save_mail_editor` | `frontpage_mail_write`, operation `save_mail_editor` |
112
112
  | Review audience | `mail campaign preview --file audience.json` | `manage_people`, area `campaign`, operation `preview` | `frontpage_mail_read`, operation `campaign.preview` |
113
113
  | Confirm sending or scheduling | `mail campaign send --id ID --file review.json --request-key KEY` | `manage_people`, area `campaign`, operation `send` | `frontpage_mail_write`, operation `campaign.send` |
114
+ | Cancel a scheduled email | `mail campaign unschedule --id ID --file cancel.json --request-key KEY` | `manage_people`, area `campaign`, operation `unschedule` | `frontpage_mail_write`, operation `campaign.unschedule` |
115
+ | Change a confirmed time | `mail campaign reschedule --id ID --file time.json --request-key KEY` | `manage_people`, area `campaign`, operation `reschedule` | `frontpage_mail_write`, operation `campaign.reschedule` |
114
116
  | Read saved audience, timing and status | `mail campaign get --id ID --json` | `manage_people`, area `campaign`, operation `get` | `frontpage_mail_read`, operation `campaign.get` |
115
117
 
116
118
  Use `--site YOUR_SITE --json` with each CLI command. Agent calls bind the current site; never supply a siteId. MCP calls take `slug`, `operation` and `payload`, with the same fields inside payload. Existing role, plan, consent and delivery checks apply.
117
119
 
118
120
  ### Save a schedule without sending
119
121
 
120
- Read the current campaign and `mail settings get` first. Convert the owner's chosen local date and time using the saved IANA timezone. `document.scheduledAt` accepts a future ISO timestamp with `Z` or an explicit offset. Do not guess an offset or silently shift a time that does not exist during daylight-saving changes. Ask for clarification if a repeated local time is ambiguous.
122
+ Read the current campaign first. The workspace uses the viewer's local timezone. Tools can save `document.scheduleLocal:{dateTime:"2030-11-15T09:00",timeZone:"America/Chicago"}`; the server converts local time to UTC. Use an IANA timezone, not a guessed offset. Missing clock-change times are rejected; repeated clock-change times use the earlier occurrence. Ask for the owner's timezone if unknown. Existing `document.scheduledAt` ISO timestamps with `Z` or an explicit offset still work. Supply only one timing input. Omit both to retain timing; scheduledAt:null selects Send now.
121
123
 
122
124
  - A timestamp selects Schedule for later.
123
125
  - `null` selects Send now and clears the saved date. It still does not send.
@@ -175,10 +177,41 @@ frontpage mail campaign get --id CAMPAIGN_DOCUMENT_ID --site YOUR_SITE --json
175
177
 
176
178
  Copy the canonical UTC scheduledAt from the saved response into review, or null for Send now. Use the exact post-save document timestamp and preview's eligible count; never use a timestamp from before an audience save. The service rejects a changed reviewed audience, count, content timestamp or scheduled time. A past date needs a new future date or Send now before confirmation. Existing older callers without review fields remain supported; agents should always supply the complete review.
177
179
 
178
- Confirmation freezes the eligible recipients and content. Groups and filters resolve at confirmation, not at the future send time. Permission, opt-out and delivery checks still apply before sending. A confirmed future campaign has stored status `pending` and scheduledAt; the UI labels that combination Scheduled. Drafts remain `draft` regardless of date. Queued, sent and delivered are different states; read campaign counts and the send ledger. Confirmed campaigns cannot be edited through this flow; cancellation and rescheduling are not added here.
180
+ Confirmation freezes the eligible recipients and content. Groups and filters resolve at confirmation, not at the future send time. Permission, opt-out and delivery checks still apply before sending. A confirmed future campaign has stored status `pending` and scheduledAt; the UI labels that combination Scheduled. Drafts remain `draft` regardless of date. Queued, sent and delivered are different states; read campaign counts and the send ledger. Before queueing begins, a confirmed schedule can be cancelled or moved as described below. Its content and recipients stay fixed unless cancelled and confirmed again.
181
+
182
+ `campaign get` returns `counts.sent` as the number accepted by the email provider, including messages later marked delivered, bounced or complained. Check individual send records for those delivery outcomes; acceptance does not promise inbox delivery. Delivery updates do not use another email from the allowance. Unfinished reservations still hold allowance until they send or fail. Configured hourly, daily and monthly limits stay unchanged.
183
+
184
+ Delivery callbacks save the event, send outcome and any required site restriction together. If that save fails, the provider receives an error so it can retry; repeated events do not apply twice. A delay cannot undo delivery, and delivery cannot erase a hard bounce or complaint. Temporary bounces and delivery delays appear as sent with a delay detail while the provider handles delivery. A delivered event clears that detail. Failed events keep the provider reason on the send record. They do not queue a second email. Hard bounces, complaints and provider suppressions restrict that address and cancel its active series enrollments on that site. Existing unsubscribes stay in effect. These updates apply to workspace, CLI and agent sends through the same service; commands, permissions and limits stay unchanged.
185
+
186
+ The existing worker defers a blocked site's due backlog so other sites can progress. Hourly and temporary holds retry after one minute; monthly allowance and sender-setup holds retry after five minutes. Future send/retry times and other workers' active claims stay intact. Provider requests time out after 15 seconds, including a stalled response body. Remaining batch claims are released on an early exit; a worker that stops before cleanup uses the existing ten-minute stale-claim recovery.
187
+
188
+ Each email keeps its original provider request and send ID after the first attempt. Later sender-setting changes do not change that retry. Temporary failures and throttling use the existing eight-attempt limit, exponential waits and a longer provider Retry-After. Waits start from the current attempt's completion. A provider throttle also defers the existing shared marketing provider slot, so other marketing messages honor that wait. Automatic sends stop after 23 hours from the first attempt, inside the provider's 24-hour duplicate-protection window. An older attempted or abandoned claimed row without its original request also stops with an uncertain-outcome error on its failed send record. Check send history and known provider IDs before deciding what to do; never automatically create a new batch or request key to repeat an uncertain send. These errors add no recovery workflow. A successful response or accepted delivery confirmation advances its series step once, including after a lost response. The next wait uses the provider message creation time when available, otherwise the confirmation time. Repeated confirmations never reset that wait or restart cancelled/completed enrollments. Series Off state, enrollment, restrictions and the platform sending switch are checked again after pacing. Campaign schedules keep their existing behavior.
179
189
 
180
190
  Keep the same requestKey and exact payload after an uncertain save or confirmation. Read back campaign state and retry the original request; never create a new send key to recover an uncertain result. A changed request needs a fresh review. The older `mail send email` / `send_mail_email` path sends immediately and cannot confirm a scheduled campaign; it returns a conflict for dated campaigns. Use campaign send instead. Test sends and dry runs do not confirm or start the campaign; existing test restrictions still apply.
181
191
 
192
+ ### Manage a confirmed schedule
193
+
194
+ Read `campaign get` immediately before reviewing a change. It returns `documentUpdatedAt` and `canManageSchedule`. **Cancel scheduled email** uses `unschedule`: it changes status to `draft`, clears scheduledAt and the old confirmed snapshot/recipients, and keeps the email and saved audience. Normal editing resumes. Saving that draft never sends it; sending or scheduling again needs a fresh review and explicit confirmation with a new send request key. There is no cancelled campaign state.
195
+
196
+ `reschedule` changes only time. Show the saved email, recipient count, current time and proposed time, then get the owner's approval. It retains the confirmed recipients/content even if groups have changed. Closing the review makes no change.
197
+
198
+ Both actions work only while the campaign is confirmed and dated, before its first queue batch. They may still work after the due time if queueing has not begun. Once queueing begins, the service rejects them with 409. Refresh and show the saved state; do not substitute a new timestamp without a fresh review.
199
+
200
+ `cancel.json`:
201
+ ```json
202
+ {"documentUpdatedAt":"POST_READ_TIMESTAMP"}
203
+ ```
204
+ `time.json`:
205
+ ```json
206
+ {"documentUpdatedAt":"POST_READ_TIMESTAMP","scheduleLocal":{"dateTime":"2030-11-16T09:00","timeZone":"America/Chicago"}}
207
+ ```
208
+ ```sh
209
+ frontpage mail campaign unschedule --id CAMPAIGN_DOCUMENT_ID --file cancel.json --request-key CANCEL_KEY --site YOUR_SITE --json
210
+ frontpage mail campaign reschedule --id CAMPAIGN_DOCUMENT_ID --file time.json --request-key CHANGE_KEY --site YOUR_SITE --json
211
+ ```
212
+
213
+ For reschedule, scheduledAt is also accepted instead of scheduleLocal. Keep the original key and exact payload after a lost response, then read back state. Accepted action keys cannot reapply an older change over a newer one. An old send confirmation retry cannot restart a cancelled draft. A different action needs a new request key. These operations share the worker's campaign lock and add no table, campaign state or worker.
214
+
182
215
  ### Email capability release check
183
216
 
184
217
  For each changed Email capability, check its shared service, UI, public API, CLI help and examples, owner-agent schema/instructions, and MCP operation/docs. Add focused contract checks and test the real adapters. Run `node scripts/people/sync-agent-docs.mjs` after editing the packaged manuals and `node scripts/people/sync-agent-docs.mjs --check` before release. Publish hosted guides through the Frontpage CLI only, then verify the public page. Do not maintain a separate scheduling implementation or a second internal manual.
@@ -196,7 +229,7 @@ Sort values: `newest`, `oldest`, `name`. Added order uses the CRM record's added
196
229
  Use existing `frontpage people workspace series.preview --file preview.json` then `series.enrol --file batch.json` for reviewed CRM enrollment. Preview input: `{ "seriesId":"SERIES_ID", "personIds":["PERSON_ID"] }`. Each returned batch contains personIds and reviewToken; commit with those fields, seriesId and a stable requestKey. Reuse each batch's key after a network error. Receipts preserve partial outcomes. Enrollment saves immediately and never requires Save series afterward. Existing enrollment is deduplicated across all states; completed/cancelled people do not restart.
197
230
 
198
231
  - **Off:** eligible people wait at step 1. Enrollment creates no queued message, first-template snapshot, due date or allowance reservation. No sender readiness or send meter is needed to record waiting people.
199
- - **On:** the first email becomes ready, subject to normal permission, sender, kill switch, send window and allowance checks.
232
+ - **On:** the first email becomes ready, subject to normal permission, sender, kill switch and allowance checks. Series can send at any hour; later steps keep their configured delays.
200
233
  - **Turning Off:** pending series messages stop before provider handoff. A message already accepted by the provider cannot be recalled.
201
234
  - **Turning On again:** new waiting people begin at step 1. Started people resume their next unsent step with its saved due date; an overdue step can send on the next pass. Each later wait starts after successful provider acceptance. Off time never skips a new person's first email or causes all later steps to send at once.
202
235
 
@@ -209,11 +242,11 @@ Selections with IDs use a read-only `POST /api/v1/sites/YOUR_SITE/mail/people` b
209
242
  ## Settings and suppressions
210
243
 
211
244
  ```bash
212
- frontpage mail settings set --header-align center --window-start 540 --window-end 1020 --hourly-cap 100 --site YOUR_SITE
245
+ frontpage mail settings set --header-align center --hourly-cap 100 --site YOUR_SITE
213
246
  frontpage mail settings set --file settings.json --site YOUR_SITE --json
214
247
  ```
215
248
 
216
- The settings JSON accepts exactly replyTo, postalLine, fromName, timezone, sendWindowStart, sendWindowEnd, hourlyCap and headerAlign. Omitted fields stay unchanged. Null clears replyTo, postalLine, fromName or hourlyCap. Window values are integer minutes after midnight (0–1439), hourlyCap is null or 1–1000, timezone is an IANA time zone, and headerAlign is left/center/right. A business postal address is still required for actual marketing sends. `--hourly-cap null` clears that cap. A settings save, content edit, read, cancellation or switch Off does not depend on the send meter.
249
+ The settings JSON accepts exactly replyTo, postalLine, fromName, timezone, sendWindowStart, sendWindowEnd, hourlyCap and headerAlign. Omitted fields stay unchanged. Null clears replyTo, postalLine, fromName or hourlyCap. sendWindowStart/sendWindowEnd and --window-start/--window-end are retained only for compatibility and no longer restrict sending. Their stored values remain integer minutes after midnight (0–1439). hourlyCap is null or 1–1000, timezone is an IANA time zone, and headerAlign is left/center/right. A business postal address is still required for actual marketing sends. `--hourly-cap null` clears that cap. A settings save, content edit, read, cancellation or switch Off does not depend on the send meter.
217
250
 
218
251
  `mail suppress list|add|rm` uses the existing site suppression service. Adding stops that site's marketing campaigns/series and cancels active enrollments. Transactional receipts and support replies follow separate rules. Removing a suppression does not restore consent, resubscribe someone or restart cancelled series.
219
252
 
package/PEOPLE.md CHANGED
@@ -579,7 +579,7 @@ Preview reports matched, eligible, no-email, suppressed, and permission-missing
579
579
 
580
580
  Campaigns can also schedule a future send through `mail save` with `document.scheduledAt`. A date on a draft never sends it. After reviewing content, audience and time, `mail campaign send` confirms the saved schedule; the existing worker waits until due. Send now uses scheduledAt:null. `campaign get` returns stored status and scheduledAt; pending plus a future time displays Scheduled in the UI. Groups and filters resolve when confirmed. Read [MAIL.md, Campaign scheduling](./MAIL.md#campaign-scheduling) for complete save, review, retry, agent and MCP examples. Direct `mail send email` is for immediate unscheduled sends and cannot bypass a saved schedule.
581
581
 
582
- For the owner agent, call `set_mail_settings({})` to read the business timezone, then `save_mail_editor` with a one_off document and future ISO scheduledAt including Z or an explicit offset. Omission preserves timing; null clears it. Read `get_mail_email` after saving and `manage_people` with area:campaign, operation:get for saved timing/audience, then operation:preview for the exact audience and eligible count. Show the owner the content, recipients and local send time. On explicit confirmation, call `manage_people` with area:campaign, operation:send, payload:{documentId,requestKey,review:{audience,eligible,documentUpdatedAt,scheduledAt}}. Use the post-save document timestamp, preview count and canonical saved UTC time. These values must still match; a changed review needs a fresh read and approval. Keep the original requestKey and payload after an uncertain result and read back state before retrying. Never use direct send_mail_email to bypass timing. MCP uses `frontpage_mail_write` operation:save_mail_editor and campaign.send, with campaign.get/preview through `frontpage_mail_read`. A confirmed campaign cannot be edited or rescheduled in this flow.
582
+ For the owner agent, use `save_mail_editor` with a one_off document and `scheduleLocal:{dateTime:"2030-11-15T09:00",timeZone:"America/Chicago"}`. The server converts local time to UTC. Use the owner's timezone; ask if unknown. Future ISO scheduledAt including Z or an explicit offset remains supported; do not supply both. Omission preserves timing; null clears it. Read `get_mail_email` after saving and `manage_people` with area:campaign, operation:get for saved timing/audience, then operation:preview for the exact audience and eligible count. Show the owner the content, recipients and local send time. On explicit confirmation, call `manage_people` with area:campaign, operation:send, payload:{documentId,requestKey,review:{audience,eligible,documentUpdatedAt,scheduledAt}}. Use the post-save document timestamp, preview count and canonical saved UTC time. These values must still match; a changed review needs a fresh read and approval. Keep the original requestKey and payload after an uncertain result and read back state before retrying. Never use direct send_mail_email to bypass timing. MCP uses `frontpage_mail_write` operation:save_mail_editor and campaign.send, with campaign.get/preview through `frontpage_mail_read`. Before queueing, campaign.unschedule cancels the scheduled email to Draft; campaign.reschedule changes only time. Both use documentUpdatedAt from a fresh campaign.get and a stable requestKey. Reschedule takes scheduleLocal or scheduledAt. Get approval for the new time and retain confirmed recipients/content. Cancellation keeps the email/audience for editing; scheduling again needs fresh confirmation and a new send key. Old accepted retries cannot undo later actions. UI, CLI, agent and MCP share this service. See the Mail guide for examples.
583
583
 
584
584
  ## CLI, API, and agent reference
585
585
 
package/README.md CHANGED
@@ -57,6 +57,18 @@ Machine-readable: `frontpage help --json` and global `--json` / `--quiet` on com
57
57
  See [AGENTS.md](./AGENTS.md) and [llms.txt](./llms.txt) in this package.
58
58
 
59
59
 
60
+ ## Articles
61
+
62
+ Articles needs no setup. Creating a section makes it active:
63
+
64
+ ```bash
65
+ frontpage articles create-section --label "Blog" --route blog
66
+ frontpage articles archive-section --section blog
67
+ frontpage articles restore-section --section blog
68
+ ```
69
+
70
+ Use `create-article` or `content get|set` to write content. Draft articles stay unpublished. Frontpage manages article routing; do not read or edit the managed routing file.
71
+
60
72
  ## People groups, stages, rules, and imports
61
73
 
62
74
  Use `frontpage people overview`, `groups`, `stages`, `membership`, `rules`, `attachments`, `import`. Use `frontpage mail campaign` for one-off group/stage/list audiences in Emails. Every editor action is available through these commands or `frontpage people workspace OPERATION --file payload.json`. Full operations and examples: [PEOPLE.md](./PEOPLE.md); public guide: https://frontpage.host/developers/people. Automated emails select a saved template or series. Campaigns use their own drafts.
@@ -124,7 +124,7 @@ export async function runCampaign(slug, args) {
124
124
  ...payload,
125
125
  operation,
126
126
  ...(documentId ? { documentId } : {}),
127
- ...(operation === "send"
127
+ ...(["send", "unschedule", "reschedule"].includes(operation)
128
128
  ? { requestKey: requestKey ?? payload.requestKey }
129
129
  : {}),
130
130
  });
@@ -133,8 +133,8 @@ export const MODULE_COMMANDS = [
133
133
  {
134
134
  key: "articles",
135
135
  name: "Articles",
136
- summary: "Content hub. Lifecycle lives on `frontpage articles`, not under modules.",
137
- genericActions: GENERIC_ACTIONS,
136
+ summary: "Articles needs no setup. Manage sections with `frontpage articles`.",
137
+ genericActions: ["docs", "request-setup", "config"],
138
138
  extraActions: [],
139
139
  notYet: [],
140
140
  examples: [
@@ -143,7 +143,7 @@ export const MODULE_COMMANDS = [
143
143
  "frontpage articles list",
144
144
  ],
145
145
  notes: [
146
- "Do not fold article create/edit under `modules articles`. Use `frontpage articles …`.",
146
+ "Creating a section makes it active. Use `frontpage articles create-section`, `archive-section`, or `restore-section`; draft articles stay unpublished. `request-setup articles` only explains this and makes no changes.",
147
147
  ],
148
148
  },
149
149
  {
@@ -263,8 +263,10 @@ export function formatModuleUsage(key) {
263
263
  "",
264
264
  "Actions (generic):",
265
265
  " docs Markup / agent how-to",
266
- " request-setup Amber bar in the editor (CLI cannot show it)",
267
- " enable|disable|archive",
266
+ key === "articles"
267
+ ? " request-setup No setup needed; makes no changes"
268
+ : " request-setup Amber bar in the editor (CLI cannot show it)",
269
+ ...(def.genericActions.includes("enable") ? [" enable|disable|archive"] : []),
268
270
  " config --config '{…}' Whitelisted JSON only",
269
271
  ];
270
272
  if (def.extraActions.length) {
package/dist/registry.js CHANGED
@@ -363,7 +363,7 @@ export const COMMANDS = [
363
363
  ],
364
364
  dangers: [
365
365
  "Secret values are never returned — masks only",
366
- "request-setup surfaces an owner prompt in the editor status bar (CLI cannot show it)",
366
+ "request-setup surfaces an owner prompt only for modules that need setup. Articles needs none; create a section with frontpage articles create-section.",
367
367
  "payments and the store share one Stripe account — payments disconnect 409s if the store still uses it",
368
368
  "OAuth cannot finish in the terminal; connect only opens the vendor URL",
369
369
  "Do not write placeId through generic config — that skips listing resolve + seed",
@@ -598,11 +598,11 @@ export const COMMANDS = [
598
598
  flags: [
599
599
  "save --file save.json: one retry-safe email/series save; existing campaigns and series need expectedUpdatedAt. Template saves keep history; last save wins. See MAIL.md.",
600
600
  "people --q --source --sort newest|oldest|name --availability all|eligible|restricted --page --selected --selected-only.",
601
- "settings set --file settings.json supports all eight fields and null resets; --header-align, --window-start, --window-end, --hourly-cap null|1..1000.",
601
+ "settings set --file settings.json supports all eight fields and null resets; --header-align, --hourly-cap null|1..1000. Legacy --window-start/--window-end remain accepted but do not restrict sending.",
602
602
  "sends list --q --status --type campaign|series|confirmation|template|test|inline --page 1 --limit 20.",
603
603
  "Series status active means On; paused/draft mean Off. Enrollment while Off waits at step 1, without sending. Existing people resume their next unsent step.",
604
- "campaign preview|audience|send|get. --id DRAFT_ID, --file audience.json ({audience:{groupIds|stageIds|personIds|filters}}). send requires --request-key; reuse it after a network error. Templates/series are for automation; campaigns have separate drafts. See PEOPLE.md.",
605
- "Schedule campaigns through save document.scheduledAt (future ISO time with timezone); null means Send now, omission preserves timing. A dated draft never sends until campaign send confirms it. Supply review:{audience,eligible,documentUpdatedAt,scheduledAt} from fresh saved reads/preview. campaign get returns status and scheduledAt; pending plus a future date means Scheduled. Direct send email cannot bypass saved timing. See MAIL.md, Campaign scheduling.",
604
+ "campaign preview|audience|send|get|unschedule|reschedule. --id DRAFT_ID, --file audience.json ({audience:{groupIds|stageIds|personIds|filters}}). send, unschedule and reschedule require --request-key; reuse it after a network error. Templates/series are for automation; campaigns have separate drafts. See PEOPLE.md.",
605
+ "Schedule campaigns through save document.scheduleLocal:{dateTime,timeZone} (local YYYY-MM-DDTHH:mm and IANA zone, converted by the server) or document.scheduledAt (future ISO time with timezone); null means Send now, omission preserves timing. A dated draft never sends until campaign send confirms it. Supply review:{audience,eligible,documentUpdatedAt,scheduledAt} from fresh saved reads/preview. campaign get returns status and scheduledAt; pending plus a future date means Scheduled. Direct send email cannot bypass saved timing. Before queueing, unschedule cancels to draft; reschedule changes only time. Both require documentUpdatedAt from fresh campaign get and a stable --request-key. reschedule accepts scheduleLocal or scheduledAt. See MAIL.md, Campaign scheduling.",
606
606
  "template history <id> pages saved copies with --limit (20 by default, max 100) and --cursor. history-get <id> --history-id reads full content. Both reads follow the plan Rewind window, plus Latest at any age; older copies stay stored. Lists report windowDays, unlimited, canUpgrade and moreBeyondWindow. Use template set with the stable template ID to save edited content as latest; past copies stay unchanged. Read template get before editing. History begins with content retained when history shipped, not lost earlier edits.",
607
607
  "email list is unsent drafts only. Sent one-offs are mail sends list",
608
608
  "send --file is an inline one-off (no saved document)",
@@ -649,9 +649,16 @@ export const COMMANDS = [
649
649
  topics: ["content"],
650
650
  examples: [
651
651
  "frontpage articles list",
652
+ 'frontpage articles create-section --label "Blog" --route blog',
653
+ "frontpage articles archive-section --section blog",
654
+ "frontpage articles restore-section --section blog",
652
655
  "frontpage articles content get --section blog --article my-post",
653
656
  "frontpage articles content set --section blog --article my-post --body '…' --base <sha>",
654
657
  ],
658
+ flags: [
659
+ "Articles needs no setup. Creating a section makes it active. Draft articles stay unpublished; archive-section / restore-section turns a section off or on.",
660
+ "Frontpage manages article routing. Use the Articles commands to create sections and edit content; do not read or edit the managed routing file.",
661
+ ],
655
662
  },
656
663
  {
657
664
  name: "settings",
@@ -810,7 +817,7 @@ export const TOPICS = {
810
817
 
811
818
  Modules & articles (short):
812
819
  - Forms: <form data-fp-form="slug"> with named inputs; no action/onsubmit/honeypot.
813
- - Articles: frontpage articles …; migrate folders via frontpage prompt (don't invent mass delete+write).
820
+ - Articles needs no setup. create-section makes a section active; archive-section / restore-section turns it off / on. Draft articles stay unpublished. Use frontpage articles …; migrate folders via frontpage prompt (don't invent mass delete+write).
814
821
  - Media: frontpage media upload (images/PDF ≤25 MB, video ≤50 MB). frontpage images generate --prompt "…" [--count N] for 1–4 AI variations of one invented picture (AI $ + storage). Use sitePath /__media/uploads/<slug>/… in markup (not raw blob URLs). Optional ?w= on rasters only.
815
822
  - Store: frontpage store for catalog, settings set-fulfillment / set-checkout-fee / set-receipt; frontpage payments owns Stripe and invoices. Write data-fp-store-grid + data-fp-cart (data-fp-requires=store; cart starts hidden). Unless they said they do not want product pages, write one src/pages/products/item.astro with data-fp-store-product. If they said no, skip that file and do not bind href or url. Guide: https://frontpage.host/developers/store
816
823
 
package/llms.txt CHANGED
@@ -63,3 +63,5 @@ Template history (frontpage-host 0.3.11+): read `mail template get ID` before ed
63
63
  Video uploads: the current CLI prepares a browser-compatible MP4 after uploading a local video, including prompt --attach. Use the returned sitePath and actual filename. prepared:false plus warning means the original was retained and playback compatibility is not assured. media list prefers an exact completed prepared copy. Existing video URLs are unchanged. See AGENTS.md for the upload and fallback contract.
64
64
 
65
65
  AI Support Agent knowledge: read the latest note, then save the same ID. Last save wins and prior saved changes remain in history. Knowledge history supports limit/cursor and version reads within the plan Rewind allowance plus the latest version. Archive with customer-inbox post knowledge/ID/archive and {} to stop future use without deleting records. See CUSTOMER-INBOX.md.
66
+
67
+ Articles needs no setup. Use `frontpage articles create-section --label "Blog" --route blog` to create an active section, `archive-section --section blog` / `restore-section --section blog` to turn it off / on, and `create-article` or `content get|set` for content. Draft articles stay unpublished. Frontpage manages article routing; do not read or edit the managed routing file.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frontpage-host",
3
- "version": "0.3.16",
3
+ "version": "0.3.18",
4
4
  "description": "Frontpage CLI — manage your site from the terminal",
5
5
  "type": "module",
6
6
  "bin": {