@cimplify/cli 0.2.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/README.md +69 -0
- package/dist/add-ZJQJZJEF.mjs +125 -0
- package/dist/chunk-4YSOZ6LY.mjs +61 -0
- package/dist/chunk-4ZVTPMUZ.mjs +155 -0
- package/dist/chunk-5XH72JMJ.mjs +211 -0
- package/dist/chunk-D7D75ONX.mjs +36 -0
- package/dist/chunk-JJYWETGA.mjs +127 -0
- package/dist/chunk-L6474RPL.mjs +37 -0
- package/dist/chunk-MQMNWLMU.mjs +48 -0
- package/dist/chunk-NZ4RG62Z.mjs +141 -0
- package/dist/chunk-TAMGCHIL.mjs +81 -0
- package/dist/chunk-XSWWWO6H.mjs +3779 -0
- package/dist/deploy-WCZOGMED.mjs +206 -0
- package/dist/dev-4HKIXWXX.mjs +130 -0
- package/dist/dispatcher.mjs +321 -0
- package/dist/domains-3RJ4T5IX.mjs +387 -0
- package/dist/env-LBYBCBWV.mjs +268 -0
- package/dist/link-SEJNW7JS.mjs +45 -0
- package/dist/list-D4JC2VWY.mjs +48 -0
- package/dist/login-MRYWLQRY.mjs +276 -0
- package/dist/logout-ZFZLSJ32.mjs +16 -0
- package/dist/logs-LK7CMBCE.mjs +95 -0
- package/dist/projects-QJUGOCQZ.mjs +164 -0
- package/dist/repo-MV22OHON.mjs +8 -0
- package/dist/rollback-XO7RIG2A.mjs +107 -0
- package/dist/status-7CMVLD54.mjs +127 -0
- package/dist/unlink-5ABCT7B6.mjs +16 -0
- package/dist/whoami-INHDUHWA.mjs +24 -0
- package/package.json +44 -0
- package/templates/storefront-bakery/.claude/skills/cimplify-storefront/SKILL.md +145 -0
- package/templates/storefront-bakery/.cursor/rules/cimplify-storefront.mdc +25 -0
- package/templates/storefront-bakery/.env.example +16 -0
- package/templates/storefront-bakery/AGENTS.md +120 -0
- package/templates/storefront-bakery/CLAUDE.md +22 -0
- package/templates/storefront-bakery/README.md +73 -0
- package/templates/storefront-bakery/__tests__/brand.test.ts +4 -0
- package/templates/storefront-bakery/__tests__/cart-flow.test.ts +4 -0
- package/templates/storefront-bakery/__tests__/contract.test.ts +4 -0
- package/templates/storefront-bakery/app/about/page.tsx +38 -0
- package/templates/storefront-bakery/app/accessibility/page.tsx +11 -0
- package/templates/storefront-bakery/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-bakery/app/account/orders/page.tsx +21 -0
- package/templates/storefront-bakery/app/account/page.tsx +22 -0
- package/templates/storefront-bakery/app/account/settings/page.tsx +21 -0
- package/templates/storefront-bakery/app/cart/page.tsx +9 -0
- package/templates/storefront-bakery/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-bakery/app/categories/[slug]/page.tsx +118 -0
- package/templates/storefront-bakery/app/checkout/page.tsx +17 -0
- package/templates/storefront-bakery/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-bakery/app/collections/[slug]/page.tsx +118 -0
- package/templates/storefront-bakery/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-bakery/app/contact/page.tsx +54 -0
- package/templates/storefront-bakery/app/error.tsx +60 -0
- package/templates/storefront-bakery/app/faq/page.tsx +46 -0
- package/templates/storefront-bakery/app/globals.css +47 -0
- package/templates/storefront-bakery/app/layout.tsx +82 -0
- package/templates/storefront-bakery/app/llms.txt/route.ts +94 -0
- package/templates/storefront-bakery/app/login/page.tsx +17 -0
- package/templates/storefront-bakery/app/not-found.tsx +39 -0
- package/templates/storefront-bakery/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-bakery/app/orders/[id]/page.tsx +21 -0
- package/templates/storefront-bakery/app/page.tsx +97 -0
- package/templates/storefront-bakery/app/privacy/page.tsx +44 -0
- package/templates/storefront-bakery/app/returns/page.tsx +11 -0
- package/templates/storefront-bakery/app/robots.ts +18 -0
- package/templates/storefront-bakery/app/search/page.tsx +38 -0
- package/templates/storefront-bakery/app/search/search-client.tsx +7 -0
- package/templates/storefront-bakery/app/shipping/page.tsx +16 -0
- package/templates/storefront-bakery/app/shop/page.tsx +31 -0
- package/templates/storefront-bakery/app/shop/shop-client.tsx +27 -0
- package/templates/storefront-bakery/app/signup/page.tsx +17 -0
- package/templates/storefront-bakery/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-bakery/app/sitemap.ts +62 -0
- package/templates/storefront-bakery/app/terms/page.tsx +44 -0
- package/templates/storefront-bakery/app/track-order/page.tsx +24 -0
- package/templates/storefront-bakery/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-bakery/components/account-iframe.tsx +13 -0
- package/templates/storefront-bakery/components/cart-drawer.tsx +14 -0
- package/templates/storefront-bakery/components/cart-pill.tsx +36 -0
- package/templates/storefront-bakery/components/category-grid.tsx +28 -0
- package/templates/storefront-bakery/components/collection-strip.tsx +45 -0
- package/templates/storefront-bakery/components/footer.tsx +148 -0
- package/templates/storefront-bakery/components/header.tsx +43 -0
- package/templates/storefront-bakery/components/hero.tsx +25 -0
- package/templates/storefront-bakery/components/nav-link.tsx +20 -0
- package/templates/storefront-bakery/components/policy-page.tsx +49 -0
- package/templates/storefront-bakery/components/product-modal.tsx +104 -0
- package/templates/storefront-bakery/components/providers.tsx +35 -0
- package/templates/storefront-bakery/components/store-product-card.tsx +87 -0
- package/templates/storefront-bakery/lib/brand.ts +570 -0
- package/templates/storefront-bakery/lib/cart.ts +12 -0
- package/templates/storefront-bakery/next.config.ts +42 -0
- package/templates/storefront-bakery/package.json +35 -0
- package/templates/storefront-bakery/postcss.config.mjs +7 -0
- package/templates/storefront-bakery/tsconfig.json +23 -0
- package/templates/storefront-bakery/vitest.config.ts +9 -0
- package/templates/storefront-fashion/.claude/skills/cimplify-storefront/SKILL.md +145 -0
- package/templates/storefront-fashion/.cursor/rules/cimplify-storefront.mdc +25 -0
- package/templates/storefront-fashion/.env.example +16 -0
- package/templates/storefront-fashion/AGENTS.md +126 -0
- package/templates/storefront-fashion/CLAUDE.md +22 -0
- package/templates/storefront-fashion/README.md +77 -0
- package/templates/storefront-fashion/__tests__/brand.test.ts +4 -0
- package/templates/storefront-fashion/__tests__/cart-flow.test.ts +55 -0
- package/templates/storefront-fashion/__tests__/contract.test.ts +4 -0
- package/templates/storefront-fashion/app/about/page.tsx +41 -0
- package/templates/storefront-fashion/app/accessibility/page.tsx +11 -0
- package/templates/storefront-fashion/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-fashion/app/account/orders/page.tsx +21 -0
- package/templates/storefront-fashion/app/account/page.tsx +22 -0
- package/templates/storefront-fashion/app/account/settings/page.tsx +21 -0
- package/templates/storefront-fashion/app/cart/page.tsx +9 -0
- package/templates/storefront-fashion/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-fashion/app/categories/[slug]/page.tsx +130 -0
- package/templates/storefront-fashion/app/checkout/page.tsx +17 -0
- package/templates/storefront-fashion/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-fashion/app/collections/[slug]/page.tsx +130 -0
- package/templates/storefront-fashion/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-fashion/app/contact/page.tsx +54 -0
- package/templates/storefront-fashion/app/error.tsx +61 -0
- package/templates/storefront-fashion/app/faq/page.tsx +46 -0
- package/templates/storefront-fashion/app/globals.css +46 -0
- package/templates/storefront-fashion/app/layout.tsx +78 -0
- package/templates/storefront-fashion/app/llms.txt/route.ts +94 -0
- package/templates/storefront-fashion/app/login/page.tsx +17 -0
- package/templates/storefront-fashion/app/lookbook/page.tsx +132 -0
- package/templates/storefront-fashion/app/not-found.tsx +39 -0
- package/templates/storefront-fashion/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-fashion/app/orders/[id]/page.tsx +24 -0
- package/templates/storefront-fashion/app/page.tsx +183 -0
- package/templates/storefront-fashion/app/privacy/page.tsx +44 -0
- package/templates/storefront-fashion/app/products/[slug]/page.tsx +165 -0
- package/templates/storefront-fashion/app/products/[slug]/product-detail.tsx +70 -0
- package/templates/storefront-fashion/app/returns/page.tsx +11 -0
- package/templates/storefront-fashion/app/robots.ts +18 -0
- package/templates/storefront-fashion/app/search/page.tsx +38 -0
- package/templates/storefront-fashion/app/search/search-client.tsx +7 -0
- package/templates/storefront-fashion/app/shipping/page.tsx +16 -0
- package/templates/storefront-fashion/app/shop/page.tsx +63 -0
- package/templates/storefront-fashion/app/shop/shop-client.tsx +32 -0
- package/templates/storefront-fashion/app/signup/page.tsx +17 -0
- package/templates/storefront-fashion/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-fashion/app/sitemap.ts +59 -0
- package/templates/storefront-fashion/app/size-guide/page.tsx +155 -0
- package/templates/storefront-fashion/app/terms/page.tsx +44 -0
- package/templates/storefront-fashion/app/track-order/page.tsx +24 -0
- package/templates/storefront-fashion/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-fashion/components/account-iframe.tsx +13 -0
- package/templates/storefront-fashion/components/brand-marquee.tsx +27 -0
- package/templates/storefront-fashion/components/cart-drawer.tsx +14 -0
- package/templates/storefront-fashion/components/cart-pill.tsx +36 -0
- package/templates/storefront-fashion/components/category-grid.tsx +28 -0
- package/templates/storefront-fashion/components/category-tiles.tsx +104 -0
- package/templates/storefront-fashion/components/collection-strip.tsx +45 -0
- package/templates/storefront-fashion/components/feature-hero.tsx +82 -0
- package/templates/storefront-fashion/components/footer.tsx +153 -0
- package/templates/storefront-fashion/components/header.tsx +43 -0
- package/templates/storefront-fashion/components/hero.tsx +28 -0
- package/templates/storefront-fashion/components/nav-link.tsx +20 -0
- package/templates/storefront-fashion/components/newsletter.tsx +50 -0
- package/templates/storefront-fashion/components/policy-page.tsx +49 -0
- package/templates/storefront-fashion/components/promo-banner.tsx +41 -0
- package/templates/storefront-fashion/components/providers.tsx +35 -0
- package/templates/storefront-fashion/components/section-heading.tsx +37 -0
- package/templates/storefront-fashion/components/store-product-card.tsx +87 -0
- package/templates/storefront-fashion/components/trade-in-cta.tsx +54 -0
- package/templates/storefront-fashion/components/trust-bar.tsx +66 -0
- package/templates/storefront-fashion/e2e/visual.spec.ts +52 -0
- package/templates/storefront-fashion/lib/brand.ts +518 -0
- package/templates/storefront-fashion/lib/cart.ts +12 -0
- package/templates/storefront-fashion/next.config.ts +42 -0
- package/templates/storefront-fashion/package.json +38 -0
- package/templates/storefront-fashion/playwright.config.ts +48 -0
- package/templates/storefront-fashion/postcss.config.mjs +7 -0
- package/templates/storefront-fashion/tsconfig.json +23 -0
- package/templates/storefront-fashion/vitest.config.ts +9 -0
- package/templates/storefront-grocery/.claude/skills/cimplify-storefront/SKILL.md +145 -0
- package/templates/storefront-grocery/.cursor/rules/cimplify-storefront.mdc +25 -0
- package/templates/storefront-grocery/.env.example +16 -0
- package/templates/storefront-grocery/AGENTS.md +96 -0
- package/templates/storefront-grocery/CLAUDE.md +22 -0
- package/templates/storefront-grocery/README.md +73 -0
- package/templates/storefront-grocery/__tests__/brand.test.ts +4 -0
- package/templates/storefront-grocery/__tests__/cart-flow.test.ts +4 -0
- package/templates/storefront-grocery/__tests__/contract.test.ts +4 -0
- package/templates/storefront-grocery/app/about/page.tsx +38 -0
- package/templates/storefront-grocery/app/accessibility/page.tsx +11 -0
- package/templates/storefront-grocery/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-grocery/app/account/orders/page.tsx +21 -0
- package/templates/storefront-grocery/app/account/page.tsx +22 -0
- package/templates/storefront-grocery/app/account/settings/page.tsx +21 -0
- package/templates/storefront-grocery/app/cart/page.tsx +9 -0
- package/templates/storefront-grocery/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-grocery/app/categories/[slug]/page.tsx +118 -0
- package/templates/storefront-grocery/app/checkout/page.tsx +17 -0
- package/templates/storefront-grocery/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-grocery/app/collections/[slug]/page.tsx +118 -0
- package/templates/storefront-grocery/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-grocery/app/contact/page.tsx +54 -0
- package/templates/storefront-grocery/app/error.tsx +60 -0
- package/templates/storefront-grocery/app/faq/page.tsx +46 -0
- package/templates/storefront-grocery/app/globals.css +45 -0
- package/templates/storefront-grocery/app/layout.tsx +77 -0
- package/templates/storefront-grocery/app/llms.txt/route.ts +94 -0
- package/templates/storefront-grocery/app/login/page.tsx +17 -0
- package/templates/storefront-grocery/app/not-found.tsx +39 -0
- package/templates/storefront-grocery/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-grocery/app/orders/[id]/page.tsx +21 -0
- package/templates/storefront-grocery/app/page.tsx +97 -0
- package/templates/storefront-grocery/app/privacy/page.tsx +44 -0
- package/templates/storefront-grocery/app/returns/page.tsx +11 -0
- package/templates/storefront-grocery/app/robots.ts +18 -0
- package/templates/storefront-grocery/app/search/page.tsx +38 -0
- package/templates/storefront-grocery/app/search/search-client.tsx +7 -0
- package/templates/storefront-grocery/app/shipping/page.tsx +16 -0
- package/templates/storefront-grocery/app/shop/page.tsx +31 -0
- package/templates/storefront-grocery/app/shop/shop-client.tsx +27 -0
- package/templates/storefront-grocery/app/signup/page.tsx +17 -0
- package/templates/storefront-grocery/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-grocery/app/sitemap.ts +62 -0
- package/templates/storefront-grocery/app/terms/page.tsx +44 -0
- package/templates/storefront-grocery/app/track-order/page.tsx +24 -0
- package/templates/storefront-grocery/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-grocery/components/account-iframe.tsx +13 -0
- package/templates/storefront-grocery/components/cart-drawer.tsx +14 -0
- package/templates/storefront-grocery/components/cart-pill.tsx +36 -0
- package/templates/storefront-grocery/components/category-grid.tsx +28 -0
- package/templates/storefront-grocery/components/collection-strip.tsx +45 -0
- package/templates/storefront-grocery/components/footer.tsx +148 -0
- package/templates/storefront-grocery/components/header.tsx +43 -0
- package/templates/storefront-grocery/components/hero.tsx +25 -0
- package/templates/storefront-grocery/components/nav-link.tsx +20 -0
- package/templates/storefront-grocery/components/policy-page.tsx +49 -0
- package/templates/storefront-grocery/components/product-modal.tsx +104 -0
- package/templates/storefront-grocery/components/providers.tsx +35 -0
- package/templates/storefront-grocery/components/store-product-card.tsx +87 -0
- package/templates/storefront-grocery/lib/brand.ts +375 -0
- package/templates/storefront-grocery/lib/cart.ts +12 -0
- package/templates/storefront-grocery/next.config.ts +42 -0
- package/templates/storefront-grocery/package.json +35 -0
- package/templates/storefront-grocery/postcss.config.mjs +7 -0
- package/templates/storefront-grocery/tsconfig.json +23 -0
- package/templates/storefront-grocery/vitest.config.ts +9 -0
- package/templates/storefront-restaurant/.claude/skills/cimplify-storefront/SKILL.md +145 -0
- package/templates/storefront-restaurant/.cursor/rules/cimplify-storefront.mdc +25 -0
- package/templates/storefront-restaurant/.env.example +16 -0
- package/templates/storefront-restaurant/AGENTS.md +102 -0
- package/templates/storefront-restaurant/CLAUDE.md +22 -0
- package/templates/storefront-restaurant/README.md +73 -0
- package/templates/storefront-restaurant/__tests__/brand.test.ts +4 -0
- package/templates/storefront-restaurant/__tests__/cart-flow.test.ts +4 -0
- package/templates/storefront-restaurant/__tests__/contract.test.ts +4 -0
- package/templates/storefront-restaurant/app/about/page.tsx +38 -0
- package/templates/storefront-restaurant/app/accessibility/page.tsx +11 -0
- package/templates/storefront-restaurant/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-restaurant/app/account/orders/page.tsx +21 -0
- package/templates/storefront-restaurant/app/account/page.tsx +22 -0
- package/templates/storefront-restaurant/app/account/settings/page.tsx +21 -0
- package/templates/storefront-restaurant/app/cart/page.tsx +9 -0
- package/templates/storefront-restaurant/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-restaurant/app/categories/[slug]/page.tsx +118 -0
- package/templates/storefront-restaurant/app/checkout/page.tsx +17 -0
- package/templates/storefront-restaurant/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-restaurant/app/collections/[slug]/page.tsx +118 -0
- package/templates/storefront-restaurant/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-restaurant/app/contact/page.tsx +54 -0
- package/templates/storefront-restaurant/app/error.tsx +60 -0
- package/templates/storefront-restaurant/app/faq/page.tsx +46 -0
- package/templates/storefront-restaurant/app/globals.css +44 -0
- package/templates/storefront-restaurant/app/layout.tsx +82 -0
- package/templates/storefront-restaurant/app/llms.txt/route.ts +94 -0
- package/templates/storefront-restaurant/app/login/page.tsx +17 -0
- package/templates/storefront-restaurant/app/not-found.tsx +39 -0
- package/templates/storefront-restaurant/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-restaurant/app/orders/[id]/page.tsx +21 -0
- package/templates/storefront-restaurant/app/page.tsx +97 -0
- package/templates/storefront-restaurant/app/privacy/page.tsx +44 -0
- package/templates/storefront-restaurant/app/reservations/page.tsx +66 -0
- package/templates/storefront-restaurant/app/reservations/reservations-client.tsx +234 -0
- package/templates/storefront-restaurant/app/returns/page.tsx +11 -0
- package/templates/storefront-restaurant/app/robots.ts +18 -0
- package/templates/storefront-restaurant/app/search/page.tsx +38 -0
- package/templates/storefront-restaurant/app/search/search-client.tsx +7 -0
- package/templates/storefront-restaurant/app/shipping/page.tsx +16 -0
- package/templates/storefront-restaurant/app/shop/page.tsx +31 -0
- package/templates/storefront-restaurant/app/shop/shop-client.tsx +27 -0
- package/templates/storefront-restaurant/app/signup/page.tsx +17 -0
- package/templates/storefront-restaurant/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-restaurant/app/sitemap.ts +62 -0
- package/templates/storefront-restaurant/app/terms/page.tsx +44 -0
- package/templates/storefront-restaurant/app/track-order/page.tsx +24 -0
- package/templates/storefront-restaurant/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-restaurant/components/account-iframe.tsx +13 -0
- package/templates/storefront-restaurant/components/cart-drawer.tsx +14 -0
- package/templates/storefront-restaurant/components/cart-pill.tsx +36 -0
- package/templates/storefront-restaurant/components/category-grid.tsx +28 -0
- package/templates/storefront-restaurant/components/collection-strip.tsx +45 -0
- package/templates/storefront-restaurant/components/footer.tsx +148 -0
- package/templates/storefront-restaurant/components/header.tsx +43 -0
- package/templates/storefront-restaurant/components/hero.tsx +25 -0
- package/templates/storefront-restaurant/components/nav-link.tsx +20 -0
- package/templates/storefront-restaurant/components/policy-page.tsx +49 -0
- package/templates/storefront-restaurant/components/product-modal.tsx +104 -0
- package/templates/storefront-restaurant/components/providers.tsx +35 -0
- package/templates/storefront-restaurant/components/store-product-card.tsx +87 -0
- package/templates/storefront-restaurant/lib/brand.ts +377 -0
- package/templates/storefront-restaurant/lib/cart.ts +12 -0
- package/templates/storefront-restaurant/next.config.ts +42 -0
- package/templates/storefront-restaurant/package.json +35 -0
- package/templates/storefront-restaurant/postcss.config.mjs +7 -0
- package/templates/storefront-restaurant/tsconfig.json +23 -0
- package/templates/storefront-restaurant/vitest.config.ts +9 -0
- package/templates/storefront-retail/.claude/skills/cimplify-storefront/SKILL.md +145 -0
- package/templates/storefront-retail/.cursor/rules/cimplify-storefront.mdc +25 -0
- package/templates/storefront-retail/.env.example +16 -0
- package/templates/storefront-retail/AGENTS.md +117 -0
- package/templates/storefront-retail/CLAUDE.md +22 -0
- package/templates/storefront-retail/README.md +77 -0
- package/templates/storefront-retail/__tests__/brand.test.ts +4 -0
- package/templates/storefront-retail/__tests__/cart-flow.test.ts +4 -0
- package/templates/storefront-retail/__tests__/contract.test.ts +4 -0
- package/templates/storefront-retail/app/about/page.tsx +41 -0
- package/templates/storefront-retail/app/accessibility/page.tsx +11 -0
- package/templates/storefront-retail/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-retail/app/account/orders/page.tsx +21 -0
- package/templates/storefront-retail/app/account/page.tsx +22 -0
- package/templates/storefront-retail/app/account/settings/page.tsx +21 -0
- package/templates/storefront-retail/app/cart/page.tsx +9 -0
- package/templates/storefront-retail/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-retail/app/categories/[slug]/page.tsx +130 -0
- package/templates/storefront-retail/app/checkout/page.tsx +17 -0
- package/templates/storefront-retail/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-retail/app/collections/[slug]/page.tsx +130 -0
- package/templates/storefront-retail/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-retail/app/contact/page.tsx +54 -0
- package/templates/storefront-retail/app/error.tsx +61 -0
- package/templates/storefront-retail/app/faq/page.tsx +46 -0
- package/templates/storefront-retail/app/globals.css +47 -0
- package/templates/storefront-retail/app/layout.tsx +77 -0
- package/templates/storefront-retail/app/llms.txt/route.ts +94 -0
- package/templates/storefront-retail/app/login/page.tsx +17 -0
- package/templates/storefront-retail/app/not-found.tsx +39 -0
- package/templates/storefront-retail/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-retail/app/orders/[id]/page.tsx +24 -0
- package/templates/storefront-retail/app/page.tsx +182 -0
- package/templates/storefront-retail/app/privacy/page.tsx +44 -0
- package/templates/storefront-retail/app/products/[slug]/page.tsx +165 -0
- package/templates/storefront-retail/app/products/[slug]/product-detail.tsx +70 -0
- package/templates/storefront-retail/app/returns/page.tsx +11 -0
- package/templates/storefront-retail/app/robots.ts +18 -0
- package/templates/storefront-retail/app/search/page.tsx +38 -0
- package/templates/storefront-retail/app/search/search-client.tsx +7 -0
- package/templates/storefront-retail/app/shipping/page.tsx +16 -0
- package/templates/storefront-retail/app/shop/page.tsx +63 -0
- package/templates/storefront-retail/app/shop/shop-client.tsx +32 -0
- package/templates/storefront-retail/app/signup/page.tsx +17 -0
- package/templates/storefront-retail/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-retail/app/sitemap.ts +59 -0
- package/templates/storefront-retail/app/terms/page.tsx +44 -0
- package/templates/storefront-retail/app/track-order/page.tsx +24 -0
- package/templates/storefront-retail/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-retail/components/account-iframe.tsx +13 -0
- package/templates/storefront-retail/components/brand-marquee.tsx +27 -0
- package/templates/storefront-retail/components/cart-drawer.tsx +14 -0
- package/templates/storefront-retail/components/cart-pill.tsx +36 -0
- package/templates/storefront-retail/components/category-grid.tsx +28 -0
- package/templates/storefront-retail/components/category-tiles.tsx +104 -0
- package/templates/storefront-retail/components/collection-strip.tsx +45 -0
- package/templates/storefront-retail/components/feature-hero.tsx +84 -0
- package/templates/storefront-retail/components/footer.tsx +153 -0
- package/templates/storefront-retail/components/header.tsx +45 -0
- package/templates/storefront-retail/components/hero.tsx +28 -0
- package/templates/storefront-retail/components/nav-link.tsx +20 -0
- package/templates/storefront-retail/components/newsletter.tsx +50 -0
- package/templates/storefront-retail/components/policy-page.tsx +49 -0
- package/templates/storefront-retail/components/promo-banner.tsx +41 -0
- package/templates/storefront-retail/components/providers.tsx +35 -0
- package/templates/storefront-retail/components/section-heading.tsx +37 -0
- package/templates/storefront-retail/components/store-product-card.tsx +87 -0
- package/templates/storefront-retail/components/trade-in-cta.tsx +54 -0
- package/templates/storefront-retail/components/trust-bar.tsx +66 -0
- package/templates/storefront-retail/lib/brand.ts +664 -0
- package/templates/storefront-retail/lib/cart.ts +12 -0
- package/templates/storefront-retail/next.config.ts +42 -0
- package/templates/storefront-retail/package.json +35 -0
- package/templates/storefront-retail/postcss.config.mjs +7 -0
- package/templates/storefront-retail/tsconfig.json +23 -0
- package/templates/storefront-retail/vitest.config.ts +9 -0
- package/templates/storefront-services/.claude/skills/cimplify-storefront/SKILL.md +145 -0
- package/templates/storefront-services/.cursor/rules/cimplify-storefront.mdc +25 -0
- package/templates/storefront-services/.env.example +16 -0
- package/templates/storefront-services/AGENTS.md +101 -0
- package/templates/storefront-services/CLAUDE.md +22 -0
- package/templates/storefront-services/README.md +73 -0
- package/templates/storefront-services/__tests__/brand.test.ts +4 -0
- package/templates/storefront-services/__tests__/cart-flow.test.ts +4 -0
- package/templates/storefront-services/__tests__/contract.test.ts +4 -0
- package/templates/storefront-services/app/about/page.tsx +38 -0
- package/templates/storefront-services/app/accessibility/page.tsx +11 -0
- package/templates/storefront-services/app/account/addresses/page.tsx +21 -0
- package/templates/storefront-services/app/account/orders/page.tsx +21 -0
- package/templates/storefront-services/app/account/page.tsx +22 -0
- package/templates/storefront-services/app/account/settings/page.tsx +21 -0
- package/templates/storefront-services/app/book/book-client.tsx +195 -0
- package/templates/storefront-services/app/book/page.tsx +65 -0
- package/templates/storefront-services/app/cart/page.tsx +9 -0
- package/templates/storefront-services/app/categories/[slug]/listing-client.tsx +19 -0
- package/templates/storefront-services/app/categories/[slug]/page.tsx +118 -0
- package/templates/storefront-services/app/checkout/page.tsx +17 -0
- package/templates/storefront-services/app/collections/[slug]/listing-client.tsx +20 -0
- package/templates/storefront-services/app/collections/[slug]/page.tsx +118 -0
- package/templates/storefront-services/app/contact/contact-form.tsx +109 -0
- package/templates/storefront-services/app/contact/page.tsx +54 -0
- package/templates/storefront-services/app/error.tsx +60 -0
- package/templates/storefront-services/app/faq/page.tsx +46 -0
- package/templates/storefront-services/app/globals.css +45 -0
- package/templates/storefront-services/app/layout.tsx +82 -0
- package/templates/storefront-services/app/llms.txt/route.ts +94 -0
- package/templates/storefront-services/app/login/page.tsx +17 -0
- package/templates/storefront-services/app/not-found.tsx +39 -0
- package/templates/storefront-services/app/opensearch.xml/route.ts +37 -0
- package/templates/storefront-services/app/orders/[id]/page.tsx +21 -0
- package/templates/storefront-services/app/page.tsx +97 -0
- package/templates/storefront-services/app/privacy/page.tsx +44 -0
- package/templates/storefront-services/app/returns/page.tsx +11 -0
- package/templates/storefront-services/app/robots.ts +18 -0
- package/templates/storefront-services/app/search/page.tsx +38 -0
- package/templates/storefront-services/app/search/search-client.tsx +7 -0
- package/templates/storefront-services/app/shipping/page.tsx +16 -0
- package/templates/storefront-services/app/shop/page.tsx +31 -0
- package/templates/storefront-services/app/shop/shop-client.tsx +27 -0
- package/templates/storefront-services/app/signup/page.tsx +17 -0
- package/templates/storefront-services/app/sitemap-page/page.tsx +167 -0
- package/templates/storefront-services/app/sitemap.ts +62 -0
- package/templates/storefront-services/app/terms/page.tsx +44 -0
- package/templates/storefront-services/app/track-order/page.tsx +24 -0
- package/templates/storefront-services/app/track-order/track-order-form.tsx +69 -0
- package/templates/storefront-services/components/account-iframe.tsx +13 -0
- package/templates/storefront-services/components/cart-drawer.tsx +14 -0
- package/templates/storefront-services/components/cart-pill.tsx +36 -0
- package/templates/storefront-services/components/category-grid.tsx +28 -0
- package/templates/storefront-services/components/collection-strip.tsx +45 -0
- package/templates/storefront-services/components/footer.tsx +148 -0
- package/templates/storefront-services/components/header.tsx +43 -0
- package/templates/storefront-services/components/hero.tsx +25 -0
- package/templates/storefront-services/components/nav-link.tsx +20 -0
- package/templates/storefront-services/components/policy-page.tsx +49 -0
- package/templates/storefront-services/components/product-modal.tsx +104 -0
- package/templates/storefront-services/components/providers.tsx +35 -0
- package/templates/storefront-services/components/store-product-card.tsx +87 -0
- package/templates/storefront-services/lib/brand.ts +396 -0
- package/templates/storefront-services/lib/cart.ts +12 -0
- package/templates/storefront-services/next.config.ts +42 -0
- package/templates/storefront-services/package.json +35 -0
- package/templates/storefront-services/postcss.config.mjs +7 -0
- package/templates/storefront-services/tsconfig.json +23 -0
- package/templates/storefront-services/vitest.config.ts +9 -0
package/README.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# @cimplify/cli
|
|
2
|
+
|
|
3
|
+
The Cimplify command-line tool. Deploy from your terminal, manage env vars, attach domains, scaffold storefronts.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
curl -fsSL https://cimplify.io/install | sh
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Detects your OS + arch, downloads the matching binary from the latest GitHub release, verifies its sha256, and drops it in `~/.local/bin/cimplify`. ~20 ms cold start. The binary bundles every storefront template and the full component registry — `init`, `add`, and `list` work without a separate `@cimplify/sdk` install.
|
|
12
|
+
|
|
13
|
+
Override the destination with `--prefix`, pin a version with `--version cli-v0.1.0`, or skip the install entirely with `bunx @cimplify/cli <command>`.
|
|
14
|
+
|
|
15
|
+
## What you can do
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
cimplify init my-store --template restaurant # scaffold a working storefront
|
|
19
|
+
cimplify login # browser PKCE flow (or --api-key for CI)
|
|
20
|
+
cimplify projects create my-store # create a Cimplify project + Freestyle repo
|
|
21
|
+
cimplify link <project-id> # bind the current directory to a project
|
|
22
|
+
cimplify deploy [--prod] # push HEAD + build + deploy
|
|
23
|
+
cimplify logs --follow # stream build logs
|
|
24
|
+
cimplify rollback <deploy-id> # re-deploy a previous SHA
|
|
25
|
+
cimplify env push # upload .env.local to the linked project
|
|
26
|
+
cimplify domains add shop.example.com # add a custom domain (prints DNS records)
|
|
27
|
+
cimplify status # latest deployment summary
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`cimplify --help` lists every subcommand and flag.
|
|
31
|
+
|
|
32
|
+
## Conventions
|
|
33
|
+
|
|
34
|
+
- **Project link:** `cimplify link <project-id>` writes `.cimplify/project.json` in the working directory. Subsequent commands read it to know which project to act on — no `--project` flag needed for the common case.
|
|
35
|
+
- **Auth:** credentials persist at `~/.config/cimplify/auth.json`. CI uses `--api-key dk_live_…` to skip the browser.
|
|
36
|
+
- **JSON mode:** pass `--json` (or set `CIMPLIFY_JSON=1`) for `{ ok, data | error }` machine-readable output on stdout.
|
|
37
|
+
- **Yes/no prompts:** pass `--yes` (or `-y`) to auto-confirm.
|
|
38
|
+
|
|
39
|
+
## How it talks to Cimplify
|
|
40
|
+
|
|
41
|
+
Every cloud command is a thin HTTP client over `https://api.cimplify.io` (override with `CIMPLIFY_API_URL`). The deploy flow specifically:
|
|
42
|
+
|
|
43
|
+
1. `git push` to the project's git remote (uses a short-TTL token minted by Cimplify when the remote is Freestyle-hosted; falls back to your existing git auth otherwise).
|
|
44
|
+
2. `POST /v1/businesses/<bid>/projects/<pid>/deploy` with the local SHA.
|
|
45
|
+
3. Poll `/deployments/<id>/progress` every 1 second, printing log chunks as they arrive.
|
|
46
|
+
4. Exit 0 on `active`, 2 on `superseded`, 1 on `failed` / `cancelled`.
|
|
47
|
+
|
|
48
|
+
## Storefront templates
|
|
49
|
+
|
|
50
|
+
`cimplify init` ships with six designs out of the box:
|
|
51
|
+
|
|
52
|
+
| Template | Use case |
|
|
53
|
+
|---|---|
|
|
54
|
+
| `bakery` (default) | Warm food-style storefront |
|
|
55
|
+
| `restaurant` | Menu + ordering UI |
|
|
56
|
+
| `retail` | Product-grid retail |
|
|
57
|
+
| `services` | Booking-style storefront |
|
|
58
|
+
| `grocery` | Catalogue-heavy grocery layout |
|
|
59
|
+
| `fashion` | Editorial fashion layout |
|
|
60
|
+
|
|
61
|
+
Each is a full Next.js project wired to `@cimplify/sdk` with the design system pre-applied.
|
|
62
|
+
|
|
63
|
+
## Related
|
|
64
|
+
|
|
65
|
+
- [`@cimplify/sdk`](../sdk/README.md) — the runtime SDK + storefront components scaffolded by `cimplify init`.
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
MIT.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { REGISTRY_INDEX, REGISTRY } from './chunk-XSWWWO6H.mjs';
|
|
3
|
+
import { promptYesNo } from './chunk-L6474RPL.mjs';
|
|
4
|
+
import { parseArgs, flagString, flagBool } from './chunk-D7D75ONX.mjs';
|
|
5
|
+
import { CliError, CLI_ERROR_CODE, info, bold, dim, success, result, yellow } from './chunk-NZ4RG62Z.mjs';
|
|
6
|
+
import { mkdirSync, existsSync, writeFileSync } from 'fs';
|
|
7
|
+
import { resolve, join, dirname } from 'path';
|
|
8
|
+
|
|
9
|
+
var DEFAULT_TARGET_DIR = "src/components/cimplify";
|
|
10
|
+
function loadIndex() {
|
|
11
|
+
const index = REGISTRY_INDEX;
|
|
12
|
+
if (!index || !Array.isArray(index.components)) {
|
|
13
|
+
throw new CliError(
|
|
14
|
+
CLI_ERROR_CODE.NOT_FOUND,
|
|
15
|
+
"Embedded SDK component registry is empty.",
|
|
16
|
+
{
|
|
17
|
+
remediation: "Rebuild the CLI with the SDK present: `cd packages/sdk && bun run build && cd ../cli && bun run build`."
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
return index;
|
|
22
|
+
}
|
|
23
|
+
function loadComponent(name) {
|
|
24
|
+
const entry = REGISTRY[name];
|
|
25
|
+
if (!entry) {
|
|
26
|
+
const known = new Set(loadIndex().components.map((c) => c.name));
|
|
27
|
+
const remediation = known.has(name) ? "The CLI bundle is missing this component's payload \u2014 rebuild via `bun run build`." : "Run `cimplify list` to see available components.";
|
|
28
|
+
throw new CliError(
|
|
29
|
+
CLI_ERROR_CODE.NOT_FOUND,
|
|
30
|
+
`Component "${name}" is not in the registry.`,
|
|
31
|
+
{ remediation }
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
return entry;
|
|
35
|
+
}
|
|
36
|
+
async function writeComponent(component, options) {
|
|
37
|
+
const outcome = {
|
|
38
|
+
component: component.name,
|
|
39
|
+
written: [],
|
|
40
|
+
skipped: []
|
|
41
|
+
};
|
|
42
|
+
mkdirSync(options.targetDir, { recursive: true });
|
|
43
|
+
for (const file of component.files) {
|
|
44
|
+
const targetPath = join(options.targetDir, file.path);
|
|
45
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
46
|
+
if (existsSync(targetPath) && !options.force) {
|
|
47
|
+
info(` ${yellow("skip")} ${file.path} ${dim("(exists; pass --force to overwrite)")}`);
|
|
48
|
+
outcome.skipped.push(file.path);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
writeFileSync(targetPath, file.content);
|
|
52
|
+
info(` ${dim("wrote")} ${file.path}`);
|
|
53
|
+
outcome.written.push(file.path);
|
|
54
|
+
}
|
|
55
|
+
return outcome;
|
|
56
|
+
}
|
|
57
|
+
function resolveDependencyOrder(roots) {
|
|
58
|
+
const visited = /* @__PURE__ */ new Set();
|
|
59
|
+
const order = [];
|
|
60
|
+
function visit(name) {
|
|
61
|
+
if (visited.has(name)) return;
|
|
62
|
+
visited.add(name);
|
|
63
|
+
const component = loadComponent(name);
|
|
64
|
+
for (const dep of component.registryDependencies) {
|
|
65
|
+
visit(dep);
|
|
66
|
+
}
|
|
67
|
+
order.push(name);
|
|
68
|
+
}
|
|
69
|
+
for (const root of roots) visit(root);
|
|
70
|
+
return order;
|
|
71
|
+
}
|
|
72
|
+
async function run(argv) {
|
|
73
|
+
const args = parseArgs(argv);
|
|
74
|
+
const dirFlag = flagString(args, "dir");
|
|
75
|
+
const force = flagBool(args, "force");
|
|
76
|
+
const all = flagBool(args, "all");
|
|
77
|
+
const noDeps = flagBool(args, "no-deps");
|
|
78
|
+
const targetDir = resolve(process.cwd(), dirFlag ?? DEFAULT_TARGET_DIR);
|
|
79
|
+
const names = args.positional;
|
|
80
|
+
let toInstall;
|
|
81
|
+
if (all) {
|
|
82
|
+
toInstall = loadIndex().components.map((c) => c.name);
|
|
83
|
+
} else {
|
|
84
|
+
if (names.length === 0) {
|
|
85
|
+
throw new CliError(
|
|
86
|
+
CLI_ERROR_CODE.INVALID_INPUT,
|
|
87
|
+
"No component name provided.",
|
|
88
|
+
{ remediation: "Run `cimplify list` to see options, then `cimplify add <name>`." }
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
toInstall = noDeps ? names : resolveDependencyOrder(names);
|
|
92
|
+
}
|
|
93
|
+
if (!all && !noDeps && toInstall.length > names.length) {
|
|
94
|
+
const transitive = toInstall.filter((n) => !names.includes(n));
|
|
95
|
+
info(`${bold("Will install with dependencies:")}`);
|
|
96
|
+
info(` Requested: ${names.join(", ")}`);
|
|
97
|
+
info(` Transitive: ${transitive.join(", ")}`);
|
|
98
|
+
info(dim(` Pass --no-deps to skip transitive components.`));
|
|
99
|
+
const proceed = await promptYesNo("Continue?", true);
|
|
100
|
+
if (!proceed) {
|
|
101
|
+
throw new CliError(CLI_ERROR_CODE.ABORTED, "Aborted by user.");
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
info("");
|
|
105
|
+
info(`Target: ${dim(targetDir)}`);
|
|
106
|
+
info("");
|
|
107
|
+
const outcomes = [];
|
|
108
|
+
for (const name of toInstall) {
|
|
109
|
+
const component = loadComponent(name);
|
|
110
|
+
info(bold(name));
|
|
111
|
+
const outcome = await writeComponent(component, { targetDir, force });
|
|
112
|
+
outcomes.push(outcome);
|
|
113
|
+
info("");
|
|
114
|
+
}
|
|
115
|
+
const totalWritten = outcomes.reduce((n, o) => n + o.written.length, 0);
|
|
116
|
+
const totalSkipped = outcomes.reduce((n, o) => n + o.skipped.length, 0);
|
|
117
|
+
success(`Wrote ${totalWritten} file(s), skipped ${totalSkipped}`);
|
|
118
|
+
result({
|
|
119
|
+
target_dir: targetDir,
|
|
120
|
+
components: outcomes,
|
|
121
|
+
totals: { written: totalWritten, skipped: totalSkipped }
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export { run as default };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { CliError, CLI_ERROR_CODE } from './chunk-NZ4RG62Z.mjs';
|
|
3
|
+
|
|
4
|
+
// src/envfile.ts
|
|
5
|
+
var COMMENT_CHAR = "#";
|
|
6
|
+
var QUOTE_DOUBLE = '"';
|
|
7
|
+
var QUOTE_SINGLE = "'";
|
|
8
|
+
var KEY_SEPARATOR = "=";
|
|
9
|
+
var KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
10
|
+
function parseEnvFile(text) {
|
|
11
|
+
const entries = [];
|
|
12
|
+
const lines = text.split("\n");
|
|
13
|
+
for (const raw of lines) {
|
|
14
|
+
const line = raw.trim();
|
|
15
|
+
if (line.length === 0) continue;
|
|
16
|
+
if (line.startsWith(COMMENT_CHAR)) continue;
|
|
17
|
+
const eq = line.indexOf(KEY_SEPARATOR);
|
|
18
|
+
if (eq === -1) continue;
|
|
19
|
+
const key = line.slice(0, eq).trim();
|
|
20
|
+
if (!KEY_PATTERN.test(key)) continue;
|
|
21
|
+
let value = line.slice(eq + 1).trim();
|
|
22
|
+
if (value.length >= 2) {
|
|
23
|
+
const first = value[0];
|
|
24
|
+
const last = value[value.length - 1];
|
|
25
|
+
if (first === QUOTE_DOUBLE && last === QUOTE_DOUBLE || first === QUOTE_SINGLE && last === QUOTE_SINGLE) {
|
|
26
|
+
value = value.slice(1, -1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
entries.push({ key, value });
|
|
30
|
+
}
|
|
31
|
+
return entries;
|
|
32
|
+
}
|
|
33
|
+
function parseKeyValueArg(input) {
|
|
34
|
+
const eq = input.indexOf(KEY_SEPARATOR);
|
|
35
|
+
if (eq === -1) {
|
|
36
|
+
throw new CliError(
|
|
37
|
+
CLI_ERROR_CODE.INVALID_INPUT,
|
|
38
|
+
`Expected KEY=VALUE, got "${input}".`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
const key = input.slice(0, eq).trim();
|
|
42
|
+
if (!KEY_PATTERN.test(key)) {
|
|
43
|
+
throw new CliError(
|
|
44
|
+
CLI_ERROR_CODE.INVALID_INPUT,
|
|
45
|
+
`Invalid env var key "${key}". Must match ${KEY_PATTERN.source}.`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
return { key, value: input.slice(eq + 1) };
|
|
49
|
+
}
|
|
50
|
+
function formatEnvFile(entries) {
|
|
51
|
+
const lines = [];
|
|
52
|
+
for (const { key, value } of entries) {
|
|
53
|
+
const needsQuote = /[\s"'#]/.test(value) || value.length === 0;
|
|
54
|
+
const rendered = needsQuote ? `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"` : value;
|
|
55
|
+
lines.push(`${key}=${rendered}`);
|
|
56
|
+
}
|
|
57
|
+
return lines.length === 0 ? "" : `${lines.join("\n")}
|
|
58
|
+
`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { formatEnvFile, parseEnvFile, parseKeyValueArg };
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { CliError, CLI_ERROR_CODE } from './chunk-NZ4RG62Z.mjs';
|
|
3
|
+
|
|
4
|
+
// src/api-client.ts
|
|
5
|
+
var DEFAULT_API_BASE_URL = "https://api.cimplify.io";
|
|
6
|
+
var ENV_API_BASE_URL = "CIMPLIFY_API_URL";
|
|
7
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
8
|
+
var HEADER_AUTHORIZATION = "Authorization";
|
|
9
|
+
var HEADER_CONTENT_TYPE = "Content-Type";
|
|
10
|
+
var HEADER_ACCEPT = "Accept";
|
|
11
|
+
var HEADER_USER_AGENT = "User-Agent";
|
|
12
|
+
var BEARER_PREFIX = "Bearer ";
|
|
13
|
+
var CONTENT_TYPE_JSON = "application/json";
|
|
14
|
+
var USER_AGENT = "cimplify-cli";
|
|
15
|
+
var METHOD_GET = "GET";
|
|
16
|
+
var METHOD_POST = "POST";
|
|
17
|
+
var METHOD_PUT = "PUT";
|
|
18
|
+
var METHOD_DELETE = "DELETE";
|
|
19
|
+
var STATUS_UNAUTHORIZED = 401;
|
|
20
|
+
var STATUS_FORBIDDEN = 403;
|
|
21
|
+
var STATUS_NOT_FOUND = 404;
|
|
22
|
+
var STATUS_CONFLICT = 409;
|
|
23
|
+
var STATUS_BAD_REQUEST_MIN = 400;
|
|
24
|
+
var STATUS_SERVER_ERROR_MIN = 500;
|
|
25
|
+
var ApiClient = class _ApiClient {
|
|
26
|
+
baseUrl;
|
|
27
|
+
apiKey;
|
|
28
|
+
constructor(baseUrl, apiKey) {
|
|
29
|
+
this.baseUrl = baseUrl.replace(/\/+$/, "");
|
|
30
|
+
this.apiKey = apiKey;
|
|
31
|
+
}
|
|
32
|
+
static fromAuth(auth) {
|
|
33
|
+
return new _ApiClient(auth.apiBaseUrl, auth.apiKey);
|
|
34
|
+
}
|
|
35
|
+
static unauthenticated(baseUrl = resolveBaseUrl()) {
|
|
36
|
+
return new _ApiClient(baseUrl, "");
|
|
37
|
+
}
|
|
38
|
+
static withKey(apiKey, baseUrl = resolveBaseUrl()) {
|
|
39
|
+
return new _ApiClient(baseUrl, apiKey);
|
|
40
|
+
}
|
|
41
|
+
get(pathname, options) {
|
|
42
|
+
return this.request(METHOD_GET, pathname, void 0, options);
|
|
43
|
+
}
|
|
44
|
+
post(pathname, body, options) {
|
|
45
|
+
return this.request(METHOD_POST, pathname, body, options);
|
|
46
|
+
}
|
|
47
|
+
put(pathname, body, options) {
|
|
48
|
+
return this.request(METHOD_PUT, pathname, body, options);
|
|
49
|
+
}
|
|
50
|
+
delete(pathname, options) {
|
|
51
|
+
return this.request(METHOD_DELETE, pathname, void 0, options);
|
|
52
|
+
}
|
|
53
|
+
async request(method, pathname, body, options) {
|
|
54
|
+
const url = this.buildUrl(pathname, options?.query);
|
|
55
|
+
const headers = {
|
|
56
|
+
[HEADER_ACCEPT]: CONTENT_TYPE_JSON,
|
|
57
|
+
[HEADER_USER_AGENT]: USER_AGENT
|
|
58
|
+
};
|
|
59
|
+
if (this.apiKey) {
|
|
60
|
+
headers[HEADER_AUTHORIZATION] = `${BEARER_PREFIX}${this.apiKey}`;
|
|
61
|
+
}
|
|
62
|
+
let payload;
|
|
63
|
+
if (body !== void 0) {
|
|
64
|
+
headers[HEADER_CONTENT_TYPE] = CONTENT_TYPE_JSON;
|
|
65
|
+
payload = JSON.stringify(body);
|
|
66
|
+
}
|
|
67
|
+
const controller = new AbortController();
|
|
68
|
+
const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
69
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
70
|
+
let response;
|
|
71
|
+
try {
|
|
72
|
+
response = await fetch(url, {
|
|
73
|
+
method,
|
|
74
|
+
headers,
|
|
75
|
+
body: payload,
|
|
76
|
+
signal: controller.signal
|
|
77
|
+
});
|
|
78
|
+
} catch (err) {
|
|
79
|
+
clearTimeout(timer);
|
|
80
|
+
throw toNetworkError(err);
|
|
81
|
+
}
|
|
82
|
+
clearTimeout(timer);
|
|
83
|
+
return parseResponse(response);
|
|
84
|
+
}
|
|
85
|
+
buildUrl(pathname, query) {
|
|
86
|
+
const base = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
87
|
+
const url = new URL(`${this.baseUrl}${base}`);
|
|
88
|
+
if (query) {
|
|
89
|
+
for (const [k, v] of Object.entries(query)) {
|
|
90
|
+
if (v === void 0 || v === null) continue;
|
|
91
|
+
url.searchParams.set(k, String(v));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return url.toString();
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
function resolveBaseUrl(override) {
|
|
98
|
+
if (override && override.length > 0) return override;
|
|
99
|
+
const fromEnv = process.env[ENV_API_BASE_URL];
|
|
100
|
+
return fromEnv && fromEnv.length > 0 ? fromEnv : DEFAULT_API_BASE_URL;
|
|
101
|
+
}
|
|
102
|
+
async function parseResponse(response) {
|
|
103
|
+
const text = await response.text();
|
|
104
|
+
let body = void 0;
|
|
105
|
+
if (text.length > 0) {
|
|
106
|
+
try {
|
|
107
|
+
body = JSON.parse(text);
|
|
108
|
+
} catch {
|
|
109
|
+
throw new CliError(
|
|
110
|
+
CLI_ERROR_CODE.SERVER_ERROR,
|
|
111
|
+
`Server returned non-JSON response (status ${response.status}): ${truncate(text)}`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (response.ok) {
|
|
116
|
+
if (body && typeof body === "object" && "data" in body) {
|
|
117
|
+
return body.data;
|
|
118
|
+
}
|
|
119
|
+
return body;
|
|
120
|
+
}
|
|
121
|
+
const code = mapStatusToCode(response.status);
|
|
122
|
+
const message = extractErrorMessage(body, response.status);
|
|
123
|
+
throw new CliError(code, message);
|
|
124
|
+
}
|
|
125
|
+
function mapStatusToCode(status) {
|
|
126
|
+
if (status === STATUS_UNAUTHORIZED) return CLI_ERROR_CODE.AUTH_FAILED;
|
|
127
|
+
if (status === STATUS_FORBIDDEN) return CLI_ERROR_CODE.AUTH_FAILED;
|
|
128
|
+
if (status === STATUS_NOT_FOUND) return CLI_ERROR_CODE.PROJECT_NOT_FOUND;
|
|
129
|
+
if (status === STATUS_CONFLICT) return CLI_ERROR_CODE.ALREADY_LINKED;
|
|
130
|
+
if (status >= STATUS_SERVER_ERROR_MIN) return CLI_ERROR_CODE.SERVER_ERROR;
|
|
131
|
+
if (status >= STATUS_BAD_REQUEST_MIN) return CLI_ERROR_CODE.INVALID_INPUT;
|
|
132
|
+
return CLI_ERROR_CODE.SERVER_ERROR;
|
|
133
|
+
}
|
|
134
|
+
function extractErrorMessage(body, status) {
|
|
135
|
+
if (body && typeof body === "object") {
|
|
136
|
+
const envelope = body;
|
|
137
|
+
if (envelope.error && typeof envelope.error.error_message === "string") {
|
|
138
|
+
return envelope.error.error_code ? `${envelope.error.error_code}: ${envelope.error.error_message}` : envelope.error.error_message;
|
|
139
|
+
}
|
|
140
|
+
if (typeof envelope.message === "string") return envelope.message;
|
|
141
|
+
}
|
|
142
|
+
return `HTTP ${status}`;
|
|
143
|
+
}
|
|
144
|
+
function toNetworkError(err) {
|
|
145
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
146
|
+
return new CliError(CLI_ERROR_CODE.NETWORK_ERROR, "Request timed out.");
|
|
147
|
+
}
|
|
148
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
149
|
+
return new CliError(CLI_ERROR_CODE.NETWORK_ERROR, `Network error: ${message}`);
|
|
150
|
+
}
|
|
151
|
+
function truncate(value, max = 200) {
|
|
152
|
+
return value.length > max ? `${value.slice(0, max)}\u2026` : value;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export { ApiClient, resolveBaseUrl };
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { promptYesNo } from './chunk-L6474RPL.mjs';
|
|
3
|
+
import { TOKEN_PURPOSE, REPO_PROVIDER, REPO_PROVIDER_VALUES } from './chunk-MQMNWLMU.mjs';
|
|
4
|
+
import { parseArgs, flagString, flagBool } from './chunk-D7D75ONX.mjs';
|
|
5
|
+
import { ApiClient } from './chunk-4ZVTPMUZ.mjs';
|
|
6
|
+
import { readAuth, readProjectLink } from './chunk-JJYWETGA.mjs';
|
|
7
|
+
import { CliError, CLI_ERROR_CODE, isJsonMode, result, dim, success, info, bold } from './chunk-NZ4RG62Z.mjs';
|
|
8
|
+
|
|
9
|
+
// src/commands/repo.ts
|
|
10
|
+
var SUB_PROVISION = "provision";
|
|
11
|
+
var SUB_CONNECT = "connect";
|
|
12
|
+
var SUB_INFO = "info";
|
|
13
|
+
var SUB_UNLINK = "unlink";
|
|
14
|
+
var SUB_ROTATE_TOKEN = "rotate-token";
|
|
15
|
+
var SUB_CLONE_URL = "clone-url";
|
|
16
|
+
var FLAG_PURGE = "purge";
|
|
17
|
+
var FLAG_YES = "yes";
|
|
18
|
+
var FLAG_PROVIDER = "provider";
|
|
19
|
+
var FLAG_NAME = "name";
|
|
20
|
+
var FLAG_BRANCH = "branch";
|
|
21
|
+
function repoEndpoint(businessId, projectId) {
|
|
22
|
+
return `/v1/businesses/${encodeURIComponent(businessId)}/projects/${encodeURIComponent(projectId)}/repo`;
|
|
23
|
+
}
|
|
24
|
+
function provisionEndpoint(businessId, projectId) {
|
|
25
|
+
return `${repoEndpoint(businessId, projectId)}/provision`;
|
|
26
|
+
}
|
|
27
|
+
function connectEndpoint(businessId, projectId) {
|
|
28
|
+
return `${repoEndpoint(businessId, projectId)}/connect`;
|
|
29
|
+
}
|
|
30
|
+
function cloneTokenEndpoint(businessId, projectId) {
|
|
31
|
+
return `${repoEndpoint(businessId, projectId)}/clone-token`;
|
|
32
|
+
}
|
|
33
|
+
async function fetchCloneToken(client, businessId, projectId, purpose = TOKEN_PURPOSE.EDITOR) {
|
|
34
|
+
return client.post(cloneTokenEndpoint(businessId, projectId), {
|
|
35
|
+
purpose
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function resolveProvider(value, fallback) {
|
|
39
|
+
if (value === void 0) return fallback;
|
|
40
|
+
if (!REPO_PROVIDER_VALUES.has(value)) {
|
|
41
|
+
throw new CliError(
|
|
42
|
+
CLI_ERROR_CODE.INVALID_INPUT,
|
|
43
|
+
`Invalid provider "${value}". Choose: ${[...REPO_PROVIDER_VALUES].join(", ")}.`
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return value;
|
|
47
|
+
}
|
|
48
|
+
function detectProviderFromUrl(url) {
|
|
49
|
+
try {
|
|
50
|
+
const parsed = new URL(url);
|
|
51
|
+
if (parsed.hostname === "git.freestyle.sh") return REPO_PROVIDER.FREESTYLE;
|
|
52
|
+
if (parsed.hostname === "github.com" || parsed.hostname.endsWith(".github.com")) {
|
|
53
|
+
return REPO_PROVIDER.GITHUB;
|
|
54
|
+
}
|
|
55
|
+
if (parsed.hostname.includes("gitea")) return REPO_PROVIDER.GITEA;
|
|
56
|
+
} catch {
|
|
57
|
+
}
|
|
58
|
+
return REPO_PROVIDER.EXTERNAL;
|
|
59
|
+
}
|
|
60
|
+
async function run(argv) {
|
|
61
|
+
const args = parseArgs(argv);
|
|
62
|
+
const sub = args.positional[0];
|
|
63
|
+
if (!sub) {
|
|
64
|
+
throw new CliError(
|
|
65
|
+
CLI_ERROR_CODE.INVALID_INPUT,
|
|
66
|
+
`Usage: cimplify repo <${SUB_PROVISION}|${SUB_CONNECT}|${SUB_INFO}|${SUB_UNLINK}|${SUB_ROTATE_TOKEN}|${SUB_CLONE_URL}>`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const auth = await readAuth();
|
|
70
|
+
const link = await readProjectLink();
|
|
71
|
+
const client = ApiClient.fromAuth(auth);
|
|
72
|
+
switch (sub) {
|
|
73
|
+
case SUB_PROVISION:
|
|
74
|
+
await provisionRepo(client, link.businessId, link.projectId, args);
|
|
75
|
+
return;
|
|
76
|
+
case SUB_CONNECT:
|
|
77
|
+
await connectRepo(client, link.businessId, link.projectId, args);
|
|
78
|
+
return;
|
|
79
|
+
case SUB_INFO:
|
|
80
|
+
await repoInfo(client, link.businessId, link.projectId);
|
|
81
|
+
return;
|
|
82
|
+
case SUB_UNLINK:
|
|
83
|
+
await unlinkRepo(client, link.businessId, link.projectId, args);
|
|
84
|
+
return;
|
|
85
|
+
case SUB_ROTATE_TOKEN:
|
|
86
|
+
await provisionRepo(client, link.businessId, link.projectId, args);
|
|
87
|
+
return;
|
|
88
|
+
case SUB_CLONE_URL:
|
|
89
|
+
await printCloneUrl(client, link.businessId, link.projectId);
|
|
90
|
+
return;
|
|
91
|
+
default:
|
|
92
|
+
throw new CliError(CLI_ERROR_CODE.INVALID_INPUT, `Unknown repo subcommand "${sub}"`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async function printCloneUrl(client, businessId, projectId) {
|
|
96
|
+
const token = await fetchCloneToken(client, businessId, projectId);
|
|
97
|
+
if (isJsonMode()) {
|
|
98
|
+
result({
|
|
99
|
+
clone_url: token.clone_url,
|
|
100
|
+
token: token.token ?? null,
|
|
101
|
+
repo_id: token.repo_id,
|
|
102
|
+
provider: token.provider,
|
|
103
|
+
expires_in_seconds: token.expires_in_seconds
|
|
104
|
+
});
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
process.stdout.write(`${token.clone_url}
|
|
108
|
+
`);
|
|
109
|
+
const hints = [
|
|
110
|
+
"",
|
|
111
|
+
dim(`Token TTL: ${token.expires_in_seconds}s. Re-run to mint a fresh one.`),
|
|
112
|
+
dim("Example:"),
|
|
113
|
+
dim(` git remote set-url origin "${token.clone_url}"`),
|
|
114
|
+
dim(" # or one-shot:"),
|
|
115
|
+
dim(` git push "${token.clone_url}" main`)
|
|
116
|
+
];
|
|
117
|
+
for (const line of hints) process.stderr.write(`${line}
|
|
118
|
+
`);
|
|
119
|
+
}
|
|
120
|
+
async function provisionRepo(client, businessId, projectId, args) {
|
|
121
|
+
const provider = resolveProvider(flagString(args, FLAG_PROVIDER), REPO_PROVIDER.FREESTYLE);
|
|
122
|
+
if (provider !== REPO_PROVIDER.FREESTYLE) {
|
|
123
|
+
throw new CliError(
|
|
124
|
+
CLI_ERROR_CODE.INVALID_INPUT,
|
|
125
|
+
`Provisioning is only supported for ${REPO_PROVIDER.FREESTYLE} today. Use \`cimplify repo connect\` for ${provider}.`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
const body = {
|
|
129
|
+
provider,
|
|
130
|
+
name_hint: flagString(args, FLAG_NAME) ?? void 0,
|
|
131
|
+
default_branch: flagString(args, FLAG_BRANCH) ?? void 0
|
|
132
|
+
};
|
|
133
|
+
const repo = await client.post(provisionEndpoint(businessId, projectId), body);
|
|
134
|
+
success(`Provisioned ${repo.provider} repo`);
|
|
135
|
+
printRepo(repo);
|
|
136
|
+
result({ repo: repoPayload(repo) });
|
|
137
|
+
}
|
|
138
|
+
async function connectRepo(client, businessId, projectId, args) {
|
|
139
|
+
const remoteUrl = args.positional[1];
|
|
140
|
+
if (!remoteUrl) {
|
|
141
|
+
throw new CliError(
|
|
142
|
+
CLI_ERROR_CODE.INVALID_INPUT,
|
|
143
|
+
`Usage: cimplify repo ${SUB_CONNECT} <https-clone-url> [--provider <p>] [--branch <name>]`
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
const provider = resolveProvider(flagString(args, FLAG_PROVIDER), detectProviderFromUrl(remoteUrl));
|
|
147
|
+
if (provider === REPO_PROVIDER.FREESTYLE) {
|
|
148
|
+
throw new CliError(
|
|
149
|
+
CLI_ERROR_CODE.INVALID_INPUT,
|
|
150
|
+
"Cannot connect a Freestyle URL \u2014 use `cimplify repo provision` instead."
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
const body = {
|
|
154
|
+
provider,
|
|
155
|
+
remote_url: remoteUrl,
|
|
156
|
+
default_branch: flagString(args, FLAG_BRANCH) ?? void 0
|
|
157
|
+
};
|
|
158
|
+
const repo = await client.post(connectEndpoint(businessId, projectId), body);
|
|
159
|
+
success(`Connected ${repo.provider} remote ${repo.remote_url}`);
|
|
160
|
+
printRepo(repo);
|
|
161
|
+
result({ repo: repoPayload(repo) });
|
|
162
|
+
}
|
|
163
|
+
async function repoInfo(client, businessId, projectId) {
|
|
164
|
+
const repo = await client.get(repoEndpoint(businessId, projectId));
|
|
165
|
+
if (!repo) {
|
|
166
|
+
info(dim("No repo attached. Run `cimplify repo provision` to mint a Freestyle repo,"));
|
|
167
|
+
info(dim("or `cimplify repo connect <url>` to link an existing remote."));
|
|
168
|
+
result({ repo: null });
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
printRepo(repo);
|
|
172
|
+
result({ repo: repoPayload(repo) });
|
|
173
|
+
}
|
|
174
|
+
async function unlinkRepo(client, businessId, projectId, args) {
|
|
175
|
+
const purge = flagBool(args, FLAG_PURGE);
|
|
176
|
+
const skipPrompt = flagBool(args, FLAG_YES);
|
|
177
|
+
if (!skipPrompt) {
|
|
178
|
+
const message = purge ? "Unlink and DELETE the upstream Freestyle repo? This cannot be undone." : "Unlink the repo from this project? (Upstream repo will be preserved.)";
|
|
179
|
+
const proceed = await promptYesNo(message, false);
|
|
180
|
+
if (!proceed) {
|
|
181
|
+
throw new CliError(CLI_ERROR_CODE.ABORTED, "Aborted by user.");
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
await client.delete(repoEndpoint(businessId, projectId), {
|
|
185
|
+
query: purge ? { purge: "true" } : void 0
|
|
186
|
+
});
|
|
187
|
+
success(purge ? "Repo unlinked and purged" : "Repo unlinked (upstream preserved)");
|
|
188
|
+
result({ unlinked: true, purged: purge });
|
|
189
|
+
}
|
|
190
|
+
function printRepo(repo) {
|
|
191
|
+
info(bold("Repo:"));
|
|
192
|
+
info(` provider: ${repo.provider}`);
|
|
193
|
+
info(` id: ${repo.id}`);
|
|
194
|
+
info(` remote_url: ${repo.remote_url}`);
|
|
195
|
+
info(` default_branch: ${repo.default_branch}`);
|
|
196
|
+
if (repo.last_pushed_commit) {
|
|
197
|
+
info(` last_pushed: ${repo.last_pushed_commit.slice(0, 12)} (${repo.last_pushed_at ?? "\u2014"})`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function repoPayload(repo) {
|
|
201
|
+
return {
|
|
202
|
+
provider: repo.provider,
|
|
203
|
+
id: repo.id,
|
|
204
|
+
remote_url: repo.remote_url,
|
|
205
|
+
default_branch: repo.default_branch,
|
|
206
|
+
last_pushed_commit: repo.last_pushed_commit ?? null,
|
|
207
|
+
last_pushed_at: repo.last_pushed_at ?? null
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export { fetchCloneToken, run };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// src/args.ts
|
|
3
|
+
function parseArgs(argv) {
|
|
4
|
+
const positional = [];
|
|
5
|
+
const flags = /* @__PURE__ */ new Map();
|
|
6
|
+
for (let i = 0; i < argv.length; i++) {
|
|
7
|
+
const arg = argv[i];
|
|
8
|
+
if (!arg.startsWith("--")) {
|
|
9
|
+
positional.push(arg);
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
const eq = arg.indexOf("=");
|
|
13
|
+
if (eq !== -1) {
|
|
14
|
+
flags.set(arg.slice(2, eq), arg.slice(eq + 1));
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
const name = arg.slice(2);
|
|
18
|
+
const next = argv[i + 1];
|
|
19
|
+
if (next !== void 0 && !next.startsWith("--")) {
|
|
20
|
+
flags.set(name, next);
|
|
21
|
+
i++;
|
|
22
|
+
} else {
|
|
23
|
+
flags.set(name, true);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return { positional, flags };
|
|
27
|
+
}
|
|
28
|
+
function flagString(args, name) {
|
|
29
|
+
const v = args.flags.get(name);
|
|
30
|
+
return typeof v === "string" ? v : void 0;
|
|
31
|
+
}
|
|
32
|
+
function flagBool(args, name) {
|
|
33
|
+
return args.flags.has(name);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export { flagBool, flagString, parseArgs };
|