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,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{loadDesignFolder,resolveProviders,findHostTailwindConfig,TailwindJit,extraThemeBlock}from"./chunk-
|
|
2
|
+
import{loadDesignFolder,resolveProviders,findHostTailwindConfig,TailwindJit,extraThemeBlock}from"./chunk-5ezzc1h2.js";import{join}from"path";async function loadPipeline(folderPath){let design=await loadDesignFolder(folderPath),config=design.config,{providers,defaultProvider}=await resolveProviders(config,folderPath),jit=new TailwindJit(Object.values(providers),join(folderPath,"screens"),void 0,()=>extraThemeBlock(design),void 0,()=>findHostTailwindConfig(folderPath,config.hostApp),config.styling?.framework),snapshotCss=await jit.build();return{folderPath,design,config,providers,defaultProvider,jit,snapshotCss}}
|
|
3
3
|
export{loadPipeline};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{spinner}from"./chunk-
|
|
2
|
+
import{spinner}from"./chunk-80fjfyha.js";import{stderr}from"process";function createProgress(options={}){let output=options.output??stderr,silent=options.silent===!0,interactive=options.interactive??(Boolean(output.isTTY)&&process.env.CI===void 0),makeSpinner=options.createSpinner??((stream)=>spinner({output:stream,indicator:"dots",withGuide:!1})),active=!1,current="",lastPrinted="",live=null,writeLine=(message)=>{if(!message||message===lastPrinted)return;output.write(` ${message}
|
|
3
3
|
`),lastPrinted=message},begin=(message)=>{if(active=!0,current=message,silent)return;if(interactive)live=makeSpinner(output),live.start(message);else writeLine(message)};return{start(message){if(active){this.step(message);return}begin(message)},step(message,stepOptions={}){if(!active){begin(message);return}if(current=message,silent)return;if(interactive)live?.message(message);else if(!stepOptions.transient)writeLine(message)},succeed(message=current){if(!active)return;if(active=!1,current=message,silent)return;if(interactive)live?.stop(message);else writeLine(message);live=null},fail(message=current){if(!active)return;if(active=!1,current=message,silent)return;if(interactive)live?.error(message);else writeLine(message);live=null},log(message){if(silent)return;if(interactive&&active){live?.clear(),writeLine(message),live=makeSpinner(output),live.start(current);return}writeLine(message)}}}
|
|
4
4
|
export{createProgress};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{fail,failWithError}from"./chunk-s23gtejf.js";import{firstPositional}from"./chunk-94vx1yb0.js";import{traceEnabled}from"./chunk-6tx68d90.js";var TOLERATED={upgrade:["folder-only"]},BUILTIN_FLAGS=["help","h","version","v"],camel=(name)=>name.replace(/-([a-z0-9])/g,(_,c)=>c.toUpperCase()),kebab=(name)=>name.replace(/[A-Z]/g,(c)=>`-${c.toLowerCase()}`);async function knownFlags(args){let defs=(typeof args==="function"?await args():await args)??{},known=new Set(BUILTIN_FLAGS);for(let[name,def]of Object.entries(defs)){if(def.type==="positional")continue;let alias="alias"in def?def.alias:void 0;for(let spelling of[name,...alias===void 0?[]:[alias].flat()])known.add(spelling),known.add(camel(spelling)),known.add(kebab(spelling))}return known}function flagsIn(rawArgs){let flags=[];for(let token of rawArgs){if(token==="--")break;if(!token.startsWith("-")||token==="-"||/^-\d/.test(token))continue;if(token.startsWith("--")){let name=token.slice(2).split("=")[0]??"";flags.push(name.startsWith("no-")?name.slice(3):name)}else flags.push(...token.slice(1).split("=")[0]?.split("")??[])}return flags}function strictFlags(name,cmd){let subCommands=cmd.subCommands,table=async()=>typeof subCommands==="function"?await subCommands():await subCommands,checked=subCommands?{...cmd,subCommands:async()=>Object.fromEntries(Object.entries(await table()??{}).map(([child,load])=>[child,async()=>{let def=typeof load==="function"?await load():await load;return strictFlags(`${name} ${child}`,def)}]))}:cmd;if(subCommands&&!cmd.run)return checked;let setup=cmd.setup;return{...checked,async setup(context){if(subCommands){let child=await firstPositional(context.rawArgs,cmd.args);if(child!==void 0&&Object.hasOwn(await table()??{},child)){await setup?.(context);return}}let known=await knownFlags(cmd.args),tolerated=TOLERATED[name]??[],unknown=flagsIn(context.rawArgs).filter((flag)=>flag!==""&&!known.has(flag)&&!tolerated.includes(flag));if(unknown.length>0){let listed=[...known].filter((f)=>f.length>1&&!BUILTIN_FLAGS.includes(f)&&f===kebab(f)),hint=listed.length>0?` (it takes ${listed.map((f)=>`--${f}`).join(", ")})`:"";fail(name,`unknown option ${unknown.map((f)=>f.length===1?`-${f}`:`--${f}`).join(", ")}${hint}`)}await setup?.(context)}}}var LOADERS={init:()=>import("./chunk-xyfed1j0.js").then((m)=>m.default),login:()=>import("./chunk-t5bb30zy.js").then((m)=>m.default),logout:()=>import("./chunk-5wv5a52y.js").then((m)=>m.default),connect:()=>import("./chunk-yeh9gb5w.js").then((m)=>m.default),run:()=>import("./chunk-3tmsrvaj.js").then((m)=>m.default),design:()=>import("./chunk-tbmkq7wy.js").then((m)=>m.default),mcp:()=>import("./chunk-1n5kmsxb.js").then((m)=>m.default),stop:()=>import("./chunk-wa6qamwh.js").then((m)=>m.default),status:()=>import("./chunk-tc4mzzfw.js").then((m)=>m.default),__daemon:()=>import("./chunk-9f22qnge.js").then((m)=>m.default),__update_check:()=>import("./chunk-wcqqx6tz.js").then((m)=>m.default),render:()=>import("./chunk-y5r2w2z3.js").then((m)=>m.default),capture:()=>import("./chunk-52hxv18g.js").then((m)=>m.default),browser:()=>import("./chunk-sn9vg42q.js").then((m)=>m.default),export:()=>import("./chunk-9g4tr0r6.js").then((m)=>m.default),upgrade:()=>import("./chunk-788t8y5x.js").then((m)=>m.default),publish:()=>import("./chunk-nr3ej3qf.js").then((m)=>m.default),emit:()=>import("./chunk-wzngjjeb.js").then((m)=>m.default),theme:()=>import("./chunk-maz6z7tz.js").then((m)=>m.default),completions:()=>import("./chunk-1jzhw3p4.js").then((m)=>m.default),...traceEnabled()?{trace:()=>import("./chunk-4nqr089t.js").then((m)=>m.default)}:{}};function guarded(name,load){return async()=>{let cmd=strictFlags(name,await load()),run=cmd.run;if(!run)return cmd;return{...cmd,async run(ctx){try{await run(ctx)}catch(err){failWithError(name,err)}}}}}var COMMANDS=Object.fromEntries(Object.entries(LOADERS).map(([name,load])=>[name,guarded(name,load)]));
|
|
3
|
+
export{COMMANDS};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{COMMANDS}from"./chunk-qdnb2t6a.js";var SHELLS=["zsh","bash","fish"],zshName=(name)=>name.replace(/\\/g,"\\\\").replace(/:/g,"\\:");function zshArguments(c,indent){let flagSpecs=c.flags.map((f)=>`${indent} '${f.flag}${f.takesValue?"=":""}[${f.description}]'`).join(" \\\n");return flagSpecs?`${indent}_arguments \\
|
|
3
|
+
${flagSpecs} \\
|
|
4
|
+
${indent} '*:file:_files'`:`${indent}_files`}function zshScript(specs){let commandLines=specs.map((c)=>` '${zshName(c.name)}:${c.description}'`).join(`
|
|
5
|
+
`),cases=specs.map((c)=>{if(c.subcommands.length===0)return` ${c.name})
|
|
6
|
+
${zshArguments(c," ")}
|
|
7
|
+
;;`;let subLines=c.subcommands.map((sub)=>` '${zshName(sub.name)}:${sub.description}'`).join(`
|
|
8
|
+
`),subCases=c.subcommands.map((sub)=>` ${sub.name})
|
|
9
|
+
${zshArguments(sub," ")}
|
|
10
|
+
;;`).join(`
|
|
11
|
+
`),own=c.flags.length>0?`
|
|
12
|
+
${zshArguments(c," ")}`:"",fallback=c.flags.length>0?`
|
|
13
|
+
*)
|
|
14
|
+
${zshArguments(c," ")}
|
|
15
|
+
;;`:"";return` ${c.name})
|
|
16
|
+
if (( CURRENT == 3 )); then
|
|
17
|
+
local -a _velloo_subcommands
|
|
18
|
+
_velloo_subcommands=(
|
|
19
|
+
${subLines}
|
|
20
|
+
)
|
|
21
|
+
_describe 'velloo ${c.name} command' _velloo_subcommands${own}
|
|
22
|
+
return
|
|
23
|
+
fi
|
|
24
|
+
case $words[3] in
|
|
25
|
+
${subCases}${fallback}
|
|
26
|
+
esac
|
|
27
|
+
;;`}).join(`
|
|
28
|
+
`);return`#compdef velloo
|
|
29
|
+
# velloo shell completions (zsh) \u2014 generated by \`velloo completions\`.
|
|
30
|
+
_velloo() {
|
|
31
|
+
local -a _velloo_commands
|
|
32
|
+
_velloo_commands=(
|
|
33
|
+
${commandLines}
|
|
34
|
+
)
|
|
35
|
+
if (( CURRENT == 2 )); then
|
|
36
|
+
_describe 'velloo command' _velloo_commands
|
|
37
|
+
return
|
|
38
|
+
fi
|
|
39
|
+
case $words[2] in
|
|
40
|
+
${cases}
|
|
41
|
+
esac
|
|
42
|
+
}
|
|
43
|
+
if ! (( $+functions[compdef] )); then
|
|
44
|
+
autoload -Uz compinit && compinit -i
|
|
45
|
+
fi
|
|
46
|
+
compdef _velloo velloo
|
|
47
|
+
`}var flagWords=(c)=>c.flags.map((f)=>f.flag).join(" ");function bashScript(specs){let names=specs.map((c)=>c.name).join(" "),cases=specs.map((c)=>{if(c.subcommands.length===0)return` ${c.name}) flags="${flagWords(c)}" ;;`;let subCases=c.subcommands.map((sub)=>` ${sub.name}) flags="${flagWords(sub)}" ;;`).join(`
|
|
48
|
+
`);return` ${c.name})
|
|
49
|
+
subs="${c.subcommands.map((sub)=>sub.name).join(" ")}"
|
|
50
|
+
case "$sub" in
|
|
51
|
+
${subCases}
|
|
52
|
+
*) flags="${flagWords(c)}" ;;
|
|
53
|
+
esac
|
|
54
|
+
;;`}).join(`
|
|
55
|
+
`);return`# velloo shell completions (bash) \u2014 generated by \`velloo completions\`.
|
|
56
|
+
_velloo() {
|
|
57
|
+
local cur cmd sub subs flags
|
|
58
|
+
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
59
|
+
cmd="\${COMP_WORDS[1]}"
|
|
60
|
+
sub="\${COMP_WORDS[2]}"
|
|
61
|
+
if [[ $COMP_CWORD -eq 1 ]]; then
|
|
62
|
+
COMPREPLY=( $(compgen -W "${names}" -- "$cur") )
|
|
63
|
+
return
|
|
64
|
+
fi
|
|
65
|
+
subs=""
|
|
66
|
+
flags=""
|
|
67
|
+
case "$cmd" in
|
|
68
|
+
${cases}
|
|
69
|
+
esac
|
|
70
|
+
if [[ $COMP_CWORD -eq 2 && -n "$subs" && "$cur" != -* ]]; then
|
|
71
|
+
COMPREPLY=( $(compgen -W "$subs" -- "$cur") )
|
|
72
|
+
return
|
|
73
|
+
fi
|
|
74
|
+
if [[ "$cur" == -* && -n "$flags" ]]; then
|
|
75
|
+
COMPREPLY=( $(compgen -W "$flags" -- "$cur") )
|
|
76
|
+
fi
|
|
77
|
+
}
|
|
78
|
+
complete -o default -F _velloo velloo
|
|
79
|
+
`}function fishFlags(c,condition){return c.flags.map((f)=>{let long=f.flag.replace(/^--/,"");return`complete -c velloo -n "${condition}" -l ${long}${f.takesValue?" -r":""} -d "${f.description}"`})}function fishScript(specs){let lines=["# velloo shell completions (fish) \u2014 generated by `velloo completions`.","function __velloo_is"," set -l words"," for token in (commandline -opc)[2..-1]"," string match -q -- '-*' $token; or set -a words $token"," end",' test "$words[1]" = "$argv[1]"; or return 1'," test (count $argv) -lt 2; and return 0",' test "$words[2]" = "$argv[2]"',"end","function __velloo_words"," set -l words"," for token in (commandline -opc)[2..-1]"," string match -q -- '-*' $token; or set -a words $token"," end"," count $words","end"];for(let c of specs){if(lines.push(`complete -c velloo -f -n "__fish_use_subcommand" -a "${c.name}" -d "${c.description}"`),c.subcommands.length===0){lines.push(...fishFlags(c,`__velloo_is ${c.name}`));continue}for(let sub of c.subcommands)lines.push(`complete -c velloo -f -n "__velloo_is ${c.name}; and test (__velloo_words) -eq 1" -a "${sub.name}" -d "${sub.description}"`),lines.push(...fishFlags(sub,`__velloo_is ${c.name} ${sub.name}`));let notSub=c.subcommands.map((sub)=>`; and not __velloo_is ${c.name} ${sub.name}`).join("");lines.push(...fishFlags(c,`__velloo_is ${c.name}${notSub}`))}return`${lines.join(`
|
|
80
|
+
`)}
|
|
81
|
+
`}function completionScript(shell,specs){switch(shell){case"zsh":return zshScript(specs);case"bash":return bashScript(specs);case"fish":return fishScript(specs)}}async function resolvable(value){return typeof value==="function"?await value():value}var kebab=(name)=>name.replace(/[A-Z]/g,(c)=>`-${c.toLowerCase()}`);function sanitize(desc){return(desc??"").split(`
|
|
82
|
+
`)[0]?.replace(/['"[\]:`$\\]/g,"").trim()??""}function flagSpecs(args){let flags=[];for(let[argName,def]of Object.entries(args)){if(def.type==="positional")continue;let isBool=def.type==="boolean",negated=isBool&&def.default===!0;flags.push({flag:negated?`--no-${kebab(argName)}`:`--${kebab(argName)}`,description:sanitize(def.description),takesValue:!isBool})}return flags}async function commandSpec(name,load,depth){let cmd,meta,args;try{cmd=await resolvable(load),meta=cmd.meta?await resolvable(cmd.meta):void 0,args=cmd.args?await resolvable(cmd.args):{}}catch{return null}if(meta?.hidden)return null;let subcommands=[];if(depth===0&&cmd.subCommands)for(let[child,loadChild]of Object.entries(await resolvable(cmd.subCommands))){let spec=await commandSpec(child,loadChild,depth+1);if(spec)subcommands.push(spec)}return{name,description:sanitize(meta?.description),flags:flagSpecs(args),subcommands}}async function commandSpecs(){let out=[];for(let[name,load]of Object.entries(COMMANDS)){if(name.startsWith("__"))continue;let spec=await commandSpec(name,load,0);if(spec)out.push(spec)}return out}import{existsSync}from"fs";import{appendFile,mkdir,readFile,writeFile}from"fs/promises";import{homedir}from"os";import{basename,dirname,join,sep}from"path";function detectShell(env=process.env){let name=basename(env.SHELL??"");return SHELLS.includes(name)?name:null}var RC_MARKER="# velloo completions";function targets(shell,homeDir){switch(shell){case"zsh":return{scriptPath:join(homeDir,".velloo","completions","velloo.zsh"),rcPath:join(homeDir,".zshrc")};case"bash":return{scriptPath:join(homeDir,".velloo","completions","velloo.bash"),rcPath:join(homeDir,".bashrc")};case"fish":return{scriptPath:join(homeDir,".config","fish","completions","velloo.fish")}}}function completionsInstalled(homeDir=homedir(),shell){return(shell?[shell]:SHELLS).some((s)=>existsSync(targets(s,homeDir).scriptPath))}async function installCompletions(shell,homeDir=homedir()){let{scriptPath,rcPath}=targets(shell,homeDir),script=completionScript(shell,await commandSpecs());await mkdir(dirname(scriptPath),{recursive:!0}),await writeFile(scriptPath,script);let rcUpdated=!1;if(rcPath){let rc=await readFile(rcPath,"utf8").catch(()=>"");if(!rc.includes(RC_MARKER)){let rel=scriptPath.slice(homeDir.length+1).split(sep).join("/"),line=`[ -f "$HOME/${rel}" ] && source "$HOME/${rel}" ${RC_MARKER}`;await appendFile(rcPath,`${rc.endsWith(`
|
|
83
|
+
`)||rc===""?"":`
|
|
84
|
+
`}${line}
|
|
85
|
+
`),rcUpdated=!0}}return{shell,scriptPath,rcPath,rcUpdated}}
|
|
86
|
+
export{SHELLS,completionScript,commandSpecs,detectShell,completionsInstalled,installCompletions};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{CHROMIUM_INSTALL_ARGV,CHROMIUM_FULL_INSTALL_ARGV,CHROMIUM_DEPS_INSTALL_ARGV}from"./chunk-c4fym47a.js";import"./chunk-nte0t7v3.js";import{fail}from"./chunk-s23gtejf.js";import{defineCommand}from"./chunk-2smsg2ct.js";async function run(argv){let code=await Bun.spawn([...argv],{stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited;if(code!==0)fail("browser install",`browser setup exited with status ${code}`)}var install=defineCommand({meta:{name:"install",description:"Install the browser used for screenshots"},args:{full:{type:"boolean",default:!1,description:"Install full Chromium instead of the smaller headless shell"},"with-deps":{type:"boolean",default:!1,description:"Also install required Linux system packages (may use sudo)"}},async run({args}){if(args["with-deps"]&&process.platform==="linux")await run(CHROMIUM_DEPS_INSTALL_ARGV);await run(args.full?CHROMIUM_FULL_INSTALL_ARGV:CHROMIUM_INSTALL_ARGV)}}),browser_default=defineCommand({meta:{name:"browser",description:"Manage the optional browser used for screenshots"},subCommands:{install}});export{browser_default as default};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import"./chunk-
|
|
2
|
+
import"./chunk-nte0t7v3.js";import{topUpTokens}from"./chunk-5ezzc1h2.js";import"./chunk-n9t36h0q.js";import"./chunk-c4fym47a.js";import{normalizeCloudUrl,loadCredential,saveCredential}from"./chunk-hfzg98c8.js";import{fail}from"./chunk-s23gtejf.js";import{verifyCredential,performDeviceLogin}from"./chunk-6zz9kfbd.js";import{defaultCloudUrl}from"./chunk-as08hzp3.js";import{defineCommand}from"./chunk-2smsg2ct.js";import{createInterface}from"readline/promises";async function waitForEnter(message){if(!process.stdin.isTTY)return;let rl=createInterface({input:process.stdin,output:process.stdout});try{await rl.question(message)}finally{rl.close()}}var login_default=defineCommand({meta:{name:"login",description:"Log in to velloo-cloud (opens the browser, saves a CLI token)"},args:{url:{type:"string",description:"velloo-cloud base URL (default: $VELLOO_CLOUD_URL or the built-in default)"},force:{type:"boolean",description:"Re-authenticate even if already logged in",default:!1}},async run({args}){let cloudUrl=args.url?normalizeCloudUrl(args.url):defaultCloudUrl();if(!args.force){let existing=await loadCredential(cloudUrl),email=existing&&await verifyCredential(cloudUrl,existing.token);if(email){console.log(`velloo login: already logged in to ${cloudUrl} as ${email}.`),console.log(" Use `velloo login --force` to switch accounts, or `velloo logout` to sign out.");return}}let result;try{result=await performDeviceLogin(cloudUrl,async({verificationUrl,userCode})=>{console.log(`
|
|
3
3
|
velloo login will open your browser to approve this device (code ${userCode}).`),await waitForEnter("Press Enter to open the browser\u2026 "),console.log(`Opening ${verificationUrl}`),console.log(`If the browser doesn't open, visit that URL and enter: ${userCode}`)})}catch(err){fail("login",err instanceof Error?err.message:String(err))}let path=await saveCredential(cloudUrl,result);console.log(`velloo login: logged in to ${cloudUrl} as ${result.email}`),console.log(` credentials saved to ${path}`);try{await topUpTokens({url:cloudUrl,token:result.token},10)}catch{}}});export{login_default as default};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{isCancel,confirm,select}from"./chunk-80fjfyha.js";import{designNameIssue}from"./chunk-nte0t7v3.js";import{managedDesignId,localDesignOf,removeLocalDesign,recordedDesignName,designRenameConflict,followDesignRename,loadDesignFolder}from"./chunk-5ezzc1h2.js";import"./chunk-n9t36h0q.js";import"./chunk-c4fym47a.js";import{agentRootCandidates}from"./chunk-9nhw49vv.js";import"./chunk-kz4423th.js";import{daemonRoot,readLock,isLive,stopDaemon}from"./chunk-k9219kmj.js";import{fail}from"./chunk-s23gtejf.js";import"./chunk-2fgfex9b.js";import"./chunk-qdnb2t6a.js";import"./chunk-cvn689d5.js";import{displayPath}from"./chunk-7njj1qmq.js";import"./chunk-7k7dpj5y.js";import{recordedAppRoot,planAppRootChange,applyAppRootChange,promptAppRootChoice,planRelocation,relocateDesign,runInit2}from"./chunk-7bvvbsqy.js";import"./chunk-hfzg98c8.js";import{repinAgentConfigs,migrateFolder2}from"./chunk-k7sehkm8.js";import"./chunk-pjtg3wnm.js";import"./chunk-d9p6s05n.js";import"./chunk-jx11jvq8.js";import{findManifest,manifestListing,findDesigns,unregisterDesign,isWithin,writeDesignName,registerLocalDesign,DESIGN_ARG_DESCRIPTION,hasDesignConfig,DESIGN_ID_ARG,resolveDesign,checkoutDesigns}from"./chunk-td5z2sm4.js";import"./chunk-6zz9kfbd.js";import"./chunk-qgwhd4n6.js";import"./chunk-as08hzp3.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
|
+
Destination: ${plan.destination}
|
|
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
|
+
Checkout: ${root}
|
|
6
|
+
Application: ${appRoot}`),listed)console.log("velloo.json: drops its entry, which cannot point outside the repo");if(!args.yes){console.log("Preview only. Add --yes to confirm this local binding.");return}if(await loadDesignFolder(folder,{preferences:!1}),await stopDaemon(daemonRoot(folder)),listed)await unregisterDesign(folder,cwd).catch((err)=>fail("design bind",err.message));if(name!==recordedDesignName(folder))await writeDesignName(folder,name);await registerLocalDesign({id:existing?.id??managedDesignId(folder)??randomUUID(),root,appRoot:existsSync(appRoot)?appRoot:root,...managedDesignId(folder)?{}:{designPath:folder}}).catch((err)=>fail("design bind",err.message)),console.log(`Bound "${name}" to ${root} on this machine.`)}}),setAppRoot=defineCommand({meta:{name:"set-app-root",description:"Point a design at a different application root"},args:{design:{type:"positional",required:!1,description:DESIGN_ARG_DESCRIPTION},id:DESIGN_ID_ARG,to:{type:"string",description:"New application root (asked from the repo's apps when omitted)"},yes:{type:"boolean",description:"Apply the displayed change"}},async run({args}){let folder=await resolveDesign(args.design,"design set-app-root",{id:args.id,interactive:!0,requireConfig:!0}),current=await recordedAppRoot(folder);console.log(`Design: ${folder}`),console.log(`Application: ${current.path}${current.exists?current.looksLikeApp?"":import_picocolors.default.yellow(" (no package.json)"):import_picocolors.default.yellow(" (missing)")}`);let target=args.to?resolve(args.to):await promptAppRootChoice(current.path);if(!target){console.log(import_picocolors.default.dim(" No other application found in this repo \u2014 pass --to <path>."));return}let change=await planAppRootChange(folder,target).catch((err)=>fail("design set-app-root",err.message));if(resolve(change.to)===resolve(change.from)){console.log(import_picocolors.default.dim(" Already pointing there \u2014 nothing changed."));return}if(!existsSync(change.to))fail("design set-app-root",`${change.to} does not exist.`);if(console.log(`New application: ${change.to}`),!existsSync(join(change.to,"package.json")))console.log(import_picocolors.default.yellow(" ! no package.json there \u2014 codegen and live islands will not resolve"));if(change.local)console.log(import_picocolors.default.dim(` local design record: appRoot \u2192 ${change.to}`));for(let r of change.rewritten)console.log(import_picocolors.default.dim(` ${r.field}: ${r.from} \u2192 ${r.to}`));if(!args.yes){console.log("Preview only. Add --yes to apply.");return}await stopDaemon(daemonRoot(folder)),await applyAppRootChange(folder,change),console.log(`velloo design: application root is now ${change.to}`)}}),design_default=defineCommand({meta:{name:"design",description:"Manage this repo's designs (list, add, remove, move, rename, upgrade, \u2026)"},subCommands:{list,add,remove,move,rename,upgrade,bind,"set-app-root":setAppRoot},run:({args})=>args._?.length?void 0:list.run?.({args,cmd:list,rawArgs:[]})});export{design_default as default};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import"./chunk-n9t36h0q.js";import"./chunk-nte0t7v3.js";import{loadCredential}from"./chunk-hfzg98c8.js";import"./chunk-5ezzc1h2.js";import"./chunk-c4fym47a.js";import"./chunk-kz4423th.js";import{listDaemons}from"./chunk-k9219kmj.js";import"./chunk-80fjfyha.js";import"./chunk-s23gtejf.js";import"./chunk-2fgfex9b.js";import"./chunk-qdnb2t6a.js";import"./chunk-cvn689d5.js";import"./chunk-7njj1qmq.js";import{designWithFolder}from"./chunk-bpeezw7w.js";import{verifyCredential}from"./chunk-6zz9kfbd.js";import"./chunk-qgwhd4n6.js";import{defaultCloudUrl}from"./chunk-as08hzp3.js";import{require_picocolors}from"./chunk-jrsknzjt.js";import{__toESM,defineCommand}from"./chunk-2smsg2ct.js";var import_picocolors=__toESM(require_picocolors(),1);var status_default=defineCommand({meta:{name:"status",description:"List the velloo canvas daemons running on this machine + cloud sign-in"},args:{},async run(){let daemons=await listDaemons();if(daemons.length===0)console.log("velloo: no canvas daemons running.");else for(let d of daemons)console.log(`${d.canvasUrl} ${designWithFolder(d.root,void 0,{absolute:!0})} (pid ${d.pid}, since ${d.startedAt})`);let cloudUrl=defaultCloudUrl(),cred=await loadCredential(cloudUrl);if(!cred){console.log(import_picocolors.default.dim(`cloud: not signed in (${cloudUrl}) \u2014 run \`velloo login\` to share.`));return}let email=await verifyCredential(cloudUrl,cred.token,3000);console.log(email?`cloud: signed in as ${email} (${cloudUrl})`:import_picocolors.default.dim(`cloud: stored credential for ${cred.email} (${cloudUrl}) \u2014 expired or cloud unreachable; \`velloo login\` to refresh.`))}});export{status_default as default};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{BoardSchema,isArchived,designNameIssue,toDesignName,ConfigSchema,ScreenSchema}from"./chunk-nte0t7v3.js";import{writeJsonAtomic,listLocalDesigns,writeLocalDesign,readRepoManifestAt,findOwningManifest,recordedDesignName,findDesigns2,pickDesign}from"./chunk-5ezzc1h2.js";import{isCancel,multiselect,select}from"./chunk-80fjfyha.js";import{fail}from"./chunk-s23gtejf.js";import{existsSync,realpathSync}from"fs";import{readdir,readFile,rm,stat}from"fs/promises";import{homedir}from"os";import{basename,dirname,isAbsolute,join,relative,resolve,sep}from"path";var MANIFEST_FILE="velloo.json",DEFAULT_FOLDER_NAME="velloo";function findManifest(dir){return readRepoManifestAt(dir,{strict:!0})}function manifestListing(folder){return findOwningManifest(folder,{strict:!0})}function findDesigns(cwd){return findDesigns2(cwd,{strict:!0})}function sameFolder(a,b){return a===b||existsSync(a)&&existsSync(b)&&realpathSync(a)===realpathSync(b)}function assertCurrent(found){if(found.legacy)throw Error(`${found.path} is in the pre-designs format (\`projects\`) \u2014 run \`velloo upgrade\` to migrate it first.`)}async function unregisterDesign(folder,projectDir){let abs=resolve(folder),here=projectDir?await findManifest(projectDir):null,found=here?.folders.some((path)=>sameFolder(path,abs))?here:await manifestListing(abs);if(!found)return{name:null,path:null,removedManifest:!1};let index=found.folders.findIndex((path)=>sameFolder(path,abs));if(index===-1)return{name:null,path:found.path,removedManifest:!1};assertCurrent(found);let name=recordedDesignName(abs)??basename(abs),manifest=withoutDesign(found.manifest,index,name);if(manifest===null)return await rm(found.path,{force:!0}),{name,path:found.path,removedManifest:!0};return await writeJsonAtomic(found.path,manifest),{name,path:found.path,removedManifest:!1}}function withoutDesign(manifest,index,name){let designs=manifest.designs.filter((_,i)=>i!==index),{defaultDesign,...rest}=manifest;if(designs.length===0&&!rest.feedback)return null;return{...rest,designs,...defaultDesign&&defaultDesign!==name?{defaultDesign}:{}}}function isWithin(parent,child){let rel=relative(parent,child);return rel===""||!rel.startsWith("..")&&!isAbsolute(rel)}async function findGitRoot(start){let home=homedir(),dir=resolve(start);while(dir!==home){try{return await stat(join(dir,".git")),dir}catch{}let parent=dirname(dir);if(parent===dir)return null;dir=parent}return null}var SCAN_SKIP=new Set(["node_modules",".git","dist","build",".next",".turbo","coverage",".velloo"]);async function discoverDesignFolders(root,maxDepth=3){let out=[],walk=async(dir,depth)=>{let entries;try{entries=await readdir(dir,{withFileTypes:!0})}catch{return}for(let entry of entries){if(!entry.isDirectory()||entry.name.startsWith(".")||SCAN_SKIP.has(entry.name))continue;let child=join(dir,entry.name);try{await stat(join(child,".design","config.json")),out.push(child);continue}catch{}if(depth<maxDepth)await walk(child,depth+1)}};return await walk(resolve(root),1),out.sort()}function deriveName(folder,projectDir){let base=basename(folder),nested=base===DEFAULT_FOLDER_NAME&&dirname(folder)!==projectDir;return toDesignName(nested?basename(dirname(folder)):base)??"app"}async function chooseDesignName(request){let folder=resolve(request.folder),issue=request.requested===void 0?null:designNameIssue(request.requested);if(issue)throw Error(`invalid --name ${JSON.stringify(request.requested)} \u2014 ${issue}`);let taken=await takenNames(request,folder);if(request.requested){let holder=taken.get(request.requested);if(holder)throw Error(`a design named "${request.requested}" already exists at ${holder} \u2014 pick another --name.`);return request.requested}let base;if(request.storage==="repository")base=deriveName(folder,resolve(request.checkout));else{let chosen=request.storage==="chosen"&&basename(folder)!==DEFAULT_FOLDER_NAME;base=deriveName(chosen?folder:request.appRoot)}let name=base;for(let n=2;taken.has(name);n++)name=`${base}-${n}`;return name}async function takenNames(request,folder){let from=request.checkout,taken=new Map,set=await findDesigns(from).catch(()=>null);for(let design of set?.designs??[])if(!sameFolder(design.root,folder))taken.set(design.name,design.root);if(!set?.repo)for(let sibling of await discoverDesignFolders(request.checkout,1)){let name=recordedDesignName(sibling);if(name&&!sameFolder(sibling,folder))taken.set(name,sibling)}return taken}async function writeDesignName(folder,name){let path=join(folder,".design","config.json"),config=ConfigSchema.parse(JSON.parse(await readFile(path,"utf8")));await writeJsonAtomic(path,{...config,name})}async function registerDesign(folder,projectDir){let abs=resolve(folder),name=recordedDesignName(abs);if(!name)throw Error(`${abs} has no design name \u2014 run \`velloo design upgrade ${abs}\` first.`);let dir=resolve(projectDir),found=await findManifest(dir),path=found?found.path:join(dir,MANIFEST_FILE);if(found?.folders.some((target)=>sameFolder(target,abs)))return{name,path,created:!1};if(found)assertCurrent(found);let clash=(await findDesigns(dir))?.designs.find((d)=>d.name===name&&!sameFolder(d.root,abs));if(clash)throw Error(`a design named "${name}" already exists at ${clash.root} \u2014 rename one with \`velloo design rename\`.`);let designs=[...found?.manifest.designs??[]],rel=(target)=>relative(dir,target).split("\\").join("/")||".",defaultDesign=found?.manifest.defaultDesign;if(!found)for(let sibling of await discoverDesignFolders(dir,1)){if(sibling===abs)continue;if(designs.push(rel(sibling)),sibling===join(dir,DEFAULT_FOLDER_NAME))defaultDesign=recordedDesignName(sibling)??void 0}designs.push(rel(abs));let manifest={...found?.manifest??{},designs,...defaultDesign?{defaultDesign}:{}};return await writeJsonAtomic(path,manifest),{name,path,created:!0}}async function registerLocalDesign(opts){await writeLocalDesign(opts.id,{root:opts.root,appRoot:opts.appRoot,...opts.designPath?{designPath:opts.designPath}:{}})}import{existsSync as existsSync2,readdirSync}from"fs";import{readdir as readdir2,readFile as readFile2}from"fs/promises";import{homedir as homedir2}from"os";import{basename as basename2,dirname as dirname2,join as join2,relative as relative2,resolve as resolve2,sep as sep2}from"path";var DEFAULT_FOLDER="velloo",DESIGN_ARG_DESCRIPTION="A design name from ./velloo.json, a design folder, or a velloo.json file or its directory (default: the design folder you're in, else this directory's velloo.json: its only design or defaultDesign)";async function existingDesignFolder(appRoot){try{let found=await findDesigns(appRoot);for(let design of found?.designs??[])if(design.exists)return design.root}catch{}let conventional=join2(resolve2(appRoot),DEFAULT_FOLDER);if(await hasDesignConfig(conventional))return conventional;let[first]=await discoverDesignFolders(resolve2(appRoot));return first??null}function isDesignFolderSync(dir){return existsSync2(join2(dir,".design","config.json"))}function isEmptyOrMissingSync(dir){try{return readdirSync(dir).length===0}catch(err){if(err.code==="ENOENT")return!0;throw err}}async function hasDesignConfig(dir){try{return await readFile2(join2(dir,".design","config.json"),"utf8"),!0}catch{return!1}}var DESIGN_ID_ARG={type:"string",description:"The design's number in `velloo design list`, instead of its name or path"};async function designFolder(set,design,abort){let repo=set.repo;if(repo&&design.outsideRepo){let entry=relative2(repo.dir,design.root);abort(`design ${JSON.stringify(design.name)} in ${repo.path} points outside the repository (${entry}), which velloo.json cannot authorize. Pass the design path explicitly, or run \`velloo design bind ${design.root}\` here to keep it as a local design on this machine.`)}if(!design.exists)abort(`design ${JSON.stringify(design.name)} ${design.local?"(a local design)":`in ${repo?.path}`} points at ${design.root}, which is not a velloo design folder (no .design/config.json).`);return design.root}function quoteArg(value){return/^[\w@%+=:,./-]+$/.test(value)?value:`'${value.replace(/'/g,"'\\''")}'`}function designsLabel(set){return set.repo?.path??"this checkout's local designs"}function byName(set,name,abort){let shared=set.conflicts.get(name);if(shared)abort(`${shared.length} designs are named ${JSON.stringify(name)}: ${shared.map((d)=>d.root).join(", ")}. Pass a path, and rename one with \`velloo design rename <path> <new-name>\`.`);return set.byName.get(name)}async function resolveDesign(arg,cmd,opts={}){let abort=opts.onFail??((m)=>fail(cmd,m)),cwd=resolve2(opts.cwd??"."),set=null;try{set=await findDesigns(cwd)}catch(err){abort(err.message)}if(opts.id!==void 0){if(arg)abort("pass a design or --id, not both.");let n=Number(opts.id);if(!Number.isInteger(n)||n<1)abort("--id takes a design's number from `velloo design list`.");if(!set||set.designs.length===0){if(n===1)return resolveDesign(void 0,cmd,{...opts,id:void 0});abort(`there is no design #${n} here \u2014 \`velloo design list\` numbers them.`)}let entry=set.designs[n-1];if(!entry)abort(`there is no design #${n} \u2014 ${designsLabel(set)} has ${set.designs.length}. \`velloo design list\` numbers them.`);return designFolder(set,entry,abort)}if(arg){let named=set&&!arg.includes(sep2)?byName(set,arg,abort):void 0;if(set&&named)return designFolder(set,named,abort);let explicit=resolve2(cwd,arg);if(await hasDesignConfig(explicit))return explicit;let project=basename2(explicit)==="velloo.json"&&existsSync2(explicit)?dirname2(explicit):explicit;if((await findDesigns(project).catch((err)=>abort(err.message)))?.designs.length)return resolveDesign(void 0,cmd,{...opts,cwd:project});let nested=join2(explicit,DEFAULT_FOLDER);if(await hasDesignConfig(nested))return nested;if(!set&&!arg.includes(sep2)){let above=await enclosingProject(cwd),match=above?.designs.find((d)=>d.name===arg);if(above&&match)abort(`design ${JSON.stringify(arg)} is listed in \`${shortPath(cwd,above.label)}\`, and commands only read the directory they run in. Run from \`${shortPath(cwd,above.dir)}\`, or pass its folder (\`${quoteArg(shortPath(cwd,match.root))}\`) instead of its name.`)}if(set&&!arg.includes(sep2))abort(`unknown design ${JSON.stringify(arg)} \u2014 ${designsLabel(set)} lists: ${set.designs.map((d)=>d.name).join(", ")}. Pass a design name or a folder path.`);if(opts.requireConfig)abort(`${explicit} is not a velloo design folder (no .design/config.json).`);return explicit}if(set&&set.designs.length>0){if(await hasDesignConfig(cwd))return cwd;let picked=pickDesign(set,cwd);if(picked&&picked.reason!=="arbitrary")return designFolder(set,picked.design,abort);let names=set.designs.map((d)=>d.name);if(opts.interactive&&process.stdin.isTTY){let chosen=await select({message:"Which design?",options:set.designs.map((d)=>({value:d.root,label:d.name,hint:relative2(cwd,d.root)}))});if(isCancel(chosen))abort("cancelled.");let design=set.designs.find((d)=>d.root===chosen);return designFolder(set,design,abort)}let example=cmd.startsWith("design ")?`velloo ${cmd} --id 1\` for ${quoteArg(names[0]??"")}, as numbered by \`velloo design list`:`velloo ${cmd} ${designExample(opts,names[0]??"")}`;abort(`${designsLabel(set)} lists several designs: ${names.join(", ")}. Pass one (e.g. \`${example}\`)${set.repo?' or set "defaultDesign"':""}.`)}if(await hasDesignConfig(cwd))return cwd;let here=join2(cwd,DEFAULT_FOLDER);if(await hasDesignConfig(here))return here;let takesDesign=opts.takesDesign!==!1,above=await enclosingProject(cwd);if(above){let nearest=[...above.designs].sort((a,b)=>relative2(cwd,a.root).length-relative2(cwd,b.root).length)[0],example=takesDesign&&nearest?`, or pass a design folder (e.g. \`velloo ${cmd} ${designExample(opts,relative2(cwd,nearest.root).split(sep2).join("/"))}\`)`:"";abort(`no velloo.json or design folder here. \`${shortPath(cwd,above.label)}\` lists ${above.designs.map((d)=>JSON.stringify(d.name)).join(", ")}, and commands only read the directory they run in: run from \`${shortPath(cwd,above.dir)}\`${example}.`)}let example=takesDesign?`, pass a design folder or a velloo.json path (e.g. \`velloo ${cmd} ${designExample(opts,"apps/web")}\`)`:"";abort(`no velloo.json or design folder in ${cwd}. Run from the directory that has your velloo.json${example}, or \`velloo init\` here.${movedCheckoutHint(cwd)}`)}function shortPath(cwd,path){let rel=relative2(cwd,path);return rel!==""&&rel.length<path.length?rel.split(sep2).join("/"):path}function designExample(opts,design){return opts.designFlag?`${opts.designFlag}=${quoteArg(design)}`:quoteArg(design)}async function enclosingProject(cwd){let here=resolve2(cwd);for(let dir=dirname2(here);dir!==here;){let set=await findDesigns(dir).catch(()=>null),designs=set?.designs.filter((d)=>d.exists&&!d.outsideRepo)??[];if(set&&designs.length>0)return{dir,label:set.repo?.path??`${dir} (local designs)`,designs};let parent=dirname2(dir);if(parent===dir)return null;dir=parent}return null}async function checkoutDesigns(cwd){let set=await findDesigns(cwd).catch(()=>null);if(set&&set.designs.length>0)return set.designs.filter((d)=>d.exists&&!d.outsideRepo).map((d)=>d.root);try{return[await resolveDesign(void 0,"upgrade",{requireConfig:!0,cwd,onFail:()=>{throw Error("no design here")}})]}catch{return[]}}async function resolveDesignForSession(arg,cmd,cwd=resolve2(".")){if(!arg&&!await hasDesignConfig(cwd)){let set=await findDesigns(cwd).catch(()=>null),picked=set?pickDesign(set,cwd):null;if(set&&picked?.reason==="arbitrary")return{folder:await designFolder(set,picked.design,(m)=>fail(cmd,m)),pick:"arbitrary"}}return{folder:await resolveDesign(arg,cmd,{cwd}),pick:void 0}}function movedCheckoutHint(cwd){if(!insideProject(cwd))return"";let orphans=listLocalDesigns().filter((design)=>!existsSync2(design.root)&&existsSync2(design.designRoot));if(orphans.length===0)return"";return`
|
|
3
|
+
This machine has designs for checkouts that no longer exist at their old paths:${orphans.map((design)=>`
|
|
4
|
+
"${recordedDesignName(design.designRoot)??design.legacyName??design.id}" at ${design.designRoot}, made for ${design.root}`).join("")}
|
|
5
|
+
If this is one of those checkouts, moved, attach its design with \`velloo design bind <design folder>\`. Otherwise forget it with \`velloo design remove <design folder>\`.`}function insideProject(cwd){let home=homedir2();for(let dir=cwd;dir!==home&&dirname2(dir)!==dir;dir=dirname2(dir))if(existsSync2(join2(dir,".git"))||existsSync2(join2(dir,"package.json")))return!0;return!1}async function listScreens(folder){let files;try{files=(await readdir2(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 readdir2(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)}
|
|
6
|
+
export{findManifest,manifestListing,findDesigns,unregisterDesign,withoutDesign,isWithin,findGitRoot,chooseDesignName,writeDesignName,registerDesign,registerLocalDesign,DESIGN_ARG_DESCRIPTION,existingDesignFolder,isDesignFolderSync,isEmptyOrMissingSync,hasDesignConfig,DESIGN_ID_ARG,resolveDesign,checkoutDesigns,resolveDesignForSession,pickBoards,pickScreen};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{isCancel,select}from"./chunk-80fjfyha.js";import"./chunk-nte0t7v3.js";import"./chunk-5ezzc1h2.js";import"./chunk-n9t36h0q.js";import"./chunk-c4fym47a.js";import"./chunk-kz4423th.js";import{daemonRoot,listDaemons,stopDaemon}from"./chunk-k9219kmj.js";import{fail}from"./chunk-s23gtejf.js";import"./chunk-2fgfex9b.js";import"./chunk-qdnb2t6a.js";import"./chunk-cvn689d5.js";import"./chunk-7njj1qmq.js";import{designWithFolder}from"./chunk-bpeezw7w.js";import{DESIGN_ARG_DESCRIPTION,resolveDesign}from"./chunk-td5z2sm4.js";import"./chunk-qgwhd4n6.js";import"./chunk-as08hzp3.js";import{require_picocolors}from"./chunk-jrsknzjt.js";import{__toESM,defineCommand}from"./chunk-2smsg2ct.js";import{resolve}from"path";var import_picocolors=__toESM(require_picocolors(),1);var ALL="__all__",canvasLine=(d)=>`${designWithFolder(d.root,void 0,{absolute:!0})} \u2014 ${d.canvasUrl}`;async function stopEach(daemons){for(let d of daemons)await stopDaemon(d.root),console.log(`velloo: stopped ${canvasLine(d)}`)}async function designHere(){try{return await resolveDesign(void 0,"stop",{onFail:()=>{throw Error("no design here")}})}catch{return}}function runningFor(daemons,folder){if(!folder)return;let root=resolve(daemonRoot(folder));return daemons.find((d)=>resolve(d.root)===root)?.root}var stop_default=defineCommand({meta:{name:"stop",description:"Stop a running canvas (picks from the running ones when none is named)"},args:{design:{type:"positional",required:!1,description:DESIGN_ARG_DESCRIPTION},all:{type:"boolean",default:!1,description:"Stop every running velloo canvas on this machine"}},async run({args}){if(args.all){let daemons=await listDaemons();if(daemons.length===0)console.log("velloo: no canvas daemons running.");else await stopEach(daemons);return}if(!args.design&&process.stdin.isTTY){let daemons=await listDaemons();if(daemons.length===0){console.log("velloo: no canvas daemons running.");return}if(daemons.length===1){await stopEach(daemons);return}let here=runningFor(daemons,await designHere()),ordered=[...daemons].sort((a,b)=>a.root===here?-1:b.root===here?1:0),chosen=await select({message:"Stop which canvas?",options:[...ordered.map((d)=>({value:d.root,label:designWithFolder(d.root,void 0,{absolute:!0}),hint:d.root===here?`${d.canvasUrl} \xB7 this directory`:d.canvasUrl})),{value:ALL,label:`All ${daemons.length} canvases`}],...here?{initialValue:here}:{}});if(isCancel(chosen))fail("stop","cancelled.");await stopEach(chosen===ALL?daemons:daemons.filter((d)=>d.root===chosen));return}if(!args.design&&!await designHere()){let daemons=await listDaemons();if(daemons.length===0){console.log("velloo: no canvas daemons running.");return}fail("stop",[`there is no design in this directory. ${daemons.length} canvas${daemons.length===1?" is":"es are"} running \u2014 stop one by its design folder, or all of them with \`velloo stop --all\`:`,...daemons.map((d)=>` ${canvasLine(d)}`)].join(`
|
|
3
|
+
`))}let folder=await resolveDesign(args.design,"stop"),root=daemonRoot(folder);if(await stopDaemon(root)){console.log(`velloo: stopped ${designWithFolder(folder)}`);return}console.log(`velloo: no canvas running for ${designWithFolder(folder)}`);let others=await listDaemons();if(others.length===0)return;console.log(import_picocolors.default.dim(` ${others.length} canvas${others.length===1?"":"es"} running elsewhere \u2014 run \`velloo stop\` to pick, or \`velloo stop --all\`:`));for(let d of others)console.log(import_picocolors.default.dim(` ${canvasLine(d)}`))}});export{stop_default as default};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import"./chunk-kz4423th.js";import{refreshUpdateCache}from"./chunk-7k7dpj5y.js";import{defineCommand}from"./chunk-2smsg2ct.js";var update_check_default=defineCommand({meta:{name:"__update_check",description:"Internal release check",hidden:!0},async run(){await refreshUpdateCache()}});export{update_check_default as default};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{ScreenSchema}from"./chunk-nte0t7v3.js";import{detectTailwindMajor,emitCode,moduleTarget,v3ClassIssues,classNamesInJsx,styleChannelOf,loadDesignFolder,hostAppRootFrom,resolveProviders}from"./chunk-5ezzc1h2.js";import"./chunk-n9t36h0q.js";import"./chunk-c4fym47a.js";import"./chunk-80fjfyha.js";import{fail}from"./chunk-s23gtejf.js";import{findDesignConfig}from"./chunk-bhx8k09w.js";import{createProgress}from"./chunk-pjtg3wnm.js";import{DESIGN_ARG_DESCRIPTION,resolveDesign,pickScreen}from"./chunk-td5z2sm4.js";import{defineCommand}from"./chunk-2smsg2ct.js";import{readFile,writeFile}from"fs/promises";import{isAbsolute,resolve}from"path";import{stdout}from"process";async function folderEmitContext(screenPath,screen){let found=await findDesignConfig(screenPath);if(!found)return{};let design=await loadDesignFolder(found.folder),{providers,defaultProvider}=await resolveProviders(design.config,found.folder),provider=screen.library&&providers[screen.library]||defaultProvider,adapter=provider,target;if(adapter.codegenModule){let manifest=await provider.loadManifest();target=moduleTarget(manifest.filter((c)=>c.source!=="velloo").map((c)=>c.id),adapter.codegenModule)}let inlineStyle=styleChannelOf(provider,design.config.styling?.framework).kind==="style";return{snippets:design.snippets,...design.config.extensions?{extensions:design.config.extensions}:{},...target?{target}:{},...inlineStyle?{inlineStyle:!0}:{}}}var emit_default=defineCommand({meta:{name:"emit",description:"Print or write agent-consumed IR for a screen."},args:{screen:{type:"positional",required:!1,description:"Screen id, or a path to a screen JSON. Omit to pick interactively."},design:{type:"string",description:DESIGN_ARG_DESCRIPTION},to:{type:"string",description:"Write IR as JSON to this path. Omit to print the JSX body to stdout (agent-friendly when piped)."},"components-alias":{type:"string",description:'Override the import prefix the IR mentions in snippet identifiers. Defaults to .design/config.json#codegen.componentsAlias, else "@/components/ui".'}},async run({args}){let interactive=Boolean(process.stdin.isTTY),screenArg=args.screen,screenPath=!!screenArg&&(screenArg.includes("/")||screenArg.endsWith(".json"))?resolve(screenArg):(await pickScreen(await resolveDesign(args.design,"emit",{designFlag:"--design"}),screenArg,interactive,"emit")).path,screenJson=JSON.parse(await readFile(screenPath,"utf8")),screen=ScreenSchema.parse(screenJson),progress=createProgress();progress.start("preparing code");try{let componentsAlias=args["components-alias"]??await readConfigAlias(screenPath),context=await folderEmitContext(screenPath,screen);progress.step("generating code");let result=await emitCode(screen,{...componentsAlias?{componentsAlias}:{},...context});if(!result.ok){progress.fail("code generation failed");let e=result.error;if(e.kind==="UnknownComponent")fail("emit",`unknown component: ${JSON.stringify(e.ref)}`);else if(e.kind==="SnippetNotFound")fail("emit",`snippet not found: ${JSON.stringify(e.snippetId)}`);else fail("emit",`screen not found: ${JSON.stringify(e.screenId)}`)}let found=await findDesignConfig(screenPath),tailwindV3Compat=found&&!context?.target&&!context?.inlineStyle?detectTailwindMajor(hostAppRootFrom(found.folder,found.config.hostApp))===3?v3ClassIssues([...result.value.classesUsed,...result.value.snippetsUsed.flatMap((s)=>classNamesInJsx(s.jsx))]):[]:[];if(args.to){progress.step("writing code");let outPath=isAbsolute(args.to)?args.to:resolve(args.to),ir=tailwindV3Compat.length>0?{...result.value,tailwindV3Compat}:result.value;await writeFile(outPath,JSON.stringify(ir,null,2),"utf8"),progress.succeed("generated code"),console.log(`velloo emit: wrote ${outPath}`);return}if(progress.succeed("generated code"),stdout.write(`// screen: ${result.value.screen.id} (${result.value.screen.name})
|
|
3
|
+
`),stdout.write(`// components: ${result.value.componentsUsed.join(", ")||"(none)"}
|
|
4
|
+
`),result.value.iconsUsed.length>0)stdout.write(`// icons (lucide): ${result.value.iconsUsed.join(", ")}
|
|
5
|
+
`);if(result.value.snippetsUsed.length>0)stdout.write(`// snippets: ${result.value.snippetsUsed.map((s)=>`${s.componentName}(${s.id})`).join(", ")}
|
|
6
|
+
`);for(let issue of tailwindV3Compat)stdout.write(issue.v3?`// tailwind v3 host: \`${issue.class}\` \u2192 \`${issue.v3}\` (${issue.note})
|
|
7
|
+
`:`// tailwind v3 host: \`${issue.class}\` \u2014 ${issue.note}
|
|
8
|
+
`);stdout.write(`
|
|
9
|
+
`),stdout.write(`${result.value.jsx}
|
|
10
|
+
`)}catch(error){throw progress.fail("code generation failed"),error}}});async function readConfigAlias(screenPath){return(await findDesignConfig(screenPath))?.config.codegen?.componentsAlias}export{emit_default as default};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{init_default,runInit2}from"./chunk-7bvvbsqy.js";import"./chunk-d9p6s05n.js";import"./chunk-9nhw49vv.js";import"./chunk-jx11jvq8.js";import"./chunk-td5z2sm4.js";import"./chunk-6zz9kfbd.js";import"./chunk-hfzg98c8.js";import"./chunk-7njj1qmq.js";import"./chunk-qgwhd4n6.js";import"./chunk-2fgfex9b.js";import"./chunk-k9219kmj.js";import"./chunk-80fjfyha.js";import"./chunk-5ezzc1h2.js";import"./chunk-c4fym47a.js";import"./chunk-as08hzp3.js";import"./chunk-n9t36h0q.js";import"./chunk-7k7dpj5y.js";import"./chunk-qdnb2t6a.js";import"./chunk-kz4423th.js";import"./chunk-s23gtejf.js";import"./chunk-nte0t7v3.js";import"./chunk-cvn689d5.js";export{init_default as default,runInit2 as runInit};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{isCancel,select}from"./chunk-80fjfyha.js";import{closePooledBrowser,renderScreen,screenshot}from"./chunk-c4fym47a.js";import{ScreenSchema}from"./chunk-nte0t7v3.js";import{writeText,registryForScreen,renderPassForScreen}from"./chunk-5ezzc1h2.js";import"./chunk-n9t36h0q.js";import{fail}from"./chunk-s23gtejf.js";import{captureWithBrowserSetup}from"./chunk-2fgfex9b.js";import{findDesignConfig}from"./chunk-bhx8k09w.js";import{loadPipeline}from"./chunk-nycs0z7h.js";import{withAssetServer}from"./chunk-0zen7bzb.js";import{createProgress}from"./chunk-pjtg3wnm.js";import{DESIGN_ARG_DESCRIPTION,resolveDesign,pickScreen}from"./chunk-td5z2sm4.js";import{defineCommand}from"./chunk-2smsg2ct.js";import{readFile}from"fs/promises";import{extname,isAbsolute,resolve}from"path";var render_default=defineCommand({meta:{name:"render",description:"dev: render a screen headless to .html or .png"},args:{screen:{type:"positional",required:!1,description:"Screen id, or a path to a screen JSON. Omit to pick interactively."},design:{type:"string",description:DESIGN_ARG_DESCRIPTION},to:{type:"string",description:"Output path; extension picks the format (.html | .png). Default: ./<screen>.html"},w:{type:"string",description:"Viewport width in px (default: 1440)"},h:{type:"string",description:"Viewport height in px (default: 900)"}},async run({args}){let interactive=Boolean(process.stdin.isTTY),screenArg=args.screen,looksLikePath=!!screenArg&&(screenArg.includes("/")||screenArg.endsWith(".json")),folder,screenPath;if(looksLikePath&&screenArg)if(screenPath=resolve(screenArg),args.design)folder=await resolveDesign(args.design,"render",{designFlag:"--design"});else{let found=await findDesignConfig(screenPath);if(!found)fail("render",`${screenPath} is not inside a velloo design folder (no .design/config.json above it). Pass --design with a design name or a path.`);folder=found.folder}else folder=await resolveDesign(args.design,"render",{designFlag:"--design"}),screenPath=(await pickScreen(folder,screenArg,interactive,"render")).path;let screen=ScreenSchema.parse(JSON.parse(await readFile(screenPath,"utf8"))),viewport={w:args.w?Number(args.w):1440,h:args.h?Number(args.h):900},outPath;if(args.to)outPath=isAbsolute(args.to)?args.to:resolve(args.to);else{let ext="html";if(interactive){let fmt=await select({message:"Output format?",options:[{value:"html",label:"HTML",hint:"no browser needed"},{value:"png",label:"PNG",hint:"screenshot (needs a headless browser)"}]});if(isCancel(fmt))fail("render","cancelled.");ext=fmt}outPath=resolve(`${screen.id}.${ext}`)}let out=extname(outPath).toLowerCase();if(out!==".html"&&out!==".png")fail("render",`unsupported output extension ${JSON.stringify(out)}. Use .html or .png.`);let progress=createProgress();progress.start("preparing render");try{let pipeline=await loadPipeline(folder),{design,config,providers,defaultProvider,snapshotCss}=pipeline,theme=design.theme,registry=registryForScreen(screen,providers,defaultProvider,config.extensions??{}),renderPass=renderPassForScreen(screen,providers,defaultProvider,theme),renderHtml=async(baseHref)=>{let{html}=await renderScreen(screen,theme,{viewport,snapshotCss,registry,snippets:design.snippets,renderPass,customCss:design.customCss,...baseHref?{baseHref}:{}});return html};if(out===".html"){progress.step("rendering HTML"),await writeText(outPath,await renderHtml()),progress.succeed("rendered HTML"),console.log(`velloo render: wrote ${outPath} (screen=${screen.id})`);return}progress.step("rendering screen"),await withAssetServer(folder,null,async(baseHref)=>{let html=await renderHtml(baseHref);try{await captureWithBrowserSetup("render",async()=>{progress.step("capturing PNG");try{await screenshot({html,viewport,outPath})}catch(error){throw progress.fail("PNG capture failed"),error}})}finally{await closePooledBrowser()}}),progress.succeed("rendered PNG"),console.log(`velloo render: wrote ${outPath} (screen=${screen.id})`)}catch(error){throw progress.fail("render failed"),error}}});export{render_default as default};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import"./chunk-nte0t7v3.js";import{localDesignOf}from"./chunk-5ezzc1h2.js";import"./chunk-n9t36h0q.js";import"./chunk-c4fym47a.js";import"./chunk-80fjfyha.js";import{AGENT_IDS,PROJECT_AGENT_IDS,GLOBAL_AGENT_IDS,resolveProjectRoot,MANUAL_AGENT_ID,manualSetupText,askAgentWiring,localDesignScopeProblem,connect}from"./chunk-9nhw49vv.js";import"./chunk-kz4423th.js";import{DesignFolderFormatError,assertFolderFormatCurrent}from"./chunk-k9219kmj.js";import{fail}from"./chunk-s23gtejf.js";import{createProgress}from"./chunk-pjtg3wnm.js";import{DESIGN_ARG_DESCRIPTION,resolveDesign}from"./chunk-td5z2sm4.js";import"./chunk-as08hzp3.js";import{require_picocolors}from"./chunk-jrsknzjt.js";import{__toESM,defineCommand}from"./chunk-2smsg2ct.js";import{resolve}from"path";var import_picocolors=__toESM(require_picocolors(),1);var connect_default=defineCommand({meta:{name:"connect",description:"Wire the velloo MCP server into your AI coding agent's config"},args:{design:{type:"positional",required:!1,description:DESIGN_ARG_DESCRIPTION},agent:{type:"string",description:`Comma-separated agents: ${AGENT_IDS.join(", ")}, manual \u2014 print the config for any other agent (default ${PROJECT_AGENT_IDS.join(",")})`},projectRoot:{type:"string",description:"Where to write the config (default: the velloo.json root that registers the folder, else the nearest package.json above it)"},http:{type:"boolean",default:!1,description:"Wire the HTTP transport (agent dials a running server) instead of stdio"},mcpUrl:{type:"string",description:"MCP server URL for --http, as printed by `velloo mcp --http`"},skill:{type:"boolean",default:!0,description:"Install the velloo-design Claude Code skill into .claude/skills"}},async run({args}){let folder=await resolveDesign(args.design,"connect",{interactive:!0});try{assertFolderFormatCurrent(folder)}catch(err){if(!(err instanceof DesignFolderFormatError))throw err;console.log(import_picocolors.default.yellow(`\u26A0 ${err.message.slice(8)}`))}let interactive=Boolean(process.stdin.isTTY),agents,manual=!1,local=localDesignOf(folder)!==null;if(args.agent){agents=args.agent.split(",").map((s)=>s.trim()).filter(Boolean);let problem=localDesignScopeProblem(folder,agents);if(problem)fail("connect",problem)}else if(interactive){let wiring=await askAgentWiring({projectRoot:await resolveProjectRoot(folder),globalOnly:local});if(wiring===null)fail("connect","cancelled.");if(wiring.agents.length===0&&!wiring.manual){console.log(import_picocolors.default.dim("No agents selected \u2014 nothing wired."));return}manual=wiring.manual,agents=wiring.agents}else agents=local?GLOBAL_AGENT_IDS:PROJECT_AGENT_IDS;if(agents.includes(MANUAL_AGENT_ID))manual=!0,agents=agents.filter((id)=>id!==MANUAL_AGENT_ID);if(manual){console.log(""),console.log(import_picocolors.default.bold(" Manual MCP setup"));for(let line of manualSetupText().split(`
|
|
3
|
+
`))console.log(` ${line}`);console.log("")}if(agents.length===0)return;let progress=createProgress();progress.start("connecting agent");let result;try{result=await connect({designFolder:folder,agents,projectRoot:args.projectRoot?resolve(args.projectRoot):void 0,transport:args.http?"http":"stdio",mcpUrl:args.mcpUrl,installSkill:args.skill})}catch(error){throw progress.fail("agent connection failed"),error}if(result.unknownAgents.length>0)progress.fail("agent connection failed"),fail("connect",`unknown agent(s): ${result.unknownAgents.join(", ")}. Valid: ${AGENT_IDS.join(", ")}.`);progress.succeed("connected agent"),console.log(""),console.log(import_picocolors.default.green("\u2713 Connected velloo to your agent.")),console.log("");for(let c of result.configs)console.log(` ${c.action==="created"?"wrote ":"updated "} ${import_picocolors.default.cyan(c.path)}`);if(result.plugin)console.log(` plugin ${import_picocolors.default.cyan("velloo@velloo")} ${import_picocolors.default.dim(`(skills + commands + subagents \u2014 local marketplace at ${result.plugin.marketplaceDir})`)}`);for(let s of result.skills??[])console.log(` skill ${import_picocolors.default.cyan(s.path??s.name)}`);if(result.geminiExtension)console.log(` gemini ${import_picocolors.default.cyan(result.geminiExtension.dir)} ${result.geminiExtension.linked?import_picocolors.default.dim("(linked)"):import_picocolors.default.dim(`(link it: gemini extensions link ${result.geminiExtension.dir})`)}`);if(result.cursorRules?.installed&&result.cursorRules.path)console.log(` rule ${import_picocolors.default.cyan(result.cursorRules.path)}`);let designArg=args.design?` ${args.design}`:"";if(console.log(""),console.log(import_picocolors.default.bold(" Next")),result.transport==="http")console.log(` 1. ${import_picocolors.default.cyan(`velloo mcp --http${designArg}`)} ${import_picocolors.default.dim("\u2014 starts the MCP server your agent dials")}`),console.log(" 2. Restart your agent so it loads the new MCP config.");else console.log(` 1. Restart your agent so it loads the new MCP config ${import_picocolors.default.dim("\u2014 it starts velloo itself")}.`),console.log(` 2. ${import_picocolors.default.cyan(`velloo run${designArg}`)} ${import_picocolors.default.dim("\u2014 optional: open the canvas to watch")}`);console.log("")}});export{connect_default as default};
|
package/cli.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
import"./chunk-s23gtejf.js";import{COMMANDS}from"./chunk-
|
|
3
|
+
import"./chunk-s23gtejf.js";import{COMMANDS}from"./chunk-qdnb2t6a.js";import{TOOL_VERSION}from"./chunk-kz4423th.js";import{maybeNotifyAboutUpdate}from"./chunk-7k7dpj5y.js";import{defineCommand,runMain}from"./chunk-2smsg2ct.js";var main=defineCommand({meta:{name:"velloo",version:TOOL_VERSION,description:"Open-source, local-first canvas for agent-driven design."},subCommands:COMMANDS});await runMain(main);var command=process.argv[2];if(!["mcp","__daemon","__update_check","run","upgrade"].includes(command??""))await maybeNotifyAboutUpdate();
|
package/launcher.cjs
CHANGED
|
@@ -54,7 +54,7 @@ if (process.platform === "win32" && process.argv.length === 3 && process.argv[2]
|
|
|
54
54
|
// npm rewrote this launcher's package in place, so re-entering by the same
|
|
55
55
|
// path runs the NEW velloo — which is the one that must migrate the design
|
|
56
56
|
// folder, since only it knows the format it migrated towards.
|
|
57
|
-
const migrate = spawnSync(process.execPath, [__filename, "upgrade", "--
|
|
57
|
+
const migrate = spawnSync(process.execPath, [__filename, "upgrade", "--design-only"], {
|
|
58
58
|
stdio: "inherit",
|
|
59
59
|
});
|
|
60
60
|
process.exit(migrate.status == null ? 1 : migrate.status);
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "velloo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Local-first, code-shaped design canvas — your AI agent designs with your real components, in your repo",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
|
-
"homepage": "https://
|
|
7
|
+
"homepage": "https://velloo.design",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "git+https://github.com/velloo-design/velloo.git"
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"bun"
|
|
27
27
|
],
|
|
28
28
|
"bin": {
|
|
29
|
-
"velloo": "
|
|
29
|
+
"velloo": "launcher.cjs"
|
|
30
30
|
},
|
|
31
31
|
"engines": {
|
|
32
32
|
"node": ">=18"
|
|
@@ -15,7 +15,13 @@ export const HELPER_DESCRIPTORS: readonly ComponentDescriptor[] = [
|
|
|
15
15
|
group: "layout",
|
|
16
16
|
family: "Box",
|
|
17
17
|
source: "velloo",
|
|
18
|
-
props: [
|
|
18
|
+
props: [
|
|
19
|
+
// Undiscoverable before this: an agent reproducing inline markup
|
|
20
|
+
// concluded Box could only be a div and reached for classes instead.
|
|
21
|
+
{ name: "as", type: "string", optional: true, control: "string" },
|
|
22
|
+
],
|
|
23
|
+
designModeNotes:
|
|
24
|
+
'A plain div by default; `as` renders a lowercase HTML tag instead — "span" for an inline run inside a sentence, "ul"/"li", "section". Anything else falls back to div.',
|
|
19
25
|
example: { className: "flex flex-col gap-6 px-8 py-12" },
|
|
20
26
|
},
|
|
21
27
|
{
|
|
@@ -63,6 +63,7 @@ export function createProvider(): FrameworkAdapter {
|
|
|
63
63
|
factory: null,
|
|
64
64
|
defaultPath: "antd-theme.ts",
|
|
65
65
|
},
|
|
66
|
+
ownedModules: { packages: ["antd"] },
|
|
66
67
|
// canvasBundleSpec is deliberately absent in v1: the server's bundle-entry
|
|
67
68
|
// builder only implements the emotion style runtime, so antd folders render
|
|
68
69
|
// via the in-process cssinjs SSR path. Extending it means a new
|
|
@@ -63,6 +63,7 @@ export function createProvider(): FrameworkAdapter {
|
|
|
63
63
|
factory: "extendTheme",
|
|
64
64
|
defaultPath: "chakra-theme.ts",
|
|
65
65
|
},
|
|
66
|
+
ownedModules: { packages: ["@chakra-ui/react"] },
|
|
66
67
|
// canvasBundleSpec is deliberately absent in v1: the server's bundle-entry
|
|
67
68
|
// builder implements only the MUI-shaped emotion style runtime (its entry
|
|
68
69
|
// template expects `ThemeProvider` + `createTheme` from `stylesModule`);
|
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { dirname, join } from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import {
|
|
3
|
+
import { helperSourcePath } from "@velloo/helpers/paths";
|
|
4
|
+
import {
|
|
5
|
+
type CanvasComponentSpec,
|
|
6
|
+
type FrameworkAdapter,
|
|
7
|
+
type Manifest,
|
|
8
|
+
TAILWIND_CLASSNAME,
|
|
9
|
+
} from "@velloo/provider";
|
|
4
10
|
import { resolveProviderSrcDir } from "@velloo/provider/src-dir";
|
|
5
11
|
import { NONE_INLINE_INTRO, NONE_INTRO } from "./intro.ts";
|
|
6
12
|
import { NONE_MANIFEST } from "./manifest.ts";
|
|
7
13
|
import { registry } from "./registry.ts";
|
|
8
14
|
import { inlineRegistry } from "./registry-inline.ts";
|
|
9
15
|
|
|
16
|
+
const PRIMITIVES = new Set(["Box", "Stack", "Container", "Card", "Button", "Input"]);
|
|
17
|
+
/** Typography the inline channel restyles; the Tailwind channel reuses the helpers. */
|
|
18
|
+
const INLINE_TYPOGRAPHY = new Set(["Heading", "Text"]);
|
|
19
|
+
|
|
10
20
|
export { Box, Button, Card, Container, Input, Stack } from "./components.tsx";
|
|
11
21
|
export { NONE_MANIFEST } from "./manifest.ts";
|
|
12
22
|
export { registry } from "./registry.ts";
|
|
@@ -53,5 +63,36 @@ export function createProvider(): FrameworkAdapter {
|
|
|
53
63
|
// Inline-styled primitives for the `style` channel; Tailwind-classed for
|
|
54
64
|
// every other channel. Lets a `none/none` folder paint with the JIT off.
|
|
55
65
|
registryForChannel: (kind) => (kind === "style" ? inlineRegistry : registry),
|
|
66
|
+
// No framework to install, so this only matters beside repository
|
|
67
|
+
// components: the screen then client-mounts, and these primitives have to
|
|
68
|
+
// render in the same browser tree as the app's own components.
|
|
69
|
+
canvasBundleSpec: {
|
|
70
|
+
styleRuntime: { kind: "none" },
|
|
71
|
+
onlyWithRepository: true,
|
|
72
|
+
components: (ids, context) => {
|
|
73
|
+
const inline = context?.channel === "style";
|
|
74
|
+
return ids.flatMap((id): CanvasComponentSpec[] => {
|
|
75
|
+
const own =
|
|
76
|
+
PRIMITIVES.has(id) || (inline && INLINE_TYPOGRAPHY.has(id))
|
|
77
|
+
? join(srcDir, inline ? "components-inline.tsx" : "components.tsx")
|
|
78
|
+
: helperSourcePath(id);
|
|
79
|
+
return own
|
|
80
|
+
? [
|
|
81
|
+
{
|
|
82
|
+
id,
|
|
83
|
+
sources: [
|
|
84
|
+
{
|
|
85
|
+
importPath: own,
|
|
86
|
+
exportName: id,
|
|
87
|
+
fidelity: "exact" as const,
|
|
88
|
+
note: "Velloo primitive, mounted beside the app's components.",
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
]
|
|
93
|
+
: [];
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
},
|
|
56
97
|
};
|
|
57
98
|
}
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
* vocabulary positively rather than correcting a shadcn claim.
|
|
7
7
|
*/
|
|
8
8
|
export const NONE_INTRO: readonly string[] = [
|
|
9
|
-
"**This folder has no component library** — only bare primitives wrapping plain HTML: `Box`/`Stack`/`Container` for layout, `Card`, `Button`, `Input`, plus the velloo helpers (`Heading`/`Text`, `Image`, `Gradient`, `Layer`, `SVG`, `Divider`, `Placeholder`, `Icon`).
|
|
9
|
+
"**This folder has no component library** — only bare primitives wrapping plain HTML: `Box`/`Stack`/`Container` for layout, `Card`, `Button`, `Input`, plus the velloo helpers (`Heading`/`Text`, `Image`, `Gradient`, `Layer`, `SVG`, `Divider`, `Placeholder`, `Icon`). The primitives stop there: for a `Badge`/`Tabs`/`Dialog`, use the app's own component when `list_components` shows one on a Repo shelf, else build it from primitives or a snippet. Call `list_components` for the exact set. Styling is **Tailwind classes**.",
|
|
10
10
|
"",
|
|
11
11
|
];
|
|
12
12
|
|
|
13
13
|
export const NONE_INLINE_INTRO: readonly string[] = [
|
|
14
|
-
"**This folder has no component library and no CSS framework** — bare primitives wrapping plain HTML (`Box`/`Stack`/`Container`, `Card`, `Button`, `Input`) plus the velloo helpers (`Heading`/`Text`, `Image`, `Icon`, `SVG`, `Divider`, `Gradient`, `Layer`, `Placeholder`).
|
|
14
|
+
"**This folder has no component library and no CSS framework** — bare primitives wrapping plain HTML (`Box`/`Stack`/`Container`, `Card`, `Button`, `Input`) plus the velloo helpers (`Heading`/`Text`, `Image`, `Icon`, `SVG`, `Divider`, `Gradient`, `Layer`, `Placeholder`). The primitives stop there: for a `Badge`/`Tabs`/`Dialog`, use the app's own component when `list_components` shows one on a Repo shelf, else build it from primitives or a snippet. Call `list_components` for the exact set.",
|
|
15
15
|
"",
|
|
16
16
|
'**Style through inline `style` objects.** `update_props { style: { display: "flex", gap: "16px", padding: "24px", borderRadius: "8px", color: "var(--color-foreground)" } }` — a plain React style object (merges shallowly; an inner `null` drops a key, `style: null` clears). Reference theme tokens as CSS variables (`var(--color-primary)`, `var(--radius)`) from `get_theme` so the design stays themable. `emit_code` emits `style={{…}}` on plain elements — no imports, no Tailwind. Tailwind utility diagnostics do not apply.',
|
|
17
17
|
"",
|
|
@@ -2,7 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { BoardGroupSchema } from "./board.ts";
|
|
3
3
|
import { ExtensionSchema } from "./extension.ts";
|
|
4
4
|
import { CURRENT_SCHEMA_VERSION } from "./migrate.ts";
|
|
5
|
-
import { FeedbackPrefsSchema } from "./repo.ts";
|
|
5
|
+
import { DesignNameSchema, FeedbackPrefsSchema } from "./repo.ts";
|
|
6
6
|
|
|
7
7
|
export const ViewportPresetSchema = z.object({
|
|
8
8
|
name: z.string().min(1),
|
|
@@ -65,6 +65,25 @@ export type CodegenConfig = z.infer<typeof CodegenConfigSchema>;
|
|
|
65
65
|
export const HostAppSchema = z.object({
|
|
66
66
|
root: z.string().min(1),
|
|
67
67
|
aliases: z.record(z.string().min(1), z.string().min(1)).optional(),
|
|
68
|
+
/**
|
|
69
|
+
* The app's preview entry: a module whose default export wraps mounted
|
|
70
|
+
* repository components in the context they need (providers, global CSS).
|
|
71
|
+
* Resolved from the design folder root. Absent ⇒ `preview.{tsx,jsx,ts,js}`
|
|
72
|
+
* in the design folder (`preview.<appKey>.*` for a named host app), then a
|
|
73
|
+
* built-in framework recipe, then no wrapper.
|
|
74
|
+
*/
|
|
75
|
+
preview: z.string().min(1).optional(),
|
|
76
|
+
/**
|
|
77
|
+
* Bounds repository-component discovery beyond what the app's entries and
|
|
78
|
+
* routes import: `include` adds component roots (files or directories,
|
|
79
|
+
* host-root relative), `exclude` drops matching specifiers or paths.
|
|
80
|
+
*/
|
|
81
|
+
components: z
|
|
82
|
+
.object({
|
|
83
|
+
include: z.array(z.string().min(1)).optional(),
|
|
84
|
+
exclude: z.array(z.string().min(1)).optional(),
|
|
85
|
+
})
|
|
86
|
+
.optional(),
|
|
68
87
|
});
|
|
69
88
|
|
|
70
89
|
export type HostApp = z.infer<typeof HostAppSchema>;
|
|
@@ -82,6 +101,13 @@ export const ConfigSchema = z
|
|
|
82
101
|
.object({
|
|
83
102
|
schemaVersion: z.literal(CURRENT_SCHEMA_VERSION),
|
|
84
103
|
toolVersion: z.string().min(1),
|
|
104
|
+
/**
|
|
105
|
+
* The design's name — what commands, `velloo.json`'s `defaultDesign`, the
|
|
106
|
+
* canvas title and agents call it. Lives here, not in the manifest, so a
|
|
107
|
+
* design carries its identity wherever it is stored. Unique among the
|
|
108
|
+
* designs of one checkout.
|
|
109
|
+
*/
|
|
110
|
+
name: DesignNameSchema,
|
|
85
111
|
/**
|
|
86
112
|
* Stable folder identity for velloo-cloud (a UUID). Published share links
|
|
87
113
|
* carry it server-side, so every clone of the folder finds its links (and
|
|
@@ -103,3 +103,29 @@ export const ExtensionSchema = z.object({
|
|
|
103
103
|
});
|
|
104
104
|
|
|
105
105
|
export type Extension = z.infer<typeof ExtensionSchema>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* `repo-components.json` in a design folder: checked-in corrections to what
|
|
109
|
+
* repository-component discovery infers. Keyed `<importPath>#<export>` (or
|
|
110
|
+
* `…#<export>.<Member>` for a compound part). Overrides refine the inferred
|
|
111
|
+
* entry; they never replace discovery, and a key or prop that no longer
|
|
112
|
+
* matches anything discovered is reported as stale.
|
|
113
|
+
*/
|
|
114
|
+
export const RepoComponentOverrideSchema = z.object({
|
|
115
|
+
description: z.string().optional(),
|
|
116
|
+
/** Leave this component out of the catalog. */
|
|
117
|
+
exclude: z.boolean().optional(),
|
|
118
|
+
/** Snippet drawn in the component's place when it can't render for real. */
|
|
119
|
+
proxy: z.string().min(1).optional(),
|
|
120
|
+
/** Replaces or adds prop descriptors by name. */
|
|
121
|
+
props: z.array(ExtensionPropDescriptorSchema).optional(),
|
|
122
|
+
/** Named preview states: state name → props. */
|
|
123
|
+
states: z.record(z.string().min(1), z.record(z.string(), z.unknown())).optional(),
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
export const RepoComponentsManifestSchema = z.object({
|
|
127
|
+
components: z.record(z.string().min(1), RepoComponentOverrideSchema),
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
export type RepoComponentOverride = z.infer<typeof RepoComponentOverrideSchema>;
|
|
131
|
+
export type RepoComponentsManifest = z.infer<typeof RepoComponentsManifestSchema>;
|