velloo 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/README.md +112 -128
  2. package/THIRD-PARTY-NOTICES.md +58 -58
  3. package/canvas/assets/InitWizard-C1CkcS7C.js +3 -0
  4. package/canvas/assets/index-CZPX0col.css +2 -0
  5. package/canvas/assets/index-D7gy-ZUv.js +49 -0
  6. package/canvas/assets/lucide-all-B49qZ9YE.js +1 -0
  7. package/canvas/assets/radix-CuVEihKE.js +41 -0
  8. package/canvas/assets/react-C1iE8mnY.js +9 -0
  9. package/canvas/assets/rolldown-runtime-XKyaHtl9.js +1 -0
  10. package/canvas/assets/vendor-DXkvBgGY.js +58 -0
  11. package/canvas/assets/wand-sparkles-BxGgFkAt.js +1 -0
  12. package/canvas/index.html +6 -6
  13. package/{chunk-seaar5na.js → chunk-0rvdh1j3.js} +1 -1
  14. package/chunk-12pgt83m.js +8 -0
  15. package/chunk-12vc3f1h.js +3 -0
  16. package/{chunk-qvdvxqs0.js → chunk-28mhcvw2.js} +1 -1
  17. package/{chunk-ysf9388d.js → chunk-3zm7ydna.js} +1 -1
  18. package/{chunk-qn05hn7a.js → chunk-457fm9yy.js} +5 -3
  19. package/chunk-46jg9aqy.js +40 -0
  20. package/chunk-5gwh0zpn.js +3 -0
  21. package/{chunk-bsn761jv.js → chunk-5hb1e233.js} +1 -1
  22. package/{chunk-3f2p94wa.js → chunk-5ts4fvd9.js} +1 -1
  23. package/{chunk-c11n1tve.js → chunk-62amy8bj.js} +1 -1
  24. package/{chunk-ktps9v0k.js → chunk-6p8zwxxx.js} +1 -1
  25. package/{chunk-02gpgqj4.js → chunk-75gfv9g4.js} +10 -11
  26. package/chunk-84qjmqmz.js +2 -0
  27. package/{chunk-6adv9eke.js → chunk-85m9p67t.js} +2 -2
  28. package/chunk-91qesxwh.js +2 -0
  29. package/{chunk-ck3bg8rf.js → chunk-976rm76x.js} +1 -1
  30. package/chunk-99ccjbaa.js +4 -0
  31. package/{chunk-8kn6tp4b.js → chunk-9hc7m55p.js} +3 -4
  32. package/{chunk-xc6mats8.js → chunk-a7xka0bj.js} +1 -1
  33. package/chunk-ak57bgnh.js +2 -0
  34. package/chunk-bf5808x5.js +2 -0
  35. package/{chunk-00n2d68z.js → chunk-bj47gjs9.js} +1 -1
  36. package/chunk-d0m56cjx.js +2 -0
  37. package/chunk-d6a6198y.js +3 -0
  38. package/{chunk-r014f76h.js → chunk-etv7qsw7.js} +1 -1
  39. package/chunk-f2793pj6.js +85 -0
  40. package/{chunk-a5mxgvcz.js → chunk-fnv123mm.js} +1 -1
  41. package/{chunk-pjtg3wnm.js → chunk-fzevxpdz.js} +1 -1
  42. package/chunk-ghwy99py.js +68 -0
  43. package/chunk-gtt1qww8.js +2 -0
  44. package/chunk-hhkjqvww.js +1501 -0
  45. package/{chunk-fejhav0p.js → chunk-hrvqwp8z.js} +1 -1
  46. package/{chunk-6600wkmq.js → chunk-hxk0wkt3.js} +1 -1
  47. package/{chunk-f8jchnwe.js → chunk-jc95phff.js} +2 -2
  48. package/chunk-kwym0g80.js +11 -0
  49. package/chunk-kxcjme3n.js +6 -0
  50. package/{chunk-pasvz8xw.js → chunk-mkctjrrz.js} +2 -2
  51. package/{chunk-v6w8akph.js → chunk-mknhfnkn.js} +1 -1
  52. package/{chunk-yp39f93e.js → chunk-mseawt58.js} +89 -55
  53. package/{chunk-gv209d5j.js → chunk-nccfyeyy.js} +1 -1
  54. package/{chunk-tmjs6xas.js → chunk-npnxs0fy.js} +1 -1
  55. package/{chunk-x61f42fj.js → chunk-p9p2vbat.js} +2 -2
  56. package/chunk-pqc7dbhc.js +2 -0
  57. package/{chunk-tax7fxav.js → chunk-qc7c328q.js} +1 -1
  58. package/chunk-qe6pp4p6.js +72 -0
  59. package/{chunk-3jqbybmp.js → chunk-qwy0jba8.js} +1 -1
  60. package/{chunk-5tatkt2j.js → chunk-s26bgjqz.js} +1 -1
  61. package/{chunk-9kvbe53e.js → chunk-s8pqbr4n.js} +1 -1
  62. package/{chunk-p93x4pn2.js → chunk-tjy12q19.js} +1 -1
  63. package/{chunk-9b4akcfp.js → chunk-v1by80c5.js} +1 -1
  64. package/chunk-vdy4ave9.js +2 -0
  65. package/chunk-vwhee991.js +3 -0
  66. package/chunk-wf7r45wh.js +12 -0
  67. package/{chunk-bpb97rsk.js → chunk-x4jsr5et.js} +1 -1
  68. package/{chunk-z9kcdgj8.js → chunk-x9gk2n9v.js} +1 -1
  69. package/chunk-xxjevh62.js +2 -0
  70. package/{chunk-6wfvb07c.js → chunk-y2y1b3zm.js} +1 -1
  71. package/chunk-y6jq6y8t.js +2 -0
  72. package/cli.js +1 -1
  73. package/package.json +3 -3
  74. package/pkgs/helpers/src/icon-data.ts +868 -172
  75. package/pkgs/shadcn-snapshot/dist/manifest.json +348 -0
  76. package/pkgs/shadcn-snapshot/src/components/canvas-portal.tsx +3 -3
  77. package/plugins/claude/velloo/.claude-plugin/plugin.json +5 -2
  78. package/plugins/gemini/gemini-extension.json +7 -2
  79. package/canvas/assets/index-CkVteRZ9.css +0 -2
  80. package/canvas/assets/index-DFOlwAKW.js +0 -31
  81. package/canvas/assets/lucide-all-CezGNjGW.js +0 -1
  82. package/canvas/assets/radix-gmpYzWRH.js +0 -41
  83. package/canvas/assets/react-D0Ec-185.js +0 -9
  84. package/canvas/assets/rolldown-runtime-hePW80VL.js +0 -1
  85. package/canvas/assets/vendor-CKmQ-Zst.js +0 -53
  86. package/chunk-0ztxyzac.js +0 -2
  87. package/chunk-2x5rw009.js +0 -40
  88. package/chunk-640swnrm.js +0 -4
  89. package/chunk-80fjfyha.js +0 -86
  90. package/chunk-8a2agf28.js +0 -22
  91. package/chunk-as4rn21e.js +0 -2
  92. package/chunk-avewjans.js +0 -85
  93. package/chunk-cfksd3zh.js +0 -2
  94. package/chunk-cy1nmr0f.js +0 -12
  95. package/chunk-dqy6a75x.js +0 -2
  96. package/chunk-fzqt4rsz.js +0 -6
  97. package/chunk-g7pbfad5.js +0 -3
  98. package/chunk-j4rt31qb.js +0 -2
  99. package/chunk-kmsbcb3q.js +0 -3
  100. package/chunk-ktsdzzgx.js +0 -2
  101. package/chunk-kvxn1cyx.js +0 -8
  102. package/chunk-n70zfv0m.js +0 -1491
  103. package/chunk-n8pr0kc8.js +0 -2
  104. package/chunk-qewarcqf.js +0 -2
  105. package/chunk-qf1c6jxh.js +0 -3
  106. package/chunk-vbk1qhdz.js +0 -3
  107. package/chunk-w40pqmyz.js +0 -63
  108. package/chunk-x05grjd9.js +0 -2
  109. package/chunk-z3r8px3d.js +0 -6
  110. package/chunk-zexzy6zv.js +0 -2
  111. package/chunk-zjbbd87h.js +0 -2
