@topy-ai/maggie 0.7.33 → 0.7.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-zh-TW.md +2 -2
- package/README.md +16 -3
- package/bundled-skills/maggie-blog-bootstrap/SKILL.md +8 -0
- package/bundled-skills/maggie-clone/SKILL.md +7 -1
- package/bundled-templates/astro-blog/README.md +217 -0
- package/bundled-templates/astro-blog/examples/blog.config.ts +30 -0
- package/bundled-templates/astro-blog/examples/content.config.ts +28 -0
- package/bundled-templates/astro-blog/examples/metadata.ts +37 -0
- package/bundled-templates/astro-blog/examples/ops-api.ts +31 -0
- package/bundled-templates/astro-blog/examples/route-manifest.ts +21 -0
- package/bundled-templates/astro-blog/starter/.env.example +36 -0
- package/bundled-templates/astro-blog/starter/README.md +168 -0
- package/bundled-templates/astro-blog/starter/astro.config.mjs +19 -0
- package/bundled-templates/astro-blog/starter/db/schema.sql +508 -0
- package/bundled-templates/astro-blog/starter/package-lock.json +8039 -0
- package/bundled-templates/astro-blog/starter/package.json +41 -0
- package/bundled-templates/astro-blog/starter/scripts/contract-check.mjs +16 -0
- package/bundled-templates/astro-blog/starter/scripts/fixture-seed.mjs +11 -0
- package/bundled-templates/astro-blog/starter/scripts/schema-check.mjs +13 -0
- package/bundled-templates/astro-blog/starter/scripts/seed-db.mjs +20 -0
- package/bundled-templates/astro-blog/starter/src/data/demo.ts +52 -0
- package/bundled-templates/astro-blog/starter/src/layouts/BaseLayout.astro +53 -0
- package/bundled-templates/astro-blog/starter/src/layouts/OpsLayout.astro +73 -0
- package/bundled-templates/astro-blog/starter/src/lib/ai-cmo.ts +14 -0
- package/bundled-templates/astro-blog/starter/src/lib/config.ts +15 -0
- package/bundled-templates/astro-blog/starter/src/lib/db.ts +95 -0
- package/bundled-templates/astro-blog/starter/src/lib/google.ts +28 -0
- package/bundled-templates/astro-blog/starter/src/lib/media.ts +12 -0
- package/bundled-templates/astro-blog/starter/src/lib/migration-validation.ts +11 -0
- package/bundled-templates/astro-blog/starter/src/lib/migration.ts +21 -0
- package/bundled-templates/astro-blog/starter/src/lib/ops-auth.ts +21 -0
- package/bundled-templates/astro-blog/starter/src/lib/providers/email.ts +45 -0
- package/bundled-templates/astro-blog/starter/src/lib/providers/media-storage.ts +37 -0
- package/bundled-templates/astro-blog/starter/src/lib/report-delivery.ts +26 -0
- package/bundled-templates/astro-blog/starter/src/lib/report-pdf.ts +49 -0
- package/bundled-templates/astro-blog/starter/src/lib/repository.ts +72 -0
- package/bundled-templates/astro-blog/starter/src/lib/seo-audit.ts +72 -0
- package/bundled-templates/astro-blog/starter/src/lib/seo-insights.ts +14 -0
- package/bundled-templates/astro-blog/starter/src/lib/seo.ts +33 -0
- package/bundled-templates/astro-blog/starter/src/lib/types.ts +58 -0
- package/bundled-templates/astro-blog/starter/src/lib/wordpress.ts +847 -0
- package/bundled-templates/astro-blog/starter/src/middleware.ts +7 -0
- package/bundled-templates/astro-blog/starter/src/pages/404.astro +11 -0
- package/bundled-templates/astro-blog/starter/src/pages/about.astro +15 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/approval/[token].ts +25 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/consent.ts +8 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/agency.ts +47 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/authors.ts +11 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/bulk.ts +58 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/calendar/publish-due.ts +12 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/config/validate.ts +4 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/content-tracking/report-state/batch.ts +19 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/content-tracking/report-state.ts +15 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/ctas.ts +5 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/entities.ts +23 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/media/optimize.ts +5 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/media/upload.ts +30 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/migrations/[id]/resume.ts +28 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/migrations/[id]/validate.ts +6 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/migrations/[id].ts +7 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/migrations/import.ts +458 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/migrations/media.ts +5 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/operations.ts +189 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/playbooks/[id]/run.ts +55 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/posts/[id]/approve.ts +13 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/posts/[id]/preview.ts +9 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/posts/[id]/publish.ts +13 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/posts/[id].ts +18 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/posts/index.ts +28 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/providers.ts +6 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/pull/history.ts +3 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/pull/latest.ts +3 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/pull/posts.ts +3 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/pull/project-context.ts +4 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/pull/sync-updates.ts +43 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/pull/sync.ts +172 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/pull/updates.ts +3 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/redirects/check.ts +5 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/redirects.ts +32 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/reports/deliver-due.ts +12 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/reports/deliver.ts +6 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/reports/export.ts +17 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/reports.ts +31 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/rewrite/history/[contentId].ts +3 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/rewrite/policy.ts +4 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/rewrite/queue.ts +4 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/seo/audit.ts +7 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/seo/insights.ts +5 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/settings/site.ts +7 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/settings.ts +19 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/sitemap/auto-detect.ts +13 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/sitemap/diff.ts +11 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/sitemap/match.ts +16 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/sitemap/matching-history.ts +4 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/sitemap/runs.ts +4 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/sitemap.ts +11 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/summary.ts +12 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/topics/[id]/faq.ts +12 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/topics.ts +11 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/wordpress/capabilities.ts +5 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/wordpress/migration-plan.ts +21 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/wordpress/migrations/[id]/resume.ts +5 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/wordpress/migrations/[id]/validate.ts +6 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/wordpress/migrations/[id].ts +13 -0
- package/bundled-templates/astro-blog/starter/src/pages/api/ops/wordpress/migrations.ts +147 -0
- package/bundled-templates/astro-blog/starter/src/pages/authors/[slug].astro +12 -0
- package/bundled-templates/astro-blog/starter/src/pages/blog/[slug].astro +25 -0
- package/bundled-templates/astro-blog/starter/src/pages/blog/index.astro +32 -0
- package/bundled-templates/astro-blog/starter/src/pages/blog/page/[page].astro +21 -0
- package/bundled-templates/astro-blog/starter/src/pages/ops/index.astro +20 -0
- package/bundled-templates/astro-blog/starter/src/pages/ops/operations.astro +33 -0
- package/bundled-templates/astro-blog/starter/src/pages/ops/posts/[id]/edit.astro +17 -0
- package/bundled-templates/astro-blog/starter/src/pages/ops/posts/[id]/preview.astro +11 -0
- package/bundled-templates/astro-blog/starter/src/pages/ops/posts/index.astro +15 -0
- package/bundled-templates/astro-blog/starter/src/pages/ops/posts/new.astro +12 -0
- package/bundled-templates/astro-blog/starter/src/pages/ops/reports.astro +12 -0
- package/bundled-templates/astro-blog/starter/src/pages/ops/rewrite.astro +13 -0
- package/bundled-templates/astro-blog/starter/src/pages/ops/settings/integrations.astro +13 -0
- package/bundled-templates/astro-blog/starter/src/pages/ops/settings/site.astro +11 -0
- package/bundled-templates/astro-blog/starter/src/pages/ops/sitemap.astro +15 -0
- package/bundled-templates/astro-blog/starter/src/pages/ops/topics.astro +13 -0
- package/bundled-templates/astro-blog/starter/src/pages/ops/wordpress.astro +34 -0
- package/bundled-templates/astro-blog/starter/src/pages/review/[token].astro +13 -0
- package/bundled-templates/astro-blog/starter/src/pages/robots.txt.ts +4 -0
- package/bundled-templates/astro-blog/starter/src/pages/sitemap.xml.ts +12 -0
- package/bundled-templates/astro-blog/starter/src/pages/topics/[slug]/page/[page].astro +10 -0
- package/bundled-templates/astro-blog/starter/src/pages/topics/[slug].astro +19 -0
- package/bundled-templates/astro-blog/starter/src/pages/topics/index.astro +10 -0
- package/bundled-templates/astro-blog/starter/src/styles/global.css +4 -0
- package/bundled-templates/astro-blog/starter/tsconfig.json +9 -0
- package/bundled-templates/astro-blog/starter/wrangler.jsonc +52 -0
- package/bundled-tools/clis/maggie_clone.py +42 -15
- package/bundled-tools/clis/maggie_dash.py +41 -25
- package/bundled-tools/clis/maggie_design.py +2 -0
- package/bundled-tools/clis/maggie_design_system.py +7 -1
- package/bundled-tools/clis/site_audit.py +25 -2
- package/bundled-tools/runtime/maggie_memory.py +6 -1
- package/package.json +1 -1
package/README-zh-TW.md
CHANGED
|
@@ -8,7 +8,7 @@ Codex、Claude Code 與相容的 coding agents。
|
|
|
8
8
|
## 安裝
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
npx @topy-ai/maggie@0.7.
|
|
11
|
+
npx @topy-ai/maggie@0.7.35 init --agent all
|
|
12
12
|
npx @topy-ai/maggie doctor --project .
|
|
13
13
|
```
|
|
14
14
|
|
|
@@ -25,7 +25,7 @@ maggie doctor --project . --require-bootstrap --strict
|
|
|
25
25
|
deployment、memory、feedback 和 MaggieDash。內容先 draft/review,外部寫入、
|
|
26
26
|
publish 與 production deployment 需要明確確認。
|
|
27
27
|
|
|
28
|
-
目前 release 是 `0.7.33
|
|
28
|
+
目前 release 是 `0.7.35`,完成下一批已驗證 feedback:production fixture isolation、MaggieDash project-id inference、responsive/background asset extraction、穩定 SEO structure hash、decorative alt、明確 site URL/build validation、真正 404、Tailwind v4 starter、portable CLI scripts,以及不含 local dependencies/cache 的 Astro starter bundle。延後功能記錄在 issue #38,不會直接成為 active memory。0.7.33 記錄並審查一筆更正回饋;確認 0.7.32 已正確處理 batch index,沒有修改已驗證的 shared behavior。0.7.32 加入 feedback 一基索引支援、MaggieDash panel 的 source/freshness/error evidence、Consent Mode 與實際 write/no-op reconciliation、SEO baseline recapture、sitemap origin rebasing、content-diff scope、migration ledger reconciliation、deployment credential preflight、release provenance/runtime preflight、icon release gate、opt-in blog auto-publish gate,以及 least-privilege VPS deployer。也修復 top-level `maggie feedback` dispatcher parity。0.7.31 加入 update 差異摘要、atomic installer copy、subset install manifest merge,以及 inventory drift 時 doctor non-zero。0.7.30 補上 feedback tracking issue closeout gate 與 batch 14/15 audit ledger。0.7.29 修正 npm package landing page 使用英文 README;0.7.28 加入 versioned Gemini model policy、明確 fallback 與 provenance、bundled-first CLI
|
|
29
29
|
dispatch、`maggie --version`、feedback batch review 聚合與重複偵測、marketplace enrichment evidence、booking
|
|
30
30
|
worker/resolver evidence,以及 read-only migration preflight。它也包含 host-owned mobile app surface contract、signed-in
|
|
31
31
|
camera-state QA、直接 Astro route resolution、correlated feedback batch,以及
|
package/README.md
CHANGED
|
@@ -60,7 +60,16 @@ Maggie keeps the existing project foundation and asks for decisions before
|
|
|
60
60
|
shared routes, analytics, or publishing boundaries change. The current
|
|
61
61
|
package ships 19 installable skills and a local-first MaggieDash foundation.
|
|
62
62
|
|
|
63
|
-
The current release is `0.7.
|
|
63
|
+
The current release is `0.7.35`. It closes the next validated feedback batch:
|
|
64
|
+
production demo fixtures are development-only, Dash infers the persisted
|
|
65
|
+
project id, clone asset extraction includes responsive/background assets, SEO
|
|
66
|
+
structure hashes ignore content-hashed asset names, decorative empty alt text
|
|
67
|
+
is accepted, and missing starter routes return a real 404. It also adds a
|
|
68
|
+
Tailwind v4 starter entry point, explicit `PUBLIC_SITE_URL` validation, a
|
|
69
|
+
portable installed-CLI script path, and a bundled Astro starter without local
|
|
70
|
+
dependencies or build caches. Deferred feature requests are tracked in
|
|
71
|
+
[issue #38](https://github.com/TOPY-AI-LTD/ai-cmo-skills/issues/38), not active
|
|
72
|
+
memory. The 0.7.33 release records the reviewed correction for the
|
|
64
73
|
batch-index feedback workflow while keeping the verified 0.7.32 behavior
|
|
65
74
|
unchanged. The 0.7.32 release added explicit one-based feedback batch index
|
|
66
75
|
support, source/freshness/error evidence for MaggieDash measurement
|
|
@@ -500,8 +509,8 @@ artifact schemas.
|
|
|
500
509
|
Recommended upgrade sequence for the current release:
|
|
501
510
|
|
|
502
511
|
```bash
|
|
503
|
-
npx @topy-ai/maggie@0.7.
|
|
504
|
-
npx @topy-ai/maggie@0.7.
|
|
512
|
+
npx @topy-ai/maggie@0.7.35 update --project . --force
|
|
513
|
+
npx @topy-ai/maggie@0.7.35 cleanup --project .
|
|
505
514
|
```
|
|
506
515
|
|
|
507
516
|
Maintainers should pass npm credentials through the repository helper, never
|
|
@@ -774,6 +783,10 @@ report. It fails closed when source evidence is missing unless
|
|
|
774
783
|
The marketplace catalog is lightweight and templates are fetched on demand.
|
|
775
784
|
These desktop previews are hosted by the public NoBlox template registry so
|
|
776
785
|
the npm package does not download every template asset during installation.
|
|
786
|
+
The package also includes the small, dependency-free Astro blog starter under
|
|
787
|
+
`bundled-templates/astro-blog/starter`; run `npm install` in the copied starter
|
|
788
|
+
and configure `PUBLIC_SITE_URL` before building. Its Tailwind v4 entry point is
|
|
789
|
+
opt-in at the host project level, and production never falls back to demo posts.
|
|
777
790
|
|
|
778
791
|
<table>
|
|
779
792
|
<tr>
|
|
@@ -68,6 +68,14 @@ response fields. It does not accept a static source scan as runtime evidence.
|
|
|
68
68
|
|
|
69
69
|
- Preserve detected framework, language, router, UI system, icon set, fonts,
|
|
70
70
|
database, and deployment target unless the user confirms a change.
|
|
71
|
+
- The bundled Astro starter is SQLite-first. A PostgreSQL or MySQL selection is
|
|
72
|
+
only a host adapter decision until the project provides and verifies its
|
|
73
|
+
repository/migration adapter; never report the starter's SQLite store as a
|
|
74
|
+
working PostgreSQL adapter.
|
|
75
|
+
- An empty directory still needs an approved host framework scaffold. Do not
|
|
76
|
+
pretend that installing Maggie skills alone creates an Astro/Next.js app;
|
|
77
|
+
use the bundled starter or the host framework's official scaffold, then run
|
|
78
|
+
the interview against that project.
|
|
71
79
|
- Store no credentials in source or `.maggie` reports. API keys stay server
|
|
72
80
|
side and are never inferred from a domain.
|
|
73
81
|
- Traditional email/password auth uses the MaggieDash auth contract; passkeys,
|
|
@@ -152,7 +152,8 @@ interaction states, and component specs. Capture desktop (1440px), tablet
|
|
|
152
152
|
- exact visible text, links, labels, alt text, forms, and public content;
|
|
153
153
|
- fonts, weights, colors, spacing, breakpoints, radii, shadows, gradients,
|
|
154
154
|
borders, and responsive layout changes from computed styles;
|
|
155
|
-
- every image,
|
|
155
|
+
- every image, responsive `srcset` candidate, CSS/inline background, video,
|
|
156
|
+
SVG, favicon, font, and layered asset;
|
|
156
157
|
- interaction models: static, click-driven, hover-driven, scroll-driven,
|
|
157
158
|
intersection-observer-driven, keyboard, or time-driven;
|
|
158
159
|
- loading, empty, error, open, active, hover, and scrolled states where
|
|
@@ -164,6 +165,11 @@ Do not click first when a section may be scroll-driven. Scroll slowly, then
|
|
|
164
165
|
test clicks and hovers. For tabs or pills, capture every state. For headers or
|
|
165
166
|
sticky elements, record before/after computed values and the trigger.
|
|
166
167
|
|
|
168
|
+
Headless browser tabs can throttle timers in the background. Wait for
|
|
169
|
+
Lenis/ScrollTrigger-style smooth scrolling and animations to settle before
|
|
170
|
+
capturing; record the settle method, such as a stable `animation.currentTime`,
|
|
171
|
+
in the evidence notes.
|
|
172
|
+
|
|
167
173
|
Persist the evidence before building:
|
|
168
174
|
|
|
169
175
|
```text
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# Astro Blog Template Contract
|
|
2
|
+
|
|
3
|
+
This is a Maggie implementation contract for an existing Astro project. It is
|
|
4
|
+
not a second starter app: inspect the host project first, preserve its layout,
|
|
5
|
+
styling, deployment adapter, and content source, then add only the missing blog
|
|
6
|
+
surfaces.
|
|
7
|
+
|
|
8
|
+
Astro is the preferred template for content-heavy sites. Use Content
|
|
9
|
+
Collections for local or build-time content, and use a live loader or server
|
|
10
|
+
endpoint only when the product requires request-time freshness. Astro defaults
|
|
11
|
+
to static output and hydrates interactive components as islands, so keep the
|
|
12
|
+
blog reading path mostly server-rendered HTML.
|
|
13
|
+
|
|
14
|
+
See the shared [blog implementation contract](../../bundled-references/blog-implementation.md)
|
|
15
|
+
and [canonical data contract](../../bundled-references/blog-data-contract.md) for the
|
|
16
|
+
stable backend model. Use the [technical SEO contract](../../bundled-references/seo-technical-contract.md)
|
|
17
|
+
for behaviour and acceptance criteria. For AI CMO-specific work, read the
|
|
18
|
+
[Maggie API Pull guide](../../bundled-tools/integrations/maggie-api-pull.md) and
|
|
19
|
+
[Maggie Project Context guide](../../bundled-tools/integrations/maggie-project-context.md).
|
|
20
|
+
The complete public-page and private-operations surface is defined in the
|
|
21
|
+
[AI-native blog application contract](../../bundled-references/ai-native-blog-contract.md).
|
|
22
|
+
The daily operations data model and API are defined in the
|
|
23
|
+
[blog operations contract](../../bundled-references/blog-operations-contract.md).
|
|
24
|
+
For deployment, use the [Maggie Deployment skill](../../bundled-skills/maggie-deployment/SKILL.md);
|
|
25
|
+
the starter includes a Cloudflare Workers target with D1, R2, KV, and Wrangler
|
|
26
|
+
configuration. Keep Node/SQLite for local development only until the D1
|
|
27
|
+
repository boundary is selected and verified.
|
|
28
|
+
|
|
29
|
+
## Expected mapping
|
|
30
|
+
|
|
31
|
+
Adapt names to the host project, but preserve these responsibilities:
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
src/content.config.ts typed post collection and schema
|
|
35
|
+
src/content/posts/ local Markdown/MDX posts, if used
|
|
36
|
+
src/pages/posts/index.astro crawlable post list
|
|
37
|
+
src/pages/posts/[...slug].astro post detail and 404 handling
|
|
38
|
+
src/pages/sitemap-index.xml.ts sitemap index when multiple sitemaps exist
|
|
39
|
+
src/pages/sitemap-0.xml.ts published post URLs and lastmod
|
|
40
|
+
src/pages/robots.txt.ts crawler rules and sitemap reference
|
|
41
|
+
src/layouts/PostLayout.astro metadata, JSON-LD, and article shell
|
|
42
|
+
src/lib/posts.ts source adapter and read model
|
|
43
|
+
src/components/analytics/GA4.astro consent-aware analytics hook
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The [`examples/`](examples/) directory contains a Content Collections schema,
|
|
47
|
+
typed config, route manifest, metadata builder, and Ops transition guard. Treat
|
|
48
|
+
them as typed starting points, not permission to change the canonical field
|
|
49
|
+
names.
|
|
50
|
+
|
|
51
|
+
The actual sitemap route may be provided by an Astro integration. Do not
|
|
52
|
+
create duplicate sitemap routes; verify the generated response instead.
|
|
53
|
+
|
|
54
|
+
The default list configuration is `postsPerPage: 9` and `gridColumns: 3`,
|
|
55
|
+
rendering a 3×3 grid. The starter exposes these as
|
|
56
|
+
`PUBLIC_POSTS_PER_PAGE` and `PUBLIC_GRID_COLUMNS`; operators can change them
|
|
57
|
+
later through the typed site-settings boundary.
|
|
58
|
+
|
|
59
|
+
Keep these stable: the post model, publication state, source identity, URL
|
|
60
|
+
rules, metadata fields, JSON-LD semantics, sitemap eligibility, and sync/error
|
|
61
|
+
state. Let the agent choose the visual layout, component composition, colors,
|
|
62
|
+
spacing, and interaction details after it has detected the existing design
|
|
63
|
+
system.
|
|
64
|
+
|
|
65
|
+
The Maggie Ops starter uses a CMS-style operator journey: persistent workspace
|
|
66
|
+
navigation, a compact account bar, dashboard-first summary metrics, quick next
|
|
67
|
+
actions, visible health status, and responsive navigation on small screens. It
|
|
68
|
+
keeps Maggie's content, API Pull, sitemap, rewrite, SEO/GEO, and agency flows
|
|
69
|
+
inside this shell without depending on another CMS.
|
|
70
|
+
|
|
71
|
+
## Required frontend surface
|
|
72
|
+
|
|
73
|
+
Implement the public information architecture from the shared application
|
|
74
|
+
contract:
|
|
75
|
+
|
|
76
|
+
```text
|
|
77
|
+
/blog title, description, hot topics, grid, FAQs, CTA, pagination
|
|
78
|
+
/blog/[slug] EEAT authorship, dates, content, related posts, FAQs, CTA
|
|
79
|
+
/topics topic index
|
|
80
|
+
/topics/[topic-slug] topic title, description, post grid, FAQs, CTA, pagination
|
|
81
|
+
/authors/[author-slug] authorship and published posts, when enabled
|
|
82
|
+
/sitemap.xml published canonical URLs only
|
|
83
|
+
/robots.txt crawler policy and sitemap reference
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The agent may design the header, cards, navigation, typography, color system,
|
|
87
|
+
responsive layout, and progressive enhancement. It must use the shared
|
|
88
|
+
repository functions for publication filtering and the shared metadata builder
|
|
89
|
+
for SEO output.
|
|
90
|
+
|
|
91
|
+
## Maggie Ops surface
|
|
92
|
+
|
|
93
|
+
Bootstrap must ship the complete private dashboard described in the shared
|
|
94
|
+
[Ops dashboard contract](../../bundled-references/ops-dashboard-contract.md). The
|
|
95
|
+
starter's `src/pages/ops/` and `src/pages/api/ops/` are the reference
|
|
96
|
+
implementation; preserve their authentication and repository boundaries when
|
|
97
|
+
customizing the UI.
|
|
98
|
+
|
|
99
|
+
Implement `/ops` as a private authenticated application, never as a public
|
|
100
|
+
content route. The minimum screens are:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
/ops health, sync state, queue, and recent reports
|
|
104
|
+
/ops/posts inventory, filters, status, and bulk-safe actions
|
|
105
|
+
/ops/posts/[id]/edit validated post edit and metadata preview
|
|
106
|
+
/ops/posts/[id]/preview noindex preview with draft/review state
|
|
107
|
+
/ops/topics topic, FAQ, and published-post management
|
|
108
|
+
/ops/sitemap sitemap sources, matching history, eligibility
|
|
109
|
+
/ops/reports technical SEO, content quality, visibility, analytics
|
|
110
|
+
/ops/settings/site origin, locale, timezone, defaults, CTA
|
|
111
|
+
/ops/settings/integrations AI CMO, GSC, and GA4 configured/verified status
|
|
112
|
+
/ops/wordpress WordPress preview, apply, resume, and import history
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
All writes require authentication, authorization, an audit event, and a
|
|
116
|
+
visible confirmation. Publishing, rewrite queueing, sitemap matching, and
|
|
117
|
+
integration changes must show a dry-run or impact preview first.
|
|
118
|
+
|
|
119
|
+
WordPress migration is an explicit server-side workflow. It reads the
|
|
120
|
+
WordPress REST API posts, categories, tags, and media collections; preserves
|
|
121
|
+
source IDs for idempotent reruns; maps categories to draft topics; stores tags
|
|
122
|
+
as migration terms; registers featured/all media; and records old-path
|
|
123
|
+
redirects. Imported posts are drafts unless the operator explicitly selects
|
|
124
|
+
the preserve-published option. See the [Astro starter migration screen](starter/README.md)
|
|
125
|
+
for environment and operation details.
|
|
126
|
+
|
|
127
|
+
## Content model
|
|
128
|
+
|
|
129
|
+
Define a single normalized post shape at the adapter boundary. The full
|
|
130
|
+
database, sync-state, delivery-state, redirect, and metadata contracts live in
|
|
131
|
+
the shared references:
|
|
132
|
+
|
|
133
|
+
- [blog data contract](../../bundled-references/blog-data-contract.md)
|
|
134
|
+
- [technical SEO contract](../../bundled-references/seo-technical-contract.md)
|
|
135
|
+
|
|
136
|
+
The Astro-specific schema starts here:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
type Post = {
|
|
140
|
+
id: string
|
|
141
|
+
slug: string
|
|
142
|
+
title: string
|
|
143
|
+
excerpt?: string
|
|
144
|
+
content: string
|
|
145
|
+
publishedAt: string
|
|
146
|
+
updatedAt?: string
|
|
147
|
+
canonicalUrl?: string
|
|
148
|
+
coverImage?: string
|
|
149
|
+
author?: { name: string; url?: string }
|
|
150
|
+
status: "draft" | "review" | "approved" | "scheduled" | "published" | "archived"
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Use the [example Content Collections schema](examples/content.config.ts) for
|
|
155
|
+
local or build-time entries. If the
|
|
156
|
+
remote API has optional or inconsistent fields, normalize and validate them in
|
|
157
|
+
`src/lib/posts.ts`; do not spread provider-specific fields through templates.
|
|
158
|
+
The `slug` is the public identity and must not silently change after
|
|
159
|
+
publication. Create a redirect when a published slug must change.
|
|
160
|
+
|
|
161
|
+
## Rendering and data freshness
|
|
162
|
+
|
|
163
|
+
- Prefer prerendered post pages for stable content and CDN delivery.
|
|
164
|
+
- Use `getStaticPaths()` for build-time collections and ensure unpublished
|
|
165
|
+
entries never produce a public route.
|
|
166
|
+
- For API Pull content that changes without a deploy, choose an Astro server
|
|
167
|
+
adapter and fetch through a server-only module, or trigger a controlled
|
|
168
|
+
rebuild after a successful sync.
|
|
169
|
+
- Keep API keys in server-only environment variables. Never expose them through
|
|
170
|
+
`PUBLIC_*`, client islands, serialized page props, or browser requests.
|
|
171
|
+
- Cache remote reads and make sync jobs idempotent. A build failure must not
|
|
172
|
+
replace the last known-good public content with an empty collection.
|
|
173
|
+
|
|
174
|
+
## API Pull and rewrite boundary
|
|
175
|
+
|
|
176
|
+
The Astro site is a host adapter, not the rewrite source of truth:
|
|
177
|
+
|
|
178
|
+
1. Fetch published or explicitly requested posts from Maggie API Pull.
|
|
179
|
+
2. Map remote identifiers, title, slug, canonical URL, timestamps, and body
|
|
180
|
+
into the local `Post` model.
|
|
181
|
+
3. Store a stable remote ID and sync cursor so retries do not duplicate posts.
|
|
182
|
+
4. Treat sitemap matching as an explicit queue input; match by canonical URL or
|
|
183
|
+
normalized slug, then title-derived slug only when the existing slug is
|
|
184
|
+
empty and the result is unique.
|
|
185
|
+
5. Pull rewrite results into a draft or review state. Do not publish from a
|
|
186
|
+
build hook, cron job, or content loader without an explicit approval gate.
|
|
187
|
+
|
|
188
|
+
The sitemap must contain only posts that are public on the host site, with
|
|
189
|
+
absolute canonical URLs and `lastmod` when known.
|
|
190
|
+
|
|
191
|
+
## SEO, GEO, and analytics requirements
|
|
192
|
+
|
|
193
|
+
Each post page should server-render:
|
|
194
|
+
|
|
195
|
+
- one `h1`, title, author, published date, and primary content;
|
|
196
|
+
- canonical URL, description, Open Graph, and Twitter metadata;
|
|
197
|
+
- Article JSON-LD that agrees with visible content;
|
|
198
|
+
- useful internal links and image dimensions/alt text;
|
|
199
|
+
- no indexable duplicate query URLs.
|
|
200
|
+
|
|
201
|
+
Add GA4 only when configured and permitted by the site's consent policy. Add
|
|
202
|
+
GSC verification through an environment variable, HTML file, or DNS workflow;
|
|
203
|
+
do not hardcode ownership tokens in the template.
|
|
204
|
+
|
|
205
|
+
## Acceptance checklist
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
npm run build
|
|
209
|
+
npm run preview
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Verify the rendered list, a post, an unpublished/missing post, `robots.txt`,
|
|
213
|
+
the sitemap, canonical metadata, JSON-LD, analytics-disabled mode, and an API
|
|
214
|
+
Pull failure with a preserved last-known-good build.
|
|
215
|
+
|
|
216
|
+
The [local site audit](../../bundled-tools/clis/site_audit.py) can check the deployed
|
|
217
|
+
host, but it does not replace route-level tests.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const blogConfig = {
|
|
2
|
+
site: {
|
|
3
|
+
name: "Example Site",
|
|
4
|
+
baseUrl: "https://example.com",
|
|
5
|
+
locale: "en-GB",
|
|
6
|
+
timezone: "Europe/London",
|
|
7
|
+
blogPath: "/blog",
|
|
8
|
+
postsPerPage: 12,
|
|
9
|
+
topicMinimumPosts: 3,
|
|
10
|
+
},
|
|
11
|
+
defaults: {
|
|
12
|
+
language: "en",
|
|
13
|
+
robotsPolicy: "index,follow",
|
|
14
|
+
},
|
|
15
|
+
integrations: {
|
|
16
|
+
aiCmo: {
|
|
17
|
+
enabled: false,
|
|
18
|
+
baseUrl: "https://api.cmo.so",
|
|
19
|
+
apiKeyEnv: "AI_CMO_API_KEY",
|
|
20
|
+
syncMode: "manual",
|
|
21
|
+
},
|
|
22
|
+
gsc: { enabled: false, verificationMode: "dns" },
|
|
23
|
+
ga4: { enabled: false, consentRequired: true },
|
|
24
|
+
},
|
|
25
|
+
publishing: {
|
|
26
|
+
requireApproval: true,
|
|
27
|
+
allowScheduledPublish: false,
|
|
28
|
+
allowAutoRewritePublish: false,
|
|
29
|
+
},
|
|
30
|
+
} as const;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { defineCollection, z } from "astro:content";
|
|
2
|
+
import { glob } from "astro/loaders";
|
|
3
|
+
|
|
4
|
+
const posts = defineCollection({
|
|
5
|
+
loader: glob({ pattern: "**/*.{md,mdx}", base: "./src/content/posts" }),
|
|
6
|
+
schema: z.object({
|
|
7
|
+
id: z.string(),
|
|
8
|
+
source: z.enum(["local", "api-pull", "cms", "manual"]),
|
|
9
|
+
sourceId: z.string().optional(),
|
|
10
|
+
title: z.string().min(1),
|
|
11
|
+
excerpt: z.string().default(""),
|
|
12
|
+
canonicalUrl: z.string().url(),
|
|
13
|
+
coverImageUrl: z.string().url().optional(),
|
|
14
|
+
coverImageAlt: z.string().optional(),
|
|
15
|
+
authorName: z.string().optional(),
|
|
16
|
+
authorUrl: z.string().url().optional(),
|
|
17
|
+
language: z.string().default("en"),
|
|
18
|
+
tags: z.array(z.string()).default([]),
|
|
19
|
+
status: z.enum(["draft", "review", "approved", "scheduled", "published", "archived"]),
|
|
20
|
+
publishedAt: z.coerce.date().optional(),
|
|
21
|
+
updatedAt: z.coerce.date().optional(),
|
|
22
|
+
}).refine(
|
|
23
|
+
(post) => post.status !== "published" || post.publishedAt !== undefined,
|
|
24
|
+
"published posts require publishedAt",
|
|
25
|
+
),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const collections = { posts };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
type PostMeta = {
|
|
2
|
+
title: string;
|
|
3
|
+
excerpt: string;
|
|
4
|
+
canonicalUrl: string;
|
|
5
|
+
imageUrl?: string;
|
|
6
|
+
authorName?: string;
|
|
7
|
+
publishedAt: string;
|
|
8
|
+
updatedAt?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function buildPostMeta(post: PostMeta, siteName: string) {
|
|
12
|
+
const image = post.imageUrl ? [post.imageUrl] : undefined;
|
|
13
|
+
return {
|
|
14
|
+
title: `${post.title} | ${siteName}`,
|
|
15
|
+
description: post.excerpt,
|
|
16
|
+
canonical: post.canonicalUrl,
|
|
17
|
+
openGraph: {
|
|
18
|
+
type: "article",
|
|
19
|
+
title: post.title,
|
|
20
|
+
description: post.excerpt,
|
|
21
|
+
url: post.canonicalUrl,
|
|
22
|
+
images: image,
|
|
23
|
+
},
|
|
24
|
+
twitter: { card: "summary_large_image", title: post.title, description: post.excerpt, images: image },
|
|
25
|
+
jsonLd: {
|
|
26
|
+
"@context": "https://schema.org",
|
|
27
|
+
"@type": "Article",
|
|
28
|
+
headline: post.title,
|
|
29
|
+
description: post.excerpt,
|
|
30
|
+
url: post.canonicalUrl,
|
|
31
|
+
datePublished: post.publishedAt,
|
|
32
|
+
...(post.updatedAt ? { dateModified: post.updatedAt } : {}),
|
|
33
|
+
...(post.authorName ? { author: { "@type": "Person", name: post.authorName } } : {}),
|
|
34
|
+
...(image ? { image } : {}),
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
type PostState = "draft" | "review" | "approved" | "published" | "archived";
|
|
2
|
+
|
|
3
|
+
const transitions: Record<PostState, PostState[]> = {
|
|
4
|
+
draft: ["review", "archived"],
|
|
5
|
+
review: ["draft", "approved", "archived"],
|
|
6
|
+
approved: ["review", "published", "archived"],
|
|
7
|
+
published: ["archived"],
|
|
8
|
+
archived: ["draft"],
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function assertPostTransition(from: PostState, to: PostState) {
|
|
12
|
+
if (!transitions[from].includes(to)) {
|
|
13
|
+
throw new Error(`invalid post transition: ${from} -> ${to}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function assertPublishable(post: {
|
|
18
|
+
status: PostState;
|
|
19
|
+
title: string;
|
|
20
|
+
slug: string;
|
|
21
|
+
canonicalUrl: string;
|
|
22
|
+
publishedAt?: string;
|
|
23
|
+
authorId?: string;
|
|
24
|
+
topicIds: string[];
|
|
25
|
+
}) {
|
|
26
|
+
if (post.status !== "approved") throw new Error("post must be approved before publishing");
|
|
27
|
+
if (!post.title || !post.slug || !post.canonicalUrl) throw new Error("post SEO identity is incomplete");
|
|
28
|
+
if (!post.authorId) throw new Error("published post requires an author");
|
|
29
|
+
if (post.topicIds.length === 0) throw new Error("published post requires a topic");
|
|
30
|
+
if (post.publishedAt && Number.isNaN(Date.parse(post.publishedAt))) throw new Error("publishedAt must be ISO-8601");
|
|
31
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export const publicRoutes = {
|
|
2
|
+
blogIndex: "/blog",
|
|
3
|
+
post: "/blog/[...slug]",
|
|
4
|
+
topics: "/topics",
|
|
5
|
+
topic: "/topics/[topic-slug]",
|
|
6
|
+
author: "/authors/[author-slug]",
|
|
7
|
+
sitemap: "/sitemap.xml",
|
|
8
|
+
robots: "/robots.txt",
|
|
9
|
+
} as const;
|
|
10
|
+
|
|
11
|
+
export const opsRoutes = {
|
|
12
|
+
dashboard: "/ops",
|
|
13
|
+
posts: "/ops/posts",
|
|
14
|
+
postEditor: "/ops/posts/[id]/edit",
|
|
15
|
+
preview: "/ops/posts/[id]/preview",
|
|
16
|
+
topics: "/ops/topics",
|
|
17
|
+
sitemap: "/ops/sitemap",
|
|
18
|
+
reports: "/ops/reports",
|
|
19
|
+
siteSettings: "/ops/settings/site",
|
|
20
|
+
integrations: "/ops/settings/integrations",
|
|
21
|
+
} as const;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
PUBLIC_SITE_URL=https://example.com
|
|
2
|
+
PUBLIC_SITE_NAME=Example Site
|
|
3
|
+
PUBLIC_SITE_LOCALE=en-GB
|
|
4
|
+
PUBLIC_SITE_TIMEZONE=Europe/London
|
|
5
|
+
PUBLIC_POSTS_PER_PAGE=9
|
|
6
|
+
PUBLIC_GRID_COLUMNS=3
|
|
7
|
+
AI_CMO_API_KEY=
|
|
8
|
+
AI_CMO_BASE_URL=https://api.cmo.so
|
|
9
|
+
GA4_MEASUREMENT_ID=
|
|
10
|
+
GSC_VERIFICATION_TOKEN=
|
|
11
|
+
GSC_SITE_URL=https://example.com
|
|
12
|
+
GSC_ACCESS_TOKEN=
|
|
13
|
+
GA4_PROPERTY_ID=
|
|
14
|
+
GA4_ACCESS_TOKEN=
|
|
15
|
+
WORDPRESS_API_TOKEN=
|
|
16
|
+
WORDPRESS_USERNAME=
|
|
17
|
+
WORDPRESS_APP_PASSWORD=
|
|
18
|
+
OPS_AUTH_PROVIDER=
|
|
19
|
+
OPS_LOCAL_TOKEN=
|
|
20
|
+
OPS_LOCAL_ROLE=agency-owner
|
|
21
|
+
MAGGIE_DEPLOY_PROVIDER=node
|
|
22
|
+
CLOUDFLARE_ENV=staging
|
|
23
|
+
BLOG_DATA_SOURCE=sqlite
|
|
24
|
+
BLOG_DB_PATH=.data/maggie.sqlite
|
|
25
|
+
REPORT_EMAIL_WEBHOOK_URL=
|
|
26
|
+
EMAIL_PROVIDER=resend
|
|
27
|
+
RESEND_API_KEY=
|
|
28
|
+
EMAIL_FROM=
|
|
29
|
+
EMAIL_REPLY_TO=
|
|
30
|
+
EMAIL_WEBHOOK_URL=
|
|
31
|
+
MEDIA_STORAGE_PROVIDER=cloudinary
|
|
32
|
+
CLOUDINARY_CLOUD_NAME=
|
|
33
|
+
CLOUDINARY_API_KEY=
|
|
34
|
+
CLOUDINARY_API_SECRET=
|
|
35
|
+
CLOUDINARY_UPLOAD_FOLDER=maggie
|
|
36
|
+
MEDIA_OUTPUT_DIR=public/media/optimized
|