@agent-cms/agentcms 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +143 -0
- package/README.md +1119 -2
- package/changelog.json +20 -0
- package/dist/admin/admin-files.json +48 -0
- package/dist/admin/assets/CodeEditor-DcFzGUt8.js +24 -0
- package/dist/admin/assets/flexweg-logo-CdtuqAFA.png +0 -0
- package/dist/admin/assets/index-CLZ1gQZl.js +5460 -0
- package/dist/admin/assets/index-DMcGogR2.css +1 -0
- package/dist/admin/assets/sql-wasm-C1U8OeUW.wasm +0 -0
- package/dist/admin/assets/sql-wasm-CYl3LXH_.js +2 -0
- package/dist/admin/assets/sql-wasm-V5jTDcrT.js +1 -0
- package/dist/admin/config.js +11 -0
- package/dist/admin/external.default.json +72 -0
- package/dist/admin/index.html +116 -0
- package/dist/admin/plugins/core-seo/bundle.js +55 -0
- package/dist/admin/plugins/core-seo/manifest.json +7 -0
- package/dist/admin/plugins/flexweg-archives/bundle.js +1414 -0
- package/dist/admin/plugins/flexweg-archives/manifest.json +7 -0
- package/dist/admin/plugins/flexweg-multilang/bundle.js +1187 -0
- package/dist/admin/plugins/flexweg-multilang/manifest.json +7 -0
- package/dist/admin/plugins/flexweg-rss/bundle.js +1354 -0
- package/dist/admin/plugins/flexweg-rss/manifest.json +7 -0
- package/dist/admin/plugins/flexweg-search/bundle.js +1243 -0
- package/dist/admin/plugins/flexweg-search/manifest.json +7 -0
- package/dist/admin/plugins/flexweg-sitemaps/bundle.js +1293 -0
- package/dist/admin/plugins/flexweg-sitemaps/manifest.json +7 -0
- package/dist/admin/runtime/cms-runtime.js +164 -0
- package/dist/admin/runtime/react-dom-client.js +13 -0
- package/dist/admin/runtime/react-dom.js +16 -0
- package/dist/admin/runtime/react-i18next.js +21 -0
- package/dist/admin/runtime/react-jsx-runtime.js +17 -0
- package/dist/admin/runtime/react.js +55 -0
- package/dist/admin/themes/corporate/bundle.js +14465 -0
- package/dist/admin/themes/corporate/manifest.json +7 -0
- package/dist/admin/themes/corporate/theme.css +2 -0
- package/dist/admin/themes/magazine/bundle.js +10229 -0
- package/dist/admin/themes/magazine/manifest.json +7 -0
- package/dist/admin/themes/magazine/theme.css +2 -0
- package/dist/admin/themes/marketplace-core/bundle.js +11213 -0
- package/dist/admin/themes/marketplace-core/manifest.json +7 -0
- package/dist/admin/themes/marketplace-core/theme.css +1613 -0
- package/dist/admin/themes/portfolio/bundle.js +9195 -0
- package/dist/admin/themes/portfolio/manifest.json +7 -0
- package/dist/admin/themes/portfolio/theme.css +2 -0
- package/dist/admin/themes/storefront/bundle.js +13172 -0
- package/dist/admin/themes/storefront/manifest.json +7 -0
- package/dist/admin/themes/storefront/theme.css +2 -0
- package/dist/agent/agentcms.mjs +1711 -0
- package/dist/agent/chunks/hosting-D_uj-Mt1.mjs +117 -0
- package/dist/agent/chunks/index-CrvEoyi0.mjs +3608 -0
- package/dist/agent/chunks/install-DkCCcKAO.mjs +577 -0
- package/dist/agent/chunks/plan-EYKegfhp.mjs +245 -0
- package/dist/agent/chunks/registry-lkfb_E9O.mjs +53517 -0
- package/dist/agent/chunks/siteAdd-BqcYt8nu.mjs +118 -0
- package/dist/agent/chunks/sql-wasm-GjJDiefO.mjs +10 -0
- package/dist/agent/chunks/sqljs-DjSCStJ0.mjs +20 -0
- package/dist/agent/vendor/sql-wasm.cjs +188 -0
- package/dist/theme-assets/corporate-menu.js +266 -0
- package/dist/theme-assets/corporate-posts.js +571 -0
- package/dist/theme-assets/corporate.css +2 -0
- package/dist/theme-assets/default-menu.js +266 -0
- package/dist/theme-assets/default-posts.js +378 -0
- package/dist/theme-assets/default.css +1 -0
- package/dist/theme-assets/magazine-menu.js +227 -0
- package/dist/theme-assets/magazine-posts.js +361 -0
- package/dist/theme-assets/magazine.css +2 -0
- package/dist/theme-assets/portfolio-filters.js +104 -0
- package/dist/theme-assets/portfolio-menu.js +240 -0
- package/dist/theme-assets/portfolio-posts.js +358 -0
- package/dist/theme-assets/portfolio.css +2 -0
- package/dist/theme-assets/storefront-catalog.js +504 -0
- package/dist/theme-assets/storefront-menu.js +239 -0
- package/dist/theme-assets/storefront-posts.js +404 -0
- package/dist/theme-assets/storefront.css +2 -0
- package/dist/version.json +9 -0
- package/package.json +101 -4
- package/plugin/.claude-plugin/plugin.json +16 -0
- package/plugin/skills/agentcms-install/SKILL.md +110 -0
- package/plugin/skills/agentcms-install/references/cloudflare.md +15 -0
- package/plugin/skills/agentcms-install/references/flexweg.md +11 -0
- package/plugin/skills/agentcms-install/references/github.md +67 -0
- package/plugin/skills/agentcms-install/references/gitlab.md +15 -0
- package/plugin/skills/agentcms-install/references/s3.md +81 -0
- package/plugin/skills/agentcms-manage/SKILL.md +92 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
@import url("https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,500;0,600;0,700;1,400&family=Inter:wght@400;500;600;700&display=swap");@import url("https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0&display=swap");*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }
|
|
2
|
+
/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:var(--font-sans),Inter,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}:root{--color-primary:71 87 59;--color-on-primary:255 255 255;--color-primary-container:95 111 82;--color-on-primary-container:223 241 205;--color-primary-fixed:214 232 197;--color-primary-fixed-dim:187 204 170;--color-on-primary-fixed:18 31 9;--color-on-primary-fixed-variant:60 75 49;--color-secondary:145 74 54;--color-on-secondary:255 255 255;--color-secondary-container:253 162 136;--color-on-secondary-container:119 54 35;--color-secondary-fixed:255 219 209;--color-secondary-fixed-dim:255 181 160;--color-on-secondary-fixed:59 9 0;--color-on-secondary-fixed-variant:116 52 33;--color-tertiary:81 82 79;--color-on-tertiary:255 255 255;--color-tertiary-container:105 106 103;--color-on-tertiary-container:236 235 231;--color-tertiary-fixed:227 226 223;--color-tertiary-fixed-dim:199 199 195;--color-background:252 249 248;--color-surface:252 249 248;--color-surface-bright:252 249 248;--color-surface-dim:220 217 217;--color-surface-container-lowest:255 255 255;--color-surface-container-low:246 243 242;--color-surface-container:240 237 237;--color-surface-container-high:234 231 231;--color-surface-container-highest:228 226 225;--color-on-surface:27 28 28;--color-on-surface-variant:68 72 64;--color-outline:117 120 111;--color-outline-variant:197 200 189;--color-error:186 26 26;--color-on-error:255 255 255;--font-serif:"Playfair Display";--font-sans:"Inter"}body{background-color:rgb(var(--color-background));color:rgb(var(--color-on-surface));font-family:var(--font-sans),system-ui,sans-serif;-webkit-font-smoothing:antialiased}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.display-serif{font-weight:700;letter-spacing:-.02em}.display-italic,.display-serif{font-family:var(--font-serif),Georgia,serif}.display-italic{font-style:italic;font-weight:400}.storefront-prose{font-size:1rem;line-height:1.6;color:rgb(var(--color-on-surface-variant))}.storefront-prose>p{margin-bottom:1.5rem}.storefront-prose>h2{font-size:2rem;line-height:1.3;margin-top:2.5rem;margin-bottom:1rem}.storefront-prose>h2,.storefront-prose>h3{font-family:var(--font-serif),Georgia,serif;font-weight:600;color:rgb(var(--color-on-surface))}.storefront-prose>h3{font-size:1.5rem;line-height:1.4;margin-top:2rem;margin-bottom:.75rem}.storefront-prose>blockquote{margin:2rem 0;border-left:3px solid rgb(var(--color-primary));padding:.5rem 1.5rem;font-family:var(--font-serif),Georgia,serif;font-style:italic;font-size:1.125rem;color:rgb(var(--color-on-surface))}.storefront-prose>ol,.storefront-prose>ul{padding-left:1.5rem;margin-bottom:1.5rem}.storefront-prose>ul{list-style-type:disc}.storefront-prose>ol{list-style-type:decimal}.storefront-prose>ol>li,.storefront-prose>ul>li{margin-bottom:.5rem}.storefront-prose figure img,.storefront-prose img{border-radius:1rem;margin:1.5rem 0}.storefront-prose a{color:rgb(var(--color-primary));font-weight:500;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px}.storefront-prose a:hover{color:rgb(var(--color-secondary))}.storefront-prose code{background:rgb(var(--color-surface-container));padding:.125rem .375rem;border-radius:.25rem;font-size:.95em;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}.storefront-page-body{max-width:768px;margin-left:auto;margin-right:auto;padding-left:1rem;padding-right:1rem;font-size:1rem;line-height:1.65;color:rgb(var(--color-on-surface-variant))}@media (min-width:768px){.storefront-page-body{padding-left:2rem;padding-right:2rem}}.storefront-page-body p{margin-bottom:1.5rem}.storefront-page-body h1{font-family:var(--font-serif),Georgia,serif;font-size:2.75rem;font-weight:700;line-height:1.15;letter-spacing:-.02em;color:rgb(var(--color-on-surface));margin-top:2rem;margin-bottom:1.5rem}@media (min-width:768px){.storefront-page-body h1{font-size:3.5rem}}.storefront-page-body h2{font-size:2rem;line-height:1.3;margin-top:3rem;margin-bottom:1rem}.storefront-page-body h2,.storefront-page-body h3{font-family:var(--font-serif),Georgia,serif;font-weight:600;color:rgb(var(--color-on-surface))}.storefront-page-body h3{font-size:1.5rem;line-height:1.4;margin-top:2.25rem;margin-bottom:.75rem}.storefront-page-body h4,.storefront-page-body h5,.storefront-page-body h6{font-weight:600;color:rgb(var(--color-on-surface));margin-top:1.75rem;margin-bottom:.5rem}.storefront-page-body blockquote{margin:2rem 0;border-left:3px solid rgb(var(--color-primary));padding:.5rem 1.5rem;font-family:var(--font-serif),Georgia,serif;font-style:italic;font-size:1.125rem;color:rgb(var(--color-on-surface))}.storefront-page-body ol,.storefront-page-body ul{padding-left:1.5rem;margin-bottom:1.5rem}.storefront-page-body ul{list-style-type:disc}.storefront-page-body ol{list-style-type:decimal}.storefront-page-body li{margin-bottom:.5rem}.storefront-page-body img{width:100%;height:auto;border-radius:1rem;margin:2.5rem 0;box-shadow:0 8px 24px -12px rgba(0,0,0,.18)}.storefront-page-body a{color:rgb(var(--color-primary));font-weight:500;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:3px}.storefront-page-body a:hover{color:rgb(var(--color-secondary))}.storefront-page-body code{background:rgb(var(--color-surface-container));padding:.125rem .375rem;border-radius:.25rem;font-size:.95em;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}.storefront-page-body table{width:100%;border-collapse:collapse;margin:2rem 0;font-size:.9375rem}.storefront-page-body td,.storefront-page-body th{padding:.625rem .875rem;border-bottom:1px solid rgb(var(--color-outline-variant));text-align:left}.storefront-page-body th{font-weight:600;color:rgb(var(--color-on-surface));background:rgb(var(--color-surface-container-low))}.storefront-page-body hr{border:0;border-top:1px solid rgb(var(--color-outline-variant));margin:3rem 0}.material-symbols-outlined{font-variation-settings:"FILL" 0,"wght" 400,"GRAD" 0,"opsz" 24;vertical-align:middle;line-height:1}.burger-toggle{background:transparent;border:0;cursor:pointer;padding:.25rem;line-height:0}.burger-menu{position:fixed;top:0;left:0;height:100vh;width:min(360px,80vw);background:rgb(var(--color-background));border-right:1px solid rgb(var(--color-outline-variant));transform:translateX(-100%);transition:transform .25s ease;z-index:60;padding:4rem 1.5rem 1.5rem;overflow-y:auto}.burger-menu.is-open{transform:translateX(0)}.burger-menu ul{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:.25rem}.burger-menu a{display:block;padding:.625rem 0;color:rgb(var(--color-on-surface));font-family:var(--font-serif),Georgia,serif;font-size:1.125rem;font-weight:500;text-decoration:none}.burger-menu a:hover{color:rgb(var(--color-primary))}.burger-menu a[aria-current=page]{color:rgb(var(--color-primary));font-weight:700}.burger-menu .menu-children{margin-left:1rem;margin-top:.25rem}.burger-menu .menu-children a{font-size:1rem;font-weight:400}.burger-close{position:absolute;top:1rem;right:1rem;background:transparent;border:0;color:rgb(var(--color-on-surface));cursor:pointer;padding:.5rem}.burger-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.4);opacity:0;pointer-events:none;transition:opacity .25s ease;z-index:55}.burger-backdrop.is-open{opacity:1;pointer-events:auto}body.burger-open{overflow:hidden}.storefront-product-card{transition:transform .3s ease,box-shadow .3s ease}.storefront-product-card:hover{transform:translateY(-4px);box-shadow:0 8px 25px -5px rgba(95,111,82,.15)}.storefront-no-scrollbar{scrollbar-width:none;-ms-overflow-style:none}.storefront-no-scrollbar::-webkit-scrollbar{display:none}.storefront-row-slide{flex:0 0 calc(50% - 0.5rem);min-width:0}@media (min-width:768px){.storefront-row-slide{flex:0 0 calc(33.33333% - 0.66667rem)}}@media (min-width:1024px){.storefront-row-slide{flex:0 0 calc(25% - 1.5rem)}}.storefront-price-promo{color:rgb(var(--color-secondary));font-weight:700}.storefront-price-strike{color:rgb(var(--color-on-surface-variant));text-decoration:line-through;font-weight:400;margin-left:.5rem}.storefront-stock-pill{display:inline-flex;align-items:center;gap:.375rem;padding:.25rem .75rem;border-radius:9999px;font-size:.6875rem;font-weight:600;letter-spacing:.05em;text-transform:uppercase}.storefront-stock-pill:before{content:"";width:.5rem;height:.5rem;border-radius:9999px;background:currentColor}.storefront-stock-in{background:rgb(var(--color-primary-fixed));color:rgb(var(--color-on-primary-fixed-variant))}.storefront-stock-low{background:rgb(var(--color-secondary-fixed));color:rgb(var(--color-on-secondary-fixed-variant))}.storefront-stock-out{background:rgb(var(--color-surface-container-high));color:rgb(var(--color-on-surface-variant))}.storefront-stock-order{background:rgb(var(--color-tertiary-fixed));color:rgb(var(--color-on-tertiary-fixed))}.storefront-catalog-tags-host{scrollbar-width:thin;scrollbar-color:rgb(var(--color-outline-variant)) transparent;-webkit-mask-image:linear-gradient(180deg,#000 calc(100% - 1.5rem),transparent);mask-image:linear-gradient(180deg,#000 calc(100% - 1.5rem),transparent)}.storefront-catalog-tags-host::-webkit-scrollbar{width:6px}.storefront-catalog-tags-host::-webkit-scrollbar-track{background:transparent}.storefront-catalog-tags-host::-webkit-scrollbar-thumb{background:rgb(var(--color-outline-variant));border-radius:3px}.storefront-catalog-tags-host:not(.is-overflowing){-webkit-mask-image:none;mask-image:none}.storefront-catalog-grid{display:grid;gap:1.5rem;grid-template-columns:repeat(2,minmax(0,1fr))}@media (min-width:768px){.storefront-catalog-grid{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width:1024px){.storefront-catalog-grid.is-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.storefront-catalog-grid.is-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.storefront-catalog-grid.is-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}.storefront-catalog-card{transition:transform .4s ease;will-change:transform}.storefront-catalog-card.is-hidden{display:none}.storefront-catalog-empty{grid-column:1/-1;text-align:center;padding:4rem 1rem;color:rgb(var(--color-on-surface-variant));font-style:italic}.storefront-filter-checkbox{width:1rem;height:1rem;border:1px solid rgb(var(--color-outline));border-radius:.25rem;accent-color:rgb(var(--color-primary))}.storefront-filter-chip{display:inline-flex;align-items:center;gap:.5rem;padding:.5rem 1rem;border-radius:9999px;border:1px solid rgb(var(--color-outline-variant));background:rgb(var(--color-surface));color:rgb(var(--color-on-surface));font-weight:500;cursor:pointer;transition:background-color .15s ease,border-color .15s ease}.storefront-filter-chip:hover{background:rgb(var(--color-surface-container))}.storefront-filter-chip.is-active{background:rgb(var(--color-primary));color:rgb(var(--color-on-primary));border-color:rgb(var(--color-primary))}.storefront-bio-card{background:rgb(var(--color-surface-container-lowest));border:1px solid rgb(var(--color-outline-variant)/.4);border-radius:1rem;padding:2rem}.storefront-bio-eyebrow{font-size:.75rem;font-weight:600;letter-spacing:.1em;color:rgb(var(--color-primary));text-transform:uppercase;margin-bottom:1rem}.storefront-bio-row{display:flex;align-items:center;gap:1rem;margin-bottom:1rem}.storefront-bio-avatar{width:4rem;height:4rem;border-radius:9999px;-o-object-fit:cover;object-fit:cover}.storefront-bio-name{font-family:var(--font-serif),Georgia,serif;font-size:1.25rem;font-weight:600;color:rgb(var(--color-on-surface))}.storefront-bio-title{font-size:.75rem;font-weight:600;letter-spacing:.1em;text-transform:uppercase}.storefront-bio-bio,.storefront-bio-title{color:rgb(var(--color-on-surface-variant))}.storefront-bio-bio{font-size:.9375rem;line-height:1.6;margin-bottom:1rem}.storefront-bio-socials{display:flex;gap:.5rem}.storefront-bio-social{display:inline-flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;border-radius:9999px;color:rgb(var(--color-on-surface-variant));transition:color .15s ease,background-color .15s ease}.storefront-bio-social:hover{color:rgb(var(--color-on-primary));background:rgb(var(--color-primary))}.storefront-related-card{background:rgb(var(--color-surface-container-highest)/.4);border:1px solid rgb(var(--color-outline-variant)/.3);border-radius:1rem;padding:2rem}.storefront-related-heading{font-family:var(--font-serif),Georgia,serif;font-size:1.5rem;font-weight:600;color:rgb(var(--color-on-surface));margin-bottom:1.5rem}.storefront-related-list{display:grid;gap:1rem;grid-template-columns:1fr 1fr}.storefront-related-item{display:block;text-decoration:none}.storefront-related-thumb{aspect-ratio:3/4;border-radius:.75rem;overflow:hidden;background:rgb(var(--color-surface-container));margin-bottom:.5rem}.storefront-related-thumb img{width:100%;height:100%;-o-object-fit:cover;object-fit:cover;transition:transform .4s ease}.storefront-related-item:hover .storefront-related-thumb img{transform:scale(1.05)}.storefront-related-title{font-family:var(--font-serif),Georgia,serif;font-size:1rem;font-weight:600;color:rgb(var(--color-on-surface));line-height:1.3}.storefront-related-price{color:rgb(var(--color-primary));font-size:.875rem;font-weight:600}.floating-label-group{position:relative}.floating-label-group input,.floating-label-group label,.floating-label-group textarea{background:rgb(var(--color-surface-container-lowest))}.floating-label-group label{position:absolute;top:1rem;left:1rem;pointer-events:none;transition:all .2s ease;color:rgb(var(--color-outline));padding:0 .25rem}.floating-label-group input:not(:-moz-placeholder)~label,.floating-label-group textarea:not(:-moz-placeholder)~label{top:-.5rem;left:.75rem;font-size:.75rem;color:rgb(var(--color-primary))}.floating-label-group input:focus~label,.floating-label-group input:not(:placeholder-shown)~label,.floating-label-group textarea:focus~label,.floating-label-group textarea:not(:placeholder-shown)~label,.floating-label-group.is-filled label{top:-.5rem;left:.75rem;font-size:.75rem;color:rgb(var(--color-primary))}.visible{visibility:visible}.invisible{visibility:hidden}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.-bottom-8{bottom:-2rem}.-left-4{left:-1rem}.-right-4{right:-1rem}.-right-8{right:-2rem}.bottom-0{bottom:0}.bottom-6{bottom:1.5rem}.left-0{left:0}.left-3{left:.75rem}.left-6{left:1.5rem}.right-0{right:0}.right-6{right:1.5rem}.top-0{top:0}.top-1\/3{top:33.333333%}.top-24{top:6rem}.top-3{top:.75rem}.-z-10{z-index:-10}.z-0{z-index:0}.z-10{z-index:10}.z-50{z-index:50}.mx-auto{margin-left:auto;margin-right:auto}.my-4{margin-top:1rem;margin-bottom:1rem}.\!mb-0{margin-bottom:0!important}.-mb-px{margin-bottom:-1px}.-mt-2{margin-top:-.5rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-section-gap-mobile{margin-bottom:3rem}.mb-stack-lg{margin-bottom:2rem}.mb-stack-md{margin-bottom:1rem}.mb-stack-sm{margin-bottom:.5rem}.mt-1{margin-top:.25rem}.mt-3{margin-top:.75rem}.mt-section-gap-mobile{margin-top:3rem}.mt-stack-lg{margin-top:2rem}.mt-stack-md{margin-top:1rem}.mt-stack-sm{margin-top:.5rem}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.\!grid{display:grid!important}.grid{display:grid}.hidden{display:none}.aspect-\[4\/5\]{aspect-ratio:4/5}.aspect-square{aspect-ratio:1/1}.aspect-video{aspect-ratio:16/9}.h-10{height:2.5rem}.h-12{height:3rem}.h-16{height:4rem}.h-3\.5{height:.875rem}.h-32{height:8rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-8{height:2rem}.h-full{height:100%}.max-h-24{max-height:6rem}.max-h-64{max-height:16rem}.min-h-\[280px\]{min-height:280px}.min-h-\[600px\]{min-height:600px}.w-10{width:2.5rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-3\.5{width:.875rem}.w-32{width:8rem}.w-4{width:1rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-auto{width:auto}.w-full{width:100%}.min-w-0{min-width:0}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-container-max{max-width:1280px}.max-w-md{max-width:28rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.translate-y-full{--tw-translate-y:100%}.transform,.translate-y-full{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-pointer{cursor:pointer}.snap-x{scroll-snap-type:x var(--tw-scroll-snap-strictness)}.snap-mandatory{--tw-scroll-snap-strictness:mandatory}.snap-start{scroll-snap-align:start}.auto-rows-\[280px\]{grid-auto-rows:280px}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-stack-lg{gap:2rem}.gap-stack-md{gap:1rem}.gap-stack-sm{gap:.5rem}.gap-x-8{-moz-column-gap:2rem;column-gap:2rem}.gap-y-3{row-gap:.75rem}.-space-x-1>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(-.25rem*var(--tw-space-x-reverse));margin-left:calc(-.25rem*(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem*var(--tw-space-y-reverse))}.space-y-stack-lg>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(2rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem*var(--tw-space-y-reverse))}.space-y-stack-sm>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.self-start{align-self:flex-start}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.scroll-smooth{scroll-behavior:smooth}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-3xl{border-radius:1.5rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-0{border-width:0}.border-y{border-top-width:1px}.border-b,.border-y{border-bottom-width:1px}.border-b-2{border-bottom-width:2px}.border-l-2{border-left-width:2px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-amber-400{--tw-border-opacity:1;border-color:rgb(251 191 36/var(--tw-border-opacity,1))}.border-blue-600{--tw-border-opacity:1;border-color:rgb(37 99 235/var(--tw-border-opacity,1))}.border-on-primary\/30{border-color:rgb(var(--color-on-primary)/.3)}.border-outline-variant{--tw-border-opacity:1;border-color:rgb(var(--color-outline-variant)/var(--tw-border-opacity,1))}.border-outline-variant\/20{border-color:rgb(var(--color-outline-variant)/.2)}.border-outline-variant\/30{border-color:rgb(var(--color-outline-variant)/.3)}.border-outline-variant\/40{border-color:rgb(var(--color-outline-variant)/.4)}.border-primary{--tw-border-opacity:1;border-color:rgb(var(--color-primary)/var(--tw-border-opacity,1))}.border-red-300{--tw-border-opacity:1;border-color:rgb(252 165 165/var(--tw-border-opacity,1))}.border-secondary{--tw-border-opacity:1;border-color:rgb(var(--color-secondary)/var(--tw-border-opacity,1))}.border-surface-container-high{--tw-border-opacity:1;border-color:rgb(var(--color-surface-container-high)/var(--tw-border-opacity,1))}.border-transparent{border-color:transparent}.bg-amber-50{--tw-bg-opacity:1;background-color:rgb(255 251 235/var(--tw-bg-opacity,1))}.bg-background{--tw-bg-opacity:1;background-color:rgb(var(--color-background)/var(--tw-bg-opacity,1))}.bg-black\/10{background-color:rgba(0,0,0,.1)}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.bg-on-primary{--tw-bg-opacity:1;background-color:rgb(var(--color-on-primary)/var(--tw-bg-opacity,1))}.bg-on-primary\/10{background-color:rgb(var(--color-on-primary)/.1)}.bg-primary{--tw-bg-opacity:1;background-color:rgb(var(--color-primary)/var(--tw-bg-opacity,1))}.bg-primary-fixed{--tw-bg-opacity:1;background-color:rgb(var(--color-primary-fixed)/var(--tw-bg-opacity,1))}.bg-primary\/10{background-color:rgb(var(--color-primary)/.1)}.bg-primary\/50{background-color:rgb(var(--color-primary)/.5)}.bg-primary\/90{background-color:rgb(var(--color-primary)/.9)}.bg-secondary-fixed\/40{background-color:rgb(var(--color-secondary-fixed)/.4)}.bg-secondary\/90{background-color:rgb(var(--color-secondary)/.9)}.bg-surface{--tw-bg-opacity:1;background-color:rgb(var(--color-surface)/var(--tw-bg-opacity,1))}.bg-surface-container{--tw-bg-opacity:1;background-color:rgb(var(--color-surface-container)/var(--tw-bg-opacity,1))}.bg-surface-container-high{--tw-bg-opacity:1;background-color:rgb(var(--color-surface-container-high)/var(--tw-bg-opacity,1))}.bg-surface-container-highest\/40{background-color:rgb(var(--color-surface-container-highest)/.4)}.bg-surface-container-low{--tw-bg-opacity:1;background-color:rgb(var(--color-surface-container-low)/var(--tw-bg-opacity,1))}.bg-surface-container-lowest{--tw-bg-opacity:1;background-color:rgb(var(--color-surface-container-lowest)/var(--tw-bg-opacity,1))}.bg-surface\/85{background-color:rgb(var(--color-surface)/.85)}.bg-surface\/90{background-color:rgb(var(--color-surface)/.9)}.bg-gradient-to-t{background-image:linear-gradient(to top,var(--tw-gradient-stops))}.from-black\/55{--tw-gradient-from:rgba(0,0,0,.55) var(--tw-gradient-from-position);--tw-gradient-to:transparent var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}.via-black\/15{--tw-gradient-to:transparent var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),rgba(0,0,0,.15) var(--tw-gradient-via-position),var(--tw-gradient-to)}.to-transparent{--tw-gradient-to:transparent var(--tw-gradient-to-position)}.object-cover{-o-object-fit:cover;object-fit:cover}.p-1{padding:.25rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.px-gutter{padding-left:1rem;padding-right:1rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-section-gap-mobile{padding-top:3rem;padding-bottom:3rem}.py-stack-lg{padding-top:2rem;padding-bottom:2rem}.pb-1{padding-bottom:.25rem}.pb-2{padding-bottom:.5rem}.pb-section-gap-desktop{padding-bottom:6rem}.pb-stack-lg{padding-bottom:2rem}.pb-stack-md{padding-bottom:1rem}.pl-3{padding-left:.75rem}.pr-1{padding-right:.25rem}.pt-3{padding-top:.75rem}.pt-section-gap-mobile{padding-top:3rem}.pt-stack-lg{padding-top:2rem}.pt-stack-md{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.font-serif{font-family:var(--font-serif),Georgia,serif}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[1\.125rem\]{font-size:1.125rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[14px\]{font-size:14px}.text-\[18px\]{font-size:18px}.text-base{font-size:1rem;line-height:1.5rem}.text-body-lg{font-size:1.125rem;line-height:1.6}.text-body-lg,.text-body-md{letter-spacing:0;font-weight:400}.text-body-md{font-size:1rem;line-height:1.5}.text-display-md{font-size:2.25rem;line-height:1.2;letter-spacing:-.01em;font-weight:700}.text-headline-md{font-size:2rem;line-height:1.3;letter-spacing:0;font-weight:600}.text-headline-sm{font-size:1.5rem;line-height:1.4;letter-spacing:0;font-weight:600}.text-label-caps{font-size:.75rem;line-height:1;letter-spacing:.1em;font-weight:600}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-relaxed{line-height:1.625}.leading-tight{line-height:1.25}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.tracking-widest{letter-spacing:.1em}.text-amber-600{--tw-text-opacity:1;color:rgb(217 119 6/var(--tw-text-opacity,1))}.text-amber-700{--tw-text-opacity:1;color:rgb(180 83 9/var(--tw-text-opacity,1))}.text-amber-700\/80{color:rgba(180,83,9,.8)}.text-blue-500{--tw-text-opacity:1;color:rgb(59 130 246/var(--tw-text-opacity,1))}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-error{--tw-text-opacity:1;color:rgb(var(--color-error)/var(--tw-text-opacity,1))}.text-on-primary{--tw-text-opacity:1;color:rgb(var(--color-on-primary)/var(--tw-text-opacity,1))}.text-on-primary-fixed-variant{--tw-text-opacity:1;color:rgb(var(--color-on-primary-fixed-variant)/var(--tw-text-opacity,1))}.text-on-primary\/80{color:rgb(var(--color-on-primary)/.8)}.text-on-primary\/90{color:rgb(var(--color-on-primary)/.9)}.text-on-secondary{--tw-text-opacity:1;color:rgb(var(--color-on-secondary)/var(--tw-text-opacity,1))}.text-on-surface{--tw-text-opacity:1;color:rgb(var(--color-on-surface)/var(--tw-text-opacity,1))}.text-on-surface-variant{--tw-text-opacity:1;color:rgb(var(--color-on-surface-variant)/var(--tw-text-opacity,1))}.text-primary{--tw-text-opacity:1;color:rgb(var(--color-primary)/var(--tw-text-opacity,1))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.text-red-600{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.text-secondary{--tw-text-opacity:1;color:rgb(var(--color-secondary)/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.placeholder-on-primary\/60::-moz-placeholder{color:rgb(var(--color-on-primary)/.6)}.placeholder-on-primary\/60::placeholder{color:rgb(var(--color-on-primary)/.6)}.accent-primary{accent-color:rgb(var(--color-primary)/1)}.opacity-40{opacity:.4}.opacity-70{opacity:.7}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow,.shadow-2xl{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px rgba(0,0,0,.25);--tw-shadow-colored:0 25px 50px -12px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-1,.ring-2{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-2{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.ring-4{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-amber-500\/60{--tw-ring-color:rgba(245,158,11,.6)}.ring-blue-500\/60{--tw-ring-color:rgba(59,130,246,.6)}.ring-surface-container-lowest{--tw-ring-opacity:1;--tw-ring-color:rgb(var(--color-surface-container-lowest)/var(--tw-ring-opacity,1))}.blur-3xl{--tw-blur:blur(64px)}.blur-3xl,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur{--tw-backdrop-blur:blur(8px)}.backdrop-blur,.backdrop-blur-md{backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.backdrop-blur-md{--tw-backdrop-blur:blur(12px)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-300{transition-duration:.3s}.duration-500{transition-duration:.5s}.duration-700{transition-duration:.7s}.hover\:gap-4:hover{gap:1rem}.hover\:border-transparent:hover{border-color:transparent}.hover\:bg-blue-700:hover{--tw-bg-opacity:1;background-color:rgb(29 78 216/var(--tw-bg-opacity,1))}.hover\:bg-on-primary\/90:hover{background-color:rgb(var(--color-on-primary)/.9)}.hover\:bg-primary:hover{--tw-bg-opacity:1;background-color:rgb(var(--color-primary)/var(--tw-bg-opacity,1))}.hover\:bg-primary-container:hover{--tw-bg-opacity:1;background-color:rgb(var(--color-primary-container)/var(--tw-bg-opacity,1))}.hover\:bg-red-50:hover{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.hover\:bg-secondary-container:hover{--tw-bg-opacity:1;background-color:rgb(var(--color-secondary-container)/var(--tw-bg-opacity,1))}.hover\:bg-secondary-fixed:hover{--tw-bg-opacity:1;background-color:rgb(var(--color-secondary-fixed)/var(--tw-bg-opacity,1))}.hover\:bg-surface-container:hover{--tw-bg-opacity:1;background-color:rgb(var(--color-surface-container)/var(--tw-bg-opacity,1))}.hover\:text-amber-700:hover{--tw-text-opacity:1;color:rgb(180 83 9/var(--tw-text-opacity,1))}.hover\:text-blue-700:hover{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}.hover\:text-on-primary:hover{--tw-text-opacity:1;color:rgb(var(--color-on-primary)/var(--tw-text-opacity,1))}.hover\:text-on-primary-container:hover{--tw-text-opacity:1;color:rgb(var(--color-on-primary-container)/var(--tw-text-opacity,1))}.hover\:text-on-secondary-container:hover{--tw-text-opacity:1;color:rgb(var(--color-on-secondary-container)/var(--tw-text-opacity,1))}.hover\:text-primary:hover{--tw-text-opacity:1;color:rgb(var(--color-primary)/var(--tw-text-opacity,1))}.hover\:text-primary-container:hover{--tw-text-opacity:1;color:rgb(var(--color-primary-container)/var(--tw-text-opacity,1))}.hover\:text-red-700:hover{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity,1))}.hover\:text-secondary:hover{--tw-text-opacity:1;color:rgb(var(--color-secondary)/var(--tw-text-opacity,1))}.hover\:shadow-xl:hover{--tw-shadow:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--tw-shadow-colored:0 20px 25px -5px var(--tw-shadow-color),0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.focus\:border-primary:focus{--tw-border-opacity:1;border-color:rgb(var(--color-primary)/var(--tw-border-opacity,1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.focus\:ring-primary:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(var(--color-primary)/var(--tw-ring-opacity,1))}.active\:scale-95:active{--tw-scale-x:.95;--tw-scale-y:.95;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:translate-y-0{--tw-translate-y:0px}.group:hover .group-hover\:scale-105,.group:hover .group-hover\:translate-y-0{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.group:hover .group-hover\:scale-105{--tw-scale-x:1.05;--tw-scale-y:1.05}.group:hover .group-hover\:bg-primary{--tw-bg-opacity:1;background-color:rgb(var(--color-primary)/var(--tw-bg-opacity,1))}.group:hover .group-hover\:text-on-primary{--tw-text-opacity:1;color:rgb(var(--color-on-primary)/var(--tw-text-opacity,1))}@media (min-width:640px){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}}@media (min-width:768px){.md\:col-span-12{grid-column:span 12/span 12}.md\:col-span-4{grid-column:span 4/span 4}.md\:col-span-5{grid-column:span 5/span 5}.md\:col-span-7{grid-column:span 7/span 7}.md\:col-span-8{grid-column:span 8/span 8}.md\:col-start-5{grid-column-start:5}.md\:flex{display:flex}.md\:aspect-\[16\/10\]{aspect-ratio:16/10}.md\:aspect-auto{aspect-ratio:auto}.md\:min-h-0{min-height:0}.md\:min-h-\[360px\]{min-height:360px}.md\:min-h-\[760px\]{min-height:760px}.md\:auto-rows-\[300px\]{grid-auto-rows:300px}.md\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:items-end{align-items:flex-end}.md\:items-center{align-items:center}.md\:justify-between{justify-content:space-between}.md\:gap-16{gap:4rem}.md\:gap-stack-lg{gap:2rem}.md\:p-12{padding:3rem}.md\:p-8{padding:2rem}.md\:px-gutter-desktop{padding-left:2rem;padding-right:2rem}.md\:py-section-gap-desktop{padding-top:6rem;padding-bottom:6rem}.md\:py-stack-lg{padding-top:2rem;padding-bottom:2rem}.md\:pt-section-gap-desktop{padding-top:6rem}.md\:text-display-lg{font-size:3rem;line-height:1.1;letter-spacing:-.02em;font-weight:700}.md\:text-display-md{font-size:2.25rem;line-height:1.2;letter-spacing:-.01em;font-weight:700}}@media (min-width:1024px){.lg\:sticky{position:sticky}.lg\:top-24{top:6rem}.lg\:col-span-12{grid-column:span 12/span 12}.lg\:col-span-3{grid-column:span 3/span 3}.lg\:col-span-4{grid-column:span 4/span 4}.lg\:col-span-5{grid-column:span 5/span 5}.lg\:col-span-7{grid-column:span 7/span 7}.lg\:col-span-8{grid-column:span 8/span 8}.lg\:col-span-9{grid-column:span 9/span 9}.lg\:mb-section-gap-desktop{margin-bottom:6rem}.lg\:mt-section-gap-desktop{margin-top:6rem}.lg\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:p-16{padding:4rem}}@media (min-width:1280px){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (prefers-color-scheme:dark){.dark\:border-amber-700{--tw-border-opacity:1;border-color:rgb(180 83 9/var(--tw-border-opacity,1))}.dark\:border-blue-500{--tw-border-opacity:1;border-color:rgb(59 130 246/var(--tw-border-opacity,1))}.dark\:bg-amber-950\/30{background-color:rgba(69,26,3,.3)}.dark\:bg-blue-950\/30{background-color:rgba(23,37,84,.3)}.dark\:text-amber-400{--tw-text-opacity:1;color:rgb(251 191 36/var(--tw-text-opacity,1))}.dark\:text-amber-400\/80{color:rgba(251,191,36,.8)}}
|
package/package.json
CHANGED
|
@@ -1,6 +1,103 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-cms/agentcms",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Static CMS whose admin runs in the browser and publishes plain HTML to any static host (GitHub/GitLab/Cloudflare Pages, S3, Flexweg, own server). Installable and manageable from AI coding agents.",
|
|
6
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
7
|
+
"homepage": "https://github.com/fleox/agentcms#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/fleox/agentcms.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/fleox/agentcms/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"cms",
|
|
17
|
+
"static-site",
|
|
18
|
+
"github-pages",
|
|
19
|
+
"s3",
|
|
20
|
+
"firebase",
|
|
21
|
+
"sqlite",
|
|
22
|
+
"markdown",
|
|
23
|
+
"ai-agent",
|
|
24
|
+
"claude-code"
|
|
25
|
+
],
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=20"
|
|
28
|
+
},
|
|
29
|
+
"bin": {
|
|
30
|
+
"agentcms": "dist/agent/agentcms.mjs"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist/agent",
|
|
34
|
+
"dist/admin",
|
|
35
|
+
"dist/theme-assets",
|
|
36
|
+
"dist/version.json",
|
|
37
|
+
"plugin",
|
|
38
|
+
"changelog.json",
|
|
39
|
+
"LICENSE",
|
|
40
|
+
"README.md"
|
|
41
|
+
],
|
|
42
|
+
"agentcms": {
|
|
43
|
+
"minSkillsVersion": "0.1.0",
|
|
44
|
+
"dataSchema": 1
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"themes:tailwind": "node scripts/build-theme-tailwind.mjs",
|
|
48
|
+
"predev": "npm run themes:tailwind",
|
|
49
|
+
"dev": "vite",
|
|
50
|
+
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.agent.json",
|
|
51
|
+
"pretest": "npm run themes:tailwind",
|
|
52
|
+
"test": "vitest run",
|
|
53
|
+
"test:watch": "vitest",
|
|
54
|
+
"prebuild": "npm run typecheck && npm run themes:tailwind",
|
|
55
|
+
"build": "vite build && node scripts/build-themes.mjs && node scripts/build-bundled-externals.mjs && node scripts/pack-bundled-zips.mjs && node scripts/write-admin-manifest.mjs && vite build --config vite.agent.config.ts && node scripts/write-version.mjs",
|
|
56
|
+
"pack:zips": "node scripts/pack-bundled-zips.mjs",
|
|
57
|
+
"preview": "vite preview",
|
|
58
|
+
"check:skills": "node scripts/check-skills.mjs",
|
|
59
|
+
"version": "node scripts/sync-version.mjs && git add plugin"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@codemirror/lang-html": "^6.4.11",
|
|
63
|
+
"@codemirror/theme-one-dark": "^6.1.3",
|
|
64
|
+
"@tiptap/extension-image": "^2.27.2",
|
|
65
|
+
"@tiptap/extension-link": "^2.27.2",
|
|
66
|
+
"@tiptap/extension-placeholder": "^2.27.2",
|
|
67
|
+
"@tiptap/react": "^2.27.2",
|
|
68
|
+
"@tiptap/starter-kit": "^2.27.2",
|
|
69
|
+
"@tiptap/suggestion": "^2.27.2",
|
|
70
|
+
"@types/dompurify": "^3.2.0",
|
|
71
|
+
"@types/jszip": "^3.4.1",
|
|
72
|
+
"@types/node": "^25.6.0",
|
|
73
|
+
"@types/react": "^18.3.28",
|
|
74
|
+
"@types/react-dom": "^18.3.7",
|
|
75
|
+
"@types/sql.js": "^1.4.11",
|
|
76
|
+
"@types/turndown": "^5.0.6",
|
|
77
|
+
"@uiw/react-codemirror": "^4.25.9",
|
|
78
|
+
"@vitejs/plugin-react": "^5.2.0",
|
|
79
|
+
"autoprefixer": "^10.4.20",
|
|
80
|
+
"clsx": "^2.1.1",
|
|
81
|
+
"dompurify": "^3.2.3",
|
|
82
|
+
"firebase": "^11.0.2",
|
|
83
|
+
"i18next": "^23.16.8",
|
|
84
|
+
"i18next-browser-languagedetector": "^8.0.2",
|
|
85
|
+
"jsdom": "^25.0.1",
|
|
86
|
+
"jszip": "^3.10.1",
|
|
87
|
+
"lucide-react": "^0.460.0",
|
|
88
|
+
"marked": "^15.0.5",
|
|
89
|
+
"postcss": "^8.4.49",
|
|
90
|
+
"react": "^18.3.1",
|
|
91
|
+
"react-dom": "^18.3.1",
|
|
92
|
+
"react-i18next": "^15.2.0",
|
|
93
|
+
"react-router-dom": "^6.28.0",
|
|
94
|
+
"sass": "^1.83.1",
|
|
95
|
+
"sql.js": "^1.13.0",
|
|
96
|
+
"tailwindcss": "^3.4.14",
|
|
97
|
+
"tiptap-markdown": "^0.8.10",
|
|
98
|
+
"turndown": "^7.2.4",
|
|
99
|
+
"typescript": "^6.0.3",
|
|
100
|
+
"vite": "^6.4.3",
|
|
101
|
+
"vitest": "^4.1.8"
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "agentcms",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Skills to install AgentCMS sites, then manage their content, themes and plugins.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "fleox"
|
|
7
|
+
},
|
|
8
|
+
"homepage": "https://github.com/fleox/agentcms",
|
|
9
|
+
"repository": "https://github.com/fleox/agentcms",
|
|
10
|
+
"license": "PolyForm-Noncommercial-1.0.0",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"cms",
|
|
13
|
+
"static-site",
|
|
14
|
+
"installer"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agentcms-install
|
|
3
|
+
description: Install a new AgentCMS site (static CMS) for the user - ask where content is stored (SQLite file, Markdown in GitHub/GitLab, Firebase, this browser), then where the site is hosted (GitHub/GitLab/Cloudflare Pages, S3 or OVH bucket, Flexweg), help create or import the needed tokens and keys, and install everything with the agentcms CLI. Use when the user wants to create, set up or install an AgentCMS / Flexweg CMS site.
|
|
4
|
+
license: PolyForm-Noncommercial-1.0.0
|
|
5
|
+
metadata:
|
|
6
|
+
version: "0.1.0"
|
|
7
|
+
repository: "https://github.com/fleox/agentcms"
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Install an AgentCMS site
|
|
11
|
+
|
|
12
|
+
AgentCMS is a static CMS: an admin web app (runs in the browser) keeps content in a **data backend** and publishes plain HTML to a **hosting** target. Nothing runs on the server. The `agentcms` CLI installs a site end to end and keeps a registry of every site this computer manages.
|
|
13
|
+
|
|
14
|
+
**Language:** talk to the user in their language. Keep commands, file contents and these instructions in English.
|
|
15
|
+
|
|
16
|
+
Every command below is `npx -y @agent-cms/agentcms@0.1.0 <command> --json` (Node.js 20+). Output is one JSON object: `{"ok":true,"data":...}` or `{"ok":false,"error":{"code","message","hint"}}` - when `ok` is false, read `hint` and act on it. If npx can't fetch the package (404 / offline), clone `https://github.com/fleox/agentcms` and use `node agentcms/dist/agent/agentcms.mjs` the same way.
|
|
17
|
+
|
|
18
|
+
## Step 0 - Versions and existing sites
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx -y @agent-cms/agentcms@0.1.0 status --json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- `data.tool.updateAvailable: true` -> a newer AgentCMS exists. Offer to update these skills first (Claude Code: `/plugin marketplace update agentcms`, then `/reload-plugins`), then continue.
|
|
25
|
+
- `data.sites` lists sites already registered on this computer. If the user actually wants to change one of them, switch to the `agentcms-manage` skill.
|
|
26
|
+
|
|
27
|
+
## Step 1 - Ask where the content is stored
|
|
28
|
+
|
|
29
|
+
Ask this first; hosting comes after. Run `npx -y @agent-cms/agentcms@0.1.0 options --json` and present `data.dataBackends` in one sentence each:
|
|
30
|
+
|
|
31
|
+
- **SQLite file** - one owner, simplest, no other account. Encrypted with a passphrase by default (a static host serves the file like any page); can also live in a separate private bucket / repo. No login screen: anyone with the admin URL, the keys and the passphrase can edit.
|
|
32
|
+
- **Markdown in a Git repo** (GitHub / GitLab) - several editors or computers, full history; each editor uses their own token.
|
|
33
|
+
- **Firebase** - real-time, email/password logins. Wizard only (see "Wizard fallback").
|
|
34
|
+
- **This browser** - quick try on one computer. Wizard only.
|
|
35
|
+
|
|
36
|
+
## Step 2 - Ask where the site is hosted
|
|
37
|
+
|
|
38
|
+
Present the entries of `data.hostings` with `cli: true` that fit the data choice. Pre-select the obvious one (Markdown on GitHub -> GitHub Pages). Then open the matching guide and follow it - it says what to create, what the user must click, and what you can automate with tools already installed (`gh`, `aws`, `glab`, `wrangler`):
|
|
39
|
+
|
|
40
|
+
| Hosting | Guide |
|
|
41
|
+
|---|---|
|
|
42
|
+
| GitHub Pages / Cloudflare Pages / other git host | [references/github.md](references/github.md) (+ [references/cloudflare.md](references/cloudflare.md)) |
|
|
43
|
+
| GitLab Pages | [references/gitlab.md](references/gitlab.md) |
|
|
44
|
+
| S3-compatible bucket (AWS, OVHcloud, Scaleway, R2...) | [references/s3.md](references/s3.md) |
|
|
45
|
+
| Flexweg | [references/flexweg.md](references/flexweg.md) |
|
|
46
|
+
|
|
47
|
+
Markdown content on GitHub/GitLab also needs the content repository: [references/github.md](references/github.md) / [references/gitlab.md](references/gitlab.md).
|
|
48
|
+
|
|
49
|
+
## Step 3 - Credentials (never through the chat)
|
|
50
|
+
|
|
51
|
+
Secrets are stored per **account** (`github:<login>`, `s3:<name>`, `flexweg:<name>`, `php-bridge:<name>`, `gitlab:<name>`), not per site - check `npx -y @agent-cms/agentcms@0.1.0 credentials list --json` first and reuse an account that is already there.
|
|
52
|
+
|
|
53
|
+
To add one, use the first option that applies:
|
|
54
|
+
|
|
55
|
+
1. Import from a tool the user is signed in to: `npx -y @agent-cms/agentcms@0.1.0 credentials set github:<login> --from-gh --json`, `npx -y @agent-cms/agentcms@0.1.0 credentials set s3:<name> --from-aws-profile <profile> --json`.
|
|
56
|
+
2. Otherwise ask the user to run it **themselves** - in Claude Code they type `! npx -y @agent-cms/agentcms@0.1.0 credentials set <account>` - and type the secret at the hidden prompt.
|
|
57
|
+
3. Or an environment variable the user set: `--from-env VAR` (`--from-env KEY_ID,SECRET` for S3).
|
|
58
|
+
|
|
59
|
+
SQLite passphrase: nothing to do before installing - `install` generates a strong one and stores it as `passphrase:<alias>`. To reuse an existing database, store its passphrase first (`! npx -y @agent-cms/agentcms@0.1.0 credentials set passphrase:<alias>`).
|
|
60
|
+
|
|
61
|
+
Rules: never ask for a token, password or secret key in the chat; never print one; never put one in a plan file, `config.js`, a repo or a commit. When you create a key with a CLI, send it straight into `credentials set` (environment variable or pipe), or copy it to the clipboard (`pbcopy` / `xclip` / `clip`) - never display it.
|
|
62
|
+
|
|
63
|
+
## Step 4 - Write the plan, dry-run it
|
|
64
|
+
|
|
65
|
+
Write `agentcms-plan.json` (no secrets - only account ids), following `data.planExample` from `options`:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"alias": "my-blog",
|
|
70
|
+
"data": { "backend": "markdown-git", "git": { "provider": "github", "owner": "my-login", "repo": "my-blog-content", "branch": "main" }, "credential": "github:my-login" },
|
|
71
|
+
"hosting": { "type": "github-pages", "settings": { "owner": "my-login", "repo": "my-blog", "siteUrl": "https://my-login.github.io/my-blog" } },
|
|
72
|
+
"admin": { "folder": "admin" }
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- `alias`: short name for this site (lower-case, dashes). Ask the user if they manage several sites.
|
|
77
|
+
- SQLite: `"data": { "backend": "sqlite-file", "path": "data/site.sqlite" }` - the file is encrypted and lives on the hosting (on git hostings: on the unpublished branch `agentcms-data` of the same repo). Add `"location": { "type": "s3", "settings": { ... }, "credential": "s3:<name>" }` to keep it in a separate private bucket (or a private GitHub repo with `"type": "git-other"`), see [references/s3.md](references/s3.md). Only set `"encryption": false` if the user insists and the file is not publicly served.
|
|
78
|
+
- `hosting.credential` can be omitted when the hosting is on the same git provider as the content.
|
|
79
|
+
- Keep `"admin": { "folder": "admin" }` so the admin is reachable at `<site URL>/admin/` from any computer.
|
|
80
|
+
|
|
81
|
+
Then:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npx -y @agent-cms/agentcms@0.1.0 install --plan agentcms-plan.json --dry-run --json
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Fix whatever `error.hint` says (token permissions, repo or bucket names, URL). Error `content-exists` means the content repo already publishes somewhere else: ask the user whether to keep that site (register it with `agentcms-manage`) or publish elsewhere (`--overwrite-target`).
|
|
88
|
+
|
|
89
|
+
## Step 5 - Install, check, hand over
|
|
90
|
+
|
|
91
|
+
Show the user a one-line summary (data -> hosting -> site URL) and ask for a go. Then:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npx -y @agent-cms/agentcms@0.1.0 install --plan agentcms-plan.json --json
|
|
95
|
+
npx -y @agent-cms/agentcms@0.1.0 doctor --site <alias> --json
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
- Relay `data.notices` (for example "GitHub Pages enabled" or how to enable it) and `data.nextSteps`.
|
|
99
|
+
- For every doctor check with `status: "fail"`, propose its `fix`. Pages hosts need about a minute before the admin URL answers - re-run doctor after waiting.
|
|
100
|
+
- Give the user the site URL and the admin URL, and remind them each new browser asks once for its access token or hosting keys (they are stored per browser, never online).
|
|
101
|
+
- **Encrypted SQLite**: the passphrase is the only key to the content. Before finishing, run `npx -y @agent-cms/agentcms@0.1.0 credentials copy passphrase:<alias> --json` (it goes to the clipboard, never to the chat) and ask the user to save it in their password manager now; the admin asks for it once per browser.
|
|
102
|
+
- The plan file holds no secrets; offer to delete it or keep it for reference.
|
|
103
|
+
|
|
104
|
+
## Wizard fallback (Firebase, this browser, local folder, ZIP)
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
npx -y @agent-cms/agentcms@0.1.0 serve --json
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Run it in the background; it prints `data.url` (http://localhost:4173/). The user opens it and follows the setup wizard with the choices from steps 1 and 2 - keep "Host the admin on this site" checked. Help them find each value; secrets go into the wizard, not the chat. Stop the process when the wizard shows its done card, then register the site: `npx -y @agent-cms/agentcms@0.1.0 site add <alias> --admin-url <admin URL> --json` (see `agentcms-manage`).
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Cloudflare Pages (from a GitHub repository)
|
|
2
|
+
|
|
3
|
+
AgentCMS commits the site into a GitHub repository; Cloudflare Pages deploys it on every commit.
|
|
4
|
+
|
|
5
|
+
1. Set up the GitHub site repository and token exactly as in [github.md](github.md) (the repository can stay private - Cloudflare reads it through its GitHub app).
|
|
6
|
+
2. The user connects it once in the Cloudflare dashboard: Workers & Pages -> Create -> Pages -> **Connect to Git** -> pick the repository -> Framework preset: None, Build command: *(empty)*, Build output directory: `/` -> Save and Deploy.
|
|
7
|
+
3. Site URL: `https://<project>.pages.dev`, or the custom domain added under the project's Custom domains.
|
|
8
|
+
|
|
9
|
+
Plan fragment:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
"hosting": { "type": "cloudflare-pages", "settings": { "owner": "<owner>", "repo": "<site-repo>", "branch": "main", "siteUrl": "https://<project>.pages.dev" } }
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`wrangler` can't link a Git repository, so step 2 stays manual; give the user the exact clicks.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Flexweg hosting
|
|
2
|
+
|
|
3
|
+
- The user creates (or opens) a site on https://www.flexweg.com, then copies an **API key** from the site's API section. They store it: `! npx -y @agent-cms/agentcms@0.1.0 credentials set flexweg:<site-name>`.
|
|
4
|
+
- Site URL: the site's public URL shown in the Flexweg dashboard.
|
|
5
|
+
- Data: SQLite file on Flexweg works out of the box. Flexweg's own SQLite service (with real logins) is only available through the setup wizard (`serve`), via the "Use Flexweg's SQLite service" checkbox.
|
|
6
|
+
|
|
7
|
+
Plan fragment:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
"hosting": { "type": "flexweg", "settings": { "siteUrl": "<public site URL>" }, "credential": "flexweg:<site-name>" }
|
|
11
|
+
```
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# GitHub - content repo, GitHub Pages hosting, token
|
|
2
|
+
|
|
3
|
+
## Repositories
|
|
4
|
+
|
|
5
|
+
- **Content** (Markdown backend): a repository holding posts as `.md` files. Make it **private** - it contains drafts.
|
|
6
|
+
- **Site** (GitHub Pages): a repository the admin publishes HTML into. On free GitHub plans Pages only works on **public** repositories.
|
|
7
|
+
- Use two repositories. Content inside the public site repository would publish the drafts too.
|
|
8
|
+
- An empty repository is fine: the first install commit creates the branch.
|
|
9
|
+
|
|
10
|
+
If `gh` is installed and signed in (`gh auth status`), offer to create them:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
gh repo create <owner>/<site-repo> --public --description "Website published by AgentCMS"
|
|
14
|
+
gh repo create <owner>/<content-repo> --private --description "AgentCMS content"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Otherwise send the user to https://github.com/new (once per repository) and ask for the owner and the names.
|
|
18
|
+
|
|
19
|
+
## Token
|
|
20
|
+
|
|
21
|
+
The same token can serve the content and the site.
|
|
22
|
+
|
|
23
|
+
**Option A - fine-grained token (recommended, least privilege).** Send the user to:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
https://github.com/settings/personal-access-tokens/new?name=AgentCMS&description=AgentCMS%20content%20and%20site&contents=write&pages=write&metadata=read
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
If GitHub ignores the query parameters, they set by hand:
|
|
30
|
+
- Resource owner: the account or organisation owning the repos.
|
|
31
|
+
- Repository access: **Only select repositories** -> the content repo + the site repo.
|
|
32
|
+
- Permissions -> Repository: **Contents: Read and write**, **Pages: Read and write** (lets AgentCMS switch Pages on), Metadata: Read-only (automatic).
|
|
33
|
+
- Expiration: their choice (note the date - the site stops publishing when it expires).
|
|
34
|
+
|
|
35
|
+
Then they store it themselves: `! npx -y @agent-cms/agentcms@0.1.0 credentials set github:<login>` and paste it at the hidden prompt.
|
|
36
|
+
|
|
37
|
+
**Option B - reuse the GitHub CLI login** (broader `repo` scope, quickest):
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx -y @agent-cms/agentcms@0.1.0 credentials set github:<login> --from-gh --json
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Each editor of a Markdown site later signs in to the admin with **their own** token (same permissions on the content repo); write access = editor, admin access = admin.
|
|
44
|
+
|
|
45
|
+
## Site URL
|
|
46
|
+
|
|
47
|
+
- Repository `<owner>/<repo>` -> `https://<owner>.github.io/<repo>`
|
|
48
|
+
- Repository named `<owner>.github.io` -> `https://<owner>.github.io`
|
|
49
|
+
- Custom domain configured in the repo's Pages settings -> that domain (`https://www.example.com`).
|
|
50
|
+
|
|
51
|
+
## Plan fragment
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
"hosting": { "type": "github-pages", "settings": { "owner": "<owner>", "repo": "<site-repo>", "branch": "main", "siteUrl": "https://<owner>.github.io/<site-repo>" } }
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Omit `hosting.credential` when the content is also on GitHub with the same account (its token is reused).
|
|
58
|
+
|
|
59
|
+
## SQLite data on a GitHub Pages site
|
|
60
|
+
|
|
61
|
+
With the SQLite backend, the database goes into the **same repository** on a dedicated branch, `agentcms-data`, that Pages never publishes: saving content doesn't rebuild the site and the file isn't served by it. It is encrypted, so a public repository is fine - but keep the passphrase safe: anyone who has it and can read the repo can read the content. Nothing to configure; the install creates the branch (after `main`, so `main` stays the default branch).
|
|
62
|
+
|
|
63
|
+
## GitHub Pages switch
|
|
64
|
+
|
|
65
|
+
The first install commit tries to enable Pages through the API (needs the Pages permission). If the install notices say it could not, or `doctor` reports `github-pages: fail`, the user opens `https://github.com/<owner>/<site-repo>/settings/pages` -> Source: **Deploy from a branch** -> `main` / `(root)` -> Save. The first build takes about a minute.
|
|
66
|
+
|
|
67
|
+
GitHub may show a "Start trial" banner for GitHub Enterprise on the Pages page of a private repo: that's the public-repo requirement, not something to buy - make the site repository public instead.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# GitLab - content repo, GitLab Pages hosting, token
|
|
2
|
+
|
|
3
|
+
- Projects: one private project for content (Markdown backend), one for the site (GitLab Pages). Create them on https://gitlab.com/projects/new, or with `glab repo create <group>/<name> --private` / `--public` when `glab` is installed and signed in.
|
|
4
|
+
- Token: project access token (Settings -> Access tokens) or personal token (Preferences -> Access tokens) with scope **`api`** and role **Developer** or higher on both projects. The user stores it: `! npx -y @agent-cms/agentcms@0.1.0 credentials set gitlab:<name>`.
|
|
5
|
+
- GitLab Pages needs the site in a folder: AgentCMS publishes into `public/` and commits a minimal `.gitlab-ci.yml` with the first publish.
|
|
6
|
+
- Site URL: `https://<group>.gitlab.io/<project>` (or the custom domain from Deploy -> Pages).
|
|
7
|
+
|
|
8
|
+
Plan fragments:
|
|
9
|
+
|
|
10
|
+
```json
|
|
11
|
+
"data": { "backend": "markdown-git", "git": { "provider": "gitlab", "project": "<group>/<content-project>", "branch": "main" }, "credential": "gitlab:<name>" },
|
|
12
|
+
"hosting": { "type": "gitlab-pages", "settings": { "project": "<group>/<site-project>", "branch": "main", "siteUrl": "https://<group>.gitlab.io/<site-project>" } }
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Self-managed GitLab: add `"apiBaseUrl": "https://gitlab.example.com/api/v4"` to both `git` and `hosting.settings`.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# S3-compatible bucket (AWS, OVHcloud, Scaleway, Cloudflare R2, MinIO)
|
|
2
|
+
|
|
3
|
+
The admin writes files straight into the bucket with signed requests from the browser. The bucket needs:
|
|
4
|
+
|
|
5
|
+
1. a key pair allowed to read / write / delete / list objects;
|
|
6
|
+
2. **CORS** allowing the admin's origin(s);
|
|
7
|
+
3. public read access for visitors, and ideally **static website hosting** (index.html for folder URLs).
|
|
8
|
+
|
|
9
|
+
If the `aws` CLI is installed, offer to do 2 and 3 for the user, and import 1 from an aws profile.
|
|
10
|
+
|
|
11
|
+
## Values for the plan
|
|
12
|
+
|
|
13
|
+
| Setting | AWS | OVHcloud | Notes |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| `endpoint` | empty | `https://s3.<region>.io.cloud.ovh.net` | Scaleway `https://s3.<region>.scw.cloud`, R2 `https://<account>.r2.cloudflarestorage.com` |
|
|
16
|
+
| `region` | e.g. `eu-west-3` | e.g. `eu-west-par`, `gra`, `sbg` | R2: `auto` |
|
|
17
|
+
| `bucket` | bucket name | bucket name | |
|
|
18
|
+
| `publicRead` | `false` (use a bucket policy) | **`true`** (OVH has no bucket policies) | sends `x-amz-acl: public-read` |
|
|
19
|
+
| `siteUrl` | website / CloudFront URL | see below | |
|
|
20
|
+
|
|
21
|
+
## Key pair
|
|
22
|
+
|
|
23
|
+
- From an existing aws CLI profile: `npx -y @agent-cms/agentcms@0.1.0 credentials set s3:<name> --from-aws-profile <profile> --json`.
|
|
24
|
+
- AWS: IAM user with `s3:GetObject`, `s3:PutObject`, `s3:PutObjectAcl`, `s3:DeleteObject`, `s3:ListBucket` on this bucket only.
|
|
25
|
+
- OVHcloud: Public Cloud -> Object Storage -> **S3 users** -> create a user with access to the bucket, then show its credentials (access key + secret).
|
|
26
|
+
- Otherwise the user runs `! npx -y @agent-cms/agentcms@0.1.0 credentials set s3:<name>` and types both values.
|
|
27
|
+
|
|
28
|
+
## CORS (aws CLI)
|
|
29
|
+
|
|
30
|
+
Origins = where the admin runs: the bucket's HTTPS endpoint (hosted admin) and `http://localhost:4173` (`agentcms serve`). Add the custom domain if any.
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
cat > /tmp/agentcms-cors.json <<'JSON'
|
|
34
|
+
{ "CORSRules": [ {
|
|
35
|
+
"AllowedOrigins": ["https://<bucket>.s3.<region>.io.cloud.ovh.net", "http://localhost:4173"],
|
|
36
|
+
"AllowedMethods": ["GET", "PUT", "DELETE", "HEAD", "POST"],
|
|
37
|
+
"AllowedHeaders": ["*"],
|
|
38
|
+
"ExposeHeaders": ["ETag"],
|
|
39
|
+
"MaxAgeSeconds": 3600 } ] }
|
|
40
|
+
JSON
|
|
41
|
+
aws --endpoint-url <endpoint> s3api put-bucket-cors --bucket <bucket> --cors-configuration file:///tmp/agentcms-cors.json
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
(Omit `--endpoint-url` on AWS.)
|
|
45
|
+
|
|
46
|
+
## Static website hosting
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
aws --endpoint-url <endpoint> s3api put-bucket-website --bucket <bucket> \
|
|
50
|
+
--website-configuration '{"IndexDocument":{"Suffix":"index.html"},"ErrorDocument":{"Key":"404.html"}}'
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
AWS also needs "Block public access" off for the bucket and a public-read bucket policy on `arn:aws:s3:::<bucket>/*`.
|
|
54
|
+
|
|
55
|
+
## Site URL and HTTPS (important)
|
|
56
|
+
|
|
57
|
+
The browser admin signs requests with WebCrypto, which only exists on **HTTPS** pages (or localhost). Website endpoints are often HTTP-only:
|
|
58
|
+
|
|
59
|
+
- OVHcloud website endpoint `http://<bucket>.s3-website.<region>.io.cloud.ovh.net` serves folders (index.html) but is HTTP. The HTTPS endpoint `https://<bucket>.s3.<region>.io.cloud.ovh.net` works for the admin at `/admin/index.html` (it doesn't serve folder indexes).
|
|
60
|
+
- Best for production: a custom domain with HTTPS in front (CDN such as Cloudflare or CloudFront) -> use it as `siteUrl`.
|
|
61
|
+
- For a test, `siteUrl` = the website endpoint is fine; tell the user to open the admin at `https://<bucket>.s3.<region>.io.cloud.ovh.net/admin/index.html`, and make sure that origin is in the CORS rules.
|
|
62
|
+
|
|
63
|
+
## Plan fragment
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
"hosting": { "type": "s3", "settings": { "endpoint": "https://s3.eu-west-par.io.cloud.ovh.net", "region": "eu-west-par", "bucket": "<bucket>", "publicRead": true, "siteUrl": "<site URL>" }, "credential": "s3:<name>" }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
SQLite data on a public bucket is encrypted by default (the file is still downloadable, but unreadable without the passphrase). For a database that is never served at all, keep it in a second, **private** bucket (no public-read, no website hosting; same CORS rules) as the data location:
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
"data": {
|
|
73
|
+
"backend": "sqlite-file",
|
|
74
|
+
"path": "site.sqlite",
|
|
75
|
+
"location": { "type": "s3", "settings": { "endpoint": "<endpoint>", "region": "<region>", "bucket": "<private-bucket>" }, "credential": "s3:<name>" }
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Create it like the site bucket but skip the website / public-read steps: `aws --endpoint-url <endpoint> s3api create-bucket --bucket <private-bucket>` (plus `put-bucket-cors` with the admin origins).
|
|
80
|
+
|
|
81
|
+
With Markdown content and an S3 hosting, the browser needs the bucket keys once to publish: admin -> Settings -> Publish target.
|