velloo 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +121 -225
  2. package/THIRD-PARTY-NOTICES.md +3 -3
  3. package/canvas/assets/index-CcPwhD7W.js +31 -0
  4. package/canvas/assets/index-CkVteRZ9.css +2 -0
  5. package/canvas/assets/lucide-all-Cezxn40A.js +1 -0
  6. package/canvas/index.html +2 -2
  7. package/{chunk-rjjc9vam.js → chunk-07fxzrx2.js} +2 -2
  8. package/{chunk-ff0jfn0v.js → chunk-32cq4wpr.js} +1 -1
  9. package/{chunk-nx09zqgs.js → chunk-3612470d.js} +1 -1
  10. package/{chunk-hf4adxe0.js → chunk-45wv1fs5.js} +8 -8
  11. package/chunk-4g4c9h7k.js +2 -0
  12. package/{chunk-8vgpffn7.js → chunk-6w42sr61.js} +1 -1
  13. package/{chunk-esb7n55g.js → chunk-8n07n0cr.js} +3 -3
  14. package/{chunk-96qhpth5.js → chunk-8qf0ne1p.js} +1 -1
  15. package/{chunk-56z5xd5b.js → chunk-8ztgcajz.js} +1 -1
  16. package/chunk-9g45c5md.js +815 -0
  17. package/{chunk-w2naqxqt.js → chunk-aefn23tr.js} +1 -1
  18. package/{chunk-jsvkqae2.js → chunk-asqpx5v7.js} +1 -1
  19. package/chunk-b4hny6hw.js +3 -0
  20. package/chunk-bntsn3wj.js +2 -0
  21. package/{chunk-bc7pkjcn.js → chunk-c4164x55.js} +1 -1
  22. package/{chunk-mfch0b0t.js → chunk-cg0sjdqt.js} +1 -1
  23. package/{chunk-3trkmgfr.js → chunk-cq2q36d1.js} +1 -1
  24. package/chunk-d19ttv1a.js +4 -0
  25. package/{chunk-8grzf8q1.js → chunk-djwvt6jx.js} +1 -1
  26. package/chunk-dqqpbmxt.js +22 -0
  27. package/{chunk-1td6z6ey.js → chunk-dy7qwj3t.js} +1 -1
  28. package/{chunk-dar6wbf2.js → chunk-ejpccmcj.js} +1 -1
  29. package/{chunk-pxaxgkaq.js → chunk-emty5315.js} +1 -1
  30. package/chunk-esg0x95a.js +5 -0
  31. package/{chunk-k423dkjz.js → chunk-ez720ked.js} +1 -1
  32. package/{chunk-h85hv05d.js → chunk-ffm2jpxp.js} +1 -1
  33. package/{chunk-6813v926.js → chunk-g3k8k6fq.js} +3 -3
  34. package/{chunk-63y5gdzw.js → chunk-h3ser37q.js} +1 -1
  35. package/{chunk-74yxy75r.js → chunk-hsk91jms.js} +1 -1
  36. package/chunk-jxgwdz2r.js +5 -0
  37. package/chunk-kvq7pcph.js +2 -0
  38. package/chunk-m0v3d581.js +2 -0
  39. package/chunk-majd3gx9.js +3 -0
  40. package/{chunk-t2x3mztc.js → chunk-mqtnj8ws.js} +1 -1
  41. package/{chunk-xtwx2p9g.js → chunk-mqx96m2g.js} +1 -1
  42. package/{chunk-c4spp880.js → chunk-nrxqr4v5.js} +1 -1
  43. package/{chunk-g185gx8a.js → chunk-nx0ex7qw.js} +1 -1
  44. package/{chunk-qwccndcd.js → chunk-q7wwqn03.js} +1 -1
  45. package/chunk-qgbat4fv.js +6 -0
  46. package/{chunk-08mjtg1e.js → chunk-qqagacne.js} +1 -1
  47. package/{chunk-69qb8p8s.js → chunk-qx83fdv2.js} +1 -1
  48. package/{chunk-ff2vt7cz.js → chunk-r5y1sh4f.js} +1 -1
  49. package/{chunk-2ba6edh8.js → chunk-rg86bhtb.js} +2 -2
  50. package/{chunk-x02z2ccm.js → chunk-rhfzy9c0.js} +1 -1
  51. package/{chunk-t6qr2ay9.js → chunk-rrrn1mkq.js} +1 -1
  52. package/{chunk-56vfy0db.js → chunk-s1cwck4c.js} +1 -1
  53. package/{chunk-tac2wvc7.js → chunk-sjxp2bx3.js} +1 -1
  54. package/chunk-skk6yvnw.js +3 -0
  55. package/{chunk-52m26hh4.js → chunk-t08391mh.js} +1 -1
  56. package/{chunk-2q561dec.js → chunk-t61vyqpd.js} +1 -1
  57. package/{chunk-ta84ehgg.js → chunk-v6ks5v53.js} +1 -1
  58. package/{chunk-hjc5eg5c.js → chunk-w30zfv3m.js} +1 -1
  59. package/{chunk-tbd6wn3q.js → chunk-x84qrz4q.js} +1 -1
  60. package/{chunk-chtv0yj6.js → chunk-xg49s85z.js} +147 -30
  61. package/{chunk-8cj4swpr.js → chunk-xxw67jpk.js} +3 -3
  62. package/{chunk-eqjtq673.js → chunk-yjwtdm71.js} +1 -1
  63. package/{chunk-8vam2893.js → chunk-z6r6wxm6.js} +1 -1
  64. package/{chunk-hsfpbjpc.js → chunk-zgwvkgsz.js} +1 -1
  65. package/cli.js +1 -1
  66. package/launcher.cjs +3 -1
  67. package/package.json +1 -1
  68. package/pkgs/helpers/src/box.tsx +12 -6
  69. package/pkgs/helpers/src/descriptors.ts +6 -0
  70. package/pkgs/helpers/src/icon.tsx +5 -3
  71. package/pkgs/helpers/src/index.ts +2 -2
  72. package/pkgs/helpers/src/text.tsx +29 -5
  73. package/pkgs/provider-antd/src/index.ts +1 -0
  74. package/pkgs/provider-antd/src/manifest.ts +1 -0
  75. package/pkgs/provider-chakra/src/manifest.ts +1 -0
  76. package/pkgs/provider-html/src/index.ts +1 -0
  77. package/pkgs/provider-mui/src/index.ts +10 -0
  78. package/pkgs/provider-mui/src/manifest.ts +1 -0
  79. package/pkgs/provider-none/src/components-inline.tsx +20 -14
  80. package/pkgs/provider-none/src/components.tsx +2 -4
  81. package/pkgs/provider-none/src/index.ts +1 -0
  82. package/pkgs/schema/src/board.ts +13 -1
  83. package/pkgs/schema/src/config.ts +38 -1
  84. package/pkgs/schema/src/flow.ts +230 -0
  85. package/pkgs/schema/src/frame.ts +7 -0
  86. package/pkgs/schema/src/index.ts +24 -0
  87. package/pkgs/schema/src/node-identity.ts +54 -1
  88. package/pkgs/schema/src/node.ts +114 -26
  89. package/pkgs/schema/src/snippet-resolve.ts +18 -12
  90. package/pkgs/schema/src/svg-sanitize.ts +3 -0
  91. package/pkgs/schema/src/theme.ts +56 -0
  92. package/pkgs/schema/src/typeset.ts +21 -4
  93. package/pkgs/shadcn-snapshot/dist/manifest.json +6 -0
  94. package/plugins/claude/velloo/agents/velloo-designer.md +7 -4
  95. package/plugins/claude/velloo/commands/setup.md +13 -0
  96. package/plugins/gemini/GEMINI.md +9 -5
  97. package/plugins/gemini/commands/velloo/setup.toml +11 -0
  98. package/skills/velloo-design/SKILL.md +11 -6
  99. package/skills/velloo-setup/SKILL.md +179 -36
  100. package/canvas/assets/index-CnyI3aig.js +0 -29
  101. package/canvas/assets/index-GNLd0pCG.css +0 -2
  102. package/canvas/assets/lucide-all-CH8LmVh0.js +0 -1
  103. package/chunk-1gkeepkm.js +0 -2
  104. package/chunk-2web93qz.js +0 -2
  105. package/chunk-ab8fga32.js +0 -22
  106. package/chunk-azeqkms7.js +0 -6
  107. package/chunk-e2btp1wd.js +0 -3
  108. package/chunk-ey65err5.js +0 -5
  109. package/chunk-rk238m15.js +0 -4
  110. package/chunk-wfhv9jg4.js +0 -2
  111. package/chunk-wnj432fw.js +0 -3
  112. package/chunk-yfvc8d2g.js +0 -716
  113. package/chunk-z73q4dq9.js +0 -2
  114. package/chunk-ztsckexy.js +0 -5
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{helperSourcePath}from"./chunk-yfvc8d2g.js";import"./chunk-8cj4swpr.js";import{snapshotVersion2,entryCssPath3,componentsDir3}from"./chunk-p93x4pn2.js";import{registry2}from"./chunk-69qb8p8s.js";import{TAILWIND_CLASSNAME}from"./chunk-chtv0yj6.js";import"./chunk-56z5xd5b.js";import{readFile}from"fs/promises";import{join}from"path";async function readManifest(cacheDir){let raw=await readFile(join(cacheDir,"manifest.json"),"utf8");return JSON.parse(raw)}import{existsSync as existsSync4,readFileSync as readFileSync4}from"fs";import{basename,join as join5}from"path";import{existsSync as existsSync3,readFileSync as readFileSync3}from"fs";import{join as join4}from"path";import{existsSync,readFileSync}from"fs";import{join as join2}from"path";function exportsName(source,id){let name=id.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");if(new RegExp(`\\bexport\\s+(?:async\\s+)?(?:function|const|let|var|class)\\s+${name}\\b`).test(source))return!0;for(let match of source.matchAll(/\bexport\s*\{([^}]*)\}/g)){let clause=match[1]??"";for(let part of clause.split(",")){let local=part.trim().split(/\s+as\s+/);if((local.length>1?local[1]:local[0])?.trim()===id)return!0}}return/\bexport\s+\*\s+from\b/.test(source)}function hostComponentFile(uiDir,addName,id){for(let extension of["tsx","ts","jsx","js"]){let path=join2(uiDir,`${addName}.${extension}`);if(!existsSync(path))continue;try{return exportsName(readFileSync(path,"utf8"),id)?path:null}catch{return null}}return null}import{existsSync as existsSync2,readdirSync,readFileSync as readFileSync2}from"fs";import{join as join3,resolve}from"path";function kebab(id){return id.replace(/(?<!^)(?=[A-Z])/g,"-").toLowerCase()}function addNameIndex(manifest){let byId=new Map(manifest.flatMap((c)=>c.registryName?[[c.id,c.registryName]]:[]));return(id)=>byId.get(id)??kebab(id)}function findUiDir(hostAppRoot){let candidates=[];try{let cj=JSON.parse(readFileSync2(join3(hostAppRoot,"components.json"),"utf8")),fromAlias=(alias,suffix="")=>{if(!alias)return;let srcBase=existsSync2(join3(hostAppRoot,"src"))?"src":"",rel=alias.replace(/^@\//,srcBase?`${srcBase}/`:"")+suffix;candidates.push(resolve(hostAppRoot,rel))};fromAlias(cj.aliases?.ui),fromAlias(cj.aliases?.components,"/ui")}catch{}candidates.push(resolve(hostAppRoot,"src/components/ui"),resolve(hostAppRoot,"components/ui"),resolve(hostAppRoot,"app/components/ui"));for(let dir of candidates)if(existsSync2(dir))return dir;return null}function installedAddNames(dir){if(!dir)return new Set;try{return new Set(readdirSync(dir).filter((f)=>f.endsWith(".tsx")||f.endsWith(".ts")).map((f)=>f.replace(/\.(tsx|ts)$/,"")))}catch{return new Set}}function enrichManifestFromHost(manifest,uiDir){if(!uiDir)return manifest;let addNameOf=addNameIndex(manifest),byFile=new Map,read=(addName)=>{if(byFile.has(addName))return byFile.get(addName)??null;for(let ext of["tsx","ts","jsx","js"]){let path=join4(uiDir,`${addName}.${ext}`);if(!existsSync3(path))continue;let source=readFileSync3(path,"utf8");return byFile.set(addName,source),source}return byFile.set(addName,""),null};return manifest.map((descriptor)=>{if(descriptor.source==="velloo")return descriptor;let source=read(addNameOf(descriptor.id));if(!source||!exportsName(source,descriptor.id))return descriptor;let additions=[...variantPropsFor(source,descriptor.id===descriptor.family),...declaredPropsFor(source,descriptor.id)];if(additions.length===0)return descriptor;let props=[...descriptor.props];for(let addition of additions){let index=props.findIndex((prop)=>prop.name===addition.name);if(index>=0)props[index]={...props[index],...addition};else props.push(addition)}return{...descriptor,props,designModeNotes:appendNote(descriptor.designModeNotes,"Props include variants detected from the app's component source.")}})}function appendNote(current,next){return current?`${current} ${next}`:next}function variantPropsFor(source,primary){let out=[];if(!primary)return out;let variantsAt=source.indexOf("variants:");if(variantsAt<0)return out;let open=source.indexOf("{",variantsAt),block=balancedBlock(source,open);if(!block)return out;for(let[name,value]of objectEntries(block.slice(1,-1))){let values=objectEntries(value.slice(1,-1)).map(([key])=>key);if(values.length===0)continue;out.push({name,type:`${values.map((value)=>JSON.stringify(value)).join(" | ")} | undefined`,optional:!0,control:"enum",enumValues:values,...defaultVariant(source,name)?{defaultValue:defaultVariant(source,name)}:{}})}return out}function defaultVariant(source,name){let at=source.indexOf("defaultVariants:");if(at<0)return;let open=source.indexOf("{",at),block=balancedBlock(source,open);if(!block)return;return objectEntries(block.slice(1,-1)).find(([key])=>key===name)?.[1].replace(/["'`\s]/g,"")}function declaredPropsFor(source,componentId){let match=[new RegExp(`interface\\s+${componentId}Props(?:\\s+extends[^\\{]+)?\\s*\\{`,"m"),new RegExp(`type\\s+${componentId}Props\\s*=.*?&\\s*\\{`,"m")].map((pattern)=>pattern.exec(source)).find(Boolean);if(!match||match.index===void 0)return[];let open=source.indexOf("{",match.index),block=balancedBlock(source,open);if(!block)return[];let out=[],property=/(?:^|[;{\n])\s*([A-Za-z_$][\w$]*)(\?)?\s*:\s*([^;\n}]+)/gm;for(let found of block.slice(1,-1).matchAll(property)){let name=found[1],raw=found[3]?.trim();if(!name||!raw||name==="children")continue;let enumValues=[...raw.matchAll(/["']([^"']+)["']/g)].map((value)=>value[1]),optional=found[2]==="?"||raw.includes("undefined");out.push({name,type:optional&&!raw.includes("undefined")?`${raw} | undefined`:raw,optional,control:enumValues.length>0?"enum":/boolean/.test(raw)?"boolean":/number/.test(raw)?"number":"string",...enumValues.length>0?{enumValues}:{}})}return out}function balancedBlock(source,open){if(open<0||source[open]!=="{")return null;let depth=0,quote="";for(let index=open;index<source.length;index++){let char=source[index],prev=source[index-1];if(quote){if(char===quote&&prev!=="\\")quote="";continue}if(char==='"'||char==="'"||char==="`"){quote=char;continue}if(char==="{")depth++;if(char==="}"&&--depth===0)return source.slice(open,index+1)}return null}function objectEntries(body){let out=[],index=0;while(index<body.length){while(index<body.length&&/[\s,]/.test(body[index]))index++;let keyMatch=/^(?:["']([^"']+)["']|([A-Za-z_$][\w$-]*))\s*:/.exec(body.slice(index));if(!keyMatch)break;let key=keyMatch[1]??keyMatch[2];if(!key)break;index+=keyMatch[0].length;while(/\s/.test(body[index]??""))index++;if(body[index]==="{"){let block=balancedBlock(body,index);if(!block)break;out.push([key,block]),index+=block.length;continue}let end=valueEnd(body,index);out.push([key,body.slice(index,end).trim()]),index=end+1}return out}function valueEnd(body,start){let quote="",depth=0;for(let index=start;index<body.length;index++){let char=body[index];if(quote){if(char===quote&&body[index-1]!=="\\")quote=""}else if(char==='"'||char==="'"||char==="`")quote=char;else if("([{".includes(char))depth++;else if(")]}".includes(char))depth--;else if(char===","&&depth===0)return index}return body.length}function createProvider(opts={}){let cacheDir=opts.cacheDir,plannedUiDir=cacheDir?join5(cacheDir,"ui"):void 0,hostUiDir=()=>plannedUiDir&&existsSync4(plannedUiDir)?plannedUiDir:opts.hostAppRoot?findUiDir(opts.hostAppRoot):null,componentsDir=componentsDir3,version=opts.version??snapshotVersion2,loadManifest=async()=>{if(cacheDir&&existsSync4(join5(cacheDir,"manifest.json")))return enrichManifestFromHost(await readManifest(cacheDir),hostUiDir());let{loadManifest:snapshotManifest}=await import("./chunk-2q561dec.js");return enrichManifestFromHost(await snapshotManifest(),hostUiDir())};return{id:"shadcn-upstream",version,componentsDir,styleEntryPath:entryCssPath3,registry:registry2,loadManifest,label:`shadcn (upstream @ ${version})`,styleChannel:TAILWIND_CLASSNAME,styleChannels:["tailwind-classname"],mcpIntro:()=>['**This folder targets shadcn/ui with Tailwind.** The canvas imports client-safe components directly from the app\'s `components/ui`, adapts overlay families to stay inline, and falls back per component when a file is missing \u2014 `component_status` says which, before you claim fidelity. Style with a className string: `update_props { style: "flex gap-4 p-6" }`.',""],catalog:async()=>{let manifest=await loadManifest(),addNameOf=addNameIndex(manifest),shadcn=manifest.filter((c)=>c.source!=="velloo"),present=installedAddNames(hostUiDir());return shadcn.map((c)=>{let addName=addNameOf(c.id);return{id:c.id,installed:present.has(addName),importPath:`@/components/ui/${addName}`}})},ownedModules:{dirs:()=>{let uiDir=hostUiDir();return uiDir?[uiDir]:[]},supplies:(file,exportName)=>{let family=basename(file).replace(/\.[jt]sx?$/,""),counterpart=join5(componentsDir3,"ui",`${family}.tsx`);return familyExports(counterpart).has(exportName)}},canvasBundleSpec:{styleRuntime:{kind:"none"},components:async(ids)=>{let manifest=await loadManifest(),addNameOf=addNameIndex(manifest),sourceById=new Map(manifest.map((entry)=>[entry.id,entry.source])),uiDir=hostUiDir();return ids.flatMap((id)=>{if(sourceById.get(id)==="velloo"){let path=helperSourcePath(id);return path?[{id,sources:[{importPath:path,exportName:id,fidelity:"exact",note:"Velloo helper, mounted beside the app's components."}]}]:[]}if(!sourceById.has(id))return[];let addName=addNameOf(id),snapshotPath=join5(componentsDir3,"ui",`${addName}.tsx`);if(CANVAS_ADAPTED_FAMILIES.has(addName))return[{id,sources:[{importPath:snapshotPath,exportName:id,fidelity:"adapted",note:"The app component uses portals or runtime state; Velloo renders its canvas-safe counterpart inline."}]}];let hostPath=uiDir?hostComponentFile(uiDir,addName,id):null;return[{id,sources:[...hostPath?[{importPath:hostPath,exportName:id,fidelity:"exact",preflight:!0,note:"Rendered directly from the app's shadcn source file."}]:[],{importPath:snapshotPath,exportName:id,fidelity:"fallback",note:hostPath?"The app source did not compile for the browser canvas; using the bundled canvas fallback.":"The app does not install this component under this name (it may be renamed in its own file); using the bundled canvas fallback."}]}]})},sourceDirs:()=>{let uiDir=hostUiDir()??plannedUiDir;return uiDir?[uiDir]:[]}}}}var CANVAS_ADAPTED_FAMILIES=new Set(["alert-dialog","calendar","carousel","chart","dialog","dropdown-menu","popover","select","sheet","sonner","tooltip"]),familyExportCache=new Map;function familyExports(path){let names=familyExportCache.get(path);if(!names){names=new Set;try{let source=readFileSync4(path,"utf8");for(let id of Object.keys(registry2))if(exportsName(source,id))names.add(id)}catch{}familyExportCache.set(path,names)}return names}export{createProvider};
2
+ import{helperSourcePath}from"./chunk-9g45c5md.js";import"./chunk-xxw67jpk.js";import{snapshotVersion2,entryCssPath3,componentsDir3}from"./chunk-p93x4pn2.js";import{registry2}from"./chunk-qx83fdv2.js";import{TAILWIND_CLASSNAME}from"./chunk-xg49s85z.js";import"./chunk-8ztgcajz.js";import{readFile}from"fs/promises";import{join}from"path";async function readManifest(cacheDir){let raw=await readFile(join(cacheDir,"manifest.json"),"utf8");return JSON.parse(raw)}import{existsSync as existsSync4,readFileSync as readFileSync4}from"fs";import{basename,join as join5}from"path";import{existsSync as existsSync3,readFileSync as readFileSync3}from"fs";import{join as join4}from"path";import{existsSync,readFileSync}from"fs";import{join as join2}from"path";function exportsName(source,id){let name=id.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");if(new RegExp(`\\bexport\\s+(?:async\\s+)?(?:function|const|let|var|class)\\s+${name}\\b`).test(source))return!0;for(let match of source.matchAll(/\bexport\s*\{([^}]*)\}/g)){let clause=match[1]??"";for(let part of clause.split(",")){let local=part.trim().split(/\s+as\s+/);if((local.length>1?local[1]:local[0])?.trim()===id)return!0}}return/\bexport\s+\*\s+from\b/.test(source)}function hostComponentFile(uiDir,addName,id){for(let extension of["tsx","ts","jsx","js"]){let path=join2(uiDir,`${addName}.${extension}`);if(!existsSync(path))continue;try{return exportsName(readFileSync(path,"utf8"),id)?path:null}catch{return null}}return null}import{existsSync as existsSync2,readdirSync,readFileSync as readFileSync2}from"fs";import{join as join3,resolve}from"path";function kebab(id){return id.replace(/(?<!^)(?=[A-Z])/g,"-").toLowerCase()}function addNameIndex(manifest){let byId=new Map(manifest.flatMap((c)=>c.registryName?[[c.id,c.registryName]]:[]));return(id)=>byId.get(id)??kebab(id)}function findUiDir(hostAppRoot){let candidates=[];try{let cj=JSON.parse(readFileSync2(join3(hostAppRoot,"components.json"),"utf8")),fromAlias=(alias,suffix="")=>{if(!alias)return;let srcBase=existsSync2(join3(hostAppRoot,"src"))?"src":"",rel=alias.replace(/^@\//,srcBase?`${srcBase}/`:"")+suffix;candidates.push(resolve(hostAppRoot,rel))};fromAlias(cj.aliases?.ui),fromAlias(cj.aliases?.components,"/ui")}catch{}candidates.push(resolve(hostAppRoot,"src/components/ui"),resolve(hostAppRoot,"components/ui"),resolve(hostAppRoot,"app/components/ui"));for(let dir of candidates)if(existsSync2(dir))return dir;return null}function installedAddNames(dir){if(!dir)return new Set;try{return new Set(readdirSync(dir).filter((f)=>f.endsWith(".tsx")||f.endsWith(".ts")).map((f)=>f.replace(/\.(tsx|ts)$/,"")))}catch{return new Set}}function enrichManifestFromHost(manifest,uiDir){if(!uiDir)return manifest;let addNameOf=addNameIndex(manifest),byFile=new Map,read=(addName)=>{if(byFile.has(addName))return byFile.get(addName)??null;for(let ext of["tsx","ts","jsx","js"]){let path=join4(uiDir,`${addName}.${ext}`);if(!existsSync3(path))continue;let source=readFileSync3(path,"utf8");return byFile.set(addName,source),source}return byFile.set(addName,""),null};return manifest.map((descriptor)=>{if(descriptor.source==="velloo")return descriptor;let source=read(addNameOf(descriptor.id));if(!source||!exportsName(source,descriptor.id))return descriptor;let additions=[...variantPropsFor(source,descriptor.id===descriptor.family),...declaredPropsFor(source,descriptor.id)];if(additions.length===0)return descriptor;let props=[...descriptor.props];for(let addition of additions){let index=props.findIndex((prop)=>prop.name===addition.name);if(index>=0)props[index]={...props[index],...addition};else props.push(addition)}return{...descriptor,props,designModeNotes:appendNote(descriptor.designModeNotes,"Props include variants detected from the app's component source.")}})}function appendNote(current,next){return current?`${current} ${next}`:next}function variantPropsFor(source,primary){let out=[];if(!primary)return out;let variantsAt=source.indexOf("variants:");if(variantsAt<0)return out;let open=source.indexOf("{",variantsAt),block=balancedBlock(source,open);if(!block)return out;for(let[name,value]of objectEntries(block.slice(1,-1))){let values=objectEntries(value.slice(1,-1)).map(([key])=>key);if(values.length===0)continue;out.push({name,type:`${values.map((value)=>JSON.stringify(value)).join(" | ")} | undefined`,optional:!0,control:"enum",enumValues:values,...defaultVariant(source,name)?{defaultValue:defaultVariant(source,name)}:{}})}return out}function defaultVariant(source,name){let at=source.indexOf("defaultVariants:");if(at<0)return;let open=source.indexOf("{",at),block=balancedBlock(source,open);if(!block)return;return objectEntries(block.slice(1,-1)).find(([key])=>key===name)?.[1].replace(/["'`\s]/g,"")}function declaredPropsFor(source,componentId){let match=[new RegExp(`interface\\s+${componentId}Props(?:\\s+extends[^\\{]+)?\\s*\\{`,"m"),new RegExp(`type\\s+${componentId}Props\\s*=.*?&\\s*\\{`,"m")].map((pattern)=>pattern.exec(source)).find(Boolean);if(!match||match.index===void 0)return[];let open=source.indexOf("{",match.index),block=balancedBlock(source,open);if(!block)return[];let out=[],property=/(?:^|[;{\n])\s*([A-Za-z_$][\w$]*)(\?)?\s*:\s*([^;\n}]+)/gm;for(let found of block.slice(1,-1).matchAll(property)){let name=found[1],raw=found[3]?.trim();if(!name||!raw||name==="children")continue;let enumValues=[...raw.matchAll(/["']([^"']+)["']/g)].map((value)=>value[1]),optional=found[2]==="?"||raw.includes("undefined");out.push({name,type:optional&&!raw.includes("undefined")?`${raw} | undefined`:raw,optional,control:enumValues.length>0?"enum":/boolean/.test(raw)?"boolean":/number/.test(raw)?"number":"string",...enumValues.length>0?{enumValues}:{}})}return out}function balancedBlock(source,open){if(open<0||source[open]!=="{")return null;let depth=0,quote="";for(let index=open;index<source.length;index++){let char=source[index],prev=source[index-1];if(quote){if(char===quote&&prev!=="\\")quote="";continue}if(char==='"'||char==="'"||char==="`"){quote=char;continue}if(char==="{")depth++;if(char==="}"&&--depth===0)return source.slice(open,index+1)}return null}function objectEntries(body){let out=[],index=0;while(index<body.length){while(index<body.length&&/[\s,]/.test(body[index]))index++;let keyMatch=/^(?:["']([^"']+)["']|([A-Za-z_$][\w$-]*))\s*:/.exec(body.slice(index));if(!keyMatch)break;let key=keyMatch[1]??keyMatch[2];if(!key)break;index+=keyMatch[0].length;while(/\s/.test(body[index]??""))index++;if(body[index]==="{"){let block=balancedBlock(body,index);if(!block)break;out.push([key,block]),index+=block.length;continue}let end=valueEnd(body,index);out.push([key,body.slice(index,end).trim()]),index=end+1}return out}function valueEnd(body,start){let quote="",depth=0;for(let index=start;index<body.length;index++){let char=body[index];if(quote){if(char===quote&&body[index-1]!=="\\")quote=""}else if(char==='"'||char==="'"||char==="`")quote=char;else if("([{".includes(char))depth++;else if(")]}".includes(char))depth--;else if(char===","&&depth===0)return index}return body.length}function createProvider(opts={}){let cacheDir=opts.cacheDir,plannedUiDir=cacheDir?join5(cacheDir,"ui"):void 0,hostUiDir=()=>plannedUiDir&&existsSync4(plannedUiDir)?plannedUiDir:opts.hostAppRoot?findUiDir(opts.hostAppRoot):null,componentsDir=componentsDir3,version=opts.version??snapshotVersion2,loadManifest=async()=>{if(cacheDir&&existsSync4(join5(cacheDir,"manifest.json")))return enrichManifestFromHost(await readManifest(cacheDir),hostUiDir());let{loadManifest:snapshotManifest}=await import("./chunk-t61vyqpd.js");return enrichManifestFromHost(await snapshotManifest(),hostUiDir())};return{id:"shadcn-upstream",version,componentsDir,styleEntryPath:entryCssPath3,registry:registry2,loadManifest,label:`shadcn (upstream @ ${version})`,styleChannel:TAILWIND_CLASSNAME,styleChannels:["tailwind-classname"],mcpIntro:()=>['**This folder targets shadcn/ui with Tailwind.** The canvas imports client-safe components directly from the app\'s `components/ui`, adapts overlay families to stay inline, and falls back per component when a file is missing \u2014 `component_status` says which, before you claim fidelity. Style with a className string: `update_props { style: "flex gap-4 p-6" }`.',""],catalog:async()=>{let manifest=await loadManifest(),addNameOf=addNameIndex(manifest),shadcn=manifest.filter((c)=>c.source!=="velloo"),present=installedAddNames(hostUiDir());return shadcn.map((c)=>{let addName=addNameOf(c.id);return{id:c.id,installed:present.has(addName),importPath:`@/components/ui/${addName}`}})},ownedModules:{dirs:()=>{let uiDir=hostUiDir();return uiDir?[uiDir]:[]},supplies:(file,exportName)=>{let family=basename(file).replace(/\.[jt]sx?$/,""),counterpart=join5(componentsDir3,"ui",`${family}.tsx`);return familyExports(counterpart).has(exportName)}},canvasBundleSpec:{styleRuntime:{kind:"none"},components:async(ids)=>{let manifest=await loadManifest(),addNameOf=addNameIndex(manifest),sourceById=new Map(manifest.map((entry)=>[entry.id,entry.source])),uiDir=hostUiDir();return ids.flatMap((id)=>{if(sourceById.get(id)==="velloo"){let path=helperSourcePath(id);return path?[{id,sources:[{importPath:path,exportName:id,fidelity:"exact",note:"Velloo helper, mounted beside the app's components."}]}]:[]}if(!sourceById.has(id))return[];let addName=addNameOf(id),snapshotPath=join5(componentsDir3,"ui",`${addName}.tsx`);if(CANVAS_ADAPTED_FAMILIES.has(addName)){let installed=uiDir!==null&&hostComponentFile(uiDir,addName,id)!==null;return[{id,sources:[{importPath:snapshotPath,exportName:id,fidelity:"adapted",note:installed?"The app's own component uses portals or runtime state; Velloo renders its canvas-safe counterpart inline.":"The app has not installed this component. Velloo renders its own canvas-safe one inline; install it in the app before implementing a design that uses it."}]}]}let hostPath=uiDir?hostComponentFile(uiDir,addName,id):null;return[{id,sources:[...hostPath?[{importPath:hostPath,exportName:id,fidelity:"exact",preflight:!0,note:"Rendered directly from the app's shadcn source file."}]:[],{importPath:snapshotPath,exportName:id,fidelity:"fallback",note:hostPath?"The app source did not compile for the browser canvas; using the bundled canvas fallback.":"The app does not install this component under this name (it may be renamed in its own file); using the bundled canvas fallback."}]}]})},sourceDirs:()=>{let uiDir=hostUiDir()??plannedUiDir;return uiDir?[uiDir]:[]}}}}var CANVAS_ADAPTED_FAMILIES=new Set(["alert-dialog","calendar","carousel","chart","dialog","dropdown-menu","popover","select","sheet","sonner","tooltip"]),familyExportCache=new Map;function familyExports(path){let names=familyExportCache.get(path);if(!names){names=new Set;try{let source=readFileSync4(path,"utf8");for(let id of Object.keys(registry2))if(exportsName(source,id))names.add(id)}catch{}familyExportCache.set(path,names)}return names}export{createProvider};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{AuthConfigResponseSchema,HealthResponseSchema,cloudJson}from"./chunk-1gkeepkm.js";var BUILT_DEFAULT="https://api.velloo.ai";function defaultCloudUrl(){return(process.env.VELLOO_CLOUD_URL??BUILT_DEFAULT).replace(/\/+$/,"")}var CONFIG_TIMEOUT_MS=5000;function cloudOrigin(baseUrl){return new URL(baseUrl).origin}async function fetchCloudAppUrl(baseUrl,timeoutMs=CONFIG_TIMEOUT_MS){let fallback=cloudOrigin(baseUrl),res;try{res=await fetch(`${fallback}/v1/auth/config`,{signal:AbortSignal.timeout(timeoutMs)})}catch{return fallback}if(!res.ok)return fallback;let config=await cloudJson(res,AuthConfigResponseSchema,"reading the cloud's config");if(!config.ok||config.value.appUrl===void 0)return fallback;try{let advertised=new URL(config.value.appUrl).origin;return isSecureCloudUrl(advertised)?advertised:fallback}catch{return fallback}}async function publishedBoardsUrl(baseUrl){return`${await fetchCloudAppUrl(baseUrl)}/boards`}async function billingPageUrl(baseUrl){return`${await fetchCloudAppUrl(baseUrl)}/billing`}var LOOPBACK=new Set(["localhost","127.0.0.1","::1","[::1]"]);function isSecureCloudUrl(cloudUrl){try{let u=new URL(cloudUrl);if(u.protocol==="https:")return!0;return u.protocol==="http:"&&LOOPBACK.has(u.hostname)}catch{return!1}}function assertSecureCloudUrl(cloudUrl){if(!isSecureCloudUrl(cloudUrl))throw Error(`refusing to send credentials to a non-HTTPS cloud URL: ${cloudUrl} (use https:// or a loopback host)`)}async function checkCloudHealth(baseUrl){let res;try{res=await fetch(`${baseUrl}/health`,{signal:AbortSignal.timeout(8000)})}catch(error){return{status:"unreachable",reason:error instanceof Error?error.message:String(error)}}let health=await cloudJson(res,HealthResponseSchema,"reading the cloud's health");if(!health.ok||health.value.ok!==!1)return{status:"ok"};let down=[health.value.db?.ok===!1?"database":null,health.value.blob?.ok===!1?"storage backend":null].filter((part)=>part!==null);return{status:"unhealthy",detail:`the cloud's ${down.length>0?down.join(" and "):"a dependency"} is unavailable \u2014 publishes and share links are down; try again later.`}}
2
+ import{AuthConfigResponseSchema,HealthResponseSchema,cloudJson}from"./chunk-bntsn3wj.js";var BUILT_DEFAULT="https://api.velloo.ai";function defaultCloudUrl(){return(process.env.VELLOO_CLOUD_URL??BUILT_DEFAULT).replace(/\/+$/,"")}var CONFIG_TIMEOUT_MS=5000;function cloudOrigin(baseUrl){return new URL(baseUrl).origin}async function fetchCloudAppUrl(baseUrl,timeoutMs=CONFIG_TIMEOUT_MS){let fallback=cloudOrigin(baseUrl),res;try{res=await fetch(`${fallback}/v1/auth/config`,{signal:AbortSignal.timeout(timeoutMs)})}catch{return fallback}if(!res.ok)return fallback;let config=await cloudJson(res,AuthConfigResponseSchema,"reading the cloud's config");if(!config.ok||config.value.appUrl===void 0)return fallback;try{let advertised=new URL(config.value.appUrl).origin;return isSecureCloudUrl(advertised)?advertised:fallback}catch{return fallback}}async function publishedBoardsUrl(baseUrl){return`${await fetchCloudAppUrl(baseUrl)}/boards`}async function billingPageUrl(baseUrl){return`${await fetchCloudAppUrl(baseUrl)}/billing`}var LOOPBACK=new Set(["localhost","127.0.0.1","::1","[::1]"]);function isSecureCloudUrl(cloudUrl){try{let u=new URL(cloudUrl);if(u.protocol==="https:")return!0;return u.protocol==="http:"&&LOOPBACK.has(u.hostname)}catch{return!1}}function assertSecureCloudUrl(cloudUrl){if(!isSecureCloudUrl(cloudUrl))throw Error(`refusing to send credentials to a non-HTTPS cloud URL: ${cloudUrl} (use https:// or a loopback host)`)}async function checkCloudHealth(baseUrl){let res;try{res=await fetch(`${baseUrl}/health`,{signal:AbortSignal.timeout(8000)})}catch(error){return{status:"unreachable",reason:error instanceof Error?error.message:String(error)}}let health=await cloudJson(res,HealthResponseSchema,"reading the cloud's health");if(!health.ok||health.value.ok!==!1)return{status:"ok"};let down=[health.value.db?.ok===!1?"database":null,health.value.blob?.ok===!1?"storage backend":null].filter((part)=>part!==null);return{status:"unhealthy",detail:`the cloud's ${down.length>0?down.join(" and "):"a dependency"} is unavailable \u2014 publishes and share links are down; try again later.`}}
3
3
  export{defaultCloudUrl,fetchCloudAppUrl,publishedBoardsUrl,billingPageUrl,isSecureCloudUrl,assertSecureCloudUrl,checkCloudHealth};
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{isCancel,confirm,select}from"./chunk-80fjfyha.js";import{designNameIssue}from"./chunk-8cj4swpr.js";import{managedDesignId,localDesignOf,removeLocalDesign,recordedDesignName,designRenameConflict,followDesignRename,loadDesignFolder}from"./chunk-yfvc8d2g.js";import"./chunk-chtv0yj6.js";import"./chunk-1gkeepkm.js";import{agentRootCandidates}from"./chunk-rjjc9vam.js";import"./chunk-t6qr2ay9.js";import{daemonRoot,readLock,isLive,stopDaemon}from"./chunk-azeqkms7.js";import{fail}from"./chunk-s23gtejf.js";import"./chunk-1td6z6ey.js";import"./chunk-ff0jfn0v.js";import"./chunk-p93x4pn2.js";import{displayPath}from"./chunk-hf4adxe0.js";import"./chunk-mfch0b0t.js";import"./chunk-rk238m15.js";import{recordedAppRoot,planAppRootChange,applyAppRootChange,promptAppRootChoice,planRelocation,relocateDesign,runInit2}from"./chunk-ab8fga32.js";import"./chunk-2ba6edh8.js";import{repinAgentConfigs,migrateFolder2}from"./chunk-xtwx2p9g.js";import"./chunk-pjtg3wnm.js";import"./chunk-k423dkjz.js";import"./chunk-8vam2893.js";import"./chunk-jsvkqae2.js";import{findManifest,manifestListing,findDesigns,unregisterDesign,isWithin,writeDesignName,registerLocalDesign,DESIGN_ARG_DESCRIPTION,hasDesignConfig,DESIGN_ID_ARG,resolveDesign,checkoutDesigns}from"./chunk-8vgpffn7.js";import"./chunk-hjc5eg5c.js";import{require_picocolors}from"./chunk-jrsknzjt.js";import{__toESM,defineCommand}from"./chunk-2smsg2ct.js";import{randomUUID}from"crypto";import{existsSync,realpathSync}from"fs";import{readdir,rm}from"fs/promises";import{join,relative,resolve}from"path";var import_picocolors=__toESM(require_picocolors(),1);async function countJson(dir,skipSuffix){try{return(await readdir(dir)).filter((f)=>f.endsWith(".json")&&!(skipSuffix&&f.endsWith(skipSuffix))).length}catch{return 0}}async function daemonState(folder){let rec=await readLock(daemonRoot(folder));if(!rec)return"stopped";return await isLive(rec)?`running :${rec.canvasPort}`:"stopped"}var list=defineCommand({meta:{name:"list",description:"List the repo's designs"},async run(){let cwd=resolve("."),found=await findDesigns(cwd).catch((err)=>{fail("design list",err.message)});if(!found||found.designs.length===0){let only=await resolveDesign(void 0,"design list",{requireConfig:!0,cwd,takesDesign:!1,onFail:(message)=>fail("design list",message)}),name=recordedDesignName(only)??"(unnamed)",owner=await manifestListing(only).catch(()=>null);if(owner&&owner.dir!==cwd){console.log(`velloo design: "${name}" (${relative(cwd,only)||only}) is listed in \`${relative(cwd,owner.path)}\`. Run \`velloo design list\` from \`${relative(cwd,owner.dir)||"."}\` to see that project's designs.`);return}console.log("velloo design: 1 design (no velloo.json yet)"),console.log(` ${import_picocolors.default.dim("1")} ${import_picocolors.default.bold(name)} ${relative(cwd,only)||only} ${await daemonState(only)}`),console.log(import_picocolors.default.dim(" `velloo design add` creates a second design and lists both."));return}let base=found.repo?.dir??found.local[0]?.root??cwd,rows=[];for(let design of found.designs){let live=design.exists&&!design.outsideRepo;rows.push({name:found.conflicts.has(design.name)?`${design.name} (duplicate)`:design.name,path:design.local?`${displayPath(design.root)} (local)`:relative(base,design.root)||".",boards:live?await countJson(join(design.root,"boards"),".notes.json"):0,state:design.outsideRepo?import_picocolors.default.yellow("outside the repo"):live?await daemonState(design.root):import_picocolors.default.yellow("missing"),live})}let pad=(text,width)=>text+" ".repeat(Math.max(0,width-Bun.stringWidth(text))),width=Math.max(...rows.map((r)=>Bun.stringWidth(r.name))),pathWidth=Math.max(...rows.map((r)=>Bun.stringWidth(r.path))),idWidth=String(rows.length).length;console.log(`velloo design: ${rows.length} in ${base}`);for(let[index,row]of rows.entries()){let marker=row.name===found.defaultDesign?import_picocolors.default.cyan("\u25CF"):" ",id=import_picocolors.default.dim(String(index+1).padStart(idWidth)),boards=row.live?`${row.boards} board${row.boards===1?"":"s"}`:"\u2014";console.log(` ${id} ${marker} ${import_picocolors.default.bold(pad(row.name,width))} ${import_picocolors.default.dim(pad(row.path,pathWidth))} ${boards.padEnd(9)} ${row.state}`)}console.log(import_picocolors.default.dim(" Pass a number as --id to the other `velloo design` commands."));for(let[name,designs]of found.conflicts)console.log(import_picocolors.default.yellow(` ! ${designs.length} designs are named "${name}" \u2014 rename one with \`velloo design rename <path> <new-name>\`.`))}}),add=defineCommand({meta:{name:"add",description:"Create another design in this repo (the init wizard, folder pre-chosen)"},args:{path:{type:"positional",required:!1,description:"Where the new design folder goes, relative to the repo (asked when omitted)"},external:{type:"boolean",description:"Create in Velloo-managed external storage"},nonInteractive:{type:"boolean",description:"Use defaults without prompting"},connect:{type:"boolean",default:!0,description:"Wire project agents"},library:{type:"string",description:"Component library (default: the sibling folder's)"},name:{type:"string",description:"The design's name (default: derived from its folder)"}},async run({args}){await runInit2({addFolder:!0,external:args.external,nonInteractive:args.nonInteractive,connect:args.connect,...args.path?{designFolder:args.path}:{},...args.library?{library:args.library}:{},...args.name?{name:args.name}:{}})}}),remove=defineCommand({meta:{name:"remove",description:"Remove a design \u2014 one outside the repo can keep its files (asked, or --delete-content)"},args:{design:{type:"positional",required:!1,description:DESIGN_ARG_DESCRIPTION},id:DESIGN_ID_ARG,deleteContent:{type:"boolean",description:"Also delete the files of a design outside the repo (with --yes, or to skip the question)"},yes:{type:"boolean",description:"Skip the confirmation (required without an interactive terminal)"}},async run({args}){let cwd=resolve("."),folder=await resolveDesign(args.design,"design remove",{id:args.id,interactive:!0,requireConfig:!0,cwd}),local=localDesignOf(folder);if(!Boolean(process.stdin.isTTY)&&args.yes!==!0)fail("design remove","refusing to delete a design folder without --yes");let boards=await countJson(join(folder,"boards"),".notes.json"),screens=await countJson(join(folder,"screens"),".annotations.json"),name=recordedDesignName(folder)??folder;console.log(`velloo design: ${name} (${folder})`),console.log(import_picocolors.default.dim(` ${boards} board${boards===1?"":"s"}, ${screens} screen${screens===1?"":"s"}`));let keepContent=local!==null&&args.deleteContent!==!0;if(args.yes!==!0)if(local&&args.deleteContent!==!0){let managed=managedDesignId(folder)!==null,choice=await select({message:"Remove this design?",initialValue:managed?"delete":"keep",options:[{value:"delete",label:"Delete it and its files",hint:managed?"in Velloo's storage":folder},{value:"keep",label:"Forget it, keep the files",hint:folder},{value:"cancel",label:"Cancel"}]});if(isCancel(choice)||choice==="cancel"){console.log(import_picocolors.default.dim(" Nothing changed."));return}keepContent=choice==="keep"}else{let approved=await confirm({message:"Delete this design folder and everything in it?",initialValue:!1});if(isCancel(approved)||!approved){console.log(import_picocolors.default.dim(" Nothing changed."));return}}if(await stopDaemon(daemonRoot(folder)))console.log(import_picocolors.default.dim(" Stopped its canvas."));let dropped=local?null:await unregisterDesign(folder,cwd).catch((err)=>fail("design remove",err.message));if(local)await removeLocalDesign(local.id);if(!keepContent)await rm(folder,{recursive:!0,force:!0});if(console.log(`velloo design: ${keepContent?"retained content at":"removed"} ${folder}`),local)console.log(import_picocolors.default.dim(` Forgot the local design "${name}".`));if(dropped?.name)console.log(import_picocolors.default.dim(dropped.removedManifest?` Dropped "${dropped.name}" \u2014 velloo.json listed no other designs, so it's gone too.`:` Dropped "${dropped.name}" from velloo.json.`))}}),move=defineCommand({meta:{name:"move",description:"Preview moving a design between the repository, managed storage and another directory; --yes applies"},args:{design:{type:"positional",required:!1,description:DESIGN_ARG_DESCRIPTION},id:DESIGN_ID_ARG,external:{type:"boolean",description:"Move to managed storage (a local design)"},to:{type:"string",description:"New directory \u2014 inside the repository it goes in velloo.json, outside it is local"},yes:{type:"boolean",description:"Apply the displayed move"}},async run({args}){let source=await resolveDesign(args.design,"design move",{id:args.id,interactive:!0,requireConfig:!0}),plan=await planRelocation(source,resolve("."),args.to,args.external===!0).catch((err)=>fail("design move",err.message)),local="a local design on this machine",recorded=plan.sourceManifestPath?plan.destinationLocal?`velloo.json path "${plan.sourceManifestPath}" \u2192 ${"a local design on this machine"}`:`velloo.json path "${plan.sourceManifestPath}" \u2192 "${plan.destinationManifestPath}"`:plan.destinationLocal?"stays a local design on this machine":`${"a local design on this machine"} \u2192 velloo.json path "${plan.destinationManifestPath}"`;if(console.log(`Source: ${plan.source}
2
+ import{isCancel,confirm,select}from"./chunk-80fjfyha.js";import{designNameIssue}from"./chunk-xxw67jpk.js";import{managedDesignId,localDesignOf,removeLocalDesign,recordedDesignName,designRenameConflict,followDesignRename,loadDesignFolder}from"./chunk-9g45c5md.js";import"./chunk-xg49s85z.js";import"./chunk-bntsn3wj.js";import{agentRootCandidates}from"./chunk-07fxzrx2.js";import"./chunk-rrrn1mkq.js";import{daemonRoot,readLock,isLive,stopDaemon}from"./chunk-qgbat4fv.js";import{fail}from"./chunk-s23gtejf.js";import"./chunk-dy7qwj3t.js";import"./chunk-32cq4wpr.js";import"./chunk-p93x4pn2.js";import{displayPath}from"./chunk-45wv1fs5.js";import"./chunk-cg0sjdqt.js";import"./chunk-d19ttv1a.js";import{recordedAppRoot,planAppRootChange,applyAppRootChange,promptAppRootChoice,planRelocation,relocateDesign,runInit2}from"./chunk-dqqpbmxt.js";import"./chunk-rg86bhtb.js";import{repinAgentConfigs,migrateFolder2}from"./chunk-mqx96m2g.js";import"./chunk-pjtg3wnm.js";import"./chunk-ez720ked.js";import"./chunk-z6r6wxm6.js";import"./chunk-asqpx5v7.js";import{findManifest,manifestListing,findDesigns,unregisterDesign,isWithin,writeDesignName,registerLocalDesign,DESIGN_ARG_DESCRIPTION,hasDesignConfig,DESIGN_ID_ARG,resolveDesign,checkoutDesigns}from"./chunk-6w42sr61.js";import"./chunk-w30zfv3m.js";import{require_picocolors}from"./chunk-jrsknzjt.js";import{__toESM,defineCommand}from"./chunk-2smsg2ct.js";import{randomUUID}from"crypto";import{existsSync,realpathSync}from"fs";import{readdir,rm}from"fs/promises";import{join,relative,resolve}from"path";var import_picocolors=__toESM(require_picocolors(),1);async function countJson(dir,skipSuffix){try{return(await readdir(dir)).filter((f)=>f.endsWith(".json")&&!(skipSuffix&&f.endsWith(skipSuffix))).length}catch{return 0}}async function daemonState(folder){let rec=await readLock(daemonRoot(folder));if(!rec)return"stopped";return await isLive(rec)?`running :${rec.canvasPort}`:"stopped"}var list=defineCommand({meta:{name:"list",description:"List the repo's designs"},async run(){let cwd=resolve("."),found=await findDesigns(cwd).catch((err)=>{fail("design list",err.message)});if(!found||found.designs.length===0){let only=await resolveDesign(void 0,"design list",{requireConfig:!0,cwd,takesDesign:!1,onFail:(message)=>fail("design list",message)}),name=recordedDesignName(only)??"(unnamed)",owner=await manifestListing(only).catch(()=>null);if(owner&&owner.dir!==cwd){console.log(`velloo design: "${name}" (${relative(cwd,only)||only}) is listed in \`${relative(cwd,owner.path)}\`. Run \`velloo design list\` from \`${relative(cwd,owner.dir)||"."}\` to see that project's designs.`);return}console.log("velloo design: 1 design (no velloo.json yet)"),console.log(` ${import_picocolors.default.dim("1")} ${import_picocolors.default.bold(name)} ${relative(cwd,only)||only} ${await daemonState(only)}`),console.log(import_picocolors.default.dim(" `velloo design add` creates a second design and lists both."));return}let base=found.repo?.dir??found.local[0]?.root??cwd,rows=[];for(let design of found.designs){let live=design.exists&&!design.outsideRepo;rows.push({name:found.conflicts.has(design.name)?`${design.name} (duplicate)`:design.name,path:design.local?`${displayPath(design.root)} (local)`:relative(base,design.root)||".",boards:live?await countJson(join(design.root,"boards"),".notes.json"):0,state:design.outsideRepo?import_picocolors.default.yellow("outside the repo"):live?await daemonState(design.root):import_picocolors.default.yellow("missing"),live})}let pad=(text,width)=>text+" ".repeat(Math.max(0,width-Bun.stringWidth(text))),width=Math.max(...rows.map((r)=>Bun.stringWidth(r.name))),pathWidth=Math.max(...rows.map((r)=>Bun.stringWidth(r.path))),idWidth=String(rows.length).length;console.log(`velloo design: ${rows.length} in ${base}`);for(let[index,row]of rows.entries()){let marker=row.name===found.defaultDesign?import_picocolors.default.cyan("\u25CF"):" ",id=import_picocolors.default.dim(String(index+1).padStart(idWidth)),boards=row.live?`${row.boards} board${row.boards===1?"":"s"}`:"\u2014";console.log(` ${id} ${marker} ${import_picocolors.default.bold(pad(row.name,width))} ${import_picocolors.default.dim(pad(row.path,pathWidth))} ${boards.padEnd(9)} ${row.state}`)}console.log(import_picocolors.default.dim(" Pass a number as --id to the other `velloo design` commands."));for(let[name,designs]of found.conflicts)console.log(import_picocolors.default.yellow(` ! ${designs.length} designs are named "${name}" \u2014 rename one with \`velloo design rename <path> <new-name>\`.`))}}),add=defineCommand({meta:{name:"add",description:"Create another design in this repo (the init wizard, folder pre-chosen)"},args:{path:{type:"positional",required:!1,description:"Where the new design folder goes, relative to the repo (asked when omitted)"},external:{type:"boolean",description:"Create in Velloo-managed external storage"},nonInteractive:{type:"boolean",description:"Use defaults without prompting"},connect:{type:"boolean",default:!0,description:"Wire project agents"},library:{type:"string",description:"Component library (default: the sibling folder's)"},name:{type:"string",description:"The design's name (default: derived from its folder)"}},async run({args}){await runInit2({addFolder:!0,external:args.external,nonInteractive:args.nonInteractive,connect:args.connect,...args.path?{designFolder:args.path}:{},...args.library?{library:args.library}:{},...args.name?{name:args.name}:{}})}}),remove=defineCommand({meta:{name:"remove",description:"Remove a design \u2014 one outside the repo can keep its files (asked, or --delete-content)"},args:{design:{type:"positional",required:!1,description:DESIGN_ARG_DESCRIPTION},id:DESIGN_ID_ARG,deleteContent:{type:"boolean",description:"Also delete the files of a design outside the repo (with --yes, or to skip the question)"},yes:{type:"boolean",description:"Skip the confirmation (required without an interactive terminal)"}},async run({args}){let cwd=resolve("."),folder=await resolveDesign(args.design,"design remove",{id:args.id,interactive:!0,requireConfig:!0,cwd}),local=localDesignOf(folder);if(!Boolean(process.stdin.isTTY)&&args.yes!==!0)fail("design remove","refusing to delete a design folder without --yes");let boards=await countJson(join(folder,"boards"),".notes.json"),screens=await countJson(join(folder,"screens"),".annotations.json"),name=recordedDesignName(folder)??folder;console.log(`velloo design: ${name} (${folder})`),console.log(import_picocolors.default.dim(` ${boards} board${boards===1?"":"s"}, ${screens} screen${screens===1?"":"s"}`));let keepContent=local!==null&&args.deleteContent!==!0;if(args.yes!==!0)if(local&&args.deleteContent!==!0){let managed=managedDesignId(folder)!==null,choice=await select({message:"Remove this design?",initialValue:managed?"delete":"keep",options:[{value:"delete",label:"Delete it and its files",hint:managed?"in Velloo's storage":folder},{value:"keep",label:"Forget it, keep the files",hint:folder},{value:"cancel",label:"Cancel"}]});if(isCancel(choice)||choice==="cancel"){console.log(import_picocolors.default.dim(" Nothing changed."));return}keepContent=choice==="keep"}else{let approved=await confirm({message:"Delete this design folder and everything in it?",initialValue:!1});if(isCancel(approved)||!approved){console.log(import_picocolors.default.dim(" Nothing changed."));return}}if(await stopDaemon(daemonRoot(folder)))console.log(import_picocolors.default.dim(" Stopped its canvas."));let dropped=local?null:await unregisterDesign(folder,cwd).catch((err)=>fail("design remove",err.message));if(local)await removeLocalDesign(local.id);if(!keepContent)await rm(folder,{recursive:!0,force:!0});if(console.log(`velloo design: ${keepContent?"retained content at":"removed"} ${folder}`),local)console.log(import_picocolors.default.dim(` Forgot the local design "${name}".`));if(dropped?.name)console.log(import_picocolors.default.dim(dropped.removedManifest?` Dropped "${dropped.name}" \u2014 velloo.json listed no other designs, so it's gone too.`:` Dropped "${dropped.name}" from velloo.json.`))}}),move=defineCommand({meta:{name:"move",description:"Preview moving a design between the repository, managed storage and another directory; --yes applies"},args:{design:{type:"positional",required:!1,description:DESIGN_ARG_DESCRIPTION},id:DESIGN_ID_ARG,external:{type:"boolean",description:"Move to managed storage (a local design)"},to:{type:"string",description:"New directory \u2014 inside the repository it goes in velloo.json, outside it is local"},yes:{type:"boolean",description:"Apply the displayed move"}},async run({args}){let source=await resolveDesign(args.design,"design move",{id:args.id,interactive:!0,requireConfig:!0}),plan=await planRelocation(source,resolve("."),args.to,args.external===!0).catch((err)=>fail("design move",err.message)),local="a local design on this machine",recorded=plan.sourceManifestPath?plan.destinationLocal?`velloo.json path "${plan.sourceManifestPath}" \u2192 ${"a local design on this machine"}`:`velloo.json path "${plan.sourceManifestPath}" \u2192 "${plan.destinationManifestPath}"`:plan.destinationLocal?"stays a local design on this machine":`${"a local design on this machine"} \u2192 velloo.json path "${plan.destinationManifestPath}"`;if(console.log(`Source: ${plan.source}
3
3
  Destination: ${plan.destination}
4
4
  Design "${plan.designName}": ${recorded}`),!args.yes){console.log("Preview only. Add --yes to apply the move.");return}await relocateDesign(plan),console.log(`Moved ${plan.designName} to ${plan.destination}. Run velloo connect to refresh existing agent guidance.`)}});async function renameThroughCanvas(folder,name){let rec=await readLock(daemonRoot(folder));if(!rec||!await isLive(rec))return!1;let res;try{res=await fetch(`http://127.0.0.1:${rec.canvasPort}/api/mutate/update_design_name`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name}),signal:AbortSignal.timeout(1e4)})}catch(err){fail("design rename",`the running canvas didn't answer (${err.message}).`)}if(res.ok)return!0;let body=await res.json().catch(()=>null);fail("design rename",body?.error?.message??`the running canvas refused (HTTP ${res.status}).`)}var rename=defineCommand({meta:{name:"rename",description:"Rename a design"},args:{design:{type:"positional",required:!1,description:"The design to rename \u2014 its current name or its folder path (or use --id)"},name:{type:"positional",required:!1,description:"The new name"},id:DESIGN_ID_ARG},async run({args}){let cwd=resolve("."),newName=args.id!==void 0&&args.name===void 0?args.design:args.name,target=args.id!==void 0&&args.name===void 0?void 0:args.design;if(newName===void 0)fail("design rename","pass the design and its new name: `velloo design rename <design> <new name>`.");let folder=await resolveDesign(target,"design rename",{id:args.id,requireConfig:!0,cwd}),previous=recordedDesignName(folder);if(previous===newName){console.log(import_picocolors.default.dim(` Already named "${newName}" \u2014 nothing changed.`));return}let conflict=await designRenameConflict(folder,newName).catch((err)=>fail("design rename",err.message));if(conflict)fail("design rename",conflict);if(!await renameThroughCanvas(folder,newName)){if(await writeDesignName(folder,newName),previous&&await followDesignRename(folder,previous,newName))console.log(import_picocolors.default.dim(` velloo.json defaultDesign \u2192 "${newName}"`))}console.log(`velloo design: renamed ${previous?`"${previous}" `:""}to "${newName}".`);let repinned=previous?await repinAgentConfigs({projectRoots:await agentRootCandidates(folder),designFolder:folder,names:[previous]}).catch(()=>[]):[];for(let path of repinned)console.log(import_picocolors.default.dim(` ${relative(cwd,path)||path}: no longer names the design`))}}),upgrade=defineCommand({meta:{name:"upgrade",description:"Migrate a design to this Velloo's format, without upgrading Velloo itself"},args:{design:{type:"positional",required:!1,description:DESIGN_ARG_DESCRIPTION},id:DESIGN_ID_ARG,all:{type:"boolean",description:"Migrate every design in this checkout"},"dry-run":{type:"boolean",default:!1,description:"Show what would change without writing"},skills:{type:"boolean",default:!0,description:"Also refresh the installed agent skills / plugin / rules to this velloo's versions"}},async run({args}){if(args.all&&(args.design||args.id!==void 0))fail("design upgrade","pass a design or --all, not both.");let folders=args.all?await checkoutDesigns(resolve(".")):[await resolveDesign(args.design,"design upgrade",{id:args.id,interactive:!0,requireConfig:!0})];if(folders.length===0)fail("design upgrade","no designs here \u2014 `velloo init` creates one.");for(let folder of folders)await migrateFolder2(folder,{dryRun:args["dry-run"],skills:args.skills})}}),bind=defineCommand({meta:{name:"bind",description:"Attach a design folder outside this checkout to it, on this machine only"},args:{design:{type:"positional",required:!0,description:"The design folder (in managed storage or anywhere outside the checkout)"},name:{type:"string",description:"Rename the design as it is bound"},yes:{type:"boolean",description:"Confirm the local binding"}},async run({args}){let cwd=resolve("."),folder=resolve(args.design);if(!await hasDesignConfig(folder))fail("design bind",`${folder} is not a velloo design folder (no .design/config.json).`);let root=cwd;if(isWithin(root,folder))fail("design bind",`${folder} is inside this checkout (${root}); a design here belongs in velloo.json \u2014 see \`velloo design add\`.`);let name=args.name??recordedDesignName(folder);if(!name)fail("design bind",`${folder} has no design name \u2014 run \`velloo upgrade ${folder}\` first.`);let issue=designNameIssue(name);if(issue)fail("design bind",`invalid --name ${JSON.stringify(name)} \u2014 ${issue}`);let clash=(await findDesigns(root).catch((err)=>fail("design bind",err.message)))?.designs.find((d)=>d.name===name&&!(existsSync(d.root)&&realpathSync(d.root)===realpathSync(folder)));if(clash)fail("design bind",`a design named "${name}" already exists at ${clash.root} \u2014 pass --name to bind this one under another.`);let existing=localDesignOf(folder),appRoot=existing?join(root,relative(existing.root,existing.appRoot)):root,listed=(await findManifest(cwd).catch(()=>null))?.folders.some((path)=>existsSync(path)&&realpathSync(path)===realpathSync(folder));if(console.log(`Design: ${name} (${folder})
5
5
  Checkout: ${root}