UNPKG

@supernovaio/cli

Version:

Supernova.io Command Line Interface

283 lines (281 loc) 15.2 kB
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="79164005-5c4d-5eb4-b9f4-98e8d135a628")}catch(e){}}(); import inquirer from "inquirer"; import { SETUP_DOCS_URL, SETUP_INTRO_HEADER_ART } from "../../constants.js"; import { colorize, emphasis, formatFullSnapshotPathLink, muted, renderPanel, success, warning } from "../../ui.js"; import { promptContinueSetup, promptScanPackages, promptScanSourcePath, promptTemplateFramework } from "./prompts.js"; import { renderDiscoveredPackages, renderSourceScan } from "./screens.js"; const introDescriptionLinesMuted = new Set([ " Run and upload static analysis of your design system sources for high quality prototypes.", " Build and upload a sandbox container with your real components, icons, CSS, and templates.", " The container is your prototyping environment — fully customizable and expandable after setup.", " Generate your first prototype using your actual product code.", " Create a container folder with an Angular template on your machine.", " Follow the setup guide to add your components to the container manually.", " Upload the container to Supernova so it can be used for prototyping.", " Generate your first prototype using your actual product code.", ]); function introPanelLineTone(line, _lineIndex) { if (line === "✅ Before you start:" || line === "🔍 What will happen next:") { return "blueBold"; } if (introDescriptionLinesMuted.has(line)) { return "gray"; } return "none"; } function shouldRunScanForFramework(framework) { return framework === "React"; } function scanContextForFramework(framework) { const shouldRunScan = shouldRunScanForFramework(framework); return { analysisProcessingRunId: undefined, componentPackages: undefined, discoveredPackages: undefined, repoPaths: undefined, scanOutputPaths: undefined, scanSourcePath: undefined, shouldRunScan, shouldUploadScanResults: shouldRunScan, templateFramework: framework, }; } function renderIntroPanel(framework, gitRootWarningLines) { switch (framework) { case "React": return renderPanel("Supernova Create Setup for React", [ ...(gitRootWarningLines.length > 0 ? [...gitRootWarningLines, ""] : []), "Connect your codebase for AI-powered prototyping with your actual components - not generics.", "", "✅ Before you start:", " • Make sure you run this command from your repository root", " • Docker installed and running", " • A successful dependency installation (e.g., npm install) is required", " • npm token ready if your packages are behind a private registry", "", "🔍 What will happen next:", " 1. Codebase analysis", " Run and upload static analysis of your design system sources for high quality prototypes.", "", " 2. Code container setup", " Build and upload a sandbox container with your real components, icons, CSS, and templates.", " The container is your prototyping environment — fully customizable and expandable after setup.", "", " 3. Create prototype", " Generate your first prototype using your actual product code.", "", `${colorize("🕒 Estimated setup time:", "blue")} Up to 30 minutes`, "", `${colorize("📘 Docs:", "blue")} ${SETUP_DOCS_URL}`, `${colorize("💬 Need help? Contact us:", "blue")} support@supernova.io`, ], { lineTone: introPanelLineTone, titleTone: "blueBold", headerArt: SETUP_INTRO_HEADER_ART }); case "Angular": return renderPanel("Supernova Create Setup for Angular", [ ...(gitRootWarningLines.length > 0 ? [...gitRootWarningLines, ""] : []), "Connect your codebase for AI-powered prototyping with your actual components - not generics.", "", "✅ Before you start:", " • Make sure you run this command from your repository root", " • Docker installed and running", " • npm token ready if your packages are behind a private registry", "", "🔍 What will happen next:", " 1. Code container setup", " Create a container folder with an Angular template on your machine.", "", " 2. Add your design system components to code container", " Follow the setup guide to add your components to the container manually.", "", " 3. Upload container", " Upload the container to Supernova so it can be used for prototyping.", "", " 4. Create prototype", " Generate your first prototype using your actual product code.", "", `${colorize("📘 Docs:", "blue")} ${SETUP_DOCS_URL}`, `${colorize("💬 Need help? Contact us:", "blue")} support@supernova.io`, ], { lineTone: introPanelLineTone, titleTone: "blueBold", headerArt: SETUP_INTRO_HEADER_ART }); case "Vue": return renderPanel("Supernova Create Setup for Vue", [ ...(gitRootWarningLines.length > 0 ? [...gitRootWarningLines, ""] : []), "Connect your codebase for AI-powered prototyping with your actual components - not generics.", "", "✅ Before you start:", " • Make sure you run this command from your repository root", " • Docker installed and running", " • npm token ready if your packages are behind a private registry", "", "🔍 What will happen next:", " 1. Code container setup", " Create a container folder with a Vue template on your machine.", "", " 2. Add your design system components to code container", " Follow the setup guide to add your components to the container manually.", "", " 3. Upload container", " Upload the container to Supernova so it can be used for prototyping.", "", " 4. Create prototype", " Generate your first prototype using your actual product code.", "", `${colorize("📘 Docs:", "blue")} ${SETUP_DOCS_URL}`, `${colorize("💬 Need help? Contact us:", "blue")} support@supernova.io`, ], { lineTone: introPanelLineTone, titleTone: "blueBold", headerArt: SETUP_INTRO_HEADER_ART }); } } export function createScanHandlers(services) { return { async INIT(context) { const templateFramework = await promptTemplateFramework(context.templateFramework); let gitRootWarningLines = []; const parentGitLocation = services.validation.findParentGitDirectoryLocation(); if (parentGitLocation) { gitRootWarningLines = [ `⚠️ Detected a git repository above the current directory: ${parentGitLocation}`, "⚠️ For the best setup defaults, run this command from the repository root.", ]; } services.ui.log(""); services.ui.log(renderIntroPanel(templateFramework, gitRootWarningLines)); await promptContinueSetup(services.ui.error); return scanContextForFramework(templateFramework); }, async SELECT_DESIGN_SYSTEM(context) { services.ui.renderStep("Design system (select)"); const designSystemId = await services.designSystems.promptDesignSystemId(); const workspaceId = await services.designSystems.resolveWorkspaceIdForDesignSystem(designSystemId); await services.designSystems.ensureWorkspaceSetupEligibility(workspaceId); await services.designSystems.ensureSandboxTemplateAccess(workspaceId); services.designSystems.updateSelectedDesignSystem(designSystemId); services.ui.log(`${emphasis("Selected design system ID:")} ${designSystemId}`); const scanContext = context.templateFramework ? scanContextForFramework(context.templateFramework) : {}; return { designSystemId, ...scanContext, workspaceId, }; }, async SELECT_SCAN_SOURCE_PATH(context) { if (!context.shouldRunScan) { return { componentPackages: undefined, discoveredPackages: undefined, repoPaths: undefined, scanSourcePath: undefined, }; } services.ui.renderStep("Design system codebase analysis"); services.ui.log(renderSourceScan()); const discovery = await promptScanSourcePath({ allowSkip: services.debug, error: services.ui.error, log: message => services.ui.log(warning(message)), }); if (!discovery) { services.ui.log(muted("Skipping codebase analysis and continuing with container setup.")); return { componentPackages: undefined, discoveredPackages: undefined, repoPaths: undefined, scanOutputPaths: undefined, scanSourcePath: undefined, shouldRunScan: false, shouldUploadScanResults: false, }; } const discoveredPackages = discovery.discoveredPackages ?? []; services.ui.log(`${emphasis("Source folder:")} ${discovery.scanSourcePath}`); services.ui.log(`${emphasis("Discovered packages:")} ${discoveredPackages.map(pkg => pkg.name).join(", ")}`); return { discoveredPackages, repoPaths: [discovery.scanSourcePath], scanSourcePath: discovery.scanSourcePath, }; }, async SELECT_SCAN_PACKAGES(context) { if (!context.shouldRunScan) { return { componentPackages: undefined }; } services.ui.renderStep("Discovered packages"); services.ui.log(renderDiscoveredPackages()); const discoveredPackages = context.discoveredPackages ?? []; if (discoveredPackages.length === 0) { services.ui.error("No discovered packages were available for scan."); } const componentPackages = await promptScanPackages(discoveredPackages, context.componentPackages, services.ui.error); services.ui.log(`${emphasis("Packages to scan:")} ${componentPackages.join(", ")}`); services.scan.persistAnalyzePackages(componentPackages); return { componentPackages }; }, async RUN_SCAN(context) { if (!context.shouldRunScan) { return { scanOutputPaths: undefined }; } if (!context.componentPackages?.length) services.ui.error("Component package names are missing."); if (!context.scanSourcePath) services.ui.error("Scan source path is missing."); if (!context.designSystemId) services.ui.error("Design system is missing."); const scanOutputPaths = await services.scan.runScanAgainstSourcePath({ componentPackages: context.componentPackages, designSystemId: context.designSystemId, scanSourcePath: context.scanSourcePath, }); return { repoPaths: [context.scanSourcePath], scanOutputPaths }; }, async REVIEW_SCAN_OUTPUT(context) { if (!context.shouldRunScan) { return { shouldUploadScanResults: false }; } if (!context.scanOutputPaths?.length || !context.componentPackages?.length || !context.designSystemId) { services.ui.error("Scan output is missing."); } services.ui.renderStep("Scan review"); const { scanOutputPaths } = context; while (true) { services.ui.log(success("Scan complete.")); const response = await inquirer.prompt([ { choices: [ { name: "Upload scan results and continue", value: "upload" }, { name: "Explore results", value: "explore" }, ...(services.debug ? [{ name: "Skip scan upload and continue", value: "skip_upload" }] : []), ], default: services.debug && context.shouldUploadScanResults === false ? "skip_upload" : "upload", message: colorize("Next action:", "blue"), name: "action", type: "list", }, ]); if (response.action === "explore") { services.ui.log(""); services.ui.log("Scan results"); services.ui.log(scanOutputPaths.map(value => ` ${muted("•")} ${formatFullSnapshotPathLink(value)}`).join("\n")); continue; } return { repoPaths: context.scanSourcePath ? [context.scanSourcePath] : context.repoPaths, scanOutputPaths, shouldUploadScanResults: response.action === "upload", }; } }, async UPLOAD_SCAN_RESULTS(context) { if (!context.shouldRunScan || !context.shouldUploadScanResults) { return undefined; } services.ui.renderStep("Upload analysis snapshots"); if (!context.designSystemId || !context.scanOutputPaths?.length || !context.repoPaths?.length) { services.ui.error("Scan upload context is incomplete."); } const uploadResult = await services.scan.uploadAnalysisSnapshots({ designSystemId: context.designSystemId, scanOutputPaths: context.scanOutputPaths, }); return { analysisProcessingRunId: uploadResult.processingRunId }; }, }; } //# sourceMappingURL=index.js.map //# debugId=79164005-5c4d-5eb4-b9f4-98e8d135a628