@equinor/fusion-framework-cli
Version:
[](./LICENSE)
1 lines âĒ 256 kB
JavaScript
import{createCommand as e,createOption as t,InvalidOptionArgumentError as r,Command as n}from"commander";import o,{fileURLToPath as i}from"node:url";import{resolve as s,dirname as a,join as c}from"node:path";import{readPackageUpSync as l}from"read-package-up";import{ConsoleLogger as d,buildApplication as u,bundleApp as p,FusionEnv as h,resolveDefaultEnv as f,checkApp as m,initializeFramework as g,uploadApplication as y,publishAppConfig as v,generateApplicationConfig as b,AllowedAppTags as $,tagApplication as w,loadAppManifest as E,startAppDevServer as S,startPortalDevServer as P,loadPortalManifest as _,buildPortal as L,bundlePortal as C,uploadPortalBundle as k,tagPortal as N,AllowedPortalTags as I,publishPortalConfig as O,generatePortalConfig as A}from"@equinor/fusion-framework-cli/bin";import{mkdir as T,writeFile as x}from"node:fs/promises";import{accessSync as D,constants as j,readFileSync as R,writeFileSync as F,rmSync as M,existsSync as G,readdirSync as U,copyFileSync as B,cpSync as z,mkdirSync as V}from"node:fs";import H from"node:assert";import q from"inquirer";import W from"is-path-inside";import{execa as K,ExecaError as Y}from"execa";import{spawn as J}from"node:child_process";import{tmpdir as X}from"node:os";import{simpleGit as Z,ResetMode as Q}from"simple-git";import{z as ee}from"zod";import te from"url";import re from"node:module";import ne from"util";import{importConfig as oe,importJSON as ie}from"@equinor/fusion-imports";import"deepmerge";const se=(e=0)=>t=>`[${t+e}m`,ae=(e=0)=>t=>`[${38+e};5;${t}m`,ce=(e=0)=>(t,r,n)=>`[${38+e};2;${t};${r};${n}m`,le={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],overline:[53,55],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],gray:[90,39],grey:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgGray:[100,49],bgGrey:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]}};Object.keys(le.modifier);Object.keys(le.color),Object.keys(le.bgColor);const de=function(){const e=new Map;for(const[t,r]of Object.entries(le)){for(const[t,n]of Object.entries(r))le[t]={open:`[${n[0]}m`,close:`[${n[1]}m`},r[t]=le[t],e.set(n[0],n[1]);Object.defineProperty(le,t,{value:r,enumerable:!1})}return Object.defineProperty(le,"codes",{value:e,enumerable:!1}),le.color.close="[39m",le.bgColor.close="[49m",le.color.ansi=se(),le.color.ansi256=ae(),le.color.ansi16m=ce(),le.bgColor.ansi=se(10),le.bgColor.ansi256=ae(10),le.bgColor.ansi16m=ce(10),Object.defineProperties(le,{rgbToAnsi256:{value:(e,t,r)=>e===t&&t===r?e<8?16:e>248?231:Math.round((e-8)/247*24)+232:16+36*Math.round(e/255*5)+6*Math.round(t/255*5)+Math.round(r/255*5),enumerable:!1},hexToRgb:{value(e){const t=/[a-f\d]{6}|[a-f\d]{3}/i.exec(e.toString(16));if(!t)return[0,0,0];let[r]=t;3===r.length&&(r=[...r].map(e=>e+e).join(""));const n=Number.parseInt(r,16);return[n>>16&255,n>>8&255,255&n]},enumerable:!1},hexToAnsi256:{value:e=>le.rgbToAnsi256(...le.hexToRgb(e)),enumerable:!1},ansi256ToAnsi:{value(e){if(e<8)return 30+e;if(e<16)return e-8+90;let t,r,n;if(e>=232)t=(10*(e-232)+8)/255,r=t,n=t;else{const o=(e-=16)%36;t=Math.floor(e/36)/5,r=Math.floor(o/6)/5,n=o%6/5}const o=2*Math.max(t,r,n);if(0===o)return 30;let i=30+(Math.round(n)<<2|Math.round(r)<<1|Math.round(t));return 2===o&&(i+=60),i},enumerable:!1},rgbToAnsi:{value:(e,t,r)=>le.ansi256ToAnsi(le.rgbToAnsi256(e,t,r)),enumerable:!1},hexToAnsi:{value:e=>le.ansi256ToAnsi(le.hexToAnsi256(e)),enumerable:!1}}),le}(),ue=(()=>{if(!("navigator"in globalThis))return 0;if(globalThis.navigator.userAgentData){const e=navigator.userAgentData.brands.find(({brand:e})=>"Chromium"===e);if(e&&e.version>93)return 3}return/\b(Chrome|Chromium)\//.test(globalThis.navigator.userAgent)?1:0})(),pe=0!==ue&&{level:ue},he={stdout:pe,stderr:pe};function fe(e,t,r){let n=e.indexOf(t);if(-1===n)return e;const o=t.length;let i=0,s="";do{s+=e.slice(i,n)+t+r,i=n+o,n=e.indexOf(t,i)}while(-1!==n);return s+=e.slice(i),s}const{stdout:me,stderr:ge}=he,ye=Symbol("GENERATOR"),ve=Symbol("STYLER"),be=Symbol("IS_EMPTY"),$e=["ansi","ansi","ansi256","ansi16m"],we=Object.create(null),Ee=e=>{const t=(...e)=>e.join(" ");return((e,t={})=>{if(t.level&&!(Number.isInteger(t.level)&&t.level>=0&&t.level<=3))throw new Error("The `level` option should be an integer from 0 to 3");const r=me?me.level:0;e.level=void 0===t.level?r:t.level})(t,e),Object.setPrototypeOf(t,Se.prototype),t};function Se(e){return Ee(e)}Object.setPrototypeOf(Se.prototype,Function.prototype);for(const[e,t]of Object.entries(de))we[e]={get(){const r=ke(this,Ce(t.open,t.close,this[ve]),this[be]);return Object.defineProperty(this,e,{value:r}),r}};we.visible={get(){const e=ke(this,this[ve],!0);return Object.defineProperty(this,"visible",{value:e}),e}};const Pe=(e,t,r,...n)=>"rgb"===e?"ansi16m"===t?de[r].ansi16m(...n):"ansi256"===t?de[r].ansi256(de.rgbToAnsi256(...n)):de[r].ansi(de.rgbToAnsi(...n)):"hex"===e?Pe("rgb",t,r,...de.hexToRgb(...n)):de[r][e](...n),_e=["rgb","hex","ansi256"];for(const e of _e){we[e]={get(){const{level:t}=this;return function(...r){const n=Ce(Pe(e,$e[t],"color",...r),de.color.close,this[ve]);return ke(this,n,this[be])}}};we["bg"+e[0].toUpperCase()+e.slice(1)]={get(){const{level:t}=this;return function(...r){const n=Ce(Pe(e,$e[t],"bgColor",...r),de.bgColor.close,this[ve]);return ke(this,n,this[be])}}}}const Le=Object.defineProperties(()=>{},{...we,level:{enumerable:!0,get(){return this[ye].level},set(e){this[ye].level=e}}}),Ce=(e,t,r)=>{let n,o;return void 0===r?(n=e,o=t):(n=r.openAll+e,o=t+r.closeAll),{open:e,close:t,openAll:n,closeAll:o,parent:r}},ke=(e,t,r)=>{const n=(...e)=>Ne(n,1===e.length?""+e[0]:e.join(" "));return Object.setPrototypeOf(n,Le),n[ye]=e,n[ve]=t,n[be]=r,n},Ne=(e,t)=>{if(e.level<=0||!t)return e[be]?"":t;let r=e[ve];if(void 0===r)return t;const{openAll:n,closeAll:o}=r;if(t.includes(""))for(;void 0!==r;)t=fe(t,r.close,r.open),r=r.parent;const i=t.indexOf("\n");return-1!==i&&(t=function(e,t,r,n){let o=0,i="";do{const s="\r"===e[n-1];i+=e.slice(o,s?n-1:n)+t+(s?"\r\n":"\n")+r,o=n+1,n=e.indexOf("\n",o)}while(-1!==n);return i+=e.slice(o),i}(t,o,n,i)),n+t+o};Object.defineProperties(Se.prototype,we);const Ie=Se();Se({level:ge?ge.level:0});const Oe=e("build").description("Build the application").addHelpText("after",["","If no manifest is provided, searches for a default app.manifest(.$ENV)?.[ts|js|json] in the current directory.","example: `ffc app build --env prod` will search for `app.manifest.prod.ts` then fallback to `app.manifest.ts`","","NOTE: app manifest is not required, a default manifest will be generated if not provided","","OUTPUT LOCATION:"," The build output location is determined by the `main` field in your package.json.",' - "main": "dist/index.js" â outputs to dist/index.js',' - "main": "build/app.js" â outputs to build/app.js'," - No main field â defaults to dist/bundle.js"," Output directory cannot be project root, src/, or current working directory.","","Examples:"," $ ffc app build"," $ ffc app build app.manifest.dev.ts --debug"].join("\n")).option("-d, --debug","Enable debug mode for verbose logging",!1).argument("[manifest]","Manifest file to use for building (e.g., app.manifest.ts)").action(async(e,t)=>{const r=new d("app:build",{debug:t.debug});await u({log:r,manifest:e})}),Ae="app-bundle.zip",Te=e("pack").description("Create a distributable app bundle of the application.").addHelpText("after",["","If no manifest is provided, a default app.manifest(.$ENV)?.[ts|js|json] is used from the current directory.","example: `ffc app pack --env prod` will search for `app.manifest.prod.ts` then fallback to `app.manifest.ts`","","NOTE: app manifest is not required, a default manifest will be generated if not provided","","Examples:"," $ ffc app pack"," $ ffc app pack app.manifest.dev.ts --archive my-app.zip --output ./dist"].join("\n")).option("-a, --archive [string]","Name of the output archive file (default: app-bundle.zip)",Ae).option("-o, --output [string]","Directory where the archive will be saved (default: current working directory)",process.cwd()).option("-d, --debug","Enable debug mode for verbose logging",!1).argument("[manifest]","Manifest file to use for bundling (e.g., app.manifest.ts)").action(async(e,t)=>{const r=new d("app:pack",{debug:t.debug});await p({log:r,manifest:e,archive:t.archive}).catch(e=>{r.error("Failed to create package:",e),process.exit(1)})}),xe=e=>{const r=Object.values(h).filter(t=>t!==h.Development||e.allowDev);return t("-e, --env <string>",`Set environment [${r.join(", ")}, custom].`).env("FUSION_ENV").default(e.default??f(e.allowDev))};xe({allowDev:!0});const De=/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,je=t("--tenantId <string>","The Azure Active Directory tenant ID").env("FUSION_TENANT_ID").default("3aa4a235-b6e2-48d5-9195-7fcf05b459b0"),Re=t("--clientId <string>","The client ID of the application registered in Azure AD").env("FUSION_CLIENT_ID").default("a318b8e1-0295-4e17-98d5-35f67dfeba14"),Fe=t("--token <string>","The Azure AD access token. If provided, the --tenant and --client options are ignored").env("FUSION_TOKEN").default(void 0),Me=t("--scope <scopes...>","Azure audience scope, normally the application ID URI of the API you want to access and `.default`").env("FUSION_AUTH_SCOPE").default(["5a842df8-3238-415d-b168-9f16a6a6031b/.default"]),Ge=(e,t)=>(e.addOption(je),e.addOption(Re),t?.excludeToken||e.addOption(Fe),t?.includeScope&&e.addOption(Me),e.hook("preAction",e=>{const n=e.opts();if(n.token){if("string"!=typeof n.token||""===n.token.trim())throw new r("Token must be a non-empty string.");return e.setOptionValue("tenantId",void 0),e.setOptionValue("clientId",void 0),void(t?.includeScope&&e.setOptionValue("scope",void 0))}if(!n.tenantId||"string"!=typeof n.tenantId)throw new r("Tenant ID must be a non-empty string.");if(!De.test(n.tenantId))throw new r("Tenant ID must be a valid UUID.");if(!n.clientId||"string"!=typeof n.clientId)throw new r("Client ID must be a non-empty string.");if(!De.test(n.clientId))throw new r("Client ID must be a valid UUID.");if(t?.includeScope){if(!Array.isArray(n.scope)||0===n.scope.length)throw new r("Scope must be a non-empty array of strings.");for(const e of n.scope)if("string"!=typeof e||""===e.trim())throw new r("Each scope must be a non-empty string.")}}),e),Ue=Ge(e("check").description("Check if application is registered in Fusion app store.").addHelpText("after",["","Verifies the registration status of your application in the Fusion app store.","Helps identify issues with app registration or configuration.","","FIRST TIME SETUP:"," Before checking app status, ensure your app is registered in the Fusion App Admin."," The check command will tell you if your app is properly registered.","","Examples:"," $ ffc app check"," $ ffc app check --env prod --debug"].join("\n")).option("-d, --debug","debug mode",!1).addOption(xe({allowDev:!1})).action(e=>{const t=new d("app:check",{debug:!!e.debug});return m({log:t,environment:e.env,auth:"token"in e?{token:e.token}:e})})),Be=Ge(e("upload").description("Upload a Fusion application bundle to the Fusion App Store.").addHelpText("after",["","Uploads a distributable application bundle (e.g., app-bundle.zip) to the Fusion app store.","","Examples:"," $ ffc app upload"," $ ffc app upload my-app-bundle.zip --appKey my-app"," $ ffc app upload --debug"].join("\n")).option("-d, --debug [boolean]","Enable debug mode for verbose logging",!1).option("-k, --appKey <string>","Application key (if not provided, resolved from the build metadata of the bundle)").addOption(xe({allowDev:!1})).argument("[bundle]","Application bundle to upload",Ae).action(async(e,t)=>{const r=new d("portal:upload",{debug:t.debug});r?.start("ðū Initializing Fusion Framework...");const n=await g({env:t.env,auth:{token:t.token,tenantId:t.tenantId,clientId:t.clientId}});r?.succeed("ðū Initialized Fusion Framework"),await y({log:r,appKey:t.appKey,framework:n,fileOrBundle:e}).catch(e=>{r.error("ðĒ Failed to upload bundle:",e),process.exit(1)})})),ze=Ge(e("config").description("Generate or publish the Fusion application configuration object.").addHelpText("after",["","By default, outputs the generated config object to stdout or a file. Use --publish to upload the config to the Fusion app registry.","- Options [--token, --tenantId, --clientId, --manifest] are only relevant when --publish is used.",'- Option [-e, --env] cannot be set to "dev" when --publish is used.',"","Note:","- If not `app.config(.$ENV)?.[ts|js|json]` is found it will fallback to generate a default config (empty object)","- If not `app.manifest(.$ENV)?.[ts|js|json]` is found it will fallback to generate a default manifest","","Examples:"," $ ffc app config app.config.ts"," $ ffc app config app.config.prod.ts --output ./dist/app.config.json"," $ ffc app config app.manifest.prod.ts --silent > ./dist/app.config.json"," $ ffc app config --publish --manifest app.manifest.ts --env prod"," $ ffc app config --env prod my-custom.config.ts"].join("\n")).option("--debug","Enable debug mode for verbose logging").option("--silent","Silent mode, suppresses output except errors").option("--publish","Publish config to Fusion app registry").option("--manifest <path>","Path to the app manifest file (required with --publish)").addOption(xe({allowDev:!0})).option("-o, --output <stdout|path>","Output the result to stdout or a file (ignored with --publish, default: stdout)","stdout").argument("[config]","Config build file to use (e.g., app.config[.env]?.[ts,js,json])").action(async(e,t)=>{const r=t.silent?null:new d("app:config",{debug:!!t.debug});if(t.publish)return"dev"===t.env&&(r?.fail("ðĪŠ",Ie.blue("--env"),'cannot be "dev" when',Ie.blue("--publish")," is used"),process.exit(1)),v({config:t.config,manifest:t.manifest,environment:t.env,auth:"token"in t?{token:t.token}:t,debug:t.debug});const{config:n}=await b({log:r,config:e,env:{environment:t.env},output:"stdout"===t.output?void 0:t.output});"stdout"===t.output&&console.log(JSON.stringify(n,null,2))}));const Ve=Ge(e("tag").description("Tag your uploaded Fusion Application build version with a specific tag.").addHelpText("after",["","Note: using --package is preferred over --manifest, since no infered compilation is required.","","Examples:"," $ ffc app tag latest"," $ ffc app tag preview --env prod --manifest app.manifest.prod.ts"," $ ffc app tag stable --package my-app@1.2.3"," $ ffc app tag latest --manifest app.manifest.custom.ts"].join("\n")).addOption(xe({allowDev:!1})).option("-p, --package [package@version]","Package to tag in format name@version (e.g., my-app@1.0.0)").option("-m, --manifest <string>","Manifest file to use. Note: ignoring if --package is provided").option("--debug","Enable debug mode for verbose logging").option("--silent","Silent mode, suppresses output except errors").argument("<tag>",`Tag to apply (${Object.values($).join(" | ")})`).action(async(e,t)=>{const r=t.silent?null:new d("app:tag",{debug:t.debug}),n={command:"build",environment:t.env,mode:process.env.NODE_ENV??"production",root:process.cwd()};let o,i;try{({appKey:o,version:i}=await async function(e,t){if(e.package){const[t,r]=e.package.split("@");if(!t||!r)throw new Error("Package must be in format name@version (e.g., my-app@1.0.0). Please verify the package name and version with --package");return{appKey:t,version:r}}const{manifest:r}=await E({manifest:e.manifest,env:t}),n=r.build?.version;if(!n)throw new Error(`Could not determine version from manifest. Please verify manifest ${e.manifest} or provide a package name and version with --package`);return{appKey:r.appKey,version:n}}(t,n))}catch(e){r?.error(`ðĒ ${e instanceof Error?e.message:"Unknown error occurred"}`),process.exit(1)}r?.info("Tagging application:",Ie.greenBright(`${o}@${i} - ${e}`)),r?.start("Initializing Fusion Framework...");const s=await g({env:t.env,auth:{token:t.token,tenantId:t.tenantId,clientId:t.clientId}});r?.succeed("Initialized Fusion Framework"),r?.start("Tagging application..."),await w({appKey:o,version:i,framework:s,log:r,tag:e}).catch(e=>{r?.error("Failed to tag application:",e),process.exit(1)})})),He=e("dev").description("Start the application in development mode.").addHelpText("after",["","Examples:"," $ ffc app dev"," $ ffc app dev --port 4000"," $ ffc app dev --manifest ./app.manifest.local.ts --config ./app.config.ts"].join("\n")).option("--debug","Enable debug mode").option("--manifest <path>","Path to the app manifest file (app.manifest[.env]?.[ts,js,json])").option("--config <path>","Path to the app config file (app.config[.env]?.[ts,js,json])").option("--env <environment>","Runtime environment for the dev server","local").option("--port <port>","Port for the development server","3000").action(async e=>{const t=new d("app:dev",{debug:e.debug});t.start("Starting application in development mode..."),S({log:t,manifest:e.manifest,config:e.config,env:e.env,port:e.port}),t.succeed("Development server started successfully.")}),qe=(e,t)=>{try{return D(e,j.F_OK),!0}catch(e){return!1}},We=e("manifest").description("Build and output the application manifest for Fusion apps.").addHelpText("after",["","By default, outputs the generated manifest object to stdout or a file. Use --output to write to a file.","","Note:","- If not `app.manifest(.$ENV)?.[ts|js|json]` is found it will fallback to generate a default manifest","","Examples:"," $ ffc app manifest"," $ ffc app manifest app.manifest.prod.ts --output ./dist/app.manifest.json",' $ ffc app manifest --silent | jq ".build.entryPoint"'," $ ffc app manifest --debug"].join("\n")).option("-d, --debug","Enable debug mode for verbose logging",!1).option("-o, --output <string>","Output the result to stdout or a file","stdout").option("-s, --silent","Silent mode, suppresses output except errors").argument("[manifest]","Manifest build file to use (e.g., app.manifest[.env]?.[ts,js,json])").action(async(e,t)=>{const r=t.silent?null:new d("app:manifest",{debug:t.debug}),n=await E({log:r,manifest:e});if("stdout"!==t.output){const e=s(process.cwd(),t.output);r?.start("Writing manifest to file",t.output),qe(a(e))||await T(a(e),{recursive:!0}),await x(e,JSON.stringify(n.manifest,null,2)),r?.succeed("Manifest written to file",e)}else console.log(JSON.stringify(n.manifest,null,2))}),Ke=Ge(e("publish").description("Deployment: Build, upload, and tag your Fusion application.").addHelpText("after",["","WHAT THIS COMMAND DOES:"," 1. Builds your application (if no bundle provided)"," 2. Uploads the bundle to Fusion app registry"," 3. Tags the uploaded version for deployment","","If no manifest is provided, a default app.manifest(.$ENV)?.[ts|js|json] is used from the current directory.","example: `ffc app publish --env prod` will search for `app.manifest.prod.ts` then fallback to `app.manifest.ts`","","NOTE: app manifest is not required, a default manifest will be generated if not provided","","FIRST TIME PUBLISHING:"," - Ensure your app is registered in Fusion App Admin"," - Use `ffc app check` first to verify registration status"," - Start with a test environment before production","","Examples:"," $ ffc app publish"," $ ffc app publish --env prod --manifest app.manifest.prod.ts"," $ ffc app publish --tag latest app.bundle.zip"].join("\n")).option("-d, --debug","Enable debug mode for verbose logging",!1).addOption(xe({allowDev:!1})).option("-m, --manifest [string]","Manifest file to use for bundling (e.g., app.manifest.ts)").option("-t, --tag [string]",`Tag to apply to the published app (${Object.values($).join(" | ")})`,$.Latest).argument("[bundle]","Path to the app bundle to upload").action(async(e,t)=>{const r=new d("app:publish",{debug:t.debug});let n;if(e)r.info(`ðĶ Using provided bundle: ${e}`),n=e;else try{r.start("ðĶ Bundle application...");n=(await p({log:r,manifest:t.manifest})).archive,r.succeed("ðĶ Bundle completed")}catch(e){r.error("ðĒ Failed to bundle application:",e),process.exit(1)}n||(r.error("ðĒ No bundle provided or created. Please specify a bundle file."),process.exit(1)),r?.start("ðū Initializing Fusion Framework...");const o=await g({env:t.env,auth:{token:t.token,tenantId:t.tenantId,clientId:t.clientId}});r?.succeed("ðū Initialized Fusion Framework"),r.start("ð Uploading application...");const i=await y({log:r,framework:o,fileOrBundle:n}).catch(e=>{r.error("ðĒ Failed to upload bundle:",e),process.exit(1)});r.succeed("ð Upload completed"),r.debug("Upload result:",i),r.start("ð·ïļ Tagging application...");const s=await w({tag:t.tag,appKey:i.name,version:i.version,log:r,framework:o}).catch(e=>{r.error("ðĒ Failed to tag application:",e),process.exit(1)});r.succeed("Tagging completed"),r.debug("Tagging result:",s)}));async function Ye(e,t="https://registry.npmjs.org"){const r=await async function(e,t="https://registry.npmjs.org"){try{const r=await fetch(`${t}/${e}`);if(!r.ok)throw new Error(`Failed to fetch package info for ${e}: ${r.statusText}`);const n=await r.json();if(!n.name)throw new Error(`Invalid package data received for ${e}`);const o=n["dist-tags"]?.latest;if(!o)throw new Error(`No latest version found for package ${e}`);return{name:n.name,latest:o,versions:Object.keys(n.versions||{}),"dist-tags":n["dist-tags"]||{},description:n.description,homepage:n.homepage,repository:n.repository,author:n.author,license:n.license,keywords:n.keywords,dependencies:n.dependencies,devDependencies:n.devDependencies,peerDependencies:n.peerDependencies}}catch(t){throw new Error(`Failed to fetch package info for ${e}: ${t instanceof Error?t.message:String(t)}`)}}(e,t);return r.latest}async function Je(e,t){const r=[{key:"dependencies",deps:e.dependencies},{key:"devDependencies",deps:e.devDependencies},{key:"peerDependencies",deps:e.peerDependencies}].filter(e=>void 0!==e.deps&&null!==e.deps);if(0!==r.length){t?.start(`Resolving workspace dependencies for ${r.length} dependency types`);try{const n=await Promise.all(r.map(({key:e,deps:r})=>async function(e,t,r){try{const n=Object.entries(t).filter(e=>{return"string"==typeof(t=e[1])&&t.startsWith("workspace:");var t});if(0===n.length)return r?.debug(`No workspace dependencies found in ${e}`),{key:e,resolved:t};r?.debug(`Resolving ${n.length} workspace dependencies for ${e}`);const o=await Promise.all(n.map(async([e,t])=>{try{const n=await Ye(e);return r?.debug(`Resolved ${e}: ${t} -> ${n}`),[e,n]}catch(n){const o=n instanceof Error?n.message:String(n);return r?.debug(`Failed to resolve ${e}: ${o}`),[e,t]}})),i={...t};for(const[e,t]of o)i[e]=t;return r?.debug(`Successfully processed ${e} with ${o.length} resolved dependencies`),{key:e,resolved:i}}catch(n){const o=n instanceof Error?n.message:String(n);return r?.debug(`Error processing ${e}: ${o}`),{key:e,resolved:t}}}(e,r,t)));for(const{key:t,resolved:r}of n)e[t]=r;const o=n.reduce((e,{resolved:t})=>e+Object.keys(t).length,0);t?.succeed(`Workspace dependencies resolved successfully (${o} total dependencies processed)`)}catch(e){const r=e instanceof Error?e.message:String(e);throw t?.debug(`Error details: ${r}`),new Error(`Failed to resolve workspace dependencies: ${r}`)}}else t?.debug("No dependencies found to resolve")}function Xe(e,t){if("string"!=typeof e||""===e.trim())throw new Error("Target path must be a non-empty string");const r=s(e);if(t){const e=s(t);if(!W(r,e))throw new Error("The target path must be within the specified base directory. Please specify a relative path or ensure the absolute path is within the base directory.")}return r}function Ze(e,t,r){const n=Xe(e,r);M(n,t)}const Qe=["code","cursor"];async function et(e,t){t.info("By selecting an IDE, it will be opened in a new window."),t.info("ð please come back to this terminal to continue."),t.info(`You can also open the project in your IDE later by typing e.g. \`code ${e}\` in the terminal.`),t.info("If you do not want to open the project in an IDE, select no.");const{openInIDE:r}=await q.prompt([{type:"list",name:"openInIDE",message:"ð Open project in IDE?",default:!1,choices:[{name:"VS Code",value:"code"},{name:"Cursor",value:"cursor"},{name:"No, I will open the project in my IDE later",value:!1}]}]);if(r){if(!function(e){return Qe.includes(e)}(r))return void t.error(`Invalid IDE command: ${r}. Only supported IDEs are: ${Qe.join(", ")}`);try{const n=K(r,[e],{stdio:"pipe",detached:!0});n.unref(),n.catch(e=>{void 0!==e.exitCode&&0!==e.exitCode?t.error(`IDE process exited with code ${e.exitCode}. The IDE may not have opened successfully.`):t.error(`Failed to open IDE (${r}): ${e.message}`)})}catch(e){t.error(`Failed to spawn IDE process (${r}): ${e instanceof Error?e.message:String(e)}`)}}}const tt=["npm","pnpm"];async function rt(e,t){const{installDeps:r}=await q.prompt([{type:"confirm",name:"installDeps",message:"ðĶ Install dependencies?",default:!0}]);if(!r)return t.debug("Skipping dependency installation"),{installed:!1};const{packageManager:n}=await q.prompt([{type:"list",name:"packageManager",message:"ðĶ Which package manager do you want to use?",choices:["pnpm","npm"],default:"pnpm"}]);return await async function(e,t,r){H(tt.includes(t),"Package manager must be npm or pnpm"),r?.start("Installing dependencies...");try{return await K(t,["install"],{cwd:e,stdio:"inherit",shell:!0}),r?.succeed("Dependencies installed successfully!"),t}catch(e){if(e instanceof Y&&0!==e.exitCode)throw r?.error(`${t} install failed with exit code ${e.exitCode}`),new Error(`${t} install failed with exit code ${e.exitCode}`);throw r?.error(`Failed to run ${t} install: ${e instanceof Error?e.message:String(e)}`),e}}(e,n,t),{installed:!0,packageManager:n}}class nt{#e;#t;#r;get name(){return this.#e.name}get description(){return this.#e.description}get resources(){return this.#e.resources}constructor(e,t,r){this.#e=e,this.#r=t,this.#t=r.logger}copyTo(e){this.#t?.debug(`Copying template resources to ${e}`);for(const t of this.#e.resources){this.#t?.debug(`Copying resource ${t.path}`,{resource:t});const r=c(this.#r,t.path),n=c(e,t.target??t.path);if(G(r))try{"file"===t.type?(B(r,n),this.#t?.debug(`Copied file: ${t.path} -> ${n}`)):"dir"===t.type?(z(r,n,{recursive:t.recursive??!1}),this.#t?.debug(`Copied directory: ${t.path} -> ${n}`)):this.#t?.debug("Resource is not a file or directory, skipping",{resource:t})}catch(e){throw this.#t?.error(`Failed to copy resource ${t.path}:`,e),e}else this.#t?.warn(`Source resource does not exist, skipping: ${r}`)}}}const ot=ee.object({type:ee.literal("file"),path:ee.string(),target:ee.string().optional()}),it=ee.object({type:ee.literal("dir"),path:ee.string(),target:ee.string().optional(),recursive:ee.boolean().optional()}),st=ee.discriminatedUnion("type",[ot,it]),at=ee.object({name:ee.string(),description:ee.string(),resources:ee.array(st)}),ct=ee.object({templates:ee.array(at),resources:ee.array(st).optional()});class lt{repo;#n=!1;#o;#i;#s;#a;#c;get protocol(){return this.#a}set protocol(e){H("https"===e||"ssh"===e,"Protocol must be either https or ssh"),this.#a=e}get branch(){return this.#c}get repoUrl(){return"ssh"===this.#a?`git@github.com:${this.repo}.git`:`https://github.com/${this.repo}.git`}set branch(e){this.#c=e,this.#n&&this._checkoutBranch()}constructor(e,t){this.repo=e,this.#i=t.baseDir??c(X(),"ffc","repo",e),this.#s=t.log,this.#c=t.branch??"main",this.#o=Z(),this.#a=t.protocol??"https"}async initialize(){if(!this.#n)try{if(this.#s?.debug("Checking if repository directory exists...",this.#i),G(this.#i)||(this.#s?.info("Repository directory does not exist, creating..."),V(this.#i,{recursive:!0}),this.#s?.succeed("Repository directory created successfully!")),this.#o=Z({baseDir:this.#i}),this._setupOutputHandler(),!this.#a||"https"===this.#a)try{const e=await this.#o.getConfig("core.sshCommand");this.#a=e?"ssh":"https"}catch{this.#a="https"}this.#s?.debug("Checking if repository is initialized...");await this.#o.checkIsRepo()?(this.#s?.info("Git is initialized, checking out branch..."),await this._checkoutBranch(),this.#s?.succeed("Branch checked out successfully!")):(this.#s?.info("Git is not initialized, cloning repo..."),await this._cloneRepo(),this.#s?.succeed("Repo cloned successfully!")),this.#s?.succeed("Repository initialized successfully!"),this.#n=!0}catch(e){throw this.#s?.fail("Repository initialization failed!"),this.#s?.error(e),e}}async getAvailableTemplates(){let e;try{const t=c(this.#i,"templates.json");this.#s?.debug("Reading template manifest file...",t),e=R(t,"utf8")}catch(e){throw new Error("Failed to read templates.json file from the root of the repository...",{cause:e})}try{this.#s?.debug("Parsing and validating template content...");const t=function(e){try{const t=JSON.parse(e);return ct.parse(t)}catch(e){if(e instanceof ee.ZodError)throw new Error(`Template manifest validation failed: ${e.message}`);throw new Error(`Failed to parse JSON: ${e instanceof Error?e.message:"Unknown error"}`)}}(e);this.#s?.debug("Parsed template content...",t);return t.templates.map(e=>{const r=[...t.resources??[],...e.resources];return new nt({...e,resources:r},this.#i,{logger:this.#s})})}catch(e){throw new Error("Failed to parse templates.json content",{cause:e})}}async cleanup(){try{this.#s?.debug(`Removing repository directory: ${this.#i}`);return Ze(Xe(this.#i,X()),{recursive:!0,force:!0},X()),this.#s?.succeed("Repository directory cleaned up successfully!"),this.#n=!1,!0}catch(e){return this.#s?.error(`Failed to remove repository directory: ${this.#i}`,e),!1}}async _cloneRepo(){try{this.#s?.debug("Cloning repo...",{repo:this.repo,repoUrl:this.repoUrl,baseDir:this.#i,branch:this.#c,protocol:this.#a}),await this.#o.clone(this.repoUrl,this.#i,["--single-branch","--branch",this.#c])}catch(e){throw new Error("Failed to clone repo...",{cause:e})}}async _checkoutBranch(){try{this.#s?.debug("Fetching repo...",{repo:this.repo,repoUrl:this.repoUrl}),await this.#o.fetch(),this.#s?.debug("Checking out branch...",this.#c);(await this.#o.checkout(this.#c)).includes("branch is up to date")?this.#s?.debug("Branch is up to date!"):(this.#s?.info("Branch is not up to date, updating to latest changes..."),await this.#o.reset(Q.HARD).pull(),this.#s?.debug("Branch updated successfully!"))}catch(e){throw new Error("Failed to checkout branch...",{cause:e})}}_setupOutputHandler(){this.#o.outputHandler((e,t,r)=>{t.on("data",e=>{this.#s?.debug("ð",String(e))}),r.on("data",e=>{this.#s?.error("ð",String(e))})})}}async function dt(e,t,r){H(!!e,"App name is required"),H(G(t.directory),`Directory '${t.directory}' does not exist, use -d to specify a different directory`);const n=s(t.directory,e);r.debug(`Target dir: ${n}`);const o=await async function(e,t,r=!1,n=process.cwd()){let o;H("string"==typeof e,"Target directory must be a string");try{o=Xe(e,n)}catch(e){const r=e instanceof Error?e.message:String(e);return t.error(`â Invalid target directory path: ${r}`),t.info('ðĄ Try using a relative path like "my-app" or ensure the absolute path is within the specified directory.'),!1}if(!G(o))return t.debug(`Target directory does not exist: ${o}`),!0;try{const e=U(o);if(0===e.length)return t.debug(`Target directory is empty: ${o}`),!0;if(t.warn(`Target directory '${o}' is not empty and contains ${e.length} item(s).`),t.info("Contents:",e.slice(0,10).join(", ")+(e.length>10?"...":"")),r){t.info("Cleaning target directory (--clean flag)...");try{Ze(o,{recursive:!0,force:!0},n),t.succeed("Target directory cleaned successfully!")}catch(e){throw t.error(`Failed to clean target directory: ${e}`),t.info("Check directory permissions and ensure you have write access to the directory."),t.info("You may need to run the command with elevated privileges or manually remove the files."),e}}else{const{action:e}=await q.prompt([{type:"list",name:"action",message:"What would you like to do?",choices:[{name:"Continue - Add files to existing directory",value:"continue"},{name:"Clean - Remove all existing files and continue",value:"clean"},{name:"Abort - Cancel the operation",value:"abort"}],default:"abort"}]);if("abort"===e)return t.info("Operation cancelled by user."),!1;if("clean"===e){t.info("Cleaning target directory...");try{Ze(o,{recursive:!0,force:!0},n),t.succeed("Target directory cleaned successfully!")}catch(e){throw t.error(`Failed to clean target directory: ${e}`),t.info("Check directory permissions and ensure you have write access to the directory."),t.info("You may need to run the command with elevated privileges or manually remove the files."),e}}else t.info("Continuing with existing directory...")}return!0}catch(e){throw t.error(`Failed to check target directory: ${e}`),t.info("Ensure the path is valid and accessible, and that you have read permissions for the directory."),t.info("Check if the directory path contains any invalid characters or if the path is too long."),e}}(n,r,t.clean,t.directory);o||process.exit(0);const i=await async function(e,t,r,n){const o=s(X(),"ffc","repo",e);if(n.debug(`Repo dir: ${o}`),t){n.debug(`Removing repo dir: ${o}`);try{Ze(Xe(o,X()),{recursive:!0,force:!0},X())}catch(e){n.debug("Cleanup failed:",e)}}const i=new lt(e,{baseDir:o,log:n,branch:r});return await i.initialize(),i}("equinor/fusion-app-template",t.clean,t.branch,r),a=await i.getAvailableTemplates(),l=await async function(e,t,r){H(Array.isArray(e),"Templates must be an array"),H(e.length>0,"No templates available");const n=e.map(e=>e.name);if(t){H("string"==typeof t,"Pre-selected template must be a string"),H(n.includes(t),"Pre-selected template must be in the list of available templates"),r?.debug(`Using pre-selected template: ${t}`);const o=e.find(e=>e.name===t);return H(o,"Pre-selected template not found"),o}if(1===e.length)return r?.debug(`Using single template: ${e[0].name}`),e[0];const{selectedTemplate:o}=await q.prompt([{type:"list",name:"selectedTemplate",message:"ðĻ Please select a template:",choices:e.map(e=>({name:`${e.name} - ${e.description}`,value:e})),pageSize:10,loop:!1}]);return o}(a,t.template,r);try{await l.copyTo(n),r.succeed("Template resources copied successfully!")}catch(e){r.error(`Failed to copy template resources: ${e instanceof Error?e.message:String(e)}`),r.info("Please check the target directory permissions and try again"),process.exit(1)}try{await(async(e,t,r)=>{const n=c(e,"package.json");try{const e=R(n,"utf-8"),o=JSON.parse(e);let i={...o};if(t?.resolveWorkspaceDependencies){r?.debug("Resolving workspace dependencies");const e=JSON.parse(JSON.stringify(o));await Je(e,r),i=e}t?.updates&&(r?.debug(`Applying updates: ${Object.keys(t.updates).join(", ")}`),i={...i,...t.updates}),JSON.stringify(o)!==JSON.stringify(i)?(r?.debug("Writing updated package.json to disk"),F(n,`${JSON.stringify(i,null,2)}\n`)):r?.debug("No changes detected, skipping package.json update")}catch(e){throw new Error(`Failed to update package.json: ${e instanceof Error?e.message:String(e)}`)}})(n,{updates:{name:e},resolveWorkspaceDependencies:!0},r),r.succeed(`Updated package.json with app name: ${e}`)}catch(e){r.error(`Failed to update package.json: ${e instanceof Error?e.message:String(e)}`),r.info("Please check the package.json file and try again"),process.exit(1)}await async function(e,t){const{cleanupTempFiles:r}=await q.prompt([{type:"confirm",name:"cleanupTempFiles",message:"ðïļ Clean up temporary template files?",default:!1}]);r?await e.cleanup():t.debug("Skipping cleanup of temporary template files")}(i,r),await et(n,r);const{installed:d,packageManager:u}=await rt(n,r);if(d&&u){const e=await async function(e,t,r,n=!1){const{startDev:o}=await q.prompt([{type:"confirm",name:"startDev",message:"ð Start development server?",default:!0}]);if(o){r.debug(`Starting development server: ${e}`),n&&r.info("Running in persistent mode - server will run until manually stopped (Ctrl+C)");try{const o=J(t,["run","dev"],{cwd:e,stdio:"inherit"});let i=null,s=!1;if(!n){const e=6e4;i=setTimeout(()=>{s=!0,r.error(`Development server did not start within ${e/1e3} seconds and may be hanging. Terminating process.`),o.kill("SIGTERM"),r.info(`You can try running '${t} run dev' manually in the project directory.`)},e)}const a=()=>{i&&clearTimeout(i),o.removeAllListeners("error"),o.removeAllListeners("exit")};return o.on("error",e=>{a(),s||(r.error(`Failed to start development server with ${t}: ${e.message}`),r.info(`Make sure ${t} is installed and the 'dev' script exists in package.json`))}),o.on("exit",e=>{a(),s||0===e||n?n&&0!==e&&r.info(`Development server stopped with exit code ${e}`):(r.error(`Development server process exited with code ${e}. The server may not have started successfully.`),r.info(`Check the output above for error details or try running '${t} run dev' manually`))}),!0}catch(e){r.error(`Failed to spawn development server process with ${t}: ${e instanceof Error?e.message:String(e)}`),r.info(`Make sure ${t} is installed and the 'dev' script exists in package.json`)}}return!1}(n,u,r,!0);e&&r.debug("Development server started successfully")}}const ut=t=>e(t).description("Create a new Fusion application from template").argument("<name>","Name of the application to create").option("-t, --template <type>","Template type to use (will prompt if not specified or not found)").option("-d, --directory <path>","Directory to create the app in",".").option("--branch <branch>","Branch to checkout","main").option("--clean","Clean the repo directory before cloning").option("--debug","Enable debug mode for verbose logging").action(async(e,t)=>{const r=new d("",{debug:t.debug});try{await dt(e,t,r)}catch(e){r.error("â An unexpected error occurred:",e instanceof Error?e.message:String(e)),t.debug&&r.error("Stack trace:",e instanceof Error?e.stack:"No stack trace available"),process.exit(1)}});Te.alias("build-pack").hook("preAction",e=>{"build-pack"===process.argv[3]&&(console.warn(Ie.bgRedBright.bold('The command "build-pack" is deprecated. Please use "pack" instead.')),e.getOptionValue("archive")||e.setOptionValue("archive",Ae))}),Be.alias("build-upload").hook("preAction",e=>{if("build-upload"===process.argv[3]){if(console.warn(Ie.bgRedBright.bold('The command "build-upload" is deprecated. Please use "upload" instead.')),e.getOptionValue("service"))throw new Error("The --service option is deprecated. Please use --env instead.");const t=e.getOptionValue("bundle")??Ae;process.argv[4]=t}}),We.alias("build-manifest").hook("preAction",()=>{"build-manifest"===process.argv[3]&&console.warn(Ie.bgRedBright.bold('The command "build-manifest" is deprecated. Please use "manifest" instead.'))}),Ke.alias("build-publish").hook("preAction",e=>{if("build-publish"===process.argv[3]&&console.warn(Ie.bgRedBright.bold('The command "build-publish" is deprecated. Please use "publish" instead.')),e.getOptionValue("service"))throw new Error("The --service option is deprecated. Please use --env instead.")});const pt=e("app").description("Develop, build, configure, and deploy Fusion applications from your workspace root.").addHelpText("after",["",'The "app" command is your main entry point for managing Fusion applications in this workspace.',"","It provides access to subcommands for every stage of the application lifecycle, including development, building, packaging, configuration, deployment, and release management.","","All available subcommands are listed below automatically. For details and options for a specific subcommand, run:"," fusion app <subcommand> --help","","Typical usage:"," - Create new applications from templates with the create subcommand"," - Run and test your app locally with the dev subcommand"," - Build, bundle, and configure your app for deployment"," - Upload, publish, and tag releases to the Fusion App Store"," - Check registration and generate manifests as needed","","This command should be run from your app root directory."].join("\n")).addCommand(Oe).addCommand(Te).addCommand(Ue).addCommand(Be).addCommand(ze).addCommand(Ve).addCommand(He).addCommand(We).addCommand(Ke).addCommand(ut("create")),ht=e("login").description("Authenticate and log in to Fusion Framework using interactive browser-based authentication.").addHelpText("after",["","WHAT HAPPENS WHEN YOU RUN THIS COMMAND:"," 1. Opens a browser window for Azure AD authentication"," 2. Prompts you to sign in with your Fusion credentials"," 3. Securely caches your tokens for future CLI commands"," 4. You only need to log in once per session","","Note: Requires interactive environment (won't work in CI/CD pipelines)","","Examples:"," $ ffc auth login"," $ ffc auth login --tenant my-tenant --client my-client-id --scope api://my-app/.default"].join("\n")).action(async e=>{const t=new d("auth:login",{debug:e.debug}),r="string"==typeof e.scope?[e.scope]:e.scope;t.start("Initializing Fusion Framework...");const n=await g({auth:{tenantId:e.tenantId,clientId:e.clientId,interactive:!0,server:{port:49741}}});t.succeed("Initialized Fusion Framework");try{t.start("Logging in...");const e=await n.auth.login({scopes:r});t.info("username:",Ie.green(e.account?.username)),t.info("tenant: ",Ie.yellow(e.tenantId)),t.info("audience:",Ie.yellow(e.account?.idTokenClaims?.aud));for(const r of e.scopes)t.info("scope: ",Ie.dim(r));t.succeed("Successfully logged in",Ie.greenBright(e.account?.name))}catch(r){throw t.fail("Failed to log in ðĨš",JSON.stringify({tenant:e.tenant,client:e.clientId},void 0,2)),r}});Ge(ht,{includeScope:!0,excludeToken:!0});const ft=e("logout").description("Log out from Fusion Framework and clear your authentication session.").addHelpText("after",["","WHAT THIS COMMAND DOES:"," - Removes your cached authentication tokens from local storage"," - Clears the current session (does not revoke tokens server-side)"," - You will need to run `ffc auth login` again for future commands","","WHEN TO USE THIS COMMAND:"," - When switching between different user accounts"," - When troubleshooting authentication issues"," - When your cached tokens have expired and you want a fresh login","","Examples:"," $ ffc auth logout"," $ ffc auth logout --tenant my-tenant --client my-client-id"].join("\n")).action(async e=>{const t=new d("auth:logout",{debug:e.debug});t.start("Initializing Fusion Framework...");const r=await g({auth:{tenantId:e.tenantId,clientId:e.clientId}});t.succeed("Initialized Fusion Framework");try{t.start("Logging in..."),await r.auth.logout(),t.succeed("Successfully logged out")}catch(r){throw t.fail("Failed to log out ðĨš",JSON.stringify({tenant:e.tenant,client:e.clientId},void 0,2)),r}});Ge(ft,{excludeToken:!0,includeScope:!1});class mt extends Error{static Name="NoAccountsError";constructor(e,t){super(e,t),this.name=mt.Name}}const gt=e("token").description("Acquire and print an access token for Fusion APIs using your current authentication context.").addHelpText("after",["","USAGE NOTES:"," - This command acquires an access token using your current interactive login session."," - It is intended for local development, manual testing, and debugging authentication issues.","","LIMITATIONS:"," - Requires an interactive user session (not suitable for CI/CD or headless environments)."," - Will only work if you have previously logged in using `ffc auth login`."," - Does NOT prompt for login; if no cached credentials are found, you must log in first."," - For automation or CI/CD, set the FUSION_TOKEN environment variable instead.","","BEST PRACTICES:"," - Use this command to quickly fetch a token for manual API calls or local scripts."," - Use the --silent flag to output only the token (useful for scripting or piping)."," - Specify --scope, --tenant, or --client for advanced scenarios.","","EXAMPLES:"," $ ffc auth token"," $ export MY_TOKEN=$(ffc auth token --silent)"," $ ffc auth token --scope api://my-app/.default"," $ ffc auth token --tenant my-tenant --client my-client-id --silent"].join("\n")).option("-d, --debug","Enable debug mode for verbose logging",!1).option("--silent","Only output the token (no extra logging)").action(async e=>{const t=e.silent?null:new d("auth:token",{debug:e.debug}),r="string"==typeof e.scope?[e.scope]:e.scope;t?.info("Using tenant",e.tenantId),t?.info("Using client",e.clientId),t?.info("Using scope",JSON.stringify(r)),t?.start("Initializing Fusion Framework...");const n=await g({auth:{tenantId:e.tenantId,clientId:e.clientId}});t?.succeed("Initialized Fusion Framework");try{t?.start("Getting access token...");const o=await n.auth.acquireAccessToken({scopes:r});t?.succeed("Successfully acquired access token"),e.silent?console.log(o):t?.info("Access token:",o)}catch(r){if(e.silent||!(r instanceof mt))throw r;t?.fail("No accounts found, please login first")}});Ge(gt,{includeScope:!0});const yt=new n("auth").description("Authenticate with Fusion Framework CLI").addHelpText("after",["","Authentication commands for Fusion Framework CLI.","","Use these commands to log in, log out, or acquire tokens for Fusion APIs.","","Examples:"," $ fusion-framework-cli auth login"," $ fusion-framework-cli auth logout"," $ fusion-framework-cli auth token --scope api://my-app/.default"].join("\n"));yt.addCommand(ht,{isDefault:!0}),yt.addCommand(ft),yt.addCommand(gt);const vt=e("create").description("Create new Fusion applications and components from templates").addHelpText("after",["",'The "create" command helps you bootstrap new Fusion applications and components',"using predefined templates from the Fusion ecosystem.","","Available templates:"," - app: Create a new Fusion application from the official template","","Examples:"," fusion create app my-new-app"," fusion create app my-new-app --template react",""].join("\n")).addCommand(ut("app")),bt=Ge(e("resolve").description("Resolve and display information about a service registered in Fusion service discovery.").addHelpText("after",["","This command looks up a service by name and prints its discovery details using the current authentication and environment.","","USEFUL FOR:"," - Finding service endpoints for API calls"," - Debugging service connectivity issues"," - Getting service metadata and configuration","","OUTPUT FORMATS:"," - Normal: Pretty-printed JSON with service details",' - Silent: Raw JSON only (useful for scripts: --silent | jq ".uri")',"","Examples:"," $ ffc disco resolve my-service",' $ ffc disco resolve my-service --silent | jq ".uri"'," $ ffc disco resolve my-service --env prod"," $ ffc disco resolve my-service --env test --tenantId my-tenant --clientId my-client-id"].join("\n")).addOption(xe({allowDev:!1})).option("--silent","Silent mode, suppresses output except errors").argument("<service>","Name of the service to resolve in Fusion service discovery").action(async(e,t)=>{const r=t.silent?null:new d("disco:resolve");r?.start("Initializing Fusion Framework...");const n=await g({env:t.environment,auth:{token:t.token,tenantId:t.tenantId,clientId:t.clientId}});r?.succeed("Initialized Fusion Framework"),r?.start(`Resolving service ${e}...`);const o=await n.serviceDiscovery.resolveService(e);r?.succeed(`Resolved service ${e}`),r?.debug(o),t.silent&&console.log(JSON.stringify(o,null,2))})),$t=e("disco").description("Service discovery operations");$t.addCommand(bt);const wt=e("dev").description("Start a local development server for the Fusion portal.").addHelpText("after",["","Examples:"," $ ffc portal dev"," $ ffc portal dev --port 4000"," $ ffc portal dev --debug"].join("\n")).option("--debug","Enable debug mode").option("--env <environment>","Runtime environment for the dev server","local").option("--port <port>","Port for the development server","3000").action(async e=>{const t=new d("portal:dev",{debug:e.debug});t.start("Starting portal in development mode..."),P({server:{port:Number(e.port)},log:t,env:e.env}),t.succeed("Development server started successfully.")});function Et(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var St,Pt,_t,Lt;function Ct(){if(Pt)return St;Pt=1;const e="object"==typeof process&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?(...e)=>console.error("SEMVER",...e):()=>{};return St=e}function kt(){if(Lt)return _t;Lt=1;const e=Number.MAX_SAFE_INTEGER||9007199254740991;return _t={MAX_LENGTH:256,MAX_SAFE_COMPONENT_LENGTH:16,MAX_SAFE_BUILD_LENGTH:250,MAX_SAFE_INTEGER:e,RELEASE_TYPES:["major","premajor","minor","preminor","patch","prepatch","prerelease"],SEMVER_SPEC_VERSION:"2.0.0",FLAG_INCLUDE_PRERELEASE:1,FLAG_LOOSE:2}}var Nt,It,Ot,At,Tt,xt,Dt,jt,Rt,Ft,Mt,Gt,Ut,Bt={exports:{}};function zt(){return Nt||(Nt=1,function(e,t){const{MAX_SAFE_COMPONENT_LENGTH:r,MAX_SAFE_BUILD_LENGTH:n,MAX_LENGTH:o}=kt(),i=Ct(),s=(t=e.exports={}).re=[],a=t.safeRe=[],c=t.src=[],l=t.safeSrc=[],d=t.t={};let u=0;const p="[a-zA-Z0-9-]",h=[["\\s",1],["\\d",o],[p,n]],f=(e,t,r)=>{const n=(e=>{for(const[t,r]of h)e=e.split(`${t}*`).join(`${t}{0,${r}}`).split(`${t}+`).join(`${t}{1,${r}}`);return e})(t),o=u++;i(e,o,t),d[e]=o,c[o]=t,l[o]=n,s[o]=new RegExp(t,r?"g":void 0),a[o]=new RegExp(n,r?"g":void 0)};f("NUMERICIDENTIFIER","0|[1-9]\\d*"),f("NUMERICIDENTIFIERLOOSE","\\d+"),f("NONNUMERICIDENTIFIER",`\\d*[a-zA-Z-]${p}*`),f("MAINVERSION",`(${c[d.NUMERICIDENTIFIER]})\\.(${c[d.NUMERICIDENTIFIER]})\\.(${c[d.NUMERICIDENTIFIER]})`),f("MAINVERSIONLOOSE",`(${c[d.NUMERICIDENTIFIERLOOSE]})\\.(${c[d.NUMERICIDENTIFIERLOOSE]})\\.(${c[d.NUMERICIDENTIFIERLOOSE]})`),f("PRERELEASEIDENTIFIER",`(?:${c[d.NONNUMERICIDENTIFIER]}|${c[d.NUMERICIDENTIFIER]})`),f("PRERELEASEIDENTIFIERLOOSE",`(?:${c[d.NONNUMERICIDENTIFIER]}|${c[d.NUMERICIDENTIFIERLOOSE]})`),f("PRERELEASE",`(?:-(${c[d.PRERELEASEIDENTIFIER]}(?:\\.${c[d.PRERELEASEIDENTIFIER