fimo 0.9.0-experimental.11 → 0.9.0-experimental.12

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.
@@ -138,13 +138,14 @@ component can appear on many pages too.
138
138
  Then, mechanically:
139
139
 
140
140
  - **Chrome** (header, footer, nav, menus, banners) is edited as ONE thing →
141
- a SINGLE TYPE per piece (`src/schemas/<Name>.json` with
142
- `"isSingleton": true`, real fields mirroring the source: nav items as an
143
- array/blocks field, logo as media), pushed with `npx fimo schemas push`,
144
- its ONE document written from the source values with
145
- `npx fimo documents set <Name> --body '<json>'` (singletons REJECT the
146
- entries endpoints), component rewired to read it. Never a loose label
147
- pile, never a collection.
141
+ a SINGLE TYPE per piece. **The machine now BUILDS these for you**: every
142
+ section it detects on 2+ pages (`"shared": true`) becomes a ready Single —
143
+ schema + filled document — in `.fimo/migration/shared-singles/<Uid>.json`
144
+ (listed under SHARED CHROME SINGLE TYPES in this prompt). For each: review &
145
+ rename fields, `npx fimo schemas push`, `npx fimo documents set <Uid>
146
+ --body '<json>'` (singletons REJECT the entries endpoints), and reference it
147
+ from every page that renders the chrome. Never a loose label pile, never a
148
+ collection, never orphan flat labels.
148
149
  - **Page-scoped structure** (a pricing page's FAQ list) → a component array
149
150
  on that page's Single, or a collection + reference when genuinely reused
150
151
  across pages. Never an orphan collection nobody can situate. CLAIM the
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "bundled": true,
3
3
  "bundler": "esbuild",
4
- "bundledAt": "2026-07-30T17:19:28.475Z",
4
+ "bundledAt": "2026-07-31T15:43:28.529Z",
5
5
  "cliVersion": "0.8.0",
6
6
  "external": [
7
7
  "oxc-parser",
package/dist/cli/index.js CHANGED
@@ -40,7 +40,7 @@ Expecting one of '${allowedValues.join("', '")}'`);return this._lifeCycleHooks[e
40
40
  `),this.outputHelp({error:!0}));let config=errorOptions||{},exitCode=config.exitCode||1,code2=config.code||"commander.error";this._exit(exitCode,code2,message)}_parseOptionsEnv(){this.options.forEach(option=>{if(option.envVar&&option.envVar in process8.env){let optionKey=option.attributeName();(this.getOptionValue(optionKey)===void 0||["default","config","env"].includes(this.getOptionValueSource(optionKey)))&&(option.required||option.optional?this.emit(`optionEnv:${option.name()}`,process8.env[option.envVar]):this.emit(`optionEnv:${option.name()}`))}})}_parseOptionsImplied(){let dualHelper=new DualOptions(this.options),hasCustomOptionValue=__name(optionKey=>this.getOptionValue(optionKey)!==void 0&&!["default","implied"].includes(this.getOptionValueSource(optionKey)),"hasCustomOptionValue");this.options.filter(option=>option.implied!==void 0&&hasCustomOptionValue(option.attributeName())&&dualHelper.valueFromOption(this.getOptionValue(option.attributeName()),option)).forEach(option=>{Object.keys(option.implied).filter(impliedKey=>!hasCustomOptionValue(impliedKey)).forEach(impliedKey=>{this.setOptionValueWithSource(impliedKey,option.implied[impliedKey],"implied")})})}missingArgument(name){let message=`error: missing required argument '${name}'`;this.error(message,{code:"commander.missingArgument"})}optionMissingArgument(option){let message=`error: option '${option.flags}' argument missing`;this.error(message,{code:"commander.optionMissingArgument"})}missingMandatoryOptionValue(option){let message=`error: required option '${option.flags}' not specified`;this.error(message,{code:"commander.missingMandatoryOptionValue"})}_conflictingOption(option,conflictingOption){let findBestOptionFromValue=__name(option2=>{let optionKey=option2.attributeName(),optionValue=this.getOptionValue(optionKey),negativeOption=this.options.find(target=>target.negate&&optionKey===target.attributeName()),positiveOption=this.options.find(target=>!target.negate&&optionKey===target.attributeName());return negativeOption&&(negativeOption.presetArg===void 0&&optionValue===!1||negativeOption.presetArg!==void 0&&optionValue===negativeOption.presetArg)?negativeOption:positiveOption||option2},"findBestOptionFromValue"),getErrorMessage=__name(option2=>{let bestOption=findBestOptionFromValue(option2),optionKey=bestOption.attributeName();return this.getOptionValueSource(optionKey)==="env"?`environment variable '${bestOption.envVar}'`:`option '${bestOption.flags}'`},"getErrorMessage"),message=`error: ${getErrorMessage(option)} cannot be used with ${getErrorMessage(conflictingOption)}`;this.error(message,{code:"commander.conflictingOption"})}unknownOption(flag2){if(this._allowUnknownOption)return;let suggestion="";if(flag2.startsWith("--")&&this._showSuggestionAfterError){let candidateFlags=[],command=this;do{let moreFlags=command.createHelp().visibleOptions(command).filter(option=>option.long).map(option=>option.long);candidateFlags=candidateFlags.concat(moreFlags),command=command.parent}while(command&&!command._enablePositionalOptions);suggestion=suggestSimilar(flag2,candidateFlags)}let message=`error: unknown option '${flag2}'${suggestion}`;this.error(message,{code:"commander.unknownOption"})}_excessArguments(receivedArgs){if(this._allowExcessArguments)return;let expected=this.registeredArguments.length,s=expected===1?"":"s",message=`error: too many arguments${this.parent?` for '${this.name()}'`:""}. Expected ${expected} argument${s} but got ${receivedArgs.length}.`;this.error(message,{code:"commander.excessArguments"})}unknownCommand(){let unknownName=this.args[0],suggestion="";if(this._showSuggestionAfterError){let candidateNames=[];this.createHelp().visibleCommands(this).forEach(command=>{candidateNames.push(command.name()),command.alias()&&candidateNames.push(command.alias())}),suggestion=suggestSimilar(unknownName,candidateNames)}let message=`error: unknown command '${unknownName}'${suggestion}`;this.error(message,{code:"commander.unknownCommand"})}version(str,flags,description){if(str===void 0)return this._version;this._version=str,flags=flags||"-V, --version",description=description||"output the version number";let versionOption=this.createOption(flags,description);return this._versionOptionName=versionOption.attributeName(),this._registerOption(versionOption),this.on("option:"+versionOption.name(),()=>{this._outputConfiguration.writeOut(`${str}
41
41
  `),this._exit(0,"commander.version",str)}),this}description(str,argsDescription){return str===void 0&&argsDescription===void 0?this._description:(this._description=str,argsDescription&&(this._argsDescription=argsDescription),this)}summary(str){return str===void 0?this._summary:(this._summary=str,this)}alias(alias){if(alias===void 0)return this._aliases[0];let command=this;if(this.commands.length!==0&&this.commands[this.commands.length-1]._executableHandler&&(command=this.commands[this.commands.length-1]),alias===command._name)throw new Error("Command alias can't be the same as its name");let matchingCommand=this.parent?._findCommand(alias);if(matchingCommand){let existingCmd=[matchingCommand.name()].concat(matchingCommand.aliases()).join("|");throw new Error(`cannot add alias '${alias}' to command '${this.name()}' as already have command '${existingCmd}'`)}return command._aliases.push(alias),this}aliases(aliases2){return aliases2===void 0?this._aliases:(aliases2.forEach(alias=>this.alias(alias)),this)}usage(str){if(str===void 0){if(this._usage)return this._usage;let args=this.registeredArguments.map(arg=>humanReadableArgName(arg));return[].concat(this.options.length||this._helpOption!==null?"[options]":[],this.commands.length?"[command]":[],this.registeredArguments.length?args:[]).join(" ")}return this._usage=str,this}name(str){return str===void 0?this._name:(this._name=str,this)}nameFromFilename(filename){return this._name=path71.basename(filename,path71.extname(filename)),this}executableDir(path72){return path72===void 0?this._executableDir:(this._executableDir=path72,this)}helpInformation(contextOptions){let helper=this.createHelp(),context=this._getOutputContext(contextOptions);helper.prepareContext({error:context.error,helpWidth:context.helpWidth,outputHasColors:context.hasColors});let text3=helper.formatHelp(this,helper);return context.hasColors?text3:this._outputConfiguration.stripColor(text3)}_getOutputContext(contextOptions){contextOptions=contextOptions||{};let error=!!contextOptions.error,baseWrite,hasColors,helpWidth;return error?(baseWrite=__name(str=>this._outputConfiguration.writeErr(str),"baseWrite"),hasColors=this._outputConfiguration.getErrHasColors(),helpWidth=this._outputConfiguration.getErrHelpWidth()):(baseWrite=__name(str=>this._outputConfiguration.writeOut(str),"baseWrite"),hasColors=this._outputConfiguration.getOutHasColors(),helpWidth=this._outputConfiguration.getOutHelpWidth()),{error,write:__name(str=>(hasColors||(str=this._outputConfiguration.stripColor(str)),baseWrite(str)),"write"),hasColors,helpWidth}}outputHelp(contextOptions){let deprecatedCallback;typeof contextOptions=="function"&&(deprecatedCallback=contextOptions,contextOptions=void 0);let outputContext=this._getOutputContext(contextOptions),eventContext={error:outputContext.error,write:outputContext.write,command:this};this._getCommandAndAncestors().reverse().forEach(command=>command.emit("beforeAllHelp",eventContext)),this.emit("beforeHelp",eventContext);let helpInformation=this.helpInformation({error:outputContext.error});if(deprecatedCallback&&(helpInformation=deprecatedCallback(helpInformation),typeof helpInformation!="string"&&!Buffer.isBuffer(helpInformation)))throw new Error("outputHelp callback must return a string or a Buffer");outputContext.write(helpInformation),this._getHelpOption()?.long&&this.emit(this._getHelpOption().long),this.emit("afterHelp",eventContext),this._getCommandAndAncestors().forEach(command=>command.emit("afterAllHelp",eventContext))}helpOption(flags,description){return typeof flags=="boolean"?(flags?this._helpOption=this._helpOption??void 0:this._helpOption=null,this):(flags=flags??"-h, --help",description=description??"display help for command",this._helpOption=this.createOption(flags,description),this)}_getHelpOption(){return this._helpOption===void 0&&this.helpOption(void 0,void 0),this._helpOption}addHelpOption(option){return this._helpOption=option,this}help(contextOptions){this.outputHelp(contextOptions);let exitCode=Number(process8.exitCode??0);exitCode===0&&contextOptions&&typeof contextOptions!="function"&&contextOptions.error&&(exitCode=1),this._exit(exitCode,"commander.help","(outputHelp)")}addHelpText(position,text3){let allowedValues=["beforeAll","before","after","afterAll"];if(!allowedValues.includes(position))throw new Error(`Unexpected value for position to addHelpText.
42
42
  Expecting one of '${allowedValues.join("', '")}'`);let helpEvent=`${position}Help`;return this.on(helpEvent,context=>{let helpStr;typeof text3=="function"?helpStr=text3({error:context.error,command:context.command}):helpStr=text3,helpStr&&context.write(`${helpStr}
43
- `)}),this}_outputHelpIfRequested(args){let helpOption=this._getHelpOption();helpOption&&args.find(arg=>helpOption.is(arg))&&(this.outputHelp(),this._exit(0,"commander.helpDisplayed","(outputHelp)"))}};function incrementNodeInspectorPort(args){return args.map(arg=>{if(!arg.startsWith("--inspect"))return arg;let debugOption,debugHost="127.0.0.1",debugPort="9229",match;return(match=arg.match(/^(--inspect(-brk)?)$/))!==null?debugOption=match[1]:(match=arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/))!==null?(debugOption=match[1],/^\d+$/.test(match[3])?debugPort=match[3]:debugHost=match[3]):(match=arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/))!==null&&(debugOption=match[1],debugHost=match[3],debugPort=match[4]),debugOption&&debugPort!=="0"?`${debugOption}=${debugHost}:${parseInt(debugPort)+1}`:arg})}__name(incrementNodeInspectorPort,"incrementNodeInspectorPort");function useColor(){if(process8.env.NO_COLOR||process8.env.FORCE_COLOR==="0"||process8.env.FORCE_COLOR==="false")return!1;if(process8.env.FORCE_COLOR||process8.env.CLICOLOR_FORCE!==void 0)return!0}__name(useColor,"useColor");exports2.Command=Command2;exports2.useColor=useColor}});var require_commander=__commonJS({"../../node_modules/.pnpm/commander@13.1.0/node_modules/commander/index.js"(exports2){var{Argument:Argument2}=require_argument(),{Command:Command2}=require_command(),{CommanderError:CommanderError2,InvalidArgumentError:InvalidArgumentError2}=require_error(),{Help:Help2}=require_help(),{Option:Option2}=require_option();exports2.program=new Command2;exports2.createCommand=name=>new Command2(name);exports2.createOption=(flags,description)=>new Option2(flags,description);exports2.createArgument=(name,description)=>new Argument2(name,description);exports2.Command=Command2;exports2.Option=Option2;exports2.Argument=Argument2;exports2.Help=Help2;exports2.CommanderError=CommanderError2;exports2.InvalidArgumentError=InvalidArgumentError2;exports2.InvalidOptionArgumentError=InvalidArgumentError2}});var detect_framework_exports={};__export(detect_framework_exports,{detectFramework:()=>detectFramework,findAdoptableApps:()=>findAdoptableApps});import{existsSync,readdirSync,readFileSync}from"node:fs";import{join,relative}from"node:path";function detectFramework(cwd){let pkgPath=join(cwd,"package.json");if(!existsSync(pkgPath))return{framework:null};let pkg;try{pkg=JSON.parse(readFileSync(pkgPath,"utf8"))}catch{return{framework:null}}let deps={...pkg.dependencies,...pkg.devDependencies};if(deps["@strapi/strapi"])return{framework:null};if(deps.next){let appDir=["app","src/app"].find(dir=>existsSync(join(cwd,dir))),pagesDir=["pages","src/pages"].find(dir=>existsSync(join(cwd,dir)));return{framework:"next",appDir,pagesDir}}if(deps["react-router"]||deps["@react-router/dev"])return{framework:"react-router"};if(deps["@remix-run/react"])return{framework:"remix",pagesDir:["app/routes"].find(dir=>existsSync(join(cwd,dir)))};if(deps.astro)return{framework:"astro",pagesDir:["src/pages"].find(dir=>existsSync(join(cwd,dir)))};if(deps.nuxt)return{framework:"nuxt",pagesDir:["pages","app/pages","src/pages"].find(dir=>existsSync(join(cwd,dir)))};if(deps["@sveltejs/kit"])return{framework:"sveltekit",pagesDir:["src/routes"].find(dir=>existsSync(join(cwd,dir)))};if(deps.vue&&deps.vite)return{framework:"vue"};if(deps.vite)return{framework:"vite",react:!!deps.react};let unsupportedByDep=[["gatsby","Gatsby"],["@angular/core","Angular"],["@docusaurus/core","Docusaurus"],["@11ty/eleventy","Eleventy"]];for(let[dep,name]of unsupportedByDep)if(deps[dep])return{framework:null,unsupported:name};return{framework:null}}function findAdoptableApps(rootDir){let apps2=[],walk2=__name((dir,depth)=>{if(depth>MAX_SCAN_DEPTH)return;if(dir!==rootDir&&existsSync(join(dir,"package.json"))){let detection=detectFramework(dir);if(detection.framework){apps2.push({dir,relDir:relative(rootDir,dir),detection});return}}let entries2;try{entries2=readdirSync(dir,{withFileTypes:!0})}catch{return}for(let entry of entries2)entry.isDirectory()&&!WORKSPACE_SKIP.has(entry.name)&&!entry.name.startsWith(".")&&walk2(join(dir,entry.name),depth+1)},"walk");return walk2(rootDir,0),apps2.sort((a,b)=>{let depthA=a.relDir.split("/").length,depthB=b.relDir.split("/").length,rank=__name(relDir=>relDir.startsWith("apps/")?0:1,"rank");return rank(a.relDir)-rank(b.relDir)||depthA-depthB||a.relDir.localeCompare(b.relDir)})}var WORKSPACE_SKIP,MAX_SCAN_DEPTH,init_detect_framework=__esm({"src/scripts/detect-framework.ts"(){__name(detectFramework,"detectFramework");WORKSPACE_SKIP=new Set(["node_modules",".git","dist","build","out",".next",".nuxt",".svelte-kit",".turbo",".vercel","coverage"]),MAX_SCAN_DEPTH=3;__name(findAdoptableApps,"findAdoptableApps")}});import{createHash}from"node:crypto";function normalizeApiUrl(input){let trimmed=input.trim();try{let url=new URL(trimmed),pathname=url.pathname.replace(/\/+$/,"");return`${url.protocol}//${url.host}${pathname}`}catch{return trimmed.replace(/\/+$/,"")}}function hashApiUrl(input){return createHash("sha256").update(normalizeApiUrl(input)).digest("hex").slice(0,6)}function safeHostLabel(host){return host.replace(/:/g,"-").replace(/[^a-zA-Z0-9.-]+/g,"-").replace(/^[.-]+|[.-]+$/g,"").toLowerCase()}function credentialsFilename(apiUrl){let normalized=normalizeApiUrl(apiUrl),hostLabel="unknown";try{hostLabel=safeHostLabel(new URL(normalized).host)}catch{}return hostLabel.length===0&&(hostLabel="unknown"),`${hostLabel}-${hashApiUrl(apiUrl)}.json`}var init_credentials_path=__esm({"src/cli/utils/credentials-path.ts"(){__name(normalizeApiUrl,"normalizeApiUrl");__name(hashApiUrl,"hashApiUrl");__name(safeHostLabel,"safeHostLabel");__name(credentialsFilename,"credentialsFilename")}});import fs,{readFileSync as readFileSync2}from"node:fs";import{homedir}from"node:os";import path,{join as join2}from"node:path";import{fileURLToPath}from"node:url";function readReleaseManifest(){try{let raw=fs.readFileSync(RELEASE_FILE,"utf8"),parsed=JSON.parse(raw),manifest={};return typeof parsed.apiUrl=="string"&&parsed.apiUrl.length>0&&(manifest.apiUrl=parsed.apiUrl),typeof parsed.webUrl=="string"&&parsed.webUrl.length>0&&(manifest.webUrl=parsed.webUrl),manifest}catch{return{}}}function configForApiUrl(apiUrl){let base=loadConfig(),target=apiUrl?.trim();return!target||target===base.apiUrl?base:{...base,apiUrl:target,credentialsFile:join2(base.credentialsDir,credentialsFilename(target))}}function configForCwd(cwd=process.cwd()){try{let raw=readFileSync2(join2(cwd,".fimo.settings.json"),"utf8"),parsed=JSON.parse(raw);if(typeof parsed.apiUrl=="string"&&parsed.apiUrl.length>0)return configForApiUrl(parsed.apiUrl)}catch{}return loadConfig()}function loadConfig(){let baked=readReleaseManifest(),apiUrl=process.env.FIMO_API_URL?.trim()||baked.apiUrl||DEFAULT_API_URL,webUrl=process.env.FIMO_WEB_URL?.trim()||baked.webUrl||DEFAULT_WEB_URL,configDir=join2(process.env.XDG_CONFIG_HOME||join2(homedir(),".config"),"fimo"),credentialsDir=join2(configDir,"credentials");return{apiUrl,webUrl,configDir,credentialsDir,credentialsFile:join2(credentialsDir,credentialsFilename(apiUrl))}}var DEFAULT_API_URL,DEFAULT_WEB_URL,THIS_FILE,CLI_ROOT,RELEASE_FILE,init_config=__esm({"src/cli/config.ts"(){init_credentials_path();DEFAULT_API_URL="http://localhost:3000",DEFAULT_WEB_URL="http://localhost:5173",THIS_FILE=fileURLToPath(import.meta.url),CLI_ROOT=path.resolve(path.dirname(THIS_FILE),"..",".."),RELEASE_FILE=path.resolve(CLI_ROOT,"release.json");__name(readReleaseManifest,"readReleaseManifest");__name(configForApiUrl,"configForApiUrl");__name(configForCwd,"configForCwd");__name(loadConfig,"loadConfig")}});import fs2 from"node:fs";function ensureCredentialsDir(cfg){fs2.existsSync(cfg.credentialsDir)||fs2.mkdirSync(cfg.credentialsDir,{recursive:!0})}function readCredentials(cfg=loadConfig()){if(!fs2.existsSync(cfg.credentialsFile))return null;let raw=fs2.readFileSync(cfg.credentialsFile,"utf-8");return JSON.parse(raw)}function writeCredentials(credentials,cfg=loadConfig()){ensureCredentialsDir(cfg);let tmpFile=`${cfg.credentialsFile}.tmp-${process.pid}`;fs2.writeFileSync(tmpFile,JSON.stringify(credentials,null,2)),fs2.renameSync(tmpFile,cfg.credentialsFile)}function clearCredentials(cfg=loadConfig()){fs2.existsSync(cfg.credentialsFile)&&fs2.unlinkSync(cfg.credentialsFile)}function setActiveOrganization(organization,cfg=loadConfig()){let creds=requireCredentials(cfg);writeCredentials({...creds,activeOrganization:organization},cfg)}function recordAuthFailure(cfg=loadConfig()){let creds=readCredentials(cfg);creds&&writeCredentials({...creds,lastFailedAuthAt:new Date().toISOString()},cfg)}function requireToken(cfg=loadConfig()){return requireCredentials(cfg).access_token}function requireCredentials(cfg=loadConfig()){let creds=readCredentials(cfg);if(!creds?.access_token)throw new NotAuthenticatedError(cfg.apiUrl);return creds}var NotAuthenticatedError,init_auth=__esm({"src/cli/auth.ts"(){init_config();NotAuthenticatedError=class extends Error{static{__name(this,"NotAuthenticatedError")}apiUrl;constructor(apiUrl,message="You are not signed in to Fimo."){super(message),this.name="NotAuthenticatedError",this.apiUrl=apiUrl}};__name(ensureCredentialsDir,"ensureCredentialsDir");__name(readCredentials,"readCredentials");__name(writeCredentials,"writeCredentials");__name(clearCredentials,"clearCredentials");__name(setActiveOrganization,"setActiveOrganization");__name(recordAuthFailure,"recordAuthFailure");__name(requireToken,"requireToken");__name(requireCredentials,"requireCredentials")}});import{spawnSync}from"node:child_process";import fs3 from"node:fs";import path2 from"node:path";import{setTimeout as sleep}from"node:timers/promises";function isPublishedInstall(cliRoot=CLI_ROOT){return fs3.existsSync(path2.join(cliRoot,"release.json"))}function resolveGlobalFimoRoot(){let result=spawnSync("npm",["root","-g"],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:GLOBAL_ROOT_TIMEOUT_MS});return result.error||result.status!==0||typeof result.stdout!="string"||result.stdout.trim().length===0?null:path2.resolve(result.stdout.trim(),"fimo")}function normalizedPath(input){try{return fs3.realpathSync(input)}catch{return path2.resolve(input)}}function autoUpgradeEnabled(options={}){let usesDefaults=Object.keys(options).length===0;if(usesDefaults&&defaultEligibility!==void 0)return defaultEligibility;let env=options.env??process.env,cliRoot=options.cliRoot??CLI_ROOT,published=options.published??isPublishedInstall(cliRoot);if(env.FIMO_AUTO_UPGRADE!=="1"||!published)return usesDefaults&&(defaultEligibility=!1),!1;let globalFimoRoot=options.globalFimoRoot===void 0?resolveGlobalFimoRoot():options.globalFimoRoot;if(!globalFimoRoot)return usesDefaults&&(defaultEligibility=!1),!1;let eligible=normalizedPath(cliRoot)===normalizedPath(globalFimoRoot);return usesDefaults&&(defaultEligibility=eligible),eligible}async function acquireLock(lockDir){let deadline=Date.now()+LOCK_WAIT_MS;for(;;){try{fs3.mkdirSync(lockDir);return}catch(error){if(error.code!=="EEXIST")throw error}let stale=!1;try{stale=Date.now()-fs3.statSync(lockDir).mtimeMs>LOCK_STALE_MS}catch{continue}if(stale){try{fs3.rmdirSync(lockDir)}catch{}continue}if(Date.now()>=deadline)throw new Error("auto-upgrade lock timeout");await sleep(LOCK_POLL_MS)}}function readGlobalFimoVersion(){let root2=resolveGlobalFimoRoot();if(!root2)return null;try{let pkg=JSON.parse(fs3.readFileSync(path2.join(root2,"package.json"),"utf8"));return typeof pkg.version=="string"?pkg.version:null}catch{return null}}async function autoUpgradeGlobal(latest){if(!VERSION_PATTERN.test(latest))return!1;let lockDir=path2.join(loadConfig().configDir,"auto-upgrade.lock");try{fs3.mkdirSync(path2.dirname(lockDir),{recursive:!0}),await acquireLock(lockDir)}catch{return!1}try{if(readGlobalFimoVersion()===latest)return!0;let install=spawnSync("npm",["install","-g",`fimo@${latest}`],{stdio:["ignore","ignore","inherit"],timeout:INSTALL_TIMEOUT_MS});return install.error||install.status!==0?!1:readGlobalFimoVersion()===latest}finally{try{fs3.rmdirSync(lockDir)}catch{}}}var INSTALL_TIMEOUT_MS,GLOBAL_ROOT_TIMEOUT_MS,LOCK_WAIT_MS,LOCK_STALE_MS,LOCK_POLL_MS,VERSION_PATTERN,defaultEligibility,init_auto_upgrade=__esm({"src/cli/auto-upgrade.ts"(){init_config();INSTALL_TIMEOUT_MS=12e4,GLOBAL_ROOT_TIMEOUT_MS=5e3,LOCK_WAIT_MS=18e4,LOCK_STALE_MS=3e5,LOCK_POLL_MS=500,VERSION_PATTERN=/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;__name(isPublishedInstall,"isPublishedInstall");__name(resolveGlobalFimoRoot,"resolveGlobalFimoRoot");__name(normalizedPath,"normalizedPath");__name(autoUpgradeEnabled,"autoUpgradeEnabled");__name(acquireLock,"acquireLock");__name(readGlobalFimoVersion,"readGlobalFimoVersion");__name(autoUpgradeGlobal,"autoUpgradeGlobal")}});var isAmbiguous,isFullWidth,isWide,init_utils=__esm({"../../node_modules/.pnpm/fast-string-truncated-width@1.2.1/node_modules/fast-string-truncated-width/dist/utils.js"(){isAmbiguous=__name(x=>x===161||x===164||x===167||x===168||x===170||x===173||x===174||x>=176&&x<=180||x>=182&&x<=186||x>=188&&x<=191||x===198||x===208||x===215||x===216||x>=222&&x<=225||x===230||x>=232&&x<=234||x===236||x===237||x===240||x===242||x===243||x>=247&&x<=250||x===252||x===254||x===257||x===273||x===275||x===283||x===294||x===295||x===299||x>=305&&x<=307||x===312||x>=319&&x<=322||x===324||x>=328&&x<=331||x===333||x===338||x===339||x===358||x===359||x===363||x===462||x===464||x===466||x===468||x===470||x===472||x===474||x===476||x===593||x===609||x===708||x===711||x>=713&&x<=715||x===717||x===720||x>=728&&x<=731||x===733||x===735||x>=768&&x<=879||x>=913&&x<=929||x>=931&&x<=937||x>=945&&x<=961||x>=963&&x<=969||x===1025||x>=1040&&x<=1103||x===1105||x===8208||x>=8211&&x<=8214||x===8216||x===8217||x===8220||x===8221||x>=8224&&x<=8226||x>=8228&&x<=8231||x===8240||x===8242||x===8243||x===8245||x===8251||x===8254||x===8308||x===8319||x>=8321&&x<=8324||x===8364||x===8451||x===8453||x===8457||x===8467||x===8470||x===8481||x===8482||x===8486||x===8491||x===8531||x===8532||x>=8539&&x<=8542||x>=8544&&x<=8555||x>=8560&&x<=8569||x===8585||x>=8592&&x<=8601||x===8632||x===8633||x===8658||x===8660||x===8679||x===8704||x===8706||x===8707||x===8711||x===8712||x===8715||x===8719||x===8721||x===8725||x===8730||x>=8733&&x<=8736||x===8739||x===8741||x>=8743&&x<=8748||x===8750||x>=8756&&x<=8759||x===8764||x===8765||x===8776||x===8780||x===8786||x===8800||x===8801||x>=8804&&x<=8807||x===8810||x===8811||x===8814||x===8815||x===8834||x===8835||x===8838||x===8839||x===8853||x===8857||x===8869||x===8895||x===8978||x>=9312&&x<=9449||x>=9451&&x<=9547||x>=9552&&x<=9587||x>=9600&&x<=9615||x>=9618&&x<=9621||x===9632||x===9633||x>=9635&&x<=9641||x===9650||x===9651||x===9654||x===9655||x===9660||x===9661||x===9664||x===9665||x>=9670&&x<=9672||x===9675||x>=9678&&x<=9681||x>=9698&&x<=9701||x===9711||x===9733||x===9734||x===9737||x===9742||x===9743||x===9756||x===9758||x===9792||x===9794||x===9824||x===9825||x>=9827&&x<=9829||x>=9831&&x<=9834||x===9836||x===9837||x===9839||x===9886||x===9887||x===9919||x>=9926&&x<=9933||x>=9935&&x<=9939||x>=9941&&x<=9953||x===9955||x===9960||x===9961||x>=9963&&x<=9969||x===9972||x>=9974&&x<=9977||x===9979||x===9980||x===9982||x===9983||x===10045||x>=10102&&x<=10111||x>=11094&&x<=11097||x>=12872&&x<=12879||x>=57344&&x<=63743||x>=65024&&x<=65039||x===65533||x>=127232&&x<=127242||x>=127248&&x<=127277||x>=127280&&x<=127337||x>=127344&&x<=127373||x===127375||x===127376||x>=127387&&x<=127404||x>=917760&&x<=917999||x>=983040&&x<=1048573||x>=1048576&&x<=1114109,"isAmbiguous"),isFullWidth=__name(x=>x===12288||x>=65281&&x<=65376||x>=65504&&x<=65510,"isFullWidth"),isWide=__name(x=>x>=4352&&x<=4447||x===8986||x===8987||x===9001||x===9002||x>=9193&&x<=9196||x===9200||x===9203||x===9725||x===9726||x===9748||x===9749||x>=9800&&x<=9811||x===9855||x===9875||x===9889||x===9898||x===9899||x===9917||x===9918||x===9924||x===9925||x===9934||x===9940||x===9962||x===9970||x===9971||x===9973||x===9978||x===9981||x===9989||x===9994||x===9995||x===10024||x===10060||x===10062||x>=10067&&x<=10069||x===10071||x>=10133&&x<=10135||x===10160||x===10175||x===11035||x===11036||x===11088||x===11093||x>=11904&&x<=11929||x>=11931&&x<=12019||x>=12032&&x<=12245||x>=12272&&x<=12287||x>=12289&&x<=12350||x>=12353&&x<=12438||x>=12441&&x<=12543||x>=12549&&x<=12591||x>=12593&&x<=12686||x>=12688&&x<=12771||x>=12783&&x<=12830||x>=12832&&x<=12871||x>=12880&&x<=19903||x>=19968&&x<=42124||x>=42128&&x<=42182||x>=43360&&x<=43388||x>=44032&&x<=55203||x>=63744&&x<=64255||x>=65040&&x<=65049||x>=65072&&x<=65106||x>=65108&&x<=65126||x>=65128&&x<=65131||x>=94176&&x<=94180||x===94192||x===94193||x>=94208&&x<=100343||x>=100352&&x<=101589||x>=101632&&x<=101640||x>=110576&&x<=110579||x>=110581&&x<=110587||x===110589||x===110590||x>=110592&&x<=110882||x===110898||x>=110928&&x<=110930||x===110933||x>=110948&&x<=110951||x>=110960&&x<=111355||x===126980||x===127183||x===127374||x>=127377&&x<=127386||x>=127488&&x<=127490||x>=127504&&x<=127547||x>=127552&&x<=127560||x===127568||x===127569||x>=127584&&x<=127589||x>=127744&&x<=127776||x>=127789&&x<=127797||x>=127799&&x<=127868||x>=127870&&x<=127891||x>=127904&&x<=127946||x>=127951&&x<=127955||x>=127968&&x<=127984||x===127988||x>=127992&&x<=128062||x===128064||x>=128066&&x<=128252||x>=128255&&x<=128317||x>=128331&&x<=128334||x>=128336&&x<=128359||x===128378||x===128405||x===128406||x===128420||x>=128507&&x<=128591||x>=128640&&x<=128709||x===128716||x>=128720&&x<=128722||x>=128725&&x<=128727||x>=128732&&x<=128735||x===128747||x===128748||x>=128756&&x<=128764||x>=128992&&x<=129003||x===129008||x>=129292&&x<=129338||x>=129340&&x<=129349||x>=129351&&x<=129535||x>=129648&&x<=129660||x>=129664&&x<=129672||x>=129680&&x<=129725||x>=129727&&x<=129733||x>=129742&&x<=129755||x>=129760&&x<=129768||x>=129776&&x<=129784||x>=131072&&x<=196605||x>=196608&&x<=262141,"isWide")}});var ANSI_RE,CONTROL_RE,TAB_RE,EMOJI_RE,LATIN_RE,MODIFIER_RE,NO_TRUNCATION,getStringTruncatedWidth,dist_default,init_dist2=__esm({"../../node_modules/.pnpm/fast-string-truncated-width@1.2.1/node_modules/fast-string-truncated-width/dist/index.js"(){init_utils();ANSI_RE=/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/y,CONTROL_RE=/[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y,TAB_RE=/\t{1,1000}/y,EMOJI_RE=new RegExp("[\\u{1F1E6}-\\u{1F1FF}]{2}|\\u{1F3F4}[\\u{E0061}-\\u{E007A}]{2}[\\u{E0030}-\\u{E0039}\\u{E0061}-\\u{E007A}]{1,3}\\u{E007F}|(?:\\p{Emoji}\\uFE0F\\u20E3?|\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation})(?:\\u200D(?:\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation}|\\p{Emoji}\\uFE0F\\u20E3?))*","yu"),LATIN_RE=/(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y,MODIFIER_RE=new RegExp("\\p{M}+","gu"),NO_TRUNCATION={limit:1/0,ellipsis:""},getStringTruncatedWidth=__name((input,truncationOptions={},widthOptions={})=>{let LIMIT=truncationOptions.limit??1/0,ELLIPSIS=truncationOptions.ellipsis??"",ELLIPSIS_WIDTH=truncationOptions?.ellipsisWidth??(ELLIPSIS?getStringTruncatedWidth(ELLIPSIS,NO_TRUNCATION,widthOptions).width:0),ANSI_WIDTH=widthOptions.ansiWidth??0,CONTROL_WIDTH=widthOptions.controlWidth??0,TAB_WIDTH=widthOptions.tabWidth??8,AMBIGUOUS_WIDTH=widthOptions.ambiguousWidth??1,EMOJI_WIDTH=widthOptions.emojiWidth??2,FULL_WIDTH_WIDTH=widthOptions.fullWidthWidth??2,REGULAR_WIDTH=widthOptions.regularWidth??1,WIDE_WIDTH=widthOptions.wideWidth??2,indexPrev=0,index2=0,length=input.length,lengthExtra=0,truncationEnabled=!1,truncationIndex=length,truncationLimit=Math.max(0,LIMIT-ELLIPSIS_WIDTH),unmatchedStart=0,unmatchedEnd=0,width=0,widthExtra=0;outer:for(;;){if(unmatchedEnd>unmatchedStart||index2>=length&&index2>indexPrev){let unmatched=input.slice(unmatchedStart,unmatchedEnd)||input.slice(indexPrev,index2);lengthExtra=0;for(let char of unmatched.replaceAll(MODIFIER_RE,"")){let codePoint=char.codePointAt(0)||0;if(isFullWidth(codePoint)?widthExtra=FULL_WIDTH_WIDTH:isWide(codePoint)?widthExtra=WIDE_WIDTH:AMBIGUOUS_WIDTH!==REGULAR_WIDTH&&isAmbiguous(codePoint)?widthExtra=AMBIGUOUS_WIDTH:widthExtra=REGULAR_WIDTH,width+widthExtra>truncationLimit&&(truncationIndex=Math.min(truncationIndex,Math.max(unmatchedStart,indexPrev)+lengthExtra)),width+widthExtra>LIMIT){truncationEnabled=!0;break outer}lengthExtra+=char.length,width+=widthExtra}unmatchedStart=unmatchedEnd=0}if(index2>=length)break;if(LATIN_RE.lastIndex=index2,LATIN_RE.test(input)){if(lengthExtra=LATIN_RE.lastIndex-index2,widthExtra=lengthExtra*REGULAR_WIDTH,width+widthExtra>truncationLimit&&(truncationIndex=Math.min(truncationIndex,index2+Math.floor((truncationLimit-width)/REGULAR_WIDTH))),width+widthExtra>LIMIT){truncationEnabled=!0;break}width+=widthExtra,unmatchedStart=indexPrev,unmatchedEnd=index2,index2=indexPrev=LATIN_RE.lastIndex;continue}if(ANSI_RE.lastIndex=index2,ANSI_RE.test(input)){if(width+ANSI_WIDTH>truncationLimit&&(truncationIndex=Math.min(truncationIndex,index2)),width+ANSI_WIDTH>LIMIT){truncationEnabled=!0;break}width+=ANSI_WIDTH,unmatchedStart=indexPrev,unmatchedEnd=index2,index2=indexPrev=ANSI_RE.lastIndex;continue}if(CONTROL_RE.lastIndex=index2,CONTROL_RE.test(input)){if(lengthExtra=CONTROL_RE.lastIndex-index2,widthExtra=lengthExtra*CONTROL_WIDTH,width+widthExtra>truncationLimit&&(truncationIndex=Math.min(truncationIndex,index2+Math.floor((truncationLimit-width)/CONTROL_WIDTH))),width+widthExtra>LIMIT){truncationEnabled=!0;break}width+=widthExtra,unmatchedStart=indexPrev,unmatchedEnd=index2,index2=indexPrev=CONTROL_RE.lastIndex;continue}if(TAB_RE.lastIndex=index2,TAB_RE.test(input)){if(lengthExtra=TAB_RE.lastIndex-index2,widthExtra=lengthExtra*TAB_WIDTH,width+widthExtra>truncationLimit&&(truncationIndex=Math.min(truncationIndex,index2+Math.floor((truncationLimit-width)/TAB_WIDTH))),width+widthExtra>LIMIT){truncationEnabled=!0;break}width+=widthExtra,unmatchedStart=indexPrev,unmatchedEnd=index2,index2=indexPrev=TAB_RE.lastIndex;continue}if(EMOJI_RE.lastIndex=index2,EMOJI_RE.test(input)){if(width+EMOJI_WIDTH>truncationLimit&&(truncationIndex=Math.min(truncationIndex,index2)),width+EMOJI_WIDTH>LIMIT){truncationEnabled=!0;break}width+=EMOJI_WIDTH,unmatchedStart=indexPrev,unmatchedEnd=index2,index2=indexPrev=EMOJI_RE.lastIndex;continue}index2+=1}return{width:truncationEnabled?truncationLimit:width,index:truncationEnabled?truncationIndex:length,truncated:truncationEnabled,ellipsed:truncationEnabled&&LIMIT>=ELLIPSIS_WIDTH}},"getStringTruncatedWidth"),dist_default=getStringTruncatedWidth}});var NO_TRUNCATION2,fastStringWidth,dist_default2,init_dist3=__esm({"../../node_modules/.pnpm/fast-string-width@1.1.0/node_modules/fast-string-width/dist/index.js"(){init_dist2();NO_TRUNCATION2={limit:1/0,ellipsis:"",ellipsisWidth:0},fastStringWidth=__name((input,options={})=>dist_default(input,NO_TRUNCATION2,options).width,"fastStringWidth"),dist_default2=fastStringWidth}});function wrapAnsi(string,columns,options){return String(string).normalize().split(CRLF_OR_LF).map(line=>exec(line,columns,options)).join(`
43
+ `)}),this}_outputHelpIfRequested(args){let helpOption=this._getHelpOption();helpOption&&args.find(arg=>helpOption.is(arg))&&(this.outputHelp(),this._exit(0,"commander.helpDisplayed","(outputHelp)"))}};function incrementNodeInspectorPort(args){return args.map(arg=>{if(!arg.startsWith("--inspect"))return arg;let debugOption,debugHost="127.0.0.1",debugPort="9229",match;return(match=arg.match(/^(--inspect(-brk)?)$/))!==null?debugOption=match[1]:(match=arg.match(/^(--inspect(-brk|-port)?)=([^:]+)$/))!==null?(debugOption=match[1],/^\d+$/.test(match[3])?debugPort=match[3]:debugHost=match[3]):(match=arg.match(/^(--inspect(-brk|-port)?)=([^:]+):(\d+)$/))!==null&&(debugOption=match[1],debugHost=match[3],debugPort=match[4]),debugOption&&debugPort!=="0"?`${debugOption}=${debugHost}:${parseInt(debugPort)+1}`:arg})}__name(incrementNodeInspectorPort,"incrementNodeInspectorPort");function useColor(){if(process8.env.NO_COLOR||process8.env.FORCE_COLOR==="0"||process8.env.FORCE_COLOR==="false")return!1;if(process8.env.FORCE_COLOR||process8.env.CLICOLOR_FORCE!==void 0)return!0}__name(useColor,"useColor");exports2.Command=Command2;exports2.useColor=useColor}});var require_commander=__commonJS({"../../node_modules/.pnpm/commander@13.1.0/node_modules/commander/index.js"(exports2){var{Argument:Argument2}=require_argument(),{Command:Command2}=require_command(),{CommanderError:CommanderError2,InvalidArgumentError:InvalidArgumentError2}=require_error(),{Help:Help2}=require_help(),{Option:Option2}=require_option();exports2.program=new Command2;exports2.createCommand=name=>new Command2(name);exports2.createOption=(flags,description)=>new Option2(flags,description);exports2.createArgument=(name,description)=>new Argument2(name,description);exports2.Command=Command2;exports2.Option=Option2;exports2.Argument=Argument2;exports2.Help=Help2;exports2.CommanderError=CommanderError2;exports2.InvalidArgumentError=InvalidArgumentError2;exports2.InvalidOptionArgumentError=InvalidArgumentError2}});var detect_framework_exports={};__export(detect_framework_exports,{detectFramework:()=>detectFramework,findAdoptableApps:()=>findAdoptableApps});import{existsSync,readdirSync,readFileSync}from"node:fs";import{join,relative}from"node:path";function hasHtmlEntry(cwd){return existsSync(join(cwd,"index.html"))}function detectFramework(cwd){let pkgPath=join(cwd,"package.json");if(!existsSync(pkgPath))return{framework:null};let pkg;try{pkg=JSON.parse(readFileSync(pkgPath,"utf8"))}catch{return{framework:null}}let deps={...pkg.dependencies,...pkg.devDependencies};if(deps["@strapi/strapi"])return{framework:null};if(deps.next){let appDir=["app","src/app"].find(dir=>existsSync(join(cwd,dir))),pagesDir=["pages","src/pages"].find(dir=>existsSync(join(cwd,dir)));return{framework:"next",appDir,pagesDir}}if(deps["@react-router/dev"])return{framework:"react-router"};if(deps["react-router"]&&hasHtmlEntry(cwd))return{framework:"react-router"};if(deps["@remix-run/react"])return{framework:"remix",pagesDir:["app/routes"].find(dir=>existsSync(join(cwd,dir)))};if(deps.astro)return{framework:"astro",pagesDir:["src/pages"].find(dir=>existsSync(join(cwd,dir)))};if(deps.nuxt)return{framework:"nuxt",pagesDir:["pages","app/pages","src/pages"].find(dir=>existsSync(join(cwd,dir)))};if(deps["@sveltejs/kit"])return{framework:"sveltekit",pagesDir:["src/routes"].find(dir=>existsSync(join(cwd,dir)))};if(deps.vue&&deps.vite&&hasHtmlEntry(cwd))return{framework:"vue"};if(deps.vite&&hasHtmlEntry(cwd))return{framework:"vite",react:!!deps.react};let unsupportedByDep=[["gatsby","Gatsby"],["@angular/core","Angular"],["@docusaurus/core","Docusaurus"],["@11ty/eleventy","Eleventy"]];for(let[dep,name]of unsupportedByDep)if(deps[dep])return{framework:null,unsupported:name};return{framework:null}}function findAdoptableApps(rootDir){let apps2=[],walk2=__name((dir,depth)=>{if(depth>MAX_SCAN_DEPTH)return;if(dir!==rootDir&&existsSync(join(dir,"package.json"))){let detection=detectFramework(dir);if(detection.framework){apps2.push({dir,relDir:relative(rootDir,dir),detection});return}}let entries2;try{entries2=readdirSync(dir,{withFileTypes:!0})}catch{return}for(let entry of entries2)entry.isDirectory()&&!WORKSPACE_SKIP.has(entry.name)&&!NON_SITE_DIRS.has(entry.name.toLowerCase())&&!entry.name.startsWith(".")&&!entry.name.startsWith("_")&&walk2(join(dir,entry.name),depth+1)},"walk");return walk2(rootDir,0),apps2.sort((a,b)=>{let depthA=a.relDir.split("/").length,depthB=b.relDir.split("/").length,rank=__name(relDir=>relDir.startsWith("apps/")?0:1,"rank");return rank(a.relDir)-rank(b.relDir)||depthA-depthB||a.relDir.localeCompare(b.relDir)})}var WORKSPACE_SKIP,NON_SITE_DIRS,MAX_SCAN_DEPTH,init_detect_framework=__esm({"src/scripts/detect-framework.ts"(){__name(hasHtmlEntry,"hasHtmlEntry");__name(detectFramework,"detectFramework");WORKSPACE_SKIP=new Set(["node_modules",".git","dist","build","out",".next",".nuxt",".svelte-kit",".turbo",".vercel","coverage"]),NON_SITE_DIRS=new Set(["examples","example","fixtures","__fixtures__","__tests__","test","tests","e2e","evals","eval","benchmarks","bench","demo","demos","sandbox","sandboxes","playground","tools","scripts","templates","template"]),MAX_SCAN_DEPTH=3;__name(findAdoptableApps,"findAdoptableApps")}});import{createHash}from"node:crypto";function normalizeApiUrl(input){let trimmed=input.trim();try{let url=new URL(trimmed),pathname=url.pathname.replace(/\/+$/,"");return`${url.protocol}//${url.host}${pathname}`}catch{return trimmed.replace(/\/+$/,"")}}function hashApiUrl(input){return createHash("sha256").update(normalizeApiUrl(input)).digest("hex").slice(0,6)}function safeHostLabel(host){return host.replace(/:/g,"-").replace(/[^a-zA-Z0-9.-]+/g,"-").replace(/^[.-]+|[.-]+$/g,"").toLowerCase()}function credentialsFilename(apiUrl){let normalized=normalizeApiUrl(apiUrl),hostLabel="unknown";try{hostLabel=safeHostLabel(new URL(normalized).host)}catch{}return hostLabel.length===0&&(hostLabel="unknown"),`${hostLabel}-${hashApiUrl(apiUrl)}.json`}var init_credentials_path=__esm({"src/cli/utils/credentials-path.ts"(){__name(normalizeApiUrl,"normalizeApiUrl");__name(hashApiUrl,"hashApiUrl");__name(safeHostLabel,"safeHostLabel");__name(credentialsFilename,"credentialsFilename")}});import fs,{readFileSync as readFileSync2}from"node:fs";import{homedir}from"node:os";import path,{join as join2}from"node:path";import{fileURLToPath}from"node:url";function readReleaseManifest(){try{let raw=fs.readFileSync(RELEASE_FILE,"utf8"),parsed=JSON.parse(raw),manifest={};return typeof parsed.apiUrl=="string"&&parsed.apiUrl.length>0&&(manifest.apiUrl=parsed.apiUrl),typeof parsed.webUrl=="string"&&parsed.webUrl.length>0&&(manifest.webUrl=parsed.webUrl),manifest}catch{return{}}}function configForApiUrl(apiUrl){let base=loadConfig(),target=apiUrl?.trim();return!target||target===base.apiUrl?base:{...base,apiUrl:target,credentialsFile:join2(base.credentialsDir,credentialsFilename(target))}}function configForCwd(cwd=process.cwd()){try{let raw=readFileSync2(join2(cwd,".fimo.settings.json"),"utf8"),parsed=JSON.parse(raw);if(typeof parsed.apiUrl=="string"&&parsed.apiUrl.length>0)return configForApiUrl(parsed.apiUrl)}catch{}return loadConfig()}function loadConfig(){let baked=readReleaseManifest(),apiUrl=process.env.FIMO_API_URL?.trim()||baked.apiUrl||DEFAULT_API_URL,webUrl=process.env.FIMO_WEB_URL?.trim()||baked.webUrl||DEFAULT_WEB_URL,configDir=join2(process.env.XDG_CONFIG_HOME||join2(homedir(),".config"),"fimo"),credentialsDir=join2(configDir,"credentials");return{apiUrl,webUrl,configDir,credentialsDir,credentialsFile:join2(credentialsDir,credentialsFilename(apiUrl))}}var DEFAULT_API_URL,DEFAULT_WEB_URL,THIS_FILE,CLI_ROOT,RELEASE_FILE,init_config=__esm({"src/cli/config.ts"(){init_credentials_path();DEFAULT_API_URL="http://localhost:3000",DEFAULT_WEB_URL="http://localhost:5173",THIS_FILE=fileURLToPath(import.meta.url),CLI_ROOT=path.resolve(path.dirname(THIS_FILE),"..",".."),RELEASE_FILE=path.resolve(CLI_ROOT,"release.json");__name(readReleaseManifest,"readReleaseManifest");__name(configForApiUrl,"configForApiUrl");__name(configForCwd,"configForCwd");__name(loadConfig,"loadConfig")}});import fs2 from"node:fs";function ensureCredentialsDir(cfg){fs2.existsSync(cfg.credentialsDir)||fs2.mkdirSync(cfg.credentialsDir,{recursive:!0})}function readCredentials(cfg=loadConfig()){if(!fs2.existsSync(cfg.credentialsFile))return null;let raw=fs2.readFileSync(cfg.credentialsFile,"utf-8");return JSON.parse(raw)}function writeCredentials(credentials,cfg=loadConfig()){ensureCredentialsDir(cfg);let tmpFile=`${cfg.credentialsFile}.tmp-${process.pid}`;fs2.writeFileSync(tmpFile,JSON.stringify(credentials,null,2)),fs2.renameSync(tmpFile,cfg.credentialsFile)}function clearCredentials(cfg=loadConfig()){fs2.existsSync(cfg.credentialsFile)&&fs2.unlinkSync(cfg.credentialsFile)}function setActiveOrganization(organization,cfg=loadConfig()){let creds=requireCredentials(cfg);writeCredentials({...creds,activeOrganization:organization},cfg)}function recordAuthFailure(cfg=loadConfig()){let creds=readCredentials(cfg);creds&&writeCredentials({...creds,lastFailedAuthAt:new Date().toISOString()},cfg)}function requireToken(cfg=loadConfig()){return requireCredentials(cfg).access_token}function requireCredentials(cfg=loadConfig()){let creds=readCredentials(cfg);if(!creds?.access_token)throw new NotAuthenticatedError(cfg.apiUrl);return creds}var NotAuthenticatedError,init_auth=__esm({"src/cli/auth.ts"(){init_config();NotAuthenticatedError=class extends Error{static{__name(this,"NotAuthenticatedError")}apiUrl;constructor(apiUrl,message="You are not signed in to Fimo."){super(message),this.name="NotAuthenticatedError",this.apiUrl=apiUrl}};__name(ensureCredentialsDir,"ensureCredentialsDir");__name(readCredentials,"readCredentials");__name(writeCredentials,"writeCredentials");__name(clearCredentials,"clearCredentials");__name(setActiveOrganization,"setActiveOrganization");__name(recordAuthFailure,"recordAuthFailure");__name(requireToken,"requireToken");__name(requireCredentials,"requireCredentials")}});import{spawnSync}from"node:child_process";import fs3 from"node:fs";import path2 from"node:path";import{setTimeout as sleep}from"node:timers/promises";function isPublishedInstall(cliRoot=CLI_ROOT){return fs3.existsSync(path2.join(cliRoot,"release.json"))}function resolveGlobalFimoRoot(){let result=spawnSync("npm",["root","-g"],{encoding:"utf8",stdio:["ignore","pipe","ignore"],timeout:GLOBAL_ROOT_TIMEOUT_MS});return result.error||result.status!==0||typeof result.stdout!="string"||result.stdout.trim().length===0?null:path2.resolve(result.stdout.trim(),"fimo")}function normalizedPath(input){try{return fs3.realpathSync(input)}catch{return path2.resolve(input)}}function autoUpgradeEnabled(options={}){let usesDefaults=Object.keys(options).length===0;if(usesDefaults&&defaultEligibility!==void 0)return defaultEligibility;let env=options.env??process.env,cliRoot=options.cliRoot??CLI_ROOT,published=options.published??isPublishedInstall(cliRoot);if(env.FIMO_AUTO_UPGRADE!=="1"||!published)return usesDefaults&&(defaultEligibility=!1),!1;let globalFimoRoot=options.globalFimoRoot===void 0?resolveGlobalFimoRoot():options.globalFimoRoot;if(!globalFimoRoot)return usesDefaults&&(defaultEligibility=!1),!1;let eligible=normalizedPath(cliRoot)===normalizedPath(globalFimoRoot);return usesDefaults&&(defaultEligibility=eligible),eligible}async function acquireLock(lockDir){let deadline=Date.now()+LOCK_WAIT_MS;for(;;){try{fs3.mkdirSync(lockDir);return}catch(error){if(error.code!=="EEXIST")throw error}let stale=!1;try{stale=Date.now()-fs3.statSync(lockDir).mtimeMs>LOCK_STALE_MS}catch{continue}if(stale){try{fs3.rmdirSync(lockDir)}catch{}continue}if(Date.now()>=deadline)throw new Error("auto-upgrade lock timeout");await sleep(LOCK_POLL_MS)}}function readGlobalFimoVersion(){let root2=resolveGlobalFimoRoot();if(!root2)return null;try{let pkg=JSON.parse(fs3.readFileSync(path2.join(root2,"package.json"),"utf8"));return typeof pkg.version=="string"?pkg.version:null}catch{return null}}async function autoUpgradeGlobal(latest){if(!VERSION_PATTERN.test(latest))return!1;let lockDir=path2.join(loadConfig().configDir,"auto-upgrade.lock");try{fs3.mkdirSync(path2.dirname(lockDir),{recursive:!0}),await acquireLock(lockDir)}catch{return!1}try{if(readGlobalFimoVersion()===latest)return!0;let install=spawnSync("npm",["install","-g",`fimo@${latest}`],{stdio:["ignore","ignore","inherit"],timeout:INSTALL_TIMEOUT_MS});return install.error||install.status!==0?!1:readGlobalFimoVersion()===latest}finally{try{fs3.rmdirSync(lockDir)}catch{}}}var INSTALL_TIMEOUT_MS,GLOBAL_ROOT_TIMEOUT_MS,LOCK_WAIT_MS,LOCK_STALE_MS,LOCK_POLL_MS,VERSION_PATTERN,defaultEligibility,init_auto_upgrade=__esm({"src/cli/auto-upgrade.ts"(){init_config();INSTALL_TIMEOUT_MS=12e4,GLOBAL_ROOT_TIMEOUT_MS=5e3,LOCK_WAIT_MS=18e4,LOCK_STALE_MS=3e5,LOCK_POLL_MS=500,VERSION_PATTERN=/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;__name(isPublishedInstall,"isPublishedInstall");__name(resolveGlobalFimoRoot,"resolveGlobalFimoRoot");__name(normalizedPath,"normalizedPath");__name(autoUpgradeEnabled,"autoUpgradeEnabled");__name(acquireLock,"acquireLock");__name(readGlobalFimoVersion,"readGlobalFimoVersion");__name(autoUpgradeGlobal,"autoUpgradeGlobal")}});var isAmbiguous,isFullWidth,isWide,init_utils=__esm({"../../node_modules/.pnpm/fast-string-truncated-width@1.2.1/node_modules/fast-string-truncated-width/dist/utils.js"(){isAmbiguous=__name(x=>x===161||x===164||x===167||x===168||x===170||x===173||x===174||x>=176&&x<=180||x>=182&&x<=186||x>=188&&x<=191||x===198||x===208||x===215||x===216||x>=222&&x<=225||x===230||x>=232&&x<=234||x===236||x===237||x===240||x===242||x===243||x>=247&&x<=250||x===252||x===254||x===257||x===273||x===275||x===283||x===294||x===295||x===299||x>=305&&x<=307||x===312||x>=319&&x<=322||x===324||x>=328&&x<=331||x===333||x===338||x===339||x===358||x===359||x===363||x===462||x===464||x===466||x===468||x===470||x===472||x===474||x===476||x===593||x===609||x===708||x===711||x>=713&&x<=715||x===717||x===720||x>=728&&x<=731||x===733||x===735||x>=768&&x<=879||x>=913&&x<=929||x>=931&&x<=937||x>=945&&x<=961||x>=963&&x<=969||x===1025||x>=1040&&x<=1103||x===1105||x===8208||x>=8211&&x<=8214||x===8216||x===8217||x===8220||x===8221||x>=8224&&x<=8226||x>=8228&&x<=8231||x===8240||x===8242||x===8243||x===8245||x===8251||x===8254||x===8308||x===8319||x>=8321&&x<=8324||x===8364||x===8451||x===8453||x===8457||x===8467||x===8470||x===8481||x===8482||x===8486||x===8491||x===8531||x===8532||x>=8539&&x<=8542||x>=8544&&x<=8555||x>=8560&&x<=8569||x===8585||x>=8592&&x<=8601||x===8632||x===8633||x===8658||x===8660||x===8679||x===8704||x===8706||x===8707||x===8711||x===8712||x===8715||x===8719||x===8721||x===8725||x===8730||x>=8733&&x<=8736||x===8739||x===8741||x>=8743&&x<=8748||x===8750||x>=8756&&x<=8759||x===8764||x===8765||x===8776||x===8780||x===8786||x===8800||x===8801||x>=8804&&x<=8807||x===8810||x===8811||x===8814||x===8815||x===8834||x===8835||x===8838||x===8839||x===8853||x===8857||x===8869||x===8895||x===8978||x>=9312&&x<=9449||x>=9451&&x<=9547||x>=9552&&x<=9587||x>=9600&&x<=9615||x>=9618&&x<=9621||x===9632||x===9633||x>=9635&&x<=9641||x===9650||x===9651||x===9654||x===9655||x===9660||x===9661||x===9664||x===9665||x>=9670&&x<=9672||x===9675||x>=9678&&x<=9681||x>=9698&&x<=9701||x===9711||x===9733||x===9734||x===9737||x===9742||x===9743||x===9756||x===9758||x===9792||x===9794||x===9824||x===9825||x>=9827&&x<=9829||x>=9831&&x<=9834||x===9836||x===9837||x===9839||x===9886||x===9887||x===9919||x>=9926&&x<=9933||x>=9935&&x<=9939||x>=9941&&x<=9953||x===9955||x===9960||x===9961||x>=9963&&x<=9969||x===9972||x>=9974&&x<=9977||x===9979||x===9980||x===9982||x===9983||x===10045||x>=10102&&x<=10111||x>=11094&&x<=11097||x>=12872&&x<=12879||x>=57344&&x<=63743||x>=65024&&x<=65039||x===65533||x>=127232&&x<=127242||x>=127248&&x<=127277||x>=127280&&x<=127337||x>=127344&&x<=127373||x===127375||x===127376||x>=127387&&x<=127404||x>=917760&&x<=917999||x>=983040&&x<=1048573||x>=1048576&&x<=1114109,"isAmbiguous"),isFullWidth=__name(x=>x===12288||x>=65281&&x<=65376||x>=65504&&x<=65510,"isFullWidth"),isWide=__name(x=>x>=4352&&x<=4447||x===8986||x===8987||x===9001||x===9002||x>=9193&&x<=9196||x===9200||x===9203||x===9725||x===9726||x===9748||x===9749||x>=9800&&x<=9811||x===9855||x===9875||x===9889||x===9898||x===9899||x===9917||x===9918||x===9924||x===9925||x===9934||x===9940||x===9962||x===9970||x===9971||x===9973||x===9978||x===9981||x===9989||x===9994||x===9995||x===10024||x===10060||x===10062||x>=10067&&x<=10069||x===10071||x>=10133&&x<=10135||x===10160||x===10175||x===11035||x===11036||x===11088||x===11093||x>=11904&&x<=11929||x>=11931&&x<=12019||x>=12032&&x<=12245||x>=12272&&x<=12287||x>=12289&&x<=12350||x>=12353&&x<=12438||x>=12441&&x<=12543||x>=12549&&x<=12591||x>=12593&&x<=12686||x>=12688&&x<=12771||x>=12783&&x<=12830||x>=12832&&x<=12871||x>=12880&&x<=19903||x>=19968&&x<=42124||x>=42128&&x<=42182||x>=43360&&x<=43388||x>=44032&&x<=55203||x>=63744&&x<=64255||x>=65040&&x<=65049||x>=65072&&x<=65106||x>=65108&&x<=65126||x>=65128&&x<=65131||x>=94176&&x<=94180||x===94192||x===94193||x>=94208&&x<=100343||x>=100352&&x<=101589||x>=101632&&x<=101640||x>=110576&&x<=110579||x>=110581&&x<=110587||x===110589||x===110590||x>=110592&&x<=110882||x===110898||x>=110928&&x<=110930||x===110933||x>=110948&&x<=110951||x>=110960&&x<=111355||x===126980||x===127183||x===127374||x>=127377&&x<=127386||x>=127488&&x<=127490||x>=127504&&x<=127547||x>=127552&&x<=127560||x===127568||x===127569||x>=127584&&x<=127589||x>=127744&&x<=127776||x>=127789&&x<=127797||x>=127799&&x<=127868||x>=127870&&x<=127891||x>=127904&&x<=127946||x>=127951&&x<=127955||x>=127968&&x<=127984||x===127988||x>=127992&&x<=128062||x===128064||x>=128066&&x<=128252||x>=128255&&x<=128317||x>=128331&&x<=128334||x>=128336&&x<=128359||x===128378||x===128405||x===128406||x===128420||x>=128507&&x<=128591||x>=128640&&x<=128709||x===128716||x>=128720&&x<=128722||x>=128725&&x<=128727||x>=128732&&x<=128735||x===128747||x===128748||x>=128756&&x<=128764||x>=128992&&x<=129003||x===129008||x>=129292&&x<=129338||x>=129340&&x<=129349||x>=129351&&x<=129535||x>=129648&&x<=129660||x>=129664&&x<=129672||x>=129680&&x<=129725||x>=129727&&x<=129733||x>=129742&&x<=129755||x>=129760&&x<=129768||x>=129776&&x<=129784||x>=131072&&x<=196605||x>=196608&&x<=262141,"isWide")}});var ANSI_RE,CONTROL_RE,TAB_RE,EMOJI_RE,LATIN_RE,MODIFIER_RE,NO_TRUNCATION,getStringTruncatedWidth,dist_default,init_dist2=__esm({"../../node_modules/.pnpm/fast-string-truncated-width@1.2.1/node_modules/fast-string-truncated-width/dist/index.js"(){init_utils();ANSI_RE=/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/y,CONTROL_RE=/[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y,TAB_RE=/\t{1,1000}/y,EMOJI_RE=new RegExp("[\\u{1F1E6}-\\u{1F1FF}]{2}|\\u{1F3F4}[\\u{E0061}-\\u{E007A}]{2}[\\u{E0030}-\\u{E0039}\\u{E0061}-\\u{E007A}]{1,3}\\u{E007F}|(?:\\p{Emoji}\\uFE0F\\u20E3?|\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation})(?:\\u200D(?:\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation}|\\p{Emoji}\\uFE0F\\u20E3?))*","yu"),LATIN_RE=/(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y,MODIFIER_RE=new RegExp("\\p{M}+","gu"),NO_TRUNCATION={limit:1/0,ellipsis:""},getStringTruncatedWidth=__name((input,truncationOptions={},widthOptions={})=>{let LIMIT=truncationOptions.limit??1/0,ELLIPSIS=truncationOptions.ellipsis??"",ELLIPSIS_WIDTH=truncationOptions?.ellipsisWidth??(ELLIPSIS?getStringTruncatedWidth(ELLIPSIS,NO_TRUNCATION,widthOptions).width:0),ANSI_WIDTH=widthOptions.ansiWidth??0,CONTROL_WIDTH=widthOptions.controlWidth??0,TAB_WIDTH=widthOptions.tabWidth??8,AMBIGUOUS_WIDTH=widthOptions.ambiguousWidth??1,EMOJI_WIDTH=widthOptions.emojiWidth??2,FULL_WIDTH_WIDTH=widthOptions.fullWidthWidth??2,REGULAR_WIDTH=widthOptions.regularWidth??1,WIDE_WIDTH=widthOptions.wideWidth??2,indexPrev=0,index2=0,length=input.length,lengthExtra=0,truncationEnabled=!1,truncationIndex=length,truncationLimit=Math.max(0,LIMIT-ELLIPSIS_WIDTH),unmatchedStart=0,unmatchedEnd=0,width=0,widthExtra=0;outer:for(;;){if(unmatchedEnd>unmatchedStart||index2>=length&&index2>indexPrev){let unmatched=input.slice(unmatchedStart,unmatchedEnd)||input.slice(indexPrev,index2);lengthExtra=0;for(let char of unmatched.replaceAll(MODIFIER_RE,"")){let codePoint=char.codePointAt(0)||0;if(isFullWidth(codePoint)?widthExtra=FULL_WIDTH_WIDTH:isWide(codePoint)?widthExtra=WIDE_WIDTH:AMBIGUOUS_WIDTH!==REGULAR_WIDTH&&isAmbiguous(codePoint)?widthExtra=AMBIGUOUS_WIDTH:widthExtra=REGULAR_WIDTH,width+widthExtra>truncationLimit&&(truncationIndex=Math.min(truncationIndex,Math.max(unmatchedStart,indexPrev)+lengthExtra)),width+widthExtra>LIMIT){truncationEnabled=!0;break outer}lengthExtra+=char.length,width+=widthExtra}unmatchedStart=unmatchedEnd=0}if(index2>=length)break;if(LATIN_RE.lastIndex=index2,LATIN_RE.test(input)){if(lengthExtra=LATIN_RE.lastIndex-index2,widthExtra=lengthExtra*REGULAR_WIDTH,width+widthExtra>truncationLimit&&(truncationIndex=Math.min(truncationIndex,index2+Math.floor((truncationLimit-width)/REGULAR_WIDTH))),width+widthExtra>LIMIT){truncationEnabled=!0;break}width+=widthExtra,unmatchedStart=indexPrev,unmatchedEnd=index2,index2=indexPrev=LATIN_RE.lastIndex;continue}if(ANSI_RE.lastIndex=index2,ANSI_RE.test(input)){if(width+ANSI_WIDTH>truncationLimit&&(truncationIndex=Math.min(truncationIndex,index2)),width+ANSI_WIDTH>LIMIT){truncationEnabled=!0;break}width+=ANSI_WIDTH,unmatchedStart=indexPrev,unmatchedEnd=index2,index2=indexPrev=ANSI_RE.lastIndex;continue}if(CONTROL_RE.lastIndex=index2,CONTROL_RE.test(input)){if(lengthExtra=CONTROL_RE.lastIndex-index2,widthExtra=lengthExtra*CONTROL_WIDTH,width+widthExtra>truncationLimit&&(truncationIndex=Math.min(truncationIndex,index2+Math.floor((truncationLimit-width)/CONTROL_WIDTH))),width+widthExtra>LIMIT){truncationEnabled=!0;break}width+=widthExtra,unmatchedStart=indexPrev,unmatchedEnd=index2,index2=indexPrev=CONTROL_RE.lastIndex;continue}if(TAB_RE.lastIndex=index2,TAB_RE.test(input)){if(lengthExtra=TAB_RE.lastIndex-index2,widthExtra=lengthExtra*TAB_WIDTH,width+widthExtra>truncationLimit&&(truncationIndex=Math.min(truncationIndex,index2+Math.floor((truncationLimit-width)/TAB_WIDTH))),width+widthExtra>LIMIT){truncationEnabled=!0;break}width+=widthExtra,unmatchedStart=indexPrev,unmatchedEnd=index2,index2=indexPrev=TAB_RE.lastIndex;continue}if(EMOJI_RE.lastIndex=index2,EMOJI_RE.test(input)){if(width+EMOJI_WIDTH>truncationLimit&&(truncationIndex=Math.min(truncationIndex,index2)),width+EMOJI_WIDTH>LIMIT){truncationEnabled=!0;break}width+=EMOJI_WIDTH,unmatchedStart=indexPrev,unmatchedEnd=index2,index2=indexPrev=EMOJI_RE.lastIndex;continue}index2+=1}return{width:truncationEnabled?truncationLimit:width,index:truncationEnabled?truncationIndex:length,truncated:truncationEnabled,ellipsed:truncationEnabled&&LIMIT>=ELLIPSIS_WIDTH}},"getStringTruncatedWidth"),dist_default=getStringTruncatedWidth}});var NO_TRUNCATION2,fastStringWidth,dist_default2,init_dist3=__esm({"../../node_modules/.pnpm/fast-string-width@1.1.0/node_modules/fast-string-width/dist/index.js"(){init_dist2();NO_TRUNCATION2={limit:1/0,ellipsis:"",ellipsisWidth:0},fastStringWidth=__name((input,options={})=>dist_default(input,NO_TRUNCATION2,options).width,"fastStringWidth"),dist_default2=fastStringWidth}});function wrapAnsi(string,columns,options){return String(string).normalize().split(CRLF_OR_LF).map(line=>exec(line,columns,options)).join(`
44
44
  `)}var ESC,CSI,END_CODE,ANSI_ESCAPE_BELL,ANSI_CSI,ANSI_OSC,ANSI_SGR_TERMINATOR,ANSI_ESCAPE_LINK,GROUP_REGEX,getClosingCode,wrapAnsiCode,wrapAnsiHyperlink,wrapWord,stringVisibleTrimSpacesRight,exec,CRLF_OR_LF,init_main=__esm({"../../node_modules/.pnpm/fast-wrap-ansi@0.1.6/node_modules/fast-wrap-ansi/lib/main.js"(){init_dist3();ESC="\x1B",CSI="\x9B",END_CODE=39,ANSI_ESCAPE_BELL="\x07",ANSI_CSI="[",ANSI_OSC="]",ANSI_SGR_TERMINATOR="m",ANSI_ESCAPE_LINK=`${ANSI_OSC}8;;`,GROUP_REGEX=new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`,"y"),getClosingCode=__name(openingCode=>{if(openingCode>=30&&openingCode<=37||openingCode>=90&&openingCode<=97)return 39;if(openingCode>=40&&openingCode<=47||openingCode>=100&&openingCode<=107)return 49;if(openingCode===1||openingCode===2)return 22;if(openingCode===3)return 23;if(openingCode===4)return 24;if(openingCode===7)return 27;if(openingCode===8)return 28;if(openingCode===9)return 29;if(openingCode===0)return 0},"getClosingCode"),wrapAnsiCode=__name(code2=>`${ESC}${ANSI_CSI}${code2}${ANSI_SGR_TERMINATOR}`,"wrapAnsiCode"),wrapAnsiHyperlink=__name(url=>`${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`,"wrapAnsiHyperlink"),wrapWord=__name((rows,word,columns)=>{let characters=word[Symbol.iterator](),isInsideEscape=!1,isInsideLinkEscape=!1,lastRow=rows.at(-1),visible=lastRow===void 0?0:dist_default2(lastRow),currentCharacter=characters.next(),nextCharacter=characters.next(),rawCharacterIndex=0;for(;!currentCharacter.done;){let character=currentCharacter.value,characterLength=dist_default2(character);visible+characterLength<=columns?rows[rows.length-1]+=character:(rows.push(character),visible=0),(character===ESC||character===CSI)&&(isInsideEscape=!0,isInsideLinkEscape=word.startsWith(ANSI_ESCAPE_LINK,rawCharacterIndex+1)),isInsideEscape?isInsideLinkEscape?character===ANSI_ESCAPE_BELL&&(isInsideEscape=!1,isInsideLinkEscape=!1):character===ANSI_SGR_TERMINATOR&&(isInsideEscape=!1):(visible+=characterLength,visible===columns&&!nextCharacter.done&&(rows.push(""),visible=0)),currentCharacter=nextCharacter,nextCharacter=characters.next(),rawCharacterIndex+=character.length}lastRow=rows.at(-1),!visible&&lastRow!==void 0&&lastRow.length&&rows.length>1&&(rows[rows.length-2]+=rows.pop())},"wrapWord"),stringVisibleTrimSpacesRight=__name(string=>{let words=string.split(" "),last2=words.length;for(;last2&&!dist_default2(words[last2-1]);)last2--;return last2===words.length?string:words.slice(0,last2).join(" ")+words.slice(last2).join("")},"stringVisibleTrimSpacesRight"),exec=__name((string,columns,options={})=>{if(options.trim!==!1&&string.trim()==="")return"";let returnValue="",escapeCode,escapeUrl,words=string.split(" "),rows=[""],rowLength=0;for(let index2=0;index2<words.length;index2++){let word=words[index2];if(options.trim!==!1){let row2=rows.at(-1)??"",trimmed=row2.trimStart();row2.length!==trimmed.length&&(rows[rows.length-1]=trimmed,rowLength=dist_default2(trimmed))}index2!==0&&(rowLength>=columns&&(options.wordWrap===!1||options.trim===!1)&&(rows.push(""),rowLength=0),(rowLength||options.trim===!1)&&(rows[rows.length-1]+=" ",rowLength++));let wordLength=dist_default2(word);if(options.hard&&wordLength>columns){let remainingColumns=columns-rowLength,breaksStartingThisLine=1+Math.floor((wordLength-remainingColumns-1)/columns);Math.floor((wordLength-1)/columns)<breaksStartingThisLine&&rows.push(""),wrapWord(rows,word,columns),rowLength=dist_default2(rows.at(-1)??"");continue}if(rowLength+wordLength>columns&&rowLength&&wordLength){if(options.wordWrap===!1&&rowLength<columns){wrapWord(rows,word,columns),rowLength=dist_default2(rows.at(-1)??"");continue}rows.push(""),rowLength=0}if(rowLength+wordLength>columns&&options.wordWrap===!1){wrapWord(rows,word,columns),rowLength=dist_default2(rows.at(-1)??"");continue}rows[rows.length-1]+=word,rowLength+=wordLength}options.trim!==!1&&(rows=rows.map(row2=>stringVisibleTrimSpacesRight(row2)));let preString=rows.join(`
45
45
  `),inSurrogate=!1;for(let i=0;i<preString.length;i++){let character=preString[i];if(returnValue+=character,!inSurrogate)inSurrogate=character>="\uD800"&&character<="\uDBFF";else continue;if(character===ESC||character===CSI){GROUP_REGEX.lastIndex=i+1;let groups=GROUP_REGEX.exec(preString)?.groups;if(groups?.code!==void 0){let code2=Number.parseFloat(groups.code);escapeCode=code2===END_CODE?void 0:code2}else groups?.uri!==void 0&&(escapeUrl=groups.uri.length===0?void 0:groups.uri)}if(preString[i+1]===`
46
46
  `){escapeUrl&&(returnValue+=wrapAnsiHyperlink(""));let closingCode=escapeCode?getClosingCode(escapeCode):void 0;escapeCode&&closingCode&&(returnValue+=wrapAnsiCode(closingCode))}else character===`
@@ -1353,6 +1353,17 @@ model of every multi-section page in \`.fimo/migration/page-drafts/\`
1353
1353
  never per-page). A page's own sections are its Single's NESTED BLOCK
1354
1354
  fields: build the Single from the draft, fill its document, rewire, claim
1355
1355
  (\`npx fimo pages set <page-id> --single <Name>\`).
1356
+ `:""}${machine.pages&&(machine.pages.sharedSingles?.length??0)>0?`
1357
+ SHARED CHROME SINGLE TYPES (push these) \u2014 header, footer, nav carry the SAME
1358
+ content on every page, so each is ONE Single Type, modeled once. The machine
1359
+ BUILT them (schema + filled document) in \`.fimo/migration/shared-singles/\`:
1360
+ ${(machine.pages.sharedSingles??[]).map(single=>`- \`${single.component}\` \u2192 \`${single.uid}\` (${single.fields} field(s), schema + document ready)`).join(`
1361
+ `)}
1362
+ For each: REVIEW & RENAME fields to editorial names, PUSH the schema
1363
+ (\`src/schemas/<Uid>.json\` + \`npx fimo schemas push\`), FILL its document
1364
+ (\`npx fimo documents set <Uid> --body '<json>'\`), and REFERENCE it from every
1365
+ page that renders the chrome (source values as fallback). Never leave chrome as
1366
+ orphan flat labels \u2014 edited once, it changes on every page.
1356
1367
  `:""}
1357
1368
  NAMES AND GROUPS \u2014 the Pages tree must read like a human organized it:
1358
1369
  - Every page label reads like a human wrote it: acronyms are uppercase
@@ -2139,8 +2150,8 @@ Next step: open ${path58.join(projectRoot,result.promptPath)} and paste it to yo
2139
2150
  `));return JSON.parse(fs52.readFileSync(filePath,"utf-8"))});syncSchemas({cwd,verbose:!1});let results=[];for(let schema of sortSchemasByReferenceDependencies(schemas3)){let contentType=toApiShape(schema);try{let result=await api.createSchema(ctx.projectId,contentType);results.push(result)}catch(error){if(isAlreadyExistsError(error)){let result=await api.updateSchema(ctx.projectId,contentType.name,contentType);results.push(result)}else{if(opts.tolerateUnknownTargets&&isUnknownTargetError(error))continue;throw error}}}return results}function applyDraftAdoption(drafts,renames,drops){let finalName=__name(uid=>renames[uid]??uid,"finalName"),kept=[],dropped=[],renamed=[];for(let draft of drafts){if(drops.has(draft.uid)){dropped.push(draft.uid);continue}let uid=finalName(draft.uid);uid!==draft.uid&&renamed.push({from:draft.uid,to:uid});let fields={};for(let[name,def]of Object.entries(draft.fields)){if(def&&typeof def=="object"&&def.type==="reference"){let ref={...def};if(typeof ref.target=="string"){if(drops.has(ref.target)){fields[name]={type:"string"};continue}ref.target=finalName(ref.target)}if(Array.isArray(ref.targets)){let targets=ref.targets.filter(target=>!drops.has(target)).map(finalName);if(targets.length===0){fields[name]={type:"string"};continue}ref.targets=targets}fields[name]=ref;continue}fields[name]=def}kept.push({uid,from:draft.uid,fields})}return{kept,dropped,renamed}}function parseDraftSelectors(draftUids,rename,drop){let canonicalUid=__name(name=>draftUids.find(uid=>uid.toLowerCase()===name.toLowerCase())??name,"canonicalUid"),renames={};for(let pair of(rename??"").split(",").map(entry=>entry.trim()).filter(Boolean)){let[from,to]=pair.split("=").map(part=>part.trim());from&&to&&(renames[canonicalUid(from)]=to)}let drops=new Set((drop??"").split(",").map(entry=>entry.trim()).filter(Boolean).map(canonicalUid));return{renames,drops}}async function schemaAdoptDraftsCommand(options,cmd){let{ctx,api}=await bootstrapProjectCommand(options,cmd,{refuseReadOnly:!0});await requireOperation("cms.schema.push",{projectId:ctx.projectId,env:ctx.env});let cwd=resolveProjectCwd(options.cwd),draftsDir=path59.join(cwd,".fimo","migration","schema-drafts");if(!fs52.existsSync(draftsDir)){ui.error({command:"schemas adopt-drafts",code:"NO_SCHEMA_DRAFTS",message:"No .fimo/migration/schema-drafts directory \u2014 run `npx fimo migrate` first."}),process.exitCode=1;return}let drafts=fs52.readdirSync(draftsDir).filter(file=>file.endsWith(".json")).map(file=>JSON.parse(fs52.readFileSync(path59.join(draftsDir,file),"utf-8"))),{renames,drops}=parseDraftSelectors(drafts.map(draft=>draft.uid),options.rename,options.drop),adoption=applyDraftAdoption(drafts.map(draft=>({uid:draft.uid,fields:draft.fields??{}})),renames,drops),schemasDir=path59.join(cwd,"src","schemas");fs52.mkdirSync(schemasDir,{recursive:!0});let renderSchemaFile=__name(schema=>`${JSON.stringify({uid:schema.uid,name:humanizeUid(schema.uid),fields:schema.fields},null,2)}
2140
2151
  `,"renderSchemaFile");for(let schema of adoption.kept){let target=path59.join(schemasDir,`${schema.uid}.json`);if(!(!fs52.existsSync(target)||options.force)&&fs52.readFileSync(target,"utf-8")!==renderSchemaFile(schema)){ui.error({command:"schemas adopt-drafts",code:"SCHEMA_FILE_EXISTS",message:`src/schemas/${schema.uid}.json already exists with different content \u2014 rerun with --force to overwrite.`}),process.exitCode=1;return}}for(let schema of adoption.kept)fs52.writeFileSync(path59.join(schemasDir,`${schema.uid}.json`),renderSchemaFile(schema));let rowsDir=path59.join(cwd,".fimo","migration","rows");if(fs52.existsSync(rowsDir)){let finalName=__name(uid=>renames[uid]??uid,"finalName");for(let file of fs52.readdirSync(rowsDir).filter(entry=>entry.endsWith(".rows.json"))){let filePath=path59.join(rowsDir,file),rowsFile=JSON.parse(fs52.readFileSync(filePath,"utf-8"));if(drops.has(rowsFile.draftUid)){fs52.rmSync(filePath);continue}let newUid=finalName(rowsFile.draftUid);rowsFile.draftUid=newUid;for(let[field,reference]of Object.entries(rowsFile.references??{})){if(typeof reference.target=="string"){if(drops.has(reference.target)){delete rowsFile.references?.[field];continue}reference.target=finalName(reference.target)}if(Array.isArray(reference.targets)){let targets=reference.targets.filter(target=>!drops.has(target)).map(finalName);if(targets.length===0){delete rowsFile.references?.[field];continue}reference.targets=targets}}fs52.rmSync(filePath),fs52.writeFileSync(path59.join(rowsDir,`${newUid}.rows.json`),`${JSON.stringify(rowsFile,null,1)}
2141
2152
  `)}}if(Object.keys(renames).length>0){let sourceDirs=["app","src","pages"].map(dir=>path59.join(cwd,dir)).filter(dir=>fs52.existsSync(dir)),renameCallSites=__name(dir=>{for(let entry of fs52.readdirSync(dir,{withFileTypes:!0})){if(entry.name==="node_modules"||entry.name.startsWith("."))continue;let full=path59.join(dir,entry.name);if(entry.isDirectory()){renameCallSites(full);continue}if(!/\.(tsx|jsx|ts|js|mjs)$/.test(entry.name))continue;let source=fs52.readFileSync(full,"utf-8");if(!source.includes("wrapCollection("))continue;let next2=source;for(let[from,to]of Object.entries(renames))next2=next2.split(`wrapCollection('${from}'`).join(`wrapCollection('${to}'`),next2=next2.split(`wrapCollection("${from}"`).join(`wrapCollection("${to}"`);next2!==source&&fs52.writeFileSync(full,next2)}},"renameCallSites");for(let dir of sourceDirs)renameCallSites(dir)}let hasReferences2=adoption.kept.some(schema=>Object.values(schema.fields).some(def=>def&&typeof def=="object"&&def.type==="reference"));await pushAllSchemas(ctx,api,cwd,void 0,{tolerateUnknownTargets:hasReferences2}),hasReferences2&&await pushAllSchemas(ctx,api,cwd);let summary2={adopted:adoption.kept.map(schema=>schema.uid),renamed:adoption.renamed,dropped:adoption.dropped,pushed:adoption.kept.length};ui.result({command:"schemas adopt-drafts",data:summary2,render:__name(()=>[`Adopted ${adoption.kept.length} schema(s) into src/schemas and pushed.`,...adoption.renamed.length>0?[`Renamed: ${adoption.renamed.map(entry=>`${entry.from}\u2192${entry.to}`).join(", ")}`]:[],...adoption.dropped.length>0?[`Dropped: ${adoption.dropped.join(", ")}`]:[]].join(`
2142
- `),"render")})}async function schemaDeleteCommand(typeName,options,cmd){let{ctx,api}=await bootstrapProjectCommand(options,cmd,{refuseReadOnly:!0});await requireOperation("cms.schema.delete",{projectId:ctx.projectId,env:ctx.env});let result=await api.deleteSchema(ctx.projectId,typeName);ui.result({command:"schemas delete",data:result,render:__name(()=>renderPrettyJson(result),"render")})}var SchemaCommandError,init_schema=__esm({"src/cli/commands/schema.ts"(){init_dist();init_sync_schemas();init_validate_schemas();init_api();init_capability_guard();init_project_context();init_project();init_render_json();SchemaCommandError=class extends Error{static{__name(this,"SchemaCommandError")}code;constructor(code2,message){super(message),this.name="SchemaCommandError",this.code=code2}};__name(renameOperation,"renameOperation");__name(humanizeUid,"humanizeUid");__name(toApiShape,"toApiShape");__name(schemaListCommand,"schemaListCommand");__name(schemaGetCommand,"schemaGetCommand");__name(schemaPushCommand,"schemaPushCommand");__name(isAlreadyExistsError,"isAlreadyExistsError");__name(sortSchemasByReferenceDependencies,"sortSchemasByReferenceDependencies");__name(isUnknownTargetError,"isUnknownTargetError");__name(pushAllSchemas,"pushAllSchemas");__name(applyDraftAdoption,"applyDraftAdoption");__name(parseDraftSelectors,"parseDraftSelectors");__name(schemaAdoptDraftsCommand,"schemaAdoptDraftsCommand");__name(schemaDeleteCommand,"schemaDeleteCommand")}});import{readFileSync as readFileSync22}from"node:fs";function isChromePrefix(prefix){return CHROME_PREFIX.test(prefix)}function resolveRouteFiles(cwd,framework,routes){return frameworkRouteFiles(framework)?.(cwd,routes)??[]}function keyPrefix(key){let dot=key.indexOf(".");return dot>0?key.slice(0,dot):null}function groupKeysByPrefix(stagedKeys){let groups=new Map;for(let key of stagedKeys){let prefix=keyPrefix(key);prefix&&groups.set(prefix,[...groups.get(prefix)??[],key])}return groups}function collectPageLabelPrefixes(resolutions,stagedKeys,routes){let groups=groupKeysByPrefix(stagedKeys),updates=new Map;for(let{routeId:routeId2,file}of resolutions){let route=routes[routeId2];if(!route||Array.isArray(route.labelPrefixes)&&route.labelPrefixes.length>0)continue;let code2;try{code2=readFileSync22(file,"utf8")}catch{continue}let matched=[];for(let[prefix,keys]of groups)keys.some(key=>code2.includes(key))&&matched.push(prefix);matched.sort(),matched.length>0&&(matched.length>1||matched[0]!==routeId2)&&updates.set(routeId2,matched)}return updates}function unclaimedLabelPrefixes(stagedKeys,routes){let claimed=new Set;for(let[routeId2,route]of Object.entries(routes))if(claimed.add(routeId2),Array.isArray(route?.labelPrefixes))for(let prefix of route.labelPrefixes)typeof prefix=="string"&&claimed.add(prefix.replace(/\.$/,""));return[...groupKeysByPrefix(stagedKeys)].filter(([prefix])=>!claimed.has(prefix)).map(([prefix,keys])=>({prefix,exampleKey:keys[0],keys:keys.length,chrome:isChromePrefix(prefix)})).sort((a,b)=>a.prefix.localeCompare(b.prefix))}function collectPageSingles(resolutions,singletonUids,routes){let updates=new Map;if(singletonUids.length===0)return updates;for(let{routeId:routeId2,file}of resolutions){let route=routes[routeId2];if(!route||Array.isArray(route.singles)&&route.singles.length>0)continue;let code2;try{code2=readFileSync22(file,"utf8")}catch{continue}let claimed=singletonUids.filter(uid=>[`documents/${uid}`,`useFimoSingle('${uid}'`,`useFimoSingle("${uid}"`,`fetchDocument('${uid}'`,`fetchDocument("${uid}"`].some(marker=>code2.includes(marker))).sort();claimed.length>0&&updates.set(routeId2,claimed)}return updates}var CHROME_PREFIX,init_label_prefixes=__esm({"src/scripts/routes/label-prefixes.ts"(){init_discover();init_module_resolve();CHROME_PREFIX=/(header|footer|nav|menu|topbar|sidebar|banner|cookie|breadcrumb|social)/i;__name(isChromePrefix,"isChromePrefix");__name(resolveRouteFiles,"resolveRouteFiles");__name(keyPrefix,"keyPrefix");__name(groupKeysByPrefix,"groupKeysByPrefix");__name(collectPageLabelPrefixes,"collectPageLabelPrefixes");__name(unclaimedLabelPrefixes,"unclaimedLabelPrefixes");__name(collectPageSingles,"collectPageSingles")}});var page_structure_exports={};__export(page_structure_exports,{buildPageSingleDraft:()=>buildPageSingleDraft,collectContentModelCandidates:()=>collectContentModelCandidates,collectIllustrationCandidates:()=>collectIllustrationCandidates,countDraftSections:()=>countDraftSections,draftPageStructures:()=>draftPageStructures,isIllustrationSection:()=>isIllustrationSection});import{readFileSync as readFileSync23,statSync as statSync13}from"node:fs";import{join as join31,relative as relative8}from"node:path";function sectionTags(code2){let seen=new Set,tags=[];for(let match of code2.matchAll(/<([A-Z]\w*)[\s/>]/g))seen.has(match[1])||(seen.add(match[1]),tags.push(match[1]));return tags}function draftSection(context,tag,file,depth){let rel=relative8(context.cwd,file),prefix=context.style.fileScope(rel),labelKeys=context.keysByPrefix.get(prefix)??[],collections=(context.collectionsByFile.get(rel)??[]).map(candidate=>({name:candidate.name,fields:candidate.fields,count:candidate.count,...candidate.typedRows?{rows:candidate.typedRows.slice(0,MAX_DRAFT_ROWS)}:{}})),children2=depth<MAX_SECTION_DEPTH?draftChildSections(context,file,depth+1):[];if(labelKeys.length===0&&collections.length===0&&children2.length===0)return null;let draft={key:camel(tag),component:tag,file:rel,prefix,labelKeys,collections};return children2.length>0&&(draft.children=children2),draft}function resolveAutoImportedComponent(context,tag){for(let dir of context.style.fallbackComponentDirs)for(let ext of context.style.extensions){let candidate=join31(context.cwd,dir,`${tag}${ext}`);try{if(statSync13(candidate).isFile())return candidate}catch{}}return null}function draftChildSections(context,file,depth){let code2;try{code2=readFileSync23(file,"utf8")}catch{return[]}let imports=componentImports(code2),sections=[];for(let tag of sectionTags(code2)){let spec=imports.get(tag),sectionFile=spec?resolveModuleFile(context.cwd,file,spec,context.style.extensions):resolveAutoImportedComponent(context,tag);if(!sectionFile||context.visited.has(sectionFile))continue;context.visited.add(sectionFile);let section=draftSection(context,tag,sectionFile,depth);section&&sections.push(section)}return sections}function draftPageStructures(args){let{cwd,framework,routes,collections}=args,keysByPrefix=new Map;for(let key of args.stagedKeys){let dot=key.indexOf(".");if(dot>0){let prefix=key.slice(0,dot);keysByPrefix.set(prefix,[...keysByPrefix.get(prefix)??[],key])}}let collectionsByFile=new Map;for(let candidate of collections)collectionsByFile.set(candidate.file,[...collectionsByFile.get(candidate.file)??[],candidate]);let style=frameworkSectionStyle(framework),drafts=[];for(let{routeId:routeId2,file}of resolveRouteFiles(cwd,framework,routes)){let sections=draftChildSections({cwd,style,keysByPrefix,collectionsByFile,visited:new Set([file])},file,1);sections.length>1&&drafts.push({pageId:routeId2,single:pascal(routeId2),sections})}return markSharedSections(drafts),drafts}function markSharedSections(drafts){let pagesByFile=new Map,index2=__name((pageId,sections)=>{for(let section of sections)pagesByFile.set(section.file,(pagesByFile.get(section.file)??new Set).add(pageId)),index2(pageId,section.children??[])},"index");for(let draft of drafts)index2(draft.pageId,draft.sections);let flag2=__name(sections=>{for(let section of sections)(pagesByFile.get(section.file)?.size??0)>1&&(section.shared=!0),flag2(section.children??[])},"flag");for(let draft of drafts)flag2(draft.sections)}function countDraftSections(draft){let walk2=__name(sections=>sections.reduce((total,section)=>total+1+walk2(section.children??[]),0),"walk");return walk2(draft.sections)}function isIllustrationSection(section,labelValues){let values=section.labelKeys.map(key=>labelValues[key]??"").filter(value=>value.trim().length>0);if(values.length<ILLUSTRATION_MIN_LABELS||values.filter(looksLikeProse).length/values.length>.4)return!1;if(values.length>=ILLUSTRATION_DENSE)return!0;let shortRatio=values.filter(value=>wordCount(value)<=3).length/values.length;return ILLUSTRATION_NAME.test(section.component)&&shortRatio>=.7}function isDroppableIllustration(section,labelValues,contentConfirmed){return isIllustrationSection(section,labelValues)&&!contentConfirmed.has(sectionIdentity(section))}function sectionBlock(section,labelValues,illustrations,contentConfirmed){let fields={},value={},fieldCount=0;for(let key of section.labelKeys){let name=labelFieldName(key);if(fields[name])continue;let labelValue=labelValues[key]??"";fields[name]={type:scalarType(labelValue)},value[name]=labelValue,fieldCount+=1}for(let collection of section.collections){let name=camel(collection.name);if(fields[name])continue;let itemFields={};for(let field of collection.fields)itemFields[field]={type:"string"};Object.keys(itemFields).length!==0&&(fields[name]={type:"blocks",schema:{fields:itemFields}},value[name]=(collection.rows??[]).map(row2=>{let item={};for(let field of collection.fields){let cell=row2[field];cell!=null&&typeof cell!="object"&&(item[field]=typeof cell=="string"?cell:String(cell))}return item}),fieldCount+=1)}for(let child of section.children??[]){if(child.shared)continue;if(isDroppableIllustration(child,labelValues,contentConfirmed)){illustrations.push(child.component);continue}let block=sectionBlock(child,labelValues,illustrations,contentConfirmed);!block||fields[child.key]||(fields[child.key]={type:"blocks",max:1,schema:{fields:block.fields}},value[child.key]=[block.value],fieldCount+=block.fieldCount)}return Object.keys(fields).length===0?null:{fields,value,fieldCount}}function buildPageSingleDraft(draft,labelValues,contentConfirmed=new Set){let fields={},document={},illustrations=[],totalFields=0;for(let section of draft.sections){if(section.shared||fields[section.key])continue;if(isDroppableIllustration(section,labelValues,contentConfirmed)){illustrations.push(section.component);continue}let block=sectionBlock(section,labelValues,illustrations,contentConfirmed);block&&(fields[section.key]={type:"blocks",max:1,schema:{fields:block.fields}},document[section.key]=[block.value],totalFields+=block.fieldCount)}return Object.keys(fields).length===0||totalFields<3?null:{uid:draft.single,pageId:draft.pageId,schema:{uid:draft.single,name:draft.single,isSingleton:!0,fields},document,...illustrations.length>0?{illustrations:[...new Set(illustrations)]}:{}}}function collectIllustrationCandidates(drafts,labelValues){let byIdentity=new Map,walk2=__name(sections=>{for(let section of sections){if(isIllustrationSection(section,labelValues)){let identity3=`${section.file}::${section.component}`;byIdentity.has(identity3)||byIdentity.set(identity3,{file:section.file,component:section.component,labelKeys:[...section.labelKeys],samples:sectionSamples(section,labelValues)})}walk2(section.children??[])}},"walk");for(let draft of drafts)walk2(draft.sections);return[...byIdentity.values()]}function collectContentModelCandidates(drafts,labelValues,contentConfirmed=new Set){let eligible=__name(section=>!section.shared&&!isDroppableIllustration(section,labelValues,contentConfirmed),"eligible"),pagesByComponent=new Map,count=__name((pageId,sections)=>{for(let section of sections)eligible(section)&&pagesByComponent.set(section.component,(pagesByComponent.get(section.component)??new Set).add(pageId)),count(pageId,section.children??[])},"count");for(let draft of drafts)count(draft.pageId,draft.sections);let byIdentity=new Map,collect2=__name(sections=>{for(let section of sections){let pages2=pagesByComponent.get(section.component)?.size??0;if(eligible(section)&&pages2>=2){let identity3=`${section.file}::${section.component}`;byIdentity.has(identity3)||byIdentity.set(identity3,{file:section.file,component:section.component,pages:pages2,samples:sectionSamples(section,labelValues)})}collect2(section.children??[])}},"collect");for(let draft of drafts)collect2(draft.sections);return[...byIdentity.values()]}var MAX_SECTION_DEPTH,MAX_DRAFT_ROWS,pascal,camel,labelFieldName,scalarType,ILLUSTRATION_NAME,ILLUSTRATION_DENSE,ILLUSTRATION_MIN_LABELS,wordCount,looksLikeProse,sectionIdentity,SECTION_SAMPLE_COUNT,sectionSamples,init_page_structure=__esm({"src/scripts/routes/page-structure.ts"(){init_discover();init_label_prefixes();MAX_SECTION_DEPTH=6,MAX_DRAFT_ROWS=50,pascal=__name(value=>value.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1-$2").split(/[-_.\s]/).filter(Boolean).map(word=>word.charAt(0).toUpperCase()+word.slice(1).toLowerCase()).join(""),"pascal"),camel=__name(value=>{let p2=pascal(value);return p2.charAt(0).toLowerCase()+p2.slice(1)},"camel");__name(sectionTags,"sectionTags");__name(draftSection,"draftSection");__name(resolveAutoImportedComponent,"resolveAutoImportedComponent");__name(draftChildSections,"draftChildSections");__name(draftPageStructures,"draftPageStructures");__name(markSharedSections,"markSharedSections");__name(countDraftSections,"countDraftSections");labelFieldName=__name(key=>camel(key.split(".").pop()??key),"labelFieldName"),scalarType=__name(value=>value.length>80||value.includes(`
2143
- `)?"text":"string","scalarType"),ILLUSTRATION_NAME=/mock|demo|preview|illustration|visual|showcase|diagram|orbit|screenshot|animation|graphic|dashboard|widget|figure/i,ILLUSTRATION_DENSE=30,ILLUSTRATION_MIN_LABELS=8,wordCount=__name(value=>value.trim().split(/\s+/).filter(Boolean).length,"wordCount"),looksLikeProse=__name(value=>{let words=wordCount(value);return words>=8||words>=5&&/[.!?]/.test(value.trim())},"looksLikeProse");__name(isIllustrationSection,"isIllustrationSection");sectionIdentity=__name(section=>`${section.file}::${section.component}`,"sectionIdentity");__name(isDroppableIllustration,"isDroppableIllustration");__name(sectionBlock,"sectionBlock");__name(buildPageSingleDraft,"buildPageSingleDraft");SECTION_SAMPLE_COUNT=6,sectionSamples=__name((section,labelValues)=>section.labelKeys.map(key=>labelValues[key]??"").filter(value=>value.trim().length>0).slice(0,SECTION_SAMPLE_COUNT),"sectionSamples");__name(collectIllustrationCandidates,"collectIllustrationCandidates");__name(collectContentModelCandidates,"collectContentModelCandidates")}});function kebabCase(name){return name.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/[^a-zA-Z0-9]+/g,"-").toLowerCase().replace(/^-+|-+$/g,"")}function richTextDoc(text3){return{type:"doc",content:[{type:"paragraph",content:[{type:"text",text:text3}]}]}}function placeholderMedia(label){let svg=`<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630"><rect width="100%" height="100%" fill="#e5e7eb"/><text x="50%" y="50%" font-family="sans-serif" font-size="44" fill="#9ca3af" text-anchor="middle" dominant-baseline="middle">${label}</text></svg>`;return{source:"local",url:`data:image/svg+xml;utf8,${encodeURIComponent(svg)}`,alt:`${label} placeholder`,width:1200,height:630,mime:"image/svg+xml",name:"placeholder.svg"}}function exampleDate(n){return new Date(Date.UTC(2024,0,n)).toISOString().slice(0,10)}function exampleReferenceSlug(field){let targetName=field.target??field.targets?.[0];if(!targetName)return;let slug=`${kebabCase(targetName)}-example-1`;return field.many?[slug]:slug}function fillFieldValue(field,def,ctx){let baked=def.default;if(baked!==void 0)return baked;switch(def.type){case"string":return`${humanizeSegment(field)} example ${ctx.index}${ctx.localeSuffix}`;case"richtext":return richTextDoc(`Example ${humanizeSegment(ctx.schemaName).toLowerCase()} content ${ctx.index}${ctx.localeSuffix}.`);case"number":return ctx.index;case"boolean":return ctx.index%2===1;case"date":return exampleDate(ctx.index);case"json":return{};case"media":return placeholderMedia(humanizeSegment(field));case"blocks":return fillBlocks(def,ctx);default:return}}function fillBlocks(def,ctx){if(ctx.depth>=MAX_FILL_DEPTH)return[];let childCtx={...ctx,depth:ctx.depth+1},schema=def.schema;if("oneOf"in schema){let total=schema.oneOf.length,take=Math.min(EXAMPLE_BLOCK_VARIANTS,total),offset=total>0?(ctx.index-1)*take%total:0;return Array.from({length:take},(_2,k)=>schema.oneOf[(offset+k)%total]).map(variant=>({_type:variant.uid,...fillItem(variant.fields,childCtx)}))}let itemCount=def.max===1?1:EXAMPLE_REPEATABLE_ITEMS;return Array.from({length:itemCount},()=>fillItem(schema.fields,childCtx))}function fillItem(fields,ctx){let item={};for(let[name,def]of Object.entries(fields)){let value=fillFieldValue(name,def,ctx);value!==void 0&&(item[name]=value)}return item}function generateExampleSeed(schema,options={}){let locale=options.locale,localeSuffix=locale?` (${locale})`:"",count=schema.isSingleton?1:Math.max(1,options.count??DEFAULT_COUNT),references={},rows=[];for(let i=1;i<=count;i+=1){let row2={};schema.isSingleton||(row2.slug=`${kebabCase(schema.name)}-example-${i}`);for(let[field,def]of Object.entries(schema.fields)){if(schema.examples&&field in schema.examples){row2[field]=schema.examples[field];continue}if(def.type==="reference"){let value2=exampleReferenceSlug(def);value2!==void 0&&(row2[field]=value2,references[field]={...def.target?{target:def.target}:{},...def.targets?{targets:def.targets}:{},by:"slug",...def.many?{many:!0}:{}});continue}let value=fillFieldValue(field,def,{localeSuffix,index:i,schemaName:schema.name,depth:0});value!==void 0&&(row2[field]=value)}rows.push(row2)}return{name:schema.name,isSingleton:schema.isSingleton,localized:schema.localized,rows,references}}var DEFAULT_COUNT,EXAMPLE_BLOCK_VARIANTS,EXAMPLE_REPEATABLE_ITEMS,MAX_FILL_DEPTH,init_example_content=__esm({"src/scripts/cms/example-content.ts"(){init_humanize();DEFAULT_COUNT=3,EXAMPLE_BLOCK_VARIANTS=5,EXAMPLE_REPEATABLE_ITEMS=2,MAX_FILL_DEPTH=6;__name(kebabCase,"kebabCase");__name(richTextDoc,"richTextDoc");__name(placeholderMedia,"placeholderMedia");__name(exampleDate,"exampleDate");__name(exampleReferenceSlug,"exampleReferenceSlug");__name(fillFieldValue,"fillFieldValue");__name(fillBlocks,"fillBlocks");__name(fillItem,"fillItem");__name(generateExampleSeed,"generateExampleSeed")}});var cms_scaffold_exports={};__export(cms_scaffold_exports,{extractSchemaTypeNames:()=>extractSchemaTypeNames,scaffoldCms:()=>scaffoldCms});function extractSchemaTypeNames(raw){let names=new Set,list=Array.isArray(raw)?raw:raw&&typeof raw=="object"?raw.data??raw.types:null;if(Array.isArray(list))for(let item of list){let name=item&&typeof item=="object"?item.name:void 0;typeof name=="string"&&names.add(name)}return names}function withoutReferences(fields){let out={};for(let[name,def]of Object.entries(fields))def.type!=="reference"&&(out[name]=def.type==="blocks"?blocksWithoutReferences(def):def);return out}function blocksWithoutReferences(def){return"oneOf"in def.schema?{...def,schema:{oneOf:def.schema.oneOf.map(variant=>({...variant,fields:withoutReferences(variant.fields)}))}}:{...def,schema:{fields:withoutReferences(def.schema.fields)}}}function hasReferences(fields){return Object.values(fields).some(def=>def.type==="reference"?!0:def.type==="blocks"?"oneOf"in def.schema?def.schema.oneOf.some(variant=>hasReferences(variant.fields)):hasReferences(def.schema.fields):!1)}function orderByDependency(schemas3){let byName=new Map(schemas3.map(schema=>[schema.name,schema])),visited=new Set,ordered=[],visit2=__name((schema,stack)=>{if(!(visited.has(schema.name)||stack.has(schema.name))){stack.add(schema.name);for(let field of Object.values(schema.fields))if(field.type==="reference"){let targets=field.targets??(field.target?[field.target]:[]);for(let target of targets){let dep=byName.get(target);dep&&dep.name!==schema.name&&visit2(dep,stack)}}stack.delete(schema.name),visited.add(schema.name),ordered.push(schema)}},"visit");for(let schema of schemas3)visit2(schema,new Set);return ordered}async function scaffoldCms(opts){let{schemas:schemas3,cms,ctx,api,locales,count=3,force=!1}=opts,existingTypes=opts.existingTypes??new Set,ordered=orderByDependency(schemas3),sp=spinner(`Scaffolding ${cms} content model in Fimo`,{rail:opts.rail??!1}),errorMessage3=__name(error=>error instanceof Error?error.message:String(error),"errorMessage"),schemasCreated=0,entriesCreated=0,skipped=0,failures=[],usedLocales=new Set,created=new Set;try{for(let schema of ordered){let exists=existingTypes.has(schema.name);if(exists&&!force){skipped+=1,created.add(schema.name);continue}let bare={name:schema.name,label:schema.label,isSingleton:schema.isSingleton,fields:withoutReferences(schema.fields)};try{exists?await api.updateSchema(ctx.projectId,schema.name,bare):await api.createSchema(ctx.projectId,bare),schemasCreated+=1,created.add(schema.name)}catch(error){if(isAlreadyExistsError(error))try{await api.updateSchema(ctx.projectId,schema.name,bare),schemasCreated+=1,created.add(schema.name);continue}catch(updateError){failures.push({type:schema.name,stage:"schema",message:errorMessage3(updateError)});continue}failures.push({type:schema.name,stage:"schema",message:errorMessage3(error)})}}for(let schema of ordered)if(!(!created.has(schema.name)||existingTypes.has(schema.name)&&!force||!hasReferences(schema.fields)))try{await api.updateSchema(ctx.projectId,schema.name,{name:schema.name,label:schema.label,isSingleton:schema.isSingleton,fields:schema.fields})}catch(error){failures.push({type:schema.name,stage:"schema",message:`references: ${errorMessage3(error)}`})}for(let schema of ordered){if(!created.has(schema.name))continue;force&&!schema.isSingleton&&await api.bulkDeleteEntries(ctx.projectId,schema.name,{where:{}}).catch(()=>{});let seedLocales=schema.localized&&locales.length>0?locales:[void 0];for(let locale of seedLocales){let seed=generateExampleSeed(schema,{count,locale});try{if(schema.isSingleton)await api.putDocument(ctx.projectId,schema.name,seed.rows[0]??{},locale?{locale}:{}),entriesCreated+=1;else{let result=await api.importEntries(ctx.projectId,schema.name,{entries:seed.rows.map(data2=>({data:data2})),...locale?{locale}:{},...Object.keys(seed.references).length>0?{references:seed.references}:{},allowDangling:!0});entriesCreated+=result.created?.length??0,result.failed&&result.failed.length>0&&failures.push({type:schema.name,stage:"entries",message:`${result.failed.length} entry(ies) rejected${locale?` (${locale})`:""}: ${result.failed[0]?.message??result.failed[0]?.code??"unknown"}`})}locale&&usedLocales.add(locale)}catch(error){failures.push({type:schema.name,stage:"entries",message:`${errorMessage3(error)}${locale?` (${locale})`:""}`})}}}let skips=skipped>0?`, ${skipped} already present`:"",issues=failures.length>0?`, ${failures.length} issue(s)`:"";return sp.succeed(`Scaffolded ${schemasCreated} ${cms} type(s) + ${entriesCreated} example entr${entriesCreated===1?"y":"ies"} in Fimo${skips}${issues}`),{cms,schemas:schemasCreated,entries:entriesCreated,locales:[...usedLocales],skipped,failures}}catch(error){throw sp.stop(),error}}var init_cms_scaffold=__esm({"src/cli/utils/cms-scaffold.ts"(){init_dist();init_example_content();init_schema();__name(extractSchemaTypeNames,"extractSchemaTypeNames");__name(withoutReferences,"withoutReferences");__name(blocksWithoutReferences,"blocksWithoutReferences");__name(hasReferences,"hasReferences");__name(orderByDependency,"orderByDependency");__name(scaffoldCms,"scaffoldCms")}});function syncStateColor(state,p2){switch(state){case"in-sync":return p2.green("in sync");case"ahead":return p2.blue("ahead");case"behind":return p2.yellow("behind");case"diverged":return p2.red("diverged");default:return p2.dim("unknown")}}function renderStatus2(report,p2,opts={}){let lines=[],sep3=opts.ascii?"|":"\xB7",header=`${p2.bold(`env: ${report.env}`)} ${p2.dim(`vs ${report.vs} ${sep3}`)} ${syncStateColor(report.syncState,p2)}`;if(lines.push(header),lines.push(""),opts.short){for(let name of SURFACE_NAMES){if(opts.surface&&opts.surface!==name)continue;let delta=report.surfaces.find(s=>s.surface===name);if(!delta)continue;let innerSep=opts.ascii?"|":"\xB7",counts=`${delta.changedCount} changed${delta.conflictCount>0?` ${innerSep} ${delta.conflictCount} conflicts`:""}`,truncatedHint=delta.truncated&&delta.items&&delta.items.length<delta.changedCount?p2.dim(` ${innerSep} ${delta.items.length} of ${delta.changedCount} shown`):"";lines.push(` ${p2.bold(name.padEnd(14))} ${p2.dim(counts)}${truncatedHint}`)}return lines.join(`
2153
+ `),"render")})}async function schemaDeleteCommand(typeName,options,cmd){let{ctx,api}=await bootstrapProjectCommand(options,cmd,{refuseReadOnly:!0});await requireOperation("cms.schema.delete",{projectId:ctx.projectId,env:ctx.env});let result=await api.deleteSchema(ctx.projectId,typeName);ui.result({command:"schemas delete",data:result,render:__name(()=>renderPrettyJson(result),"render")})}var SchemaCommandError,init_schema=__esm({"src/cli/commands/schema.ts"(){init_dist();init_sync_schemas();init_validate_schemas();init_api();init_capability_guard();init_project_context();init_project();init_render_json();SchemaCommandError=class extends Error{static{__name(this,"SchemaCommandError")}code;constructor(code2,message){super(message),this.name="SchemaCommandError",this.code=code2}};__name(renameOperation,"renameOperation");__name(humanizeUid,"humanizeUid");__name(toApiShape,"toApiShape");__name(schemaListCommand,"schemaListCommand");__name(schemaGetCommand,"schemaGetCommand");__name(schemaPushCommand,"schemaPushCommand");__name(isAlreadyExistsError,"isAlreadyExistsError");__name(sortSchemasByReferenceDependencies,"sortSchemasByReferenceDependencies");__name(isUnknownTargetError,"isUnknownTargetError");__name(pushAllSchemas,"pushAllSchemas");__name(applyDraftAdoption,"applyDraftAdoption");__name(parseDraftSelectors,"parseDraftSelectors");__name(schemaAdoptDraftsCommand,"schemaAdoptDraftsCommand");__name(schemaDeleteCommand,"schemaDeleteCommand")}});import{readFileSync as readFileSync22}from"node:fs";function isChromePrefix(prefix){return CHROME_PREFIX.test(prefix)}function resolveRouteFiles(cwd,framework,routes){return frameworkRouteFiles(framework)?.(cwd,routes)??[]}function keyPrefix(key){let dot=key.indexOf(".");return dot>0?key.slice(0,dot):null}function groupKeysByPrefix(stagedKeys){let groups=new Map;for(let key of stagedKeys){let prefix=keyPrefix(key);prefix&&groups.set(prefix,[...groups.get(prefix)??[],key])}return groups}function collectPageLabelPrefixes(resolutions,stagedKeys,routes){let groups=groupKeysByPrefix(stagedKeys),updates=new Map;for(let{routeId:routeId2,file}of resolutions){let route=routes[routeId2];if(!route||Array.isArray(route.labelPrefixes)&&route.labelPrefixes.length>0)continue;let code2;try{code2=readFileSync22(file,"utf8")}catch{continue}let matched=[];for(let[prefix,keys]of groups)keys.some(key=>code2.includes(key))&&matched.push(prefix);matched.sort(),matched.length>0&&(matched.length>1||matched[0]!==routeId2)&&updates.set(routeId2,matched)}return updates}function unclaimedLabelPrefixes(stagedKeys,routes){let claimed=new Set;for(let[routeId2,route]of Object.entries(routes))if(claimed.add(routeId2),Array.isArray(route?.labelPrefixes))for(let prefix of route.labelPrefixes)typeof prefix=="string"&&claimed.add(prefix.replace(/\.$/,""));return[...groupKeysByPrefix(stagedKeys)].filter(([prefix])=>!claimed.has(prefix)).map(([prefix,keys])=>({prefix,exampleKey:keys[0],keys:keys.length,chrome:isChromePrefix(prefix)})).sort((a,b)=>a.prefix.localeCompare(b.prefix))}function collectPageSingles(resolutions,singletonUids,routes){let updates=new Map;if(singletonUids.length===0)return updates;for(let{routeId:routeId2,file}of resolutions){let route=routes[routeId2];if(!route||Array.isArray(route.singles)&&route.singles.length>0)continue;let code2;try{code2=readFileSync22(file,"utf8")}catch{continue}let claimed=singletonUids.filter(uid=>[`documents/${uid}`,`useFimoSingle('${uid}'`,`useFimoSingle("${uid}"`,`fetchDocument('${uid}'`,`fetchDocument("${uid}"`].some(marker=>code2.includes(marker))).sort();claimed.length>0&&updates.set(routeId2,claimed)}return updates}var CHROME_PREFIX,init_label_prefixes=__esm({"src/scripts/routes/label-prefixes.ts"(){init_discover();init_module_resolve();CHROME_PREFIX=/(header|footer|nav|menu|topbar|sidebar|banner|cookie|breadcrumb|social)/i;__name(isChromePrefix,"isChromePrefix");__name(resolveRouteFiles,"resolveRouteFiles");__name(keyPrefix,"keyPrefix");__name(groupKeysByPrefix,"groupKeysByPrefix");__name(collectPageLabelPrefixes,"collectPageLabelPrefixes");__name(unclaimedLabelPrefixes,"unclaimedLabelPrefixes");__name(collectPageSingles,"collectPageSingles")}});var page_structure_exports={};__export(page_structure_exports,{buildPageSingleDraft:()=>buildPageSingleDraft,buildSharedSingleDrafts:()=>buildSharedSingleDrafts,collectContentModelCandidates:()=>collectContentModelCandidates,collectIllustrationCandidates:()=>collectIllustrationCandidates,countDraftSections:()=>countDraftSections,draftPageStructures:()=>draftPageStructures,isIllustrationSection:()=>isIllustrationSection});import{readFileSync as readFileSync23,statSync as statSync13}from"node:fs";import{basename as basename8,join as join31,relative as relative8}from"node:path";function sectionTags(code2){let seen=new Set,tags=[];for(let match of code2.matchAll(/<([A-Z]\w*)[\s/>]/g))seen.has(match[1])||(seen.add(match[1]),tags.push(match[1]));return tags}function draftSection(context,tag,file,depth){let rel=relative8(context.cwd,file),prefix=context.style.fileScope(rel),labelKeys=context.keysByPrefix.get(prefix)??[],collections=(context.collectionsByFile.get(rel)??[]).map(candidate=>({name:candidate.name,fields:candidate.fields,count:candidate.count,...candidate.typedRows?{rows:candidate.typedRows.slice(0,MAX_DRAFT_ROWS)}:{}})),children2=depth<MAX_SECTION_DEPTH?draftChildSections(context,file,depth+1):[];if(labelKeys.length===0&&collections.length===0&&children2.length===0)return null;let draft={key:camel(tag),component:tag,file:rel,prefix,labelKeys,collections};return children2.length>0&&(draft.children=children2),draft}function resolveAutoImportedComponent(context,tag){for(let dir of context.style.fallbackComponentDirs)for(let ext of context.style.extensions){let candidate=join31(context.cwd,dir,`${tag}${ext}`);try{if(statSync13(candidate).isFile())return candidate}catch{}}return null}function draftChildSections(context,file,depth){let code2;try{code2=readFileSync23(file,"utf8")}catch{return[]}let imports=componentImports(code2),sections=[];for(let tag of sectionTags(code2)){let spec=imports.get(tag),sectionFile=spec?resolveModuleFile(context.cwd,file,spec,context.style.extensions):resolveAutoImportedComponent(context,tag);if(!sectionFile||context.visited.has(sectionFile))continue;context.visited.add(sectionFile);let section=draftSection(context,tag,sectionFile,depth);section&&sections.push(section)}return sections}function draftPageOwnSection(context,file){let rel=relative8(context.cwd,file),prefix=context.style.fileScope(rel),labelKeys=context.keysByPrefix.get(prefix)??[],collections=(context.collectionsByFile.get(rel)??[]).map(candidate=>({name:candidate.name,fields:candidate.fields,count:candidate.count,...candidate.typedRows?{rows:candidate.typedRows.slice(0,MAX_DRAFT_ROWS)}:{}}));if(labelKeys.length===0&&collections.length===0)return null;let component=pascal(basename8(rel).replace(/\.\w+$/,""));return{key:camel(component),component,file:rel,prefix,labelKeys,collections,pageOwn:!0}}function draftPageStructures(args){let{cwd,framework,routes,collections}=args,keysByPrefix=new Map;for(let key of args.stagedKeys){let dot=key.indexOf(".");if(dot>0){let prefix=key.slice(0,dot);keysByPrefix.set(prefix,[...keysByPrefix.get(prefix)??[],key])}}let collectionsByFile=new Map;for(let candidate of collections)collectionsByFile.set(candidate.file,[...collectionsByFile.get(candidate.file)??[],candidate]);let style=frameworkSectionStyle(framework),drafts=[];for(let{routeId:routeId2,file}of resolveRouteFiles(cwd,framework,routes)){let context={cwd,style,keysByPrefix,collectionsByFile,visited:new Set([file])},childSections=draftChildSections(context,file,1),ownSection=draftPageOwnSection(context,file),sections=ownSection?[ownSection,...childSections]:childSections;sections.length>=1&&drafts.push({pageId:routeId2,single:pascal(routeId2),sections})}return markSharedSections(drafts),drafts}function markSharedSections(drafts){let pagesByFile=new Map,index2=__name((pageId,sections)=>{for(let section of sections)pagesByFile.set(section.file,(pagesByFile.get(section.file)??new Set).add(pageId)),index2(pageId,section.children??[])},"index");for(let draft of drafts)index2(draft.pageId,draft.sections);let flag2=__name(sections=>{for(let section of sections)(pagesByFile.get(section.file)?.size??0)>1&&(section.shared=!0),flag2(section.children??[])},"flag");for(let draft of drafts)flag2(draft.sections)}function countDraftSections(draft){let walk2=__name(sections=>sections.reduce((total,section)=>total+1+walk2(section.children??[]),0),"walk");return walk2(draft.sections)}function isIllustrationSection(section,labelValues){if(section.pageOwn)return!1;let values=section.labelKeys.map(key=>labelValues[key]??"").filter(value=>value.trim().length>0);if(values.length<ILLUSTRATION_MIN_LABELS||values.filter(looksLikeProse).length/values.length>.4)return!1;if(values.length>=ILLUSTRATION_DENSE)return!0;let shortRatio=values.filter(value=>wordCount(value)<=3).length/values.length;return ILLUSTRATION_NAME.test(section.component)&&shortRatio>=.7}function isDroppableIllustration(section,labelValues,contentConfirmed){return isIllustrationSection(section,labelValues)&&!contentConfirmed.has(sectionIdentity(section))}function sectionBlock(section,labelValues,illustrations,contentConfirmed){let fields={},value={},fieldCount=0,groups=new Map,relOf=__name(key=>key.startsWith(`${section.prefix}.`)?key.slice(section.prefix.length+1):key,"relOf");for(let key of section.labelKeys){let parts=relOf(key).split(".");if(parts.length>=3){let[group,item,...fieldParts]=parts,itemMap=groups.get(group)??new Map,itemFields=itemMap.get(item)??{};itemFields[camel(fieldParts.join("-"))]=labelValues[key]??"",itemMap.set(item,itemFields),groups.set(group,itemMap);continue}let name=labelFieldName(key);if(fields[name])continue;let labelValue=labelValues[key]??"";fields[name]={type:scalarType(labelValue)},value[name]=labelValue,fieldCount+=1}for(let[group,itemMap]of groups){let name=camel(group);if(fields[name])continue;let itemFields={};for(let itemValue of itemMap.values())for(let fieldName of Object.keys(itemValue))itemFields[fieldName]={type:"string"};fields[name]={type:"blocks",schema:{fields:itemFields}},value[name]=[...itemMap.values()],fieldCount+=1}for(let collection of section.collections){let name=camel(collection.name);if(fields[name])continue;let itemFields={};for(let field of collection.fields)itemFields[field]={type:"string"};Object.keys(itemFields).length!==0&&(fields[name]={type:"blocks",schema:{fields:itemFields}},value[name]=(collection.rows??[]).map(row2=>{let item={};for(let field of collection.fields){let cell=row2[field];cell!=null&&typeof cell!="object"&&(item[field]=typeof cell=="string"?cell:String(cell))}return item}),fieldCount+=1)}for(let child of section.children??[]){if(child.shared)continue;if(isDroppableIllustration(child,labelValues,contentConfirmed)){illustrations.push(child.component);continue}let block=sectionBlock(child,labelValues,illustrations,contentConfirmed);!block||fields[child.key]||(fields[child.key]={type:"blocks",max:1,schema:{fields:block.fields}},value[child.key]=[block.value],fieldCount+=block.fieldCount)}return Object.keys(fields).length===0?null:{fields,value,fieldCount}}function buildPageSingleDraft(draft,labelValues,contentConfirmed=new Set){let fields={},document={},illustrations=[],totalFields=0;for(let section of draft.sections){if(section.shared||fields[section.key])continue;if(isDroppableIllustration(section,labelValues,contentConfirmed)){illustrations.push(section.component);continue}let block=sectionBlock(section,labelValues,illustrations,contentConfirmed);block&&(fields[section.key]={type:"blocks",max:1,schema:{fields:block.fields}},document[section.key]=[block.value],totalFields+=block.fieldCount)}return Object.keys(fields).length===0||totalFields<3?null:{uid:draft.single,pageId:draft.pageId,schema:{uid:draft.single,name:draft.single,isSingleton:!0,fields},document,...illustrations.length>0?{illustrations:[...new Set(illustrations)]}:{}}}function buildSharedSingleDrafts(drafts,labelValues){let byIdentity=new Map,walk2=__name(sections=>{for(let section of sections){if(section.shared){let identity3=`${section.file}::${section.component}`;if(!byIdentity.has(identity3)){let block=sectionBlock(section,labelValues,[],new Set);if(block&&Object.keys(block.fields).length>0){let uid=pascal(section.component);byIdentity.set(identity3,{uid,component:section.component,file:section.file,schema:{uid,name:uid,isSingleton:!0,fields:block.fields},document:block.value})}}continue}walk2(section.children??[])}},"walk");for(let draft of drafts)walk2(draft.sections);return[...byIdentity.values()]}function collectIllustrationCandidates(drafts,labelValues){let byIdentity=new Map,walk2=__name(sections=>{for(let section of sections){if(isIllustrationSection(section,labelValues)){let identity3=`${section.file}::${section.component}`;byIdentity.has(identity3)||byIdentity.set(identity3,{file:section.file,component:section.component,labelKeys:[...section.labelKeys],samples:sectionSamples(section,labelValues)})}walk2(section.children??[])}},"walk");for(let draft of drafts)walk2(draft.sections);return[...byIdentity.values()]}function collectContentModelCandidates(drafts,labelValues,contentConfirmed=new Set){let eligible=__name(section=>!section.shared&&!isDroppableIllustration(section,labelValues,contentConfirmed),"eligible"),pagesByComponent=new Map,count=__name((pageId,sections)=>{for(let section of sections)eligible(section)&&pagesByComponent.set(section.component,(pagesByComponent.get(section.component)??new Set).add(pageId)),count(pageId,section.children??[])},"count");for(let draft of drafts)count(draft.pageId,draft.sections);let byIdentity=new Map,collect2=__name(sections=>{for(let section of sections){let pages2=pagesByComponent.get(section.component)?.size??0;if(eligible(section)&&pages2>=2){let identity3=`${section.file}::${section.component}`;byIdentity.has(identity3)||byIdentity.set(identity3,{file:section.file,component:section.component,pages:pages2,samples:sectionSamples(section,labelValues)})}collect2(section.children??[])}},"collect");for(let draft of drafts)collect2(draft.sections);return[...byIdentity.values()]}var MAX_SECTION_DEPTH,MAX_DRAFT_ROWS,pascal,camel,labelFieldName,scalarType,ILLUSTRATION_NAME,ILLUSTRATION_DENSE,ILLUSTRATION_MIN_LABELS,wordCount,looksLikeProse,sectionIdentity,SECTION_SAMPLE_COUNT,sectionSamples,init_page_structure=__esm({"src/scripts/routes/page-structure.ts"(){init_discover();init_label_prefixes();MAX_SECTION_DEPTH=6,MAX_DRAFT_ROWS=50,pascal=__name(value=>value.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/([A-Z]+)([A-Z][a-z])/g,"$1-$2").split(/[-_.\s]/).filter(Boolean).map(word=>word.charAt(0).toUpperCase()+word.slice(1).toLowerCase()).join(""),"pascal"),camel=__name(value=>{let p2=pascal(value);return p2.charAt(0).toLowerCase()+p2.slice(1)},"camel");__name(sectionTags,"sectionTags");__name(draftSection,"draftSection");__name(resolveAutoImportedComponent,"resolveAutoImportedComponent");__name(draftChildSections,"draftChildSections");__name(draftPageOwnSection,"draftPageOwnSection");__name(draftPageStructures,"draftPageStructures");__name(markSharedSections,"markSharedSections");__name(countDraftSections,"countDraftSections");labelFieldName=__name(key=>camel(key.split(".").pop()??key),"labelFieldName"),scalarType=__name(value=>value.length>80||value.includes(`
2154
+ `)?"text":"string","scalarType"),ILLUSTRATION_NAME=/mock|demo|preview|illustration|visual|showcase|diagram|orbit|screenshot|animation|graphic|dashboard|widget|figure/i,ILLUSTRATION_DENSE=30,ILLUSTRATION_MIN_LABELS=8,wordCount=__name(value=>value.trim().split(/\s+/).filter(Boolean).length,"wordCount"),looksLikeProse=__name(value=>{let words=wordCount(value);return words>=8||words>=5&&/[.!?]/.test(value.trim())},"looksLikeProse");__name(isIllustrationSection,"isIllustrationSection");sectionIdentity=__name(section=>`${section.file}::${section.component}`,"sectionIdentity");__name(isDroppableIllustration,"isDroppableIllustration");__name(sectionBlock,"sectionBlock");__name(buildPageSingleDraft,"buildPageSingleDraft");__name(buildSharedSingleDrafts,"buildSharedSingleDrafts");SECTION_SAMPLE_COUNT=6,sectionSamples=__name((section,labelValues)=>section.labelKeys.map(key=>labelValues[key]??"").filter(value=>value.trim().length>0).slice(0,SECTION_SAMPLE_COUNT),"sectionSamples");__name(collectIllustrationCandidates,"collectIllustrationCandidates");__name(collectContentModelCandidates,"collectContentModelCandidates")}});function kebabCase(name){return name.replace(/([a-z0-9])([A-Z])/g,"$1-$2").replace(/[^a-zA-Z0-9]+/g,"-").toLowerCase().replace(/^-+|-+$/g,"")}function richTextDoc(text3){return{type:"doc",content:[{type:"paragraph",content:[{type:"text",text:text3}]}]}}function placeholderMedia(label){let svg=`<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="630"><rect width="100%" height="100%" fill="#e5e7eb"/><text x="50%" y="50%" font-family="sans-serif" font-size="44" fill="#9ca3af" text-anchor="middle" dominant-baseline="middle">${label}</text></svg>`;return{source:"local",url:`data:image/svg+xml;utf8,${encodeURIComponent(svg)}`,alt:`${label} placeholder`,width:1200,height:630,mime:"image/svg+xml",name:"placeholder.svg"}}function exampleDate(n){return new Date(Date.UTC(2024,0,n)).toISOString().slice(0,10)}function exampleReferenceSlug(field){let targetName=field.target??field.targets?.[0];if(!targetName)return;let slug=`${kebabCase(targetName)}-example-1`;return field.many?[slug]:slug}function fillFieldValue(field,def,ctx){let baked=def.default;if(baked!==void 0)return baked;switch(def.type){case"string":return`${humanizeSegment(field)} example ${ctx.index}${ctx.localeSuffix}`;case"richtext":return richTextDoc(`Example ${humanizeSegment(ctx.schemaName).toLowerCase()} content ${ctx.index}${ctx.localeSuffix}.`);case"number":return ctx.index;case"boolean":return ctx.index%2===1;case"date":return exampleDate(ctx.index);case"json":return{};case"media":return placeholderMedia(humanizeSegment(field));case"blocks":return fillBlocks(def,ctx);default:return}}function fillBlocks(def,ctx){if(ctx.depth>=MAX_FILL_DEPTH)return[];let childCtx={...ctx,depth:ctx.depth+1},schema=def.schema;if("oneOf"in schema){let total=schema.oneOf.length,take=Math.min(EXAMPLE_BLOCK_VARIANTS,total),offset=total>0?(ctx.index-1)*take%total:0;return Array.from({length:take},(_2,k)=>schema.oneOf[(offset+k)%total]).map(variant=>({_type:variant.uid,...fillItem(variant.fields,childCtx)}))}let itemCount=def.max===1?1:EXAMPLE_REPEATABLE_ITEMS;return Array.from({length:itemCount},()=>fillItem(schema.fields,childCtx))}function fillItem(fields,ctx){let item={};for(let[name,def]of Object.entries(fields)){let value=fillFieldValue(name,def,ctx);value!==void 0&&(item[name]=value)}return item}function generateExampleSeed(schema,options={}){let locale=options.locale,localeSuffix=locale?` (${locale})`:"",count=schema.isSingleton?1:Math.max(1,options.count??DEFAULT_COUNT),references={},rows=[];for(let i=1;i<=count;i+=1){let row2={};schema.isSingleton||(row2.slug=`${kebabCase(schema.name)}-example-${i}`);for(let[field,def]of Object.entries(schema.fields)){if(schema.examples&&field in schema.examples){row2[field]=schema.examples[field];continue}if(def.type==="reference"){let value2=exampleReferenceSlug(def);value2!==void 0&&(row2[field]=value2,references[field]={...def.target?{target:def.target}:{},...def.targets?{targets:def.targets}:{},by:"slug",...def.many?{many:!0}:{}});continue}let value=fillFieldValue(field,def,{localeSuffix,index:i,schemaName:schema.name,depth:0});value!==void 0&&(row2[field]=value)}rows.push(row2)}return{name:schema.name,isSingleton:schema.isSingleton,localized:schema.localized,rows,references}}var DEFAULT_COUNT,EXAMPLE_BLOCK_VARIANTS,EXAMPLE_REPEATABLE_ITEMS,MAX_FILL_DEPTH,init_example_content=__esm({"src/scripts/cms/example-content.ts"(){init_humanize();DEFAULT_COUNT=3,EXAMPLE_BLOCK_VARIANTS=5,EXAMPLE_REPEATABLE_ITEMS=2,MAX_FILL_DEPTH=6;__name(kebabCase,"kebabCase");__name(richTextDoc,"richTextDoc");__name(placeholderMedia,"placeholderMedia");__name(exampleDate,"exampleDate");__name(exampleReferenceSlug,"exampleReferenceSlug");__name(fillFieldValue,"fillFieldValue");__name(fillBlocks,"fillBlocks");__name(fillItem,"fillItem");__name(generateExampleSeed,"generateExampleSeed")}});var cms_scaffold_exports={};__export(cms_scaffold_exports,{extractSchemaTypeNames:()=>extractSchemaTypeNames,scaffoldCms:()=>scaffoldCms});function extractSchemaTypeNames(raw){let names=new Set,list=Array.isArray(raw)?raw:raw&&typeof raw=="object"?raw.data??raw.types:null;if(Array.isArray(list))for(let item of list){let name=item&&typeof item=="object"?item.name:void 0;typeof name=="string"&&names.add(name)}return names}function withoutReferences(fields){let out={};for(let[name,def]of Object.entries(fields))def.type!=="reference"&&(out[name]=def.type==="blocks"?blocksWithoutReferences(def):def);return out}function blocksWithoutReferences(def){return"oneOf"in def.schema?{...def,schema:{oneOf:def.schema.oneOf.map(variant=>({...variant,fields:withoutReferences(variant.fields)}))}}:{...def,schema:{fields:withoutReferences(def.schema.fields)}}}function hasReferences(fields){return Object.values(fields).some(def=>def.type==="reference"?!0:def.type==="blocks"?"oneOf"in def.schema?def.schema.oneOf.some(variant=>hasReferences(variant.fields)):hasReferences(def.schema.fields):!1)}function orderByDependency(schemas3){let byName=new Map(schemas3.map(schema=>[schema.name,schema])),visited=new Set,ordered=[],visit2=__name((schema,stack)=>{if(!(visited.has(schema.name)||stack.has(schema.name))){stack.add(schema.name);for(let field of Object.values(schema.fields))if(field.type==="reference"){let targets=field.targets??(field.target?[field.target]:[]);for(let target of targets){let dep=byName.get(target);dep&&dep.name!==schema.name&&visit2(dep,stack)}}stack.delete(schema.name),visited.add(schema.name),ordered.push(schema)}},"visit");for(let schema of schemas3)visit2(schema,new Set);return ordered}async function scaffoldCms(opts){let{schemas:schemas3,cms,ctx,api,locales,count=3,force=!1}=opts,existingTypes=opts.existingTypes??new Set,ordered=orderByDependency(schemas3),sp=spinner(`Scaffolding ${cms} content model in Fimo`,{rail:opts.rail??!1}),errorMessage3=__name(error=>error instanceof Error?error.message:String(error),"errorMessage"),schemasCreated=0,entriesCreated=0,skipped=0,failures=[],usedLocales=new Set,created=new Set;try{for(let schema of ordered){let exists=existingTypes.has(schema.name);if(exists&&!force){skipped+=1,created.add(schema.name);continue}let bare={name:schema.name,label:schema.label,isSingleton:schema.isSingleton,fields:withoutReferences(schema.fields)};try{exists?await api.updateSchema(ctx.projectId,schema.name,bare):await api.createSchema(ctx.projectId,bare),schemasCreated+=1,created.add(schema.name)}catch(error){if(isAlreadyExistsError(error))try{await api.updateSchema(ctx.projectId,schema.name,bare),schemasCreated+=1,created.add(schema.name);continue}catch(updateError){failures.push({type:schema.name,stage:"schema",message:errorMessage3(updateError)});continue}failures.push({type:schema.name,stage:"schema",message:errorMessage3(error)})}}for(let schema of ordered)if(!(!created.has(schema.name)||existingTypes.has(schema.name)&&!force||!hasReferences(schema.fields)))try{await api.updateSchema(ctx.projectId,schema.name,{name:schema.name,label:schema.label,isSingleton:schema.isSingleton,fields:schema.fields})}catch(error){failures.push({type:schema.name,stage:"schema",message:`references: ${errorMessage3(error)}`})}for(let schema of ordered){if(!created.has(schema.name))continue;force&&!schema.isSingleton&&await api.bulkDeleteEntries(ctx.projectId,schema.name,{where:{}}).catch(()=>{});let seedLocales=schema.localized&&locales.length>0?locales:[void 0];for(let locale of seedLocales){let seed=generateExampleSeed(schema,{count,locale});try{if(schema.isSingleton)await api.putDocument(ctx.projectId,schema.name,seed.rows[0]??{},locale?{locale}:{}),entriesCreated+=1;else{let result=await api.importEntries(ctx.projectId,schema.name,{entries:seed.rows.map(data2=>({data:data2})),...locale?{locale}:{},...Object.keys(seed.references).length>0?{references:seed.references}:{},allowDangling:!0});entriesCreated+=result.created?.length??0,result.failed&&result.failed.length>0&&failures.push({type:schema.name,stage:"entries",message:`${result.failed.length} entry(ies) rejected${locale?` (${locale})`:""}: ${result.failed[0]?.message??result.failed[0]?.code??"unknown"}`})}locale&&usedLocales.add(locale)}catch(error){failures.push({type:schema.name,stage:"entries",message:`${errorMessage3(error)}${locale?` (${locale})`:""}`})}}}let skips=skipped>0?`, ${skipped} already present`:"",issues=failures.length>0?`, ${failures.length} issue(s)`:"";return sp.succeed(`Scaffolded ${schemasCreated} ${cms} type(s) + ${entriesCreated} example entr${entriesCreated===1?"y":"ies"} in Fimo${skips}${issues}`),{cms,schemas:schemasCreated,entries:entriesCreated,locales:[...usedLocales],skipped,failures}}catch(error){throw sp.stop(),error}}var init_cms_scaffold=__esm({"src/cli/utils/cms-scaffold.ts"(){init_dist();init_example_content();init_schema();__name(extractSchemaTypeNames,"extractSchemaTypeNames");__name(withoutReferences,"withoutReferences");__name(blocksWithoutReferences,"blocksWithoutReferences");__name(hasReferences,"hasReferences");__name(orderByDependency,"orderByDependency");__name(scaffoldCms,"scaffoldCms")}});function syncStateColor(state,p2){switch(state){case"in-sync":return p2.green("in sync");case"ahead":return p2.blue("ahead");case"behind":return p2.yellow("behind");case"diverged":return p2.red("diverged");default:return p2.dim("unknown")}}function renderStatus2(report,p2,opts={}){let lines=[],sep3=opts.ascii?"|":"\xB7",header=`${p2.bold(`env: ${report.env}`)} ${p2.dim(`vs ${report.vs} ${sep3}`)} ${syncStateColor(report.syncState,p2)}`;if(lines.push(header),lines.push(""),opts.short){for(let name of SURFACE_NAMES){if(opts.surface&&opts.surface!==name)continue;let delta=report.surfaces.find(s=>s.surface===name);if(!delta)continue;let innerSep=opts.ascii?"|":"\xB7",counts=`${delta.changedCount} changed${delta.conflictCount>0?` ${innerSep} ${delta.conflictCount} conflicts`:""}`,truncatedHint=delta.truncated&&delta.items&&delta.items.length<delta.changedCount?p2.dim(` ${innerSep} ${delta.items.length} of ${delta.changedCount} shown`):"";lines.push(` ${p2.bold(name.padEnd(14))} ${p2.dim(counts)}${truncatedHint}`)}return lines.join(`
2144
2155
  `)}let surfaceOpts={ascii:opts.ascii,...opts.all?{maxItems:Number.MAX_SAFE_INTEGER}:{}};for(let name of SURFACE_NAMES){if(opts.surface&&opts.surface!==name)continue;let delta=report.surfaces.find(s=>s.surface===name);delta&&(lines.push(renderSurface(delta,p2,surfaceOpts)),lines.push(""))}if(!opts.surface&&report.crossSurface&&report.crossSurface.length>0&&(lines.push(renderCrossSurface(report.crossSurface,p2,{ascii:opts.ascii})),lines.push("")),report.agents&&report.agents.length>0){lines.push(p2.bold("AGENTS")),lines.push(p2.dim(" declared \xB7 active \xB7 last run"));for(let agent of report.agents){let status=agent.status==="active"?p2.green("active"):agent.status==="paused"?p2.yellow("paused"):p2.red("failed"),lastRun=agent.lastRunAt?p2.dim(new Date(agent.lastRunAt).toISOString().slice(0,19)+"Z"):p2.dim("never");lines.push(` ${agent.name.padEnd(18)} ${status.padEnd(7)} ${lastRun}`)}lines.push("")}return lines.join(`
2145
2156
  `).replace(/\n+$/,"")}var init_render_status=__esm({"src/cli/utils/format/render-status.ts"(){init_esm2();init_cross_surface();init_surface();__name(syncStateColor,"syncStateColor");__name(renderStatus2,"renderStatus")}});function pickSurfaces(opts){let selected=[["code","code"],["content","content"],["i18n","translations"],["agents","activations"],["assets","assets"],["forms","forms"]].filter(([flag2])=>opts[flag2]===!0).map(([,surface])=>surface);return selected.length>0?selected:void 0}function withSoftTimeout(p2,ms){return new Promise(resolve10=>{let t2=setTimeout(()=>resolve10({kind:"timeout"}),ms);p2.then(value=>{clearTimeout(t2),resolve10({kind:"ok",value})},error=>{clearTimeout(t2),resolve10({kind:"error",error})})})}async function localCodeSurface(cwd){if(!await isGitRepo(cwd))return{surface:"code",status:"unchanged",changedCount:0,conflictCount:0,items:[]};try{let items=(await runGit2(["status","--porcelain"],cwd)).split(`
2146
2157
  `).filter(Boolean).map(line=>{let code2=line.slice(0,2),path71=line.slice(3).trim();return{verb:code2.startsWith("A")||code2.startsWith("?")?"added":code2.startsWith("D")?"removed":"changed",key:path71,origin:"local-uncommitted"}});return{surface:"code",status:items.length===0?"unchanged":"ok",changedCount:items.length,conflictCount:0,items}}catch{return{surface:"code",status:"unchanged",changedCount:0,conflictCount:0,items:[]}}}function mergeCodeSurfaces(serverCode,local){if(!serverCode)return local;if(serverCode.status==="failed"||serverCode.status==="timed_out")return{...serverCode,items:[...serverCode.items??[],...local.items??[]],changedCount:serverCode.changedCount+local.changedCount};let items=[...serverCode.items??[],...local.items??[]],changedCount=serverCode.changedCount+local.changedCount,conflictCount=serverCode.conflictCount+local.conflictCount;return{surface:"code",status:changedCount>0||conflictCount>0?"ok":"unchanged",durationMs:serverCode.durationMs,changedCount,conflictCount,items}}async function statusCommand2(arg1,maybeCmd){let cmd=maybeCmd??arg1,options=maybeCmd?arg1:cmd.opts(),program2=cmd.parent??cmd,envOverride2=envOverrideFromCommand(program2),ctx=await getProjectContext({cwd:options.cwd,envOverride:envOverride2}),api=new FimoApiClient().withEnv(ctx.env),cwd=resolveProjectCwd(options.cwd),surfaces=pickSurfaces(options),codePromise=localCodeSurface(cwd),serverPromise=withSoftTimeout(api.getEnvStatus(ctx.projectId,ctx.env,{against:options.vs,surfaces}),SOFT_TIMEOUT_MS*15),[local,serverResult]=await Promise.all([codePromise,serverPromise]);if(serverResult.kind==="timeout"){ui.error({command:"status",code:"STATUS_TIMEOUT",message:`Server did not respond within ${SOFT_TIMEOUT_MS*15/1e3}s. Try again, or run \`fimo diff\` to drill in.`});return}if(serverResult.kind==="error"){let err=serverResult.error,message=err instanceof Error?err.message:String(err);ui.error({command:"status",code:"STATUS_REQUEST_FAILED",message:`Failed to fetch status: ${message}`});return}let server=serverResult.value,serverCode=server.surfaces.find(s=>s.surface==="code"),code2=mergeCodeSurfaces(serverCode,local),merged={...server,surfaces:[code2,...server.surfaces.filter(s=>s.surface!=="code")]};ui.result({command:"status",data:merged,render:__name(rctx=>{let p2=rctx.color?palette:makeColorPalette({forceDisable:!0});return renderStatus2(merged,p2,{short:options.short,surface:surfaces?.length===1?surfaces[0]:void 0,all:options.all,ascii:rctx.ascii})},"render")})}var SOFT_TIMEOUT_MS,init_status=__esm({"src/cli/commands/status.ts"(){init_dist();init_api();init_color();init_render_status();init_git();init_project_context();init_project();SOFT_TIMEOUT_MS=2e3;__name(pickSurfaces,"pickSurfaces");__name(withSoftTimeout,"withSoftTimeout");__name(localCodeSurface,"localCodeSurface");__name(mergeCodeSurfaces,"mergeCodeSurfaces");__name(statusCommand2,"statusCommand")}});init_dist();import fs62 from"node:fs";import path70 from"node:path";var import_index=__toESM(require_commander(),1),{program,createCommand,createArgument,createOption,CommanderError,InvalidArgumentError,InvalidOptionArgumentError,Command,Argument,Option,Help}=import_index.default;init_detect_framework();init_api();init_esm();init_dist();init_api();init_config();init_project();import fs12 from"node:fs";import path13 from"node:path";init_esm();var MAX_TYPE_TO_CONFIRM_ATTEMPTS=3;async function runConsent(input){let{caps,allowShell=!1,quiet=!1,io}=input,{caps:known}=partitionCapabilities(caps);if(renderCapabilityList(known,io),quiet)return known.some(isCritical)?(io.print("! critical-tier capabilities require interactive consent (use --allow-critical only when you understand the risk)"),{decision:"denied",approved:[]}):{decision:"allowed",approved:[...known]};let highRisk=known.filter(isHighRisk);if(highRisk.length===0){let ok=await io.promptYesNo(`? Proceed with install of ${input.agentName}? [y/N]`);return{decision:ok?"allowed":"denied",approved:ok?[...known]:[]}}let approved=known.filter(cap=>!isHighRisk(cap)),denied=[];for(let cap of highRisk.filter(c2=>!isCritical(c2))){if(cap==="shell:exec"&&allowShell){approved.push(cap),io.print(` \u2713 ${cap} (--allow-shell)`);continue}await io.promptYesNo(`? Allow ${cap} for ${input.agentName}? [y/n]`)?approved.push(cap):denied.push(cap)}if(denied.length>0)return io.print(`! aborting install \u2014 denied: ${denied.join(", ")}`),{decision:"denied",approved:[]};for(let cap of highRisk.filter(isCritical)){if(!await typeToConfirm(cap,input.agentName,io))return io.print(`! aborting install \u2014 failed to confirm ${cap}`),{decision:"denied",approved:[]};approved.push(cap)}return{decision:"allowed",approved}}__name(runConsent,"runConsent");async function typeToConfirm(cap,agentName,io){io.print(""),io.print(`! ${agentName} declares the CRITICAL capability '${cap}'`),io.print(" Type the literal token to confirm; anything else aborts.");for(let attempt=1;attempt<=MAX_TYPE_TO_CONFIRM_ATTEMPTS;attempt++){if(await io.promptText(` type '${cap}' (${attempt}/${MAX_TYPE_TO_CONFIRM_ATTEMPTS}): `)===cap)return!0;io.print(" mismatch.")}return!1}__name(typeToConfirm,"typeToConfirm");function renderCapabilityList(caps,io){if(caps.length===0){io.print(" (no capabilities declared \u2014 read-only default trio will apply at runtime)");return}io.print(""),io.print("This agent declares the following capabilities:");let byTier={low:[],medium:[],high:[],critical:[]};for(let cap of caps)byTier[riskTierOf(cap)].push(cap);let ORDER=["low","medium","high","critical"];for(let tier of ORDER){let list=byTier[tier];if(list.length!==0)for(let cap of list.sort())io.print(` \u25CF ${tier.padEnd(8)} ${cap}`)}io.print("")}__name(renderCapabilityList,"renderCapabilityList");function defaultConsentIO(){return{print(line){process.stdout.write(`${line}
@@ -2423,13 +2434,14 @@ ${error instanceof CaptureError?error.stderrTail:""}`);parityWarnings.push(`Coul
2423
2434
  ${releaseAgeHint}`:""}${stderrTail}`)}}stepTimer.mark(Date.now(),"Baseline",parityNote?"ok":"skip",parityNote??"not captured");let effectiveDetection={...detection,framework:framework??detection.framework},jsxWrapperModule=frameworkJsxWrapperModule(effectiveDetection),templateWrapStyle=frameworkTemplateWrapStyle(framework),applied=null,rootWiring=null;if(options.apply!==!1&&!options.check)if(!parityNote&&options.parity!==!1)parityWarnings.push("Skipped --apply transforms: the render baseline could not be captured first. After `npx fimo migrate snapshot` succeeds, RE-RUN `npx fimo migrate` \u2014 the codemod (text wrapping, root wiring, collection-page rewiring) only applies then.");else{if(jsxWrapperModule||templateWrapStyle){if(runSp?.update("Applying safe wrap transforms"),applied=jsxWrapperModule?applyWrap(cwd,{excludePrefixes,importModule:jsxWrapperModule}):applyTemplateWrap(cwd,{style:templateWrapStyle,excludePrefixes}),Object.keys(applied.labels).length>0){let labelsPath=path64.join(cwd,".fimo","migration","labels.json");fs57.mkdirSync(path64.dirname(labelsPath),{recursive:!0});let existing=readJson2(labelsPath)??{};fs57.writeFileSync(labelsPath,`${JSON.stringify({...existing,...applied.labels},null,2)}
2424
2435
  `)}scan=scanWrappable(cwd,{i18nFimoWired,excludePrefixes,dataDirs:frameworkDataDirs(framework),keepInternal:!0}),coverage={wrappable:scan.items.length,wrapped:scan.wrappedCount}}let wireRoot=frameworkRootWiring(effectiveDetection);wireRoot&&(rootWiring=wireRoot(cwd),parityWarnings.push(...rootWiring.warnings))}stepTimer.mark(Date.now(),"Apply",applied?"ok":"skip",applied?`${applied.applied.length} auto-wrapped`:"no codemod applied"),runSp?.update("Seeding migrated content");let contentSeed=null,i18nIngest=null,cmsScaffold=null,cmsWired=null,seededApi=null,seededCtx=null;if(!options.check)try{let{bootstrapProjectCommand:bootstrapProjectCommand2}=await Promise.resolve().then(()=>(init_project_context(),project_context_exports)),{seedStagedLabels:seedStagedLabels2}=await Promise.resolve().then(()=>(init_staged_labels(),staged_labels_exports)),{ctx,api}=await bootstrapProjectCommand2({cwd:options.cwd},void 0,{quiet:!0});seededApi=api,seededCtx=ctx;let result=await seedStagedLabels2({cwd,ctx,api});"skipped"in result||(contentSeed=result);let storeDir=findMessageStore(cwd);if(storeDir){let{records,locales}=collectMessageRecords(storeDir);if(records.length>0){await api.setLabels(ctx.projectId,records),i18nIngest={messages:records.length,locales};let configured2=new Set(config.i18n?.locales??[]);for(let locale of locales)configured2.add(locale);config.i18n={...config.i18n,locales:[...configured2]},fs57.writeFileSync(configPath,`${JSON.stringify(config,null,2)}
2425
2436
  `)}}let scaffoldTargets=dataSources.filter(source=>source.kind==="cms"&&source.decision==="ingest"&&source.contentState==="example"&&scaffoldableHosts.has(source.host)&&(options.force||!source.scaffolded));if(scaffoldTargets.length>0&&cmsSchemas.length>0){let{scaffoldCms:scaffoldCms2,extractSchemaTypeNames:extractSchemaTypeNames2}=await Promise.resolve().then(()=>(init_cms_scaffold(),cms_scaffold_exports)),i18nConfig=config.i18n,seedLocales=i18nConfig?.locales&&i18nConfig.locales.length>0?i18nConfig.locales:i18nConfig?.defaultLocale?[i18nConfig.defaultLocale]:[],existingTypes=extractSchemaTypeNames2(await api.listSchemas(ctx.projectId).catch(()=>null));if(cmsScaffold=await scaffoldCms2({schemas:cmsSchemas,cms:cmsConnector?.detection.cms??"CMS",ctx,api,locales:seedLocales,force:options.force,existingTypes}),fs57.writeFileSync(path64.join(cwd,".fimo","migration","cms-scaffold.json"),`${JSON.stringify(cmsScaffold,null,2)}
2426
- `),cmsScaffold.failures.length>0){let first2=cmsScaffold.failures[0];parityWarnings.push(`${cmsScaffold.cms} scaffold: ${cmsScaffold.failures.length} issue(s) \u2014 see .fimo/migration/cms-scaffold.json (e.g. ${first2.type}: ${first2.message})`)}let wired=cmsConnector?.wireClient?.(cwd,cmsSchemas);wired&&(cmsWired=wired,parityWarnings.push(...wired.warnings));for(let source of scaffoldTargets)source.scaffolded=!0;writeDataSourceDecisions(cwd,dataSources)}}catch{}let migrationDir=path64.join(cwd,".fimo","migration"),wrapDir=path64.join(migrationDir,"wrap");fs57.mkdirSync(wrapDir,{recursive:!0}),stepTimer.mark(Date.now(),"Seed",cmsScaffold&&cmsScaffold.failures.length>0?"warn":"ok",`${contentSeed?.seeded??0} labels${cmsScaffold?`, ${cmsScaffold.schemas} CMS types`:""}`);let schemaDrafts=options.check?[]:writeSchemaDrafts(cwd,scan),stagedRows=options.check?0:writeRowsStaging(cwd,scan,schemaDrafts),collectionRewire=null;if(options.apply!==!1&&!options.check&&applied){let rewire=frameworkCollectionRewire(effectiveDetection);rewire&&(scan.collections.length>0||scan.dataFiles.length>0)&&(runSp?.update("Rewiring collection pages"),collectionRewire=rewire(cwd,scan,schemaDrafts),parityWarnings.push(...collectionRewire.warnings),collectionRewire.rewired>0&&(scan=scanWrappable(cwd,{i18nFimoWired,excludePrefixes,dataDirs:frameworkDataDirs(framework),keepInternal:!0}),coverage={wrappable:scan.items.length,wrapped:scan.wrappedCount},schemaDrafts=writeSchemaDrafts(cwd,scan),stagedRows=writeRowsStaging(cwd,scan,schemaDrafts)))}let pageBindings=null,labelPrefixResult=null,pageDraftsSummary=[],pageSingleSummary=[],pageIllustrations=new Set,illustrationUndecided=[],contentModelUndecided=[];if(!options.check){let provisionalUids=new Set,draftFields={};for(let draft of schemaDrafts)provisionalUids.add(draft.uid),draftFields[draft.uid]=draft.fields;let cmsIsWired=cmsWired!=null||dataSources.some(source=>source.kind==="cms"&&source.decision==="ingest"&&source.scaffolded);if(pageBindings=collectPageBindings({routes:config.routes??{},listPages:(collectionRewire?.pages??[]).map(page=>({routePath:page.routePath,schema:page.uid})),cmsPageTypes:cmsIsWired?cmsPageTypeEvidence(cmsSchemas):[],provisionalUids,schemaFields:draftFields}),pageBindings.strong.length>0){let routes=config.routes??{};for(let page of pageBindings.strong){let route=routes[page.routeId];route&&(route.params={[page.param]:page.binding},typeof route.path=="string"&&(!route.label||route.label===discoveredRouteLabel(route.path))&&(route.label=humanizeSegment(page.binding.schema)))}fs57.writeFileSync(configPath,`${JSON.stringify(config,null,2)}
2437
+ `),cmsScaffold.failures.length>0){let first2=cmsScaffold.failures[0];parityWarnings.push(`${cmsScaffold.cms} scaffold: ${cmsScaffold.failures.length} issue(s) \u2014 see .fimo/migration/cms-scaffold.json (e.g. ${first2.type}: ${first2.message})`)}let wired=cmsConnector?.wireClient?.(cwd,cmsSchemas);wired&&(cmsWired=wired,parityWarnings.push(...wired.warnings));for(let source of scaffoldTargets)source.scaffolded=!0;writeDataSourceDecisions(cwd,dataSources)}}catch{}let migrationDir=path64.join(cwd,".fimo","migration"),wrapDir=path64.join(migrationDir,"wrap");fs57.mkdirSync(wrapDir,{recursive:!0}),stepTimer.mark(Date.now(),"Seed",cmsScaffold&&cmsScaffold.failures.length>0?"warn":"ok",`${contentSeed?.seeded??0} labels${cmsScaffold?`, ${cmsScaffold.schemas} CMS types`:""}`);let schemaDrafts=options.check?[]:writeSchemaDrafts(cwd,scan),stagedRows=options.check?0:writeRowsStaging(cwd,scan,schemaDrafts),collectionRewire=null;if(options.apply!==!1&&!options.check&&applied){let rewire=frameworkCollectionRewire(effectiveDetection);rewire&&(scan.collections.length>0||scan.dataFiles.length>0)&&(runSp?.update("Rewiring collection pages"),collectionRewire=rewire(cwd,scan,schemaDrafts),parityWarnings.push(...collectionRewire.warnings),collectionRewire.rewired>0&&(scan=scanWrappable(cwd,{i18nFimoWired,excludePrefixes,dataDirs:frameworkDataDirs(framework),keepInternal:!0}),coverage={wrappable:scan.items.length,wrapped:scan.wrappedCount},schemaDrafts=writeSchemaDrafts(cwd,scan),stagedRows=writeRowsStaging(cwd,scan,schemaDrafts)))}let pageBindings=null,labelPrefixResult=null,pageDraftsSummary=[],pageSingleSummary=[],sharedSingleSummary=[],pageIllustrations=new Set,illustrationUndecided=[],contentModelUndecided=[];if(!options.check){let provisionalUids=new Set,draftFields={};for(let draft of schemaDrafts)provisionalUids.add(draft.uid),draftFields[draft.uid]=draft.fields;let cmsIsWired=cmsWired!=null||dataSources.some(source=>source.kind==="cms"&&source.decision==="ingest"&&source.scaffolded);if(pageBindings=collectPageBindings({routes:config.routes??{},listPages:(collectionRewire?.pages??[]).map(page=>({routePath:page.routePath,schema:page.uid})),cmsPageTypes:cmsIsWired?cmsPageTypeEvidence(cmsSchemas):[],provisionalUids,schemaFields:draftFields}),pageBindings.strong.length>0){let routes=config.routes??{};for(let page of pageBindings.strong){let route=routes[page.routeId];route&&(route.params={[page.param]:page.binding},typeof route.path=="string"&&(!route.label||route.label===discoveredRouteLabel(route.path))&&(route.label=humanizeSegment(page.binding.schema)))}fs57.writeFileSync(configPath,`${JSON.stringify(config,null,2)}
2427
2438
  `)}pageBindings.unbound.length>0&&parityWarnings.push(`${pageBindings.unbound.length} dynamic page(s) not navigable in the Studio preview yet (no schema binding) \u2014 see the agent prompt \xA7 Routes & pages`);let stagedLabelsFile=readJson2(path64.join(cwd,".fimo","migration","labels.json")),stagedKeys=[...new Set([...Object.keys(stagedLabelsFile??{}),...scan.wrappedIds.labels])];if(stagedKeys.length>0){let routes=config.routes??{},resolutions=resolveRouteFiles(cwd,framework??null,routes),prefixUpdates=collectPageLabelPrefixes(resolutions,stagedKeys,routes);if(prefixUpdates.size>0){for(let[routeId2,prefixes]of prefixUpdates){let route=routes[routeId2];route&&(route.labelPrefixes=prefixes)}fs57.writeFileSync(configPath,`${JSON.stringify(config,null,2)}
2428
2439
  `)}labelPrefixResult={prefilled:[...prefixUpdates.entries()].map(([id,prefixes])=>({id,prefixes})),unclaimed:unclaimedLabelPrefixes(stagedKeys,routes)};{let stagedOrder=scan.wrappedIds.ordered.length>0?scan.wrappedIds.ordered:Object.keys(stagedLabelsFile??{}),orders=[];for(let[routeId2,route]of Object.entries(routes)){let rawPrefixes=Array.isArray(route?.labelPrefixes)?route.labelPrefixes.filter(prefix=>typeof prefix=="string"):[routeId2],prefixes=(rawPrefixes.length>0?rawPrefixes:[routeId2]).map(prefix=>prefix.endsWith(".")?prefix:`${prefix}.`),order=stagedOrder.filter(key=>prefixes.some(prefix=>key.startsWith(prefix)));order.length>0&&orders.push({pageId:routeId2,order:order.slice(0,1e3)})}if(orders.length>0||resolutions.length>0)try{let{bootstrapProjectCommand:bootstrapProjectCommand2}=await Promise.resolve().then(()=>(init_project_context(),project_context_exports)),{ctx,api}=await bootstrapProjectCommand2({cwd:options.cwd},void 0,{quiet:!0});for(let{pageId,order}of orders)await api.putPageLabelOrder(ctx.projectId,pageId,order).catch(()=>null);labelPrefixResult.orderedPages=orders.length;let schemaList=await api.listSchemas(ctx.projectId).catch(()=>null),singletonUids=(Array.isArray(schemaList)?schemaList:schemaList?.data??[]).filter(schema=>schema?.isSingleton&&typeof schema.name=="string").map(schema=>schema.name),singleClaims=collectPageSingles(resolutions,singletonUids,routes);if(singleClaims.size>0){for(let[routeId2,singles]of singleClaims){let route=routes[routeId2];route&&(route.singles=singles)}fs57.writeFileSync(configPath,`${JSON.stringify(config,null,2)}
2429
2440
  `)}}catch{parityWarnings.push(`Could not store the on-page label order for ${orders.length} page(s) (not signed in?) \u2014 the Studio Pages view falls back to unordered labels.`)}}let structureDrafts=draftPageStructures({cwd,framework:framework??null,routes,stagedKeys,collections:scan.collections});if(structureDrafts.length>0){let draftsDir=path64.join(migrationDir,"page-drafts");fs57.mkdirSync(draftsDir,{recursive:!0});for(let draft of structureDrafts)fs57.writeFileSync(path64.join(draftsDir,`${draft.pageId}.json`),`${JSON.stringify(draft,null,2)}
2430
2441
  `);pageDraftsSummary=structureDrafts.map(draft=>({id:draft.pageId,single:draft.single,sections:countDraftSections(draft)}));let singlesDir=path64.join(migrationDir,"page-singles");fs57.mkdirSync(singlesDir,{recursive:!0});let contentConfirmed=new Set(readIllustrationDecisions(cwd).filter(record=>record.disposition==="content").map(record=>`${record.file}::${record.component}`));for(let draft of structureDrafts){let single=buildPageSingleDraft(draft,stagedLabelsFile??{},contentConfirmed);if(single){fs57.writeFileSync(path64.join(singlesDir,`${single.uid}.json`),`${JSON.stringify(single,null,2)}
2431
- `),pageSingleSummary.push({id:single.pageId,uid:single.uid,fields:Object.keys(single.schema.fields).length});for(let name of single.illustrations??[])pageIllustrations.add(name)}}let illustrationCandidates=collectIllustrationCandidates(structureDrafts,stagedLabelsFile??{}),interactive=process.stdin.isTTY&&process.stdout.isTTY&&currentMode().format==="pretty",illustrationResult=await resolveIllustrationDecisions(cwd,illustrationCandidates,{interactive,pauseSpinner:__name(()=>runSp?.stop(),"pauseSpinner"),resumeSpinner:__name(()=>{runSp=spinner("Preparing the migration")},"resumeSpinner")});if(illustrationUndecided=illustrationResult.undecided,illustrationResult.dropped.length>0){let locale=config.i18n?.defaultLocale??"en",api=seededApi,ctx=seededCtx;await removeDroppedIllustrations(cwd,illustrationResult.dropped,api&&ctx?key=>api.deleteLabel(ctx.projectId,locale,key):null)}let contentConfirmedNow=new Set(illustrationResult.records.filter(record=>record.disposition==="content").map(record=>`${record.file}::${record.component}`)),contentModelCandidates=collectContentModelCandidates(structureDrafts,stagedLabelsFile??{},contentConfirmedNow);contentModelUndecided=(await resolveContentModelDecisions(cwd,contentModelCandidates,{interactive,pauseSpinner:__name(()=>runSp?.stop(),"pauseSpinner"),resumeSpinner:__name(()=>{runSp=spinner("Preparing the migration")},"resumeSpinner")})).undecided}labelPrefixResult.unclaimed.length>0&&parityWarnings.push(`${labelPrefixResult.unclaimed.length} label prefix(es) not claimed by any page (${labelPrefixResult.unclaimed.slice(0,5).map(entry=>entry.prefix).join(", ")}${labelPrefixResult.unclaimed.length>5?", \u2026":""}) \u2014 the agent prompt \xA7 Routes & pages lists them; shared/chrome prefixes may stay in Labels & Text.`)}}for(let candidate of scan.collections)delete candidate.fieldValues,delete candidate.typedSample,delete candidate.typedRows,delete candidate.manyFields;for(let dataFile of scan.dataFiles)for(let collection of dataFile.collections)delete collection.fieldValues,delete collection.typedSample,delete collection.typedRows,delete collection.manyFields,delete collection.verbatimFields;let wiringStatus=checkRootWiring(cwd,effectiveDetection),structured=remainingStructuredWork(cwd,scan),structuredWorkLeft=structured.remainingCollections.length+structured.undecidedDataFiles.length,plan={generatedAt:new Date().toISOString(),framework:framework??null,routes:routeCount,coverage,items:scan.items,collections:scan.collections,dataFiles:scan.dataFiles},planPath=path64.join(migrationDir,"plan.json");fs57.writeFileSync(planPath,`${JSON.stringify(plan,null,2)}
2432
- `);let cmsScaffoldAvailable=cmsConnector&&cmsSchemas.length>0&&!dataSources.some(source=>source.host===cmsConnector.detection.host&&source.decision==="ingest"&&source.contentState==="example")?{cms:cmsConnector.detection.cms,types:cmsSchemas.length}:void 0,cmsTouchpoints=cmsScaffold?cmsConnector?.detectTouchpoints?.(cwd):void 0;if(illustrationUndecided.length>0||contentModelUndecided.length>0){let pending=[];if(illustrationUndecided.length>0){let names=illustrationUndecided.map(candidate=>candidate.component);pending.push(`${illustrationUndecided.length} possible illustration(s) \u2014 drop from the CMS or keep as content (wrap.illustrations): ${names.slice(0,6).join(", ")}${names.length>6?", \u2026":""}`)}if(contentModelUndecided.length>0){let names=contentModelUndecided.map(candidate=>candidate.component);pending.push(`${contentModelUndecided.length} cross-page section(s) \u2014 classify as Collection / Single / Component (wrap.contentModel): ${names.slice(0,6).join(", ")}${names.length>6?", \u2026":""}`)}ui.error({command:"migrate wrap",code:"MIGRATION_INTERVIEW_REQUIRED",message:`The content model needs ${pending.length} human decision(s) before the agent prompt is generated \u2014 these poison the model if guessed.`,hint:`Run \`fimo migrate wrap\` in an interactive terminal to answer, or record the decisions in .fimo/migration/manifest.json. ${pending.join(". ")}.`});return}let promptPath=path64.join(wrapDir,"agent-prompt.md");if(fs57.writeFileSync(promptPath,renderAgentPrompt(framework??"js",coverage,scan,dataSources,{applied:applied?applied.applied.length:0,seeded:contentSeed?.seeded??0,structuredWorkLeft,schemaDrafts:schemaDrafts.length,stagedRows,rewiredPages:collectionRewire?.rewired??0,i18nIngested:i18nIngest??void 0,i18nWired:i18nFimoWired,cmsScaffold:cmsScaffold??void 0,cmsScaffoldAvailable,cmsWired:cmsWired??void 0,cutover:cmsScaffold&&cmsTouchpoints?{cms:cmsScaffold.cms,...cmsTouchpoints}:void 0,pages:pageBindings?{total:routeCount,machineBound:pageBindings.strong.map(page=>({id:page.routeId,path:page.path,schema:page.binding.schema})),bound:pageBindings.bound,candidates:pageBindings.unbound.flatMap(page=>page.candidates.map(candidate=>({id:candidate.routeId,path:candidate.path,param:candidate.param,schema:candidate.binding.schema,queryField:candidate.binding.queryField,displayField:candidate.binding.displayField,source:candidate.source}))),unbound:pageBindings.unbound.filter(page=>page.candidates.length===0).map(({id,path:pagePath})=>({id,path:pagePath})),labelPrefilled:labelPrefixResult?.prefilled??[],unclaimedPrefixes:labelPrefixResult?.unclaimed??[],drafts:pageDraftsSummary,singleDrafts:pageSingleSummary,illustrations:[...pageIllustrations]}:void 0,seo:seoDecision,decisions:{illustrations:readIllustrationDecisions(cwd).map(({file,component,disposition})=>({file,component,disposition})),contentModel:readContentModelDecisions(cwd).map(({file,component,kind})=>({file,component,kind}))},wiring:wiringStatus?{present:wiringStatus.present,hint:wiringStatus.hint,reason:rootWiring?.warnings[0]?.replace(/^Root wiring not applied: /,"").replace(/ — follow [^—]*$/,"")??null}:null})),parityNote&&(plan.parity={baseline:".fimo/migration/parity-baseline.json",capturedAt:new Date().toISOString()},fs57.writeFileSync(planPath,`${JSON.stringify(plan,null,2)}
2442
+ `),pageSingleSummary.push({id:single.pageId,uid:single.uid,fields:Object.keys(single.schema.fields).length});for(let name of single.illustrations??[])pageIllustrations.add(name)}}let sharedSingles=buildSharedSingleDrafts(structureDrafts,stagedLabelsFile??{});if(sharedSingles.length>0){let sharedDir=path64.join(migrationDir,"shared-singles");fs57.mkdirSync(sharedDir,{recursive:!0});for(let single of sharedSingles)fs57.writeFileSync(path64.join(sharedDir,`${single.uid}.json`),`${JSON.stringify(single,null,2)}
2443
+ `),sharedSingleSummary.push({uid:single.uid,component:single.component,fields:Object.keys(single.schema.fields).length})}let illustrationCandidates=collectIllustrationCandidates(structureDrafts,stagedLabelsFile??{}),interactive=process.stdin.isTTY&&process.stdout.isTTY&&currentMode().format==="pretty",illustrationResult=await resolveIllustrationDecisions(cwd,illustrationCandidates,{interactive,pauseSpinner:__name(()=>runSp?.stop(),"pauseSpinner"),resumeSpinner:__name(()=>{runSp=spinner("Preparing the migration")},"resumeSpinner")});if(illustrationUndecided=illustrationResult.undecided,illustrationResult.dropped.length>0){let locale=config.i18n?.defaultLocale??"en",api=seededApi,ctx=seededCtx;await removeDroppedIllustrations(cwd,illustrationResult.dropped,api&&ctx?key=>api.deleteLabel(ctx.projectId,locale,key):null)}let contentConfirmedNow=new Set(illustrationResult.records.filter(record=>record.disposition==="content").map(record=>`${record.file}::${record.component}`)),contentModelCandidates=collectContentModelCandidates(structureDrafts,stagedLabelsFile??{},contentConfirmedNow);contentModelUndecided=(await resolveContentModelDecisions(cwd,contentModelCandidates,{interactive,pauseSpinner:__name(()=>runSp?.stop(),"pauseSpinner"),resumeSpinner:__name(()=>{runSp=spinner("Preparing the migration")},"resumeSpinner")})).undecided}labelPrefixResult.unclaimed.length>0&&parityWarnings.push(`${labelPrefixResult.unclaimed.length} label prefix(es) not claimed by any page (${labelPrefixResult.unclaimed.slice(0,5).map(entry=>entry.prefix).join(", ")}${labelPrefixResult.unclaimed.length>5?", \u2026":""}) \u2014 the agent prompt \xA7 Routes & pages lists them; shared/chrome prefixes may stay in Labels & Text.`)}}for(let candidate of scan.collections)delete candidate.fieldValues,delete candidate.typedSample,delete candidate.typedRows,delete candidate.manyFields;for(let dataFile of scan.dataFiles)for(let collection of dataFile.collections)delete collection.fieldValues,delete collection.typedSample,delete collection.typedRows,delete collection.manyFields,delete collection.verbatimFields;let wiringStatus=checkRootWiring(cwd,effectiveDetection),structured=remainingStructuredWork(cwd,scan),structuredWorkLeft=structured.remainingCollections.length+structured.undecidedDataFiles.length,plan={generatedAt:new Date().toISOString(),framework:framework??null,routes:routeCount,coverage,items:scan.items,collections:scan.collections,dataFiles:scan.dataFiles},planPath=path64.join(migrationDir,"plan.json");fs57.writeFileSync(planPath,`${JSON.stringify(plan,null,2)}
2444
+ `);let cmsScaffoldAvailable=cmsConnector&&cmsSchemas.length>0&&!dataSources.some(source=>source.host===cmsConnector.detection.host&&source.decision==="ingest"&&source.contentState==="example")?{cms:cmsConnector.detection.cms,types:cmsSchemas.length}:void 0,cmsTouchpoints=cmsScaffold?cmsConnector?.detectTouchpoints?.(cwd):void 0;if(illustrationUndecided.length>0||contentModelUndecided.length>0){let pending=[];if(illustrationUndecided.length>0){let names=illustrationUndecided.map(candidate=>candidate.component);pending.push(`${illustrationUndecided.length} possible illustration(s) \u2014 drop from the CMS or keep as content (wrap.illustrations): ${names.slice(0,6).join(", ")}${names.length>6?", \u2026":""}`)}if(contentModelUndecided.length>0){let names=contentModelUndecided.map(candidate=>candidate.component);pending.push(`${contentModelUndecided.length} cross-page section(s) \u2014 classify as Collection / Single / Component (wrap.contentModel): ${names.slice(0,6).join(", ")}${names.length>6?", \u2026":""}`)}ui.error({command:"migrate wrap",code:"MIGRATION_INTERVIEW_REQUIRED",message:`The content model needs ${pending.length} human decision(s) before the agent prompt is generated \u2014 these poison the model if guessed.`,hint:`Run \`fimo migrate wrap\` in an interactive terminal to answer, or record the decisions in .fimo/migration/manifest.json. ${pending.join(". ")}.`});return}let promptPath=path64.join(wrapDir,"agent-prompt.md");if(fs57.writeFileSync(promptPath,renderAgentPrompt(framework??"js",coverage,scan,dataSources,{applied:applied?applied.applied.length:0,seeded:contentSeed?.seeded??0,structuredWorkLeft,schemaDrafts:schemaDrafts.length,stagedRows,rewiredPages:collectionRewire?.rewired??0,i18nIngested:i18nIngest??void 0,i18nWired:i18nFimoWired,cmsScaffold:cmsScaffold??void 0,cmsScaffoldAvailable,cmsWired:cmsWired??void 0,cutover:cmsScaffold&&cmsTouchpoints?{cms:cmsScaffold.cms,...cmsTouchpoints}:void 0,pages:pageBindings?{total:routeCount,machineBound:pageBindings.strong.map(page=>({id:page.routeId,path:page.path,schema:page.binding.schema})),bound:pageBindings.bound,candidates:pageBindings.unbound.flatMap(page=>page.candidates.map(candidate=>({id:candidate.routeId,path:candidate.path,param:candidate.param,schema:candidate.binding.schema,queryField:candidate.binding.queryField,displayField:candidate.binding.displayField,source:candidate.source}))),unbound:pageBindings.unbound.filter(page=>page.candidates.length===0).map(({id,path:pagePath})=>({id,path:pagePath})),labelPrefilled:labelPrefixResult?.prefilled??[],unclaimedPrefixes:labelPrefixResult?.unclaimed??[],drafts:pageDraftsSummary,singleDrafts:pageSingleSummary,sharedSingles:sharedSingleSummary,illustrations:[...pageIllustrations]}:void 0,seo:seoDecision,decisions:{illustrations:readIllustrationDecisions(cwd).map(({file,component,disposition})=>({file,component,disposition})),contentModel:readContentModelDecisions(cwd).map(({file,component,kind})=>({file,component,kind}))},wiring:wiringStatus?{present:wiringStatus.present,hint:wiringStatus.hint,reason:rootWiring?.warnings[0]?.replace(/^Root wiring not applied: /,"").replace(/ — follow [^—]*$/,"")??null}:null})),parityNote&&(plan.parity={baseline:".fimo/migration/parity-baseline.json",capturedAt:new Date().toISOString()},fs57.writeFileSync(planPath,`${JSON.stringify(plan,null,2)}
2433
2445
  `)),runSp){let elapsed=Date.now()-spinnerStartedAt;elapsed<1500&&await new Promise(resolve10=>setTimeout(resolve10,1500-elapsed)),runSp.stop()}let dependencyChanged=wiring.changes.some(change=>change.startsWith("added")||change.startsWith("updated fimo ")),promptRel=path64.relative(cwd,promptPath),data2={framework,routes:routeCount,files_scanned:scan.filesScanned,...coverage,wiring_changes:wiring.changes,applied:applied?{count:applied.applied.length,files:applied.filesChanged}:null,env_sync:envSync,package_manager:pm,plan_path:path64.relative(cwd,planPath),prompt_path:promptRel};"skipped"in envSync&&envSync.skipped==="unavailable"&&parityWarnings.push(`Could not import your env keys into the project (${envSync.error??"unknown"}) \u2014 pages with server-side external fetches may hang in the sandbox. Import manually with npx fimo secrets set / vars set.`),stepTimer.mark(Date.now(),"Finalize","ok",`${schemaDrafts.length} draft(s)`);let dashboardSteps=stepTimer.steps(),dashboardTotalMs=stepTimer.totalMs(Date.now());ui.result({command:"migrate wrap",data:data2,render:__name(ctx=>{let p2=ctx.color?palette:makeColorPalette({forceDisable:!0}),rootWiringDone=!wiringStatus||wiringStatus.present||scan.wrappedCount===0,migrationComplete=coverage.wrappable===0&&!dependencyChanged&&rootWiringDone&&structuredWorkLeft===0,dashboard=renderWrapDashboard({title:"Migration to Fimo \xB7 wrap in place",verdict:migrationComplete?"complete":"in progress",steps:dashboardSteps,gates:[{label:"Coverage",status:coverage.wrappable===0?"ok":"warn"},{label:"Wiring",status:rootWiringDone?"ok":"warn"}],totalMs:dashboardTotalMs,findings:parityWarnings.slice(0,5),colors:ctx.color?{ok:p2.green,warn:p2.yellow,fail:p2.red}:void 0,ascii:ctx.ascii}),facts=[["Files scanned",String(scan.filesScanned)],...migrationComplete?[]:[["Content to migrate",String(coverage.wrappable)]],...coverage.wrapped>0?[["Already migrated",String(coverage.wrapped)]]:[],["Pages found",String(routeCount)],["Render baseline",parityNote??"not captured"],...excludedSections.sections.length>0?[["Skipped sections",`${excludedSections.sections.map(sec=>`/${sec}`).join(", ")} (${excludedSections.source==="config"?"fimo-config migration.exclude":"back-office heuristic \u2014 override via migration.include"})`]]:[],...dataSources.length>0?[["Live data sources",dataSources.map(record=>`${record.host}${record.kind==="cms"?" [CMS]":""}${record.decision==="ingest"?" (to ingest)":""}${record.decidedBy==="default"?" (defaulted \u2014 confirm with the user)":""}`).join(", ")]]:[],...scan.collections.length>0?[["Collections found",`${scan.collections.length} (${scan.collections.slice(0,3).map(candidate=>candidate.name).join(", ")}${scan.collections.length>3?", \u2026":""}) \u2014 agent recipe in the prompt`]]:[],...applied&&applied.applied.length>0?[["Auto-wrapped",`${applied.applied.length} item(s) (${applied.applied.filter(a=>a.kind==="text").length} text, ${applied.applied.filter(a=>a.kind==="image").length} image, ${applied.applied.filter(a=>a.kind==="file-link").length} link)`]]:[],...wiringStatus?[["Root wiring",rootWiring&&rootWiring.changes.length>0?rootWiring.changes.join("; "):wiringStatus.present?"already in place":"needs the agent (recipe in the prompt)"]]:[],...collectionRewire?[["Collection pages",collectionRewire.rewired>0?`${collectionRewire.rewired} page(s) rewired through wrapCollection${collectionRewire.warnings.length>0?` (${collectionRewire.warnings.length} left to the agent)`:""}`:"none rewired (reasons in the prompt)"]]:[],...contentSeed?[["Content seeded",contentSeed.seeded>0?`${contentSeed.seeded} label(s)`:`up to date (${contentSeed.already})`]]:[],...cmsScaffold?[[`${cmsScaffold.cms} scaffolded`,`${cmsScaffold.schemas} type(s), ${cmsScaffold.entries} example entr${cmsScaffold.entries===1?"y":"ies"}${cmsScaffold.locales.length>0?` (${cmsScaffold.locales.join(", ")})`:""}${cmsScaffold.skipped>0?`, ${cmsScaffold.skipped} existing`:""}${cmsScaffold.failures.length>0?`, ${cmsScaffold.failures.length} issue(s)`:""}`]]:[],...cmsWired?[[`${cmsScaffold?.cms??"CMS"} reads`,cmsWired.wired?"wired to Fimo (whole site reads scaffolded content)":"not auto-wired (see prompt)"]]:[],..."skipped"in envSync?[]:[["Env keys",envSync.imported.length>0?`${envSync.imported.length} imported (${envSync.imported.filter(e=>e.kind==="secret").length} secrets)`:"already synced"]],["Migration plan",path64.relative(cwd,planPath)]],factWidth=Math.max(...facts.map(([label])=>label.length)),factLines=facts.map(([label,value])=>` ${p2.dim(label.padEnd(factWidth))} ${p2.cyan(value)}`);if(migrationComplete){let check=ctx.ascii?"[ok]":"\u2713",shipStep=`${p2.cyan("npx fimo deploy")} ${p2.dim("then edit your content live in your Fimo Studio")}`;return[dashboard,"",...factLines,"",`${p2.green(`${check} Migration complete!`)} Every piece of content on your site is editable from Fimo.`,"",...renderStepsBox([shipStep],ctx.ascii,p2,{title:"Ship it",numbered:!1})].join(`
2434
2446
  `)}let rows=[];dependencyChanged&&rows.push(["install the new fimo dependency",`${pm} install`]),(coverage.wrappable>0||!rootWiringDone||structuredWorkLeft>0)&&rows.push(["ask your coding agent",`"Migrate the content to Fimo (follow ${promptRel})"`]),rows.push(["push and preview in your Fimo Studio","npx fimo deploy"]);let descWidth=Math.max(...rows.map(([desc])=>desc.length)),steps=rows.map(([desc,action])=>`${p2.dim(desc.padEnd(descWidth))} ${p2.cyan(action)}`),headline=coverage.wrappable>0?`${p2.bold("Your site is connected.")}
2435
2447
  The migration will make ${p2.cyan(String(coverage.wrappable))} piece(s) of content editable from Fimo \u2014 the migration plan lists every one (file and line).`:p2.bold("Your site is connected and fully migrated: every scanned piece of content is editable from Fimo.");return[dashboard,"",headline,"",...factLines,"",...renderStepsBox(steps,ctx.ascii,p2),"",p2.dim("Check progress anytime with `fimo migrate wrap --check` \u2014 it passes when everything is editable.")].join(`
@@ -1,5 +1,11 @@
1
1
  import { existsSync, readdirSync, readFileSync } from 'node:fs';
2
2
  import { join, relative } from 'node:path';
3
+ /** A Vite SPA declares its entry with a root `index.html`; a library that only
4
+ * bundles with Vite has none. This is what separates a deployable SITE from a
5
+ * package that merely depends on react-router / vite / vue. */
6
+ function hasHtmlEntry(cwd) {
7
+ return existsSync(join(cwd, 'index.html'));
8
+ }
3
9
  /**
4
10
  * Detect the framework of an existing site from its package.json and layout.
5
11
  * Used by `fimo init` (adopt-existing-site) and the wrap migration to decide
@@ -29,7 +35,16 @@ export function detectFramework(cwd) {
29
35
  const pagesDir = ['pages', 'src/pages'].find((dir) => existsSync(join(cwd, dir)));
30
36
  return { framework: 'next', appDir, pagesDir };
31
37
  }
32
- if (deps['react-router'] || deps['@react-router/dev']) {
38
+ // A react-router SITE is either framework mode (`@react-router/dev`) or a Vite
39
+ // SPA (an `index.html` entry). The `react-router` RUNTIME lib alone is a
40
+ // LIBRARY signal — the CLI, component libs and the `fimo/react-router` adapter
41
+ // all depend on it without being a site — so it must be paired with an app
42
+ // entry, or every workspace package reads as react-router (the monorepo picker
43
+ // bug: apps/cli mislabeled and offered as "your site").
44
+ if (deps['@react-router/dev']) {
45
+ return { framework: 'react-router' };
46
+ }
47
+ if (deps['react-router'] && hasHtmlEntry(cwd)) {
33
48
  return { framework: 'react-router' };
34
49
  }
35
50
  if (deps['@remix-run/react']) {
@@ -49,13 +64,15 @@ export function detectFramework(cwd) {
49
64
  const pagesDir = ['src/routes'].find((dir) => existsSync(join(cwd, dir)));
50
65
  return { framework: 'sveltekit', pagesDir };
51
66
  }
52
- if (deps.vue && deps.vite) {
67
+ if (deps.vue && deps.vite && hasHtmlEntry(cwd)) {
53
68
  return { framework: 'vue' };
54
69
  }
55
- if (deps.vite) {
70
+ if (deps.vite && hasHtmlEntry(cwd)) {
56
71
  // A react dependency guarantees the JSX runtime: the --apply codemod and
57
72
  // react-router route discovery are safe. Bare vite (Solid, Preact, lit)
58
- // stays hands-off.
73
+ // stays hands-off. Vite is also just a build tool libraries use, so an
74
+ // app entry (index.html) is required — a lib that bundles with Vite is not
75
+ // a site.
59
76
  return { framework: 'vite', react: Boolean(deps.react) };
60
77
  }
61
78
  // Known frameworks we can NAME but not wrap yet — lets `fimo init` route
@@ -86,6 +103,37 @@ const WORKSPACE_SKIP = new Set([
86
103
  '.vercel',
87
104
  'coverage',
88
105
  ]);
106
+ /**
107
+ * Directory names that hold NON-site packages — fixtures, examples, evals,
108
+ * scaffolding templates, internal tooling. Pruned from the picker so a
109
+ * monorepo's real sites aren't buried under dozens of candidates (the Fimo
110
+ * workspace surfaced 22, mostly `evals/*`, their `_references/*` mirrors, and
111
+ * `tools/*`). Generic monorepo conventions, not a project-specific list.
112
+ * Auto-discovery only: `fimo init <path>` still adopts any explicit directory.
113
+ */
114
+ const NON_SITE_DIRS = new Set([
115
+ 'examples',
116
+ 'example',
117
+ 'fixtures',
118
+ '__fixtures__',
119
+ '__tests__',
120
+ 'test',
121
+ 'tests',
122
+ 'e2e',
123
+ 'evals',
124
+ 'eval',
125
+ 'benchmarks',
126
+ 'bench',
127
+ 'demo',
128
+ 'demos',
129
+ 'sandbox',
130
+ 'sandboxes',
131
+ 'playground',
132
+ 'tools',
133
+ 'scripts',
134
+ 'templates',
135
+ 'template',
136
+ ]);
89
137
  /** How deep below the root the scan looks for a framework app (`apps/ui` is
90
138
  * depth 2, `packages/frontend/web` is depth 3). */
91
139
  const MAX_SCAN_DEPTH = 3;
@@ -122,7 +170,13 @@ export function findAdoptableApps(rootDir) {
122
170
  return;
123
171
  }
124
172
  for (const entry of entries) {
125
- if (entry.isDirectory() && !WORKSPACE_SKIP.has(entry.name) && !entry.name.startsWith('.')) {
173
+ if (entry.isDirectory() &&
174
+ !WORKSPACE_SKIP.has(entry.name) &&
175
+ !NON_SITE_DIRS.has(entry.name.toLowerCase()) &&
176
+ // `.`-prefixed (dotdirs) and `_`-prefixed (internal / `_references`
177
+ // reference mirrors) are never the user's deployable site.
178
+ !entry.name.startsWith('.') &&
179
+ !entry.name.startsWith('_')) {
126
180
  walk(join(dir, entry.name), depth + 1);
127
181
  }
128
182
  }
@@ -34,6 +34,11 @@ export interface PageSectionDraft {
34
34
  /** The same file drafts on several pages — chrome. Model it ONCE as a
35
35
  * Single Type, never as a per-page block. */
36
36
  shared?: boolean;
37
+ /** The page component's OWN inline content (hero, stats, FAQ rendered
38
+ * directly in the page file, not in an imported child). It aggregates
39
+ * several on-page sections, so it is exempt from illustration detection
40
+ * (its many short labels are real content, not a UI mock). */
41
+ pageOwn?: boolean;
37
42
  }
38
43
  export interface PageStructureDraft {
39
44
  pageId: string;
@@ -90,6 +95,28 @@ export interface PageSingleDraft {
90
95
  */
91
96
  export declare function isIllustrationSection(section: PageSectionDraft, labelValues: Record<string, string>): boolean;
92
97
  export declare function buildPageSingleDraft(draft: PageStructureDraft, labelValues: Record<string, string>, contentConfirmed?: ReadonlySet<string>): PageSingleDraft | null;
98
+ /**
99
+ * The machine-built Single Type for a shared chrome section (header, footer,
100
+ * nav, cookie banner): its structure AND content are identical on every page,
101
+ * so it is modeled ONCE and referenced. `markSharedSections` flags these; today
102
+ * `buildPageSingleDraft` just SKIPS them, so they die as orphan flat labels —
103
+ * this builds the Single the agent pushes instead.
104
+ */
105
+ export interface SharedSingleDraft {
106
+ uid: string;
107
+ component: string;
108
+ file: string;
109
+ schema: Record<string, unknown>;
110
+ document: Record<string, unknown>;
111
+ }
112
+ /**
113
+ * One Single Type per unique shared chrome section (deduped by
114
+ * `(file, component)` — the same header on N pages is ONE Single). Reuses
115
+ * `sectionBlock` so a header's nav/logo/labels become real fields; a section
116
+ * that yields no fields (a pure decorative wrapper) is skipped rather than
117
+ * emitting an empty Single.
118
+ */
119
+ export declare function buildSharedSingleDrafts(drafts: PageStructureDraft[], labelValues: Record<string, string>): SharedSingleDraft[];
93
120
  /**
94
121
  * A section the detector reads as an illustration/product-demo, with enough
95
122
  * context for the human to confirm in a glance: WHERE it lives (`file`,
@@ -1,5 +1,5 @@
1
1
  import { readFileSync, statSync } from 'node:fs';
2
- import { join, relative } from 'node:path';
2
+ import { basename, join, relative } from 'node:path';
3
3
  import { frameworkSectionStyle } from '../frameworks/discover.js';
4
4
  import { componentImports, resolveModuleFile, resolveRouteFiles } from './label-prefixes.js';
5
5
  // How deep the section recursion nests components into blocks. The platform
@@ -96,6 +96,30 @@ function draftChildSections(context, file, depth) {
96
96
  }
97
97
  return sections;
98
98
  }
99
+ /**
100
+ * The page component's OWN inline content — hero copy, stats, an inline FAQ —
101
+ * lives under the page FILE's label prefix and is never an imported child, so
102
+ * `draftChildSections` skips it and it strands as orphan flat labels. Draft it
103
+ * as ONE section (its detected collections + labels, NO child recursion — the
104
+ * imported children are already separate top-level sections). Marked `pageOwn`
105
+ * so illustration detection doesn't mistake its many short labels for a mock.
106
+ */
107
+ function draftPageOwnSection(context, file) {
108
+ const rel = relative(context.cwd, file);
109
+ const prefix = context.style.fileScope(rel);
110
+ const labelKeys = context.keysByPrefix.get(prefix) ?? [];
111
+ const collections = (context.collectionsByFile.get(rel) ?? []).map((candidate) => ({
112
+ name: candidate.name,
113
+ fields: candidate.fields,
114
+ count: candidate.count,
115
+ ...(candidate.typedRows ? { rows: candidate.typedRows.slice(0, MAX_DRAFT_ROWS) } : {}),
116
+ }));
117
+ if (labelKeys.length === 0 && collections.length === 0) {
118
+ return null;
119
+ }
120
+ const component = pascal(basename(rel).replace(/\.\w+$/, ''));
121
+ return { key: camel(component), component, file: rel, prefix, labelKeys, collections, pageOwn: true };
122
+ }
99
123
  export function draftPageStructures(args) {
100
124
  const { cwd, framework, routes, collections } = args;
101
125
  const keysByPrefix = new Map();
@@ -114,8 +138,13 @@ export function draftPageStructures(args) {
114
138
  const drafts = [];
115
139
  for (const { routeId, file } of resolveRouteFiles(cwd, framework, routes)) {
116
140
  const context = { cwd, style, keysByPrefix, collectionsByFile, visited: new Set([file]) };
117
- const sections = draftChildSections(context, file, 1);
118
- if (sections.length > 1) {
141
+ const childSections = draftChildSections(context, file, 1);
142
+ const ownSection = draftPageOwnSection(context, file);
143
+ const sections = ownSection ? [ownSection, ...childSections] : childSections;
144
+ // buildPageSingleDraft's `totalFields >= 3` is the real triviality filter,
145
+ // so drafting any page with content (>= 1 section) is safe — and it is what
146
+ // lets an inline-only page (all content in the page file) get a Single.
147
+ if (sections.length >= 1) {
119
148
  drafts.push({ pageId: routeId, single: pascal(routeId), sections });
120
149
  }
121
150
  }
@@ -186,6 +215,11 @@ const looksLikeProse = (value) => {
186
215
  * agent to confirm rather than deleting it silently.
187
216
  */
188
217
  export function isIllustrationSection(section, labelValues) {
218
+ // The page's own aggregate content is many sections at once, not a single
219
+ // component's UI mock — never read it as an illustration.
220
+ if (section.pageOwn) {
221
+ return false;
222
+ }
189
223
  const values = section.labelKeys.map((key) => labelValues[key] ?? '').filter((value) => value.trim().length > 0);
190
224
  if (values.length < ILLUSTRATION_MIN_LABELS) {
191
225
  return false;
@@ -218,7 +252,25 @@ function sectionBlock(section, labelValues, illustrations, contentConfirmed) {
218
252
  const fields = {};
219
253
  const value = {};
220
254
  let fieldCount = 0;
255
+ // Partition the section's labels: a key with a nested path
256
+ // (`<prefix>.<group>.<item>.<field>`) is a COLLECTION encoded in the label
257
+ // keys (`ecosystem-items.github.name`, `…react.name`, …). Flattening it by
258
+ // last segment would collapse every item to one `name` field and silently
259
+ // drop the rest — group it into a repeatable block. Single-segment keys stay
260
+ // scalar fields.
261
+ const groups = new Map();
262
+ const relOf = (key) => key.startsWith(`${section.prefix}.`) ? key.slice(section.prefix.length + 1) : key;
221
263
  for (const key of section.labelKeys) {
264
+ const parts = relOf(key).split('.');
265
+ if (parts.length >= 3) {
266
+ const [group, item, ...fieldParts] = parts;
267
+ const itemMap = groups.get(group) ?? new Map();
268
+ const itemFields = itemMap.get(item) ?? {};
269
+ itemFields[camel(fieldParts.join('-'))] = labelValues[key] ?? '';
270
+ itemMap.set(item, itemFields);
271
+ groups.set(group, itemMap);
272
+ continue;
273
+ }
222
274
  const name = labelFieldName(key);
223
275
  if (fields[name]) {
224
276
  continue;
@@ -228,6 +280,21 @@ function sectionBlock(section, labelValues, illustrations, contentConfirmed) {
228
280
  value[name] = labelValue;
229
281
  fieldCount += 1;
230
282
  }
283
+ for (const [group, itemMap] of groups) {
284
+ const name = camel(group);
285
+ if (fields[name]) {
286
+ continue;
287
+ }
288
+ const itemFields = {};
289
+ for (const itemValue of itemMap.values()) {
290
+ for (const fieldName of Object.keys(itemValue)) {
291
+ itemFields[fieldName] = { type: 'string' };
292
+ }
293
+ }
294
+ fields[name] = { type: 'blocks', schema: { fields: itemFields } };
295
+ value[name] = [...itemMap.values()];
296
+ fieldCount += 1;
297
+ }
231
298
  for (const collection of section.collections) {
232
299
  const name = camel(collection.name);
233
300
  if (fields[name]) {
@@ -311,6 +378,43 @@ export function buildPageSingleDraft(draft, labelValues, contentConfirmed = new
311
378
  ...(illustrations.length > 0 ? { illustrations: [...new Set(illustrations)] } : {}),
312
379
  };
313
380
  }
381
+ /**
382
+ * One Single Type per unique shared chrome section (deduped by
383
+ * `(file, component)` — the same header on N pages is ONE Single). Reuses
384
+ * `sectionBlock` so a header's nav/logo/labels become real fields; a section
385
+ * that yields no fields (a pure decorative wrapper) is skipped rather than
386
+ * emitting an empty Single.
387
+ */
388
+ export function buildSharedSingleDrafts(drafts, labelValues) {
389
+ const byIdentity = new Map();
390
+ const walk = (sections) => {
391
+ for (const section of sections) {
392
+ if (section.shared) {
393
+ const identity = `${section.file}::${section.component}`;
394
+ if (!byIdentity.has(identity)) {
395
+ const block = sectionBlock(section, labelValues, [], new Set());
396
+ if (block && Object.keys(block.fields).length > 0) {
397
+ const uid = pascal(section.component);
398
+ byIdentity.set(identity, {
399
+ uid,
400
+ component: section.component,
401
+ file: section.file,
402
+ schema: { uid, name: uid, isSingleton: true, fields: block.fields },
403
+ document: block.value,
404
+ });
405
+ }
406
+ }
407
+ // A shared section owns its whole subtree — don't descend for more.
408
+ continue;
409
+ }
410
+ walk(section.children ?? []);
411
+ }
412
+ };
413
+ for (const draft of drafts) {
414
+ walk(draft.sections);
415
+ }
416
+ return [...byIdentity.values()];
417
+ }
314
418
  /** How many sample strings a candidate carries so a human can judge in 3s. */
315
419
  const SECTION_SAMPLE_COUNT = 6;
316
420
  const sectionSamples = (section, labelValues) => section.labelKeys
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fimo",
3
- "version": "0.9.0-experimental.11",
3
+ "version": "0.9.0-experimental.12",
4
4
  "description": "Fimo CLI - create, deploy, and manage Fimo projects",
5
5
  "bin": {
6
6
  "fimo": "dist/cli/index.js"
@@ -21,7 +21,7 @@
21
21
  "cmdk": "^1.1.1",
22
22
  "date-fns": "^4.1.0",
23
23
  "embla-carousel-react": "^8.6.0",
24
- "fimo": "0.9.0-experimental.11",
24
+ "fimo": "0.9.0-experimental.12",
25
25
  "input-otp": "^1.4.2",
26
26
  "isbot": "^5",
27
27
  "lucide-react": "^0.577.0",