@@ -0,0 +1,8 @@
1
+ // @bun
2
+ import{require_react_development}from"./chunk-hhkjqvww.js";import{__toESM,__commonJS}from"./chunk-2smsg2ct.js";var require_react_jsx_runtime_development=__commonJS(function(exports){var React=__toESM(require_react_development());(function(){function getComponentNameFromType(type){if(type==null)return null;if(typeof type==="function")return type.$$typeof===REACT_CLIENT_REFERENCE?null:type.displayName||type.name||null;if(typeof type==="string")return type;switch(type){case REACT_FRAGMENT_TYPE:return"Fragment";case REACT_PROFILER_TYPE:return"Profiler";case REACT_STRICT_MODE_TYPE:return"StrictMode";case REACT_SUSPENSE_TYPE:return"Suspense";case REACT_SUSPENSE_LIST_TYPE:return"SuspenseList";case REACT_ACTIVITY_TYPE:return"Activity";case REACT_VIEW_TRANSITION_TYPE:return"ViewTransition"}if(typeof type==="object")switch(typeof type.tag==="number"&&console.error("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),type.$$typeof){case REACT_PORTAL_TYPE:return"Portal";case REACT_CONTEXT_TYPE:return type.displayName||"Context";case REACT_CONSUMER_TYPE:return(type._context.displayName||"Context")+".Consumer";case REACT_FORWARD_REF_TYPE:var innerType=type.render;return type=type.displayName,type||(type=innerType.displayName||innerType.name||"",type=type!==""?"ForwardRef("+type+")":"ForwardRef"),type;case REACT_MEMO_TYPE:return innerType=type.displayName||null,innerType!==null?innerType:getComponentNameFromType(type.type)||"Memo";case REACT_LAZY_TYPE:innerType=type._payload,type=type._init;try{return getComponentNameFromType(type(innerType))}catch(x){}}return null}function testStringCoercion(value){return""+value}function checkKeyStringCoercion(value){try{testStringCoercion(value);var JSCompiler_inline_result=!1}catch(e){JSCompiler_inline_result=!0}if(JSCompiler_inline_result){JSCompiler_inline_result=console;var JSCompiler_temp_const=JSCompiler_inline_result.error,JSCompiler_inline_result$jscomp$0=typeof Symbol==="function"&&Symbol.toStringTag&&value[Symbol.toStringTag]||value.constructor.name||"Object";return JSCompiler_temp_const.call(JSCompiler_inline_result,"The provided key is an unsupported type %s. This value must be coerced to a string before using it here.",JSCompiler_inline_result$jscomp$0),testStringCoercion(value)}}function getTaskName(type){if(type===REACT_FRAGMENT_TYPE)return"<>";if(typeof type==="object"&&type!==null&&type.$$typeof===REACT_LAZY_TYPE)return"<...>";try{var name=getComponentNameFromType(type);return name?"<"+name+">":"<...>"}catch(x){return"<...>"}}function getOwner(){var dispatcher=ReactSharedInternals.A;return dispatcher===null?null:dispatcher.getOwner()}function UnknownOwner(){return Error("react-stack-top-frame")}function hasValidKey(config){if(hasOwnProperty.call(config,"key")){var getter=Object.getOwnPropertyDescriptor(config,"key").get;if(getter&&getter.isReactWarning)return!1}return config.key!==void 0}function defineKeyPropWarningGetter(props,displayName){function warnAboutAccessingKey(){specialPropKeyWarningShown||(specialPropKeyWarningShown=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",displayName))}warnAboutAccessingKey.isReactWarning=!0,Object.defineProperty(props,"key",{get:warnAboutAccessingKey,configurable:!0})}function elementRefGetterWithDeprecationWarning(){var componentName=getComponentNameFromType(this.type);return didWarnAboutElementRef[componentName]||(didWarnAboutElementRef[componentName]=!0,console.error("Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.")),componentName=this.props.ref,componentName!==void 0?componentName:null}function ReactElement(type,key,props,owner,debugStack,debugTask){var refProp=props.ref;return type={$$typeof:REACT_ELEMENT_TYPE,type,key,props,_owner:owner},(refProp!==void 0?refProp:null)!==null?Object.defineProperty(type,"ref",{enumerable:!1,get:elementRefGetterWithDeprecationWarning}):Object.defineProperty(type,"ref",{enumerable:!1,value:null}),type._store={},Object.defineProperty(type._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(type,"_debugInfo",{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(type,"_debugStack",{configurable:!1,enumerable:!1,writable:!0,value:debugStack}),Object.defineProperty(type,"_debugTask",{configurable:!1,enumerable:!1,writable:!0,value:debugTask}),Object.freeze&&(Object.freeze(type.props),Object.freeze(type)),type}function jsxDEVImpl(type,config,maybeKey,isStaticChildren,debugStack,debugTask){var children=config.children;if(children!==void 0)if(isStaticChildren)if(isArrayImpl(children)){for(isStaticChildren=0;isStaticChildren<children.length;isStaticChildren++)validateChildKeys(children[isStaticChildren]);Object.freeze&&Object.freeze(children)}else console.error("React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.");else validateChildKeys(children);if(hasOwnProperty.call(config,"key")){children=getComponentNameFromType(type);var keys=Object.keys(config).filter(function(k){return k!=="key"});isStaticChildren=0<keys.length?"{key: someKey, "+keys.join(": ..., ")+": ...}":"{key: someKey}",didWarnAboutKeySpread[children+isStaticChildren]||(keys=0<keys.length?"{"+keys.join(": ..., ")+": ...}":"{}",console.error(`A props object containing a "key" prop is being spread into JSX:
3
+ let props = %s;
4
+ <%s {...props} />
5
+ React keys must be passed directly to JSX without using spread:
6
+ let props = %s;
7
+ <%s key={someKey} {...props} />`,isStaticChildren,children,keys,children),didWarnAboutKeySpread[children+isStaticChildren]=!0)}if(children=null,maybeKey!==void 0&&(checkKeyStringCoercion(maybeKey),children=""+maybeKey),hasValidKey(config)&&(checkKeyStringCoercion(config.key),children=""+config.key),"key"in config){maybeKey={};for(var propName in config)propName!=="key"&&(maybeKey[propName]=config[propName])}else maybeKey=config;return children&&defineKeyPropWarningGetter(maybeKey,typeof type==="function"?type.displayName||type.name||"Unknown":type),ReactElement(type,children,maybeKey,getOwner(),debugStack,debugTask)}function validateChildKeys(node){isValidElement(node)?node._store&&(node._store.validated=1):typeof node==="object"&&node!==null&&node.$$typeof===REACT_LAZY_TYPE&&(node._payload.status==="fulfilled"?isValidElement(node._payload.value)&&node._payload.value._store&&(node._payload.value._store.validated=1):node._store&&(node._store.validated=1))}function isValidElement(object){return typeof object==="object"&&object!==null&&object.$$typeof===REACT_ELEMENT_TYPE}var REACT_ELEMENT_TYPE=Symbol.for("react.transitional.element"),REACT_PORTAL_TYPE=Symbol.for("react.portal"),REACT_FRAGMENT_TYPE=Symbol.for("react.fragment"),REACT_STRICT_MODE_TYPE=Symbol.for("react.strict_mode"),REACT_PROFILER_TYPE=Symbol.for("react.profiler"),REACT_CONSUMER_TYPE=Symbol.for("react.consumer"),REACT_CONTEXT_TYPE=Symbol.for("react.context"),REACT_FORWARD_REF_TYPE=Symbol.for("react.forward_ref"),REACT_SUSPENSE_TYPE=Symbol.for("react.suspense"),REACT_SUSPENSE_LIST_TYPE=Symbol.for("react.suspense_list"),REACT_MEMO_TYPE=Symbol.for("react.memo"),REACT_LAZY_TYPE=Symbol.for("react.lazy"),REACT_ACTIVITY_TYPE=Symbol.for("react.activity"),REACT_VIEW_TRANSITION_TYPE=Symbol.for("react.view_transition"),REACT_CLIENT_REFERENCE=Symbol.for("react.client.reference"),ReactSharedInternals=React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,hasOwnProperty=Object.prototype.hasOwnProperty,isArrayImpl=Array.isArray,createTask=console.createTask?console.createTask:function(){return null};React={react_stack_bottom_frame:function(callStackForError){return callStackForError()}};var specialPropKeyWarningShown,didWarnAboutElementRef={},unknownOwnerDebugStack=React.react_stack_bottom_frame.bind(React,UnknownOwner)(),unknownOwnerDebugTask=createTask(getTaskName(UnknownOwner)),didWarnAboutKeySpread={};exports.Fragment=REACT_FRAGMENT_TYPE,exports.jsx=function(type,config,maybeKey){var trackActualOwner=1e4>ReactSharedInternals.recentlyCreatedOwnerStacks++;if(trackActualOwner){var previousStackTraceLimit=Error.stackTraceLimit;Error.stackTraceLimit=10;var debugStackDEV=Error("react-stack-top-frame");Error.stackTraceLimit=previousStackTraceLimit}else debugStackDEV=unknownOwnerDebugStack;return jsxDEVImpl(type,config,maybeKey,!1,debugStackDEV,trackActualOwner?createTask(getTaskName(type)):unknownOwnerDebugTask)},exports.jsxs=function(type,config,maybeKey){var trackActualOwner=1e4>ReactSharedInternals.recentlyCreatedOwnerStacks++;if(trackActualOwner){var previousStackTraceLimit=Error.stackTraceLimit;Error.stackTraceLimit=10;var debugStackDEV=Error("react-stack-top-frame");Error.stackTraceLimit=previousStackTraceLimit}else debugStackDEV=unknownOwnerDebugStack;return jsxDEVImpl(type,config,maybeKey,!0,debugStackDEV,trackActualOwner?createTask(getTaskName(type)):unknownOwnerDebugTask)}})()});
8
+ export{require_react_jsx_runtime_development};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ import{topUpTokens}from"./chunk-mseawt58.js";import{loadCredential,saveCredential,deleteCredential,fetchAccount,revokeCredential,performDeviceLogin}from"./chunk-62amy8bj.js";import{fetchCloudAppUrl}from"./chunk-5ts4fvd9.js";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;let stored=await loadCredential(cloudUrl);if(stored)await revokeCredential(cloudUrl,stored.token);await deleteCredential(cloudUrl)}}}
3
+ export{canvasDistPath,createCanvasAuth};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{ELEMENT_TAG,helperDescriptors,require_react_jsx_dev_runtime_development,STACK_ALIGN_CLASS,STACK_JUSTIFY_CLASS,CONTAINER_WIDTH_CLASS,CARD_CLASS,BUTTON_BASE_CLASS,BUTTON_VARIANT_CLASS,INPUT_CLASS,TextRunContext,textTag,helpersRegistry,helperSourcePath}from"./chunk-yp39f93e.js";import{headingInlineStyle,textInlineStyle}from"./chunk-w40pqmyz.js";import{TAILWIND_CLASSNAME,require_react_development}from"./chunk-n70zfv0m.js";import{__toESM}from"./chunk-2smsg2ct.js";import{noLibVersion}from"./chunk-cxe6jjwj.js";import{resolveProviderSrcDir}from"./chunk-v6c3h9ft.js";import{dirname,join}from"path";import{fileURLToPath}from"url";var NONE_INTRO=["**This folder has no component library** \u2014 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**.",""],NONE_INLINE_INTRO=["**This folder has no component library and no CSS framework** \u2014 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.","",'**Style through inline `style` objects.** `update_props { style: { display: "flex", gap: "16px", padding: "24px", borderRadius: "8px", color: "var(--color-foreground)" } }` \u2014 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={{\u2026}}` on plain elements \u2014 no imports, no Tailwind. Tailwind utility diagnostics do not apply.',""];var React=__toESM(require_react_development(),1),jsx_dev_runtime=__toESM(require_react_jsx_dev_runtime_development(),1);import{clsx}from"clsx";var Box=React.forwardRef(({as,className,...rest},ref)=>React.createElement(typeof as==="string"&&ELEMENT_TAG.test(as)?as:"div",{ref,className:clsx(className),...rest}));Box.displayName="Box";var Stack=React.forwardRef(({direction="col",gap=4,align,justify,className,...rest},ref)=>jsx_dev_runtime.jsxDEV("div",{ref,className:clsx("flex",direction==="row"?"flex-row":"flex-col",`gap-${gap}`,align?STACK_ALIGN_CLASS[align]:void 0,justify?STACK_JUSTIFY_CLASS[justify]:void 0,className),...rest},void 0,!1,void 0,this));Stack.displayName="Stack";var Container=React.forwardRef(({size="md",className,...rest},ref)=>jsx_dev_runtime.jsxDEV("div",{ref,className:clsx("mx-auto w-full px-4",CONTAINER_WIDTH_CLASS[size],className),...rest},void 0,!1,void 0,this));Container.displayName="Container";var Button=React.forwardRef(({variant="default",className,type,...rest},ref)=>jsx_dev_runtime.jsxDEV("button",{ref,type:type??"button",className:clsx(BUTTON_BASE_CLASS,BUTTON_VARIANT_CLASS[variant],className),...rest},void 0,!1,void 0,this));Button.displayName="Button";var Input=React.forwardRef(({className,type="text",value,onChange,...rest},ref)=>jsx_dev_runtime.jsxDEV("input",{ref,type,value,onChange,readOnly:value!==void 0&&onChange===void 0||rest.readOnly,className:clsx(INPUT_CLASS,className),...rest},void 0,!1,void 0,this));Input.displayName="Input";var Card=React.forwardRef(({className,...rest},ref)=>jsx_dev_runtime.jsxDEV("div",{ref,className:clsx(CARD_CLASS,className),...rest},void 0,!1,void 0,this));Card.displayName="Card";var REUSED_HELPER_IDS=["Heading","Text","Prose","Icon","SVG","Image","Layer","Divider","Gradient","Placeholder"],registry={Box,Stack,Container,Card,Button,Input,...helpersRegistry(REUSED_HELPER_IDS)};var PRIMITIVE_DESCRIPTORS=[{id:"Box",category:"ui",source:"velloo",plainElement:!0,props:[{name:"as",type:"string",optional:!0,control:"string"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Stack",category:"ui",source:"velloo",props:[{name:"direction",type:'"row" | "col" | undefined',optional:!0,control:"enum",enumValues:["row","col"],defaultValue:"col"},{name:"gap",type:"number | undefined",optional:!0,control:"number",defaultValue:"4"},{name:"align",type:'"start" | "center" | "end" | "stretch" | undefined',optional:!0,control:"enum",enumValues:["start","center","end","stretch"]},{name:"justify",type:'"start" | "center" | "end" | "between" | "around" | undefined',optional:!0,control:"enum",enumValues:["start","center","end","between","around"]},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Container",category:"ui",source:"velloo",props:[{name:"size",type:'"sm" | "md" | "lg" | "xl" | "full" | undefined',optional:!0,control:"enum",enumValues:["sm","md","lg","xl","full"],defaultValue:"md"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Card",category:"ui",source:"velloo",props:[{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Button",category:"ui",source:"velloo",props:[{name:"variant",type:'"default" | "ghost" | "outline" | undefined',optional:!0,control:"enum",enumValues:["default","ghost","outline"],defaultValue:"default"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Input",category:"ui",source:"velloo",props:[{name:"placeholder",type:"string | undefined",optional:!0,control:"string"},{name:"value",type:"string | undefined",optional:!0,control:"string"},{name:"type",type:"string | undefined",optional:!0,control:"string",defaultValue:"text"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]}],NONE_MANIFEST2=[...PRIMITIVE_DESCRIPTORS,...helperDescriptors(REUSED_HELPER_IDS)];var React2=__toESM(require_react_development(),1),jsx_dev_runtime2=__toESM(require_react_jsx_dev_runtime_development(),1);function merge(defaults,authored){return authored?{...defaults,...authored}:defaults}var space=(n)=>`${n*0.25}rem`,Box2=React2.forwardRef(({as,...rest},ref)=>React2.createElement(typeof as==="string"&&ELEMENT_TAG.test(as)?as:"div",{ref,...rest}));Box2.displayName="Box";var alignStyle={start:"flex-start",center:"center",end:"flex-end",stretch:"stretch"},justifyStyle={start:"flex-start",center:"center",end:"flex-end",between:"space-between",around:"space-around"},Stack2=React2.forwardRef(({direction="col",gap=4,align,justify,style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("div",{ref,style:merge({display:"flex",flexDirection:direction==="row"?"row":"column",gap:space(gap),...align?{alignItems:alignStyle[align]}:{},...justify?{justifyContent:justifyStyle[justify]}:{}},style),...rest},void 0,!1,void 0,this));Stack2.displayName="Stack";var containerMaxWidth={sm:"640px",md:"768px",lg:"1024px",xl:"1280px",full:"100%"},Container2=React2.forwardRef(({size="md",style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("div",{ref,style:merge({marginInline:"auto",width:"100%",paddingInline:"1rem",maxWidth:containerMaxWidth[size]},style),...rest},void 0,!1,void 0,this));Container2.displayName="Container";var buttonVariantStyle={default:{background:"var(--color-foreground)",color:"var(--color-background)"},ghost:{background:"transparent",color:"var(--color-foreground)"},outline:{background:"transparent",color:"var(--color-foreground)",border:"1px solid var(--color-border)"}},Button2=React2.forwardRef(({variant="default",type,style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("button",{ref,type:type??"button",style:merge({display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"0.5rem",borderRadius:"var(--radius)",padding:"0.5rem 1rem",fontSize:"0.875rem",fontWeight:500,cursor:"pointer",...buttonVariantStyle[variant]},style),...rest},void 0,!1,void 0,this));Button2.displayName="Button";var Input2=React2.forwardRef(({type="text",value,onChange,style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("input",{ref,type,value,onChange,readOnly:value!==void 0&&onChange===void 0||rest.readOnly,style:merge({display:"block",width:"100%",borderRadius:"var(--radius)",border:"1px solid var(--color-input)",background:"var(--color-background)",padding:"0.5rem 0.75rem",fontSize:"0.875rem"},style),...rest},void 0,!1,void 0,this));Input2.displayName="Input";var Card2=React2.forwardRef(({style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("div",{ref,style:merge({borderRadius:"var(--radius)",border:"1px solid var(--color-border)",background:"var(--color-card)",color:"var(--color-card-foreground)",padding:"1.5rem",boxShadow:"0 1px 2px 0 rgb(0 0 0 / 0.05)"},style),...rest},void 0,!1,void 0,this));Card2.displayName="Card";var Heading=React2.forwardRef(({level=1,style,...rest},ref)=>{let Tag=`h${level}`;return jsx_dev_runtime2.jsxDEV(Tag,{ref,style:merge(headingInlineStyle(level),style),...rest},void 0,!1,void 0,this)});Heading.displayName="Heading";var Text=React2.forwardRef(({variant,style,...rest},ref)=>{let run=React2.useContext(TextRunContext);return jsx_dev_runtime2.jsxDEV(TextRunContext.Provider,{value:!0,children:React2.createElement(textTag(run),{ref,style:merge(textInlineStyle(variant,run),style),...rest})},void 0,!1,void 0,this)});Text.displayName="Text";var REUSED_HELPER_IDS2=["Prose","Icon","SVG","Image","Layer","Divider","Gradient","Placeholder"],inlineRegistry={Box:Box2,Stack:Stack2,Container:Container2,Card:Card2,Button:Button2,Input:Input2,Heading,Text,...helpersRegistry(REUSED_HELPER_IDS2)};var PRIMITIVES=new Set(["Box","Stack","Container","Card","Button","Input"]),INLINE_TYPOGRAPHY=new Set(["Heading","Text"]),here=dirname(fileURLToPath(import.meta.url)),srcDir=resolveProviderSrcDir(here,"provider-none",process.env.VELLOO_NOLIB_SRC),entryCssPath2=join(srcDir,"tailwind-entry.css"),componentsDir2=srcDir;async function loadManifest(){return NONE_MANIFEST2}function createProvider2(){return{id:"none",version:noLibVersion,componentsDir:componentsDir2,styleEntryPath:entryCssPath2,registry,loadManifest,label:`none ${noLibVersion}`,styleChannel:TAILWIND_CLASSNAME,styleChannels:["tailwind-classname","style"],themeRoles:["background","foreground","card","muted","border","input"],mcpIntro:(channel)=>[...channel==="style"?NONE_INLINE_INTRO:NONE_INTRO],registryForChannel:(kind)=>kind==="style"?inlineRegistry:registry,canvasBundleSpec:{styleRuntime:{kind:"none"},onlyWithRepository:!0,components:(ids,context)=>{let inline=context?.channel==="style";return ids.flatMap((id)=>{let own=PRIMITIVES.has(id)||inline&&INLINE_TYPOGRAPHY.has(id)?join(srcDir,inline?"components-inline.tsx":"components.tsx"):helperSourcePath(id);return own?[{id,sources:[{importPath:own,exportName:id,fidelity:"exact",note:"Velloo primitive, mounted beside the app's components."}]}]:[]})}}}}
2
+ import{ELEMENT_TAG,helperDescriptors,require_react_jsx_dev_runtime_development,STACK_ALIGN_CLASS,STACK_JUSTIFY_CLASS,CONTAINER_WIDTH_CLASS,CARD_CLASS,BUTTON_BASE_CLASS,BUTTON_VARIANT_CLASS,INPUT_CLASS,TextRunContext,textTag,helpersRegistry,helperSourcePath}from"./chunk-mseawt58.js";import{headingInlineStyle,textInlineStyle}from"./chunk-ghwy99py.js";import{TAILWIND_CLASSNAME,require_react_development}from"./chunk-hhkjqvww.js";import{__toESM}from"./chunk-2smsg2ct.js";import{noLibVersion}from"./chunk-cxe6jjwj.js";import{resolveProviderSrcDir}from"./chunk-v6c3h9ft.js";import{dirname,join}from"path";import{fileURLToPath}from"url";var NONE_INTRO=["**This folder has no component library** \u2014 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**.",""],NONE_INLINE_INTRO=["**This folder has no component library and no CSS framework** \u2014 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.","",'**Style through inline `style` objects.** `update_props { style: { display: "flex", gap: "16px", padding: "24px", borderRadius: "8px", color: "var(--color-foreground)" } }` \u2014 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={{\u2026}}` on plain elements \u2014 no imports, no Tailwind. Tailwind utility diagnostics do not apply.',""];var React=__toESM(require_react_development(),1),jsx_dev_runtime=__toESM(require_react_jsx_dev_runtime_development(),1);import{clsx}from"clsx";var Box=React.forwardRef(({as,className,...rest},ref)=>React.createElement(typeof as==="string"&&ELEMENT_TAG.test(as)?as:"div",{ref,className:clsx(className),...rest}));Box.displayName="Box";var Stack=React.forwardRef(({direction="col",gap=4,align,justify,className,...rest},ref)=>jsx_dev_runtime.jsxDEV("div",{ref,className:clsx("flex",direction==="row"?"flex-row":"flex-col",`gap-${gap}`,align?STACK_ALIGN_CLASS[align]:void 0,justify?STACK_JUSTIFY_CLASS[justify]:void 0,className),...rest},void 0,!1,void 0,this));Stack.displayName="Stack";var Container=React.forwardRef(({size="md",className,...rest},ref)=>jsx_dev_runtime.jsxDEV("div",{ref,className:clsx("mx-auto w-full px-4",CONTAINER_WIDTH_CLASS[size],className),...rest},void 0,!1,void 0,this));Container.displayName="Container";var Button=React.forwardRef(({variant="default",className,type,...rest},ref)=>jsx_dev_runtime.jsxDEV("button",{ref,type:type??"button",className:clsx(BUTTON_BASE_CLASS,BUTTON_VARIANT_CLASS[variant],className),...rest},void 0,!1,void 0,this));Button.displayName="Button";var Input=React.forwardRef(({className,type="text",value,onChange,...rest},ref)=>jsx_dev_runtime.jsxDEV("input",{ref,type,value,onChange,readOnly:value!==void 0&&onChange===void 0||rest.readOnly,className:clsx(INPUT_CLASS,className),...rest},void 0,!1,void 0,this));Input.displayName="Input";var Card=React.forwardRef(({className,...rest},ref)=>jsx_dev_runtime.jsxDEV("div",{ref,className:clsx(CARD_CLASS,className),...rest},void 0,!1,void 0,this));Card.displayName="Card";var REUSED_HELPER_IDS=["Heading","Text","Prose","Icon","SVG","Image","Layer","Divider","Gradient","Placeholder"],registry={Box,Stack,Container,Card,Button,Input,...helpersRegistry(REUSED_HELPER_IDS)};var PRIMITIVE_DESCRIPTORS=[{id:"Box",category:"ui",source:"velloo",plainElement:!0,props:[{name:"as",type:"string",optional:!0,control:"string"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Stack",category:"ui",source:"velloo",props:[{name:"direction",type:'"row" | "col" | undefined',optional:!0,control:"enum",enumValues:["row","col"],defaultValue:"col"},{name:"gap",type:"number | undefined",optional:!0,control:"number",defaultValue:"4"},{name:"align",type:'"start" | "center" | "end" | "stretch" | undefined',optional:!0,control:"enum",enumValues:["start","center","end","stretch"]},{name:"justify",type:'"start" | "center" | "end" | "between" | "around" | undefined',optional:!0,control:"enum",enumValues:["start","center","end","between","around"]},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Container",category:"ui",source:"velloo",props:[{name:"size",type:'"sm" | "md" | "lg" | "xl" | "full" | undefined',optional:!0,control:"enum",enumValues:["sm","md","lg","xl","full"],defaultValue:"md"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Card",category:"ui",source:"velloo",props:[{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Button",category:"ui",source:"velloo",props:[{name:"variant",type:'"default" | "ghost" | "outline" | undefined',optional:!0,control:"enum",enumValues:["default","ghost","outline"],defaultValue:"default"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Input",category:"ui",source:"velloo",props:[{name:"placeholder",type:"string | undefined",optional:!0,control:"string"},{name:"value",type:"string | undefined",optional:!0,control:"string"},{name:"type",type:"string | undefined",optional:!0,control:"string",defaultValue:"text"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]}],NONE_MANIFEST2=[...PRIMITIVE_DESCRIPTORS,...helperDescriptors(REUSED_HELPER_IDS)];var React2=__toESM(require_react_development(),1),jsx_dev_runtime2=__toESM(require_react_jsx_dev_runtime_development(),1);function merge(defaults,authored){return authored?{...defaults,...authored}:defaults}var space=(n)=>`${n*0.25}rem`,Box2=React2.forwardRef(({as,...rest},ref)=>React2.createElement(typeof as==="string"&&ELEMENT_TAG.test(as)?as:"div",{ref,...rest}));Box2.displayName="Box";var alignStyle={start:"flex-start",center:"center",end:"flex-end",stretch:"stretch"},justifyStyle={start:"flex-start",center:"center",end:"flex-end",between:"space-between",around:"space-around"},Stack2=React2.forwardRef(({direction="col",gap=4,align,justify,style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("div",{ref,style:merge({display:"flex",flexDirection:direction==="row"?"row":"column",gap:space(gap),...align?{alignItems:alignStyle[align]}:{},...justify?{justifyContent:justifyStyle[justify]}:{}},style),...rest},void 0,!1,void 0,this));Stack2.displayName="Stack";var containerMaxWidth={sm:"640px",md:"768px",lg:"1024px",xl:"1280px",full:"100%"},Container2=React2.forwardRef(({size="md",style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("div",{ref,style:merge({marginInline:"auto",width:"100%",paddingInline:"1rem",maxWidth:containerMaxWidth[size]},style),...rest},void 0,!1,void 0,this));Container2.displayName="Container";var buttonVariantStyle={default:{background:"var(--color-foreground)",color:"var(--color-background)"},ghost:{background:"transparent",color:"var(--color-foreground)"},outline:{background:"transparent",color:"var(--color-foreground)",border:"1px solid var(--color-border)"}},Button2=React2.forwardRef(({variant="default",type,style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("button",{ref,type:type??"button",style:merge({display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"0.5rem",borderRadius:"var(--radius)",padding:"0.5rem 1rem",fontSize:"0.875rem",fontWeight:500,cursor:"pointer",...buttonVariantStyle[variant]},style),...rest},void 0,!1,void 0,this));Button2.displayName="Button";var Input2=React2.forwardRef(({type="text",value,onChange,style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("input",{ref,type,value,onChange,readOnly:value!==void 0&&onChange===void 0||rest.readOnly,style:merge({display:"block",width:"100%",borderRadius:"var(--radius)",border:"1px solid var(--color-input)",background:"var(--color-background)",padding:"0.5rem 0.75rem",fontSize:"0.875rem"},style),...rest},void 0,!1,void 0,this));Input2.displayName="Input";var Card2=React2.forwardRef(({style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("div",{ref,style:merge({borderRadius:"var(--radius)",border:"1px solid var(--color-border)",background:"var(--color-card)",color:"var(--color-card-foreground)",padding:"1.5rem",boxShadow:"0 1px 2px 0 rgb(0 0 0 / 0.05)"},style),...rest},void 0,!1,void 0,this));Card2.displayName="Card";var Heading=React2.forwardRef(({level=1,style,...rest},ref)=>{let Tag=`h${level}`;return jsx_dev_runtime2.jsxDEV(Tag,{ref,style:merge(headingInlineStyle(level),style),...rest},void 0,!1,void 0,this)});Heading.displayName="Heading";var Text=React2.forwardRef(({variant,style,...rest},ref)=>{let run=React2.useContext(TextRunContext);return jsx_dev_runtime2.jsxDEV(TextRunContext.Provider,{value:!0,children:React2.createElement(textTag(run),{ref,style:merge(textInlineStyle(variant,run),style),...rest})},void 0,!1,void 0,this)});Text.displayName="Text";var REUSED_HELPER_IDS2=["Prose","Icon","SVG","Image","Layer","Divider","Gradient","Placeholder"],inlineRegistry={Box:Box2,Stack:Stack2,Container:Container2,Card:Card2,Button:Button2,Input:Input2,Heading,Text,...helpersRegistry(REUSED_HELPER_IDS2)};var PRIMITIVES=new Set(["Box","Stack","Container","Card","Button","Input"]),INLINE_TYPOGRAPHY=new Set(["Heading","Text"]),here=dirname(fileURLToPath(import.meta.url)),srcDir=resolveProviderSrcDir(here,"provider-none",process.env.VELLOO_NOLIB_SRC),entryCssPath2=join(srcDir,"tailwind-entry.css"),componentsDir2=srcDir;async function loadManifest(){return NONE_MANIFEST2}function createProvider2(){return{id:"none",version:noLibVersion,componentsDir:componentsDir2,styleEntryPath:entryCssPath2,registry,loadManifest,label:`none ${noLibVersion}`,styleChannel:TAILWIND_CLASSNAME,styleChannels:["tailwind-classname","style"],themeRoles:["background","foreground","card","muted","border","input"],mcpIntro:(channel)=>[...channel==="style"?NONE_INLINE_INTRO:NONE_INTRO],registryForChannel:(kind)=>kind==="style"?inlineRegistry:registry,canvasBundleSpec:{styleRuntime:{kind:"none"},onlyWithRepository:!0,components:(ids,context)=>{let inline=context?.channel==="style";return ids.flatMap((id)=>{let own=PRIMITIVES.has(id)||inline&&INLINE_TYPOGRAPHY.has(id)?join(srcDir,inline?"components-inline.tsx":"components.tsx"):helperSourcePath(id);return own?[{id,sources:[{importPath:own,exportName:id,fidelity:"exact",note:"Velloo primitive, mounted beside the app's components."}]}]:[]})}}}}
3
3
  export{NONE_MANIFEST2,inlineRegistry,entryCssPath2,componentsDir2,createProvider2};
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{normalizeRepoManifest,CURRENT_SCHEMA_VERSION,schemaVersionOf,planMigration}from"./chunk-w40pqmyz.js";import{localDesignOf,findOwningManifest,recordedDesignName,loadDesignFolder}from"./chunk-yp39f93e.js";import{TOOL_VERSION}from"./chunk-g7pbfad5.js";import{existsSync,realpathSync}from"fs";import{readdir,readFile,writeFile}from"fs/promises";import{join,resolve}from"path";function isObject(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}var isAnnotationSidecar=(file)=>file.endsWith(".annotations.json"),isThemeDocument=(file)=>file.endsWith(".json");async function planRewrites(folder,dir,matches,transform){let files=[];try{files=await readdir(join(folder,dir))}catch{return[]}let out=[];for(let file of files.sort()){if(!matches(file))continue;let rel=join(dir,file),prev=await readFile(join(folder,rel),"utf8"),next=`${JSON.stringify(transform(JSON.parse(prev)),null,2)}
2
+ import{normalizeRepoManifest,CURRENT_SCHEMA_VERSION,schemaVersionOf,planMigration}from"./chunk-ghwy99py.js";import{localDesignOf,findOwningManifest,recordedDesignName,loadDesignFolder}from"./chunk-mseawt58.js";import{TOOL_VERSION}from"./chunk-d6a6198y.js";import{existsSync,realpathSync}from"fs";import{readdir,readFile,writeFile}from"fs/promises";import{join,resolve}from"path";function isObject(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}var isAnnotationSidecar=(file)=>file.endsWith(".annotations.json"),isThemeDocument=(file)=>file.endsWith(".json");async function planRewrites(folder,dir,matches,transform){let files=[];try{files=await readdir(join(folder,dir))}catch{return[]}let out=[];for(let file of files.sort()){if(!matches(file))continue;let rel=join(dir,file),prev=await readFile(join(folder,rel),"utf8"),next=`${JSON.stringify(transform(JSON.parse(prev)),null,2)}
3
3
  `;if(next!==prev)out.push({rel,next})}return out}async function upgradeFolder(folder,opts={}){let configPath=join(folder,".design","config.json"),rawConfig=JSON.parse(await readFile(configPath,"utf8")),from=schemaVersionOf(rawConfig),manifest=await findOwningManifest(folder).catch(()=>null),run=planMigration(rawConfig,{name:legacyNameOf(folder,manifest)}),manifestFiles=manifest?.legacy?[manifest.path]:[];if(run.applied.length===0){if(manifest?.legacy&&!opts.dryRun)await migrateManifest(manifest);return{from,to:CURRENT_SCHEMA_VERSION,applied:[],changedFiles:manifestFiles}}let rewrites=[...await planRewrites(folder,"screens",isAnnotationSidecar,(parsed)=>Array.isArray(parsed)?parsed.map((e)=>typeof e==="object"&&e!==null?run.annotation(e):e):parsed),...await planRewrites(folder,"theme",isThemeDocument,(parsed)=>isObject(parsed)?run.theme(parsed):parsed)],nextConfig={...run.config,toolVersion:TOOL_VERSION},changedFiles=[join(".design","config.json"),...rewrites.map((r)=>r.rel),...manifestFiles];if(opts.dryRun)return{from,to:CURRENT_SCHEMA_VERSION,applied:run.applied,changedFiles};await writeFile(configPath,`${JSON.stringify(nextConfig,null,2)}
4
4
  `,"utf8");for(let r of rewrites)await writeFile(join(folder,r.rel),r.next,"utf8");if(manifest?.legacy)await migrateManifest(manifest);return await loadDesignFolder(folder),{from,to:CURRENT_SCHEMA_VERSION,applied:run.applied,changedFiles}}function legacyNameOf(folder,manifest){let local=localDesignOf(folder);if(local)return local.legacyName;let target=realOr(folder);for(let[path,name]of manifest?.legacyNames??[])if(realOr(path)===target)return name;return}function realOr(path){return existsSync(path)?realpathSync(path):resolve(path)}async function migrateManifest(manifest){for(let[path,name]of manifest.legacyNames){if(recordedDesignName(path))continue;let configPath=join(path,".design","config.json"),raw;try{raw=JSON.parse(await readFile(configPath,"utf8"))}catch{continue}if(isObject(raw))await writeFile(configPath,`${JSON.stringify({...raw,name},null,2)}
5
5
  `)}let raw=JSON.parse(await readFile(manifest.path,"utf8"));await writeFile(manifest.path,`${JSON.stringify(normalizeRepoManifest(raw).manifest,null,2)}
@@ -1,5 +1,7 @@
1
1
  // @bun
2
- import{ok,err,PROTECTED_SHARES_UNAVAILABLE,PublishDestinationsResponseSchema,LinkResponseSchema,LinkAccessResponseSchema,VersionUploadResponseSchema,PublishedDesignsResponseSchema,TeamsResponseSchema,unreachable,protocolViolation,uploadRaceLost,readFailure,cloudFailure,httpFailureFrom,boardLimitFrom,describeBoardLimit,describeCloudError,cloudJson,cloudFetch}from"./chunk-zexzy6zv.js";import{prettifyError,string,number,boolean,array,object,strictObject,record,_enum,literal,AnnotationSchema,CanvasNoteSchema,BoardSchema,ExtensionSchema,ViewportPresetSchema,LibrarySchema,StylingSchema,ScreenSchema,SnippetSchema,sanitizeSvgMarkup,ThemeSchema,ViewportSchema}from"./chunk-w40pqmyz.js";import{buildBoardComposite,MAX_CONCURRENT_RENDERS,renderScreen,captureMountedDocument,captureScreenshot}from"./chunk-n70zfv0m.js";import{writeJsonAtomic,managedDesignId,localDesignOf,recordedDesignName,orderedBoards,activeBoards,registryForScreen,renderPassForScreen,hostStylesheetsForScreen,hostFilesFetch,storedHostSource,shipHostFiles,createCaptureMount}from"./chunk-yp39f93e.js";import{LIVE_BUNDLE_PATH,withAssetServer,createOneShotLiveBundler,buildLiveModule}from"./chunk-ck3bg8rf.js";import{checkCloudHealth}from"./chunk-3f2p94wa.js";function publishedDesignSubtitle(design){let published=design.lastPublishedAt?`Published ${design.lastPublishedAt}`:"Publish time unavailable",who=design.ownerEmail?.trim()||design.ownerName?.trim(),publisher=who?`by ${who}`:"publisher unavailable",repo=design.git?.repo?.trim(),branch=design.git?.branch?.trim(),source=repo?`repo ${repo}${branch?` (${branch})`:""}`:"repository unavailable";return`${published} \xB7 ${publisher} \xB7 ${source}`}async function listPublishedDesigns(opts){let body=await cloudFetch(`${opts.baseUrl}/v1/links`,PublishedDesignsResponseSchema,{operation:"listing published designs",token:opts.token});if(!body.ok)return body;return ok((body.value.links??[]).filter((link)=>link.published).map((link)=>({...link,url:link.url.startsWith("http")?link.url:`${opts.baseUrl}${link.url}`})))}async function unpublishDesign(opts){let res=await fetch(`${opts.baseUrl}/v1/links/${encodeURIComponent(opts.slug)}`,{method:"DELETE",headers:{authorization:`Bearer ${opts.token}`}}).catch((error)=>error);if(!(res instanceof Response))return err(unreachable(res,{url:opts.baseUrl}));if(!res.ok)return err(await httpFailureFrom("unpublishing the design",res));return ok(void 0)}var VERSION_UPLOAD_TIMEOUT_MS=60000,VERSION_UPLOAD_RETRIES=1;async function listPublishDestinations(opts){let query=new URLSearchParams({folderId:opts.folderId});if(opts.teamId)query.set("teamId",opts.teamId);return cloudFetch(`${opts.baseUrl}/v1/publish-destinations?${query}`,PublishDestinationsResponseSchema,{operation:"listing publish destinations",token:opts.token})}async function uploadLinkBundle(opts){let{baseUrl,token,form}=opts,authorized={authorization:`Bearer ${token}`},createRes=await fetch(`${baseUrl}/v1/links`,{method:"POST",headers:authorized,body:JSON.stringify(opts.link)}).catch((error)=>error);if(!(createRes instanceof Response))return err(unreachable(createRes,{url:baseUrl}));if(createRes.status!==200&&createRes.status!==201)return err(await httpFailureFrom("link creation",createRes));let created=createRes.status===201,createdLink=await cloudJson(createRes,LinkResponseSchema,"link creation");if(!createdLink.ok)return createdLink;let link=createdLink.value;if(opts.link.publishMode==="new"&&!created)return err(protocolViolation("the cloud reused a link even though a new publish destination was requested"));if(opts.link.publishMode==="update"&&created)return await fetch(`${baseUrl}/v1/links/${link.slug}`,{method:"DELETE",headers:authorized}).catch(()=>{}),err(protocolViolation("the cloud created a link even though an existing destination was selected"));if(!created){let accessRes=await fetch(`${baseUrl}/v1/links/${link.slug}/access`,{method:"PUT",headers:{...authorized,"content-type":"application/json"},body:JSON.stringify({visibility:opts.link.visibility,password:opts.link.password??null,passwordExpiresAt:opts.link.password?opts.link.passwordExpiresAt??null:null,expectedVersionId:opts.link.expectedVersionId??null,...opts.link.audience?.length?{audience:opts.link.audience}:{},...opts.link.publicComments!==void 0?{publicComments:opts.link.publicComments}:{}})});if(!accessRes.ok)return err(await httpFailureFrom("privacy update",accessRes));let access=await cloudJson(accessRes,LinkAccessResponseSchema,"privacy update");if(!access.ok)return access;link={...link,...access.value}}if(form.append("publishMode",opts.link.publishMode),opts.link.expectedVersionId)form.append("expectedVersionId",opts.link.expectedVersionId);let attempt=await uploadVersionWithRetry({url:`${baseUrl}/v1/links/${link.slug}/versions`,headers:authorized,form,timeoutMs:opts.uploadTimeoutMs??VERSION_UPLOAD_TIMEOUT_MS,retries:opts.uploadRetries??VERSION_UPLOAD_RETRIES});if(!attempt.ok)return attempt;let upload=attempt.value,uploadRes=upload.response;if(uploadRes.status!==201){let{detail,code}=await readFailure(uploadRes);if(upload.transientFailures>0&&uploadRes.status===409&&/slot changed|already has a version/i.test(detail))return err(uploadRaceLost());if(created)await fetch(`${baseUrl}/v1/links/${link.slug}`,{method:"DELETE",headers:authorized}).catch(()=>{});return err(cloudFailure("upload",uploadRes.status,detail,code))}let parsed=await cloudJson(uploadRes,VersionUploadResponseSchema,"upload");if(!parsed.ok)return parsed;let uploaded=parsed.value;return ok({link:{slug:link.slug,visibility:link.visibility??opts.link.visibility,passwordProtected:link.passwordProtected??opts.link.password!=null,...link.audience!==void 0?{audience:link.audience}:{},...link.publicComments!==void 0?{publicComments:link.publicComments}:{}},created,files:uploaded.files,bytes:uploaded.bytes,shareUrl:uploaded.url.startsWith("http")?uploaded.url:`${baseUrl}${uploaded.url}`,...uploaded.tier!==void 0?{tier:uploaded.tier}:{},...uploaded.history!==void 0?{history:uploaded.history}:{}})}async function uploadVersionWithRetry(opts){let attempts=Math.max(1,Math.floor(opts.retries)+1),transientFailures=0,lastNetworkError="unknown network error",lastTimedOut=!1;for(let attempt=1;attempt<=attempts;attempt+=1){let controller=new AbortController,timedOut=!1,timer=setTimeout(()=>{timedOut=!0,controller.abort()},Math.max(1,opts.timeoutMs));try{let response=await fetch(opts.url,{method:"POST",headers:opts.headers,body:opts.form,signal:controller.signal});if(response.status<500||attempt===attempts)return ok({response,transientFailures});transientFailures+=1,await response.body?.cancel().catch(()=>{})}catch(error){if(transientFailures+=1,lastTimedOut=timedOut,lastNetworkError=error instanceof Error?error.message:String(error),attempt===attempts){let retried=attempts>1?` after ${attempts} attempts`:"";return err(timedOut?unreachable(`timed out after ${formatDuration(opts.timeoutMs)}${retried}`,{url:opts.url,timedOut:!0}):unreachable(`version upload${retried}: ${lastNetworkError}`,{url:opts.url}))}}finally{clearTimeout(timer)}}return err(lastTimedOut?unreachable(`timed out after ${formatDuration(opts.timeoutMs)}`,{url:opts.url,timedOut:!0}):unreachable(`version upload: ${lastNetworkError}`,{url:opts.url}))}function formatDuration(ms){return ms>=1000?`${Math.round(ms/1000)}s`:`${Math.max(1,Math.round(ms))}ms`}import{execFileSync}from"child_process";import{existsSync}from"fs";import{readFile}from"fs/promises";import{join}from"path";var DESIGN_BUNDLE_FORMAT=2,BundleScreenshotsSchema=object({cover:string().optional(),screens:record(string(),string()).optional(),boards:record(string(),string()).optional()}),DesignBundleMetaSchema=object({formatVersion:number().int().positive().optional(),title:string().optional(),screens:array(object({id:string(),name:string().optional()})).optional(),boards:array(object({id:string()})).optional(),screenshots:BundleScreenshotsSchema.optional()});var DesignBundleSchema=strictObject({formatVersion:literal(DESIGN_BUNDLE_FORMAT),title:string(),viewport:ViewportSchema,defaultLibrary:string(),libraries:record(string(),LibrarySchema),extensions:record(string(),ExtensionSchema),styling:StylingSchema.optional(),viewportPresets:array(ViewportPresetSchema),theme:ThemeSchema,themes:record(string(),ThemeSchema),customCss:string(),snippets:array(SnippetSchema),screens:array(ScreenSchema),boards:array(BoardSchema),annotations:record(string(),array(AnnotationSchema)),notes:record(string(),array(CanvasNoteSchema)),live:boolean(),snapshotCssPath:string(),bundlePath:string().optional(),hostStylesheets:array(string().regex(/^(?:assets\/host\/[A-Za-z0-9._@~+-][A-Za-z0-9._@~+/-]*\.css|https:\/\/\S+)$/)).optional(),appStylesheets:record(string(),string().regex(/^app-[a-z0-9]+\.css$/)).optional(),frozenScreens:record(string(),record(string(),string().regex(/^frozen\/[a-z0-9]+\.json$/))).optional(),screenshots:object({cover:string(),screens:record(string(),string()),boards:record(string(),string())}).optional()}),FrozenScreenSchema=strictObject({head:array(strictObject({tag:_enum(["style","link"]),attributes:record(string(),string()),css:string().optional(),file:string().regex(/^(?:snapshot|app-[a-z0-9]+|frozen\/[a-z0-9]+)\.css$/).optional()})),body:string(),htmlAttributes:record(string(),string()),bodyAttributes:record(string(),string())});function frozenVariantKey(themeName,scheme){return`${themeName}/${scheme}`}import{homedir}from"os";import{delimiter,dirname,resolve}from"path";function designGitEnv(folder){let ceilings=[homedir()];if(managedDesignId(folder)||localDesignOf(folder))ceilings.push(dirname(resolve(folder)));let inherited=process.env.GIT_CEILING_DIRECTORIES;if(inherited)ceilings.push(inherited);return{...process.env,GIT_CEILING_DIRECTORIES:ceilings.join(delimiter)}}var MAX_SCREENSHOT_BYTES=4194304,MAX_SCREENSHOT_COUNT=120,DOWNSCALE_WIDTH=1280;function isBrowserMissing(err){return err instanceof Error&&err.name==="BrowserMissingError"}async function captureBundleScreenshots(opts){let{screens,boards,viewport,renderHtml,capture,warn,progress}=opts,selectedScreens=opts.screenIds?screens.filter((screen)=>opts.screenIds?.has(screen.id)):screens,selectedBoards=opts.boardIds?boards.filter((board)=>opts.boardIds?.has(board.id)):boards,manifest={cover:"",screens:{},boards:{}},total=selectedScreens.length+selectedBoards.filter((board)=>board.frames.length>0).length,done=0,advance=()=>{done+=1,progress?.(done,total)},shoot=async(html,vp,fullPage,screen)=>{let of=screen?{screen}:{},png=await capture({html,viewport:vp,fullPage,deviceScaleFactor:1,...of});if(png.byteLength>MAX_SCREENSHOT_BYTES&&DOWNSCALE_WIDTH<vp.w)png=await capture({html,viewport:vp,fullPage,deviceScaleFactor:DOWNSCALE_WIDTH/vp.w,...of});return png.byteLength<=MAX_SCREENSHOT_BYTES?png:null},jobs=[];for(let screen of selectedScreens)jobs.push({run:async()=>{try{let png=await shoot(await renderHtml(screen),viewport,!0,screen);if(!png)return warn(`screenshot of screen "${screen.id}" exceeds 4MB even downscaled \u2014 skipped`),null;return{kind:"screen",id:screen.id,path:`screenshots/${screen.id}.png`,bytes:png}}catch(err){if(isBrowserMissing(err))throw err;return warn(`screenshot of screen "${screen.id}" failed \u2014 skipped (${message(err)})`),null}finally{advance()}}});let screenById=new Map(screens.map((screen)=>[screen.id,screen]));for(let board of selectedBoards){if(board.frames.length===0)continue;jobs.push({run:async()=>{try{let framed=(await Promise.all(board.frames.map(async(frame)=>{let screen=screenById.get(frame.screen);return screen?{frame,html:await renderHtml(screen,board.theme,frame.scheme??"light")}:null}))).filter((entry)=>entry!==null);if(framed.length===0)return null;let composite=buildBoardComposite(framed),png=await shoot(composite.html,composite.viewport,!1);if(!png)return warn(`screenshot of board "${board.id}" exceeds 4MB even downscaled \u2014 skipped`),null;return{kind:"board",id:board.id,path:`screenshots/${board.id}.png`,bytes:png}}catch(err){if(isBrowserMissing(err))throw err;return warn(`screenshot of board "${board.id}" failed \u2014 skipped (${message(err)})`),null}finally{advance()}}})}let shotLimit=MAX_SCREENSHOT_COUNT-1,results=Array.from({length:jobs.length},()=>null),nextJob=0,completedShots=0,reservedShots=0,browserMissing=!1,worker=async()=>{while(!browserMissing&&nextJob<jobs.length&&completedShots+reservedShots<shotLimit){let index=nextJob++;reservedShots+=1;try{let shot=await jobs[index]?.run();if(shot)results[index]=shot,completedShots+=1}catch(err){if(isBrowserMissing(err))browserMissing=!0;else throw err}finally{reservedShots-=1}}},concurrency=Math.max(1,Math.min(MAX_CONCURRENT_RENDERS,Math.floor(opts.concurrency??MAX_CONCURRENT_RENDERS)));if(await Promise.all(Array.from({length:Math.min(concurrency,jobs.length)},worker)),browserMissing)return warn("no headless browser available \u2014 publishing without screenshots"),null;if(nextJob<jobs.length)warn(`screenshot limit (${MAX_SCREENSHOT_COUNT}) reached \u2014 remaining shots skipped`);let files=[];for(let shot of results){if(!shot)continue;if(files.push({path:shot.path,bytes:shot.bytes}),shot.kind==="screen")manifest.screens[shot.id]=shot.path;else manifest.boards[shot.id]=shot.path}let coverSource=selectedBoards.map((b)=>manifest.boards[b.id]).find((p)=>p!==void 0)??selectedScreens.map((s)=>manifest.screens[s.id]).find((p)=>p!==void 0);if(!coverSource)return null;let source=files.find((f)=>f.path===coverSource);if(!source)return null;return manifest.cover="screenshots/cover.png",files.push({path:manifest.cover,bytes:source.bytes}),{manifest,files}}function message(err){let msg=err instanceof Error?err.message:String(err);return msg.split(`
2
+ import{ok,err,PROTECTED_SHARES_UNAVAILABLE,PublishDestinationsResponseSchema,LinkResponseSchema,LinkAccessResponseSchema,VersionUploadResponseSchema,VERSION_UPLOAD_PROGRESS_TYPE,VersionUploadLineSchema,PublishedDesignsResponseSchema,TeamsResponseSchema,unreachable,protocolViolation,uploadRaceLost,readFailure,cloudFailure,httpFailureFrom,boardLimitFrom,describeBoardLimit,describeCloudError,cloudJson,cloudFetch}from"./chunk-ak57bgnh.js";import{prettifyError,string,number,boolean,array,object,strictObject,record,_enum,literal,AnnotationSchema,CanvasNoteSchema,BoardSchema,ExtensionSchema,ViewportPresetSchema,LibrarySchema,StylingSchema,ScreenSchema,SnippetSchema,sanitizeSvgMarkup,ThemeSchema,ViewportSchema}from"./chunk-ghwy99py.js";import{buildBoardComposite,MAX_CONCURRENT_RENDERS,renderScreen,captureMountedDocument,captureScreenshot}from"./chunk-hhkjqvww.js";import{registryForScreen,renderPassForScreen,hostStylesheetsForScreen,writeJsonAtomic,managedDesignId,localDesignOf,recordedDesignName,orderedBoards,activeBoards,hostFilesFetch,storedHostSource,shipHostFiles,createCaptureMount}from"./chunk-mseawt58.js";import{LIVE_BUNDLE_PATH,withAssetServer,createOneShotLiveBundler,buildLiveModule}from"./chunk-976rm76x.js";import{checkCloudHealth}from"./chunk-5ts4fvd9.js";function publishedDesignSubtitle(design){let published=design.lastPublishedAt?`Published ${design.lastPublishedAt}`:"Publish time unavailable",who=design.ownerEmail?.trim()||design.ownerName?.trim(),publisher=who?`by ${who}`:"publisher unavailable",repo=design.git?.repo?.trim(),branch=design.git?.branch?.trim(),source=repo?`repo ${repo}${branch?` (${branch})`:""}`:"repository unavailable";return`${published} \xB7 ${publisher} \xB7 ${source}`}async function listPublishedDesigns(opts){let body=await cloudFetch(`${opts.baseUrl}/v1/links`,PublishedDesignsResponseSchema,{operation:"listing published designs",token:opts.token});if(!body.ok)return body;return ok((body.value.links??[]).filter((link)=>link.published).map((link)=>({...link,url:link.url.startsWith("http")?link.url:`${opts.baseUrl}${link.url}`})))}async function unpublishDesign(opts){let res=await fetch(`${opts.baseUrl}/v1/links/${encodeURIComponent(opts.slug)}`,{method:"DELETE",headers:{authorization:`Bearer ${opts.token}`}}).catch((error)=>error);if(!(res instanceof Response))return err(unreachable(res,{url:opts.baseUrl}));if(!res.ok)return err(await httpFailureFrom("unpublishing the design",res));return ok(void 0)}var VERSION_UPLOAD_IDLE_MS=60000,VERSION_UPLOAD_RETRIES=1,UPLOAD_CHUNK_BYTES=262144;async function listPublishDestinations(opts){let query=new URLSearchParams({folderId:opts.folderId});if(opts.teamId)query.set("teamId",opts.teamId);return cloudFetch(`${opts.baseUrl}/v1/publish-destinations?${query}`,PublishDestinationsResponseSchema,{operation:"listing publish destinations",token:opts.token})}async function uploadLinkBundle(opts){let{baseUrl,token,form}=opts,authorized={authorization:`Bearer ${token}`},createRes=await fetch(`${baseUrl}/v1/links`,{method:"POST",headers:authorized,body:JSON.stringify(opts.link)}).catch((error)=>error);if(!(createRes instanceof Response))return err(unreachable(createRes,{url:baseUrl}));if(createRes.status!==200&&createRes.status!==201)return err(await httpFailureFrom("link creation",createRes));let created=createRes.status===201,createdLink=await cloudJson(createRes,LinkResponseSchema,"link creation");if(!createdLink.ok)return createdLink;let link=createdLink.value;if(opts.link.publishMode==="new"&&!created)return err(protocolViolation("the cloud reused a link even though a new publish destination was requested"));if(opts.link.publishMode==="update"&&created)return await fetch(`${baseUrl}/v1/links/${link.slug}`,{method:"DELETE",headers:authorized}).catch(()=>{}),err(protocolViolation("the cloud created a link even though an existing destination was selected"));if(!created){let accessRes=await fetch(`${baseUrl}/v1/links/${link.slug}/access`,{method:"PUT",headers:{...authorized,"content-type":"application/json"},body:JSON.stringify({visibility:opts.link.visibility,password:opts.link.password??null,passwordExpiresAt:opts.link.password?opts.link.passwordExpiresAt??null:null,expectedVersionId:opts.link.expectedVersionId??null,...opts.link.audience?.length?{audience:opts.link.audience}:{},...opts.link.publicComments!==void 0?{publicComments:opts.link.publicComments}:{}})});if(!accessRes.ok)return err(await httpFailureFrom("privacy update",accessRes));let access=await cloudJson(accessRes,LinkAccessResponseSchema,"privacy update");if(!access.ok)return access;link={...link,...access.value}}if(form.append("publishMode",opts.link.publishMode),opts.link.expectedVersionId)form.append("expectedVersionId",opts.link.expectedVersionId);let discardCreatedLink=async()=>{if(!created)return;await fetch(`${baseUrl}/v1/links/${link.slug}`,{method:"DELETE",headers:authorized}).catch(()=>{})},attempt=await uploadVersionWithRetry({url:`${baseUrl}/v1/links/${link.slug}/versions`,headers:authorized,form,idleMs:opts.uploadTimeoutMs??VERSION_UPLOAD_IDLE_MS,retries:opts.uploadRetries??VERSION_UPLOAD_RETRIES,onProgress:opts.onProgress??(()=>{})});if(!attempt.ok)return await discardCreatedLink(),attempt;let upload=attempt.value,uploadRes=upload.response;if(uploadRes.status!==201){let{detail,code}=await readFailure(uploadRes);if(upload.transientFailures>0&&uploadRes.status===409&&/slot changed|already has a version/i.test(detail))return err(uploadRaceLost());return await discardCreatedLink(),err(cloudFailure("upload",uploadRes.status,detail,code))}let parsed=await cloudJson(uploadRes,VersionUploadResponseSchema,"upload");if(!parsed.ok)return parsed;let uploaded=parsed.value;return ok({link:{slug:link.slug,visibility:link.visibility??opts.link.visibility,passwordProtected:link.passwordProtected??opts.link.password!=null,...link.audience!==void 0?{audience:link.audience}:{},...link.publicComments!==void 0?{publicComments:link.publicComments}:{}},created,files:uploaded.files,bytes:uploaded.bytes,shareUrl:uploaded.url.startsWith("http")?uploaded.url:`${baseUrl}${uploaded.url}`,...uploaded.tier!==void 0?{tier:uploaded.tier}:{},...uploaded.history!==void 0?{history:uploaded.history}:{}})}async function uploadVersionWithRetry(opts){let attempts=Math.max(1,Math.floor(opts.retries)+1),transientFailures=0,lastNetworkError="unknown network error",lastTimedOut=!1,stalled=(retried)=>unreachable(`nothing sent or received for ${formatDuration(opts.idleMs)}${retried}`,{url:opts.url,timedOut:!0}),encoded=new Response(opts.form),contentType=encoded.headers.get("content-type")??"multipart/form-data",bundle=new Uint8Array(await encoded.arrayBuffer());for(let attempt=1;attempt<=attempts;attempt+=1){let controller=new AbortController,timedOut=!1,timer,stillGoing=(graceMs=0)=>{clearTimeout(timer),timer=setTimeout(()=>{timedOut=!0,controller.abort()},Math.max(1,opts.idleMs+graceMs))};stillGoing();let sent=0,lastPullAt=performance.now(),buffered=null,drainMs=(now)=>{if(!buffered||now<=buffered.at)return 0;let rate=(sent-buffered.sent)/(now-buffered.at);return rate>0?2*buffered.sent/rate:0},body=new ReadableStream({pull(stream){if(sent>=bundle.byteLength){stream.close();return}let now=performance.now();if(!buffered&&now-lastPullAt>20)buffered={at:now,sent};lastPullAt=now;let chunk=bundle.subarray(sent,sent+UPLOAD_CHUNK_BYTES);stream.enqueue(chunk),sent+=chunk.byteLength,stillGoing(sent>=bundle.byteLength?drainMs(now):0),opts.onProgress({stage:"sending",done:sent,total:bundle.byteLength})}},{highWaterMark:0});try{let response=await fetch(opts.url,{method:"POST",headers:{...opts.headers,accept:`${VERSION_UPLOAD_PROGRESS_TYPE}, application/json`,"content-type":contentType,"content-length":String(bundle.byteLength)},body,signal:controller.signal});stillGoing();let answered=isProgressStream(response)?await readProgressStream(response,stillGoing,opts.onProgress):ok(response);if(!answered.ok)return answered;if(answered.value.status<500||attempt===attempts)return ok({response:answered.value,transientFailures});transientFailures+=1,await answered.value.body?.cancel().catch(()=>{})}catch(error){if(transientFailures+=1,lastTimedOut=timedOut,lastNetworkError=error instanceof Error?error.message:String(error),attempt===attempts){let retried=attempts>1?` after ${attempts} attempts`:"";return err(timedOut?stalled(retried):unreachable(`version upload${retried}: ${lastNetworkError}`,{url:opts.url}))}}finally{clearTimeout(timer)}}return err(lastTimedOut?stalled(""):unreachable(`version upload: ${lastNetworkError}`,{url:opts.url}))}function isProgressStream(response){return response.status===200&&(response.headers.get("content-type")??"").startsWith(VERSION_UPLOAD_PROGRESS_TYPE)}async function readProgressStream(response,stillGoing,onProgress){if(!response.body)throw Error("the cloud's upload answer had no body");let decoder=new TextDecoder,pending="";for await(let chunk of response.body){stillGoing(),pending+=decoder.decode(chunk,{stream:!0});let newline=pending.indexOf(`
3
+ `);while(newline!==-1){let text=pending.slice(0,newline).trim();if(pending=pending.slice(newline+1),newline=pending.indexOf(`
4
+ `),!text)continue;let line=parseUploadLine(text);if(!line)return err(protocolViolation(`unreadable upload progress line: ${text}`));if(line.type==="progress"){onProgress({stage:line.stage,done:line.done,total:line.total});continue}return ok(new Response(JSON.stringify(line.body??null),{status:line.status,headers:{"content-type":"application/json"}}))}}throw Error("the cloud closed the upload before answering")}function parseUploadLine(text){try{let parsed=VersionUploadLineSchema.safeParse(JSON.parse(text));return parsed.success?parsed.data:null}catch{return null}}function formatDuration(ms){return ms>=1000?`${Math.round(ms/1000)}s`:`${Math.max(1,Math.round(ms))}ms`}import{execFileSync}from"child_process";import{existsSync}from"fs";import{readFile}from"fs/promises";import{join}from"path";var DESIGN_BUNDLE_FORMAT=2,BundleScreenshotsSchema=object({cover:string().optional(),screens:record(string(),string()).optional(),boards:record(string(),string()).optional()}),DesignBundleMetaSchema=object({formatVersion:number().int().positive().optional(),title:string().optional(),screens:array(object({id:string(),name:string().optional()})).optional(),boards:array(object({id:string()})).optional(),screenshots:BundleScreenshotsSchema.optional()});var DesignBundleSchema=strictObject({formatVersion:literal(DESIGN_BUNDLE_FORMAT),title:string(),viewport:ViewportSchema,defaultLibrary:string(),libraries:record(string(),LibrarySchema),extensions:record(string(),ExtensionSchema),styling:StylingSchema.optional(),viewportPresets:array(ViewportPresetSchema),theme:ThemeSchema,themes:record(string(),ThemeSchema),customCss:string(),snippets:array(SnippetSchema),screens:array(ScreenSchema),boards:array(BoardSchema),annotations:record(string(),array(AnnotationSchema)),notes:record(string(),array(CanvasNoteSchema)),live:boolean(),snapshotCssPath:string(),bundlePath:string().optional(),hostStylesheets:array(string().regex(/^(?:assets\/host\/[A-Za-z0-9._@~+-][A-Za-z0-9._@~+/-]*\.css|https:\/\/\S+)$/)).optional(),appStylesheets:record(string(),string().regex(/^app-[a-z0-9]+\.css$/)).optional(),frozenScreens:record(string(),record(string(),string().regex(/^frozen\/[a-z0-9]+\.json$/))).optional(),screenshots:object({cover:string(),screens:record(string(),string()),boards:record(string(),string())}).optional()}),FrozenScreenSchema=strictObject({head:array(strictObject({tag:_enum(["style","link"]),attributes:record(string(),string()),css:string().optional(),file:string().regex(/^(?:snapshot|app-[a-z0-9]+|frozen\/[a-z0-9]+)\.css$/).optional()})),body:string(),htmlAttributes:record(string(),string()),bodyAttributes:record(string(),string())});function frozenVariantKey(themeName,scheme){return`${themeName}/${scheme}`}import{homedir}from"os";import{delimiter,dirname,resolve}from"path";function designGitEnv(folder){let ceilings=[homedir()];if(managedDesignId(folder)||localDesignOf(folder))ceilings.push(dirname(resolve(folder)));let inherited=process.env.GIT_CEILING_DIRECTORIES;if(inherited)ceilings.push(inherited);return{...process.env,GIT_CEILING_DIRECTORIES:ceilings.join(delimiter)}}var MAX_SCREENSHOT_BYTES=4194304,MAX_SCREENSHOT_COUNT=120,DOWNSCALE_WIDTH=1280;function isBrowserMissing(err){return err instanceof Error&&err.name==="BrowserMissingError"}async function captureBundleScreenshots(opts){let{screens,boards,viewport,renderHtml,capture,warn,progress}=opts,selectedScreens=opts.screenIds?screens.filter((screen)=>opts.screenIds?.has(screen.id)):screens,selectedBoards=opts.boardIds?boards.filter((board)=>opts.boardIds?.has(board.id)):boards,manifest={cover:"",screens:{},boards:{}},total=selectedScreens.length+selectedBoards.filter((board)=>board.frames.length>0).length,done=0,advance=()=>{done+=1,progress?.(done,total)},shoot=async(html,vp,fullPage,screen)=>{let of=screen?{screen}:{},png=await capture({html,viewport:vp,fullPage,deviceScaleFactor:1,...of});if(png.byteLength>MAX_SCREENSHOT_BYTES&&DOWNSCALE_WIDTH<vp.w)png=await capture({html,viewport:vp,fullPage,deviceScaleFactor:DOWNSCALE_WIDTH/vp.w,...of});return png.byteLength<=MAX_SCREENSHOT_BYTES?png:null},jobs=[];for(let screen of selectedScreens)jobs.push({run:async()=>{try{let png=await shoot(await renderHtml(screen),viewport,!0,screen);if(!png)return warn(`screenshot of screen "${screen.id}" exceeds 4MB even downscaled \u2014 skipped`),null;return{kind:"screen",id:screen.id,path:`screenshots/${screen.id}.png`,bytes:png}}catch(err){if(isBrowserMissing(err))throw err;return warn(`screenshot of screen "${screen.id}" failed \u2014 skipped (${message(err)})`),null}finally{advance()}}});let screenById=new Map(screens.map((screen)=>[screen.id,screen]));for(let board of selectedBoards){if(board.frames.length===0)continue;jobs.push({run:async()=>{try{let framed=(await Promise.all(board.frames.map(async(frame)=>{let screen=screenById.get(frame.screen);return screen?{frame,html:await renderHtml(screen,board.theme,frame.scheme??"light")}:null}))).filter((entry)=>entry!==null);if(framed.length===0)return null;let composite=buildBoardComposite(framed),png=await shoot(composite.html,composite.viewport,!1);if(!png)return warn(`screenshot of board "${board.id}" exceeds 4MB even downscaled \u2014 skipped`),null;return{kind:"board",id:board.id,path:`screenshots/${board.id}.png`,bytes:png}}catch(err){if(isBrowserMissing(err))throw err;return warn(`screenshot of board "${board.id}" failed \u2014 skipped (${message(err)})`),null}finally{advance()}}})}let shotLimit=MAX_SCREENSHOT_COUNT-1,results=Array.from({length:jobs.length},()=>null),nextJob=0,completedShots=0,reservedShots=0,browserMissing=!1,worker=async()=>{while(!browserMissing&&nextJob<jobs.length&&completedShots+reservedShots<shotLimit){let index=nextJob++;reservedShots+=1;try{let shot=await jobs[index]?.run();if(shot)results[index]=shot,completedShots+=1}catch(err){if(isBrowserMissing(err))browserMissing=!0;else throw err}finally{reservedShots-=1}}},concurrency=Math.max(1,Math.min(MAX_CONCURRENT_RENDERS,Math.floor(opts.concurrency??MAX_CONCURRENT_RENDERS)));if(await Promise.all(Array.from({length:Math.min(concurrency,jobs.length)},worker)),browserMissing)return warn("no headless browser available \u2014 publishing without screenshots"),null;if(nextJob<jobs.length)warn(`screenshot limit (${MAX_SCREENSHOT_COUNT}) reached \u2014 remaining shots skipped`);let files=[];for(let shot of results){if(!shot)continue;if(files.push({path:shot.path,bytes:shot.bytes}),shot.kind==="screen")manifest.screens[shot.id]=shot.path;else manifest.boards[shot.id]=shot.path}let coverSource=selectedBoards.map((b)=>manifest.boards[b.id]).find((p)=>p!==void 0)??selectedScreens.map((s)=>manifest.screens[s.id]).find((p)=>p!==void 0);if(!coverSource)return null;let source=files.find((f)=>f.path===coverSource);if(!source)return null;return manifest.cover="screenshots/cover.png",files.push({path:manifest.cover,bytes:source.bytes}),{manifest,files}}function message(err){let msg=err instanceof Error?err.message:String(err);return msg.split(`
3
5
  `)[0]??msg}var cloudUnhealthy=(detail)=>({kind:"CloudUnhealthy",detail}),noScreens=(root)=>({kind:"NoScreens",root}),noBoardScreens=(unplaced)=>({kind:"NoBoardScreens",unplaced}),bundleInvalid=(detail)=>({kind:"BundleInvalid",detail}),teamNotFound=(requested)=>({kind:"TeamNotFound",requested}),teamAmbiguous=(requested)=>({kind:"TeamAmbiguous",requested}),teamNotPublishable=(requested,reviewer)=>({kind:"TeamNotPublishable",requested,reviewer}),noPublishableTeam=(reviewer)=>({kind:"NoPublishableTeam",reviewer}),teamChoiceRequired=(names)=>({kind:"TeamChoiceRequired",names}),REVIEWERS_CANNOT_PUBLISH="reviewers can view and comment on boards, but not publish them \u2014 to publish, ask an owner or admin to make you a member",FREE_PLAN_OWNER_ONLY="on the Free plan only the organization owner publishes \u2014 ask the owner to renew, or leave the organization to publish on your own";function unplacedHint(unplaced){if(unplaced.length===0)return"";let shown=unplaced.slice(0,5).join(", "),more=unplaced.length>5?`, and ${unplaced.length-5} more`:"",[subject,it]=unplaced.length===1?["1 screen is","it"]:[`${unplaced.length} screens are`,"each"];return` ${subject} on no board (${shown}${more}): add a frame for ${it} on the canvas, or with add_frame.`}function describePublishError(error){switch(error.kind){case"CloudUnhealthy":return error.detail;case"NoScreens":return`no screens found in ${error.root} \u2014 is this a velloo design folder?`;case"NoBoardScreens":return`the selected boards have no screens.${unplacedHint(error.unplaced)}`;case"BundleInvalid":return`velloo built an invalid design bundle and did not upload it: ${error.detail}. This is a bug \u2014 please report it.`;case"TeamNotFound":return`no team named or identified by '${error.requested}'`;case"TeamAmbiguous":return`more than one team is named '${error.requested}'; pass its UUID`;case"TeamNotPublishable":return error.reviewer?REVIEWERS_CANNOT_PUBLISH:`you can't publish to '${error.requested}' \u2014 you can only publish to teams you're on`;case"NoPublishableTeam":return error.reviewer?REVIEWERS_CANNOT_PUBLISH:FREE_PLAN_OWNER_ONLY;case"TeamChoiceRequired":return`you can publish to more than one team \u2014 choose one (${error.names.join(", ")}) with --team`;case"HttpFailure":{if(error.status===403&&/protected shares/i.test(error.detail))return`${PROTECTED_SHARES_UNAVAILABLE}. Publish publicly, or upgrade your plan from your cloud's billing page`;let limit=boardLimitFrom(error);if(limit)return`${describeBoardLimit(limit)}. Run \`velloo publish list\` to see them, or upgrade your plan from your cloud's billing page`;return describeCloudError(error)}default:return describeCloudError(error)}}var normalizedBoardIds=(boardIds)=>[...new Set(boardIds)].sort();function publishSlotMismatches(slot,current){let mismatches=[];if(!slot.context.contextKnown)mismatches.push("older publish has no board-selection context");if(!(current.candidateTeamIds?slot.teamId!==null&&current.candidateTeamIds.includes(slot.teamId):slot.teamId===current.teamId))mismatches.push("team differs");if(JSON.stringify(normalizedBoardIds(slot.context.boardIds))!==JSON.stringify(normalizedBoardIds(current.boardIds)))mismatches.push("board selection differs");if(slot.context.repo!==current.repo)mismatches.push("repository differs");else if(current.repo!==null){if(!slot.context.branch||!current.branch)mismatches.push("branch is unavailable");else if(slot.context.branch!==current.branch)mismatches.push("branch differs")}return mismatches}function recommendedPublishSlot(slots,current){return exactPublishSlots(slots,current)[0]??null}function exactPublishSlots(slots,current){return slots.filter((slot)=>publishSlotMismatches(slot,current).length===0).sort((left,right)=>publishedAt(right.lastPublishedAt)-publishedAt(left.lastPublishedAt))}var publishedAt=(value)=>{let parsed=value?Date.parse(value):Number.NaN;return Number.isFinite(parsed)?parsed:Number.NEGATIVE_INFINITY},PUBLISH_VIEWPORT={w:1440,h:900};function defaultPublishTitle(folderRoot){return`${recordedDesignName(folderRoot)??folderRoot.split("/").filter(Boolean).pop()} designs`}async function ensureFolderId(folder,existing,report){if(existing)return existing;let path=join(folder,".design","config.json"),raw=JSON.parse(await readFile(path,"utf8")),folderId=crypto.randomUUID();return await writeJsonAtomic(path,{...raw,folderId}),report({kind:"note",message:"assigned this folder a cloud id (.design/config.json folderId) \u2014 commit it so every clone finds the folder's share links."}),folderId}function reportProvenance(git,report){if(git.repo){report({kind:"info",message:git.branch?`source: ${git.repo} on ${git.branch}`:`source: ${git.repo} (detached HEAD \u2014 no branch recorded)`});return}report({kind:"info",message:git.branch?`source: branch ${git.branch} \u2014 no git remote, publishing without a repository`:"source: not a git repository \u2014 publishing without repository or branch"})}function gitProbe(folder){return{encoding:"utf8",stdio:["ignore","pipe","ignore"],env:designGitEnv(folder)}}function gitCommitSha(folder){try{let probe=gitProbe(folder);if(execFileSync("git",["-C",folder,"status","--porcelain"],probe).trim().length>0)return null;return execFileSync("git",["-C",folder,"rev-parse","HEAD"],probe).trim()}catch{return null}}function normalizeRemote(url){let rest=url.trim().replace(/\.git\/?$/,"");if(/^[./~]/.test(rest)||/^[a-z]:[\\/]/i.test(rest)||rest.startsWith("file://"))return null;let scp=/^(?:[\w.-]+@)?([\w.-]+):(?!\/\/)(.+)$/.exec(rest);if(scp?.[1]&&scp[2])return`${scp[1]}/${scp[2].replace(/^\/+/,"")}`;try{let parsed=new URL(rest.includes("://")?rest:`https://${rest}`);if(!parsed.hostname||!parsed.pathname||parsed.pathname==="/")return null;return`${parsed.hostname}${parsed.pathname.replace(/\/+$/,"")}`}catch{return null}}function gitContext(folder){let probe=gitProbe(folder),run=(args)=>{try{return execFileSync("git",["-C",folder,...args],probe).trim()||null}catch{return null}},branchRaw=run(["rev-parse","--abbrev-ref","HEAD"]),remote=run(["remote","get-url","origin"]);return{repo:remote?normalizeRemote(remote):null,branch:branchRaw==="HEAD"?null:branchRaw}}function publishableTeams(teams){return teams.filter((team)=>team.canPublish!==!1)}function resolvePublishTeam(teams,requested){if(teams.length===0)return requested?err(teamNotFound(requested)):ok({kind:"personal"});let reviewer=teams.some((team)=>team.role==="reviewer"),publishable=publishableTeams(teams);if(requested){let named=(candidates)=>candidates.filter((team)=>team.id===requested||team.name.toLowerCase()===requested.toLowerCase()),exact=named(publishable);if(exact.length>1)return err(teamAmbiguous(requested));let[team]=exact;if(team)return ok({kind:"team",team});return err(named(teams).length>0?teamNotPublishable(requested,reviewer):publishable.length===0?noPublishableTeam(reviewer):teamNotFound(requested))}let[only,...rest]=publishable;if(!only)return err(noPublishableTeam(reviewer));return rest.length===0?ok({kind:"team",team:only}):ok({kind:"choose",teams:publishable})}async function listTeams(baseUrl,token){let body=await cloudFetch(`${baseUrl}/v1/teams/mine`,TeamsResponseSchema,{operation:"listing teams",token});return body.ok?ok(body.value.teams):body}function selectBoards(design,boardIds){if(!boardIds||boardIds.length===0)return activeBoards(design).map(([,board])=>board);let wanted=new Set(boardIds);return orderedBoards(design).map(([,board])=>board).filter((board)=>wanted.has(board.id))}var SNAPSHOT_CSS_PATH="snapshot.css",SHARED_CSS_MIN_LENGTH=2048;function frozenVariantsOf(screen,design,boards){let themes=new Map,see=(themeName,pinnedDark)=>{let theme=(themeName?design.themes.get(themeName):void 0)??design.theme,seen=themes.get(theme.name);themes.set(theme.name,{themeName:seen?seen.themeName:themeName,theme,dark:Boolean(seen?.dark)||pinnedDark||Boolean(theme.colorsDark)})};see(void 0,!1);for(let board of boards)for(let frame of board.frames)if(frame.screen===screen.id)see(board.theme,frame.scheme==="dark");return[...themes.values()].flatMap(({themeName,theme,dark})=>(dark?["light","dark"]:["light"]).map((scheme)=>({key:`${screen.id}\x00${theme.name}\x00${scheme}`,screen,themeName,theme,scheme})))}async function publishDesign(cloud,pipeline,request,report=()=>{}){let{folder:design}=pipeline,{root,config}=design;report({kind:"step",step:"check",message:"checking the cloud"});let health=await checkCloudHealth(cloud.baseUrl);if(health.status==="unreachable")return err(unreachable(health.reason,{url:cloud.baseUrl}));if(health.status==="unhealthy")return err(cloudUnhealthy(health.detail));if(design.screens.size===0)return err(noScreens(root));report({kind:"step",step:"select",message:"collecting boards"});let boards=selectBoards(design,request.boardIds),screenIds=Boolean(request.boardIds&&request.boardIds.length>0)?new Set(boards.flatMap((b)=>b.frames.map((f)=>f.screen))):null,screens=screenIds?[...design.screens.values()].filter((s)=>screenIds.has(s.id)):[...design.screens.values()];if(screens.length===0){let placed=new Set([...design.boards.values()].flatMap((board)=>board.frames.map((frame)=>frame.screen)));return err(noBoardScreens([...design.screens.keys()].filter((id)=>!placed.has(id))))}let viewport=request.viewport??PUBLISH_VIEWPORT,title=request.title?.trim()||defaultPublishTitle(root),form=new FormData,bundleFiles=0,bundleBytes=0,addFile=(path,data,type)=>{if(typeof data==="string"?data.length===0:data.byteLength===0)return report({kind:"warn",message:`skipped empty file: ${path}`}),!1;return form.append("file",new File([data],path,type?{type}:void 0)),bundleFiles+=1,bundleBytes+=typeof data==="string"?new TextEncoder().encode(data).byteLength:data.byteLength,!0},bundler=pipeline.liveBundler??createOneShotLiveBundler(root,config);report({kind:"step",step:"styles",message:"compiling styles"});let snapshotCss=await pipeline.snapshotCss(),live=!1,liveCode=null;if(bundler){report({kind:"step",step:"bundle",message:"bundling live components"});let bundle=await buildLiveModule(bundler);for(let message of bundle.warnings)report({kind:"warn",message});if(bundle.code!==null&&addFile("bundle.js",bundle.code,"text/javascript"))liveCode=bundle.code,live=!0}report({kind:"step",step:"capture",message:"capturing previews"});let mount=createCaptureMount(pipeline.folder,pipeline.providers,pipeline.defaultProvider),appCss=new Map,appStylesheets={},assetBearing=[],shipped=new Set,sharedCss=new Map;if(snapshotCss)sharedCss.set(snapshotCss,SNAPSHOT_CSS_PATH);let addOnce=(path,data,type)=>{if(shipped.has(path))return;shipped.add(path),addFile(path,data,type)};for(let screen of screens){let css=await mount.appCss(screen).catch(()=>"");if(css.trim()==="")continue;appCss.set(screen.id,css);let path=`app-${Bun.hash(css).toString(36)}.css`;addOnce(path,css,"text/css"),appStylesheets[screen.id]=path,sharedCss.set(css,path),assetBearing.push(css)}let frozenFiles=new Map,frozenAt=new Map,freezeAttempted=new Set,notFrozen=new Set,browserMissing=!1,nameOf=(screen)=>screen.name||screen.id,shareStyle=(style)=>{let{tag,attributes,css}=style;if(css===void 0)return{tag,attributes};if(css.length<SHARED_CSS_MIN_LENGTH)return{tag,attributes,css};let file=sharedCss.get(css);if(!file)file=`frozen/${Bun.hash(css).toString(36)}.css`,frozenFiles.set(file,css),sharedCss.set(css,file);return{tag,attributes,file}},keepFrozen=(variant,page)=>{if(freezeAttempted.add(variant.key),!page?.mounted){notFrozen.add(nameOf(variant.screen));return}let frozen={head:page.head.map(shareStyle),body:page.body,htmlAttributes:page.htmlAttributes,bodyAttributes:page.bodyAttributes},json=JSON.stringify(frozen),path=`frozen/${Bun.hash(json).toString(36)}.json`;frozenFiles.set(path,json);let variants=frozenAt.get(variant.screen.id)??new Map;variants.set(frozenVariantKey(variant.theme.name,variant.scheme),path),frozenAt.set(variant.screen.id,variants)},shots=await withAssetServer(root,liveCode,async(baseHref)=>{let htmlCache=new Map,renderHtml=async(screen,themeName,scheme="light")=>{let theme=(themeName?design.themes.get(themeName):void 0)??design.theme,key=`${screen.id}\x00${theme.name}\x00${scheme}`,cached=htmlCache.get(key);if(cached)return cached;let canvasBundle=await mount.forScreen(screen,theme,scheme==="dark"),rendering=renderScreen(screen,theme,{viewport,snapshotCss,registry:registryForScreen(screen,pipeline.providers,pipeline.defaultProvider,config.extensions??{},config.styling?.framework),renderPass:renderPassForScreen(screen,pipeline.providers,pipeline.defaultProvider,theme),snippets:design.snippets,customCss:design.customCss,appCss:appCss.get(screen.id),dark:scheme==="dark",baseHref,includeRuntime:!1,...live?{liveBundleUrl:LIVE_BUNDLE_PATH}:{},...canvasBundle?{canvasBundle}:{},hostStylesheets:hostStylesheetsForScreen(screen,pipeline.providers,pipeline.defaultProvider,config.hostApp)}).then(({html})=>html);return htmlCache.set(key,rendering),rendering},variants=[];for(let screen of screens){if(await mount.forScreen(screen,design.theme,!1)===void 0)continue;variants.push(...frozenVariantsOf(screen,design,boards))}let previewed=(screen)=>request.screenshotSelection?.screenIds.has(screen.id)??!0,withPreview=new Map;for(let variant of variants)if(variant.themeName===void 0&&variant.scheme==="light"&&previewed(variant.screen))withPreview.set(variant.screen.id,variant);let freeze=async(variant)=>{try{keepFrozen(variant,await captureMountedDocument({html:await renderHtml(variant.screen,variant.themeName,variant.scheme),viewport}))}catch(error){if(error instanceof Error&&error.name==="BrowserMissingError")browserMissing=!0;freezeAttempted.add(variant.key),notFrozen.add(nameOf(variant.screen))}},ownLoads=Promise.all(variants.filter((variant)=>withPreview.get(variant.screen.id)!==variant).map(freeze)),shots=await captureBundleScreenshots({screens,boards,...request.screenshotSelection?{screenIds:request.screenshotSelection.screenIds,boardIds:request.screenshotSelection.boardIds}:{},viewport,renderHtml,capture:async(req)=>{let variant=req.screen?withPreview.get(req.screen.id):void 0,toFreeze=variant!==void 0&&!freezeAttempted.has(variant.key),shot=await captureScreenshot({html:req.html,viewport:req.viewport,fullPage:req.fullPage,deviceScaleFactor:req.deviceScaleFactor,...toFreeze?{freeze:!0}:{}});if(toFreeze)keepFrozen(variant,shot.frozen);return shot.png},warn:(message)=>report({kind:"warn",message}),progress:(done,total)=>report({kind:"capture",done,total})});return await ownLoads,await Promise.all(variants.filter((variant)=>!freezeAttempted.has(variant.key)).map(freeze)),shots},{bundle:mount.serve,host:hostFilesFetch(()=>root)});for(let path of[...frozenFiles.keys()].sort()){let text=frozenFiles.get(path)??"";addFile(path,text,path.endsWith(".css")?"text/css":"application/json"),assetBearing.push(text)}let frozenScreens={};for(let screen of screens){let at=frozenAt.get(screen.id);if(at)frozenScreens[screen.id]=Object.fromEntries([...at].sort(([a],[b])=>a<b?-1:1))}for(let f of shots?.files??[])addFile(f.path,f.bytes,"image/png");if(notFrozen.size>0)report({kind:"warn",message:`the share will not match the canvas for ${[...notFrozen].sort().join(", ")}: the canvas draws ${notFrozen.size===1?"it":"them"} with the app's own components, which could not be mounted here, so a viewer sees velloo's stand-ins instead. ${browserMissing?"Run `velloo browser install` and publish again.":"component_status says what stopped them mounting."}`});let host=Object.values(pipeline.providers).some((provider)=>provider.hostStylesheets)?await shipHostFiles({source:storedHostSource(root),stylesheets:config.hostApp?.stylesheets??[],screens,snippets:[...design.snippets.values()],warn:(message)=>report({kind:"warn",message}),designAsset:(path)=>existsSync(join(root,path))}):{screens,snippets:[...design.snippets.values()],files:[],stylesheets:[]};for(let f of host.files)addFile(f.path,f.bytes,f.type);let annotations=Object.fromEntries([...design.annotations].filter(([screenId,list])=>list.length>0&&screens.some((s)=>s.id===screenId))),notes=Object.fromEntries([...design.notes].filter(([boardId,list])=>list.length>0&&boards.some((b)=>b.id===boardId))),designDoc={formatVersion:DESIGN_BUNDLE_FORMAT,title,viewport,defaultLibrary:config.defaultLibrary,libraries:config.libraries,extensions:config.extensions??{},...config.styling?{styling:config.styling}:{},viewportPresets:config.viewportPresets??[],theme:design.theme,themes:Object.fromEntries(design.themes),customCss:design.customCss,snippets:host.snippets,screens:host.screens,boards,annotations,notes,live,snapshotCssPath:SNAPSHOT_CSS_PATH,...live?{bundlePath:"bundle.js"}:{},...host.stylesheets.length>0?{hostStylesheets:host.stylesheets}:{},...Object.keys(appStylesheets).length>0?{appStylesheets}:{},...Object.keys(frozenScreens).length>0?{frozenScreens}:{},...shots?{screenshots:shots.manifest}:{}},validated=DesignBundleSchema.safeParse(designDoc);if(!validated.success)return err(bundleInvalid(prettifyError(validated.error)));addFile("design.json",JSON.stringify(designDoc),"application/json"),addFile(SNAPSHOT_CSS_PATH,snapshotCss||`/* this folder uses no CSS framework */
4
- `,"text/css");let assetRefs=new Set,assetRe=/\/assets\/[A-Za-z0-9._@\-/]+/g;for(let source of[...host.screens,...host.snippets])for(let m of JSON.stringify(source).matchAll(assetRe))assetRefs.add(m[0]);for(let text of[design.customCss,...assetBearing])for(let m of text.matchAll(assetRe))assetRefs.add(m[0]);for(let ref of assetRefs){if(ref.startsWith("/assets/host/"))continue;let rel=ref.replace(/^\//,"");try{let bytes=await readFile(join(root,rel));addFile(rel,/\.svg$/i.test(rel)?Buffer.from(sanitizeSvgMarkup(bytes.toString("utf8")),"utf8"):bytes)}catch{report({kind:"warn",message:`asset not found: ${rel}`})}}let commitSha=gitCommitSha(root);if(commitSha)form.append("commitSha",commitSha);let git=request.provenance??gitContext(root);if(reportProvenance(git,report),git.repo)form.append("gitRepo",git.repo);if(git.branch)form.append("gitBranch",git.branch);let folderId=await ensureFolderId(root,config.folderId,report);report({kind:"step",step:"upload",message:`uploading ${bundleFiles} file${bundleFiles===1?"":"s"} (${formatBytes(bundleBytes)})`});let uploaded=await uploadLinkBundle({baseUrl:cloud.baseUrl,token:cloud.token,link:{...request.destination.slug?{slug:request.destination.slug}:{},folderId,publishMode:request.destination.mode,...request.destination.mode==="update"?{expectedVersionId:request.destination.expectedVersionId}:{},title,visibility:request.visibility,...request.teamId?{teamId:request.teamId}:{},...request.audience?.length?{audience:request.audience}:{},...request.publicComments!==void 0?{publicComments:request.publicComments}:{},...request.password?{password:request.password}:{},...request.passwordExpiresAt?{passwordExpiresAt:request.passwordExpiresAt}:{}},form});if(!uploaded.ok)return uploaded;let upload=uploaded.value;return ok({shareUrl:upload.shareUrl,slug:upload.link.slug,visibility:upload.link.visibility,passwordProtected:upload.link.passwordProtected,...upload.link.audience!==void 0?{audience:upload.link.audience}:{},...upload.link.publicComments!==void 0?{publicComments:upload.link.publicComments}:{},files:upload.files,bytes:upload.bytes,screenshots:shots?.files.length??0,boards:boards.length,screens:screens.length,commitSha,created:upload.created,...upload.tier!==void 0?{tier:upload.tier}:{},...upload.history!==void 0?{history:upload.history}:{}})}function formatBytes(bytes){if(bytes>=1048576)return`${(bytes/1048576).toFixed(1)} MB`;if(bytes>=1024)return`${Math.round(bytes/1024)} KB`;return`${bytes} B`}
5
- export{publishedDesignSubtitle,listPublishedDesigns,unpublishDesign,listPublishDestinations,designGitEnv,teamChoiceRequired,describePublishError,recommendedPublishSlot,exactPublishSlots,PUBLISH_VIEWPORT,gitContext,publishableTeams,resolvePublishTeam,listTeams,publishDesign};
6
+ `,"text/css");let assetRefs=new Set,assetRe=/\/assets\/[A-Za-z0-9._@\-/]+/g;for(let source of[...host.screens,...host.snippets])for(let m of JSON.stringify(source).matchAll(assetRe))assetRefs.add(m[0]);for(let text of[design.customCss,...assetBearing])for(let m of text.matchAll(assetRe))assetRefs.add(m[0]);for(let ref of assetRefs){if(ref.startsWith("/assets/host/"))continue;let rel=ref.replace(/^\//,"");try{let bytes=await readFile(join(root,rel));addFile(rel,/\.svg$/i.test(rel)?Buffer.from(sanitizeSvgMarkup(bytes.toString("utf8")),"utf8"):bytes)}catch{report({kind:"warn",message:`asset not found: ${rel}`})}}let commitSha=gitCommitSha(root);if(commitSha)form.append("commitSha",commitSha);let git=request.provenance??gitContext(root);if(reportProvenance(git,report),git.repo)form.append("gitRepo",git.repo);if(git.branch)form.append("gitBranch",git.branch);let folderId=await ensureFolderId(root,config.folderId,report);report({kind:"step",step:"upload",message:`uploading ${bundleFiles} file${bundleFiles===1?"":"s"} (${formatBytes(bundleBytes)})`});let uploaded=await uploadLinkBundle({baseUrl:cloud.baseUrl,token:cloud.token,link:{...request.destination.slug?{slug:request.destination.slug}:{},folderId,publishMode:request.destination.mode,...request.destination.mode==="update"?{expectedVersionId:request.destination.expectedVersionId}:{},title,visibility:request.visibility,...request.teamId?{teamId:request.teamId}:{},...request.audience?.length?{audience:request.audience}:{},...request.publicComments!==void 0?{publicComments:request.publicComments}:{},...request.password?{password:request.password}:{},...request.passwordExpiresAt?{passwordExpiresAt:request.passwordExpiresAt}:{}},form,onProgress:(progress)=>report({kind:"upload",...progress})});if(!uploaded.ok)return uploaded;let upload=uploaded.value;return ok({shareUrl:upload.shareUrl,slug:upload.link.slug,visibility:upload.link.visibility,passwordProtected:upload.link.passwordProtected,...upload.link.audience!==void 0?{audience:upload.link.audience}:{},...upload.link.publicComments!==void 0?{publicComments:upload.link.publicComments}:{},files:upload.files,bytes:upload.bytes,screenshots:shots?.files.length??0,boards:boards.length,screens:screens.length,commitSha,created:upload.created,...upload.tier!==void 0?{tier:upload.tier}:{},...upload.history!==void 0?{history:upload.history}:{}})}function describeUploadProgress(progress){switch(progress.stage){case"sending":return`uploading ${formatBytes(progress.done)} of ${formatBytes(progress.total)}`;case"processing":return`checking files on the cloud ${progress.done}/${progress.total}`;case"storing":return`storing files on the cloud ${progress.done}/${progress.total}`}}function formatBytes(bytes){if(bytes>=1048576)return`${(bytes/1048576).toFixed(1)} MB`;if(bytes>=1024)return`${Math.round(bytes/1024)} KB`;return`${bytes} B`}
7
+ export{publishedDesignSubtitle,listPublishedDesigns,unpublishDesign,listPublishDestinations,designGitEnv,teamChoiceRequired,describePublishError,recommendedPublishSlot,exactPublishSlots,PUBLISH_VIEWPORT,gitContext,publishableTeams,resolvePublishTeam,listTeams,publishDesign,describeUploadProgress};
@@ -0,0 +1,40 @@
1
+ // @bun
2
+ import{isCancel,multiselect,log,select,manifestListing,findDesigns}from"./chunk-qe6pp4p6.js";import{localDesignOf}from"./chunk-mseawt58.js";import{TOOL_VERSION}from"./chunk-d6a6198y.js";import{BUN_RUNTIME_FLAGS}from"./chunk-skk6yvnw.js";import{require_picocolors}from"./chunk-jrsknzjt.js";import{__toESM}from"./chunk-2smsg2ct.js";import{readFile as readFile3}from"fs/promises";import{homedir as homedir4}from"os";import{resolve as resolve2}from"path";var import_picocolors=__toESM(require_picocolors(),1);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{mkdir,writeFile}from"fs/promises";import{dirname as dirname3,join as join3}from"path";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}async function installCursorRules(projectRoot,designFolder){let pinned=await designArgumentFor(projectRoot,designFolder),arg=pinned?` ${pinned}`:"",body=`---
3
+ description: Drive UI design through the Velloo MCP server (a local design canvas backed by this project's shadcn components).
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Velloo design
8
+
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."}
10
+
11
+ - Cursor starts the velloo MCP server itself (wired as \`velloo mcp\`), so the
12
+ tools are available once the MCP config is loaded \u2014 nothing to start first. If
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}\`
15
+ (stays in the foreground; \`b\` background, \`s\` stop, \`o\` open). If you start
16
+ it yourself, pass \`--background\` so you aren't stuck in that session. It
17
+ prints the canvas URL (defaults to \`:7300\`, or a free port if that's taken,
18
+ so don't assume 7300). When a canvas is already up, the server's
19
+ \`initialize\` instructions hand you its live URL.
20
+ - You are the designer: compose screens from the project's shadcn components via
21
+ the velloo MCP tools, verify visually with \`screenshot\`, then \`emit_code\` to
22
+ turn a design into real code in this project's conventions.
23
+ - Read the server's \`initialize\` instructions \u2014 they are the authoritative tool
24
+ reference; this rule is just the pointer.
25
+ - Designs are static on the canvas (no handlers, routing, or data fetching);
26
+ write those when you implement.
27
+ `,dest=join3(projectRoot,".cursor","rules","velloo.mdc");return await mkdir(dirname3(dest),{recursive:!0}),await writeFile(dest,body,"utf8"),{installed:!0,path:dest}}import{existsSync as existsSync4}from"fs";import{cp as cp2,mkdir as mkdir3,readFile,rm,writeFile as writeFile2}from"fs/promises";import{homedir as homedir2}from"os";import{dirname as dirname5,join as join5}from"path";import{fileURLToPath as fileURLToPath2}from"url";import{existsSync as existsSync3}from"fs";import{access as access2,cp,mkdir as mkdir2,readdir}from"fs/promises";import{dirname as dirname4,join as join4}from"path";import{fileURLToPath}from"url";var here=dirname4(fileURLToPath(import.meta.url));function resolveSkillsRoot(){let dev=join4(here,"..","..","..","..","skills");return[process.env.VELLOO_SKILLS_SRC,join4(here,"skills"),dev].filter((p)=>Boolean(p)).find((p)=>existsSync3(p))??dev}var SKILLS_ROOT=resolveSkillsRoot();async function installSkills(projectRoot,baseDir=".agents"){let entries;try{entries=await readdir(SKILLS_ROOT,{withFileTypes:!0})}catch{return[]}let results=[];for(let entry of entries){if(!entry.isDirectory())continue;let name=entry.name,srcDir=join4(SKILLS_ROOT,name);try{await access2(join4(srcDir,"SKILL.md"))}catch{continue}let destDir=join4(projectRoot,baseDir,"skills",name);await mkdir2(dirname4(destDir),{recursive:!0}),await cp(srcDir,destDir,{recursive:!0}),results.push({name,installed:!0,path:join4(destDir,"SKILL.md")})}return results}var here2=dirname5(fileURLToPath2(import.meta.url));function resolvePluginsRoot(){let dev=join5(here2,"..","..","..","..","plugins");return[process.env.VELLOO_PLUGINS_SRC,join5(here2,"plugins"),dev].filter((p)=>Boolean(p)).find((p)=>existsSync4(p))??dev}var PLUGINS_ROOT=resolvePluginsRoot(),bareVersion=()=>TOOL_VERSION.split(" ")[0]??"0.0.0";async function patchVersion(manifestPath){let manifest=JSON.parse(await readFile(manifestPath,"utf8"));return manifest.version=bareVersion(),await writeFile2(manifestPath,`${JSON.stringify(manifest,null,2)}
28
+ `),bareVersion()}async function installClaudePlugin(homeDir=homedir2()){let src=join5(PLUGINS_ROOT,"claude","velloo");if(!existsSync4(src))return null;let marketplaceDir=join5(homeDir,".velloo","claude-plugins"),pluginDir=join5(marketplaceDir,"plugins","velloo");if(await rm(pluginDir,{recursive:!0,force:!0}),await mkdir3(join5(marketplaceDir,".claude-plugin"),{recursive:!0}),await cp2(src,pluginDir,{recursive:!0}),existsSync4(SKILLS_ROOT))await cp2(SKILLS_ROOT,join5(pluginDir,"skills"),{recursive:!0});let version=await patchVersion(join5(pluginDir,".claude-plugin","plugin.json"));await writeFile2(join5(marketplaceDir,".claude-plugin","marketplace.json"),`${JSON.stringify({name:"velloo",owner:{name:"Velloo",url:"https://velloo.design"},plugins:[{name:"velloo",source:"./plugins/velloo",description:"Design and implement UI on the Velloo canvas \u2014 skills, slash commands, and subagents.",version}]},null,2)}
29
+ `);let settingsPath=join5(homeDir,".claude","settings.json"),settings={};try{settings=JSON.parse(await readFile(settingsPath,"utf8"))}catch(err){if(err.code!=="ENOENT")throw Error(`${settingsPath} exists but isn't valid JSON \u2014 fix or remove it, then re-run connect.`)}let marketplaces=settings.extraKnownMarketplaces&&typeof settings.extraKnownMarketplaces==="object"?settings.extraKnownMarketplaces:{},enabled=settings.enabledPlugins&&typeof settings.enabledPlugins==="object"?settings.enabledPlugins:{},merged={...settings,extraKnownMarketplaces:{...marketplaces,velloo:{source:{source:"directory",path:marketplaceDir}}},enabledPlugins:{...enabled,"velloo@velloo":!0}};return await mkdir3(dirname5(settingsPath),{recursive:!0}),await writeFile2(settingsPath,`${JSON.stringify(merged,null,2)}
30
+ `),{marketplaceDir,settingsPath,version}}async function installGeminiExtension(homeDir=homedir2()){let src=join5(PLUGINS_ROOT,"gemini");if(!existsSync4(src))return null;let dir=join5(homeDir,".velloo","gemini-extension");if(await rm(dir,{recursive:!0,force:!0}),await cp2(src,dir,{recursive:!0}),existsSync4(SKILLS_ROOT))await cp2(SKILLS_ROOT,join5(dir,"skills"),{recursive:!0});await patchVersion(join5(dir,"gemini-extension.json"));let linked=!1;if(homeDir===homedir2()&&Bun.which("gemini"))try{let proc=Bun.spawn(["gemini","extensions","link",dir],{stdin:"ignore",stdout:"ignore",stderr:"ignore"}),timeout=setTimeout(()=>proc.kill(),15000);linked=await proc.exited===0,clearTimeout(timeout)}catch{linked=!1}return{dir,linked}}import{mkdir as mkdir4,readFile as readFile2,writeFile as writeFile3}from"fs/promises";import{dirname as dirname6}from"path";async function writeAgentConfig(projectRoot,agent,conn,homeDir){let path=agent.path(projectRoot,homeDir),entry=agent.entry(conn),existing=null;try{existing=await readFile2(path,"utf8")}catch(err){if(err.code!=="ENOENT")throw err}let content;switch(agent.format){case"json":content=mergeJson(existing,entry,path);break;case"codex-toml":content=mergeCodexToml(existing,entry,path);break;case"continue-block":content=continueBlockFile(entry);break;case"continue-config":content=mergeContinueConfig(existing,entry,path);break;case"opencode-json":content=mergeOpencodeJson(existing,entry,path);break;case"vscode-json":content=mergeVscodeJson(existing,entry,path);break}return await mkdir4(dirname6(path),{recursive:!0}),await writeFile3(path,content,"utf8"),{agent:agent.id,path,action:existing===null?"created":"updated"}}function invalidConfig(path,format,err){let msg=err instanceof Error?err.message:String(err);return Error(`${path} exists but isn't valid ${format} (${msg}) \u2014 fix or remove it, then re-run connect.`)}function mergeJson(existing,entry,path){let parsed={};if(existing!==null)try{parsed=JSON.parse(existing)}catch(err){throw invalidConfig(path,"JSON",err)}let servers=parsed.mcpServers&&typeof parsed.mcpServers==="object"?parsed.mcpServers:{},merged={...parsed,mcpServers:{...servers,velloo:entry}};return`${JSON.stringify(merged,null,2)}
31
+ `}function mergeOpencodeJson(existing,entry,path){let parsed={$schema:"https://opencode.ai/config.json"};if(existing!==null)try{parsed=JSON.parse(existing)}catch(err){throw invalidConfig(path,"JSON",err)}let mcp=parsed.mcp&&typeof parsed.mcp==="object"?parsed.mcp:{},merged={...parsed,mcp:{...mcp,velloo:entry}};return`${JSON.stringify(merged,null,2)}
32
+ `}function mergeVscodeJson(existing,entry,path){let parsed={};if(existing!==null)try{parsed=JSON.parse(existing)}catch(err){throw invalidConfig(path,"JSON",err)}let servers=parsed.servers&&typeof parsed.servers==="object"?parsed.servers:{},merged={...parsed,servers:{...servers,velloo:entry}};return`${JSON.stringify(merged,null,2)}
33
+ `}function tomlValue(v){if(typeof v==="string")return JSON.stringify(v);if(Array.isArray(v))return`[${v.map(tomlValue).join(", ")}]`;return String(v)}var VELLOO_TABLE=/^\s*\[\s*mcp_servers\s*\.\s*(?:"velloo"|velloo)\s*(?:\]|\.)/,ANY_TABLE=/^\s*\[/;function mergeCodexToml(existing,entry,path){if(existing!==null&&existing.trim()!=="")try{Bun.TOML.parse(existing)}catch(err){throw invalidConfig(path,"TOML",err)}let lines=existing===null?[]:existing.split(`
34
+ `);while(lines.length>0&&lines[lines.length-1]?.trim()==="")lines.pop();let keep=[],insertAt=-1,i=0;while(i<lines.length){let line=lines[i];if(VELLOO_TABLE.test(line)){if(insertAt===-1)insertAt=keep.length;i++;while(i<lines.length&&!ANY_TABLE.test(lines[i]))i++;continue}keep.push(line),i++}let block=["[mcp_servers.velloo]",...Object.entries(entry).map(([k,v])=>`${k} = ${tomlValue(v)}`)];if(insertAt===-1){if(keep.length>0&&keep[keep.length-1]?.trim()!=="")keep.push("");keep.push(...block)}else keep.splice(insertAt,0,...block);let content=`${keep.join(`
35
+ `)}
36
+ `;return Bun.TOML.parse(content),content}function toYaml(value){let yaml=Bun.YAML.stringify(value,null,2).replace(/[ \t]+$/gm,"");return yaml.endsWith(`
37
+ `)?yaml:`${yaml}
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]})}import{existsSync as existsSync5}from"fs";import{homedir as homedir3}from"os";import{join as join6}from"path";async function refreshAgentArtifacts(opts){let homeDir=opts.homeDir??homedir3(),refreshed=[];if(existsSync5(join6(homeDir,".velloo","claude-plugins","plugins","velloo"))){let plugin=await installClaudePlugin(homeDir);if(plugin)refreshed.push(`claude plugin (${plugin.marketplaceDir})`)}for(let projectRoot of opts.projectRoots){let skillsDir=join6(projectRoot,".agents","skills");if(existsSync5(skillsDir)){let skills=await installSkills(projectRoot);if(skills.length>0)refreshed.push(`${skills.length} skills (${skillsDir})`)}}if(existsSync5(join6(homeDir,".velloo","gemini-extension"))){let ext=await installGeminiExtension(homeDir);if(ext)refreshed.push(`gemini extension (${ext.dir})`)}for(let projectRoot of opts.projectRoots){let cursorRule=join6(projectRoot,".cursor","rules","velloo.mdc");if(existsSync5(cursorRule)){let rules=await installCursorRules(projectRoot,opts.designFolder);if(rules.installed&&rules.path)refreshed.push(`cursor rule (${rules.path})`)}}return{refreshed}}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 agentOptions(projectRoot){let wired=new Set([...await globallyWiredAgents(),...await projectWiredAgents(projectRoot)]),detected=new Set(detectInstalledAgents()),rows=new Map;for(let agent of Object.values(AGENTS)){let key=agent.id.replace(/-global$/,""),row=rows.get(key)??{label:baseLabel(agent.id),detected:!1};if(row[agent.scope]={id:agent.id,wired:wired.has(agent.id)},detected.has(agent.id))row.detected=!0;rows.set(key,row)}return[...rows.values()].sort((a,b)=>Number(b.detected)-Number(a.detected))}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)),alreadyWired=[...new Set([...preWired,...projectWired])];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:alreadyWired};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:alreadyWired};if(mode==="manual")return{agents:[],manual:!0,preWired:alreadyWired};if(mode==="global")return{agents:targets,manual:!1,preWired:alreadyWired};if(mode==="project")return{agents:projectTargets,manual:!1,preWired:alreadyWired};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:alreadyWired});if(picked===null)return null;return{agents:picked.filter((id)=>id!==MANUAL_AGENT_ID),manual:picked.includes(MANUAL_AGENT_ID),preWired:alreadyWired}}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:[...BUN_RUNTIME_FLAGS,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,agentOptions,askAgentWiring,localDesignScopeProblem,connect};
@@ -0,0 +1,3 @@
1
+ // @bun
2
+ import{isCancel,select,DESIGN_ARG_DESCRIPTION,resolveDesign}from"./chunk-qe6pp4p6.js";import"./chunk-ghwy99py.js";import"./chunk-mseawt58.js";import"./chunk-hhkjqvww.js";import"./chunk-ak57bgnh.js";import"./chunk-d6a6198y.js";import{daemonRoot,listDaemons,stopDaemon}from"./chunk-jc95phff.js";import{fail}from"./chunk-s23gtejf.js";import"./chunk-tjy12q19.js";import"./chunk-75gfv9g4.js";import{designWithFolder}from"./chunk-v1by80c5.js";import"./chunk-mknhfnkn.js";import"./chunk-5ts4fvd9.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};
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{colorizeDiff,emitTheme,emitNativeTheme,loadDesignFolder,emitDesignMdPair,resolveProviders}from"./chunk-yp39f93e.js";import{ThemeSchema}from"./chunk-w40pqmyz.js";import"./chunk-n70zfv0m.js";import"./chunk-zexzy6zv.js";import"./chunk-80fjfyha.js";import"./chunk-s23gtejf.js";import{detectHost}from"./chunk-gv209d5j.js";import{DESIGN_ARG_DESCRIPTION,resolveDesign}from"./chunk-z3r8px3d.js";import{defineCommand}from"./chunk-2smsg2ct.js";import{readFile}from"fs/promises";import{isAbsolute,join,resolve}from"path";import{stdin,stdout}from"process";import{createInterface}from"readline/promises";async function readMaybe(path){try{return await readFile(path,"utf8")}catch{return}}async function themeEmitter(folderRoot,theme,outDir,cssOnly,tailwind3){let design=await loadDesignFolder(folderRoot),{defaultProvider}=await resolveProviders(design.config,folderRoot),adapter=defaultProvider;if(adapter.themeToNative&&adapter.themeModule){let toNative=adapter.themeToNative.bind(adapter),spec=adapter.themeModule;return{native:!0,produce:(apply)=>emitNativeTheme(toNative(theme),{spec,outputDir:outDir,apply,...theme.colorsDark?{darkThemeOptions:toNative(theme,!0)}:{},sourceTheme:theme})}}let customCss=await readMaybe(join(folderRoot,"theme","custom.css"));return{native:!1,produce:(apply)=>emitTheme(theme,{outputDir:outDir,apply,cssOnly,...customCss?{customCss}:{},...tailwind3?{tailwindMajor:3}:{}})}}async function report(produce,apply){let result=await produce(apply),useColor=stdout.isTTY===!0,anyChange=!1;for(let warning of result.warnings)console.error(`velloo theme export: warning: ${warning}`);for(let file of result.files){if(file.diff.identical){console.log(`velloo theme export: ${file.path} is already up to date.`);continue}if(anyChange=!0,file.applied)console.log(`velloo theme export: wrote ${file.path}`);else{let rendered=useColor?colorizeDiff(file.diff.diff):file.diff.diff;stdout.write(`${rendered}
2
+ import{colorizeDiff,emitTheme,emitNativeTheme,loadDesignFolder,emitDesignMdPair,resolveProviders}from"./chunk-mseawt58.js";import{ThemeSchema}from"./chunk-ghwy99py.js";import"./chunk-hhkjqvww.js";import"./chunk-ak57bgnh.js";import{DESIGN_ARG_DESCRIPTION,resolveDesign}from"./chunk-qe6pp4p6.js";import"./chunk-s23gtejf.js";import{detectHost}from"./chunk-nccfyeyy.js";import{defineCommand}from"./chunk-2smsg2ct.js";import{readFile}from"fs/promises";import{isAbsolute,join,resolve}from"path";import{stdin,stdout}from"process";import{createInterface}from"readline/promises";async function readMaybe(path){try{return await readFile(path,"utf8")}catch{return}}async function themeEmitter(folderRoot,theme,outDir,cssOnly,tailwind3){let design=await loadDesignFolder(folderRoot),{defaultProvider}=await resolveProviders(design.config,folderRoot),adapter=defaultProvider;if(adapter.themeToNative&&adapter.themeModule){let toNative=adapter.themeToNative.bind(adapter),spec=adapter.themeModule;return{native:!0,produce:(apply)=>emitNativeTheme(toNative(theme),{spec,outputDir:outDir,apply,...theme.colorsDark?{darkThemeOptions:toNative(theme,!0)}:{},sourceTheme:theme})}}let customCss=await readMaybe(join(folderRoot,"theme","custom.css"));return{native:!1,produce:(apply)=>emitTheme(theme,{outputDir:outDir,apply,cssOnly,...customCss?{customCss}:{},...tailwind3?{tailwindMajor:3}:{}})}}async function report(produce,apply){let result=await produce(apply),useColor=stdout.isTTY===!0,anyChange=!1;for(let warning of result.warnings)console.error(`velloo theme export: warning: ${warning}`);for(let file of result.files){if(file.diff.identical){console.log(`velloo theme export: ${file.path} is already up to date.`);continue}if(anyChange=!0,file.applied)console.log(`velloo theme export: wrote ${file.path}`);else{let rendered=useColor?colorizeDiff(file.diff.diff):file.diff.diff;stdout.write(`${rendered}
3
3
  `),stdout.write(`Would write to: ${file.path}
4
4
 
5
5
  `)}}for(let note of result.notes)console.log(`velloo theme export: ${note}`);if(!anyChange||apply)return;if(!stdin.isTTY){console.log("(non-TTY) re-run with --apply to write the files.");return}let rl=createInterface({input:stdin,output:stdout}),answer=(await rl.question("Apply all? (y/N) ")).trim().toLowerCase();if(rl.close(),answer==="y"||answer==="yes"){let final=await produce(!0);for(let file of final.files)if(file.applied)console.log(`velloo theme export: wrote ${file.path}`)}else console.log("velloo theme export: skipped (no changes written).")}var exportTheme=defineCommand({meta:{name:"export",description:"Export DTCG tokens.json plus the framework theme in diff mode \u2014 Tailwind v4 globals.css by default, or v3 CSS + preset when detected"},args:{to:{type:"string",required:!0,description:"Target app directory (writes <to>/app/globals.css and <to>/tailwind.config.ts)"},design:{type:"string",description:DESIGN_ARG_DESCRIPTION},theme:{type:"string",description:"Path to theme JSON (default: the design's theme/default.json)"},apply:{type:"boolean",description:"Write files instead of printing diffs. Default: dry-run."},"css-only":{type:"boolean",description:"Skip tailwind.config.ts (CSS-only export)."},"force-v4":{type:"boolean",description:"Emit the v4 artifacts even when the target app looks like Tailwind v3."},format:{type:"enum",options:["framework","design-md"],default:"framework",description:'Output format: "framework", or "design-md" for a Google Labs DESIGN.md.'}},async run({args}){let folderRoot=await resolveDesign(args.design,"theme export",{designFlag:"--design"}),themePath=args.theme?resolve(args.theme):join(folderRoot,"theme","default.json"),outDir=isAbsolute(args.to)?args.to:resolve(args.to),themeJson=JSON.parse(await readFile(themePath,"utf8")),theme=ThemeSchema.parse(themeJson);if(args.format==="design-md"){let design=await loadDesignFolder(folderRoot);await report((apply)=>emitDesignMdPair(design,theme,{outputDir:outDir,apply}),Boolean(args.apply));return}let tailwind3=!args["force-v4"]&&detectHost(outDir).tailwindMajor===3,{native,produce}=await themeEmitter(folderRoot,theme,outDir,Boolean(args["css-only"]),tailwind3);if(!native&&tailwind3)console.log("velloo theme export: target looks like Tailwind v3 \u2014 emitting velloo-theme.css + velloo.preset (pass --force-v4 for the v4 artifacts).");await report(produce,Boolean(args.apply))}}),theme_default=defineCommand({meta:{name:"theme",description:"Work with a design's theme"},subCommands:{export:exportTheme}});export{theme_default as default};
@@ -1,3 +1,3 @@
1
1
  // @bun
2
- import{AuthConfigResponseSchema,HealthResponseSchema,cloudJson}from"./chunk-zexzy6zv.js";var BUILT_DEFAULT="https://api.velloo.ai";function defaultCloudUrl(){return(process.env.VELLOO_CLOUD_URL??BUILT_DEFAULT).replace(/\/+$/,"")}var CONFIG_TIMEOUT_MS=5000;function cloudOrigin(baseUrl){return new URL(baseUrl).origin}async function fetchCloudAppUrl(baseUrl,timeoutMs=CONFIG_TIMEOUT_MS){let fallback=cloudOrigin(baseUrl),res;try{res=await fetch(`${fallback}/v1/auth/config`,{signal:AbortSignal.timeout(timeoutMs)})}catch{return fallback}if(!res.ok)return fallback;let config=await cloudJson(res,AuthConfigResponseSchema,"reading the cloud's config");if(!config.ok||config.value.appUrl===void 0)return fallback;try{let advertised=new URL(config.value.appUrl).origin;return isSecureCloudUrl(advertised)?advertised:fallback}catch{return fallback}}async function publishedBoardsUrl(baseUrl){return`${await fetchCloudAppUrl(baseUrl)}/boards`}async function billingPageUrl(baseUrl){return`${await fetchCloudAppUrl(baseUrl)}/billing`}var LOOPBACK=new Set(["localhost","127.0.0.1","::1","[::1]"]);function isSecureCloudUrl(cloudUrl){try{let u=new URL(cloudUrl);if(u.protocol==="https:")return!0;return u.protocol==="http:"&&LOOPBACK.has(u.hostname)}catch{return!1}}function assertSecureCloudUrl(cloudUrl){if(!isSecureCloudUrl(cloudUrl))throw Error(`refusing to send credentials to a non-HTTPS cloud URL: ${cloudUrl} (use https:// or a loopback host)`)}async function checkCloudHealth(baseUrl){let res;try{res=await fetch(`${baseUrl}/health`,{signal:AbortSignal.timeout(8000)})}catch(error){return{status:"unreachable",reason:error instanceof Error?error.message:String(error)}}let health=await cloudJson(res,HealthResponseSchema,"reading the cloud's health");if(!health.ok||health.value.ok!==!1)return{status:"ok"};let down=[health.value.db?.ok===!1?"database":null,health.value.blob?.ok===!1?"storage backend":null].filter((part)=>part!==null);return{status:"unhealthy",detail:`the cloud's ${down.length>0?down.join(" and "):"a dependency"} is unavailable \u2014 publishes and share links are down; try again later.`}}
2
+ import{AuthConfigResponseSchema,HealthResponseSchema,cloudJson}from"./chunk-ak57bgnh.js";var BUILT_DEFAULT="https://api.velloo.ai";function defaultCloudUrl(){return(process.env.VELLOO_CLOUD_URL??BUILT_DEFAULT).replace(/\/+$/,"")}var CONFIG_TIMEOUT_MS=5000;function cloudOrigin(baseUrl){return new URL(baseUrl).origin}async function fetchCloudAppUrl(baseUrl,timeoutMs=CONFIG_TIMEOUT_MS){let fallback=cloudOrigin(baseUrl),res;try{res=await fetch(`${fallback}/v1/auth/config`,{signal:AbortSignal.timeout(timeoutMs)})}catch{return fallback}if(!res.ok)return fallback;let config=await cloudJson(res,AuthConfigResponseSchema,"reading the cloud's config");if(!config.ok||config.value.appUrl===void 0)return fallback;try{let advertised=new URL(config.value.appUrl).origin;return isSecureCloudUrl(advertised)?advertised:fallback}catch{return fallback}}async function publishedBoardsUrl(baseUrl){return`${await fetchCloudAppUrl(baseUrl)}/boards`}async function billingPageUrl(baseUrl){return`${await fetchCloudAppUrl(baseUrl)}/billing`}var LOOPBACK=new Set(["localhost","127.0.0.1","::1","[::1]"]);function isSecureCloudUrl(cloudUrl){try{let u=new URL(cloudUrl);if(u.protocol==="https:")return!0;return u.protocol==="http:"&&LOOPBACK.has(u.hostname)}catch{return!1}}function assertSecureCloudUrl(cloudUrl){if(!isSecureCloudUrl(cloudUrl))throw Error(`refusing to send credentials to a non-HTTPS cloud URL: ${cloudUrl} (use https:// or a loopback host)`)}async function checkCloudHealth(baseUrl){let res;try{res=await fetch(`${baseUrl}/health`,{signal:AbortSignal.timeout(8000)})}catch(error){return{status:"unreachable",reason:error instanceof Error?error.message:String(error)}}let health=await cloudJson(res,HealthResponseSchema,"reading the cloud's health");if(!health.ok||health.value.ok!==!1)return{status:"ok"};let down=[health.value.db?.ok===!1?"database":null,health.value.blob?.ok===!1?"storage backend":null].filter((part)=>part!==null);return{status:"unhealthy",detail:`the cloud's ${down.length>0?down.join(" and "):"a dependency"} is unavailable \u2014 publishes and share links are down; try again later.`}}
3
3
  export{defaultCloudUrl,fetchCloudAppUrl,publishedBoardsUrl,billingPageUrl,isSecureCloudUrl,assertSecureCloudUrl,checkCloudHealth};
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{AuthConfigResponseSchema,AccountResponseSchema,DeviceCodeResponseSchema,DeviceTokenResponseSchema,CliTokenResponseSchema,readFailure}from"./chunk-zexzy6zv.js";import{string,object,record,literal}from"./chunk-w40pqmyz.js";import{openUrl}from"./chunk-hggap8fq.js";import{isSecureCloudUrl,assertSecureCloudUrl}from"./chunk-3f2p94wa.js";import{chmod,mkdir,readFile,writeFile}from"fs/promises";import{homedir}from"os";import{dirname,join}from"path";var CloudCredentialSchema=object({token:string().min(1),email:string().min(1)}),CredentialsFileSchema=object({version:literal(1),clouds:record(string(),CloudCredentialSchema)}),credentialsPath=()=>process.env.VELLOO_CREDENTIALS_PATH??join(homedir(),".velloo","credentials.json"),normalizeCloudUrl=(url)=>url.replace(/\/+$/,"");async function readAll(){try{let parsed=CredentialsFileSchema.safeParse(JSON.parse(await readFile(credentialsPath(),"utf8")));if(parsed.success)return parsed.data}catch{}return{version:1,clouds:{}}}async function loadCredential(cloudUrl){return(await readAll()).clouds[normalizeCloudUrl(cloudUrl)]??null}async function listCredentials(){return(await readAll()).clouds}async function saveCredential(cloudUrl,cred){let all=await readAll();return all.clouds[normalizeCloudUrl(cloudUrl)]=cred,writeAll(all)}async function deleteCredential(cloudUrl){let all=await readAll(),key=normalizeCloudUrl(cloudUrl);if(!(key in all.clouds))return!1;return delete all.clouds[key],await writeAll(all),!0}async function clearCredentials(){let all=await readAll(),count=Object.keys(all.clouds).length;if(count===0)return 0;return await writeAll({version:1,clouds:{}}),count}async function writeAll(all){let path=credentialsPath();return await mkdir(dirname(path),{recursive:!0,mode:448}),await writeFile(path,`${JSON.stringify(all,null,2)}
2
+ import{AuthConfigResponseSchema,AccountResponseSchema,DeviceCodeResponseSchema,DeviceTokenResponseSchema,CliTokenResponseSchema,readFailure}from"./chunk-ak57bgnh.js";import{string,object,record,literal}from"./chunk-ghwy99py.js";import{openUrl}from"./chunk-hggap8fq.js";import{isSecureCloudUrl,assertSecureCloudUrl}from"./chunk-5ts4fvd9.js";import{chmod,mkdir,readFile,writeFile}from"fs/promises";import{homedir}from"os";import{dirname,join}from"path";var CloudCredentialSchema=object({token:string().min(1),email:string().min(1)}),CredentialsFileSchema=object({version:literal(1),clouds:record(string(),CloudCredentialSchema)}),credentialsPath=()=>process.env.VELLOO_CREDENTIALS_PATH??join(homedir(),".velloo","credentials.json"),normalizeCloudUrl=(url)=>url.replace(/\/+$/,"");async function readAll(){try{let parsed=CredentialsFileSchema.safeParse(JSON.parse(await readFile(credentialsPath(),"utf8")));if(parsed.success)return parsed.data}catch{}return{version:1,clouds:{}}}async function loadCredential(cloudUrl){return(await readAll()).clouds[normalizeCloudUrl(cloudUrl)]??null}async function listCredentials(){return(await readAll()).clouds}async function saveCredential(cloudUrl,cred){let all=await readAll();return all.clouds[normalizeCloudUrl(cloudUrl)]=cred,writeAll(all)}async function deleteCredential(cloudUrl){let all=await readAll(),key=normalizeCloudUrl(cloudUrl);if(!(key in all.clouds))return!1;return delete all.clouds[key],await writeAll(all),!0}async function clearCredentials(){let all=await readAll(),count=Object.keys(all.clouds).length;if(count===0)return 0;return await writeAll({version:1,clouds:{}}),count}async function writeAll(all){let path=credentialsPath();return await mkdir(dirname(path),{recursive:!0,mode:448}),await writeFile(path,`${JSON.stringify(all,null,2)}
3
3
  `,{mode:384}),await chmod(path,384),path}import{hostname}from"os";async function fetchAccount(cloudUrl,token,timeoutMs=8000){if(!isSecureCloudUrl(cloudUrl))return{status:"unreachable"};let res=await fetch(`${cloudUrl}/v1/me`,{headers:{authorization:`Bearer ${token}`},signal:AbortSignal.timeout(timeoutMs)}).catch(()=>null);if(!res)return{status:"unreachable"};if(res.status===401||res.status===403)return{status:"rejected"};if(!res.ok)return{status:"unreachable"};let parsed=AccountResponseSchema.safeParse(await res.json().catch(()=>null));if(!parsed.success)return{status:"unreachable"};let body=parsed.data;return{status:"ok",account:{email:body.email,...body.name?{name:body.name}:{},...body.tier?{tier:body.tier}:{},...body.accountId?{accountId:body.accountId}:{},...body.creditMicros!==void 0?{creditMicros:body.creditMicros}:{}}}}async function verifyCredential(cloudUrl,token,timeoutMs=8000){let found=await fetchAccount(cloudUrl,token,timeoutMs);return found.status==="ok"?found.account.email:null}async function revokeCredential(cloudUrl,token,timeoutMs=5000){if(!isSecureCloudUrl(cloudUrl))return!1;return(await fetch(`${cloudUrl}/v1/auth/cli-token`,{method:"DELETE",headers:{authorization:`Bearer ${token}`},signal:AbortSignal.timeout(timeoutMs)}).catch(()=>null))?.ok??!1}var sleepCancelable=(ms,signal)=>new Promise((resolve,reject)=>{if(signal.aborted){reject(Error("cancelled"));return}let timer=setTimeout(resolve,ms);signal.addEventListener("abort",()=>{clearTimeout(timer),reject(Error("cancelled"))},{once:!0})});async function performDeviceLogin(cloudUrl,onPrompt,signal){assertSecureCloudUrl(cloudUrl);let configRes=await fetch(`${cloudUrl}/v1/auth/config`).catch(()=>null);if(!configRes?.ok)throw Error(`cannot reach ${cloudUrl} \u2014 is velloo-cloud up?`);let config=AuthConfigResponseSchema.safeParse(await configRes.json().catch(()=>null)),issuer=config.success?config.data.issuer:void 0,clientId=config.success?config.data.clientId:void 0;if(issuer===void 0||clientId===void 0)throw Error(`${cloudUrl} does not advertise a sign-in service \u2014 is velloo-cloud current?`);let codeRes=await fetch(`${issuer}/api/auth/device/code`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({client_id:clientId})}).catch(()=>null);if(!codeRes?.ok)throw Error(`the auth service at ${issuer} is not answering \u2014 is it up?`);let deviceBody=DeviceCodeResponseSchema.safeParse(await codeRes.json().catch(()=>null));if(!deviceBody.success)throw Error(`the auth service at ${issuer} answered something this velloo can't read`);let device=deviceBody.data;await onPrompt({verificationUrl:device.verification_uri_complete,userCode:device.user_code,expiresIn:device.expires_in}),openUrl(device.verification_uri_complete);let deadline=Date.now()+device.expires_in*1000,intervalMs=Math.max(1,device.interval)*1000,accessToken=null,abortSignal=signal??new AbortController().signal;while(Date.now()<deadline){await sleepCancelable(intervalMs,abortSignal);let res=await fetch(`${issuer}/api/auth/device/token`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({grant_type:"urn:ietf:params:oauth:grant-type:device_code",device_code:device.device_code,client_id:clientId}),signal:abortSignal});if(res.status===429){let retryAfter=Number(res.headers.get("retry-after")??res.headers.get("x-retry-after"));intervalMs=Number.isFinite(retryAfter)&&retryAfter>0?Math.max(intervalMs,retryAfter*1000):intervalMs+5000;continue}let polled=DeviceTokenResponseSchema.safeParse(await res.json().catch(()=>({}))),body=polled.success?polled.data:{};if(body.access_token){accessToken=body.access_token;break}if(body.error==="authorization_pending")continue;if(body.error==="slow_down"){intervalMs+=5000;continue}throw Error(body.error_description??body.error??"device authorization failed")}if(!accessToken)throw Error("the sign-in code expired \u2014 run velloo login again");let label=hostname().trim().slice(0,80),exchangeRes=await fetch(`${cloudUrl}/v1/auth/cli-token`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({accessToken,...label?{label}:{}})});if(exchangeRes.status!==201){let{detail}=await readFailure(exchangeRes);throw Error(`token exchange failed (${exchangeRes.status}): ${detail}`)}let exchanged=CliTokenResponseSchema.safeParse(await exchangeRes.json().catch(()=>null));if(!exchanged.success)throw Error(`${cloudUrl} returned a sign-in token this velloo can't read`);return exchanged.data}
4
4
  export{normalizeCloudUrl,loadCredential,listCredentials,saveCredential,deleteCredential,clearCredentials,fetchAccount,verifyCredential,revokeCredential,performDeviceLogin};
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{CHROMIUM_INSTALL_ARGV,CHROMIUM_FULL_INSTALL_ARGV,CHROMIUM_DEPS_INSTALL_ARGV}from"./chunk-n70zfv0m.js";import"./chunk-w40pqmyz.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};
2
+ import{CHROMIUM_INSTALL_ARGV,CHROMIUM_FULL_INSTALL_ARGV,CHROMIUM_DEPS_INSTALL_ARGV}from"./chunk-hhkjqvww.js";import"./chunk-ghwy99py.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};