velloo 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -41
- package/canvas/assets/index-CqXW6xA_.js +29 -0
- package/canvas/assets/index-gB0StCrx.css +2 -0
- package/canvas/assets/lucide-all-C_CNpsMs.js +1 -0
- package/canvas/assets/{radix-C3HaOB-d.js → radix-gmpYzWRH.js} +1 -1
- package/canvas/index.html +3 -3
- package/chunk-0zen7bzb.js +3 -0
- package/{chunk-h0c36khx.js → chunk-1jzhw3p4.js} +1 -1
- package/chunk-1n5kmsxb.js +2 -0
- package/{chunk-k6ferbam.js → chunk-2fgfex9b.js} +1 -1
- package/{chunk-t2ttkxe9.js → chunk-3g3dqej3.js} +1 -1
- package/chunk-3tmsrvaj.js +2 -0
- package/chunk-49cgk5s2.js +2 -0
- package/{chunk-e2ag33vd.js → chunk-4nqr089t.js} +2 -2
- package/chunk-52hxv18g.js +6 -0
- package/chunk-5ezzc1h2.js +688 -0
- package/{chunk-74skmg76.js → chunk-5wv5a52y.js} +1 -1
- package/chunk-6nzqhfqq.js +5 -0
- package/{chunk-fgw3hp2v.js → chunk-6zz9kfbd.js} +1 -1
- package/chunk-788t8y5x.js +2 -0
- package/chunk-7bvvbsqy.js +26 -0
- package/{chunk-cep3ktr3.js → chunk-7k7dpj5y.js} +1 -1
- package/{chunk-hs2j6s1v.js → chunk-7njj1qmq.js} +8 -31
- package/{chunk-8ssr8a8w.js → chunk-80fjfyha.js} +3 -6
- package/chunk-94vx1yb0.js +3 -0
- package/{chunk-n5007jcz.js → chunk-9f22qnge.js} +1 -1
- package/chunk-9g4tr0r6.js +2 -0
- package/{chunk-1gx45384.js → chunk-9nhw49vv.js} +7 -8
- package/{chunk-2z0k59hz.js → chunk-as08hzp3.js} +1 -1
- package/chunk-bhx8k09w.js +3 -0
- package/chunk-bpeezw7w.js +3 -0
- package/{chunk-b2ebm1t3.js → chunk-bvmtq0vn.js} +2 -2
- package/{chunk-w5rzk6ms.js → chunk-c4fym47a.js} +64 -20
- package/{chunk-d385435m.js → chunk-c6hywdvq.js} +1 -1
- package/{chunk-jnsfgtn9.js → chunk-cvn689d5.js} +1 -1
- package/chunk-cxzkkn12.js +2 -0
- package/{chunk-56vqqr8s.js → chunk-d9p6s05n.js} +1 -1
- package/{chunk-5js0qw32.js → chunk-dsks52m7.js} +1 -1
- package/{chunk-b7j86xq7.js → chunk-hfzg98c8.js} +1 -1
- package/{chunk-7e39xe21.js → chunk-js6mz7h1.js} +1 -1
- package/chunk-jx11jvq8.js +7 -0
- package/{chunk-2vx420g2.js → chunk-k6n249vb.js} +2 -2
- package/chunk-k7sehkm8.js +3 -0
- package/{chunk-k784090q.js → chunk-k9219kmj.js} +1 -1
- package/{chunk-65wb0g7d.js → chunk-kz4423th.js} +1 -1
- package/{chunk-g02nd9hn.js → chunk-m3czg1tt.js} +1 -1
- package/chunk-maz6z7tz.js +5 -0
- package/{chunk-rksq3w72.js → chunk-n9kcxaj7.js} +2 -2
- package/chunk-n9t36h0q.js +2 -0
- package/chunk-nr3ej3qf.js +5 -0
- package/{chunk-bk8b7f9a.js → chunk-nte0t7v3.js} +4 -3
- package/{chunk-kxk5x7g6.js → chunk-nycs0z7h.js} +1 -1
- package/{chunk-79ykzywe.js → chunk-pjtg3wnm.js} +1 -1
- package/chunk-qdnb2t6a.js +3 -0
- package/chunk-qgwhd4n6.js +86 -0
- package/chunk-sn9vg42q.js +2 -0
- package/{chunk-7p7ha0qk.js → chunk-t5bb30zy.js} +1 -1
- package/chunk-tbmkq7wy.js +6 -0
- package/chunk-tc4mzzfw.js +2 -0
- package/chunk-td5z2sm4.js +6 -0
- package/chunk-wa6qamwh.js +3 -0
- package/chunk-wcqqx6tz.js +2 -0
- package/chunk-wzngjjeb.js +10 -0
- package/chunk-xyfed1j0.js +2 -0
- package/chunk-y5r2w2z3.js +2 -0
- package/chunk-yeh9gb5w.js +3 -0
- package/cli.js +1 -1
- package/launcher.cjs +1 -1
- package/package.json +3 -3
- package/pkgs/helpers/src/descriptors.ts +7 -1
- package/pkgs/provider-antd/src/index.ts +1 -0
- package/pkgs/provider-chakra/src/index.ts +1 -0
- package/pkgs/provider-mui/src/index.ts +1 -0
- package/pkgs/provider-none/src/index.ts +42 -1
- package/pkgs/provider-none/src/intro.ts +2 -2
- package/pkgs/schema/src/config.ts +27 -1
- package/pkgs/schema/src/extension.ts +26 -0
- package/pkgs/schema/src/index.ts +18 -0
- package/pkgs/schema/src/migrate.ts +57 -4
- package/pkgs/schema/src/node.ts +99 -0
- package/pkgs/schema/src/repo.ts +98 -16
- package/pkgs/schema/src/screen.ts +7 -0
- package/pkgs/schema/src/svg-sanitize.ts +472 -59
- package/pkgs/shadcn-snapshot/dist/manifest.json +9 -1
- package/skills/velloo-setup/SKILL.md +70 -48
- package/canvas/assets/index-BCvDZiBo.css +0 -2
- package/canvas/assets/index-BcBJ11d2.js +0 -28
- package/canvas/assets/lucide-all-BdEyryfF.js +0 -1
- package/chunk-1bywxgc5.js +0 -4
- package/chunk-1y50g9vp.js +0 -2
- package/chunk-1yhc252b.js +0 -3
- package/chunk-2mv65qxs.js +0 -5
- package/chunk-329e3phg.js +0 -451
- package/chunk-40657ggd.js +0 -10
- package/chunk-582y60bv.js +0 -2
- package/chunk-5x173xay.js +0 -2
- package/chunk-75wbh438.js +0 -2
- package/chunk-7dggmqwq.js +0 -53
- package/chunk-946pcnt5.js +0 -5
- package/chunk-9vg3yafz.js +0 -3
- package/chunk-aapybh30.js +0 -6
- package/chunk-bjnhhsak.js +0 -2
- package/chunk-dt03awr1.js +0 -2
- package/chunk-erwfk47h.js +0 -3
- package/chunk-mq4znqv2.js +0 -2
- package/chunk-nfr3q7mg.js +0 -5
- package/chunk-nsqs1bqf.js +0 -2
- package/chunk-pphgrsxa.js +0 -2
- package/chunk-qpvj6kzq.js +0 -6
- package/chunk-qwv7xkms.js +0 -2
- package/chunk-tmtzxcs5.js +0 -2
- package/chunk-xr6f94rj.js +0 -2
- package/chunk-y0zxzefg.js +0 -5
- package/chunk-zf3xc1wz.js +0 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{
|
|
2
|
+
import{__toESM,__commonJS}from"./chunk-2smsg2ct.js";var require_src=__commonJS(function(exports,module){var cursor={to(x,y){if(!y)return`\x1B[${x+1}G`;return`\x1B[${y+1};${x+1}H`},move(x,y){let ret="";if(x<0)ret+=`\x1B[${-x}D`;else if(x>0)ret+=`\x1B[${x}C`;if(y<0)ret+=`\x1B[${-y}A`;else if(y>0)ret+=`\x1B[${y}B`;return ret},up:(count=1)=>`\x1B[${count}A`,down:(count=1)=>`\x1B[${count}B`,forward:(count=1)=>`\x1B[${count}C`,backward:(count=1)=>`\x1B[${count}D`,nextLine:(count=1)=>"\x1B[E".repeat(count),prevLine:(count=1)=>"\x1B[F".repeat(count),left:"\x1B[G",hide:"\x1B[?25l",show:"\x1B[?25h",save:"\x1B7",restore:"\x1B8"},scroll={up:(count=1)=>"\x1B[S".repeat(count),down:(count=1)=>"\x1B[T".repeat(count)},erase={screen:"\x1B[2J",up:(count=1)=>"\x1B[1J".repeat(count),down:(count=1)=>"\x1B[J".repeat(count),line:"\x1B[2K",lineEnd:"\x1B[K",lineStart:"\x1B[1K",lines(count){let clear="";for(let i=0;i<count;i++)clear+=this.line+(i<count-1?cursor.up():"");if(count)clear+=cursor.left;return clear}};module.exports={cursor,scroll,erase,beep:"\x07"}});import{styleText}from"util";import{stdout,stdin}from"process";import*as l from"readline";import l__default from"readline";var getCodePointsLength=(()=>{let SURROGATE_PAIR_RE=/[\uD800-\uDBFF][\uDC00-\uDFFF]/g;return(input)=>{let surrogatePairsNr=0;SURROGATE_PAIR_RE.lastIndex=0;while(SURROGATE_PAIR_RE.test(input))surrogatePairsNr+=1;return input.length-surrogatePairsNr}})(),isFullWidth=(x)=>x===12288||x>=65281&&x<=65376||x>=65504&&x<=65510,isWideNotCJKTNotEmoji=(x)=>x===8987||x===9001||x>=12272&&x<=12287||x>=12289&&x<=12350||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>=65040&&x<=65049||x>=65072&&x<=65106||x>=65108&&x<=65126||x>=65128&&x<=65131||x>=127488&&x<=127490||x>=127504&&x<=127547||x>=127552&&x<=127560||x>=131072&&x<=196605||x>=196608&&x<=262141;var ANSI_RE=/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y,CONTROL_RE=/[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y,CJKT_WIDE_RE=/(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/yu,TAB_RE=/\t{1,1000}/y,EMOJI_RE=/[\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=/\p{M}+/gu,NO_TRUNCATION={limit:1/0,ellipsis:""},getStringTruncatedWidth=(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=0,CONTROL_WIDTH=widthOptions.controlWidth??0,TAB_WIDTH=widthOptions.tabWidth??8,EMOJI_WIDTH=widthOptions.emojiWidth??2,FULL_WIDTH_WIDTH=2,REGULAR_WIDTH=widthOptions.regularWidth??1,WIDE_WIDTH=widthOptions.wideWidth??2,PARSE_BLOCKS=[[LATIN_RE,REGULAR_WIDTH],[ANSI_RE,0],[CONTROL_RE,CONTROL_WIDTH],[TAB_RE,TAB_WIDTH],[EMOJI_RE,EMOJI_WIDTH],[CJKT_WIDE_RE,WIDE_WIDTH]],indexPrev=0,index=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:while(!0){if(unmatchedEnd>unmatchedStart||index>=length&&index>indexPrev){let unmatched=input.slice(unmatchedStart,unmatchedEnd)||input.slice(indexPrev,index);lengthExtra=0;for(let char of unmatched.replaceAll(MODIFIER_RE,"")){let codePoint=char.codePointAt(0)||0;if(isFullWidth(codePoint))widthExtra=2;else if(isWideNotCJKTNotEmoji(codePoint))widthExtra=WIDE_WIDTH;else widthExtra=REGULAR_WIDTH;if(width+widthExtra>truncationLimit)truncationIndex=Math.min(truncationIndex,Math.max(unmatchedStart,indexPrev)+lengthExtra);if(width+widthExtra>LIMIT){truncationEnabled=!0;break outer}lengthExtra+=char.length,width+=widthExtra}unmatchedStart=unmatchedEnd=0}if(index>=length)break outer;for(let i=0,l=PARSE_BLOCKS.length;i<l;i++){let[BLOCK_RE,BLOCK_WIDTH]=PARSE_BLOCKS[i];if(BLOCK_RE.lastIndex=index,BLOCK_RE.test(input)){if(lengthExtra=BLOCK_RE===CJKT_WIDE_RE?getCodePointsLength(input.slice(index,BLOCK_RE.lastIndex)):BLOCK_RE===EMOJI_RE?1:BLOCK_RE.lastIndex-index,widthExtra=lengthExtra*BLOCK_WIDTH,width+widthExtra>truncationLimit)truncationIndex=Math.min(truncationIndex,index+Math.floor((truncationLimit-width)/BLOCK_WIDTH));if(width+widthExtra>LIMIT){truncationEnabled=!0;break outer}width+=widthExtra,unmatchedStart=indexPrev,unmatchedEnd=index,index=indexPrev=BLOCK_RE.lastIndex;continue outer}}index+=1}return{width:truncationEnabled?truncationLimit:width,index:truncationEnabled?truncationIndex:length,truncated:truncationEnabled,ellipsed:truncationEnabled&&LIMIT>=ELLIPSIS_WIDTH}},dist_default=getStringTruncatedWidth;var NO_TRUNCATION2={limit:1/0,ellipsis:"",ellipsisWidth:0},fastStringWidth=(input,options={})=>dist_default(input,NO_TRUNCATION2,options).width,dist_default2=fastStringWidth;var 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=(openingCode)=>{if(openingCode>=30&&openingCode<=37)return 39;if(openingCode>=90&&openingCode<=97)return 39;if(openingCode>=40&&openingCode<=47)return 49;if(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;return},wrapAnsiCode=(code)=>`${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`,wrapAnsiHyperlink=(url)=>`${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`,wrapWord=(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;while(!currentCharacter.done){let character=currentCharacter.value,characterLength=dist_default2(character);if(visible+characterLength<=columns)rows[rows.length-1]+=character;else rows.push(character),visible=0;if(character===ESC||character===CSI)isInsideEscape=!0,isInsideLinkEscape=word.startsWith(ANSI_ESCAPE_LINK,rawCharacterIndex+1);if(isInsideEscape){if(isInsideLinkEscape){if(character===ANSI_ESCAPE_BELL)isInsideEscape=!1,isInsideLinkEscape=!1}else if(character===ANSI_SGR_TERMINATOR)isInsideEscape=!1}else if(visible+=characterLength,visible===columns&&!nextCharacter.done)rows.push(""),visible=0;currentCharacter=nextCharacter,nextCharacter=characters.next(),rawCharacterIndex+=character.length}if(lastRow=rows.at(-1),!visible&&lastRow!==void 0&&lastRow.length&&rows.length>1)rows[rows.length-2]+=rows.pop()},stringVisibleTrimSpacesRight=(string)=>{let words=string.split(" "),last=words.length;while(last){if(dist_default2(words[last-1]))break;last--}if(last===words.length)return string;return words.slice(0,last).join(" ")+words.slice(last).join("")},exec=(string,columns,options={})=>{if(options.trim!==!1&&string.trim()==="")return"";let returnValue="",escapeCode,escapeUrl,words=string.split(" "),rows=[""],rowLength=0;for(let index=0;index<words.length;index++){let word=words[index];if(options.trim!==!1){let row=rows.at(-1)??"",trimmed=row.trimStart();if(row.length!==trimmed.length)rows[rows.length-1]=trimmed,rowLength=dist_default2(trimmed)}if(index!==0){if(rowLength>=columns&&(options.wordWrap===!1||options.trim===!1))rows.push(""),rowLength=0;if(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);if(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}if(options.trim!==!1)rows=rows.map((row)=>stringVisibleTrimSpacesRight(row));let preString=rows.join(`
|
|
3
3
|
`),inSurrogate=!1;for(let i=0;i<preString.length;i++){let character=preString[i];if(returnValue+=character,!inSurrogate){if(inSurrogate=character>="\uD800"&&character<="\uDBFF",inSurrogate)continue}else inSurrogate=!1;if(character===ESC||character===CSI){GROUP_REGEX.lastIndex=i+1;let groups=GROUP_REGEX.exec(preString)?.groups;if(groups?.code!==void 0){let code=Number.parseFloat(groups.code);escapeCode=code===END_CODE?void 0:code}else if(groups?.uri!==void 0)escapeUrl=groups.uri.length===0?void 0:groups.uri}if(preString[i+1]===`
|
|
4
4
|
`){if(escapeUrl)returnValue+=wrapAnsiHyperlink("");let closingCode=escapeCode?getClosingCode(escapeCode):void 0;if(escapeCode&&closingCode)returnValue+=wrapAnsiCode(closingCode)}else if(character===`
|
|
5
5
|
`){if(escapeCode&&getClosingCode(escapeCode))returnValue+=wrapAnsiCode(escapeCode);if(escapeUrl)returnValue+=wrapAnsiHyperlink(escapeUrl)}}return returnValue},CRLF_OR_LF=/\r?\n/;function wrapAnsi(string,columns,options){return String(string).normalize().split(CRLF_OR_LF).map((line)=>exec(line,columns,options)).join(`
|
|
@@ -82,8 +82,5 @@ ${d}${n}
|
|
|
82
82
|
`}case"submit":{let n=l?` ${styleText2("dim",l)}`:"",r=i?styleText2("gray",S_BAR):"";return`${s}${r}${n}`}case"cancel":{let n=l?` ${styleText2(["strikethrough","dim"],l)}`:"",r=i?styleText2("gray",S_BAR):"";return`${s}${r}${n}${l.trim()?`
|
|
83
83
|
${r}`:""}`}default:{let n=i?`${styleText2("cyan",S_BAR)} `:"",r=i?styleText2("cyan",S_BAR_END):"";return`${s}${n}${o}
|
|
84
84
|
${r}
|
|
85
|
-
`}}}}).prompt();
|
|
86
|
-
|
|
87
|
-
${design.projectName} \u2014 ${design.designRoot} (was for ${design.root})`).join("")}
|
|
88
|
-
Run \`velloo folder bind <design folder>\` from the new checkout.`}async function resolveDesignLocation(arg,cmd,opts={}){let designRoot=await resolveDesignFolder(arg,cmd,opts),local=localDesignOf(designRoot);if(local)return{designRoot,manifestPath:void 0,appRoot:local.appRoot,projectName:local.projectName};let found=await findManifest(opts.cwd??designRoot);return{designRoot,manifestPath:found?.path,appRoot:found?.dir,projectName:[...found?.folders??[]].find(([,path])=>path===designRoot)?.[0]}}async function listScreens(folder){let files;try{files=(await readdir(join2(folder,"screens"))).filter((f)=>f.endsWith(".json"))}catch{return[]}let out=[];for(let f of files.sort()){let path=join2(folder,"screens",f);try{let s=ScreenSchema.parse(JSON.parse(await readFile2(path,"utf8")));out.push({id:s.id,name:s.name||s.id,path})}catch{}}return out}async function listBoards(folder){let files;try{files=(await readdir(join2(folder,"boards"))).filter((f)=>f.endsWith(".json"))}catch{return[]}let out=[];for(let f of files.sort())try{let b=BoardSchema.parse(JSON.parse(await readFile2(join2(folder,"boards",f),"utf8")));out.push({id:b.id,name:b.name||b.id,screens:b.frames.map((fr)=>fr.screen),archived:isArchived(b)})}catch{}return out}function boardsByScreen(boards){let map=new Map;for(let b of boards)for(let sid of b.screens){let names=map.get(sid)??[];names.push(b.name),map.set(sid,names)}return map}async function pickBoards(folder,arg,interactive,cmd){let all=await listBoards(folder);if(all.length===0)return[];if(arg){let ids=new Set(arg.split(",").map((s)=>s.trim()).filter(Boolean)),chosen=all.filter((b)=>ids.has(b.id));if(chosen.length===0)fail(cmd,`no boards matched "${arg}". Available: ${all.map((b)=>b.id).join(", ")}`);return chosen}let boards=all.filter((b)=>!b.archived);if(boards.length===0)return[];if(!interactive)return boards;let chosen=await multiselect(boardSelectionPrompt(boards));if(isCancel(chosen))fail(cmd,"cancelled.");return resolveBoardSelection(boards,chosen)}function boardSelectionPrompt(boards){return{message:"Which boards to publish? (a: select all / clear all)",options:boards.map((board)=>({value:board.id,label:board.name,hint:`${board.screens.length} screen${board.screens.length===1?"":"s"}`})),initialValues:[],required:!1}}function resolveBoardSelection(boards,selectedIds){let selected=new Set(selectedIds),chosen=boards.filter((board)=>selected.has(board.id));return chosen.length>0?chosen:null}async function pickScreen(folder,arg,interactive,cmd){let screens=await listScreens(folder);if(arg){let byId=screens.find((s)=>s.id===arg);if(byId)return byId;return{id:arg,name:arg,path:resolve2(arg)}}if(screens.length===0)fail(cmd,`no screens found in ${folder}/screens.`);if(screens.length===1)return screens[0];if(!interactive)fail(cmd,`pick a screen: ${screens.map((s)=>s.id).join(", ")}`);let onBoard=boardsByScreen(await listBoards(folder)),chosen=await select({message:"Which screen?",options:screens.map((s)=>({value:s.id,label:s.name,hint:onBoard.get(s.id)?.join(", ")??`${s.id}.json`}))});if(isCancel(chosen))fail(cmd,"cancelled.");return screens.find((s)=>s.id===chosen)}
|
|
89
|
-
export{isCancel,confirm,multiselect,log,cancel,note,password,spinner,select,text,findDesignConfig,FOLDER_ARG_DESCRIPTION,existingDesignFolder,isDesignFolderSync,isEmptyOrMissingSync,hasDesignConfig,resolveDesignFolder,resolveDesignLocation,pickBoards,pickScreen};
|
|
85
|
+
`}}}}).prompt();
|
|
86
|
+
export{isCancel,confirm,multiselect,log,cancel,note,password,spinner,select,text};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
async function resolve(value){return typeof value==="function"?await value():await value}async function firstPositional(rawArgs,args){let defs=args?await resolve(args):{},camel=(name)=>name.replace(/-([a-z0-9])/g,(_,c)=>c.toUpperCase()),takesValue=(flag)=>{let name=camel(flag.replace(/^-{1,2}/,""));return Object.entries(defs).some(([key,def])=>{if(def.type!=="string"&&def.type!=="enum")return!1;let aliases="alias"in def&&def.alias!==void 0?[def.alias].flat():[];return camel(key)===name||aliases.includes(name)})};for(let i=0;i<rawArgs.length;i++){let token=rawArgs[i]??"";if(token==="--")return;if(token.startsWith("-")){if(!token.includes("=")&&takesValue(token))i++;continue}return token}return}function withSubcommands(cmd,subCommands){let chosen=null,dispatches=(name)=>name===null||name!==void 0&&Object.hasOwn(subCommands,name);return{...cmd,subCommands:()=>dispatches(chosen)?subCommands:{},async setup(context){if(chosen=await firstPositional(context.rawArgs,cmd.args),!dispatches(chosen))await cmd.setup?.(context)},async run(context){if(!dispatches(chosen))await cmd.run?.(context)}}}
|
|
3
|
+
export{firstPositional,withSubcommands};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import"./chunk-bk8b7f9a.js";import{signInRequired,boardLimitReached,topUpTokens,createServer}from"./chunk-329e3phg.js";import{boardLimitFrom,describeCloudError}from"./chunk-mq4znqv2.js";import"./chunk-w5rzk6ms.js";import{loadCredential,saveCredential,deleteCredential}from"./chunk-b7j86xq7.js";import{listPublishedDesigns,unpublishDesign,listPublishDestinations,describePublishError,PUBLISH_VIEWPORT,gitContext,listTeams,publishDesign}from"./chunk-946pcnt5.js";import{TOOL_VERSION}from"./chunk-65wb0g7d.js";import{updateStatus,upgradeInstalledVelloo}from"./chunk-cep3ktr3.js";import{assertLoopbackHost,daemonRoot,writeLock,removeLock,readRememberedPort,rememberPort,portCandidates,registryUpsert,registryRemove}from"./chunk-k784090q.js";import{fetchAccount,performDeviceLogin}from"./chunk-fgw3hp2v.js";import{defaultCloudUrl,fetchCloudAppUrl}from"./chunk-2z0k59hz.js";import{defineCommand}from"./chunk-2smsg2ct.js";import{existsSync as existsSync2}from"fs";import{existsSync}from"fs";import{dirname,join}from"path";import{fileURLToPath}from"url";var here=dirname(fileURLToPath(import.meta.url));function resolveCanvasDist(){let devLayout=join(here,"..","dist");return[process.env.VELLOO_CANVAS_DIST,join(here,"canvas"),devLayout].filter((p)=>Boolean(p)).find((p)=>existsSync(join(p,"index.html")))??devLayout}var canvasDistPath=resolveCanvasDist();var ACCOUNT_TTL_MS=60000,ACCOUNT_TIMEOUT_MS=5000;function createCanvasAuth(cloudUrl,dependencies={}){let runDeviceLogin=dependencies.performDeviceLogin??performDeviceLogin,login={state:"idle"},pending=null,cached=null,cachedApp=null,describe=async(token,email)=>{if(cached&&cached.token===token&&Date.now()-cached.at<ACCOUNT_TTL_MS)return{account:cached.account,verified:cached.verified};let found=await fetchAccount(cloudUrl,token,ACCOUNT_TIMEOUT_MS),resolved=found.status==="ok"?{account:found.account,verified:!0}:{account:{email},verified:found.status==="rejected"?!1:null};return cached={token,at:Date.now(),...resolved},resolved},resolveAppUrl=async()=>{if(cachedApp&&Date.now()-cachedApp.at<ACCOUNT_TTL_MS)return cachedApp.url;let url=await fetchCloudAppUrl(cloudUrl,ACCOUNT_TIMEOUT_MS);return cachedApp={at:Date.now(),url},url},status=async()=>{let cred=await loadCredential(cloudUrl),appUrlP=resolveAppUrl();if(!cred?.token)return{loggedIn:!1,cloudUrl,appUrl:await appUrlP,verified:null,login};let[{account,verified},appUrl]=await Promise.all([describe(cred.token,cred.email),appUrlP]);return{loggedIn:!0,cloudUrl,appUrl,verified,login,...account?{account}:{}}};return{status,async beginLogin(){if(login.state==="pending")return status();let attempt=new AbortController;pending=attempt,login={state:"idle"};let settle=()=>{},ready=new Promise((resolve)=>{settle=resolve});return runDeviceLogin(cloudUrl,({verificationUrl,userCode,expiresIn})=>{login={state:"pending",userCode,verificationUrl,expiresAt:new Date(Date.now()+expiresIn*1000).toISOString()},settle()},attempt.signal).then(async(result)=>{await saveCredential(cloudUrl,result),cached=null,login={state:"idle"},await topUpTokens({url:cloudUrl,token:result.token},10).catch(()=>{return})}).catch((err)=>{login=attempt.signal.aborted?{state:"idle"}:{state:"error",message:err instanceof Error?err.message:String(err)}}).finally(()=>{if(pending===attempt)pending=null;settle()}),await ready,status()},async cancelLogin(){pending?.abort(),pending=null,login={state:"idle"}},async logout(){pending?.abort(),pending=null,login={state:"idle"},cached=null,await deleteCredential(cloudUrl)}}}function createCanvasPublish(cloudUrl,auth){let tokenFor=async()=>(await loadCredential(cloudUrl))?.token,access=async()=>{if(!await tokenFor())return{state:"signed-out"};return(await auth.status().catch(()=>null))?.verified===!1?{state:"expired"}:{state:"ready"}},rejection=(error)=>error.kind==="LoggedOut"?signInRequired("expired",describeCloudError(error)):Error(describeCloudError(error)),publishedAt=(value)=>{let parsed=value?Date.parse(value):Number.NaN;return Number.isFinite(parsed)?parsed:Number.NEGATIVE_INFINITY};return{access,async teams(){let token=await tokenFor();if(!token)return[];let listed=await listTeams(cloudUrl,token);return listed.ok?listed.value:[]},async published(){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud");let listed=await listPublishedDesigns({baseUrl:cloudUrl,token});if(!listed.ok)throw rejection(listed.error);return listed.value.map((design)=>({slug:design.slug,title:design.title??"",url:design.url,visibility:design.visibility,passwordProtected:design.passwordProtected,canManage:design.canManage,lastPublishedAt:design.lastPublishedAt})).sort((left,right)=>publishedAt(right.lastPublishedAt)-publishedAt(left.lastPublishedAt))},async unpublish(slug){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud");let removed=await unpublishDesign({baseUrl:cloudUrl,token,slug});if(!removed.ok)throw rejection(removed.error)},async destinations(host){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud");let provenance=gitContext(host.folder.root),folderId=host.folder.config.folderId;if(!folderId){let teams=await listTeams(cloudUrl,token);if(!teams.ok)throw rejection(teams.error);return{effectiveTeamId:teams.value.find((team)=>team.isDefault)?.id??null,provenance,slots:[]}}let listed=await listPublishDestinations({baseUrl:cloudUrl,token,folderId});if(!listed.ok)throw rejection(listed.error);return{...listed.value,provenance}},async run(host,request,onProgress,onWarning){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud \u2014 sign in from the account menu first.");let step="start",message="starting",published=await publishDesign({baseUrl:cloudUrl,token},{folder:host.folder,providers:host.providers,defaultProvider:host.defaultProvider,snapshotCss:host.snapshotCss},{boardIds:request.boardIds,...request.title?{title:request.title}:{},visibility:request.visibility,...request.password?{password:request.password}:{},destination:request.destination,...request.teamId?{teamId:request.teamId}:{},provenance:gitContext(host.folder.root),viewport:PUBLISH_VIEWPORT},(event)=>{if(event.kind==="warn"){onWarning(event.message);return}if(event.kind==="note"){onWarning(event.message);return}if(event.kind==="info")return;if(event.kind==="capture"){onProgress({step,message,capture:{done:event.done,total:event.total}});return}step=event.step,message=event.message,onProgress({step,message})});if(!published.ok){let reason=describePublishError(published.error);if(published.error.kind==="LoggedOut")throw signInRequired("expired",reason);let limit=published.error.kind==="HttpFailure"?boardLimitFrom(published.error):null;if(limit)throw boardLimitReached(limit,reason);throw Error(reason)}let outcome=published.value;return{shareUrl:outcome.shareUrl,visibility:outcome.visibility,passwordProtected:outcome.passwordProtected,files:outcome.files,bytes:outcome.bytes,screenshots:outcome.screenshots,boards:outcome.boards,screens:outcome.screens,created:outcome.created,...outcome.tier!==void 0?{tier:outcome.tier}:{},...outcome.history!==void 0?{history:outcome.history}:{}}}}}function createCanvasUpdates(){return{async status(opts={}){let status=await updateStatus(opts);return{current:status.current,latest:status.latest,available:status.available,method:status.method,channel:status.channel,upgradable:status.upgradable,...status.reason===void 0?{}:{reason:status.reason}}},async upgrade(){let outcome=await upgradeInstalledVelloo();return{upgraded:outcome.upgraded,from:outcome.from,to:outcome.to,restartRequired:outcome.upgraded}}}}var IDLE_MS=300000;function portFree(port,host){try{return Bun.serve({port,hostname:host,fetch:()=>new Response("")}).stop(!0),!0}catch{return!1}}var daemon_default=defineCommand({meta:{name:"__daemon",hidden:!0,description:"(internal) Run the persistent canvas daemon. Spawned by `velloo run` / `velloo mcp`."},args:{folder:{type:"positional",required:!0,description:"Design folder (absolute)"},port:{type:"string",description:"Preferred canvas port"},host:{type:"string",description:"Bind hostname (default 127.0.0.1)"}},async run({args}){let root=daemonRoot(args.folder),host=args.host??"127.0.0.1";assertLoopbackHost(host);let cloudUrl=defaultCloudUrl(),cred=await loadCredential(cloudUrl),cloud={url:cloudUrl,token:cred?.token,resolveToken:async()=>(await loadCredential(cloudUrl))?.token},auth=createCanvasAuth(cloudUrl),publish=createCanvasPublish(cloudUrl,auth),updates=createCanvasUpdates(),canvasPort=portCandidates({explicit:args.port?Number(args.port):void 0,remembered:await readRememberedPort(root),root}).find((port)=>portFree(port,host))??0,handle;try{handle=await createServer({folder:root,port:canvasPort,host,mcp:{transport:"http",port:0},canvasDist:canvasDistPath,cloud,auth,publish,updates})}catch(err){if(canvasPort===0)throw err;handle=await createServer({folder:root,port:0,host,mcp:{transport:"http",port:0},canvasDist:canvasDistPath,cloud,auth,publish,updates})}let rec={root,pid:process.pid,canvasUrl:handle.url,canvasPort:handle.port,mcpUrl:handle.mcpUrl??"",mcpPort:handle.mcpPort??0,cloudUrl,version:TOOL_VERSION,startedAt:new Date().toISOString()};await writeLock(rec),await registryUpsert(rec),await rememberPort(root,handle.port).catch(()=>{return}),console.error(`velloo: canvas daemon up at ${handle.url} (mcp ${handle.mcpUrl}), pid ${process.pid}`);let stopped=!1,shutdown=async()=>{if(stopped)return;stopped=!0,removeLock(root),await registryRemove(root).catch(()=>{return}),await handle.close(),process.exit(0)};process.on("SIGTERM",shutdown),process.on("SIGINT",shutdown);let rootMissing=0;setInterval(()=>{if(existsSync2(root)){rootMissing=0;return}if(rootMissing+=1,rootMissing>=2)console.error(`velloo: design folder ${root} is gone \u2014 shutting down.`),shutdown()},1e4);let idleSince=Date.now();setInterval(()=>{let{canvas,mcp}=handle.connections();if(canvas+mcp>0){idleSince=null;return}if(idleSince===null){idleSince=Date.now();return}if(Date.now()-idleSince>=IDLE_MS)console.error("velloo: canvas idle for 5 min \u2014 shutting down."),shutdown()},30000),await new Promise(()=>{})}});export{daemon_default as default};
|
|
2
|
+
import"./chunk-nte0t7v3.js";import{signInRequired,boardLimitReached,topUpTokens,createServer}from"./chunk-5ezzc1h2.js";import{boardLimitFrom,describeCloudError}from"./chunk-n9t36h0q.js";import"./chunk-c4fym47a.js";import{loadCredential,saveCredential,deleteCredential}from"./chunk-hfzg98c8.js";import{listPublishedDesigns,unpublishDesign,listPublishDestinations,describePublishError,PUBLISH_VIEWPORT,gitContext,listTeams,publishDesign}from"./chunk-6nzqhfqq.js";import{TOOL_VERSION}from"./chunk-kz4423th.js";import{updateStatus,upgradeInstalledVelloo}from"./chunk-7k7dpj5y.js";import{assertLoopbackHost,daemonRoot,writeLock,removeLock,readRememberedPort,rememberPort,portCandidates,registryUpsert,registryRemove}from"./chunk-k9219kmj.js";import{fetchAccount,performDeviceLogin}from"./chunk-6zz9kfbd.js";import{defaultCloudUrl,fetchCloudAppUrl}from"./chunk-as08hzp3.js";import{defineCommand}from"./chunk-2smsg2ct.js";import{existsSync as existsSync2}from"fs";import{existsSync}from"fs";import{dirname,join}from"path";import{fileURLToPath}from"url";var here=dirname(fileURLToPath(import.meta.url));function resolveCanvasDist(){let devLayout=join(here,"..","dist");return[process.env.VELLOO_CANVAS_DIST,join(here,"canvas"),devLayout].filter((p)=>Boolean(p)).find((p)=>existsSync(join(p,"index.html")))??devLayout}var canvasDistPath=resolveCanvasDist();var ACCOUNT_TTL_MS=60000,ACCOUNT_TIMEOUT_MS=5000;function createCanvasAuth(cloudUrl,dependencies={}){let runDeviceLogin=dependencies.performDeviceLogin??performDeviceLogin,login={state:"idle"},pending=null,cached=null,cachedApp=null,describe=async(token,email)=>{if(cached&&cached.token===token&&Date.now()-cached.at<ACCOUNT_TTL_MS)return{account:cached.account,verified:cached.verified};let found=await fetchAccount(cloudUrl,token,ACCOUNT_TIMEOUT_MS),resolved=found.status==="ok"?{account:found.account,verified:!0}:{account:{email},verified:found.status==="rejected"?!1:null};return cached={token,at:Date.now(),...resolved},resolved},resolveAppUrl=async()=>{if(cachedApp&&Date.now()-cachedApp.at<ACCOUNT_TTL_MS)return cachedApp.url;let url=await fetchCloudAppUrl(cloudUrl,ACCOUNT_TIMEOUT_MS);return cachedApp={at:Date.now(),url},url},status=async()=>{let cred=await loadCredential(cloudUrl),appUrlP=resolveAppUrl();if(!cred?.token)return{loggedIn:!1,cloudUrl,appUrl:await appUrlP,verified:null,login};let[{account,verified},appUrl]=await Promise.all([describe(cred.token,cred.email),appUrlP]);return{loggedIn:!0,cloudUrl,appUrl,verified,login,...account?{account}:{}}};return{status,async beginLogin(){if(login.state==="pending")return status();let attempt=new AbortController;pending=attempt,login={state:"idle"};let settle=()=>{},ready=new Promise((resolve)=>{settle=resolve});return runDeviceLogin(cloudUrl,({verificationUrl,userCode,expiresIn})=>{login={state:"pending",userCode,verificationUrl,expiresAt:new Date(Date.now()+expiresIn*1000).toISOString()},settle()},attempt.signal).then(async(result)=>{await saveCredential(cloudUrl,result),cached=null,login={state:"idle"},await topUpTokens({url:cloudUrl,token:result.token},10).catch(()=>{return})}).catch((err)=>{login=attempt.signal.aborted?{state:"idle"}:{state:"error",message:err instanceof Error?err.message:String(err)}}).finally(()=>{if(pending===attempt)pending=null;settle()}),await ready,status()},async cancelLogin(){pending?.abort(),pending=null,login={state:"idle"}},async logout(){pending?.abort(),pending=null,login={state:"idle"},cached=null,await deleteCredential(cloudUrl)}}}function createCanvasPublish(cloudUrl,auth){let tokenFor=async()=>(await loadCredential(cloudUrl))?.token,access=async()=>{if(!await tokenFor())return{state:"signed-out"};return(await auth.status().catch(()=>null))?.verified===!1?{state:"expired"}:{state:"ready"}},rejection=(error)=>error.kind==="LoggedOut"?signInRequired("expired",describeCloudError(error)):Error(describeCloudError(error)),publishedAt=(value)=>{let parsed=value?Date.parse(value):Number.NaN;return Number.isFinite(parsed)?parsed:Number.NEGATIVE_INFINITY};return{access,async teams(){let token=await tokenFor();if(!token)return[];let listed=await listTeams(cloudUrl,token);return listed.ok?listed.value:[]},async published(){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud");let listed=await listPublishedDesigns({baseUrl:cloudUrl,token});if(!listed.ok)throw rejection(listed.error);return listed.value.map((design)=>({slug:design.slug,title:design.title??"",url:design.url,visibility:design.visibility,passwordProtected:design.passwordProtected,canManage:design.canManage,lastPublishedAt:design.lastPublishedAt})).sort((left,right)=>publishedAt(right.lastPublishedAt)-publishedAt(left.lastPublishedAt))},async unpublish(slug){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud");let removed=await unpublishDesign({baseUrl:cloudUrl,token,slug});if(!removed.ok)throw rejection(removed.error)},async destinations(host){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud");let provenance=gitContext(host.folder.root),folderId=host.folder.config.folderId;if(!folderId){let teams=await listTeams(cloudUrl,token);if(!teams.ok)throw rejection(teams.error);return{effectiveTeamId:teams.value.find((team)=>team.isDefault)?.id??null,provenance,slots:[]}}let listed=await listPublishDestinations({baseUrl:cloudUrl,token,folderId});if(!listed.ok)throw rejection(listed.error);return{...listed.value,provenance}},async run(host,request,onProgress,onWarning){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud \u2014 sign in from the account menu first.");let step="start",message="starting",published=await publishDesign({baseUrl:cloudUrl,token},{folder:host.folder,providers:host.providers,defaultProvider:host.defaultProvider,snapshotCss:host.snapshotCss},{boardIds:request.boardIds,...request.title?{title:request.title}:{},visibility:request.visibility,...request.password?{password:request.password}:{},destination:request.destination,...request.teamId?{teamId:request.teamId}:{},provenance:gitContext(host.folder.root),viewport:PUBLISH_VIEWPORT},(event)=>{if(event.kind==="warn"){onWarning(event.message);return}if(event.kind==="note"){onWarning(event.message);return}if(event.kind==="info")return;if(event.kind==="capture"){onProgress({step,message,capture:{done:event.done,total:event.total}});return}step=event.step,message=event.message,onProgress({step,message})});if(!published.ok){let reason=describePublishError(published.error);if(published.error.kind==="LoggedOut")throw signInRequired("expired",reason);let limit=published.error.kind==="HttpFailure"?boardLimitFrom(published.error):null;if(limit)throw boardLimitReached(limit,reason);throw Error(reason)}let outcome=published.value;return{shareUrl:outcome.shareUrl,visibility:outcome.visibility,passwordProtected:outcome.passwordProtected,files:outcome.files,bytes:outcome.bytes,screenshots:outcome.screenshots,boards:outcome.boards,screens:outcome.screens,created:outcome.created,...outcome.tier!==void 0?{tier:outcome.tier}:{},...outcome.history!==void 0?{history:outcome.history}:{}}}}}function createCanvasUpdates(){return{async status(opts={}){let status=await updateStatus(opts);return{current:status.current,latest:status.latest,available:status.available,method:status.method,channel:status.channel,upgradable:status.upgradable,...status.reason===void 0?{}:{reason:status.reason}}},async upgrade(){let outcome=await upgradeInstalledVelloo();return{upgraded:outcome.upgraded,from:outcome.from,to:outcome.to,restartRequired:outcome.upgraded}}}}var IDLE_MS=300000;function portFree(port,host){try{return Bun.serve({port,hostname:host,fetch:()=>new Response("")}).stop(!0),!0}catch{return!1}}var daemon_default=defineCommand({meta:{name:"__daemon",hidden:!0,description:"(internal) Run the persistent canvas daemon. Spawned by `velloo run` / `velloo mcp`."},args:{folder:{type:"positional",required:!0,description:"Design folder (absolute)"},port:{type:"string",description:"Preferred canvas port"},host:{type:"string",description:"Bind hostname (default 127.0.0.1)"}},async run({args}){let root=daemonRoot(args.folder),host=args.host??"127.0.0.1";assertLoopbackHost(host);let cloudUrl=defaultCloudUrl(),cred=await loadCredential(cloudUrl),cloud={url:cloudUrl,token:cred?.token,resolveToken:async()=>(await loadCredential(cloudUrl))?.token},auth=createCanvasAuth(cloudUrl),publish=createCanvasPublish(cloudUrl,auth),updates=createCanvasUpdates(),canvasPort=portCandidates({explicit:args.port?Number(args.port):void 0,remembered:await readRememberedPort(root),root}).find((port)=>portFree(port,host))??0,handle;try{handle=await createServer({folder:root,port:canvasPort,host,mcp:{transport:"http",port:0},canvasDist:canvasDistPath,cloud,auth,publish,updates})}catch(err){if(canvasPort===0)throw err;handle=await createServer({folder:root,port:0,host,mcp:{transport:"http",port:0},canvasDist:canvasDistPath,cloud,auth,publish,updates})}let rec={root,pid:process.pid,canvasUrl:handle.url,canvasPort:handle.port,mcpUrl:handle.mcpUrl??"",mcpPort:handle.mcpPort??0,cloudUrl,version:TOOL_VERSION,startedAt:new Date().toISOString()};await writeLock(rec),await registryUpsert(rec),await rememberPort(root,handle.port).catch(()=>{return}),console.error(`velloo: canvas daemon up at ${handle.url} (mcp ${handle.mcpUrl}), pid ${process.pid}`);let stopped=!1,shutdown=async()=>{if(stopped)return;stopped=!0,removeLock(root),await registryRemove(root).catch(()=>{return}),await handle.close(),process.exit(0)};process.on("SIGTERM",shutdown),process.on("SIGINT",shutdown);let rootMissing=0;setInterval(()=>{if(existsSync2(root)){rootMissing=0;return}if(rootMissing+=1,rootMissing>=2)console.error(`velloo: design folder ${root} is gone \u2014 shutting down.`),shutdown()},1e4);let idleSince=Date.now();setInterval(()=>{let{canvas,mcp}=handle.connections();if(canvas+mcp>0){idleSince=null;return}if(idleSince===null){idleSince=Date.now();return}if(Date.now()-idleSince>=IDLE_MS)console.error("velloo: canvas idle for 5 min \u2014 shutting down."),shutdown()},30000),await new Promise(()=>{})}});export{daemon_default as default};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{isCancel,select}from"./chunk-80fjfyha.js";import{closePooledBrowser}from"./chunk-c4fym47a.js";import"./chunk-nte0t7v3.js";import{writeText,findFrame,exportFilename,exportFramePng,exportBoardPng,exportFramePdf,exportBoardPdf,exportScreenHtml,exportScreenPng,exportScreenPdf,exportFrameHtml,exportBoardHtml,screensForExportTarget}from"./chunk-5ezzc1h2.js";import"./chunk-n9t36h0q.js";import{fail}from"./chunk-s23gtejf.js";import{captureWithBrowserSetup}from"./chunk-2fgfex9b.js";import{confirmRenderFailures}from"./chunk-m3czg1tt.js";import{loadPipeline}from"./chunk-nycs0z7h.js";import{withAssetServer}from"./chunk-0zen7bzb.js";import{DESIGN_ARG_DESCRIPTION,resolveDesign}from"./chunk-td5z2sm4.js";import{defineCommand}from"./chunk-2smsg2ct.js";import{extname,isAbsolute,resolve}from"path";var export_default=defineCommand({meta:{name:"export",description:"Export a screen, frame, or board as PNG, PDF, or standalone HTML (format = --to extension)"},args:{target:{type:"positional",required:!1,description:"Screen, frame, or board id. Omit to pick interactively."},design:{type:"string",description:DESIGN_ARG_DESCRIPTION},to:{type:"string",description:"Output path; extension picks the format (.png | .pdf | .html). Default: ./<target>.png"},mode:{type:"string",description:"light (default) | dark | compare (side-by-side light|dark; PNG, non-board only)"},scale:{type:"string",description:"PNG raster density (0.25\u20133; default 1; 2 = retina)"},theme:{type:"string",description:"Named theme to render with (default: the board's pin, else the folder default)"},w:{type:"string",description:"Viewport width for screen targets (default: first preset)"},h:{type:"string",description:"Viewport height for screen targets (default: first preset)"},yes:{type:"boolean",description:"Export even when a component fails to render (required without an interactive terminal)"}},async run({args}){let folder=await resolveDesign(args.design,"export",{designFlag:"--design"}),pipeline=await loadPipeline(folder),design=pipeline.design,mode=args.mode??"light";if(!["light","dark","compare"].includes(mode))fail("export",`--mode must be light, dark, or compare \u2014 got '${args.mode}'`);let scale=args.scale?Number(args.scale):1;if(!Number.isFinite(scale)||scale<0.25||scale>3)fail("export",`--scale must be between 0.25 and 3 \u2014 got '${args.scale}'`);let targetId=args.target;if(!targetId){let options=[...[...design.boards.values()].map((b)=>({value:b.id,label:b.name,hint:`board \xB7 ${b.frames.length} frame${b.frames.length===1?"":"s"}`})),...[...design.screens.values()].map((s)=>({value:s.id,label:s.name||s.id,hint:"screen"}))];if(options.length===0)fail("export",`nothing to export in ${folder}.`);if(!process.stdin.isTTY)fail("export",`pass a target: ${options.map((o)=>o.value).join(", ")} (boards and screens; frame ids work too)`);let chosen=await select({message:"Export what?",options});if(isCancel(chosen))fail("export","cancelled.");targetId=chosen}let screen=design.screens.get(targetId),framed=screen?null:findFrame(design,targetId),board=screen||framed?null:design.boards.get(targetId),kind=screen?"screen":framed?"frame":board?"board":null;if(!kind)fail("export",`no screen, frame, or board with id "${targetId}" in ${folder}. Boards: ${[...design.boards.keys()].join(", ")||"(none)"}; screens: ${[...design.screens.keys()].join(", ")||"(none)"}.`);let name=screen?.name||framed?.frame.label||(framed?design.screens.get(framed.frame.screen)?.name:void 0)||board?.name||targetId,outPath=args.to?isAbsolute(args.to)?args.to:resolve(args.to):resolve(exportFilename(name,"png")),ext=extname(outPath).toLowerCase().slice(1);if(ext!=="png"&&ext!=="pdf"&&ext!=="html")fail("export",`unsupported output extension ".${ext}" \u2014 use .png, .pdf, or .html.`);let format=ext;if(mode==="compare"&&(format!=="png"||kind==="board"))fail("export",'mode "compare" is PNG-only and not available for boards.');let preset=design.config.viewportPresets[0]??{name:"default",w:1440,h:900},viewport={w:args.w?Number(args.w):preset.w,h:args.h?Number(args.h):preset.h};await confirmRenderFailures("export",{folder:design,providers:pipeline.providers,defaultProvider:pipeline.defaultProvider},screensForExportTarget(design,kind,targetId),args.yes===!0);let opts={mode,scale,...args.theme?{theme:args.theme}:{}},assetOrigin,p={folder:design,providers:pipeline.providers,defaultProvider:pipeline.defaultProvider,snapshotCss:async()=>pipeline.snapshotCss,assetOrigin:()=>assetOrigin},produce=async()=>{if(kind==="screen"&&screen){if(format==="html"){let out=await exportScreenHtml(p,screen,{dark:mode==="dark",...args.theme?{theme:args.theme}:{},viewport});return{bytes:out.html,warnings:out.warnings}}if(format==="pdf")return{bytes:await exportScreenPdf(p,screen,{...opts,viewport}),warnings:[]};return{bytes:await exportScreenPng(p,screen,{...opts,viewport}),warnings:[]}}if(kind==="frame"&&framed){if(format==="html"){let out=await exportFrameHtml(p,framed.board,framed.frame,opts);return{bytes:out.html,warnings:out.warnings}}return{bytes:format==="pdf"?await exportFramePdf(p,framed.board,framed.frame,opts):await exportFramePng(p,framed.board,framed.frame,opts),warnings:[]}}if(!board)fail("export","internal: target resolution failed");if(format==="html"){let out=await exportBoardHtml(p,board,opts);return{bytes:out.html,warnings:out.warnings}}return{bytes:format==="pdf"?await exportBoardPdf(p,board,opts):await exportBoardPng(p,board,opts),warnings:[]}},result;try{if(format==="html")result=await produce();else await withAssetServer(folder,null,async(baseHref)=>{assetOrigin=baseHref,await captureWithBrowserSetup("export",async()=>{result=await produce()})})}finally{await closePooledBrowser()}if(!result)fail("export","capture produced no output");if(typeof result.bytes==="string")await writeText(outPath,result.bytes);else await Bun.write(outPath,result.bytes);console.log(`velloo export: wrote ${outPath} (${kind}=${targetId}, mode=${mode})`);for(let warning of result.warnings)console.log(` note: ${warning}`)}});export{export_default as default};
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{localDesignOf}from"./chunk-
|
|
2
|
+
import{localDesignOf}from"./chunk-5ezzc1h2.js";import{TOOL_VERSION}from"./chunk-kz4423th.js";import{isCancel,multiselect,log,select}from"./chunk-80fjfyha.js";import{manifestListing,findDesigns}from"./chunk-td5z2sm4.js";import{require_picocolors}from"./chunk-jrsknzjt.js";import{__toESM}from"./chunk-2smsg2ct.js";import{existsSync}from"fs";import{homedir}from"os";import{dirname,join}from"path";var claudeEntry=(conn)=>conn.transport==="http"?{type:"http",url:conn.url}:{command:conn.command,args:conn.args},cursorEntry=(conn)=>conn.transport==="http"?{url:conn.url}:{command:conn.command,args:conn.args},codexEntry=cursorEntry,continueEntry=(conn)=>conn.transport==="http"?{name:"velloo",type:"streamable-http",url:conn.url}:{name:"velloo",type:"stdio",command:conn.command,args:conn.args},droidEntry=(conn)=>conn.transport==="http"?{type:"http",url:conn.url}:{type:"stdio",command:conn.command,args:conn.args,disabled:!1},geminiEntry=(conn)=>conn.transport==="http"?{httpUrl:conn.url}:{command:conn.command,args:conn.args},opencodeEntry=(conn)=>conn.transport==="http"?{type:"remote",url:conn.url,enabled:!0}:{type:"local",command:[conn.command,...conn.args],enabled:!0},vscodeEntry=(conn)=>conn.transport==="http"?{type:"http",url:conn.url}:{type:"stdio",command:conn.command,args:conn.args};function claudeDesktopConfigPath(homeDir){if(process.platform==="win32")return join(homeDir,"AppData","Roaming","Claude","claude_desktop_config.json");if(process.platform==="darwin")return join(homeDir,"Library","Application Support","Claude","claude_desktop_config.json");return join(homeDir,".config","Claude","claude_desktop_config.json")}var AGENTS={"claude-code":{id:"claude-code",label:"Claude Code (project)",scope:"project",format:"json",family:"claude-code",path:(root)=>join(root,".mcp.json"),entry:claudeEntry},cursor:{id:"cursor",label:"Cursor (project)",scope:"project",format:"json",family:"cursor",path:(root)=>join(root,".cursor","mcp.json"),entry:cursorEntry},codex:{id:"codex",label:"Codex CLI (project)",scope:"project",format:"codex-toml",path:(root)=>join(root,".codex","config.toml"),entry:codexEntry},continue:{id:"continue",label:"Continue (project)",scope:"project",format:"continue-block",path:(root)=>join(root,".continue","mcpServers","velloo.yaml"),entry:continueEntry},"claude-code-global":{id:"claude-code-global",label:"Claude Code (global)",scope:"global",format:"json",family:"claude-code",path:(_root,home)=>join(home,".claude.json"),entry:claudeEntry},"cursor-global":{id:"cursor-global",label:"Cursor (global)",scope:"global",format:"json",family:"cursor",path:(_root,home)=>join(home,".cursor","mcp.json"),entry:cursorEntry},"codex-global":{id:"codex-global",label:"Codex CLI (global)",scope:"global",format:"codex-toml",path:(_root,home)=>join(home,".codex","config.toml"),entry:codexEntry},"continue-global":{id:"continue-global",label:"Continue (global)",scope:"global",format:"continue-config",path:(_root,home)=>join(home,".continue","config.yaml"),entry:continueEntry},"claude-desktop":{id:"claude-desktop",label:"Claude Desktop",scope:"global",format:"json",gui:!0,path:(_root,home)=>claudeDesktopConfigPath(home),entry:claudeEntry},opencode:{id:"opencode",label:"opencode (project)",scope:"project",format:"opencode-json",path:(root)=>join(root,"opencode.json"),entry:opencodeEntry},"opencode-global":{id:"opencode-global",label:"opencode (global)",scope:"global",format:"opencode-json",path:(_root,home)=>join(home,".config","opencode","opencode.json"),entry:opencodeEntry},"droid-global":{id:"droid-global",label:"Droid (global)",scope:"global",format:"json",path:(_root,home)=>join(home,".factory","mcp.json"),entry:droidEntry},"cline-global":{id:"cline-global",label:"Cline (global)",scope:"global",format:"json",path:(_root,home)=>join(home,".cline","data","settings","cline_mcp_settings.json"),entry:cursorEntry},gemini:{id:"gemini",label:"Gemini CLI (project)",scope:"project",format:"json",path:(root)=>join(root,".gemini","settings.json"),entry:geminiEntry},"gemini-global":{id:"gemini-global",label:"Gemini CLI (global)",scope:"global",format:"json",path:(_root,home)=>join(home,".gemini","settings.json"),entry:geminiEntry},"windsurf-global":{id:"windsurf-global",label:"Windsurf (global)",scope:"global",format:"json",path:(_root,home)=>join(home,".codeium","windsurf","mcp_config.json"),entry:cursorEntry},vscode:{id:"vscode",label:"VS Code / Copilot (project)",scope:"project",format:"vscode-json",path:(root)=>join(root,".vscode","mcp.json"),entry:vscodeEntry}},AGENT_IDS=Object.keys(AGENTS),PROJECT_AGENT_IDS=["claude-code","cursor"],GLOBAL_AGENT_IDS=["claude-code-global","cursor-global"];function detectInstalledAgents(homeDir=homedir()){let has=(rel)=>existsSync(join(homeDir,rel)),found=[];if(Bun.which("claude")||has(".claude.json")||has(".claude"))found.push("claude-code-global");if(Bun.which("cursor-agent")||Bun.which("cursor")||has(".cursor"))found.push("cursor-global");if(Bun.which("codex")||has(".codex"))found.push("codex-global");if(has(".continue"))found.push("continue-global");if(existsSync(dirname(claudeDesktopConfigPath(homeDir))))found.push("claude-desktop");if(Bun.which("opencode")||has(join(".config","opencode")))found.push("opencode-global");if(Bun.which("droid")||has(".factory"))found.push("droid-global");if(Bun.which("cline")||has(".cline"))found.push("cline-global");if(Bun.which("gemini")||has(join(".gemini","settings.json")))found.push("gemini-global");if(has(join(".codeium","windsurf")))found.push("windsurf-global");return found}import{existsSync as existsSync2,realpathSync}from"fs";import{access}from"fs/promises";import{dirname as dirname2,join as join2,parse,relative,resolve,sep}from"path";async function resolveProjectRoot(designFolder,override){if(override)return override;let local=localDesignOf(designFolder);if(local)return local.root;let registered=await registeringManifest(designFolder);if(registered)return registered.dir;return nearestPackageRoot(designFolder)}async function designArgumentFor(projectRoot,designFolder){let set=await findDesigns(projectRoot).catch(()=>null),target=realOr(designFolder);if(set?.designs.some((d)=>!d.outsideRepo&&realOr(d.root)===target))return null;return relative(projectRoot,designFolder).split(sep).join("/")||"."}function realOr(path){return existsSync2(path)?realpathSync(path):resolve(path)}async function agentRootCandidates(designFolder){if(localDesignOf(designFolder))return[];let roots=[await resolveProjectRoot(designFolder)];return roots.push(await nearestPackageRoot(designFolder)),[...new Set(roots)]}async function registeringManifest(designFolder){let abs=resolve(designFolder),found;try{found=await manifestListing(abs)}catch{return null}if(!found)return null;let real=existsSync2(abs)?realpathSync(abs):abs;return found.folders.some((folder)=>folder===abs||existsSync2(folder)&&realpathSync(folder)===real)?found:null}async function nearestPackageRoot(designFolder){let fallback=dirname2(designFolder),dir=fallback,fsRoot=parse(dir).root;for(let i=0;i<8;i++){try{return await access(join2(dir,"package.json")),dir}catch{}if(dir===fsRoot)break;dir=dirname2(dir)}return fallback}import{existsSync as existsSync5}from"fs";import{homedir as homedir3}from"os";import{join as join6}from"path";import{mkdir,writeFile}from"fs/promises";import{dirname as dirname3,join as join3}from"path";async function installCursorRules(projectRoot,designFolder){let pinned=await designArgumentFor(projectRoot,designFolder),arg=pinned?` ${pinned}`:"",body=`---
|
|
3
3
|
description: Drive UI design through the Velloo MCP server (a local design canvas backed by this project's shadcn components).
|
|
4
4
|
alwaysApply: false
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Velloo design
|
|
8
8
|
|
|
9
|
-
Velloo is a local, code-shaped design canvas exposed over MCP. The design folder
|
|
10
|
-
for this project is \`${designRel}\`.
|
|
9
|
+
Velloo is a local, code-shaped design canvas exposed over MCP. ${pinned?`The design folder for this project is \`${pinned}\`.`:"`velloo design list` shows this project's designs; the MCP server's instructions say which one a session is on."}
|
|
11
10
|
|
|
12
11
|
- Cursor starts the velloo MCP server itself (wired as \`velloo mcp\`), so the
|
|
13
12
|
tools are available once the MCP config is loaded \u2014 nothing to start first. If
|
|
14
|
-
they're missing, ask the user to run \`velloo connect
|
|
15
|
-
restart Cursor. To watch the canvas, the user runs \`velloo run
|
|
13
|
+
they're missing, ask the user to run \`velloo connect${arg}\` and
|
|
14
|
+
restart Cursor. To watch the canvas, the user runs \`velloo run${arg}\`
|
|
16
15
|
(stays in the foreground; \`b\` background, \`s\` stop, \`o\` open). If you start
|
|
17
16
|
it yourself, pass \`--background\` so you aren't stuck in that session. It
|
|
18
17
|
prints the canvas URL (defaults to \`:7300\`, or a free port if that's taken,
|
|
@@ -36,6 +35,6 @@ for this project is \`${designRel}\`.
|
|
|
36
35
|
`)}
|
|
37
36
|
`;return Bun.TOML.parse(content),content}function toYaml(value){let yaml=Bun.YAML.stringify(value,null,2).replace(/[ \t]+$/gm,"");return yaml.endsWith(`
|
|
38
37
|
`)?yaml:`${yaml}
|
|
39
|
-
`}function continueBlockFile(entry){let version=TOOL_VERSION.split(" ")[0]??"0.0.0";return toYaml({name:"velloo",version,schema:"v1",mcpServers:[entry]})}function mergeContinueConfig(existing,entry,path){let doc={name:"Local Assistant",version:"1.0.0",schema:"v1"};if(existing!==null&&existing.trim()!==""){let parsed;try{parsed=Bun.YAML.parse(existing)}catch(err){throw invalidConfig(path,"YAML",err)}if(parsed===null||typeof parsed!=="object"||Array.isArray(parsed))throw invalidConfig(path,"YAML",Error("expected a top-level mapping"));doc=parsed}let others=(Array.isArray(doc.mcpServers)?doc.mcpServers:[]).filter((s)=>!(s!==null&&typeof s==="object"&&s.name==="velloo"));return toYaml({...doc,mcpServers:[...others,entry]})}var
|
|
40
|
-
`)}function baseLabel(id){return(AGENTS[id]?.label??id).replace(/\s*\((?:project|global)\)$/,"")}function projectVariantOf(id){let agent=AGENTS[id];if(!agent)return;if(agent.scope==="project")return id;let candidate=id.replace(/-global$/,"");return candidate!==id&&AGENTS[candidate]?candidate:void 0}async function askAgentWiring(opts){let preWired=await globallyWiredAgents(),projectWired=opts?.projectRoot&&!opts.globalOnly?await projectWiredAgents(opts.projectRoot):[],detected=detectInstalledAgents(),fallback=detected.length===0,wanted=fallback?GLOBAL_AGENT_IDS:detected,missing=wanted.filter((id)=>!preWired.includes(id));if(projectWired.length>0)log.info(`Already wired for this project: ${projectWired.map(baseLabel).join(", ")} ${import_picocolors.default.dim("(re-wiring is a no-op merge)")}`);if(preWired.length>0){let labels=preWired.map(baseLabel).join(", ");if(opts?.skipWhenCovered&&missing.length===0)return log.success(`velloo is already wired globally \u2014 ${labels} ${import_picocolors.default.dim("(covers this project; skipping agent setup)")}`),{agents:[],manual:!1,preWired};log.info(`Already wired globally: ${labels} ${import_picocolors.default.dim("(covers this project)")}`)}log.info(fallback?`No coding agents detected on this machine \u2014 offering the defaults (${wanted.map(baseLabel).join(", ")}).`:`Coding agents detected: ${detected.map(baseLabel).join(", ")}`);let targets=missing.length>0?missing:wanted,names=targets.map(baseLabel).join(", "),projectTargets=opts?.globalOnly?[]:targets.map(projectVariantOf).filter((id)=>Boolean(id));if(opts?.globalOnly)log.info(import_picocolors.default.dim("This design lives outside the repository, so only global agent configs are offered \u2014 nothing is written into the checkout."));let mode=await select({message:"Wire the velloo MCP into your coding agents?",options:[{value:"global",label:`Install globally \u2014 ${names}`,hint:"recommended \u2014 one config covers every project"},...projectTargets.length>0?[{value:"project",label:"Install for this project only",hint:projectTargets.map(baseLabel).join(", ")}]:[],{value:"choose",label:"Let me pick agents",hint:"the full list"},{value:"manual",label:"Manual MCP setup instructions",hint:"prints the config to paste into any agent"},{value:"skip",label:"Don't install now",hint:"wire later with `velloo connect`"}],initialValue:"global"});if(isCancel(mode))return null;if(mode==="skip")return{agents:[],manual:!1,preWired};if(mode==="manual")return{agents:[],manual:!0,preWired};if(mode==="global")return{agents:targets,manual:!1,preWired};if(mode==="project")return{agents:projectTargets,manual:!1,preWired};let picked=await pickAgents({exclude:[...opts?.skipWhenCovered?preWired:[],...opts?.globalOnly?Object.values(AGENTS).filter((agent)=>agent.scope==="project").map((agent)=>agent.id):[]],initial:[...new Set([...targets,...preWired,...projectWired])],wired:[...new Set([...preWired,...projectWired])]});if(picked===null)return null;return{agents:picked.filter((id)=>id!==MANUAL_AGENT_ID),manual:picked.includes(MANUAL_AGENT_ID),preWired}}async function pickAgents(opts){let exclude=new Set(opts?.exclude??[]),wired=new Set(opts?.wired??[]),agents=Object.values(AGENTS).filter((a)=>!exclude.has(a.id)).sort((a,b)=>a.scope===b.scope?0:a.scope==="global"?-1:1),detected=detectInstalledAgents(),initial=(opts?.initial??(detected.length>0?detected:GLOBAL_AGENT_IDS)).filter((id)=>!exclude.has(id)),picked=await multiselect({message:"Wire the velloo MCP into which agents?",options:[...agents.map((a)=>({value:a.id,label:a.label,hint:wired.has(a.id)?`already wired \u2014 ${a.path(".","~")}`:a.path(".","~")})),{value:MANUAL_AGENT_ID,label:"Manual / other agent",hint:"prints the MCP config to paste anywhere"}],initialValues:initial,required:!1});return isCancel(picked)?null:picked}function hasVellooEntry(content,format){try{switch(format){case"json":{let parsed=JSON.parse(content);return Boolean(parsed.mcpServers&&"velloo"in parsed.mcpServers)}case"codex-toml":return/^\s*\[\s*mcp_servers\s*\.\s*(?:"velloo"|velloo)\s*(?:\]|\.)/m.test(content);case"continue-block":return!0;case"continue-config":{let doc=Bun.YAML.parse(content);return Array.isArray(doc?.mcpServers)&&doc.mcpServers.some((s)=>s!==null&&typeof s==="object"&&s.name==="velloo")}case"opencode-json":{let parsed=JSON.parse(content);return Boolean(parsed.mcp&&"velloo"in parsed.mcp)}case"vscode-json":{let parsed=JSON.parse(content);return Boolean(parsed.servers&&"velloo"in parsed.servers)}}}catch{return!1}}async function projectWiredAgents(projectRoot){let out=[];for(let agent of Object.values(AGENTS)){if(agent.scope!=="project")continue;let content;try{content=await readFile3(agent.path(projectRoot,homedir4()),"utf8")}catch{continue}if(hasVellooEntry(content,agent.format))out.push(agent.id)}return out}async function globallyWiredAgents(homeDir=homedir4()){let out=[];for(let agent of Object.values(AGENTS)){if(agent.scope!=="global")continue;let content;try{content=await readFile3(agent.path(".",homeDir),"utf8")}catch{continue}if(hasVellooEntry(content,agent.format))out.push(agent.id)}return out}function localDesignScopeProblem(folder,agents){if(!localDesignOf(folder))return null;let refused=agents.filter((id)=>AGENTS[id]?.scope==="project");if(refused.length===0)return null;let globals=refused.map((id)=>`${id}-global`).filter((id)=>AGENTS[id]).join(", ");return`${refused.join(", ")} ${refused.length===1?"writes":"write"} into the checkout, and ${folder} is a local design outside it \u2014 only global configs are allowed${globals?` (use ${globals})`:""}.`}async function connect(opts){let transport=opts.transport??"stdio",homeDir=opts.homeDir??homedir4(),projectRoot=await resolveProjectRoot(opts.designFolder,opts.projectRoot),local=localDesignOf(opts.designFolder)!==null,
|
|
41
|
-
export{AGENT_IDS,PROJECT_AGENT_IDS,GLOBAL_AGENT_IDS,resolveProjectRoot,agentRootCandidates,refreshAgentArtifacts,
|
|
38
|
+
`}function continueBlockFile(entry){let version=TOOL_VERSION.split(" ")[0]??"0.0.0";return toYaml({name:"velloo",version,schema:"v1",mcpServers:[entry]})}function mergeContinueConfig(existing,entry,path){let doc={name:"Local Assistant",version:"1.0.0",schema:"v1"};if(existing!==null&&existing.trim()!==""){let parsed;try{parsed=Bun.YAML.parse(existing)}catch(err){throw invalidConfig(path,"YAML",err)}if(parsed===null||typeof parsed!=="object"||Array.isArray(parsed))throw invalidConfig(path,"YAML",Error("expected a top-level mapping"));doc=parsed}let others=(Array.isArray(doc.mcpServers)?doc.mcpServers:[]).filter((s)=>!(s!==null&&typeof s==="object"&&s.name==="velloo"));return toYaml({...doc,mcpServers:[...others,entry]})}var MANUAL_AGENT_ID="manual";function manualSetupText(){return["velloo speaks MCP over stdio (recommended) or HTTP \u2014 any MCP-capable agent can connect.","","stdio \u2014 the agent spawns the server itself:",' command: "velloo" args: ["mcp"]',` (resolves the design folder from the agent's cwd; pin one with ["mcp", "path/to/velloo"])`,""," Most agents take the JSON convention:",' { "mcpServers": { "velloo": { "command": "velloo", "args": ["mcp"] } } }',"","HTTP \u2014 for agents that dial a URL: `velloo mcp --http <design>` prints the URL of the","running canvas's MCP server, then point the agent at it:",' { "mcpServers": { "velloo": { "type": "http", "url": "<the printed URL>" } } }'," The port changes whenever the canvas restarts, so prefer stdio where the agent allows it."].join(`
|
|
39
|
+
`)}function baseLabel(id){return(AGENTS[id]?.label??id).replace(/\s*\((?:project|global)\)$/,"")}function projectVariantOf(id){let agent=AGENTS[id];if(!agent)return;if(agent.scope==="project")return id;let candidate=id.replace(/-global$/,"");return candidate!==id&&AGENTS[candidate]?candidate:void 0}async function askAgentWiring(opts){let preWired=await globallyWiredAgents(),projectWired=opts?.projectRoot&&!opts.globalOnly?await projectWiredAgents(opts.projectRoot):[],detected=detectInstalledAgents(),fallback=detected.length===0,wanted=fallback?GLOBAL_AGENT_IDS:detected,missing=wanted.filter((id)=>!preWired.includes(id));if(projectWired.length>0)log.info(`Already wired for this project: ${projectWired.map(baseLabel).join(", ")} ${import_picocolors.default.dim("(re-wiring is a no-op merge)")}`);if(preWired.length>0){let labels=preWired.map(baseLabel).join(", ");if(opts?.skipWhenCovered&&missing.length===0)return log.success(`velloo is already wired globally \u2014 ${labels} ${import_picocolors.default.dim("(covers this project; skipping agent setup)")}`),{agents:[],manual:!1,preWired};log.info(`Already wired globally: ${labels} ${import_picocolors.default.dim("(covers this project)")}`)}log.info(fallback?`No coding agents detected on this machine \u2014 offering the defaults (${wanted.map(baseLabel).join(", ")}).`:`Coding agents detected: ${detected.map(baseLabel).join(", ")}`);let targets=missing.length>0?missing:wanted,names=targets.map(baseLabel).join(", "),projectTargets=opts?.globalOnly?[]:targets.map(projectVariantOf).filter((id)=>Boolean(id));if(opts?.globalOnly)log.info(import_picocolors.default.dim("This design lives outside the repository, so only global agent configs are offered \u2014 nothing is written into the checkout."));let mode=await select({message:"Wire the velloo MCP into your coding agents?",options:[{value:"global",label:`Install globally \u2014 ${names}`,hint:"recommended \u2014 one config covers every project"},...projectTargets.length>0?[{value:"project",label:"Install for this project only",hint:projectTargets.map(baseLabel).join(", ")}]:[],{value:"choose",label:"Let me pick agents",hint:"the full list"},{value:"manual",label:"Manual MCP setup instructions",hint:"prints the config to paste into any agent"},{value:"skip",label:"Don't install now",hint:"wire later with `velloo connect`"}],initialValue:"global"});if(isCancel(mode))return null;if(mode==="skip")return{agents:[],manual:!1,preWired};if(mode==="manual")return{agents:[],manual:!0,preWired};if(mode==="global")return{agents:targets,manual:!1,preWired};if(mode==="project")return{agents:projectTargets,manual:!1,preWired};let picked=await pickAgents({exclude:[...opts?.skipWhenCovered?preWired:[],...opts?.globalOnly?Object.values(AGENTS).filter((agent)=>agent.scope==="project").map((agent)=>agent.id):[]],initial:[...new Set([...targets,...preWired,...projectWired])],wired:[...new Set([...preWired,...projectWired])]});if(picked===null)return null;return{agents:picked.filter((id)=>id!==MANUAL_AGENT_ID),manual:picked.includes(MANUAL_AGENT_ID),preWired}}async function pickAgents(opts){let exclude=new Set(opts?.exclude??[]),wired=new Set(opts?.wired??[]),agents=Object.values(AGENTS).filter((a)=>!exclude.has(a.id)).sort((a,b)=>a.scope===b.scope?0:a.scope==="global"?-1:1),detected=detectInstalledAgents(),initial=(opts?.initial??(detected.length>0?detected:GLOBAL_AGENT_IDS)).filter((id)=>!exclude.has(id)),picked=await multiselect({message:"Wire the velloo MCP into which agents?",options:[...agents.map((a)=>({value:a.id,label:a.label,hint:wired.has(a.id)?`already wired \u2014 ${a.path(".","~")}`:a.path(".","~")})),{value:MANUAL_AGENT_ID,label:"Manual / other agent",hint:"prints the MCP config to paste anywhere"}],initialValues:initial,required:!1});return isCancel(picked)?null:picked}function hasVellooEntry(content,format){try{switch(format){case"json":{let parsed=JSON.parse(content);return Boolean(parsed.mcpServers&&"velloo"in parsed.mcpServers)}case"codex-toml":return/^\s*\[\s*mcp_servers\s*\.\s*(?:"velloo"|velloo)\s*(?:\]|\.)/m.test(content);case"continue-block":return!0;case"continue-config":{let doc=Bun.YAML.parse(content);return Array.isArray(doc?.mcpServers)&&doc.mcpServers.some((s)=>s!==null&&typeof s==="object"&&s.name==="velloo")}case"opencode-json":{let parsed=JSON.parse(content);return Boolean(parsed.mcp&&"velloo"in parsed.mcp)}case"vscode-json":{let parsed=JSON.parse(content);return Boolean(parsed.servers&&"velloo"in parsed.servers)}}}catch{return!1}}async function projectWiredAgents(projectRoot){let out=[];for(let agent of Object.values(AGENTS)){if(agent.scope!=="project")continue;let content;try{content=await readFile3(agent.path(projectRoot,homedir4()),"utf8")}catch{continue}if(hasVellooEntry(content,agent.format))out.push(agent.id)}return out}async function globallyWiredAgents(homeDir=homedir4()){let out=[];for(let agent of Object.values(AGENTS)){if(agent.scope!=="global")continue;let content;try{content=await readFile3(agent.path(".",homeDir),"utf8")}catch{continue}if(hasVellooEntry(content,agent.format))out.push(agent.id)}return out}function localDesignScopeProblem(folder,agents){if(!localDesignOf(folder))return null;let refused=agents.filter((id)=>AGENTS[id]?.scope==="project");if(refused.length===0)return null;let globals=refused.map((id)=>`${id}-global`).filter((id)=>AGENTS[id]).join(", ");return`${refused.join(", ")} ${refused.length===1?"writes":"write"} into the checkout, and ${folder} is a local design outside it \u2014 only global configs are allowed${globals?` (use ${globals})`:""}.`}async function connect(opts){let transport=opts.transport??"stdio",homeDir=opts.homeDir??homedir4(),projectRoot=await resolveProjectRoot(opts.designFolder,opts.projectRoot),local=localDesignOf(opts.designFolder)!==null,httpUrl=opts.mcpUrl;if(transport==="http"&&!httpUrl)throw Error("the HTTP transport needs the server URL: run `velloo mcp --http` and pass the URL it prints as --mcp-url");let designArg=await designArgumentFor(projectRoot,opts.designFolder),connectionFor=(agent)=>{if(transport==="http")return{transport:"http",url:httpUrl};if(agent.gui){let script=process.argv[1]?resolve2(process.argv[1]):Bun.which("velloo");return script?{transport:"stdio",command:process.execPath,args:[script,"mcp",resolve2(opts.designFolder)]}:{transport:"stdio",command:"velloo",args:["mcp",resolve2(opts.designFolder)]}}return{transport:"stdio",command:"velloo",args:agent.scope==="project"&&designArg?["mcp",designArg]:["mcp"]}},configs=[],unknownAgents=[],projectScoped=[];for(let id of opts.agents){let agent=AGENTS[id];if(!agent){unknownAgents.push(id);continue}if(local&&agent.scope==="project"){projectScoped.push(id);continue}configs.push(await writeAgentConfig(projectRoot,agent,connectionFor(agent),homeDir))}let hasFamily=(family)=>opts.agents.some((id)=>AGENTS[id]?.family===family),hasAny=(...ids)=>opts.agents.some((id)=>ids.includes(id)),plugin=opts.installSkill&&hasFamily("claude-code")?await installClaudePlugin(homeDir)??void 0:void 0,skills=opts.installSkill&&!local&&hasAny("opencode","opencode-global","droid-global","cline-global","gemini","gemini-global","codex","codex-global")?await installSkills(projectRoot):void 0,geminiExtension=opts.installSkill&&hasAny("gemini","gemini-global")?await installGeminiExtension(homeDir)??void 0:void 0,cursorRules=opts.installSkill&&!local&&hasFamily("cursor")?await installCursorRules(projectRoot,opts.designFolder):void 0;return{projectRoot,transport,configs,skills,plugin,geminiExtension,cursorRules,unknownAgents,projectScoped}}
|
|
40
|
+
export{AGENTS,AGENT_IDS,PROJECT_AGENT_IDS,GLOBAL_AGENT_IDS,resolveProjectRoot,designArgumentFor,agentRootCandidates,writeAgentConfig,refreshAgentArtifacts,MANUAL_AGENT_ID,manualSetupText,askAgentWiring,globallyWiredAgents,localDesignScopeProblem,connect};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{AuthConfigResponseSchema,HealthResponseSchema,cloudJson}from"./chunk-
|
|
2
|
+
import{AuthConfigResponseSchema,HealthResponseSchema,cloudJson}from"./chunk-n9t36h0q.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};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{ConfigSchema}from"./chunk-nte0t7v3.js";import{readFile}from"fs/promises";import{dirname,join,resolve}from"path";async function findDesignConfig(startPath){let dir=resolve(startPath);if(!dir.endsWith("/"))dir=dirname(dir);while(!0){let candidate=join(dir,".design","config.json");try{let raw=await readFile(candidate,"utf8"),config=ConfigSchema.parse(JSON.parse(raw));return{folder:dir,config}}catch(err){if(err.code!=="ENOENT")throw err}let parent=dirname(dir);if(parent===dir)return null;dir=parent}}
|
|
3
|
+
export{findDesignConfig};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{recordedDesignName}from"./chunk-5ezzc1h2.js";import{displayPath}from"./chunk-7njj1qmq.js";import{basename,relative,resolve}from"path";function designWithFolder(folder,name,opts={}){let shown=name??recordedDesignName(folder)??basename(folder),rel=relative(resolve("."),folder),where=rel!==""&&!rel.startsWith("..")&&!opts.absolute?`./${rel}`:displayPath(folder);return`"${shown}" (${where})`}
|
|
3
|
+
export{designWithFolder};
|